bazaar-orig-v0.7.14/0000775000175000017500000000000015166123241013140 5ustar hasanhasanbazaar-orig-v0.7.14/translators.sh0000775000175000017500000000743015166123241016057 0ustar hasanhasan#!/usr/bin/env bash # Helper script that automates the preparation steps to translate Bazaar. # # The script will add the passed language code to the LINGUAS file to avoid # editing it manually. # also: # It will reorder the contents of the file alphabetically; # It will check if the code is already in the file; # It will show the contents of the LINGUAS file, allowing a visual check; # It won't really check if the locale code is valid but will inform you # that it is not in the list of codes inside /usr/share/locale; # It will generate a .backup inside /tmp before proceeding and a .tmp file # before overwriting LINGUAS. # translators_helper() { local lang_input local lang_f local po_d local build_d local system_langs local langs_in_file local temp_file lang_f="LINGUAS" po_d="po" build_d="build" mapfile -t system_langs < <(find /usr/share/locale/ -maxdepth 1 -type d -printf "%f\n") temp_file="$(mktemp --suffix=BAZAAR)" printf "Temporary file: %s\n" "${temp_file}" printf "Setting im_a_translator to true\n" meson setup build -Dim_a_translator=true || return 1 pushd "${po_d}" >/dev/null || return 1 langs_in_file="$(wc --lines "${lang_f}" | grep --only-matching --extended-regex "[0-9]{1,}")" printf "\nNumber of languages currently in file %s\n" "${langs_in_file}" unset langs_in_file printf "Language codes currently in %s file.\n" "${lang_f}" cat --squeeze-blank "${lang_f}" read -r -n 1 -p "Proceed? (Type y or Y to confirm)" YN case "$YN" in [Yy]) printf "\n%s\n" "Proceeding..." ;; *) printf "\n%s\n" "Leaving..." exit 3 ;; esac printf "\nCopying %s to /tmp/%s\n" "${lang_f}" "${lang_f}.backup" cp --verbose "${lang_f}" "/tmp/${lang_f}.backup" read -r -p "Type the language code you want to enable translation for. ex.: pt_BR or es: " lang_input if [[ "${system_langs[*]}" =~ ${lang_input} ]]; then printf "Found %s in the system's language code list.\n" "${lang_input}" sleep 2s else printf "Could not find \"%s\" in the system's language code list, but proceeding nonetheless.\n" "${lang_input}" sleep 2s fi if grep --only-matching "${lang_input}" "${lang_f}"; then printf "%s already in file\n" "${lang_input}" sleep 2s else printf "Language to be added: %s\n" "${lang_input}" printf "%s\n" "${lang_input}" | tee -p --append "${lang_f}" 2>&1 sleep 2s fi cat --squeeze-blank "${lang_f}" | ( sed --unbuffered 1q sort ) | tee -p "${temp_file}" cat --squeeze-blank "${temp_file}" >"${lang_f}" langs_in_file="$(wc --lines "${lang_f}" | grep --only-matching --extended-regex "[0-9]{1,}")" printf "Number of languages currently in file %s\n" "${langs_in_file}" unset langs_in_file cat --squeeze-blank "${temp_file}" cat --squeeze-blank "${lang_f}" # $EDITOR LINGUAS popd || return 1 pushd "${build_d}" || return 1 printf "Generating the main pot (Portable Object Template) file for lang %s...\n" "${lang_input}" meson compile bazaar-pot printf "Update and/or create the po (Portable Object) files for %s.\n" "${lang_input}" meson compile bazaar-update-po echo "--------------------------------" printf "\nConfiguration done. Now ready for you to open your \"po\" file in your text editor and begin translating.\n" printf "When you are done, commit your changes form your fork and submit a pull request on \n%s also, refer to TRANSLATORS.md if needed\e]8;;\e\\ \n\n" "https://github.com/bazaar-org/bazaar/blob/master/TRANSLATORS.md" echo "--------------------------------" popd || return 1 return 0 } translators_helper || echo 'An error occurred; review the above output' 2>&1 bazaar-orig-v0.7.14/screenshots/0000775000175000017500000000000015166123241015500 5ustar hasanhasanbazaar-orig-v0.7.14/screenshots/fullview.png0000664000175000017500000116462215166123241020057 0ustar hasanhasanPNG  IHDRUƑ(-tEXtCreation TimeTue 10 Feb 2026 07:53:51 PM CETՕ)tEXtSoftwaregnome-screenshot>IDATxg-rqw"@$\hq(;B ݊'h@p\>LvvGvwfngy])s A4 U* @wRŀ(`',@ RftL:,Q }wCmv`i֮PRx=yPSx=y]N=tO=ZF"rrSQ$Ɠyޮ2H&LPVD5Mhi7 L$ {-J 7%%^%JF+FR;%Xu &Uovm e'ٮ $d{6xMvU6حxrC*~Ǡ9 %5+ej D2S㱦9l^wؼt^&SbPQ)+yJZS%)[scy{=ܖd؀9PdE,&JZI7nXJ%Qrڠͣ9XiX-IK' l@%`>(q` ^Ys13qsLAxJK4JJJ{'V̵T@c;\K. -V`?6I9P*At*'N 8MwѺBh1z/_1`,x?2V`9Ukr8mܹϘ0a܎<`P>}jjjY0s挏I `q +D)P!©ΗLs@E2C3gάxɧ۷ϱ"ғbA6l|N|fܹf)`kM$˱0ȒLP%QDIh~wƏ@*8O?um-6Qi7o M5OX&AvIPZ+DiVITI]>z0EJamm @577VVVvi5VJ"Z{jsmT%՟+*2!-PA@ 8@pHCxQi8ݞu]˩bRYpAh w -b,G yxA%`^sPŽWL8b;p½DѵU}-V|)2BZd#5k֞UYYy.dȦM9phUខUkbVͫnP%VZsrZ=J~[:2Zv\Z1RtW枀MXkTI7.VMx**i㏧} *is0ozr?v'n+Pkk+|>9 j-n9Nrݔ'jXK{QMdy=XADXk7E2RTT2JSS l8RXXئJIC Rl'SSŚ[E1Tx\<EPCCCJpbϧt\T!P-UiښS9VD@Z'TxY^G:BqkX̀A@*Dx4ĊC$_˛$#+!SN9:\gӦMSOdy^zŗ觟~&ΡҖ*V.^gMHT[Dp@H˖-qd-vmϘ_{eD8gv͞XJcc=.Be}=9߀襗#jʔ锎?Lh*v,))YsU$_ˈje@eȐ!t@5<Ok-b{9#CG$̮N;&OxM/t4p@wxm'MY{Tj@k,]TT{gϞw-7`ʔqҵ^2t啗@W'HPhtuWSYY|N%ny#9FH7]@ Sg{cCyd3_|槟~+jkke@+$* lӺS`H+ўd*oGf(&?L[l{\.]}("Ͽ@}9V==ēޓ}q>E͗/>I&vmKо%֛~b XSzG|m˺S.qL%͘/LT.LzAб=;wK| *E<ӰaC#:t(=(//Oܱ>|>|A1ߗ+?ገJKKe!NvˮT.#{Ewu;]~U2*+{ӝw&+mYwGh*Yca̘1>1ҘWgkTaɲF Z$z2e [>r-[&9|HSw9Htn>n͛D<*ނq ypĭQ)=ZrCe55‰;t*ψ#NXIwl M?$ '/_R{ϩA;򱬬4 =X _. Qxq\smZwGtA @nӟO?+bs3swl'|x\y7oR[~:gG>QGNրW_+=о)OA9k<|JgT`I.UҀ @TH*i@P A4 UҀ @TH*i@P A4 UҀ @TH*i@P A4 UҀ @TH*i@P A4 UҀ @TH*i@P A4 UҀ @TH*i@P A4 UҀ @TjsEQ2 =@^'3I td.- `[?UC"n=og@D{mcXCP.~A W;oL>mhTO5/b^uz'T%4oX@PzQowzQ0n90|u2y[mo5o*;@PrB [[ӕZ[LJJJ4}HG}zLoϋT =?>Ad$$bz;L zAOЭū%Ώܴ>7O #En.c'gt%6V* m-{xO ^1CC 4Mjz/dЁ ^bڝ\fF#8Ls"+GM98!~_l6mxǼd[iDB:~SSs@\לv⡑.ٖn+`@B'7Rqq hp'kTV>݌D,o|xZxkKL/(-B}]Q5>Ƙ?y5y:H鍍r{$]b:gF.0UCqPcs40$UrhJGn"^V(_D MKŸ k^~մ(&GO@=ZZEp(8)H 68=TԳ*w}"~ؽqBiR0ZLm|x??^?G˔Q[dP"d\&.~65khp Q66y2555֒j9֒<59K#2zn^ݼGmM_Qoic/R[#(| 0Ad } 4gn '?Cǹ~3o>.|oT7#>:W]Xۻuヌ^|%Js=MC :hժU;򲤗OGuutͷQee%mݺf:4b+?0JV@ E~ZO[%N'J5骣qe8Pлwosϙr]s5-8akkVFTk7"W8bG9-րvgoV䧍4qxnmVӫW/~~Xߟ~mu2ۻ^lo\fϹ7[#{hOO ^,/c 3i¸ NϓbuuRV 1*X,JtpiƒK卵t.n;ha}W﬏n6b[.4{[1/ө(:t(3K2{hʔp= j@s\tȾӨՅ[c%JrG=.D35nӧɮ5:%M5&qG^,jM`(!9Jdk`MhIZ6mUznT?T0t GlO?c7Mir䪂8ׯ/=ģ2I~~|AFsΰ~ dTi|3i5nZ[*_/--tF,+aaRr~ܛ?LӵIBdZ%r5Rp9PJDP0F{xT)+tl?J˱ ﻤ*cwf ]]VV".ӠA{tDmޛs]NL *5/L*AW%vޏleR[d 9]o (z9u 9P8ƊS ׹JjZK莏 *e N+heM52y{8ښTʨX&WM{^z1uԑ />lQZF8uk19S믿; o[ps,cnS[['A_p]{))N>Ӈ u@F$j:7nH>o 8ᄣF7EUάQMT#li!r_ D|Md[1Nlk$("yZJNTLtˇyt^-Է${Moۛ{q8B ;QOK\[|C5^{'e@@ ׷>{i*Ozd{vy'Ͽ膛?^py?_CC#+9U 㬵T;[].#+|t.utu4ORGؠ>j 65Jxk2۠ 6_EqOﵦY/ӌy߸E+o 6%%UT1'ypӦcap=믥aÆdeTWWQo#&MH<[l+WtU jkkE@\WQTB ' D.F C (5z.ƊHZwhCv^ceC}>ow#¢ed3X.&Ս7蕊qiܸ1pNtQM}k+t4vgmuv@|Z; QsVU6QP)yHm"KhZQ*puu{Xv}U8χ]nl6z|0)ibN;v %CP{.ɼVWz!h?Y$+ތ\x{-%JdkTQk.RDF(R8bƖfj[Ɯ/P.DɼVZZJqTZ h3Q%UnRT)fdx5N+ףˑuSs Ƞbӛq`eKJ@jRhM]TS }r-[P֌.[l`׾fak={$8@%3vſpÛb<_AȪ%5>]|Q,Eo"c&EDJMb;!Qr 90C]gKX?Ev/;im1s-~]sgΜ#ٳ 2eݙ@ dR椧)o2*^46G %R1G(G+.g;.bR܁`D"&j&QX.]F^z9n[(_JǏ,=/csQQ7y]jmm\pUVV5U +R0kt3xTYPW'29bjcWk%Nmf9t8(hS!@uF-n ۨYkSa];9"(G,׏O&R6{4h O?ѷ~Y8iiR1q℈܌wߗÚ5k R 䜑>h:p:QU S:ǔq֨IbFvH0()Q8ᰙT6-Lq8裪M~D=!q`EXگ&H*ۻzGip3N3s"_dI+ߟDcDT\\DwqуRqiRaa 6AЮĺJ~۾CP=TD85O(k褀 PBNJ0 Xۈ[|ؐ&6tD+W{>5n3`.UUUQGp:]I't"UV]Xs3?xQ~r(SpwGIpO> E~e<P9ïX2i;xPsΔ_E|qAyT|G)_9 IU{ReqvUWszqO5$+hiPMy,j@U|޳6 ^$ OdMbn;EThoJPqV rzlirllD#9Kܲk_rUanL˵1="G#{ᑃ= ?wh%#+ڣ;q\R%"ȟJI1>elȩ VXYVJ$TZK?ђ>ZS 5{U<3z9h`FvānqݸAȈܘ-.Z //9"h"`!áDv5YCO80rn)A)OJ0`q JИ'U-yT8ңʚddT'ɕU^r;Ƌ@kӄV&BF^>ݰ7VRo NFR>YJs~l xo&`jdi2/Zy|B>MGA蔊6U3Wjk82zM ENӃ. (Fm hM|HO+k[jo& PԨ`Qs:cnn tQchLOD6v͞K脝 iqБSr7A)4/HF5EMwykݼ6 #'jʭbɅKQ|b Έ)nCz/}).F=Jz <;P{noHϲ-~j:ToOޮ}y;tT9=.%vEQ{b51]GH17Q-_b7%# +F砭֓rDP UҪ>\[EMl64h-_W (HRi {;u MX.߯6 AtVEN;)`ʧb|)Q;E MDMу+2ʟ pt:rASD"1jZVSB8LyS8hwHԀyj m$& VT*.+v`e]CXJBVK Y; ޥ-@VR6Hkyܩ4@QLgõP`T hJ(1֧s(P蠭mFtlhjPD ڲ6wЭ^T @q T:K4Sہ+5@YR]rr3NF[3dညVћDU)6=2Y 5UL-y|E!%$G(@b%/|* YTbPO9ƨBmoHsOn0܅+rlq_uPbJ!_d>/: s@ŘT<*ͽh5g~6_G ވqWD?x7иͼ4g0v7kE`ֹTת >}BZ Y t:PCU(qs@E]rurdNJP{#?ZMP'>ǝJ. kCbVV8诟֣{ @!9xTYE.q(a@%T[& A} F,'k_UGJ0, kUSD}P[rZ O~{Pr_,O}*@`W+hp҄~n6C<@di+-ڈ#2Ai)#kh= jkzS f@NKs =gJD3` :o)XU֦#Fn%43ך{FZ 9Y+4_T.кK޵uD u:ksM6ԗwo/1Hg?]MjQ8򏹍&a/"x3b7 @W7܇ t:ͥ(.ńFT,#T/N4OF"Zs%P讀7>%>"Wj`tEt,TB%mT>s2[K0a UE:gO|(ݧKk |rGOyp~ "@&%Unٵ/qUa:AYc뚍T;Voɕ1l]|*QM|MX,X 9;gGo5_4QCLoaЕ.<'ݚß6 J.ܣXT؃7_LjRR$ //2s^sv+K.wzNq߁^~r2ٶ@¯2/}.rŒHߙ`A n2{Q|2kT.'SMCbk2X9b (TEPQ7j̀%T`l(5O.ޫNm.觕[t롥TM?ej]j-}G{D69}ݴ|onCTrڟ֣0+Tw\{;zs&J<>rRL-ϭG.سvO% m k6c~ C+|K55귍ԧIY*r2'7t>@Prh.kOW!XE(Z隋 E+hpe\?uTO: y=h<dyW/O,|Kk/zMOEy =zjoY,-[egm .zf+_AzFޖTR4zeZIhTjepEX#AXꈓ!q5E|g]7MTQҰT8蹯ҽKD)aA.TӢM~zzaj r"c/~nZ2 7Й imMjUz@nhW++\}ddh/]2Vxz[3=5%d%7^mTQ|B׿V-oDgrB62SU@& ]wT5ߡ<*j"h5T| @#lk(qq~'kP]WT/`T%{O8E6WChMBbK&uF%)jd2^rq0dք|wͲ:dTNRLims鯚wSf#3Xw<9pSW6ˠ ֠L&[fJZ',ǜW,&Пߩw:rr 5~jlUe0;EtQ=h?K,nqjrwīE(wكht_-8vv;vm tAGuC$c入xB( A_Ԧf 6:DpDjxLRx=JP>)s-%Bu(n\ככ 05TM>K =2Og\>}+3D@m3yy{y>^JgN+Xkq-3t.}6Cb],_c6&G 2R[ݠV2 3Tl[9mDܑ/M^I,OnV }ʗM_HO(6+v#Vʤ/j7>::?@YR]?'Q+rxRG_{<ၸ6Qj(Z)z-Y+EhÁ1wKNWJHSg"xhXM}3+ b[C%Lc);Slw);ގmrt ,mQoNbtAN~M4)4ŅMw<Z"\弙&jj Z0LwJvƩM_\N\O 0P,r Z+WPNFjpB2{˓yW v*e-\K:nL@*G))4%{:ei͑eQ{z^4h5lwOU&eu~ Ɵ sq{ҟ^w A5VVxc\q<_מ;!\G>%WAsxeģbn\bpBN"ip3xnlk<7ysV\ 6^}ʡR =i=X;2QU馷l>Y߾'`6fE\e1xFkӱ۫3/$^7&G}pWh|{݂gȡcIf/*,fj~Jk?@RPZ.NL͂ڣOk.~=uGᢠ&U AE;q8'X~|⪛q,rY"[i.ׯ_ɩiK4ӏ뵚+E C }xsrݎ" ڜ!hTc8ed'Q rhi5 7r=hIi)ODZP9|, Qh 69|>>jَ+EWm)OT7wìڴ|*j8aIE֞-t 8أU q)@& ]]XSCSʀ.Ipp&%BAD9W`Mӓ_4tv) Tn7 Yp/QbtLF&5Egļ>_(DŽ8iDjԸThicjÁE?d9S/H/}L1\ @  xMj @yO8TK-cJ ue qqhk8iZ&bqhX)@K@5TPlCP=&Gsd+͏Zf ;ŨbIRKmIjMm)N"dr<9Tk%oT񇙤8'pMr_Vc ͂ۙci 4}DU pً dSY(8SAj}l^SRdKMP+ŔLRHOR /Գ+#z`qTr~rv8cxHFGl6AmjͨA4p '#Qa))Է5H~w#]VK<'`ŁZ|`~X%}:@UAj<)(ԣA+4&tӎ=ƍC-J+ 4Nn1{݂{a "pJ  /m~J]F `WD|GGէhܘƯDˇA¸EEA[wx}TxLr:rd yA~F4/qn$M2I""ʄ-TQ\ez9 r"j &!hTӣqi,jT8 碖Q FJqhP8I֭rZ)9mɐk('W ".nO=vA OGnS2PjuZ 8Z6ԐRLJRR=Aqg.H AL8jؠg*t7 AJ0SMHmS(TWQzu2[6R-7!WI؇dU[H[NBj t6iH'@n A V+%,~N͂*_Z%J^ɔIj% gDĻ4R=\EEM~́OW&* :7@iV8bk A9Kܲk_4pՑ͗@K*n_JV(Wlp-KFREV g=zRӬ1aG|'Lq,,k@N}r2qw\+h н 9gj&|s(>l-u iy9z!Z*yzVJds  -z~=u(HS< 8,1]*hCƊ'ʠ^)-9TRٍkߵW+Z~hzjs22b"/pS}6Ts:5(&)psh)uǙ>T|/}."  ,57d rK(079*֯"ֻU,?E,߹+}/|JJq>yܗRw8U->#v[,F*9)qTDǍ;w-G3 ApP%??\.-z} j= >T_JyMjSKƩTqg/jG Ԙ7Z Gz%Yg.ټ\15Qh5TIDÓX/".90\{O"ġ(r |UVlQJ]qm}Ek+A*M⧽Fɝ#7~Lx O?Q ):R>q-"Rd7 u8C^`T*.vJt6{S]ԍ*7^} [{Ql6qv)d~8fNYFy?ʠ\|ү\g C=2"@J-w=M.OU Dec")Qm,!#tk8m=IZO.\Ds|}j5,V|!Ϟ`ԛ0L䤸 AǁW/ߩ[oLNٵv졗6S**c^YE>\+vo _qЃ*2?n;TT LmIlJ$.]\).Ycř䳝j{{2!ŋ|ẁ S\Sk27u ){sD_r,tUWRzh-y;=b>[__Y[&/~Fy)k~XAp;$FU\[Ew#{q7" R*:m;9DJbJK՟DA{\>UDo>8V] p+ :ט7[!)w;c8|9pBYnOr(*X\\@^P +=fv l[ !R N81v';l#Hއ#ߛ HmM# ]}>bEMM5m\Sv7]B U"#-}xq/5'$$ 6b=!9}YEWA&9k!;Hf]*TŭTVg}N:TMP |XaFVd5J/E _迿MνzosN=C ӢMJtChnMmkLX2'TeEz1p ;'͋\?SĞeYJ⧰O~&;ɼ&C= K\ckpdJY+%Խ3wևXr ճDR% ,Z7O[Aqv`GkCO[p,J &,`\᡾%v]AM)ګptxHmJk[pS M?0' eUcPo L>!@AӢN:]/sOrbԊ`S&+5rVN]*{Y*kɨZb;'ށZ$3JE19 Jx/sևR(<5-IOW 4C3FɮMdZWߪBwYN텿+t(AF+d`Y2szX-距xTYtnD20ʹprn8,LN)sƌyPTPAY:w.q Mh5HZ|2Q[QZ@='ZnN>h8-w鬊){چK.(J.>B7QK~`Rs Xc$^WLqQ֥[ ^o>A>X~ [e؛E|M7'Ne딉SsI['.]ԯ_߈D֤`,,hzDЁLLۑ֑oY#{%6-G=@\yez3kꢘL]GǥЧK[>xewUޡo m/7@w񸧈n\!hTӣ^4t?u MMT^H?}%{#N'J5ZG"VmލMTZV@(@(wI֓fdU:h ]SӴ$E9OG*Q\c\{_!" WJw˓vqzڲ׭He呵<-tY)uVPOYA^ENjPSʭrb#'JBBFѮd?(s@6qnku1Y-qn|^g4mh@֘@@}y:CdfmDEmRp캐}bs3*%?qZ&o~r1}\"ȃ*\?vm]\1/9rdG{Ubgf xW]C}j@qaH'Mu'T!+ qAN~WM:W?\NYGWkc݁vw/-Ez9ihOg؍@n AhW.Tr݆wA $K"my7\ -Ak!jl R_%PȇˡPK<䣒'hTҿ5z_s 1uT-;/ :3V9 .E)P= 5}j)y ] d ?rޔ3wV,_F r_Ʀ1xiذ4q# r @GAP2u~t84iDq>V^K[lf(5rcdVd`^Իw/8pjs%  * _oMm-g]@]@ATVXaqk9V~AȨDf XCv% APL:'!g z9U#ndAȚx=b^ mwU bZNZ++)a@H\ d=@4UCu ATy,TH*i@P A4 UҀ @TH*i@P A4 UҀ @TH*i@P A4 UҀ @TH*A&jnj&K@TU@Qr:x Aqy{ aw}8678NrSg-x$bz;L [ ^o>tڼe+Um4d GԻWO/'h?m8ϻ` ˣ8 y<)F >1x 4 Q5e\BPu6Ц;SI%hx`lC 0 QOkTh#jjjji 1}y\98ɬVA6hlhWrѰaC y]8u a>`k']ˣ8 Wd#B%Paytct1}plY.op\ *%qP6mj u1}plYop^*pC%M z`gOCI@yT t!\Ű &=*ʑ0,:n^|%zdׂӧOc>J)NW0s; {(??yC|^O?jjj[!۴iұ};=6|>:.te4mit86:Vg)8iG#xAR6oٚ#҂ Ov1}ժU5k|It;o͛¯#IM;#6 qV{?wx[oo?6l(QQQj߰3+c_oԼ5o@GE> PIqsI/cSNy9pBr]b 3gҮS߆LqTsuu5w߉2@1cY0J=~w8#GL˯G5-,~7'_;iƌ2t˭ʕ߉2ޢl OЕ!]_VmJzz!]ל9sEq79V[X~79ptqRm3`@?ybT_g^n@OUUUtwgtPƛnKŜFI^{ %?sR=:F}KKK ]Í~OS`wT f/oMSUpltT+8r6^MH˖-O:2IzR7nnY׸lW kQƼhɓ)_Pjjn'x>sJ#d* te8;v&=< OZǏU֬YC>@ 橶˿{F@qYSNO[sh+x$[;IaPyc^W^={Peeecn[>ݩ}ФIN5-$<, 1 Kt+*eR}R96}l@5J>z|VpREJ_w-]z4x 9ާ 6.믿+d]88IOgGupߟLyy?&kG,Vs=R 2T.C, =h+:ꇞsy4hh"&k \vF}Q{4|Gtw>VXIwu|}IꫮW_}Mz!SKfs %A/ QbwLFz<1zE0s,z@^VUmv_8ʫ4iTJԥg8y萃Ç,&AXZU%dgf+j\˸9ߑ\eiz *UhH5\c[a={nEVk׭',hmqWy=ӌhYő.=.{G<:\wߕ_|gԥnXXP/I&_z58#hM3;LQ9"dm֧O%kS *Uz)+%]v1ӏ?0sZFFY`luΈ viRqI -Zf!wK)Yn m2ctzn펈vjjjh-xyyy泃mٮ7|+ą_**Puu@ (XD;yc#ڲwa_qAS"^Кl٬'8/ =zIRfv5Px_r{6qx*..NYsG!{E=BRKsSr ΧQM'T.#`ȔpN{Ѵ3EOA{̜Icƌ8i._<ihqgqj Ig#k̤"ۨHg~aZN83^e//Y"dGO8L~ ?cDt泃nY}G>L?<}5F6 -~K7ԖqyK.3/NIں͸w-oO}R͝;O?f diO>tD>y}L'x tUHT smHf(.z t޹Ӿ&_>;v~pϗ'wډ l[v|)B O[.hҤI4i⤸MA ?ӷ"z5Ғ%Kw^t9g?k %@wv([p|l^'|Mh!pO@|sfҥ\TN6e|%pYsjS}=D" t|Qf-h!h'JVVZR*C'.9`kȐsBT^8 R=nVYCO=ʔ'\+O\%_O?,}$JKE7.5LF4?=,' tU]l1bl̖,]1mUwۿrh8kĝWgqh?Sw%rmҒ| FE*ۄ*7p lfW+k.ܱr|Ѣ%qo||A͵xPR f] [|94v7M|C@-O$rTȾT9;:1#X 8NR6rŭ.*|sL:pn9ˤޠTkW4> ږ-[ͥtx 5U(y }%_0O2>3y"|i'-Cyn;p]SDPg.NB r K5zhZp!-;Z!+|Q42te7O= ntŪ'<6`W<{~k֚H fÅJNb}ǝ_M})ӧ|G񩧞w{_ޙ>CS-bwTiNoI7`yMەRc#R9@ޕl2-Ol?y{{kqLqT _}@7=Pj6leeeV3'< |[Nwq|VZE>vq2m OU!]'*r'ȻȜ,>ktԫWτqcdMk|wΙ6RuUl25KmR9n83T^+*Z)Qpz;B f3vXYQϝpZntꫯѪիe@3Ϡ S;V*G&?3Ij2m]et>dW{;eΓhSZ3λBⰨCm$uǟx¸Iu_lvs \ˑ}FPvݏ<}\y>|3d$4> ~=*0[q=FL'Cy4'({x*|+hiPMz 6۟xtct1}plY.op\ r@BV&N%,=x>;`+'ʣ8 d# *-tdaH~:q[q awN86#78N;Gqq9Nᡂ***2r8")r=ϻ>`'Gq駟E7p4>/<i%I+]vtgӇKiw5G4vMf;&ǟw?ct@nr8e+O~WIASNW]u\|3w}ʕoc}}|g~r @qwRII2%Gyp ]#v 2¡_4jHʄZ@_|)m8qAtܹsE҅G'p1b۸P^/]x)GBjjj_9QA_|] `΁^z[XB6ΚumU@=IEEwҽOB=]D瓪;ETYY)4?#;oʂ̥OWA͒w@:cnI]t>͛1/g{뭷{[C't<z!^z{Eڰa~)'D=nwW%|1d=s!gs~$/^y駟E҃9H:cHQ\9|74q:ӌ׆ L?oԷ2XDa[׿MV̙3Zqq1A$:O~Y/|4h\f+WREE~!Ĩ .X>\{ߝ*_'gy"9qM!C SޥRq M0^{xA:g1\q\p|AQΑ׸&֧~*._AdΜ?t}'^{P[l5@h˖-⢶1'^ZM6U>wdά@~oN;(S2=owr8GMgumjjW_}Y>o~{obكǟV:D"ۿDy7 Ͽ_.LfqLvOJKKh̘kf:QyM9l&_xxe\~X㭷DvGQG)k\|%{K[:#do'/LDџ|8/_)~O:f]~}ŗ/},n_xeQ8=UX'ʛns|t7#<$/P:g;r:WΉ''N>W"Y^usT[|Ȏ7|l;v =co\0-[l4qq|}Tw<8ʻvmX_xEY n]j |Raƍ'{~W>%k)d>>\09昣dba+hذr]^-M4:Dq%{wM[n}||wk,OмXQ/o_фe>OE 7ڈ:U^s0{*r>wu'\+u\ʫwbwovoωIQFf;|ך5͞;MDje-L>z)2gw1{ڛ|M&EeA8[nQ~F|>Zjӧ*7kn|x˷ܕ])W,Q9mvT/XY)mM7pcذ﷢\Vp)%Ki]>|UD,<Ѓ <=ĹZϠA#Mmm[;o&07.,ñق?mm>ǛkCǟmܨMm%y;IꫯRٶtƌ///3rEmذI(͸}yZ@w,z); '>t`cٲyx΅_ x;K='йpUrosι@LBxo;oA0>59yUKK ojf7n~=d[P(.x H߾}v9'F,4|Wۊs hn6OO5s>ӛ_W]'DRwb3zۃ:L>f ;06m,usϰaC8͛77iܬt@ٗ_jR78hfڴ]e9˵?c=I 1P<6~q`ؼD_c~_ 'OW|.aֳg\( K/"O|7"1s@w~?So+ ;8YVm䈺ޮ4U}Vٲeˌ}G]_~^t$Gi@Ȳe+e UŽ]N+W炘Nϗh:t\<\r@kq%Η)vco9ڗ<7xGɠ~2y?7;|;˸#P9 Ŭ^JQ̿^k|{sfsϽ MS:@}t9`޼%qp3TJq-Ǖ^'|  {qA^x8,ӿgrLmP!7q{G6x qȤCfw_ًwgK|}*}g}̥r!'vaL˜ӄk]{5WN餓Nws8_ ㎻dMI>pmǏ>HbIfMa> hΜ92/~^C8#_0sdk.rM)r@j3}M8ݻz 6 umg/y[5Ptle^sgۓ >se_~Uyc9Q9qˇV-:U+#$Y 5L|fybߞJ,긆w*sΗf.>׈ OOfõ9).7MJIu\w\Õn1{킻>4hpu.4WT:5׎Z}AT~73w`lxt>1p|hiPMjhqKEqtnROOPw;U:;_= pr 9Uq?6lpõ{/=<2G w?{E/4.r*i@P A4 UҀ @TH*i@P A4 UҀ @TH*i@P A4 UҀ @TY igvd] G 'eA4 UҀ @TH*i@P A4 UҀ @TQU#}DRP.,󷊚*!^A+P@] Hj@\B^J)B RѺz\Еt*jPŏ@'$ LcW(HYG\&`(t=҅*@@rP.8ϵ”  QkC4<Mw(0 l$e%JA㣐bCdA̅#7 d.<@ KqPVd%EPO۬wP”*HYU`0hByY ]B^/t^`(1t:ɡeaǵ]($& LZ3Em(LT.b\=8AʆUZ[FT 4?klۡ#֡OW&,4\c]b]xyѲ5f쓋bLiźxiq9-q#VF)([V~ vO Z[ԈXRwn1U B{FU5<_E=UDJȼD8of,F}D|ѿJvo[iR涇> }Գ*J )??D!JbCޚr\!Zp"Yp 7Mvp{ţ#^!1zEVuY9o9/o:~_+}]v@Uy=7r`t߱^{h/PnwuPj˨#rvEc'茶vw.^6򳄿iI.>awdmn-EeD~h}#X}<Xew7#S6P|6m1"?&{b{ dXC}"e٬#|hAjHVg)0 leP.@ 2؛y iVoC3$1g?]b.#1@~잫~G >bGmшPlF MZSc/*nI 'JzDh`TbfO~4ބm PIA# _DzP~0Orą%.4z$nFQ~Q%?L":Z.]$ ;OXWE5[W_ͯ])_ 7(qwj@ ^yrB~-Wh)VZZW|VN FNH6 Nmݞ|u9Χ2ZgRSb& u(t>Y )Γϰ݊IJ>5?LMT_*#kzr> rȼaG ܢVYc_lJlz=ju[ErRe2-Q,AEN1V51ߍQtP;RbJ.OE"CPt8lg9ug|7CZ{iQp|'{`]ۢ:“Vպtmv:ݻ<;L]?466ʻk(\Ekkx[qᩨHn{l@~A1UH՛V2C u( rSP:N  : 6 Q%%Qf H1DZQlG}bRU|dy􋔰qY1Ѩ)?//t e%s{2蒟G M2m} ȈenA|a 9EE >CQœݨ>z/DZl9}soy++{w/^B? 0@y>̳T\\L/9o=d!￧+VRuu mذ^zJ 7I/D-"P9+]*mJmVĹv̡erAP.(o!"BB<6QճTS%T?]${)MU'+vˤq)&䟝㹪znáFJ"^KQII-dŶ6YIOF}HbiGKqrKVo_8S>=HvwljjiƪPs3s*U6SeRp:Kn$իr.Z6hРte' NeuVϨ>#}D{=O?, XKiҤ O7nݩ >|8AbzI/wss/((@ ƿ'7+3ioSR2C }(t< r[ViNKuNs&B}G+lCCI%Ҡ$"h޲[ԣ,_'N2[c-b<-(e췴7PF:Ui!"`쩲4{4p 3f4^jӎ4d`qe=}bJ5V*Zdu͛7g#"Ǵwe,W-#~|Gyp@#xqaKu M$"&L0N/?oGxܲ0Գgq#\/;[Niw$Bѣ88-*y<1_駟3gҬYT0~'JۖkhEtQo{]I /9\x( %?䐃hm. P__^\V.zP{~\;P1z;;c]:: rA۠\DZ5W^)(x/(I|>φ^ܻۼUr4B(IYiD@E5MO|nHDdkX,qݨRQa>??|=A6lM[XTQQ4'"z3Hu'Jۃ6wt VPDIVK]`w7x77P}}=mذQ;\X}D-PՓ.]&M0A*+WA:Q/6lC}T^^O ϿKǟioJ{B;^ vmy.ͷ}4^^={dm\/z-VecGӁTPEoø \Ӏ_|^~.rLP.H 傮*[b5#bM)UlS~ssd6yi]mv$YnX_-Brϔ#@$Q*&2Mf&ETUI nF?Zy@?~լDU" 7;(~'Arj@b\: ߍO;C8`' F>CN$t}Ct>As:.8ɜ2dXGuܳIE@oJUpeaiԨQTWWK;8Y&c%.['N˖-~[Ld>=hy$fߎaÆ!hpSα5Y. CP.TI-,mi?lXw֦-jwN Y1}&T773v+NMaX_&Qb$ 9@UB5mdBL$?ߵ2 @]86S_=*z.)6,t)&5Lv]s=䝸Tew*nCWg׊ LN/x4@esIRLUs0u6N:jjjloDrAۡ\еu@S; fjm-i1ƍnKFk2Xc DZbX5!k䰙hZ q>m Je6Q;K_U]j-_,<{G_~2T@MXo -y=ie[ϕ+WwxꚆڹmqڵk>;|su]#rDĬ73WA5ۺJ&\uj\e7 UtE<[r5-YT7<;^8d>'W-:~W5V~T;=nosnsNkZ:2Y\;[&v9;ڹ傮/+5|OӍiU"M5V1"zsUWT963+A/DؽEm5g}T>mK#D#k+MGEBX"ܗC <[ePyWVj+ k7WiǵLpdx>s2CY^LDDž&Y^&<C8 =8'dupkNV^^.{a\OW]F~76d8Ϸ~[9AB$X㡇l,g^6Cӂ #fڌ :>}D4/YN55Ҙַoc_Z]wh.|^?ƹ<\@cc8*C;po|nc˒|e^^x&QkS!U׉c3 )0Eeڍ⇵)J1Ag.yqXpfp{yzPC?ckpF&v\)ȵ^Æ O<^&{Kxvu1\N[Zÿ>2!Վ:hQ4u.17t>yynmim'ǻio.\z7&]o.EKneN>sm'A~" .r|m޼YΣ/C[MMZ`ܬop0vuw(t} *jeϝ\l+5*6ɼG#GS`<>F[IжKcZ#YvNdBJK֊;E-մn]1 PI8q|rhXf*ΕҺQ[dm^=˨H^s픚ڲQ9]+LƈTT,t0j.HqF+qBYk\Ք: wx|wkO1^ h5jIaGp):,{&|O^y:+߅9h¿=zzEqZ*]^zGȁ9X~NL7NZZй]yokpcki0'N\?.S;uF(t}]$D@Ŧnn$ZXR;Īr]KX0EX1/~D~Lu6TwRPϒԊ YWMA= % :QL,s3=>J~qYb|>Q+qfZC'XBŲiK po@z:? em~_:5=drKۺuɕ7Ȫgea0wJJe(| X>Wekɞ_GyYp΅qND^A"H\oOBp`Ś78PsSAZehMy|2Ȣ`Se\vիx>?k|1VZZ&orPѺi.5%8M Ã*\8 T˨Z1i"V=kmK`'hDR(Q_wϤF~~?Dk#ha 1ǾI4 7d[H/Hk C%EdTMwͲf y9S#-y^u B υ!CM\O\iyX\2 A~ny= _6Uy>o~}kCIBoے`׍)Jdxy'9{yWCJ6%'Ni,T@.$ `an;S'kQN2.!5!"t.?MܹS{a .WCC@V p\dedddd|P@ FzE K l4,\$H5PZNfFLT}HVj thjt]%CIB1 Awy*wG@KjˮJ_c$uZ~d+Db됸^2n |kX ]c"njVEȤX6vMrΝhak~DlIĮZJK322222222222`\1UzRRͻX|HBHJӼ=i*_eҕlHx7"M.E]0i%*#%=p#ޢI3#q׹UQ|IYyɣjɕpmc#].ȸ|NU,HRKz6S߭^O-Z3ut Rw*>4hW&[<.ߛhh~MM]ESƫ27TEV@nYibS<ſZ*jPjMGFFFFFFFFFFFuTpͬ_(We'" T(*aVQ"uճŒ+:pJm۴ \}w{J8ZWSGu9Rqޥ&'=^O)1"\|uJZq‡ȕ +SI@u9V~=OrCS${oq"Ȕ_'8Y8%YD'Uy㒽ٍ辸):{,}s'Nwbxell6܌UF}Pt~*\iU>lF6*")i]Vۍt$A4QMܔ IvsN$T\]OGwU(EE}ӫuR乪{䜴VmC:FiszϪ.vWW[; yW XA,0arbVjM_}tyZU喛\DG}I+N+p9v"|ߠ믿*ni[:#####!@`\暫T9z(#* TK/n33<2==+p' p1r\y UjeጌKJTk_s1&r{\t- e'W NjAѥ[(RaORqY7c*V'e{i%Pd=^]'`ٶ!2ѡKM7<^Swtn6ڶmu:6EpYJҰ@y>}X,--r߄!Dر8>߯vN _viڸqyװ\z!`cҘ*BKUkf3ӱ\Iؓ҈-g,bh'CqlUm3.?+Ѩ.-P"(%kJZ^5g"gT8[&愎fzT^UJko?M2Ap\_U'%lP\O ].yPlIxA08'ݵkCҭB0O~]`s`_p[Ю];_{ab(3,h%Z1n?\?qT0w:&8= pꫯfo~~r?)LAᅬń H ` m7įkڿ>(KΓsHb-4K u/(UWhsUV y+YP|#+muϒ}.$UaS%EUޏV)x+%ϩm*'nDז(J@ TnK^cOhJm)*kmFQŽ!F7Ч#tp% %/6\ @+QD(MlO}ѵv| @`,M\*XpO@8B  ^ZZb/G^fDZ,2ntt>OЏMl~&222.G,/-Љ#%%T.8{Bz܋t18 c?,VPLJMV&,Xnr|48E>XLVkۿGàdd*Kn,S9[ ɻL֘2E7B( 0Т**ĭ Ե \Z% Δ cZ%UDD't!E\;tZT4bYU ZDeL[n"moN`䮷u=P5OSeINl[nN g$9W7ALP[cQ'dtnY2cc'&m`<V%@jEq߭&K Cqz'  tFK,ULf92ZWTԣDhi,3 J.(NQpt,%Yd^ɗMHQt+.m=bɾ?VI:^=݁i3GrtDΤ ,[^U*I]GD{^.+e(E_ktqiB倵edd\~XRE}@k=Զ֗zΠK#䌌 eaRS>% jk)Ti`ҊZZR姂pH-0R{:I,,Q%?./VB紑nuJH&J"RDĈ.%Uyde"چmfYīջo;ǙF܀|};gD r>K%RqW.uta]NR FoVz$r9az[ZLtd,Ax8&Qiq.\+GAgU|G$.+,iդxD2mJJ4&8<?Q^ I4}M wjK'$uRq~Zʬq JؔdקڎZ_ wq32226\A傍u&URUfUU//H+-2#C `YSb WQ$9n{.TTLV EX1хUd,D-#tWZt9>Q!gʯERD>9t| jIwDD:V̆*YzԐ+U1ߘ+P{Dpkg~{.^۞Nký;]ȸ,d ֗TqR>`Y+kWR'E\&udA|Lt:I UH8(Hs&*a)9#Ңt_-@T|+3qi%[MKJ'7Iɔ8_e7}JLp9`v䊊܈p6&svFctNw;'Ѻ\Z2_*ܭUjo*n'-[S{Z6R)>\,dwazjj9 #̏t q(^-,,bg2222.d b MLGye(",NCܢĊlCd#(xqTjJce\D1mǩ QY:bĵ tn[UW4LLB>T](;Ys\'Kd=VVrq0Xᕃs^ ".њh*6 5 0wittne*###E 2.\Z~l~^Gh'k%2L!u-"Z,B`ZrE:VB1~M2]WVpq A>IDDU?ZD'Z'Xt@P%6ͳ.\q傍t]wLrUJFU|!ZX^VM#r!\LX!r 00gMTHWqb -,XT`^q=tkZbũ(U~J]]*(aLHkҷ9 DPjɓl.AJ|-O'8r绿l)IA-l;j-SK(####A 2 Y.8HJBEF. NH6JySYŇVq*nI]}ru TUInk!J9Gn8!/"bdK+E{/_UM<Ԫ!1qg|;(,.egr˔.@^gcHq&NVG/*5/H.#beddd\rƄ#Zo ƅX#zBrGBESu]osi](lfu"0dؗV kVW Ck`b(rEILJO*#>qŅg2GfO.ePK%!:jS>"4^K!MR4:TDZ03R1"l^ icu/h:;סW6u4E}/dѝhdA EM&UVFFFF%,l,yHY^^f "$4HC^+++vr^ VW/J 6֝TP_*#U)():cR Z\b+$ WGL\(Z(*`5($WVoG{7*ߩ`zT)"?M 7d>OPl\+$I+¨ļ% ”#t-յiF凕?xz|kN̴iqɪ!47&G?r0#\crzFFFFF XmY<3&J2 Wo$ e\XR'MI_]j1R5wA (MaYИXI,TtPHVd{#2QD'䋊-X\ NtL"'C&K/?,IR(PĊ$STbRG\G#kM=(4}M-X 3]E^Oe_3sE7Obt+ي7#####t* $K"dnn+I8ne畣|jKJT*XXBkX% S#eUU+J*"F"As\m]dZG*(r[DD::.+R`JS{B. eԟ9ft6}UT=*> V ^J SlX*SI+*BS[nDtwMiH*Um=22L ̨҅#Tb*ߠ>J+DUq9IݵOݽ8-b]+D j\Ĉ8A7m<<d{$YҕUKNRll=4kdpт=O /)ު@rJ'VVVV_'xO'ibb$8 pAрoڷ*kټTwyk{*@.u[Pi-gkwGS dצ>=Ɖeil0???Iر~75 /xnv:tvۭg_}ڲe K putI~t{9Fw.vEr~?C}r?'2P3gп7G;w]v>Y> o;t1ڼyB*ȍ:,//1".|+($J|VyNr=5rz=RgtrFWɵjm>NUwS1a*VsnD2~r%b|J;;襗^gҦMX?2 DؽL@؁'yYԧ>様w[nm~ G}^{5z~bg>i:x_?Lo}K@?CL̳>W?^^^NWB'uk~j&rZMmI?t0S3֩Usdddd\1Aĉ0@Νc 3@`x誫AVŸxLٳO5/3*WF\_k#`rf_11O__нCCo} +-9Z6_2r$As)}`9gW^+,MNNEd#BR ^,z IU<=z BlQ2>זCN+]$KbB%> ˂n%2iu)%lHgZNtّ^$lIIۏ-T%m%L.Tws"*-1]eQGa,A 1C*嗖[hRk}.ڍ iu_ @w.fo^̜/+4>>Fژ*D0%?њk*Ѳ*3II] UY*k ]i/aRvl@JF,*a%Z@c dL\^Pz]*✢ңnO:'QmH)QQGz tyjmׂ*bbʀ1Bݱ3H<@@ HR%ex-|*r bQ+ Mt倬zVGUWT6(V+VAq r[O &ij=t|ꈔwAa tBU,%nT,!UUI.DKB"Ҫ@T7:֮>f0;'ucl4pY! 4\2e׮ <{411&Ɩ+0[ؼ /[^ ,pAi/,Y "D 3] @ӂLy=[+?喦W.`ZUFFF;v d #@7,ZX@[ 9U 0V[@<3 d˖trM=L7t# !j/] H W7ui&#io޼ /X!ν2Z|]sw%@p\}inh?'1{ H3i-)TM$! Jk*5k^yFvZהL#"ҼK5kX.)*iZn )ђRk%<lgUuםV]uSTNn+%M#TyrzTRE7̂4} ăg7gg0?@DNc&Arpn T)@9_eR@t4A 54D@v F0낙Ox Әau޽{8򜙙;w@xHA_W_Wy_xSV "?3򱕒cHXhX/F?t 7[s״ʑE;BAC$]9/<Ֆ@3U8ޅVkz(~6x&ue .>6|*V?D-nٿ?-~ZZ2d*DTPѵdAtj x, tmQדP~_@XTK5p* =(sq>[#AR~}y[}U$b %Dٵd %ĊĊ^-UϲΪ+TVV-ox%/{g_i&^ ФDקT޽;%mO15ٹybɳQ+Iwo .+ OW";Wl%֒xS~@rky³O lǹ^d,d[,փTYW]ZSkTr}r:&j 04DyG5XE%KUGTf9`+vqBH硫L%BRt+}v*NO)VU❨x4b_4IXg%PEVHKVi2qe ݣ˗t^H=!+5ݮn؊(OqO#$RHJEyx:LY3AFƆCǎYOvx 9=ieyXm_t~E8ՇG{*I/7Ha?gN322222.?L'eI TtYֺ>oAzHE1ᐺDtrXET5bc鵤kڸ|CU.?J7+jBրK KzBǧ YdU%BUb(s#/䴥DUlY*\\© j^,gddd:s [(۹w:XP>k@7]J^BtiZ%######a}c$׍QDKK,G:KCe+]e"QpԥD)%AJ; `J.?D [\FNcZW39_CKrYbQI("^)F>H$т-]G=:=J2(" Ϧdddd?WVhrj-UzWXk*Y RXE9+ĘwV+iw]#mm 6(##B傌K*K %;m**uD*UrdTA|Tx`LTRE*-QeE1TNפ#='! T̾+#lD.]Cݔp]wLWWպDz3YuUEZFU7U6%R(u7\PrQ񹤪_wcyyR>B]yelD@@ZXubqa侦0i4͆@q*2 H*6AXgl#T\emȸ0d b"JhUcFAZ ]{%KV*VΕAjJ.?|P-U"S&t=P*_:\$ń*/k$5WFtUkU ARW˺xu<@+?(REmq%vTtP6,‹*~ D.G2E"S J+,jdTx[ɲT=t5{ZEԓ }Qdu=,>[%wJ,!.%؛$ך履ut+qݢJc\Rxݺ2BW3eƵcĸdʎʏ/Mʐ8_d b"[O`bYINuᒐ TA@DGȖ*zDU@ݿ|Iljv;^_ZhDx^.>.g{CKSzhMi $'gI金2IjK(Ɗhmp. B !}ls(I,[_3O$Bɯ-##bKGkoxҦd!rPDt ##cMd ##JYi,2t PttP) f["Q4SGR+ $c^HrTŵn eւlUQ,JiV׼7VVWu%LFJ^/c+ȊwC'DJt'u٤+qܕi#bTzIW+v84;%U_)VJ J]Y)ȸX%#Ӓ!erـђ#Ӥ5|6D>HfVuF?YwuU[*€l{@[U(BNMF*칆oS& ȉwtxdžhaڷ{;OSl:juSQjXtm[dkh1UTvdKb 8fUx7*IU-N V꼃֭|fĂk^~P:l1Sxlgwau<Ν^$Ku!qѰ~K*xK|#-ҝGSPK.n?D)!PE6]km}tHyM'TDH09פ[ 7Yl3q`4nHAҦb4X\W\y79/7|]읦oWhfnN?GgJVZ4[_,iTu۩`ie]ӊ%JIIGh|3IX$5v l쾽^$ D5BwBIB# і-w7uYZZZ;vhnnJ֭[Xaȸ4V(7J#Z¢4 dLddddnw0Aϯy5 nW1 B r_*R/S*4KJNCNSђ@ey*ȔtUg|=Od`E  8 MRP'`XAlb ci'H`";0ًC4Vݽm/[-,s stlARk)i T4NU 㨘-R[(Mc`(Xg+o4]9yiz])&GΝ[{zdA,Ν;c}믿A-ڽ{_}^}5GMgΜ)n^fԩSLn޼ M&~#?C\&ر&&&hzz611厎Rs^]-YӪH cxFYʨ G~:L$$);Q$>Lfddd{d5:BčჃW2afUZ^^{K%f\^}}nGu-Pl*u!Y}+In*@ϕ뾯{Hb.]IU>bIRߦf Ttݴe[b$~OTZz:pKf7B7J*/ҙyzZByMN+mYnZ.:ETUY݄O'|Ҹrw_ܤ QeNdFEX}h~~lĠ˯q2{&m߾Z$"/O>3'N~I*Hc=]ut7ee f dW ,wp+eJlF x/o8OW&#w1#s| }W~322t?$0p 2LLF T T\^du5d *|3.OpI.@2= k'ιJk!/n#ҭ ZҸclL4H34Zpu5O0< WVp!c9Y+tX-(%ӾRCr-UJ 7gXeerA,n+h"K$I)ay7 O2!bEZrBTXCUtƇ$Vܯ-]I_Zފ׊g  %ܹ):tm/Aڹc;m-[7$m۶IZ,vvVMZ̅LO]ǚv =f˕e:uvL.BA8kLTUd*YЂ+DP|rBwseIa[AT\q)݀V 0Z L>AMv:FQGYX=z>LPxMb-1y\|@LOOp e̬@`pBFۂbcCA k-ZRxo喂Lfd|d;{+r(pmfb Wo߾D_78={v%w ON+&v7\;?}br {gPgYvAZPIc X'KzxrDM-XBP1%SOJJ Vs*XϧJ.H_5FliNlN ;(Va&vrr qǿe&^+xGi˖,ؒŔs6%w'hٻkKh[*yYťՂxY'g8(.ڊ_ \ŤQa~t <|œ ]BGPt^ǖ3>H[GWdF@(n(g}3 YaX\{N}9APZ| (mt566^u?/{7 ;W0WqǏc.=r]w{Ѝ7uם,V,F^DhsXm8f wT4&ċ (vP@u_/7:₺CbAqA 6W|lRo+XAу`32.^};v>g~]A1q}gwE$,O0s8s'UЧ> w}WTvwʄ/(HVX R݉'襗^61O}cO~XңdɫU>puXɬ#R O˫ȓx_%DQTK$b2dPk"j˫F'J > #^v<̀  3c\X9zݣP1M,AAٽ{G!meFYv%)_zU8Ҥ{ .'W?mnf!D*ɂdY`7" -ctnzh:]zgN >4Qb j!>A /e݅XČH'MVX@8@@9UC{w lڴȋofẍot E0CP /QƷ#GЮ];馛ndw#)x(B $[`sN&3!(eŪn%ik3|۫qƕfoL=jAӂsO@ `y K^{D$+Ah<3LH=z>ٍȑlbyWӟd)o[喛9W3 c`bkN glѺuV&`{y&rgx;O? G,8X<ēmd䣉˄~pjjuhh'6c̙*#ѭXUm#ro9|*Z-'=mX+'>PўI c"X*OtOhIX"y]"St*!FrdC+(X Mn%}dxP! 5 ȔXRD#S(]ufry01q]=䐷Qj,k7 :({-[qI0A_ Ne2Ⰼ7Ѯ隫2vMRŽ*cO* 4PA[FPZm&SeWhzv<|=:VRA,F?ry -n_ZK4>o_9H/`"r-h-q3zY\йVg&2Pg*2.j ,η"n@Ƥ7)m(w|CܶX.s;g96&-EʮŇBB+g{[Y$ I^(;dI+ukY;\ )u{ŨOUvb\q~{Y5 [ dpqR`A аTqeDxj^ٸ eD%/㙑qqa-477 :HOk.nCl޿cl!cO b=e S >mv-GL<E|x//1m3 ߗ*~r 7@]+_BᾞyقعaQZA{-/p}*zkSsQvŠpJ詳w*-PmDj aC2mEDAR"P*ΉiQ'$(6hgA 4>6&| :4[ԯb"\6! %4)╽Xt8Vqс~<"' ML;2Z#\pբsn}{b {Y)=;Xtgh堑#o. z7 B}"7Jo@OϹU׭a̴98 ֲ'fr[*ȕdy {d!8\ɍIbfF.m$r8-#Ì fR^`022Zb>҈&3)+aB%: 4.oY̸pa 3bSWHr?O1 yE@yA[:8 8 kAmɂ1?AO="  d0ٽ=`fKR*1֬w HSD& kvpߧ];ګCะLGOoc'gsV[SpU$V(`Ľt*W0+z@ V-fKj` , 뮻!?VB8<{"DiL~v9 ;wO6w(8}MOOY!&fPfQ dxvv f#-f~2߭ |1dvÌF}Q6clVHbLH %}ґh{r[D'W;}h b u5fЦ0iF;>nmﭷ*Ы#qx06B[E@de6ւ$X* 쀫T 1k1I\hTȸpDw7&ENv!VSN>Fu@М8qǬ'5DT7cIy|f W j'F jIɰ^g޷#UЎs{ЙWojϪKB2ȕ%DKuTF)kW ɹ6m|wWm#462P|,Lx9ep_#"cQU&Xkuz[y߱f{^$p#5+f~(˼_;.gSCOK[$âHߟo})~IVaqw2pݛY3CX,IsPO8!耔 ٙ~8,  :P~aj&tE9|  @K<nXu 0upf෍s( R!oawɞ楥ꀁ X;СCLf Ƶ^{-nA`6 myXU {3,D@\}!<$r|!dk| s]rmL$#M7$pgg2ax6>7%id?x'TTcyn Q1S[:啖K&< W,݀*4ҿQU.Х?[~WilDuT%,qtGi*)tIInr\n d+߻ QFdxx]uDŦ[ N35D Z ËĂ>hN)oT{ q›)X-O굽%Z A:"SV {ްB n7=x%:6%3 N3.H&+[۷o믻$˦F>XYE5{*%"ᙈ}cVURD[w6 zSg6גS"eD?wIE)ZKʢS [,@@o3 47_-Gs f`)C~5+D1Yfg~$(gb>(_f 8GS9;ߴ\IǴv=Yv9k I톺XNn$.WRs^wr`eǙot=36#Yny!}R_:ȥ iw-U22=ڌTkK+4;s49K٧A*eZ;:>aBT]&X,Q&&ǡ3B9ᑗ`%av]{`_;sX__ϝa%:l ;WݢV1g\͊w̲7KޫW2koMҷ|Y(m'bɧ"r&h[ԉ[24薃t5m1 A uI HʭԲf> N1J[|?C}Z׿uJQ4?@z,U.(,[v1Oj5pq[ݫG%eҪGdFʩOhC׿uzoX"Y:7jKc[)[n/eku8:.N^R2p1傌 Bd;w] >?ߣ/@N;R57Ol׿)$/`ܲmZJ;2H~?8 #`lƛccCs8[ yDy%R:Jq98Hp:bڼ|*FuAQ?o(:qT*3f\-A )bn:ڲuS:gyUP%J'4?mgВ{R_%܋@hT9OeI5efWG,eur꘸0K+ s|xƋ}v{8(⹌LSUh,3 #8=҃@u|#vс3Hf1 F ^tn^{'%P|dbYvm|,ClQ"p㢛4ǃFV ҟ/ĸ4*ĻvVO2l. kPK am<c%7$(]{Պm9+ZFFF:!##=ꋴZK>:cT?ne@@,͛Fh1ںe-q20'@(lP& @i; *aib;3ihe4K@8F:#X)ku: L {\0sq2KΜ+&ia~4=rP;+fl/I7]#;TjoNW%JZ;,c“Heg邼wfx3,XF4X-u*ڸ +izCLm4Nz=j_+gWaV%ա][ʦ>"W2hE[cX $ A R'8Q "ք<0U"g 2 f.֚qvXzsMX>\1!A0AsA{KITب~?AOZ)ZR;8h",P6M Ӷ;n^rf^3 +} TT5M D6\c[K(~K2(KXho$RAV>7Pwa &/p MZ?l4A786YZͱ@}UGP NHx*YdB%###/TVv9d  vcRT :QÁWz5zвX)ijhWm9%X đuIvUl6fύ[%NޜN5ZXQl[OPn(l23;OgL2qdjz-Qw$¤ o萿u Ak,3%* aKR%֣Lأ?r`x5h!-uWNJXP^ ٺB^(R0ƍO8We1I8J_I~b6o, v9X'NHZ8]bێr+(+E&Ǚ\vkD8dsEB "iiH"k+|pJL5Y8/GՊV…Ԯbܔݘ# V*ɤJFFFFFƽgNş=]*+qzNƩ2qn3CLaBXj7#---E n[,,YI;j1ab') yVa&fd'|!԰+ a7V6Kv,NC7 B#x08;,o8|? ;2L% q3::)AW5-VEH1lڊX = +I2\iFBѺi9y!V<y;ksO.a;mb9r‘;x剂F3Z o;fnb)Z%Peaw1hIP2~t߆Q6{'=>7͆a¦8{W+ɞ 0!/1MLloMoOkE .Ήa,̰LOg<2'O'80,M[ #?DwăNRYɓUa:Wd]3(rYYA5VQ5J!%]ynϏZ;) \Dd~LD ĄJl 4p#̾97;;[wbkLO>,a>_y*,Ni`NtˆHEVfy'smF5 Ÿ.{/qyrfUцuˇX>ݣGL.tnκzwY;֙T }gk KҙS399MGwOG%ZY.>4qM娌ii\Zy@I!q]s;nCL秃5 *oSlaef4=S{+݋+šWCtPmG$?DK1OđT #+Km{W^  I"jލxп$ -#rŊi6V13bṂ>]878\~zkh۶&'OΝ;{v>ha_ B_ytW/2!~yYaBӥz!0ps- ɂwKQO]g#e3 ^I kRG}Y Huˊ~IN.`Q`L|P; xi$#>ȍG~& XG8߭uvlʄ[f!D e* W$b1WsbR%##ʀY`bˎt+%Ens:sD}NA<[׏?} R+*,0I.[R,g,P *=y, v{HaN`qֱJW7+A zI {B\:^LCD12p" m9ug"34׌U*ҕm5IGrY((NO9 Se8aLkM6amm߃hoˀU=m RlFPxR{xi!IKA8y}qHw:(spm n]_e8Ð rʗU^Xqm> w ,۶mgҞ=~>K_7 L9I<J;v-[6sHOK$#G~:uTѧNqO:M܏ҷ} ?Q\O>HNI\s5++w?pu~rg[exJa8Ss[FM9JCM#|{Ѣ8q?Z-fHkf;!X8(,.-rgYc;~+ V~KliO3esّ֘@GU!ōQv^3,4M%v)&0abdo*8⠽4?7GWooNĻ}g333l5}g םw+ʅݯS[\JPcNIɔDСwαcwSg  )8f?Bf7RuWD@W!W|_*ΫDAٗguWNudAQNFU)jub!L0:EP$D^h 9-W4Ph${D"ԩP|$ *vp^ka*h OOS8/}-"V[iCY$IRb%%_<5Dxњ$VV|g>E>۷;q1ڴipy];q[=zؗ|ٵkgqV trs zg~gȯ~7Fă\ 7[fqDɽlEg@=@qOs&*OoQ?NJrФ yaCߞOP=P1Sw/|lm6&Ӌ?<3O9fhL\cDŒ/D= 9zfiPaQbnfAbqn-Mhltě{҆If3!,:75abPqI fb+&X[%3@&gL ]AqgVljgE9R2..eF}rAw:M "[hD}R88U*iZ9X0`ly흷YWX>Tcjl@K/'N:>*/gh}D4ql\իJ(+{euIjrQuTSJ\4FdQP]VX1j2i_U*Z&ZpBNBR䬒8e)-Ĝ 3[t&+5(C.q Iؙ̗8-HGk?:5HGK仈U:'L`۹(8q3+ĊהȞsϱȀ+X aVC 0Zŭ\%L(sUW+03W(\xd˔C^Pf l_yYxo"wZm<1jvzz4Cq`4P阹[!*/-\WJ]-Jw\3ׅs(QGu*n-2BxVJCArYșGM[0"&!p!֋'lC;"߱Gm'nhL,/*)EDtmfB{&bTe∌Dwţ0sCТ߂0BBY/4z7U*{i׮]ÍBM7H?&v.9]w-}s}^? E'>1=ē?ez\;Enq=499I<05[na!_IhN,L 'gKkZw }!;7WuC;ě wЎ&elLH:\ګoI Ba %(&V xf)':@L}CJbNLqHÁ),d(zc+eǏF Ĥ+!jq0 nAz 2lV/P!rcs)#*/OJhH6`@ۣ22.UL/}iϞ=م[ G)bw8_p!u!ej#ƹN$>do};t7з0)9$ /|#^}U?C̏xrΪY_,+!g>iz']!%RE>/w֪w͔Ց*Rp\LS'k qHq!Oشr}}]H( Tp/.<9u\cF4]C4v}-+:ͼSP:I:CQD77/y!bKWGeҦMT/kNo&UWg\okP4`#XXt+&Ѳ 3.RÉd Lq RěS(3,|X ő ʺ\X@ǒqj^D;6 R>[oG֤,CmL`̝2V`o֛]p| VXQh(XU(OZ.,YDlX3(;V@o8l B;1LZ!oF$s/[j8XXȅ)'Ai_^783v&mDUaXq}bL+,(H,xE plě{N 8_lڴ >^3gβ%|{T{ѣǘ(< MkϿHj1ɲIaaa]29Sɷ=$ >$B9 Rg~AvQbn s ..w뮣ɱ\>+{gb 2[K ȮӧD@7o;wD.?𖐲 9+*D@tf<ѲMv흷h1.y< nW B6.ı֚5>j*3gpaѧhh{A/x?l>8F[ t'v֡bf^{M&H,+.(8JG4m7[FߴHp|f-PV+hU`ۇt׈M\V者;siZ,:d ŌdB8rFsuOÝOWǝNI#2B*^6Yex];?iKޏפ}(+1N.tzJ xp-RW|[$ n,23SӋ 4W=wj;Gj1+i,A@Է2 KΞb{-f2,$sqV'L8,lP''H enQ"cxȏ2 À|8 Oh'ܚ'1Bf3r=kUp ##vLXڔf}hG*n?#|8H?x[<3lafKU ˋ{_gRcq@?/ Vwyovk/)HA^~}%ݿ)7ɹF`e%X/#i ֿYy @t_60BQP?M-B^eS_8ISΓ iiE[4X0}}4uv߳#4{ݷv^ƊٌA;i "ɾvT$XhqTA^\zj̚:Fպ뺂OQD)HU[UbpSU߲G 솎W.>,7< N0wni6VAPM[`o+!s%&M}, `5;3Ol`?w000,[,@;w' .*xx5ʒi+$Id1$ xbqmeܝLSKR)#ru ,hbo@#٣`C* f^)X' Xn? CfŀoFpq>H9r;1e;:Zׅ7ܨA:"~n4?~+"J!p#<_/P7woNsDN7) ܃pg`k eH%_aQawL8g\ 9ivvq,| bm)pQ&@qn%[no&fu#O2@=Kn3XH11ΰ lq= = `]  ,mD\WyrL֤AxU{E<j#UOygO}oJkLW, Q$%;g˕Z'|[C+t h{wSXw8˙EBZjԢ< n+9+BD1ܢwu?-TF6Ӯ1Cxc,e,H\?}ξ0okt1?)=Dq̊ (ض0Σ# 57 < B5bmP¶m6SdddhF a#O\a?.#ʴ'VR垙Qp!.GzӺwn{k+m@ܲW66QmJ*tx>q(1HiSsuIg\R0+6,3gst1^*%P7`#1eݵ/Xk8Rd&D.`LgQ5I -uc+6;y[vܸrS]ڏaAe+V9Dbh"?ylGA>ݯԹj ".X1Ap8p ed\8H?(w&\-!`%=GiPܯ+f6[K!XU㯌Oy 70y7 b,:g.'~;O!={\@ d ކ{ц `˯%TZgdoבA.[Zp%/]+lq=]h0 #;Bw7bۭ* )48GXɮoC*l*vߵ6]5Js -ϭ4ivht +5QҖkit Wr-Yře:YZ\Ϟ#U\?WCZ4mc&ڥP_H H8Cd RDYk啕 m`tjQWU@Qtv+&nEviTԺZV)d:i/ʧiW()Z݃0^! 5 aRfɓY*-/v:Z$P˦%(>ĔX!mݒɾj>Co3 UΞ=gBlZݒY'Jr&b*@鰲ݻj-4r#(R)=>ӫӧo|q! wѠ]ooWV͎6q㑮, 0k՟Tl=~tg4mYK~Dsq5M#lRG,bdd\ `wxOò?<go|'?ĸ,b:2 ýDM7 d X{4׳#P y2 HKumq6do˖ϰ<5dW5C|ӆL}җ(귷o-Sk2xa?'MYyINIZ lɸV LU=uN,1LG tuڴ(m!&UິH=z]0ZtS8L樵ԡaht :\ M:iZ]4{nˢGR*U)O36A;r)T?wtq1I`qh , :+;er Jƻ!v>qMRཅbF:p8N9q1shG:)9Ywzy% &^wiZQ^uK;@MC8v!aKLaRU.mPK*'&8L6_3F,mT}tݳ̛3t敹BSTL Uôآ`1p? o~T2OЦmc^Ź%Zii^vY6R3,FJCrRC&U_r`0X/eLՑ2Av_G4HNڿݧt[$ש~@Hg| ?NI>nL7w!R$${JlVit "AG!RHۚ \ItEV+$D'z76>rX % qT>v'/Ý;1. F@pM̤\NCH+ P@r@ rP l15\Mo UW]JV҅P@e12tA RV.bV=\TPl!1!ɓ !(\*`~{~~}/,W_ZN U[?yv-kM- l) jke3.];=z8=7Ħ ,iа}) U` 5> ֝ {W'`X}2A(.]+hOHs._!KqQ>T"##GX kVۉeV*,&u`A?sN;s<xGAS#Dڪ  `1`i-Pw |we qAzDi 7Ì \pUz{ |ApfĀ )1QGטxC~D/dbȐ,Zܿ*I3!q`>ŸSp `RR6`gsAk;5AlRWo_#[l@wZ}şt V)'(]Z<,b6\.e"ҍ)'5,|pWHpFgM1ƒ { xdFF_(-'Q\̰'ϸV)}vYh iC3Dw0Kr򲝲%e0$v]:nj;WܲR+ؿ'.,j]{>#AVGO_x.Ѧۘ_^XEjɫ"U{վ+&+t1mZϖ-lrps?pWALDbܻ3tIZ^b _ +ke o5mٵ-Ckv2P4ܬ)O~h(=M鉀tMDDzs]X}\f=єSRHh5I_|_ysIH?&^eHk*]+I9v zJv(YDDJd!BQ ͻGdǶ#:lFnږJ bEo> [^Z%] pnDZ;` A ɫVqs着e) Uyr`XH͔oUy֯(k%DpDHJ\Hy]*O39ÊO=ڽ4y&giuOxֱ~xjT Zғ'ק})r͛&xY`~}}-)צAQ{A,ȶaZZ^;Qh? oKp7i:R e;j! ]qQI Q|U7r|]}F _AOYn8Ϊ#QN@IE_9!31Y )muy$¬^%Z1Xuhhmc %oW;n"*4 /3yQ]"V%H&Ax^*<-^<>a`!oyf*½&qf%~Ьuv>_n5ٴǀ ġL{s-ǷՋ0-+ $#_ BŐ/ C0M^Z4tʺ& X&lc\\ ^y8pHb0sp¬p`Sm ! N^Hg,s} O@%\=s,e¢(sP[fFF;&]b36.yriݯ)t VVʢv59ޒĝbobdICqڵm{v=q4=ڋ:֤L˫4?=n?'@h;!qdzܪD 2VO\ǼN@?+[[mH? 3fhiqF V)/| ~m?B@X,łhK_NH״`k/gU X.ϸ x *wR ^D1! 'kC+P*oQsuq<ҤL,Q[[,R//!;>@cC>U%Q(T> b6}a!יvBo-{(uĊ8N$rٺ+UYg83T=>#c}` !Z($cc-))+&.:&mHVKK%R%fE!r%fjzMMp 2UF̲ v0hFpJԌ }XV/!#}{{rA/-e}TqgD3stj{!h|xn>p-A{wbpvnff zڼg]Z[UXONENrm9BE{cuT1KG膟O[oM6qC/YϞO<|X8z,Uu2gueÑ^uuR^GdD KZm)xz4wx aAv*qDLD/ #z=J#M$AAebBet)_2ߝ h.^QxJ&Qu#25VpB,97E'Ogվ^\^MnK{ @1[X ]ûGWOIpFF\7==MN1R\+ݱ0FItՠ M O+l!VsybP/uVr0&?+ α`|1j_s9>6jkvd:\M~RLB gpVicI33Rӹb8$Ұ FbxX7##=;fd|X255:փXdE;;4=?F%%>aբ].Ϲ"No<]?/{NGƽ<۶S0=OBqV*Nߗe03A^'vk?Gl"U0طhb|uQD}PM oT:n-g]i/ lL+Pkdo4]B ^J$\9~+.ڈEq0@[[W}~ZSJ(x,q+P>}kKZʺɬ"1WU);P**$13Hۃa$,~zYc2giaq>6p!w۶;hמ$;♯&_NǸ82EIyk49(Ũ;^{赬p>{R2.9`I1,%)2q,^(!)-_ܵ2*䱐Z]7@%ńO `BKn}d.AAl;|mgre'GCcG̍ë-V) RӢ?#Sq>p$#OҦB6œ$P/}ȅײ.6=|8{iǙ@Dzx?z-?]ppitluc$~6KY1PЏgDK/]샟wNg&inrVͪ?liBT1wa+ݔ(ԎP鄱bc nlB[D[o?M[#>9y~WNI7QDh3!4ʮD~M62H}c֙fUOO/j8*=}RJaP 'LؼiRRS ޞAH+y+ +̈zǁjWZ/H;Ha+U-]Ut<ÔTc"PQN"{2lj/WҾL$B{s4=u} A)>eV*hR'hMt>Ooۑ&\u#F?d7#^e ~־E)*j۲i`[!/o":O29ȸ2+{K/\$Bfuĸ7^&גЉ WȷX ]R-IĽ [1^vbu$ѫ}u1pfY3t96qĆ3.Jq3.Y;eB%&VGr/=c8(qfLeai=~U:u`y.>K AnV ¤ N=86D8f ] &VsPGKZ%hS6h*1H U()cNm;WOiV v&8@`X!~++mݻwp<ND/̊y 1R XRľʑ)P߱pB.HV['(9IB&&V½YjBDQpZ%wFFF,z{=y$ ' 򐃵*9@YR9G[788&[Ш"W8-H9VGtcL։KQ ZTXe£0)mK"mG 2c6Ÿ hpز] (AF3>Jq2A^&d  M&zL7YyʸnRtVIylXrmHMD.`Cz/-q A7˔/X*MNPGdJ'e^5>V뺶5 ۊ8YQV%Wj("tz2|p ?ʂhitdĘwQ(#%jL#M$d1Er w8RcUNcSq/$05Fvmb}Jo*U "FC79Jb >e!H+dٕJykk*_gFFF7oqyzYw:۴unZ3hLrnaf'qQ%hAt+K5!` #]8,2 1$>,U!CY-A&hG` WZPXj#63oǖ;͔mxx8d|(dJGOA4x'E*&U,ɂ*Zh@ \cmU/)XmP8ض^qdJ'l :\ևX@k]^Z*)թ@uK=' %xoB儡 k+8%;DA#]}@u&x]M\ss &(-_m_$V(>*oҍ\\ .@Ν;讻z [ gjVwCZl`־fSR:~,[$ZK ]/Xv:vʁYy nնyK쬬0Ajzjff"b#>\ҥa Ҧs |ې3Ȗ*TȸB~q60es\i2lOql`|;w:YU%+XyMJĒ2mk.ɚbڴZ_T<|ʌsOWS)&&F#*VݺuS@9OA^m_e^WL)<ɚ9w} 7ubd 28(fyzhs/2UUХF*e*02 ԭF|Rtd RA,әmtRDg'K TDҔB簰d%?NG,[>'.>\!^ދ_X*#c';.u}km (<ݶm/f2$o}DMӱ+ظU6*b34,. ~e݆֊eC9 zLBjCqpǓ#^Ҷ\kIٹ9^SD㮽_+ + 0F2Qh4sMk366ƫfdd\!8u,׾cbQ C486cVA74@{ӎs}㤏b;P޲=R >;Vt]@ږlT^#Q1^Tl2u mZ nӦ!UgKꃤЕXg`%Wa%T.H9f\~*)WTFY0*L<&Bo$$@m7c|`]ukQ(9:Rg*ju3~dQ}lTBXBO jbr\z[g.@j7_[smV9}cP#+X"?44hN~) bM)-pqaJ}U{'FD`̂k btqD#]>V0B*%[:!Is mda~gfhvf&8YZo6uKrMA`0%D7@;d+ ҡ# qTix< +Bپ3la(RU+܌3N Vq oZdNI#_k#ɩLܵk2[0,TDfG[Ƌ1d뺤(-~ĀjʍewD%vzu~YY^epa-@3WB⻋nΙ10FrKDWC¬W|&(+M$2[ ?̒00"=*yA,gkr3PW"R@X1mX6#4fl\^?|f+~rU=0Uܾo7HŁC'Wۯ-;gWwu;c4r5cuZȊEj{+NcƎ}' :mێ[ᠨҲ3,9An $u߬޾ $P%.2)Y$ʿ%ٲ93ֱ>㣑Y EmjYeZ$H$HFzw#nͬ^7G.2##"###O 䳘 K$rdI[y!% ?aĶx)S=$T*HSx3gymzԣݘ_ mL,f&eq6tL7ᚫYkh_d(fDʹaێjE A90k?ev$ʸ@w&qeAc&d¢)zch.uր 3 3䣌I[/6Q:vzO4FXš~:ƤKMe+[EډĬO[ D=kd's󟛣4)B;F}w=˴k&=uN%_nO<0D{F =T" #ŁI]\@z/>JP.BdqTnE._KRXJ{.Kj&vG[fFƁ4U\ ǖy$ZgGkJ@%.Jpxڋgyy~ T|& .E1DF Qzԣj~ V*%2L#4wy˫Ԫ~i}>[eeʦ-KP҆Yrb}<@"W&o c,&yo+7Tahn|Y\/&qb5].J}HJ_Zx T) HkHvR_7%L׌s۫(K Jj#}GAFFJ,+r^ 1uL.JB{ tiFCd9J uN+Xӆ2F5F5%/zы//wNcS8w&jtmܗv@˅:u4mݺ.^DԦubbKCCCԣW0}ڗ+ jOi<*Ojz*9GֿH_~ s/Y`eZztcFH[dD 8> '4}@\[N>!Pkib E1 Q✸o%;zi##H}GV#<89!8JvqG28ʯX0߇2% O~OOO488Ƞ&('~zԣ u.^X*[FbL:[ `l-'z]i/]Ev.4^Њ1`{rȖY"5&sXZp>޻76T!l#t̅do#ZЯ/QU$:%´騫๞hA9K3n )jțG@/yA RzB>|j6Յ_ODDY )&,IZ-0 j>xC:p/,;6~zj[(8p T/Pu GjeX39a#j}H+DiN O+t6'O?A{фC=DǏm۶%Fх ~Ν.͝>:vȚTì=zsʼn}ִ.kz P#n WݹLo>PG^Zo=cCpCXAvNHLwI/&ɇ<[|bI@gpu5ibo⽰ޮS#rF1PJ*cZH---Rmeѱ`%rJAAaZ@eA-`Cpzԣf Oqb6#~UCgev%s&;˿vo-T[y(ʫ R/ y|"/#CK&{y'!:`buf&Y?UY BBh`^I|).tYfD73B⧭!$PB[#jXTjWY0&2trEz"r)~AL;NƵ[YKW4~DQNԆ:)jߝ<3V8X\\^ӳg1-իKg-`RuX$oeٳg|P~bba>СCO%[wk$g/թ@Ajѭ;Ku0 P_+_zaO7z.@7݆`%E-Ai" Hz 7Rmբ-dN)EvT(. HǝU%9vPD}}V R=. 5eZ˻UA_?ҥv=ccr{.IwX*=Qn\ą]5-QeJT_Zq໗'sV8h,,{PB(g"V)ZV0ZAR`a٢-%E"-v|$e<˩udPT-UV9 r:fBZ46ݚk,nyCWR]0[A46@·١@/cmzlЊV[ D&w 1 WztDRʺbdŋ&JTߜeEI4)Dj[^Yx.\j={44ӏ=a?-!-cqH1 mm.0Ơ ĺ enR՗t IB'@agL?W_ &vQhEwqpV\[xHPI$m6,+T %/օߌ4(AisZ, r}4]4Axim44R;X73*eR\B!IgjpŅ9_}'tpA-YzL‰O2LLz (J($cH$n' `r>Dt뭷ЯB r}of~2=筶s#7^]t~7Ooy˛dDA{p-?0 Yʦ5 }Q%G\7UuD +-3s4ҟC[k z:$ 6ȾsĴ[g #4sjvn7]hD's (/1bbx}) Akq/mgMY!n \[lg:/*_719'&9b(.#P>ρvg$ztgYGlh$g)aYxXXY TrNu̲[N / qA*b+G,8.A [J>@(@I$\iTr*&hݴi)AၤQ]@wIMIj]+VN 昮bfE .l+MXEῶ `'?QR#EZDӽvG-PJu)!*\&Qkga|$b& L!ٽ3((5gpQqfqV[3gU)%ѹ Sj괍s"Zvȁc γEQSD; \m)23Ekx_] 6ַwp7 K!_/v]?Dzcz{c?`ׄ]aX#?25۝8rStS4W-Cor<=qn~m8Pn,rfίqܐ6q\brAc#,>\Xص6EDݹK~H܏r]>ݧ8VK<>pDaHYhW%rX`M1`8U Q1ZTH\spʼnk/Ge d3p2!=dv{t=$sW ːY"` g(PzA{NdĹ8>ȗ' VjYU!RvcP-}"*-C5ZT6ku2M[h3hs@? ԭ[:<) ֯| &GW%sRIt?RiB29N6T/FR*#@L\ۮƼCI.X}?tI6pZ*E?Qer؎ ߋRQe  3f{EY ]tϖg~?d<ؾuv: \^:{5χ 1440yn&:{cJMA#_6BDYh#SUH67t)E畠;Ӈ?Aտd\mD~CtvIO^Si²;eȨD)_i0BC\O;gwva2'RJ O(,^@I@c8X N~$tupqEԮ>R,H}1X{ .= s!,!{.1RZt?).VJҤS^jUz;Gc<Ϗ?F3ȇh~WG~co^f8kssv7xnBAӣ4H>C 5p*KTkhuxfM0u1J]0OE Mㅍ J([xV{J,F; y4҂!2wif6 1UF{RKQ2SVS6FHvN`%.(mGJ4 I @ :ēDu  Mg ;93¶Oy^čkϺ9Ζ{`Q(&-V|KǵqO,rzHx 7g^:Yz)ڿ[l/}#r&8XC"C=G:xG@ZX[]Ƃ*.xeYA6zH+Znn@AdH8[ +Pg.$Ȥ(eS`s 2_͠Mnhld(,(Ϋ:l.R7eoDO|hCK,q(C.Q 9di!BY1S#k}&J7$s8~"JHRd( <+sL1:cxQ q,/Jmg2kMvQLc$ 弤AV\ם=e__ڗ:=٤=B/MYxi0*^2 m]2A9ZriԣLTIX${<(DXut%@K dud)>M` D,X}{ES{U,*JmK&Cv )aL|-6sa(nǯV s*.vb=tKt}o/!@2,?)z/'?gm =fmۨu!>@ ˍ@2f9+d|XoRKJ;P2mIw#uėdf2@AZJdƚ;leָXIY&$"L ^YnG;^vFԦ~V;&Gmn;ӌtEE]x\Hw< >"ppNB5^̝EO9L(%ڋ)IjaP]Sfm{ uؿηб8sX FL+JɾO͘P?I&Ts kb \(ڣh:GB=xt8\{.?74$S@Lg*dMT/ E)  XaVW]ݕr%Q!ej=hV9K SD%U`ĂC7rlg/›yg+9pHz k\ "GCG@/7\~lrr]'Zsl}87>>ڋңMC̣r\kGB*YdiȀXCT_^uiݲ(, krIL J[ ^s|\x} \+I'2f,@AO)IgI8B0zEFI]I%.eV*LagFD 0I++*G ״889l)%IR7 JɋJ7;ȺYβr<ꊞz")_\8gТlM:SPa|4t^ڿoOӛވ.NQ2i<0u;1VrF-CKi>bZދNDE{t3A6b`Tzu% 2TJYJ’ėkK9,*WʕIĭ56IVߒ}!7T(OPAY\`(B4QV,GUKTp+ GC_PxI*OYPeNn=޺u Zs|iբ??AJ3 m.8+rAd O1HR*߅QYG\R u| 3 sVXq!*\ǐ㕢Mvq=w)!nD8 YzvȨ=KYo5%٦b2! 1+E)&fx.CܶY仴gb I l㒐BQ_Gk] QYSb78N1 DI@̈/a`M]0`jĴ^,$+ K U*sg[ط\A6nx_>Ml\!n[`fhbGG=9Hn&l@Sfe\B3m(m%~)[ 8,i z&JLԓTRe=W{ 76:ʊ \zrIƱS6~|XioIs.zH4XTehef-/RREllj r`BI )(r)EI6[X|DȠB|laL=EIN+ @HӨĈEٗGɳDnE&Y(L /-BѺWeL`H>O3>a03;`1l(-&H.L%5O$LrKxѧx S8-Ib0Y23nbh࿒ep}Γ˳_7j0].vmiH? H"o.Ko FOǏ0 r&5~QC =Qzt(- uP$(->PH&fA1+*}ݴkNz'B)veEXS98x+pZ]]4[9泞KO\R}eSw(?S9  ,z1x"{/Eފ46#WZ`/G=MB*nϽ(*><WXJJ TR2]Fw V)yRdxLe3Jts2e!ޙPlK@f"蠗= A(R"\lt z0ɺFu]Yy}]E CL AV{#X (bO^g1PE~MG_HɸGqSPPEUgk[g!fjUZKW-2diU(È`Tq$sVV(GSW }cG{vogݶmA`ghVd`$5H.N9]r٠uuͧzԣLJC#@4dv~"&/2ksKL9?_ʀjbdO_^YLu`^Cʥ2od]A䋕$[aFo~$1A9@6\jJ=Qzt3ʻo~SOy+!dեQe[6D* ZٲD(R2>9$:+Ν˹(j sm;(nk!RWײI~lв)M viaJ8d&P'،$Ta/DѬkV: .&0 y+0e+;ICMƾO\h#oA,Q?X% tbrW Řgڻw'@=,A\Ҥk0`1:2B,Dʕizg1#CC$ۥsk_%Hj:Q!˄eN%PLDyχTq !M^{tQojI@I,ABn;P ={Ї?!85]z wZ+>NX`?H,n$%)7 NR$ %~P"}6DVikԁv\`sq` ^zԣLۏ[v.*UJoQ\UWe(htmFPY fFZ)=zRR]\S}rbb㠡=FJY[Y[l~iI_]=W^A^"$*EWcƺ0Z`3Җ*pI,U$yjWeCCFSGk(J1֝x*=QnFZPwK T_sy[gYSlAV iP)BiK"e]JҎ`՗VI!-XBH*X7;6:LD1Ñl 8nh:nQy^J"2tG Fb!,J)a a-W,õ4@VP2Ö{d4db;W _Ͱaxc#⠲Ӱpn- Js -1ev76>Jwocߑf4M"(WJ߀C<ظfΌ8NFc (2sp*Z m\XjG7GÀbIkM]8CDJ悹V( X*HPTO\% /Rg'hI[da b@q+lwX .Lwd~/3ygnV+5o6'|JZ|\z*>$8ʁgk{Xrr%D/$2=G=ME;S" 0N,Ɛ, iena‹ 9wy'-..={ sO'[)hzf$jrR߃=ʰJ6)D$lYS0(dk ُq碪ōSzJ^IJıh-g2:F4gi6\ aZZ9mX-U +pc ಜ9(ydu2Nآ]V_u?jg#]^OKxWQXSNYN]P7a4?;rɴUafĩäU@CHfpd#`.M1՛gj]nR<  xSh0@~arUtjYM\!QuF->fk ?%./qBi6N j(E2˛PG=kH*%$Mreuc r-h~~]E?m 7^tD{Xťu%ղQ.J}ٖ9Ib@QQRG?נlPkgJ^ >x3ۣy?$){{t`eec_Iš_҇x7ܻaZy*WZed-oYE4EcwъU2h{."E=2ЊYKx \mMU2gLrZ֢tmu#]nc)H%aUs'/F!Zof6`׶ I/L/ ~~s'6A!d(t#ʩJWԍV 颅 n;#+5nDX ӥT(mʰ$ `(6<Xh˟zHQs۶mc=GKX,ȍ&#H4aazכJW6O٢:CC;Fi)ٹ>ufkuv2m%ĹHpY> wJ-eDinZiP͂=RJ/ʷDK=  B8e\UKF >J1]wIwO|7{#ۿtog~ f ex0>>FsOzԣ$Z85 (ZvW%:p`BPUԔXhz+ޓ![`ݔP~dt̮FIg#QT}C;ǖ"eI1 >^+\ l5I;Ϋ!!ݨ1wGG=z%H=|+3>[9q5ǟOscs[n9F;vO}/;@=e:qV psϽᇿa* S|໬l+ MS`tA,;v1Wlgz*=QމJ#:cN%9ЃFJFcM:]TkdYeJMQ&"z\zΝ;Ok0 F}73ɉ \ @ABXPP#iMKbqZ9t>(m*X]/bw^,G6~ ~KnK\8JK׍(<Jn.XJY}G$Bkvzy%UFF~?= _~bҳgi[NМT^L۫hl6:}+'m䊌NX*!my:GK >yh}W>D;\,9e@8djdd(fHaB?'Ar'P})Z\:Ld(Z?ݎ!+L;m(v짋W82W(جP-ZZ3SãD=p4wV"Rd>JK 0w"I+i(0d rͰ;0QF;^銤5W`R}TՑB14x)CM9o9,9ǎB,Ϥth3@S&b4Cbhp% 0osyX_}K/t+g.x^U4tmݻkAvA>XpKF,#n9O{RVhL.zPϹ".}MO]>Vh Ǚ3/ъ, \jbn[^td7-Z եAD.hWi%=nV:)İKO1*>2DihDe(TX+ {zE՘}=w׿Zk;Az n6ju8E/> v]t'?J:C;nKc /9d,59 D'%,VGbX?rHZ})!'Km mZLZåxKJ"M k QN825!g癄tk 4.3LS R:>FV[̑ mb~&7M%^Ut?_ g37J[ '@7?+yAzH*$ӣfZE^{=uu/#ދ1,;[ˎvvk Z9ƙɴ]znjzdH[Kyzgvc !ߞzip}?Ȃ BDL;!ٳǮ#tajv|3@ (.\v h.AnV@ xlA322@ :m/@}B j|֚x.xxFx&J/0fmvSIAN\/C70Ekn>rjz~[/<g<%X قQi%^ epp^:dO㭁 }&2o DEŸ:O;+RwBKgfwn|2Pzj5X5.M/[ТE+tRZ#JK—ϝqv Z](E褱8sk߶JHur >R@LPd=qSp/L+R&Ǜhr̂*uGXIH ",ѭX!Zt րXAd"ι\6MO|zU*#c7׷e[X&fFҥ91Y֤c$B7LTC><ǀѭC0q[b4 䭮^w`  &f"`dbG m 3g*Bڮv; gX/".?duF:RbZt@&'&y.B_qMҒ8`8@l(tܰ4YOGiCـJNOpq_6rc@,^A&z-KshKZzDKG=k>m]ϱ!RwYYݿPޖA9;D uJϤmK,xMVRYy6'Ju.*kE#Рn ec+XQɿ&뱎kPV(ۅQꬌ_ReLl6oF-Q]'Ȉ2&HW@) t]\ũTLkYX\rEpx!DqhcA" SFG{$ѵgtdԣ$B ܭBpġZ\\_̓:[-,V:)KMXO_g]< W@wcbA?{ \@tz /_z" Fbo4cz뽳+i;⸤ל }}]7.'c(1R1'mT%X.V3!X#@!<-`dzyf6:FG=6[YO{&kO=j V,M-г={+>sf^A*WxmE(0JP6o#IQONQ]~x=EFD(9+\d""EA`1yejOb33"Vl9&? "`#oD3zZ y1b=f ]Hze9O ]dqV!dFF]{zMfAOb<сj.E<@45'X "^ X՘ָT\q_G꜡'+0ƛ&T7SD/,^Ytcw43Y^t_O[$033,,U+=@sXH"ưz+jf`X) Ȳn5O#RziW/m\etiʚW=w;FoQzjSѮo^^ =#9z'hGi-(W[` -MSR@6V JS VexA4T֪-p2:S JCT*|i9y qT@5-fވ -‡hvZYYg<=kgQ:HId8n9=/"c7]$D~6izMP̍ BzZk=f r\, ҿmĴζmۺ Uʱi EQ~BX-^nDJkӀ>.]GNY?:%# AZBI ׹8\(boE])}q>=cTARGNn^+852/d.tɢ_2; 9/^V Tn㙣9lZ!+oJ6+\4+po{xbsH{2/>һ.z2?tPSףNz'̙3슍{{^q_;8Aޤcz]|=t.}wMw Ϻhh4hlv>kINܴ`FZfW@L@-Dh..S}z3pJ s\+ykUûY>2M+܏-L2#IXg_6>\P%A+TI*LCT2 Yӧ6{@Rf=u3җIA-kI*[ıQo3JKov;^ܱxLH p Ru 5tB @@! &a[db@#R6 fJ.RH%^h %aҢ$]a0 5$`+Pzluv}|]]T*U,շut!\V,-'0t6d#+Rl؈YP A> -.p`oWOh#7wN+&\:v׻Ǘ^:Cwp\F;X0^|ԩSGdO4ǎGx̷o߶f_/ ܍D@w{fz=PԂw+ F<E҂38V8Fi8>VXfY :+  @B %Ĥ4/nU͕6=455e]Le3`TȩtDѷ7!8fQ[u*J'Y'efQz$A)1U`l3v;,(uDiz L .={+~8p*`?qV$x~-བ I(Yf [( M2AiP pD.գͣwIss7Ч~Gs˿k.~]~tQM~a:q6~7=)cgΜ?OYazzœwnz;H"=_|ȂS1 yyt)~'&&K_ 7M n~'WG,9a|@4{=f>H-wuv$V'fp0Uhh-ṈK 1NEb1X(M ,XX@|v +VAlK3 T:K_{ip]x]>yjN9E5.: Ad t ЂMTOTwZ,\n#Cd:~AnXpV.vQ6LƱ QJHq4wQg$e*%e+v, |[e$²i{7*F$\e@ń$J0U[}IxӨ9D2& Ih7ˌtBU=l=IO8/X܁tq&yfRgEDV*}Y$]3mӋͧ\g( BI g 'sexm߾ݞ{ 0XO<oNNNё#G8%c=7m2X@ O`W6qσ T k| UaŽK#s&M;2ﶞUHkMw90kMR'>?^KĊʭ?OϞ>I[VV}ID):ϠF]y pҘ_W|+Vbf!Oˁhs̔|uKn;hǸK\Gu,ȲLWgbRX,omnZl6mIвӃ!E7<6f3t8!2iI6}ʬ|6L[W4xԨ7b#`Y 6MOY{,<"G֟2mpBP7*x҂~Gk]!NJ ]D6I4^GfP7$MK e4( s ErNa~}A~ ;&OsG /cs/=LA][.?0MB4}XK@ֆhZn,,4PiDӚ{q9 5 OǍd%9p݃sE޺w)k[]v/q^R8X ,2`;v%wDI2\ݘ$zkRhyuH[Bhİ9'!7.KKtX}{0X@uY>G< +'{@_= $Xkx2&UC y睬P{e0 (\҄g߳ ^ulh׶I/;Mm?l-y XC_rETqv}v* Ml,^̅qB8 #| `V+Fi$[|{nr4@* V B: ko.y\hrj dkP؀$gE/DQI.b& z瞂@E'XY ͼFSYhRַ`%I%;Wh[NŦ$.\Z?k\ᘙL@6wTɉԵQ֯ R\MwJZ/C4\@RQD;g Y'dsn=gQUL ;LAj+aR-1|`FsD$yH_utVo8/ZSaP=6j®+ ! 2*.]dA0Z(2SXlqa Y? .2c #XAa4`"u J]߸,u`ȿ3,8̤elPK5) B+P+1aMYf]0:[@8Cu`gg  ּVH %Oʥ m"@8'V8W:j¤m9@@DZܽ+1aN? E9"=#30k?Jk/?̐Ubݮg'?~7~O@yX\RdGMZ0 /3~ 9/!2,5cEfB{;yX9P>uijUJ[.H~ZT8ؕ0Yy v?o?!@s13hj}7 l|R9`Zb?ɺDP;uir]K kMTLXG08Rrbʕ>˼Ux!iA%^A{o#;>Gm(K4lxE5~!Z5,$^[x=WI}jJ&=JV#}(v݉SHDKjŲL^.lx`+D=i76km~1 }Ĭe~- GY@#nܷ2n<y k`|[bkwq;]x.G\atfԼc Nf-X(ݳ3g8@x}ǃY1iAƽ`*w~- (>ϟV;DW'g?Yoǂ|~>AD@F2;==ŀE~O5}xNecut GGX`<[@7Af Z@A2Q0oc>3m5"¥W ,hq<X~|g *`iT\\a *"TX,E]Y`Jz\(h}p?K]AW}ibc A .DF܃|@igܧ\ga>8HmŚ uۄ4x$R.-gVDEboˡ-Bx'Hf\,y%`XVURDǮo%7cr_rE\o:\р<+ 4(@i3 ҄:#Ǘd֣m?b/Ǹ=y>v~ijAP??JsI?}ܣN%;~Ga@Oz;Ritb2O[9-نxZ9ʦuLA,L#Р0;2[Y[~WfD)R#Q!ٟhok{gD2&3}@X!<-/5f)%k_c|Ҟ;]UZ5gv*&$3($0IZt<0<3@¸E;Qw<4J0-{ e۸buf6 ^&XA0uaJJe%$Sjo-o"-tB(?gqXhtX`@"`?ڄ/X@~;C(%_bq}w3.n+F$>CA㴀)V6`+WS{S<{ĥvzmyŏ\11H}eV\攚-v%0Ga۞(8&185bhp^X1hǡ`q+6dzl_V86pnfexD X;s2~<L[i@jy.x1& cig-Sk˳~ m(I'KzYaRA[Z[}V&OOҙK8G6rH}aN_R,q p&L ^qriղy_oҪmgKϜa ,Z$Le@vgXLơ4%6',ϯ]/d+Y:4SvQebhCǒS3d`j7lg>(S*sV;d.\@V-cf5J!J @RhQbLgΞw/rҹ+vے>(wSP1J&:c;TЁ4Ե( $e$cRmז( S-̭XnEI" -C VsxI0x$IK.qj&O)6^ ҌB46i-0G!_nE{}%q|:b_޴q=CL HAy0TJ5``jR&vVDH hwk܃vUuz:-+EZ. 2ah qLhpC'+~o9= `"u@P1FZp!sj K,8:K6g}Q?{ BIq p>&||R}M.8>\?9$P g@ Lup_XZ۱ۂ]>[n9?z 'fm\gQuu`l qpo/}^x97W9VT2i$\gi&GGGh'v .P^ h'P2/+G!Mi3p^{ `ܶ]3bee/sGG+'ٿOPb\)"'SIJ_,d%+ (PVĸ3ԿoʻN9Z]Z,Cdn(P1Ãa26Pdi ,q%rKjIqY3$Zu#9ߎ! mjkA2Xlj \M;% wSeJy l]yŁ2gq3;Yrp1Gm:l`%Y*F!2%2Jھ(1po%0'luI٤5.QԝXcƻQwSb 9`iwqEn~-j:a֪,Mӂlyk1YriѣGRݩ┩.PN^ . mm":iWSG"8pGB\}$*(:BbH9! d A݆0CC}(<,[Hr/L?zjAp2T<#@/X q`x5Y8}&eキS`.mK LD(%! @XFM\XB ).vLK[1co5˴~]{l-<__ =㼗S2WF7ЀgeԖ[ڞx1 ѶY022$Ӗ$d$^UXlM(*xKսkZ{,=Aُ|_8C)XԨ>dx=q9#y;%jXˮŁ*{pA&bH*fڴ9vcF ͞ rJzm)zA~ZQΥlö PEIJ_b~vQGkYgfWf= pWm-R&hbE6,-c 1VAu;i'ڴcV 9*T/X33 feМ/[g՛S z$kzj纰0ejm/%}l. 3z۶mg.bfp3Aiky[b!O#tsC]όGFhPl-c2i-@ \ EcM Ś{q0KNyg5Ay-p0mWf<,YܗXڈX&^\_@!2~h!OWVJ,,Pq?wpsPΎ!C_"}eLZf h\N1aƒnA!LyZUThq2*-i[($ZC2]HHQ@*Q/j]Fx-!>f2E 86?Xr"ؾ[H:o*)fРzFK,pLm v:yE0㔛m(B3iǰR)ٺFFIS]͑9Fs,B `b@Α@t•`gbb lyD 6<Md@zּ& DӱS h) ?Dk˥>S$ǥ,RV2BIYG XINrh<9G'`IIiB4pPI,pI.XS@LVZ q,()9X0w{RN(aoFU l~] v T#F[eu:2\cbj~ #?XDI֢o|o.\࠹e'o=բMUHnPDD dx _g@SoN`E2u{6>]Cp VGz)7/ e+..k QMsa*]٥ͭ4,o_&;-pLeZ8[ftQpt:mYXXl?/^g` e/1Ђh !PI6В7޷\qZR#=F$-0Ү%\ QNjYwӂ; d* qi로s8r+ds.m ()"J"Ju@.́D̄rH]P) HU,V+ c+ kp;>D~|go񏂰aw_> qJ~ei.FEd9q-lqǚ3[GBI/\.szgۖ(6)㙹l WM-K#^//@]~.;A ~r9sΜ=MCt222mt0uʪU,U2 4n3+oICQztc=UmKt /!'_tQO?1 -@8@|Q.PciJv`AۇY)x? @;Q oiz@*Ǐ-C?Xs*bFլS3&6[!] %KGB̆:.P @]L"mhzF˫<|J.a ,*85`LCdǨa5!ulvr2|݂EYRs*hh~nCTJEJOYMǚj|QXy( x+TiN&M1Pᘦ6-.Ҳ]n4rK{W!h LϬs~q}XYmvO +VnA%H ˓Z ~yf<%6(Y{oJm&0ժBv088ĀhYwm20cc ``q-٪kX]zq[z# -<1 M}=h^`&m@o:E\d'\q3PJh p! :;dARkFkϥXHv X [crEJb#¥Q""c3x@0/0@ p) p@Y)@NO;sҥwv&xo߹cv"%S93ȀX>*Іk=JdbK @[۝/n[Q/6~n[-8{*P翊='IIJW3/}i+FҐ3O;VZ*sEƤmm&4X緼[zG7.= ]r~ kӅ+i+svݚuZnM0q*1_V'<25I-6_˞,[gr\=j֜@i H]pFmj'MMU1r44d p_Pɪ j(cJA]?_%ze&NdKIf9Elô@W&]PԅB|Yՙ"󔡅)AKٰYF gj^B_YØh"Z laD[&Dԝ?^ԝ}J-U}ݮ棝4qn7fAe[!1Np ܟE]oXɥ)Z6"ә"ef 4't+s [:'b9;00 sJVoDsرcGC4=")K\}@HEݬX6   z0O,1N! kH c,;ЖRV\jDpG7@&~ "!,?z%~  bXQh HJS!`KX"s:epq)AG>0`G6E"7 +4C-㙶 )̴rzd_/;N>UjHB6Ą[Md0TG[_87-UJt}e<)5݇V1>f(φ %eMh@l$A}K*MPʆA~c:PڢƢMzԣ0={6|g^\ME `](^C291I?c?J_vЏ([hyKX$ ,q*eJ! g") V!)9t5D*y@e5>AMom)5n$8ݎnرݽLŪ=XjS2TL Նe Tvr̜f57 k f.\QpθE)DKK7sl L"4:481w&Q\f0VQ FܗǯEE"ɞ=[ihxL&3,AsK>AF*Ec~ałlX^ו{OQH맵eXQHpchQ[h7B2'bAef"%=2VȀ,VU ܁8A].$KHF!bYxm)dee`I/qj, ,ēӁ&ͫf(xGPQ3`BL&(iP Cbuip}r"1x>喖c1o8 +کQ @QoNAA=dEO\x4);[Ѡglm =AZ9V X^{F Q[mkzj,0o#G{IY}v ڑ?q]=Sk22K/`eu,Gk{7a) `_\iM[`|7+-W+}WXZ;*C#C4™U~~&f~6K`ٴ?1 Pbz#>26oZ~?NǏ~GMCLL!W5 1S JT9¤Po95E5dVFh%+*l6UkWVk`3 f"/䃙B^97 5Yje؜=0oqy 2S}@e%NXS@#8@g)7Mz`9% DtFreAAQ%* -{@ăA;bMoV3 ^eH+k CuQ #~\gJ $(`рXaLNN3Ȳe|y7\x1q#;O|^Lo|=<7sVcI˿E}&X(sZa'f% HMJ Yp^ h7nXEkG!NMNKk*6-ȂX0g?'~?JTsׇS'GuX%3g2_jtJaP$e)fЦ*,ʦn}T}*Y64Om@bl+׾*nLgIqTM&ӳ4ͱ4@ PMIZ- R,2JT{scX4 p_s .K>v3*AkY-[FnMe.E}} ȂK\뎮0yeb?S$f֖sϝ7^k S3Mdi8Si+h7zzf.KJHr424QqWReV3i᭤G$z͈s2' Yؕ%f, 4ެPm`c`zԣ5 5PZ j)xiK#"K9 J-V $f"i 0WqdBF$ J<܃&T%DU B{R1n MZw/ZN1- !4>QhuGՃEx2&QR@v|>^vY: 'wR޷\Ֆ s?`ICPdWT ڣ)7Wd|seɕky%PVI?KJc(N!@b dH lT0),`stp+35qjvPs JF0Zo^5 Eo ~+謁:2( QAx zԣW~ "ßs1Qk~C=l~_,h\ʖS5QXh{Aڻc'پ XY\a)T.JwӫMSo>-Ct.6%>}~S9~~w+vI+a)GfU]켗dRQ" P[FPD$taEu =*\Aj!r~.F`$*\j^Œ@M(,q J3!1y@Q) O?̨; >ճ'+SWvիl{&U35YhED^@Kdع}DUN>˥utf?fB*?la6 39V88YelaXaNp6%zes+#t!_JD ms=8k=ѫM+ d?GgPtJ|AeGYnA'R6'BZ@;XH!A]E( A… .K}o¤A(NIJF> !E8ggȧ1t^uGCŲC͉|Ӡhˍ|e$ 9+NM\s?xv%wc#gu=VIgιj&)a=/ˉeUxgJ\Ң(m|b6gy#9[ܮA[L|Eںg;U*X%KqA6ZYy$\彐rz>8*ƿLZA[fбG= Euz=}ߝ Oڵ\BO]yoy7`3 Oo~GhdpyvdQy mۊ ,҈ʔE#otV6Pe}2F\[Zl2R8F*Q@^ 0|~zXC2݊cՆp9J>\飙9#vѶ-Cq\キDn*\HJGQ@nEU#BlVQ//02@)\<ȋ o 0pqdg ͙fnُ` b53\مci2nݵP5I}]knQW܍00!YE[]O% \q,W8ΙN=-0 PNi'd$;ZM;@ܹL%-V΄,r3S3TD[|YVS2NҴXzJ B=٣Ȅ ЀŰNGۏO쳯ڜ@^["wꗟ|[oY5+t\o[8thmaz)ΚgFPkƁ6)JZd8Ũ6=׶ N~^|.^jn?qƄenA˵:?aT-®=pks.Ŷesbf%ꯖiQkf2IFp7%B'D2PwpdChmIlp#-}xbA#0AIVH٨ Lie<1=+gdd$-`Dmd#.@kE&V $P,~ "^E k衵VbH6I,@-DnpAf-|K.8H ,ZB !i'u|^A$/lT-1_xN>.Q L;8IR2Z$;)[M~eωMU@gK܀Ҁb'r%n@Nb/@_UB #1IZʖI̻M2?_1?rDҖ,¢d¹$aTŏר#h'J{Np]}! ߼haFoI0fy K60+B]4I.(D+7 Pz#GsVi# @ע&4 ;f@߇SE [d~}fd<78>>@bBs/R/w'9Ak s8=Vg0!g=|E@2 LC w~y>S0E^mOщ2(9e#;G\{i 9W-u_i(G=9ILmʌ6 8@ $8.B1{bvS"7k .)ҢwSplCBAPVbQLr":blX˒!jBLjP}1 |> j;*# hE,PM߳vw1&垘8/ c ٪ƹ"LoI%?(P=]&}5Jx-?|)S6Qh[洼I֜{^nw4g.:zgc\1w ^}njblŋ욱j]\B2.rf'XO,d x?^ʟE`ϖ-[Qnz%f|qz衇隍*҇"m7[Mϥze+ȹg׌қS$+?ʱcGE WÅb%:sq(l1ZC +!7-4;3@ L~9q2Qo:BK 3tԣp(ی5vZZYᠭH/t^X\L`J~ߞT9˖c58fh{' MqRhKlUُ'G?u?7"1.@ٓ،}&&+-R N {ºzEpMYi&O(g\Ffۖ\Y\yM'T|n|˼վR>aZn; ؐ"ā$H 0@f(&F܅0mh5H! XL{n%E XAk@ Z BH:8XO޽{y<Ч~:7HXŽ!N RĢr2}᯲ƶƷl-ja9{@ӧ^VY$c15=c4bAm*I. ˚Wl=08TRc~f24U,n9'v/6}֤YlzP)&w/.ŰyxxcuJ'[>IpZS T┹5i |Bd!DJx +2O@OtV)xܱ>Ⱦ!1HZ0RG3:FY@~'<,@NۛsCvi_:# 9E%m:CY=:Ź<Go;,a?" xB7u]t? ~xl7AL0tBr3 @[PըSsw)ak`ּnU+. SVkk+/PI~`ς&K)$nE')ewqTZ-C3WS0o|ZY姿)Oz؂#;(6Ӵ-[ifF3!7tlj}^3.fvzLL ,)饤UQD {N|D1s%xa`Ԍ]Tie'&ҕhz+n- a /p۶ ϿH/>chK-W&'bmBЍLaM17`r-WvV)D>@ J,ǖ^6T偸 " pChz {Eɀb6ٖ5YfB<9csr{PP ";x i'&]kMprYĺD AwK;owE/lFhˍ+c>D*Jp `(S)}޳g>anva[hY-= O0qNnR f|aILsHSS4:L"x @ٹs'[6-8kWW"j! --bpE[~e3@D[ӈ|Շ{Aa /6'v-Ah1rrOLN[yѹ]h$]PҚ~}^_"{N6@*! 8w"DZ[gf2PGI٧ E]mbB ٗQmD$)l{E[[8@YG3h`K$|~%κk.,RF9H\c)33s "eQtqRZVᒷ8{3r;.}DOP7\,X}K `dB|x3UݨYgW8k7 ~jʿԼ\z{sM+EhJ4ϒم  9 *y.@Vɸz*K뵰Y @% (ͳOe:g+rdڱGGQcsΚ)v\㒏͗bB;.7{t`NV, .9MN3*'X`Μj7ed3(-L,3D !MIGI_kt n~m>hb+|{ FYpr.8Nfi۾}73(;o[e i..Y̧8z'/űwC TrL} sQS7H srʚ=zԣ3}w&tH70Fbm ||BJ6y!ǵ4ǢMDׂ$,C8B]׊T~~$E" C:')Zqhq$ OӮM⳸k )Hpl. t}*ʥrBmL?[#.m3[%yVbk# NKVmwcgτ 7-`ɼ8={Sb] VynN}B{h)b)$mB@醏'}=ؕI?k5Ѭ롇,_пʝwy*MZM T뾻B6%^F"bdЂ*q: MRuYSլFBm>Roi|462@ZsQvM0LjZqZvW0es\;aZ>0\GƶKܥi:w*+;Ӏ}b!a4\2ÀC446ĸtX EQ`L%)=KFЊ "K.NPۻYViԹ^oI_>;qphNv.: qU>l[9*Ifhv#S%v*xG4cԬ4IdFF}j8M+4sp=ֆzJ^s$̋KB- ^/1֪ +>d\d\?sS* < 4)SX h;֟@}`"**{ ^x`8.A1A$pP7>a1:򰥃]_nX큃gyڮS1]=x ɮ:>e4bl2FU)V NP0dl倬u4ffZ'̹X"ӌ͛4"YHX&*&󑲨PK(E$*-P%/"LFpy+ql/ {1h#Cq{&a" &#ks%[0%!o$1a߉%/?V[sWr1Z\g;0mH2r9ԅ!ϖ D10 y'V .)އwDڒx@UҡK%^CI,WNH&Yn&5 nI8VtiY9$db=U8u~UIy JXL(~O&Z2ܦ]?֧ vp??H>Xk6TixָтE"i%:6!/ѵAMN(ꨩuӁzh&&bĂO`el =ٿÇ1)hx ZÚ:U6Ė@"u,ǖ+.^X 6239֎]4: :} M6¬! ,7B n{x&|0&!]ZyFqL*R#,Vj}N<::l^h+p9<-1E]vPA38|V,n`?B xh"H d)/aA</H%j5\سgm?y-BA7XNN\m-&2@+[KK5<2bmn-'&f\ P! n,1Ѐ`IH&ψ"0}P;1Qکq혈]jWsON). r%~ ci Q !8s.w \E2%(Lrlfs +ub[mdBXs$U[PɳpYS-V}"M{<.<$5"+[g?G>8{'YA#?a9~VfuB=V@}{zɧ衇Zz2_.]ѣGiǎ|,m9w#XE|;峷e2e/?6|-M!$?Dff%p;4>鶨Q[kkV`R,][MfƝ&I6u76` ۳n?~[o9dϭ$srQ`BDf$UY@ʋ;4M`V9J O- E 2Aq:G-Zpez]:O/@[im4:<@C)_MHLz> %_&D1Ptr=[X̹3`ixh;9|PԍNC&>Id4.a-P5,5hHVT08gky"k2- k!5wߦϼ8PVg?ckj8uI>hۙv H=t^N 6l <@&vY P}tuVbBKHYh4] LNM1 b@H"b$*A;p@]D`L" .+m.]erpy=;+mYxضu .^Z){wȧmPXz ǻ^bkbm# ϰuLr%FXte\]CzbĊ(Mq}:młI0sAS. u%$AJLؕTQ kq+)ȳek]['SY中?I듰> am}8@X>?ǫW'h]Ν;59\Ę?0կ~ffٚExD>yrMww'x>@OςG]bpդ~k6Tֈ8&5_%=$A +W\ܕW X)Z@Ź\ntHR\[G-0NcCt-htCVd hTͽ LB05@.8M,#xny |q k51%'+3ըF.>v2+tdGڳ{; Jа9n#Qm,ƿ2JQr ŖAHЖ*/R,[htdNv-[s֔V\ :>DL-KtKtUfܽ971okS%xc<W( G}̔IEǑz.!D]o%blh,Rb GI8 W P"jKQh$k'DORrʚIɰ[{‡ejhv h7m?rSڱ;\.! !Xę0^.>[U*>r xEXk}-jrEv~^ó& a!LK6pr B:5q'XHܓ*V>3ħR^b.lXSΜ9{?gy=GЧ>><G={5y5 Zy;̃<Зc/s/"?}W7OzԣW?_-`Z͉h)vS&ze@"Z-~ BKzXIҿqp`k5k89cQ) Fn&5ƙ+Ce755O9J0#Q*F,@5gyfVO;p 0{`O<=i鷚!;eqR?&Z@sS{\4ة3!T^fx]&KZf+$ 4eIFO>,kc#Vf`λgn?/ T>vS@Cr:Xm@z3?VśonԩS<9B'P17C? [!_wAf 녩=z̳J-|]n'Nfה+v:Eo{[@qwă[f.] S7?BSƻ|{ scǎ-g~T`أmoO|^+XKzPĘ*L>-v:Ð(/Ƴe C.ʚ%TF7Ҥxd<ڵ}ݳ tB0co}[8N HR -.[- ߫6Y:ef\ERr.kR`W $xDO¯]YLtX'4Y?u -#.cP$,uc'U` \yL(yMdvv[A @=ܳke^|i9OG-<(Šy@5b"oɄcǙB;)|7nr-rb%s;Uaa>o<`-΁r@_W`ER_Bo=q+Wh!*ťm4ZXG.;DcSTy@W;ֆWP` 1Y  6:x[ˆu( TI3>8&3w>\+bLҕKb"-W$hvYDŽ_Yd\X/`A` HA|\a ` ~c#N Iv$4Bv}E?V-rޢE\z:]gA鋒?) ͟>B`^/--+%~# qsw]@˻/&>4T;mE\ ;hʴ n޾kN@> c3I[zX]s[f`h^. ױcGOqv>}cj=zw c9,'t  1  q 4d1iAf0lFɦͯAryk6J8W> d| m"kI,c5ĨAKčCbadq_ u[`jax9PZh: e` N/p[\i-X*pjY Rl吋@d3C1#z{G%rk D1~1=Љ[+:vj5n̜K'GGq Z7\XXadbrg9*[T"ZXjĬe-0Иn` 559@V_맘aEl0..`k ̴{jNBW.8"-e4܍I.#JCQG|)['r&g^࠴.~1kbu"L0ё+e(8;+oy2i+KBd !-+hpD;H㑷1r3-JTq~'/MD`g… =P`ڨ_<̓t. | cA}/]c`7d۶mf 9V0LJZtF-6́뉠&p 뀒n gqH_AB`C?`A9}!wy!A Z?,I1qG}ߕYtM `"$%r!K!dp%38GwOuyqߗh=ȬDW[ggLO?UPDK+UFg]uYP#j(`)h PG}υ+zl~755$Qqx޷}:RTYeNg2~x{(,x?{s_uEH0gHam7pbWD]2 VMHAtY^Pd&,R"$־yos+9c)*HzDҍ Oy;R@!2iހ44Ls:tp?3d`AIw^8rY7ꯇ ^|G6bX#~ϥ2Yprjh/ѕ*G9TVSTe[mvcA/mH+miz҆k &mڥK3g}jU8 SywIvYWb(R~m|23a7))CǏgs=_X@MK<\Qv/QN1tė!ٽMQ5}[)bgW~EaY@7 / ZT<0F@MZZYw՜L* R{v01뀔3+*J`-{fgu6Rm*V4քX/evPu"N9ob4(RI*cpw@ ց.ڱBsntorG'^pͮko5Y.`e5܃Q2RPpL4M  };bxxcziyCdkG8}gSv=0]&YTrk|^g~'/{`Q#D>Eq+c#  }ﻞ|Q, gAט͂ȕ&ݤ2:gq,""zYvaa[GPCT , N v<`4(U]'4Gy2piSMڄtS@χc}`lcHdSgG7MPD%MHSTDA?,M*X_ef9`ttMZ^ZR8` ke}Y뀸SQǵ[a\֒&آ}Uk`]\RPqHAYg"NuiY[-J+WS '&|5+ Q)\D#_>w4tdD!J'Ǚ^l;OQ'"Vl8Np`jHP +?D:zQM=rUeb뵑R+ko6Z 3rqbu3 M$bL!< %۞-7S4DK'c-̀{n*sEsl˫ 4tBRPE{ESYjUzm5;V6GM@ÝLawTݚ_pR QEcqpZ`(첊J:fQR,HAl_7 ~u|*,Yp+__[>|, '67k<T@V$WƠ̏Ϭg& g )L¾cH3bpBf9` yȽ?{[̢ZZ^ sjOtcjK=߂Ӧ o286It]b I~ :5Li8.}zH=Ì^]MTICMocuVp rL^{ (>&:zz{5DGˣ! W/O{LJ% y _b4?ۭ]4d"܍վ;Ӆ'_sQR ~Ǩ!AI EƁFs +yePu*Crtܹ"|C&KڠFW"gdtPbuXtp'W&Aj zʟ̠`^]yb}ohv9z\4VZJ)ck˲& E&i)UZCuK !céR-#yy-Ɵ[vr}#EԩSqmDW/ ߟ"\p`;f̐0 }ˆҲ00")m@|)3+ж7Ay9F&ՙmngIqP{ 8Ŝ+)>)tyB朌 N5&qcE\çꊭe])S}5ZHe&( +"9;YSmL]ɱgu]&p%u' %hʄJ\g4[-2wɌK{i@ Ѩ{2uC]9a4SBio"BbAS |X! YnjB)O.6 Z-z}ySWD{Kܔ>}v)lMǝ>*d_ؘ*-gHH&,. 6|Hq~Sqg9]~M~&.E'2Ko<~}.#Ej8-%'`Ֆ D_k2uN>yIڑppr\o8Louo1_ܠ;+4"k[p*2f34 zzl1Jh b{`jKЦD# pwddTSLO]<+X ܄L\MxKG5M 0;n@*dxMmJ!s_ߥy_qPD8wag{Qd#k,!\8U_)a5D]2_(aMQ ÀT PVׁâi8 ÙTﱼ#_d ҩ-h7>#sPZb[|QLƂ&L?;wn: Y Z"I n{vщ*Jfs8m/}*ac_wLY$i& h4 +!"n -Mٍs//@(2S '1)Uy֘Z%696OG MZI+1;H ϊ CWRfӑÇb3:eAs@B+^< G (wzM4bM2xFPkjQ]8z/l]GmC e(L+( j/^ 3D2pT ϽGƳmaP.Kozm)sMna0ZC_SI{Чa?hJ 33ˌgPpdPBDġcs}}jLt+0b0E%xvF!;j1 ?~9uܺ=GT6,`B 7Y\z=蓤XNI5圓|qUlv)òK t5n0I=X8.0|Qr 9TRN8Fsr >8)Ř&GlPP*`~[)٢%9&Ql`t'`MtGcC8.\+(6RBY'RHTZiq/$x3z?uIpņIZ_\70Q6)9qzLsY^Y `,D1Fm}=#Z SWR&9vT!w޲9ZJY 3D -<C7,cB86/X̣)EKc Lc^w-;͆^4`iӎ>]V}cUPjkn> )UK, oWKW[wL-΋w_cG$t SYDY@I#b huϪ3"VBn??+Vzоaf˰΅'{sSW?kt l`KRd1σa IkApddN, !"EP%åa$8p[^J3aA8H3؞[ήOjvmdzvcܻBߤɩ_o8p47&"vL4R-HfgRPD.0Ct t:jw'{^+n k]cc'/QHL Kً1g?9iqӴ 6ˬAtDqFP!,+l"%Tz^jZYe־J/s8+%W}X =̃"A0j½4(d|:%C"PLm&eqM4^eSS usK;` eQJSdzDB̄mD(D)A @ez@*'0g Lx&bLxZIxֱ.V<`9W&,խnjwfAPCW M(\iKMTMK,W}s'5N^rXǗS>\ƀrlQ7pg]]Odh꧗?O3Є1@/kzmSwF2*DY]]tjrQ76,@u Π;DŒ(o;zyq\@ֶr*)P&5s10iCQ~ qp1s\IeG;rҨ^k1i1F' ;#ρUZ"/b[ce>gc0apKjxمP WtYS-Xfctuɓ'qe!m@e;rk) -M>m27Ivre&x2ZeNj[l<3#S%ՔX&mI`7e˘LA˲lЉ? N3)r\B%9)(.HwciVW.JS\20e3Zw2Ja56 3 7=/6  ։(#22ܠG&ƹv#cmi:ݾ&g4T-? 퀔{ 02lT ;Ԩl@6DuH42<(;&@r]L;(+297%ggyڦ^ g×s'4uO^ko(\}J5d훑442՚uE"&%-@ECGrDgݱ4ڽp-Sa^/I֮) KEء &!2OTR"uڵk `4)LhYfLX~6y@66D+e;̓"0 47BٕrH`'0!e}1,UT(uD45611MI[S` +AXtT$m)(a,3|2pOsc5Q!WsՄڝPX@ V2.4'$En;n"0VPOGY$+IU@ay!3RJ<隄>uzYW"̪ԘۅHcyǃÖ^kUIĩIkp (NjvlhR۪b),'$_7@S{ $)O w?.hxkPTDeiev=S?Ju@yu]V*1zWo:PvS/k{lL6:gRu05xY65jHF _DjBio,uA㜲&R0}Pxn)5*Fz   &#iH(yv?i)x< )H }Igf_$f`#=11H );qd4% $hQPfœJt]3c JG=#PX,@񱑸'B?O{l3e~ "YX<G#W k9/i f Ryiν{xX1i``LQxc+=<wZ,/АJW*hksϠFIlo.:XaݶevW>~ w,9ZfcY-K70&WpB.bQMy{V!|68?Fsl+|4 g \mÔil{mR٭?_wF*D5+ZFWA"8(]bpEyO l8r"8z܃[t}Mx+^RY-Rts6sƙw&X895Ko{ߚdIv58;OR⠴H,!9, 6O/ӈ1G(SbF=Zte@%K{W:a,aC$NC{~զL 8HE S f-J׊?DsM(#h4.%8!UWVVVx= LF!XEb""Z-qeFwyP^`XVܵYvN_k=ڥeq+$AAx$~M*,Im?璲مeBb@uQRƊ~N۱=4D0t D&jtdECTdz%'c5_w5l$ :;C%Pql!$:}̤ٚo]*ksINRf1r 74""}<˅ %mǀ{&ʞޣsnъA;v,TҴ"[A7n\;ae$" r[*@]RV3=v(3/pj1vbl2[ASs1+-8<`TD;t {1C{[4EuX @ >DcH_Jh1*3Aksf;1*75c@)7Qʈ?^Ahl2Wo8VM2SԓnS]tAxk_<72:)es ׈ה'8 b!aOUA8ӶݎlmXl`(L#F5|C؎h0htz 9w'Zߎ|G30Dnv!*.b/p7!"X(pUf;0DQwHĿ퀓9_n9@fg} h1&buvfM|RN>Tr`ڭ;Stm_ƹy\l`s>]_ScpJ ?1lA{)8ˆ 55M'w!Ec}!b)U ۼ(Ci{: 0!WEzӷRHû*hJ1GCSBcM87 (#bH6Z S?SV4;,<,=IC(}lb|n5̘} A )`yę)1{̘O!ÊThؙ{(ϫRI2=`S*IP0x=[Au}дNN:|iYo} DBxg"|/\#ٴMtm˹uNY(?1r%eoUN[26%{ftqۗ + e,S5JMm:y>}&&D'CzYMbWgh0 5m-,6 ҅TNeǂsB*OUSaVZlZ[ U٣>bw^뵇n?N{lmbirLepU\gld=@gF0=r)l\ 8O)CB`@ennA) >C `.c VV1Zm!-EX(0K}du[727z$'_v:M3[sT* = N0?evW4o}|ͱ 0PpN@ѓM߭M8s%N"brX<0V B*f[3/$6 C3 ܦ`5i3| 5M""5 6Rr纽f1R5|*@^Lm'R96Y8SʸRRm+(#%H}?~9ظkEBr?IuXYq8yO1dW)&FƣˌUd&73 @sba?{=K@dD0a# Lq}嘫7>Fc 9ү_xO#h)4ωо3ZnC"X HeR4`[MAgw R7Uo޼"&AOYfʪ):#)XtZc;pmxXw}0( ~Yh(BpilO'%e:{|t,`˫^ ,#h=z*'f|z6.^8M#HѱTU5R.FJ +LFBE$ ;L}eu[,7f&ҁJ7RPIG 4D3j T`a͒R9YLP q1v0ljJ:㢅E9%|9JURsmX\ :ݞm:A6c3HTJFAzbP[kRj:ᮁv4T\+hhc¶0xj:rǟѶYtM# 'akkDL(%,haYVF9}9z}2A֤"*+ r 1ǠTe*?7!z0iLI+:}!@ܲ#]JEa]qEA.Ot[ܯL b}td,pmMAP !08<)]_3`H*-,.@CtMR/@u=~hc_D@U 2w2SM !+{CcC:"^x (YMtL`>拎?+G-N$#ORlHm?)xDa_)8H~AalI$iOoDU(/a J3 ROc2/`XntzkSHN⎥Ek*zy2eJpטt6;&&R16N2~r҂;\&wY;Xwہ(\J$*,D !p{7mvpj,Yo\FBݭ[%" !J  RiEnr/:+؝#*4q|U 0`k\&Yce}%QET`@"Š",=vYkik[Z2X#4}[T X%pjX)؆ Hi:F1XM13 3UcTXU{a vڔIuY&9ǀXEd:NKLI?t{^7i>&업je(H%`STQP^N :)TYnsvd}eG JYF}{xЁ)þ"K4=و/mźB$sm)yVP}CYyE+%&K!azza֎ӪU^Ӈ~(agpڷ ef41v~A:SMnyH2;)zR%P^C=ϼj'iqJ_ˣ?`sc@up.Z! ktϚ!)#S5 t1z׾gEhab-*v( 88(c P]dUC fc cwȰ-D--D`Q*y!8,a*x,-G9gN"ĹIQ6:iʼ ABaJ/{֊>\XNY ҿqnJAq?ϨRcSUPIs`%V'Rh}FM6Wrl66e-S AC،ٙSvl\+Ԏ @sRDžyd @O d%Gv^CٳgY@~{}`5G+P5CS%160ԗg}7 Hu `dqr }Ezzגx*Vv ůwH=4QgA *O=wHrL\XTgr@ʘ0_2+F+Wo+7hr.-.,0Pjϥ^rK< ICMWh3* D&p`@euNSi3룍R>GhsY5*Ut'@ =6ieMğ*r80i/:<ȁA^kWy][&~|Xss;8CES.փp<6zb l: s3АT hEJ}iHDS'ģTTLqe  Y;_EV܃Xў*4MRkiC0tv egϻ}r0Zb=M/UD{ﴚ۷oә3gxX_5^^*ǖ j[L)x#9"M&#JE(.bM+k @eff{b #FM =܃R58bd-Bqݾ{Up1"%$/YAG-2OSPNv9B ѥ(z,1h 2eu87ɽ6V艵4kgi6F?qzeRRH" w,(䳴a "GĶ^GZBj,HTfR2tlBЗd>!2Od;hbњ:9@W+@_ <͋F2 1_X@ s:04[e#D:IK|׃Ry};` }/BK9Qc̙%aш`H`Y^Z!@C PDT[Oݶkk_Dsc8UYl9ߒuctN:q;<(ASE˟K#p@TJq`ieu$:u{=>pdcv]R=btȩs'y` txc&%cstJUKKVX5&aC*"lE AZ8)ԡQQYe^Ƀ>^K=nZ/T?0dХY0lk}ԭRusgFH /'O|RphEE7%B#|CڜuO$V&DПf8qQ!.Rgay"E~P8 cU`iI* B9ba}Q._ }A!#rmLXF1*A 0*4;3777`91Au )>;~rU:}4/w_ Z}f_V{ .͂D]}8ԌCW1> CCu:tpBV[غso*MMM,-m.ЧY0S>,DD*B8V1QC[cx;Oj 8G6f}jm7A7'ňs )E2@ 0}X3Sʩq4ml 8ftV7; tul̒6g^v˶+bZQX2B;awV ?,s=Bo zO/HX41c|nIlom8a U|@ ,}9d!vw}P Ď A<7HKZ^fV}3op^/:e} 8HSY-ѾjF7fʑ4r< v)M Z x􀖏1&)`4 K?+ɓO>IoVp"X cNes ֽ3EYؒl`a\qt9ϗY%ﰋv:Š!NnsI k$T pJ"DT AgPP ň~QMj YBQq8<)^(zb$A Jk\[Z`VX+KU7Uʞa (`wTFPƜ>q1`^qwoh?IT^Ħ2&/(-Wk_di[ ì J:-ԃ9#J9;(h4 98LH嫷;tʇ̎R`Hw%KRzL#EϔR \T*H).S0Y7>>Z+tue}n;m&IckʍHƇҿ V7i=;D#'iyM F,%zm伋j5V^)؁ #Q:w9k1njՕ%6z*;YԸΣd4c2$IbT[,fsknz 1kHKJnw"Uk'm7@n|r=q$=sk^mvkV1pfЗ[F&tg $yf `Kin8C 93 AIF#kx^rD~0Uú} Whc~^+7'=O矦s ,u)ZR0 SԨSEEkL` ȸ.s 3fW#N:Qz#qsl3 0|P;>E8͑IWIQ1y#wz6j1 "1p ,AP[l:bv__vA\ >,Ǖ 4tJޡUM%RqZ %\"b69v̠-h˽yRBC9@2_82T\0e#XQK@̀ y=,Hl LU$ ˵]vIpp*|4& ҙ#KQD)L^; Vp@D >&xP,w2~a\w8TsE˯}1G}6$1JK.cMa=hcl 3Գz5`z`ڗ=>Z"ig!'#."BdVӣJ FhG&+>E(PdpfP38 ܓgLZ}Q y:qDLmiw!,s/ 5=A.>Ky$4\UCXH5tX+ka!up4"/ѣ?!ݼy>DJ+atc),i.\pLAт`-R9rUe9kD ,DA]V@D# xθcTP$nbO) T'J/mi6ٷ:w8wft,QW@qss^Z -yffL Iغ,**"꼩ד%@ṉې2!ݒ vυn :>j|aI?pvt%gNy&_wgӍ7 s|ys1@<Lp  W1[Wq@EŮऌCtt)-ͬB{~tkl %Zɩ|6]|ݹ%C Vo(;%6^7%+E}My@xs)kjOL"kEOArbҵg*oKnkXb(TV*4&4YHc;6Xy匯wtdB9ݽhe&{MO)V.4Toqe`=qP4aEGA)֖2".KƁj(gc2YgsqPUy *<}Ef@5e#wJ5OA 6b:at~sTp.b͝}f_x-j6 M Ə""URMQlPq:>Ȁ)!IX9ݎesm0'D C< h𻦋Æ-FR(I%öp.Qa@RȴsGnyVI"қJ nqL U(lq~ kmW~, .M2~ ~0+cma;Kq䝱n8t?0ݻH RyVQ=lK`Π f}Lw9ѣGx 5 CӍH~{J}э+gX˞ҁ*yBf=̕rY&xR Cƨ_ibt 2J&w?wn T@)!SGZAQD+%EIy ^@ i=^S,Vb>_MO]hymy0?Kn)aܴt.FER'ZR@l!ڕ@&mϤPX2XP̓4:qmTD"$ơiL4>8VNM7)qtpziNj=0`pfRDOʾc,oBDcX'm#4G(0|4]72{nPqB6VXz&r&7k䀧MN7ϱR\IyJyU3 Q/=^~M>XeYWXP-CzvUO# ?UͲVK1 wU^_!4HNqNX*\G6?{*^AP?Dh9?+Sy=8 p֌.g~OBØTse`A{ Zะ ؖ@D]R APn@ƒP8|q\" %o˜?}0fIhyVPM0tJB| 0QdbY/38~<%FZ'I5>Usd[ҝȦ̈z4QLL [b%PGQ# $)< x-Y(7%`YT)3- &ᬫV{ vpz!:@pn yXϳzl!ѕ a!D|A>M+V+GhEȪ󴲁MDXfrv9uAmݤْ葨݆ @M:pZ5`:qJY^MA3~[ThhuGȼKW9CeܝS= 9ϢhjBS7%j 眚0PmX4x1לт/087In8уEëhiYJS<)7 iQzUJGkj!w,}$ky@9 gQţ5AMUQCG)w Jd'Q·`xqOEA3Xg~o|]h iluc*x^N:Zj#55Y|oH;Ignj0^V OB٨%:`|/y w~q%qZ0X]s.sv5F> [. rqk_r:p/à%O`dB&^& N$(Tvum(a{g,v:"('6lDqS:>fX ydD fcJA^cEj@<*.g@5UTZ0Y|M tj#Ruct QtVUYd)YHMER0SoT#B([U9-n8h^pN3Th emu-n% J)ʎy`\  ┊L=ZX:DxyZo"ŠlNDrF-Z۽PVqFPA4 ->V<8 m"<[\U c8(?.`BAZF:æ{ \ e8tSu m;PAB¼iw -gp.B)gGνug0 q=dž tuSw *3-%m&+m99FǏD[{w.gΧkՁI(̊1{[RU&g?scW T{Tv=ʯK+n@nLާ#ti=~6~Qjy}7(s#g,n8- g97&q1`* l>/yi4Cys gL-*Pc݂&T|-Z^ef劀jG$")Z?in:f^jE%}RɃ;M+Q, rmm +=Q4eY<Y.2<l*a``L*z͒ʽl7Iy}uUI5}DӁɽ вq'L%g,R$\%/<f]@ILT֧F1FchUiqIs40Mo-Е.I-G44$"`  /\9;Ϫ%sP(EJLj4؉3"Z)0Rr@ :fXn0!7[A5J3[lLJIc*qƌ PYK!{ư[M;?QL 9f!UJ4j)9Uo6YF#[HEub42imf0קoM0[mh,%Qfz!^S.{.ڴ<04otnܙNԠўHk+X }@z'&j.__~e60?Cz .wv`lٟAŶa};vK~/}"F+R/5)$0 (zҹJt ?ktd w&'8ug syy`R֧YE8Bm]A' CE@#ͦwV1ϐ mRx#xV(CE I`DV*)߿훘i5xD_(|xHZG|Xic\eyX 5w~3y"H,882Ȭs|U#a hjcn2p Gi96-eҗUiCET[X:rr|‚=@$Np]r_H D ,^KGNC=BT<\hWSLO>JsWB X}F՜ձ lk{k_}lQSͬJq/lu9{}9;зo \W92}W=C( T7:I9|pH<ʄB}  u8[mvQy0>^}%&Pr*_ }zͷMOߡk׮zJK`޸qo({5>ˠ…s\y gffK9B'O3hiz]'3p's~/O7)Sc+RIhQ:~fJż5'2"M-t屇0~.8w[~ZTZ0kSO2ΐ'Q$8uKGFD nlƳ}VhhZX ac=+xsSB5,BSE2 LmYî?xM|k!Ovc| c=y:ƑdWlsP<[u쵽UCC#V : jEJ*}rL)+ D&UiB" C&efᴗhznLzc[n{O}`H1hjdK?梅룑-5jkg3au_7~M*R)F )m#T+XtC]chZTvJE_L׌3t[bj-v7 J $]Tfp9e_IBs{ZA Qh@Yu#4uЎDݵ ɷ۝*r r {t9hDU QZmQ$9YB,)֕U4l9Zpյmv@Ԛk)ՙLqr/D߬FU>Q F Mf#yYΟ?&εk]TTN>~?5"!x~ӿfGwޡ'x Cwo pG_O?o=6p߻wƍ̐f5@?ഄ, sKNDJYôUt>IGl,^^2enNӹAZY\ ( *)?Ւ3%ϲT;v8|mLяE\>ٺ;2leVsKhl90ϬJ㣖v)z"T[.0BJ]n 0EilshX[``[3v_>YXٵ8ѝO?uߋMۮﻎE0q3EvH|X$\6M&L@9SS }ѣ Jt@BP&[X~ea`9u`QsZ9%>9Ǣ,\0_Ukv< 0̄O @?>uo+p?cuSلm¶z=VRR2*d^ ޻*$L&E4cfO5ͦ3fEDvjdQX.P-{ey}PVFʰ3lFFyk}Cݘwr-6haަչsy|so~":[apg=N85 `jks8dZ>dZoʌIK u {#"ts&0HAHɭTipCpKWGhQѡEZl2;F-V P'W > '` ( 1uOѓHBP]3J~VzAǖHTahYe H&@ Utѡj%Pfʉnns*0◗Wi~aM@@ ,lqG۾b0hi_P "EZ^lب 5}:JaN-R2?uZAϹ< M57 >Wоy晧yX,4ܖ`R[ ꩦuܵ"A4ՁbOuZ\camsx<;֠Egc~즭 I&Jic)vfˍM-?Źۑk1.J)*s[t}BZل-F)B-A% `` [[]-}4&AuwS|˳ \{.ʈ8JM!K׹5SaHk~ ;;׉;-I4`Oҵ,i:]/vKT*l׎ lӭX*~l%(׾}/q?E-X?E7 (w# (IuaYb )~? =.\+g[%Wy|Řz-NÏ)9c2zj&e>踇[oɓ'n܀}PRk~^m7K?K=ʰ+X KT(K\fg s3w`yeB\i3fQ60*f^w@ ޒ2 l;X01+蒟$Q;&*x>]:WʢfĦ;:zXԋV3ԡյ, @GVJkHV$kpШ{$@8߹y>~f*dw`tbKǤ߇lan ݘH]X܎؅U+oLhJT~OA '(*C )[&s3NRء|gc(X}_ˮ;:a\c X\Mg1蘃yQO@Ƭ7֠M_ Ξ="}?7SSStpܹiƨCmw}~> Ć@}`v^xyzw̲z'i{{yWz-qOuMiݴ_TٻٶL]r!8a7f-N] i/;%CINPExbZ"VY|H|d 9!Oݦ>MY8tm倔Max#BsfkP 0Fh"F$}5#lN)8F1!rŹ~95Zt 6u8f}}5H4~0,47XA4(MŁk`80JE>BDoɭ q%BK٠;6ˬ!D,7- 1zkp`Jc"ҳia nWV`0@.ݵ5 TTk$ou|c~9S>.u$"ʑev`֙ sob?v*Щ!$N3?diJRm.&M3}U?Dŀ_Z\` h6(>:sqmFG%SſcmtraJ ĬB:Hcbb?ӲJٳgo0d!H'9ݹ{ldlTrA".K,d$C pƪk4& P"Q79&ت#W`(بZ^tLR \gcZPuMm@6u9wq2/X]xY깄ՂVGϬ!NmX&^;J/P Dw_I8"EdBDT ƐO]M8])u/Ď\,W.:Hx&5c8>@2Tal3gϹ,y,mW1\e-}vtKp*̔XaT4 kcyQ7okry:~ч~[9%k_{1O9_iӧܜ>4u>Cy=ܳlw`8`?zxQMĊ}J}S:#oZM]syy.C.xNcfԝc$ZR[RQPP.6EeJ]H?ިBL0pl772I_[tJ7y FV(H&ӭ2厁^62m'Veh~|h(׼rl`  bAlAhQ)Rv2{Vm.^vQ|`0^p}tk7\W`&MΘ"Yw;=o`9O *kQ; `T z$URX Gs8HtaFº]j6W4Ͼꯀ]EMlf`q XphoGvC@ _׵>~fTZG(:2{,~3{ ̒RCHIm!jߥ Jm~HMCZړO^0`p K.T~kj+0qYopb ="h,Z!F#Ky:*Qy\PFKjwC6I'h-8QRn4^b򦩠~jeHYyc|e#T 7 0Ix ̐Bte b>=CHXwbq~ F_ky` @ !n:Eצ > n9n|k7nJ$N魷y Ra,B)X/0^Ov,JAEX$=^Mx0$i;Y;[k{=ZT(p"X4tȮӶ3l#A}ja|jHNp뵲gdlEE/"W=@"25^DI @$s5|h՝Id$"}*uW`,Wuj7D :^~d3:r$l}1 -(.?쌄JtD\mfFmnmμ4`!?oK\I}bUbPͬ[5ޢ FtmGt`gm^CA'-g)Gj> {_ݛӚZ Uvp)cs!K% _2֩ ~8W`+i~@T1:0qoD1M8S1~,Yy;D03!C ,0aPl-~#8!`ŶM/^g`JĬҷ 32cT@Y-\Q9[WWUdVhwF=TsI~C +%':k(n *싯^ISc-(`$M~Rr6iAfoL;<7GvdgEQ<% 3[B'16elYK 7,9vdI:zxā;` V(CRm`ty|Uw_v O0taD1Bz;hf:\$%VMPe\tJ+«l(ቶV3:xu28X)%(wYV*\FN:]9G?~=YZTCj5žS\*#2ޙ30 DqB~Z"[yuIdY/$_#"K uq/1= Ee?( RtǗȓ#W+ #/>sv͗Ϭ#TzNV聖H mgh/./.Uz>g#"~g ,#T|82SPy  h|:iuMQ֊SoMAϺV emT߱8̉1ezͷ@mPE-ORY(TDZmX^:b>Ꞅ8I dv:pjrIq%d6&9;I:Yvb>YL ="cIxlCwjƤ5=_D3N±ZMPP{ wz`H >"vw$@^/2d\oNtFTW#·-Nų:GTEJ᡺sǸJU9p05]o5~90rzQzǖx-.ga#I:I/3=Vpr.TamN @ 8OH{ϊKdDXl"M:~L E#(?̩8;d #bLs8@S'D bzlJ8'Jj0!oئsJ4ZFSn ?&/k6MYj8` @3HG}T0\JM.\,-RNBnXIy EJS%ֹYtF ĎQZ85 RcКK mݖj =dzHCGy*k޺uB85pX7Sę3&R  p:`Q&~j>nÑB zF=50Zo'\^Kq\ӑ],a/?^J w`NfIK#*]w,Ζv>h`]`zB?$b7 u+YHh D] [?F'_}xoLgRRQc9Օsf^*-'pl⵷dɻ,m( xŕ~`w1Yq.>>xfӆgP'v`;JXJx6ls &2G{@ϳwc2  "ut8tV_%PfsdiiBa.ݜT@]|(U~mπ*mlҿGB*wUސ+x?p#+ã416DݾA{+@."lsel[JPVJNZxv֊Cd z(sRRɹoc}A C)ƇjfzX $_GK>Z4=a>Ƭh@3R? =I1@T:81H/={.; h`8 aD 5g`x_XfrpAK+s>o|E Vb ?WBM!2EB^5y_ӃjA0 }.eMz`hգTel@\ [r%o˭B!Zf,%&+"X580дzȈ|}=Pzs4Uh42TA3E(z(&`cy8C0=HYy@4Z )(t[pkϷVS Iw?OxN fLx/:+"5L LpE$`V5_O7RBQ'n,d}]ۅ ,3S=[$#2^#5ШҔV{J홆~gϏT1v)|<{i{@r*Ddz*Etze(@D.O֘(Sꨦx`~JYPSN!8(@:M)K hȌJa'/]-z. 5ƺAdV@ۥ=.-6@0sr#؉FTrjA'/op@+is>|]A'A/35X[۠Ç8pENG6ݺ=-3H[n`φڷQF]$ }e~'G1]^S3'.]5MK˛0KSB%pɭ\T:0p*3hDdymCt̃L:Kc# lpm}>K#LJ-2T:~?^Csz*Q$@}T)ڽkgM ~fO!zwرH΁D7i vT F%XNAM+pR*ipEE8 ~׊xa;'w}[,]cMM2kQ^Q\Y u\.ҵb=DsrI.'+2;%xBtn·LU ,.[m ^meV&b15L̎ c=F@^MJEσ' v"QX|ЇY*X%^-쑔iBIA ztӄ2z яp|}/;_!`i<5ԹVܪ1k{P6jzJ&cge~>k<ϸ;9h=~U@lAg.NRl1P*!W)[O3}eziTy,BpiMoHm'8̏S"DxkRJ=ivjL$d"n$6@& (&c#yxPU9 \HDVA@@s)ů:-u" ^cı)Vs \R#SW,bkE (;^`:0LO?H;p} LFˋk,c/Mݟg@sF}Fdž?HpV)Ďp˴LC4;DEcC;cS>u С1/ޠ?K/>C/]iZ?2B@oR254Pͪ(`p0p*F @bE'hԄ{ĀWbʖ2Aopp!e XW"XD#(s]g0P 54DS Pg(֠UۺzIr9 =$HSJQZH '*60tPQ7ٝ >XO:;x `龣Pq /߸X/m0V3ժt֪_ط_86,6핦^j7 Z/p7cU ~ g09%'d4j)e^^oCPbE˨sN5si=E\8/e:.w^+[78w86tM|(#ՠP%0D[GdT1 ώsA< u6"+E@5WXq Q .{pߐ/k,k0$Wl-%8~Ο;@:=s\N?s=ɑKXXi8tV J[ou-ИyoO~3\s-_y\Ao҅'.Pߍ-Ïݵv?E]ӭ =ult,k9_!h ^ZSӃ=o! 0C^-N)ii1|ll*_t  gw-p=o6XO'I^{4FDS(`:'PX( "B?]/JkJZ&`9TbxSN=s!:qP(GQP‘_;25_Uڞ{9zd<6AVp qx Pe<4y; Y$rNGA gl3%xɍփ'5q-drZI2I,gRm"RS.J}`n^-_,I2i0&:ZA I|P*V@JK',"@2Mlylz_^K sBgZEeq}zea;*g6$ @{{w hQ +khTED`ZJƵ:K ,Ҷdkhj'ؗ=P%+I9gxƉXj~;`# Ykp>#M?R:#"2S+_BD#W[Z嗤q mDYjh)ZV9*}oďnߍ\9.R8" ?Y _h?8@cGctA:~d@@&z2OnoplM33s#rѣTӧy7Acn2nĽ1uMm:uG.2sL?uZ~N:|/sm G~:4f_DO^8HN=޾E^ D=vk$H &67xJ#3\@hCk>u+!r~e-x0!e &cCs0,ZI-w`mx D;Nr'Xrn>qQK 'CB"@{X Qc<{Ӗ7})#%U&ODWPnFH@h1{ѰOJF*"D +2aNzq~>U+Ϣ{Cw``D)x1.@l$2d0`}50qϳ[c~-lDA f̯/;@&o^h P5c9E7< ^V`~5},Vʁ2G hf@.ǀ@E xkTPŽ(r腏0eXQHP5%a0i,4Zs::u sIvS7|o;~rCKTۆyKeGMh{r,Qkn8901Dޟ=g/4'wss 4;;ǚ(LpN߇]o@OI+ΩEgP9ྻ;~Ht:|mklln;ø0% z;z&=qwf\VR2$$5"y.ȴK b!>{Adžɻ`h I;-o J^YR}J_5Dc<:<|#ƤFjGFnXEn` |EƤr+5 ^8RxZ*X͂1) xU0hy[Vc&Du1Y#ea9QznH#`_8R ,;_}[i1qcjKA$+$W ro{A{z0?Pq\ <,\davd2Q8F{娲h)egiR5-l`v}A D\Pf _wا2Vd"T4̅؎ XųjPg[ԉ˫$,zH^< $'詰՗Xgv[aʣ!YO{,J.HywfH}\gIǁY0'a-#$LdhT ENY+|#Ө,̬crơOap$Ȗx,>}R6Dfpܚ]w'f0GZ+ﳂԎA6FZ-6<9vxF4@ё~:}lǙ(L&As>6 ׫ O<0Q;w'!?C {||EaӈwMNkBKRg^٘o|fLXOAR~^pGdg(ݟ Bv)zm<_ Tx<ݽ{߿?}'Ç*Oz}מG#а\_9z3StX&2 wTljBYˠ--g{;0DJ#| ٰaM@Grtic$5})JFUZY)>' Z2Өi6qtRE z0^Yjt& a9jDZ+ã07x $MсC8gDQ#q30V2e4m}!rj=,Mmp n 뤧)0ZJHLRquhE6 kY3HBÁeT+NT'})g[}FOr߻MC(tb 9;'.Й3xبV~TV=ƻNMS|~x/"@ j\ca3¶0( ˪hV B=9( ^Ư~ %]ܭ}H `<ݎC*ۮ `Ҕ>( FV3$0JY-J&>u{ F^5*,kMYbD;acc;a pI)DPJK ކW@jI@*y|졋Ud2 k˄kF6&[U\=01@>Cı @{Jcmmt @_M=E-=;R|ݻO7oO?&_P x[1 Hkp~[3tq68}KO1psLޛss8~]tܟ._I|n@:~hO5>{?v󙙙[.ZtmI`~5u]8ڝ?"h0\(]pΟOw起nӃ%fX{$& 7)|UuruTm<5{*+|3H҇Jq_p4vp,`t -*umಜ! eΟY#8PI.Qx:,dLوc`G_PԧE9v{кLۃ:hu<",] B4pDa\V - f`9e-YmT$XpSι3>(ڈ1MvkV*+k;6jb6~ޛ })$)lR\xnfmfýK@!L&4^Y nڷsf2nü }+4̐|ag]gD\"еk2_:@)?gϞ %ұ3'<_ݠ>xFLj/U#`ٳgy-*c ϝVrxSa:V`=|cʆQE mmk{FSM2MkWh> ;Q4e1>ϻ_zӾ`ʣTtLa gP~d${]G<4 >`߯=PU LU^ExmϺI~>m@3MXq׷}clZ)T؀=rq:~0M;V~?qO/Qq \spW_}Y<Νq:wJHqj}xv?>>F|8EBnll"0kCE3خQdD)c}xlim^٤cV,ZS qǣјD7xE! L7>Jk4]B1a"4n8-lG#x=eitY#pT΍j0*5T:XfjjDŽV pNjMO8d~y7ߢYo0+μ0Rpwn(8a(e%!+@"Adot**HΓ L\vkVڮvVߵ$S)rh2z4Hُb=$n@EMؤ(Cc(׽~$ 𶵬wB!xvˎg*e TCALe`30^`[MS5GʬUAXV NR5m8b&Fjך>k=>kKĢۇX,][]}ctA:t`ph9zK-3 %* l1Y0!>҂n߾G?|/qFǀ }S'WbS*YPhlT4bB +m׏~T)s fd1\WH3akR|f*I>=˲1ِJvvٿ#s&V&6!@J Nv "L`WzA@j`l Qoj}uSv'@ݟBft_T(TǕx4UH:y4'EȪij)ẩ"95QWF ">^I"/QpD;\e7#ەҳqV>h(M` jZ&m ,q"lW0 MSO3'ݤT~aj_9"?Ah9DB1 ?~ħ8beF9| 4yEOٓ `a? }:{4=y,U_tŁ0/$ NB%ay'ι[\?ak `D0_}Z_tۻⲸ,X+-8mVa:9s8]v>*W1\g )STFHBZg[(UZ O&z>d"9`,4 Eٟ'WjC3CdotBj교 7lc34wq~vp @ūՎ;~ajIS>kuGzk@ AC#M(-gg%\ @2@,5R b4-o:+t[)EC#~:$wx(48q"Dh@a=)D:^*UqY++C<ز:׹*EjU:ߐ3=>Y z1G53X:b˱b. ]8,ʤZw,kݯ5"G7:B_z:uh*_ gz:۟Xw#]'ύ4L \7+n]~l哌V2*PbWTqP,;SdFqَ'XE'|N;F|r~_wİA-ܓܕAc`2b{w[ۏtPÑ}Q6Hh~7ͮ][@]w;ґ1@-[6eJDezz6pL[l8lsaaѾ_z#ܹ.ke="h:۶mvTlpw޳m۷h!m߾F`9u<n%u2.`s.805bn'?%^Go=^MrdD\@=źn!`puԡB fCqڬkfuF5^AW.&6pe4->' |4U7d`FAKq.u2{Gh敕^磞0/]/6gGtC*{/ӧ`pF46bЎ"Nľz\AjB6H&2~)R|lX0)nVz%0h#J獋l (02lHB!|Fƙ6hlF8 w\p@ < ?ٮ7ƙ =D[Ϸvw;'N ]f (S\{Ti}*$h虍=Bk7P%I(4&fS+}|ڰ_|VH`Q*3RT`Q'79ŗH|pU>(#u S+eg-Qhe{b-.mUHWfli~$XR~NLE P/w%/V;1P׺J쏮ëڮ2Ϛʺ#m(Fc)0_t]@8In!nuOJB"F/ֽyHFȸ+SSG_bؘ7n^ݺBC,iF2i'pAN N,6sg7nG\7ddNQyJuukTsu*[7EP> Uw`_[3/O9ׇ'%]KWbP˞U|]۾scNؑPd^y-;su͡C.{]Gm*9'}w>hm]#نn۶ԩIdv+ p/}䣌?cO> dp>џ۟ٔ]&W-CS#|D5ӒhX]Yn7hU 줍qt~Ra",[2˄bh:6+uV7yI[7H*s̪D+W*UJJ % %d6gOk B۶Kַcw}~>I!]~0FGr&FԫaFwC݋+XzpZcO2Px둮bznC.9(:Mhphjxg;vF?(䳴<.ƺoǍΌwPƧpׯ=Ζ3'3j&&]fMھ*f&7mt>ksキ a_7?mGv;8(R貴]d6 c`>QBY)9翇+շۗ%;n#CH*m,0-# Ȩ!۴yg&lh7NnF?n%R*vQlb:r(hr"8-lSUpyI(8?";s=}=;w?˯7WvwgPN8Q xQ=zMH}ߴ_y1w'ݷzk20渏 Gyb,󎗇k?#Gd$\[ePO AE*ہ5+#sݡC}L8q٘$Z ݬQԉ2dvhy]m$z5LtmqDo5J#W>ϨNS \z,xQ5@$ե6yu/+]+%Hd.w92~R=.A?@%Q朢0?8cuySO<0g~3/^~eg.YI?%F:^2_VZ$%/0tK@oպZ1qOB]k\i5AAAPaW`IcuO"`lZ ~H3CdY$`5QD:Q=tJDuCbʟ5ד6ȅz驐 7&`{x#ݕkI;G'.f#&L4)1ðAƃ ZP7x6Z N;O"-nrж[m6inG;`wܺY(х@1ss1.B\PrdNL]ۺeǿh+ cA 3]m!Ms{ѱpqQ>tiʁ6ăPWC_8o/oo\mZxǎ9۷o͂. %sI'6g]1O1!(@t2c .u'bs ڽE f!3ٟ㟰|Ozj3__~d<=}ԩ|}$j=c?+nh)/w~^|EL ߷/2H1%pL|˓p->"tZ}>.b}Cyĉ6FC=cF tM~)vP'6@S<?ȏJ=RO 0Ø#ocDa8宻 p{:sea~!ץQ!.kb9t@gWFp, 4m"HCk{Q|G̻2[ۅJ6m]b$ped(ۛ/ۄlP`?QQ }f\RW]3CeW1{GM؃@ 3{ Ƹ{Xӿ8//sDg@_t oU&m۴elAAS 9kiD2ϼeA[B}J}$r劣2J:Q2ҝ`tTTUe* ?wdNlv6Dn>dJ~WN +!IwQk9f! M ٜ Ǯ먨<\$Rt>e}.a)i4>D\%N9b_^}혋Mz{n=x=aC>g"{#6c~%bNx7+S=ׁ k01ټe^ܧm)|ps ; '.Pk L!"t.RKM,؅KD9NJgyCn;}sMOq~~9HCTSfGl,.)`㼉4V\cÆ >\h#aӭ9,a!c)E7!iDiř7/A7ey{[M'Z%WN?__nc+2 0 %wPt8]v SO;?[nj^t{XZ .9Tu߉#%\e@ˣ>||Lړ(.VK{M/0/r@Ki`D|w$6N sީ#)Y\bv ~ c!E mf`DcH (a3CO?_A y˭AQ Oʑ!6Pw^̧_08.uXF׶)UY2xub2UA)=~Rd*m/ SK(Xk7=] WPkjW4еF?D4߶~EG}3H+&"g̿gX2TNeҤyͺ#}~wcόM* :sPN?;DDgdN&<=œㇹ(oAC@RdXo3bi/=eAX^ @+tRM|D{[6FA~v}I0MZ#5!PkLٸ&2 $O2XgLm;ܡYGYUuO:DWHEAva~EqKaN\|݊;ʏa.;E/بDg[{/1jS/_lmCQl^h}w`Gn^8ie΍{\Ä-u8q={7m-%Ù NIUԃOt@2lў|455Ca-l>gp`#l*i촋?[mr"09~ ˞|>wɮ^Ç}&6Nxna{>Koa=-. irc_rhߗ[yJDڳ{3+85W~xCݵh֙aB̅ }E>)v/ 7 kdK3k=?ō/{fvѮN/ع 3kg,g-6T4 4+G*׌{Qwda~0/KYBC 4Ձ% S>sS@ )"aD(lGZS+ٱ}]x! uHU7n1ʨ9"{ZL}dGDy(ֳzN;F(_P,^-uKVd'>ʥdP.m0z|^Y{%ZͿi1(M/nX(X7#D=)R"O(ixl*uEB9UL$$[O6[t`~^6V:I /~!? 'xg/ y{Ņz\tٍnvn-DѷQa8z*;]pŭ֐=ozQ۶}3e;n:p~C),h<6{OTi&0nL#n%"Ri'YzOU `m0fPm%7VH>:3Vf=NVaݐ}{=RͨGgg؀b|]0 _-9Zo hO;H֪o?z/ױ-6zӪ۳n]c3_5a{vRS b֜7x]|Oc&G5SS>F& OP޴OA?.}!pCFPI&J@$o(L+RȪϾդ(»5Q"qÆ{ʓ2pԃO:f G]`=++N 0y+,.Jk-HQSbɡ|.zժdLH=M3Q~~KpFej[}r#ZZki@OwmԚy$J\7KҌy\a<3/qGn9< s1/0Ľ9X,AQa|bXBȋJpZy)l҈ |v(.ǪpӴ' }} tbb[7HroѵWJ[e-!b𽴔a]`uC>_cQk\JwR?EHXWnCPa"SuMyC5p c YI?-~Z1[MZ뤩R [ /+66.G]q#pC ⤉jBjUғY7! \,X `Ɖ׻m7owںw)OF _ [޵w"6p>6u?t pEU@ s]s;m_|u8o˛8@׾eO=|/xڅ0>o=g}X;wxi?q363أ;rP|^'"㡻^]䞻o(B)7,o9q3f玭v)P ];즃{sxϯ~/ #irsXk:_ }ɖ>N@J>zFYNL&tQ9y{;)  ǁ4lbh0sjU0ZDAi6B'<> _ʫv7{)]]a̧1؛p @ U΀& WȲG[דo]w{ uP?Gq6<Ž_}Ο)F =E#!Fvǎِ)˥KpyRTu`YOe(44٬xpBF h *R(NιviCBpǏ#O1_JJim0<A_N׉ <(?([ƺPk+(׺v-6I*ն~_Uyzז MO|~A y`1k?qϿ/b1瀠G>c@(D2?: ` w֥ZYt+Gaiz!AJʴ:N BgO{0AKb>/0D}VIb{HDDe2gN5G$D7%XTE*M\C2h~&M8}ORY#]u8h]'u#ãn`xN,!j52$ AK#.5V׹+ e7ߴӵRZ)MjUR={wK_+q#!Nݿowx1^rȺ 8s6 8J?#t;{@ZC%5c{Ygqǭ g.> SGE1tJ]_;9A7ݖDp` 1QZ^OOۦok4Nu]Es8DUݖFNQ4塤S}*/U $6~=? F0q:^X+2^Xwpb`;?1Y,̅SF5A:d <{5K=3 (Ɗ 2O2Y @ h`hQ/mf/# 5HF"pN1̸N^$q\6ω`BQ6GDQ4'Nm!@i}+߈7nT^;^]L)16(`F3i~㿮t):u/8C6eOek8pr(ݣՋϘE9Ѽe=__h6P7$(! )|*ybiuزR?"m[2tUbpewrf.5YJKIJHit25l7 }Nӗ8F$%] xuVq*FKraI vѽv`߶vZv+! ?P";ꪘkXD[C7څ¦o_ ͓i\$`\ y։;/h{쳱7P*8&Y>g^Ç۬w˽j_9:5kSgƠΣ&6Nڎ_| ;|! ʕ8NE޶usWv8(_Kz~=% eٽ_\O=L0 7g%n ^14]m= ,SY6RuhQH~ V'եD1dmj0 M'%i 8eLi'5v{Yؗw@.=b|+6HNԏMǁ(tYPo@$p FFG9j? `PHTh|eFDˆr¸mIKIoJY\}^`|a$v dyzi 5xBU1JYs1IUESF+lU.?ioFST_5QQr\Oٹ ?/,}\_sUk=T7WP9%]3O/ cOOQuy1<]7g10O\3pw(yaxH:h {@|.vJ”szvS>~4Ts.)b2HHg dhcDזGߗS%)EqBt/IB (?e9|Ԯ@ ՁHTAvd12\Š8X';(b8>(_ε3Z6>ҶFl;%#To @pAvxfl޴6 /=w?i;uE۷ Uvqn)r%w;؁旼._`' #'Ërpy ¦Ag©Mg{΅}^ti"ӡ".{-aLnl{ocKgw.۱= ޸4Ii34P~}gC vM-=Vb8TaM>1GRu)$/Kv\NN]d{>Ux( j()ePdw ltWOc( GV%Ki k/N3HUwcOTFu=܁J_b4BcF@|~G)KE+abe"S5U-8H_;%Տ0)g0U0 $!u:m{+i6EŻp4wأϹNwp "1KoU'6~]x,I[e^Ga/i?@NI^rY ێk{D;zTMu9iJ3k op4WMxb@߮1^tM l@OX+V,~嚙DermuVÄ\T޲5٦WV?wA`i0k $j|pcq(p>~Ǡgtױp?sy$)zr_5CZ,%ڢccRo {KLeǔX;bDB<@ r^Z=(z(&JA\֪CkX2%_S^CXg^Ueթ7K U&DGn*QkF(F qdGɼBLӸ-г]6OoL}7lҶGLۍȪ:@rTr5c[lrD\U @,Kp(|F?A(P'=eϜ dx-o_x=^Nls78f_Ʒdq홖{':dQ4/1Rj1Emfe*тGnuR>3XJKUNVh?l>JtEd:k%ZJCnEPDdVIEoS 3]ť𒛶vӇ6b`mGovE_UO!`T{>W._~ :%\OX'z7v &i8;m9Ξ;mCxYo% 7vݻwgڋ G %N>%q!oC՜Zs:0L,99:;'ؗ<{qNT14wqh^@J0`(V6H #ʽs NfHĎM?7uKFa( Q$E$FtG9|G=䚡H07n={w^xԻ _Ex)m #_[s!U4GM]{aX[Vm}L_y:ViRݎ$<e˯l|QMn.<4fH(Eih˅`BsqvSS(d掘!ܫ<;g8Y1WzQGʔp$ΰ /!ؘ ~ B5Iy{ae\[FPw 9: }S?DmG$#'a c@r5fTbJOI*eĜ*E5QRf$`1e,袺 PQݥk%둮W6cK߉qҢ rqœvDQb^p{ϥKSvʴG}7 D8H9p;p n| +czt@ 'cu[xluS{-[7I؅m-mݶ#ҫyw9rG#zw{6씆!W<0صck^n/]>?|_F|$@q9y#8BD% aԴDvkX  0a6c.lUa5zJ!ݰZ=% F{.;tsB<g9:uX.E`$E0B[<@Jx(sQTF7mSGd6,gp%bT0_^k3;H4H?Tb+yffpG%P)! 너͇N^ b(.AX-$~ۂquĉ>W k(d#J.32p/I|W EzeY Qube"۱eZl9Q$%X _[Dߪ׺}Uu>\wyFRzG̚>a{TV+}zA}Q~rdT`cn޲X`c1f$b11&(b0NǸphV(`Di0(J_E,m#]X'ȺOerX,2E|G>9y'ʠ^b濭m1HQO!D*$13uG氮/+PV{ "rJ ,=-b G.nu*Y,E_yr'VKM^YRz$vI :Z*"Jµͩ#kRVGOahM.AeM?v ^P,'=v};Ëck`&ϬaD f=w [I[o kv=`:m$~oi:xSI`_|35 p3У9p>adn ym?^g?4l۶nrX{KsgaQea[7CU8?b&Jt*<3BjKϷqĚȾn.6^7_ʬ`ezf1_޶?UMH!hg>SK=vzZOǐɣD0$2:h%bxaKJ7"{niQulhFSי+#ckB=+yC/GPqu:bZgܵXnbe;(5ntB0V reǎ5`hI@c6\&C';rpȟ|N,r>X &o60"tj:`),,`6_lpPANہ8'_ꖮE:׉8P&m8p~ -v F%>|z]mٞ`d8q25"n^b_Z;tZS5k-Z(5+J^pxR)XsG%0SHL@Y U=7 ̿_arK1e|l I0$,qedM-$<KR/i ="sz~cyԗY΄} ҏ)e)gMM߭FkQ ߯"׉m* bT3)/~XGthSU/; u?bؖnںd߉y&LT9  VKt`+#vei IUw^v<곴l :p X.Qfflz*|MځTר1\+i/3UVVCw.D Iw:ݻ$I'mm{ش[_I{{#ex+tw d[dyW={晗m(:n8ps!۴ym߶5m!hD*Tⲇpf--8ax[[V ԆƢk3&>gv2dD=:gjji{s6d g,-u o'4Y̰&:YOZ773;O[ 6T}.WA>MTǐgUvfb5 kY~ę=֔Ue^r?S!upn:M mic[7|%ahi8(S-m`Ƹ{!_)>*z-4HwN8C  β!P*]qx`ӀO!\+xp(˦fŮG>%"("\SOewюyԃHs21$:E"W%y`A^x!7B Qcȏh/Tn ]S{ R>` 0Cm=z(*H-w皒%Ҝ@XѧUySSnm bT71{"풀!ZT7'[zX+;%}|uta괖f$ A1ΘaL ϙSbR1ʏ"GƟhK1s>|Z߉y=2/e$ (\ފ*$>@~$s{n߄ G5۪zN|( wn o<|{ڟ(xنMhʴy~~1i*|f%'/kh㏺[o<1 {K..^L[pyt =VtT=\QrI.ѮX]=:^KLn7o>y$*u5,u (n (ep9i..]*g;]3哄w[N8±@ʊƒ;Xh%}"RP;>K]/; ϬήUo<8i1$ԪxvMR[/Q.E|~RY?T"Ur9A\ן IEems-Ilni0'1;$T+>j @ɢ|I- CG6Z)1h8eaw}.##ÒJI}1fgMmumsr_\K|1h|-{z!Q_=\!XgΜ.IņM쿪g^\;N? E_z~2]:=M]֢^@%]#M>1"G-q 0A5?۸ᢻjF׀ 0H(!dn"SҴ:R/:Rj\")!\K'lh7_4H5HFzk$c^Տ (Y %"D :1OH %Ru+`" "RKR.uCl'pI N:'yU[ſi􃥏ȦO?|B/ 0ll C#$a:73B\9 iG1O@>mپ'n2N"rv@=[m ;g< Ff,W U{wljOg!ܱn跪,o~Ͼտ0>pW`=m?B}_F[\5pb_:onn((1͈Mnp C}psi7V*X@DaK.=+w&pJ=kB˝kR؄O9̋ڹ 7:؃\o3P g D1YNM[ŧJQk"HՉH=Y^0?1qr12EO/*qN0(@_i`xݭz(; .Vm PV0zZWy: IiAZᐛ$2`ݧvz++70.{4ucn8c1j ^MV=e\o x̕nkmܲ/=/*@tAT";V6Ȍ<`#%l(}xO! l00$rU.|N҇,iI0J!My7 c,a8p'Oԗ2L|:|TRdpU{NJ$9>`n@J2? OY` թ'/H vMm~1\]f*S*=#GVhYI1/@8[}QOGE@\RDhD&{`62$yٰ ʲZ/AN9m=RFh #w>E۹C] \g!)nA:5b(ʏ@ZWC0^r/{ZHh*c~:[ſ=g#fׅ"NMeDᑋDlct"Mnj p΍o`k~Dlnaxo.N ہ]Yoy L%zeVniTJm)6{o}پ.M8cbaa8qkإ3️]wf}{8ٸ]s(c> =m[e`iRԹ'lS|eؿ}>?ާwuc1h-Qy1$(.yD0SkmiVm1.ϲV0gԙ+g/SĨc&b3!ɮ]{h4)EUiS;ﮕy*Iax^{iDžD(a~45u9LutlʑyZݚV\i)ႃcHܒ# RSCʽ(N 9 z>juk7.zΆR-FfsZwOܘ pjm+AI7nR;u[a6O>5&R{7H?Z'&|uP-,z ,.p=`'π/:¸{MI~Hpa }.;zS>mz8t k+F4`a 10*n$?Sh8A0a"F|%oȟ{iue5I|k6;E|+S>p)@k375AW7;?M={\_[n,oޛʨsnU,X[^ RY\cR@ÇK^MW sglIqh>/~YP+qfP? PJ}$R-rFbԉ k{ߟP;K;u{ipi DUi~lI]H 7LNXG$]J!tX֫0->@,;bfP.@޲\1lxr?"(?ɵ) OxbêOuy^vR4^N@zF(ND4ې gޒSW@~ZnF."2l7-oǓvteږ^_vVʑ#톽;=.(w ֎7 P)w ҍ;iڶlݻ6=[Hz ,H萇Kg_/;ACHG\;5:@ڕ˗l6pE}"=~a]GFcNW[(UB3&Jwy Y{K3| fωNL͛{@<,qzx$WʰusVz6U=fOCZ/IG3Yd$.@hJ8$\hT:Is^Hb_qG#HjSATFˑdzvQC^v> Nv; u}15h"'T ,n"~&>ZԮm2HS)Rj`S$*"0wu-16El@0 l.p]w@Xol@\a =ra3:F$;z|Skk>_CB~hMS uXȑ#&ᬥZF|HY|Vذ CÐ " r{/Ls{?'Q$U}Q#܇v3Na|&JCԶIBV0 V3Vꞣ2!r7m.KHB/=ȳw[BTֵ>}7~֊!Ld"qi0uN6LH /ھc[x.P,sgN1#pzO˓}@I(C>lqٺu2llw 9C ,0CWHo)n yFc^..,;^+ /}أMhgcp|ٞzs9t,HHXo#1BRU1m./fyi> 6 J:ŪF9Ą]6gߵ^:eˑI)҂׆:BëNe:&ZY7-܂ ]~%}KP,rci"X-LQZXf¨-t8h077 Eh:qa]Nf_3@RH,&6g|tgqXyYk+60>w퓪q) [UUYKm4%ǥ"JQ ܐ=7ڑgcgǸdJS) DzXq v?X~p(q"v y&P:@ C1Mԛ;pGPL%esMKZL~;\G2n -u91LN c6pASdC*#N(FSQ{]e}$\i5тX?aAڃ m)g6yV$ߖ=}яO#Pʙ(+iF|IoqH >!|;zu@Q`vZP4Eۿm[&@0zk>ffܢ^>|a$ ߤ (r c'n6f{mY Dil򜱧zF푇u㶰ص]s_7^\lpmDVsl9,p5e }B}Q9;s~CYte&MiYNb: (B3)z><|q_ơMU+oA;z'Hܶz#jYIv*;EΉvR+4%ʀI[ K#FMj LYHlX}|LX" ߍp3!knXt}i=5׏?.@20``i 36R=Jy ^2No6785- S>F!!D;eaĉq2OH$$>ڠQF;U~]#|aLkD&~?$5I\<Wy]l(K'Y32_!'Aʌ?vN>nZbjUYjFU*3u*i@~J}vY$>@)>yf7E*՚[Xæ[6;護xK#PPz"ؖ,DQf| V?̗2Kxg|^2Nj2Ψ [Fj)D0$I"#i (~cW B i9S:Q#1O y`g~<A>16lX |P$u%KDnjXwRT2~X+(AOĴcg-YҕGkmɴQ[<wr^ `zTy'g񭰸!uM*"K⩿ 2"R|x/i՘Zٳ5>="Q5WtJEq_J<ߞ/vG'obX1"()pl%R;K-k %N|0*&Va#H$@ 0iGr6bփ{ MlO=TԬyN>>sn63@'c-J/lN'5cca$:>b?p$`I`Rд#I LUXƠhR8Y-):*3r,:i/@ I=i=tu3 I͈6vڂa DQ}I(I:=YmONM'eQ̵rSH0|Nԩvewu(iU]kN?3ZEV=cdﳼmqMߎ.56NVX0o cgxvw{-"rj 0vW/t0Nv6N#bJIH ͸{Ɔh`^ ;<57\`NPŤ ,D'u6's?qC>P-0JxTP ҏ)q%X$ X܂ts5NJ SKZ)ruz hFw/J٥,0GLlB"aMw() GMAtn-S@ )JqFvTUEU.j[ڶiC֍"z MB;33~ cUtٴi>+oޟv̦ ۶e– );ޙ*kvn&3jqM GܩJj{TzMqZ4@LîϋVk1}.3ZN aʌGI. 4z7U)*O6LAiM%\DS-iJ9n:m~G9&3"IDWl7`"a[R҈36Z[jtuEQB;1y&KsO- 6rR(i= dD`BrIڄ~;u:pxЧ~gHDsQ̴֚7F5DlW]kk m١z00IXd*Th>` dl^(p-c4^%g.RXVȏqK|xCe@ɽMO'z?s@5cu"6e3|0-r?, ZblX֞\Azb-0V`=`v\_=In+ SrbIV{)(BKTZ[/?%<)[.@*_b|}=uml\aI$ ^ltj5xmrF(މXi%jSe&C3A ]۵m\ e}3=K‹FaW~G}*,8cgD+zc$ L.eJ;1{SV.yhK G'y cuB˜:# Ytzr'*}~%A^2~] &=ڧZA=FƗaD`al@ ~w*ht=CCaޙrM/AYX/P[)Y/-gB+ʹ"0E>1_*X ]J{;u/$# ]/ֹpRBζӜNb<]Rx3m][i:"Δ޻h qOxX| y?)q atv6-e5Q-m 9]GXQjg2i~!p/کWp2oWy1KOVSBRR?y^#`G9׬)O,5$ZJdž>:YnQ|1lbPh@ݹW h:i32IJ' (?f@#yщI.sj-:F}$r1R``63^AIOEIPNb0DWҡ:;r"$۷_v4=`/ OcRtsHMPkLYT3g'_7>(sQ,Rg'I[<"ei)ώ( ȒN*fu2`<1?Jo(r,#/G)]^%$M' $V}0B[yj)k(1 ,H6|F /՚E[r/uTUvݣh p9s/AI%Oe I=Waϵ>+BZbI m (oXkVS)Q_5r!g@BE) (֫/GLc[)2Nnܿ/窱0rx8ShG $M Q'~~c-um>vmm(d['wg/Aڌٽ#a[ٞIPbQLmai%j-ع a#w8>u?yѦgx# 5idKK馕%QˬoSURҰn敁cXj>%[n^#ibָtԙMS4MQ] w<NcV|9rJ`TO/W+uR^餾ig7(4VcKN =ZeԽUuj@H^{= }=i?p< v͇%|n'oim'E2ˑ+ᆽ?lYHg^h" `#NK\ ,Xdhr /E Nu=_V$'QɽhC' U_Q.ul%Ni +7!@u[CN!OҜ ?^6үP*.څ\o$E[qRƓ׍|^ksV7gW~]e4<^}c5}l=ӡX%AL&s?J\`чԫǾ޳UB>OsE**}oi m{"vLa7d,3L}F{ɸd|$&(Kҹr@KJnC$$A.RBҎѺG9\ϙGJ@JSWb$K )s90e :9+֋dJKy2NN}Jy`XɵiS$T:KU]¤kYզ둮T:-P00鸘K4|6ƃpC s.x S&Ldpՙ,Lw2bZNMfK۾msdZ&Yt%%':v& .=W av]N8Iʥ9;wq&LɢG#ָ}tSf0zt*7,Cb (se{"k)bO豔#g#3>L/Ŷ VvQԠ<)M}JР+#=  H]ts$5p# r|=NŦ1J mߺD"~Nl(8@2.W pe`N(@E!Weޒ,Vh~gC&,+fȽAq/%B;iym"*Q8u1{3Qclo&e;谽ީϚ4DjHl̒BR5O2R״E{fJb섊j^1|܎˶?Tknź-u5?3:d3yxs{tó!E ?1x+w()K{%˽ýttvG{4NW3h(srrB^kZ$F Du~7TAq$̷8( [K28:0O[Y|yk?#WPѵ ͺ! .)E#+Y V_YWN TsG66"b/ |W-lDm8lg#eA}sNc"baa.Fr0SG? e,K1 --:9dhbd/KFT#l6Oч<ERWUGuL:n4VK7F虚wN^7%teΜvwZuc{Tj te"%Nmtӂ_K(RXިb+Jz8Kz u=Yw| - \IICĆajs}C耘!naT JU*$ӵ=w\YIu1>iAs :x?IOTPriXt~ ; R]Uظjg&JT~S9۷a-!+Wi—q=~_E7sի[u^D4Bb^fl+[nqaݺxذgn{ɧ7?~V[80E܋]g<I ջ}k*p&ID fx/I<ݻwSGYT 6*rC:9.\Rh\ X1!"(=c쑸J.%K>a'>u@ 4MT?~bP'?I a'"?B8ۑh)5VtR(Wuo>W(H^Y\}`pY{yet֯wo;wΞKc nٲ9`lȇr-4=L\@Pno 5얆zR=;|?6E5R7~ht{ jgwƶW}͞~&B?d ,}qTC<_1{EAf<MM [VcqB\3<@sxQv?2D;)#Qo}0xh#QI%dTVn/Ziҽ.pҎq4iGN.ܾ~۫Dnܛ5GpI mL*]vH~PKF_ϵ PaݔvS?;;eMST֒}"d =v;1:X2r9"i+}VK&pG T)s&hEP n ?&M$Q[\@Md q M/*NVv#iе`Nk1Ba{K&'2ӆ?qڦg͇ V2Wxq>gʫP!\rD \ .(_r?)P-N5D-ӧxk@w:w9}O/|{> q͔^R".kTe;S%x:'ѿr!es yeJ:s/mH|'.\lKBFX7uۣ,B?+<,QcŢ{VA?”ܫpOdb>Pg P Q?K~PN@ضc]^^v0覣V ))ʐ Ř^6{ nn x)wZꁞaQJ@y4!:XJݓwiFM*ܴ)(Pm#u6]>D"<-|ɖ7n ]zA W7E)RE7 P.3`Il,jZ0<{Lr+*ArYAHGG)ROht(7Zf dMɓKRo /W;H4H?bbC8eSaӲVLL#&بFOJl5'.k*Z騤k={xw(JdQ~[Tpc4JPhRx@AlpĮex`=nsmG?37?7Y#]Pg;FI8_'$$O*ItD'F "W$LiN Ht@ Hx [#>-,R8Z-]۹VT/ʹ˾ݝEiY"CSut!B87]c'╰)*tϊ}(P\L< t=Uո(Sߛ bmD|[Lb4*RP'6UEtd]t h˭FjXC4(jIW.-]"\Ihe\E|r% eTeТZmq(m|e-y z|_$)Q>?|"Z"~r!* 5ʡokBͧ MAK\oEx2  n1 (2#f/_8&n!6& v ŹYh/:b,Z۩][w6έV valhNf!6oj[JPJ`lkX7mI+UUY;~m '2?f,Jeh0F0\afH8K.9aưOoxO|r1J eX[+)|:w E7ops6 ֮m\?(`;^¢Nf\աL6BO@EE9vƙFYXegQ3Ovb8ǡԹ ,Q48I[F߷ +Pj%huIDօtbnș#1j݀7bdH KY.,f2Ti" db5PNw 3㴷MHR[Km[Ugtي \K7n%/i Cq%,í2 MJX^C NFG8Rsﰙjc 6.5g㴔YHr] gsosg cy?? 94H~¶7_u /=zêbTe%:#%o ?1Ӓ߸M} _p͘/;eW\^}u7ݪRLQ`hkz ]^p1߫)u2PB68ӢdU)2F3>`lq”\uPl_ AE_q2)t/ .;fIVdq/8)|& JĽb^ƽ\G](G%0:5KUV_{{A\!y?)> H`ϙڬpud gKlSi: V(|'Ɨ>QI9Ou^u3a1L8 /k'ģNҴqg!APeǔ5܈_tѺphwa?8J3>@KKnN8磥@{lLt) N9j ^^7cF p_{!;zҿnqeumޱcޖC۱&6o}z|^V~g(acz)_dXlNaw/(zr^b,r(\74(.-qZaweKDΡzc-۹evmV<#7C`yg쉧v@ey !lNgY}(D gCCّ?3ffم$ϝPca tmJԇUp"[렖\^˰Onɭ&Cil0HjݪJ|׭ې_}شYN&:.(8n\Z mO5Q寜EF\܀ U) `R\8}iaD]#wLr{Ųq2E_b!¸EG 2yQh45LzbfoqqɵIq˾ZC;`U_GR=0ĦwM/ F=@4>3E*JX|Hs|sQVE»qsTkSFVno鲞W P'ܳxFj#ωgY EVBf?](c #G] ̻AF c #cv&Ƥ" P;:cIGC8F.$qD5ɓaQqh}뭷-nG|_̖ߣ>&O"!N{. Y,JI%Q6$uQM$;-F12mb@~xlNe EzxB](kBxCHb0_b?]c\$^[w1rzG] /`=\ip(6y<> }|([7S#𼨏? r9tmM]/0^6Q'3 m/ܵF$p!~?C_(\ZI]OHCҝwij3+/YPw>u 0):U)`ev v"iιndZ/Tsi=R8uwXŸk^ im }a~PR=^]F.?2RH]4Vd潣z;vrt*rd|,QN?<+ˋQbrc.B.bS:G#kr70x @/,l('+ H7$K\N c% fЈ}qjمlu^=>cos.^_ Jeq?Zj@X~&&&@WSȲINɰѲ1LHNWzZYwև_Y'4UqSSSWOTPPj)J 1~_ P!N٨F}'_/)bJ`6}R s=~0D$@ sZJLV R-zaTE^B]lc H'6N^rq[|wdr7ya#=Gz52.Ro>@*r-mV J~XæO,EذY8cOOjZb.,\\BI \6ԕQW1y% ŏg?Y_>w!׊gؑC :𜤱H:!~ b}Cz * ňA^i3;P?6g'e G^Jm'm;mHxigvx{}C Bhp!*J(* ʗ!sw:,E޴D&G:at\&(M$I|2GR9ɜâ=,e|Q\ahLP ҏ!̔OH偫lGk%VbiRFbGDu`#d ޽s%cdLbOp(z`饢9+U/y#MJO޺^tHNׅ_:=ADN!BKXGWrGDwƈt(]>MVLD0#vP!*Cryy1Fy<ʎӰΦ\n\<=N )Nۮ1N%1-]n8 v门Zdf:E.riXu:9j+)ꂗP 啌ʯKQ4.\`݁驼޸9o%J!(##}~6Bnr扞_)Nf ?CQ$H:h$H^GbԩvSEYh$6hJ$fgSō;E?o6iNtuiuTQƜCɠn[ذ~c\0Ug/$f-W \ P)"v05Jd1Ux+ slbP ik`Xa*4kM* #: / qb`Q66y_͵=Ni}L^ȑ'.%|[ m/9"刵r0`I=ԛLzc< x!ͽb[`]K׫ޛ̕g{w;}A)}zW2#ܡ{yrX]R([\ .nhǰf#_ Ac'O+I|/qVr]7nFlxx7~lrOXg.;|#a 0^(wD㉺k#X,W1ʥU$7B ?ӷ$%F(Bㄾ 16x6YhT]tm71*d3cqwTt\8a܀2H#&3XLvP5f^2Gy1/ mEKVc)%@"1)=[ǵ^$%Sꮶ_ O?x\wqU]"+P!JWQigT.=R3BF Qgh{0싑D WHBZ!2IZg$1RdҚiڙm&yau ˞? *bKahE|-Ma(iqt D'}.zY*mg X|v':3Bc7!|7coͨ5SUeV-0@ B=) 9!i,y%g̸XpbVEpGł[FVMq)C͹[+Z;- phd [g՚*x\b{ɓvq , VI;r޾s;cd?qK-̧pԝ> Iԉ||KR̕ϋAJW[/bv0|u*pyQxM[p&_-&琍9`ƛl$l\ c|oܞ'@A'C sDwQDsv(h'?Y L/h?ppsBM`uY'C2VƈB3ļ|0^=m2H#R=@Ԙ1`;rg]/@d{~D+ P)]/FDK~&<:aVyGM{|s Ȯwqq)#HǎI yB%VEd$֣V q=&jo誱DبΊG &.FڍsҎn.6lVv%|]4(&m2UrE\pa=g$L.EUr)"QcQ_$BTgZ0## (f~%``llTqAiec_@8q$A"jP#AF6QR6 y5<$nkho 02<3 ׸1>(!3Wgu]FfrE;>\H(P2ۥU0zb-OR DԄI,o{-s8wO%MPF8e O$1BF]: 6Q \lxFbHPU N(k)[suw/F,&KbD!ZogN/7PJó ݌?V-z(ޡ0|N ؟/gRnico_7a`Uͽ3gtp@TqGCFm: q6)3ў__s2N_"ת@L+.{) +4@2 թNڎ-cybx drrc{-F%(!`tњ)~У}:ÚO|'Y (;T"kk]z;πzKwZ:*{]β ]:%Eca;#L8eBd]$(vAAC'߭(b.I#Ðn=P!nhuXbv/iqܰq"hG"|,/6P# ; \$0* &h3t[JT'UfDI]L,&+G,_vmH]ԨZ`Uq$%ju҂NQ]oY~kVM?+BGVOE"<<NgSYeH@\>,ǖ׹Ƌ9%LLR[Hz=?b޽b1 ],.Ζ6Z_\@]!*, _hI pӖ au- #_ƚ yF G@Nag ٘渀XI!7]c_aS0SF<{Q mV ' \BG@K0>PbHW`RYG D!# IkD}OC l`W;W/ةSvMv62ߑ a1T'eD܉!lp:^[DvEQz8G"9Eqc֪ Nя;3FYIݮ}.H|EfNbHD=0V.NG RԜF_!SK78FP[ zD@YMϯ i1[Y1\3(m22z% s]~a,kSۙy>O?I%KFiC %첪3bpv%K[= d2nbXb(nE\_ujWSu= =` ҏrɳ^?`LIa-;*eI#L`XLƐf.#JFX0rO $ ׊Mﴅ #DK``J Wl;F2 T6W{3vt]&AHe>9$>*?Mxz^z]|V`;a 3EKA|;m߸N%Bk(JL[\K1̹N$g(c;^"'~/}(BjN>[^W,%'aď.+t\CW_*5a.> o( )Sg/~˽ ǽCRz;b(<\uצ_ ׈$ˍMnn6-ĕֹpν-͓;CH4.BX%X&7 L4z)Љ9󠍌MR)CE oy͘(4IJbזRlAGb "pS>bverd>}ug3Ze s5zfHς{u]:-[nK%hSkԾ'ϧĕc!{݅@ Z&5lݜ&lm0BE}rd07Yz݋3$1pې5?5UvUi-LH6(uf oTa>j*}V M*Ԋbc[J*_2 >@8ȶȬ%M+BҭiAǕʫ{GMě*6Ù}"a+"o73@ro{ƓpJ\% '3[$'eaQE--61twיSɧ劖5yLHG#MX>B 汳W+ogsO/x>P*XƯ($6Vv1HwPRb ȕ\ҦHl3ɰy)QGeu V! P%D+M}6tJ(C%MNQ]do\~.ubx_ho\ $On9bDMBAb;ʑ^׉-Byv_nOr?Lu'w|;^VM>JC^"ȝD]ToTv*2ʝD&%ɵtU?%h^9ivMgxo.Ø{)Kyӟ )Cb𜨃cp-u8%bʓ$Ø@"#~_ED^xp"Ix$FKRl L9)ԥr[aL*@DaS'Mԃ߹NܾRAy> ͆8\ฟ(lqk'A, 6xO#Wwy }|l\lzF0WNfWbu؋ԣ8=riNtb| @,:>mR>\{W<%+bi; E;}" }TS$8la}p5y0Y X0G?ywf?xQbZoԿzgKI(&:_n;p3إڵI~O~%C5LJHڰ?Zmg]QDB)]76 ȘiGct(J &c& fәY ѭBn\̎)R)|pX ,@(Jg'-bb_7D+#fI$?%E"a @ɰ)R2PQu$FEFraO܀km Z&'ۄMVdg6 XD?F Ft{ܷJF ?s%:`Kn X(FVQ9 ͎&Ɛ q8$xu(RFJe+'N28e U* aafغm-֋Wy[7=C{l=b33Y$|MKS}'Pa9P0|Q"EYrQd cbsCC"#@HNzG P܏Ki>VHfssHw\+O]cNuWXemN_?#>B[]B "EC"c x qH޿vX㾁7H@I/ 7eˊ-ˑ˖=qƕRj2NbIRJ%I%?RTLf4c4%[JDQ[$7A ޳O}ދ瞽Wk}hdG{î=É~6+V}aM3pzM2rRn~;?-cC 2Ka(΂,4kMִ 2R3Adq_?ՑL<xq45!2΋ez3J-^(oa܇31a{pU9z *0R)z"a.&ɁÛ@iYm[j39q:'Hz\LΫbdNPf$̫%Ӡ18|g9+ E1L ۤhł8,X񕲳5BhOcF=F pH ٔ ,E_%w<3e\v(ZXS'u]I77LQt8ik\JZthx i^f4BI- ,NƿI=,K@ϱ(+TN| PRƢژodİZY] fGW"t#=2,m\X ƴPe|}7lYPV' gdžAR]1wu1&`PζH'GyG~ɼ`Gs0S… F9PSʬ,v Q2k:N1s hVpTo Ot8`NC7=ް3S@W eh}= P+ /Q;w( R^րN"^H @aG `Fԩ msL8ґ7evdl Vcu9163zҮ965wŧ6c֬k>77xq6axw} 2aV fTq/,вY̾3fI/Y1 9,&&I,P1FdfK nfzD]6l=` RJxw"&oD B~[23Kf "9/O8흮$j4 Ff]ʐeF0l+@RM4N ;f3U;Cq\NY Q"t] *KN^1;Y1<N 㗙88VbQg#N EU=[kS,9#w FC;qYhdL~D~l~F1U$|Lk^%Lm\O.{)&< 5.#S54XJȆYJt 0GjX u-o3X2 8B{LϋPBÂI|M8fNQtyE:uM;Mule`f]~q;==~sΧfa O~:\=>x1lۈ/:h+78,Yd zpi4ZD)9\5) yd_p)ϹO\ m QNg Fc! S5 ݗx<;jB"TI ~d`(zꩧbx;uzn  Qa5h#YV53Iq[-ɸP,;wCIXySwd Lб~^rl ך 5\{?C5洚I%}P <@ΏEP%kϑ9-;V ɻ#|f9ux.lY-sL}C~x|3g1gb roVF2c>yj9S}=Dz+L̞s@!+)߈lytS3ȀR 9cL,3 ("2$6sY O34][_5*%lO 1¢HLTL;ˎ4q38 E*;g05Kf%C;ֺ^thO'YJC= SF![ҥ>_ei-5bm L Dim\}7p:S^֌^?4ba^ 4M_a/{H##Wg/b)"a' S"DgqJ2mLǬcx>Pߎ`9X fc.0W8K=5NSp^c.Ϝ_e}V }k_dt|gz^QD:/ ׌-QcXABCywN/$YcDӑrCܘaƖmRYryϸVo~- ؍a?0ýkظנ?K`S*SAS 2YL̍ӧDIДܮ ‰:YudT'Јe`f-$a9J6[gÃNgQbIL]iGd zjK(3/1 AkcOE{8nƫ I{7\ b:!=C]r=iO$1JoSmRHǀHN'U}LYO!AX t#3]'W+Apzw\ y=὏u]Tn2dbY_F)(C3 R[^GQ},Ix<qίN\zz(:^8sfbaWgi[-"zs~˳X.k/ y;~w}P{{?^xS᧶Tx´p165u7CC0~?#EM6O1WS`e0Ά ε?|7Y7 Y{ י2V.wW=3pYǘ/!evO禼1 *k]My1~պ<}0$`qa |l do}[e=e(5Q(@3(ohEEPؕ Jyc}t ⸡4_2d*!=$-y^MV7UڮԗdR+Qȗ79(X\3KBu >l.ltTx^I&x(mYæ+t+ᣍҬ%'ԈwN]]y-WI9¢ E8Sbga 8jǒsB¿ic-JT:fp$h`y >p)/ $|O/rxq𑵏G|$LR ゙b,h1<1,&qfll:\ϵS\Sl._C>~[ZXfϴsH]!@|fynŃ9&ֺTPsOkmd9 ~ uOSg٨3j013w ;'eZo+ͩK5?ð(P-kqhqj~r猫@::~prao7Žf{}/uz3Smae~PS73sЁ﹧d~*͚];x@5; } # SӲ'8XvWV֓>I?[:]~7 5=tը$Nǭ0$Rwe'H0ta öنYd'~6NXL a!cϤӉyj-ە ͆Нi&oN Y ==)S{Y 1cR9S@SJ, $ӝb^AD(q)o}OZUv6.YPcjU) u .;! 52ҊM)lJ\=I_wu$rGȣda~06LA-o&UD`me!hB,y̎T맰4e.6~8|2H1dbx\S2f'9!hdY)Ҝ,U|VlbfcI|8g'CˌUeXPc-$@vnp-QtGP{tƂ2u^U5tmgO41BV <,IquPD_u3F*g&9߽ˆ1әlh|'K")$ב@h b2f)GiiTbdE# >_Ӳ?/:Ӳ4pt#bwL_o)crM̙r:'I-21Qvr +RdKT|1,%58}I)G`@Mk6HfS**N  =^Q;ɏ[z1րG,`<Nֲ>KAL $:ʘeb:fɼ,lkSnSj^1+uDz\sj{aAw=*}P# ͚]uX_-0W[GL56t:YӌfNbjQpPŀi7KGd%;4c(L [7R @@YY^$<^:]@zKNó _{kᥕVz[aC:N\vmpYB]cltΩ3vjC|Ǝ!זFԹ28?{$0\~M[,O?~flQXQV$9$ʅ,u$ZY+p,(Š kSC]Iaf)aWd%O!E3$&Å(΍w>f"2|L6X-4odS<4 ~^crdt9.f->/}WuG8.ݝ:^aaGq:wۋ^ߕN\ܘRCF'?O8niGU57Qs3#;|OpeFG]Sf[>gG<nYDxv60,ιoOڸ|׏W'H6!9I$ m%q*'9Nf3E1 JKkBZoL&HI[ajaHX}+`D#)|2gh`дt/!FIMC{M[0LIm ȆN1πNNcu 22,jʙyYď890 掀],mF(|Wb7 l=1, |_yeR̐iN5-)3}ft r|"X4^w F/oO9\7l9^@Y5ޑ#8THQfޙ:Y*Pswf*s0 >yC0dΫ7S )e7~ A|iwz_o+ã>N/ ņc6tYrCFw? KM{NLG8UfԙB2l\ pK{ RAZSq>M5Cr9yϭg5(nKzΦ)Ohp cr?}[ P#Ç1گx3wPhfx!hy6Ky<837%Ë2~FYuPs QHڐ!ǵ=S?g$&fⲖ7{j3 )lB6rL]ksE)oX@]ݬ _'Olzm 2IYJJ"YE:@A"`sm"*S:s>8`UlʛuvHPs, m^Ώ3*Ȥދ;r:Ьn[ z.|oCݡƵ7nx ٹy qg 9琝ykAWa(ԙmXW3,*6pnƐzqeXP'c1,a<`}8Y.er0_~j(<;?3< Sk soA1Za9ap!`x w5 r~K9 *zjayo69z1ȹ(X#GYdj갨dNI0e^ʹv".tp^qض6wVo9;vߐ3@w8Sb>p8Ύ6PY4jbf[& $}CuPQ6;QgM;X'{re6+-ޖW|FCU s 7s17D1<9Νa-wt{]Ʒ7ܰ>?y&#GC{nV+lsS<aI2Y3/N G,4k I.[qSC=X|ǖ7r겉M{]f,r2ϗ˩C8(icM̀2IafG7)N@uQ"L'ޜQf,ySe cn)7t932Muצ0F#(Wƹ̕P p:5֊$w˸U,c1R _D c!̧i͈dtcI@C_3j8) c)`\ۇ94O%-!\.R yӱU\VPsW\ E*~`pTaEe 1ZF@iZYhX!YN4|>Gυ? <n~kggמ2,M0jԙN q93C|NSz2}0Hjɢ;=U#Dև)d$qNc e !Fp,\G4fW݇Qa&s,ǘ[ԙYg{f,Rs62Y-D_ԅBD̚hD]zicHhk ]/eYWU` SFNﳚE>2d*S˄f `PGjZgޏ pl Sy?Gv#Sf\4aQx1U5½t&ipcA_.BZ(y46,IyHtFO[3VaEIC p/C_c%ŝQ1@1GG ߓv1y8lD`Vz)pap~A}f H̢j-~S/`8scqC+¡>v;'|#t~/~i_XG>Ѱy;긴hfĒ q*g_ˀC~\gO99ǰs|lRlI3ejF\veͮZ3'ǐ5 琋1Muxcv:+=dǪ8:MtqQ@eE7Փ&EL+ Y6# 2)@ i6,3$k{颭QPkmG xF %gJd j2)rr=ݤ+j% 3#=򁥂8wN(CFnQ#h ֥Ǣm4t,#GChWՒ4zdtkV1te~Mz,eewU-x%:ȊPJKʛDOLqy"Z{u?t Sq,X(ia9|x!1/͹ %@ ,m`1fkNbSkGdO">nus#lNҳ] {ʛXp>'Σ]6cf[*<_  PEǺS5G@Ă:PߴA>xu scn(,%c'x5 '|3: 71sq\$b8@ƙR_za-PAX?`HȢ12of8:p.H %^v2)g fse.w{qõUS{ 5N#úlRXLǿk`C+ NJXQFapl}N8g&"fW9]&mOYfެ$X/]P%6`]ŀ"Z$fwG0/d>2B&Y$,gC{@U),)Qd704 ϬrG e5a;RS(2;/+ $C=! l^2aM-,@Q`U)Wf+iN_~^w9 &YA~au_ *P<tUYxOK%`nV@bu=t꛼na^ $ݚ1PšB*)2}4$&TG_'&i&@UiR0;CGoF7oz0]r$fmpej|` L`>wBz/dQRad>W̶qP\;D{1<^1#s~ xQװ IpKKFٛtYjqDaư+@I7b=9 !-voCx4tGaHAg#qИ0mo] 0snaN p*71HŘiL0jH9n2ݨz+9S,L\ б'N?~D8v 7sd }?L1 a۞ЬY25 &(?<x-3M},Ŭy ^2+F`De}sMܨfϙ.SVnfy%1UNC{ɤ,` 1BV>脇AvO2 `B%Q6bGlkGwV&_,t"MwEjEJN@1Y1PqxM# bV +!23XG-*,fT36I^4]?յt bڧ^;3j$Ƥp.ezծr\dtuX8k1tw RáE:ϼ;i+#*Bh MU@y.ZZ!1zp^}@#ptLH1W])p@oX&1 1;2"o#}f2.{N0 C2% й&T1/u065z@4rT ,>z5ñfSBY5\`sowq)+~c8fD߸\iF{P=!@[|{1,O ~bePsw[z<'>Vu1ٶ̈́Io B'h֬Lu3?Cyn|Yv&A1ϘsGmm| Efyn>RPL:wx>˘ve4U#j 4BZI.K抄G":1d#]w(t}[L9ryZ.dHcϤf􆠄RV BƌNrVG;:҅"j> XHPS N)|ӹWQlR[RHPïdeLWDJG` k~N`Ra2e4-6Ovm;!!^ۍ1gRR<*G`O!#w"Y49g"PuDqQ4/}J:#b ( 9wͰ'y4،%dRq4mraͱKSN3{Ǒs7#h&P Y]8mG1L1OMTQ 9(!Ca+EG8%@!{G㸙q}ԑQGv1ekƓ{"TyYD1lt|L,׎{pi2uḏ<=۰&8&cYfoI}c()Ͳ0«i9)PgYT )LesRNVˀ̙Ω~ cu%슀*)$MLS <0ДFIsHfQgl9Ӹc*7Mg:>LF}6;^C s;' lۗY*YM(ȴ*3KGy'1)Btp"xtqtxH]2+e6Br$ԑ*=el4 w2J> e-;akC[f4U) r1!M4Lkf w]Oe׍] VfXqB _G X0FB)kiYL:oizC[R&1z2Xα0 fgk5>\#h>a| I>{ :7`yφ/q wGRhXʾqjpn9g>󹘎O3p|3v[JYRu^ }=xP|߻vãÙ|}`8:u(.'8N"s}k2Ԭ-;2+ƔʶTLb,z`-Ȉ8"+{f|ĨMco S/cPhƸ3B~piٔtm %KYL,9y8F2`DœUfa>qsD@MqT=?~7^c@ i8_f/2dps>35|F?h &kEM".$>]Gd֧z*\eep.2qxƍD5P Lcc #LZɌ`R` s~,5XIAݴ,LCf.% ]o6c,z>]Pi}>204:Aϊ8,lLX&_21y.i83;x hD:8ptpjho Yëf< *>.h\6Fy9)7T&1hӏ@,&ͶmCͨ(|}^Ѡ\V}sۺf-wTJ}(Z+*eƴ۷툠ى|:;r^SۜE aJCIL3_&2}p+yy3G-fr%]*!L9`D762QRIE2%dR q"mtHLfU zaL%.,2o#iDC}y-xFTN4֛=oT=3 O?̱ipp/F,V"]7dOy #Ϝ<㮭E(~.LlSO}=*?>_F4[≮"h{9_0[Ucc 9.a fw1 sr\#@-ԃ$dD׬"fa>@ԍ74)S[,"Hϕm\:: mC _ʗ=7!3ڦ~cO}*),w54񒵀S IP )z"[Z,&s q1,)ܡ_q7i uY kl;/p'e,,FƝ~([3+<)X/| cڪnL1Mi"fSkSs6-,u c 1ے>@eQ֛ 4*_trd֥̀f͚m&L_i Ɯi4EG`竩ϖvD,K-*+cuଞ8q8fI΂KAz'l>G11RԯZ0 æsFqEMa&cPY*W88êHLiΡ>USsf46J*@uV22NEǬ8ؘPuJ6yRb{d6mSOɸ&:c 3DDw:4D~Lʮv'!N&E6QJ3EG#sqHs"4́4̆$`'n)aڶ}9t$dҽNvrGZoDzw&(S=\FfSYQia #/.!T}1OH#&,]Jr =nB)L+g22*e F Osnnr\Ck]@0 4'PZe2;v L@?OEStDէ/7G0O-n_,H9ȑK_r)=wGf _|)b&>ʹ<?׿ c  @>mw/:q= S q6K WJZP>,<vN1/sI}5\ᴲ)ǙI=*kA-_ נ^1p~ {ҡ7>Z`"{P/˃6g_4 = buWgτ'mo  ;XC{'Ɖ}3jX:Ѭ-|})schc p'\OƝ:d-y-HO4}j!-C Y Cfc`, m P>z1f?zCC{)7 ¼0ݲKW83#TgϢXnX dx.1G:#d {0 Y| g,7έXU`P-ΆPuݦd z]\C[Yfakǎ-S~Npuv*"hȆ7 AZM.E7k벌|Np;ϻo=~3?*XM{Iqw4!&;A<{ &c L2"V:OL QWti;%d 1ͻ0*8󦉐Q c!FaEKY8ɡC0V8(q*؆;vg2BZI;mkzG@$:1gdzڙ9ɑ %|e>F!l,Av&~oܶ;3./5l#z:Pk!eFlnԪ}J4AVsh FM;M;y"\F4dP)k0mv7O mr(t2qD*AԞʩ WKZ@E|nK9!IeT| %Dm5ΥOGG/V`4 "o}M0:2> ܝΰ{]j݋62&fuu*@h5XuuyVsmg{Y9,Guyy=}R!u>SghYFp"ʔqE!TZpeY>2:qZlUBP\D#}33ûnzWؽmw W{:~'su:N=cDq~P c1-)o1O/ @[Zj{ VԖ(yexq=a`*x0BM{D}ux* E7eN5DszK cGH m rov,%0Ƹ'>v{`Zޅ%2k\k#K6z)0Ӛ2éǦQ~9y)뀝*iדS1Yet)-aSY ;u&FLbbLigg{,kX Jh4~Q< QPt_RF# YHsuwQq%t8p(j01 c箝Est*.tΓ  ME&FB7Oa:ءݻW>agIi6X$B-.9=/9KT k.DٵkOqyIPKaaab+qk{\оӧgeNWd&?5p۶~(uÜg2,10?Z;]+fV7^TJXx(a_B|y㺥_ |kNȱz׻UX+fKqW[g G1ơ{>d`x/x‡6+곇ׁf*^!2C , ʰ'ٓφ{{x<"qc 3Re.@ y;~2P׀2&S\?S'm0,L@0(- >vY9ݥH Oq:4>rh߳XQ~>|Cg\1e7u0f!5ڠ av&~v(/{E94`c\w>7U0cmdN\VȌ{όDzO>Y /uPƐ1:p#mp$C+m>a^RkHشu"fo\G/soj@|LnYsWwnSV慜g ey/mUV6k+eWџGO:rβ/ " iݘ+:2ҚPkvT#uad~X.8Ѵpϫ[9T SN \:5Qq" -KDa wB &1m⩒jYXT| EV#zBPNZ1ܹ,E]~0YfoȐC3EfjWP$3C&hI5ˠYǮ/eZ?3|g].Yo%%#'fչ2>5kc2Z1P%^+XPvfG rlH fJgKgXm>#&Sl;R=l|>pP)vT/M{@{-@.Gv.L` l,\&KN`q 0?\2.Đ75FN3V yR2f*<ߴ17J+QLƝ4ڸ:YY) `<R$<:-F@]p,(? Ek E_ c8R_8}qJV0WE2͆M1n I,UgJ62>lc 492ˡ)yUkCh ;)1su奩.}20#U]l>:DZȂ)EٱIarq,jPUIJMq1j Sjx-; PE2 `|muB'_OEiyyD,W*>"Ke X),Nk "Yr_ZZ1XȓF[};Q+i\$?wgp<˦1՗#.< !5.pqVnPb]V_'MS#莽"9V^ u3(5)\kCwP:7?ܠ"mccqjF[eCԺ*f!S̩P~CyK]a3{ 3 bh+;הR:|G @DYASuC'z@anQ``. ☕H@2&H|Ghלk&iMͬ%tb֞5s1jv7=5*̵bJs6(q<ו58}|j9W ĩl4r%?8n̟ [5 eVzo0 MjIi6ں`oY7bƞ `_DV&! "Y5j6e!r!e> M(Fu1e EL4ueӿ*:y+;)pS҂8-c'snLi3- JJ{;W6f2d*/%;c++EzZB5 q C06If)幢22b1ד>lݓ~E+{ ;\Iokrf֌ 5Ɖ;ۿd”U޳ŀs-9mbA%_>?T?J'>IY>|4|ߌcJ[φ{a }I{C*>RXrVbXLF\?dIeMf;NVs~(2$4$Ԏ= #JECe0Δ豣 ''3G֏pcc>8}5 + ,! R^P+EY > r,0ݵ7cͿբ9,K\WglJʺ͂VEFP@= Z3 q\rM@X"x`&Z-fr2Ԑvx]) iLg6/|o, cm;)1Ɠk$(N9~3`G>SgƐ: 9$e)1qQ?03dރ#S?Bw} n~ͨުjB1tbX!ezVt ~< ~늭 ?{Xk]3E|UCf~^ƭS׉Q:X߮Aͣ/ߝVm1x=/Pk줰t;S2L`HفFX[M ԏ15k1|EIVJ% ZbXcrxp4'ѼQץq3&Zl4nm'3ibz,wbxI/^ iY3(;1.a]Ğ9Uvc)mV@Fփ鲾M*Ifj;X 2W,(!quql,w2<ǧ1uR*AL~6JPb"LW" tr4B9-Pa|{Mo׼{lkbOdpPIǙgAScߌ::޸o W `(6NҘs\sH0aCh݀:2Gt鳟6hŹ5LFpM!(K{93dp0F0vՊ~Ƃkk1]pò|Y )g Z'4S LOz ;2FAQ[Bp Nu PsP03Q?eı]9qq>sKVs)lCԞnw'ui םym8R&vI5iSAHd2SkI0k8CfP`}{޳e"26b^rCзn_PsBl'j]|s}ٞ@J_gcLyY7ev K<={nu,Cy^T9VFb]JXJП)`iJ1E 㷒M{sҽ/dtH[kdzO c,WJT9Us7யw1#kdÄOBj7jإLG!d?=]Q,:7\͌Z;M1°@K upgP L 3/RD3y̐|0dD/S !*Os|NrK@g=ڗ3/@IRLb%ɐ1 F6LLݏA?r2R }؈=).RzLXQVy4f!k\yƇQ(en3VL[~t8AULFAxFw4Z|DЂ] ո@\?vxD%ݨKeX)󶸨ӑsE J^,0/a:WL 8t,N5#M.9 6=qIY&XXŰ _./@ad}~vܐt"^z9|u.ifX,g߆ͬf 00\' eqy5&sgc OL}Em̖dz_:8 y$#Kףּs}'E9Qd2.ʹo??cj(m;;(Cq dzaȞYŵ4ˑ j3 FG_Hdp7۬Kh[j0|FVvȬb.འ5zGQ!݆qY4 !צ*uK& ̻OsY]?^I$vN19Lh2 o4gd,n4ܘrES$Q+092^Ya8_*r{3wrj+3&@ɜy^1:^>TZ1l9+{ UQEBS 3\iEڸf0 >2DL\~^Ʈ:qɈd0w{>p9k cJ+̰ =qdR۞+YK!pNtp3fאtC PH*CdaӾwx;/|o+W+{ k'O.闙lQBf'bV715Dܽ>DM Xh` eEP*Y<M:|OZ+f-B_\ت[#C]njR<ȱRFL+>bB0Q)\49,1Ӯu]`q 9㙮1CyCyfԩ\/b~-M@B_t1RpC.n~b%Nj&Evde Ɏ +Qzti'KHiH!+AuC%JEf Ԅ1jydnEqS SQWt/ƴ!O(|*M Ť)2x܍cЙY>~OWT†Pȴ-8UJ㑎ٶ= IYԂ)hv<LKrW׍J*}_ 2^A1 Ejd(VVJ nL QO @6B,9Q{0:UINY&-`EFR(Af8BMo E _ e0^+c$.~JN"ixN _߈NxJ{:.پŁ܃|5P-.ddgE7C84| fVܝC#΢*'9mt?*3] 7o9yHkU+  u:\, e ސC1\[h;'@[ ]CԱYl@Ӄkɱb\X3FoT.ͬ#֜kPuֹƍ>fV #3\ga11d K?#NdIF/|Oa(Ӊq!121U\X`jSm54䜓j ̐:XsKF {A'6e SHجGVLYj9ie86篺1'|gaաe^ok*}zKa~xh6ZץϚF^OI7/xպ.YPZ`fYe3<9|haAߑg>vagwKg6OM=+N.L 1ͬBKf! i\ ں&kad_t!A k'4V$%X­"M/I1j䮍m5zh,pʤt<&u%I +lפ  F 2 tN_BU8vC$\2i cUa4}}}lOk(\֞s%S979~hH\Iy>/zBDb]xpļ!8wHqWrUwGqlY_|ZÑuP)Kp0Pص{W8p@oWNt{]kw=k{ƩWa ;wia(_drYaEUqPd#b^ONi#0fF:(~ DŰ( ag  A ^aϿCu>4:uA vPPOpͼ tȔ1KNsąY.v<8r0EF4xCC(o;8}|^Lml(/piZfQSFZl`݂Z)F3x.u9o~31̖%x<ցv\=8,O]kl+낋;_C(b#$Ō}[5| 'e/?+j +3h~k_~S(*~woL«A 2GHa4G􋂶ۈэYYEР~x2n|$XYvlu**@&9r]&lJIcn ,dMzƾ6vc?GY42)Bj3]P: HRxRv ^Juz7|u~ql-KvƜ͊ lRts`7ܤK!C!dB+pd(1N F(ʀʤ+M0^M:<Ї~1Y|lY Gox#wYԅk_F&9A"0 {n{_MSL-TNN/בŦXP..nGG4wޛvke`Rx,^pb/z)M$y0Ɯl2/wX*\.]$qN 5 j5tptXԳaNc7~Qք4ONv'vP> }B<k ~ڡ6e]ԩc@ "n jc8)EcE{z9T0(fm /q":cWCFuRtTղEjKnl0 zԱ1!ecCkvMc1^tVfsia9  687hN9}q{O!d_8iuʢ}+ 9 26l>C=d2rԚ:2űbQ־Dʓ/<&cQ jY`.S 5ttl-[5C Z c+2miXx"9q~X8=V3L|fVn>k m{b5-) 7,,,:5&˕TKn`ݮFaҤYr*dBNZ4d'9a(~xiΙd1 yZ,51f@Mu4=@b߼&@ L-ꑌ ȮkT)uYB&"t@91 pY-[,oyPBN9ry Vm[dHכ:s\3qT7J%s0,ORÒCU4+ -cvp.vÓ2ߙM;eP?)wR޹jn'S|rk3fd^՚4u0ƛ& 8sRߓCLaN=Oh'sEkt}sQ g Z u2t:0̖n'S:s鞿@k.|mu\eںʮ oAZU >ș S寄]M~ *#Ӥ;Rgqq!UG M1ijc PҤ"gd3b֣ V"$]fȂ1(_QXI.Uc.;?~4A#kdfatsI7&K%Ny)4VrJ:Rkib7 *Et!$(up)N/Iʨ6e0r}RNOxYI]F p!( I[%j0׺\F<3B%-l^=2&]WZ#O$Y'"J}Ycj4zћrg}Nnͯ|R,(͞mw?5krMM$MTx`vax/b8'$HV/j\sO?o| gZhھKK"s;΂qN֏C;WȞNKAr(B-FQS>ܸ=o'OG0cS'9O.WPcqؓcN;fA05o֗o LGp5]CVc'AV@x5L0 Y&\4cG9%#56 -|\>7̉~bXMϦM:` pyFIadirj_ƕs# 0$Bd1 1j&;5!L *Raq).lqN6ձl:` , f]!dU:5\{x|ປ vpæ- JSǐ0Ww N>Ԧ9~,A \kR'\ 29i?i\u_|!qt-AQp,?+u\`$8p`fz5~>vTw택|$=@<je@,G+^K`劀*xfqg@LDӪ^ }WhVʼnusx4;Y5鬨N&TnNgzXȚrrz)~[y_ԁQw0=rJ4gf$3mP hX:eLrZ/!K;Y0kR)pl>:Xd[ &dKjو ؕDRc d6ڍcBW ݘm*k"񔂚5c =<7 B]æs6HQH$p1)U!8/2 4Ӻ7tˠT2׿:|)'4]j-|a|]J)xw.o!ufa]++_J\_E8\?*io~[ Boxy</Ry}Ї>½($1N3Lk w0D:'452 <ػOb[X!ɂcƖ|~9|Q_e~1 5p8*w5r6Y{ϙG 斻\G60ԉ6BgsFy~;rf0`\EQx#iϛ-;nύL%:/VN e8 '3(| 2[6N8k 6`0uA FsQPEuqd(Cd@h`a[6Rl6\cñ̺SΘ  pevx 1sX 6z7LF\+;$:8/` aFL2%Y{_^ƕs .9T#1:8{~c4.e`D^blI\qfRW[AGY ;;e{zi:F,D!c /36y{qU ˵.BY8qjx 1&+klh|3!]'c(}wIC>%'x<'ޟ3:?ѳ1M0w~*2.l낳~CKEa}/`tS眫:$LC|~nPL39}o|b< !]^?_LJDfaM$:s `}V'tdP ER@F@$fcyēhlɎiB:aDGX`zL28DЗ2 wYN'+e6U0Bs<]AlaAM>gJKl)6;-1"w%|~:}ate\?5)/m{*∙m&26˅haəXSqcoތLINfpiu-*~;|ߩl  aGIN @1Y`"wNq\(Ӂ[1z*hd6WOn"ۛAdm0BXfv% mԉ4O2۶Qk횫qT2 ~=z49=/~|II;d\}O6D~;;g\`w~oEvs SsJYp$*LҴ8K8(yg ;p8Pw'u٭X$CnL9mMχjs±#³?zt~uN+"琹nul±O:+UaΔǑMuxx1&}{1f/x(9 xxeLh yP`,CxVEWMY2f7S܃e{ev'1\V|5yhhL)㦚sg< TP!mb>9) 2Ov/3Ov?ls^)c% 6rOgk̺xs;I]x?q/d$7s0_ƈ@>Ӊ3WPǝp]ofRSYmk1kbM]uhZ/[=7n!F(>2XzszӐ~)M9䓟-׼*_yp߼)sox{✔) n2mzC1U:w*ϻ~slg^7f?#?aX^]S\-ve4UΈi<ZNjQ6 '(v$ Ɲ'IUtN]VcnT1(5]uEGُyblHtP ر#D؞/]f4h"b8M+%;Dhu!#e=ON7CG0kh41262UP h0q,BׂQ&];Xy+)jSwKspq1WDfGj7b\Iai5˫+l!(LI eL FE/ R٘Q)9{;Rvv>0'{ꩯGX~K\|+_I|<>s^;;v pI*@?k] TK{GYDJBw#>S~:e~ ."{ԈQ #i!ocuX}g3Sǀqaí~BlauXݩL1Źdzg:X<䓱?\<+ 0,Fb?|Ñ#Ƀm-XWfc}+vP5;BԻ 9xb  oUCp9V)g>`n?}0=nB#pʜ:ceF әA~Ks1.G-h*]eZq.sN沛49 0L9^22ndt <ùߗX0PP4LF !j\DŽ60]kڪ^ iY; RfzP/}$ NcpwvQM fR<>ɜ2]^~hr ˱." <[V[cq]s,>{ѷ /~1n$إ; `J m?>+C.֮u<R+ B¯ꯖAlJ8?K# .ggõ\R8\hҮ2ϩo+! t)6ro$ή+ MA0yE?0WRBƝ|z^+ݨᲱLb28чz,VLD 0`+1=z85ܤƱy!̃ 6L49#WZ V$"MKyqyob̷m۱ {Z/M} ÝBWu:6nL/ُcB]2Ϻ9}WƘɡ;wwXKXf'fas S31z裢|gùG%7$]b=^SO3`8!ƔJ;i`> ~s<>$2"LF!?0'?X4- ؁Ց5:NIv7tlڤXcK0ĬH|O}ea2vplx\2ÎPv%9dg`t8:~EjS&Q- C?c P,m7a@+I 0ԇa, NYh!5cxɌb|tv8FCy*䳌r (1/6 c¹8uC+Ɨu5_f!Bu5A%hcG@Џ\`[]oLvǔ\7zրOt;x;\wk#Сs3*͙>|EEYضo}[wBށa'QwsUki]𶷽->k亀2j~ovk¶fYy?;;%.dLJ*}/e|p/])6KwwS*>J@ [ 2 ptQ ˩C?f3lD`KbxQsRhjR I4ڦY[Ll_.)CfgP/ WS p ?a0d _uUrH%ӕ<4i8N)'JeR_X !vbZX`c^P J-t])BxBM(F[MSr !kC&#;# ͎/EAnCCciWPc}m=(\*](a5:%N3C,(G&O ]ÙlKTW|Y80yⲝlVR:5tM˜/Cz|3`jM: oW>᥈^R'E(xZ,i, E31'ön[3flpp">uL|u{.ufYl1V.3¦cnDc;rp 1;2 tu4ݽ,Ku<YDUl:8 G:t' ad?BΑV_ $p|6/! PO'P >b8\.ԑBK!MPF 6) (3Ñ!`2 |\G紬X´`qNr\3a3=%|Kʌ FZl[\kO2F"&3ˌJ%i"*즖ٟv8[]GdQZTeo ˳@r2qLvz_ukbz>oX^H=s!cb\̅7lS uΰvu-x?kS(!rm0* kol|ۡnVSP{W~W"|lx^]WT}6s82i&S<`VPKτVmWݚuŜ^/I@@osno{#/ue.2SOi|(e# my{{lkT/'OzHv&s;$4łD E"k(NB41`w譗:'U"2[ E q!5f)]M˜Gjt61V˜":g N 1I"`V9t,/Kz3miJ˨MbƙH dfHNZG@DE6J_@.bS $b3 ut#^1,RrrdbRXs&ktqbjUftrl钘Hc:E,n}e9SRo d lBkke;λy2nFoX/}o/Ov*ڑδ+NşS]\/;S‹g7Ě][S%g>8Q8<:v8j:MH6 P0:tL &94S/Ν̗}{a =y^`xöm1K$5D*.X*^()oAc؆:!2(C5eb ݔaaUd~)NJ9Y #FqOA08Vf򝡆\gP3uG 2p`y14Q,YD@ɔ}c n|:r;yZ9M[ 1seE!wp^߂N`M',@y;1ʌM\O|ܢ:3hjQ4,+ZW17.#~[0we8jPOEdEe=D[(>q=7ߴ7nWi1Umvi1\[bRl5B_DV-,[=QZf{u"Zx"^?VTepe>%i r] edq#)PIFf, M9˂mB4#%Po~^yq>Z?)bW2㆗b6ZA T賞K! hwMZ.m2^ \F uL U !3Ni4wƔЉ#c7-,dFYr9f!IޓAVdKNc292\ouGx; vc܍"M녚ڔ~G)ivv: .V~ll¶-q߿c6;lu\ΧSC”7y{Ã84ރG2̃mo%>υCv2rmx>:m GNiP[K}/&?t->naarWd*ٖHٵ4mϏq4cKJ?̢z%PO 00Ǐ X<=}z^vh#}۱=4^|,N-;hpm{'qbPwNxzSPn妸}]Cr~E1)ub?+װ;'B_DpDz.=9hudb\q/颚0bK>ETx\ga{SƟWhL H4,rD)1Y9-3G06F`*MUnm#K9!O]tvj}v) E>kPtFˡ0mY 21"â³b}tEA,Ӎ@E9ܑ\yKJGmgg[8u gc}q>lֆ㖿[gW[6c Ӽ=ܭJ]7A K9yJfm28h/|)i kȞ8nKOXʸ/[ _EGa==4 "X ;7ͭ de*#sk,=2eRݕ-u:.]VP`?Cu\uا~FǼXnˊse,|ZRt޹`ZgAJ0)B8緍vjV4y #ñ-^ϤMrNZ1i; cyF@[3QGVsp{_J6I Q=9u\^.w<5v= 6{uV{9]/.FDͪqV~ՅJ&J=nw?gX{y?}r6;Ug}6;s gGuދ9aT;.e}-/8ܷ|Z+xPǙ~o7^~.v'Y&Qr4}|P^'ly% oq{m_h6[,/k \^x\Hs}~Z_KюZVk5/E;x!v>}6r\oW0Gp^L2Z[`·.h낋w{r<ů[y&\ _{g7GÃʤ3j֬YJ qi5}0fUuT?X'I7׆&kaݬYf͚z[`m]ЬmKRrk?d; MhYŏH jnՖۖQUx\7/"ZՋ'-5k֬ɮ5َ͚?*6ڊ@\G q~6k,Y*-şpDmfu{hqϤ P/Bf͚5kyMuAf۵yl30nrvT5&lygjwxԵxj" یv5k֬Ѯ5͚-ڵv-T#P%ek ͚5gvܬYf͚^X[4k6ڵv/O_/JLD͚]كZ^8i^D;Xf͚5k֬Yekf͒muwÍ7=bƭ1thWƽ2JL{5kvpmyU֬Yf͚5ܮwe[4{/47X@ Uk.z^OJfͮ{.;ݬYf^zںY | zC={GASYfamYf͚5kuAٶ:o{SPoϟ'h|ޡMҬYf͚5k֬Yf͚5Czk'uf͚5k֬Yf͚5k쪷?߅?p[U5k֬Yf͚5k֬Yf7*?O諎z4k֬Yf͚5k֬Yf.B%\4U5k֬Yf͚5k֬Yf[Gٷ<LV*͚5k֬Yf͚5k֬Y-ۯ_ pͷӟ?𡏔UkJf͚5k֬Yf͚5kl˶z4k֬Yf͚5k֬Yf.:y22R`,'õl-Of͚5k֬Yf͚5kb'|wekLf͚5k֬Yf͚5k֬e/|=5PYf͚5k֬Yf͚5kl @f͚5k֬Yf͚5k֬Y-XTi֬Yf͚5k֬Yf͚ځ6PYf͚5k֬Yf͚5kvZ@f͚5k֬Yf͚5k֬Y;õbWK[ҬYf͚5k֬Yf͚5 o}˛õbWK[ҬYf͚5k֬Yf͚5 {Z Ti֬Yf͚5k֬Yf͚;5|n^ R*7k֬Yf{1ymg/(4k֬Yfͮ+~)p5Yhb Ti֬Yf^G$9r,ڵ#sM{o8g ,^|q_Gzcf͚5k4 :\Fۮ 5k֬Y׉ml׿co>?{iR8lf͚5kv5?Df]M@f͚5kubǎϵ}_[=lf͚5kvߎ6B6k?͚5k֬Yf͚5k֬YWzs'^ C )䧶4k֬Yf۱}}zMVz,۬Yf͚]m/l| _G>>rla޽+}םoysL|)Zww{RgV:x }#n֬Yf^kTB_ُ6K\Yf͚5kv =oFsz95lYW?}ϵKN g8ҿҬYf͚έTn֬Yf͚]3@f͚5k֬Yf͚5k֬Y-UJf͚5k֬Yf͚5k֬*͚5k֬Yf͚5k֬Yf[4k֬Yf͚5k֬Yf͚mҬYf͚5k֬Yf͚5kkJf͚5k֬Yf͚5k֬슀*?sa>͚5k֬Yf͚5k֬Yf&+!"g͚5k֬Yf͚5k֬Yfדf͚5k֬Yf͚5k֬Y-XU5k֬Yf͚5k֬YfͶ` Ti֬Yf͚5k֬Yf͚5ۂ5PYf͚5k֬Yf͚5kl @f͚5k֬Yf͚5k֬Y-XU5k֬Yf͚5k֬YfͶ` Ti֬Yf͚5k֬Yf͚5ۂ5PYf͚5k֬Yf͚5kl @f͚5k֬Yf͚5k֬Y-XU5k֬Yf͚5k֬YfͶ` Ti֬Yf͚5k֬Yf͚5ۂ5PYf͚5k֬Yf͚5kl @f͚5k֬Yf͚5k֬Y-XU5k֬Yf͚5k֬YfͶ` Ti֬Yf͚5k֬Yf͚5ۂ5PYf͚5k֬Yf͚5kl @f͚5k֬Yf͚5k֬Y-XU5k֬Yf͚5k֬YfͶ` Ti֬Yf͚5k֬Yf͚5ۂ5PYf͚5k֬Yf͚5kl @f͚5k֬Yf͚5k֬Y-XU5k֬Yf͚5k֬YfͶ` Ti֬Yf͚5k֬Yf͚5ۂ5PYf͚5k֬Yf͚5kl @f͚5k֬Yf͚5k֬Y-XU5k֬Yf͚5k֬YfͶ` Ti֬Yf͚5k֬Yf͚5ۂ5PYf͚5k֬Yf͚5kl @f͚5k֬YKQ}q" "(bbя;$IiAA؅4*%-JH}Z->x@*(үkf9W'dIB!B{hBsɮ]dI+tRy=pUcǎ˞={D#ސ6mG},ǏONC>3ܹ 2\._ٶmL2MW-6lB!BoT!qν#ٳgGy2eΝczrJҤI's ,8Yx;M~)}X||z׸jd=z!B!PB✢EgˊKG?k \Jz*7aÆH4W ղeeҤFѲP2e>YʺukeÆ9J߾%e,B!BH|#WiذtK_pAv%s?'UG];VWoZ_2ouND u]li)U*G~wTǍ]RFuO~WYA$[RJ ϱqFk,`;erI:R^mI>Ӿ}GsޗޚprE>}əqܽ{O}իW3X>|DXҶm+DnѫWw)S~dĉjYMTys~QS.<yewe࡞tϘ1U qR-[6'u2if}D@5~eS )YM{hZ8qԓO#M cXҥKjjyg9wo4Mʕ< !B!A wҦMJ 'ZJVmcڴ385u|'lR|駞ɓ'|'Oٳ: \U>CU4_(U0yE[(nKQeRw^zKҥK+>Tߡ4+UVP4DE̟JTcqy⋯UJeU"D~x'p/dݺ.?lr =o}ӦM~*veep;v.]Iݤ[b|lN@{k}gRD1odʣ~QD(y|2ի (b 0;VZjn^B!:t!bI:UsP bd̘QߣPAzRt)bW+ (\q1(TP>s3&0J>}%O=aR T6zȑ_Jg`caUP@APuCbE\#]ݗFrȡ ޽ȋ/5i.f}4?QhtvWBp?8r]z&:x<_+6 Pٿ~G6lGBw]3}ǎx*8QF~ر4B=y)X\.xB!܈RpdcpCȞ=[sq|„q7 ("~g0aBXݚȑMw+VRXl9Z'Pp:u($,+_|`BgLD{6/5jI<#pv>g2"}+UV*%^3 GM>tCyO?{γ~`-q9O^M:(T2i^4nԣZ`Qw ɺ-Hd0%T'niƌ)ԵkwfvPb@ņܩdyX.\9:8g,nePfAt &/ːڵk &#}{Y KwKP.\JqU,Ry$-[F;P*eQ%B!СR9'v֭R. 7o|drenp*w߭ppR&,+ťǫ Z[knUZR e)>`u}vݲgҝwJ"|*C>h' &O=4_U&sLnSkKXQDP E*սʟܢM ۷q}gqD]`!d)UP'P W[92B'gx.(v,VO ڔ?blٲiCo1[Dzr V_B!fTZųbBr; XXn/%JGY(8궻ŊS $eHm I +!nNK}iy>[yk{_V&c)>C!C:YUxcB!Bƒ*$^x; E"}⏔)Na}홃7˺ ؝e=y~r$ؚD2H ,?:ph(oN w!X"O< X X/&҈cYBڥJ]U o3 /vcr*0J[$@Lgy#G=a8' J4i^;``[uaڎwK ܊ҥ@17zF4i X]Zpxg3&キs([r玎n#3g`'ؚ1j@z+W.gCY'8߾\CGv4\g.2"l;(-xΜ9)vY@9/b P5p@ګ #^APTˍ /1Y ^gR͝;OƍQ2ixSxݡMB!BB* P \Zh%ʕw}bjUzkq-Jpm/\` ֬@'΀ <.0arٶ-:/FڂXH\0,J*)ӧ8*ˠL2JhX 6m^vܭJ5;,* 5Aǖ( ?+4(%Kw\Tr>}zְvǝڵK)nuK`ѫW$k$R^#ə1U~X (,,w^x^c:b*]+];wn KM[jbZJ}{k{j2ŊS`"I%SLL.f`bkkkd(SvXXgU7mKL dwz^ym9 mڴ'O8߿k˩P ,mIiͣy[@_JcʡKΞ=PR {Z;ҳgwOC]+PAeQ{" V,p9QQ=AX*u%B!-U C̙dΜFP]n9TL^ G, bs=ǰ3`k  \z.]PR`'%5kyXږU Va0i~g-ٲx6_Jɛo4y('NhlRRE[WsX0S6 RVMs9%%CYd"ET+@(`.FGRY&r <v41ӽ-*y궅FrL]/w ;ȏʨ[_#6ω'%i۵nJ u47Y.P}TP'a: ҥK}!B!然w+fzb#}!X]ڷ>ktB!B1p8e^V/\y]d{]_r gq|VhB \6W,XPB!B!*UBȊo۶B!BȵJBs FXx≜Ҵi&B!YSB!B!7B!B!rB !B!BHPB!B!TB!B!*B!B!a@ !B!BHPB!B!TB!B!*B!B!a@ !B!BHPB!B!TB!B!*B!B!a@ !B!BH$B‎;ˋ/ **-[ݻȵf׮ݚGʵdxRiyo7o9޷o)VDEΝGc/+]ByŋH ɓb*zF~r?H͚u@_?o2e˗_~0Hw)2xP)ZW[Yp+WQ"EϡGT!3f̒pA~v_\[z+[ٿ`}Pҥ 4Dnf"&DJ^sʟQ|c'#S<7&! T!qƋ/>o)-3ߞ+mڴ%Kw!Jf͚ FYkyoqI-w-Dԩ3}N2w0U]k rr9p,]Lo$&Y7d͚U/wy܈8!yz$O<ҫWwɒaP2Hr廲nz3yMx \o,[\fzӤsD_~UxctVrʥ}NU$ID8CX57ǽ`2t`<ǂ */_JldіC(@@Xiܹ֬SXl?pL(׉'ŋ=#QP^y+P}L{oTVK]pM͛o?nsJ+W.~^֬@3m_a5Fī_<ҟ?}& w|V\ܜe{^~%K5-?҆:uY*uoS4i.Vb y{,G}6޶m{5bv'05@۶sZޖ-[g̙3%JޮK I׮[< ,UCG0a@h.zR/_!?Jվ}GMꄿ6i2xfZO7owg2e4GP(#yƺ`͙h/6Vgý\`P7uLNp#GkBC;z~ugϞߝ~gϞUW~a?gjBXk̰/A@(/N8ς4!m~ج82_AM?ՅP"qq#u3`򧽾Yܴ3OUzmرS6mI'}K˅Tx_j4y,!06laqϜ9[qp)uIyga_Sk?\Yrʴiwȝ:uwݺ *@/_cӥL2|is׮=`_@ӪUKnju KuԩSA}~nU TɆ o2jp9~ 5L%I,#4S HX*CWw7沏>(ab%\̙+ig{t^VX)M:#Λ7G2f|0h};w7m0[.Yd z%sL 3fL~Jr~Vy^3cTٷ@ :>gA]СuٞpU_!t"[7`oVҧߴyFQG ;d0׬Yk_~LxAYni/Ì;Ljʖ-#_9->5eqLH_veٲw3 5xafO__tIɐ!~0mnF4AE|^\wذ!ұc6m:A %7ꆕHH_Æxl1J_r~Ln3uϦӦ͔nz%jUY|Gc*uMj>}soϿ~c)~ y&Mj }۾+P5oTQpAm_|q_݌\, 'Nw9'~fxHOuR;tl&ݵOt3LRW ;wi]4iZ4i|L!CFӗ.c }=/ף' ͷmѴ_fZW`qm6יd>X-YǏ7`eBl@F8pOw6mZceWeէA)Ӳekt]vR%_{pC 8cJ'+i{ZՍRup h-\PR LdPP`y$KvΉmԹ ilg+2e܈ĸ+npkJ8α:tМ3Å^?-`@Po˖ |倱x^Jn g^TE3_`AfݪHu r#Y7F[@K{$P?}Յ؎ ԩP ȟYW=y׺uK]+5cݦ G7{p nMBnvT!qWmF?c@EǎUctǎ {쑌MnbՠYf ۷o7jk0^~\:L+7 ]ι瞔F9]wQBa?:V\9+,O +,z k U)%X .9sz+` Zӧ@"}zP @3Z+ *'l/_^I >uxfKuW^;)\8ʬ:.5Uu3Ϩ"V{I6"puOo6ij{@ݰ@c2LJ,!キV*XM˯e)D+wޙs+n{ FՇ!6?V$fJg`>AjV0`  O+yUYf{ o4)L{%Ll]61 Kz=V- *7_+ /2V%:ࡠp$X} Dٲ|+p/*3 fdӦM{yX51…>]Hn޼믿1߫I՜.c}pۂҨqWCꫯt֟VlzފE_T6 ?CcSaB 7nωM]vWe@TZjocҹ~0ߴsS7$v&ڍU觞zR>h:@,HN1!e,?.^t@m~p" ,ϸqur{͙Gq$xG,DlA-[~:@826}Ȕ!m&0iw3Άsݘ<3A KXqSP^'_ N|dz?↽2#7\|uj n6p8 sb{`q6%M np`dZ7dzgE?СRpO xa@|N ,gʔQ'Q ԇ Bwht<8 \,J*ѣG5 ^iX`k܌ȟX*##ȑoTp*UH_Iݺ Vz_Zn+"{fD@ӯ_3+u4 w*jFwu0~hcTTAU~Ft$E4lJʕ4R}l1֩S?)δ -IeР5po$\"U&FD.cƌ ["N2UWfϞpiF ( T=QWp>Zʗ/V_L˔)j [;0'O&5bXXý^}nى2sAAp?5ߌx0ƳvM|0z ΉM]vWh(a-Zbʤ2bneb^#H lѢyBȵ$I۰M))|~/\y]d{][~s0P-!` ?B뾈USݝN[ 'Mz_p) _Y;?rC !Fm駟mƱ{q; Ppɐ! )& }Klٮ`"IMdiһw_uL&*T6/`.]:|@\9=ߎ'RoA% Y!B!Bn:C!B!rB !B!BHPB!B! 8I%()Vǎ,ػ> ADABEeٲN8!۬"=5kرez";:vuێvI~7uާ@Ұ駛<`obҥKRnCiٲM߰E("n裏?؆d2ҽ{OUǎ&|J2slM?> =ԩSn,zyZ>G_%KQƈ[Syc{gJ%_BGM3.\L^yuBZӦ͈s~y)S^+ҥ 4DH؍ _+7 v־Zڷog0vU>Kم+VŋH8\O}y|o7r !$thB `>L4'ڵ3gȜ9sI2oI<>soDJ6WwgI(DKf;wԩS`9VΞ=+u6JjFQP\χ _$C˅ d2fx$Rv+;r:N,Y$wq5݁^}#=1b$K\Zh*q_JӦ?[N:(xXG1 gn*k׮9rȚ5_}ϟ_2dH/&!9e˶rwK~}T>:uoɌoj]%ބӗCB" Mի2ʠF{@ȭN5k"ʕB*UH;Kj*fs M[?J޼y$kGETN93ラK*;]Kj֬* efjsIV ᄏL\z)TV[n)ǎj ,U5't~cٳguk fѰRUf ɸ?^`SOs< @A'K\VI(]*\P1GVvԽ\j% ϛ7_zEbŪR`^=|QPWUk{EO>z*Uȝ6oZΞngW/< rw[dJZpXu} (QK+\$j?E/F,U{X'ZX-ڵV&&B+$pӏK߀<@Yܠ+~ 9sֺ L UVeq}8o"k epVVK۠.!xF\ς[hmƍcpuyZPa>s}\?^xyYB$Kv-I\G&ϭ#Pߊm y_Y}9 ^hwx. ,`I-+O;`TaLM[Be͓[y\;YQ'pH ߨ'1)܎-v@m=X^X?Ik 2\"PޠiB_aFtz襋Ivc>g֬7%y02ZgNC >۟J'ԩSS'qZA9Or~L"7W46 V qw*=:55?N0pnK0 ,U=RzHF˖-v:&74ϒZon?(B+ժUUǩtO?W&S QQa}@ լY UetЩSWV^ϳt"Fm/[$SNa6o@9SBy#(MeKkI/ڵ}iFn?ܥ|qwV5u$σu£i 4 j\%LmێUQFP00a{f4Svܭ SCAD+i¸dɒ1dPR˜9SD ǩk$e䑽?~Bkذ!Fn8ΝؤITܤIBt cn*SLSUԹ3Jr|ķRꦇ4UC;piӦ#̘1EǶܹ5B{YiQp!k7?}߾M>\` <7;\֑- !˗/Ay 7m=X^Č[ji7,SL!sΗ@#oC,_e nߛ:\:tc>YV-uanv `!rʥu$ yւ?$N(Tv•"K%>`3i81v;Mf5Zp{@TW n8}84Z̀%!fPEȾƘ\Z]> 8-NU(/~^ԩw@wHnfw9C}qdp&+U3gͳPԏM_( %cG+PZb~Ϟ=Z&v0 XO<5͙Wg^L<6lHn~NgsI0bhOPghn>.`bnP|Ah>6sL^ȑM-XaU 4h,ӦMQm}&aU[m,Y;5P<m=@sKڴޱ0f^myuL![۷_߱a3g{M7wlټ?xq9vu( JO G`j K0b @9m;Aۃ 櫟z\g^O>}:!zJ@xAPЗ_~I}kC8H240!jǎBLp Un]t5VBvG 6,A— j/`o9vǖ,ST|Bsrp9PM9`Ю96\~bҌ2f(Pi0!eW;H;#!`Kr*kUɖ->,%Lmvc%Vd'xȑ/_K,HVߊMoDZ\U[GEԺ)=w6aN*pnBR|9ʘA?[b>ځmFMtgXD@;sZfԌ3z`燓nynxPN1;`9Ҿ}*n1XCNq;l)PQo .T5jT j.{.-N\mmW.tIts.nj'4iާBW̙T vXU7 B%`¶k׮ agܸ L ` XĪ"k .$˟ I0!fի {P(X`R'bX~czk?ey}DvӦUN=azY~{+(rtT&2ۺuV#dp{d Xa% :pAL%{Z0 dH+;|?K/H={vٲ'(X,ulYu/Fr Z7Rej`Eg݃"VAt<*:NJ,+菂]dܸ:񅵂sd䓝~!u#0w*pu T;3P-7X`Oо#'uc(QB2=4& ߏxM9uOyd;o! #qBXɞ/^wc=}˃>9nz0؄qY'qGp'ᄡj5bqZk#o>'k߼yąRDC{ĉ0"11AP9rhҥu5 R>DL1ф9|XC!X 9s8Q_!Aj &rrG}]`d[i]%k %ah7e)݈7&VYllܹp@c CZrԬYSNW0E=C; jug6#>kƌY*@ڃJ?|!&ݺ4 ~TT MSٳtR X5x@h:ui3%aժ500LjڡCgu_3} }m))SF|_1 p뮻]1<%uۙ3gE\!iQQ5 v$+W.9ŶP"6m$Snf%Z8ar+tOGJXmΝ[cO ӦmB-݂ۓj&&ND=DALb3e~z"X$ l+\?\we$Iy6b!ר/@|9Q4uwqھq9U c>*uԟ*O>d J'tU'˖ɓ G 2ʾ# 4/ O4^'P /;^C hzݺ b_r_t `9s&-Έr9 .m$M@iB=YLJƌ[`XBteL_ >[U%(|0أ~@0S^܀t>Q @p/, #p2ń ue 9|V]VcOC"AK!`XbV9B["BBN:Ynժ.BmV"ѤIStBK H'k(yPFC l|(Fkwԝ&_Gԥ&Riu ؝%I2eY"F~@m۶u@-2v@d3:Cb$bRqf"}QQuiAF贶e \!3q8 x?6`10ᇒc fl?ء } &4Sw9o~[ @+?"QQfzK0 @&*`9L2ѿ7{b$].+؝ (x/b.] pRPq[߃9V(Q_AYmȑmvܸ1~385V}KZ5Wz :Myځ5,,uw'7 f  7󋑵^<._ʟc᦭mJ/T>rNb y~ղܹ^GX2!twAcu#8|GXE<vEBcHHlIxwsBۻJt N̠Ra !$ܹzC`Q(Rw 9͞La!oժ1]knO"5k;U[[".&ׯzC1vmh E.sn lNH|b+) /\y]d{][>0 }Qm*\oe X\o pY B7(FP!17s BB Cnh&؆F>/;li>^ nO" 64uy'@qaTAܧ^zI]" !>t!B!BMG|RB!B!$ T!B!B *U!B!B€GT{߬`k˚5J݅!֐ŋ]vˋ/散GʵKn2hء-؊q%*۷.Q޳i'zw)ƧwҺu[8* *ɓ'{uĎnD8w/~mRLy˯f$mFodb,p+ȷj 0R$I(c君L`|'~9J+B &M˅ Sҷooɒ%tC,Y*'>\8ps,w$Oz"k֬?~;%.$&c݈+RNu.C)nzm4.q~H^fo#%ܚ$LrԟRXyDŽ+b%K]=+==N-"w}rƓO\u#KBq3H?K$w˷1hR 05)Y,XDڵ w5}L='*>X ̯\qRR5uaxz;`NtYjԮ]hoy~)5.\.XPrYya:QXIu$pWѕVYޔK.o6m;tw?y/̙32lH[o?roO6Ζ-[=nc^ #F!˦MU1~Xԯ_US[Ա!Ckjhq5v?co}}\+z7+Wy wuWMC7n)˕m;ݱcw~yjwO @3FޣwޣCH|@6gZxuʆ =s7K?ԩӵ5Vz^iqӶ|BZze*ҲeMki6o|իӰ&}wk!O?u>I {:]%ҁ{ //] g@Yt|}9^}\AlϞ~˅}qxҨQ', bF`،+d`-'OP3i9rq|˷nSCoCrW7NSݴ3\2a<T^rqeDH|C 8/^4=f:!2mdI8̞=L F3.p}ӧ֭?u̔nzA,_X)!au@@QRy#̖f͚̙$:v*ÇUQ*,~7{BԩܹKmҤ 4iR3@6 m<{B2eжTc̘{veٲw3\1V^!S8hU Q`5\?bܿdbfpef*@ܹ4̙E(O>u S@{, WV[Ah^)S(M3}zٶmG#t50W#/"k}ug߭f IΝt"Vٶm&h5kaMLرL>] >?{_{X*0e+$sLcP€1c0N~ <tж֭[g03iOLoŊ5F@ o^/ 4Xҥ$IS_&P'/^T)͵?Ser\v$&L6Bii .R%#d .\g>L2MoM)Q"zM>JJ%K}x0_ߐ!\m C~7y :t5ws֍`UU{M2=Xc?իh{EgnD7)3`VBy-߲eKen  r}5(q1|GPc[`j~T&omҥ(jժiCSģGY|939Vйm[7O:zg]$u#c2ٸ{r'K+j*j&(^y5gT\AݻwN#n˲TR> ZɳBA䑛߿ߊj-1)'@%b_ʚ5x*JD?UϴZm8(qşsO/5P ;ȗئС&2{nh'@-(!ɓ'T*7I_yJ;+[tƦT!q6|+pMӦMt0r]wz0pmUسV'n{~K{82;& d[X}V,Z17K +&b6S.xi[x'H7ꭥ0qs 7@AiL8}B]w]{_ə{z*_-t=4yɱ0|zJ_r}l5 0 ά1͚δėRMDl+>G_o6}ofU^n\ܹQ1y(sˋ/asI8"߀`,}tؖ!q *$ Zn6AӧApp֬ٞ!Zq@ '&{X(T``f"j\d`{ZB`}uz s|,ڵk:j]dϞMa\UUL3gZhS ?; ?֭[o&O"+N4YMd  V]$L@ܦ= cb zZK:vvmۺpbZ  nF0(ij J%Kdiժ$89{&;֘kHp)'lȠAirKMXMɒ%Uٸ&PF-[X> pK{衇d1>S0PdK8v2"$>`LqE>r䈌7ZͲ !.RDgW80*W}aqX{/GUtLv0q^X-ۣ1n޼ERl[郉=݁LO`j%د_֋/N 13,8 GyDcb؃[¤^ {zGAܾI;=t谺 X!Z {)S&XUtC$y\p?!z帤1|FUvbjsFF-80d'RgϹN{8 fȑïNpCLT̾Guss[]:q۶h_ݷo'sBM~p22,غ;v]DYiolK8vWPpqG2{0d,Pf 'j?B֭@15nҌ:`]7ā;,}$ꔝ~A73#b[FTKa2 ʮ52eNYDǮ&0-_ayk 0 ҩS7]ErlCۣGo#󾈻o-;@_C޺6u4FڪK˖-W+:t,K,s} ׬YݬԀd?L±[V]܂X?&9w7i@P$H{ު@ЄnzNŊub7^ƌ畖J*eH+-!8Ew:#Tc7g;>tY'7hzmݮEU `[ :`BpOP0AO-8X` 7DPx7`iw!o;8]6, eLٞ2+V>g>=zf3ӇXu-nelq۶WÐQϞ}9<ԓ! nF0:;ܾzjVc  תU繑(K7 ٳg48?b_srwC`s\A;¸ Wryh7x&Ď8k] zEN,1Pj?9 tlE#Ϻu( Ia# XS|cH/ Ca2;f\ft}$YlˈJq`oAZh*ךݻJƌ >X9v(aPRl!FvFѷo1UD:ہ,c۰+fQQwj捺F1?_6}sDCƍ]!ja_n ҫ 1+ TK0@իHWɫTd4tu!$rlm>k}ǎY]O}:'[ AҤ6Bn 1ᤙ8a݈ pq:u.< .ϡC˸q* 0DTrh-SLX̔)ӋDŽlmK vQ]t62y4=+WN 7uVu#2-ZXbhK/i\4~M] !!B!rAB!B!*U!B!B€[*b{*V"/[$VRCf̘%W'ŋ lwz;܌7߈,\Hʕ(E-goV)% lqA|ŗۗ_~%cڧlc [*UV:u"?۶mW<RjK\zɍ͍:V *Uŀr)$I" ! w猐{$Բeur}#|kA_~7Ǎ#w}DL{Mn% *`&ˈoŋ=DZȑwI( 3gLS{J)Ef~N>Ejժ.f)3gvu//7CO!"a„^OreVVH+@Ŋt'(;:vl/kח%KJjU؂ 2~h!7ٲeY-ҋFQNҤI9=PF#Gv9q7[sl'R p=-]=]'|*5MQn&cN|?uꔮD.\LM!4bU67ߘzk{>4[q!˗/o5U5|ET>s{|ҨQ?V`&k=u+$M4וY X߸c5ۅ8҃4oQi?{s-+ (,UA=f'O!H#p˖mӁ_3gθN0S(PMus ҇(QO6<5?_Iuyg[Vt97o5N8!ݻk,YF`{f^9_}ҏ?gz ԣ ^?i)W~Yeycz&Lrl:.Mcfvghlrش3klAٲew\ccc=yXH}|Pjժ!SN?C)feƨ6mZ=M48>w{kS3sűO?~u"oނnUA]kzw1W$-ۣn Xvc{82-'On ecNiڴ|wz\?ݴ1c/w 0@"K,&o54,S6 =iW3{8`ʢ<ÚWC V'I8@YЬY ;eqkd=wnו3aSOx׃6A=|Hkzm~A((X|_*10o۶IQ#8 3up=-~3c%u,Y(=ײ p)SiGϘ1(0 NMuXFOO=;v̴L1 m +X56#(%B)[ _۴ʙaÆ2Y'Nnn?K7}6e3\ ҁe]zI&HҤIp'=y'let(}EMIw(3|(<ʕK[@"E uC(YWSLYF nu~)ɝY͛{s9zԩ3L=ke& LʮMY;ujmg{bG|Ѱa}뮻M~w}Rf tC6>3{YfMdEF)[ˌ}=FmwȐAF єK9N6>,~pU&b`͚ҡC;_~Qa\hٲ:Ϯ];RN{鶽؉ގ3G䁯/ldawo%}:(*y,vk 2L&r3J*%e˖|X"*,Y H>qbO?>}z=W,=vlRQo!<@s%K!a`foVu7׬ tkwtP4ϘYХKG]Q->;4gJ}|Ν'GͪBi=B4~ZTRcmrڸK.<߿ z`Aܶi[+Cmȋ5kẐV^95n99N2In"洧ohԨĒq J>}zy҄iܸnۋ-B?O~D]^XYitwŋ:S3޳g.cǎ:X a B[X>vKӣP}X;{΁5 &Vh֛5k~P` vmǘ  H%nKBmbʕ+ X-' ZVX]]( ~u9A۷笷p_y?=4ow^S'S{*1Q'2guN3q~;c|y% u3xtBV2 y7lHWSدV j#@ Dj^8@@D^*UR羚qKtc}g=g?vJ0E$ g[ZX4R Yc޽{L@*ee>8xg/]9r0cGR/KpM7iS3áp(T*UgyƌW጗6m@A[$п hky}ϓ%ho#Lں'Uizuᶽ؉"Rg~ PYJ s]~B\߲!*U ?K7)y/ 0#a?q#(eg}JC^+ VQ *㷻61a5gQ|AV'` ;qI{\H=gz'LBVYb k:"_<fÁgƄ+SZqݬYJ?pX8 /a 0裍*$-̂]_:J3nh5Sn L0A;`[iy%SO=)2d5U@ >`V?a4F30w١Cߺ\.Hn;H%2XhKK'u@TZj.sFZnk\(.\9v`e z⌘1XGq 7m?](Xح2g~X~qgϞ=CZnO7m,}( Y6#ZC 70#+"cF)*ULb%J L xg>P  { H5:bWH۶t`o>T0pd=6l[ϻp;*" [\βegD:˒% Áyf<=z΢}\2ҏ:ZzU3quy]8>Se˖Va ;󅆩2v@{0L L,miAխP̟;uy@G:z,g^k|/}.?a]fByHMٽ{Nr@dB{AE1cyJ*EA[U; YAPMb.!h;~G9̙3/uHN`>uc@TĔ}QP vӿhgߑysЯ¢6> % vAwKaUb9#{ r7%ᴗk5޻?ݴ`/r/$zE$|HmʕfXݰCs=v(RL"U\!:a;@Ng;9*UBd_>*A:5mn@cǎWWDϞ=GyAĊF 1U""VxЊ,nD z;FM رobi~r], SN6xSۘe0~|OtxY 7}!̈́6@uT$L_ 1b P,bGtAW-0Y;Р/3vӏZnu fϤI5nE l޼n E,u7ڷaWRy&~ eE@a!p˵nX0טk͛RTm۶,rIxwsBۻJt KFP5</Ͷe6*cQ@TRiƭq V!]Xu붒!,TXUv"HHUBbYe??+W^l˶w7Y 5aFi81a)SG2}VV~[+uqjԨ&BpeʔEޑ,i&]cOBȍ V3-SLU_ieFVw%bݾ­]tWWX x!b'cƌf,sΗɓ\rj`ܥBb !B!r?T!B!B *U!B!B€JB!B!0pe![/^JD޽Lڵ[^|1=zT!B!ŕ*B!B!a@ !B!BHu!$$~w5)Y,XDڵ ȑT/_!iҤ^~T\]珒W_m&?UVKoy~Tkt%mUd֬7zZv7o%cNx6mLש^|1j՚;p1!B!*UHĹxiA=&Æ i&KĉksL.~I}]ygdΜYt4zdҤ)ҭ[gOKVmȑ#;ÆJ˜9Y&2sl˗Smv /&)SZɓ'co˖ ڵ6ʢzl)t2С̘1UҤICq,XhFe޼91_*T(St4Xƌ/2u f4پ}Z4mTP^AqKNK…#d;vȾ}_T))[;/Ŋ ,Y H>qrw[5{Փϭ[_kҰS|2̟̩S>Ǐ7ʠB!B!$0Rpw 6|$[,ݻq(:@jUsRFy _zH$d;6?ٳsرd_Tс2f̨A:u*BźebkiРw_UX>U>L J鼾CQxQcO=K.\GO?%mڴ{;wN+ʕ>B!Bɉ#\>>SB?Cm(˗zP }:Je%#-ۨ ;xٱ\!rɛ7 ^wÁ >^NX\O8sB!B /=FXHTloָ%ƍ5E1@ܹ+b Pm֬YkZ*Ҿ}URgnCyA{0kQڵ4@2e˖҅ ,ldg-z=耤IY@cOp-`B!rQEl̑>[&ʇ|ɾ}<;X 6B#ڵ1ʁhbrº/%K&F)A˔ӧOKrѱK2e(6}nW'Oif}D5 \ww-mڴsyg|RPA}80-Z45Jv֬ir]wi'gK*>$Y^~]СIc&U"۷_F@P݊x*pA (`> dkuKZ5G^FEϧas#G 2!B!ܠ\vy5qe[- |M,Yfd޼p3hkf( IÆhL1cF=|"f2dpR#F1V{1#ha;G|P@w 8!B!BXؿ!. |vl Y\'B!BI(n@ϗ]sĈkeD(V+n?:F!B!k}7;HlL% !B!rcp9ZěBė"% 'B!BM07($% 'B!Bȭ@qSoB!Bpr(EVXw|*e!B!%ʍP9JbB!B! I+S,Rł B!B!5SX\/J;TB!B!\bzT8B!B5(Nn !B!BuGb!B!B!!C !B!BHPB!B!TB!B!<(IENDB`bazaar-orig-v0.7.14/screenshots/flathub.png0000664000175000017500000046256315166123241017653 0ustar hasanhasanPNG  IHDRT"@!-tEXtCreation TimeTue 10 Feb 2026 08:23:00 PM CET䍁tEXtSoftwaregnome-screenshot>dIDATx|[?G{H mAݷ{ݶ;-@;@{ىmKG:ʱ"y}kstX:?=F$B($ TB@(D TBQn; P(P XKxZÕ2BY?C""""""/˂ )mGDDDDDDD6:;hptmDDDDDDDԻwm3 Gׇr_"""""""C> (Z4w눈whIpƮkWP8Bx\s!""""""'~(-8ߒC'- TXBDDDDDD;5WaPBvӑDsHSׅ4u=u?-TxJ!JGTu4w=u6oϦ.;h,- X&""""""YZ:qkB,.Z4; `˗\ODDDDDDD]/>O2NiY0b׾>Y@*%|c9\ 6%""""""Zڄ60Hk2^ZV"\I[+TZZ=!CDDDDDDԛΜj}?ݶS+exY#|BPq\\oWܴœ'O09**bS* Qx8š e:kٲo7X+yzyB`%)mH)b{pkI{bUDG.[,zO6J!""""""" ,W._yM6* \*Ul[6XOf* i=LzӤI> Z Ç2mڴ :d*-m\+bPSJ `xOl^^gS"""""""V(..z<=='T0`5 jVT4Rl+H~"L+..fll-BDDDDDDD%''S*V▆ lgjsJ( _5.o+*m>)DDDDDDD1 k߄7 완=iz&ܖY~xŊ:e޽8̇sHuu֊꾜NDFFJttDEE Y͘1YiXbel1'[CT# Z=P\ti)S>#DDԡꤸXJJJ4Pa5k ^C"""" 2drufa{6!rmJ^ x3ZGHE)->+G1!"SϗUej9-n|"% FEKtDeMnnÃ9[nN5{6iJ*57DSm=G&"8j(**=RRR$"s;֟;+ (7'N޿ ^:S6֚T-Nli*4  ٴ S:VyyP]_}DR4L\q?"""΄lWsp5iBDDC}|zxmT|99)߹-M掌>/WoXBDDDv&].A?η/$So)7 R“4PO$DDaDSwzm3|_(EFqDDDJaaTTT\3%:܆xL[2$3Mevf %C~{8-:1Tð:N-ybgFqDDD~4$ "c[˗AgiI@[{[5Mk=T!"é{b6@9%qDDDԻ⤬LZ 2Z×AL *Y5u@chi:ٱcG'OJ߾}mݢc]ᥗ^6Iny{-BD=۷_%55EM*w}L:EBֆ!vX>wHjob<&-AGK9!"0slUTTʅ ^~JK'!aFVb\$.1)}'3.Ѣ:|ԣ /uO"̿$//_G?m8v"" /xhKeJ , E-%Z[WJv*Sy= rIFFʏ3sO|LƎt8`ۃކo ^z9ysϽ vՒn\o?q L(^x,} ].?^ٳ;~~um""j-=6T۷o)(! 4ԅz( (gΜ&P8qRoJsF)QQNgۦɻu|D :)P\\rmol|UHr[57'N#h֊ u}1x馵_dȐB*VVG!f{äXy AU NmU__Y멬Tɓ'{#%J]]VZe}5֡JDDQ&\/&M$_%99YCEwrAy\6B6j7P 6߽z4 CyF3o7OO;gO]+f)|X~5x;~PO~FN> y[ַW{ɧ,xwܭoJoZʕW._)I>(Aq;R7R}EV\-w}EJ>…K7[n],Y6o}_ײl*ߞ^G Boa>MYz꒖S+@-@}=ziYb ao/y5E8=O/^.*u*M(**_eކ߃Oj qɓ .ȃ~\.])~w/"" v7~>lb>_k/~UÔdkn!a*hY~l>993:E/2);uohHG7SK&f͒;wc=nj;o_4aĉ Xwod?cQKIZZdd뮛)CsqFtNq9 hk%|Ztk~ʩS$ܹsy u ̷nݮC͛go=:,G4>}<̳5>sTT[%fLiJ~ޡ}E2s ٳgVZxy=F@A&*ZΝ% xIIIox`g?~B{y}=y7 PMAkpv&Lzm]'8rֿ &C  _;wNC Y[mZvejJKDD=~ +N>|F ԃӧIdddzjYj8s6e eٲzph}3@ 4CzX>Oʕ̙Ұ(33+hԦL8^yAȃ)\ VOWg?)(SL6~`=PINN?ୈˊ5"۲ek@`?זÇ橧aɒ%5?~r"Ag ]wݩY;C=P_6;|{Cg8ڹ*Dԣt!?C/]#Ti˲""jJϝ;CkDDx>03d` cccCYV5p{Y& m4g_?-9U],: fAr|1cFzZ;e酃Ʋj* TΜ9>W00$ MqP\  LujUol@ ny&A0 h˯R.7!Ν4”Xv|_Ӧ?'ON_wx1KP ʾ W\?1uWw/Vk.-7n*&: ~/"#{f4@IZp|k_ipݯ[= ?*@~KӟN[aZO(=-5Ng(o>Z^V=0?QF`Zw3tz?΂A?[ٶmV4f5:M. 8@!)U T/mU4oCn ho۶}мF, |?g}Nb8!L &kfDSu|T% `}_tg@T :T6mu f9 >&87jxQӟHQׯ5BmZfU>|Tb8ǃwӦMU;6yҢK88Jlmm5jD?u괆)A~ߚAR(E?cYð!-0cB4ãrEiq=z$''x6.Tw띭97`|\ MO8%0,6nMMZs)Ppy*_7ڴ "" 3Y :` T AH4G/?vVL e˖-z>?7po]8Ft)[FKp ?#{1vW_f #'k-,hlokn- oh az@_^> 1h`@@k&馛1nԐnݺ7K8c< 4dn *]0wvkcXmKW{B%*|ozۄp2z 0&7o1>ȑ# Ǐ""8[x/G~[j*S窹ew7-5DDtr&3ouzI SbEMM@/~*?v>&/^F8CS@"{љ?$=G M6C/ћ PmSs>a֓ Iјfo3? ?9 *0 CNz#|Ӈ *B4o6c!BfEHm3gcԡ? iz k PO>@0/=8p[[Z8ZpCӌ:| _?!BJ1 u4moVDFF7]T sG0 ?`aLu9?_s0RooK._BO|~7N{BDDGwJKKuHg{Bc"E愒MܾvS 22QP--[޾~ɒ7:: oZB=*3PcUhX?[Ṕ2 <a *b0w0_gOHhst/;P2#VQhy|c}2O{Auwә* YQRYYe~'pA Ш=$$$3*TP@z =*SZ[ M&"z۔t_[""":*DDfhﱪ=t)ZCuY*-R0cBD JS+#jV[[[+n?qq/ "^ **J߄E^SDDDD=>'TMDKpއ)Q@$%^S"""""F=^;CDDDԽ/"^U RSSoe5 جFl Rz*DDypNDDDD1 Q Q Q Q Q Q)DDDDDDDD=ᐈ P!""""""!J^^K߾}%=Kgb ((JAE*P!""""""" """""""1P!""""""" """""""1P!""""""" """""""1P Vc"׆( UBb?Vf恊:xNDDDDDDn_g/sg]]n=3DDDDDDD)""kvJ`RSS#sΜlRQs:ő(2`G "-M4X[VZ\WH⛛Dv.DDDDDDDԀ#"kY! H Tڑ PXBDDD6N?Q!<>gك*`aJ40N!"""jshxb+XaB Q5c~'""" - >e+bV jO T 0L XOQa-(qخwخ VXB퉁 Q+Vx)[4U€ȫC_P?m93 XqPڊ QJ xBdilDDDDtmac(Nih`x*O`BD+( Rܾ}vk'DDDDGV`*Nyg`0v@)TBToN!ߛ|ַ* gp=\p=\SxBŜ4(2 V\`N Cj *DD-В0c Qjqy\#ÇKD⊏3ND?,85EauzYxߴؗ)A#x?zZXA\(_#2:K+rT;'*04G a >1T`BDԌz! Rܾ ?͛;5U-Yŕ Ai"""vnqI;;]T$ns]*N! U S])Q k%fPHLԪ""""xZBbFW^SV?EJaB TBdU[ :|0%mk~:/ H3 W^< |HNq!/3Yl'uޙ9kU*j *DDMh>w94aBԽa<}eeTWW yHUUItt4(Wg2|6K4J{Nۈq+;VPKpP?QT.cO=Hޞ)Dm!LBNyy" 3[g9QXBDJVVo9G|؀{CX> ~A `QWk8DӭPaQ qg>᳚)]Um-.ID د. m|FD/pu%FSwo:?tGjI=$g:_ˆZxer8ř <>&= :y{0TXa1"q jOH[DD) fUgLLV)>]9w}LF-@ ~Qߪ>%e;v?oD#Sv…Lmjdd9sf -Oַ7-x >cw|:|o-h @ w(6&Pf}9 [ƃF{caJ k""TionXqL TZބKJekB1 g^xQ; SNC+G_~E2?>}/6l4 Urֿode]\u+l/zW}ﻯ瘓#۷CkϪU+5ڹsv-BD]ӟ\?ˀÚ~w&O$'e!-^.a>V> "6jK%D* )Bw٭(T\. jeܹ ]{qUUed"]αc7}7))ɒ(gΜA4\s}\tI%99Y3|{=_g32o͕YurY)++3y.k:3ξ/˨2U.IJJ26K5./âBZZZ^GDнO~:ܱ1I_ TѿL@/A/NA}|f# Q'›<2aŋ@?$fF8 # @ ѣG7{(ir_Q o`cO Ba5*ۇ'Ҁ!u8@⭷EAF?~B?,`X QDPP!Cdٲ% y,n4hٶm ^tyskEVnzU1dЀ o/]6X>*PقA̒%K4a Qڜ9OJ|cm@f1_uv`k @Q7V/cω'5LAE, 2A3<80G @`߾r9N*G5Nk5z} XE (2l'?O=_dY喛mE wSfΜ}N.O>w߽e0i \Ν#7*6lxM+Py)UCr Ra%z ~_ÿq kqlk>16i'2a2bpYey'k_5#, T:,LU(]鉨Uyϻd޼:Cu}Tfl8?>>/4t7ܰFjjj}=SR#'Ll@, !So :v1BAгĚ}f.]Sn;r͛&xǵxoaCM0Rf̚ / O܎ʔ|A ڵG„J & M7h (Ab M|s luk3Uw{H5BԞ8B>>̜?[||D7!PCt-+8P@cY`ljZwe#2ۅ@dyZ=І8AD[=dШU9`Pg+V,ӟX>paX%FPR[[U0Z34?e̘1jQhiګTKGi !TfPLp".h@1u !Aaac1/ p A_;N pa_ @CmTOcgg.pS?+7CNBji72{52)p b""" +FxVVV6;.?xAFg!"Pw@Š'JȃGV< QQA`PcO2Y}S """ KV 9Qk0P!""""""" """""""1P!""""""" 8BDDDDDD1PnJ0`!"""""bB]5AJOmB V(1P.\$Ф4 [QcBt Wꅡ uO3&&F:S:Q` 'M""""^rE  4ށN˪H c.VQwv{3S/.!j TS4~VՉA5D#t7 9EGD\s;^C*DDDDDPkIRvKIiHADKd[\PRTG6!^O$'&H 8aBDDDDDኁ u`aJAUTKb^8tNZDI <%R"}%-&P()-uf/ڬI-dҍ!\kTc^BAs-Qo@:UbpWJ"I(,kU_$uN>7 È(0PSm[ Գ^+;DDDDDDS%,xT1!Jt8qE˄zr} Q,?%j<Ꙣkj5$""""" W TC\kp+zu{Jjihڕ^PkezNe"_>)#wIְvCDDDDD*ԣ0Li_U*DDDDDD*Z[0cR)DDDDDXB]"q)5* S(1PNіo)؄3x mG%DDDDsBȸx:+6)J87np!""l {y3!?DDDFrr(r TjTTgb%;[>U,ǏO;t8ɸqcu1cNm~Mk雉}FFFުYZYDDD":/ӐU+5lϿ-Wzk6EUKYY"NzH^^*,w ٽ{6E>}_jB*E0fB_%+Wbپ}… [o͟?OC86ԩStjd"#F ˗jo @ÇQO2c Ĕf'N0aMQ tPyZz/)GV:FO}BgAIbb @Kzz_yun 8p_JUIMM/|rRY%RUUMi X$''KddL>]{pQ@z :T(pτ'W`X*Kl ap 2fp_4?%*5k$!""" .WU!!Jc%K{|eeVL6U-Z(&M(!""" Q'? `L TDtNG!>^""j? ‰@ +`ADD-a*C@(0P!"bPnxM' W0Q{ [*}}C0@B>io}YFqWʷ=r@:BuMŽ~ʚ[]+ S%66FJK) Uz7*롲#Xa7rp7,:ңFZ;l?QOguuUUUsɫj>J%oV˹wY/[G|3QghJin޶[Wqz,OK1wپ}&L()OqDD}هp8@z= 1bxC(U륽Iku'ɬ*᷄coyKUu;wN1 +@Ae/`A7OG\@%BNQa-`okeҥK`ʀzX;N!XL޲[~e-o(uku'ꉬoީ.Bra=?q>}3F}^OwP=N!Dem4}}˨~~ѣGP'qw*D 6T:7D=U "cIII:D'1!{$NkGBy˶nº +V5  S K~O  *VX{Fi_ P"|v:m=T01N_O*z?T9Q!?wӦ#`O[!8zG}T?ˉ'tfN9Y_Ezzi;vJ~~^Fsi9{>}F٫3z:j"wQi/؞G L-G4ڿ6?+y@/}Y^}?5Z{7ܬ xI;&""XB7ׯYpr9s ""[O;l?Qo23.wSj/ MlWTD~ZˁCxtv٧۴5e풜,}Ճ'NJTTDŽ U hrOBpg; Çu^R`c/qR^^Ae eA(Q\\"'N_rj2֙Urݸ_ttPHÑϿۃ%&&ׁA8ti}ܖ-[%##Cg^Bc;/ʄ 6'%__k\\)׿p#u7|ΰm6IW a̦M>x^55չ-((4qnuL}c;b_q""@z=|X7' %F>2|nDzXAwz[OsVXc]6!:dw@ Nmlknz Tym?ȻL mc*@LIIу\ .`?!7evՀ/n9s?΄-ٳg5Xbުaև nРAn\<@Q;2˞C<4>}ZЙҴi,YoMÐӧ… t`9Cx]o&B nzsVvtd)mO[YU5Za3/hJ}@rmkH z (*P{Ԙvk=MAk,Yx 8]|Yzv]/!֭3ڵ7}r`  {&_zVc~oSÓW_ 7ݴ=f=os5ZtbX=[ 8hyzjGOIk屖n?56"0trufۚ\MeqJܣGU V @0bpp Aٳgi1a83lbӷo]ȑ#5vvvۄ`p!8HQQsAu"ɓ:q޽Z9\422rP93o\ɌKtQ.XoLLڵ'LX&EX&(=kMPQ&["$-mPx_!U*ߺ詁R=zqX7JZZFE}eΜ Vog˼MY a~;,T 4P׉p1 l4QΝc قex :TA Tz:_t"eX]ta ~>T?aڵkl??<ժTiH{&AȄ^4ƍ*gϞB'{5ߎS_G=B~׬^{oo`J """ k*Oz|P@GL 2¢()R]]/V h^ *( (**c֬d˖58*exu]`x *7VZ!P`ƌLT2`;#::x]C ?~P|(.G_AX.J 'k`A z6"""z T(l"(`k[3C .{|*u)t곢6ģ-yt9sbOIˬ7o)ݨ  _qa"资t$(p>}4 %P^)"e˖j# ;LoԨxM:Y *HP5j-д?*NapvTWWi؁ A@aO뮛`'G4Ŷ@ob&&$$v!B `xm` ÕPn{׻p A#+V,.nC}A?o<7޸V Mha~QcBDDapp#W1'C/cȏXm}VԀ܎ 큃f a88BhbpĂ 0U1NXP,p `ׯir*اS`4׸|l%.pB{A{2{ AA5p_Q`8#Z6ڂ -o NV E"48{oV5 Z_xPDqx{\ȍsޫ ̺#\v٪JiBDD/Έ="`BDDa[) 0+p;n]Wu rCETDGE{{x"$С({thBDDMB#4YDDm@–xC񟷢 $z6[ec1㋿fʽũ#\`У~b|" Uڕ[E'"j+*DD{ 2vu>?|^{]]/ :Q@H)ޞ( \v93V P0mVYgn=TNP!" RYYxTKQQNOFD**m?N5B/İԓ\]~z^+[0xos4|#bt"=-@Ζ7|K{qOtͬ]DD-@Vg#uuu|A.[Av+*[Okzdܸ|3}{fz`Y999RXX$Æ qݩSXu^L*6ʥKZb`JJJm4M)**2ۙ+}Tݶ3g2ps[- ~9III1JioSn 8@JKtJdl}dee~>|䂂|9GuddyNqo#qwʯ;ۇwQk1P!"-L ;RrFkR@(re6* T0laCllRN># ?rqK||29&L!Qyy3QQx9sN:DO9sV-ɺ5an8Vp@4. ]N>-W}Iffن* m.]0x ۾//} ʺhiC II׈:{-oY&N +V,DD@V`AqiݦaG{*NsM8m)4VucEPhnA,'/^Agѿ KZnUr <@* T ˓}ѣ";V 4hVj xA x@x(G? \6! AP͂m@hc|P1fh)))痐/eee2rIKKfyx ^ ߏx>LqfZ"2cCjJyFFzty`-VsUTTʹsz 5~L2YNݻWw( TPf[K@ew_kŚGۭY}6㏿1mp>[>t^;!*+ : Beʔ)z=B #@ 4 uUp9## D@eǸqc\0$'NԃX?+ݹ 5j 2Xee2{,ٽ{V: p.^&M yyW*yyyr @ Fܹ2ctkx ۃ۱/Qb0 !Bns@0!?DLy9ٶm>o'? *ԣ|μOx*jjjT4Fl{5ۈmB@  >#Kzz`z_NE7e0C؃j:JDq0_o=o`~2줞aʑ"=҅ UvB!6o0exbh\!"\\aU/7%XJc<}u.!ط;::F{=zL~A>L\QQ'@5˷E.7lAAjcǎk`]n❦nG` a`#""Өh(k>|Gs [oLoRvN:, !u>+V[?POEdtrS~t7I'C 21.ND"HpFiN漫^"MPvi(8Uw(&X)ńQW{ؿZu{Ȉf?[q":K TiTWWi```&O dQ݂Azz56փ0`'}Yt( ;4)BĺB7۰k^F*B,V(U[[PB5 "afP8/Q{H5\l7ߖ_c˾\_< P%2\VWE&|QRXZCtP߄~5;'zLA-&QQͲݾo4h Vmrf) o5)Di`з7ebLj5g„ !DZZ Xka PF Cd G؁paP(it9af̘D4p@ 4iN+&]M>^P!"P1P$ S-fHTDd۝2of [+Ec2fXKg7&@ũ=<چ8|=Rc"5TA9zpfBTDJS^%iizc  \NNnĀ}V|֪i6ڃ샦T"`{ QGbҵXwI>e2&z")DDbɌhs\uHuCΞzv|?iB,Jbc65z]3c_ZuDDDDM@ X\i;:+T: ?u?Glߟ"{Dp(w,Br$ Jk#:Z]JHԺ3 =|W.oYsNzȈ)cS+R<TBdžNu~DDDDN.V0 yKH{ˋq̶T=WV.r%F(tT&KߌrDEY%3&%$/gk3{O<Dzet8C$e:C=Μ9J͛A֭[gRr9}Zg|cn_x{nOLDDD"uW'ƶaj+aal\S~6|HJa 99QXDEQc%6.A6},X\M!q 2dpdmi&nj3qD?~ Z&SF&sΕYf!Cib%܆-鏽'-Qcثk1PD Uֳ"*z <'<7"jh4!#EERm6#(,,ȑ#ȑ#0Vł J WSCz4-//iI4Tt̸*:2MM'!""" aJ㐟N.]||4!Qz#[LEZ%e&x{)++_ >xrrr$++Koh~^ɿbAٵ{ݷW\!KffI ]'j<jj5\A'z? }Sob6%"" t TՅ&L87ta~tR KUov Zh&2"#"X۠:EE6I9Hee9_@1:u?2ZJL@5ҠŪ8Ab],**?j}hme"""";,4aJ9Ƥ!?]ş"pJwHNnyn *XXMi1q{]֐ib .ZP ]vG r uqYÄ@gaq!u(s cI)]*]LxG8 J:TZ ^]'a:401b{a.{@V4wz?uevo.jO.}""9Dw u=*ԡĽY*qF:68۱Hsw"X8}Ո2oBpS'wq"1"P1o:1>fG;9mrPSgHuUN=wHwh`z=P.SV疎ۛvڎUG\RVV0!""jGxo{ k!`wcB>(f@Ӗ}M+|o+8`8EDSs뤶K3@%Pfq9tJq[R)!%T|zRitk@==TP;F.yta  J4:V*!6!I :ĸ>N]$~0+DD>{/!@:E*A9$]3POPh!YXB==L _i""j ?M[GsgHT9!2ksּFʼ>D$NDD- " 4U*\:x+W $R1qHGS & PA %Pjl{2@}xRdK~UTԹC% Jx˛<2B9p\KȄxI/ Lin9DDDDDDTV Ԕ uG3 Sm>#*T UdW/zLAC{'FoDDDDDDͅ*" p;u)DDDDDPWeSj.H!""""" G T& VCs47u!"""""Pkt }쏡\5 _""""" W TK4V⿽ڦ5CxQcB]`%cãpy1Pn!TPox'a:m{IOF"""p@%*Q{BQ]]-ٗ5HKK$EEET,.KϐnZ\-uu"BDDDD]  &.˲en( Z'c2~8G?Ҫ0Ne2t6lJ{_*W7%K u-rHPu2e͕͛ȅ :A;DMU*RZZ*1UUzvJ9x<_]BBYUUՠvYYLo,q.geeɹsRSSǩƻ.l/փCEEn3IDDDDm "" J.\ ;wcǎk_+V, iə3g霆0cƌ!CHjjV\|YN'Yfhbr2y≿kLLL _keJDm\o߰5Fmn4mvBYK֭QJJJV|c QX1c,]X M8M1L+W֯EfμN~ :TL@qAvةa̙37|񋟗GJNNYa:"W宻ЪLYh?1a{4d!ArBJrrzxf YPjG[U0G""""j;VQX}SN8i;%A}J~>s9m6ʔ#G'zU.cbcchvZPՂ%Z>&QiMȳD&OB *S.\Cy $O?O ˏyhs˹su43f̐-[jASKT&DDDDv T(\No$'Oz0M\keʔ&B%6lVsϻRPP(ݻhoe˖^.#&ILL!EIpօ`ަtA(0V *\ozzF[o۸s;|O򈈈Qp8sΡ?\Z P##2A%En ̨ UfϞ%Nw$Ue;s1f999Zyz9t8!HKK:tXF)%ڰ-^J/_۷o Xfܸu6mPJR2dQ`BDDaT}'8:u'[6n8x≧bU,yy:+ 9uAؕ+#Q~ߛf6ŲoJDK.YZu !2`/ooәP%bqs5j(Yh DDDDD탁 "gر,BȗEy),CcصkoJUVj *?p;INlPݧ"Upc&t`LCk6l L$!!ѿ}aTa `Ǐ}P2e˞={jfڇZÈ0 U1{Y0G w.[睶;ENԆOu)55ۥ`8`;Ci4JBD*E'ZaZs1j11_/׈KPwLyVTq5F,!tnGY<砪jF~(X.sZ*x<`b܎j-x+-,,,7XOEESA#* jc);}o>>-/<̳:Kwߥ3 #y_yڰA"dyߏB99~~x~R\W̗E aد|vg~U1:;ylzz"%b M';U+xMNN֓]S .|ܾĆۊ `0UeF!BDDDD~2,B:diСZaCDDDD퇁 Q/db=QaBDDaEDDAD"" KVBDD$I``(|1P!"Yt5A\mn?Z-z:p=\OwYxzϻ\Nl`BDᅁ  ^{A >[ Qb+Op U "" n'""Bg4DDD)RSS+ނ*DჁ u= O>&Oa fY9xDuA+- ٢y2QdUHtt9E/TW;̩ZcXB>PQkv.Wi\ۉS򝹳4`!"j-2).L]""j/xO{]*T!  T:QT,y2I5i?o!/]_,1Bb7RQQ)qfddHzz uۍr *DRiQo9&VVH9:!"j +Pq: ʰKaʯky7DlQC,X Q`}a Q@ nͦ|{3؃ײ.gO(!"j)48eeelܸQ~_IAAAS:޽{u{ƌ@{= Q@K=z\,+'O__cޔʂrsXaVDo܌~ra2$Zyihše'LP`1!q688ge9ߘ1veWUkHj`a`lI9ٓo[)unIf?;G0#ЩwrYUdzzI Z,Z*&)L|?sÅzBD u;s3*SQ?_QW'kn;ܣXC41Y>~꭭r7j[Ã9i9؆oG޸}m'Kÿ́;vx0@'J\jNOp6ϟ>vs<̟#3Jkt::~_Ewmr"ƪXBԻuDͨ raUjo&L 6СAm;)vV#k)vio>ِy6aA”@M0;/e˯&TRS+5ۈʒPu::O?4 Tz!>v T$ȈVirew^á+lR7&8WRL9f@SSdNFD9rLAarن/"~,;IZMSe#ENn?ͺz_/]?1$ǂ*Oy!r1 iz>mZQw֛s LaK555˵R\\|M%*f?ܧU;xօu汕U(B$,w*>hx]I}xR~UZVUU+--!vX.ە+wD9N^kQk1 ' C!Ѓ=>iz_9Ke_ʫk;voG' ٘uuu yP=0#ҡ- RtnCYΜ\Y8 1U߯,7]5x}g *hQ#<11̙:L_lLLKi.N}cZ^k[Qirk>-;ͲDͶ~YXX cÇH&{ŋ5hʋcǎFӦMd=}]2w j80߽{̚5K"C쯄u9rT{'A4hĘ8D]4H9o 2d5!~`~;y7V!C}wˇ"'K\\(0P.5{[ 4I s0V$O8M/yW<)V?Ǝ_62.,ٚbԘ&pg>p[I9*`Ϳت| $d}Ʉ#8pXcdzjXQ`6#u5@K]yxjB BL'H= uL`ٳO6o~_Gbl5RRRR$** QNMM)S ^3cm˥8p '6:1A[<~읺کzP0C@W`˫sDEU5ll3.#9u괼r]wHveٺuL:_k6oU9[sӟlBn^X/K,u:uJ0a/'7|S5HmGom#6Zt 0roh.Z.Y˲^m۶kfǸ~W\^+k{󩭭_C2 0Sۭa*s J| (㽮ߵZ3 Tmô e)hcE9x@NBܼf6Dg<ԙO+#̷K V| ̱adb u$N P wE+%KC%́+6J9Gbo##a_s⩮eff?^$$$oǐ]7_)L A0ʄ|Wdl̙3KF>}F-[,5h@*oA~mf 9afDEyo *zݻ_o\ ܾ6yW`x5z+劐w.'_RfΜ76ɡCJ2yz_lǸqcRf̘. jje̘Q2m4s@׿W_ ifͺ<]Ͽ >YsL8Q+ J |y'ۍ>P1넡+oY7ɤItHУ>&.dd)ӌ@cŊ߱Pb2}fk#ʙ3gu~rؿC0iD|WrT9-*x~Pҷo_7Ax->%JJX*e.U7V ϼG/_Lì{\_6u; +\{u@… ʕ+y&ӧʾ}u?b{oix؟kfk'DDD-@`K3Ik')NjxBba:OR1E-܆DAuc1U1*uq:x ʽ s=z\~p mbZQOGS Yz]}GR OUm<(h8$29N"(q8[7gϞ8@?q(bȎ>}Il߾SSRŔeݨ|9zϊ,\FBll/Xx|fРt*wqYFq`tй1cFm 8?6cx˔)d„G; ç;oøccPk'},͌1쒣 .J4 ^fƂJj#T|u.ndR3wj>:&ضϘ*&/ {ͷgLQ &}m;تeXQ`O[/IlJ(saƷ-m^jʬpDKwioDV`U% 퇂>8pl ݧ},p`ye5j?Vg|CspZM'>nX㠼ifYz~5Yzm*!9o*\sz؏a^ 5P=2xwǏ }#ax~xVeVd20Pj@Sx""`B]+Js)_V}R2BT ͠ca> muxʭ&m>?{|0g~xcA/æL烠|ȵJkEXQ)Q95|`fc%VCWo}l77D~㏃z6‚\xq9r>ҥlp<*< g YOڞj0%?~> g˽(*oГa)Y}KmxNnzm!AOx@p`nA>%'On(8}oQ5A̭u`_#@`>H] ,^1xN}տ *S|*XСCES/nǾEIfE3wl 0 s\`}i|#<+W u9V S{C UNAp? AqMSL֙ZpA0zpXl( X];BjƍeR,ۓ: :PVPx">Gގe* 8u fǏuzZXA}!pQ(z`OLLPAГu8uX5\da8L,ۈ*7޸V^}Uݧ^3rpz1<|F}],zl0- *"C"k, CE@~y?%O=u\wP5&&lkł4bpmOT Yf' >3?1 Sg„ &Ld^M PTze)Pt@_w xiC @s3ҥVؾ=HU4T||ho>`RBx(?wmӯ`?TJ5ڟiDmtʘVق!Nߘ=SCOs }ǧLe+Ă~1Cpop{_w\3-46u_sn7dj/YYIx_@xO쿃V5 umDm9TwYw&yڰA" s/-A.^3Oj_J!{Qg{g~v|[uwN֛d`95߈Bzw)o],m ft1;<Ci,.ip? [ 80 $c}{M]|nTc 7k@ |k[ǙTS&w_#&4<|X;Ahuv$B"dɒ%Ê+~m&;wa ~~m}`[/ 2. M#ClM` vVJX.,U_ؗlZl{IKTT߹[5߂~O( @!&"j wJ= -+ h~zr\92iQڐmن7y?(_9M LIle *AF''5z;H0j@ԺXFrEe7*P5a! 0U(րK0|bz`ɓuHop""j=47~≧t Q[1Evs.тBrJ8/]n9ѩ|QKukYIy忦N S#ۆ/MZ;{^m@`Mj1p`pKO fݙetmMG07jrXbYّ}Y0(1*RO!mcرRd^g"#XQ&pIP3x{8e֭:De{ Ū@ظqQaBDuPQxr!"j+*i>?c 5 URT|xx=Jw2P>'sfiB`1Gs0΃',}bD=u:z#*ΝƜH۷:Ah >s%##C?J{7Æ 6[X4E3h@|+(ɑRj}@C|``=.e4X7?ٗuH`ݩ-Z&t$$kՖ@ky% i\.^ 2rr#Gvge]!CksY_4.AhwJ,^H{/o8䇈p𝗗g}c\7Uf[UqV־þ(..1U.z"DA9;ܹZclѣGs*,OD 7C4G)v?NnfYp6 '` Qs=7oCٵkV L?n >8hFXBT$ Lz0<,C8HDgvT``صk (Geup1i$46XA`j0`8>:{V͠rfIA*jk3{uf3u@`0O4 e1fQcۈ$++S3mǷ6떛'c\N+¶=J-> W|Ơ1ϝ:n۶Co- 䩧/],YrDD`BDD8QC  #|7cǎA=fݻW߯q $o_jsp_=;0ԩ3ZҎMNN,ottx}`2~qq:T2+iX`i 2qx8z9?AC ™+\w c^!9sg/"(Wy`ҴiSu.@ǷSNip=S"/3yVAiSq"~{=Ra;ﰪb!p·+s:9쇈Z Q3ҁ) T!zZq'ݠB;8: 6:zX\q`-)pۊ A}pkA{ x l||?C+Ojjju9AhGx/yhdpzcvb;Ur»N?|C A>+%%Eƍ $O#F Dt-m&UDD;:Q3/5qJHcȌէ'|)/5:/*U0}UڳBCfP* Q+B T̔hp\F4Ŷ`ݻ) cd5` )˜~2pJjE䦟 cv7]]>Q-8ah7֠+x,13?!tB Ub:܇*D N7'"Ʀp,^׆ca pY={*΢8qBl"p  ij8~LA/UG7bUX!z1Cp߱cGkm[S TZ A փ(x4t@ GaFlCN= B[ǰOT  e,<^'v<,b=hXDv6aovckkktNx1t 3Q  꿷9ݣF4>R~uH4!1o\$ )^o/ˊ'f<{$'Viq`Iiu ŏ>` (JPޡ#qL!Bk&<#A p]T\$55jv*R@Fũ1q)*11ЗPxDˌӯ !ȬY3}, `ʔrx mhH$3gxΝsmYhA+xnqQ@B2|Mkߦ2|ٞ1M;y=&Pr߸1ra_'N T’!H8c/Ԛw[Cɬ5{DȨ(-+qeEE`4?ZDDDD= IQu}v-zyc%z~//d *X@ΕwwE22)Q0s-xܝ/oM(;![ON"kn^, %;G^FfOGSH9YiϘ*1MsTV7f_6Kf[gmnl3gKc.W{7!zhs9yu {`tRRi>ɕ/q5R[sfJx/__.C^S7T?Yshj?A c։aP o_nTUU8Bp:)}FyGr^#)RuE?/SS'OJ}/6=&)1Gj5T9|wuS]{eNt)τvzrDV>:TV{HXCJ W4%RB $H ʲf c}ZFsbC3l!r)[bZҨHh3lG.޼|jHbJOlk^emZ6^]__=i5M:!^iER-&P{3_Ue_-R18N>xD>&I4q:˘;*D!"""MP,8@Oskp1Z]'PZ}bb$BI(sbcA76˙R 7&2\N H di̋TVi~~ކ*fȺ(֌$> 42M!3kI՜܏aƧ9'3GfI4cN>6=!""""".80 }98xFIJ22׸ɢbyMZ ʮ _ ?98k%0TL 40a|nI0ć'Mʒ@3]Tܹ~Gy0Y>T SB`ȓ%^1K3zާ%w^s!Skfh[i MMiP?;)s22 mȿLN>~JGP2(>N:vض}DDDDтyurN]BJMMv$mkͷeee{ ow(zDE'*j}[믗k ;͜ul"N_hYPP o?Kw eɒ%_BL"DD\p8!.x7⮨W_ $|a"3Ҝ0zZb>w% oՙ"EeѿwrN۩*䷟*CN0ękժUE/#x+>[??5P߿Q@z= 23=jB3fȟgٸqC;+oX4|3}tYrG{bBfyuBDdeR3j(kP](ۭ出 KllN'"""QXAs""""" """""""1P!"0Q Q{Ĺa"" uunDD!!Qv"" .ه^#x<_s!0@„?u1Q{=(0P!""""""" """""""1P!"]Ǻ;#""" -w]d, R[bҺ2u]` r`id=)C%Ir(a""" %)ٕuL+tRDDItl󭚈;ܑDD#GիWIttɓPF%cƌ])81c$''IDD0,)/csΛرc$11cjk$''<̬{8o˥D 诳fƛҿuȸqr QWbBDDԅ*j+$&_ב" }[6@NN&@9)K,n۶]O4y7$--UÏ;P/-fPt)[juuuz햊 )((H<.\l x$&&FOYo5UfR]nJJ>cWm㲜?DQcBDDTHlzU]ʪKdᕱ2{BZob P9`ٳfj߿vQ EeVG?+<\*22҄#QТFO>,?)gȎ;$99EJJJfm2ןrYٴM;wn*_iӦʌcΙecW-'Nʕ+*+5!"""jBDDmrs_#uɍ,wMm;`{233%; &H||./??_AILL9B+CpCN`ϙ3th[om͛ȡCG"ui _,[LNC\,>[1N _tlxYz‹&)eΘ1Mm\C>"""*DDD,SE=yn+GZS<97GJ咞]#kch ?QPa</f T~M''N_~Udӂ>'vǠ'9HAX^--m2ۦz /fTPqT/P CDDD1P!""WTIՅ3gt$Y- 㩬'~Bp9*СAL0L N ap}EECoz @21E5"""z Tjc3'%6P\#́|  ?8x+ʺ*9V|\vzI3AkekƷ!-*;nQˬYi#WIЛ .H~:*>0D˗J\\6TC6o~K}eذafmXp85 )))ĤɸqcuhtVmOKKƳ~Ȑ,<{[kU kZZECDDDx^Q['ΒR;~Z*gd8"\0Mj5!!A{ ԛ0%&>Y*B#&!I*+$Ƅ%Hq%,K^~C/bEȴQtma @pS":T+J0nǰ kZVX".Wh(P a ,)/^Ҟ-`*Q#F ׀$**Znqj82h 0rLO/^×`ΜZnXAQWcBDD$a89qTK}Y8ϝ1!șRy^jqc7&hDEH))H\C3>H&Q&{JıbUId1j8" "vhVSPiS0h@{:U9'O6a>Z ”@x cG0ᤁi}efen_M1eL۴I iacV^ɒ%3/jwZ{{ 3ـS& á!)SAh" zC}~mIk6~Ȯ^ҕJ8aw;-ScS-:waA归پk ֠ݔ23UrəQ6jbLAhp>ӧqB!" 4,1t ![7$%lÎKQֵ( 9{)vX fiOXŤ '1pU:# ]s0߱ $ڑqPiI1ȜV) :uA  (*l߱ yEPָV1O7 KIVPgE>ze[Qn-G[3* 9fab[ۍ(DnJ Ó %>޳0y͛ըk탴4[lQbcc,;޴i38;;;~||t3j{֭ZꤐLIIQ]i8rCmێ 6`Ȑ!FUUJh+SMwuQ8_^nWO{cm;v-[4HmxԿwn]]j23 4='x<)mSO=Y=IA/" oBPQ@Bz,:Nt2mƈc=l%H;2j7گ+?2TGZwذctc>!eN.(N=Db\tBB( ?㻰^QQ;<;w",_2>񢤤 #FEv4Ꮛ"ʚ5kлw/FuoNaW^Z#F W}xΆ 뵘asy@6Mw~<'ԢY8WYY;W(.dR$&&{ܺu~<-UUٵ0|=Ok׮ENNt/zmܸ={Dqq>7;˗:"!?S'AAASe†nF%aKr#ƕ*$ǣȭ:[`铌NVX\] XIԣ Hbxr0펊j7HVU߹Xdݠpz왃M6)Aq& }@(#cݺ3$''G (o 3|~& ))Z 4x %cZyij_ܹs Q>( {(x<߉Є (zPPԯ3'geeToZ6"Mˎe˖k16[VV~h~vK[>|.A* Bƣv%lڼ ɫWA7%tA)P:qNNKW tȓG3xRׯtWaY ,\.t&VA_wnT:+[Lݫd6)$X}0=B0̆BXPTTQFj۹Ox"- g8_%Cfذ),0 *ĪG)0p3t萀2YdEEA^Øyd9r޿fZ =L7`?^(Z"?RSStG~Îŗp%,^9 v(Qsw;$ˉ>Orj_8@1=DPΈ" tht:!}CiZ1Ti .MC%+D $[aI:bUe'^ [cR8b@܈_])ql='!K}iX/bʆ g ~_-F Fǂ$1KNN zZO!T?&ƪ`AȓB͹Za ϔ)hW״ik3_3ƀ}_~c FъѣuXԪU E / =)S{o_k1Pz]}Ah DPA:05;XM؈2Fx0Uݡ;{W3ݥJ>׭'/]7 q W"A %0=VC9V(H^,(ء_d#Bo zVP0gzPp:;^xPB=4(z}>*)m8~wovժUk!6Lfzh(^Z}/2~ 7KP%Lix]r&柩N{a=ǎjڊvIN] w) h‘  Žl;=J]Q=FbcUb!9\XxCU3X1=%2:ǡex=êd6-bbg @J{UBzNbC/>B̘Qx\z8Ga\3jow50k=`IA>ˎ0X!n$t6z  B}ҤikfgCA"kX|EOll,`AD<  u<ݻ{hE>z~    B_;`QTs]2` AAAAh:f'o.LWAAAa}o;BHsT W#PaAAAA f}os_=[RI    B6{bK=+")-㷸$$$`P BdžfiY  vf_}n-Ii(Tl6o;#AU)dS~욀  ZT}kfx:VpxpPğw  t,(wCҰmSv7Zlo$"oDPAE|bb VPFXNJ-Zۚ5%%u4AJ>IzAA@T ;~P2`*ӼRb)f1#Llbض[l%N-jɰsBPL ^\.X}+   Щ4@lŜ75)qqjZٷ[\mZD(1EA!#V+bbb`Ah":(TVVJ ( bMf{aEhI̢ Ƴ)Š  vH||<" TV;ZL&BcX"IHF0Ic1(Š -G***BQ%)))@DU@L:`b)lL$''E\\Кetr9C8 a eUAh0؍ 4"-NiixB.HKKkAh ߓЩSa,..k!" Dm#(Ч@ZT)B5P#!3;]t!EhBAP'7" DlAZ Z S!4Q !Ř*5599=DL |L6?/ `_} Ah)DPZ鉘"51:Fx;ԩ=gϸeQEA)ط@B~fy3E1B YYYH ggo - B8طlVhvCEhVAl> <rzz)B:)Aƍ B5cDYᔙH@3IH3gl D A!+D`B b>.t,b1O0" D} \"4"Bx8e6g6`N, "}9AEh6 =>,[B<@.yS m<ۏx >М,?BN2[^{FDs/[nG>S?lu@h|;%qʔȐ830q47|: <2ƃ6@[0O#nG:0=~8~-ct?C܇aÆBggD^=>t6y1 :>x?y]իWԩ9Gy~ב!|bcc!MNfHΝuΥo>>.IIIhiQ}qtF:CcT;\p O ڂt,X{^o_wx≧7ߨE_| K.GBBSO=99=g}֭[]?c=SN9 ^:_C:iĀ{3gv۝߿?aɓ'bԩxWcGj_w=]z {I\{_C#cu DG\\>@-,_ҥ˴p?ѣGA6nPjO=YgFsxwqq/^Ma]&G yOL/O>SvQݻӶɐ#L6bp YNm6axo"4 dP|9ݸq2?'x Nmq5Waƌiزe+N>4^{IOgus= Ah-z vVms홢"U?؎:ԓj\9;x-|7t{9s4 ͜?̙3pUWNoFvG_F#{O<1`™g!2 ɟpKoXvj_ZC_~n yPRR;[l}O7qcӦ֭;6oӝhXb%}yUP7~W=IvءaHIIVzjb}7w訨k#N O?2W yU>jj#c 1wohK%=zyyn?d`GrŊݿ?I͂Pڂ9GB#ꫯٳ]w݃\L[T'0r' V_g%&MAhlܸQ v~'xoEHn]O(!qk5(PIIIǬ^zU}xswi'%dzz{ uq1]w(X=@"#}AEh!pU1sΙzCVŕ6U f}vM'dݻk71kzMo'xD{&K{v=C[/..#9O<q*DoFڵaMBA@3gP 2}nz^x? >C?# O2Yy督畕#BMh Rw4,Yzw>H~啗K.wߎNkh\x^/\E'Mjт ە ~Zߦ +Wޏ֛PZZp?]v<-_~sR-S|׾^xn+;oguY.z!"#\Hȏ )40F8R̆ ^Ӄl6[4Gׯ_ӦMm6"L=p@fKo2(C+xJngKx;v{Y=^{~w (B̘1] j^2~rsӍS1CABps?l 2o{<|m5Ϻ!r}$Ygg֢EK50$]$ Wj2q,C\.o3>ڭ[7ݞ2VZzD=t3W8XWmƏOZ =Ah"4 wq0P!̻0r䈀ϳZs ;`DwZc^6,ԎLq`5))Q7l>H!ϩ9H^WYv8' :3(Cdv"܁=DFܵxZ~tޚ q#葭1cFiu`Μ9C~AyYll$X_rZt,Y7 zӵkMkKh..4 Al\QJra2UV` w1v왣4F=KG\K<jy\ψvNf $Ϟ^Q_1Z7acF3ZWb G2_xm~mAMs 0@{b avF]äϹ3QoPH7nٳ36l~gBG0#z&u6MOB"Ag0[sYV)@b}i褴4@98/z9Ο@'e",X~Bd!42\ 4 f7b}QzD1aÆE}C=HW\=B]Q{Ӎ/\-YBIaCzP,a?3}sQz|/>CH&'$ qԳ~n1[#L)ڂ)MY|,lQpg^&U0~Xe9쌐9&%-I)jRdםX^ែ\qikt~ 'kyp>ݤE%,e¤f2C2/sx?&TvvwJtwau}뮻\pT&sX8S[oN@]#[HNhշq=܉cG2]ew?LWnݺHç(߬3 qa7&#+*!>s>n[#L}3s6^9:)9]&%]t822};q(lumzT/+B}MJtdW\q|_ӧOӉ79;wQ2n8ݱL$G R#U??xYvءڃ$8knJ8G{ 7pfsMkΆsYwtE-WkPuZy5/ӕ3g N9~qǨοM#LDK뽟\uwqnq2J@=~鵱m5%Ʒ|KZ8̚a;BнBǁSaԍ?|{aO]zqfMG>dB\>8Ȇ1CTqE+[p*dNwܿ=ˡо`Ȣx qqjZk<N-n1lEmmkDhl Kgk*;=SF'S9T8Tp51 g0F#B-B  D ik ͅ*BtBnv3^M-c0 &agyaaT m . ;EAgДHȏl0ȶ.B`X"P)US8cGc,#Hȏ g$)@#Ghf&$E mS4 BG>mPAha_C9AEhV8.cASnWVVamy>  +47"  BG%F"Zs+PB cH"sBCW<&) ^xc4[%77Wogff@+SSL1DENA I- "-BJJ8vBG<ۏH3bdZΔ$ )WJ(!EA!qqqo!-*BbU!g1 NgYY)u&B0mEEeg!K1EA)AEhQXJ 0ѱd5k"==YY"m )(**Ϻ1=!$J  AEhqXrt, A:FT1prmvIIdddha%>>?/ |fZHٱcΡ,)޼A L@+9Sր*B"]o#c6;(>;ܗm㵈BsbBbgB99' `}$ZAEh5`JbbUtQ:9U}fa%8qY@1Ah)vsxO(EAI||Ss BK#`AI7>.ل ]ىQ2faO󌵹!"4'f1ֆ΃EA{j"TV%\ً|)BK$E[AA2" B9VP`ΩZ΋EA! Bd~mJ`&`"B  mTAJ~Ahs* B{AA6J(Ahm" B{EAvt\AAAEAAA"   PGDPAAAA#"    TAAAA*    uDAAAA:"    BA%AłBl]uA B%5" jR BlkQ8 B#.uAhv:b~m Z}5E,.͏غ t vV谂tr酯u sA혘f̍Y( B".uAh%:\v%$ī"Vm[uIڠM;tJb\\. bb:[غ "([Lmim,1[ 1 z]UUI -GeeNMS( BEl]:biL;o b'8bWӷ|۴xLkýͼmG/㏋4)@[M6iUFغ ~c .ưN/̉#%% ]xKK\"f BBl]:bڵ\WTT 11Q bAhF]j%b6i{: :.v/Wjvc.p8k[ 1lM1!#.mnf溺87佂h6*6/gDȡb$JKKEk$TJYm]p4v[!4m֛n_hϴE[oL].C~m&ǡQll,Z+nB{6Kۥ 3k8m:ؚm]i M]:><R `Q h11=T399-Esd B{K6\l]Zm:IB{z$ػIJC(|ʩ%"'ʶN1ՒgTKkem\> J!,uhf;.[ bB{zcthDp6/eVikX 1g({[=ѮM&B) -#Š\ޘ4Dd-m\=cG9$g.l\rrnsm|s s%uڢӖʢ[=46,.@T9hRUk$+J-B[x#P[**'-Z֣ͯm ' IlyVq=,۷!d,sh[,>6M ,,Dْ@h+GH6uEWyoX |j?R{BΝl Bk#ڽJS,6Č,c 7e,ldZKJ,hW_:RxDmUZZc51[r9 omΘ+eZT+閍6eFAJJ)h lIY 4oџȹZX+Иd~.t3.EY+!?up 05v1UTTXPRfCe.cu!!d;:g9ѽ Ч0x@ tC+Tc*Z ߭[/>셮]=py2,XW*S$Ɉ>DVL),,DEɏ_=GhE@cxqq1[ݙ5j$ƌBlyhN[Cels#/~ן#fk.tLR_l[`SXR٭;ʦ}BFs%ҖA9l=pܼf?x- w)Ե;JQkЮ`J!J=ئ]YYܼR'pIQ ?+e\[E˼cb k׮ 7\ǟ]{{9?TDQETa_/UɴQIܭmF#ԝhˎ-[6#zv^'X?EAAv &FQlfQ?7SD9ᄓ_~)"MO"Y߸o%x*ʡ&27-E:-O6;=ϸ8vXJ %d(VY7Mq:a+.;)do>%zSHK_t؝= aS&qɰIЈRO5X0Z }fFo,6ŷe8d\ w][9hYG>C3g;\~%Zxygc˖JJnM_E"RPP7s*J '|"v}.]'x ѣӹ2d>n|'Ux5~mEzdeeD ꍅΰǭ'g^ < mh61|u]d$/(wNr$WR睈N:5kG!x8ۣ0^z֭^(ӧOYg=HlܸI_sΜ_λAPS>cH_[ֳB޻t#b)~,= +ɶ?m XoN8L hΞ޾uMX]uʮӯ,^xI۶mG.q!?~h>m >眳~^ߐK{B9+)ALݻWs͛7ҝw/ K Pnnn{#lvءs7ꫯøqc1bp]3?9_~5^y5p)o.<BR#|7|[U uxw߉X͜95~O?~WLieXUHz ?n,-ŎQ0 B'т n69+"?''GaÆZ^4l'̛@ )0p]qرf'y%z=rW^y4VOoPP9M7okfo/bS Hs;D# EbJ G݊> e8rjj^닡ԩkKo:2 {f@c.rc„)z > 7TutbH޴#bS=8Sݾ [maJSبwE.3y[[~S|,8M:G,@=s#)w߽u뫯 sY>jdwߋ#iTh+%&mi^O&ǂuUkCM) .q62G{m )*Eb rp&0>j;`$mDi]m=Զ]#um<p#QWwǢZc?eh#<\_~"+ WwZ)ڋʕ+cߜWI[LAU B}(7zftnϲ3mp29(h읝@6@#nD#rԺaWU+bwz;{Q`x)*&|!*#4Gs@ Ōѹr e !šgub[b>gj,:ug1eb 26!< /_$>:/o˷FƣnNSw|xKˁ3/nӻė2A -ެW[>.PǞdu6EN .QpeWB'^6< 7.KL>ln}Ƴ.X? an4j24a_'xD{!`6wUWcDN>'ЛC%FlؘNŖmm'g'zv{+# =r +šIؠ:Fшb5Z(0߅cy,|?g.`cĈtF8BmZtC쀽{hE+^B>~ṇa+fzp=la\Wj9H,buyɃm U$ܲNj=G(P@M^8vW'O F"hyXfp3n@љ{ß$ 03i]3Y-?P3n5;W^y9z>QI){uP'!rdsň N%۶rp{EƅHnz8KŴ{c8 _ko^1rfOP`"jNqzB^e]s^kCljpļlY7h0Ē|/eQmk) *d=rSϘ1M72O(P䚃)ͰsLȊJ#PFho69Bw;hy@;*F$x-Dv|;}pD+r(ު52GG -Vlqɜ3nIL!no%ΩJ6+e'FylX'IXI"g,沄Mɪ/SUr)5c-y-5Kj;*/AZqH-AqeWx eۡ^ n>#繛7`[Ű9]Qc>Kmkvl~K5oU}s]葓w(B>\{v5qmƮ#;O\x*EbU~Т<㰧ev°b";etm΍Ƥ7pZ봘iqn3GEIPErSNڮ@}oHxmEQ}9@bzӴwݧ9 QJ:: Q+cw]j B9i'..>NE[\mZ<'<`ؤ)!?&jSxU їOZtɬBn \~Oތͤ;!pWK] ^KFZl>69ݺ8b\ bUYdU )5i~xDU ;>ZTxz𳬖佐SBv>5[†r̾7=Зľ##6Թb'YY/l a*Omc=Q5~}uv B(  C *'b ]"h wcSnݻ7M37Q7)C&w6ܹĠAw~yzPtSzÐ8 r2lwKu4&}s^P,)BA% \d!/awU|e"yp.~up.6y/7 mj҆U%+U>1AճT+~ڒc6C (dr^) ,1|oKKFo-Aw8lKDO` kQM} Roc8$< Ի/Ⳳ 뀣"Uū[WDC~y<|J͒q=u[qf>cj1̛7_0y?f>y[v>};To|w]UmCOii7 +K =XPg"T@Vʏ/@F3AZyj0^ocؼ0" &ߣsbK7xK@#° *d{.szfb00K/5QIxૢQAh(>y|?/dA1߆^=[TFcO@,+6溱n W9j\I'iSjZBJSD{|t!2W>ln%ܒ.g $|-X1>}AB7Z.(^K.=Sy+rWU+m} sI 'x+ ʍn3~*ݱ}%zWM[h4GkNoc qftBIg hpV@zi//HD>r6loFzzBB~"-ȸu*R |sXb%nB5/oe!go,0z_`a| 7@qi q)ox!߲gq:Ǐx n7K+unqPڌ$+zfذψD-Mpj/_Ңx Fa0Sl0-ͱcv7RS,\cbNRYAIݺX1zxn񱺍n ߋM\>vځ]먲 B' #ww6yx0pRhRCXw Eu9 RnDLyn6X>۪5d1 GWeA?׊/Ӿ"!!)~34nJT@w6|gb={旊АcC܉[ƹ->).ߙ(]~7@ikp>9o hAE@׋; *=qd T"`x,^D:1i\RB.˾OK-֢=C'qxjyu^1z/~[6z$,ZV]ӫt)k[rss}B PLfV܈I7 oJBr =_< K{{ez ¦Uuعs;1{b؅>$X|c zX>,[ cmFp2RS'iO4 3 foJ7oE2v]{ G8'~[mʭ.y;aՆIc1[ujGCEZt,&.~J<7\ *1 OM;}`P9[D 1䡢 4?b!0w68WQ7b㐒#A=-m_]IKxHV̢PQjOL13*6cfQe.bAW"6=_(1p(šm-X-jGKV]nxG|p{ZL%ؒ]냽}}^)NiBoooћ6ne~wq-5SPxߋS׍Wg@4$4M!QLj+.󪅏PI#UBR5Gw7SC}Hկ;*9PnG(*N X,;#11 ,"We'+!7ͣ);V\*mzEOsλ]N?ؼ9Wjꐯ: o. QqvSbxD vlaS}%DԂ,?>B3u?:6 hA+KVcD?Sx}g7n,^e38G}{/Z{}{}ր&"SPtZDIǬ;+8}SoC%ƫFrbґTո鑪:0J,SEm:!n+Nx<Ɉ<<35NDj5~lߍ+}y[x{F潱wY3;֪ةj)we괟!}݅=zh1G3<={3m(k׮ÑG>xz- =_}R /  Ta߳z-̘1 wuv{٪u~q= Pbkav%13k2-ztWWi]jG_=R?ilЖ>a׆{`<,o1T`L S 2Zۗzm2qℐܤʦM9㐓8 .U?t,pͧ="^_n_}{DQ˲מN@%~~j;u(ǯaOLJE FEZ`#of>^Js֮H6y!}] pN̄Ɉ5 m A鰕UDCOxL;,y {H69Ѓ!x4((;ND-=k`mXw;%S/ .TBsܹP ;?2BAh^:tOll|(>lN+:gҽkS#jul{쉘2e:>p^':_}Uݙ}g5 •W~7l}:\3N; /TnW]um+#@O!Q!/bepŸkeFZD$sG{Pp_}H(7h,!5-vzG+ѿ;ˁ`i]HZ`㣴s//^6LÖ-[c5 #~o׍z4-(t3wӰl#8?߳m6Uo"ZX(}}&~O}lÆ8 1`@愴k2+XDbUv7Y* $VKba.NEk NKu:s&Q˧[^F(W7YZ.SeɽX{]yexԳ#?GsA]|{8q7Rc?C6mFRRR@x/Q<6s(h̛o}=>n|i{tH^#8CF#@wtYjkqqx-_9і1m% aZWI؜Tߜ:z2wu#nX3]U-;~/**֢-ܨ}v-kjj{_ *1ym7| 8'؞)?\G."E_s_/semU]E[O!oEEj#[-ljD#&tyE<mJ #vM:ZH9OU,Tы[3U,|O]gk릩Qy0w{ìY'Ĝe /5~W]Ϟ֍p*CE9=xU5:x߉G'& @]e+C9VvBj/Hk;O!8`?L3tVHtK_qϰ㽱EwvQ~䑇L%oK5RΪݗ^zN(Ʊ;FGFF͞9oBsNjjB G(x0fqlѵ`}wxc֕ռy1jH=hb|{R$2(gfcK.xNuk gy%Ű/'XwG TUuxT?RXt,^6卅ǚP1ZԢ4,zmE VYV1?I`VÆܥ}{-B},v'X ~l;V9n,(l())F84+z{nZHKKUz&>ˆP$P˷.!ߗmf/lk^-&V춛wϾ}ϧIEd²H+=bgӧs-c2F}^9\_Zߗܧ)rrkJ\xC};* `;P/2:7k;{,N88}m۵p9gsBxg홶o)RLW(XP`8 gPK.yʫhC9A2 pJCPZ y˦, zOGȎ |\{F' %:|TPގ·~Z;pW Tj;jtN<`1,[sczhCg{B6=<ݪgm?'=?0` GN)1` Ł_|V֕C>|'*V_ 6`ŊzBQ2z G$2\0 R^^T<6/7nҮ]tx;fع3;u) #'Q{i4 `=ƾgKWo^wub:>c\*k7;sQ 8abSZ[*Sb<>N[PL}@af7dA&Aŷ$Tz^1E߶>JJ۳g=1!ui{om(F1B%nХht"q,2imm6NOv:h#}`9L葒Rz^ZZ|;u 3yqS0v}6@/#J0,O.")*ޤO)c:|o~ӎWaAL_]_eV9eMe*}գk=55%`m==e֬>d:ަs<lφQ4z8'n~mQ}{>9(- q#P*F3<,,sxl+ ,6.]"_<uScY`3Q_ʋBoA߄Z="!l02@k~(VKz1?B$EJqޚlq~|'W$Fh;6skm?Dg?/mh͚\9zeu5J6_u"?IT۵wXP|3+~9s~̙3 NDPi$w#εpxRGc,tTx,xƆ/0m=65op駟Ӆ ޽{鰕H͞*uUkՖP GNG.29̠OၣlqČAf-Pu#9>=W(pPLvvw-'|FG~'igHUW]u` ,_XMu*2d {6V*8=<ǰOOSmޝ̰>4(|HB~}p _fbȐYq9s-z_spagSy]"Lsl`v;!yj25(x@oo^[ ")$A g4YBZ'OAF~}uG;0ڕ8nϴ=ץng1[nSd!-^+++Sp6z׃4l[F &(CaSRRU6֍ȥ.[s> T8"NDPMHSP},+#3\;NfJ X5\+ -vD8^wq7֭[?nS1 iR|睷iQZ]`AXf(7F;> 8K%5>H7)&wZzN߇|'us2PT7[jMPHaW_++VL*N ݡɨQ#t%FJI#3L w# -O$K}YD i.iacP\Dݿ؍E ,UȢ|2J5;<@1M1Ż'q{Í*->_{j;K|WLaNZWzQ6p@_y o>q.L<BHkxh㴝`Q`kQeՂ0m\OFP+bxCSC 1,Zd 2,(}h42=}Df/<R٣pzq:>Cm#Ѵ7ރ]i% _s?D*B YvfrK&ŽQGfXvzsv[;6vKFnLC/vS{qQVй2xC%`1B]&+3K,0TƸWzak!y8gria)T7ӘA+k˭ZMog(ZS t$ƫ=zY0fD,U3g1˝b51bM>̌t iG_n0c}zzaH;*Lʎ]7pj@_|nlptVlT$j|{S& CIL wj>3,a9?/=D<#uBWΆ]ccm8Sk wbXYő#G3uDs?S-M:LG=a7?º NʟZCy _v%5gff4ŵӑθP5! KC wXMkc-6[vc. x63\Ck6ǬycX9'vB"OUVzX;`p9,AYA.SKT"HsNfEzgotV(sku:|uׄ%#y] .\ 9]Y226n)0' jy^cM(;YL1 Aɐ?bS3*C-(o҉iSbIim..Rl7b\*Xպg_x;tݪ UzTyQDfJKfQ˧R5ւ }zԿc[q.R6 7S_[Tӻ/n2 YH]DJ|` qgޗy0 \Q=U#[ӝD]?kX9I^UU, dݲ+2jQQ^\7\oH[w C{?CԀ6?B=8bqc2(424~J@ O{챯9O/oopYk( , с?8GOanL0OQp 7%k( gaOFrhil3(Z8S g5{ҋǟ§Ҟ3Ok%kbF=[\mZ<2 UZ1tʈdHHSs8$wDx1gBbCth)8ss ߬oŘ)6HN8db@)aT/,Q35}B7%"S,Ӣ.oȏYԺtUz9+JkťW.C %m8AEcWHf1,<)2Xt{S*sTbs,k!xf7|A(jbW6Q~&q5윍S뗗'N3]YU}Ʒa>!TXz]B4}4"oa+U{ji^*exԢ?")nL[Jl͡@聹eN5XJ47b_sF8.}8 -D*tdG7;N].;uFi~IDQڗ֡pФ!]JİJ JPB8MWDb,.n0?R5(NQy7ZEjD+^1ڻN^FcIj*E;e80 ZV_jyR|[(_L^tr_} "Ő6}m o ӣH6_[j9m~R[QLaJsR)j|_513Qvikym=#WU#ԕ) usdIh GQq{.a|=v.LsOksϽ{G,0Gsmx>j~zS!0/ A oScP0=hfBҡC~Z=nO9$0.5='#CؾВ4Uk/7 'lك[~R]൫x2N@Z`"Sswқ{7iGT7 K8~R{ [n4U*&ܦ'nMHO#\aϞ]ʃJ=򽥥gN'B!̈́{`GmM<  {Q6(KeTkzqTj/'gJjTQ R3|^*e>JX3vf1赻0ACDwÚ-yf#^ 36s]xT*#e2r^ޣb ټA%lG`OMMꆴNC BV~؞;ɹU??S j58J8 b7#USPSBBy7zx٦_w60s(CkόJL! .YlӔГ! " '&e8ʢN|%n4(o| J,t4EΝ;3 (+L ʥb =um{ b^UΩ6RRd^1mVF5X]8vkIP R%jꆝ)]DŔ*WwЩ{37Guؼ 1 ) q/N8zB"wl./qks,\+7/FRs˯}=MXC12y$}Ww?xt1pOzν F}׫v-sʣ7˱⌍Cλ~߶IS2yD-*a0 +f7 5^vqGw+ ܸ2=F/\RlwkƊN|mU+1~?BGqJXo <+vlR 01HX뺼=!읹\sJ`aP<.QZHq[yn.Vtβ"1⟽^/lW"mn{\q~22Ë)/ 9#Cu,e 9v6P:go=noJM7gv{:'6/~ԁNXR/=Q@qq1vLv)1(EIRBJGJȣW^ۼezKUZK [p^$Ah/D8L=?KIP*O&}`ڧf/ę =3ѽb1,=)DzS*sjwKRBJbM3n,}v=賜waBدŸs]$|YXw bvD;u ۠ ppIYA>bвz!Y:uQC7vy:pOîbk -՞)J֬s%{BN5j|Ɏȡ>dNwۤBnXW{=c"jCRLc+m6OA"T'$)eP,L@&qX,OD!m>-lH?`=4#]b۶C6bt 3ivU,6=P1!BEXb؜S1>ǂe݇clN6ln^oj[PMrrrs|H bM87`4;YFN[ځU[/#eX qí"T $yV X,UNCl6u}[Fl`.:e`K _gDILR$)+՘.YAhR Q)`v(}Y7U3׎c1i8Tz_|[7<(_~4kgnW߭ g/tFWr]/rd&I矞ZIIs4~})D b]HH҂ʊmNJ*mcŻR^q@w_io}OA>TZCSP-8ETNYu(C&^օ3ÿ)};*]CHAh]W[ pܧ!'#VS*G;rÎ~,z\#ۂmVh)>w(*k",66P7AeR1vC{uz[yrOi&B 9Tz6ӧF]ae|w?\ީ da8 ,[Nn|T 5uS] [޽{o*5j[U$Z`#l2-Cg}ckSچ 2`SB*J%FX.>o=i8全zEX|mڱ5 ɰc[V91d=QS!\2 ;[Ԛ'ſOO}v; x~;((En'%k{na?w BLŀ##GFlm`UufOe{],AѩsݦX3g {yx?fO0JW2Jӎ5ҠQ/^7[/Fz1ig!*K+~yHg%'*dХ}M{fgw D(aշo_Lg;Xel6MڪӔ&)LpˮW.˶E-;QQ3a؏#_7A\\,z"oY1såD-JTܭ Nqy?cTU,1m.B%HPqPEbqY%1'i}z!>>Mz[o1}|-h|9|xO8!%8]yb쯡A\ʈzlF _E vШ)buGleF`ҥ V~zʅ5=@c7mG\4=7%pP&9Ym! AB~|6cY(7:#.]Ggȋbg@oܒ|•R\3Qu 0/L#:JDyF"Ə%FyJCbX)(.W#cqq ?‚P50c8P+,J䭲ƌ#)1AN[?bMG4iii8vF'({1BA|7 S<}ڧ]]8 5 {>o胘wl,#:1};&:%ڰx"ˇ shWתӐ3xPLYJ{TL6s@/T~1:uwqz_0vr;vu>G~"/ >p%Lǟo.Rv۝s}1}Kr媰|uҊ+!*aWX}}Wh9*WP ֩oކMW {<v'qᵐyWP<[Xm}Tr>q6mկoE٨/O;w\㌽.sIlzKg8\zZ*&7.[UbJbXKPcRKPbJ,JHTtdN Al=C<Уa?'9scuݠq^z%,YD[䓏>͙gSC!oΫJy 46c"T^Ph{OfoEAqW%ҷai2d ތvUW]wJLDZ]"ymhJ\vz:`Hhpqnyt#*z`*,\*8Xu؏Vn=EwL9|{j$[QQ_ W\q)g/{rss/bƌX_Jyzy1 ś'x<vi)A5]'|C,J2HKށ,nyFCV}j ltTsd<}Hp4iΚqįkgVƯ/kA{ í>˅Q gݏ~Nk7o_o4s6R"Ba͟H%ࠝ' 1pj<52n}Faxv׬r7^bnD=f6|lātmY ZLn{&!!7--LFi~Xue5d'si<S :Ν;?;ܹ^^H /H%(ڧ^L`" 4 q'Z-.Oߩ1;[bbpqS-7`w7"|Zuo<N]?0b\rˍ}7fo@޽nz8=*;<2r䈀|Cx]7nl1cFw3-[\sb  x'|XN>?5S "\oo,ZmA +oBum8}Axj,O}_w+/GޫFxq'N/|HsS۷~`6m Ah*C%\ql1?໹PJ2ӶbƤ)Im.pU&x˰^p)qOU ^p?ZQxxZL?VG蒒WVس:YIizc벪 /ڂXm]{cr,ݺ v]4(s}s9Z.Fw5ZZBNd 싸bmZ\SCZ%nCa .$'UC͍XyU<[c gzNq(/GUśµzQk%7'o|p߹)[[o@.&ᜲR<-ށ).ILpsjm, ITiw&.F Up9Yg1jGm>1,{oryz۷OT}F=931o|bϢ3ׯ>sz/9/HCwO37 /<Gu9\qxg% Bc"J+xaL$&` I3v٢ !;YزYj:= s{ S[֭htp16dxn4d$F:R{G^?} c0Qw yO>+GU;*J6m^qe;.[J]r"^7"c-M HINB=|^%{6Zq?#֮DR s(wBVb܈ycs+!˱픹]V%^Ejȩ(^^!E32:kZŔnt"69cwxc N, z$[j ʯd(V\L1#`6/ BH["n 6fc^{aq|S ˫neL>캫NBplݺU'1`@c~*N>t,^DE9CtrY// k֬ HO8ΓO>=Wѳqa~qBٶmC;huGqoߟ;Ep \}u LMo.{ϥw1m.'xiIlA% yفkOv Wfs`Ā?1mJ*x:mjcHuizt#8~p{wæp~U#Qq>g'=NƭyfcX<8+{S'msQQG{ƀf%,l*ޮ㽓㼕]#ol ټya{t,U#_>ڌKbU Ely| j=.n{`fY|)E }QjRSVI_tB#NCsPغO([>f3@ܜx#u. RʜJؘ'sy9M㏘gvχn=H\pp& :1(={>ۗ]v>{CYY9_v)xwaѢZIVRv(;zf-856mڄD;G$^Boщq >濰ۙe$yItԩ}s=܉:OsI'B)k.Nhn6"/wxttg{mkqĪyFK.]cûqcBCU#n ǧέ ޑ$[n]MwaՈ׺<,ظ sq cm]َ,۶{q)HKH#?Oq+=.Tk+E8-C cŘQÑECaɂ]>-)C w[DW8ERvh"@ڤ6b:wR8?x;".VTOm7dO0;{<FH!cpd;%dbw߶쏄Gbcj iTl]lP[oG=? {?!ec#„3t2iT'p̚]t^y?@?P75worIz ZZ\&!MALYk[n@3M٠v;PuF­R1xpodŵ 񨬊f'oǘbin}2g*xtWgŨꞃ&U|z_>1׫R_ F'0Z}NZg>ΆФ16g0[~y/-=Һྃ.BtXNP_v#// neE:sr&mX{؞xpC]g~u3OqܝZ/I'sq)ΟrdIq))...Ai,[7ftX1CmwCVll?ڰ#тrRJUX\(ڻ<)un,yGw!9cF ySL1[[olZsA}5[Q)~s6T U&V=okEOD {#P1!/.4gn ޲w8x Jg˷k6Q<S.ĮJL8 4ysq뭷>VLVfX۷xB,@=\,Q%XQSD1oa lٺ K3KuiiS ~moz%X/wd'Vb{=jp*w}^7ܪ"؃ ;x/0kяj$h7K_6b16eäZlt%CdM:P6F jJũoVTVpG16mŦy(ٴY+JiM9ҶّÅ7lvs ͂d+3c[<{'`p*RzeiWdef !>j1f jƗz[MSzjsZ1aNb<"YlA6BpA 6%??_'[Z6k6tFlv{TU|蒇=c@N߿?u$%CrDS%ՖfjkT+Z7L{۝BIi`KJQ^^ 02999껦g[ ,g:䦬zx3@nz<|Y9a@1V dW1f8,+U30|$=i#TH}DssscߞͿF%%g׃NCG`̘ĭupQɡ%Jpqٌ2vl6oV֛#7o槠(IuQV#I',V *V %DuʑVn]ԈuvAң֌m<7\[E]m,4=HJJ@zZNp:UP沁ҍEw{%*bh '⵸|?kט 'خku>V?b~2介}WT91#^v#;m:qc;2x46;`Qg@ 57:x; ^7[?v(ѣ:r$=缍IU@Ň3f趻Bk'B#JTp0GW/T2eejԺryTBBv^:7 Gi;׍ gǧY2g0:36I܁[1D 3O[ng;CxS[{:ܾ@l=2b뭋thCqXj޺ W_RSH!U~N"Ygϵ2"r8<}H%}k0[z"TY@"04i"6o{ŰU\\4${;&(ZvmAhRj+|YXvU/h_dŦ ͖_t;:06J_\m`7u! l}MzM[7ш*mî(pW0[lUl,Ŋ dW.C;P 3vQHB#Ŏ(qf =нWw UPm,QzVFC_}cݜ1OXӎ¸imP6҃ 4v/4UA%n>+-Q8U8N\_m:3ﯯQW;nƗغP2:j\8N%R@qq<@U]{#-z@9uly4%dJV5bBCi 4 U *[Ś鲀3ٿ+|H۵FGx;ףP)c$3uB}^4` ^ۍܦoĕP]žNKzC:R0;ziȽ{]۱ Bk՟~$: y^PeS;okAڝΪ@l1h 5 *tLZ3]07PH8q%h?@/hϢB5ST:_B{ϮOo4׭u}No/t-6["t!EhvIZ\sI}N^`xLKz$ﳺtZi٤6o>hbBG :=`E;ZNaZRR怟ItNQuZp#SY.mg%miTaoZޗ b}Fv^hjBM!jk BKCm9,Ahϴf[Kgg B[-ibB{&Z;o/;A&Czn'[m0ZJKHVi]06?GZ m֣wB<^h/zpi Hv[Ɣ:SxRRZ R B Vc0l]@ڢ_ԍu}Ahz]Uڥ?9pl6] t!-- .l0fkS^l=Tc1ZE:cBG@uAhC.PKJQQQ,Bnw@ nm6l]Az]:amv+nPCf["6ֆTw]nTUUoebb 6muAh݈ BǠ%m=..^][l]ƲDP U \..K)k;;xB;>Z:"+ Psׇ+ .uAh4:DRZs,&1*s}R Bc4͋6/u .uAh4:Dx _㵁ʂpj9-.-غ t vA(;n.'Tj!.-غ t vVP t'Ahn37vA,.uA B-C6 fAPocb B@l]?am+`A>A=uAh= B@l]?bw\P10?DV 4-=$.-غ t #`$'֚C[Gl]:bi ;othA02՚ 4-ӯBC7b B@l]?-am+Vs:p\zkc| '8 xLLf B".uAh%:\v%$ī"Vm[uIڠM;tJb\\. bb:[غ "([Lmim,1[ 1 z]UUI -GeeNMS( BEl]:biL;o b'8bWӷ|۴xLkýͼmMH?xeq& hI&mjh[֏غ t vi%9Qr$#!! > oiiKLuAh[ B@l]?@T ⊊ $&&JA,ڨUmBYl]&2"'mȏ Яo)BǰUڮ7w:Ίغ mڲݚ B[BuAhDkCH` AY.m8Cus$uۺo)CL[uAG].`eqn AYڮ*Xn [oHB= BhZF#ֵLrChO[aDFPd҆8Mm٩qEjZlL$[m,4H!Zׅ bBG"Z;o;AŬp Im7lf)m.>KCK贴݇NVmeB[z$z_̷Y~?nG =hf;]37֡ju&2s=ђn.vp Bkz$>e=zd-RH BKӣl=3uR 홖uupd>#6\qicbb4zv/Š^hi[qNm>R h=Юj"4)<(R0 B1L,R)mtp`^.C,`ꎑf M t,=v UZ֣P)Хkm/²WaM؜EE%P0[ IIHOCvvW흃c̨3))) aYBJ4Š B[5>3';n#,u"y{{4%uy8#$mHB]4l?Z X:z #'~$$E||_`1{]^%n#]/[+{vvl߁ǟ6[ z(ecӰQ3%ж +"Bih_}/a}~!?Z'.(ÂuUrz0e@5 !jvqq1}Uo>W`[Bj]3~;#...` "+BG9m=/c MX7~nFpc<ƛF8x8ѷO/$$$+y"Z^tʅ}\/ |搿kJX_M-Z%KC'Bo6mBNN{OրxԑH tc}fk/P9r7e}, N8?>W}݅39X'cSE#_/UɴQIMfj+biXa^,m 7oo,rlt Dϸ;I^ } ƾp'؂P?S5%3/QV^1`\lccؘcΜ906aÝRw&?K4MHi}umIirwᅲCQޠ HX$o>r]vcd#~:uF[=tT)/K%ێI1Ѥ*xlv4ARaE/W򮼓c9\aXC< B"&@W=SB@S|x(}O9yGՎef/~qKFֱ0VIQw~۶qyfZ;v ֮]inB61oOP(#}nZ^^ߋ۰ֶ͇Qdz}XKB "cpx7DFF˴@l:1O> 6%&&Ĕ'=C/(A%@5999Q}fd'Y EMHdvcW{3bnݶiP! M%kevbk1eϞJm[gTBX{2e2T*=,Wd!+d \iTIEʄ:İgϞRPrOOOoe˖k>w+ '0 ɢ1=ugOM6CrO<-to0_[5[D#&Coi::wz^{Bgy:rY=t00NkԤᡷ|d-yOˊc,ZX 4Ko6v&FHo4=W+)TGhsϽ(k]t66*}im2喒f7?EťGmK\q.A{3ѲeZU803fLǹ-ۧyG'KNN^g-Tk/Gw޸ګpQ]q&9زe+BXjРЧOok//߿=UĤIssf)i~i{if&ܡ8lGXscr@\1 b"""B>_h:.Dp8i׹"n+3.]Yÿ \L|<~ y{]8sP444^5ޢN_^ٌ> S}8%K|YX 2dСcNw߃z+C ưaC`i{p{yիsCi̔wCyhݺhϔYvv.9zc[ED M*ڏb)Ml&&y+7~Mn6dY`wXWS}X*'= naal[vU 3g>)-eCg̸ +VDC@KzML>>oxI b ={ ̖ɖWG}}hlk駟:m |}q#pIټ)%Wġ//ޛ>y7z\bz~'i|Mnnfo||OB_Cg&/[}B!ɢ-T}~Bd*ukd몈B:jN4ظrM3K>'!ڷo/Ts|^zU6Ƨ~*{a9#V*?[_|!j');n;w)88\zňwyļbOu .x kQ͠T [`uSC{rxMVѧ9\T$oFi36پExV,Zz]p (-,n[@*.44ϬG5~)TU붖Y? |INŋ3oCn]ePg}/C1 /||i%&F?k\xTg_-#YYM+K1cBßkssswzϓ@}2W>TYhrmx̸E!ACS,?x㙻d/Q6O0k P8ԓen(=9ohȑ#\ѢP~mJ]Xa(%(CIX7۴u>2-F|f2->vp-\ӢJEmbZԨ~p-k"SfP5j$BP opfF&BC|),).ZS95Tz?`mb: /\-D '-A돳ٜ#sp---]os7n܌s|[j/. '3.+/WkJ\)DQ?'OJ(huR5O<X>cr, ]9W ~xK|ɫ&w f9N38GJ =#ޓ&'n{^?CQLe#]m><Ma?N^{Hga1BXš ;P#V{Cpقq1wW5NZ#8"w?/Ζ^at@_0Wߐ(tja DKʹW>S꧐~[(ovƍ?XcԊ%FETby˴?[ LAPCpbэz-[l_~~sdځ֘RBuI'HXQ&l8١4 N.rYЎd s/Ɛ)ưh},F14+ٳWbu<N Rѭp{'EbIL6m\戉~` EQr 6f z6L%OhR>cpM7}8m3Toݺ 27˩So-6 SZ \^155M 7L%`wߝUZapSH1py>xGNؖ.]&{e;68[ßCP4Lh#/A↯ 1%ۚ R#%r-ji QھR4R,P{M#1¿VO~*=ZG㪩qRL`o[WSNenć_II,Ts0_wLbN}MtTaqX~]+CW_}%,Y&0&0ڎ顀uS{aE5~,p.LP{bm[.fCfV'$"+'O ޥZ4o&' Y~xfx/dVCh}}nˮzNT߯hKS7C64x:ᤈ1ylB}VsUΝ;UF *@"wG%r)H!//W 1ZڏQk^KV WP+4<VvbDw?+ :>ߴہU^=:lݟ:55~ FmaGcGɾ/#> |p<*9y؟b_tqsd jvWb/K^y x2MXFMl/$/́W.v]mFp*Vgo3$$xZJ7nsnE0P2F)h %$ /b2(,ȗQ* NLB%+rbf孉Af}\9Ee>vs굊RQ(+q/؍ &;JWЁGzn 㑚HzQOm ΈExm?Ztm{ 8~_;v Ə$Z o9?`?_p8{8m)=v ɩyE_oRd9??z|r\{i2RQ4ihhvd7Q)rp$Yp9Y؝lÄ5LcBa #mi1ijP-JP 6Ɯ\gBǢgdJ%iimNC۶(а0厪$Cͦ[s"bXmV $Y_ȌLqr3Zn8*yudo܈ˮ@jB 9[a7/BkFD"rǛ<_ܶ@ӎӈb:8e/5j!Zӏ>%&#z>?vE>_;uh!+1|p/q8)0u``7pW.p ߩ>&!۷f= ؕ 86T0u9 ` spW^h%IGm+uTY68ʶ8>쳕T̍ !PdBL^`K0lOٲ1DW<ۑ9}RBFAe>؃-brpE8^qy\m;s[]hh)|IXZN!b0t`Oi'A0ɞ}&=3Rx,ŗpyK8H2|W`UgG^$)/00o~Tؿ}}+)]ǖLضdʇR½ViL.6#2ٶ(V( o*,k^֖lT"̙Y,s@U2)xP48KOGfP؄9عKoumBM1eMx䶿cJ7<~<|]8:ROȟK#'YQ;[^}{'Ml4yߕBeTJmpH:6mWZ@$T" vUh gSX^޽ I+xCtȎBd[V 3i}vBQ(AEE㢬QYF ~;F?W(W]T(6lb3;[fr³\a Ec!yrFj.HqoڸuxL߉i<̣f3L o^6D(tWZs?ς?H1Q}̱fα.L_L%W!Zh(sQ7F!(s&Γk7QP|8P^,^aM˔8قf9jvNmUɠgdaZ rM2rA >֭fsZIKq=O| eL VSAZP4FҺ+2<L",2u!fgn @#>gNXi%daS~,n)P6P JP mes *&y\UVq'Xnwⴊ?ovxx8ƶi1HLOD0RBR,} {v9Z+C!qa&-9Q鰆=B1@ *&S^6oBqiHвE3Le[.~н,t% Ȣs3.[*^ESbRʗ}w{rO)J+M0}Fg*Ҽ-8TϮ E&焲:Vv'- zŽ8f1w @q&# iG,#XBGZVomCsZ}ebj hLKԘڀ6t3dXL*uV v,M̴ksyyeۺgJj,J 6k7A}\Z*ӷ_zqg{qsO6⋯駟˴͛7GMQ۟!9BAe}/|= o#F|%8BRxŗѮP]ߐT8֥wD >޾Oo>Q {~e:-[`pW-*駟.S'S//29FkXhKJP;coIȐ믟oquh!|crk׮׬Y38u<9BFG7K"''GM R$ QrڣSsJJYRqX 41$Y2` .)'n4ˋF]&=<'= QILLđ#H1Ƒ"LT{zP}(l/W0B(ƄuZN;x:yGgF -0l~;@6N ,kpdb{_ϵy[l]bW{_]wݎ!CWw!~(*fwA]zT?;Zn`*OrRE Zr{ *e,w`ҋѧOo9(%KCVPIsqbhL:SC΀~jb ߄cŌјuѤ"N./TQQQݻ1#T?$,\TkHMPٵkrECtcÆ\Nrr7l h1#f l.(=ú֬+"#"eEA"ŕGjKAR"WIL!eg9ܹst]KC8%ptc==SHy-zԄJј0rHT0Fʋڴ7-Wm8i0]ϼ=~D5c\xЎ)Bafs e+PNJ\0${ (6=fyR;9 6۪w'dي$kX[W}_~56n܌>]tv?qHjt,z 46RZX°<$fJx$^xfGcfPx|;6Mƃ?d 3jŭıaf _2 !#GuE0L𫯾}=)SN Ç"RE=c̘} -9220Aƍpcܸcq9S@ =X7|9xy':-XPS^,ϥpUC!Kpq{\3~ONnΝ[ LO}kWƁC a]Gv=׶¼= =6mZcРrq1g^̰sq|vj3miT-dz~sll,FТH׊@\٦[FY[=f4~yeS[81 mc=[Ż񴭺uϞi&6cƭ҆O;,ߤa _Zz>̴8spҪ;;7^}*`q8+9SSҲpa]iל&ϯ7 Q5%eˬYo˾K.| }>ܘ;yɲbOiY{W,Sg+>[S]Qerpl΀}aؿ ;xm+/lvn/o}K "rpҥ}~I k&FVv~#x|ckBԽ@ DT `#](/EKňMf [N,lb üM4uܻLg`fEE#1?h+. oP '?lPH+rL`D@eޛ M7*#ax=w VNb뮻AF4Λ2c&1*ayad'HH8W_}gu<&~7n& D'0 ڵk3<]Ɗ"=(q-]()k=2,foKp9)Gk.2ONǠnBKueni@fȎElrct=9s>۳>%LcOc<}/Hᖞn?oEo1JWbn1;mtm[Ǯ@X^\0%Fw]0_|9ٿ{GQ>&o`is!/N؞=Qr(>a>W-; ~"[#<9ERdkT8N9rF^e@[[w1~QBēO UBԼO ۖoQ 8bOO_-+6#w xw T<քjԶVr9&ӧ_/kE K*ymgM TO=ĂB?A( -ZT3V'cˡb,U <}JG}*G wȐnY:J'}-)s ܋:J84S&ҋ6`MXR!zwGߨѢ;ѺukC!EX{2?v0h_a+; mi)NO5ݧ*+}%P} :.=wGq$*jFe=+ F:VNnBކ/B8Yf'u%k8 =';q`_BSPCAU5Z[-[joٲU[BuFdʼn$__}^s[֭}ZY,4%~q]/I2Y '3g>*"Fpr~os|%kL2Y>׳g) _7%孾6Ku|'9k9vj8Zc>BPa 0#LKQ̴V`%o̺oQ;tf#"yd4^v.B\rEygYǎފr3~B{sPIc!CɈwmq}wKm9?pΡt 7nڀA *Ud@H4Gct|\9ZD8OiT4%6U'SZ3<3"ρkU~6F1|!R8v-zϔލʾ={d!c^l'B~۶m1L H֊+eA*#L,Y&ӛ9h9y} Ɂ\x}MvFnr.T(/n~A=?s 21=ºᬎsLgfo~Cvv@[}XܯǤ[Uz.\uO3⧟~ZFL7F|q`u)gH*(_zN@+˯m*m QŨ0 ޮᷧrKϘq:>k*d>1/sϕ-+[:(+:y1` &gS<V91ȎȂ=&" "ѵcWW_Nyo=a/oix̜(tTzL *| N2 R(2lï>K0>q~!7r`T)SNr-3oy՗Fho>*Ѿg>o%E]K[%O~aH' {Nvlo8({{fI!FWocS]k}%fCjY04~HIˮ{\u$;F&}fK4"EB]w?vgJOjAb.0#3S 9XVYR GNI`F SlնPѹ%^W1|9 xo;vS"*w2k֬sE8a4'ڂt #=E{P?wOڵ+zr+7ڀE *UЬ }L0ޯRa,b`%LE B,/P\\5סVKxəiN*{EuTWmNSȉ#])p;^+K^=Ťwnk)zjw~}Lb$=\K΋p!| 39-d~ /#AO5# :$gCv96\nL-BD<{vLTQ3hDt#IH6A%(+4^iY'3j,\" vt(]zo)RPad QĠ J/,*zbj `ny 1BBTfƒ>"ĩ]=i ŮqE^ig`eh|ظA};K&{ vbz]|2[6| <lQk{.*}4iuF}oN8u٫/=v*5ѭ[WvG1m"PWM~pG/MTt6AE[]#anG#_],SD?7pl}.}}`>h;wLQ<< =ikչD?Yɴ9}T#8fl'+6jgd4  vر\ge*MPm@ݠ*2Ȋ>먜Td ߲Vr Yh,0Uy2n`g =#18(8sݮ^tg*sy'&et(~=e2Õ zeȢ87Wc_\~Wn>LGA'8]tR7O9c zY/J? 1ro0%In!i^i~,믠*o\C g8[w7ł%[bS  AsLө&Kr"ݼϹ\ TXx7\EhY̜#hK#| {Yl_$믿q:mK.h8y^vyϐ|PԼ袩i ܌b톧Ys1תUeB uh*(Xz-7}="曯Iǟ>/]F"s!t,>"DՖ:.W.S`_|DFQaN*@ս(M*^3W_'ǮoX\ϿVqeM_==aS&L/Ǩ,y:FD0@biWV頠}sL7Tw~~wWpE$61|]*#dwPÕ~pqA!߶c+%?|,ʻW58_0ЃkoBѹ{PU8`1eωHu(T6poL3o9 ߑ).l!l,=sYb}$N(YD+s5!vt$|=g/ R`zpLYIJFT(*UL&z}e 2"LJa*+\^39,ڌb.&ڍZ>役Dg8SP rL݊?Id*WD/TdGG]S1b@W<\<<5;tm[,:ryuI'zg1a)}_uѥm .KqܻbPaߙ'!qF1pWFGfuB\8kQvP:JPQ(M7nQ&I!R?>uor3suu?)DFK2gU _5Q 0v>kr ؟g>}SeQʺeUw8DD"-YyEhӲa9\T Q)C0aD_[;EcD]sոS.Xv3Cu~L,J+6\mgDK)oHiTl8-xlMST(ՋTBÆ&oHqW>}X˧8Krwx-k+Aq]O `o+) Haw.ֽ%nw!SJlaft wkKOQn&,ҁ4FVczs}Vm= >0 ɸmѩc{ÈNT^izbخ%XwuFf06+zؿ/:vS׊ÓcD"ިEzF(AEQvdXEC\~'be28B5uu{2RnxIѧܔ?Tv>7aR4 WqքXgǔM t-qۿę ČsFn6ylik| 6kRUIʫu1%<؄/EsկG4ޏQX8J^cP菠so2buY)GTb([WQ{q&GPelSs^R_X=Ei Ύҭu&16c=t?M&ق?7BBB\[5֭0rXvQp⣏>i >)U>FpW=j vm,k1%'3_Y?#=XET}Z{̚B'ǏА`aTWSޭ0bHj]RQzBݳֱ}Ga¡Ψ7 .@ ]pLߑjOWe b@e+ Û&Xr6&bJPh 4Gu>.zDS&۶*lmt /<:77oBqq1Z(n۶-.86%"w3.[?n^){8oDL< sd̼L:X{wi A3{r}s)7R`A )7+kӃ,n ]@QltUl]!-- |TB\1J ñ`~,XuÓ#y|zL;(\z\xU8;.49> K6%؂?:FAQ ^ZL2ƌR)_8_Fࢿw+a75,, `5ql([o(APԭ;8*CaV2QhT?ۭn/qrYx`[h<bc84U2JUc\DGGc|Pw̳m/'V&aq9x0{ؾ}ڷoG5"o} ##re\qߋQTT[oF޽^fZMc9~ .W]u.y?( _~l%Ou6mpAؘ)Vs,DZCH>oa6n,ҫ4MLs<}d1|]mjUPN-ZT[Gu7ۧ'`, PSSWeM%~Tˮrq\u4ƹ6|KlesI}Ƹ=0+!A8aozRрO/CU(cѧ|<z5Gt68'FRnnEhˢW/cQ1e m5ͯ{w{FݱbJ>#7AaA>ŇyhC}͆m۶'/u~7bpQc w/AXs0L"3g>* 2/^s R/N> }t҉믿W * 9EěSb{+_''>5+<}D6Fj/7MOm{l([o(AXy}=kV>J2Q,n1q2b[I}s,= bI<lMڇwϻ_*sMJw(M?6!;'OeÄ7cn">X3^,S~&'LCג#&Dx Vٿ>$2u{"hիWOt$ 55Ur$ 8 +}aY\m=ԢqdwM|~ban)PЯȣaL_wޅn'L'uŘV.13)hpb4 1{ ߓ*hժ v祠Bpy?BQSMo ' ؐ\)yv|.:?퀶-"QPlX~/Z )rڂeBP\shT)_WzCƨ'܄QW!]OE198;hhSueʡMbtnn1 ٞXWLؙQ pxt{2$olF2v@j^ \3tr.]/{ox[U Ebuct%fO}P-.g?.|ߊ|^LN?7ξ?o]&IɞCs?\ Nw>#ea/텷|wC QN9>w? OŦfC [ڲ͡?\z>yIw|1i[C]tJ$SyDFDEE}oqZz9󲖋FaZV>+BCaCpеU}o ޛ? CC?m蛊i> M}抴 zU^k),g)qo Li;2k Ć+[W*B Flf#*f0j/#f'Ju J=iٺx; _ޟ>N? |!2l21%)t&ߋy^I!Z7kO/zv[nc"/xH !+ mZbG~װlKǂ^A][&ˣr_"/ĖQ8Яen ƌq;~] ψ5}vIǣي| tSp5t%!0nXFyveQ!&e D \C Jp$9ݻ#44Z0-H.XYg_=[$3{T>ƍB(ކZB`9f?E7{>plǜ ].1mYג?*o^D8+R^k&IE F~dRc5A>X.sC(0=pb"v%cGI22/&[ZX[~Mai' zF+ ӊ.h,JaӿSODuUu~e,h#4#F{^ Gzd˸dQZH:C>߬Y$e:뿜{<?\ŇiI|O:Ǐy~qԋZι_`vDO2Uf:#?`U/HX?nbwĢ˶&d.) ùJ_v_Uו+[WT%T3GMGak i4{?T 1Utb&n2b\9NX)g 7.Eo)>5)eC * ~aG,&J7"bqn>˕1FI,(;B᪯y#:1 KP˜l\S/)? ofe_?#Dg1;㇋׎*>[⬏[?'="}F6:#'\-_۫u'%eV1PLsf3TP-Vx (Fˠz ->OOڵkm䒺crr+ icDzP+GLLLhmV~`!(*D7(}eϥU Ǵ5ku nj`@xU/'m}K.K*۷f{!&Q, CCa=e$v}FWe~ϱ=7VۂJ7KF`Z5,(o _nM+GPtXՊ9~Ko8{rɴR%)L5nI(XA}1m6,,TN(]KEW([JPg빯)2تJBaG0߲ep GxNy ,ފZVr,YGqȜ -|hٲɖB0O&B S"ms\ڷsVv#S+vW `_@يV 6ahսq )=Tկ*2eG|BX}}1?GٺBC *>_BJ}sP np nakaNQj7+&)qC$Fc WJIME݆H))o'(qE(Sm$}NBa娴4ס#H, H*BXA(r`>$T'L6bGg1.1С];am8j]bˣGE݁}W^e #RǨkxk#Yp8Eiq^%nݺ1g:B,!Pn$@)xnZn@^^-|XetR&88DlTh4oVLZ-&Pԗ~"Lu_l]QXIDXY%zy#j;ZrW_j Z,r=V(ue 7zo#:th\)@ _TXo_YHٳ!S;o4jA,,Ҙl/5PS4dbc51Rh,4~]hj؟5bcXX#gJP(|i~9h&RLCuDazeƈOe1(5baHV ͛GAP/l1f}KcubED%(_W(?FP!Z!TleCP-%HaZczum]$ կ+N^6YSyjj7+'''#8؂(6viQTT$V+)q[Gb}cMݮs+[W(je E@ٺB.;oL4Y_J !lBY!6R9 ESCߠ!JpFhzoul]h([W(?5i獅&QVI?G>+Տ6̏oF[:UP+Me E㧦1$jhH"WkFY:ըAl+j+[W(e E@ٺB ;o4 AEHd+ՏQmtl][+Me E6켡Ҥbt{~ EmYbe E@ٺB4PP4~j"MNPДngìP(jce Eݣl]h([W(?a &+A>BQԤ)[W(u쮉 *BYjۓl]+Me EGEWU!+P+uil]hԅw1hRk E(PP>uSvPh~i5 &7>n=U(dz xPP떛b1\([W(je E@ٺB+;oH49Aų...*[XXA&PAvX"i!!!a֨-*[W(uSv1ߤ{7n-tn!b [⒕h 1뢢"ǎp(|iR&i+e E@ٺBN; BBLjLXlVuCw㾤IXۜ<~nb@[M6iUul]h([W(?a F UqGf BDDD<}nr3+ e E@ٺB7ugC\PPp+(m6/t+[W(&uSQ;o,4ZAE~II||KBQl,e(+[W(6u7&D UQP( ,m6uim]_/hS(NT[?;ol4njBhxviZcl<)m=PTMMd5i@1­_fK9g@K0k^^UUhJ4D[~ZBC@l:ESeƆ7;oFl* 3>Q})Bcڂ__mݛ}ovHCQhlg[eUh(W4tyc *F^/թȩ7m80N@ߗ]+QEة϶^QqU( huTvL)?l^P ZP) -BH[U4V47m ivkXzES>ze'T6vjd:A*"x+W4dycG%6Km㒒$l^w‘B,[E̥} rs[*2yjhBزtpIXnij&heMK_rzˏ[ټBQi)?6X0AJuEz$b/BhAb`佋5DGGHEm=оdL\y-k6{~POL1w't磸X} *S,ܥgMl\s9^ߗj9jO>Z="[\tPߩH,/q(Êȣ?`u|:WWUJP*sVXXm۷cadcyqՕWo>6Y`K{N GKN 1rpK9.kfFʖhӮn'8Y *>֮]ѣG[fSx?1mݺ 7t'ŋߓ=&Z:D+//$`uN`F^HG.NȉMb#ܕAb 0[Z\+U_$>FI34pwޔOҬYG655U;H8&ZH'j 6_[޻w/yMzIe9roЩSGW(<0|X H1nCh(A TFHgCJ{eRHYGs r[~>qWbCF][ëMiеy9I;3:BٹJ .*HAEZ"aEuU_&O;wB>cNb7A4h ?УRL1b8Gжmvڍ{o{ EuSI7:A8yXްy`I! fl*i-p|k FH©-֩Pg__kEQcE vEedd 77!,3D31o/;yi!ұ*Ʃhٲ+RW_S{&m02@ }[TJP, 7ԜXa\|H;.m : mkqso""}YƂ^ R[႞7.jy͚i!9(SN9 UE**giIހN1;;d'1[ɮe( m(ߋء]%NA&tի !~qzx-BQwk} XI]Ca0_lAG0A[׌q }uiAza'Y}4};oJ1 -UB#P;X 0P}܅o硣4F)EEE;Vb]bj]*m/󐙙%"z2 s)g=qSyYocܣGw\}88;>SߟV8cp׸Ҁ?+ݻwi?P=a<D(iJPѰ` >7?KS/:Dis^v҆8p 1^;W罋ggM^: Qp L> 6Ǣ@7EPdL۴Qa%`ĬQ~jHݳ 1Z3' 2))شi3$H)JٲeeD&h})M,g{E%[/Dua [q}G$:w('^u1jӦ  STb*)X>Fv?33b}5^$lty(Yph0:>*/_!qbٲxwHtNb 2d0 \x6Oet…ByW~G<3} 㤨2gΗؽ{7|5Y׆ڴt=[C52%;"߬CvL>[LM߭ÅTT*HE‚ _yf|0CĎ=-FPHOb*m":U9C[t@S[ɽe||՘oNN^4 *K.q?}uXH˖-PN8k>JoԒ( |<&KQ Cbܘ t^ڞdR}GJ]jPRP/DN<ZDvv&~m*S֦0Cgo:#f|Ç_UZm]1ǻ_Kʊ=^)#џ2/RJG *"b XHGٜ܈ANY+}9ɰDl6C#~µh7jlٶ:+&N-g q0wArgțE7RN. ㎕O> I&L/iBAk("4<YC?H!p݅@Naɴ * X_p["a@7nSRRκ l16sI70c[Q!qS| o/D?{zz:^{M1GF^{:jPiӦ-СCpMe&Iջマ￟+?'$&l!O1oz9b\}M7 H8ᄓѼy^~'-hh(AxKr@/AfPt8y j9X]{ծv%S qpSJe{8p ~ggɜsO;5j`q;O>JD*+݇051)9oBZG`+ُA((3 GE,2Cmq0!KumTp˯0AUҷoy;v1CQxPc(rEB tTx羪G> |yZ|MغgDoЉ|Jbmg::6omB;qc Mc֬ʭ2(W\-ڟBs:ԦMkWaˆ;ˢTn-=SZ`LPY\zÁ" M+6JP o7SH@bB|~g%?M3IHDm'YV"yݷH߾GHg-k3)Naz_&Jr YNnjjuy|Q"Sxmo\";K`@';YnψWqf3rȢx8Ӕp/BEk3(fj m EIk;#˶d!Z{rE"^Y32E\aH2>%fQ@wtU #A(P}W{{|Qߟ-/]t/7|'pu2G zyMxarv<F#X)pL_˺5LqP /AEmZZ RN)}$w~kŗc@Laq6)##B?#H:R2省$"ٌ0`-H\}}>lB4ф|;-''r.EF *U v5qL,!l:K )}+ u\=;CڬzBz WuK,۠)~X̹`:&i_'nkFJ̥ԐKM ECdsv纽-[ )IxDc!,bKOAE-ϒ#SBv&매gg2b X,b`YlAQIb@%I{"{m/}p_w^b߽b"53f܊+W >C› #Ʀ`8JP߰?[)jP?1N)egeɚ)$P1S7̈́c]_jm9K,MާA(ُ?hS&eMI& miJF1]sRDS{QlFpXyKoH;Ҏ]Խ`:`KASTbUm #,f[JK7b;|LxDFkA~md} ߛ!m`S@?} IM@HXBCd{dB*~\cC,ĕ$=DBW_l88J|0Z6ag}>P8dI'ҭ8BQQy CZ$#S꣘k۔*5_ m=9mwĶOkOg `iM_a8!lz.*W!YF@&hLIޒfm .P=8 '҉{d2p!)*z =x U˽>ϵf 6c͢.ei>h_VňkޏcCݖX>?*MLah@bHk/ ߿Le[9bpsjj@fW W^510 Sj5Vkb`DtJec*DFkעj%Yό&0rEVFӧOo!ļ_0Ӧ]'7=FqrIsu(Z.,Zm(ĔA*] %T BC,%iiաRV7E.'Y;#u/h5Tbr;:)77-wZ]+b˨F\zr@e~6,0Kbɒ,f]t6\*Y +kXM^ TT-'~AiF$ND ̰ 6i"u0 Iֵ/  '9:E*5r^Ƕ\|o[ԑzkS|儇^d?粧˖-a%{z)|ѧR|aͨ^"a=w%!ڮuQ(~Bll+9xɧѫW/1%djPu:X,$R)9>Y93V֛6U(QFT٭BT#=v.!]G@pxܒmx#'3T*<ްquvu6 M` ,@uUbt8眳 U(O?U.-EK(rM'6@7}x?;;Er)PSbwإ)8KO-faLϐ'zW@IVv}x5pl@G.>.Lk֖'>C޽>omDM?,-"tTy}wߝ%<B!nɭΐmye*I'MKY^|9D\N;nţDnnj 5VhΕ8hURe$/v3UhCk\zۭBЩ [fs$60?6fɸg\gKFmDCk/X+ˠՀ{ǤkPPcԅ3<%94:9}yOe%#sF)Bx8vn1?8o΅-td g W jzW(#;' #n>h-l]9tȅR<\1kVx`: yZK#B\)?}*^T1G6H؋=&q\>&ƯG۶dxXy+ T튑& ^Z@, U~X`F>U~dx_P;vF.dgT'6}o0Lmg2jHlOK0s擘7o\5i)))XxR9唓QQcIVVLr>W݆={d*BAfN}o,,eNc4+P(%TzKz.( AriԵCBZCaqme8'ߺZC[1rBF5Bx %Gn2ŇuQJ\2X BĭC -v1@`W/#XA69cHoRj^¯DbXN>;hBIAvGgy\_$?KYHYz}G~Eϕ"5 pfZ}F΋NѧحHټieۑtf~?$c2V$dӨ`]V_~QrW)ΕBQ(APP4p XpF ր3(؟z 7\.YPTI)gߊ V/ :oN1UxX,AbQ*a(LُD9ЖU<Ƃ{A,-n+&J9{_ iʹvXEnA^ W3\@^q3n4Q*YSBF)둕"T)^lbJNsVXNV!r#+- -Z92d&4!JLTϪ Eݠ*BsAc}#ԟ2%f,-[y0ޗ,H;|0y o(9d.m1W$t"`!f1rU+A a,aKǡ6h׹~z ?*P_kkaVC'=[᱘5 =Z І_Avq+3'YPÛ Pc){ֺHO:$DS|QR\N=QTI޶qW(:EH-~&zԸ@;REE撻]IRӆI1GK?*0x `JPQ(j`8ڼhyD2̭:#ZZ"dвM[ddfuH܁ٿ2m2HήKV M^XϬ0!n棶gl9q}ŗ n9YKOkFAEM e9B)EBK:][xЯIڭsծ;9wB8(,*,\j|P%JPjzXQ[׮!kHJ4 &X|*-`7;Jz9I]kzoZ@PT/F^oFd&@P.,g[%{&JcG1|EĹYykYrQxxzuP^b +f0֡+]؂ÂR;.Vqa:؄[1HڶFz|]O-(#v$[AkiҲؐ[dũݢԞXzq/\ԯO1*v6x?~}} Ec7ΥV %%(+r{wnAU9x.Rl-HvHHюy\]R 0Oxî9IQ~6Fh"f_w?>g^qǢ1}^o>|D>k{qsP/TOac,L;B۳r?(-BCsh$Q!k|S } Ҫ~(޳Rm"T;]SPqEq jXú%gʔx7l?8nmݺMBN:ĀEo-܎;vK/F>?+VB{"ѣGU MtADnUU8&M쀓G#4vSlCfaxs%?cllsr(0"A)GsQާ?ڷo殈p YY8rl G }뵩G׾_Xb&0O?s=s?Njp)omU:\=cP4~R ҥ3b[Bngb4A-ZğtGil== =O,߻^6(HԀJ <=N/B`J3MNF@ڗ)R[R*S D;Yh9r8~ma9AC4h`@˯i|G=՘?6ɴrV>5EyhUd؎0S$,Z|ر*XhȨ-![,HTU$?uLs}d 6p*kV.^n]]HX-*k{JKUv[t 2D?K.޽н{7~~/qc→XB޽PT)H$DWCř~} يYSpraiu҆T-$=Щc'l٢B: ;pw`߾x1vѓ ^ypN; NRRRSSΐa^x)[`8i{?܋XBLzLrpsy=WHm3gΗ2u1_ȊsFh>ex"mcv)AQ*a\+:{I'M*)#Xeܟo,71psHq-w%3gy^2'NG}:.&M:wy[Dhڴl֯߀n!Ӡ?~ f|R^7znW^_wlk4k2E8wq&'tXd|~>ڨ}|ᙼ@^Wc@oT3eggmYV {t[lv9O1pn g}=Ez=.>Hz\*sMl Umد=^=ǾkB1'ĉ]iS~S~by(Kq;v7N?/^;B+.*Jد )7N=^3}>#nz)A=997F?g}<>'swkoϟyXfso}*U'{y.COߙַ*\};Fk~L]&L(?vo^FyE Mxh@~p aI쥛L|pSQ s(_{[mInưth3|nΜOOɰ믟L&W_}:K. T;X4k ő#ka;V4OǟK/v,5\~ղӸkOO|;MTw?p OY݅m#l\/S|A!՗_~?@z띆b)aMYEヌdzE?X>>Sd4%swud$_7>~]|BdM\l46&9'Jb*(A`|tZ7ln:*?ܘѳݙ꼞8gcf RM~F/|w짌 d7e(s3CA}Ws|\APL ;luS@qE}=qHt )1p<ɔy滥0a\_}Fjj߅SEJ'tjpM2gwg $u]wbbb1O?W>zÇH/5jGpus(@W;1V1Oc^?3 >;s[E2uJ$K(3fĈ{B{)dI:Jkd)ػA8\omx 2XLNSk/b!..Ja|C[u3%pk҄ e݈|Dxe_(p?r\)v>mbqܗ^z}*EE F-IDh)ЙÙSz|5a-LZOiqZ28~=RdڏC~k3y3A8I'#hs0a_deehTڀȘ￟+ӋNzGm>Zl)9Q|X`!iK<_~|gr0o?ś~mڴqubB{=,Fgaun0Wxs\}Wۧm'Onv">WTnzt i-EчP`؄._rVqdߴŸ~>>}svֳ׬KCX!0q#A*;X<:>F4i ٽf-WGu@T-;Ga0DizyܯC3=?qLǧot•LIf>7Ʋeq( 7 !~[{ rn߿_Fp૥ aÀ)" ͝&j0ܻ+Dؚ=/1ŒEf[[p趸zHk|d<XB`b{Q~_;9Ja\*r2ᇟx.WF9qrÉkJ &O9L1Q{5xW_Io6a:?N`Kq&1Nz~L83ez?C)zgxO>#𚮹*QHg`H?ۍ~'Qt%tadCGA͙cК:i?~}k3)z_)$&!qsOe]HXc`߀oQQZ_Mzx1?7okn_a}]vQJ5k#U;זw?˃{J/om[V)?+1ew V~}d]&]lY휓#83o 6NIرLqa:C _ƨ2bFZZ,}_~A Ģ}}9CMVx揖Qbx ~ߏ.MΞ{,߁c=c)Zn&c} 0Cv 3EqaL`륗^$#`(ΰ~ڹ,)t2jjF14M+Me)>&;RP-ʊӚLev:eqZL@^yFU WBh\nݺ܊O@6f:}rsX*"Ї_ndd`okM[:Wr`Hgzc Ajuoe,DWߔR\/>HvLzY䝂 '"`]vV8Q`GIav[q',s|%S4msl؆7E$O%ZNJ9G錬BLLMo} P9"uI&ޣSLjQcPP4X]9"|9w.Y؆zGm 1eG6PT'^~¶. #sbԽ&r\ #)Sxy'h]Dz(A x +T 8 !bq^^)KvYZ*h%iBcϕč5-$>zkc\D6:06n,kBL28g8.jmrI+KIƟ'Ei=EMkaH :,ԥQ2Žb=pPQ/\j.c3`^էMp2:i{ae2,TH!0\DZ9z7TAWDHLFExCI]!a,,Γ4esI^H3'_ Kj <'OjKTavYEhüb:1D X0 5\9ѴYzg̘.ũ_~'S8`K/+pPg=_7/nnEI9uc ;m"$8Y ƿ?g6GOE1EɌ`a 5m7^ߟ-Ϳ1nulsX@!)l!gGXh^]Q!܉%y^,ܗ"fǯW@V_;vF/+bnP0}a"DΘ2k6XF 

bPu;ỵΔed\RR?Ge1(:aժ2r\?vf>csʹ~vm g j /;v{e|3[]_QJ5Ԍ>8PZ zTLcelv#É5l'ـj\}†59sz^~ːcNn/_QZ6^@M*/Tͷ\"#ccFoݭ[W 0y#-0Ht܉ ^`Ոe"4u=AK$!AV*Dpk["PdY;FvCFhwD Dc9%@~"1 {WRSpA-BNoLkJk=ꋲ"C=*]Sz{͖"'ےqr=!3u8q7Nָ4bIUq{]x$\.7 R/ݻ[|am-77j{c+6Ywp1K!3|Vٛ'&g=[`pl ls _faAha6ᷫstv$y{lXS}Ƹͅ^*~O/N.Yn-C{cի~b &mQDW*LX = R'_We)#Ehcz Ñu SY#~F-QMq㹽} q*ڀQ^}6GQ5L }/9g^h9Fx\B,8}>}\ i̘bz(0/L˥Vj[0"5(>ZӁU^{ NѹB{x.:/|`c+JP&`~R!,ܹU+n8{)$ ͫ;K6LN~ Y-&!RxXKi0$J+*ҢL,HA!zTeGi$zxƞ&70c DV?; Nc5Uc&S4q"t6eSt@zP[va 'bm5<(qzѸh8}D\1JhQ}PfɶNqe!Kl)Ĕt[@fEq0ϯ<@ ͐]d]r%fYV c~@op.‚M;lvoa xfe`;ȕz(2I_uڵ+s \ъvQGՅH:>oT6?qnݺ>}_c9x="٢/GtiA )}8 9֤8"nm=i߁7{iHݻQvk幵_ ' ?go[_dԟ2ZT@75LQ )8eDF2>b4t"ۮlaT>Mxw=?5! 0-[׮غcTX a+)'BBan{v)NQXhlZ/;^aprˁ @OrEgn6=U )-,III j<0j:=XLaM#rЭ[W k|祗7Ah+S‰'1 SR^+@tUcJpC @9ܭRyn,PaZO?7 {f m(keHbV? kGieY!bకN` ˻`xC/A8{Ix gj.GSAAf!#=')I'1(;Xb_~-sӠ('=;@&l+Bm @CF .m T)1lK{H3khJ{dyLRZ'K.Peet:ߦ7uL먰+ N=\U~a3ЉqES.,S3hPp;MeQ%*=%(rF؄C*k TtбFVzGn¢[UoEӧV9kd[ .|&_B *ě‰c>}if$%Ү&W08'YbۡTPpdqd\5=O˂+0TmѢ2$'+PF*Fĕ*~pjECɜwoQvM}۷EV2qrU9Bevg`ptj^@()RIkڶ7U}=蠘5mH=SS] 0qq}\}x[ٰ@zx7fM~əje:Lf RWzh#DGN2mު"[EHx3y|Q~6ӓP~vqI7Vd)*m"s>;N:^) 2dSt7+)&'p3n-tnt0EqqJZ) g+s~}J;byeyhN֗ć.EEqѧ﹕_Gɑxb,.8*^~WJ~)`4t]wt!P`@oآE ̙\g9ST.KB҄u_)| X2^R(N2kE N)xЫɍ+_Q q$$"`1跉kgzPA3/Ml$.~.(Qyb?2ee3SBB-ٽ%(+ejsotZ&ȆwNKUڟUoETh|^POpx@QWTg޹ysZi;yuwgGʎU>i>}Fj$ibu;eb>#mV!8S]+1*;W7o2$$FeDl,&c-l]9tCtjDF?##bRi:Fi7p['(ֹO#;7 mMHvRRS('SSbJ—pb|y&Xl¹Îv(v#ڷsvwawʠLӑ1g8`v._AdEb' 7X5<ʎN/[,:̹`VACŹc"ѹG_qE==ԣwq$4j_.J!*$p/δh!P1Fbtp l]a 92<&AA)?1t`{"uZf$![!0 )b)=5֧P(iUZm);~ -m]4jSZn) e-H[t#" 7/W,P4\{ņ` "$HMBBzdf7$/afgfgn{w93KYȘK&-9JP-9KRŏIpARU=-loaB0k%-+`,VKvQJExDp#Z rrA}JhoQQs̄ݕD&% 0d :: $%g?R` /ݕr@=G6-Νb&pRQV~ sd;E'd;i*!8ķ̞"4<[y/TⴣZp;|K_kGj7B9ٞ^T."Yy[f b3H{TPR Ͼ$ղsONM$|C sSXqHo͖9en!9L?2;YGUT+`Ok.k?Sn>3:Z=`JѣGZBKUorqQJWB[zRYÛ}:{a}0맳OӝulkoNSԶގ2r䢿PS9>3~C +Gv$;x}cH{m7;˺c*,Ƌڜ^*uBحP(]l;۱/3'Rj|x3ȣFydwuYض O^**S歡vF[X(PRb3wXo3QkhvٝDٛu}k;w~x;\={vӶm-u1-;9i0dq pKTx*aNRm֊?k.NK[e׮tWuNL۱cZ>ڰa#͜9@l/܇ζ㏏R'L,(66ĂuR"Kf.wKPmz7t<]YN}I%{ (+-* 򩫫{6Pz+KE9x#xTXIL Ϭa\$g%oj:ɩT԰v.+kVRnjmY{]v<ͽ^`-)x{)}X3C҄zI;%xxe;vQyn {M[9VRR",++[{UxUZZJyuV)*9X~h5@ DC>?Rϻ̛-)w_-05K?IcΣfmW]ٷm!dPmMk!b*[2ʧ~NwSڴQhΜ<Æ Kzt҉4h@p]_k/n/5✚"1ųXQU@ (|} E~?$Qpvi6_!?G޶/!lD[WFov=tЮoC%c5,˞/U,8p/LI>e}jH8eߙl\۩c{6KT<\rH1rъ?8P=g9^{ 9'_.==,xƎ=[')عsw)Sgq3裏m|by_? .Q 7t(:3d9}QTTD˗@\seN;1b8m0"}H?cy^˻xwteWrTQQ!D0y^Oee%{؈̙7Q+3EP!`r2܉lYUN{ -\д%uLQ /6чIw(J-I|w$\F5UoZPf1zv辰/@w}1bAEkU-u=n9l˯m~>Ï^e/s&2O?D;?Hn/?l{}g}"FK8A~&*m`JOϐBGwR}7Q'6^D/֎ cGΓ\>U3N$g^hʆaco;RϿltއ~,ą {/|y}v?!H>Y<뮻6m]~/g?'8IX=7,YJ,dlÆ%d4!HaqO>ktްalj!e&L8W8rN:Nb1v<_*K\ws#.]: RQ.@C=m Sb0MT,5!pB1K&jR~Wd{l%R*,pO%꺿OrvUI|8˛A )c]tx{m'1Sh4zOvr&fEZQG>M=ȎWK3.c=fv/V)z٩n[5k|,+"A(upNѦK/V3}Y\pqV{y2}Tfsn@Lt&NLMۗ\ƌ9ƍ;@lo׼oqV5Gy[R}}2B~~)}v1x;\k{r%$$szA>Aa]1MBJ~Js~^ mݻz>M{gsՔf ,TНDXy0aK'1 졡Avj=mAGShݕMoCbqy?&kLZC7e+̃T$?:vSN{|c@햿{d{bܹ)kYXaAE{hw8p o:gS9dm I]GI !ݑNiQQn&@g}Z&^!C(=k_@v&ૃ?#"ӧMιiֳPqI 9wmΦ{IZmR՟Z 1sEN_WQ̫Yq.K.Xfkv4$ܩXkN*sG_rkGxiӮ: nf"G#^,Ĭ\c8>sW^ٳN8y.K^Trr_j?5UkTXDˑC%ٳ'=Ӟi6#f ~p%ASAL2d8d6"n2Em u$o>Q7ZJgͤ@l.*KhGѩ=zYޡouIHCq?+^NT&cr.U.3G/_Θ NY/y.N]p7UД2z| R}!:`zbun당?l^f15ǝIBOІNEvI*W 1LYV_(- .Cӏ?$U2w֬givC2T8W4i| Z`m~svJM1 ]dwE ŴMBXa{ر GSDkJ!Fy[ydco;&$ҡ&m;6m E>:u*襢*>͸+(s.=2єu %OIWNўDd=f(_^+ߤogI[ʢɓ&y+CGb`w^v֛a? *< 1:2aO#slVz VH8p*NL˞*:~.M2Qp便eOfra/,4MpoooSF?%a""Q"C_G$ tQkkbEc܂.iU h'~8CX$Ozq[!Ioj*!unA:z&FwxSOg[~z6љISZNx.=]Z'Ovd?pS):B:Ыy_׌:;%Cnϝp\WVӶ=E aՎM > oڰs_̡{G]KlX*Vz${X-t YN=s e-YJl)~T*ʕM'o)erg_(-`i e8 {2y54z_|*- pߋz9w_z 5+k|zM]|:ÞOK aDTr\o,N4{hܞBK=L>/rfϞBڽP5kYMĔ{|ehѮ@Pi"TxΥԬY| DT#زRzXTp'7G=U=x.xs>ӧӘ3FX,ܹx{+.#JWC<wǶmdX=|3r˿s=>&N<|i8r8{{-'+c7e]_?JKK.]&aaE&tܙbb a{Is 6YgzB pYRviS$[u<) YZ^h''vw$i"Y{\SmIAED&e\+ו}uڽ-pgQ&|kfяWUD,+e ϕgv7v*Ϙ*O6.#Qݧ]EM%ݖB| =*+M7}Cy-:G<N.jQ%]cW#>3ĈX6(+ީH94&%ETuРAԩS.nғn4i4ĞGwNc]Laix=Ȝ[lU/7p|橛9laϗw}E%7,̘݄ t|E=~Wڲ10߫rYZ͂Gzzfv=чk3qOiA2GZ$@v  W3Dץ ͙lQ/PC﫜v59wϛ@W\~+7BeV⢋./.lh=u^fΜ;Dѿw$wqr1g?K34ʾ;0+/OEoQ.f'wI?cE<385DNJ+&lĉg+ϵhs*%<fZ h+ٵ|_,qHz6xX"93Ϩ6GQѡpQhO:otcuu8vh4q)Tf~mF_C61b(>x/j舮U|5+FKv7ҭk<#Nx-j͎)75[)totɗRFR=[iL6Uq)1}{$v[ ~n=}jZTב'/-/X(^R&N# 4N{]b/kJ.fj:u]w4Ͼ_塢\f %+8 }̼V*s+W !NlrXdZv:*"Q<ԩL2TPXHt%>N>}cefvk&?A{`a3f,H ).MTJ&˂[^m'/ s>&2rîۦs<0ü降96YXjKR]ZJU׉eބе=$cO&i+seq5`\9ecU}493ޡekk>>-zhGq _?HwpChK1 ~[BgͻVM^xdn`t{tNω0[iXt1gӳYvv Nh9},hp z ݰ~u }kO1۲U[Si:AÓ+hȐԿrFEu{A9O{2#Ayr_N=ia'11 /"mJۭ<-=&6 eO\W*v7cxL.J\gV[ Y 64]=$PgpyhŊhbDcƜ.󹅛 ·*C8X_ 0ma@NƱ!>ڴ LN8!?YONN.8duE8]1s9۩݋ý8uK7K(쵯og=K,CSN:iKh4S#Y<TuccqBoXr9Rmz&õ&^5Mt/q[1nwhA˘H *u./IgnMd Lk˴w^xvMۋʨ@{Dtꜚq-euQV|=un9;azNl8!͗mm"rYx7k)2?[RPWH *hC9EPAO1s-db6?܌9shcKrbw7D ȣ3cum3xh\&!5Pey #7u]~1{ U˝L R N1׹TXW.]M|mƬf}͕ kjjeN&&C0dt4e k7Àxa'~@߶KJI옧m|q~ء(WdQAr]T1 oCvr?gio1z{ڬ|e&DQC&w>KskNVsD`c!!}dZUZ`yC)B/vS^Ii#UOpVL1_EZꬄ0DͶ\2{Z6<m>x}v Oe!%R`d_NyQS'Y"DZ9;5w]vhRZ=hv( D ٶyѿ4>ۨ臬nTpP%y Wyu?C9OS XtLH k|PSt,]v2 wJ9?:\_m7ˬMޡ`N0?{cĘ 6}PѶ}AhJKv4gVI+c*~M=xi~jE) _YWp"\_Ar`/ VރNKz0L0+[@Bbk hAShmUPc$+_ z-npFTcH Bsz{{ӆ+]1bXup>Ak4ykM *XprR:_X " 3FjCp[R P;`C@,-[o f\cf#qZf7MS6Bᄯ<ՙ՚L-IP@[Np0M@dBu%iN[@ k^fbjᔥВkm8j4(9!gLM I@E llz[%8C*ʉz:ѴH-m2ֈe[gwر/e T6 Vdm6+0) zX+6˶6L&[tMbmWN_X9l=R i-.r`:y[ *(!!QDR56˶e3jtb&h {fG"QJvVhs+&Cj b'UY]U;ۙi%KnMiQb@v")-oq$G.SRRTUUI[MNNE$m]H$kILK:yh6±@TT)VUVd;(##+\SY :ĚlO(vh*r!d]^^FUM hYꩤX Xzl@@'vi^n@\PP@ VJOO'nat:T[[+V-S<2nc뉉6qm:llO-Ѧ=T*d}+Bp8O .yZ֞CX@_6!ﳸ+dJlz_1l@@'vVhIi?:lW0Gus t]:llO-.r?1ɕ!+_ZJP*dc% [偭>i;o AEat 0Ǭ5Gmz:- llOsyk] *mLxv{!3G"hhD[#NPQ([m+3 zUaa等v+0FA>@Mۃ;hhڹ0桹+a:-llDo lllh큠4x"TB @DJP,@h DDvd7w54H@T@,Q"\+}-Eh%uB25MPqqb Z`tu ௠N>4@EHDBPq/θ8K DQdQ%A8PqJ:62n A󻆪wxKP 5bXKA|=DT̴ =aY % ]~KAe?@qkFE0ZFPX}-/^dڵ@á|^;%}9T-&k}}VyTu{I-,,Wff {SNJ%).2  [%Y~|Cd?.<4Xk5ԐVI f H Ab /:33NV LX[`AlVSC2Z(|+:OX#3aEMMlX1`W ~j % MkOT̄#!{2qN8^*f!?չ#IDATx%YYTݜ:6/l` D$('"UT %]vqv'9ufkouxB!B!B)~B!B!HE!B!B-!B!BȢ!B!BY,q!B!B/l,`pD1B!B!dᲠĮ"$Q"B!BY|̻5ߢtOB!B!dp5o"| F%ΟB!B!,EfZt/q3ע1 !B!B`¼e.E#cӧ,!B!BYiLβ3\EXS=4B!B!2"bMdf#bXoB!B!ən,ZQf[EȪEܢ!B!B2Tf.4m:"ׅB!B!ɩ%^օ\"p͆(4kNB!B!1j o_9#̴4UR.c@!B!Bưkw1V-bW/?f N%nU7Sma:!B!Bc:[Tmպ̄TUUB!B!F'Z,lfͅIjUdOB9UoB!B!25\ahB=a,f܊bŭ֚Ll1ž !B!B*U+nY5>Df.FUتErc8pɎB!B!LdMX['&fMq[ju; Y>TV[\ !B!BP-jUL\}MtKtĭ&Z`0^y9@wH!B!2ThUTC[ &D҄mXϘ0~Qץ2&L* bVX~랛v~u4 X݈nB!B!dnL'O?[o8"WZ$Uh;De][^a˵{ȭ/|uQbV3!B!BȂF]]]_y~A5)G˵*zk >_-הbW-TS [~F|ܹ!B!B"rݻ_~՟i,nUky`+n]jZlj– Fz{{Q_B!B!EZ[[? ǂK\ \dV\EXoM%nMjZ&DWrE؊8 B!B!dIɤY__a8\U3-^tW "[:pXlQ"B!BYZ#ʉA^}ȫ5%xljl&۪Xm=/+"!B%#ˡP(,iB BjAt+㭳\HjJ6 YΖx!-c\QݮW r-w}B!eGX0FFFEak#H3wr !ZGt 8[Ֆ;[oMiXlI7O3omkk{;!BȲBD !:ZqBOZY5RCN-ɤ81䱷Zu]5Y yoy7VH 绖e7B!,ghhdbBY.ѯ/Rjk ,_UܚN@jTsI{nE!HR K SB! :=s&V~LeeQܹB!e#Jx{*8)J.2D">LD/m۴tΊh{~1aL&nMM&dMLŭX,B!dY!g4{KqB"dI"r ,'W4$+zlnt1VXnMeL2oⴊ Xִ39B!E .fH&ZGD080.߿-`r-ɞ0߮2*s˻Sbp)aB!dY9-!, k–YWq11&sOhf*d2"!2m݇O38pZ[yͫuL_MomzMY\{oށ~##Ν;cB!غXaʋlCa5Ց.Ϩaz$̈2C<A!1}[ަ xy xX4mo{+^_dir=_am yۿ?^2Q>&n3o}ۓ.󲗽o}oHP\2BYwrpp3Icc㴿`:3|y(Ryʃxbn] 3ΑBX"k%|׽5Xc~ ]0!YnDᄏ)]\,CCC{~zI ׽8v>?-܌ ^4~Qw$nyW%]eܹ.bq%p\$k^*vmhnnwީ׵Et6ĉ3yfƕW^[v}lY0D!˝.LXlUf"4h45\jQ4B!dWjHÇOX߼D-HWܟa׮KK,"N> rq% 7OqW~oyohodK9W::ur~|W/ᓟ:tX`O>{裏BYHld-mV<&3%ʹ-B! Jd^u+^ |䏫Z񐅃Zah+.W˴!"닉"Z2\*m㝫+EXlm۶2bW _BX-Ţ~w???g>UW]bGBYJ̖0%1Wui###nس)|{w\p3vF?vk5YL.B!d }vlٲk -o0H@Oqz^]~^iKqzkɸ%Nk^z77U?ݕiz{ 3::?_!2"hM⒘X]K_Gy 3A{ \z<ٷ|V.Gz/>O"YK /+xsoտO=4jA\P bWĦ7W=VeYy+15~n9s2_*'^W#N=z4"q!wߣ?-^WG;xO>w=Yy%~WwSB!Bsv޽xߧKMz{ޯիW]ҶA5=颴KaBȂC]Ixopx>WbW9=Uڅoq?ՍJqazK[om=W w֖{~7߂|}߇UV.yϻۛXto%0vޥ%}=_wݵXN\{lRoPbֿ(1+YqIpӦi֭_ *? [nRbn uu Cx,_+i˹{"??/k /qa_~^o﵅7+phkkGD1ĺJi7Agv>->iz h'ψsLc=ʏNB[R@:@%?Ehkkq,Eດm!,iȑ#=h``@=7w>vt7膦ڙnizXN!a<T-puwM8%[M*t+{rq,7:666{!EL j"t–P볲vq–𒗼H*y]Z8a2uk.*Y%xd'wVw ?zuz~]9o|)'!#~B;wNHy~*⣋r|cY6'˺&GD"YqK.B!d*>,IS\$)K 8e"[B,wM֛h0~'?J0F;0/P^bUIF+R8Imfu noO4ke9 z~(Y1zb0gŻ1~ӟ?ݣ8y"(։K 'bk$._o}]8y~yn9z1=Op:ϋk!wi|=]wonk@2,}$y{ާ[9#ĢBvߞ;"B!djkD$>lKvc<-V/Yoo;oyqZ(.L ٓO>ŝq}UNkg|XEܭ^Z7Ms^ "e/TĿVn"={_—w|D+k*_O s!w nR پappH[JϷ s? l5t,8'>WZE!LdNaK,d\C[B,tKfN R6'o{[.)ű+F?G -t?yIhq{{?kjm"YM_V׫8U o~oֽy~^58#{R'ٰakqJK"lI`Ш 6΄BbJ%UuD ^E]qeuEXy-IHG:;G.N=o~j䆇k&̺;+u իWOKeV$#p֑XX"$T^Z qMV'+VRDz"S[tfDp %>|uCq7˛a2>D҃=<,JZz;ߡ b]%;zTZ'mvvܩx@qHxoذ^uA?{2?:.B@-q]to@.q%2Bʖ(H¤!–O`0 =һ$dXJ .o; %BYzO:۟{޲ŋX,;kNw+K|-ĵVDK1 Wď~NsN! ) 3-n]J؎ل[B4(S2Ɖ% 1p.b+I-qq dV&ΝKq/hE! l6d2@ -[B!dVE!'{1ebbBZZ9 !BȂdq{K!.;A].E!Bf\8ӱ>`!'29N(eXpm"jI莅-B!2+HdBDLnBRTI$V`R/Q˅!B$TLrO]B/"Z-t7BgyB!2kb1)!-B!2k~Ձ, ^=%B!BȬ".l B{'B"v!B!X#WغlD A)jBYP"B!s$J!2P"B!B![B!B!dBqB!B!,Z(nB!B!E -B!B!hE!B!B-!B!BȢ!B!BYP"B!B![B!B!dBqB!B!,Z(nB!B!E -B!B!hE!B!B-!B!BȢ!EEXDP@T҃eYmB.0`&|>~6!,"+"qB!3tB&bW0D8BB!+j@!d"pQ"E!dANrH!\R&GQB!B! [B"jZBѐJ뢈\BB!E2Ա!,B4B!d"`z3$=z<ʃlϯ; ZnBX\a+5%vsҌ>'w+_o |^?o'𖷼]>иLp!|wgB.^| _C=˴4yϻ o|0SHy.!1! BaZ;~_+:tlŊ}|݇4 ?:?|t677o@!}ݏͷ{–7/J"fBLAqBȼ .Abl bm֪l߾ ~u.k‰'M'暫0w~緰r%-Byt?L3rB)(nB"^w=Ob zGT1/n_~'6nۿ*wwh×Uz>Q=/xˣ(I9sVuG}L asl7 ??A!^nT/ l٬͛ل"|ccv!x1 BE!dn/WT]f߾W _dBzxXu^.áCUGzq6L\'Bf "2/|igz[C[E݁z"Vlpp|{Q444bv \vM.2}<_YϺBgUmmmz~6{xˑJׯ׾J֬Y뮻O?hq!xy^|p^w]qObrBؽB!d^F[6_%n1FX0H~FZ544~/xޤtӳ׿_Wn|Ee~,'>Q9s{hnn?ۻw}/~w~_~M j꯾QDu^1P"2_5L7<|_$ T@ 7B!FFyDz׻ޫ̈?߂B:==e[2 T3@-It0iWB!K00ԐWC<ʃlϯkDŽq -B!Pea6mFkkVRBfunB6!,i鴎IE!dqFA!Ld.-"2oHcB9!!yCX "ōRB!BBiB!)IA!dE!d^~i!ʼnߴ"2KD!d B'ER~B! -B!  VB !,8.BYH9-5!PE!dA! &(BDg [B~B! qu|HӰmBɊ(e3clBYP" T @6!Ad`VDB! [B,ҐKiTaY!.RJl-ZB!,x\KbBRH!J9+2լf!ZBbB!!B!BYP"B!B![B!B!dBqB!B!,Z(nB!B!E -B!B!hE!B!B-!B!BȢ!B!BYP"B!B![B!B!dBqkc6!d`LB.3Bqk 2!d1 oy5WLB*3Aqk }Yq˲'rafe[fVe&!d12BjgL2PZ"/EJ%=e !d>V&dU~eLWY:jxa,BȂ0a@pU(oA׉`0+.Q<6pGw B_^56#,`|(l ^g9†h~N̞wpęyLBTEa"hV WKxIowź__P({لxL,3l3y|LyUfN!`C82sO_y7hMe&YXPZx1T:XLGĢEF m -l(nd–}y%.^oB悪5c1*ۘTr=jD-{r˞C!SpŖ]q zó1axwq ˥Iپ,,R֊d eneȂb21j`uUeqwK폐Nvc<ɘxua7D6bdL"lM&j7!rL*.NjU^"2Ң,yj,E Ȃg2a,wm5=I;v8!s8WD׽p\Q4XǮ2Bs!aK η䚸-Bc&tδrY_jWg[˹gc*jJ]-v+3ƽI".2P" juɄ--dd=}EyvT`Js0NJˀW,iߎWօ(fu- ]b$ BZ_=n9B';We[zkBY;e_ AH8;,RJenP7UE.VFBq,8–w;,+mRxɮZwf%#1fXg Ƅ.6>LLGw]7TML'nYpaL첫4!|WԚ`u^D{̒K[oEZZ-5i ],5*ǂMGIF1acŔ Ȃ+jMEh˭bB[rmQ{\/;Ȝ0;G2`ecB|JۦԈ=7\;[b}#J8BȜм7 9&"pake|DW['lM"j( Y>1ak,g|<_/ s- 8Ϙ9e1+_˫qs@ZWribUm&ylVʢYYC1w!%5tm;][,4!s9ЍGc {Po+Y^a\3x%LZز=DAkP"ˆbbVD-"QN(s \9YPLVw1(Z#le_w Vp;[[ X1 *?"zs=9edFSB@m`U CBS[%#p~~?JY/ɨí[w|_~@3u4lG*JkRjrxk-/rٓXsk7wF~iwO, ]F9_EE\Bq,8Jog=.K46ނpUr.A0sN1x4Y\H%Z Wo_s,ylXnGM/DPg1iaKBضm$100PٔܧX,_iʻ,Zn.B)k|>2N<){\)y/83mתkLլ&ʱ]1Sd!ך^a˞t߄,:+4!qc ӧӯ-Wؒw},r>^KM<Cg@sM.==eƹN|GmLFUвK T3.Ce*/z8&Y_Ua*d:mϊ"WZ;@"U+Eߦl ??hy˶ǶG\@q,(ܠUnrrĥK^ma-\yZzD(r]dX+ՂXx"VC")MץѱTȺ=yDJDED^iZu&Ck͚5Z|jzrlb%B,/96^B"Xr<"n޽{<9VZ{ ^)£X9{JG;#꺍]g/d5bγrpDKu+.nb 7K@m78rD]n-=&.E&1j]-b)n%ptscٞ-)_Jug#ϲw5D P*lyESiQ&Zr_G\;=&ι[_-޵Zm+\V!Xxɉ}(FJgs:Rf;YoH[d2$;K<"d!ЍXc][yw\+6'#7Iߺ s邿l1)TUZ(Ts"2x278BUUH:Wq⥸lK P ,č(;!0$Ƣ('PDN<$dyٟ?xs-+j,ʯ红l_b2ʶer,R)0+lbOWZv=د5Q2#P*ԴI91iFL>u#('LQ,ع^3_9qH̢>v<<{N nۈ=8xfA66Wk7__)C dRt9Zp멄ȼ3ք{`8iB""=AȚbb[fٵm.뮃/8w G^&)Sx34XbĩSBGah(``L-"m6.]K%*+% ֭[0%dd3( @"k׮]Za/ׂؗ%-IGY"rzLW++ڒ5V\5]-Iz"K}Q3Ajr5Oout$pdFj.uN Q :"-ܵkXՂՖ e83>wQ\Qm׉ & Ǐ ,CBUq+Oʝ㦋E%N[n+dnE9g)q-_V+g8;0vFFYO:vηz^Jm4ʕu|lomV\wQk1f2s k΅p 5Lq&yfǎ:3fyUfv%#Od G}ùx"NJ렘1S4gJ_zTya;'wif@J]٢ a|VoKIx-_L$3`%1icHp 3<챲TXS.sRCf nZ%vx&eD-Z0+d*W]Жߵ6rL֧ܿH Ȣjh Բjt `WhԲ-Wp涼D-IcÇUk"hqB+޳(,$E @e9'3QQ12w}!ԭjF(ƅr8ݝDt7nVV>eܿe;[yMl8•V8PDE7DWBV ,eZe! |(X.é{<׹4ԅ]Xߨu# r!@JXP~0,-ʢis@.iuqy|umz!=Ae/Y}Zϓ@bmx<6l3N!$' ƹO2n=ٮYp_GBR O=Gu s=QdNsǽ=2ͧ-Tv-"Ƈ+";B&d .b:;|d+N{cɏkf2fu ˭ a;+CU~ʢ"o@}̏Y>eǕùoe]HLdhPBW>D:|lZo"*N b9Ԇub|#C,{SsPP~Qҩ{j:Q -3oJUY|Y bA^5]nELE2I#Q+ Uh5A/drrx[i?S? K Bԧ>zmm(ի3,$Ϟ= `Y3%^WE#xB.qG̶Y%s-(ߨj>y5QiZ0OFE'#Ntjqځ@2"4c80 tngɘiy壵sDe˯^(u2MDŽ·j;%m`RD@g2U/m 1 sJJe`6`h h>F1)#Ǖ/][J@+S؋w(,`ǖ(n;5Rx̪ㄸW뤄(Twtq⑳p(,_j=2Lqa'0\MD:Z*ё=£H<[~uXwMm+pG1u~188-qK-Dz'a[[.IJK\e]n6DB'c$)OcmBDmO쌱;` M(n%O"^akܲ~GҾi"^`$MٲgED (a!_0lhԌ]טϵsU4Wd2ʖ@`枃+U\LUטO+Ui 4 jL[vjK6qq@Tc):LŇQ_܏UEdS5uzrqI r]vD+ jŌΎ̂j7!u/&A}n"gZB:Ɨ3]YqM-8kإLc.RǦ*jE˩[ƘC(HXn,NW?x33H%_R;a-T9QuIIxrԩ󖓘q^b%n.kl-?;bɈ!xzxo(n8|J%(G8AF5.ͱ[2BM|r4'W Fr(erb z0\-R\y%X)K[amifçe*W*l`"qzHPJjD{+IQJؑbů-8x ;bRȞSRWBX" #>%O=."]D|WΨ=KWEĜfCqInvI[IcR݊ycf+džBy_FE,43\}b&A]#/D "1z />_wH‹𬫯¯a* 0 ƎoÕk:NT:*篨 q.bERrm/" [d+30PzZV(q*b>鍰܅+[q9|A YC&Gpݽv=^?{T/FK@0BBvlN> !#AH \`0Vcm-SO#kVTQ[ <_[58ƹ3IuE,hYZ*VO+Wh^]ˀv4}vF(wp;D;hj]G',lDE[nw߭ݾZ[[%AE$i{=,/$qieohlB[{*}fŦ|ZԅMD"F8Ʊ4N4/Qj׭ ~ s]'8ٝĉ4:L4|ƒYT'P_ׂQF#lƍgM $D4  3: ,0S7֘2=kl{v=! ¯#<"jDPȩ1lYӀ=lfΞC$1kw  #Š]j+*ZX#"n#J "UQ ?jFЊ#Y<yg3|̧kÿ3\͡-a՗`@ӕ ՚81BgPH\ee.1j6"bI"mhhȈ$!ĚV[)<; bJz(eXģJx/p nhkiVeL\{Ƞ/]@i&4n_3_D|=WnC+6cw=:>XȾ̓q"b̓d s2gO%dEl%I5W[ JvIEĊHR z%V!r#)عb}̀ezyqLk/]u DP|+*+R (MEmH Jvư_ D+ר2VgOVPAc}E Bg^Z}bPT3,SIT,Kbrt=iT*ujaU:8:Zľi+&%ѥQ]R1d҂,9ɖLɶM{3- rR 0PcMu/ H }M aMkFKOښ/Krٳ.ӭ+MbuЁqK7=&߲CPMY2W쁧1ߣ oycUƇ!Ѵֶ+VMta-Bϝ;+R QOBdT#GuE[$ؼ/AeY'\s5m۶鬋+* V/oWwwCΗ퉘F/|.)'{z'g)g"RPXq?2P"ˆjtbJi7idJJ("V߀T10I5 : Yb1TLQoKy'nq]B56RF@<B$gHx-B@sc'0JBvo:|\ty)Q뮓paz\0k=r /#9y%m UP l2THȧD.[[](a%JBR0%ŕ(3:`YzF9@E-!)N.Ё+==@?ǪJ,.KcIsP]:ˢWlnc0t@zbrO5}}|wߏWƆ]ېVQNY4 .*[b+_W yVJJhiiASS i˄իWcÆ :]OZQ]]]Xv-6nܨ/YV嘥ޮ'ɶ(>z;7tDwe[gW_n4͵;BEʌ޾dl uiJY#Tb}-4!K[dIs^)ObD$E_`V d;r%%rij*gs|X~ٱ6[G% 2?A914F^}s0R-(}H9$ w-<ҦjX31̣O5e0KJhfKXu$1ݐ)9PP0Ը:Z# ,K YKX( 0%H(D%Ih-l,h9Q*}p۶#F~j:Ҵ@E*i"$1K,*o%-qsAY|خ2IEOЈ՛5݈#z~cxtQ'cXsխ8twY*dLY-P\ĉz\2#< '"dIO㕆X^%–;zJ!V[b%ې,Ǐ"#+bX56BByM+Z[}p8ΩƶNe t؈}`/2w&]ن?ĒjppysD b*吔U"4)HEq -S#CR"Og+i+KR DfXe&qs X mH5Kաs L%).EUoÇlF! TKW"O-8zl>=[C9+P˱eͪKޒ-5i<:U!*}K,%վZ [Pi84j.ױs’QBVMM@[J825~9%'¦ia 4_k`EP@R$^ UZfX?""hHh920rM%0><ҀojjeFcH2xYfL\>\>ߛ#*Q.GVAG7Ou ۣ}Pxł<;#hq?yҸJ,j&ƏuUeڎ;6cJUs)\^UQlnPW +#8= ɑl cTէnބ;00x\֭[{W2U\ BȒ"LʢUdԚ6ǂ;cz-ĺTUKD 2^)'p/qZ:6bƕJ21p$(VoAD /#UV_{V:u" 9ԲAab3<6d #6V )1+|"9ceG\ H!t8bCUA{@iBgpdJ7vu+t97qy JXhJBmrV"HdP=stH5xJk1lKH+e[JcQ-vZbfIA[,<VWEWaa#Gzz/2\=5LbJE,d'0׃G~}6SGS=StS/睐pNlîUqm岾%+bH-]W,mP▸$>wG^Nj?A5?Sj{ a]Kad\~ Kܠh[7XܦϞ=뮻IAYP"KGRZ񎔸`EZ*KXl59K/mZJ1P^Z2Ģva9j'WʬLӎJlIT6!$TyM[;xR#.ᜪT4!"V'TD-̈/YҟiTN-,J 䢦lձ5&|N` %&HE<-*'&uy:)!U]{8ӕCwo\–}%Ԋi9Yai*%km>Ε(d/3o N*neQq Qr0%cE 75ʗC(*2_*n7 !Ԑ[U– pЙo0Pq;Um776raK\ !K[dcTd#nm!_X%"M](J~!ѯĎL1jTE!Y=2To>SNWDʩe|f;R_ =ִRr&>%RL'r}"шO_**P ? %8ioiטT9e6,1c1̊-%TbHd JG` 'ɚ8q:1[|8rB"gFc]Cg4W#Jmc6JBVZ4|#CvNO#grQG8v3P,K4JˆFPg,'ˮzKg-6t+"Q"DT=yuJ8*ع9hhl( F ,_>x܉Õ͖JJjNTj:ح*Vw,( T[G& j(*1!a[%RנT*Is&],iuj7 pB1JTDս9iz%hћ@~}C1bh,l@(\ B!d!qZBBȒ CXY9%b#"WG [y; Bм-x+:0Xݸαʥ;ݬ=tg:Vw,mMj`PR3}ёD/LogQ 0tb*bKХl1HD%u |b%Ztq<~|2ޡ9?W@\ tr tA*a)i`H&hm20"DѤ;KkK.o@gGC):𨥅lNb5X",FJ%p\3<Z9lVA%>*~\K[r하eu |mف"a1$JuX۶6&V@Kqꂖv{EY̘5!,}sB bu>k-)eSYl'VF%Au0x J4ϑF Ƶ[ 8+}_^K>!a_#Q!ԌBpͯv 1r&q f)ے*" +._H}=v a%),V3*7@`JPQ5Ms9DɈT)7pc(Ѫ޾|..R&Qbc zJ"2$\U+dF ڝ0n-1>WQ/H%:m3ߦއr65=J)X6|"f$3^f9|WWj[o-9!d!ewo_LFbX*zvL'!dBq,yܸQiCW:VӢT(S7P {nVڗ.hT.<0釵SGC ~1muv ԭA<ЂɦMߵ}ɞi N|-7?Q x/2J:3RB^ \hvb!`؏R&+TZ*SB'@63b`F14u${LflG)('J_F%MĔ0j~椳@ksL=\ gUDW(*JxQ-j]}yX.eZ")iJ׊$UEʧ+ENLk"D@_{r*B#j:cITUK ,،+beс6:uJgGloo٘d@"K,.ޔL&1<<<'H!RKF째E5Ȳ çԖ8BCd1:l>L?2 '80S}:Vt紵v^=dCZJLXadb}6Xު ֯RT`Q\TO@J wE+`>*w*Y$|HqZJpk6! K&J2UI,J6caɞDJ%Yt PDb[7p'@5A^–!<[RB"|"Ti˱X+l#.xׇ[zFJJIJթz{z :4Ez_ǎuD՟w'ضm۱b B(n%]m*i086%g1„v ݉.XC4E%_Ȳq+ e`;=kz5eJé!e唠Wky*y V)c=ɶ FAmXNX>JvOJ}-.x*-q$8{Qko"Ը$12Z@JtWVJF [ꞘhIMpdv!`}9T"X`%4Cjگ_[a j;Q5* Т툠[>1~Q@!Z޲qA%˦1'֛s"$ #Y}J2{ZeY)B,?H$0H;L!5!uuuK\uа{ 7Abzj9sFA}}E!-[)*vv2%зq.dmWb`q u%ߘH5C.Ə9$F(ćD% =ǑWA +#`uJ CCTӛڵUQv⏙^)u 39HYQ-TP)o'Ҕæ%45j̹a:ǡi ՗"lI+ʤK:}P !2*ȣs7HӉS%\"&zD2Et?7ch: ; TtE4eLod.SZ*B---zhoobڵ@!dnE 3i,B1ʱB1,i[cΏ(˵hw7yAJTGnOXߓ؈+1\n EKܧ1u[8֊}SۺlVlrhErbQRR)G% -5q'T>*SӺ]^0G4lmVG W@g[| lQ)1џW]Jʡf!Qg,(˱*[9jM\/ej@-^iK,ɐẌj;"JoZ*l:F,Bʼn63n#e>j^++VXg4@7|ҧ,$8Y1w0d2+–51FW2_Zu{':&Sv'bBpb`9;Er)M`MFDչj3FL䲣JR˝=X܉dd8m*i7VȒh Q–SH8"Z < {$Wш|%+31:X:}Nʫx$N+!4?PĚUJTv38VS㸊J:Ҥ+@hQ~F*nN,YvU3*XhԉfaZϐK%Y>nyr9v;m> ]vNY^ȏ#sĤO]d-]䚷謷%˅@ D=YP"ˀPQqYsB~HN S)P5pv* 1$RBQĜ%1QK [^J+ԆWK/:J$SO m Z:ke)훮jKM'6\-+k۶e(J$2:(U\c+WnjL%4U{IZGoT @VҁXn bxTOVW<3Jά!Նs6Ҷc5uAu>zmmFc $ &FTNXʄ򽷝(ڝSсK-zLϋвuy$0M'{tOJZ䲴f{Gl!c$<:{JaȸoW$h{:_RItP롰Ef71dAuEb[7,㵎td=UxKnGn_}i5Hy)1.Ov~nD - 0,l"֘3(3JUR"MIgDysN(=^ 0lZ6YyW^QKrߵQD |z;#HfB͠D*mJTRÎFH[>vZdRR"s*9BUry>c`R>9WzSkzGT WiFc=Q "P#`1Urr[#~|IM ~f ^52˫Xe(eH>}=TQit,,[NH,񙎻|eꡲ^Z$u(l`ƍXjRT%s^?ۺ֎hCY20؄Ly/{l%E3IX=@q:"<8qBgʋFZҢGOO=E.[)i >}ZgK_ަ[۶ms)g}ȯ?222HGKИ嗗*͔ < "-]^ՉH$B3g|x,8gVߢ_ G ._P o], \eF7Dwܶk>PeGA KUvxs6u!4룼]D)gkʙahE)%((=˞yZ;VQm qEVK>[Ul)D‡dR߹zD 3$PPbO k=hìXUuD,QYpɏ0(*ԘZ6KhX.(7g;V,n٧W2J\RY W+MƼ۝lyE=?Az H9T2Jq "NM~Eb%Ç+D:{yte X뉀بŝU: ło˖-ު#CbmBN{+J!GL3EL {Tq8]X█"by'"N,.ʳi"c}}hiiţTΊ;xT J/`*zz} z!”zSUmQk1uiTF#v8m_Kb9Y0Kek--,.b~X *q,%pzJ8\bg~ND9=^k%h#򠂐ubŇ-"& ຝb%":%0e߮q㻹 #"8ٟhԥ_!t6П, _pꥫHJFX ]2]+b׽NaʕZrG6~-[#n޼OUW_Ģ%*=˄,bآ"K)m܌7CoOE%/#&rKO^Pnz\w\9\s.k^ fY@Uv\d|kH@-+@DuE#N/h ɴcT+ l1*~ GJo;G$d ,CRFB cԧJ9d>i7z87t @.SqXy>^Z1.[%M FO*H\#w\T:snֶF 4Y{t=Nl&A,q_$FKKK 3AaA-1$֬Y"*W\eo˸Ϡ a#d1Bq,izL:׮ڍ1_x}Oa&nU-\ >:f.R E"cНQBWIEa?MģJ20T0QUD0֐ rEK}0j0pr>'lC lB6J9`H\~rz]Mް- BS^TpUxf-7v=kc̥3mtkk hLp4PDAL;K=9!K [4%ӥ ;!*͗WDZs6t"z(Xf% -qeLmZ.|Uݏ PCS扨%ǚ/-{j1[?k8YZoH0ږ>ɔ#tNrB qnC Jn>%1-)YNWµVy8YKe]{s'p=jA@Ji<ҹ2O'6 !dH-XcTB:"v[;dȒw*`xy>NGtEjǍر %6_g$E$I[HbτD!B! -qZrfY<:իu0OI+qd;3<<YI@Йf2C29rMMM\^RGKkkktYV,7$SK,IE߯JKAM(C-HAXJQb]H r} ]gvSru-Zy&dy7Xɽ+$^lKαGA2uw﫜s ,^@Դ[2vIu'//$P"ă,D*4"jp$&"bHWW.r-l;vlVĭDĭCiERJUQy{Moz>VDFDkL?y#"_r%r<" r=E+t-98wWb6-7]k&T\#ɵ'Ċ+5<~aժUzӧOcZ +6ʺ{QR<vء@"AfyEȅq` :yx¸`҉@,ɻacK3f!_,`_W7NL>Ϭs\o5ֲ|.9H皢ŃI|PB+ ݻwk -$*~*bņ "BsȲG*0b$XȇY HDpE ̊%2m!!oDAM9W$nS+ԉ"(+4C_~DH'B\;A zկql[DZkXWn񺮆r.rZN&$;wg6>mݺU "Њ +ϫX3,֝E3R ˚5kt#^}iRλzȷ͠'T[TP߀ڥ-ԷPpzpA-y՚1D{(_  zI}TkVc_w":AE%Y~1_v*.aR2դ S _@]UgVIÙ;|PJ=R)~TI}ZYB^b.^;%VR=|I *QR Jf]ׂ1c[qXJvS+T`JU@e\>|e1sS)ٿT&W*r҈ κ()1$9^i%ȴvRq?Rّq9Fɸ_ T#B\ku-yY{/42PSy幕p5!VZr|]qp|ׂMLղ%54頻JlȕQA%;VE-QL~0t+^(}(ԭR[@UB{Ҵcq$6^ECM/d؆bPWR=?يua 3~fS% y%$tHvs/ 3 RkRǖ:+2.ZAOR"dq~̟HJq,{\CoEVVx]9Zk .Ӥk 4X䘤r! ʃ7 {"g,ٿ x-"BBBL]|2uM| y٣cɸ@edB0Z[.*}w+S=[DMVI[:lBbSq73 iakH O9AZm-9 uPyCpt>lE[aV7?` eJPȤ_] Z5k ;Fa8z!X6c꣑4۷oזZnR+B<>}ODr" vڥaA,٥$Ͻp; e]B(n&/ղUΗ#,FK!7FEŅoWd1]K"!ՑFX3˷8K]-_?s#jju$%91Rncַ't.ChаE" "{~A![d#nXضNje5.B!D$6.\%}iG&5P(P$wA٧Euur6~P:) K  3k3$CgIKJhQeql/:n|%¨Rm1v6#9?&V5FFp)VIkSZXA$arRIr!վS`X7%㔭f摷 XrmC M}ꚮloBfW1!,/I4&T3Ԁ+^߆/F\3 z?OHwv"{:--%#{W_ BYP"K߿w.'CT:PnDNJUb.!D><|O1}׬QJhD X u!'K**dLi\+"FYt)ym+L\XȐcޗ݃L&ӘUQ }ezCgVd,P")0 ±nuW(q@_~oG?!;}N QDwoY_0S V.RrvFWɴ67fp:܁[֡Gݳޞ~eu(Ϟ 恬Ms]xo_65!+k'pGckӣXv-VYVUW ggdxrE<:敯,>e$#%XD DTkovۤ0LAU@;WAgODP56'|ؒD;/6rJ.q wJK{+:hIق 1.XjlpsGHf+量7)ݍפԹX`W5Nc4("/z͘wQZw5׬KFjMǭ5"BU@5}jVr(bp 9**@r,Kf9%ԕLuLv E8@(ބW݄C{0Ycokhj˩vmDF)DCBQ4+:zebA'sD#zXɳ+5 ~@ B%UNN| oiT<"Xur/pqkZlsÒE"d9"[2ߗJQKU(`{޹b*?$-_$.,+nžBj5<]'Oa0M?"U}*\Z:!d9(Y*bUnU`dp ӚHҎm[wОG)+Z|hTD1X8IŢk H,j7D;W(P70Y\hաD5}'GC"dS P&ԏԱ8i: kRШ7%l)1δbܕ#vmǛM}̠ǻ2J(,Xdw߈7;lj!T,a 3(5Z8:Xi`˦Mt XNK^#ڕNV,T:0F#JJk(""aK,rPyLs&G*1#_2ץlɾ cUU~( %ƅq*qdptZz:,t4pJIt%9L$=gXsce2Si'X 6804.S$2?|g%sG_o/,"Ѩ}`>yͫѾj%FS9[ F;WuGqr_ Hjcj\+pFi%jecCC `jȹ06F?Z;TzQun1h9u|V  SW@K]3mƐF#ڛmT:|CJ8llh c=$2?P"daCakyqOWc;n|ۯ.@tzކo~9ƺ(N8%|,'P"Km}-jU9D|*Q4 N@w]A%rz4T%"3qźqQmLd%qO,(XVcMBW ^7hQ={+H8#O>ûjCÊ+Q ᤹ ;҅['U3}Z+iN,j5*%{^Ыs-usԮV9p7SX(1AF GNC)}uȧKht X%pkVF9TeV O:O%R>7z{؄x<'{y|:Fv’% -x} ZWJAzNE.TDXm=C4[^eJlm\Ռ )%9Q>2҅PsR# Wrv9U-Fe;}JjѮ>L>;v^*9ҙ{sZ;yi:sJ ZJxCHpa\-p'JLN~CΒ(9CX D=J e= 8vЏLJsrFF.K2ޜ& 13PRMh0ZXЙ! t찶:v4a`X "8iL"gLXʣ!*ŖΆT\eAl@H7apP1̴頯"nmgYxHhDUj׵r]DEsq] !+bLDGx|CMMM8r0zOA|帬C<[K 212İ?6nUO-)zmE}ͷ* 5{9xҪEz]vdF:UIPz\R{HoϚjLbYتϦG?5ѩc[=6nC Ãpx=xƆM'(fU#SVH`A5JxHP7`(aFbXI $UQ-GVQ^R`ɠL_7-Yڇ?$KhkB$@T}˰}zմ:w^Kk MGzcReEɖX[ngu E>%z5K#5tX ۂJ4Qa:~%T_D|?}^JCAy4#ߎHh8Qʶ4M'YJQuڕv-s*-MDXoA&q@TȼrYbE= :2߽e<\9fyվb{nRuQhF,VX&mݎޒ,2R1c~޽[3PVKZJDqgXVӆuȲI"I(6 -䠸E4":ToX_},RQUrWnT{+trmXn+:#( PFQUkaV╸GHD`|čNbʬ 㮝_ڪu%̏jAqϳsiZ=ۋ{BG[0wBφ s Jt 0~+;#+UFOO>WiDME&gau[={YR?be[֩c8qTS)af^! P:B:Hh:\)ᬅmuJ+"/_u}[10:~uI5>Q%I%cͪFcJP,9.\YIիp)=W ڒn˦-s(]c8V><`3B6n2tx1CQUPuKU@o`[Iت3aDqt *w&Dp;2vlmƎ(-_v>!D$JR}%ft}v dAq,i"#VLrXk C:4S(A>z;ܹ 'a%lXIUFFU<J`MJ%Ȩml%pS╡c>匇D*h-Ɯ  6U!`!S<Le%Zw\[}N93 V?^h8k[[zRzkto-ΌKUs^wP=!ToC,b?^`%y9׽Y]H/.~-.EUHjˆz.t6Mu.p׬n>x,+ͭx葇ڦ:}7QGFJUף$ѸXĕh'Boy2 jBfgwȕ'$EEP'6 I`PA3`#Q#kPSWFwJy^QNҁŒJR.x߀^^,iKuU; 5 _"d)Aq,ič,NjQuZl6d3J-V #9sm. =XCCʈOU>$ao6pBŔXCAb@NyۉI3ܸ.5gK4 ';1"Ql[21`V'_%۷O~'jNrJFmk:ʖUo[ۺp][E[,JH׊HD`R OyԇزϾr%4YX^x걽xc8=QlK܇H=ȫKY 5p/tFgXؾ*?f؇HV I6N2Es:‘ca"@sSf'?><{K^nxt\" E#Xѡ%iteD>{JAuL 0"܌8!d-QEˋHKe\P6Gdˋ '܂o;2Rݰa@u[:[b{{kۼrE5Mh]kǥ"ۖH+Wr,IX% umVDVb( %oPrJйJǺFc} F B$BRHg䷀DK^řaـPz&@N qUi[ZsJj4^+{eɎMa:s=T\ZΒus% 8o؂u6+숎 Pva81MM(wT&3ǵcCnb<3;ѓAoΔqv@ ߓ Rjݓ})Wς&vf%ԇ:ƶfŐ+0ڥI^`˯U\GS#8y u16Fܰ v<|JoêWݸj-6| Td@Om:#51sX`:U!D >6g R/CQ]+)Xc!XBfԇL>A%b kG(hAZsj;G28ݗʦ "v_|4vtб؉hmnk֮6Mu﮾j-6nݺ \l!CSClٺ7x#uoX6ŪUU{`)Pz6}{H`G=c,L&NΞ=/B"l޽bq 7஻‰'@"OeYSBAxѨRѢS.'@Au07B:O"dCq,iumޭ~Jؒ%>"e% N{v!$zjz@Ã(E l*2Q9=q(E-2EqUKJJuӢXRiG˱R=q,񦫱uz\L:uMx~ Q6v'p.3vۼWnߌS)h(%W@v~PɛXs-mC ERRJɫGPͬSB[{ԏьZد uMPbjِ@M <чWOvtc!+`Iq;Mbqg-8W@:([ZԨ:Y8*%lЊIoVPEb.hwWn:]RV AUբqyk>GRV:) <"<M?zI0a,uM ȒFa%J;}}gN8F M9 9URtj> 3@ZBW}+)'BHVD~x2#hY gt GbZ Y=VFT9ݷnhj  ,=PDkc#Z Vu|U z~>8vl~hXݩ(aJn%goVfjIѽW喓DCԇl3l^>g7zAěH(дOG"SD!P%y4DLJZf!~;#ʪ1zȆiC몵]vmV\}UJJ3G024uO==$VK`yYnp*Buviqe)!/J2_"7h+qTkY;;w%VX%˖ n wH !! '!$$$I ztl nؖeْ};[i%m9?͛zgvι=\ { 5 uPA?ys[ZZtA9[܆9bh=z'$bpTÅJ|J#ĈI2WKVLp . v=wr@VX%`lĕaUBY*9 _8MQ]9aOwD% 9Fĸ &絠Qdp8?#%T ӈ}JʪuѦ4 ՈsV5wm})T(D bckM),Qup~,y[knC>WYRZc_8t:E !DКZuFsZSLie 4~ כ^`''QD~ B@\=,EY\sP~6{!׫Е:/ź-[Ѓ"Xk֬wuu'b[mqs'ڊ(v_|xn=<EףĜ\禛n8 );ynA/#?>6E:Y~]~N҂5~y P׹+裏Q i L?"n sJ7ׅc:T0֞9.zZ/fX~% j~+ RF{\ I홣%%pxBZN!}W_KSztZ٬8c6I])gdKK@mi5ʘ`bx _=;y*sRdA4bAbAX"+agtF<<|Q]p0=;zҪXz$|)J3OpCr;Ԧ*їH!`  uRJ ma.%Z #~(9RnJ|QFPuY!A  c !eYOq4/jku9A1؀ݵW'=@y%S ]Y/9DT! 9c2F*u*TeB>u:ZGuN< SD}pa/:T-~O^Mɠ_wuuR6tKC KW@D{8'DFw'C(Vq nGr(Q2Q<i;S޽{Xm(4QDHEo,ҢI]p{ SŋjYk//NS  .ea)Q1Xvfjkk67%cSazqKNsJV̇ڲ/T2"%4(#YQT.XNFBO!-h(&⨅q$NRV"uj]K *FcH{PYQcrnV/tJ*PY^GadS@0z]5`)A-'8~ [ުeX_' r{ ^N*yFi n~Ʉɴ>TR2[ Oez bV1ۏІK8 h[ %VsSAbʈ G(-S} "W1U%VC ehH -K]ÆFmu:ժMCW={pхjc׮ؾiuUUYz!E0u kۇSIA^2]9~u! 8WC#=lhg1,3v#y1nF'|.\4A}L4…u=b+;i0q%Z%VmEAd˔0CՇNDYm5G ѬH!Q )NX `)TY|>hjYXb*(N7M-/ rc:77+i\-f)0D(\y79'B=E)™!0#p[ GQFkxxP{kC0R˧QQH"eՈFpQOӓ E 53JKCFhÕkѣcb{GrAiB'9+C .]j 8tpڕpS+r^oqޮ>ߌfNǗ#qmTDO R S/FtuWO>لvL cY+g`(B@N_}C W#P=oDO!NF l.ThYܢ~dߧs:]}ݺu(-)SOo='Ċ5!2T%p2tx\xKBqeeUi˔Zn!:+`W PlQnl`ŋ)"A 'gv" mK 9IT/`$A1j_'%:m O 5 JK(C5蔰|]JKt] fWEG_,W) !Eo=_q=x%Oh klYIK n>tFU/řK C,3m!%i-:O"k9|X$cJ̗r݊˹QS$~ooQyP$":;N:;p)\L c%DՃ`޽x/k^%F'7C5ƻʋ(\1>3:E_AFS(5BϤ07NHv W1(]܃v˯(ꗨJj4#ؽUT6҃|vkX:_ơR-Iaae.H.G iOa> 0'exlX!9RBE//ĝ%f8fipIT̝eoTePQZHFIe:Te# k`R6v7dkTV,T1>';bbWRV'--r!u>ڥRQI2JVj/Hǧ ltwtB}fL\qy(d5<E\ 8G֒vlŞ}ϣ&kꑍj:5!Tg@7A%T%E,9 RNd$5|IpX]jz췏crmOoЍ$ZDP-ѿ㞆=uT >\UVR=( ¹b(Af28AV{HQը:VQ,[PںRXE N1B46 ȑyq,l}"A6or UgJZN%+K0\a"0qP|С5e$l/Q!-xٙ ᝕)2Qcj&"?ڀn>U#3D{82< +Xūѡ ,36@rۡ> M*,()kQ%%Us N!D>[:B0eDv/,eFPf:p1z c5k|rW,E.ɎNs#8׃@YT[JR 7mXXSc=+?V"qѐ_ CYۧCImuxi6523>x0}YeFo`j?c'YhD,ii⅋%=v숺V8"{߽xͫ_Tй Ҁ!`kFAI`YW؏>W䲜[cdgs˹Etn3^L"x) ]( g(!"{"D8E=JTd2NT`@]k=UגQkq!oQYU>N!ԏq7&oXЈ'|Rr`./Y> ,^hI ::gV)XY?ݿ/^+Ǡ +X_cmYYnP3ϖIύ~I AVJKKsIy|;::䙛ت?1gLw YU^ɓ~45MS0c8^4j3tEPBM8Ұ7`;B"ٯ:,Bmh-ft^U[n+A "n sD$;jD# z"q4 b-vB) Y h1֞;!D02R%(Q&7TtHN, ?$s oL2Qز]ܶZʌpdsa>/.yv[:?ZG0<4玴XgNDn\p$ŮƢY$Y&Ԭ4TWFS #j+pWYhllBVGG;~a%FUFWwp(jjj o\#H)e+ :NމJ`-ף ғ nrȑ{zzA>{˖-޽{sڴi{1%v0HmD-Sbeq-AE }H)OY7hKefmRۡ:?&tY'h BHf9 ;PJ92 Y3PfNOsK9M@ W͋aʘ"  S +ы ΐ>WyR!dBu*q!eU*;-Ǒ#>r`$)d04B_%lïo)+G - 9 =.ڰ?#GtaZ}7H+@7DP/>l%wma&!CiUB - PQQ>iY `I=bCqvnB# -\΄-:)MG&-7Yx`rlb 8eV^??͛ǑH֮BE(->/F_OL_Saz$,/ҮFyQ,y,W:b$oᖢ"^rȖeQUW]q^mf:s2(yIQwA>AzKέIjЯlD%<%=Vl 1 Xρa-1D&A(jam1x,@)+%P1ʰCYvDѝPĬ~Zà YAu͖ 9 iU[t.28*ihRc.&@UmMc*IULZqK1:0ed/ܹ y)o1 = lܸQ2|#җB1^";x9pyoO>xșB sZ2LsudxmM8S-sppP;Z pɯAx;M{o XKHE_dj me,+[A 3(Rn ;CC2A2Cƒ!DȪTt L,Ϡ;|YciiJ(0qKP qQC!bĆ @eE}q(QtDcs>IAiFIce2(euò:tHYx](P<#{א"RSSMמ2rm1ſX6/-)5#-ϓoA?3.qK ^pCAsG]zHZ6)#̟EO:H\6Ve\w DP$@FT !R,KRj~'{4V_%s =)*sb:"n (YDA4(X\zoE)\tҜ֬YcSlhTGХ^cËe²7M Ei/Ek㲜~o^ sm("Y-q9̿yɛXNnGH /Nң?yRpuMx(aňfbF:5CPȔxa=3d57 #rfuM"10h@"oPu,PEau-±A2H|zԌrTC6YlV[8 XR?Dv3 ~M$W6f9t[ռ¤> 2N?zJx[ mD1I G]y+9Za(sZ3q͐|anJhXVJRO(+QXڇh0 !%< Ӱm bI$Y鵥:(ʃJPKje:HB&AT_xЩ> `' 0L^ٽ{^mr-zYSS!{GmsA>n6HZWWߦDdJ*^QQ~"־}p%:6Ù$[¼/'qY`Fȣa_\ANlM8eoC7W+?l, &? pn?A(3jI\qKxta7Kh}),@IwFаN^_Wc-˧UN0D(*?W/ƈqj>&z`~?\c xF}u+lg sfX?=2+{jz3˳r_/;OZ&1 g>#4x&b9,7CQBmޚQYIA f<ሥLn2rwA8ۈ%itCLg'/˔% oC/}!gltu('NkyjjkP[SZ$LRUcFsCV\_)`qX&5"GO,//백M1s3"(d$|jjj:ڜIo(cỂɣpDGeѭ:4@j3Iyav#0*#2~(27]+j ݈,aoG+mt3ҚHmmKK]Q}4 עpإ jY]݈ shQף -K!Z 5cM"?X_h|Î ٌRYތ:7[k?\F=Y*sD!ۈE\?8z ?_f"9ܷeYT{Q|Zr6Ys>ǿ,ޣݰ$DQ8h|hHOS=Gy,1^[fip$Q&oȈdTY܃?٤NJ7l0=?'y/nnB$,QF-andmO#_L@&pYJ GG()u@)Z`Cxn-XJI$S,BЂE*{W$I\xj[T#քME/kD #lxG NyG06)[lRs\joj~"XFRudm:ߧ\j?F"C0 Jcd v;,sx hAWy 73mL\P>cg(_fG`CMj[,k8#~{v][]b9VQU!ңpŊرc6lؠ絶jÊ kCC?K/'Oĉ't2}杳d"0ȡ^GZ}İ(k*SEƜQup-   9ؠ<4`iBG{ְajoáCpQYBWfx8O?9cV|y]|!J\XTyD$\˄HE'R#p*?hi b&^)ʾkb/~2H2 ah DE2FSpB@9f/WJ*9,I./CP eTep`5a,]@Y ib  SӦam<]"qAދ|Ϥ0(y$}"5 8pi%HwTlIe0_;hsR T +ޯUua/t{!%1T}ЈYEq߾}߶Jm裏⢋.ݻMT;F/^,! UD%Kp&O,5uvnV ۠d3.Iu6,KghN32s뺆_-j_7UB 7 }0`_i(\82:qAԣCq<^ W\҇ۏq&a>A>cz 5H~+U_A|ʸ꘵$"xOF MKAR SREC(!'xIlb w$TYȪ+([f[#!xY`tw(!9Twu!Pb-(k ; 7"&CG1aݪ~]ȗ.YRu8p(|1vٯ/g=[q]7^x]PwjD"M(\r]6Hw"9mO-+7=Y˙rM),=ʙ?Qf&RV^r|K'Gvi;O `2u<,A.eD& 6ۏ#l2fIij@R+piqH)"u(,Ǣ8u hNjU_6:z{q՛urg}CzĚwӹD#/|\R?7;w_p! }KpuTY N˖-F2og!Y;L$Ae/զGe< +FvΨCqKW W {0?ΝAψ%CldCA9q ~pEo~% COw^[7߄UeݯU_}rLձcX982zCʘPB1T[<6L2(SB꼎zcXԠm-~&oYe#xXzZ7q4%mN#QA3jG"̺6I1 Q|H.,-+TEB"9U9ɲܤf|zq /[ZSغ={~AUY ~l\.m`F=f0ӑ =_CfRIܽ-KPYUuתc(3lʃ;7 6nBގF>ITŐŚ gDZnPގO?([ަsEQ=cяTen޲[6_7>IlݺD֭毵PÏ-o~ݬ߯FdUFAOe0Ay /Q\g<=@r~eL:_=V0xpT>rԌQ ;>ciCÛ'x2$Σ !JD0D}}j*}fb^VREE:N$Fw?8xfn+kM|F# 'Gg<ֵm4|,ǯ-rl!ڣEE.ϕelg6b8ŔXZݼ]&|X#c>x,I%tp7[Q"m nn-˹v֫v=|mK8'HYaQRZu\5|C}عQ-p1;n09 Uª3U:,AFqKXh^wYϏ`i_җQt h=ճ zT]kEԲo~ѣ ׾uȦRXՃZ%$p0WR˟LQ#JJ%9DطoA<ګƚUrrӋm;ǵ5WnFuU%Nu`Պe:ҖfQ1U b tkuԢVp8*yFG!݈E&ah窜NIg[/8oQ=lwC7QOᐍ0йn&M >%*NKn䈨N|x%cx/3#y^ @>s|x73=qD|T5^*!"_ TggA:@O#(],v(AyIP =VĢ͛a(d#FW=box+"[]o84J/wb22/C;?_)a'"O'CT;쓧pE  E&Zd38p0bC֧1;pWlڈk 558yn4jУEDEL8;q+ ITkK.H VcBL/'ىz MZhq:|l;a:ՊZ%ZKcU\,E*D"GCCZ\+Ɓfgwey\o+;>D)u.QtweY}>@O2+rPH szեݠH gjCCCz zAFa677c޽uOܟ{I+НW]Zt˺ͺsZ" xqKz"JVUCCzĨ;U{W#P;+Z>=bi(χfee;k8d#S;~v3c8Ao:^Xj~Z i݆Uzy𩯭F2~l۾C IN ya#z V=H +Rϳ<{v mmXbo^MTe?ӝ߽{.R׿bs=k=[%f hlGӂFT׆ ÏyDKJA+$h#.ږG2Q +Wqx=EXG6ER{s/YN$Yw͖!fO-R \9(Wzu5[0p@[^(.ש !$џߋ݋SF*Y҂^T)kˍ/PK"֏=<3,#7WTWIEA< N cs\@D4aѣ:Q}X_:Ӆy> Pcb`hPpCm)-QiRuz&&!MEyjq 8ن>l\~&:xɦ'08kWQJ˺1>zYXj5: /뇴X]m#N:˗'pq\o*{.Y'k*aɓJj։S;;`B)D{MNA$R'n3֜ܰHO-ˑ }zQe+.Th@[}ger718)dqHm$NakL mذnooׂkM=~Xp90EA >k33zr<YR^;n^|7:!~e7׽Oq4/]~ qKwPhxz6|'ѯ䅲r|[Թg{~MM<2L [+UWdYTrIyx~:oϽ _ RjxދewU(į~H܊p[4fًðNn=vʀYz9Z0D^%^W}PuioSJzYzIVTaT_gۅ7j!'ODS)r5+ ̕wGmFS:]aDrcO=m=Ʋgl,kgiv$t|w{I6oz: \N'wrB[ fCK Ej6}}XԼPT8u8v=[^fDz$*;~F\b)2zmF۾샃<٪m۞իWرXj^񓣄-TVV}}X`aAJ .םLoޡ=[¼B&?չBUUZT/JzDKJg26*ѯ U!%n4zU.jFOw2Bz~2Ơ߯=N;lUzi=mKᢍռxRQ KYTB0zTO&: Qr>|2tv^ݹ J CfŚFeyP*z1\RFF4v;pGցQk޲$e}l@&힗r:e$כeݐGg~ gYgrBQHX ̅6eK_b8x|f`GM5z &oYDO766,_GiPN(Qet^Lvpr볓O&ƫ=u:_-C )^t*j?֦,FpA}[tX%Q ,] YGAP [|Q 0]$t =CƛE 8oQ {߇C"KO ZF+f8GuMz׾}^`(U/<[oD0D$AWwzѶ^WUn˓O݌¦=|N,rǡɉ`cۉmhNb{rɺ28B3ʡwWMy&wF<άY舦`:_k=}TA O D_| Jg(A>aLwI`&O"5x eV Wcs:_p3Cbh / 3c.nv]:f}ڎ;v<QZtZQZZ-r,½=zDZq)Jb\D-aԋTy9p}(]mx߯z;£?;J*ņpƋv_Y%l]oy[u(cO|RZSODxL(#=j-sdNPYU_"ĉcس{>TIkQ/ze%`j-0,qhiY'+ڣ/ ~8։+/K/~t/;nLrqj$:h9xvyMd𶻥ϘK2)7YjO!NsY>k$ѽXD}ZNRy# `n[n{OY59PAa]@%R݈ ;սu*N 5,X*J*ΦQatT~bT-hmmǒ%Kq/ӞW˗@IIԵ󡽪ABU|ssJ,;\w2tAc%KIڊ?g~⿴qa|V#Xh!r)TV|B<]Xp_'o~ P6x8)72|N^oعuܺu|X55Um PV^ŨQ=:;߃cJ\khEWشa=:u>Zl{9TV)lXW%-VZ^V|zzt?,5r9% B=E^g+#MrIs_E EԨrafG#JLvuV\+oBygWλ9{{-3s\* 04|Z" sMH^Wҙ䖆A=0lɗEo, /nَ͋ Tɨo~!FK"n * J( ht䩧'V"ڛJ(OgTJ[(IP''mPo. $RO$&:>J@$gB𢵈 UK9*ǧDƦzT׏<:ʊr<>L`u8r8N1K;sn1'cI"qMH)qI3PV444ZF#Px A{6rٹܲs|ˬ-kD*19l{MUq宊[ 0QxUD&>\7` ot;*p~Tb;إתSC¼_V*"zSJ `Cq#X~j%bĠzlx9ԥeqcOb>%D>U> J:]2%:?nl#:t|F*z`u5zG¦&yXĹMhm=Ce8zcX Ž PSUawbaK 2mF/t<+䌼\-͝5Q\qTb"22#٣-'/W.YɦdQgs uѲ]A$  rׯӟbb8JFG& UarD::38&~Nl|Hs'BYĥnXoC✳pFI%gâ*::Щ>,CEeG{rӋ-6|') ]K/‚zUPwOb3;ǂzpU8x.b46Ƕb)*-^Ӕ^ryF-ODI-sGM*_w2L԰)QF"J"Y7 H:<7\h"9AAΐ6@OkaB$y@-a2^ˈR4 Mz Ӿ^~֪`VF#ƲKe!‘N,N2zR։_k[iVYGrwly\lwF} ]Œt kАZG'P$wGHnx=;^AY&O µ@eY)q[3۞Fʢd*S~ - gA%^W**2Y?de%Iѝid31U~e^ዔMsa AO'P)Qe4"X Dva'0Ke>X|9x \q:F{{;?e˖ѣz? ]꫱~N]]^o͚5ףclɒ%fS 0qK{K$Fawor:țo( Ezo=r#F"&/#'{c'nr\n z VYN}/f,\Ԅ믻Ye$ 1İ?7_Os#j@ggǷ)ˇ\v+zBK{,Q1/7TIe^=[H5(uϟ7yq}ʚIw6a pGI\PgS#(yN&gcpVzmB,% B,7dϵ FM90lc3=(UbVD?!:zVBiFbTz!EJtZa8pJ ZJJ(*gL},ҡ $HTiF(I]Z_RTڒFnMW(AjjGH-^ ;%ۋlo}kPhIɤEꩧҥK500reR2c{>իW؃ʆ`Ϟ=ËjkkqkIǙZV1}c~@?"n 3bFB M7lE4:O޷}PC :ڻpTiz\zUkeI3 JʰqXZfo~3' G040Z_{7#e<QFGƆ gSItqQp2PCWL\:32ecÜ5ɕK[aP`d5Ro@{1cvrdi+J:Q|X#9#/xz>fz?Pu,-z59+$Fٜ[HcAr̻525B|:QEI"PB(G RFzR."D@%rYbyCp"s@KVweqѪеo/67.ጇNKF.^đ'ش ?ֈQ[qm/އAeJ0{_;oU٥]tS~w0#ڒfءmyYq)pI=EySϘ( !pqKъ*˓/WW/yH0/7hqa5Դ4KBAx};`,ezT7 ׏Y"y ,h h/#[)՝hQ P__] SI3,2杆g$̱8-o(4G6ѕ(Qc]џKօ+ZM.NH{(#w,5ÃsKL`S\\"۴,X?39üdo6z^cc#{B kDf4z$<xr B爰hhhH ]Qetffҕar=T$L*[ypoT< .|ˤ*2 vG̔+*,XԒێZ(%VbQzXU ׏ZތJD1R_ W,2bՋڜϿcIYsm`Vn4KM8b\e"{⹐|g7Ęy8< X^4H L<[¬ؼ sOܹS C왣b Wf^`^x]yYK<^ ILNo3s^ol㱼^q{\SFθA~L'\~}.ļ$3rcP3![+yL Up6qK1Xn|{0NiI=V\ (hP'wy8" 6(p= ]mdBڦ6ayN/'hxe,/xM ?xM(2Mϕk¿#E7A-Wdß~m/RڵK{ɝ7,wq# S$bR,>6sB(vvvO#q+\cP5ܗyny/'n˖-z>wSwq2ñs;>w<ѡ'o<\e2nkѢE19 0Hq<itSr#" pPQL׫ӂpqKwi{f%iYN) c#\Qj#GɈBfқT2alB1e0 &7o7W܎ lɓ5\[&;1Vߏw/fT \G 1!]vY?b\\"yLއGɔǣ@op>Oq)䢸(q[jN<&_s! L3HP}6fz`yGLtv]YXŲh\Sϓ UQZb n3 z>봴Q4LhW2#fyqw>WgXfR]IF U"{d52""?ehh o8+gg.l9r+~<}j70• Pf˸ '3 ;3*m(ܞ =yG3JHy#X?7ȐYge\bay.\:r(荥ʢOeP3!\ ̘!m9?2 C eS(Vϔ#{ N+"n 3|/.|ohMDt/#x=`ٛaF;>2o'(5EF1럫òVe2x23eޑ6kg5+Cx{vyhY nmGcׯ_{ 8U ܷ9N>&Pxe5eXG*q|Z$(j߃Pnxh ¹c幙/f`@#=?@үĭ0~w]D4 S#H}T?S2ڋtD಼#ΣI8?%wqް򽂦w>A”)l3E(OT$lu= <ypUSxc/$*dSYYoUů@g;NRT:5kDz/1$yx?7.TPn{sZ5\K??>8>92xN+4OvB#R7Tsl+4P'㝫-7=y9R`۷o_n\Wb2Hz|۴8}ㄡf0zAf1;zmyŽ<'%ƠZEg[#8:_~9ܼeSekjzRQhJf/_3m- 9g0};p?()r G-aF/xY7' M(s +{Yk71z6:0:\}uX֯S[CLj|"e Ӆ F=Z'BaŖq42p}zT6/A~74zH BϙA\.Ӄ˙Τ: &7'hF0cw;&ŀɫ73@}t~`~\҈Z0~tJp§n8L?.~j!3e~ œ%'J77y) 3ǖ}%l)4ԝ\s˩|G8߈%Xti1#p)vRtya:qw%q}y N{ak2bw?/UeY^ɪF,%wFT;v`޽\r >qVTʉLyb,ˬY/xD*Ӿ$w9+ֹ>d)i >z1079En3Y/}KN}q]s^^^-[繱F8[DBsG&yϭmhgrY ʔVFMgG ZzړWȴ zs%QB:Q)6?&ߖƻ]޾@"n 3\\z1-[{О 6!\ڌ 0[Z;m'~]P{]a\cV ~pd]՘TO?S`7#Jbf;̱;y̙dT`3(^9rd3#jy.3W=B{5e 04H1j@:92Mx}"|6e9:{8A4Aiԯyf y$*ߞict`S+G[_>UC<5xR 9e"M^]6E3']6m-b՗. FFʉZ.H}'M^[^a #roɷow{ح -Mq8 I!̓èD6]J \a+'pi!+xEWoKZ0nƨQłf?suʈ[<|M(q,"0p*ļ[3:"A+'xѓ%@o#lqΟ`D ;ޤN87rf5r;"ozp{ሜX ym>bDLL~hebzߠP {N7T$ m&OU/0gfז5{=<Z*$piv/9AkxxK Ga.0p=-+σkT5F [!gש"><#'|ŢVld8–1c$up4,wdP ]nȢ5z#xCV~djŒu9 n; y1yӣ#P,o]\˯_ey?h{BXEF [w<=c ]5JrYyTA1[w cBG["n 3|Q3_5̽e6jc~|9Q 9-=PFcKS8uYyg91ZxmQ#rQld݆'t2*YB Kтe`r-+OlWLhTN%nt,õЕFv0V蜡E[ŮQ[+"n 3p4{#b>rE-߈5Qy1Us(!g4S#"kt5%3Ӑ9#:B1\$+nZBXAR!mrZ^-0^|,0c'Ĉh0E 5cYLn~ \Q"-O.NN;ЅD–(9B-aMDc+_䂛<~~=qy#\]c5! U.nǵ[T4/0g]~" ^ƭy QgO lwLI2쑗G[qa>PO*V_W2"n 3B|YH~-H*M|2^c7]߯;?B \|ea* BqȫGW+xyB/՛yqD͐g|伿5=E T^^=#b WrfcyBe%Zf 5Wo1!i{DW2"Y(yxm P xoP@Ě@ؚxhl]o]jK.%/& mDf-hfr 60#t!!lx\eX9Бe5E*A¨ 5ZĢw_k+ID./yu_AgU<#0#)$px"W~hf[KqU#pz/tU=ZAc*<Y=[!׷@-i"F0qK \fEo+3U=P,(,$ly3 L\VߓJE4>S}QJ0CR券%h*Us(fOdo-R$cTop"F@:%7KA@ |2 m m'L ~ YA52/^0gożpʼn*#Abj|ydA9[¬ ٌHA"W! %,oAK!AA "n A8- %P 7,z(a x2. % _& 3,Hq*P E!R [ )*Y gDA1% 8$ PAaqKAҀAAs[    ¬EĭYJg!0o9~bJ^ S3F [0 qKAAAA%    ZDAAAAf-"n    Aall,  |C-a)(0Af*Et-  0qK8#ΤXh[i` p>֙=oAAن[”8 K#KsE1ٮgBgQ_AAa 0.Smĝp\0^u=CYoAAـ[(ҰFT$|Fdt}J\ L'-[?Aك[BцD띩5"v%™Pt:?ft\5|O1 b|P c G~E0WAͺp̾F0gGmWd3g=kz%,5Q BMODe;Sa PQ^Wȅ *r!v #?# G*G6 7<\'g{,o2gk%wJW=&bWoy啗?rk? q>/i6grW~_n>?)>c:z]i3M^֛ okLN3G;n◿|yq| u Dܚ[oPva;ݢpT8qx?v<}^O? bzyL5"Լ.DzpѥWYMˈ`li%~c bLy&o2Q *hnjЍ5Y{6P1455omPLx$_}$vJOoĆfI(-u#c| rq99`9T;Q2J2BV։AG}n ;9t[BRp:}wLEWnFFW4(Glk>~n{f*xGp7w8[U߯|1H.o&3xH)n}Y2w1IY8ʒAM.KVj!GLG"o|\7z>M!DCs G2ӟT|5# 5WոjKШ:^*lSgB;θ Zd3es⚞g^|(.񍿫D/?/43}=?e+_Z\yu;O=K7oYhׯ_CT^c>swyIww^W\/|suG&ڵxǟ/Yl/_Żb2^7ٙS1eaLթ^3bŘ~߿۾zxWbǷo_{{\sbX!R {lۙ?x%oz[p]/u,u9nwB{mϷIwDH) ܚGӊɇp`|ޅ};"UeeQ*p[O(QrcArjW~)|.V_x1c n{,/7 d\(P,dαre[>b{D"xNiLc2NtC{[pCyylT''[5zT{o?5//W+umCx͖0(fHtlDV7L꬜T&-s,/usE%q:30.kdžj+GPm;B3Rq$ձN cW{/k.PfYiz8}x̓xy^}я~sltuh7_cǎkjgގPtb=zf/?j{?} | ,:ɻiT^uسg/{WfjtӍj<[xӛ0f}6F?b;ey׾4^f8(l\^T<2Y RCـnN®#efmGU3Yy3㪫=%:/ؑ#GU %'?qqnIk}v-Z=7ۇ>q_HA_5O1 '7ܮ_埌J&~/hÁW Q]ݤS$qM]ŪFeYQgC7ÑS~lm˴0аD܎w.7-t,kDx:~c? <[lٲYV|a3-6ԧi8X\~衇յՆH~8 4>`/\gg؁ش8Krz8!/xaN#vSbT*dJh;\a1(*VRU[yYXQRUC-,^^e5eZ70,%FUW(%XXō?cG:#mPXP!z ЋcA(9rW!LT5]wk(`}_3=wG544=XK/iNzp /~W R\uhjjڵkҲX'I~_CDkկ~]5~Ĩt0rs"޽N{>ŮB`ޚ|_ĭxleY*Oq,)yeMP t.p?kCAܲj^n/"Fu.}f.˿ ݸ=ظ2 ׶vUwi3 =*z ߪDQ qA.=/&\WǏJ25(nź6c)NC/E~]?s?ؘ,oܼbGQz]8Ldg/nzxs5XcWeO!lk_ wp39yG(sI) !城;^^Nܼ3jMWd/Ma22:әp?8g¯aiW=8ow"]E \g4g{۴@U=f|9؋׵{3<[U7UcKc`_*\,$ؤW@pvo]3؏L2_0CWWGW_uc+!tR2Sp(eta ~lUuu8;1zqqg`FWeM!]pAD"a Oi?wq;>Q Ojա|u:?x,6^unbG%KZGv$8QG'GtÍ^ /vzNL'R 33W/p{lLOn{ܚv|S0uxŸb<ԑ0b^O=+^,_~/3⛖ϊ_2dc-_Q}[y)!s~L΄믿%%%200O4?] ]0d?~amnz1#p# co]'J*e j ㌓wFu][3e]ה9V淎jp>&30 9mڛʈN!l};N ju}VZx0tnV]{= 7巿}B__^C#YzGp_F -oI9U dre3R s[{yl5V1查ߘ}w;2rNo1zٚs2ߞ][ RG BĭyF1sl}O^,X 6̸݊$ Kcy3UVނ򏰰e8#):'hMʊq,̛/a=;Q_ɭ bz?÷iWrzw7zO~3xzJqBps<*n^[E!hijL`̇>}}FĊ MO-'%;b"E/7i`PWZiYP d+JaB5^P(GwYP^|r??tZx4uN.K{*sˉqD ŅNJ浯}oe/[78mH[wu? l10D;Fl>َEֵ088TTvQlLzP0|^ XobU>1_4G&7H>u<oDBˌw==j^[gk"l3_W2gXe8 _x3TR$oLb:̑:S-XE7>ϷOԇ Dƭrx{XR%Tl;o\vvs樈z8{Ed-V&{[/љ.?>pn tcqGQ`オLڰc~ζQ2yxDOzLʨT E!3lv4SP~O7ʴcF2Q9Ydz~dK#!H\ \V,J1kj Mz>RXVEqGKtu%AP ;0V]-nbP x 0b.У(|V~} .y -3ˑTէb"6YUe4cZtη/ƜHyzH9ΔQW/*7UdO=e ;5.qpsǭ|}  m8=l &'mCzc 3 36@fa`^zg"'rog̰D[&a 6>v]ؽ{jkWbԑíѧ**ݛ=i%V$V"~bx]ػu\0pCu%V6 ,-e\ʺQH&ԝ 'FG6D4ZeCH95f+"nA y%ׇ֘73s^[WpudڛСgcU|9V#ܶlԫskhhy.k0{0^ل1>ftlOCZznϕK-/'Z{jsMآ8Eq3  ut) ukf6 ql^Ts/(]+qρXuf.B sG-7< Cc:3b2Zջ(-]ɟ+v@ɑ:SH<|;SH"}ާz–7|TC l,#h_G4HMK0il38CH)vskZ{[{wlC B}=agN/Ti >%ׁ;և-ޔK9EUzф_smΡа3 {Lju5&dJJ0zǵQ[FW9ouO? 45Ռʃ5YjR"Y[{JKGcuH+,<8yڅ \EKC)g*3g.>:: ޣtu? ێ1LNbµoj;Ig{ ZAH)DܚxS|!;][H#t+.yommn΍3E70q#l.s':N&=$.ǝ K̨FQ*aIG7oـB{Gm߾׿*Փ@cc[Y<թsj-ZX&/H!y%Ui b~--VU Ux}?Weuedz81'ߖ%0:s,q>SgQp:S+HX@,CgS#B;٭J (Ai,}>H_]X'PaY_];#nNso{Oeew==;'[5Z5 +fx$ϭD;ֹٔxKrӐZh-[>t mZ2B{gg/oWp3\XV/)[?W a<)cYͶݏ;4-ELA:SK5O1)Fwee, 9#kMvbMOڃۉc'Hm9N/wcݍO;j9>\y3=ws#&ޤ끘LUf9|1G-Gܲ0Nj׎; 6]{k*g.3WuU9NX,EؤVX_J99ǃBf+Rg ԙ\Bĭy{c$~{tF&zXSdMylK`ڵۿ ^ٻ{_[XBF>Tnq{䜌+p\Hf/fL;Q#ͺ#Lby%PJgpFF∇_rW;D<[^[[͍hhFz)qߋ1K!Ҧ*]~ff [z_H)P:,??fJcf!-WN=E-U`/A:go-yF@\fGa\=jC&sK}X36;똺:lx5}Y;F~9y c8S \X ϑ8b 0:r-$Բ}|[t,ˊ%RA(3[sBT }Jx]ZZ/^W6|+ !UEo6 )T7kZƢض.{'}Q,T4 \} }Ef:ަD"o~x_%%Q\~ey#{L9fM0bman*cTuK$5\O>/]DCnlO2B8D Vh\ k&6>Z뻕Q<ۗ/Ԟ[y%0:Sx"WG'8oC{ѨҋHx?۾K/>O}J J` +!;~%vU-wޫ5c;e)ύOQ<㜳 F`??Wqq-to7ߦ?'Nt1]M^.4v.3|Ej[uqb\rZs! SEG̾gaw+K1 Kާ1n=k0VT8 D=* [Yԙ #u0ϭ9d)d(%PõM^$YΟtR╯:Sl1d&Kelpq7}}w/,غWtԹjĭ񼵊СùߡP .u]={וwގƏ~v-7aڪނ%KZ0WtOwj7[woضm; 'q>)ayu^f'${u#:tRe%[VVnZ-? 80JR+{z5v$' 3u-?Лt=^g>??C1ؾ<6V%8<.7mRg 9r4/ؼR,ZTm|6%Cmm-&mH)Esk¶vyB*{_9 #َJɋ(c&}辎)[UZO|i_;t(E+sw9b/?Smp /ߢbW7n%C?qggI3o?ӿb:C5;:Vq˫ԽW6fk $oݻq% zP !o/0mW%'oVvbƲ3؆m'I.X㻡LA! f/Rg vVWWiu{FwqAn"5Op$5~W4aűYڼys.\'zUEKW=e^r&w_}ZUieܖ/kNG-6|q .PŞ={q!(nx kLNj#ڛ4륩F(~UoqJ<|FK^r2odu 1DC{nYX?e{$Plb!}hiiA08~"空2Pߓ>V_:6QIGF}{ں֥ű8,wxiqɒ%u=Xvj X#nf;1vҥKRt!u0qk+yA9 ߔFJlmw_`#jqhyոJIlq9^).']MMΈc)4JJQe :esrn1XUUU7=<~z;zzzQR /\.ۢ>lt1lٜ[Sַ7pG/?ߢ]_+VHqQ=z!@͏LxQ- ^q &|GpkaUdb{'r8om}S|~w9x>fOO˱aEZI LGΣ>{ψQץLu^}x+_w9*1;F2t;i* 'G3:$o|t A; pqsM7Gg,1㽦4PxE7z+ݣ^R6 Pñ ׺iy;j9ֶ9l2hδ痄&~}.]--M3 ӉQ?)7b ā4HMyzzNf[)l9!C@#%ژ#"2e˖{[&t=v옪3 16.~_莄n{f^lwܦ'..I裏gbUmmO~{{\uظ8`TLX/]~+3R{@lDذԹ W#uWyf+ꔐt+м'fE yBA"7)٧EێueKI9ͺ⒱YYQo@Ye;]{u15#Po*^W1k?WS^lb1_:Si5yђ2 0A&,T/ 55qDLK^ZDYk-[i-pzT^a#{{Kq,Zj޸3ܜ%/Nz("_'--s$`/_zꩧ={k [zlܽ-oax'? W^و1ٳD{IB[x@boe&vp2[r 7V괁^:| կ~E\4P6mژ Z+f!tf" W4ئ {gz߯~뵸kmq?/z-fǜD8;Tj2] т_nn::ARٞpDg4H9i/&UWd G |Ny1]gu/+ bi.b=}B=|/w_8( E闽=d^C.[a@8s^`5CXFLM_fӅב n(ņ'o~;`˗9B Rޟ8 ykI9Xʎ;t(=܃~O/*6- ["Q󾭪TBL!PlE[-c:/S);{0 G>EcM^5–9Wn)v3[>v*xĭEKd\xDKn䶅OO*c⇸wq'i9e}{zŷ.R-\Zn矾wL_4& ` :+qz{ywC`؛F =/\/ݵe/{cnfgh?^#^"|\+a:¼1w>G |ѲeKq5WicoID/2?9}ú5yΔhtZxq\=6,j?8vMߍKª|v߈ [nQFӒQ1*/c ֏3-IsbG~:U1U΄:;o׍.>l!օ##\N X\z1ԙL+v9v=)\wu)za\3(#3M:x-q#dQ<)N&؟. q7/;+(rmj:z:(v=8H)EY +eX/Z%VџьEMQ߿_hԾG<ҞQG;Ѯ z_S9SVzs+Rq眧b{aXd@/ Oa/s0< ]).& Iݶi,P 2/b5):66&i"D.9̄šs*s'^+(|x g&-P3'>zhq.dnR_rÐab&fOC=3'tݟ\ܸZi>zϠzv ^A+|J1c0R\u[Su(N$s=ٛuy:n\Jƿs䡡\ Rq{%W^9,\Uqc{|)h%=/{9WLѱxč-2Vϙ>{Q8y&ܹ:"*3n=3eJ}T+=HeǮ/+"ܸ<ٹV#t\KyЇ~CL&"F*ͿbR.ehK %vu5 c|Ju=,` .:ֳ5X>ڳ:ÖsΞ ;8_}a,$Ά΂r0O}:{腜;m*_#ʘW ulX.H)YHqkQ*1ϩއsL-mxv0Kgw~wN/eɏ=:FH&urhDFw^zs蹗d,{q7M1<{ 0X빒QDCf{gH5cqo3(z"^fO;΍>_#QV~rC+9s$WX}2{<& zy Gj^5֚Xn‹4.nK|5῍s%X0qn3l؆jރ \'cTCil^Qkl?GI^] /hDSMK7S}giX]Z,qG9љxTEnpB[(7x8{@hV,>(y+k{; >_ޏm7JK [ylǍ.xBQ.pk{^ӕ@ {m1y 0'IyY,[ o+{^~Ȫk?Y>{(,E:; ;h`"O<)lI8[fqr9];+m!U;]g+rALJD)cbnͫOkrӜ:PE d%:d#=<|rɐ|1^=z=jcҹ ;疳Y~Hιc/ ba؅s~.cd>ys9<:0whع}0hUj/\9cZBϕw \8s,B23\BDp9.yaab&i6Қ8mӚaM- H%H|[}!'H X'g.Cm þ elS8 CCx/x:;rK9,>=ӢScYF,fb:5Vt߷>ݝX>-y|Ed N̕^K"YuKX-uWi3KSf{.=TXU͘S֜4ۤ>mIp`JϭJ1/.^P & M |۽oYLL q맏p]9܀O+bSr?>oj|22F{kkb#ǰ3VY <s؏dve{լx*3xb-RCBܲX i)rv<ѴNCY O'YKF}QrnIjx?\\Xm3SpCs^M#JTw6SҐ Pbwf5 ĭ+5ĭ[豗׾r%Y|V[ULJB[ntq¿/0sBcC\ܼ[݋^jk[7^"xkt9W'D˚fu yuMCO纔]G9 O+ߏ׾H@$nF-ÛI׍a8DBy]p;CgqN'q|/7֯o5=0Vtd*msx!فuekk"%Q/$ssKNVr!m-%Vw6SV%N瞬mHQ|:_J$&&ee~~?\R!6-c%NʕBFļ܈FdAp0DN?U E,hɄ;oF]34 x1:ڋzt;}7D"*ȞYm_&(Ջs#E-J_|/Wqv_.=ip,J^Ryó),hN7KxZ\C 2ٌ0M.NÔ|k?KUR-XҨKU`˱e_x @̕No="cϷ%H懴ZeX"O{{;po޺ ۮ!Q>!B~$𵱫y*#M2qٸozG~5Gd\?&ǎg?W Ү^VpY˩‘ CĔЕ.BD@J>q&o2nF7 B.VTѺD}WM4eVST Buۿ@?>/"&7 ~1~ B+/~!l5!m ٰa$Q`)/Gi3%)n"bi F;J%sJH|Gb1}~3T. ˶nisc)p-mX+Ç _: 7i)W>lV9[R)QAКWM>{n|yl _zkŢM3[kD%Z!J.Lq)=ׯkU!{>Yxr.jٖQBoՆKq-[XhV W†2lt6S\a+{baHKui<(U&΢e b<We5#}YD"UV pʵ؅.)z͍;C:OqN"OWW,xr\\֠KX%FGV^(۹H"9ȥS\BKЍ[+'ъC>эT⧺H$P#N o}ٹV< ػwinnƛiᰒ] .\ p Ν/';>{Y|{?b=vСbHdPP,g7ݟ:_=|1::'|Zj/NrdO?,Ξ=+€oVף\ry^ _G]ݍn~+t^\ iÆjB"Ie ՊBo#8o޿ 5TR(TX_<А1LطDٸQyJU&YپȨP]n!j05߾W{š5k3e˱[l#}9?~BCfyzTΦM ꐿ>wfH?#Y,ʱ缜ϓms^׊w6۾1!whJH懴傔;W!=[ًOyBx߇c"nm]V?~懆e[oSӧݙ3gd3VVtۙl ^x5R" K\qN9*u,<[?}/oz Tm5sI1g1'7}:~a@N}$`O 8[fQa10'lv'w%];]+fC) ,$Yd߾%g&xA_}NNYcua<?"ķ7>ſRY",ʘKxϭ/>=ۊG*ԓD0z>9܅n sVT/skP.u{,x>𣣣]jqoWisN@̍=]b/)EgZjċ|||zo{:q/:{v X^Gr;_ث{ z=h\bݻ)nse^P($e ._ذ1Vn1da|cR\bypBy+<;LFLq#^+rYEֶ^8|4z~ 2:'rmd%tŻ{ZEL@SnNnpeQdg, 0, .?lKx݆M7(l dQʁm^!񱮿~bd[j2p \ijjZ|<؃.ʱlzҡ!A$-͠l:::虻~N3N$> pũe{n!sϋG)xH{81r?h)c9V;3-f]w-MD98UUBbʵ|='\Vٶmxp+|Da+byɉ_?p_{@|gm;qzQe^Bx0:o U;+M/Mt{<wYr`aoaw&Õfڵaۖ:_Jpl4Jkygmںpk%;T  ˴/B貣 M_ ŭmh h"JēE []֩!|Hp:ꨊ0Dv*a##̹{q G ]e\3ob!}s0J>.WbI(2wvDcT ƴ,)8Ԛ1,cdn60^>boF.\)Dsd=ʯ;ED"YHqkRRlp!+7^ &s깞0 zTte+ L]$7΂kgj9Ű¡6k !/^^KXd*SrJZ}I%35&[dm]ys7m!sgcgZq'+\b0zW=H$)nB\Z6Cퟩo`}xŏ|/𚷾#/Syץ^L@/\#3$闾=O/lܾ>ʩӾU=Μ9+ٳm2Bh"͞'c׉}-lb%OO|J=?9a('5E"yx\+=&'ǐJ%ɤDCZ,urs*ž| >V:_}UtdDL-~ys?Xp8!/7FFFDΒ#G۰7xn4peǞ8`qŞGE^.ηP$7fr6OhQx>υ@U ?b7sކCnI˕.{qb6 5# t븱\3>7ve'*\yYb 'WsW\e㷾‹.(E3bb1={Ø=z,sj&e^,ᙾ ex'gp:NGO$9ȱdVr| B^YÞYl 9?*GoUKQdZ~3E%vT-plok4>9BX ^l?پqrhܐ-Ns~/ki7W3307ܵo :j t~qNb>Lam.`[ 7\$677q,O,n4o}|ۧ}^< >_c>viI9a47س'rBXoՇ=xWP3"|Q$swhP4Z8UA>Bt\8wIg1ʢ7BW$Ki> ((ntZoXbJfDiK3䲅 ׯ`s 'o|[xk|gC=,zӈmIa~+I_K],f,. a1,A;-gkݔ0\l0ԀfC@xhjN*]siGRD`3{@%Ɲw!W?xx dib6tu$;裿4,@DQXnndͫOkrӜ8*E\."V﹕_"½sٿ^:Orwhp_^d/XDrY͜rO-<ҌHʕjNK_zr=ģst^H$+R6S>8/qoWƜ&ih@a> TNk9[EOP\///O;pwSYWZ:։iHG8 ^T_-wߖ-Y1blbC=Vde; [S^V"7 JFn_8YX(Q ݘMe,!g!nqBxE5= NA7jY3-(y_kQFKH$r꙯}Mm;:iq)e![|Y BcZ"c[fYdۄ'=}5~s/C62Dǰnڕ \xN3UBZ_ $\EWbdbRhywL;l\Z'Or2cٖ YlMl-G:3:o|ʭg~)WZzr\DԐ*^)GزgؓGS: yjf928$TH'QWSuhn[VYD")mbODV+E RhD, CRnDrjX8gZtv[o/BI!D" RZ%s/U٘GZƣuv ]#"i4:dR$&#d|^+| Xg[VNϙH$;3IIbC)m+F_ᇹ|X^_iW%ɜk=b*gDt2c/R 2rĮ}J\ͧR!+ʦgm xb^iY狭/gz=l[[[#H/e3gۿzfấgJ$/? z[(%t7[[aXq%J^.lL 0^az1Yrz\N;6kRJ$b̹0_!jyp<HV6sS*Y Nef|[#v[7u|H$R|U؎rlfanRn0W;gb\D.D|6fg~"mD:(fJRZf9U8bP[k ].ǒG"Y}$)a )e3 E-f[? _dX6s[\H'>b3%K )n- sD"S(;lĮ^",Bʵ3 \\mof1e%`1mBE",uʱ ɲJrɤNq9'n_δeH$+{lfk3JۡӅI$ǕDR͔,=\ōc\ޕn@J$=v{Xrmf){3-bPK",}.͔H$\ld!ŭ%@ j\M(Z :DdS82lH)HV fJ$I\ )Hqk`YD"Y\\ d% mD"ϕV.eDܸKLD6S"HGگV =jD\ i3%rELD"))hl%H$D"H$D"YHqkR؋&{$r~%6S",G͔H$Z6Sr ZWfJWfJRZV6RR1A˜̦ɊD"Y¨T:hW`cT4V>Le2 Ap&$d 2JUЈt+b3311I]R!-D"Yʰ%Tu E4SpRymꢔ\}Uۧ59iNn\4UR Yt %16⑁xiD[ӊ7q̷Qh3z(D"Ytt@ۺ/LS5L H$˝YlL̸ݮc4M)25'6O>y!^4pb1ŷ/ZdE]n{C-9rG1ВH$+ ޽H-LP' CK"(*6 o2:o))+!n,+ < c]f+RؒH$+klαcg%0.'K1>{ؿ_ [dAvM'vnlfĀ$ ۷'4/)YZHqkapDZ?܋D"dαcg@fG1t 8|D!;&{Pw0 $d%3 ws ϧi8;d#M"ޱcvpG1ɉ/A"HVdfr! D"Y cW͔,M {b EH$wl,f:Od@|m'C%ɪ݄7g)Y:HqkP؛C1drTDD``^b6Q%ۿLᖣ"J$UGNtfe?`A"HV#l~\ܰͥl{Y1FhWk``N63 B"HV#)c&#eLB[KpĕӑAH$jTxEnz"m{pu XR,gffz&V𥓸蘓͌ydN"N Uh3eF[Fo荅!H$x$g UU-Z(8Vbud61\JzuI5e66 *WjELRnEHg;)LD[ a2D"F,QbL%Jbs簽lIV]a5J2qVZ#\m %YMff{VdW͔,- Q%Q"Z42gyl6+f;g}mf[?ߔH6RКIZq/p0H$<@K[NثD"H$˄rE+>/,Em\(=ZE!PsJyʆd5Sne;gV%Y^Hqk!_DbPnJa&aPԲFb}eG"Y6Dc*s>O>`c4k̢ެ ,%ۊeT-va!-D"H8bVn*n,rU^,1V&-"rtk1HU 4_tdxh%Tr%di#+IJÊaGY"Viy 7%DRy^\,r)e\.7;Q*ZӾmcJ$YӼaM +FRF[*!Y͔{d%bEQJزk:sr1-\.,EJ6`"Ts^gZΓ\= ?3 \AtI* iǖHVJHweJز,-]z}EH)nI%* z9ʆdbV1RZ$lef.d{-Se9-~Vb7 ,}ySyÑ<:=\L/.%Yxh6{gZeŶ/mb%tE+.pIKrPZ? dRl6Wmo+GTLLE)jYO2沬eS< =$˃‘UwwhrE|;il O\n=fmg~K$+iaޅ6jjJ_"HqKre)Wʫ\rdC=+췻WG;.)tIeMV.Q<0K>YJV2 UQ+c6 A10o rARjtoa*ϖ%r"d\pÊ\lLs O]a [>O1CFSVxjeyrʣV)QKX&pR%v \:Pu]ߒ\v%r [%+3ɲ$U*VZQLXE"tDP Z!0BúNx~x|>8uHgFQɕ@[+C4Q˪pط-UPurFjr+`U֌>ӫKT<')p -k+k ;LRCfDžX[[+/]Ν;088RDR>iϝԐkr^7CKKKn^aPSS#DX*5|>/$bݲyoI %[<ǖJ<ܾ(g@&3:NS3!zDr!-g&a.ji69q*2)N \p\d9SOSB1k#Q7:O*C,9BOUr &<YK;x9>FGG1gϞEuu8}4G~:lܸ311EGGXv9!tטIu9sBHw {.e7'c\X[,LN"䮳m,BqR1zƼp› YJ̲쨴F[ˏup]lxQ{DVsO/HK<)[lσ#8 Tney FQ1%4abmY fyn'TB;022"`0zĩa^Ca^[۷o'!ثK2?PYYb֯_?m;ƍ3qሺ92bHϠJL/,>D Y>@f8Dx3/(6Do}^FF11͛q!?.uc|bvl-ve5m*}A`uZ"OZUA[+Fa`^(@B2,leŧHɓf[ƒKql_H _3i$T qK|h5bi[TgCw B!mjoH)q%Bq2G3Ȇjh,:6.#43dqI$AeEHX.t! 2A=UbB,ukۄ0h16Q<~t>4P5 / s0K[~/eF7?{[3xyH g]۷eM;j=XzJRܒ\^ +߭[.l)sfziiCbwWL8M7%/L.- Q)p$Qh5\S.8N8&^YYgL~{Kzs-J5%D-CA*x3plgSLY)%Om[*Q).yD+[nKn8MF4?sܸg褻[rin4ڶBSC9laO 4ŞWs񓧰izBmpᶛo2I=^76_'i}#62bl+$WR^[Su3#did#Q׽AHJ:)uO&b Ju9R F[ ߹"i-V%.QdkU+g^͇aLX-mfmhzς|[^.-f I'gEtңuuZ;m☒n:8dys?3vǶAsaG^9\{M>̟bU FF򞹼gPB%HqKr#W2ԋJ▖L!O6Xg.:_60pc, Q*a# /WċƄa Y0ah~֗~l~(cZXaj3 I&M6U7ƭD<[>GG)5[Q'sz6zpZ\piɼҪf魕5 @lc(GZͥ]dƂkG"Y|',-ڞAg܆b!-ɕ#gl߭1YR5<242"~v4'ڤbC:9sFBcH`_{ߋAy$/ξBL.\͛݃d*)Qx ^7rXƴ5s&,0:< Z6lǎkZ[gWTDWVQYSU v/+ˊ\By _ܲO,Uss$sŭ0F&70`D2)QU[Օ!iduQkKק*+=&zM.ޡjH$sLBRλi<'IH)2HqKrUԌdYjh$pHT*>{dq`*#>b)- ۳|)p)P]LJ5H wIq o---dSr%䲓7ƶ2mX{H [,pe17񷊤}|Q]a_:`JP/=7خn_lgx8Tz!e3$l09036s"X~hɼ4ee)Q#'Gm+ԲRO5>-ϛK>[u%K"8=7g'"ȇ sʖ{K*|,mJ5- VV[[œ֍Ӷidb-+'rYl/=&zAӴfMTl)Yp[n:8wXsD"!RU:Á+M.@ʭ3B=\F%2jj$ \mmLk,孟)~F被gK6F)#{.C͎mMbizwHN2ᚫX9rόmzFeZfI‹ \zYuIʆѱ1@ o=6?05W/Nr\y+_\,h2eQ9F^Wb:t(UrQ"[J@Gc&_z|3/Ϲ3]ۧX7<}ʴz[l.,X憹CSǰ{)*,Ce.~ /})Q3isQb1KJA.k+%*̷amyh!,9$`=V:i~@z ,1 VN{NNN'￿qpp=8p-1!Jt NK<>l-,]q$"O^ӃO* `Woi(Sby^΢{i^__/,J'kJ+VelJ!-a4-+ByiY.m<#6{s^;ӽ틩Qrݶ?Y<0c;ŦSb)JOY֧aVi"fՇrg̼~(W1m[z⇛+b@1(?Ksy,&6 C}JDa;pH֩Z jfXG@$S\~_yAzas%G}YpO&BhD&s?G$^Z!:H&PHxk]Z<ϧy5CCXю',{ςU1o,+j1X\v H.Rܒ\yt{H"l FݞSΘ|㩔ڤ`ERs638\.sRi4"S}7i!9+k0) yු"u: 睫>EPf.-pfByY奇ֲQnFDaon߫qlM{ ll-3 C=8}Jmٳg76m$SI"ȈjhhD8,g>󒽵 /CۧJgx%B/^ކR^9b1(asko><́EwSzdhe[r3Ju x+.إDI aL.nrz[,f QD")V&l{KĈ3!S/R|^rY 3_tObϢJ.7Rܒ\r/B#[C槹Fp1WJϸȆNZVvbm~t C^*P$mUHIfEq:#$. Dž^NHE"$̍;auvÑ #԰H7jQQjg:jZh h\j;Dڷ݆hd`Tj] LT`8_M9T:ٶw$*Ci"Ͳ|e8:1ʮ(x?kƇT^o-{ sYBH$HcPؐ. ?{N2OtV`.6.joF[HWON,53Z3/.ux_65cr2 xiƑͦP_Gr4 e 7iRCȤpQY = ! ]8 'MI >4"#]\<KAVA6[!4KPRمh.O9M)pZ91PDݦ"QftSRLL+/Ʃ2BR)k}XV&_dY!nY"jQy’C[eFsV$[ogϞb> l [lgxBKZa ^[$Kbb3Rߕ2M}7 0ATSl5>duiۍyh \ۂpGpBALd8pP{diZpSie,(zsS%xB2BIہE&c[C>S~xZX"P(MV6UړRzqy[eOVX;۽0M̒zX xU7oބ/~}8z6oڜ>S}f1=%J$I_?v6}6\w.=C+1}=SZG$`rWra;H$O|ΝĀ;A[%$W ]/[ǼJypby5)s8{^%HP}9I ~hяk8iP*ڱɋ.>Ea>em#>cO<#ljG&c!W([Y찄,ۼMD]HX6=RLҋ$OsXT&b~>GǛ؜~yD[hbn/!(=VnMMMbC *y-7Ok}!k׮H.7:;s}\ "Xi&Y (~F|&Z+a;w NT~yabP e\nYV J g3xnGD[MRD"Y:LR'AG]z>G76L. x>aT?l]F{$ ޽(_Y,%%%3y̟ټ, txU*(wx׉3BIԵyutA e8 1TUzjSsͤ-Q|޼-:u"$l")$ȋsm%ZEԼ6 [~Ba+D[0?<ͽd^ ر*O0R,4õXrF[J^^R^9jɤI:k\D,ߌ%PU]mD+hQ444`0(4FPYYI?x#@t`c(g)YzHqK4TXzz' /n\*QSp~R*Ȅ'0 T ,p;0&4JS6/fZ2(5U .p(t=R[0;8p3LJ]?M*I+(5,cHJБ^ Ceǖ- ?%^ "u W 56zHE'ѨKa4ݸ6܍=7BED[#0Z W]#6z/ѧ ;q)!^}ANO.=pnCM . Ν:-AJ")gLyqۇ 7I=qYR#S! U*}wh8I(HIkE%'D= dE0vy^9tu77rmǴ& 3: YQ]a,{oo| G.ž:ߊ{ކ{g먈:&B'ڰd]ZnݲQ41* Y*NOBĭ!LfRg4LT 88t\؄[lnZ5j^_: LG1*Eb}rR2T.Wvhذ!WT7op?'y[ 0??: 5i>6{_y^&;FAp.ť7·=cHFDAնN!x7n/e_ w5>Bw{o2FƬje_?mvɇ$Eh(F[y9'VWWZ[[GSO=믿^,@`͚5Bb[4Inn@.XHqK"YHqKhnXlӬcT/xZH,j@Ux[:ZFcv~{T& Fgr 8I:гITP_lb-vAoZ_u3ο k p@U2썐Bt"QF֌n LJC,k[#9okXj֑Dbrp;I&`*,N/U|kk6$zr](3 Wj3msifL%ˑ B hhв^V*4zx s"1 &oc/B;>dT+'u!|3!$ZUL&iK;|銓$MbCh,|NO7llz _u1d hHRRA)!:N=?NFq*B$jhFމC+<tI\~n1/~CUKCwAǠUV@NBc*tOp&p+Jۑ@N',:]|I<xݽ{+HrW0M#@2EҐH套^~AoD?x X(nF 6y$K)nG%JRܒ,ig x Qpw_B*&xGF|V[d*N謪ƻJ1Ĭ{'"Ȇdd?؅Y)횛ߏr7nablwwwj%H$ D[%BLeSPJ*)IPDzؼ~:OGeõp4S;PUdS<N=ʪCDx]A Nq/kȠFKj,8]xatlҧD]wm`z[ٕ ;ϋKs2 7 G,Wlmz`eMFqϽ>mk&f+xۖ > $+׃JG![ {%[ aӻ߉z&QIlXSgXy'lKGh 4 =- kӋxM#ú*{*x[CWp$uA]pL0ʐ&Ѥ'Y1fG!FeΗBP9/:8 Zz*@PcNyj/lj\H$qL';ΦNZ~ĭj:F7*ΞaNSrQ4]S%3HcFRS <ۮEQw3P  ϊi%l҆_A_ZdN*B*?{PF>~8eNvӝ7g|u!psXIHҶ%$;FSzHr P {eƆZ WtRI Tuc{hkԀ`o-BdUMDT-UU'\ !F:TwTD2/"$pC"YY0g Vϱnzq_}<>>.FGܼiX \$]"F&H$!-gTX]@|uE-R"Z".8pizMKI ^jq%$ڔS&!r?3Tw-kk)^,v4E_(S'c[ym),%l"b [4itdؔ5[O?TNS+ض&J}ϸp:QCJExZ.R1$X, ';-MDZ Fq)bC 4;ќCg8I"ƶFIHP܏F4]0GW>|Wpk^8@t Jd8Yyoz T@g;7O5yg:P ĕVUj@Xng8Qh)DBjfvჇλį &.5HtAD4d9Hb*H @D\Ծgjז ̹Ӣ uH':7]Or@*>!x^O5*깧r>?gf 4)8tzMdtGkDAP}Ȓ<~*Sr*>zUDgp2$f^(E"D^dt\iѵ./P'Fsȩx{A5-xE0d!d씋{S}]bZlذA|r/D", Y(sp.jMWJ[*$hUGWхJdCh7N 5iPoYKit0hTlm2=in鵥\;`S`2%R"C Y(oP r5ɻz|(6󡴗\$2? *Bdۜ}Dַ A\vtzU=$Ɛ#o/Hڇw{pqLNFEXI&X~#n~P'Q[1ni@&#9KD`Ou>L =1@h~uE*BB2=X06.rѲu$Mfc#P1o$R;ԙ&y3!7BB(4 5$rE)!j3%$/G1:Z,/ZW] vG%uH աD췾 Д 'Gk߸qF4=ՐK4in7]5?Dt}taQWHHsX!CB.;pAWC Q͍Lu7\q(}c_:/V{: $pCszE(2K~9xdBnɢa-^+Mnn7@"H$W)nI6%[( lSz]DFpm<ҭe,W2L/amj )RVyTD5 ˥X,L ,\RvEĭE]\:rYs]2ӑnh?g,4Jy"J ^r\%O?"بܪqf$z hjy,wvL pKGLVⸯ.|iLrOi8T хq DUbǡ>}Z\!ؗ@/kZ+HkkA;/+W5Y"ϑ01fgţYr"fG5 RŖHJ5ڹ8q+dؾ} $Eb#k#Y:HqK).R3˾Ne]CHc 8Ěi p҇cm}wؖY ?3Oi.tOT5UKв ]vZ`X`ZJ^䈹fJR_bW_E7%m~}PZȲ!E-s۹pY/\^AeA0N_ OvSj/x' ;'1ZՆ F:Cx/COۄtpD0w{ IJx_^;;pf*1K ^=a/b; a]C#;'p\46iFZwХ [&ZVG0BT.ιŶX7FU蜵lJ#CgnD67$(Z&){ [,² 3Dī#h!U#KI<4xA$NoYd >Z]3\~gG'ox~1d2=z _=t ox!81zZt6d<b8EAOP[Np%G=8?+iO>^]Kjzp7A "ۋ#pe'!l@GsB7y*VTӡ&{Z*UUPRP>wFӧpYGΝ׈Q'PSS- bp`{k!H$C[%Ml}ҧ3٠( %(yir -H.9! .ha6my.@ +\VxiJ򒱡-|Ao._)f֕s{؊S(V^/ط1iP:]E+TtV ږEAdϓNx։MZ?^ |?9mރ?*V'8|=Z[c/=/)hX:G8F8_=7]x ]ص cIx[Mc^9E8 %k?tgAyYС)lpD!oX!5+'4_E"ո˃lM2c =FDatt-.o._$_WH ĥ81Ṥ1 w1M$\ Ǎ +D%D'ߙz,茏K(0M%SEg=n8h T-PDMBD~!tm&qK{fxMgXҞKsMenmAAp$Fee%I\B9qgO:d_~jtaiL<8 a܈>v6o,}sݺ܌R9 #T{7__9D3:DBaHYH@6X*7obI=]]#UW: /еϙ46W[gd @R}vxQl^-I¬NJo'H*M5+[n!+)رS,۹sG6PD"Y|%YQJ+[ &ecAKi} Yyb5o4=_ 7r|-S \VF0d)*v)t5ZV e%>ک2<4lϿd0_;'̱:;CwUzӼmPɜRi\}Pڪ[p}Rκuo~;Ј/yHΩ 5wÃض>u:w]Yd87?!+, 0 aCWMK13!N,@JSJlKsP$DCPHu_]$[wB:ϳ@0] +y2;{M&Ϩy@[rc8FCotI, >{#)>Ũa!nt)#SZ v Hi ;uyՏ=Q_5]QQ8$BeF3) ; u/+<< 2i'Ox !d>CD$CDVJ31Ab{Z[#GL+RbAA"ϡѩ-&,Ѩ(|޽[KSJ$)nI4WgL,ypȾ3ey>eJς .ĈESܲcb6sԠضUrq\%`Rynr6$>TEWּjWmvlMFK|,ɕ}/8F'lƔf@]/|ԼxII\.8IHz_1ٺ &?H,ֿ&ΞE۝B(Ĥď^F؄1֠iYPuCS? @uv&XDeƪhƅԺ !s8~1{l}oل=[g 03& FF!`pX8bEaKiq&UNF.Ah*U{x_s9/<d&zı3 ab"PItMal'lm=wD,`9$F!yI<QxnUWWnk]kY۹Q?Ǚ3g=ֆ ;H86m܊D;Xq؛A? x""Aک=_ ֥1$#m ͣ&uUHzt,hD MNq $bړA\Fa blFYtcM]vH5?8ijٹ۶md#-dy -ɒGR n>*&(Q (x\ֲ>4=ɨכn=X:q XOߔ5% RDZ]|qkj^Q5z%-FMز \RD2q<[)6OI$woϜCӏ?&5oCsGΜ=7|GxX[!DUp+$B5ytbMBEb/9@zIbϮ8}"Gobs( w&?M(MB,Z J%y<cMi$8p'-k_|^f\~RaœB琌pAгH{Xo;]邑z&-wF' \΍0T:xM*7m%̍q8 ƍO~-P6n;jN1ۇI#ޗ,q>m<ƻf|1 ;,DUu5ưw^HV6H$rʡo&&&`/)nIV4s!rPG*2BfT͔R}*D6.4+mYf{l*]+vVxm3Qy|atN$a9TqpzGo6Jo 3DR.NjD I'Tw ^P7o۵H )g+aMZT$|'P_K3jDndlNr¯#;QHTO"߄>s4\w+*H91TҠ CYv!*)MNn> 9]zN0*6ޏ P Ct?C"0FEy$FeYn'I`A▞.LaIt4 1[6Kd65ke|is,裏枻0\MMp:~9' Y\s=⳧GO>-:"C֯_/_pè.ݷĨ۶m3*HeV(Kmm- 4%Y$SiĽajp>q!f_C|v\;^{;**~75b,οrguY*rPrzrދʚZh\7W|ܶ)k7= S4Vy =bFŽ$erd;c"7 nkDzT =}8^O2?lh0&It!&ΐup7 e6;(&zϣƝAd qmمdi\s͈k8рZ} $m۶~SK\nX1y:+Dj:W [$pbH9vHYČBN,Hx =$3[M6gc)t?}q׋g|>$>7CWV8HT5|ϟ !}?mك UA+B=.mXSq8HPI\>ɣL ,!Qҍ5wA8kkl$TO:5Up}EיϏxhHԯ&I^eth[.Hz{4=;|Y8wg;d31;^`;GD걣?g?'|oo>яe|cÏ^xsE$KElK}x"_kk;8bKD2%^58vlۄbdA1D 7Ȩ$!dd< ?]I'UFnB^h-UJ2T(.\/`{9'sA<\0e$H2C':S-T2yD|1K_&.n1;G#pj=ۋʀ7'n=Iz⥣]$*-HBqzį y $ha#}VoA.C ,lBOc-nx=B|QP_C3jw߂~z' ꗿހz vN#{y{>i#<`% DXRxއ-MKcIMp7@IϟN5ľN xx/NuP;5l|A2i˦uVI]tZ*!rw΀Li|^A b2d+l5ðx͓D°]?xe:uZ|o ޹; RdO?-Gsec!t-….<ēczBzgwиDGﯫÉ'I2?|>'˿@"YiHqKaQlX=5O}'&IHBwZW+\KTH+.LCXJUs{jM_@e !ħ:PAœGTYw:Iض8c.Y7 ѿ7W0D/UeI؃O<)`s#,xq;<”cf q3&I= 8,D1K ۷Ox-o[/^ıcǰf!q>.qtlPfvuslDhgynin/!Ƈqn8@*c CGSaU UU# mI T@#{L/9%Ctp(2!vk4܇qۭε=#xs1N/=clٮ[q(DRȳ>O'-G=~6/Un=w{[,wJ(fI;}{n:>nEoOodܬgΜp>?9,yz'-]ů_|rG[eAk Ex=w]8La1hj6+Vc '{X qܷ5x ϴY^Af}ςU}/Fᵰvc1: A@زfꨱ^W!~`6J`b[{Ë䦆'>ȯ!Z4Le(7ꘜE(Ţ>Uh$|M9GNjEq~x|Ax1E"f:s$RÓDr%`Q>GvL<&Oܶ[nirgȿwnQBߗN"YHqKX=9F7:-J\ZWLҋ)`\YgH5z6.v =r2<9ng)]8M&L%CWc3 ÕH1a_jBBʑ0x vH8jmFSr+ ?Y>\ 5$NĢ1hX$*Ĩ݈*?6n݆G{ v*`tDKkGihY'1NTN*Iao-<8A߾QҎ43j J@f;&4£p|$XlTJ:6nTO1M<=> -C-4+\wPE#Vq 9ʮ%*PAGzx\H$DO # 7.9kZ0'1u:HO+!-9$luNykAuȞGc2%raqO$ !Mb T]4^\bnqx# J""%<4U?O@·e|bu^*7m9}݇Ǝh$ӹvDr0K``(*R}TW9rD(rRyk̂S)V4+wTF."m1Q$r-2*Hh>ïx[szK|!IHqK,#LNFu1Pq'q~;zvnYO :Dׯb'%H$=Ԅ0xZ7t`h&ft(^xć oކ;z  胃5GPΞG} 71>Dme}];7*@B= iA*0v;ʛ c2)#tBJ.=v؏'I"M—CX"ˡ8iSExh8dC( $ҐrdNL*Yu#Q%5KW5Lx5oX^[i;'###"G5rbÇEx7:Y->cعsgv$΋Kܵ !|xۄ֞KbZB233NQvKD-i$rdYpm5݆ THsmsBѢ ã㸜{ƣI1yOElK X4"_#9i]mCoل 7x{/5bo>yx/N=NĨlj *H|3qj'ކVOJs@#%`ݢp|pwScaa {[GI E5c8E z_~d2i\ \hJ\!c``P4v$Ҝgfbװ/….+rw/BvIZ?^v 57NHPOD}V^mم&tz!4ތwV+niBrREGņI Vک q<{_ }:=$:߃/ġ]:Xz ïݺJ#?F4,9] 7 )./$jeHGEx6HĢg?E;"x@P NӴD3Z*v`(+V9a-@ȕ&,"tvfK;? 28,uzlKBϳ{ۛ=[O ;tw~nXی:nASe<хkV]h:!wbai \<%YfM夯1q+#$l;ׅ߅fUbtzWeymXilj&H0\W[KjܹM:0Ip:phpm1o [7x>-y\JPsӰDŽK駟FK+U8M`ϥ hhibFxƢ $ҥK\9 h###2GG xq'-(xݖX^<%YpjɅZ2,,u3G{s?D$ Ome׼&_7x,,fa \,OEݸq,lv\O[6pÍ9oB0Z[־@rY̲D2#8p4 ['iU3.`v\8ߏd: goFֺͯ <9Cu8 -vb5;GŃ_T{@|$hd}~V2@MYOMko8q("P~ Iw$ycpF9@-$V9p h?A7* qٌa[! z=t0'f2)sEَ;y58E z L۱0ϡ,Dw%{Z,έ#$&ֱS8Đm" azs΂TXbo,chx>,xx xZGV|;ށ"w_"#Hr+_!sIO oiɊͨ~N=<4!E:3akeȏ"BHp-B]ȢX"2K\T H&r= &8uQ>DR>zF{"n!v㔟{+'xP_;NzJH % KHE[eBގG`ptATVb1!iFоh85Iy5uݹK*DCIIb$^ߨVLf#mwODwjxl:MDci['#컈X*;֢ZuY Dp)^ ,B[t51;HPeN_$)&ǣ#8|iג Q$/lƒ-yl&|AzH2rw'ETEb)葠r@x?>3.ɥƨ\V#!Yҕ0BWVfzn /r*+еD.Z l U\sX|;BJ$ .^-qK\:> ^wKsq']vMozHJI$#}uHbdº DrqX`M,5 AI FNdo!`XL/;G:G έ 14:PkZ#'DWvavP4sK"))nINHh ϏzN;p9v퀖!z9vx4n;?TA.T.hJ",9 =1[fe V2όd6NeМp݊&SF֫/bmk=/[I8"i ȝ {{ɪJ^/N^yYNu3B"FE~3ܐnh ?=Oo}1a܈<<"^ĩ# Zi mrTx}!TV5 ɧzKcktк+6I Y/j <$( ǩ$1hH@Ĝ!a& ъÉz'8Hrrzm)£KȦ8BW v/G \z%Ǣ`erbgWdኽXOb SϲypFSȅyƶwuu\h@&ΚׅuX @ ZSpqx'&0Rw|M.qADɌ&㆒7 #·ϕ($XdM бI,~TW0 nY"H7%=$dER_0mYu剿%pE_5Rb%(E1 #FRCC}`O,nnyT.졗H'mEX u#d4V!Hʫz5" cY9z7/)@aH3iv܄.|JZC8DI{sY,P81|e,~{WqxޗN8eo'NaIy;ޗ;܎ͅ  ^\,5lL\ .+b4H4HD&5: 4|zAXtL1F4E'ҵN шQ-A:4 b1dQh \$fyoKﭳ)hF ݣ#kJ$2_Mx+IqK"))nI Gg-/Lp8#{WYg5tdӖqFGDeq.j`QwMMu,b;6lVZd!N)fCNLӏ|F$[.UnL?CZuU5~ɕʷ%GKHG[e7Tw q땗  $Du:]CMEC#Qߋ*?yeݱ*ºhbyԐ1_4:(>#MұB'2! rFƣ| Y"8\ƣy} ~wu/LR g7K!3C|^!(n 42D.#RM^,54rI3>\t8T J '^O(j8҄MD͛pՕhnjWCz8bUwQ߸qKrI6T/PIٌ{6W#Ǯ:7Ԋuxg~s<.kgp'r'a>tm^l4>FV8xdۺ/?{ WZ.mm>Q"FHܪ`WXHZ|ۃd+:7PZEJ͉! ժ $ՑR a=2f/M3A$ʀG`tC^E"$Y1qjI!s*D{z3-Xh2~Z͍h}Ck]aCγgro|Z~s'B._nZ0$8B٬*$C!B LFGK%U/ƒR6\kQĩ$#U?tڛqgj1GTN 1!؉x#ܼ6L##\1.h^lI C"ue$_ ɮ^a~N9w Cq66d~z~ӹ 1zԒ^SQ@[](Ej@CȒ( 5`8Ջh‰J??k":pĮZ5&lHX L }6u3D7=UMH W)2/ְDt!aKV09{il8nE-b$ VnZVE$6F^@W!b 9?e9PxvW SVB=w !1>&uy=^^΢' E #43;h8,υ\2ٴ D/d ю&5CUt$西C2#QJV䨬tp^u߬.G\۬ kl|LN9U $-žL5Mk**)s+HqK"))nIC|n魛SmKNQ Ի]]m$ۭfjdDQ]UEsUTߦ&@&o/ 52<A+AZ,IdJ y)j$1$*)$銳]kbↆ2>FÐ˕ށA&ض}Ν=-H.A2!>n[A(T!^[md~3i?׃;w e1nH>}q?Ξ@wj]Cpf#.9:H@Cr0׹U?hkG(HK#t4#pI8чѠ5'NbDfX۠c(Eߨh́N z44M!D*j׀SxH<["|ւbo$j"d&.0 "#%P=\G9 FN)=28I"P"d0|Ȃ{WF0^6ocy]qC6vx98\?;>n@xྐྵ狊[bЧȻCC1rv8f/)d.0#St(u'WItSH(Ѕ .!@KScOxLV}:̺H?s-CzSsK3b ;~7Dh.'kxlĶ~{$Zz۶m`*<5͞` 8 x? R)ݖ$ p) d䵂ȡU*pN3YU^qaK^ZaFf+P[ S- .^rH-PT8ұU[4f كs06d.+dѼ,XXc-higCuHO]kC ׁg <8:3 ]T cL3dh2sZCѴXYط]%P5z9sDrpvT=^̜.&;Gre!Db5R%[dФUԓ+tQ9NIeQ(O'?_ɔ!B62'eQT*䳙$fi D4ZOC_.*I*&".x+2x@\Fl'ҙG1()'tg9`1pb1bU%Ȳ9er83r>kFxeqty?XNVۖy ^b7gCE&B# [»iz[{%TT1Ғ؃}h'̲8CF⹢[ 4IG=>g^bf__;ܢU,80 d0h5L%GˆNN<~_K0,S鯂#6ͦ&{rNйN_ъsEb42dhn2s^|Q Ou/P;ΫpjdٍQ( 3\^P"hB!>/—v4PKft.ʡ析t[| lpR-aDxt y2N-OLX /}20yTpa&t- rN`}T `K%IŪ-{ 0HM$Ӱ d!]HkQ~*D\) G`D@~I ֢Ba,k\ڊ J09Ax,owÖƬ}G86v4!z_L"8]CC.LY'=؅$1{hip4R1r, EimJTIVkReDRhJƯ4AT.M&/E/.JR<2yy(Uepůs.,k9Lq_3|1DpB)'=A'~Lw'鹿tTDq5I2cQ %,1y3#!X)-pGI>'`(Gf㼌 \Gm=F >/rKz\&|¢' ͒Ǿ^"wE]]FFFE֖nfv>\oK1*:%"#v,bAH`ϫbwX` Xك gnUlS'%VyhFAsWzkf;E`孰RS⢼V`/7?/)~hM(YD46\Ndd pqh8A觿1r4ئZؾE#2",I v O"q}n ظ'!PiB!+_fα'<$t/Ja?eHNN.ιEJ& GN{O'q\&B2W%ӰKReq5LZAUG˰se4 a<. ֯_/$hGCN{a?krh1X5i.}׵ǖŇZTݛnpp?B_@F&Ŝ V?B$QX#P@$M t-Wck1׸E< ~x@_ς4Ԕa5^89.ŏy){ 0X;ՕI6Tb_ &cm}⨨,wm8y{OO7ɔLMu(\}Ԁ_ĎӅjs=^{dD-^W@ 2r tLQYm5+%1<;"58ώ!>tXc ږލɉ~rkSʁ|*7TEHb |-+\-< L*<Z ҅%epQE]״ )[ct@Xsyl[qAf[og`Iݓp3ȖK:+q+co(`hʞ?\j\_gYL|esO^o/ᶁ=oy +In?%l//t$ۄxJF0P C;S :ץ^ :R2tNKp݅#6jjj_*X 8th!н&>rd, _Qg2cYCD!"ڏ)c!B^g!sip?mډ{p=HF&s^vY?7܃ʋ;`> SQh.:5?޷&$X`z12:0dx߹BU3 'VNFG}*Iblf؊:hhns{ϖcl[x޴ץ^v޴bْm!C NTEa2dhn2B F .pzܖ=h\~  _7ζ*d'HTX(}_"O+~lݹ EF8>m6ut߾b^24w Z%y b X2*Wۚ奈!UQ@SC^z,T'UnG^2 +!F}ndðZ-@[k#v$؞r+qcegM&hnn&u5d& Fߓ6׋/ mƐ$0gu1V;3fNKM-md@p֊d H\Piȿb\YV3F{O^9U /VC'/q15ky s z2dh.2B|vjLLLdن.X.nE$?׋'E](M~J ;2X:-{q !O`5\^aA3JT%SMztQW98W '&SY[ : |^*uxdHc"'N>_^nv)&a3ş:b[ӃE Гm-G\=}ֵ7xUb_7n|AT3X\ezɧb2lݶ+W,Go_9 r8oQCxhkmO<6a$csK3SS"I`;DUї.O `Uؼy /Y,([x1{qֈqxqJsNZOO-4$=N9|$A:ʕعk1Ncj\m}>3xbr;:GӮ]cYEypbÞ`0(T:+9b\7A3 G{v]i3D :GI :>c.* ID,2J Ӎ[Pzy<*(xP B=*_p%vwn]Χk.P,I'CYEyySLP E2@spg:<JW9)zV9OT9M#OM"kșΦ|PNLv%eGG|j80؇>$* {jMq`٘ :%18!RIk;v11 "X@a AwwB'°,J fdUKp+Kx456tn{28/C!XwL9۷`\*:cp+OlrrJxr:O3a>fW,pc A,\@|7!;wP!/P0| CnP=p(9(+/5zzzE.33@ CCØ"c0?-_km{`]L3t2c㶶V2t"J9ހq|Sd/q?yEkkoµk17Cci޽b(>yk#,W !Cs :Mr9RkӮ`ai cB1Vv#AX1KC)\,;Re%UbVP[aE>P q-Vd&$hrlӅ{9p8Rl@'A2B \6&gY\\M+Qs,pL@JO>4P|X) MLFWF|r2NJ/t F8*CAC'X\]t0{oެr#~ }E=˗-E^8kMq6mKIy3CYtۭ/{rYW'w@':uZ|n383gKщX2\ˋ3il䒋._+J@~>:)A//YȯDuw[^s+[WtY= :Zsyz>D#qqnΙyG32M`y eb@+i>(шJtN6>1CxچC+>ϽxOjݮ'=5%ػD0П8o4O ./2tȸ0t^W8T.ylrbdM łe=$ܣTa勘u"M`4? mCwT{v2fd4-JiZ71T]~N(!6[}F\ӰG"EGGąUW] 6 /_ƍO(D6,fv(׮х+ AaS)DOD8 c*/bQORϡ"< ebl" E2$N75+]r"ODSx+r[7 ہEL녍MR X< H33LpfXvE<  c6&/po_k:q] *͕9D-B}9=e}7hgU~1lwghJ{Yg|4<<ߡ}tt0cOXp'`9,l.ܡe&X^|CW^-._ghQ$itVI\9$t}Jk4dh2FKC8/*`Ї[ vz@-ܯ\}!\+ζԜ\4+VM9<|";YaTp5΢QjNJj3v{RE-J?QMB$J\AyDŽUW_U¯Lp0i޽[lo[aD=<,O}ν08J l) $Xh5D*P%)pY)'xb*fsykC%ESHBpAx+jO'p.{8oO.67Xj] k5^$gQ 1MhJguh==:1E_q~*[sLy(q;a?,QTU֑IT˜dq%y)cKio>_н66p-3vw.y$AM JUn9}v=FT8ʊ"Ѹh+;8K ;"#1*p:U\X fFCςY-^xcbyG拭=CaԆ}i"0h$7d$d-C81{Ԕ/A| i[r4Zˡh lEF!ʫwwE\%>$dPi*h{|A5!3Ex'QD>V8wt&Q =a0w/%T۝vlx.dͼ da'%OKrȒAllS~f wيU9Z2_x\lo/VYs獄N$Dz"C3!FeŒ0Gb˒^C0\> 4֝/SzuܱIx\iӁ83@(.X<~nwɂ'?+@)a\8O}}Z_S)Ǻ 6(46)ޞ p0Xca;C)ǦSKz@(Ɋv16%XܮZMr riy56 (h\p"TEU bPACgRzDZ4_\0dE2t^9 IFcs3%eLȢlս9p"u BxdVDu$ ;'Gxb 4MK#j|rrkG$?k'}LMɊ bnjEQQx15'(SQ2 @qX {4p"y7P>bAr&el2t^K@'`bFGWud^d~"U.:at"gc0A=6ܲѱkC.#c8ŀ0aJ 2-dvǯ5UџF.sn%+wwN h Nq3*"\k6NNzУ_$IWD.._J eLJ+^E{CGW 12YdTHr JKAM:GPSYXE&KS(yT8l%xnN[RHލWja9E"dslU7jl|א$%P%zBtVjY OVl Y TsQ\ֱT[Ҫ1nq$NF Xvx41d)^ 壘>̼{0֗S'^C'3Iþ: +C!q9 Rμ |CNV2t΋]|pu+.V"<5%h[lvTĢVN/YjD_E14[$R9v_Zj,-G$PB&'sf DPB,r,C ψ:23ۊJPJ4L 椳n=G_i" SH=!ʕNELvcq'>JR<*+'l& ӥ?_xEkwm@f>C `w؁4C5UocV'Z`Ȑ?o,<3dБz;߅%KN/虭t=pxD"yVD}`;6dtKd.LU3  e_|˖.HMOo/ξ,"%^_t0lq]57BMKapb','GYC>S⑄E؃KQQI1;+&O&|sK%9Z>J+$\%4\\:Kp0H|5eX 9$zky׹jX 5ؽk7$[?Lj8${A-7LeP_jTj.p@(Z`l,J0`Nh W;:ېsD'*5IaȐ!C kk  e'=T۝-UU9#29aHTW[=G$)1!6Hlư's<1j|| >ӹ86>nfK$xOΡ4Kpː!C 2dD|[2dh2B/jkjcι¡5P uLJ%Ngfds(bᒥd#1 q2򜦠b!HmKf BQ=i7H)/L&.%^P_:j&P]&.G^r9 8,ԟXKdG-ARk刄1:$Zj=8^ah ."PPa2: `x>-Y\09NS͐!C 2dȐ3%!CNVmC ]41SIxd4dq&8GGJ1xj*qM;ԸD#GZę})\nbHwVeM'C"T+W*NF HEl. 2dȐ!C 2tdT.7t2d,d$ 44N8r' onn δb ʳFW8.\'|`|x `? 4$:Dww29r!dC}U{lv'"S㘿h_Z)k``lt uUJb|j z2dȐ!C ::Ud-C e`_D{k#24ҹN+dU M?zm1x=jg.#[>6#p:/9'#j;&M'6im88_V:?nB|Q Gy\Her@EAW@.N xKJeQYB6"/Qg2hjXA_驚t:ZQgQQY _HFhj 2dȐ!CNrS:R/2t.:e!iEQ(dlE$8ex<锢9;9._ȟ^Vv, 7P9, f]|'3\]x]ɈV,Xé< :Wd-C缂*xԫNU X ? 259 [l'yiGڡf=6͸op,/G'Gw!?fRps51t<6ڻ7؋};J*&bHrh^TM;Oa ]]>r|mo IG3"ld #: fEx, z|N94E0*Q桘%$<(@FfہPpz2tΉ ӟkAWWAWUWox=_*8y`+kp߶p}o!C[5زu+VX!?>6h*%'IDQ<؍o>0dȐ)ZCXD"^*U~/PDSrkm Q2tȀ[ D1Ţx![{a?`VE[e9zDG`l4t4V^Y",YP99$~oB˓S,@/m;|=Kc]4YG1Ž]}9b'b^k#&Yӏ+CȌFpMנa"#p{PA.GNڗ#@&+(ӅB:"E ˦lm$+ntZKQHA+*L~8F 86e,˟?+_=i&>Lhv;:twvu" H oF]ՉzdI`tsgo@Bm]- :fYT x 059p$"iooEMce!CgB<=Cy,Y[/i|}b#3t.ɀ[ عWjxba/!qQ{FKtb1+3fndA^\alBA@T+ꀋ'!'vߘ@09 j", UM-;d/Ij[ n{w\FgRϭ{*Qjދ;mWhY+Y||Hy* pDUks#Hv8_B[kq'y:p*ZgMWs?} اo_'Na"s>l`ŕqp5a=s>r^jO܎w2TC ::u)\-sϸ>5t.ɀ[ =سw^EΡl6#y.x=Na?~Z*E8N!mJJdV!s)fw,Ft|CS9R*PXX;E<۽JRS5hSj>};7@t/}}0pɚހ,a݈ۚZ7)ݰW)Yeٵ{k6dج )=b'cOz"M+WXù42F2NF0e<w MBRn_P8v__?Z[uhd^SB>Ws$t K#`dd $yظuV.]@a;y"}9:vNǞؐ~7p(t[6/RDQ5Ðix}o//8t\ F*kGJΘ^~Z t7i; b_\}{ vCo|nFah1) hصm axq\yjlٴ 7^ۏ$?,{kirضu31:؇t?b-7`bl7=+-ދ'W"*w4aIy4"R4VrYP.IyZUiH%FQr^-oz7^wt{9 (yڝng|hKea~2PL^4FӀ/>`d2yib_S4.z]v8w>Gqs ܄aߴzDŽwr(hW?A-vyyn2diN 0Ӿ2d-C~E}t^,vB^]hN3A!dUc@/kv8SJɩ4q4;iM ` ln~'2?S` !Ӡ6Ev )o;;I),,$$H/W]v,݋WG}%#ؾy'6?}q(|!i<ܵ@ -pzdelqsneY[fQa䷱sy53/Ț756jEm9Łhq/|?p?~E/7OD'|u d쁿k4kػmu.800J \~ 4#h)Mo=|^֖fOH`Ng0myn榫EpX[(4`X]d 2dȐW e;{|a\𕕕0Y%PhI x*Zu`Q45Dˋ3|QJK>,U-imP:i5'ahnD+lsO!T)!6‹_W\*QvZ9b=hbTW9g\{ y8O 0b?9m 6joe,Êq7|O[Ai9ҵ;j)d$YbpMݯq凧0 GacPfpL-V}c.Fjkktxe㸶1ʊs-/Y9FOp+& c Q~Bmi;p#C`}"74>}ow=wu&O@JZ?7ů;~/''C=% p0K+0BDa8a#0(J8}r|*o|ϒm!y 6sQ, vdտ @h";-$8fDENX} \Ca8*z(r?p+q'qtvc=Ah"%ڲ^.[Z7 eQBJ pi:3BC ڸa |:cެJ<8gkR8ݻ` /"T<N C_m7? S#0][x.4kFxK! Vck?9 y9e:ZPc|;cxE ߆#w~І%.E& Oam2^5 6-phl"U5; Sf}.hB9GxeUxiNbJZ5[qx TRqڤSI,y@7nx?#zW_u%=kV_-7ceضm۰o^?^qqX SSSBQ0228(&16ة] C#CbvZJO0za,% J M*syKY24JA^7 &arڂX1GsA\itv inE[TR-Eb)?XN 8Y:o&#q=L 9IBUD[$W 2tzu5kjnar3͹1all dt؈ _cn`=y3d$np3znZ['Ȓ`S rM5Ӆ[F,*Ǔ7##@ݵh+΄MFwW[ 'BP<9 !x-Q*Gů߮\ W؆x$K۱$)D/D*H-gr(J&2dq46iv;$ɰ3[}~ZUHh^W*{%M95Ҭn'3ocJ9TbFa-WkF_ctt5F#<0w Xʄ<7yaڵW/@qlH\'H ̩Foo~zzb|jR; Ҋz~d]-r{6/nI2 Mԏ }^۲$_KoMQlTL.ӱ̊~U$yu>#PD4o]WZsKӽ4pIG9ػJ1ɪDQ%2yd$WpfW"))0!mpA"ZӲ m:*Oh:yIg<n*}\ 2tfuWa5t\sA4O_ZUY%"xѱQӕS8p^V5d&J4t^?>={⾷U\$q)Z846ƕ"_w%m"g 6>Ux|[(k ߏo;; +nddj ]EtЏ'uj21bbnd!Ohnj=S}}h7+X x"!rgE߹cZ .NXF]Vֲnڶ alzC}{z$zr911Ƃ'+YQ9~ E"rx`""3Y`ņʼnd4&b:%(bHǏɂdUb)48{AHVݰDXcW-4dQehf!x^ccq`TUe%&'& Nh $qIvX/:*܃^jD<ׇp,*340ںZ8x^sժ wʕ˱i6ZnWa p ]"*qQơJ[rȩ8ηU4P* pD%"P/U$"PTڎ/Y Ϧ#XO]W5E=Hj@'\A=yKQD贤پtj)ǽV~%.RiEI1+jz.2~<=hȐ XHmG3z iļ>TTr0$A*p>YM< vt8؍ZD .e:*Mx׍D G}O~NGvt44jQ97Mr1ҫ)EX\˅ҁ_F߰2b-"#bvu0e7/Z% 8c?9 p2:VvVD(^Ԗ-[`"s)gRXu*3"zB[dXekc۶@c]%V^x)B~^2h&'xG}C  U:X.-O ?ϞMPDa\0!@C@g{Iq-"\\a@j EYJ`]Ihq4qHPpK{vŽطZ`dt$pOEhNxsC&;B<[X$ ̘Upk"ϣwSB;UG[l^TD]t1ojK`͚Uشe;2<,/+z؜\%H᠘He`UJeLJD~Bb(>&9LȚ%T0(lRWqBdE>.ERz ƀ>CbKBYQ{8,=ԗ$oSK+m,ʇ% N(/ݼD>2!CΞNK 0d*"2t^=~'x),YH;P)z9vR]Y!G^M}~"{g9sk #xȹ+ԇ9l%ĔG&z_ \wVqo D1^(^«yj%@&AW^1}%1޷ԟ24H`WrTC(]9f*=ESJ %y gAZ/ʡ"29dh2d蕠]qȀ ePKKU]S#n?Sbw_Wu*= to8 EOLڳ.]~x/4)֍+n@Up3lB?/rI>).MGUc#0 [ENL xhzl֎axn47S-ZQ?̱ГWwS$ym[%̈́kliW5p`ʁΨ w6%( L$)% 5g&eҹ7mm%p8|5d=j5HMx#NDPI46)9*<./ N6+~C y "V!2Qq' |e(;D"Q;C9sR Ê\:wub0mpy]>`VV6aؾ}'6|_fYT'L^ztxe-Ji::f"I/E01p=S%t&{)%X/U/Fx<"\\›)'B}ΪO9T sT$=-<ɧ!*3iCiR?(fpEx1X`K䶗0B%{u3[SM+=Ԧ%_@sFh^B6t VeϞ^xmbt$ epyK;9&DdZ £ Ncm?Kl`u!d?Xjy\~4F1l~U69)->?Fƨϫ86=|9]`1C}f K\2J78k@6=I4D2F eeV6nA99,AhE0>mڅFO E$TXsVT #m]DZCvx|D8"Q(X)k* %+@ ۡ $cGs 042,75a-ˏx=wchh84G;< oN=ПCW>%N$"k^g^w5>/+n_o|g?ۑ_p=8_L*'"CE;pIUM_ɪRلBbA4fL`P7)8"&Z(h+r×5=$TqIx(*sCXx^dt2)ye\j7DE'RE}M8+;W'җKRe08[2A.q3Ɵ2xː!CΰGw*?91)O Bi^ @rqԮhX 5`8^/ҩ 4uh,+kXؾ~2tˀ[ ڳW[{h>Nk ,>A{iOϬZ^\8iYNxPiuCF:g[62*N~

ɵ{$d4A!ʸ[*Q[R ڶg)TV^[M6f { %w@.lSDe,rv6LFťhpW؁+#V<,|UaK?v_C o `'+G6s# MDB /'QSUA \v u 4D}72/59 ŌWK_M[thá%)h<.'Ty'ν0Ec/ey+*\s/ WjUc"$J0q,qb> T#mp$HqCwKkAAa<4a +108ʚjQ2;̏G& '1nEDz{`n{?W:;l"l|q w#bpx :;8hhY8ZȘXP'4FPux" kܕf<7]8 XUM¸omm%6E5>\N;RQ?lX+d(TߋP>KtM?x}~~Q9+@2!Cs>Y'p/H+ P 9ɹNʅĵ"f5RntLMiC83G ق~ O٩x\"~b1N-bQӴ7@@p zǟͷތu4nXœ=qފg}FTxvjzDv.UJpK5%ʇ55VR L{#C$uu?b&'5;G Jwk jlaq %%ֽ:+ Y2S"HO8d#0Fo!Lm,)i'#FPʁ8qɮCR f8K/Xp+y0'*jJgn-Zщ0VOC :;1i9хê׿t=n._LB>h.[ 2NOi En~j2@2t^V,_¿]z'jkk .=Gp&OJ{Ys4[9͆-UXnS$"d=&*/Z9[yd3`9zXr)OO@Yb%G>8 1U(vZ`0<g6qN03dzʔ49iLµ[Qi Z2B"]tjjeFvy}.F5} IdΗC^gޟ7c9}όVY-G}H(ohh|f*rW :hA!>`r*IZZe~GE?"6mَ'\|ZlټB$cq  ?Ᏸxb> 3Ag3}6M@17[ً|*]iF6;y>2 ؉; Y=ҋSx/BzGqm7_|;ddJHayZl)!ڢnG#cK <)SJ'$ 5R9b$X%Hw_{=V1#=QH3KDǕ"7Yh$9ԴJ(rYg&C9M*K{2'riH˥jr`V6N͈v.rI("9"1磱J 2dLm-Jz9 مg_IKo[pː O bO'8f*yCpX4#䬤v3pi'x0Ԉ]S YYA!Ap!3\*-`B@n623B~b;յH=:\p9 SE51VZ&,k{4xR*' g^+fbɿB\۶@u[n(}?LoaTi{ IS=>t=j )+*0o<<ؓbj[[3=W]s%adlz3~ t{YU9~! AzB~a5XMNY&qP/KPRevV:Uc;hqCؖOfCExϊ2mEeuX-QI;C-N/8f_"Nј 2t.rpMeӣ,,skП e׿-?Љ|%|^**yۤR)85|PΆy7O<Rr`.x^͢ud HqX|Q?[ނm/'L mA42x ٜ hObJY@q7JwZdrOlځ`Qs]+چPAFDE1ޏږ5D27c=\Bs!K_GB&6*0W9a4o  r΀ {4M'?t066ʣ Q1?{ZqL<\)LeTQldKQ x) 2tbaglʤPSQ\68'ߘm>L C=|6EΪYZz-D6r O!} )4E$m9*"=Jx=wGGSsvCxux{߅-VZ$mӏF]"5ObVwaP>8 j=[=<%V 1Zozjj܆o|wގ72҅CU$MNG T}+\!Qbw`Hn1]iP$R+}Ss *R**xzR_ p@ Kpl0.{"Qx*w㊤ꡔ $,*vk!%sUEYhǰŘYJihm|5c>33e1ّI^:lR_T`x :u2 غyZ`7ϋ$n[\t|~[2dȀ[OpĆ=kϾXri-v⼽c>܃ nNj!~=t ZN|eYl{q-4v˥'@:oÃbjmnƔ9VJ% -ͣc^Fstyp5VCk#Mધk/{aВ E+l[`%:v!b5WSc WQ[ ^*B՘Ha*cA,LE.rTOZ aN ȉ\&KP2°bX4V tѣr.,K?e'#N(?55EsԼ[?/(GWͰxͰ{%#"ĔM'PT%џAjOtjV N zp7Lh142.`i&殊j\}0dҸ/K0 BA[xq: ol wMP}i;rh ̲L LI 0t#TPa?qk x'ÿ~X,yns𖷽Wg?7/}|c7be,`&"tnWHr&f4aUQ/Oc2%X%N-5+KDvCPAB3'筼-WREwx1_ d$^f+bf'Lؚ"5} ˰N$ XiTʇ{oq.2YhP I@ 8MWG:u ZsĒ㈥&`:H[KNC 2dI|j`uՊL& C  zލ۶E<^hvbEbUPPŪF˗*!kޤO:3 %uWs_0dѶ\wWDb:n8WU(bg.+V,=+vόXcKXjq_/Ng&(>,{q;/ ʧBV)?P  aUSTVDp尋cb $ iՌ aL*Vq^٢a%ֶ^<F#T@48O. ȚH$# ^䯼 r p>NqEbG<:\-2L 'C "OF#<>Vԋ/Yg}}W$ѹ _"oxM7 N^@7UF_')[ ߟd37 ˋ/^M @};UY7'^wނ>wxyȤXP]цHl|C[!Z}brwM $ҫ37-Y#Da(4 E5{xq8+"ȒZ_1sq,Ux=--X</׿nU'W_?2=40.1n7  n9Gq-| 5@`=l"Næ@MZҌ~Ey, 5En Q:sz>:!)oY^&!/x*1^Sb*j ya!V1+**2TJE7"ȵ'A;Eقb-! n|t U _X:"Q_ G(hkmst2d"' xoȐ : ZvlycS\pڭ"I灃k#a-baX$FJb|v9x+3ϡ2DM׬Ν!!CNAy{v4D&Ưi =;P,f3)GP/^X<Ž $(*2\09](*f"S>x\u%gZ6nKI!P,"ϓD+Ex!鵡~-VȈ>A$Y:MfVD{={M 2 U`߾"~$EVq:NP /FƧs!m"/ 8S9uPVݑp1BQ h݈8UqH$NjS9!C$"AXub[v80Yhr9ؙN@Φ`Y=[DAm!tV{؄r"4F g>NnSW/D\fpA-jL]DȞ"ٻZ!r1 3_!p!bN@"}M*75|;gZ_jG΄J&iR~ s6C>~;Ͻ|Z䢑L+ "tѐ!C 2ʓeP  Rήn,]wtq*cͭmtxBEKVV"\3vƣ'oikǙPu}3nEG~G<`|TC5[RUW]%`u3ҁ!.FɛRm7:]^h*Bs} ҹ@=,8U+OA1[xA;a2d@=jR %H&$".p :t dH%ðR]^<:HMrLo9:Mߓg l4:hX\ P%jzUR&|`n{woſ~?a‡>^:Ǫe—MymD#PSf jdn|?7|~+|cxߋ}~OaO_330+"wE1J927bx;Ln$ksW xU3PLSWVN8~K&fUXB\փ x`T 8KfEye**ҹƕin&]n?47x6 OOJb!&'^~RMaR3VmMSwx32W3А!CK^i2B{9'fP.okbZ&k'%c!&VS(w~559!V]X^&B+δ\,bUZOz{fFdEEEyFN:J$La/{j>H'ߊEk~sp} UFtwwO`aC2=o(F/[px6+4wEYݎ4Hٝ!-rjq*ĊD&$zZv ><<cx߂+|7ލno]hnjµ^}KƢxqv,qo@Q@ ")7GVvHY E';ҋ!^s?׾m7? Nw O}g?O?bN#)]qT| زIDbǕ9Eҫ)r蝉fMWزfrp1czhP?}IJ^9&Z2G/@m@Jb\S9HDr>?T",8W\Enu'e~q[V<}.&7}Ĥ^#)8EHz0'i9:ݏP1 9V}li" 2#;w=2dYG$ZV;4<.4,^Pincb=_{sT QZ.ؤ9N} (o\)rGċ 9r'SX.dűxїsx{ކL N6t^Ȁ[ r!#^mnj͒%3mqywCq$)TTV!<5 ݆Dljd4 Aܙ&Si C3;a($zN>.`U8  j/t6pX`1]{Uzn?byf=l8Zfm⯑PD@ Zi \/hTSPQeL*`UM*xi!aGь!,W<`q9 b&`o!MW 4. >o؄wxo{_D *zhJs-شu}Vh`Ia Wp g YW`ʥxϻ߂+:/}0cO~u|ӟ7#|PϖC,~ϱ繝 2B [E8 #r`UpN2\|d8J K1ٟ#dx\%Lm8VQfH<0t\tf=ΊG!Ch._ Ucپ^e(S$լ'f|x"amʹ|Ht(^Y:A"7f]Eņl%:R;oHA+$~ChW6 |`)vP"_r\90ooڏm&?nq!w K_7 rpض};~_oz 2,>/ ^uXb:Qx|iaozb;`)hI3nxѿ t@gd>3Bzb% 3"Yu+;;bS`pQ.=V=6Rf.Ky4ڀt)Odd% eLbɹԨ͎r,@(R[MI2*.A%c0҇39vDj6ScԿh`9EfȐ!Cg^ ҂!A|}g`hzo< `URr_7A:]gq !#XRːM2t^s7 # ::PpVH"\"G48STR ֱxM 8:^"q'>8ՅGQ5tn4uEY&΁T+cx~V|Xކo~JpՕJxm޲Bx;%֍#H{߈̌8ý/A""{E8fsådX1AOsV <ȸU 44j{s؛A`b$L1+̋%v/445]c{HOom\!d$hiK#K)DRT,f P*Q;FL劓E|ZBI3ӂDPĉ ae tk҃hEst:-34Air)L,᪇Apn.s@mtSq4^EkC41GKhȐ!CgV$~.o&=0t2 3Xnй,7t^tFZcB`W kVĮ![رu pFP-FVWqzūP\sRv/Npc׮ݢzd2R8lVE,^؁^:d0>Q>i{$x\a՞=ݝB䊖d|sf24qR AZ!ߴ)FszN:t>N& PxMgBLۧ!p`{^Ne|g;ZvP`)`ߌElsUEO=*~!/+/pK_ 5K };`~*"BrY0a)dkBHg LM}w?1\~=A[כNg/|QofbJGHN ~6QZGcF K#HsVc2[w ^(SI"@On | {Ii?`wLYe࢖,EUO B8;Uگ`l2u/A`g8|8PM#+M-@\/dcjV-vItӶ8=Ls*x `Y8b'RZŊ }/0$;m[a$S!iEÐ!CΆ~y?~t5+ځ6X^Ya'>Kss]2t^3Ъ-_I\rUC?+--%up뭷 -E" 8b"sؽ}"Q^!'8R6bn'qBHZYp!\ %вcvK+HNT$BFd gW8K>bmc2ؚ CqO'D-4M-<8"4uJyLJV1i4IE;b+Ey!vZ(tdm\2t^oJY|Z uCP;bf#ȸ~La1pUs~lK4)"̀%G YL"ao/~ 07`س{7::"Z4!O XQ[8+hEдr4\>p#31t*}/n#WÖvu|UDZ{),6TymҾ U(dH5w@d8k𓟻?ԗ6m\4p|29| ?E EDiiQS˗-N,CCC}_yr&/p\xNNKIH{[N?W阻 q$xad9涇Ʌ5L<0 "aYb/NET^Fy zIiN΅Tš$ԓ bӜcznUbƣoׇ[/?I<'p7"W71JP'iaXriZPt!4%V|q3hsj~,\І8w=er~{xqkj?}]_/æ{f7 ˠN17KąM19Q6Qh,#!ew,qoY+( $N 6,X 4^rQ,T\eftX>"Ge2E]:K|̢`v`"ُͣ9D'4Z<m*lز)sW)y\P-P@-   #[F.7W,<[N2dЙ֪*|ļ76:FAa𵠗 gJ9=띜?S(v!C e蜐t_޲G%68ҙtqM\+L)!N\m$텥^ |DvEt2EdYFt͹R 7-x'0:4;_Zg?E\(:~W^|6n&@C=XsP18.-:GdZar^l߲t93)xF'0aPHPgԐ"í sІkna94&hw zz=Ƨjq1_ϻڑMiWw`vtn]o|Уﻸ+q=>/b2ſ}Y]?7{*u!5Y91 #WTdijNW5}|QmX/_f[Tk=rK 7Ώ3UJM : `JM[Wk[ם|e"AgJ=}Sg!P `=`l}X\A<:MCK/F%A'U?#Z\CPB^ZH,fOc=Ih.-5f'cQ?752AY64[y 2dL8 Z O_,Mi sX z7E EʎzeI3dq:tS<>b񢅴݃"'PHx iB~'ELt@r FgԼ%A\͉\$1&T2rM)ϔ$z iDܚB146nWm 㵷@ᵕR̰9*Z zLA%C&($v2 e [yn͠m<"Y~# YUfMnI":D& ڰSC-GMg\TDtʁ0kvGɊ=x j:D'"g(ʃ U`HK:= V%ݳ &SQZe$ 32OLAؗvX9/V6w&wP__M/Ls_@ցNFƻ&جfhp A{owy/nƢݨ /Bd8Wq%kQ?_$y[ϴ 㮻ߊ/}߱|e› pe>,UQ(ĐHEڸ\+2U ny%*#Q{UU/n/޸ʀH~p7؀qN_-s_>QV[7EhuiACu<ij dq% kmHT ?[Is~+RzXb 0ITc|*e袚~ e@/B Noqh{~I4lAY,qXPmBI !ĹaLcү~4WsGqUoY$]׉g׮]B9eu7ߌ]bN0.. q5WG?5Zzpx==?8_:xӵg?;_a62鳙$psA/f ltHNŌ`3b^?$5_%1F-Xb-r86G7هW/&/Ԗ;1۷?տi"^ Ou"FY bQ tn(H{s#דf{nw/x`MsaM$ZXr\"yQi%*IK4B# (8ѽ5%rJ!XU-+}9](yr99!CgGeozN©- LfP嶟}p 8Ǥ!C e,T|^73w>yDŽșZrp]}MDcCTd()GBV Z]fHIO vZv]Eg<: U6Vno4꾄MLd`NJvь*{.P0RE\HgD@sV{ֽ:2b >&z+b}t{&H7ytLsC)"{!d=$,Yӥ`ÓE0LĞ4Pc4V;wn>?sEր^淾믻\x>?-zvb$>WG-D]m5>AggN)37|Jy*_!@P,h܋ MQVECSEVy[:~'IwF"DmynGVʋ ؑ<i.dd- 4oEN2qhzAociц^iAsؽjl:BPI;zF @W!>F=9TVsJH954 ́<ؠM_>C^D2oNJ Q&_v $u^2T=8PUUլʿe1gmwcA5L4Tb#kW$-6cg$݆ j$lcQ@Ãy\[mF]FKRhA΢l{;r|)|ATAsYiV;l$ R8lhdh>C扝dstFI&Md^> 5Q]@ْNSNS".4p?Lz5l-> WiZwQkXAz2.}^*U%߶&VQqAR^(|Sh,A)UT6h:*H=p#d;Ƥ(ޣʨd2tng:"FQ G?#CǞ> hinx~9wM%pSM'iki$Ф{_~[v{qIc`<>];b5y>cSx>_۰X;~?j/I>m}PMy1j(@Z6"eG 0)౻`AvVϑ'q0>ĸ̑x6/i?M gh==9JY=@ ء{I4O7ĸ pYlXH0@*FNpJWCYi{,&.R`>Mr&*E "kKT>8Do!-7OUcU9 2taqZ٭JfwXO=ut*(-J[1Limp{S~,Gst<6dh2MVI*9}UzN9NB[K}2xn%^wh[QMB+W̺yx-fz]o _ϯ_h|Ǜ=$ E^f%/WGd(M4ģ8"Pupx(@b1[ r˧2HԱm،›w V$gٓtb'L^CtGSٰ"%qxri"0J ltŁeK$\YD"*}V}#ij˟*_Еv UK+ eȐ&M7vLʹrEzc(V7VbC" vU3JgTbbm ?]1"n(rBZ9VQ`L*S-:'czm:R‹At,{*2D rq/Cź !C iD4íK[-!|hw UO"MW]9gyaqF[҉f:qmǧ7!CgJ2t{s{r mvNHk}o{#ƐJ"WYLNNb5-vX ==}d2xgۏ Ǫ+CPkCH )H_:;;as8@sD]M%<4VoݲMjdϰOGdfѢGރz^?ϡ{hEa. ݷ "D,EF>L68~A؊\"UOkLXCcZA*Z=>L4ΦctCDzj6?5ڿ -UWKۧ>e&VV[/dZYcY7PI-p7UODVI,^?l,*f,2#Qv2d2}n"TZͯB6Vd2l5a-떍x|!Z'PAl1"$CɑQet7^7 LUf{q@z:W :^[y 6Ϙqp :؀,TAOmKÛGyvs }[}3Ua$-m6J޷ ;giDy N$褼ъ⹆Fl޽W|ECt}g P媨[v܋;&6uISv 0fu7A`pua|Q+עo,%7BNv@L픨#/H\'<ǖ@8;3IzRtɂ|.% T쥤olq"MFz'{,I"1~_=f_t~_ [Zʊ;!P$Q>9V6GsUxɆ,(-sHnϗ'Łm\̧^rt_jG'93KS_NVOx oȐA,Y~bi[ఘ e| UΣ!aE6D/ /lIxL$¨{Y\(_3Զ4z`K2l. >cg s & h{%+2oy6 APɐڒ`lw0 'GQa U ~NXuj`@W(H3VW;~[Ź5߮QW$]{ Ka-FJ~Mڌaffr|a߀V i`:̯ɤ/h`g$ 3ͫg1OIR:RٹNLWY<pT֙\zC z90+͟p;%c!C2If\ nta-z"ڒo>%o Va޽"$Cp[b^Iƪf=CP E,*geX9%3t !pVO19lDΒ$7-PsNm+Av kE5/bEtٌV-jo^6jVLp=LJ|6"ѫD2+W>ₕ;(P?b)5{e(cĉy DD%Y9<<؈] 1 36As"[Ha׏i0܄-`J{hU,ЀSUρ=0CFX)~P5 -Zpp5T* 9~azYd2!rtpO)Np6k߻w;pW```=.@٬ص'$ ~: . UTƶ,-[9H:|(4^Mh4bL d2Y0-VQMbt|ɁD&J npE6ӪD{6r]gܮ{%ٖ%[\˗fɗ-v{,ے{[I}މ{\<4 b03s %^Y^ l~ z5":܄&ǁ è#hc6KxP+z1Eu:ִVKk+"󮬬x(ޞDKS&'&01:2v5F'=@ҥKuXeFaρ6nܠe#(Ty\R[|9ZZZ0<zҩ(cez=8GL$yլ}iQh/tDD;pcd֪ؽ&nTUX;gjl8`Cܢ1R-u.Pp4ai֛80h`Y1ӏJ_ժQ3H('|8b_G>,71ԫk}J+Z jڋ-80&ֵNbęOJ#Ēس= zT+o2Ǻ1 KL"Pר d/Z'$v?&_IKѢoE9ߺ{lIeNxx^[[.seE*YTMLZlRm^ɉ4/QB֮]=۶|̆{~0Us0%#Ғvh ٗ)ldeʠ޳h;SeGtv(]8|(֬\ <::ӛkugkJ~OMELqfb9%9:-l)K5?N$`0&xQLޜ*"L][{8\({I@1J ~?UǶ]1 M[?Ui9|㵯ÁGp=xF*l 0UPb)2S:|0t=(,"n NFzִkEx}>$c GDP=I堚#elTOӫ118{g̣O[5+A[jj+gK \c&,j?l9~OR]?MZ-&XW=FX겳bGAP0)-jVYӂ1umc &GNWVA$S'y }竨 xhU1t l ]euQg]y;@z~~ Ī|=H0}I}?pIRx۰ Sҩ}~+!2'Rqc͉Q)J}auOU&ۀкіx}"*~=~h<fKwoHfdq%0 [–#ap#$Ș2+o1UHժcBS*{}j[:ҰRL2:-qLI\+oȕޚ/d(6]FZn#xvت1 b*q&N'' ! N,\n?ÛRWS˖bŒ%uf#Ɏ6() B9^T'uL9'w4z##+[jQkk+ a;N4"n ma/7Ӛ U~l dr|@NcTqf~tY0>&S>E/.'t}:JTV"~uxxD md\℔ B?Nz@|i֟~fB9;կsNöv]g4€:#7 kpQpi^ d3ק)[LKWOIc’3soܴ5vyN!-0pX8|j%A*J+Wmfg \TKdXZhQ;3\3VjƎMb\ PMxg 2~Kh]a돤ژ3b~ot/35s &lK=%gx7wHzU#ک| OVf̓ <\0'I"KwKEqҳl4j0UUUy;m ZyD.D-aHh9okVjNJ2̄n[fy(SGES[h kd\2aEpRT̩\MDt2vd#[ux_x>AFeW !?[3As^vp*v[2â'mӳ ^h*o&5Fǧ}#g>_ V*SU7A(f+cx2PQԨMqz(b|!|6u&q+}esV [ !{#I8\;ӓHcfb*4ʬOiO[h*ӜzM-lf澕O)+}4P(Z + C=URs-F|]ԵMUA-یڲŭْqAD-!▰p/7\CS7Qrt#'|ZJz[Iݰk$Sw)8ׂ03Sθc; ':>+װlhgp)G#cP2 pg)ja社w_jPΦj\|Q $Wg/&qFW=d9c\ȁid6=8.rHQSu%!uLEgvt;j+5Vn䩴IXuubj^t=/;H:f\.f֫{F{SMo{tPZO݀/WuHu|Sm[P(Xւ㡱*{*xl1ȲVXTaqK8AXμi($<X*~#ӯ~7(&FFϗ.?%pYQ\|ugM.}Bٶ/͵HY6OKZ~6}~Lx3҄[UCT1Q1X=2S9/a_6cm@a \se?w0(cfl8qB<]\(l1 Li癡83}S˙S4s,α9ǿn8i"ߦńZR_tj/lQY(.vJ[#HZ=f'cXCaqKX2\t-eXᵆ(g1_$=a. oI5wcΔA(-0YO%ZiQXOׯHG:CJGm!sBqc7ƷzR^RWP5ܫ>FH(W,IP@Wo.΁&hy߆CsJD"e)oG;ceL4veI/LM c @7rMEA;؊eee$`fad.]nhLmE$\4}-zKaA-VdcPu[Y–s4E@cNĴ-k.A%@%/yt@)?ՋJˣ-Fg!c-*--jezaz5#r , \XruϙדkQH޹+#{ᄓ-:Q\xJФhʆ2BVjoD0IN(±.USB-.sZt؉MplM[2 `LW bPBU `POj F%z1;u/et `zLdbF'2 @teԖn+Kb.;0B}Ucj"rtׂiN buf T!LAd-pUQRg"=6# $~3Gm=xE^tHKulH40o%,!lCQ8ȤYSa(Tt1`TJVD}Q)lRV"ՙ` \A(>sp*6-[䢸QgȐEH7k)uh^ $#O;̜PfrbCã3/x\> 7gg 0㽖Vzu<#0b[.#UzR ̊3"ÜA(tUe8Vq\-%E-Ե T,jtD(,`a_ ZSJMUR6bEr2[߶Xeנ.K׋ImÓ(Yq0h‘+**1?$bшL&,g@ә`w~'|I5KJu4n@UUmhaL݄.AD62#^4& Lg!ZErN}"D{Ñ:LXbt_lSTJ"F]عt%D>Hm5R 0[ܲE@֖sDm9 ʻ BQcXj]WVlԍq [xu[ۿ5hQi .1B9f:kdMЃth[M|~KબDAoDGE(.+S\)L1oN [vi*1ljZXb)b&Ad܎tMEo[T .W2'aH"r ŌbuU*HOD._*~֖#ˎڲ.cK8)Sf>o! *Gv/\նp*E{%6Q(_,?3# Q[lt@@ [Q[aqKX8De}fVSlkQmѲrd8; \r\6׶#kOT56<ޖj%lQˑv%9qKLGnY3ZK嬯wm#1]a\*ea}ig:Wd:R)j9-b0YٓIOFJ(&obJʹAcDN()dȅ)Q!t9;%1BYd>E\R(5l;i8:<4DѱT-H Z5jӣ#:^5. 9B1A)۵>;JZpYLk$k;-)ty1%1娳KK(g: eLʎ暶斈\\#▰4*-pٟ^1יP&$r!6^)a)W:j VNNC䲶JEȻ"JCN(fb:-HQy-;L5 .>e:EJf\hgF2;+b+՚=~E 1Sn\Srra>qKXx=qF$W ,%~PJ/a0fP8So[#':.=_ ZT7]"lӘ̊P) n\aL䲅_])wMH1ᄓ.b])pQL-gj[))"&NVMҲi&9/[‰í  ]9u[Lʊ|/}]tmtcl!.K̒FPd QH WY— IG,^m8.Ӱl!̴eo'K̒Va-;.7*-t-lͰA+DN,N6Е^m]AXdqJd\vCx0ݳ +5g&aKtB)0-ErKT53zul~ic-eM!0=+; aː-aaqK(fҋAP8-KBO]W[NEpdGǦPL9H]˸s#73 \vx!d9&z lM ҡPC(NPȃ_p0qJ/heDnr[VN43YEc&\_P"p9"e:~" ,Biȸ"l 'C eE\.skeoP|]kH%7ܿoHa.aQ+} F-AA(.=/Q .59Sב k͘3f=paRwls}AXRo _V A%JEre# !QA( i**z[^(nRm#^_j\rO [ P$rܐ4Mi6#=#tM[F Lgۘv]Aɗ^?wgΰ-A(ef+|y7:wKavRpqKAʀDe!i|79( =[F(6DA24%FXHL߂ B"  9bRD AAX% AAr@-AAAAdqKAAAA(YDAAAAJAAAAEĭ;W AʡCg|G? A,m9AXP%    ,"n    %[    B"    P%    ,"n    %[    B"  iD`AAa1!  #'JGcKAA(GDAYPV8].AA\qKA Q؄|}"r  [ 0Db>>7!ˈ%B1f[N qKAr0[Q#rEkI 'BWk )ƚ8' ,$n/{^>X %'raYHXȾ >"n R(,# P$l9N$z撙lS%b  LP{9KA(}DZĔ_Sۋ{hkkBK xaTTM7a+b|l ]ې8 ~BCou +V!n#kj2DlK/A惹t=u mhOO9*\""dk739s]; ؋/"wun,^s򗿊.۷_c!~4߼:Cqs"XÍWa} /s;z3:@7`7Мj%B0:?gc d^nl`>?g8!>|" [b3[Nc~:-d9z;;v,tᜁ#tFBQ^]ӗ B~d2۷@pnacD_} >Xan8I  M Pf3Ɖ~&B "n-"f;VBW]sմêј'``X!_O g9u# J0ӿҕ+bi P~ ǧ/ oO{|v+X,l3ڧO_aqkp<~hbsw?ǻ}3>Oi_&E]]-.RN+_ lي`0N; 5  s~Qg@,בد###HcV<(e|J}GP__"h 0$lQ:=a[w GGE-o@c ~m@WS@YNm<ň&ۧӇ~k}o}Mdf+`Ϟ?ŦMh!__ߩ ꫯ_2{߷^Rytӛ4m '"n- ‹_*aj;5Rko| D[[r>ޢ;5Sꫛ; }.W_}%O?Ԕs?{aټ=ŋ03c?Lz}H5EZ=0֣H@< Oh<@+|߇׽555y# sA KgcY~ZB0~+`b82yPFLOe*L,Q.:XĚFIO;`(h$&&J4I}вp>S+>x;nx_BAn߾C^}U?cD"DUAʜ\vwߍ/}K:ݦW=E믿\46nܠ6k׮-xkFl1:spE)q~7b>Ew[-ŵc;[=ΖϏU/YɖێFfojy_ vK5ʒzu_xR {%|a066^M`GL#?ikJ2Kc`Bg#(chc/gN,M SMcXd(n}-gwSO=%-$ѯ599Ư;Z;:+2)lK|֜yi+/,oKț '"n-"BSl}nêVSǪU83Y?n?B7\C3j뗿~ߣJGw1̛`m#;zŸv6N[50h'=Gla@2;)Qk0n2HAvc|Q=ωC5k_z2rXz۷ޞéhّ)g }Ilι_e8#N&%\yzohmK2Hְ/##pkMb6' ̗R~_Yxu_a>q^{N+6ޭd._mfcCj۶x;ަ ҹxoօ<^ܧ?xo! /ϭK! O&{Stl*=x9a:Ht[֟dskzVtrGEQ ^^Uz"3MqkXo߾i뗢$ 82ݫύG#3MgoC2OP<կ~K/v͵dIG`cbbXÖT=;<Ɛ LQ`BYQigWT/wTy}XYY*=s)?_WtΝӗ[pNbC63SQ3j^-xP7茍Uמ\ |`L: =j)'6(dP´(KJ}CDP߂`嬷S"XGUv+k*4j-vƹ"092Z@oF~Q] y>'?M^%\4XƆvQWWgZ|U3foFTC5ez#GlCG?2Ɏ▙1RB BFz^ǧ_Er;x~L o~s'uG?) jOKMҠOC8&lABCB¡|/_VοihhH*͛_M/m_Roߋm|"SO466 :r.ʡ(S=ٽң{SiˤSУE(FxpԧH;tnf泗Ā9D& ؃}?uXZU2A<Ó#8Ūs/EJmzF$<6{m9vQ[޺kpk?0dGn]vWBDn}#J,?yi;b3fD>b_s':T. ㆩ ó||{X#ʪe ^G8yumW^*8<pc ~?cA@lt) a512?xjJc2 :MaȭE@1dS߹A u]K\T ĺ,]ᓥ.KD:6<>Nt: mi`\s̟|zZbI[h> x0x`YuHEk)ûXgG_~4.C7q[{Mv&}C/k?X1X;ݧS SW\_E PβeKEN9d=@G.z70`k֯LYb<űk__ryE#?Բk۷?6]Vf%\5Tyk'ǦիS;b3[C7&3q٨ed{{h:+% ZdIR0JǛh8+B^rzP\t} 笹SHՋ߷jjg2SRdM3C u8ͫc261 1i.pw;3vD;N[p #NC\ ~q5욏6_O b&#;Ÿv6^5k;b3K]6SBfbmHԖX) qO$M]%jK(GXSj)Qb#XSr2I x M9# 1Ld6bSQ}٥utߎ˴ ;kc˱\Da$Flٓ}Y3uȋ/G.Yf~=rYȫ9ψ榌cS͌J)I-<9gx´'|*}63Huٹiv1|_g_j!_~NZRLE$_j% 3E1FXEn?#p?6o|>|C> /<_L[[[inV4%4EGϺ7DbeLlf{:k(K> )ibG3Ҟ|*b%,f Dn-b̬'ViMeJPأ+r~(Z[!pżh+nymXFu Xoc\ D TG)dԎ޲1ɑ_Q̱uJHgi,_Dmߏ;]z7"6$Qf Dn-b |."csرG=jѼ~5\s)u91rzsdI)`"G_*,!023PfRH.哿os&02m?Kd W8VI5d'ہmxqty8E+b3rDĭEN![G_z}s8Kp;oʥ!|g? <+/wC7\g6mdR-<+Xԟb}=#gXůxI| wlƊz},(x<ЦRbaWJPĺ= ,:YF㹗aI{"C|`Omj %ܮm{Gy6^\wpAss3>cŨ_xE7/*lܸClql4ootqAC/W ϵ6/Y)_$cYknAW\SfeF,%)]B 6ɎࢸUPNg0NML[\^HvėaZ`Lٸ@{<{T \\߉bt Gݺ5]/q0  6S(GDZL2ZwGpef<\)*\q՛kqUoy T<+>Pߵ*c} uCW~_8 L[[v;Tx!jP?M M#?ւ&G[t IG[nMo&_՟x)uҏx[fSﳷ_Cw& 0+,3A2@EIN.aWu72HLz$\(IXx{nh0 G? y1\ sLqk3--[-oUcp|T٣MpFq+e;˹}>K`q,\lٲU;,CCêǭ z ?<zgu&;Gt?9^:#^ku1W{Tǧ~FNұ#?~uqq ?񉏥O= ך\i˳N5k27-{ۧs>5|-抹-sHtCȝ]G>|B|B)D+ DAk6L`,rc*{1܍!&ĪyM%j16rT&,?V&[B#64+t4n3&n7pdDhy܇ޚǿzqea͛膼S"9jo{jP*Lci+2J5~õ8tg,g}N1uujWb9_׿/LGg*ml)ߦV-3O~\//h?#3]ӹoK_]|Ee<9 g~^v|瞇S܊dEzwtG!_rm} yhN]1> q%R9nn+?;3>VW33USPߧ ?/c[~ܹ+ιTѻ11Г-: hfFI10bp,|éθ^ے (-3{J-ÿcˆpjߤo~ sA3 S#޽֭{ɴF"?p.tvۿ(DQТ@;G?iJUx7\;V틱cE9 ,uRO>XӴIG qxQbN'~0? 1zZt-귿8_O~MP ~>#Wdzo½O"nOw?1r>lq<83< ڵk\x/[`'(Qbo /#mرC/n t2l߄[̹  tg:@;cOov||\YE3v۶3֭;**T`u~0Ҍ>훹bfSK.#aG%h6ωf6/;Xl!B9""fZͭ[¨?).2= O> 3% ^a 8ε.Gzl 5Z"ٱcޱ^nxS: tAu{sҡ`e?gr>fSHc/WOOܖvmf(ϋga !NP",tsihȨ3AI+E%;pG%b#6n#; y^b"ﴣ#_CP2-x0!_УPtO~nCG'gEY>Pq^{)=6'ֱvW7"ǹ8VNW!^~ #V"L۾޲7x >ue5DY59׮Ӈdjζ(F3>=ɴ_V#%7bI\x3xM ߯-\Moh&qZ/kc4RpBo)F9;x|1oQg`VinNQ}hӫد|Ӷ5::& b3rDĭENF--w$1E\O^%bԮ^ $&n-`Z"{5Rй1=d٢QgF;1Ԛu(r1<رP,*ÉNKWW^ Mz\cә9VXGk d#XXwj>愹p:'?1=kvlOSAԣ2-ᓟ]=VL1 Kt}yk}n]8^JȬ;-2܏Y$fT#BYo(N^1:F b3l_͕q^g\n5&5}ygJv+.Jrl' ~MMCWW<s l"ӝ͋/P7Ků[o}Ny2R'ivzZ.]ߙ>S iwNdDswf 刈[ȭShj=-4~<ŬB %j9}RPzGַ}R#0ms_YaK+QHo~sb:]aU{{.F:` ;w#bQUn3Αy臲]c\B=2"2{s"棏>X}i/HJ`] .wK;6 _v<؃;N[s@?-?@c;b t{Wx|hV7ЬĶTdVg(҃^kbOq^K_8Fxt,> t^0:%̈p*$QgQyC)g)Lؾ}*?OqNz\Ї_T4No9838O._ןu;p?e}] 1*r^ /]p\+W6bClP>ZYd8Zb6_;LcM'>j ~i+k֢|!vJ mF#sYg3Std/c'|466ke:0Ƣk.X|:S8Z]oFb3CYUr󰋘ry7q E?:B\ȖAmӦ=sS(JK>Z~Ldm3N`o|㫘K\6\FCxry'b}(moT!U?i6*uNC9us۵kMi8-Xۊ\m7:ж=کw6,˨FCqa׼YL,.68W4ԑҎ>oG~^[W #NMTۭÚ&kLw>kJ ;CȺM")O`YvDϋ?\юQ S:#:uG&+VkۏYf9ӱ;~}1,{ln}YQّyyǭ2S~#YG.0:(ءN)f 刈[[F%YD:&`CM?yWtl`1|<Xѽ^t"8 {>8B  i,jRҩq.>.sD=bA{6Ls\2Ls=S5YEOft~XL6ϨY=$1Α(0א#$7q+mo$ Pkq]wc.wh,gx8,+1qI틫l&ZPt%&oA2.pf}|>5+P?̉Ix=]36'i[/hg~XR(J֖fsGEc:{ƳaFA|.mfZbDlf1Sj k9ml;…6/}}8ay'ǕW]NK*pMo֩~ GGUAc0g?Wbgr'R"vT/Uxi)1::tbD S>)=(1A;g]v*sɑ9Jw L1 o8{MMD) GiDŽ惋 nbn-fqwz>^nG?/@)18~窞fSSL=v |pZsaqC EcQcJ-6بv\ffMɏbh}6m ڻ㯽w>f={{3 "i&Q ?z!5'.+`up 76aWWg㱙(U)46(f3 ڎҜ+^zil#3rAv ޹fcmf8mkww7G1nX)>)iILK{8VeÊ=k&Xu Ip&kRUDjJ:&}!E$rk,>U-wͭ$:l|fQ/a}}y:KG:n^'|ZSXl^>Մ)ILrFؑ%,3_,^(h.3W06K7pdԓڍKNMy+W1mcńLܐE3Cw# [K`v7 uEC˕;7>Q<ۜU{ {r,_~ ۾_9)hxQs0R=xlSQMQ)*~l_G׿|Q3^!Gz7Cv/fь-䃢ƍu]|*TcXgǍ7ހ}:JQ`n>O,^7 8r7ͨ7F}vcxޣ 2:uvP2҂-#Vd1-f UIќy"l B~f Dn-bŠȑ8BU7SwbkDbtCKIb )NB3 rTjC3[ !cFP}] _C#O:[^-`^D6o|Aݨ>4ԝ#T掖11;_ߩ;k0R?xk6_-^b茪o`fT]o^Okҍab%UGbmFoZFhᨲi ~7x>XQ?߿7W{d)섡8o|[GQh(tBlfi`Gpﴕոo90/+FhUNm b3rBĭEP"G_F)#=qB6Fg2Ȕń'}UQU +; ٳkڲT#ק8Tk}86=F%l巉k/m֨hQ~.4|# t~#@6Nzzz LI-zc]vEk㔵WwGd_,:]?{|y)P@@$m2"fDž,3,f**oղf4`(^3m](a a2.i ,Vf 傈["֯_QwD;v]To LصjJywݝ0Tr|A? V\xTCx'mהWjoZ e+V=:`7}ۑ@@sώbv^e(ҹL`,MW>e˖#ȷ{O&ň`я~8X˨S_:q{f+dFlfϮ0W..{,qAL[l>D,kOtwܩ'l.|9 Bu) C;1.gh'DDŎP߳3%u8Y˞R{H.7xhL?l s;6-r1.74糑i'Ltaظ!cvx844B 6}5٫]&)"l 6S(uDZ8X"C\K/)7͕UW\9q̥6mzY$ p,gb^;^R b͟o};bfKi+BPYTU*(?~ш^ށK.c^[j_|At|m[ѵi} َ @S_t n]}='{?vf477=Ø kOڵ[s}߇~ޫGrn= ^r`y3:Ӷ\K/gMlxQ<7QA?C_~-p=Gŏ}=Z;h4FfBlfkw2G1O(;Ss^vaR`߾zdXFT kھB`e} p$-f %.2|͕&@A94,{f/;k~LgcN<{Xt¬:2-φճ>c>Y 55|13{!11zg8.!l(a톑RScP OE%*<e{"k:f4#occznx{hR{V[<>-oQ WOFZDf+߶׿A^,jN媫ϢBT,{j7z%ܯD %izz;8aGlR;;Wc)r?,TO'?٥ 稒裏yVՂ[zkz}܏<푅W^.u)&>]z%oE>,B"6=SWNjڋ'{Ft1y']brK-wyUI-ƚzb3REĭ2e6np]:ن)@͕ >YX(F$Q F1|sb #RxϸK !NLqo bB1fhHtL \wuhYچWRjJHEb`< 6oGɦz&d;6ohՠ>0Ka4ύ@Xnt5W)Mu-ʘ{i1>7fcD''}`]\9眭'^~#˰OAƼuɉsv:q\WqoA\ataBYhf/h/Xz㈙ӛ'ξX-'~xl>K9+)U͎B!"'abcfn}厕BtؙM 0t39@ CpwqK^ImmmgO#8n 2-cדQz·/mۦ#1>x-ƚ5ksiz;\'kmN: uyo>b4y¡y^ܷcvJKRYf7Vﵗ1t`DÊ.詬~53QSVUai'GC@{E+*=YO}%#ǃ韒 :Wm͹&<Ɣo趝SϰE)/)I)vk_~$#.·tE6֭[kAHɑb1;<Ly\vgпթOw eݻ0K/XG agX>j:>ڟdpSS#.}Ll|{?7S6y̺(߱LTsb+LȮWL!{g˗/TNܖ=>Bc9~-,VQs@ Kz,ѵ.THD|)- QzoV5:iPXb>Xȷ>hyl~]¢ƹ(t:Xt$>h:; >Nk::LAGߨE;umڵK=x:҃L#bh=snM?^9W^x1>&&&ӟ\cL6)v7Byȣ_FB*_VV/GuŎ~/#6Y_BG :BKM;[؊u{C>j9v, x@i_r T켻rC^,MuxVxbSNPdԾ{sq*dmЇ_H$#Fҗdj8n{ \zXq:xpv>6 ?Ɂ8)H?3_-1 acxޣCvFs\K?ޢE8ؘFk!; Hhp 7?YFE#; J^ڲaM:-[>{TA)իvک:Î ֊$ 7]}b$ fժz^ty睫 er+H0f{Xr2uEe>1ji۶u/tx)vMjZ4bkxhG0q:7oު{ 4/{scJvoM׿ɮNG8q&5EM8jPځʺ&khgǐAhd}עf%|GGMeƙU@aWXGr Xz<3pgw8ŭ.p`c +\U;'sn~:#;)qvT梫3磰tMox^2~V44XS[=x=27X|^cG]=y(0>67s+qkW_??׾U@1T 0XydN?t|S{nTaJQtvv"trpxb"T8qSLb6EqKMM>7Q>b?9(ϛcݍޖW}=NGRw[hhŨ~b*S<ub~?p|UƸ5М@}H "Gvj^|5S ɐB$b'559EbX}Vj"_ Rb1{M,QtlAnbk%%\@#gYr:38`s"_ar͉_7cNI} aUv{XXKȑ^Ç:A[[Nt:(ƌZر#=޽{)(2dy||cF~ό]u8ҵƪzniWAoּIF B,uNl4%Bf \{cd+Vqں# At'(G/d&_DN s]vkQ)ذY{.UM?턾6}ٴe-J1?zň,FEQe֢_ZඳGqDd8BVvC̭ re4!ꫛukFš2)f(^icH>CYb Qӱ8l=v؃c{-b.7u`%:#0B@ 7p晧2S)`}  + Qʘsh@HN;EH tJ+>6?;眳)7[dԽ=k|9R0谁îCߣSlm '7_.o/6Ow:})A_>C=#yX5֯_^X΂^WW!Ɗ+i bپJq5T>kH#eqvL,2/R-&n.opP)L)dQxtץhƔEf0!#ɲq[~eIq{/9%Ak5ADĭEFr͉9,Ĭvr Qؓݔ s: udWW̳/n2g1v:l!9Lp{(P|afWXɆ=ۏGg0n ]r%*u3NQUwFWWpJICqFD>6Ât~ȢRɕmBFQ(W _P#Ls '"#n&`Vo{.Z- nm%_ʊ snZ67ߠ_7YCřh ^ϨY-0m}U7ߕ۽3W{;T)63Nx})ѧ뮻X*r  {ժUWپ.1~S}O߀  B4ݛ7Ml  3[)/"n lFE(4&~ :h CC:Dv84 ,f \LxqDpy=lݡ~RO-L"ac1AeeUp:zf Phf P̥J7Y!O$JVk6DWA{!c3RFeP!6SrBl B̷Jľ!훒4oXylP z/)\!)B9!6Spf Ņ[%}eol'~o#· ŀips:r󜭳!6Sr@l B,J޵x!B1Xd{qX#6SRGl B,N<"n8nkم@ٛ&7 N4l\)P8 a3[eݻfm 3n|8b3A(f BL V"'Pj̷)B9!6Sp~"n!=j ‰p4f PA(AAAAEĭ2$MzA(5] LAJ slpUF8oVo` Bt.Ĺ%b3A(Ef Ή#V`ߜ|H$z{5{YAI^7󥝏vlpC{Óp -&=A$ HT#RQXF1xt ca A(jh ^6TmPYs)Xǫ=yS/5WSC4{œc;1D"83*~v?AJ+_w4,kA0ԽlXl鉏rd3b3A(}bի?IlAa :KvTf >@bj))Lǫ{YkD*Aht8&''>'Z _tH9)p5уxN"A(/] 79Ʊ%BYAxжmP !nIZb,ɉw~ WՎr*Fͬ Bpe U? 11̍D*bp~Aw{7b3AXdמ9 A^!6S(ND*Až?ga@{GGG;X(ͬ*5AX<({Gw6s>i hݛUdq(!QE޻;+tOn6oͨY,uTh5');8;H٨bAX®:@<J `t:,AX-mOۜ fFfkcQژb"_;$=Tn *eƼ(( 0rlQ}{lP\U8c':l? AߍwfE:,N&fz=(uFaې0 kdwZ9]ql̂VaFwAfaj4Bm@(:VWL*nD*a A(5hl[+Tf ʼn[%|$12 bvTfzg3G4z3g1\ \BW)\pb|q~m ط^ KʰNnf3]r.;ݶj3Bĭb*E2J ?ȟ7e3K-t)r53g-#L:ZSd TNuˑE\$5ǹi 4} 0{ islTvDLL9F!6S(>DA"a+\c/A(erN;%TlʘϨ.Gb \H.aUd" L:U,w;"4 ];-LDĭC ؔ|ִyL;)l%S/ly=+܎EMM JT-xb"p O)hIb`ԛw9njkjny]nNML.,;Eq1E;"n BNs\VVRעP4"oBEDcFi CA ][kFŹD?'2fT"?jpYUީQ[p [>wx-ZUTT ظ& ft#xv5PMTޯ{MTZ,ql٪DQ-ܹ Gџ%ɂ}sw[~S$ӱ? oouK/mҟ=sػwVe/~{شez\S?D~ !nvTby>uwwu '=h*d2#d,t-SǛж2xOPԢ/#Ħdx#"8rp0q7#@?ca1cQpaK$:X,7S)A–g>*Itvİ-*)WDf[)vо~~]–<}JR'SbH\ |1 [ P$Q"UrƘ#"fzbGpYgūZxIߴi{ -j\\cN]UxqirW |_z@A G׿ő|< :;WgՍx.e}mFt7חyơC2&VB13::vK,ׯį~k_^f׵=e{5UiqeIGk9鈰RDhljTSmy;o>Q% <:f^Nk"{O&9j_{GET69ѩP^ NE>C(Aԩ/@]u]VlRǬ=cy&A]#x{3mgl?wFf/U'G0n{-tTnj1ny#  #jfz"I(E׭[#mۮ:!Q X ۷瞣~aɒ%8x ڴեf(%jkkt>K[hllL.hࢋ.nrA7lؠkEަsZ(y6oެ[.l q^KwzMoz%LYX\ޞIJoMZ[\p/팰pߴ8O2Ǿk ±E+!v[ &ϾFAڲLU!e;gBGu.${XYZ[R9熣VQy"  !5-jHKY)AN(PSaZP>+lijjg~_'>9|VEr'}xT6 -_\ Aѣ=9=FO S8 ʼn3ĈgW\q9Jw9?R \FQ$!Wkެ{4Q\0`B!ض'ȈrFH1ISX|؂naPYm>u6[wgN-c"3^q\9ko7jNmQ?юֲ:.nUF-AA(2#p%!6Ӌ[!2O|M#$ >bD-JflXc t=]N 5y1DH^uVz= *j;7M:kٰP$Eh,i_úPYyTt+q:{Dő=:=Pl[NT/1]GJac\4u.f&VܦG8t3q`>يƔMOTΞ3"n-ZĩD"Nn๽w$oAtޫ }(Ƒ2I>a~1 >WHk^\QꔐEAh0Bײ:?+}Q WBOMG1ABJVGT /|J*LD3/1(Q첔.= uc(ꗯV(~WS$%ƍGLK7Lg)"\(i UKXSW֪m-ߠoNhJʴ_VYJ>'>j"V3KCA撜9!,iƣH"+j6غ=7vC XGcCbQ]#Y#,C幭?z:jL5;a$X)F*U .li0"aKaJ0H^L گjHthmEba}G4?nmMy'gT^XQk1. ,J[_"*ty6qnc̴Ri✎J%x08P!56k*VDU@SRj(*sjp\s_ ;OJJ@fSjն+*NEgYM?F]NObŻ0ѻ=碾m% L&!%hzIJYX 1nw,/=)A+`Cs'U`P mZ貔8oʹJS(_U 9CCpfTd:j޶v#id Gc$wgh1]Y@ETTՠ&5*j8:;aq'Zpϓ>oi+i'9a||RZ"%NzNǙBDS2PEQqNR}P N}1+N6>)G,AfWWT=MJ!ewYs먣T*! UD=zKudXf$㪡h-Z^YX h#Զ*j:a __~Gk^4I]e!vDa0󨥭pT=8+@{]Çaڵ@8zmmͺ&oQF&124f٠ eCbJGD(E& Q׬A44i% ѠlXTiF&ވH(mXk2{S:4%#%tjB $5 y{5V&-6 BπڟzUB[_k02D ^K;ע :`D.pCR|R.JߊdkGV{a[ I|BYJ3לּS"7 ǃKK/PBȵi«>GOO/jkkpxI9mؽ{֪FBSS#,Yql޼Y_(+3ar|4U6ıR+,q ϔzٻɰu5HSv3czzMU`BQ. AXi+sl&s8N uF[§~F>AQ v7i1UO@OQ a櫮R /ՠ P;2B[]*`T7Fz'TC4~ IT3I YFP&~e.5fTg<2- #-T_܅j-Hqe\O4L0MGBa$1!uT4U% u=߂JJ((Dzھz)(d;Y؝Jݠ 5TgL :Lc@ >{i}K0VjBWSoh;"ZVbޘ&:*d !aő" -ʦ%ыJrTjԡ?z;B<]/wI83PЌZ8da% ;F8ć**'RMK`L=K8l3FCUvU)ϻ%A8 xp,!vٶ*ȕS*kzLᤳs~]l]jU{ ^x;$^|.zXr'1<GSioRB݀r:Pժ!kzQ֒ZThjmFmc @4QUTT5TQժM^+j`a-Ԡ_5k5JUSpX#EgX8A*g3s~:w33T=D #ӀbE<EBT<+[s!8h[k% +w"ܕ-6&J34&=>24EsاFCanVb;8tdHCZӑhF$:sF*L "*YccZ tP]Q#Զ x|< NNg_>j&eKв}(EM2Dx"S4BeRumZVmu+uչGTa/1GFFs*n:U$j9)I~"`2zmh_ێ8"q/~!l>VOa-R.,koGz3ݫdL }j[ؠŭ ՁQS#3Cg4 *-oS~-/D*'ZY9m~ ̆ǐz,%|+3\&UJ߻;DEg3X֚?:64E:Cϒ x"ǕO}=A|FWZ_|=\FՠMsN_v V=xB_ AÒIp7nߊ}JhkB? iui:\SH67Nz&uw Xz&{5^ƒ^+ןdȃz];MkWۓ]X7{&qmxqKO+8ھT^ĈI~zO zpe3R_3|gUסk̈́!T@י[Tץ:Љ!~հiX҄z~^Հ:i5dRL(3nqd2ҿzӍFlȇꅯԍ&}aZgzǒXf F5:`o˼uH,1%64kxu2JZֺZ/:ȕjQy(y0RȨHuD #iD5a p M'd}rvLz{JG(Ou~8އhf3>:{H_m5(7 WseìQWJb Sus%3Я f+^b"cY@j~f-F1+;\QxjoG&)aeQR 1tgn|H]33-7ckڱkW%W8 hX_#(nدk3bQbJ|cc(^'bJ3ǟ,f8Sw#@hYЕ 3U6nX::KhTTawxf ڔz lfxü }jxe3?:{ N@J{${w97ě֓pƮ-յͪl\PlS͑j.k_~pfWT@ M ` q'Q"[t ݭn0 u?\~IO 's/JкtA]ILdl`tk}AA]GKID4Y$ VbthOFbfyTbMՕ[J\QǒסGV=V&監<_YpN58%б#ãhѶ !%qj ?Z!a'`ɲv~DpyݲuhiB\~-&aYIF]0].&rE8k,yX<7+zx ȬZ&j%H/*Lf* L *8DiNfcA=J3{cRԫ؀)Xf wnڄ`%Q ЅzPηɲ({;020;Zpj'#V&Y]hCChQnD Wآ(55^q);`ur\q:nzlgsX[_ .ݨ~ Ru.7l+X9t}G\}rqp?ޭ )A묉 XQLLCZn?c AMm[ѣ0or܇7]ؿ֞ pP:_~A^m+e5qT(k vK;^Ei%cQAifcoyյlW^E&5huJP?%%u}{2~~ 8Gquݞ146 4f$$?4VZaN5#ԍ.=p4=ݘ TTPY]C`<ҥKo/eW*a~X%:?, EX.F}tOGe)qwa+[Ě&j9-33AWm. C\Е-rYοE*݈WК5Nڄrޞ~6!44kgEjPrzw`5:mȹN NZĒ j:qUUģ~ꘔĖCx(+C-ز(Qh/65PS7 `#MjM:jm:e0遾^QYQJU *.Y#oe Fz0txJD}=4ʆ8lcUܷC7Zj$Wa5̃USnBG iE^Z\t؎NN͈NQ2وU?N6%F¬)7"0pUND ]qFq'Ft-w RRRvatl\ c(_ב\e;G"J4ic?{y9҃fWj8$CP"h TX<1 *+욞),tz~#JMDPO)c#!fCz9¡z=iWxk1JtĖkPڸ,Ke$Œ3.C+5WDhgaC/#cH=WZk3ʰ9*:^H(!8tu?Vr%p@aWO(5_+tnŵJ׽jTUU=^M^< 5Yl{ƆiG5LkQUW 'P8]wAr;CC#ɧ0rhIJ:LuՕFE2(Lm[$T/sB+X9t(/ksM " zU#N ayFoJ54L6£ZXǷ{ڦ?h#:d">WʩWUF}o*w3%3ēzԤ$VM##hOPSs~P̢P QbڌAu3#DS}~$NݸϽ܉Ε} !%ԣJ]0ZŰu>4xqaQTYo) .ILƢُq!VЌV5bFbugz\s@}VcO&REc醌ãE@1 _#بD6ņ1ĔSê5ߧ~.xwi7LwƚF`+qKi%b ;d~ 0?%>r:B$cBb+I>Ԙ,+D1[>|Uj{Q s];ul^I!]opxDHE|Iߤ~yuת`UǨUUQ`>GZϰNJ`^0vPh&TSHDQ0(<: &395a\}v9Rѽ 1GG10Czu}uM󈃺 JBO׭ {=xΚFǓ񵻷`ߐvQAkDJT;5x=#e8똀W<bU҄]dUdߩTӄ-'XWU+TOu}e2ƍ B!.4E:C1`?Fuc5j+U!;EQ#&)'6Þ=>%X26/_DJRNЀr۷c.%^5a߾}X~B" S) V\DQjAI"L} TNyL9 WNq<6:*]\sTKꭥ: Z2C=X֮έ`V NTZ+~Azs+qXbc_f#bjC:ĒJ 8dcaޣD=Z`eMBْ1,kלD1ՠƕ٪W^;ݻ01T{'U#QT^^l0 E] }NO*X@=DgɅT,<Nv"u*:?# |3l[TC1!%HO“hC!j@MÐ(pĵ ZNnrb3}؄UU~*ɎtDܣX.-&TЩ`*)X.'7eZo$;t8FqlA+xohؓFdU*Pb-;s*~EW–/hERȈ?HFF2uJZL訬qC/h)Ǔ؊'8JJ:xQ | p2] 3ճTϮD$PϜ`u%JL#66So8_U~ch2ʪHqLzpc*8XB )>]\zr2IcA]B#T=J0^9JT3ռZGD9hinS5Lx-ݮVQXrt.s=-quHr3*+Wb,~2Ft{hգL\,&>چXv+W^҈bNKPRaCm3^ǣcTBSrꯪo@zWcZ`ulT.̚$˲_㇖+*d誮 05pm\.]vik a1 0u.-R_k{*(U~"㇋{s=W D' u=Au82m+,q9/\wB6JFH, Xs DjBZ•+b̡U-̢AԘ\yD0z ȷ wp&1y{wIB#||EQ>V?}E9bQ@v0O> 1>$A]#ѐ=; ' #[M`$XlCvt]d4N׳sf(K֔IT-z! 7W+ɐ:MgQۨ 2G8={X $"vD9v{6+/,ZE@Uwvw`PMLFp .GSꕄM-Kkn}dYn`<_"}x'|@;DFe\=SbQ S),vcMS;$R'ൗ|/A3]BiMz k2BuQo,gZcd$bU@S8:F#a1*kIU̎%БwR7QRCٌWЬ!^nV[$8R5# KV#}__7zV 0^ H?L|WkEVJ{7KZqК.`Z,ե :v x?\V@$~~2)5jUـv09/vm촐 `0r!aJBrT花; f)>|T$ b AG&W6RenGvxQE5P)s39"}hix7q]srI;G 1狙i55DF@ ~$ggxw{gY&07Δ_Sʇ䳠 VH,FXj=tXꖂXzd:s0 6F ">)\C4є2B[0U)Dv q/q$~i e-~)ΠjR\<#61*7D.Jk06>2Ehm=˓OB,Db1 7똾D\8x\Œ\o|L? i*;S_LVQ&# nǵ]p6܅VsluLᷕm۴ߜ+M6:>32d~JZш`yum3-3L\SX)ta ddGz +>Y!ZiJпq oo[Qل$Ohj<ēOp~zqppՃrs!51\WVJ4I#D(=Uz{#G빚߉x4U|xN/#H֕+bK&QQkbH kU,olhJ=I#RͣT)X1;~ pnA9#,hDGQnp9+:4fIpdxa$0\XO~|O>341<<fk(q\W24h&51{3ǐa 1 W |m/('j#ϐ;ruZbxV抄Ր / V:axCF9Q[ˣkZᑑqcXt mf e,\'uȳM(l4H HÈ}  '8bM1wX/"GȐ|3RJ&M'0seh*@gq:AFY3it0=^1C=15i" LdzJ@VF^u]cPX\QSS3j6r8Ь?Tyx'!D^ClqpNDt~C λ}XyX((PQx=_9%/@I79񕖣UM1dh ##hD홿kX1w`y.(kFS,HFmjho"5$*MFPn:]w"2iG#rjUl9 K;J,(bLFK|TL޵:M|pjM(TC=|Zē-1T16I(SBbr`jֲF[Ɓr`hZWZ(qQWB ZY6:p4J|dU0X2V kEPԔTPAV-vWX-"ZmR^ШT>y_-J5DK@0<6d>^ʾe- U<n}ejϲGBēݢ*b1[R<>OS{{9Q3JNʖ2 NYg{I rp"+ $`a%%S\ @+ ,0 Q%h Y/юcLWPoxHK9r-ASAm+ӝ"BԩDm/KQ.brjX ~sx`Di12_}v~b 8q$=>6N_BHBIE݆?hbH=L bCybD!QSGMA,JBbرmF0rψʞm7Z MK'W<0bk_o<~5!Y2g jWsB+CϽ#!.s&U*ŒI23HO}_2Q`M66ZA,TΛ{?yuX_Y}jwZX0˔1 ;[n\/:F~+j} ˏMc8wܞz&!?\w:]SyKs4Pk'`Um]ogH[]c)8%|m7sFh9E0n)]cDj5r2#n-FmY8gXˋCL @Ցqbb͈_l@M졑| xҊ3C<r^9(me㘊|(Vy!f%Y)[\[6KdOP.?Rop8;Wm*wo}P;fHkw濯͞.Пm[GyBe\Ls766+++Z%16 %F@/ 1DA,& gipE9HE-&^eQfc0Kؠ\CrcT0,D;DZVbH\h+{mkZYV\C-Vb$jyqU{UM1: (/׺G(j"J{3byeA#"9t ha,V[x16>zørMZLRXC(@+tD$#^q[(uS> %{ǟ ☈(kwL5IҖw> EN`:ۇn6f#ȒDj0FffQ1<3/@#_F@dRt"ErJ>̅e:n lhSJ6L4٩i. g;l#n<β|A{hTIq!ܼyr"N8_ J%^xy8rV,engM5֐H$7~{t} Ey3TR 7j2hǎ%5pd4#â6DJWH{!igxdluFR> rO%WyV/rW7|zL88 ^i$k5\E!|T\ݩW;xfʊ%Qebp!hըي86cbda8FbaUViJxFubΈ9Q=ugWڦ!edDV qӊL/lĤVZd ͩf*@]4jfGvIbhHx*X}=@2xu8^05A!sG+BD )ț{x':`J / .d-cjo*rLEiCۀ^p:n  3P|#^ʚ,ZaIZ0J6b0Z=d2|_9Tnvz c#Q%oۢS͖5`bZ.#t-*5-j26>|{ˑ{MM[l%PuA-uz>'3%Q?w۞xMnЋykyI 4KE5NIpICd<$Yn]W[< !ƹƽ-}ObLHK cl1%ƒr͎>5 6qdRIl E4hlnpK?Y έR`1Uzg@j'wLV+Q`_c~FpCMU$ZqgΜЇzN>!x{ov:}={N FzuBr " WDdH $R%eTMo/Dz8-sO_(S`Ak09s#SpQK|cMC`FI<4*2Q-1;y~KIt7a\^ïR?}2e\n^6s@LÐg G_5#b$U (Q$4A1>Ӳՠ m}4-|n1$8L YDSNr9>D.9n*]wE3} L%061`Orh0 A:݃R?<enTi8m;=d۷6%Tr؛d~ꡉfj8P111j` 2xy/Fn1Bkii S l1*ձOpNq)g2 =z-k2`p@C"ȯ{U h$<$;RDЉ*kl\WCv̇zbWZ8w\G@- %0u<#,S;ׅjF{!!}<8x-\t^$x*VQ'P*-ƕpҗm?8),VH*`5,vyWsZ9qi4RGZO0լ+iw-%VDl{[ܽO Үh,@zx TH _P*'[ޥD,8I|EmZZ+눗_P͉YVC.W@zA_M "W!X&15(AOֆ LiT!y,iB :&{ݱsqRAǝFi8ey2ã]: qS,z~3wu;v!tESZ" AwI+2uxqdxL֦t4JMF &$`k_wØK?:8ߐ|YoKB>w-psy=[O1AWz8֑5S(VZC ZPJ!ULK5;ZQ/mu;=G8Ш<:2&Dʼnܖ6PGŢ6;V-qn4dY}OoO[uٞ gqvēD{Q Y,-/G-eˢЈv( t4x?X[X?qk rMJpgWAkS.g@O7JST;TV1P32Dfh^n:mQQm\aֿrߛa]*pozMOTST7Z7%.9oYݼ[ d2KaU_yaM BЫ/'O>4nGj.(ld1 4",JfWr̊I@`@q |z%?AD")6-6dRi kyG FƆj0kh{JRFRz6Ym0oue ""Lڇ K2QI7H%SX~3sD<,aɰ' |]MN pH_ Zҽ{"#(FR<G`y\yLd 4s8sZS7 !5]l7vh 6Vё+0̠+k5`ɤF+1I|,FڢLIPFV48H4BH\|v &鸮v((ia/-c0eLƢ$Nwۦk+N$lE3i4ui0 @kP5u?XXsͮƊFNuNk:lfdAʮʕkb|{ 'PxHB$4≕B+廙 Gd =҄C= 21@oRuQqv~fT|7i7&>-HVT?KJk X-TKǦtnNevxa74]FZfŧsZƹ\\XA!Fo%g4.HN0Y) !m3ϋl__jåyx8rEDYd $xԍzUQ,wKOT/#6\.{9̯Lmbuw1F(&%uަ8A=/ AtbV4L4VaKb`c;ӿf*C?\_A^mgޢ*b #|ݲQ,Ol5GJ+0>1Ʋi>3{!$LI҆[ؖ(B gp9/v B\OzH~՟jX{>(it(lTp\/>{ R#~0|qeA}<gوWFeI0ʍ4"nj0?9ha+ɓ{[;AJhȯQLAFE jεn1(JE#q<Ѳ783TR.(O_Oe'r ZO eSI@[SqYغpmiOP楳xw14: au*Vdދp杗hb/]7_ǻo,}8P E1mhs!\jl?} }^|@AO,ڸpL4hbiy+qi4uN-'aE8ٮP5su'$F9*[-3?2MߘlEt5#kl&f*i P吝p+JjAv.@8[XYL~# #sdN# YZGK'!> ÎD5'dg!1n1ʺ{1Fdtb@,(: ([%mɹՊ_ h$ZWA+_~ 5q߼Vj$"8!{E<š~|(XH2o9yw{Nw;R2)ǘlD[uXM˵ڦag2 ̱Αԛ @z-%sGw[(+R8q`T3'"8|kpyL>Uwb|)EHƭ-@.4{feD_m'F8T5Jf\kҕ2jE=t #2sA +9*& {a4({͋Hԑ( A:Vi ShpN,`fuEYjg`;4bJ˭{Ӻ Hf]&ֶ^`VwQz'0⊩}1J;1|[LU2:e@Z2!>ͶTŲTeh7xyE"j2BDoQk!Iȵ1C1EgIG \{E׎eN~1:u,PȍN q>vi3(녅p"qq$g[Q)#g6gDHQ؀uqcv}ݎ٫{>yg]У"ZI^UP `K~7>9ՎV Iާ~Ӡ}ؾ=0%Gx3 ɦ15 C򻤙JɿY$e;=zVa"XUTtC42^~;5ZFq&wp'- 3 aEvnP@*õVH=Lxo7mcyuIuLM ̸V.}`6?[GtyP  =!K9QX[% bE"A5[-+IT!׸eC}?I#fg+g+{pxiY{6i{̾?2}ks0_IgD%pKxkcB`4.ssT 6Ht? fbh:-׶uȣh5x !QBtdw{MMIi 5& hz:>Fõ,#)4̓#_Ĺ}Qowwc>HwEIPQv jbؐ +e ]x  FOG(-vw e*EBnܕV_%P_uh MފbK] qc}y:_Dž'JqÈIF]OOJ-ԉm$" %(~ȮذO@0r"( X\ҭK61S]Tc*QikE0Qow܈'0竃SjMssP) !"G1-ȒzS5.cyVW'j8r0?~g ]D3I:7.,ɑ1OL㥋H |NyG:¬l?p+d j$էq?Bzl6Y&X#!FKF@(+CQ~xc8|LŖxZTLͫG]vU8R$bmH:8Ֆ<̟Cj(_iu|0Q󌓢Xn `K~F$MCڳ[,U˳(A3*El]skEVEl65RiYLa87VkZ4JM톞#ǭâ4=2}'9>7=/)@/bPX-j޶bE+iLO/ɉa\q7琫$Fc_Gu%-m[y k#@$o˽qqq@FOs/ ~f_wׂ'Tn޼ ѣGso| 28rid2}\D~"X aXTe,`C*E!\r e _(Ǔa$d(614_<޹KU4R_ZĤ˼"ܶ[\ZĹw_ %ʽ³8ʆ(XVJPnx *&BΝLw8v(<l,=#Dc,F0L`bt+9 H<VJL&Y(J(eί'%=5>TC,ѓgzzCsbppn!yvb卢t d%Z/$H %q *UHOiS" F&-Xȇi!% ݒz o6&Ps:=M5e+7q|IxK (НV]ޑLgz#I3) Z&B*Dg4,[vf?x "Qƴ-$:9q \,8XX$[9!381&7cr}$-$= :hDZTEgW>yfN]đ%:+ ?e49fDJv,+J9~iFu(ݩV[8:tHHχQ &Y" 01QVg{eO X녥n\nJ:m@wC/GⓒR=aD)(JĐPoP}K # _y<ɈG\`|ʆPчHI+^^1JoQlˏQz=iˀ+J3U Jf[[[`"z(chd@%BD 㸵Gaq'xV$ppmqL %ɾ;C[G`&d|I 'QpO&mMU+w~3~ܪ ,EwTce\8R!1Vdz`\ڱQ,,YY>?W6T 1v,&z7=ya aZBAiZjx:(7d<퉳L 2 .-MϏ(nc WU{s,{1Nf3qUtŐq (`28& >86` ͙ iPǻC$WǠrldQIsL%W:[q$D=W&帬Lq E4 0Nq$h|zk)aR]Xz2P{vEM5eTwm[-r gxTbATFx Tm@5T# #ÆcF-$thȽ5nH܏V2GJܵM 5~߶bæ|j1F0"K)`QIR(gƈc,{ZbhAox b R)ٖgCyU<xu?xP%lg(#:O&[* C&hdWD̔P@Cmi2%PhQ rzkM@bPv+Jn]+E:Sd?* )"]O6s9"ٷ90}b-m*\^@<z^פ p)1ve3 U+)̀'KSG1ZR>@Ξ;T[Ґh)%flkAJU qǘ&JxcO\'w]@njQYN7oTFS drrhm+vBɄqx:|- q a$J(Ų,GJ=IMeV FtLkڛ#tV#S.CJ4=6pm\ )E1$&G;U[݊H ҙuҼ^ca,tb[(I&qIV x@Q sÆԩ'Q|1;:+K7b*M!03*QQ0*"~ F%HF &ϰŨhJR\`*e,CFQL2Z6*BvdK `q5'Hsl^ib89<(9(RR||:Jq({㳣x?mT@!qtC[#iMUnh8"Z0A=Y˪^+s4hLĖF-MECc\٨ إMua:A)~:H`* 8x]5ѕ<Ф&|V@dpXk &2V2mm*FXG4D1r- #,YXd /vk?nfO>:|Q-Đ|y$Du휂T{gYɟ~U b#O}O4bjϹř'|`WmJǃp zml7uLEmU 鈠s"͛kxa@68[&uq,G#<\ E}Ah.rsţ|#qȷ$CҞ^| |I@^}n*Bnseicm6ז ؑQ,^d<.,.>bs0<5)m4 @L:l{Rxr_/|*Ed"3ﶔXR)|o6z!USe-g3UWVTS܆|[tu=Cat2ERi@d:3,jjUfQcG1$kZD@X !I< 8!Gj.!ez6J-Od u O>o[DEړAbxYn|ָ/"3N}ʝ5wA'3b AG0;A8Zq/vÈ:[Ĺn9fEO>ZY~z+rT4]s1.ՐM'k TcaS;!Un{G!J/ާDFTfϏd8N)orR, h&dԧioVOl?~DâPG""IuGG"X5 G;X@1+Uzlۗϭ!=ZH7LyrH3|qzcvn7Q0|Ca4$ɲ=LO؄xE{ c:9|u.'WP6Ej0mNk}W?0(FǤ`^SIJܲu~(<pUP00Oq֟Ԋb^, :_By-޺s?wSCxy!y.bX[Z OpXE~|8'&/zPD燽 ( PȣRKM%^ spkai4|0BY=f񇢘B)"#5J%`uu[='a%A|!Š O|wQtJxپ)ۧàj2'2 Pݔ\W5X鶣kcnKm4$hʌbO4UDPH/v.Z rEAFT1k)@W.0B,!# L\_9Øn`Zb]D>HOooR-\$D#cS+-g*qÓ}"'X(KN?C:-Q|VPzvzn[-(gM"=OHKA'ҙ7gkT ou䣗:7>>.T}]ED#~L%2 kȟ-SL/<eO@ ?.YpR*qfזR mG[Odcеb$^*ԇfHb6P7ϱ!fx\ᅪ<)5%_?X_Vs۸z51d«HJyG 2wGxuRji5H{51|*qQ n`D nbC+F,jȠ^x~ ieZC%1Bb4 |򌮩ˆw7r$8rc1`H@ưKD-}3YY- 򲿴'Oa-urPv8x[m\9ڕM'pg1 C*eFV?"}֒aKUEk*l T -Y@&dvsAAcǎ8^.!=>+`~fe 005y@x E);9pT%5aO͡[/ PpO&En(22F^ 32,+uy5-oRP$#k;AM7`h3,s&09j9iOvHBHs[X^9o՛K\ ,},8Lr Tu㨊fѨV4`v(G,D>pM(k!)D\#њUEuL86HP?3}wwjW4,'K#.R"J$6TQ8?gC~s 0e`bbgΜʼnUAG!C2>N}l3]d>y2yP\2dCZEro8Ixb(TʦJ `F, x)S"A:Hr7b%ū|;:H$ -9X'GK`;W:8Geޯ\b!\ʲr} {THu8[F057S./x?@FW ]9w-4)1`ӧ]hR`bh/m[(BBZց z2^l#)S9W@66\T4bJ!K70I#%Fp"%r8FS']2wP(WpXBBaG5wqaV]u[k!v{lvB+pKǕL JGP.W5R$sm|LdziB2@傩Hi6j;=;'5)YTW1)sfQTh;Oɸc5VEGOӎWq4Fmz ӣ1v,J{r㑃~􂍃C8:+o_~n4dr$1. n}9nqZ] *>r|Y瓃q4 LGpu_ȏ[asbl?4~tdvL=L"~g}DZc- 輦p~Q.Hד>jU5t*( ppKFI TRM7xJ2|x(  >CP|5\|C@{$v:'!yL:(b.ߔoKa4<x,.ɇObi YGg"n|bU"hK@U [7Q(:0V*PvE->TμM:PQki=Wsgˢ/̱ܲQ- )(quMKq͎KmxQ[ܛ0#p!Pgy*4r'mwJ}WΡy][S [.ߖ3N7(}4و/knEadMEu-RqV(q˔Ij(c5\;B !`MF[Ucj0~G&5e]#s|Arkt0ySٜ+5\+`ĈRSx>o`{2Hqx!D)Eg"A*}[ƾLŇg03w?7n}/6Hrfү'޽z,yY#bx;oy|B@7-i1rRZiz _xBAlT["(Fp|aq {e"bQ[6ӏ,mnwS J5xhÀL\[WzZEn~f gxl&\Cx꒍3KW*X[4fZ\&H:2oT+mYϯá0~C_N=0Zq fp4j]9%PO nMhvge^浂WǑGp Cb4«¡/P:)@D`O* BB3ciA2W߼I廳̝m̎'}\qrXm>w/<(b ]FWDo̙5UCY'<`/+Mq<xsh3=y ְ2/n}Tj4pͼSm2.!L9?p zͤfWH۾:xͿߟ ]X9ݏ|{ɵV=v-(zaΡVs 婕0Af @],߲ju b@v5%QUPX[ %NPFQ之'IjdV .%ZW]'k1Sc[9VlTkZ8p!>VC}"ɥ'>⦥خLJ 孢@e1Y)TETޥ)OPcɈ.N9YA LvuHR@#GH>i{#sqxyɇW|/޶G֟O0'RkBtqb7e$%Jo׍|kuzZY)5ƥۿt?|cO=9T ^GEŻ-tFɇο\kN搱OI "h+G uϨ,n=ABIdx Ek/d_ ^fpɱ E1,I$[Xi!K(J:3 ,8#ӆ\NOıqM$@,lsG55뾿P 'M( h Zʎ X*  釅1CY$QY0WK O>8|k8tC865y@#͢;0L܏!# 9 &Q]O.F ñЉ#X}k7n}Dhtht+Wט^˧A̓Op-7[{muGz'|wT۬p1;QW1l֌2Uuc&e0!fc}ns%FkUmuB oG.t1^Fn Dbw>-.p+s2NO/)!1ĜRvwǕ{Ht1|Hyzvx^ęݛ!ɷ=i{_Ժ۪9y^|.x;?*.eG[^嚏VFiA}̗x"fƓJb:›W f"tѬ4= |4jF:Cciy 0!#9ZYƍyA&9)8?r?={I<fX(kGGMQ+#(֕k!GQAR sx80wdJ#jk$x/a@LODSM*V3 4KFT~2ٌ* ؞@$ j44ʨK3Y UBtA8]YWE?zxcr?n[O])}qWqc%|qONLuz_ͭo2h`r8 +sG{K8Rț_}Vl1VIlq ^VByTVJmTqo)ۍf|ݝ[vow77}xa$K<P!e{!;ᡸ~ 㙹QҩmkMWW^fMtxLZt(Vn 3o#$ԁp?R0ϗ":*pA,bYkxwpv0^y㬀Lu|kϢ-3JGRyDpDl&UElqpf.-◾$~= N:^zM<-VJ3sⵍkzkW/]E6Blx!k? }"N_|qw1X1ȫX&奥LRN;r0bN֔! ӔhYYN#UP3ݶ!3\y<ܙtZSUۣӌh/m_S.#YgtrjٯT[&=79LD^+ Zu~M/1bfr|e݁g̘$HQ`z7a9.NN||)d?Oe[d}&a+>K?S?pƐ`_Fj=\!B%xOG*ÔCxi}~Q_"&-q(>QpEѝ<:69]ħ" %!ZK$fAxI|__7q.={Qs-F$6鈘Sf(Uފ =.[o}2> 榱^`NONp L 61~J3X&}{B_O#LMO~$&^J.xcG~'( ߜTUy>Vu:.̴1c,LeSfUSi `meI؍ 0OOp<S1ph1w$<0j dޭ o.n=k@?x3['іu(᧧S'N"L"ÓOVX,);S[N7v!f> jA %뵱QFp/4hUjEt/j˩Sp )Y`DwLj+xF:|X* y”dZu.b#26{I3Rq1k%9Gyf א9 oX^^EvQdlK ۚVdx4XFš/mEQ}$= OP~I> mHwϓ2O xeS=;N cG4OA4G&p _ z!z1btaTa8ñã_C4J3mpyJx|9|ODf4o/ڥvHb$bdQN_WmNlԱtmW/~Y'b~[-v[Ѱuhm`xxLZkLEYKڮػvu]mA&gP-WYkF (_\ Aj#7=# :!kw\h2:O`*EQqI[M,\; QrCR dF1)ӪE^!r=Rˍ#VZut WMkWGki|YreXNr4Э QGTf 0"X%ӾAF_z:$.31*<>% yxEF{F%fW==gE,$';$@g A^[LįG3Wk,"M4#:&`B׮ "mFMQf <;ŔǨ,x&xp"WjJgB6(^X*HBm[ϧ m4Q~zbp+21رP[{~0; I?l,elLR?(h2WJ]$rx2PtSV G0wpdX.aUb$̺xvSG%|Q|燯\"91+OD eРXiu:e_]'JRi94oyW0joaz| fuJtN%+Mbiub85g7ߡ'0V-ib|l]{ʓSwıh*Q̭ 0B,DY"E%_GvsZC0"Ѯm1s9Ak""p*p:klS5\A4kY?by@+R(Ղ1l+&Db3ʬ"[VŠe8"V@dsaƣ$?]@\rsU;JrVת/!WV4])M$\ + Xvs-@mq%9; !0Ϭ),..SZхP(jxv"8O6=PWdBM%}&'Έ:R>rę]% mYl+_kX6<*0`ZR[R.Ÿ+affFܸqCHT <!aFGa^#Gk.\ĉl㔗_~Gw gdd?199!uSL&ORYB Hj e~ΝJcd>tΈŢ:S$>) X]ɣh]-a|b qtu'?5hY5 : i͟GR,zw4̡E"76Ξ=qkȱT 'of'J48\~v_XO-AXaz ¶ҧZ9~B.k^1sJESWۀfkc19Y(DnKiҬ%tݮH#*{K~m&EEضwS;qm+Oڽ3Q@{崂LfmYfuc[Le ر0jH2rHD71:!# @#۩Dz裞gk-Yʪcf#H 1kLetqRpK M urVOk1emW:F:5qFH0;W'GxXwdN _ca - Do`0%K 5![]Z!K ~-9d>ŋ Ob8=./o'BhpVX(_scf}Q/U <Qbၐ#:v™$cEcj@yW4 u! ᠞|Za"%ẽ,`)Pn Y$'X"\(dCf2Hdtc/AX⻩䄤5PkWpƪ8xbTjz$ӧv:]խy|]VC jWWȭKsX)*H,5QamO>>"J1gcMKWc* ͍T=m"yaY8#Zk3 ;hѱ,^,{'r]SZG:/JȰ]KӞRg@[J0bFpʎhkjz^SkD|՝.?(3רOlcj!ݴmXh~B Fep^tx P77mE Վmݙ9O>\rEFeYn1'JĴZ FDIOwUNLGcf&ᷛx[!,,]H  x,)n^riUSCgT£˫XC*!abv> =*OI@Nt9L\+Nn6 Ω)򻫩f=S$!0ICPPK,HhE_2O4>:Z }]PqFpk}GtEJ[I+ (1ҾJ;=>9痵yVk}#7!X<*}['}"B^1_O~> oŗ tD2Q&1PwZdގEs\Cǣ EcQcvא^¥#|`x1Ev4'ND]12^5f;4 S<2eϻOUgu5D\9WRMKJjc*"otѣG<أ;i)}ukFV17 DÇor}\SOGRAj0F<9[ב`s(;KUI6]]@:+@%#?eu]Lq T-K ;81=뗯"Sp2󽎀a-Mz841"'tm/̇f1ann vQ2ڕ̝uierZwX*y F>M9f  p~!tH'ݏ@  t}oJb߽[,}z AedbZ0>j*=[ҮFO>?B9u2 s. aU V#.eOaD#:0YƹteXqd =KOv,N ŷӾ3aUËOG}uIiS# i!g^c+ )cu肮)cTg^kIKƖlÓ%OS<$['|W'$R\mIYq c" L_%Xn)^xO=$N=rI\Vmڲ6ʷ;!6|{KЂEKCV}u}q+l߾ymz۷ߺގkۆslg()yٶX[moχ# 6y(o߀۴cՠm'9XuC f.̄@|=qe,d(];E,{cCS vI 0Z:zبVcz΁Z9~׾p<[%8h 3X춥xM96"4#Y…kX]]'FNK{ɊBL:HH#Kbu0qX14b7PqCHwmh& G L]smղ48HZ]տASo +8T@]Fa]uv[uC\{C+" 3lڛGԕoJ&Ej =nZLIl>ɝj0 t4{ï1=o[D-O_֝gJLXs@ݣzҖo{1OH7A$cRry-Ἱ͑1k{Fӱ۷o^ӲvTkܙMNumk`kn}-mg&O>0TcStO5׆{AA~ߙȱtOZ*n^1߱hDGy>OWZl'FN#Ȃ8p CJ 0Tv2=\+xM-jd$,FF$w.s H%Zu sC\Bٹs&~W~^ gϟ`(5'sr hnOEgIN!ЈPϹBIb1B.F6;(cqS-tʯ)S4̺jlC CEwq˜ÿ^w\~ Z#h{ vFA0WJSqI1(U%RZB4ps);v[UdUǟKC hxFZ?l*rkP(mm:\ZcgvSw˯1 G"cK@f0+PШs4J5ivO69a;'}TF$HG?%[W.AFʽϟki%GٕrE@mW7 ?f_p WG3A3W?-jIƃq=qc@}L&Ox>dlVK<8>Yz{!ϡ.݀t|eyϕ olmc;U,Q޾{rl&mq~dk;Ω0ca ?T`,lԆ'ܫpq jﱱQ~s}ʢ,-@U!CG(!'ښғ;s/(?tpBWOTix4 'Fqxf_xF.,屼޻յڍ:ڭ7d.) hhbU&G'ƛob]%?څVy8.n@2g+6py'a[ |Ǵ I.ZUۻ3H~vKKտ;J̐i3?e8Y=u@oݏڱgR'wA.9tvTz_o|ڶ͐]iu[J7]h8Wrvsl߮c_}=-3M#Rr|FRJe<8O ;8OZ ]uW@-_E20A ZS{1MtWTUDYx27NG!Y˕^^c*jVe^QD' ;g#!l0> :y-"'^ŵKO?+by~O5~*|8# ;r>@WͪysJIJZ9( gۦE/~FH jQ)px'-Et-9n,=̻+8r0Wpu!vj>q_oarr||28kƎ5cˏwXnUAB57نٳ= R>({miv@k[e$"#ajk$/rG6gg+}wY'2xXܡOɾUǏ͏y%-e;}꧜m3Sʪm[vv̺[9ힽŹga*FUW.Xk#--/nKHO]etz&`Ua+ TKǨ0 kdKu"!|rwY*ZPFtb5 *G uis fM`d&M[n5k"䲓c˹q#ݯ,WS2x>/ٓrvGs7B 쾴2 # ~nz"@2R(͛{Аbxu4u5hv\(ѣG17; )A(͎(1c93ܭ{pn "v v.m.&K,۷n?ع]IRK]OR8}˕Ju# NLcaaQG5իXYY8sVqLP2٬Z]]Ŭh|: C<^o&wL2n|H(ZpCU A?c'Y\>^J{ o~;IxX݁s^AٹݦuHmo:v!4:)'!+k󙮁usj%xE]=ׇVݸ6uUM~9nD_D$@SpLgF2c(QE0T}By}`D4"4K-@%VXNptAyj)kőP~J j5[J0ߏvOCeE'VlUrxz=܊n-OD/X>O(T2MNdwdвkBl._(LwRC.+#vJ=>/dW}.Vۍ~,}%On~ۃGzmǍĸ&իX 0K&*_@jHA r媒? ੧⒀I˾\aZ/~C yiqӧOy;;<6660::A+V[ZZv#*"E{oZ.\nOS ;vL!OC6Mu0tpy)tࡹMq,Y˜p/Fȱ^畵-upAN#BL,&d$ecC*` zcu7B2(p$q д|"K ku>"-ͺDvSO:1_kY59/$}Z*Eȑ.\ a!WJe g‘>4tJQ=in Gո͆\Ҽ}[W}r^6@ YZ`'8?):'(!_C$D"BNaQH4f ii~iQ)-9ȃ=(]WޠN X&%W6"ΪO.e>:][~/0ZAOX@|;;S-Ow[D ^!Mxlk]APxP Gd]7ͥ/S{=fY~*XK1_8lä n)'ڀ-n0]-ND p;_e~,÷B>x,֮}/"/U裒ڵk5J|N:)\?|Jys_ pTo_>I`//+[H_&ɧW8il"mooŸɟ',AƛG01|(I__s 2۷$"6F6n|bqeWxdZ-811dϏPc!|h 80(UoqY[ $AŸ>Y~~>Xm1tC$ԖC[3]\Q~\jm~5jʫ0Ov 3-mJ{]e6Ɠ 8v ,9@ i Ț/q@ՠAهy ;ijWTĦ+ahX|'A[iQ,$`OƛͶ"@1نhچ>~Sⰰ HW>_X+֒7:C$9:B옔Ǿa)YO:^B/PyL4T|d4ifJE'h4Y$d"<$G2oF715H s#I8$ wO #F dа.o8K6*͒4)H~N 5G~ˍP'$X.42d[*aQo@hv@ =%#)v8Ύ~߁iֶ{_SɌlUdD9\L;˳~qk}r},|ySoO,j>y42_΁m)<bT'o(ixkN*7h=WZXL$6鿝5Zɋc*fֆKA5dK. 5vp}Ur̊lw;XXȨ+BAnjj5)c[hXlUI05>B疃lR@T+-$T#.֪ML%nCDO#6*4-t>-6ֺ.s E;_[W*k{{JQؐR@Ks@)o;J+:ÈȻqÙL~m3 S`Ҩޖv FjwPXH2(k 5T`XX)'*b\+BLtܮF]) *u |,A9xhp+?RW/*}",N;ޑkλr}{Nmޭݩ>M7bwIH$+GL р??J $GǐoD$[?DR>uz7V̕c7w!N#.mVD1um :^"(< kpcm j6zZXGypmh`D,Z¿K093b!Jt&+J702:U|Ƶkx 8n|xŋ-mD M: :Bͭ"(e3 ѬTe;>Q׎%ao,w6n^G0UYo.|/Yi,F(熔o(FE6W׵9RI8Z@MaIK  СG|g ѦD@MxIX˗M'[_ wwȑ#x?-Ft '%e$ꥥ%!F8x!Й+ ۦz,P6/;~z6us7nQ-|mj?عÕY5/K_ꡳ]{p3,sآg~}܇]U=^6Q bJf-bWU+5y B( QATݥ~C VK?S3OJ(0(VXyz #Jjd{aYC1S01_s9eu(k[!EKЈ-h.nHhr%FaO*fKb>=.'OĐuoqxr Pi{GC:[L7Ŕ݊L1޶% Xf[GB9>kWǡ}]MދBxzwڨ'^.אwZiTBi;ѱ%g'6=Gﵛ4Zye-)I0݄Ė( A@wNӊcoǹMV[UjeڝR{؍eQ@7O\|o*B»:rNf'Fq2?Rᅧ+sqx}׳pPzjm嘀ͮ3/rF/F'~N qM4g(QgC<+Bx< 5#c/>w[o ?o'(E}?Zכ8>;硃r10^\/k?s #8.c?xeT~RoS!T'_h0ƛ?~YlTr(\_PP/x17;'8z5e9qOȺ!ygX&#xo8O>oEc.+0e"=8 =CH|>u:S=3Um]BC6j]+d]6Vs(v-4>#MM ,zFSt+:nJe]J-.6*PEƙCGgp`$HrX6Bd &?MgNݛ]}=qu 293<|nR(" %"H#^iW/G>_iv" C(,koy(G1OXACSdB~BL&wqD^\`~Oq;؃filh;w$ہKKZ= K<5j}ry 67P#hdʇ'%JhD#:rr|e /~Ea4Z}D2^%E-J}Lh5cwn^}*k[i 1w?ۆ{o;XN2ȭZJ`^<~N% g^@G`hW_B$}H_s-Vv@j0Dyz 3 'D𐯉o#p"O~+79K8ofͯg'`7kHx ֯`-7caqAVa"7o߫?ELJ?mtNdqUGO~ ז9=WEAgt yw4/=,fǐ8Mj::#oPN& KXz8^0=ߛI$f;[jbP(e~zzJfPg};^?yȑʝccchۣv dZ 5˳Ր ,o"XwD#^Zqb䖼o]R.Pchzvw-;={ױpjg=$;pһ4w՗zd 92|m=ƵHݺ'E',FG"ĵ9}YXz+ITc|jJYE`f c#~7~Q6|1"?U'0q0UQ@BDO {883C o< 0IWChek scX\dֻD-Foĕo|+d!?*W7WԴ~ cir _} >|{DVWv jU,[xbDY$g;Ukk:o"@i<Ƞ7iE} *n,tpnGtm3oQd }{'|x> n1B)iS6UXmbXq\ō"˘KdWV(]"0F^r]%0BUr eeeZA^Gj9}qdtVUO}ą(2yxy  X(y-Q' `|(!XCQl4(-NZ)3"@`"+h^5>EXZ)YT4wk  S1(<*6Ż?,Va@c ]06wH,Cc|lgfjb0In$- /bcb:Y^aHPRfL!m}q{nM zbnd3r+ rA~ l*ʢBA~T[rY0<3o{]`[&IYLIPvP* &n$te_| GNc6osjwmJLs[䛳_mϺDg_;;0qPŠ[o&ʈUgV<DASȎc0tv~HrBo3W"N2+ B /&"VXz~28T<4=Xq_{!z##axZƲ8Ut6p+}Xh/ȱ梧#V~nFl}0vOtS rN!O]@#)lg8rYlCDMCgx^B'o(,_T5q1kj~EaڝmFO]-[94UQ>S XTQ4BueEWwHǒ5`Y0; w2= {Qr`Vz-A.=`Pr6T5Q5q'jlUvY 3[7ޣxxѡTzO4 gb&!Rj&ȱ8Rgj*9< Sx̼q7Z2&b!bWa>Q'/iY\;w^};[VwԩS8R 0%T?}qD៘uFD'ܹ9\g,kQ5TGfQ1n"lU.CRED2#q u~G"/<(CqŬ<Vyj6=z(,n$X1wFM`19|(nt--µ% G$Sc7Eyd mh5R+&W^ ҙr `T76XZ,$u/?vOuX,m'{pmSԙbA (Ghnj8R=@ 1|IwNdfH#MF,glo50sX̕]]CFW>RTDJv)c3Gw !qHji)ZiϩAf?lj[M.H$}BmfQ ){ڽ{O B[Wkuw6j-X!鞦6m3g4=P%X|+8,,#ȽÐ%Q3Vf8bN~7ɺJpR]ld.+TbpxjS)(ټO7̾~T /3/sz|8!G/_ ~iTZ\D/__Ͼ'ozI|ҦNM`ml'x=,( 6!NP^7^}~U :[d<:Ϳ.| YKZyR&O=02 <#FZBPhf}A6;=~gb|f+dG.a\>g1_?x ͖Fpb*<uww{ȌC?~Gup5NJOo߸&F_?xYta/ʓ0 QNЀQoh d"!T  #:7/bNx.bAkԇ* is6ʌQe%b?~q~Ȫ4eN=|xN.TY<'C]hzMl͒0?.z$5L'6@Kƅ(rb3*XTPu:s@}&eG`bh`Kj&WG_ndCp 4DsܴbPGSt`򯆍FMѤ%:8?VArE)q D(욌L]:H1K8Nh,׵Xa}ؓ Od}3vk"1|4d^L;>;(ԂɥЯ|sd&D^+4/,4=Zl` dMSվe&IN\\۬N7l\mTJFmQrỹIf&#m9mb;. \ ȂXՔ# 1澻ioVN1կ6GK xhBp R,\J\ 8sj țrlMDCi%Y|niw0&j1DV)wReE]jj v>*oOWLh4X':lvHYݏb W7IO7:F-`jKГ@ i miDbwu;0"@kgt atCJ2;+_o3x/JMn$r)]t<4Μ9oqyLOU<)>nt]yoSqz̙xobeP~z`j,8( 8'O䵍2J=+E;˘tpMy>Q+_~Jx$nse>9NCsbdIP%Frǂkrz c'3kAwKp\vǭ!%o}@Б1i_7&S~GH"_xJ?|z M&Qa'D%1[͝Q\Z(F,P,X]Q* XJW+9J@֫>Ȱ7h;kM}]~Ia/q 0vdēM]Z[*φ+Q'TPkD_ Pfu؛V\IlpT!Bub˦Hc,2.1[ 1cES D1=X~*Lٮf>j5uM'Xlbԣ>M=Gh=^.X`X*Y)ٯh@&f8y ٪6;c<n i0zc5yCG!B'3&PQ T 1ʊ@yNff@lr/J %M*dFީKMJ&94dT#ǰ 8.Џ2ĎRm@X_z:o?pp3Q[}f_al:naG'"J[HNV "Яbm4qs˶ʹ my'LŷdV~AN] \\z}>AmWċ\mTsv}g\.2j xO9i|=zT#xXn>6h׽ޠ47H(cǷmV nm O AP7 uڃ-߀[6 tpDۍCLM!y3-4/}K;8v(>)xy(BXƻ9pHNgaQvQ[hQnGF1wpKWeF՟{F:Νf~OnaDc6BtYϧfGgF~VzۍX2N|NT1aD]q=OwȘ t# LUӉNk(_.N(CܮAi_ri7Dwmk@A:B]^_rx?$'a9n6R~ ; ڐ kX)F^cU:"`5M*Y;12YyFCY.heEc-3qO"z鲴Id#eJ~x.F3 MO2t#԰k~͍lKeRAGG&j&"plC(BR,R4#5"CA7kl9o5iʓ9c. )mKӏEnmA~V1qMQUùˆ$~SV~MCGgG5cPqW fY,!=`L@XEK"kf9H;p{gjFDZj-MlZ:6q6+[h6!g(4JN(ż[[%x 2rOҥ(16s?#'IL0z%ɏD{Gx'pQ@7sX]`IR7Frx_~A[XYZFM{@o͟Q*LUA$/>Y[}nH..0^G3An!jG#-[ ὫM<0B,z#3axB#yqA@w+W(Gɓ9Gݗ^zESxK7Ν,l(z=|KR>.'? Q?;#NNo #UOZYg䟲kɹa5+L1HH+u:a{aj]Wd_{ٲ<컡ra^v3].IJ%`$dB, ˀa`@%K2$bM3;39ιrA߹Uy|3sϭsa4a&ˬdwe bv6dҪ@Lۅpd(2W2mtY1qИǀe!ANG>?K&x ɭ78sF,31$/@SrH%~w^ 8Y.I *p>>N&W5oHO fVҹ=7\iVde %i-n },r G#ɦ%⬈3 w^! QvY"G{Z=2Y" vevM4\?\Vi\ZdoMk;JavN3LlF6^"<".i-+L],^v5rMv_j`ώ!P@5Es啊[v lViKsӃ]51;7X4*p8]6uV4k[̈YCP(7wY47/S*+ebh- 1F )814H O"1O!CZzb+WMO?;GK5M(dR|h "*aatwܹIi>N-6nO@m|x\%Oa-Ut+a,b~V;yK:=dTsEgo$aWI|Oy~kSE\d& i6R9q*wu*'!vVVVrVHH?ܳx7!߻駟{yffEטXG}} 'y㏎<O@BA&Jڠ2xQ #dVeݙ`LJ2=_yj4; bV}x('*V 21i E! 4a\&o.ٖ{Ճ9Gd85ذLKJsS匉JAp0c>;wii/xiV2:Q;\&{ k zH` ;kD||a\I4V ">lxqjKqxZXM "7Ҭh4餻eBe+ىE<.yc2fݦ] 6p仹D34Q#d֣)"p 4ݾAx YuVv!DDyE죬 eB6])^WIPJ]+cgӾ2rlJS]v:nX3_J3̈́Z5o ڴZFcBnstyZ›neUO/נMs p;偖L-g?9yk5/EjSm\Cȗ:. A:j~,>4(I\s8v}9q10:v9٪ r&):vC_B F1bz35F!V Þ9i"MTyPĽg66M5z*xIފ\Y,GOgDLz [}N%O@5"½p`nT2)¦;?_9 $Edcn., ?-7f5O|> ɿĽ n9 >\L:Dp4i*R܂'u߉pCrݩcQx"y+ ݺ6y׫dG1=ɇ.~|?麣 +ŕc[P!M$Qn^8Hl]bAD0eTTcδC(4R*Lsvb 83zm!;aD?MސIn=$f`%zGəW=rXRA;Ճg4pHbc9O`V# %KR5+ xVeRˆUF0VEy{X04vUEI9ǰ ?)jP"ǮWiuRy_lAm0t>)vݾI}F5UeMcO]{U݊ u8e>7<>y ~<lY%jT<Κ%VC+0oX^ l,c  \^\FPUJUUˠPvF_fh4Ww؍Æ"_1hW/N|~>zGzi$H.s;<$j+L_RFvh 0} J"~"P0%iav(R1'ҴS17y"J\z~4D@UBW>SO"FXKЅN"Zqv̝XUT'&?V[ΤQ=8CgC|bޙu&E"2"Ɉ(U($ l癣3_˥FnxYFDd4m1j0}a"?y`A/mτ f@M M02~_z)tB-E{Ŗ8kU@=L`6C(MissHL4GZLYXx宥QA~'J颺ƵѺ5Nuѹ-2q;s;ױKg[gEqFq KkhyM!щq\T=ڻyIǐֽ{iǪ"鞤!w6* u7_VXcT9e "ƒ^$v)$TMoU#(rYJQ6RauYFYx?Qt,!{`;;!ؖKRuw;:z!H3m~`ES~ʳURgR8Ue&,^n7U$Ueb bwʰTTJmY(AmWscF4#\~G#qK yJ$[`@9/ tnA*"9,=v A ]N FdM~Ld̜?`(\{4ݢ!t/&8| ]ħ`>$Y<ЍPC "ahPN/BQ#t6a?~iE\*fxۢEu|BJX Q[Ll.:O oұ "4zr<=_(̂ij48뛍83z~բH_/g4P0`Ӡv u^P6n2¦I;' Oĉln$!/kk=8 *;|0fՒ, *xa1T.oC}"I.c1Dv sŸx`^6%V(*xBJ ,AvHy0}>b~az <\^PoRpitbmOuzV1tLLii[)!#2`ĩ=" P}udiSdhԖhWl 8F!WBΖ6,9ԻPu+ԗ h[X¢:VXԖn;M+GXV`WZ?nvjJ,v$B#!@x d \!:Rǐ/H̷hpw?[ʋ|go(]ꮔNU}XJ-ZVPTW+w (Zq $͍LE\"{ʪ2pLu.E 08ff1GVb6~7̡ e1W-9Ȗ**M7aO-vATBCoDei}; 6zWW)|x҄ ZS#|"+|ɟ}FwnN6Q(X{\v%p:HÙ 9:m{F1ejmEu2+a]STU Zer=vB;qyiޘrx2 !]'9B/&+f' sk4DhX,^ 4>ao$&B!sÿ7SO^8IN͙Ixj=bl΃bJ&gMWt2!!!zH ɭ$/J==]xMdJ{K^79L ߔ|;u؏+sLs#Vg(pS9\ED͒e`>xU ETkB7-,yrES YtNGӰ |X[p8™XTcȟu^~r[78Ĥmx3(݃?gtŰ/cܪⷰw\v&6gElxe;rpy[Ug \d U7mB}.0^6搰3gΊ~^~ba߬:/Ā^38I;V`eR8M3#K4f[i|>5EzeVn|iWm5RS_dDYH`|r k/h| "^ ݟ pT+5XT#!BUoJiMXLPGy%1fm& N2JDf=~SSʕ乽^,=.4a?"e": ѻ%1fwF0977_-ÞYLpr8_~[~^#R=>[pMd?-Up/Fgg'$b`m\)0 sY4sf*a"KUAuhx>T2-&]E>#\OJU2%؆ C%-8zWBBbgC[<0hr?^Yzq0D(b1MO+,eTN4 >> `~˂do6*Y2OELD1xƐgM4hZI-ش,fZYHl׼x8yJȡzFvEz]p9yS*'># o~S ɓiJJ弛܂I۬tb5VKf)j9d5SE7ǣk"jl uVexSG\|L纹|rK3g +Yx:vy <`_ggGTNuh06?]kٯSS.DW[+1B>"3co-"żX"~1tmGZ1<ďIheD|:^r^!KDXZA6g܅>|i%\]f3L~YCoX=n$ >s=-<)Sa$ݞN_XŲ?4jq3B.Ӆ唅3e$s6B>*TE"ٞ>⧿Sc{B55:FKֿ?͙dz}b9wCmJ {e5z JH };YU@$>`KDBBa$X{JYT& 4&7zT%T{=;!K]4bcL UCG!mA#Qn-fspy hؘq)GțN/ j}4ՉN`3F˯b_Db%Q,C N HDeTnGivt_KD,O+-*V]2LN_Epth8e$?Q6JpL(b/qj9Z Wtbr*DLs/X*>~,#ogXnڕ:y7z5y 汗N;%)]p0St\.lQv$jT>Eae[ kشj[IR*}37So=Q,dquZvcϾH.t<tҽ~&~:1s5|~z beqFt5_d4O&=Q. R￀>>|oL9JdPFSt"7"A(k.m)_@B"aW EĈ >\":,&Džd,.'yaӄ@[DQf_<XtMLXx"ޚ(X+Muu Heă=>_zΟ94L#wYI:?˥\Q-9!L %Pi2+جn.!ːB蚰\>,ӫ(r*odvt]6܎EԣO k0Bv*|~==ݷ( 1 %'%Ņ/x=~W /'#wc1r#NΥ]~Z֥e1+1PVH4LDބK}mǽpѠBd{4XHji7ԁ8\t5<15 :L"4D<m1"/rCd +M>LLQ(euWpfI u(" ރۯ㿍LN[%GnrZv ?,+/}= #Ùxd0.Lv|1(vxT7ԩ\VT*3]E|K3[aèl(Mh??Fz1i W~PdeqBEs#6kZ /Uu,o%ƚVS&G&O6Usjv>"xQ-h_(0z]0f q=u63=[sE\(*].cX͙4{qo#boЬs G8_"`vf o#M殦u?>\H托ʱMwDW-2*~ 犢hbAGg vpDKݝ-$$$ p_|r |y//Nӳr kbZ$'O# /j]C&^^z$}s$6ITUH#*ud瑍ph ҩ$'':b6KKh=K+ ɭ4m~% [&4I04*"ɤ2YNh: vա`S" E1RZPo@C,a:O\:(R4Ktκgq?DѲǬ,*C*|n")KsJq WT3'NE3Q*%T1UDt.Ue) Ug{{#i0:P|.8ۂ"ӡZIOa`8 [o-с阛=()_|}ȭZ :hzHS|ڬ>\^ !n JAHDSgS(Qa2x׹{1. #ID<7]5N}S%Fnx<=wf]xWD r>7 ic:|2(Q|qW@fl$Ό' BAn%gW>x.̚ݘteKE,% בv( \CC@mfhvp+tq~.nl3]|#rٌA+W`m]>׌9=b {hg~mKW{R?~_L AN_Ņiџ-jC=ɻ5 Q@ $bLL I4rȦr+d ?}wmbBxhڬ!Q*մ"sLRl1Ԭs劮D[a 3|14Le1'6n1C ,g_[CLJ5&(P}~}t{4teMt5G:)0&$R6~WDŽb6 Pf cOݿ3_&ZZ7CN.? /M0e,~#_#̅{ o`wl\W/N!$@*,\$ +,T?`nԛ6ԍWTVhPX(P༪PL4Փ!Nh$:ֱap LhC(ro,!5dpֱMgTTjRRq胁ȉm;5muAtttV C7(ukx[><7-B+7.WȭZ7⹥p*&uDyV*, :߲.9H$otY Ef,eG<}4ۇiz+:WbG}'Ovn7aB2 dryq9Һ|"ZyOa":;҆_:7OuVX;1:Ჟ3wFf?Pjv@$z1{1{ St"b9?i\ZC#r`hnq~"\ҥŌD  Zi PDAjx:޾CG~B F ozq ke?ˢ3!v1\ءiSdؿ?O&D*elHpg0 dGFwǁGN,J%*ۿ+..X51~Qk~f=5pհ|Un+Qr#Mg98{*SMA_~拈J]"$WHr!>Hp</Dlp!4P+IWSK+4V4 RkS r_rEUmr+ *m!<ևڿPcT˭/Ľ9M.w: y\ q)ۖiZuO}4Y`aKVuT3V9t߬P(k;_~yJ}bwx'&&+ggo WKlSNիWw,m;h4^Pd,1v{ o>(zqq)cRՑ!nnBxaߏ-+) +Y O.AW6k! ZJY0%z]dˎTUë}3O;OB.[ęȚ(>vcvᓉe,^FYmMzji De||ME%VqH0Kd1حt'2/Sn=n㉣6;e"ò*ad$5"#2 2b鲸qrPG4MŃby{AE"L ڈ6[/!G vv;c~v>(=M؞BхkW0+MTD^}7\ sP3Hߙ;< 昻7STm[܃My\:bWuqV,s:zatW8;yn5bsV:FRxq~K evB_ĭk|2p9A߁E2̃"`GO~h|3'hػwاJ\uwwcddX"`7CncGEH'ap? A"Z]]w@׎?1"þxC <Q_?6 ս E篚yi0R8dqۍř,_#tþV,fav5;_}a"2%PdT5>pjȖZ]HydsE=ҊY<6,ɫe}TR I7Fڂ5{ Dt|L8߅wU>#/Do^=nk#7|9DsOU sۺCE#Fv@$1 q$[՘eWx*Фccȭ-")R݅<{=K@9b,!pC63M-D]ܚWBV,U~= ofJ]((&@1 РV0WtE$!0j;1%ކ_;>[WCD0[n&7͌@k4d14Gb(|Uģii lfMЧc9af. wR]>ɛFF #_*gsk_`m Ǟob,&-3LAv6VZ^ Wk+Kvqց٩T\ZE(R[DŽ ̇l*,sW &FGv5J;xx󔐐Dٍj8 q"T*tt*VML:QYbCwUrt܋alG)܌DBǞd(B4ط}QDׂE4CcKQ2JVvᄩkr%aM] e7ux^_BjB}'[{`yLUɖjI<[uR s7BD6nؕ+qݸT6 Dn1)(Z ƌ| 9%[b Ks 0";@N}0*}2֢+bٹUlt)n#iLF"]@+Cb3bF?a.jos*R X(QBXYR}Y|8t3 FxsWQ!Li<׵yeUB/>>/N8 4CƟً P;%*Δ~R;E2Pݘ# Tfe nҬjBuDUt>uW Ehf ԛKHpɞX"Յ4;§~`yqZ6g.2Z0KlOW1r\Ԏf".x̫L}o⸺fbAkg7+ 0-po<ġYxK0Gw!MD7+?#ǚ}.ZěLjT6JIOp %joS VMZ(eDPQ_lc*`2M@ 2 t4,#4cCPȅfN\Mj{ j"KXѻy Km7UKϷao$$$$$$v4qq;%nWQ[b+jh-0V_DX, 2SG.d-l)dWP2!J4 UV0Q*p0yT n(,S^>_:KYڦ,.ryB.&rFk*L",ԑֳ˦ciElr#1FȤ35o xvEq.]0˘!>s~KVLƿB.* Um[ؾDmmD%'o˪?QF]]rmSuTGViY2'γ\!p!ֆ((8/3vG{ua|HK!x:RhD(*}wa%S JA?LZX,@?-H"bq$ f0&߷s_^%YVWw#3ܵ[ں{0jy-1 5@ױF& ]=;*2p]'iڭg_ΞK0J(:y3GML)+z_.s9M_z4<'B8%V<1 m6[XH.^|8n`6U(Naܸ:V@Po#mh RBBBBB~ApFLpܪ']m6K%cF5In} CLՓ%ʤT].v+$]WZYY=:X[ODT {\w)uJ*p:BJd W0~PNm7 R^R+OpM]ۅ` + Lcql s 'Bl5#+9qy$mUjRvXGqNJDZ7PGG<O ~w911t:-D")>|-Z[[t͋xi9 2,{ߊdBvrAM*D.r]4;Y(;7e*)t:[NJnb4p&Bar(DݖCH)'lw|i>|W#cqqs"gkk+z{{WCAhq"Vsq044w}--wW>vt (2<=ڈO!Ck%*X;(Y( ##숡[q>+ ػxNAY0:;4D*z,LNfC)̭_w`.b,oQ{[UJNɥD3}wf"H/bh D~ů?Eq T"{10@g\,%j ϒtC@!ktƹ擆Pd½NS駟 /nFFkW}S[o.:t+Q"Ez|᳄ h=~*o$,47n/ȭ/}O$2Hփ[mu;K9X^VnʧRb Ãl~02CgJP:@Z7 +ʖTIDZߊ34WY=ZVDeqa]=k/JnuۘP\[@$nܖib4P=l9SsMW6cvÖ[ԽqyvPG 8VwBz=BX&_{>'h $q(ڻq/eXE#4]#hB1)Z^/ 3 "ܹDOSfehOlK_cOr@a ܊'0_@w{NGIHgx>ߴVGH"aܞt~>Yz7X S Eqa#{ @+'6O2H40tH6ˠ}bD6!H1voA<Cq^ d8ˁ##T 0__kh6#~seQW/kj(P~V6k(_lRqF?/7ìA]~a"T7{n:6!Zc&g_6Hݸ=vsx; UXUMMG XY+C#Rj'YRcZvsh(|:#'`V0ГR _IdYI,82d1"a\Gડ1"Nta5f`aڝJmn~\dpRd0R- qO_jh "?Fa.NLOψ}Lace X >x۶ bIsĉwߞd[Kr&Z"I&$JHHISVm+-%$n4>sGyNS=_T#sVšO']]]_ ,@'c3*dng@Ud׳*Y ER=YհP.о`Xc24z'HaQL%Z/eŠ*Ol-z&̍ Ƙ(&]*Y(323߲U"|>4dnrk+~^LtFGqIF| $. ! ==kYXXD<o&ܰ;FϦqpO jWbEp$tOM#Dv >?'N,by@+3n<2Az?)"-nJm"F9|Eme|I(!U$ʜNJ=9+׮qrqxu|qhH XS\A˰C WSȨtJὋy=V "^4`Nhس}gyZŬw]cUǎC2Çij"!bu;Z g 7%4V߿_vvvЫ?{/3l@'vyPن?eH7ZٓE˔FĿF&4"I)(b2ٛ2U1{7&aqe,S0gJlmcV32!Hh]u߭*Ux㍿)[_ dXAԌQѫTua/&h#7?9`PF*N98Rg*li䔦fB4R"$dQe[FadXWD[Љd3 Uj8]/n} L8M 8KP٪n,̒mW͔U_f HraC03\PPaUBic0RxX~d4ma v3ex ?@<|3hS0k `_Šj og∦ p߃h^Ad1Dǂ׵=z;+L U~[hksօáMWUu nA1Fs-7y&JHHH}WG׮\cD:-K3&+|5$੧wOՉy9[+ЄQ%"֒)!ߏ<-=/ P,LPsU[G~֫YLŵvV1v˪$4ߎ={:t?]4`oMV2ǠTY4 twl;0J&q4Ik4ݺ\f%=:*M'r|}u;b\,v$-zi'W<&u;]_3fn[n e=5ӧsJh!"˯-/#cpt ?"ӄ?;-GƯˣԋt <:@gbL3y,,He|[cj*%fk!Ȋ3?*{DZsUծ(hl4O0-OGD? ı:[9(K[&Bp^:O_3,eC9|I#:x +ɒ Rsw<ܛQEb!bqffm"4S2ߙco:&!!q?KkB6D*PUX^%G$O$,p%i_*M"VyG\[BK{ Dt͢Hݞps(di@ձli 9)aCu h>r2[ KBfbS:\.úWç®JݤsTń%N5l%Edzhudq-^?Gt}<]1juooٕ{Pz O҃O3ϖ+\6B><^$3D 13Ϻ.װgďe16&¢^6.=UL8V3EAHs!dr~/@vCSnD=|iOp%[߅^U"j0D6[:E OJt2_;cc:Yh9 z"aglŀf KWr̊BEhݿgme{##ro4$$$$fi6vQ|®4+6ة`eQ `crzNl;Sv֕$QmˮĎL&?:oOa)<]k։jXYY^uF.,&ɰ$YrKơ-~Ntb+DFxkyg<=D iKWgvFJ91rg"Z 4+ )rin~ΖjL}gMa-o- Nvw&CΞ=‘#-&h0ҥK{/OihhHl?88;&Xt#pwgv$$$$$0[uK>>Mfs|&D(bܹx'qŪ?B(o؇i&xM҉{.fg@*[Sq}~"0 T%EVUZ677/W?R,~VHm?~秞zd2|-C__ߦPwV̝;w݈صk W/F4x VNAo`,!%%qϟãG氮ت$V[[$U[[7ު_^/3'M: G-3)AR@axiXN#c.@\j RH UȗKu"3;qu5AΊAVJrKBBB!+iM )e<"x*gZKK;?~뭷<[" 6zW?ym];UnՏ-[Rbԟ@5]y7( Kz>ϽHbpC>S{/n?ԘPBP)ClpE?fSu xS-x;]:>?^ᩩuV$n"!? ^u߅itMlf-f:~$j]]uTtl*-WYhɝ[9?{%qx!ctt`U@U~Q|,.Gp矷e`^›SDE >,[Dח9>&[HH9 +x@(>L >n߾t yݍև%3n ]?tzFhn/Tz.u>*mU"H޻}ot{ue wbRR 4U gG%$$n "1q*'&Z[~{}n7ЈI+e 5ߩ&zmC Rɘ2ݺ /<."ebPz^h+bjkGS)[|W| Km/&\}m !!!!!!!!!!!!!!!!qh^Sƪ6#Բuq3,uTتϪֽurK;$$$$$$$$$$$$$$$$$ ,VY Cebqwz@n꫞~6+P ItIHHHHHHHHHHHHHHH:s HjPf߷͒Cۅ(V߷ U.l^U\7ȥzVNwԺ%bqĐfVfD<qc5.!!!!!!!!!!!!!!!!q}lG.5SV;![ FQx=ﭭB&*بj2 氯QѵSB붩q; -kypDeuh{˷ O܎jFdvV=nUUQqmVeԿ7~n$$$$$$$$$$$$$$$$$uM_olq'[|[.!!!!!!!!!!!!!!!!(veI2H睐^}KHHHHHHHHHHHHHHHHl Ol`vo4)t#*~na[}kjz H wHHHHHHHHHHHHHHHHHl Tu׈-"v % , ;멸v}en/KX_vj8vMr܁uwXw[qɭ*$$$$$$$$$$$$$$$$FnF}8*r!$A%!!!!!!!!!!!!!!!qp#D]'ɭ*$q%!!!!!!!!!!!!!!!q+#WȭzHKBBBBBBBBBBBBBBBWNh^$!. Ոܒh )$%!!!!!!!!!!!!!!!!qB[-$%!!!!!!!!!!!!!!!!q?IDATxǕ=3Z`Y,C;q03^\.w0;xcC؉-3ɲbVZ_LwMuw~hg^AWU'0 0 0 0 3Iaaaaf0 0 0 0c@aaa0 0 0 0̘g4 aaa`F0 0 0 Ì~F 2R=aaaf2bp Q" 0 0 0 Ì<& ` 1caaaÙJ bP Vaaa^D*ʡ(qaaaD{P &"Go?0 0 0 0ÃVQE" 0 0 0 0C'zRmD0@x40 0 0 Ì Fp}"TjabF-dgaaaf蘬$vDB"TC82#_maaa¥b ߡ \aaa.-G0Dt&4m%L}i򇁝aaaaDͺ~ǂue6J&>~a1=/0 0 0 0EOUñ0ߑQ~Տ[W0 0 0 0L{-}xa+v%)W)wԇT 60 0 0 0#lӬ["X ۦ[PEcLXwT 0 0 0 0-p8)5F&װ0 0 sB#ƍk366e)֢8B]k!2ɖ~SboI.Zttz<+ 0 0/4ߛ[p2 3H# 4f8"{GDl^.Ԝ@aaRS36QfArzM٬ :Ё"z'JG}^v(P(oq~S_ H2XEaaf&,0؂FBHOSS#^l!ڥ(TE=&#@tk|T[AšūD3 0 Ыn -ÌhhSH(OWW7 H3W MJpo4HA,oaa_J\v2#n[444D?PZ#*f5?”MV~Vz; 0UDzoZ~g˗#'-܌wmBk_<0c/>za=4򃦳 ʃ*? LkFL0Y'u{r\y"N:if$~\wղ] g>i|Qs)'uw__J@ŒM;7IJeGRP{(c 4g8~mz.&L fL8/yy>x 0L:.e 5cPPaPҗ^T~\}XH?쓸o| fhsO__hFuNoz1}I}7p]1-Gs2: mmmzMC7cC|ч|XNA|y8W^9; å~#hyӟ W\jqd|Qy.UW w/yL~<80!S-1~̝;Gm9s.馿`E8|&O7psQKvdt4l~ V~O<3 ٳg)ѓZF #w}'R|[W_c w>4Z?>/mvR)6y䕑üolj8x|qǭwm\ 0z@yV`]DaF54eڴh-ڂ0#=h[YGyQycLBX{{;ߏ?U~Jvjo~[x63O38p7_bŊcqɧۋ!RQ W0̨Wdhח,GAK\ziNK޽{O?AL<A.o)?%Ҷzu=/ƒއG2N< MyU"_">/%4Sh89QêUGF;]wNsa.`]TZ #ᄏd[vۭrH2egZ2s]o(;nCiMܐ~O. KC/ehz裏ɺ?P շ3U?SrMKA}p#t,ԧݾBZoi8:}@5q-ƻzA:.==x$~ ox3B_H݁ fuտx_d[;hЇo_ Q7C.L#XPY3@Nq/0LakUmeWX}G^nڴiHyG@9?T-0 02W [yLC;}׮x+.WQ:::yy5'_Rh93J6:7ݍEk/<'k֬7Pd# }{<щ/~)F3ůl]$~|C<ܓ͛7vj@{م?/qfG?ar|U7e-J̙3u69]=pQs I}WF(7tk׮}(4ꬮN~_`Fύ7 czI޽'03K7%JGOO-.DlhWUclٲU͟?_.JГsΖ6g_:JBMG~)ZC*$dIqӦM?Q0G?qyܡ+ydǎv'wD*9Tz 0̨nn?Oo~:tyOV:;; 7֕M]]x衇{SxHn{(F2]ē@CW~_I%-ַ>P_siMFfH(r w}w)G~(Q___\wquz_M7m^|e2.},N">˛a* ښ.N֮]({F7Kp{'? ycYMLDΗr{-8w饗狣֭[/xtgț,'dhz`' 6'M$cɅ~V.JM}H|׿nW5)oO:]%JWJ.Jm{n} 4Jcٲehnnl'?iA3}[h%-KjpM7,~ȩ>NBrf:tDOOIH2Fy]RgҍMԅi/-^,77$^,][t&8'65E_qݧ nhXgrj ڗ†I}Ӿi_y=q  h H믿cBN7EI ro@m -[L8A%T*mGsLk^-?n酹'HӧCMMs׿n/|=9mۗn_j w)+:} t~aj6+Gj.̝;pn47GZafT|i0t#|0:OyiZ b6!4lYT#q!&\r}arJ:ڹv?)u/Z.C!h* 7;v씢 ,J#"F]n*J8Y;4Z7M_9C}ocq__N{w8r}ɿ\$j}?hM :A0Cpß1r]o,H@1cˋuGS; QUkp^vΨ gi}BvT)Fۿ}HN]2M#N>). 0P\aܹ9wA譆C{8 0(A7&~Q^,pgzCGoo3,GroU `z= Qie"4چ߻Nyb6u 3sΒo}'?M? d# kz¼q&.g̘n>5DBp#JТȇ|  E[Cz3G<oIހN:UFRmkh{' .駟*==iewz |Ap{s t=,woMLJ4 c:E0w'F M *;$\vcIBSHLHM" JW_+׿7]I9yD}J1S\FPۆ-^_JMCہ'qa\r=.\(P$A"oX# ӫY~ 0cu.T Pf  p.zà!ϗ]v|U" tMkM\l_hm :д zrHì$&(" M9hX& Zcnvt ˛i׽QƥR"Wu'wDL (҈J?'ZeAh}5!)<]`$|~%O5T>ɾ2w\\yd^m)Ò79|_F:8#pmvTsgV4&v1MJ6у>$,25x'ћHܳg\}|u-BG"B4/|sEN!!^wHDc^-/Q8 V2IS{No7mϽ*0ZO5p:N>4[}g }' % ctf-x߻K?뒔Ժb :aF] |_n:&E3/I'>?`FW^ CKx/DOO3`F7 FsV;кoxcvH> V7ܐAahRz[jO+)2C_ɩƝB U'_IhH:?YG:C.)0 аdz:JoE!טz$MW70[nE Cn~+=3^hߦ?݁޴qGh4.q@Nj/n CjͯQ" 0*Aӳ+-D}ޡG0 0 &…GN.I74*Rmд:zUCCº@HT0z477tuu{(#@a: &Ս `d:S0 0a`[C'q(2 0 0U'[ep2؀fBiּCaaa%sfd@m0؀FoaB؟,2dJN0 ÌnXaQ[[)x0 0Ddˊ#KN "0 3`afxmm-aC͵u300~dY0 0@aF $zaa4O! 0aQ@CC`AMf af0IAgaF$Nn0 0#^9af0ȇtfaF6,0 ÌPhh5 0:^qa0 3!ռ0肏 0#@aF40 Ì>MqafGgaF]]afBo:3 0#@aF:E>0 38aafQ[[rXկ±.Gk8ttOaC {{0 ÌXaAD@ '>1U{&MD~z|A&0 sh9 0# @aFDmf#~㗿5[{nL< ^x7ˑ!}(EHRؼy3~tvvbyߊG}Q.&Lzl۶ _F2%KžsϭƪU NcC;dӋ^X|H9SHAP\AbBkkG=q5SNłe>@bgu&fΜ)Sqǝƣg.]*~ Bu zGL?yOj{h!gA" ů#P~x; ;rJWWa%lrǏF)\k׮;B|Crϗ;\~ P9i A+}{ߍz ~͜9_J?GOO/'|ZFJyu= $BΚ5Sƽkg^̛7't0v|'dyÃuaҖR>1N;LaP@7e'.^y 7:w].Q5t7c @oo-DxsӍ^yG76l7Gq}{m7Oc8e)9tJ6ԝ;۾q.}_kv$~,^ .4:b9x'zl8uFHXD[^lqi A~oٲMloڴ8H&yL4&N GӄA{YgHC7&Ln׮]/E38Msbμy:իiN9$)8j*i)+;v" .)|Byv5F"@ v7EUwwOI+qEm}9gۂ>9KN^Hl a5 @ mH1<7JAn ׽rT wmKO:RQ߮Nϼڶp=J3ϐOpQa&z c_I_aB8p࠼q$A'Qkξa\.o6馐niT#fDlMoz| (k %Lް 3AO¶IHV xM:uwltܸҶH '4A%qyr{=q^ƚ݆{vFe<)젋© >Lڊt~ꩧH꟠Q wN7$К`2eE 7%(5/Hرc-[K/DD#i]2oʕ'$^чPu YݱmڴY AԿi ~,$ꐨE#KW]+[.f,XSիW9zeC\!!ţ@a0(nhJ<㢋.k.F#M#=QGZyS7i$)})IK7$JSLOI!;;#6&N(o#&Թ1uT74e֕nxIXpC7K`GܹS@84MN H,!!1 4AR40g(>}O)'>-Je!Q-h` /c@h֭[ R@A B#UN:DL6U:E#`HLSAGٳ45D6B}(т4 ȁD3`OR&aF稣*؜\SyT0 zXa! \^{@UzB7oy˛d]w=8Һ<,Y"G;Κ*}k #nܸQxW'4҃~׻Q3{FЍXthXn:9n_ͩ Id ^~uGz6z{Nc$&[hT r^Lfh Y6D" '/E"v%j_>\.{BSWh!,jjcet 3> 0# ^af@ QFuLW =B$;=ma7o?o@) 4={ȩt|~@57'yO7hFVƲeGfE@k\$"8)ƈn|C64J 7v䠷~AbOS=:k{T7)2R|gjR4G/h0D\ 2^IPtDZ̓Z_IFtYfɛ|2Қ24/Ӆh*raZ*+M~LpEx)olR)LAUYڞ3Mk!ц5ErSxD@j::˩34#l C_29"FM9o)Bj6qa9[`aF4nΣ@7l\Гn):ݷo~/W] "Ztj&A7nѢtsK7&*?@ScFn"iHA jSqѥJFК r(ytJnboFR {M n:iK'hgR7V@i?(S޹˿v\qF =0 *7>A9:rkcZD 'PR;8і[paD(-A>_!Ǡ9 ~(ޮCAh-g[)覲P$e;%וi*$8meY Zwug O܋vttآ1?iH!anLI)8mL" !{DiCEuL@k͐#@8La=-0]'P*z8G" ]'(t֌`-A#8ƪAPuqfCs?aF0ֆ/X$o3r8}#a7m? 0#0 3haftCk8 *3 0aX-0 Ì80ȃa^y0 3wkaa"5 0Ȃca 0#>SaaF|fٰ0 3BE*0 35a 0#nAaF8t50 3aafCe6p.f->GCKX,A=?JW(_JqE(7|&|( |} CT1ۛH4yDECK{^āMaswofĜ 6nM'bosr&+ va>ԇ tCw(i~Kìi3Y}vszz/~gYXl̚{&LV1vM9l%E؄A)8gq\_"I_g Mg'+NBs2RKU2gC߼Lt {_8/b's]rΟ8I8v̟߄d)\ &6 m|}mJZ[51fR.I9"MV>wp>gZWFΞn~;c'$?+VqXBOB@(D%L+/%E·wN;XkCǦ8"<0ŏ8,~Iw>e|= !wK/"'<ܲc6m4e3)GIJnӃ;̟7BHk8<تO ڟtp->@tHԩ?:1sexǯ =a,~lO1"ZJAc7oiKy}a|L92 vC+2lW]6?Xpf4,~ %Lc#b[4oht u*s7} &l!cuKo?S ᾈh~֡RCPFMp{<2O't}=XIJ4HPD`:?"]a1{4s?4,~ %Lc#b'co\ל?{H'8z7p6 /Zެ|Xͭ~rQ/I#?>l߼M c&\>*U.ppͤf}r,}=cF' UV5?!yx~[v3_D4BP)!C|&m=M}|ߟw'P> QW1XJLGĴo6e;8nJ9xm>7_6?Y3ɛ[%AC2ϟg6.mJ>ZpmצljT9lF]6rD,ʱ͋4FHJ-xjYF,~lO1"ZJAc7oiKucoIGix3&ӱ1pkx‡^<ϡcbx19hm,~x Mgc0g+7J].8-eퟴ)µMʟr wنl&X6훔ò%/ida ~ۋ>oxn拈_Xh*:uhDz #/㗞/GDF^G Xv8KN.GDF^_"IW22gC߼L*-~8_&< M3o{b9lF]6rD,af8Ea* '籱=_Xh*:uhDz #/NmbVk >>_6?Y3ɛ[gE?/xdVxeà]n.I9"tpf0,TgҬm(|/)q$Q{KC/"~auԡQ>F~{6ܞ&Th"%\':UPD`:?"ˬGٿ=GsEkcÛUo:Q?_U[ O\@k/lSeà]n.I9"tPl}r,L%`8s(|ۊ?JW(_JqE(7?U1ۛH4yD}_('nM3`^ #XJLGĴ~fN8烏&oVl,~F ~ev(eNʇϟ)(fݦ䣵\TMm*pmhfRe3ݾq94R@*KLihi>S ᾈh~֡RCPFMp{>_6?Y3ɛۡ?N)YRۄ7\k)*U.ppͤf}rhlrsBJ#@(ʗ|\ͧw_B} CT1ۛH4yDED'J}+T||09hm,~x Mgc0g+7C-~0C*$7 o֖hskS5U]n.I9"t3j J;()q$Wr)ߗ)p_D4BP)!C|&m=M}RJ2&?&ӱ1p[7ĻL/Zެ|X͍ŏbBl|}mJƶJc6m4e3)GIJn߸vLa o BR+B{KC/"~auԡQ>F~{6ܞ&辈Do%BPBC Xv8V烏&oVl,~F ~e6⇦:aà]n.I9"tT@ %@,~ B>uԡQ>F~{6ܞ&辈Do%BPBC Xv8VGcr|Xf`W&onIP%ۄ7\k)*U.I9-I9l&X6Cc >SYX"ҁ-/jgg#B>uԡQ>F~{6ܞ&辈Do%i0FŏtC9Jǰ,Fap?* &oVl,~F ~eG|!6W6%_c[1e3)Ge3)pͤf}rhl&T@(t^-/jGg#B>u:t_l!ݩUo-7L=(D0Cc4YJLgzs.+BV0 g Ks,tOVl,~F ~e6bM݆!km\ڔ|m*pMnߤljxrـCF7.fRLa ?Jpq?!:TJ]a.m> !e ~km⋈OV"P`c(a"0]͹a- s1_?aڰ$>M-qXd`W&on#ITo =DMxõ@+__RƲea9 ˆ0aنLo\-J=2j,E` CTQ0+J'Wf7 l7ED'J}+m(10.\ n`'ߴtB4qӆs,tOVl,~F ~e6WBgp-;צklT9lYe͂A9*\F7.H Oh*2CE.g XF7.H ,~D'RԡsduE Cwmrݪx[#cܶC 颊:Gc7-ŏꦵSGEkcÛUo:Q?_Q,@͕Mئ\n9aٲ"vWˑؠ+G>ʗm$ˡGH5ގ+/jf#B>uʤ5⇀fSWGنanϲ4ۄߚauhI}kPbC 颈!OZeCix8+h[BhFl7?=Uެ|Xm$A.?+p#b)T-!,VȊrdP6my1D(S|GT݆Lo\>T@v\|Q;5 CT&u&~dlltNA>3new/M0B'F([^=(}VP7F'>͌'kg}L{sMI}.q x ۷oqtˆ6Xnr]~AoVl,~F ~e6W>"-;צklSDkAe M9(IÙuΝd˟ف<ϡ2t8e3ee0ˡ 0j/j_f#B>uʤC=.A ">R@>,^t” ̂nimh)@J#$@|%qk:F4'JU"Ta*uCoә,2賐l@f/ؕ7 ܇!Grfu jP? $q)8i1W6bjchEkcÛUo:)I3ʱGIw>+M|lW \~ڔ|m,~drP=0HA:EC\%a?c&-AG` c3 ڿc =D=ղ4ɳ6Hmt؆GH4LvE(=;ױ:4?Cx# B2̦h#>sމkz;ԅbqpH:[-8(}VP:jT<'|,L{)E#~8ǁ܀}3~hXy|RǞ?ވĸz1`pnv@W[ K[u{1+g$BTX gS*7m(ȟ-+T|d#`P6PNz|D-;K~6%_cR'ZI9QJď1@'~H#ERhC$P_ T{ ߺƄ@`g 6dQ : (,P2$[3v62ݾq94JREE,~D'Rԡ!fHuly E=[_HN3waC?=zۇա7q>Q2m?TDx& a>cq͏œePƵ30 oBٹx4|{zh*m $[Q;{&j&O´w.>{~+ >쫻gv݃hoC<+4mI#DrJ?2g嶉ŏb>"̖hskS5)u-HpAA[8'aO:in+I؟l,'VdAAx"㓘?H-ؗ1i?|Og,~8܍Wu/8-PKauhO>DLBO ~P˧l҃_xgGY}3/|zyΓoiO5#f'2q4=QضǾK5 \hoB7 BۍwO7t@7Ns5NsϷZZ"͸LYmcG9/Aa&}h6cx;}#GgQ~ e q\[L >?Yr-Zv62ݾq94** /jf#B>uʤQď}8;pɽD> %EkFkg+ꉢR%qk:F4'JU"T퇊DT!'p?2عf-aޅ<R ^q1jgM"FMm1g`hO"#Bg 1]-??m0ެ|ن319:YHi/*|VnX()-;צkl+ǀ-c-|<ח@*Q"?3"D~'@iKȐ$XǾ~ܿM &ADL)"6%_c(s,]80l{#L>Dž0"AhԞt Mp::ma3R6­Ymd}rhl#J٘H5PvY#%(M͇wQ2m1bő]}m݈MgSVzd2sկ6Hɉ q ^Cg/;ԝx\m>[ _8 |:\IyD`Y ӄY#NOVlY(:g-xWދ]y=wAXۄrd܇"nB\~ڔ|mJhmϦ*-+6o0+`CGy "+Q#EBo}Fצ1U@_^RG|4yq#J ü^yҴBز#Q 6g2WoDL2TD|oұ~*L ͯɖfOl?/II) V~L~-dvA\rQ5Ma~鋟e5ӄ޻߳*7-P:#up/ n+M|l,~Gʦ?2ȻёH%jTBq58oI-:wwY[0F7j#[H@٘Ha#B><Ը7H/845_DW ]gi{_BO ~]])كXCN?"[؞ȅR J dz 5B^tr2~E䲆iYI6ެ|ٴG^xk;ȩyklُ˩1V_)-~*:r?C !l.}m›M4ď 7Jg_^k V#"~/p\DLF&1Ձ*G|4yq#E*~Y(չKrg;'̽I~p?d#?,XfV"~hR-L͠n'Ƶ%})0!C߶/2G巉3k"&yn)iml$`G?buﮃnh||ҧ5Aͭ@ʽS6H}yn #e+SYX,~DGXFƕ^8FE܇WԊ+/EW 1`?V“) ,|S.v}o:F4'JU"TM|QsBO4#$+hWhG..3Bskd(4,K 7[LVtwÔt#Fy4||sm8[xa?J H 18Ћ n:f 4P>.XֵMIMEmc;\ŏPھ oƶQ#~dtm"?4ky Б:A>g-=]#LFaH`#4L7T?R/(sEU*wR{%u8iD#6sǞDcCǼ'~;NmVވDJʴ/B1 a>ᇛ<5}Fn’(67&DAG6'~Bw S.yeQ kMN+RV&C|Lŏ¹}l$'b sC*ݖp$J+)SyX ,~iP35ϐ['.͊^91KN @2YZ$kj'J̜}ɢxONFag}|U ?F~b8-:e  fp^8sG%~dl&ꑜ?<6ܚ-dƄv}q|K򼘛2-T%A1|AG4wSm›M:&a4s j*"tP@;1ޞF7n#b}$l~g* U@(?.LepE\+/A;f@Y@Rc uH$ŏB0⡥*x:䍛LnX27˵X0볁m>ƈ*V &78#<"H(~}"Hz`Q LySD.kh&?Bu(%9堦"J2 >N }߅P6>? wޑ(Y 1mJm/almg] grە~[`ܟōaBi)5b5k 2ݎ vWbH!`C#XTt^|񄉒< aJ„>oOh~iP̜ẘp9Z-1djJ?D{r +7M\(҂fL$`_ K|s^+M.%Ƭ8(}VP7E@K%e^%ϝk `8nkGEmccmp$mڄ+,͕MIclSQͲia's fi7O E[e-[1^w&P<Ҿ+~e0v4z&wt|lܶ La\_ܹZ^QXFn#b}$lg* Bx;P( 56BX0ۓ/"~a<ԸQ"!~|RGS\}CF?l_Wӓ\m۶?o]Oj0BͷO$-z\uh7;,y&pauhO>DLۛ"eJI$yN9i㸾 S8#@p]q8u>zR>ԪwY5MXW҂ӍXV.E˦p` ZRoOh~iPVJȺ:EP-N-Б'08ŸWm-#㤓O ,V41Y6{jF.8(}VP7E ؗ! gHd8Y!l$]lϚg 2rOb10"5s,B8n~:`'C+RYB4,~ |G)=)5mQaqJgM{I&В'eGӔf[X}^m;WˤI,[[mm/5`٢)Hӱy?xHܾ,Ln'm _gnm?,w$g b7a :vmS0eߺZmVވ}VP7E ؗ! ?))!cB^ ܍RHH$75nLo܌F/FFV2wxI!/> _|uǍ|HrPq}%qF0~ܸX؛>eշ 0qKolƤStg-xto?vVkz_So&>6?tq!PLGȊM>X>SWmpċxCZ-EG /]8ۉcb 2"::B(n+*GR6RE݉Yp:ӛ*~^;Sh676 \coq vLhm@ ~7 JJn{[&c҂#2nV[BQz##4'P"TM| Da><4 O? }ǠwF)zG~OY<*3.$x곴;,(,~ |G)=.(5cQg 3rSg.Nj{']' gőlox:GuVXS^}9Ab߁HC䆂Qo[@/Xb?|mo?C<Ѵ6/ Wh[̴L#Ap'e#Z9?r7nr4=h-(͏(+!I[`i޳ v)}MsgUJV[ߺ4<,T |qwb?񼎕]{kq 0Yn#ĉ0s lٲUgGF ,u[gn%-.Yuk$\O>RJʴ/(3'WtGMu8ӋǟB9K릓hY;7hY'.8L$n6{okǶ>ō gch7 !6Ed|> }oW[CLڍ sV8uR K']@~鞜B‡(O4n܋-[?qSE-W+L_hO1g!i)~hŏ mϔN#ഺG~: %"GAwvvcKmlEK?lEjf?tۦ1G~ðlLa 勻uo%^›Nj?u m82|qx1?ލhX:,>A{}o5!^c?M组R>[KѪTnD{gC'~~;1cnmccC*ۖۗ?Hz{:pŨO3#O<'ҕRdgV(%‹/9QUZ#"V>P@T@҉woOh~iPI'\dD?dM9c`s_?;܌N8GsRI^o 4^iX ~; 8e/VB>>4Fď Dp?q͵h9K[SSNž[nύPQ\- |".voE`^xV;k $ŏ2% 8coQaqJg"0fq~l;N5mӒmGɛaLio5 Do^ o:g n|Bsf_aG?jR{~qo~b :3ӇA)Ť,~Q`E~T}<嘅hijGG`j#T55`ҥS܊aL {|&!JL-[: mգqil#e )lLa(X~($Laꋈ_&5n^o_\%zq8Ic`@y垍U"~^}[DS3lx&)Q[P7E ؗ`FDg#o6Q\zʲq1Hx ]p6 |<Yl@\gROW )ԀN{I1{Sre Jp,8/$>_ý^_c9w%ՊOLc0x9 {`tCt䶘Kϥva_G~Ys1͜y3Cw m8,t>3g( 86Sz϶+O2lJhmJcP|r[6r-u`C]J46ʏiŏel7};bHX(ymkuŠү z4n#b}$l><d",~y+''Zǣ)o懛D.}?;M{w7? }65kE.)>RJʴ/]6"z8faV/>5)jiҌ02lonT8ym͵/|A8:o},~,~6(i1Ϧ|㸾 S8p}0i!'ނoAlՀ<OuA)Yt`A[vKw}-C[!V&oǸ؂g崉MR&Cp)PMMIclr[6r2Ro&[9A54`rmM_h656wLNB9Y`* UaYp:VO><|ؽtuQYYyS%4ݱj x!iG_gayn9X"Ke#挨\|{{ Z'N3 BGD}fA.lj ):7aoh//lŵ-rjv8&|ڬDM=fq}%qF;;B"4LF{>cA v"GaJO$hZ𩄞M.:,T?񼎕OɎo2u>ţmFOxfvpP.j@7XYS_܉_޶+'AVҬ8(DLۛ"싁 ӎrPD8c&/j¶ #zG~MsD~f><*deTVN/ X2bmZ,~(lqFȏPcJ4b꼋U#[FwW F[ԗ2:KE<^'? m~b :3ӇAMW&X(e^sfnpAjŏ[aG9q#@cecch},H`X>mĤ%gᑝ[p [&$08̛юZǓkwcttՉ$IS;0GvׯYIΔk8fJQz#!%,J}+*&#a,^ 7Pg;܀mWc*Y$5cqU]\'mCGh9i}ǥӺk̖TGzo? pZ?8TpȞmX杁_cgH462~6s4.*;8h%@bMxp0uSl4Q\_:R+ Wh[̨>$ m2EA(Ǧԉ֦1 vlBOgT9LfG`@/BZ}I†M[,nB.xw&06^8YZa* UwP߀:AIz.ė~u= Dmoŏ2-/L.ýjOEAtF~;Ly BFgc@>_禭,<g]4-M^WHeC%*vŏnCc1Sg쓹E7[h?g9#^[k5Ȧ@ F`)2vqR'+qY-|Ml>_2i6p)ʱ)ڔ46ڮM(l*G%laV,E$Amچn*Y𴸸)-nߺW: YJ\3Gia* O2E }ߞ<4aB磍C[1a S&yx~{Є /B6n@&5n?p_)}`rz>r`+I@~mmg<02 h-; MmSQpWM~E ؗ(~S6XPDuÓlK`h<`r[ݛ`n3q1mRSѧwRV?*fv_WQ&L}1g|WGϛ,7xMոuJNDu6]ع!O-,~h|ʤٴrjS)imµ]?P*U͵96E1W j`K+Y7چdIKʛǯ,~둩<,T "taJ„>oO0E ƭRQY] oF_ov?"5؏dֶJgP7MqߦZ.pc^T@/!ɈŏDuqFOhoƦrZK "6ib@Gi3{Zg6bgavJ_?)ߊוCc1SglGq =Yۊ4M,}ȩ9e?|Vdo^8jlf@Ea 8zI2E: MZզ1 vlBOgT9" } p߳}G|t4HA4H&Fo?XLea  S&yx~{Є /B6n@&5nUF~ܡXENVAM/^Ut kг}'zWߋ7޾>A7R1Z>֡?k݁Is6R=#H|^3CoD|Է2mo@/Q.l4Q0(7UVQpFT.uaOZ/5 A")ab~]<޳٘99M^k<,~T0;L8))nu|2KPIwuOwAdҥ~5e /ie;%PTa6eZ&\ ?R(lΚq ̵RDD?ŏ0K:d4Ⱥ9D~ͨ\0G6*G?,T MJ„EhЄ \ =k~8X :d3hڻ ]z ԣ{ }3D&т}O#{pԢ&7o\K#\칓sWU8tuѿ)aQ[P7E ؗ(~HhҲ105uV "t&}zko+‡\1?g[5 ޭ~#U @S&4Di>N |( }>ڸa<ԸDptU3ch.~ zW?u5hhoFu~꜆kA2.3&A6A`coFu}k kʈmi{_}wp2' s;+g+DZ~dr;pJg_,6?BQPҖ/e;L8ز4G]-,)3сukq\w6r> Tw\f[@$-8ɟpۆIy_|mwi+ mƯ@\e(ncS)imµ]?P*Ur˦ BSJۈ,baGvD鼨!\G ?ߺ[哋K"Oî 6WyaGHN>nsr+)SoAώ]X`5!c?J6օ㦙EX>y?x:mCw0o̳p[auhOV"TM|%}hQ0Mxr@aADNijHiVԢp*~-JY`I_aray8~nd?Xٸ;@_ ~;0PwfΙ[H7}xpr|pUڋ$@1#n-k^ښ&ϬL/>q6ɻ qH}HaCy!&4T&\ ?MTeM`B:lىUv$,P bI׼kDH3z8v6L/m7bV>oH>nN ŧ'qcAR!=k7_V8c1}݆<& @o'OlJi8Gߖ7˯Eo%Be`_ևToG4őP*d#AdV7h6Y&ǬR[䘩⇣HKlŏz9%Ӄ֢ #'߂ɳ@Cɽ)os4_/7/?4 ?I͈%cRioϧßY[QDg3k'*&W"|b{-6eZ&\ ?Mr[r8:{^l1ҥW>aC V=ZhRxxAq=⇥/ŏ}<,T G,~lO$iT]#w?+I6`O|<{OG˔hkli"ƚqTaۭw)U`(DLۛi3`wX۫Fŏ iUd2j3 EB(ŏд#?;L8,~8dlrӋoIJon܄Mc}9h;,T?5 5ܺ}~uoIu5-Cxg, n~ƢI-mwi+ mP>ƽPn MIclلΦ\n9-sc݀bQ:7t"> p(--v?jcilx 0.;[GF+SMѸ4`DŞT@pv\?qKGOD+!HقG>n磬-/蘜ly+Pec1kQ6'ÄSÏ₫A~[auX7=xB?TM`BaJӓ6nn,RGR U&~D\wG &L}?\?lS6Sϣo>7}=> Dm}̾?yb2N7\9^&OkxK0Cĺ8Q,~Tѐ'3h{SWdՃm@Y1 jZJ s1>T@F!#]k r$H< m hȔ{GNubxkR2o˹pZ,_~%,J}+*&hL1uh ӄuמķ]mm bqo ީ/Y'd)iǾaraÕ,G'`o~[љ8 s/pZ*qO{P.[>'Ϙ;a} $Z 5~N-S`lf@Ea 8z[>OG倥N!Z2xdl\8F8tc-~,‘Z_5[?JF1>1%⨝}ܒy4.D=mZ9bӔ9=g^܃X&o/F4'J}+*&hL1u QfPҊ&X 2P *E>{,~ %PC;L8,~ItfG=w-9DŽI!SkI,t2yY[&on,~S¬ CdacPߒRҦ`Ǜ: LOEWs3֢9FE`?wT/>q:[Hٴeu*>nDYDu R[ ۊںxS*wn^ ֣saT^˯Eo%BeM)s޿#! JZ`Ф;\5$R22. ӄoH^Ac>"X[C>s"K[TLofa|S Ɇz+6ɻ qH}(8LP?*Tզm]FZOVl^2 }Չ$%n_ȶ]`_gKIp} ŏCGHaCd{.ZnkaJ YYu8$Z c8x㋥XJJ )L;\ďQ>`YP(ɲFT_ =]RW߬X#0uZ-EQ; „IbV̧LXpY),~T?0wN喹sJIb1i{7f6ΘG`m &ً}=#Xj},4:58HN< p]zD5HTÝX^a* U}ܒy.ACݦ-1<X2IC$U8͉y ϞlCE3Sd+i{_4mk{:bD`}C, djPfu/x ժ{M8[x?\rߦ%΍O~RYk~|Ji%e>?fN TM0EC&eper(6ֵ]רf)8l@2ڧ7aܔLރ=]M 9g"/q@}J!>BHd}4R{к`BKCU*ԣqil#?Lea [=?;Oa Ps!Z,{gb.“;,L\!_ ੿/Qk{:bD`:?PXm\^) !UdO/ 5]ZWHsVkYP~JpQӸ*2g_g'.B,~Q9F1^nM bD^O hѹszbkt7֣);M:HH oM [jVSJ!͎괗|z4n#b}UGH M\ŏ&]' Opjq:ԏSuaS^ﰶ/")L;\ B%~4RP8N=~o?* ! lqXp%9駐mfebΖO\V;BX(!esvÂMY3lVqwЀ>=ɢ742,24ʵ.z4Hí}dY4RlW/*GH M\ŏ&*5{$يzM8$4h忧T7'P":t%%am_FFE !m܀0?Saja跏/,~(qaRa"0i-,ô,~T0L^-C6paÕ̬L%qĐ7/77?)aĕ*S•Vc)jmJ=*U 48QYr-JުN,~R%] ]7 L?ܿ!$+֕i/%qa`# (l(i#{(Syׄ6paÕ̬L%qĐ7/77?)aĕ*),~e+ YD ~B9eSwWǰR] ]7 L?yFR!wi\D:T ~pȈJt,~UvCOXPZ kJfV&lɛ0k|J? QhN )>B5n#bMOO!eCGH\B׵' eCGqTxP" LQ[0uk aJt,~\C~ecHi? ,~Iw>e;% ReP [w忯MWk~{ASum״esnˡUʆ}<,T Q.4q]{bx܀0Mj\?yDED'J}+amQ:,Q0ŏhi?iY}]L`Õ̬L7/77?)a* •Vm.}mJZRƶJc^"+5(bxˡU1'~ډ(,TQ.4q]{bx܀0] M|RJaC`wX[T##*&ӱ1p[ׄa(]?Xp%3+|6͍wJA>qdpa@_֦ԃRͫnlA0ݾq94#0&T@~el~nOGt_D|ԷaXP1H!&ժ{M8'W22gC߼LXpYWLQ`cͤf}rhlǀR6m8}<,Twe/nDz #/"z>Q[0ukQD`:?"UV'W22gC߼LXpYWLQ`cͤf}rhlǀR6m>T@ò7oo"߆=(D:T ~EupȈ(a"0ժ{M8W22gC߼LXpYWL8APl߁66%_Mf}rhlǀR6m>T@ò7oo"߆=(D:T ~EupȈ(a"0ժ{M8e=&JfV&lɛ0k|⪕IJ/ܶ@_֦ԃMr wLl7.Vz ([O!eX#La7oo"߆O6.m\JaC`wX[ԡLQp((a"0ժ{M8e=&JfV&lɛ0k|⪕IJ/ܶ@_֦ԃMr wLl7.Vz ([O!eGSX|=Yf]H@Ʌpy~isZpܜd.LV"ThP1:Ͽ:,%Lc#bZu gL?\ʤ;*, Yҙ/@s>+M0ECU+&1PخphskSڔz0>r wLl7.Vz ([O!e拑G#@~qۂ[OmE}Y|=Z|ٹBCoDf.:[9N>8ГǷX6oahyFַ2mMo{M*sBh}Q1[QD`A֝ݞLo-gMIxT|ޥ6zu g|Jw=?\ʤ; o6>Оn~ 1¯xY+8Y``Y/w,~SVЉ{W0 6Iڄ7McfReg¾=Xt<SN{\\pbecW/}r,>nj`9|2Hcnغz7Mje<>vcc* 2WwC;ZF~d3f<:F̍Be҅8tZ>5{pmSYܻ-[P&C`wX[j>H}V! "JLw،Hϧ7s/ ?X򭆿XUSׄQAXp'3+|µW3$?J3vS.WL%j2 A\ڄ7Mn&b{]l>\PaS+l ,}=]~imϡm9:זG?#@pUv4]iP㎦5?҇/yr%S#˰ouRtr 0iɍq]9-YƬb MY\&ŋbb L)g2>y\tbdʧm9(<\ur/ą燾5m_\`u(a"08eْ/qW_sc֔򭖿U{M8eM+YJ14ڒ-h?Or$+aD[D4QX8V~Oy6o_ge ["!~U_5"\~ _桵)`lSLQn\ʦ !m+fEds6Cz<\Hοʎ& ]܀0MjQ#~E}qӓk_H\∐{3v}d &?Mןv-a|/=ϩCkc\NMYb?n|iK,O'|߯MbJ}n dܵizk = i8X@(#,h N߈=]i|w@#E~)h;qߠ63y\:CxjkJ^\"?e Fپ?}?m?I؜mwu򶽷mi3OOB4:\hc^}ٜh }K=^@6ϯމA9 3/_D<ק7l9}f9uT/8̘{~"; /O99u|i/_lƎ=T&m#f|fͯ~tfҥx|ŏ2cÕ̬L%qD ׏px^?%lr>³qFk`g>Ջ~ǀ㏩_7Q&Uܚwa:3n& _L{;q__eRlCC WL&  oZR6%ͤC(օϽ<{wu;6"bxK6Pn.d2,[9ǮW]pas{dquXpdpaܔV[4iw'Zά-s2^aħ/횔Iw֤3&\\ڄ7McfR `Z/c 6[SƃxgOC}c-x\UrGڄ};z-@~5 u^bP9eeԠ' [bS{hLO]p)osL#FjQ,1|â#ti5ҩܤGhM27̗ߋ'.{JjR+ߌ>bjc* @wC;Z$ܞ b_޹ mNj3U')coЋGwJ9u˝م {X7=Siܢp̪p{֧ 5~+*=m`onqq9"edatUwlnO6T PhGO,~ %m|!~ߴ6:[PUNY1;ȭ_q5R&)lzM\zq8n~m/?S'<{r/"S ᳸H>Zus.RmO/g\~|G&}#Z\8e瞧xvS[}]شzR 8᥯=Mz۾8rCO9w&,kBGn +TZ~!ud"S`&"xjGվAI|ZC#-/g.mZGYS==d\hYY ܈#C~ZͤaN?wiXY+&q $c)2?nܗA.-l=Џd-W|lƷ5m_\ŏpoF~߃} +rTכ8 sı~)r IPLnX8wƖ]}%]8]MĂcׇæ5O=j_VDD*ҧ /FaCI;l!jXy;*:[IQ4-fv,]"_{Jg=i,ń ?*kϬEM]I )xs'ڹ7^ :+MV WLAL.߄@ _R6%MVn\|V݌ڀTNDӳgNݶȰ?7|'5&L}a)[&K߿7็aN+_C\N}~tf\Nj}ys ͜źp[]{xoFb11*,~(|۾۞-|XD Q*h|r$GS(@?"rB Xb_œ 2J>`S+7]q.sݍ19bG%[`⇒{Aub6C :y)z7Bys8^< `11cj̨Am~37b ,~xkR&yڠLoBf冯Mc֦ljBْ5kޞD"K|X_(G*U%%E⇳ݾTq 'g؊[~Z~ք-Iw M9V~K뛭`-8h ǧt&]ec* U%6!CM7={RМOؙ[OOi,s&kYʖӶԘ7ܝ8 &›OmXuO3֥ٝQ-u57|Fux%u0h2c-w_/Sݸ{JLBźvgMo/ {3'n}\~xQHܹ$V߸ Bym8ڛpޏ!G3iݰa&Rp[qMgcZ8r-86LhűGdH2m5յt^OH aA|x@b/tcZ`n=ۂVOSV﷟foߙA"aC喉'a),@ _R6%M6IJMԊ[ e̘Z}&5y|&E'IM)ۺ97tikЌ }{ s#m;r,=z+П={m/m?'-7 $q݃]x7ǤeG&-co>ukOr#&ec* U%6m"F VGxj &ikn} y4/ ؅a:ve [׏5yjME [ǠvM.״b'~q%~Ys!;oS'qxjpjGio|{;$n{Kfa UqO;~wR[\`p0ko~3&X8~|ݳ%y%Eq<)[fuob徍غ}(?LDx:CX#XB.fx͟kuj,z.-SO̝zζ>h^VvXpG@ŏಝzB<:9WW‰gβŃ:l^wO?]ơ5^xUGZLӊUwn5.Ͻv3ȃk"7i>0n^]é3v~gf<ۣeqRܨ~ɳ39{wq8g1#pG>8#ܑs<`'lsڛ9O؉ޯZݒrK={U/V%}*c^X:{`sco{O'8%A= ܰq=o97+f}{[y0}~Jyɂ@GLOEEIt zY,y΂{wkX7;i+,eЕND~tlu Q3'ad6K u$҈D x`ؗ6x= ڡ|{޺AN+$'joCe;N[g:XLA,[tۑ'³u*Oka|793Tx^cAwي Dg'v99e,;b>lڸ6<08N\7^xMۼYz;&'9oKే6m>z\ ^g}j.Ʋ#A{l粗]?oP(­?Umkoe+'Vlmi{O}DnAoI᝗^.ûv!bGJ؉=ޫd#,C7S瓝7<=_7<߽u'99NmnܝxN6-8wOo=rh0/7zqkGц52^_.!C~S! 0Dl1 Ō3-o}E25.w*x.s=hg^=Y\.772mZ%3A"?te2+ 6kv1Epßn {݃p= [vLS8w;vm}S;qGD~ԉwL@^N ^/O^: ٽpW'?&܁k󎅗M{G+>e%|_Ù~/>"8炓%Z? 3#~K._?c tO>=6"zlB8aJ7fGG2K6]c/ ́bxk/|1;O/Kz:ŝe0mFW$Tm 0ͺQr>-r{ӷfͩk<}MqC_XmwZ"?xa7g# J_EX*cPe 0&sOJrqbk/p$1=v]y-e]pc{-m Nd`miH7-u}zy.4ﵷQs_2Muw@՝{TcP6: ( W-O]w 8Ϊ otmA'#2.\]};>yc[Ptb{xWh{ѷ ]t<8ms}1Iuƫ>z ݣtjt:$c|s]_'ܜ߀ҘkViu>[Wmd38{uU걝TB|n%Cu[t;x(ȴzoGfŸ qP:uرX>L 3(l5| ȹ>[f"E.cyܠq x֟/c, CPA,[tHn]}{rqX  ű<7x/Ypƹa;x%n=^$ݰrq̓l׷Cot{l:w# ۇӜ;L[ -ݞ<;y=6VnwU mwua&1fO8ܿAi!mS}}p=kp[P˟R胡5MڎI VG k⺇,Zp\9"ʛ:y֎)')i^Œ[u\r|87n㕳7Ġ[E.U#,q8)R%Gp|د;<"D!8 !ڲW oڲ9Tj;M!+mѓ1q_t2fKʕ_al|F_<e 20^D OHQC_fS8mjG䇺CGU8ow3bBs %6E?F^m [Oσ{G%6[p?vwɘh}“J=4vt@H D~rOZܻFLVNb3Ȃ\ʳ3)\WR}9'aܘ?m~ ]bd3t+Sy ;MU鍌`zGft̆ם7?W~}#NeVtȵdm$a,7ȉЕ5^?Z;8kkr=8ՉQ0CǢ2"UWއ`>U{h*'qʈa,?ݲx=Ҭ`Q7%֎IsRԍp!Y""8U##.oTί !?;tTtq#|@SMvsO fy'O=g%u}('P }"? m'#ߴڞ#'CWvj~xeD~7q*X˰rNnc#sWQ//c:2}lZjrEEe:X(vY CqMHn:AU%֎D~Xԍ<I D~rьa 1iq)ZWwUw,"tm`"?}o "? mwp?F6{ku4zSn05^_NQoI2̺O@/j˄Ʃթ&WLOLAG:~z߷mc{Ѝ]NYb@eɃ@/x湠)ض!{&S^C"N&C(F5Igrڞ#'CWvj~xeD~7:E>(V\1>)XasV=tk׃SX;Qgɂjwb"?xurAs?&S 뗰APD) ;b/ 9q.0|j{]ZiB+#)ȏ%A8:!PU]-P\2+Kn:0n|zpkGIݤ9) M$P7B $E`ڝ,o\܏I{k`To՘,d $oU_4Yru2]ah;923|NSoW$C/Ѹ:uC T㡪,K,[&e˙WTtaX7%֎IsRԍpIndAHJ?;/<]Y:)Lj VE!\7.Z5KGD~s` j:yE@"?d^S\1>P#mnY,vY CqM03,ðn)K%u椨/4>`Ƀjw^"?xurAs?&S6&kC.rة|b 2ȏtmЕm^xVGuz##l z}P6NN5b}RP"eXe1?2 5)XμSú׮,vMn\ЄHu#$"@@lcX%E"?>܏I{& cyڐ?+Eh)/+C+;5tj}~7&s<P:2aqjuQ07!R=n⚔a,g^&T7zM7v=8enҜu&GR!Y;,<]Y:)Lj VE!\W6RV_"?ҵ%CWVv*N/^pg}|QC_&̟WV6NN5b}"*3B5 jp0פ c9N= _QR7iNqB#)Ս<I,o\܏I{& cyڐ?+%`r[GNGD~ʮ.gZI6ZZ "?x>ϬTL?lZjrdDTfj..a(Ira[7zM7v=8enҜu&GҬ!q2wLaR0V/ 9㺲\!qD~kK䇮 mxdz:ׯSaK냲qjuE.0MF= _QR7iNqB#)׍<ID~tey~L;0m+[Mֆq]Y.5r`r[GNGD~ʎȏ6w<#:E>(V\1>qғ#dQú׮,vMn\ЄHFHD"?xurAs?&S6&kC,jx#'#]["?tehe')ȏ%A8:KF= _QR7iNqB# !YwLaR0V/ 9㺲\1:2ȏtmЕ]GUm> 0CB,_̺O@/j˄Ʃթ&WLO$eG`D~hðn)K%u椨/4>GKEox莌/YlG'^\cF5q|~L;0m+[Mֆq]Y.՘6X8^e9+C+;|%UQD~7:E>(V\1>a8jIF= _QR7iNqB#"@R@߇y.hǤc چU}dmוRYmh?`_\SqD~kK䇮 t7o1yE"?d^pg}|QC_&̟WV6NN5b}")F!?&GD~W7%֎IsRԍpipJ@HD$wmnvfKDQO(QUQċb̈f<\܏I{& cyڐ?+˥3چ!v9&OnqD~kK䇮 L]mLϚ:a^燄Yu*_ 畕SSMlH0G6ܹ`KG}uӍ]NYb(4'Eݸ~ I[iA]v?y%s7#_"2DAH~83<4c1ImX~ުh6rƬmÉ w/_#[GNGD~4&عힸ LSA2̺O@/j˄Ʃթ&WLO$e<"?ꫛn|zpkGIݤ9) MLR݊!y0ǁ!2H0%"ènLTD/1#~ޚ8>sAs?&S6&kC,j6dY7t׭8r"?ҵ%CWVv6Fsӓ7F]~xeߘuɎg}|QC_&̟WV6NN5b}")FX޿oFޛwzD~W7%֎IsRԍpĺMU/++V\1>al#,s#?wo{3%C)K%u椨/4>2u+>J{= ɂ윙L7T*Uvj ;Fú1QePN.ƌ82"?iX~ުh6rƬmCocw}s 'pLK{T6[GNGD~&_qyTN  |ADG4NjrdDR U]`5>񓕷;!uӍ]NYb(4'Eݸ~ I{ OjOI l=wcKLTD/1#ȏt0V/ 9㺲\1k0(*?Lf| gd9+C+;|?+?Lfqj~#B*ߘuɎg}|QC_&̟WV6NN5b}")F<O~2l/z׮,vMn\Є$mwVfGVPľ;O&ɖ?/|8` {:ˣ\9+V١@s?¼ku10m+[Mֆq]Y.՘m[p_T 1ܻXg .LƑ-2s|}͆ݏyy O 8?$D~cѸ:uI6]سu-O wV8q=tk׃SX;J&IQ7_h}d6qݓ0q&9;vlui_ABAH`0 5a޵S6&kC,j6c/|.B~f3=yؽo ?}ϩ XȏtmЕc/ރs}06,9Db~c:( CP&;։ȏ &'2m`$x 09e7>1)K%u椨/4>2ucLa;>Ur#3A=uAϼ{DD~u10m+[Mֆq]Y.՘m<=pݿucm0 :o 19+C+;OwMIt| ݱ }3Ty!ID~DԉwNO$eقO= :pw vWba_QR7iNqB#X7'CGGd\~ZOߚ5?4Ajߔ\foڜċ`k`d?^%#1ImX~ުh6r,{4abޫnz,OR=rq7=}K` a3hkscdkD,_;&S'q:>a8jl_[Su gσ#tCWo 8噕1,TWaF}pbm-hI_QR7iNqY;6didܱR:Pܸ{-[#yg~w?P!JHw}@Hʈ |+}ğL@c@4> Oy<($T1@ß(` B'мh$AHީyl@;qP1J ؁'мI 4/2 ČqL( OyA@h^1  @@hn%4> Ol @ @ ” @ @ <!@ 0A@ @ )"@@ @ Ly2 #@ %A@h^$D4R /Y_t1:TXtJ12|q$2!Rfh:l+p갭'ܩV)i*0 u?y-cVxl >8Z=d38x0TȕZ !KK׶1SXB7n_nߒ׍gKK+L 6f3tT@m]\6o[i1=6^<( gf^rga8=mdh|N:P!,nVjuTTv~ʊ&cJBmR(r'|τl+ZO[pE@|o.yvH"1D~V@䇝m"m~'Nǻ/. _-# RֵG~&Bn0ѵqG'Bc=  ;ܦ;3Ɠ"L 3ɐ!17VD~TP7+n?>v!}}p=kpp?XB 9YA|dOϟMccp8.|K_ ,YytH"eFag/}=y";l^qQ'|}pYx}.e]z'|l`B~,d&P]Kѳra0ƒϞ^X`yANVpdimiiq .(K011l`t.&!tyXrT@3_-JuFX;q(>uఝ;vlu |b#Lx "؁3a6OOeFag{6t\f|CP~oQ7맹?Z\2.e]z'|l`B~,d&P:cd#[ܹu9c 5k6= Cng+8 :c cccu϶oVjuTh&$E(b(w|6r\5RB0oDGeFag{aKEzc̏;GKY׶uI*[? Y D7=8f~̘1 "?vz K;mOOtuu5>̏& 7-bQ|JB(bh}*ȝ}$AH `'l͏7~#qC䇑mD~G7|0"po#Zڥk[$Lȏ,QaBwaїl͏ٳgANVpdi}}}˵XOo͏ם & 7-,bQ|JB( Z8 9ӀިIlGe[4 ?a$ہ2"?l+ '?2 _9݃D0FقY{9P'c`B~,d&Pݔbd3:'[77 ΂,ԶU!^=V-xJowiBpCX-"V,W$tRyڞs$f^2TȵdD~N#YϺb6$bLLȏ,Qar=wT7 lANVpdi@,&!-}"V,ל@]c VE,B $a0g<3T"eFag;ȏ@v3~V=̎ 40KY׶uI*[? Y DpڍgO53 ΂,Զbaggl=}  ~-bQ| <(bYHk"@DpRH@(ˈ0;)H~0zډ@8U^40KY׶uI*[? Y D(\R-r;=[YVn^Zw|掝 & 7-bQ|JB(E,=jID$`\tJ# Khim=T>~0!?Dun#-gKKD~lgAvj[]KA,BbmjVGef %[c"VI9 $%L䇑mD~Nagz/`fcqei֣n?Icc!KT7z61Y7l Cng+8 Se 3uzl pCX-}"V,W$tRy,P o:Z<,#q{0e0;)N~0Lgٌ/2Ҁ+,-]c&'|l`B~,d&PFԃ}_ D~lgAvj[;'e a1t"V,W$tRy,PĪ&] ad[vQ7(Z T>~0!?Dun#%r Cng+8 S pCX-}"V,W$tRy,PiB2 !(D~V@䇝-jhj T>~0!?Dun#%r Cng+8 S pCX-}"V:WZ*nQ72X:@HDL䇑mD~vőB4@Sue %@=LtQSr;=[Y6y;BbmtEZ9QYBI:|#X%oiTQi0;["?% .e]c&'|l`B~,d&PF/ANVpdiMގDй F&JMU+G:* 4U( ݢTod @3-;-FagKdJtete %@=LtQSr;=[Y6y;BAe(57V,W$tRy,PĒ74AH*(D~VqIe}Uo)hPAdlwIDX I*[? Y D'&)ANVpdiMގDй F&JMU+G:* 4U( ݢTod @3m0 cĒ-ȏI[TJ4 2%2YZ2LORXM&G=1 M "?vz K;mv&16QjZoZ9QYBI:|#X%o i# 8ORhKc/A\̐ȏ>5s=2LORXM&G=1 M "?vz K;mv&16QjZoZ9QYBI:|#X%o A=t Naz'[ַKP<'>pMq\ T>~0!?Dun#QOLBSԶ:(DijVGef %[c",۟`"@RG=t GĎ͛uBR"? lE&.-ue %@=LtQ$cD~lE%`em FޖNZĪZ*nQ72Xfl5Ii^fwSh8G:>+CbD~؊L' i\0!?I#rzpudnn&1 DH2&)@NVt^VvjF bmEZ9QYBI:|#X%o'"@RRfh{8^y+wiUʀ#[]#.PMten &gqԏ CߥO%> DH2&)C~i#eGh(L/fom,v /D u,hy,PĒ7F_R :U| <`FDK^?8O+d BKk+8t҇,RD~6kYLOR6K&~0U[haX_]#CK;Kb`& "$ӚQF c*Ah(d(/l,vGrbI"c"4ڟi8Rfh{r}[w0,]yxP(\b M%022#m{aߝ_֜t<ڵh]0f̛ٖNz u&2LOR6%G#0M#AQ=uO0M-a#9ԳAKU_y'!bҎkszԶ#4 b14ltcIuxr '@3_-JuF@K OH D4h)3=g~L`tt Y}0>6{wrɏ"]`7'BtdTɑOwK 0ۙy'sSp3IU} i\0!?I(\ a"x-4asFnj10|8ѡdo;)zq<}[YڶvwA:Ƣ, 7>>P=C Z?= %[c"lڟ4iRfh{ʊ` o ᚫoqu7CcWeϿ 0>:05D&2LOR65ȏ*فt>X:G'SO0M-aҠ"?vp$3(ev@G]v"~AZXn(_#u&DH Z mV&+P;wy5V]lϙ79ip##cuofGFj?#O 05D&2LOR6cG͹]d,,j.܈ Ŭ!?a3vChT{$㎆EC!her B5ܲee uC8%chCi*ԓ@55aB~')[0:QBz(v@>g#W9 UQLg]]l|>AK>upg@3[_w[W>VH І"~5)ZX9`oKS32v›ZMD FGJ8"VO0c׎Bܵ![`iS^bB~G1cP~%,a۶l޼9~Z+柾}8wy":>\ؕl#lݺR x8,_P"UF d&ChT ުUxwpq˞ p-c=_"3* #;B й .qbm:2^I逓̀9䦟nF_HC45RfhK3?[(Q0 @ꅷHKDצ*8D~ei6I~/#%ynѻM. سg?ܹ~_kʊ pnJ|kpʩ'W>$8sox='>fQo{כCxE/ 8 aDz2b`!4 : 2%Kzߛ``9\tbxu14A䇉!.]"?y`V AxA8X׎fim0౹/|! TAH*@K-oPHB֙alc0[D:TL62u:`^ヌ7˄ UY %D~$dkhڔO~ީ}},_*3f>6O?˞ s.˧+^RWWٶu;˯xaz G_Kp9ig< h,7 71*vk"?dmBjEN巖+a`ocI#ki!\ɏB m;}:kO6FN!R uAd /!:i($C(a'sR1}`/-KEqax=<GaZZ'g=^{ۻ0d+ `!bɏ P>Ʊ/ra${Fx{c On7nޭb!<ཎ:6= ]޷) VY#  iД.Sz"LxL6!xG^D~cGH bq8</uiNw'{aro'8 \XB_HC! aHb~ipᕏNfy^u۽4UK pK)'̬ pɥwJYэU*UYD~$dkU$&\AfΜg>ςKT _"K.71[}"B~0|?-ofUfz&ïfHPw: e&D~,`J~0H;nZwwI"\N77h;B н  >,Wawf¼ߥM, n. 2h@HC Mm?7ŻYmHT>"n[:RtLww7}3Hٿ}Z](u;wmDK.Ͽ}GviDe^PߞEWw:K*C j6Ww$NҒ+>HA+$1 X8~o]jd2Ny+r~|as7Ar| ۱^QOȡB.*7c PCB  #A"?@ǖ 2;}.XN6:]'Vk$*#@Œ$'z%M[t2mWMq1 I*.VϢ'Tޣ*qAa{"fϜ_U'a`8\+eW*em\e {Ug`Zr ;Mp F%כvY NФ.6W>Da:l_?;tƈ^ahbim;- nGmLd!W˶3N{3Xػ%ϒ=^ts6^bi{oLwViVsz^2PyuT>:|#XRh'$1p*.2"?[xoeqf8X #[*;s"N.k_.~]0}FwCobAUA D~mkE~\uY T>~BK#=ݠKTD a>-c!1NXd_#@iHb`sCHuq׼+~ 60)ʋ{INmK019hO.~w:9Y5<';/oCdG=eDI 3>IP&?(Gv`%eR.BY/( |"?B"@RCD~-;( 0"dZ{ RmNգA-ۖȏS>U y'n12r0<^|Z\|~V3 )VN`\EcW+%@L^5ةm ư :h͵@ki*3BFx#8 h޽1/ݿEpK˳@23H ʢz$/Ԯ!i $Lm٫+ȧ b,'z%M["?.ޡ>)\8?pi&'VuXB):``wd:-S)BGϺ 4DDE6fdS☲Y,6F|" oTf0#)?=2c %PLGݶD~z%KYj>poub ojJuFĢB6B @}`eG`EP&^ g.?򶗯X?WfzjG>`Eh{x #B>pe?D7RR8Ĩ>Zm:! ӰYLORA.fd4 .DwZ?iOekl]2gd oY? # v2.6Y>@Him=R01$"?LĶ4PaqA'?Pfr8!"W 1'ngNwR WW&?M1SfBlMP z ګٖ6ڿ=a^hfD4 /#l 0~/>3Z8kf9S#,Z-[O>-Uϕ #[5 /&k+v2LOR9q_+^p<8s8p+fK`ׁiU쀖 ` wj{RɏFNc/I"NlK fw #1mpƑ`9 ﭾ%X_ŲE+]w~۟YĈ TݠiP_FXن,d~sB-rzPzpal c}#hlHI\ #["?jnO,?n8mt Q(A~_+@Lt}^ܽfv8NIl|$21=#+_"n];BA䇉ؖ5,.kvb[_,dw3l=,h5ޛc#g/'wm}3a,?\&@[czJ+#?1;gf*r$TG(: *L,+ԮSuFhz $u-+֟m-̹?.mvjXh};w<__5 cƷ*%LEP=RQaaYZ ݭGgosᘥvɏ'%xKa)PPXO xc}Oa!A:g,*QeJ]"?2E~8eB|6=޵A~zSWȏaqAa# EN[^%Fx&xLl _sٍS;y~G=f\r__ą/}t}{a}o?WB~H+"*B<(bqxԀ2"?66#@&{&P{ <a΢WkɈoQ7W Y6Ub<FW/~lʿOH1wBGpd="+bLxyt';- FkX\K~00" A2/}څ0~|Spw‘3ӏ]-ْ|%Lx Ͼ`?޿#?ƻecSoO"Cls!$"@Rˈ+[q6[L`buV>~P8IU.ģ+%/zU] c<F&p$0||=~_{@v*<AD~؉mi0ZؚI, UT&?2vkKxycG^ml2QuMTj2#?ν2иh$i(HV0#i'`k@& tZ cBQBa|L Pk]!=ߑ5@3? Z2 ÙJ!?x2֍MM+kc._ O|uFspK~t0ch og`F:|#QPab\q_1 !h(*{ r-!<#fI'wEa{璓"\WZ c;܎ xBo.IslJT>~n?lHxSK{5ꊁMŤe_Ӆ{hyppm1qD/Q FlG<#jPoKvy+N~Cv?=t Ekw9pSy=|ٯ6y6߬9=쇝{[9o(%Cls!"@R\{~ݞ:o*A213T ߽[wɍ~fXDRˉ{Q'? ]aZ[Z}?*t=" L J To: *L,+ky.4AHD~q&'mtw GCS]ݷ :r۾_Ľ BA]}M.[=@ C-o8!3T>~PK( QdC`U.I]tj;GC7c6bcXNhVkT˺?>}DiUH3HyEH8-#@u#?巕@uiq΁5珻w>߹j( ǡ5 ',\7?? ux6 ?nuAfb4Pv@5?41 $5d"?_5Cojˊ  v}^la{97R*"w$HF䇞i]}V~, A'd__$߼;G%a+Oޒ胺وNUf#?djκ;o]T (کmNlAhH `qA- b'K0|*2ތ=C0rٜ]^߹]7z00o+,?uiNȹ7 ٺs{f@gKgߖu[` ĩ:|#QPab\E_s!4D"?8&;İD\ lg"?LÄ$Lȏ8IKցlf0T x8{['{V4MM䇼"D~$ bmY\KU*caq .;z;`!o}#`,>̘ pҢ5Y}`reҥf) E `C!!6+:.#0(P#Y.0!?IcSEgK;r\s뽰g-]{W֣ܓ#]qrӶCi1om"9W|zgi[ Nf`ar[}b?x|آ ,dJ];H~w_Z&p-8q1q4Nm.A~wqO %sKeb{{Exv#xkq#' yMc-. fLLl Cdzw}9ď@R5ؐt@HD "?ʶ΋c ˖e_򯸫b(9Eh<4P=޽povɶA0ܑT2"?PE c0gwqp&\b/~9ooyfc=s6u{!uo~('Bý.H~r*u5?%8N}GO[@3h@ 6MyX\J~*) n[Py;ʳ<2),Gwlo |uEaoCRvA &Z<:cAHZ l8fH|Z@LYxoo9?K䁽qVRvfbv&Cu]aB~{Rs7#A,^z/ WbFpƹ0}qrϴZvrpr Y;*a?03ϹΆƊpyŐi?5vuܓ﹄Jlp \IL>f#;zhvke `ଶLcrNᘸ4 &۪;,.eqA H?'4q nل[8⿩ld;C.:vyNٺ;]?GuE>#=J#7g-Vf@@d\`1ߙ0F/x wy ήޑnp7tcV fGO~X)/@WC6i~0!?Om;J,,d;K"R*35`{04ںc4#rd=aSwKఇ=?b# p]dHRN~gR‚r'[^)(g_,[t/&mNlnC"? FޖZ'&B_\J{YG?޲e"\J-tZ ɪՅWK%ӗWPCG!PvlzZKuTQE*l+8Lkp?AtÑKZ&[?%{>h3gs-WmWwdX%k2s_l`B~Բ`=z'#|=Aȍey@iRkd;^w8yhπ' 뒕lqψ8 `8Ĕ2)udw0¡D~0(6dCplѽ0m;y[<85#^f0 $e^`f{n_&5bO|R[oyvB  -ZKuԀuQg[$?+2啫رr@wۼw5f@ɉcL9/@WC6i~0!?m,L0G;H1PvW-RU`7<dP%@0 1]̗O&*Dx*M )gRوzFhvXR..lcHˡ[kEbضyĶ$C bmY\u@pό&8e7`d x!K{>oa%p*c<΂1bs>2kxc; ~uԊ!@M}-ϥXD@H*:ҳ0[uRZ5ʋ>4ՐML;~'HL ra(-V . ){cgplhA& vƙ[K8xy&h fVR tàS[{/s?= zHZ`D/e6="? ) bmY\u$zW>"~⇫PK7"J5=O,ߕRR.>":c jP!ג8ttC#euGdGa/ &#i vg`pk7FG\gy0)W5>luUWg{Wُ{wk|hi fH}^2iL]=8Ќ Fsnzصs7Wxf'GndTOպKt.xNlAy[j2Bk㰙Zv> v򓠳wfmLv8{B,PqIga>he"1Oo>l,, mLgGvķK`1q(lg}`01c̜ߝP RNX\N~D85N6 Y. 88Շc,]\wT^Ɓ[`fo7t 9=<!@E_s}-ϥX !@-*ZÖptF`ڹ 6 xuP(/X6kor<80螰HwLlղzm5f5 AC7@ۭ9V9nOfa'`}Y56;|Y=;yt`e{gB`?dwIcPX#g#ȣKr쇎pD~NX\#oXÓ 6NvG꫎\2"QxGj,;to{j'Wfϝ OkLg_͹PG!@Io\u?'DԒB%;L|xdFGa\bnٽ&|=f=>^.}=̂΢0;ʜ2"?,m5f5 faszrpʙp9Xy^v+!vbpUYill\@Kv tT\]fCۙK[M3i[l`B~,dȳX;i?k]pzK̏w z[oLxs hq q\?EȄ~75LN24M@Z z^1mZعl b nlrYcA2f؉mՍF(#oK,by:v^=PzRXw`JG\/`AKf=%52m-c0Nȶ*9SW4 jPabqE_s#cI %C\KF3?Ppk{;tϝ!Ԟ>;ɛΈ w3pz+916}StwX=* UZ2"?,m5!# &"&B&ѕTˏtf`N8qa;Lw2.qNOqaOtS[ȏжe=xS̏8Z\oӷ[f~aǷBbm4EZy3"c0%ZLSuO옡OodZ[ s߈kjPV50|iƚc@H*@-*Z2"?ʱ#Fgwsj8aЪ( o}@0!]ቘ[>ڑ:Z<6C;VZn~0!?2 ]L_eiϚLjm1AdŰo{ P%?j_+ӷ[Ppa lMMVD~ a1t"J!L6TNA٦\2THcEĊ062XwA(>6oCH3TM"@ |˵dD~Ԝ̱Vr<0?c#PC缙~,SVh6Vp ̞7Gj,6K[M`6绉l`B~,duF^[Uʌ '& ?z\P}Ā: RaY!C}懘M@Gv|)40Q!,FޖNXĪ@=D˃ŒsLha|8jPaRwҌ5f9r-aL~D$JWǬ8gڮ6s:blɴil. +'O'-gMI\8W0##ضJTyYxZV؋vZES2\sbD~N a1t"V<=VF mC!( +s5a仭MҌ5f9r-aL~ջYXaG@\ƒ-p3lL\f `'?c&d_X,uxeAQ@̋3& K-e=T8 F0;1-kvG5ƶSh`pCX-&U+Dw*Fy j0"ɏys0|iq:uTT}m>4c8BõYAH*@7\KFP&Z#I#ZU[g>UD~괵%?d!}jc!KT_.1!!EdŰ!"?vzcڶyĶ'Cn$jVW%[_ BTƝw~`pCX-ZĪZ]dqP$B ߾͇f,> "@R eD~ن<=M>#\AQaK䇝m,dZ}uXM&GSc+G=1!ӳ[,Զc'U78pCX-ZĪZ]U( ݢTod `}m>4cY0,u;ű#XkhLF䇝SO\ F\XM&GSc+G=1!ӳ[,Զc'U78pCX-ZĪZ]U( ݢTod `}m>4cY0,Ih&#+2"?lÏ,Qaۈz4E>2z$Obim;'h#6QjZoZ9uK+_-JuF@K 6oCH3E_S@0 dD~:MV"vD~Bn0mD="[e=ʧIANVplS6VD~#6QjZoZ9uK+_-JuF@K 6oCH3E_&8I h&#Ζȏm;C">#? Y Dh|leH*&r;=[Nmc? YB,|Qɺ1"@\!% WC?.+s;sw!1òi$ GϘQڊD~5nS=XrT<>~,uʯTod `}m>4cYxi1:@HCٙВ}UowTǟ&x["eߺאfضq3| g_zv#?k˖/ G_'}f͟w2ڙ$.`B~,d sO楿LϢp!t޴}/#? Y,Uzyg+mQuzwW_ 8 Rb&&K-e=ʧI0V`JYp~شi3\s͵p 7exqյ;BooO>^j) ۪;trD٦EeZ9u+{}/, YpwQqB(&u}_!X} }ID)3-ku2 }5:wxKD}LfݣLz'']v⨕0klX4id+Wm.aqhYLȏ,ABT{}Pt/İ|Hg@"jŐ_>}g~~(l{6מ_@혓,Z>3?u9s&r? iq>eWHqtb_9竜範hKE/[(UJdJ;_~"%Ԯ/2z4^>Q֭{+;S]z{ Q"߹ tl˱LlQOd#򣉠#6QjZoZ9uK`ȎA1?@{ l߾u*E_&SLjD~Xu*0:<y7> |疭uF`8c=6: ி{Cwot{9ƻgk~kcVW0gw7,\P{= ;7r`h~w\{!wG+%<'O8Yi?X5:Q;W?s,];a Yz'uQ]L(mSpg -[oIKd^ X^9=!{ʫT( S;2/_9ײ3G}B{Bq 3^[QtZYڽ[ ?cVK>?Mm/{l͍}p繄OϾb|33Oڵwg9,Gxg >p,_~|q>ҥKo~|/cnG?'p.ElxR^x|╗/CYZҌe} c=ag8pbyo%6F/'q*W*ر)F/ {!&,[]W 2?-ps,R]m}U1c_|vL|R.f1!?Dud[`l߽#΅Bݛu[yW6֚PN~G~`g_4̜ct܋}Ő߽ɞ0Z>pymڟ2Bci ݛM f|<ë^:6m]{aժUu;9,={x6g^WVI}?{(}?E_IO=i^N::/~K<כ*~Zm ,mMҠSy[:ճU+GN,3-:qG_}ܱkw_tYCQxpf7?g;=w/Yz:iedmr k&+<5+{{iMk!ˢFR i;qX{a;☣Yxdfti\wW~M5E.YpAw̜=˓A1EܱKG=yOPt۠u7:Wa݉Zrfٰ(d?VɄSe+'{?s.V0w1zykdm+ 'a= { k.ܱc|߆q8aF3nfW6}YY3}2 H.["Z[[u3gNe&ǯ~+7歰{n(gx3@ug3[mCR~{_lն-n1~ VV ։% f 6owG'W6N]}3!x_wϽaA[_d$Q kl7w'y-pf#r1^{/ql߾͇f,3zMHL ΖsqN~## |2'jN[ uo%M/l\#El`*.9Hƛ\cݻ^<J>)2%XڲvݺkNT3?X(zg/+bD~ha YzwK;nN΂ՀmZ;X,;-@ezN|v. 쀶d]pEkg|-;2.)qxAQ"?×"x;00 ~S].suvֿӟ~ [c=H{ʢxwnf?V/R-O_믿#@-[ gd  A0$/ODgx:-uH?*p)P bmiVju bX\ \ʀ9zÓM?o& yxɊнeDdpcdǝN,ynEA L^G,3WHD"?l ?s<dӺ0J eGn3o7c#m6{d{kuO {{ ;K-|/Zo*22Do4^Ck×0<@4bV4HEf=ȹGǯuW@c ߍzv^5k P ٞyp_kûHdw ͜ - OlRk>?c"t};f7U$l fs'֭[xB%[rWX;31nSO=V@+o 1#X¨fpf2'!QGnճ˗ Pe8\[6a 2ܹBGz D~ 7I"V:tL l_ΉA̡0޽Y1 ?t+~ْS?~=|iƲk>4l֠5@RZR=Ǭ`ܺϹǟ?*ؿ{/aMygdZ 2tp-./|}Y}֩B#RRbጧmp᷾ a~ ^{K?1"?tl'zI!KTWe0.vv=6M_-/ W_'lgu蕱GK؛V:;;a֬Y|%6w<\~KJl`ŋ<¥fϞ\53A,Y 3gNw +kn>llzß6Iwmpiz~ﯔzmܷڲFjyB(pCX̥,.:<9-.ubk%~oƝXG? .{^g+K)å5qu^`}m>4cYxAX6@3@RZRC% |y~[5+Wvؼ~[?_}]{4sL⭯:aI}Y͔OϘϺ¼XV'_ sç߮ Wrb:,nra&70OQ4HC]=q˱Ǯ_땍r+݃&cZ -i/\4T~ O? hw y&Om]-n߸020ukw? >e_teh'| tSUW~FzwcY#nTgZ#GLl+r+Uo{pŗdWY&| ;'}ؾ}|󟫩'Wڈ"?1~ VV ։É3}GMe7~6 O}iW y|`;?w>kں<{uLpu#ɨ8"k!ˢ Ұ!  R8>%@*/nx{W.ΎNO>>O9Ϲi{a.HDd#~Õ]uV3-+o-^o!wJ.A1}#JZ}j'o~%$'F`_ _fq3wAO;s2bSgD׶?LO ȏ`NzR{ڵw/~`d>0+? __udp{u=pk ˯'>\w=~?Vf|_t=3w\ 4oxÛ<e011὾_=">3,\}5^x}>X&ysk[Q ᆰK?X\uxrT[\ĊBj(;~Nx_ 8 @v;|_h|!eĿ;.~'_#_Qv*m6B,ZϠa,]zhLoɖ?5fYs2I['.0u3Z:;" Ƽ{}rKomnw:5;tm;X&un,稷ݑq(z󉓃űc:2-Бm~2&[-nގWaԍ=Q*W5D~T.N~301Į@' %_:Q,D \[N;Uif70Q|Pl@++'v5Optr%l=񂯗wvS,J~.xoaLfo(۲GbYCoq_ydJWiyvNeZ̞D̅Dqo6fʾVZs*ul~``i)?`oЀ֦G`QW8ޟ2!Lp8.1}Dy1rcP{m.gA[O7?T_>bص3 ыGLȏ,Q]zx{mm4,[>9@FzkPRocv!>3d4ώ]0] 9?7ˤlu|~_$/SөI'C;?Sn Ç vq CeG(K؆- NzNy6pc2_\1 JN Hh3^N!Ce‬q:5{ԴXrTVlq|`25XQl-,vcdD`GX`` 2`7Z2>aV''R`CH3E_rNH D4ƣ~8a[G!גcKGHc!KT׼ӛusweJ.9&P9D1$E%㿾:s F׉eV(O*}`&~ROsgojJ0djlŋBƉKn*P20bÿAYʈ+AGdjmQ#|Ȯ"չIЎokcg!juWT xGrQx?,ڮ<~Gx#%)\?Vǻ;-+0XҌe}F xoKGD~NaxH t%[_=*n57núh. oG9zrq[iD]I-[?cS"?Dvm\ѴxD Ի* C'GmԴXrTV %PDqݐFF^?ac}m>4cYx1om焤AH0uQ-v 27@ĄXM&GSc+Gjsl]!ӳ[,Զ]uկN~2Zv'CH!,FޖNjV/|JB(E,y3ش}_!X}-gl@9! G]D~oK䇝-u%@=LtQVfYS،&Cjg+8Xکm 9 {!#a䈲MVjuW$tRy,PĒ7MҌe}Ʀt xoKGD~Q Y Dh|leH-[?zXbiMގ0s) 7I"V:BI:|#X%ok!ˢM8' "@ID~oK䇝-u%@=LtQVfY# -vj۪p!?NJNҟVjuW$tRy,PĒ7MҌe}Ʀt V @KDNGD~̝ t%@=LtQVfY# -vj۪-kbmiuK+_-JuF@K 6oCH3E_>qn 'X-e9agKG~,d&PFԣ)Y#|lHa {M=vj۪#?l j#oK'N{(O%P_Z*nQ72Xfi6B,Zsf|T !@KDNGD~Q Y Dh|leH-[?z Cng+8XکmNlnp"?N=V/|JB(E,y3ش}_!X}-gl@9On3> : $uL"'~["?l0|@7aY Dh|leH-[?zS*zԶc'U78u@3\Q_Z*nQ72Xfi6B,Zs v $UL"'~["?lpʋ>4MXn0mD="[e=R֏T@ʦ;m؉m NG WG5txrTV %[c"l߾͇f,36}'G-u=I h)ȉߖ;["? M&GSc+GjC'1Nm4cYx<9KB2!qXAGD~bG혓XBŚ$!]Y Dh|leH-[?z(K`^hNmߖ;Cp!06Ӑ%@=LtQVfY#}f'pE.cBʦ;m؉m NO83P@,Q_Z*nQ72Xfi6B,ZsAN!y8غ~C \*euQ-X-\v*n')Dun#,Z>~$?>GD~mS6VD~Q,Ҷ#N{(OP_Z*nQ72Xfi6B,ZsA它s߄DG,F"?%%?]ڃŅ]]Dun#,Z>~$0y0hrzԶc'U78bfp)tCy:juW$tRy,PĒ7MҌe}Ʀt.K!y0ǁۯBK0Bߖ;C`ڿ{cOL$ERn0mD="[e=R֏q۸!Nm4cYx<9K۵'AD$`ݾ)5 #ȏm=ɏ_}l߸:H jӐ%ͧh|leH-[?zᠿHPcm;c|| Y17iuK+_-JuF@K 6:e>4cYx<9KۡgN$H $A;g&m(4CGD~GX_~ޘc=c H_TEP.66Fԣ)Y#|lHaO|oʹɥcSm"A9 "PWV/!/ԮSu|iƲk>c:yr]J%_N{|@HJ`@υJ#ȏm=^SY u}BY|QVfY#E>y`2lȞ= ,'M=vfD~+BG:v 02r%PZ]tPN !ˢM8t](B ʝw'>}oc:KE85ehהiKGݶD~Xj\]aǃ*[&ܛXU/}]ll>GSc+Gj"=6 ^?Zvtt('M=vfD~+BG:v ###ާYظ2skuCy:jui"?B:U7̇f,36}'Gux:߼x|NÎۿ~s?%S,e|,~IA޽p9gF/Q-vS౗|[-{£j^ͧh|leH-[?zfQdi5Kӟ2g'U78*;f~ɏzg];q+$Oy:jui"?B:U7̇f,36}'GuT¯P 0;j0koi{a#H–;)upQ6Ì,=/kA.66Fԣ)Y#|lHa[mkD' *rZr;m؉m Nl$' R)t74)OP_:C_]Ҍe}Ʀt.؂?CGGd\RZOߚ5?ӎXR a%pªEG=3 w/-uai%*w}'k^ud?Ixc9xΉppr D~Wmץ LM̲cGR{*oaPnߛ^uH{|2{XLKK+d&S1 @D~+BG2va[G3;ZO]c@fA/@O8P @lquzJ_]Ҍe}ƦtRluJye}$9>U==~m((?E")&G DGT`3Ih'мI 4/"E䀐*8|/fcv@'}`1J 'мI 4/7> b wjc.FhvI 4/h| "=&DL;;"1By@1J A@h^$DxL>i@ 4F OyA@ 4!@ 0A@ @ )"@@ @ LyB @ aʃ@ @ SDLH'"4=4F }$4> E' DTeft\:fvAɸG:w,aN{XT1"W}aܑWl__?d#{](ˠlL]UwNd;qbV%S#[Gֽwd -1o!lXX4c)t@!V'ߊ>Pb+c\_'e9QY;uTPurz>ppp 0z ܞ<+ Ϟ gh0q'+F{_(7Z'9_Ս}_()N /k_o-W@X?Q;plr>>-g]z6q rR9j́A{oOIHo*%طxb3~kn:> Q;_tx΅'Bm嬒eү'C_u7y8Y}焾K_ 7 ~ԯ'B^g<"-buȑC__,hyM(9\l'RocK ys܋UW-2q"$ >޽ 7MkdE~$b"' c4h9S̸۳s㒅Oqʞĉ6>O8(w;g9)8gtsY'ÿ? #" $e>"^~5>b%?~\ϙu69LAыV]o>,L9C#Hr@:ure;XbL/:.<۰u +;$N~TG~T'0Fwȏ$_!y6dZ+\ \?|NQ`^v>s +?$$e"؁_y>Wo@䇺uW!֯kN#ΈX&i_mM] 6F_/Pω/9}H[GuHvoֶo_=#C L+ CWdSѾ2g]ϛ3;7R|?Ի{=0@D|p8|k?'$EP˦`2uW!֯kn#\~ŒEs53?@ETuVu,U/.k|D~@-G _[# H̋{l#?B`㊍/IPVfk~^*c7Pֽ.j|"?Uw7`-+?6 逍/6J(wBLoɖ?5kN1vтD~ʦe{o/=?TAWcݗoj.x$9GinT<To" c`"?Lٟ_ _{0}\ .x_=>z{֞~w?y3~ O)>>᝺T@k6"?Μu6㗰k|' CVUyyU:D~*F8d:s 뻯fEn9ZH%A~0QҚ S]铏uz)^zKv!Y#0 1: ս.j|"?Uw69}J23WD~꠪#/X~PgL_Q+>;w| "C-l"?\f4>s@ 4lZ Ƀeү'C_u7u}aⲏ@@hJ|ȑC_:@G2}G]QYPda1"Mėa CIh]ޚ-+W.dAk]rH䇲uW!֯ZL z:z2#߇?JD~Q]"??jŏmi53[C䇾Ȧ}e+aR.gd0@ of$ {]D~ɰ1WT=_YD~pD~dLgdS&s+hD|?D~߬v ҥ(Mw|tA3@@ eү'C_u75ɏp.PICZQCn?bL_ay,"?}E6훈/r@ P׽.j|"?UwStM~N|ȑ%R9uTׁȏd:Z}QhX^]_ME&0V!äh%D"?uK~q`쯟_5r@TNnu #V|ar"CWdSѾ20)Od%) "@Bd C"?Я'C_uwx_m"?r"?ISP.To" c`"?L%ؼ-+eAGzWD l W!֯;|ȏ.D~\9V kX岪]_ME&0V!äb;"?t@aO\岪]_ME&0V!ä<@ 0!#j|"?Uwa?ߊ ':@G2}G>GN@@*&CWdSѾrdXD_@8L@H@+CD~W!֯;<ɏ."?r"?\]m\V+h_n/ah äbrԊ/s>i"?t}E6%"?xK&-Pȴ@+ q`Ƶate.=K3Bb(Iw<:۝kj`ҋ'=p`0I58ߦmD}j$onj?tB񅂶BI]0:`ܬM@ZQS.ňYJ!]F~ k.[V:;gE|8]ge m?X2V|a`_+)iof N&_D)`_ 3g!_ 3}Zr 6 #`ڎ0gS[C[ց`u fc8^'"i[|_a8H.,֔ /{{JR[ҫ3q1hkk\.c*|&&.Y,(S:dZB>ЭW>=B $ a__a2B^MV&usAAD~r:T ( ?b$A#- ;pۼғOY}'`ܽjԳnEthpc: 2Xh>}G>1a"%?eK|l9x8j [0ͽju/Z FZ~2la(=3  =-Y9ќq$|#FʩDFa2z|e֝_.d8ԣ]YgYܸ @`m N~t#/CD"?G0u^ [rGl;ѪpD~YmfcFu"7FM"DHK0`l,=s\q«6/XK0A$7éP,~eP_Q+Q ٔp; >ל f̀]]~k> /ʸw;;;ݻ=Q5x F~ut&cwM9vd6>t4m+d@E~ mv5s7 [C#Fix\y\z˜;۽qO%PWې EeVu֟(TM<"?6N0O#!?b@xBg%G{ 1spy<}ucщ b8N$hY/)eOmf>}G>G# CWdS"#H(YKa߹A߂0%22fw .~[*yzlVH.fӡ\?{X\6W? LJ"#,BCp̪57 cFGK<ݑq3R4ڳ;:;Z3<$\l0BhVPW'E~PT}UD>V pV MFIX]HeB9*^`n;ёFEuG{p071sZB ]f";+ DmsyehQ+üI ݼ1*{ԉ/y&ocpc#WN&.g0̟ZK;_5٫ZIRvPbE]! nblO`$%8|`uuMFn23\1 H"?lʨyZtC'(QuE<7ե199iӃ!Fc6offqQLMM$ '@!co|q־GљII_9:Q#p2[c~4tJCK+Jy /Z]80]b@X V C/V7>W,gˌ<@If0'iڵq*TkGs mSeBN?:fle)96EMZfrX80 mxuZBaKJ ցD[qb/L/!o y4%Ғf$kN"?c'?tU0|"?/0&rq%}xl0Z1pTs ·4;xN?:fle)96ʣ%BN\pE8r0ZZZ /z%]]Ø?'! Yb[+I ՆE %4I8 $ "h@~pdRdIR_} uФ!?GWn^:ΞG]B mvjl-beSB\xGH?Ոg$VW}BGlC[Bn9?p]}g3־Kw[`{ȏ  %VK#?Tb C+w˰X1eXr쯽WдNU 9OH&')IaTcF`[[i3ɱj#$e:A,K~sK8гK_{8s_y]T#@8"YQ#7-ߌw׫*/&&/ŶL1q15v̜r"z ˍ&-Ƈ#N$ 'gجk鹄/M:^'G"@jXa_dɏ"~poCM]77K-O^  Z#A' Wcdr2r"XКPRƨ-sb9?B)ێT MiߪqZSY4mmgJm$Ǻ b:A,7CΉʡ|ǯ~)ִܜ۹}I~h%2GaK}nذ05xI| S ؉`K󆷭Kr SRB: e*H%D <VW0}91Sqoo+"@8Xa85( ̱RIFn߻яp<Z2l>`O M]vbT r2r:򢀉L"?Tc4DzlQQNbǶGq18n\]x'5GVele)96bpjD Ng1tY 5['pG+Lӹ"n}Ƨn|57 o7~ 𛸥U26>k1Ԇcpcw-|"? ʟ猥`© "@jV^!YiSېL2ٳ~z^,Eߚ?ܱh,oZ-ܼ4J(D~ȋ&Z3I:3g,Xř" N'),>9G sC7 u%cک],3%6gc]ՆR XUtC'(QuƑAˍIH[[[!ёhzӿlhgT,bjr8-a1 sOz04* M;lN: #?)|0&6& Lm`ĈX.apF|;`z?y^t<{>d"{FOaPeX"~JO`|sWaL{J,$ʷZHCȏrzi51z~8XcfT6գqGM'7ȏ'?Rvwzt]ϙK1[ݠT*W-tb 磵-~ X?{ Ro~uqLOOG8!SWn^4Yf-=lBej:p:XI{qeֻiJ~꤄Sͯo|k{m[8t@6bÆM -T 5s5QX [CuGFG/ ce/{^#*fZߞiS4,HNBhf8ђX׈"҉JH4WNXNON;PUF'y\[(`vbỌ&4_h5LjN~^TN"&TcF`[[i3ɱjC)&ԍ Ax⤳:jNIߘ-1|t55|?:dwͿMc>߁M׏Vd)d&18n AF~d9|Nj4F~kkq D~,ǖk7#m/1L Fz.Co*t8a -!}0@*r < FGGǸY^V'iKwM]#EEy"DMw:ɏQBdPC)'"%֭_DSsJ 5"r~1JdBGg;ƒW^WV:$sX FZᩧQ[!^vɧ+d%weψ`x`Yf{^J "b[GP2J"?PE:B!o^tCG֩G~0G.Jxw덅 H',F[KMhZk[ށ#|uvvtvv_y |UFy2ek_ݏt=J$v"?`pڀ 'pZyGTގ%B}Y0 I\x_n_w *i< ox b&oc,|#;=Ai33oub^gh@B9EQHP1<,/|=zp5j#|'QC2U"? )6᩠̙d2hinFYEE "PGulڴ 3:0N'b2C͗c=y$N^fmAXD $]85cfj zzo}3~~ |.T \AuAː8ff߆~#Xbz ƈǨo"?B)  D~(*c%Ä7$^{qL .Z#?R-kaW$cک],3%6gc]ՆR ,4Hԋ7/N:f ?ĖOs~a M4u%tEƾ \;|M$Xv񅗩P?|Nbh/ B4.˵@ p$e!C*o"//k䇵[{Z NxY}kdSV8/V#crbuu`IKHk ;,^(ro[?:ʚcF~XOu׽y 5YʞTcee)96b c9\AU[EMCSk1I7ɆFOxk_Aplm3MLb_4+ۑɖɉ9hlv(55珅3>0"CQ8sɏ}1}fÿsU>^[rIm/َ WL^۱˒uPП'Ռhdd 0 k*E%n+mb|xQXA~"T"k{kK2M>Ay>Gj10a a~\rqQNb.s*Biz 9|6|8i3ɱjC)*j,D~?D XO֧*E瓑fXZbfn-K{p_!IM/>|޻ذVW.[[Z0=; "3 p qȏڊN~p(Ҧg띶R.AHp9RD&Q IV2c8_4#7< "@jUQE)oN/8u\1bWPI/PَHu__NRQg_MN$`5?&+o9Jm"?`}GA;ϳftGâ_ 2Lɿ7].sbȏRn[REdfD_xf;.]8-L`rrR'?<S蝻(cr!9^*˜Ctr7s.7ԋ =5'w&)) l6ksVb~~g/Ļ|uhb|%pV;s :!? ,r^hΏ"L>eݿN9r }}Ԥ㜷GzE `ȏJ,J~[p(54u6 >(_r8x9b]]/$R:鱪q!YylyP gL4I抉eX -Ô{2'u粐N iJ7sq>^jȏqM/|!ҭg;x r>ڲ6I(CG5[+}d<,5ڂ |bҌoskw9|jv43rHh["Gz]7GwqN_{+7#FlqZBJp_~n}χ4 @X 0~`cĿk/[< Pɤ."XmǞc??^ef׮'teVOPZHɴ=5-SNTbPs0њI抉eX -Ô{2]o^o~ui;e">_^rvl? q՗l!QYtBmdXqdmeN#xOg1tl\&؞3F7χHptwvcpX>p#Wvaa~Hگf -kzή/2qR81C"?=~ソm9 ¿&?86ld,™5v,Bb7IŞ THg>457 voiii#?& Bf&Mꄆ kQolʃ_eãDk&Iw+&a| SM˜:G*?M2f~>k|=01?!du*={q%o=m3%6gbC)"?c˵T)ղ%HS MNO >770^m 9xy0ƫzc7%W0/+HAS_ٕAyB,.VF'uo&Q.lV48 U!A `B?wOE.χHm-&CP˺а9wTAyc&Z3I#\1 eQbG~Fi%`6lϯ~bɸ:uHb)7'H,Oȇ<<[/Dֵie5i3ADȏcA,*,ލʱ]{o"n#X Og1tl>#?fgn/3δfyD~RcIil*8WȼkKnt4\^' rY)ҴO<9B|R+0k!sɚ7aRSs#Jcp8^W `ۍWC8]X^&o܃clqٽ?~;<rp-n:;|Q<;pY6[]ut+|ĺǎIU^ۀCshY!:B>Qbx-7WL,tnߛ.9uF~>^SW`;7^Li4?, dɜ,Ef|3_pW _{o1̲ڲ6I(sN`,o-[u~]>hnnFcc#ub󖳠zӉ<9?x ~UO7m=;VW.? )azz cދ9f$K4IZ@D~DEXqXT#Os_q~8)X&a1ϰq9bJ !CO|Īh's~448ѡ㕕tyRԡGqGmͭ6`nJ7⼩5~Wlklɱ)h zZ0[T])+3q޵.L,tnߛ.9wU3ni+٣@G}r߻IMȧxgFd-3Қ95-//aG,sZV@2QD)+N0-lݴQ&zE`m˹,0$A=-rzgPγ_A巔b<7H!`apFtjT tҸ+O wy|k9߼xlk}R6a(} =˓Q& |.On:ƒhhoܼ_{*ֶ]&a| rSoS?YM&2xsȤ38oo667v`ra$!C9s\ k^=6 zNdڒi:;; Eww/:::7;un?S瓏bfvژ4W^1A\Q\b.k`4+YLmb(Zq|* !|4dcԗR@Z"KÝ_O` "@j"?e '?L]S|J /;7mhk5. sK8OڦHa k/b|Λkk3&c e/?5z6{O- ucK9nQM0l? ~*my*nf׻Ԇ _.sj|Ri B;dYDt]y.4SJ//l=?N$(q|(-WFFX; eV6,pS9|xcNڿ%o{;v^۷'?ۍ J'&01>6I{IMPB4 &&'0??g? arrg͝Ͱ~!+$Hy䞏ȏ|";(ש1Z[b,Xv I)ښ[bhS'L,g4@H-@䇠lG~5rü`KiI\yS>B}W4)Vn:g108M/!kԏ9 'w˲DW5?$.@yhj04㋘ګ_7KnoZu[ B0[N?2ǯJ[Um A\&?l{- k߉׿24:4M\h»mny^O̽L(>P}Ɯe@ܶFFX; e0~tO~4W4~#<ޛI,ƦgD‚  󘚚4^qo@NjS3Kg%,-e'u9>ڃUfIO#>k/|y.;7u7'?n':&jjVxg/m.7:DGk:lfs>405x hL?#)Y%6}z.KZ*w]2.ġC}E㇣1UކNl)IeBZ"?7Q E1ALŢ}Ό+ǺTGvb8^4t|=/P! C-.Una$-zeN=Xr9;nD#ԜOx^&E|37K-5xZh\n|%hmkp.Wr6cdJ}}3"Iϲ L(8!̗˜䇻"g! ʱ.kE{&݁V0rX+,uO>qaq}#'G8!n,..cNx:gG1\IMr|.bb<昪|d['X?PMϘ7msS /匹wtz y66 a~T, .-3[mMnt>>Z˓K:'GX>BrÚ/?bzK`Ck?7gH_O,*oޝ#5W;[b2maU>} >ߥH:(C@9I(szβF93+S1H pNLlovƮhY=ho $f qߏ c]'>ؖn"U[>euHB%Np gg=Z]A ooC yS vavLxʪ{iMNU{T/@8AH-ŞlK+gߢu![gy-͵VV5gI\E}C| 6ˣQ|UE䇂䇭.0]avKm2+k䇱e=^4)fY= ) Gfhq~Z3د;4,&W֮Ic39].3q kkAreNCY(`"g6!Gxio-'qϵunUP~ÖIXZcqq sІ{veSZY-uhM5YZQPD~X tiᄉjǕ~OL4֬Y{2|پm#p>E󺲱!UE/55x OFxiinĆXD©"@j~!CP65þ!N{Z@,K*gn%3^WG8~65 CS-zH]na$-zeVaNy;O$ţG>ul;FWNxer?^c2Fg~:U$ۤhpW"rJıI(sz2+OwaAsWHH.hAOc&_!9\z,/!/-% h ϞL:h|r[R"?lq&"A0W_yf֯[m,^LMd9sN8 r_J E#?,[gXk/"ReSۏÿ5bN"RJ"ZZٖKӄ!ۏ]3I$-*ǜ̆ _.G~8$L]& kDSa2ik[ڛ1hQn |2D~ #-BMx+V?ZIcA3PB |MruhHֹ&Ag@#V'%,Q °olpNF)+C(_D~+ D ̱D~DϤx'<Dz<cVi\##R Lŷ,u0I%nf׻Ԇ _.2 byH+k/~@_Xc& !#GQcwƢIc Ec |E=;1!-''Cx+tn'KxXi""DD,&ϋ#-lF ȏȱb<捕$W-p9]8FXE+CA,k?$-zeVk/64ݔbd48˨ ^{ד2j%D~@#?1D Own'϶_tufö lD"p~!#Ij LF p^9(#<Ԟ0/7YD~Hb`*+/ PHGe>Α 34W_qӖ&Mxm!kk9"EPMg*S8D+Dqa-D~HcN,D~p wnf׻PǛ.9g>), gJmņR D~H+0jڊN,$"CՖO /ae!gpc "@jBZ^X'wnf׻PǛ.9U>TgJmņR D~H+0jڊN./ʜJ1lDi@ R 0B4BGx ?aG3.+\̗X 2D~, O>S/ms&h(6bXY3H`M z"CՖO  C9m"? 1䇕 g\}W^ҙ/ݱePYJe|}_L>Ql(@Ԩb: >ȏ(,e'Ǯ-H5m"@jⅡXD~T)"?c #D~NB"?Dq* 7A䇺C'2]lU[>e@ NCRD~8#$VIÙE~XkU!'#V; en]"?TY @{ˬw-"?TmDN-@8MAH-OGub!#<3XDpbvkA\5>TgJmņR +@Bj:ho.E䇪-ȉCǒҼ$T@r$Gr˗# ȏ*BGx g&a KmA|R*3%6gbC)"?,L"`"?:ʶq( |"'V}i3 cZ %9#"@j Uȏ-f׻;ݱeTCW*iMy|Xv!!,F}_L>Ql(pzθtl;w1b'cNO@ NR+W#D~T'pw{CE8Q%1Pׄw >X7;$Ew "?`0={fL2irRc*6cQ# "?!*PMco!ѷ] ERvwv"QK>J'@ȶ gGoo^yA>y[4oLu;P\&Wׯ@ .HP}WD~T'ZPβ"{_#&-iceeD~_䇵.ݝX 2g-[{ݎYzR 46pvmg5]kܠIm |8K)!,FlK^b0"Lj@"?G#C5ݲU`jE(=YԅhOL"tG)F˭z;PblGɏP+\%mo?|}]J?zO<\acL?Z ^ UEwtl;. գSOu?W/';0⻆} 꽼_ 2g&֑›e>îGqZ[25hW^Ջf){$|hu_&L>zٶLsWnx^TԗʻRNI!bhpji+fh7~<T?,-w0@)6s5 cakXZD~0bʶs;NҺRLfpn_ M&9Ti~tߺ˱D~(uhU8r3s~WǗ$9߹uQBSSЇ/|Y\xa'vw WK"Ən=<$G /}(J86|O6?>+|j?4ʱ.[^ԏK/B{[S9<8Ǡ5z i+f!3Ώ6_5HmZS3{'l8J-mhꭶn OiE#_Gj6@߅O"DGl£5/Dan,~h#ѷ/\BۉO|H}.4u"874"KoCFi| ~}X"kWA0L.dy;iE\1=U!%خf5nFCAgC&tQ g2L/Ϗyf['84|V xuvᷯύ[_aOkw*>uu/]Fa0"?"2yc8[PTXN/dWL>g "8 uᢵ8 ʏr#?9zng␉pu)2<~}kA\̝Tӟ8? t GYiIct\>YK(>o<|y6+zmt:K/9ٿ_~;L&69 &:2ru?u){ƀ -79[[PQ DSKgaմTs0卨~+}c{/EDƨ_::!RtOWnR\g6Dc!P>@X]=cHZ}Ft4R6Wʿz/މ$%j llj;BpYN# } dur:zxp-QNl&bC/A8Z#o?Oc%~{XOUȏ_2_0A 4 s,D~D%:!OTBY~ҙ 7~W]jQ |yõ{jL2u}SFS#S,hr3񵗦$Mg'LfRic;cM;1Hqf 㡇GeKM~ݿ|%cN׼jA$ gmiE.W?3t_OGƻn|t1ze7GQs?_ӻ2nX׌r#e5Cd0t&_M[}0Oרj|piz:gpW 9qqS8+0OԌ~A~,< |Ëp/c;hNXR밴Y;1c,Vl߁?̛[^c/7A~Bx%WYR:闿 w ^vWC7]A-8qgA.Tiy@:|MxEce]!x.CaZrÜm"?,8<3K 8Ã3#}v*aټq&|5/gjIc t/TFL&s˻MdQh{fq~ja~vI8d"?10:B@19̟.9s@}ceb~?ɉ12JoiT=z 7LN%gqF"P(p|h ?u~`џl?'015:1$\7̘|E{{w%q; y0>vzQ (N4&uBk0GI#%)~[pF<5+KSwD;1Zsu/|6cQ!ٻeg^zXNd9@P$UĝM]D_g=v4>`jwڮz]gkK86HkۆU:  ,88pvcEcdoS Z\qlCȚ?uvs11Jz ID~80њeskC$%Q~ULӟ;c9v| F8QGv9?8^$~֚ [q͕kqvc>G"aG?1 ] IMq6}]xYo6a4G䇚y~$0t&_M[}0ω'?( C]2a |w``ᏏzIDEXrN1wٟ#Ɍ|dL^9ט_?8ǟ s9u-|.WjY|5mEQ9N"KjfQ=OYJͱC?6lwynqtW WU8!ay>IМ%n7) `25 flj;4#?"vE_yduINMs8?ԛg8`ى2랏D^)ĸ\m.Un[ Jyx"V-}/bhoDh\49AH-k,%?.Ç_rWd(Dn8"?:[\Ȗb_އ 0UR@ .}_9›8)W ㏏+ys;;O=5k\4--Iuk\HIGhXm82͛122O cdOO4c0r*K.겿>?mx/osۆ5>ҟal"zWD ?3F$m "?IvNl[}0ϩA~\kVQ{{6>b1~z)iw߶7*BR}w1k7is MC8$:jlpbpJ ]^jWmJ{<~\2U[L];j2o7vzQnwc:!k7CX9@j]@('TL:<{=4]r]a?]P~^H?ZA>vMb|oЬwL4Vq6)Ue1G+- b{2D~8 ' 1)ǯVMqŕxKcvИ| gG7z{Wzw4yݿ}qR_Ӯ#|mmS~a㺫ಋ'cظ?>r^{Uh3zD0.S׉m+f9L%ViaXV6ZK;rd~J76󭿋u߻}zZ(egwm//:Ѵ,oawnGۯ1%Y۠eq $po+7WzU$Yyn4ߍYpZAW,RW?L`dlW_\ƫ+? JWB?poX҆_(r" ɳ!olRmO%-]s\n{-_B`,Η1Jla1ȏJc v=n"?yncY|O-o݁L&K/1'nv>:d2 1IS3ĕ㕷l4'rgߤ~S҉bn>֖ EKs.'I씭>Cq|LJqyoĊKKE%}>$ϥQ_(T,/_]_<_4&E$p^+4VʈR;kN 4RF=|ރGf%>u& Oէ1<`FS_4ʐk؉ eC{- 'G5әK~8"IvNl[}0!?4϶˰e* &ǍOТ{!fgQa2qyا95,?~LGqz s? (>9AL`{Pɑ,X{]`1Q6T״_x6&4[4鏻$/×ޖE}1I9^9@8)k}k;X[K  _|eLMMtGT]XO~uE(N尰g֔e^ ~T vMin^ˡ~}#R㪪0W4h,YE7'n5ީx~LB;g_Q^6 SK'R`̘|ϓosdbK/ .˻Oӗ<3+.ykQ.ƉbpTnӶmxч7]~@By)caIS N?ڐ|5ʓ|/Â/7t^os71ao@iUbSUNV"?mȋ &v$2'%R:ّHy>JPF~"B +L"?L[A>|~mŦdG"x7k y4{ dhEi>BO+6~H0f֨ԋ܋IN$ )TR6qa8 0L3H:Zyͻ_R3IVcI+: o [LEG&>30zJB'#`Y󎣓,D&4RB>\.a%ZA,#?yKWrc[|nud"*@G .`v/ m&γm)E~Xk7H0+]ڄmjk& 0oJegHD wo_) c6b.qI>giK h*:r]:ND~86CmE?'ȈDף>rz",YgzZg%Ƨk<˷)kpH+ELhQ$)Va<-}"?cp|"?D2k `j {v"*@G~T8.;jEH Ǎ &|TFc`.gMX.8e̚Uj5  N\ "!dNkK TM҅M)92/8aR-c*մ%@  C._1~y^f _,`|EUGȏJ!9g)mxa eXD~HG YDWD~8/2ee0/O ,ľr2y9UEN;N䇚pR*3%:_RF$ayCGtCG2w6*X?Pd$Gr'N|R W}D~8/2eX%=Z D~Toy䇵ζ[g W"?lLɿ2D~Wi'"?`1tEȏ|"'V^{!"@j"?\B䇯L_10D~xזoQm30_3%:_(`1dWQ>,b(Zq>ɏ@ V6p]d r2r"~T| !S-[5>TgJu,!CͿJ;ՀSKgȏ(,u%E@ i `p_ .Qf{Mtoc`*Wam2׾ltoQm30_3%:_Mz0tQ>,b(ۊQWb[D~™"@j՟ef4 N;0%?,M}&Hw1f` agJu,!CͿJ;h/D~D9bD~D Zp23k{Sk &Z3I÷TD~(3%:_NYD("C_10+Ul[{߱|X/6,b(ۊQWb[D~DE_LXuIHnrZȏ/"?ʉS}zV2<9זoQ+%Cц'_l)ֱP5*TÙ Lȏ(,u%EG[p& BQ,W~D~x_` LC~X4ܒwڅ÷(hÓ/ϔ X(C䇚vJ'A(*ֻ$ʲtI%QĶPUdA~t@8QVRL,̙ƕn7D~jS}z]8|Sʚe|}_XB"?SG~pYDxcȻ$tI%QĶP5{K [m@Hա 7D~jS}z|=xj:l56DM.c"?:ʶbԕQl/-B|C 'fSUR< !#(Pӏ㈂O6,ߖ=e|}_XB"?SD3y>mx K1QY e[1Jlȏ(8vszĀ[m@Hin!(2ZT|?2qT'YJe|}_XB"?Sm7?`㱬Ϯȏ(,u%EG[F~Gv1Rя@81MAHaq?8B䇠D~jS}:wbv)#aOLI{pRن'_l)ֱP5*T;0|?ƾj_!IS}%Vci9CRⱯ_qڭPgJu,!CͿJ;Վ`zZX_ NJyCGtCGV"#-#YO~??)/T'!R |ZJqd,D~;0%?ƮCb~ 郟W>K䇢 O>S/c jUکvҾ/?O> /763Y"$b(ۊQWb[D~De$vnpu7ҧfJ$Gr$,w?3YI U?PK{Qߊw_EAGӛ} ?CAGGv4Է e|}_XB"?Smɏo!weϯ/+{4$I"?:ʶbԕQlO,??(_<*H>/>ߑ'AT5sg!꾯T,C S}zȡǾ{h>7>_PgJu,!CͿJ;#U韟8:??0 $b(ۊQWb[D~De$3󵗿g"ⅳe<~/~E~Ы/2?gxdh~W./_%qI䇿D~c`*O O^x{g'GUg\[1a>Qc_j;ivQrRG<4i+:3~&I2%QĶbHf愧|k/_~}=!:wē,@H8<;?3cË_KWmtdԒQX'#C~ Ji,ƧnMCʏNGw:['Asٶ u|"?@G3`|T~V';0ԭ9Gm硥i|!u5ΪO3鿡n]f!#J:l+F]mb_';vsƧnM6-GشqpYنdN N'쳇CO5Ј8A5Ǿp%Y^R?IK_4DOhYA@8uA@8uQކG}J}sJ_ӗBy)ca9ì: 5u;$ē0 QA@8uA@8uq'A"@N1™@}@© © "=N9 3N xq2I I SSG S? S? ©"@@ @ @ @ i"@@ @ @ @ i"@@ @ $@t ÉN:QA? S? S'LrQ*о:nD^4t4AK$`T06?cbqlztۮeoóz~rbS:Gٙ'=dpٕ,HWcyA+Ʒy)biȍ "ZljnE5Y6e2Feb̒,D@ ۔ 0JRe8v@#&Ғʅ&\.nj~m,LM-oǟFSn/*mG/lrKsUKe5agFױf մj zeφk^An4JtӾYb;"ApӮy]_F6Id[nߑ\  w\Xg$ rz٨FF~\7 Qn*` #_Xvxr3=J=a%+ˮ,fARs׍o@7}-=O,@1T.0e|t9̚ ӷzYx{ޅh(CDTuuU S׍r6 9*ǥnU3uXNcxTcoǫ^eϺ E |5Xkw<:o57صE<T ITF]C|ܾE1/&wYDeThs7&*ʱksLcGt-h߼=AH ,7| 'w'11K^(1;c&ÕoA?*s~w2[d2ʝYҡh(<9#&Ғʅ&\.'ٰe+cO>_| c]]Uu腜MB{iq;lUL:,Xzt>GúukcD*4\n"AnD}WW }ע~m;J U?P9c'<5>9;:; #0f{;\`Ξ^cH腜MB{iq;lUL:,Xzt݂/zM((?\* N;1K$wU| 7m1F"@ ԝu9;wvxwg11K^(1;c&Õs~1$[-#AHK*Zr2rD~@b>\`új7R|K^u=1DD*mG/lrKsUKe5agFױfҋ+>~oHn%#DHc*$*. nUiDtݰ"́K7ȏrbSaL3=0f"?\1o^p.ճʛ`JB&..G$6}[ʟVퟗ]~)PUnIq/U9.u#xx]rÛK/ ij3n 21K$wU| -.xREXgrD΃?pYZrGٙ31gה}: *hVPrD~D Q#߾:Tef!"*UWUip=u8z!g^r\*F[U=S747K5^4wƍt^Y"AvcmH華 A6t KX:|'pgsΎ>AG`vxr3=JpGY_-L.( f2JŘ%j+XV2˓;b"-\ha"ȅ˨r o2R4#D!"*UWUip=u8z!g^r\*F[U=S747K5^4㷣 Qo#He9 n;T{= U3L<}11K!c"?N6_\`/4䈉r ..G$6}Ќ@@cz &|㯪9.Ct=eEAk) 9\RY7Bwتꙺu,1YDQNDTCLpL2 ]6?Ih׷UR8;9OΎ>i`!L3=0f"?\1olJ AHK*Zr2rD~@b>\`W S=EY)J[ 9\RY7Bwتꙺ1ӄXnE$H%=($*. nUiS|$ Vt0Aރclo,- b[$2e|t@:({lRPuU S׍r6 9*ǥnU3ucg\`W cn4ʞ"T]Uu腜MB{iq;lULݘ$~Mu p 6'fZ;O #0f{;Rѭ言ȏ`)Cv0I$D,͉!DpYZa!Lv#BR1fI cU䎘HK*Zr2rD~@b>\`W cn4ʞ"T]Uu腜MB{i且j\e|<& M$Ĉ9AH- "?>ccCXD~ #sQ*,P[rL YiIB A.\F]HG lX d̀FU3"?:^:GcE% + QՓي"?B M$Ĉ9AHN"?>ccCXǒa\,̳ʶ1J'#DΟ_Nr ..G$6}2f@@u腜MB{i}^ujKبVƠD~D-  p 6?CIBAH "?>ccCXǂt2I> #] ]FCm1*PfyrrGL% -Lpu9"? 1].a+17TݍJ[ 9\^O>[bb_f5K~&::k/:|&DXbD  #_Xvxrؓ^ 3m"Sx5?D~W#?YjP!#P&\L3UһnX{J2VL$91(n &[.a+17TݍJ[ 9\f'l$F0&W4CgW*ݔHJ: js"A 5sֱ8R356ul,"$ #WA82e,9f$_J(Oɘ؛k+D&drƈ.ذȘZCT Fu腜MXt=˯?Q^ܣ=D>#F<`How=T| "A, #B #0f{;$fF!Yٗ&? #P&q,W*񛠒}%V6iħ6Bd")ȸLF('or o_)" [Vip=u8z!g]+#?r}T,>hB*`4aH$J%\7{ ȏH0O0#mekz1M9SǼ )]0aWjǾ,'9hnLcyoډ9AT?n3=nL; , &Q5 KZn;ՏJmW`m;v1x3f;6փ)>vD}PmR 0Ǧ-94po꘱6Q{bfoY9/ k@{ ҇ytHWӓ`/2Bu,ob4 %#H&>N7J`Td\DFt@ܔDJA-Un g #?̑b 3(=0cLaq.HT ӸqkmmmvU!A֋hH"A js]3Hq=2A$  d1aG>՟H%uUF{81۶%(b'N0UWg;TEk/O9ub+iL~8+.&C~?+r~>+oy\mޏ@:1*VFSL\rߞdrƈ.ذ` 2WJA-Un ''?PBbd [1܃q+29t&P L,hӣݫ&!ztC,ndY!$Ȫ&\jd/A]M>jbw r;$A 5p&ގF~,NN/9\_,dCǮn0;5 /ŶNt4&LhR >bQ/7*Ɨ"/i8<5=tK~^\D~31T.02/ڢ78toTGX9[7|m3[O]e>Zd58r츑%iD4?zKVXe9W?].ad̀^* [Vip=u8z!g]Oם8y49,RۻLŲnk*vTwvf~ yg]&4lp]SLL zt= "Ht] :<\4 B$J 5p&ގF~p :]=]bf$"$u~텿ܖhEC'q/sXʠUכoDřDKcvn/pD22^s+ox-:;;w7R|@1?7$'IW4r 2~"#\`Â)ȘDU.*UVzqB&,ׯor,&'1:8 :q|`uޤI&+F(uRq|K"R4vشd "&>LGUtYg9zjH$ aʸ~ܮ :Lc'. B:+0511{!r_GbYG_1'W\n/d Ӄӧ R s/e1o.|3kyQFGpjH #P&\K~rKZ;~&8oz+t"c,ZO+huWGn=v_g|=&Sdrƈ.ذ` 2f@/QJA-Un 'N><#8v쨑6[(a:o.|o]J'Ḁ=SB>czXo:QH4+\¿Qq|v+ o-S0cGYjmM_) b;Zsuv_Ӂ3/x*,jRuk!tbap% PN6}n÷px-ޘ24ywS'Cr$$1E22^򃣘//y7sr~ېN/Pη2,qvE7]u8>w#t.'216,KTԃQ) S׍r6a~BYh`[K;Zes{Gsyt*j>\_gKOczΧDHf$'?n?_P?D8}!䤃^םȏ?'a$/NWJ@Qٞ.4twe"pxu眳<9R) m Vw>:10OD~ܮ"l_%(MN.#"?P!ualۺ% CK#ݱ]^_seb|0&'v[/\Od2B9ycD lX0s3+`Bu腜MXt=_N"Ob{. SW`^ՄRyvB.ƃ\tT2Pȏ`=5ݘuh@87uzS8ێ_{~TNÈY֫~)hH?/D~xc6N>-}m QY9Θ^ds%_2.V-7aaJu|LWh(<9#&Ғʅ&\FN~7/;L$]Gl*aKJӊ-c8TFID"?"+E1VzqB&,ܯ\ Mͭ6inɏɗ[wQw%WZnaL~ڐڋy5u h$߷>)FPL2톁q~y c'eU 0o!(mu˛67i^ 9olq R,at&cy.[ٹMG 9#&Ғʅ&\&{=Fw%l"dؾʱktt}p'QIwhUn 'Ipj ۀ&lneCfحNSӍYR?D@[hT"A՗]@$H%Pm+05s8|g'&ғ J>W=M4liuriO.rbeD~ܮ/e''wDZRD 6Xgi! MƧF{T9yTn*F]]jfh(-9'MMǓ/Fea2B9ycD lX dF ckbH *mG/l¢UJoozzY;)4/̢-3osGqeGK(N>'L&'ƐV4!8Q—zttv7m.?ylټN`}xɧ+DCٷdrƈ.ذȘJEwUZRv&h-%8z!g]OW&9R2FCuww|8^#SI:9;:s _oJu-D~q;) X7ħ8 rQ'q%d969D~@LPrl[Uy7ׄ??$|Vf3& .#뉛.po{b/e''wDZRD q̿7_)O1ާyRɎ֖VKKK:.4[ _7? $+%w^QwUZRv&h-%8z!g]OW,ʨ!bm[osro/cY[\e`iۉ,"#ȏ@u0D{ v$?  k$ V`ܸimx7L&?ƼHd onٍG{#?P~UI~ +0{˯8ګyJ|m D~CNr cY3ױq<2%!159F_.=CЈa͚;mBS(MdyR9۰Q'c9DyVȏr̽` Ԓ3Ak) 9zrAx_{1 D"?*ZY毮fPYW٘]V=>_oU,Wh"?uuڭ@$Bb,{mGV Ok$ `"? YZ-+|Ā~1s`Ɍl^{s<ϵ ($EYA̐&Lu3>zH;|Xqɏ8m_&_,ONr\W;~Xj&|sA|UGy,07y] Xj^X}^G:q0qt]Ft@ lp9 VxjIٙt腜MXt=_ n.bAJ|,d&JatÛq,׎;5t"KКcGpq=6nHxhw֢RMDr;O$$3V a_ X^ rAH !˜ْIPT=|ωl97 V`R)|*vQ`})ŭ<[ ]pok.^e2U䎘HK*Zr2%Vrq2c~>}_~#=gŒ0==k.cx]X1:2 ), HhmӁx]x! iqb sO?_c~q5*+x+y#\`W cn4s0[%eRҍr6YA%?,Xs~8!">*NrƳK/ g=mY}-xko}aQKdJ+/kiF QJ?QU z>I7n=rQ)#  B:c^sl:g&i׸fi.Akԟ0'/M憇on2>ktSoJ'TW`Jłf ec Oֶ.vc_A)/'wDZRD kɎ #~e_6ٙ)z_!߅,=s?vt:^1 yw?mވ݂'z W\q9#A+5]]W/Z&]16}2f`1SZR)h-%8z!gT-~Ƃ^;\\| @JX}8_u&l۶rSyS"?uu#H=x|$?>b-# B:N arlg~3'$?,\vk0Mڦu08q`4e=rcԱ,f"?ǨϮz Â䎘HK*Zr2R9Gttu-.]>i>_0F~٥<|98r׬AKkHhmmC?tګ O?]w}-#.]|Ow^;nB;axm׾I~ܪ/2BxlA{};eThs߱IdJmr"@j"? =i,pP_${N,NMKcf|XBZ6O'PuM훑Y*z%'Į}f]>Q/dYX gƗ;b"-\ha"ȅ˨1u暫VNx,$Cqlh F:9B0Rmpqdx8bclvګ'V4J016}2f`1N@Ӌ"SKʦG/l^A\RYׯgdkdS޻|| RK|L/l)h'#XGM7ft bN]LJ"*. nUis"AN8ZwbpwW$@+0v儥i&'ƫ;9<ԂcN ٙ\}yZjNgCyd wzLw_FB}{U\ʷ&t :&ý=t9<'MT:sqwv=7mA[s~V/?h;>"ggI,L&\`W cn6jsP[% ZKI7 q.# ׫b3W3ֺ_r G6CN*b˺Mt:ȏ@5ݸ=j@[Ո-s6IHgŇtLxa\/ј.5>%cBco}F\X Fp^D~nT[o@ ivr Դ f`Ʉt4})x14eu ?tSf->Id@6D Q+ x7`ú5Xۃ.$|"SC3KKK8^?.W M-8~|m-ƫ5(V45](y|CG~ߟ 7Ft@ lp9aKO-)n=^A\]G^Αy+4b^z;Ca5xT#Ii}"?utLK??@$_H;sp~%S lj YQR W`jŏM䇯>[邘TjԘƯ݉~e ҐM0 w4Yd{!W{kRC/'b"?ԎH}S`U䎘HK*Zr2*r|/2/%]5Q_WLK5Fӯ2=3mE2ZAB7 ׉M~u:Lk׬ƥ_7+5-m@9ycD lX dF cj+d@ZTp^\p^}tfݺdh:g|I@2ȏ@5*LϵF%^|׎۷m:1G@ M%nw^Pp Θ /#|m. i]Q}x;s^!TDD~@`WuB8?n4ƥ1c^%e{lLxs{.rms!  j L4pU9N74c$dD Ky$ @¢ܼNXlhh}?iyXLl@ lp9aK D~U@'dxKq27z?`|yD~VgVL xk 4'H"AV  n 'w]' mcizKv6ꓕs a1_p>Y]: 2g>r·#Sc"? 䇿D@1T.0e߯Dx\aőHT:BYD9 b(k%L0B9ycD l؀z5\w޵UD~U@- ޹9䇃Lld21YA: bj,h^^78d"!ؔa"Aî> "@jgpv>"? @~☹DC3ӇCa-}-:j RDc]Ҿ-@ }M=N"Йݎ{D~8c g9)V2˓;b"-\ha"ȅ˨1ܜ/w~~ВZI1^o8GXOtzˬyğdb6}2f`1N@ӻ6,D~U ?WioSz nZTp7^4]O/pZɔ{nDaWTDDDD~=ybN*xqhADxy{pnA~ӚN/+]YAu6J1)\11Z*43iIB A.\F]"J;?G`zj BԉZs2h ]1/^9XeܐI9;2\V -ذȘ.;MPh*BZJ .N4i[)ze [zIY)_\ bj,h^SOM78d F$k/o;$so[$HHj$FvsBU|Bú-̡EK}304%SMidRf Eļ =}kmyѦُu+HQ b&#_ ̵ ͌/'wDZRD Qs:LbjnOM hjl_Z09'',V ih_=G_(8{zգΜtwDMLMM_1d~~(zYYI,L&\`W cn6js4kڪ&=MW=^AeT؉&?Tp=!Wk>d6 R&?]3K5"mdz&Ye :L~1[^;auc IkV:L9&8OamOw݈ST?*mk_!T4p^01k [ (d&=㮽)F]y> eyIn)iU l(vuXyJ\D~Z, UCI 0T.0e?557LṃOGwiT:_iƲu647 %{U%*橱mntwuDKm7JR?1]ط(ǧC1m.9qc0oZb6}2f`1N@ӻ6AӔc9$ u[+ËV/[U^kW` ,.dhGn\=~5Ozw)AtMS4g#AuS!Ah$ʱIdJ#AU $Az247A_|9c-4'\hxݭi$Py|>0>wmE]}Xr D&7 ,(UCI 0T.0e|FsK3;:ݷ  \O16}2f`1N@ӻ6AӔc9$ u{R {͋GWOb"Aet]DZ7$H6'{9mN>2щ+[rg\ִ.W;5^Red8F:`Oxi<(fa1fؗݍfOfۦ{gha/9K3S8K1ex`g3`"-\ha"ȅ˨ #:֮YaD"4}/7x3qѹgddEc$s-qvm ףaZc6֭]kqK''or o_بr̽ج `K*R2GW87"j5H k[py fxj @\vJNjUDupZ)Bol -:夓 auC$H`O4 B:h.uCiTɪtKqÞc][7lagОGJ@1@ƫxNVi #3C\:$8=ء]d^E2P._3ND~8# ̵lFcRL% -Lpu9?a-\.7xKnS~t:&ڊ!~;q3030^caXQ8l M8{9(m/&&?t&㸴`6;].a+175\w޵lI"CӔ c9$ Z #*24$sŝ#@rDtvj*>.dUPRK5"=QYcz1zP b꬘9AJq^)>u#OQۮ!T4& m}f,іu񟣯žg %6K:q_];j4g>4"De.>(5x|M;<#?:Cs;F̈_l# M.\F].kO>:93u^~-dss3rz<~ O2WC'<%օs."gwhnis4l>0o\`W cn6js4+K;r@E~pl|m=nZYޔC:1./[*})*=QY3QU[ 0C$J AmJo㴹>A$=mN:G{/13w;I0+Jh4i73%tAFq5(r{}^b%N f\D~8c(2p/(Ǥ1hr2r M-o/֭cGO?V޻~ǘ g O 5Wy睇5kp!|+-P] 6}2f`1NH"d̿.D~ʫ/Ci?؊`>O7`bec_q θ,GOM78d֫FDM{b "AI$ȲۼV$  C%fgzP̥؂N4I .sTXgXݿJ'c%ӕZ'*7!T.a+175\wB%c`+PC5 OⷞЖM~XˡTJH?D~,G/~?"+ Dk B>+05v题5͕5t (dV /fKY/C-wv\~*$M, ƘbccJL )? )$~- L3c 4mVլ^V]ZVҶ{9Sr3wVc_s;uμӜȁ0?`h~C)tBg'2W&npW~DmZZZqKWG>L9&xشi3֬YZfjlܰ= Lm>cvǒku-a5vځMOjl' af" ,bU;j-~8z(X݃_mZ!̳S)&Z&xZU#EqʙNbW; 8 T)x"73b&??UqYy;Lvyд)' eqUe<=NÐ+@ŏr:O6FTWH1Ovm 4_!`Ӆz3S('%Je.ŏh6Sdm'~8@)*rKk'DG.^m۶/D{{;þ}{rJuT/aص{\[*qs|("alz|6~R;f;_0 +5a+/'S>p?v{z{N|wM;"kZ \E*ŏp+8ʙo^ +A2:W+@ŏh2-z:>pp~sZEuX ɌاIcOUdVl2QO?s6s ж WZ+@ŏڼ%;yuFD/{'Qx;wFхG1 g?#cMu/C3Kemf?&~DG$6i[m KolcoW^bp1xOnx^R.cFFsK Z[V;Ht܉+Wb)WxWDhB bJiLvځMOjl' af" ,bjb 5"ߘ;Hrԉ?Bs?t#tC<3gY}J?;_<37*#W|EgH\ dW'JRs( uCfmºhn3ze!vڐrP߂Qa(D2_H'aa66v? yJڲe3=wlܸ=}<Ӧm‡!FW-ڽhij¼yzDeHtGe"Laa*lvPv"`Vhk& "z(Pc!Bߚ;,}O C^݃GVqLyیy^~NƊȚh|W3E Z+^x'$|(Pc P?j+~X' rܙwbcn靖 6 㬶uXuqb#.:|HVl\„67 ! b PIG1es#bL6@ggߕD ijjgUWK/˱{n|+@6L5عfϞ &J;x:Q,s8>_?~9"xf3?245aKT kAo׾N!~Wh~T#(CDrF3?;_<37jLGD; >"H ePI NBjzWm,WHGŀF)>ڙWaY9Y -߅C+э_Á8؅]xa?[!2.4i|C?dMV 3 PT?ņ<|EX`>y)FfQH¾wr1]s#xйiYz|vf{'~G2.vR8e 3_s?9Z6>5bE6'p$qaX-IkD 7Rk}rI}} O;X?jB]࠻Ώ}gB"kuJ?;_<37d0)sAiE$ ;eSAH͡R;XSIG4EBXˍYGԘ{E_ڙ^$+嵼XN%D'Ye rV2Yz|vf{/~;6"Q.z#ȳ{v??hn?ڒ'U^;銪dN;UID|0LE,;ֈb 5of[?iii[_~^{&}pb̘Ѹ«tUUj桨!5?<*GP)'D˦ # 2+iN/PWԽcT"alc/OэZtc^$,DJ'6^4GR79Y^DV Uf"Kolcowď]I;'s7ztvͭcy]fyAH#00C;i(Pc8Ao-渽}l#\ۧx+r_'3k)$k~vy(jgnHmŏ{\"E?EXΝd8@Btgw/o8uaډ 6Z |ӅH:/u DdecGѯ0H?r@D&nh!ބW2[њ0J np|F9{05i6= ?T/ښ􂰈qvQpBZq{_>9GR|.-+ON:g2K?sC"~D]S)N.OSվB8 > T%)_$אگJ7JcOUd*$O7Al1W m|˜;:Zy:$bHR+$ڟC()b!ZQB֯P>Hp"iE~K"iE~Yh'\v*m œ2XyɝdE*Nolco7ď]xcu)T2#v0=+e*lvPv"`Vhk& "I[?}T"3be}*6Yy5ѺZfZRu"H'?Aq?#S!H=PLpALXIu=7K(苬>w6bi$Dxe @#6vf{+~I"" q<Ɏgc*lvPv"`Vhk& "ŏiotGSoZagnHo2EO(D ~)CNP@?bW]TNϏhՕNDPm>2}LCXy<766v$<;\j *uvY(kB~;Wa'jðB[3^4Q_?7G+Hu͕IpN_$(~R_A>31a"9@$_%u?QGgWuDҎ\}2( [t`?tmNXTogmٙmNM#[`MvځMOjl' af" ,bia9RPkQ I=#^_hE|jᛋh qxPS!C:c@Cg~! KY}C9)T(Iť79Vޠŏov3Q@FvځMOjl' af" ,bia)MEs(׮Q ">lo{^R$^kͶg站~憈{ 2~)}C$gc>RDRk( ALXW~oi EX#u;MA?tmY'r!tYNolcoGi6= ?T/ښ􂰈qq'F7Rk3/};ŏ3?rizsCN:K{Ab>31"9@ŏ &,BQwuy^t͡a˷Dp 2bcW@63@(RYvz|vf{;N;UID|0LE,;#=1D1w[yikSE 68JchDUj桨!'R8SB__ u⇢|EY|>vm6Q@FvځMOj54FK mƑʞU"ߘ;Hͼo(~{ۋY<bm+nU~vy(jgnI?wdPN8~OE | z( :DuWG#~u"Hb |vf{;N;UID|0LE,;#=1D1w[yik"~hBתlk~vy(jgn?T q /[ݟ8A"#D!5HC4_Qwuy?Z'D}Tx&ގ2lz|6~R;f;_0 +5aKHeO*of^Zڷ/Ͷg站~憈0U.}JEJ8~OE | $?@ŏ|EQGjP9?Bgmٙm(~ #|~;Wa'jðB[3^40VFBKk_R֘|5Pܐ.~& B$OdCNPP+.G?R넢dv`㫰A5ۉaXH/XwG*{bzFc 6׾e?~|m5f?;_<37d(Aq"SA$"H1'HczV z;ddaZ#~cWrc}hzG#"+Khmٙm톖!Oᮜу-9D|0LE,;#=,j>4ETB(-t/obVgm0ŏxl 8OEdq5ӦPlOd(R(~ B.97NGAD(ۄ1%me{M?pgZ'HC?ϛ2߾*\6rED;}*x IjT~[:N_U$S5wxs'Md(V͘s06CP@1^wuysRS>r\X,`gk6{7zg~JXs/^y,:r;\!E8 ߢd}@?"!YYBklco7tďI'Cw0~|9;rwe' LSK "k_?WO~ Ɉ*lvPv"`Vhk& "Ƒʞ@@SL)~Tp 7g9-_nJ־Zoŏh( ѲmE[ϙW;@R/[f!*8uAb߁r~||_ȹ`@A@Hݠ<b?<גּqMX}Zcyg-;hoeRXLpqp o}Bc3<at" ›hoحO)"k, wyxuBf(Uȿduvf{#~HQ񍷿,~ݻ~΀G(EKFEﶸȽp.%7۪V+"e;2=aUc*D|0P̼Xf;arWFH۩k-U_)~$wSg#O> o{pAsCQI$ZIiokٓF{y;a\7kd>AZ+D{"1dBr:~|N$M~~"9@ŏdE̜;?Z̟| ކt63GbGwW(w'g3(?vw]kpoW+Νl on( gYS0=ڃGVm9+=l\y#[g6G:ƪX^4 Ιs8_ qi9-oOo;o-ކ@Qq| ="o2Ynޢ;pu~~&|oӵ=f~ghnjwݳWGx*zK%77ym؈1G㵷^|!&NGa5O]qeoo> WzΙ}X_q_Mxe}wamX|k™s{8xw/Ïju[G+pg kV3Nhkbcq5KCp4| b;נ{a68y[ӦcPҰrQXN!fsFKoi',Qaoŏt} ^Mg{2uK@[c>m޺/3fT#sٸa4ewۉGE~oxs&|u^3*?{xk^Yc۰Ptϣrx³px 𣵛1t;/N]w_q=Sï%V}S/< os+Ș歸=(#ARsHMR(~.R0uq#sL߹MM( ǮW6]qsf/F@JEl,~Ew[ fi-C+lJ~ow V.]|93<擏7_3&Vbۂל?>Yt~kM*F5𒳧YW?]CJv Dd:;|)J86S'c鳰c7]ߏwC+`v=V\|Bu ?}5!MRȶESL)~dVވ&"'cXo)8vT\䣞PczOxwblل3^|SvJhspvw-pvYMAHDѨقEMgMv9_݅?x/{9} I;c1.7ִ͸r$|>8hz'cԈݞ NOpi*JY3}w_zp/Zi(vQŢ!}8Zޞ#cΘO^{e<渱xׅ㌱coJ BjS/Dt?G<(Ś Q/Go?,=ewJ=(q +tǷ^?vfi+ΜQ>0*SE͛~n轋Ϛ479MdgpG?^s"O~;poX8,~sx']q/_|\g̨9ގhh7oFA]33l6vCK|W-3ÿ{qoYs@]?Α@ŞE xy&<;!?ysYxg?~[6?{pVDkk3-h,^,p?ĊyyoQlR'?KW$%Xt7}x5WA?ĆTm4V50+#ԵىTWZoNl_v u#Yɳ{GQ'O]=Dï};?T *3yGݣs ݙ8Uď׿'_ 4==)~XvޛHxAt>B7>sfj(v'zK5&'帷=,~߅/<<| N+_`վNoLwVJ#۵`r˦M/jPE;{_>gw򎮣#/Dz=s>n;tLuWSH.~jJϛ Ѳ+ŗvN-thi(ZWݦ71\ޗوyXnjk,,jюݧ/ 8wX=փ-M{SZG)^*^wؿlC]>>w]p\4շW9z<>;vEM/gݿewBQvՏo;:}`D/h7cI'Lj:P٧O;Y':-cf/lO Oq]"ѾiaF?[57Š[1>Iiv"FǑfy ‹>[$>[yiV7dqqxonI-EqTްZWS2BBL[ؙm>EpSOc{Gbr%ca{G>СN?^|V>W\vkعcwUaf9wngxnZA>բx\3+ ㋟Q5Stvv߂믬Gg6\\ )~X }vZyJ3N@a,8WpsA+M^3&LߟYTiΙ(lۂc(#ƍgaQ:lX4 맔ArS'W,݉7 MolsA1xE$BT^F`'fϞw'3b tI A RS( to*1Y}Gok6aF݈8{:|mYn[aQuZbyq z'N<"zp q~#y'b{]>e7^){Wk\wU_yIŎ@z@9vL7ZXvSR&FcPP 2BN]kȎW5(? 3i*Y/gycI|ăg-?Ci}݇;R^Pw©q׷Y{e-qf̻"uz!n>ӿT>y+L*6'*W\w=.:9tRCf G"?d|Wyy__Dee:mE `OW7Ǵaqq\rebɎʙ)}"{ ժM˽XԽn$Hmp*J Kv>c[q攱6Yhqx!,ڼ;:b ~ ~yˎqGyp,+ vf{/~ȱ>xp^Ypwnݎձ w2}Z;477{vʷW`\qٕ_X0\ލVW{j]]<354瑔bWqtYA$FcPP 2BN]k0Uޙ]<剄mp]_ ʙmcĘ]=ǎsPFtC||ED1 6G9 #E(do>g*z=8psUkbs57SЍ;?PT{^RwW gM"hqc^6}w}Fȶ=^ C- w[=+4m妭ӧo E+>DoiAa/~_m9n{o\3q̩xY+ok=9m?)`RS#^tTaz,ȳ-G6_:o6>s&3N7b/Û/9_+"~֏9} Yxadۿ[{ڄ65ҌcGKod#Vylaag;5y%?zgd\~E|u|ED.[[v_uWrPgUM/w|>.)jPǎA>X^oiijl3K׿'8qZ[Z7܎5|?>ZWx([TPP 2BN]k^CZ]{_:kw6{tDW\v.K[~3vlşw#[=C@Ce8Ӄq˶NKKfM5+Qk?sG@v$_ }oc Rj'gV_n>ۿES^ ߯9|˦<Ʋ]oċG9HxHfiqql+ >!;:qMWz{K7Y5a >b6OnS(f1t^pT̝<~'dnYlm=V[:Dyt>,@Ym6HI5ȿdlcowj!~x{=U_oܚ3C xE5Y{6y8U'yp~_O.\K.>/WSo|X6oنbs-):]+ޏ]U+_][tlG޻OW(z,'(}+|4|?bќn^]JO+uk#Wp+v%Nxp%u3hU߈ZYlg=G5 :Al&7ſrcっgn!mx󅧣m'1 w F_>]],(~j#pT='ǝcp~׷xx]?R U HT_ߵy />򶘟-ی"sAZ?z*|X0?Fzt~(9ŏ\m0ȿdlcowj2 Xl9>y{*cx~&_?)W{(?_C蓋q>H|!v]]xx?u7zeK/~x;V$S@r3⇭f%ѢaWh藿G8⽒V?\ 3hnF\ݓo ps YinW8?ѻͦW\ +Ah onGiuL4ժ]oD̽~ʋ] rS?%O8FǢgKvW|ȇv>XKBOn?ڎX͚-^95ny"R ^}=w{2p_,PE~?>%w[wc爔z26u oo+'HMͮ1z- cFwWsgû+g+yOFUܹ6GY:z-FJ7B;ŏJ^- (1pqog~+U# 2/iCY"cs[IG(7ϔ 6r)UdLYW4?7+de EY׆W(z<.xuWxr=Ab abe2 2BN]kmVĎ\Ouį@pni iTS=Xj ۀG_2查ʿN 'q)&8 T[q"6>N"n>:Tm bY[p~U{XIm8k]u\8yѣ;a{r9u:`X>Ջ{2Q"M|r+pȇ:AZ7i&67B#GqŌI^:㠻} hom1w]~drgi챣ƑWO?cZrE-\$EA\G&?[5%KʠZN3|J0E7to^`-~@%K|e-~{/WʃPer5نQn50op&y& 1!O*z )YKxgeZU~2L;lZA1aNѯ|*ڊ^=Pm`7?"!/"o23۝⇿E^c"\OTުص`F{;?*$`lB`!> )\8sq7yb'!+NmCxHI~jA 4u /EvN⇭ VJ ? Ew]*BGRP}"E}ZO664ۀ`pP|7a6gcljhew{| W0.fnĎ~Xڭ{2 A+C?)WZ+G:;h_ Mn|mR?d-;x;M~;fP_!"D*)|!T/'B>)hT~Byc"3PHaRrS?M\s]_r+nAQro FOVN% ;+WGC"ek;uŏ'r-h~K/-5cYTx)~"RV])eS~uSXH{yU"H˂>o?lC֮ʕB(-t/Ͷgm@cpHRK$= Bw@ĉO@?+e$<ٟ8Tġ&??#Cj:@ŏ؁|d$?eHYXt+Nȉǒ9D6ȉ>/7z9NdÚ苠U-c'R4o(~Df;v-6v.9Nl%+2O==,ob\Atz3QۄAA0g?B(-t/Ͷgm@d"HMSI'(|"=@AdOWf2E~Ym<(@<mM+#\ke*DV0 ?#&b܅;C7]B|bmf9 Q2#rMOjl' af" ,bia쉡acݟP+Bתlk~vy(jgnȰ?RTNo?"6Pr)#6Y"}PG$Vq@զ vl%ݦ&NPNH_&VQ#<ٟ8TI'ٟoе c_76>BD7> Vm?25"+[mFuoqE/s0-WTmvPv"`Vhk& "Ƒʞ6v),l2}m極}?~|m5f?;_<37d(>DԆ"(PBjzAjPM.; f(8g~h#rMOjl' af" ,bia쉡acݟ&f^ZڗOCf[cCQk?sCN5).`k/6/M|D$Z6E"( u"AjPŏ (~(*P Mv6?z?T/ښ􂰈qq'"]v |šu ]k1j桨!#BCD6a"eS) r%P Vm?[5PP8 U(t&m*6~R;f;_0 +5aKHeO E6CCVf[cCQk?sCN]yt[Dm("EH|"=@}~bHm?@G*&6Y6JFWemSA5ۉaXH/XwG*{b(Beɇ]Zе*|6fZ2R"mاM_Bj :BxEjyU ?BJ(݄ɦjlN mDzAXҸ8RC.?M>P:U֘|5Pܐ%~PU6Ѳ)AH-R'(~Ph=Tmo^QٗB&L6UeTmvPv"`Vhk& "Ƒʞ6v),la)t/Ͷg站~憌HJ:Tm bgD˦/X uC69U G %ndS]MOjl' af" ,bia쉡acݟ¦P:U֘|5Pܐ)~BPU:Ѳ)AH-RG(~ ޶t_Dm&#b JXQ@Fv6?z?T/ښ􂰈qq'"]v u ]k1j桨!#ZPQU<Ѳ)A`R'(~ ޶t_Dm?Rv6ͲQe4*lN mDzAXҸ8RC.?MDoZе*|6fZ2(&)U) qFBj:@"hP?".vWŽ2˶ID|0LE,;#=1!lSXTL6yu ]k1j桨!#]ǥ"q@զ v"Hv dP$RʛWli?hH?J%!P Mv6?z?9vv"`Vhk& "Ƒʞ6v),l*&As gZе*|6fZ2\\ħ"q@զ vw"Hv 'H<[i+m*_)~P#I=C_oo*P Mv6?z?9vv"`Vhk& "Ƒʞ6v),l*&xBY?~|m5f?;_<37dC!'ʡ"q@զ v"Hva. t=@j~2FWJ?(~T&~x[ہ⮣Gb9?Ml˶́ðB[3^40TPOaaS1;p ++(~lk~vy(jgnp?$7oA9EAD$ZǁMAX?ĉO/B_>FWnpi?h??{W 쫔,.ۦGo'3N mDzAXҸ8RC.?M$mMEk6cnS^'R>EDJCcv=8N&A6`D#~@domSag' af" ,bia쉡acݟ¦b9|zҶ[q%K/Ͷg站~憌~۶{imaéJ=(D\8P)t8) ?DVw2EBP(`O~Rf  K]MOf/ښ􂰈qq'"]v IFYn۫Z?w0//V}B(-t/Ͷg站~憌c``wZ?|ZwR ":Tm b9ݦ&N| !?O uc7VB)~P#X,||G^U zvdomSag' af" ,bia쉡acݟ¦bmӱmKꏼȫ@>k1j桨!#E|_(_y/EJ6LR6cnS^'R>ED $N"bi>}?ރwɿ GzCJ##]X?MDÇy-?irĂ2˶́ðB[3^40TPOaaS1ɶ۽kPsϭF=K}i}(~lk~^W3E I׿~'~j֣ JS/ }eedvFG88}YSv[Qv4d4ɮKIčs mRI @t8cẗq̓.[0OG=o];B<ٟ?C?{477cܤ<{"oʏP|*6@\YC13~@qďb vYppgw0ǂl(@qOD85DR QyBƉX:7mE4f4NtpXIkX(~۟栬XbxEj(~J<㟀صtP?uT^ gW6f `EM Y6,lbcehtUv6?z?9vv"`Vhk& "Ƒʞ6v),l*&jmǑÝ5]? ?n:J] mςg0~vy(jgnH?O?tW8Fyĸ٠2bET()hCZ9r8+~HNX;0]M  4\rub!wDThގ/ym 4D JZ88HS?AY2EG+ZU@jC>`NV` UyYlp?um4N'1hljt(Ƀ^OlrY6Fi ^]MOfډ0LE,;#=1!lSXTLs(ty9g,%7K/ܹs1q\S W3E ⇼Cwo޼˖-^u+Qcf™u0|ݣnAo/T$8"6=n:NNTe; Gdqq+qjS;vОnS^'Rd?V"Nr<ٟ8T̷}ĆM:Gױ=7ݽdWC3 "Qq4`f,)bM V?\G <\? p$dRTD u% *3 7a:JH^~2tIĭ$ 'V)ΉQ:JHup$d E@rW}_1!Øu=\? p$dBCd QB.\? p$ 5(B!B!dCB!B! B!BP!B!BȰ!B!B=@!B!2B!B!aB!B! {(B!B!dCB!B! B!BP!B!BȰ!B!B=@!B!2B!B!aB!B! {(B!B!dCB!B! B!BP!B!BȰ!B!B=@!B!2B!B!aB!B! {(B!B!dCB!B! B!BP!B!BȰ!B!B=@!B!2B!B!aB!B! { vB!B!C+͂WB!B!dCB!B! B!BP!B!BȰ!B!B=@B!B!ԃh.yB!B!E9T? B!B5$DXB!B!Rs^A1B!B#!EG {B!BFGZg-0 *Z!B!BH,5P,G?%!pqB!B!H@jEe"|Ռ3vGl-ju !B!BR+yyxYy)_ }}UB!B!H@j *m!JU sYFVB'>MB!B!QV 5 })]B&]nEB!B!H@jR3pkQM!B!B!\6 5@} PCE "lطoSG766^B!B!,Z[[wVz[n>EQ$ <HtA\BH={v=3ciӋA!B!?^|'|*`v#6䰹 D(z۵kcFuԃ\ !B!2hkk#"~?~csV\+DIIJٳIls՟ BA(B!B!)|477g~تUfwr rJHSʎIH1H3fg T*Q!B!BN!AP)|p˖ x*^m/[`B# 7 Iۼ"H!)4˿{uFx,&UB!B9yA[V |@-B!B!%BY.%ozщ5?$y0N1Q؇#P !B!BNR" ѴIEZ敷bL c(B!B!#K^ks?$MZ%$Ub%,2!B!BjNH %EFP Фs$[bLɺ}Qt%IuyB!B$K =jvGZWTiݭ/E!B!28E~֭0:C%v($JA|bD&I(B!B!GX~'kArC,=߬2LB!Bɏ jbքz !m#Ұ'B!Bs+L4-,ӥkFɱq IDATx\u7lzH#@J/ f_vAC {PBSI$>'23;KvvΜ2gΔ3;37/@PQf(3T* E`"0@E=eOȢk_";}i4 :'\Ѵ@4 [ )z+7 SJtmZ;, GWftEȥ3*4xL?:r;>*ґL%6s;z\Wfzs;2k5oMKz݂3oꭡܮZ3.TTrZ, GkoӚZa^ߚZ,Eg[ZrjhTm]M!\D/\ tu83_zC@+2 شu9ΨڲLUae:#:,л%|!No2=R97B43/L#LYf5љaLknzk緆0 7RӚ=N91S٥5]u,]YM+3e)G[) Ŵgv>PyLg-ԴQ%ўJU'wtZ{zv.iojZ[qhUo˴,N]񦦵fi֌eZ[W{*tvX֚ykTOl%,Ӗ5i|LWc:Lk1=1UUez5[{&ȴ7DԴv=-YUe|KVրIKRb:LkuHUg:im55Lj|jKKԺLhSi-zB`+ʴg~U+/Ҷ555:B:_W<:Ze&?\e)j3k2\+mR8&O[Sq&azk @G]Sm7MĚ ^tvUN+|)i) Rk @מHsZ!&@S[bdRy5㭝%;ѕUei*S- v#,GkC R2ŧ:鴹MkͼNehh2 3ŗ+59254RV/δfHcg֚밮gtfXJk3j2}.\4JmOKfH`&7T`Kq[ 4uښL K]aά&?-)qֶf*/&0RU-T`&\.7ԥNSPwYߎnss:iMU LrՙӾyCSaTt@іGm+B/yW EkLm+K)ueSsKv^tE0adrC1}JL/dB2-yjT= qM7-[.B/IMd2զtfřR㭝fXaRJ_Uɟ?~[SO]cƍ߯o>@YYfr%|g ì@L 4ŁM)qh33ɝooX<%SnzT[omҤ郞>$˗/x_z+80Y*j)Y5i|k[/LnTEӣ7gA=냪UT;~@̲L~`fUjmSJ7USkL9S2yQQfp__kʦn>}OTd#6pã򕯌{;XZ?#RѨKYRեeCӖJtVVNhX&W)J3!DS[~PY>ԓvmV^=STmbKMfjmNϗoizuF`=e 4)ʹ2TTy2t& hѢߏ5:"ͬJ  šR2 ̴4E}Rשja<ZK23*28K,=GX Cwҥr!CB$EqFqAJNILɚtc:LkZ1L?` e>xn߾}''2}OqƌwRFJ;| I:_k4ԝU\ebzTC>|ZIP!VZjjjʕ+6յ2-Tߞ _MP zviu#D&#LT7[َJ39UEӪR0mnvL7Ն)|SC.ӷ|߼@ ׾6>'-[-Z,YVXgecb})""@رL^l뮥魖K`L*q>wҗReIZkLKR{ǐ Z1 o >*@//^GT2dHVuzK\ZkVe+<͡6i/)>bmXԹZێPMK Mq&kw2 ,n\{@oًkaHM@T77]:L{1Lqe\uiLߥKo>B+W&`͊LÇO}tgXA|6(2.S\e&Lk4U]UfLg%vZʟ_*P *,@oa7xCXzc}z`\{ *3e 4Yjz:/mǔj2j=:6@/<M[䷧lFjeR3-Mo[ՎdJZ3}+_YТET*G70`_ǦFj>Rř.Ĵ3-;_瓟 zlٲ\ƾ ѧ>}I]. Ѵ50ӕIWZxqz>*U^ŹZI5Qʟ^jSt?;o>2QbժU b_}v #jV֥Қu XP?B=_UT] J e6X"3c uuuo߾пlӧ_d2<7x´:o֥!T?YiTG^!<SO=uVLP^fŵi kOn~rizh4cVj'з*?_qf~\*xy]0ც!}gh!˗gʕ+]6kr/ 0 zRx_V7x}q|ilkB6fu+FX6l31@/:jg}6e @[_R^]Xp5w,4L 9kCԤ\?ihd5}VuI# t,YS~-cֿ[oyiuVcEn(SlMܛ-j)DS%S6lf z.Vyu[a_IݸPX4oUu Ҵ~P؇+2JXw\ǚ6|M<[2ь\HU3EWf{#Z9/=Q]ʓ}h,3g[ԥ_߳(Q~VKwqrž4#>͟?[,qq]k3gՑhj->ڪ5k^O{nHU3ӫZ'@/;'.Z5+VasKekC+-Ow~ Gӱo-_,N\зof4|*.^S~_1}{o:SU^~t뭷{/͞=~M;vl0&M[w}҄ Y W%|OD+ɉmӧO0`@&Cg%ZZW-{gU+WT%7)q 1>,Ԭ;eeڴ׿[S{t駥C6; mxJj-sI@y3fL=|袟;U3tbTW^_fԥi^ _~zҨDe2*?o͟??D#FHuF͔UW߽$ѓa囧u%NsC*ϟijbҒ3TrZ<;",ٰL;Ju:|O}; _Jz' ms/EϯDÏdܣGwOrwK74yI싧Yb&:ۥ^;kz8xM{/X>:sS߾JPޭɓJ{H$aK:{GgfWpÍM7ݜN>^yկ~#.V5=|xjtm75z74vک#HkR6s^{֔ou⯉T ?xjM7$ ><-Xp᢬OL%Jw܉8[iҤZ?f+VԤ/[A`欳.h]s/} QXf 7L,(Sl 6Ȇc9: }O/RX\ϥ n/M3gL>? PFr{~z {o|om{NP !,:tKE&6=gX@Ey{ ~/('QÎʆ/~/nۂeLz#G5"AoSOg|;S/..)IJq|_O?J<ӻ˯LHN;,ӟTzޖ vaO~.kU{a~lo/Yz{#QZG'Q97G6mKj4k֬l?:GlAon;3 TU4e&.\{vءVM2dpЇ>Rg9c^{홀+UI)묳N7n\×F+VH=XyEŎԷo]1߿w 'MڵUmvm0mݞe⊂iǏO?7ިaZ|XgS[Ň#<"}SOFuBMwzUW3{}_L ,LiuPui뭷*o{Y袟\>pn՜o%]~_6V;wI'cxo_ֆ#<przOHץY^*O믿!\g?IhR)qƣGǯzLufN L>Q+ȏ}#aA> Z1=cK;+GCiY8eimIvh/_uꬴx,vmt1Geab=|z{0wu[V)ydj }k_NxK^)o.\Zkx|_m{Kׯ~연q_3&I Y|N3>~sέѯя ,ߙuDl{W,@u]vF~g/4k*>rTn_6mZ6W>*}_on`Z?.]p293gά?4gܼiᦛn*}3_Ͱӎ)SJ.B++ӳ!/}锴-մtҒ#v//D5NsK7pS{W袋 %6Mfn),͚UHuv( <ΜjLV6V[ӳI-/ti4/_pu7dWgR׿eA|eԩf~}:wܻRK"OOZdIq?EѼsfï/꿓R[Wg?x}0KWB3wuw6N:){IֈO?-mZo?䁢B"ƭS]XatYk)%HE_S ZRaw_t"!L?Yuz8@WTc*W潞=LLK.&2/r׿Y2,S'|JeZ;lrۢbNC=$̝[:D:j 1gΜԙ]w\j)?.(DeM6n=EV*,S,$)iō}//m)VSShoԒ .qap[2,Slƌӟ\V9o1u&_+}gUr:C'>тJγAV9~\W|{һJ[*he&v\|ٯ#Q\,2Mzm~;8hd q[l>em ^} ]<+Z;6v!YH^˂54l"͟,0ynidPО"<فhf~-%Tr?H 4NrP6O^Qij6Zx<#Mr6lsq{"X}!E%K/dhO[odܸhђ1bDZX.^S7̏*Vwywֆm0;]oiw^_~NQa"'B1ӧȖUmžm Ł$m5c̉)QlĉiȞk{O+>/#5`=& 6؟BT; .m=ZkomʽVoOV[m7on:-mUr\ԋ/aZ=S|jrovTf L[.1 E+o馛D ,HFN;]V¿6L#GL\cǿ3;]BsQ[ŁO~_^H˗פ?!vvTSm!`UNieߔzr ZTywwK`& /<5Ɖ';;ω|ק}mw(ٍEHmYzW53}_?~2xg0ZNo.0>O}\sܸqYo=f=&AYQ}%IT` RGW1b٢s=W0^*4*- /qtMmwq:]t !M<)tnSbPoN?VP%//|'=ܑAgs ,h鬰L$Q{2!ݾ PƢ"'7G]S>">͗[ EY>L8#cku_/|s a8@yUWg;snv ?v(SLI**&}.Oᄃ$]wl`fu%M׌*S57]>GP`\o~7LR8+c]t`gEUOzf| 6:[t/teZ-X2s}_T}O;$Q&gصӻF4*=EP$8Cx㍲9ݼf3eJmwguD0*ėaԨM^_  j :3tR*432a fʂ @xr=v͘13k 3l%o*])ZsmJw߽ 33gH~q0:*D]zD58_,s[mez䑩 ^}uVjmx0޿+饗^?-fzjOhu%*?۷e"!ܗt>;-k-V\]&zcƌIL&햵ɹ1:o*,]_~|:wg?k-ʉo^lwP(0ַK^_.,mrbQ'O>~mSl_aJN/!CgUJ9KV[u(cZ^QzoVeƌ%G{7u> 0sfiӞK3glդ"@5a„ndAAӰaR[,X l]v٩aNȍ/1DpsBjN2f:?gŊzɠLAPߙ:=ܑh37tKw| \xOS!t%= 0uu`#42wtEfC.'?-Kq3]k]G}Tk=OLcǎ>tz|`˗645|U Ѻ'C=RՅf~yf`9rqK~YN;<0mY.g]ׯ /(-Y4ꩧׁ`?D|:}iB^J_ک?8աe#O}2uK/ezw&sW'^{tR['aÆ?~}fh6ta,hUPȤo`=ާ?,sy?nUi6e"2']+IPh?d)k5њ-|{OK,N=MT7mZO}f:C |l8̋}=AgyFJѲL8Ѻq(վTnlMҦn>4n: *UN:8;QeSNlALL|W~%. ,XjE7(>@]z7>@mh^}uvjN]u0/dwb1-2Zq]k:vm[0>mڴo'/T?j7j8뮻dro{Y{߇jpַefϞp=WY"}'߭ޖydjzgs]:lٲPKZ }^\K.MkԩO?x㍆8Ol0G9X \m߯ʦů'Nܬѯemn=[QF5vO{Gv줓NL-ZI;W3fLOs_M>#? C ћR<7yZ 7* >խ8YrQ|A4ђl̘Y($S̝;;] ĂM?_Lx@Zk0xy>-" w۰ٳ_kX~pN򗿘6`B3gN_u'sQôx8{Qv?B'w56L>W)-fZ3Z;%]Nor~|Hӟv>IlU9vQ!%~~GߞSLrfΜ>#|?>͘1\Ѿ%"` uԑiذa3/أO/|2-} /N55˳+j~1t>~]W7Q^=RITdky}%Z*htYI š:f/gi}{?P볡)_ʗ r!~0#O:D%˗ŋ;5Si{? &t%>WD;֎=zTwbmRfde:mnKZ)ufQl;>-C'p|v) g5׾/~g :*>yNO|cilS`&gO}Q˪Ὁ2f̘W^A8ޑj/m„ O?J⋲~Y>|xk)Y\0Oʂ5{~*t`ovFe=L ?Ӆ^UkIuם_?UMlG24U.>P,%BQIcHe1}%L5gРAYX&7>~N\v:3:-0 .!Ycms}=wrӶi.TZʹL`(Kqmu ~m?g Fm0/mo;m~񋟧顇ζ?>A?_@?Dlu:wg<-^ɓ/yI.ZmѸqN]!G7.]Dp&4o>1 p~}&ׯWݯP'kk--zlo]2E+ і3q˖դuYη7jQ%c 7LI^z7FA87w>L9vyӧg2ӬYkNuY˟6 _[\ܠQy(tuh&/?roλ fesb;vl_Wһtפ)SLs漖5lz=цiĈ. W\mӒ%K2kNr1chQ&Eg9ó-^8imˣVΫjiU㹡Oin派EC55+J@Y׿ݪG]um.ߦ)DK̙aUrzV[^IgqVx=STZ׌vSDw :ŕfBt䑇')՞i z߁~/=@U|nc,Y$d~z3@>|x׾eiq 70}ӟjq#GdUUU*@[7*6۔ߚvO[nEm]kSD [o-N>uk5"43p}Wi7WLsRzw+WL=QTU]mZij弪VV51憾oN[4ļqZShrͷY^-9?>MiCӀRk\w  3Ao**)YMK_{T:Z%fԥi^ _~zҨDe2*?oSO4bĈ]'Â7OW uo uyCjbZ l|LrP`͛3gnZӌ3KҐ!COB{G AU3@8KR .\zئ &1::M@ӆ JsV;z+ PTzJصiũ':7tMʗkP@kTJoߧ*7Bjm0cXbߎ}iРAYPeMmm}fGw(G]FPtL} 'NT'*X՛6ZUҚ-,1RdZ+*P3![2EZd+ie*CB1bD~Ԇfsʓ}h1y!U郓&OU|֜ؗcr,N]-:=zjew- =ӎTSK`TCM:]؇+,FJv~Xg;B9uZ9UM>y 1oxԬ+@/4rܯ ڣfe]6-XZ0|PUцڴ|lhw:2.ЧO bUWߣ~X骢ڼ.xHM7wZ|XH_-Z(+~MT8Z}ץҚ|e]Z;YU4~_T]  4("\k&(3P  @ZlYM@(_3P|9kPf̨.k*3P%,_}ұ>񏤾}&  RL-ZҕWaP[[l.ͺ=:T2_wu%*DeʔyӾmҘ1isMS>n>2Ѣ=SDge6|bׯ_(wCM *L @vL]tqVY&N9sYP9>XяO/<`;qlԧ>[_n;v{$ ޫ{v|0e2ӧHS<\0-0|f_E Ҽy >4vء%.-X pMYiӞOlBx]o騣HMgWʇwP:0swYv۷vڡ`]wݝO?p( 8 4gM]\*@/ߧLR0g2o]ǃߕo,N^{f6lXhiM.SO={"ʕ+Ӏ:묓&N,mцY,Y$=SW^I>?X" 4(-"۷eU]]]bi?mozVN:!-.\X7#;aذiuǧ"3&Fl#<^z镴h:l&LX?ǬY6tӔ/w{uSޙ3gG},kiҥz߶@TΜ9sOz饗ӂodƆ x;u:T<}G?o˞%gMgN/oqƥm*=VN}GMV/{<74-=Nx{vžN}U~ !0E`@mmmJgV0ޑ29Qe:fֿ8$Ʌ+V[6;??ץy^/t /fj6M]W;RMʂaƌY'LGqX}ҤIJ^W:oʖaj=o}Uܞ|8ԲzSW1cf6lFim*cϤG}צo%x Yş|Ll_>|hn8ݳgU>-R\ZkD׻ޞ]o2;JEstzp3j=jK~}o]wl;_}^z'Q_a=vormwdE[lQu׿~eґ*3q?f{Zk ˞F~J@Q%w}o|yS" kT}!D0m}:qYEXOTx>BϞQqGnɪQ @y2P\%4殿 ZxꩧK tMZ݆(箻G֑/y]فD mݶ`S"qڳD;[o= D8R",BJBÆ IG}TAUme!8?q4jTp…Pqǽ2JlonlU9 7 7ܰ9vUV9'Bf3߳@%|*x5u >,uz!Y~tM7g5KsD1B629&%!ڷqǽ#vء9Ʌ J'Ojr~\ PNGw4b6[5ےi=,F(#G~̘1=ui]w-9/.TY 3_pAv3aȑcIٺڣ3xo,%OQdiϵr:?,uGTyONmT)Zr!ځ5'ڠ5N-B> Yxq'l!F=qG;]R]I`ʋ } -VEU#wg XݒieYh^n JoϣJSeQTi & CThJ߾o},mlʺˮ[݊*7W#B'p|V&#D+*D7-TWvO)~s72duXh%cۮ+64[Q)D7n\vW^)=1!^ET)'xt_l .YOB+%ڦ { @yђ H;S2[o-~#n{[N%3WVc_NfZDiӦIvmJ):NBx&g ʈM݉6g…iѢEi66ywD\ETiLʉ'u Ҋ+͋6B6* 'QM0! E+tmyf}~AVߗDrTSᤜlE#K_/JskXKUqc7YOTɵeޓO>a/T? 3PkWbu=H^)SʪlmB.SN-G5!;w"3<|TS"}}iРAi6kL~Ւ?-k\#*pQw|h9rTVꫯItGmĬ+LO6;X* >Ĵ6xtX]5ض`ժU֖Z6׿pONQF ׊VadS6oe;nkډ'p{饨^5*>+/ =pVkذa O`ʋ cp?x3JDX&.+onӧ*}CL=M?,XUUUӈJR{D\bFmP#'oXmȐ!iφA͛7Jz%_HM 6a4r4,ՑE+aԨ頃, fl9OΈ#|="w{tZiqu  tחQe&Z3j1_׿~jV_ʪMcZ̋e+s}nL]-*EDX$Sm̊+ #!*ʄM6٤ԩ58CXȑMlSGE$ͯ:;UV~f[k5&D;SʀBB_7CǶ)n@=|eiӦeUORQ'ZU&/?w˿+wG˪料1czj'xW9ؙD&ZM>e94~ ˗w]x C`ʋwP훺C\ivyFLy8O> q>żD%sQfR{ onbEMH V[mY0?7m:j{&su7k>O|_k(%?P][l6x7|s6;&[63UM"-p}=Pr_=)*+gM*ǶomW; IE(oI翲%_nrv"bѪ,3brYb,mn閬SkD+ͥZ!7(寻׽`VיU=EіGwg:Gx{>3%2]yU gZ+*W\h&DK2inYp`%YPW^NlAVM_~8>}[-uM̎;6i֬WӢEӝwޝUx㍳+9s^4> KzӰaC<0% iDey^~4mف_x%ۮiE[r-Ҙ1cjs˶7Wbk5N97n\Zgg'6i뭷dEWo1/ @y2_}K|`/~Zw>}Lo>1rm?G}duߚPDb(%B{g(c 2q?D@hҤ]U`!UYlyXkaKە3l۲nuՋGJ B;SyxA4o>n'OB&~Mf"\C2kv={M7ݚM;w5Tdii~:t7daRM68ѧz:ngD3q?F{W4il^k3K]EXC?Zgg]vBI>\K^fm= 3P^f >Ow-g}f9sfv~ʔQ!G( *ZD;=ܳ o}D%c9:Uff͚)ǏKli8hN,{G_|) ̟zvP?Z :,޺YR"p ǥG#DA۶Өf'x>]gqu2:ӛEwYh4wܬLTv[&j&AeaEhKԿ챏Lvm..\bZƍ['x oo,̞ﱽ#G*,sT(,'z}Tܖ>}fϓ.ۯ_zWP2{mj>m;jպ"uaoF}/{<7t챍ߕ*D5#ƭZ!7{v|TurU%7wZxnw9o>55+ZfMqod]Za\O>1](@%GI|UECݛyC]io|eDLbBOfdUYrOzqޠ\߫@%2KH9*8p@rћkLP6rl"43p`u袋_~K_HPe< @)Ly 1oxԬ+@XlYZdI֬&$?yh{6o;-R͝/ܼ 3Pf >}5)ޓ @-;!_=97(C ?߰@4hPPfL 0 UWW'{x/7(c֪txﭺ 3P=8PfE9x%ky C IO@=f/ﱅe^O>iС)qc@]>"aÆB:(S{kUw-:2Ќ/}O`zO@{hafʕ0`@Z8/ڐ!CR~Ғ%KR]]] UUU @ _Ghfҥ&UWWAiF`*D:thZ|yMPReT$0&İlٲlDPfT.P3VJ[E A`*\.8bŊTSS uuu ]UUUΆ' b2dHʕ+UD%~em#(P HW6 !.Q5&7'"$b%3@r!PQf(3T* E`"0@EPQf(3T* E`"0@EPQf(3T* E`"0@EPQf(3T* E`"0@EPQf(3*iJuu7O{? RUVPi|]ff*Dcras_OΏ1"=L%0P1V'b",3o޼YLNIT\\e|iz#f*LmmmV3T* E`"0@EPQf(3T* E`"0@EPQf .L|x󫪪ҠAҘ1cĉ==p4sϧ}Ӯ/iuMcޑf~ak_rz;ޞEuuuiɒ%饗^J7xs:̳ӱǾ3]~_RmmmN` s=?}L555 z2U&O-viǴFz3'Zp9?H{gEn1]xO…_i}I|`H`hC4inCh?y?頃HUUU%/ /g24{iɒi̘1i OvX}U9M7tKfm.׍wfΜ0U .†4jԨ׿-sΏz3NOj/4gܴZӖ[n?4yQK*=f#JƍKO:ȑ#[\=ܛ#sf-b=miz:#ҠA]G<._O1s}׿m:vmh,HT_Ԓty?N_| fO?G?>&'tPT2dp{ッrQ%TX،3G?I{LN}%S>ZpRazѴk=RSVXoeE;JG2Ŗ.]ogpe?/"8s)_b^fqYY9?FabF5R + ֿ;L 0"mFS>N;cN}mbJEB#z ._\)T`gI/n饗_UQSnϧv%}+_Lܧ޶M?zg҅`Zz+~ZЇ>V0?*D|_ x<~vao~So,Y~__wӢUՁϥ|CiܸuRTiJEK&S=`<*D%lM Ҁ#<Ꮵ eqӷ DXz / B)[ly))95QSOZ:O:SlBj3UW&L:th Q1h7JlI8tfN1lXa%kG$g!,L+?5/-"@fz5͜9a^rrC2?\؎i=n"я~ѴN:`Z>ΝZ+*W܉ N~X&D$;nwyU~KUp ^0tELKTiNW]uuA0(Dh&* |{4(fNhѢƳ>[0oȐi-== LV7*7yꩧӶ۾2뮻nw߽cFߺ)__sFhhҥRkKH)/~0-f̘Ug)3f{> k秥o凍rY;wm(%?naV&'*Wm[do|fVXyeu*-W?:IsW5GL~(f˦<iʕY_nUM:Ksצk5:cK.[jz\~7j9sV_R[RFiu)lm m~rh}NiiM}R|}Fa?> YZ2]voһδZÛ\Oouh f[ӢE ۮ ^{tٳ_Z23kVak#j;`vF=xZ`AzpH\&SiSNmMc63k֫iȑ%7u8㬂/&LH';P[b1?CUfS)3gNjIlW/O2 8=3xL{W*2st?*۶a|ĉ/^RP&Y0fGXfwlerJ]wݴg'OޭaG|ɂuE{5enK;K䲷~Gx\Ə_ݺ/D8qfٲaɒũ9뭷^uYrQ̞=;͟??m&騣L_~ Ly(t]-Z|8yGV@9;C;ve.†*19_c a躋+\qŕ վ)*<̳ 7nUoNM͊ Jw/Kz _ׂiOC&:tH> R?9{]xFo{fsק~Itg6ja1cL2dp.Z2-P%B潞OVXhك>0Et9oU=GG<~xj CQ)ht+aG˛7fmuf~-DoLTz)v%}'NiԨQߛJ6GaYx{0aK/gaVRQ=9a|u [;͙37G4z /K/E2Ԝ#8,]v%e~ 5;ZFYx{S7xxW4j*"0=2Q1ӾYrqǽ+ _v[^x&+D03Ub)M74M6`vM;L_W Ӣ2̭ޞ 9^kɒ%Y`]w%{_o͆DŜ +itҗ}7 4J'7~tڲeJUiZFˍVfSWLJ˯駟V"MqYoiJܟ%ȇ}|Fg'};NzpjIGGyD:3@wRah9DxcNoYVo1N9cNW]ϬMٯ%K1cƤ 7=t5 {go~W0T՘v5VC{{&{1Y륿'Z+ 64ܒM&횵<,jzY@eܸqYŖ#8~t(f 7HeS;̙3ӪUL\S݋Z޸O\~_O<Νm>cǶ-EOW_}MzGkcǮviǬ TTnU\U͝V51憾oN[4ļqZS@Yxi%OivZ[[Wr~uusmUECݛyC]io|eTPQf(3T* E`"0@EPQf(3T* E`"0@EٻH٪.\6B !J) $H0Řqwξw}}FjWڕv]y3 *f0f۶R,K@`@ xTj@QekBC2j0 äa0 !4`/gr'8 3RdH$Aq,Ǔ ``'(cֳm|cm+Вk{ _8l!3nfE ˸ f=;f9}{q@9p+˸nnƸj"4C`Y`LH&k93^%[w{×{|>'? QmG` 4^X&;_ͼfևe L| T3fS;B3f0eLEӊT1cMI٦>?'E"Qg|8:f 3GeeLU~SfP)̘{Sk3ˌ0d~!7_m0nA XʗS3cknq191**\z´a2l1431hBx53掷1H٪˘2fP؃(F5Fkeغ17ݸc6flt**P6%bd|1S+Fe*\ #80=q6w͌ӸAl|D_@$akkkT&S64n9-/1cmco2@e ,=a'8+d%h2-80چ@j,1**H3Ìe5̝-F91/$2٠X{D-y^Ry'Hpr[18c1T63T 7He*wŪ3\L8&xϊmewB4ǹ ?jJ-  RF9g)tG'&288-=mxCzbNpx$?abeL%3L__^A.׎KVMxT0k*L6ve588{R.X;-Zj5]<)*[l_TQ:KA;3uRjjUWWgL&cD(Z|fL2&38]Nڸ[X*$e2 ˸L`'8}84xmŲ"]eOkU]TccӦ) :f LLmf:3`RJ1-ݭP([<۴u>[,IeqkB3-R3r/gcS>^:М9sj3^9.[fj3h0a mpp ʘKw[Jv.W^a'Z:noUַӺzҧϳ{VMMMMysH!f RebzK;e£Z/uD ?ӦUmf"#PQ LkgX,wtth]z1ڡ6>Nyzw{d?,7Iy,[{ba}ɰweoS~Wcs8Px2x\;vPWWۤWUU~?[4Q4*UPӎCvCކʼgJ ʹu;=5mڴy|k׌x̫n1_OYW}wDPG`ah4[7'L-t҉D`amݺM[LX yUӊ DT|uyfJD"'m۶y]I[ٻwv9bx6|.3`\j=z)6QW$xbⶥhL.YP;);UA_yZty{_O\Z~gH1>b'N-/YX-@&3`R tuui߾6=dƥ=}15vdXy|qyBykǽ w5))\5z`Ҽ)^*g@/!遙;י _'|*LuOc+\QhX39uP{I̮ޘZk} .X{#f)k^C'5HYg;jt* K疵|빶o֬YGyY'ta*kp/--:Suͷs1k? 'S׿}1ڵ \x:cUz~~KTSS:H]vٛu *ioow27u#2cJ{:=)կя~ :;t*}f@Q׆Gw u5vg(ݽ1Eb# Úi},cZ/E(6P;|F7nڞi:f{EQǘ-.STYhnz zLzuחsٺ 0xHg Xk|A o8K{݉jllHc5\ BK&U!GZ7::::dGֿ$/SCЫj<Ϝ2)ɟW;Xm$5jrV/ת10STWwמi:Z3-_L޽ //K遙5kvB)멧v4K̜xL5;'>K.Hs=OsN,6K{{K_֮ihhywG'LzT+,ci]_yi?T zCq쎪ߖj (6TPGsr^XXfk_ ]U5T4Uf҃.; N`QLo~~aG>!]z%#2JOu1-/󈰌Q]]^3ug(f@ O7lvޣmѐ~|Q7J$OQ6Nɴ-kjk;_cd{ꨐk7N=b8~LH ]{\MzTviJl~=crs-\L}qzrk8es}CZ6Sm 3`B5Mp6}ivs҃$㭧kD#w*G&VkyN8ad#ٰac;̪/mm[oݙݝsҥK5پ}%P0UH;vf``Pw ua!_s_"Wԩ2_ZK82h۔|[S'%9U.kXe?j{JoTN0O=3/9˗/ӼyF<צݐy|X<>FOzH&uE`iVL;thb5N SaimȄh|k'qYޘN7n%˶3ass%'5T [n͛Z2 I\wwS㷡X㷽ɛm) (>TFt7)J;_hhB \ 2v'=ǵ*ެHg*_13G|OgjJg2ﭩxۗ:oXF|PaL Db1{Ud=JD,T'bˁTr!\crmK[ܧ g{o{u=ŴҗEgyƘ3mNhӦN~tDX/'?y@y X:Vsw 0bgouuÊUX>ݴ%7U2S3'V]w}j}^8Db8Tp-]D ԣ>m۶+'ߋZXiueoVCCa1~ LzQNeB<`zW+}Vs+Ǻ;y}m7c2_3ݽSε3Е:g[o;@#0&Ą-"mW%b>qʱ y*3 d&daZ<`Q)$Aa_qVs Mi2JD`d+SRaeJ[PԹDB RvL >/DL!W%cU\섥Zε߿L` 0,3ЃyАE^B"OsB3%ns-5TǓ׶ %WX,D֮ȐB*D/TL@P555VPܡQmf@ޡӎɸ7OUߔ13,o\r{mCJ7<2GNU3e-'Trq)}0B/AˡPș0+* ے #y< */ٝpR[s}dMOf Cgb*alYJ}mL[^ Pq SVt;F`&tM]sm(a0+Ye'j<W:R>!;W Eε53`'DbIo4,*;N7Rd'G9]|6,<@0XoQGGq*ޤ~R`\Hęo ˲JWuNВ)V1urk lX?/1;t?w E`Y,ߪ3npJNI.tf 7wM3M7ݬRƛEK&0.709ZLv>ӑ ÊYY&Sgg0q H/0U 3vXxi[?T8ek~tܸXA.W,˒S0PmmmrPnQ2@i4OiYqsS4u=猠 !a[ݧ]V16ikժY1=-h%5Lln"yzaǠF1 ȟVI%NbY}9de`kO_7΄fڄw(]^&<֜ܘӜgh@i`'W0S 36`bJTg{}`w30u܊ fre9͹@,fhɔ[ߚ)H+r??Pַ w6#7 a0FיU7a^n:b0;!,Oyܾ%| 훧rҵ}JrbfbB21Mfx T(mŢ#SnVi+d];<Yl~ql̀ S ȟ]_ɔ[3*AzCuܸ a:AL4 *L.񔾼vJ+T[[+NB3et!0f%UC+J?pTWϤU1J`V`Pf\eT#0rlU3BUځUVxVjzABXlW]]fB3et 0Ui[d60-cMAhΥ YTvܹsL0u{x2`0Siƶm*KK\d z^MSit~rBI8!cٚ_'673V&fm&3 T[K&dRי6 `z=J$ G T, 3؉f̀dXiҥk$)EK&f|B c dB/c*;aK$/{fQ0{Tm0.7DIeL.V[kf` `:7T;\`zђ bBmŪ&=* Lå{o~[-nr[@|3[ޡb0UkLx0qy<'LhnTb% =Z;ט2 ƙ0В (̙xXbyiɔK,TLgH!X*fB`P>OM=C]eSe& U tPuSEJ7L1?UVz`%ynf%&f RߤT;1<҅C*U"Qcε7ӥhf3 lף 1үR!03Z"R$yO-͍ .f3`\nx& UlJEC m\߯zTAi* ?v~-jkk588C:V$WEG" Y}gm]Y3g> 3 Cz&3LLKxD/l ecbXި"IHZUUUAy<# W)EExY6;;u{i׮ZhU__~gy]N ŴI֖ 'ߋii4NX^Z.r_y/֬9ZJ.tq%&R\ e0r ůby[pP9M 0Ǧ9*yM˗/Swκ `wy 6MHe۶mh4:b}ܹʗy-ϝO`k\@y pږ>~)%0OmΊuv7Bld,YXGq3Cݻ(Zxu1k@armu;vԭޖ:vyV\Z7mLyNJ˓)߆ cj/wqWj^VuLX{f|Ÿ6@Pʌi˴pBDlOxaEe*XLMr4R1D^VTj4P(;3Ҝ5 _\W{+L|>;0v)* e,^ ~Dß_J;nIVa)SCCV>JGuӺ(_[lM-S]f<\]@y`dYXZRo}X-)nK&˓(9+'x{<]k,kő>h4g7|`0%灬D^w"pVJm{M܄/6mڔ~'˼/:JGGgA۾}GjTkڌ6k(T)nlٖMS[16ՠ]*hį( Rs|@Raק?uuu;^W^x 9S"VV&رl28ys}ڰa."|:|*;T $㠃T!B˼'Bi#dl۶]]tA^bk1?akSk(f466$PD;ڦgK~ʯxUCi6 啢aUV<$yU ՘ğg'|` %Krb7ߒ dv9_~r m,ڵ[=N?4#444|LpxiV'Pb˴73}{1|w}w{.z * \aż6AK&f|+g[֪U+8羗4x^X<ז(b`B{tvwms 3O2L.{.]Bs"cY3"arNK ׺u5d2ݻ=CUU]}q۶mK-O fl6A0iŏ/ xV oq!%*Gd|J=R+N'ə[rjؖ3um#c"Á+xJνɹYN^MuC,2b$3u$齜$SQ;JUB1UA.h"By bq҈~:C;˻wv/Xҫn\`k\@ 0,fl׳-?j\\[lѶGCZ֫g^)Nk&ou赶LV9-ţ>р& x|g_[N$cY|}}2Y'1qQV-]ŋ;8VLՙ'|J=Hj d455؞'ݭիڵ;[[G9yYZRmI{M77ϙP Ø;w.T`IΉ26n|Eֽfxt16۶m׽38]˗/ssm ( 5k#jcGD5*{ A%LH&b~)M+ST 0 _t(N<Z37C=.kXTryF2uug=T5S-WTpی~xZuuu9Ꭳ:rDȴ9'T3ٱc J'˖-ՑGT6:'$}g}ժUοb0?Rʫ: l߾?0cZM%t{3o_@$VzBaT-[M[o-#{1ju *%M#;L *wbCUV ixcRx'scMDt=:`rxLer˗/ȍ 3QH\eҗ>ᆛ}lP:VF{y=)]A%0[xpYNl )PF7wܱNy|{uT/C0B*/O\U65'0~#WP{ˈsnOBXeU<)2`W<,͓|CQ]r7zui:!EhD$f@X* b,\Pr yТVyg@;(Wv0yf VELGCؒY0LXថ.[W+:SАvɷbiUu$}˵fj{|@s"W푝)ެD81*33ʌ'xtP7XW,π"Cheh ;nj)A0ӌ5&8avm?0% cj:ڒj Θ2R<,zP*q*ׄa:4J$>JRђ Ef;\*= ҫ 4_Ձv훣x"LOv4D2V/ 9%VA-ot!m OUkksQMfuق )33޾|C3ƊU]]{@{h[oמ&"l{n"؊WM'PQShL'.tPTsL]]݈c ˌ0 hTh˞|39眭R}JDZҩ =x'vP*28Kژzw?;CbZd^3FeZhXVL`6 Vijj҅~Dj֫gT,|aui \3kȎU<>[C=cdIZK튵Gb5k}:ÜٟyH%2`#05Vk\ )͛駟Q@ (VM}W4)ثpW1ʑ|YC}=mT֣@zv$C׭vq;wnAd f@^\7˫VTs=c:G]z4Q#iNK_Z@`+ԭpWxyfLAPOue|՞v?kI*5x"YsG<a4` 0VЌaZ4oЋ/ӫn9Cڰ3 5IE~ՊY#[0Ynh&QA{$F y wIPiyW:Cl-IX`2LEhD:HiTޡnOu'ZA%,o\9 wA *䯱S~g۲&U ta*M0CX`$3` -׍Zrڱc֭[㪇tD[/U'O%,D|@1/Tx-4ӥHOQƒO<Kڻ411AuZ.s a )Fh&۶lK.ђ%mvmذQkuTW-*^S-KQ١d{e 4t):PxZS엯*rQ w+sUJ-V *8ASMg޼yE Ȏ (\cLcLe˖:_щ oGOuUiSZvurGS~Y j HiJ\+O s5йGىI?֚E,:eiA/bF` 5^ry 7$mٹs6mڤAW(4=^]*)1ةxSx9'P-o (DxgJN,6ܖI-ək1R\XX v&eju>'$c4kѢEZ`Sf:2 *PUɷXǚP7t5utt*41qEŴҶnK{}}^%J3rf^[ބjr*K=т Fa̲ ̝;Ws*t)4CX fP#fyz3ln3 ^[[5kvqڵ[SOO<\9A:!(shFk:V}}ԨFرB*Ќc0+PPA Ɇfg}>O˖-ҥKRMuwwϩHƜpM󘐍LŘ@n1S]]jjjc_X?{&SU0Bot 3@zp1|iߴpg5ya&[U;8 3 fSTH*f;n"́^C)9JQif}9c3cn[a f̗ujT.ƪ"SqF?d*9n =3cnf 3 *e}hhHqRmƘLp5]e&\ z,g 5_P2(_֥X,l//VرZ2e;f㊭U`L/3dܼ^Ϩ 3PP2{>%QDlUUUfc|)D4 )UK%gJmd1@#0@3w{^EQu`(LOL7JY%2cm{s[2eV &3oLvLf@e"0@>5S@Qoo^TJl7 *! 6urU/f<LTlwd2w  ?T+nj1#ب.D` Llfhf``@3Q9P73fl3-P˹iK%|O$/FS$QSSӌrgN T3^m*343Lfp`G` =<eҙ/nh ޽G-- -a`f QmÔ9`f"0@q1ֳU|n*quvv9ASmW3W4sb1ḡd@*+,>ޖ9~xP ͘u0Uè;; >`&1cgiWnn$3x̭̜)$,**LfmB3n&w-1kZ4c7555 1 / #tn3Kf̌w\HX3**P>w|7w58pF=G9Tr*17c1s ,C` 5^h& {zƭ6gu3X`m&43ɖn=X d os묻ec323KX ,[%Whd4os\ rm+[%=ylz *d[ 3@f ?}P MS+(k@&}{0q.c0,egr=6af3h2 2frˤdg<S)WeJh*klfArhJߖ f@&۹-4~ 006cdgܴWJ_S X5*Z)S3f\bmlϔmP![&}?0 Ǥo/z ]fUq*;h@LdB+Z.e/tY0 63־\ A|(1/t06K7q "P]1K14`"0,3Vlǹ:p mj|!(F`Y*XTrǣ]̾|B0eA`Y.[p& ('ZWetfP]Ӊ 3rzASq CUlXC`Y*ۀBDH$*\@ek/x<#ӏIf|2f=۶|7v -f)W%/s\f p`+,(x<,_̺Y6s;b{X!0s`/(c&bZy`V)c> ϘLf&g=0jdL@en7`@~?9x`, P+&)h4p8}E"gˌ}hrg `v 0 [M ajR@ŘVSS㌇s;n0`VU ʘɬ;i`&2*g2b}}̸L8&[p 3flAw2p8=cA 47Q(VOOOs083Gq1f 3GeeLU1MM?3ޔfrPA2/bjn3c3cjflm{I3Ph@KŴa2SUU0R/( 0353掷c@ )kb$r( 3Ɩ>6VPy0@3_ʦD^fr d.@ f͌nf\njřMP0@'ٔ5zXɅ3Ì ,=|a'( j&I3mxm`fZ2Pa/_,fz}NIؙ:_ﺯrÌ17Ӓm˙qw*f0An555IqN9JqPϝJs3cp@e"0@rCΖiL0B' ` ٩*303В EǙmflf`nx\IJ)u[BA !80u['R`Fa|-u&s^7<3 @P 2 L&HcJ[[e2L ˦wurY  @aPA@*l߬qgb@L77@c&'LncsbgN%P*x12s1nPocQmiK|6Gj[]{ *Pr>(lŜmjU+*+|ըV/ <-*;eЊqC4sB31*P2 d$FWL%/ܭ'"f=miu)wצbV\p"ÓO^-tX 8P;>VKɄj =`"0Jba|dBᐞtbyڕ0fGbkաП [Zce:s RUJ` ϘB3T83 ZU&[P&8S(=3NXhhZfk6k~xBsuFT-Tuu1@ &dZ7}fUXf e֦>zHQElJzשq^sΕ7k[feMf#0&aAݻWc]'NFaEu_/V(USSϷE<(P12ffҮ]@%}ɬ ˤ`G=ufgck[!f"*7,lt{k=&[8\ G]l;T$Ѽy 瞳h* lC`d$evܩhNOi0 z".uB3/? 0В 䭘aX,m۶io[~NX&jNW{FS&۞L`6!0Rhb zǎX~WWf9vm߾ݩ6'43B3` 0&mF x]eL;%f߫;vTiP 8&' Ν;#ީW1gwaiɒ%>[cﱘ^O?>޽[>O+V,_c*4,-}9H8Pc}Gׄe[GF_S]tRy<Ӄ/B0fÞ={6mڬ7b}z } ncԾK.H0f@ ט"FOt@u ű?zGڥEB35cZtyݺK/CX\--N3럭koCoQ[[[*@o=Tl~};wڷkngzG~_W]1TIN;, 9wjjjF3gNSjFcBERW\q>t'P83`ci2$߯=zNۄxF[cݫ;K@@sq|3wu>+566hζ={$?;n Wh&yޣH$M6颋.ҥKF{B!gVW_q|ÿWWW  jPLcӗMuN=b?ZO ;q%:UUU願B2 ӘC&e> }q;~?c=I'˗i ,X c2VL.0&ztulĘݤUyj-^wqܚnLULYh~襁vqF7wzɧ/+}3le6dWhԙH$3wiܝ~>f@ iѡHX_^ S_!=&.̝;+L/!|f ˸ _{k.gLN;,iEC*nE۶mwϟOOLm3mLSeǎG޽[7RG__9?Rx׻ޑթcƓ~SJsu^pNe[n30c.ʂ3c*q ʗ 2f / Ng1r'mN׶y3&#"0C=.v3CCJ$l-]D1V3L1*LUNPLf@fL4첷8U j?~JR-\gq/h4Nw:Ɯ9Mo1Ueke"?_2a|Mus.w?c .eՒc͛+,o: Sw>6Uʛc~7T=|.\XFfČ lMrӇy{=a2I/;$=Pe[/f]sT__ٳW_¿ߤ{'b1o\}_uW?T1SXZꪏޜ f좋.>Զ͕+W訣tMyoO7yXh2 100n2\;s ͵@Ea=== S(H^) /~q 2{STJyB淵{ַ^Jyݩ;kGyi'f7W\qrjJg_?_Z馛K.f&d~*暚k ҡp S[]_HT7OM}JVwT(_v{X$_PTv_r{oD`\)1kU^ɟMjTU/%(knur^%e*'sOsi-|sZ]pUsK>Q .p|WpB'<\n;vk뮻^^zoJw k_D*O~icR6iifg'r3=]s7yMjmmMokk?, o8K*|*I3A z\%2ئ[[dokP&TLai ȳFZZ+ki3.V/PR,ѣ8zAڢ^TsyL&,s{]wݭ}ڜvGM3<1!466&߃u tuuٷo߾qJ9S&R{sٯ׍7|zηrmvT488LL | tu1enN 0& ԅaZj,yC~mL&dL X>Y5-*0-_ُ1Νi2f9so#ζnQ>Ƅ^Ν;y{zzSˍ 円4zv1kdbK/-[jŊzMڸUVꨣCXfvr9@U]uG&XenEy"xD_o̰L@L)|~E.M/>]e M]ŜksWk^;u->[ޙ^yռsyB!ÝЌcפ㹯yqrr~{snG&,0YFSL[cmzڥ~Y)\HY2-hWk+rmOv*Qk-y5KLXgR~2&owj}#Z'eݻd۫:sO~]β9o{rͷИyl&S5﷩sI'8/^|q6l謟~jnnaS:,Lz %H=p"md𔇵y@+BR8m;EK_n*zsH<\|2Mnw=ӟLM6z^ӶcNq?6p8|䣣g*].g}ΜQmk@jk?n}K_ImJ@`kijjL-T⋜ygٿvL@!,L|&&'0kM6 a3XTw/JVO-doHW6ʺ`|oY%{~/vsƪ2IRzgO:&c9?Syf޽2QXo{ۻzQZpks=TDr}SWq+Ïv^ǿG?9`gƍhO8xoZN:D|^z}Y۔gܹY(_n+d rV* 1<񄞉m>O&xެVdI^ۜkgt7SW\q7ol*vuh*{.肜@1sl8*1j zY=Yq%ŋgS/ږ%.Wxrr=XBe%}v)e+{k'6?A54#bd䫪J'ߡGyLvRWW1-.\O>ɩȲdk^?i.7oV8t'xVX>9Ls?M~ƩRc -kK.Hw7o'Nś|9 vEю $tlgd2df|bcnXw'OܝmfLfMD3ic fr6T"ak%/[Km3f3-muj_zFvj"ZNZi~Z%*%(kNr^_[x>؊$dǤ쎰3NV39NS! ߇u~a۵2ު|DUUA1!LMC5:Rw\}m6?:{~D+`<&02Ug=K56f\c2E ?993$}mϘ扴NgNʱ>v_{w+qNɴoī}6x.mĵ g*o{m۶}Ķ;WW\qTP($3SWW' (X,W4.oPu^y`.^Y_M Rn~ӟaL}=}J&agq[M7S˳/,YFO;s=u|=E=VZR`%ߧDmf`z܉DB~ӟgWSSy:ma3uvv3qT1\7`4Z2G>D1nbKm㲷+OiߐB&ij&Z%-V%n,sByN[ +߽i[43V*K0[w?&]qZtn=~jm㺺S_ʗa>CLS /}_ӥwݻ%|YMW0OߡbxPN}vJ(KnyLFdiͩnuP<ɹ9V$K2NmH5E{v33(̴bD"#}_8bѩ;V?^L{'skR_0~eoև?7qK/+hy9/-^hv|ay]㻻{ 8k /<_+WsUu׋/ZZu1kвeKU3~Q`L} fLX}QzYI>{,dqKC!z{teIAYި'ڝ)jU˳Yfy+{Qq4UFVr*fӨ^ :r+ U9fu}v Ǐ ˤ>4"hsMds뭷?k*ܘK_Wύn*7fӟK.HsxA~yw={o]wݣ3zNRВ i f229*Y Y%*<}M^z"z@lBWyer7m;y]^ſ^ ݲeyΜ r <3^3E׎OM6;9E͗#*׸td? g]ZpX_Cf?C-u~ʣT'74c014nv`V 0Ɣ9X xb*_RewET-Jr"~PP[d<-_\*c7oFX==y3Cg>G fre9͹L n"\̎A%ۤ fENKh5,fwYLr12-oԺ 455Wujێ;tG~߯k:Զc=F~Զ뮻^~/|NzJjoVwwOjO(JVO>*FW-q-#OrZY53HoA,39r`J#lW{x'wT=sB? Ƈ ,4mʩǮ4n`fϞzFl;|̮]ط{9+fVy߫wmʹlL:2`*۶s3aSgg*J+˓|C=qe5#ԲMdy~`Lyϻo|KGT~1UhL}jmS:Sf͚|w7so}G^Sg}ֈ}=Ĩ7vة/׿? &[f 74c2.2`:PaxMCȰid&mSo!kb̅*V`leRFlΩ 1a']}Uw[N9uNp+:☥KK 3'p1L泟G]~u1-^~y~ߪיLŚ#㗜Py(a01eg}XkƱީ6:Dw)_*VĂ6X^sRUEf5rp嗪_^Q)WiJoxYZr u晧;zA wܱN |lkk=S;ꫛޮX,ztЁ?眳g)+ (X/Qܚ݁ ;Q(}gm%-{.M+oҊL9}fZ̈́LL=2 3R|<Ӝ=}07]{3yw8S2 p/M>|^ԪeJjUNΈ!CROTI)g xFsJZP#-p͓o١Ľ{dDdmTժֹH^q_kL >󳽢L!*)))ֿp "è:+X:OI١u;dBZYidzDEfZ\Fe)nBl7)_({XqoufE2ẇf|V#0HP] r ~)$F 9:!W|8WuRuC*7$^(nFDugNNa-V4$ӑP a"4dZ/ b?48f(}jń|V,9#M+B9jMQҿ&S9i k;VBeS@Vf^@p*ϸ1~sr5rcn3q9^XXhn>-RsMVCj>^a92Tv{&2[z|f3SOt뭷z r|X7XQW,GMbAGWwdKmSw0~նgw*7$Mtso*3 @QaYqƷ l#<&X3o|mذQUUUֽ)((ԩӔ6s漩7xZ߿@7 olbm/,,k̘~)`B-^DEEEWffc:hh1 3XZ2[{G`^,KL:q>_:V4. Ff<kCW֠Ζ[PFFuT{6Ѯ.Keֺ xf3i^UUU[ӪU't)''c0ʢEO{\:s~M:\>6m쳽z.}ٳ1V4t=LX|뽟{3y%t_7m!B1 [ #1NG*уd$ō z|,ujA~{{}YH*;νnx.ᅗ2ii5jrswcLn1̷:fezScJC:akOM6U 6}@Е@0^ECn 5ffp}ԸNIa#qRd;ds6_ߵ&7*K G3d5$kojWc2ډ+b͘жmE;Sv .JZi{X6nܤ?̙3\Vc/j e1>-__ߠ[i2u\a-^\sFn}≧ 3kѴiuu 3@{T @Qa^.#C9633S -CoVpJ|flB2q2p%ݹZ;dnCYQk$ۻDWFgn~6)''۽%O2FBBf>kYYL<q= '^ukb;vmtrr.,2cyUu뭿ӠATZZr +8`͛7_۶Y!PFT^^Ufݺq2Fc]Qm% %f2-jL󹬫›Ry=L8s*v3 $SYThy1t~^H :mX6 tL4A3u \tׯ_}rUϗZ55^mAҋ; ^vzЌ]1a_Cѹ瞭ro0gWHT43wM3 A0k%d2|{!0|19ϵl&N:y^zzϯPF;i^WSD׎R<MLLX2'L00b*/<=iÆ.SL~M}g?A ,Ԓ%_H㚀Ǎ *q8,ܿ|ą/.y\u1wMl>ٗe捍M@Ɨ\ͪUKCf|yZ6>Xs ռ3cQ Z6)ޮ$%^37 ̭COS~iOX;bJf@D:34c#ş+yK& ЛCWiy~z:fӜ4y${CXc 74cOMMZ4Y/_3WhEIJꉲuԺQڧ233=5r6툢2hm!cQ*,oY,OnAUԠ !Il)%Q>c#*ɶHDf@tFhߺ6c \^ En ڞZXӐjB'*oƎ[D avkohײ@ڰa֮]tMjn-ڔU%? UY\4P(-9 ʌ1 %$x,L aiOhp4&Pb%C֭۴zjeWgjR_oӒ~[UZ$!YJ K[ >LC fksN{~ hfm1A8pl٪+"E5k(}]kmVw8S_aڧ@#󕔔hȐ!so{n- pB3F-f'&83h@YM6)&]TV&Uk&T3k}VJSߢhoWT <4"y0v)==Ce=7 0&Th&1Tqm3|4iii5jF2kJJRߖ_9J--j7ԶCʼn;-Z;TTF&Ք`]-yk&9^6;67%()QӐMۘ> %wUI2 qЅ @!0#TePMPLf_SSUZZjhjjjUHV=_S!s8w)==z>}(//WAC*ʄ1 bT8%ЌI{AKJJ7iTSS;̴ZollTSS"n]fYcL{zpNV%n+T0%Z`{ǘ 17L]?艤LɄ\ԯ9Gb-N*q,)ǏΨ4j_{Cf{g2:ZmƵ g#pJG0ev].CJ|"=Eў`Yyhe"= 1bzׇl6uWh p1fhV!(=171z3jnwKf\VioUHO:5ˌf ḟuWrrbA$f"9>L3f͌gu뵵5!mkuV17חg 1ȷQuvM9F4)V4B:Ì17-͘c56*|?l ֶ:Ū~C'd|lZf͌˘7O\e`fY*+:VLCG5f<@%1Ʒ +Ta>Y JNNV Dڮ)uqPN@163N6"(Z2DKN~>瘛 8 f!>{V1ͼIu:#'1ckfs-8c;&3 OyIIZZZԓb @fؚX;>30-LOeWR*fLՊɌufn x~s-/6[UYYhw d0xXS3ck21%A f j͔$QJH)==]K3Ueؚ/G%)z3 pmL.[0rivk Ж ˘1]՛mVeϖL.Tg%17\\eb[ Z:|௬]̘oXƷey0@2b>ě2+0ԤJ544O>@oZTuuXGKHH=2 =gx_|wf կ__ mjkkU\\UՆw"$@D` [W]\Qv]%%@@^^RRt *++XfLH&)) o  6 ƅ1ffk2EEE@nnRSSiŌթ"aLUfWefπL$ac|nqkr-J̚9_vkٗnUqlf }.e1SM3\xs{# 0n@"0@ '4Z6 k5ho7k Y6J6y 9Е\A߹~1_ xc<=AX 1*ThgUmql3Nq]#4P1m]e\e^ =bKЌ+$٦sk ŵ1;7/=ֳSJ5@"0@[m7H9(٦2:\\F0,g뉰 = zHZ4 2frU xyRpKJh­*hmfAho@ߵ<o &6 OfU1|3fn+yk;H,}g"0@/ڌkPDžD :!hi@E`^&XǹDa])(ƯK=Ud;t$BPf" ;cm$@, E`j@ -f@1PXB` *fЫ@B` *fЫ@B` *fЫ@B` *fЫ@B` *fЫ@B` *fЫ@B` *fЫ@B` *fЫ@B` *fЫ@B` *fЫ qUUU;\JPa1mƍ+U^^aॺZGqtchuGo߾B8cTYY^կnұ=qiƌwYjڵ>K\cE /O<.B%%% 罳_^yU񏷹kyUD&[_,?j!N:D!~?i4p kTF*˔zww[,+ OЌzmknnwߧ׶_~U^z h]{Uںu{_~e[oWܪ RPPɓ'Oȑ#JYYyh۶muR5tP 'רӫ?Xk֬ю5JOOӐ!Ct)')//yVg}{o>뼤=3zyf$[:أQ||F\ru?u/y>}p8tO?766jZ.]t.ǟ}=Z4˽[˭ ڂ ~zUUU[ 0@;F{wB{w: ̘y&4ϻ>q 8Pƍ_+,lURRhjj~KG}ܪ"?){0W̱+WR{[7, wDw箾6aO٨0ڭXK|m vn^7[;\M0ުb42&0c̙35k!sL{٘7r fƍ5L N͘q- Ҙ0yLѰaì7}нT0mf'; "Ռ'SK.1\}VG?8SՆӖ_iѢ^B y߽3fzՖʴ GK9stXLӢ˼t63 "GEE.]xMŗYfM>p0}hShso{'3O>>p1a~i-tzn1~Q ҿ/edd͘qn;Sk}y]s͏ѣuw?)1b|!1&p`*t5-- N/L2o<3|2zm6J%&4k!nCv}N=y,XCO 7\^?3tu7hm&yW^u}q؝wޮ_V 2>=g#f ܷeyLK7:u߳FuǙ@դI5{qV0˖}#8L;߂֟美 P@g#0BOq#Glo{7<2.&Ï;}ھ}0Ba3,c?DF{.o{ Tq0myfL ߰gawT,f; ̜9}o;#8BNL3,c-{rhK&STvYgzfLżMu޾̪wߥ2q1פDw`(//SEwT }9VUe˾ Z;nSB®^VxwB$\a_kf6mܦL{K.Ț}.O=XׯWssiamK}䫤Խ3mf:T{ۇ~x1?Xu7"?Z}D*??ݪSa6vU6m?}` 7[qXѣо{00GӢj˖8-;[lgZSL?@g#0:̴2iӽ9wS8***j"(UiepTVVZim,%g`fOa?ī5vn^q ӟ^^V3ڊntEhIj/.3mPC~w*'.(/:Ҟ{iU}0-Zܦڄe:ZE45|[tG&RmZɣZ_|̪{{(6ͶsjkkMۣXwI'jzǭ=f*,YT7pN;TE\㦛nqp|j}kT^^ngT%\3ܹ|}B'|Z't{+.HׯͶmۊppAzzjjv׿$?/ m@jcz̞}"ag+"믿ёG𜢢"TFNNt.{wnOVVj*0bB!w};lVߍPy+,cF\3mdsYvj`&Z;޿jjjRbbbcm&:[tG^Bjkk9nĈ^_"UX8H^>S{Ky uz._}zc2SẂN8a'iÆ ϹT 3fzsDfn#gqnWz:քjf"eZjy:眳_ި3gXkbV 1ՏogV_&|0{?ަ>Sgzsiزe^~e%G#<+Wz<Ϫsy㍷VC-q:x͑ﱁZD ˗p>9cGusՕW^Zr˯[x߯__M4Q{x9pvYzx7ӡ'33CG&OZ/-ݮ /Dg}U=@.\l]<ş[Sjj9`Esss<#{PnU9昣ݕ`RSӬ{ /[Fa<{Zsk/{_~~0_޶}{no߾]뾿L 뮕fS,KHi͚5uSȼV&$co6lȴPrW<Zguc{ Zm]wݭPy:&;=r4gΛY~~zvv-2.C` <3m~:ߪz1y$[nIJJJu~3c_JjKuƍ7Lmo~]T(ӊUg1_ývZ~߬!C蠃Z+n>nժUΟw:c_uC=Xwܑn|} wy.60@2͚ubݹPofXqz xs~jMdޫGqU<ɄhUW $Ncs?ּy9 o֬CL.\^9j}Dž w>|X}gy7+9995L׿EGqX}%c T޻bʕߴfa'оvL.c=ӷo/QW2J(ktym7aJH[_j57a*s}]}4qDŽ h{| x r3Pa[VV۾;:W ,o+WXMM֘15s 9=hM>Ms漡>"[_ N:Aa;>>C{ڰaJKK+&3nXǞ*o0?99}icBG=b cRSS8;F/6T(z .8ߺ-v%!?FC=T8SGÀCG7+TQQ|/7Ymi^>}y>ȿOj/\O-Όnyz饗| UVVY-Ǝ TkAo8p_5j~T/mMjiqX~Sn|E8?q]S5vnLf_766m[N:^n:II8g-Ωj39v[<&wR`se_Y0Ø*!L%"0<'_UUzwܱVhĸ7G/77G^x GݞoM.fb\SS 2ũ_~:t9g)??_,XwMsd۹3}Yf4O4II8g-Ωj39v[<&wR`se_Y0^ z3UW!0^ z3UW!0^ z3UW!0^ z3'h 0B" 8.3 2EZh@ f%Ґ Na<ǰOf_ `/grOpf (dhiiNJxgH 0˄1{`p /sX!3nfEe\ fn[fsq@w, ul6kת zPA3Lss{@>.JJ1/|1+Vzk̈́fL&W38Ch =oXs2eMX,gd+==]@ogB1YJHiǎYSh\B3LfaZ0ye|ӂ)55Ev1_0Y-XaB3h@C`*,ܬF2@31cj&g4ϐ f}fA2v`o晙eZK];ܡu z3ĘPaSQƴb2fB3ci V`&>> Ę'B3 17,cʘY15חXY=bras\r|@pfL͌ڞe< B4&@vid@ؚcsQa 1_uS&itcs Ve30!Cٔ5fSRRc3cmq7ϱ8Iv3cmco2@lKY͇v%''+:WX[؛8clG` xM6f1͖Y@`Lt Dk3cn%3랡3.Z2c|f|`7]xV!,us3cp@l"0@r"7[Z3Sv7 @Ǵ9Ufog%1rKC6MݟkD`173llbbo@|0=wsn)9 @\cn18XmfAPo׮` _}]cP 8xF`F` =z'wv9F:H@h-[ GaZ6'ZT!42$f@X" P&r["mE&Л UtI8χޅ PA :ba| 1+?G#ӑ" SM& 2kBc G`ѰLaK{N%q 0z:3 e:Lo{SQ v iiiQSSmf# [&$$(11Z|!z33VqmohhPccB]pLh+d'%%)99ݡB5"0hOXs[uu5mh,Ѣu>DqujR;CJ;d\ǺXwXs8?c~mݗr5&-MhxV233)P&B37"0@ tu`a3/))QYUJZ{YMXu]}*May<< ΥmMΩJs+u@VN雯z 9UMfQݭy>VXϴ64@uzX|G\%TFye=c4gJEMrsf1 CTUUNo&~$,F}ep20IX&豊<,evmVkc^k~a4f@V cL'lXX&Hr?M(E(°L  MO+kzkz-B0"0"2^[[kn[d uYX&L$džӥayd1ZZ_QcFuo$A`רuCL-]krOVr|b7[?;ևQ$aae®BfX9ק{SHݮ55ZX\_&azz3*BU"in[ z6L @}e܄the®Bhe<.N1Rl6YFYkF6,co{SkzA p,%&,s}1J 񕺳 ^XZ:#,ֱ ?, oS$Rt󔉚19ov?/@!H* 6L?{"e7kc ϰL-:%,1e2fhGœ}qNJnQ|L1AS$<ֲoDA'+)>زڱJ---_hyL- #['nXslW묚IOxedf)/ZON鴑Cm2汜]z.6f@OvAHҲ=UڷN>21eiXWk;M%hZV.#W.,пY6aL l![ ˘m ^sͳo<,WL2 M15v_Vg֬ 8WM(ڴcb' (T q#L$džgX&2~PZ)OֽEfx≧tGʕ:-@TZ ec:?,2* Cck+s ^εf*!!:gΛk-}QWVV^WW=\S X6,㐟pEj1e"j*㺮=a0* K{[/ZZZ577V6l&t?3=QJJ5Y빹L |2 xORQy02ELg(..y]^xMX&++S^ۊ\ODiii뮿CҩnVsPaŻLFP!WjQI'e"B*XEisﱻteSY檫Ӻu?y4i1L?X=􈊋Km?ժOUOc~v3EE!f娅eBOUem;9`E[6T?hfok+¯$,aK֤/g Sr̄dugU*olXJCa3oc2]~׋/ky:/++K?zu N\rǘpǟr?'mۊiO;И1^nO^zOM7\IIIh=_z;3 j`VQ aooxKihF?P v^^Nϭ^f{2ƗU-a*l6[|INN֔);v(!a?zg4ueggDwSpsO)##c7o^ر{+%%Ek|ooi@ @oG`DLHeF/FĞj&f#Gj֠Aݢ%ZYY~Xfg;'O5vid$.z:ҥ_Xn+PkUj5Ə|:)>>޽L_c]NEEz۴^a .8W]vW5>Po/Rz@@tJXuuZPa=&,OJ8` ?, ?wnu6w+!0:?߰1xptꩧх>1t,X:>{UWM% oVGD*9G (°LFa+)>=&f/'OO?]+4,c^Ӹ ԘH.99m^y5}ӟ^oD1|+RSSuA3)aÆKJJ뫯=K^#C=bgjh<_Њ " 22- ˤu#ْ_MKTuvK2rNAη~~71W^yyLaa˄o߮7wo:n{_~A;svf|@+3 j1NoLa*//SIq*++`mKNNQvvܼMMѩ}?# ˸y~7^./32JM||x?yD-k@KQQB[ZݽY%V:|@+3 q])#>YXPW[VPeEE}5ִufj=8 d (° 8 ȘЇm+s?&OnSR&x?I7n?%%Ecƌֲe__UU^  #,79{Rb |2577<\K>_}ƍ`~}m˄2^III>|֬i?<+M%WXf9a뫯UW]̒q* <ؚoذQzkx>~uuB ZQ:,=Dݝ,nX_jҤJMM{&0S4,o߰Woƌ݁W^yMgy~ {^9r^=;|rwp{ZlH[^ Z Zv>찌e̱Ssݭ\mDa&}dG7,fO>jd̿XX,<{݄F:VoẀ-[ر{+.ޚeǚ '|r8`qlnb2R{VN$9~eA:>~٠md2tꩧ#\f {>྾}Z-\ǾVh&dXFeL#ݖPf*mnWG@y>bum󛔜6ǖ[+3)1̰LwX&DtZvZZZݥO?38MSNqWO1Ue}}=^[~뛝-W1jHkXb-Jihh_w͛Y\p~Wyyy+> m,,㮆:,cUńe/^h7)--L:M)A|V\nnB!{9ﱦʌ?=TXv'&t=׏~t֯`m[`5YVZL.X>Ku晧%/-Z ;WUUo.\:4SGuzkg\~[3 ͬZZ֭WRR?U{DZ2h Qap*2 x2A sPLEì̲ (LDUh=#:*Um2yyХ^h8{˖zᅗIVd}[n y:c;S{VX<-2`p/f@t0MڄbBeaTD1m:KYy1P\L{KC nXa%==j-tiΜ7hZn03ffΜٳjs ?>|o/SBB<);v97U_W_}m~2˅oUYp:"Z.ܿą/.y\u1wMl>ٗe捍M@gÚ\˦J]]ZZ@4Qna-䧭Ua;W/]oC32ђ h 3,(ejkvJ l6S0𾟻}e@7 ͜tחkj ɘЌ 7aЕ0+LېGħJqhmU]mM9:yf2?CH^aСaB3 ˋ>fLbU y $f@x ,,Hq6+|Le8"˄QwX`aNB`DW6AeA*̘ImMe\9:+,Cfθk+(c&LXtDKa )RU]noVyypqqqJMIQvNwRi~ /,a0+tWh仾T]Skeזm2e2QqX&豁54ԫ0aMheZf1j0M 9 PdtЌ ȸ=Q 8b"J  (H`2WWXY&,-@y`m뤰iT}{FQ`%8{ƴg5j ˨=NJj$~:|+!{j_ `w!03,7Q6L0ʠA;dj묹 L4x(m0@X&FC3---V{x%..Κl6k44ޤFGZjv8_! KWbMIq J%*9G5eچdb"Jbb *==MSM#@#.>^VXsecHSS;(ӛ~~s/=qgZozjNLʼZ5JٔnKVfB㨘 : <,;5飨@X*&P И#LeS*"h*k`vBmk7ΰ )PHesOͽmf0!y@$( 3,v&9t]jqȪH2qANt[* V)Z2 ;,ƱV׶qZ?݆eW? nXWSSS 8so=NLLʦ:5vJ;+Uy]?'[{=-)E"h]J%5eJ%kx3]O>yz~ֿs]:D|~v;ymR{9ӏ^Οf2r.$U(G>xVny\x\Yl-?|:lypvb f@t`/,Xl6pLjJ Z^?E=Q5?zL&@gU㑻6?K0a`1L>x!Ck wq# ̴89+^uM Kߊ',|UxQϰ+ܤe[VYSKgVCr זfC~ګ^ko痽?;DLHQ|\ϨRs/,UPaG왜~c`Vn?N/MҲk~5&:4a@K2??戀E`7БLk7t5-Y.ԅ}7$4S\|Mb*=S+a$^%SեK6߽{}t!:hDUo[AME o| fkum\}{m>[MINH{N[ZxZLU_۫0f7o{ؼ2 f@Դ=:as^uSZUz {m;EZˋ6.WmcCXs&'%ef "pF2f^70aM5;ϑw_iMSVBFm2ݠLKK5E~v yڱc6oޢs?ՊZ?o #-UCK 2&&WG\'W.yiI ʮj#uI1pOg;* ᷜX~uU91Mq>Ϋ#ot꾳܁9L8{NwG^Y}۷G\c+q* YL4Z1u^WX 6|#{Kl;ETV[e-gdhLߡa_TէPK7Y>Y ۪[mT?]ե*/-KVEO0˭kt͍+kzo"yu^sεܩW2?F^U(=M`@("(Uɤac~qf/(ښUWWKfSrrՆ)PeO֙?G/,&fKeֺ xf3i^UUU[ӪU't)''cۢEO[4\V\e9gizS^^|X6m^a=E>Gcf+¹獎fu FDYeUm0zZN7K- 9FuyxjqXa0r'}F{9 ,̼S͓1s؄|,k7;WOMu?}:ӳ޵*>QI*ӎZ]iC1Z/VqGNi9/3+,3":Nʷ9tGGz3 za@mBekn]XR:SmɒnM=I]S>XAXf,hXfWqtajTUwquSeƴlȰ_x%LZZ۷[T1nMV ֹ p>F1ӄ 㕔V̄t<29*4YYZnL\4uT8fŜ q)39MeuUjy[uW9q1ጿw&H{rS/uV.Pj=4f5!WQ_ES _<#/ӢMl//gfiU...~][J#&3nB5ᣦGn.zWD|SKt?愁sOI;3'Qu{@"0Cackڵ:{MYV{aa\ŒQPkT1mۊ4we]+`b9^k7i4s6ׯر{/B@̣>eZ V(\u5WiĈֺy'xʪ0cMW[7;uׂWx|I:nf{~#zj[o֕/ܮێxᲷح0Knj몜uZy./sga{L3KQ{-޴B=q|uS>T1/9f2{?w/,w?p3DߕWIM+Y= =7}>'2潠V4E`DMaKc[ud`I J,+Ѥ,^XƧ MohM%Ogq1L@Ŵs%hxO2B3{QQVV^6qleUŧOz_ozIM^VG/ܮW/]{׻_Fnm[*KWWk dsU< 2L9l bf@t קs~/(౭ ?jubJԓ54薷9(QXaqk_ߦO{locZ&yrFںu{[vvVJ46l=-mۦ@M+%OMe5l OIIIf]>Rvrc}eZ264~Ug8=Ů.wpZE՚ϭ &{AEq3RJ]s{߉{T{M/=OK6}[힞->;B?tJ5s= nINJn]{Ͱ2Mk{lhE}oVF\Y('u7_B{YՈ: RUW^.Q7XTѱцmjnGjs̨>V`X]I>^--- qrWk~1Z5ر55A-s~JJ)S&#zNVV:P䰫;\Y~Ӳt'[-f:Nq66 ):qA6O~LNSGU^^tId2ko;ΙJo}7w|gkt!6do%u1PiA5k%'1{Vh3i @X?a|ee.y0|=Bi OSU_ɥhy7X[%^ m^^6m?rWX˕DٖTYrPPP7c5UeRR 'd̿Ne}ʶӒRx whפY?;ꗑTWhT]_HkvpjvfK|/6J%%$091*0Uf\Lsj{Gꐑ;L.Ss.]]H[JuStLGϹ]֖o7g9k<]G?tzO@u$.}qaxkf̾,3oll*)=a0i&rssjwhB6uײku6k~;~9Dk櫊8,nP%ܰL$ 92֦λv<U~2ϝd]\Aox_#rȄET1UXa.]tk0zF4˥^<9so^]~{G^/))у>lf:tRedd#Lup;mP2-1Φ)9h۸qvRSӔ`/k")) W}&yN l+> f@t gk$h4F`b,,˴J1_X&Pf: &11A2dƏW&ؒȄ\.<=iÆ.SL~M DC߾}ݠ jɒ/TTTdl 7'O7l\#ݖZμ f@457)9i14Xϯ]82|YayIX&*4hX1NѴ )lseBn+?^p T):{ꤡíJ3~2A'emDU]B`pɮ'7mo] QL.0E5,] qUq5MQ@ viKHzku<_>2֬tWV hll/Zā'NۛvLe2ڋ CTC)RɮH;-zL<`T©e=6ܰv];` \svec44F +ۘi#dB3\:҆)DHF- mt-@@\ ťjqlԮgp[ E=,22a` ˘{ZWoo=OWW1%&& 1ܳ˸@€l$Ygɼ{Ѽ' (F@UqmWr%_E<^a[ vX&L$dž/PXhhhQBH LwidB fjjjnl],NL4U7׫ޠ&]@WI)ݖlQK9ٻ8rϖlM/zoD(!zڹؽvoA`EVzEzm{mn~3=gΙ λy j`Xu#F1,Sd2 !,} D} ˴imX5& kʶӵyp&L e M Ȥ0Sj2=>Hjkm^>e`]*25Y;Q7L5`@yY^Yf3F6ƽ-ܬh2%j u DǺb&2,}B*`b2-Wf;]T^k]%UR@dcD,fdz۪qz&gh]4Vhk]io{XKo25݇eaPKo2:vHWj\-45q%a*֛k8@P`E}}}46M].mY`yeaiҶfIKڱPHMC*uuY\i_sl<ϩ}j:2]ߧ(tSElh*l\#Ksmi>%ͽ3O`X^6겱E$iq=]>זފPevXjUllM66;@Hsli-wj^N3P*}@_ݖi)rPX?^O؊ra`pj 3{Ksss,_"GƦ4R+4VLT'f 8/02lذl=gΜhkk ҜZ[+k+ T?bZzIΝ@9Sk'2b)2|+VƢEYKKsjin-.SS9:@햵o,\0-[@ZKKsjin7Pu҇u>dʥos˶G@Ishk7ee[2TArᒗ]mեcEV3+˔bR]fJWɥL>3ͱpXjUL])$3Pf`(T ¤yh&M,Ue+3d T*3cB3yv^b6fұ5}Fʪ=MP WJ_Kd-[́%y4ߕy|<ݗy3^3Pzoi ' i;}&M"ihѢkؐJ|aҗÊ1u~s#0ULM^m&i Ic)@S{lstGS(|lXL~lyPvye`p*V)Uh&d4 |1bTv)Ɣ[܂J5%0@y MxRMSWW8y0,go1a\f`K$( LqHRxlH][kT^Ue "]h*y@ҹVނ)_P(&0PWfLZJݵc*$.<#X.վ޴V*n R]U4^ޞҤBM~к z.f`Tm&O/*v@VjTE`t Mo[O>`p!j3b=$2 Gf`Lr} h`C|+f`mpb1OEPHf`kp}`Sg. (&0d' T`0"0tR> @@5zK`QO 5l1@֛ C C C ZMMMG1l zzK`D@jT>%@tE`5$#Tԛ0L PL`/ 1K_3 Q&dhkk TǪ␌ ӛLڮ4u7U/|c+dg`h!L>[[[tx8eKNӺd+?&L ͔l!8C r]VJ) 2i 1lذAD1Q@UX]19-V5es_MMMWJK t1C R]Uɫɤ N$ѣcPLZj/566fa)0l dUgTG`JUe@ZLZv&͘1R fĈْŖ,Ye4/K`JA|IUVeߞIƍ+L *R8f rXhQG5WϓL$%0DqX&WISX&7iRU&gfV\ͣLjєWI3B30 P)^RyIGF R(fܸQ__K.+VdT&h N3PźkTIS #GVYmm]֢)ͥ%)4SL&|fJiii&aA>wB3iN-bKVQm T23f ͡ƒ%K;B3uuu%!0UL(Z1 3 YIYgi.mժ,0S[[bҺ TL*34)-͵sp 0Uy^/-y+'t н4A9D@w[RLj#4*@*UL*Z1IslsnU T!=JĦ.Xwi-͵nsq@*P!R4رcXixX9:z@+>Fbsmk3孙%0vmGm@Hsmi-K庚6}U҇C9ill sniN@R7Y7[VfR;9_ZKsq2 0Ux 94P}f`Շr |-v4TCwyךO[|` TV< -:nO```D`!E`Dqq`u7?WSS@ * an 3 )*&ʷT:M 3 )*Uocż?9V=d  b_Ko=^3@U{yq;~uܺNYe xq;c}O:NZ2@)2l|)H1sc+x Z.ڑ#acė<&QP'nsϒ{,FlM vw,]}9_z77gVWD{3yΜ͘G*Z$FM[nyc{3Έ-^sX^M'Gy;Qin&#0UJP6я|$sNk]$Vco~M1鵯 W[t=PS?qb =i Ucc/),SIӳ{]<kOu1#c~7| Q7fL4krM PT>j;7}KbcuWS[ SFeYkrO}+1bmcw3lfᗞ87bb;Zjӯ~ /y4leEbgM~aڴNǎa+G?Na?ouꩱٛߜ+ggghom]{8&5Q?aB VmVSq/zQloCo{?)03AK&s~ے;ϻ$ ӧǶÏ\r|%1?uꩧO:o~ظ!n:5}K㹳Ί+{wǭ;=tb%Do,?uMUYbS˳ˎߏic?aV;}ʥ\({O,'{I}>X;ffk ޱ0VUL._J_zc/4WѶbEx .4]vY,(,)c89f'G%ͱegd{(j C1Jʼ . mm+~v~ϒ# ?Þ\;79 t7sf0MjyCt\_r)(WZNGbw@ߗɮ[5-Ҵ-Ib>@ߩ0}^,R*܎g>_W|;YLUO<yd,NfsNn)T2g?pߓW_]5a$IU2kM>}2o^]x+-ʥ*6%Yh@\b=|I%c)ͷU2q+˔K|N`zS׫ku,_._ԧJƿűϻ]vؗΤ CS}7 {ݱ%Ądj3ѝW\GcLXL*_ ˴}(ko,XKrs KR`yc u5F*96kʫ?mea$v:; kLs?> EW YP6yrL}ڨ1#04Ϟ];,,lN O`f{eI N &V=tE<-׿')KB[:WI6XIkz瞮ԲV@ɘ {.yZx1o̶WաL~qO~0;u%끸~))bJd+^T=]w~~1PRoNc)԰4kVXqKJ)yoJL} <0~(ʥSjwkj+}4{ozXSYeVz`z CzW *TރZqo}+fyfXJmFt{6fmYV#ɭzhMkZ,1Bܹ1be;6u5Æi& 1cvYߟ-_e)x5+t̨&~)iu~,N4L+|06UO<Ϟ~zV}e諁~t٩8%Y \%YRk))S!Umڥi^ګ s?cE[V,>Q<o|cŰLjڤ`2C ϳeFnӥ,oc:Cj5sԺKstw \UysXpFl]{ы?~y[J/ˤj6}wFkؤI]'}0T0}0cVWXc[nZ{Ȏˍ=.[ܔK;64VE_/cر]S[Y+nf[f!# fozS !Kn1Kn9_ѲhQq#'{v[=Z/n̘kl,2ES9}66Ԃ K.ۦ|r;찬QjjXO-x.i>=cOώ_Zx<_w],ΒcSŨ'?>Sa`o{GEf}vIX&Gښb魷F_Ϳ’DpYY`f5Z/]@O=6f|_̜j E~{IУ?}(WR rMPy )UoZ)믏i@Ka~7#KR먅=Rk9sbԞ{fl>w{]sMԖZ73ګS;8 %瞋?x]*9~^;PK{Q˖TLvCǺym㏏'>2EU͈qRUO=Mjs^C\?ztܶkK92&w\XͰakQGEwl׿鸶UBN8!;&4r)HU,ofG%c܏}1ƍ~JsuRdzώKO ڵ̛Wr&<蠸3ܴ֩CTE(LGM믏UO>1<7e@ORՉΤV++`{ _I?6<c1,CcI'ň3@@^dO5qD9*2EbĎ;Sx"~4H{#t֧c ש>kZK}z^}cO|b&M=~;)/[}VI쑓O*ʤ)=Rَ))_߅GO9%dzߝB/})]c_رq s%'v-j6lʔXr  "xR÷*gώgQRQ'73G6,%/) $)\3ĶVl7 ? Mfueώ)_1cg;IX/zQۛ1s;S枢S8g}qwLRJئ~)`𪫲E.U/IKWR˟*(#w9fƓ,X\j{ba )s䦛:ƞŵB][.0ӟb/~&_,(W+^7Z2:.-f'PRhK/*tRV_rbf|3gDѭ}CYg Oxb?]S`a}7zkU=IUv,1 ]/0x{{Tg^ #R1ouLz+c3]$=nz}n={_J0=])S`_rYJRšɯ}mV !OghmR-==B@L㮻fc{zkOy~񋒐][nvߕpCL-'UI ?}p3X8WMz}Wz>5]lKm:_֌Օ-i_j]|] RDZ]&Ӻ%VXmm1cƖz:jkkbƨK^Tj0ª,^n-[׬ۊu]lw.]}!D`!E`!E`!E`!E`!E`!6TSSgn T>an-RT*UdvNe~3PE*}/kooϹ4?TDv~l[[['s[:`%0@m9|a=}keʕ4f`p_v]G.|O>iy:@*zDsssGOe`4+@u*U>E/͵94VLX T lZec-`smix.~UOr>%VZKsli-wj^N3 w2͟ u؊r=eh:@aLͱ|.ͭ9922Pf 8o˰aò9s-KsjinxxIc'0UzZ:Ν;7Ksjy+4Vi~3+^-ⱼ-S͗Xbe,Z8421U lfUvL 7`.\˖- ki-ͥ94P흶Nj[2ҷ`RseۣF T ˤ9՛2-r TJpĮ6ұEX+͙e[1. 3P҇TQ&@䁙XpQZ*&OܱՕƊ+4V__.˔g~3P%2UW)>硙4OŔ)EcccP|={NI Sқ T"塙Jeƛ5̙ML81F0ح\*ϟ},͕LCCCG0L|[y8FX TބfvO---ْ&f͚M L0>FUJ[bE,X0"YRU2sq@/az @ԚLޮ)Mt~iߨQ3yfT4җR5e˖es`I~)w9|+o%,c Tބf~$ȷIN߬IvZ/ZD(>G6Z.>`p!j3jbwUWlv{j_/*?xDLe}W2ƌ<ӱ;9"fΜ?/⦛n ɓb]w׿u>{Gw.[o-̙K.ƑS}U~ ZZZ==~ߗ?cْ*~wb-t7+V(onne˖g!/$ | [ K |s_&Ν-)rٿ~,3.g_jU>q7f/yN|+_*K^YfǟtA\s5(K,sח߾6[͟ n8D_|+_.d̖*ַz/Ē%K;f|.[ '9N>=8/],ҒKww=%.Nb?j-zZL%Ӿjʕ|bX\ ΜrGg^/+2RCwӟ}9/5HprWL2%vےc/om.2/}ݲ_gyVPH`N}0oUUF1ߟ>ha-oysV%U뮻3ʪ$i_:>GK̒?xk_'O'x"{Nk/~9=I} xu/yYeT %UIy)oǴó|PVM(]F*׌3p}O,wX`a뮻;Ik~3ӟdI/x~58Թ&{>8ޯӲ^[rtMN:1cƖ1g59O~=__R@1t/~>H^?o$0åUSA;vl `vfMo6:U8)X}wBy'o|}/؟B8)dBTYsnr*wQ/N;# (~X-o˪$Cqwu]u=#SI7񵎖KOvcǤL dm?̳%X̘1#=z%X\v"0;$,`nU͙3ҧX C;N<-;#F0.\-U){ɥ(gc,Ua3H!LB>pJ㟝:tPRJU-Z2/u`#/ $ PzmW)sͷt0yXfs=0 R<03lXY\}ﻲC3@u۶n]q|ƌ%QC .s7e] α;Ʈo]HUA}xDz>f)~${O?өYg_Cv2[ ߾+d;a;9⢋.ᆛbѢE1nܸU)qRˬ4=s]g Շʥ[Ł3[[o+9_gci*Dv&0>wSҚ)U1{%Bz[Ǻ98?E]_ʫ$W^荅 e~)l,&MZٳ;,[by\|%%cV>yͫ'9Vĉg;w^76۬d;sߧ_Cp{#nUq;Moz}+:U ь;6~^\xEOW<fŽ@Va{cS_Wq)HJ23f̈7ᵱ{Ӳ5?<0S^dذaqHuĈ%UfRJRsU$UJzjc3Rg7o~ؤI:M֮)]J-R;bcǎTiʔ)$>S/{ 9z衒cı^vhե66ŋg-<:Eq3A񏿏޺o#G+ Il׿.vq6O˗/ӣc;x?WӧO/پk+oT'FULsWxܿuuk$4L6ӬitsQӦMxԂj…_~\|sEu%.O`(z8qx;K,)9&Us=JGlՕlWj9F*\rYŪU:UjԴ69rP3qVWx_'?IVy'was~b}\qUR\wݿc %&0*ʏ~tfXzn0.]Z2!kT-yz{㨣M|K_Ԇjɓ'@ђ (M$ɂ 㤓>|۳)dr5e]^r}ݧd26|J1s΋|񖷼)&M?D?n=3rdi8bZx/}YۥTO:DZSs`o9>fURt :g>3F1jԨ8fC=gԩST2v/BZ~ew1 ̤E[w}Ǥ#i)/O=TnvK$)ܼNhM6-N= ѝmݦLk<K.Qc뭷 fmVUo~=̙35 ʤ"'xB~K{|gc]w/*x≬T g\Wy<3:Sկ~UrY&f͚UiloEւU:> T*r?@(e:蠬Ք)Sb]cJ[bu^cl9Y˫߯}dwyyjb-裏,ѣGGok}?queRT! ox}-_c.蒸λbΜٱ|MyvX;cիpuMR[Η5cueKڗf\|]P^ŢE;?OgU[*ktlX\p~aU*+xͺli_n+ZڋKtݺveT`H`H`H`H`Hj*n]vnX]ْM릦0ª,^n-[׬ۊu]lw.]}fRfRfRfRfRfRfRfRfRfRfRfRfRfRf0jjj?=`S<@ [3@'2Ty-+3@!6ބa簄gb30u|M Fh!_ڞ)?^pHf`4$C[[[&oaÆ&$BiiX)jjjWZR0f`ꪪL^M&Mu&F PmVbR}!1Ke˖g_ ˗?: =30U*&:eҒ7iƌM`1#FȖ4/dҎ/ypL ^30T K ȬZ*L7n\a`xP1'N+WŢE:1z,d%Qm/$2LП2iIhPH096rl-fRLRE`L˦L=z5jTPB1ƍXtYX" ͤ*4)@df`p*] LZ09"jkMi.-IbZ4#0ULKKK455 @Isj)S__g␌j3Pf imm>ا1ei5,Y+9Fh2=eREԊ)UihhJ=KsiV5e,ńf`p eRUIǏ@9Kii-."Ӈ}i[1M8ӷ_94=/%B4P \[RLj#46f`*UL*Z1IslsnU T!=JĦ.Xwi-͵nsq@*TOr^v14V'WvϹ9Jss@u*7[VfR;Hk нsnUf̥%Tڣ. ![wssS@*o$@>Φv>JČ Z[>&0U(4ƺ?릫}]3s#|\&0U,4体~ U-:nO`Ѳiʺgf]`"0dVco-}m$4 3PE*&#sq ׿K_3B3P6Ps'0U>Wf] uvJ_o0B3Pg~ a GPF(uV1)T3K݅2u7-z+ֵrL>---1_[Һ6 -]ЌP PfN ˤeŊ=Tz*뗖9rd%Ēe͛.^##͛M/~pN J۰hy,}XA1j4iR @)wJKcɬYbs3cgǰ9)|*[9fY)SD]]]P j̛@u *kP2ϏUK 2f@\4.ZC ]?/_l\yg?>Og4jk'0Fvh}yϻXxYh:8|E( 6{!>Oul @PaMӢ1/_0xbŊ1aj#W,Sǟ׽M[[n98Wwť^w}O̙37 )SW vڱsϐp!y;]8?Ņ^OːȎ;-]),X z#U'?/B2_ʩ1qĊ666G ϰ>{gjM`9{^2gωY`g|-q?wީ-]4yxgb֬Y:U*>wo|*${߻J2Z+|fe<7t˚o35* Ѥ*^+"-Y4[n/^{]%TwR/."XreZ;u{3l9q=o~,Tr뭷ױ8wT]Im:f2rnmciWÏW)ũ~۰JsIF3:vqǘ6mj={vGdܸq)#8<ƌSrJ[*YlY|U+1~n9;jNk*T?;3l&Lq;Zr7pSGU|Sq/xT7'n|c>W_}MN!*\dɒ3#0&;츽[t^|ym٦sίgvO9䠎}[m5馛ω~Ykd-_\P͘9vhѢNS{}lﯟf`JuPIwnX4hޗ)|r?hjjO<1qĎ^bڴ33>Xb޼q5UW=fl_%͋Fkkk>{E]9ѣۯyͫ{ '-eR~$3<mm?w3@jo~I%QN:}%uuuo0,tsWeKTӾY*cyۗ\rYt̤=\5kv~:=|l_K @ II!qɓc%뮻T27Gsssg>~hIf-ZG3N3/'攝=;OZV瘨eӟ|0[755_raWEh\f%Ϗ+kcư#b Դ؇İfXS1v`Mjhh@JaZ6mo1-G!O>.jb/+O ,΅1~W;?nii6AV+c,m% @Yͱ|¨(Ǎ%m1P^5WgկM]yX+{ ڗe/P^ˣ}٪ؐ^#cC3O>Tl("CXo[줾b̫msg@YV4. Ν.blJ40o}8' UKRxˎ¿  УÇg;nx[c<](w(]>M^9"nmn9Қ)JݨvmdqYLXm-Ǐ~~i͔^sN8.Ux5o}_Z3_~XhAX5SzE1qbͧDmmP ĆRfu1  P8 Q>|xb[=^qEiW,0/53XmKkPK[mL81=xy{č/=z36LgZoqq7ש=Sj'⾚y27)zaIo~r31<~Ŀ޿ْ3_Ϟ~vj}\1׎h_^NR_zL<^욮/_6<Z pH{i̕W^ukz.[jK֟0W,oE--YXcܸ1PcǎQFţMMN;F]9='zL(74cV3ѓy;* i[c(#UeyvaӾ2{MVeR<<ӚgO+[c0"ͭg5-LyP&t8i߬MT=7+;ܓFOԵÛoR׋׿&ieSlMꪪLs@?+JMPhP3zd:?*6%i롇 v|wl,/?yR[t;_`ī֬˗flۿllLpLݚ%Kmjj.`kmm& Ғnii+G[[{̘eMP0NWٳ[nĈKc;. ϭ+Z%Y5>V5-O<j ?)vac¤)1v¤l|ypx[;oKAշkJReNw?.q g_8~l̛4.ukbE塘@NX)⇟_p^q鄭ĊQcҤ~Ĕ)Sc*#0mXmsG0:?||M4uŗƣ>1V__|(%TmmMXx>\Hfm*\X?,^n-[׬ۊuOźv %0UdCfʷ˃2ŷWZ7pS6iųWDwbMEAPL{`0MM1%)ߚu{M,KM?Sܴc-Zj1"kuƁ׾hy,_jMQ>>j' MIGVMaElՌؘf`Q 6ToCCCӎq!Ŧ ֵVXN[{,YU, Sݯ=R-9Ovc5eǥob!C=$v}q~_f\ck~ϭc}mEkeMΦ' ~yŒ&n[˷[kJDz5Yܹb֎souklR^k`ë>,F}p}ثf5@NX`imi5-VPiڶJY(ky+F`MvG]sR;-om^69jFFkKƂc'SnMGu1mGFQ›t׆?/F鰔| MI \|裏u  ARH{{{t|o1І7>Fn><+)_[e{(V[v) 䡘@L ˔l4gjg:4k2kS8fٔأeLԦw)=x K]aW7>fc8"Vso{K]@lH*3~FYKz8~+6&O6LQ5F{G=ڛbx~_ϦMجLqL^ZC1QTi&UNJfֆxg븈 k0ښkNRhm!ucIœn;y,_9;6$> 햵VZ~M-*L27Q1;FXf:>C]Ѹۨթ5ɗVIjw>sq|X>lDIuL[Y˥McJco]ua5۝D[;257u}o cOu,Yzs u g>菿:}h_d_axˢ~`S#,l j jHe{ Q]P)9\P Diu_±06pdݤL5&!M. hJ P=Jpa"RWW'c H2Va\UѪͱj2a!,x`&$LZyF#M83dhH-SrP&ު~ɾYRt&B-0xp& 1͑fGړ*LvI턋d`eVKy9ٴiSLe˖)ݳgKN:ܡu]H{{Y:u\v٥>̵k~6?Wϟg;孷\uurUWyy/&uPN8ofbc+Wd<~KQΝ#Gq|X"08VphW*9nK{Da4XfP-#V Ebfۚr晫ApJHx D7AXiJ8* ZB鵘P2xė%I+GBޒ({4smݺMnv m~Xmn& xsYrgg5k֚`H+{e׮2<ֽ.V|a@t^{ʫryʜ9E`deՌUFWD<ɴb "G`% Gckdra%}(&6{H[M<Ʉ FՊ2b3p6+`HʶzD'Khl?ie[oM*?f͚% /ʎ;7?(z9ϧC=h`bw~;LGiE ?0JE+w>j5ٳg$sG=h00NW%ɗ||~Y~,Yr@^ Bt: 'i,k7?Gzzwu?|d!,@y#0JfRzR45"?4,1-4a-K8± 3vhDp&Vmo{X~8<[(&^U&2 8i AΖЋ D'W赸O| M'o=o6X&2XɦnLh,HT[c 8we-&[l5UHuϴiӲV.\qB^O'6JT)!h( d_,_5ZYF+̔ŋ;k[&;SCC̛7WFJI>lٲUPapDLtK!D4ܡQ_{1ebe*3xub/aqhep%sqcO,w)j''ʘSmfdGDWSCqK5dkgPb狘J۰ls # g$ 3ΪY2fm+?̘1]E[dVJW9NeijrRj.^شdڴi׭͛c я455%gHC2q± 2)V=FUfBj3VElibUgbegLu`\5|xʄI D)z76sAmMs[3S"CC4* X3o{Ljڧ4MKKrAiwʂB"a*j2m4 tkph fY[RYA"k' h' h5yx5 \JceZ SR\aWXE33ia#0f2S+ɘBa+HŒf:,Q>egCMrE5sLB>3:wD&Gz9aJWU Ȅe+Xi\v)#i4y]3VSٹs4'gG{{ ^(m3e)7'ty/ĉ裏X,MDy}2L4s 4ibꐷz[8p3M8QAJ͓ ޒm۶'^;`|#0r*U&,rh/+b3&ow4!ˈՖdf$pZ2:F ,ɮXۧ rֆL!!ѠÄf4,㌇eL'щe$Ԟ)`kϔҌ5 6As$~֭{TIw^ٷ=~\)O<E{1Rڎ:H37\o5Ld0"zc}4!*k{1YU{B[| Ll,IFLR loՒzI6KHWD3?eMVk'ki Kcq:Y}ZR|aƷLX&Ml VL) 3eL}dT:HFyMImNxತ~T J{ݻw',]D&M]vƍUuRD YbycrbHE֘Sc<+6~Κ F@Y²ihVMoH|S$XeD3Z3 Ī̄%w$ɖZ u\pIWŒS+"7.ufbEn[3] 6NZEzSǯ4a׿)v̚5K_JTY>}Zco&S}r_&&LHڿfZ3G}~ y]fY+v)2hHjyl!ΒS}}2Uo48aZvig ױO^xEf$(3hݐ+KKV[/ h8%fNGliO1%ΦL[$ D^Haz"ЌhLy0"5m5 {>a:EiHFC3Jed{2"I&kH ̈́ej)5/8[)3?Wn g7ݼysOM4lwᄂ0&5LZ[[>G,;w i&S(= bD)} Ae>JPf@ф!qy2zQ穑ofoPfLe /e *XAGJ$B3r.j.&0c2b* ķbfA;dOKȽTqЌ#zL?de졙`d08ZeZgZ#yV 7}}}Y&۶mM6>PٳgIkktuuK[d6mԩSM_$XE8Αf9ܑaݚ5\)ӯ;@"P⃆?t@0۬uvkY+{~Fj%@Zw0jrcLdS_~D1M`jɔ.ftiM&Uk=(-O:5kh8e{eU?03fL7s{ őhuk#M #_!Ö-[MJXG:/<+Lw|J"y6ElI2g.ʶϠ ( ب`´#>_hI> ;pEbH<"`+&+XFb{cA"A cfׯH| iN ^=.kpyoe֙LN[K&83L݉~k԰B3ݖ k+"[8#Ze&0`!0@G&dMv9mB"/(eE#?)-2\ bP$`HzT2@($!0/c& "0r8:& ɾX 9 C!ۇT3y};_@ > 5A%/a =O(2aB3D=$/= JhbGcNP~%[lښ ⩩:fe_ X^~?B&LA{i^ߔ-w/udժ㤶vy{jC` [3ֲŋ9sfk un6~gU6ҽ6SHء?~%2Z10D*3 ͨwt[<-"~~9ԓ㩑I&MƓ\*z/?&N[%Z1 *9ԠcӞ)[8Fe7ct3T=F:5cSa|G` ݑZ3Bc][ծTsH=:)T&g}(2Z Zj)scBP($`H\.|XK;&X^sOܔA`*5z#%W~ux r|j17;!0@u_v*f/A+dfY_Zc,@*Pj؇u@ `z*]4c?^%Q!]jZLtrsc\F` rG?d``@e 'z# D>6tMQt͎**~EC:w\.]]% X 6l^?:ѱ6coVKѮ J0}uS0'D?cӱ6k-ӸLfP>n3oo Ay}(,Ph@I^aF?^5S44X ۪i4`xzNtM[1[ 3`LT?[TSSc{p8,c~]~LS5>w@tLMcmc.PP҅2o޽{\4@R.(k{PtLjŤcmPh@2YskՖI7_ x[Z[[10`XݮDutf@e ,[Lgg t MtLM*1ȍ 3TlUf%Vi&,{3덍 et -E3Ʀe-,T:Pa .VطabcWWcfaVLTPa e2cZQ@L .|֖G{e`ktve{X&58PPtAoft`-2uihh`ݻ$Ui0NdNf V0&z2~_Bٳ L4Ijv^OtLC2'gPP nW ͤv2'NzZ5ttt/)ӪVef{@ \f0UfR X횬eĬfX}fkll4Ug ؗuŴL__SV%10kn-a E` OhZ:H`[և]o .뼫+:ɐ簟>J S++ _cze>fPB3Um X:Xthb-"b=Α ACPJXlonUM ʤ[O=/a*XKЌ 4ٷY k9JvcR`V&:\ffR4~M26 cfkKe Rjx&cP]P% iѤ{2LPJ-*VɷLmdjdߖj@&ݹڂږn?A`G`*ڌJ \+׳cJ$!XTɴ/J6NT'3TLbmOmϔnP!]ƾ(lB0@`*ڌ]_R,f0# dj}`Tm&۾L A|(\LT'3#Xrk2XՋ Lj3鎳d;p -[t `|#08op&1ePJxT'CP(3s3a\@9Iײ_1a 0f2Χ +t*[;'0`J7)pX 9Plڋ[NgҺ{H Pfg zm/v -:)/=.5`CpX0d X  ̺.۷ۏʁUY .r%mOՋ @N }^ \tbctvMxFC390~ejѠNv8HMMMt@ "*&@ >ߌ}~3ƥc_:i&Sp03TLUej2:`sMMx@btr/5440 /YPm U(]Uйetu&Mssb̤b==/鸘NI!4@"0@I& |>]omm 0^h8fҤ+Q66NkRTzJ2ֲUUF?kXFM*C%WE2TzfMC3ڢɪ6B3T3T԰}妦Fill`PLkk.퓁*42fNf`Z02_[0 A3eZ4XЌ->fP2`P~?a kLC3:;h f|f@2P|yssa C Cӛ͸\cP=Pareb 3ǔ|~q:&s;B3TѪ2 Z@tLR} T3TaݾO'ӤI|@v:ckVԠ}LN2W4*-چI'-uuup:clxf>fPhXӊ ce2**~Hz(kX\.x<0|:Ʀcmָ},T>3Tt}Ұ--`t>fG**w~hnZ0rLjk&PPam\.8阛5rg\E !\׵jhhc\9PPo7[bms}iMh@up pD\.T,8JAt-UT3TԠ?Y{*b}&< H`Xcn  -] F}mflf`VP\nb-ÉePPdZ ?e&f@QU7lFrm**HpGTry9B'@Pp'd:)8?T63).1pP~73Uq5@Cp#2J===+lƼSnhP>aIXc5 E`L;v}uLj].us97: 8YԩS;Sff0RVg)y3żrbL{C<cD` 5VA|;[X&1a ErBd:o./eW X 0*L9p[A|B*Ŭ:sT 3 ق'e ʄB!Jz˄v3pH!AgR0{4ΔsT*3( ( p8(ad:X`FϣLϕ-0+ܜ9U؟ Pf@ފQy0% ך3+ӶC%'{đq65 =Q!|3g"0FVL^TnJ 7 ܹW^Gjs o4ۦf#v#?K(;?>`;c!vs!0RHuLap8,^^jj .nC!-*YLQцXA8`2cҭ2ІT~ *5zlוi 0=f@NDsh;$mӪ5VL14> pK__.t%>rJ2SHD+K}_F)xB3`r @Ũ.U`% ½7HMKF*j/5筯gJٚ볂2~O[nWtri<k96w$-[4(So_,300`%۽PiG~g;u| RQa=Б4a/%,\~i#ZF['E!)6F3vLÑss 3`TiD['9B2Y)ɽ/Ⱦڥ{% nw_m/f\RL 6~C(*HϳLKKKTHFQ2Uem&w=)#iOkL^i F[[5)djd}|ŨDP-0FVt..L}IY*'z_cL8Ѫt^>W}}ٖˎ;|ursIM]wN̹ܽg̘sU /0*Fu_v<* i4DdZyTc/>JBHyT0J܇T)5y^*d``Uj; M~`f^RCC"O"2Zb dk4 jPhVHunSe־G5bl%}ؘخXuѪp3!IaLe Ҟi[3xr5qɓ'… O3<ôħ䩧sȟ|C0Hh.S4 lRhmzMXG_d`,0h FC3V[ԩT*J_;v[#_G>r޽[F䨣V)[>dE0,٪RJ:VE/kZ$B)UDO28Z%ܪX.REIggr}ȶmg?Eo~)N'yo0rf@^ zC]8EU_7ah'lBB(P8pu+ Ďs&-\N IW# ͔G)VvߕW|3'|ڄfV~TN:D)3 H**Ǫ+muԎ 2N˄eݥG_۴ej3a h淿] 8X(f6gxՕ|CR[[|f20/_h58C`PLMH4v޿[je#ڎ"FP =U=x BK u0&) ۷/۷o]رü3fG.\r̝;gcV<Ѽ/v˗VL+yŗ䨣V$zޤ:r 7ɣ>.[ldʔ69# +,9ydow/"RWW+f͒O\%^zI*G CUg4 a{h>TsRj>WL[BY! mU [z[XI9t[džA>|{deB---i2:::b!iP ح_L7g+g}N>/JwwOm۶btl}*k֬Mڮ֭{L˭Hϟ' 0vLP(K~ico8<izqG安]ѹ[5nqE.w8[#IQlĖG.pH"ሄpE"aDfV{Q:;ᶿI8Fn(sٲ3L+d2*3cX>?^'̲V dɒ{o0S~ӟ?'oe^7~K9sYӟ~g/Cf^__/ill|iuO~LK+{9 N}}lxͲs.S}Fg?!whE/PfϞ}ݦb>v=&T^SS#`PL혴}FnC"2=^D&Ʉ &8rs{p #1˱pؖTWA`8#]_JÏ2thqt-ڼY:?&3uT~)*3jy7^v/vc5`\k5_LM'e]*W]a[QN8arf/2Xl-^bV 1}4aP-Zؿjӧ>y饗owlִ ZX; G% .o|jӦ*>HԮLxC76$`OQgg8.iϥVIUZ E}BʤI*3?唓#;YtI]w o~Ia˄ ?jL&HcfJW[WoIaV׾"_~sO߱c BˏI۲ϕ 曠 ej *B>m4(cx;ſUAk`8Rz4}}} PmwHCe,>Z3t-ɻMB$6?$\k4D mZ3[,ۖi"dI=9O~*==f~J\ߞ={N>]r:uJbY6cٻw:y{/qZ% ̨/_{3z_n6?Xq\p{d޼%P(dcPɤɿSJ/$rm* /"z{|~j夕T.q;p9Z4K}}\}7\~d%>O%\fY02ʷL8;rR~)-e:5<6Pj-Eȣ9`i,30-:H&NXK,O2EZZb៧/~=̚ &pXN8pgg- P4OIMd,31]8v0s}V%yӧOO,kN;,fd-zcfyժ㤡!iV (Jq}rf={{^~vPs뭷=,HFK&PLag$(EzF@ycs*BïjﻣįiӦ,n9Iẅ́JOeڴiItvvo&,!|C>9sfF3߹sgQSSc*r翐m۶wsL>M9!=/YNmtwF_̲V9s<;JTZhՏxi-/|t2Ї>(\P<fVnrH0VJ]z]]]]nëV>ˤI??~\_&\YY~ϷHww,_6r衇$MGk-[̄Z;Xٽ{|[ߑO\%}}rF~vO_V8`vmo|M>Ok⊏˩,+V+'N0}ꩧgJUW]tFxg}N?80TyK/D'?Y3r_)ő_Eys1wdX&mnM6WʤZtUN+dh@'k9 @={ G0}{;v9^js,b$ޔ`t )mq?2AW=nD<:Jbf~O|^~u3/Gй.'䌞/1wN3m% H\egΜLebjnfx}K.H_>mg:7w>8?ǟԧeڧ?\~~[~e˖7\o BJ_g/LK}фj2WC9!Ug?D(I&w-9JCn&yM{\Uۦm:IlT9 Nq&j2cUqFSkkQG)g.YtI\tr YIپ}y 3f0;wNkնG{3m:R-Z%7翔5k0d]昷h3N+rM-lݺ՜K[C-X@?~yMMMMiWC0z =i&+V'^D )T"^8<5&G~k08xM3]w _N:Q3m49j3wfS`,Pa Rnf9f*̌ӓ_w\j@&]`fB4J cIh ^\gRsC0׾!5Kp`59zb|8=a/|KI6\s͜p©Ւ׿|Ai}ɧ䓟z[d;G^}5v{=UJT`f@UTnɝڼ7i{O/QtqNkЦ=)'\y7O0ie\a|ߔ;tܶgeTL}Z]f_:ϫ .ftjK^qnCziuj$"By pKު Dz{~FisvIߏHoz }viy^7@0ˆ o6>?LfOnᦤ6LG>əga^On*^b+A㏯o};{?/ d:~)/iY\-Z$ֽn0&0FqC|Vnwntt?nEH/D}ۤnI~M27WXFMzcI5,^&mmmf嫮"GyTU!abv,\ nf6o"B`M.|VuK1Z9^7Zvww%?#'^SNy?m@ /@ұw}oٳZ\BQGH3OH|c ow[omY;W̩ޟ00JZltW\ySܯ/SBP[\wʗ=A a7Q@ud:~@Zh̟?Ojk=ya'*i~QcrH:@Qi*8nsɩ^铝!wy٭XG?_?`l8NYx3}X3~_~)&B00Jf![]cs<]#otI,Sb}i8ӝ TܩR*9SDܴcF&L}+&pǶ b>+cyoVTF`"-η7$nlpS[ɓ[>˺cR-"ZLUKT<+I'(\sw-'x`K/,/R۫Y`~bٲeP2ΑWkaWĞYNZ3j䨹u}Ⱥ~JWs|q-&9cxN8PP44s-7W|T,9@̴tʿ[o r95$4s} @1T lLZׁ=miiSS9s '/_|477}gǮ0P*ndr8~v^qfr:sw8/n%l'yLٶ/,!@|~~ DY9Q?^m-$ 9O\MTzXoH__b+jrߐ+By]n~iPLf@ K1rE\5pDr[cE3غ1X6s Ɣ,}[~ 2Z&08MX~W m-9I?s8'5 *e/I83|OO|ӟ~r ( ow ˜w޹2{,(&Ȍ`۬PqB3s.nŚW2{}gP9Z 2Rӥ 0چI+d X4o~[(+,[o'Ya9sf @Qaޠ##)%Lq7,?~mJ9jkS?<,կpP8C>nTn) O|crgW~ӟ7rgJ!&g%RSS#",f@IɂVY I #(>|} 3 S?tԞwsڡTիKZװ?xI {~_4,sw%G`^FN9G험g6/C/rH˥çFۙ e2mݺ-i5s9K; ˼62T(GOP+]auj("_ɴ6o/:t_g2q4I#Pi+:SfIe 8oeX snONsBO俢Ssi{\?dF?n2Ub֬!}R gu C;4Հ (Tc%O佾 k{{v_bZxsJ5eKfPr:ۊ{53tVˁZTҶyMfZ` KSBg3}뭷tq+裏ra#+,ˆ oɽ7$kn3i=9hR`NggWN3ʫrP)%\׳iߘ͇䒋Ij>+̄/'%gѰ>U%t4u=.;t8t&.n.;8GlnWl{t.]~]F/=_(z`t D222VXFҥKLrq;&wer}VXfI& / 1 yV}MF",(GudMP駟O ihh0Ulʁ瓇~$cw%wuB!s?ܹsͺ4#z|ڤ_,6ZGF"6mZ93ͷS3 ?gΡIgy,CX`dvNu l(3אĂ2ֲă3˃>y}fM *xUO>h%mgcYlY<3rY ( h5`4sol۶TKYrE뮆F|YnhK/$Q%D<:?]oZ?q)A[hGUaMU&k֬5S!Zg}ϓ)s }hhc^ZaU#<"OsϽ^?}l{y3ڟ/:kΝ L c=jm4,k˥?wc 0gI,_@hhêUJaV9TWWخhg5aj5J]]] 9Xmy9!-uES-4ϳy) h*j2qČia{XƢmXeX&9ÇӴۺuy?N>$sP!d0EMۄ#랤BА;#s̟?Oݻca+qf2u|>ITN&>ȼ7Zm r䑇io$ )ϗX*6{.s\j&cIK'XkZ']|hpJ+,\0z4-M"˫3s h{/Eshk8(p P">Cs}EЅW>OW|T;n\ wuwR;lȓO>m5QHK +k|iP#7Єm&Lhc9:YAƛ套^}?<ڼui^4~y5qZU^뮻!p+hŪrGdlfKCX._+hpHi%{Z~<##(-*d0ҥ^h>5Lc]x̲VC9SJ z_kԩ:K}S r&X/m;  xN?iD{ͺ=:L`O?k&is䦛l ? h P/vԜ9Ϙj>Guٮdɇ "ijlgBi詣,kp'W|Y=VQֽnz͕BOMMMugn;GLKKKe;B`xތ3Ve ˼I[[ h%՝8>_&L0UtV~Lmf<ϗN8P#}ڰ2j9&|^ 9ÆbҤI'#e3Vj\r ͨ|HLj*|~zp¤}Z1e=&\r)'ࣕ~V[}VfQZu Ah{oo4v`vL7J=EK&eXg!ǬYE =,s+,A Jq,ږj) ^]imOTi4mxIٹsW> hNNn`ZvC^ڶmY>䐃[+djᒧz,/fڳgyJZiF Qa%u [o7뮻A:H6miFBS/Jzs=o)F=DTNn&ٷT0L$v㏓74)qՐZUw6˟9Cwi5A 9 SN[$iIc{*;ZEhIM6?"/Y>3dɒkئ,Xq8ϟ?z{L[&eh vKZgǎIAb3() [rIJ0/;IyBXr=e|c=&:-7ˁ@eVLЇQ5kfˏVТ̘1]N;SIF'xZG[Jrm20u^7ݤIM[ˮ];wL a$U8`kz*V%6m\4s<2 P  {ٲeQ[1U]48{XFiuҪ0x 53f0mRiٳgcve ʑGaB'Vz7olA55n~/^1wJ3ZEEБ>~)w i/28-v]pkhhYfѫBSM|nۜCEoJ0:s۶?mufo%e3Ybyx'>M哦3/G*й.'䌞/1wN3m% H\eڭ=tl҅F3P%3:S_`;5d-0^x<5+ptC)S$>ۦm:IlT9K+N(E)o0q 3t3: zNNz ./(3 -!Hd`:Մetz.3WfP`\q @FQ3̩SO0GRM3Ö9`inn7xS͖}ϙouQHGߑb*4R=~irG}|$[%t2fϟ'3gΐ-[ʮ]_~=LSbIaS׋u~-'N0~ZZZRhX 6fe ʢE dz@L(4B`(3`B̤nz\}v1DShȥ 3` :֒-C#bUuie2mЌVƎL !,+3T\\tn{ 0|PPaRC*3T0 ].-c`Fy>kMcq/:&5au|>)gJ~Ϲçcl:fe *t;֖CMj~.cY:T Dl*wK ihrʍb1tf,oP0@8O0RSSc{p8,cj:fkKK**X<ַ^ty޽ :fbұ6bPPabo2Y|q20n阚YeҵcJ7F* *Xo fotvvJ__Lt,Mtl-|nG?G"fd`޽zccHaC2e-,T:Pa .VطabcWWcfaVLTPa e2cZQ@L .|֖G{e`ktve{X&58PPtAoft`-2uihh`ݻ$Ui0NdNf V0&z2~_Bٳ L4Ijv^OtLC2'gPP nW ͤv2'NzZ5ttt/)ӪVef{@ \f0UfR X횬eĬfX}fkll4Ug ؗuŴL__SV%10kn-a E` OhZ:H`[և]o .뼫+:ɐ簟>J S++ _cze>fPB3Um X:Xthb-"b=Α ACPJXlonUM ʤ[O=/a*XKЌ 4ٷY k9JvcR`V&:\ffR4~M26 cfkKe Rjx&cP] _-2VH&e +dUd҅gmRnV)MUe2me+?`Qa*E}[tZj &k[ePj3*58smd_֎)u [x` #[P%Ӿ|Z+8{>P=0_LbmOmϔnP!]ƾ(lB0@єu 3Ttf*5=]e| 0Ih%S˥Յ @j3eXH @ d:}:V`FoLf}v5@uHC,0*t 3g(3٪ͤ;Βx1(lՒ)4BP7%Tl@)YQ./ A*!0_E3a\@9Iײ_1@I}փ 3`X.DƹL8Chc!uʾ=ݲ ?cH m@2`t!K!-]{qLZc`1CSTt)ۖm.ТcN._R6g(#-Ge]Bf],c_t]ur d E`q WPF' vL>/KKJ1v _1:w&<Ԁg?*-0ɰ^ Sk%8ЀetAmGjjj:`!V1Yf1.I43HV3 DR&F2V50йAFx<B1:9xfȬI[Ug6V~$YZ2PUсkPF']o477i L:.ӛ2tB3TB Q.(cM|3$`p̤IIWWWsmmlL2֤6@ɔflUѹ~Fz ~i3f^GЌh({p ե؁0R2IjXFQNC1-vOLhFh l M9U +yYEL~Lu`~tM:44cG&NV#"e(2M$6"WX& ',`ihF4v' yРLYfJI)t"WX& :onn",chpHzzz˕t +sۨ 3V ǏDƑ\a(Œ1%eci>fN ܎ IYtS \d }LaB3q)5,Ue40& 阚4ke\FKzϩLOy*\?db4ioNtlj{)B4pXٌB3Ǘhۂ9o$![ Nn[@tlMج6*Glƨf@Jav>ɲ= Ev H2Z&Vc݊>τpFܲU`B~yQ5ᾐHSI$mnP:\.xxf$9ˑ+Q<f"i#YJ&ӳA'IJö4K)vcvVFX-91 @f c)^SbYܘZLT#yEI)z0X,:\nq:G/[.08QntMܬ7eaL0\sͷlFL^og?"0OL=’yP(PR?PV 29R)*:P֘`L<+22B5|r$h^\>=")Z۷>"VA h;&p?D򙊡1V[{@ؘ[Kk:Ǘ-tA|2;hU?z.fZ3f GrI1A 't2ZBu(q3co~X`ʮΈ?)#4)SMN\'W|ݕ25F'wOOjkkO,ֲ~o8}B>jPX\}{l۶g=ut @5|577}Iba>eOV;&{lR; .KvI]ܞV1r)d׬yVY!ˌfulWMT )0*Ɠx#َ͐LYtNj g{)֓b=)w]OB'qPnU)9qh5H^s'Xe`hCl ^E&B"*Ñ]!cFeđtye)Δe\I5Ԩ]]]_oxPE`5Bf7:ٳd$ dۧs'@@QSS#'g::2of'0^mٲ5:&3r_\T;Z[[.K_t ƗC),C+ثΤVyTQ%S5Oq9͙Jo;ǤN9 5@H-jg4:y^xᅳ-;?*e Ipط H{{ L8IZ[[ͷnbcC4C==ݲg>q2e+Q-|2zNwBwkIw2ۻ8.R,r8r(>ECkb/ŇKzqa#Q ^zH֪SyѓkYJݦ%쳻CG333rF>k嗿iI 2Ih& >X6?/(Lb eltx&J3!Ӟg)Kk>/ ߸{>sOn2{pƍpi#h\%yFX_[_|q{|xd+{NYTu__2k/`yh~57o|#qӰLa FLL:ˑ ɄB/[Ҋ7NQ_^TR-W^'O8,Tw ] _$O%Q5_{wPG7!Ĺs277.߫yB358f-$^)7-4CҺy3M\DU B~uo`0GZFx0rPR$kZ eھsaciu&Iwccc<7sW+o~b}apSYV#Qȫ.S%L3K_ uUaP:VE~#ѶGz{zʪ_ի?5/3;>FW Ĥ*E%;Fs^}j~-LEVČEeb")Ze=Ɇe2f_'70etLz|?M1qy>^?<U'>w{{;~+>2^WƏQ(Y>{˗[xޥfCK\)f*b"L`Y FI 3V0թ2S49EAA_팶[aS*V8BL;_pxOMã]xa>)GMWĹ8?fws\ephݿߏ0,3ٰLQ.#/ˑV vY$ӊ0.PtMҟO^|<$}~8mgzW\O?gַrt;87i<= G^x=#´2˴$Bzϝ;#Wz5~fW0 e:}^6@P%_^z "<2- '龐:8υe,3/j߈ߠ>iL ;';_Ξ7&?ǔaR2exN} t=/%LwH:=;>'=13!Gs>/,(gyǭjO{fYOs2i?|tmJIBIɓ'agZȍuZ(/g0.\7΍zx~L>&ep𚆃~. u2v0]vpeLQgUf666jbN?ɿkIRb &uttt`& ed3Xem,TWv^L%~[߼~νF!|<3{|? @$;~f},tp:'UR2[* q⺚3sG=z/|?2q{&0%lŘ?2!dۡx _ƊB1y $oV?M.e'{h[O3o_x  $]M$~qWsD2&*'0L?#?'%AqT1/j8 (#[ܹs{ XMQ8 d32q͖` %Ei-XŏK3e{5e,%mXqL?[o߾to={ƨ3aA`BHzIݝL_ $0wrfb8svR7IwL*$Ai; P'{Fsp}x$St#kY&80sFΒL1PcI&NDw8zǏ}~޽~֭[۩b%yd1`L6DS) ˔hN$,-R`&}\74חä9}⧚3ZɎA(8}<% t d8Vd/Z")IgDzaٗ󎫎5pX8yTz5kfU)+ DmVYت2ihLdWYϭ,R`&EE8.]ZV"(XL8C.5@U^YLb3 a`լdP&!0s V:$&0OpX23 3 'M8nmi ,Vz"0J`RfX)3V +7nkIENDB`bazaar-orig-v0.7.14/CONTRIBUTING.md0000664000175000017500000000677315166123241015406 0ustar hasanhasan# Contributing Guide Thank you for contributing to Bazaar! Here are some instructions to get you started. * [New Contributor Guide](#contributing-guide) * [Ways to Contribute](#ways-to-contribute) * [Find an Issue](#find-an-issue) * [Ask for Help](#ask-for-help) * [Pull Request Lifecycle](#pull-request-lifecycle) * [Development Environment Setup](#development-environment-setup) * [Sign Your Commits](#sign-your-commits) * [Pull Request Checklist](#pull-request-checklist) Welcome! We are glad that you are here! 💖 As you get started, you are in the best position to give us feedback on areas of our project that we need help with including: * Problems found during setting up a new developer environment * Documentation * Bugs in our automation scripts and actions If anything doesn't make sense, or doesn't work when you run it, please open a bug report and let us know! ## Ways to Contribute We welcome many different types of contributions including: * New features * Builds, CI/CD * Bug fixes * Documentation * Issue Triage * Answering questions in Discussions * Release management * [Translations](https://github.com/bazaar-org/bazaar/blob/master/TRANSLATORS.md) - follow the dedicated instructions in that document ## Find an Issue These are the issues that need the most amount of attention and would be an effective way to get started: - [Help Wanted issues](https://github.com/bazaar-org/bazaar/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22help%20wanted%22) - [Good first issues](https://github.com/bazaar-org/bazaar/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22) Sometimes there won’t be any issues with these labels. That’s ok! There is likely still something for you to work on. If you want to contribute but you don’t know where to start or can't find a suitable issue then feel free to post on the [discussion forum](https://github.com/bazaar-org/bazaar/discussions) Once you see an issue that you'd like to work on, please post a comment saying that you want to work on it. Something like "I want to work on this" is fine. ## Ask for Help The best way to reach us with a question when contributing is to ask on: * The original github issue you want to contribute to * The [discussions](https://github.com/bazaar-org/bazaar/discussions) area ## Building GNOME Builder or ```sh just build-flatpak ``` See [Flatpak Docs](https://docs.flatpak.org/en/latest/flatpak-builder.html) ### Find out which version is installed for bug reports ```sh flatpak info io.github.kolunmi.Bazaar ``` ### Verbose output ```sh G_MESSAGES_DEBUG=all flatpak run io.github.kolunmi.Bazaar ``` ## Pull Request Lifecycle [Instructions](https://contribute.cncf.io/maintainers/github/templates/required/contributing/#pull-request-lifecycle) ⚠️ **Explain your pull request process** ## Sign Your Commits [Instructions](https://contribute.cncf.io/maintainers/github/templates/required/contributing/#sign-your-commits) ## Pull Request Checklist When you submit your pull request, or you push new commits to it, our automated systems will run some checks on your new code. We require that your pull request passes these checks, but we also have more criteria than just that before we can accept and merge it. We recommend that you check the following things locally before you submit your code: - [ ] Use the GNU Style Guide - [ ] Format your commits using `clang-format`; see [.clang-format](/.clang-format) - [ ] Follow the [GNOME Commit Style](https://handbook.gnome.org/development/commit-messages.html) bazaar-orig-v0.7.14/meson.build0000664000175000017500000000740315166123241015306 0ustar hasanhasanproject('bazaar', 'c', version: run_command('version.sh', 'get-vcs').stdout().strip(), meson_version: '>= 1.0.0', default_options: [ 'warning_level=2', 'werror=false', 'c_std=gnu11', ], ) python3 = find_program('python3') i18n = import('i18n') if get_option('im_a_translator') subdir('po') else gnome = import('gnome') cc = meson.get_compiler('c') project_c_args = [] test_c_args = [ '-Wcast-align', '-Wdeclaration-after-statement', '-Werror=address', '-Werror=array-bounds', '-Werror=empty-body', '-Werror=implicit', '-Werror=implicit-function-declaration', '-Werror=incompatible-pointer-types', '-Werror=init-self', '-Werror=int-conversion', '-Werror=int-to-pointer-cast', '-Werror=main', '-Werror=misleading-indentation', '-Werror=missing-braces', '-Werror=missing-include-dirs', '-Werror=nonnull', '-Werror=overflow', '-Werror=parenthesis', '-Werror=pointer-arith', '-Werror=pointer-to-int-cast', '-Werror=redundant-decls', '-Werror=return-type', '-Werror=sequence-point', '-Werror=shadow', '-Werror=strict-prototypes', '-Werror=trigraphs', '-Werror=undef', '-Werror=write-strings', '-Wformat-nonliteral', '-Wignored-qualifiers', '-Wimplicit-function-declaration', '-Wlogical-op', '-Wmissing-declarations', '-Wmissing-format-attribute', '-Wmissing-include-dirs', '-Wmissing-noreturn', '-Wnested-externs', '-Wno-cast-function-type', '-Wno-dangling-pointer', '-Wno-missing-field-initializers', '-Wno-sign-compare', '-Wno-unused-parameter', '-Wold-style-definition', '-Wpointer-arith', '-Wredundant-decls', '-Wstrict-prototypes', '-Wswitch-default', '-Wswitch-enum', '-Wundef', '-Wuninitialized', '-Wunused', '-fno-strict-aliasing', ['-Werror=format-security', '-Werror=format=2'], ] if get_option('buildtype') != 'plain' test_c_args += '-fstack-protector-strong' endif foreach arg: test_c_args if cc.has_multi_arguments(arg) project_c_args += arg endif endforeach add_project_arguments(project_c_args, language: 'c') if get_option('bge_only') subdir('bge') else config_h = configuration_data() config_h.set_quoted('PACKAGE_VERSION', meson.project_version()) config_h.set_quoted('GETTEXT_PACKAGE', 'bazaar') config_h.set_quoted('LOCALEDIR', get_option('prefix') / get_option('localedir')) config_h.set_quoted('DONATE_LINK', 'https://ko-fi.com/kolunmi') config_h.set_quoted('RELEASE_PAGE', run_command('version.sh', 'get-gh-release').stdout().strip()) dl_worker_bin_name = 'bazaar-dl-worker' config_h.set_quoted('DL_WORKER_BIN_NAME', dl_worker_bin_name) if get_option('hardcoded_main_config_path') != '' config_h.set_quoted('HARDCODED_MAIN_CONFIG', get_option('hardcoded_main_config_path')) endif if get_option('hardcoded_blocklist_path') != '' config_h.set_quoted('HARDCODED_BLOCKLIST', get_option('hardcoded_blocklist_path')) endif if get_option('hardcoded_content_config_path') != '' config_h.set_quoted('HARDCODED_CONTENT_CONFIG', get_option('hardcoded_content_config_path')) endif if get_option('sandboxed_libflatpak') config_h.set_quoted('SANDBOXED_LIBFLATPAK', '1') endif if get_option('development') config_h.set10('DEVELOPMENT_BUILD', get_option('development')) endif configure_file(output: 'config.h', configuration: config_h) add_project_arguments(['-I' + meson.project_build_root()], language: 'c') subdir('bge') subdir('data') subdir('src') subdir('po') gnome.post_install( glib_compile_schemas: true, gtk_update_icon_cache: true, update_desktop_database: true, ) endif endif bazaar-orig-v0.7.14/Justfile0000664000175000017500000000467515166123241014664 0ustar hasanhasan# These are just convenience scripts, NOT a build system! appid := env("BAZAAR_APPID", "io.github.kolunmi.Bazaar") manifest := "./build-aux/flatpak/" + appid + ".json" branch := env("BAZAAR_BRANCH", "master") just := just_executable() alias run := run-base run-base: build-base ./build/src/bazaar build-base: meson setup build --wipe ninja -C build build-flatpak $manifest=manifest $branch=branch: #!/usr/bin/env bash set -xeuo pipefail flatpak --user remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo FLATPAK_BUILDER_DIR=$(realpath ".flatpak-builder") BUILDER_ARGS+=(--default-branch="${branch}") BUILDER_ARGS+=(--state-dir="${FLATPAK_BUILDER_DIR}/flatpak-builder") BUILDER_ARGS+=("--user") BUILDER_ARGS+=("--ccache") BUILDER_ARGS+=("--force-clean") BUILDER_ARGS+=("--install") BUILDER_ARGS+=("--disable-rofiles-fuse") BUILDER_ARGS+=("${FLATPAK_BUILDER_DIR}/build-dir") BUILDER_ARGS+=("${manifest}") if which flatpak-builder &>/dev/null ; then flatpak-builder "${BUILDER_ARGS[@]}" else flatpak run org.flatpak.Builder "${BUILDER_ARGS[@]}" fi build-flatpak-bundle $appid=appid: flatpak build-export repo "${FLATPAK_BUILDER_DIR}/build-dir" flatpak build-bundle repo "${appid}".flatpak "${appid}" build-rpm: #!/usr/bin/env bash mkdir -p rpmbuild podman run --rm -i -v .:/build:Z -v ./rpmbuild:/root/rpmbuild:Z registry.fedoraproject.org/fedora:latest <<'EOF' set -xeuo pipefail dnf install -y rpmdevtools mkdir -p $HOME/rpmbuild/SOURCES RPMDIR="/build/build-aux/rpm" cp "${RPMDIR}"/* $HOME/rpmbuild/SOURCES spectool -agR "${RPMDIR}"/bazaar.spec dnf builddep -y "${RPMDIR}"/bazaar.spec rpmbuild -bb "${RPMDIR}"/bazaar.spec EOF [private] default: @{{ just }} --list # Check just Syntax [group('just')] check: #!/usr/bin/bash find . -type f -name "*.just" | while read -r file; do echo "Checking syntax: $file" {{ just }} --unstable --fmt --check -f $file done echo "Checking syntax: Justfile" {{ just }} --unstable --fmt --check -f Justfile # Fix {{ just }} Syntax [group('{{ just }}')] fix: #!/usr/bin/bash find . -type f -name "*.just" | while read -r file; do echo "Checking syntax: $file" {{ just }} --unstable --fmt -f $file done echo "Checking syntax: Justfile" {{ just }} --unstable --fmt -f Justfile || { exit 1; } update-flatpak: bazaar-orig-v0.7.14/TRANSLATORS-ZH-CN.md0000664000175000017500000001010515166123241016110 0ustar hasanhasan# 翻译者指南 感谢你对翻译 Bazaar 的兴趣!🏷️🗺️💜 一些基本规则: * 你必须精通你所贡献的语言。 * **严禁**使用 LLM 生成译文。如果你这样做,你将被项目作者禁止参与此项目。 * flathub.org 本身就有良好的中文支持,因此 Bazaar 里 Flathub 页面的翻译应当和 flathub.org 高度一致。 即使 flathub.org 中个别翻译可能并不恰当,也请直接采用 flathub.org 的原文。 例如 https://flathub.org/zh-Hans/apps/category/game/subcategories/ArcadeGame 里将 Arcade 翻译为“游乐中心”,虽然实际上是“街机”更合适,但我们依旧选择直接采用“游乐中心”作为翻译 ## 统一术语 Uninstall 为“卸载”而非“删除” 根据: ```bash ❯ flatpak uninstall --help 用法: flatpak uninstall [选项…] [引用…] - 卸载应用程序或运行时 ... ``` Donate 为“捐助”而非“捐赠” 根据 flathub.org ## 基本流程 Fork 本项目(以便稍后开启 PR)并克隆仓库。然后确保你的当前目录位于 Bazaar 项目的根目录: ```sh # 将 '...' 替换为你拥有写入权限的 Bazaar Fork 的 URL git clone ... cd bazaar ``` # 自动设置 完成上述操作后,你可以运行 `./translators.sh` 并按照屏幕上的提示进行操作。该脚本会显示当前 `po/LINGUAS` 的内容。如果一切正确,输入 `Y` 并按回车。随后脚本会要求你输入语言代码,请输入并回车。脚本现在将生成一个新的 `po` 文件或更新现有文件,以便所有新的待翻译字符串都可用。 现在,你可以使用文本编辑器或翻译编辑器(POEdit、GTranslator、Lokalize 等)打开 `po` 文件并开始翻译。完成后,提交你的更改并在 GitHub 上提交 Pull Request(PR)。 # 手动设置 完成克隆后,使用 Meson 设置项目,并将 `im_a_translator` 标志设为 `true`: ```sh meson setup build -Dim_a_translator=true ``` 接下来,进入构建目录: ```sh cd build ``` 运行以下命令生成主 `pot`(**P**ortable **O**bject **T**emplate)文件: ```sh meson compile bazaar-pot ``` 你可能会看到一堆警告 `blp` 扩展名未知的输出,可以安全忽略它。 最后,仍然在构建目录内,运行以下命令来更新和/或创建 `po`(**P**ortable **O**bject)文件: ```sh meson compile bazaar-update-po ``` 现在,你可以使用文本编辑器或翻译编辑器([POEdit](https://flathub.org/apps/net.poedit.Poedit)、[GTranslator](https://flathub.org/apps/org.gnome.Gtranslator)、[Lokalize](https://flathub.org/apps/org.kde.lokalize) 等)打开 `po` 文件并开始翻译。 完成后,提交你的更改并在 GitHub 上提交 PR。请确保只提交与你的翻译相关的文件。 ## 更新现有翻译 根据上述命令再次生成全新的 `.pot` 文件(如有必要)。 ```sh msgmerge --update --verbose po/zh_CN.po po/bazaar.pot ``` 请在 PR 中将上述更新步骤作为一个单独的提交(Commit),以便于代码审查。谢谢! ## 测试你的翻译 确保使用简体中文对应的[语言代码](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes)"zh_CN"! ```sh msgfmt po/zh_CN.po -o bazaar.mo ``` 复制 `.mo` 文件,使 Bazaar 能够识别它: ```sh sudo cp bazaar.mo /var/lib/flatpak/runtime/io.github.kolunmi.Bazaar.Locale/x86_64/stable/active/files/zh/share/zh_CN/LC_MESSAGES/ ``` 确保先结束 Bazaar 的后台进程,以便应用所需的更改/语言。 ```sh killall bazaar ``` 覆盖使用的语言并启动 Bazaar: ```sh LANGUAGE=zh_CN flatpak run io.github.kolunmi.Bazaar ``` # 翻译者注意事项 自动和手动流程都可能生成标记为 `fuzzy`(模糊)的条目。这意味着对于这些条目,`gettext` 尝试从现有的翻译中推导结果。某些翻译软件(如 Lokalize)会利用此标记将字符串设为“未审核”,并在条目被标记为完成时移除标记。如果你使用文本编辑器处理 pot 文件,请务必手动删除你认为已完成条目的 `fuzzy` 标记,否则你的翻译将不会出现在 Bazaar 中。 bazaar-orig-v0.7.14/TRANSLATORS-PL.md0000664000175000017500000001036715166123241015616 0ustar hasanhasan# Instrukcje dla tłumaczy Dziękuję za wasze zainteresowanie w tłumaczeniu Bazaar'u! 🏷️🗺️💜 Oto parę podstawowych zasad: * Musisz być biegły w języku, na który będziesz tłumaczyć. * Nie korzystaj z [SI](https://pl.wikipedia.org/wiki/Sztuczna_inteligencja), aby wygenerować tłumaczenie (Sam mógłbym to zrobić). Jeśli to zrobisz, zablokuję cię. * Jeśli edytujesz istniejące tłumaczenie zapoznaj się z `TRANSLATORS-[kod języka].md`, aby zapoznać się z zasadami obecnymi dla tego języka. Tłumaczenie na język polski: * Zanim rozpoczniesz tłumaczenie zapoznaj się z http://fsc.com.pl/poradnik/ * Przydatne strony: - Słownik Diki - https://www.diki.pl/ - Słownik Bab.la - https://bab.la/ - Słownik Cambridge - https://dictionary.cambridge.org/ * Słowniki zapisane w podpunkcie "Przydatne strony" mają funkcje tłumaczenia całych wyrażen i zdań, lecz proszę z nich nie korzystać, bo to nie są dokładne tłumaczenia. * Proszę również ogranicznyć korzystanie z serwisów takich jak Google Tłumacz, DeepL, itp. ## Procedury podstawowe Utwórz fork projektu (tak abyś mógł później zrobić pull request) i skonuj repozytorium. Następnie upewnij się, że jesteś w folderze odpowiadającym budową do podstawy repozytorium: ``` # Zmień '...' na adress URL twojego forku Bazaar'u, # w którym masz uprawnienia do zapisywania git clone ... cd bazaar ``` Nie zamykaj okna terminala # Konfiguracja Automatyczna Dodaj kod języka docelowego do `po/LINGUAS`. Na przykład, jeśli dodajesz hiszpańskie tłumaczenie, wstaw `es` do nowej linijki, upewniając się, że lista jest w kolejności alfabetycznej. Zatem jeśli `po/LINGUAS` wygląda następująco: ``` # Please keep this file sorted alphabetically. ab en_GB ms ``` musisz zmienić to na: ``` # Please keep this file sorted alphabetically. ab en_GB es ms ``` Jak już to zrobisz, możesz uruchomić `./translators.sh` i podążać za instrukcjami widocznymi na ekranie. Skrypt pokaże ci jak plik `po/LINGUAS` aktualnie wygląda, jeśli wszystko się zgadza naciśnij Y, a następnie enter. Następnie skrypt poprosi cię o wprowadzenie kodu języka docelowego, wpisz go, a następnie naciśnij enter. Następnie skrypt wygeneruje nowy plik `po` lub zaktualizuje istniejący, tak aby wszystkie przetłumaczalne linijki były dostępne. Teraz jesteś gotowy, aby otworzyć swój plik `po` w wybranym edytorze tekstu lub edytorze tłumaczeń (POEdit, GTranslator, Lokalize, itp.) i rozpocząć proces tłumaczenia. Jak już skończysz, skommituj swoje zmiany i utwórz pull request na githubie. # Konfiguracja Ręczna Jak już to zrobisz, skonfiguruj projekt za pomocą mesona z flagą `im_a_translator` ustawioną na `true`: ```sh meson setup build -Dim_a_translator=true ``` Dodaj kod języka docelowego do `po/LINGUAS`. Na przykład, jeśli dodajesz hiszpańskie tłumaczenie, wstaw `es` do nowej linijki, upewniając się, że lista jest w kolejności alfabetycznej. Zatem jeśli `po/LINGUAS` wygląda następująco: ``` # Please keep this file sorted alphabetically. ab en_GB ms ``` musisz zmienić to na: ``` # Please keep this file sorted alphabetically. ab en_GB es ms ``` Następnie, przejdź do katalogu `build`: ```sh cd build ``` Uruchom tą komendę, aby wygenerować główny plik `pot` (**P**ortable **O**bject **T**emplate): ```sh meson compile bazaar-pot ``` Na wierszu poleceń może wyskoczyć mnóstwo błędów o tym, że rozszerzenie `blp` jest nieznane. Możesz je zignorować. Wreszcie, wciąż będąc w katalogu `build`, uruchom następującą komendę, aby zaktualizować i/lub stworzyć pliki `po` (**P**ortable **O**bject): ```sh meson compile bazaar-update-po ``` Teraz jesteś gotowy, aby otworzyć swój plik `po` w wybranym edytorze tekstu lub edytorze tłumaczeń (POEdit, GTranslator, Lokalize, itp.) i rozpocząć proces tłumaczenia. Jak już skończysz, skommituj swoje zmiany i utwórz pull request na githubie. ## Testowanie swojego tłumaczenia Dostosuj do swojego [kodu języka](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes)! ``` msgfmt po/de.po -o bazaar.mo sudo cp bazaar.mo /usr/share/locale/de/LC_MESSAGES/ ``` Upewnij się, że zatrzymasz wszystkie utuchomione instancje Bazaar'u. ``` killall bazaar ``` ``` LANGUAGE=de bazaar ``` bazaar-orig-v0.7.14/.devcontainer/0000775000175000017500000000000015166123241015677 5ustar hasanhasanbazaar-orig-v0.7.14/.devcontainer/Dockerfile0000664000175000017500000000075115166123241017674 0ustar hasanhasanFROM fedora:rawhide RUN dnf update -y && dnf install -y \ meson \ ninja \ cmake \ just \ git \ blueprint-compiler \ desktop-file-utils \ gtk4-devel \ libadwaita-devel \ libdex-devel \ flatpak-devel \ libxmlb-devel \ appstream-devel \ glycin-devel \ glycin-gtk4-devel \ libyaml-devel \ libsoup3-devel \ json-glib-devel \ md4c-devel \ webkitgtk6.0-devel \ libsecret-devel \ libproxy-devel \ clangd bazaar-orig-v0.7.14/.devcontainer/devcontainer.json0000664000175000017500000000136615166123241021261 0ustar hasanhasan{ "name": "Bazaar devcontainer", "build": { "dockerfile": "Dockerfile" }, "features": { "ghcr.io/devcontainers/features/common-utils:2": { "installZsh": "false", "username": "vscode", "userUid": "1000", "userGid": "1000", "upgradePackages": "true" } }, "remoteUser": "vscode", "customizations": { "vscode": { "extensions": [ "ms-vscode.cpptools-extension-pack", "bodil.blueprint-gtk" ] } }, // Wayland support "containerEnv": { "WAYLAND_DISPLAY": "${localEnv:WAYLAND_DISPLAY}", "XDG_RUNTIME_DIR": "${localEnv:XDG_RUNTIME_DIR}", "XDG_SESSION_TYPE": "${localEnv:XDG_SESSION_TYPE}" }, "mounts": [ "source=${localEnv:XDG_RUNTIME_DIR},target=${localEnv:XDG_RUNTIME_DIR},type=bind,consistency=cached" ] }bazaar-orig-v0.7.14/TRANSLATORS-FR.md0000664000175000017500000001225615166123241015611 0ustar hasanhasan# Instructions pour les traducteurs Merci pour votre intérêt à traduire Bazaar ! 🏷️🗺️💜 Ceci est une adaptation française de `TRANSLATORS.md` pour la traduction française spécifiquement. Voici quelques règles simples: * Vous devez parler couramment Français et avoir une bonne compréhension de l'anglais * L'utilisation de modèles de langue (IA) pour générer du texte dans les fichiers est interdite (N'importe qui pourrait le faire). Si vous le faite, vous serez banni du projet par le créateur * Le but n'est pas de fournir une traduction littérale, mais une expérience claire et complète aux utilisateurs francophones * Utilisez `chore(po): update French translation` comme titre de Pull Request pour être uniforme avec les autres langues > Note : La section "Recommandées" dépend du système dans lequel est fourni Bazaar - de plus il n'y a pas encore de système de traduction pour cette page là. ## Installation > Pour traduire et soumettre votre traduction, il est recommandé de savoir utiliser Git, la plateforme Github et un éditeur de traductions comme [celui fourni par Gnome](https://flathub.org/fr/apps/org.gnome.Gtranslator) par exemple. Vous devrez fork le projet et le cloner sur votre machine - afin de pouvoir soumettre votre traduction dans un Pull Request après. Ensuite vous devrez vous assurez que le dossier actuellement ouvert est le dossier racine de Bazaar. ## Mise en place ### Automatique Une fois que c'est fait, vous pourrez exécuter `./translators.sh` et suivre les différentes instructions (en anglais). Le script va vous montrer l'état actuel de `po/LINGUAS`. Si tout est correct, tappez `Y` et appuyez sur entrée. Après cela, le script va vous demander votre code de langue (`fr`), écrivez le et appuyez sur entrée. Le script va générer un nouveau fichier `po` ou mettre à jour le fichier existant avec de nouvelles entrées traduisibles. Vous êtes dorénavant prêts à ouvrir le fichier `po` dans votre éditeur de texte ou votre éditeur de traduction ([POEdit](https://flathub.org/apps/net.poedit.Poedit), [GTranslator](https://flathub.org/apps/org.gnome.Gtranslator), [Lokalize](https://flathub.org/apps/org.kde.lokalize), etc.) et à commencer à traduire. Une fois que vous avez fini, envoyez vos commits et soumettez un Pull Request sur Github. Faites attention à n'envoyez que le(s) fichier(s) liés à votre traduction. ### Manuelle Une fois que c'est fait, mettez en place meson avec le flag `im_a_translator` mis à `true`: ```sh meson setup build -Dim_a_translator=true ``` Ensuite ouvrez le dossier `build`: ```sh cd build ``` Et exécutez la commande suivante pour générer le fichier `pot` (**P**ortable **O**bject **T**emplate) principal : ```sh meson compile bazaar-pot ``` Il se pourrait que vous verrez pas mal de messages disant que l'extension `blp` est inconnue - vous pouvez les ignorer. Enfin, toujours dans le dossier build, exécutez la commande suivante pour mettre à jour ou créer le fichier `po` : ```sh meson compile bazaar-update-po ``` Vous êtes dorénavant prêts à ouvrir le fichier `po` dans votre éditeur de texte ou votre éditeur de traduction ([POEdit](https://flathub.org/apps/net.poedit.Poedit), [GTranslator](https://flathub.org/apps/org.gnome.Gtranslator), [Lokalize](https://flathub.org/apps/org.kde.lokalize), etc.) et à commencer à traduire. Une fois que vous avez fini, envoyez vos commits et soumettez un Pull Request sur Github. Faites attention à n'envoyez que le(s) fichier(s) liés à votre traduction. ## Mettre à jour la traduction existante Générez à nouveau un fichier `.pot` (si nécessaire) à l'aide des commandes ci-dessus. ```sh msgmerge --update --verbose po/fr.po po/bazaar.pot ``` Veuillez créer un commit séparé pour la mise à jour précédente dans votre Pull Request afin de faciliter la révision. Merci ! ## Tester la traduction Depuis le dossier de Bazaar, exécutez la commande suivante : ```sh msgfmt po/fr.po -o bazaar.mo ``` Ensuite copiez le fichier `.mo` pour que Bazaar puisse le voir : ```sh sudo cp bazaar.mo /var/lib/flatpak/runtime/io.github.kolunmi.Bazaar.Locale/x86_64/stable/active/files/fr/share/fr/LC_MESSAGES/ ``` Assurez-vous d'abord de tuer le processus d'arrière-plan de Bazaar afin que les modifications/la langue souhaitées soient utilisées : ```sh killall bazaar ``` Et ensuite redémarrez Bazaar pour voir vos traductions ! >Si vous n'avez pas votre système en français, vous pouvez utiliser la commande suivante pour lancer Bazaar en français: ```sh LANGUAGE=fr flatpak run io.github.kolunmi.Bazaar ``` ## Notes des traducteurs Les processus automatiques et manuels peuvent générer des entrées marquées comme « floues » (`fuzzy`). Cela signifie que pour ces entrées, `gettext` a tenté de dériver une traduction préexistante. Certaines suites de traduction, comme Lokalize, utilisent ce marquage pour définir les chaînes comme non révisées et les supprimer lorsque l'entrée est marquée comme terminée. Lorsque vous travaillez avec des fichiers pot à l'aide d'un éditeur de texte, veillez à supprimer vous-même les marques `fuzzy` des entrées que vous considérez comme terminées, sinon votre traduction n'apparaîtra pas dans Bazaar. bazaar-orig-v0.7.14/TRANSLATORS.md0000664000175000017500000001016715166123241015303 0ustar hasanhasan# Instructions for Translators Thank you for your interest in translating Bazaar! 🏷️🗺️💜 Some basic rules: * You must be fluent in the language you contribute * You may not use llms to generate the strings (I could do that). If you do, I will ban you from the project * If you are editing existing translation, make sure to check rules for that language in `TRANSLATORS-[language code].md` file. ## Basic Process Fork the project (so you can open a PR later) and clone the repo. Then make sure your current directory is the bazaar project root: ```sh # Replace '...' with the URL of your Bazaar fork # for which you have write permissions git clone ... cd bazaar ``` # Automatic Setup Once you've done that, you can run `./translators.sh` and follow instructions present on the screen. The script will show you what `po/LINGUAS` currently looks like. If everything is correct, type `Y` and press enter. After that the script will ask you to enter language code, please enter it, and press enter. The script will now generate a new `po` file or update an existing one such that any new translatable strings will be available. You are now ready to open your `po` file in your text editor or translation editor (POEdit, GTranslator, Lokalize, etc.) and begin translating. When you are done, commit your changes and submit a pull request on github. # Manual Setup Once you've done that, setup the project with meson with the `im_a_translator` flag set to `true`: ```sh meson setup build -Dim_a_translator=true ``` Add your language identifier to `po/LINGUAS`. For example, if you are adding a Spanish translation, insert `es` into the newline-separated list, keeping it sorted alphabetically. So if the `po/LINGUAS` file currently looks like this: ``` # Please keep this file sorted alphabetically. ab en_GB ms ``` you will edit the file to look like this: ``` # Please keep this file sorted alphabetically. ab en_GB es ms ``` Next, enter the build directory: ```sh cd build ``` Run this command to generate the main `pot` (**P**ortable **O**bject **T**emplate) file: ```sh meson compile bazaar-pot ``` You might get a bunch of output complaining that the `blp` extension is unknown. You can ignore this. Finally, still inside the build directory, run the following command to update and/or create the `po` (**P**ortable **O**bject) files: ```sh meson compile bazaar-update-po ``` You are now ready to open your `po` file in your text editor or translation editor ([POEdit](https://flathub.org/apps/net.poedit.Poedit), [GTranslator](https://flathub.org/apps/org.gnome.Gtranslator), [Lokalize](https://flathub.org/apps/org.kde.lokalize), etc.)and begin translating. When you are done, commit your changes and submit a pull request on GitHub. Make sure to only commit files that are related to your translation. ## Update existing translations Generate a fresh `.pot` file again (if necessary) with the commands from above. ```sh msgmerge --update --verbose po/de.po po/bazaar.pot ``` Please make the previous update step a separate commit in your PR so it is easier to review. Thanks! ## Test your translations Replace "de" with your [Language code](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes)! ```sh msgfmt po/de.po -o bazaar.mo ``` Copy the `.mo` file so Bazaar can see it ```sh sudo cp bazaar.mo /var/lib/flatpak/runtime/io.github.kolunmi.Bazaar.Locale/x86_64/stable/active/files/de/share/de/LC_MESSAGES/ ``` Make sure to kill the background process from Bazaar first so the desired changes/language will be used. ```sh killall bazaar ``` Override the used Language and launch Bazaar ```sh LANGUAGE=de flatpak run io.github.kolunmi.Bazaar ``` # Notes From Translators Both automatic and manual processes may generate entries marked as `fuzzy`. This means that for such entries, `gettext` attempted to derive previously existing translation. Some translation suites, like Lokalize, will utilize this marking to set strings as unreviewed and remove when the entry is marked finished. When working with pot-files using text editor, be sure to remove `fuzzy` marks yourself from entries you deem finished, else your translation will not appear in Bazaar. bazaar-orig-v0.7.14/bazaar.doap0000664000175000017500000000253615166123241015253 0ustar hasanhasan bazaar Discover and install applications A new app store for Linux with a focus on discovering and installing applications and addons from Flatpak remotes, particularly Flathub. C GTK 4 Libadwaita Kolunmi kolunmi bazaar-orig-v0.7.14/.well-known/0000775000175000017500000000000015166123241015313 5ustar hasanhasanbazaar-orig-v0.7.14/.well-known/funding-manifest-urls0000664000175000017500000000006015166123241021453 0ustar hasanhasanhttps://www.kolunmi.net/ https://usebazaar.org/ bazaar-orig-v0.7.14/.foundry/0000775000175000017500000000000015166123241014704 5ustar hasanhasanbazaar-orig-v0.7.14/.foundry/.gitignore0000664000175000017500000000002215166123241016666 0ustar hasanhasantmp/ user/ cache/ bazaar-orig-v0.7.14/src/0000775000175000017500000000000015166123241013727 5ustar hasanhasanbazaar-orig-v0.7.14/src/bz-search-page.c0000664000175000017500000006523215166123241016673 0ustar hasanhasan/* bz-search-page.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-apps-page.h" #include "bz-async-texture.h" #include "bz-category-tile.h" #include "bz-dynamic-list-view.h" #include "bz-entry-inspector.h" #include "bz-finished-search-query.h" #include "bz-group-tile-css-watcher.h" #include "bz-rich-app-tile.h" #include "bz-screenshot.h" #include "bz-search-filter-popover.h" #include "bz-search-page.h" #include "bz-search-pill-list.h" #include "bz-search-result.h" #include "bz-template-callbacks.h" #include "bz-util.h" struct _BzSearchPage { AdwBin parent_instance; BzStateInfo *state; BzEntryGroup *selected; gboolean remove; gboolean search_in_progress; BzFinishedSearchQuery *current_query; BzContentProvider *blocklists_provider; BzContentProvider *txt_blocklists_provider; GListStore *search_model; GtkSelectionModel *selection_model; guint search_update_timeout; DexFuture *search_query; /* Template widgets */ GtkText *search_bar; AdwSpinner *search_busy; GtkBox *content_box; GtkStack *search_stack; GtkGridView *grid_view; GtkWidget *filter_button; BzSearchFilterPopover *filter_popover; }; G_DEFINE_FINAL_TYPE (BzSearchPage, bz_search_page, ADW_TYPE_BIN) enum { PROP_0, PROP_STATE, PROP_TEXT, PROP_CURRENT_QUERY, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void search_changed (GtkEditable *editable, BzSearchPage *self); static void search_activate (GtkText *text, BzSearchPage *self); static void grid_activate (GtkGridView *grid_view, guint position, BzSearchPage *self); static void invalidating_state_prop_changed (BzSearchPage *self, GParamSpec *pspec, BzStateInfo *info); static void blocklists_items_changed (BzSearchPage *self, guint position, guint removed, guint added, GListModel *model); static DexFuture * search_query_then (DexFuture *future, GWeakRef *wr); static void update_filter (BzSearchPage *self); static void emit_idx (BzSearchPage *self, GListModel *model, guint selected_idx); static void bz_search_page_dispose (GObject *object) { BzSearchPage *self = BZ_SEARCH_PAGE (object); if (self->state != NULL) g_signal_handlers_disconnect_by_func (self->state, invalidating_state_prop_changed, self); if (self->blocklists_provider != NULL) g_signal_handlers_disconnect_by_func (self->blocklists_provider, blocklists_items_changed, self); if (self->txt_blocklists_provider != NULL) g_signal_handlers_disconnect_by_func (self->txt_blocklists_provider, blocklists_items_changed, self); g_clear_handle_id (&self->search_update_timeout, g_source_remove); dex_clear (&self->search_query); g_clear_object (&self->state); g_clear_object (&self->selected); g_clear_object (&self->current_query); g_clear_object (&self->blocklists_provider); g_clear_object (&self->txt_blocklists_provider); g_clear_object (&self->search_model); g_clear_object (&self->selection_model); G_OBJECT_CLASS (bz_search_page_parent_class)->dispose (object); } static void bz_search_page_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzSearchPage *self = BZ_SEARCH_PAGE (object); switch (prop_id) { case PROP_STATE: g_value_set_object (value, bz_search_page_get_state (self)); break; case PROP_TEXT: g_value_set_string (value, bz_search_page_get_text (self)); break; case PROP_CURRENT_QUERY: g_value_set_object (value, self->current_query); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_search_page_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzSearchPage *self = BZ_SEARCH_PAGE (object); switch (prop_id) { case PROP_STATE: bz_search_page_set_state (self, g_value_get_object (value)); break; case PROP_TEXT: bz_search_page_set_text (self, g_value_get_string (value)); break; case PROP_CURRENT_QUERY: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static gboolean is_zero (gpointer object, int value) { return value == 0; } static gboolean is_null (gpointer object, GObject *value) { return value == NULL; } static gboolean is_empty (gpointer object, GListModel *model) { if (model == NULL) return TRUE; return g_list_model_get_n_items (model) == 0; } static gboolean is_valid_string (gpointer object, const char *value) { return value != NULL && *value != '\0'; } static char * idx_to_string (gpointer object, guint value) { return g_strdup_printf ("%d", value + 1); } static char * score_to_string (gpointer object, double value) { return g_strdup_printf ("%0.1f", value); } static char * no_results_found_subtitle (gpointer object, const char *search_text) { if (search_text == NULL || *search_text == '\0') return g_strdup (""); return g_strdup_printf (_ ("No results found for \"%s\" in Flathub"), search_text); } static void has_active_filters_cb (BzSearchFilterPopover *filter_popover, GParamSpec *pspec, BzSearchPage *self) { gboolean active = FALSE; g_object_get (filter_popover, "has-active-filters", &active, NULL); if (active) gtk_widget_add_css_class (self->filter_button, "accent"); else gtk_widget_remove_css_class (self->filter_button, "accent"); } static void pill_list_cb (BzSearchPage *self, const char *label, GtkWidget *pill_list) { bz_search_page_set_text (self, label); update_filter (self); } static void category_clicked (BzFlathubCategory *category, GtkButton *button) { GtkWidget *self = NULL; GtkWidget *nav_view = NULL; AdwNavigationPage *apps_page = NULL; self = gtk_widget_get_ancestor (GTK_WIDGET (button), BZ_TYPE_SEARCH_PAGE); g_assert (self != NULL); nav_view = gtk_widget_get_ancestor (GTK_WIDGET (self), ADW_TYPE_NAVIGATION_VIEW); g_assert (nav_view != NULL); apps_page = bz_apps_page_new_from_category (category); adw_navigation_view_push (ADW_NAVIGATION_VIEW (nav_view), apps_page); } static void bind_category_tile_cb (BzSearchPage *self, BzCategoryTile *tile, BzFlathubCategory *category, BzDynamicListView *view) { g_signal_connect_swapped (tile, "clicked", G_CALLBACK (category_clicked), category); } static void unbind_category_tile_cb (BzSearchPage *self, BzCategoryTile *tile, BzFlathubCategory *category, BzDynamicListView *view) { g_signal_handlers_disconnect_by_func (tile, category_clicked, category); } static void tile_activated_cb (GtkListItem *list_item, BzRichAppTile *tile) { BzSearchResult *result = gtk_list_item_get_item (list_item); BzEntryGroup *group = bz_search_result_get_group (result); gtk_widget_activate_action (GTK_WIDGET (tile), "window.show-group", "s", bz_entry_group_get_id (group)); } static void reset_search_cb (BzSearchPage *self, GtkButton *button) { bz_search_page_set_text (self, ""); bz_search_filter_popover_clear (self->filter_popover); bz_search_page_refresh (self); } static void copy_id_cb (GtkListItem *list_item, GtkButton *button) { BzSearchResult *result = NULL; BzEntryGroup *group = NULL; const char *id = NULL; GdkClipboard *clipboard = NULL; result = gtk_list_item_get_item (list_item); group = bz_search_result_get_group (result); id = bz_entry_group_get_id (group); clipboard = gdk_display_get_clipboard (gdk_display_get_default ()); gdk_clipboard_set_text (clipboard, id); } static void debug_id_inspect_cb (GtkListItem *list_item, GtkButton *button) { BzSearchResult *search_result = NULL; BzStateInfo *state = NULL; BzEntryGroup *group = NULL; g_autofree char *unique_id = NULL; g_autoptr (BzResult) result = NULL; search_result = gtk_list_item_get_item (list_item); state = bz_search_result_get_state (search_result); if (state == NULL) return; group = bz_search_result_get_group (search_result); unique_id = bz_entry_group_dup_ui_entry_id (group); result = bz_application_map_factory_convert_one ( bz_state_info_get_entry_factory (state), gtk_string_object_new (unique_id)); if (result != NULL) { BzEntryInspector *inspector = NULL; inspector = bz_entry_inspector_new (); bz_entry_inspector_set_result (inspector, result); gtk_window_present (GTK_WINDOW (inspector)); } } static void bz_search_page_class_init (BzSearchPageClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_search_page_dispose; object_class->get_property = bz_search_page_get_property; object_class->set_property = bz_search_page_set_property; props[PROP_STATE] = g_param_spec_object ( "state", NULL, NULL, BZ_TYPE_STATE_INFO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_TEXT] = g_param_spec_string ( "text", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_CURRENT_QUERY] = g_param_spec_object ( "current-query", NULL, NULL, BZ_TYPE_FINISHED_SEARCH_QUERY, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_ASYNC_TEXTURE); g_type_ensure (BZ_TYPE_CATEGORY_TILE); g_type_ensure (BZ_TYPE_DYNAMIC_LIST_VIEW); g_type_ensure (BZ_TYPE_GROUP_TILE_CSS_WATCHER); g_type_ensure (BZ_TYPE_RICH_APP_TILE); g_type_ensure (BZ_TYPE_SCREENSHOT); g_type_ensure (BZ_TYPE_SEARCH_RESULT); g_type_ensure (BZ_TYPE_SEARCH_PILL_LIST); g_type_ensure (BZ_TYPE_SEARCH_FILTER_POPOVER); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-search-page.ui"); bz_widget_class_bind_all_util_callbacks (widget_class); gtk_widget_class_bind_template_child (widget_class, BzSearchPage, search_bar); gtk_widget_class_bind_template_child (widget_class, BzSearchPage, search_busy); gtk_widget_class_bind_template_child (widget_class, BzSearchPage, content_box); gtk_widget_class_bind_template_child (widget_class, BzSearchPage, search_stack); gtk_widget_class_bind_template_child (widget_class, BzSearchPage, grid_view); gtk_widget_class_bind_template_child (widget_class, BzSearchPage, filter_button); gtk_widget_class_bind_template_child (widget_class, BzSearchPage, filter_popover); gtk_widget_class_bind_template_callback (widget_class, bind_category_tile_cb); gtk_widget_class_bind_template_callback (widget_class, unbind_category_tile_cb); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, is_zero); gtk_widget_class_bind_template_callback (widget_class, is_null); gtk_widget_class_bind_template_callback (widget_class, is_empty); gtk_widget_class_bind_template_callback (widget_class, has_active_filters_cb); gtk_widget_class_bind_template_callback (widget_class, is_valid_string); gtk_widget_class_bind_template_callback (widget_class, idx_to_string); gtk_widget_class_bind_template_callback (widget_class, score_to_string); gtk_widget_class_bind_template_callback (widget_class, reset_search_cb); gtk_widget_class_bind_template_callback (widget_class, pill_list_cb); gtk_widget_class_bind_template_callback (widget_class, no_results_found_subtitle); gtk_widget_class_bind_template_callback (widget_class, tile_activated_cb); gtk_widget_class_bind_template_callback (widget_class, copy_id_cb); gtk_widget_class_bind_template_callback (widget_class, debug_id_inspect_cb); } static void bz_search_page_init (BzSearchPage *self) { self->search_model = g_list_store_new (BZ_TYPE_SEARCH_RESULT); gtk_widget_init_template (GTK_WIDGET (self)); /* TODO: move all this to blueprint */ self->selection_model = GTK_SELECTION_MODEL (gtk_no_selection_new (NULL)); gtk_no_selection_set_model (GTK_NO_SELECTION (self->selection_model), G_LIST_MODEL (self->search_model)); gtk_grid_view_set_model (self->grid_view, self->selection_model); g_signal_connect (self->search_bar, "changed", G_CALLBACK (search_changed), self); g_signal_connect (self->search_bar, "activate", G_CALLBACK (search_activate), self); g_signal_connect (self->grid_view, "activate", G_CALLBACK (grid_activate), self); g_signal_connect_swapped (self->filter_popover, "notify::selected-categories", G_CALLBACK (update_filter), self); g_signal_connect_swapped (self->filter_popover, "notify::only-verified", G_CALLBACK (update_filter), self); g_signal_connect_swapped (self->filter_popover, "notify::only-free", G_CALLBACK (update_filter), self); g_signal_connect_swapped (self->filter_popover, "notify::only-non-eol", G_CALLBACK (update_filter), self); } GtkWidget * bz_search_page_new (GListModel *model, const char *initial) { BzSearchPage *self = NULL; self = g_object_new ( BZ_TYPE_SEARCH_PAGE, "model", model, NULL); if (initial != NULL) gtk_editable_set_text (GTK_EDITABLE (self->search_bar), initial); return GTK_WIDGET (self); } BzEntryGroup * bz_search_page_get_selected (BzSearchPage *self, gboolean *remove) { g_return_val_if_fail (BZ_IS_SEARCH_PAGE (self), NULL); if (remove != NULL) *remove = self->remove; return self->selected; } void bz_search_page_set_state (BzSearchPage *self, BzStateInfo *state) { g_return_if_fail (BZ_IS_SEARCH_PAGE (self)); if (self->state != NULL) g_signal_handlers_disconnect_by_func (self->state, invalidating_state_prop_changed, self); g_clear_object (&self->state); if (self->blocklists_provider != NULL) g_signal_handlers_disconnect_by_func (self->blocklists_provider, blocklists_items_changed, self); g_clear_object (&self->blocklists_provider); if (self->txt_blocklists_provider != NULL) g_signal_handlers_disconnect_by_func (self->txt_blocklists_provider, blocklists_items_changed, self); g_clear_object (&self->txt_blocklists_provider); if (state != NULL) { self->state = g_object_ref (state); g_signal_connect_swapped ( state, "notify::disable-blocklists", G_CALLBACK (invalidating_state_prop_changed), self); g_signal_connect_swapped ( state, "notify::hide-eol", G_CALLBACK (invalidating_state_prop_changed), self); g_signal_connect_swapped ( state, "notify::show-only-foss", G_CALLBACK (invalidating_state_prop_changed), self); g_signal_connect_swapped ( state, "notify::show-only-flathub", G_CALLBACK (invalidating_state_prop_changed), self); g_signal_connect_swapped ( state, "notify::show-only-verified", G_CALLBACK (invalidating_state_prop_changed), self); g_signal_connect_swapped ( state, "notify::parental-age-rating", G_CALLBACK (invalidating_state_prop_changed), self); g_object_get ( state, "blocklists-provider", &self->blocklists_provider, "txt-blocklists-provider", &self->txt_blocklists_provider, NULL); if (self->blocklists_provider != NULL) g_signal_connect_data ( self->blocklists_provider, "items-changed", G_CALLBACK (blocklists_items_changed), self, NULL, G_CONNECT_SWAPPED | G_CONNECT_AFTER); if (self->txt_blocklists_provider != NULL) g_signal_connect_data ( self->txt_blocklists_provider, "items-changed", G_CALLBACK (blocklists_items_changed), self, NULL, G_CONNECT_SWAPPED | G_CONNECT_AFTER); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_STATE]); } BzStateInfo * bz_search_page_get_state (BzSearchPage *self) { g_return_val_if_fail (BZ_IS_SEARCH_PAGE (self), NULL); return self->state; } void bz_search_page_set_text (BzSearchPage *self, const char *text) { g_return_if_fail (BZ_IS_SEARCH_PAGE (self)); gtk_editable_set_text (GTK_EDITABLE (self->search_bar), text); if (text != NULL) gtk_editable_set_position (GTK_EDITABLE (self->search_bar), g_utf8_strlen (text, -1)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TEXT]); } const char * bz_search_page_get_text (BzSearchPage *self) { g_return_val_if_fail (BZ_IS_SEARCH_PAGE (self), NULL); return gtk_editable_get_text (GTK_EDITABLE (self->search_bar)); } void bz_search_page_refresh (BzSearchPage *self) { g_return_if_fail (BZ_IS_SEARCH_PAGE (self)); update_filter (self); } gboolean bz_search_page_ensure_active (BzSearchPage *self, const char *initial) { const char *text = NULL; g_return_val_if_fail (BZ_IS_SEARCH_PAGE (self), FALSE); text = gtk_editable_get_text (GTK_EDITABLE (self->search_bar)); if (text != NULL && *text != '\0' && gtk_widget_has_focus (GTK_WIDGET (self->search_bar))) return FALSE; gtk_widget_grab_focus (GTK_WIDGET (self->search_bar)); bz_search_page_set_text (self, initial); return TRUE; } static void search_changed (GtkEditable *editable, BzSearchPage *self) { GSettings *settings = NULL; g_clear_handle_id (&self->search_update_timeout, g_source_remove); settings = bz_state_info_get_settings (self->state); if (settings != NULL && g_settings_get_boolean (settings, "search-debounce")) { self->search_update_timeout = g_timeout_add_once ( 150, (GSourceOnceFunc) update_filter, self); gtk_widget_set_visible (GTK_WIDGET (self->search_busy), TRUE); } else update_filter (self); } static void search_activate (GtkText *text, BzSearchPage *self) { GtkSelectionModel *model = NULL; guint n_items = 0; g_autoptr (BzSearchResult) result = NULL; BzEntryGroup *group = NULL; model = gtk_grid_view_get_model (self->grid_view); n_items = g_list_model_get_n_items (G_LIST_MODEL (model)); if (gtk_widget_get_visible (GTK_WIDGET (self->search_busy))) return; if (n_items > 0) { result = g_list_model_get_item (G_LIST_MODEL (model), 0); group = bz_search_result_get_group (result); if (bz_entry_group_get_removable_and_available (group) > 0) { gtk_widget_activate_action (GTK_WIDGET (self), "window.remove-group", "(sb)", bz_entry_group_get_id (group), FALSE); } else if (bz_entry_group_get_installable_and_available (group) > 0) { gtk_widget_activate_action (GTK_WIDGET (self), "window.install-group", "(sb)", bz_entry_group_get_id (group), FALSE); } } } static void grid_activate (GtkGridView *grid_view, guint position, BzSearchPage *self) { GtkSelectionModel *model = NULL; model = gtk_grid_view_get_model (self->grid_view); emit_idx (self, G_LIST_MODEL (model), position); } static void invalidating_state_prop_changed (BzSearchPage *self, GParamSpec *pspec, BzStateInfo *info) { update_filter (self); } static void blocklists_items_changed (BzSearchPage *self, guint position, guint removed, guint added, GListModel *model) { update_filter (self); } static DexFuture * search_query_then (DexFuture *future, GWeakRef *wr) { g_autoptr (BzSearchPage) self = NULL; g_autoptr (GPtrArray) filtered = NULL; BzFinishedSearchQuery *finished = NULL; GPtrArray *results = NULL; guint old_length = 0; const char *page_name = NULL; BzCategoryFlags categories = BZ_CATEGORY_FLAGS_NONE; gboolean only_verified = FALSE; gboolean only_free = FALSE; gboolean only_non_eol = FALSE; bz_weak_get_or_return_reject (self, wr); finished = g_value_get_object (dex_future_get_value (future, NULL)); results = bz_finished_search_query_get_results (finished); categories = bz_search_filter_popover_get_selected_categories (self->filter_popover); only_verified = bz_search_filter_popover_get_only_verified (self->filter_popover); only_free = bz_search_filter_popover_get_only_free (self->filter_popover); only_non_eol = bz_search_filter_popover_get_only_non_eol (self->filter_popover); filtered = g_ptr_array_new_with_free_func (g_object_unref); for (guint i = 0; i < results->len; i++) { BzSearchResult *result = g_ptr_array_index (results, i); BzEntryGroup *group = bz_search_result_get_group (result); if (self->state != NULL) /* This is for debug mode */ bz_search_result_set_state (result, self->state); if (categories != BZ_CATEGORY_FLAGS_NONE && !(bz_entry_group_get_categories (group) & categories)) continue; if (only_verified && !bz_entry_group_get_is_verified (group)) continue; if (only_free && !bz_entry_group_get_is_floss (group)) continue; if (only_non_eol && bz_entry_group_get_eol (group)) continue; g_ptr_array_add (filtered, g_object_ref (result)); } old_length = g_list_model_get_n_items (G_LIST_MODEL (self->search_model)); g_list_store_splice ( self->search_model, 0, old_length, (gpointer *) filtered->pdata, filtered->len); gtk_widget_set_visible (GTK_WIDGET (self->search_busy), FALSE); if (filtered->len > 0) { page_name = "results"; gtk_widget_activate_action (GTK_WIDGET (self->grid_view), "list.scroll-to-item", "u", 0); } else { const char *search_text = NULL; search_text = gtk_editable_get_text (GTK_EDITABLE (self->search_bar)); page_name = (search_text && *search_text) ? "no-results" : "empty"; } self->current_query = g_object_ref (finished); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CURRENT_QUERY]); gtk_stack_set_visible_child_name (self->search_stack, page_name); dex_clear (&self->search_query); return NULL; } static void update_filter (BzSearchPage *self) { BzSearchEngine *engine = NULL; const char *search_text = NULL; g_autoptr (GStrvBuilder) builder = NULL; guint n_terms = 0; g_auto (GStrv) terms = NULL; g_autoptr (DexFuture) future = NULL; g_autofree gchar **tokens = NULL; g_clear_handle_id (&self->search_update_timeout, g_source_remove); dex_clear (&self->search_query); g_clear_object (&self->current_query); self->current_query = bz_finished_search_query_new (); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CURRENT_QUERY]); gtk_widget_set_visible (GTK_WIDGET (self->search_busy), FALSE); if (self->state == NULL) return; engine = bz_state_info_get_search_engine (self->state); if (engine == NULL) return; search_text = gtk_editable_get_text (GTK_EDITABLE (self->search_bar)); if (search_text == NULL || *search_text == '\0') { g_list_store_remove_all (self->search_model); gtk_stack_set_visible_child_name (self->search_stack, "empty"); return; } builder = g_strv_builder_new (); tokens = g_strsplit_set (search_text, " \t\n", -1); for (gchar **token = tokens; *token != NULL; token++) { if (**token != '\0') { g_strv_builder_take (builder, *token); n_terms++; } else g_free (*token); } if (n_terms == 0) { g_list_store_remove_all (self->search_model); gtk_stack_set_visible_child_name (self->search_stack, "empty"); return; } terms = g_strv_builder_end (builder); self->search_in_progress = TRUE; future = bz_search_engine_query ( engine, (const char *const *) terms); gtk_widget_set_visible ( GTK_WIDGET (self->search_busy), dex_future_is_pending (future)); future = dex_future_then ( future, (DexFutureCallback) search_query_then, bz_track_weak (self), bz_weak_release); self->search_query = g_steal_pointer (&future); } static void emit_idx (BzSearchPage *self, GListModel *model, guint selected_idx) { g_autoptr (BzSearchResult) result = NULL; BzEntryGroup *group = NULL; result = g_list_model_get_item (G_LIST_MODEL (model), selected_idx); group = bz_search_result_get_group (result); gtk_widget_activate_action (GTK_WIDGET (self), "window.show-group", "s", bz_entry_group_get_id (group)); } bazaar-orig-v0.7.14/src/bz-user-data-tile.c0000664000175000017500000001334515166123241017332 0ustar hasanhasan/* bz-user-data-tile.c * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-entry-group.h" #include "bz-env.h" #include "bz-error.h" #include "bz-state-info.h" #include "bz-user-data-page.h" #include "bz-user-data-tile.h" #include "bz-window.h" struct _BzUserDataTile { BzListTile parent_instance; BzEntryGroup *group; GtkPicture *icon_picture; GtkImage *fallback_icon; GtkLabel *title_label; GtkButton *remove_button; }; G_DEFINE_FINAL_TYPE (BzUserDataTile, bz_user_data_tile, ADW_TYPE_BIN) enum { PROP_0, PROP_GROUP, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bz_user_data_tile_dispose (GObject *object) { BzUserDataTile *self = BZ_USER_DATA_TILE (object); g_clear_object (&self->group); G_OBJECT_CLASS (bz_user_data_tile_parent_class)->dispose (object); } static void bz_user_data_tile_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzUserDataTile *self = BZ_USER_DATA_TILE (object); switch (prop_id) { case PROP_GROUP: g_value_set_object (value, bz_user_data_tile_get_group (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_user_data_tile_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzUserDataTile *self = BZ_USER_DATA_TILE (object); switch (prop_id) { case PROP_GROUP: bz_user_data_tile_set_group (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static gboolean is_null (gpointer object, GObject *value) { return value == NULL; } static gboolean is_zero (gpointer object, int value) { return value == 0; } static char * format_size (gpointer object, guint64 value) { return g_format_size (value); } static void remove_cb (BzUserDataTile *self, GtkButton *button) { BzWindow *window; AdwToast *toast; const char *title; g_autofree char *message = NULL; if (self->group == NULL) return; title = bz_entry_group_get_title (self->group); bz_entry_group_reap_user_data (self->group); window = BZ_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))); message = g_strdup_printf (_ ("Trashed User Data for %s"), title); toast = adw_toast_new (message); bz_window_add_toast (window, toast); } static void bz_user_data_tile_class_init (BzUserDataTileClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_user_data_tile_dispose; object_class->get_property = bz_user_data_tile_get_property; object_class->set_property = bz_user_data_tile_set_property; props[PROP_GROUP] = g_param_spec_object ( "group", NULL, NULL, BZ_TYPE_ENTRY_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_LIST_TILE); g_type_ensure (BZ_TYPE_ENTRY_GROUP); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-user-data-tile.ui"); gtk_widget_class_bind_template_child (widget_class, BzUserDataTile, icon_picture); gtk_widget_class_bind_template_child (widget_class, BzUserDataTile, fallback_icon); gtk_widget_class_bind_template_child (widget_class, BzUserDataTile, title_label); gtk_widget_class_bind_template_child (widget_class, BzUserDataTile, remove_button); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, is_null); gtk_widget_class_bind_template_callback (widget_class, is_zero); gtk_widget_class_bind_template_callback (widget_class, format_size); gtk_widget_class_bind_template_callback (widget_class, remove_cb); gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_BUTTON); } static void bz_user_data_tile_init (BzUserDataTile *self) { gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_user_data_tile_new (void) { return g_object_new (BZ_TYPE_USER_DATA_TILE, NULL); } void bz_user_data_tile_set_group (BzUserDataTile *self, BzEntryGroup *group) { g_return_if_fail (BZ_IS_USER_DATA_TILE (self)); g_return_if_fail (group == NULL || BZ_IS_ENTRY_GROUP (group)); g_clear_object (&self->group); if (group != NULL) self->group = g_object_ref (group); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_GROUP]); } BzEntryGroup * bz_user_data_tile_get_group (BzUserDataTile *self) { g_return_val_if_fail (BZ_IS_USER_DATA_TILE (self), NULL); return self->group; } bazaar-orig-v0.7.14/src/bz-context-row.c0000664000175000017500000000542215166123241017000 0ustar hasanhasan/* bz-context-row.c * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-context-row.h" GType bz_importance_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static const GEnumValue values[] = { { BZ_IMPORTANCE_UNIMPORTANT, "BZ_IMPORTANCE_UNIMPORTANT", "unimportant" }, { BZ_IMPORTANCE_NEUTRAL, "BZ_IMPORTANCE_NEUTRAL", "neutral" }, { BZ_IMPORTANCE_INFORMATION, "BZ_IMPORTANCE_INFORMATION", "information" }, { BZ_IMPORTANCE_WARNING, "BZ_IMPORTANCE_WARNING", "warning" }, { BZ_IMPORTANCE_IMPORTANT, "BZ_IMPORTANCE_IMPORTANT", "important" }, { 0, NULL, NULL } }; type = g_enum_register_static ("BzImportance", values); } return type; } const gchar * bz_context_row_importance_to_css_class (BzImportance importance) { switch (importance) { case BZ_IMPORTANCE_UNIMPORTANT: return "green"; case BZ_IMPORTANCE_NEUTRAL: return "grey"; case BZ_IMPORTANCE_INFORMATION: return "yellow"; case BZ_IMPORTANCE_WARNING: return "orange"; case BZ_IMPORTANCE_IMPORTANT: return "red"; default: return "grey"; } } AdwActionRow * bz_context_row_new (const gchar *icon_name, BzImportance importance, const gchar *title, const gchar *subtitle) { AdwActionRow *row; GtkWidget *icon; const gchar *css_class; g_return_val_if_fail (icon_name != NULL, NULL); g_return_val_if_fail (title != NULL, NULL); row = ADW_ACTION_ROW (adw_action_row_new ()); adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), title); if (subtitle != NULL) adw_action_row_set_subtitle (row, subtitle); icon = gtk_image_new_from_icon_name (icon_name); gtk_widget_set_valign (icon, GTK_ALIGN_CENTER); gtk_widget_add_css_class (icon, "circular-lozenge"); css_class = bz_context_row_importance_to_css_class (importance); gtk_widget_add_css_class (icon, css_class); adw_action_row_add_prefix (row, icon); return row; } bazaar-orig-v0.7.14/src/bz-comet-overlay.h0000664000175000017500000000310715166123241017300 0ustar hasanhasan/* bz-comet-overlay.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-comet.h" G_BEGIN_DECLS #define BZ_TYPE_COMET_OVERLAY (bz_comet_overlay_get_type ()) G_DECLARE_FINAL_TYPE (BzCometOverlay, bz_comet_overlay, BZ, COMET_OVERLAY, GtkWidget) GtkWidget * bz_comet_overlay_new (void); void bz_comet_overlay_set_child (BzCometOverlay *self, GtkWidget *child); GtkWidget * bz_comet_overlay_get_child (BzCometOverlay *self); void bz_comet_overlay_set_pulse_color (BzCometOverlay *self, GdkRGBA *color); GdkRGBA * bz_comet_overlay_get_pulse_color (BzCometOverlay *self); void bz_comet_overlay_spawn (BzCometOverlay *self, BzComet *comet); void bz_comet_overlay_pulse_child (BzCometOverlay *self, GtkWidget *child); G_END_DECLS bazaar-orig-v0.7.14/src/bz-featured-carousel.h0000664000175000017500000000266115166123241020130 0ustar hasanhasan/* bz-featured-carousel.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_FEATURED_CAROUSEL (bz_featured_carousel_get_type ()) G_DECLARE_FINAL_TYPE (BzFeaturedCarousel, bz_featured_carousel, BZ, FEATURED_CAROUSEL, GtkBox) BzFeaturedCarousel *bz_featured_carousel_new (void); GListModel *bz_featured_carousel_get_model (BzFeaturedCarousel *self); void bz_featured_carousel_set_model (BzFeaturedCarousel *self, GListModel *model); gboolean bz_featured_carousel_get_is_aotd (BzFeaturedCarousel *self); void bz_featured_carousel_set_is_aotd (BzFeaturedCarousel *self, gboolean is_aotd); G_END_DECLS bazaar-orig-v0.7.14/src/bz-blocklist-condition.txt0000664000175000017500000000106015166123241021050 0ustar hasanhasanprefix=bz name=blocklist_condition parent-prefix=g parent-name=object author=AUTOGEN enum=bz blocklist_condition_post_process_kind identity invert include="bz-blocklist-condition-match-envvar.h" include="bz-blocklist-condition-match-locale.h" property=match_envvar BzBlocklistConditionMatchEnvvar BZ_TYPE_BLOCKLIST_CONDITION_MATCH_ENVVAR object property=match_locale BzBlocklistConditionMatchLocale BZ_TYPE_BLOCKLIST_CONDITION_MATCH_LOCALE object property=post_process BzBlocklistConditionPostProcessKind BZ_TYPE_BLOCKLIST_CONDITION_POST_PROCESS_KIND enum bazaar-orig-v0.7.14/src/bz-auth-state.c0000664000175000017500000003421415166123241016567 0ustar hasanhasan/* bz-auth-state.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-async-texture.h" #include "bz-auth-state.h" #define SECRET_SCHEMA_NAME "io.github.kolunmi.Bazaar.FlathubAuth" #define SECRET_LABEL "Flathub Authentication" struct _BzAuthState { GObject parent_instance; char *name; char *token; char *profile_icon_url; GDateTime *token_expires; BzAsyncTexture *paintable; gboolean loading; guint expiration_timeout_id; }; G_DEFINE_FINAL_TYPE (BzAuthState, bz_auth_state, G_TYPE_OBJECT) enum { PROP_0, PROP_NAME, PROP_TOKEN, PROP_PROFILE_ICON_URL, PROP_AUTHENTICATED, PROP_PAINTABLE, N_PROPS }; static GParamSpec *properties[N_PROPS]; static const SecretSchema * get_secret_schema (void) { static const SecretSchema schema = { SECRET_SCHEMA_NAME, SECRET_SCHEMA_NONE, { { "service", SECRET_SCHEMA_ATTRIBUTE_STRING }, { "NULL", 0 }, } }; return &schema; } static gboolean on_token_expired (gpointer user_data) { BzAuthState *self = BZ_AUTH_STATE (user_data); self->expiration_timeout_id = 0; bz_auth_state_clear (self); return G_SOURCE_REMOVE; } static void schedule_token_expiration (BzAuthState *self) { GDateTime *now; gint64 seconds_until_expiration; if (self->expiration_timeout_id != 0) g_source_remove (self->expiration_timeout_id); self->expiration_timeout_id = 0; if (self->token_expires == NULL) return; now = g_date_time_new_now_utc (); seconds_until_expiration = g_date_time_difference (self->token_expires, now) / G_TIME_SPAN_SECOND; g_date_time_unref (now); if (seconds_until_expiration <= 0) { bz_auth_state_clear (self); return; } if (seconds_until_expiration > G_MAXUINT / 1000) self->expiration_timeout_id = g_timeout_add_seconds (G_MAXUINT / 1000, on_token_expired, self); else self->expiration_timeout_id = g_timeout_add_seconds (seconds_until_expiration, on_token_expired, self); } static void save_to_secrets (BzAuthState *self) { GHashTable *attributes; GError *error = NULL; g_autoptr (GVariantBuilder) builder = NULL; g_autoptr (GVariant) variant = NULL; g_autofree char *serialized = NULL; if (self->loading) return; attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); g_hash_table_insert (attributes, g_strdup ("service"), g_strdup ("flathub")); builder = g_variant_builder_new (G_VARIANT_TYPE_VARDICT); if (self->name != NULL) g_variant_builder_add (builder, "{sv}", "name", g_variant_new_string (self->name)); if (self->token != NULL) g_variant_builder_add (builder, "{sv}", "token", g_variant_new_string (self->token)); if (self->token_expires != NULL) { g_autofree char *expires = g_date_time_format_iso8601 (self->token_expires); g_variant_builder_add (builder, "{sv}", "token-expires", g_variant_new_string (expires)); } if (self->profile_icon_url != NULL) g_variant_builder_add (builder, "{sv}", "profile-icon-url", g_variant_new_string (self->profile_icon_url)); variant = g_variant_builder_end (builder); serialized = g_variant_print (variant, FALSE); secret_password_storev_sync ( get_secret_schema (), attributes, NULL, SECRET_LABEL, serialized, NULL, &error); g_hash_table_unref (attributes); if (error != NULL) { g_warning ("Failed to save authentication to secrets: %s", error->message); g_error_free (error); } } static void load_from_secrets (BzAuthState *self) { GHashTable *attributes; GError *error = NULL; g_autofree char *secret = NULL; attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); g_hash_table_insert (attributes, g_strdup ("service"), g_strdup ("flathub")); secret = secret_password_lookupv_sync ( get_secret_schema (), attributes, NULL, &error); g_hash_table_unref (attributes); if (error != NULL) { if (!g_error_matches (error, SECRET_ERROR, SECRET_ERROR_NO_SUCH_OBJECT)) g_warning ("Failed to load authentication from secrets: %s", error->message); g_error_free (error); return; } if (secret != NULL) { g_autoptr (GVariant) variant = NULL; g_autoptr (GVariantIter) iter = NULL; variant = g_variant_parse (G_VARIANT_TYPE_VARDICT, secret, NULL, NULL, &error); if (error != NULL) { g_warning ("Failed to parse secret: %s", error->message); g_error_free (error); return; } if (variant != NULL) { iter = g_variant_iter_new (variant); for (;;) { g_autofree char *key = NULL; g_autoptr (GVariant) value = NULL; if (!g_variant_iter_next (iter, "{sv}", &key, &value)) break; if (g_strcmp0 (key, "name") == 0) { g_clear_pointer (&self->name, g_free); self->name = g_variant_dup_string (value, NULL); } else if (g_strcmp0 (key, "token") == 0) { g_clear_pointer (&self->token, g_free); self->token = g_variant_dup_string (value, NULL); } else if (g_strcmp0 (key, "token-expires") == 0) { g_autoptr (GDateTime) dt = g_date_time_new_from_iso8601 (g_variant_get_string (value, NULL), NULL); if (dt != NULL) { g_clear_pointer (&self->token_expires, g_date_time_unref); self->token_expires = g_steal_pointer (&dt); } } else if (g_strcmp0 (key, "profile-icon-url") == 0) { g_clear_pointer (&self->profile_icon_url, g_free); self->profile_icon_url = g_variant_dup_string (value, NULL); g_clear_object (&self->paintable); if (self->profile_icon_url != NULL && self->profile_icon_url[0] != '\0') { g_autoptr (GFile) file = g_file_new_for_uri (self->profile_icon_url); self->paintable = bz_async_texture_new (file, NULL); } } } } } if (self->token_expires != NULL) { GDateTime *now = g_date_time_new_now_utc (); if (g_date_time_compare (now, self->token_expires) >= 0) { g_date_time_unref (now); bz_auth_state_clear (self); return; } g_date_time_unref (now); schedule_token_expiration (self); } } static void clear_secrets (BzAuthState *self) { gboolean result = FALSE; g_autoptr (GError) local_error = NULL; g_autoptr (GHashTable) attributes = NULL; attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); g_hash_table_replace (attributes, g_strdup ("service"), g_strdup ("flathub")); result = secret_password_clearv_sync ( get_secret_schema (), attributes, NULL, &local_error); if (!result) g_warning ("Failed to clear auth values from secrets: %s", local_error->message); } static void bz_auth_state_dispose (GObject *object) { BzAuthState *self = BZ_AUTH_STATE (object); g_clear_handle_id (&self->expiration_timeout_id, g_source_remove); g_clear_pointer (&self->name, g_free); g_clear_pointer (&self->token, g_free); g_clear_pointer (&self->profile_icon_url, g_free); g_clear_pointer (&self->token_expires, g_date_time_unref); g_clear_object (&self->paintable); G_OBJECT_CLASS (bz_auth_state_parent_class)->dispose (object); } static void bz_auth_state_finalize (GObject *object) { BzAuthState *self = BZ_AUTH_STATE (object); g_clear_pointer (&self->name, g_free); g_clear_pointer (&self->token, g_free); g_clear_pointer (&self->profile_icon_url, g_free); g_clear_pointer (&self->token_expires, g_date_time_unref); G_OBJECT_CLASS (bz_auth_state_parent_class)->finalize (object); } static void bz_auth_state_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzAuthState *self = BZ_AUTH_STATE (object); switch (prop_id) { case PROP_NAME: g_value_set_string (value, self->name); break; case PROP_TOKEN: g_value_set_string (value, self->token); break; case PROP_PROFILE_ICON_URL: g_value_set_string (value, self->profile_icon_url); break; case PROP_AUTHENTICATED: g_value_set_boolean (value, bz_auth_state_is_authenticated (self)); break; case PROP_PAINTABLE: g_value_set_object (value, bz_auth_state_get_paintable (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_auth_state_class_init (BzAuthStateClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = bz_auth_state_dispose; object_class->finalize = bz_auth_state_finalize; object_class->get_property = bz_auth_state_get_property; properties[PROP_NAME] = g_param_spec_string ( "name", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); properties[PROP_TOKEN] = g_param_spec_string ( "token", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); properties[PROP_PROFILE_ICON_URL] = g_param_spec_string ( "profile-icon-url", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); properties[PROP_AUTHENTICATED] = g_param_spec_boolean ( "authenticated", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); properties[PROP_PAINTABLE] = g_param_spec_object ( "paintable", NULL, NULL, GDK_TYPE_PAINTABLE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPS, properties); } static void bz_auth_state_init (BzAuthState *self) { self->loading = TRUE; load_from_secrets (self); self->loading = FALSE; } BzAuthState * bz_auth_state_new (void) { return g_object_new (BZ_TYPE_AUTH_STATE, NULL); } const char * bz_auth_state_get_name (BzAuthState *self) { g_return_val_if_fail (BZ_IS_AUTH_STATE (self), NULL); return self->name; } const char * bz_auth_state_get_token (BzAuthState *self) { g_return_val_if_fail (BZ_IS_AUTH_STATE (self), NULL); return self->token; } const char * bz_auth_state_get_profile_icon_url (BzAuthState *self) { g_return_val_if_fail (BZ_IS_AUTH_STATE (self), NULL); return self->profile_icon_url; } gboolean bz_auth_state_is_authenticated (BzAuthState *self) { g_return_val_if_fail (BZ_IS_AUTH_STATE (self), FALSE); return self->token != NULL && self->token[0] != '\0'; } GdkPaintable * bz_auth_state_get_paintable (BzAuthState *self) { g_return_val_if_fail (BZ_IS_AUTH_STATE (self), NULL); return GDK_PAINTABLE (self->paintable); } void bz_auth_state_set_authenticated (BzAuthState *self, const char *name, const char *token, GDateTime *token_expires, const char *profile_icon_url) { gboolean was_authenticated = FALSE; gboolean name_changed = FALSE; gboolean token_changed = FALSE; gboolean icon_changed = FALSE; g_return_if_fail (BZ_IS_AUTH_STATE (self)); was_authenticated = bz_auth_state_is_authenticated (self); if (g_strcmp0 (self->name, name) != 0) { g_clear_pointer (&self->name, g_free); self->name = g_strdup (name); name_changed = TRUE; } if (g_strcmp0 (self->token, token) != 0) { g_clear_pointer (&self->token, g_free); self->token = g_strdup (token); token_changed = TRUE; } g_clear_pointer (&self->token_expires, g_date_time_unref); if (token_expires != NULL) self->token_expires = g_date_time_ref (token_expires); if (g_strcmp0 (self->profile_icon_url, profile_icon_url) != 0) { g_clear_pointer (&self->profile_icon_url, g_free); self->profile_icon_url = g_strdup (profile_icon_url); icon_changed = TRUE; g_clear_object (&self->paintable); if (profile_icon_url != NULL && profile_icon_url[0] != '\0') { g_autoptr (GFile) file = g_file_new_for_uri (profile_icon_url); self->paintable = bz_async_texture_new (file, NULL); } g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PAINTABLE]); } if (name_changed) g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_NAME]); if (token_changed) g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TOKEN]); if (icon_changed) g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PROFILE_ICON_URL]); if (!!was_authenticated != !!bz_auth_state_is_authenticated (self)) g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_AUTHENTICATED]); schedule_token_expiration (self); save_to_secrets (self); } void bz_auth_state_clear (BzAuthState *self) { g_return_if_fail (BZ_IS_AUTH_STATE (self)); g_clear_handle_id (&self->expiration_timeout_id, g_source_remove); clear_secrets (self); bz_auth_state_set_authenticated (self, NULL, NULL, NULL, NULL); } bazaar-orig-v0.7.14/src/bz-pride-flag-config.txt0000664000175000017500000000034015166123241020353 0ustar hasanhasanprefix=bz name=pride_flag_config parent-prefix=g parent-name=object author=AUTOGEN include= include="bz-pride-flag-spec.h" ensure=BZ_TYPE_PRIDE_FLAG_SPEC property=flag_specs GListModel G_TYPE_LIST_MODEL object bazaar-orig-v0.7.14/src/bz-main-config.txt0000664000175000017500000000133215166123241017267 0ustar hasanhasanprefix=bz name=main_config parent-prefix=g parent-name=object author=AUTOGEN include= include="bz-hook.h" include="bz-search-bias.h" ensure=BZ_TYPE_HOOK ensure=BZ_TYPE_HOOK_DIALOG ensure=BZ_TYPE_HOOK_DIALOG_OPTION ensure=BZ_TYPE_SEARCH_BIAS property=txt_blocklist_paths GListModel G_TYPE_LIST_MODEL object property=blocklist_version int G_TYPE_INT int property=yaml_blocklist_paths GListModel G_TYPE_LIST_MODEL object property=curated_config_version int G_TYPE_INT int property=curated_config_paths GListModel G_TYPE_LIST_MODEL object property=override_eol_markings GListModel G_TYPE_LIST_MODEL object property=hooks GListModel G_TYPE_LIST_MODEL object property=search_biases GListModel G_TYPE_LIST_MODEL object bazaar-orig-v0.7.14/src/bz-favorite-button.h0000664000175000017500000000265015166123241017644 0ustar hasanhasan/* bz-favorite-button.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry.h" #include "bz-state-info.h" #include G_BEGIN_DECLS #define BZ_TYPE_FAVORITE_BUTTON (bz_favorite_button_get_type ()) G_DECLARE_FINAL_TYPE (BzFavoriteButton, bz_favorite_button, BZ, FAVORITE_BUTTON, GtkButton) GtkWidget * bz_favorite_button_new (void); void bz_favorite_button_set_entry (BzFavoriteButton *self, BzEntry *entry); BzEntry * bz_favorite_button_get_entry (BzFavoriteButton *self); void bz_favorite_button_set_state (BzFavoriteButton *self, BzStateInfo *state); BzStateInfo * bz_favorite_button_get_state (BzFavoriteButton *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-context-row.h0000664000175000017500000000252715166123241017010 0ustar hasanhasan/* bz-context-row.h * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS typedef enum { BZ_IMPORTANCE_UNIMPORTANT, BZ_IMPORTANCE_NEUTRAL, BZ_IMPORTANCE_INFORMATION, BZ_IMPORTANCE_WARNING, BZ_IMPORTANCE_IMPORTANT, } BzImportance; #define BZ_TYPE_IMPORTANCE (bz_importance_get_type ()) GType bz_importance_get_type (void) G_GNUC_CONST; AdwActionRow * bz_context_row_new (const gchar *icon_name, BzImportance importance, const gchar *title, const gchar *subtitle); const gchar * bz_context_row_importance_to_css_class (BzImportance importance); G_END_DECLS bazaar-orig-v0.7.14/src/bz-featured-tile.h0000664000175000017500000000262115166123241017244 0ustar hasanhasan/* bz-featured-tile.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry-group.h" #include G_BEGIN_DECLS #define BZ_TYPE_FEATURED_TILE (bz_featured_tile_get_type ()) G_DECLARE_FINAL_TYPE (BzFeaturedTile, bz_featured_tile, BZ, FEATURED_TILE, GtkButton) BzFeaturedTile *bz_featured_tile_new (BzEntryGroup *group); BzEntryGroup *bz_featured_tile_get_group (BzFeaturedTile *self); void bz_featured_tile_set_group (BzFeaturedTile *self, BzEntryGroup *group); gboolean bz_featured_tile_get_is_aotd (BzFeaturedTile *self); void bz_featured_tile_set_is_aotd (BzFeaturedTile *self, gboolean is_aotd); G_END_DECLS bazaar-orig-v0.7.14/src/pride-flag-config-schema.xml0000664000175000017500000000032015166123241021157 0ustar hasanhasan bazaar-orig-v0.7.14/src/bz-inspector.c0000664000175000017500000002174615166123241016524 0ustar hasanhasan/* bz-inspector.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-inspector.h" #include "bz-entry-inspector.h" #include "bz-template-callbacks.h" #include "bz-window.h" struct _BzInspector { AdwWindow parent_instance; BzStateInfo *state; GBinding *debug_mode_binding; GBinding *disable_blocklists_binding; GtkWindow *preview_window; GtkCheckButton *debug_mode_check; GtkCheckButton *disable_blocklists_check; GtkEditable *search_entry; GtkFilterListModel *filter_model; GtkSingleSelection *groups_selection; }; G_DEFINE_FINAL_TYPE (BzInspector, bz_inspector, ADW_TYPE_WINDOW); enum { PROP_0, PROP_STATE, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static gboolean filter_func (BzEntryGroup *group, BzInspector *self); static void bz_inspector_dispose (GObject *object) { BzInspector *self = BZ_INSPECTOR (object); g_clear_pointer (&self->state, g_object_unref); g_clear_object (&self->debug_mode_binding); g_clear_object (&self->disable_blocklists_binding); if (self->preview_window != NULL) gtk_window_close (self->preview_window); g_clear_object (&self->preview_window); G_OBJECT_CLASS (bz_inspector_parent_class)->dispose (object); } static void bz_inspector_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzInspector *self = BZ_INSPECTOR (object); switch (prop_id) { case PROP_STATE: g_value_set_object (value, bz_inspector_get_state (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_inspector_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzInspector *self = BZ_INSPECTOR (object); switch (prop_id) { case PROP_STATE: bz_inspector_set_state (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void preview_changed (BzInspector *self, GParamSpec *pspec, GtkCheckButton *button) { if (gtk_check_button_get_active (button)) { BzWindow *window = NULL; BzEntryGroup *selected = NULL; g_assert (self->preview_window == NULL); window = bz_window_new (self->state); gtk_window_set_default_size (GTK_WINDOW (window), 750, 750); gtk_window_present (GTK_WINDOW (window)); selected = gtk_single_selection_get_selected_item (self->groups_selection); if (selected != NULL) bz_window_show_group (window, selected); self->preview_window = (GtkWindow *) g_object_ref_sink (window); } else { if (self->preview_window != NULL) gtk_window_close (self->preview_window); g_clear_object (&self->preview_window); } } static void selected_group_changed (BzInspector *self, GParamSpec *pspec, GtkSingleSelection *selection) { BzEntryGroup *group = NULL; if (self->preview_window == NULL || !gtk_widget_get_mapped (GTK_WIDGET (self->preview_window))) return; group = gtk_single_selection_get_selected_item (self->groups_selection); if (group != NULL) bz_window_show_group (BZ_WINDOW (self->preview_window), group); } static void entry_changed (BzInspector *self, GtkEditable *editable) { GtkFilter *filter = NULL; filter = gtk_filter_list_model_get_filter (self->filter_model); gtk_filter_changed (filter, GTK_FILTER_CHANGE_DIFFERENT); } static void decache_and_inspect_cb (GtkListItem *list_item, GtkButton *button) { GtkStringObject *item = NULL; BzInspector *self = NULL; g_autoptr (BzResult) result = NULL; item = gtk_list_item_get_item (list_item); self = BZ_INSPECTOR (gtk_widget_get_ancestor (GTK_WIDGET (button), BZ_TYPE_INSPECTOR)); g_assert (self != NULL); result = bz_application_map_factory_convert_one ( bz_state_info_get_entry_factory (self->state), g_object_ref (item)); if (result != NULL) { BzEntryInspector *inspector = NULL; inspector = bz_entry_inspector_new (); bz_entry_inspector_set_result (inspector, result); gtk_window_present (GTK_WINDOW (inspector)); } } static void open_file_externally_cb (GtkListItem *list_item, GtkButton *button) { GtkStringObject *string = NULL; const char *path = NULL; g_autofree char *uri = NULL; string = gtk_list_item_get_item (list_item); path = gtk_string_object_get_string (string); uri = g_strdup_printf ("file://%s", path); g_app_info_launch_default_for_uri (uri, NULL, NULL); } static void bz_inspector_class_init (BzInspectorClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bz_inspector_set_property; object_class->get_property = bz_inspector_get_property; object_class->dispose = bz_inspector_dispose; props[PROP_STATE] = g_param_spec_object ( "state", NULL, NULL, BZ_TYPE_STATE_INFO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-inspector.ui"); bz_widget_class_bind_all_util_callbacks (widget_class); gtk_widget_class_bind_template_child (widget_class, BzInspector, debug_mode_check); gtk_widget_class_bind_template_child (widget_class, BzInspector, disable_blocklists_check); gtk_widget_class_bind_template_child (widget_class, BzInspector, search_entry); gtk_widget_class_bind_template_child (widget_class, BzInspector, filter_model); gtk_widget_class_bind_template_child (widget_class, BzInspector, groups_selection); gtk_widget_class_bind_template_callback (widget_class, preview_changed); gtk_widget_class_bind_template_callback (widget_class, selected_group_changed); gtk_widget_class_bind_template_callback (widget_class, decache_and_inspect_cb); gtk_widget_class_bind_template_callback (widget_class, open_file_externally_cb); gtk_widget_class_bind_template_callback (widget_class, entry_changed); } static void bz_inspector_init (BzInspector *self) { GtkCustomFilter *filter = NULL; gtk_widget_init_template (GTK_WIDGET (self)); filter = gtk_custom_filter_new ((GtkCustomFilterFunc) filter_func, self, NULL); gtk_filter_list_model_set_filter (self->filter_model, GTK_FILTER (filter)); } BzInspector * bz_inspector_new (void) { return g_object_new (BZ_TYPE_INSPECTOR, NULL); } BzStateInfo * bz_inspector_get_state (BzInspector *self) { g_return_val_if_fail (BZ_IS_INSPECTOR (self), NULL); return self->state; } void bz_inspector_set_state (BzInspector *self, BzStateInfo *state) { g_return_if_fail (BZ_IS_INSPECTOR (self)); g_clear_pointer (&self->state, g_object_unref); g_clear_pointer (&self->debug_mode_binding, g_object_unref); g_clear_pointer (&self->disable_blocklists_binding, g_object_unref); if (state != NULL) { self->state = g_object_ref (state); self->debug_mode_binding = g_object_bind_property ( state, "debug-mode", self->debug_mode_check, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); self->disable_blocklists_binding = g_object_bind_property ( state, "disable-blocklists", self->disable_blocklists_check, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_STATE]); } static gboolean filter_func (BzEntryGroup *group, BzInspector *self) { const char *text = NULL; const char *id = NULL; const char *title = NULL; text = gtk_editable_get_text (self->search_entry); id = bz_entry_group_get_id (group); title = bz_entry_group_get_title (group); if (text == NULL || *text == '\0') return TRUE; if (strcasestr (id, text) != NULL) return TRUE; if (strcasestr (title, text) != NULL) return TRUE; return FALSE; } /* End of bz-inspector.c */ bazaar-orig-v0.7.14/src/bz-decorated-screenshot.c0000664000175000017500000001166615166123241020623 0ustar hasanhasan/* bz-decorated-screenshot.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-decorated-screenshot.h" #include "bz-screenshot.h" #include struct _BzDecoratedScreenshot { GtkButton parent_instance; BzAsyncTexture *async_texture; /* Template widgets */ }; G_DEFINE_FINAL_TYPE (BzDecoratedScreenshot, bz_decorated_screenshot, GTK_TYPE_BUTTON) enum { PROP_0, PROP_ASYNC_TEXTURE, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bz_decorated_screenshot_dispose (GObject *object) { BzDecoratedScreenshot *self = BZ_DECORATED_SCREENSHOT (object); g_clear_pointer (&self->async_texture, g_object_unref); gtk_widget_dispose_template (GTK_WIDGET (self), BZ_TYPE_DECORATED_SCREENSHOT); G_OBJECT_CLASS (bz_decorated_screenshot_parent_class)->dispose (object); } static void bz_decorated_screenshot_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzDecoratedScreenshot *self = BZ_DECORATED_SCREENSHOT (object); switch (prop_id) { case PROP_ASYNC_TEXTURE: g_value_set_object (value, bz_decorated_screenshot_get_async_texture (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_decorated_screenshot_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzDecoratedScreenshot *self = BZ_DECORATED_SCREENSHOT (object); switch (prop_id) { case PROP_ASYNC_TEXTURE: bz_decorated_screenshot_set_async_texture (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_decorated_screenshot_class_init (BzDecoratedScreenshotClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bz_decorated_screenshot_set_property; object_class->get_property = bz_decorated_screenshot_get_property; object_class->dispose = bz_decorated_screenshot_dispose; props[PROP_ASYNC_TEXTURE] = g_param_spec_object ( "async-texture", NULL, NULL, BZ_TYPE_ASYNC_TEXTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-decorated-screenshot.ui"); } static void on_enter_notify (GtkEventController *controller, gpointer user_data) { g_autoptr (GdkCursor) cursor = gdk_cursor_new_from_name ("pointer", NULL); gtk_widget_set_cursor (GTK_WIDGET (user_data), cursor); } static void on_leave_notify (GtkEventController *controller, gpointer user_data) { gtk_widget_set_cursor (GTK_WIDGET (user_data), NULL); } static void bz_decorated_screenshot_init (BzDecoratedScreenshot *self) { GtkEventController *enter_leave = gtk_event_controller_motion_new (); gtk_widget_init_template (GTK_WIDGET (self)); g_signal_connect (enter_leave, "enter", G_CALLBACK (on_enter_notify), GTK_WIDGET (self)); g_signal_connect (enter_leave, "leave", G_CALLBACK (on_leave_notify), GTK_WIDGET (self)); gtk_widget_add_controller (GTK_WIDGET (self), enter_leave); } BzDecoratedScreenshot * bz_decorated_screenshot_new (void) { return g_object_new (BZ_TYPE_DECORATED_SCREENSHOT, NULL); } BzAsyncTexture * bz_decorated_screenshot_get_async_texture (BzDecoratedScreenshot *self) { g_return_val_if_fail (BZ_IS_DECORATED_SCREENSHOT (self), NULL); return self->async_texture; } void bz_decorated_screenshot_set_async_texture (BzDecoratedScreenshot *self, BzAsyncTexture *async_texture) { g_return_if_fail (BZ_IS_DECORATED_SCREENSHOT (self)); g_clear_pointer (&self->async_texture, g_object_unref); if (async_texture != NULL) self->async_texture = g_object_ref (async_texture); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ASYNC_TEXTURE]); } /* End of bz-decorated-screenshot.c */ bazaar-orig-v0.7.14/src/bz-screenshots-carousel.c0000664000175000017500000004742715166123241020675 0ustar hasanhasan/* bz-screenshots-carousel.c * * Copyright 2025 Alexander Vanhee * * Adapted from gs-screenshot-carousel.c * * Copyright (C) 2013-2016 Richard Hughes * Copyright (C) 2013 Matthias Clasen * Copyright (C) 2015-2019 Kalev Lember * Copyright (C) 2019 Joaquim Rocha * Copyright (C) 2021 Adrien Plazas * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include #include #include "bz-decorated-screenshot.h" #include "bz-screenshots-carousel.h" #include "bz-template-callbacks.h" #define LIGHT_CLASS "screenshot-carousel-light" #define DARK_CLASS "screenshot-carousel-dark" #define LIGHT_MIX_PERCENTAGE 15 #define DARK_MIX_PERCENTAGE 4 struct _BzScreenshotsCarousel { GtkWidget parent_instance; BgeCarousel *carousel; // GtkWidget *carousel_indicator; GtkButton *prev_button; GtkWidget *prev_button_revealer; GtkButton *next_button; GtkWidget *next_button_revealer; GtkSingleSelection *selection; GListModel *model; gboolean compact; char *light_accent_color; char *dark_accent_color; char *widget_css_class; GtkCssProvider *css; gulong items_changed_id; }; G_DEFINE_FINAL_TYPE (BzScreenshotsCarousel, bz_screenshots_carousel, GTK_TYPE_WIDGET) enum { PROP_0, PROP_MODEL, PROP_COMPACT, PROP_LIGHT_ACCENT_COLOR, PROP_DARK_ACCENT_COLOR, N_PROPS }; static GParamSpec *properties[N_PROPS]; enum { SIGNAL_CLICKED, N_SIGNALS }; static guint signals[N_SIGNALS]; static void refresh_css (BzScreenshotsCarousel *self); static void clear_css (BzScreenshotsCarousel *self); static void update_button_visibility (BzScreenshotsCarousel *self) { gdouble position; guint n_pages; if (!self->carousel) return; position = gtk_single_selection_get_selected (self->selection); n_pages = g_list_model_get_n_items (G_LIST_MODEL (self->selection)); /* gtk_widget_set_opacity (self->carousel_indicator, n_pages > 1); */ gtk_revealer_set_reveal_child (GTK_REVEALER (self->prev_button_revealer), position >= 0.5); gtk_revealer_set_reveal_child (GTK_REVEALER (self->next_button_revealer), position < n_pages - 1.5); } static void carousel_navigate (BzScreenshotsCarousel *self, AdwNavigationDirection direction) { guint n_children = 0; gdouble position = 0.0; n_children = g_list_model_get_n_items (G_LIST_MODEL (self->selection)); position = gtk_single_selection_get_selected (self->selection); position += (direction == ADW_NAVIGATION_DIRECTION_BACK) ? -1 : 1; position = round (position); position = MIN (position, n_children - 1); position = MAX (0, position); gtk_single_selection_set_selected (self->selection, position); } static void on_prev_clicked (BzScreenshotsCarousel *self) { if (!self->carousel) return; carousel_navigate (self, ADW_NAVIGATION_DIRECTION_BACK); } static void on_next_clicked (BzScreenshotsCarousel *self) { if (!self->carousel) return; carousel_navigate (self, ADW_NAVIGATION_DIRECTION_FORWARD); } static void on_notify_selected (BzScreenshotsCarousel *self) { update_button_visibility (self); } static void on_notify_n_items (BzScreenshotsCarousel *self) { update_button_visibility (self); } static void open_screenshot_at_index (BzScreenshotsCarousel *self, guint index) { guint n_items; if (!self->model) return; n_items = g_list_model_get_n_items (self->model); if (index >= n_items) return; g_signal_emit (self, signals[SIGNAL_CLICKED], 0, index); } static void on_screenshot_clicked (BzDecoratedScreenshot *screenshot, BzScreenshotsCarousel *self) { BzAsyncTexture *async_texture = NULL; guint index = 0; guint n_items = 0; if (!self->model) return; async_texture = bz_decorated_screenshot_get_async_texture (screenshot); if (async_texture == NULL) return; n_items = g_list_model_get_n_items (self->model); for (guint i = 0; i < n_items; i++) { g_autoptr (BzAsyncTexture) item = NULL; item = g_list_model_get_item (self->model, i); if (item == async_texture) { index = i; break; } } open_screenshot_at_index (self, index); } static void on_expand_clicked (BzScreenshotsCarousel *self) { gdouble position; guint index; guint n_pages; if (!self->carousel || !self->model) return; n_pages = g_list_model_get_n_items (G_LIST_MODEL (self->selection)); if (n_pages == 0) return; position = gtk_single_selection_get_selected (self->selection); index = (guint) round (position); index = MIN (index, n_pages - 1); open_screenshot_at_index (self, index); } static int get_carousel_height (BzScreenshotsCarousel *self) { return self->compact ? 250 : 375; } static void on_screenshot_focus_changed (BzDecoratedScreenshot *screenshot, GParamSpec *pspec, BzScreenshotsCarousel *self) { if (!self->carousel) return; if (gtk_widget_has_focus (GTK_WIDGET (screenshot))) { BzAsyncTexture *texture = NULL; guint n_items = 0; texture = bz_decorated_screenshot_get_async_texture (screenshot); n_items = g_list_model_get_n_items (self->model); for (guint i = 0; i < n_items; i++) { g_autoptr (BzAsyncTexture) item = NULL; item = g_list_model_get_item (self->model, i); if (item == texture) { gtk_single_selection_set_selected (self->selection, i); break; } } } } static GtkWidget * on_create_widget (BzScreenshotsCarousel *self, BzAsyncTexture *item, BgeCarousel *carousel) { GtkWidget *screenshot = NULL; g_autofree char *caption = NULL; guint n_items = 0; guint index = 0; screenshot = g_object_new (BZ_TYPE_DECORATED_SCREENSHOT, "async-texture", item, NULL); n_items = g_list_model_get_n_items (self->model); for (index = 0; index < n_items; index++) { g_autoptr (BzAsyncTexture) it = g_list_model_get_item (self->model, index); if (it == item) break; } caption = g_strdup_printf (_ ("Screenshot %u of %u"), index + 1, n_items); gtk_accessible_update_property (GTK_ACCESSIBLE (screenshot), GTK_ACCESSIBLE_PROPERTY_LABEL, caption, -1); g_signal_connect (screenshot, "clicked", G_CALLBACK (on_screenshot_clicked), self); g_signal_connect (screenshot, "notify::has-focus", G_CALLBACK (on_screenshot_focus_changed), self); return screenshot; } static void on_remove_widget (BzScreenshotsCarousel *self, BzDecoratedScreenshot *screenshot, BzAsyncTexture *item, BgeCarousel *carousel) { } static void dark_changed (BzScreenshotsCarousel *self, GParamSpec *pspec, AdwStyleManager *mgr) { gboolean is_dark; if (self->css == NULL) return; is_dark = adw_style_manager_get_dark (adw_style_manager_get_default ()); gtk_widget_remove_css_class (GTK_WIDGET (self), LIGHT_CLASS); gtk_widget_remove_css_class (GTK_WIDGET (self), DARK_CLASS); gtk_widget_add_css_class (GTK_WIDGET (self), is_dark ? DARK_CLASS : LIGHT_CLASS); } static void bz_screenshots_carousel_dispose (GObject *object) { BzScreenshotsCarousel *self = BZ_SCREENSHOTS_CAROUSEL (object); GtkWidget *root_child = gtk_widget_get_first_child (GTK_WIDGET (self)); if (self->model && self->items_changed_id) { g_signal_handler_disconnect (self->model, self->items_changed_id); self->items_changed_id = 0; } g_clear_object (&self->model); clear_css (self); g_clear_pointer (&self->light_accent_color, g_free); g_clear_pointer (&self->dark_accent_color, g_free); g_clear_pointer (&self->widget_css_class, g_free); if (root_child != NULL) gtk_widget_unparent (root_child); gtk_widget_dispose_template (GTK_WIDGET (self), BZ_TYPE_SCREENSHOTS_CAROUSEL); G_OBJECT_CLASS (bz_screenshots_carousel_parent_class)->dispose (object); } static void bz_screenshots_carousel_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzScreenshotsCarousel *self = BZ_SCREENSHOTS_CAROUSEL (object); switch (prop_id) { case PROP_MODEL: g_value_set_object (value, self->model); break; case PROP_COMPACT: g_value_set_boolean (value, self->compact); break; case PROP_LIGHT_ACCENT_COLOR: g_value_set_string (value, self->light_accent_color); break; case PROP_DARK_ACCENT_COLOR: g_value_set_string (value, self->dark_accent_color); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_screenshots_carousel_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzScreenshotsCarousel *self = BZ_SCREENSHOTS_CAROUSEL (object); switch (prop_id) { case PROP_MODEL: bz_screenshots_carousel_set_model (self, g_value_get_object (value)); break; case PROP_COMPACT: bz_screenshots_carousel_set_compact (self, g_value_get_boolean (value)); break; case PROP_LIGHT_ACCENT_COLOR: bz_screenshots_carousel_set_light_accent_color (self, g_value_get_string (value)); break; case PROP_DARK_ACCENT_COLOR: bz_screenshots_carousel_set_dark_accent_color (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_screenshots_carousel_class_init (BzScreenshotsCarouselClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_screenshots_carousel_dispose; object_class->get_property = bz_screenshots_carousel_get_property; object_class->set_property = bz_screenshots_carousel_set_property; properties[PROP_MODEL] = g_param_spec_object ("model", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); properties[PROP_COMPACT] = g_param_spec_boolean ("compact", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); properties[PROP_LIGHT_ACCENT_COLOR] = g_param_spec_string ("light-accent-color", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); properties[PROP_DARK_ACCENT_COLOR] = g_param_spec_string ("dark-accent-color", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPS, properties); signals[SIGNAL_CLICKED] = g_signal_new ("clicked", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-screenshots-carousel.ui"); bz_widget_class_bind_all_util_callbacks (widget_class); gtk_widget_class_bind_template_child (widget_class, BzScreenshotsCarousel, carousel); gtk_widget_class_bind_template_child (widget_class, BzScreenshotsCarousel, prev_button); gtk_widget_class_bind_template_child (widget_class, BzScreenshotsCarousel, prev_button_revealer); gtk_widget_class_bind_template_child (widget_class, BzScreenshotsCarousel, next_button); gtk_widget_class_bind_template_child (widget_class, BzScreenshotsCarousel, next_button_revealer); gtk_widget_class_bind_template_child (widget_class, BzScreenshotsCarousel, selection); gtk_widget_class_bind_template_callback (widget_class, on_prev_clicked); gtk_widget_class_bind_template_callback (widget_class, on_next_clicked); gtk_widget_class_bind_template_callback (widget_class, on_notify_selected); gtk_widget_class_bind_template_callback (widget_class, on_notify_n_items); gtk_widget_class_bind_template_callback (widget_class, on_create_widget); gtk_widget_class_bind_template_callback (widget_class, on_remove_widget); gtk_widget_class_bind_template_callback (widget_class, on_expand_clicked); gtk_widget_class_bind_template_callback (widget_class, get_carousel_height); gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT); gtk_widget_class_set_css_name (widget_class, "screenshot-carousel"); } static void bz_screenshots_carousel_init (BzScreenshotsCarousel *self) { gtk_widget_init_template (GTK_WIDGET (self)); g_signal_connect_object ( adw_style_manager_get_default (), "notify::dark", G_CALLBACK (dark_changed), self, G_CONNECT_SWAPPED); } GtkWidget * bz_screenshots_carousel_new (void) { return g_object_new (BZ_TYPE_SCREENSHOTS_CAROUSEL, NULL); } void bz_screenshots_carousel_set_model (BzScreenshotsCarousel *self, GListModel *model) { g_return_if_fail (BZ_IS_SCREENSHOTS_CAROUSEL (self)); g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model)); if (self->model == model) return; if (self->model && self->items_changed_id) { g_signal_handler_disconnect (self->model, self->items_changed_id); self->items_changed_id = 0; } g_clear_object (&self->model); if (model) { self->model = g_object_ref (model); gtk_single_selection_set_selected (self->selection, 0); } g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]); } GListModel * bz_screenshots_carousel_get_model (BzScreenshotsCarousel *self) { g_return_val_if_fail (BZ_IS_SCREENSHOTS_CAROUSEL (self), NULL); return self->model; } void bz_screenshots_carousel_set_compact (BzScreenshotsCarousel *self, gboolean compact) { g_return_if_fail (BZ_IS_SCREENSHOTS_CAROUSEL (self)); if (self->compact == compact) return; self->compact = compact; g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COMPACT]); } gboolean bz_screenshots_carousel_get_compact (BzScreenshotsCarousel *self) { g_return_val_if_fail (BZ_IS_SCREENSHOTS_CAROUSEL (self), FALSE); return self->compact; } void bz_screenshots_carousel_set_light_accent_color (BzScreenshotsCarousel *self, const char *color) { g_return_if_fail (BZ_IS_SCREENSHOTS_CAROUSEL (self)); if (color == self->light_accent_color || (color != NULL && g_strcmp0 (self->light_accent_color, color) == 0)) return; g_clear_pointer (&self->light_accent_color, g_free); if (color != NULL) self->light_accent_color = g_strdup (color); refresh_css (self); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LIGHT_ACCENT_COLOR]); } const char * bz_screenshots_carousel_get_light_accent_color (BzScreenshotsCarousel *self) { g_return_val_if_fail (BZ_IS_SCREENSHOTS_CAROUSEL (self), NULL); return self->light_accent_color; } void bz_screenshots_carousel_set_dark_accent_color (BzScreenshotsCarousel *self, const char *color) { g_return_if_fail (BZ_IS_SCREENSHOTS_CAROUSEL (self)); if (color == self->dark_accent_color || (color != NULL && g_strcmp0 (self->dark_accent_color, color) == 0)) return; g_clear_pointer (&self->dark_accent_color, g_free); if (color != NULL) self->dark_accent_color = g_strdup (color); refresh_css (self); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DARK_ACCENT_COLOR]); } const char * bz_screenshots_carousel_get_dark_accent_color (BzScreenshotsCarousel *self) { g_return_val_if_fail (BZ_IS_SCREENSHOTS_CAROUSEL (self), NULL); return self->dark_accent_color; } static void refresh_css (BzScreenshotsCarousel *self) { g_autofree char *css_string = NULL; g_autofree char *light_bg = NULL; g_autofree char *dark_bg = NULL; gboolean is_dark; clear_css (self); if (self->light_accent_color == NULL && self->dark_accent_color == NULL) return; self->widget_css_class = g_strdup_printf ("screenshot-carousel-%p", (void *) self); gtk_widget_add_css_class (GTK_WIDGET (self), self->widget_css_class); if (self->light_accent_color != NULL && self->dark_accent_color != NULL) light_bg = g_strdup_printf ("color-mix(in srgb, %s %d%%, rgb(255,255,255))", self->light_accent_color, LIGHT_MIX_PERCENTAGE); else if (self->light_accent_color != NULL) light_bg = g_strdup (self->light_accent_color); else if (self->dark_accent_color != NULL) light_bg = g_strdup_printf ("color-mix(in srgb, %s %d%%, rgb(255,255,255))", self->dark_accent_color, LIGHT_MIX_PERCENTAGE); if (self->light_accent_color != NULL && self->dark_accent_color != NULL) dark_bg = g_strdup_printf ("color-mix(in srgb, %s %d%%, rgb(29,29,32))", self->dark_accent_color, DARK_MIX_PERCENTAGE); else if (self->dark_accent_color != NULL) dark_bg = g_strdup (self->dark_accent_color); else if (self->light_accent_color != NULL) dark_bg = g_strdup_printf ("color-mix(in srgb, %s %d%%, rgb(29,29,32))", self->light_accent_color, DARK_MIX_PERCENTAGE); css_string = g_strdup_printf ( ".%s.%s{background-color:%s;}\n" ".%s.%s{background-color:%s;}", self->widget_css_class, LIGHT_CLASS, light_bg, self->widget_css_class, DARK_CLASS, dark_bg); self->css = gtk_css_provider_new (); gtk_css_provider_load_from_string (self->css, css_string); gtk_style_context_add_provider_for_display ( gdk_display_get_default (), GTK_STYLE_PROVIDER (self->css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); is_dark = adw_style_manager_get_dark (adw_style_manager_get_default ()); gtk_widget_add_css_class (GTK_WIDGET (self), is_dark ? DARK_CLASS : LIGHT_CLASS); } static void clear_css (BzScreenshotsCarousel *self) { gtk_widget_remove_css_class (GTK_WIDGET (self), LIGHT_CLASS); gtk_widget_remove_css_class (GTK_WIDGET (self), DARK_CLASS); if (self->widget_css_class != NULL) { gtk_widget_remove_css_class (GTK_WIDGET (self), self->widget_css_class); g_clear_pointer (&self->widget_css_class, g_free); } if (self->css != NULL) gtk_style_context_remove_provider_for_display ( gdk_display_get_default (), GTK_STYLE_PROVIDER (self->css)); g_clear_pointer (&self->css, g_object_unref); } bazaar-orig-v0.7.14/src/bz-lozenge.c0000664000175000017500000002400415166123241016147 0ustar hasanhasan/* bz-lozenge.c * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include "bz-context-row.h" #include "bz-lozenge.h" struct _BzLozenge { GtkBox parent_instance; gchar *title; gchar *label; gchar **icon_names; BzImportance importance; GtkWidget *icon_box; GtkWidget *label_widget; GtkWidget *title_label; }; G_DEFINE_FINAL_TYPE (BzLozenge, bz_lozenge, GTK_TYPE_BOX) enum { PROP_0, PROP_TITLE, PROP_LABEL, PROP_ICON_NAMES, PROP_IMPORTANCE, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { NULL }; static void bz_lozenge_rebuild (BzLozenge *self); static void bz_lozenge_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzLozenge *self = NULL; self = BZ_LOZENGE (object); switch (prop_id) { case PROP_TITLE: g_value_set_string (value, self->title); break; case PROP_LABEL: g_value_set_string (value, self->label); break; case PROP_ICON_NAMES: g_value_set_boxed (value, self->icon_names); break; case PROP_IMPORTANCE: g_value_set_enum (value, self->importance); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_lozenge_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzLozenge *self = NULL; self = BZ_LOZENGE (object); switch (prop_id) { case PROP_TITLE: bz_lozenge_set_title (self, g_value_get_string (value)); break; case PROP_LABEL: bz_lozenge_set_label (self, g_value_get_string (value)); break; case PROP_ICON_NAMES: bz_lozenge_set_icon_names (self, g_value_get_boxed (value)); break; case PROP_IMPORTANCE: bz_lozenge_set_importance (self, g_value_get_enum (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_lozenge_dispose (GObject *object) { BzLozenge *self = NULL; self = BZ_LOZENGE (object); g_clear_pointer (&self->title, g_free); g_clear_pointer (&self->label, g_free); g_clear_pointer (&self->icon_names, g_strfreev); g_clear_pointer (&self->icon_box, gtk_widget_unparent); g_clear_pointer (&self->label_widget, gtk_widget_unparent); g_clear_pointer (&self->title_label, gtk_widget_unparent); G_OBJECT_CLASS (bz_lozenge_parent_class)->dispose (object); } static void bz_lozenge_class_init (BzLozengeClass *klass) { GObjectClass *object_class = NULL; object_class = G_OBJECT_CLASS (klass); object_class->get_property = bz_lozenge_get_property; object_class->set_property = bz_lozenge_set_property; object_class->dispose = bz_lozenge_dispose; props[PROP_TITLE] = g_param_spec_string ("title", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_LABEL] = g_param_spec_string ("label", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_ICON_NAMES] = g_param_spec_boxed ("icon-names", NULL, NULL, G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_IMPORTANCE] = g_param_spec_enum ("importance", NULL, NULL, BZ_TYPE_IMPORTANCE, BZ_IMPORTANCE_NEUTRAL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_lozenge_init (BzLozenge *self) { GtkWidget *container = NULL; self->importance = BZ_IMPORTANCE_NEUTRAL; gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL); gtk_box_set_spacing (GTK_BOX (self), 12); gtk_widget_set_halign (GTK_WIDGET (self), GTK_ALIGN_CENTER); container = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_widget_set_halign (container, GTK_ALIGN_CENTER); gtk_box_append (GTK_BOX (self), container); self->icon_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); gtk_widget_set_halign (self->icon_box, GTK_ALIGN_CENTER); gtk_box_append (GTK_BOX (container), self->icon_box); self->label_widget = gtk_label_new (NULL); gtk_widget_set_halign (self->label_widget, GTK_ALIGN_CENTER); gtk_widget_add_css_class (self->label_widget, "circular-lozenge"); gtk_widget_add_css_class (self->label_widget, "large"); gtk_box_append (GTK_BOX (container), self->label_widget); self->title_label = gtk_label_new (NULL); gtk_label_set_justify (GTK_LABEL (self->title_label), GTK_JUSTIFY_CENTER); gtk_label_set_wrap (GTK_LABEL (self->title_label), TRUE); gtk_label_set_wrap_mode (GTK_LABEL (self->title_label), PANGO_WRAP_WORD_CHAR); gtk_label_set_xalign (GTK_LABEL (self->title_label), 0.5); gtk_widget_add_css_class (self->title_label, "title-2"); gtk_box_append (GTK_BOX (self), self->title_label); bz_lozenge_rebuild (self); } GtkWidget * bz_lozenge_new (void) { return g_object_new (BZ_TYPE_LOZENGE, NULL); } void bz_lozenge_set_title (BzLozenge *self, const gchar *title) { g_return_if_fail (BZ_IS_LOZENGE (self)); if (g_strcmp0 (self->title, title) == 0) return; g_clear_pointer (&self->title, g_free); self->title = g_strdup (title); bz_lozenge_rebuild (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TITLE]); } const gchar * bz_lozenge_get_title (BzLozenge *self) { g_return_val_if_fail (BZ_IS_LOZENGE (self), NULL); return self->title; } void bz_lozenge_set_label (BzLozenge *self, const gchar *label) { g_return_if_fail (BZ_IS_LOZENGE (self)); if (g_strcmp0 (self->label, label) == 0) return; g_clear_pointer (&self->label, g_free); self->label = g_strdup (label); bz_lozenge_rebuild (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_LABEL]); } const gchar * bz_lozenge_get_label (BzLozenge *self) { g_return_val_if_fail (BZ_IS_LOZENGE (self), NULL); return self->label; } void bz_lozenge_set_icon_names (BzLozenge *self, const gchar *const *icon_names) { g_return_if_fail (BZ_IS_LOZENGE (self)); g_clear_pointer (&self->icon_names, g_strfreev); self->icon_names = g_strdupv ((gchar **) icon_names); bz_lozenge_rebuild (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ICON_NAMES]); } gchar ** bz_lozenge_get_icon_names (BzLozenge *self) { g_return_val_if_fail (BZ_IS_LOZENGE (self), NULL); return g_strdupv (self->icon_names); } void bz_lozenge_set_importance (BzLozenge *self, BzImportance importance) { g_return_if_fail (BZ_IS_LOZENGE (self)); if (self->importance == importance) return; self->importance = importance; bz_lozenge_rebuild (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_IMPORTANCE]); } BzImportance bz_lozenge_get_importance (BzLozenge *self) { g_return_val_if_fail (BZ_IS_LOZENGE (self), BZ_IMPORTANCE_NEUTRAL); return self->importance; } static void bz_lozenge_rebuild (BzLozenge *self) { GtkWidget *child = NULL; const gchar *css_class = NULL; g_return_if_fail (BZ_IS_LOZENGE (self)); while ((child = gtk_widget_get_first_child (self->icon_box)) != NULL) gtk_box_remove (GTK_BOX (self->icon_box), child); if (self->icon_names != NULL && self->icon_names[0] != NULL) { gtk_widget_set_visible (self->icon_box, TRUE); gtk_widget_set_visible (self->label_widget, FALSE); css_class = bz_context_row_importance_to_css_class (self->importance); for (gsize i = 0; self->icon_names[i] != NULL; i++) { GtkWidget *icon = NULL; icon = gtk_image_new_from_icon_name (self->icon_names[i]); gtk_image_set_pixel_size (GTK_IMAGE (icon), 24); gtk_widget_set_halign (icon, GTK_ALIGN_CENTER); gtk_widget_add_css_class (icon, "circular-lozenge"); gtk_widget_add_css_class (icon, css_class); gtk_widget_add_css_class (icon, "large"); gtk_box_append (GTK_BOX (self->icon_box), icon); } } else if (self->label != NULL && *self->label != '\0') { const gchar *new_classes[3] = { "circular-lozenge", "large", NULL }; gtk_widget_set_visible (self->icon_box, FALSE); gtk_widget_set_visible (self->label_widget, TRUE); gtk_label_set_markup (GTK_LABEL (self->label_widget), self->label); gtk_widget_set_css_classes (self->label_widget, new_classes); css_class = bz_context_row_importance_to_css_class (self->importance); gtk_widget_add_css_class (self->label_widget, css_class); } else { gtk_widget_set_visible (self->icon_box, FALSE); gtk_widget_set_visible (self->label_widget, FALSE); } if (self->title != NULL && *self->title != '\0') { gtk_label_set_text (GTK_LABEL (self->title_label), self->title); gtk_widget_set_visible (self->title_label, TRUE); } else { gtk_widget_set_visible (self->title_label, FALSE); } } bazaar-orig-v0.7.14/src/bz-user-data-tile.blp0000664000175000017500000000506415166123241017664 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzUserDataTile: Adw.Bin { child: Revealer { transition-type: slide_down; reveal-child: bind $invert_boolean($is_zero(template.group as <$BzEntryGroup>.user-data-size) as ) as ; child: Adw.Bin { accessibility { labelled-by: title_label; described-by: description_label; } margin-bottom: 4; margin-start: 4; margin-end: 4; margin-top: 4; styles [ "card", ] child: Box { orientation: horizontal; spacing: 10; Picture icon_picture { margin-start: 10; margin-top: 10; margin-bottom: 10; height-request: 48; width-request: 48; paintable: bind template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable; visible: bind $invert_boolean($is_null(template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable) as ) as ; styles ["icon-dropshadow"] } Image fallback_icon { margin-start: 10; margin-top: 10; margin-bottom: 10; height-request: 48; width-request: 48; pixel-size: 48; icon-name: "application-x-executable"; visible: bind $is_null(template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable) as ; styles ["icon-dropshadow"] } Box { orientation: vertical; valign: center; spacing: 4; Label title_label { xalign: 0.0; ellipsize: end; single-line-mode: true; has-tooltip: true; tooltip-text: bind template.group as <$BzEntryGroup>.id; label: bind template.group as <$BzEntryGroup>.title; } Label description_label { halign: start; label: bind $format_size(template.group as <$BzEntryGroup>.user-data-size as ) as ; styles ["accent", "caption-heading"] } } Button remove_button { styles [ "flat", "destructive-action", ] hexpand: true; halign: end; width-request: 32; height-request: 32; valign: center; margin-end: 16; has-tooltip: true; tooltip-text: _("Trash User Data"); icon-name: "user-trash-symbolic"; clicked => $remove_cb() swapped; } }; }; }; } bazaar-orig-v0.7.14/src/dl-worker.c0000664000175000017500000001301415166123241016000 0ustar hasanhasan/* dl-worker.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::DL-WORKER-SUBPROCESS" #include "bz-env.h" #include "bz-global-net.h" #include "bz-util.h" BZ_DEFINE_DATA ( main, Main, { GMainLoop *loop; GIOChannel *stdout_channel; }, BZ_RELEASE_DATA (loop, g_main_loop_unref); BZ_RELEASE_DATA (stdout_channel, g_io_channel_unref)); BZ_DEFINE_DATA ( download, Download, { char *src; char *dest; GIOChannel *stdout_channel; }, BZ_RELEASE_DATA (src, g_free); BZ_RELEASE_DATA (dest, g_free); BZ_RELEASE_DATA (stdout_channel, g_io_channel_unref)); static DexFuture * read_stdin (MainData *data); static DexFuture * download_fiber (DownloadData *data); int main (int argc, char *argv[]) { g_autoptr (GIOChannel) stdout_channel = NULL; g_autoptr (GMainLoop) main_loop = NULL; g_autoptr (MainData) data = NULL; g_autoptr (DexFuture) future = NULL; g_log_writer_default_set_use_stderr (TRUE); dex_init (); stdout_channel = g_io_channel_unix_new (STDOUT_FILENO); g_assert (g_io_channel_set_encoding (stdout_channel, NULL, NULL)); g_io_channel_set_buffered (stdout_channel, FALSE); main_loop = g_main_loop_new (NULL, FALSE); data = main_data_new (); data->loop = g_main_loop_ref (main_loop); data->stdout_channel = g_io_channel_ref (stdout_channel); future = dex_scheduler_spawn ( dex_thread_pool_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) read_stdin, main_data_ref (data), main_data_unref); g_main_loop_run (main_loop); return EXIT_SUCCESS; } static DexFuture * read_stdin (MainData *data) { g_autoptr (GIOChannel) stdin_channel = NULL; stdin_channel = g_io_channel_unix_new (STDIN_FILENO); for (;;) { g_autoptr (GError) local_error = NULL; g_autofree char *string = NULL; char *newline = NULL; g_autoptr (GVariant) variant = NULL; g_autofree char *src_uri = NULL; g_autofree char *dest_path = NULL; g_autoptr (DownloadData) dl_data = NULL; g_io_channel_read_line ( stdin_channel, &string, NULL, NULL, &local_error); if (string == NULL) { if (local_error != NULL) g_warning ("FATAL: Failure reading stdin channel: %s", local_error->message); g_main_loop_quit (data->loop); return NULL; } newline = g_utf8_strchr (string, -1, '\n'); if (newline != NULL) *newline = '\0'; variant = g_variant_parse ( G_VARIANT_TYPE ("(ss)"), string, NULL, NULL, &local_error); if (variant == NULL) { g_warning ("Failure parsing variant text '%s' into structure: %s\n", string, local_error->message); g_main_loop_quit (data->loop); continue; } g_variant_get (variant, "(ss)", &src_uri, &dest_path); dl_data = download_data_new (); dl_data->src = g_steal_pointer (&src_uri); dl_data->dest = g_steal_pointer (&dest_path); dl_data->stdout_channel = g_io_channel_ref (data->stdout_channel); dex_future_disown (dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) download_fiber, download_data_ref (dl_data), download_data_unref)); } return NULL; } static DexFuture * download_fiber (DownloadData *data) { gboolean success = FALSE; g_autoptr (GError) local_error = NULL; g_autoptr (GFile) dest_file = NULL; g_autoptr (GFileOutputStream) dest_output = NULL; g_autoptr (SoupMessage) message = NULL; g_autoptr (GVariant) variant = NULL; g_autofree char *output = NULL; g_autofree char *output_plus_nl = NULL; dest_file = g_file_new_for_path (data->dest); dest_output = g_file_replace ( dest_file, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL, &local_error); if (dest_output == NULL) { g_warning ("%s", local_error->message); goto done; } message = soup_message_new (SOUP_METHOD_GET, data->src); success = dex_await (bz_send_with_global_http_session_then_splice_into ( message, G_OUTPUT_STREAM (dest_output)), &local_error); if (!success) { g_warning ("%s", local_error->message); goto done; } done: variant = g_variant_new ("(sb)", data->dest, success); output = g_variant_print (variant, TRUE); output_plus_nl = g_strdup_printf ("%s\n", output); g_io_channel_write_chars (data->stdout_channel, output_plus_nl, -1, NULL, NULL); return dex_future_new_true (); } bazaar-orig-v0.7.14/src/bz-transaction-list-dialog.c0000664000175000017500000001347715166123241021253 0ustar hasanhasan/* bz-transaction-list-dialog.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include "bz-entry.h" #include "bz-transaction-list-dialog.h" struct _BzTransactionListDialog { AdwAlertDialog parent_instance; GListModel *entries; gboolean confirmed; GtkFilterListModel *app_filter; /* Template widgets */ GtkNoSelection *selection_model; GtkLabel *secondary_label; }; G_DEFINE_FINAL_TYPE (BzTransactionListDialog, bz_transaction_list_dialog, ADW_TYPE_ALERT_DIALOG) static gboolean match_for_app (BzEntry *item, gpointer user_data); static void on_response (AdwAlertDialog *alert, gchar *response, BzTransactionListDialog *self); static void bz_transaction_list_dialog_dispose (GObject *object) { BzTransactionListDialog *self = BZ_TRANSACTION_LIST_DIALOG (object); g_clear_object (&self->entries); g_clear_object (&self->app_filter); G_OBJECT_CLASS (bz_transaction_list_dialog_parent_class)->dispose (object); } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static gboolean is_null (gpointer object, GObject *value) { return value == NULL; } static void bz_transaction_list_dialog_class_init (BzTransactionListDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_transaction_list_dialog_dispose; gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-transaction-list-dialog.ui"); gtk_widget_class_bind_template_child (widget_class, BzTransactionListDialog, selection_model); gtk_widget_class_bind_template_child (widget_class, BzTransactionListDialog, secondary_label); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, is_null); } static void bz_transaction_list_dialog_init (BzTransactionListDialog *self) { GtkCustomFilter *filter = NULL; gtk_widget_init_template (GTK_WIDGET (self)); g_signal_connect (self, "response", G_CALLBACK (on_response), self); filter = gtk_custom_filter_new ((GtkCustomFilterFunc) match_for_app, NULL, NULL); self->app_filter = gtk_filter_list_model_new (NULL, GTK_FILTER (filter)); gtk_no_selection_set_model (self->selection_model, G_LIST_MODEL (self->app_filter)); } static void on_response (AdwAlertDialog *alert, gchar *response, BzTransactionListDialog *self) { self->confirmed = g_strcmp0 (response, "confirm") == 0; } AdwDialog * bz_transaction_list_dialog_new (GListModel *entries, const gchar *heading, const gchar *body, const gchar *body_no_apps, const gchar *secondary_label, const gchar *cancel_label, const gchar *confirm_label) { BzTransactionListDialog *dialog = NULL; guint n_total = 0; guint n_apps = 0; guint n_other = 0; g_return_val_if_fail (G_IS_LIST_MODEL (entries), NULL); dialog = g_object_new (BZ_TYPE_TRANSACTION_LIST_DIALOG, NULL); dialog->entries = g_object_ref (entries); gtk_filter_list_model_set_model (dialog->app_filter, entries); adw_alert_dialog_add_response (ADW_ALERT_DIALOG (dialog), "cancel", cancel_label); adw_alert_dialog_add_response (ADW_ALERT_DIALOG (dialog), "confirm", confirm_label); adw_alert_dialog_set_response_appearance (ADW_ALERT_DIALOG (dialog), "confirm", ADW_RESPONSE_SUGGESTED); adw_alert_dialog_set_heading (ADW_ALERT_DIALOG (dialog), heading); n_total = g_list_model_get_n_items (entries); n_apps = g_list_model_get_n_items (G_LIST_MODEL (dialog->app_filter)); n_other = n_total - n_apps; if (n_total > 0) { if (n_apps == 0 && body_no_apps != NULL) { g_autofree char *formatted_body = NULL; formatted_body = g_strdup_printf (body_no_apps, n_other); adw_alert_dialog_set_body (ADW_ALERT_DIALOG (dialog), formatted_body); adw_alert_dialog_set_extra_child (ADW_ALERT_DIALOG (dialog), NULL); } else { adw_alert_dialog_set_body (ADW_ALERT_DIALOG (dialog), body); if (n_other > 0 && secondary_label != NULL) { g_autofree char *formatted_label = NULL; formatted_label = g_strdup_printf (secondary_label, n_other); gtk_label_set_label (dialog->secondary_label, formatted_label); gtk_widget_set_visible (GTK_WIDGET (dialog->secondary_label), TRUE); } } } return ADW_DIALOG (dialog); } gboolean bz_transaction_list_dialog_was_confirmed (BzTransactionListDialog *self) { g_return_val_if_fail (BZ_IS_TRANSACTION_LIST_DIALOG (self), FALSE); return self->confirmed; } static gboolean match_for_app (BzEntry *item, gpointer user_data) { return bz_entry_is_of_kinds (item, BZ_ENTRY_KIND_APPLICATION); } bazaar-orig-v0.7.14/src/bz-category-flags.c0000664000175000017500000001235615166123241017422 0ustar hasanhasan/* bz-category-flags.c * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include "bz-category-flags.h" static const struct { const char *name; BzCategoryFlags flag; } name_flag_map[] = { { "audiovideo", BZ_CATEGORY_FLAGS_AUDIOVIDEO }, { "development", BZ_CATEGORY_FLAGS_DEVELOPMENT }, { "education", BZ_CATEGORY_FLAGS_EDUCATION }, { "game", BZ_CATEGORY_FLAGS_GAME }, { "graphics", BZ_CATEGORY_FLAGS_GRAPHICS }, { "network", BZ_CATEGORY_FLAGS_NETWORK }, { "office", BZ_CATEGORY_FLAGS_OFFICE }, { "science", BZ_CATEGORY_FLAGS_SCIENCE }, { "system", BZ_CATEGORY_FLAGS_SYSTEM }, { "utility", BZ_CATEGORY_FLAGS_UTILITY }, { "trending", BZ_CATEGORY_FLAGS_TRENDING }, { "popular", BZ_CATEGORY_FLAGS_POPULAR }, { "recently-added", BZ_CATEGORY_FLAGS_RECENTLY_ADDED }, { "recently-updated", BZ_CATEGORY_FLAGS_RECENTLY_UPDATED }, { "mobile", BZ_CATEGORY_FLAGS_MOBILE }, { "adwaita", BZ_CATEGORY_FLAGS_ADWAITA }, { "kde", BZ_CATEGORY_FLAGS_KDE }, }; GType bz_category_flags_get_type (void) { static gsize g_define_type_id = 0; if (g_once_init_enter (&g_define_type_id)) { static const GFlagsValue values[] = { { BZ_CATEGORY_FLAGS_NONE, "BZ_CATEGORY_FLAGS_NONE", "none" }, { BZ_CATEGORY_FLAGS_AUDIOVIDEO, "BZ_CATEGORY_FLAGS_AUDIOVIDEO", "audiovideo" }, { BZ_CATEGORY_FLAGS_DEVELOPMENT, "BZ_CATEGORY_FLAGS_DEVELOPMENT", "development" }, { BZ_CATEGORY_FLAGS_EDUCATION, "BZ_CATEGORY_FLAGS_EDUCATION", "education" }, { BZ_CATEGORY_FLAGS_GAME, "BZ_CATEGORY_FLAGS_GAME", "game" }, { BZ_CATEGORY_FLAGS_GRAPHICS, "BZ_CATEGORY_FLAGS_GRAPHICS", "graphics" }, { BZ_CATEGORY_FLAGS_NETWORK, "BZ_CATEGORY_FLAGS_NETWORK", "network" }, { BZ_CATEGORY_FLAGS_OFFICE, "BZ_CATEGORY_FLAGS_OFFICE", "office" }, { BZ_CATEGORY_FLAGS_SCIENCE, "BZ_CATEGORY_FLAGS_SCIENCE", "science" }, { BZ_CATEGORY_FLAGS_SYSTEM, "BZ_CATEGORY_FLAGS_SYSTEM", "system" }, { BZ_CATEGORY_FLAGS_UTILITY, "BZ_CATEGORY_FLAGS_UTILITY", "utility" }, { BZ_CATEGORY_FLAGS_TRENDING, "BZ_CATEGORY_FLAGS_TRENDING", "trending" }, { BZ_CATEGORY_FLAGS_POPULAR, "BZ_CATEGORY_FLAGS_POPULAR", "popular" }, { BZ_CATEGORY_FLAGS_RECENTLY_ADDED, "BZ_CATEGORY_FLAGS_RECENTLY_ADDED", "recently-added" }, { BZ_CATEGORY_FLAGS_RECENTLY_UPDATED, "BZ_CATEGORY_FLAGS_RECENTLY_UPDATED", "recently-updated" }, { BZ_CATEGORY_FLAGS_MOBILE, "BZ_CATEGORY_FLAGS_MOBILE", "mobile" }, { BZ_CATEGORY_FLAGS_ADWAITA, "BZ_CATEGORY_FLAGS_ADWAITA", "adwaita" }, { BZ_CATEGORY_FLAGS_KDE, "BZ_CATEGORY_FLAGS_KDE", "kde" }, { 0, NULL, NULL } }; GType type = g_flags_register_static ("BzCategoryFlags", values); g_once_init_leave (&g_define_type_id, type); } return g_define_type_id; } BzCategoryFlags bz_category_flags_add (BzCategoryFlags flags, const char *name) { g_autofree char *lower = NULL; if (name == NULL) return flags; lower = g_ascii_strdown (name, -1); for (gsize i = 0; i < G_N_ELEMENTS (name_flag_map); i++) { if (g_strcmp0 (name_flag_map[i].name, lower) == 0) return flags | name_flag_map[i].flag; } return flags; } gboolean bz_category_flags_has_name (BzCategoryFlags flags, const char *name) { for (gsize i = 0; i < G_N_ELEMENTS (name_flag_map); i++) { if (g_strcmp0 (name_flag_map[i].name, name) == 0) return (flags & name_flag_map[i].flag) != 0; } return FALSE; } BzCategoryFlags bz_category_flags_from_name (const char *name) { g_autofree char *lower = g_ascii_strdown (name, -1); for (gsize i = 0; i < G_N_ELEMENTS (name_flag_map); i++) if (g_strcmp0 (name_flag_map[i].name, lower) == 0) return name_flag_map[i].flag; return BZ_CATEGORY_FLAGS_NONE; } bazaar-orig-v0.7.14/src/bz-inhibited-scrollable.h0000664000175000017500000000242415166123241020572 0ustar hasanhasan/* bz-inhibited-scrollable.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_INHIBITED_SCROLLABLE (bz_inhibited_scrollable_get_type ()) G_DECLARE_FINAL_TYPE (BzInhibitedScrollable, bz_inhibited_scrollable, BZ, INHIBITED_SCROLLABLE, GtkWidget) GtkWidget * bz_inhibited_scrollable_new (void); void bz_inhibited_scrollable_set_scrollable (BzInhibitedScrollable *self, GtkScrollable *scrollable); GtkScrollable * bz_inhibited_scrollable_get_scrollable (BzInhibitedScrollable *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-rounded-picture.c0000664000175000017500000002164415166123241017624 0ustar hasanhasan/* bz-rounded-picture.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-rounded-picture.h" struct _BzRoundedPicture { GtkWidget parent_instance; GdkPaintable *paintable; double radius; }; G_DEFINE_FINAL_TYPE (BzRoundedPicture, bz_rounded_picture, GTK_TYPE_WIDGET) enum { PROP_0, PROP_PAINTABLE, PROP_RADIUS, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { NULL }; static void invalidate_contents (BzRoundedPicture *self, GdkPaintable *paintable) { gtk_widget_queue_draw (GTK_WIDGET (self)); } static void invalidate_size (BzRoundedPicture *self, GdkPaintable *paintable) { gtk_widget_queue_resize (GTK_WIDGET (self)); } static void bz_rounded_picture_dispose (GObject *object) { BzRoundedPicture *self = BZ_ROUNDED_PICTURE (object); if (self->paintable != NULL) { g_signal_handlers_disconnect_by_func (self->paintable, invalidate_contents, self); g_signal_handlers_disconnect_by_func (self->paintable, invalidate_size, self); } g_clear_object (&self->paintable); G_OBJECT_CLASS (bz_rounded_picture_parent_class)->dispose (object); } static void bz_rounded_picture_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzRoundedPicture *self = BZ_ROUNDED_PICTURE (object); switch (prop_id) { case PROP_PAINTABLE: g_value_set_object (value, self->paintable); break; case PROP_RADIUS: g_value_set_double (value, self->radius); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_rounded_picture_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzRoundedPicture *self = BZ_ROUNDED_PICTURE (object); switch (prop_id) { case PROP_PAINTABLE: bz_rounded_picture_set_paintable (self, g_value_get_object (value)); break; case PROP_RADIUS: bz_rounded_picture_set_radius (self, g_value_get_double (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_rounded_picture_measure (GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline) { BzRoundedPicture *self = BZ_ROUNDED_PICTURE (widget); *minimum = 0; *natural = 0; if (self->paintable == NULL) return; if (orientation == GTK_ORIENTATION_HORIZONTAL) { *natural = gdk_paintable_get_intrinsic_width (self->paintable); } else { *natural = gdk_paintable_get_intrinsic_height (self->paintable); } } static void bz_rounded_picture_snapshot (GtkWidget *widget, GtkSnapshot *snapshot) { BzRoundedPicture *self = BZ_ROUNDED_PICTURE (widget); int widget_width; int widget_height; double paintable_width; double paintable_height; double paintable_aspect; double widget_aspect; double scale; double draw_width, draw_height; double x, y; GskRoundedRect rect; GskShadow shadow; if (self->paintable == NULL) return; widget_width = gtk_widget_get_width (widget); widget_height = gtk_widget_get_height (widget); if (widget_width <= 0 || widget_height <= 0) return; paintable_width = gdk_paintable_get_intrinsic_width (self->paintable); paintable_height = gdk_paintable_get_intrinsic_height (self->paintable); if (paintable_width <= 0 || paintable_height <= 0) { paintable_width = widget_width; paintable_height = widget_height; } paintable_aspect = paintable_width / paintable_height; widget_aspect = (double) widget_width / (double) widget_height; if (widget_aspect > paintable_aspect) { scale = (double) widget_height / paintable_height; draw_height = widget_height; draw_width = paintable_width * scale; } else { scale = (double) widget_width / paintable_width; draw_width = widget_width; draw_height = paintable_height * scale; } x = (widget_width - draw_width) / 2.0; y = (widget_height - draw_height) / 2.0; shadow.color.red = 0.0; shadow.color.green = 0.0; shadow.color.blue = 0.0; shadow.color.alpha = 0.35; shadow.dx = 0.0; shadow.dy = 2.0; shadow.radius = 16.0; gtk_snapshot_push_shadow (snapshot, &shadow, 1); gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y)); gsk_rounded_rect_init_from_rect (&rect, &GRAPHENE_RECT_INIT (0, 0, draw_width, draw_height), self->radius); gtk_snapshot_push_rounded_clip (snapshot, &rect); gdk_paintable_snapshot (self->paintable, snapshot, draw_width, draw_height); gtk_snapshot_pop (snapshot); gtk_snapshot_pop (snapshot); } static void bz_rounded_picture_class_init (BzRoundedPictureClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_rounded_picture_dispose; object_class->get_property = bz_rounded_picture_get_property; object_class->set_property = bz_rounded_picture_set_property; widget_class->measure = bz_rounded_picture_measure; widget_class->snapshot = bz_rounded_picture_snapshot; props[PROP_PAINTABLE] = g_param_spec_object ("paintable", NULL, NULL, GDK_TYPE_PAINTABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_RADIUS] = g_param_spec_double ("radius", NULL, NULL, 0.0, G_MAXDOUBLE, 12.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_rounded_picture_init (BzRoundedPicture *self) { self->radius = 12.0; } GtkWidget * bz_rounded_picture_new (void) { return g_object_new (BZ_TYPE_ROUNDED_PICTURE, NULL); } void bz_rounded_picture_set_paintable (BzRoundedPicture *self, GdkPaintable *paintable) { g_return_if_fail (BZ_IS_ROUNDED_PICTURE (self)); g_return_if_fail (paintable == NULL || GDK_IS_PAINTABLE (paintable)); if (self->paintable == paintable) return; if (self->paintable != NULL) { g_signal_handlers_disconnect_by_func (self->paintable, invalidate_contents, self); g_signal_handlers_disconnect_by_func (self->paintable, invalidate_size, self); } g_clear_object (&self->paintable); if (paintable != NULL) { self->paintable = g_object_ref (paintable); g_signal_connect_swapped (self->paintable, "invalidate-contents", G_CALLBACK (invalidate_contents), self); g_signal_connect_swapped (self->paintable, "invalidate-size", G_CALLBACK (invalidate_size), self); } gtk_widget_queue_resize (GTK_WIDGET (self)); gtk_widget_queue_draw (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PAINTABLE]); } GdkPaintable * bz_rounded_picture_get_paintable (BzRoundedPicture *self) { g_return_val_if_fail (BZ_IS_ROUNDED_PICTURE (self), NULL); return self->paintable; } void bz_rounded_picture_set_radius (BzRoundedPicture *self, double radius) { g_return_if_fail (BZ_IS_ROUNDED_PICTURE (self)); if (self->radius == radius) return; self->radius = radius; gtk_widget_queue_draw (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_RADIUS]); } double bz_rounded_picture_get_radius (BzRoundedPicture *self) { g_return_val_if_fail (BZ_IS_ROUNDED_PICTURE (self), 0.0); return self->radius; } bazaar-orig-v0.7.14/src/bz-backend.h0000664000175000017500000001037615166123241016107 0ustar hasanhasan/* bz-backend.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-entry.h" G_BEGIN_DECLS #define BZ_TYPE_BACKEND (bz_backend_get_type ()) G_DECLARE_INTERFACE (BzBackend, bz_backend, BZ, BACKEND, GObject) struct _BzBackendInterface { GTypeInterface parent_iface; DexChannel *(*create_notification_channel) (BzBackend *self); /* DexFuture* -> char*|BzEntry* */ DexFuture *(*load_local_package) (BzBackend *self, GFile *file, GCancellable *cancellable); /* DexFuture* -> gboolean */ DexFuture *(*retrieve_remote_entries) (BzBackend *self, GCancellable *cancellable); /* DexFuture* -> GHashTable* */ DexFuture *(*retrieve_install_ids) (BzBackend *self, GCancellable *cancellable); /* DexFuture* -> GPtrArray* -> char* */ DexFuture *(*retrieve_update_ids) (BzBackend *self, GCancellable *cancellable); /* DexFuture* -> GListModel* (of BzRepository objects) */ DexFuture *(*list_repositories) (BzBackend *self, GCancellable *cancellable); /* DexFuture* -> gboolean */ DexFuture *(*schedule_transaction) (BzBackend *self, BzEntry **installs, guint n_installs, BzEntry **updates, guint n_updates, BzEntry **removals, guint n_removals, DexChannel *channel, GCancellable *cancellable); gboolean (*cancel_task_for_entry) (BzBackend *self, BzEntry *entry); }; DexChannel * bz_backend_create_notification_channel (BzBackend *self); DexFuture * bz_backend_load_local_package (BzBackend *self, GFile *file, GCancellable *cancellable); DexFuture * bz_backend_retrieve_remote_entries (BzBackend *self, GCancellable *cancellable); DexFuture * bz_backend_retrieve_install_ids (BzBackend *self, GCancellable *cancellable); DexFuture * bz_backend_retrieve_update_ids (BzBackend *self, GCancellable *cancellable); DexFuture * bz_backend_list_repositories (BzBackend *self, GCancellable *cancellable); DexFuture * bz_backend_schedule_transaction (BzBackend *self, BzEntry **installs, guint n_installs, BzEntry **updates, guint n_updates, BzEntry **removals, guint n_removals, DexChannel *channel, GCancellable *cancellable); DexFuture * bz_backend_merge_and_schedule_transactions (BzBackend *self, GListModel *transactions, DexChannel *channel, GCancellable *cancellable); gboolean bz_backend_cancel_task_for_entry (BzBackend *self, BzEntry *entry); G_END_DECLS bazaar-orig-v0.7.14/src/bz-result.c0000664000175000017500000001666615166123241016041 0ustar hasanhasan/* bz-result.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-result.h" struct _BzResult { GObject parent_instance; DexFuture *finally; GObject *object; GError *error; GTimer *timer; char *non_error_msg; }; G_DEFINE_FINAL_TYPE (BzResult, bz_result, G_TYPE_OBJECT); enum { PROP_0, PROP_PENDING, PROP_RESOLVED, PROP_REJECTED, PROP_OBJECT, PROP_MESSAGE, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static DexFuture * future_finally (DexFuture *future, BzResult *self); static void bz_result_dispose (GObject *object) { BzResult *self = BZ_RESULT (object); dex_clear (&self->finally); g_clear_object (&self->object); g_clear_pointer (&self->error, g_error_free); g_clear_pointer (&self->timer, g_timer_destroy); g_clear_pointer (&self->non_error_msg, g_free); G_OBJECT_CLASS (bz_result_parent_class)->dispose (object); } static void bz_result_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzResult *self = BZ_RESULT (object); switch (prop_id) { case PROP_PENDING: g_value_set_boolean (value, bz_result_get_pending (self)); break; case PROP_RESOLVED: g_value_set_boolean (value, bz_result_get_resolved (self)); break; case PROP_REJECTED: g_value_set_boolean (value, bz_result_get_rejected (self)); break; case PROP_OBJECT: g_value_set_object (value, bz_result_get_object (self)); break; case PROP_MESSAGE: g_value_set_string (value, bz_result_get_message (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_result_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { // BzResult *self = BZ_RESULT (object); switch (prop_id) { case PROP_PENDING: case PROP_RESOLVED: case PROP_REJECTED: case PROP_OBJECT: case PROP_MESSAGE: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_result_class_init (BzResultClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bz_result_set_property; object_class->get_property = bz_result_get_property; object_class->dispose = bz_result_dispose; props[PROP_PENDING] = g_param_spec_boolean ( "pending", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_RESOLVED] = g_param_spec_boolean ( "resolved", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_REJECTED] = g_param_spec_boolean ( "rejected", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_OBJECT] = g_param_spec_object ( "object", NULL, NULL, G_TYPE_OBJECT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_MESSAGE] = g_param_spec_string ( "message", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_result_init (BzResult *self) { } BzResult * bz_result_new (DexFuture *future) { BzResult *self = NULL; DexFutureStatus status = DEX_FUTURE_STATUS_PENDING; g_return_val_if_fail (DEX_IS_FUTURE (future), NULL); self = g_object_new (BZ_TYPE_RESULT, NULL); status = dex_future_get_status (future); switch (status) { case DEX_FUTURE_STATUS_PENDING: self->timer = g_timer_new (); self->finally = dex_future_finally ( dex_ref (future), (DexFutureCallback) future_finally, g_object_ref (self), g_object_unref); break; case DEX_FUTURE_STATUS_RESOLVED: self->object = g_value_dup_object (dex_future_get_value (future, NULL)); self->non_error_msg = g_strdup ("Object was already successfully resolved"); break; case DEX_FUTURE_STATUS_REJECTED: { g_autoptr (GError) local_error = NULL; dex_future_get_value (future, &local_error); self->error = g_error_copy (local_error); } break; default: g_assert_not_reached (); } return self; } gboolean bz_result_get_pending (BzResult *self) { g_return_val_if_fail (BZ_IS_RESULT (self), FALSE); return self->finally != NULL; } gboolean bz_result_get_resolved (BzResult *self) { g_return_val_if_fail (BZ_IS_RESULT (self), FALSE); return self->object != NULL; } gboolean bz_result_get_rejected (BzResult *self) { g_return_val_if_fail (BZ_IS_RESULT (self), FALSE); return self->error != NULL; } gpointer bz_result_get_object (BzResult *self) { g_return_val_if_fail (BZ_IS_RESULT (self), NULL); return self->object; } const char * bz_result_get_message (BzResult *self) { g_return_val_if_fail (BZ_IS_RESULT (self), NULL); if (self->error != NULL) return self->error->message; else return self->non_error_msg; } DexFuture * bz_result_dup_future (BzResult *self) { g_return_val_if_fail (BZ_IS_RESULT (self), NULL); if (self->finally != NULL) return dex_ref (self->finally); else if (self->object != NULL) return dex_future_new_for_object (self->object); else if (self->error != NULL) return dex_future_new_for_error (g_error_copy (self->error)); else return NULL; } static DexFuture * future_finally (DexFuture *future, BzResult *self) { g_autoptr (GError) local_error = NULL; const GValue *value = NULL; dex_clear (&self->finally); g_timer_stop (self->timer); value = dex_future_get_value (future, &local_error); if (value != NULL) { self->object = g_value_dup_object (value); self->non_error_msg = g_strdup_printf ( "Successfully resolved object in %f seconds", g_timer_elapsed (self->timer, NULL)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_OBJECT]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MESSAGE]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PENDING]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_RESOLVED]); } else { self->error = g_error_copy (local_error); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MESSAGE]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PENDING]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_REJECTED]); } return dex_ref (future); } /* End of bz-result.c */ bazaar-orig-v0.7.14/src/bz-parser.c0000664000175000017500000000266515166123241016011 0ustar hasanhasan/* bz-parser.c * * Copyright 2025 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-parser.h" G_DEFINE_INTERFACE (BzParser, bz_parser, G_TYPE_OBJECT) static GHashTable * bz_parser_real_process_bytes (BzParser *self, GBytes *bytes, GError **error) { return NULL; } static void bz_parser_default_init (BzParserInterface *iface) { iface->process_bytes = bz_parser_real_process_bytes; } GHashTable * bz_parser_process_bytes (BzParser *self, GBytes *bytes, GError **error) { g_return_val_if_fail (BZ_IS_PARSER (self), NULL); g_return_val_if_fail (bytes != NULL, NULL); return BZ_PARSER_GET_IFACE (self)->process_bytes ( self, bytes, error); } bazaar-orig-v0.7.14/src/bz-global-net.h0000664000175000017500000000330415166123241016535 0ustar hasanhasan/* bz-global-net.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include G_BEGIN_DECLS GProxyResolver * bz_get_default_proxy_resolver (void); DexFuture * bz_send_with_global_http_session (SoupMessage *message); DexFuture * bz_send_with_global_http_session_then_splice_into (SoupMessage *message, GOutputStream *output); DexFuture * bz_https_query_json (const char *uri); DexFuture * bz_query_flathub_v2_json (const char *request); DexFuture * bz_query_flathub_v2_json_authenticated (const char *request, const char *token); DexFuture * bz_query_flathub_v2_json_authenticated_post (const char *request, const char *token); DexFuture * bz_query_flathub_v2_json_authenticated_delete (const char *request, const char *token); DexFuture * bz_query_flathub_v2_json_take (char *request); G_END_DECLS bazaar-orig-v0.7.14/src/bz-safety-dialog.c0000664000175000017500000001645215166123241017244 0ustar hasanhasan/* bz-safety-dialog.c * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include "bz-app-permissions.h" #include "bz-context-row.h" #include "bz-entry-group.h" #include "bz-entry.h" #include "bz-lozenge.h" #include "bz-result.h" #include "bz-safety-calculator.h" #include "bz-safety-dialog.h" #include "bz-safety-row.h" #include "bz-template-callbacks.h" #include "bz-window.h" struct _BzSafetyDialog { AdwDialog parent_instance; BzEntryGroup *group; BzLozenge *lozenge; GtkListBox *permissions_list; }; G_DEFINE_FINAL_TYPE (BzSafetyDialog, bz_safety_dialog, ADW_TYPE_DIALOG) enum { PROP_0, PROP_GROUP, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static AdwActionRow *create_permission_row (BzSafetyRow *row_data); static void update_permissions_list (BzSafetyDialog *self); static void bz_safety_dialog_dispose (GObject *object) { BzSafetyDialog *self; self = BZ_SAFETY_DIALOG (object); g_clear_object (&self->group); G_OBJECT_CLASS (bz_safety_dialog_parent_class)->dispose (object); } static void bz_safety_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzSafetyDialog *self; self = BZ_SAFETY_DIALOG (object); switch (prop_id) { case PROP_GROUP: g_value_set_object (value, self->group); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_safety_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzSafetyDialog *self; self = BZ_SAFETY_DIALOG (object); switch (prop_id) { case PROP_GROUP: g_clear_object (&self->group); self->group = g_value_dup_object (value); update_permissions_list (self); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_safety_dialog_class_init (BzSafetyDialogClass *klass) { GObjectClass *object_class; GtkWidgetClass *widget_class; object_class = G_OBJECT_CLASS (klass); widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_safety_dialog_dispose; object_class->get_property = bz_safety_dialog_get_property; object_class->set_property = bz_safety_dialog_set_property; props[PROP_GROUP] = g_param_spec_object ("group", NULL, NULL, BZ_TYPE_ENTRY_GROUP, G_PARAM_READWRITE); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_LOZENGE); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-safety-dialog.ui"); bz_widget_class_bind_all_util_callbacks (widget_class); gtk_widget_class_bind_template_child (widget_class, BzSafetyDialog, lozenge); gtk_widget_class_bind_template_child (widget_class, BzSafetyDialog, permissions_list); } static void bz_safety_dialog_init (BzSafetyDialog *self) { gtk_widget_init_template (GTK_WIDGET (self)); } AdwDialog * bz_safety_dialog_new (BzEntryGroup *group) { return g_object_new (BZ_TYPE_SAFETY_DIALOG, "group", group, NULL); } static AdwActionRow * create_permission_row (BzSafetyRow *row_data) { return bz_context_row_new (bz_safety_row_get_icon_name (row_data), bz_safety_row_get_importance (row_data), bz_safety_row_get_title (row_data), bz_safety_row_get_subtitle (row_data)); } static void update_permissions_list (BzSafetyDialog *self) { const char *icon_names[2]; const char *app_name = NULL; g_autofree char *title_text = NULL; BzImportance importance = BZ_IMPORTANCE_UNIMPORTANT; BzEntry *entry = NULL; BzResult *result = NULL; GtkWidget *child; g_autoptr (GListModel) model = NULL; guint n_items = 0; while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->permissions_list))) != NULL) gtk_list_box_remove (self->permissions_list, child); if (self->group == NULL) return; g_object_get (self->group, "ui-entry", &result, NULL); if (result == NULL) return; entry = bz_result_get_object (result); if (entry == NULL) { g_clear_object (&result); return; } app_name = bz_entry_get_title (entry); model = bz_safety_calculator_analyze_entry (entry); importance = bz_safety_calculator_calculate_rating (entry); n_items = g_list_model_get_n_items (model); for (gint level = BZ_IMPORTANCE_IMPORTANT; level >= BZ_IMPORTANCE_UNIMPORTANT; level--) { for (gint j = 0; j < n_items; j++) { g_autoptr (BzSafetyRow) row_data = NULL; AdwActionRow *row = NULL; BzImportance row_importance = 0; row_data = g_list_model_get_item (model, j); row_importance = bz_safety_row_get_importance (row_data); if (row_importance != level) continue; row = create_permission_row (row_data); gtk_list_box_append (self->permissions_list, GTK_WIDGET (row)); } } switch (importance) { case BZ_IMPORTANCE_UNIMPORTANT: icon_names[0] = "app-safety-ok-symbolic"; icon_names[1] = NULL; title_text = g_strdup_printf (_ ("%s is Safe"), app_name); break; case BZ_IMPORTANCE_NEUTRAL: icon_names[0] = "app-safety-ok-symbolic"; icon_names[1] = NULL; title_text = g_strdup_printf (_ ("%s has no Unsafe Permissions"), app_name); break; case BZ_IMPORTANCE_INFORMATION: icon_names[0] = "app-safety-ok-symbolic"; icon_names[1] = NULL; title_text = g_strdup_printf (_ ("%s is Probably Safe"), app_name); break; case BZ_IMPORTANCE_WARNING: icon_names[0] = "app-safety-unknown-symbolic"; icon_names[1] = NULL; title_text = g_strdup_printf (_ ("%s is Possibly Unsafe"), app_name); break; case BZ_IMPORTANCE_IMPORTANT: icon_names[0] = "app-safety-unsafe-symbolic"; icon_names[1] = NULL; title_text = g_strdup_printf (_ ("%s is Unsafe"), app_name); break; default: g_assert_not_reached (); } bz_lozenge_set_icon_names (self->lozenge, icon_names); bz_lozenge_set_title (self->lozenge, title_text); bz_lozenge_set_importance (self->lozenge, importance); g_clear_object (&result); } bazaar-orig-v0.7.14/src/bz-malcontent-service.h0000664000175000017500000000233015166123241020311 0ustar hasanhasan/* bz-malcontent-service.h * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-state-info.h" #include #include G_BEGIN_DECLS #define BZ_TYPE_MALCONTENT_SERVICE bz_malcontent_service_get_type () G_DECLARE_FINAL_TYPE (BzMalcontentService, bz_malcontent_service, BZ, MALCONTENT_SERVICE, GObject) BzMalcontentService * bz_malcontent_service_new (GDBusConnection *bus, BzStateInfo *state); void bz_malcontent_service_start (BzMalcontentService *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-list-tile.h0000664000175000017500000000233615166123241016423 0ustar hasanhasan/* bz-list-tile.h * * Copyright 2025 Hari Rana * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_LIST_TILE (bz_list_tile_get_type()) G_DECLARE_DERIVABLE_TYPE (BzListTile, bz_list_tile, BZ, LIST_TILE, GtkWidget) struct _BzListTileClass { GtkWidgetClass parent_class; }; BzListTile *bz_list_tile_new (void); GtkWidget *bz_list_tile_get_child (BzListTile *self); void bz_list_tile_set_child (BzListTile *self, GtkWidget *child); G_END_DECLSbazaar-orig-v0.7.14/src/bz-blocklist-condition-match-envvar.txt0000664000175000017500000000026315166123241023445 0ustar hasanhasanprefix=bz name=blocklist_condition_match_envvar parent-prefix=g parent-name=object author=AUTOGEN property=var char G_TYPE_STRING string property=regex char G_TYPE_STRING string bazaar-orig-v0.7.14/src/bz-safety-calculator.h0000664000175000017500000000263515166123241020141 0ustar hasanhasan/* bz-safety-calculator.h * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-context-row.h" #include "bz-entry.h" #include "bz-safety-row.h" #include G_BEGIN_DECLS typedef enum { BZ_HIGH_RISK_GROUP_NONE = 0, BZ_HIGH_RISK_GROUP_X11 = 1 << 0, BZ_HIGH_RISK_GROUP_DISK = 1 << 1, } BzHighRiskGroup; #define BZ_TYPE_HIGH_RISK_GROUP (bz_high_risk_group_get_type ()) GListModel * bz_safety_calculator_analyze_entry (BzEntry *entry); BzImportance bz_safety_calculator_calculate_rating (BzEntry *entry); char * bz_safety_calculator_get_top_icon (BzEntry *entry, int index); BzHighRiskGroup bz_safety_calculator_get_high_risk_groups (BzEntry *entry); G_END_DECLS bazaar-orig-v0.7.14/src/bz-transaction-tile.c0000664000175000017500000003074515166123241017775 0ustar hasanhasan/* bz-transaction-tile.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-application.h" #include "bz-entry-group.h" #include "bz-entry.h" #include "bz-error-dialog.h" #include "bz-error.h" #include "bz-flatpak-entry.h" #include "bz-list-tile.h" #include "bz-state-info.h" #include "bz-template-callbacks.h" #include "bz-transaction-tile.h" #include "bz-window.h" struct _BzTransactionTile { BzListTile parent_instance; BzTransactionEntryTracker *tracker; }; G_DEFINE_FINAL_TYPE (BzTransactionTile, bz_transaction_tile, BZ_TYPE_LIST_TILE); enum { PROP_0, PROP_TRACKER, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bz_transaction_tile_dispose (GObject *object) { BzTransactionTile *self = BZ_TRANSACTION_TILE (object); g_clear_pointer (&self->tracker, g_object_unref); G_OBJECT_CLASS (bz_transaction_tile_parent_class)->dispose (object); } static void bz_transaction_tile_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzTransactionTile *self = BZ_TRANSACTION_TILE (object); switch (prop_id) { case PROP_TRACKER: g_value_set_object (value, bz_transaction_tile_get_tracker (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_transaction_tile_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzTransactionTile *self = BZ_TRANSACTION_TILE (object); switch (prop_id) { case PROP_TRACKER: bz_transaction_tile_set_tracker (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static char * format_removal_size (gpointer object, guint64 value) { g_autofree char *size = NULL; size = g_format_size (value); return g_strdup_printf (_ ("%s Freed"), size); } static char * format_download_progress (gpointer object, guint64 bytes_transferred, guint64 total_size) { g_autofree char *downloaded_str = NULL; g_autofree char *total_str = NULL; downloaded_str = g_format_size (bytes_transferred); if (total_size == (guint64) -1) return g_strdup_printf ("%s", downloaded_str); else { total_str = g_format_size (total_size); return g_strdup_printf ("%s / %s", downloaded_str, total_str); } } static gboolean is_transaction_type (gpointer object, BzTransactionEntryTracker *tracker, int type) { if (tracker == NULL) return FALSE; return bz_transaction_entry_tracker_get_kind (tracker) == type; } static gboolean is_transaction_tracker_install (gpointer object, BzTransactionEntryTracker *tracker) { return is_transaction_type (object, tracker, BZ_TRANSACTION_ENTRY_KIND_INSTALL); } static gboolean is_transaction_tracker_update (gpointer object, BzTransactionEntryTracker *tracker) { return is_transaction_type (object, tracker, BZ_TRANSACTION_ENTRY_KIND_UPDATE); } static gboolean is_transaction_tracker_removal (gpointer object, BzTransactionEntryTracker *tracker) { return is_transaction_type (object, tracker, BZ_TRANSACTION_ENTRY_KIND_REMOVAL); } static gboolean is_transaction_tracker_errored (gpointer object, GListModel *finished_ops) { guint n_items = 0; if (finished_ops == NULL) return FALSE; n_items = g_list_model_get_n_items (finished_ops); for (guint i = 0; i < n_items; i++) { g_autoptr (BzTransactionTask) task = NULL; task = g_list_model_get_item (finished_ops, i); if (bz_transaction_task_get_error (task) != NULL) return TRUE; } return FALSE; } static gboolean list_has_items (gpointer object, GListModel *model) { if (model == NULL) return FALSE; return g_list_model_get_n_items (model) > 0; } static gboolean is_queued (gpointer object, BzTransactionEntryStatus status) { return status == BZ_TRANSACTION_ENTRY_STATUS_QUEUED; } static gboolean is_ongoing (gpointer object, BzTransactionEntryStatus status) { return status == BZ_TRANSACTION_ENTRY_STATUS_ONGOING; } static gboolean is_completed (gpointer object, BzTransactionEntryStatus status) { return status == BZ_TRANSACTION_ENTRY_STATUS_DONE; } static gboolean is_both (gpointer object, gboolean first, gboolean second) { return first && second; } static GdkPaintable * get_main_icon (gpointer object, BzTransactionEntryTracker *tracker) { BzEntry *entry = NULL; GdkPaintable *icon_paintable = NULL; if (tracker == NULL) goto return_generic; entry = bz_transaction_entry_tracker_get_entry (tracker); if (entry == NULL) goto return_generic; icon_paintable = bz_entry_get_icon_paintable (entry); if (icon_paintable != NULL) return g_object_ref (icon_paintable); return_generic: return (GdkPaintable *) gtk_icon_theme_lookup_icon ( gtk_icon_theme_get_for_display (gdk_display_get_default ()), "application-x-executable", NULL, 64, 1, gtk_widget_get_default_direction (), GTK_ICON_LOOKUP_NONE); } static gboolean is_entry_kind (gpointer object, BzTransactionEntryTracker *tracker, int kind) { BzEntry *entry = NULL; if (tracker == NULL) return FALSE; entry = bz_transaction_entry_tracker_get_entry (tracker); if (entry == NULL) return FALSE; return bz_entry_is_of_kinds (entry, kind); } static gboolean is_entry_application (gpointer object, BzTransactionEntryTracker *tracker) { return is_entry_kind (object, tracker, BZ_ENTRY_KIND_APPLICATION); } static gboolean is_entry_runtime (gpointer object, BzTransactionEntryTracker *tracker) { return is_entry_kind (object, tracker, BZ_ENTRY_KIND_RUNTIME); } static gboolean is_entry_addon (gpointer object, BzTransactionEntryTracker *tracker) { return is_entry_kind (object, tracker, BZ_ENTRY_KIND_ADDON); } static void run_cb (BzTransactionTile *self, GtkButton *button) { BzTransactionEntryTracker *tracker = NULL; BzEntry *entry = NULL; tracker = bz_transaction_tile_get_tracker (self); if (tracker == NULL) return; entry = bz_transaction_entry_tracker_get_entry (tracker); if (entry == NULL) return; gtk_widget_activate_action (GTK_WIDGET (self), "window.launch-group", "s", bz_entry_get_id (entry)); } static void cancel_cb (BzTransactionTile *self, GtkButton *button) { gboolean result = FALSE; BzTransactionEntryTracker *tracker = NULL; BzEntry *entry = NULL; BzStateInfo *state = NULL; BzBackend *backend = NULL; tracker = bz_transaction_tile_get_tracker (self); if (tracker == NULL) return; entry = bz_transaction_entry_tracker_get_entry (tracker); if (entry == NULL || !BZ_IS_FLATPAK_ENTRY (entry)) return; state = bz_state_info_get_default (); backend = bz_state_info_get_backend (state); if (backend == NULL) return; result = bz_backend_cancel_task_for_entry (backend, entry); if (result) gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE); } static void error_clicked_cb (GtkListItem *item, GtkButton *button, BzTransactionTile *self) { BzTransactionTask *task = NULL; const char *error = NULL; const char *name = NULL; BzErrorDialog *dialog = NULL; task = gtk_list_item_get_item (item); if (task == NULL) return; error = bz_transaction_task_get_error (task); if (error == NULL) return; name = bz_backend_transaction_op_payload_get_name ( bz_transaction_task_get_op (task)); if (name != NULL) { g_autofree char *body = NULL; body = g_strdup_printf ("%s: %s", name, error); dialog = bz_error_dialog_new (_ ("Transaction Error"), body); } else dialog = bz_error_dialog_new (_ ("Transaction Error"), error); adw_dialog_present (ADW_DIALOG (dialog), GTK_WIDGET (self)); } static void bz_transaction_tile_class_init (BzTransactionTileClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bz_transaction_tile_set_property; object_class->get_property = bz_transaction_tile_get_property; object_class->dispose = bz_transaction_tile_dispose; props[PROP_TRACKER] = g_param_spec_object ( "tracker", NULL, NULL, BZ_TYPE_TRANSACTION_ENTRY_TRACKER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_LIST_TILE); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-transaction-tile.ui"); bz_widget_class_bind_all_util_callbacks (widget_class); gtk_widget_class_bind_template_callback (widget_class, format_removal_size); gtk_widget_class_bind_template_callback (widget_class, format_download_progress); gtk_widget_class_bind_template_callback (widget_class, get_main_icon); gtk_widget_class_bind_template_callback (widget_class, is_entry_application); gtk_widget_class_bind_template_callback (widget_class, is_entry_runtime); gtk_widget_class_bind_template_callback (widget_class, is_entry_addon); gtk_widget_class_bind_template_callback (widget_class, is_transaction_tracker_install); gtk_widget_class_bind_template_callback (widget_class, is_transaction_tracker_update); gtk_widget_class_bind_template_callback (widget_class, is_transaction_tracker_removal); gtk_widget_class_bind_template_callback (widget_class, is_transaction_tracker_errored); gtk_widget_class_bind_template_callback (widget_class, list_has_items); gtk_widget_class_bind_template_callback (widget_class, is_queued); gtk_widget_class_bind_template_callback (widget_class, is_ongoing); gtk_widget_class_bind_template_callback (widget_class, is_completed); gtk_widget_class_bind_template_callback (widget_class, is_both); gtk_widget_class_bind_template_callback (widget_class, run_cb); gtk_widget_class_bind_template_callback (widget_class, cancel_cb); gtk_widget_class_bind_template_callback (widget_class, error_clicked_cb); gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_BUTTON); } static void bz_transaction_tile_init (BzTransactionTile *self) { gtk_widget_init_template (GTK_WIDGET (self)); } BzTransactionTile * bz_transaction_tile_new (void) { return g_object_new (BZ_TYPE_TRANSACTION_TILE, NULL); } BzTransactionEntryTracker * bz_transaction_tile_get_tracker (BzTransactionTile *self) { g_return_val_if_fail (BZ_IS_TRANSACTION_TILE (self), NULL); return self->tracker; } void bz_transaction_tile_set_tracker (BzTransactionTile *self, BzTransactionEntryTracker *tracker) { g_return_if_fail (BZ_IS_TRANSACTION_TILE (self)); g_clear_pointer (&self->tracker, g_object_unref); if (tracker != NULL) self->tracker = g_object_ref (tracker); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TRACKER]); } /* End of bz-transaction-tile.c */ bazaar-orig-v0.7.14/src/meson.build0000664000175000017500000002245415166123241016100 0ustar hasanhasanmath = cc.find_library('m', required: false) xmllint = find_program('xmllint', required: true) gtk_dep = dependency('gtk4', version: '>= 4.22.1') libadwaita_dep = dependency('libadwaita-1', version: '>= 1.8') libdex_dep = dependency('libdex-1', version: '>= 1.0.0') flatpak_dep = dependency('flatpak', version: '>= 1.9') appstream_dep = dependency('appstream', version: '>= 1.0') xmlb_dep = dependency('xmlb', version: '>= 0.3.4') yaml_dep = dependency('yaml-0.1', version: '>= 0.2.5') libsoup_dep = dependency('libsoup-3.0', version: '>= 3.6.0') json_glib_dep = dependency('json-glib-1.0', version: '>= 1.10.0') glycin_dep = dependency('glycin-2', version: '>= 2.0') glycin_gtk4_dep = dependency('glycin-gtk4-2', version: '>= 2.0') webkit_dep = dependency('webkitgtk-6.0', version: '>= 2.50.2') libsecret_dep = dependency('libsecret-1', version: '>= 0.20') libproxy_dep = dependency('libproxy-1.0', version: '>= 0.5') malcontent_dep = dependency('malcontent-0', version: '>= 0.12.0') dl_worker_sources = [ 'bz-env.c', 'bz-global-net.c', 'dl-worker.c', ] dl_worker_deps = [ math, libdex_dep, libsoup_dep, json_glib_dep, libproxy_dep, ] dl_worker_exe = executable(dl_worker_bin_name, dl_worker_sources, dependencies: dl_worker_deps, install: true, ) marshalers = gnome.genmarshal('bz-marshalers', sources: 'bz-marshalers.list', prefix: 'bz_marshal', valist_marshallers: true, ) gdbus_src = gnome.gdbus_codegen( 'gs-shell-search-provider-generated', 'shell-search-provider-dbus-interfaces.xml', interface_prefix : 'org.gnome.', namespace : 'Bz', ) bz_sources = files( 'bz-addon-tile.c', 'bz-addons-dialog.c', 'bz-age-rating-dialog.c', 'bz-all-apps-page.c', 'bz-app-permissions.c', 'bz-app-size-dialog.c', 'bz-app-tile.c', 'bz-application-map-factory.c', 'bz-application.c', 'bz-apps-page.c', 'bz-appstream-description-render.c', 'bz-appstream-parser.c', 'bz-async-texture.c', 'bz-auth-state.c', 'bz-backend.c', 'bz-category-flags.c', 'bz-category-tile.c', 'bz-comet-overlay.c', 'bz-content-provider.c', 'bz-context-row.c', 'bz-context-tile.c', 'bz-context-tile-callbacks.c', 'bz-curated-app-tile.c', 'bz-curated-view.c', 'bz-data-graph.c', 'bz-decorated-screenshot.c', 'bz-developer-badge.c', 'bz-donations-dialog.c', 'bz-download-worker.c', 'bz-dynamic-list-view.c', 'bz-entry-cache-manager.c', 'bz-entry-group-util.c', 'bz-entry-group.c', 'bz-entry-inspector.c', 'bz-entry-selection-row.c', 'bz-entry.c', 'bz-env.c', 'bz-error-dialog.c', 'bz-error.c', 'bz-fading-clamp.c', 'bz-favorite-button.c', 'bz-favorites-page.c', 'bz-favorites-tile.c', 'bz-featured-carousel.c', 'bz-featured-tile.c', 'bz-flathub-category-section.c', 'bz-flathub-category.c', 'bz-flathub-category.c', 'bz-flathub-page.c', 'bz-flathub-state.c', 'bz-flatpak-entry.c', 'bz-flatpak-instance.c', 'bz-full-view.c', 'bz-global-net.c', 'bz-global-progress.c', 'bz-gnome-shell-search-provider.c', 'bz-group-tile-css-watcher.c', 'bz-hardware-support-dialog.c', 'bz-hooks.c', 'bz-inhibited-scrollable.c', 'bz-inspector.c', 'bz-install-controls.c', 'bz-installed-tile.c', 'bz-io.c', 'bz-library-page.c', 'bz-license-dialog.c', 'bz-list-tile.c', 'bz-login-page.c', 'bz-lozenge.c', 'bz-malcontent-service.c', 'bz-newline-parser.c', 'bz-parser.c', 'bz-preferences-dialog.c', 'bz-progress-bar.c', 'bz-releases-list.c', 'bz-result.c', 'bz-rich-app-tile.c', 'bz-rounded-picture.c', 'bz-row-view.c', 'bz-safety-calculator.c', 'bz-safety-dialog.c', 'bz-screenshot-page.c', 'bz-screenshot.c', 'bz-screenshots-carousel.c', 'bz-search-engine.c', 'bz-search-filter-popover.c', 'bz-search-pill-list.c', 'bz-search-page.c', 'bz-section-view.c', 'bz-serializable.c', 'bz-share-list.c', 'bz-spdx.c', 'bz-stats-dialog.c', 'bz-subcategory-list.c', 'bz-tag-list.c', 'bz-template-callbacks.c', 'bz-themed-entry-group-rect.c', 'bz-transaction-dialog.c', 'bz-transaction-list-dialog.c', 'bz-transaction-manager.c', 'bz-transaction-tile.c', 'bz-transaction.c', 'bz-updates-card.c', 'bz-user-data-page.c', 'bz-user-data-tile.c', 'bz-window.c', 'bz-world-map-parser.c', 'bz-world-map.c', 'bz-yaml-parser.c', 'bz-zoom.c', 'main.c', ) subdir('progress-bar-designs') bz_deps = [ # Bazaar GTK Extensions; see ../bge/ bge_dep, math, gtk_dep, libadwaita_dep, flatpak_dep, appstream_dep, xmlb_dep, yaml_dep, libsoup_dep, json_glib_dep, libdex_dep, glycin_dep, glycin_gtk4_dep, webkit_dep, libsecret_dep, libproxy_dep, malcontent_dep, ] gen_gobject = find_program('./gen_gobject.sh') gen_gobject_header = generator( gen_gobject, output: '@BASENAME@.h', arguments: ['--header', '@INPUT@', '@OUTPUT@'], ) gen_gobject_code = generator( gen_gobject, output: '@BASENAME@.c', arguments: ['--code', '@INPUT@', '@OUTPUT@'], ) gobject_specs = files( 'bz-age-rating-attribute.txt', 'bz-backend-notification.txt', 'bz-backend-transaction-op-payload.txt', 'bz-backend-transaction-op-progress-payload.txt', 'bz-blocklist-condition-match-envvar.txt', 'bz-blocklist-condition-match-locale.txt', 'bz-blocklist-condition.txt', 'bz-blocklist.txt', 'bz-bulk-install-dialog-result.txt', 'bz-comet.txt', 'bz-country-data-point.txt', 'bz-country.txt', 'bz-curated-category-info.txt', 'bz-curated-image-info.txt', 'bz-curated-markdown-info.txt', 'bz-curated-row.txt', 'bz-curated-section.txt', 'bz-data-point.txt', 'bz-exponential-function.txt', 'bz-finished-search-query.txt', 'bz-flathub-auth-provider.txt', 'bz-flathub-sub-category.txt', 'bz-hash-table-object.txt', 'bz-hook-dialog-option.txt', 'bz-hook-dialog.txt', 'bz-hook.txt', 'bz-internal-config.txt', 'bz-linear-function.txt', 'bz-main-config.txt', 'bz-pride-flag-config.txt', 'bz-pride-flag-spec.txt', 'bz-pride-flag-stripe-spec.txt', 'bz-release.txt', 'bz-repository.txt', 'bz-root-blocklist.txt', 'bz-root-curated-config.txt', 'bz-safety-row.txt', 'bz-search-bias.txt', 'bz-search-result.txt', 'bz-state-info.txt', 'bz-transaction-dialog-result.txt', 'bz-transaction-entry-tracker.txt', 'bz-transaction-task.txt', 'bz-url.txt', 'bz-verification-status.txt', ) gen_gobject_srcs = [] foreach f : gobject_specs header = gen_gobject_header.process(f) code = gen_gobject_code.process(f) gen_gobject_srcs += [header, code] endforeach generated_gobjects = declare_dependency( sources: gen_gobject_srcs, ) bz_deps += [ generated_gobjects ] blueprints = custom_target('blueprints', input: files( 'bz-addon-tile.blp', 'bz-addons-dialog.blp', 'bz-donations-dialog.blp', 'bz-age-rating-dialog.blp', 'bz-all-apps-page.blp', 'bz-app-size-dialog.blp', 'bz-app-tile.blp', 'bz-apps-page.blp', 'bz-appstream-description-render.blp', 'bz-category-tile.blp', 'bz-context-tile.blp', 'bz-curated-app-tile.blp', 'bz-curated-view.blp', 'bz-decorated-screenshot.blp', 'bz-developer-badge.blp', 'bz-entry-inspector.blp', 'bz-entry-selection-row.blp', 'bz-error-dialog.blp', 'bz-favorite-button.blp', 'bz-favorites-page.blp', 'bz-favorites-tile.blp', 'bz-featured-carousel.blp', 'bz-featured-tile.blp', 'bz-flathub-category-section.blp', 'bz-flathub-page.blp', 'bz-full-view.blp', 'bz-hardware-support-dialog.blp', 'bz-inspector.blp', 'bz-install-controls.blp', 'bz-installed-tile.blp', 'bz-library-page.blp', 'bz-license-dialog.blp', 'bz-login-page.blp', 'bz-preferences-dialog.blp', 'bz-progress-bar.blp', 'bz-releases-dialog.blp', 'bz-releases-list.blp', 'bz-rich-app-tile.blp', 'bz-row-view.blp', 'bz-safety-dialog.blp', 'bz-screenshot-page.blp', 'bz-screenshots-carousel.blp', 'bz-search-page.blp', 'bz-search-filter-popover.blp', 'bz-section-view.blp', 'bz-stats-dialog.blp', 'bz-transaction-list-dialog.blp', 'bz-transaction-tile.blp', 'bz-updates-card.blp', 'bz-user-data-page.blp', 'bz-user-data-tile.blp', 'bz-window.blp', 'shortcuts-dialog.blp', ), output: '.', command: [ find_program('blueprint-compiler', version: '>= 0.20.0'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@' ], ) release_notes = custom_target('release-notes.xml', output: 'release-notes.xml', input: meson.project_source_root() / 'data' / 'io.github.kolunmi.Bazaar.metainfo.xml.in', command: [ 'sh', '-c', xmllint.full_path() + ' --xpath "//releases/release[1]" "$1" > "$2"', '--', '@INPUT@', '@OUTPUT@', ], ) countries_gvariant = custom_target( 'countries-gvariant', input: files('../scripts/countries.json.in'), output: 'countries.gvariant', command: [ python3, meson.project_source_root() / 'scripts' / 'countries.py', '@INPUT@', meson.project_source_root() / 'po' / 'LINGUAS', '@OUTPUT@', ], ) bz_sources += gnome.compile_resources('bz-resources', 'bazaar.gresource.xml', c_name: 'bz', source_dir: meson.current_build_dir(), dependencies: [blueprints, release_notes, countries_gvariant], ) executable('bazaar', bz_sources, gdbus_src, marshalers, dependencies: bz_deps, install: true, ) bazaar-orig-v0.7.14/src/bz-search-engine.h0000664000175000017500000000277415166123241017233 0ustar hasanhasan/* bz-search-engine.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include G_BEGIN_DECLS #define BZ_TYPE_SEARCH_ENGINE (bz_search_engine_get_type ()) G_DECLARE_FINAL_TYPE (BzSearchEngine, bz_search_engine, BZ, SEARCH_ENGINE, GObject) BzSearchEngine * bz_search_engine_new (void); GListModel * bz_search_engine_get_model (BzSearchEngine *self); void bz_search_engine_set_model (BzSearchEngine *self, GListModel *model); GListModel * bz_search_engine_get_biases (BzSearchEngine *self); void bz_search_engine_set_biases (BzSearchEngine *self, GListModel *biases); DexFuture * bz_search_engine_query (BzSearchEngine *self, const char *const *terms); G_END_DECLS /* End of bz-search-engine.h */ bazaar-orig-v0.7.14/src/bz-verification-status.txt0000664000175000017500000000065115166123241021106 0ustar hasanhasanprefix=bz name=verification_status parent-prefix=g parent-name=object author=AUTOGEN property=verified gboolean G_TYPE_BOOLEAN boolean property=method char G_TYPE_STRING string property=website char G_TYPE_STRING string property=login_name char G_TYPE_STRING string property=login_provider char G_TYPE_STRING string property=timestamp char G_TYPE_STRING string property=login_is_organization gboolean G_TYPE_BOOLEAN boolean bazaar-orig-v0.7.14/src/bz-entry-inspector.h0000664000175000017500000000240015166123241017652 0ustar hasanhasan/* bz-entry-inspector.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-result.h" G_BEGIN_DECLS #define BZ_TYPE_ENTRY_INSPECTOR (bz_entry_inspector_get_type ()) G_DECLARE_FINAL_TYPE (BzEntryInspector, bz_entry_inspector, BZ, ENTRY_INSPECTOR, AdwWindow) BzEntryInspector * bz_entry_inspector_new (void); BzResult * bz_entry_inspector_get_result (BzEntryInspector *self); void bz_entry_inspector_set_result (BzEntryInspector *self, BzResult *result); G_END_DECLS /* End of bz-entry-inspector.h */ bazaar-orig-v0.7.14/src/bz-transaction-entry-tracker.txt0000664000175000017500000000105115166123241022213 0ustar hasanhasanprefix=bz name=transaction_entry_tracker parent-prefix=g parent-name=object author=AUTOGEN enum=bz transaction_entry_kind install update removal enum=bz transaction_entry_status queued ongoing done include= include="bz-entry.h" property=entry BzEntry BZ_TYPE_ENTRY object property=current_ops GListModel G_TYPE_LIST_MODEL object property=finished_ops GListModel G_TYPE_LIST_MODEL object property=kind BzTransactionEntryKind BZ_TYPE_TRANSACTION_ENTRY_KIND enum property=status BzTransactionEntryStatus BZ_TYPE_TRANSACTION_ENTRY_STATUS enum bazaar-orig-v0.7.14/src/bz-flathub-category-section.h0000664000175000017500000000352415166123241021417 0ustar hasanhasan/* bz-flathub-category-section.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-flathub-category.h" #include G_BEGIN_DECLS #define BZ_TYPE_FLATHUB_CATEGORY_SECTION (bz_flathub_category_section_get_type ()) G_DECLARE_FINAL_TYPE (BzFlathubCategorySection, bz_flathub_category_section, BZ, FLATHUB_CATEGORY_SECTION, GtkBox) GtkWidget *bz_flathub_category_section_new (void); void bz_flathub_category_section_set_category (BzFlathubCategorySection *self, BzFlathubCategory *category); BzFlathubCategory *bz_flathub_category_section_get_category (BzFlathubCategorySection *self); void bz_flathub_category_section_set_compact (BzFlathubCategorySection *self, gboolean compact); gboolean bz_flathub_category_section_get_compact (BzFlathubCategorySection *self); void bz_flathub_category_section_set_min_items (BzFlathubCategorySection *self, guint min_items); guint bz_flathub_category_section_get_min_items (BzFlathubCategorySection *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-app-tile.h0000664000175000017500000000252115166123241016224 0ustar hasanhasan/* bz-app-tile.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-entry-group.h" G_BEGIN_DECLS #define BZ_TYPE_APP_TILE (bz_app_tile_get_type ()) G_DECLARE_FINAL_TYPE (BzAppTile, bz_app_tile, BZ, APP_TILE, GtkButton) GtkWidget * bz_app_tile_new (void); BzEntryGroup * bz_app_tile_get_group (BzAppTile *self); void bz_app_tile_set_group (BzAppTile *self, BzEntryGroup *group); gint bz_app_tile_get_preferred_width (BzAppTile *self); void bz_app_tile_set_preferred_width (BzAppTile *self, gint preferred_width); G_END_DECLS /* End of bz-app-tile.h */ bazaar-orig-v0.7.14/src/bz-application-map-factory.h0000664000175000017500000000331015166123241021231 0ustar hasanhasan/* bz-application-map-factory.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_APPLICATION_MAP_FACTORY (bz_application_map_factory_get_type ()) G_DECLARE_FINAL_TYPE (BzApplicationMapFactory, bz_application_map_factory, BZ, APPLICATION_MAP_FACTORY, GObject) BzApplicationMapFactory * bz_application_map_factory_new (GtkMapListModelMapFunc func, gpointer user_data, GDestroyNotify ref_user_data, GDestroyNotify unref_user_data, GtkFilter *filter); GListModel * bz_application_map_factory_generate (BzApplicationMapFactory *self, GListModel *model); gpointer bz_application_map_factory_convert_one (BzApplicationMapFactory *self, gpointer item); G_END_DECLS /* End of bz-application-map-factory.h */ bazaar-orig-v0.7.14/src/curated-config-schema.xml0000664000175000017500000000073215166123241020603 0ustar hasanhasan bazaar-orig-v0.7.14/src/bz-screenshot.c0000664000175000017500000003747415166123241016700 0ustar hasanhasan/* bz-screenshot.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-screenshot.h" #include "bz-async-texture.h" #define TOP_HALF_FIXED_WIDTH 650 #define TOP_HALF_FIXED_HEIGHT 265 struct _BzScreenshot { GtkWidget parent_instance; GdkPaintable *paintable; double focus_x; double focus_y; gboolean rounded_corners; gboolean top_half; GskScalingFilter filter; }; G_DEFINE_FINAL_TYPE (BzScreenshot, bz_screenshot, GTK_TYPE_WIDGET) enum { PROP_0, PROP_PAINTABLE, PROP_FOCUS_X, PROP_FOCUS_Y, PROP_ROUNDED_CORNERS, PROP_TOP_HALF, PROP_FILTER, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void invalidate_contents (BzScreenshot *self, GdkPaintable *paintable); static void invalidate_size (BzScreenshot *self, GdkPaintable *paintable); static void async_loaded (BzScreenshot *self, GParamSpec *pspec, BzAsyncTexture *texture); static void bz_screenshot_dispose (GObject *object) { BzScreenshot *self = BZ_SCREENSHOT (object); if (self->paintable != NULL) { g_signal_handlers_disconnect_by_func (self->paintable, invalidate_contents, self); g_signal_handlers_disconnect_by_func (self->paintable, invalidate_size, self); g_signal_handlers_disconnect_by_func (self->paintable, async_loaded, self); } g_clear_object (&self->paintable); G_OBJECT_CLASS (bz_screenshot_parent_class)->dispose (object); } static void bz_screenshot_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzScreenshot *self = BZ_SCREENSHOT (object); switch (prop_id) { case PROP_PAINTABLE: g_value_set_object (value, bz_screenshot_get_paintable (self)); break; case PROP_FOCUS_X: g_value_set_double (value, bz_screenshot_get_focus_x (self)); break; case PROP_FOCUS_Y: g_value_set_double (value, bz_screenshot_get_focus_y (self)); break; case PROP_ROUNDED_CORNERS: g_value_set_boolean (value, bz_screenshot_get_rounded_corners (self)); break; case PROP_TOP_HALF: g_value_set_boolean (value, bz_screenshot_get_top_half (self)); break; case PROP_FILTER: g_value_set_enum (value, bz_screenshot_get_filter (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_screenshot_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzScreenshot *self = BZ_SCREENSHOT (object); switch (prop_id) { case PROP_PAINTABLE: bz_screenshot_set_paintable (self, g_value_get_object (value)); break; case PROP_FOCUS_X: bz_screenshot_set_focus_x (self, g_value_get_double (value)); break; case PROP_FOCUS_Y: bz_screenshot_set_focus_y (self, g_value_get_double (value)); break; case PROP_ROUNDED_CORNERS: bz_screenshot_set_rounded_corners (self, g_value_get_boolean (value)); break; case PROP_TOP_HALF: bz_screenshot_set_top_half (self, g_value_get_boolean (value)); break; case PROP_FILTER: bz_screenshot_set_filter (self, g_value_get_enum (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static GtkSizeRequestMode bz_screenshot_get_request_mode (GtkWidget *widget) { BzScreenshot *self = BZ_SCREENSHOT (widget); if (self->top_half) return GTK_SIZE_REQUEST_CONSTANT_SIZE; return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; } static void bz_screenshot_measure (GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline) { BzScreenshot *self = BZ_SCREENSHOT (widget); if (self->paintable == NULL) return; if (self->top_half) { if (orientation == GTK_ORIENTATION_HORIZONTAL) { *minimum = TOP_HALF_FIXED_WIDTH; *natural = TOP_HALF_FIXED_WIDTH; } else { *minimum = TOP_HALF_FIXED_HEIGHT; *natural = TOP_HALF_FIXED_HEIGHT; } } else { if (orientation == GTK_ORIENTATION_VERTICAL) { int intrinsic_height; double intrinsic_aspect_ratio; intrinsic_height = gdk_paintable_get_intrinsic_height (self->paintable); intrinsic_aspect_ratio = gdk_paintable_get_intrinsic_aspect_ratio (self->paintable); if (for_size >= 0 && intrinsic_aspect_ratio > 0.0) { double result; result = ceil ((double) for_size / intrinsic_aspect_ratio); *minimum = (int) MIN (intrinsic_height, result); *natural = (int) MIN (intrinsic_height, result); } else { *minimum = 0; *natural = intrinsic_height; } } else { *minimum = 0; *natural = gdk_paintable_get_intrinsic_width (self->paintable); } } } static void bz_screenshot_snapshot (GtkWidget *widget, GtkSnapshot *snapshot) { BzScreenshot *self; int widget_width; int widget_height; double paintable_aspect; double scaled_w, scaled_h; double x, y; GskRoundedRect rect; self = BZ_SCREENSHOT (widget); if (self->paintable == NULL) return; widget_width = gtk_widget_get_width (widget); widget_height = gtk_widget_get_height (widget); paintable_aspect = gdk_paintable_get_intrinsic_aspect_ratio (self->paintable); if (self->top_half) { int paintable_width = gdk_paintable_get_intrinsic_width (self->paintable); if (paintable_width > TOP_HALF_FIXED_WIDTH) scaled_w = TOP_HALF_FIXED_WIDTH; else scaled_w = paintable_width > 0 ? paintable_width : TOP_HALF_FIXED_WIDTH; if (paintable_aspect > 0.0) scaled_h = scaled_w / paintable_aspect; else scaled_h = widget_height * 2.0; x = (widget_width - scaled_w) / 2.0; y = 0; } else { if (paintable_aspect > 0.0) { scaled_w = widget_width; scaled_h = scaled_w / paintable_aspect; if (scaled_h > widget_height) { scaled_h = widget_height; scaled_w = scaled_h * paintable_aspect; } } else { scaled_w = widget_width; scaled_h = widget_height; } x = (widget_width - scaled_w) / 2.0; y = (widget_height - scaled_h) / 2.0; } if (self->rounded_corners) { rect.corner[0].width = 10.0; rect.corner[0].height = 10.0; rect.corner[1].width = 10.0; rect.corner[1].height = 10.0; rect.corner[2].width = 10.0; rect.corner[2].height = 10.0; rect.corner[3].width = 10.0; rect.corner[3].height = 10.0; if (self->top_half) { rect.bounds = GRAPHENE_RECT_INIT (x, y, scaled_w, scaled_h); gtk_snapshot_push_rounded_clip (snapshot, &rect); gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (0, 0, widget_width, widget_height)); } else { rect.bounds = GRAPHENE_RECT_INIT (0, 0, widget_width, widget_height); gtk_snapshot_push_rounded_clip (snapshot, &rect); } } gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y)); /* TODO: doesn't handle all cases properly */ if (self->filter == GSK_SCALING_FILTER_NEAREST && BZ_IS_ASYNC_TEXTURE (self->paintable)) { g_autoptr (GdkTexture) texture = NULL; texture = bz_async_texture_dup_texture (BZ_ASYNC_TEXTURE (self->paintable)); if (texture != NULL) gtk_snapshot_append_scaled_texture ( snapshot, texture, self->filter, &GRAPHENE_RECT_INIT (0.0, 0.0, scaled_w, scaled_h)); } else if (self->filter == GSK_SCALING_FILTER_NEAREST && GDK_IS_TEXTURE (self->paintable)) gtk_snapshot_append_scaled_texture ( snapshot, GDK_TEXTURE (self->paintable), self->filter, &GRAPHENE_RECT_INIT (0.0, 0.0, scaled_w, scaled_h)); else gdk_paintable_snapshot (self->paintable, snapshot, scaled_w, scaled_h); if (self->rounded_corners) { gtk_snapshot_pop (snapshot); if (self->top_half) gtk_snapshot_pop (snapshot); } } static void bz_screenshot_class_init (BzScreenshotClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_screenshot_dispose; object_class->get_property = bz_screenshot_get_property; object_class->set_property = bz_screenshot_set_property; props[PROP_PAINTABLE] = g_param_spec_object ( "paintable", NULL, NULL, GDK_TYPE_PAINTABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_FOCUS_X] = g_param_spec_double ( "focus-x", NULL, NULL, -1.0, G_MAXDOUBLE, -1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_FOCUS_Y] = g_param_spec_double ( "focus-y", NULL, NULL, -1.0, G_MAXDOUBLE, -1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_ROUNDED_CORNERS] = g_param_spec_boolean ( "rounded-corners", NULL, NULL, TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_TOP_HALF] = g_param_spec_boolean ( "top-half", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_FILTER] = g_param_spec_enum ( "filter", NULL, NULL, GSK_TYPE_SCALING_FILTER, GSK_SCALING_FILTER_TRILINEAR, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); widget_class->get_request_mode = bz_screenshot_get_request_mode; widget_class->measure = bz_screenshot_measure; widget_class->snapshot = bz_screenshot_snapshot; } static void bz_screenshot_init (BzScreenshot *self) { self->focus_x = -1.0; self->focus_y = -1.0; self->rounded_corners = TRUE; self->top_half = FALSE; self->filter = GSK_SCALING_FILTER_TRILINEAR; } GtkWidget * bz_screenshot_new (void) { return g_object_new (BZ_TYPE_SCREENSHOT, NULL); } void bz_screenshot_set_paintable (BzScreenshot *self, GdkPaintable *paintable) { g_return_if_fail (BZ_IS_SCREENSHOT (self)); g_return_if_fail (paintable == NULL || GDK_IS_PAINTABLE (paintable)); if (self->paintable != NULL) { g_signal_handlers_disconnect_by_func (self->paintable, invalidate_contents, self); g_signal_handlers_disconnect_by_func (self->paintable, invalidate_size, self); g_signal_handlers_disconnect_by_func (self->paintable, async_loaded, self); } g_clear_object (&self->paintable); if (paintable != NULL) { self->paintable = g_object_ref (paintable); g_signal_connect_swapped (paintable, "invalidate-contents", G_CALLBACK (invalidate_contents), self); g_signal_connect_swapped (paintable, "invalidate-size", G_CALLBACK (invalidate_size), self); if (BZ_IS_ASYNC_TEXTURE (paintable)) g_signal_connect_swapped (paintable, "notify::loaded", G_CALLBACK (async_loaded), self); } gtk_widget_queue_resize (GTK_WIDGET (self)); gtk_widget_queue_draw (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PAINTABLE]); } GdkPaintable * bz_screenshot_get_paintable (BzScreenshot *self) { g_return_val_if_fail (BZ_IS_SCREENSHOT (self), NULL); return self->paintable; } void bz_screenshot_set_focus_x (BzScreenshot *self, double focus_x) { g_return_if_fail (BZ_IS_SCREENSHOT (self)); self->focus_x = focus_x; gtk_widget_queue_draw (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_FOCUS_X]); } double bz_screenshot_get_focus_x (BzScreenshot *self) { g_return_val_if_fail (BZ_IS_SCREENSHOT (self), 0.0); return self->focus_x; } void bz_screenshot_set_focus_y (BzScreenshot *self, double focus_y) { g_return_if_fail (BZ_IS_SCREENSHOT (self)); self->focus_y = focus_y; gtk_widget_queue_draw (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_FOCUS_Y]); } double bz_screenshot_get_focus_y (BzScreenshot *self) { g_return_val_if_fail (BZ_IS_SCREENSHOT (self), 0.0); return self->focus_y; } void bz_screenshot_set_rounded_corners (BzScreenshot *self, gboolean rounded_corners) { g_return_if_fail (BZ_IS_SCREENSHOT (self)); if (self->rounded_corners == rounded_corners) return; self->rounded_corners = rounded_corners; gtk_widget_queue_draw (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ROUNDED_CORNERS]); } gboolean bz_screenshot_get_rounded_corners (BzScreenshot *self) { g_return_val_if_fail (BZ_IS_SCREENSHOT (self), TRUE); return self->rounded_corners; } void bz_screenshot_set_top_half (BzScreenshot *self, gboolean top_half) { g_return_if_fail (BZ_IS_SCREENSHOT (self)); if (self->top_half == top_half) return; self->top_half = top_half; gtk_widget_queue_resize (GTK_WIDGET (self)); gtk_widget_queue_draw (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TOP_HALF]); } gboolean bz_screenshot_get_top_half (BzScreenshot *self) { g_return_val_if_fail (BZ_IS_SCREENSHOT (self), FALSE); return self->top_half; } void bz_screenshot_set_filter (BzScreenshot *self, GskScalingFilter filter) { g_return_if_fail (BZ_IS_SCREENSHOT (self)); if (self->filter == filter) return; self->filter = filter; gtk_widget_queue_draw (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_FILTER]); } GskScalingFilter bz_screenshot_get_filter (BzScreenshot *self) { g_return_val_if_fail (BZ_IS_SCREENSHOT (self), FALSE); return self->filter; } static void invalidate_contents (BzScreenshot *self, GdkPaintable *paintable) { gtk_widget_queue_draw (GTK_WIDGET (self)); } static void invalidate_size (BzScreenshot *self, GdkPaintable *paintable) { gtk_widget_queue_resize (GTK_WIDGET (self)); } static void async_loaded (BzScreenshot *self, GParamSpec *pspec, BzAsyncTexture *texture) { gtk_widget_queue_draw (GTK_WIDGET (self)); gtk_widget_queue_resize (GTK_WIDGET (self)); } bazaar-orig-v0.7.14/src/bz-all-apps-page.c0000664000175000017500000001161515166123241017133 0ustar hasanhasan/* bz-all-apps-page.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include "bz-all-apps-page.h" #include "bz-app-tile.h" #include "bz-entry-group.h" struct _BzAllAppsPage { AdwNavigationPage parent_instance; char *title; GListModel *applications; GtkGridView *grid_view; }; G_DEFINE_FINAL_TYPE (BzAllAppsPage, bz_all_apps_page, ADW_TYPE_NAVIGATION_PAGE) enum { PROP_0, PROP_PAGE_TITLE, PROP_APPLICATIONS, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void tile_clicked_cb (GtkListItem *list_item, BzAppTile *tile); static void bz_all_apps_page_dispose (GObject *object) { BzAllAppsPage *self = BZ_ALL_APPS_PAGE (object); g_clear_pointer (&self->title, g_free); g_clear_object (&self->applications); G_OBJECT_CLASS (bz_all_apps_page_parent_class)->dispose (object); } static void bz_all_apps_page_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzAllAppsPage *self = BZ_ALL_APPS_PAGE (object); switch (prop_id) { case PROP_PAGE_TITLE: g_value_set_string (value, self->title); break; case PROP_APPLICATIONS: g_value_set_object (value, self->applications); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_all_apps_page_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzAllAppsPage *self = BZ_ALL_APPS_PAGE (object); switch (prop_id) { case PROP_PAGE_TITLE: g_clear_pointer (&self->title, g_free); self->title = g_value_dup_string (value); break; case PROP_APPLICATIONS: g_clear_object (&self->applications); self->applications = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_all_apps_page_class_init (BzAllAppsPageClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_all_apps_page_dispose; object_class->get_property = bz_all_apps_page_get_property; object_class->set_property = bz_all_apps_page_set_property; props[PROP_PAGE_TITLE] = g_param_spec_string ( "page-title", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); props[PROP_APPLICATIONS] = g_param_spec_object ( "applications", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_APP_TILE); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-all-apps-page.ui"); gtk_widget_class_bind_template_child (widget_class, BzAllAppsPage, grid_view); gtk_widget_class_bind_template_callback (widget_class, tile_clicked_cb); } static void bz_all_apps_page_init (BzAllAppsPage *self) { gtk_widget_init_template (GTK_WIDGET (self)); } AdwNavigationPage * bz_all_apps_page_new (const char *title, GListModel *applications) { BzAllAppsPage *apps_page = NULL; GtkSelectionModel *selection_model = NULL; apps_page = g_object_new ( BZ_TYPE_ALL_APPS_PAGE, "page-title", title, "applications", applications, NULL); adw_navigation_page_set_title (ADW_NAVIGATION_PAGE (apps_page), title); selection_model = GTK_SELECTION_MODEL (gtk_no_selection_new (applications)); gtk_grid_view_set_model (apps_page->grid_view, selection_model); g_object_unref (selection_model); return ADW_NAVIGATION_PAGE (apps_page); } static void tile_clicked_cb (GtkListItem *list_item, BzAppTile *tile) { BzEntryGroup *group = NULL; group = gtk_list_item_get_item (list_item); if (group == NULL) return; gtk_widget_activate_action (GTK_WIDGET (tile), "window.show-group", "s", bz_entry_group_get_id (group)); } bazaar-orig-v0.7.14/src/bz-decorated-screenshot.blp0000664000175000017500000000041715166123241021146 0ustar hasanhasanusing Gtk 4.0; template $BzDecoratedScreenshot: Button { halign: center; focus-on-click: false; styles [ "flat", "decorated-screenshot" ] child: Gtk.Picture { paintable: bind template.async-texture; content-fit: contain; halign: center; }; }bazaar-orig-v0.7.14/src/bz-data-point.txt0000664000175000017500000000032615166123241017142 0ustar hasanhasanprefix=bz name=data_point parent-prefix=g parent-name=object author=AUTOGEN property=independent double G_TYPE_DOUBLE double property=dependent double G_TYPE_DOUBLE double property=label char G_TYPE_STRING string bazaar-orig-v0.7.14/src/bz-hooks.c0000664000175000017500000005215515166123241015637 0ustar hasanhasan/* bz-hooks.c * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::HOOKS" #include #include "bz-env.h" #include "bz-error.h" #include "bz-hooks.h" #include "bz-util.h" BZ_DEFINE_DATA ( execute_hook, ExecuteHook, { BzHook *hook; BzHookTransactionType ts_type; char *ts_appid; BzEntryGroup *group; }, BZ_RELEASE_DATA (hook, g_object_unref); BZ_RELEASE_DATA (ts_appid, g_free); BZ_RELEASE_DATA (group, g_object_unref)) BZ_DEFINE_DATA ( run_emission, RunEmission, { GListModel *hooks; BzHookSignal signal; BzHookTransactionType ts_type; char *ts_appid; BzEntryGroup *group; }, BZ_RELEASE_DATA (hooks, g_object_unref); BZ_RELEASE_DATA (ts_appid, g_free); BZ_RELEASE_DATA (group, g_object_unref)) BZ_DEFINE_DATA ( dialog, Dialog, { char *id; AdwDialog *dialog; }, BZ_RELEASE_DATA (id, g_free); BZ_RELEASE_DATA (dialog, g_object_unref)); static DexFuture * execute_hook_fiber (ExecuteHookData *data); static DexFuture * run_emission_fiber (RunEmissionData *data); DexFuture * bz_execute_hook (BzHook *hook, BzHookTransactionType ts_type, const char *ts_appid, BzEntryGroup *group) { g_autoptr (ExecuteHookData) data = NULL; dex_return_error_if_fail (BZ_IS_HOOK (hook)); data = execute_hook_data_new (); data->hook = g_object_ref (hook); data->ts_type = ts_type; data->ts_appid = bz_maybe_strdup (ts_appid); data->group = bz_object_maybe_ref (group); return dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) execute_hook_fiber, execute_hook_data_ref (data), execute_hook_data_unref); } DexFuture * bz_run_hook_emission (GListModel *hooks, BzHookSignal signal, BzHookTransactionType ts_type, const char *ts_appid, BzEntryGroup *group) { g_autoptr (RunEmissionData) data = NULL; dex_return_error_if_fail (G_IS_LIST_MODEL (hooks)); data = run_emission_data_new (); data->hooks = g_object_ref (hooks); data->signal = signal; data->ts_type = ts_type; data->ts_appid = bz_maybe_strdup (ts_appid); data->group = bz_object_maybe_ref (group); return dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) run_emission_fiber, execute_hook_data_ref (data), execute_hook_data_unref); } static DexFuture * execute_hook_fiber (ExecuteHookData *data) { BzHook *hook = data->hook; BzHookTransactionType ts_type = data->ts_type; char *ts_appid = data->ts_appid; BzEntryGroup *group = data->group; BzHookSignal signal = 0; g_autoptr (GEnumClass) signal_enum_class = NULL; g_autoptr (GEnumClass) ts_type_enum_class = NULL; GEnumValue *signal_enum = NULL; GEnumValue *ts_type_enum = NULL; g_autoptr (GDateTime) date = NULL; g_autofree char *timestamp_sec = NULL; g_autofree char *timestamp_usec = NULL; const char *id = NULL; const char *shell = NULL; g_autoptr (GPtrArray) dialogs = NULL; g_autoptr (DialogData) current_dialog = NULL; gboolean hook_aborted = FALSE; gboolean finish = FALSE; signal = bz_hook_get_when (hook); switch (signal) { case BZ_HOOK_SIGNAL_BEFORE_TRANSACTION: case BZ_HOOK_SIGNAL_AFTER_TRANSACTION: dex_return_error_if_fail (ts_appid != NULL); break; case BZ_HOOK_SIGNAL_VIEW_APP: default: dex_return_error_if_fail (BZ_IS_ENTRY_GROUP (group)); break; } signal_enum_class = g_type_class_ref (BZ_TYPE_HOOK_SIGNAL); ts_type_enum_class = g_type_class_ref (BZ_TYPE_HOOK_TRANSACTION_TYPE); signal_enum = g_enum_get_value (signal_enum_class, signal); ts_type_enum = g_enum_get_value (ts_type_enum_class, ts_type); date = g_date_time_new_now_utc (); timestamp_sec = g_strdup_printf ("%zu", g_date_time_to_unix (date)); timestamp_usec = g_strdup_printf ("%zu", g_date_time_to_unix_usec (date)); id = bz_hook_get_id (hook); shell = bz_hook_get_shell (hook); if (shell == NULL) { g_warning ("Main Config: hook definition must have shell code, skipping this hook"); return dex_future_new_for_int (BZ_HOOK_RETURN_STATUS_CONTINUE); } dialogs = g_ptr_array_new_with_free_func (dialog_data_unref); if (bz_hook_get_dialogs (hook) != NULL) { GListModel *config_dialogs = NULL; guint n_dialogs = 0; config_dialogs = bz_hook_get_dialogs (hook); n_dialogs = g_list_model_get_n_items (config_dialogs); for (guint i = 0; i < n_dialogs; i++) { g_autoptr (BzHookDialog) config_dialog = NULL; const char *dialog_id = NULL; const char *dialog_title = NULL; const char *dialog_body = NULL; gboolean dialog_body_use_markup = FALSE; const char *dialog_default_response = NULL; g_autoptr (AdwDialog) dialog = NULL; guint n_opts = 0; g_autoptr (DialogData) dialog_data = NULL; config_dialog = g_list_model_get_item (config_dialogs, i); dialog_id = bz_hook_dialog_get_id (config_dialog); dialog_title = bz_hook_dialog_get_title (config_dialog); dialog_body = bz_hook_dialog_get_body (config_dialog); dialog_body_use_markup = bz_hook_dialog_get_body_use_markup (config_dialog); dialog_default_response = bz_hook_dialog_get_default_response_id (config_dialog); if (dialog_title == NULL || dialog_body == NULL) { g_warning ("Main Config: dialog definition must have a title and body, skipping this hook"); return dex_future_new_for_int (BZ_HOOK_RETURN_STATUS_CONTINUE); } if (dialog_default_response == NULL) { g_warning ("Main Config: dialog definition must have a default response, skipping this hook"); return dex_future_new_for_int (BZ_HOOK_RETURN_STATUS_CONTINUE); } dialog = g_object_ref_sink (adw_alert_dialog_new (dialog_title, dialog_body)); if (bz_hook_dialog_get_options (config_dialog) != NULL) { GListModel *config_opts = NULL; guint n_options = 0; config_opts = bz_hook_dialog_get_options (config_dialog); n_options = g_list_model_get_n_items (config_opts); for (guint j = 0; j < n_options; j++) { g_autoptr (BzHookDialogOption) config_opt = NULL; const char *opt_id = NULL; const char *opt_string = NULL; const char *opt_style = NULL; config_opt = g_list_model_get_item (config_opts, j); opt_id = bz_hook_dialog_option_get_id (config_opt); if (opt_id == NULL) { g_warning ("Main Config: dialog option definition must have an id, skipping this hook"); return dex_future_new_for_int (BZ_HOOK_RETURN_STATUS_CONTINUE); } opt_string = bz_hook_dialog_option_get_string (config_opt); if (opt_string == NULL) { g_warning ("Main Config: dialog option definition must have a string, skipping this hook"); return dex_future_new_for_int (BZ_HOOK_RETURN_STATUS_CONTINUE); } opt_style = bz_hook_dialog_option_get_style (config_opt); adw_alert_dialog_add_response (ADW_ALERT_DIALOG (dialog), opt_id, opt_string); if (opt_style != NULL) { AdwResponseAppearance appearance = ADW_RESPONSE_DEFAULT; if (g_strcmp0 (opt_style, "suggested") == 0) appearance = ADW_RESPONSE_SUGGESTED; else if (g_strcmp0 (opt_style, "destructive") == 0) appearance = ADW_RESPONSE_DESTRUCTIVE; else g_warning ("Main Config: dialog option definition appearance can be " "\"suggested\" or \"destructive\". \"%s\" is invalid.", opt_style); adw_alert_dialog_set_response_appearance ( ADW_ALERT_DIALOG (dialog), opt_id, appearance); } n_opts++; } } if (n_opts == 0) { g_warning ("Main Config: dialog definition must have options, skipping this hook"); return dex_future_new_for_int (BZ_HOOK_RETURN_STATUS_CONTINUE); } adw_alert_dialog_set_body_use_markup ( ADW_ALERT_DIALOG (dialog), dialog_body_use_markup); adw_alert_dialog_set_default_response ( ADW_ALERT_DIALOG (dialog), dialog_default_response); dialog_data = dialog_data_new (); dialog_data->id = dialog_id != NULL ? g_strdup (dialog_id) : NULL; dialog_data->dialog = g_steal_pointer (&dialog); g_ptr_array_add (dialogs, g_steal_pointer (&dialog_data)); } } for (guint stage = 0;; stage++) { g_autoptr (GError) local_error = NULL; g_autoptr (GSubprocessLauncher) launcher = NULL; g_autofree char *stage_str = NULL; const char *hook_stage = NULL; g_autoptr (GSubprocess) subprocess = NULL; gboolean result = FALSE; GInputStream *stdout_pipe = NULL; g_autoptr (GBytes) stdout_bytes = NULL; gsize stdout_size = 0; gconstpointer stdout_data = NULL; g_autofree char *stdout_str = NULL; char *stdout_newline = NULL; launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE); g_subprocess_launcher_set_cwd (launcher, g_get_home_dir ()); g_subprocess_launcher_setenv (launcher, "BAZAAR_HOOK_INITIATED_UNIX_STAMP", timestamp_sec, TRUE); g_subprocess_launcher_setenv (launcher, "BAZAAR_HOOK_INITIATED_UNIX_STAMP_USEC", timestamp_usec, TRUE); stage_str = g_strdup_printf ("%d", stage); g_subprocess_launcher_setenv (launcher, "BAZAAR_HOOK_STAGE_IDX", stage_str, TRUE); g_subprocess_launcher_setenv (launcher, "BAZAAR_HOOK_ID", id, TRUE); g_subprocess_launcher_setenv (launcher, "BAZAAR_HOOK_TYPE", signal_enum->value_nick, TRUE); g_subprocess_launcher_setenv (launcher, "BAZAAR_HOOK_WAS_ABORTED", hook_aborted ? "true" : "false", TRUE); switch (signal) { case BZ_HOOK_SIGNAL_BEFORE_TRANSACTION: case BZ_HOOK_SIGNAL_AFTER_TRANSACTION: g_subprocess_launcher_setenv (launcher, "BAZAAR_TS_APPID", ts_appid, TRUE); g_subprocess_launcher_setenv (launcher, "BAZAAR_TS_TYPE", ts_type_enum->value_nick, TRUE); break; case BZ_HOOK_SIGNAL_VIEW_APP: default: g_subprocess_launcher_setenv (launcher, "BAZAAR_APPID", bz_entry_group_get_id (group), TRUE); break; } if (finish) hook_stage = "teardown"; else if (hook_aborted) hook_stage = "catch"; else if (stage == 0) hook_stage = "setup"; else if (current_dialog != NULL) { GApplication *application = NULL; GtkWindow *window = NULL; g_autofree char *response = NULL; hook_stage = "teardown-dialog"; application = g_application_get_default (); window = gtk_application_get_active_window (GTK_APPLICATION (application)); if (window != NULL) { adw_dialog_present (current_dialog->dialog, GTK_WIDGET (window)); response = dex_await_string ( bz_make_alert_dialog_future (ADW_ALERT_DIALOG (current_dialog->dialog)), &local_error); if (response == NULL) g_warning ("Failed to resolve response from dialog " "\"%s\", assuming default response \"%s\": %s", current_dialog->id, adw_alert_dialog_get_default_response ( ADW_ALERT_DIALOG (current_dialog->dialog)), local_error->message); g_clear_pointer (&local_error, g_error_free); } else g_warning ("A window was not available to present dialog " "\"%s\" on, assuming default response \"%s\"", current_dialog->id, adw_alert_dialog_get_default_response ( ADW_ALERT_DIALOG (current_dialog->dialog))); g_subprocess_launcher_setenv (launcher, "BAZAAR_HOOK_DIALOG_ID", current_dialog->id, TRUE); g_subprocess_launcher_setenv ( launcher, "BAZAAR_HOOK_DIALOG_RESPONSE_ID", response != NULL ? response : adw_alert_dialog_get_default_response ( ADW_ALERT_DIALOG (current_dialog->dialog)), TRUE); g_clear_pointer (¤t_dialog, dialog_data_unref); } else if (dialogs->len > 0) { hook_stage = "setup-dialog"; current_dialog = g_ptr_array_steal_index (dialogs, 0); g_subprocess_launcher_setenv (launcher, "BAZAAR_HOOK_DIALOG_ID", current_dialog->id, TRUE); } else hook_stage = "action"; g_subprocess_launcher_setenv (launcher, "BAZAAR_HOOK_STAGE", hook_stage, TRUE); subprocess = g_subprocess_launcher_spawn ( launcher, &local_error, "/bin/sh", "-c", shell, NULL); if (subprocess == NULL) { g_warning ("Hook failed to spawn, abandoning it now: %s", local_error->message); return dex_future_new_for_int (BZ_HOOK_RETURN_STATUS_CONTINUE); } result = dex_await ( dex_subprocess_wait_check (subprocess), &local_error); if (!result) { g_warning ("Hook failed to exit cleanly, abandoning it now: %s", local_error->message); return dex_future_new_for_int (BZ_HOOK_RETURN_STATUS_CONTINUE); } stdout_pipe = g_subprocess_get_stdout_pipe (subprocess); stdout_bytes = g_input_stream_read_bytes (stdout_pipe, 1024, NULL, &local_error); if (!stdout_bytes) { g_warning ("Failed to read stdout pipe of hook, abandoning it now: %s", local_error->message); return dex_future_new_for_int (BZ_HOOK_RETURN_STATUS_CONTINUE); } stdout_data = g_bytes_get_data (stdout_bytes, &stdout_size); stdout_str = g_malloc (stdout_size + 1); memcpy (stdout_str, stdout_data, stdout_size); stdout_str[stdout_size] = '\0'; stdout_newline = strchr (stdout_str, '\n'); if (stdout_newline != NULL) *stdout_newline = '\0'; if (g_strcmp0 (hook_stage, "setup") == 0) { if (g_strcmp0 (stdout_str, "ok") == 0) continue; else if (g_strcmp0 (stdout_str, "pass") == 0) return dex_future_new_for_int (BZ_HOOK_RETURN_STATUS_CONTINUE); } else if (g_strcmp0 (hook_stage, "setup-dialog") == 0) { if (g_strcmp0 (stdout_str, "ok") == 0) continue; else if (g_strcmp0 (stdout_str, "pass") == 0) { g_clear_pointer (¤t_dialog, dialog_data_unref); continue; } } else if (g_strcmp0 (hook_stage, "teardown-dialog") == 0) { if (g_strcmp0 (stdout_str, "ok") == 0) continue; else if (g_strcmp0 (stdout_str, "abort") == 0) { hook_aborted = TRUE; continue; } } else if (g_strcmp0 (hook_stage, "catch") == 0) { if (g_strcmp0 (stdout_str, "recover") == 0) { hook_aborted = FALSE; continue; } else if (g_strcmp0 (stdout_str, "abort") == 0) { finish = TRUE; continue; } } else if (g_strcmp0 (hook_stage, "action") == 0) { finish = TRUE; continue; } else if (g_strcmp0 (hook_stage, "teardown") == 0) { if (g_strcmp0 (stdout_str, "continue") == 0) return dex_future_new_for_int (BZ_HOOK_RETURN_STATUS_CONTINUE); else if (g_strcmp0 (stdout_str, "stop") == 0) return dex_future_new_for_int (BZ_HOOK_RETURN_STATUS_STOP); else if (g_strcmp0 (stdout_str, "confirm") == 0) return dex_future_new_for_int (BZ_HOOK_RETURN_STATUS_CONFIRM); else if (g_strcmp0 (stdout_str, "deny") == 0) return dex_future_new_for_int (BZ_HOOK_RETURN_STATUS_DENY); } else g_assert_not_reached (); g_warning ("Received invalid response from hook for stage \"%s\", abandoning it now", hook_stage); return dex_future_new_for_int (BZ_HOOK_RETURN_STATUS_CONTINUE); } } static DexFuture * run_emission_fiber (RunEmissionData *data) { GListModel *hooks = data->hooks; BzHookSignal signal = data->signal; BzHookTransactionType ts_type = data->ts_type; char *ts_appid = data->ts_appid; BzEntryGroup *group = data->group; guint n_hooks = 0; n_hooks = g_list_model_get_n_items (hooks); for (guint i = 0; i < n_hooks; i++) { g_autoptr (BzHook) hook = NULL; BzHookSignal when = 0; hook = g_list_model_get_item (hooks, i); when = bz_hook_get_when (hook); if (when == signal) { const char *check_appid_regex = NULL; BzHookReturnStatus hook_result = BZ_HOOK_RETURN_STATUS_CONTINUE; check_appid_regex = bz_hook_get_check_appid_regex (hook); if (check_appid_regex != NULL) { GRegex *regex = NULL; regex = g_object_get_data (G_OBJECT (hook), "check-appid-regex"); if (regex == NULL) { g_autoptr (GError) local_error = NULL; regex = g_regex_new ( check_appid_regex, G_REGEX_OPTIMIZE, G_REGEX_MATCH_DEFAULT, &local_error); if (regex != NULL) g_object_set_data_full ( G_OBJECT (hook), "check-appid-regex", regex, (GDestroyNotify) g_regex_unref); else g_warning ("Hook check-appid-regex property '%s' " "is an invalid regex string: %s", check_appid_regex, local_error->message); } if (regex != NULL && !g_regex_match (regex, ts_appid, G_REGEX_MATCH_DEFAULT, NULL)) continue; } hook_result = dex_await_int ( bz_execute_hook (hook, ts_type, ts_appid, group), NULL); if (hook_result == BZ_HOOK_RETURN_STATUS_CONFIRM || hook_result == BZ_HOOK_RETURN_STATUS_STOP) break; else if (hook_result == BZ_HOOK_RETURN_STATUS_DENY) return dex_future_new_reject ( G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Prevented by a configured hook"); } } return dex_future_new_true (); } bazaar-orig-v0.7.14/src/bz-screenshot-page.blp0000664000175000017500000001147415166123241020135 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzScreenshotPage: Adw.NavigationPage { title: _("Screenshots"); child: Adw.BreakpointBin { width-request: 360; height-request: 100; Adw.Breakpoint { condition ("max-width: 700px") setters { mobile_caption_box.margin-bottom: 70; } } child: Adw.ToastOverlay toast_overlay { child: Adw.ToolbarView { top-bar-style: flat; extend-content-to-top-edge: true; styles [ "view-dark", ] [top] Adw.HeaderBar header_bar { styles [ "flat", "header-osd", ] show-end-title-buttons: false; show-start-title-buttons: false; show-title: false; } content: Overlay { [overlay] Box { orientation: horizontal; halign: start; valign: end; margin-bottom: 12; margin-start: 12; spacing: 6; Box navigation_controls { orientation: horizontal; spacing: 6; visible: bind $has_multiple_screenshots(template.screenshots) as ; styles [ "osd-box", ] Button previous_button { icon-name: "go-previous-symbolic"; tooltip-text: _("Previous Screenshot"); clicked => $previous_clicked() swapped; styles [ "flat", ] } Button next_button { icon-name: "go-next-symbolic"; tooltip-text: _("Next Screenshot"); clicked => $next_clicked() swapped; styles [ "flat", ] } } Box { styles [ "osd-box", ] Button copy_button { icon-name: "edit-copy-symbolic"; tooltip-text: _("Copy Image"); clicked => $copy_clicked() swapped; styles [ "flat", ] } } } [overlay] Revealer { halign: center; valign: end; reveal-child: bind $is_valid_string(template.current-caption) as ; transition-type: crossfade; can-target: false; child: Box mobile_caption_box { margin-bottom: 12; styles [ "osd-box", ] Label { halign: center; hexpand: true; label: bind template.current-caption; height-request: 34; justify: center; max-width-chars: 30; wrap: true; margin-start: 8; margin-end: 8; wrap-mode: word_char; styles [ "heading" ] } }; } [overlay] Box { orientation: horizontal; halign: end; valign: end; margin-bottom: 12; margin-end: 12; Box zoom_controls { orientation: horizontal; styles [ "osd-box", ] Revealer { reveal-child: bind template.is-zoomed as ; transition-type: slide_right; Button reset_zoom_button { icon-name: "zoom-original-symbolic"; tooltip-text: _("Reset View"); clicked => $reset_zoom_clicked() swapped; styles [ "flat", ] } } Button zoom_out_button { icon-name: "zoom-minus-symbolic"; tooltip-text: _("Zoom Out"); clicked => $zoom_out_clicked() swapped; styles [ "flat", ] } Button zoom_in_button { icon-name: "zoom-plus-symbolic"; tooltip-text: _("Zoom In"); clicked => $zoom_in_clicked() swapped; styles [ "flat", ] } } } child: Adw.Carousel carousel { can-focus: false; interactive: bind $invert_boolean(template.is-zoomed) as ; allow-scroll-wheel: bind $invert_boolean(template.is-zoomed) as ; allow-mouse-drag: bind $invert_boolean(template.is-zoomed) as ; allow-long-swipes: false; notify::position => $on_carousel_position_changed(); }; }; }; }; }; }bazaar-orig-v0.7.14/src/bz-apps-page.h0000664000175000017500000000272515166123241016374 0ustar hasanhasan/* bz-apps-page.h * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-flathub-category.h" G_BEGIN_DECLS #define BZ_TYPE_APPS_PAGE (bz_apps_page_get_type ()) G_DECLARE_FINAL_TYPE (BzAppsPage, bz_apps_page, BZ, APPS_PAGE, AdwNavigationPage) AdwNavigationPage * bz_apps_page_new (const char *title, GListModel *applications); AdwNavigationPage * bz_apps_page_new_with_carousel (const char *title, GListModel *applications, GListModel *carousel_applications); AdwNavigationPage * bz_apps_page_new_from_category (BzFlathubCategory *category); void bz_apps_page_set_subtitle (BzAppsPage *self, const char *subtitle); G_END_DECLS bazaar-orig-v0.7.14/src/bz-search-page.h0000664000175000017500000000332315166123241016671 0ustar hasanhasan/* bz-search-page.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-state-info.h" G_BEGIN_DECLS #define BZ_TYPE_SEARCH_PAGE (bz_search_page_get_type ()) G_DECLARE_FINAL_TYPE (BzSearchPage, bz_search_page, BZ, SEARCH_PAGE, AdwBin) GtkWidget * bz_search_page_new (GListModel *model, const char *initial); void bz_search_page_set_state (BzSearchPage *self, BzStateInfo *state); BzStateInfo * bz_search_page_get_state (BzSearchPage *self); void bz_search_page_set_text (BzSearchPage *self, const char *text); const char * bz_search_page_get_text (BzSearchPage *self); BzEntryGroup * bz_search_page_get_selected (BzSearchPage *self, gboolean *remove); BzEntryGroup * bz_search_page_get_previewing (BzSearchPage *self); void bz_search_page_refresh (BzSearchPage *self); gboolean bz_search_page_ensure_active (BzSearchPage *self, const char *initial); G_END_DECLS bazaar-orig-v0.7.14/src/bz-curated-row.txt0000664000175000017500000000024415166123241017335 0ustar hasanhasanprefix=bz name=curated_row parent-prefix=g parent-name=object author=AUTOGEN include="bz-curated-section.h" property=sections GListModel G_TYPE_LIST_MODEL object bazaar-orig-v0.7.14/src/bz-inspector.h0000664000175000017500000000225615166123241016524 0ustar hasanhasan/* bz-inspector.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-state-info.h" G_BEGIN_DECLS #define BZ_TYPE_INSPECTOR (bz_inspector_get_type ()) G_DECLARE_FINAL_TYPE (BzInspector, bz_inspector, BZ, INSPECTOR, AdwWindow) BzInspector * bz_inspector_new (void); BzStateInfo * bz_inspector_get_state (BzInspector *self); void bz_inspector_set_state (BzInspector *self, BzStateInfo *state); G_END_DECLS /* End of bz-inspector.h */ bazaar-orig-v0.7.14/src/bz-download-worker.c0000664000175000017500000004073115166123241017627 0ustar hasanhasan/* bz-download-worker.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include "bz-download-worker.h" #include "bz-env.h" #include "bz-util.h" struct _BzDownloadWorker { GObject parent_instance; char *name; GSubprocess *subprocess; GHashTable *waiting; GMutex read_mutex; DexFuture *task; BzGuard *write_gate; GMutex write_mutex; }; static void initable_iface_init (GInitableIface *iface); G_DEFINE_FINAL_TYPE_WITH_CODE ( BzDownloadWorker, bz_download_worker, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)); enum { PROP_0, PROP_NAME, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static DexFuture * monitor_worker_fiber (GWeakRef *wr); BZ_DEFINE_DATA ( invoke_worker, InvokeWorker, { GWeakRef *self; DexPromise *promise; GFile *src; GFile *dest; }, BZ_RELEASE_DATA (self, bz_weak_release); BZ_RELEASE_DATA (promise, dex_unref); BZ_RELEASE_DATA (src, g_object_unref); BZ_RELEASE_DATA (dest, g_object_unref)); static DexFuture * invoke_worker_fiber (InvokeWorkerData *data); static void terminate (BzDownloadWorker *self); static void plumb_data_input_stream_read_line_async (GDataInputStream *stream, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); static char * plumb_data_input_stream_read_line_finish (GDataInputStream *stream, GAsyncResult *result, gpointer user_data); static GMutex default_worker_mutex = { 0 }; static GPtrArray *default_workers = NULL; static guint next_default_worker = 0; static void bz_download_worker_dispose (GObject *object) { BzDownloadWorker *self = BZ_DOWNLOAD_WORKER (object); terminate (self); dex_clear (&self->task); g_clear_object (&self->subprocess); g_mutex_clear (&self->write_mutex); bz_clear_guard (&self->write_gate); g_mutex_clear (&self->read_mutex); g_clear_pointer (&self->waiting, g_hash_table_unref); g_clear_pointer (&self->name, g_free); G_OBJECT_CLASS (bz_download_worker_parent_class)->dispose (object); } static void bz_download_worker_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzDownloadWorker *self = BZ_DOWNLOAD_WORKER (object); switch (prop_id) { case PROP_NAME: g_value_set_string (value, bz_download_worker_get_name (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_download_worker_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzDownloadWorker *self = BZ_DOWNLOAD_WORKER (object); switch (prop_id) { case PROP_NAME: bz_download_worker_set_name (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_download_worker_class_init (BzDownloadWorkerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bz_download_worker_set_property; object_class->get_property = bz_download_worker_get_property; object_class->dispose = bz_download_worker_dispose; props[PROP_NAME] = g_param_spec_string ( "name", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_download_worker_init (BzDownloadWorker *self) { g_mutex_init (&self->read_mutex); g_mutex_init (&self->write_mutex); self->waiting = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, dex_unref); } static gboolean bz_download_worker_initable_init (GInitable *initable, GCancellable *cancellable, GError **error) { BzDownloadWorker *self = BZ_DOWNLOAD_WORKER (initable); self->subprocess = g_subprocess_new ( G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE, error, DL_WORKER_BIN_NAME, NULL); if (self->subprocess == NULL) return FALSE; self->task = dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) monitor_worker_fiber, bz_track_weak (self), bz_weak_release); return TRUE; } static void initable_iface_init (GInitableIface *iface) { iface->init = bz_download_worker_initable_init; } BzDownloadWorker * bz_download_worker_new (const char *name, GError **error) { return g_initable_new ( BZ_TYPE_DOWNLOAD_WORKER, NULL, error, "name", name, NULL); } const char * bz_download_worker_get_name (BzDownloadWorker *self) { g_return_val_if_fail (BZ_IS_DOWNLOAD_WORKER (self), NULL); return self->name; } void bz_download_worker_set_name (BzDownloadWorker *self, const char *name) { g_return_if_fail (BZ_IS_DOWNLOAD_WORKER (self)); g_clear_pointer (&self->name, g_free); if (name != NULL) self->name = g_strdup (name); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NAME]); } DexFuture * bz_download_worker_invoke (BzDownloadWorker *self, GFile *src, GFile *dest) { g_autoptr (DexPromise) promise = NULL; g_autoptr (InvokeWorkerData) data = NULL; dex_return_error_if_fail (BZ_IS_DOWNLOAD_WORKER (self)); dex_return_error_if_fail (G_IS_FILE (src)); dex_return_error_if_fail (G_IS_FILE (dest)); promise = dex_promise_new (); data = invoke_worker_data_new (); data->self = bz_track_weak (self); data->promise = dex_ref (promise); data->src = g_object_ref (src); data->dest = g_object_ref (dest); dex_future_disown (dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) invoke_worker_fiber, invoke_worker_data_ref (data), invoke_worker_data_unref)); return DEX_FUTURE (g_steal_pointer (&promise)); } BzDownloadWorker * bz_download_worker_get_default (void) { g_autoptr (GMutexLocker) locker = NULL; BzDownloadWorker *ret = NULL; locker = g_mutex_locker_new (&default_worker_mutex); if (default_workers == NULL) { default_workers = g_ptr_array_new_with_free_func (g_object_unref); for (guint i = 0; i < bz_get_n_download_workers (); i++) { g_autoptr (GError) local_error = NULL; g_autoptr (BzDownloadWorker) worker = NULL; worker = bz_download_worker_new ("default", &local_error); if (worker == NULL) g_warning ("FATAL!!! The default download worker could not be spawned: %s", local_error->message); g_assert (worker != NULL); g_ptr_array_add (default_workers, g_steal_pointer (&worker)); } } /* Check if any of the subprocesses need to be recreated */ for (guint i = 0; i < default_workers->len; i++) { BzDownloadWorker **loc = NULL; loc = (BzDownloadWorker **) &g_ptr_array_index (default_workers, i); if (g_subprocess_get_identifier ((*loc)->subprocess) == NULL) { g_autoptr (GError) local_error = NULL; g_autoptr (BzDownloadWorker) worker = NULL; g_clear_object (loc); worker = bz_download_worker_new ("default", &local_error); if (worker == NULL) g_warning ("FATAL!!! The default download worker could not be spawned: %s", local_error->message); g_assert (worker != NULL); *loc = g_steal_pointer (&worker); } } ret = g_ptr_array_index (default_workers, next_default_worker); next_default_worker = (next_default_worker + 1) % default_workers->len; return ret; } void bz_reap_default_download_workers (void) { g_autoptr (GMutexLocker) locker = NULL; locker = g_mutex_locker_new (&default_worker_mutex); if (default_workers == NULL) return; for (guint i = 0; i < default_workers->len; i++) { BzDownloadWorker *worker = NULL; worker = g_ptr_array_index (default_workers, i); g_subprocess_force_exit (worker->subprocess); } g_clear_pointer (&default_workers, g_ptr_array_unref); next_default_worker = 0; } static DexFuture * monitor_worker_fiber (GWeakRef *wr) { g_autoptr (BzDownloadWorker) self = NULL; g_autoptr (GInputStream) input_stream = NULL; g_autoptr (GDataInputStream) subprocess_stdout = NULL; bz_weak_get_or_return_reject (self, wr); input_stream = g_object_ref (g_subprocess_get_stdout_pipe (self->subprocess)); subprocess_stdout = g_data_input_stream_new (g_object_ref (input_stream)); g_clear_object (&self); for (;;) { g_autoptr (GError) local_error = NULL; g_autofree char *line = NULL; line = dex_await_string ( dex_async_pair_new ( subprocess_stdout, &DEX_ASYNC_PAIR_INFO_STRING ( plumb_data_input_stream_read_line_async, plumb_data_input_stream_read_line_finish)), &local_error); if (line == NULL) { if (local_error != NULL) g_warning ("Could not read stdout from download worker subprocess: %s", local_error->message); goto err; } do { g_autoptr (GVariant) variant = NULL; g_autofree char *dest_path = NULL; gboolean success = FALSE; DexPromise *promise = NULL; if (line == NULL) { line = g_data_input_stream_read_line_utf8 (subprocess_stdout, NULL, NULL, &local_error); if (line == NULL) { if (local_error != NULL) g_warning ("Could not read stdout from download worker subprocess: %s", local_error->message); goto err; } } variant = g_variant_parse (G_VARIANT_TYPE ("(sb)"), line, NULL, NULL, &local_error); if (variant == NULL) { g_warning ("Could not interpret stdout from download worker subprocess: %s", local_error->message); goto err; } g_variant_get (variant, "(sb)", &dest_path, &success); bz_weak_get_or_return_reject (self, wr); g_mutex_lock (&self->read_mutex); promise = g_hash_table_lookup (self->waiting, dest_path); if (promise != NULL) { if (success) dex_promise_resolve_boolean (promise, TRUE); else dex_promise_reject ( promise, g_error_new (G_IO_ERROR, G_IO_ERROR_UNKNOWN, "The subprocess reported an error downloading '%s'", dest_path)); promise = NULL; g_hash_table_remove (self->waiting, dest_path); } g_mutex_unlock (&self->read_mutex); g_clear_object (&self); g_clear_pointer (&line, g_free); } while (g_input_stream_has_pending (input_stream)); } return dex_future_new_true (); err: bz_weak_get_or_return_reject (self, wr); /* give up on this subprocess and wait to be disposed */ g_mutex_lock (&self->read_mutex); terminate (self); g_mutex_unlock (&self->read_mutex); return dex_future_new_false (); } static DexFuture * invoke_worker_fiber (InvokeWorkerData *data) { DexPromise *promise = data->promise; GFile *src = data->src; GFile *dest = data->dest; g_autoptr (BzDownloadWorker) self = NULL; g_autoptr (GError) local_error = NULL; g_autoptr (BzGuard) guard = NULL; g_autofree char *src_uri = NULL; g_autofree char *dest_path = NULL; DexPromise *existing = NULL; g_autoptr (GVariant) variant = NULL; g_autoptr (GString) output = NULL; g_autoptr (GOutputStream) stdin_stream = NULL; gint64 bytes_written = -1; src_uri = g_file_get_uri (src); dest_path = g_file_get_path (dest); bz_weak_get_or_return_reject (self, data->self); g_mutex_lock (&self->read_mutex); existing = g_hash_table_lookup (self->waiting, dest_path); if (existing != NULL) { dex_promise_reject ( existing, g_error_new (G_IO_ERROR, G_IO_ERROR_CANCELLED, "The operation was replaced")); existing = NULL; } g_hash_table_replace (self->waiting, g_strdup (dest_path), dex_ref (promise)); g_mutex_unlock (&self->read_mutex); variant = g_variant_new ("(ss)", src_uri, dest_path); output = g_string_new (NULL); output = g_variant_print_string (variant, g_steal_pointer (&output), TRUE); g_string_append_c (output, '\n'); stdin_stream = g_object_ref (g_subprocess_get_stdin_pipe (self->subprocess)); BZ_BEGIN_GUARD_WITH_CONTEXT (&guard, &self->write_mutex, &self->write_gate); g_clear_object (&self); bytes_written = dex_await_int64 ( dex_future_first ( dex_output_stream_write ( stdin_stream, output->str, output->len, G_PRIORITY_DEFAULT_IDLE), dex_ref (promise), NULL), &local_error); bz_clear_guard (&guard); /* Check if we've been cancelled */ if (!dex_future_is_pending (DEX_FUTURE (promise))) return dex_future_new_false (); if (bytes_written < 0) { bz_weak_get_or_return_reject (self, data->self); g_mutex_lock (&self->read_mutex); g_hash_table_remove (self->waiting, dest_path); dex_promise_reject (promise, g_steal_pointer (&local_error)); g_mutex_unlock (&self->read_mutex); g_clear_object (&self); } return dex_future_new_true (); } static void terminate (BzDownloadWorker *self) { GHashTableIter waiting_iter = { 0 }; g_hash_table_iter_init (&waiting_iter, self->waiting); for (;;) { g_autofree char *dest_path = NULL; g_autoptr (DexPromise) promise = NULL; if (!g_hash_table_iter_next ( &waiting_iter, (gpointer *) &dest_path, (gpointer *) &promise)) break; g_hash_table_iter_steal (&waiting_iter); dex_promise_reject ( promise, g_error_new (G_IO_ERROR, G_IO_ERROR_CANCELLED, "The subprocess was terminated")); } } static void plumb_data_input_stream_read_line_async (GDataInputStream *stream, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_data_input_stream_read_line_async ( stream, G_PRIORITY_DEFAULT_IDLE, cancellable, callback, user_data); } static char * plumb_data_input_stream_read_line_finish (GDataInputStream *stream, GAsyncResult *result, gpointer user_data) { return g_data_input_stream_read_line_finish_utf8 ( stream, result, NULL, user_data); } /* End of bz-download-worker.c */ bazaar-orig-v0.7.14/src/bz-preferences-dialog.h0000664000175000017500000000211515166123241020246 0ustar hasanhasan/* bz-preferences-dialog.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-state-info.h" G_BEGIN_DECLS #define BZ_TYPE_PREFERENCES_DIALOG (bz_preferences_dialog_get_type ()) G_DECLARE_FINAL_TYPE (BzPreferencesDialog, bz_preferences_dialog, BZ, PREFERENCES_DIALOG, AdwPreferencesDialog) AdwDialog * bz_preferences_dialog_new (BzStateInfo *state); G_END_DECLS bazaar-orig-v0.7.14/src/bz-appstream-parser.c0000664000175000017500000006450115166123241020000 0ustar hasanhasan/* bz-appstream-parser.c */ #define G_LOG_DOMAIN "BAZAAR::APPSTREAM-PARSER" #define BAZAAR_MODULE "appstream-parser" #include "config.h" #include #include "bz-appstream-parser.h" #include "bz-async-texture.h" #include "bz-category-flags.h" #include "bz-io.h" #include "bz-release.h" #include "bz-url.h" #include "bz-verification-status.h" static guint parse_control_value (const char *value) { if (g_strcmp0 (value, "pointing") == 0) return BZ_CONTROL_POINTING; else if (g_strcmp0 (value, "keyboard") == 0) return BZ_CONTROL_KEYBOARD; else if (g_strcmp0 (value, "console") == 0) return BZ_CONTROL_CONSOLE; else if (g_strcmp0 (value, "tablet") == 0) return BZ_CONTROL_TABLET; else if (g_strcmp0 (value, "touch") == 0) return BZ_CONTROL_TOUCH; else if (g_strcmp0 (value, "gamepad") == 0) return BZ_CONTROL_GAMEPAD; else if (g_strcmp0 (value, "tv-remote") == 0) return BZ_CONTROL_TV_REMOTE; else if (g_strcmp0 (value, "voice") == 0) return BZ_CONTROL_VOICE; else if (g_strcmp0 (value, "vision") == 0) return BZ_CONTROL_VISION; else return 0; } static gboolean calculate_is_mobile_friendly (guint required_controls, guint recommended_controls, guint supported_controls) { return (required_controls & BZ_CONTROL_TOUCH) != 0 || (recommended_controls & BZ_CONTROL_TOUCH) != 0 || (supported_controls & BZ_CONTROL_TOUCH) != 0; } static char * proxy_screenshot_url (const char *url, gboolean high_quality) { g_autofree char *src = NULL; g_autofree char *encoded_url = NULL; const char *suffix = NULL; if (g_str_has_prefix (url, "https://dl.flathub.org/repo/screenshots/")) { suffix = url + strlen ("https://dl.flathub.org/repo/screenshots/"); src = g_strdup_printf ("https://dl.flathub.org/media/%s", suffix); } else if (g_str_has_prefix (url, "https://dl.flathub.org/")) { src = g_strdup (url); } else { return g_strdup (url); } encoded_url = g_base64_encode ((const guchar *) src, strlen (src)); g_strdelimit (encoded_url, "=", '\0'); for (char *p = encoded_url; *p; p++) { if (*p == '+') *p = '-'; if (*p == '/') *p = '_'; } return g_strdup_printf ( "https://imgproxy.flathub.org/insecure/%s/%s", high_quality ? "q:90/f:avif" : "dpr:1/f:avif/rs:fill-down", encoded_url); } static GdkPaintable * find_screenshot (GPtrArray *images, const char *caption, gboolean match_highest, guint target_width, guint target_height, gboolean require_flathub, const char *module_dir, const char *unique_id_checksum, const char *cache_filename, char **out_caption) { const char *best_url = NULL; gint best_diff = G_MAXINT; guint best_res = 0; guint target_pixels = target_width * target_height; if (images == NULL) return NULL; for (guint j = 0; j < images->len; j++) { AsImage *image_obj = g_ptr_array_index (images, j); const char *url = as_image_get_url (image_obj); guint width = as_image_get_width (image_obj); guint height = as_image_get_height (image_obj); guint pixels = width * height; if (url == NULL) continue; if (require_flathub && !g_str_has_prefix (url, "https://dl.flathub.org/")) continue; if (match_highest) { if (pixels > best_res) { best_url = url; best_res = pixels; } } else { gint diff = ABS ((gint) pixels - (gint) target_pixels); if (diff < best_diff) { best_url = url; best_diff = diff; } } } if (best_url != NULL) { g_autoptr (GFile) screenshot_file = NULL; g_autoptr (GFile) cache_file = NULL; g_autofree char *proxied_url = NULL; BzAsyncTexture *texture = NULL; proxied_url = proxy_screenshot_url (best_url, match_highest); screenshot_file = g_file_new_for_uri (proxied_url); cache_file = g_file_new_build_filename ( module_dir, unique_id_checksum, cache_filename, NULL); texture = bz_async_texture_new_lazy (screenshot_file, cache_file); if (out_caption != NULL) *out_caption = g_strdup (caption ? caption : ""); return GDK_PAINTABLE (texture); } return NULL; } gboolean bz_appstream_parser_populate_entry (BzEntry *entry, AsComponent *component, const char *appstream_dir, const char *remote_name, const char *module_dir, const char *unique_id_checksum, const char *id, guint kinds, GError **error) { AsDeveloper *developer_obj = NULL; GPtrArray *screenshots = NULL; AsReleaseList *releases = NULL; GPtrArray *releases_arr = NULL; GPtrArray *icons = NULL; AsBranding *branding = NULL; GPtrArray *requires_relations = NULL; GPtrArray *recommends_relations = NULL; GPtrArray *supports_relations = NULL; const char *title = NULL; const char *description = NULL; const char *metadata_license = NULL; const char *project_license = NULL; gboolean is_floss = FALSE; const char *project_group = NULL; const char *developer = NULL; const char *developer_id = NULL; const char *long_description = NULL; const char *project_url = NULL; g_autoptr (GPtrArray) as_search_tokens = NULL; g_autofree char *search_tokens = NULL; g_autoptr (GdkPaintable) icon_paintable = NULL; g_autoptr (GIcon) mini_icon = NULL; g_autoptr (GListStore) screenshot_paintables = NULL; g_autoptr (GListStore) screenshot_captions = NULL; g_autoptr (GdkPaintable) thumbnail_paintable = NULL; g_autoptr (GListStore) share_urls = NULL; g_autofree char *donation_url = NULL; g_autofree char *forge_url = NULL; g_autofree char *ratings_summary = NULL; g_autoptr (GListStore) version_history = NULL; const char *accent_color_light = NULL; const char *accent_color_dark = NULL; guint required_controls = 0; guint recommended_controls = 0; guint supported_controls = 0; gint min_display_length = 0; gint max_display_length = 0; gboolean is_mobile_friendly = FALSE; g_autoptr (AsContentRating) content_rating = NULL; GPtrArray *as_keywords = NULL; g_autoptr (GListStore) keywords = NULL; GPtrArray *as_categories = NULL; BzCategoryFlags categories = BZ_CATEGORY_FLAGS_NONE; g_autoptr (BzVerificationStatus) verification_status = NULL; g_return_val_if_fail (BZ_IS_ENTRY (entry), FALSE); g_return_val_if_fail (AS_IS_COMPONENT (component), FALSE); title = as_component_get_name (component); if (title == NULL) title = as_component_get_id (component); description = as_component_get_summary (component); metadata_license = as_component_get_metadata_license (component); project_license = as_component_get_project_license (component); is_floss = as_component_is_floss (component); project_group = as_component_get_project_group (component); project_url = as_component_get_url (component, AS_URL_KIND_HOMEPAGE); as_search_tokens = as_component_get_search_tokens (component); developer_obj = as_component_get_developer (component); if (developer_obj != NULL) { developer = as_developer_get_name (developer_obj); developer_id = as_developer_get_id (developer_obj); } long_description = as_component_get_description (component); screenshots = as_component_get_screenshots_all (component); if (screenshots != NULL) { screenshot_paintables = g_list_store_new (BZ_TYPE_ASYNC_TEXTURE); screenshot_captions = g_list_store_new (GTK_TYPE_STRING_OBJECT); for (guint i = 0; i < screenshots->len; i++) { AsScreenshot *screenshot = NULL; GPtrArray *images = NULL; const gchar *caption = NULL; g_autofree char *caption_str = NULL; g_autoptr (GdkPaintable) paintable = NULL; g_autofree char *cache_name = NULL; screenshot = g_ptr_array_index (screenshots, i); images = as_screenshot_get_images_all (screenshot); caption = as_screenshot_get_caption (screenshot); if (i == 0 && thumbnail_paintable == NULL) { thumbnail_paintable = find_screenshot (images, caption, FALSE, 400, 300, TRUE, module_dir, unique_id_checksum, "thumbnail", NULL); if (thumbnail_paintable == NULL) thumbnail_paintable = find_screenshot (images, caption, FALSE, 400, 300, FALSE, module_dir, unique_id_checksum, "thumbnail", NULL); } cache_name = g_strdup_printf ("screenshot_%u", i); paintable = find_screenshot (images, caption, TRUE, 0, 0, TRUE, module_dir, unique_id_checksum, cache_name, &caption_str); if (paintable == NULL) paintable = find_screenshot (images, caption, TRUE, 0, 0, FALSE, module_dir, unique_id_checksum, cache_name, &caption_str); if (paintable != NULL) { g_autoptr (GtkStringObject) caption_obj = NULL; g_list_store_append (screenshot_paintables, paintable); caption_obj = gtk_string_object_new (caption_str); g_list_store_append (screenshot_captions, caption_obj); } } } share_urls = g_list_store_new (BZ_TYPE_URL); if (kinds & BZ_ENTRY_KIND_APPLICATION && g_strcmp0 (remote_name, "flathub") == 0) { g_autofree char *flathub_url = NULL; g_autoptr (BzUrl) url = NULL; flathub_url = g_strdup_printf ("https://flathub.org/apps/%s", id); url = bz_url_new (); bz_url_set_name (url, C_ ("Project URL Type", "Flathub Page")); bz_url_set_url (url, flathub_url); bz_url_set_icon_name (url, "flathub-symbolic"); g_list_store_append (share_urls, url); } for (int e = AS_URL_KIND_UNKNOWN + 1; e < AS_URL_KIND_LAST; e++) { const char *url = NULL; url = as_component_get_url (component, e); if (url != NULL) { const char *enum_string = NULL; const char *icon_name = NULL; g_autoptr (BzUrl) share_url = NULL; switch (e) { case AS_URL_KIND_HOMEPAGE: enum_string = C_ ("Project URL Type", "Project Website"); icon_name = "globe-symbolic"; break; case AS_URL_KIND_BUGTRACKER: enum_string = C_ ("Project URL Type", "Issue Tracker"); icon_name = "computer-fail-symbolic"; break; case AS_URL_KIND_FAQ: enum_string = C_ ("Project URL Type", "FAQ"); icon_name = "help-faq-symbolic"; break; case AS_URL_KIND_HELP: enum_string = C_ ("Project URL Type", "Help"); icon_name = "help-browser-symbolic"; break; case AS_URL_KIND_DONATION: enum_string = C_ ("Project URL Type", "Donate"); icon_name = "heart-filled-symbolic"; g_clear_pointer (&donation_url, g_free); donation_url = g_strdup (url); break; case AS_URL_KIND_TRANSLATE: enum_string = C_ ("Project URL Type", "Translate"); icon_name = "translations-symbolic"; break; case AS_URL_KIND_CONTACT: enum_string = C_ ("Project URL Type", "Contact"); icon_name = "mail-send-symbolic"; break; case AS_URL_KIND_VCS_BROWSER: enum_string = C_ ("Project URL Type", "Source Code"); icon_name = "code-symbolic"; g_clear_pointer (&forge_url, g_free); forge_url = g_strdup (url); break; case AS_URL_KIND_CONTRIBUTE: enum_string = C_ ("Project URL Type", "Contribute"); icon_name = "system-users-symbolic"; break; default: break; } share_url = g_object_new ( BZ_TYPE_URL, "name", enum_string, "url", url, "icon-name", icon_name, NULL); g_list_store_append (share_urls, share_url); } } if (g_list_model_get_n_items (G_LIST_MODEL (share_urls)) == 0) g_clear_object (&share_urls); releases = as_component_load_releases (component, TRUE, error); if (releases == NULL) return FALSE; releases_arr = as_release_list_get_entries (releases); if (releases_arr != NULL) { version_history = g_list_store_new (BZ_TYPE_RELEASE); for (guint i = 0; i < releases_arr->len; i++) { AsRelease *as_release = NULL; const char *release_description = NULL; g_autoptr (BzRelease) release = NULL; as_release = g_ptr_array_index (releases_arr, i); release_description = as_release_get_description (as_release); release = g_object_new ( BZ_TYPE_RELEASE, "description", release_description, "timestamp", as_release_get_timestamp (as_release), "url", as_release_get_url (as_release, AS_RELEASE_URL_KIND_DETAILS), "version", as_release_get_version (as_release), NULL); g_list_store_append (version_history, release); } } icons = as_component_get_icons (component); if (icons != NULL) { g_autofree char *select = NULL; gboolean select_is_local = FALSE; int select_width = 0; int select_height = 0; for (guint i = 0; i < icons->len; i++) { AsIcon *icon = NULL; int width = 0; int height = 0; gboolean is_local = FALSE; icon = g_ptr_array_index (icons, i); width = as_icon_get_width (icon); height = as_icon_get_height (icon); is_local = as_icon_get_kind (icon) != AS_ICON_KIND_REMOTE; if (select == NULL || (is_local && !select_is_local) || (width > select_width && height > select_height)) { if (is_local) { const char *filename = NULL; g_autofree char *resolution = NULL; g_autofree char *path = NULL; filename = as_icon_get_filename (icon); if (filename == NULL) continue; resolution = g_strdup_printf ("%dx%d", width, height); path = g_build_filename ( appstream_dir, "icons", "flatpak", resolution, filename, NULL); if (!g_file_test (path, G_FILE_TEST_EXISTS)) continue; g_clear_pointer (&select, g_free); select = g_steal_pointer (&path); select_is_local = TRUE; select_width = width; select_height = height; } else { const char *url = NULL; url = as_icon_get_url (icon); if (url == NULL) continue; g_clear_pointer (&select, g_free); select = g_strdup (url); select_is_local = FALSE; select_width = width; select_height = height; } } } if (select != NULL) { g_autofree char *select_uri = NULL; g_autoptr (GFile) source = NULL; g_autoptr (GFile) cache_into = NULL; BzAsyncTexture *texture = NULL; if (select_is_local) select_uri = g_strdup_printf ("file://%s", select); else select_uri = g_steal_pointer (&select); source = g_file_new_for_uri (select_uri); cache_into = g_file_new_build_filename ( module_dir, unique_id_checksum, "icon-paintable.png", NULL); texture = bz_async_texture_new_lazy (source, cache_into); icon_paintable = GDK_PAINTABLE (texture); if (select_is_local) mini_icon = bz_load_mini_icon_sync (unique_id_checksum, select); } } branding = as_component_get_branding (component); if (branding != NULL) { accent_color_light = as_branding_get_color ( branding, AS_COLOR_KIND_PRIMARY, AS_COLOR_SCHEME_KIND_LIGHT); accent_color_dark = as_branding_get_color ( branding, AS_COLOR_KIND_PRIMARY, AS_COLOR_SCHEME_KIND_DARK); } content_rating = as_component_get_content_rating (component, "oars-1.1"); if (content_rating != NULL) { g_object_ref (content_rating); } else { content_rating = as_component_get_content_rating (component, "oars-1.0"); if (content_rating != NULL) g_object_ref (content_rating); } requires_relations = as_component_get_requires (component); recommends_relations = as_component_get_recommends (component); supports_relations = as_component_get_supports (component); if (requires_relations != NULL) { for (guint i = 0; i < requires_relations->len; i++) { AsRelation *relation = g_ptr_array_index (requires_relations, i); AsRelationItemKind item_kind = as_relation_get_item_kind (relation); if (item_kind == AS_RELATION_ITEM_KIND_CONTROL) { AsControlKind control_kind = as_relation_get_value_control_kind (relation); const char *control_str = as_control_kind_to_string (control_kind); if (control_str != NULL) required_controls |= parse_control_value (control_str); } else if (item_kind == AS_RELATION_ITEM_KIND_DISPLAY_LENGTH) { AsRelationCompare compare = as_relation_get_compare (relation); gint value = as_relation_get_value_int (relation); if (compare == AS_RELATION_COMPARE_GE) min_display_length = value; } } } if (recommends_relations != NULL) { for (guint i = 0; i < recommends_relations->len; i++) { AsRelation *relation = g_ptr_array_index (recommends_relations, i); AsRelationItemKind item_kind = as_relation_get_item_kind (relation); if (item_kind == AS_RELATION_ITEM_KIND_CONTROL) { AsControlKind control_kind = as_relation_get_value_control_kind (relation); const char *control_str = as_control_kind_to_string (control_kind); if (control_str != NULL) recommended_controls |= parse_control_value (control_str); } } } if (supports_relations != NULL) { for (guint i = 0; i < supports_relations->len; i++) { AsRelation *relation = g_ptr_array_index (supports_relations, i); AsRelationItemKind item_kind = as_relation_get_item_kind (relation); if (item_kind == AS_RELATION_ITEM_KIND_CONTROL) { AsControlKind control_kind = as_relation_get_value_control_kind (relation); const char *control_str = as_control_kind_to_string (control_kind); if (control_str != NULL) supported_controls |= parse_control_value (control_str); } else if (item_kind == AS_RELATION_ITEM_KIND_DISPLAY_LENGTH) { AsRelationCompare compare = as_relation_get_compare (relation); gint value = as_relation_get_value_int (relation); if (compare == AS_RELATION_COMPARE_LE) max_display_length = value; } } } is_mobile_friendly = calculate_is_mobile_friendly (required_controls, recommended_controls, supported_controls); if (as_search_tokens != NULL) { g_autoptr (GStrvBuilder) builder = NULL; g_auto (GStrv) strv = NULL; builder = g_strv_builder_new (); for (guint i = 0; i < as_search_tokens->len; i++) { const char *token = NULL; token = g_ptr_array_index (as_search_tokens, i); g_strv_builder_add (builder, token); } strv = g_strv_builder_end (builder); search_tokens = g_strjoinv (" ", strv); } as_keywords = as_component_get_keywords (component); if (as_keywords != NULL && as_keywords->len > 0) { keywords = g_list_store_new (GTK_TYPE_STRING_OBJECT); for (guint i = 0; i < as_keywords->len; i++) { const char *keyword = NULL; g_autoptr (GtkStringObject) keyword_obj = NULL; keyword = g_ptr_array_index (as_keywords, i); keyword_obj = gtk_string_object_new (keyword); g_list_store_append (keywords, keyword_obj); } } as_categories = as_component_get_categories (component); if (as_categories != NULL) { for (guint i = 0; i < as_categories->len; i++) { const char *name = NULL; name = g_ptr_array_index (as_categories, i); categories = bz_category_flags_add (categories, name); } } if (g_strcmp0 (remote_name, "flathub") == 0) { const char *verified_str = NULL; const char *method = NULL; const char *website = NULL; const char *login_name = NULL; const char *login_provider = NULL; const char *timestamp = NULL; const char *login_is_org_str = NULL; gboolean verified = FALSE; gboolean login_is_org = FALSE; GHashTable *custom_fields = NULL; custom_fields = as_component_get_custom (component); if (custom_fields != NULL) { verified_str = g_hash_table_lookup (custom_fields, "flathub::verification::verified"); method = g_hash_table_lookup (custom_fields, "flathub::verification::method"); website = g_hash_table_lookup (custom_fields, "flathub::verification::website"); login_name = g_hash_table_lookup (custom_fields, "flathub::verification::login_name"); login_provider = g_hash_table_lookup (custom_fields, "flathub::verification::login_provider"); timestamp = g_hash_table_lookup (custom_fields, "flathub::verification::timestamp"); login_is_org_str = g_hash_table_lookup (custom_fields, "flathub::verification::login_is_organization"); } verified = (verified_str != NULL && g_strcmp0 (verified_str, "true") == 0); login_is_org = (login_is_org_str != NULL && g_strcmp0 (login_is_org_str, "true") == 0); verification_status = bz_verification_status_new (); g_object_set (verification_status, "verified", verified, "method", method, "website", website, "login-name", login_name, "login-provider", login_provider, "timestamp", timestamp, "login-is-organization", login_is_org, NULL); } g_object_set ( entry, "title", title, "description", description, "long-description", long_description, "url", project_url, "search-tokens", search_tokens, "metadata-license", metadata_license, "project-license", project_license, "is-floss", is_floss, "project-group", project_group, "developer", developer, "developer-id", developer_id, "icon-paintable", icon_paintable, "mini-icon", mini_icon, "screenshot-paintables", screenshot_paintables, "screenshot-captions", screenshot_captions, "thumbnail-paintable", thumbnail_paintable, "share-urls", share_urls, "donation-url", donation_url, "forge-url", forge_url, "ratings-summary", ratings_summary, "version-history", version_history, "light-accent-color", accent_color_light, "dark-accent-color", accent_color_dark, "required-controls", required_controls, "recommended-controls", recommended_controls, "supported-controls", supported_controls, "min-display-length", min_display_length, "max-display-length", max_display_length, "is-mobile-friendly", is_mobile_friendly, "content-rating", content_rating, "keywords", keywords, "categories", categories, "verification-status", verification_status, NULL); return TRUE; } bazaar-orig-v0.7.14/src/bz-stats-dialog.c0000664000175000017500000001276115166123241017106 0ustar hasanhasan/* bz-stats-dialog.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include "bz-data-graph.h" #include "bz-stats-dialog.h" #include "bz-world-map.h" #include "bz-template-callbacks.h" struct _BzStatsDialog { AdwBreakpointBin parent_instance; GListModel *model; GListModel *country_model; int total_downloads; /* Template widgets */ BzDataGraph *graph; BzWorldMap *world_map; }; G_DEFINE_FINAL_TYPE (BzStatsDialog, bz_stats_dialog, ADW_TYPE_BREAKPOINT_BIN) enum { PROP_0, PROP_MODEL, PROP_COUNTRY_MODEL, PROP_TOTAL_DOWNLOADS, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bz_stats_dialog_dispose (GObject *object) { BzStatsDialog *self = BZ_STATS_DIALOG (object); g_clear_object (&self->model); g_clear_object (&self->country_model); G_OBJECT_CLASS (bz_stats_dialog_parent_class)->dispose (object); } static void bz_stats_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzStatsDialog *self = BZ_STATS_DIALOG (object); switch (prop_id) { case PROP_MODEL: g_value_set_object (value, self->model); break; case PROP_COUNTRY_MODEL: g_value_set_object (value, self->country_model); break; case PROP_TOTAL_DOWNLOADS: g_value_set_int (value, self->total_downloads); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_stats_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzStatsDialog *self = BZ_STATS_DIALOG (object); switch (prop_id) { case PROP_MODEL: g_clear_object (&self->model); self->model = g_value_dup_object (value); break; case PROP_COUNTRY_MODEL: g_clear_object (&self->country_model); self->country_model = g_value_dup_object (value); break; case PROP_TOTAL_DOWNLOADS: self->total_downloads = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static char * format_total_downloads (gpointer object, int value) { if (value <= 0) return g_strdup ("---"); if (value >= 1000000) /* Translators: M is the suffix for millions */ return g_strdup_printf (_("%.2fM Total Installs"), value / 1000000.0); else if (value >= 1000) /* Translators: K is the suffix for thousands*/ return g_strdup_printf (_("%.2fK Total Installs"), value / 1000.0); else return g_strdup_printf (_("%'d Total Installs"), value); } static void bz_stats_dialog_class_init (BzStatsDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_stats_dialog_dispose; object_class->get_property = bz_stats_dialog_get_property; object_class->set_property = bz_stats_dialog_set_property; props[PROP_MODEL] = g_param_spec_object ( "model", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE); props[PROP_COUNTRY_MODEL] = g_param_spec_object ( "country-model", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE); props[PROP_TOTAL_DOWNLOADS] = g_param_spec_int ( "total-downloads", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READWRITE); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_DATA_GRAPH); g_type_ensure (BZ_TYPE_WORLD_MAP); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-stats-dialog.ui"); bz_widget_class_bind_all_util_callbacks (widget_class); gtk_widget_class_bind_template_callback (widget_class, format_total_downloads); gtk_widget_class_bind_template_child (widget_class, BzStatsDialog, graph); gtk_widget_class_bind_template_child (widget_class, BzStatsDialog, world_map); } static void bz_stats_dialog_init (BzStatsDialog *self) { gtk_widget_init_template (GTK_WIDGET (self)); } AdwBreakpointBin * bz_stats_dialog_new (GListModel *model, GListModel *country_model, int total_downloads) { BzStatsDialog *stats_dialog = NULL; stats_dialog = g_object_new ( BZ_TYPE_STATS_DIALOG, "model", model, "country-model", country_model, "total-downloads", total_downloads, NULL); return ADW_BREAKPOINT_BIN (stats_dialog); } void bz_stats_dialog_animate_open (BzStatsDialog *self) { g_return_if_fail (BZ_IS_STATS_DIALOG (self)); bz_data_graph_animate_open (self->graph); } bazaar-orig-v0.7.14/src/bz-age-rating-dialog.c0000664000175000017500000010710715166123241017765 0ustar hasanhasan/* bz-age-rating-dialog.c * * Copyright 2021 Endless OS Foundation LLC * Copyright 2025 Alexander Vanhee * * Author: Philip Withnall (GNOME Software) * Adapted for Bazaar by Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include #include #include "bz-age-rating-attribute.h" #include "bz-age-rating-dialog.h" #include "bz-context-row.h" #include "bz-lozenge.h" struct _BzAgeRatingDialog { AdwDialog parent_instance; BzEntry *entry; BzLozenge *lozenge; GtkListBox *list; }; G_DEFINE_FINAL_TYPE (BzAgeRatingDialog, bz_age_rating_dialog, ADW_TYPE_DIALOG) enum { PROP_0, PROP_ENTRY, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { NULL }; typedef enum { BZ_AGE_RATING_GROUP_TYPE_DRUGS, BZ_AGE_RATING_GROUP_TYPE_LANGUAGE, BZ_AGE_RATING_GROUP_TYPE_MONEY, BZ_AGE_RATING_GROUP_TYPE_SEX, BZ_AGE_RATING_GROUP_TYPE_SOCIAL, BZ_AGE_RATING_GROUP_TYPE_VIOLENCE, } BzAgeRatingGroupType; #define BZ_AGE_RATING_GROUP_TYPE_COUNT (BZ_AGE_RATING_GROUP_TYPE_VIOLENCE + 1) typedef struct { GList *attributes; } BzAgeRatingGroup; typedef void (*AttributeCallback) (const gchar *attribute, AsContentRatingValue value, gpointer user_data); static const struct { const gchar *id; BzAgeRatingGroupType group_type; const gchar *title; const gchar *unknown_description; const gchar *icon_name; const gchar *icon_name_negative; } attribute_details[] = { { "violence-cartoon", BZ_AGE_RATING_GROUP_TYPE_VIOLENCE, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Cartoon Violence"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding cartoon violence"), "violence-symbolic", "violence-none-symbolic" }, { "violence-fantasy", BZ_AGE_RATING_GROUP_TYPE_VIOLENCE, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Fantasy Violence"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding fantasy violence"), "violence-symbolic", "violence-none-symbolic" }, { "violence-realistic", BZ_AGE_RATING_GROUP_TYPE_VIOLENCE, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Realistic Violence"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding realistic violence"), "violence-symbolic", "violence-none-symbolic" }, { "violence-bloodshed", BZ_AGE_RATING_GROUP_TYPE_VIOLENCE, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Violence Depicting Bloodshed"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding bloodshed"), "violence-symbolic", "violence-none-symbolic" }, { "violence-sexual", BZ_AGE_RATING_GROUP_TYPE_VIOLENCE, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Sexual Violence"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding sexual violence"), "violence-symbolic", "violence-none-symbolic" }, { "drugs-alcohol", BZ_AGE_RATING_GROUP_TYPE_DRUGS, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Alcohol"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding references to alcohol"), "alcohol-use-symbolic", "alcohol-use-none-symbolic" }, { "drugs-narcotics", BZ_AGE_RATING_GROUP_TYPE_DRUGS, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Narcotics"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding references to illicit drugs"), "drug-use-symbolic", "drug-use-none-symbolic" }, { "drugs-tobacco", BZ_AGE_RATING_GROUP_TYPE_DRUGS, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Tobacco"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding references to tobacco products"), "smoking-symbolic", "smoking-none-symbolic" }, { "sex-nudity", BZ_AGE_RATING_GROUP_TYPE_SEX, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Nudity"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding nudity of any sort"), "nudity-symbolic", "nudity-none-symbolic" }, { "sex-themes", BZ_AGE_RATING_GROUP_TYPE_SEX, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Sexual Themes"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding references to or depictions of sexual nature"), "nudity-symbolic", "nudity-none-symbolic" }, { "language-profanity", BZ_AGE_RATING_GROUP_TYPE_LANGUAGE, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Profanity"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding profanity of any kind"), "strong-language-symbolic", "strong-language-none-symbolic" }, { "language-humor", BZ_AGE_RATING_GROUP_TYPE_LANGUAGE, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Inappropriate Humor"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding inappropriate humor"), "strong-language-symbolic", "strong-language-none-symbolic" }, { "language-discrimination", BZ_AGE_RATING_GROUP_TYPE_SOCIAL, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Discrimination"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding discriminatory language of any kind"), "strong-language-symbolic", "strong-language-none-symbolic" }, { "money-advertising", BZ_AGE_RATING_GROUP_TYPE_MONEY, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Advertising"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding advertising of any kind"), "advertising-symbolic", "advertising-none-symbolic" }, { "money-gambling", BZ_AGE_RATING_GROUP_TYPE_MONEY, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Gambling"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding gambling of any kind"), "gambling-symbolic", "gambling-none-symbolic" }, { "money-purchasing", BZ_AGE_RATING_GROUP_TYPE_MONEY, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Purchasing"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding the ability to spend money"), "money-symbolic", "money-none-symbolic" }, { "social-chat", BZ_AGE_RATING_GROUP_TYPE_SOCIAL, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Chat Between Users"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding ways to chat with other users"), "messaging-symbolic", "messaging-none-symbolic" }, { "social-audio", BZ_AGE_RATING_GROUP_TYPE_SOCIAL, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Audio Chat Between Users"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding ways to talk with other users"), "audio-chat-symbolic", "audio-chat-none-symbolic" }, { "social-contacts", BZ_AGE_RATING_GROUP_TYPE_SOCIAL, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Contact Details"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding sharing of social network usernames or email addresses"), "contacts-symbolic", NULL }, { "social-info", BZ_AGE_RATING_GROUP_TYPE_SOCIAL, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Identifying Information"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding sharing of user information with third parties"), "social-info-symbolic", NULL }, { "social-location", BZ_AGE_RATING_GROUP_TYPE_SOCIAL, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Location Sharing"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding sharing of physical location with other users"), "location-services-active-symbolic", "location-services-disabled-symbolic" }, { "sex-prostitution", BZ_AGE_RATING_GROUP_TYPE_SEX, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Prostitution"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding references to prostitution"), "nudity-symbolic", "nudity-none-symbolic" }, { "sex-adultery", BZ_AGE_RATING_GROUP_TYPE_SEX, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Adultery"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding references to adultery"), "nudity-symbolic", "nudity-none-symbolic" }, { "sex-appearance", BZ_AGE_RATING_GROUP_TYPE_SEX, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Sexualized Characters"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding sexualized characters"), "nudity-symbolic", "nudity-none-symbolic" }, { "violence-worship", BZ_AGE_RATING_GROUP_TYPE_VIOLENCE, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Desecration"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding references to desecration"), "violence-symbolic", "violence-none-symbolic" }, { "violence-desecration", BZ_AGE_RATING_GROUP_TYPE_VIOLENCE, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Human Remains"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding visible dead human remains"), "human-remains-symbolic", NULL }, { "violence-slavery", BZ_AGE_RATING_GROUP_TYPE_VIOLENCE, /* TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ */ N_ ("Slavery"), /* TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ */ N_ ("No information regarding references to slavery"), "violence-symbolic", "violence-none-symbolic" }, }; static const gchar *content_rating_attribute_get_icon_name (const gchar *attribute, gboolean negative_version); static const gchar *content_rating_attribute_get_title (const gchar *attribute); static const gchar *content_rating_attribute_get_unknown_description (const gchar *attribute); static BzAgeRatingGroupType content_rating_attribute_get_group_type (const gchar *attribute); static const gchar *content_rating_group_get_description (BzAgeRatingGroupType group_type); static const gchar *content_rating_group_get_icon_name (BzAgeRatingGroupType group_type, gboolean negative_version); static const gchar *content_rating_group_get_title (BzAgeRatingGroupType group_type); static BzImportance content_rating_value_get_importance (AsContentRatingValue value); static gint attributes_compare (BzAgeRatingAttribute *attr1, BzAgeRatingAttribute *attr2); static void collect_attribute (const gchar *attribute, AsContentRatingValue value, gpointer user_data); static void process_attributes (AsContentRating *content_rating, gboolean show_worst_only, AttributeCallback callback, gpointer user_data); static gchar *format_age_short (AsContentRatingSystem system, guint age); static void update_lozenge (BzAgeRatingDialog *self, AsContentRating *content_rating); static void update_list (BzAgeRatingDialog *self); static void bz_age_rating_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzAgeRatingDialog *self = NULL; self = BZ_AGE_RATING_DIALOG (object); switch (prop_id) { case PROP_ENTRY: self->entry = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_age_rating_dialog_constructed (GObject *object) { BzAgeRatingDialog *self = NULL; self = BZ_AGE_RATING_DIALOG (object); G_OBJECT_CLASS (bz_age_rating_dialog_parent_class)->constructed (object); if (self->entry != NULL) update_list (self); } static void bz_age_rating_dialog_dispose (GObject *object) { BzAgeRatingDialog *self = NULL; self = BZ_AGE_RATING_DIALOG (object); g_clear_object (&self->entry); gtk_widget_dispose_template (GTK_WIDGET (self), BZ_TYPE_AGE_RATING_DIALOG); G_OBJECT_CLASS (bz_age_rating_dialog_parent_class)->dispose (object); } static void bz_age_rating_dialog_class_init (BzAgeRatingDialogClass *klass) { GObjectClass *object_class = NULL; GtkWidgetClass *widget_class = NULL; object_class = G_OBJECT_CLASS (klass); widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bz_age_rating_dialog_set_property; object_class->constructed = bz_age_rating_dialog_constructed; object_class->dispose = bz_age_rating_dialog_dispose; props[PROP_ENTRY] = g_param_spec_object ( "entry", NULL, NULL, BZ_TYPE_ENTRY, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_LOZENGE); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-age-rating-dialog.ui"); gtk_widget_class_bind_template_child (widget_class, BzAgeRatingDialog, lozenge); gtk_widget_class_bind_template_child (widget_class, BzAgeRatingDialog, list); } static void bz_age_rating_dialog_init (BzAgeRatingDialog *self) { gtk_widget_init_template (GTK_WIDGET (self)); } BzAgeRatingDialog * bz_age_rating_dialog_new (BzEntry *entry) { return g_object_new (BZ_TYPE_AGE_RATING_DIALOG, "entry", entry, NULL); } static const gchar * content_rating_attribute_get_icon_name (const gchar *attribute, gboolean negative_version) { for (gsize i = 0; i < G_N_ELEMENTS (attribute_details); i++) { if (g_str_equal (attribute, attribute_details[i].id)) { if (negative_version && attribute_details[i].icon_name_negative != NULL) return attribute_details[i].icon_name_negative; return attribute_details[i].icon_name; } } g_assert_not_reached (); } static const gchar * content_rating_attribute_get_title (const gchar *attribute) { for (gsize i = 0; i < G_N_ELEMENTS (attribute_details); i++) { if (g_str_equal (attribute, attribute_details[i].id)) return _ (attribute_details[i].title); } g_assert_not_reached (); } static const gchar * content_rating_attribute_get_unknown_description (const gchar *attribute) { for (gsize i = 0; i < G_N_ELEMENTS (attribute_details); i++) { if (g_str_equal (attribute, attribute_details[i].id)) return _ (attribute_details[i].unknown_description); } g_assert_not_reached (); } static BzAgeRatingGroupType content_rating_attribute_get_group_type (const gchar *attribute) { for (gsize i = 0; i < G_N_ELEMENTS (attribute_details); i++) { if (g_str_equal (attribute, attribute_details[i].id)) return attribute_details[i].group_type; } g_assert_not_reached (); } static const gchar * content_rating_group_get_description (BzAgeRatingGroupType group_type) { switch (group_type) { case BZ_AGE_RATING_GROUP_TYPE_DRUGS: return _ ("Does not include references to drugs"); case BZ_AGE_RATING_GROUP_TYPE_LANGUAGE: return _ ("Does not include swearing, profanity, and other kinds of strong language"); case BZ_AGE_RATING_GROUP_TYPE_MONEY: return _ ("Does not include ads or monetary transactions"); case BZ_AGE_RATING_GROUP_TYPE_SEX: return _ ("Does not include sex or nudity"); case BZ_AGE_RATING_GROUP_TYPE_SOCIAL: return _ ("Does not include uncontrolled chat functionality"); case BZ_AGE_RATING_GROUP_TYPE_VIOLENCE: return _ ("Does not include violence"); default: g_assert_not_reached (); } } static const gchar * content_rating_group_get_icon_name (BzAgeRatingGroupType group_type, gboolean negative_version) { switch (group_type) { case BZ_AGE_RATING_GROUP_TYPE_DRUGS: return negative_version ? "smoking-none-symbolic" : "smoking-symbolic"; case BZ_AGE_RATING_GROUP_TYPE_LANGUAGE: return negative_version ? "strong-language-none-symbolic" : "strong-language-symbolic"; case BZ_AGE_RATING_GROUP_TYPE_MONEY: return negative_version ? "money-none-symbolic" : "money-symbolic"; case BZ_AGE_RATING_GROUP_TYPE_SEX: return negative_version ? "nudity-none-symbolic" : "nudity-symbolic"; case BZ_AGE_RATING_GROUP_TYPE_SOCIAL: return negative_version ? "messaging-none-symbolic" : "messaging-symbolic"; case BZ_AGE_RATING_GROUP_TYPE_VIOLENCE: return negative_version ? "violence-none-symbolic" : "violence-symbolic"; default: g_assert_not_reached (); } } static const gchar * content_rating_group_get_title (BzAgeRatingGroupType group_type) { switch (group_type) { case BZ_AGE_RATING_GROUP_TYPE_DRUGS: return _ ("Drugs"); case BZ_AGE_RATING_GROUP_TYPE_LANGUAGE: return _ ("Strong Language"); case BZ_AGE_RATING_GROUP_TYPE_MONEY: return _ ("Money"); case BZ_AGE_RATING_GROUP_TYPE_SEX: return _ ("Nudity"); case BZ_AGE_RATING_GROUP_TYPE_SOCIAL: return _ ("Social"); case BZ_AGE_RATING_GROUP_TYPE_VIOLENCE: return _ ("Violence"); default: g_assert_not_reached (); } } static BzImportance content_rating_value_get_importance (AsContentRatingValue value) { switch (value) { case AS_CONTENT_RATING_VALUE_NONE: return BZ_IMPORTANCE_UNIMPORTANT; case AS_CONTENT_RATING_VALUE_UNKNOWN: return BZ_IMPORTANCE_NEUTRAL; case AS_CONTENT_RATING_VALUE_MILD: return BZ_IMPORTANCE_INFORMATION; case AS_CONTENT_RATING_VALUE_MODERATE: return BZ_IMPORTANCE_WARNING; case AS_CONTENT_RATING_VALUE_INTENSE: return BZ_IMPORTANCE_IMPORTANT; case AS_CONTENT_RATING_VALUE_LAST: default: return BZ_IMPORTANCE_NEUTRAL; } } static gint attributes_compare (BzAgeRatingAttribute *attr1, BzAgeRatingAttribute *attr2) { BzImportance importance1 = 0; BzImportance importance2 = 0; const gchar *id1 = NULL; const gchar *id2 = NULL; importance1 = bz_age_rating_attribute_get_importance (attr1); importance2 = bz_age_rating_attribute_get_importance (attr2); if (importance1 != importance2) { if (importance1 == BZ_IMPORTANCE_NEUTRAL && importance2 == BZ_IMPORTANCE_UNIMPORTANT) return -1; if (importance1 == BZ_IMPORTANCE_UNIMPORTANT && importance2 == BZ_IMPORTANCE_NEUTRAL) return 1; return importance2 - importance1; } else { id1 = bz_age_rating_attribute_get_id (attr1); id2 = bz_age_rating_attribute_get_id (attr2); return g_strcmp0 (id1, id2); } } static void collect_attribute (const gchar *attribute, AsContentRatingValue value, gpointer user_data) { BzAgeRatingGroup *groups = NULL; BzAgeRatingGroupType group_type = 0; BzImportance rating = 0; const gchar *icon_name = NULL; const gchar *title = NULL; const gchar *description = NULL; BzAgeRatingAttribute *attr = NULL; groups = user_data; group_type = content_rating_attribute_get_group_type (attribute); rating = content_rating_value_get_importance (value); icon_name = content_rating_attribute_get_icon_name (attribute, value == AS_CONTENT_RATING_VALUE_NONE); title = content_rating_attribute_get_title (attribute); if (value == AS_CONTENT_RATING_VALUE_UNKNOWN) description = content_rating_attribute_get_unknown_description (attribute); else description = as_content_rating_attribute_get_description (attribute, value); attr = g_object_new (BZ_TYPE_AGE_RATING_ATTRIBUTE, "id", attribute, "icon-name", icon_name, "importance", rating, "title", title, "description", description, NULL); groups[group_type].attributes = g_list_insert_sorted (groups[group_type].attributes, attr, (GCompareFunc) attributes_compare); } static AsContentRatingValue get_rating_value (AsContentRating *content_rating, const gchar *id) { if (content_rating == NULL) return AS_CONTENT_RATING_VALUE_UNKNOWN; return as_content_rating_get_value (content_rating, id); } static void process_attributes (AsContentRating *content_rating, gboolean show_worst_only, AttributeCallback callback, gpointer user_data) { g_autofree const gchar **rating_ids = NULL; AsContentRatingValue value_bad = AS_CONTENT_RATING_VALUE_NONE; guint age_bad = 0; guint rating_age = 0; AsContentRatingValue rating_value = 0; const gchar *const violence_group[] = { "violence-bloodshed", "violence-realistic", "violence-fantasy", "violence-cartoon", NULL }; const gchar *const social_group[] = { "social-audio", "social-chat", "social-contacts", "social-info", NULL }; const gchar *const coalesce_groups[] = { "sex-themes", "sex-homosexuality", NULL }; rating_ids = as_content_rating_get_all_rating_ids (); for (gsize i = 0; rating_ids[i] != NULL; i++) { rating_value = get_rating_value (content_rating, rating_ids[i]); rating_age = as_content_rating_attribute_to_csm_age (rating_ids[i], rating_value); if (rating_age > age_bad) age_bad = rating_age; if (rating_value > value_bad) value_bad = rating_value; } if (show_worst_only && (value_bad == AS_CONTENT_RATING_VALUE_NONE || age_bad == 0)) { callback (NULL, AS_CONTENT_RATING_VALUE_UNKNOWN, user_data); return; } for (gsize i = 0; rating_ids[i] != NULL; i++) { if (g_strv_contains (violence_group, rating_ids[i]) || g_strv_contains (social_group, rating_ids[i])) continue; rating_value = get_rating_value (content_rating, rating_ids[i]); rating_age = as_content_rating_attribute_to_csm_age (rating_ids[i], rating_value); if (show_worst_only && rating_age < age_bad) continue; if (g_strv_contains (coalesce_groups + 1, rating_ids[i]) && as_content_rating_attribute_to_csm_age (coalesce_groups[0], get_rating_value (content_rating, coalesce_groups[0])) >= rating_age) continue; callback (rating_ids[i], rating_value, user_data); } for (gsize i = 0; violence_group[i] != NULL; i++) { rating_value = get_rating_value (content_rating, violence_group[i]); rating_age = as_content_rating_attribute_to_csm_age (violence_group[i], rating_value); if (show_worst_only && rating_age < age_bad) continue; callback (violence_group[i], rating_value, user_data); } for (gsize i = 0; social_group[i] != NULL; i++) { rating_value = get_rating_value (content_rating, social_group[i]); rating_age = as_content_rating_attribute_to_csm_age (social_group[i], rating_value); if (show_worst_only && rating_age < age_bad) continue; callback (social_group[i], rating_value, user_data); } } static gchar * format_age_short (AsContentRatingSystem system, guint age) { if (age < 3) age = 3; /* Translators: Age rating format, e.g. "12+" for ages 12 and up */ return g_strdup_printf (_ ("%d+"), age); } static void update_lozenge (BzAgeRatingDialog *self, AsContentRating *content_rating) { const gchar *locale = NULL; AsContentRatingSystem system = 0; guint age = G_MAXUINT; g_autofree gchar *age_text = NULL; g_autofree gchar *title_text = NULL; BzImportance importance = BZ_IMPORTANCE_NEUTRAL; gboolean is_unknown = FALSE; locale = setlocale (LC_MESSAGES, NULL); system = as_content_rating_system_from_locale (locale); if (content_rating != NULL) age = as_content_rating_get_minimum_age (content_rating); if (age != G_MAXUINT) age_text = format_age_short (system, age); if (content_rating != NULL && age_text == NULL && age == 0) age_text = g_strdup (C_ ("Age rating", "All")); if (age_text == NULL || (content_rating != NULL && g_strcmp0 (as_content_rating_get_kind (content_rating), "oars-1.0") != 0 && g_strcmp0 (as_content_rating_get_kind (content_rating), "oars-1.1") != 0)) { g_clear_pointer (&age_text, g_free); age_text = g_strdup ("?"); importance = BZ_IMPORTANCE_NEUTRAL; } else { if (age >= 18) importance = BZ_IMPORTANCE_IMPORTANT; else if (age >= 15) importance = BZ_IMPORTANCE_WARNING; else if (age >= 12) importance = BZ_IMPORTANCE_INFORMATION; else importance = BZ_IMPORTANCE_NEUTRAL; } if (self->entry == NULL) { title_text = g_strdup (_ ("Age Rating")); } else { is_unknown = (content_rating == NULL || (g_strcmp0 (as_content_rating_get_kind (content_rating), "oars-1.0") != 0 && g_strcmp0 (as_content_rating_get_kind (content_rating), "oars-1.1") != 0) || age == G_MAXUINT); if (is_unknown) { title_text = g_strdup_printf (_ ("%s has an unknown age rating"), bz_entry_get_title (self->entry)); } else { if (age <= 3) title_text = g_strdup_printf (_ ("%s is suitable for everyone"), bz_entry_get_title (self->entry)); else if (age <= 5) title_text = g_strdup_printf (_ ("%s is suitable for young children"), bz_entry_get_title (self->entry)); else if (age <= 12) title_text = g_strdup_printf (_ ("%s is suitable for children"), bz_entry_get_title (self->entry)); else if (age <= 18) title_text = g_strdup_printf (_ ("%s is suitable for teenagers"), bz_entry_get_title (self->entry)); else if (age < G_MAXUINT) title_text = g_strdup_printf (_ ("%s is suitable for adults"), bz_entry_get_title (self->entry)); else title_text = g_strdup_printf (_ ("%s is suitable for %s"), bz_entry_get_title (self->entry), age_text); } } bz_lozenge_set_label (self->lozenge, age_text); bz_lozenge_set_title (self->lozenge, title_text); bz_lozenge_set_importance (self->lozenge, importance); } static void update_list (BzAgeRatingDialog *self) { AsContentRating *content_rating = NULL; BzAgeRatingGroup groups[BZ_AGE_RATING_GROUP_TYPE_COUNT] = { 0 }; guint attr_count = 0; BzAgeRatingAttribute *attr = NULL; AdwActionRow *row = NULL; BzImportance max_importance = 0; BzImportance attr_importance = 0; BzImportance row_importances[BZ_AGE_RATING_GROUP_TYPE_COUNT] = { 0 }; GtkWidget *rows[BZ_AGE_RATING_GROUP_TYPE_COUNT] = { NULL }; const gchar *group_icon = NULL; const gchar *group_title = NULL; const gchar *group_description = NULL; const gchar *attr_description = NULL; g_autofree gchar *description = NULL; g_autoptr (GList) l = NULL; g_autofree gchar *tmp = NULL; content_rating = bz_entry_get_content_rating (self->entry); update_lozenge (self, content_rating); process_attributes (content_rating, FALSE, collect_attribute, groups); for (gsize i = 0; i < BZ_AGE_RATING_GROUP_TYPE_COUNT; i++) { if (groups[i].attributes == NULL) continue; attr_count = g_list_length (groups[i].attributes); row = NULL; if (attr_count == 1) { attr = (BzAgeRatingAttribute *) groups[i].attributes->data; row = bz_context_row_new (bz_age_rating_attribute_get_icon_name (attr), bz_age_rating_attribute_get_importance (attr), bz_age_rating_attribute_get_title (attr), bz_age_rating_attribute_get_description (attr)); row_importances[i] = bz_age_rating_attribute_get_importance (attr); } else { max_importance = BZ_IMPORTANCE_UNIMPORTANT; for (l = groups[i].attributes; l != NULL; l = l->next) { attr = (BzAgeRatingAttribute *) l->data; attr_importance = bz_age_rating_attribute_get_importance (attr); if (attr_importance > max_importance) max_importance = attr_importance; } if (max_importance == BZ_IMPORTANCE_UNIMPORTANT) { group_icon = content_rating_group_get_icon_name (i, TRUE); group_title = content_rating_group_get_title (i); group_description = content_rating_group_get_description (i); row = bz_context_row_new (group_icon, BZ_IMPORTANCE_UNIMPORTANT, group_title, group_description); } else { group_icon = content_rating_group_get_icon_name (i, FALSE); group_title = content_rating_group_get_title (i); g_clear_pointer (&description, g_free); for (l = groups[i].attributes; l != NULL; l = l->next) { attr = (BzAgeRatingAttribute *) l->data; attr_importance = bz_age_rating_attribute_get_importance (attr); if (attr_importance == BZ_IMPORTANCE_UNIMPORTANT) continue; attr_description = bz_age_rating_attribute_get_description (attr); if (description == NULL) { description = g_strdup (attr_description); } else { tmp = g_strdup_printf (_ ("%s • %s"), description, attr_description); g_clear_pointer (&description, g_free); description = g_steal_pointer (&tmp); } } row = bz_context_row_new (group_icon, max_importance, group_title, description); } row_importances[i] = max_importance; } rows[i] = GTK_WIDGET (row); g_list_free_full (g_steal_pointer (&groups[i].attributes), g_object_unref); } for (gint level = BZ_IMPORTANCE_IMPORTANT; level >= BZ_IMPORTANCE_UNIMPORTANT; level--) { for (gsize i = 0; i < BZ_AGE_RATING_GROUP_TYPE_COUNT; i++) { if (rows[i] == NULL || row_importances[i] != level) continue; gtk_list_box_append (self->list, rows[i]); } } } bazaar-orig-v0.7.14/src/bz-entry-group-util.h0000664000175000017500000000212315166123241017755 0ustar hasanhasan/* bz-entry-group-util.h * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry-group.h" #include "bz-entry.h" #include G_BEGIN_DECLS BzEntry * bz_entry_group_find_entry (BzEntryGroup *group, gboolean (*test) (BzEntry *entry), GtkWidget *window, GError **error); G_END_DECLS bazaar-orig-v0.7.14/src/bz-flatpak-instance.h0000664000175000017500000000331015166123241017732 0ustar hasanhasan/* bz-flatpak-instance.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_FLATPAK_ERROR (bz_flatpak_error_quark ()) GQuark bz_flatpak_error_quark (void); typedef enum { BZ_FLATPAK_ERROR_CANNOT_INITIALIZE = 0, BZ_FLATPAK_ERROR_LOCAL_SYNCHRONIZATION_FAILURE, BZ_FLATPAK_ERROR_REMOTE_SYNCHRONIZATION_FAILURE, BZ_FLATPAK_ERROR_TRANSACTION_FAILURE, BZ_FLATPAK_ERROR_IO_MISBEHAVIOR, BZ_FLATPAK_ERROR_APPSTREAM_FAILURE, BZ_FLATPAK_ERROR_GLYCIN_FAILURE, } BzFlatpakError; #define BZ_TYPE_FLATPAK_INSTANCE (bz_flatpak_instance_get_type ()) G_DECLARE_FINAL_TYPE (BzFlatpakInstance, bz_flatpak_instance, BZ, FLATPAK_INSTANCE, GObject) DexFuture * bz_flatpak_instance_new (void); DexFuture * bz_flatpak_instance_has_flathub (BzFlatpakInstance *self, GCancellable *cancellable); DexFuture * bz_flatpak_instance_ensure_has_flathub (BzFlatpakInstance *self, GCancellable *cancellable); G_END_DECLS bazaar-orig-v0.7.14/src/bz-entry-group-util.c0000664000175000017500000001003715166123241017753 0ustar hasanhasan/* bz-entry-group-util.c * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include #include "bz-entry-group-util.h" #include "bz-error.h" BzEntry * bz_entry_group_find_entry (BzEntryGroup *group, gboolean (*test) (BzEntry *entry), GtkWidget *window, GError **error) { g_autoptr (GListModel) model = NULL; guint n_items = 0; g_autoptr (GPtrArray) candidates = NULL; g_return_val_if_fail (BZ_IS_ENTRY_GROUP (group), NULL); model = dex_await_object (bz_entry_group_dup_all_into_store (group), error); if (model == NULL) return NULL; n_items = g_list_model_get_n_items (model); candidates = g_ptr_array_new_with_free_func (g_object_unref); for (guint i = 0; i < n_items; i++) { g_autoptr (BzEntry) entry = NULL; entry = g_list_model_get_item (model, i); if (bz_entry_is_installed (entry) && (test == NULL || test (entry))) g_ptr_array_add (candidates, g_steal_pointer (&entry)); } if (candidates->len == 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "BUG: No entry candidates satisfied this test condition"); return NULL; } else if (candidates->len == 1) return g_ptr_array_steal_index_fast (candidates, 0); else if (window != NULL) { AdwDialog *alert = NULL; g_autofree char *response = NULL; alert = adw_alert_dialog_new (NULL, NULL); adw_alert_dialog_set_prefer_wide_layout (ADW_ALERT_DIALOG (alert), TRUE); adw_alert_dialog_format_heading ( ADW_ALERT_DIALOG (alert), _ ("Choose an Installation")); adw_alert_dialog_format_body ( ADW_ALERT_DIALOG (alert), _ ("You have multiple versions of this app installed. Which " "one would you like to proceed with?")); adw_alert_dialog_add_responses ( ADW_ALERT_DIALOG (alert), "cancel", _ ("Cancel"), NULL); adw_alert_dialog_set_close_response (ADW_ALERT_DIALOG (alert), "cancel"); adw_alert_dialog_set_response_appearance ( ADW_ALERT_DIALOG (alert), "cancel", ADW_RESPONSE_DESTRUCTIVE); for (guint i = 0; i < candidates->len; i++) { BzEntry *entry = NULL; const char *unique_id = NULL; entry = g_ptr_array_index (candidates, i); unique_id = bz_entry_get_unique_id (entry); adw_alert_dialog_add_responses ( ADW_ALERT_DIALOG (alert), unique_id, unique_id, NULL); if (i == 0) adw_alert_dialog_set_default_response (ADW_ALERT_DIALOG (alert), unique_id); } adw_dialog_present (alert, GTK_WIDGET (window)); response = dex_await_string ( bz_make_alert_dialog_future (ADW_ALERT_DIALOG (alert)), NULL); if (response != NULL) { for (guint i = 0; i < candidates->len; i++) { BzEntry *entry = NULL; const char *unique_id = NULL; entry = g_ptr_array_index (candidates, i); unique_id = bz_entry_get_unique_id (entry); if (g_strcmp0 (unique_id, response) == 0) return g_object_ref (entry); } } } return NULL; } bazaar-orig-v0.7.14/src/internal-config-schema.xml0000664000175000017500000000032115166123241020762 0ustar hasanhasan bazaar-orig-v0.7.14/src/bz-data-graph.c0000664000175000017500000011335015166123241016517 0ustar hasanhasan/* bz-data-graph.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include "bz-data-graph.h" #include "bz-data-point.h" #include #define LABEL_MARGIN 75.0 #define LABEL_MARGIN_RIGHT 35.0 #define TICK_LENGTH 5.0 struct _BzDataGraph { GtkWidget parent_instance; GListModel *model; char *independent_axis_label; char *dependent_axis_label; char *tooltip_prefix; int independent_decimals; int dependent_decimals; double transition_progress; double rounded_axis_max; AdwStyleManager *style_manager; GskPath *path; GskPathMeasure *path_measure; GskRenderNode *fg; gboolean wants_animate_open; GtkEventController *motion; double motion_x; double motion_y; GtkGesture *gesture; GtkWidget *tooltip_box; GtkWidget *tooltip_label1; GtkWidget *tooltip_prefix_label; GtkWidget *tooltip_label2; }; G_DEFINE_FINAL_TYPE (BzDataGraph, bz_data_graph, GTK_TYPE_WIDGET) enum { PROP_0, PROP_MODEL, PROP_INDEPENDENT_AXIS_LABEL, PROP_DEPENDENT_AXIS_LABEL, PROP_TOOLTIP_PREFIX, PROP_INDEPENDENT_DECIMALS, PROP_DEPENDENT_DECIMALS, PROP_TRANSITION_PROGRESS, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void items_changed (GListModel *model, guint position, guint removed, guint added, BzDataGraph *self); static void refresh_path (BzDataGraph *self, double width, double height); static double calculate_axis_tick_value (double value, gboolean round_up); static void on_style_changed (BzDataGraph *self, GParamSpec *pspec, AdwStyleManager *style_manager); static void bz_data_graph_dispose (GObject *object) { BzDataGraph *self = BZ_DATA_GRAPH (object); if (self->model != NULL) g_signal_handlers_disconnect_by_func ( self->model, items_changed, self); g_signal_handlers_disconnect_by_func (self->style_manager, on_style_changed, self); g_clear_object (&self->model); g_clear_pointer (&self->independent_axis_label, g_free); g_clear_pointer (&self->dependent_axis_label, g_free); g_clear_pointer (&self->tooltip_prefix, g_free); g_clear_pointer (&self->path, gsk_path_unref); g_clear_pointer (&self->path_measure, gsk_path_measure_unref); g_clear_pointer (&self->fg, gsk_render_node_unref); if (self->tooltip_box != NULL) gtk_widget_unparent (self->tooltip_box); G_OBJECT_CLASS (bz_data_graph_parent_class)->dispose (object); } static void bz_data_graph_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzDataGraph *self = BZ_DATA_GRAPH (object); switch (prop_id) { case PROP_MODEL: g_value_set_object (value, bz_data_graph_get_model (self)); break; case PROP_INDEPENDENT_AXIS_LABEL: g_value_set_string (value, bz_data_graph_get_independent_axis_label (self)); break; case PROP_DEPENDENT_AXIS_LABEL: g_value_set_string (value, bz_data_graph_get_dependent_axis_label (self)); break; case PROP_TOOLTIP_PREFIX: g_value_set_string (value, bz_data_graph_get_tooltip_prefix (self)); break; case PROP_INDEPENDENT_DECIMALS: g_value_set_int (value, bz_data_graph_get_independent_decimals (self)); break; case PROP_DEPENDENT_DECIMALS: g_value_set_int (value, bz_data_graph_get_dependent_decimals (self)); break; case PROP_TRANSITION_PROGRESS: g_value_set_double (value, bz_data_graph_get_transition_progress (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_data_graph_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzDataGraph *self = BZ_DATA_GRAPH (object); switch (prop_id) { case PROP_MODEL: bz_data_graph_set_model (self, g_value_get_object (value)); break; case PROP_INDEPENDENT_AXIS_LABEL: bz_data_graph_set_independent_axis_label (self, g_value_get_string (value)); break; case PROP_DEPENDENT_AXIS_LABEL: bz_data_graph_set_dependent_axis_label (self, g_value_get_string (value)); break; case PROP_TOOLTIP_PREFIX: bz_data_graph_set_tooltip_prefix (self, g_value_get_string (value)); break; case PROP_INDEPENDENT_DECIMALS: bz_data_graph_set_independent_decimals (self, g_value_get_int (value)); break; case PROP_DEPENDENT_DECIMALS: bz_data_graph_set_dependent_decimals (self, g_value_get_int (value)); break; case PROP_TRANSITION_PROGRESS: bz_data_graph_set_transition_progress (self, g_value_get_double (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_data_graph_size_allocate (GtkWidget *widget, int width, int height, int baseline) { BzDataGraph *self = BZ_DATA_GRAPH (widget); refresh_path (self, (double) width - LABEL_MARGIN - LABEL_MARGIN_RIGHT, (double) height - LABEL_MARGIN); gtk_widget_queue_draw (widget); } static void on_style_changed (BzDataGraph *self, GParamSpec *pspec, AdwStyleManager *style_manager) { gtk_widget_queue_draw (GTK_WIDGET (self)); } static void bz_data_graph_snapshot (GtkWidget *widget, GtkSnapshot *snapshot) { BzDataGraph *self = BZ_DATA_GRAPH (widget); double widget_width = 0.0; double widget_height = 0.0; AdwStyleManager *style_manager = NULL; g_autoptr (GdkRGBA) accent_color = NULL; GdkRGBA widget_color = { 0 }; g_autoptr (GskPath) transitioning = NULL; g_autoptr (GskStroke) stroke = NULL; if (self->path == NULL) return; widget_width = gtk_widget_get_width (widget); widget_height = gtk_widget_get_height (widget); style_manager = adw_style_manager_get_default (); accent_color = adw_style_manager_get_accent_color_rgba (style_manager); gtk_widget_get_color (widget, &widget_color); if (self->transition_progress > 0.0 && self->transition_progress < 1.0) { GskPathPoint point0 = { 0 }; double path_distance = 0.0; GskPathPoint point1 = { 0 }; g_autoptr (GskPathBuilder) builder = NULL; gsk_path_get_start_point (self->path, &point0); path_distance = gsk_path_measure_get_length (self->path_measure) * self->transition_progress; gsk_path_measure_get_point (self->path_measure, path_distance, &point1); builder = gsk_path_builder_new (); gsk_path_builder_add_segment (builder, self->path, &point0, &point1); transitioning = gsk_path_builder_to_path (builder); } stroke = gsk_stroke_new (3.0); gsk_stroke_set_line_cap (stroke, GSK_LINE_CAP_ROUND); gtk_snapshot_save (snapshot); gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (LABEL_MARGIN, 0.0)); if (self->fg != NULL) { graphene_rect_t bounds = { 0 }; gsk_render_node_get_bounds (self->fg, &bounds); gtk_snapshot_push_mask (snapshot, GSK_MASK_MODE_ALPHA); gtk_snapshot_append_node (snapshot, self->fg); gtk_snapshot_pop (snapshot); gtk_snapshot_append_color (snapshot, &widget_color, &bounds); gtk_snapshot_pop (snapshot); } if (self->transition_progress > 0.0) { g_autoptr (GskPathBuilder) builder = NULL; GskPathPoint point0 = { 0 }; GskPathPoint point1 = { 0 }; graphene_point_t start_position = { 0 }; graphene_point_t end_position = { 0 }; g_autoptr (GskPath) path = NULL; const GskColorStop gradient_stops[] = { { 0.0, { .red = accent_color->red, .green = accent_color->green, .blue = accent_color->blue, .alpha = 0.75, }, }, { 1.0, { .red = accent_color->red, .green = accent_color->green, .blue = accent_color->blue, .alpha = 0.0, }, }, }; const GskColorStop hfadeout_mask_stops[] = { { 0.0, { .red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0, }, }, { 0.75, { .red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0, }, }, { 1.0, { .red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 0.0, }, }, }; gtk_snapshot_append_stroke ( snapshot, transitioning != NULL ? transitioning : self->path, stroke, accent_color); /* Gradient under the graph line */ builder = gsk_path_builder_new (); gsk_path_get_start_point ( transitioning != NULL ? transitioning : self->path, &point0); gsk_path_point_get_position ( &point0, transitioning != NULL ? transitioning : self->path, &start_position); gsk_path_get_end_point ( transitioning != NULL ? transitioning : self->path, &point1); gsk_path_point_get_position ( &point1, transitioning != NULL ? transitioning : self->path, &end_position); gsk_path_builder_move_to (builder, start_position.x, start_position.y); gsk_path_builder_add_segment ( builder, transitioning != NULL ? transitioning : self->path, &point0, &point1); gsk_path_builder_move_to (builder, end_position.x, end_position.y); /* close the loop for `gtk_snapshot_push_fill` */ gsk_path_builder_line_to (builder, end_position.x, widget_height - LABEL_MARGIN); gsk_path_builder_line_to (builder, start_position.x, widget_height - LABEL_MARGIN); gsk_path_builder_line_to (builder, start_position.x, start_position.y); path = gsk_path_builder_to_path (builder); gtk_snapshot_push_fill ( snapshot, path, GSK_FILL_RULE_WINDING); gtk_snapshot_push_mask (snapshot, GSK_MASK_MODE_ALPHA); gtk_snapshot_append_linear_gradient ( snapshot, &GRAPHENE_RECT_INIT ( 0.0, 0.0, end_position.x, widget_height - LABEL_MARGIN), &GRAPHENE_POINT_INIT (0.0, 0.0), &GRAPHENE_POINT_INIT (end_position.x, 0.0), hfadeout_mask_stops, G_N_ELEMENTS (hfadeout_mask_stops)); gtk_snapshot_pop (snapshot); /* Push Mask (mask) */ gtk_snapshot_append_linear_gradient ( snapshot, &GRAPHENE_RECT_INIT ( 0.0, 0.0, end_position.x, widget_height - LABEL_MARGIN), &GRAPHENE_POINT_INIT (0.0, 0.0), &GRAPHENE_POINT_INIT (0.0, widget_height - LABEL_MARGIN), gradient_stops, G_N_ELEMENTS (gradient_stops)); gtk_snapshot_pop (snapshot); /* Push Mask (image) */ gtk_snapshot_pop (snapshot); /* Push Fill */ } gtk_snapshot_restore (snapshot); if (self->motion_x >= LABEL_MARGIN && self->motion_y >= 0.0 && self->motion_x < widget_width - LABEL_MARGIN_RIGHT && self->motion_y < widget_height - LABEL_MARGIN) { guint n_items = 0; guint hovered_idx = 0; g_autoptr (BzDataPoint) point = NULL; g_autoptr (GskStroke) crosshair_stroke = NULL; double graph_height = 0.0; double graph_width = 0.0; double fraction = 0.0; double point_x = 0.0; double point_y = 0.0; GskRoundedRect rounded_rect = { { { 0 } } }; GdkRGBA line_color = { 0 }; double card_x = 0.0; double card_y = 0.0; double rounded_axis_max = 0.0; const char *prefix = NULL; g_autofree char *line2_text = NULL; GtkRequisition natural_size = { 0 }; n_items = g_list_model_get_n_items (self->model); graph_width = widget_width - LABEL_MARGIN - LABEL_MARGIN_RIGHT; fraction = (self->motion_x - LABEL_MARGIN) / graph_width; hovered_idx = floor ((double) n_items * fraction); if (hovered_idx >= n_items) hovered_idx = n_items - 1; point = g_list_model_get_item (self->model, hovered_idx); if (self->rounded_axis_max > 0.0) rounded_axis_max = self->rounded_axis_max; else { double max_dependent = 0.0; for (guint i = 0; i < n_items; i++) { g_autoptr (BzDataPoint) p = g_list_model_get_item (self->model, i); double dep = bz_data_point_get_dependent (p); if (i == 0 || dep > max_dependent) max_dependent = dep; } rounded_axis_max = calculate_axis_tick_value (max_dependent, TRUE); } graph_height = widget_height - LABEL_MARGIN; point_x = ((double) hovered_idx / (double) (n_items - 1)) * graph_width + LABEL_MARGIN; point_y = (1.0 - bz_data_point_get_dependent (point) / rounded_axis_max) * graph_height; line_color = widget_color; line_color.alpha = 0.5; crosshair_stroke = gsk_stroke_new (1.0); #define APPEND_LINE(x0, y0, x1, y1, color) \ G_STMT_START \ { \ g_autoptr (GskPathBuilder) builder = NULL; \ g_autoptr (GskPath) path = NULL; \ \ builder = gsk_path_builder_new (); \ gsk_path_builder_move_to (builder, (x0), (y0)); \ gsk_path_builder_line_to (builder, (x1), (y1)); \ \ path = gsk_path_builder_to_path (builder); \ gtk_snapshot_append_stroke (snapshot, path, crosshair_stroke, (color)); \ } \ G_STMT_END APPEND_LINE (self->motion_x, 0.0, self->motion_x, widget_height - LABEL_MARGIN, &line_color); #undef APPEND_LINE gsk_rounded_rect_init_from_rect ( &rounded_rect, &GRAPHENE_RECT_INIT (point_x - 4.0, point_y - 4.0, 8.0, 8.0), 4.0); gtk_snapshot_push_rounded_clip (snapshot, &rounded_rect); gtk_snapshot_append_color (snapshot, accent_color, &rounded_rect.bounds); gtk_snapshot_pop (snapshot); gtk_label_set_text (GTK_LABEL (self->tooltip_label1), bz_data_point_get_label (point)); prefix = self->tooltip_prefix != NULL ? self->tooltip_prefix : ""; gtk_label_set_text (GTK_LABEL (self->tooltip_prefix_label), prefix); line2_text = g_strdup_printf ("%'.0f", bz_data_point_get_dependent (point)); gtk_label_set_text (GTK_LABEL (self->tooltip_label2), line2_text); gtk_widget_get_preferred_size (self->tooltip_box, NULL, &natural_size); gtk_widget_allocate (self->tooltip_box, natural_size.width, natural_size.height, -1, NULL); if (self->motion_x > widget_width / 2.0) card_x = self->motion_x - natural_size.width - 10.0; else card_x = self->motion_x + 10.0; card_y = self->motion_y + 10.0; gtk_snapshot_save (snapshot); gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (card_x, card_y)); gtk_widget_snapshot_child (widget, self->tooltip_box, snapshot); gtk_snapshot_restore (snapshot); } if (self->wants_animate_open) { AdwAnimationTarget *transition_target = NULL; AdwSpringParams *transition_spring = NULL; g_autoptr (AdwAnimation) transition = NULL; self->wants_animate_open = FALSE; transition_target = adw_property_animation_target_new (G_OBJECT (self), "transition-progress"); transition_spring = adw_spring_params_new (1.0, 1.0, 80.0); transition = adw_spring_animation_new (GTK_WIDGET (self), 0.0, 1.0, transition_spring, transition_target); adw_spring_animation_set_epsilon (ADW_SPRING_ANIMATION (transition), 0.000001); adw_animation_play (transition); } } static void bz_data_graph_class_init (BzDataGraphClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_data_graph_dispose; object_class->get_property = bz_data_graph_get_property; object_class->set_property = bz_data_graph_set_property; props[PROP_MODEL] = g_param_spec_object ( "model", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_INDEPENDENT_AXIS_LABEL] = g_param_spec_string ( "independent-axis-label", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_DEPENDENT_AXIS_LABEL] = g_param_spec_string ( "dependent-axis-label", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_TOOLTIP_PREFIX] = g_param_spec_string ( "tooltip-prefix", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_INDEPENDENT_DECIMALS] = g_param_spec_int ( "independent-decimals", NULL, NULL, -1, 4, (int) 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_DEPENDENT_DECIMALS] = g_param_spec_int ( "dependent-decimals", NULL, NULL, -1, 4, (int) 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_TRANSITION_PROGRESS] = g_param_spec_double ( "transition-progress", NULL, NULL, 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); widget_class->size_allocate = bz_data_graph_size_allocate; widget_class->snapshot = bz_data_graph_snapshot; } static void update_cursor (BzDataGraph *self, gdouble x, gdouble y) { double widget_width = gtk_widget_get_width (GTK_WIDGET (self)); double widget_height = gtk_widget_get_height (GTK_WIDGET (self)); if (x >= LABEL_MARGIN && y >= 0.0 && x < widget_width - LABEL_MARGIN_RIGHT && y < widget_height - LABEL_MARGIN) gtk_widget_set_cursor_from_name (GTK_WIDGET (self), "crosshair"); else gtk_widget_set_cursor (GTK_WIDGET (self), NULL); } static void motion_enter (BzDataGraph *self, gdouble x, gdouble y, GtkEventControllerMotion *controller) { self->motion_x = x; self->motion_y = y; update_cursor (self, x, y); gtk_widget_queue_draw (GTK_WIDGET (self)); } static void motion_event (BzDataGraph *self, gdouble x, gdouble y, GtkEventControllerMotion *controller) { self->motion_x = x; self->motion_y = y; update_cursor (self, x, y); gtk_widget_queue_draw (GTK_WIDGET (self)); } static void motion_leave (BzDataGraph *self, GtkEventControllerMotion *controller) { self->motion_x = -1.0; self->motion_y = -1.0; gtk_widget_set_cursor (GTK_WIDGET (self), NULL); gtk_widget_queue_draw (GTK_WIDGET (self)); } static void gesture_begin (BzDataGraph *self, double start_x, double start_y, GtkGestureDrag *gesture) { self->motion_x = start_x; self->motion_y = start_y; gtk_widget_queue_draw (GTK_WIDGET (self)); } static void gesture_update (BzDataGraph *self, double offset_x, double offset_y, GtkGestureDrag *gesture) { double start_x, start_y; gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y); self->motion_x = start_x + offset_x; self->motion_y = start_y + offset_y; gtk_widget_queue_draw (GTK_WIDGET (self)); } static void gesture_end (BzDataGraph *self, double offset_x, double offset_y, GtkGestureDrag *gesture) { gtk_widget_queue_draw (GTK_WIDGET (self)); } static void bz_data_graph_init (BzDataGraph *self) { GtkWidget *inner_box = NULL; GtkWidget *label2_box = NULL; GtkWidget *icon_image = NULL; self->style_manager = adw_style_manager_get_default (); g_signal_connect_swapped (self->style_manager, "notify::dark", G_CALLBACK (on_style_changed), self); g_signal_connect_swapped (self->style_manager, "notify::accent-color", G_CALLBACK (on_style_changed), self); self->motion = gtk_event_controller_motion_new (); g_signal_connect_swapped (self->motion, "enter", G_CALLBACK (motion_enter), self); g_signal_connect_swapped (self->motion, "motion", G_CALLBACK (motion_event), self); g_signal_connect_swapped (self->motion, "leave", G_CALLBACK (motion_leave), self); gtk_widget_add_controller (GTK_WIDGET (self), self->motion); self->gesture = gtk_gesture_drag_new (); gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (self->gesture), TRUE); g_signal_connect_swapped (self->gesture, "drag-begin", G_CALLBACK (gesture_begin), self); g_signal_connect_swapped (self->gesture, "drag-update", G_CALLBACK (gesture_update), self); g_signal_connect_swapped (self->gesture, "drag-end", G_CALLBACK (gesture_end), self); gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (self->gesture)); self->motion_x = -1.0; self->motion_y = -1.0; self->rounded_axis_max = 0.0; self->tooltip_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_widget_add_css_class (self->tooltip_box, "card"); gtk_widget_add_css_class (self->tooltip_box, "floating-tooltip"); inner_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4); gtk_widget_set_margin_start (inner_box, 12); gtk_widget_set_margin_end (inner_box, 12); gtk_widget_set_margin_top (inner_box, 12); gtk_widget_set_margin_bottom (inner_box, 12); self->tooltip_label1 = gtk_label_new (""); gtk_widget_add_css_class (self->tooltip_label1, "heading"); gtk_label_set_xalign (GTK_LABEL (self->tooltip_label1), 0.0); gtk_box_append (GTK_BOX (inner_box), self->tooltip_label1); label2_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); icon_image = gtk_image_new_from_icon_name ("square-filled-symbolic"); gtk_widget_add_css_class (icon_image, "accent"); gtk_box_append (GTK_BOX (label2_box), icon_image); self->tooltip_prefix_label = gtk_label_new (""); gtk_widget_add_css_class (self->tooltip_prefix_label, "body"); gtk_widget_add_css_class (self->tooltip_prefix_label, "dim-label"); gtk_label_set_xalign (GTK_LABEL (self->tooltip_prefix_label), 0.0); gtk_box_append (GTK_BOX (label2_box), self->tooltip_prefix_label); self->tooltip_label2 = gtk_label_new (""); gtk_widget_add_css_class (self->tooltip_label2, "monospace"); gtk_widget_add_css_class (self->tooltip_label2, "dimmed"); gtk_label_set_xalign (GTK_LABEL (self->tooltip_label2), 0.0); gtk_box_append (GTK_BOX (label2_box), self->tooltip_label2); gtk_box_append (GTK_BOX (inner_box), label2_box); gtk_box_append (GTK_BOX (self->tooltip_box), inner_box); gtk_widget_set_parent (self->tooltip_box, GTK_WIDGET (self)); } GtkWidget * bz_data_graph_new (void) { return g_object_new (BZ_TYPE_DATA_GRAPH, NULL); } GListModel * bz_data_graph_get_model (BzDataGraph *self) { g_return_val_if_fail (BZ_IS_DATA_GRAPH (self), NULL); return self->model; } const char * bz_data_graph_get_independent_axis_label (BzDataGraph *self) { g_return_val_if_fail (BZ_IS_DATA_GRAPH (self), NULL); return self->independent_axis_label; } const char * bz_data_graph_get_dependent_axis_label (BzDataGraph *self) { g_return_val_if_fail (BZ_IS_DATA_GRAPH (self), NULL); return self->dependent_axis_label; } const char * bz_data_graph_get_tooltip_prefix (BzDataGraph *self) { g_return_val_if_fail (BZ_IS_DATA_GRAPH (self), NULL); return self->tooltip_prefix; } int bz_data_graph_get_independent_decimals (BzDataGraph *self) { g_return_val_if_fail (BZ_IS_DATA_GRAPH (self), 0); return self->independent_decimals; } int bz_data_graph_get_dependent_decimals (BzDataGraph *self) { g_return_val_if_fail (BZ_IS_DATA_GRAPH (self), 0); return self->dependent_decimals; } double bz_data_graph_get_transition_progress (BzDataGraph *self) { g_return_val_if_fail (BZ_IS_DATA_GRAPH (self), 0.0); return self->transition_progress; } void bz_data_graph_set_model (BzDataGraph *self, GListModel *model) { g_return_if_fail (BZ_IS_DATA_GRAPH (self)); g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model)); if (self->model != NULL) g_signal_handlers_disconnect_by_func ( self->model, items_changed, self); g_clear_object (&self->model); if (model != NULL) self->model = g_object_ref (model); gtk_widget_queue_allocate (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MODEL]); } void bz_data_graph_set_independent_axis_label (BzDataGraph *self, const char *independent_axis_label) { g_return_if_fail (BZ_IS_DATA_GRAPH (self)); g_clear_pointer (&self->independent_axis_label, g_free); if (independent_axis_label != NULL) self->independent_axis_label = g_strdup (independent_axis_label); gtk_widget_queue_draw (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INDEPENDENT_AXIS_LABEL]); } void bz_data_graph_set_dependent_axis_label (BzDataGraph *self, const char *dependent_axis_label) { g_return_if_fail (BZ_IS_DATA_GRAPH (self)); g_clear_pointer (&self->dependent_axis_label, g_free); if (dependent_axis_label != NULL) self->dependent_axis_label = g_strdup (dependent_axis_label); gtk_widget_queue_draw (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DEPENDENT_AXIS_LABEL]); } void bz_data_graph_set_tooltip_prefix (BzDataGraph *self, const char *tooltip_prefix) { g_return_if_fail (BZ_IS_DATA_GRAPH (self)); g_clear_pointer (&self->tooltip_prefix, g_free); if (tooltip_prefix != NULL) self->tooltip_prefix = g_strdup (tooltip_prefix); gtk_widget_queue_draw (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TOOLTIP_PREFIX]); } void bz_data_graph_set_independent_decimals (BzDataGraph *self, int independent_decimals) { g_return_if_fail (BZ_IS_DATA_GRAPH (self)); self->independent_decimals = CLAMP (independent_decimals, -1, 4); gtk_widget_queue_allocate (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INDEPENDENT_DECIMALS]); } void bz_data_graph_set_dependent_decimals (BzDataGraph *self, int dependent_decimals) { g_return_if_fail (BZ_IS_DATA_GRAPH (self)); self->dependent_decimals = CLAMP (dependent_decimals, -1, 4); gtk_widget_queue_allocate (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DEPENDENT_DECIMALS]); } void bz_data_graph_set_transition_progress (BzDataGraph *self, double transition_progress) { g_return_if_fail (BZ_IS_DATA_GRAPH (self)); self->transition_progress = transition_progress; gtk_widget_queue_draw (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TRANSITION_PROGRESS]); } void bz_data_graph_animate_open (BzDataGraph *self) { g_return_if_fail (BZ_IS_DATA_GRAPH (self)); self->wants_animate_open = TRUE; gtk_widget_queue_draw (GTK_WIDGET (self)); } static void items_changed (GListModel *model, guint position, guint removed, guint added, BzDataGraph *self) { gtk_widget_queue_allocate (GTK_WIDGET (self)); } static double calculate_axis_tick_value (double value, gboolean round_up) { double exponent = 0.0; double fraction = 0.0; double rounded_axis_fraction = 0.0; exponent = floor (log10 (value)); fraction = value / pow (10, exponent); if (round_up) { if (fraction <= 1.0) rounded_axis_fraction = 1.0; else if (fraction <= 2.0) rounded_axis_fraction = 2.0; else if (fraction <= 5.0) rounded_axis_fraction = 5.0; else rounded_axis_fraction = 10.0; } else if (fraction < 1.5) rounded_axis_fraction = 1.0; else if (fraction < 3.0) rounded_axis_fraction = 2.0; else if (fraction < 7.0) rounded_axis_fraction = 5.0; else rounded_axis_fraction = 10.0; return rounded_axis_fraction * pow (10, exponent); } static void refresh_path (BzDataGraph *self, double width, double height) { guint n_items = 0; double min_independent = 0.0; double max_independent = 0.0; double max_dependent = 0.0; PangoContext *pango = NULL; PangoFontMetrics *metrics = NULL; double font_height = 0.0; int independent_label_step = 0; g_autoptr (GskPathBuilder) curve_builder = NULL; g_autoptr (GtkSnapshot) snapshot = NULL; g_autoptr (GskPathBuilder) grid_builder = NULL; g_autoptr (GskPath) grid = NULL; g_autoptr (GskStroke) grid_stroke = NULL; double rounded_axis_max = 0.0; double tick_spacing = 0.0; int num_ticks = 0; g_clear_pointer (&self->path, gsk_path_unref); g_clear_pointer (&self->path_measure, gsk_path_measure_unref); g_clear_pointer (&self->fg, gsk_render_node_unref); if (self->model == NULL) return; if (width < LABEL_MARGIN || height < LABEL_MARGIN) return; n_items = g_list_model_get_n_items (self->model); if (n_items <= 1) return; for (guint i = 0; i < n_items; i++) { g_autoptr (BzDataPoint) point = NULL; double independent = 0.0; double dependent = 0.0; point = g_list_model_get_item (self->model, i); independent = bz_data_point_get_independent (point); dependent = bz_data_point_get_dependent (point); if (i == 0) { min_independent = independent; max_independent = independent; max_dependent = dependent; } else { min_independent = MIN (independent, min_independent); max_independent = MAX (independent, max_independent); max_dependent = MAX (dependent, max_dependent); } } rounded_axis_max = calculate_axis_tick_value (max_dependent, TRUE); pango = gtk_widget_get_pango_context (GTK_WIDGET (self)); metrics = pango_context_get_metrics (pango, NULL, NULL); font_height = (double) (int) PANGO_PIXELS_CEIL (pango_font_metrics_get_height (metrics)); g_clear_pointer (&metrics, pango_font_metrics_unref); num_ticks = MIN (5, floor (height / (font_height + 25.0))); if (num_ticks < 2) num_ticks = 2; tick_spacing = calculate_axis_tick_value (rounded_axis_max / (double) num_ticks, FALSE); if (tick_spacing == 0.0) tick_spacing = 1.0; rounded_axis_max = ceil (max_dependent / tick_spacing) * tick_spacing; self->rounded_axis_max = rounded_axis_max; independent_label_step = MAX (1, n_items / MAX (1, floor (width / MAX (font_height + 10.0, LABEL_MARGIN)))) * 1.5; curve_builder = gsk_path_builder_new (); snapshot = gtk_snapshot_new (); grid_builder = gsk_path_builder_new (); for (guint i = 0; i < n_items; i++) { g_autoptr (BzDataPoint) point = NULL; double independent = 0.0; double dependent = 0.0; double x = 0.0; double y = 0.0; point = g_list_model_get_item (self->model, i); independent = bz_data_point_get_independent (point); dependent = bz_data_point_get_dependent (point); x = (independent - min_independent) / (max_independent - min_independent) * width; y = (1.0 - dependent / rounded_axis_max) * height; if (i == 0) gsk_path_builder_move_to (curve_builder, x, y); else gsk_path_builder_line_to (curve_builder, x, y); if (i % independent_label_step == 0) { const char *label = NULL; char buf[32] = { 0 }; g_autoptr (PangoLayout) layout = NULL; PangoRectangle extents; label = bz_data_point_get_label (point); if (label == NULL) { switch (self->independent_decimals) { case 0: g_snprintf (buf, sizeof (buf), "%d", (int) round (independent)); break; case 1: g_snprintf (buf, sizeof (buf), "%.1f", independent); break; case 2: g_snprintf (buf, sizeof (buf), "%.2f", independent); break; case 3: g_snprintf (buf, sizeof (buf), "%.3f", independent); break; default: g_snprintf (buf, sizeof (buf), "%f", independent); break; } label = buf; } layout = pango_layout_new (pango); pango_layout_set_text (layout, label, -1); pango_layout_get_pixel_extents (layout, NULL, &extents); gtk_snapshot_save (snapshot); gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, height + LABEL_MARGIN / 10.0)); gtk_snapshot_rotate (snapshot, -LABEL_MARGIN_RIGHT); gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (-extents.width, 0)); gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 1.0, 1.0, 1.0, 1.0 }); gtk_snapshot_restore (snapshot); gsk_path_builder_move_to (grid_builder, x, height); gsk_path_builder_line_to (grid_builder, x, height + TICK_LENGTH); } } gsk_path_builder_move_to (grid_builder, 0.0, height); gsk_path_builder_line_to (grid_builder, width, height); gtk_snapshot_save (snapshot); gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (-LABEL_MARGIN * 0.75, -font_height / 2.0)); for (double value = 0.0; value <= rounded_axis_max; value += tick_spacing) { char buf[32] = { 0 }; g_autoptr (PangoLayout) layout = NULL; double y_pos = (1.0 - value / rounded_axis_max) * height; switch (self->dependent_decimals) { case 0: g_snprintf (buf, sizeof (buf), "%d", (int) round (value)); break; case 1: g_snprintf (buf, sizeof (buf), "%.1f", value); break; case 2: g_snprintf (buf, sizeof (buf), "%.2f", value); break; case 3: g_snprintf (buf, sizeof (buf), "%.3f", value); break; default: g_snprintf (buf, sizeof (buf), "%f", value); break; } layout = pango_layout_new (pango); pango_layout_set_text (layout, buf, -1); gtk_snapshot_save (snapshot); gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (0, y_pos)); gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 1.0, 1.0, 1.0, 1.0 }); gtk_snapshot_restore (snapshot); gsk_path_builder_move_to (grid_builder, -TICK_LENGTH, y_pos); gsk_path_builder_line_to (grid_builder, 0.0, y_pos); } gtk_snapshot_restore (snapshot); gsk_path_builder_move_to (grid_builder, 0.0, 0.0); gsk_path_builder_line_to (grid_builder, 0.0, height); grid = gsk_path_builder_to_path (grid_builder); grid_stroke = gsk_stroke_new (1.0); gtk_snapshot_append_stroke (snapshot, grid, grid_stroke, &(GdkRGBA){ 1.0, 1.0, 1.0, 1.0 }); self->path = gsk_path_builder_to_path (curve_builder); self->path_measure = gsk_path_measure_new (self->path); self->fg = gtk_snapshot_to_node (snapshot); } bazaar-orig-v0.7.14/src/bz-context-tile-callbacks.h0000664000175000017500000000160415166123241021046 0ustar hasanhasan/* bz-context-tile-callbacks.h * * Copyright 2026 Eva M, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include void bz_widget_class_bind_all_context_tile_callbacks (GtkWidgetClass *widget_class); bazaar-orig-v0.7.14/src/bz-template-callbacks.c0000664000175000017500000001151415166123241020236 0ustar hasanhasan/* bz-template-callbacks.c * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-template-callbacks.h" static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } /* Let's try to use this more for conciseness */ static gboolean not (gpointer object, gboolean value) { return invert_boolean (object, value); } static gboolean is_zero (gpointer object, int value) { return value == 0; } static gboolean is_double_zero (gpointer object, double value) { return value == 0.0; } static gboolean is_null (gpointer object, GObject *value) { return value == NULL; } static gboolean is_gt (gpointer object, int value1, int value2) { return value1 > value2; } static gboolean is_lt (gpointer object, int value1, int value2) { return value1 < value2; } static gboolean is_ge (gpointer object, int value1, int value2) { return value1 >= value2; } static gboolean is_le (gpointer object, int value1, int value2) { return value1 <= value2; } static gboolean logical_and (gpointer object, gboolean value1, gboolean value2) { return value1 && value2; } static gboolean logical_or (gpointer object, gboolean value1, gboolean value2) { return value1 || value2; } static gboolean is_positive (gpointer object, int value) { return value >= 0; } static gboolean is_empty (gpointer object, GListModel *model) { return model == NULL || g_list_model_get_n_items (model) == 0; } static gboolean is_empty_string (gpointer object, const char *str) { return str == NULL || *str == '\0'; } static gboolean is_longer (gpointer object, GListModel *model, int value) { return model != NULL && g_list_model_get_n_items (model) > value; } static char * bool_to_string (gpointer object, gboolean condition, char *if_true, char *if_false) { return g_strdup (condition ? if_true : if_false); } static gpointer choose (gpointer object, gboolean condition, gpointer if_true, gpointer if_false) { return condition ? if_true : if_false; } static char * format_int (gpointer object, gint integer) { return g_strdup_printf ("%d", integer); } static char * format_uint (gpointer object, guint uint) { return g_strdup_printf ("%u", uint); } static char * format_double (gpointer object, double number) { return g_strdup_printf ("%f", number); } void bz_widget_class_bind_all_util_callbacks (GtkWidgetClass *widget_class) { g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class)); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, not); gtk_widget_class_bind_template_callback (widget_class, is_zero); gtk_widget_class_bind_template_callback (widget_class, is_double_zero); gtk_widget_class_bind_template_callback (widget_class, is_null); gtk_widget_class_bind_template_callback (widget_class, is_gt); gtk_widget_class_bind_template_callback (widget_class, is_lt); gtk_widget_class_bind_template_callback (widget_class, is_ge); gtk_widget_class_bind_template_callback (widget_class, is_le); gtk_widget_class_bind_template_callback (widget_class, logical_and); gtk_widget_class_bind_template_callback (widget_class, logical_or); gtk_widget_class_bind_template_callback (widget_class, is_positive); gtk_widget_class_bind_template_callback (widget_class, is_empty); gtk_widget_class_bind_template_callback (widget_class, is_empty_string); gtk_widget_class_bind_template_callback (widget_class, is_longer); gtk_widget_class_bind_template_callback (widget_class, bool_to_string); gtk_widget_class_bind_template_callback (widget_class, choose); gtk_widget_class_bind_template_callback (widget_class, format_int); gtk_widget_class_bind_template_callback (widget_class, format_uint); gtk_widget_class_bind_template_callback (widget_class, format_double); } bazaar-orig-v0.7.14/src/bz-apps-page.blp0000664000175000017500000001033715166123241016720 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzAppsPage: Adw.NavigationPage { Adw.ToolbarView { [top] Adw.HeaderBar { [end] MenuButton { primary: true; icon-name: "open-menu-symbolic"; has-tooltip: true; tooltip-text: _("Main Menu"); menu-model: menu { section { item { label: _("_Donate to Bazaar ❤️"); action: "app.donate"; } } section { item { label: _("_Refresh"); action: "app.sync-remotes"; } item { label: _("_Preferences"); action: "app.preferences"; } item { label: _("_Login With Flathub"); action: "app.flathub-login"; hidden-when: "action-disabled"; } item { label: _("_Manage Leftover User Data"); action: "window.user-data"; } item { label: _("_Keyboard Shortcuts"); action: "app.shortcuts"; } item { label: _("_About Bazaar"); action: "app.about"; } } section { item { label: _("_Quit Bazaar"); action: "app.quit"; } } }; } } content: Adw.BreakpointBin { width-request: 360; height-request: 100; child: Gtk.ScrolledWindow { hscrollbar-policy: never; Adw.Clamp { maximum-size: 1500; tightening-threshold: 1400; Box content_box { orientation: vertical; spacing: 10; margin-start: 30; margin-end: 30; margin-top: 8; margin-bottom: 50; $BzFeaturedCarousel { margin-start: 3; margin-end: 3; margin-bottom: 12; hexpand: true; visible: bind $is_not_null(template.carousel-applications) as ; model: SliceListModel { offset: 0; size: 7; model: bind template.carousel-applications; }; } Box { margin-start: 3; orientation: vertical; Label title { styles [ "title-1", ] label: bind template.page-title; xalign: 0.0; wrap: true; wrap-mode: word_char; } Label subtitle { visible: bind $is_not_empty_string(template.page-subtitle) as ; label: bind template.page-subtitle; margin-top: 4; xalign: 0.0; } $BzSubcategoryList { margin-top: 12; margin-bottom: 8; category: bind template.category; flathub-state: bind template.flathub-state; } } $BzDynamicListView list_view { styles [ "flathub-page-section", ] hexpand: true; scroll: false; valign: start; noscroll-kind: flow-box; child-type: "BzAppTile"; child-prop: "group"; model: bind template.applications; bind-widget => $bind_widget_cb(template); unbind-widget => $unbind_widget_cb(template); } Button { label: _("Show All"); visible: bind $is_not_empty_list(template.all-applications) as ; halign: center; margin-top: 8; clicked => $show_all_cb(template); styles ["pill"] } } } }; Adw.Breakpoint { condition ("max-width: 700px") setters { content_box.margin-start: 10; content_box.margin-end: 10; list_view.column-spacing: 3; list_view.row-spacing: 3; title.halign: center; title.justify: center; subtitle.halign: center; } } }; } } bazaar-orig-v0.7.14/src/bz-newline-parser.h0000664000175000017500000000206015166123241017442 0ustar hasanhasan/* bz-newline-parser.h * * Copyright 2025 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_NEWLINE_PARSER (bz_newline_parser_get_type ()) G_DECLARE_FINAL_TYPE (BzNewlineParser, bz_newline_parser, BZ, NEWLINE_PARSER, GObject) BzNewlineParser * bz_newline_parser_new (gboolean comments, guint max_lines); G_END_DECLS bazaar-orig-v0.7.14/src/bz-backend-notification.txt0000664000175000017500000000113615166123241021155 0ustar hasanhasanprefix=bz name=backend_notification parent-prefix=g parent-name=object author=AUTOGEN enum=bz backend_notification_kind error tell_incoming replace_entry remote_sync_start remote_sync_finish install_done update_done remove_done external_change include="bz-entry.h" property=kind BzBackendNotificationKind BZ_TYPE_BACKEND_NOTIFICATION_KIND enum property=error char G_TYPE_STRING string property=n_incoming int G_TYPE_INT int property=entry BzEntry BZ_TYPE_ENTRY object property=version char G_TYPE_STRING string property=remote_name char G_TYPE_STRING string property=unique_id char G_TYPE_STRING string bazaar-orig-v0.7.14/src/bz-release.txt0000664000175000017500000000042015166123241016515 0ustar hasanhasanprefix=bz name=release parent-prefix=g parent-name=object author=AUTOGEN include= property=description char G_TYPE_STRING string property=timestamp guint64 G_TYPE_UINT64 uint64 property=url char G_TYPE_STRING string property=version char G_TYPE_STRING string bazaar-orig-v0.7.14/src/bz-template-callbacks.h0000664000175000017500000000154615166123241020247 0ustar hasanhasan/* bz-template-callbacks.h * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include void bz_widget_class_bind_all_util_callbacks (GtkWidgetClass *widget_class); bazaar-orig-v0.7.14/src/bz-app-size-dialog.c0000664000175000017500000001323115166123241017471 0ustar hasanhasan/* bz-app-size-dialog.c * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-app-size-dialog.h" #include "bz-io.h" #include "bz-entry-group.h" #include "bz-lozenge.h" #include "bz-template-callbacks.h" #include struct _BzAppSizeDialog { AdwBin parent_instance; BzEntryGroup *group; }; G_DEFINE_FINAL_TYPE (BzAppSizeDialog, bz_app_size_dialog, ADW_TYPE_BIN) enum { PROP_0, PROP_GROUP, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bz_app_size_dialog_dispose (GObject *object) { BzAppSizeDialog *self = BZ_APP_SIZE_DIALOG (object); g_clear_object (&self->group); G_OBJECT_CLASS (bz_app_size_dialog_parent_class)->dispose (object); } static void bz_app_size_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzAppSizeDialog *self = BZ_APP_SIZE_DIALOG (object); switch (prop_id) { case PROP_GROUP: g_value_set_object (value, self->group); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_app_size_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzAppSizeDialog *self = BZ_APP_SIZE_DIALOG (object); switch (prop_id) { case PROP_GROUP: g_clear_object (&self->group); self->group = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static char * get_runtime_size_title (gpointer object, gboolean runtime_installed) { return g_strdup (runtime_installed ? _ ("Installed Runtime Size") : _ ("Runtime Download Size")); } static char * format_size (gpointer object, guint64 value) { g_autofree char *size_str = g_format_size (value); char *space = g_strrstr (size_str, "\xC2\xA0"); if (space != NULL) { *space = '\0'; return g_strdup_printf ("%s %s", size_str, space + 2); } return g_strdup (size_str); } static void open_user_data_folder_cb (GtkWidget *widget, gpointer user_data) { BzAppSizeDialog *self = NULL; const char *id = NULL; g_autofree char *path = NULL; g_autoptr (GFile) file = NULL; g_autoptr (GtkFileLauncher) launcher = NULL; GtkRoot *root = NULL; self = BZ_APP_SIZE_DIALOG (gtk_widget_get_ancestor (widget, BZ_TYPE_APP_SIZE_DIALOG)); if (self->group == NULL) return; id = bz_entry_group_get_id (self->group); if (id == NULL) return; path = bz_dup_user_data_path (id); file = g_file_new_for_path (path); launcher = gtk_file_launcher_new (file); root = gtk_widget_get_root (widget); gtk_file_launcher_launch (launcher, GTK_WINDOW (root), NULL, NULL, NULL); } static void bz_app_size_dialog_class_init (BzAppSizeDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_app_size_dialog_dispose; object_class->get_property = bz_app_size_dialog_get_property; object_class->set_property = bz_app_size_dialog_set_property; props[PROP_GROUP] = g_param_spec_object ( "group", NULL, NULL, BZ_TYPE_ENTRY_GROUP, G_PARAM_READWRITE); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_LOZENGE); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-app-size-dialog.ui"); bz_widget_class_bind_all_util_callbacks (widget_class); gtk_widget_class_bind_template_callback (widget_class, format_size); gtk_widget_class_bind_template_callback (widget_class, get_runtime_size_title); gtk_widget_class_bind_template_callback (widget_class, open_user_data_folder_cb); } static void bz_app_size_dialog_init (BzAppSizeDialog *self) { gtk_widget_init_template (GTK_WIDGET (self)); } AdwDialog * bz_app_size_dialog_new (BzEntryGroup *group) { BzAppSizeDialog *widget = NULL; AdwDialog *dialog = NULL; widget = g_object_new (BZ_TYPE_APP_SIZE_DIALOG, "group", group, NULL); dialog = adw_dialog_new (); adw_dialog_set_content_height (dialog, 500); adw_dialog_set_content_width (dialog, 600); adw_dialog_set_child (dialog, GTK_WIDGET (widget)); return dialog; } AdwNavigationPage * bz_app_size_page_new (BzEntryGroup *group) { BzAppSizeDialog *widget = NULL; AdwNavigationPage *page = NULL; widget = g_object_new (BZ_TYPE_APP_SIZE_DIALOG, "group", group, NULL); page = adw_navigation_page_new (GTK_WIDGET (widget), _ ("App Size")); adw_navigation_page_set_tag (page, "app-size"); return page; } bazaar-orig-v0.7.14/src/bz-fading-clamp.h0000664000175000017500000000252215166123241017034 0ustar hasanhasan/* bz-fading-clamp.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_FADING_CLAMP (bz_fading_clamp_get_type ()) G_DECLARE_FINAL_TYPE (BzFadingClamp, bz_fading_clamp, BZ, FADING_CLAMP, GtkWidget) GtkWidget *bz_fading_clamp_new (void); GtkWidget *bz_fading_clamp_get_child (BzFadingClamp *self); void bz_fading_clamp_set_child (BzFadingClamp *self, GtkWidget *child); int bz_fading_clamp_get_max_height (BzFadingClamp *self); void bz_fading_clamp_set_max_height (BzFadingClamp *self, int max_height); G_END_DECLS bazaar-orig-v0.7.14/src/bz-parser.h0000664000175000017500000000237215166123241016011 0ustar hasanhasan/* bz-parser.h * * Copyright 2025 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_PARSER (bz_parser_get_type ()) G_DECLARE_INTERFACE (BzParser, bz_parser, BZ, PARSER, GObject) struct _BzParserInterface { GTypeInterface parent_iface; GHashTable *(*process_bytes) (BzParser *self, GBytes *bytes, GError **error); }; GHashTable * bz_parser_process_bytes (BzParser *self, GBytes *bytes, GError **error); G_END_DECLS bazaar-orig-v0.7.14/src/bz-developer-badge.blp0000664000175000017500000000277515166123241020077 0ustar hasanhasanusing Gtk 4.0; template $BzDeveloperBadge: Box { orientation: horizontal; spacing: 3; halign: start; visible: bind $invert_boolean($is_null(template.entry as <$BzEntry>.developer) as ) as ; Label developer_label { label: bind $get_developer_link(template.entry, template.entry as <$BzEntry>.verification-status) as ; use-markup: true; xalign: 0.0; wrap: true; lines: 3; ellipsize: end; wrap-mode: word_char; natural-wrap-mode: word; styles [ "app-developer", ] } MenuButton info_button { icon-name: bind $get_icon_name(template.entry as <$BzEntry>.verification-status) as ; popover: popover; visible: bind $invert_boolean($is_null(template.entry as <$BzEntry>.verification-status) as ) as ; styles [ "developer-badge", ] has-tooltip: true; tooltip-text: bind $get_verified_tooltip(template.entry as <$BzEntry>.verification-status) as ; EventControllerMotion { enter => $on_info_button_enter(); leave => $on_info_button_leave(); } } } Popover popover { has-arrow: true; position: right; child: Box { orientation: vertical; margin-top: 12; margin-bottom: 12; margin-start: 12; margin-end: 12; Label popover_label { label: bind $get_popover_text(template.entry, template.entry as <$BzEntry>.verification-status) as ; wrap: true; xalign: 0.0; max-width-chars: 40; use-markup: true; } }; } bazaar-orig-v0.7.14/src/bz-screenshot-page.c0000664000175000017500000003761715166123241017611 0ustar hasanhasan/* bz-screenshot-page.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-screenshot-page.h" #include "bz-screenshot.h" #include "bz-zoom.h" #include struct _BzScreenshotPage { AdwNavigationPage parent_instance; AdwCarousel *carousel; AdwToastOverlay *toast_overlay; GListModel *screenshots; GListModel *captions; guint current_index; guint initial_index; gboolean is_zoomed; }; G_DEFINE_FINAL_TYPE (BzScreenshotPage, bz_screenshot_page, ADW_TYPE_NAVIGATION_PAGE) static void on_zoom_level_changed (BzZoom *zoom, GParamSpec *pspec, BzScreenshotPage *self); enum { PROP_0, PROP_SCREENSHOTS, PROP_CURRENT_INDEX, PROP_CURRENT_CAPTION, PROP_IS_ZOOMED, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bz_screenshot_page_dispose (GObject *object) { BzScreenshotPage *self = BZ_SCREENSHOT_PAGE (object); g_clear_object (&self->screenshots); g_clear_object (&self->captions); G_OBJECT_CLASS (bz_screenshot_page_parent_class)->dispose (object); } static void bz_screenshot_page_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzScreenshotPage *self = BZ_SCREENSHOT_PAGE (object); switch (prop_id) { case PROP_SCREENSHOTS: g_value_set_object (value, self->screenshots); break; case PROP_CURRENT_INDEX: g_value_set_uint (value, self->current_index); break; case PROP_CURRENT_CAPTION: { const char *caption = bz_screenshot_page_get_current_caption (self); g_value_set_string (value, caption); } break; case PROP_IS_ZOOMED: g_value_set_boolean (value, self->is_zoomed); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void populate_carousel (BzScreenshotPage *self) { guint n_items = 0; guint i = 0; if (self->screenshots == NULL) return; n_items = g_list_model_get_n_items (self->screenshots); if (n_items == 0) return; for (guint offset = 0; offset < n_items; offset++) { g_autoptr (BzAsyncTexture) async_texture = NULL; GtkWidget *zoom_widget = NULL; GtkWidget *screenshot = NULL; i = (self->initial_index + offset) % n_items; async_texture = g_list_model_get_item (self->screenshots, i); if (async_texture == NULL) continue; screenshot = bz_screenshot_new (); bz_screenshot_set_paintable (BZ_SCREENSHOT (screenshot), GDK_PAINTABLE (async_texture)); bz_screenshot_set_rounded_corners (BZ_SCREENSHOT (screenshot), FALSE); gtk_widget_set_margin_top (screenshot, 25); gtk_widget_set_margin_bottom (screenshot, 25); gtk_widget_set_margin_start (screenshot, 25); gtk_widget_set_margin_end (screenshot, 25); zoom_widget = bz_zoom_new (); gtk_widget_set_hexpand (zoom_widget, TRUE); gtk_widget_set_vexpand (zoom_widget, TRUE); bz_zoom_set_child (BZ_ZOOM (zoom_widget), screenshot); adw_carousel_append (self->carousel, zoom_widget); } } static void update_is_zoomed (BzScreenshotPage *self) { GtkWidget *page = NULL; BzZoom *zoom = NULL; double zoom_level = 1.0; gboolean was_zoomed = self->is_zoomed; guint n_pages = 0; n_pages = adw_carousel_get_n_pages (self->carousel); if (self->current_index >= n_pages) return; page = adw_carousel_get_nth_page (self->carousel, self->current_index); if (page != NULL && BZ_IS_ZOOM (page)) { GtkWidget *screenshot = NULL; zoom = BZ_ZOOM (page); g_object_get (zoom, "zoom-level", &zoom_level, NULL); screenshot = bz_zoom_get_child (zoom); if (screenshot != NULL) bz_screenshot_set_filter ( BZ_SCREENSHOT (screenshot), zoom_level <= 4.5 ? GSK_SCALING_FILTER_TRILINEAR : GSK_SCALING_FILTER_NEAREST); } self->is_zoomed = zoom != NULL && bz_zoom_is_transformed (zoom); if (was_zoomed != self->is_zoomed) g_object_notify_by_pspec (G_OBJECT (self), props[PROP_IS_ZOOMED]); } static void on_zoom_level_changed (BzZoom *zoom, GParamSpec *pspec, BzScreenshotPage *self) { update_is_zoomed (self); } static void connect_zoom_signal (BzScreenshotPage *self, GtkWidget *page) { BzZoom *zoom = NULL; if (page != NULL && BZ_IS_ZOOM (page)) { zoom = BZ_ZOOM (page); g_signal_connect (zoom, "notify::zoom-level", G_CALLBACK (on_zoom_level_changed), self); } } static void bz_screenshot_page_constructed (GObject *object) { BzScreenshotPage *self = BZ_SCREENSHOT_PAGE (object); GtkWidget *page = NULL; G_OBJECT_CLASS (bz_screenshot_page_parent_class)->constructed (object); populate_carousel (self); self->current_index = 0; page = adw_carousel_get_nth_page (self->carousel, 0); if (page != NULL) connect_zoom_signal (self, page); update_is_zoomed (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CURRENT_CAPTION]); } static void bz_screenshot_page_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzScreenshotPage *self = BZ_SCREENSHOT_PAGE (object); switch (prop_id) { case PROP_SCREENSHOTS: g_set_object (&self->screenshots, g_value_get_object (value)); break; case PROP_CURRENT_INDEX: self->initial_index = g_value_get_uint (value); break; case PROP_CURRENT_CAPTION: case PROP_IS_ZOOMED: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void zoom_in_clicked (BzScreenshotPage *self) { GtkWidget *page = NULL; BzZoom *zoom = NULL; guint n_pages = 0; n_pages = adw_carousel_get_n_pages (self->carousel); if (self->current_index >= n_pages) return; page = adw_carousel_get_nth_page (self->carousel, self->current_index); if (page == NULL || !BZ_IS_ZOOM (page)) return; zoom = BZ_ZOOM (page); bz_zoom_zoom_in (zoom); } static void zoom_out_clicked (BzScreenshotPage *self) { GtkWidget *page = NULL; BzZoom *zoom = NULL; guint n_pages = 0; n_pages = adw_carousel_get_n_pages (self->carousel); if (self->current_index >= n_pages) return; page = adw_carousel_get_nth_page (self->carousel, self->current_index); if (page == NULL || !BZ_IS_ZOOM (page)) return; zoom = BZ_ZOOM (page); bz_zoom_zoom_out (zoom); } static void reset_zoom_clicked (BzScreenshotPage *self) { GtkWidget *page = NULL; BzZoom *zoom = NULL; guint n_pages = 0; n_pages = adw_carousel_get_n_pages (self->carousel); if (self->current_index >= n_pages) return; page = adw_carousel_get_nth_page (self->carousel, self->current_index); if (page == NULL || !BZ_IS_ZOOM (page)) return; zoom = BZ_ZOOM (page); bz_zoom_reset (zoom); } static void previous_clicked (BzScreenshotPage *self) { guint n_pages = 0; GtkWidget *page = NULL; n_pages = adw_carousel_get_n_pages (self->carousel); if (n_pages == 0) return; if (self->current_index > 0) page = adw_carousel_get_nth_page (self->carousel, self->current_index - 1); else page = adw_carousel_get_nth_page (self->carousel, n_pages - 1); if (page != NULL) adw_carousel_scroll_to (self->carousel, page, TRUE); } static void next_clicked (BzScreenshotPage *self) { guint n_pages = 0; GtkWidget *page = NULL; n_pages = adw_carousel_get_n_pages (self->carousel); if (n_pages == 0) return; if (self->current_index < n_pages - 1) page = adw_carousel_get_nth_page (self->carousel, self->current_index + 1); else page = adw_carousel_get_nth_page (self->carousel, 0); if (page != NULL) adw_carousel_scroll_to (self->carousel, page, TRUE); } static void on_carousel_position_changed (AdwCarousel *carousel, GParamSpec *pspec, BzScreenshotPage *self) { GtkWidget *old_page = NULL; GtkWidget *new_page = NULL; BzZoom *old_zoom = NULL; guint new_index = (guint) round (adw_carousel_get_position (carousel)); guint n_pages = adw_carousel_get_n_pages (carousel); if (new_index == self->current_index || new_index >= n_pages) return; if (self->current_index < n_pages) { old_page = adw_carousel_get_nth_page (carousel, self->current_index); if (old_page != NULL && BZ_IS_ZOOM (old_page)) { old_zoom = BZ_ZOOM (old_page); g_signal_handlers_disconnect_by_func (old_zoom, on_zoom_level_changed, self); bz_zoom_reset (old_zoom); } } self->current_index = new_index; if (new_index < n_pages) { new_page = adw_carousel_get_nth_page (carousel, new_index); connect_zoom_signal (self, new_page); } update_is_zoomed (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CURRENT_INDEX]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CURRENT_CAPTION]); } static void copy_clicked (BzScreenshotPage *self) { g_autoptr (BzAsyncTexture) async_texture = NULL; g_autoptr (GdkTexture) texture = NULL; GdkClipboard *clipboard; AdwToast *toast = NULL; guint n_items = 0; guint actual_index = 0; if (self->screenshots == NULL) return; n_items = g_list_model_get_n_items (self->screenshots); if (n_items == 0) return; actual_index = (self->initial_index + self->current_index) % n_items; async_texture = g_list_model_get_item (self->screenshots, actual_index); if (async_texture == NULL) return; texture = bz_async_texture_dup_texture (async_texture); if (texture == NULL) return; clipboard = gdk_display_get_clipboard (gdk_display_get_default ()); gdk_clipboard_set_texture (clipboard, texture); toast = adw_toast_new (_ ("Copied!")); adw_toast_set_timeout (toast, 1); adw_toast_overlay_add_toast (self->toast_overlay, toast); } static gboolean on_key_pressed (GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, BzScreenshotPage *self) { if (keyval == GDK_KEY_Left) { previous_clicked (self); return TRUE; } else if (keyval == GDK_KEY_Right) { next_clicked (self); return TRUE; } return FALSE; } static gboolean has_multiple_screenshots (GObject *object, GListModel *screenshots, gpointer user_data) { if (screenshots == NULL) return FALSE; return g_list_model_get_n_items (screenshots) > 1; } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static gboolean is_valid_string (gpointer object, const char *value) { return value != NULL && *value != '\0'; } static void bz_screenshot_page_class_init (BzScreenshotPageClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_screenshot_page_dispose; object_class->constructed = bz_screenshot_page_constructed; object_class->get_property = bz_screenshot_page_get_property; object_class->set_property = bz_screenshot_page_set_property; props[PROP_SCREENSHOTS] = g_param_spec_object ( "screenshots", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); props[PROP_CURRENT_INDEX] = g_param_spec_uint ( "current-index", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); props[PROP_CURRENT_CAPTION] = g_param_spec_string ( "current-caption", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_IS_ZOOMED] = g_param_spec_boolean ( "is-zoomed", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_ZOOM); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-screenshot-page.ui"); gtk_widget_class_bind_template_child (widget_class, BzScreenshotPage, carousel); gtk_widget_class_bind_template_child (widget_class, BzScreenshotPage, toast_overlay); gtk_widget_class_bind_template_callback (widget_class, zoom_in_clicked); gtk_widget_class_bind_template_callback (widget_class, zoom_out_clicked); gtk_widget_class_bind_template_callback (widget_class, on_carousel_position_changed); gtk_widget_class_bind_template_callback (widget_class, reset_zoom_clicked); gtk_widget_class_bind_template_callback (widget_class, copy_clicked); gtk_widget_class_bind_template_callback (widget_class, previous_clicked); gtk_widget_class_bind_template_callback (widget_class, next_clicked); gtk_widget_class_bind_template_callback (widget_class, has_multiple_screenshots); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, is_valid_string); } static void bz_screenshot_page_init (BzScreenshotPage *self) { GtkEventController *key_controller = NULL; gtk_widget_init_template (GTK_WIDGET (self)); key_controller = gtk_event_controller_key_new (); g_signal_connect (key_controller, "key-pressed", G_CALLBACK (on_key_pressed), self); gtk_widget_add_controller (GTK_WIDGET (self), key_controller); } const char * bz_screenshot_page_get_current_caption (BzScreenshotPage *self) { g_autoptr (GtkStringObject) caption_obj = NULL; guint n_items = 0; guint actual_index = 0; g_return_val_if_fail (BZ_IS_SCREENSHOT_PAGE (self), NULL); if (self->captions == NULL) return ""; n_items = g_list_model_get_n_items (self->captions); if (n_items == 0) return ""; actual_index = (self->initial_index + self->current_index) % n_items; caption_obj = g_list_model_get_item (self->captions, actual_index); if (caption_obj == NULL) return ""; return gtk_string_object_get_string (caption_obj); } void bz_screenshot_page_set_captions (BzScreenshotPage *self, GListModel *captions) { g_return_if_fail (BZ_IS_SCREENSHOT_PAGE (self)); g_set_object (&self->captions, captions); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CURRENT_CAPTION]); } AdwNavigationPage * bz_screenshot_page_new (GListModel *screenshots, GListModel *captions, guint initial_index) { BzScreenshotPage *page = g_object_new ( BZ_TYPE_SCREENSHOT_PAGE, "screenshots", screenshots, "current-index", initial_index, NULL); if (captions != NULL) bz_screenshot_page_set_captions (page, captions); return ADW_NAVIGATION_PAGE (page); } bazaar-orig-v0.7.14/src/bz-entry.c0000664000175000017500000026052315166123241015655 0ustar hasanhasan/* bz-entry.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ /* TODO: clean this mess up */ #define G_LOG_DOMAIN "BAZAAR::ENTRY" #define BAZAAR_MODULE "entry" #include #include "bz-app-permissions.h" #include "bz-async-texture.h" #include "bz-category-flags.h" #include "bz-country-data-point.h" #include "bz-data-point.h" #include "bz-entry.h" #include "bz-env.h" #include "bz-global-net.h" #include "bz-io.h" #include "bz-release.h" #include "bz-repository.h" #include "bz-serializable.h" #include "bz-url.h" #include "bz-util.h" #include "bz-verification-status.h" G_DEFINE_FLAGS_TYPE ( BzEntryKind, bz_entry_kind, G_DEFINE_ENUM_VALUE (BZ_ENTRY_KIND_APPLICATION, "application"), G_DEFINE_ENUM_VALUE (BZ_ENTRY_KIND_RUNTIME, "runtime"), G_DEFINE_ENUM_VALUE (BZ_ENTRY_KIND_ADDON, "addon")) G_DEFINE_FLAGS_TYPE ( BzControlType, bz_control_type, G_DEFINE_ENUM_VALUE (BZ_CONTROL_NONE, "none"), G_DEFINE_ENUM_VALUE (BZ_CONTROL_POINTING, "pointing"), G_DEFINE_ENUM_VALUE (BZ_CONTROL_KEYBOARD, "keyboard"), G_DEFINE_ENUM_VALUE (BZ_CONTROL_CONSOLE, "console"), G_DEFINE_ENUM_VALUE (BZ_CONTROL_TABLET, "tablet"), G_DEFINE_ENUM_VALUE (BZ_CONTROL_TOUCH, "touch"), G_DEFINE_ENUM_VALUE (BZ_CONTROL_GAMEPAD, "gamepad"), G_DEFINE_ENUM_VALUE (BZ_CONTROL_TV_REMOTE, "tv-remote"), G_DEFINE_ENUM_VALUE (BZ_CONTROL_VOICE, "voice"), G_DEFINE_ENUM_VALUE (BZ_CONTROL_VISION, "vision")) G_DEFINE_ENUM_TYPE ( BzRelationType, bz_relation_type, G_DEFINE_ENUM_VALUE (BZ_RELATION_REQUIRES, "requires"), G_DEFINE_ENUM_VALUE (BZ_RELATION_RECOMMENDS, "recommends"), G_DEFINE_ENUM_VALUE (BZ_RELATION_SUPPORTS, "supports")) typedef struct { gint hold; gboolean installed; char *installed_version; gboolean searchable; guint kinds; GListModel *addons; char *id; char *unique_id; char *unique_id_checksum; char *title; char *eol; char *description; char *long_description; char *remote_repo_name; char *url; guint64 size; guint64 installed_size; GdkPaintable *icon_paintable; GIcon *mini_icon; GdkPaintable *remote_repo_icon; char *search_tokens; char *metadata_license; char *project_license; gboolean is_floss; char *project_group; char *developer; char *developer_id; GListModel *developer_apps; GListModel *screenshot_paintables; GListModel *screenshot_captions; GdkPaintable *thumbnail_paintable; GListModel *share_urls; char *donation_url; char *forge_url; char *ratings_summary; GListModel *version_history; char *light_accent_color; char *dark_accent_color; gboolean is_mobile_friendly; guint required_controls; guint recommended_controls; guint supported_controls; gint min_display_length; gint max_display_length; AsContentRating *content_rating; GListModel *keywords; BzCategoryFlags categories; BzAppPermissions *permissions; gboolean is_flathub; BzVerificationStatus *verification_status; GListModel *download_stats; GListModel *download_stats_per_country; int recent_downloads; int total_downloads; int favorites_count; GHashTable *flathub_prop_queries; DexFuture *mini_icon_future; } BzEntryPrivate; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (BzEntry, bz_entry, G_TYPE_OBJECT); enum { PROP_0, PROP_HOLDING, PROP_INSTALLED, PROP_INSTALLED_VERSION, PROP_SEARCHABLE, PROP_KINDS, PROP_ADDONS, PROP_ID, PROP_UNIQUE_ID, PROP_UNIQUE_ID_CHECKSUM, PROP_TITLE, PROP_EOL, PROP_DESCRIPTION, PROP_DOWNLOAD_STATS_PER_COUNTRY, PROP_LONG_DESCRIPTION, PROP_REMOTE_REPO_NAME, PROP_URL, PROP_SIZE, PROP_INSTALLED_SIZE, PROP_ICON_PAINTABLE, PROP_MINI_ICON, PROP_SEARCH_TOKENS, PROP_REMOTE_REPO_ICON, PROP_METADATA_LICENSE, PROP_PROJECT_LICENSE, PROP_IS_FLOSS, PROP_PROJECT_GROUP, PROP_DEVELOPER, PROP_DEVELOPER_ID, PROP_DEVELOPER_APPS, PROP_SCREENSHOT_PAINTABLES, PROP_SCREENSHOT_CAPTIONS, PROP_THUMBNAIL_PAINTABLE, PROP_SHARE_URLS, PROP_DONATION_URL, PROP_FORGE_URL, PROP_RATINGS_SUMMARY, PROP_VERSION_HISTORY, PROP_IS_FLATHUB, PROP_VERIFICATION_STATUS, PROP_DOWNLOAD_STATS, PROP_RECENT_DOWNLOADS, PROP_TOTAL_DOWNLOADS, PROP_FAVORITES_COUNT, PROP_LIGHT_ACCENT_COLOR, PROP_DARK_ACCENT_COLOR, PROP_IS_MOBILE_FRIENDLY, PROP_REQUIRED_CONTROLS, PROP_RECOMMENDED_CONTROLS, PROP_SUPPORTED_CONTROLS, PROP_MIN_DISPLAY_LENGTH, PROP_MAX_DISPLAY_LENGTH, PROP_CONTENT_RATING, PROP_KEYWORDS, PROP_CATEGORIES, PROP_PERMISSIONS, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; BZ_DEFINE_DATA ( query_flathub, QueryFlathub, { GWeakRef self; int prop; char *id; char *developer; }, g_weak_ref_clear (&self->self); BZ_RELEASE_DATA (id, g_free); BZ_RELEASE_DATA (developer, g_free)); static DexFuture * query_flathub_fiber (QueryFlathubData *data); static DexFuture * query_flathub_then (DexFuture *future, QueryFlathubData *data); static void query_flathub (BzEntry *self, int prop); static void download_stats_per_day_foreach (JsonObject *object, const gchar *member_name, JsonNode *member_node, GListStore *store); static void download_stats_per_country_foreach (JsonObject *object, const gchar *member_name, JsonNode *member_node, GListStore *store); static gboolean maybe_save_paintable (BzEntryPrivate *priv, const char *key, GdkPaintable *paintable, GVariantBuilder *builder); static GdkPaintable * make_async_texture (GVariant *parse); static GIcon * load_mini_icon_sync (const char *unique_id_checksum, const char *path); static void clear_entry (BzEntry *self); static void bz_entry_dispose (GObject *object) { BzEntry *self = BZ_ENTRY (object); clear_entry (self); G_OBJECT_CLASS (bz_entry_parent_class)->dispose (object); } static void bz_entry_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzEntry *self = BZ_ENTRY (object); BzEntryPrivate *priv = bz_entry_get_instance_private (self); switch (prop_id) { case PROP_HOLDING: g_value_set_boolean (value, bz_entry_is_holding (self)); break; case PROP_INSTALLED: g_value_set_boolean (value, priv->installed); break; case PROP_INSTALLED_VERSION: g_value_set_string (value, priv->installed_version); break; case PROP_SEARCHABLE: g_value_set_boolean (value, priv->searchable); break; case PROP_ADDONS: g_value_set_object (value, priv->addons); break; case PROP_KINDS: g_value_set_flags (value, priv->kinds); break; case PROP_ID: g_value_set_string (value, priv->id); break; case PROP_UNIQUE_ID: g_value_set_string (value, priv->unique_id); break; case PROP_UNIQUE_ID_CHECKSUM: g_value_set_string (value, priv->unique_id_checksum); break; case PROP_TITLE: g_value_set_string (value, priv->title); break; case PROP_EOL: g_value_set_string (value, priv->eol); break; case PROP_DESCRIPTION: g_value_set_string (value, priv->description); break; case PROP_LONG_DESCRIPTION: g_value_set_string (value, priv->long_description); break; case PROP_REMOTE_REPO_NAME: g_value_set_string (value, priv->remote_repo_name); break; case PROP_URL: g_value_set_string (value, priv->url); break; case PROP_SIZE: g_value_set_uint64 (value, priv->size); break; case PROP_INSTALLED_SIZE: g_value_set_uint64 (value, priv->installed_size); break; case PROP_ICON_PAINTABLE: g_value_set_object (value, priv->icon_paintable); break; case PROP_MINI_ICON: g_value_set_object (value, priv->mini_icon); break; case PROP_SEARCH_TOKENS: g_value_set_boxed (value, priv->search_tokens); break; case PROP_REMOTE_REPO_ICON: g_value_set_object (value, priv->remote_repo_icon); break; case PROP_METADATA_LICENSE: g_value_set_string (value, priv->metadata_license); break; case PROP_PROJECT_LICENSE: g_value_set_string (value, priv->project_license); break; case PROP_IS_FLOSS: g_value_set_boolean (value, priv->is_floss); break; case PROP_PROJECT_GROUP: g_value_set_string (value, priv->project_group); break; case PROP_DEVELOPER: g_value_set_string (value, priv->developer); break; case PROP_DEVELOPER_ID: g_value_set_string (value, priv->developer_id); break; case PROP_DEVELOPER_APPS: query_flathub (self, PROP_DEVELOPER_APPS); g_value_set_object (value, priv->developer_apps); break; case PROP_SCREENSHOT_PAINTABLES: g_value_set_object (value, priv->screenshot_paintables); break; case PROP_SCREENSHOT_CAPTIONS: g_value_set_object (value, priv->screenshot_captions); break; case PROP_THUMBNAIL_PAINTABLE: g_value_set_object (value, priv->thumbnail_paintable); break; case PROP_SHARE_URLS: g_value_set_object (value, priv->share_urls); break; case PROP_DONATION_URL: g_value_set_string (value, priv->donation_url); break; case PROP_FORGE_URL: g_value_set_string (value, priv->forge_url); break; case PROP_RATINGS_SUMMARY: g_value_set_string (value, priv->ratings_summary); break; case PROP_VERSION_HISTORY: g_value_set_object (value, priv->version_history); break; case PROP_LIGHT_ACCENT_COLOR: g_value_set_string (value, priv->light_accent_color); break; case PROP_DARK_ACCENT_COLOR: g_value_set_string (value, priv->dark_accent_color); break; case PROP_IS_MOBILE_FRIENDLY: g_value_set_boolean (value, priv->is_mobile_friendly); break; case PROP_REQUIRED_CONTROLS: g_value_set_flags (value, priv->required_controls); break; case PROP_RECOMMENDED_CONTROLS: g_value_set_flags (value, priv->recommended_controls); break; case PROP_SUPPORTED_CONTROLS: g_value_set_flags (value, priv->supported_controls); break; case PROP_MIN_DISPLAY_LENGTH: g_value_set_int (value, priv->min_display_length); break; case PROP_MAX_DISPLAY_LENGTH: g_value_set_int (value, priv->max_display_length); break; case PROP_CONTENT_RATING: g_value_set_object (value, priv->content_rating); break; case PROP_KEYWORDS: g_value_set_object (value, priv->keywords); break; case PROP_CATEGORIES: g_value_set_uint (value, priv->categories); break; case PROP_PERMISSIONS: g_value_set_object (value, priv->permissions); break; case PROP_IS_FLATHUB: g_value_set_boolean (value, priv->is_flathub); break; case PROP_VERIFICATION_STATUS: g_value_set_object (value, priv->verification_status); break; case PROP_DOWNLOAD_STATS: query_flathub (self, PROP_DOWNLOAD_STATS); g_value_set_object (value, priv->download_stats); break; case PROP_DOWNLOAD_STATS_PER_COUNTRY: query_flathub (self, PROP_DOWNLOAD_STATS_PER_COUNTRY); g_value_set_object (value, priv->download_stats_per_country); break; case PROP_RECENT_DOWNLOADS: query_flathub (self, PROP_RECENT_DOWNLOADS); g_value_set_int (value, priv->recent_downloads); break; case PROP_TOTAL_DOWNLOADS: query_flathub (self, PROP_TOTAL_DOWNLOADS); g_value_set_int (value, priv->total_downloads); break; case PROP_FAVORITES_COUNT: query_flathub (self, PROP_FAVORITES_COUNT); g_value_set_int (value, priv->favorites_count); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_entry_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzEntry *self = BZ_ENTRY (object); BzEntryPrivate *priv = bz_entry_get_instance_private (self); switch (prop_id) { case PROP_INSTALLED: priv->installed = g_value_get_boolean (value); break; case PROP_INSTALLED_VERSION: g_clear_pointer (&priv->installed_version, g_free); priv->installed_version = g_value_dup_string (value); break; case PROP_SEARCHABLE: priv->searchable = g_value_get_boolean (value); break; case PROP_ADDONS: g_clear_object (&priv->addons); priv->addons = g_value_dup_object (value); break; case PROP_KINDS: priv->kinds = g_value_get_flags (value); break; case PROP_ID: g_clear_pointer (&priv->id, g_free); priv->id = g_value_dup_string (value); break; case PROP_UNIQUE_ID: g_clear_pointer (&priv->unique_id, g_free); priv->unique_id = g_value_dup_string (value); break; case PROP_UNIQUE_ID_CHECKSUM: g_clear_pointer (&priv->unique_id_checksum, g_free); priv->unique_id_checksum = g_value_dup_string (value); break; case PROP_TITLE: g_clear_pointer (&priv->title, g_free); priv->title = g_value_dup_string (value); break; case PROP_EOL: g_clear_pointer (&priv->eol, g_free); priv->eol = g_value_dup_string (value); break; case PROP_DESCRIPTION: g_clear_pointer (&priv->description, g_free); priv->description = g_value_dup_string (value); break; case PROP_LONG_DESCRIPTION: g_clear_pointer (&priv->long_description, g_free); priv->long_description = g_value_dup_string (value); break; case PROP_REMOTE_REPO_NAME: g_clear_pointer (&priv->remote_repo_name, g_free); priv->remote_repo_name = g_value_dup_string (value); priv->is_flathub = g_strcmp0 (priv->remote_repo_name, "flathub") == 0; g_object_notify_by_pspec (object, props[PROP_IS_FLATHUB]); break; case PROP_URL: g_clear_pointer (&priv->url, g_free); priv->url = g_value_dup_string (value); break; case PROP_SIZE: priv->size = g_value_get_uint64 (value); break; case PROP_INSTALLED_SIZE: priv->installed_size = g_value_get_uint64 (value); break; case PROP_ICON_PAINTABLE: g_clear_object (&priv->icon_paintable); priv->icon_paintable = g_value_dup_object (value); break; case PROP_MINI_ICON: g_clear_object (&priv->mini_icon); priv->mini_icon = g_value_dup_object (value); break; case PROP_SEARCH_TOKENS: g_clear_pointer (&priv->search_tokens, g_free); priv->search_tokens = g_value_dup_string (value); break; case PROP_REMOTE_REPO_ICON: g_clear_object (&priv->remote_repo_icon); priv->remote_repo_icon = g_value_dup_object (value); break; case PROP_METADATA_LICENSE: g_clear_pointer (&priv->metadata_license, g_free); priv->metadata_license = g_value_dup_string (value); break; case PROP_PROJECT_LICENSE: g_clear_pointer (&priv->project_license, g_free); priv->project_license = g_value_dup_string (value); break; case PROP_IS_FLOSS: priv->is_floss = g_value_get_boolean (value); break; case PROP_PROJECT_GROUP: g_clear_pointer (&priv->project_group, g_free); priv->project_group = g_value_dup_string (value); break; case PROP_DEVELOPER: g_clear_pointer (&priv->developer, g_free); priv->developer = g_value_dup_string (value); break; case PROP_DEVELOPER_ID: g_clear_pointer (&priv->developer_id, g_free); priv->developer_id = g_value_dup_string (value); break; case PROP_DEVELOPER_APPS: g_clear_object (&priv->developer_apps); priv->developer_apps = g_value_dup_object (value); break; case PROP_SCREENSHOT_PAINTABLES: g_clear_object (&priv->screenshot_paintables); priv->screenshot_paintables = g_value_dup_object (value); break; case PROP_SCREENSHOT_CAPTIONS: g_clear_object (&priv->screenshot_captions); priv->screenshot_captions = g_value_dup_object (value); break; case PROP_THUMBNAIL_PAINTABLE: g_clear_object (&priv->thumbnail_paintable); priv->thumbnail_paintable = g_value_dup_object (value); break; case PROP_SHARE_URLS: g_clear_object (&priv->share_urls); priv->share_urls = g_value_dup_object (value); break; case PROP_DONATION_URL: g_clear_pointer (&priv->donation_url, g_free); priv->donation_url = g_value_dup_string (value); break; case PROP_FORGE_URL: g_clear_pointer (&priv->forge_url, g_free); priv->forge_url = g_value_dup_string (value); break; case PROP_RATINGS_SUMMARY: g_clear_pointer (&priv->ratings_summary, g_free); priv->ratings_summary = g_value_dup_string (value); break; case PROP_VERSION_HISTORY: g_clear_object (&priv->version_history); priv->version_history = g_value_dup_object (value); break; case PROP_LIGHT_ACCENT_COLOR: g_clear_pointer (&priv->light_accent_color, g_free); priv->light_accent_color = g_value_dup_string (value); break; case PROP_DARK_ACCENT_COLOR: g_clear_pointer (&priv->dark_accent_color, g_free); priv->dark_accent_color = g_value_dup_string (value); break; case PROP_IS_MOBILE_FRIENDLY: priv->is_mobile_friendly = g_value_get_boolean (value); break; case PROP_REQUIRED_CONTROLS: priv->required_controls = g_value_get_flags (value); break; case PROP_RECOMMENDED_CONTROLS: priv->recommended_controls = g_value_get_flags (value); break; case PROP_SUPPORTED_CONTROLS: priv->supported_controls = g_value_get_flags (value); break; case PROP_MIN_DISPLAY_LENGTH: priv->min_display_length = g_value_get_int (value); break; case PROP_MAX_DISPLAY_LENGTH: priv->max_display_length = g_value_get_int (value); break; case PROP_CONTENT_RATING: g_clear_object (&priv->content_rating); priv->content_rating = g_value_dup_object (value); break; case PROP_KEYWORDS: g_clear_object (&priv->keywords); priv->keywords = g_value_dup_object (value); break; case PROP_CATEGORIES: priv->categories = g_value_get_uint (value); break; case PROP_PERMISSIONS: g_clear_object (&priv->permissions); priv->permissions = g_value_dup_object (value); break; case PROP_IS_FLATHUB: priv->is_flathub = g_value_get_boolean (value); break; case PROP_VERIFICATION_STATUS: g_clear_object (&priv->verification_status); priv->verification_status = g_value_dup_object (value); break; case PROP_DOWNLOAD_STATS: case PROP_DOWNLOAD_STATS_PER_COUNTRY: { if (prop_id == PROP_DOWNLOAD_STATS) { g_clear_object (&priv->download_stats); priv->download_stats = g_value_dup_object (value); } else { g_clear_object (&priv->download_stats_per_country); priv->download_stats_per_country = g_value_dup_object (value); } } break; case PROP_RECENT_DOWNLOADS: priv->recent_downloads = g_value_get_int (value); break; case PROP_TOTAL_DOWNLOADS: priv->total_downloads = g_value_get_int (value); break; case PROP_FAVORITES_COUNT: priv->favorites_count = g_value_get_int (value); break; case PROP_HOLDING: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_entry_class_init (BzEntryClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bz_entry_set_property; object_class->get_property = bz_entry_get_property; object_class->dispose = bz_entry_dispose; props[PROP_HOLDING] = g_param_spec_boolean ( "holding", NULL, NULL, FALSE, G_PARAM_READABLE); props[PROP_INSTALLED] = g_param_spec_boolean ( "installed", NULL, NULL, FALSE, G_PARAM_READWRITE); props[PROP_INSTALLED_VERSION] = g_param_spec_string ( "installed-version", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_SEARCHABLE] = g_param_spec_boolean ( "searchable", NULL, NULL, TRUE, G_PARAM_READWRITE); props[PROP_ADDONS] = g_param_spec_object ( "addons", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE); props[PROP_KINDS] = g_param_spec_flags ( "kinds", NULL, NULL, BZ_TYPE_ENTRY_KIND, 0, G_PARAM_READWRITE); props[PROP_ID] = g_param_spec_string ( "id", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_UNIQUE_ID] = g_param_spec_string ( "unique-id", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_UNIQUE_ID_CHECKSUM] = g_param_spec_string ( "unique-id-checksum", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_TITLE] = g_param_spec_string ( "title", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_EOL] = g_param_spec_string ( "eol", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_DESCRIPTION] = g_param_spec_string ( "description", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_LONG_DESCRIPTION] = g_param_spec_string ( "long-description", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_URL] = g_param_spec_string ( "url", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_REMOTE_REPO_NAME] = g_param_spec_string ( "remote-repo-name", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_SIZE] = g_param_spec_uint64 ( "size", NULL, NULL, 0, G_MAXUINT64, 0, G_PARAM_READWRITE); props[PROP_INSTALLED_SIZE] = g_param_spec_uint64 ( "installed-size", NULL, NULL, 0, G_MAXUINT64, 0, G_PARAM_READWRITE); props[PROP_ICON_PAINTABLE] = g_param_spec_object ( "icon-paintable", NULL, NULL, GDK_TYPE_PAINTABLE, G_PARAM_READWRITE); props[PROP_MINI_ICON] = g_param_spec_object ( "mini-icon", NULL, NULL, G_TYPE_ICON, G_PARAM_READWRITE); props[PROP_SEARCH_TOKENS] = g_param_spec_string ( "search-tokens", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_REMOTE_REPO_ICON] = g_param_spec_object ( "remote-repo-icon", NULL, NULL, GDK_TYPE_PAINTABLE, G_PARAM_READWRITE); props[PROP_METADATA_LICENSE] = g_param_spec_string ( "metadata-license", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_PROJECT_LICENSE] = g_param_spec_string ( "project-license", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_IS_FLOSS] = g_param_spec_boolean ( "is-floss", NULL, NULL, FALSE, G_PARAM_READWRITE); props[PROP_PROJECT_GROUP] = g_param_spec_string ( "project-group", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_DEVELOPER] = g_param_spec_string ( "developer", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_DEVELOPER_ID] = g_param_spec_string ( "developer-id", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_DEVELOPER_APPS] = g_param_spec_object ( "developer-apps", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE); props[PROP_SCREENSHOT_PAINTABLES] = g_param_spec_object ( "screenshot-paintables", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE); props[PROP_SCREENSHOT_CAPTIONS] = g_param_spec_object ( "screenshot-captions", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE); props[PROP_THUMBNAIL_PAINTABLE] = g_param_spec_object ( "thumbnail-paintable", NULL, NULL, GDK_TYPE_PAINTABLE, G_PARAM_READWRITE); props[PROP_SHARE_URLS] = g_param_spec_object ( "share-urls", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE); props[PROP_DONATION_URL] = g_param_spec_string ( "donation-url", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_FORGE_URL] = g_param_spec_string ( "forge-url", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_RATINGS_SUMMARY] = g_param_spec_string ( "ratings-summary", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_VERSION_HISTORY] = g_param_spec_object ( "version-history", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE); props[PROP_LIGHT_ACCENT_COLOR] = g_param_spec_string ( "light-accent-color", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_DARK_ACCENT_COLOR] = g_param_spec_string ( "dark-accent-color", NULL, NULL, NULL, G_PARAM_READWRITE); props[PROP_IS_MOBILE_FRIENDLY] = g_param_spec_boolean ( "is-mobile-friendly", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_REQUIRED_CONTROLS] = g_param_spec_flags ( "required-controls", NULL, NULL, BZ_TYPE_CONTROL_TYPE, BZ_CONTROL_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_RECOMMENDED_CONTROLS] = g_param_spec_flags ( "recommended-controls", NULL, NULL, BZ_TYPE_CONTROL_TYPE, BZ_CONTROL_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_SUPPORTED_CONTROLS] = g_param_spec_flags ( "supported-controls", NULL, NULL, BZ_TYPE_CONTROL_TYPE, BZ_CONTROL_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_MIN_DISPLAY_LENGTH] = g_param_spec_int ( "min-display-length", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_MAX_DISPLAY_LENGTH] = g_param_spec_int ( "max-display-length", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_CONTENT_RATING] = g_param_spec_object ( "content-rating", NULL, NULL, AS_TYPE_CONTENT_RATING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_KEYWORDS] = g_param_spec_object ( "keywords", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE); props[PROP_CATEGORIES] = g_param_spec_uint ( "categories", NULL, NULL, 0, G_MAXUINT, BZ_CATEGORY_FLAGS_NONE, G_PARAM_READWRITE); props[PROP_PERMISSIONS] = g_param_spec_object ( "permissions", NULL, NULL, BZ_TYPE_APP_PERMISSIONS, G_PARAM_READWRITE); props[PROP_IS_FLATHUB] = g_param_spec_boolean ( "is-flathub", NULL, NULL, FALSE, G_PARAM_READWRITE); props[PROP_VERIFICATION_STATUS] = g_param_spec_object ( "verification-status", NULL, NULL, BZ_TYPE_VERIFICATION_STATUS, G_PARAM_READWRITE); props[PROP_DOWNLOAD_STATS] = g_param_spec_object ( "download-stats", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE); props[PROP_DOWNLOAD_STATS_PER_COUNTRY] = g_param_spec_object ( "download-stats-per-country", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE); props[PROP_RECENT_DOWNLOADS] = g_param_spec_int ( "recent-downloads", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READWRITE); props[PROP_TOTAL_DOWNLOADS] = g_param_spec_int ( "total-downloads", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READWRITE); props[PROP_FAVORITES_COUNT] = g_param_spec_int ( "favorites-count", NULL, NULL, -1, G_MAXINT, -1, G_PARAM_READWRITE); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_entry_init (BzEntry *self) { BzEntryPrivate *priv = bz_entry_get_instance_private (self); priv->hold = 0; priv->searchable = TRUE; priv->favorites_count = -1; } static void bz_entry_real_serialize (BzSerializable *serializable, GVariantBuilder *builder) { BzEntry *self = BZ_ENTRY (serializable); BzEntryPrivate *priv = bz_entry_get_instance_private (self); g_variant_builder_add (builder, "{sv}", "installed", g_variant_new_boolean (priv->installed)); if (priv->installed_version != NULL) g_variant_builder_add (builder, "{sv}", "installed-version", g_variant_new_string (priv->installed_version)); g_variant_builder_add (builder, "{sv}", "kinds", g_variant_new_uint32 (priv->kinds)); g_variant_builder_add (builder, "{sv}", "searchable", g_variant_new_boolean (priv->searchable)); if (priv->addons != NULL) { guint n_items = 0; n_items = g_list_model_get_n_items (priv->addons); if (n_items > 0) { g_autoptr (GVariantBuilder) sub_builder = NULL; sub_builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); for (guint i = 0; i < n_items; i++) { g_autoptr (GtkStringObject) string = NULL; string = g_list_model_get_item (priv->addons, i); g_variant_builder_add (sub_builder, "s", gtk_string_object_get_string (string)); } g_variant_builder_add (builder, "{sv}", "addons", g_variant_builder_end (sub_builder)); } } if (priv->id != NULL) g_variant_builder_add (builder, "{sv}", "id", g_variant_new_string (priv->id)); if (priv->unique_id != NULL) g_variant_builder_add (builder, "{sv}", "unique-id", g_variant_new_string (priv->unique_id)); if (priv->unique_id_checksum != NULL) g_variant_builder_add (builder, "{sv}", "unique-id-checksum", g_variant_new_string (priv->unique_id_checksum)); if (priv->title != NULL) g_variant_builder_add (builder, "{sv}", "title", g_variant_new_string (priv->title)); if (priv->eol != NULL) g_variant_builder_add (builder, "{sv}", "eol", g_variant_new_string (priv->eol)); if (priv->description != NULL) g_variant_builder_add (builder, "{sv}", "description", g_variant_new_string (priv->description)); if (priv->long_description != NULL) g_variant_builder_add (builder, "{sv}", "long-description", g_variant_new_string (priv->long_description)); if (priv->remote_repo_name != NULL) g_variant_builder_add (builder, "{sv}", "remote-repo-name", g_variant_new_string (priv->remote_repo_name)); if (priv->url != NULL) g_variant_builder_add (builder, "{sv}", "url", g_variant_new_string (priv->url)); if (priv->size > 0) g_variant_builder_add (builder, "{sv}", "size", g_variant_new_uint64 (priv->size)); if (priv->installed_size > 0) g_variant_builder_add (builder, "{sv}", "installed-size", g_variant_new_uint64 (priv->installed_size)); if (priv->icon_paintable != NULL) maybe_save_paintable (priv, "icon-paintable", priv->icon_paintable, builder); if (priv->mini_icon != NULL) { g_autoptr (GVariant) serialized = NULL; serialized = g_icon_serialize (priv->mini_icon); g_variant_builder_add (builder, "{sv}", "mini-icon", serialized); } if (priv->remote_repo_icon != NULL) maybe_save_paintable (priv, "remote-repo-icon", priv->remote_repo_icon, builder); if (priv->search_tokens != NULL) g_variant_builder_add (builder, "{sv}", "search-tokens", g_variant_new_string (priv->search_tokens)); if (priv->metadata_license != NULL) g_variant_builder_add (builder, "{sv}", "metadata-license", g_variant_new_string (priv->metadata_license)); if (priv->project_license != NULL) g_variant_builder_add (builder, "{sv}", "project-license", g_variant_new_string (priv->project_license)); g_variant_builder_add (builder, "{sv}", "is-floss", g_variant_new_boolean (priv->is_floss)); if (priv->project_group != NULL) g_variant_builder_add (builder, "{sv}", "project-group", g_variant_new_string (priv->project_group)); if (priv->developer != NULL) g_variant_builder_add (builder, "{sv}", "developer", g_variant_new_string (priv->developer)); if (priv->developer_id != NULL) g_variant_builder_add (builder, "{sv}", "developer-id", g_variant_new_string (priv->developer_id)); if (priv->screenshot_paintables != NULL) { guint n_items = 0; n_items = g_list_model_get_n_items (priv->screenshot_paintables); if (n_items > 0) { g_autoptr (GVariantBuilder) sub_builder = NULL; sub_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); for (guint i = 0; i < n_items; i++) { g_autoptr (GdkPaintable) paintable = NULL; g_autofree char *key = NULL; paintable = g_list_model_get_item (priv->screenshot_paintables, i); key = g_strdup_printf ("screenshot_%d.png", i); maybe_save_paintable (priv, key, paintable, sub_builder); } g_variant_builder_add (builder, "{sv}", "screenshot-paintables", g_variant_builder_end (sub_builder)); } } if (priv->screenshot_captions != NULL) { guint n_items = 0; n_items = g_list_model_get_n_items (priv->screenshot_captions); if (n_items > 0) { g_autoptr (GVariantBuilder) sub_builder = NULL; sub_builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); for (guint i = 0; i < n_items; i++) { g_autoptr (GtkStringObject) string = NULL; string = g_list_model_get_item (priv->screenshot_captions, i); g_variant_builder_add (sub_builder, "s", gtk_string_object_get_string (string)); } g_variant_builder_add (builder, "{sv}", "screenshot-captions", g_variant_builder_end (sub_builder)); } } if (priv->thumbnail_paintable != NULL) maybe_save_paintable (priv, "thumbnail-paintable", priv->thumbnail_paintable, builder); if (priv->share_urls != NULL) { guint n_items = 0; n_items = g_list_model_get_n_items (priv->share_urls); if (n_items > 0) { g_autoptr (GVariantBuilder) sub_builder = NULL; sub_builder = g_variant_builder_new (G_VARIANT_TYPE ("a(sss)")); for (guint i = 0; i < n_items; i++) { g_autoptr (BzUrl) url = NULL; const char *name = NULL; const char *url_str = NULL; const char *icon_name = NULL; url = g_list_model_get_item (priv->share_urls, i); name = bz_url_get_name (url); url_str = bz_url_get_url (url); icon_name = bz_url_get_icon_name (url); g_variant_builder_add (sub_builder, "(sss)", name, url_str, icon_name ? icon_name : ""); } g_variant_builder_add (builder, "{sv}", "share-urls", g_variant_builder_end (sub_builder)); } } if (priv->donation_url != NULL) g_variant_builder_add (builder, "{sv}", "donation-url", g_variant_new_string (priv->donation_url)); if (priv->forge_url != NULL) g_variant_builder_add (builder, "{sv}", "forge-url", g_variant_new_string (priv->forge_url)); if (priv->version_history != NULL) { guint n_items = 0; n_items = g_list_model_get_n_items (priv->version_history); if (n_items > 0) { g_autoptr (GVariantBuilder) sub_builder = NULL; sub_builder = g_variant_builder_new (G_VARIANT_TYPE ("a(mstmsms)")); for (guint i = 0; i < n_items; i++) { g_autoptr (BzRelease) release = NULL; guint64 timestamp = 0; const char *url = NULL; const char *version = NULL; const char *description = NULL; release = g_list_model_get_item (priv->version_history, i); timestamp = bz_release_get_timestamp (release); url = bz_release_get_url (release); version = bz_release_get_version (release); description = bz_release_get_description (release); g_variant_builder_add ( sub_builder, "(mstmsms)", description, timestamp, url, version); } g_variant_builder_add (builder, "{sv}", "version-history", g_variant_builder_end (sub_builder)); } } if (priv->light_accent_color != NULL) g_variant_builder_add (builder, "{sv}", "light-accent-color", g_variant_new_string (priv->light_accent_color)); if (priv->dark_accent_color != NULL) g_variant_builder_add (builder, "{sv}", "dark-accent-color", g_variant_new_string (priv->dark_accent_color)); g_variant_builder_add (builder, "{sv}", "is-mobile-friendly", g_variant_new_boolean (priv->is_mobile_friendly)); if (priv->required_controls != BZ_CONTROL_NONE) g_variant_builder_add (builder, "{sv}", "required-controls", g_variant_new_uint32 (priv->required_controls)); if (priv->recommended_controls != BZ_CONTROL_NONE) g_variant_builder_add (builder, "{sv}", "recommended-controls", g_variant_new_uint32 (priv->recommended_controls)); if (priv->supported_controls != BZ_CONTROL_NONE) g_variant_builder_add (builder, "{sv}", "supported-controls", g_variant_new_uint32 (priv->supported_controls)); if (priv->min_display_length > 0) g_variant_builder_add (builder, "{sv}", "min-display-length", g_variant_new_int32 (priv->min_display_length)); if (priv->max_display_length > 0) g_variant_builder_add (builder, "{sv}", "max-display-length", g_variant_new_int32 (priv->max_display_length)); if (priv->content_rating != NULL) { const gchar *kind = as_content_rating_get_kind (priv->content_rating); g_autoptr (GVariantBuilder) sub_builder = NULL; g_autofree const gchar **rating_ids = NULL; sub_builder = g_variant_builder_new (G_VARIANT_TYPE ("a(ss)")); rating_ids = as_content_rating_get_all_rating_ids (); for (gsize i = 0; rating_ids[i] != NULL; i++) { AsContentRatingValue value = as_content_rating_get_value (priv->content_rating, rating_ids[i]); const gchar *value_str = as_content_rating_value_to_string (value); if (value != AS_CONTENT_RATING_VALUE_UNKNOWN) g_variant_builder_add (sub_builder, "(ss)", rating_ids[i], value_str); } g_variant_builder_add (builder, "{sv}", "content-rating-kind", g_variant_new_string (kind ? kind : "oars-1.1")); g_variant_builder_add (builder, "{sv}", "content-rating-values", g_variant_builder_end (sub_builder)); } if (priv->keywords != NULL) { guint n_items = 0; n_items = g_list_model_get_n_items (priv->keywords); if (n_items > 0) { g_autoptr (GVariantBuilder) sub_builder = NULL; sub_builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); for (guint i = 0; i < n_items; i++) { g_autoptr (GtkStringObject) string = NULL; string = g_list_model_get_item (priv->keywords, i); g_variant_builder_add (sub_builder, "s", gtk_string_object_get_string (string)); } g_variant_builder_add (builder, "{sv}", "keywords", g_variant_builder_end (sub_builder)); } } if (priv->categories != BZ_CATEGORY_FLAGS_NONE) g_variant_builder_add (builder, "{sv}", "categories", g_variant_new_uint32 (priv->categories)); if (priv->verification_status != NULL) { gboolean verified = FALSE; g_autofree char *method = NULL; g_autofree char *website = NULL; g_autofree char *login_name = NULL; g_autofree char *login_provider = NULL; g_autofree char *timestamp = NULL; gboolean login_is_organization = FALSE; g_object_get (priv->verification_status, "verified", &verified, "method", &method, "website", &website, "login-name", &login_name, "login-provider", &login_provider, "timestamp", ×tamp, "login-is-organization", &login_is_organization, NULL); g_variant_builder_add (builder, "{sv}", "verification-verified", g_variant_new_boolean (verified)); if (method != NULL) g_variant_builder_add (builder, "{sv}", "verification-method", g_variant_new_string (method)); if (website != NULL) g_variant_builder_add (builder, "{sv}", "verification-website", g_variant_new_string (website)); if (login_name != NULL) g_variant_builder_add (builder, "{sv}", "verification-login-name", g_variant_new_string (login_name)); if (login_provider != NULL) g_variant_builder_add (builder, "{sv}", "verification-login-provider", g_variant_new_string (login_provider)); if (timestamp != NULL) g_variant_builder_add (builder, "{sv}", "verification-timestamp", g_variant_new_string (timestamp)); g_variant_builder_add (builder, "{sv}", "verification-login-is-organization", g_variant_new_boolean (login_is_organization)); } if (priv->permissions != NULL) { bz_app_permissions_serialize (priv->permissions, builder); } g_variant_builder_add (builder, "{sv}", "is-flathub", g_variant_new_boolean (priv->is_flathub)); if (priv->is_flathub) { if (priv->flathub_prop_queries != NULL) { if (g_hash_table_contains (priv->flathub_prop_queries, GINT_TO_POINTER (PROP_DOWNLOAD_STATS)) && priv->download_stats != NULL) { guint n_items = 0; n_items = g_list_model_get_n_items (priv->download_stats); if (n_items > 0) { g_autoptr (GVariantBuilder) sub_builder = NULL; sub_builder = g_variant_builder_new (G_VARIANT_TYPE ("a(ddms)")); for (guint i = 0; i < n_items; i++) { g_autoptr (BzDataPoint) point = NULL; double independent = 0.0; double dependent = 0.0; const char *label = NULL; point = g_list_model_get_item (priv->download_stats, i); independent = bz_data_point_get_independent (point); dependent = bz_data_point_get_dependent (point); label = bz_data_point_get_label (point); g_variant_builder_add (sub_builder, "(ddms)", independent, dependent, label); } g_variant_builder_add (builder, "{sv}", "download-stats", g_variant_builder_end (sub_builder)); } } if (g_hash_table_contains (priv->flathub_prop_queries, GINT_TO_POINTER (PROP_RECENT_DOWNLOADS))) g_variant_builder_add (builder, "{sv}", "recent-downloads", g_variant_new_int32 (priv->recent_downloads)); if (g_hash_table_contains (priv->flathub_prop_queries, GINT_TO_POINTER (PROP_FAVORITES_COUNT))) g_variant_builder_add (builder, "{sv}", "favorites-count", g_variant_new_int32 (priv->favorites_count)); } } } static gboolean bz_entry_real_deserialize (BzSerializable *serializable, GVariant *import, GError **error) { BzEntry *self = BZ_ENTRY (serializable); BzEntryPrivate *priv = bz_entry_get_instance_private (self); g_autoptr (GVariantIter) iter = NULL; clear_entry (self); iter = g_variant_iter_new (import); for (;;) { g_autofree char *key = NULL; g_autoptr (GVariant) value = NULL; if (!g_variant_iter_next (iter, "{sv}", &key, &value)) break; if (g_strcmp0 (key, "installed") == 0) priv->installed = g_variant_get_boolean (value); else if (g_strcmp0 (key, "installed-version") == 0) priv->installed_version = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "kinds") == 0) priv->kinds = g_variant_get_uint32 (value); else if (g_strcmp0 (key, "searchable") == 0) priv->searchable = g_variant_get_boolean (value); else if (g_strcmp0 (key, "addons") == 0) { g_autoptr (GListStore) store = NULL; g_autoptr (GVariantIter) addon_iter = NULL; store = g_list_store_new (GTK_TYPE_STRING_OBJECT); addon_iter = g_variant_iter_new (value); for (;;) { g_autofree char *unique_id = NULL; g_autoptr (GtkStringObject) string = NULL; if (!g_variant_iter_next (addon_iter, "s", &unique_id)) break; string = gtk_string_object_new (unique_id); g_list_store_append (store, string); } priv->addons = G_LIST_MODEL (g_steal_pointer (&store)); } else if (g_strcmp0 (key, "id") == 0) priv->id = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "unique-id") == 0) priv->unique_id = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "unique-id-checksum") == 0) priv->unique_id_checksum = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "title") == 0) priv->title = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "eol") == 0) priv->eol = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "description") == 0) priv->description = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "long-description") == 0) priv->long_description = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "remote-repo-name") == 0) priv->remote_repo_name = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "url") == 0) priv->url = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "size") == 0) priv->size = g_variant_get_uint64 (value); else if (g_strcmp0 (key, "installed-size") == 0) priv->installed_size = g_variant_get_uint64 (value); else if (g_strcmp0 (key, "icon-paintable") == 0) priv->icon_paintable = make_async_texture (value); else if (g_strcmp0 (key, "mini-icon") == 0) priv->mini_icon = g_icon_deserialize (value); else if (g_strcmp0 (key, "remote-repo-icon") == 0) priv->remote_repo_icon = make_async_texture (value); else if (g_strcmp0 (key, "search-tokens") == 0) priv->search_tokens = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "metadata-license") == 0) priv->metadata_license = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "project-license") == 0) priv->project_license = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "is-floss") == 0) priv->is_floss = g_variant_get_boolean (value); else if (g_strcmp0 (key, "developer") == 0) priv->developer = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "developer-id") == 0) priv->developer_id = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "screenshot-paintables") == 0) { g_autoptr (GListStore) store = NULL; g_autoptr (GVariantIter) screenshot_iter = NULL; store = g_list_store_new (BZ_TYPE_ASYNC_TEXTURE); screenshot_iter = g_variant_iter_new (value); for (;;) { g_autofree char *basename = NULL; g_autoptr (GVariant) screenshot = NULL; g_autoptr (GdkPaintable) texture = NULL; if (!g_variant_iter_next (screenshot_iter, "{sv}", &basename, &screenshot)) break; texture = make_async_texture (screenshot); g_list_store_append (store, texture); } priv->screenshot_paintables = G_LIST_MODEL (g_steal_pointer (&store)); } else if (g_strcmp0 (key, "screenshot-captions") == 0) { g_autoptr (GListStore) store = NULL; g_autoptr (GVariantIter) caption_iter = NULL; store = g_list_store_new (GTK_TYPE_STRING_OBJECT); caption_iter = g_variant_iter_new (value); for (;;) { g_autofree char *caption = NULL; g_autoptr (GtkStringObject) string = NULL; if (!g_variant_iter_next (caption_iter, "s", &caption)) break; string = gtk_string_object_new (caption); g_list_store_append (store, string); } priv->screenshot_captions = G_LIST_MODEL (g_steal_pointer (&store)); } else if (g_strcmp0 (key, "thumbnail-paintable") == 0) priv->thumbnail_paintable = make_async_texture (value); else if (g_strcmp0 (key, "share-urls") == 0) { g_autoptr (GListStore) store = NULL; g_autoptr (GVariantIter) url_iter = NULL; store = g_list_store_new (BZ_TYPE_URL); url_iter = g_variant_iter_new (value); for (;;) { g_autofree char *name = NULL; g_autofree char *url_str = NULL; g_autoptr (BzUrl) url = NULL; g_autofree char *icon_name = NULL; if (!g_variant_iter_next (url_iter, "(sss)", &name, &url_str, &icon_name)) break; url = bz_url_new (); bz_url_set_name (url, name); bz_url_set_url (url, url_str); bz_url_set_icon_name (url, icon_name); g_list_store_append (store, url); } priv->share_urls = G_LIST_MODEL (g_steal_pointer (&store)); } else if (g_strcmp0 (key, "donation-url") == 0) priv->donation_url = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "forge-url") == 0) priv->forge_url = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "version-history") == 0) { g_autoptr (GListStore) store = NULL; g_autoptr (GVariantIter) version_iter = NULL; store = g_list_store_new (BZ_TYPE_RELEASE); version_iter = g_variant_iter_new (value); for (;;) { guint64 timestamp = 0; g_autofree char *url = NULL; g_autofree char *description = NULL; g_autofree char *version = NULL; g_autoptr (BzRelease) release = NULL; if (!g_variant_iter_next (version_iter, "(mstmsms)", &description, ×tamp, &url, &version)) break; release = bz_release_new (); bz_release_set_timestamp (release, timestamp); bz_release_set_url (release, url); bz_release_set_version (release, version); bz_release_set_description (release, description); g_list_store_append (store, release); } priv->version_history = G_LIST_MODEL (g_steal_pointer (&store)); } else if (g_strcmp0 (key, "light-accent-color") == 0) priv->light_accent_color = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "dark-accent-color") == 0) priv->dark_accent_color = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "is-mobile-friendly") == 0) priv->is_mobile_friendly = g_variant_get_boolean (value); else if (g_strcmp0 (key, "required-controls") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32)) priv->required_controls = g_variant_get_uint32 (value); else if (g_strcmp0 (key, "recommended-controls") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32)) priv->recommended_controls = g_variant_get_uint32 (value); else if (g_strcmp0 (key, "supported-controls") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32)) priv->supported_controls = g_variant_get_uint32 (value); else if (g_strcmp0 (key, "min-display-length") == 0) priv->min_display_length = g_variant_get_int32 (value); else if (g_strcmp0 (key, "max-display-length") == 0) priv->max_display_length = g_variant_get_int32 (value); else if (g_strcmp0 (key, "content-rating-kind") == 0) { g_autofree gchar *kind = NULL; kind = g_variant_dup_string (value, NULL); if (priv->content_rating == NULL) priv->content_rating = as_content_rating_new (); as_content_rating_set_kind (priv->content_rating, kind); } else if (g_strcmp0 (key, "content-rating-values") == 0) { g_autoptr (GVariantIter) rating_iter = NULL; if (priv->content_rating == NULL) priv->content_rating = as_content_rating_new (); rating_iter = g_variant_iter_new (value); for (;;) { g_autofree gchar *rating_id = NULL; g_autofree gchar *rating_value_str = NULL; AsContentRatingValue rating_value; if (!g_variant_iter_next (rating_iter, "(ss)", &rating_id, &rating_value_str)) break; rating_value = as_content_rating_value_from_string (rating_value_str); if (rating_value != AS_CONTENT_RATING_VALUE_UNKNOWN) as_content_rating_set_value (priv->content_rating, rating_id, rating_value); } } else if (g_strcmp0 (key, "keywords") == 0) { g_autoptr (GListStore) store = NULL; g_autoptr (GVariantIter) keywords_iter = NULL; store = g_list_store_new (GTK_TYPE_STRING_OBJECT); keywords_iter = g_variant_iter_new (value); for (;;) { g_autofree char *keyword = NULL; g_autoptr (GtkStringObject) string = NULL; if (!g_variant_iter_next (keywords_iter, "s", &keyword)) break; string = gtk_string_object_new (keyword); g_list_store_append (store, string); } priv->keywords = G_LIST_MODEL (g_steal_pointer (&store)); } else if (g_strcmp0 (key, "categories") == 0) priv->categories = g_variant_get_uint32 (value); else if (g_strcmp0 (key, "verification-verified") == 0) { if (priv->verification_status == NULL) priv->verification_status = bz_verification_status_new (); g_object_set (priv->verification_status, "verified", g_variant_get_boolean (value), NULL); } else if (g_strcmp0 (key, "verification-method") == 0) { if (priv->verification_status == NULL) priv->verification_status = bz_verification_status_new (); g_object_set (priv->verification_status, "method", g_variant_get_string (value, NULL), NULL); } else if (g_strcmp0 (key, "verification-website") == 0) { if (priv->verification_status == NULL) priv->verification_status = bz_verification_status_new (); g_object_set (priv->verification_status, "website", g_variant_get_string (value, NULL), NULL); } else if (g_strcmp0 (key, "verification-login-name") == 0) { if (priv->verification_status == NULL) priv->verification_status = bz_verification_status_new (); g_object_set (priv->verification_status, "login-name", g_variant_get_string (value, NULL), NULL); } else if (g_strcmp0 (key, "verification-login-provider") == 0) { if (priv->verification_status == NULL) priv->verification_status = bz_verification_status_new (); g_object_set (priv->verification_status, "login-provider", g_variant_get_string (value, NULL), NULL); } else if (g_strcmp0 (key, "verification-timestamp") == 0) { if (priv->verification_status == NULL) priv->verification_status = bz_verification_status_new (); g_object_set (priv->verification_status, "timestamp", g_variant_get_string (value, NULL), NULL); } else if (g_strcmp0 (key, "verification-login-is-organization") == 0) { if (priv->verification_status == NULL) priv->verification_status = bz_verification_status_new (); g_object_set (priv->verification_status, "login-is-organization", g_variant_get_boolean (value), NULL); } else if (g_strcmp0 (key, "is-flathub") == 0) priv->is_flathub = g_variant_get_boolean (value); else if (g_str_has_prefix (key, "permissions-")) { continue; } } if (priv->permissions == NULL) priv->permissions = bz_app_permissions_new (); if (!bz_app_permissions_deserialize (priv->permissions, import, error)) { g_warning ("Failed to deserialize app permissions"); } return TRUE; } void bz_entry_hold (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_if_fail (BZ_IS_ENTRY (self)); priv = bz_entry_get_instance_private (self); if (++priv->hold == 1) g_object_notify_by_pspec (G_OBJECT (self), props[PROP_HOLDING]); } void bz_entry_release (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_if_fail (BZ_IS_ENTRY (self)); priv = bz_entry_get_instance_private (self); if (--priv->hold == 0) g_object_notify_by_pspec (G_OBJECT (self), props[PROP_HOLDING]); } gboolean bz_entry_is_holding (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), FALSE); priv = bz_entry_get_instance_private (self); return priv->hold > 0; } gboolean bz_entry_is_installed (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), FALSE); priv = bz_entry_get_instance_private (self); return priv->installed; } void bz_entry_set_installed (BzEntry *self, gboolean installed) { BzEntryPrivate *priv = NULL; g_return_if_fail (BZ_IS_ENTRY (self)); priv = bz_entry_get_instance_private (self); priv->installed = installed; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INSTALLED]); } const char * bz_entry_get_installed_version (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->installed_version; } void bz_entry_set_installed_version (BzEntry *self, const char *version) { BzEntryPrivate *priv = NULL; g_return_if_fail (BZ_IS_ENTRY (self)); priv = bz_entry_get_instance_private (self); g_clear_pointer (&priv->installed_version, g_free); priv->installed_version = g_strdup (version); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INSTALLED_VERSION]); } gboolean bz_entry_is_of_kinds (BzEntry *self, guint kinds) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), FALSE); priv = bz_entry_get_instance_private (self); return (priv->kinds & kinds) == kinds; } gboolean bz_entry_is_searchable (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), TRUE); priv = bz_entry_get_instance_private (self); return priv->searchable; } void bz_entry_append_addon (BzEntry *self, const char *id) { BzEntryPrivate *priv = NULL; g_autoptr (GtkStringObject) string = NULL; g_return_if_fail (BZ_IS_ENTRY (self)); g_return_if_fail (id != NULL); priv = bz_entry_get_instance_private (self); string = gtk_string_object_new (id); if (priv->addons == NULL) { priv->addons = (GListModel *) g_list_store_new (GTK_TYPE_STRING_OBJECT); g_list_store_append (G_LIST_STORE (priv->addons), string); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ADDONS]); } else g_list_store_append (G_LIST_STORE (priv->addons), string); } GListModel * bz_entry_get_addons (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->addons; } const char * bz_entry_get_id (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->id; } const char * bz_entry_get_unique_id (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->unique_id; } const char * bz_entry_get_unique_id_checksum (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->unique_id_checksum; } const char * bz_entry_get_title (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->title; } const char * bz_entry_get_developer (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->developer; } gboolean bz_entry_is_verified (BzEntry *self) { BzEntryPrivate *priv = NULL; gboolean verified = FALSE; g_return_val_if_fail (BZ_IS_ENTRY (self), FALSE); priv = bz_entry_get_instance_private (self); if (priv->verification_status != NULL) g_object_get (priv->verification_status, "verified", &verified, NULL); return verified; } const char * bz_entry_get_eol (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), 0); priv = bz_entry_get_instance_private (self); return priv->eol; } const char * bz_entry_get_description (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->description; } const char * bz_entry_get_long_description (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->long_description; } const char * bz_entry_get_remote_repo_name (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->remote_repo_name; } guint64 bz_entry_get_size (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), 0); priv = bz_entry_get_instance_private (self); return priv->size; } guint64 bz_entry_get_installed_size (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), 0); priv = bz_entry_get_instance_private (self); return priv->installed_size; } GdkPaintable * bz_entry_get_icon_paintable (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->icon_paintable; } GListModel * bz_entry_get_screenshot_paintables (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->screenshot_paintables; } GIcon * bz_entry_get_mini_icon (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->mini_icon; } const char * bz_entry_get_search_tokens (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->search_tokens; } GListModel * bz_entry_get_share_urls (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->share_urls; } const char * bz_entry_get_url (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->url; } const char * bz_entry_get_donation_url (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->donation_url; } const char * bz_entry_get_forge_url (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->forge_url; } BzRepository * bz_entry_get_repository (BzEntry *self, GListModel *repos) { BzEntryPrivate *priv = NULL; guint n_repos = 0; g_auto (GStrv) parts = NULL; const char *scope = NULL; const char *repo_name = NULL; gboolean is_user = FALSE; priv = bz_entry_get_instance_private (self); if (priv->unique_id == NULL) return NULL; parts = g_strsplit (priv->unique_id, "::", -1); if (g_strv_length (parts) < 3) return NULL; scope = parts[0]; repo_name = parts[1]; is_user = g_strcmp0 (scope, "FLATPAK-USER") == 0; n_repos = g_list_model_get_n_items (repos); for (guint i = 0; i < n_repos; i++) { g_autoptr (BzRepository) repo = g_list_model_get_item (repos, i); const char *name = bz_repository_get_name (repo); gboolean repo_is_user = bz_repository_get_is_user (repo); if (repo_is_user == is_user && g_strcmp0 (name, repo_name) == 0) return g_object_ref (repo); } return NULL; } gboolean bz_entry_get_is_foss (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), FALSE); priv = bz_entry_get_instance_private (self); return priv->is_floss; } const char * bz_entry_get_light_accent_color (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->light_accent_color; } const char * bz_entry_get_dark_accent_color (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); priv = bz_entry_get_instance_private (self); return priv->dark_accent_color; } gboolean bz_entry_get_is_mobile_friendly (BzEntry *self) { BzEntryPrivate *priv = bz_entry_get_instance_private (self); g_return_val_if_fail (BZ_IS_ENTRY (self), FALSE); return priv->is_mobile_friendly; } guint bz_entry_get_required_controls (BzEntry *self) { BzEntryPrivate *priv = bz_entry_get_instance_private (self); g_return_val_if_fail (BZ_IS_ENTRY (self), BZ_CONTROL_NONE); return priv->required_controls; } guint bz_entry_get_recommended_controls (BzEntry *self) { BzEntryPrivate *priv = bz_entry_get_instance_private (self); g_return_val_if_fail (BZ_IS_ENTRY (self), BZ_CONTROL_NONE); return priv->recommended_controls; } guint bz_entry_get_supported_controls (BzEntry *self) { BzEntryPrivate *priv = bz_entry_get_instance_private (self); g_return_val_if_fail (BZ_IS_ENTRY (self), BZ_CONTROL_NONE); return priv->supported_controls; } gboolean bz_entry_has_control (BzEntry *self, BzControlType control, BzRelationType relation) { BzEntryPrivate *priv = bz_entry_get_instance_private (self); g_return_val_if_fail (BZ_IS_ENTRY (self), FALSE); switch (relation) { case BZ_RELATION_REQUIRES: return (priv->required_controls & control) != 0; case BZ_RELATION_RECOMMENDS: return (priv->recommended_controls & control) != 0; case BZ_RELATION_SUPPORTS: return (priv->supported_controls & control) != 0; default: return FALSE; } } gint bz_entry_get_min_display_length (BzEntry *self) { BzEntryPrivate *priv = bz_entry_get_instance_private (self); g_return_val_if_fail (BZ_IS_ENTRY (self), 0); return priv->min_display_length; } gint bz_entry_get_max_display_length (BzEntry *self) { BzEntryPrivate *priv = bz_entry_get_instance_private (self); g_return_val_if_fail (BZ_IS_ENTRY (self), 0); return priv->max_display_length; } gboolean bz_entry_supports_form_factor (BzEntry *self, guint available_controls, gint display_length) { BzEntryPrivate *priv = bz_entry_get_instance_private (self); g_return_val_if_fail (BZ_IS_ENTRY (self), FALSE); if (priv->required_controls != BZ_CONTROL_NONE) { if ((priv->required_controls & available_controls) != priv->required_controls) return FALSE; } if (priv->min_display_length > 0 && display_length < priv->min_display_length) return FALSE; if (priv->max_display_length > 0 && display_length > priv->max_display_length) return FALSE; return TRUE; } AsContentRating * bz_entry_get_content_rating (BzEntry *self) { BzEntryPrivate *priv = bz_entry_get_instance_private (self); g_return_val_if_fail (BZ_IS_ENTRY (self), NULL); return priv->content_rating; } BzCategoryFlags bz_entry_get_category_flags (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), BZ_CATEGORY_FLAGS_NONE); priv = bz_entry_get_instance_private (self); return priv->categories; } gboolean bz_entry_get_is_flathub (BzEntry *self) { BzEntryPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_ENTRY (self), FALSE); priv = bz_entry_get_instance_private (self); return priv->is_flathub; } GIcon * bz_load_mini_icon_sync (const char *unique_id_checksum, const char *path) { return load_mini_icon_sync (unique_id_checksum, path); } gint bz_entry_calc_usefulness (BzEntry *self) { BzEntryPrivate *priv = NULL; gint score = 0; g_return_val_if_fail (BZ_IS_ENTRY (self), FALSE); priv = bz_entry_get_instance_private (self); score += priv->is_flathub ? 1000 : 0; score += priv->title != NULL ? 5 : 0; score += priv->description != NULL ? 1 : 0; score += priv->long_description != NULL ? 5 : 0; score += priv->url != NULL ? 1 : 0; score += priv->size > 0 ? 1 : 0; score += priv->icon_paintable != NULL ? 15 : 0; score += priv->remote_repo_icon != NULL ? 1 : 0; score += priv->metadata_license != NULL ? 1 : 0; score += priv->project_license != NULL ? 1 : 0; score += priv->project_group != NULL ? 1 : 0; score += priv->developer != NULL ? 1 : 0; score += priv->developer_id != NULL ? 1 : 0; score += priv->screenshot_paintables != NULL ? 5 : 0; score += priv->share_urls != NULL ? 5 : 0; score -= priv->eol != NULL ? 500 : 0; return score; } void bz_entry_serialize (BzEntry *self, GVariantBuilder *builder) { g_return_if_fail (BZ_IS_ENTRY (self)); g_return_if_fail (builder != NULL); return bz_entry_real_serialize (BZ_SERIALIZABLE (self), builder); } gboolean bz_entry_deserialize (BzEntry *self, GVariant *import, GError **error) { g_return_val_if_fail (BZ_IS_ENTRY (self), FALSE); g_return_val_if_fail (import != NULL, FALSE); return bz_entry_real_deserialize (BZ_SERIALIZABLE (self), import, error); } static void query_flathub (BzEntry *self, int prop) { BzEntryPrivate *priv = NULL; g_autoptr (QueryFlathubData) data = NULL; g_autoptr (DexFuture) future = NULL; gboolean is_download_stat = FALSE; priv = bz_entry_get_instance_private (self); is_download_stat = (prop == PROP_DOWNLOAD_STATS || prop == PROP_DOWNLOAD_STATS_PER_COUNTRY || prop == PROP_RECENT_DOWNLOADS || prop == PROP_TOTAL_DOWNLOADS); if (!is_download_stat && !priv->is_flathub) return; if (priv->id == NULL) return; if (priv->flathub_prop_queries == NULL) priv->flathub_prop_queries = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, dex_unref); else if (g_hash_table_contains (priv->flathub_prop_queries, GINT_TO_POINTER (prop))) return; data = query_flathub_data_new (); g_weak_ref_init (&data->self, self); data->prop = prop; data->id = g_strdup (priv->id); data->developer = g_strdup (priv->developer); future = dex_scheduler_spawn ( bz_get_io_scheduler (), bz_get_dex_stack_size (), (DexFiberFunc) query_flathub_fiber, query_flathub_data_ref (data), query_flathub_data_unref); future = dex_future_then ( future, (DexFutureCallback) query_flathub_then, query_flathub_data_ref (data), query_flathub_data_unref); g_hash_table_replace ( priv->flathub_prop_queries, GINT_TO_POINTER (prop), g_steal_pointer (&future)); } static gint compare_dates (BzDataPoint *a, BzDataPoint *b) { double date_a = bz_data_point_get_independent (a); double date_b = bz_data_point_get_independent (b); return (date_a > date_b) - (date_a < date_b); } static DexFuture * query_flathub_fiber (QueryFlathubData *data) { int prop = data->prop; char *id = data->id; char *developer = data->developer; g_autoptr (GError) local_error = NULL; g_autofree char *request = NULL; g_autoptr (JsonNode) node = NULL; switch (prop) { case PROP_DOWNLOAD_STATS: case PROP_DOWNLOAD_STATS_PER_COUNTRY: case PROP_RECENT_DOWNLOADS: case PROP_TOTAL_DOWNLOADS: request = g_strdup_printf ("/stats/%s?all=false&days=175", id); break; case PROP_DEVELOPER_APPS: request = g_strdup_printf ("/collection/developer/%s", developer); break; case PROP_FAVORITES_COUNT: request = g_strdup_printf ("/favorites/%s/count", id); break; default: g_assert_not_reached (); return NULL; } node = dex_await_boxed (bz_query_flathub_v2_json (request), &local_error); if (node == NULL) { if (!g_error_matches (local_error, DEX_ERROR, DEX_ERROR_FIBER_CANCELLED)) g_warning ("Could not retrieve property %s for %s from flathub: %s", props[prop]->name, id, local_error->message); return dex_future_new_for_error (g_steal_pointer (&local_error)); } switch (prop) { case PROP_DOWNLOAD_STATS: { JsonObject *root = NULL; JsonObject *per_day = NULL; g_autoptr (GListStore) store = NULL; if (!JSON_NODE_HOLDS_OBJECT (node)) { g_debug ("No data for property %s for %s from flathub", props[prop]->name, id); return dex_future_new_for_error ( g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Unexpected JSON response format")); } root = json_node_get_object (node); per_day = json_object_get_object_member (root, "installs_per_day"); store = g_list_store_new (BZ_TYPE_DATA_POINT); json_object_foreach_member ( per_day, (JsonObjectForeach) download_stats_per_day_foreach, store); g_list_store_sort (store, (GCompareDataFunc) compare_dates, NULL); return dex_future_new_for_object (store); } break; case PROP_DOWNLOAD_STATS_PER_COUNTRY: { JsonObject *per_country = NULL; g_autoptr (GListStore) store = NULL; per_country = json_object_get_object_member ( json_node_get_object (node), "installs_per_country"); store = g_list_store_new (BZ_TYPE_COUNTRY_DATA_POINT); json_object_foreach_member ( per_country, (JsonObjectForeach) download_stats_per_country_foreach, store); return dex_future_new_for_object (store); } break; case PROP_RECENT_DOWNLOADS: { int recent_downloads = 0; if (json_object_has_member (json_node_get_object (node), "installs_last_month")) recent_downloads = json_object_get_int_member (json_node_get_object (node), "installs_last_month"); return dex_future_new_for_int (recent_downloads); } break; case PROP_TOTAL_DOWNLOADS: { int total_downloads = 0; if (json_object_has_member (json_node_get_object (node), "installs_total")) total_downloads = json_object_get_int_member (json_node_get_object (node), "installs_total"); return dex_future_new_for_int (total_downloads); } break; case PROP_DEVELOPER_APPS: { JsonObject *response_obj = NULL; JsonArray *apps_array = NULL; g_autoptr (GtkStringList) app_ids = NULL; response_obj = json_node_get_object (node); apps_array = json_object_get_array_member (response_obj, "hits"); app_ids = gtk_string_list_new (NULL); for (guint i = 0; i < json_array_get_length (apps_array); i++) { JsonObject *app_obj = json_array_get_object_element (apps_array, i); const char *app_id = json_object_get_string_member (app_obj, "app_id"); if (app_id != NULL) gtk_string_list_append (app_ids, app_id); } return dex_future_new_for_object (app_ids); } break; case PROP_FAVORITES_COUNT: { int favorites_count = 0; if (json_object_has_member (json_node_get_object (node), "favorites_count")) favorites_count = json_object_get_int_member (json_node_get_object (node), "favorites_count"); return dex_future_new_for_int (favorites_count); } break; default: g_assert_not_reached (); return NULL; } } static DexFuture * query_flathub_then (DexFuture *future, QueryFlathubData *data) { g_autoptr (BzEntry) self = NULL; int prop = data->prop; const GValue *value = NULL; self = g_weak_ref_get (&data->self); if (self == NULL) return NULL; value = dex_future_get_value (future, NULL); g_object_set_property (G_OBJECT (self), props[prop]->name, value); return NULL; } static void download_stats_per_day_foreach (JsonObject *object, const gchar *member_name, JsonNode *member_node, GListStore *store) { double independent = 0; double dependent = 0; g_autoptr (BzDataPoint) point = NULL; g_autoptr (GDateTime) date = NULL; g_autofree char *formatted_label = NULL; g_autofree char *iso_with_tz = NULL; dependent = json_node_get_int (member_node); iso_with_tz = g_strdup_printf ("%sT00:00:00Z", member_name); date = g_date_time_new_from_iso8601 (iso_with_tz, NULL); formatted_label = g_date_time_format (date, "%-d %b"); independent = (double) g_date_time_to_unix (date); point = g_object_new ( BZ_TYPE_DATA_POINT, "independent", independent, "dependent", dependent, "label", formatted_label, NULL); g_list_store_append (store, point); } static void download_stats_per_country_foreach (JsonObject *object, const gchar *member_name, JsonNode *member_node, GListStore *store) { guint downloads = 0; g_autoptr (BzCountryDataPoint) point = NULL; downloads = json_node_get_int (member_node); point = g_object_new ( BZ_TYPE_COUNTRY_DATA_POINT, "country-code", member_name, "downloads", downloads, NULL); g_list_store_append (store, point); } static gboolean maybe_save_paintable (BzEntryPrivate *priv, const char *key, GdkPaintable *paintable, GVariantBuilder *builder) { g_autoptr (GError) local_error = NULL; const char *source_uri = NULL; const char *cache_into_path = NULL; g_autoptr (GdkTexture) texture = NULL; g_autoptr (GFile) save_file = NULL; gboolean result = FALSE; if (!BZ_IS_ASYNC_TEXTURE (paintable)) { return FALSE; } source_uri = bz_async_texture_get_source_uri (BZ_ASYNC_TEXTURE (paintable)); cache_into_path = bz_async_texture_get_cache_into_path (BZ_ASYNC_TEXTURE (paintable)); if (cache_into_path == NULL) goto done; if (bz_async_texture_get_loaded (BZ_ASYNC_TEXTURE (paintable))) texture = bz_async_texture_dup_texture (BZ_ASYNC_TEXTURE (paintable)); else goto done; save_file = g_file_new_for_path (cache_into_path); if (!g_file_query_exists (save_file, NULL)) { g_autoptr (GFile) parent_file = NULL; g_autoptr (GBytes) png_bytes = NULL; g_autoptr (GFileOutputStream) output = NULL; gssize bytes_written = 0; parent_file = g_file_get_parent (save_file); result = g_file_make_directory_with_parents ( parent_file, NULL, &local_error); if (!result) { if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS)) g_clear_pointer (&local_error, g_error_free); else { g_warning ("Couldn't serialize texture to %s: %s\n", cache_into_path, local_error->message); goto done; } } png_bytes = gdk_texture_save_to_png_bytes (texture); if (png_bytes == NULL) goto done; output = g_file_replace ( save_file, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL, &local_error); if (output == NULL) { g_warning ("Couldn't serialize texture to %s: %s\n", cache_into_path, local_error->message); goto done; } bytes_written = g_output_stream_write_bytes ( G_OUTPUT_STREAM (output), png_bytes, NULL, &local_error); if (bytes_written < 0) { g_warning ("Couldn't serialize texture to %s: %s\n", cache_into_path, local_error->message); goto done; } result = g_output_stream_close (G_OUTPUT_STREAM (output), NULL, &local_error); if (!result) { g_warning ("Couldn't serialize texture to %s: %s\n", cache_into_path, local_error->message); goto done; } } done: g_variant_builder_add (builder, "{sv}", key, g_variant_new ("(sms)", source_uri, cache_into_path)); return TRUE; } static GdkPaintable * make_async_texture (GVariant *parse) { g_autofree char *source = NULL; g_autofree char *cache_into = NULL; g_autoptr (GFile) source_file = NULL; g_autoptr (GFile) cache_into_file = NULL; g_autoptr (BzAsyncTexture) texture = NULL; g_variant_get (parse, "(sms)", &source, &cache_into); source_file = g_file_new_for_uri (source); if (cache_into != NULL) cache_into_file = g_file_new_for_path (cache_into); texture = bz_async_texture_new_lazy (source_file, cache_into_file); return GDK_PAINTABLE (g_steal_pointer (&texture)); } static GIcon * load_mini_icon_sync (const char *unique_id_checksum, const char *path) { g_autofree char *main_cache = NULL; g_autoptr (GString) mini_icon_basename = NULL; g_autofree char *mini_icon_path = NULL; g_autoptr (GBytes) bytes = NULL; cairo_surface_t *surface_in = NULL; int width = 0; int height = 0; cairo_surface_t *surface_out = NULL; cairo_t *cairo = NULL; g_autoptr (GFile) parent_file = NULL; g_autoptr (GFile) mini_icon_file = NULL; g_autoptr (GIcon) mini_icon = NULL; main_cache = bz_dup_module_dir (); mini_icon_basename = g_string_new (unique_id_checksum); g_string_append (mini_icon_basename, "-24x24.png"); mini_icon_path = g_build_filename (main_cache, mini_icon_basename->str, NULL); if (g_file_test (mini_icon_path, G_FILE_TEST_EXISTS)) /* Assume the icon left behind by last writer */ goto done; surface_in = cairo_image_surface_create_from_png (path); width = cairo_image_surface_get_width (surface_in); height = cairo_image_surface_get_height (surface_in); /* 24x24 for the gnome-shell search provider */ surface_out = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 24, 24); cairo = cairo_create (surface_out); cairo_scale (cairo, 24.0 / (double) width, 24.0 / (double) height); cairo_set_source_surface (cairo, surface_in, 0, 0); cairo_paint (cairo); cairo_restore (cairo); parent_file = g_file_new_for_path (main_cache); g_file_make_directory_with_parents (parent_file, NULL, NULL); cairo_surface_flush (surface_out); cairo_surface_write_to_png (surface_out, mini_icon_path); cairo_destroy (cairo); cairo_surface_destroy (surface_in); cairo_surface_destroy (surface_out); done: mini_icon_file = g_file_new_for_path (mini_icon_path); mini_icon = g_file_icon_new (mini_icon_file); return g_steal_pointer (&mini_icon); } static void clear_entry (BzEntry *self) { BzEntryPrivate *priv = bz_entry_get_instance_private (self); dex_clear (&priv->mini_icon_future); g_clear_pointer (&priv->flathub_prop_queries, g_hash_table_unref); g_clear_object (&priv->addons); g_clear_pointer (&priv->id, g_free); g_clear_pointer (&priv->unique_id, g_free); g_clear_pointer (&priv->unique_id_checksum, g_free); g_clear_pointer (&priv->installed_version, g_free); g_clear_pointer (&priv->title, g_free); g_clear_pointer (&priv->eol, g_free); g_clear_pointer (&priv->description, g_free); g_clear_pointer (&priv->long_description, g_free); g_clear_pointer (&priv->remote_repo_name, g_free); g_clear_pointer (&priv->url, g_free); g_clear_object (&priv->icon_paintable); g_clear_object (&priv->mini_icon); g_clear_object (&priv->remote_repo_icon); g_clear_pointer (&priv->search_tokens, g_free); g_clear_pointer (&priv->metadata_license, g_free); g_clear_pointer (&priv->project_license, g_free); g_clear_pointer (&priv->project_group, g_free); g_clear_pointer (&priv->developer, g_free); g_clear_pointer (&priv->developer_id, g_free); g_clear_object (&priv->developer_apps); g_clear_object (&priv->screenshot_paintables); g_clear_object (&priv->screenshot_captions); g_clear_object (&priv->thumbnail_paintable); g_clear_object (&priv->share_urls); g_clear_pointer (&priv->donation_url, g_free); g_clear_pointer (&priv->forge_url, g_free); g_clear_pointer (&priv->ratings_summary, g_free); g_clear_object (&priv->version_history); g_clear_pointer (&priv->light_accent_color, g_free); g_clear_pointer (&priv->dark_accent_color, g_free); g_clear_object (&priv->verification_status); g_clear_object (&priv->download_stats); g_clear_object (&priv->download_stats_per_country); g_clear_object (&priv->content_rating); g_clear_object (&priv->keywords); g_clear_object (&priv->permissions); } bazaar-orig-v0.7.14/src/bz-apps-page.c0000664000175000017500000003606115166123241016367 0ustar hasanhasan/* bz-apps-page.c * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include #include "bz-all-apps-page.h" #include "bz-app-tile.h" #include "bz-application.h" #include "bz-apps-page.h" #include "bz-dynamic-list-view.h" #include "bz-entry-group.h" #include "bz-env.h" #include "bz-flathub-category.h" #include "bz-subcategory-list.h" #include "bz-state-info.h" struct _BzAppsPage { AdwNavigationPage parent_instance; char *title; GListModel *applications; GListModel *all_applications; GListModel *carousel_applications; char *subtitle; BzFlathubCategory *category; /* Template widgets */ }; G_DEFINE_FINAL_TYPE (BzAppsPage, bz_apps_page, ADW_TYPE_NAVIGATION_PAGE) enum { PROP_0, PROP_PAGE_TITLE, PROP_APPLICATIONS, PROP_ALL_APPLICATIONS, PROP_CAROUSEL_APPLICATIONS, PROP_PAGE_SUBTITLE, PROP_CATEGORY, PROP_FLATHUB_STATE, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void tile_clicked (BzEntryGroup *group, GtkButton *button); static void bz_apps_page_dispose (GObject *object) { BzAppsPage *self = BZ_APPS_PAGE (object); g_clear_pointer (&self->title, g_free); g_clear_object (&self->applications); g_clear_object (&self->all_applications); g_clear_object (&self->carousel_applications); g_clear_pointer (&self->subtitle, g_free); g_clear_object (&self->category); G_OBJECT_CLASS (bz_apps_page_parent_class)->dispose (object); } static void bz_apps_page_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzAppsPage *self = BZ_APPS_PAGE (object); switch (prop_id) { case PROP_PAGE_TITLE: g_value_set_string (value, self->title); break; case PROP_APPLICATIONS: g_value_set_object (value, self->applications); break; case PROP_ALL_APPLICATIONS: g_value_set_object (value, self->all_applications); break; case PROP_CAROUSEL_APPLICATIONS: g_value_set_object (value, self->carousel_applications); break; case PROP_PAGE_SUBTITLE: g_value_set_string (value, self->subtitle); break; case PROP_CATEGORY: g_value_set_object (value, self->category); break; case PROP_FLATHUB_STATE: g_value_set_object (value, bz_state_info_get_flathub(bz_state_info_get_default ())); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_apps_page_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzAppsPage *self = BZ_APPS_PAGE (object); switch (prop_id) { case PROP_PAGE_TITLE: g_clear_pointer (&self->title, g_free); self->title = g_value_dup_string (value); break; case PROP_APPLICATIONS: g_clear_object (&self->applications); self->applications = g_value_dup_object (value); break; case PROP_ALL_APPLICATIONS: g_clear_object (&self->all_applications); self->all_applications = g_value_dup_object (value); break; case PROP_CAROUSEL_APPLICATIONS: g_clear_object (&self->carousel_applications); self->carousel_applications = g_value_dup_object (value); break; case PROP_PAGE_SUBTITLE: g_clear_pointer (&self->subtitle, g_free); self->subtitle = g_value_dup_string (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bind_widget_cb (BzAppsPage *self, BzAppTile *tile, BzEntryGroup *group, BzDynamicListView *view) { g_signal_connect_swapped (tile, "clicked", G_CALLBACK (tile_clicked), group); } static void unbind_widget_cb (BzAppsPage *self, BzAppTile *tile, BzEntryGroup *group, BzDynamicListView *view) { g_signal_handlers_disconnect_by_func (tile, G_CALLBACK (tile_clicked), group); } static gboolean is_not_null (gpointer object, GObject *value) { return value != NULL; } static gboolean is_not_empty_string (gpointer object, const char *str) { return str != NULL && str[0] != '\0'; } static gboolean is_not_empty_list (gpointer object, GListModel *list) { return list != NULL && g_list_model_get_n_items (list) > 0; } static void featured_carousel_group_clicked_cb (BzAppsPage *self, BzEntryGroup *group, GtkWidget *carousel) { gtk_widget_activate_action (GTK_WIDGET (self), "window.show-group", "s", bz_entry_group_get_id (group)); } static void show_all_cb (BzAppsPage *self, GtkButton *button) { GtkWidget *nav_view = NULL; AdwNavigationPage *all_page = NULL; g_autofree char *all_title = NULL; guint n_items = 0; g_return_if_fail (BZ_IS_APPS_PAGE (self)); if (self->all_applications == NULL) return; n_items = g_list_model_get_n_items (self->all_applications); if (n_items == 0) return; nav_view = gtk_widget_get_ancestor (GTK_WIDGET (self), ADW_TYPE_NAVIGATION_VIEW); if (nav_view == NULL) return; all_title = g_strdup_printf (_("All \"%s\""), self->title); all_page = bz_all_apps_page_new (all_title, g_object_ref (self->all_applications)); if (all_page == NULL) return; adw_navigation_view_push (ADW_NAVIGATION_VIEW (nav_view), all_page); } static void bz_apps_page_class_init (BzAppsPageClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_apps_page_dispose; object_class->get_property = bz_apps_page_get_property; object_class->set_property = bz_apps_page_set_property; props[PROP_PAGE_TITLE] = g_param_spec_string ( "page-title", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); props[PROP_APPLICATIONS] = g_param_spec_object ( "applications", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); props[PROP_ALL_APPLICATIONS] = g_param_spec_object ( "all-applications", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE); props[PROP_CAROUSEL_APPLICATIONS] = g_param_spec_object ( "carousel-applications", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); props[PROP_PAGE_SUBTITLE] = g_param_spec_string ( "page-subtitle", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_CATEGORY] = g_param_spec_object ( "category", NULL, NULL, BZ_TYPE_FLATHUB_CATEGORY, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_FLATHUB_STATE] = g_param_spec_object ( "flathub-state", NULL, NULL, BZ_TYPE_FLATHUB_STATE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_APP_TILE); g_type_ensure (BZ_TYPE_SUBCATEGORY_LIST); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-apps-page.ui"); gtk_widget_class_bind_template_callback (widget_class, is_not_null); gtk_widget_class_bind_template_callback (widget_class, is_not_empty_string); gtk_widget_class_bind_template_callback (widget_class, is_not_empty_list); gtk_widget_class_bind_template_callback (widget_class, bind_widget_cb); gtk_widget_class_bind_template_callback (widget_class, unbind_widget_cb); gtk_widget_class_bind_template_callback (widget_class, featured_carousel_group_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, show_all_cb); } static void bz_apps_page_init (BzAppsPage *self) { gtk_widget_init_template (GTK_WIDGET (self)); } AdwNavigationPage * bz_apps_page_new (const char *title, GListModel *applications) { return bz_apps_page_new_with_carousel (title, applications, NULL); } AdwNavigationPage * bz_apps_page_new_with_carousel (const char *title, GListModel *applications, GListModel *carousel_applications) { BzAppsPage *apps_page = NULL; apps_page = g_object_new ( BZ_TYPE_APPS_PAGE, "page-title", title, "applications", applications, "carousel-applications", carousel_applications, NULL); adw_navigation_page_set_title (ADW_NAVIGATION_PAGE (apps_page), title); return ADW_NAVIGATION_PAGE (apps_page); } static gboolean filter_by_category (BzEntryGroup *group, const char *category_name) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (group), FALSE); g_return_val_if_fail (category_name != NULL, FALSE); return bz_entry_group_has_category (group, category_name); } static DexFuture * filter_applications_fiber (BzAppsPage *self) { g_autoptr (GError) error = NULL; g_autoptr (GtkFilterListModel) filtered_model = NULL; GListModel *all_model = NULL; const char *category_name = NULL; BzStateInfo *state_info = NULL; state_info = bz_state_info_get_default (); if (state_info == NULL) return NULL; all_model = bz_state_info_get_filtered_entry_groups (state_info); if (all_model == NULL) return NULL; category_name = g_object_get_data (G_OBJECT (self), "category-name"); if (category_name == NULL) return NULL; filtered_model = gtk_filter_list_model_new ( g_object_ref (all_model), GTK_FILTER (gtk_custom_filter_new ( (GtkCustomFilterFunc) filter_by_category, g_strdup (category_name), g_free))); g_set_object (&self->all_applications, G_LIST_MODEL (filtered_model)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ALL_APPLICATIONS]); return NULL; } static AdwNavigationPage * create_split_page (const char *title, GListModel *model, GListModel *carousel_model) { AdwNavigationPage *apps_page = NULL; guint n_items = g_list_model_get_n_items (model); if (n_items > 48) { g_autoptr (GListModel) limited_model = NULL; limited_model = G_LIST_MODEL (gtk_slice_list_model_new ( g_object_ref (model), 0, 48)); if (carousel_model != NULL && g_list_model_get_n_items (carousel_model) > 0) apps_page = bz_apps_page_new_with_carousel (title, limited_model, carousel_model); else apps_page = bz_apps_page_new (title, limited_model); if (g_set_object (&BZ_APPS_PAGE (apps_page)->all_applications, model)) g_object_notify_by_pspec (G_OBJECT (apps_page), props[PROP_ALL_APPLICATIONS]); } else { if (carousel_model != NULL && g_list_model_get_n_items (carousel_model) > 0) apps_page = bz_apps_page_new_with_carousel (title, model, carousel_model); else apps_page = bz_apps_page_new (title, model); } return apps_page; } static AdwNavigationPage * create_standard_page (const char *title, GListModel *model, GListModel *carousel_model) { if (carousel_model != NULL && g_list_model_get_n_items (carousel_model) > 0) return bz_apps_page_new_with_carousel (title, model, carousel_model); else return bz_apps_page_new (title, model); } static void setup_category_filter (AdwNavigationPage *apps_page, const char *category_name) { if (apps_page == NULL || category_name == NULL || g_strcmp0 (category_name, "adwaita") == 0) return; g_object_set_data_full (G_OBJECT (apps_page), "category-name", g_strdup (category_name), g_free); dex_future_disown (dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) filter_applications_fiber, g_object_ref (apps_page), g_object_unref)); } AdwNavigationPage * bz_apps_page_new_from_category (BzFlathubCategory *category) { g_autoptr (GListModel) model = NULL; g_autoptr (GListModel) carousel_model = NULL; AdwNavigationPage *apps_page = NULL; const char *title = NULL; const char *category_name = NULL; g_autofree char *subtitle = NULL; int total_entries = 0; guint n_items = 0; g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY (category), NULL); model = bz_flathub_category_dup_applications (category); if (model == NULL) return NULL; title = bz_flathub_category_get_display_name (category); category_name = bz_flathub_category_get_name (category); n_items = g_list_model_get_n_items (model); carousel_model = bz_flathub_category_dup_quality_applications (category); total_entries = bz_flathub_category_get_total_entries (category); if (n_items > 48) apps_page = create_split_page (title, model, carousel_model); else apps_page = create_standard_page (title, model, carousel_model); if (total_entries > 0 && !bz_flathub_category_get_is_spotlight (category)) { subtitle = g_strdup_printf (_ ("%d Applications"), total_entries); bz_apps_page_set_subtitle (BZ_APPS_PAGE (apps_page), subtitle); } BZ_APPS_PAGE(apps_page)->category = g_object_ref (category); g_object_notify_by_pspec (G_OBJECT (apps_page), props[PROP_CATEGORY]); if (n_items <= 48) setup_category_filter (apps_page, category_name); return apps_page; } void bz_apps_page_set_subtitle (BzAppsPage *self, const char *subtitle) { g_return_if_fail (BZ_IS_APPS_PAGE (self)); if (g_strcmp0 (self->subtitle, subtitle) == 0) return; g_clear_pointer (&self->subtitle, g_free); if (subtitle != NULL) self->subtitle = g_strdup (subtitle); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PAGE_SUBTITLE]); } static void tile_clicked (BzEntryGroup *group, GtkButton *button) { gtk_widget_activate_action (GTK_WIDGET (button), "window.show-group", "s", bz_entry_group_get_id (group)); } bazaar-orig-v0.7.14/src/bz-curated-view.h0000664000175000017500000000232015166123241017105 0ustar hasanhasan/* bz-curated-view.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-content-provider.h" #include "bz-state-info.h" G_BEGIN_DECLS #define BZ_TYPE_CURATED_VIEW (bz_curated_view_get_type ()) G_DECLARE_FINAL_TYPE (BzCuratedView, bz_curated_view, BZ, CURATED_VIEW, AdwBin) GtkWidget * bz_curated_view_new (void); void bz_curated_view_set_state (BzCuratedView *self, BzStateInfo *state); BzStateInfo * bz_curated_view_get_state (BzCuratedView *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-hooks.h0000664000175000017500000000244015166123241015634 0ustar hasanhasan/* bz-hooks.h * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry-group.h" #include "bz-hook.h" G_BEGIN_DECLS DexFuture * bz_execute_hook (BzHook *hook, BzHookTransactionType ts_type, const char *ts_appid, BzEntryGroup *group); DexFuture * bz_run_hook_emission (GListModel *hooks, BzHookSignal signal, BzHookTransactionType ts_type, const char *ts_appid, BzEntryGroup *group); G_END_DECLS bazaar-orig-v0.7.14/src/bz-global-progress.c0000664000175000017500000002631415166123241017614 0ustar hasanhasan/* bz-global-progress.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include "bz-global-progress.h" #include "progress-bar-designs/common.h" struct _BzGlobalProgress { AdwBin parent_instance; GtkWidget *wdgt; BgeWdgtSpec *wdgt_spec; char *draw_widget_class; BzStateInfo *state; gboolean active; gboolean pending; double fraction; int expand_size; GSettings *settings; }; G_DEFINE_FINAL_TYPE (BzGlobalProgress, bz_global_progress, ADW_TYPE_BIN) enum { PROP_0, PROP_ACTIVE, PROP_PENDING, PROP_EXPAND_SIZE, PROP_STATE, PROP_SETTINGS, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void global_progress_bar_flag_changed (BzGlobalProgress *self, const char *key, GSettings *settings); static void set_wdgt_state (BzGlobalProgress *self); static void ensure_draw_css (BzGlobalProgress *self); static void bz_global_progress_dispose (GObject *object) { BzGlobalProgress *self = BZ_GLOBAL_PROGRESS (object); if (self->settings != NULL) g_signal_handlers_disconnect_by_func ( self->settings, global_progress_bar_flag_changed, self); g_clear_object (&self->wdgt_spec); g_clear_object (&self->state); g_clear_object (&self->settings); G_OBJECT_CLASS (bz_global_progress_parent_class)->dispose (object); } static void bz_global_progress_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzGlobalProgress *self = BZ_GLOBAL_PROGRESS (object); switch (prop_id) { case PROP_ACTIVE: g_value_set_boolean (value, bz_global_progress_get_active (self)); break; case PROP_PENDING: g_value_set_boolean (value, bz_global_progress_get_pending (self)); break; case PROP_EXPAND_SIZE: g_value_set_int (value, bz_global_progress_get_expand_size (self)); break; case PROP_STATE: g_value_set_object (value, bz_global_progress_get_state (self)); break; case PROP_SETTINGS: g_value_set_object (value, bz_global_progress_get_settings (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_global_progress_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzGlobalProgress *self = BZ_GLOBAL_PROGRESS (object); switch (prop_id) { case PROP_ACTIVE: bz_global_progress_set_active (self, g_value_get_boolean (value)); break; case PROP_PENDING: bz_global_progress_set_pending (self, g_value_get_boolean (value)); break; case PROP_EXPAND_SIZE: bz_global_progress_set_expand_size (self, g_value_get_int (value)); break; case PROP_STATE: bz_global_progress_set_state (self, g_value_get_object (value)); break; case PROP_SETTINGS: bz_global_progress_set_settings (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_global_progress_class_init (BzGlobalProgressClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_global_progress_dispose; object_class->get_property = bz_global_progress_get_property; object_class->set_property = bz_global_progress_set_property; props[PROP_ACTIVE] = g_param_spec_boolean ( "active", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_PENDING] = g_param_spec_boolean ( "pending", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_EXPAND_SIZE] = g_param_spec_int ( "expand-size", NULL, NULL, 0, G_MAXINT, 100, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_STATE] = g_param_spec_object ( "state", NULL, NULL, BZ_TYPE_STATE_INFO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_SETTINGS] = g_param_spec_object ( "settings", NULL, NULL, G_TYPE_SETTINGS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); gtk_widget_class_set_css_name (widget_class, "global-progress"); } static void bz_global_progress_init (BzGlobalProgress *self) { self->wdgt_spec = bge_wdgt_spec_new_for_resource ("/io/github/kolunmi/Bazaar/bz-global-progress.wdgt", NULL); g_assert (self->wdgt_spec != NULL); self->wdgt = (GtkWidget *) bge_wdgt_renderer_new (); adw_bin_set_child (ADW_BIN (self), self->wdgt); bge_wdgt_renderer_set_state (BGE_WDGT_RENDERER (self->wdgt), "inactive"); bge_wdgt_renderer_set_spec (BGE_WDGT_RENDERER (self->wdgt), self->wdgt_spec); } GtkWidget * bz_global_progress_new (void) { return g_object_new (BZ_TYPE_GLOBAL_PROGRESS, NULL); } void bz_global_progress_set_active (BzGlobalProgress *self, gboolean active) { g_return_if_fail (BZ_IS_GLOBAL_PROGRESS (self)); if ((active && self->active) || (!active && !self->active)) return; self->active = active; set_wdgt_state (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ACTIVE]); } gboolean bz_global_progress_get_active (BzGlobalProgress *self) { g_return_val_if_fail (BZ_IS_GLOBAL_PROGRESS (self), FALSE); return self->active; } void bz_global_progress_set_pending (BzGlobalProgress *self, gboolean pending) { g_return_if_fail (BZ_IS_GLOBAL_PROGRESS (self)); if ((pending && self->pending) || (!pending && !self->pending)) return; self->pending = pending; set_wdgt_state (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PENDING]); } gboolean bz_global_progress_get_pending (BzGlobalProgress *self) { g_return_val_if_fail (BZ_IS_GLOBAL_PROGRESS (self), FALSE); return self->pending; } void bz_global_progress_set_expand_size (BzGlobalProgress *self, int expand_size) { g_return_if_fail (BZ_IS_GLOBAL_PROGRESS (self)); self->expand_size = MAX (expand_size, 0); gtk_widget_queue_resize (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_EXPAND_SIZE]); } int bz_global_progress_get_expand_size (BzGlobalProgress *self) { g_return_val_if_fail (BZ_IS_GLOBAL_PROGRESS (self), FALSE); return self->expand_size; } void bz_global_progress_set_state (BzGlobalProgress *self, BzStateInfo *state) { g_return_if_fail (BZ_IS_GLOBAL_PROGRESS (self)); g_return_if_fail (state == NULL || BZ_IS_STATE_INFO (state)); g_clear_object (&self->state); if (state != NULL) self->state = g_object_ref (state); bge_wdgt_renderer_set_reference (BGE_WDGT_RENDERER (self->wdgt), (GObject *) state); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_STATE]); } BzStateInfo * bz_global_progress_get_state (BzGlobalProgress *self) { g_return_val_if_fail (BZ_IS_GLOBAL_PROGRESS (self), NULL); return self->state; } void bz_global_progress_set_settings (BzGlobalProgress *self, GSettings *settings) { g_return_if_fail (BZ_IS_GLOBAL_PROGRESS (self)); if (self->settings != NULL) g_signal_handlers_disconnect_by_func ( self->settings, global_progress_bar_flag_changed, self); g_clear_object (&self->settings); if (settings != NULL) { self->settings = g_object_ref (settings); g_signal_connect_swapped ( self->settings, "changed::global-progress-bar-theme", G_CALLBACK (global_progress_bar_flag_changed), self); g_signal_connect_swapped ( self->settings, "changed::rotate-flag", G_CALLBACK (global_progress_bar_flag_changed), self); } ensure_draw_css (self); gtk_widget_queue_draw (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SETTINGS]); } GSettings * bz_global_progress_get_settings (BzGlobalProgress *self) { g_return_val_if_fail (BZ_IS_GLOBAL_PROGRESS (self), FALSE); return self->settings; } static void global_progress_bar_flag_changed (BzGlobalProgress *self, const char *key, GSettings *settings) { ensure_draw_css (self); gtk_widget_queue_draw (GTK_WIDGET (self)); } static void set_wdgt_state (BzGlobalProgress *self) { const char *state = NULL; if (self->active) { if (self->pending) state = "pending"; else state = "fraction"; } else state = "inactive"; bge_wdgt_renderer_set_state (BGE_WDGT_RENDERER (self->wdgt), state); } static void ensure_draw_css (BzGlobalProgress *self) { g_autoptr (GtkWidget) draw_widget = NULL; draw_widget = bge_wdgt_renderer_lookup_object ( BGE_WDGT_RENDERER (self->wdgt), "fg"); if (draw_widget == NULL) return; if (self->settings != NULL) { g_autofree char *id = NULL; g_autofree char *final_id = NULL; g_autofree char *class = NULL; gboolean rotate = FALSE; id = g_settings_get_string (self->settings, "global-progress-bar-theme"); rotate = g_settings_get_boolean (self->settings, "rotate-flag"); if (rotate && g_strcmp0 (id, "accent-color") != 0) final_id = g_strdup_printf ("%s-horizontal", id); else final_id = g_strdup (id); class = bz_dup_css_class_for_pride_id (final_id); if (self->draw_widget_class != NULL && g_strcmp0 (self->draw_widget_class, class) == 0) return; if (self->draw_widget_class != NULL) gtk_widget_remove_css_class (draw_widget, self->draw_widget_class); g_clear_pointer (&self->draw_widget_class, g_free); gtk_widget_add_css_class (draw_widget, class); self->draw_widget_class = g_steal_pointer (&class); } else { if (self->draw_widget_class != NULL) gtk_widget_remove_css_class (draw_widget, self->draw_widget_class); g_clear_pointer (&self->draw_widget_class, g_free); } } bazaar-orig-v0.7.14/src/bz-license-dialog.blp0000664000175000017500000000601715166123241017722 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzLicenseDialog: Adw.Bin { child: Adw.ToolbarView { [top] Adw.HeaderBar { show-title: false; } content: Adw.Clamp { maximum-size: 600; child: Box { orientation: vertical; margin-top: 6; margin-bottom: 18; margin-start: 18; margin-end: 18; Box { orientation: vertical; margin-bottom: 24; valign: center; vexpand: true; $BzLozenge { visible: bind template.entry as <$BzEntry>.is-floss as ; title: bind $get_label_cb(template.entry as <$BzEntry>) as ; icon-names: [ "heart-outline-thick-symbolic", "community-symbolic", "thumbs-up-outline-symbolic", ]; importance: unimportant; } $BzLozenge { visible: bind $invert_boolean(template.entry as <$BzEntry>.is-floss as ) as ; title: bind $get_label_cb(template.entry as <$BzEntry>) as ; icon-names: [ "hand-openyay-symbolic", "proprietary-code-symbolic", "license-symbolic", ]; importance: information; } } Box { orientation: vertical; spacing: 12; ListBox { selection-mode: none; styles [ "boxed-list", ] ListBoxRow { vexpand: true; activatable: false; Label { label: bind $get_license_info(template.entry as <$BzEntry>) as ; valign: start; margin-top: 12; margin-bottom: 12; margin-start: 12; margin-end: 12; use-markup: true; xalign: 0; wrap: true; wrap-mode: word_char; } } } ListBox { visible: bind template.entry as <$BzEntry>.is-floss as ; selection-mode: none; styles [ "boxed-list", ] Adw.ButtonRow { title: _("Get Involved"); end-icon-name: "external-link-symbolic"; activated => $contribute_cb(template); has-tooltip: true; tooltip-text: bind $get_involved_tooltip(template.entry) as ; } } ListBox { visible: bind $should_show_eula(template.entry as <$BzEntry>) as ; selection-mode: none; styles [ "boxed-list", ] Adw.ButtonRow { title: _("Learn More"); end-icon-name: "external-link-symbolic"; activated => $eula_cb(template); has-tooltip: true; tooltip-text: bind $eula_tooltip(template.entry) as ; } } } }; }; }; } bazaar-orig-v0.7.14/src/bz-yaml-parser.c0000664000175000017500000012220315166123241016740 0ustar hasanhasan/* bz-yaml-parser.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::YAML" #include "config.h" #include #include #include #include "bz-parser.h" #include "bz-util.h" #include "bz-yaml-parser.h" /* clang-format off */ G_DEFINE_QUARK (bz-yaml-error-quark, bz_yaml_error); /* clang-format on */ static void deinit_schema_node (gpointer data); BZ_DEFINE_DATA ( schema_node, SchemaNode, { int kind; union { struct { char *vtype; } scalar; struct { GType type; GHashTable *type_hints; } object; struct { SchemaNodeData *child; } list; struct { GHashTable *children; } mappings; }; }, deinit_schema_node (self);) struct _BzYamlParser { GObject parent_instance; SchemaNodeData *schema; }; static void parser_iface_init (BzParserInterface *iface); G_DEFINE_FINAL_TYPE_WITH_CODE ( BzYamlParser, bz_yaml_parser, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (BZ_TYPE_PARSER, parser_iface_init)) enum { KIND_SCALAR, KIND_OBJECT, KIND_LIST, KIND_MAPPINGS, }; static SchemaNodeData * compile_schema (XbNode *node); static gboolean parse (BzYamlParser *self, yaml_parser_t *parser, yaml_event_t *event, gboolean parse_first, gboolean toplevel, SchemaNodeData *schema, GHashTable *output, GHashTable *anchors, GPtrArray *path_stack, GError **error); static GObject * parse_object (BzYamlParser *self, yaml_parser_t *parser, yaml_event_t *event, GType object_gtype, GHashTable *type_hints, GHashTable *anchors, const char *prop_path, GError **error); static char * join_path_stack (GPtrArray *path_stack); static void destroy_gvalue (GValue *value); static GValue * make_gvalue_alloc (GType type); static GValue * copy_gvalue_alloc (GValue *value); static void bz_yaml_parser_dispose (GObject *object) { BzYamlParser *self = BZ_YAML_PARSER (object); g_clear_pointer (&self->schema, schema_node_data_unref); G_OBJECT_CLASS (bz_yaml_parser_parent_class)->dispose (object); } static void bz_yaml_parser_class_init (BzYamlParserClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = bz_yaml_parser_dispose; g_type_ensure (GTK_TYPE_STRING_OBJECT); } static void bz_yaml_parser_init (BzYamlParser *self) { } static GHashTable * bz_yaml_parser_real_process_bytes (BzParser *iface_self, GBytes *bytes, GError **error) { BzYamlParser *self = BZ_YAML_PARSER (iface_self); g_autoptr (GError) local_error = NULL; gsize bytes_size = 0; const guchar *bytes_data = NULL; yaml_parser_t parser = { 0 }; yaml_event_t event = { 0 }; g_autoptr (GHashTable) output = NULL; g_autoptr (GHashTable) anchors = NULL; g_autoptr (GPtrArray) path_stack = NULL; gboolean result = FALSE; g_return_val_if_fail (BZ_IS_YAML_PARSER (self), NULL); g_return_val_if_fail (bytes != NULL, NULL); bytes_data = g_bytes_get_data (bytes, &bytes_size); yaml_parser_initialize (&parser); yaml_parser_set_input_string (&parser, bytes_data, bytes_size); output = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) destroy_gvalue); anchors = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) destroy_gvalue); path_stack = g_ptr_array_new_with_free_func (g_free); result = parse ( self, &parser, &event, TRUE, TRUE, self->schema, output, anchors, path_stack, &local_error); yaml_parser_delete (&parser); if (result) return g_steal_pointer (&output); else { g_propagate_error (error, g_steal_pointer (&local_error)); return NULL; } } static void parser_iface_init (BzParserInterface *iface) { iface->process_bytes = bz_yaml_parser_real_process_bytes; } BzYamlParser * bz_yaml_parser_new_for_resource_schema (const char *path) { g_autoptr (GError) local_error = NULL; g_autoptr (GBytes) bytes = NULL; const char *resource_data = NULL; g_autoptr (XbSilo) silo = NULL; g_autoptr (XbNode) root = NULL; g_autoptr (SchemaNodeData) schema = NULL; g_autoptr (BzYamlParser) parser = NULL; g_return_val_if_fail (path != NULL, NULL); bytes = g_resources_lookup_data ( path, G_RESOURCE_LOOKUP_FLAGS_NONE, &local_error); if (bytes == NULL) g_critical ("Could not load internal resource: %s", local_error->message); g_assert (bytes != NULL); resource_data = g_bytes_get_data (bytes, NULL); silo = xb_silo_new_from_xml (resource_data, &local_error); if (silo == NULL) g_critical ("Could not parse internal xml resource: %s", local_error->message); g_assert (silo != NULL); root = xb_silo_get_root (silo); parser = g_object_new (BZ_TYPE_YAML_PARSER, NULL); parser->schema = compile_schema (root); return g_steal_pointer (&parser); } static SchemaNodeData * compile_schema (XbNode *node) { const char *element = NULL; g_autoptr (SchemaNodeData) schema = NULL; element = xb_node_get_element (node); schema = schema_node_data_new (); #define ERROR_OUT(...) \ G_STMT_START \ { \ g_critical ("Fatal: internal schema: " __VA_ARGS__); \ g_assert (FALSE); \ } \ G_STMT_END if (g_strcmp0 (element, "scalar") == 0) { const char *type = NULL; type = xb_node_get_attr (node, "type"); if (type == NULL) ERROR_OUT ("scalar must have a type"); if (!g_variant_type_is_basic ((const GVariantType *) type)) ERROR_OUT ("invalid variant type for scalar '%s'", type); schema->kind = KIND_SCALAR; schema->scalar.vtype = g_strdup (type); } else if (g_strcmp0 (element, "object") == 0) { const char *class = NULL; GType gtype = G_TYPE_INVALID; g_autoptr (GTypeClass) gtype_class = NULL; XbNode *child = NULL; class = xb_node_get_attr (node, "class"); if (class == NULL) ERROR_OUT ("object must have a class"); gtype = g_type_from_name (class); if (gtype == G_TYPE_INVALID || !g_type_is_a (gtype, G_TYPE_OBJECT)) ERROR_OUT ("'%s' is not a valid object class", class); schema->kind = KIND_OBJECT; schema->object.type = gtype; schema->object.type_hints = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, NULL); gtype_class = g_type_class_ref (gtype); child = xb_node_get_child (node); while (child != NULL) { const char *child_element = NULL; const char *name = NULL; GParamSpec *property = NULL; const char *typehint_name = NULL; GType typehint_gtype = G_TYPE_INVALID; XbNode *next = NULL; child_element = xb_node_get_element (child); if (g_strcmp0 (child_element, "typehint") != 0) ERROR_OUT ("\"typehint\" is the only valid child element of \"object\""); name = xb_node_get_attr (child, "name"); if (name == NULL) ERROR_OUT ("typehint must have a name"); /* TODO: implement recursive checking */ if (strchr (name, '.') == NULL) { property = g_object_class_find_property (G_OBJECT_CLASS (gtype_class), name); if (property == NULL) ERROR_OUT ("typehint property '%s' is invalid", name); } typehint_name = xb_node_get_attr (child, "type"); if (typehint_name == NULL) ERROR_OUT ("typehint must have a type"); typehint_gtype = g_type_from_name (typehint_name); if (typehint_gtype == G_TYPE_INVALID || !g_type_is_a (typehint_gtype, G_TYPE_OBJECT)) ERROR_OUT ("'%s' is not a valid object class", typehint_name); g_hash_table_replace ( schema->object.type_hints, g_strdup (name), GSIZE_TO_POINTER (typehint_gtype)); next = xb_node_get_next (child); g_object_unref (child); child = next; } } else if (g_strcmp0 (element, "list") == 0) { g_autoptr (XbNode) child = NULL; child = xb_node_get_child (node); if (child == NULL) ERROR_OUT ("list must have a child"); schema->kind = KIND_LIST; schema->list.child = compile_schema (child); } else if (g_strcmp0 (element, "mappings") == 0) { XbNode *child = NULL; schema->kind = KIND_MAPPINGS; schema->mappings.children = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, schema_node_data_unref); child = xb_node_get_child (node); while (child != NULL) { const char *child_element = NULL; const char *key = NULL; g_autoptr (XbNode) child_child = NULL; XbNode *next = NULL; child_element = xb_node_get_element (child); if (g_strcmp0 (child_element, "mapping") != 0) ERROR_OUT ("\"mapping\" is the only valid child element of \"mappings\""); key = xb_node_get_attr (child, "key"); if (key == NULL) ERROR_OUT ("mapping must have a key"); child_child = xb_node_get_child (child); if (child == NULL) ERROR_OUT ("mapping must have a child"); g_hash_table_replace ( schema->mappings.children, g_strdup (key), compile_schema (child_child)); next = xb_node_get_next (child); g_object_unref (child); child = next; } } else ERROR_OUT ("unrecognized element '%s'", element); #undef ERROR_OUT return g_steal_pointer (&schema); } static gboolean parse (BzYamlParser *self, yaml_parser_t *parser, yaml_event_t *event, gboolean parse_first, gboolean toplevel, SchemaNodeData *schema, GHashTable *output, GHashTable *anchors, GPtrArray *path_stack, GError **error) { if (parse_first && !yaml_parser_parse (parser, event)) { g_set_error ( error, BZ_YAML_ERROR, BZ_YAML_ERROR_INVALID_YAML, "Failed to parse YAML at line %zu, column %zu: %s", parser->problem_mark.line, parser->problem_mark.column, parser->problem); return FALSE; } #define NEXT_EVENT() \ G_STMT_START \ { \ yaml_event_delete (event); \ if (!yaml_parser_parse (parser, event)) \ { \ g_set_error ( \ error, \ BZ_YAML_ERROR, \ BZ_YAML_ERROR_INVALID_YAML, \ "Failed to parse YAML at line %zu, column %zu: %s", \ parser->problem_mark.line, \ parser->problem_mark.column, \ parser->problem); \ return FALSE; \ } \ } \ G_STMT_END #define EXPECT(event_type, string_type) \ if (event->type != (event_type)) \ { \ g_set_error ( \ error, \ BZ_YAML_ERROR, \ BZ_YAML_ERROR_DOES_NOT_CONFORM, \ "Failed to validate YAML against schema at line %zu, column %zu: " \ "expected " string_type " here", \ event->start_mark.line, \ event->start_mark.column); \ yaml_event_delete (event); \ return FALSE; \ } #define TRY_ALIAS(var, gtype, string_type) \ if (event->type == YAML_ALIAS_EVENT) \ { \ GValue *_value = NULL; \ \ _value = g_hash_table_lookup ( \ anchors, \ event->data.alias.anchor); \ if (_value == NULL) \ { \ g_set_error ( \ error, \ BZ_YAML_ERROR, \ BZ_YAML_ERROR_INVALID_YAML, \ "Failed to resolve YAML alias at line %zu, column %zu: " \ "the anchor \"%s\" does not yet exist", \ event->start_mark.line, \ event->start_mark.column, \ (const char *) event->data.alias.anchor); \ yaml_event_delete (event); \ return FALSE; \ } \ \ if (!G_VALUE_HOLDS (_value, (gtype))) \ { \ g_set_error ( \ error, \ BZ_YAML_ERROR, \ BZ_YAML_ERROR_DOES_NOT_CONFORM, \ "Failed to validate YAML against schema at line %zu, column %zu: " \ "the alias needs to be of type " string_type " here", \ event->start_mark.line, \ event->start_mark.column); \ yaml_event_delete (event); \ return FALSE; \ } \ \ (var) = copy_gvalue_alloc (_value); \ } if (toplevel) { EXPECT (YAML_STREAM_START_EVENT, "start of stream"); NEXT_EVENT (); EXPECT (YAML_DOCUMENT_START_EVENT, "start of document"); NEXT_EVENT (); } switch (schema->kind) { case KIND_SCALAR: { GValue *value = NULL; TRY_ALIAS (value, G_TYPE_VARIANT, "scalar"); if (value != NULL) { GVariant *variant = NULL; variant = g_value_get_variant (value); if (!g_variant_type_equal ( g_variant_get_type (variant), (const GVariantType *) schema->scalar.vtype)) { g_set_error ( error, BZ_YAML_ERROR, BZ_YAML_ERROR_DOES_NOT_CONFORM, "Failed to validate YAML against schema at line %zu, column %zu: " "the alias needs to be of scalar type %s here", event->start_mark.line, event->start_mark.column, schema->scalar.vtype); destroy_gvalue (value); yaml_event_delete (event); return FALSE; } } else { g_autofree char *anchor = NULL; g_autoptr (GVariant) variant = NULL; EXPECT (YAML_SCALAR_EVENT, "scalar"); anchor = bz_maybe_strdup ((const char *) event->data.scalar.anchor); if (g_variant_type_equal ((const GVariantType *) schema->scalar.vtype, G_VARIANT_TYPE_STRING)) variant = g_variant_new_string ((const char *) event->data.scalar.value); else { g_autoptr (GError) local_error = NULL; variant = g_variant_parse ( (const GVariantType *) schema->scalar.vtype, (const char *) event->data.scalar.value, NULL, NULL, &local_error); if (variant == NULL) { g_set_error ( error, BZ_YAML_ERROR, BZ_YAML_ERROR_BAD_SCALAR, "Failed to parse scalar variant at line %zu, column %zu: " "%s", event->start_mark.line, event->start_mark.column, local_error->message); yaml_event_delete (event); return FALSE; } } value = make_gvalue_alloc (G_TYPE_VARIANT); g_value_set_variant (value, g_steal_pointer (&variant)); if (anchor != NULL) g_hash_table_replace ( anchors, g_steal_pointer (&anchor), copy_gvalue_alloc (value)); } g_hash_table_replace (output, join_path_stack (path_stack), value); } break; case KIND_OBJECT: { g_autoptr (GObject) object = NULL; GValue *value = NULL; TRY_ALIAS (value, schema->object.type, "object"); if (value == NULL) { object = parse_object ( self, parser, event, schema->object.type, schema->object.type_hints, anchors, NULL, error); if (object == NULL) /* event is already cleaned up */ return FALSE; value = make_gvalue_alloc (schema->object.type); g_value_set_object (value, object); } g_hash_table_replace (output, join_path_stack (path_stack), value); } break; case KIND_LIST: { GValue *value = NULL; TRY_ALIAS (value, G_TYPE_PTR_ARRAY, "list"); if (value == NULL) { g_autofree char *anchor = NULL; g_autoptr (GPtrArray) list = NULL; EXPECT (YAML_SEQUENCE_START_EVENT, "list"); anchor = bz_maybe_strdup ((const char *) event->data.sequence_start.anchor); list = g_ptr_array_new_with_free_func ((GDestroyNotify) destroy_gvalue); for (;;) { g_autoptr (GHashTable) list_output = NULL; g_autoptr (GPtrArray) list_path_stack = NULL; gboolean result = FALSE; GValue *append = NULL; NEXT_EVENT (); if (event->type == YAML_SEQUENCE_END_EVENT) break; list_output = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) destroy_gvalue); list_path_stack = g_ptr_array_new_with_free_func (g_free); result = parse ( self, parser, event, FALSE, FALSE, schema->list.child, list_output, anchors, list_path_stack, error); if (!result) /* event is already cleaned up */ return FALSE; append = make_gvalue_alloc (G_TYPE_HASH_TABLE); g_value_set_boxed (append, list_output); g_ptr_array_add (list, append); } value = make_gvalue_alloc (G_TYPE_PTR_ARRAY); g_value_set_boxed (value, list); if (anchor != NULL) g_hash_table_replace ( anchors, g_steal_pointer (&anchor), copy_gvalue_alloc (value)); } g_hash_table_replace (output, join_path_stack (path_stack), value); } break; case KIND_MAPPINGS: { EXPECT (YAML_MAPPING_START_EVENT, "mappings"); for (;;) { g_autofree char *key = NULL; SchemaNodeData *map_schema = NULL; gboolean result = FALSE; NEXT_EVENT (); if (event->type == YAML_MAPPING_END_EVENT) break; EXPECT (YAML_SCALAR_EVENT, "scalar key"); key = g_strdup ((const char *) event->data.scalar.value); map_schema = g_hash_table_lookup (schema->mappings.children, key); if (map_schema == NULL) { g_autofree char *path = NULL; path = join_path_stack (path_stack); g_set_error ( error, BZ_YAML_ERROR, BZ_YAML_ERROR_DOES_NOT_CONFORM, "Failed to validate YAML against schema at line %zu, column %zu: " "key '%s' shouldn't exist at path %s", event->start_mark.line, event->start_mark.column, key, path); yaml_event_delete (event); return FALSE; } g_ptr_array_add (path_stack, g_steal_pointer (&key)); result = parse ( self, parser, event, TRUE, FALSE, map_schema, output, anchors, path_stack, error); if (!result) /* event is already cleaned up */ return FALSE; g_ptr_array_set_size (path_stack, path_stack->len - 1); } } break; default: g_assert_not_reached (); } if (toplevel) { NEXT_EVENT (); EXPECT (YAML_DOCUMENT_END_EVENT, "end of document"); NEXT_EVENT (); EXPECT (YAML_STREAM_END_EVENT, "end of stream"); } yaml_event_delete (event); return TRUE; } static GObject * parse_object (BzYamlParser *self, yaml_parser_t *parser, yaml_event_t *event, GType object_gtype, GHashTable *type_hints, GHashTable *anchors, const char *prop_path, GError **error) { GValue *value = NULL; g_autofree char *object_anchor = NULL; g_autoptr (GTypeClass) gtype_class = NULL; g_autoptr (GObject) object = NULL; TRY_ALIAS (value, object_gtype, "object mapping"); if (value != NULL) { object = g_value_dup_object (value); destroy_gvalue (value); return g_steal_pointer (&object); } EXPECT (YAML_MAPPING_START_EVENT, "object mapping"); object_anchor = bz_maybe_strdup ((const char *) event->data.mapping_start.anchor); gtype_class = g_type_class_ref (object_gtype); object = g_object_new (object_gtype, NULL); for (;;) { g_autofree char *property = NULL; GParamSpec *spec = NULL; NEXT_EVENT (); if (event->type == YAML_MAPPING_END_EVENT) break; EXPECT (YAML_SCALAR_EVENT, "scalar key"); property = g_strdup ((const char *) event->data.scalar.value); spec = g_object_class_find_property (G_OBJECT_CLASS (gtype_class), property); if (spec == NULL) { g_set_error ( error, BZ_YAML_ERROR, BZ_YAML_ERROR_DOES_NOT_CONFORM, "Failed to validate YAML against schema at line %zu, column %zu: " "property '%s' doesn't exist on type %s", event->start_mark.line, event->start_mark.column, property, g_type_name (object_gtype)); yaml_event_delete (event); return FALSE; } NEXT_EVENT (); if (g_type_is_a (spec->value_type, G_TYPE_LIST_MODEL)) { g_autofree char *replace_prop_path = NULL; GType element_gtype = 0; g_autoptr (GListModel) list = NULL; if (prop_path != NULL) replace_prop_path = g_strdup_printf ("%s.%s", prop_path, property); element_gtype = GPOINTER_TO_SIZE (g_hash_table_lookup ( type_hints, replace_prop_path != NULL ? replace_prop_path : property)); TRY_ALIAS (value, G_TYPE_LIST_MODEL, "mappings"); if (value != NULL) { list = g_value_dup_object (value); if (!G_IS_LIST_MODEL (list) || g_list_model_get_item_type (list) != element_gtype) { g_set_error ( error, BZ_YAML_ERROR, BZ_YAML_ERROR_DOES_NOT_CONFORM, "Failed to validate YAML against schema at line %zu, column %zu: " "the alias needs to be a list of object type %s here", event->start_mark.line, event->start_mark.column, g_type_name (element_gtype)); destroy_gvalue (value); yaml_event_delete (event); return FALSE; } } else { g_autofree char *anchor = NULL; EXPECT (YAML_SEQUENCE_START_EVENT, "sequence"); anchor = bz_maybe_strdup ((const char *) event->data.sequence_start.anchor); if (element_gtype == GTK_TYPE_STRING_OBJECT) { list = (GListModel *) gtk_string_list_new (NULL); for (;;) { NEXT_EVENT (); if (event->type == YAML_SEQUENCE_END_EVENT) break; EXPECT (YAML_SCALAR_EVENT, "scalar list value"); gtk_string_list_append ( GTK_STRING_LIST (list), (const char *) event->data.scalar.value); } } else { if (element_gtype == 0) element_gtype = G_TYPE_OBJECT; list = (GListModel *) g_list_store_new (element_gtype); for (;;) { g_autoptr (GObject) child_object = NULL; NEXT_EVENT (); if (event->type == YAML_SEQUENCE_END_EVENT) break; child_object = parse_object ( self, parser, event, element_gtype, type_hints, anchors, replace_prop_path != NULL ? replace_prop_path : property, error); if (child_object == NULL) /* event is already cleaned up */ return FALSE; g_list_store_append (G_LIST_STORE (list), child_object); } } if (anchor != NULL) { value = make_gvalue_alloc (G_TYPE_LIST_MODEL); g_value_set_object (value, list); g_hash_table_replace ( anchors, g_steal_pointer (&anchor), value); } } g_object_set (object, property, list, NULL); } else if (g_type_is_a (spec->value_type, G_TYPE_OBJECT)) { g_autofree char *replace_prop_path = NULL; g_autoptr (GObject) prop_object = NULL; if (prop_path != NULL) replace_prop_path = g_strdup_printf ("%s.%s", prop_path, property); prop_object = parse_object ( self, parser, event, spec->value_type, type_hints, anchors, replace_prop_path != NULL ? replace_prop_path : property, error); if (prop_object == NULL) /* event is already cleaned up */ return FALSE; g_object_set (object, property, prop_object, NULL); } else if (g_type_is_a (spec->value_type, G_TYPE_ENUM)) { g_autoptr (GEnumClass) class = NULL; GEnumValue *enum_value = NULL; TRY_ALIAS (value, spec->value_type, "scalar enum value"); if (value != NULL) { g_object_set_property (object, property, value); destroy_gvalue (value); } else { g_autofree char *anchor = NULL; EXPECT (YAML_SCALAR_EVENT, "scalar enum value"); anchor = bz_maybe_strdup ((const char *) event->data.scalar.anchor); class = g_type_class_ref (spec->value_type); enum_value = g_enum_get_value_by_nick ( class, (const char *) event->data.scalar.value); if (enum_value == NULL) enum_value = g_enum_get_value_by_name ( class, (const char *) event->data.scalar.value); if (enum_value == NULL) { g_set_error ( error, BZ_YAML_ERROR, BZ_YAML_ERROR_BAD_SCALAR, "Failed to parse scalar enum at line %zu, column %zu: " "'%s' does not exist in type %s", event->start_mark.line, event->start_mark.column, (const char *) event->data.scalar.value, g_type_name (spec->value_type)); yaml_event_delete (event); return FALSE; } if (anchor != NULL) { value = make_gvalue_alloc (spec->value_type); g_value_set_enum (value, enum_value->value); g_hash_table_replace ( anchors, g_steal_pointer (&anchor), value); } g_object_set (object, property, enum_value->value, NULL); } } else { g_autoptr (GError) local_error = NULL; const GVariantType *vtype = NULL; g_autoptr (GVariant) variant = NULL; TRY_ALIAS (value, spec->value_type, "scalar"); if (value != NULL) { g_object_set_property (object, property, value); destroy_gvalue (value); } else { g_autofree char *anchor = NULL; if (spec->value_type == G_TYPE_STRING && event->type == YAML_MAPPING_START_EVENT) { /* Handle optional translated strings */ const char *const *langs = NULL; g_autofree char *english = NULL; anchor = bz_maybe_strdup ((const char *) event->data.mapping_start.anchor); langs = g_get_language_names (); for (;;) { g_autofree char *code = NULL; NEXT_EVENT (); if (event->type == YAML_MAPPING_END_EVENT) break; EXPECT (YAML_SCALAR_EVENT, "scalar key language code"); if (variant != NULL) continue; code = g_strdup ((const char *) event->data.scalar.value); NEXT_EVENT (); EXPECT (YAML_SCALAR_EVENT, "scalar translated string"); if (g_strv_contains (langs, code)) variant = g_variant_new_string ((const char *) event->data.scalar.value); else if (english == NULL && g_strcmp0 (code, "en") == 0) english = g_strdup ((const char *) event->data.scalar.value); } if (variant == NULL) variant = g_variant_new_string (english != NULL ? english : "NULL"); } else { EXPECT (YAML_SCALAR_EVENT, "scalar value"); anchor = bz_maybe_strdup ((const char *) event->data.scalar.anchor); switch (spec->value_type) { case G_TYPE_BOOLEAN: vtype = G_VARIANT_TYPE_BOOLEAN; break; case G_TYPE_INT: vtype = G_VARIANT_TYPE_INT32; break; case G_TYPE_INT64: vtype = G_VARIANT_TYPE_INT64; break; case G_TYPE_UINT: vtype = G_VARIANT_TYPE_UINT32; break; case G_TYPE_UINT64: vtype = G_VARIANT_TYPE_UINT64; break; case G_TYPE_DOUBLE: case G_TYPE_FLOAT: vtype = G_VARIANT_TYPE_DOUBLE; break; case G_TYPE_STRING: default: vtype = G_VARIANT_TYPE_STRING; break; } if (g_variant_type_equal (vtype, G_VARIANT_TYPE_STRING)) variant = g_variant_new_string ((const char *) event->data.scalar.value); else { variant = g_variant_parse ( vtype, (const char *) event->data.scalar.value, NULL, NULL, &local_error); if (variant == NULL) { g_set_error ( error, BZ_YAML_ERROR, BZ_YAML_ERROR_BAD_SCALAR, "Failed to parse scalar variant at line %zu, column %zu: %s", event->start_mark.line, event->start_mark.column, local_error->message); yaml_event_delete (event); return FALSE; } } } if (anchor != NULL) value = make_gvalue_alloc (spec->value_type); switch (spec->value_type) { case G_TYPE_BOOLEAN: g_object_set (object, property, g_variant_get_boolean (variant), NULL); if (anchor != NULL) g_value_set_boolean (value, g_variant_get_boolean (variant)); break; case G_TYPE_INT: g_object_set (object, property, g_variant_get_int32 (variant), NULL); if (anchor != NULL) g_value_set_int (value, g_variant_get_int32 (variant)); break; case G_TYPE_INT64: g_object_set (object, property, g_variant_get_int64 (variant), NULL); if (anchor != NULL) g_value_set_int64 (value, g_variant_get_int64 (variant)); break; case G_TYPE_UINT: g_object_set (object, property, g_variant_get_uint32 (variant), NULL); if (anchor != NULL) g_value_set_uint (value, g_variant_get_uint32 (variant)); break; case G_TYPE_UINT64: g_object_set (object, property, g_variant_get_uint64 (variant), NULL); if (anchor != NULL) g_value_set_uint64 (value, g_variant_get_uint64 (variant)); break; case G_TYPE_DOUBLE: case G_TYPE_FLOAT: g_object_set (object, property, g_variant_get_double (variant), NULL); if (anchor != NULL) g_value_set_double (value, g_variant_get_double (variant)); break; case G_TYPE_STRING: default: g_object_set (object, property, g_variant_get_string (variant, NULL), NULL); if (anchor != NULL) g_value_set_string (value, g_variant_get_string (variant, NULL)); break; } if (anchor != NULL) g_hash_table_replace ( anchors, g_steal_pointer (&anchor), value); } } } if (object_anchor != NULL) { value = make_gvalue_alloc (G_TYPE_LIST_MODEL); g_value_set_object (value, object); g_hash_table_replace ( anchors, g_steal_pointer (&object_anchor), value); } return g_steal_pointer (&object); } static char * join_path_stack (GPtrArray *path_stack) { GString *string = NULL; if (path_stack->len == 0) return g_strdup ("/"); string = g_string_new (NULL); for (guint i = 0; i < path_stack->len; i++) { const char *component = NULL; component = g_ptr_array_index (path_stack, i); g_string_append_printf (string, "/%s", component); } return g_string_free_and_steal (string); } static void destroy_gvalue (GValue *value) { g_value_unset (value); g_free (value); } static GValue * make_gvalue_alloc (GType type) { GValue *ret = NULL; ret = g_new0 (typeof (*ret), 1); g_value_init (ret, type); return ret; } static GValue * copy_gvalue_alloc (GValue *value) { GValue *ret = NULL; ret = g_new0 (typeof (*ret), 1); g_value_init (ret, value->g_type); g_value_copy (value, ret); return ret; } static void deinit_schema_node (gpointer data) { SchemaNodeData *self = data; switch (self->kind) { case KIND_SCALAR: g_clear_pointer (&self->scalar.vtype, g_free); break; case KIND_OBJECT: g_clear_pointer (&self->object.type_hints, g_hash_table_unref); break; case KIND_LIST: g_clear_pointer (&self->list.child, schema_node_data_unref); break; case KIND_MAPPINGS: g_clear_pointer (&self->mappings.children, g_hash_table_unref); break; default: g_assert_not_reached (); } } bazaar-orig-v0.7.14/src/bz-context-tile-callbacks.c0000664000175000017500000002745215166123241021052 0ustar hasanhasan/* bz-context-tile-callbacks.c * * Copyright 2026 Eva M, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include #include #include #include "bz-context-tile-callbacks.h" #include "bz-entry.h" #include "bz-safety-calculator.h" #include "bz-spdx.h" static char * format_with_small_suffix (char *number, const char *suffix) { char *dot = g_strrstr (number, "."); if (dot != NULL) { char *end = dot; while (*(end + 1) != '\0') end++; while (end > dot && *end == '0') *end-- = '\0'; if (end == dot) *dot = '\0'; } return g_strdup_printf ("%s\xC2\xA0%s", number, suffix); } static char * format_favorites_count (gpointer object, int favorites_count) { if (favorites_count < 0) return g_strdup (" "); return g_strdup_printf ("%d", favorites_count); } static char * format_recent_downloads (gpointer object, int value) { double result; int digits; if (value <= 0) return g_strdup (_ ("---")); if (value >= 1000000) { result = value / 1000000.0; digits = (int) log10 (result) + 1; /* Translators: M is the suffix for millions */ return g_strdup_printf (_ ("%.*fM"), 3 - digits, result); } else if (value >= 1000) { result = value / 1000.0; digits = (int) log10 (result) + 1; /* Translators: K is the suffix for thousands*/ return g_strdup_printf (_ ("%.*fK"), 3 - digits, result); } else return g_strdup_printf ("%'d", value); } static char * format_recent_downloads_tooltip (gpointer object, int value) { return g_strdup_printf (_ ("%d downloads in the last month"), value); } static char * format_size (gpointer object, guint64 value) { g_autofree char *size_str = g_format_size (value); char *space = g_strrstr (size_str, "\xC2\xA0"); char *decimal = NULL; int digits = 0; if (value == 0) return g_strdup (_ ("N/A")); if (space != NULL) { *space = '\0'; for (char *p = size_str; *p != '\0' && *p != '.'; p++) if (g_ascii_isdigit (*p)) digits++; if (digits >= 3) { decimal = g_strrstr (size_str, "."); if (decimal != NULL) *decimal = '\0'; } return format_with_small_suffix (size_str, space + 2); } return g_strdup (size_str); } static char * get_size_label (gpointer object, gboolean is_installable, gboolean runtime_installed, guint64 runtime_size) { if (is_installable && !runtime_installed && runtime_size > 0) { g_autofree char *size_str = g_format_size (runtime_size); return g_strdup_printf (_ ("+%s runtime"), size_str); } return g_strdup (is_installable ? _ ("Download") : _ ("Installed")); } static guint64 get_size_type (gpointer object, BzEntry *entry, gboolean is_installable) { if (entry == NULL) return 0; return is_installable ? bz_entry_get_size (entry) : bz_entry_get_installed_size (entry); } static char * format_size_tooltip (gpointer object, guint64 value) { g_autofree char *size_str = NULL; if (value == 0) return g_strdup (_ ("Size information unavailable")); size_str = g_format_size (value); return g_strdup_printf (_ ("Download size of %s"), size_str); } static char * format_age_rating (gpointer object, AsContentRating *content_rating) { guint age; if (content_rating == NULL) return g_strdup ("?"); age = as_content_rating_get_minimum_age (content_rating); if (age < 3) age = 3; /* Translators: Age rating format, e.g. "12+" for ages 12 and up */ return g_strdup_printf (_ ("%d+"), age); } static char * get_age_rating_label (gpointer object, AsContentRating *content_rating) { guint age; if (content_rating == NULL) return g_strdup (_ ("Age Rating")); age = as_content_rating_get_minimum_age (content_rating); if (age == 0) return g_strdup (_ ("All Ages")); else return g_strdup (_ ("Age Rating")); } static char * get_age_rating_tooltip (gpointer object, AsContentRating *content_rating) { guint age; if (content_rating == NULL) return g_strdup (_ ("Age rating information unavailable")); age = as_content_rating_get_minimum_age (content_rating); if (age == 0) return g_strdup (_ ("Suitable for all ages")); return g_strdup_printf (_ ("Suitable for ages %d and up"), age); } static char * get_age_rating_style (gpointer object, AsContentRating *content_rating) { guint age; if (content_rating == NULL) return g_strdup ("grey"); age = as_content_rating_get_minimum_age (content_rating); if (age >= 18) return g_strdup ("error"); else if (age >= 15) return g_strdup ("orange"); else if (age >= 12) return g_strdup ("warning"); else return g_strdup ("grey"); } static char * format_license_tooltip (gpointer object, BzEntry *entry) { const char *license; gboolean is_floss = FALSE; g_autofree char *name = NULL; if (entry == NULL) return g_strdup (_ ("Unknown")); g_object_get (entry, "is-floss", &is_floss, "project-license", &license, NULL); if (license == NULL || *license == '\0') return g_strdup (_ ("Unknown")); if (is_floss && bz_spdx_is_valid (license)) { name = bz_spdx_get_name (license); return g_strdup_printf (_ ("Free software licensed under %s"), (name != NULL && *name != '\0') ? name : license); } if (is_floss) return g_strdup (_ ("Free software")); if (bz_spdx_is_proprietary (license)) return g_strdup (_ ("Proprietary Software")); name = bz_spdx_get_name (license); return g_strdup_printf (_ ("Special License: %s"), (name != NULL && *name != '\0') ? name : license); } static char * get_license_label (gpointer object, BzEntry *entry) { const char *license; gboolean is_floss = FALSE; if (entry == NULL) return g_strdup (_ ("Unknown")); g_object_get (entry, "is-floss", &is_floss, "project-license", &license, NULL); if (is_floss) return g_strdup (_ ("Free")); if (license == NULL || *license == '\0') return g_strdup (_ ("Unknown")); if (bz_spdx_is_proprietary (license)) return g_strdup (_ ("Proprietary")); return g_strdup (_ ("Special License")); } static char * get_license_icon (gpointer object, gboolean is_floss, int index) { const char *icons[][2] = { { "license-symbolic", "proprietary-code-symbolic" }, { "community-symbolic", "license-symbolic" } }; return g_strdup (icons[is_floss ? 1 : 0][index]); } static char * get_formfactor_label (gpointer object, gboolean is_mobile_friendly) { return g_strdup (is_mobile_friendly ? _ ("Adaptive") : _ ("Desktop Only")); } static char * get_formfactor_tooltip (gpointer object, gboolean is_mobile_friendly) { return g_strdup (is_mobile_friendly ? _ ("Works on desktop, tablets, and phones") : _ ("May not work on mobile devices")); } static char * get_safety_rating_icon (gpointer object, BzEntry *entry, int index) { char *icon = NULL; BzImportance importance = 0; if (entry == NULL) return g_strdup ("app-safety-unknown-symbolic"); if (index < 0 || index > 2) return NULL; if (index == 0) { importance = bz_safety_calculator_calculate_rating (entry); switch (importance) { case BZ_IMPORTANCE_UNIMPORTANT: case BZ_IMPORTANCE_NEUTRAL: return g_strdup ("app-safety-ok-symbolic"); case BZ_IMPORTANCE_INFORMATION: case BZ_IMPORTANCE_WARNING: return NULL; case BZ_IMPORTANCE_IMPORTANT: return g_strdup ("dialog-warning-symbolic"); default: return NULL; } } icon = bz_safety_calculator_get_top_icon (entry, index - 1); return icon; } static char * get_safety_rating_style (gpointer object, BzEntry *entry) { BzImportance importance; if (entry == NULL) return g_strdup ("grey"); importance = bz_safety_calculator_calculate_rating (entry); switch (importance) { case BZ_IMPORTANCE_UNIMPORTANT: case BZ_IMPORTANCE_NEUTRAL: return g_strdup ("grey"); case BZ_IMPORTANCE_INFORMATION: return g_strdup ("warning"); case BZ_IMPORTANCE_WARNING: return g_strdup ("orange"); case BZ_IMPORTANCE_IMPORTANT: return g_strdup ("error"); default: return g_strdup ("grey"); } } static char * get_safety_rating_label (gpointer object, BzEntry *entry) { BzImportance importance; if (entry == NULL) return g_strdup (_ ("N/A")); importance = bz_safety_calculator_calculate_rating (entry); switch (importance) { case BZ_IMPORTANCE_UNIMPORTANT: return g_strdup (_ ("Safe")); case BZ_IMPORTANCE_NEUTRAL: return g_strdup (_ ("Low Risk")); case BZ_IMPORTANCE_INFORMATION: return g_strdup (_ ("Low Risk")); case BZ_IMPORTANCE_WARNING: return g_strdup (_ ("Medium Risk")); case BZ_IMPORTANCE_IMPORTANT: return g_strdup (_ ("High Risk")); default: return g_strdup (_ ("N/A")); } } void bz_widget_class_bind_all_context_tile_callbacks (GtkWidgetClass *widget_class) { g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class)); gtk_widget_class_bind_template_callback (widget_class, format_favorites_count); gtk_widget_class_bind_template_callback (widget_class, format_recent_downloads); gtk_widget_class_bind_template_callback (widget_class, format_recent_downloads_tooltip); gtk_widget_class_bind_template_callback (widget_class, format_size); gtk_widget_class_bind_template_callback (widget_class, get_size_label); gtk_widget_class_bind_template_callback (widget_class, get_size_type); gtk_widget_class_bind_template_callback (widget_class, format_size_tooltip); gtk_widget_class_bind_template_callback (widget_class, format_age_rating); gtk_widget_class_bind_template_callback (widget_class, get_age_rating_label); gtk_widget_class_bind_template_callback (widget_class, get_age_rating_tooltip); gtk_widget_class_bind_template_callback (widget_class, get_age_rating_style); gtk_widget_class_bind_template_callback (widget_class, format_license_tooltip); gtk_widget_class_bind_template_callback (widget_class, get_license_label); gtk_widget_class_bind_template_callback (widget_class, get_license_icon); gtk_widget_class_bind_template_callback (widget_class, get_formfactor_label); gtk_widget_class_bind_template_callback (widget_class, get_formfactor_tooltip); gtk_widget_class_bind_template_callback (widget_class, get_safety_rating_icon); gtk_widget_class_bind_template_callback (widget_class, get_safety_rating_style); gtk_widget_class_bind_template_callback (widget_class, get_safety_rating_label); } bazaar-orig-v0.7.14/src/bz-context-tile.h0000664000175000017500000000311215166123241017125 0ustar hasanhasan/* bz-context-tile.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_CONTEXT_TILE (bz_context_tile_get_type ()) G_DECLARE_FINAL_TYPE (BzContextTile, bz_context_tile, BZ, CONTEXT_TILE, GtkButton) BzContextTile *bz_context_tile_new (void); GtkWidget *bz_context_tile_get_lozenge_child (BzContextTile *self); void bz_context_tile_set_lozenge_child (BzContextTile *self, GtkWidget *child); const char *bz_context_tile_get_label (BzContextTile *self); void bz_context_tile_set_label (BzContextTile *self, const char *label); const char *bz_context_tile_get_lozenge_style (BzContextTile *self); void bz_context_tile_set_lozenge_style (BzContextTile *self, const char *style); G_END_DECLS bazaar-orig-v0.7.14/src/bz-screenshot.h0000664000175000017500000000374415166123241016676 0ustar hasanhasan/* bz-screenshot.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_SCREENSHOT (bz_screenshot_get_type ()) G_DECLARE_FINAL_TYPE (BzScreenshot, bz_screenshot, BZ, SCREENSHOT, GtkWidget) GtkWidget * bz_screenshot_new (void); void bz_screenshot_set_paintable (BzScreenshot *self, GdkPaintable *paintable); GdkPaintable * bz_screenshot_get_paintable (BzScreenshot *self); void bz_screenshot_set_focus_x (BzScreenshot *self, double focus_x); double bz_screenshot_get_focus_x (BzScreenshot *self); void bz_screenshot_set_focus_y (BzScreenshot *self, double focus_y); double bz_screenshot_get_focus_y (BzScreenshot *self); void bz_screenshot_set_rounded_corners (BzScreenshot *self, gboolean rounded_corners); gboolean bz_screenshot_get_rounded_corners (BzScreenshot *self); void bz_screenshot_set_top_half (BzScreenshot *self, gboolean top_half); gboolean bz_screenshot_get_top_half (BzScreenshot *self); void bz_screenshot_set_filter (BzScreenshot *self, GskScalingFilter filter); GskScalingFilter bz_screenshot_get_filter (BzScreenshot *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-all-apps-page.h0000664000175000017500000000210515166123241017132 0ustar hasanhasan/* bz-all-apps-page.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_ALL_APPS_PAGE (bz_all_apps_page_get_type ()) G_DECLARE_FINAL_TYPE (BzAllAppsPage, bz_all_apps_page, BZ, ALL_APPS_PAGE, AdwNavigationPage) AdwNavigationPage * bz_all_apps_page_new (const char *title, GListModel *applications); G_END_DECLS bazaar-orig-v0.7.14/src/bz-app-tile.c0000664000175000017500000002103415166123241016217 0ustar hasanhasan/* bz-app-tile.c * * Copyright 2025 Adam Masciola * * Layout manager adapted from GNOME Softwares GsSummaryTileLayout * * Copyright (C) 2013 Matthias Clasen * Copyright (C) 2019 Richard Hughes * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include "bz-app-tile.h" #define BZ_TYPE_APP_TILE_LAYOUT (bz_app_tile_layout_get_type ()) G_DECLARE_FINAL_TYPE (BzAppTileLayout, bz_app_tile_layout, BZ, APP_TILE_LAYOUT, GtkLayoutManager) struct _BzAppTileLayout { GtkLayoutManager parent_instance; gint preferred_width; }; G_DEFINE_FINAL_TYPE (BzAppTileLayout, bz_app_tile_layout, GTK_TYPE_LAYOUT_MANAGER) static void bz_app_tile_layout_measure (GtkLayoutManager *layout_manager, GtkWidget *widget, GtkOrientation orientation, gint for_size, gint *minimum, gint *natural, gint *minimum_baseline, gint *natural_baseline) { BzAppTileLayout *self = BZ_APP_TILE_LAYOUT (layout_manager); GtkWidget *child = NULL; gint min = 0; gint nat = 0; for (child = gtk_widget_get_first_child (widget); child != NULL; child = gtk_widget_get_next_sibling (child)) { gint child_min_baseline = -1; gint child_nat_baseline = -1; gint child_min = 0; gint child_nat = 0; if (!gtk_widget_should_layout (child)) continue; gtk_widget_measure (child, orientation, for_size, &child_min, &child_nat, &child_min_baseline, &child_nat_baseline); min = MAX (min, child_min); nat = MAX (nat, child_nat); if (child_min_baseline > -1) *minimum_baseline = MAX (*minimum_baseline, child_min_baseline); if (child_nat_baseline > -1) *natural_baseline = MAX (*natural_baseline, child_nat_baseline); } *minimum = min; *natural = nat; if (self->preferred_width > 0 && orientation == GTK_ORIENTATION_HORIZONTAL) *natural = MAX (*minimum, self->preferred_width); } static void bz_app_tile_layout_allocate (GtkLayoutManager *layout_manager, GtkWidget *widget, gint width, gint height, gint baseline) { GtkWidget *child = NULL; for (child = gtk_widget_get_first_child (widget); child != NULL; child = gtk_widget_get_next_sibling (child)) { if (child && gtk_widget_should_layout (child)) gtk_widget_allocate (child, width, height, baseline, NULL); } } static void bz_app_tile_layout_class_init (BzAppTileLayoutClass *klass) { GtkLayoutManagerClass *layout_manager_class = GTK_LAYOUT_MANAGER_CLASS (klass); layout_manager_class->measure = bz_app_tile_layout_measure; layout_manager_class->allocate = bz_app_tile_layout_allocate; } static void bz_app_tile_layout_init (BzAppTileLayout *self) { } struct _BzAppTile { GtkButton parent_instance; BzEntryGroup *group; gint preferred_width; }; G_DEFINE_FINAL_TYPE (BzAppTile, bz_app_tile, GTK_TYPE_BUTTON); enum { PROP_0, PROP_GROUP, PROP_PREFERRED_WIDTH, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bz_app_tile_dispose (GObject *object) { BzAppTile *self = BZ_APP_TILE (object); g_clear_object (&self->group); G_OBJECT_CLASS (bz_app_tile_parent_class)->dispose (object); } static void bz_app_tile_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzAppTile *self = BZ_APP_TILE (object); switch (prop_id) { case PROP_GROUP: g_value_set_object (value, bz_app_tile_get_group (self)); break; case PROP_PREFERRED_WIDTH: g_value_set_int (value, self->preferred_width); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_app_tile_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzAppTile *self = BZ_APP_TILE (object); switch (prop_id) { case PROP_GROUP: bz_app_tile_set_group (self, g_value_get_object (value)); break; case PROP_PREFERRED_WIDTH: bz_app_tile_set_preferred_width (self, g_value_get_int (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static gboolean is_null (gpointer object, GObject *value) { return value == NULL; } static gboolean is_zero (gpointer object, int value) { return value == 0; } static gboolean description_line_amount (gpointer object, bool value) { return value ? 2 : 1; } static void bz_app_tile_class_init (BzAppTileClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bz_app_tile_set_property; object_class->get_property = bz_app_tile_get_property; object_class->dispose = bz_app_tile_dispose; props[PROP_GROUP] = g_param_spec_object ( "group", NULL, NULL, BZ_TYPE_ENTRY_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_PREFERRED_WIDTH] = g_param_spec_int ( "preferred-width", NULL, NULL, -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-app-tile.ui"); gtk_widget_class_set_layout_manager_type (widget_class, BZ_TYPE_APP_TILE_LAYOUT); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, is_null); gtk_widget_class_bind_template_callback (widget_class, is_zero); gtk_widget_class_bind_template_callback (widget_class, description_line_amount); } static void bz_app_tile_init (BzAppTile *self) { self->preferred_width = -1; gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_app_tile_new (void) { return g_object_new (BZ_TYPE_APP_TILE, NULL); } BzEntryGroup * bz_app_tile_get_group (BzAppTile *self) { g_return_val_if_fail (BZ_IS_APP_TILE (self), NULL); return self->group; } void bz_app_tile_set_group (BzAppTile *self, BzEntryGroup *group) { g_return_if_fail (BZ_IS_APP_TILE (self)); g_clear_object (&self->group); if (group != NULL) self->group = g_object_ref (group); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_GROUP]); } gint bz_app_tile_get_preferred_width (BzAppTile *self) { g_return_val_if_fail (BZ_IS_APP_TILE (self), -1); return self->preferred_width; } void bz_app_tile_set_preferred_width (BzAppTile *self, gint preferred_width) { GtkLayoutManager *layout_manager; g_return_if_fail (BZ_IS_APP_TILE (self)); if (self->preferred_width == preferred_width) return; self->preferred_width = preferred_width; layout_manager = gtk_widget_get_layout_manager (GTK_WIDGET (self)); BZ_APP_TILE_LAYOUT (layout_manager)->preferred_width = preferred_width; gtk_layout_manager_layout_changed (layout_manager); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PREFERRED_WIDTH]); } /* End of bz-app-tile.c */ bazaar-orig-v0.7.14/src/bz-curated-view.blp0000664000175000017500000000352615166123241017444 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzCuratedView: Adw.Bin { child: Adw.ViewStack stack { enable-transitions: true; transition-duration: 400; Adw.ViewStackPage { name: "empty"; title: _("Empty"); child: Adw.StatusPage { icon-name: "starred-symbolic"; title: _("No Curation"); description: _("There is no curation information provided on this system. You can still browse applications on Flathub"); child: Button { label: _("Browse Flathub"); halign: center; clicked => $browse_flathub_cb(template); styles ["pill"] }; }; } Adw.ViewStackPage { name: "offline"; title: _("Offline"); child: Adw.StatusPage { icon-name: "connected-squares-x"; title: _("Offline"); }; } Adw.ViewStackPage { name: "content"; title: _("Browser"); child: ScrolledWindow { hscrollbar-policy: never; child: Adw.ClampScrollable { maximum-size: 1500; tightening-threshold: 1400; child: ListView { css-name: "curated-list-view"; model: NoSelection { model: bind template.state as <$BzStateInfo>.curated-provider; }; factory: BuilderListItemFactory { template ListItem { activatable: false; selectable: false; focusable: false; child: $BzDynamicListView { hexpand: true; scroll: false; noscroll-kind: list-box; child-type: "BzRowView"; child-prop: "row"; model: bind template.item as <$BzRootCuratedConfig>.rows; }; } }; }; }; }; } }; } bazaar-orig-v0.7.14/src/bz-user-data-tile.h0000664000175000017500000000236315166123241017335 0ustar hasanhasan/* bz-user-data-tile.h * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry-group.h" #include "bz-list-tile.h" #include G_BEGIN_DECLS #define BZ_TYPE_USER_DATA_TILE (bz_user_data_tile_get_type ()) G_DECLARE_FINAL_TYPE (BzUserDataTile, bz_user_data_tile, BZ, USER_DATA_TILE, AdwBin) GtkWidget * bz_user_data_tile_new (void); void bz_user_data_tile_set_group (BzUserDataTile *self, BzEntryGroup *group); BzEntryGroup * bz_user_data_tile_get_group (BzUserDataTile *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-flathub-page.c0000664000175000017500000002412415166123241017046 0ustar hasanhasan/* bz-flathub-page.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-app-tile.h" #include "bz-apps-page.h" #include "bz-dynamic-list-view.h" #include "bz-entry-group.h" #include "bz-featured-carousel.h" #include "bz-flathub-category-section.h" #include "bz-flathub-category.h" #include "bz-flathub-page.h" #include "bz-inhibited-scrollable.h" #include "bz-section-view.h" struct _BzFlathubPage { AdwBin parent_instance; BzStateInfo *state; /* Template widgets */ AdwViewStack *stack; }; G_DEFINE_FINAL_TYPE (BzFlathubPage, bz_flathub_page, ADW_TYPE_BIN) enum { PROP_0, PROP_STATE, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; enum { SIGNAL_OPEN_SEARCH, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL]; static BzFlathubCategory * get_category_by_name (GListModel *categories, const char *name); static void invalidating_state_changed (BzFlathubPage *self, GParamSpec *pspec, BzStateInfo *info); static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static gboolean is_null (gpointer object, GObject *value) { return value == NULL; } static void tile_clicked (BzEntryGroup *group, GtkButton *button); static void show_more_clicked (BzFlathubPage *self, GtkButton *button, const char *category_name); static void bz_flathub_page_dispose (GObject *object) { BzFlathubPage *self = BZ_FLATHUB_PAGE (object); if (self->state != NULL) g_signal_handlers_disconnect_by_func (self->state, invalidating_state_changed, self); g_clear_object (&self->state); G_OBJECT_CLASS (bz_flathub_page_parent_class)->dispose (object); } static void bz_flathub_page_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzFlathubPage *self = BZ_FLATHUB_PAGE (object); switch (prop_id) { case PROP_STATE: g_value_set_object (value, bz_flathub_page_get_state (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_flathub_page_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzFlathubPage *self = BZ_FLATHUB_PAGE (object); switch (prop_id) { case PROP_STATE: bz_flathub_page_set_state (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bind_widget_cb (BzFlathubPage *self, BzAppTile *tile, BzEntryGroup *group, BzDynamicListView *view) { g_signal_connect_swapped (tile, "clicked", G_CALLBACK (tile_clicked), group); } static void unbind_widget_cb (BzFlathubPage *self, BzAppTile *tile, BzEntryGroup *group, BzDynamicListView *view) { g_signal_handlers_disconnect_by_func (tile, G_CALLBACK (tile_clicked), group); } static void show_more_mobile_cb (BzFlathubPage *self, GtkButton *button) { show_more_clicked (self, button, "mobile"); } static void show_more_gaming_cb (BzFlathubPage *self, GtkButton *button) { show_more_clicked (self, button, "game"); } static BzFlathubCategory * get_category_by_name (GListModel *categories, const char *name) { guint n_items; guint i; if (categories == NULL) return NULL; n_items = g_list_model_get_n_items (categories); for (i = 0; i < n_items; i++) { g_autoptr (BzFlathubCategory) category = g_list_model_get_item (categories, i); const char *category_name; category_name = bz_flathub_category_get_name (category); if (g_strcmp0 (category_name, name) == 0) return g_object_ref (category); } return NULL; } static gpointer get_category_by_name_cb (gpointer object, gpointer categories_obj, const char *name) { return get_category_by_name (G_LIST_MODEL (categories_obj), name); } static void open_search_cb (BzFlathubPage *self, GtkButton *button) { g_signal_emit (self, signals[SIGNAL_OPEN_SEARCH], 0); } static void show_group_action (GtkWidget *widget, BzEntryGroup *group) { gtk_widget_activate_action (widget, "window.show-group", "s", bz_entry_group_get_id (group)); } static void bz_flathub_page_class_init (BzFlathubPageClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_flathub_page_dispose; object_class->get_property = bz_flathub_page_get_property; object_class->set_property = bz_flathub_page_set_property; props[PROP_STATE] = g_param_spec_object ( "state", NULL, NULL, BZ_TYPE_STATE_INFO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); signals[SIGNAL_OPEN_SEARCH] = g_signal_new ( "open-search", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_type_ensure (BZ_TYPE_SECTION_VIEW); g_type_ensure (BZ_TYPE_FLATHUB_CATEGORY_SECTION); g_type_ensure (BZ_TYPE_FLATHUB_CATEGORY); g_type_ensure (BZ_TYPE_INHIBITED_SCROLLABLE); g_type_ensure (BZ_TYPE_DYNAMIC_LIST_VIEW); g_type_ensure (BZ_TYPE_APP_TILE); g_type_ensure (BZ_TYPE_FEATURED_CAROUSEL); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-flathub-page.ui"); gtk_widget_class_bind_template_child (widget_class, BzFlathubPage, stack); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, is_null); gtk_widget_class_bind_template_callback (widget_class, bind_widget_cb); gtk_widget_class_bind_template_callback (widget_class, unbind_widget_cb); gtk_widget_class_bind_template_callback (widget_class, get_category_by_name_cb); gtk_widget_class_bind_template_callback (widget_class, show_more_mobile_cb); gtk_widget_class_bind_template_callback (widget_class, show_more_gaming_cb); gtk_widget_class_bind_template_callback (widget_class, open_search_cb); } static void bz_flathub_page_init (BzFlathubPage *self) { gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_flathub_page_new (void) { return g_object_new (BZ_TYPE_FLATHUB_PAGE, NULL); } void bz_flathub_page_set_state (BzFlathubPage *self, BzStateInfo *state) { g_return_if_fail (BZ_IS_FLATHUB_PAGE (self)); g_return_if_fail (state == NULL || BZ_IS_STATE_INFO (state)); if (self->state != NULL) g_signal_handlers_disconnect_by_func (self->state, invalidating_state_changed, self); g_clear_object (&self->state); if (state != NULL) { self->state = g_object_ref (state); g_signal_connect_swapped ( state, "notify::flathub", G_CALLBACK (invalidating_state_changed), self); g_signal_connect_swapped ( state, "notify::has-flathub", G_CALLBACK (invalidating_state_changed), self); g_signal_connect_swapped ( state, "notify::online", G_CALLBACK (invalidating_state_changed), self); } invalidating_state_changed (self, NULL, state); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_STATE]); } BzStateInfo * bz_flathub_page_get_state (BzFlathubPage *self) { g_return_val_if_fail (BZ_IS_FLATHUB_PAGE (self), NULL); return self->state; } static void show_more_clicked (BzFlathubPage *self, GtkButton *button, const char *category_name) { g_autoptr (BzFlathubCategory) category = NULL; GtkWidget *nav_view = NULL; AdwNavigationPage *apps_page = NULL; category = get_category_by_name ( bz_flathub_state_get_categories ( bz_state_info_get_flathub (self->state)), category_name); if (category == NULL) return; apps_page = bz_apps_page_new_from_category (category); nav_view = gtk_widget_get_ancestor (GTK_WIDGET (self), ADW_TYPE_NAVIGATION_VIEW); g_assert (nav_view != NULL); adw_navigation_view_push (ADW_NAVIGATION_VIEW (nav_view), apps_page); } static void tile_clicked (BzEntryGroup *group, GtkButton *button) { show_group_action (GTK_WIDGET (button), group); } static void invalidating_state_changed (BzFlathubPage *self, GParamSpec *pspec, BzStateInfo *info) { BzFlathubState *flathub = NULL; gboolean has_repo = FALSE; const char *page = NULL; if (self->state != NULL) { flathub = bz_state_info_get_flathub (self->state); has_repo = bz_state_info_get_has_flathub (self->state); } if (flathub != NULL && has_repo) page = "content"; else if (!has_repo) page = "empty"; else page = "offline"; adw_view_stack_set_visible_child_name (self->stack, page); } bazaar-orig-v0.7.14/src/bz-favorite-button.blp0000664000175000017500000000206015166123241020165 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzFavoriteButton: Button { styles [ "small-pill", "suggested-action", "favorite", ] margin-top: 8; valign: start; halign: start; has-tooltip: true; tooltip-text: _("Favorite Count"); visible: bind template.entry as <$BzEntry>.is-flathub; clicked => $button_clicked_cb() swapped; child: Stack stack { transition-type: crossfade; StackPage { name: "content"; child: Box box { Image icon { icon-name: "bookmark-outline-symbolic"; } Revealer count_revealer { reveal-child: bind $is_positive(template.entry as <$BzEntry>.favorites-count) as ; transition-type: slide_left; child: Label count_label { margin-start: 4; label: bind $format_favorites_count(template.entry as <$BzEntry>.favorites-count) as ; }; } }; } StackPage { name: "spinner"; child: Adw.Spinner { halign: center; width-request: 16; }; } }; }bazaar-orig-v0.7.14/src/bz-progress-bar.h0000664000175000017500000000223015166123241017114 0ustar hasanhasan/* bz-progress-bar.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_PROGRESS_BAR (bz_progress_bar_get_type ()) G_DECLARE_FINAL_TYPE (BzProgressBar, bz_progress_bar, BZ, PROGRESS_BAR, AdwBin) GtkWidget * bz_progress_bar_new (void); void bz_progress_bar_set_fraction (BzProgressBar *self, double fraction); double bz_progress_bar_get_fraction (BzProgressBar *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-io.c0000664000175000017500000002750715166123241015126 0ustar hasanhasan/* bz-io.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-io.h" #include "bz-env.h" static DexFuture * reap_file_fiber (GFile *file); static DexFuture * reap_path_fiber (char *path); static DexFuture * get_directory_size_fiber (GFile *file); static DexFuture * get_user_data_size_fiber (char *app_id); static DexFuture * get_all_user_data_ids_fiber (void); char * bz_dup_user_data_path (const char *app_id) { g_return_val_if_fail (app_id != NULL, NULL); return g_build_filename (g_get_home_dir (), ".var", "app", app_id, NULL); } DexScheduler * bz_get_io_scheduler (void) { static DexScheduler *scheduler = NULL; if (g_once_init_enter_pointer (&scheduler)) g_once_init_leave_pointer (&scheduler, dex_thread_pool_scheduler_new ()); return scheduler; } void bz_reap_file (GFile *file) { g_autoptr (GError) local_error = NULL; g_autofree gchar *uri = NULL; g_autoptr (GFileEnumerator) enumerator = NULL; gboolean result = FALSE; g_return_if_fail (G_IS_FILE (file)); uri = g_file_get_uri (file); if (uri == NULL) uri = g_file_get_path (file); enumerator = g_file_enumerate_children ( file, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK "," G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error); if (enumerator == NULL) { if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) g_warning ("failed to reap cache directory '%s': %s", uri, local_error->message); g_clear_pointer (&local_error, g_error_free); return; } for (;;) { g_autoptr (GFileInfo) info = NULL; g_autoptr (GFile) child = NULL; GFileType file_type = G_FILE_TYPE_UNKNOWN; info = g_file_enumerator_next_file (enumerator, NULL, &local_error); if (info == NULL) { if (local_error != NULL) g_warning ("failed to enumerate cache directory '%s': %s", uri, local_error->message); g_clear_pointer (&local_error, g_error_free); break; } child = g_file_enumerator_get_child (enumerator, info); file_type = g_file_info_get_file_type (info); if (!g_file_info_get_is_symlink (info) && file_type == G_FILE_TYPE_DIRECTORY) bz_reap_file (child); else { result = g_file_delete (child, NULL, &local_error); if (!result) { g_warning ("failed to reap cache directory '%s': %s", uri, local_error->message); g_clear_pointer (&local_error, g_error_free); } } } result = g_file_enumerator_close (enumerator, NULL, &local_error); if (!result) { g_warning ("failed to reap cache directory '%s': %s", uri, local_error->message); g_clear_pointer (&local_error, g_error_free); } result = g_file_delete (file, NULL, &local_error); if (!result) { g_warning ("failed to reap cache directory '%s': %s", uri, local_error->message); g_clear_pointer (&local_error, g_error_free); } } static void trash_file_callback (GObject *object, GAsyncResult *result, gpointer user_data) { g_autoptr (DexPromise) promise = user_data; g_autoptr (GError) error = NULL; if (g_file_trash_finish (G_FILE (object), result, &error)) dex_promise_resolve_boolean (promise, TRUE); else dex_promise_reject (promise, g_steal_pointer (&error)); } static DexFuture * trash_file_dex (GFile *file) { DexPromise *promise = dex_promise_new_cancellable (); g_file_trash_async (file, G_PRIORITY_DEFAULT, dex_promise_get_cancellable (promise), trash_file_callback, dex_ref (promise)); return DEX_FUTURE (promise); } static DexFuture * reap_user_data_fiber (char *app_id) { g_autofree char *user_data_path = NULL; g_autoptr (GFile) file = NULL; g_autoptr (DexFuture) trash_future = NULL; g_autoptr (GError) error = NULL; gboolean result = FALSE; user_data_path = bz_dup_user_data_path (app_id); file = g_file_new_for_path (user_data_path); trash_future = trash_file_dex (file); result = dex_await_boolean (dex_ref (trash_future), &error); if (!result) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) g_warning ("failed to trash user data '%s': %s", user_data_path, error->message); } return dex_future_new_true (); } DexFuture * bz_reap_user_data_dex (const char *app_id) { dex_return_error_if_fail (app_id != NULL); return dex_scheduler_spawn ( bz_get_io_scheduler (), bz_get_dex_stack_size (), (DexFiberFunc) reap_user_data_fiber, g_strdup (app_id), g_free); } void bz_reap_path (const char *path) { g_autoptr (GFile) file = NULL; g_return_if_fail (path != NULL); file = g_file_new_for_path (path); bz_reap_file (file); } DexFuture * bz_reap_file_dex (GFile *file) { dex_return_error_if_fail (G_IS_FILE (file)); return dex_scheduler_spawn ( bz_get_io_scheduler (), bz_get_dex_stack_size (), (DexFiberFunc) reap_file_fiber, g_object_ref (file), g_object_unref); } DexFuture * bz_reap_path_dex (const char *path) { dex_return_error_if_fail (path != NULL); return dex_scheduler_spawn ( bz_get_io_scheduler (), bz_get_dex_stack_size (), (DexFiberFunc) reap_path_fiber, g_strdup (path), g_free); } DexFuture * bz_get_user_data_size_dex (const char *app_id) { dex_return_error_if_fail (app_id != NULL); return dex_scheduler_spawn ( bz_get_io_scheduler (), bz_get_dex_stack_size (), (DexFiberFunc) get_user_data_size_fiber, g_strdup (app_id), g_free); } DexFuture * bz_get_user_data_ids_dex (void) { return dex_scheduler_spawn ( bz_get_io_scheduler (), bz_get_dex_stack_size (), (DexFiberFunc) get_all_user_data_ids_fiber, NULL, NULL); } static DexFuture * get_user_data_size_fiber (char *app_id) { g_autofree char *user_data_path = NULL; g_autoptr (GFile) file = NULL; user_data_path = bz_dup_user_data_path (app_id); file = g_file_new_for_path (user_data_path); return get_directory_size_fiber (file); } static DexFuture * get_directory_size_fiber (GFile *file) { g_autoptr (DexFuture) enumerator_future = NULL; g_autoptr (GFileEnumerator) enumerator = NULL; g_autoptr (GError) error = NULL; guint64 total_size = 0; enumerator_future = dex_file_enumerate_children ( file, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, G_PRIORITY_DEFAULT); enumerator = dex_await_object (dex_ref (enumerator_future), &error); if (enumerator == NULL) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) return dex_future_new_for_uint64 (0); return dex_future_new_for_error (g_steal_pointer (&error)); } for (;;) { g_autoptr (DexFuture) next_future = NULL; g_autolist (GFileInfo) infos = NULL; next_future = dex_file_enumerator_next_files (enumerator, 10, G_PRIORITY_DEFAULT); infos = dex_await_boxed (dex_ref (next_future), &error); if (infos == NULL) { if (error != NULL) return dex_future_new_for_error (g_steal_pointer (&error)); break; } for (GList *l = infos; l != NULL; l = l->next) { GFileInfo *info = l->data; GFileType file_type = g_file_info_get_file_type (info); if (file_type == G_FILE_TYPE_DIRECTORY) { g_autoptr (GFile) child = g_file_enumerator_get_child (enumerator, info); g_autoptr (DexFuture) size_future = get_directory_size_fiber (child); guint64 child_size = dex_await_uint64 (dex_ref (size_future), &error); if (error != NULL) return dex_future_new_for_error (g_steal_pointer (&error)); total_size += child_size; } else { total_size += g_file_info_get_size (info); } } } return dex_future_new_for_uint64 (total_size); } static DexFuture * get_all_user_data_ids_fiber (void) { g_autofree char *var_app_path = NULL; g_autoptr (GFile) var_app_dir = NULL; g_autoptr (DexFuture) enumerator_future = NULL; g_autoptr (GFileEnumerator) enumerator = NULL; g_autoptr (GError) error = NULL; GHashTable *ids = NULL; var_app_path = g_build_filename (g_get_home_dir (), ".var", "app", NULL); var_app_dir = g_file_new_for_path (var_app_path); ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); enumerator_future = dex_file_enumerate_children ( var_app_dir, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, G_PRIORITY_DEFAULT); enumerator = dex_await_object (dex_ref (enumerator_future), &error); if (enumerator == NULL) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) return dex_future_new_take_boxed (G_TYPE_HASH_TABLE, ids); g_hash_table_unref (ids); return dex_future_new_for_error (g_steal_pointer (&error)); } for (;;) { g_autoptr (DexFuture) next_future = NULL; g_autolist (GFileInfo) infos = NULL; next_future = dex_file_enumerator_next_files (enumerator, 10, G_PRIORITY_DEFAULT); infos = dex_await_boxed (dex_ref (next_future), &error); if (infos == NULL) { if (error != NULL) { g_hash_table_unref (ids); return dex_future_new_for_error (g_steal_pointer (&error)); } break; } for (GList *l = infos; l != NULL; l = l->next) { GFileInfo *info = l->data; GFileType file_type = g_file_info_get_file_type (info); if (file_type == G_FILE_TYPE_DIRECTORY) { const char *app_id = g_file_info_get_name (info); g_hash_table_insert (ids, g_strdup (app_id), NULL); } } } return dex_future_new_take_boxed (G_TYPE_HASH_TABLE, ids); } char * bz_dup_root_cache_dir (void) { const char *user_cache = NULL; const char *id = NULL; user_cache = g_get_user_cache_dir (); id = g_application_get_application_id (g_application_get_default ()); if (id == NULL) id = "Bazaar"; return g_build_filename (user_cache, id, NULL); } char * bz_dup_cache_dir (const char *submodule) { g_autofree char *root_cache_dir = NULL; g_return_val_if_fail (submodule != NULL, NULL); root_cache_dir = bz_dup_root_cache_dir (); return g_build_filename (root_cache_dir, submodule, NULL); } static DexFuture * reap_file_fiber (GFile *file) { bz_reap_file (file); return dex_future_new_true (); } static DexFuture * reap_path_fiber (char *path) { bz_reap_path (path); return dex_future_new_true (); } bazaar-orig-v0.7.14/src/bz-favorites-tile.c0000664000175000017500000002475315166123241017454 0ustar hasanhasan/* bz-favorites-tile.c * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include "bz-entry-group-util.h" #include "bz-entry-group.h" #include "bz-env.h" #include "bz-error.h" #include "bz-favorites-page.h" #include "bz-favorites-tile.h" #include "bz-global-net.h" #include "bz-state-info.h" #include "bz-window.h" struct _BzFavoritesTile { BzListTile parent_instance; BzEntryGroup *group; GtkPicture *icon_picture; GtkImage *fallback_icon; GtkLabel *title_label; GtkLabel *description_label; GtkButton *install_remove_button; GtkButton *support_button; GtkButton *unfavorite_button; GtkStack *unfavorite_stack; }; G_DEFINE_FINAL_TYPE (BzFavoritesTile, bz_favorites_tile, BZ_TYPE_LIST_TILE) enum { PROP_0, PROP_GROUP, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; enum { SIGNAL_UNFAVORITED, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL]; static void install_remove_cb (BzFavoritesTile *self, GtkButton *button); static void support_cb (BzFavoritesTile *self, GtkButton *button); static DexFuture * unfavorite_fiber (BzFavoritesTile *tile); static void unfavorite_cb (BzFavoritesTile *self, GtkButton *button); static void bz_favorites_tile_dispose (GObject *object) { BzFavoritesTile *self = BZ_FAVORITES_TILE (object); g_clear_object (&self->group); G_OBJECT_CLASS (bz_favorites_tile_parent_class)->dispose (object); } static void bz_favorites_tile_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzFavoritesTile *self = BZ_FAVORITES_TILE (object); switch (prop_id) { case PROP_GROUP: g_value_set_object (value, bz_favorites_tile_get_group (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_favorites_tile_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzFavoritesTile *self = BZ_FAVORITES_TILE (object); switch (prop_id) { case PROP_GROUP: bz_favorites_tile_set_group (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static gboolean is_null (gpointer object, GObject *value) { return value == NULL; } static gboolean is_zero (gpointer object, int value) { return value == 0; } static char * get_install_remove_tooltip (gpointer object, int removable) { if (removable > 0) return g_strdup (_ ("Uninstall")); else return g_strdup (_ ("Install")); } static char * get_install_remove_icon (gpointer object, int removable) { if (removable > 0) return g_strdup ("user-trash-symbolic"); else return g_strdup ("document-save-symbolic"); } static gboolean switch_bool (gpointer object, gboolean condition, gboolean true_value, gboolean false_value) { return condition ? true_value : false_value; } static gboolean logical_and (gpointer object, gboolean value1, gboolean value2) { return value1 && value2; } static void bz_favorites_tile_class_init (BzFavoritesTileClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_favorites_tile_dispose; object_class->get_property = bz_favorites_tile_get_property; object_class->set_property = bz_favorites_tile_set_property; props[PROP_GROUP] = g_param_spec_object ( "group", NULL, NULL, BZ_TYPE_ENTRY_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); signals[SIGNAL_UNFAVORITED] = g_signal_new ( "unfavorited", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, BZ_TYPE_ENTRY_GROUP); g_type_ensure (BZ_TYPE_LIST_TILE); g_type_ensure (BZ_TYPE_ENTRY_GROUP); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-favorites-tile.ui"); gtk_widget_class_bind_template_child (widget_class, BzFavoritesTile, icon_picture); gtk_widget_class_bind_template_child (widget_class, BzFavoritesTile, fallback_icon); gtk_widget_class_bind_template_child (widget_class, BzFavoritesTile, title_label); gtk_widget_class_bind_template_child (widget_class, BzFavoritesTile, description_label); gtk_widget_class_bind_template_child (widget_class, BzFavoritesTile, install_remove_button); gtk_widget_class_bind_template_child (widget_class, BzFavoritesTile, support_button); gtk_widget_class_bind_template_child (widget_class, BzFavoritesTile, unfavorite_button); gtk_widget_class_bind_template_child (widget_class, BzFavoritesTile, unfavorite_stack); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, is_null); gtk_widget_class_bind_template_callback (widget_class, is_zero); gtk_widget_class_bind_template_callback (widget_class, switch_bool); gtk_widget_class_bind_template_callback (widget_class, logical_and); gtk_widget_class_bind_template_callback (widget_class, get_install_remove_tooltip); gtk_widget_class_bind_template_callback (widget_class, get_install_remove_icon); gtk_widget_class_bind_template_callback (widget_class, install_remove_cb); gtk_widget_class_bind_template_callback (widget_class, unfavorite_cb); gtk_widget_class_bind_template_callback (widget_class, support_cb); gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_BUTTON); } static void bz_favorites_tile_init (BzFavoritesTile *self) { gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_favorites_tile_new (void) { return g_object_new (BZ_TYPE_FAVORITES_TILE, NULL); } void bz_favorites_tile_set_group (BzFavoritesTile *self, BzEntryGroup *group) { g_return_if_fail (BZ_IS_FAVORITES_TILE (self)); g_return_if_fail (group == NULL || BZ_IS_ENTRY_GROUP (group)); g_clear_object (&self->group); if (group != NULL) self->group = g_object_ref (group); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_GROUP]); } BzEntryGroup * bz_favorites_tile_get_group (BzFavoritesTile *self) { g_return_val_if_fail (BZ_IS_FAVORITES_TILE (self), NULL); return self->group; } static void install_remove_cb (BzFavoritesTile *self, GtkButton *button) { int removable = 0; if (self->group == NULL) return; removable = bz_entry_group_get_removable (self->group); if (removable > 0) gtk_widget_activate_action (GTK_WIDGET (self), "window.remove-group", "(sb)", bz_entry_group_get_id (self->group), FALSE); else gtk_widget_activate_action (GTK_WIDGET (self), "window.install-group", "(sb)", bz_entry_group_get_id (self->group), TRUE); } static void support_cb (BzFavoritesTile *self, GtkButton *button) { const char *url = NULL; if (self->group == NULL) return; url = bz_entry_group_get_donation_url (self->group); if (url == NULL) return; g_app_info_launch_default_for_uri (url, NULL, NULL); } static DexFuture * unfavorite_fiber (BzFavoritesTile *tile) { g_autoptr (GError) local_error = NULL; g_autoptr (BzStateInfo) state = NULL; g_autofree char *request = NULL; BzFavoritesPage *page = NULL; BzAuthState *auth_state = NULL; const char *token = NULL; const char *app_id = NULL; GtkWidget *revealer = NULL; GtkWidget *row = NULL; revealer = gtk_widget_get_parent (GTK_WIDGET (tile)); row = gtk_widget_get_parent (GTK_WIDGET (revealer)); page = BZ_FAVORITES_PAGE (gtk_widget_get_ancestor (GTK_WIDGET (tile), BZ_TYPE_FAVORITES_PAGE)); if (page == NULL) return NULL; g_object_get (page, "state", &state, NULL); if (state == NULL) return NULL; auth_state = bz_state_info_get_auth_state (state); token = bz_auth_state_get_token (auth_state); if (token == NULL || !bz_auth_state_is_authenticated (auth_state)) return NULL; app_id = bz_entry_group_get_id (tile->group); request = g_strdup_printf ("/favorites/%s/remove", app_id); dex_await ( bz_query_flathub_v2_json_authenticated_delete (request, token), &local_error); if (local_error != NULL) { GtkWidget *window = NULL; gtk_stack_set_visible_child_name (tile->unfavorite_stack, "button"); window = gtk_widget_get_ancestor (GTK_WIDGET (tile), GTK_TYPE_WINDOW); if (window != NULL) bz_show_error_for_widget (window, _("Failed to remove favorite"), local_error->message); } else { gtk_widget_set_overflow (revealer, GTK_OVERFLOW_HIDDEN); gtk_revealer_set_reveal_child (GTK_REVEALER (revealer), FALSE); gtk_widget_add_css_class (row, "hidden"); g_signal_emit (tile, signals[SIGNAL_UNFAVORITED], 0, tile->group); } return NULL; } static void unfavorite_cb (BzFavoritesTile *self, GtkButton *button) { gtk_stack_set_visible_child_name (self->unfavorite_stack, "spinner"); dex_future_disown (dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) unfavorite_fiber, g_object_ref (self), g_object_unref)); } bazaar-orig-v0.7.14/src/bz-transaction-list-dialog.h0000664000175000017500000000277515166123241021257 0ustar hasanhasan/* bz-transaction-list-dialog.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_TRANSACTION_LIST_DIALOG (bz_transaction_list_dialog_get_type ()) G_DECLARE_FINAL_TYPE (BzTransactionListDialog, bz_transaction_list_dialog, BZ, TRANSACTION_LIST_DIALOG, AdwAlertDialog) AdwDialog * bz_transaction_list_dialog_new (GListModel *entries, const gchar *heading, const gchar *body, const gchar *body_no_apps, const gchar *secondary_label, const gchar *cancel_label, const gchar *confirm_label); gboolean bz_transaction_list_dialog_was_confirmed (BzTransactionListDialog *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-featured-carousel.blp0000664000175000017500000000313115166123241020447 0ustar hasanhasanusing Gtk 4.0; template $BzFeaturedCarousel: Box { orientation: vertical; spacing: 12; styles [ "featured-carousel", ] Overlay { [overlay] Button previous_button { halign: start; valign: center; width-request: 48; height-request: 48; margin-start: 12; icon-name: "go-previous-symbolic"; visible: bind $is_gt(selection.n-items, 1); clicked => $previous_button_clicked_cb(); styles [ "circular", "flat", "image-button", ] accessibility { label: _("Previous"); } } [overlay] Button next_button { halign: end; valign: center; width-request: 48; height-request: 48; margin-end: 12; icon-name: "go-next-symbolic"; visible: bind $is_gt(selection.n-items, 1); clicked => $next_button_clicked_cb(); styles [ "circular", "flat", "image-button", ] accessibility { label: _("Next"); } } child: $BgeCarousel carousel { styles ["card"] allow-mouse-drag: true; allow-overshoot: false; allow-scroll-wheel: true; allow-raise: false; create-widget => $on_create_widget(template); remove-widget => $on_remove_widget(template); model: SingleSelection selection { autoselect: true; model: bind template.model; notify::selected => $on_notify_selected(template); // notify::n-items => $on_notify_n_items(template); }; }; } EventControllerKey { key-pressed => $key_pressed_cb(); } } bazaar-orig-v0.7.14/src/bz-curated-view.c0000664000175000017500000002115615166123241017110 0ustar hasanhasan/* bz-curated-view.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include "bz-curated-row.h" #include "bz-curated-view.h" #include "bz-dynamic-list-view.h" #include "bz-entry-group.h" #include "bz-inhibited-scrollable.h" #include "bz-root-curated-config.h" #include "bz-row-view.h" struct _BzCuratedView { AdwBin parent_instance; BzStateInfo *state; BzContentProvider *curated_provider; GPtrArray *css_providers; /* Template widgets */ AdwViewStack *stack; }; G_DEFINE_FINAL_TYPE (BzCuratedView, bz_curated_view, ADW_TYPE_BIN) enum { PROP_0, PROP_STATE, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; enum { SIGNAL_BROWSE_FLATHUB, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL]; static void items_changed (BzCuratedView *self, guint position, guint removed, guint added, GListModel *model); static void online_changed (BzCuratedView *self, GParamSpec *pspec, BzStateInfo *info); static void set_page (BzCuratedView *self); static void release_css_provider (gpointer ptr); static void bz_curated_view_dispose (GObject *object) { BzCuratedView *self = BZ_CURATED_VIEW (object); if (self->state != NULL) g_signal_handlers_disconnect_by_func ( self->state, online_changed, self); if (self->curated_provider != NULL) g_signal_handlers_disconnect_by_func ( self->curated_provider, items_changed, self); g_clear_object (&self->state); g_clear_object (&self->curated_provider); g_clear_pointer (&self->css_providers, g_ptr_array_unref); G_OBJECT_CLASS (bz_curated_view_parent_class)->dispose (object); } static void bz_curated_view_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzCuratedView *self = BZ_CURATED_VIEW (object); switch (prop_id) { case PROP_STATE: g_value_set_object (value, bz_curated_view_get_state (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_curated_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzCuratedView *self = BZ_CURATED_VIEW (object); switch (prop_id) { case PROP_STATE: bz_curated_view_set_state (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void browse_flathub_cb (BzCuratedView *self, GtkButton *button) { g_signal_emit (self, signals[SIGNAL_BROWSE_FLATHUB], 0); } static void bz_curated_view_class_init (BzCuratedViewClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_curated_view_dispose; object_class->get_property = bz_curated_view_get_property; object_class->set_property = bz_curated_view_set_property; props[PROP_STATE] = g_param_spec_object ( "state", NULL, NULL, BZ_TYPE_STATE_INFO, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); signals[SIGNAL_BROWSE_FLATHUB] = g_signal_new ( "browse-flathub", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_type_ensure (BZ_TYPE_ROW_VIEW); g_type_ensure (BZ_TYPE_ROOT_CURATED_CONFIG); g_type_ensure (BZ_TYPE_CURATED_ROW); g_type_ensure (BZ_TYPE_DYNAMIC_LIST_VIEW); g_type_ensure (BZ_TYPE_INHIBITED_SCROLLABLE); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-curated-view.ui"); gtk_widget_class_bind_template_child (widget_class, BzCuratedView, stack); gtk_widget_class_bind_template_callback (widget_class, browse_flathub_cb); } static void bz_curated_view_init (BzCuratedView *self) { self->css_providers = g_ptr_array_new_with_free_func (release_css_provider); gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_curated_view_new (void) { return g_object_new (BZ_TYPE_CURATED_VIEW, NULL); } void bz_curated_view_set_state (BzCuratedView *self, BzStateInfo *state) { g_return_if_fail (BZ_IS_CURATED_VIEW (self)); g_return_if_fail (state == NULL || BZ_IS_STATE_INFO (state)); if (self->state != NULL) g_signal_handlers_disconnect_by_func ( self->state, online_changed, self); if (self->curated_provider != NULL) { g_signal_handlers_disconnect_by_func ( self->curated_provider, items_changed, self); items_changed ( self, 0, g_list_model_get_n_items (G_LIST_MODEL (self->curated_provider)), 0, G_LIST_MODEL (self->curated_provider)); } g_clear_object (&self->state); g_clear_object (&self->curated_provider); if (state != NULL) { self->state = g_object_ref (state); g_signal_connect_swapped ( state, "notify::online", G_CALLBACK (online_changed), self); g_object_get ( state, "curated-provider", &self->curated_provider, NULL); if (self->curated_provider != NULL) { items_changed ( self, 0, 0, g_list_model_get_n_items (G_LIST_MODEL (self->curated_provider)), G_LIST_MODEL (self->curated_provider)); g_signal_connect_swapped ( self->curated_provider, "items-changed", G_CALLBACK (items_changed), self); } } else set_page (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_STATE]); } BzStateInfo * bz_curated_view_get_state (BzCuratedView *self) { g_return_val_if_fail (BZ_IS_CURATED_VIEW (self), NULL); return self->state; } static void items_changed (BzCuratedView *self, guint position, guint removed, guint added, GListModel *model) { if (removed > 0) g_ptr_array_remove_range (self->css_providers, position, removed); for (guint i = 0; i < added; i++) { g_autoptr (BzRootCuratedConfig) config = NULL; const char *css = NULL; g_autoptr (GtkCssProvider) provider = NULL; config = g_list_model_get_item (model, position + i); css = bz_root_curated_config_get_css (config); provider = gtk_css_provider_new (); if (css != NULL) gtk_css_provider_load_from_string (provider, css); gtk_style_context_add_provider_for_display ( gdk_display_get_default (), GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER); g_ptr_array_insert (self->css_providers, position + i, g_steal_pointer (&provider)); } set_page (self); } static void online_changed (BzCuratedView *self, GParamSpec *pspec, BzStateInfo *info) { set_page (self); } static void set_page (BzCuratedView *self) { const char *page = NULL; if (self->state != NULL && !bz_state_info_get_online (self->state)) page = "offline"; else if (self->curated_provider != NULL && g_list_model_get_n_items (G_LIST_MODEL (self->curated_provider)) > 0) page = "content"; else page = "empty"; adw_view_stack_set_visible_child_name (self->stack, page); } static void release_css_provider (gpointer ptr) { GtkCssProvider *provider = ptr; gtk_style_context_remove_provider_for_display ( gdk_display_get_default (), GTK_STYLE_PROVIDER (provider)); g_object_unref (provider); } bazaar-orig-v0.7.14/src/bz-install-controls.h0000664000175000017500000000321315166123241020017 0ustar hasanhasan/* bz-install-controls.h * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry-group.h" #include "bz-state-info.h" #include G_BEGIN_DECLS #define BZ_TYPE_INSTALL_CONTROLS (bz_install_controls_get_type ()) G_DECLARE_FINAL_TYPE (BzInstallControls, bz_install_controls, BZ, INSTALL_CONTROLS, GtkBox) GtkWidget * bz_install_controls_new (void); gboolean bz_install_controls_get_wide (BzInstallControls *self); void bz_install_controls_set_wide (BzInstallControls *self, gboolean wide); BzEntryGroup * bz_install_controls_get_entry_group (BzInstallControls *self); void bz_install_controls_set_entry_group (BzInstallControls *self, BzEntryGroup *group); BzStateInfo * bz_install_controls_get_state (BzInstallControls *self); void bz_install_controls_set_state (BzInstallControls *self, BzStateInfo *state); G_END_DECLS bazaar-orig-v0.7.14/src/bz-zoom.c0000664000175000017500000004733615166123241015505 0ustar hasanhasan/* bz-zoom.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-zoom.h" #include #include #define OVERPAN_FACTOR 0.5 struct _BzZoom { GtkWidget parent_instance; GtkWidget *child; double zoom_level; double min_zoom; double max_zoom; double pan_x; double pan_y; double mouse_x; double mouse_y; double gesture_start_zoom; double drag_start_x; double drag_start_y; gboolean is_dragging; AdwAnimation *zoom_animation; double target_zoom; double target_pan_x; double target_pan_y; double start_zoom; double start_pan_x; double start_pan_y; GtkGesture *zoom_gesture; GtkGesture *drag_gesture; GtkEventController *scroll_controller; GtkEventController *motion_controller; }; G_DEFINE_FINAL_TYPE (BzZoom, bz_zoom, GTK_TYPE_WIDGET) enum { PROP_0, PROP_CHILD, PROP_ZOOM_LEVEL, PROP_MIN_ZOOM, PROP_MAX_ZOOM, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bz_zoom_constrain_pan (BzZoom *self); static void bz_zoom_zoom_at_point (BzZoom *self, double zoom_factor, double center_x, double center_y); static void bz_zoom_dispose (GObject *object) { BzZoom *self; self = BZ_ZOOM (object); g_clear_pointer (&self->child, gtk_widget_unparent); g_clear_object (&self->zoom_animation); G_OBJECT_CLASS (bz_zoom_parent_class)->dispose (object); } static void bz_zoom_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzZoom *self; self = BZ_ZOOM (object); switch (prop_id) { case PROP_CHILD: g_value_set_object (value, bz_zoom_get_child (self)); break; case PROP_ZOOM_LEVEL: g_value_set_double (value, bz_zoom_get_zoom_level (self)); break; case PROP_MIN_ZOOM: g_value_set_double (value, bz_zoom_get_min_zoom (self)); break; case PROP_MAX_ZOOM: g_value_set_double (value, bz_zoom_get_max_zoom (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_zoom_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzZoom *self; self = BZ_ZOOM (object); switch (prop_id) { case PROP_CHILD: bz_zoom_set_child (self, g_value_get_object (value)); break; case PROP_ZOOM_LEVEL: bz_zoom_set_zoom_level (self, g_value_get_double (value)); break; case PROP_MIN_ZOOM: bz_zoom_set_min_zoom (self, g_value_get_double (value)); break; case PROP_MAX_ZOOM: bz_zoom_set_max_zoom (self, g_value_get_double (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void on_motion (BzZoom *self, double x, double y, GtkEventControllerMotion *controller) { self->mouse_x = x; self->mouse_y = y; } static void on_zoom_begin (BzZoom *self, GdkEventSequence *sequence, GtkGesture *gesture) { self->gesture_start_zoom = self->zoom_level; } static void on_zoom_changed (BzZoom *self, double scale, GtkGesture *gesture) { double target_zoom; double zoom_factor; double center_x; double center_y; target_zoom = self->gesture_start_zoom * scale; if (self->zoom_level > 0) zoom_factor = target_zoom / self->zoom_level; else zoom_factor = 1.0; gtk_gesture_get_bounding_box_center (gesture, ¢er_x, ¢er_y); bz_zoom_zoom_at_point (self, zoom_factor, center_x, center_y); } static gboolean on_scroll (BzZoom *self, double dx, double dy, GtkEventControllerScroll *controller) { GdkEvent *event; GdkDevice *device; GdkInputSource source; double zoom_factor; event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (controller)); if (event == NULL) return GDK_EVENT_PROPAGATE; device = gdk_event_get_device (event); if (device == NULL) return GDK_EVENT_PROPAGATE; source = gdk_device_get_source (device); if (source != GDK_SOURCE_MOUSE) return GDK_EVENT_PROPAGATE; zoom_factor = dy < 0 ? 1.1 : 0.9; bz_zoom_zoom_at_point (self, zoom_factor, self->mouse_x, self->mouse_y); return GDK_EVENT_STOP; } static void on_drag_begin (BzZoom *self, double start_x, double start_y, GtkGesture *gesture) { if (!bz_zoom_is_transformed(self)) { gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_DENIED); return; } self->drag_start_x = self->pan_x; self->drag_start_y = self->pan_y; self->is_dragging = TRUE; } static void on_drag_update (BzZoom *self, double offset_x, double offset_y, GtkGesture *gesture) { if (!self->is_dragging) return; self->pan_x = self->drag_start_x + offset_x; self->pan_y = self->drag_start_y + offset_y; bz_zoom_constrain_pan (self); gtk_widget_queue_draw (GTK_WIDGET (self)); } static void on_drag_end (BzZoom *self, double offset_x, double offset_y, GtkGesture *gesture) { self->is_dragging = FALSE; } static void bz_zoom_snapshot (GtkWidget *widget, GtkSnapshot *snapshot) { BzZoom *self; int width; int height; GskTransform *transform; graphene_point_t point; self = BZ_ZOOM (widget); width = gtk_widget_get_width (widget); height = gtk_widget_get_height (widget); if (width <= 0 || height <= 0) return; transform = NULL; graphene_point_init (&point, width / 2.0 + self->pan_x, height / 2.0 + self->pan_y); transform = gsk_transform_translate (transform, &point); /* See bz_zoom_size_allocate */ // transform = gsk_transform_scale (transform, self->zoom_level, self->zoom_level); graphene_point_init ( &point, -(width * self->zoom_level) / 2.0, -(height * self->zoom_level) / 2.0); transform = gsk_transform_translate (transform, &point); gtk_snapshot_save (snapshot); gtk_snapshot_transform (snapshot, transform); if (self->child) gtk_widget_snapshot_child (widget, self->child, snapshot); gtk_snapshot_restore (snapshot); gsk_transform_unref (transform); } static void bz_zoom_measure (GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline) { BzZoom *self; self = BZ_ZOOM (widget); if (self->child) gtk_widget_measure (self->child, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline); else { *minimum = 0; *natural = 0; } } static void bz_zoom_size_allocate (GtkWidget *widget, int width, int height, int baseline) { BzZoom *self; self = BZ_ZOOM (widget); if (self->child) /* TODO: maybe add a property to control whether the child is artificially scaled? */ gtk_widget_allocate ( self->child, self->zoom_level * width, self->zoom_level * height, baseline, NULL); bz_zoom_constrain_pan (self); } static void bz_zoom_class_init (BzZoomClass *klass) { GObjectClass *object_class; GtkWidgetClass *widget_class; object_class = G_OBJECT_CLASS (klass); widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_zoom_dispose; object_class->get_property = bz_zoom_get_property; object_class->set_property = bz_zoom_set_property; widget_class->snapshot = bz_zoom_snapshot; widget_class->measure = bz_zoom_measure; widget_class->size_allocate = bz_zoom_size_allocate; props[PROP_CHILD] = g_param_spec_object ( "child", NULL, NULL, GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_ZOOM_LEVEL] = g_param_spec_double ( "zoom-level", NULL, NULL, 0.1, 10.0, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_MIN_ZOOM] = g_param_spec_double ( "min-zoom", NULL, NULL, 0.1, 1.0, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_MAX_ZOOM] = g_param_spec_double ( "max-zoom", NULL, NULL, 1.0, 10.0, 5.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_zoom_init (BzZoom *self) { self->zoom_level = 1.0; self->min_zoom = 1.0; self->max_zoom = 5.0; self->pan_x = 0.0; self->pan_y = 0.0; self->mouse_x = 0.0; self->mouse_y = 0.0; self->gesture_start_zoom = 1.0; self->is_dragging = FALSE; self->zoom_gesture = gtk_gesture_zoom_new (); g_signal_connect_swapped (self->zoom_gesture, "begin", G_CALLBACK (on_zoom_begin), self); g_signal_connect_swapped (self->zoom_gesture, "scale-changed", G_CALLBACK (on_zoom_changed), self); gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (self->zoom_gesture)); self->drag_gesture = gtk_gesture_drag_new (); gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (self->drag_gesture), GDK_BUTTON_PRIMARY); g_signal_connect_swapped (self->drag_gesture, "drag-begin", G_CALLBACK (on_drag_begin), self); g_signal_connect_swapped (self->drag_gesture, "drag-update", G_CALLBACK (on_drag_update), self); g_signal_connect_swapped (self->drag_gesture, "drag-end", G_CALLBACK (on_drag_end), self); gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (self->drag_gesture)); self->scroll_controller = gtk_event_controller_scroll_new (GTK_EVENT_CONTROLLER_SCROLL_VERTICAL | GTK_EVENT_CONTROLLER_SCROLL_HORIZONTAL); g_signal_connect_swapped (self->scroll_controller, "scroll", G_CALLBACK (on_scroll), self); gtk_widget_add_controller (GTK_WIDGET (self), self->scroll_controller); self->motion_controller = gtk_event_controller_motion_new (); g_signal_connect_swapped (self->motion_controller, "motion", G_CALLBACK (on_motion), self); gtk_widget_add_controller (GTK_WIDGET (self), self->motion_controller); gtk_widget_set_focusable (GTK_WIDGET (self), TRUE); } GtkWidget * bz_zoom_new (void) { return g_object_new (BZ_TYPE_ZOOM, NULL); } GtkWidget * bz_zoom_get_child (BzZoom *self) { g_return_val_if_fail (BZ_IS_ZOOM (self), NULL); return self->child; } void bz_zoom_set_child (BzZoom *self, GtkWidget *child) { g_return_if_fail (BZ_IS_ZOOM (self)); g_return_if_fail (child == NULL || GTK_IS_WIDGET (child)); if (self->child == child) return; g_clear_pointer (&self->child, gtk_widget_unparent); self->child = child; if (self->child) gtk_widget_set_parent (self->child, GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CHILD]); } double bz_zoom_get_zoom_level (BzZoom *self) { g_return_val_if_fail (BZ_IS_ZOOM (self), 1.0); return self->zoom_level; } void bz_zoom_set_zoom_level (BzZoom *self, double zoom_level) { double new_zoom; g_return_if_fail (BZ_IS_ZOOM (self)); new_zoom = CLAMP (zoom_level, self->min_zoom, self->max_zoom); if (fabs (new_zoom - self->zoom_level) < 0.001) return; self->zoom_level = new_zoom; bz_zoom_constrain_pan (self); gtk_widget_queue_resize (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ZOOM_LEVEL]); } gboolean bz_zoom_is_transformed (BzZoom *self) { g_return_val_if_fail (BZ_IS_ZOOM (self), FALSE); return fabs (self->zoom_level - 1.0) >= 0.001 || fabs (self->pan_x) >= 0.5 || fabs (self->pan_y) >= 0.5; } double bz_zoom_get_min_zoom (BzZoom *self) { g_return_val_if_fail (BZ_IS_ZOOM (self), 1); return self->min_zoom; } void bz_zoom_set_min_zoom (BzZoom *self, double min_zoom) { g_return_if_fail (BZ_IS_ZOOM (self)); self->min_zoom = min_zoom; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MIN_ZOOM]); } double bz_zoom_get_max_zoom (BzZoom *self) { g_return_val_if_fail (BZ_IS_ZOOM (self), 5.0); return self->max_zoom; } void bz_zoom_set_max_zoom (BzZoom *self, double max_zoom) { g_return_if_fail (BZ_IS_ZOOM (self)); self->max_zoom = max_zoom; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MAX_ZOOM]); } static void bz_zoom_constrain_pan (BzZoom *self) { int widget_width; int widget_height; double overpan_x; double overpan_y; double range_x; double range_y; double max_pan_x; double max_pan_y; widget_width = gtk_widget_get_width (GTK_WIDGET (self)); widget_height = gtk_widget_get_height (GTK_WIDGET (self)); if (widget_width <= 0 || widget_height <= 0) return; overpan_x = widget_width * OVERPAN_FACTOR; overpan_y = widget_height * OVERPAN_FACTOR; range_x = MAX (0, (widget_width * self->zoom_level - widget_width) / 2.0); range_y = MAX (0, (widget_height * self->zoom_level - widget_height) / 2.0); max_pan_x = range_x + overpan_x; max_pan_y = range_y + overpan_y; self->pan_x = CLAMP (self->pan_x, -max_pan_x, max_pan_x); self->pan_y = CLAMP (self->pan_y, -max_pan_y, max_pan_y); } static void bz_zoom_zoom_at_point (BzZoom *self, double zoom_factor, double center_x, double center_y) { double old_zoom; double new_zoom; int widget_width; int widget_height; double widget_center_x; double widget_center_y; double old_content_x; double old_content_y; double zoom_ratio; double new_content_x; double new_content_y; old_zoom = self->zoom_level; new_zoom = old_zoom * zoom_factor; new_zoom = CLAMP (new_zoom, self->min_zoom, self->max_zoom); if (fabs (new_zoom - old_zoom) < 0.001) return; widget_width = gtk_widget_get_width (GTK_WIDGET (self)); widget_height = gtk_widget_get_height (GTK_WIDGET (self)); widget_center_x = widget_width / 2.0; widget_center_y = widget_height / 2.0; old_content_x = center_x - widget_center_x - self->pan_x; old_content_y = center_y - widget_center_y - self->pan_y; zoom_ratio = new_zoom / old_zoom; new_content_x = old_content_x * zoom_ratio; new_content_y = old_content_y * zoom_ratio; self->zoom_level = new_zoom; self->pan_x = center_x - widget_center_x - new_content_x; self->pan_y = center_y - widget_center_y - new_content_y; bz_zoom_constrain_pan (self); gtk_widget_queue_resize (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ZOOM_LEVEL]); } static void on_animation_value (double value, BzZoom *self) { self->zoom_level = self->start_zoom + (self->target_zoom - self->start_zoom) * value; self->pan_x = self->start_pan_x + (self->target_pan_x - self->start_pan_x) * value; self->pan_y = self->start_pan_y + (self->target_pan_y - self->start_pan_y) * value; bz_zoom_constrain_pan (self); gtk_widget_queue_resize (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ZOOM_LEVEL]); } static void bz_zoom_animate_to (BzZoom *self, double target_zoom, double target_pan_x, double target_pan_y) { AdwAnimationTarget *target; if (self->zoom_animation) adw_animation_skip (self->zoom_animation); self->start_zoom = self->zoom_level; self->start_pan_x = self->pan_x; self->start_pan_y = self->pan_y; self->target_zoom = target_zoom; self->target_pan_x = target_pan_x; self->target_pan_y = target_pan_y; target = adw_callback_animation_target_new ((AdwAnimationTargetFunc) on_animation_value, self, NULL); self->zoom_animation = adw_timed_animation_new (GTK_WIDGET (self), 0, 1, 150, target); adw_timed_animation_set_easing (ADW_TIMED_ANIMATION (self->zoom_animation), ADW_EASE_OUT_CUBIC); adw_animation_play (self->zoom_animation); } void bz_zoom_zoom_in (BzZoom *self) { int width; int height; double old_zoom; double new_zoom; double widget_center_x; double widget_center_y; double center_x; double center_y; double old_content_x; double old_content_y; double zoom_ratio; double new_content_x; double new_content_y; double new_pan_x; double new_pan_y; g_return_if_fail (BZ_IS_ZOOM (self)); width = gtk_widget_get_width (GTK_WIDGET (self)); height = gtk_widget_get_height (GTK_WIDGET (self)); center_x = width / 2.0; center_y = height / 2.0; old_zoom = self->zoom_level; new_zoom = old_zoom * 1.2; new_zoom = CLAMP (new_zoom, self->min_zoom, self->max_zoom); if (fabs (new_zoom - old_zoom) < 0.001) return; widget_center_x = width / 2.0; widget_center_y = height / 2.0; old_content_x = center_x - widget_center_x - self->pan_x; old_content_y = center_y - widget_center_y - self->pan_y; zoom_ratio = new_zoom / old_zoom; new_content_x = old_content_x * zoom_ratio; new_content_y = old_content_y * zoom_ratio; new_pan_x = center_x - widget_center_x - new_content_x; new_pan_y = center_y - widget_center_y - new_content_y; bz_zoom_animate_to (self, new_zoom, new_pan_x, new_pan_y); } void bz_zoom_zoom_out (BzZoom *self) { int width; int height; double old_zoom; double new_zoom; double widget_center_x; double widget_center_y; double center_x; double center_y; double old_content_x; double old_content_y; double zoom_ratio; double new_content_x; double new_content_y; double new_pan_x; double new_pan_y; g_return_if_fail (BZ_IS_ZOOM (self)); width = gtk_widget_get_width (GTK_WIDGET (self)); height = gtk_widget_get_height (GTK_WIDGET (self)); center_x = width / 2.0; center_y = height / 2.0; old_zoom = self->zoom_level; new_zoom = old_zoom * 0.8; new_zoom = CLAMP (new_zoom, self->min_zoom, self->max_zoom); if (fabs (new_zoom - old_zoom) < 0.001) return; widget_center_x = width / 2.0; widget_center_y = height / 2.0; old_content_x = center_x - widget_center_x - self->pan_x; old_content_y = center_y - widget_center_y - self->pan_y; zoom_ratio = new_zoom / old_zoom; new_content_x = old_content_x * zoom_ratio; new_content_y = old_content_y * zoom_ratio; new_pan_x = center_x - widget_center_x - new_content_x; new_pan_y = center_y - widget_center_y - new_content_y; bz_zoom_animate_to (self, new_zoom, new_pan_x, new_pan_y); } void bz_zoom_reset (BzZoom *self) { g_return_if_fail (BZ_IS_ZOOM (self)); bz_zoom_animate_to (self, 1.0, 0.0, 0.0); } void bz_zoom_fit_to_window (BzZoom *self) { g_return_if_fail (BZ_IS_ZOOM (self)); bz_zoom_animate_to (self, 1.0, 0.0, 0.0); } /* End of bz-zoom.c */ bazaar-orig-v0.7.14/src/bazaar.gresource.xml0000664000175000017500000004346715166123241017724 0ustar hasanhasan style.css internal-config.yaml progress-bar-designs/pride/pride-flags.yaml internal-config-schema.xml main-config-schema.xml blocklist-schema.xml curated-config-schema.xml pride-flag-config-schema.xml release-notes.xml countries.gvariant bz-addon-tile.ui bz-addons-dialog.ui bz-donations-dialog.ui bz-age-rating-dialog.ui bz-app-size-dialog.ui bz-app-tile.ui bz-all-apps-page.ui bz-apps-page.ui bz-appstream-description-render.ui bz-curated-view.ui bz-category-tile.ui bz-context-tile.ui bz-curated-app-tile.ui bz-decorated-screenshot.ui bz-developer-badge.ui bz-entry-inspector.ui bz-entry-selection-row.ui bz-error-dialog.ui bz-favorite-button.ui bz-favorites-page.ui bz-favorites-tile.ui bz-featured-carousel.ui bz-featured-tile.ui bz-flathub-category-section.ui bz-flathub-page.ui bz-full-view.ui bz-hardware-support-dialog.ui bz-inspector.ui bz-install-controls.ui bz-library-page.ui bz-installed-tile.ui bz-license-dialog.ui bz-login-page.ui bz-preferences-dialog.ui bz-progress-bar.ui bz-releases-dialog.ui bz-releases-list.ui bz-rich-app-tile.ui bz-row-view.ui bz-safety-dialog.ui bz-screenshot-page.ui bz-screenshots-carousel.ui bz-search-page.ui bz-search-filter-popover.ui bz-section-view.ui bz-stats-dialog.ui bz-transaction-tile.ui bz-transaction-list-dialog.ui bz-updates-card.ui bz-user-data-page.ui bz-user-data-tile.ui bz-window.ui shortcuts-dialog.ui icons/scalable/actions/app-installed-symbolic.svg icons/scalable/actions/bookmark-filled-symbolic.svg icons/scalable/actions/bookmark-outline-symbolic.svg icons/scalable/actions/bug-symbolic.svg icons/scalable/actions/check-plain-symbolic.svg icons/scalable/actions/circle-filled-symbolic.svg icons/scalable/actions/code-symbolic.svg icons/scalable/actions/community-symbolic.svg icons/scalable/actions/connected-squares-x-symbolic.svg icons/scalable/actions/copy-symbolic.svg icons/scalable/actions/cross-large-circle-filled-symbolic.svg icons/scalable/actions/delay-symbolic.svg icons/scalable/actions/device-support-adaptive-symbolic.svg icons/scalable/actions/device-support-desktop-symbolic.svg icons/scalable/actions/device-support-touch-symbolic.svg icons/scalable/actions/device-supported-symbolic.svg icons/scalable/actions/download-plus-symbolic.svg icons/scalable/actions/drive-harddisk-symbolic.svg icons/scalable/actions/earth-symbolic.svg icons/scalable/actions/edit-clear-all-symbolic.svg icons/scalable/actions/execute-to-symbolic.svg icons/scalable/actions/external-link-symbolic.svg icons/scalable/actions/eye-outline-filled-symbolic.svg icons/scalable/actions/flathub-symbolic.svg icons/scalable/actions/flatpak-symbolic.svg icons/scalable/actions/folder-download-symbolic.svg icons/scalable/actions/globe-symbolic.svg icons/scalable/actions/go-previous-symbolic.svg icons/scalable/actions/graph2-symbolic.svg icons/scalable/actions/hand-openyay-symbolic.svg icons/scalable/actions/heart-filled-symbolic.svg icons/scalable/actions/heart-outline-thick-symbolic.svg icons/scalable/actions/horizontal-arrows-disabled-symbolic.svg icons/scalable/actions/left-large-symbolic.svg icons/scalable/actions/library-symbolic.svg icons/scalable/actions/license-symbolic.svg icons/scalable/actions/meeting-symbolic.svg icons/scalable/actions/media-playback-pause-symbolic.svg icons/scalable/actions/media-playback-start-symbolic.svg icons/scalable/actions/media-playback-stop-symbolic.svg icons/scalable/actions/newspaper-symbolic.svg icons/scalable/actions/open-book-symbolic.svg icons/scalable/actions/parent-symbolic.svg icons/scalable/actions/paintbrush-symbolic.svg icons/scalable/actions/people-symbolic.svg icons/scalable/actions/person-symbolic.svg icons/scalable/actions/pip-out-symbolic.svg icons/scalable/actions/power-profile-performance-symbolic.svg icons/scalable/actions/proprietary-code-symbolic.svg icons/scalable/actions/puzzle-piece-symbolic.svg icons/scalable/actions/regex-symbolic.svg icons/scalable/actions/right-large-symbolic.svg icons/scalable/actions/sad-computer-symbolic.svg icons/scalable/actions/school-symbolic.svg icons/scalable/actions/server-pick-symbolic.svg icons/scalable/actions/share-alt-symbolic.svg icons/scalable/actions/share-symbolic.svg icons/scalable/actions/sidebar-show-symbolic.svg icons/scalable/actions/sliders-horizontal-symbolic.svg icons/scalable/actions/smartphone2-symbolic.svg icons/scalable/actions/software-update-available-symbolic.svg icons/scalable/actions/square-filled-symbolic.svg icons/scalable/actions/thumbs-up-outline-symbolic.svg icons/scalable/actions/timer-sand-symbolic.svg icons/scalable/actions/translations-symbolic.svg icons/scalable/actions/user-trash-symbolic.svg icons/scalable/actions/verified-checkmark-symbolic.svg icons/scalable/actions/view-more-horizontal-symbolic.svg icons/scalable/actions/view-more-symbolic.svg icons/scalable/actions/zoom-minus-symbolic.svg icons/scalable/actions/zoom-plus-symbolic.svg icons/scalable/actions/permissions-legacy-windowing-system-symbolic.svg icons/scalable/actions/permissions-microphone-symbolic.svg icons/scalable/actions/permissions-sandboxed-symbolic.svg icons/scalable/actions/permissions-screen-contents-symbolic.svg icons/scalable/actions/permissions-system-devices-symbolic.svg icons/scalable/actions/permissions-warning-symbolic.svg icons/scalable/actions/app-safety-ok-symbolic.svg icons/scalable/actions/app-safety-unknown-symbolic.svg icons/scalable/actions/app-safety-unsafe-symbolic.svg icons/scalable/actions/auditable-code-symbolic.svg icons/scalable/actions/ratings/advertising-symbolic.svg icons/scalable/actions/ratings/advertising-none-symbolic.svg icons/scalable/actions/ratings/alcohol-use-symbolic.svg icons/scalable/actions/ratings/alcohol-use-none-symbolic.svg icons/scalable/actions/ratings/audio-chat-symbolic.svg icons/scalable/actions/ratings/audio-chat-none-symbolic.svg icons/scalable/actions/ratings/contacts-symbolic.svg icons/scalable/actions/ratings/drug-use-symbolic.svg icons/scalable/actions/ratings/drug-use-none-symbolic.svg icons/scalable/actions/ratings/gambling-symbolic.svg icons/scalable/actions/ratings/gambling-none-symbolic.svg icons/scalable/actions/ratings/human-remains-symbolic.svg icons/scalable/actions/ratings/messaging-symbolic.svg icons/scalable/actions/ratings/messaging-none-symbolic.svg icons/scalable/actions/ratings/money-symbolic.svg icons/scalable/actions/ratings/money-none-symbolic.svg icons/scalable/actions/ratings/nudity-symbolic.svg icons/scalable/actions/ratings/nudity-none-symbolic.svg icons/scalable/actions/ratings/smoking-symbolic.svg icons/scalable/actions/ratings/smoking-none-symbolic.svg icons/scalable/actions/ratings/social-info-symbolic.svg icons/scalable/actions/ratings/strong-language-symbolic.svg icons/scalable/actions/ratings/strong-language-none-symbolic.svg icons/scalable/actions/ratings/violence-symbolic.svg icons/scalable/actions/ratings/violence-none-symbolic.svg icons/scalable/actions/on-the-go-symbolic.svg icons/scalable/actions/we-love-games-symbolic.svg icons/io.github.kolumni.Bazaar.Create.svg icons/io.github.kolumni.Bazaar.Develop.svg icons/io.github.kolumni.Bazaar.Learn.svg icons/io.github.kolumni.Bazaar.Play.svg icons/io.github.kolumni.Bazaar.Network.svg icons/io.github.kolumni.Bazaar.Work.svg icons/io.github.kolumni.Bazaar.Audiovideo.svg icons/io.github.kolumni.Bazaar.Science.svg icons/io.github.kolumni.Bazaar.System.svg icons/io.github.kolumni.Bazaar.Utilities.svg icons/io.github.kolumni.Bazaar.Mobile.svg icons/io.github.kolumni.Bazaar.Trending.svg icons/io.github.kolumni.Bazaar.Popular.svg icons/io.github.kolumni.Bazaar.New.svg icons/io.github.kolumni.Bazaar.Updated.svg icons/io.github.kolumni.Bazaar.Adwaita.svg icons/io.github.kolumni.Bazaar.Kde.svg icons/io.github.kolunmi.Bazaar.github.svg icons/io.github.kolunmi.Bazaar.gitlab.svg icons/io.github.kolunmi.Bazaar.gnome.svg icons/io.github.kolunmi.Bazaar.kde.svg icons/io.github.kolunmi.Bazaar.google.svg bz-global-progress.wdgt bazaar-orig-v0.7.14/src/bz-full-view.blp0000664000175000017500000010037215166123241016754 0ustar hasanhasanusing Gtk 4.0; using Gio 2.0; using Adw 1; template $BzFullView: Adw.Bin { child: Adw.ToolbarView { [top] Adw.HeaderBar header_bar { overflow: hidden; [title] Revealer { reveal-child: bind $is_scrolled_down(main_scroll.vadjustment as .value) as ; transition-type: slide_up; transition-duration: 500; overflow: visible; child: Label { label: bind template.entry-group as <$BzEntryGroup>.title; styles ["title"] }; } [end] MenuButton { primary: true; icon-name: "open-menu-symbolic"; has-tooltip: true; tooltip-text: _("Main Menu"); menu-model: bind template.main-menu; } [end] Button progress_button { styles [ "flat", "global-progress-button", ] can-focus: bind template.state as <$BzStateInfo>.transaction-manager as <$BzTransactionManager>.active; can-target: bind progress_button.can-focus; action-name: "window.open-library"; has-tooltip: true; tooltip-text: _("Open App Library"); child: $BzGlobalProgress { expand-size: 125; state: bind template.state as <$BzStateInfo>; active: bind template.state as <$BzStateInfo>.transaction-manager as <$BzTransactionManager>.active; pending: bind template.state as <$BzStateInfo>.transaction-manager as <$BzTransactionManager>.pending; settings: bind template.state as <$BzStateInfo>.settings; }; } } content: Adw.ViewStack stack { enable-transitions: true; Adw.ViewStackPage { name: "empty"; title: _("Empty"); child: Adw.StatusPage { icon-name: "sad-computer-symbolic"; title: _("No Results"); description: _("Try a different search query"); }; } Adw.ViewStackPage { name: "content"; title: _("Content"); child: Adw.BreakpointBin { width-request: 360; height-request: 100; Adw.Breakpoint { condition ("max-width: 700px") setters { context_bar.orientation: vertical; context_bar.spacing: 4; context_bar.homogeneous: false; header_box.spacing: 12; app_name_box.spacing: 0; formfactor_support_tile_wide.visible: false; formfactor_support_tile_narrow.visible: true; screenshots.compact: true; header_bar.show-title: false; } } child: Adw.BreakpointBin breakpoint_bin { width-request: 360; height-request: 100; Adw.Breakpoint breakpoint { condition ("max-width: 525px") setters { top_box.margin-start: 10; top_box.margin-end: 10; bottom_box.margin-start: 10; bottom_box.margin-end: 10; bottom_box.margin-top: 5; wide_install_controls.visible: false; narrow_install_controls.visible: true; app_icon.valign: start; app_icon.pixel-size: 96; } } child: Overlay { [overlay] Box shadow_overlay { valign: start; height-request: 3; can-target: false; } child: ScrolledWindow main_scroll { child: Box main_box { orientation: vertical; vexpand: false; margin-bottom: 15; spacing: 20; Adw.Banner { title: _("Installing .flatpak bundles is not yet supported"); revealed: bind template.ui-entry as <$BzResult>.object as <$BzFlatpakEntry>.is-bundle as ; } Adw.Clamp { maximum-size: 910; tightening-threshold: 576; margin-top: 15; child: Box top_box { orientation: vertical; margin-start: 25; margin-end: 25; spacing: 20; Box header_box { orientation: horizontal; spacing: 20; Image app_icon { valign: center; halign: center; pixel-size: 128; paintable: bind template.entry-group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable; visible: bind $invert_boolean($is_null(template.entry-group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable) as ) as ; styles [ "icon-dropshadow", ] } Image fallback_icon { valign: center; halign: center; pixel-size: 128; icon-name: "application-x-executable"; visible: bind $is_null(template.entry-group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable) as ; styles [ "icon-dropshadow", ] } Box not_icon { orientation: horizontal; baseline-position: center; halign: fill; hexpand: true; spacing: 15; Box app_name_box { orientation: vertical; valign: center; hexpand: true; spacing: 3; Label { styles [ "title-1", "app-title", ] xalign: 0.0; wrap: true; lines: 2; ellipsize: end; wrap-mode: word_char; natural-wrap-mode: word; label: bind template.ui-entry as <$BzResult>.object as <$BzEntry>.title; } Box { styles [ "bz-debug", ] halign: start; orientation: horizontal; spacing: 6; visible: bind template.state as <$BzStateInfo>.debug-mode; Button { icon-name: "edit-copy-symbolic"; clicked => $copy_id_cb(template); } Label { styles [ "bz-monospace", ] selectable: true; label: bind template.entry-group as <$BzEntryGroup>.id; } Button { label: "Inspect UI Entry"; clicked => $debug_id_inspect_cb(template); } } $BzDeveloperBadge { entry: bind template.ui-entry as <$BzResult>.object as <$BzEntry>; } Box { layout-manager: Adw.WrapLayout { child-spacing: 4; line-spacing: 0; }; Button { visible: bind $invert_boolean($is_null(template.ui-entry as <$BzResult>.object as <$BzEntry>.donation-url) as ) as ; styles [ "small-pill", "suggested-action", "support", ] margin-top: 8; valign: start; halign: start; has-tooltip: true; tooltip-text: bind template.ui-entry as <$BzResult>.object as <$BzEntry>.donation-url; clicked => $support_cb(template); child: Adw.ButtonContent { use-underline: true; label: _("_Support"); icon-name: "heart-filled-symbolic"; }; } $BzFavoriteButton { state: bind template.state as <$BzStateInfo>; entry: bind template.ui-entry as <$BzResult>.object as <$BzEntry>; } } } $BzInstallControls wide_install_controls { wide: true; entry-group: bind template.entry-group as <$BzEntryGroup>; state: bind template.state as <$BzStateInfo>; update => $update_cb(template); } } } Box context_bar { hexpand: false; homogeneous: true; spacing: 0; orientation: horizontal; halign: fill; styles [ "app-context-bar", ] Box { homogeneous: true; $BzContextTile download_size_tile { label: bind $get_size_label( $is_zero(template.entry-group as <$BzEntryGroup>.removable) as , template.entry-group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzFlatpakEntry>.runtime as <$BzResult>.object as <$BzEntry>.installed, template.entry-group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzFlatpakEntry>.runtime as <$BzResult>.object as <$BzEntry>.size, ) as ; has-tooltip: true; tooltip-text: bind $format_size_tooltip(template.ui-entry as <$BzResult>.object as <$BzEntry>.size) as ; lozenge-style: "grey"; sensitive: bind $invert_boolean($is_zero($get_size_type(template.ui-entry as <$BzResult>.object as <$BzEntry>, $is_zero(template.entry-group as <$BzEntryGroup>.removable) as ) as ) as ) as ; clicked => $size_cb(template); lozenge-child: Label { justify: center; label: bind $format_size($get_size_type(template.ui-entry as <$BzResult>.object as <$BzEntry>, $is_zero(template.entry-group as <$BzEntryGroup>.removable) as ) as ) as ; lines: 3; ellipsize: end; halign: center; wrap: true; xalign: 0.5; use-markup: true; }; } $BzContextTile license_tile { label: bind $get_license_label(template.ui-entry as <$BzResult>.object as <$BzEntry>) as ; lozenge-style: bind $bool_to_string(template.ui-entry as <$BzResult>.object as <$BzEntry>.is-floss, "grey", "warning") as ; clicked => $license_cb(template); has-tooltip: true; tooltip-text: bind $format_license_tooltip(template.ui-entry as <$BzResult>.object as <$BzEntry>) as ; lozenge-child: Box { spacing: 6; Image { icon-name: bind $get_license_icon(template.ui-entry as <$BzResult>.object as <$BzEntry>.is-floss, 0) as ; } Image { icon-name: bind $get_license_icon(template.ui-entry as <$BzResult>.object as <$BzEntry>.is-floss, 1) as ; } }; } $BzContextTile { clicked => $safety_cb(template); label: bind $get_safety_rating_label(template.ui-entry as <$BzResult>.object as <$BzEntry>) as ; lozenge-style: bind $get_safety_rating_style(template.ui-entry as <$BzResult>.object as <$BzEntry>) as ; lozenge-child: Box { spacing: 4; Image { icon-name: bind $get_safety_rating_icon(template.ui-entry as <$BzResult>.object as <$BzEntry>,0) as ; visible: bind $invert_boolean($is_empty_string($get_safety_rating_icon(template.ui-entry as <$BzResult>.object as <$BzEntry>,0) as ) as ) as ; } Image { icon-name: bind $get_safety_rating_icon(template.ui-entry as <$BzResult>.object as <$BzEntry>,1) as ; visible: bind $invert_boolean($is_empty_string($get_safety_rating_icon(template.ui-entry as <$BzResult>.object as <$BzEntry>,1) as ) as ) as ; } Image { icon-name: bind $get_safety_rating_icon(template.ui-entry as <$BzResult>.object as <$BzEntry>,2) as ; visible: bind $invert_boolean($is_empty_string($get_safety_rating_icon(template.ui-entry as <$BzResult>.object as <$BzEntry>,2) as ) as ) as ; } }; } } Box { homogeneous: true; $BzContextTile formfactor_support_tile_wide { label: bind $get_formfactor_label(template.ui-entry as <$BzResult>.object as <$BzEntry>.is-mobile-friendly) as ; has-tooltip: true; tooltip-text: bind $get_formfactor_tooltip(template.ui-entry as <$BzResult>.object as <$BzEntry>.is-mobile-friendly) as ; clicked => $formfactor_cb(template); lozenge-style: "grey"; lozenge-child: Box { Image { visible: bind template.ui-entry as <$BzResult>.object as <$BzEntry>.is-mobile-friendly as ; icon-name: "device-support-adaptive-symbolic"; pixel-size: 56; styles [ "wide-image", ] } Image { visible: bind $invert_boolean(template.ui-entry as <$BzResult>.object as <$BzEntry>.is-mobile-friendly) as ; icon-name: "device-support-desktop-symbolic"; } }; } $BzContextTile formfactor_support_tile_narrow { visible: false; label: bind $get_formfactor_label(template.ui-entry as <$BzResult>.object as <$BzEntry>.is-mobile-friendly) as ; has-tooltip: true; tooltip-text: bind $get_formfactor_tooltip(template.ui-entry as <$BzResult>.object as <$BzEntry>.is-mobile-friendly) as ; lozenge-style: bind $bool_to_string(template.ui-entry as <$BzResult>.object as <$BzEntry>.is-mobile-friendly, "grey", "error") as ; clicked => $formfactor_cb(template); lozenge-child: Box { Image { visible: bind template.ui-entry as <$BzResult>.object as <$BzEntry>.is-mobile-friendly as ; icon-name: "smartphone2-symbolic"; } Image { visible: bind $invert_boolean(template.ui-entry as <$BzResult>.object as <$BzEntry>.is-mobile-friendly) as ; icon-name: "device-support-desktop-symbolic"; } }; } $BzContextTile { clicked => $age_rating_cb(template); has-tooltip: true; tooltip-text: bind $get_age_rating_tooltip(template.ui-entry as <$BzResult>.object as <$BzEntry>.content-rating) as ; label: bind $get_age_rating_label(template.ui-entry as <$BzResult>.object as <$BzEntry>.content-rating) as ; lozenge-style: bind $get_age_rating_style(template.ui-entry as <$BzResult>.object as <$BzEntry>.content-rating) as ; lozenge-child: Label { label: bind $format_age_rating(template.ui-entry as <$BzResult>.object as <$BzEntry>.content-rating) as ; hexpand: true; }; } $BzContextTile { can-target: bind $invert_boolean($is_null(template.ui-entry) as ) as ; sensitive: bind $invert_boolean($is_null(template.ui-entry as <$BzResult>.object as <$BzEntry>.recent-downloads) as ) as ; clicked => $dl_stats_cb(template); label: _("Downloads/Month"); has-tooltip: bind $invert_boolean($is_null(template.ui-entry as <$BzResult>.object as <$BzEntry>.recent-downloads) as ) as ; tooltip-text: bind $format_recent_downloads_tooltip(template.ui-entry as <$BzResult>.object as <$BzEntry>.recent-downloads) as ; lozenge-style: "grey"; lozenge-child: Label { justify: center; label: bind $format_recent_downloads(template.ui-entry as <$BzResult>.object as <$BzEntry>.recent-downloads) as ; halign: center; use-markup: true; }; } } } $BzInstallControls narrow_install_controls { wide: false; visible: false; entry-group: bind template.entry-group as <$BzEntryGroup>; state: bind template.state as <$BzStateInfo>; update => $update_cb(template); } Box { visible: bind $invert_boolean($is_null(template.entry-group as <$BzEntryGroup>.eol) as ) as ; orientation: vertical; spacing: 8; styles [ "card", "colored", "warning", ] Label { label: _("Stopped Receiving Core Updates"); margin-top: 8; margin-start: 8; margin-end: 8; wrap: true; wrap-mode: word_char; justify: center; styles [ "title-4", ] } Label { label: _("This app uses a runtime that no longer receives updates or security fixes. It may become unsafe to use."); margin-bottom: 8; margin-start: 8; margin-end: 8; wrap: true; wrap-mode: word_char; justify: center; } } }; } Box screenshot_box { Adw.Spinner { vexpand: true; visible: bind $invert_boolean(template.ui-entry as <$BzResult>.resolved as ) as ; } $BzScreenshotsCarousel screenshots { vexpand: true; hexpand: true; visible: bind $logical_and( template.ui-entry as <$BzResult>.resolved as , $invert_boolean($is_empty(template.ui-entry as <$BzResult>.object as <$BzEntry>.screenshot-paintables) as ) as ) as ; clicked => $screenshot_clicked_cb() swapped; light-accent-color: bind template.ui-entry as <$BzResult>.object as <$BzEntry>.light-accent-color; dark-accent-color: bind template.ui-entry as <$BzResult>.object as <$BzEntry>.dark-accent-color; model: bind template.ui-entry as <$BzResult>.object as <$BzEntry>.screenshot-paintables; } } Adw.Clamp { maximum-size: 910; tightening-threshold: 576; child: Box { orientation: vertical; Box bottom_box { orientation: vertical; margin-start: 25; margin-end: 25; margin-bottom: 20; margin-top: 10; spacing: 15; Revealer { transition-type: slide_down; reveal-child: bind $logical_and( $logical_and($invert_boolean($is_zero(template.entry-group as <$BzEntryGroup>.user-data-size) as ) as ,$is_zero(template.entry-group as <$BzEntryGroup>.removable) as ) as , $invert_boolean($is_zero(template.entry-group as <$BzEntryGroup>.installable-and-available) as ) as ) as ; visible: bind $invert_boolean($logical_and($is_zero(template.entry-group as <$BzEntryGroup>.removable) as , $is_zero(template.entry-group as <$BzEntryGroup>.installable) as ) as ) as ; child: Box { height-request: 50; margin-bottom: 10; spacing: 12; styles [ "card", "colored", "accent", ] Label { halign: start; valign: center; hexpand: true; margin-start: 12; margin-top: 8; margin-bottom: 8; label: bind $format_leftover_label(template.ui-entry as <$BzResult>.object as <$BzEntry>.title, template.entry-group as <$BzEntryGroup>.user-data-size) as ; use-markup: true; wrap: true; wrap-mode: word_char; justify: left; } Button { valign: center; margin-end: 8; clicked => $delete_user_data_cb(template); child: Adw.ButtonContent { icon-name: "user-trash-symbolic"; label: _("Trash Data"); }; } }; } Box { spacing: 10; orientation: vertical; Label { styles [ "title-2", ] valign: start; xalign: 0; wrap: true; wrap-mode: word_char; label: bind template.ui-entry as <$BzResult>.object as <$BzEntry>.description; } $BzFadingClamp fading_clamp { max-height: bind $get_description_max_height(description_toggle.active) as ; min-max-height: 170; child: $BzAppstreamDescriptionRender { appstream-description: bind template.ui-entry as <$BzResult>.object as <$BzEntry>.long-description; }; } } ToggleButton description_toggle { styles [ "circular", ] visible: bind fading_clamp.will-change; halign: center; child: Label { label: bind $get_description_toggle_text(description_toggle.active) as ; margin-start: 16; margin-end: 16; }; } Adw.PreferencesGroup { visible: bind $logical_and($invert_boolean($is_null(template.entry-group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.addons) as ) as , $invert_boolean($is_zero(template.entry-group as <$BzEntryGroup>.removable) as ) as ) as ; Adw.ActionRow { [prefix] Image { icon-name: "puzzle-piece-symbolic"; } [suffix] Image { icon-name: "go-next-symbolic"; styles [ "dimmed", ] } title: _("Manage Add-Ons"); activatable: true; activated => $install_addons_cb(template); } } $BzReleasesList releases_list { version-history: bind template.ui-entry as <$BzResult>.object as <$BzEntry>.version-history; installed-versions: bind template.entry-group as <$BzEntryGroup>.installed-versions; } $BzShareList { urls: bind template.ui-entry as <$BzResult>.object as <$BzEntry>.share-urls; } Box { orientation: vertical; visible: bind $invert_boolean($is_zero(other_apps_model.n-items) as ) as ; Label { styles [ "heading", "h4", ] label: bind $format_other_apps_label(template.entry-group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.developer) as ; xalign: 0; wrap: true; wrap-mode: word_char; margin-bottom: 6; margin-start: 3; } $BzDynamicListView { hexpand: true; scroll: false; noscroll-kind: flow-box; child-type: "BzAppTile"; child-prop: "group"; max-children-per-line: bind $get_dev_apps_max_children_per_line(other_apps_model.model) as ; bind-widget => $bind_app_tile_cb(template); unbind-widget => $unbind_app_tile_cb(template); model: SliceListModel other_apps_model { offset: 0; size: 6; model: bind $get_developer_apps_entries(template.entry-group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.developer-apps, template.entry-group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>) as ; }; } Button { visible: bind $is_longer(template.entry-group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.developer-apps, 6) as ; clicked => $more_apps_button_clicked_cb(template); halign: center; margin-top: 11; margin-bottom: 8; child: Label { label: bind $format_more_other_apps_label(template.entry-group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.developer) as ; justify: center; wrap: true; wrap-mode: word_char; }; styles [ "pill", ] } } $BzTagList { margin-top: 8; flathub-state: bind template.state as <$BzStateInfo>.flathub; prefix: Label { label: _("Tags:"); styles [ "dimmed", ] }; model: SliceListModel { size: 5; model: bind template.entry-group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.keywords; }; } } }; } }; }; }; }; }; } }; }; } bazaar-orig-v0.7.14/src/bz-comet.txt0000664000175000017500000000070015166123241016205 0ustar hasanhasanprefix=bz name=comet parent-prefix=g parent-name=object author=AUTOGEN include= property=name char G_TYPE_STRING string property=from GtkWidget GTK_TYPE_WIDGET object property=to GtkWidget GTK_TYPE_WIDGET object property=paintable GdkPaintable GDK_TYPE_PAINTABLE object property=path GskPath GSK_TYPE_PATH boxed gsk_path_unref gsk_path_ref property=path_length double G_TYPE_DOUBLE double property=progress double G_TYPE_DOUBLE double bazaar-orig-v0.7.14/src/bz-category-tile.blp0000664000175000017500000000143315166123241017610 0ustar hasanhasanusing Gtk 4.0; template $BzCategoryTile: Button { styles [ "card", "category-tile", ] child: Box { margin-start: 16; margin-end: 16; margin-top: 24; margin-bottom: 24; orientation: vertical; spacing: 12; valign: center; halign: center; Image { pixel-size: 48; icon-name: bind template.category as <$BzFlathubCategory>.icon-name; visible: bind $invert_boolean($is_null(template.category as <$BzFlathubCategory>.icon-name) as ) as ; styles [ "icon-dropshadow", ] } Label { css-name: "category-tile-label"; halign: center; xalign: 0.5; label: bind template.category as <$BzFlathubCategory>.short-name; wrap: true; wrap-mode: word_char; } }; } bazaar-orig-v0.7.14/src/bz-releases-list.h0000664000175000017500000000252515166123241017271 0ustar hasanhasan/* bz-releases-list.h * * Copyright 2025 Alexander Vanhee, Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_RELEASES_LIST (bz_releases_list_get_type ()) G_DECLARE_FINAL_TYPE (BzReleasesList, bz_releases_list, BZ, RELEASES_LIST, AdwBin) GtkWidget * bz_releases_list_new (void); GtkWidget * bz_releases_dialog_new (GListModel *version_history, GListModel *installed_versions); void bz_releases_list_set_version_history (BzReleasesList *self, GListModel *version_history); GListModel * bz_releases_list_get_version_history (BzReleasesList *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-backend-transaction-op-progress-payload.txt0000664000175000017500000000103515166123241024717 0ustar hasanhasanprefix=bz name=backend_transaction_op_progress_payload parent-prefix=g parent-name=object author=AUTOGEN include="bz-backend-transaction-op-payload.h" property=op BzBackendTransactionOpPayload BZ_TYPE_BACKEND_TRANSACTION_OP_PAYLOAD object property=status char G_TYPE_STRING string property=is_estimating gboolean G_TYPE_BOOLEAN boolean property=progress double G_TYPE_DOUBLE double property=total_progress double G_TYPE_DOUBLE double property=bytes_transferred guint64 G_TYPE_UINT64 uint64 property=start_time guint64 G_TYPE_UINT64 uint64 bazaar-orig-v0.7.14/src/bz-safety-dialog.blp0000664000175000017500000000622515166123241017574 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzSafetyDialog: Adw.Dialog { content-height: 576; content-width: 640; title: _("Safety"); child: Adw.ToolbarView { [top] Adw.HeaderBar { show-title: false; } content: ScrolledWindow { hscrollbar-policy: never; Adw.Clamp { maximum-size: 640; tightening-threshold: 400; Box { orientation: vertical; spacing: 24; margin-start: 24; margin-end: 24; margin-top: 24; margin-bottom: 24; $BzLozenge lozenge { title: _("Safe"); icon-names: [ "app-safety-ok-symbolic", ]; importance: unimportant; } ListBox permissions_list { selection-mode: none; styles [ "boxed-list", ] } Adw.PreferencesGroup { margin-top: 10; title: _("Details"); Adw.ActionRow { title: _("License"); subtitle: bind template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.project-license; subtitle-selectable: true; styles [ "property", ] } Adw.ActionRow { title: _("App ID"); subtitle: bind template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.id; subtitle-selectable: true; styles [ "property", ] } Adw.ActionRow { title: _("SDK"); subtitle: bind template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzFlatpakEntry>.runtime as <$BzResult>.object as <$BzEntry>.title; subtitle-selectable: true; has-tooltip: true; tooltip-text: bind template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzFlatpakEntry>.application-runtime; visible: bind $invert_boolean($is_null(template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzFlatpakEntry>.runtime as <$BzResult>.object) as ) as ; styles [ "property", ] [suffix] MenuButton { visible: bind $invert_boolean($is_null(template.group as <$BzEntryGroup>.eol) as ) as ; styles [ "error", "flat", ] valign: center; icon-name: "dialog-warning-symbolic"; popover: Popover { child: Label { margin-top: 8; margin-bottom: 8; margin-start: 8; margin-end: 8; max-width-chars: 35; wrap: true; label: _("This app uses an outdated version of the software platform (SDK) and might contain bugs or security vulnerabilities which will not be fixed."); }; }; } } } } } }; }; } bazaar-orig-v0.7.14/src/bz-releases-dialog.blp0000664000175000017500000000130315166123241020074 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzReleasesDialog: Adw.Dialog { title: _("Version History"); content-width: 550; content-height: 600; child: Adw.ToolbarView { [top] Adw.HeaderBar { show-title: true; } content: ScrolledWindow { propagate-natural-height: true; vexpand: true; hscrollbar-policy: never; child: Adw.Clamp { maximum-size: 500; tightening-threshold: 600; margin-top: 24; margin-bottom: 24; margin-start: 12; margin-end: 12; child: ListBox releases_box { styles ["boxed-list"] valign: start; selection-mode: none; }; }; }; }; }bazaar-orig-v0.7.14/src/bz-gnome-shell-search-provider.c0000664000175000017500000003547515166123241022027 0ustar hasanhasan/* bz-gnome-shell-search-provider.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-gnome-shell-search-provider.h" #include "bz-entry-group.h" #include "bz-finished-search-query.h" #include "bz-search-result.h" #include "bz-util.h" #include "gs-shell-search-provider-generated.h" struct _BzGnomeShellSearchProvider { GObject parent_instance; BzSearchEngine *engine; GDBusConnection *connection; BzShellSearchProvider2 *skeleton; DexFuture *task; GHashTable *last_results; }; G_DEFINE_FINAL_TYPE (BzGnomeShellSearchProvider, bz_gnome_shell_search_provider, G_TYPE_OBJECT); enum { PROP_0, PROP_ENGINE, PROP_CONNECTION, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; BZ_DEFINE_DATA ( request, Request, { BzGnomeShellSearchProvider *self; GDBusMethodInvocation *invocation; GApplication *application; }, BZ_RELEASE_DATA (invocation, g_object_unref); BZ_RELEASE_DATA (application, g_application_release);) static DexFuture * request_finally (DexFuture *future, RequestData *data); static void start_request (BzGnomeShellSearchProvider *self, GDBusMethodInvocation *invocation, const char *const *terms); static void bz_gnome_shell_search_provider_dispose (GObject *object) { BzGnomeShellSearchProvider *self = BZ_GNOME_SHELL_SEARCH_PROVIDER (object); dex_clear (&self->task); g_clear_object (&self->engine); g_clear_object (&self->connection); g_clear_object (&self->skeleton); g_clear_pointer (&self->last_results, g_hash_table_unref); G_OBJECT_CLASS (bz_gnome_shell_search_provider_parent_class)->dispose (object); } static void bz_gnome_shell_search_provider_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzGnomeShellSearchProvider *self = BZ_GNOME_SHELL_SEARCH_PROVIDER (object); switch (prop_id) { case PROP_ENGINE: g_value_set_object (value, bz_gnome_shell_search_provider_get_engine (self)); break; case PROP_CONNECTION: g_value_set_object (value, bz_gnome_shell_search_provider_get_connection (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_gnome_shell_search_provider_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzGnomeShellSearchProvider *self = BZ_GNOME_SHELL_SEARCH_PROVIDER (object); switch (prop_id) { case PROP_ENGINE: bz_gnome_shell_search_provider_set_engine (self, g_value_get_object (value)); break; case PROP_CONNECTION: bz_gnome_shell_search_provider_set_connection (self, g_value_get_object (value), NULL); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_gnome_shell_search_provider_class_init (BzGnomeShellSearchProviderClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bz_gnome_shell_search_provider_set_property; object_class->get_property = bz_gnome_shell_search_provider_get_property; object_class->dispose = bz_gnome_shell_search_provider_dispose; props[PROP_ENGINE] = g_param_spec_object ( "engine", NULL, NULL, BZ_TYPE_SEARCH_ENGINE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_CONNECTION] = g_param_spec_object ( "connection", NULL, NULL, G_TYPE_DBUS_CONNECTION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); } static gboolean get_initial_result_set (BzShellSearchProvider2 *skeleton, GDBusMethodInvocation *invocation, gchar **terms, BzGnomeShellSearchProvider *self) { start_request (self, invocation, (const char *const *) terms); return TRUE; } static gboolean get_subsearch_result_set (BzShellSearchProvider2 *skeleton, GDBusMethodInvocation *invocation, gchar **previous_results, gchar **terms, BzGnomeShellSearchProvider *self) { start_request (self, invocation, (const char *const *) terms); return TRUE; } static gboolean get_result_metas (BzShellSearchProvider2 *skeleton, GDBusMethodInvocation *invocation, gchar **results, BzGnomeShellSearchProvider *self) { g_autoptr (GVariantBuilder) builder = NULL; builder = g_variant_builder_new (G_VARIANT_TYPE ("aa{sv}")); for (char **result = results; *result != NULL; result++) { BzEntryGroup *group = NULL; g_autoptr (GVariantBuilder) meta_builder = NULL; const char *title = NULL; const char *description = NULL; GIcon *icon = NULL; group = g_hash_table_lookup (self->last_results, *result); if (group == NULL) { g_warning ("failed to find '%s' in gnome-shell search result cache", *result); continue; } meta_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add (meta_builder, "{sv}", "id", g_variant_new_string (*result)); title = bz_entry_group_get_title (group); g_variant_builder_add (meta_builder, "{sv}", "name", g_variant_new_string (title)); description = bz_entry_group_get_description (group); if (description != NULL) g_variant_builder_add (meta_builder, "{sv}", "description", g_variant_new_string (description)); icon = bz_entry_group_get_mini_icon (group); if (icon != NULL) { g_autofree gchar *icon_str = g_icon_to_string (icon); if (icon_str != NULL) g_variant_builder_add (meta_builder, "{sv}", "gicon", g_variant_new_string (icon_str)); else { g_autoptr (GVariant) icon_serialized = NULL; icon_serialized = g_icon_serialize (icon); if (icon_serialized != NULL) g_variant_builder_add (meta_builder, "{sv}", "icon", icon_serialized); } } g_variant_builder_add_value (builder, g_variant_builder_end (meta_builder)); } g_dbus_method_invocation_return_value (invocation, g_variant_new ("(aa{sv})", builder)); return TRUE; } static gboolean activate_result (BzShellSearchProvider2 *skeleton, GDBusMethodInvocation *invocation, gchar *result, gchar **terms, guint32 timestamp, BzGnomeShellSearchProvider *self) { g_action_group_activate_action ( G_ACTION_GROUP (g_application_get_default ()), "show-app-id", g_variant_new ("s", result)); bz_shell_search_provider2_complete_activate_result (skeleton, invocation); return TRUE; } static gboolean launch_search (BzShellSearchProvider2 *skeleton, GDBusMethodInvocation *invocation, gchar **terms, guint32 timestamp, BzGnomeShellSearchProvider *self) { g_autofree gchar *string = NULL; string = g_strjoinv (" ", terms); g_action_group_activate_action ( G_ACTION_GROUP (g_application_get_default ()), "show-app-id", g_variant_new ("s", string)); bz_shell_search_provider2_complete_launch_search (skeleton, invocation); return TRUE; } static void bz_gnome_shell_search_provider_init (BzGnomeShellSearchProvider *self) { self->skeleton = bz_shell_search_provider2_skeleton_new (); self->last_results = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); g_signal_connect ( self->skeleton, "handle-get-initial-result-set", G_CALLBACK (get_initial_result_set), self); g_signal_connect ( self->skeleton, "handle-get-subsearch-result-set", G_CALLBACK (get_subsearch_result_set), self); g_signal_connect ( self->skeleton, "handle-get-result-metas", G_CALLBACK (get_result_metas), self); g_signal_connect ( self->skeleton, "handle-activate-result", G_CALLBACK (activate_result), self); g_signal_connect ( self->skeleton, "handle-launch-search", G_CALLBACK (launch_search), self); } BzGnomeShellSearchProvider * bz_gnome_shell_search_provider_new (void) { return g_object_new (BZ_TYPE_GNOME_SHELL_SEARCH_PROVIDER, NULL); } BzSearchEngine * bz_gnome_shell_search_provider_get_engine (BzGnomeShellSearchProvider *self) { g_return_val_if_fail (BZ_IS_GNOME_SHELL_SEARCH_PROVIDER (self), NULL); return self->engine; } void bz_gnome_shell_search_provider_set_engine (BzGnomeShellSearchProvider *self, BzSearchEngine *engine) { g_return_if_fail (BZ_IS_GNOME_SHELL_SEARCH_PROVIDER (self)); g_return_if_fail (engine == NULL || BZ_IS_SEARCH_ENGINE (engine)); g_clear_pointer (&self->engine, g_object_unref); if (engine != NULL) self->engine = g_object_ref (engine); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ENGINE]); } GDBusConnection * bz_gnome_shell_search_provider_get_connection (BzGnomeShellSearchProvider *self) { g_return_val_if_fail (BZ_IS_GNOME_SHELL_SEARCH_PROVIDER (self), NULL); return self->connection; } gboolean bz_gnome_shell_search_provider_set_connection (BzGnomeShellSearchProvider *self, GDBusConnection *connection, GError **error) { gboolean success = TRUE; g_return_val_if_fail (BZ_IS_GNOME_SHELL_SEARCH_PROVIDER (self), FALSE); g_return_val_if_fail (connection == NULL || G_IS_DBUS_CONNECTION (connection), FALSE); if (self->connection != NULL) g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self->skeleton)); g_clear_pointer (&self->connection, g_object_unref); if (connection != NULL) { g_autoptr (GError) local_error = NULL; self->connection = g_object_ref (connection); success = g_dbus_interface_skeleton_export ( G_DBUS_INTERFACE_SKELETON (self->skeleton), connection, "/io/github/kolunmi/Bazaar/SearchProvider", &local_error); if (!success) { if (error != NULL) g_propagate_error (error, g_steal_pointer (&local_error)); else g_warning ("Could not register gnome shell search provider: %s", local_error->message); } } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CONNECTION]); return success; } static DexFuture * request_finally (DexFuture *future, RequestData *data) { BzGnomeShellSearchProvider *self = data->self; GDBusMethodInvocation *invocation = data->invocation; g_autoptr (GError) local_error = NULL; const GValue *value = NULL; BzFinishedSearchQuery *finished = NULL; GPtrArray *results = NULL; g_autoptr (GVariantBuilder) builder = NULL; value = dex_future_get_value (future, &local_error); if (value != NULL) { finished = g_value_get_object (value); results = bz_finished_search_query_get_results (finished); builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); for (guint i = 0; i < results->len; i++) { BzSearchResult *result = NULL; BzEntryGroup *group = NULL; const char *id = NULL; result = g_ptr_array_index (results, i); group = bz_search_result_get_group (result); if (bz_entry_group_get_removable (group) > 0) /* Skip already installed groups */ continue; id = bz_entry_group_get_id (group); g_variant_builder_add (builder, "s", id); g_hash_table_replace ( self->last_results, g_strdup (id), g_object_ref (group)); } g_dbus_method_invocation_return_value ( invocation, g_variant_new ("(as)", builder)); } else { g_warning ("search engine reported an error to the search provider, " "returning an empty response to invocation: %s", local_error->message); g_dbus_method_invocation_return_value (invocation, g_variant_new ("(as)", NULL)); } return NULL; } static void start_request (BzGnomeShellSearchProvider *self, GDBusMethodInvocation *invocation, const char *const *terms) { g_autoptr (RequestData) data = NULL; g_autoptr (DexFuture) future = NULL; dex_clear (&self->task); g_hash_table_remove_all (self->last_results); if (g_strv_length ((gchar **) terms) == 1 && g_utf8_strlen (terms[0], -1) == 1) { g_dbus_method_invocation_return_value ( invocation, g_variant_new ("(as)", NULL)); return; } if (self->engine == NULL) { g_warning ("search provider does not have an engine, " "returning empty response to invocation"); g_dbus_method_invocation_return_value ( invocation, g_variant_new ("(as)", NULL)); return; } data = request_data_new (); data->self = self; data->invocation = g_object_ref (invocation); data->application = g_application_get_default (); g_application_hold (data->application); future = bz_search_engine_query (self->engine, terms); future = dex_future_finally ( future, (DexFutureCallback) request_finally, request_data_ref (data), request_data_unref); self->task = g_steal_pointer (&future); } /* End of bz-gnome-shell-search-provider.c */ bazaar-orig-v0.7.14/src/bz-app-size-dialog.blp0000664000175000017500000001067115166123241020031 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzAppSizeDialog: Adw.Bin { child: Adw.ToolbarView { [top] Adw.HeaderBar { show-title: false; } content: Adw.Clamp { maximum-size: 600; child: Box { orientation: vertical; margin-top: 6; margin-bottom: 18; margin-start: 18; margin-end: 18; Box { orientation: vertical; margin-bottom: 24; $BzLozenge { title: _("Download Size"); label: bind $format_size(template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.size as ) as ; importance: neutral; } } Adw.PreferencesGroup { margin-bottom: 15; Adw.ActionRow { [prefix] Label { label: bind $format_size(template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.size as ) as ; use-markup: true; valign: center; width-request: 90; margin-top: 8; margin-bottom: 8; styles [ "circular-lozenge", "title-4", "grey", ] } title: _("Download Size"); subtitle: _("Amount to download from the internet"); } Adw.ActionRow { [prefix] Label { label: bind $format_size(template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.installed-size as ) as ; use-markup: true; valign: center; width-request: 90; margin-top: 8; margin-bottom: 8; styles [ "circular-lozenge", "title-4", "grey", ] } title: _("Installed Size"); subtitle: _("Size on Disk"); } Adw.ActionRow { visible: bind $invert_boolean($is_null(template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzFlatpakEntry>.runtime as <$BzResult>) as ) as ; [prefix] Label { label: bind $format_size($choose(template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzFlatpakEntry>.runtime as <$BzResult>.object as <$BzEntry>.installed, template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzFlatpakEntry>.runtime as <$BzResult>.object as <$BzEntry>.installed-size as , template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzFlatpakEntry>.runtime as <$BzResult>.object as <$BzEntry>.size as ) as ) as ; use-markup: true; valign: center; width-request: 90; margin-top: 8; margin-bottom: 8; styles [ "circular-lozenge", "title-4", "grey", ] } title: bind $get_runtime_size_title(template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzFlatpakEntry>.runtime as <$BzResult>.object as <$BzEntry>.installed) as ; subtitle: bind template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzFlatpakEntry>.runtime as <$BzResult>.object as <$BzEntry>.title; } Adw.ActionRow { visible: bind $invert_boolean($is_zero(template.group as <$BzEntryGroup>.user-data-size) as ) as ; [prefix] Label { label: bind $format_size(template.group as <$BzEntryGroup>.user-data-size) as ; use-markup: true; valign: center; width-request: 90; margin-top: 8; margin-bottom: 8; styles [ "circular-lozenge", "title-4", "grey", ] } [suffix] Button { has-tooltip: true; tooltip-text: _("Open user data folder"); icon-name: "folder-open-symbolic"; clicked => $open_user_data_folder_cb(); valign: center; styles [ "flat", ] } title: _("User Data Size"); subtitle: _("Caches, settings, and other app data"); } } }; }; }; } bazaar-orig-v0.7.14/src/bz-flathub-category-section.c0000664000175000017500000002433515166123241021415 0ustar hasanhasan/* bz-flathub-category-section.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-apps-page.h" #include "bz-entry-group.h" #include "bz-flathub-category-section.h" #include "bz-flathub-category.h" #include "bz-flathub-page.h" struct _BzFlathubCategorySection { GtkBox parent_instance; GtkLabel *section_title; GtkWidget *section_list; GtkButton *more_button; BzFlathubCategory *category; gboolean compact; guint min_items; GtkSliceListModel *slice_model; }; G_DEFINE_FINAL_TYPE (BzFlathubCategorySection, bz_flathub_category_section, GTK_TYPE_BOX) enum { PROP_0, PROP_CATEGORY, PROP_COMPACT, PROP_MIN_ITEMS, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void tile_clicked (BzEntryGroup *group, GtkButton *button) { gtk_widget_activate_action (GTK_WIDGET (button), "window.show-group", "s", bz_entry_group_get_id (group)); } static void on_more_button_clicked (GtkButton *button, BzFlathubCategorySection *self) { GtkWidget *flathub_page = NULL; GtkWidget *nav_view = NULL; AdwNavigationPage *apps_page = NULL; if (self->category == NULL) return; flathub_page = gtk_widget_get_ancestor (GTK_WIDGET (self), BZ_TYPE_FLATHUB_PAGE); if (flathub_page == NULL) return; nav_view = gtk_widget_get_ancestor (GTK_WIDGET (self), ADW_TYPE_NAVIGATION_VIEW); if (nav_view == NULL) return; apps_page = bz_apps_page_new_from_category (self->category); if (apps_page == NULL) return; adw_navigation_view_push (ADW_NAVIGATION_VIEW (nav_view), apps_page); } static void bind_widget_cb (BzFlathubCategorySection *self, GtkWidget *tile, BzEntryGroup *group, GtkWidget *view) { g_signal_connect_swapped (tile, "clicked", G_CALLBACK (tile_clicked), group); } static void unbind_widget_cb (BzFlathubCategorySection *self, GtkWidget *tile, BzEntryGroup *group, GtkWidget *view) { g_signal_handlers_disconnect_by_func (tile, G_CALLBACK (tile_clicked), group); } static int get_spacing (gpointer object, gboolean compact) { return compact ? 9 : 11; } static void update_model (BzFlathubCategorySection *self) { GtkExpression *expression; guint max_items; if (self->category == NULL) return; max_items = self->compact ? 6 : 12; max_items = MAX (max_items, self->min_items); if (self->slice_model != NULL) { gtk_slice_list_model_set_size (self->slice_model, max_items); return; } expression = gtk_property_expression_new (BZ_TYPE_FLATHUB_CATEGORY, NULL, "applications"); self->slice_model = gtk_slice_list_model_new (NULL, 0, max_items); gtk_expression_bind (expression, self->slice_model, "model", self->category); g_object_set (self->section_list, "model", self->slice_model, NULL); } static void bz_flathub_category_section_dispose (GObject *object) { BzFlathubCategorySection *self = BZ_FLATHUB_CATEGORY_SECTION (object); g_clear_object (&self->category); g_clear_object (&self->slice_model); G_OBJECT_CLASS (bz_flathub_category_section_parent_class)->dispose (object); } static void bz_flathub_category_section_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzFlathubCategorySection *self = BZ_FLATHUB_CATEGORY_SECTION (object); switch (prop_id) { case PROP_CATEGORY: g_value_set_object (value, bz_flathub_category_section_get_category (self)); break; case PROP_COMPACT: g_value_set_boolean (value, bz_flathub_category_section_get_compact (self)); break; case PROP_MIN_ITEMS: g_value_set_uint (value, bz_flathub_category_section_get_min_items (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_flathub_category_section_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzFlathubCategorySection *self = BZ_FLATHUB_CATEGORY_SECTION (object); switch (prop_id) { case PROP_CATEGORY: bz_flathub_category_section_set_category (self, g_value_get_object (value)); break; case PROP_COMPACT: bz_flathub_category_section_set_compact (self, g_value_get_boolean (value)); break; case PROP_MIN_ITEMS: bz_flathub_category_section_set_min_items (self, g_value_get_uint (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static gboolean is_null (gpointer object, GObject *value) { return value == NULL; } static void bz_flathub_category_section_class_init (BzFlathubCategorySectionClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_flathub_category_section_dispose; object_class->get_property = bz_flathub_category_section_get_property; object_class->set_property = bz_flathub_category_section_set_property; props[PROP_CATEGORY] = g_param_spec_object ( "category", NULL, NULL, BZ_TYPE_FLATHUB_CATEGORY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_COMPACT] = g_param_spec_boolean ( "compact", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_MIN_ITEMS] = g_param_spec_uint ( "min-items", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-flathub-category-section.ui"); gtk_widget_class_bind_template_child (widget_class, BzFlathubCategorySection, section_title); gtk_widget_class_bind_template_child (widget_class, BzFlathubCategorySection, section_list); gtk_widget_class_bind_template_child (widget_class, BzFlathubCategorySection, more_button); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, is_null); gtk_widget_class_bind_template_callback (widget_class, on_more_button_clicked); gtk_widget_class_bind_template_callback (widget_class, bind_widget_cb); gtk_widget_class_bind_template_callback (widget_class, unbind_widget_cb); gtk_widget_class_bind_template_callback (widget_class, get_spacing); } static void bz_flathub_category_section_init (BzFlathubCategorySection *self) { self->compact = FALSE; self->min_items = 0; gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_flathub_category_section_new (void) { return g_object_new (BZ_TYPE_FLATHUB_CATEGORY_SECTION, NULL); } void bz_flathub_category_section_set_category (BzFlathubCategorySection *self, BzFlathubCategory *category) { const char *display_name; g_autofree char *more_label = NULL; g_return_if_fail (BZ_IS_FLATHUB_CATEGORY_SECTION (self)); g_return_if_fail (category == NULL || BZ_IS_FLATHUB_CATEGORY (category)); if (self->category == category) return; g_clear_object (&self->category); g_clear_object (&self->slice_model); if (category != NULL) { self->category = g_object_ref (category); display_name = bz_flathub_category_get_display_name (category); gtk_label_set_text (self->section_title, display_name); more_label = g_strdup (bz_flathub_category_get_more_of_name (category)); gtk_button_set_label (self->more_button, more_label); update_model (self); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CATEGORY]); } BzFlathubCategory * bz_flathub_category_section_get_category (BzFlathubCategorySection *self) { g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY_SECTION (self), NULL); return self->category; } void bz_flathub_category_section_set_compact (BzFlathubCategorySection *self, gboolean compact) { g_return_if_fail (BZ_IS_FLATHUB_CATEGORY_SECTION (self)); if (self->compact == compact) return; self->compact = compact; update_model (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_COMPACT]); } gboolean bz_flathub_category_section_get_compact (BzFlathubCategorySection *self) { g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY_SECTION (self), FALSE); return self->compact; } void bz_flathub_category_section_set_min_items (BzFlathubCategorySection *self, guint min_items) { g_return_if_fail (BZ_IS_FLATHUB_CATEGORY_SECTION (self)); if (self->min_items == min_items) return; self->min_items = min_items; update_model (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MIN_ITEMS]); } guint bz_flathub_category_section_get_min_items (BzFlathubCategorySection *self) { g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY_SECTION (self), 0); return self->min_items; } bazaar-orig-v0.7.14/src/bz-blocklist-condition-match-locale.txt0000664000175000017500000000021415166123241023377 0ustar hasanhasanprefix=bz name=blocklist_condition_match_locale parent-prefix=g parent-name=object author=AUTOGEN property=regex char G_TYPE_STRING string bazaar-orig-v0.7.14/src/bz-safety-row.txt0000664000175000017500000000044415166123241017203 0ustar hasanhasanprefix=bz name=safety_row parent-prefix=g parent-name=object author=AUTOGEN include="bz-context-row.h" property=importance BzImportance BZ_TYPE_IMPORTANCE enum property=title char G_TYPE_STRING string property=subtitle char G_TYPE_STRING string property=icon_name char G_TYPE_STRING string bazaar-orig-v0.7.14/src/bz-search-filter-popover.c0000664000175000017500000003671515166123241020740 0ustar hasanhasan/* bz-search-filter-popover.c * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include "bz-application.h" #include "bz-category-flags.h" #include "bz-flathub-category.h" #include "bz-flathub-state.h" #include "bz-search-filter-popover.h" #include "bz-state-info.h" struct _BzSearchFilterPopover { GtkPopover parent_instance; BzCategoryFlags selected_categories; gboolean only_verified; gboolean only_free; gboolean only_non_eol; gboolean has_active_filters; gboolean state_forced_verified; gboolean state_forced_free; gboolean state_forced_non_eol; AdwWrapBox *wrap_box; GtkWidget *verified_button; GtkWidget *free_button; GtkWidget *non_eol_button; }; G_DEFINE_FINAL_TYPE (BzSearchFilterPopover, bz_search_filter_popover, GTK_TYPE_POPOVER) enum { PROP_0, PROP_SELECTED_CATEGORIES, PROP_ONLY_VERIFIED, PROP_ONLY_FREE, PROP_ONLY_NON_EOL, PROP_HAS_ACTIVE_FILTERS, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void update_has_active_filters (BzSearchFilterPopover *self); static void apply_filter_button (BzSearchFilterPopover *self, guint prop, gboolean value); static void sync_from_state (BzSearchFilterPopover *self); static void on_state_setting_changed (BzSearchFilterPopover *self, GParamSpec *pspec, BzStateInfo *state); static void on_category_button_clicked (GtkButton *button, gpointer user_data); static void rebuild_category_buttons (BzSearchFilterPopover *self); static void on_show (GtkPopover *popover, gpointer user_data); static void on_filter_button_clicked (GtkButton *button, gpointer user_data); static void bz_search_filter_popover_dispose (GObject *object) { BzSearchFilterPopover *self = BZ_SEARCH_FILTER_POPOVER (object); BzStateInfo *state = NULL; state = bz_state_info_get_default (); if (state != NULL) g_signal_handlers_disconnect_by_data (state, self); gtk_widget_dispose_template (GTK_WIDGET (object), BZ_TYPE_SEARCH_FILTER_POPOVER); G_OBJECT_CLASS (bz_search_filter_popover_parent_class)->dispose (object); } static void bz_search_filter_popover_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzSearchFilterPopover *self = BZ_SEARCH_FILTER_POPOVER (object); switch (prop_id) { case PROP_SELECTED_CATEGORIES: g_value_set_flags (value, self->selected_categories); break; case PROP_ONLY_VERIFIED: g_value_set_boolean (value, self->only_verified); break; case PROP_ONLY_FREE: g_value_set_boolean (value, self->only_free); break; case PROP_ONLY_NON_EOL: g_value_set_boolean (value, self->only_non_eol); break; case PROP_HAS_ACTIVE_FILTERS: g_value_set_boolean (value, self->has_active_filters); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_search_filter_popover_class_init (BzSearchFilterPopoverClass *klass) { GObjectClass *object_class = NULL; GtkWidgetClass *widget_class = NULL; object_class = G_OBJECT_CLASS (klass); widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_search_filter_popover_dispose; object_class->get_property = bz_search_filter_popover_get_property; props[PROP_SELECTED_CATEGORIES] = g_param_spec_flags ( "selected-categories", NULL, NULL, BZ_TYPE_CATEGORY_FLAGS, BZ_CATEGORY_FLAGS_NONE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_ONLY_VERIFIED] = g_param_spec_boolean ( "only-verified", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_ONLY_FREE] = g_param_spec_boolean ( "only-free", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_ONLY_NON_EOL] = g_param_spec_boolean ( "only-non-eol", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_HAS_ACTIVE_FILTERS] = g_param_spec_boolean ( "has-active-filters", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-search-filter-popover.ui"); gtk_widget_class_bind_template_child (widget_class, BzSearchFilterPopover, wrap_box); gtk_widget_class_bind_template_child (widget_class, BzSearchFilterPopover, verified_button); gtk_widget_class_bind_template_child (widget_class, BzSearchFilterPopover, free_button); gtk_widget_class_bind_template_child (widget_class, BzSearchFilterPopover, non_eol_button); gtk_widget_class_bind_template_callback (widget_class, on_filter_button_clicked); } static void bz_search_filter_popover_init (BzSearchFilterPopover *self) { BzStateInfo *state = NULL; gtk_widget_init_template (GTK_WIDGET (self)); g_signal_connect (self, "show", G_CALLBACK (on_show), NULL); state = bz_state_info_get_default (); if (state != NULL) { g_signal_connect_swapped (state, "notify::show-only-verified", G_CALLBACK (on_state_setting_changed), self); g_signal_connect_swapped (state, "notify::show-only-foss", G_CALLBACK (on_state_setting_changed), self); g_signal_connect_swapped (state, "notify::hide-eol", G_CALLBACK (on_state_setting_changed), self); } } GtkWidget * bz_search_filter_popover_new (void) { return g_object_new (BZ_TYPE_SEARCH_FILTER_POPOVER, NULL); } BzCategoryFlags bz_search_filter_popover_get_selected_categories (BzSearchFilterPopover *self) { g_return_val_if_fail (BZ_IS_SEARCH_FILTER_POPOVER (self), BZ_CATEGORY_FLAGS_NONE); return self->selected_categories; } gboolean bz_search_filter_popover_get_only_verified (BzSearchFilterPopover *self) { g_return_val_if_fail (BZ_IS_SEARCH_FILTER_POPOVER (self), FALSE); return self->only_verified; } gboolean bz_search_filter_popover_get_only_free (BzSearchFilterPopover *self) { g_return_val_if_fail (BZ_IS_SEARCH_FILTER_POPOVER (self), FALSE); return self->only_free; } gboolean bz_search_filter_popover_get_only_non_eol (BzSearchFilterPopover *self) { g_return_val_if_fail (BZ_IS_SEARCH_FILTER_POPOVER (self), FALSE); return self->only_non_eol; } void bz_search_filter_popover_clear (BzSearchFilterPopover *self) { GtkWidget *child = NULL; g_return_if_fail (BZ_IS_SEARCH_FILTER_POPOVER (self)); if (!self->state_forced_verified) apply_filter_button (self, PROP_ONLY_VERIFIED, FALSE); if (!self->state_forced_free) apply_filter_button (self, PROP_ONLY_FREE, FALSE); if (!self->state_forced_non_eol) apply_filter_button (self, PROP_ONLY_NON_EOL, FALSE); for (child = gtk_widget_get_first_child (GTK_WIDGET (self->wrap_box)); child != NULL; child = gtk_widget_get_next_sibling (child)) gtk_widget_remove_css_class (child, "accent"); if (self->selected_categories != BZ_CATEGORY_FLAGS_NONE) { self->selected_categories = BZ_CATEGORY_FLAGS_NONE; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SELECTED_CATEGORIES]); update_has_active_filters (self); } } static void update_has_active_filters (BzSearchFilterPopover *self) { gboolean active = FALSE; active = (self->only_verified && !self->state_forced_verified) || (self->only_free && !self->state_forced_free) || (self->only_non_eol && !self->state_forced_non_eol) || self->selected_categories != BZ_CATEGORY_FLAGS_NONE; if (self->has_active_filters == active) return; self->has_active_filters = active; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_HAS_ACTIVE_FILTERS]); } static void apply_filter_button (BzSearchFilterPopover *self, guint prop, gboolean value) { struct { guint prop; gboolean *field; GtkWidget **button; } map[] = { { PROP_ONLY_VERIFIED, &self->only_verified, &self->verified_button }, { PROP_ONLY_FREE, &self->only_free, &self->free_button }, { PROP_ONLY_NON_EOL, &self->only_non_eol, &self->non_eol_button }, }; for (guint i = 0; i < G_N_ELEMENTS (map); i++) { if (map[i].prop != prop) continue; *map[i].field = value; if (value) gtk_widget_add_css_class (*map[i].button, "accent"); else gtk_widget_remove_css_class (*map[i].button, "accent"); g_object_notify_by_pspec (G_OBJECT (self), props[prop]); update_has_active_filters (self); return; } } static void sync_from_state (BzSearchFilterPopover *self) { BzStateInfo *state = NULL; gboolean state_verified = FALSE; gboolean state_free = FALSE; gboolean state_hide_eol = FALSE; state = bz_state_info_get_default (); if (state == NULL) return; g_object_get (state, "show-only-verified", &state_verified, "show-only-foss", &state_free, "hide-eol", &state_hide_eol, NULL); self->state_forced_verified = state_verified; self->state_forced_free = state_free; self->state_forced_non_eol = state_hide_eol; if (state_verified) apply_filter_button (self, PROP_ONLY_VERIFIED, TRUE); if (self->verified_button != NULL) gtk_widget_set_sensitive (self->verified_button, !state_verified); if (state_free) apply_filter_button (self, PROP_ONLY_FREE, TRUE); if (self->free_button != NULL) gtk_widget_set_sensitive (self->free_button, !state_free); if (state_hide_eol) apply_filter_button (self, PROP_ONLY_NON_EOL, TRUE); if (self->non_eol_button != NULL) gtk_widget_set_sensitive (self->non_eol_button, !state_hide_eol); } static void on_state_setting_changed (BzSearchFilterPopover *self, GParamSpec *pspec, BzStateInfo *state) { gboolean state_verified = FALSE; gboolean state_free = FALSE; gboolean state_hide_eol = FALSE; g_object_get (state, "show-only-verified", &state_verified, "show-only-foss", &state_free, "hide-eol", &state_hide_eol, NULL); if (!state_verified) apply_filter_button (self, PROP_ONLY_VERIFIED, FALSE); if (!state_free) apply_filter_button (self, PROP_ONLY_FREE, FALSE); if (!state_hide_eol) apply_filter_button (self, PROP_ONLY_NON_EOL, FALSE); sync_from_state (self); } static void on_filter_button_clicked (GtkButton *button, gpointer user_data) { BzSearchFilterPopover *self = BZ_SEARCH_FILTER_POPOVER (user_data); const char *name = NULL; name = gtk_widget_get_name (GTK_WIDGET (button)); if (g_str_equal (name, "verified")) apply_filter_button (self, PROP_ONLY_VERIFIED, !self->only_verified); else if (g_str_equal (name, "free")) apply_filter_button (self, PROP_ONLY_FREE, !self->only_free); else if (g_str_equal (name, "non-eol")) apply_filter_button (self, PROP_ONLY_NON_EOL, !self->only_non_eol); } static void on_category_button_clicked (GtkButton *button, gpointer user_data) { BzSearchFilterPopover *self = BZ_SEARCH_FILTER_POPOVER (user_data); BzCategoryFlags flag = BZ_CATEGORY_FLAGS_NONE; flag = (BzCategoryFlags) GPOINTER_TO_SIZE ( g_object_get_data (G_OBJECT (button), "category-flag")); self->selected_categories ^= flag; if (self->selected_categories & flag) gtk_widget_add_css_class (GTK_WIDGET (button), "accent"); else gtk_widget_remove_css_class (GTK_WIDGET (button), "accent"); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SELECTED_CATEGORIES]); update_has_active_filters (self); } static void rebuild_category_buttons (BzSearchFilterPopover *self) { g_autoptr (BzFlathubState) flathub = NULL; g_autoptr (GListModel) categories = NULL; BzStateInfo *state = NULL; GtkWidget *child = NULL; while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->wrap_box))) != NULL) adw_wrap_box_remove (self->wrap_box, child); sync_from_state (self); state = bz_state_info_get_default (); if (state == NULL) return; g_object_get (state, "flathub", &flathub, NULL); if (flathub == NULL) return; g_object_get (flathub, "categories", &categories, NULL); if (categories == NULL) return; for (guint i = 0; i < g_list_model_get_n_items (categories); i++) { g_autoptr (BzFlathubCategory) category = NULL; const char *name = NULL; const char *label = NULL; const char *icon = NULL; GtkWidget *button = NULL; GtkWidget *content = NULL; BzCategoryFlags flag = BZ_CATEGORY_FLAGS_NONE; category = g_list_model_get_item (categories, i); if (!bz_flathub_category_get_is_xdg (category)) continue; name = bz_flathub_category_get_name (category); label = bz_flathub_category_get_short_name (category); icon = bz_flathub_category_get_symbolic_icon_name (category); flag = bz_category_flags_from_name (name); content = g_object_new (ADW_TYPE_BUTTON_CONTENT, "label", label, "icon-name", icon ? icon : "", NULL); button = gtk_button_new (); gtk_button_set_child (GTK_BUTTON (button), content); gtk_accessible_update_property (GTK_ACCESSIBLE (button), GTK_ACCESSIBLE_PROPERTY_LABEL, label, -1); g_object_set_data (G_OBJECT (button), "category-flag", GSIZE_TO_POINTER ((gsize) flag)); if (self->selected_categories & flag) gtk_widget_add_css_class (button, "accent"); g_signal_connect (button, "clicked", G_CALLBACK (on_category_button_clicked), self); adw_wrap_box_append (self->wrap_box, button); } } static void on_show (GtkPopover *popover, gpointer user_data) { rebuild_category_buttons (BZ_SEARCH_FILTER_POPOVER (popover)); } bazaar-orig-v0.7.14/src/bz-age-rating-dialog.h0000664000175000017500000000235715166123241017773 0ustar hasanhasan/* bz-age-rating-dialog.h * * Copyright 2021 Endless OS Foundation LLC * Copyright 2025 Alexander Vanhee * * Author: Philip Withnall (GNOME Software) * Adapted for Bazaar by Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry.h" #include #include G_BEGIN_DECLS #define BZ_TYPE_AGE_RATING_DIALOG (bz_age_rating_dialog_get_type ()) G_DECLARE_FINAL_TYPE (BzAgeRatingDialog, bz_age_rating_dialog, BZ, AGE_RATING_DIALOG, AdwDialog) BzAgeRatingDialog *bz_age_rating_dialog_new (BzEntry *entry); G_END_DECLS bazaar-orig-v0.7.14/src/bz-screenshots-carousel.h0000664000175000017500000000372215166123241020670 0ustar hasanhasan/* bz-screenshots-carousel.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_SCREENSHOTS_CAROUSEL (bz_screenshots_carousel_get_type ()) G_DECLARE_FINAL_TYPE (BzScreenshotsCarousel, bz_screenshots_carousel, BZ, SCREENSHOTS_CAROUSEL, GtkWidget) GtkWidget * bz_screenshots_carousel_new (void); void bz_screenshots_carousel_set_model (BzScreenshotsCarousel *self, GListModel *model); GListModel * bz_screenshots_carousel_get_model (BzScreenshotsCarousel *self); void bz_screenshots_carousel_set_compact (BzScreenshotsCarousel *self, gboolean compact); gboolean bz_screenshots_carousel_get_compact (BzScreenshotsCarousel *self); void bz_screenshots_carousel_set_light_accent_color (BzScreenshotsCarousel *self, const char *color); const char * bz_screenshots_carousel_get_light_accent_color (BzScreenshotsCarousel *self); void bz_screenshots_carousel_set_dark_accent_color (BzScreenshotsCarousel *self, const char *color); const char * bz_screenshots_carousel_get_dark_accent_color (BzScreenshotsCarousel *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-backend-transaction-op-payload.txt0000664000175000017500000000046415166123241023062 0ustar hasanhasanprefix=bz name=backend_transaction_op_payload parent-prefix=g parent-name=object author=AUTOGEN include="bz-entry.h" property=name char G_TYPE_STRING string property=entry BzEntry BZ_TYPE_ENTRY object property=download_size guint64 G_TYPE_UINT64 uint64 property=installed_size guint64 G_TYPE_UINT64 uint64 bazaar-orig-v0.7.14/src/bz-subcategory-list.h0000664000175000017500000000300515166123241020007 0ustar hasanhasan/* bz-subcategory-list.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-flathub-category.h" #include "bz-flathub-state.h" #include G_BEGIN_DECLS #define BZ_TYPE_SUBCATEGORY_LIST (bz_subcategory_list_get_type ()) G_DECLARE_FINAL_TYPE (BzSubcategoryList, bz_subcategory_list, BZ, SUBCATEGORY_LIST, GtkBox) GtkWidget *bz_subcategory_list_new (void); BzFlathubCategory *bz_subcategory_list_get_category (BzSubcategoryList *self); void bz_subcategory_list_set_category (BzSubcategoryList *self, BzFlathubCategory *category); BzFlathubState *bz_subcategory_list_get_flathub_state (BzSubcategoryList *self); void bz_subcategory_list_set_flathub_state (BzSubcategoryList *self, BzFlathubState *flathub_state); G_END_DECLS bazaar-orig-v0.7.14/src/bz-releases-list.c0000664000175000017500000004345115166123241017267 0ustar hasanhasan/* bz-releases-list.c * * Copyright 2025 Alexander Vanhee, Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-appstream-description-render.h" #include "bz-fading-clamp.h" #include "bz-release.h" #include "bz-releases-list.h" #include "bz-template-callbacks.h" /* Dialog structure */ typedef struct { /* Template widgets */ AdwDialog parent_instance; GtkListBox *releases_box; GListModel *installed_versions; } BzReleasesDialog; typedef struct { AdwDialogClass parent_class; } BzReleasesDialogClass; static GType bz_releases_dialog_get_type (void) G_GNUC_CONST; G_DEFINE_TYPE (BzReleasesDialog, bz_releases_dialog, ADW_TYPE_DIALOG) /* Main widget structure */ struct _BzReleasesList { AdwBin parent_instance; GListModel *version_history; GListModel *installed_versions; /* Template widgets */ GtkListBox *preview_box; GtkBox *show_all_box; }; G_DEFINE_FINAL_TYPE (BzReleasesList, bz_releases_list, ADW_TYPE_BIN) enum { PROP_0, PROP_VERSION_HISTORY, PROP_INSTALLED_VERSIONS, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static gboolean is_version_installed (GListModel *installed_versions, const char *version) { guint n_items = 0; if (!installed_versions || !version) return FALSE; n_items = g_list_model_get_n_items (installed_versions); for (guint i = 0; i < n_items; i++) { g_autoptr (GObject) item = NULL; item = g_list_model_get_item (installed_versions, i); if (GTK_IS_STRING_OBJECT (item)) { const char *installed_version = NULL; installed_version = gtk_string_object_get_string (GTK_STRING_OBJECT (item)); if (installed_version != NULL && g_strcmp0 (installed_version, version) == 0) return TRUE; } } return FALSE; } // From gs-common.c static char * format_timestamp (guint64 unix_time) { g_autoptr (GDateTime) then = NULL; g_autoptr (GDateTime) now = NULL; gint days, weeks, months, years; if (unix_time == 0) return NULL; then = g_date_time_new_from_unix_utc (unix_time); now = g_date_time_new_now_local (); if (then == NULL || now == NULL) return NULL; days = (gint) (g_date_time_difference (now, then) / G_TIME_SPAN_DAY); weeks = days / 7; months = days / 30; years = weeks / 52; if (days < 1) /* Translators: something happened less than a day ago */ return g_strdup (_ ("Today")); else if (days < 2) /* Translators: something happened more than a day ago but less than 2 days ago */ return g_strdup (_ ("Yesterday")); else if (days < 15) /* Translators: something happened days ago */ return g_strdup_printf (ngettext ("%d day ago", "%d days ago", days), days); else if (weeks < 8) /* Translators: something happened weeks ago */ return g_strdup_printf (ngettext ("%d week ago", "%d weeks ago", weeks), weeks); else if (years < 1) /* Translators: something happened months ago */ return g_strdup_printf (ngettext ("%d month ago", "%d months ago", months), months); else /* Translators: something happened years ago */ return g_strdup_printf (ngettext ("%d year ago", "%d years ago", years), years); } static char * format_timestamp_tooltip (guint64 unix_time) { g_autoptr (GDateTime) then = NULL; if (unix_time == 0) return NULL; then = g_date_time_new_from_unix_utc (unix_time); if (then == NULL) return NULL; /* TRANSLATORS: This is the date string with: day number, month name, year. i.e. "22 March 2026" */ return g_date_time_format (then, _ ("%e %B %Y")); } static GtkWidget * create_release_row (const char *version, const char *description, guint64 timestamp, const char *url, gboolean use_clamp, GListModel *installed_versions) { AdwActionRow *row = NULL; GtkBox *content_box = NULL; GtkBox *header_box = NULL; GtkLabel *version_label = NULL; GtkLabel *date_label = NULL; GtkLabel *installed_label = NULL; BzAppstreamDescriptionRender *description_widget = NULL; BzFadingClamp *fading_clamp = NULL; GtkBox *more_info_box = NULL; GtkLabel *more_info_label = NULL; GtkImage *more_info_icon = NULL; g_autofree char *date_str = NULL; g_autofree char *date_tooltip = NULL; g_autofree char *version_text = NULL; g_autofree char *markup = NULL; date_str = format_timestamp (timestamp); row = ADW_ACTION_ROW (adw_action_row_new ()); gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE); content_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 3)); gtk_widget_set_margin_top (GTK_WIDGET (content_box), 15); gtk_widget_set_margin_bottom (GTK_WIDGET (content_box), 15); gtk_widget_set_margin_start (GTK_WIDGET (content_box), 15); gtk_widget_set_margin_end (GTK_WIDGET (content_box), 15); header_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8)); version_text = g_strdup_printf (_ ("Version %s"), version); version_label = GTK_LABEL (gtk_label_new (version_text)); gtk_widget_add_css_class (GTK_WIDGET (version_label), "accent"); gtk_widget_add_css_class (GTK_WIDGET (version_label), "heading"); gtk_label_set_ellipsize (version_label, PANGO_ELLIPSIZE_END); gtk_widget_set_halign (GTK_WIDGET (version_label), GTK_ALIGN_START); gtk_box_append (header_box, GTK_WIDGET (version_label)); if (is_version_installed (installed_versions, version)) { installed_label = GTK_LABEL (gtk_label_new (_ ("Installed"))); gtk_widget_add_css_class (GTK_WIDGET (installed_label), "lozenge"); gtk_widget_add_css_class (GTK_WIDGET (installed_label), "small"); gtk_widget_set_halign (GTK_WIDGET (installed_label), GTK_ALIGN_START); gtk_widget_set_hexpand (GTK_WIDGET (installed_label), TRUE); gtk_box_append (header_box, GTK_WIDGET (installed_label)); } else { gtk_widget_set_hexpand (GTK_WIDGET (version_label), TRUE); } date_label = GTK_LABEL (gtk_label_new (date_str ? date_str : "")); gtk_widget_add_css_class (GTK_WIDGET (date_label), "dim-label"); gtk_widget_set_halign (GTK_WIDGET (date_label), GTK_ALIGN_END); date_tooltip = format_timestamp_tooltip (timestamp); if (date_tooltip != NULL) gtk_widget_set_tooltip_text (GTK_WIDGET (date_label), date_tooltip); gtk_box_append (header_box, GTK_WIDGET (date_label)); gtk_box_append (content_box, GTK_WIDGET (header_box)); if (description != NULL && *description) { description_widget = bz_appstream_description_render_new (); bz_appstream_description_render_set_appstream_description (description_widget, description); if (use_clamp) { fading_clamp = BZ_FADING_CLAMP (bz_fading_clamp_new ()); bz_fading_clamp_set_max_height (fading_clamp, 270); bz_fading_clamp_set_child (fading_clamp, GTK_WIDGET (description_widget)); gtk_widget_set_margin_top (GTK_WIDGET (fading_clamp), 10); gtk_box_append (content_box, GTK_WIDGET (fading_clamp)); } else { gtk_widget_set_margin_top (GTK_WIDGET (description_widget), 10); gtk_box_append (content_box, GTK_WIDGET (description_widget)); } } else { GtkLabel *fallback_label = NULL; fallback_label = GTK_LABEL (gtk_label_new (_ ("No details for this release"))); gtk_widget_set_margin_top (GTK_WIDGET (fallback_label), 5); gtk_widget_add_css_class (GTK_WIDGET (fallback_label), "dim-label"); gtk_label_set_xalign (fallback_label, 0.0); gtk_label_set_wrap (fallback_label, TRUE); gtk_box_append (content_box, GTK_WIDGET (fallback_label)); } if (!use_clamp && url && *url) { more_info_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4)); markup = g_markup_printf_escaped ("%s", url, url, _ ("Get More Information")); more_info_label = GTK_LABEL (gtk_label_new (NULL)); gtk_label_set_markup (more_info_label, markup); gtk_widget_set_tooltip_text (GTK_WIDGET (more_info_label), url); gtk_box_append (more_info_box, GTK_WIDGET (more_info_label)); more_info_icon = GTK_IMAGE (gtk_image_new_from_icon_name ("external-link-symbolic")); gtk_image_set_pixel_size (more_info_icon, 12); gtk_widget_add_css_class (GTK_WIDGET (more_info_icon), "accent"); gtk_box_append (more_info_box, GTK_WIDGET (more_info_icon)); gtk_box_append (content_box, GTK_WIDGET (more_info_box)); } gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), GTK_WIDGET (content_box)); return GTK_WIDGET (row); } static void bz_releases_dialog_dispose (GObject *object) { BzReleasesDialog *self = (BzReleasesDialog *) object; g_clear_object (&self->installed_versions); G_OBJECT_CLASS (bz_releases_dialog_parent_class)->dispose (object); } static void bz_releases_dialog_class_init (BzReleasesDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_releases_dialog_dispose; gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-releases-dialog.ui"); gtk_widget_class_bind_template_child (widget_class, BzReleasesDialog, releases_box); } static void bz_releases_dialog_init (BzReleasesDialog *self) { gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_releases_dialog_new (GListModel *version_history, GListModel *installed_versions) { BzReleasesDialog *dialog = NULL; guint n_items = 0; dialog = g_object_new (bz_releases_dialog_get_type (), NULL); if (installed_versions) dialog->installed_versions = g_object_ref (installed_versions); if (version_history == NULL) return GTK_WIDGET (dialog); n_items = g_list_model_get_n_items (version_history); for (guint i = 0; i < n_items; i++) { g_autoptr (BzRelease) release = NULL; const char *version = NULL; const char *description = NULL; const char *url = NULL; guint64 timestamp = 0; GtkWidget *row = NULL; release = g_list_model_get_item (version_history, i); if (release == NULL) continue; version = bz_release_get_version (release); description = bz_release_get_description (release); url = bz_release_get_url (release); timestamp = bz_release_get_timestamp (release); row = create_release_row (version, description, timestamp, url, FALSE, dialog->installed_versions); gtk_list_box_append (dialog->releases_box, row); } return GTK_WIDGET (dialog); } static void clear_preview_box (BzReleasesList *self) { GtkWidget *child = NULL; g_return_if_fail (BZ_IS_RELEASES_LIST (self)); while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->preview_box))) != NULL) { if (child == GTK_WIDGET (self->show_all_box)) break; gtk_list_box_remove (self->preview_box, child); } } static void populate_preview_box (BzReleasesList *self) { guint n_items = 0; g_return_if_fail (BZ_IS_RELEASES_LIST (self)); clear_preview_box (self); if (self->version_history == NULL) { gtk_widget_set_visible (GTK_WIDGET (self->show_all_box), FALSE); return; } n_items = g_list_model_get_n_items (self->version_history); if (n_items == 0) { gtk_widget_set_visible (GTK_WIDGET (self->show_all_box), FALSE); return; } if (n_items > 0) { g_autoptr (BzRelease) release = NULL; const char *version = NULL; const char *description = NULL; guint64 timestamp = 0; GtkWidget *row = NULL; release = g_list_model_get_item (self->version_history, 0); if (release != NULL) { version = bz_release_get_version (release); description = bz_release_get_description (release); timestamp = bz_release_get_timestamp (release); row = create_release_row (version, description, timestamp, NULL, TRUE, self->installed_versions); gtk_list_box_insert (self->preview_box, row, 0); } } gtk_widget_set_visible (GTK_WIDGET (self->show_all_box), n_items > 0); } static void show_all_releases_cb (AdwButtonRow *button, BzReleasesList *self) { GtkWidget *dialog = NULL; GtkRoot *root = NULL; g_return_if_fail (BZ_IS_RELEASES_LIST (self)); root = gtk_widget_get_root (GTK_WIDGET (self)); if (root == NULL) return; dialog = bz_releases_dialog_new (self->version_history, self->installed_versions); adw_dialog_present (ADW_DIALOG (dialog), GTK_WIDGET (root)); } static void bz_releases_list_dispose (GObject *object) { BzReleasesList *self = BZ_RELEASES_LIST (object); g_clear_object (&self->version_history); g_clear_object (&self->installed_versions); G_OBJECT_CLASS (bz_releases_list_parent_class)->dispose (object); } static void bz_releases_list_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzReleasesList *self = BZ_RELEASES_LIST (object); switch (prop_id) { case PROP_VERSION_HISTORY: g_value_set_object (value, self->version_history); break; case PROP_INSTALLED_VERSIONS: g_value_set_object (value, self->installed_versions); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_releases_list_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzReleasesList *self = BZ_RELEASES_LIST (object); switch (prop_id) { case PROP_VERSION_HISTORY: bz_releases_list_set_version_history (self, g_value_get_object (value)); break; case PROP_INSTALLED_VERSIONS: g_clear_object (&self->installed_versions); self->installed_versions = g_value_dup_object (value); populate_preview_box (self); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_releases_list_class_init (BzReleasesListClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_releases_list_dispose; object_class->get_property = bz_releases_list_get_property; object_class->set_property = bz_releases_list_set_property; props[PROP_VERSION_HISTORY] = g_param_spec_object ("version-history", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_INSTALLED_VERSIONS] = g_param_spec_object ("installed-versions", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_RELEASE); g_type_ensure (BZ_TYPE_APPSTREAM_DESCRIPTION_RENDER); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-releases-list.ui"); bz_widget_class_bind_all_util_callbacks (widget_class); gtk_widget_class_bind_template_child (widget_class, BzReleasesList, preview_box); gtk_widget_class_bind_template_child (widget_class, BzReleasesList, show_all_box); gtk_widget_class_bind_template_callback (widget_class, show_all_releases_cb); } static void bz_releases_list_init (BzReleasesList *self) { gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_releases_list_new (void) { return g_object_new (BZ_TYPE_RELEASES_LIST, NULL); } void bz_releases_list_set_version_history (BzReleasesList *self, GListModel *version_history) { g_return_if_fail (BZ_IS_RELEASES_LIST (self)); g_return_if_fail (version_history == NULL || G_IS_LIST_MODEL (version_history)); if (self->version_history == version_history) return; g_clear_object (&self->version_history); if (version_history != NULL) { self->version_history = g_object_ref (version_history); populate_preview_box (self); gtk_widget_set_visible (GTK_WIDGET (self), g_list_model_get_n_items (version_history) > 0); } else { clear_preview_box (self); gtk_widget_set_visible (GTK_WIDGET (self), FALSE); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_VERSION_HISTORY]); } GListModel * bz_releases_list_get_version_history (BzReleasesList *self) { g_return_val_if_fail (BZ_IS_RELEASES_LIST (self), NULL); return self->version_history; } bazaar-orig-v0.7.14/src/bz-entry-inspector.blp0000664000175000017500000000454315166123241020212 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzEntryInspector: Adw.Window { title: "Entry Inspector"; default-width: 600; default-height: 800; width-request: 300; height-request: 600; Adw.ToolbarView { top-bar-style: raised_border; bottom-bar-style: raised_border; reveal-bottom-bars: false; content: Box { orientation: vertical; spacing: 5; Label { xalign: 0.0; label: bind template.result as <$BzResult>.message as ; } Label { styles [ "heading", ] xalign: 0.0; selectable: true; label: bind template.result as <$BzResult>.object as <$BzEntry>.title; } Label { xalign: 0.0; selectable: true; label: bind template.result as <$BzResult>.object as <$BzEntry>.unique_id; } Label { xalign: 0.0; selectable: true; label: bind template.result as <$BzResult>.object as <$BzEntry>.unique_id_checksum; } Label { xalign: 0.0; selectable: true; label: bind template.result as <$BzResult>.object as <$BzEntry>.id; } Box { orientation: horizontal; spacing: 5; Image { pixel-size: 16; paintable: bind template.result as <$BzResult>.object as <$BzEntry>.icon-paintable; } Image { pixel-size: 32; paintable: bind template.result as <$BzResult>.object as <$BzEntry>.icon-paintable; } Image { pixel-size: 64; paintable: bind template.result as <$BzResult>.object as <$BzEntry>.icon-paintable; } Image { pixel-size: 128; paintable: bind template.result as <$BzResult>.object as <$BzEntry>.icon-paintable; } } Box { orientation: horizontal; Button { label: "Serialize"; clicked => $gen_serialized(template); } CheckButton convert_to_json { label: "Convert to JSON"; active: true; } } ScrolledWindow { propagate-natural-height: true; child: TextView { styles [ "monospace", ] // wrap-mode: word_char; buffer: TextBuffer text_buffer {}; }; } }; [top] Adw.HeaderBar top_header_bar {} } } bazaar-orig-v0.7.14/src/icons/0000775000175000017500000000000015166123241015042 5ustar hasanhasanbazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.Utilities.svg0000664000175000017500000001355615166123241024313 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.Popular.svg0000664000175000017500000000751215166123241023755 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolunmi.Bazaar.gitlab.svg0000664000175000017500000000403515166123241023572 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.Mobile.svg0000664000175000017500000002551315166123241023543 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.Kde.svg0000664000175000017500000000306415166123241023034 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolunmi.Bazaar.gnome.svg0000664000175000017500000000241115166123241023431 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.Audiovideo.svg0000664000175000017500000003521015166123241024417 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.Trending.svg0000664000175000017500000003006215166123241024101 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.Play.svg0000664000175000017500000001416515166123241023242 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolunmi.Bazaar.github.svg0000664000175000017500000000277315166123241023621 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolunmi.Bazaar.google.svg0000664000175000017500000000263515166123241023610 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/0000775000175000017500000000000015166123241016610 5ustar hasanhasanbazaar-orig-v0.7.14/src/icons/scalable/actions/0000775000175000017500000000000015166123241020250 5ustar hasanhasanbazaar-orig-v0.7.14/src/icons/scalable/actions/execute-to-symbolic.svg0000664000175000017500000000062215166123241024672 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/library-symbolic.svg0000664000175000017500000000211015166123241024246 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/permissions-legacy-windowing-system-symbolic.svg0000664000175000017500000000125215166123241031752 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/server-pick-symbolic.svg0000664000175000017500000000165215166123241025046 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/power-profile-performance-symbolic.svg0000664000175000017500000000226315166123241027704 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/sad-computer-symbolic.svg0000664000175000017500000000222415166123241025213 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/puzzle-piece-symbolic.svg0000664000175000017500000000120315166123241025220 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/drive-harddisk-symbolic.svg0000664000175000017500000000121415166123241025506 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/globe-symbolic.svg0000664000175000017500000000527015166123241023704 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/zoom-plus-symbolic.svg0000664000175000017500000000140315166123241024553 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/school-symbolic.svg0000664000175000017500000000201315166123241024073 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/bookmark-filled-symbolic.svg0000664000175000017500000000074715166123241025662 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/delay-symbolic.svg0000664000175000017500000000216015166123241023705 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/device-support-touch-symbolic.svg0000664000175000017500000000212015166123241026674 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/hand-openyay-symbolic.svg0000664000175000017500000000141615166123241025206 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/zoom-minus-symbolic.svg0000664000175000017500000000133715166123241024731 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/copy-symbolic.svg0000664000175000017500000000136715166123241023571 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/go-previous-symbolic.svg0000664000175000017500000000117615166123241025074 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/bookmark-outline-symbolic.svg0000664000175000017500000000124715166123241026076 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/pip-out-symbolic.svg0000664000175000017500000000170715166123241024212 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/community-symbolic.svg0000664000175000017500000000262515166123241024641 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/newspaper-symbolic.svg0000664000175000017500000000153015166123241024613 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/timer-sand-symbolic.svg0000664000175000017500000000105715166123241024656 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/translations-symbolic.svg0000664000175000017500000000120615166123241025330 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/check-plain-symbolic.svg0000664000175000017500000000133615166123241024771 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/horizontal-arrows-disabled-symbolic.svg0000664000175000017500000000264515166123241030070 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/device-supported-symbolic.svg0000664000175000017500000000155015166123241026073 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/user-trash-symbolic.svg0000664000175000017500000000205015166123241024702 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/device-support-adaptive-symbolic.svg0000664000175000017500000000154015166123241027354 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/flathub-symbolic.svg0000664000175000017500000000371615166123241024244 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/verified-checkmark-symbolic.svg0000664000175000017500000000306115166123241026333 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/connected-squares-x-symbolic.svg0000664000175000017500000000225415166123241026503 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/app-safety-unsafe-symbolic.svg0000664000175000017500000000156115166123241026143 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/permissions-microphone-symbolic.svg0000664000175000017500000000075115166123241027327 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/starred-symbolic.svg0000664000175000017500000000131715166123241024256 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/smartphone2-symbolic.svg0000664000175000017500000000101615166123241025050 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/cross-large-circle-filled-symbolic.svg0000664000175000017500000000162015166123241027524 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/person-symbolic.svg0000664000175000017500000000060215166123241024114 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/earth-symbolic.svg0000664000175000017500000000433015166123241023713 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/on-the-go-symbolic.svg0000664000175000017500000000625715166123241024417 0ustar hasanhasanbazaar-orig-v0.7.14/src/icons/scalable/actions/circle-filled-symbolic.svg0000664000175000017500000000040515166123241025305 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/graph2-symbolic.svg0000664000175000017500000000107615166123241023777 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/flatpak-symbolic.svg0000664000175000017500000000132415166123241024232 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/auditable-code-symbolic.svg0000664000175000017500000000242215166123241025452 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/meeting-symbolic.svg0000664000175000017500000000107015166123241024236 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/app-safety-ok-symbolic.svg0000664000175000017500000000125515166123241025273 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/right-large-symbolic.svg0000664000175000017500000000074415166123241025022 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/media-playback-pause-symbolic.svg0000664000175000017500000000100715166123241026564 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/image-missing-symbolic.svg0000664000175000017500000000152215166123241025341 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/sidebar-show-symbolic.svg0000664000175000017500000000114215166123241025175 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/folder-download-symbolic.svg0000664000175000017500000000116615166123241025674 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/square-filled-symbolic.svg0000664000175000017500000000047615166123241025354 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/heart-filled-symbolic.svg0000664000175000017500000000112515166123241025147 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/external-link-symbolic.svg0000664000175000017500000000242415166123241025367 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/left-large-symbolic.svg0000664000175000017500000000074315166123241024636 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/code-symbolic.svg0000664000175000017500000000140615166123241023523 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/media-playback-start-symbolic.svg0000664000175000017500000000105215166123241026604 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/eye-outline-filled-symbolic.svg0000664000175000017500000000154015166123241026304 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/permissions-warning-symbolic.svg0000664000175000017500000000156115166123241026631 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/permissions-system-devices-symbolic.svg0000664000175000017500000000214715166123241030131 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/sliders-horizontal-symbolic.svg0000664000175000017500000000176715166123241026457 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/share-alt-symbolic.svg0000664000175000017500000000157115166123241024474 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/regex-symbolic.svg0000664000175000017500000000117215166123241023723 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/parent-symbolic.svg0000664000175000017500000000257615166123241024113 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/download-plus-symbolic.svg0000664000175000017500000000344015166123241025401 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/edit-clear-all-symbolic.svg0000664000175000017500000000231315166123241025366 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/paintbrush-symbolic.svg0000664000175000017500000000106715166123241024773 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/app-installed-symbolic.svg0000664000175000017500000000143515166123241025350 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/0000775000175000017500000000000015166123241021717 5ustar hasanhasanbazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/violence-none-symbolic.svg0000664000175000017500000000101715166123241027017 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/audio-chat-none-symbolic.svg0000664000175000017500000000115215166123241027231 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/money-symbolic.svg0000664000175000017500000000076215166123241025413 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/alcohol-use-symbolic.svg0000664000175000017500000000124715166123241026476 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/nudity-symbolic.svg0000664000175000017500000000076015166123241025576 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/drug-use-none-symbolic.svg0000664000175000017500000000170115166123241026746 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/violence-symbolic.svg0000664000175000017500000000055115166123241026064 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/money-none-symbolic.svg0000664000175000017500000000114615166123241026345 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/smoking-none-symbolic.svg0000664000175000017500000000074315166123241026667 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/nudity-none-symbolic.svg0000664000175000017500000000131015166123241026523 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/alcohol-use-none-symbolic.svg0000664000175000017500000000133715166123241027433 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/contacts-symbolic.svg0000664000175000017500000000202015166123241026067 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/strong-language-symbolic.svg0000664000175000017500000000053715166123241027361 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/human-remains-symbolic.svg0000664000175000017500000000061415166123241027024 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/gambling-none-symbolic.svg0000664000175000017500000000102715166123241026774 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/messaging-symbolic.svg0000664000175000017500000000065615166123241026243 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/audio-chat-symbolic.svg0000664000175000017500000000075115166123241026300 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/strong-language-none-symbolic.svg0000664000175000017500000000065715166123241030321 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/advertising-symbolic.svg0000664000175000017500000000160515166123241026600 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/drug-use-symbolic.svg0000664000175000017500000000152615166123241026016 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/gambling-symbolic.svg0000664000175000017500000000075015166123241026041 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/social-info-symbolic.svg0000664000175000017500000000175515166123241026472 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/messaging-none-symbolic.svg0000664000175000017500000000100515166123241027165 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/smoking-symbolic.svg0000664000175000017500000000065515166123241025734 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/ratings/advertising-none-symbolic.svg0000664000175000017500000000157215166123241027540 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/device-support-desktop-symbolic.svg0000664000175000017500000000103715166123241027231 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/thumbs-up-outline-symbolic.svg0000664000175000017500000000327015166123241026213 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/share-symbolic.svg0000664000175000017500000000217515166123241023717 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/proprietary-code-symbolic.svg0000664000175000017500000000241315166123241026100 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/permissions-screen-contents-symbolic.svg0000664000175000017500000000106315166123241030273 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/license-symbolic.svg0000664000175000017500000000564115166123241024240 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/heart-outline-thick-symbolic.svg0000664000175000017500000000232715166123241026474 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/people-symbolic.svg0000664000175000017500000000155115166123241024076 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/view-more-horizontal-symbolic.svg0000664000175000017500000000102715166123241026711 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/we-love-games-symbolic.svg0000664000175000017500000001302115166123241025255 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/app-safety-unknown-symbolic.svg0000664000175000017500000000256215166123241026363 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/software-update-available-symbolic.svg0000664000175000017500000000215115166123241027637 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/permissions-sandboxed-symbolic.svg0000664000175000017500000000221215166123241027125 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/bug-symbolic.svg0000664000175000017500000000351415166123241023370 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/view-more-symbolic.svg0000664000175000017500000000076315166123241024530 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/media-playback-stop-symbolic.svg0000664000175000017500000000053115166123241026435 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/scalable/actions/open-book-symbolic.svg0000664000175000017500000000222715166123241024504 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.Network.svg0000664000175000017500000000575515166123241023773 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolunmi.Bazaar.kde.svg0000664000175000017500000000341715166123241023076 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.New.svg0000664000175000017500000000501015166123241023053 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.Develop.svg0000664000175000017500000000536215166123241023732 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.Learn.svg0000664000175000017500000002253015166123241023371 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.Create.svg0000664000175000017500000001453415166123241023540 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.System.svg0000664000175000017500000001640015166123241023613 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.Updated.svg0000664000175000017500000000323115166123241023713 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.Work.svg0000664000175000017500000002045415166123241023255 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.Science.svg0000664000175000017500000005662615166123241023716 0ustar hasanhasan bazaar-orig-v0.7.14/src/icons/io.github.kolumni.Bazaar.Adwaita.svg0000664000175000017500000000056215166123241023703 0ustar hasanhasan bazaar-orig-v0.7.14/src/bz-flathub-category.c0000664000175000017500000006340615166123241017755 0ustar hasanhasan/* bz-flathub-category.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "appstream.h" #include "bz-flathub-category.h" #include "bz-flathub-sub-category.h" #include "bz-serializable.h" struct _BzFlathubCategory { GObject parent_instance; BzApplicationMapFactory *map_factory; char *name; GListModel *applications; GListModel *quality_applications; int total_entries; gboolean is_spotlight; GListModel *subcategories; }; static void serializable_iface_init (BzSerializableInterface *iface); G_DEFINE_FINAL_TYPE_WITH_CODE ( BzFlathubCategory, bz_flathub_category, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (BZ_TYPE_SERIALIZABLE, serializable_iface_init)); enum { PROP_0, PROP_MAP_FACTORY, PROP_NAME, PROP_DISPLAY_NAME, PROP_SHORT_NAME, PROP_IS_XDG, PROP_SYMBOLIC_ICON_NAME, PROP_ICON_NAME, PROP_APPLICATIONS, PROP_QUALITY_APPLICATIONS, PROP_TOTAL_ENTRIES, PROP_IS_SPOTLIGHT, PROP_SUBCATEGORIES, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void clear (BzFlathubCategory *self); typedef struct { const char *id; const char *display_name; const char *short_name; const char *more_of_name; gboolean is_xdg; const char *icon_name; const char *symbolic_icon_name; const void *subcategories; } CategoryInfo; typedef struct { const char *display_name; const char *category_id; } Subcategory; static const Subcategory audiovideo_subcategories[] = { { N_ ("Editing"), "AudioVideoEditing" }, { N_ ("Midi"), "Midi" }, { N_ ("Mixer"), "Mixer" }, { N_ ("Music"), "Music" }, { N_ ("Player"), "Player" }, { N_ ("Recorder"), "Recorder" }, { N_ ("Sequencer"), "Sequencer" }, { N_ ("Tuner"), "Tuner" }, { N_ ("TV"), "TV" }, { NULL, NULL } }; static const Subcategory game_subcategories[] = { { N_ ("Emulation"), "Emulator" }, { N_ ("Action"), "ActionGame" }, { N_ ("Adventure"), "AdventureGame" }, { N_ ("Arcade"), "ArcadeGame" }, { N_ ("Blocks"), "BlocksGame" }, { N_ ("Board"), "BoardGame" }, { N_ ("Card"), "CardGame" }, { N_ ("Kids"), "KidsGame" }, { N_ ("Logic"), "LogicGame" }, { N_ ("Role Playing"), "RolePlaying" }, { N_ ("Shooter"), "Shooter" }, { N_ ("Simulation"), "Simulation" }, { N_ ("Sports"), "SportsGame" }, { N_ ("Strategy"), "StrategyGame" }, { NULL, NULL } }; static const CategoryInfo category_info[] = { { "audiovideo", N_ ("Audio & Video"), N_ ("Media"), N_ ("More Audio & Video"), TRUE, "io.github.kolumni.Bazaar.Audiovideo", "applications-multimedia-symbolic", audiovideo_subcategories }, { "development", N_ ("Developer Tools"), N_ ("Develop"), N_ ("More Developer Tools"), TRUE, "io.github.kolumni.Bazaar.Develop", "code-symbolic", NULL }, { "education", N_ ("Education"), N_ ("Learn"), N_ ("More Education"), TRUE, "io.github.kolumni.Bazaar.Learn", "open-book-symbolic", NULL }, { "game", N_ ("Gaming"), N_ ("Play"), N_ ("More Gaming"), TRUE, "io.github.kolumni.Bazaar.Play", "applications-games-symbolic", game_subcategories }, { "graphics", N_ ("Graphics & Photography"), N_ ("Create"), N_ ("More Graphics & Photography"), TRUE, "io.github.kolumni.Bazaar.Create", "paintbrush-symbolic", NULL }, { "network", N_ ("Networking"), N_ ("Internet"), N_ ("More Networking"), TRUE, "io.github.kolumni.Bazaar.Network", "globe-symbolic", NULL }, { "office", N_ ("Productivity"), N_ ("Work"), N_ ("More Productivity"), TRUE, "io.github.kolumni.Bazaar.Work", "meeting-symbolic", NULL }, { "science", N_ ("Science"), N_ ("Science"), N_ ("More Science"), TRUE, "io.github.kolumni.Bazaar.Science", "applications-science-symbolic", NULL }, { "system", N_ ("System"), N_ ("System"), N_ ("More System"), TRUE, "io.github.kolumni.Bazaar.System", "applications-system-symbolic", NULL }, { "utility", N_ ("Utilities"), N_ ("Tools"), N_ ("More Utilities"), TRUE, "io.github.kolumni.Bazaar.Utilities", "applications-utilities-symbolic", NULL }, { "trending", N_ ("Trending"), N_ ("Trending"), N_ ("More Trending"), FALSE, "io.github.kolumni.Bazaar.Trending", "", NULL }, { "popular", N_ ("Popular"), N_ ("Popular"), N_ ("More Popular"), FALSE, "io.github.kolumni.Bazaar.Popular", "", NULL }, { "recently-added", N_ ("Recently Added"), N_ ("New"), N_ ("More New"), FALSE, "io.github.kolumni.Bazaar.New", "", NULL }, { "recently-updated", N_ ("Recently Updated"), N_ ("Updated"), N_ ("More Updated"), FALSE, "io.github.kolumni.Bazaar.Updated", "", NULL }, { "mobile", N_ ("Mobile"), N_ ("Mobile"), N_ ("More Mobile"), FALSE, "io.github.kolumni.Bazaar.Mobile", "", NULL }, { "adwaita", N_ ("Adwaita"), N_ ("Adwaita"), N_ ("More Adwaita"), FALSE, "io.github.kolumni.Bazaar.Adwaita", "", NULL }, { "kde", N_ ("KDE Apps"), N_ ("KDE Apps"), N_ ("More KDE Apps"), FALSE, "io.github.kolumni.Bazaar.Kde", "", NULL }, { NULL, NULL, NULL, NULL, FALSE, NULL, NULL, NULL } }; static const CategoryInfo * get_category_info (const char *category_id) { for (int i = 0; category_info[i].id != NULL; i++) { if (g_strcmp0 (category_info[i].id, category_id) == 0) return &category_info[i]; } return NULL; } static GListModel * create_subcategories (const Subcategory *subcategories) { GListStore *store; store = g_list_store_new (BZ_TYPE_FLATHUB_SUB_CATEGORY); for (gsize i = 0; subcategories[i].display_name != NULL; i++) g_list_store_append (store, g_object_new (BZ_TYPE_FLATHUB_SUB_CATEGORY, "name", _ (subcategories[i].display_name), "id", subcategories[i].category_id, NULL)); return G_LIST_MODEL (store); } static void bz_flathub_category_dispose (GObject *object) { BzFlathubCategory *self = BZ_FLATHUB_CATEGORY (object); clear (self); G_OBJECT_CLASS (bz_flathub_category_parent_class)->dispose (object); } static void bz_flathub_category_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzFlathubCategory *self = BZ_FLATHUB_CATEGORY (object); switch (prop_id) { case PROP_MAP_FACTORY: g_value_set_object (value, bz_flathub_category_get_map_factory (self)); break; case PROP_NAME: g_value_set_string (value, bz_flathub_category_get_name (self)); break; case PROP_APPLICATIONS: g_value_take_object (value, bz_flathub_category_dup_applications (self)); break; case PROP_QUALITY_APPLICATIONS: g_value_take_object (value, bz_flathub_category_dup_quality_applications (self)); break; case PROP_DISPLAY_NAME: g_value_set_string (value, bz_flathub_category_get_display_name (self)); break; case PROP_SHORT_NAME: g_value_set_string (value, bz_flathub_category_get_short_name (self)); break; case PROP_IS_XDG: g_value_set_boolean (value, bz_flathub_category_get_is_xdg (self)); break; case PROP_SYMBOLIC_ICON_NAME: g_value_set_string (value, bz_flathub_category_get_symbolic_icon_name (self)); break; case PROP_ICON_NAME: g_value_set_string (value, bz_flathub_category_get_icon_name (self)); break; case PROP_TOTAL_ENTRIES: g_value_set_int (value, bz_flathub_category_get_total_entries (self)); break; case PROP_IS_SPOTLIGHT: g_value_set_boolean (value, bz_flathub_category_get_is_spotlight (self)); break; case PROP_SUBCATEGORIES: g_value_set_object (value, bz_flathub_category_get_subcategories (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_flathub_category_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzFlathubCategory *self = BZ_FLATHUB_CATEGORY (object); switch (prop_id) { case PROP_MAP_FACTORY: bz_flathub_category_set_map_factory (self, g_value_get_object (value)); break; case PROP_NAME: bz_flathub_category_set_name (self, g_value_get_string (value)); break; case PROP_APPLICATIONS: bz_flathub_category_set_applications (self, g_value_get_object (value)); break; case PROP_QUALITY_APPLICATIONS: bz_flathub_category_set_quality_applications (self, g_value_get_object (value)); break; case PROP_TOTAL_ENTRIES: bz_flathub_category_set_total_entries (self, g_value_get_int (value)); break; case PROP_IS_SPOTLIGHT: bz_flathub_category_set_is_spotlight (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_flathub_category_class_init (BzFlathubCategoryClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bz_flathub_category_set_property; object_class->get_property = bz_flathub_category_get_property; object_class->dispose = bz_flathub_category_dispose; props[PROP_MAP_FACTORY] = g_param_spec_object ( "map-factory", NULL, NULL, BZ_TYPE_APPLICATION_MAP_FACTORY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_NAME] = g_param_spec_string ( "name", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_DISPLAY_NAME] = g_param_spec_string ( "display-name", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_SHORT_NAME] = g_param_spec_string ( "short-name", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_IS_XDG] = g_param_spec_boolean ( "is-xdg", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_SYMBOLIC_ICON_NAME] = g_param_spec_string ( "symbolic-icon-name", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_ICON_NAME] = g_param_spec_string ( "icon-name", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_APPLICATIONS] = g_param_spec_object ( "applications", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_QUALITY_APPLICATIONS] = g_param_spec_object ( "quality-applications", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_TOTAL_ENTRIES] = g_param_spec_int ( "total-entries", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_IS_SPOTLIGHT] = g_param_spec_boolean ( "is-spotlight", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_SUBCATEGORIES] = g_param_spec_object ( "subcategories", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_flathub_category_init (BzFlathubCategory *self) { } static void bz_flathub_category_real_serialize (BzSerializable *serializable, GVariantBuilder *builder) { BzFlathubCategory *self = BZ_FLATHUB_CATEGORY (serializable); if (self->name != NULL) g_variant_builder_add (builder, "{sv}", "name", g_variant_new_string (self->name)); if (self->applications != NULL) { guint n_items = 0; n_items = g_list_model_get_n_items (self->applications); if (n_items > 0) { g_autoptr (GVariantBuilder) sub_builder = NULL; sub_builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); for (guint i = 0; i < n_items; i++) { g_autoptr (GtkStringObject) string = NULL; string = g_list_model_get_item (self->applications, i); g_variant_builder_add (sub_builder, "s", gtk_string_object_get_string (string)); } g_variant_builder_add (builder, "{sv}", "applications", g_variant_builder_end (sub_builder)); } } if (self->quality_applications != NULL) { guint n_items = 0; n_items = g_list_model_get_n_items (self->quality_applications); if (n_items > 0) { g_autoptr (GVariantBuilder) sub_builder = NULL; sub_builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); for (guint i = 0; i < n_items; i++) { g_autoptr (GtkStringObject) string = NULL; string = g_list_model_get_item (self->quality_applications, i); g_variant_builder_add (sub_builder, "s", gtk_string_object_get_string (string)); } g_variant_builder_add (builder, "{sv}", "quality-applications", g_variant_builder_end (sub_builder)); } } g_variant_builder_add (builder, "{sv}", "total-entries", g_variant_new_int32 (self->total_entries)); g_variant_builder_add (builder, "{sv}", "is-spotlight", g_variant_new_boolean (self->is_spotlight)); } static gboolean bz_flathub_category_real_deserialize (BzSerializable *serializable, GVariant *import, GError **error) { BzFlathubCategory *self = BZ_FLATHUB_CATEGORY (serializable); g_autoptr (GVariantIter) iter = NULL; clear (self); iter = g_variant_iter_new (import); for (;;) { g_autofree char *key = NULL; g_autoptr (GVariant) value = NULL; /* TODO automate this, this is awful */ if (!g_variant_iter_next (iter, "{sv}", &key, &value)) break; if (g_strcmp0 (key, "name") == 0) bz_flathub_category_set_name (self, g_variant_get_string (value, NULL)); else if (g_strcmp0 (key, "applications") == 0) { g_autoptr (GtkStringList) list = NULL; g_autoptr (GVariantIter) list_iter = NULL; list = gtk_string_list_new (NULL); list_iter = g_variant_iter_new (value); for (;;) { g_autofree char *id = NULL; if (!g_variant_iter_next (list_iter, "s", &id)) break; gtk_string_list_append (list, id); } self->applications = (GListModel *) g_steal_pointer (&list); } else if (g_strcmp0 (key, "quality-applications") == 0) { g_autoptr (GtkStringList) list = NULL; g_autoptr (GVariantIter) list_iter = NULL; list = gtk_string_list_new (NULL); list_iter = g_variant_iter_new (value); for (;;) { g_autofree char *id = NULL; if (!g_variant_iter_next (list_iter, "s", &id)) break; gtk_string_list_append (list, id); } self->quality_applications = (GListModel *) g_steal_pointer (&list); } else if (g_strcmp0 (key, "total-entries") == 0) self->total_entries = g_variant_get_int32 (value); else if (g_strcmp0 (key, "is-spotlight") == 0) self->is_spotlight = g_variant_get_boolean (value); } return TRUE; } static void serializable_iface_init (BzSerializableInterface *iface) { iface->serialize = bz_flathub_category_real_serialize; iface->deserialize = bz_flathub_category_real_deserialize; } BzFlathubCategory * bz_flathub_category_new (void) { return g_object_new (BZ_TYPE_FLATHUB_CATEGORY, NULL); } BzApplicationMapFactory * bz_flathub_category_get_map_factory (BzFlathubCategory *self) { g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY (self), NULL); return self->map_factory; } const char * bz_flathub_category_get_name (BzFlathubCategory *self) { g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY (self), NULL); return self->name; } GListModel * bz_flathub_category_dup_applications (BzFlathubCategory *self) { g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY (self), NULL); if (self->applications != NULL) { if (self->map_factory != NULL) return bz_application_map_factory_generate ( self->map_factory, G_LIST_MODEL (self->applications)); else return G_LIST_MODEL (g_object_ref (self->applications)); } else return NULL; } GListModel * bz_flathub_category_dup_quality_applications (BzFlathubCategory *self) { g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY (self), NULL); if (self->quality_applications != NULL) { if (self->map_factory != NULL) return bz_application_map_factory_generate ( self->map_factory, G_LIST_MODEL (self->quality_applications)); else return G_LIST_MODEL (g_object_ref (self->quality_applications)); } else return NULL; } int bz_flathub_category_get_total_entries (BzFlathubCategory *self) { g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY (self), 0); return self->total_entries; } gboolean bz_flathub_category_get_is_spotlight (BzFlathubCategory *self) { g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY (self), FALSE); return self->is_spotlight; } void bz_flathub_category_set_map_factory (BzFlathubCategory *self, BzApplicationMapFactory *map_factory) { g_return_if_fail (BZ_IS_FLATHUB_CATEGORY (self)); g_return_if_fail (map_factory == NULL || BZ_IS_APPLICATION_MAP_FACTORY (map_factory)); g_clear_object (&self->map_factory); if (map_factory != NULL) self->map_factory = g_object_ref (map_factory); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MAP_FACTORY]); } void bz_flathub_category_set_name (BzFlathubCategory *self, const char *name) { const CategoryInfo *info; g_return_if_fail (BZ_IS_FLATHUB_CATEGORY (self)); g_clear_pointer (&self->name, g_free); self->name = g_strdup (name); info = get_category_info (name); if (info != NULL && info->subcategories != NULL) { g_clear_object (&self->subcategories); self->subcategories = create_subcategories ((const Subcategory *) info->subcategories); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SUBCATEGORIES]); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NAME]); } void bz_flathub_category_set_applications (BzFlathubCategory *self, GListModel *applications) { g_return_if_fail (BZ_IS_FLATHUB_CATEGORY (self)); g_clear_pointer (&self->applications, g_object_unref); if (applications != NULL) self->applications = g_object_ref (applications); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_APPLICATIONS]); } void bz_flathub_category_set_quality_applications (BzFlathubCategory *self, GListModel *applications) { g_return_if_fail (BZ_IS_FLATHUB_CATEGORY (self)); g_clear_pointer (&self->quality_applications, g_object_unref); if (applications != NULL) self->quality_applications = g_object_ref (applications); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_QUALITY_APPLICATIONS]); } void bz_flathub_category_set_total_entries (BzFlathubCategory *self, int total_entries) { g_return_if_fail (BZ_IS_FLATHUB_CATEGORY (self)); if (self->total_entries == total_entries) return; self->total_entries = total_entries; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TOTAL_ENTRIES]); } void bz_flathub_category_set_is_spotlight (BzFlathubCategory *self, gboolean is_spotlight) { g_return_if_fail (BZ_IS_FLATHUB_CATEGORY (self)); if (self->is_spotlight == is_spotlight) return; self->is_spotlight = is_spotlight; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_IS_SPOTLIGHT]); } const char * bz_flathub_category_get_display_name (BzFlathubCategory *self) { const CategoryInfo *info; g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY (self), NULL); info = get_category_info (self->name); return info ? _ (info->display_name) : self->name; } const char * bz_flathub_category_get_short_name (BzFlathubCategory *self) { const CategoryInfo *info; g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY (self), NULL); info = get_category_info (self->name); return info ? _ (info->short_name) : self->name; } const char * bz_flathub_category_get_more_of_name (BzFlathubCategory *self) { const CategoryInfo *info; g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY (self), NULL); info = get_category_info (self->name); return info ? _ (info->more_of_name) : self->name; } gboolean bz_flathub_category_get_is_xdg (BzFlathubCategory *self) { const CategoryInfo *info; g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY (self), FALSE); info = get_category_info (self->name); return info ? info->is_xdg : FALSE; } const char * bz_flathub_category_get_symbolic_icon_name (BzFlathubCategory *self) { const CategoryInfo *info; g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY (self), NULL); info = get_category_info (self->name); return info ? info->symbolic_icon_name : NULL; } const char * bz_flathub_category_get_icon_name (BzFlathubCategory *self) { const CategoryInfo *info; g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY (self), NULL); info = get_category_info (self->name); return info ? info->icon_name : NULL; } GListModel * bz_flathub_category_get_subcategories (BzFlathubCategory *self) { g_return_val_if_fail (BZ_IS_FLATHUB_CATEGORY (self), NULL); return self->subcategories; } static void clear (BzFlathubCategory *self) { g_clear_pointer (&self->map_factory, g_object_unref); g_clear_pointer (&self->name, g_free); g_clear_pointer (&self->applications, g_object_unref); g_clear_pointer (&self->quality_applications, g_object_unref); g_clear_object (&self->subcategories); } static const char * bz_flathub_category_map_appstream_id (const char *as_category_id) { g_autofree char *lowercase = NULL; const CategoryInfo *info = NULL; g_return_val_if_fail (as_category_id != NULL, NULL); lowercase = g_ascii_strdown (as_category_id, -1); info = get_category_info (lowercase); return info ? info->id : NULL; } GListModel * bz_flathub_category_list_from_appstream (GPtrArray *as_categories) { g_autoptr (GListStore) categories = NULL; g_return_val_if_fail (as_categories != NULL, NULL); if (as_categories->len == 0) return NULL; categories = g_list_store_new (BZ_TYPE_FLATHUB_CATEGORY); for (guint i = 0; i < as_categories->len; i++) { const char *category_id = NULL; const char *mapped_id = NULL; category_id = (const char *) g_ptr_array_index (as_categories, i); if (category_id == NULL) continue; mapped_id = bz_flathub_category_map_appstream_id (category_id); if (mapped_id != NULL) { g_autoptr (BzFlathubCategory) category = NULL; category = bz_flathub_category_new (); bz_flathub_category_set_name (category, mapped_id); g_list_store_append (categories, category); } } if (g_list_model_get_n_items (G_LIST_MODEL (categories)) == 0) return NULL; return G_LIST_MODEL (g_steal_pointer (&categories)); } /* End of bz-flathub-category.c */ bazaar-orig-v0.7.14/src/bz-serializable.c0000664000175000017500000000377615166123241017167 0ustar hasanhasan/* bz-serializable.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-serializable.h" G_DEFINE_INTERFACE (BzSerializable, bz_serializable, G_TYPE_OBJECT) static void bz_serializable_real_serialize (BzSerializable *self, GVariantBuilder *builder) { return; } static gboolean bz_serializable_real_deserialize (BzSerializable *self, GVariant *import, GError **error) { return TRUE; } static void bz_serializable_default_init (BzSerializableInterface *iface) { iface->serialize = bz_serializable_real_serialize; iface->deserialize = bz_serializable_real_deserialize; } void bz_serializable_serialize (BzSerializable *self, GVariantBuilder *builder) { g_return_if_fail (BZ_IS_SERIALIZABLE (self)); g_return_if_fail (builder != NULL); BZ_SERIALIZABLE_GET_IFACE (self)->serialize ( self, builder); } gboolean bz_serializable_deserialize (BzSerializable *self, GVariant *import, GError **error) { g_return_val_if_fail (BZ_IS_SERIALIZABLE (self), FALSE); g_return_val_if_fail (import != NULL, FALSE); return BZ_SERIALIZABLE_GET_IFACE (self)->deserialize ( self, import, error); } bazaar-orig-v0.7.14/src/bz-app-tile.blp0000664000175000017500000000435215166123241016556 0ustar hasanhasanusing Gtk 4.0; template $BzAppTile: Button { preferred-width: 270; styles [ "card", "app-tile", ] child: Overlay { Box { margin-start: 12; margin-end: 12; margin-top: 12; margin-bottom: 12; orientation: horizontal; spacing: 15; can-focus: false; Image { pixel-size: 64; paintable: bind template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable; styles ["icon-dropshadow"] } Box { valign: center; hexpand: true; orientation: vertical; spacing: 4; Box { orientation: horizontal; spacing: 6; Label { css-name: "app-tile-title"; styles [ "heading", ] xalign: 0.0; ellipsize: end; label: bind template.group as <$BzEntryGroup>.title; } Image { css-name: "app-tile-verified-check"; styles [ "verified", ] visible: bind template.group as <$BzEntryGroup>.is-verified; icon-name: "verified-checkmark-symbolic"; pixel-size: 14; accessibility { label: _("Verified"); } } } Label { css-name: "app-tile-description"; xalign: 0.0; yalign: 0.0; wrap: true; ellipsize: end; vexpand: true; lines: bind $description_line_amount($is_zero(template.group as <$BzEntryGroup>.removable) as ) as ; single-line-mode: true; label: bind template.group as <$BzEntryGroup>.description; } Box { css-name: "app-tile-installed-pill"; halign: start; spacing: 4; visible: bind $invert_boolean($is_zero(template.group as <$BzEntryGroup>.removable) as ) as ; styles ["small-pill", "installed-pill"] Image { icon-name: "app-installed-symbolic"; pixel-size: 12; } Label { // Translators: As in 'The app is installed'. label: _("Installed"); } } } } }; } bazaar-orig-v0.7.14/src/bz-backend.c0000664000175000017500000002262115166123241016076 0ustar hasanhasan/* bz-backend.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include "bz-backend.h" #include "bz-transaction.h" G_DEFINE_INTERFACE (BzBackend, bz_backend, G_TYPE_OBJECT) static DexChannel * bz_backend_real_create_notification_channel (BzBackend *self) { return NULL; } static DexFuture * bz_backend_real_load_local_package (BzBackend *self, GFile *file, GCancellable *cancellable) { return dex_future_new_reject (G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Unimplemented"); } static DexFuture * bz_backend_real_retrieve_remote_entries (BzBackend *self, GCancellable *cancellable) { return dex_future_new_reject (G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Unimplemented"); } static DexFuture * bz_backend_real_retrieve_install_ids (BzBackend *self, GCancellable *cancellable) { return dex_future_new_reject (G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Unimplemented"); } static DexFuture * bz_backend_real_retrieve_update_ids (BzBackend *self, GCancellable *cancellable) { return dex_future_new_reject (G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Unimplemented"); } static DexFuture * bz_backend_real_list_repositories (BzBackend *self, GCancellable *cancellable) { return dex_future_new_reject (G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Unimplemented"); } static DexFuture * bz_backend_real_schedule_transaction (BzBackend *self, BzEntry **installs, guint n_installs, BzEntry **updates, guint n_updates, BzEntry **removals, guint n_removals, DexChannel *channel, GCancellable *cancellable) { return dex_future_new_reject (G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Unimplemented"); } static gboolean bz_backend_real_cancel_task_for_entry (BzBackend *self, BzEntry *entry) { return FALSE; } static void bz_backend_default_init (BzBackendInterface *iface) { iface->create_notification_channel = bz_backend_real_create_notification_channel; iface->load_local_package = bz_backend_real_load_local_package; iface->retrieve_remote_entries = bz_backend_real_retrieve_remote_entries; iface->retrieve_install_ids = bz_backend_real_retrieve_install_ids; iface->retrieve_update_ids = bz_backend_real_retrieve_update_ids; iface->list_repositories = bz_backend_real_list_repositories; iface->schedule_transaction = bz_backend_real_schedule_transaction; iface->cancel_task_for_entry = bz_backend_real_cancel_task_for_entry; } DexChannel * bz_backend_create_notification_channel (BzBackend *self) { g_return_val_if_fail (BZ_IS_BACKEND (self), NULL); return BZ_BACKEND_GET_IFACE (self)->create_notification_channel (self); } DexFuture * bz_backend_load_local_package (BzBackend *self, GFile *file, GCancellable *cancellable) { dex_return_error_if_fail (BZ_IS_BACKEND (self)); dex_return_error_if_fail (G_IS_FILE (file)); dex_return_error_if_fail (cancellable == NULL || G_IS_CANCELLABLE (self)); return BZ_BACKEND_GET_IFACE (self)->load_local_package (self, file, cancellable); } DexFuture * bz_backend_retrieve_remote_entries (BzBackend *self, GCancellable *cancellable) { dex_return_error_if_fail (BZ_IS_BACKEND (self)); dex_return_error_if_fail (cancellable == NULL || G_IS_CANCELLABLE (self)); return BZ_BACKEND_GET_IFACE (self)->retrieve_remote_entries (self, cancellable); } DexFuture * bz_backend_retrieve_install_ids (BzBackend *self, GCancellable *cancellable) { dex_return_error_if_fail (BZ_IS_BACKEND (self)); return BZ_BACKEND_GET_IFACE (self)->retrieve_install_ids (self, cancellable); } DexFuture * bz_backend_retrieve_update_ids (BzBackend *self, GCancellable *cancellable) { dex_return_error_if_fail (BZ_IS_BACKEND (self)); return BZ_BACKEND_GET_IFACE (self)->retrieve_update_ids (self, cancellable); } DexFuture * bz_backend_list_repositories (BzBackend *self, GCancellable *cancellable) { dex_return_error_if_fail (BZ_IS_BACKEND (self)); dex_return_error_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); return BZ_BACKEND_GET_IFACE (self)->list_repositories (self, cancellable); } DexFuture * bz_backend_schedule_transaction (BzBackend *self, BzEntry **installs, guint n_installs, BzEntry **updates, guint n_updates, BzEntry **removals, guint n_removals, DexChannel *channel, GCancellable *cancellable) { dex_return_error_if_fail (BZ_IS_BACKEND (self)); dex_return_error_if_fail ((installs != NULL && n_installs > 0) || (updates != NULL && n_updates > 0) || (removals != NULL && n_removals)); if (installs != NULL) { for (guint i = 0; i < n_installs; i++) dex_return_error_if_fail (BZ_IS_ENTRY (installs[i])); } if (updates != NULL) { for (guint i = 0; i < n_updates; i++) dex_return_error_if_fail (BZ_IS_ENTRY (updates[i])); } if (removals != NULL) { for (guint i = 0; i < n_removals; i++) dex_return_error_if_fail (BZ_IS_ENTRY (removals[i])); } return BZ_BACKEND_GET_IFACE (self)->schedule_transaction ( self, installs, n_installs, updates, n_updates, removals, n_removals, channel, cancellable); } DexFuture * bz_backend_merge_and_schedule_transactions (BzBackend *self, GListModel *transactions, DexChannel *channel, GCancellable *cancellable) { guint n_items = 0; g_autoptr (GPtrArray) installs_pa = NULL; g_autoptr (GPtrArray) updates_pa = NULL; g_autoptr (GPtrArray) removals_pa = NULL; dex_return_error_if_fail (G_IS_LIST_MODEL (transactions)); n_items = g_list_model_get_n_items (transactions); dex_return_error_if_fail (n_items > 0); installs_pa = g_ptr_array_new_with_free_func (g_object_unref); updates_pa = g_ptr_array_new_with_free_func (g_object_unref); removals_pa = g_ptr_array_new_with_free_func (g_object_unref); for (guint i = 0; i < n_items; i++) { g_autoptr (BzTransaction) transaction = NULL; GListModel *installs = NULL; GListModel *updates = NULL; GListModel *removals = NULL; guint n_installs = 0; guint n_updates = 0; guint n_removals = 0; transaction = g_list_model_get_item (transactions, i); installs = bz_transaction_get_installs (transaction); updates = bz_transaction_get_updates (transaction); removals = bz_transaction_get_removals (transaction); if (installs != NULL) n_installs = g_list_model_get_n_items (installs); if (updates != NULL) n_updates = g_list_model_get_n_items (updates); if (removals != NULL) n_removals = g_list_model_get_n_items (removals); for (guint j = 0; j < n_installs; j++) g_ptr_array_add (installs_pa, g_list_model_get_item (installs, j)); for (guint j = 0; j < n_updates; j++) g_ptr_array_add (updates_pa, g_list_model_get_item (updates, j)); for (guint j = 0; j < n_removals; j++) g_ptr_array_add (removals_pa, g_list_model_get_item (removals, j)); } return bz_backend_schedule_transaction ( self, (BzEntry **) installs_pa->pdata, installs_pa->len, (BzEntry **) updates_pa->pdata, updates_pa->len, (BzEntry **) removals_pa->pdata, removals_pa->len, channel, cancellable); } gboolean bz_backend_cancel_task_for_entry (BzBackend *self, BzEntry *entry) { g_return_val_if_fail (BZ_IS_BACKEND (self), FALSE); g_return_val_if_fail (BZ_IS_ENTRY (entry), FALSE); return BZ_BACKEND_GET_IFACE (self)->cancel_task_for_entry (self, entry); } bazaar-orig-v0.7.14/src/bz-application.c0000664000175000017500000036011315166123241017013 0ustar hasanhasan/* bz-application.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::CORE" #define BAZAAR_MODULE "core" #define MAX_IDS_PER_BLOCKLIST 2048 #include "config.h" #include #include #include "bz-application-map-factory.h" #include "bz-application.h" #include "bz-auth-state.h" #include "bz-backend-notification.h" #include "bz-content-provider.h" #include "bz-donations-dialog.h" #include "bz-download-worker.h" #include "bz-entry-cache-manager.h" #include "bz-entry-group.h" #include "bz-env.h" #include "bz-error.h" #include "bz-favorites-page.h" #include "bz-flathub-state.h" #include "bz-flatpak-entry.h" #include "bz-flatpak-instance.h" #include "bz-gnome-shell-search-provider.h" #include "bz-hash-table-object.h" #include "bz-inspector.h" #include "bz-internal-config.h" #include "bz-io.h" #include "bz-login-page.h" #include "bz-malcontent-service.h" #include "bz-newline-parser.h" #include "bz-parser.h" #include "bz-preferences-dialog.h" #include "bz-result.h" #include "bz-root-blocklist.h" #include "bz-root-curated-config.h" #include "bz-serializable.h" #include "bz-state-info.h" #include "bz-transaction-manager.h" #include "bz-util.h" #include "bz-window.h" #include "bz-yaml-parser.h" #include "progress-bar-designs/common.h" struct _BzApplication { AdwApplication parent_instance; BzApplicationMapFactory *application_factory; BzApplicationMapFactory *entry_factory; BzContentProvider *blocklists_provider; BzContentProvider *curated_provider; BzContentProvider *txt_blocklists_provider; BzEntryCacheManager *cache; BzFlathubState *flathub; BzFlathubState *tmp_flathub; BzFlatpakInstance *flatpak; BzGnomeShellSearchProvider *gs_search; BzInternalConfig *internal_config; BzMainConfig *config; BzMalcontentService *malcontent; BzNewlineParser *txt_blocklist_parser; BzSearchEngine *search_engine; BzStateInfo *state; BzTransactionManager *transactions; BzYamlParser *blocklist_parser; BzYamlParser *curated_parser; DexChannel *flatpak_notifs; DexFuture *notif_watch; DexFuture *sync; DexPromise *ready_to_open_files; GHashTable *eol_runtimes; GHashTable *ids_to_groups; GHashTable *ignore_eol_set; GHashTable *installed_set; GHashTable *sys_name_to_addons; GHashTable *usr_name_to_addons; GHashTable *sys_ref_to_addon_group_ids; GHashTable *usr_ref_to_addon_group_ids; GListStore *groups; GListStore *installed_apps; GListStore *search_biases_backing; GNetworkMonitor *network; GPtrArray *blocklist_regexes; GPtrArray *txt_blocked_id_sets; GSettings *settings; GTimer *init_timer; GWeakRef main_window; GtkCustomFilter *appid_filter; GtkCustomFilter *group_filter; GtkFilterListModel *group_filter_model; GtkFlattenListModel *search_biases; GtkMapListModel *blocklists_to_files; GtkMapListModel *curated_configs_to_files; GtkMapListModel *txt_blocklists_to_files; GtkStringList *blocklists; GtkStringList *curated_configs; GtkStringList *txt_blocklists; gboolean flathub_remote_initialized; gboolean running; guint periodic_timeout_source; int n_entries_incoming; int n_remotes_syncing; }; G_DEFINE_FINAL_TYPE (BzApplication, bz_application, ADW_TYPE_APPLICATION) BZ_DEFINE_DATA ( blocklist_regex, BlocklistRegex, { int priority; GRegex *block; GRegex *allow; }, BZ_RELEASE_DATA (block, g_regex_unref); BZ_RELEASE_DATA (allow, g_regex_unref)) BZ_DEFINE_DATA ( respond_to_flatpak, RespondToFlatpak, { GWeakRef *self; BzBackendNotification *notif; }, BZ_RELEASE_DATA (self, bz_weak_release); BZ_RELEASE_DATA (notif, g_object_unref)) BZ_DEFINE_DATA ( cache_write_back, CacheWriteBack, { GWeakRef *self; GPtrArray *notify_groups; gboolean update_filters; }, BZ_RELEASE_DATA (self, bz_weak_release); BZ_RELEASE_DATA (notify_groups, g_ptr_array_unref)) BZ_DEFINE_DATA ( open_flatpakref, OpenFlatpakref, { GWeakRef *self; GFile *file; }, BZ_RELEASE_DATA (self, bz_weak_release); BZ_RELEASE_DATA (file, g_object_unref)) BZ_DEFINE_DATA ( open_appstream, OpenAppstream, { GWeakRef *self; char *id; }, BZ_RELEASE_DATA (self, g_object_unref); BZ_RELEASE_DATA (id, g_free)) static DexFuture * init_fiber (GWeakRef *wr); static DexFuture * cache_flathub_fiber (GWeakRef *wr); static DexFuture * respond_to_flatpak_fiber (RespondToFlatpakData *data); static DexFuture * open_appstream_fiber (OpenAppstreamData *data); static DexFuture * open_flatpakref_fiber (OpenFlatpakrefData *data); static DexFuture * backend_sync_finally (DexFuture *future, GWeakRef *wr); static DexFuture * init_fiber_finally (DexFuture *future, GWeakRef *wr); static DexFuture * init_sync_finally (DexFuture *future, GWeakRef *wr); static DexFuture * flathub_update_finally (DexFuture *future, GWeakRef *wr); static DexFuture * cache_write_back_finally (DexFuture *future, CacheWriteBackData *data); static DexFuture * sync_then (DexFuture *future, GWeakRef *wr); static DexFuture * watch_backend_notifs_then_loop_cb (DexFuture *future, GWeakRef *wr); static BzEntryGroup * ensure_group_and_add (BzApplication *self, const char *id, BzEntry *entry, BzEntry *eol_runtime, gboolean ignore_eol, gboolean installed); static void fiber_replace_entry (BzApplication *self, BzEntry *entry); static void fiber_check_for_updates (BzApplication *self); static GFile * fiber_dup_flathub_cache_file (char **path_out, GError **error); static gboolean periodic_timeout_cb (BzApplication *self); static gboolean scheduled_timeout_cb (GWeakRef *wr); static void network_status_changed (BzApplication *self, GParamSpec *pspec, GNetworkMonitor *network); static void disable_blocklists_changed (BzApplication *self, GParamSpec *pspec, BzStateInfo *state); static void show_hide_app_setting_changed (BzApplication *self, const char *key, GSettings *settings); static gboolean window_close_request (BzApplication *self, GtkWidget *window); static void blocklists_changed (BzApplication *self, guint position, guint removed, guint added, GListModel *model); static void txt_blocklists_changed (BzApplication *self, guint position, guint removed, guint added, GListModel *model); static void init_service_struct (BzApplication *self, GtkStringList *blocklists, GtkStringList *txt_blocklists, GtkStringList *curated_configs); static GtkWindow * new_window (BzApplication *self); static void open_appstream_take (BzApplication *self, char *appstream); static void open_flatpakref_take (BzApplication *self, GFile *file); static void command_line_open_location (BzApplication *self, GApplicationCommandLine *cmdline, const char *path); static void open_generic_id (BzApplication *self, const char *generic_id); static gpointer map_strings_to_files (GtkStringObject *string, gpointer data); static gpointer map_generic_ids_to_groups (GtkStringObject *string, BzApplication *self); static gpointer map_ids_to_entries (GtkStringObject *string, BzApplication *self); static gboolean filter_application_ids (GtkStringObject *string, BzApplication *self); static gboolean filter_entry_groups (BzEntryGroup *group, BzApplication *self); static gint cmp_group (BzEntryGroup *a, BzEntryGroup *b, gpointer user_data); static gint cmp_entry (BzEntry *a, BzEntry *b, gpointer user_data); static gboolean validate_group_for_ui (BzApplication *self, BzEntryGroup *group); static DexFuture * make_sync_future (BzApplication *self); static void finish_with_background_task_label (BzApplication *self); static void bz_application_dispose (GObject *object) { BzApplication *self = BZ_APPLICATION (object); dex_clear (&self->flatpak_notifs); dex_clear (&self->notif_watch); dex_clear (&self->ready_to_open_files); dex_clear (&self->sync); g_clear_handle_id (&self->periodic_timeout_source, g_source_remove); g_clear_object (&self->appid_filter); g_clear_object (&self->application_factory); g_clear_object (&self->blocklist_parser); g_clear_object (&self->blocklists); g_clear_object (&self->blocklists_provider); g_clear_object (&self->blocklists_to_files); g_clear_object (&self->cache); g_clear_object (&self->curated_configs); g_clear_object (&self->curated_configs_to_files); g_clear_object (&self->curated_parser); g_clear_object (&self->curated_provider); g_clear_object (&self->entry_factory); g_clear_object (&self->flathub); g_clear_object (&self->flatpak); g_clear_object (&self->group_filter); g_clear_object (&self->group_filter_model); g_clear_object (&self->groups); g_clear_object (&self->gs_search); g_clear_object (&self->installed_apps); g_clear_object (&self->malcontent); g_clear_object (&self->internal_config); g_clear_object (&self->network); g_clear_object (&self->search_biases); g_clear_object (&self->search_biases_backing); g_clear_object (&self->search_engine); g_clear_object (&self->settings); g_clear_object (&self->state); g_clear_object (&self->tmp_flathub); g_clear_object (&self->transactions); g_clear_object (&self->txt_blocklist_parser); g_clear_object (&self->txt_blocklists); g_clear_object (&self->txt_blocklists_provider); g_clear_object (&self->txt_blocklists_to_files); g_clear_pointer (&self->blocklist_regexes, g_ptr_array_unref); g_clear_pointer (&self->eol_runtimes, g_hash_table_unref); g_clear_pointer (&self->ids_to_groups, g_hash_table_unref); g_clear_pointer (&self->ignore_eol_set, g_hash_table_unref); g_clear_pointer (&self->init_timer, g_timer_destroy); g_clear_pointer (&self->installed_set, g_hash_table_unref); g_clear_pointer (&self->sys_name_to_addons, g_hash_table_unref); g_clear_pointer (&self->txt_blocked_id_sets, g_ptr_array_unref); g_clear_pointer (&self->usr_name_to_addons, g_hash_table_unref); g_clear_pointer (&self->sys_ref_to_addon_group_ids, g_hash_table_unref); g_clear_pointer (&self->usr_ref_to_addon_group_ids, g_hash_table_unref); g_weak_ref_clear (&self->main_window); G_OBJECT_CLASS (bz_application_parent_class)->dispose (object); } static void bz_application_activate (GApplication *app) { BzApplication *self = BZ_APPLICATION (app); new_window (self); } static int bz_application_command_line (GApplication *app, GApplicationCommandLine *cmdline) { BzApplication *self = BZ_APPLICATION (app); g_autoptr (GError) local_error = NULL; gint argc = 0; g_auto (GStrv) argv = NULL; gboolean help = FALSE; gboolean no_window = FALSE; g_auto (GStrv) blocklists_strv = NULL; g_auto (GStrv) content_configs_strv = NULL; g_auto (GStrv) locations = NULL; GOptionEntry main_entries[] = { { "help", 0, 0, G_OPTION_ARG_NONE, &help, "Print help" }, { "no-window", 0, 0, G_OPTION_ARG_NONE, &no_window, "Ensure the service is running without creating a new window" }, { "extra-blocklist", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &blocklists_strv, "Add an extra blocklist to read from" }, { "extra-curated-config", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &content_configs_strv, "Add an extra yaml file with which to configure the app browser" }, /* Here for backwards compat */ { "extra-content-config", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &content_configs_strv, "Add an extra yaml file with which to configure the app browser (backwards compat)" }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &locations, "flatpakref file to open" }, { NULL } }; argv = g_application_command_line_get_arguments (cmdline, &argc); g_debug ("Handling gapplication command line; argc=%d, argv= \\", argc); for (guint i = 0; i < argc; i++) { g_debug (" [%d] %s", i, argv[i]); } if (argv != NULL && argc > 0) { g_autofree GStrv argv_shallow = NULL; g_autoptr (GOptionContext) context = NULL; argv_shallow = g_memdup2 (argv, sizeof (*argv) * argc); context = g_option_context_new ("- an app center for GNOME"); g_option_context_set_help_enabled (context, FALSE); g_option_context_add_main_entries (context, main_entries, NULL); if (!g_option_context_parse (context, &argc, &argv_shallow, &local_error)) { g_application_command_line_printerr (cmdline, "%s\n", local_error->message); return EXIT_FAILURE; } if (help) { g_autofree char *help_text = NULL; if (self->running) g_application_command_line_printerr (cmdline, "The Bazaar service is running.\n\n"); else g_application_command_line_printerr (cmdline, "The Bazaar service is not running.\n\n"); help_text = g_option_context_get_help (context, TRUE, NULL); g_application_command_line_printerr (cmdline, "%s\n", help_text); return EXIT_SUCCESS; } } if (!self->running) { g_autoptr (GtkStringList) blocklists = NULL; g_autoptr (GtkStringList) txt_blocklists = NULL; g_autoptr (GtkStringList) content_configs = NULL; g_autoptr (DexFuture) init = NULL; g_debug ("Starting daemon!"); g_application_hold (G_APPLICATION (self)); self->running = TRUE; blocklists = gtk_string_list_new (NULL); txt_blocklists = gtk_string_list_new (NULL); content_configs = gtk_string_list_new (NULL); init_service_struct (self, blocklists, txt_blocklists, content_configs); #ifdef HARDCODED_BLOCKLIST g_debug ("Bazaar was configured with a hardcoded txt blocklist at %s, adding that now...", HARDCODED_BLOCKLIST); gtk_string_list_append (txt_blocklists, HARDCODED_BLOCKLIST); #endif if (blocklists_strv != NULL) gtk_string_list_splice ( txt_blocklists, g_list_model_get_n_items (G_LIST_MODEL (txt_blocklists)), 0, (const char *const *) blocklists_strv); #ifdef HARDCODED_CONTENT_CONFIG g_debug ("Bazaar was configured with a hardcoded curated content config at %s, adding that now...", HARDCODED_CONTENT_CONFIG); gtk_string_list_append (content_configs, HARDCODED_CONTENT_CONFIG); #endif if (content_configs_strv != NULL) gtk_string_list_splice ( content_configs, g_list_model_get_n_items (G_LIST_MODEL (content_configs)), 0, (const char *const *) content_configs_strv); g_timer_start (self->init_timer); init = dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) init_fiber, bz_track_weak (self), bz_weak_release); init = dex_future_finally ( init, (DexFutureCallback) init_fiber_finally, bz_track_weak (self), bz_weak_release); dex_future_disown (g_steal_pointer (&init)); } if (!no_window) new_window (self); if (locations != NULL && *locations != NULL) command_line_open_location (self, cmdline, locations[0]); return EXIT_SUCCESS; } static gboolean bz_application_local_command_line (GApplication *application, gchar ***arguments, int *exit_status) { return FALSE; } static gboolean bz_application_dbus_register (GApplication *application, GDBusConnection *connection, const gchar *object_path, GError **error) { BzApplication *self = BZ_APPLICATION (application); return bz_gnome_shell_search_provider_set_connection (self->gs_search, connection, error); } static void bz_application_dbus_unregister (GApplication *application, GDBusConnection *connection, const gchar *object_path) { BzApplication *self = BZ_APPLICATION (application); bz_gnome_shell_search_provider_set_connection (self->gs_search, NULL, NULL); } static void bz_application_class_init (BzApplicationClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GApplicationClass *app_class = G_APPLICATION_CLASS (klass); object_class->dispose = bz_application_dispose; app_class->activate = bz_application_activate; app_class->command_line = bz_application_command_line; app_class->local_command_line = bz_application_local_command_line; app_class->dbus_register = bz_application_dbus_register; app_class->dbus_unregister = bz_application_dbus_unregister; g_type_ensure (BZ_TYPE_RESULT); } static void bz_application_toggle_debug_mode_action (GSimpleAction *action, GVariant *parameter, gpointer user_data) { BzApplication *self = user_data; gboolean debug_mode = FALSE; debug_mode = bz_state_info_get_debug_mode (self->state); bz_state_info_set_debug_mode (self->state, !debug_mode); } static void bz_application_bazaar_inspector_action (GSimpleAction *action, GVariant *parameter, gpointer user_data) { BzApplication *self = user_data; BzInspector *inspector = NULL; g_assert (BZ_IS_APPLICATION (self)); inspector = bz_inspector_new (); bz_inspector_set_state (inspector, self->state); gtk_application_add_window (GTK_APPLICATION (self), GTK_WINDOW (inspector)); gtk_window_present (GTK_WINDOW (inspector)); } static void bz_application_donate_action (GSimpleAction *action, GVariant *parameter, gpointer user_data) { BzApplication *self = user_data; GtkWindow *window = NULL; AdwDialog *dialog = NULL; g_assert (BZ_IS_APPLICATION (self)); window = gtk_application_get_active_window (GTK_APPLICATION (self)); if (window == NULL) window = new_window (self); dialog = bz_donations_dialog_new (); adw_dialog_present (dialog, GTK_WIDGET (window)); bz_state_info_set_donation_prompt_dismissed (self->state, TRUE); } static void bz_application_search_action (GSimpleAction *action, GVariant *parameter, gpointer user_data) { BzApplication *self = user_data; GtkWindow *window = NULL; const char *initial_text = NULL; g_assert (BZ_IS_APPLICATION (self)); window = gtk_application_get_active_window (GTK_APPLICATION (self)); if (window == NULL) window = new_window (self); if (parameter != NULL) initial_text = g_variant_get_string (parameter, NULL); bz_window_search (BZ_WINDOW (window), initial_text); } static void bz_application_show_app_id_action (GSimpleAction *action, GVariant *parameter, gpointer user_data) { BzApplication *self = user_data; GtkWindow *window = NULL; const char *app_id = NULL; g_assert (BZ_IS_APPLICATION (self)); window = gtk_application_get_active_window (GTK_APPLICATION (self)); if (window == NULL) window = new_window (self); if (parameter != NULL) { app_id = g_variant_get_string (parameter, NULL); bz_window_show_app_id (BZ_WINDOW (window), app_id); } } static void bz_application_sync_remotes_action (GSimpleAction *action, GVariant *parameter, gpointer user_data) { BzApplication *self = user_data; g_assert (BZ_IS_APPLICATION (self)); if (self->sync != NULL && dex_future_is_pending (self->sync)) return; dex_clear (&self->sync); self->sync = make_sync_future (self); } static void bz_application_about_action (GSimpleAction *action, GVariant *parameter, gpointer user_data) { BzApplication *self = user_data; GtkWindow *window = NULL; AdwDialog *dialog = NULL; const char *developers[] = { C_ ("About Dialog Developer Credit", "Adam Masciola "), C_ ("About Dialog Developer Credit", "Alexander Vanhee"), /* This array MUST be NULL terminated */ NULL }; const char *special_thanks[] = { "arewelibadwaitayet https://arewelibadwaitayet.com/", /* This array MUST be NULL terminated */ NULL }; g_assert (BZ_IS_APPLICATION (self)); window = gtk_application_get_active_window (GTK_APPLICATION (self)); dialog = adw_about_dialog_new (); g_object_set ( dialog, "application-name", "Bazaar", "application-icon", "io.github.kolunmi.Bazaar", "developer-name", _ ("The Bazaar Contributors"), "developers", developers, // Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 "translator-credits", _ ("translator-credits"), "version", PACKAGE_VERSION, "copyright", "© 2025 Adam Masciola", "license-type", GTK_LICENSE_GPL_3_0, "website", "https://github.com/bazaar-org/bazaar", "issue-url", "https://github.com/bazaar-org/bazaar/issues", NULL); adw_about_dialog_add_acknowledgement_section ( ADW_ABOUT_DIALOG (dialog), _ ("Special Thanks"), special_thanks); adw_dialog_present (dialog, GTK_WIDGET (window)); } static void bz_application_preferences_action (GSimpleAction *action, GVariant *parameter, gpointer user_data) { BzApplication *self = user_data; GtkWindow *window = NULL; AdwDialog *preferences = NULL; g_assert (BZ_IS_APPLICATION (self)); window = gtk_application_get_active_window (GTK_APPLICATION (self)); preferences = bz_preferences_dialog_new (self->state); adw_dialog_present (preferences, GTK_WIDGET (window)); } static void bz_application_flathub_login_action (GSimpleAction *action, GVariant *parameter, gpointer user_data) { BzApplication *self = user_data; GtkWindow *window = NULL; BzAuthState *auth_state = NULL; AdwNavigationPage *login_page = NULL; g_assert (BZ_IS_APPLICATION (self)); window = gtk_application_get_active_window (GTK_APPLICATION (self)); auth_state = bz_state_info_get_auth_state (self->state); login_page = bz_login_page_new (auth_state); bz_window_push_page (BZ_WINDOW (window), login_page); } static void bz_application_flathub_logout_action (GSimpleAction *action, GVariant *parameter, gpointer user_data) { BzApplication *self = BZ_APPLICATION (user_data); GtkWindow *window = gtk_application_get_active_window (GTK_APPLICATION (self)); BzAuthState *auth_state = bz_state_info_get_auth_state (self->state); g_assert (BZ_IS_WINDOW (window)); bz_auth_state_clear (auth_state); bz_window_add_toast ( BZ_WINDOW (window), adw_toast_new (_ ("Logged Out Successfully!"))); } static void bz_application_flathub_favorites_action (GSimpleAction *action, GVariant *parameter, gpointer user_data) { BzApplication *self = user_data; GtkWindow *window = NULL; AdwNavigationPage *favorites_page = NULL; g_assert (BZ_IS_APPLICATION (self)); window = gtk_application_get_active_window (GTK_APPLICATION (self)); if (window == NULL) window = new_window (self); favorites_page = ADW_NAVIGATION_PAGE (bz_favorites_page_new (self->state)); bz_window_push_page (BZ_WINDOW (window), favorites_page); } static void bz_application_quit_action (GSimpleAction *action, GVariant *parameter, gpointer user_data) { BzApplication *self = user_data; g_assert (BZ_IS_APPLICATION (self)); g_application_quit (G_APPLICATION (self)); } static const GActionEntry app_actions[] = { { "flathub-login", bz_application_flathub_login_action, NULL }, { "flathub-logout", bz_application_flathub_logout_action, NULL }, { "flathub-favorites", bz_application_flathub_favorites_action, NULL }, { "quit", bz_application_quit_action, NULL }, { "preferences", bz_application_preferences_action, NULL }, { "about", bz_application_about_action, NULL }, { "sync-remotes", bz_application_sync_remotes_action, NULL }, { "search", bz_application_search_action, "s" }, { "show-app-id", bz_application_show_app_id_action, "s" }, { "donate", bz_application_donate_action, NULL }, { "bazaar-inspector", bz_application_bazaar_inspector_action, NULL }, { "toggle-debug-mode", bz_application_toggle_debug_mode_action, NULL }, }; static void bz_application_init (BzApplication *self) { self->running = FALSE; g_weak_ref_init (&self->main_window, NULL); self->gs_search = bz_gnome_shell_search_provider_new (); g_action_map_add_action_entries ( G_ACTION_MAP (self), app_actions, G_N_ELEMENTS (app_actions), self); gtk_application_set_accels_for_action ( GTK_APPLICATION (self), "app.quit", (const char *[]){ "q", NULL }); gtk_application_set_accels_for_action ( GTK_APPLICATION (self), "app.preferences", (const char *[]){ "comma", NULL }); gtk_application_set_accels_for_action ( GTK_APPLICATION (self), "app.sync-remotes", (const char *[]){ "r", NULL }); gtk_application_set_accels_for_action ( GTK_APPLICATION (self), "app.search('')", (const char *[]){ "f", NULL }); gtk_application_set_accels_for_action ( GTK_APPLICATION (self), "app.bazaar-inspector", (const char *[]){ "i", NULL }); gtk_application_set_accels_for_action ( GTK_APPLICATION (self), "app.toggle-debug-mode", (const char *[]){ "d", NULL }); } BzStateInfo * bz_state_info_get_default (void) { GApplication *app = NULL; BzApplication *self = NULL; app = g_application_get_default (); if G_UNLIKELY (app == NULL) return NULL; self = (BzApplication *) app; g_assert (BZ_IS_APPLICATION (self)); return self->state; } static DexFuture * init_fiber (GWeakRef *wr) { g_autoptr (BzApplication) self = NULL; g_autoptr (GError) local_error = NULL; g_autofree char *root_cache_dir = NULL; g_autoptr (GFile) root_cache_dir_file = NULL; g_autoptr (GListModel) repos = NULL; gboolean has_flathub = FALSE; gboolean result = FALSE; g_autoptr (GHashTable) cached_set = NULL; g_autofree char *flathub_cache = NULL; g_autoptr (GFile) flathub_cache_file = NULL; bz_weak_get_or_return_reject (self, wr); bz_state_info_set_online (self->state, TRUE); bz_state_info_set_busy (self->state, TRUE); bz_state_info_set_background_task_label (self->state, _ ("Performing setup…")); root_cache_dir = bz_dup_root_cache_dir (); root_cache_dir_file = g_file_new_for_path (root_cache_dir); if (dex_await (dex_file_query_exists (root_cache_dir_file), NULL)) { g_autofree char *cache_version_path = NULL; g_autoptr (GFile) cache_version_file = NULL; gboolean wipe_cache = TRUE; cache_version_path = g_build_filename (root_cache_dir, "cache-version", NULL); cache_version_file = g_file_new_for_path (cache_version_path); if (dex_await (dex_file_query_exists (cache_version_file), NULL)) { g_autoptr (GBytes) bytes = NULL; bytes = dex_await_boxed (dex_file_load_contents_bytes (cache_version_file), NULL); if (bytes != NULL) { g_autoptr (GVariant) variant = NULL; variant = g_variant_new_from_bytes (G_VARIANT_TYPE_STRING, bytes, FALSE); if (variant != NULL) { const char *version = NULL; version = g_variant_get_string (variant, NULL); wipe_cache = g_strcmp0 (version, PACKAGE_VERSION) != 0; } } } if (wipe_cache) { bz_state_info_set_donation_prompt_dismissed (self->state, FALSE); g_info ("Version incompatibility detected: clearing cache"); dex_await (bz_reap_file_dex (root_cache_dir_file), NULL); } if (dex_await (dex_file_make_directory_with_parents (root_cache_dir_file), NULL)) { g_autoptr (GVariant) variant = NULL; g_autoptr (GBytes) bytes = NULL; variant = g_variant_new_string (PACKAGE_VERSION); bytes = g_variant_get_data_as_bytes (variant); dex_await (dex_file_replace_contents_bytes ( cache_version_file, bytes, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION), NULL); } } else bz_state_info_set_donation_prompt_dismissed (self->state, TRUE); g_clear_object (&self->flatpak); self->flatpak = dex_await_object (bz_flatpak_instance_new (), &local_error); if (self->flatpak == NULL) return dex_future_new_for_error (g_steal_pointer (&local_error)); bz_transaction_manager_set_backend (self->transactions, BZ_BACKEND (self->flatpak)); bz_state_info_set_backend (self->state, BZ_BACKEND (self->flatpak)); has_flathub = dex_await_boolean ( bz_flatpak_instance_has_flathub (self->flatpak, NULL), &local_error); if (local_error != NULL) return dex_future_new_for_error (g_steal_pointer (&local_error)); if (!has_flathub) { GtkWindow *window = NULL; g_autofree char *response = NULL; window = gtk_application_get_active_window (GTK_APPLICATION (self)); if (window != NULL) { AdwDialog *alert = NULL; alert = adw_alert_dialog_new (NULL, NULL); #ifdef SANDBOXED_LIBFLATPAK adw_alert_dialog_format_heading ( ADW_ALERT_DIALOG (alert), _ ("Set Up System Flathub?")); adw_alert_dialog_format_body ( ADW_ALERT_DIALOG (alert), _ ("The system Flathub remote is not set up. Bazaar requires " "Flathub to be configured on the system Flatpak installation " "to browse and install applications.\n\n" "You can still use Bazaar to browse and remove already installed apps.")); #else adw_alert_dialog_format_heading ( ADW_ALERT_DIALOG (alert), _ ("Set Up Flathub?")); adw_alert_dialog_format_body ( ADW_ALERT_DIALOG (alert), _ ("Flathub is not set up on this system. " "You will not be able to browse and install applications in Bazaar if its unavailable.\n\n" "You can still use Bazaar to browse and remove already installed apps.")); #endif adw_alert_dialog_add_responses ( ADW_ALERT_DIALOG (alert), "later", _ ("Later"), "add", _ ("Set Up Flathub"), NULL); adw_alert_dialog_set_response_appearance ( ADW_ALERT_DIALOG (alert), "add", ADW_RESPONSE_SUGGESTED); adw_alert_dialog_set_default_response (ADW_ALERT_DIALOG (alert), "add"); adw_alert_dialog_set_close_response (ADW_ALERT_DIALOG (alert), "later"); adw_dialog_present (alert, GTK_WIDGET (window)); response = dex_await_string ( bz_make_alert_dialog_future (ADW_ALERT_DIALOG (alert)), NULL); } if (response != NULL && g_strcmp0 (response, "add") == 0) { result = dex_await ( bz_flatpak_instance_ensure_has_flathub (self->flatpak, NULL), &local_error); if (result) has_flathub = TRUE; else { g_warning ("Failed to install flathub: %s", local_error->message); g_clear_error (&local_error); } } } bz_state_info_set_has_flathub (self->state, has_flathub); self->installed_set = dex_await_boxed ( bz_backend_retrieve_install_ids ( BZ_BACKEND (self->flatpak), NULL), &local_error); if (self->installed_set == NULL) { g_warning ("Unable to enumerate installed entries from flatpak backend; " "no entries will appear to be installed: %s", local_error->message); g_clear_error (&local_error); self->installed_set = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, g_free); } repos = dex_await_object ( bz_backend_list_repositories (BZ_BACKEND (self->flatpak), NULL), &local_error); if (repos != NULL) bz_state_info_set_repositories (self->state, repos); else { g_warning ("Failed to enumerate repositories: %s", local_error->message); g_clear_error (&local_error); } /* Revive old cache from previous Bazaar process */ cached_set = dex_await_boxed ( bz_entry_cache_manager_enumerate_disk (self->cache), &local_error); if (cached_set != NULL) { g_autoptr (GPtrArray) futures = NULL; GHashTableIter iter = { 0 }; g_autoptr (GPtrArray) entries = NULL; futures = g_ptr_array_new_with_free_func (dex_unref); g_hash_table_iter_init (&iter, cached_set); for (;;) { char *checksum = NULL; if (!g_hash_table_iter_next ( &iter, (gpointer *) &checksum, NULL)) break; g_ptr_array_add ( futures, bz_entry_cache_manager_get_by_checksum ( self->cache, checksum)); } g_clear_pointer (&cached_set, g_hash_table_unref); if (futures->len > 0) dex_await (dex_future_allv ( (DexFuture *const *) futures->pdata, futures->len), NULL); entries = g_ptr_array_new_with_free_func (g_object_unref); for (guint i = 0; i < futures->len; i++) { DexFuture *future = NULL; const GValue *value = NULL; future = g_ptr_array_index (futures, i); value = dex_future_get_value (future, &local_error); if (value != NULL) g_ptr_array_add (entries, g_value_dup_object (value)); else { g_warning ("Unable to retrieve cached entry: %s", local_error->message); g_clear_error (&local_error); } } g_ptr_array_sort_values_with_data ( entries, (GCompareDataFunc) cmp_entry, NULL); for (guint i = 0; i < entries->len; i++) { BzEntry *entry = NULL; entry = g_ptr_array_index (entries, i); fiber_replace_entry (self, entry); } gtk_filter_changed (GTK_FILTER (self->group_filter), GTK_FILTER_CHANGE_LESS_STRICT); gtk_filter_changed (GTK_FILTER (self->appid_filter), GTK_FILTER_CHANGE_LESS_STRICT); } else { g_warning ("Unable to enumerate cached entries: %s", local_error->message); g_clear_error (&local_error); } flathub_cache_file = fiber_dup_flathub_cache_file (&flathub_cache, &local_error); if (flathub_cache_file != NULL) { if (dex_await (dex_file_query_exists (flathub_cache_file), NULL)) { g_autoptr (GBytes) bytes = NULL; bytes = dex_await_boxed ( dex_file_load_contents_bytes (flathub_cache_file), &local_error); if (bytes != NULL) { g_autoptr (GVariant) variant = NULL; g_autoptr (BzFlathubState) flathub = NULL; variant = g_variant_new_from_bytes (G_VARIANT_TYPE_VARDICT, bytes, FALSE); if (variant == NULL) { g_warning ("Failed to interpret cached flathub state from %s: %s", flathub_cache, local_error->message); g_clear_error (&local_error); } flathub = bz_flathub_state_new (); result = bz_serializable_deserialize ( BZ_SERIALIZABLE (flathub), variant, &local_error); if (result) { self->flathub = g_steal_pointer (&flathub); bz_flathub_state_set_map_factory (self->flathub, self->application_factory); bz_state_info_set_flathub (self->state, self->flathub); bz_state_info_set_busy (self->state, FALSE); dex_promise_resolve_boolean (self->ready_to_open_files, TRUE); } else { g_warning ("Failed to deserialize cached flathub state from %s: %s", flathub_cache, local_error->message); g_clear_error (&local_error); } } else { g_warning ("Failed to decache cache flathub state from %s: %s", flathub_cache, local_error->message); g_clear_error (&local_error); } } } else { g_warning ("Unable to ensure cache directory: %s", local_error->message); g_clear_error (&local_error); } return dex_future_new_true (); } static DexFuture * cache_flathub_fiber (GWeakRef *wr) { g_autoptr (BzApplication) self = NULL; g_autoptr (GError) local_error = NULL; gboolean result = FALSE; g_autofree char *flathub_cache = NULL; g_autoptr (GFile) flathub_cache_file = NULL; bz_weak_get_or_return_reject (self, wr); flathub_cache_file = fiber_dup_flathub_cache_file (&flathub_cache, &local_error); if (flathub_cache_file != NULL) { g_autoptr (GVariantBuilder) builder = NULL; g_autoptr (GVariant) variant = NULL; g_autoptr (GBytes) bytes = NULL; builder = g_variant_builder_new (G_VARIANT_TYPE_VARDICT); bz_serializable_serialize (BZ_SERIALIZABLE (self->flathub), builder); variant = g_variant_builder_end (builder); bytes = g_variant_get_data_as_bytes (variant); result = dex_await ( dex_file_replace_contents_bytes ( flathub_cache_file, bytes, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION), &local_error); if (!result) { g_warning ("Failed to cache flathub state to %s: %s", flathub_cache, local_error->message); g_clear_error (&local_error); } } else { g_warning ("Unable to ensure cache directory: %s", local_error->message); g_clear_error (&local_error); } return dex_future_new_true (); } static DexFuture * respond_to_flatpak_fiber (RespondToFlatpakData *data) { g_autoptr (BzApplication) self = NULL; BzBackendNotification *notif = data->notif; g_autoptr (GError) local_error = NULL; g_autoptr (GPtrArray) build_futures = NULL; g_autoptr (GPtrArray) build_notify_groups = NULL; g_autoptr (DexFuture) read_future = NULL; g_autoptr (DexFuture) reread_timeout = NULL; gboolean update_labels = FALSE; gboolean update_filters = FALSE; bz_weak_get_or_return_reject (self, data->self); build_futures = g_ptr_array_new_with_free_func (dex_unref); build_notify_groups = g_ptr_array_new_with_free_func (g_object_unref); read_future = dex_future_new_for_object (notif); /* `reread_timeout` defines how long we are allowed to spend adding to `build-futures` before we update the UI later */ reread_timeout = dex_timeout_new_msec (100); for (;;) { BzBackendNotificationKind kind = 0; if (!dex_future_is_resolved (read_future)) { g_autoptr (DexFuture) future = NULL; future = dex_future_all_race ( dex_ref (reread_timeout), dex_ref (read_future), NULL); dex_await (g_steal_pointer (&future), NULL); if (!dex_future_is_pending (reread_timeout)) break; } notif = g_value_get_object (dex_future_get_value (read_future, NULL)); kind = bz_backend_notification_get_kind (notif); switch (kind) { case BZ_BACKEND_NOTIFICATION_KIND_ERROR: { const char *error = NULL; GtkWindow *window = NULL; error = bz_backend_notification_get_error (notif); if (error == NULL) break; g_warning ("Received an error from the flatpak backend: %s", error); window = gtk_application_get_active_window (GTK_APPLICATION (self)); if (window != NULL) bz_show_error_for_widget (GTK_WIDGET (window), _ ("A backend error occurred"), error); } break; case BZ_BACKEND_NOTIFICATION_KIND_TELL_INCOMING: { int n_incoming = 0; n_incoming = bz_backend_notification_get_n_incoming (notif); self->n_entries_incoming += n_incoming; update_labels = TRUE; } break; case BZ_BACKEND_NOTIFICATION_KIND_REPLACE_ENTRY: { BzEntry *entry = NULL; entry = bz_backend_notification_get_entry (notif); fiber_replace_entry (self, entry); g_ptr_array_add (build_futures, bz_entry_cache_manager_add (self->cache, entry)); if (bz_entry_is_of_kinds (entry, BZ_ENTRY_KIND_APPLICATION)) { const char *id = NULL; BzEntryGroup *group = NULL; update_filters = TRUE; id = bz_entry_get_id (entry); group = g_hash_table_lookup (self->ids_to_groups, id); if (group != NULL) g_ptr_array_add (build_notify_groups, g_object_ref (group)); } self->n_entries_incoming--; update_labels = TRUE; } break; case BZ_BACKEND_NOTIFICATION_KIND_REMOTE_SYNC_START: { const char *remote_name = NULL; remote_name = bz_backend_notification_get_remote_name (notif); if (bz_state_info_get_has_flathub (self->state)) /* We only count instances of the "flathub" remote if we have flathub, since that's all we care about for the UI */ { if (g_strcmp0 (remote_name, "flathub") == 0) self->n_remotes_syncing++; } else self->n_remotes_syncing++; g_debug ("remote '%s' has begun synchronization; " "now currently syncing %u remote(s)", remote_name, self->n_remotes_syncing); } break; case BZ_BACKEND_NOTIFICATION_KIND_REMOTE_SYNC_FINISH: { const char *remote_name = NULL; remote_name = bz_backend_notification_get_remote_name (notif); if (bz_state_info_get_has_flathub (self->state)) { if (g_strcmp0 (remote_name, "flathub") == 0) { self->n_remotes_syncing--; if (self->n_remotes_syncing == 0) self->flathub_remote_initialized = TRUE; } } else { self->n_remotes_syncing--; if (self->n_remotes_syncing == 0) bz_state_info_set_busy (self->state, FALSE); } g_debug ("remote '%s' has finished synchronization; " "now currently syncing %u remote(s)", remote_name, self->n_remotes_syncing); } break; case BZ_BACKEND_NOTIFICATION_KIND_INSTALL_DONE: case BZ_BACKEND_NOTIFICATION_KIND_UPDATE_DONE: case BZ_BACKEND_NOTIFICATION_KIND_REMOVE_DONE: { const char *unique_id = NULL; g_autoptr (BzEntry) entry = NULL; unique_id = bz_backend_notification_get_unique_id (notif); entry = dex_await_object ( bz_entry_cache_manager_get (self->cache, unique_id), &local_error); if (entry == NULL) { g_warning ("Backend notification references an entry " "which couldn't be decached: %s", local_error->message); break; } switch (kind) { case BZ_BACKEND_NOTIFICATION_KIND_INSTALL_DONE: { const char *version = NULL; version = bz_backend_notification_get_version (notif); g_hash_table_replace (self->installed_set, g_strdup (unique_id), g_strdup (version)); bz_entry_set_installed_version (entry, version); bz_entry_set_installed (entry, TRUE); if (bz_entry_is_of_kinds (entry, BZ_ENTRY_KIND_APPLICATION)) { BzEntryGroup *group = NULL; group = g_hash_table_lookup (self->ids_to_groups, bz_entry_get_id (entry)); if (group != NULL) { gboolean found = FALSE; guint position = 0; found = g_list_store_find (self->installed_apps, group, &position); if (!found) g_list_store_insert_sorted (self->installed_apps, group, (GCompareDataFunc) cmp_group, NULL); } } } break; case BZ_BACKEND_NOTIFICATION_KIND_UPDATE_DONE: { const char *version = NULL; version = bz_backend_notification_get_version (notif); g_hash_table_replace (self->installed_set, g_strdup (unique_id), g_strdup (version)); } break; case BZ_BACKEND_NOTIFICATION_KIND_REMOVE_DONE: { bz_entry_set_installed_version (entry, NULL); bz_entry_set_installed (entry, FALSE); g_hash_table_remove (self->installed_set, unique_id); if (bz_entry_is_of_kinds (entry, BZ_ENTRY_KIND_APPLICATION)) { BzEntryGroup *group = NULL; group = g_hash_table_lookup (self->ids_to_groups, bz_entry_get_id (entry)); if (group != NULL && !bz_entry_group_get_removable (group)) { gboolean found = FALSE; guint position = 0; found = g_list_store_find (self->installed_apps, group, &position); if (found) g_list_store_remove (self->installed_apps, position); } } } break; case BZ_BACKEND_NOTIFICATION_KIND_ERROR: case BZ_BACKEND_NOTIFICATION_KIND_TELL_INCOMING: case BZ_BACKEND_NOTIFICATION_KIND_REPLACE_ENTRY: case BZ_BACKEND_NOTIFICATION_KIND_REMOTE_SYNC_START: case BZ_BACKEND_NOTIFICATION_KIND_REMOTE_SYNC_FINISH: case BZ_BACKEND_NOTIFICATION_KIND_EXTERNAL_CHANGE: default: g_assert_not_reached (); }; g_ptr_array_add (build_futures, bz_entry_cache_manager_add (self->cache, entry)); if (bz_entry_is_of_kinds (entry, BZ_ENTRY_KIND_APPLICATION)) { const char *id = NULL; BzEntryGroup *group = NULL; id = bz_entry_get_id (entry); group = g_hash_table_lookup (self->ids_to_groups, id); if (group != NULL) g_ptr_array_add (build_notify_groups, g_object_ref (group)); } } break; case BZ_BACKEND_NOTIFICATION_KIND_EXTERNAL_CHANGE: { g_autoptr (GHashTable) installed_set = NULL; g_autoptr (GPtrArray) diff_reads = NULL; GHashTableIter old_iter = { 0 }; GHashTableIter new_iter = { 0 }; g_autoptr (GPtrArray) diff_writes = NULL; bz_state_info_set_background_task_label (self->state, _ ("Refreshing…")); installed_set = dex_await_boxed ( bz_backend_retrieve_install_ids ( BZ_BACKEND (self->flatpak), NULL), &local_error); if (installed_set == NULL) { g_warning ("Failed to enumerate installed entries: %s", local_error->message); finish_with_background_task_label (self); break; } diff_reads = g_ptr_array_new_with_free_func (dex_unref); g_hash_table_iter_init (&old_iter, self->installed_set); for (;;) { char *unique_id = NULL; if (!g_hash_table_iter_next ( &old_iter, (gpointer *) &unique_id, NULL)) break; if (!g_hash_table_contains (installed_set, unique_id)) g_ptr_array_add ( diff_reads, bz_entry_cache_manager_get (self->cache, unique_id)); } g_hash_table_iter_init (&new_iter, installed_set); for (;;) { char *unique_id = NULL; if (!g_hash_table_iter_next ( &new_iter, (gpointer *) &unique_id, NULL)) break; if (!g_hash_table_contains (self->installed_set, unique_id)) g_ptr_array_add ( diff_reads, bz_entry_cache_manager_get (self->cache, unique_id)); } if (diff_reads->len > 0) { dex_await (dex_future_allv ( (DexFuture *const *) diff_reads->pdata, diff_reads->len), NULL); diff_writes = g_ptr_array_new_with_free_func (dex_unref); for (guint i = 0; i < diff_reads->len; i++) { DexFuture *future = NULL; future = g_ptr_array_index (diff_reads, i); if (dex_future_is_resolved (future)) { BzEntry *entry = NULL; const char *id = NULL; const char *unique_id = NULL; BzEntryGroup *group = NULL; gboolean installed = FALSE; const char *version = NULL; entry = g_value_get_object (dex_future_get_value (future, NULL)); id = bz_entry_get_id (entry); group = g_hash_table_lookup (self->ids_to_groups, id); if (group != NULL) bz_entry_group_connect_living (group, entry); unique_id = bz_entry_get_unique_id (entry); installed = g_hash_table_contains (installed_set, unique_id); version = g_hash_table_lookup (installed_set, unique_id); if (installed && version != NULL && *version != '\0') bz_entry_set_installed_version (entry, version); bz_entry_set_installed (entry, installed); if (group != NULL) { gboolean found = FALSE; guint position = 0; found = g_list_store_find (self->installed_apps, group, &position); if (installed && !found) g_list_store_insert_sorted ( self->installed_apps, group, (GCompareDataFunc) cmp_group, NULL); else if (!installed && found && bz_entry_group_get_removable (group) == 0) g_list_store_remove (self->installed_apps, position); } g_ptr_array_add ( diff_writes, bz_entry_cache_manager_add (self->cache, entry)); } } dex_await (dex_future_allv ( (DexFuture *const *) diff_writes->pdata, diff_writes->len), NULL); } g_clear_pointer (&self->installed_set, g_hash_table_unref); self->installed_set = g_steal_pointer (&installed_set); fiber_check_for_updates (self); finish_with_background_task_label (self); } break; default: g_assert_not_reached (); } dex_clear (&read_future); read_future = dex_channel_receive (self->flatpak_notifs); if (!dex_future_is_pending (reread_timeout)) break; } if (build_futures->len > 0) { g_autoptr (DexFuture) future = NULL; g_autoptr (CacheWriteBackData) write_back_data = NULL; future = dex_future_allv ( (DexFuture *const *) build_futures->pdata, build_futures->len); write_back_data = cache_write_back_data_new (); write_back_data->self = bz_track_weak (self); write_back_data->notify_groups = g_ptr_array_ref (build_notify_groups); write_back_data->update_filters = update_filters; future = dex_future_finally ( future, (DexFutureCallback) cache_write_back_finally, cache_write_back_data_ref (write_back_data), cache_write_back_data_unref); dex_future_disown (g_steal_pointer (&future)); } if (update_labels) { if (self->n_entries_incoming > 0) bz_state_info_set_background_task_label_take_printf ( self->state, _ ("Loading %d apps…"), self->n_entries_incoming); else { bz_state_info_set_background_task_label (self->state, _ ("Checking for updates…")); fiber_check_for_updates (self); finish_with_background_task_label (self); } } if (self->n_entries_incoming == 0 && self->flathub_remote_initialized) { bz_state_info_set_busy (self->state, FALSE); finish_with_background_task_label (self); } return g_steal_pointer (&read_future); } static DexFuture * open_appstream_fiber (OpenAppstreamData *data) { g_autoptr (BzApplication) self = NULL; char *id = data->id; bz_weak_get_or_return_reject (self, data->self); dex_await (dex_ref (self->ready_to_open_files), NULL); open_generic_id (self, id); return dex_future_new_true (); } static DexFuture * open_flatpakref_fiber (OpenFlatpakrefData *data) { g_autoptr (BzApplication) self = NULL; GFile *file = data->file; g_autoptr (GError) local_error = NULL; g_autoptr (DexFuture) future = NULL; GtkWindow *window = NULL; const GValue *value = NULL; bz_weak_get_or_return_reject (self, data->self); dex_await (dex_ref (self->ready_to_open_files), NULL); future = bz_backend_load_local_package (BZ_BACKEND (self->flatpak), file, NULL); dex_await (dex_ref (future), NULL); window = gtk_application_get_active_window (GTK_APPLICATION (self)); if (window == NULL) window = new_window (self); value = dex_future_get_value (future, &local_error); if (value != NULL) { if (G_VALUE_HOLDS_OBJECT (value)) { BzEntry *entry = NULL; entry = g_value_get_object (value); bz_window_show_entry (BZ_WINDOW (window), entry); } else open_generic_id (self, g_value_get_string (value)); } else bz_show_error_for_widget (GTK_WIDGET (window), _ ("Failed to open .flatpakref"), local_error->message); return dex_future_new_true (); } static DexFuture * init_fiber_finally (DexFuture *future, GWeakRef *wr) { g_autoptr (BzApplication) self = NULL; g_autoptr (GError) local_error = NULL; const GValue *value = NULL; bz_weak_get_or_return_reject (self, wr); value = dex_future_get_value (future, &local_error); if (value != NULL) { g_autoptr (DexFuture) sync_future = NULL; self->flatpak_notifs = bz_backend_create_notification_channel ( BZ_BACKEND (self->flatpak)); self->notif_watch = dex_future_then_loop ( dex_channel_receive (self->flatpak_notifs), (DexFutureCallback) watch_backend_notifs_then_loop_cb, bz_track_weak (self), bz_weak_release); sync_future = make_sync_future (self); sync_future = dex_future_finally ( sync_future, (DexFutureCallback) init_sync_finally, bz_track_weak (self), bz_weak_release); self->sync = g_steal_pointer (&sync_future); self->periodic_timeout_source = g_timeout_add_seconds ( /* Check every day */ 60 * 60 * 24, (GSourceFunc) periodic_timeout_cb, self); bz_malcontent_service_start (self->malcontent); } else { GtkWindow *window = NULL; bz_state_info_set_online (self->state, FALSE); bz_state_info_set_busy (self->state, FALSE); window = gtk_application_get_active_window (GTK_APPLICATION (self)); if (window != NULL) { g_autofree char *error_string = NULL; error_string = g_strdup_printf ( "Could not initialize: %s", local_error->message); bz_show_error_for_widget (GTK_WIDGET (window), _ ("An initialization error occurred"), error_string); } } return dex_future_new_true (); } static DexFuture * init_sync_finally (DexFuture *future, GWeakRef *wr) { g_autoptr (BzApplication) self = NULL; g_autoptr (GError) local_error = NULL; bz_weak_get_or_return_reject (self, wr); /* Do nothing */ return dex_future_new_true (); } static DexFuture * backend_sync_finally (DexFuture *future, GWeakRef *wr) { g_autoptr (BzApplication) self = NULL; bz_weak_get_or_return_reject (self, wr); bz_state_info_set_online (self->state, dex_future_is_resolved (future)); bz_state_info_set_syncing (self->state, FALSE); bz_state_info_set_allow_manual_sync (self->state, TRUE); return dex_future_new_true (); } static DexFuture * flathub_update_finally (DexFuture *future, GWeakRef *wr) { g_autoptr (BzApplication) self = NULL; bz_weak_get_or_return_reject (self, wr); if (dex_future_is_resolved (future)) { g_clear_object (&self->flathub); g_assert (self->tmp_flathub != NULL); self->flathub = g_steal_pointer (&self->tmp_flathub); bz_flathub_state_set_map_factory (self->flathub, self->application_factory); bz_state_info_set_flathub (self->state, self->flathub); return dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) cache_flathub_fiber, bz_track_weak (self), bz_weak_release); } else { g_clear_object (&self->tmp_flathub); return dex_ref (future); } } static DexFuture * cache_write_back_finally (DexFuture *future, CacheWriteBackData *data) { g_autoptr (BzApplication) self = NULL; GPtrArray *notify_groups = data->notify_groups; gboolean update_filters = data->update_filters; bz_weak_get_or_return_reject (self, data->self); for (guint i = 0; i < notify_groups->len; i++) { BzEntryGroup *group = NULL; group = g_ptr_array_index (notify_groups, i); g_object_notify (G_OBJECT (group), "ui-entry"); } if (update_filters) { gtk_filter_changed (GTK_FILTER (self->group_filter), GTK_FILTER_CHANGE_LESS_STRICT); gtk_filter_changed (GTK_FILTER (self->appid_filter), GTK_FILTER_CHANGE_LESS_STRICT); } return dex_future_new_true (); } static DexFuture * sync_then (DexFuture *future, GWeakRef *wr) { g_autoptr (BzApplication) self = NULL; bz_weak_get_or_return_reject (self, wr); dex_promise_resolve_boolean (self->ready_to_open_files, TRUE); return dex_future_new_true (); } static DexFuture * watch_backend_notifs_then_loop_cb (DexFuture *future, GWeakRef *wr) { g_autoptr (BzApplication) self = NULL; g_autoptr (GError) local_error = NULL; const GValue *value = NULL; BzBackendNotification *notif = NULL; g_autoptr (RespondToFlatpakData) data = NULL; g_autoptr (DexFuture) ret_future = NULL; bz_weak_get_or_return_reject (self, wr); value = dex_future_get_value (future, NULL); g_assert (value != NULL); notif = g_value_get_object (value); data = respond_to_flatpak_data_new (); data->self = bz_track_weak (self); data->notif = g_object_ref (notif); ret_future = dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) respond_to_flatpak_fiber, respond_to_flatpak_data_ref (data), respond_to_flatpak_data_unref); return g_steal_pointer (&ret_future); } static BzEntryGroup * ensure_group_and_add (BzApplication *self, const char *id, BzEntry *entry, BzEntry *eol_runtime, gboolean ignore_eol, gboolean installed) { BzEntryGroup *group = NULL; group = g_hash_table_lookup (self->ids_to_groups, id); if (group != NULL) { bz_entry_group_add (group, entry, eol_runtime, ignore_eol); } else { g_autoptr (BzEntryGroup) new_group = NULL; g_debug ("Creating new application group for id %s", id); new_group = bz_entry_group_new (self->entry_factory); bz_entry_group_add (new_group, entry, eol_runtime, ignore_eol); g_list_store_append (self->groups, new_group); g_hash_table_replace (self->ids_to_groups, g_strdup (id), g_object_ref (new_group)); group = new_group; } if (installed && !g_list_store_find (self->installed_apps, group, NULL)) g_list_store_insert_sorted ( self->installed_apps, group, (GCompareDataFunc) cmp_group, NULL); return group; } static void fiber_replace_entry (BzApplication *self, BzEntry *entry) { const char *id = NULL; const char *unique_id = NULL; const char *unique_id_checksum = NULL; gboolean user = FALSE; gboolean installed = FALSE; const char *flatpak_id = NULL; const char *version = NULL; GHashTable *name_to_addons = NULL; id = bz_entry_get_id (entry); unique_id = bz_entry_get_unique_id (entry); unique_id_checksum = bz_entry_get_unique_id_checksum (entry); if (id == NULL || unique_id == NULL || unique_id_checksum == NULL) return; user = bz_flatpak_entry_is_user (BZ_FLATPAK_ENTRY (entry)); name_to_addons = user ? self->usr_name_to_addons : self->sys_name_to_addons; installed = g_hash_table_contains (self->installed_set, unique_id); bz_entry_set_installed (entry, installed); version = g_hash_table_lookup (self->installed_set, unique_id); if (version != NULL && *version != '\0') bz_entry_set_installed_version (entry, version); flatpak_id = bz_flatpak_entry_get_flatpak_id (BZ_FLATPAK_ENTRY (entry)); if (flatpak_id != NULL) { GPtrArray *addons = NULL; addons = g_hash_table_lookup (name_to_addons, flatpak_id); if (addons != NULL) { g_debug ("Appending %d addons to %s", addons->len, unique_id); for (guint i = 0; i < addons->len; i++) { const char *addon_id = NULL; addon_id = g_ptr_array_index (addons, i); bz_entry_append_addon (entry, addon_id); } g_hash_table_remove (name_to_addons, flatpak_id); addons = NULL; } } if (bz_entry_is_of_kinds (entry, BZ_ENTRY_KIND_APPLICATION)) { gboolean ignore_eol = FALSE; const char *runtime_name = NULL; BzEntry *eol_runtime = NULL; BzEntryGroup *group = NULL; GHashTable *ref_to_addon_group_ids = NULL; GPtrArray *pending = NULL; if (self->ignore_eol_set != NULL) ignore_eol = g_hash_table_contains (self->ignore_eol_set, id); runtime_name = bz_flatpak_entry_get_application_runtime (BZ_FLATPAK_ENTRY (entry)); if (!ignore_eol && runtime_name != NULL) eol_runtime = g_hash_table_lookup (self->eol_runtimes, runtime_name); group = ensure_group_and_add (self, id, entry, eol_runtime, ignore_eol, installed); ref_to_addon_group_ids = user ? self->usr_ref_to_addon_group_ids : self->sys_ref_to_addon_group_ids; pending = g_hash_table_lookup (ref_to_addon_group_ids, id); if (pending != NULL) { for (guint i = 0; i < pending->len; i++) bz_entry_group_append_addon_group_id (group, g_ptr_array_index (pending, i)); g_hash_table_remove (ref_to_addon_group_ids, id); } } if (flatpak_id != NULL && bz_entry_is_of_kinds (entry, BZ_ENTRY_KIND_RUNTIME) && g_str_has_prefix (flatpak_id, "runtime/")) { const char *stripped = NULL; const char *eol = NULL; stripped = flatpak_id + strlen ("runtime/"); eol = bz_entry_get_eol (entry); if (eol != NULL) g_hash_table_replace ( self->eol_runtimes, g_strdup (stripped), g_object_ref (entry)); else g_hash_table_remove (self->eol_runtimes, stripped); } if (bz_entry_is_of_kinds (entry, BZ_ENTRY_KIND_ADDON) && strstr (id, ".Debug") == NULL && strstr (id, ".Locale") == NULL) { const char *extension_of_what = NULL; extension_of_what = bz_flatpak_entry_get_addon_extension_of_ref ( BZ_FLATPAK_ENTRY (entry)); if (extension_of_what != NULL && g_str_has_prefix (extension_of_what, "app/")) { g_auto (GStrv) parts = NULL; BzEntryGroup *app_group = NULL; ensure_group_and_add (self, id, entry, NULL, FALSE, installed); parts = g_strsplit (extension_of_what, "/", -1); if (parts != NULL && parts[1] != NULL) { app_group = g_hash_table_lookup (self->ids_to_groups, parts[1]); if (app_group != NULL) bz_entry_group_append_addon_group_id (app_group, id); else { GHashTable *ref_to_addon_group_ids = user ? self->usr_ref_to_addon_group_ids : self->sys_ref_to_addon_group_ids; GPtrArray *pending = NULL; pending = g_hash_table_lookup (ref_to_addon_group_ids, parts[1]); if (pending == NULL) { pending = g_ptr_array_new_with_free_func (g_free); g_hash_table_replace (ref_to_addon_group_ids, g_strdup (parts[1]), pending); } g_ptr_array_add (pending, g_strdup (id)); } } } if (extension_of_what != NULL) { GPtrArray *addons = NULL; /* BzFlatpakInstance ensures addons come before applications */ addons = g_hash_table_lookup (name_to_addons, extension_of_what); if (addons == NULL) { addons = g_ptr_array_new_with_free_func (g_free); g_hash_table_replace ( name_to_addons, g_strdup (extension_of_what), addons); } g_ptr_array_add (addons, g_strdup (unique_id)); } else g_warning ("Entry with unique id %s is an addon but " "does not seem to extend anything", unique_id); } } static void fiber_check_for_updates (BzApplication *self) { g_autoptr (GError) local_error = NULL; g_autoptr (GPtrArray) update_ids = NULL; GtkWindow *window = NULL; g_debug ("Checking for updates..."); bz_state_info_set_checking_for_updates (self->state, TRUE); update_ids = dex_await_boxed ( bz_backend_retrieve_update_ids (BZ_BACKEND (self->flatpak), NULL), &local_error); window = gtk_application_get_active_window (GTK_APPLICATION (self)); if (update_ids != NULL && update_ids->len > 0) { g_autoptr (GPtrArray) futures = NULL; g_autoptr (GListStore) store = NULL; futures = g_ptr_array_new_with_free_func (dex_unref); for (guint i = 0; i < update_ids->len; i++) { const char *unique_id = NULL; unique_id = g_ptr_array_index (update_ids, i); g_ptr_array_add (futures, bz_entry_cache_manager_get (self->cache, unique_id)); } dex_await ( dex_future_allv ((DexFuture *const *) futures->pdata, futures->len), NULL); store = g_list_store_new (BZ_TYPE_ENTRY); for (guint i = 0; i < futures->len; i++) { DexFuture *future = NULL; const GValue *value = NULL; future = g_ptr_array_index (futures, i); value = dex_future_get_value (future, &local_error); if (value != NULL) g_list_store_append (store, g_value_get_object (value)); else { const char *unique_id = NULL; unique_id = g_ptr_array_index (update_ids, i); g_warning ("%s could not be resolved for the update list and thus will not be included: %s", unique_id, local_error->message); g_clear_pointer (&local_error, g_error_free); } } if (g_list_model_get_n_items (G_LIST_MODEL (store)) > 0) bz_state_info_set_available_updates (self->state, G_LIST_MODEL (store)); } else if (local_error != NULL) { g_warning ("Failed to check for updates: %s", local_error->message); if (window != NULL) bz_show_error_for_widget (GTK_WIDGET (window), _ ("Failed to check for updates"), local_error->message); } bz_state_info_set_checking_for_updates (self->state, FALSE); } static GFile * fiber_dup_flathub_cache_file (char **path_out, GError **error) { gboolean result = FALSE; g_autofree char *module_dir = NULL; g_autoptr (GFile) module_dir_file = NULL; g_autofree char *path = NULL; g_autoptr (GFile) file = NULL; module_dir = bz_dup_module_dir (); module_dir_file = g_file_new_for_path (module_dir); result = dex_await ( dex_file_make_directory_with_parents ( module_dir_file), error); if (!result) return NULL; path = g_build_filename (module_dir, "flathub-cache", NULL); file = g_file_new_for_path (path); if (path_out != NULL) *path_out = g_steal_pointer (&path); return g_steal_pointer (&file); } static gboolean periodic_timeout_cb (BzApplication *self) { gboolean have_connection = FALSE; gboolean metered_connection = FALSE; if (self->sync != NULL && dex_future_is_pending (self->sync)) /* If for some reason the last update check is still happening, let it finish */ goto done; dex_clear (&self->sync); have_connection = bz_state_info_get_have_connection (self->state); metered_connection = bz_state_info_get_metered_connection (self->state); if (have_connection && !metered_connection) /* Do not do periodic sync on metered connections. The user will have to manually refresh instead. */ self->sync = make_sync_future (self); done: return G_SOURCE_CONTINUE; } static gboolean scheduled_timeout_cb (GWeakRef *wr) { g_autoptr (BzApplication) self = NULL; gboolean have_connection = FALSE; /* Use weak ref here since the source tag of this callback won't be tracked by the main application obj */ self = g_weak_ref_get (wr); if (self == NULL) goto done; dex_clear (&self->sync); have_connection = bz_state_info_get_have_connection (self->state); if (have_connection) self->sync = make_sync_future (self); done: return G_SOURCE_REMOVE; } static void network_status_changed (BzApplication *self, GParamSpec *pspec, GNetworkMonitor *network) { gboolean was_connected = FALSE; gboolean was_metered = FALSE; GNetworkConnectivity connectivity = 0; gboolean have_connection = FALSE; gboolean is_metered = FALSE; was_connected = bz_state_info_get_have_connection (self->state); was_metered = bz_state_info_get_metered_connection (self->state); connectivity = g_network_monitor_get_connectivity (network); have_connection = connectivity == G_NETWORK_CONNECTIVITY_FULL; is_metered = g_network_monitor_get_network_metered (network); if (!bz_state_info_get_busy (self->state) && ((!was_connected && have_connection && !is_metered) || (was_metered && !is_metered))) /* Wait a bit to prevent flakiness */ g_timeout_add_full ( G_PRIORITY_DEFAULT, 500, (GSourceFunc) scheduled_timeout_cb, bz_track_weak (self), bz_weak_release); bz_state_info_set_have_connection (self->state, have_connection); bz_state_info_set_metered_connection (self->state, is_metered); } static void disable_blocklists_changed (BzApplication *self, GParamSpec *pspec, BzStateInfo *state) { gtk_filter_changed (GTK_FILTER (self->group_filter), GTK_FILTER_CHANGE_DIFFERENT); gtk_filter_changed (GTK_FILTER (self->appid_filter), GTK_FILTER_CHANGE_DIFFERENT); } static void show_hide_app_setting_changed (BzApplication *self, const char *key, GSettings *settings) { g_object_freeze_notify (G_OBJECT (self->state)); bz_state_info_set_hide_eol (self->state, g_settings_get_boolean (self->settings, "hide-eol")); bz_state_info_set_show_only_foss (self->state, g_settings_get_boolean (self->settings, "show-only-foss")); bz_state_info_set_show_only_flathub (self->state, g_settings_get_boolean (self->settings, "show-only-flathub")); bz_state_info_set_show_only_verified (self->state, g_settings_get_boolean (self->settings, "show-only-verified")); gtk_filter_changed (GTK_FILTER (self->group_filter), GTK_FILTER_CHANGE_DIFFERENT); gtk_filter_changed (GTK_FILTER (self->appid_filter), GTK_FILTER_CHANGE_DIFFERENT); g_object_thaw_notify (G_OBJECT (self->state)); } static gboolean window_close_request (BzApplication *self, GtkWidget *window) { int width = 0; int height = 0; GList *remaining_windows = NULL; gboolean reap_dl_workers = TRUE; width = gtk_widget_get_width (window); height = gtk_widget_get_height (window); g_settings_set (self->settings, "window-dimensions", "(ii)", width, height); remaining_windows = gtk_application_get_windows ( GTK_APPLICATION (self)); for (GList *l = remaining_windows; l != NULL; l = l->next) { if (l->data != window) { reap_dl_workers = FALSE; break; } } if (reap_dl_workers) /* If no windows are left, kill the dl-worker subprocesses to minimize idle memory usage */ bz_reap_default_download_workers (); /* Do not stop other handlers from being invoked for the signal */ return FALSE; } static void blocklists_changed (BzApplication *self, guint position, guint removed, guint added, GListModel *model) { g_autoptr (GError) local_error = NULL; if (removed > 0) g_ptr_array_remove_range (self->blocklist_regexes, position, removed); for (guint i = 0; i < added; i++) { g_autoptr (BzRootBlocklist) root = NULL; g_autoptr (GPtrArray) regex_datas = NULL; GListModel *blocklists = NULL; root = g_list_model_get_item (model, position + i); regex_datas = g_ptr_array_new_with_free_func (blocklist_regex_data_unref); blocklists = bz_root_blocklist_get_blocklists (root); if (blocklists != NULL) { guint n_blocklists = 0; n_blocklists = g_list_model_get_n_items (blocklists); for (guint j = 0; j < n_blocklists; j++) { g_autoptr (BzBlocklist) blocklist = NULL; GListModel *conditions = NULL; GListModel *allow = NULL; GListModel *allow_regex = NULL; GListModel *block = NULL; GListModel *block_regex = NULL; g_autoptr (BlocklistRegexData) data = NULL; blocklist = g_list_model_get_item (blocklists, j); allow = bz_blocklist_get_allow (blocklist); allow_regex = bz_blocklist_get_allow_regex (blocklist); block = bz_blocklist_get_block (blocklist); block_regex = bz_blocklist_get_block_regex (blocklist); if (allow == NULL && allow_regex == NULL && block == NULL && block_regex == NULL) { g_warning ("Blocklist file has an empty blocklist, ignoring"); continue; } conditions = bz_blocklist_get_conditions (blocklist); if (conditions != NULL) { guint n_conditions = 0; gboolean ignore = FALSE; n_conditions = g_list_model_get_n_items (conditions); for (guint k = 0; k < n_conditions; k++) { gboolean condition_result = FALSE; g_autoptr (BzBlocklistCondition) condition = NULL; BzBlocklistConditionMatchEnvvar *match_envvar = NULL; BzBlocklistConditionMatchLocale *match_locale = NULL; BzBlocklistConditionPostProcessKind postprocess = BZ_BLOCKLIST_CONDITION_POST_PROCESS_KIND_IDENTITY; condition = g_list_model_get_item (conditions, k); match_envvar = bz_blocklist_condition_get_match_envvar (condition); match_locale = bz_blocklist_condition_get_match_locale (condition); postprocess = bz_blocklist_condition_get_post_process (condition); if (match_envvar == NULL && match_locale == NULL) { g_warning ("Blocklist file has an empty condition"); continue; } if (!condition_result && match_envvar != NULL) { const char *var = NULL; const char *regex = NULL; var = bz_blocklist_condition_match_envvar_get_var (match_envvar); regex = bz_blocklist_condition_match_envvar_get_regex (match_envvar); if (var != NULL && regex != NULL) { g_autoptr (GRegex) compiled = NULL; const char *value = NULL; compiled = g_regex_new ( regex, G_REGEX_ANCHORED, G_REGEX_MATCH_ANCHORED, &local_error); if (compiled == NULL) { g_warning ("Blocklist condition contains invalid regex: %s", local_error->message); g_clear_error (&local_error); continue; } value = g_getenv (var); if (value != NULL && g_regex_match ( compiled, value, G_REGEX_MATCH_ANCHORED, NULL)) condition_result = TRUE; if (postprocess == BZ_BLOCKLIST_CONDITION_POST_PROCESS_KIND_INVERT) condition_result = !condition_result; } else g_warning ("Blocklist file has a envvar condition " "missing a var and/or a regex pattern"); } if (!condition_result && match_locale != NULL) { const char *regex = NULL; regex = bz_blocklist_condition_match_locale_get_regex (match_locale); if (regex != NULL) { g_autoptr (GRegex) compiled = NULL; const char *const *locales = NULL; compiled = g_regex_new ( regex, G_REGEX_ANCHORED, G_REGEX_MATCH_ANCHORED, &local_error); if (compiled == NULL) { g_warning ("Blocklist condition contains invalid regex: %s", local_error->message); g_clear_error (&local_error); continue; } locales = g_get_language_names (); for (guint l = 0; locales[l] != NULL; l++) { if (g_regex_match ( compiled, locales[i], G_REGEX_MATCH_ANCHORED, NULL)) condition_result = TRUE; if (condition_result) break; } if (postprocess == BZ_BLOCKLIST_CONDITION_POST_PROCESS_KIND_INVERT) condition_result = !condition_result; } else g_warning ("Blocklist file has a match-locale " "condition missing a regex pattern"); } if (!condition_result) { ignore = TRUE; break; } } if (ignore) continue; } data = blocklist_regex_data_new (); data->priority = bz_blocklist_get_priority (blocklist); #define BUILD_REGEX(_name, _builder) \ if (_name != NULL) \ { \ guint _n_strings = 0; \ \ _n_strings = g_list_model_get_n_items (_name); \ for (guint _i = 0; _i < _n_strings; _i++) \ { \ g_autoptr (GtkStringObject) _object = NULL; \ const char *_string = NULL; \ g_autoptr (GRegex) _regex = NULL; \ \ _object = g_list_model_get_item (_name, _i); \ _string = gtk_string_object_get_string (_object); \ _regex = g_regex_new (_string, G_REGEX_DEFAULT, G_REGEX_MATCH_DEFAULT, &local_error); \ \ if (_regex != NULL) \ g_strv_builder_add (_builder, _string); \ else \ { \ g_warning ("Blocklist file has an invalid " \ "regular expression '%s': %s", \ _string, local_error->message); \ g_clear_error (&local_error); \ } \ } \ } #define BUILD_REGEX_ESCAPED(_name, _builder) \ if (_name != NULL) \ { \ guint _n_strings = 0; \ \ _n_strings = g_list_model_get_n_items (_name); \ for (guint _i = 0; _i < _n_strings; _i++) \ { \ g_autoptr (GtkStringObject) _object = NULL; \ const char *_string = NULL; \ \ _object = g_list_model_get_item (_name, _i); \ _string = gtk_string_object_get_string (_object); \ \ g_strv_builder_take (_builder, g_regex_escape_string (_string, -1)); \ } \ } #define GATHER(name) \ if (name != NULL || \ name##_regex != NULL) \ { \ g_autoptr (GStrvBuilder) _builder = NULL; \ g_auto (GStrv) _patterns = NULL; \ \ _builder = g_strv_builder_new (); \ \ BUILD_REGEX_ESCAPED (name, _builder) \ BUILD_REGEX (name##_regex, _builder) \ \ _patterns = g_strv_builder_end (_builder); \ if (_patterns != NULL) \ { \ g_autofree char *_joined = NULL; \ g_autofree char *_regex_string = NULL; \ \ _joined = g_strjoinv ("|", _patterns); \ _regex_string = g_strdup_printf ("^(%s)$", _joined); \ data->name = g_regex_new (_regex_string, G_REGEX_OPTIMIZE, \ G_REGEX_MATCH_DEFAULT, NULL); \ } \ } GATHER (allow); GATHER (block); #undef GATHER #undef BUILD_REGEX_ESCAPED #undef BUILD_REGEX if (data->allow != NULL || data->block != NULL) g_ptr_array_add (regex_datas, g_steal_pointer (&data)); } } g_ptr_array_insert (self->blocklist_regexes, position + i, g_steal_pointer (®ex_datas)); } gtk_filter_changed (GTK_FILTER (self->group_filter), GTK_FILTER_CHANGE_DIFFERENT); gtk_filter_changed (GTK_FILTER (self->appid_filter), GTK_FILTER_CHANGE_DIFFERENT); } static void txt_blocklists_changed (BzApplication *self, guint position, guint removed, guint added, GListModel *model) { if (removed > 0) g_ptr_array_remove_range (self->txt_blocked_id_sets, position, removed); for (guint i = 0; i < added; i++) { g_autoptr (BzHashTableObject) obj = NULL; GHashTable *set = NULL; obj = g_list_model_get_item (model, position + i); set = bz_hash_table_object_get_hash_table (obj); g_ptr_array_insert (self->txt_blocked_id_sets, position + i, g_hash_table_ref (set)); } gtk_filter_changed (GTK_FILTER (self->group_filter), GTK_FILTER_CHANGE_DIFFERENT); gtk_filter_changed (GTK_FILTER (self->appid_filter), GTK_FILTER_CHANGE_DIFFERENT); } static void init_service_struct (BzApplication *self, GtkStringList *blocklists, GtkStringList *txt_blocklists, GtkStringList *curated_configs) { g_autoptr (GError) local_error = NULL; g_autoptr (GBytes) internal_config_bytes = NULL; g_autoptr (BzYamlParser) internal_config_parser = NULL; g_autoptr (GHashTable) internal_config_parse_results = NULL; const char *app_id = NULL; #ifdef HARDCODED_MAIN_CONFIG g_autoptr (GFile) config_file = NULL; g_autoptr (GBytes) config_bytes = NULL; #endif GtkCustomFilter *filter = NULL; GNetworkMonitor *network = NULL; g_autoptr (BzAuthState) auth_state = NULL; g_type_ensure (BZ_TYPE_INTERNAL_CONFIG); internal_config_bytes = g_resources_lookup_data ( "/io/github/kolunmi/Bazaar/internal-config.yaml", G_RESOURCE_LOOKUP_FLAGS_NONE, NULL); g_assert (internal_config_bytes != NULL); internal_config_parser = bz_yaml_parser_new_for_resource_schema ( "/io/github/kolunmi/Bazaar/internal-config-schema.xml"); g_assert (internal_config_parser != NULL); internal_config_parse_results = bz_parser_process_bytes ( BZ_PARSER (internal_config_parser), internal_config_bytes, &local_error); if (internal_config_parse_results == NULL) g_critical ("FATAL: unable to parse internal config resource: %s", local_error->message); g_assert (internal_config_parse_results != NULL); self->internal_config = g_value_dup_object (g_hash_table_lookup (internal_config_parse_results, "/")); g_type_ensure (BZ_TYPE_MAIN_CONFIG); #ifdef HARDCODED_MAIN_CONFIG config_file = g_file_new_for_path (HARDCODED_MAIN_CONFIG); config_bytes = g_file_load_bytes (config_file, NULL, NULL, &local_error); if (config_bytes != NULL) { g_autoptr (BzYamlParser) parser = NULL; g_autoptr (GHashTable) parse_results = NULL; parser = bz_yaml_parser_new_for_resource_schema ( "/io/github/kolunmi/Bazaar/main-config-schema.xml"); parse_results = bz_parser_process_bytes ( BZ_PARSER (parser), config_bytes, &local_error); if (parse_results != NULL) { GListModel *override_eol_markings = NULL; self->config = g_value_dup_object (g_hash_table_lookup (parse_results, "/")); override_eol_markings = bz_main_config_get_override_eol_markings (self->config); if (override_eol_markings != NULL) { guint n_appids = 0; self->ignore_eol_set = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, g_free); n_appids = g_list_model_get_n_items (override_eol_markings); for (guint i = 0; i < n_appids; i++) { g_autoptr (GtkStringObject) string = NULL; const char *value = NULL; string = g_list_model_get_item (override_eol_markings, i); value = gtk_string_object_get_string (string); g_hash_table_replace (self->ignore_eol_set, g_strdup (value), NULL); } } } else { g_warning ("Could not load main config at %s: %s", HARDCODED_MAIN_CONFIG, local_error->message); g_clear_error (&local_error); } } g_clear_error (&local_error); #endif self->init_timer = g_timer_new (); self->ready_to_open_files = dex_promise_new (); if (self->config != NULL && bz_main_config_get_yaml_blocklist_paths (self->config) != NULL) { GListModel *paths = NULL; guint n_paths = 0; paths = bz_main_config_get_yaml_blocklist_paths (self->config); n_paths = g_list_model_get_n_items (paths); for (guint i = 0; i < n_paths; i++) { g_autoptr (GtkStringObject) string = NULL; string = g_list_model_get_item (paths, i); gtk_string_list_append (blocklists, gtk_string_object_get_string (string)); } } self->blocklists = g_object_ref (blocklists); self->blocklists_to_files = gtk_map_list_model_new ( NULL, (GtkMapListModelMapFunc) map_strings_to_files, NULL, NULL); gtk_map_list_model_set_model ( self->blocklists_to_files, G_LIST_MODEL (self->blocklists)); if (self->config != NULL && bz_main_config_get_txt_blocklist_paths (self->config) != NULL) { GListModel *paths = NULL; guint n_paths = 0; paths = bz_main_config_get_txt_blocklist_paths (self->config); n_paths = g_list_model_get_n_items (paths); for (guint i = 0; i < n_paths; i++) { g_autoptr (GtkStringObject) string = NULL; string = g_list_model_get_item (paths, i); gtk_string_list_append (txt_blocklists, gtk_string_object_get_string (string)); } } self->txt_blocklists = g_object_ref (txt_blocklists); self->txt_blocklists_to_files = gtk_map_list_model_new ( NULL, (GtkMapListModelMapFunc) map_strings_to_files, NULL, NULL); gtk_map_list_model_set_model ( self->txt_blocklists_to_files, G_LIST_MODEL (self->txt_blocklists)); if (self->config != NULL && bz_main_config_get_curated_config_paths (self->config) != NULL) { GListModel *paths = NULL; guint n_paths = 0; paths = bz_main_config_get_curated_config_paths (self->config); n_paths = g_list_model_get_n_items (paths); for (guint i = 0; i < n_paths; i++) { g_autoptr (GtkStringObject) string = NULL; string = g_list_model_get_item (paths, i); gtk_string_list_append (curated_configs, gtk_string_object_get_string (string)); } } self->curated_configs = g_object_ref (curated_configs); self->curated_configs_to_files = gtk_map_list_model_new ( NULL, (GtkMapListModelMapFunc) map_strings_to_files, NULL, NULL); gtk_map_list_model_set_model ( self->curated_configs_to_files, G_LIST_MODEL (self->curated_configs)); self->search_biases = gtk_flatten_list_model_new (NULL); self->search_biases_backing = g_list_store_new (G_TYPE_LIST_MODEL); { GListModel *main_config_search_biases = NULL; GListModel *internal_config_search_biases = NULL; if (self->config != NULL) main_config_search_biases = bz_main_config_get_search_biases (self->config); internal_config_search_biases = bz_internal_config_get_search_biases (self->internal_config); /* Main config biases take precedence over the hardcoded ones */ if (main_config_search_biases != NULL) g_list_store_append (self->search_biases_backing, main_config_search_biases); if (internal_config_search_biases != NULL) g_list_store_append (self->search_biases_backing, internal_config_search_biases); } gtk_flatten_list_model_set_model ( self->search_biases, G_LIST_MODEL (self->search_biases_backing)); g_type_ensure (BZ_TYPE_ROOT_BLOCKLIST); g_type_ensure (BZ_TYPE_BLOCKLIST); g_type_ensure (BZ_TYPE_BLOCKLIST_CONDITION); self->blocklist_parser = bz_yaml_parser_new_for_resource_schema ( "/io/github/kolunmi/Bazaar/blocklist-schema.xml"); self->txt_blocklist_parser = bz_newline_parser_new ( TRUE, MAX_IDS_PER_BLOCKLIST); g_type_ensure (BZ_TYPE_ROOT_CURATED_CONFIG); g_type_ensure (BZ_TYPE_CURATED_ROW); g_type_ensure (BZ_TYPE_CURATED_SECTION); self->curated_parser = bz_yaml_parser_new_for_resource_schema ( "/io/github/kolunmi/Bazaar/curated-config-schema.xml"); self->cache = bz_entry_cache_manager_new (); self->state = bz_state_info_new (); bz_state_info_set_busy (self->state, TRUE); bz_state_info_set_donation_prompt_dismissed (self->state, TRUE); bz_state_info_set_parental_age_rating (self->state, -1); { g_autoptr (GtkIconTheme) user_theme = NULL; g_autoptr (GtkIconTheme) system_theme = NULL; g_autofree char *user_export_dir = NULL; user_theme = gtk_icon_theme_new (); user_export_dir = g_build_filename (g_get_home_dir (), ".local/share/flatpak/exports/share/icons", NULL); gtk_icon_theme_add_search_path (user_theme, user_export_dir); bz_state_info_set_user_icon_theme (self->state, user_theme); system_theme = gtk_icon_theme_new (); gtk_icon_theme_add_search_path (system_theme, "/var/lib/flatpak/exports/share/icons"); bz_state_info_set_system_icon_theme (self->state, system_theme); } { g_autoptr (GError) bus_error = NULL; g_autoptr (GDBusConnection) sys_bus = NULL; sys_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &bus_error); if (sys_bus != NULL) self->malcontent = bz_malcontent_service_new (sys_bus, self->state); else g_warning ("Failed to connect to system bus for malcontent: %s", bus_error->message); if (self->malcontent != NULL) g_signal_connect_swapped ( self->state, "notify::parental-age-rating", G_CALLBACK (show_hide_app_setting_changed), self); } g_signal_connect_swapped ( self->state, "notify::disable-blocklists", G_CALLBACK (disable_blocklists_changed), self); auth_state = bz_auth_state_new (); bz_state_info_set_auth_state (self->state, auth_state); g_object_bind_property ( auth_state, "authenticated", g_action_map_lookup_action (G_ACTION_MAP (self), "flathub-login"), "enabled", G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); network = g_network_monitor_get_default (); if (network != NULL) { GNetworkConnectivity connectivity = 0; gboolean metered = FALSE; connectivity = g_network_monitor_get_connectivity (network); bz_state_info_set_have_connection (self->state, connectivity == G_NETWORK_CONNECTIVITY_FULL); metered = g_network_monitor_get_network_metered (network); bz_state_info_set_metered_connection (self->state, metered); g_signal_connect_swapped (network, "notify", G_CALLBACK (network_status_changed), self); } else g_warning ("Unable to detect networking device! Continuing anyway..."); app_id = g_application_get_application_id (G_APPLICATION (self)); g_assert (app_id != NULL); g_debug ("Constructing gsettings for %s ...", app_id); self->settings = g_settings_new (app_id); if (g_settings_get_boolean (self->settings, "force-adwaita-icons")) { GtkSettings *gtk_settings = NULL; gtk_settings = gtk_settings_get_default (); g_object_set ( gtk_settings, "gtk-icon-theme-name", "Adwaita", NULL); } bz_state_info_set_hide_eol ( self->state, g_settings_get_boolean (self->settings, "hide-eol")); g_signal_connect_swapped ( self->settings, "changed::hide-eol", G_CALLBACK (show_hide_app_setting_changed), self); bz_state_info_set_show_only_foss ( self->state, g_settings_get_boolean (self->settings, "show-only-foss")); g_signal_connect_swapped ( self->settings, "changed::show-only-foss", G_CALLBACK (show_hide_app_setting_changed), self); bz_state_info_set_show_only_flathub ( self->state, g_settings_get_boolean (self->settings, "show-only-flathub")); g_signal_connect_swapped ( self->settings, "changed::show-only-flathub", G_CALLBACK (show_hide_app_setting_changed), self); bz_state_info_set_show_only_verified ( self->state, g_settings_get_boolean (self->settings, "show-only-verified")); g_signal_connect_swapped ( self->settings, "changed::show-only-verified", G_CALLBACK (show_hide_app_setting_changed), self); self->blocklist_regexes = g_ptr_array_new_with_free_func ( (GDestroyNotify) g_ptr_array_unref); self->blocklists_provider = bz_content_provider_new (); bz_content_provider_set_parser (self->blocklists_provider, BZ_PARSER (self->blocklist_parser)); bz_content_provider_set_input_files ( self->blocklists_provider, G_LIST_MODEL (self->blocklists_to_files)); g_signal_connect_swapped (self->blocklists_provider, "items-changed", G_CALLBACK (blocklists_changed), self); self->txt_blocked_id_sets = g_ptr_array_new_with_free_func ( (GDestroyNotify) g_hash_table_unref); self->txt_blocklists_provider = bz_content_provider_new (); bz_content_provider_set_parser (self->txt_blocklists_provider, BZ_PARSER (self->txt_blocklist_parser)); bz_content_provider_set_input_files ( self->txt_blocklists_provider, G_LIST_MODEL (self->txt_blocklists_to_files)); g_signal_connect_swapped (self->txt_blocklists_provider, "items-changed", G_CALLBACK (txt_blocklists_changed), self); self->groups = g_list_store_new (BZ_TYPE_ENTRY_GROUP); self->installed_apps = g_list_store_new (BZ_TYPE_ENTRY_GROUP); self->ids_to_groups = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, g_object_unref); self->eol_runtimes = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, g_object_unref); self->sys_name_to_addons = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_ptr_array_unref); self->usr_name_to_addons = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_ptr_array_unref); self->sys_ref_to_addon_group_ids = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_ptr_array_unref); self->usr_ref_to_addon_group_ids = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_ptr_array_unref); self->entry_factory = bz_application_map_factory_new ( (GtkMapListModelMapFunc) map_ids_to_entries, self, NULL, NULL, NULL); filter = gtk_custom_filter_new ( (GtkCustomFilterFunc) filter_application_ids, self, NULL); self->appid_filter = g_object_ref_sink (g_steal_pointer (&filter)); self->application_factory = bz_application_map_factory_new ( (GtkMapListModelMapFunc) map_generic_ids_to_groups, self, NULL, NULL, GTK_FILTER (self->appid_filter)); filter = gtk_custom_filter_new ( (GtkCustomFilterFunc) filter_entry_groups, self, NULL); self->group_filter = g_object_ref_sink (g_steal_pointer (&filter)); self->group_filter_model = gtk_filter_list_model_new ( g_object_ref (G_LIST_MODEL (self->groups)), g_object_ref (GTK_FILTER (self->group_filter))); self->search_engine = bz_search_engine_new (); bz_search_engine_set_model (self->search_engine, G_LIST_MODEL (self->group_filter_model)); bz_search_engine_set_biases (self->search_engine, G_LIST_MODEL (self->search_biases)); bz_gnome_shell_search_provider_set_engine (self->gs_search, self->search_engine); self->curated_provider = bz_content_provider_new (); bz_content_provider_set_input_files ( self->curated_provider, G_LIST_MODEL (self->curated_configs_to_files)); bz_content_provider_set_parser (self->curated_provider, BZ_PARSER (self->curated_parser)); self->transactions = bz_transaction_manager_new (); bz_transaction_manager_set_config (self->transactions, self->config); bz_state_info_set_all_entry_groups (self->state, G_LIST_MODEL (self->groups)); bz_state_info_set_all_installed_entry_groups (self->state, G_LIST_MODEL (self->installed_apps)); bz_state_info_set_filtered_entry_groups (self->state, G_LIST_MODEL (self->group_filter_model)); bz_state_info_set_application_factory (self->state, self->application_factory); bz_state_info_set_blocklists (self->state, G_LIST_MODEL (self->blocklists)); bz_state_info_set_blocklists_provider (self->state, self->blocklists_provider); bz_state_info_set_curated_configs (self->state, G_LIST_MODEL (self->curated_configs)); bz_state_info_set_curated_provider (self->state, self->curated_provider); bz_state_info_set_entry_factory (self->state, self->entry_factory); bz_state_info_set_main_config (self->state, self->config); bz_state_info_set_search_engine (self->state, self->search_engine); bz_state_info_set_settings (self->state, self->settings); bz_state_info_set_transaction_manager (self->state, self->transactions); bz_state_info_set_txt_blocklists (self->state, G_LIST_MODEL (self->txt_blocklists)); bz_state_info_set_txt_blocklists_provider (self->state, self->txt_blocklists_provider); bz_state_info_set_cache_manager (self->state, self->cache); g_object_bind_property ( self->state, "allow-manual-sync", g_action_map_lookup_action (G_ACTION_MAP (self), "sync-remotes"), "enabled", G_BINDING_SYNC_CREATE); gtk_style_context_add_provider_for_display ( gdk_display_get_default (), bz_get_pride_style_provider (), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); } static GtkWindow * new_window (BzApplication *self) { BzWindow *window = NULL; g_autoptr (GtkWidget) main_window = NULL; int width = 0; int height = 0; window = bz_window_new (self->state); gtk_application_add_window (GTK_APPLICATION (self), GTK_WINDOW (window)); main_window = g_weak_ref_get (&self->main_window); if (main_window != NULL) { width = gtk_widget_get_width (main_window); height = gtk_widget_get_height (main_window); g_settings_set (self->settings, "window-dimensions", "(ii)", width, height); } else { g_settings_get (self->settings, "window-dimensions", "(ii)", &width, &height); g_signal_connect_object ( window, "close-request", G_CALLBACK (window_close_request), self, G_CONNECT_SWAPPED); g_weak_ref_init (&self->main_window, window); } gtk_window_set_default_size (GTK_WINDOW (window), width, height); gtk_window_present (GTK_WINDOW (window)); return GTK_WINDOW (window); } static void open_appstream_take (BzApplication *self, char *appstream) { const char *id = NULL; g_autoptr (OpenAppstreamData) data = NULL; g_info ("Loading appstream link %s...", appstream); if (g_str_has_prefix (appstream, "appstream://")) id = appstream + strlen ("appstream://"); else id = appstream + strlen ("appstream:"); data = open_appstream_data_new (); data->self = bz_track_weak (self); data->id = g_strdup (id); dex_future_disown (dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) open_appstream_fiber, open_appstream_data_ref (data), open_appstream_data_unref)); g_free (appstream); } static void open_flatpakref_take (BzApplication *self, GFile *file) { g_autofree char *path = NULL; g_autoptr (OpenFlatpakrefData) data = NULL; path = g_file_get_path (file); g_info ("Loading flatpakref at %s...", path); data = open_flatpakref_data_new (); data->self = bz_track_weak (self); data->file = g_steal_pointer (&file); dex_future_disown (dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) open_flatpakref_fiber, open_flatpakref_data_ref (data), open_flatpakref_data_unref)); } static void command_line_open_location (BzApplication *self, GApplicationCommandLine *cmdline, const char *location) { if (g_uri_is_valid (location, G_URI_FLAGS_NONE, NULL)) { if (g_str_has_prefix (location, "appstream:")) open_appstream_take (self, g_strdup (location)); else open_flatpakref_take (self, g_file_new_for_uri (location)); } else if (g_path_is_absolute (location)) open_flatpakref_take (self, g_file_new_for_path (location)); else { const char *cwd = NULL; cwd = g_application_command_line_get_cwd (cmdline); if (cwd != NULL) open_flatpakref_take (self, g_file_new_build_filename (cwd, location, NULL)); else open_flatpakref_take (self, g_file_new_for_path (location)); } } static void open_generic_id (BzApplication *self, const char *generic_id) { BzEntryGroup *group = NULL; GtkWindow *window = NULL; group = g_hash_table_lookup (self->ids_to_groups, generic_id); window = gtk_application_get_active_window (GTK_APPLICATION (self)); if (window == NULL) window = new_window (self); if (group != NULL) gtk_widget_activate_action (GTK_WIDGET (window), "window.show-group", "s", generic_id); else { g_autofree char *message = NULL; message = g_strdup_printf ("ID '%s' was not found", generic_id); bz_show_error_for_widget (GTK_WIDGET (window), _ ("Could not find app"), message); } } static gpointer map_strings_to_files (GtkStringObject *string, gpointer data) { const char *path = NULL; GFile *result = NULL; path = gtk_string_object_get_string (string); result = g_file_new_for_path (path); g_object_unref (string); return result; } static gpointer map_generic_ids_to_groups (GtkStringObject *string, BzApplication *self) { BzEntryGroup *group = NULL; group = g_hash_table_lookup ( self->ids_to_groups, gtk_string_object_get_string (string)); g_object_unref (string); return bz_object_maybe_ref (group); } static gpointer map_ids_to_entries (GtkStringObject *string, BzApplication *self) { g_autoptr (GError) local_error = NULL; const char *id = NULL; g_autoptr (DexFuture) future = NULL; g_autoptr (BzResult) result = NULL; id = gtk_string_object_get_string (string); future = bz_entry_cache_manager_get (self->cache, id); result = bz_result_new (future); g_object_unref (string); return g_steal_pointer (&result); } static gboolean filter_application_ids (GtkStringObject *string, BzApplication *self) { BzEntryGroup *group = NULL; group = g_hash_table_lookup ( self->ids_to_groups, gtk_string_object_get_string (string)); if (group != NULL) return validate_group_for_ui (self, group); else return FALSE; } static gboolean filter_entry_groups (BzEntryGroup *group, BzApplication *self) { return validate_group_for_ui (self, group); } static gint cmp_group (BzEntryGroup *a, BzEntryGroup *b, gpointer user_data) { const char *title_a = NULL; const char *title_b = NULL; title_a = bz_entry_group_get_title (a); title_b = bz_entry_group_get_title (b); if (title_a == NULL) return 1; if (title_b == NULL) return -1; return strcasecmp (title_a, title_b); } static gint cmp_entry (BzEntry *a, BzEntry *b, gpointer user_data) { gboolean a_is_runtime = FALSE; gboolean b_is_runtime = FALSE; gboolean a_is_addon = FALSE; gboolean b_is_addon = FALSE; a_is_runtime = bz_entry_is_of_kinds (a, BZ_ENTRY_KIND_RUNTIME); b_is_runtime = bz_entry_is_of_kinds (b, BZ_ENTRY_KIND_RUNTIME); if (a_is_runtime && !b_is_runtime) return -1; if (!a_is_runtime && b_is_runtime) return 1; a_is_addon = bz_entry_is_of_kinds (a, BZ_ENTRY_KIND_ADDON); b_is_addon = bz_entry_is_of_kinds (b, BZ_ENTRY_KIND_ADDON); if (a_is_addon && !b_is_addon) return -1; if (!a_is_addon && b_is_addon) return 1; return 0; } static gboolean validate_group_for_ui (BzApplication *self, BzEntryGroup *group) { const char *id = NULL; int allowed_priority = G_MAXINT; int blocked_priority = G_MAXINT; if (bz_state_info_get_hide_eol (self->state) && bz_entry_group_get_eol (group) != NULL) return FALSE; if (bz_state_info_get_show_only_foss (self->state) && !bz_entry_group_get_is_floss (group)) return FALSE; if (bz_state_info_get_show_only_flathub (self->state) && !bz_entry_group_get_is_flathub (group)) return FALSE; if (bz_state_info_get_show_only_verified (self->state) && !bz_entry_group_get_is_verified (group)) return FALSE; if (self->malcontent != NULL) { int parental_age = -1; int app_age = 0; parental_age = bz_state_info_get_parental_age_rating (self->state); app_age = bz_entry_group_get_content_age_rating (group); if (app_age > parental_age && parental_age != -1) return FALSE; } if (bz_state_info_get_disable_blocklists (self->state)) return TRUE; id = bz_entry_group_get_id (group); for (guint i = 0; i < self->txt_blocked_id_sets->len; i++) { GHashTable *set = NULL; set = g_ptr_array_index (self->txt_blocked_id_sets, i); if (g_hash_table_contains (set, id)) return FALSE; } for (guint i = 0; i < self->blocklist_regexes->len; i++) { GPtrArray *regex_datas = NULL; regex_datas = g_ptr_array_index (self->blocklist_regexes, i); for (guint j = 0; j < regex_datas->len; j++) { BlocklistRegexData *data = NULL; data = g_ptr_array_index (regex_datas, j); if (data->allow != NULL && data->priority < allowed_priority && g_regex_match (data->allow, id, G_REGEX_MATCH_DEFAULT, NULL)) allowed_priority = data->priority; if (data->block != NULL && data->priority < blocked_priority && g_regex_match (data->block, id, G_REGEX_MATCH_DEFAULT, NULL)) blocked_priority = data->priority; } } return allowed_priority <= blocked_priority; } static DexFuture * make_sync_future (BzApplication *self) { g_autoptr (DexFuture) backend_future = NULL; g_autoptr (DexFuture) flathub_future = NULL; g_autoptr (DexFuture) ret_future = NULL; bz_state_info_set_allow_manual_sync (self->state, FALSE); bz_state_info_set_syncing (self->state, TRUE); backend_future = bz_backend_retrieve_remote_entries (BZ_BACKEND (self->flatpak), NULL); backend_future = dex_future_finally ( backend_future, (DexFutureCallback) backend_sync_finally, bz_track_weak (self), bz_weak_release); g_clear_object (&self->tmp_flathub); self->tmp_flathub = bz_flathub_state_new (); flathub_future = bz_flathub_state_update_to_today (self->tmp_flathub); flathub_future = dex_future_finally ( flathub_future, (DexFutureCallback) flathub_update_finally, bz_track_weak (self), bz_weak_release); ret_future = dex_future_all ( dex_ref (backend_future), dex_ref (flathub_future), NULL); ret_future = dex_future_then ( ret_future, (DexFutureCallback) sync_then, bz_track_weak (self), bz_weak_release); return g_steal_pointer (&ret_future); } static void finish_with_background_task_label (BzApplication *self) { if (self->n_entries_incoming > 0) bz_state_info_set_background_task_label_take_printf ( self->state, _ ("Loading %d apps…"), self->n_entries_incoming); else if (bz_state_info_get_syncing (self->state)) bz_state_info_set_background_task_label (self->state, _ ("Refreshing…")); else if (bz_state_info_get_busy (self->state)) bz_state_info_set_background_task_label (self->state, _ ("Writing to cache…")); else bz_state_info_set_background_task_label (self->state, NULL); } bazaar-orig-v0.7.14/src/bz-share-list.h0000664000175000017500000000173615166123241016573 0ustar hasanhasan/* bz-share-list.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_SHARE_LIST (bz_share_list_get_type ()) G_DECLARE_FINAL_TYPE (BzShareList, bz_share_list, BZ, SHARE_LIST, GtkBox) GtkWidget * bz_share_list_new (void); G_END_DECLS bazaar-orig-v0.7.14/src/bz-donations-dialog.c0000664000175000017500000002160115166123241017737 0ustar hasanhasan/* bz-donations-dialog.c * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include #include "bz-appstream-description-render.h" #include "bz-donations-dialog.h" #include "bz-template-callbacks.h" struct _BzDonationsDialog { AdwDialog parent_instance; char *release_notes; char *release_url; AdwBreakpoint *breakpoint; /* Template widgets */ GtkLabel *title; GtkLabel *subtitle; GtkButton *release_button; GtkButton *donate_button; }; G_DEFINE_FINAL_TYPE (BzDonationsDialog, bz_donations_dialog, ADW_TYPE_DIALOG); enum { PROP_0, PROP_RELEASE_NOTES, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static const char *bz_donations_dialog_get_release_notes (BzDonationsDialog *self); static void bz_donations_dialog_dispose (GObject *object) { BzDonationsDialog *self = BZ_DONATIONS_DIALOG (object); g_clear_pointer (&self->release_notes, g_free); g_clear_pointer (&self->release_url, g_free); g_clear_object (&self->breakpoint); G_OBJECT_CLASS (bz_donations_dialog_parent_class)->dispose (object); } static void bz_donations_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzDonationsDialog *self = BZ_DONATIONS_DIALOG (object); switch (prop_id) { case PROP_RELEASE_NOTES: g_value_set_string (value, bz_donations_dialog_get_release_notes (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void donate_clicked (BzDonationsDialog *self, GtkButton *button) { g_app_info_launch_default_for_uri ( DONATE_LINK, NULL, NULL); } static void release_page_clicked (BzDonationsDialog *self, GtkButton *button) { if (self->release_url != NULL) g_app_info_launch_default_for_uri (self->release_url, NULL, NULL); } static void on_map (BzDonationsDialog *self, gpointer user_data) { GtkRoot *root = NULL; root = gtk_widget_get_root (GTK_WIDGET (self)); if (root == NULL || self->breakpoint == NULL) return; adw_application_window_add_breakpoint (ADW_APPLICATION_WINDOW (root), g_object_ref (self->breakpoint)); } static void bz_donations_dialog_class_init (BzDonationsDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->get_property = bz_donations_dialog_get_property; object_class->dispose = bz_donations_dialog_dispose; props[PROP_RELEASE_NOTES] = g_param_spec_string ( "release-notes", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_APPSTREAM_DESCRIPTION_RENDER); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-donations-dialog.ui"); bz_widget_class_bind_all_util_callbacks (widget_class); gtk_widget_class_bind_template_child (widget_class, BzDonationsDialog, title); gtk_widget_class_bind_template_child (widget_class, BzDonationsDialog, subtitle); gtk_widget_class_bind_template_child (widget_class, BzDonationsDialog, release_button); gtk_widget_class_bind_template_child (widget_class, BzDonationsDialog, donate_button); gtk_widget_class_bind_template_callback (widget_class, donate_clicked); gtk_widget_class_bind_template_callback (widget_class, release_page_clicked); } static void bz_donations_dialog_init (BzDonationsDialog *self) { g_autoptr (GBytes) release_notes_bytes = NULL; g_autoptr (GError) error = NULL; g_autoptr (XbBuilderSource) source = NULL; g_autoptr (XbBuilder) builder = NULL; g_autoptr (XbSilo) silo = NULL; g_autoptr (XbNode) release_node = NULL; g_autoptr (XbNode) url_node = NULL; g_autoptr (XbNode) description_node = NULL; const char *version = NULL; const char *date = NULL; const char *url = NULL; AdwBreakpointCondition *condition = NULL; gtk_widget_init_template (GTK_WIDGET (self)); gtk_widget_set_tooltip_text (GTK_WIDGET (self->release_button), RELEASE_PAGE); gtk_widget_set_tooltip_text (GTK_WIDGET (self->donate_button), DONATE_LINK); condition = adw_breakpoint_condition_new_length ( ADW_BREAKPOINT_CONDITION_MAX_WIDTH, 500, ADW_LENGTH_UNIT_PX); self->breakpoint = adw_breakpoint_new (condition); adw_breakpoint_add_setter (self->breakpoint, G_OBJECT (self), "width-request", &(GValue) { G_TYPE_INT, { { .v_int = 350 } } }); g_signal_connect (self, "map", G_CALLBACK (on_map), NULL); release_notes_bytes = g_resources_lookup_data ( "/io/github/kolunmi/Bazaar/release-notes.xml", G_RESOURCE_LOOKUP_FLAGS_NONE, &error); if (release_notes_bytes == NULL) { g_warning ("Failed to load release notes: %s", error->message); return; } source = xb_builder_source_new (); if (!xb_builder_source_load_bytes (source, release_notes_bytes, XB_BUILDER_SOURCE_FLAG_LITERAL_TEXT, &error)) { g_warning ("Failed to load release notes into xmlb: %s", error->message); return; } builder = xb_builder_new (); xb_builder_import_source (builder, source); silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, NULL, &error); if (silo == NULL) { g_warning ("Failed to compile release notes silo: %s", error->message); return; } release_node = xb_silo_query_first (silo, "release", &error); if (release_node == NULL) { g_warning ("Failed to find release node: %s", error != NULL ? error->message : "no error"); g_clear_error (&error); return; } version = xb_node_get_attr (release_node, "version"); date = xb_node_get_attr (release_node, "date"); if (version != NULL) { g_autofree char *title_str = NULL; /* Translators: the %s format specifier will be something along the lines of "0.7.6" etc */ title_str = g_strdup_printf (_ ("What's New in %s?"), version); gtk_label_set_label (self->title, title_str); } if (date != NULL) { g_autofree char *date_full = NULL; g_autoptr (GDateTime) dt = NULL; g_autofree char *subtitle_str = NULL; date_full = g_strdup_printf ("%sT00:00:00Z", date); dt = g_date_time_new_from_iso8601 (date_full, NULL); if (dt != NULL) { /* Translators: this is a release date label, like "Released February 9, 2026" */ subtitle_str = g_date_time_format (dt, _ ("Released %B %-e, %Y")); if (subtitle_str != NULL) gtk_label_set_label (self->subtitle, subtitle_str); } } url_node = xb_silo_query_first (silo, "release/url[@type='details']", &error); if (url_node != NULL) { url = xb_node_get_text (url_node); if (url != NULL) self->release_url = g_strdup (url); } else g_clear_error (&error); description_node = xb_silo_query_first (silo, "release/description", &error); if (description_node != NULL) { self->release_notes = xb_node_export (description_node, XB_NODE_EXPORT_FLAG_INCLUDE_SIBLINGS, &error); if (self->release_notes == NULL) { g_warning ("Failed to export description node: %s", error->message); g_clear_error (&error); } } else { g_warning ("Failed to find description node: %s", error != NULL ? error->message : "no error"); g_clear_error (&error); } if (self->release_notes != NULL) g_object_notify_by_pspec (G_OBJECT (self), props[PROP_RELEASE_NOTES]); } AdwDialog * bz_donations_dialog_new (void) { return g_object_new (BZ_TYPE_DONATIONS_DIALOG, NULL); } static const char * bz_donations_dialog_get_release_notes (BzDonationsDialog *self) { g_return_val_if_fail (BZ_IS_DONATIONS_DIALOG (self), NULL); return self->release_notes; } /* End of bz-donations-dialog.c */ bazaar-orig-v0.7.14/src/bz-updates-card.blp0000664000175000017500000000144115166123241017413 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzUpdatesCard: Adw.Bin { child: ListBox { selection-mode: none; margin-start: 4; margin-end: 4; margin-bottom: 4; styles [ "boxed-list", ] Adw.ExpanderRow expander_row { title: bind $format_update_count(template.state as <$BzStateInfo>.available-updates) as ; [suffix] Box { height-request: 60; Button { label: _("_Update All"); use-underline: true; valign: center; clicked => $update_all_cb(); styles [ "suggested-action", ] } } } }; } FilterListModel runtimes_filter_model { filter: CustomFilter runtimes_filter {}; model: bind template.state as <$BzStateInfo>.available-updates; }bazaar-orig-v0.7.14/src/bz-row-view.c0000664000175000017500000001214315166123241016264 0ustar hasanhasan/* bz-row-view.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-row-view.h" #include "bz-curated-view.h" #include "bz-dynamic-list-view.h" #include "bz-section-view.h" struct _BzRowView { AdwBin parent_instance; BzCuratedRow *row; /* Template widgets */ }; G_DEFINE_FINAL_TYPE (BzRowView, bz_row_view, ADW_TYPE_BIN) enum { PROP_0, PROP_ROW, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bz_row_view_dispose (GObject *object) { BzRowView *self = BZ_ROW_VIEW (object); g_clear_object (&self->row); G_OBJECT_CLASS (bz_row_view_parent_class)->dispose (object); } static void bz_row_view_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzRowView *self = BZ_ROW_VIEW (object); switch (prop_id) { case PROP_ROW: g_value_set_object (value, bz_row_view_get_row (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_row_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzRowView *self = BZ_ROW_VIEW (object); switch (prop_id) { case PROP_ROW: bz_row_view_set_row (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static gboolean is_null (gpointer object, GObject *value) { return value == NULL; } static void group_activated_cb (GtkListItem *list_item, BzEntryGroup *group, BzRowView *view) { gtk_widget_activate_action (GTK_WIDGET (view), "window.show-group", "s", bz_entry_group_get_id (group)); } static void bind_section_view_cb (GtkListItem *list_item, BzSectionView *section_view, BzCuratedSection *section, BzDynamicListView *view) { g_signal_connect_swapped (section_view, "group-activated", G_CALLBACK (group_activated_cb), list_item); } static void unbind_section_view_cb (GtkListItem *list_item, BzSectionView *section_view, BzCuratedSection *section, BzDynamicListView *view) { g_signal_handlers_disconnect_by_func (section_view, group_activated_cb, list_item); } static void bz_row_view_class_init (BzRowViewClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_row_view_dispose; object_class->get_property = bz_row_view_get_property; object_class->set_property = bz_row_view_set_property; props[PROP_ROW] = g_param_spec_object ( "row", NULL, NULL, BZ_TYPE_CURATED_ROW, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_DYNAMIC_LIST_VIEW); g_type_ensure (BZ_TYPE_SECTION_VIEW); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-row-view.ui"); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, is_null); gtk_widget_class_bind_template_callback (widget_class, bind_section_view_cb); gtk_widget_class_bind_template_callback (widget_class, unbind_section_view_cb); } static void bz_row_view_init (BzRowView *self) { gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_row_view_new (BzCuratedRow *row) { return g_object_new ( BZ_TYPE_ROW_VIEW, "row", row, NULL); } void bz_row_view_set_row (BzRowView *self, BzCuratedRow *row) { g_return_if_fail (BZ_IS_ROW_VIEW (self)); g_return_if_fail (row == NULL || BZ_IS_CURATED_ROW (row)); g_clear_object (&self->row); if (row != NULL) self->row = g_object_ref (row); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ROW]); } BzCuratedRow * bz_row_view_get_row (BzRowView *self) { g_return_val_if_fail (BZ_IS_ROW_VIEW (self), NULL); return self->row; } bazaar-orig-v0.7.14/src/bz-featured-tile.blp0000664000175000017500000000473615166123241017603 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzFeaturedTile: Button { styles [ "featured-tile", ] Overlay { [overlay] Image { halign: end; valign: start; icon-name: "app-installed-symbolic"; icon-size: normal; visible: bind template.group as <$BzEntryGroup>.removable; margin-top: 12; margin-end: 12; } Box content_box { halign: center; orientation: horizontal; margin-start: 10; margin-end: 10; Box { orientation: vertical; valign: center; margin-top: 50; margin-bottom: 50; Image image { paintable: bind template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable; margin-bottom: 12; pixel-size: 128; styles [ "icon-dropshadow", ] } Label title { xalign: 0.5; halign: center; ellipsize: end; label: bind template.group as <$BzEntryGroup>.title; styles [ "title-1", ] } Adw.Clamp { maximum-size: 350; tightening-threshold: 350; Box { orientation: vertical; Label description { ellipsize: end; xalign: 0.5; lines: 1; justify: center; label: bind template.group as <$BzEntryGroup>.description; wrap: true; wrap-mode: word_char; styles [ "caption", ] } Box { spacing: 4; halign: center; margin-top: 4; visible: bind template.is-aotd; Image { icon-name: "starred-symbolic"; pixel-size: 12; } Label { ellipsize: end; xalign: 0.5; lines: 1; justify: center; label: _("App of the Day"); wrap: true; wrap-mode: word_char; styles [ "caption", ] } } } } } $BzScreenshot screenshot { visible: bind $invert_boolean(template.narrow) as ; paintable: bind template.first-screenshot; rounded-corners: true; top-half: true; valign: end; margin-top: 20; } } } } bazaar-orig-v0.7.14/src/bz-installed-tile.h0000664000175000017500000000237315166123241017430 0ustar hasanhasan/* bz-installed-tile.h * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry-group.h" #include "bz-list-tile.h" #include G_BEGIN_DECLS #define BZ_TYPE_INSTALLED_TILE (bz_installed_tile_get_type ()) G_DECLARE_FINAL_TYPE (BzInstalledTile, bz_installed_tile, BZ, INSTALLED_TILE, BzListTile) GtkWidget * bz_installed_tile_new (void); void bz_installed_tile_set_group (BzInstalledTile *self, BzEntryGroup *group); BzEntryGroup * bz_installed_tile_get_group (BzInstalledTile *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-flatpak-private.h0000664000175000017500000000344115166123241017605 0ustar hasanhasan/* bz-flatpak-private.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include #include "bz-flatpak-entry.h" #include "bz-flatpak-instance.h" G_BEGIN_DECLS /* BzFlatpakInstance */ FlatpakInstallation * bz_flatpak_instance_get_system_installation (BzFlatpakInstance *self); FlatpakInstallation * bz_flatpak_instance_get_user_installation (BzFlatpakInstance *self); /* BzFlatpakEntry */ char * bz_flatpak_ref_parts_format_unique (const char *origin, const char *fmt, gboolean user); char * bz_flatpak_ref_format_unique (FlatpakRef *ref, gboolean user); BzFlatpakEntry * bz_flatpak_entry_new_for_ref (FlatpakRef *ref, FlatpakRemote *remote, gboolean user, AsComponent *component, const char *appstream_dir, GError **error); FlatpakRef * bz_flatpak_entry_get_ref (BzFlatpakEntry *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-category-flags.h0000664000175000017500000000407215166123241017423 0ustar hasanhasan/* bz-category-flags.h * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_CATEGORY_FLAGS (bz_category_flags_get_type ()) typedef enum { BZ_CATEGORY_FLAGS_NONE = 0, BZ_CATEGORY_FLAGS_AUDIOVIDEO = 1 << 0, BZ_CATEGORY_FLAGS_DEVELOPMENT = 1 << 1, BZ_CATEGORY_FLAGS_EDUCATION = 1 << 2, BZ_CATEGORY_FLAGS_GAME = 1 << 3, BZ_CATEGORY_FLAGS_GRAPHICS = 1 << 4, BZ_CATEGORY_FLAGS_NETWORK = 1 << 5, BZ_CATEGORY_FLAGS_OFFICE = 1 << 6, BZ_CATEGORY_FLAGS_SCIENCE = 1 << 7, BZ_CATEGORY_FLAGS_SYSTEM = 1 << 8, BZ_CATEGORY_FLAGS_UTILITY = 1 << 9, BZ_CATEGORY_FLAGS_TRENDING = 1 << 10, BZ_CATEGORY_FLAGS_POPULAR = 1 << 11, BZ_CATEGORY_FLAGS_RECENTLY_ADDED = 1 << 12, BZ_CATEGORY_FLAGS_RECENTLY_UPDATED = 1 << 13, BZ_CATEGORY_FLAGS_MOBILE = 1 << 14, BZ_CATEGORY_FLAGS_ADWAITA = 1 << 15, BZ_CATEGORY_FLAGS_KDE = 1 << 16, } BzCategoryFlags; GType bz_category_flags_get_type (void); BzCategoryFlags bz_category_flags_add (BzCategoryFlags flags, const char *name); gboolean bz_category_flags_has_name (BzCategoryFlags flags, const char *name); BzCategoryFlags bz_category_flags_from_name (const char *name); G_END_DECLS bazaar-orig-v0.7.14/src/bz-search-result.txt0000664000175000017500000000054115166123241017662 0ustar hasanhasanprefix=bz name=search_result parent-prefix=g parent-name=object author=AUTOGEN include="bz-state-info.h" property=group BzEntryGroup BZ_TYPE_ENTRY_GROUP object property=original_index guint G_TYPE_UINT uint property=score double G_TYPE_DOUBLE double property=title_markup char G_TYPE_STRING string property=state BzStateInfo BZ_TYPE_STATE_INFO object bazaar-orig-v0.7.14/src/bz-flathub-category-section.blp0000664000175000017500000000213415166123241021741 0ustar hasanhasanusing Gtk 4.0; template $BzFlathubCategorySection : Box { orientation: vertical; spacing: 10; visible: bind $invert_boolean($is_null(template.category as <$BzFlathubCategory>) as ) as ; margin-bottom: 12; Label section_title { styles [ "title-1", ] visible: bind $invert_boolean(template.category as <$BzFlathubCategory>.is-spotlight) as ; xalign: 0.0; hexpand: true; margin-start: 3; margin-end: 3; margin-bottom: 5; ellipsize: end; } $BzDynamicListView section_list { styles [ "flathub-page-section", ] hexpand: true; scroll: false; noscroll-kind: flow-box; child-type: "BzAppTile"; child-prop: "group"; row-spacing: bind $get_spacing(template.compact) as ; column-spacing: bind $get_spacing(template.compact) as ; bind-widget => $bind_widget_cb(); unbind-widget => $unbind_widget_cb(); } Button more_button { styles [ "pill", ] can-shrink: true; halign: center; valign: center; margin-top: 5; clicked => $on_more_button_clicked(); } }bazaar-orig-v0.7.14/src/bz-updates-card.c0000664000175000017500000003474215166123241017072 0ustar hasanhasan/* bz-updates-card.c * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include "bz-entry.h" #include "bz-release.h" #include "bz-releases-list.h" #include "bz-template-callbacks.h" #include "bz-updates-card.h" struct _BzUpdatesCard { AdwBin parent_instance; BzStateInfo *state; /* Template widgets */ AdwExpanderRow *expander_row; GtkCustomFilter *runtimes_filter; GtkFilterListModel *runtimes_filter_model; GPtrArray *app_rows; GtkWidget *runtimes_row; }; G_DEFINE_FINAL_TYPE (BzUpdatesCard, bz_updates_card, ADW_TYPE_BIN) enum { PROP_0, PROP_STATE, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; enum { SIGNAL_UPDATE, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL]; static char *format_update_count (gpointer object, GListModel *updates); static void update_all_cb (GtkButton *button, BzUpdatesCard *self); static void update_runtimes_cb (GtkButton *button, BzUpdatesCard *self); static gboolean filter_runtimes (BzEntry *entry, BzUpdatesCard *self); static void on_available_updates_changed (BzUpdatesCard *self, GParamSpec *pspec, BzStateInfo *state); static void on_runtimes_changed (GtkFilterListModel *model, guint position, guint removed, guint added, BzUpdatesCard *self); static void on_update_single_cb (GtkButton *button, BzEntry *entry) { BzUpdatesCard *self = NULL; g_autoptr (GListStore) store = NULL; self = BZ_UPDATES_CARD (gtk_widget_get_ancestor (GTK_WIDGET (button), BZ_TYPE_UPDATES_CARD)); store = g_list_store_new (BZ_TYPE_ENTRY); g_list_store_append (store, entry); g_signal_emit (self, signals[SIGNAL_UPDATE], 0, store); } static void on_version_history_cb (GtkButton *button, BzEntry *entry) { GtkRoot *root = NULL; g_autoptr (GListModel) history = NULL; GtkWidget *dialog = NULL; root = gtk_widget_get_root (GTK_WIDGET (button)); if (root == NULL) return; g_object_get (entry, "version-history", &history, NULL); dialog = bz_releases_dialog_new (history, NULL); adw_dialog_present (ADW_DIALOG (dialog), GTK_WIDGET (root)); } static GtkWidget * build_app_row (BzEntry *entry, BzUpdatesCard *self) { AdwActionRow *row = NULL; GtkWidget *icon = NULL; GtkWidget *history_button = NULL; GtkWidget *update_button = NULL; GdkPaintable *paintable = NULL; g_autoptr (GListModel) history = NULL; g_autofree char *installed_ver = NULL; const char *new_ver = NULL; // This will probably the same as the installed version if using cache... row = ADW_ACTION_ROW (adw_action_row_new ()); adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), bz_entry_get_title (entry)); g_object_get (entry, "icon-paintable", &paintable, NULL); icon = paintable != NULL ? gtk_image_new_from_paintable (paintable) : gtk_image_new_from_icon_name ("application-x-executable"); g_clear_object (&paintable); gtk_image_set_pixel_size (GTK_IMAGE (icon), 48); gtk_widget_set_size_request (icon, 48, 48); gtk_widget_set_margin_top (icon, 6); gtk_widget_set_margin_bottom (icon, 6); gtk_widget_set_valign (icon, GTK_ALIGN_CENTER); gtk_widget_add_css_class (icon, "icon-dropshadow"); adw_action_row_add_prefix (row, icon); g_object_get (entry, "version-history", &history, "installed-version", &installed_ver, NULL); if (history != NULL && g_list_model_get_n_items (history) > 0 && installed_ver != NULL) { g_autoptr (BzRelease) first = g_list_model_get_item (history, 0); new_ver = bz_release_get_version (first); if (new_ver != NULL && g_strcmp0 (installed_ver, new_ver) != 0) { g_autofree char *subtitle = g_strdup_printf ("%s → %s", installed_ver, new_ver); adw_action_row_set_subtitle (row, subtitle); } } history_button = gtk_button_new_from_icon_name ("view-list-bullet-symbolic"); gtk_widget_set_valign (history_button, GTK_ALIGN_CENTER); gtk_widget_set_tooltip_text (history_button, _ ("Version History")); gtk_widget_add_css_class (history_button, "flat"); gtk_widget_set_visible (history_button, history != NULL && g_list_model_get_n_items (history) > 0); g_signal_connect_data (history_button, "clicked", G_CALLBACK (on_version_history_cb), g_object_ref (entry), (GClosureNotify) g_object_unref, 0); adw_action_row_add_suffix (row, history_button); update_button = gtk_button_new_with_label (_ ("Update")); gtk_widget_set_valign (update_button, GTK_ALIGN_CENTER); g_signal_connect_data (update_button, "clicked", G_CALLBACK (on_update_single_cb), g_object_ref (entry), (GClosureNotify) g_object_unref, 0); adw_action_row_add_suffix (row, update_button); return GTK_WIDGET (row); } static GtkWidget * build_runtimes_row (BzUpdatesCard *self) { AdwActionRow *row = NULL; GtkWidget *update_button = NULL; row = ADW_ACTION_ROW (adw_action_row_new ()); gtk_widget_set_visible (GTK_WIDGET (row), FALSE); update_button = gtk_button_new_with_label (_ ("Update")); gtk_widget_set_valign (update_button, GTK_ALIGN_CENTER); g_signal_connect (update_button, "clicked", G_CALLBACK (update_runtimes_cb), self); adw_action_row_add_suffix (row, update_button); return GTK_WIDGET (row); } static void on_runtimes_changed (GtkFilterListModel *model, guint position, guint removed, guint added, BzUpdatesCard *self) { guint n_items = 0; g_autofree char *title = NULL; if (self->runtimes_row == NULL) return; n_items = g_list_model_get_n_items (G_LIST_MODEL (model)); gtk_widget_set_visible (self->runtimes_row, n_items > 0); if (n_items == 0) return; title = g_strdup_printf (ngettext ("%u Runtime Update", "%u Runtime Updates", n_items), n_items); adw_preferences_row_set_title (ADW_PREFERENCES_ROW (self->runtimes_row), title); } static void repopulate_expander_row (BzUpdatesCard *self) { GListModel *updates = NULL; guint n_items = 0; guint i = 0; for (i = 0; i < self->app_rows->len; i++) adw_expander_row_remove (self->expander_row, g_ptr_array_index (self->app_rows, i)); g_ptr_array_set_size (self->app_rows, 0); if (self->runtimes_row != NULL) { adw_expander_row_remove (self->expander_row, self->runtimes_row); self->runtimes_row = NULL; } if (self->state == NULL) return; updates = bz_state_info_get_available_updates (self->state); if (updates == NULL) return; n_items = g_list_model_get_n_items (updates); for (i = 0; i < n_items; i++) { g_autoptr (BzEntry) entry = NULL; GtkWidget *row = NULL; entry = g_list_model_get_item (updates, i); if (entry == NULL || !BZ_IS_ENTRY (entry)) continue; if (!bz_entry_is_of_kinds (entry, BZ_ENTRY_KIND_APPLICATION)) continue; row = build_app_row (entry, self); adw_expander_row_add_row (self->expander_row, row); g_ptr_array_add (self->app_rows, row); } self->runtimes_row = build_runtimes_row (self); adw_expander_row_add_row (self->expander_row, self->runtimes_row); on_runtimes_changed (self->runtimes_filter_model, 0, 0, 0, self); } static void on_available_updates_changed (BzUpdatesCard *self, GParamSpec *pspec, BzStateInfo *state) { gtk_filter_changed (GTK_FILTER (self->runtimes_filter), GTK_FILTER_CHANGE_DIFFERENT); repopulate_expander_row (self); } static void bz_updates_card_dispose (GObject *object) { BzUpdatesCard *self = BZ_UPDATES_CARD (object); g_clear_object (&self->state); g_clear_pointer (&self->app_rows, g_ptr_array_unref); gtk_widget_dispose_template (GTK_WIDGET (self), BZ_TYPE_UPDATES_CARD); G_OBJECT_CLASS (bz_updates_card_parent_class)->dispose (object); } static void bz_updates_card_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzUpdatesCard *self = BZ_UPDATES_CARD (object); switch (prop_id) { case PROP_STATE: g_value_set_object (value, bz_updates_card_get_state (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_updates_card_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzUpdatesCard *self = BZ_UPDATES_CARD (object); switch (prop_id) { case PROP_STATE: bz_updates_card_set_state (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_updates_card_class_init (BzUpdatesCardClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_updates_card_dispose; object_class->get_property = bz_updates_card_get_property; object_class->set_property = bz_updates_card_set_property; props[PROP_STATE] = g_param_spec_object ( "state", NULL, NULL, BZ_TYPE_STATE_INFO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); signals[SIGNAL_UPDATE] = g_signal_new ( "update", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_LIST_MODEL); g_signal_set_va_marshaller ( signals[SIGNAL_UPDATE], G_TYPE_FROM_CLASS (klass), g_cclosure_marshal_VOID__OBJECTv); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-updates-card.ui"); bz_widget_class_bind_all_util_callbacks (widget_class); gtk_widget_class_bind_template_child (widget_class, BzUpdatesCard, expander_row); gtk_widget_class_bind_template_child (widget_class, BzUpdatesCard, runtimes_filter); gtk_widget_class_bind_template_child (widget_class, BzUpdatesCard, runtimes_filter_model); gtk_widget_class_bind_template_callback (widget_class, format_update_count); gtk_widget_class_bind_template_callback (widget_class, update_all_cb); } static void bz_updates_card_init (BzUpdatesCard *self) { gtk_widget_init_template (GTK_WIDGET (self)); self->app_rows = g_ptr_array_new (); gtk_custom_filter_set_filter_func ( self->runtimes_filter, (GtkCustomFilterFunc) filter_runtimes, self, NULL); g_signal_connect (self->runtimes_filter_model, "items-changed", G_CALLBACK (on_runtimes_changed), self); } GtkWidget * bz_updates_card_new (void) { return g_object_new (BZ_TYPE_UPDATES_CARD, NULL); } void bz_updates_card_set_state (BzUpdatesCard *self, BzStateInfo *state) { g_return_if_fail (BZ_IS_UPDATES_CARD (self)); g_return_if_fail (state == NULL || BZ_IS_STATE_INFO (state)); g_clear_object (&self->state); if (state != NULL) { self->state = g_object_ref (state); g_signal_connect_object (state, "notify::available-updates", G_CALLBACK (on_available_updates_changed), self, G_CONNECT_SWAPPED); } gtk_filter_changed (GTK_FILTER (self->runtimes_filter), GTK_FILTER_CHANGE_DIFFERENT); repopulate_expander_row (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_STATE]); } BzStateInfo * bz_updates_card_get_state (BzUpdatesCard *self) { g_return_val_if_fail (BZ_IS_UPDATES_CARD (self), NULL); return self->state; } static char * format_update_count (gpointer object, GListModel *updates) { guint n_updates = 0; if (updates == NULL) return g_strdup (""); n_updates = g_list_model_get_n_items (updates); return g_strdup_printf (ngettext ("%u Available Update", "%u Available Updates", n_updates), n_updates); } static void update_all_cb (GtkButton *button, BzUpdatesCard *self) { GListModel *updates = NULL; g_return_if_fail (GTK_IS_BUTTON (button)); g_return_if_fail (BZ_IS_UPDATES_CARD (self)); if (self->state == NULL) return; updates = bz_state_info_get_available_updates (self->state); if (updates == NULL) return; g_signal_emit (self, signals[SIGNAL_UPDATE], 0, updates); } static void update_runtimes_cb (GtkButton *button, BzUpdatesCard *self) { GListModel *runtimes = NULL; g_autoptr (GListStore) store = NULL; guint n_items = 0; runtimes = G_LIST_MODEL (self->runtimes_filter_model); n_items = g_list_model_get_n_items (runtimes); if (n_items == 0) return; store = g_list_store_new (BZ_TYPE_ENTRY); for (guint i = 0; i < n_items; i++) { g_autoptr (BzEntry) entry = g_list_model_get_item (runtimes, i); if (entry != NULL) g_list_store_append (store, entry); } g_signal_emit (self, signals[SIGNAL_UPDATE], 0, store); } static gboolean filter_runtimes (BzEntry *entry, BzUpdatesCard *self) { g_return_val_if_fail (BZ_IS_ENTRY (entry), FALSE); return bz_entry_is_of_kinds (entry, BZ_ENTRY_KIND_RUNTIME) || bz_entry_is_of_kinds (entry, BZ_ENTRY_KIND_ADDON); } bazaar-orig-v0.7.14/src/bz-gnome-shell-search-provider.h0000664000175000017500000000341115166123241022015 0ustar hasanhasan/* bz-gnome-shell-search-provider.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-search-engine.h" G_BEGIN_DECLS #define BZ_TYPE_GNOME_SHELL_SEARCH_PROVIDER (bz_gnome_shell_search_provider_get_type ()) G_DECLARE_FINAL_TYPE (BzGnomeShellSearchProvider, bz_gnome_shell_search_provider, BZ, GNOME_SHELL_SEARCH_PROVIDER, GObject) BzGnomeShellSearchProvider * bz_gnome_shell_search_provider_new (void); BzSearchEngine * bz_gnome_shell_search_provider_get_engine (BzGnomeShellSearchProvider *self); void bz_gnome_shell_search_provider_set_engine (BzGnomeShellSearchProvider *self, BzSearchEngine *engine); GDBusConnection * bz_gnome_shell_search_provider_get_connection (BzGnomeShellSearchProvider *self); gboolean bz_gnome_shell_search_provider_set_connection (BzGnomeShellSearchProvider *self, GDBusConnection *connection, GError **error); G_END_DECLS /* End of bz-gnome-shell-search-provider.h */ bazaar-orig-v0.7.14/src/bz-env.c0000664000175000017500000000625215166123241015301 0ustar hasanhasan/* bz-env.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-env.h" gsize bz_get_dex_stack_size (void) { static guint64 stack_size = 0; if (g_once_init_enter (&stack_size)) { const char *envvar = NULL; guint64 value = 0; /* Ensure we have enough space for gtk/glycin Some routines try to optimize by putting stuff on the stack, see https://gitlab.gnome.org/GNOME/libdex/-/issues/27#note_2582332 2025-10-21 22:47:02 eva */ value = MAX (8388608, dex_get_min_stack_size ()); envvar = g_getenv ("BAZAAR_DEX_STACK_SIZE"); if (envvar != NULL) { g_autoptr (GError) local_error = NULL; g_autoptr (GVariant) variant = NULL; variant = g_variant_parse ( G_VARIANT_TYPE_UINT64, envvar, NULL, NULL, &local_error); if (variant != NULL) { guint64 parse_result = 0; parse_result = g_variant_get_uint64 (variant); if (parse_result < dex_get_min_stack_size ()) g_warning ("BAZAAR_DEX_STACK_SIZE must be greater than %zu on this system", dex_get_min_stack_size ()); else value = parse_result; } else g_warning ("BAZAAR_DEX_STACK_SIZE is invalid: %s", local_error->message); } g_once_init_leave (&stack_size, value); } return stack_size; } guint64 bz_get_n_download_workers (void) { static guint64 n_dl_workers = 0; if (g_once_init_enter (&n_dl_workers)) { const char *envvar = NULL; guint64 value = 0; value = 8; envvar = g_getenv ("BAZAAR_N_DOWNLOAD_WORKERS"); if (envvar != NULL) { g_autoptr (GError) local_error = NULL; g_autoptr (GVariant) variant = NULL; variant = g_variant_parse ( G_VARIANT_TYPE_UINT64, envvar, NULL, NULL, &local_error); if (variant != NULL) { guint64 parse_result = 0; parse_result = g_variant_get_uint64 (variant); if (parse_result == 0) g_warning ("BAZAAR_N_DOWNLOAD_WORKERS must be greater than 0"); else value = parse_result; } else g_warning ("BAZAAR_N_DOWNLOAD_WORKERS is invalid: %s", local_error->message); } g_once_init_leave (&n_dl_workers, value); } return n_dl_workers; } bazaar-orig-v0.7.14/src/bz-transaction-manager.h0000664000175000017500000000471715166123241020457 0ustar hasanhasan/* bz-transaction-manager.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-backend.h" #include "bz-main-config.h" #include "bz-transaction.h" G_BEGIN_DECLS #define BZ_TRANSACTION_MGR_ERROR (bz_transaction_mgr_error_quark ()) GQuark bz_transaction_mgr_error_quark (void); typedef enum { BZ_TRANSACTION_MGR_ERROR_CANCELLED_BY_HOOK = 0, } BzTransaction_MgrError; #define BZ_TYPE_TRANSACTION_MANAGER (bz_transaction_manager_get_type ()) G_DECLARE_FINAL_TYPE (BzTransactionManager, bz_transaction_manager, BZ, TRANSACTION_MANAGER, GObject) BzTransactionManager * bz_transaction_manager_new (void); void bz_transaction_manager_set_config (BzTransactionManager *self, BzMainConfig *config); BzMainConfig * bz_transaction_manager_get_config (BzTransactionManager *self); void bz_transaction_manager_set_backend (BzTransactionManager *self, BzBackend *backend); BzBackend * bz_transaction_manager_get_backend (BzTransactionManager *self); void bz_transaction_manager_set_paused (BzTransactionManager *self, gboolean paused); gboolean bz_transaction_manager_get_paused (BzTransactionManager *self); gboolean bz_transaction_manager_get_active (BzTransactionManager *self); gboolean bz_transaction_manager_get_pending (BzTransactionManager *self); gboolean bz_transaction_manager_get_has_transactions (BzTransactionManager *self); G_GNUC_WARN_UNUSED_RESULT DexFuture * bz_transaction_manager_add (BzTransactionManager *self, BzTransaction *transaction); void bz_transaction_manager_cancel_current (BzTransactionManager *self); void bz_transaction_manager_clear_finished (BzTransactionManager *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-screenshot-page.h0000664000175000017500000000263215166123241017603 0ustar hasanhasan/* bz-screenshot-page.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-async-texture.h" #include G_BEGIN_DECLS #define BZ_TYPE_SCREENSHOT_PAGE (bz_screenshot_page_get_type ()) G_DECLARE_FINAL_TYPE (BzScreenshotPage, bz_screenshot_page, BZ, SCREENSHOT_PAGE, AdwNavigationPage) AdwNavigationPage *bz_screenshot_page_new (GListModel *screenshots, GListModel *captions, guint initial_index); void bz_screenshot_page_set_captions (BzScreenshotPage *self, GListModel *captions); const char * bz_screenshot_page_get_current_caption (BzScreenshotPage *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-transaction-dialog-result.txt0000664000175000017500000000042415166123241022177 0ustar hasanhasanprefix=bz name=transaction_dialog_result parent-prefix=g parent-name=object author=AUTOGEN include="bz-entry.h" property=selected_entry BzEntry BZ_TYPE_ENTRY object property=delete_user_data gboolean G_TYPE_BOOLEAN boolean property=confirmed gboolean G_TYPE_BOOLEAN boolean bazaar-orig-v0.7.14/src/bz-appstream-parser.h0000664000175000017500000000272715166123241020007 0ustar hasanhasan/* bz-appstream-parser.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry.h" #include #include G_BEGIN_DECLS gboolean bz_appstream_parser_populate_entry (BzEntry *entry, AsComponent *component, const char *appstream_dir, const char *remote_name, const char *module_dir, const char *unique_id_checksum, const char *id, guint kinds, GError **error); G_END_DECLS bazaar-orig-v0.7.14/src/bz-hardware-support-dialog.blp0000664000175000017500000000165015166123241021605 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzHardwareSupportDialog: Adw.Dialog { content-height: 530; content-width: 640; title: _("Hardware Support"); Adw.ToolbarView { [top] Adw.HeaderBar { show-title: false; } content: ScrolledWindow { hscrollbar-policy: never; Adw.Clamp { maximum-size: 600; tightening-threshold: 400; Box { orientation: vertical; spacing: 24; margin-start: 24; margin-end: 24; margin-top: 24; margin-bottom: 24; $BzLozenge lozenge { title: _("Hardware Support"); icon-names: [ "device-supported-symbolic", ]; importance: unimportant; } ListBox list { selection-mode: none; styles [ "boxed-list", ] } } } }; } } bazaar-orig-v0.7.14/src/bz-user-data-page.blp0000664000175000017500000000652715166123241017650 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzUserDataPage: Adw.NavigationPage { title: _("Manage Leftover User Data"); Adw.ToolbarView { [top] Adw.HeaderBar { [end] MenuButton { primary: true; icon-name: "open-menu-symbolic"; has-tooltip: true; tooltip-text: _("Main Menu"); menu-model: menu { section { item { label: _("_Donate to Bazaar ❤️"); action: "app.donate"; } } section { item { label: _("_Refresh"); action: "app.sync-remotes"; } item { label: _("_Preferences"); action: "app.preferences"; } item { label: _("_Login With Flathub"); action: "app.flathub-login"; hidden-when: "action-disabled"; } item { label: _("_Manage Leftover User Data"); action: "window.user-data"; } item { label: _("_Keyboard Shortcuts"); action: "app.shortcuts"; } item { label: _("_About Bazaar"); action: "app.about"; } } section { item { label: _("_Quit Bazaar"); action: "app.quit"; } } }; } } content: Adw.BreakpointBin { width-request: 360; height-request: 450; child: Adw.ViewStack stack { enable-transitions: true; transition-duration: 400; Adw.ViewStackPage { name: "loading"; title: _("Loading"); child:Adw.Spinner { halign: fill; valign: center; width-request: 64; height-request: 64; margin-bottom: 18; }; } Adw.ViewStackPage { name: "empty"; title: _("Empty"); child: Adw.StatusPage { icon-name: "folder-documents-symbolic"; title: _("No User Data Found"); }; } Adw.ViewStackPage { name: "content"; title: _("User Data"); child: ScrolledWindow { hscrollbar-policy: never; child: Adw.ClampScrollable { maximum-size: 650; child: ListView list_view { styles [ "navigation-sidebar", "user-data-list-view" ] margin-start: 25; margin-end: 25; overflow: visible; model: NoSelection { model: bind template.model; }; factory: BuilderListItemFactory { template ListItem { activatable: false; selectable: false; focusable: false; child: $BzUserDataTile { group: bind template.item as <$BzEntryGroup>; }; } }; }; }; }; } }; Adw.Breakpoint { condition ("max-width: 700px") setters { list_view.margin-start: 0; list_view.margin-end: 0; } } }; } } bazaar-orig-v0.7.14/src/bz-error-dialog.blp0000664000175000017500000000277615166123241017441 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzErrorDialog: Adw.Dialog { content-width: 500; content-height: 400; child: Adw.ToastOverlay toast_overlay { child: Adw.ToolbarView { [top] Adw.HeaderBar {} content: Box { orientation: vertical; spacing: 0; margin-start: 24; margin-end: 24; margin-top: 12; margin-bottom: 24; Label error_title { halign: center; styles [ "title-1", ] } Box { orientation: horizontal; spacing: 6; margin-top: 12; margin-bottom: 6; Label { label: _("Details"); halign: start; hexpand: true; styles [ "heading", ] } Button copy_button { icon-name: "edit-copy-symbolic"; tooltip-text: _("Copy"); clicked => $on_copy_button_clicked(); styles [ "flat", ] } } ScrolledWindow { vexpand: true; hscrollbar-policy: automatic; vscrollbar-policy: automatic; TextView text_view { editable: false; wrap-mode: word_char; monospace: true; left-margin: 6; right-margin: 6; top-margin: 6; bottom-margin: 6; styles [ "card", ] } } }; }; }; } bazaar-orig-v0.7.14/src/bz-entry-group.c0000664000175000017500000012267715166123241017016 0ustar hasanhasan/* bz-entry-group.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::ENTRY-GROUP" #define BAZAAR_MODULE "entry-group" #include "bz-entry-group.h" #include "bz-env.h" #include "bz-flatpak-entry.h" #include "bz-io.h" #include "bz-util.h" struct _BzEntryGroup { GObject parent_instance; BzApplicationMapFactory *factory; GtkStringList *unique_ids; GtkStringList *installed_versions; char *id; char *title; char *developer; char *description; GIcon *mini_icon; gboolean is_floss; char *light_accent_color; char *dark_accent_color; gboolean is_flathub; gboolean is_verified; char *search_tokens; char *eol; guint64 installed_size; GtkStringList *addon_group_ids; int n_addons; char *donation_url; BzCategoryFlags categories; int content_age_rating; int max_usefulness; int installable; int updatable; int removable; int installable_available; int updatable_available; int removable_available; gboolean read_only; gboolean searchable; gboolean is_addon; guint64 user_data_size; DexFuture *user_data_size_future; DexFuture *reap_user_data_future; GWeakRef ui_entry; BzResult *standalone_ui_entry; GMutex mutex; }; G_DEFINE_FINAL_TYPE (BzEntryGroup, bz_entry_group, G_TYPE_OBJECT) enum { PROP_0, PROP_MODEL, PROP_INSTALLED_VERSIONS, PROP_ID, PROP_TITLE, PROP_DEVELOPER, PROP_DESCRIPTION, PROP_MINI_ICON, PROP_IS_FLOSS, PROP_LIGHT_ACCENT_COLOR, PROP_DARK_ACCENT_COLOR, PROP_IS_FLATHUB, PROP_IS_VERIFIED, PROP_SEARCH_TOKENS, PROP_UI_ENTRY, PROP_EOL, PROP_INSTALLED_SIZE, PROP_N_ADDONS, PROP_DONATION_URL, PROP_CATEGORIES, PROP_INSTALLABLE, PROP_UPDATABLE, PROP_REMOVABLE, PROP_INSTALLABLE_AND_AVAILABLE, PROP_UPDATABLE_AND_AVAILABLE, PROP_REMOVABLE_AND_AVAILABLE, PROP_USER_DATA_SIZE, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void installed_changed (BzEntryGroup *self, GParamSpec *pspec, BzEntry *entry); static void holding_changed (BzEntryGroup *self, GParamSpec *pspec, BzEntry *entry); static DexFuture * dup_all_into_store_fiber (BzEntryGroup *self); static DexFuture * user_data_size_then (DexFuture *future, GWeakRef *wr); static void check_user_data_size (BzEntryGroup *self); static void bz_entry_group_dispose (GObject *object) { BzEntryGroup *self = BZ_ENTRY_GROUP (object); dex_clear (&self->user_data_size_future); dex_clear (&self->reap_user_data_future); g_clear_object (&self->factory); g_clear_object (&self->unique_ids); g_clear_object (&self->installed_versions); g_clear_pointer (&self->id, g_free); g_clear_pointer (&self->title, g_free); g_clear_pointer (&self->developer, g_free); g_clear_pointer (&self->description, g_free); g_clear_pointer (&self->light_accent_color, g_free); g_clear_pointer (&self->dark_accent_color, g_free); g_clear_object (&self->mini_icon); g_clear_pointer (&self->search_tokens, g_free); g_clear_pointer (&self->eol, g_free); g_clear_pointer (&self->donation_url, g_free); g_weak_ref_clear (&self->ui_entry); g_clear_object (&self->standalone_ui_entry); g_mutex_clear (&self->mutex); G_OBJECT_CLASS (bz_entry_group_parent_class)->dispose (object); } static void bz_entry_group_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzEntryGroup *self = BZ_ENTRY_GROUP (object); switch (prop_id) { case PROP_MODEL: g_value_set_object (value, bz_entry_group_get_model (self)); break; case PROP_INSTALLED_VERSIONS: g_value_set_object (value, bz_entry_group_get_installed_versions (self)); break; case PROP_ID: g_value_set_string (value, bz_entry_group_get_id (self)); break; case PROP_TITLE: g_value_set_string (value, bz_entry_group_get_title (self)); break; case PROP_DEVELOPER: g_value_set_string (value, bz_entry_group_get_developer (self)); break; case PROP_DESCRIPTION: g_value_set_string (value, bz_entry_group_get_description (self)); break; case PROP_MINI_ICON: g_value_set_object (value, bz_entry_group_get_mini_icon (self)); break; case PROP_IS_FLOSS: g_value_set_boolean (value, bz_entry_group_get_is_floss (self)); break; case PROP_LIGHT_ACCENT_COLOR: g_value_set_string (value, bz_entry_group_get_light_accent_color (self)); break; case PROP_DARK_ACCENT_COLOR: g_value_set_string (value, bz_entry_group_get_dark_accent_color (self)); break; case PROP_IS_FLATHUB: g_value_set_boolean (value, bz_entry_group_get_is_flathub (self)); break; case PROP_IS_VERIFIED: g_value_set_boolean (value, bz_entry_group_get_is_verified (self)); break; case PROP_SEARCH_TOKENS: g_value_set_boxed (value, bz_entry_group_get_search_tokens (self)); break; case PROP_EOL: g_value_set_string (value, bz_entry_group_get_eol (self)); break; case PROP_INSTALLED_SIZE: g_value_set_uint64 (value, bz_entry_group_get_installed_size (self)); break; case PROP_N_ADDONS: g_value_set_int (value, bz_entry_group_get_n_addons (self)); break; case PROP_DONATION_URL: g_value_set_string (value, bz_entry_group_get_donation_url (self)); break; case PROP_CATEGORIES: g_value_set_uint (value, self->categories); break; case PROP_UI_ENTRY: g_value_take_object (value, bz_entry_group_dup_ui_entry (self)); break; case PROP_INSTALLABLE: g_value_set_int (value, bz_entry_group_get_installable (self)); break; case PROP_UPDATABLE: g_value_set_int (value, bz_entry_group_get_updatable (self)); break; case PROP_REMOVABLE: g_value_set_int (value, bz_entry_group_get_removable (self)); break; case PROP_INSTALLABLE_AND_AVAILABLE: g_value_set_int (value, bz_entry_group_get_installable_and_available (self)); break; case PROP_UPDATABLE_AND_AVAILABLE: g_value_set_int (value, bz_entry_group_get_updatable_and_available (self)); break; case PROP_REMOVABLE_AND_AVAILABLE: g_value_set_int (value, bz_entry_group_get_removable_and_available (self)); break; case PROP_USER_DATA_SIZE: g_value_set_uint64 (value, bz_entry_group_get_user_data_size (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_entry_group_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { // BzEntryGroup *self = BZ_ENTRY_GROUP (object); switch (prop_id) { case PROP_MODEL: case PROP_ID: case PROP_TITLE: case PROP_DEVELOPER: case PROP_DESCRIPTION: case PROP_MINI_ICON: case PROP_IS_FLOSS: case PROP_LIGHT_ACCENT_COLOR: case PROP_DARK_ACCENT_COLOR: case PROP_IS_FLATHUB: case PROP_IS_VERIFIED: case PROP_SEARCH_TOKENS: case PROP_EOL: case PROP_UI_ENTRY: case PROP_INSTALLABLE: case PROP_UPDATABLE: case PROP_REMOVABLE: case PROP_INSTALLABLE_AND_AVAILABLE: case PROP_UPDATABLE_AND_AVAILABLE: case PROP_REMOVABLE_AND_AVAILABLE: case PROP_USER_DATA_SIZE: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_entry_group_class_init (BzEntryGroupClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bz_entry_group_set_property; object_class->get_property = bz_entry_group_get_property; object_class->dispose = bz_entry_group_dispose; props[PROP_MODEL] = g_param_spec_object ( "model", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READABLE); props[PROP_INSTALLED_VERSIONS] = g_param_spec_object ( "installed-versions", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READABLE); props[PROP_ID] = g_param_spec_string ( "id", NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_TITLE] = g_param_spec_string ( "title", NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_DEVELOPER] = g_param_spec_string ( "developer", NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_DESCRIPTION] = g_param_spec_string ( "description", NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_MINI_ICON] = g_param_spec_object ( "mini-icon", NULL, NULL, G_TYPE_ICON, G_PARAM_READABLE); props[PROP_IS_FLOSS] = g_param_spec_boolean ( "is-floss", NULL, NULL, FALSE, G_PARAM_READABLE); props[PROP_LIGHT_ACCENT_COLOR] = g_param_spec_string ( "light-accent-color", NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_DARK_ACCENT_COLOR] = g_param_spec_string ( "dark-accent-color", NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_IS_FLATHUB] = g_param_spec_boolean ( "is-flathub", NULL, NULL, FALSE, G_PARAM_READABLE); props[PROP_IS_VERIFIED] = g_param_spec_boolean ( "is-verified", NULL, NULL, FALSE, G_PARAM_READABLE); props[PROP_SEARCH_TOKENS] = g_param_spec_string ( "search-tokens", NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_EOL] = g_param_spec_string ( "eol", NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_INSTALLED_SIZE] = g_param_spec_uint64 ( "installed-size", NULL, NULL, 0, G_MAXUINT64, 0, G_PARAM_READABLE); props[PROP_N_ADDONS] = g_param_spec_int ( "n-addons", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READABLE); props[PROP_DONATION_URL] = g_param_spec_string ( "donation-url", NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_CATEGORIES] = g_param_spec_uint ( "categories", NULL, NULL, 0, G_MAXUINT, BZ_CATEGORY_FLAGS_NONE, G_PARAM_READABLE); props[PROP_UI_ENTRY] = g_param_spec_object ( "ui-entry", NULL, NULL, BZ_TYPE_RESULT, G_PARAM_READABLE); props[PROP_INSTALLABLE] = g_param_spec_int ( "installable", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READABLE); props[PROP_UPDATABLE] = g_param_spec_int ( "updatable", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READABLE); props[PROP_REMOVABLE] = g_param_spec_int ( "removable", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READABLE); props[PROP_INSTALLABLE_AND_AVAILABLE] = g_param_spec_int ( "installable-and-available", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READABLE); props[PROP_UPDATABLE_AND_AVAILABLE] = g_param_spec_int ( "updatable-and-available", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READABLE); props[PROP_REMOVABLE_AND_AVAILABLE] = g_param_spec_int ( "removable-and-available", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READABLE); props[PROP_USER_DATA_SIZE] = g_param_spec_uint64 ( "user-data-size", NULL, NULL, 0, G_MAXUINT64, 0, G_PARAM_READABLE); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_entry_group_init (BzEntryGroup *self) { self->unique_ids = gtk_string_list_new (NULL); self->installed_versions = gtk_string_list_new (NULL); self->max_usefulness = -1; g_weak_ref_init (&self->ui_entry, NULL); self->standalone_ui_entry = NULL; g_mutex_init (&self->mutex); } BzEntryGroup * bz_entry_group_new (BzApplicationMapFactory *factory) { BzEntryGroup *group = NULL; g_return_val_if_fail (BZ_IS_APPLICATION_MAP_FACTORY (factory), NULL); group = g_object_new (BZ_TYPE_ENTRY_GROUP, NULL); group->factory = g_object_ref (factory); return group; } BzEntryGroup * bz_entry_group_new_for_single_entry (BzEntry *entry) { BzEntryGroup *group = NULL; const char *id = NULL; const char *unique_id = NULL; const char *title = NULL; const char *developer = NULL; const char *description = NULL; GIcon *mini_icon = NULL; const char *search_tokens = NULL; gboolean is_floss = FALSE; const char *light_accent_color = NULL; const char *dark_accent_color = NULL; gboolean is_flathub = FALSE; gboolean is_verified = FALSE; const char *eol = NULL; guint64 installed_size = 0; const char *donation_url = NULL; BzCategoryFlags entry_categories = BZ_CATEGORY_FLAGS_NONE; DexFuture *future = NULL; g_return_val_if_fail (BZ_IS_ENTRY (entry), NULL); group = g_object_new (BZ_TYPE_ENTRY_GROUP, NULL); id = bz_entry_get_id (entry); unique_id = bz_entry_get_unique_id (entry); title = bz_entry_get_title (entry); developer = bz_entry_get_developer (entry); description = bz_entry_get_description (entry); mini_icon = bz_entry_get_mini_icon (entry); search_tokens = bz_entry_get_search_tokens (entry); is_floss = bz_entry_get_is_foss (entry); light_accent_color = bz_entry_get_light_accent_color (entry); dark_accent_color = bz_entry_get_dark_accent_color (entry); is_flathub = bz_entry_get_is_flathub (entry); is_verified = bz_entry_is_verified (entry); eol = bz_entry_get_eol (entry); installed_size = bz_entry_get_installed_size (entry); donation_url = bz_entry_get_donation_url (entry); entry_categories = bz_entry_get_category_flags (entry); if (id != NULL) group->id = g_strdup (id); if (title != NULL) group->title = g_strdup (title); if (developer != NULL) group->developer = g_strdup (developer); if (description != NULL) group->description = g_strdup (description); if (mini_icon != NULL) group->mini_icon = g_object_ref (mini_icon); if (search_tokens != NULL) group->search_tokens = g_strdup (search_tokens); group->is_floss = is_floss; if (light_accent_color != NULL) group->light_accent_color = g_strdup (light_accent_color); if (dark_accent_color != NULL) group->dark_accent_color = g_strdup (dark_accent_color); group->is_flathub = is_flathub; group->is_verified = is_verified; if (eol != NULL) group->eol = g_strdup (eol); group->installed_size = installed_size; if (donation_url != NULL) group->donation_url = g_strdup (donation_url); group->categories = entry_categories; if (unique_id != NULL) gtk_string_list_append (group->unique_ids, unique_id); future = dex_future_new_for_object (entry); group->standalone_ui_entry = bz_result_new (future); dex_unref (future); return group; } GMutexLocker * bz_entry_group_lock (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); return g_mutex_locker_new (&self->mutex); } GListModel * bz_entry_group_get_model (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); return G_LIST_MODEL (self->unique_ids); } GListModel * bz_entry_group_get_installed_versions (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); return G_LIST_MODEL (self->installed_versions); } const char * bz_entry_group_get_id (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); return self->id; } const char * bz_entry_group_get_title (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); return self->title; } const char * bz_entry_group_get_developer (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); return self->developer; } const char * bz_entry_group_get_description (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); return self->description; } GIcon * bz_entry_group_get_mini_icon (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); return self->mini_icon; } gboolean bz_entry_group_get_is_floss (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), FALSE); return self->is_floss; } const char * bz_entry_group_get_light_accent_color (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); return self->light_accent_color; } const char * bz_entry_group_get_dark_accent_color (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); return self->dark_accent_color; } gboolean bz_entry_group_get_is_flathub (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), FALSE); return self->is_flathub; } gboolean bz_entry_group_get_is_verified (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), FALSE); return self->is_verified; } const char * bz_entry_group_get_search_tokens (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); return self->search_tokens; } const char * bz_entry_group_get_eol (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); return self->eol; } guint64 bz_entry_group_get_installed_size (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), 0); return self->installed_size; } GListModel * bz_entry_group_get_addon_group_ids (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); if (self->addon_group_ids == NULL) return NULL; return G_LIST_MODEL (self->addon_group_ids); } void bz_entry_group_append_addon_group_id (BzEntryGroup *self, const char *id) { g_return_if_fail (BZ_IS_ENTRY_GROUP (self)); g_return_if_fail (id != NULL); if (self->addon_group_ids == NULL) self->addon_group_ids = gtk_string_list_new (NULL); if (gtk_string_list_find (self->addon_group_ids, id) != G_MAXUINT) return; gtk_string_list_append (self->addon_group_ids, id); } int bz_entry_group_get_n_addons (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), 0); return self->n_addons; } const char * bz_entry_group_get_donation_url (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); return self->donation_url; } gboolean bz_entry_group_has_category (BzEntryGroup *self, const char *name) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), FALSE); return bz_category_flags_has_name (self->categories, name); } BzCategoryFlags bz_entry_group_get_categories (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), BZ_CATEGORY_FLAGS_NONE); return self->categories; } int bz_entry_group_get_content_age_rating (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), 0); return self->content_age_rating; } guint64 bz_entry_group_get_user_data_size (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), 0); check_user_data_size (self); return self->user_data_size; } BzResult * bz_entry_group_dup_ui_entry (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); if (self->standalone_ui_entry != NULL) return g_object_ref (self->standalone_ui_entry); if (g_list_model_get_n_items (G_LIST_MODEL (self->unique_ids)) > 0) { g_autoptr (BzResult) result = NULL; result = g_weak_ref_get (&self->ui_entry); if (result == NULL) { g_autoptr (GtkStringObject) id = NULL; id = g_list_model_get_item (G_LIST_MODEL (self->unique_ids), 0); result = bz_application_map_factory_convert_one (self->factory, g_steal_pointer (&id)); if (result == NULL) return NULL; g_weak_ref_set (&self->ui_entry, result); } return g_steal_pointer (&result); } else return NULL; } char * bz_entry_group_dup_ui_entry_id (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); if (g_list_model_get_n_items (G_LIST_MODEL (self->unique_ids)) > 0) { g_autoptr (GtkStringObject) id = NULL; id = g_list_model_get_item (G_LIST_MODEL (self->unique_ids), 0); return g_strdup (gtk_string_object_get_string (id)); } else return NULL; } int bz_entry_group_get_installable (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), 0); if (self->read_only) return 0; return self->installable; } int bz_entry_group_get_updatable (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), 0); return self->updatable; } int bz_entry_group_get_removable (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), 0); if (self->read_only) return 0; return self->removable; } int bz_entry_group_get_installable_and_available (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), 0); return self->installable_available; } int bz_entry_group_get_updatable_and_available (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), 0); return self->updatable_available; } int bz_entry_group_get_removable_and_available (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), 0); return self->removable_available; } gboolean bz_entry_group_is_searchable (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), TRUE); return self->searchable; } gboolean bz_entry_group_is_addon (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), FALSE); return self->is_addon; } void bz_entry_group_add (BzEntryGroup *self, BzEntry *entry, BzEntry *runtime, gboolean ignore_eol) { g_autoptr (GMutexLocker) locker = NULL; const char *unique_id = NULL; const char *installed_version = NULL; gint usefulness = 0; const char *eol = NULL; const char *title = NULL; const char *developer = NULL; const char *description = NULL; GIcon *mini_icon = NULL; const char *search_tokens = NULL; gboolean is_floss = FALSE; const char *light_accent_color = NULL; const char *dark_accent_color = NULL; gboolean is_flathub = FALSE; gboolean is_verified = FALSE; guint64 installed_size = 0; GListModel *addons = NULL; int n_addons = 0; const char *donation_url = NULL; BzCategoryFlags entry_categories = BZ_CATEGORY_FLAGS_NONE; guint existing = 0; gboolean is_searchable = FALSE; AsContentRating *content_rating = NULL; gboolean is_addon = FALSE; g_return_if_fail (BZ_IS_ENTRY_GROUP (self)); g_return_if_fail (BZ_IS_ENTRY (entry)); g_return_if_fail (runtime == NULL || BZ_IS_ENTRY (runtime)); locker = g_mutex_locker_new (&self->mutex); is_addon = bz_entry_is_of_kinds (entry, BZ_ENTRY_KIND_ADDON); if (is_addon) self->is_addon = TRUE; if (self->id == NULL) { self->id = g_strdup (bz_entry_get_id (entry)); self->read_only = g_strcmp0 (self->id, g_application_get_application_id (g_application_get_default ())) == 0; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ID]); } unique_id = bz_entry_get_unique_id (entry); installed_version = bz_entry_get_installed_version (entry); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INSTALLED_VERSIONS]); if (!ignore_eol) { eol = bz_entry_get_eol (entry); if (eol == NULL && runtime != NULL) eol = bz_entry_get_eol (runtime); if (eol != NULL) { g_clear_pointer (&self->eol, g_free); self->eol = g_strdup (eol); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_EOL]); } } title = bz_entry_get_title (entry); description = bz_entry_get_description (entry); installed_size = bz_entry_get_installed_size (entry); is_flathub = bz_entry_get_is_flathub (entry); is_floss = bz_entry_get_is_foss (entry); if (is_addon) // You would not see any addon when the filter is on without this. is_verified = TRUE; if (!is_addon) { developer = bz_entry_get_developer (entry); mini_icon = bz_entry_get_mini_icon (entry); search_tokens = bz_entry_get_search_tokens (entry); light_accent_color = bz_entry_get_light_accent_color (entry); dark_accent_color = bz_entry_get_dark_accent_color (entry); is_verified = bz_entry_is_verified (entry); donation_url = bz_entry_get_donation_url (entry); entry_categories = bz_entry_get_category_flags (entry); content_rating = bz_entry_get_content_rating (entry); addons = bz_entry_get_addons (entry); is_searchable = bz_entry_is_searchable (entry); if (addons != NULL) n_addons = g_list_model_get_n_items (addons); } usefulness = bz_entry_calc_usefulness (entry); existing = gtk_string_list_find (self->unique_ids, unique_id); if (usefulness >= self->max_usefulness) { if (existing != G_MAXUINT) { gtk_string_list_remove (self->unique_ids, existing); gtk_string_list_remove (self->installed_versions, existing); } gtk_string_list_splice (self->unique_ids, 0, 0, (const char *const[]) { unique_id, NULL }); gtk_string_list_splice (self->installed_versions, 0, 0, (const char *const[]) { installed_version != NULL ? installed_version : "", NULL }); if (title != NULL) { g_clear_pointer (&self->title, g_free); self->title = g_strdup (title); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TITLE]); } if (description != NULL) { g_clear_pointer (&self->description, g_free); self->description = g_strdup (description); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DESCRIPTION]); } if (installed_size != self->installed_size) { self->installed_size = installed_size; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INSTALLED_SIZE]); } if (!!is_flathub != !!self->is_flathub) { self->is_flathub = is_flathub; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_IS_FLATHUB]); } if (!!is_floss != !!self->is_floss) { self->is_floss = is_floss; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_IS_FLOSS]); } if (!!is_verified != !!self->is_verified) { self->is_verified = is_verified; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_IS_VERIFIED]); } if (!is_addon) { if (developer != NULL) { g_clear_pointer (&self->developer, g_free); self->developer = g_strdup (developer); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DEVELOPER]); } if (mini_icon != NULL) { g_clear_object (&self->mini_icon); self->mini_icon = g_object_ref (mini_icon); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MINI_ICON]); } if (search_tokens != NULL) { g_clear_pointer (&self->search_tokens, g_free); self->search_tokens = g_strdup (search_tokens); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SEARCH_TOKENS]); } if (light_accent_color != NULL) { g_clear_pointer (&self->light_accent_color, g_free); self->light_accent_color = g_strdup (light_accent_color); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_LIGHT_ACCENT_COLOR]); } if (dark_accent_color != NULL) { g_clear_pointer (&self->dark_accent_color, g_free); self->dark_accent_color = g_strdup (dark_accent_color); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DARK_ACCENT_COLOR]); } if (n_addons != self->n_addons) { self->n_addons = n_addons; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_N_ADDONS]); } if (donation_url != NULL) { g_clear_pointer (&self->donation_url, g_free); self->donation_url = g_strdup (donation_url); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DONATION_URL]); } if (entry_categories != BZ_CATEGORY_FLAGS_NONE) { self->categories = entry_categories; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CATEGORIES]); } if (content_rating != NULL) self->content_age_rating = as_content_rating_get_minimum_age (content_rating); } self->max_usefulness = usefulness; } else { if (existing == G_MAXUINT) { gtk_string_list_append (self->unique_ids, unique_id); gtk_string_list_append (self->installed_versions, installed_version != NULL ? installed_version : ""); } if (title != NULL && self->title == NULL) { self->title = g_strdup (title); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TITLE]); } if (description != NULL && self->description == NULL) { self->description = g_strdup (description); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DESCRIPTION]); } if (installed_size > 0 && self->installed_size == 0) { self->installed_size = installed_size; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INSTALLED_SIZE]); } if (!is_addon) { if (developer != NULL && self->developer == NULL) { self->developer = g_strdup (developer); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DEVELOPER]); } if (mini_icon != NULL && self->mini_icon == NULL) { self->mini_icon = g_object_ref (mini_icon); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MINI_ICON]); } if (search_tokens != NULL && self->search_tokens == NULL) { self->search_tokens = g_strdup (search_tokens); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SEARCH_TOKENS]); } if (light_accent_color != NULL && self->light_accent_color == NULL) { self->light_accent_color = g_strdup (light_accent_color); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_LIGHT_ACCENT_COLOR]); } if (dark_accent_color != NULL && self->dark_accent_color == NULL) { self->dark_accent_color = g_strdup (dark_accent_color); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DARK_ACCENT_COLOR]); } if (donation_url != NULL && self->donation_url == NULL) { self->donation_url = g_strdup (donation_url); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DONATION_URL]); } } } if (existing == G_MAXUINT) { if (bz_entry_is_installed (entry)) { self->removable++; if (!bz_entry_is_holding (entry)) { self->removable_available++; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_REMOVABLE_AND_AVAILABLE]); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_REMOVABLE]); } else { gboolean is_installed_ref = FALSE; if (BZ_IS_FLATPAK_ENTRY (entry)) is_installed_ref = bz_flatpak_entry_is_installed_ref (BZ_FLATPAK_ENTRY (entry)); if (!is_installed_ref) { self->installable++; if (!bz_entry_is_holding (entry)) { self->installable_available++; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INSTALLABLE_AND_AVAILABLE]); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INSTALLABLE]); } } } if (!is_addon && is_searchable && !self->searchable) self->searchable = TRUE; } void bz_entry_group_connect_living (BzEntryGroup *self, BzEntry *entry) { g_autoptr (GMutexLocker) locker = NULL; g_return_if_fail (BZ_IS_ENTRY_GROUP (self)); g_return_if_fail (BZ_IS_ENTRY (entry)); locker = g_mutex_locker_new (&self->mutex); g_signal_handlers_disconnect_by_func (entry, installed_changed, self); g_signal_handlers_disconnect_by_func (entry, holding_changed, self); g_signal_connect_object (entry, "notify::installed", G_CALLBACK (installed_changed), self, G_CONNECT_SWAPPED); g_signal_connect_object (entry, "notify::holding", G_CALLBACK (holding_changed), self, G_CONNECT_SWAPPED); } DexFuture * bz_entry_group_dup_all_into_store (BzEntryGroup *self) { g_return_val_if_fail (BZ_IS_ENTRY_GROUP (self), NULL); /* _must_ be the main scheduler since invokations * of BzApplicationMapFactory functions expect this */ return dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) dup_all_into_store_fiber, g_object_ref (self), g_object_unref); } static void installed_changed (BzEntryGroup *self, GParamSpec *pspec, BzEntry *entry) { g_autoptr (GMutexLocker) locker = NULL; gboolean is_installed_ref = FALSE; const char *unique_id = NULL; const char *version = NULL; guint index = 0; locker = g_mutex_locker_new (&self->mutex); if (BZ_IS_FLATPAK_ENTRY (entry)) is_installed_ref = bz_flatpak_entry_is_installed_ref (BZ_FLATPAK_ENTRY (entry)); unique_id = bz_entry_get_unique_id (entry); version = bz_entry_get_installed_version (entry); index = gtk_string_list_find (self->unique_ids, unique_id); if (index != G_MAXUINT) { gtk_string_list_splice (self->installed_versions, index, 1, (const char *const[]) { version != NULL ? version : "", NULL }); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INSTALLED_VERSIONS]); if (bz_entry_is_installed (entry)) { self->installable--; self->removable++; if (!bz_entry_is_holding (entry)) { self->installable_available--; self->removable_available++; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INSTALLABLE_AND_AVAILABLE]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_REMOVABLE_AND_AVAILABLE]); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INSTALLABLE]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_REMOVABLE]); } else { self->removable--; if (!is_installed_ref) self->installable++; if (!bz_entry_is_holding (entry)) { self->removable_available--; if (!is_installed_ref) self->installable_available++; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_REMOVABLE_AND_AVAILABLE]); if (!is_installed_ref) g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INSTALLABLE_AND_AVAILABLE]); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_REMOVABLE]); if (!is_installed_ref) g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INSTALLABLE]); } dex_clear (&self->user_data_size_future); self->user_data_size = 0; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_USER_DATA_SIZE]); } static void holding_changed (BzEntryGroup *self, GParamSpec *pspec, BzEntry *entry) { g_autoptr (GMutexLocker) locker = NULL; locker = g_mutex_locker_new (&self->mutex); if (bz_entry_is_holding (entry)) { if (bz_entry_is_installed (entry)) self->removable_available--; else self->installable_available--; } else { if (bz_entry_is_installed (entry)) self->removable_available++; else self->installable_available++; } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_REMOVABLE_AND_AVAILABLE]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INSTALLABLE_AND_AVAILABLE]); } static DexFuture * dup_all_into_store_fiber (BzEntryGroup *self) { g_autoptr (GPtrArray) futures = NULL; guint n_items = 0; g_autoptr (GListStore) store = NULL; guint n_resolved = 0; futures = g_ptr_array_new_with_free_func (dex_unref); n_items = g_list_model_get_n_items (G_LIST_MODEL (self->unique_ids)); for (guint i = 0; i < n_items; i++) { g_autoptr (GtkStringObject) string = NULL; g_autoptr (BzResult) result = NULL; string = g_list_model_get_item (G_LIST_MODEL (self->unique_ids), i); result = bz_application_map_factory_convert_one (self->factory, g_steal_pointer (&string)); g_ptr_array_add (futures, bz_result_dup_future (result)); } dex_await (dex_future_allv ( (DexFuture *const *) futures->pdata, futures->len), NULL); store = g_list_store_new (BZ_TYPE_ENTRY); for (guint i = 0; i < futures->len; i++) { DexFuture *future = NULL; future = g_ptr_array_index (futures, i); if (dex_future_is_resolved (future)) { BzEntry *entry = NULL; entry = g_value_get_object (dex_future_get_value (future, NULL)); bz_entry_group_connect_living (self, entry); g_list_store_append (store, entry); } } n_resolved = g_list_model_get_n_items (G_LIST_MODEL (store)); if (n_resolved == 0) { g_warning ("No entries for %s were able to be resolved", self->id); return dex_future_new_reject ( G_IO_ERROR, G_IO_ERROR_UNKNOWN, "No entries for %s were able to be resolved", self->id); } if (n_resolved != n_items) g_warning ("Some entries for %s failed to resolve", self->id); return dex_future_new_for_object (store); } static DexFuture * reap_user_data_then (DexFuture *future, GWeakRef *wr) { g_autoptr (BzEntryGroup) self = NULL; guint64 old_size = 0; bz_weak_get_or_return_reject (self, wr); dex_clear (&self->reap_user_data_future); old_size = self->user_data_size; self->user_data_size = 0; if (old_size != 0) g_object_notify_by_pspec (G_OBJECT (self), props[PROP_USER_DATA_SIZE]); return dex_future_new_true (); } void bz_entry_group_reap_user_data (BzEntryGroup *self) { g_return_if_fail (BZ_IS_ENTRY_GROUP (self)); g_return_if_fail (self->id != NULL); if (self->reap_user_data_future != NULL) return; self->reap_user_data_future = dex_future_then ( bz_reap_user_data_dex (self->id), (DexFutureCallback) reap_user_data_then, bz_track_weak (self), bz_weak_release); } static DexFuture * user_data_size_then (DexFuture *future, GWeakRef *wr) { g_autoptr (BzEntryGroup) self = NULL; g_autoptr (GError) error = NULL; guint64 size = 0; guint64 old_size = 0; bz_weak_get_or_return_reject (self, wr); dex_clear (&self->user_data_size_future); size = dex_await_uint64 (dex_ref (future), &error); if (error != NULL) size = 0; old_size = self->user_data_size; self->user_data_size = size; if (old_size != size) g_object_notify_by_pspec (G_OBJECT (self), props[PROP_USER_DATA_SIZE]); return dex_future_new_true (); } static void check_user_data_size (BzEntryGroup *self) { g_autoptr (DexFuture) future = NULL; if (self->user_data_size_future != NULL || self->id == NULL) return; if (self->reap_user_data_future != NULL) return; future = bz_get_user_data_size_dex (self->id); future = dex_future_then ( future, (DexFutureCallback) user_data_size_then, bz_track_weak (self), bz_weak_release); self->user_data_size_future = g_steal_pointer (&future); } bazaar-orig-v0.7.14/src/bz-curated-category-info.txt0000664000175000017500000000140115166123241021270 0ustar hasanhasanprefix=bz name=curated_category_info parent-prefix=g parent-name=object author=AUTOGEN include= property=title char G_TYPE_STRING string property=subtitle char G_TYPE_STRING string property=description char G_TYPE_STRING string property=banner char G_TYPE_STRING string property=light_banner char G_TYPE_STRING string property=dark_banner char G_TYPE_STRING string property=banner_height int G_TYPE_INT int property=banner_fit GtkContentFit GTK_TYPE_CONTENT_FIT enum property=banner_text_halign GtkAlign GTK_TYPE_ALIGN enum property=banner_text_valign GtkAlign GTK_TYPE_ALIGN enum property=banner_text_label_xalign double G_TYPE_DOUBLE double property=appids GListModel G_TYPE_LIST_MODEL object property=enable_bulk_install gboolean G_TYPE_BOOLEAN boolean bazaar-orig-v0.7.14/src/bz-search-pill-list.h0000664000175000017500000000201115166123241017657 0ustar hasanhasan/* bz-search-pill-list.h * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_SEARCH_PILL_LIST (bz_search_pill_list_get_type ()) G_DECLARE_FINAL_TYPE (BzSearchPillList, bz_search_pill_list, BZ, SEARCH_PILL_LIST, GtkBox) GtkWidget *bz_search_pill_list_new (void); G_END_DECLS bazaar-orig-v0.7.14/src/bz-application.h0000664000175000017500000000202215166123241017010 0ustar hasanhasan/* bz-application.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-state-info.h" G_BEGIN_DECLS #define BZ_TYPE_APPLICATION (bz_application_get_type ()) G_DECLARE_FINAL_TYPE (BzApplication, bz_application, BZ, APPLICATION, AdwApplication) BzStateInfo * bz_state_info_get_default (void); G_END_DECLS bazaar-orig-v0.7.14/src/bz-category-tile.h0000664000175000017500000000235615166123241017267 0ustar hasanhasan/* bz-category-tile.h * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-flathub-category.h" G_BEGIN_DECLS #define BZ_TYPE_CATEGORY_TILE (bz_category_tile_get_type ()) G_DECLARE_FINAL_TYPE (BzCategoryTile, bz_category_tile, BZ, CATEGORY_TILE, GtkButton) GtkWidget * bz_category_tile_new (void); BzFlathubCategory * bz_category_tile_get_category (BzCategoryTile *self); void bz_category_tile_set_category (BzCategoryTile *self, BzFlathubCategory *category); G_END_DECLSbazaar-orig-v0.7.14/src/main.c0000664000175000017500000000342415166123241015022 0ustar hasanhasan/* main.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::MAIN" #include "config.h" #include #include #include #include "bz-application.h" int main (int argc, char *argv[]) { g_autoptr (BzApplication) app = NULL; int result = 0; if (argc > 1 && g_strcmp0 (argv[1], "--version") == 0) { g_print ("%s\n", PACKAGE_VERSION); return 0; } g_debug ("Initializing libdex..."); dex_init (); g_debug ("Configuring textdomain..."); bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); /* Init Bazaar GTK Extensions */ bge_init(); g_debug ("Constructing main application object..."); app = g_object_new ( BZ_TYPE_APPLICATION, "application-id", "io.github.kolunmi.Bazaar", "flags", G_APPLICATION_HANDLES_COMMAND_LINE, "resource-base-path", "/io/github/kolunmi/Bazaar", NULL); g_debug ("Running!"); result = g_application_run (G_APPLICATION (app), argc, argv); return result; } bazaar-orig-v0.7.14/src/bz-linear-function.txt0000664000175000017500000000025615166123241020201 0ustar hasanhasanprefix=bz name=linear_function parent-prefix=g parent-name=object author=AUTOGEN property=slope double G_TYPE_DOUBLE double property=y_intercept double G_TYPE_DOUBLE double bazaar-orig-v0.7.14/src/bz-comet-overlay.c0000664000175000017500000004405715166123241017304 0ustar hasanhasan/* bz-comet-overlay.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-comet-overlay.h" typedef struct { double x; double y; double progress; } PulseState; struct _BzCometOverlay { GtkWidget parent_instance; GtkWidget *child; GHashTable *nodes; GArray *pulses; GdkRGBA *pulse_color; }; G_DEFINE_FINAL_TYPE (BzCometOverlay, bz_comet_overlay, GTK_TYPE_WIDGET) enum { PROP_0, PROP_CHILD, PROP_PULSE_COLOR, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void progress_changed (BzComet *comet, GParamSpec *pspec, BzCometOverlay *self); static void animation_done (AdwAnimation *animation, BzCometOverlay *self); static void update_params (BzCometOverlay *self, BzComet *comet, int width, int height); static void pulse_cb (double value, GtkWidget *widget); static void append_pulse (GtkSnapshot *snapshot, double size, double opacity, GdkRGBA *color); static void bz_comet_overlay_dispose (GObject *object) { BzCometOverlay *self = BZ_COMET_OVERLAY (object); g_clear_pointer (&self->child, gtk_widget_unparent); g_clear_pointer (&self->nodes, g_hash_table_unref); g_clear_pointer (&self->pulses, g_array_unref); g_clear_pointer (&self->pulse_color, gdk_rgba_free); G_OBJECT_CLASS (bz_comet_overlay_parent_class)->dispose (object); } static void bz_comet_overlay_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzCometOverlay *self = BZ_COMET_OVERLAY (object); switch (prop_id) { case PROP_CHILD: g_value_set_object (value, bz_comet_overlay_get_child (self)); break; case PROP_PULSE_COLOR: g_value_set_boxed (value, bz_comet_overlay_get_pulse_color (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_comet_overlay_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzCometOverlay *self = BZ_COMET_OVERLAY (object); switch (prop_id) { case PROP_CHILD: bz_comet_overlay_set_child (self, g_value_get_object (value)); break; case PROP_PULSE_COLOR: bz_comet_overlay_set_pulse_color (self, g_value_get_boxed (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_comet_overlay_size_allocate (GtkWidget *widget, int width, int height, int baseline) { BzCometOverlay *self = BZ_COMET_OVERLAY (widget); // GHashTableIter iter = { 0 }; if (self->child != NULL && gtk_widget_should_layout (self->child)) gtk_widget_allocate (self->child, width, height, baseline, NULL); /* This causes visual hiccups, keeping for reference */ // g_hash_table_iter_init (&iter, self->nodes); // for (;;) // { // BzComet *comet = NULL; // GskRenderNode *node = NULL; // // if (!g_hash_table_iter_next ( // &iter, (gpointer *) &comet, (gpointer *) &node)) // break; // // update_params (self, comet, width, height); // } } static void bz_comet_overlay_snapshot (GtkWidget *widget, GtkSnapshot *snapshot) { BzCometOverlay *self = BZ_COMET_OVERLAY (widget); GdkRGBA *color = NULL; GHashTableIter iter = { 0 }; if (self->child != NULL) gtk_widget_snapshot_child (widget, self->child, snapshot); color = bz_comet_overlay_get_pulse_color (self); g_hash_table_iter_init (&iter, self->nodes); for (;;) { BzComet *comet = NULL; GskRenderNode *node = NULL; double progress = 0.0; GskPath *path = NULL; double path_length = 0.0; g_autoptr (GskPathMeasure) path_measure = NULL; GskPathPoint path_point = { 0 }; graphene_point_t end_position = { 0 }; double pulse_radius = 0.0; GskRoundedRect clip = { 0 }; graphene_point_t paintable_position = { 0 }; GdkRGBA clip_color = { 0 }; if (!g_hash_table_iter_next ( &iter, (gpointer *) &comet, (gpointer *) &node)) break; progress = bz_comet_get_progress (comet); path = bz_comet_get_path (comet); path_length = bz_comet_get_path_length (comet); gsk_path_get_end_point (path, &path_point); gsk_path_point_get_position (&path_point, path, &end_position); pulse_radius = progress / path_length * 150.0; clip_color = *color; clip_color.alpha = color->alpha * (1.0 - (progress / path_length)); clip.bounds = GRAPHENE_RECT_INIT ( end_position.x - pulse_radius, end_position.y - pulse_radius, pulse_radius * 2.0, pulse_radius * 2.0); clip.corner[0].width = pulse_radius; clip.corner[0].height = pulse_radius; clip.corner[1].width = pulse_radius; clip.corner[1].height = pulse_radius; clip.corner[2].width = pulse_radius; clip.corner[2].height = pulse_radius; clip.corner[3].width = pulse_radius; clip.corner[3].height = pulse_radius; gtk_snapshot_push_rounded_clip (snapshot, &clip); gtk_snapshot_append_color (snapshot, &clip_color, &clip.bounds); gtk_snapshot_pop (snapshot); path_measure = gsk_path_measure_new (path); gsk_path_measure_get_point (path_measure, progress, &path_point); gsk_path_point_get_position (&path_point, path, &paintable_position); gtk_snapshot_save (snapshot); gtk_snapshot_translate (snapshot, &paintable_position); gtk_snapshot_append_node (snapshot, node); gtk_snapshot_restore (snapshot); } for (guint i = 0; i < self->pulses->len; i++) { PulseState *pulse = NULL; pulse = &g_array_index (self->pulses, PulseState, i); gtk_snapshot_save (snapshot); gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (pulse->x, pulse->y)); append_pulse (snapshot, pulse->progress * 200.0, 1.0 - pulse->progress, color); gtk_snapshot_restore (snapshot); } g_array_set_size (self->pulses, 0); } static void bz_comet_overlay_class_init (BzCometOverlayClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_comet_overlay_dispose; object_class->get_property = bz_comet_overlay_get_property; object_class->set_property = bz_comet_overlay_set_property; props[PROP_CHILD] = g_param_spec_object ( "child", NULL, NULL, GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_PULSE_COLOR] = g_param_spec_boxed ( "pulse-color", NULL, NULL, GDK_TYPE_RGBA, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); widget_class->size_allocate = bz_comet_overlay_size_allocate; widget_class->snapshot = bz_comet_overlay_snapshot; } static void bz_comet_overlay_init (BzCometOverlay *self) { AdwStyleManager *style_manager = NULL; self->nodes = g_hash_table_new_full ( g_direct_hash, g_direct_equal, g_object_unref, (GDestroyNotify) gsk_render_node_unref); self->pulses = g_array_new (FALSE, FALSE, sizeof (PulseState)); style_manager = adw_style_manager_get_default (); self->pulse_color = adw_style_manager_get_accent_color_rgba (style_manager); } GtkWidget * bz_comet_overlay_new (void) { return g_object_new (BZ_TYPE_COMET_OVERLAY, NULL); } void bz_comet_overlay_set_child (BzCometOverlay *self, GtkWidget *child) { g_return_if_fail (BZ_IS_COMET_OVERLAY (self)); g_return_if_fail (child == NULL || GTK_IS_WIDGET (child)); if (self->child == child) return; if (child != NULL) g_return_if_fail (gtk_widget_get_parent (child) == NULL); g_clear_pointer (&self->child, gtk_widget_unparent); self->child = child; if (child != NULL) gtk_widget_set_parent (child, GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CHILD]); } GtkWidget * bz_comet_overlay_get_child (BzCometOverlay *self) { g_return_val_if_fail (BZ_IS_COMET_OVERLAY (self), NULL); return self->child; } void bz_comet_overlay_set_pulse_color (BzCometOverlay *self, GdkRGBA *color) { g_return_if_fail (BZ_IS_COMET_OVERLAY (self)); if (self->pulse_color != NULL && color != NULL && gdk_rgba_equal (self->pulse_color, color)) return; g_clear_pointer (&self->pulse_color, gdk_rgba_free); if (color != NULL) self->pulse_color = gdk_rgba_copy (color); gtk_widget_queue_draw (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PULSE_COLOR]); } GdkRGBA * bz_comet_overlay_get_pulse_color (BzCometOverlay *self) { AdwStyleManager *style_manager = NULL; g_return_val_if_fail (BZ_IS_COMET_OVERLAY (self), NULL); if (self->pulse_color != NULL) return self->pulse_color; style_manager = adw_style_manager_get_default (); return adw_style_manager_get_accent_color_rgba (style_manager); } void bz_comet_overlay_spawn (BzCometOverlay *self, BzComet *comet) { AdwAnimationTarget *target = NULL; AdwSpringParams *spring = NULL; GtkWidget *from = NULL; GtkWidget *to = NULL; GdkPaintable *paintable = NULL; g_autoptr (AdwAnimation) animation = NULL; g_return_if_fail (BZ_IS_COMET_OVERLAY (self)); g_return_if_fail (BZ_IS_COMET (comet)); from = bz_comet_get_from (comet); to = bz_comet_get_to (comet); paintable = bz_comet_get_paintable (comet); g_return_if_fail (from != NULL && gtk_widget_is_ancestor (from, GTK_WIDGET (self))); g_return_if_fail (to != NULL && gtk_widget_is_ancestor (to, GTK_WIDGET (self))); g_return_if_fail (paintable != NULL); target = adw_property_animation_target_new (G_OBJECT (comet), "progress"); spring = adw_spring_params_new (1.0, 0.1, 3.0); animation = adw_spring_animation_new ( GTK_WIDGET (self), 0.0, 0.0, spring, target); adw_spring_animation_set_epsilon ( ADW_SPRING_ANIMATION (animation), 0.0001); g_object_bind_property (comet, "path-length", animation, "value-to", G_BINDING_DEFAULT); update_params ( self, comet, gtk_widget_get_width (GTK_WIDGET (self)), gtk_widget_get_height (GTK_WIDGET (self))); g_signal_connect (comet, "notify::progress", G_CALLBACK (progress_changed), self); bz_comet_set_progress (comet, 0.0); g_signal_connect (animation, "done", G_CALLBACK (animation_done), self); g_object_notify (G_OBJECT (comet), "progress"); adw_animation_play (animation); } void bz_comet_overlay_pulse_child (BzCometOverlay *self, GtkWidget *child) { AdwAnimationTarget *target = NULL; AdwSpringParams *spring = NULL; g_autoptr (AdwAnimation) animation = NULL; g_return_if_fail (BZ_IS_COMET_OVERLAY (self)); g_return_if_fail (GTK_IS_WIDGET (child) && gtk_widget_is_ancestor (child, GTK_WIDGET (self))); target = adw_callback_animation_target_new ( (AdwAnimationTargetFunc) pulse_cb, g_object_ref (child), g_object_unref); spring = adw_spring_params_new (1.5, 0.1, 5.0); animation = adw_spring_animation_new ( GTK_WIDGET (self), 0.0, 1.0, spring, target); adw_spring_animation_set_epsilon ( ADW_SPRING_ANIMATION (animation), 0.0001); adw_animation_play (animation); } static void progress_changed (BzComet *comet, GParamSpec *pspec, BzCometOverlay *self) { double path_length = 0.0; double progress = 0.0; GdkPaintable *paintable = NULL; double intrinsic_width = 0; double t = 0.0; double size_scale = 0.0; double icon_size = 0.0; double grad_size = 0.0; GdkRGBA *color = NULL; g_autoptr (GtkSnapshot) snapshot = NULL; path_length = bz_comet_get_path_length (comet); progress = bz_comet_get_progress (comet); paintable = bz_comet_get_paintable (comet); intrinsic_width = gdk_paintable_get_intrinsic_width (paintable); t = progress / path_length; size_scale = 1.0 - 4.0 * (t - 0.5) * (t - 0.5); icon_size = size_scale * intrinsic_width; grad_size = MAX (1.0, (path_length - progress) / path_length * intrinsic_width * 2.0); color = bz_comet_overlay_get_pulse_color (self); snapshot = gtk_snapshot_new (); append_pulse (snapshot, grad_size, 1.0 - (path_length - progress), color); gtk_snapshot_save (snapshot); gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (-icon_size / 2.0, -icon_size / 2.0)); gdk_paintable_snapshot (paintable, snapshot, icon_size, icon_size); gtk_snapshot_restore (snapshot); g_hash_table_replace (self->nodes, g_object_ref (comet), gtk_snapshot_to_node (snapshot)); gtk_widget_queue_draw (GTK_WIDGET (self)); } static void animation_done (AdwAnimation *animation, BzCometOverlay *self) { AdwAnimationTarget *target = NULL; GObject *comet = NULL; target = adw_animation_get_target (animation); comet = adw_property_animation_target_get_object ( ADW_PROPERTY_ANIMATION_TARGET (target)); g_hash_table_remove (self->nodes, comet); } static void update_params (BzCometOverlay *self, BzComet *comet, int width, int height) { GtkWidget *from = NULL; GtkWidget *to = NULL; graphene_rect_t from_rect = { 0 }; graphene_rect_t to_rect = { 0 }; graphene_point_t from_center = { 0 }; graphene_point_t to_center = { 0 }; graphene_point_t low_interp = { 0 }; graphene_point_t high_interp = { 0 }; // GskPath *last_path = NULL; g_autoptr (GskPathBuilder) path_builder = NULL; g_autoptr (GskPath) path = NULL; g_autoptr (GskPathMeasure) path_measure = NULL; float distance = 0.0; from = bz_comet_get_from (comet); to = bz_comet_get_to (comet); g_assert (from != NULL); g_assert (to != NULL); g_assert (gtk_widget_compute_bounds (from, GTK_WIDGET (self), &from_rect)); g_assert (gtk_widget_compute_bounds (to, GTK_WIDGET (self), &to_rect)); graphene_rect_get_center (&from_rect, &from_center); graphene_rect_get_center (&to_rect, &to_center); graphene_point_interpolate (&from_center, &to_center, 0.333, &low_interp); graphene_point_interpolate (&to_center, &from_center, 0.333, &high_interp); path_builder = gsk_path_builder_new (); gsk_path_builder_move_to (path_builder, from_center.x, from_center.y); gsk_path_builder_cubic_to ( path_builder, high_interp.x, from_center.y, to_center.x, low_interp.y, to_center.x, to_center.y); path = gsk_path_builder_to_path (path_builder); path_measure = gsk_path_measure_new (path); distance = gsk_path_measure_get_length (path_measure); bz_comet_set_path (comet, path); bz_comet_set_path_length (comet, distance); } static void pulse_cb (double value, GtkWidget *widget) { BzCometOverlay *self = NULL; graphene_rect_t rect = { 0 }; gboolean result = FALSE; PulseState pulse = { 0 }; self = (BzCometOverlay *) gtk_widget_get_ancestor (widget, BZ_TYPE_COMET_OVERLAY); if (self == NULL) { g_warning ("Couldn't find ancestor BzCometOverlay for pulse!"); return; } result = gtk_widget_compute_bounds (widget, GTK_WIDGET (self), &rect); if (!result) { g_warning ("Couldn't compute bounds of widget for pulse!"); return; } pulse.x = rect.origin.x + rect.size.width / 2.0; pulse.y = rect.origin.y + rect.size.height / 2.0; pulse.progress = value; g_array_append_val (self->pulses, pulse); gtk_widget_queue_draw (GTK_WIDGET (self)); } static void append_pulse (GtkSnapshot *snapshot, double size, double opacity, GdkRGBA *color) { const GdkRGBA transparent = { .red = 1.0, .green = 1.0, .blue = 1.0, .alpha = 0.0 }; GdkRGBA pulse_color = { 0 }; GskColorStop grad_stops[2] = { 0 }; if (size < 1.0) return; pulse_color = *color; pulse_color.alpha = color->alpha * 0.75 * opacity; grad_stops[0].color = pulse_color; grad_stops[0].offset = 0.9; grad_stops[1].color = transparent; grad_stops[1].offset = 0.9; gtk_snapshot_append_radial_gradient ( snapshot, &GRAPHENE_RECT_INIT (-size / 2.0, -size / 2.0, size, size), &GRAPHENE_POINT_INIT (0.0, 0.0), size / 2.0, size / 2.0, 0.0, 1.0, grad_stops, G_N_ELEMENTS (grad_stops)); } bazaar-orig-v0.7.14/src/bz-marshalers.list0000664000175000017500000000262515166123241017403 0ustar hasanhasan# see glib-genmarshal(1) for a detailed description of the file format, # possible parameter types are: # VOID indicates no return type, or no extra # parameters. if VOID is used as the parameter # list, no additional parameters may be present. # BOOLEAN for boolean types (gboolean) # CHAR for signed char types (char) # UCHAR for unsigned char types (guchar) # INT for signed integer types (int) # UINT for unsigned integer types (guint) # LONG for signed long integer types (glong) # ULONG for unsigned long integer types (gulong) # INT64 for signed 64bit integer types (gint64) # UINT64 for unsigned 64bit integer types (guint64) # ENUM for enumeration types (int) # FLAGS for flag enumeration types (guint) # FLOAT for single-precision float types (float) # DOUBLE for double-precision float types (double) # STRING for string types (char *) # BOXED for boxed (anonymous but reference counted) types (GBoxed*) # PARAM for GParamSpec or derived types (GParamSpec*) # POINTER for anonymous pointer types (gpointer) # OBJECT for GObject or derived types (GObject*) # VARIANT for GVariant types (GVariant*) # NONE deprecated alias for VOID # BOOL deprecated alias for BOOLEAN VOID:OBJECT,OBJECT VOID:OBJECT,BOXED bazaar-orig-v0.7.14/src/bz-env.h0000664000175000017500000000157215166123241015306 0ustar hasanhasan/* bz-env.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS gsize bz_get_dex_stack_size (void); guint64 bz_get_n_download_workers (void); G_END_DECLS bazaar-orig-v0.7.14/src/bz-dynamic-list-view.c0000664000175000017500000006643115166123241020063 0ustar hasanhasan/* bz-dynamic-list-view.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-dynamic-list-view.h" #include "bz-marshalers.h" G_DEFINE_ENUM_TYPE ( BzDynamicListViewKind, bz_dynamic_list_view_kind, G_DEFINE_ENUM_VALUE (BZ_DYNAMIC_LIST_VIEW_KIND_HBOX, "h-box"), G_DEFINE_ENUM_VALUE (BZ_DYNAMIC_LIST_VIEW_KIND_VBOX, "v-box"), G_DEFINE_ENUM_VALUE (BZ_DYNAMIC_LIST_VIEW_KIND_LIST_BOX, "list-box"), G_DEFINE_ENUM_VALUE (BZ_DYNAMIC_LIST_VIEW_KIND_FLOW_BOX, "flow-box"), G_DEFINE_ENUM_VALUE (BZ_DYNAMIC_LIST_VIEW_KIND_CAROUSEL, "carousel")) struct _BzDynamicListView { AdwBin parent_instance; GListModel *model; gboolean scroll; BzDynamicListViewKind noscroll_kind; GType child_type; char *child_prop; char *object_prop; guint max_children_per_line; guint row_spacing; guint column_spacing; char *child_type_string; GtkScrolledWindow *scrolled_window; GPtrArray *box_children; }; G_DEFINE_FINAL_TYPE (BzDynamicListView, bz_dynamic_list_view, ADW_TYPE_BIN); enum { PROP_0, PROP_MODEL, PROP_SCROLL, PROP_NOSCROLL_KIND, PROP_CHILD_TYPE, PROP_CHILD_PROP, PROP_OBJECT_PROP, PROP_MAX_CHILDREN_PER_LINE, PROP_VADJUSTMENT, PROP_ROW_SPACING, PROP_COLUMN_SPACING, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; enum { SIGNAL_BIND_WIDGET, SIGNAL_UNBIND_WIDGET, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL]; static void refresh (BzDynamicListView *self); static void list_item_factory_setup (BzDynamicListView *self, GtkListItem *item, GtkSignalListItemFactory *factory); static void list_item_factory_teardown (BzDynamicListView *self, GtkListItem *item, GtkSignalListItemFactory *factory); static void list_item_factory_bind (BzDynamicListView *self, GtkListItem *item, GtkSignalListItemFactory *factory); static void list_item_factory_unbind (BzDynamicListView *self, GtkListItem *item, GtkSignalListItemFactory *factory); static GtkWidget * create_child_widget (GObject *object, BzDynamicListView *self); static void items_changed (GListModel *model, guint position, guint removed, guint added, BzDynamicListView *self); static void bz_dynamic_list_view_dispose (GObject *object) { BzDynamicListView *self = BZ_DYNAMIC_LIST_VIEW (object); if (self->model != NULL) g_signal_handlers_disconnect_by_func (self->model, items_changed, self); g_clear_object (&self->model); g_clear_pointer (&self->child_prop, g_free); g_clear_pointer (&self->object_prop, g_free); g_clear_pointer (&self->child_type_string, g_free); g_clear_pointer (&self->box_children, g_ptr_array_unref); G_OBJECT_CLASS (bz_dynamic_list_view_parent_class)->dispose (object); } static void bz_dynamic_list_view_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzDynamicListView *self = BZ_DYNAMIC_LIST_VIEW (object); switch (prop_id) { case PROP_MODEL: g_value_set_object (value, bz_dynamic_list_view_get_model (self)); break; case PROP_SCROLL: g_value_set_boolean (value, bz_dynamic_list_view_get_scroll (self)); break; case PROP_NOSCROLL_KIND: g_value_set_enum (value, bz_dynamic_list_view_get_noscroll_kind (self)); break; case PROP_CHILD_TYPE: g_value_set_string (value, bz_dynamic_list_view_get_child_type (self)); break; case PROP_CHILD_PROP: g_value_set_string (value, bz_dynamic_list_view_get_child_prop (self)); break; case PROP_OBJECT_PROP: g_value_set_string (value, bz_dynamic_list_view_get_object_prop (self)); break; case PROP_MAX_CHILDREN_PER_LINE: g_value_set_uint (value, bz_dynamic_list_view_get_max_children_per_line (self)); break; case PROP_VADJUSTMENT: g_value_set_object (value, bz_dynamic_list_view_get_vadjustment (self)); break; case PROP_ROW_SPACING: g_value_set_uint (value, bz_dynamic_list_view_get_row_spacing (self)); break; case PROP_COLUMN_SPACING: g_value_set_uint (value, bz_dynamic_list_view_get_column_spacing (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_dynamic_list_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzDynamicListView *self = BZ_DYNAMIC_LIST_VIEW (object); switch (prop_id) { case PROP_MODEL: bz_dynamic_list_view_set_model (self, g_value_get_object (value)); break; case PROP_SCROLL: bz_dynamic_list_view_set_scroll (self, g_value_get_boolean (value)); break; case PROP_NOSCROLL_KIND: bz_dynamic_list_view_set_noscroll_kind (self, g_value_get_enum (value)); break; case PROP_CHILD_TYPE: bz_dynamic_list_view_set_child_type (self, g_value_get_string (value)); break; case PROP_CHILD_PROP: bz_dynamic_list_view_set_child_prop (self, g_value_get_string (value)); break; case PROP_OBJECT_PROP: bz_dynamic_list_view_set_object_prop (self, g_value_get_string (value)); break; case PROP_MAX_CHILDREN_PER_LINE: bz_dynamic_list_view_set_max_children_per_line (self, g_value_get_uint (value)); break; case PROP_ROW_SPACING: bz_dynamic_list_view_set_row_spacing (self, g_value_get_uint (value)); break; case PROP_COLUMN_SPACING: bz_dynamic_list_view_set_column_spacing (self, g_value_get_uint (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_dynamic_list_view_class_init (BzDynamicListViewClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bz_dynamic_list_view_set_property; object_class->get_property = bz_dynamic_list_view_get_property; object_class->dispose = bz_dynamic_list_view_dispose; props[PROP_MODEL] = g_param_spec_object ( "model", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_SCROLL] = g_param_spec_boolean ( "scroll", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_NOSCROLL_KIND] = g_param_spec_enum ( "noscroll-kind", NULL, NULL, BZ_TYPE_DYNAMIC_LIST_VIEW_KIND, BZ_DYNAMIC_LIST_VIEW_KIND_LIST_BOX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_MAX_CHILDREN_PER_LINE] = g_param_spec_uint ( "max-children-per-line", NULL, NULL, 1, G_MAXUINT, 4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_ROW_SPACING] = g_param_spec_uint ( "row-spacing", NULL, NULL, 0, G_MAXUINT, 11, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_COLUMN_SPACING] = g_param_spec_uint ( "column-spacing", NULL, NULL, 0, G_MAXUINT, 11, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_CHILD_TYPE] = g_param_spec_string ( "child-type", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_CHILD_PROP] = g_param_spec_string ( "child-prop", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_OBJECT_PROP] = g_param_spec_string ( "object-prop", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_VADJUSTMENT] = g_param_spec_object ( "vadjustment", NULL, NULL, GTK_TYPE_ADJUSTMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); signals[SIGNAL_BIND_WIDGET] = g_signal_new ( "bind-widget", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, bz_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 1, GTK_TYPE_WIDGET); g_signal_set_va_marshaller ( signals[SIGNAL_BIND_WIDGET], G_TYPE_FROM_CLASS (klass), bz_marshal_VOID__OBJECT_OBJECTv); signals[SIGNAL_UNBIND_WIDGET] = g_signal_new ( "unbind-widget", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, bz_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 1, GTK_TYPE_WIDGET); g_signal_set_va_marshaller ( signals[SIGNAL_UNBIND_WIDGET], G_TYPE_FROM_CLASS (klass), bz_marshal_VOID__OBJECT_OBJECTv); } static void bz_dynamic_list_view_init (BzDynamicListView *self) { self->child_type = G_TYPE_INVALID; self->noscroll_kind = BZ_DYNAMIC_LIST_VIEW_KIND_LIST_BOX; self->max_children_per_line = 4; self->row_spacing = 11; self->column_spacing = 11; self->box_children = g_ptr_array_new (); } BzDynamicListView * bz_dynamic_list_view_new (void) { return g_object_new (BZ_TYPE_DYNAMIC_LIST_VIEW, NULL); } GListModel * bz_dynamic_list_view_get_model (BzDynamicListView *self) { g_return_val_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self), NULL); return self->model; } gboolean bz_dynamic_list_view_get_scroll (BzDynamicListView *self) { g_return_val_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self), FALSE); return self->scroll; } BzDynamicListViewKind bz_dynamic_list_view_get_noscroll_kind (BzDynamicListView *self) { g_return_val_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self), FALSE); return self->noscroll_kind; } const char * bz_dynamic_list_view_get_child_type (BzDynamicListView *self) { g_return_val_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self), NULL); return self->child_type_string; } const char * bz_dynamic_list_view_get_child_prop (BzDynamicListView *self) { g_return_val_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self), NULL); return self->child_prop; } const char * bz_dynamic_list_view_get_object_prop (BzDynamicListView *self) { g_return_val_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self), NULL); return self->object_prop; } guint bz_dynamic_list_view_get_max_children_per_line (BzDynamicListView *self) { g_return_val_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self), 4); return self->max_children_per_line; } GtkAdjustment * bz_dynamic_list_view_get_vadjustment (BzDynamicListView *self) { g_return_val_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self), NULL); if (self->scrolled_window == NULL) return NULL; return gtk_scrolled_window_get_vadjustment (self->scrolled_window); } void bz_dynamic_list_view_set_model (BzDynamicListView *self, GListModel *model) { g_return_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self)); if (self->model != NULL) g_signal_handlers_disconnect_by_func (self->model, items_changed, self); g_clear_object (&self->model); if (model != NULL) self->model = g_object_ref (model); refresh (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MODEL]); } void bz_dynamic_list_view_set_scroll (BzDynamicListView *self, gboolean scroll) { g_return_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self)); self->scroll = scroll; refresh (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SCROLL]); } void bz_dynamic_list_view_set_noscroll_kind (BzDynamicListView *self, BzDynamicListViewKind noscroll_kind) { g_return_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self)); g_return_if_fail (noscroll_kind >= 0 && noscroll_kind < BZ_DYNAMIC_LIST_VIEW_N_KINDS); self->noscroll_kind = noscroll_kind; refresh (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NOSCROLL_KIND]); } void bz_dynamic_list_view_set_child_type (BzDynamicListView *self, const char *child_type) { GType type = G_TYPE_INVALID; g_return_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self)); if (child_type != NULL) { type = g_type_from_name (child_type); g_return_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET)); } g_clear_pointer (&self->child_type_string, g_free); self->child_type = type; if (child_type != NULL) self->child_type_string = g_strdup (child_type); refresh (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CHILD_TYPE]); } void bz_dynamic_list_view_set_child_prop (BzDynamicListView *self, const char *child_prop) { g_return_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self)); g_clear_pointer (&self->child_prop, g_free); if (child_prop != NULL) self->child_prop = g_strdup (child_prop); refresh (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CHILD_PROP]); } void bz_dynamic_list_view_set_object_prop (BzDynamicListView *self, const char *object_prop) { g_return_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self)); g_clear_pointer (&self->object_prop, g_free); if (object_prop != NULL) self->object_prop = g_strdup (object_prop); refresh (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_OBJECT_PROP]); } void bz_dynamic_list_view_set_max_children_per_line (BzDynamicListView *self, guint max_children) { GtkWidget *child; g_return_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self)); g_return_if_fail (max_children > 0); self->max_children_per_line = max_children; child = adw_bin_get_child (ADW_BIN (self)); if (child != NULL && self->noscroll_kind == BZ_DYNAMIC_LIST_VIEW_KIND_FLOW_BOX && !self->scroll) { gtk_flow_box_set_max_children_per_line (GTK_FLOW_BOX (child), max_children); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MAX_CHILDREN_PER_LINE]); } guint bz_dynamic_list_view_get_row_spacing (BzDynamicListView *self) { g_return_val_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self), 5); return self->row_spacing; } guint bz_dynamic_list_view_get_column_spacing (BzDynamicListView *self) { g_return_val_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self), 5); return self->column_spacing; } void bz_dynamic_list_view_set_row_spacing (BzDynamicListView *self, guint row_spacing) { GtkWidget *child; g_return_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self)); self->row_spacing = row_spacing; child = adw_bin_get_child (ADW_BIN (self)); if (child != NULL && self->noscroll_kind == BZ_DYNAMIC_LIST_VIEW_KIND_FLOW_BOX && !self->scroll) { gtk_flow_box_set_row_spacing (GTK_FLOW_BOX (child), row_spacing); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ROW_SPACING]); } void bz_dynamic_list_view_set_column_spacing (BzDynamicListView *self, guint column_spacing) { GtkWidget *child; g_return_if_fail (BZ_IS_DYNAMIC_LIST_VIEW (self)); self->column_spacing = column_spacing; child = adw_bin_get_child (ADW_BIN (self)); if (child != NULL && self->noscroll_kind == BZ_DYNAMIC_LIST_VIEW_KIND_FLOW_BOX && !self->scroll) { gtk_flow_box_set_column_spacing (GTK_FLOW_BOX (child), column_spacing); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_COLUMN_SPACING]); } static void refresh (BzDynamicListView *self) { if (self->model != NULL) g_signal_handlers_disconnect_by_func (self->model, items_changed, self); self->scrolled_window = NULL; g_ptr_array_set_size (self->box_children, 0); adw_bin_set_child (ADW_BIN (self), NULL); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_VADJUSTMENT]); if (self->model == NULL || self->child_prop == NULL || self->child_type == G_TYPE_INVALID) return; if (self->scroll) { GtkWidget *window = NULL; GtkNoSelection *selection = NULL; GtkListItemFactory *factory = NULL; GtkWidget *view = NULL; window = gtk_scrolled_window_new (); selection = gtk_no_selection_new (g_object_ref (self->model)); factory = gtk_signal_list_item_factory_new (); view = gtk_list_view_new (GTK_SELECTION_MODEL (selection), factory); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (window), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_widget_add_css_class (view, "navigation-sidebar"); gtk_list_view_set_single_click_activate (GTK_LIST_VIEW (view), TRUE); g_signal_connect_swapped (factory, "setup", G_CALLBACK (list_item_factory_setup), self); g_signal_connect_swapped (factory, "teardown", G_CALLBACK (list_item_factory_teardown), self); g_signal_connect_swapped (factory, "bind", G_CALLBACK (list_item_factory_bind), self); g_signal_connect_swapped (factory, "unbind", G_CALLBACK (list_item_factory_unbind), self); gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (window), view); self->scrolled_window = GTK_SCROLLED_WINDOW (window); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_VADJUSTMENT]); adw_bin_set_child (ADW_BIN (self), window); } else { switch (self->noscroll_kind) { case BZ_DYNAMIC_LIST_VIEW_KIND_HBOX: case BZ_DYNAMIC_LIST_VIEW_KIND_VBOX: { GtkWidget *widget = NULL; if (self->noscroll_kind == BZ_DYNAMIC_LIST_VIEW_KIND_VBOX) widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10); else widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10); g_signal_connect ( self->model, "items-changed", G_CALLBACK (items_changed), self); adw_bin_set_child (ADW_BIN (self), widget); items_changed (self->model, 0, 0, g_list_model_get_n_items (self->model), self); } break; case BZ_DYNAMIC_LIST_VIEW_KIND_LIST_BOX: { GtkWidget *widget = NULL; widget = gtk_list_box_new (); gtk_list_box_set_selection_mode ( GTK_LIST_BOX (widget), GTK_SELECTION_NONE); gtk_list_box_bind_model ( GTK_LIST_BOX (widget), self->model, (GtkListBoxCreateWidgetFunc) create_child_widget, self, NULL); adw_bin_set_child (ADW_BIN (self), widget); } break; case BZ_DYNAMIC_LIST_VIEW_KIND_FLOW_BOX: { GtkWidget *widget = NULL; widget = gtk_flow_box_new (); gtk_flow_box_set_homogeneous (GTK_FLOW_BOX (widget), TRUE); gtk_flow_box_set_max_children_per_line (GTK_FLOW_BOX (widget), self->max_children_per_line); gtk_flow_box_set_row_spacing (GTK_FLOW_BOX (widget), self->row_spacing); gtk_flow_box_set_column_spacing (GTK_FLOW_BOX (widget), self->column_spacing); gtk_flow_box_set_selection_mode (GTK_FLOW_BOX (widget), GTK_SELECTION_NONE); gtk_flow_box_bind_model ( GTK_FLOW_BOX (widget), self->model, (GtkFlowBoxCreateWidgetFunc) create_child_widget, self, NULL); adw_bin_set_child (ADW_BIN (self), widget); } break; case BZ_DYNAMIC_LIST_VIEW_KIND_CAROUSEL: { GtkWidget *widget = NULL; widget = adw_carousel_new (); adw_carousel_set_allow_scroll_wheel (ADW_CAROUSEL (widget), FALSE); g_signal_connect ( self->model, "items-changed", G_CALLBACK (items_changed), self); adw_bin_set_child (ADW_BIN (self), widget); items_changed (self->model, 0, 0, g_list_model_get_n_items (self->model), self); } break; case BZ_DYNAMIC_LIST_VIEW_N_KINDS: default: g_assert_not_reached (); } } } static void list_item_factory_setup (BzDynamicListView *self, GtkListItem *item, GtkSignalListItemFactory *factory) { GtkWidget *child = NULL; child = g_object_new (self->child_type, NULL); gtk_list_item_set_child (item, child); } static void list_item_factory_teardown (BzDynamicListView *self, GtkListItem *item, GtkSignalListItemFactory *factory) { gtk_list_item_set_child (item, NULL); } static void list_item_factory_bind (BzDynamicListView *self, GtkListItem *item, GtkSignalListItemFactory *factory) { GObject *object = NULL; GtkWidget *child = NULL; object = gtk_list_item_get_item (item); child = gtk_list_item_get_child (item); gtk_list_item_set_focusable (item, FALSE); gtk_list_item_set_selectable (item, FALSE); gtk_list_item_set_activatable (item, FALSE); if (self->object_prop != NULL) { GBinding *binding = NULL; binding = g_object_bind_property ( object, self->object_prop, child, self->child_prop, G_BINDING_SYNC_CREATE); g_object_set_data_full ( G_OBJECT (item), "binding", binding, g_object_unref); } else g_object_set (child, self->child_prop, object, NULL); g_signal_emit (self, signals[SIGNAL_BIND_WIDGET], 0, child, object); } static void list_item_factory_unbind (BzDynamicListView *self, GtkListItem *item, GtkSignalListItemFactory *factory) { GtkWidget *child = NULL; GBinding *binding = NULL; g_autoptr (GObject) object = NULL; child = gtk_list_item_get_child (item); binding = g_object_steal_data (G_OBJECT (item), "binding"); if (binding != NULL) { object = g_binding_dup_source (binding); g_binding_unbind (binding); g_object_unref (binding); } else { g_object_get (child, self->child_prop, &object, NULL); g_object_set (child, self->child_prop, NULL, NULL); } g_signal_emit (self, signals[SIGNAL_UNBIND_WIDGET], 0, child, object); } static GtkWidget * create_child_widget (GObject *object, BzDynamicListView *self) { GtkWidget *widget = NULL; widget = g_object_new (self->child_type, NULL); if (self->object_prop != NULL) g_object_bind_property ( object, self->object_prop, widget, self->child_prop, G_BINDING_SYNC_CREATE); else g_object_set (widget, self->child_prop, object, NULL); gtk_widget_set_receives_default (widget, TRUE); g_signal_emit (self, signals[SIGNAL_BIND_WIDGET], 0, widget, object); switch (self->noscroll_kind) { case BZ_DYNAMIC_LIST_VIEW_KIND_LIST_BOX: { GtkWidget *child = NULL; child = gtk_list_box_row_new (); gtk_widget_add_css_class (GTK_WIDGET (child), "disable-adw-flow-box-styling"); gtk_widget_set_focusable (GTK_WIDGET (child), FALSE); gtk_list_box_row_set_selectable (GTK_LIST_BOX_ROW (child), FALSE); gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (child), widget); return child; } case BZ_DYNAMIC_LIST_VIEW_KIND_FLOW_BOX: { GtkWidget *child = NULL; child = gtk_flow_box_child_new (); gtk_widget_add_css_class (GTK_WIDGET (child), "disable-adw-flow-box-styling"); gtk_widget_set_focusable (GTK_WIDGET (child), FALSE); gtk_flow_box_child_set_child (GTK_FLOW_BOX_CHILD (child), widget); return child; } case BZ_DYNAMIC_LIST_VIEW_KIND_HBOX: case BZ_DYNAMIC_LIST_VIEW_KIND_VBOX: case BZ_DYNAMIC_LIST_VIEW_KIND_CAROUSEL: case BZ_DYNAMIC_LIST_VIEW_N_KINDS: default: return widget; } } static void items_changed (GListModel *model, guint position, guint removed, guint added, BzDynamicListView *self) { GtkWidget *bin_child = NULL; bin_child = adw_bin_get_child (ADW_BIN (self)); for (guint i = 0; i < removed; i++) { switch (self->noscroll_kind) { case BZ_DYNAMIC_LIST_VIEW_KIND_HBOX: case BZ_DYNAMIC_LIST_VIEW_KIND_VBOX: { GtkWidget *child = NULL; child = g_ptr_array_index (self->box_children, position); gtk_box_remove (GTK_BOX (bin_child), g_steal_pointer (&child)); g_ptr_array_remove_index (self->box_children, position); } break; case BZ_DYNAMIC_LIST_VIEW_KIND_CAROUSEL: adw_carousel_remove ( ADW_CAROUSEL (bin_child), adw_carousel_get_nth_page (ADW_CAROUSEL (bin_child), position)); break; case BZ_DYNAMIC_LIST_VIEW_KIND_LIST_BOX: case BZ_DYNAMIC_LIST_VIEW_KIND_FLOW_BOX: case BZ_DYNAMIC_LIST_VIEW_N_KINDS: default: g_assert_not_reached (); } } for (guint i = 0; i < added; i++) { g_autoptr (GObject) object = NULL; GtkWidget *widget = NULL; object = g_list_model_get_item (model, position + i); widget = create_child_widget (object, self); switch (self->noscroll_kind) { case BZ_DYNAMIC_LIST_VIEW_KIND_HBOX: case BZ_DYNAMIC_LIST_VIEW_KIND_VBOX: { if (position + i < self->box_children->len) { GtkWidget *sibling = NULL; sibling = g_ptr_array_index (self->box_children, position + i); gtk_box_insert_child_after (GTK_BOX (bin_child), widget, sibling); } else gtk_box_append (GTK_BOX (bin_child), widget); } break; case BZ_DYNAMIC_LIST_VIEW_KIND_CAROUSEL: adw_carousel_insert (ADW_CAROUSEL (bin_child), widget, position + i); break; case BZ_DYNAMIC_LIST_VIEW_KIND_LIST_BOX: case BZ_DYNAMIC_LIST_VIEW_KIND_FLOW_BOX: case BZ_DYNAMIC_LIST_VIEW_N_KINDS: default: g_assert_not_reached (); } } } /* End of bz-dynamic-list-view.c */ bazaar-orig-v0.7.14/src/bz-tag-list.h0000664000175000017500000000273415166123241016243 0ustar hasanhasan/* bz-tag-list.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-flathub-state.h" #include G_BEGIN_DECLS #define BZ_TYPE_TAG_LIST (bz_tag_list_get_type ()) G_DECLARE_FINAL_TYPE (BzTagList, bz_tag_list, BZ, TAG_LIST, GtkBox) GtkWidget *bz_tag_list_new (void); GListModel *bz_tag_list_get_model (BzTagList *self); void bz_tag_list_set_model (BzTagList *self, GListModel *model); GtkWidget *bz_tag_list_get_prefix (BzTagList *self); void bz_tag_list_set_prefix (BzTagList *self, GtkWidget *prefix); BzFlathubState *bz_tag_list_get_flathub_state (BzTagList *self); void bz_tag_list_set_flathub_state (BzTagList *self, BzFlathubState *flathub_state); G_END_DECLS bazaar-orig-v0.7.14/src/bz-repository.txt0000664000175000017500000000036615166123241017325 0ustar hasanhasanprefix=bz name=repository parent-prefix=g parent-name=object author=AUTOGEN property=is_user gboolean G_TYPE_BOOLEAN boolean property=title char G_TYPE_STRING string property=url char G_TYPE_STRING string property=name char G_TYPE_STRING string bazaar-orig-v0.7.14/src/bz-search-filter-popover.h0000664000175000017500000000275215166123241020737 0ustar hasanhasan/* bz-search-filter-popover.h * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-category-flags.h" #include G_BEGIN_DECLS #define BZ_TYPE_SEARCH_FILTER_POPOVER (bz_search_filter_popover_get_type ()) G_DECLARE_FINAL_TYPE (BzSearchFilterPopover, bz_search_filter_popover, BZ, SEARCH_FILTER_POPOVER, GtkPopover) GtkWidget * bz_search_filter_popover_new (void); BzCategoryFlags bz_search_filter_popover_get_selected_categories (BzSearchFilterPopover *self); gboolean bz_search_filter_popover_get_only_verified (BzSearchFilterPopover *self); gboolean bz_search_filter_popover_get_only_free (BzSearchFilterPopover *self); gboolean bz_search_filter_popover_get_only_non_eol (BzSearchFilterPopover *self); void bz_search_filter_popover_clear (BzSearchFilterPopover *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-app-permissions.c0000664000175000017500000012354315166123241017645 0ustar hasanhasan/* bz-app-permissions.c * * Copyright 2026 Alexander Vanhee * Copyright (C) 2022 Red Hat * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include #include #include #include "bz-app-permissions.h" #define DOES_NOT_CONTAIN ((guint) ~0) G_DEFINE_FLAGS_TYPE ( BzAppPermissionsFlags, bz_app_permissions_flags, G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_NONE, "none"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_NETWORK, "network"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_SYSTEM_BUS, "system-bus"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_SESSION_BUS, "session-bus"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_DEVICES, "devices"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_HOME_FULL, "home-full"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_HOME_READ, "home-read"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL, "filesystem-full"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ, "filesystem-read"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_FULL, "downloads-full"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_READ, "downloads-read"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_SETTINGS, "settings"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_X11, "x11"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_ESCAPE_SANDBOX, "escape-sandbox"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_OTHER, "filesystem-other"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_BUS_POLICY_OTHER, "bus-policy-other"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_AUDIO_DEVICES, "audio-devices"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_INPUT_DEVICES, "input-devices"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_SYSTEM_DEVICES, "system-devices"), G_DEFINE_ENUM_VALUE (BZ_APP_PERMISSIONS_FLAGS_SCREEN, "screen")) G_DEFINE_ENUM_TYPE ( BzFilesystemPathType, bz_filesystem_path_type, G_DEFINE_ENUM_VALUE (BZ_FILESYSTEM_PATH_SYSTEM_ROOT, "system-root"), G_DEFINE_ENUM_VALUE (BZ_FILESYSTEM_PATH_HOME_SUBDIR, "home-subdir"), G_DEFINE_ENUM_VALUE (BZ_FILESYSTEM_PATH_HOST_OS, "host-os"), G_DEFINE_ENUM_VALUE (BZ_FILESYSTEM_PATH_HOST_ETC, "host-etc"), G_DEFINE_ENUM_VALUE (BZ_FILESYSTEM_PATH_XDG_DESKTOP, "xdg-desktop"), G_DEFINE_ENUM_VALUE (BZ_FILESYSTEM_PATH_XDG_DOCUMENTS, "xdg-documents"), G_DEFINE_ENUM_VALUE (BZ_FILESYSTEM_PATH_XDG_MUSIC, "xdg-music"), G_DEFINE_ENUM_VALUE (BZ_FILESYSTEM_PATH_XDG_PICTURES, "xdg-pictures"), G_DEFINE_ENUM_VALUE (BZ_FILESYSTEM_PATH_XDG_PUBLIC_SHARE, "xdg-public-share"), G_DEFINE_ENUM_VALUE (BZ_FILESYSTEM_PATH_XDG_VIDEOS, "xdg-videos"), G_DEFINE_ENUM_VALUE (BZ_FILESYSTEM_PATH_XDG_TEMPLATES, "xdg-templates"), G_DEFINE_ENUM_VALUE (BZ_FILESYSTEM_PATH_XDG_CACHE, "xdg-cache"), G_DEFINE_ENUM_VALUE (BZ_FILESYSTEM_PATH_XDG_CONFIG, "xdg-config"), G_DEFINE_ENUM_VALUE (BZ_FILESYSTEM_PATH_XDG_DATA, "xdg-data"), G_DEFINE_ENUM_VALUE (BZ_FILESYSTEM_PATH_XDG_RUN, "xdg-run"), G_DEFINE_ENUM_VALUE (BZ_FILESYSTEM_PATH_CUSTOM, "custom")) G_DEFINE_ENUM_TYPE ( BzBusPolicyPermission, bz_bus_policy_permission, G_DEFINE_ENUM_VALUE (BZ_BUS_POLICY_PERMISSION_UNKNOWN, "unknown"), G_DEFINE_ENUM_VALUE (BZ_BUS_POLICY_PERMISSION_NONE, "none"), G_DEFINE_ENUM_VALUE (BZ_BUS_POLICY_PERMISSION_SEE, "see"), G_DEFINE_ENUM_VALUE (BZ_BUS_POLICY_PERMISSION_TALK, "talk"), G_DEFINE_ENUM_VALUE (BZ_BUS_POLICY_PERMISSION_OWN, "own")) struct _BzAppPermissions { GObject parent; gboolean is_sealed; BzAppPermissionsFlags flags; GPtrArray *filesystem_read; GPtrArray *filesystem_full; GPtrArray *bus_policies; }; G_DEFINE_FINAL_TYPE (BzAppPermissions, bz_app_permissions, G_TYPE_OBJECT) static gint cmp_filesystem_path_pointers (gconstpointer item1, gconstpointer item2); static int cmp_bus_policy_qsort (const void *item1, const void *item2); static guint app_permissions_get_array_index (GPtrArray *array, BzFilesystemPathType type, const char *subpath); static guint get_strv_index (const gchar *const *strv, const gchar *value); static void bz_app_permissions_finalize (GObject *object) { BzAppPermissions *self = BZ_APP_PERMISSIONS (object); g_clear_pointer (&self->filesystem_read, g_ptr_array_unref); g_clear_pointer (&self->filesystem_full, g_ptr_array_unref); g_clear_pointer (&self->bus_policies, g_ptr_array_unref); G_OBJECT_CLASS (bz_app_permissions_parent_class)->finalize (object); } static void bz_app_permissions_class_init (BzAppPermissionsClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = bz_app_permissions_finalize; } static void bz_app_permissions_init (BzAppPermissions *self) { } BzFilesystemPath * bz_filesystem_path_new (BzFilesystemPathType type, const char *subpath) { BzFilesystemPath *path = g_new0 (BzFilesystemPath, 1); path->type = type; path->subpath = g_strdup (subpath); return path; } void bz_filesystem_path_free (BzFilesystemPath *path) { g_return_if_fail (path != NULL); g_free (path->subpath); g_free (path); } char * bz_filesystem_path_to_display_string (const BzFilesystemPath *path) { g_return_val_if_fail (path != NULL, NULL); switch (path->type) { case BZ_FILESYSTEM_PATH_SYSTEM_ROOT: return g_strdup_printf (_ ("System folder %s"), path->subpath ? path->subpath : "/"); case BZ_FILESYSTEM_PATH_HOME_SUBDIR: return g_strdup_printf (_ ("Home subfolder %s"), path->subpath); case BZ_FILESYSTEM_PATH_HOST_OS: return g_strdup (_ ("Host system folders")); case BZ_FILESYSTEM_PATH_HOST_ETC: return g_strdup (_ ("Host system configuration from /etc")); case BZ_FILESYSTEM_PATH_XDG_DESKTOP: if (path->subpath) return g_strdup_printf (_ ("Desktop subfolder %s"), path->subpath); return g_strdup (_ ("Desktop folder")); case BZ_FILESYSTEM_PATH_XDG_DOCUMENTS: if (path->subpath) return g_strdup_printf (_ ("Documents subfolder %s"), path->subpath); return g_strdup (_ ("Documents folder")); case BZ_FILESYSTEM_PATH_XDG_MUSIC: if (path->subpath) return g_strdup_printf (_ ("Music subfolder %s"), path->subpath); return g_strdup (_ ("Music folder")); case BZ_FILESYSTEM_PATH_XDG_PICTURES: if (path->subpath) return g_strdup_printf (_ ("Pictures subfolder %s"), path->subpath); return g_strdup (_ ("Pictures folder")); case BZ_FILESYSTEM_PATH_XDG_PUBLIC_SHARE: if (path->subpath) return g_strdup_printf (_ ("Public Share subfolder %s"), path->subpath); return g_strdup (_ ("Public Share folder")); case BZ_FILESYSTEM_PATH_XDG_VIDEOS: if (path->subpath) return g_strdup_printf (_ ("Videos subfolder %s"), path->subpath); return g_strdup (_ ("Videos folder")); case BZ_FILESYSTEM_PATH_XDG_TEMPLATES: if (path->subpath) return g_strdup_printf (_ ("Templates subfolder %s"), path->subpath); return g_strdup (_ ("Templates folder")); case BZ_FILESYSTEM_PATH_XDG_CACHE: if (path->subpath) return g_strdup_printf (_ ("User cache subfolder %s"), path->subpath); return g_strdup (_ ("User cache folder")); case BZ_FILESYSTEM_PATH_XDG_CONFIG: if (path->subpath) return g_strdup_printf (_ ("User configuration subfolder %s"), path->subpath); return g_strdup (_ ("User configuration folder")); case BZ_FILESYSTEM_PATH_XDG_DATA: if (path->subpath) return g_strdup_printf (_ ("User data subfolder %s"), path->subpath); return g_strdup (_ ("User data folder")); case BZ_FILESYSTEM_PATH_XDG_RUN: if (path->subpath) return g_strdup_printf (_ ("User runtime subfolder %s"), path->subpath); return g_strdup (_ ("User runtime folder")); case BZ_FILESYSTEM_PATH_CUSTOM: return g_strdup_printf (_ ("Filesystem access to %s"), path->subpath); default: return g_strdup (_ ("Unknown filesystem path")); } } const char * bz_filesystem_path_to_icon_name (const BzFilesystemPath *path) { switch (path->type) { case BZ_FILESYSTEM_PATH_HOST_OS: return "computer-symbolic"; case BZ_FILESYSTEM_PATH_HOST_ETC: return "emblem-system-symbolic"; case BZ_FILESYSTEM_PATH_XDG_DESKTOP: return "user-desktop-symbolic"; case BZ_FILESYSTEM_PATH_XDG_DOCUMENTS: return "folder-documents-symbolic"; case BZ_FILESYSTEM_PATH_XDG_MUSIC: return "folder-music-symbolic"; case BZ_FILESYSTEM_PATH_XDG_PICTURES: return "folder-pictures-symbolic"; case BZ_FILESYSTEM_PATH_XDG_PUBLIC_SHARE: return "folder-publicshare-symbolic"; case BZ_FILESYSTEM_PATH_XDG_VIDEOS: return "folder-videos-symbolic"; case BZ_FILESYSTEM_PATH_XDG_CONFIG: return "emblem-system-symbolic"; case BZ_FILESYSTEM_PATH_SYSTEM_ROOT: case BZ_FILESYSTEM_PATH_HOME_SUBDIR: case BZ_FILESYSTEM_PATH_XDG_TEMPLATES: case BZ_FILESYSTEM_PATH_XDG_CACHE: case BZ_FILESYSTEM_PATH_XDG_DATA: case BZ_FILESYSTEM_PATH_XDG_RUN: case BZ_FILESYSTEM_PATH_CUSTOM: default: return "folder-symbolic"; } } BzBusPolicy * bz_bus_policy_new (GBusType bus_type, const char *bus_name, BzBusPolicyPermission permission) { BzBusPolicy *policy = NULL; g_return_val_if_fail (bus_type != G_BUS_TYPE_NONE, NULL); g_return_val_if_fail (bus_name != NULL && *bus_name != '\0', NULL); policy = g_new0 (BzBusPolicy, 1); policy->bus_type = bus_type; policy->bus_name = g_strdup (bus_name); policy->permission = permission; return policy; } void bz_bus_policy_free (BzBusPolicy *self) { g_return_if_fail (self != NULL); g_free (self->bus_name); g_free (self); } BzAppPermissions * bz_app_permissions_new (void) { return g_object_new (BZ_TYPE_APP_PERMISSIONS, NULL); } void bz_app_permissions_seal (BzAppPermissions *self) { g_return_if_fail (BZ_IS_APP_PERMISSIONS (self)); if (self->is_sealed) return; self->is_sealed = TRUE; if (self->filesystem_read) qsort (self->filesystem_read->pdata, self->filesystem_read->len, sizeof (gpointer), cmp_filesystem_path_pointers); if (self->filesystem_full) qsort (self->filesystem_full->pdata, self->filesystem_full->len, sizeof (gpointer), cmp_filesystem_path_pointers); if (self->bus_policies) qsort (self->bus_policies->pdata, self->bus_policies->len, sizeof (gpointer), cmp_bus_policy_qsort); } gboolean bz_app_permissions_is_sealed (BzAppPermissions *self) { g_return_val_if_fail (BZ_IS_APP_PERMISSIONS (self), TRUE); return self->is_sealed; } gboolean bz_app_permissions_is_empty (BzAppPermissions *self) { g_return_val_if_fail (BZ_IS_APP_PERMISSIONS (self), TRUE); return (self->flags == BZ_APP_PERMISSIONS_FLAGS_NONE && (self->filesystem_read == NULL || self->filesystem_read->len == 0) && (self->filesystem_full == NULL || self->filesystem_full->len == 0) && (self->bus_policies == NULL || self->bus_policies->len == 0)); } void bz_app_permissions_set_flags (BzAppPermissions *self, BzAppPermissionsFlags flags) { g_return_if_fail (BZ_IS_APP_PERMISSIONS (self)); g_assert (!self->is_sealed); self->flags = flags; } BzAppPermissionsFlags bz_app_permissions_get_flags (BzAppPermissions *self) { g_return_val_if_fail (BZ_IS_APP_PERMISSIONS (self), BZ_APP_PERMISSIONS_FLAGS_NONE); return self->flags; } void bz_app_permissions_add_flag (BzAppPermissions *self, BzAppPermissionsFlags flags) { g_return_if_fail (BZ_IS_APP_PERMISSIONS (self)); g_return_if_fail (flags != BZ_APP_PERMISSIONS_FLAGS_NONE); g_assert (!self->is_sealed); self->flags = self->flags | flags; } void bz_app_permissions_remove_flag (BzAppPermissions *self, BzAppPermissionsFlags flags) { g_return_if_fail (BZ_IS_APP_PERMISSIONS (self)); g_return_if_fail (flags != BZ_APP_PERMISSIONS_FLAGS_NONE); g_assert (!self->is_sealed); self->flags = (self->flags & (~flags)); } void bz_app_permissions_add_filesystem_read (BzAppPermissions *self, BzFilesystemPathType type, const char *subpath) { g_return_if_fail (BZ_IS_APP_PERMISSIONS (self)); g_assert (!self->is_sealed); if (app_permissions_get_array_index (self->filesystem_read, type, subpath) != DOES_NOT_CONTAIN || app_permissions_get_array_index (self->filesystem_full, type, subpath) != DOES_NOT_CONTAIN) return; if (self->filesystem_read == NULL) self->filesystem_read = g_ptr_array_new_with_free_func ((GDestroyNotify) bz_filesystem_path_free); g_ptr_array_add (self->filesystem_read, bz_filesystem_path_new (type, subpath)); } const GPtrArray * bz_app_permissions_get_filesystem_read (BzAppPermissions *self) { g_return_val_if_fail (BZ_IS_APP_PERMISSIONS (self), NULL); return self->filesystem_read; } void bz_app_permissions_add_filesystem_full (BzAppPermissions *self, BzFilesystemPathType type, const char *subpath) { guint read_index = DOES_NOT_CONTAIN; g_return_if_fail (BZ_IS_APP_PERMISSIONS (self)); g_assert (!self->is_sealed); if (app_permissions_get_array_index (self->filesystem_full, type, subpath) != DOES_NOT_CONTAIN) return; if (self->filesystem_full == NULL) self->filesystem_full = g_ptr_array_new_with_free_func ((GDestroyNotify) bz_filesystem_path_free); g_ptr_array_add (self->filesystem_full, bz_filesystem_path_new (type, subpath)); read_index = app_permissions_get_array_index (self->filesystem_read, type, subpath); if (read_index != DOES_NOT_CONTAIN) { g_ptr_array_remove_index (self->filesystem_read, read_index); if (self->filesystem_read->len == 0) g_clear_pointer (&self->filesystem_read, g_ptr_array_unref); } } const GPtrArray * bz_app_permissions_get_filesystem_full (BzAppPermissions *self) { g_return_val_if_fail (BZ_IS_APP_PERMISSIONS (self), NULL); return self->filesystem_full; } void bz_app_permissions_add_bus_policy (BzAppPermissions *self, GBusType bus_type, const char *bus_name, BzBusPolicyPermission permission) { g_return_if_fail (BZ_IS_APP_PERMISSIONS (self)); g_return_if_fail (bus_type != G_BUS_TYPE_NONE); g_return_if_fail (bus_name != NULL && *bus_name != '\0'); g_return_if_fail (permission != BZ_BUS_POLICY_PERMISSION_UNKNOWN); g_assert (!self->is_sealed); for (unsigned int i = 0; self->bus_policies != NULL && i < self->bus_policies->len; i++) { BzBusPolicy *policy = g_ptr_array_index (self->bus_policies, i); if (policy->bus_type == bus_type && g_str_equal (policy->bus_name, bus_name)) { policy->permission = MAX (policy->permission, permission); return; } } if (permission == BZ_BUS_POLICY_PERMISSION_NONE) return; if (self->bus_policies == NULL) self->bus_policies = g_ptr_array_new_with_free_func ((GDestroyNotify) bz_bus_policy_free); g_ptr_array_add (self->bus_policies, bz_bus_policy_new (bus_type, bus_name, permission)); } const BzBusPolicy *const * bz_app_permissions_get_bus_policies (BzAppPermissions *self, size_t *out_n_bus_policies) { g_return_val_if_fail (BZ_IS_APP_PERMISSIONS (self), NULL); g_return_val_if_fail (self->is_sealed, NULL); if (out_n_bus_policies != NULL) *out_n_bus_policies = (self->bus_policies != NULL) ? self->bus_policies->len : 0; return (self->bus_policies != NULL && self->bus_policies->len > 0) ? (const BzBusPolicy *const *) self->bus_policies->pdata : NULL; } BzAppPermissions * bz_app_permissions_new_from_metadata (GKeyFile *keyfile, GError **error) { char **strv = NULL; BzAppPermissions *permissions = NULL; BzAppPermissionsFlags flags = BZ_APP_PERMISSIONS_FLAGS_NONE; g_autofree char *app_id = NULL; g_autofree char *mpris_id = NULL; g_autofree char *app_id_non_devel = NULL; g_autofree char *mpris_id_non_devel = NULL; g_return_val_if_fail (keyfile != NULL, NULL); permissions = bz_app_permissions_new (); app_id = g_key_file_get_value (keyfile, "Application", "name", NULL); strv = g_key_file_get_string_list (keyfile, "Context", "sockets", NULL, NULL); if (strv != NULL && g_strv_contains ((const gchar *const *) strv, "system-bus")) flags |= BZ_APP_PERMISSIONS_FLAGS_SYSTEM_BUS | BZ_APP_PERMISSIONS_FLAGS_ESCAPE_SANDBOX; if (strv != NULL && g_strv_contains ((const gchar *const *) strv, "session-bus")) flags |= BZ_APP_PERMISSIONS_FLAGS_SESSION_BUS | BZ_APP_PERMISSIONS_FLAGS_ESCAPE_SANDBOX; if (strv != NULL && !g_strv_contains ((const gchar *const *) strv, "fallback-x11") && g_strv_contains ((const gchar *const *) strv, "x11")) flags |= BZ_APP_PERMISSIONS_FLAGS_X11; if (strv != NULL && g_strv_contains ((const gchar *const *) strv, "fallback-x11") && !g_strv_contains ((const gchar *const *) strv, "wayland")) flags |= BZ_APP_PERMISSIONS_FLAGS_X11; if (strv != NULL && g_strv_contains ((const gchar *const *) strv, "pulseaudio")) flags |= BZ_APP_PERMISSIONS_FLAGS_AUDIO_DEVICES; if (strv != NULL && g_strv_contains ((const char *const *) strv, "gpg-agent")) flags |= BZ_APP_PERMISSIONS_FLAGS_ESCAPE_SANDBOX; g_strfreev (strv); strv = g_key_file_get_string_list (keyfile, "Context", "devices", NULL, NULL); if (strv != NULL && g_strv_contains ((const gchar *const *) strv, "all")) flags |= BZ_APP_PERMISSIONS_FLAGS_DEVICES; if (strv != NULL && g_strv_contains ((const gchar *const *) strv, "input")) flags |= BZ_APP_PERMISSIONS_FLAGS_INPUT_DEVICES; if (strv != NULL && (g_strv_contains ((const gchar *const *) strv, "shm") || g_strv_contains ((const gchar *const *) strv, "kvm"))) flags |= BZ_APP_PERMISSIONS_FLAGS_SYSTEM_DEVICES; g_strfreev (strv); strv = g_key_file_get_string_list (keyfile, "Context", "shared", NULL, NULL); if (strv != NULL && g_strv_contains ((const gchar *const *) strv, "network")) flags |= BZ_APP_PERMISSIONS_FLAGS_NETWORK; g_strfreev (strv); strv = g_key_file_get_string_list (keyfile, "Context", "filesystems", NULL, NULL); if (strv != NULL) { const struct { const gchar *key; BzAppPermissionsFlags perm; } filesystems_access[] = { { "home", BZ_APP_PERMISSIONS_FLAGS_HOME_FULL }, { "home:rw", BZ_APP_PERMISSIONS_FLAGS_HOME_FULL }, { "home:ro", BZ_APP_PERMISSIONS_FLAGS_HOME_READ }, { "~", BZ_APP_PERMISSIONS_FLAGS_HOME_FULL }, { "~:rw", BZ_APP_PERMISSIONS_FLAGS_HOME_FULL }, { "~:ro", BZ_APP_PERMISSIONS_FLAGS_HOME_READ }, { "host", BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL }, { "host:rw", BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL }, { "host:ro", BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ }, { "xdg-config/kdeglobals:ro", BZ_APP_PERMISSIONS_FLAGS_NONE }, { "xdg-download", BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_FULL }, { "xdg-download:rw", BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_FULL }, { "xdg-download:ro", BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_READ }, { "xdg-data/flatpak/overrides:create", BZ_APP_PERMISSIONS_FLAGS_ESCAPE_SANDBOX }, { "xdg-run/pipewire-0", BZ_APP_PERMISSIONS_FLAGS_SCREEN | BZ_APP_PERMISSIONS_FLAGS_AUDIO_DEVICES }, { "xdg-run/pipewire-0:rw", BZ_APP_PERMISSIONS_FLAGS_SCREEN | BZ_APP_PERMISSIONS_FLAGS_AUDIO_DEVICES }, { "xdg-run/pipewire-0:ro", BZ_APP_PERMISSIONS_FLAGS_SCREEN | BZ_APP_PERMISSIONS_FLAGS_AUDIO_DEVICES }, { "xdg-run/gvfsd", BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL }, }; guint filesystems_hits = 0; guint strv_len = g_strv_length (strv); for (guint i = 0; i < G_N_ELEMENTS (filesystems_access); i++) { guint index = get_strv_index ((const gchar *const *) strv, filesystems_access[i].key); if (index < strv_len) { flags |= filesystems_access[i].perm; filesystems_hits++; strv[index][0] = '\0'; } } if ((flags & BZ_APP_PERMISSIONS_FLAGS_HOME_FULL) != 0) flags = flags & ~BZ_APP_PERMISSIONS_FLAGS_HOME_READ; if ((flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL) != 0) flags = flags & ~BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ; if ((flags & BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_FULL) != 0) flags = flags & ~BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_READ; if (strv_len > filesystems_hits) { const struct { const gchar *prefix; BzFilesystemPathType type; } filesystems_other[] = { { "/", BZ_FILESYSTEM_PATH_SYSTEM_ROOT }, { "home/", BZ_FILESYSTEM_PATH_HOME_SUBDIR }, { "~/", BZ_FILESYSTEM_PATH_HOME_SUBDIR }, { "host-os", BZ_FILESYSTEM_PATH_HOST_OS }, { "host-etc", BZ_FILESYSTEM_PATH_HOST_ETC }, { "xdg-desktop", BZ_FILESYSTEM_PATH_XDG_DESKTOP }, { "xdg-documents", BZ_FILESYSTEM_PATH_XDG_DOCUMENTS }, { "xdg-music", BZ_FILESYSTEM_PATH_XDG_MUSIC }, { "xdg-pictures", BZ_FILESYSTEM_PATH_XDG_PICTURES }, { "xdg-public-share", BZ_FILESYSTEM_PATH_XDG_PUBLIC_SHARE }, { "xdg-videos", BZ_FILESYSTEM_PATH_XDG_VIDEOS }, { "xdg-templates", BZ_FILESYSTEM_PATH_XDG_TEMPLATES }, { "xdg-cache", BZ_FILESYSTEM_PATH_XDG_CACHE }, { "xdg-config", BZ_FILESYSTEM_PATH_XDG_CONFIG }, { "xdg-data", BZ_FILESYSTEM_PATH_XDG_DATA }, { "xdg-run", BZ_FILESYSTEM_PATH_XDG_RUN } }; flags |= BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_OTHER; for (guint j = 0; strv[j]; j++) { gchar *perm = strv[j]; gboolean is_readonly = FALSE; gchar *colon = NULL; guint i = 0; const gchar *subpath = NULL; if (!perm[0]) continue; is_readonly = g_str_has_suffix (perm, ":ro"); colon = strrchr (perm, ':'); if (colon) *colon = '\0'; for (i = 0; i < G_N_ELEMENTS (filesystems_other); i++) { if (g_str_has_prefix (perm, filesystems_other[i].prefix)) { const gchar *slash = NULL; if (filesystems_other[i].type == BZ_FILESYSTEM_PATH_SYSTEM_ROOT) { if (perm[1] != '\0') subpath = perm + 1; else subpath = NULL; } else { slash = strchr (perm, '/'); if (slash && slash != perm) subpath = slash + 1; } if (is_readonly) bz_app_permissions_add_filesystem_read (permissions, filesystems_other[i].type, subpath); else bz_app_permissions_add_filesystem_full (permissions, filesystems_other[i].type, subpath); break; } } if (i == G_N_ELEMENTS (filesystems_other)) { if (is_readonly) bz_app_permissions_add_filesystem_read (permissions, BZ_FILESYSTEM_PATH_CUSTOM, perm); else bz_app_permissions_add_filesystem_full (permissions, BZ_FILESYSTEM_PATH_CUSTOM, perm); } } } } g_strfreev (strv); if (!(flags & (BZ_APP_PERMISSIONS_FLAGS_SYSTEM_BUS | BZ_APP_PERMISSIONS_FLAGS_SESSION_BUS))) { const struct { GBusType bus_type; const char *keyfile_group; BzAppPermissionsFlags unfiltered_flag; } bus_policy_types[] = { { G_BUS_TYPE_SESSION, "Session Bus Policy", BZ_APP_PERMISSIONS_FLAGS_SESSION_BUS }, { G_BUS_TYPE_SYSTEM, "System Bus Policy", BZ_APP_PERMISSIONS_FLAGS_SYSTEM_BUS }, }; if (app_id != NULL) { mpris_id = g_strconcat ("org.mpris.MediaPlayer2.", app_id, NULL); app_id_non_devel = g_str_has_suffix (app_id, ".Devel") ? g_strndup (app_id, strlen (app_id) - strlen (".Devel")) : NULL; mpris_id_non_devel = (app_id_non_devel != NULL) ? g_strconcat ("org.mpris.MediaPlayer2.", app_id_non_devel, NULL) : NULL; } for (size_t h = 0; h < G_N_ELEMENTS (bus_policy_types); h++) { g_auto (GStrv) bus_policies = NULL; if (flags & bus_policy_types[h].unfiltered_flag) continue; bus_policies = g_key_file_get_keys (keyfile, bus_policy_types[h].keyfile_group, NULL, NULL); for (size_t i = 0; bus_policies != NULL && bus_policies[i] != NULL; i++) { const struct { GBusType bus_type; const char *bus_name; gboolean is_prefix; BzBusPolicyPermission permission_is_at_least; BzAppPermissionsFlags flags; } bus_policy_permissions[] = { { G_BUS_TYPE_SESSION, "ca.desrt.dconf", FALSE, BZ_BUS_POLICY_PERMISSION_TALK, BZ_APP_PERMISSIONS_FLAGS_SETTINGS }, { G_BUS_TYPE_SESSION, "org.freedesktop.Flatpak", FALSE, BZ_BUS_POLICY_PERMISSION_TALK, BZ_APP_PERMISSIONS_FLAGS_ESCAPE_SANDBOX }, { G_BUS_TYPE_SESSION, "org.freedesktop.impl.portal.PermissionStore", FALSE, BZ_BUS_POLICY_PERMISSION_TALK, BZ_APP_PERMISSIONS_FLAGS_ESCAPE_SANDBOX }, { G_BUS_TYPE_SESSION, "org.gtk.vfs.", TRUE, BZ_BUS_POLICY_PERMISSION_TALK, BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL }, }; const char *bus_name_pattern = bus_policies[i]; g_autofree char *bus_policy_str = NULL; BzBusPolicyPermission bus_policy = BZ_BUS_POLICY_PERMISSION_UNKNOWN; size_t j = 0; bus_policy_str = g_key_file_get_string (keyfile, bus_policy_types[h].keyfile_group, bus_name_pattern, NULL); g_assert (bus_policy_str != NULL); if (g_str_equal (bus_policy_str, "none")) bus_policy = BZ_BUS_POLICY_PERMISSION_NONE; else if (g_str_equal (bus_policy_str, "see")) bus_policy = BZ_BUS_POLICY_PERMISSION_SEE; else if (g_str_equal (bus_policy_str, "talk")) bus_policy = BZ_BUS_POLICY_PERMISSION_TALK; else if (g_str_equal (bus_policy_str, "own")) bus_policy = BZ_BUS_POLICY_PERMISSION_OWN; else bus_policy = BZ_BUS_POLICY_PERMISSION_UNKNOWN; if (app_id != NULL && bus_policy_types[h].bus_type == G_BUS_TYPE_SESSION && (g_str_equal (bus_name_pattern, app_id) || (g_str_has_prefix (bus_name_pattern, app_id) && bus_name_pattern[strlen (app_id)] == '.') || g_str_equal (bus_name_pattern, mpris_id) || g_str_equal (bus_name_pattern, "org.freedesktop.DBus") || g_str_has_prefix (bus_name_pattern, "org.freedesktop.portal."))) continue; if (app_id_non_devel != NULL && bus_policy_types[h].bus_type == G_BUS_TYPE_SESSION && (g_str_equal (bus_name_pattern, app_id_non_devel) || (g_str_has_prefix (bus_name_pattern, app_id_non_devel) && bus_name_pattern[strlen (app_id_non_devel)] == '.') || g_str_equal (bus_name_pattern, mpris_id_non_devel))) continue; for (j = 0; j < G_N_ELEMENTS (bus_policy_permissions); j++) { if (bus_policy_permissions[j].bus_type == bus_policy_types[h].bus_type && ((!bus_policy_permissions[j].is_prefix && g_str_equal (bus_name_pattern, bus_policy_permissions[j].bus_name)) || (bus_policy_permissions[j].is_prefix && g_str_has_prefix (bus_name_pattern, bus_policy_permissions[j].bus_name))) && bus_policy >= bus_policy_permissions[j].permission_is_at_least) { flags |= bus_policy_permissions[j].flags; break; } } if (j == G_N_ELEMENTS (bus_policy_permissions)) { flags |= BZ_APP_PERMISSIONS_FLAGS_BUS_POLICY_OTHER; bz_app_permissions_add_bus_policy (permissions, bus_policy_types[h].bus_type, bus_name_pattern, bus_policy); } } } } bz_app_permissions_set_flags (permissions, flags); bz_app_permissions_seal (permissions); return permissions; } void bz_app_permissions_serialize (BzAppPermissions *self, GVariantBuilder *builder) { GFlagsClass *flags_class = NULL; guint i = 0; g_return_if_fail (BZ_IS_APP_PERMISSIONS (self)); g_return_if_fail (builder != NULL); flags_class = g_type_class_ref (BZ_TYPE_APP_PERMISSIONS_FLAGS); if (self->flags != BZ_APP_PERMISSIONS_FLAGS_NONE) { g_autoptr (GVariantBuilder) sub_builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); for (i = 0; i < flags_class->n_values; i++) { if (self->flags & flags_class->values[i].value) g_variant_builder_add (sub_builder, "s", flags_class->values[i].value_nick); } g_variant_builder_add (builder, "{sv}", "permissions-flags", g_variant_builder_end (sub_builder)); } g_type_class_unref (flags_class); if (self->filesystem_read != NULL && self->filesystem_read->len > 0) { GEnumClass *enum_class = NULL; g_autoptr (GVariantBuilder) sub_builder = NULL; enum_class = g_type_class_ref (BZ_TYPE_FILESYSTEM_PATH_TYPE); sub_builder = g_variant_builder_new (G_VARIANT_TYPE ("a(ss)")); for (i = 0; i < self->filesystem_read->len; i++) { const BzFilesystemPath *path = g_ptr_array_index (self->filesystem_read, i); GEnumValue *enum_value = g_enum_get_value (enum_class, path->type); g_variant_builder_add (sub_builder, "(ss)", enum_value->value_nick, path->subpath ? path->subpath : ""); } g_variant_builder_add (builder, "{sv}", "permissions-filesystem-read", g_variant_builder_end (sub_builder)); g_type_class_unref (enum_class); } if (self->filesystem_full != NULL && self->filesystem_full->len > 0) { GEnumClass *enum_class = NULL; g_autoptr (GVariantBuilder) sub_builder = NULL; enum_class = g_type_class_ref (BZ_TYPE_FILESYSTEM_PATH_TYPE); sub_builder = g_variant_builder_new (G_VARIANT_TYPE ("a(ss)")); for (i = 0; i < self->filesystem_full->len; i++) { const BzFilesystemPath *path = g_ptr_array_index (self->filesystem_full, i); GEnumValue *enum_value = g_enum_get_value (enum_class, path->type); g_variant_builder_add (sub_builder, "(ss)", enum_value->value_nick, path->subpath ? path->subpath : ""); } g_variant_builder_add (builder, "{sv}", "permissions-filesystem-full", g_variant_builder_end (sub_builder)); g_type_class_unref (enum_class); } if (self->bus_policies != NULL && self->bus_policies->len > 0) { GEnumClass *enum_class = NULL; g_autoptr (GVariantBuilder) sub_builder = NULL; enum_class = g_type_class_ref (BZ_TYPE_BUS_POLICY_PERMISSION); sub_builder = g_variant_builder_new (G_VARIANT_TYPE ("a(iss)")); for (i = 0; i < self->bus_policies->len; i++) { BzBusPolicy *policy = g_ptr_array_index (self->bus_policies, i); GEnumValue *enum_value = g_enum_get_value (enum_class, policy->permission); g_variant_builder_add (sub_builder, "(iss)", (gint32) policy->bus_type, policy->bus_name, enum_value->value_nick); } g_variant_builder_add (builder, "{sv}", "permissions-bus-policies", g_variant_builder_end (sub_builder)); g_type_class_unref (enum_class); } } gboolean bz_app_permissions_deserialize (BzAppPermissions *self, GVariant *import, GError **error) { g_autoptr (GVariantIter) iter = NULL; g_return_val_if_fail (BZ_IS_APP_PERMISSIONS (self), FALSE); g_return_val_if_fail (import != NULL, FALSE); iter = g_variant_iter_new (import); for (;;) { g_autofree char *key = NULL; g_autoptr (GVariant) value = NULL; if (!g_variant_iter_next (iter, "{sv}", &key, &value)) break; if (g_strcmp0 (key, "permissions-flags") == 0) { GFlagsClass *flags_class = NULL; g_autoptr (GVariantIter) flags_iter = NULL; flags_class = g_type_class_ref (BZ_TYPE_APP_PERMISSIONS_FLAGS); flags_iter = g_variant_iter_new (value); self->flags = BZ_APP_PERMISSIONS_FLAGS_NONE; for (;;) { g_autofree char *flag_nick = NULL; if (!g_variant_iter_next (flags_iter, "s", &flag_nick)) break; for (guint i = 0; i < flags_class->n_values; i++) { if (g_str_equal (flag_nick, flags_class->values[i].value_nick)) { self->flags |= flags_class->values[i].value; break; } } } g_type_class_unref (flags_class); } else if (g_strcmp0 (key, "permissions-filesystem-read") == 0) { GEnumClass *enum_class = NULL; g_autoptr (GVariantIter) paths_iter = NULL; enum_class = g_type_class_ref (BZ_TYPE_FILESYSTEM_PATH_TYPE); if (self->filesystem_read == NULL) self->filesystem_read = g_ptr_array_new_with_free_func ((GDestroyNotify) bz_filesystem_path_free); paths_iter = g_variant_iter_new (value); for (;;) { g_autofree char *type_nick = NULL; g_autofree char *subpath = NULL; if (!g_variant_iter_next (paths_iter, "(ss)", &type_nick, &subpath)) break; for (guint i = 0; i < enum_class->n_values; i++) { if (g_str_equal (type_nick, enum_class->values[i].value_nick)) { g_ptr_array_add (self->filesystem_read, bz_filesystem_path_new (enum_class->values[i].value, subpath[0] ? subpath : NULL)); break; } } } g_type_class_unref (enum_class); } else if (g_strcmp0 (key, "permissions-filesystem-full") == 0) { GEnumClass *enum_class = NULL; g_autoptr (GVariantIter) paths_iter = NULL; enum_class = g_type_class_ref (BZ_TYPE_FILESYSTEM_PATH_TYPE); if (self->filesystem_full == NULL) self->filesystem_full = g_ptr_array_new_with_free_func ((GDestroyNotify) bz_filesystem_path_free); paths_iter = g_variant_iter_new (value); for (;;) { g_autofree char *type_nick = NULL; g_autofree char *subpath = NULL; if (!g_variant_iter_next (paths_iter, "(ss)", &type_nick, &subpath)) break; for (guint i = 0; i < enum_class->n_values; i++) { if (g_str_equal (type_nick, enum_class->values[i].value_nick)) { g_ptr_array_add (self->filesystem_full, bz_filesystem_path_new (enum_class->values[i].value, subpath[0] ? subpath : NULL)); break; } } } g_type_class_unref (enum_class); } else if (g_strcmp0 (key, "permissions-bus-policies") == 0) { GEnumClass *enum_class = NULL; g_autoptr (GVariantIter) policies_iter = NULL; enum_class = g_type_class_ref (BZ_TYPE_BUS_POLICY_PERMISSION); if (self->bus_policies == NULL) self->bus_policies = g_ptr_array_new_with_free_func ((GDestroyNotify) bz_bus_policy_free); policies_iter = g_variant_iter_new (value); for (;;) { gint32 bus_type_int = 0; g_autofree char *bus_name = NULL; g_autofree char *permission_nick = NULL; if (!g_variant_iter_next (policies_iter, "(iss)", &bus_type_int, &bus_name, &permission_nick)) break; for (guint i = 0; i < enum_class->n_values; i++) { if (g_str_equal (permission_nick, enum_class->values[i].value_nick)) { g_ptr_array_add (self->bus_policies, bz_bus_policy_new ((GBusType) bus_type_int, bus_name, enum_class->values[i].value)); break; } } } g_type_class_unref (enum_class); } } bz_app_permissions_seal (self); return TRUE; } static gint cmp_filesystem_path_pointers (gconstpointer item1, gconstpointer item2) { const BzFilesystemPath *const *pitem1 = item1; const BzFilesystemPath *const *pitem2 = item2; const BzFilesystemPath *path1 = *pitem1; const BzFilesystemPath *path2 = *pitem2; if (path1->type != path2->type) return path1->type - path2->type; return g_strcmp0 (path1->subpath, path2->subpath); } static int cmp_bus_policy_qsort (const void *item1, const void *item2) { const BzBusPolicy *const *pitem1 = item1; const BzBusPolicy *const *pitem2 = item2; const BzBusPolicy *policy1 = *pitem1; const BzBusPolicy *policy2 = *pitem2; if (policy1->bus_type != policy2->bus_type) return policy1->bus_type - policy2->bus_type; return strcmp (policy1->bus_name, policy2->bus_name); } static guint app_permissions_get_array_index (GPtrArray *array, BzFilesystemPathType type, const char *subpath) { if (array == NULL) return DOES_NOT_CONTAIN; for (guint i = 0; i < array->len; i++) { const BzFilesystemPath *path = g_ptr_array_index (array, i); if (path->type == type && g_strcmp0 (path->subpath, subpath) == 0) return i; } return DOES_NOT_CONTAIN; } static guint get_strv_index (const gchar *const *strv, const gchar *value) { guint ii; for (ii = 0; strv[ii]; ii++) { if (g_str_equal (strv[ii], value)) break; } return ii; } bazaar-orig-v0.7.14/src/bz-addon-tile.h0000664000175000017500000000227115166123241016533 0ustar hasanhasan/* bz-addon-tile.h * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry-group.h" #include "bz-list-tile.h" #include G_BEGIN_DECLS #define BZ_TYPE_ADDON_TILE (bz_addon_tile_get_type ()) G_DECLARE_FINAL_TYPE (BzAddonTile, bz_addon_tile, BZ, ADDON_TILE, BzListTile) GtkWidget * bz_addon_tile_new (void); void bz_addon_tile_set_group (BzAddonTile *self, BzEntryGroup *group); BzEntryGroup * bz_addon_tile_get_group (BzAddonTile *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-bulk-install-dialog-result.txt0000664000175000017500000000033315166123241022252 0ustar hasanhasanprefix=bz name=bulk_install_dialog_result parent-prefix=g parent-name=object author=AUTOGEN include="bz-entry.h" property=entries GListModel G_TYPE_LIST_MODEL object property=confirmed gboolean G_TYPE_BOOLEAN boolean bazaar-orig-v0.7.14/src/bz-curated-app-tile.h0000664000175000017500000000241415166123241017652 0ustar hasanhasan/* bz-curated-app-tile.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-entry-group.h" G_BEGIN_DECLS #define BZ_TYPE_CURATED_APP_TILE (bz_curated_app_tile_get_type ()) G_DECLARE_FINAL_TYPE (BzCuratedAppTile, bz_curated_app_tile, BZ, CURATED_APP_TILE, AdwBin) BzCuratedAppTile * bz_curated_app_tile_new (void); BzEntryGroup * bz_curated_app_tile_get_group (BzCuratedAppTile *self); void bz_curated_app_tile_set_group (BzCuratedAppTile *self, BzEntryGroup *group); G_END_DECLS /* End of bz-curated-app-tile.h */ bazaar-orig-v0.7.14/src/bz-state-info.txt0000664000175000017500000000635615166123241017164 0ustar hasanhasanprefix=bz name=state_info parent-prefix=g parent-name=object author=AUTOGEN include="bz-application-map-factory.h" include="bz-auth-state.h" include="bz-backend.h" include="bz-content-provider.h" include="bz-entry-cache-manager.h" include="bz-flathub-state.h" include="bz-internal-config.h" include="bz-main-config.h" include="bz-search-engine.h" include="bz-transaction-manager.h" property=all_entries GListModel G_TYPE_LIST_MODEL object property=all_entry_groups GListModel G_TYPE_LIST_MODEL object property=filtered_entry_groups GListModel G_TYPE_LIST_MODEL object property=all_installed_entry_groups GListModel G_TYPE_LIST_MODEL object property=all_user_data_entry_groups GListModel G_TYPE_LIST_MODEL object property=allow_manual_sync gboolean G_TYPE_BOOLEAN boolean property=application_factory BzApplicationMapFactory BZ_TYPE_APPLICATION_MAP_FACTORY object property=auth_state BzAuthState BZ_TYPE_AUTH_STATE object property=available_updates GListModel G_TYPE_LIST_MODEL object property=backend BzBackend BZ_TYPE_BACKEND object property=background_task_label char G_TYPE_STRING string property=blocklists GListModel G_TYPE_LIST_MODEL object property=blocklists_provider BzContentProvider BZ_TYPE_CONTENT_PROVIDER object property=busy gboolean G_TYPE_BOOLEAN boolean property=busy_progress double G_TYPE_DOUBLE double property=busy_progress_label char G_TYPE_STRING string property=busy_step_label char G_TYPE_STRING string property=cache_manager BzEntryCacheManager BZ_TYPE_ENTRY_CACHE_MANAGER object property=checking_for_updates gboolean G_TYPE_BOOLEAN boolean property=curated_configs GListModel G_TYPE_LIST_MODEL object property=curated_provider BzContentProvider BZ_TYPE_CONTENT_PROVIDER object property=debug_mode gboolean G_TYPE_BOOLEAN boolean property=disable_blocklists gboolean G_TYPE_BOOLEAN boolean property=donation_prompt_dismissed gboolean G_TYPE_BOOLEAN boolean property=entry_factory BzApplicationMapFactory BZ_TYPE_APPLICATION_MAP_FACTORY object property=flathub BzFlathubState BZ_TYPE_FLATHUB_STATE object property=has_flathub gboolean G_TYPE_BOOLEAN boolean property=have_connection gboolean G_TYPE_BOOLEAN boolean property=hide_eol gboolean G_TYPE_BOOLEAN boolean property=internal_config BzInternalConfig BZ_TYPE_INTERNAL_CONFIG object property=main_config BzMainConfig BZ_TYPE_MAIN_CONFIG object property=metered_connection gboolean G_TYPE_BOOLEAN boolean property=online gboolean G_TYPE_BOOLEAN boolean property=repositories GListModel G_TYPE_LIST_MODEL object property=search_engine BzSearchEngine BZ_TYPE_SEARCH_ENGINE object property=settings GSettings G_TYPE_SETTINGS object property=show_only_flathub gboolean G_TYPE_BOOLEAN boolean property=show_only_foss gboolean G_TYPE_BOOLEAN boolean property=show_only_verified gboolean G_TYPE_BOOLEAN boolean property=syncing gboolean G_TYPE_BOOLEAN boolean property=system_icon_theme GtkIconTheme GTK_TYPE_ICON_THEME object property=transaction_manager BzTransactionManager BZ_TYPE_TRANSACTION_MANAGER object property=txt_blocklists GListModel G_TYPE_LIST_MODEL object property=txt_blocklists_provider BzContentProvider BZ_TYPE_CONTENT_PROVIDER object property=user_icon_theme GtkIconTheme GTK_TYPE_ICON_THEME object property=parental_blocked_ids GListModel G_TYPE_LIST_MODEL object property=parental_age_rating int G_TYPE_INT int bazaar-orig-v0.7.14/src/bz-featured-tile.c0000664000175000017500000003705115166123241017244 0ustar hasanhasan/* bz-featured-tile.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-featured-tile.h" #include "bz-entry.h" #include "bz-group-tile-css-watcher.h" #include "bz-screenshot.h" #include "bz-util.h" #define BZ_TYPE_FEATURED_TILE_LAYOUT (bz_featured_tile_layout_get_type ()) G_DECLARE_FINAL_TYPE (BzFeaturedTileLayout, bz_featured_tile_layout, BZ, FEATURED_TILE_LAYOUT, GtkLayoutManager) struct _BzFeaturedTileLayout { GtkLayoutManager parent_instance; gboolean narrow_mode; GtkWidget *content_box; int last_width; }; G_DEFINE_FINAL_TYPE (BzFeaturedTileLayout, bz_featured_tile_layout, GTK_TYPE_LAYOUT_MANAGER) enum { LAYOUT_SIGNAL_NARROW_MODE_CHANGED, LAYOUT_SIGNAL_LAST }; static guint layout_signals[LAYOUT_SIGNAL_LAST] = { 0 }; static void bz_featured_tile_layout_measure (GtkLayoutManager *layout_manager, GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline) { GtkWidget *child; *minimum = 0; *natural = 0; *minimum_baseline = -1; *natural_baseline = -1; for (child = gtk_widget_get_first_child (widget); child != NULL; child = gtk_widget_get_next_sibling (child)) { int child_min; int child_nat; if (!gtk_widget_should_layout (child)) continue; gtk_widget_measure (child, orientation, for_size, &child_min, &child_nat, NULL, NULL); *minimum = MAX (*minimum, child_min); *natural = MAX (*natural, child_nat); } } static void bz_featured_tile_layout_allocate (GtkLayoutManager *layout_manager, GtkWidget *widget, gint width, gint height, gint baseline) { BzFeaturedTileLayout *self; GtkWidget *child; gboolean narrow_mode; int spacing; const int NARROW_THRESHOLD = 950; const int MIN_SPACING = 15; const int MAX_SPACING = 128; const int MAX_WIDTH = 1300; self = BZ_FEATURED_TILE_LAYOUT (layout_manager); narrow_mode = (width < NARROW_THRESHOLD); if (self->content_box != NULL && self->last_width != width) { self->last_width = width; if (narrow_mode) { spacing = 100; } else { if (width < NARROW_THRESHOLD) spacing = MIN_SPACING; else if (width >= MAX_WIDTH) spacing = MAX_SPACING; else spacing = MIN_SPACING + ((width - NARROW_THRESHOLD) * (MAX_SPACING - MIN_SPACING)) / (MAX_WIDTH - NARROW_THRESHOLD); } gtk_box_set_spacing (GTK_BOX (self->content_box), spacing); } for (child = gtk_widget_get_first_child (widget); child != NULL; child = gtk_widget_get_next_sibling (child)) { if (gtk_widget_should_layout (child)) gtk_widget_allocate (child, width, height, -1, NULL); } if (self->narrow_mode != narrow_mode) { self->narrow_mode = narrow_mode; g_signal_emit (self, layout_signals[LAYOUT_SIGNAL_NARROW_MODE_CHANGED], 0, self->narrow_mode); } } static void bz_featured_tile_layout_class_init (BzFeaturedTileLayoutClass *klass) { GtkLayoutManagerClass *layout_manager_class; layout_manager_class = GTK_LAYOUT_MANAGER_CLASS (klass); layout_manager_class->measure = bz_featured_tile_layout_measure; layout_manager_class->allocate = bz_featured_tile_layout_allocate; layout_signals[LAYOUT_SIGNAL_NARROW_MODE_CHANGED] = g_signal_new ("narrow-mode-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); } static void bz_featured_tile_layout_init (BzFeaturedTileLayout *self) { self->last_width = -1; } struct _BzFeaturedTile { GtkButton parent_instance; BzEntryGroup *group; gboolean narrow_mode; gboolean is_aotd; guint refresh_id; BzGroupTileCssWatcher *css; GtkWidget *stack; GtkWidget *image; GtkWidget *title; GtkWidget *description; GtkWidget *screenshot; GtkWidget *content_box; GdkPaintable *first_screenshot; gboolean has_screenshot; DexFuture *ui_entry_resolve; }; G_DEFINE_FINAL_TYPE (BzFeaturedTile, bz_featured_tile, GTK_TYPE_BUTTON) enum { PROP_0, PROP_GROUP, PROP_FIRST_SCREENSHOT, PROP_HAS_SCREENSHOT, PROP_NARROW, PROP_IS_AOTD, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { NULL, }; static void bz_featured_tile_refresh (BzFeaturedTile *self); static void update_screenshot (BzFeaturedTile *self); static gboolean bz_featured_tile_refresh_idle_cb (GWeakRef *wr) { g_autoptr (BzFeaturedTile) self = NULL; self = g_weak_ref_get (wr); if (self == NULL) goto done; self->refresh_id = 0; bz_featured_tile_refresh (self); done: return G_SOURCE_REMOVE; } static void schedule_refresh (BzFeaturedTile *self) { if (self->refresh_id != 0) return; self->refresh_id = g_idle_add_full ( G_PRIORITY_DEFAULT, (GSourceFunc) bz_featured_tile_refresh_idle_cb, bz_track_weak (self), bz_weak_release); } static void bz_featured_tile_layout_narrow_mode_changed_cb (GtkLayoutManager *layout_manager, gboolean narrow_mode, gpointer user_data) { BzFeaturedTile *self; self = BZ_FEATURED_TILE (user_data); if (self->narrow_mode != narrow_mode) { self->narrow_mode = narrow_mode; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NARROW]); schedule_refresh (self); } } static inline void notify_properties (BzFeaturedTile *self, gboolean has_screenshot) { if (self->has_screenshot != has_screenshot) { self->has_screenshot = has_screenshot; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_HAS_SCREENSHOT]); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_FIRST_SCREENSHOT]); } static DexFuture * ui_entry_resolved_finally (DexFuture *future, GWeakRef *wr) { g_autoptr (BzFeaturedTile) self = NULL; const GValue *value = NULL; gboolean has_screenshot = FALSE; bz_weak_get_or_return_reject (self, wr); value = dex_future_get_value (future, NULL); if (value != NULL) { BzEntry *ui_entry = NULL; g_autoptr (GListModel) screenshots = NULL; ui_entry = g_value_get_object (value); g_object_get (ui_entry, "screenshot-paintables", &screenshots, NULL); if (screenshots != NULL && g_list_model_get_n_items (screenshots) > 0) { self->first_screenshot = g_list_model_get_item (screenshots, 0); has_screenshot = TRUE; } } dex_clear (&self->ui_entry_resolve); notify_properties (self, has_screenshot); return NULL; } /* FIXME: duplicate code from rich-app-tile */ static void update_screenshot (BzFeaturedTile *self) { g_autoptr (BzResult) ui_entry_result = NULL; g_autoptr (GListModel) screenshots = NULL; dex_clear (&self->ui_entry_resolve); g_clear_object (&self->first_screenshot); if (self->group == NULL) { notify_properties (self, FALSE); return; } ui_entry_result = bz_entry_group_dup_ui_entry (self->group); self->ui_entry_resolve = dex_future_finally ( bz_result_dup_future (ui_entry_result), (DexFutureCallback) ui_entry_resolved_finally, bz_track_weak (self), bz_weak_release); } static void bz_featured_tile_refresh (BzFeaturedTile *self) { gtk_label_set_wrap (GTK_LABEL (self->description), self->narrow_mode); gtk_label_set_lines (GTK_LABEL (self->description), self->narrow_mode ? 2 : 1); update_screenshot (self); } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static int get_start_margin (gpointer object, gboolean narrow) { return narrow ? 20 : 50; } static void bz_featured_tile_dispose (GObject *object) { BzFeaturedTile *self; self = BZ_FEATURED_TILE (object); g_clear_handle_id (&self->refresh_id, g_source_remove); if (self->group != NULL) g_signal_handlers_disconnect_by_func (self->group, schedule_refresh, self); g_clear_object (&self->group); g_clear_object (&self->css); g_clear_object (&self->first_screenshot); G_OBJECT_CLASS (bz_featured_tile_parent_class)->dispose (object); } static void bz_featured_tile_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzFeaturedTile *self; self = BZ_FEATURED_TILE (object); switch (prop_id) { case PROP_GROUP: g_value_set_object (value, bz_featured_tile_get_group (self)); break; case PROP_FIRST_SCREENSHOT: g_value_set_object (value, self->first_screenshot); break; case PROP_HAS_SCREENSHOT: g_value_set_boolean (value, self->has_screenshot); break; case PROP_NARROW: g_value_set_boolean (value, self->narrow_mode); break; case PROP_IS_AOTD: g_value_set_boolean (value, bz_featured_tile_get_is_aotd (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void bz_featured_tile_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzFeaturedTile *self; self = BZ_FEATURED_TILE (object); switch (prop_id) { case PROP_GROUP: bz_featured_tile_set_group (self, g_value_get_object (value)); break; case PROP_IS_AOTD: bz_featured_tile_set_is_aotd (self, g_value_get_boolean (value)); break; case PROP_FIRST_SCREENSHOT: case PROP_HAS_SCREENSHOT: case PROP_NARROW: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void bz_featured_tile_class_init (BzFeaturedTileClass *klass) { GObjectClass *object_class; GtkWidgetClass *widget_class; object_class = G_OBJECT_CLASS (klass); widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_featured_tile_dispose; object_class->get_property = bz_featured_tile_get_property; object_class->set_property = bz_featured_tile_set_property; props[PROP_GROUP] = g_param_spec_object ("group", NULL, NULL, BZ_TYPE_ENTRY_GROUP, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); props[PROP_FIRST_SCREENSHOT] = g_param_spec_object ("first-screenshot", NULL, NULL, GDK_TYPE_PAINTABLE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_HAS_SCREENSHOT] = g_param_spec_boolean ("has-screenshot", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_NARROW] = g_param_spec_boolean ("narrow", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_IS_AOTD] = g_param_spec_boolean ("is-aotd", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_SCREENSHOT); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-featured-tile.ui"); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, get_start_margin); gtk_widget_class_bind_template_child (widget_class, BzFeaturedTile, image); gtk_widget_class_bind_template_child (widget_class, BzFeaturedTile, title); gtk_widget_class_bind_template_child (widget_class, BzFeaturedTile, description); gtk_widget_class_bind_template_child (widget_class, BzFeaturedTile, screenshot); gtk_widget_class_bind_template_child (widget_class, BzFeaturedTile, content_box); gtk_widget_class_set_css_name (widget_class, "featured-tile"); gtk_widget_class_set_layout_manager_type (widget_class, BZ_TYPE_FEATURED_TILE_LAYOUT); } static void bz_featured_tile_init (BzFeaturedTile *self) { GtkLayoutManager *layout_manager; BzFeaturedTileLayout *tile_layout; gtk_widget_init_template (GTK_WIDGET (self)); self->css = bz_group_tile_css_watcher_new (); bz_group_tile_css_watcher_set_widget (self->css, GTK_WIDGET (self)); layout_manager = gtk_widget_get_layout_manager (GTK_WIDGET (self)); g_warn_if_fail (layout_manager != NULL); tile_layout = BZ_FEATURED_TILE_LAYOUT (layout_manager); tile_layout->content_box = self->content_box; g_signal_connect_object (layout_manager, "narrow-mode-changed", G_CALLBACK (bz_featured_tile_layout_narrow_mode_changed_cb), self, 0); } BzFeaturedTile * bz_featured_tile_new (BzEntryGroup *group) { return g_object_new (BZ_TYPE_FEATURED_TILE, "group", group, NULL); } BzEntryGroup * bz_featured_tile_get_group (BzFeaturedTile *self) { g_return_val_if_fail (BZ_IS_FEATURED_TILE (self), NULL); return self->group; } void bz_featured_tile_set_group (BzFeaturedTile *self, BzEntryGroup *group) { g_return_if_fail (BZ_IS_FEATURED_TILE (self)); g_return_if_fail (group == NULL || BZ_IS_ENTRY_GROUP (group)); g_clear_handle_id (&self->refresh_id, g_source_remove); if (self->group != NULL) g_signal_handlers_disconnect_by_func (self->group, schedule_refresh, self); g_clear_object (&self->group); if (group != NULL) { self->group = g_object_ref (group); g_signal_connect_swapped (group, "notify", G_CALLBACK (schedule_refresh), self); schedule_refresh (self); } bz_group_tile_css_watcher_set_group (self->css, group); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_GROUP]); } gboolean bz_featured_tile_get_is_aotd (BzFeaturedTile *self) { g_return_val_if_fail (BZ_IS_FEATURED_TILE (self), FALSE); return self->is_aotd; } void bz_featured_tile_set_is_aotd (BzFeaturedTile *self, gboolean is_aotd) { g_return_if_fail (BZ_IS_FEATURED_TILE (self)); if (self->is_aotd == is_aotd) return; self->is_aotd = is_aotd; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_IS_AOTD]); } bazaar-orig-v0.7.14/src/bz-installed-tile.blp0000664000175000017500000000677315166123241017766 0ustar hasanhasanusing Gtk 4.0; template $BzInstalledTile: $BzListTile { accessibility { labelled-by: title_label; described-by: description_label; } child: Box { orientation: horizontal; spacing: 10; Image icon_picture { margin-start: 10; margin-top: 10; margin-bottom: 10; height-request: 64; width-request: 64; pixel-size: 64; paintable: bind template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable; visible: bind $invert_boolean($is_null(template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable) as ) as ; styles ["icon-dropshadow"] } Image fallback_icon { margin-start: 10; margin-top: 10; margin-bottom: 10; height-request: 64; width-request: 64; pixel-size: 64; icon-name: "application-x-executable"; visible: bind icon_picture.visible inverted; styles ["icon-dropshadow"] } Box { orientation: vertical; valign: center; spacing: 4; Label title_label { xalign: 0.0; ellipsize: end; single-line-mode: true; has-tooltip: true; tooltip-text: bind template.group as <$BzEntryGroup>.id; label: bind template.group as <$BzEntryGroup>.title; } Label description_label { halign: start; ellipsize: end; single-line-mode: true; label: bind $format_description(template.group as <$BzEntryGroup>.installed-size, template.group as <$BzEntryGroup>.installed-versions) as ; styles ["dimmed", "caption", "installed-size"] } Label { xalign: 0.0; ellipsize: end; single-line-mode: true; visible: bind $invert_boolean($is_null(template.group as <$BzEntryGroup>.eol) as ) as ; label: _("Stopped Receiving Updates"); styles ["warning", "caption"] } } Button support_button { styles [ "circular", "flat", "suggested-action", "support" ] has-tooltip: true; tooltip-text: _("Support This Application"); width-request: 32; height-request: 32; valign: center; icon-name: "heart-filled-symbolic"; visible: bind $invert_boolean($is_null(template.group as <$BzEntryGroup>.donation-url) as ) as ; clicked => $support_cb() swapped; } Box { orientation: horizontal; spacing: 8; margin-end: 8; hexpand: true; halign: end; Button addons_button { styles [ "flat" ] tooltip-text: _("Manage Add-Ons"); visible: bind $invert_boolean($is_zero(template.group as <$BzEntryGroup>.n-addons as ) as ) as ; valign: center; icon-name: "application-x-addon-symbolic"; clicked => $install_addons_cb() swapped; } Button remove_button { styles [ "flat", ] tooltip-text: _("Remove"); valign: center; icon-name: "user-trash-symbolic"; visible: bind $invert_boolean($is_zero(template.group as <$BzEntryGroup>.removable) as ) as ; sensitive: bind $invert_boolean($is_zero(template.group as <$BzEntryGroup>.removable-and-available) as ) as ; clicked => $remove_cb() swapped; } Image { pixel-size: 14; icon-name: "go-next-symbolic"; margin-end: 4; styles ["dimmed"] } } }; }bazaar-orig-v0.7.14/src/bz-favorites-tile.h0000664000175000017500000000237315166123241017453 0ustar hasanhasan/* bz-favorites-tile.h * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry-group.h" #include "bz-list-tile.h" #include G_BEGIN_DECLS #define BZ_TYPE_FAVORITES_TILE (bz_favorites_tile_get_type ()) G_DECLARE_FINAL_TYPE (BzFavoritesTile, bz_favorites_tile, BZ, FAVORITES_TILE, BzListTile) GtkWidget * bz_favorites_tile_new (void); void bz_favorites_tile_set_group (BzFavoritesTile *self, BzEntryGroup *group); BzEntryGroup * bz_favorites_tile_get_group (BzFavoritesTile *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-entry-selection-row.h0000664000175000017500000000240215166123241020440 0ustar hasanhasan/* bz-entry-selection-row.h * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-flatpak-entry.h" #include "bz-repository.h" G_BEGIN_DECLS #define BZ_TYPE_ENTRY_SELECTION_ROW (bz_entry_selection_row_get_type ()) G_DECLARE_FINAL_TYPE (BzEntrySelectionRow, bz_entry_selection_row, BZ, ENTRY_SELECTION_ROW, AdwActionRow) BzEntrySelectionRow * bz_entry_selection_row_new (BzFlatpakEntry *entry, BzRepository *repository); GtkCheckButton * bz_entry_selection_row_get_radio (BzEntrySelectionRow *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-rounded-picture.h0000664000175000017500000000261115166123241017622 0ustar hasanhasan/* bz-rounded-picture.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_ROUNDED_PICTURE (bz_rounded_picture_get_type ()) G_DECLARE_FINAL_TYPE (BzRoundedPicture, bz_rounded_picture, BZ, ROUNDED_PICTURE, GtkWidget) GtkWidget * bz_rounded_picture_new (void); void bz_rounded_picture_set_paintable (BzRoundedPicture *self, GdkPaintable *paintable); GdkPaintable * bz_rounded_picture_get_paintable (BzRoundedPicture *self); void bz_rounded_picture_set_radius (BzRoundedPicture *self, double radius); double bz_rounded_picture_get_radius (BzRoundedPicture *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-section-view.blp0000664000175000017500000001400515166123241017453 0ustar hasanhasanusing Gtk 4.0; using Gio 2.0; using Adw 1; template $BzSectionView: Adw.Bin { hexpand: bind template.section as <$BzCuratedSection>.expand_horizontally; vexpand: bind template.section as <$BzCuratedSection>.expand_vertically; child: Box { hexpand: true; vexpand: true; halign: fill; valign: fill; Box { visible: bind $invert_boolean($is_null(template.section as <$BzCuratedSection>.category) as ) as ; orientation: vertical; spacing: 5; Overlay { hexpand: true; child: Picture { css-name: "banner"; height-request: bind $clamp_banner_height(template.section as <$BzCuratedSection>.category as <$BzCuratedCategoryInfo>.banner-height) as ; styles [ "browser-banner", ] can-shrink: true; paintable: bind $get_banner(template.section as <$BzCuratedSection>.category) as <$GdkPaintable>; content-fit: bind template.section as <$BzCuratedSection>.category as <$BzCuratedCategoryInfo>.banner-fit; }; [overlay] Overlay banner_text_overlay { css-name: "banner-text-overlay"; hexpand: false; vexpand: false; child: Box banner_text_bg { css-name: "banner-text-bg"; }; halign: bind template.section as <$BzCuratedSection>.category as <$BzCuratedCategoryInfo>.banner-text-halign; valign: bind template.section as <$BzCuratedSection>.category as <$BzCuratedCategoryInfo>.banner-text-valign; [overlay] Box banner_text { css-name: "banner-text"; hexpand: false; vexpand: false; halign: center; valign: center; orientation: vertical; spacing: 5; Label { css-name: "title"; styles [ "browser-banner-title", ] wrap: true; wrap-mode: word_char; ellipsize: end; lines: 3; margin-start: 25; margin-end: 25; visible: bind $invert_boolean($is_null(template.section as <$BzCuratedSection>.category as <$BzCuratedCategoryInfo>.title) as ) as ; xalign: bind template.section as <$BzCuratedSection>.category as <$BzCuratedCategoryInfo>.banner-text-label-xalign; label: bind template.section as <$BzCuratedSection>.category as <$BzCuratedCategoryInfo>.title; } Label { css-name: "subtitle"; styles [ "browser-banner-subtitle", ] wrap: true; wrap-mode: word_char; ellipsize: end; lines: 3; margin-start: 25; margin-end: 25; visible: bind $invert_boolean($is_null(template.section as <$BzCuratedSection>.category as <$BzCuratedCategoryInfo>.subtitle) as ) as ; xalign: bind template.section as <$BzCuratedSection>.category as <$BzCuratedCategoryInfo>.banner-text-label-xalign; label: bind template.section as <$BzCuratedSection>.category as <$BzCuratedCategoryInfo>.subtitle; } Label { css-name: "description"; styles [ "browser-banner-description", ] wrap: true; wrap-mode: word_char; ellipsize: end; lines: 10; margin-start: 25; margin-end: 25; visible: bind $invert_boolean($is_null(template.section as <$BzCuratedSection>.category as <$BzCuratedCategoryInfo>.description) as ) as ; xalign: bind template.section as <$BzCuratedSection>.category as <$BzCuratedCategoryInfo>.banner-text-label-xalign; label: bind template.section as <$BzCuratedSection>.category as <$BzCuratedCategoryInfo>.description; } } } } $BzDynamicListView { margin-start: 25; margin-end: 25; margin-top: 20; margin-bottom: 20; hexpand: true; scroll: false; noscroll-kind: flow-box; child-type: "BzCuratedAppTile"; child-prop: "group"; model: bind $convert_to_groups(template.section as <$BzCuratedSection>.category as <$BzCuratedCategoryInfo>.appids) as ; bind-widget => $bind_widget_cb(template); unbind-widget => $unbind_widget_cb(template); } Button { styles [ "pill", ] margin-start: 25; margin-end: 25; margin-bottom: 20; halign: center; visible: bind template.section as <$BzCuratedSection>.category as <$BzCuratedCategoryInfo>.enable-bulk-install as ; label: _("Install All"); clicked => $install_all_clicked(template); } } Box { hexpand: true; vexpand: true; visible: bind $invert_boolean($is_null(template.section as <$BzCuratedSection>.markdown) as ) as ; $BgeMarkdownRender { hexpand: true; vexpand: true; markdown: bind template.section as <$BzCuratedSection>.markdown as <$BzCuratedMarkdownInfo>.string as ; } } Box { visible: bind $invert_boolean($is_null(template.section as <$BzCuratedSection>.image) as ) as ; width-request: bind $clamp_image_dimension(template.section as <$BzCuratedSection>.image as <$BzCuratedImageInfo>.width) as ; height-request: bind $clamp_image_dimension(template.section as <$BzCuratedSection>.image as <$BzCuratedImageInfo>.height) as ; Picture { css-name: "image"; paintable: bind $get_image(template.section as <$BzCuratedSection>.image) as <$GdkPaintable>; can-shrink: bind template.section as <$BzCuratedSection>.category as <$BzCuratedImageInfo>.can-shrink; content-fit: bind template.section as <$BzCuratedSection>.category as <$BzCuratedImageInfo>.fit; } } }; } bazaar-orig-v0.7.14/src/bz-spdx.c0000664000175000017500000000317615166123241015471 0ustar hasanhasan/* bz-spdx.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-spdx.h" gboolean bz_spdx_is_valid (const char *license_id) { g_autofree char *url = NULL; g_return_val_if_fail (license_id != NULL, FALSE); url = as_get_license_url (license_id); return url != NULL; } char * bz_spdx_get_url (const char *license_id) { g_return_val_if_fail (license_id != NULL, NULL); return as_get_license_url (license_id); } char * bz_spdx_get_name (const char *license_id) { char *result = NULL; g_return_val_if_fail (license_id != NULL, NULL); if (bz_spdx_is_proprietary (license_id)) return g_strdup ("Proprietary"); result = as_license_to_spdx_id (license_id); if (result == NULL) return g_strdup (license_id); return result; } gboolean bz_spdx_is_proprietary (const char *license_id) { g_return_val_if_fail (license_id != NULL, FALSE); return g_str_has_prefix (license_id, "LicenseRef-proprietary"); } bazaar-orig-v0.7.14/src/bz-global-net.c0000664000175000017500000002350115166123241016531 0ustar hasanhasan/* bz-global-net.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::GLOBAL-NET" #include "config.h" #include #include #include "bz-env.h" #include "bz-global-net.h" #include "bz-util.h" BZ_DEFINE_DATA ( http_request, HttpRequest, { SoupMessage *message; GOutputStream *splice_into; gboolean close_output; }, BZ_RELEASE_DATA (message, g_object_unref); BZ_RELEASE_DATA (splice_into, g_object_unref)); static DexFuture * http_send_fiber (HttpRequestData *data); static void http_send_and_splice_finish (GObject *object, GAsyncResult *result, gpointer user_data); static DexFuture * query_json_source_then (DexFuture *future, GOutputStream *output_stream); static DexFuture * send (SoupMessage *message, GOutputStream *splice_into, gboolean close_output); static DexFuture * query_flathub_v2_json_with_method (const char *request, const char *method, const char *token); GProxyResolver * bz_get_default_proxy_resolver (void) { static GProxyResolver *resolver = NULL; if (g_once_init_enter_pointer (&resolver)) { pxProxyFactory *factory = NULL; g_auto (GStrv) proxies = NULL; g_autoptr (GProxyResolver) resolver_instance = NULL; factory = px_proxy_factory_new (); /* blocking */ proxies = px_proxy_factory_get_proxies (factory, DONATE_LINK); g_clear_pointer (&factory, px_proxy_factory_free); resolver_instance = g_simple_proxy_resolver_new ( proxies != NULL && *proxies != NULL ? proxies[0] : NULL, NULL); g_once_init_leave_pointer (&resolver, g_steal_pointer (&resolver_instance)); } return resolver; } DexFuture * bz_send_with_global_http_session (SoupMessage *message) { dex_return_error_if_fail (SOUP_IS_MESSAGE (message)); return send (message, NULL, FALSE); } DexFuture * bz_send_with_global_http_session_then_splice_into (SoupMessage *message, GOutputStream *output) { dex_return_error_if_fail (SOUP_IS_MESSAGE (message)); dex_return_error_if_fail (G_IS_OUTPUT_STREAM (output)); return send (message, output, TRUE); } DexFuture * bz_https_query_json (const char *uri) { g_autoptr (GError) local_error = NULL; g_autoptr (SoupMessage) message = NULL; SoupMessageHeaders *headers = NULL; g_autoptr (GOutputStream) output = NULL; g_autoptr (DexFuture) future = NULL; dex_return_error_if_fail (uri != NULL); message = soup_message_new (SOUP_METHOD_GET, uri); headers = soup_message_get_request_headers (message); soup_message_headers_append (headers, "User-Agent", "Bazaar"); output = g_memory_output_stream_new_resizable (); future = send (message, output, TRUE); future = dex_future_then ( future, (DexFutureCallback) query_json_source_then, g_object_ref (output), g_object_unref); return g_steal_pointer (&future); } DexFuture * bz_query_flathub_v2_json (const char *request) { dex_return_error_if_fail (request != NULL); return query_flathub_v2_json_with_method (request, SOUP_METHOD_GET, NULL); } DexFuture * bz_query_flathub_v2_json_take (char *request) { DexFuture *future = NULL; dex_return_error_if_fail (request != NULL); future = bz_query_flathub_v2_json (request); g_free (request); return future; } DexFuture * bz_query_flathub_v2_json_authenticated (const char *request, const char *token) { dex_return_error_if_fail (request != NULL); return query_flathub_v2_json_with_method (request, SOUP_METHOD_GET, token); } DexFuture * bz_query_flathub_v2_json_authenticated_post (const char *request, const char *token) { dex_return_error_if_fail (request != NULL); return query_flathub_v2_json_with_method (request, SOUP_METHOD_POST, token); } DexFuture * bz_query_flathub_v2_json_authenticated_delete (const char *request, const char *token) { dex_return_error_if_fail (request != NULL); return query_flathub_v2_json_with_method (request, SOUP_METHOD_DELETE, token); } static DexFuture * query_flathub_v2_json_with_method (const char *request, const char *method, const char *token) { g_autofree char *uri = NULL; g_autoptr (SoupMessage) message = NULL; SoupMessageHeaders *headers = NULL; g_autoptr (GOutputStream) output = NULL; g_autoptr (DexFuture) future = NULL; uri = g_strdup_printf ("https://flathub.org/api/v2%s", request); message = soup_message_new (method, uri); headers = soup_message_get_request_headers (message); soup_message_headers_append (headers, "User-Agent", "Bazaar"); if (token != NULL && token[0] != '\0') { g_autofree char *cookie_value = NULL; cookie_value = g_strdup_printf ("session=%s", token); soup_message_headers_append (headers, "Cookie", cookie_value); } output = g_memory_output_stream_new_resizable (); future = send (message, output, TRUE); future = dex_future_then ( future, (DexFutureCallback) query_json_source_then, g_object_ref (output), g_object_unref); return g_steal_pointer (&future); } static DexFuture * http_send_fiber (HttpRequestData *data) { static SoupSession *session = NULL; SoupMessage *message = data->message; GOutputStream *splice_into = data->splice_into; gboolean close_output = data->close_output; GOutputStreamSpliceFlags splice_flags = G_OUTPUT_STREAM_SPLICE_NONE; g_autoptr (DexPromise) promise = NULL; if (g_once_init_enter_pointer (&session)) { g_autoptr (SoupSession) session_instance = NULL; session_instance = soup_session_new (); soup_session_set_proxy_resolver (session_instance, bz_get_default_proxy_resolver ()); g_once_init_leave_pointer (&session, g_steal_pointer (&session_instance)); } splice_flags = G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE; if (close_output) splice_flags |= G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET; promise = dex_promise_new_cancellable (); soup_session_send_and_splice_async ( session, message, splice_into, splice_flags, G_PRIORITY_DEFAULT_IDLE, dex_promise_get_cancellable (promise), http_send_and_splice_finish, dex_ref (promise)); return DEX_FUTURE (g_steal_pointer (&promise)); } static void http_send_and_splice_finish (GObject *object, GAsyncResult *result, gpointer user_data) { DexPromise *promise = user_data; g_autoptr (GError) local_error = NULL; gssize bytes_written = 0; g_assert (SOUP_IS_SESSION (object)); g_assert (G_IS_ASYNC_RESULT (result)); g_assert (DEX_IS_PROMISE (promise)); bytes_written = soup_session_send_and_splice_finish (SOUP_SESSION (object), result, &local_error); if (bytes_written >= 0) { g_debug ("Spliced %zu bytes from http reply into output stream", bytes_written); dex_promise_resolve_uint64 (promise, bytes_written); } else { g_debug ("Could not splice http reply into output stream: %s", local_error->message); dex_promise_reject (promise, g_steal_pointer (&local_error)); } dex_unref (promise); } static DexFuture * query_json_source_then (DexFuture *future, GOutputStream *output_stream) { g_autoptr (GError) local_error = NULL; g_autoptr (GBytes) bytes = NULL; gsize bytes_size = 0; gconstpointer bytes_data = NULL; g_autoptr (JsonParser) parser = NULL; gboolean result = FALSE; JsonNode *node = NULL; bytes = g_memory_output_stream_steal_as_bytes ( G_MEMORY_OUTPUT_STREAM (output_stream)); bytes_data = g_bytes_get_data (bytes, &bytes_size); if (bytes_size == 0) return dex_future_new_take_boxed (JSON_TYPE_NODE, json_node_new (JSON_NODE_NULL)); parser = json_parser_new_immutable (); result = json_parser_load_from_data (parser, bytes_data, bytes_size, &local_error); if (!result) return dex_future_new_for_error (g_steal_pointer (&local_error)); node = json_parser_get_root (parser); return dex_future_new_take_boxed (JSON_TYPE_NODE, json_node_ref (node)); } static DexFuture * send (SoupMessage *message, GOutputStream *splice_into, gboolean close_output) { g_autoptr (HttpRequestData) data = NULL; g_autoptr (DexFuture) future = NULL; data = http_request_data_new (); data->message = g_object_ref (message); data->splice_into = bz_object_maybe_ref (splice_into); data->close_output = close_output; future = dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) http_send_fiber, http_request_data_ref (data), http_request_data_unref); return g_steal_pointer (&future); } bazaar-orig-v0.7.14/src/bz-safety-dialog.h0000664000175000017500000000204315166123241017240 0ustar hasanhasan/* bz-safety-dialog.h * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry-group.h" #include G_BEGIN_DECLS #define BZ_TYPE_SAFETY_DIALOG (bz_safety_dialog_get_type ()) G_DECLARE_FINAL_TYPE (BzSafetyDialog, bz_safety_dialog, BZ, SAFETY_DIALOG, AdwDialog) AdwDialog *bz_safety_dialog_new (BzEntryGroup *group); G_END_DECLS bazaar-orig-v0.7.14/src/blocklist-schema.xml0000664000175000017500000000071415166123241017677 0ustar hasanhasan bazaar-orig-v0.7.14/src/bz-appstream-description-render.h0000664000175000017500000000274115166123241022307 0ustar hasanhasan/* bz-appstream-description-render.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_APPSTREAM_DESCRIPTION_RENDER (bz_appstream_description_render_get_type ()) G_DECLARE_FINAL_TYPE (BzAppstreamDescriptionRender, bz_appstream_description_render, BZ, APPSTREAM_DESCRIPTION_RENDER, AdwBin) BzAppstreamDescriptionRender * bz_appstream_description_render_new (void); const char * bz_appstream_description_render_get_appstream_description (BzAppstreamDescriptionRender *self); void bz_appstream_description_render_set_appstream_description (BzAppstreamDescriptionRender *self, const char *appstream_description); G_END_DECLS /* End of bz-appstream-description-render.h */ bazaar-orig-v0.7.14/src/bz-curated-section.txt0000664000175000017500000000136115166123241020173 0ustar hasanhasanprefix=bz name=curated_section parent-prefix=g parent-name=object author=AUTOGEN include= include="bz-entry-group.h" include="bz-curated-category-info.h" include="bz-curated-markdown-info.h" include="bz-curated-image-info.h" property=expand_horizontally gboolean G_TYPE_BOOLEAN boolean property=expand_vertically gboolean G_TYPE_BOOLEAN boolean property=classes GListModel G_TYPE_LIST_MODEL object property=light_classes GListModel G_TYPE_LIST_MODEL object property=dark_classes GListModel G_TYPE_LIST_MODEL object property=category BzCuratedCategoryInfo BZ_TYPE_CURATED_CATEGORY_INFO object property=markdown BzCuratedMarkdownInfo BZ_TYPE_CURATED_MARKDOWN_INFO object property=image BzCuratedImageInfo BZ_TYPE_CURATED_IMAGE_INFO object bazaar-orig-v0.7.14/src/bz-flathub-sub-category.txt0000664000175000017500000000024415166123241021130 0ustar hasanhasanprefix=bz name=flathub_sub_category parent-prefix=g parent-name=object author=AUTOGEN property=name char G_TYPE_STRING string property=id char G_TYPE_STRING string bazaar-orig-v0.7.14/src/bz-exponential-function.txt0000664000175000017500000000026415166123241021254 0ustar hasanhasanprefix=bz name=exponential_function parent-prefix=g parent-name=object author=AUTOGEN property=factor double G_TYPE_DOUBLE double property=y_intercept double G_TYPE_DOUBLE double bazaar-orig-v0.7.14/src/bz-finished-search-query.txt0000664000175000017500000000047015166123241021301 0ustar hasanhasanprefix=bz name=finished_search_query parent-prefix=g parent-name=object author=AUTOGEN property=interpreted_query char G_TYPE_STRING string property=results GPtrArray G_TYPE_PTR_ARRAY boxed g_ptr_array_unref g_ptr_array_ref property=n_results guint G_TYPE_UINT uint property=elapsed double G_TYPE_DOUBLE double bazaar-orig-v0.7.14/src/bz-window.c0000664000175000017500000010634515166123241016024 0ustar hasanhasan/* bz-window.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ // This file is an utter mess #include "config.h" #include #include "bz-addons-dialog.h" #include "bz-application.h" #include "bz-comet-overlay.h" #include "bz-curated-view.h" #include "bz-entry-group-util.h" #include "bz-entry-group.h" #include "bz-env.h" #include "bz-error.h" #include "bz-flathub-page.h" #include "bz-flatpak-entry.h" #include "bz-full-view.h" #include "bz-global-progress.h" #include "bz-hooks.h" #include "bz-io.h" #include "bz-library-page.h" #include "bz-progress-bar.h" #include "bz-search-page.h" #include "bz-template-callbacks.h" #include "bz-transaction-dialog.h" #include "bz-transaction-manager.h" #include "bz-user-data-page.h" #include "bz-util.h" #include "bz-window.h" struct _BzWindow { AdwApplicationWindow parent_instance; BzStateInfo *state; GtkEventController *key_controller; gboolean breakpoint_applied; /* Template widgets */ BzCometOverlay *comet_overlay; AdwNavigationView *navigation_view; BzFullView *full_view; BzSearchPage *search_page; BzLibraryPage *library_page; AdwToastOverlay *toasts; AdwViewStack *main_view_stack; GtkStack *main_stack; }; G_DEFINE_FINAL_TYPE (BzWindow, bz_window, ADW_TYPE_APPLICATION_WINDOW) enum { PROP_0, PROP_STATE, PROP_COMPACT, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; BZ_DEFINE_DATA ( transact, Transact, { GWeakRef *self; BzEntry *entry; BzEntryGroup *group; gboolean remove; gboolean auto_confirm; GtkWidget *source; }, BZ_RELEASE_DATA (self, bz_weak_release); BZ_RELEASE_DATA (entry, g_object_unref); BZ_RELEASE_DATA (group, g_object_unref); BZ_RELEASE_DATA (source, g_object_unref)) static DexFuture * transact_fiber (TransactData *data); BZ_DEFINE_DATA ( bulk_install, BulkInstall, { GWeakRef *self; GListModel *groups; }, BZ_RELEASE_DATA (self, bz_weak_release); BZ_RELEASE_DATA (groups, g_object_unref)) static DexFuture * bulk_install_fiber (BulkInstallData *data); static DexFuture * transact (BzWindow *self, BzEntry *entry, gboolean remove, GtkWidget *source); static void try_transact (BzWindow *self, BzEntry *entry, BzEntryGroup *group, gboolean remove, gboolean auto_confirm, GtkWidget *source); static void search (BzWindow *self, const char *text); static void bulk_install (BzWindow *self, BzEntry **installs, guint n_installs); static void set_page (BzWindow *self); static void emit_hook_disown (BzWindow *self, BzHookSignal signal, BzEntryGroup *group); static void bz_window_dispose (GObject *object) { BzWindow *self = BZ_WINDOW (object); g_clear_object (&self->state); G_OBJECT_CLASS (bz_window_parent_class)->dispose (object); } static void bz_window_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzWindow *self = BZ_WINDOW (object); switch (prop_id) { case PROP_STATE: g_value_set_object (value, self->state); break; case PROP_COMPACT: g_value_set_boolean (value, self->breakpoint_applied); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_window_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { // BzWindow *self = BZ_WINDOW (object); switch (prop_id) { case PROP_STATE: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static char * list_length (gpointer object, GListModel *model) { if (model == NULL) return g_strdup (0); return g_strdup_printf ("%u", g_list_model_get_n_items (model)); } static void update_cb (BzWindow *self, GListModel *entries, GtkWidget *widget) { g_autoptr (BzTransaction) transaction = NULL; guint n_updates = 0; g_autofree BzEntry **updates_buf = NULL; GListModel *available_updates = NULL; g_return_if_fail (BZ_IS_WINDOW (self)); g_return_if_fail (G_IS_LIST_MODEL (entries)); n_updates = g_list_model_get_n_items (entries); if (n_updates == 0) return; updates_buf = g_malloc_n (n_updates, sizeof (*updates_buf)); for (guint i = 0; i < n_updates; i++) updates_buf[i] = g_list_model_get_item (entries, i); transaction = bz_transaction_new_full ( NULL, 0, updates_buf, n_updates, NULL, 0); dex_future_disown (bz_transaction_manager_add ( bz_state_info_get_transaction_manager (self->state), transaction)); available_updates = bz_state_info_get_available_updates (self->state); if (G_IS_LIST_STORE (available_updates)) { GListStore *store = G_LIST_STORE (available_updates); guint n_available = g_list_model_get_n_items (available_updates); for (guint i = n_available; i > 0; i--) { guint current_size = 0; guint idx = 0; g_autoptr (BzEntry) available_entry = NULL; const char *available_id = NULL; idx = i - 1; current_size = g_list_model_get_n_items (available_updates); if (idx >= current_size) continue; available_entry = g_list_model_get_item (available_updates, idx); available_id = bz_entry_get_id (available_entry); for (guint j = 0; j < n_updates; j++) { if (g_strcmp0 (available_id, bz_entry_get_id (updates_buf[j])) == 0) { g_list_store_remove (store, idx); break; } } } } g_object_notify (G_OBJECT (self->state), "available-updates"); for (guint i = 0; i < n_updates; i++) g_object_unref (updates_buf[i]); } void bz_window_show_app_id (BzWindow *self, const char *app_id) { g_autoptr (BzEntryGroup) group = NULL; g_return_if_fail (BZ_IS_WINDOW (self)); g_return_if_fail (app_id != NULL); group = bz_application_map_factory_convert_one ( bz_state_info_get_application_factory (self->state), gtk_string_object_new (app_id)); if (group != NULL) bz_window_show_group (self, group); } static void page_toggled_cb (BzWindow *self, GParamSpec *pspec, AdwToggleGroup *toggles) { set_page (self); } static void browse_flathub_cb (BzWindow *self, BzCuratedView *widget) { adw_view_stack_set_visible_child_name (self->main_view_stack, "flathub"); } static void open_search_cb (BzWindow *self, BzSearchPage *widget) { adw_view_stack_set_visible_child_name (self->main_view_stack, "search"); } static void breakpoint_apply_cb (BzWindow *self, AdwBreakpoint *breakpoint) { self->breakpoint_applied = TRUE; gtk_widget_add_css_class (GTK_WIDGET (self), "narrow"); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_COMPACT]); } static void breakpoint_unapply_cb (BzWindow *self, AdwBreakpoint *breakpoint) { self->breakpoint_applied = FALSE; gtk_widget_remove_css_class (GTK_WIDGET (self), "narrow"); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_COMPACT]); } static void sync_cb (BzWindow *self, GtkButton *button) { g_action_group_activate_action ( G_ACTION_GROUP (g_application_get_default ()), "sync-remotes", NULL); } static void transactions_clear_cb (BzWindow *self, GtkButton *button) { bz_transaction_manager_clear_finished ( bz_state_info_get_transaction_manager (self->state)); } static void action_escape (GtkWidget *widget, const char *action_name, GVariant *parameter) { BzWindow *self = BZ_WINDOW (widget); GListModel *stack = NULL; guint n_pages = 0; stack = adw_navigation_view_get_navigation_stack (self->navigation_view); n_pages = g_list_model_get_n_items (stack); adw_navigation_view_pop (self->navigation_view); if (n_pages <= 2) set_page (self); } static char * format_progress (gpointer object, double value) { return g_strdup_printf ("%.0f%%", 100.0 * value); } static char * format_title (gpointer object, const char *title) { if (title == NULL || *title == '\0' || g_strcmp0 (title, _ ("Bazaar")) == 0) return g_strdup (_ ("Bazaar")); /* Translators: %s is the title of the current page */ return g_strdup_printf (_ ("Bazaar — %s"), title); } static BzEntryGroup * resolve_group_from_parameter (BzWindow *self, GVariant *parameter, gboolean *auto_confirm) { const char *id = NULL; g_variant_get (parameter, "(&sb)", &id, auto_confirm); return bz_application_map_factory_convert_one ( bz_state_info_get_application_factory (self->state), gtk_string_object_new (id)); } static void action_install_group (GtkWidget *widget, const char *action_name, GVariant *parameter) { BzWindow *self = BZ_WINDOW (widget); g_autoptr (BzEntryGroup) group = NULL; gboolean auto_confirm = FALSE; group = resolve_group_from_parameter (self, parameter, &auto_confirm); if (group != NULL) try_transact (self, NULL, group, FALSE, auto_confirm, NULL); } static void action_remove_group (GtkWidget *widget, const char *action_name, GVariant *parameter) { BzWindow *self = BZ_WINDOW (widget); g_autoptr (BzEntryGroup) group = NULL; gboolean auto_confirm = FALSE; group = resolve_group_from_parameter (self, parameter, &auto_confirm); if (group != NULL) try_transact (self, NULL, group, TRUE, auto_confirm, NULL); } static void action_show_group (GtkWidget *widget, const char *action_name, GVariant *parameter) { BzWindow *self = BZ_WINDOW (widget); const char *id = NULL; g_autoptr (BzEntryGroup) group = NULL; id = g_variant_get_string (parameter, NULL); group = bz_application_map_factory_convert_one ( bz_state_info_get_application_factory (self->state), gtk_string_object_new (id)); if (group == NULL) return; if (bz_entry_group_is_addon (group)) { AdwDialog *dialog = NULL; dialog =bz_addons_dialog_new_single (group); adw_dialog_present (dialog, GTK_WIDGET (self)); } else bz_window_show_group (self, group); } static void action_addons_group (GtkWidget *widget, const char *action_name, GVariant *parameter) { BzWindow *self = BZ_WINDOW (widget); const char *id = NULL; g_autoptr (BzEntryGroup) group = NULL; AdwDialog *addons_dialog = NULL; id = g_variant_get_string (parameter, NULL); group = bz_application_map_factory_convert_one ( bz_state_info_get_application_factory (self->state), gtk_string_object_new (id)); if (group == NULL) return; addons_dialog = bz_addons_dialog_new (group); adw_dialog_present (addons_dialog, GTK_WIDGET (self)); } static void action_bulk_install (GtkWidget *widget, const char *action_name, GVariant *parameter) { BzWindow *self = BZ_WINDOW (widget); g_autoptr (GListStore) ids = NULL; g_autoptr (GListModel) groups = NULL; GVariantIter iter = { 0 }; const char *id = NULL; ids = g_list_store_new (GTK_TYPE_STRING_OBJECT); g_variant_iter_init (&iter, parameter); while (g_variant_iter_next (&iter, "&s", &id)) { g_autoptr (GtkStringObject) string = gtk_string_object_new (id); g_list_store_append (ids, string); } groups = bz_application_map_factory_generate ( bz_state_info_get_application_factory (self->state), G_LIST_MODEL (ids)); if (groups != NULL && g_list_model_get_n_items (groups) > 0) bz_window_bulk_install (self, groups); } static void action_user_data (GtkWidget *widget, const char *action_name, GVariant *parameter) { BzWindow *self = BZ_WINDOW (widget); AdwNavigationPage *user_data_page = NULL; user_data_page = ADW_NAVIGATION_PAGE (bz_user_data_page_new (self->state)); adw_navigation_view_push (self->navigation_view, user_data_page); } static void action_open_library (GtkWidget *widget, const char *action_name, GVariant *parameter) { BzWindow *self = BZ_WINDOW (widget); adw_navigation_view_pop_to_tag (self->navigation_view, "main"); adw_view_stack_set_visible_child_name (self->main_view_stack, "installed"); bz_library_page_reset_search (self->library_page); } static DexFuture * launch_group_fiber (BzEntryGroup *group) { g_autoptr (GError) local_error = NULL; g_autoptr (GListStore) store = NULL; GtkWidget *window = NULL; BzStateInfo *state = NULL; state = bz_state_info_get_default (); window = GTK_WIDGET (gtk_application_get_active_window ( GTK_APPLICATION (g_application_get_default ()))); store = dex_await_object ( bz_entry_group_dup_all_into_store (group), &local_error); if (store == NULL) { if (window != NULL) bz_show_error_for_widget (window, _ ("Failed to launch application"), local_error->message); return dex_future_new_for_error (g_steal_pointer (&local_error)); } for (guint i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (store)); i++) { g_autoptr (BzEntry) entry = NULL; entry = g_list_model_get_item (G_LIST_MODEL (store), i); if (BZ_IS_FLATPAK_ENTRY (entry) && bz_entry_is_installed (entry)) { gboolean result = bz_flatpak_entry_launch ( BZ_FLATPAK_ENTRY (entry), BZ_FLATPAK_INSTANCE (bz_state_info_get_backend (state)), &local_error); if (!result && window != NULL) bz_show_error_for_widget (window, _ ("Failed to launch application"), local_error->message); return result ? dex_future_new_true () : dex_future_new_for_error (g_steal_pointer (&local_error)); } } return dex_future_new_false (); } static void action_launch_group (GtkWidget *widget, const char *action_name, GVariant *parameter) { BzWindow *self = BZ_WINDOW (widget); const char *id = NULL; g_autoptr (BzEntryGroup) group = NULL; id = g_variant_get_string (parameter, NULL); group = bz_application_map_factory_convert_one ( bz_state_info_get_application_factory (self->state), gtk_string_object_new (id)); if (group == NULL) return; dex_future_disown (dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) launch_group_fiber, g_object_ref (group), g_object_unref)); } static void bz_window_class_init (BzWindowClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_window_dispose; object_class->get_property = bz_window_get_property; object_class->set_property = bz_window_set_property; props[PROP_STATE] = g_param_spec_object ( "state", NULL, NULL, BZ_TYPE_STATE_INFO, G_PARAM_READABLE); props[PROP_COMPACT] = g_param_spec_boolean ( "compact", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_COMET_OVERLAY); g_type_ensure (BZ_TYPE_SEARCH_PAGE); g_type_ensure (BZ_TYPE_GLOBAL_PROGRESS); g_type_ensure (BZ_TYPE_PROGRESS_BAR); g_type_ensure (BZ_TYPE_CURATED_VIEW); g_type_ensure (BZ_TYPE_FULL_VIEW); g_type_ensure (BZ_TYPE_LIBRARY_PAGE); g_type_ensure (BZ_TYPE_FLATHUB_PAGE); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-window.ui"); bz_widget_class_bind_all_util_callbacks (widget_class); gtk_widget_class_bind_template_child (widget_class, BzWindow, comet_overlay); gtk_widget_class_bind_template_child (widget_class, BzWindow, navigation_view); gtk_widget_class_bind_template_child (widget_class, BzWindow, full_view); gtk_widget_class_bind_template_child (widget_class, BzWindow, toasts); gtk_widget_class_bind_template_child (widget_class, BzWindow, search_page); gtk_widget_class_bind_template_child (widget_class, BzWindow, library_page); gtk_widget_class_bind_template_child (widget_class, BzWindow, main_view_stack); gtk_widget_class_bind_template_child (widget_class, BzWindow, main_stack); gtk_widget_class_bind_template_callback (widget_class, list_length); gtk_widget_class_bind_template_callback (widget_class, update_cb); gtk_widget_class_bind_template_callback (widget_class, page_toggled_cb); gtk_widget_class_bind_template_callback (widget_class, breakpoint_apply_cb); gtk_widget_class_bind_template_callback (widget_class, breakpoint_unapply_cb); gtk_widget_class_bind_template_callback (widget_class, sync_cb); gtk_widget_class_bind_template_callback (widget_class, transactions_clear_cb); gtk_widget_class_bind_template_callback (widget_class, browse_flathub_cb); gtk_widget_class_bind_template_callback (widget_class, open_search_cb); gtk_widget_class_bind_template_callback (widget_class, format_progress); gtk_widget_class_bind_template_callback (widget_class, format_title); gtk_widget_class_install_action (widget_class, "escape", NULL, action_escape); gtk_widget_class_install_action (widget_class, "window.user-data", NULL, action_user_data); gtk_widget_class_install_action (widget_class, "window.open-library", NULL, action_open_library); gtk_widget_class_install_action (widget_class, "window.install-group", "(sb)", action_install_group); gtk_widget_class_install_action (widget_class, "window.remove-group", "(sb)", action_remove_group); gtk_widget_class_install_action (widget_class, "window.show-group", "s", action_show_group); gtk_widget_class_install_action (widget_class, "window.addons-group", "s", action_addons_group); gtk_widget_class_install_action (widget_class, "window.bulk-install", NULL, action_bulk_install); gtk_widget_class_install_action (widget_class, "window.launch-group", "s", action_launch_group); gtk_widget_class_add_binding_action (widget_class, GDK_KEY_d, GDK_CONTROL_MASK, "window.open-library", NULL); gtk_widget_class_add_binding_action (widget_class, GDK_KEY_w, GDK_CONTROL_MASK, "window.close", NULL); } static gboolean key_pressed (BzWindow *self, guint keyval, guint keycode, GdkModifierType state, GtkEventControllerKey *controller) { gunichar unichar = 0; char buf[32] = { 0 }; const char *visible_child_name = NULL; /* Ignore if this is a modifier-shortcut of some sort */ if (state & ~(GDK_NO_MODIFIER_MASK | GDK_SHIFT_MASK)) return FALSE; unichar = gdk_keyval_to_unicode (keyval); if (unichar == 0 || !g_unichar_isgraph (unichar)) return FALSE; g_unichar_to_utf8 (unichar, buf); visible_child_name = adw_view_stack_get_visible_child_name (self->main_view_stack); if (g_strcmp0 (visible_child_name, "installed") == 0) return bz_library_page_ensure_active (self->library_page, buf); else { adw_view_stack_set_visible_child_name (self->main_view_stack, "search"); return bz_search_page_ensure_active (self->search_page, buf); } } static void bz_window_init (BzWindow *self) { gtk_widget_init_template (GTK_WIDGET (self)); #ifdef DEVELOPMENT_BUILD gtk_widget_add_css_class (GTK_WIDGET (self), "devel"); #endif adw_view_stack_set_visible_child_name (self->main_view_stack, "flathub"); self->key_controller = gtk_event_controller_key_new (); g_signal_connect_swapped (self->key_controller, "key-pressed", G_CALLBACK (key_pressed), self); gtk_widget_add_controller (GTK_WIDGET (self), self->key_controller); } static void app_busy_changed (BzWindow *self, GParamSpec *pspec, BzStateInfo *info) { bz_search_page_refresh (self->search_page); set_page (self); } static void has_inputs_changed (BzWindow *self, GParamSpec *pspec, BzContentProvider *provider) { if (!bz_content_provider_get_has_inputs (provider)) adw_view_stack_set_visible_child_name (self->main_view_stack, "flathub"); } static DexFuture * transact_fiber (TransactData *data) { g_autoptr (BzWindow) self = NULL; g_autoptr (GError) local_error = NULL; g_autoptr (BzEntry) selected_entry = NULL; g_autoptr (DexFuture) transact_future = NULL; g_autofree char *id_dup = NULL; BzMainConfig *config = NULL; GListModel *hooks = NULL; gboolean delete_user_data = FALSE; GdkDisplay *display = NULL; GdkSeat *seat = NULL; GdkDevice *keyboard = NULL; GdkModifierType modifiers = GDK_NO_MODIFIER_MASK; bz_weak_get_or_return_reject (self, data->self); // Get ID early before any async operations if (data->group != NULL) id_dup = g_strdup (bz_entry_group_get_id (data->group)); else id_dup = g_strdup (bz_entry_get_id (data->entry)); /* Prevent Bazaar from being removed by itself */ if (data->remove) { const char *bazaar_id = NULL; bazaar_id = g_application_get_application_id (g_application_get_default ()); if (g_strcmp0 (id_dup, bazaar_id) == 0) { bz_show_error_for_widget (GTK_WIDGET (self), _ ("You can't remove Bazaar from Bazaar!"), _ ("You can't remove Bazaar from Bazaar!")); return dex_future_new_false (); } } config = bz_state_info_get_main_config (self->state); if (config != NULL) hooks = bz_main_config_get_hooks (config); #define RUN_HOOK(_signal) \ G_STMT_START \ { \ if (hooks != NULL && \ !dex_await ( \ bz_run_hook_emission ( \ hooks, (_signal), \ data->remove \ ? BZ_HOOK_TRANSACTION_TYPE_REMOVAL \ : BZ_HOOK_TRANSACTION_TYPE_INSTALL, \ id_dup, NULL), \ &local_error)) \ return dex_future_new_for_error (g_steal_pointer (&local_error)); \ } \ G_STMT_END RUN_HOOK (BZ_HOOK_SIGNAL_BEFORE_TRANSACTION); display = gdk_display_get_default (); seat = gdk_display_get_default_seat (display); keyboard = gdk_seat_get_keyboard (seat); if (keyboard != NULL) modifiers = gdk_device_get_modifier_state (keyboard); if (modifiers & GDK_SHIFT_MASK) /* Holding shift while invoking a transaction skips the dialog and assumes the first valid entry */ { if (data->group != NULL) { g_autoptr (GListModel) store = NULL; guint n_items = 0; store = dex_await_object ( bz_entry_group_dup_all_into_store (data->group), &local_error); if (store == NULL) return dex_future_new_for_error (g_steal_pointer (&local_error)); n_items = g_list_model_get_n_items (store); for (guint i = 0; i < n_items; i++) { g_autoptr (BzEntry) entry = NULL; gboolean installed = FALSE; entry = g_list_model_get_item (store, i); installed = bz_entry_is_installed (entry); if ((data->remove && installed) || (!data->remove && !installed)) { selected_entry = g_steal_pointer (&entry); break; } } if (selected_entry == NULL) return dex_future_new_false (); } else selected_entry = g_object_ref (data->entry); } else { g_autoptr (BzTransactionDialogResult) dialog_result = NULL; // Show the dialog dialog_result = dex_await_object ( bz_transaction_dialog_show ( GTK_WIDGET (self), data->entry, data->group, data->remove, data->auto_confirm), &local_error); if (dialog_result == NULL) return dex_future_new_for_error (g_steal_pointer (&local_error)); if (!bz_transaction_dialog_result_get_confirmed (dialog_result)) return dex_future_new_false (); selected_entry = g_object_ref ( bz_transaction_dialog_result_get_selected_entry (dialog_result)); delete_user_data = bz_transaction_dialog_result_get_delete_user_data ( dialog_result); } // Perform the transaction transact_future = transact ( self, selected_entry, data->remove, data->source); if (!dex_await (g_steal_pointer (&transact_future), &local_error)) return dex_future_new_for_error (g_steal_pointer (&local_error)); // Handle user data deletion if (delete_user_data) { if (data->group != NULL) bz_entry_group_reap_user_data (data->group); else dex_future_disown (bz_reap_user_data_dex (id_dup)); } RUN_HOOK (BZ_HOOK_SIGNAL_AFTER_TRANSACTION); #undef RUN_HOOK return dex_future_new_true (); } BzWindow * bz_window_new (BzStateInfo *state) { BzWindow *window = NULL; g_return_val_if_fail (BZ_IS_STATE_INFO (state), NULL); window = g_object_new (BZ_TYPE_WINDOW, NULL); window->state = g_object_ref (state); g_signal_connect_object (state, "notify::busy", G_CALLBACK (app_busy_changed), window, G_CONNECT_SWAPPED); /* these seem unsafe but BzApplication never * changes the objects we are connecting to */ g_signal_connect_object (bz_state_info_get_curated_provider (state), "notify::has-inputs", G_CALLBACK (has_inputs_changed), window, G_CONNECT_SWAPPED); g_object_notify_by_pspec (G_OBJECT (window), props[PROP_STATE]); set_page (window); return window; } void bz_window_search (BzWindow *self, const char *text) { g_return_if_fail (BZ_IS_WINDOW (self)); search (self, text); } void bz_window_show_entry (BzWindow *self, BzEntry *entry) { g_autoptr (BzEntryGroup) group = NULL; g_return_if_fail (BZ_IS_WINDOW (self)); g_return_if_fail (BZ_IS_ENTRY (entry)); group = bz_entry_group_new_for_single_entry (entry); bz_window_show_group(self, group); } void bz_window_show_group (BzWindow *self, BzEntryGroup *group) { GListModel *stack = NULL; gboolean in_stack = FALSE; g_return_if_fail (BZ_IS_WINDOW (self)); g_return_if_fail (BZ_IS_ENTRY_GROUP (group)); bz_full_view_set_entry_group (self->full_view, group); emit_hook_disown (self, BZ_HOOK_SIGNAL_VIEW_APP, group); stack = adw_navigation_view_get_navigation_stack (self->navigation_view); for (guint i = 0; i < g_list_model_get_n_items (stack); i++) { g_autoptr (AdwNavigationPage) page = NULL; page = g_list_model_get_item (stack, i); if (g_strcmp0 (adw_navigation_page_get_tag (page), "view") == 0) { in_stack = TRUE; adw_navigation_view_pop_to_page (self->navigation_view, page); break; } } if (!in_stack) adw_navigation_view_push_by_tag (self->navigation_view, "view"); } void bz_window_add_toast (BzWindow *self, AdwToast *toast) { g_return_if_fail (BZ_IS_WINDOW (self)); g_return_if_fail (ADW_IS_TOAST (toast)); adw_toast_overlay_add_toast (self->toasts, toast); } void bz_window_push_page (BzWindow *self, AdwNavigationPage *page) { g_return_if_fail (BZ_IS_WINDOW (self)); g_return_if_fail (ADW_IS_NAVIGATION_PAGE (page)); adw_navigation_view_push (self->navigation_view, page); } void bz_window_bulk_install (BzWindow *self, GListModel *groups) { g_autoptr (BulkInstallData) data = NULL; g_return_if_fail (BZ_IS_WINDOW (self)); g_return_if_fail (G_IS_LIST_MODEL (groups)); data = bulk_install_data_new (); data->self = bz_track_weak (self); data->groups = g_object_ref (groups); dex_future_disown (dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) bulk_install_fiber, bulk_install_data_ref (data), bulk_install_data_unref)); } BzStateInfo * bz_window_get_state_info (BzWindow *self) { g_return_val_if_fail (BZ_IS_WINDOW (self), NULL); return self->state; } static DexFuture * transact (BzWindow *self, BzEntry *entry, gboolean remove, GtkWidget *source) { g_autoptr (BzTransaction) transaction = NULL; if (remove) transaction = bz_transaction_new_full ( NULL, 0, NULL, 0, &entry, 1); else transaction = bz_transaction_new_full ( &entry, 1, NULL, 0, NULL, 0); return bz_transaction_manager_add ( bz_state_info_get_transaction_manager (self->state), transaction); } static void try_transact (BzWindow *self, BzEntry *entry, BzEntryGroup *group, gboolean remove, gboolean auto_confirm, GtkWidget *source) { g_autoptr (TransactData) data = NULL; g_return_if_fail (entry != NULL || group != NULL); if (bz_state_info_get_busy (self->state)) { adw_toast_overlay_add_toast ( self->toasts, adw_toast_new_format (_ ("Can't do that right now!"))); return; } data = transact_data_new (); data->self = bz_track_weak (self); data->entry = bz_object_maybe_ref (entry); data->group = bz_object_maybe_ref (group); data->remove = remove; data->auto_confirm = auto_confirm; data->source = bz_object_maybe_ref (source); dex_future_disown (dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) transact_fiber, transact_data_ref (data), transact_data_unref)); } static void bulk_install (BzWindow *self, BzEntry **installs, guint n_installs) { g_autoptr (BzTransaction) transaction = NULL; g_return_if_fail (BZ_IS_WINDOW (self)); g_return_if_fail (installs != NULL); g_return_if_fail (n_installs > 0); if (bz_state_info_get_busy (self->state)) { adw_toast_overlay_add_toast ( self->toasts, adw_toast_new_format (_ ("Can't do that right now!"))); return; } transaction = bz_transaction_new_full ( installs, n_installs, NULL, 0, NULL, 0); dex_future_disown (bz_transaction_manager_add ( bz_state_info_get_transaction_manager (self->state), transaction)); } static DexFuture * bulk_install_fiber (BulkInstallData *data) { g_autoptr (BzWindow) self = NULL; g_autoptr (GError) local_error = NULL; g_autoptr (BzBulkInstallDialogResult) result = NULL; GListModel *entries = NULL; guint n_installs = 0; g_autofree BzEntry **installs_buf = NULL; bz_weak_get_or_return_reject (self, data->self); result = dex_await_object ( bz_bulk_install_dialog_show (GTK_WIDGET (self), data->groups), &local_error); if (result == NULL) return dex_future_new_for_error (g_steal_pointer (&local_error)); if (!bz_bulk_install_dialog_result_get_confirmed (result)) return dex_future_new_false (); entries = bz_bulk_install_dialog_result_get_entries (result); n_installs = g_list_model_get_n_items (entries); if (n_installs == 0) return dex_future_new_false (); installs_buf = g_malloc_n (n_installs, sizeof (*installs_buf)); for (guint i = 0; i < n_installs; i++) installs_buf[i] = g_list_model_get_item (entries, i); bulk_install (self, installs_buf, n_installs); for (guint i = 0; i < n_installs; i++) g_object_unref (installs_buf[i]); return dex_future_new_true (); } static void search (BzWindow *self, const char *initial) { if (initial != NULL && *initial != '\0') bz_search_page_set_text (self->search_page, initial); adw_view_stack_set_visible_child_name (self->main_view_stack, "search"); adw_navigation_view_pop_to_tag (self->navigation_view, "main"); gtk_widget_grab_focus (GTK_WIDGET (self->search_page)); } static void set_page (BzWindow *self) { const char *selected_navigation_page_name = NULL; if (self->state == NULL) return; if (bz_state_info_get_busy (self->state)) { gtk_stack_set_visible_child_name (self->main_stack, "loading"); adw_navigation_view_pop_to_tag (self->navigation_view, "main"); } else gtk_stack_set_visible_child_name (self->main_stack, "main"); selected_navigation_page_name = adw_navigation_view_get_visible_page_tag (self->navigation_view); if (g_strcmp0 (selected_navigation_page_name, "view") != 0) bz_full_view_set_entry_group (self->full_view, NULL); } static void emit_hook_disown (BzWindow *self, BzHookSignal signal, BzEntryGroup *group) { BzMainConfig *config = NULL; GListModel *hooks = NULL; if (self->state == NULL) return; config = bz_state_info_get_main_config (self->state); if (config == NULL) return; hooks = bz_main_config_get_hooks (config); if (hooks == NULL) return; dex_future_disown (bz_run_hook_emission ( hooks, signal, 0, NULL, group)); } bazaar-orig-v0.7.14/src/bz-root-blocklist.txt0000664000175000017500000000032115166123241020044 0ustar hasanhasanprefix=bz name=root_blocklist parent-prefix=g parent-name=object author=AUTOGEN include= include="bz-blocklist.h" ensure=BZ_TYPE_BLOCKLIST property=blocklists GListModel G_TYPE_LIST_MODEL object bazaar-orig-v0.7.14/src/bz-flatpak-instance.c0000664000175000017500000027550015166123241017741 0ustar hasanhasan/* bz-flatpak-instance.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::FLATPAK" #define BAZAAR_MODULE "flatpak" #include #include #include "config.h" #include "bz-backend-notification.h" #include "bz-backend-transaction-op-payload.h" #include "bz-backend-transaction-op-progress-payload.h" #include "bz-backend.h" #include "bz-env.h" #include "bz-flatpak-private.h" #include "bz-global-net.h" #include "bz-io.h" #include "bz-repository.h" #include "bz-util.h" /* clang-format off */ G_DEFINE_QUARK (bz-flatpak-error-quark, bz_flatpak_error); /* clang-format on */ struct _BzFlatpakInstance { GObject parent_instance; DexScheduler *scheduler; FlatpakInstallation *system; GFileMonitor *system_events; int system_mute; FlatpakInstallation *user; GFileMonitor *user_events; int user_mute; GMutex mute_mutex; GMutex notif_mutex; GPtrArray *notif_channels; DexFuture *notif_send; GMutex transactions_mutex; /* BzEntry* -> GPtrArray* -> GCancellable* */ GHashTable *ongoing_cancellables; }; static void backend_iface_init (BzBackendInterface *iface); G_DEFINE_FINAL_TYPE_WITH_CODE ( BzFlatpakInstance, bz_flatpak_instance, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (BZ_TYPE_BACKEND, backend_iface_init)); BZ_DEFINE_DATA ( init, Init, { BzFlatpakInstance *self; }, BZ_RELEASE_DATA (self, g_object_unref)) static DexFuture * init_fiber (InitData *data); BZ_DEFINE_DATA ( check_has_flathub, CheckHasFlathub, { GWeakRef *self; GCancellable *cancellable; }, BZ_RELEASE_DATA (self, bz_weak_release); BZ_RELEASE_DATA (cancellable, g_object_unref)); static DexFuture * check_has_flathub_fiber (CheckHasFlathubData *data); BZ_DEFINE_DATA ( ensure_flathub, EnsureFlathub, { GWeakRef *self; GCancellable *cancellable; }, BZ_RELEASE_DATA (self, bz_weak_release); BZ_RELEASE_DATA (cancellable, g_object_unref)); static DexFuture * ensure_flathub_fiber (EnsureFlathubData *data); BZ_DEFINE_DATA ( load_local_ref, LoadLocalRef, { GWeakRef *self; GCancellable *cancellable; GFile *file; }, BZ_RELEASE_DATA (self, bz_weak_release); BZ_RELEASE_DATA (cancellable, g_object_unref); BZ_RELEASE_DATA (file, g_object_unref)); static DexFuture * load_local_ref_fiber (LoadLocalRefData *data); BZ_DEFINE_DATA ( gather_refs, GatherRefs, { GWeakRef *self; GCancellable *cancellable; guint total; }, BZ_RELEASE_DATA (self, bz_weak_release); BZ_RELEASE_DATA (cancellable, g_object_unref)); static DexFuture * retrieve_remote_refs_fiber (GatherRefsData *data); static DexFuture * retrieve_installs_fiber (GatherRefsData *data); static DexFuture * retrieve_updates_fiber (GatherRefsData *data); BZ_DEFINE_DATA ( list_repos, ListRepos, { GWeakRef *self; GCancellable *cancellable; }, BZ_RELEASE_DATA (self, bz_weak_release); BZ_RELEASE_DATA (cancellable, g_object_unref)); static DexFuture * list_repositories_fiber (ListReposData *data); BZ_DEFINE_DATA ( retrieve_refs_for_remote, RetrieveRefsForRemote, { GatherRefsData *parent; FlatpakInstallation *installation; FlatpakRemote *remote; }, BZ_RELEASE_DATA (parent, gather_refs_data_unref); BZ_RELEASE_DATA (installation, g_object_unref); BZ_RELEASE_DATA (remote, g_object_unref)); static DexFuture * retrieve_refs_for_remote_fiber (RetrieveRefsForRemoteData *data); static void gather_refs_update_progress (const char *status, guint progress, gboolean estimating, GatherRefsData *data); BZ_DEFINE_DATA ( transaction, Transaction, { GWeakRef *self; GMutex mutex; GCancellable *cancellable; GPtrArray *installs; GPtrArray *updates; GPtrArray *removals; DexChannel *channel; GPtrArray *send_futures; GHashTable *ref_to_entry_hash; GHashTable *op_to_progress_hash; guint unidentified_op_cnt; }, BZ_RELEASE_DATA (self, bz_weak_release); g_mutex_clear (&self->mutex); BZ_RELEASE_DATA (cancellable, g_object_unref); BZ_RELEASE_DATA (installs, g_ptr_array_unref); BZ_RELEASE_DATA (updates, g_ptr_array_unref); BZ_RELEASE_DATA (removals, g_ptr_array_unref); BZ_RELEASE_DATA (channel, dex_unref); BZ_RELEASE_DATA (send_futures, g_ptr_array_unref); BZ_RELEASE_DATA (ref_to_entry_hash, g_hash_table_unref); BZ_RELEASE_DATA (op_to_progress_hash, g_hash_table_unref)); static DexFuture * transaction_fiber (TransactionData *data); BZ_DEFINE_DATA ( transaction_job, TransactionJob, { TransactionData *parent; FlatpakTransaction *transaction; }, BZ_RELEASE_DATA (parent, transaction_data_unref); BZ_RELEASE_DATA (transaction, g_object_unref)); static DexFuture * transaction_job_fiber (TransactionJobData *data); static void transaction_new_operation (FlatpakTransaction *object, FlatpakTransactionOperation *operation, FlatpakTransactionProgress *progress, TransactionData *data); static void transaction_operation_done (FlatpakTransaction *object, FlatpakTransactionOperation *operation, gchar *commit, gint result, TransactionData *data); static gboolean transaction_operation_error (FlatpakTransaction *object, FlatpakTransactionOperation *operation, GError *error, gint details, TransactionData *data); static gboolean transaction_ready (FlatpakTransaction *object, TransactionData *data); static BzFlatpakEntry * find_entry_from_operation (TransactionData *data, FlatpakTransactionOperation *operation); BZ_DEFINE_DATA ( transaction_operation, TransactionOperation, { TransactionData *parent; BzFlatpakEntry *entry; BzBackendTransactionOpPayload *op; }, BZ_RELEASE_DATA (parent, transaction_data_unref); BZ_RELEASE_DATA (entry, g_object_unref); BZ_RELEASE_DATA (op, g_object_unref)); static void transaction_progress_changed (FlatpakTransactionProgress *object, TransactionOperationData *data); static void installation_event (BzFlatpakInstance *self, GFile *file, GFile *other_file, GFileMonitorEvent event_type, GFileMonitor *monitor); static void send_notif (BzFlatpakInstance *self, DexChannel *channel, BzBackendNotification *notif, gboolean lock); static void send_notif_all (BzFlatpakInstance *self, BzBackendNotification *notif, gboolean lock); #define SEND_AND_RETURN_ERROR(_self, _lock, _error, ...) \ G_STMT_START \ { \ g_autofree char *_error_string = NULL; \ g_autoptr (BzBackendNotification) _notif = NULL; \ \ _error_string = g_strdup_printf (__VA_ARGS__); \ \ _notif = bz_backend_notification_new (); \ bz_backend_notification_set_kind (_notif, BZ_BACKEND_NOTIFICATION_KIND_ERROR); \ bz_backend_notification_set_error (_notif, _error_string); \ send_notif_all ((_self), _notif, (_lock)); \ \ return dex_future_new_for_error ( \ g_error_new_literal (BZ_FLATPAK_ERROR, \ (_error), \ _error_string)); \ } \ G_STMT_END BZ_DEFINE_DATA ( wait_notif, WaitNotif, { GWeakRef self; DexChannel *channel; BzBackendNotification *notif; }, g_weak_ref_clear (&self->self); BZ_RELEASE_DATA (channel, dex_unref); BZ_RELEASE_DATA (notif, g_object_unref)); static DexFuture * wait_notif_finally (DexFuture *future, WaitNotifData *data); static gint cmp_rref (FlatpakRemoteRef *a, FlatpakRemoteRef *b, GHashTable *hash); static AsComponent * parse_component_for_node (XbNode *node, GError **error); static GBytes * decompress_appstream_gz (GBytes *appstream_gz, GCancellable *cancellable, GError **error); static XbSilo * build_silo (XbBuilderSource *source, GCancellable *cancellable, GError **error); static AsComponent * extract_first_component_for_silo (XbSilo *silo, GError **error); static void bz_flatpak_instance_dispose (GObject *object) { BzFlatpakInstance *self = BZ_FLATPAK_INSTANCE (object); dex_clear (&self->scheduler); g_clear_object (&self->system); g_clear_object (&self->system_events); g_clear_object (&self->user); g_clear_object (&self->user_events); g_mutex_clear (&self->mute_mutex); g_clear_pointer (&self->notif_channels, g_ptr_array_unref); dex_clear (&self->notif_send); g_mutex_clear (&self->notif_mutex); g_clear_pointer (&self->ongoing_cancellables, g_hash_table_unref); g_mutex_clear (&self->transactions_mutex); G_OBJECT_CLASS (bz_flatpak_instance_parent_class)->dispose (object); } static void bz_flatpak_instance_class_init (BzFlatpakInstanceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = bz_flatpak_instance_dispose; } static void bz_flatpak_instance_init (BzFlatpakInstance *self) { self->scheduler = dex_thread_pool_scheduler_new (); self->system_mute = 0; self->user_mute = 0; g_mutex_init (&self->mute_mutex); self->notif_channels = g_ptr_array_new_with_free_func (dex_unref); g_mutex_init (&self->notif_mutex); self->ongoing_cancellables = g_hash_table_new_full ( g_direct_hash, g_direct_equal, g_object_unref, (GDestroyNotify) g_ptr_array_unref); g_mutex_init (&self->transactions_mutex); } static DexChannel * bz_flatpak_instance_create_notification_channel (BzBackend *backend) { BzFlatpakInstance *self = BZ_FLATPAK_INSTANCE (backend); g_autoptr (DexChannel) channel = NULL; channel = dex_channel_new (0); g_mutex_lock (&self->notif_mutex); g_ptr_array_add (self->notif_channels, dex_ref (channel)); g_mutex_unlock (&self->notif_mutex); return g_steal_pointer (&channel); } static DexFuture * bz_flatpak_instance_load_local_package (BzBackend *backend, GFile *file, GCancellable *cancellable) { BzFlatpakInstance *self = BZ_FLATPAK_INSTANCE (backend); g_autoptr (LoadLocalRefData) data = NULL; data = load_local_ref_data_new (); data->self = bz_track_weak (self); data->cancellable = bz_object_maybe_ref (cancellable); data->file = g_object_ref (file); return dex_scheduler_spawn ( self->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) load_local_ref_fiber, load_local_ref_data_ref (data), load_local_ref_data_unref); } static DexFuture * bz_flatpak_instance_retrieve_remote_refs (BzBackend *backend, GCancellable *cancellable) { BzFlatpakInstance *self = BZ_FLATPAK_INSTANCE (backend); g_autoptr (GatherRefsData) data = NULL; data = gather_refs_data_new (); data->self = bz_track_weak (self); data->cancellable = bz_object_maybe_ref (cancellable); data->total = 0; return dex_scheduler_spawn ( self->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) retrieve_remote_refs_fiber, gather_refs_data_ref (data), gather_refs_data_unref); } static DexFuture * bz_flatpak_instance_retrieve_install_ids (BzBackend *backend, GCancellable *cancellable) { BzFlatpakInstance *self = BZ_FLATPAK_INSTANCE (backend); g_autoptr (GatherRefsData) data = NULL; data = gather_refs_data_new (); data->self = bz_track_weak (self); data->cancellable = bz_object_maybe_ref (cancellable); return dex_scheduler_spawn ( self->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) retrieve_installs_fiber, gather_refs_data_ref (data), gather_refs_data_unref); } static DexFuture * bz_flatpak_instance_retrieve_update_ids (BzBackend *backend, GCancellable *cancellable) { BzFlatpakInstance *self = BZ_FLATPAK_INSTANCE (backend); g_autoptr (GatherRefsData) data = NULL; data = gather_refs_data_new (); data->self = bz_track_weak (self); data->cancellable = bz_object_maybe_ref (cancellable); return dex_scheduler_spawn ( self->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) retrieve_updates_fiber, gather_refs_data_ref (data), gather_refs_data_unref); } static DexFuture * bz_flatpak_instance_list_repositories (BzBackend *backend, GCancellable *cancellable) { BzFlatpakInstance *self = BZ_FLATPAK_INSTANCE (backend); g_autoptr (ListReposData) data = NULL; data = list_repos_data_new (); data->self = bz_track_weak (self); data->cancellable = bz_object_maybe_ref (cancellable); return dex_scheduler_spawn ( self->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) list_repositories_fiber, list_repos_data_ref (data), list_repos_data_unref); } static DexFuture * bz_flatpak_instance_schedule_transaction (BzBackend *backend, BzEntry **installs, guint n_installs, BzEntry **updates, guint n_updates, BzEntry **removals, guint n_removals, DexChannel *channel, GCancellable *cancellable) { BzFlatpakInstance *self = BZ_FLATPAK_INSTANCE (backend); BzFlatpakEntry **installs_dup = NULL; BzFlatpakEntry **updates_dup = NULL; BzFlatpakEntry **removals_dup = NULL; g_autoptr (TransactionData) data = NULL; for (guint i = 0; i < n_installs; i++) dex_return_error_if_fail (BZ_IS_FLATPAK_ENTRY (installs[i])); for (guint i = 0; i < n_updates; i++) dex_return_error_if_fail (BZ_IS_FLATPAK_ENTRY (updates[i])); for (guint i = 0; i < n_removals; i++) dex_return_error_if_fail (BZ_IS_FLATPAK_ENTRY (removals[i])); if (n_installs > 0) { installs_dup = g_malloc0_n (n_installs, sizeof (*installs_dup)); for (guint i = 0; i < n_installs; i++) installs_dup[i] = g_object_ref (BZ_FLATPAK_ENTRY (installs[i])); } if (n_updates > 0) { updates_dup = g_malloc0_n (n_updates, sizeof (*updates_dup)); for (guint i = 0; i < n_updates; i++) updates_dup[i] = g_object_ref (BZ_FLATPAK_ENTRY (updates[i])); } if (n_removals > 0) { removals_dup = g_malloc0_n (n_removals, sizeof (*removals_dup)); for (guint i = 0; i < n_removals; i++) removals_dup[i] = g_object_ref (BZ_FLATPAK_ENTRY (removals[i])); } data = transaction_data_new (); data->self = bz_track_weak (self); data->cancellable = bz_object_maybe_ref (cancellable); data->installs = installs_dup != NULL ? g_ptr_array_new_take ((gpointer *) installs_dup, n_installs, g_object_unref) : NULL; data->updates = updates_dup != NULL ? g_ptr_array_new_take ((gpointer *) updates_dup, n_updates, g_object_unref) : NULL; data->removals = removals_dup != NULL ? g_ptr_array_new_take ((gpointer *) removals_dup, n_removals, g_object_unref) : NULL; data->channel = bz_dex_maybe_ref (channel); data->send_futures = g_ptr_array_new_with_free_func (dex_unref); data->ref_to_entry_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); data->op_to_progress_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL); g_mutex_init (&data->mutex); return dex_scheduler_spawn ( self->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) transaction_fiber, transaction_data_ref (data), transaction_data_unref); } static gboolean bz_flatpak_instance_cancel_task_for_entry (BzBackend *backend, BzEntry *entry) { BzFlatpakInstance *self = BZ_FLATPAK_INSTANCE (backend); g_autoptr (GMutexLocker) locker = NULL; GPtrArray *cancellables = NULL; locker = g_mutex_locker_new (&self->transactions_mutex); cancellables = g_hash_table_lookup (self->ongoing_cancellables, entry); if (cancellables == NULL) return FALSE; for (guint i = 0; i < cancellables->len; i++) { GCancellable *cancellable = NULL; cancellable = g_ptr_array_index (cancellables, i); g_cancellable_cancel (cancellable); } return TRUE; } static void backend_iface_init (BzBackendInterface *iface) { iface->create_notification_channel = bz_flatpak_instance_create_notification_channel; iface->load_local_package = bz_flatpak_instance_load_local_package; iface->retrieve_remote_entries = bz_flatpak_instance_retrieve_remote_refs; iface->retrieve_install_ids = bz_flatpak_instance_retrieve_install_ids; iface->retrieve_update_ids = bz_flatpak_instance_retrieve_update_ids; iface->list_repositories = bz_flatpak_instance_list_repositories; iface->schedule_transaction = bz_flatpak_instance_schedule_transaction; iface->cancel_task_for_entry = bz_flatpak_instance_cancel_task_for_entry; } FlatpakInstallation * bz_flatpak_instance_get_system_installation (BzFlatpakInstance *self) { g_return_val_if_fail (BZ_IS_FLATPAK_INSTANCE (self), NULL); return self->system; } FlatpakInstallation * bz_flatpak_instance_get_user_installation (BzFlatpakInstance *self) { g_return_val_if_fail (BZ_IS_FLATPAK_INSTANCE (self), NULL); return self->user; } DexFuture * bz_flatpak_instance_new (void) { g_autoptr (InitData) data = NULL; data = init_data_new (); data->self = g_object_new (BZ_TYPE_FLATPAK_INSTANCE, NULL); return dex_scheduler_spawn ( data->self->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) init_fiber, init_data_ref (data), init_data_unref); } DexFuture * bz_flatpak_instance_has_flathub (BzFlatpakInstance *self, GCancellable *cancellable) { g_autoptr (CheckHasFlathubData) data = NULL; dex_return_error_if_fail (BZ_IS_FLATPAK_INSTANCE (self)); dex_return_error_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); data = check_has_flathub_data_new (); data->self = bz_track_weak (self); data->cancellable = bz_object_maybe_ref (cancellable); return dex_scheduler_spawn ( self->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) check_has_flathub_fiber, check_has_flathub_data_ref (data), check_has_flathub_data_unref); } DexFuture * bz_flatpak_instance_ensure_has_flathub (BzFlatpakInstance *self, GCancellable *cancellable) { g_autoptr (EnsureFlathubData) data = NULL; dex_return_error_if_fail (BZ_IS_FLATPAK_INSTANCE (self)); dex_return_error_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); data = ensure_flathub_data_new (); data->self = bz_track_weak (self); data->cancellable = bz_object_maybe_ref (cancellable); return dex_scheduler_spawn ( self->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) ensure_flathub_fiber, ensure_flathub_data_ref (data), ensure_flathub_data_unref); } static DexFuture * init_fiber (InitData *data) { BzFlatpakInstance *self = data->self; g_autoptr (GError) local_error = NULL; g_autofree char *main_cache = NULL; bz_discard_module_dir (); self->system = flatpak_installation_new_system (NULL, &local_error); if (self->system != NULL) { self->system_events = flatpak_installation_create_monitor ( self->system, NULL, &local_error); if (self->system_events != NULL) g_signal_connect_swapped ( self->system_events, "changed", G_CALLBACK (installation_event), self); else { g_warning ("Failed to initialize event watch for system installation: %s", local_error->message); g_clear_pointer (&local_error, g_error_free); } } else { g_warning ("Failed to initialize system installation: %s", local_error->message); g_clear_pointer (&local_error, g_error_free); } #ifdef SANDBOXED_LIBFLATPAK { g_autoptr (GFile) user_installation_path = NULL; const char *home = g_get_home_dir (); g_autofree char *user_flatpak_path = g_build_filename (home, ".local", "share", "flatpak", NULL); user_installation_path = g_file_new_for_path (user_flatpak_path); self->user = flatpak_installation_new_for_path ( user_installation_path, TRUE, NULL, &local_error); } #else self->user = flatpak_installation_new_user (NULL, &local_error); #endif if (self->user != NULL) { self->user_events = flatpak_installation_create_monitor ( self->user, NULL, &local_error); if (self->user_events != NULL) g_signal_connect_swapped ( self->user_events, "changed", G_CALLBACK (installation_event), self); else { g_warning ("Failed to initialize event watch for user installation: %s", local_error->message); g_clear_pointer (&local_error, g_error_free); } } else { g_warning ("Failed to initialize user installation: %s", local_error->message); g_clear_pointer (&local_error, g_error_free); } if (self->system == NULL && self->user == NULL) return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_CANNOT_INITIALIZE, "Failed to initialize any flatpak installations"); return dex_future_new_for_object (self); } static DexFuture * check_has_flathub_fiber (CheckHasFlathubData *data) { g_autoptr (BzFlatpakInstance) self = NULL; GCancellable *cancellable = data->cancellable; g_autoptr (GError) local_error = NULL; g_autoptr (GPtrArray) system_remotes = NULL; guint n_system_remotes = 0; g_autoptr (GPtrArray) user_remotes = NULL; guint n_user_remotes = 0; bz_weak_get_or_return_reject (self, data->self); if (self->system != NULL) { system_remotes = flatpak_installation_list_remotes ( self->system, cancellable, &local_error); if (system_remotes == NULL) return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_CANNOT_INITIALIZE, "Failed to enumerate remotes for system installation: %s", local_error->message); n_system_remotes = system_remotes->len; } // Downloading from user remotes in the Flatpak is unsupported. #ifndef SANDBOXED_LIBFLATPAK if (self->user != NULL) { user_remotes = flatpak_installation_list_remotes ( self->user, cancellable, &local_error); if (user_remotes == NULL) return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_CANNOT_INITIALIZE, "Failed to enumerate remotes for user installation: %s", local_error->message); n_user_remotes = user_remotes->len; } #endif for (guint i = 0; i < n_system_remotes + n_user_remotes; i++) { FlatpakRemote *remote = NULL; const char *name = NULL; if (i < n_system_remotes) remote = g_ptr_array_index (system_remotes, i); else remote = g_ptr_array_index (user_remotes, i - n_system_remotes); if (flatpak_remote_get_disabled (remote) || flatpak_remote_get_noenumerate (remote)) continue; name = flatpak_remote_get_name (remote); if (g_strcmp0 (name, "flathub") == 0) return dex_future_new_true (); } return dex_future_new_false (); } static DexFuture * ensure_flathub_fiber (EnsureFlathubData *data) { g_autoptr (BzFlatpakInstance) self = NULL; GCancellable *cancellable = data->cancellable; g_autoptr (GError) local_error = NULL; g_autoptr (FlatpakRemote) sys_remote = NULL; g_autoptr (FlatpakRemote) usr_remote = NULL; gboolean result = FALSE; bz_weak_get_or_return_reject (self, data->self); #define REPO_URL "https://dl.flathub.org/repo/flathub.flatpakrepo" if (self->system != NULL) sys_remote = flatpak_installation_get_remote_by_name ( self->system, "flathub", cancellable, NULL); if (self->user != NULL) usr_remote = flatpak_installation_get_remote_by_name ( self->user, "flathub", cancellable, NULL); if (sys_remote != NULL) { flatpak_remote_set_disabled (sys_remote, FALSE); flatpak_remote_set_noenumerate (sys_remote, FALSE); flatpak_remote_set_gpg_verify (sys_remote, TRUE); result = flatpak_installation_modify_remote ( self->system, sys_remote, cancellable, &local_error); if (!result) return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_REMOTE_SYNCHRONIZATION_FAILURE, "Failed to modify existing system flathub remote: %s", local_error->message); } #ifndef SANDBOXED_LIBFLATPAK else if (self->system != NULL) #else else if (self->system != NULL && usr_remote == NULL) #endif { g_autoptr (SoupMessage) message = NULL; g_autoptr (GOutputStream) output = NULL; g_autoptr (GBytes) bytes = NULL; g_autoptr (FlatpakRemote) remote = NULL; message = soup_message_new (SOUP_METHOD_GET, REPO_URL); output = g_memory_output_stream_new_resizable (); result = dex_await ( bz_send_with_global_http_session_then_splice_into (message, output), &local_error); if (!result) return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_IO_MISBEHAVIOR, "Failed to retrieve flatpakrepo file from %s: %s", REPO_URL, local_error->message); bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (output)); remote = flatpak_remote_new_from_file ("flathub", bytes, &local_error); if (remote == NULL) return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_IO_MISBEHAVIOR, "Failed to construct flatpak remote from flatpakrepo file %s: %s", REPO_URL, local_error->message); flatpak_remote_set_gpg_verify (remote, TRUE); result = flatpak_installation_add_remote ( self->system, remote, TRUE, cancellable, &local_error); if (!result) return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_REMOTE_SYNCHRONIZATION_FAILURE, "Failed to add flathub to system flatpak installation: %s", local_error->message); } #ifndef SANDBOXED_LIBFLATPAK if (usr_remote != NULL) { flatpak_remote_set_disabled (usr_remote, FALSE); flatpak_remote_set_noenumerate (usr_remote, FALSE); flatpak_remote_set_gpg_verify (usr_remote, TRUE); result = flatpak_installation_modify_remote ( self->user, usr_remote, cancellable, &local_error); if (!result) return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_REMOTE_SYNCHRONIZATION_FAILURE, "Failed to modify existing user flathub remote: %s", local_error->message); } #endif return dex_future_new_true (); } static DexFuture * load_local_ref_fiber (LoadLocalRefData *data) { GFile *file = data->file; gboolean result = FALSE; g_autoptr (GError) local_error = NULL; g_autofree char *uri = NULL; g_autofree char *path = NULL; uri = g_file_get_uri (file); path = g_file_get_path (file); if (uri == NULL) uri = g_strdup_printf ("file://%s", path); if (g_str_has_suffix (uri, ".flatpakref")) { const char *resolved_uri = NULL; g_autoptr (GKeyFile) key_file = g_key_file_new (); g_autofree char *name = NULL; if (g_str_has_prefix (uri, "flatpak+https")) resolved_uri = uri + strlen ("flatpak+"); else resolved_uri = uri; key_file = g_key_file_new (); if (g_str_has_prefix (resolved_uri, "http")) { g_autoptr (SoupMessage) message = NULL; g_autoptr (GOutputStream) output = NULL; g_autoptr (GBytes) bytes = NULL; message = soup_message_new (SOUP_METHOD_GET, resolved_uri); output = g_memory_output_stream_new_resizable (); result = dex_await ( bz_send_with_global_http_session_then_splice_into (message, output), &local_error); if (!result) return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_IO_MISBEHAVIOR, "Failed to retrieve flatpakref file from %s: %s", resolved_uri, local_error->message); bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (output)); result = g_key_file_load_from_bytes (key_file, bytes, G_KEY_FILE_NONE, &local_error); } else if (path != NULL) result = g_key_file_load_from_file ( key_file, path, G_KEY_FILE_NONE, &local_error); else local_error = g_error_new ( G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Cannot handle URIs of this type"); if (!result) return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_IO_MISBEHAVIOR, "Failed to load flatpakref '%s' into a key file: %s", uri, local_error->message); name = g_key_file_get_string (key_file, "Flatpak Ref", "Name", &local_error); if (name == NULL) return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_IO_MISBEHAVIOR, "Failed to load locate \"Name\" key in flatpakref '%s': %s", uri, local_error->message); return dex_future_new_take_string (g_steal_pointer (&name)); } else /* This is a bundle ref */ { g_autoptr (FlatpakBundleRef) bref = NULL; g_autoptr (BzFlatpakEntry) entry = NULL; g_autoptr (GBytes) appstream_gz = NULL; g_autoptr (GBytes) appstream = NULL; g_autoptr (AsComponent) component = NULL; if (path == NULL) return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_IO_MISBEHAVIOR, "Cannot load '%s' as a flatpak bundle: URI is not a local file", uri); bref = flatpak_bundle_ref_new (file, &local_error); if (bref == NULL) return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_IO_MISBEHAVIOR, "Failed to load local flatpak bundle '%s': %s", path, local_error->message); appstream_gz = flatpak_bundle_ref_get_appstream (bref); if (appstream_gz != NULL) { appstream = decompress_appstream_gz (appstream_gz, NULL, &local_error); if (appstream == NULL) { g_warning ("Failed to decompress AppStream data: %s", local_error->message); g_clear_error (&local_error); } else { g_autoptr (XbBuilderSource) source = NULL; source = xb_builder_source_new (); if (!xb_builder_source_load_bytes (source, appstream, XB_BUILDER_SOURCE_FLAG_LITERAL_TEXT, &local_error)) { g_warning ("Failed to load AppStream bytes into xmlb: %s", local_error->message); g_clear_error (&local_error); } else { g_autoptr (XbSilo) silo = NULL; silo = build_silo (source, NULL, &local_error); if (silo == NULL) { g_warning ("Failed to compile xmlb silo: %s", local_error->message); g_clear_error (&local_error); } else { component = extract_first_component_for_silo (silo, &local_error); if (component == NULL && local_error != NULL) { g_warning ("Failed to parse component: %s", local_error->message); g_clear_error (&local_error); } } } } } entry = bz_flatpak_entry_new_for_ref ( FLATPAK_REF (bref), NULL, FALSE, component, NULL, &local_error); if (entry == NULL) return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_IO_MISBEHAVIOR, "Failed to parse information from flatpak bundle '%s': %s", path, local_error->message); return dex_future_new_for_object (entry); } } static DexFuture * retrieve_remote_refs_fiber (GatherRefsData *data) { g_autoptr (BzFlatpakInstance) self = NULL; GCancellable *cancellable = data->cancellable; g_autoptr (GError) local_error = NULL; g_autoptr (GPtrArray) system_remotes = NULL; guint n_system_remotes = 0; g_autoptr (GPtrArray) user_remotes = NULL; guint n_user_remotes = 0; g_autoptr (GHashTable) blocked_names_hash = NULL; g_autoptr (GPtrArray) jobs = NULL; g_autoptr (GPtrArray) job_names = NULL; g_autoptr (DexFuture) future = NULL; gboolean result = FALSE; g_autoptr (GString) error_string = NULL; bz_weak_get_or_return_reject (self, data->self); if (self->system != NULL) { system_remotes = flatpak_installation_list_remotes ( self->system, cancellable, &local_error); if (system_remotes == NULL) SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_CANNOT_INITIALIZE, "Failed to enumerate remotes for system installation: %s", local_error->message); n_system_remotes = system_remotes->len; } if (self->user != NULL) { user_remotes = flatpak_installation_list_remotes ( self->user, cancellable, &local_error); if (user_remotes == NULL) SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_CANNOT_INITIALIZE, "Failed to enumerate remotes for user installation: %s", local_error->message); n_user_remotes = user_remotes->len; } if (n_user_remotes + n_system_remotes == 0) return dex_future_new_true (); jobs = g_ptr_array_new_with_free_func (dex_unref); job_names = g_ptr_array_new_with_free_func (g_free); for (guint i = 0; i < n_system_remotes + n_user_remotes; i++) { FlatpakInstallation *installation = NULL; FlatpakRemote *remote = NULL; const char *name = NULL; g_autoptr (RetrieveRefsForRemoteData) job_data = NULL; g_autoptr (DexFuture) job_future = NULL; if (i < n_system_remotes) { installation = self->system; remote = g_ptr_array_index (system_remotes, i); } else { installation = self->user; remote = g_ptr_array_index (user_remotes, i - n_system_remotes); } name = flatpak_remote_get_name (remote); { g_autoptr (BzBackendNotification) notif = NULL; notif = bz_backend_notification_new (); bz_backend_notification_set_kind (notif, BZ_BACKEND_NOTIFICATION_KIND_REMOTE_SYNC_START); bz_backend_notification_set_remote_name (notif, name); send_notif_all (self, notif, TRUE); } job_data = retrieve_refs_for_remote_data_new (); job_data->parent = gather_refs_data_ref (data); job_data->installation = g_object_ref (installation); job_data->remote = g_object_ref (remote); job_future = dex_scheduler_spawn ( self->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) retrieve_refs_for_remote_fiber, retrieve_refs_for_remote_data_ref (job_data), retrieve_refs_for_remote_data_unref); g_ptr_array_add (jobs, g_steal_pointer (&job_future)); g_ptr_array_add (job_names, g_strdup (name)); } if (jobs->len == 0) return dex_future_new_true (); result = dex_await (dex_future_allv ( (DexFuture *const *) jobs->pdata, jobs->len), NULL); if (!result) error_string = g_string_new ("No remotes could be synchronized:\n\n"); for (guint i = 0; i < jobs->len; i++) { DexFuture *job_future = NULL; char *name = NULL; job_future = g_ptr_array_index (jobs, i); name = g_ptr_array_index (job_names, i); dex_future_get_value (job_future, &local_error); if (local_error != NULL) { if (error_string == NULL) error_string = g_string_new ("Some remotes couldn't be fully sychronized:\n"); g_string_append_printf (error_string, "\n%s failed because: %s\n", name, local_error->message); } g_clear_pointer (&local_error, g_error_free); } if (result) { if (error_string != NULL) return dex_future_new_take_string ( g_string_free_and_steal (g_steal_pointer (&error_string))); else return dex_future_new_true (); } else return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_REMOTE_SYNCHRONIZATION_FAILURE, "%s", error_string->str); } static void gather_refs_update_progress (const char *status, guint progress, gboolean estimating, GatherRefsData *data) { } static DexFuture * retrieve_refs_for_enumerable_remote (RetrieveRefsForRemoteData *data, const char *remote_name, FlatpakInstallation *installation, FlatpakRemote *remote) { g_autoptr (BzFlatpakInstance) self = NULL; GCancellable *cancellable = data->parent->cancellable; g_autoptr (GError) local_error = NULL; gboolean result = FALSE; g_autoptr (GFile) appstream_dir = NULL; g_autofree char *appstream_dir_path = NULL; g_autofree char *appstream_xml_path = NULL; g_autoptr (GFile) appstream_xml = NULL; g_autoptr (XbBuilderSource) source = NULL; g_autoptr (XbSilo) silo = NULL; g_autoptr (XbNode) root = NULL; g_autoptr (GPtrArray) children = NULL; g_autoptr (GHashTable) component_hash = NULL; g_autoptr (GPtrArray) refs = NULL; bz_weak_get_or_return_reject (self, data->parent->self); g_debug ("Remote '%s' is enumerable, listing all remote refs", remote_name); result = flatpak_installation_update_remote_sync ( installation, remote_name, cancellable, &local_error); if (!result) SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_REMOTE_SYNCHRONIZATION_FAILURE, "Failed to synchronize remote '%s': %s", remote_name, local_error->message); result = flatpak_installation_update_appstream_full_sync ( installation, remote_name, NULL, (FlatpakProgressCallback) gather_refs_update_progress, data, NULL, cancellable, &local_error); if (!result) SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_REMOTE_SYNCHRONIZATION_FAILURE, "Failed to synchronize appstream data for remote '%s': %s", remote_name, local_error->message); appstream_dir = flatpak_remote_get_appstream_dir (remote, NULL); if (appstream_dir == NULL) SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_IO_MISBEHAVIOR, "Failed to locate appstream directory for remote '%s': %s", remote_name, local_error->message); appstream_dir_path = g_file_get_path (appstream_dir); appstream_xml_path = g_build_filename (appstream_dir_path, "appstream.xml.gz", NULL); if (!g_file_test (appstream_xml_path, G_FILE_TEST_EXISTS)) SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_IO_MISBEHAVIOR, "Failed to verify existence of appstream " "bundle download at path %s for remote '%s'", appstream_xml_path, remote_name); appstream_xml = g_file_new_for_path (appstream_xml_path); source = xb_builder_source_new (); result = xb_builder_source_load_file ( source, appstream_xml, XB_BUILDER_SOURCE_FLAG_WATCH_FILE | XB_BUILDER_SOURCE_FLAG_LITERAL_TEXT, cancellable, &local_error); if (!result) SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_IO_MISBEHAVIOR, "Failed to load binary xml from appstream bundle " "download at path %s for remote '%s': %s", appstream_xml_path, remote_name, local_error->message); silo = build_silo (source, cancellable, &local_error); #ifdef __GLIBC__ /* From gnome-software/plugins/core/gs-plugin-appstream.c * * https://gitlab.gnome.org/GNOME/gnome-software/-/issues/941 * libxmlb <= 0.3.22 makes lots of temporary heap allocations parsing large XMLs * trim the heap after parsing to control RSS growth. */ malloc_trim (0); #endif if (silo == NULL) SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_IO_MISBEHAVIOR, "Failed to compile binary xml silo from appstream bundle " "download at path %s for remote '%s': %s", appstream_xml_path, remote_name, local_error->message); root = xb_silo_get_root (silo); children = xb_node_get_children (root); component_hash = g_hash_table_new (g_str_hash, g_str_equal); for (guint i = 0; i < children->len; i++) { XbNode *component_node = NULL; AsComponent *component = NULL; const char *id = NULL; component_node = g_ptr_array_index (children, i); component = parse_component_for_node (component_node, &local_error); if (component == NULL) { SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_APPSTREAM_FAILURE, "Failed to parse appstream component from appstream bundle silo " "originating from download at path %s for remote '%s': %s", appstream_xml_path, remote_name, local_error->message); } id = as_component_get_id (component); g_hash_table_replace (component_hash, (gpointer) id, component); } refs = flatpak_installation_list_remote_refs_sync ( installation, remote_name, cancellable, &local_error); if (refs == NULL) SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_REMOTE_SYNCHRONIZATION_FAILURE, "Failed to enumerate refs for remote '%s': %s", remote_name, local_error->message); { g_autoptr (BzBackendNotification) notif = NULL; notif = bz_backend_notification_new (); bz_backend_notification_set_kind (notif, BZ_BACKEND_NOTIFICATION_KIND_TELL_INCOMING); bz_backend_notification_set_n_incoming (notif, refs->len); send_notif_all (self, notif, TRUE); } /* Ensure the receiving side of the channel gets * runtimes first, then addons, then applications */ g_ptr_array_sort_values_with_data ( refs, (GCompareDataFunc) cmp_rref, component_hash); for (guint i = 0; i < refs->len; i++) { FlatpakRemoteRef *rref = NULL; const char *name = NULL; AsComponent *component = NULL; g_autoptr (BzFlatpakEntry) entry = NULL; rref = g_ptr_array_index (refs, i); name = flatpak_ref_get_name (FLATPAK_REF (rref)); component = g_hash_table_lookup (component_hash, name); if (component == NULL) { g_autofree char *desktop_id = NULL; desktop_id = g_strdup_printf ("%s.desktop", name); component = g_hash_table_lookup (component_hash, desktop_id); } entry = bz_flatpak_entry_new_for_ref ( FLATPAK_REF (rref), remote, installation == self->user, component, appstream_dir_path, NULL); if (entry != NULL) { g_autoptr (BzBackendNotification) notif = NULL; notif = bz_backend_notification_new (); bz_backend_notification_set_kind (notif, BZ_BACKEND_NOTIFICATION_KIND_REPLACE_ENTRY); bz_backend_notification_set_entry (notif, BZ_ENTRY (entry)); send_notif_all (self, notif, TRUE); } else { g_autoptr (BzBackendNotification) notif = NULL; notif = bz_backend_notification_new (); bz_backend_notification_set_kind (notif, BZ_BACKEND_NOTIFICATION_KIND_TELL_INCOMING); bz_backend_notification_set_n_incoming (notif, -1); send_notif_all (self, notif, TRUE); } } return dex_future_new_true (); } static DexFuture * retrieve_refs_for_noenumerable_remote (RetrieveRefsForRemoteData *data, const char *remote_name, FlatpakInstallation *installation, FlatpakRemote *remote) { g_autoptr (BzFlatpakInstance) self = NULL; GCancellable *cancellable = data->parent->cancellable; g_autoptr (GError) local_error = NULL; g_autoptr (GPtrArray) installed_apps = NULL; guint matched = 0; bz_weak_get_or_return_reject (self, data->parent->self); installed_apps = flatpak_installation_list_installed_refs_by_kind ( installation, FLATPAK_REF_KIND_APP, cancellable, &local_error); if (installed_apps == NULL) SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_LOCAL_SYNCHRONIZATION_FAILURE, "Failed to enumerate installed apps for non-enumerable remote '%s': %s", remote_name, local_error->message); g_debug ("Found %u total installed apps, filtering for remote '%s'", installed_apps->len, remote_name); for (guint i = 0; i < installed_apps->len; i++) { FlatpakInstalledRef *iref = NULL; const char *ref_origin = NULL; g_autoptr (AsComponent) component = NULL; g_autoptr (BzFlatpakEntry) entry = NULL; g_autoptr (GBytes) appstream_gz = NULL; iref = g_ptr_array_index (installed_apps, i); ref_origin = flatpak_installed_ref_get_origin (iref); if (g_strcmp0 (ref_origin, remote_name) != 0) continue; matched++; appstream_gz = flatpak_installed_ref_load_appdata (iref, cancellable, NULL); if (appstream_gz != NULL) { g_autoptr (GBytes) appstream = NULL; g_autoptr (XbBuilderSource) source = NULL; g_autoptr (XbSilo) silo = NULL; g_autoptr (GError) appstream_error = NULL; appstream = decompress_appstream_gz (appstream_gz, cancellable, &appstream_error); if (appstream == NULL) { g_info ("Could not decompress appstream for installed ref: %s", appstream_error ? appstream_error->message : "unknown error"); goto create_entry; } source = xb_builder_source_new (); if (!xb_builder_source_load_bytes (source, appstream, XB_BUILDER_SOURCE_FLAG_LITERAL_TEXT, &appstream_error)) { g_info ("Could not load appstream bytes: %s", appstream_error ? appstream_error->message : "unknown error"); goto create_entry; } silo = build_silo (source, cancellable, &appstream_error); if (silo == NULL) { g_info ("Could not build silo from appstream: %s", appstream_error ? appstream_error->message : "unknown error"); goto create_entry; } component = extract_first_component_for_silo (silo, &appstream_error); if (component == NULL) { g_info ("Could not parse appstream component: %s", appstream_error ? appstream_error->message : "unknown error"); } } create_entry: entry = bz_flatpak_entry_new_for_ref ( FLATPAK_REF (iref), remote, installation == self->user, component, NULL, NULL); if (entry != NULL) { g_autoptr (BzBackendNotification) notif = NULL; notif = bz_backend_notification_new (); bz_backend_notification_set_kind (notif, BZ_BACKEND_NOTIFICATION_KIND_REPLACE_ENTRY); bz_backend_notification_set_entry (notif, BZ_ENTRY (entry)); send_notif_all (self, notif, TRUE); } } g_debug ("Found %u installed apps from non-enumerable remote '%s'", matched, remote_name); { g_autoptr (BzBackendNotification) notif = NULL; notif = bz_backend_notification_new (); bz_backend_notification_set_kind (notif, BZ_BACKEND_NOTIFICATION_KIND_TELL_INCOMING); bz_backend_notification_set_n_incoming (notif, matched); send_notif_all (self, notif, TRUE); } return dex_future_new_true (); } static DexFuture * retrieve_refs_for_remote_fiber (RetrieveRefsForRemoteData *data) { FlatpakInstallation *installation = data->installation; FlatpakRemote *remote = data->remote; g_autoptr (BzFlatpakInstance) self = NULL; const char *remote_name = NULL; gboolean is_noenumerate = FALSE; g_autoptr (DexFuture) ret = NULL; bz_weak_get_or_return_reject (self, data->parent->self); remote_name = flatpak_remote_get_name (remote); is_noenumerate = flatpak_remote_get_noenumerate (remote); /* the fedora flatpak repos cause too many issues */ if (strstr (remote_name, "fedora") != NULL) is_noenumerate = TRUE; #ifdef SANDBOXED_LIBFLATPAK if (is_noenumerate || installation == self->user) #else if (is_noenumerate) #endif ret = retrieve_refs_for_noenumerable_remote ( data, remote_name, installation, remote); else ret = retrieve_refs_for_enumerable_remote ( data, remote_name, installation, remote); { g_autoptr (BzBackendNotification) notif = NULL; notif = bz_backend_notification_new (); bz_backend_notification_set_kind (notif, BZ_BACKEND_NOTIFICATION_KIND_REMOTE_SYNC_FINISH); bz_backend_notification_set_remote_name (notif, remote_name); send_notif_all (self, notif, TRUE); } return g_steal_pointer (&ret); } static DexFuture * retrieve_installs_fiber (GatherRefsData *data) { g_autoptr (BzFlatpakInstance) self = NULL; GCancellable *cancellable = data->cancellable; g_autoptr (GError) local_error = NULL; g_autoptr (GPtrArray) system_refs = NULL; guint n_system_refs = 0; g_autoptr (GPtrArray) user_refs = NULL; guint n_user_refs = 0; g_autoptr (GHashTable) ids = NULL; bz_weak_get_or_return_reject (self, data->self); if (self->system != NULL) { flatpak_installation_drop_caches ( self->system, cancellable, NULL); system_refs = flatpak_installation_list_installed_refs ( self->system, cancellable, &local_error); if (system_refs == NULL) SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_LOCAL_SYNCHRONIZATION_FAILURE, "Failed to discover installed refs for system installation: %s", local_error->message); n_system_refs = system_refs->len; } if (self->user != NULL) { flatpak_installation_drop_caches ( self->user, cancellable, NULL); user_refs = flatpak_installation_list_installed_refs ( self->user, cancellable, &local_error); if (user_refs == NULL) SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_LOCAL_SYNCHRONIZATION_FAILURE, "Failed to discover installed refs for user installation: %s", local_error->message); n_user_refs = user_refs->len; } ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); for (guint i = 0; i < n_system_refs + n_user_refs; i++) { gboolean user = FALSE; FlatpakInstalledRef *iref = NULL; const char *version = NULL; g_autofree char *unique_id = NULL; if (i < n_system_refs) { user = FALSE; iref = g_ptr_array_index (system_refs, i); } else { user = TRUE; iref = g_ptr_array_index (user_refs, i - n_system_refs); } version = flatpak_installed_ref_get_appdata_version (iref); unique_id = bz_flatpak_ref_format_unique (FLATPAK_REF (iref), user); g_hash_table_replace (ids, g_steal_pointer (&unique_id), g_strdup (version != NULL ? version : "")); } return dex_future_new_take_boxed ( G_TYPE_HASH_TABLE, g_steal_pointer (&ids)); } static gboolean should_skip_extension_ref (FlatpakInstalledRef *iref) { const gchar *ref_name = flatpak_ref_get_name (FLATPAK_REF (iref)); /* These get updated with their parents and look really bad in the UI */ return g_str_has_suffix (ref_name, ".Locale") || g_str_has_suffix (ref_name, ".Debug") || g_str_has_suffix (ref_name, ".Sources"); } static DexFuture * retrieve_updates_fiber (GatherRefsData *data) { g_autoptr (BzFlatpakInstance) self = NULL; GCancellable *cancellable = data->cancellable; g_autoptr (GError) local_error = NULL; g_autoptr (GPtrArray) system_refs = NULL; guint n_sys_refs = 0; g_autoptr (GPtrArray) user_refs = NULL; guint n_user_refs = 0; g_autoptr (GPtrArray) ids = NULL; bz_weak_get_or_return_reject (self, data->self); if (self->system != NULL) { system_refs = flatpak_installation_list_installed_refs_for_update ( self->system, cancellable, &local_error); if (system_refs == NULL) SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_REMOTE_SYNCHRONIZATION_FAILURE, "Failed to discover update-elligible refs for system installation: %s", local_error->message); n_sys_refs = system_refs->len; } if (self->user != NULL) { user_refs = flatpak_installation_list_installed_refs_for_update ( self->user, cancellable, &local_error); if (user_refs == NULL) SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_REMOTE_SYNCHRONIZATION_FAILURE, "Failed to discover update-elligible refs for user installation: %s", local_error->message); n_user_refs = user_refs->len; } ids = g_ptr_array_new_with_free_func (g_free); for (guint i = 0; i < n_sys_refs + n_user_refs; i++) { gboolean user = FALSE; FlatpakInstalledRef *iref = NULL; if (i < n_sys_refs) { user = FALSE; iref = g_ptr_array_index (system_refs, i); } else { user = TRUE; iref = g_ptr_array_index (user_refs, i - n_sys_refs); } if (should_skip_extension_ref (iref)) continue; g_ptr_array_add (ids, bz_flatpak_ref_format_unique (FLATPAK_REF (iref), user)); } return dex_future_new_take_boxed ( G_TYPE_PTR_ARRAY, g_steal_pointer (&ids)); } static DexFuture * list_repositories_fiber (ListReposData *data) { g_autoptr (BzFlatpakInstance) self = NULL; GCancellable *cancellable = NULL; g_autoptr (GError) local_error = NULL; g_autoptr (GPtrArray) system_repos = NULL; g_autoptr (GPtrArray) user_repos = NULL; g_autoptr (GListStore) repos = NULL; cancellable = data->cancellable; bz_weak_get_or_return_reject (self, data->self); repos = g_list_store_new (BZ_TYPE_REPOSITORY); if (self->system != NULL) { system_repos = flatpak_installation_list_remotes ( self->system, cancellable, &local_error); if (system_repos == NULL) SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_CANNOT_INITIALIZE, "Failed to enumerate remotes for system installation: %s", local_error->message); for (guint i = 0; i < system_repos->len; i++) { FlatpakRemote *remote = NULL; g_autoptr (BzRepository) repo = NULL; remote = g_ptr_array_index (system_repos, i); repo = g_object_new (BZ_TYPE_REPOSITORY, "name", flatpak_remote_get_name (remote), "title", flatpak_remote_get_title (remote), "url", flatpak_remote_get_url (remote), "is-user", FALSE, NULL); g_list_store_append (repos, repo); } } if (self->user != NULL) { user_repos = flatpak_installation_list_remotes ( self->user, cancellable, &local_error); if (user_repos == NULL) SEND_AND_RETURN_ERROR ( self, TRUE, BZ_FLATPAK_ERROR_CANNOT_INITIALIZE, "Failed to enumerate remotes for user installation: %s", local_error->message); for (guint i = 0; i < user_repos->len; i++) { FlatpakRemote *remote = NULL; g_autoptr (BzRepository) repo = NULL; remote = g_ptr_array_index (user_repos, i); repo = g_object_new (BZ_TYPE_REPOSITORY, "name", flatpak_remote_get_name (remote), "title", flatpak_remote_get_title (remote), "url", flatpak_remote_get_url (remote), "is-user", TRUE, NULL); g_list_store_append (repos, repo); } } return dex_future_new_for_object (g_steal_pointer (&repos)); } static DexFuture * transaction_fiber (TransactionData *data) { g_autoptr (BzFlatpakInstance) self = NULL; GCancellable *cancellable = data->cancellable; GPtrArray *installations = data->installs; GPtrArray *updates = data->updates; GPtrArray *removals = data->removals; DexChannel *channel = data->channel; g_autoptr (GError) local_error = NULL; gboolean result = FALSE; g_autoptr (GPtrArray) transactions = NULL; g_autoptr (GPtrArray) entries = NULL; g_autoptr (GPtrArray) jobs = NULL; g_autoptr (GHashTable) errored = NULL; bz_weak_get_or_return_reject (self, data->self); transactions = g_ptr_array_new_with_free_func (g_object_unref); entries = g_ptr_array_new_with_free_func (g_object_unref); if (installations != NULL) { for (guint i = 0; i < installations->len; i++) { BzFlatpakEntry *entry = NULL; FlatpakRef *ref = NULL; gboolean is_user = FALSE; g_autofree char *ref_fmt = NULL; g_autoptr (FlatpakTransaction) transaction = NULL; entry = g_ptr_array_index (installations, i); ref = bz_flatpak_entry_get_ref (entry); is_user = bz_flatpak_entry_is_user (BZ_FLATPAK_ENTRY (entry)); ref_fmt = flatpak_ref_format_ref (ref); if ((is_user && self->user == NULL) || (!is_user && self->system == NULL)) { dex_channel_close_send (channel); return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_TRANSACTION_FAILURE, "Failed to append the update of %s to transaction " "because its installation couldn't be found", ref_fmt); } transaction = flatpak_transaction_new_for_installation ( is_user ? self->user : self->system, cancellable, &local_error); if (transaction == NULL) { dex_channel_close_send (channel); return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_TRANSACTION_FAILURE, "Failed to initialize potential transaction for installation: %s", local_error->message); } result = flatpak_transaction_add_install ( transaction, bz_entry_get_remote_repo_name (BZ_ENTRY (entry)), ref_fmt, NULL, &local_error); if (!result) { dex_channel_close_send (channel); return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_TRANSACTION_FAILURE, "Failed to append the installation of %s to transaction: %s", ref_fmt, local_error->message); } g_ptr_array_add (transactions, g_steal_pointer (&transaction)); g_ptr_array_add (entries, g_object_ref (entry)); g_hash_table_replace (data->ref_to_entry_hash, g_steal_pointer (&ref_fmt), g_object_ref (entry)); } } if (updates != NULL) { g_autoptr (FlatpakTransaction) user_transaction = NULL; g_autoptr (FlatpakTransaction) sys_transaction = NULL; for (guint i = 0; i < updates->len; i++) { BzFlatpakEntry *entry = NULL; FlatpakRef *ref = NULL; gboolean is_user = FALSE; g_autofree char *ref_fmt = NULL; entry = g_ptr_array_index (updates, i); ref = bz_flatpak_entry_get_ref (entry); is_user = bz_flatpak_entry_is_user (BZ_FLATPAK_ENTRY (entry)); ref_fmt = flatpak_ref_format_ref (ref); if ((is_user && self->user == NULL) || (!is_user && self->system == NULL)) { dex_channel_close_send (channel); return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_TRANSACTION_FAILURE, "Failed to append the update of %s to transaction " "because its installation couldn't be found", ref_fmt); } if (is_user && user_transaction == NULL) user_transaction = flatpak_transaction_new_for_installation ( self->user, cancellable, &local_error); else if (!is_user && sys_transaction == NULL) sys_transaction = flatpak_transaction_new_for_installation ( self->system, cancellable, &local_error); if ((is_user && user_transaction == NULL) || (!is_user && sys_transaction == NULL)) { dex_channel_close_send (channel); return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_TRANSACTION_FAILURE, "Failed to initialize potential transaction for installation: %s", local_error->message); } /* Put updates in one transaction to prevent dependency race-conditions, since the update list is most likely coming from this instance */ result = flatpak_transaction_add_update ( is_user ? user_transaction : sys_transaction, ref_fmt, NULL, NULL, &local_error); if (!result) { dex_channel_close_send (channel); return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_TRANSACTION_FAILURE, "Failed to append the update of %s to transaction: %s", ref_fmt, local_error->message); } g_ptr_array_add (entries, g_object_ref (entry)); g_hash_table_replace (data->ref_to_entry_hash, g_steal_pointer (&ref_fmt), g_object_ref (entry)); } if (user_transaction != NULL) g_ptr_array_add (transactions, g_steal_pointer (&user_transaction)); if (sys_transaction != NULL) g_ptr_array_add (transactions, g_steal_pointer (&sys_transaction)); } if (removals != NULL) { for (guint i = 0; i < removals->len; i++) { BzFlatpakEntry *entry = NULL; FlatpakRef *ref = NULL; gboolean is_user = FALSE; g_autofree char *ref_fmt = NULL; g_autoptr (FlatpakTransaction) transaction = NULL; entry = g_ptr_array_index (removals, i); ref = bz_flatpak_entry_get_ref (entry); is_user = bz_flatpak_entry_is_user (BZ_FLATPAK_ENTRY (entry)); ref_fmt = flatpak_ref_format_ref (ref); if ((is_user && self->user == NULL) || (!is_user && self->system == NULL)) { dex_channel_close_send (channel); return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_TRANSACTION_FAILURE, "Failed to append the removal of %s to transaction " "because its installation couldn't be found", ref_fmt); } transaction = flatpak_transaction_new_for_installation ( is_user ? self->user : self->system, cancellable, &local_error); if (transaction == NULL) { dex_channel_close_send (channel); return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_TRANSACTION_FAILURE, "Failed to initialize potential transaction for installation: %s", local_error->message); } result = flatpak_transaction_add_uninstall ( transaction, ref_fmt, &local_error); if (!result) { dex_channel_close_send (channel); return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_TRANSACTION_FAILURE, "Failed to append the removal of %s to transaction: %s", ref_fmt, local_error->message); } g_ptr_array_add (transactions, g_steal_pointer (&transaction)); g_ptr_array_add (entries, g_object_ref (entry)); g_hash_table_replace (data->ref_to_entry_hash, g_steal_pointer (&ref_fmt), g_object_ref (entry)); } } g_mutex_lock (&self->transactions_mutex); #define REGISTER_CANCELLABLES(entry) \ G_STMT_START \ { \ GPtrArray *cancellables = NULL; \ \ cancellables = g_hash_table_lookup (self->ongoing_cancellables, entry); \ if (cancellables != NULL) \ g_ptr_array_add (cancellables, g_object_ref (cancellable)); \ else \ { \ cancellables = g_ptr_array_new_with_free_func (g_object_unref); \ g_ptr_array_add (cancellables, g_object_ref (cancellable)); \ g_hash_table_replace (self->ongoing_cancellables, g_object_ref (entry), cancellables); \ } \ } \ G_STMT_END if (installations != NULL) { for (guint i = 0; i < installations->len; i++) { BzEntry *entry = NULL; entry = g_ptr_array_index (installations, i); REGISTER_CANCELLABLES (entry); } } if (removals != NULL) { for (guint i = 0; i < removals->len; i++) { BzEntry *entry = NULL; entry = g_ptr_array_index (removals, i); REGISTER_CANCELLABLES (entry); } } if (updates != NULL) { for (guint i = 0; i < updates->len; i++) { BzEntry *entry = NULL; entry = g_ptr_array_index (updates, i); REGISTER_CANCELLABLES (entry); } } #undef REGISTER_CANCELLABLES g_mutex_unlock (&self->transactions_mutex); jobs = g_ptr_array_new_with_free_func (dex_unref); for (guint i = 0; i < transactions->len; i++) { FlatpakTransaction *transaction = NULL; g_autoptr (TransactionJobData) job_data = NULL; transaction = g_ptr_array_index (transactions, i); job_data = transaction_job_data_new (); job_data->parent = transaction_data_ref (data); job_data->transaction = g_object_ref (transaction); g_ptr_array_add ( jobs, dex_scheduler_spawn ( self->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) transaction_job_fiber, transaction_job_data_ref (job_data), transaction_job_data_unref)); } dex_await (dex_future_all_racev ( (DexFuture *const *) jobs->pdata, jobs->len), NULL); g_mutex_lock (&self->transactions_mutex); #define UNREGISTER_CANCELLABLES(entry) \ G_STMT_START \ { \ GPtrArray *cancellables = NULL; \ \ cancellables = g_hash_table_lookup (self->ongoing_cancellables, entry); \ if (cancellables != NULL) \ { \ g_ptr_array_remove (cancellables, cancellable); \ if (cancellables->len == 0) \ g_hash_table_remove (self->ongoing_cancellables, entry); \ } \ } \ G_STMT_END if (installations != NULL) { for (guint i = 0; i < installations->len; i++) { BzEntry *entry = NULL; entry = g_ptr_array_index (installations, i); UNREGISTER_CANCELLABLES (entry); } } if (removals != NULL) { for (guint i = 0; i < removals->len; i++) { BzEntry *entry = NULL; entry = g_ptr_array_index (removals, i); UNREGISTER_CANCELLABLES (entry); } } if (updates != NULL) { for (guint i = 0; i < updates->len; i++) { BzEntry *entry = NULL; entry = g_ptr_array_index (updates, i); UNREGISTER_CANCELLABLES (entry); } } #undef UNREGISTER_CANCELLABLES g_mutex_unlock (&self->transactions_mutex); if (data->send_futures->len > 0) dex_await (dex_future_allv ( (DexFuture *const *) data->send_futures->pdata, data->send_futures->len), NULL); errored = g_hash_table_new_full ( g_direct_hash, g_direct_equal, g_object_unref, (GDestroyNotify) g_error_free); for (guint i = 0; i < jobs->len; i++) { DexFuture *job = NULL; BzEntry *entry = NULL; job = g_ptr_array_index (jobs, i); entry = g_ptr_array_index (entries, i); dex_future_get_value (job, &local_error); if (local_error != NULL) g_hash_table_replace ( errored, g_object_ref (entry), g_steal_pointer (&local_error)); } dex_channel_close_send (channel); return dex_future_new_take_boxed (G_TYPE_HASH_TABLE, g_steal_pointer (&errored)); } static DexFuture * transaction_job_fiber (TransactionJobData *data) { TransactionData *parent = data->parent; FlatpakTransaction *transaction = data->transaction; GCancellable *cancellable = parent->cancellable; g_autoptr (GError) local_error = NULL; gboolean result = FALSE; g_signal_connect (transaction, "new-operation", G_CALLBACK (transaction_new_operation), parent); g_signal_connect (transaction, "operation-done", G_CALLBACK (transaction_operation_done), parent); g_signal_connect (transaction, "operation-error", G_CALLBACK (transaction_operation_error), parent); g_signal_connect (transaction, "ready", G_CALLBACK (transaction_ready), parent); result = flatpak_transaction_run (transaction, cancellable, &local_error); if (!result) return dex_future_new_reject ( BZ_FLATPAK_ERROR, BZ_FLATPAK_ERROR_TRANSACTION_FAILURE, "Failed to run flatpak transaction on installation: %s", local_error->message); return dex_future_new_true (); } static void transaction_new_operation (FlatpakTransaction *transaction, FlatpakTransactionOperation *operation, FlatpakTransactionProgress *progress, TransactionData *data) { g_autoptr (BzFlatpakInstance) self = NULL; FlatpakTransactionOperationType kind = 0; BzFlatpakEntry *entry = NULL; g_autoptr (BzBackendTransactionOpPayload) payload = NULL; g_autoptr (TransactionOperationData) operation_data = NULL; bz_weak_get_or_return (self, data->self); kind = flatpak_transaction_operation_get_operation_type (operation); if (kind == FLATPAK_TRANSACTION_OPERATION_INSTALL || kind == FLATPAK_TRANSACTION_OPERATION_UPDATE || kind == FLATPAK_TRANSACTION_OPERATION_INSTALL_BUNDLE || kind == FLATPAK_TRANSACTION_OPERATION_UNINSTALL) { g_mutex_lock (&self->mute_mutex); if (self->user == flatpak_transaction_get_installation (transaction)) self->user_mute++; else self->system_mute++; g_mutex_unlock (&self->mute_mutex); } if (data->channel == NULL) return; flatpak_transaction_progress_set_update_frequency (progress, 100); entry = find_entry_from_operation (data, operation); payload = bz_backend_transaction_op_payload_new (); bz_backend_transaction_op_payload_set_entry ( payload, BZ_ENTRY (entry)); bz_backend_transaction_op_payload_set_name ( payload, flatpak_transaction_operation_get_ref (operation)); bz_backend_transaction_op_payload_set_download_size ( payload, flatpak_transaction_operation_get_download_size (operation)); bz_backend_transaction_op_payload_set_installed_size ( payload, flatpak_transaction_operation_get_installed_size (operation)); g_mutex_lock (&data->mutex); g_ptr_array_add ( data->send_futures, dex_channel_send ( data->channel, dex_future_new_for_object (payload))); data->unidentified_op_cnt--; g_mutex_unlock (&data->mutex); g_object_set_data_full ( G_OBJECT (operation), "payload", g_object_ref (payload), g_object_unref); operation_data = transaction_operation_data_new (); operation_data->parent = transaction_data_ref (data); operation_data->entry = bz_object_maybe_ref (entry); operation_data->op = g_object_ref (payload); g_signal_connect_data ( progress, "changed", G_CALLBACK (transaction_progress_changed), transaction_operation_data_ref (operation_data), transaction_operation_data_unref_closure, G_CONNECT_DEFAULT); } static void transaction_operation_done (FlatpakTransaction *transaction, FlatpakTransactionOperation *operation, gchar *commit, gint result, TransactionData *data) { g_autoptr (BzFlatpakInstance) self = NULL; g_autoptr (BzBackendTransactionOpPayload) payload = NULL; FlatpakTransactionOperationType op_type = 0; BzBackendNotificationKind notif_kind = 0; const char *origin = NULL; const char *ref = NULL; gboolean is_user = FALSE; g_autofree char *unique_id = NULL; g_autoptr (BzBackendNotification) notif = NULL; const char *version = NULL; FlatpakInstallation *installation = NULL; g_autoptr (FlatpakInstalledRef) iref = NULL; g_autoptr (GError) local_error = NULL; g_autoptr (FlatpakRef) parsed_ref = NULL; bz_weak_get_or_return (self, data->self); g_mutex_lock (&data->mutex); g_hash_table_replace ( data->op_to_progress_hash, g_object_ref (operation), GINT_TO_POINTER (100)); payload = g_object_steal_data (G_OBJECT (operation), "payload"); if (payload != NULL) g_ptr_array_add ( data->send_futures, dex_channel_send ( data->channel, dex_future_new_for_object (payload))); g_mutex_unlock (&data->mutex); if (result == FLATPAK_TRANSACTION_RESULT_NO_CHANGE) return; op_type = flatpak_transaction_operation_get_operation_type (operation); switch (op_type) { case FLATPAK_TRANSACTION_OPERATION_INSTALL: case FLATPAK_TRANSACTION_OPERATION_INSTALL_BUNDLE: notif_kind = BZ_BACKEND_NOTIFICATION_KIND_INSTALL_DONE; break; case FLATPAK_TRANSACTION_OPERATION_UPDATE: notif_kind = BZ_BACKEND_NOTIFICATION_KIND_UPDATE_DONE; break; case FLATPAK_TRANSACTION_OPERATION_UNINSTALL: notif_kind = BZ_BACKEND_NOTIFICATION_KIND_REMOVE_DONE; break; case FLATPAK_TRANSACTION_OPERATION_LAST_TYPE: default: g_assert_not_reached (); } origin = flatpak_transaction_operation_get_remote (operation); ref = flatpak_transaction_operation_get_ref (operation); is_user = flatpak_transaction_get_installation (transaction) == self->user; unique_id = bz_flatpak_ref_parts_format_unique (origin, ref, is_user); if (notif_kind == BZ_BACKEND_NOTIFICATION_KIND_INSTALL_DONE || notif_kind == BZ_BACKEND_NOTIFICATION_KIND_UPDATE_DONE) { installation = flatpak_transaction_get_installation (transaction); parsed_ref = flatpak_ref_parse (ref, &local_error); if (parsed_ref != NULL) { iref = flatpak_installation_get_installed_ref ( installation, flatpak_ref_get_kind (parsed_ref), flatpak_ref_get_name (parsed_ref), flatpak_ref_get_arch (parsed_ref), flatpak_ref_get_branch (parsed_ref), NULL, &local_error); if (iref != NULL) version = flatpak_installed_ref_get_appdata_version (iref); else if (local_error != NULL) { g_warning ("Failed to get installed ref for version: %s", local_error->message); g_clear_error (&local_error); } } else if (local_error != NULL) { g_warning ("Failed to parse ref for version: %s", local_error->message); g_clear_error (&local_error); } } notif = bz_backend_notification_new (); bz_backend_notification_set_kind (notif, notif_kind); bz_backend_notification_set_unique_id (notif, unique_id); if (version != NULL && *version != '\0') bz_backend_notification_set_version (notif, version); send_notif_all (self, notif, TRUE); } static gboolean transaction_operation_error (FlatpakTransaction *object, FlatpakTransactionOperation *operation, GError *error, gint details, TransactionData *data) { g_autoptr (BzBackendTransactionOpPayload) payload = NULL; /* `FLATPAK_TRANSACTION_ERROR_DETAILS_NON_FATAL` is the only possible value of `details` */ g_warning ("Transaction failed to complete: %s", error->message); g_mutex_lock (&data->mutex); g_hash_table_replace ( data->op_to_progress_hash, g_object_ref (operation), GINT_TO_POINTER (100)); payload = g_object_steal_data (G_OBJECT (operation), "payload"); if (payload != NULL) { g_object_set_data_full ( G_OBJECT (payload), "error", g_strdup (error->message), g_free); g_ptr_array_add ( data->send_futures, dex_channel_send ( data->channel, dex_future_new_for_object (payload))); } g_mutex_unlock (&data->mutex); /* Don't recover for now */ return FALSE; } static gboolean transaction_ready (FlatpakTransaction *object, TransactionData *data) { g_autolist (GObject) operations = NULL; operations = flatpak_transaction_get_operations (object); g_mutex_lock (&data->mutex); data->unidentified_op_cnt += g_list_length (operations); g_mutex_unlock (&data->mutex); return TRUE; } static BzFlatpakEntry * find_entry_from_operation (TransactionData *data, FlatpakTransactionOperation *operation) { GPtrArray *related_to_ops = NULL; const char *ref_fmt = NULL; BzFlatpakEntry *entry = NULL; related_to_ops = flatpak_transaction_operation_get_related_to_ops (operation); ref_fmt = flatpak_transaction_operation_get_ref (operation); entry = g_hash_table_lookup (data->ref_to_entry_hash, ref_fmt); if (entry != NULL) return entry; if (related_to_ops != NULL) { for (guint i = 0; i < related_to_ops->len; i++) { FlatpakTransactionOperation *related_op = NULL; related_op = g_ptr_array_index (related_to_ops, i); entry = find_entry_from_operation (data, related_op); if (entry != NULL) break; } } return entry; } static void transaction_progress_changed (FlatpakTransactionProgress *progress, TransactionOperationData *data) { TransactionData *parent = data->parent; g_autoptr (BzBackendTransactionOpProgressPayload) payload = NULL; int int_progress = 0; double double_progress = 0.0; GHashTableIter iter = { 0 }; int progress_sum = 0; guint n_ops = 0; double total_progress = 0.0; g_mutex_lock (&parent->mutex); int_progress = flatpak_transaction_progress_get_progress (progress); double_progress = (double) flatpak_transaction_progress_get_progress (progress) / 100.0; g_hash_table_replace ( parent->op_to_progress_hash, g_object_ref (data->op), GINT_TO_POINTER (int_progress)); g_hash_table_iter_init (&iter, parent->op_to_progress_hash); for (;;) { gpointer key = NULL; gpointer val = NULL; if (!g_hash_table_iter_next (&iter, &key, &val)) break; progress_sum += GPOINTER_TO_INT (val); n_ops++; } total_progress = MIN ((double) progress_sum / (double) ((n_ops + parent->unidentified_op_cnt) * 100), 1.0); payload = bz_backend_transaction_op_progress_payload_new (); bz_backend_transaction_op_progress_payload_set_op ( payload, data->op); bz_backend_transaction_op_progress_payload_set_status ( payload, flatpak_transaction_progress_get_status (progress)); bz_backend_transaction_op_progress_payload_set_is_estimating ( payload, flatpak_transaction_progress_get_is_estimating (progress)); bz_backend_transaction_op_progress_payload_set_progress ( payload, double_progress); bz_backend_transaction_op_progress_payload_set_total_progress ( payload, total_progress); bz_backend_transaction_op_progress_payload_set_bytes_transferred ( payload, flatpak_transaction_progress_get_bytes_transferred (progress)); bz_backend_transaction_op_progress_payload_set_start_time ( payload, flatpak_transaction_progress_get_start_time (progress)); g_ptr_array_add ( data->parent->send_futures, dex_channel_send ( data->parent->channel, dex_future_new_for_object (payload))); g_mutex_unlock (&parent->mutex); } static void installation_event (BzFlatpakInstance *self, GFile *file, GFile *other_file, GFileMonitorEvent event_type, GFileMonitor *monitor) { gboolean emit = FALSE; g_autoptr (BzBackendNotification) notif = NULL; g_mutex_lock (&self->mute_mutex); if (monitor == self->user_events) { if (self->user_mute > 0) self->user_mute--; else emit = TRUE; } else { if (self->system_mute > 0) self->system_mute--; else emit = TRUE; } g_mutex_unlock (&self->mute_mutex); if (!emit) return; notif = bz_backend_notification_new (); bz_backend_notification_set_kind (notif, BZ_BACKEND_NOTIFICATION_KIND_EXTERNAL_CHANGE); send_notif_all (self, notif, TRUE); } static void send_notif (BzFlatpakInstance *self, DexChannel *channel, BzBackendNotification *notif, gboolean lock) { g_autoptr (GMutexLocker) locker = NULL; if (lock) locker = g_mutex_locker_new (&self->notif_mutex); if (self->notif_send == NULL || !dex_future_is_pending (self->notif_send)) { dex_clear (&self->notif_send); self->notif_send = dex_channel_send ( channel, dex_future_new_for_object (notif)); } else { g_autoptr (WaitNotifData) data = NULL; data = wait_notif_data_new (); g_weak_ref_init (&data->self, self); data->channel = dex_ref (channel); data->notif = g_object_ref (notif); self->notif_send = dex_future_finally ( g_steal_pointer (&self->notif_send), (DexFutureCallback) wait_notif_finally, wait_notif_data_ref (data), wait_notif_data_unref); } } static void send_notif_all (BzFlatpakInstance *self, BzBackendNotification *notif, gboolean lock) { g_autoptr (GMutexLocker) locker = NULL; if (lock) locker = g_mutex_locker_new (&self->notif_mutex); for (guint i = 0; i < self->notif_channels->len;) { DexChannel *channel = NULL; channel = g_ptr_array_index (self->notif_channels, i); if (dex_channel_can_send (channel)) { send_notif (self, channel, notif, FALSE); i++; } else g_ptr_array_remove_index_fast (self->notif_channels, i); } } static DexFuture * wait_notif_finally (DexFuture *future, WaitNotifData *data) { g_autoptr (BzFlatpakInstance) self = NULL; g_autoptr (GMutexLocker) locker = NULL; bz_weak_get_or_return_reject (self, &data->self); locker = g_mutex_locker_new (&self->notif_mutex); if (future == self->notif_send) dex_clear (&self->notif_send); send_notif (self, data->channel, data->notif, FALSE); return dex_future_new_true (); } static gint cmp_rref (FlatpakRemoteRef *a, FlatpakRemoteRef *b, GHashTable *hash) { FlatpakRefKind a_fkind = 0; FlatpakRefKind b_fkind = 0; AsComponent *a_comp = NULL; AsComponent *b_comp = NULL; AsComponentKind a_kind = AS_COMPONENT_KIND_UNKNOWN; AsComponentKind b_kind = AS_COMPONENT_KIND_UNKNOWN; a_fkind = flatpak_ref_get_kind (FLATPAK_REF (a)); b_fkind = flatpak_ref_get_kind (FLATPAK_REF (b)); a_comp = g_hash_table_lookup (hash, flatpak_ref_get_name (FLATPAK_REF (a))); b_comp = g_hash_table_lookup (hash, flatpak_ref_get_name (FLATPAK_REF (b))); if (a_comp == NULL) return a_fkind == FLATPAK_REF_KIND_RUNTIME ? -1 : 1; if (b_comp == NULL) return b_fkind == FLATPAK_REF_KIND_RUNTIME ? 1 : -1; a_kind = as_component_get_kind (a_comp); b_kind = as_component_get_kind (b_comp); if (a_kind == AS_COMPONENT_KIND_RUNTIME) return -1; if (b_kind == AS_COMPONENT_KIND_RUNTIME) return 1; if (a_kind == AS_COMPONENT_KIND_ADDON) return -1; if (b_kind == AS_COMPONENT_KIND_ADDON) return 1; if (a_kind == AS_COMPONENT_KIND_DESKTOP_APP || a_kind == AS_COMPONENT_KIND_CONSOLE_APP || a_kind == AS_COMPONENT_KIND_WEB_APP) return 1; if (b_kind == AS_COMPONENT_KIND_DESKTOP_APP || b_kind == AS_COMPONENT_KIND_CONSOLE_APP || b_kind == AS_COMPONENT_KIND_WEB_APP) return -1; return 0; } static AsComponent * parse_component_for_node (XbNode *node, GError **error) { g_autofree char *component_xml = NULL; g_autoptr (AsMetadata) metadata = NULL; AsComponent *component = NULL; gboolean result = FALSE; component_xml = xb_node_export (node, XB_NODE_EXPORT_FLAG_NONE, error); if (component_xml == NULL) return NULL; metadata = as_metadata_new (); result = as_metadata_parse_data ( metadata, component_xml, -1, AS_FORMAT_KIND_XML, error); if (!result) return NULL; component = as_metadata_get_component (metadata); return bz_object_maybe_ref (component); } static GBytes * decompress_appstream_gz (GBytes *appstream_gz, GCancellable *cancellable, GError **error) { g_autoptr (GZlibDecompressor) decompressor = NULL; g_autoptr (GInputStream) stream_gz = NULL; g_autoptr (GInputStream) stream_data = NULL; g_autoptr (GBytes) appstream = NULL; decompressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP); stream_gz = g_memory_input_stream_new_from_bytes (appstream_gz); stream_data = g_converter_input_stream_new (stream_gz, G_CONVERTER (decompressor)); appstream = g_input_stream_read_bytes ( stream_data, 0x100000, /* 1MB */ cancellable, error); if (appstream == NULL) return NULL; return g_steal_pointer (&appstream); } static XbSilo * build_silo (XbBuilderSource *source, GCancellable *cancellable, GError **error) { g_autoptr (XbBuilder) builder = NULL; const gchar *const *locales = NULL; g_autoptr (XbSilo) silo = NULL; builder = xb_builder_new (); locales = g_get_language_names (); for (guint i = 0; locales[i] != NULL; i++) xb_builder_add_locale (builder, locales[i]); xb_builder_import_source (builder, source); silo = xb_builder_compile ( builder, XB_BUILDER_COMPILE_FLAG_NATIVE_LANGS, cancellable, error); return g_steal_pointer (&silo); } static AsComponent * extract_first_component_for_silo (XbSilo *silo, GError **error) { g_autoptr (XbNode) root = NULL; g_autoptr (GPtrArray) children = NULL; root = xb_silo_get_root (silo); children = xb_node_get_children (root); if (children == NULL || children->len == 0) return NULL; return parse_component_for_node ( g_ptr_array_index (children, 0), error); } bazaar-orig-v0.7.14/src/bz-context-tile.blp0000664000175000017500000000130015166123241017450 0ustar hasanhasanusing Gtk 4.0; template $BzContextTile: Button { styles [ "context-tile", "flat", ] focusable: false; halign: center; Box { orientation: vertical; spacing: 4; hexpand: true; Button ring_button { styles [ "lozenge-ring-button", ] halign: center; valign: center; margin-bottom: 4; child: Box lozenge { styles [ "lozenge", ] halign: center; }; accessibility { described-by: label; } } Label label { styles [ "context-tile-text", ] justify: center; wrap: true; wrap-mode: word_char; xalign: 0.5; } } } bazaar-orig-v0.7.14/src/bz-entry-selection-row.c0000664000175000017500000001146215166123241020441 0ustar hasanhasan/* bz-entry-selection-row.c * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include "bz-entry-selection-row.h" #include "bz-flatpak-entry.h" #include "bz-template-callbacks.h" struct _BzEntrySelectionRow { AdwActionRow parent_instance; GtkCheckButton *radio; BzFlatpakEntry *entry; BzRepository *repository; }; G_DEFINE_FINAL_TYPE (BzEntrySelectionRow, bz_entry_selection_row, ADW_TYPE_ACTION_ROW) enum { PROP_0, PROP_ENTRY, PROP_REPOSITORY, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bz_entry_selection_row_dispose (GObject *object) { BzEntrySelectionRow *self = BZ_ENTRY_SELECTION_ROW (object); g_clear_object (&self->entry); g_clear_object (&self->repository); G_OBJECT_CLASS (bz_entry_selection_row_parent_class)->dispose (object); } static void bz_entry_selection_row_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzEntrySelectionRow *self = BZ_ENTRY_SELECTION_ROW (object); switch (prop_id) { case PROP_ENTRY: g_value_set_object (value, self->entry); break; case PROP_REPOSITORY: g_value_set_object (value, self->repository); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_entry_selection_row_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzEntrySelectionRow *self = BZ_ENTRY_SELECTION_ROW (object); switch (prop_id) { case PROP_ENTRY: g_clear_object (&self->entry); self->entry = g_value_dup_object (value); break; case PROP_REPOSITORY: g_clear_object (&self->repository); self->repository = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static char * get_subtitle (gpointer object, const char *version, gboolean is_user) { const char *scope = is_user ? _ ("this user") : _ ("all users"); return g_strdup_printf ("%s • %s", version, scope); } static void bz_entry_selection_row_class_init (BzEntrySelectionRowClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_entry_selection_row_dispose; object_class->get_property = bz_entry_selection_row_get_property; object_class->set_property = bz_entry_selection_row_set_property; props[PROP_ENTRY] = g_param_spec_object ( "entry", NULL, NULL, BZ_TYPE_FLATPAK_ENTRY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); props[PROP_REPOSITORY] = g_param_spec_object ( "repository", NULL, NULL, BZ_TYPE_REPOSITORY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_REPOSITORY); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-entry-selection-row.ui"); bz_widget_class_bind_all_util_callbacks (widget_class); gtk_widget_class_bind_template_callback (widget_class, get_subtitle); gtk_widget_class_bind_template_child (widget_class, BzEntrySelectionRow, radio); } static void bz_entry_selection_row_init (BzEntrySelectionRow *self) { gtk_widget_init_template (GTK_WIDGET (self)); } BzEntrySelectionRow * bz_entry_selection_row_new (BzFlatpakEntry *entry, BzRepository *repository) { g_return_val_if_fail (BZ_IS_ENTRY (entry), NULL); return g_object_new (BZ_TYPE_ENTRY_SELECTION_ROW, "entry", entry, "repository", repository, NULL); } GtkCheckButton * bz_entry_selection_row_get_radio (BzEntrySelectionRow *self) { g_return_val_if_fail (BZ_IS_ENTRY_SELECTION_ROW (self), NULL); return self->radio; } bazaar-orig-v0.7.14/src/bz-error-dialog.h0000664000175000017500000000207015166123241017076 0ustar hasanhasan/* bz-error-dialog.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_ERROR_DIALOG (bz_error_dialog_get_type ()) G_DECLARE_FINAL_TYPE (BzErrorDialog, bz_error_dialog, BZ, ERROR_DIALOG, AdwDialog) BzErrorDialog *bz_error_dialog_new (const char *title, const char *text); G_END_DECLS bazaar-orig-v0.7.14/src/bz-share-list.c0000664000175000017500000001661115166123241016564 0ustar hasanhasan/* bz-share-list.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-share-list.h" #include "bz-url.h" #include "bz-window.h" #include struct _BzShareList { GtkBox parent_instance; GListModel *urls; AdwPreferencesGroup *group; }; G_DEFINE_FINAL_TYPE (BzShareList, bz_share_list, GTK_TYPE_BOX) enum { PROP_0, PROP_URLS, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void copy_cb (BzShareList *self, GtkButton *button) { const char *link = NULL; GdkClipboard *clipboard = NULL; AdwToast *toast = NULL; GtkWidget *ancestor = NULL; GtkRoot *root = NULL; link = g_object_get_data (G_OBJECT (button), "url"); clipboard = gdk_display_get_clipboard (gdk_display_get_default ()); gdk_clipboard_set_text (clipboard, link); toast = adw_toast_new (_ ("Copied!")); adw_toast_set_timeout (toast, 1); ancestor = gtk_widget_get_ancestor (GTK_WIDGET (self), ADW_TYPE_TOAST_OVERLAY); if (ancestor != NULL) { adw_toast_overlay_add_toast (ADW_TOAST_OVERLAY (ancestor), toast); return; } root = gtk_widget_get_root (GTK_WIDGET (self)); if (root != NULL && BZ_IS_WINDOW (root)) bz_window_add_toast (BZ_WINDOW (root), toast); } static void follow_link_cb (BzShareList *self, GtkButton *button) { const char *link = NULL; link = g_object_get_data (G_OBJECT (button), "url"); g_app_info_launch_default_for_uri (link, NULL, NULL); } static AdwActionRow * create_url_action_row (BzShareList *self, BzUrl *url_item) { g_autofree char *url_string = NULL; g_autofree char *url_title = NULL; g_autofree char *icon_name = NULL; AdwActionRow *action_row; GtkBox *suffix_box; GtkButton *copy_button; GtkButton *open_button; GtkSeparator *separator; GtkImage *prefix_icon; g_object_get (url_item, "url", &url_string, "name", &url_title, "icon-name", &icon_name, NULL); action_row = ADW_ACTION_ROW (adw_action_row_new ()); adw_preferences_row_set_use_markup (ADW_PREFERENCES_ROW (action_row), FALSE); adw_preferences_row_set_title (ADW_PREFERENCES_ROW (action_row), url_title ? url_title : url_string); adw_action_row_set_subtitle (action_row, url_string); if (icon_name != NULL && icon_name[0] != '\0') { prefix_icon = GTK_IMAGE (gtk_image_new_from_icon_name (icon_name)); gtk_image_set_icon_size (prefix_icon, GTK_ICON_SIZE_NORMAL); adw_action_row_add_prefix (action_row, GTK_WIDGET (prefix_icon)); } suffix_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4)); gtk_widget_set_valign (GTK_WIDGET (suffix_box), GTK_ALIGN_CENTER); copy_button = GTK_BUTTON (gtk_button_new_from_icon_name ("edit-copy-symbolic")); gtk_widget_set_tooltip_text (GTK_WIDGET (copy_button), _ ("Copy Link")); gtk_button_set_has_frame (copy_button, FALSE); g_object_set_data_full (G_OBJECT (copy_button), "url", g_strdup (url_string), g_free); g_signal_connect_swapped (copy_button, "clicked", G_CALLBACK (copy_cb), self); separator = GTK_SEPARATOR (gtk_separator_new (GTK_ORIENTATION_VERTICAL)); gtk_widget_set_margin_top (GTK_WIDGET (separator), 6); gtk_widget_set_margin_bottom (GTK_WIDGET (separator), 6); open_button = GTK_BUTTON (gtk_button_new_from_icon_name ("external-link-symbolic")); gtk_widget_set_tooltip_text (GTK_WIDGET (open_button), _ ("Open Link")); gtk_button_set_has_frame (open_button, FALSE); g_object_set_data_full (G_OBJECT (open_button), "url", g_strdup (url_string), g_free); g_signal_connect_swapped (open_button, "clicked", G_CALLBACK (follow_link_cb), self); gtk_box_append (suffix_box, GTK_WIDGET (copy_button)); gtk_box_append (suffix_box, GTK_WIDGET (separator)); gtk_box_append (suffix_box, GTK_WIDGET (open_button)); adw_action_row_add_suffix (action_row, GTK_WIDGET (suffix_box)); adw_action_row_set_activatable_widget (action_row, GTK_WIDGET (open_button)); adw_action_row_set_subtitle_lines (action_row, 1); return action_row; } static void populate_urls (BzShareList *self) { guint n_items = 0; if (self->group) { gtk_box_remove (GTK_BOX (self), GTK_WIDGET (self->group)); self->group = NULL; } self->group = ADW_PREFERENCES_GROUP (adw_preferences_group_new ()); gtk_box_append (GTK_BOX (self), GTK_WIDGET (self->group)); if (!self->urls) return; n_items = g_list_model_get_n_items (self->urls); for (guint i = 0; i < n_items; i++) { g_autoptr (BzUrl) url_item = NULL; AdwActionRow *action_row; url_item = g_list_model_get_item (self->urls, i); action_row = create_url_action_row (self, url_item); adw_preferences_group_add (self->group, GTK_WIDGET (action_row)); } } static void bz_share_list_dispose (GObject *object) { BzShareList *self = BZ_SHARE_LIST (object); g_clear_object (&self->urls); G_OBJECT_CLASS (bz_share_list_parent_class)->dispose (object); } static void bz_share_list_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzShareList *self = BZ_SHARE_LIST (object); switch (prop_id) { case PROP_URLS: g_value_set_object (value, self->urls); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_share_list_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzShareList *self = BZ_SHARE_LIST (object); switch (prop_id) { case PROP_URLS: g_clear_object (&self->urls); self->urls = g_value_dup_object (value); populate_urls (self); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_share_list_class_init (BzShareListClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = bz_share_list_dispose; object_class->get_property = bz_share_list_get_property; object_class->set_property = bz_share_list_set_property; props[PROP_URLS] = g_param_spec_object ( "urls", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_URL); } static void bz_share_list_init (BzShareList *self) { gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL); } GtkWidget * bz_share_list_new (void) { return g_object_new (BZ_TYPE_SHARE_LIST, NULL); } bazaar-orig-v0.7.14/src/bz-user-data-page.h0000664000175000017500000000207615166123241017315 0ustar hasanhasan/* bz-user-data-page.h * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-state-info.h" #include G_BEGIN_DECLS #define BZ_TYPE_USER_DATA_PAGE (bz_user_data_page_get_type ()) G_DECLARE_FINAL_TYPE (BzUserDataPage, bz_user_data_page, BZ, USER_DATA_PAGE, AdwNavigationPage) GtkWidget * bz_user_data_page_new (BzStateInfo *state); G_END_DECLS bazaar-orig-v0.7.14/src/bz-hardware-support-dialog.h0000664000175000017500000000217715166123241021264 0ustar hasanhasan/* bz-hardware-support-dialog.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry.h" #include #include G_BEGIN_DECLS #define BZ_TYPE_HARDWARE_SUPPORT_DIALOG (bz_hardware_support_dialog_get_type ()) G_DECLARE_FINAL_TYPE (BzHardwareSupportDialog, bz_hardware_support_dialog, BZ, HARDWARE_SUPPORT_DIALOG, AdwDialog) BzHardwareSupportDialog *bz_hardware_support_dialog_new (BzEntry *entry); G_END_DECLS bazaar-orig-v0.7.14/src/bz-transaction-tile.h0000664000175000017500000000251115166123241017770 0ustar hasanhasan/* bz-transaction-tile.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-transaction-entry-tracker.h" G_BEGIN_DECLS #define BZ_TYPE_TRANSACTION_TILE (bz_transaction_tile_get_type ()) G_DECLARE_FINAL_TYPE (BzTransactionTile, bz_transaction_tile, BZ, TRANSACTION_TILE, BzListTile) BzTransactionTile * bz_transaction_tile_new (void); BzTransactionEntryTracker * bz_transaction_tile_get_tracker (BzTransactionTile *self); void bz_transaction_tile_set_tracker (BzTransactionTile *self, BzTransactionEntryTracker *tracker); G_END_DECLS /* End of bz-transaction-tile.h */ bazaar-orig-v0.7.14/src/bz-developer-badge.c0000664000175000017500000003122515166123241017534 0ustar hasanhasan/* bz-developer-badge.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-developer-badge.h" #include "bz-verification-status.h" struct _BzDeveloperBadge { GtkBox parent_instance; BzEntry *entry; GtkLabel *developer_label; GtkMenuButton *info_button; GtkPopover *popover; GtkLabel *popover_label; }; G_DEFINE_FINAL_TYPE (BzDeveloperBadge, bz_developer_badge, GTK_TYPE_BOX) enum { PROP_0, PROP_ENTRY, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static gboolean is_null (gpointer object, GObject *value) { return value == NULL; } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static char * get_developer_name (gpointer object, GObject *entry) { if (entry == NULL || !BZ_IS_ENTRY (entry)) return NULL; return g_strdup (bz_entry_get_developer (BZ_ENTRY (entry))); } static char * get_icon_name (gpointer object, GObject *status) { gboolean verified = FALSE; if (status == NULL) return g_strdup ("info-outline-symbolic"); g_object_get (status, "verified", &verified, NULL); return g_strdup (verified ? "verified-checkmark-symbolic" : "info-outline-symbolic"); } static char * get_verified_tooltip (gpointer object, GObject *status) { gboolean verified = FALSE; if (status == NULL) return g_strdup (_ ("Not Verified")); g_object_get (status, "verified", &verified, NULL); return g_strdup (verified ? _ ("Verified") : _ ("Not Verified")); } static char * format_app_id (const char *app_id) { return g_strdup_printf ("%s", app_id); } static char * format_website_url (const char *website) { return g_strdup_printf ("%s", website, website, website); } static char * format_provider_name (const char *login_provider) { if (g_strcmp0 (login_provider, "github") == 0) return g_strdup ("GitHub"); else if (g_strcmp0 (login_provider, "gitlab") == 0) return g_strdup ("GitLab"); else if (g_strcmp0 (login_provider, "gnome") == 0) return g_strdup ("GNOME GitLab"); else if (g_strcmp0 (login_provider, "kde") == 0) return g_strdup ("KDE GitLab"); else return g_strdup (login_provider); } static char * format_provider_url (const char *login_provider, const char *login_name) { if (g_strcmp0 (login_provider, "github") == 0) return g_strdup_printf ("https://github.com/%s", login_name); else if (g_strcmp0 (login_provider, "gitlab") == 0) return g_strdup_printf ("https://gitlab.com/%s", login_name); else if (g_strcmp0 (login_provider, "gnome") == 0) return g_strdup_printf ("https://gitlab.gnome.org/%s", login_name); else if (g_strcmp0 (login_provider, "kde") == 0) return g_strdup_printf ("https://invent.kde.org/%s", login_name); else return NULL; } static char * get_developer_link (gpointer object, BzEntry *entry, BzVerificationStatus *status) { const char *dev = NULL; const char *method = NULL; const char *login_name = NULL; const char *login_provider = NULL; const char *website = NULL; gboolean verified = FALSE; g_autofree char *escaped_dev = NULL; if (entry == NULL || !BZ_IS_ENTRY (entry)) return NULL; dev = bz_entry_get_developer (entry); escaped_dev = g_markup_escape_text (dev, -1); if (status == NULL) return g_steal_pointer (&escaped_dev); g_object_get (status, "verified", &verified, "method", &method, "login-name", &login_name, "login-provider", &login_provider, "website", &website, NULL); if (!verified) return g_steal_pointer (&escaped_dev); if (g_strcmp0 (method, "login_provider") == 0 && login_name != NULL && login_provider != NULL) { g_autofree char *url = NULL; url = format_provider_url (login_provider, login_name); if (url != NULL) return g_strdup_printf ("%s", url, url, escaped_dev); } if (g_strcmp0 (method, "website") == 0 && website != NULL && *website != '\0') return g_strdup_printf ("%s", website, website, escaped_dev); return g_steal_pointer (&escaped_dev); } static char * get_popover_text (gpointer object, GObject *entry_obj, GObject *status_obj) { BzVerificationStatus *status = NULL; const char *app_id = NULL; const char *website = NULL; const char *method = NULL; const char *login_name = NULL; const char *login_provider = NULL; gboolean verified = FALSE; g_autofree char *formatted_app_id = NULL; g_autofree char *formatted_website = NULL; g_autofree char *provider_name = NULL; if (entry_obj == NULL || !BZ_IS_ENTRY (entry_obj)) return g_strdup (_ ("Developer information not available.")); app_id = bz_entry_get_id (BZ_ENTRY (entry_obj)); formatted_app_id = format_app_id (app_id); if (status_obj == NULL) return g_strdup_printf (_ ("The ownership of the %s app ID has not been verified and it may be a community package."), formatted_app_id); status = BZ_VERIFICATION_STATUS (status_obj); g_object_get (status, "verified", &verified, "method", &method, "website", &website, "login-name", &login_name, "login-provider", &login_provider, NULL); if (!verified) return g_strdup_printf (_ ("The ownership of the %s app ID has not been verified and it may be a community package."), formatted_app_id); if (g_strcmp0 (method, "manual") == 0) return g_strdup_printf (_ ("The ownership of the %s app ID has been manually verified by the Flathub team."), formatted_app_id); if (g_strcmp0 (method, "login_provider") == 0 && login_name != NULL && login_provider != NULL) { g_autofree char *url = NULL; g_autofree char *linked_name = NULL; provider_name = format_provider_name (login_provider); url = format_provider_url (login_provider, login_name); if (url != NULL) linked_name = g_strdup_printf ("%s", url, url, login_name); else linked_name = g_strdup (login_name); return g_strdup_printf (_ ("The ownership of the %1$s app ID has been verified by %2$s on %3$s."), formatted_app_id, linked_name, provider_name); } if (website != NULL && *website != '\0') { formatted_website = format_website_url (website); return g_strdup_printf (_ ("The ownership of the %1$s app ID has been verified using %2$s."), formatted_app_id, formatted_website); } return g_strdup_printf (_ ("The ownership of the %s app ID has been verified."), formatted_app_id); } static void on_info_button_enter (GtkEventControllerMotion *controller, gdouble x, gdouble y, gpointer user_data) { GtkWidget *widget = GTK_WIDGET (user_data); gtk_widget_set_cursor_from_name (widget, "pointer"); } static void on_info_button_leave (GtkEventControllerMotion *controller, gpointer user_data) { GtkWidget *widget = GTK_WIDGET (user_data); gtk_widget_set_cursor (widget, NULL); } static void bz_developer_badge_dispose (GObject *object) { BzDeveloperBadge *self = BZ_DEVELOPER_BADGE (object); g_clear_object (&self->entry); G_OBJECT_CLASS (bz_developer_badge_parent_class)->dispose (object); } static void bz_developer_badge_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzDeveloperBadge *self = BZ_DEVELOPER_BADGE (object); switch (prop_id) { case PROP_ENTRY: g_value_set_object (value, bz_developer_badge_get_entry (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_developer_badge_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzDeveloperBadge *self = BZ_DEVELOPER_BADGE (object); switch (prop_id) { case PROP_ENTRY: bz_developer_badge_set_entry (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_developer_badge_class_init (BzDeveloperBadgeClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_developer_badge_dispose; object_class->get_property = bz_developer_badge_get_property; object_class->set_property = bz_developer_badge_set_property; props[PROP_ENTRY] = g_param_spec_object ( "entry", NULL, NULL, BZ_TYPE_ENTRY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-developer-badge.ui"); gtk_widget_class_bind_template_child (widget_class, BzDeveloperBadge, developer_label); gtk_widget_class_bind_template_child (widget_class, BzDeveloperBadge, info_button); gtk_widget_class_bind_template_child (widget_class, BzDeveloperBadge, popover); gtk_widget_class_bind_template_child (widget_class, BzDeveloperBadge, popover_label); gtk_widget_class_bind_template_callback (widget_class, on_info_button_enter); gtk_widget_class_bind_template_callback (widget_class, on_info_button_leave); gtk_widget_class_bind_template_callback (widget_class, is_null); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, get_developer_name); gtk_widget_class_bind_template_callback (widget_class, get_developer_link); gtk_widget_class_bind_template_callback (widget_class, get_icon_name); gtk_widget_class_bind_template_callback (widget_class, get_verified_tooltip); gtk_widget_class_bind_template_callback (widget_class, get_popover_text); } static void bz_developer_badge_init (BzDeveloperBadge *self) { gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_developer_badge_new (void) { return g_object_new (BZ_TYPE_DEVELOPER_BADGE, NULL); } BzEntry * bz_developer_badge_get_entry (BzDeveloperBadge *self) { g_return_val_if_fail (BZ_IS_DEVELOPER_BADGE (self), NULL); return self->entry; } void bz_developer_badge_set_entry (BzDeveloperBadge *self, BzEntry *entry) { BzVerificationStatus *status = NULL; gboolean verified = FALSE; g_return_if_fail (BZ_IS_DEVELOPER_BADGE (self)); g_return_if_fail (entry == NULL || BZ_IS_ENTRY (entry)); if (g_set_object (&self->entry, entry)) { gtk_widget_remove_css_class (GTK_WIDGET (self), "verified"); gtk_widget_remove_css_class (GTK_WIDGET (self), "dimmed"); if (entry != NULL) { g_object_get (entry, "verification-status", &status, NULL); if (status != NULL) { g_object_get (status, "verified", &verified, NULL); g_object_unref (status); } gtk_widget_add_css_class (GTK_WIDGET (self), verified ? "verified" : "dimmed"); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ENTRY]); } } bazaar-orig-v0.7.14/src/bz-screenshots-carousel.blp0000664000175000017500000000510315166123241021211 0ustar hasanhasanusing Gtk 4.0; template $BzScreenshotsCarousel: Gtk.Widget { accessibility { label: _("Screenshots Carousel"); } styles [ "screenshot-carousel", "frame", "carousel-box", ] layout-manager: Gtk.BinLayout {}; Gtk.Overlay { halign: fill; valign: fill; child: Gtk.Box { orientation: vertical; halign: fill; valign: fill; $BgeCarousel carousel { vexpand: true; hexpand: true; valign: fill; height-request: bind $get_carousel_height(template.compact) as ; allow-mouse-drag: true; allow-overshoot: true; allow-scroll-wheel: true; allow-raise: bind $invert_boolean(template.compact) as ; create-widget => $on_create_widget(template); remove-widget => $on_remove_widget(template); model: SingleSelection selection { autoselect: true; model: bind template.model; notify::selected => $on_notify_selected(template); notify::n-items => $on_notify_n_items(template); }; } // $BzCarouselIndicatorDots carousel_indicator { // carousel: carousel; // opacity: 0; // hexpand: true; // halign: center; // // styles [ // "boxed-indicator", // "indicator-box", // ] // } }; [overlay] Gtk.Revealer prev_button_revealer { transition-type: crossfade; reveal-child: false; halign: start; valign: center; can-focus: false; Gtk.Button prev_button { icon-name: "go-previous-symbolic"; valign: center; halign: start; clicked => $on_prev_clicked() swapped; styles [ "circular", "osd", ] } } [overlay] Gtk.Revealer next_button_revealer { transition-type: crossfade; reveal-child: false; halign: end; valign: center; can-focus: false; Gtk.Button next_button { icon-name: "go-next-symbolic"; valign: center; clicked => $on_next_clicked() swapped; styles [ "circular", "osd", ] } } [overlay] Box { styles [ "osd-box", "pip-button", ] margin-end: 8; margin-bottom: 8; halign: end; valign: end; can-focus:false; Gtk.Button { icon-name: "pip-out-symbolic"; tooltip-text: _("Open Screenshot Viewer"); clicked => $on_expand_clicked() swapped; styles [ "flat", ] } } } } bazaar-orig-v0.7.14/src/bz-subcategory-list.c0000664000175000017500000002457315166123241020017 0ustar hasanhasan/* bz-subcategory-list.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include #include "bz-apps-page.h" #include "bz-flathub-state.h" #include "bz-flathub-sub-category.h" #include "bz-subcategory-list.h" #include "bz-util.h" #include "bz-window.h" struct _BzSubcategoryList { GtkBox parent_instance; BzFlathubCategory *category; BzFlathubState *flathub_state; DexFuture *task; }; G_DEFINE_FINAL_TYPE (BzSubcategoryList, bz_subcategory_list, GTK_TYPE_BOX); enum { PROP_0, PROP_CATEGORY, PROP_FLATHUB_STATE, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static DexFuture * search_finally (DexFuture *future, GWeakRef *wr) { g_autoptr (BzSubcategoryList) self = NULL; g_autoptr (GError) local_error = NULL; GtkRoot *root = NULL; const GValue *value = NULL; bz_weak_get_or_return_reject (self, wr); root = gtk_widget_get_root (GTK_WIDGET (self)); value = dex_future_get_value (future, &local_error); if (value != NULL) { GListModel *model = NULL; guint n_items = 0; model = g_value_get_object (value); n_items = g_list_model_get_n_items (model); if (n_items <= 1) { AdwToast *toast = adw_toast_new (_ ("No Results Found")); bz_window_add_toast (BZ_WINDOW (root), toast); } else { const char *subcategory_name = NULL; g_autofree char *subtitle = NULL; AdwNavigationPage *apps_page = NULL; GtkWidget *nav_view = NULL; subcategory_name = g_object_get_data (G_OBJECT (self), "current-subcategory"); subtitle = g_strdup_printf (_ ("%d Applications"), n_items); apps_page = bz_apps_page_new (subcategory_name, model); bz_apps_page_set_subtitle (BZ_APPS_PAGE (apps_page), subtitle); nav_view = gtk_widget_get_ancestor (GTK_WIDGET (self), ADW_TYPE_NAVIGATION_VIEW); adw_navigation_view_push (ADW_NAVIGATION_VIEW (nav_view), apps_page); } } else { AdwToast *toast = adw_toast_new (_ ("Search failed")); bz_window_add_toast (BZ_WINDOW (root), toast); g_warning ("Search failed: %s", local_error->message); } dex_clear (&self->task); return dex_future_new_true (); } static void subcategory_button_clicked_cb (BzSubcategoryList *self, GtkButton *button) { g_autoptr (DexFuture) future = NULL; const char *category = NULL; const char *label = NULL; g_autofree char *route = NULL; g_return_if_fail (BZ_IS_SUBCATEGORY_LIST (self)); g_return_if_fail (GTK_IS_BUTTON (button)); if (self->flathub_state == NULL) return; if (self->category == NULL) return; if (self->task != NULL) return; category = bz_flathub_category_get_name (self->category); if (category == NULL || *category == '\0') return; label = gtk_button_get_label (button); if (label == NULL || *label == '\0') return; g_object_set_data_full (G_OBJECT (self), "current-subcategory", g_strdup (label), g_free); route = g_strdup (g_object_get_data (G_OBJECT (button), "subcategory-id")); if (route == NULL) return; future = bz_flathub_state_search_collection (self->flathub_state, route); future = dex_future_finally ( future, (DexFutureCallback) search_finally, bz_track_weak (self), bz_weak_release); self->task = g_steal_pointer (&future); } static void rebuild_subcategories (BzSubcategoryList *self) { GtkWidget *child; GListModel *subcategories; guint n_items; dex_clear (&self->task); while ((child = gtk_widget_get_first_child (GTK_WIDGET (self))) != NULL) gtk_box_remove (GTK_BOX (self), child); if (self->category == NULL) { gtk_widget_set_visible (GTK_WIDGET (self), FALSE); return; } subcategories = bz_flathub_category_get_subcategories (self->category); if (subcategories == NULL) { gtk_widget_set_visible (GTK_WIDGET (self), FALSE); return; } n_items = g_list_model_get_n_items (subcategories); if (n_items == 0) { gtk_widget_set_visible (GTK_WIDGET (self), FALSE); return; } gtk_widget_set_visible (GTK_WIDGET (self), TRUE); for (guint i = 0; i < n_items; i++) { g_autoptr (BzFlathubSubCategory) subcategory = NULL; const char *label = NULL; const char *subcat_id = NULL; const char *category = NULL; g_autofree char *route = NULL; GtkWidget *button = NULL; subcategory = g_list_model_get_item (subcategories, i); if (subcategory == NULL) continue; label = bz_flathub_sub_category_get_name(subcategory); subcat_id = bz_flathub_sub_category_get_id(subcategory); category = bz_flathub_category_get_name (self->category); route = g_strdup_printf ("/collection/category/%s/subcategories?subcategory=%s", category, subcat_id); button = gtk_button_new_with_label (label); gtk_widget_add_css_class (button, "small-pill"); g_object_set_data_full (G_OBJECT (button), "subcategory-id", g_steal_pointer (&route), g_free); g_signal_connect_swapped (button, "clicked", G_CALLBACK (subcategory_button_clicked_cb), self); gtk_box_append (GTK_BOX (self), button); } } static void bz_subcategory_list_dispose (GObject *object) { BzSubcategoryList *self = BZ_SUBCATEGORY_LIST (object); dex_clear (&self->task); g_clear_object (&self->category); g_clear_object (&self->flathub_state); G_OBJECT_CLASS (bz_subcategory_list_parent_class)->dispose (object); } static void bz_subcategory_list_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzSubcategoryList *self = BZ_SUBCATEGORY_LIST (object); switch (prop_id) { case PROP_CATEGORY: g_value_set_object (value, bz_subcategory_list_get_category (self)); break; case PROP_FLATHUB_STATE: g_value_set_object (value, bz_subcategory_list_get_flathub_state (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_subcategory_list_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzSubcategoryList *self = BZ_SUBCATEGORY_LIST (object); switch (prop_id) { case PROP_CATEGORY: bz_subcategory_list_set_category (self, g_value_get_object (value)); break; case PROP_FLATHUB_STATE: bz_subcategory_list_set_flathub_state (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_subcategory_list_class_init (BzSubcategoryListClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bz_subcategory_list_set_property; object_class->get_property = bz_subcategory_list_get_property; object_class->dispose = bz_subcategory_list_dispose; props[PROP_CATEGORY] = g_param_spec_object ( "category", NULL, NULL, BZ_TYPE_FLATHUB_CATEGORY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_FLATHUB_STATE] = g_param_spec_object ( "flathub-state", NULL, NULL, BZ_TYPE_FLATHUB_STATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_subcategory_list_init (BzSubcategoryList *self) { GtkLayoutManager *layout; gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_HORIZONTAL); gtk_widget_set_visible (GTK_WIDGET (self), FALSE); layout = GTK_LAYOUT_MANAGER (adw_wrap_layout_new ()); adw_wrap_layout_set_child_spacing (ADW_WRAP_LAYOUT (layout), 8); adw_wrap_layout_set_line_spacing (ADW_WRAP_LAYOUT (layout), 8); gtk_widget_set_layout_manager (GTK_WIDGET (self), layout); } GtkWidget * bz_subcategory_list_new (void) { return g_object_new (BZ_TYPE_SUBCATEGORY_LIST, NULL); } BzFlathubCategory * bz_subcategory_list_get_category (BzSubcategoryList *self) { g_return_val_if_fail (BZ_IS_SUBCATEGORY_LIST (self), NULL); return self->category; } void bz_subcategory_list_set_category (BzSubcategoryList *self, BzFlathubCategory *category) { g_return_if_fail (BZ_IS_SUBCATEGORY_LIST (self)); g_return_if_fail (category == NULL || BZ_IS_FLATHUB_CATEGORY (category)); g_clear_object (&self->category); if (category != NULL) self->category = g_object_ref (category); rebuild_subcategories (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CATEGORY]); } BzFlathubState * bz_subcategory_list_get_flathub_state (BzSubcategoryList *self) { g_return_val_if_fail (BZ_IS_SUBCATEGORY_LIST (self), NULL); return self->flathub_state; } void bz_subcategory_list_set_flathub_state (BzSubcategoryList *self, BzFlathubState *flathub_state) { g_return_if_fail (BZ_IS_SUBCATEGORY_LIST (self)); g_return_if_fail (flathub_state == NULL || BZ_IS_FLATHUB_STATE (flathub_state)); g_clear_object (&self->flathub_state); if (flathub_state != NULL) self->flathub_state = g_object_ref (flathub_state); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_FLATHUB_STATE]); } bazaar-orig-v0.7.14/src/bz-user-data-page.c0000664000175000017500000002111615166123241017304 0ustar hasanhasan/* bz-user-data-page.c * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-application-map-factory.h" #include "bz-env.h" #include "bz-io.h" #include "bz-user-data-page.h" #include "bz-user-data-tile.h" #include "bz-util.h" struct _BzUserDataPage { AdwNavigationPage parent_instance; BzStateInfo *state; GListModel *model; /* Template widgets */ AdwViewStack *stack; }; G_DEFINE_FINAL_TYPE (BzUserDataPage, bz_user_data_page, ADW_TYPE_NAVIGATION_PAGE) enum { PROP_0, PROP_STATE, PROP_MODEL, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static DexFuture * fetch_user_data_fiber (GWeakRef *wr); static void items_changed (BzUserDataPage *self, guint position, guint removed, guint added, GListModel *model); static void set_page (BzUserDataPage *self); static void bz_user_data_page_dispose (GObject *object) { BzUserDataPage *self = BZ_USER_DATA_PAGE (object); if (self->model != NULL) g_signal_handlers_disconnect_by_func (self->model, items_changed, self); g_clear_object (&self->model); g_clear_object (&self->state); G_OBJECT_CLASS (bz_user_data_page_parent_class)->dispose (object); } static void bz_user_data_page_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzUserDataPage *self = BZ_USER_DATA_PAGE (object); switch (prop_id) { case PROP_STATE: g_value_set_object (value, self->state); break; case PROP_MODEL: g_value_set_object (value, self->model); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_user_data_page_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzUserDataPage *self = BZ_USER_DATA_PAGE (object); switch (prop_id) { case PROP_STATE: self->state = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_user_data_page_constructed (GObject *object) { BzUserDataPage *self = BZ_USER_DATA_PAGE (object); g_autoptr (DexFuture) future = NULL; G_OBJECT_CLASS (bz_user_data_page_parent_class)->constructed (object); future = dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) fetch_user_data_fiber, bz_track_weak (self), bz_weak_release); dex_future_disown (g_steal_pointer (&future)); } static gboolean is_zero (gpointer object, int value) { return value == 0; } static void bz_user_data_page_class_init (BzUserDataPageClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_user_data_page_dispose; object_class->constructed = bz_user_data_page_constructed; object_class->get_property = bz_user_data_page_get_property; object_class->set_property = bz_user_data_page_set_property; props[PROP_STATE] = g_param_spec_object ( "state", NULL, NULL, BZ_TYPE_STATE_INFO, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); props[PROP_MODEL] = g_param_spec_object ( "model", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_USER_DATA_TILE); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-user-data-page.ui"); gtk_widget_class_bind_template_child (widget_class, BzUserDataPage, stack); gtk_widget_class_bind_template_callback (widget_class, is_zero); } static void bz_user_data_page_init (BzUserDataPage *self) { gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_user_data_page_new (BzStateInfo *state) { return g_object_new (BZ_TYPE_USER_DATA_PAGE, "state", state, NULL); } static void items_changed (BzUserDataPage *self, guint position, guint removed, guint added, GListModel *model) { set_page (self); } static void set_page (BzUserDataPage *self) { if (self->model != NULL && g_list_model_get_n_items (G_LIST_MODEL (self->model)) > 0) adw_view_stack_set_visible_child_name (self->stack, "content"); else adw_view_stack_set_visible_child_name (self->stack, "empty"); } static int compare_entry_groups_by_title (BzEntryGroup *group_a, BzEntryGroup *group_b) { const char *title_a = bz_entry_group_get_title (group_a); const char *title_b = bz_entry_group_get_title (group_b); return g_utf8_collate (title_a, title_b); } static DexFuture * fetch_user_data_fiber (GWeakRef *wr) { g_autoptr (BzUserDataPage) self = NULL; g_autoptr (GHashTable) ids_hash = NULL; g_autoptr (GError) local_error = NULL; GHashTableIter iter = { 0 }; g_autoptr (GtkStringList) id_list = NULL; BzApplicationMapFactory *factory = NULL; g_autoptr (GListModel) model = NULL; g_autoptr (GListStore) sorted_store = NULL; GListModel *installed_groups = NULL; g_autoptr (GHashTable) installed_ids = NULL; guint n_items; self = g_weak_ref_get (wr); if (self == NULL) return dex_future_new_reject (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Page destroyed"); installed_groups = bz_state_info_get_all_installed_entry_groups (self->state); installed_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); if (installed_groups != NULL) { guint n_installed = g_list_model_get_n_items (installed_groups); for (guint i = 0; i < n_installed; i++) { g_autoptr (BzEntryGroup) group = NULL; const char *id = NULL; group = g_list_model_get_item (installed_groups, i); id = bz_entry_group_get_id (group); if (id != NULL) g_hash_table_replace (installed_ids, g_strdup (id), NULL); } } ids_hash = dex_await_boxed ( bz_get_user_data_ids_dex (), &local_error); if (ids_hash == NULL) { g_warning ("Failed to enumerate user data directories: %s", local_error->message); return dex_future_new_for_error (g_steal_pointer (&local_error)); } id_list = gtk_string_list_new (NULL); g_hash_table_iter_init (&iter, ids_hash); for (;;) { char *app_id = NULL; if (!g_hash_table_iter_next (&iter, (gpointer *) &app_id, NULL)) break; if (!g_hash_table_contains (installed_ids, app_id)) gtk_string_list_append (id_list, app_id); } factory = bz_state_info_get_application_factory (self->state); model = bz_application_map_factory_generate (factory, G_LIST_MODEL (id_list)); sorted_store = g_list_store_new (BZ_TYPE_ENTRY_GROUP); n_items = g_list_model_get_n_items (model); for (guint i = 0; i < n_items; i++) { g_autoptr (BzEntryGroup) group = g_list_model_get_item (model, i); g_list_store_append (sorted_store, group); } g_list_store_sort (sorted_store, (GCompareDataFunc) compare_entry_groups_by_title, NULL); if (self->model != NULL) g_signal_handlers_disconnect_by_func (self->model, items_changed, self); g_clear_object (&self->model); self->model = G_LIST_MODEL (g_steal_pointer (&sorted_store)); g_signal_connect_swapped (self->model, "items-changed", G_CALLBACK (items_changed), self); set_page (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MODEL]); return dex_future_new_true (); } bazaar-orig-v0.7.14/src/release-notes.xml.in0000664000175000017500000000000015166123241017612 0ustar hasanhasanbazaar-orig-v0.7.14/src/bz-age-rating-dialog.blp0000664000175000017500000000152415166123241020314 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzAgeRatingDialog: Adw.Dialog { content-height: 550; content-width: 640; title: _("Age Rating"); Adw.ToolbarView { [top] Adw.HeaderBar { show-title: false; } content: ScrolledWindow { hscrollbar-policy: never; Adw.Clamp { maximum-size: 600; tightening-threshold: 400; Box { orientation: vertical; spacing: 24; margin-start: 24; margin-end: 24; margin-top: 24; margin-bottom: 24; $BzLozenge lozenge { title: _("Age Rating"); label: "?"; importance: neutral; } ListBox list { selection-mode: none; styles [ "boxed-list", ] } } } }; } } bazaar-orig-v0.7.14/src/bz-hash-table-object.txt0000664000175000017500000000025715166123241020361 0ustar hasanhasanprefix=bz name=hash_table_object parent-prefix=g parent-name=object author=AUTOGEN property=hash_table GHashTable G_TYPE_HASH_TABLE boxed g_hash_table_unref g_hash_table_ref bazaar-orig-v0.7.14/src/bz-country-data-point.txt0000664000175000017500000000025715166123241020646 0ustar hasanhasanprefix=bz name=country_data_point parent-prefix=g parent-name=object author=AUTOGEN property=country_code char G_TYPE_STRING string property=downloads guint G_TYPE_UINT uint bazaar-orig-v0.7.14/src/bz-content-provider.c0000664000175000017500000004447715166123241020026 0ustar hasanhasan/* bz-content-provider.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::CONTENT-PROVIDER" #include "config.h" #include #include #include "bz-content-provider.h" #include "bz-env.h" #include "bz-io.h" #include "bz-util.h" struct _BzContentProvider { GObject parent_instance; GListModel *input_files; BzParser *parser; GListStore *input_mirror; GHashTable *input_tracking; GListStore *outputs; GtkFlattenListModel *impl_model; }; static void list_model_iface_init (GListModelInterface *iface); G_DEFINE_FINAL_TYPE_WITH_CODE ( BzContentProvider, bz_content_provider, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init)) enum { PROP_0, PROP_INPUT_FILES, PROP_PARSER, PROP_HAS_INPUTS, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; BZ_DEFINE_DATA ( input_init, InputInit, { GFile *file; }, BZ_RELEASE_DATA (file, g_object_unref)) static DexFuture * input_init_fiber (InputInitData *data); BZ_DEFINE_DATA ( input_load, InputLoad, { GFile *file; BzParser *parser; }, BZ_RELEASE_DATA (file, g_object_unref); BZ_RELEASE_DATA (parser, g_object_unref)) static DexFuture * input_load_fiber (InputLoadData *data); BZ_DEFINE_DATA ( input_tracking, InputTracking, { GMutex mutex; GWeakRef self; char *path; GFileMonitor *monitor; GListStore *output; DexFuture *init; DexFuture *task; }, g_mutex_clear (&self->mutex); g_weak_ref_clear (&self->self); BZ_RELEASE_DATA (path, g_free); BZ_RELEASE_DATA (monitor, g_object_unref); BZ_RELEASE_DATA (output, g_object_unref); BZ_RELEASE_DATA (init, dex_unref); BZ_RELEASE_DATA (task, dex_unref)) static DexFuture * input_init_finally (DexFuture *future, InputTrackingData *data); static DexFuture * input_load_finally (DexFuture *future, InputTrackingData *data); static void impl_model_changed (BzContentProvider *self, guint position, guint removed, guint added, GListModel *impl_model); static void input_files_changed (BzContentProvider *self, guint position, guint removed, guint added, GListModel *input_files); static void input_file_changed_on_disk (InputTrackingData *data, GFile *file, GFile *other_file, GFileMonitorEvent event_type, GFileMonitor *monitor); static gboolean commence_reload (InputTrackingData *data); static void bz_content_provider_dispose (GObject *object) { BzContentProvider *self = BZ_CONTENT_PROVIDER (object); g_clear_object (&self->input_files); g_clear_object (&self->parser); g_clear_object (&self->input_mirror); g_clear_pointer (&self->input_tracking, g_hash_table_unref); g_clear_object (&self->outputs); g_clear_object (&self->impl_model); G_OBJECT_CLASS (bz_content_provider_parent_class)->dispose (object); } static void bz_content_provider_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzContentProvider *self = BZ_CONTENT_PROVIDER (object); switch (prop_id) { case PROP_INPUT_FILES: g_value_set_object (value, bz_content_provider_get_input_files (self)); break; case PROP_PARSER: g_value_set_object (value, bz_content_provider_get_parser (self)); break; case PROP_HAS_INPUTS: g_value_set_boolean (value, bz_content_provider_get_has_inputs (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_content_provider_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzContentProvider *self = BZ_CONTENT_PROVIDER (object); switch (prop_id) { case PROP_INPUT_FILES: bz_content_provider_set_input_files (self, g_value_get_object (value)); break; case PROP_PARSER: bz_content_provider_set_parser (self, g_value_get_object (value)); break; case PROP_HAS_INPUTS: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_content_provider_class_init (BzContentProviderClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bz_content_provider_set_property; object_class->get_property = bz_content_provider_get_property; object_class->dispose = bz_content_provider_dispose; props[PROP_INPUT_FILES] = g_param_spec_object ( "input-files", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_PARSER] = g_param_spec_object ( "parser", NULL, NULL, BZ_TYPE_PARSER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_HAS_INPUTS] = g_param_spec_boolean ( "has-inputs", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_content_provider_init (BzContentProvider *self) { self->input_mirror = g_list_store_new (G_TYPE_FILE); self->input_tracking = g_hash_table_new_full ( g_direct_hash, g_direct_equal, g_object_unref, input_tracking_data_unref); self->outputs = g_list_store_new (G_TYPE_LIST_MODEL); self->impl_model = gtk_flatten_list_model_new (g_object_ref (G_LIST_MODEL (self->outputs))); g_signal_connect_swapped ( self->impl_model, "items-changed", G_CALLBACK (impl_model_changed), self); } static GType list_model_get_item_type (GListModel *list) { return G_TYPE_OBJECT; } static guint list_model_get_n_items (GListModel *list) { BzContentProvider *self = BZ_CONTENT_PROVIDER (list); return g_list_model_get_n_items (G_LIST_MODEL (self->impl_model)); } static gpointer list_model_get_item (GListModel *list, guint position) { BzContentProvider *self = BZ_CONTENT_PROVIDER (list); return g_list_model_get_item (G_LIST_MODEL (self->impl_model), position); } static void list_model_iface_init (GListModelInterface *iface) { iface->get_item_type = list_model_get_item_type; iface->get_n_items = list_model_get_n_items; iface->get_item = list_model_get_item; } BzContentProvider * bz_content_provider_new (void) { return g_object_new (BZ_TYPE_CONTENT_PROVIDER, NULL); } void bz_content_provider_set_input_files (BzContentProvider *self, GListModel *input_files) { guint old_length = 0; g_return_if_fail (BZ_IS_CONTENT_PROVIDER (self)); g_return_if_fail (input_files == NULL || G_IS_LIST_MODEL (input_files)); if (self->input_files != NULL) { old_length = g_list_model_get_n_items (self->input_files); g_signal_handlers_disconnect_by_func ( self->input_files, input_files_changed, self); } g_clear_object (&self->input_files); g_hash_table_remove_all (self->input_tracking); g_list_store_remove_all (self->input_mirror); g_list_store_remove_all (self->outputs); if (input_files != NULL) { self->input_files = g_object_ref (input_files); g_signal_connect_swapped ( input_files, "items-changed", G_CALLBACK (input_files_changed), self); input_files_changed ( self, 0, old_length, g_list_model_get_n_items (input_files), input_files); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_INPUT_FILES]); } GListModel * bz_content_provider_get_input_files (BzContentProvider *self) { g_return_val_if_fail (BZ_IS_CONTENT_PROVIDER (self), NULL); return self->input_files; } void bz_content_provider_set_parser (BzContentProvider *self, BzParser *parser) { GHashTableIter iter = { 0 }; g_return_if_fail (BZ_IS_CONTENT_PROVIDER (self)); g_return_if_fail (parser == NULL || BZ_IS_PARSER (parser)); g_clear_object (&self->parser); if (parser != NULL) self->parser = g_object_ref (parser); g_hash_table_iter_init (&iter, self->input_tracking); for (;;) { GFile *file = NULL; InputTrackingData *data = NULL; if (!g_hash_table_iter_next ( &iter, (gpointer *) &file, (gpointer *) &data)) break; commence_reload (data); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PARSER]); } BzParser * bz_content_provider_get_parser (BzContentProvider *self) { g_return_val_if_fail (BZ_IS_CONTENT_PROVIDER (self), NULL); return self->parser; } gboolean bz_content_provider_get_has_inputs (BzContentProvider *self) { g_return_val_if_fail (BZ_IS_CONTENT_PROVIDER (self), FALSE); return self->input_files != NULL && g_list_model_get_n_items (self->input_files) > 0 && g_list_model_get_n_items (G_LIST_MODEL (self)) > 0; } static void impl_model_changed (BzContentProvider *self, guint position, guint removed, guint added, GListModel *impl_model) { g_list_model_items_changed ( G_LIST_MODEL (self), position, removed, added); } static void input_files_changed (BzContentProvider *self, guint position, guint removed, guint added, GListModel *input_files) { gboolean emit_has_inputs = FALSE; g_autofree GFile **additions = NULL; g_autofree GListStore **new_outputs = NULL; emit_has_inputs = g_list_model_get_n_items (input_files) == 0 || g_list_model_get_n_items (G_LIST_MODEL (self->input_mirror)) == 0; if (removed > 0) { for (guint i = 0; i < removed; i++) { g_autoptr (GFile) removal = NULL; InputTrackingData *data = NULL; removal = g_list_model_get_item ( G_LIST_MODEL (self->input_mirror), position + i); data = g_hash_table_lookup (self->input_tracking, removal); g_assert (data != NULL); g_mutex_lock (&data->mutex); dex_clear (&data->task); g_mutex_unlock (&data->mutex); g_hash_table_remove (self->input_tracking, removal); } } if (added > 0) { additions = g_malloc0_n (added, sizeof (*additions)); for (guint i = 0; i < added; i++) additions[i] = g_list_model_get_item ( G_LIST_MODEL (self->input_files), position + i); new_outputs = g_malloc0_n (added, sizeof (*new_outputs)); for (guint i = 0; i < added; i++) new_outputs[i] = g_list_store_new (G_TYPE_OBJECT); } g_list_store_splice (self->input_mirror, position, removed, (gpointer *) additions, added); g_list_store_splice (self->outputs, position, removed, (gpointer *) new_outputs, added); for (guint i = 0; i < added; i++) { g_autoptr (InputInitData) init_data = NULL; g_autoptr (InputTrackingData) tracking_data = NULL; g_autoptr (DexFuture) future = NULL; init_data = input_init_data_new (); init_data->file = g_object_ref (additions[i]); future = dex_scheduler_spawn ( bz_get_io_scheduler (), bz_get_dex_stack_size (), (DexFiberFunc) input_init_fiber, input_init_data_ref (init_data), input_init_data_unref); tracking_data = input_tracking_data_new (); g_mutex_init (&tracking_data->mutex); g_weak_ref_init (&tracking_data->self, self); tracking_data->path = g_file_get_path (additions[i]); tracking_data->output = g_steal_pointer (&new_outputs[i]); g_mutex_lock (&tracking_data->mutex); future = dex_future_finally ( future, (DexFutureCallback) input_init_finally, input_tracking_data_ref (tracking_data), input_tracking_data_unref); tracking_data->init = g_steal_pointer (&future); g_mutex_unlock (&tracking_data->mutex); g_hash_table_replace ( self->input_tracking, g_steal_pointer (&additions[i]), input_tracking_data_ref (tracking_data)); } if (emit_has_inputs) g_object_notify_by_pspec (G_OBJECT (self), props[PROP_HAS_INPUTS]); } static void input_file_changed_on_disk (InputTrackingData *data, GFile *file, GFile *other_file, GFileMonitorEvent event_type, GFileMonitor *monitor) { if (event_type == G_FILE_MONITOR_EVENT_CHANGED || event_type == G_FILE_MONITOR_EVENT_CREATED || event_type == G_FILE_MONITOR_EVENT_DELETED) g_idle_add_full ( G_PRIORITY_DEFAULT, (GSourceFunc) commence_reload, input_tracking_data_ref (data), input_tracking_data_unref); } static DexFuture * input_init_fiber (InputInitData *data) { GFile *file = data->file; g_autoptr (GError) local_error = NULL; g_autoptr (GFileMonitor) monitor = NULL; monitor = g_file_monitor_file ( file, G_FILE_MONITOR_NONE, NULL, &local_error); if (monitor == NULL) return dex_future_new_for_error (g_steal_pointer (&local_error)); return dex_future_new_for_object (monitor); } static DexFuture * input_init_finally (DexFuture *future, InputTrackingData *data) { g_autoptr (BzContentProvider) self = NULL; g_autoptr (GError) local_error = NULL; g_autoptr (GMutexLocker) locker = NULL; const GValue *value = NULL; locker = g_mutex_locker_new (&data->mutex); dex_clear (&data->init); bz_weak_get_or_return_reject (self, &data->self); g_list_store_remove_all (data->output); value = dex_future_get_value (future, &local_error); if (value != NULL) { data->monitor = g_value_dup_object (value); g_signal_connect_swapped ( data->monitor, "changed", G_CALLBACK (input_file_changed_on_disk), data); g_clear_pointer (&locker, g_mutex_locker_free); commence_reload (data); } else g_warning ("Could not init object watch at path %s: %s", data->path, local_error->message); return NULL; } static DexFuture * input_load_fiber (InputLoadData *data) { GFile *file = data->file; BzParser *parser = data->parser; g_autoptr (GError) local_error = NULL; g_autoptr (GBytes) bytes = NULL; g_autoptr (GHashTable) parse_results = NULL; GObject *object = NULL; bytes = dex_await_boxed (dex_file_load_contents_bytes (file), &local_error); if (bytes == NULL) return dex_future_new_for_error (g_steal_pointer (&local_error)); parse_results = bz_parser_process_bytes (parser, bytes, &local_error); if (parse_results == NULL) return dex_future_new_for_error (g_steal_pointer (&local_error)); object = g_value_get_object (g_hash_table_lookup (parse_results, "/")); if (object == NULL) return dex_future_new_reject (G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Parser returned invalid results"); return dex_future_new_for_object (object); } static DexFuture * input_load_finally (DexFuture *future, InputTrackingData *data) { g_autoptr (BzContentProvider) self = NULL; g_autoptr (GError) local_error = NULL; g_autoptr (GMutexLocker) locker = NULL; const GValue *value = NULL; locker = g_mutex_locker_new (&data->mutex); g_list_store_remove_all (data->output); bz_weak_get_or_return_reject (self, &data->self); value = dex_future_get_value (future, &local_error); if (value != NULL) g_list_store_append (data->output, g_value_get_object (value)); else if (local_error->domain != G_IO_ERROR) g_warning ("Could not load object at path %s: %s", data->path, local_error->message); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_HAS_INPUTS]); return NULL; } static gboolean commence_reload (InputTrackingData *data) { g_autoptr (BzContentProvider) self = NULL; g_autoptr (GMutexLocker) locker = NULL; g_autoptr (InputLoadData) load_data = NULL; g_autoptr (DexFuture) future = NULL; locker = g_mutex_locker_new (&data->mutex); dex_clear (&data->task); self = g_weak_ref_get (&data->self); if (self == NULL) goto done; if (self->parser == NULL) goto done; load_data = input_load_data_new (); load_data->file = g_file_new_for_path (data->path); load_data->parser = g_object_ref (self->parser); future = dex_scheduler_spawn ( bz_get_io_scheduler (), bz_get_dex_stack_size (), (DexFiberFunc) input_load_fiber, input_load_data_ref (load_data), input_load_data_unref); future = dex_future_finally ( future, (DexFutureCallback) input_load_finally, input_tracking_data_ref (data), input_tracking_data_unref); data->task = g_steal_pointer (&future); done: return G_SOURCE_REMOVE; } bazaar-orig-v0.7.14/src/bz-window.blp0000664000175000017500000003126115166123241016351 0ustar hasanhasanusing Gtk 4.0; using Gio 2.0; using Adw 1; template $BzWindow: Adw.ApplicationWindow { title: bind $format_title(navigation_view.visible-page as .title); default-width: 1220; default-height: 900; width-request: 360; height-request: 294; ShortcutController { Shortcut { trigger: "Escape"; action: "action(escape)"; } Shortcut { trigger: "Back"; action: "action(escape)"; } Shortcut { trigger: "BackSpace"; action: "action(escape)"; } Shortcut { trigger: "g"; action: "action(escape)"; } } content: Adw.ToolbarView { content: $BzCometOverlay comet_overlay { child: Adw.BreakpointBin split_breakpoint_bin { width-request: 360; height-request: 450; child: Adw.ToastOverlay toasts { child: Adw.NavigationView navigation_view { pop-on-escape: false; Adw.NavigationPage { tag: "main"; title: _("Bazaar"); child: Adw.ToolbarView toolbar_view { top-bar-style: flat; bottom-bar-style: flat; reveal-bottom-bars: false; content: Stack main_stack { StackPage { name: "loading"; child: Box { halign: fill; valign: center; orientation: vertical; spacing: 6; Adw.Spinner { width-request: 64; height-request: 64; margin-bottom: 18; } Label { label: _("Refreshing…"); wrap: true; justify: center; margin-bottom: 24; styles [ "title-3", ] } }; } StackPage { name: "main"; child: Adw.ViewStack main_view_stack { Adw.ViewStackPage { name: "browse"; title: _("Curated"); icon-name: "starred-symbolic"; visible: bind template.state as <$BzStateInfo>.curated-provider as <$BzContentProvider>.has-inputs; child: $BzCuratedView browse { state: bind template.state as <$BzStateInfo>; browse-flathub => $browse_flathub_cb(template); }; } Adw.ViewStackPage { name: "flathub"; title: _("Flathub"); icon-name: "flathub-symbolic"; child: $BzFlathubPage { state: bind template.state as <$BzStateInfo>; open-search => $open_search_cb(template); }; } Adw.ViewStackPage { name: "installed"; // Translators: . title: _("Library"); icon-name: "library-symbolic"; badge-number: bind template.state as <$BzStateInfo>.available-updates as .n-items; needs-attention: bind template.state as <$BzStateInfo>.available-updates as .n-items; child: $BzLibraryPage library_page { state: bind template.state; transactions: bind template.state as <$BzStateInfo>.transaction-manager; model: bind template.state as <$BzStateInfo>.all-installed-entry-groups; update => $update_cb(template); }; } Adw.ViewStackPage { name: "search"; title: _("Search"); icon-name: "system-search-symbolic"; child: $BzSearchPage search_page { state: bind template.state; }; } }; } }; [top] Box { orientation: vertical; Adw.HeaderBar top_header_bar { [start] Box { styles [ "bz-debug", ] orientation: horizontal; spacing: 6; visible: bind template.state as <$BzStateInfo>.debug-mode; Button { has-tooltip: true; tooltip-text: "Open Bazaar Inspector"; icon-name: "bug-symbolic"; action-name: "app.bazaar-inspector"; } } [start] MenuButton { visible: bind template.state as <$BzStateInfo>.auth-state as <$BzAuthState>.authenticated; menu-model: account_menu; styles [ "circular", "flat", ] child: Adw.Avatar { size: 24; custom-image: bind template.state as <$BzStateInfo>.auth-state as <$BzAuthState>.paintable; }; } [start] Revealer { transition-type: crossfade; transition-duration: 750; reveal-child: bind $logical_or($invert_boolean($is_null(template.state as <$BzStateInfo>.background-task-label) as ) as , status_popover.visible) as ; child: MenuButton { styles [ "flat", ] child: Box { Adw.Spinner { visible: bind status_popover_label.visible; } Image { visible: bind $invert_boolean(status_popover_label.visible) as ; icon-name: "check-plain-symbolic"; } }; popover: Popover status_popover { has-arrow: true; position: right; child: Box { orientation: vertical; margin-top: 12; margin-bottom: 12; margin-start: 12; margin-end: 12; width-request: 300; Label status_popover_label { hexpand: true; visible: bind $invert_boolean($is_null(template.state as <$BzStateInfo>.background-task-label) as ) as ; label: bind template.state as <$BzStateInfo>.background-task-label; } Label { hexpand: true; visible: bind $invert_boolean(status_popover_label.visible) as ; label: _("Refresh completed!"); } }; }; }; } [title] Adw.ViewSwitcher { stack: main_view_stack; policy: wide; sensitive: bind $invert_boolean(template.state as <$BzStateInfo>.busy) as ; } [end] MenuButton { primary: true; icon-name: "open-menu-symbolic"; has-tooltip: true; tooltip-text: _("Main Menu"); menu-model: primary_menu; } [end] Button progress_button { styles [ "flat", "global-progress-button", ] can-focus: bind template.state as <$BzStateInfo>.transaction-manager as <$BzTransactionManager>.active; can-target: bind progress_button.can-focus; action-name: "window.open-library"; has-tooltip: true; tooltip-text: _("Open App Library"); child: $BzGlobalProgress { expand-size: 125; state: bind template.state as <$BzStateInfo>; active: bind template.state as <$BzStateInfo>.transaction-manager as <$BzTransactionManager>.active; pending: bind template.state as <$BzStateInfo>.transaction-manager as <$BzTransactionManager>.pending; settings: bind template.state as <$BzStateInfo>.settings; }; } } Adw.Banner { styles [ "bz-donations-banner", ] revealed: bind $invert_boolean(template.state as <$BzStateInfo>.donation-prompt-dismissed as ) as ; title: _("You are running a new version of Bazaar!"); button-label: _("See What's New"); action-name: "app.donate"; } Adw.Banner { sensitive: bind $invert_boolean(template.state as <$BzStateInfo>.syncing as ) as ; revealed: bind $logical_and($invert_boolean(template.state as <$BzStateInfo>.metered_connection as ) as , $logical_and(template.state as <$BzStateInfo>.have_connection as , $invert_boolean(template.state as <$BzStateInfo>.online as ) as ) as ) as ; title: _("You have a network connection but are viewing a cached version of Flathub"); button-label: _("Refresh Manually"); button-clicked => $sync_cb(template); } } [bottom] Adw.ViewSwitcherBar { stack: main_view_stack; reveal: true; sensitive: bind $invert_boolean(template.state as <$BzStateInfo>.busy) as ; } }; } Adw.NavigationPage { tag: "view"; title: bind full_view.entry-group as <$BzEntryGroup>.title as ; child: $BzFullView full_view { state: bind template.state; main-menu: primary_menu; update => $update_cb(template); }; } }; }; Adw.Breakpoint { condition ("max-width: 700px") setters { top_header_bar.title-widget: null; toolbar_view.reveal-bottom-bars: true; } apply => $breakpoint_apply_cb(template); unapply => $breakpoint_unapply_cb(template); } }; }; }; } menu primary_menu { section { item { label: _("_Donate to Bazaar ❤️"); action: "app.donate"; } } section { item { label: _("_Refresh"); action: "app.sync-remotes"; } item { label: _("_Preferences"); action: "app.preferences"; } item { label: _("_Login With Flathub"); action: "app.flathub-login"; hidden-when: "action-disabled"; } item { label: _("_Manage Leftover User Data"); action: "window.user-data"; } item { label: _("_Keyboard Shortcuts"); action: "app.shortcuts"; } item { label: _("_About Bazaar"); action: "app.about"; } } section { item { label: _("_Quit Bazaar"); action: "app.quit"; } } } menu debug_menu { section { item { label: "Open Bazaar Inspector"; action: "app.bazaar-inspector"; } } } menu account_menu { section { item { label: _("Favorites"); action: "app.flathub-favorites"; } } section { item { label: _("Log Out"); action: "app.flathub-logout"; } } } bazaar-orig-v0.7.14/src/bz-installed-tile.c0000664000175000017500000002102415166123241017415 0ustar hasanhasan/* bz-installed-tile.c * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-addons-dialog.h" #include "bz-entry-group-util.h" #include "bz-entry-group.h" #include "bz-env.h" #include "bz-error.h" #include "bz-installed-tile.h" #include "bz-library-page.h" #include "bz-state-info.h" #include "bz-window.h" struct _BzInstalledTile { BzListTile parent_instance; BzEntryGroup *group; GtkPicture *icon_picture; GtkImage *fallback_icon; GtkLabel *title_label; GtkButton *support_button; GtkButton *remove_button; }; G_DEFINE_FINAL_TYPE (BzInstalledTile, bz_installed_tile, BZ_TYPE_LIST_TILE) enum { PROP_0, PROP_GROUP, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bz_installed_tile_dispose (GObject *object) { BzInstalledTile *self = BZ_INSTALLED_TILE (object); g_clear_object (&self->group); G_OBJECT_CLASS (bz_installed_tile_parent_class)->dispose (object); } static void bz_installed_tile_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzInstalledTile *self = BZ_INSTALLED_TILE (object); switch (prop_id) { case PROP_GROUP: g_value_set_object (value, bz_installed_tile_get_group (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_installed_tile_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzInstalledTile *self = BZ_INSTALLED_TILE (object); switch (prop_id) { case PROP_GROUP: bz_installed_tile_set_group (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static gboolean is_null (gpointer object, GObject *value) { return value == NULL; } static gboolean is_zero (gpointer object, int value) { return value == 0; } static gboolean logical_and (gpointer object, gboolean a, gboolean b) { return a && b; } static gboolean logical_or (gpointer object, gboolean a, gboolean b) { return a || b; } static char * format_description (gpointer object, guint64 size, GListModel *versions) { g_autoptr (GString) result = NULL; g_autoptr (GString) versions_str = NULL; g_autofree char *size_str = NULL; guint n_versions = 0; result = g_string_new (NULL); if (versions != NULL) n_versions = g_list_model_get_n_items (versions); if (n_versions > 0) { versions_str = g_string_new (NULL); for (guint i = 0; i < n_versions; i++) { g_autoptr (GtkStringObject) string = NULL; const char *version = NULL; string = g_list_model_get_item (versions, i); version = gtk_string_object_get_string (string); if (version != NULL && *version != '\0') { if (versions_str->len > 0) g_string_append_c (versions_str, ' '); g_string_append (versions_str, version); } } if (versions_str->len > 0) { g_string_append (result, versions_str->str); g_string_append (result, " • "); } } size_str = g_format_size (size); g_string_append (result, size_str); return g_string_free (g_steal_pointer (&result), FALSE); } static void support_cb (BzInstalledTile *self, GtkButton *button) { const char *url = NULL; if (self->group == NULL) return; url = bz_entry_group_get_donation_url (self->group); if (url == NULL) return; g_app_info_launch_default_for_uri (url, NULL, NULL); } static void permissions_cb (BzInstalledTile *self) { if (self->group == NULL) return; gtk_widget_activate_action (GTK_WIDGET (self), "window.permissions", "s", bz_entry_group_get_id (self->group)); } static void install_addons_cb (BzInstalledTile *self) { if (self->group == NULL) return; gtk_widget_activate_action (GTK_WIDGET (self), "window.addons-group", "s", bz_entry_group_get_id (self->group)); } static void remove_cb (BzInstalledTile *self, GtkButton *button) { if (self->group == NULL) return; gtk_widget_activate_action (GTK_WIDGET (self), "window.remove-group", "(sb)", bz_entry_group_get_id (self->group), FALSE); } static void bz_installed_tile_class_init (BzInstalledTileClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_installed_tile_dispose; object_class->get_property = bz_installed_tile_get_property; object_class->set_property = bz_installed_tile_set_property; props[PROP_GROUP] = g_param_spec_object ( "group", NULL, NULL, BZ_TYPE_ENTRY_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_LIST_TILE); g_type_ensure (BZ_TYPE_ENTRY_GROUP); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-installed-tile.ui"); gtk_widget_class_bind_template_child (widget_class, BzInstalledTile, icon_picture); gtk_widget_class_bind_template_child (widget_class, BzInstalledTile, fallback_icon); gtk_widget_class_bind_template_child (widget_class, BzInstalledTile, title_label); gtk_widget_class_bind_template_child (widget_class, BzInstalledTile, support_button); gtk_widget_class_bind_template_child (widget_class, BzInstalledTile, remove_button); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, is_null); gtk_widget_class_bind_template_callback (widget_class, is_zero); gtk_widget_class_bind_template_callback (widget_class, logical_and); gtk_widget_class_bind_template_callback (widget_class, logical_or); gtk_widget_class_bind_template_callback (widget_class, format_description); gtk_widget_class_bind_template_callback (widget_class, support_cb); gtk_widget_class_bind_template_callback (widget_class, install_addons_cb); gtk_widget_class_bind_template_callback (widget_class, remove_cb); gtk_widget_class_bind_template_callback (widget_class, permissions_cb); gtk_widget_class_install_action (widget_class, "installed-tile.install-addons", NULL, (GtkWidgetActionActivateFunc) install_addons_cb); gtk_widget_class_install_action (widget_class, "installed-tile.permissions", NULL, (GtkWidgetActionActivateFunc) permissions_cb); gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_BUTTON); } static void bz_installed_tile_init (BzInstalledTile *self) { gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_installed_tile_new (void) { return g_object_new (BZ_TYPE_INSTALLED_TILE, NULL); } void bz_installed_tile_set_group (BzInstalledTile *self, BzEntryGroup *group) { g_return_if_fail (BZ_IS_INSTALLED_TILE (self)); g_return_if_fail (group == NULL || BZ_IS_ENTRY_GROUP (group)); g_clear_object (&self->group); if (group != NULL) self->group = g_object_ref (group); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_GROUP]); } BzEntryGroup * bz_installed_tile_get_group (BzInstalledTile *self) { g_return_val_if_fail (BZ_IS_INSTALLED_TILE (self), NULL); return self->group; } bazaar-orig-v0.7.14/src/bz-auth-state.h0000664000175000017500000000320615166123241016571 0ustar hasanhasan/* bz-auth-state.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include G_BEGIN_DECLS #define BZ_TYPE_AUTH_STATE (bz_auth_state_get_type ()) G_DECLARE_FINAL_TYPE (BzAuthState, bz_auth_state, BZ, AUTH_STATE, GObject) BzAuthState *bz_auth_state_new (void); const char * bz_auth_state_get_name (BzAuthState *self); const char * bz_auth_state_get_token (BzAuthState *self); const char * bz_auth_state_get_profile_icon_url (BzAuthState *self); gboolean bz_auth_state_is_authenticated (BzAuthState *self); GdkPaintable * bz_auth_state_get_paintable (BzAuthState *self); void bz_auth_state_set_authenticated (BzAuthState *self, const char *name, const char *token, GDateTime *token_expires, const char *profile_icon_url); void bz_auth_state_clear (BzAuthState *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-flatpak-entry.c0000664000175000017500000006401715166123241017275 0ustar hasanhasan/* bz-flatpak-entry.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::FLATPAK-ENTRY" #define BAZAAR_MODULE "entry" #include "config.h" #include #include #include "bz-app-permissions.h" #include "bz-application-map-factory.h" #include "bz-application.h" #include "bz-appstream-parser.h" #include "bz-flatpak-private.h" #include "bz-io.h" #include "bz-result.h" #include "bz-serializable.h" #include "bz-state-info.h" #define VERSION_SUFFIX_REGEX "\\s+[0-9][0-9.]*\\s*$" struct _BzFlatpakEntry { BzEntry parent_instance; gboolean user; gboolean is_bundle; gboolean is_installed_ref; char *flatpak_name; char *flatpak_id; char *flatpak_version; char *application_name; char *application_runtime; char *application_command; char *runtime_name; char *addon_extension_of_ref; BzResult *runtime_result; FlatpakRef *ref; }; static void serializable_iface_init (BzSerializableInterface *iface); G_DEFINE_FINAL_TYPE_WITH_CODE ( BzFlatpakEntry, bz_flatpak_entry, BZ_TYPE_ENTRY, G_IMPLEMENT_INTERFACE (BZ_TYPE_SERIALIZABLE, serializable_iface_init)) enum { PROP_0, PROP_USER, PROP_FLATPAK_NAME, PROP_IS_BUNDLE, PROP_FLATPAK_ID, PROP_FLATPAK_VERSION, PROP_APPLICATION_NAME, PROP_APPLICATION_RUNTIME, PROP_APPLICATION_COMMAND, PROP_RUNTIME_NAME, PROP_RUNTIME_RESULT, PROP_ADDON_OF_REF, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void clear_entry (BzFlatpakEntry *self); static void bz_flatpak_entry_dispose (GObject *object) { BzFlatpakEntry *self = BZ_FLATPAK_ENTRY (object); clear_entry (self); g_clear_object (&self->ref); G_OBJECT_CLASS (bz_flatpak_entry_parent_class)->dispose (object); } static void bz_flatpak_entry_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzFlatpakEntry *self = BZ_FLATPAK_ENTRY (object); switch (prop_id) { case PROP_USER: g_value_set_boolean (value, self->user); break; case PROP_FLATPAK_ID: g_value_set_string (value, self->flatpak_id); break; case PROP_FLATPAK_NAME: g_value_set_string (value, self->flatpak_name); break; case PROP_FLATPAK_VERSION: g_value_set_string (value, self->flatpak_version); break; case PROP_APPLICATION_NAME: g_value_set_string (value, self->application_name); break; case PROP_IS_BUNDLE: g_value_set_boolean (value, self->is_bundle); break; case PROP_APPLICATION_RUNTIME: g_value_set_string (value, self->application_runtime); break; case PROP_APPLICATION_COMMAND: g_value_set_string (value, self->application_command); break; case PROP_RUNTIME_NAME: g_value_set_string (value, self->runtime_name); break; case PROP_RUNTIME_RESULT: g_value_take_object (value, bz_flatpak_entry_dup_runtime_result (self)); break; case PROP_ADDON_OF_REF: g_value_set_string (value, self->addon_extension_of_ref); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_flatpak_entry_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { // BzFlatpakEntry *self = BZ_FLATPAK_ENTRY (object); switch (prop_id) { case PROP_USER: case PROP_FLATPAK_NAME: case PROP_FLATPAK_ID: case PROP_FLATPAK_VERSION: case PROP_APPLICATION_NAME: case PROP_IS_BUNDLE: case PROP_APPLICATION_RUNTIME: case PROP_APPLICATION_COMMAND: case PROP_RUNTIME_NAME: case PROP_ADDON_OF_REF: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_flatpak_entry_class_init (BzFlatpakEntryClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bz_flatpak_entry_set_property; object_class->get_property = bz_flatpak_entry_get_property; object_class->dispose = bz_flatpak_entry_dispose; props[PROP_USER] = g_param_spec_boolean ( "user", NULL, NULL, FALSE, G_PARAM_READABLE); props[PROP_FLATPAK_NAME] = g_param_spec_string ( "flatpak-name", NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_FLATPAK_ID] = g_param_spec_string ( "flatpak-id", NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_FLATPAK_VERSION] = g_param_spec_string ( "flatpak-version", NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_APPLICATION_NAME] = g_param_spec_string ( "application-name", NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_IS_BUNDLE] = g_param_spec_boolean ( "is-bundle", NULL, NULL, FALSE, G_PARAM_READABLE); props[PROP_APPLICATION_RUNTIME] = g_param_spec_string ( "application-runtime", NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_APPLICATION_COMMAND] = g_param_spec_string ( "application-command", NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_RUNTIME_NAME] = g_param_spec_string ( "runtime-name", NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_RUNTIME_RESULT] = g_param_spec_object ( "runtime", NULL, NULL, BZ_TYPE_RESULT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_ADDON_OF_REF] = g_param_spec_string ( "addon-extension-of-ref", NULL, NULL, NULL, G_PARAM_READABLE); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_flatpak_entry_init (BzFlatpakEntry *self) { } static void bz_flatpak_entry_real_serialize (BzSerializable *serializable, GVariantBuilder *builder) { BzFlatpakEntry *self = BZ_FLATPAK_ENTRY (serializable); g_variant_builder_add (builder, "{sv}", "user", g_variant_new_boolean (self->user)); g_variant_builder_add (builder, "{sv}", "is-installed-ref", g_variant_new_boolean (self->is_installed_ref)); if (self->flatpak_name != NULL) g_variant_builder_add (builder, "{sv}", "flatpak-name", g_variant_new_string (self->flatpak_name)); if (self->flatpak_id != NULL) g_variant_builder_add (builder, "{sv}", "flatpak-id", g_variant_new_string (self->flatpak_id)); if (self->flatpak_version != NULL) g_variant_builder_add (builder, "{sv}", "flatpak-version", g_variant_new_string (self->flatpak_version)); if (self->application_name != NULL) g_variant_builder_add (builder, "{sv}", "application-name", g_variant_new_string (self->application_name)); if (self->application_runtime != NULL) g_variant_builder_add (builder, "{sv}", "application-runtime", g_variant_new_string (self->application_runtime)); if (self->application_command != NULL) g_variant_builder_add (builder, "{sv}", "application-command", g_variant_new_string (self->application_command)); if (self->runtime_name != NULL) g_variant_builder_add (builder, "{sv}", "runtime-name", g_variant_new_string (self->runtime_name)); if (self->addon_extension_of_ref != NULL) g_variant_builder_add (builder, "{sv}", "addon-extension-of-ref", g_variant_new_string (self->addon_extension_of_ref)); bz_entry_serialize (BZ_ENTRY (self), builder); } static gboolean bz_flatpak_entry_real_deserialize (BzSerializable *serializable, GVariant *import, GError **error) { BzFlatpakEntry *self = BZ_FLATPAK_ENTRY (serializable); g_autoptr (GVariantIter) iter = NULL; clear_entry (self); iter = g_variant_iter_new (import); for (;;) { g_autofree char *key = NULL; g_autoptr (GVariant) value = NULL; if (!g_variant_iter_next (iter, "{sv}", &key, &value)) break; if (g_strcmp0 (key, "user") == 0) self->user = g_variant_get_boolean (value); else if (g_strcmp0 (key, "is-installed-ref") == 0) self->is_installed_ref = g_variant_get_boolean (value); else if (g_strcmp0 (key, "flatpak-name") == 0) self->flatpak_name = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "flatpak-id") == 0) self->flatpak_id = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "flatpak-version") == 0) self->flatpak_version = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "application-name") == 0) self->application_name = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "application-runtime") == 0) self->application_runtime = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "application-command") == 0) self->application_command = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "runtime-name") == 0) self->runtime_name = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "addon-extension-of-ref") == 0) self->addon_extension_of_ref = g_variant_dup_string (value, NULL); } return bz_entry_deserialize (BZ_ENTRY (self), import, error); } static void serializable_iface_init (BzSerializableInterface *iface) { iface->serialize = bz_flatpak_entry_real_serialize; iface->deserialize = bz_flatpak_entry_real_deserialize; } BzResult * bz_flatpak_entry_dup_runtime_result (BzFlatpakEntry *self) { BzStateInfo *state = NULL; BzApplicationMapFactory *factory = NULL; g_autofree char *runtime_unique_id = NULL; g_return_val_if_fail (BZ_IS_FLATPAK_ENTRY (self), NULL); state = bz_state_info_get_default (); if (self->runtime_result != NULL) return g_object_ref (self->runtime_result); if (self->application_runtime == NULL) return NULL; factory = bz_state_info_get_entry_factory (state); if (factory == NULL) return NULL; runtime_unique_id = g_strdup_printf ("FLATPAK-SYSTEM::flathub::runtime/%s", self->application_runtime); self->runtime_result = bz_application_map_factory_convert_one ( factory, gtk_string_object_new (runtime_unique_id)); return self->runtime_result != NULL ? g_object_ref (self->runtime_result) : NULL; } BzFlatpakEntry * bz_flatpak_entry_new_for_ref (FlatpakRef *ref, FlatpakRemote *remote, gboolean user, AsComponent *component, const char *appstream_dir, GError **error) { g_autoptr (BzFlatpakEntry) self = NULL; GBytes *bytes = NULL; g_autoptr (GKeyFile) key_file = NULL; gboolean result = FALSE; guint kinds = 0; g_autofree char *module_dir = NULL; const char *id = NULL; g_autofree char *unique_id = NULL; g_autofree char *unique_id_checksum = NULL; guint64 download_size = 0; guint64 installed_size = 0; const char *title = NULL; const char *eol = NULL; const char *remote_name = NULL; g_autoptr (GdkPaintable) icon_paintable = NULL; g_autoptr (BzAppPermissions) permissions = NULL; gboolean searchable = FALSE; g_return_val_if_fail (FLATPAK_IS_REF (ref), NULL); g_return_val_if_fail (FLATPAK_IS_REMOTE_REF (ref) || FLATPAK_IS_BUNDLE_REF (ref) || FLATPAK_IS_INSTALLED_REF (ref), NULL); g_return_val_if_fail (component == NULL || appstream_dir != NULL || FLATPAK_IS_BUNDLE_REF (ref) || FLATPAK_IS_INSTALLED_REF (ref), NULL); self = g_object_new (BZ_TYPE_FLATPAK_ENTRY, NULL); self->user = user; self->is_bundle = FLATPAK_IS_BUNDLE_REF (ref); self->is_installed_ref = FLATPAK_IS_INSTALLED_REF (ref); self->ref = g_object_ref (ref); key_file = g_key_file_new (); if (FLATPAK_IS_REMOTE_REF (ref)) bytes = flatpak_remote_ref_get_metadata (FLATPAK_REMOTE_REF (ref)); else if (FLATPAK_IS_BUNDLE_REF (ref)) bytes = flatpak_bundle_ref_get_metadata (FLATPAK_BUNDLE_REF (ref)); else if (FLATPAK_IS_INSTALLED_REF (ref)) bytes = flatpak_installed_ref_load_metadata (FLATPAK_INSTALLED_REF (ref), NULL, error); result = g_key_file_load_from_bytes ( key_file, bytes, G_KEY_FILE_NONE, error); if (!result) return NULL; #define GET_STRING(member, group_name, key) \ G_STMT_START \ { \ self->member = g_key_file_get_string ( \ key_file, group_name, key, error); \ if (self->member == NULL) \ return NULL; \ } \ G_STMT_END if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN)) { gsize n_groups = 0; g_auto (GStrv) groups = NULL; g_print ("Debug Key File Data for %s - groups:\n", flatpak_ref_get_name (ref)); groups = g_key_file_get_groups (key_file, &n_groups); for (gsize i = 0; i < n_groups; i++) { gsize n_keys = 0; g_auto (GStrv) keys = NULL; g_print (" group %s\n", groups[i]); keys = g_key_file_get_keys (key_file, groups[i], &n_keys, NULL); for (gsize j = 0; j < n_keys; j++) { g_autofree char *value = NULL; value = g_key_file_get_value (key_file, groups[i], keys[j], NULL); g_print (" %s=%s\n", keys[j], value); } } } if (g_key_file_has_group (key_file, "Application")) { kinds |= BZ_ENTRY_KIND_APPLICATION; GET_STRING (application_name, "Application", "name"); GET_STRING (application_runtime, "Application", "runtime"); if (g_key_file_has_key (key_file, "Application", "command", NULL)) GET_STRING (application_command, "Application", "command"); } if (g_key_file_has_group (key_file, "ExtensionOf")) { kinds |= BZ_ENTRY_KIND_ADDON; GET_STRING (addon_extension_of_ref, "ExtensionOf", "ref"); } if (g_key_file_has_group (key_file, "Runtime")) { kinds |= BZ_ENTRY_KIND_RUNTIME; GET_STRING (runtime_name, "Runtime", "name"); } #undef GET_STRING // if (kinds == 0) // { // g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, // "Key file presented no useful information"); // return NULL; // } module_dir = bz_dup_module_dir (); self->flatpak_name = g_strdup (flatpak_ref_get_name (ref)); self->flatpak_id = flatpak_ref_format_ref (ref); self->flatpak_version = g_strdup (flatpak_ref_get_branch (ref)); id = flatpak_ref_get_name (ref); unique_id = bz_flatpak_ref_format_unique (ref, user); unique_id_checksum = g_compute_checksum_for_string (G_CHECKSUM_MD5, unique_id, -1); if (remote != NULL) remote_name = flatpak_remote_get_name (remote); else if (FLATPAK_IS_BUNDLE_REF (ref)) remote_name = flatpak_bundle_ref_get_origin (FLATPAK_BUNDLE_REF (ref)); else if (FLATPAK_IS_INSTALLED_REF (ref)) remote_name = flatpak_installed_ref_get_origin (FLATPAK_INSTALLED_REF (ref)); if (FLATPAK_IS_REMOTE_REF (ref)) download_size = flatpak_remote_ref_get_download_size (FLATPAK_REMOTE_REF (ref)); else if (FLATPAK_IS_BUNDLE_REF (ref)) { g_autoptr (GFileInfo) file_info = NULL; GFile *bundle_file = flatpak_bundle_ref_get_file (FLATPAK_BUNDLE_REF (ref)); file_info = g_file_query_info (bundle_file, G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, NULL, NULL); if (file_info != NULL) download_size = g_file_info_get_size (file_info); } if (FLATPAK_IS_REMOTE_REF (ref)) installed_size = flatpak_remote_ref_get_installed_size (FLATPAK_REMOTE_REF (ref)); else if (FLATPAK_IS_BUNDLE_REF (ref)) installed_size = flatpak_bundle_ref_get_installed_size (FLATPAK_BUNDLE_REF (ref)); else if (FLATPAK_IS_INSTALLED_REF (ref)) installed_size = flatpak_installed_ref_get_installed_size (FLATPAK_INSTALLED_REF (ref)); if (component != NULL) { result = bz_appstream_parser_populate_entry (BZ_ENTRY (self), component, appstream_dir, remote_name, module_dir, unique_id_checksum, id, kinds, error); if (!result) return NULL; } g_object_get (self, "icon-paintable", &icon_paintable, NULL); if (icon_paintable == NULL) { if (FLATPAK_IS_BUNDLE_REF (ref)) { for (int size = 128; size > 0; size -= 64) { g_autoptr (GBytes) icon_bytes = NULL; GdkTexture *texture = NULL; icon_bytes = flatpak_bundle_ref_get_icon (FLATPAK_BUNDLE_REF (ref), size); if (icon_bytes == NULL) continue; texture = gdk_texture_new_from_bytes (icon_bytes, NULL); /* don't error out even if loading fails */ if (texture != NULL) { icon_paintable = (GdkPaintable *) g_steal_pointer (&texture); break; } } } else if (FLATPAK_IS_INSTALLED_REF (ref)) { BzStateInfo *state = NULL; const char *icon_name = NULL; GtkIconTheme *theme = NULL; GtkIconPaintable *paintable = NULL; state = bz_state_info_get_default (); icon_name = flatpak_ref_get_name (ref); theme = user ? bz_state_info_get_user_icon_theme (state) : bz_state_info_get_system_icon_theme (state); if (theme != NULL) { paintable = gtk_icon_theme_lookup_icon ( theme, icon_name, NULL, 128, 1, GTK_TEXT_DIR_NONE, 0); if (paintable != NULL) icon_paintable = (GdkPaintable *) g_steal_pointer (&paintable); } } } g_object_get (self, "title", &title, NULL); if (title == NULL) { if (self->application_name != NULL) title = self->application_name; else if (self->runtime_name != NULL) title = self->runtime_name; else title = self->flatpak_id; } if ((kinds & BZ_ENTRY_KIND_RUNTIME) && !(kinds & BZ_ENTRY_KIND_ADDON) && self->flatpak_version != NULL) { static GRegex *version_regex = NULL; g_autofree char *stripped_title = NULL; if (g_once_init_enter_pointer (&version_regex)) { g_autoptr (GRegex) re = NULL; /* GNOME runtimes have the flatpak version at the end whilst others don't. */ re = g_regex_new (VERSION_SUFFIX_REGEX, 0, 0, NULL); g_once_init_leave_pointer (&version_regex, g_steal_pointer (&re)); } stripped_title = g_regex_replace (version_regex, title, -1, 0, "", 0, NULL); title = g_strdup_printf ("%s %s", stripped_title, self->flatpak_version); } if (FLATPAK_IS_REMOTE_REF (ref)) eol = flatpak_remote_ref_get_eol (FLATPAK_REMOTE_REF (ref)); else if (FLATPAK_IS_INSTALLED_REF (ref)) eol = flatpak_installed_ref_get_eol (FLATPAK_INSTALLED_REF (ref)); permissions = bz_app_permissions_new_from_metadata (key_file, error); if (permissions == NULL) return NULL; searchable = !FLATPAK_IS_INSTALLED_REF (ref); g_object_set ( self, "kinds", kinds, "id", id, "unique-id", unique_id, "unique-id-checksum", unique_id_checksum, "title", title, "eol", eol, "remote-repo-name", remote_name, "size", download_size, "installed-size", installed_size, "icon-paintable", icon_paintable, "permissions", permissions, "searchable", searchable, NULL); return g_steal_pointer (&self); } char * bz_flatpak_ref_parts_format_unique (const char *origin, const char *fmt, gboolean user) { return g_strdup_printf ( "FLATPAK-%s::%s::%s", user ? "USER" : "SYSTEM", origin, fmt); } char * bz_flatpak_ref_format_unique (FlatpakRef *ref, gboolean user) { g_autofree char *fmt = NULL; const char *origin = NULL; fmt = flatpak_ref_format_ref (FLATPAK_REF (ref)); if (FLATPAK_IS_REMOTE_REF (ref)) origin = flatpak_remote_ref_get_remote_name (FLATPAK_REMOTE_REF (ref)); else if (FLATPAK_IS_BUNDLE_REF (ref)) origin = flatpak_bundle_ref_get_origin (FLATPAK_BUNDLE_REF (ref)); else if (FLATPAK_IS_INSTALLED_REF (ref)) origin = flatpak_installed_ref_get_origin (FLATPAK_INSTALLED_REF (ref)); return bz_flatpak_ref_parts_format_unique (origin, fmt, user); } FlatpakRef * bz_flatpak_entry_get_ref (BzFlatpakEntry *self) { g_return_val_if_fail (BZ_IS_FLATPAK_ENTRY (self), NULL); if (self->ref == NULL) self->ref = flatpak_ref_parse (self->flatpak_id, NULL); return self->ref; } char * bz_flatpak_id_format_unique (const char *flatpak_id, gboolean user) { g_autoptr (FlatpakRef) ref = NULL; ref = flatpak_ref_parse (flatpak_id, NULL); if (ref == NULL) return NULL; return bz_flatpak_ref_format_unique (ref, user); } gboolean bz_flatpak_entry_is_user (BzFlatpakEntry *self) { g_return_val_if_fail (BZ_IS_FLATPAK_ENTRY (self), FALSE); return self->user; } const char * bz_flatpak_entry_get_flatpak_name (BzFlatpakEntry *self) { g_return_val_if_fail (BZ_IS_FLATPAK_ENTRY (self), NULL); return self->flatpak_name; } const char * bz_flatpak_entry_get_flatpak_id (BzFlatpakEntry *self) { g_return_val_if_fail (BZ_IS_FLATPAK_ENTRY (self), NULL); return self->flatpak_id; } const char * bz_flatpak_entry_get_flatpak_version (BzFlatpakEntry *self) { g_return_val_if_fail (BZ_IS_FLATPAK_ENTRY (self), NULL); return self->flatpak_version; } const char * bz_flatpak_entry_get_application_name (BzFlatpakEntry *self) { g_return_val_if_fail (BZ_IS_FLATPAK_ENTRY (self), NULL); return self->application_name; } const char * bz_flatpak_entry_get_application_runtime (BzFlatpakEntry *self) { g_return_val_if_fail (BZ_IS_FLATPAK_ENTRY (self), NULL); return self->application_runtime; } const char * bz_flatpak_entry_get_runtime_name (BzFlatpakEntry *self) { g_return_val_if_fail (BZ_IS_FLATPAK_ENTRY (self), NULL); return self->runtime_name; } const char * bz_flatpak_entry_get_addon_extension_of_ref (BzFlatpakEntry *self) { g_return_val_if_fail (BZ_IS_FLATPAK_ENTRY (self), NULL); return self->addon_extension_of_ref; } gboolean bz_flatpak_entry_is_bundle (BzFlatpakEntry *self) { g_return_val_if_fail (BZ_IS_FLATPAK_ENTRY (self), FALSE); return self->is_bundle; } gboolean bz_flatpak_entry_is_installed_ref (BzFlatpakEntry *self) { g_return_val_if_fail (BZ_IS_FLATPAK_ENTRY (self), FALSE); return self->is_installed_ref; } gboolean bz_flatpak_entry_launch (BzFlatpakEntry *self, BzFlatpakInstance *flatpak, GError **error) { FlatpakRef *ref = NULL; #ifdef SANDBOXED_LIBFLATPAK g_autofree char *fmt = NULL; g_autofree char *cmdline = NULL; #else FlatpakInstallation *installation = NULL; #endif g_return_val_if_fail (BZ_IS_FLATPAK_ENTRY (self), FALSE); g_return_val_if_fail (BZ_IS_FLATPAK_INSTANCE (flatpak), FALSE); ref = bz_flatpak_entry_get_ref (self); #ifdef SANDBOXED_LIBFLATPAK fmt = flatpak_ref_format_ref (FLATPAK_REF (ref)); if (g_file_test ("/run/systemd", G_FILE_TEST_EXISTS)) cmdline = g_strdup_printf ("flatpak-spawn --host systemd-run --user --pipe flatpak run %s", fmt); else cmdline = g_strdup_printf ("flatpak-spawn --host flatpak run %s", fmt); return g_spawn_command_line_async (cmdline, error); #else installation = self->user ? bz_flatpak_instance_get_user_installation (flatpak) : bz_flatpak_instance_get_system_installation (flatpak); /* async? */ return flatpak_installation_launch ( installation, flatpak_ref_get_name (ref), flatpak_ref_get_arch (ref), flatpak_ref_get_branch (ref), flatpak_ref_get_commit (ref), NULL, error); #endif } static void clear_entry (BzFlatpakEntry *self) { g_clear_pointer (&self->flatpak_name, g_free); g_clear_pointer (&self->flatpak_id, g_free); g_clear_pointer (&self->flatpak_version, g_free); g_clear_pointer (&self->application_name, g_free); g_clear_pointer (&self->application_runtime, g_free); g_clear_pointer (&self->application_command, g_free); g_clear_pointer (&self->runtime_name, g_free); g_clear_pointer (&self->addon_extension_of_ref, g_free); g_clear_object (&self->runtime_result); } bazaar-orig-v0.7.14/src/bz-url.txt0000664000175000017500000000030115166123241015675 0ustar hasanhasanprefix=bz name=url parent-prefix=g parent-name=object author=AUTOGEN property=name char G_TYPE_STRING string property=url char G_TYPE_STRING string property=icon_name char G_TYPE_STRING string bazaar-orig-v0.7.14/src/bz-flathub-state.c0000664000175000017500000007733415166123241017265 0ustar hasanhasan/* bz-flathub-state.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::FLATHUB" #define COLLECTION_FETCH_SIZE 192 #define CATEGORY_FETCH_SIZE 48 #define QUALITY_MODERATION_PAGE_SIZE 300 #define KEYWORD_SEARCH_PAGE_SIZE 48 #define ADWAITA_URL "https://arewelibadwaitayet.com" #include #include #include "bz-env.h" #include "bz-flathub-category.h" #include "bz-flathub-state.h" #include "bz-global-net.h" #include "bz-io.h" #include "bz-serializable.h" #include "bz-util.h" struct _BzFlathubState { GObject parent_instance; char *for_day; BzApplicationMapFactory *map_factory; char *app_of_the_day; GtkStringList *apps_of_the_week; GListStore *categories; gboolean has_connection_error; DexFuture *initializing; }; typedef enum { QUALITY_MODE_NONE, QUALITY_MODE_FIRST, QUALITY_MODE_RANDOM } QualityMode; static void serializable_iface_init (BzSerializableInterface *iface); G_DEFINE_FINAL_TYPE_WITH_CODE ( BzFlathubState, bz_flathub_state, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (BZ_TYPE_SERIALIZABLE, serializable_iface_init)) static GListModel *bz_flathub_state_dup_apps_of_the_day_week (BzFlathubState *self); enum { PROP_0, PROP_FOR_DAY, PROP_MAP_FACTORY, PROP_APP_OF_THE_DAY, PROP_APP_OF_THE_DAY_GROUP, PROP_APPS_OF_THE_WEEK, PROP_APPS_OF_THE_DAY_WEEK, PROP_CATEGORIES, PROP_HAS_CONNECTION_ERROR, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static DexFuture * initialize_fiber (GWeakRef *wr); static DexFuture * initialize_finally (DexFuture *future, GWeakRef *wr); static void notify_all (BzFlathubState *self); static void clear (BzFlathubState *self); static void bz_flathub_state_dispose (GObject *object) { BzFlathubState *self = BZ_FLATHUB_STATE (object); dex_clear (&self->initializing); g_clear_pointer (&self->map_factory, g_object_unref); clear (self); G_OBJECT_CLASS (bz_flathub_state_parent_class)->dispose (object); } static void bz_flathub_state_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzFlathubState *self = BZ_FLATHUB_STATE (object); switch (prop_id) { case PROP_FOR_DAY: g_value_set_string (value, bz_flathub_state_get_for_day (self)); break; case PROP_MAP_FACTORY: g_value_set_object (value, bz_flathub_state_get_map_factory (self)); break; case PROP_APP_OF_THE_DAY: g_value_set_string (value, bz_flathub_state_get_app_of_the_day (self)); break; case PROP_APP_OF_THE_DAY_GROUP: g_value_take_object (value, bz_flathub_state_dup_app_of_the_day_group (self)); break; case PROP_APPS_OF_THE_WEEK: g_value_take_object (value, bz_flathub_state_dup_apps_of_the_week (self)); break; case PROP_APPS_OF_THE_DAY_WEEK: g_value_take_object (value, bz_flathub_state_dup_apps_of_the_day_week (self)); break; case PROP_CATEGORIES: g_value_set_object (value, bz_flathub_state_get_categories (self)); break; case PROP_HAS_CONNECTION_ERROR: g_value_set_boolean (value, bz_flathub_state_get_has_connection_error (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_flathub_state_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzFlathubState *self = BZ_FLATHUB_STATE (object); switch (prop_id) { case PROP_FOR_DAY: dex_future_disown (bz_flathub_state_set_for_day (self, g_value_get_string (value))); break; case PROP_MAP_FACTORY: bz_flathub_state_set_map_factory (self, g_value_get_object (value)); break; case PROP_APP_OF_THE_DAY: case PROP_APP_OF_THE_DAY_GROUP: case PROP_APPS_OF_THE_WEEK: case PROP_APPS_OF_THE_DAY_WEEK: case PROP_CATEGORIES: case PROP_HAS_CONNECTION_ERROR: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_flathub_state_class_init (BzFlathubStateClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bz_flathub_state_set_property; object_class->get_property = bz_flathub_state_get_property; object_class->dispose = bz_flathub_state_dispose; props[PROP_FOR_DAY] = g_param_spec_string ( "for-day", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_MAP_FACTORY] = g_param_spec_object ( "map-factory", NULL, NULL, BZ_TYPE_APPLICATION_MAP_FACTORY, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_APP_OF_THE_DAY] = g_param_spec_string ( "app-of-the-day", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_APP_OF_THE_DAY_GROUP] = g_param_spec_object ( "app-of-the-day-group", NULL, NULL, BZ_TYPE_ENTRY_GROUP, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_APPS_OF_THE_WEEK] = g_param_spec_object ( "apps-of-the-week", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_APPS_OF_THE_DAY_WEEK] = g_param_spec_object ( "apps-of-the-day-week", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_CATEGORIES] = g_param_spec_object ( "categories", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_HAS_CONNECTION_ERROR] = g_param_spec_boolean ( "has-connection-error", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_flathub_state_init (BzFlathubState *self) { } static void bz_flathub_state_real_serialize (BzSerializable *serializable, GVariantBuilder *builder) { BzFlathubState *self = BZ_FLATHUB_STATE (serializable); if (self->initializing != NULL && dex_future_is_pending (self->initializing)) return; if (self->for_day != NULL) g_variant_builder_add (builder, "{sv}", "for-day", g_variant_new_string (self->for_day)); if (self->app_of_the_day != NULL) g_variant_builder_add (builder, "{sv}", "app-of-the-day", g_variant_new_string (self->app_of_the_day)); if (self->apps_of_the_week != NULL) { guint n_items = 0; n_items = g_list_model_get_n_items (G_LIST_MODEL (self->apps_of_the_week)); if (n_items > 0) { g_autoptr (GVariantBuilder) sub_builder = NULL; sub_builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); for (guint i = 0; i < n_items; i++) { const char *string = NULL; string = gtk_string_list_get_string (self->apps_of_the_week, i); g_variant_builder_add (sub_builder, "s", string); } g_variant_builder_add (builder, "{sv}", "apps-of-the-week", g_variant_builder_end (sub_builder)); } } if (self->categories != NULL) { guint n_items = 0; n_items = g_list_model_get_n_items (G_LIST_MODEL (self->categories)); if (n_items > 0) { g_autoptr (GVariantBuilder) sub_builder = NULL; sub_builder = g_variant_builder_new (G_VARIANT_TYPE ("av")); for (guint i = 0; i < n_items; i++) { g_autoptr (BzFlathubCategory) category = NULL; g_autoptr (GVariantBuilder) category_builder = NULL; category = g_list_model_get_item (G_LIST_MODEL (self->categories), i); category_builder = g_variant_builder_new (G_VARIANT_TYPE_VARDICT); bz_serializable_serialize (BZ_SERIALIZABLE (category), category_builder); g_variant_builder_add (sub_builder, "v", g_variant_builder_end (category_builder)); } g_variant_builder_add (builder, "{sv}", "categories", g_variant_builder_end (sub_builder)); } } } static gboolean bz_flathub_state_real_deserialize (BzSerializable *serializable, GVariant *import, GError **error) { BzFlathubState *self = BZ_FLATHUB_STATE (serializable); gboolean result = FALSE; g_autoptr (GVariantIter) iter = NULL; if (self->initializing != NULL && !dex_future_is_pending (self->initializing)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_BUSY, "Cannot perform serialization operations while initializing!"); return FALSE; } clear (self); iter = g_variant_iter_new (import); for (;;) { g_autofree char *key = NULL; g_autoptr (GVariant) value = NULL; /* TODO automate this, this is awful */ if (!g_variant_iter_next (iter, "{sv}", &key, &value)) break; if (g_strcmp0 (key, "for-day") == 0) self->for_day = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "app-of-the-day") == 0) self->app_of_the_day = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "apps-of-the-week") == 0) { g_autoptr (GtkStringList) list = NULL; g_autoptr (GVariantIter) list_iter = NULL; list = gtk_string_list_new (NULL); list_iter = g_variant_iter_new (value); for (;;) { g_autofree char *id = NULL; if (!g_variant_iter_next (list_iter, "s", &id)) break; gtk_string_list_append (list, id); } self->apps_of_the_week = g_steal_pointer (&list); } else if (g_strcmp0 (key, "categories") == 0) { g_autoptr (GListStore) categories = NULL; g_autoptr (GVariantIter) categories_iter = NULL; categories = g_list_store_new (BZ_TYPE_FLATHUB_CATEGORY); categories_iter = g_variant_iter_new (value); for (;;) { g_autoptr (GVariant) category_import = NULL; g_autoptr (BzFlathubCategory) category = NULL; if (!g_variant_iter_next (categories_iter, "v", &category_import)) break; category = bz_flathub_category_new (); result = bz_serializable_deserialize ( BZ_SERIALIZABLE (category), category_import, error); if (!result) return FALSE; g_object_bind_property (self, "map-factory", category, "map-factory", G_BINDING_SYNC_CREATE); g_list_store_append (categories, category); } self->categories = g_steal_pointer (&categories); } } notify_all (self); return TRUE; } static void serializable_iface_init (BzSerializableInterface *iface) { iface->serialize = bz_flathub_state_real_serialize; iface->deserialize = bz_flathub_state_real_deserialize; } BzFlathubState * bz_flathub_state_new (void) { return g_object_new (BZ_TYPE_FLATHUB_STATE, NULL); } const char * bz_flathub_state_get_for_day (BzFlathubState *self) { g_return_val_if_fail (BZ_IS_FLATHUB_STATE (self), NULL); return self->for_day; } BzApplicationMapFactory * bz_flathub_state_get_map_factory (BzFlathubState *self) { g_return_val_if_fail (BZ_IS_FLATHUB_STATE (self), NULL); return self->map_factory; } const char * bz_flathub_state_get_app_of_the_day (BzFlathubState *self) { g_return_val_if_fail (BZ_IS_FLATHUB_STATE (self), NULL); if (self->initializing != NULL && dex_future_is_pending (self->initializing)) return NULL; return self->app_of_the_day; } BzEntryGroup * bz_flathub_state_dup_app_of_the_day_group (BzFlathubState *self) { g_autoptr (GtkStringObject) string = NULL; g_return_val_if_fail (BZ_IS_FLATHUB_STATE (self), NULL); if (self->initializing != NULL && dex_future_is_pending (self->initializing)) return NULL; g_return_val_if_fail (self->map_factory != NULL, NULL); string = gtk_string_object_new (self->app_of_the_day); return bz_application_map_factory_convert_one (self->map_factory, string); } GListModel * bz_flathub_state_dup_apps_of_the_week (BzFlathubState *self) { g_return_val_if_fail (BZ_IS_FLATHUB_STATE (self), NULL); if (self->initializing != NULL && dex_future_is_pending (self->initializing)) return NULL; if (self->apps_of_the_week != NULL) { if (self->map_factory != NULL) return bz_application_map_factory_generate ( self->map_factory, G_LIST_MODEL (self->apps_of_the_week)); else return G_LIST_MODEL (g_object_ref (self->apps_of_the_week)); } else return NULL; } GListModel * bz_flathub_state_dup_apps_of_the_day_week (BzFlathubState *self) { g_autoptr (GtkStringList) combined_list = NULL; g_return_val_if_fail (BZ_IS_FLATHUB_STATE (self), NULL); if (self->initializing != NULL && dex_future_is_pending (self->initializing)) return NULL; combined_list = gtk_string_list_new (NULL); if (self->app_of_the_day != NULL) gtk_string_list_append (combined_list, self->app_of_the_day); if (self->apps_of_the_week != NULL) { guint n_items = g_list_model_get_n_items (G_LIST_MODEL (self->apps_of_the_week)); for (guint i = 0; i < n_items; i++) { const char *app_id = gtk_string_list_get_string (self->apps_of_the_week, i); gtk_string_list_append (combined_list, app_id); } } if (self->map_factory != NULL) return bz_application_map_factory_generate (self->map_factory, G_LIST_MODEL (combined_list)); else return G_LIST_MODEL (g_object_ref (combined_list)); } GListModel * bz_flathub_state_get_categories (BzFlathubState *self) { g_return_val_if_fail (BZ_IS_FLATHUB_STATE (self), NULL); if (self->initializing != NULL && dex_future_is_pending (self->initializing)) return NULL; return G_LIST_MODEL (self->categories); } gboolean bz_flathub_state_get_has_connection_error (BzFlathubState *self) { g_return_val_if_fail (BZ_IS_FLATHUB_STATE (self), FALSE); return self->has_connection_error; } DexFuture * bz_flathub_state_set_for_day (BzFlathubState *self, const char *for_day) { dex_return_error_if_fail (BZ_IS_FLATHUB_STATE (self)); dex_clear (&self->initializing); clear (self); if (for_day != NULL) { g_autoptr (DexFuture) future = NULL; self->for_day = g_strdup (for_day); self->apps_of_the_week = gtk_string_list_new (NULL); self->categories = g_list_store_new (BZ_TYPE_FLATHUB_CATEGORY); future = dex_scheduler_spawn ( bz_get_io_scheduler (), bz_get_dex_stack_size (), (DexFiberFunc) initialize_fiber, bz_track_weak (self), bz_weak_release); future = dex_future_finally ( future, (DexFutureCallback) initialize_finally, bz_track_weak (self), bz_weak_release); self->initializing = g_steal_pointer (&future); return dex_ref (self->initializing); } else { notify_all (self); return dex_future_new_false (); } } DexFuture * bz_flathub_state_update_to_today (BzFlathubState *self) { g_autoptr (GDateTime) datetime = NULL; g_autofree gchar *for_day = NULL; dex_return_error_if_fail (BZ_IS_FLATHUB_STATE (self)); datetime = g_date_time_new_now_utc (); for_day = g_date_time_format (datetime, "%F"); g_debug ("Syncing with flathub for day: %s", for_day); return bz_flathub_state_set_for_day (self, for_day); } void bz_flathub_state_set_map_factory (BzFlathubState *self, BzApplicationMapFactory *map_factory) { g_return_if_fail (BZ_IS_FLATHUB_STATE (self)); g_return_if_fail (map_factory == NULL || BZ_IS_APPLICATION_MAP_FACTORY (map_factory)); g_clear_object (&self->map_factory); if (map_factory != NULL) self->map_factory = g_object_ref (map_factory); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MAP_FACTORY]); } static gboolean is_kde_plasma (void) { const char *desktop = g_getenv ("XDG_CURRENT_DESKTOP"); if (desktop == NULL) return FALSE; return g_str_equal (desktop, "KDE") || g_strstr_len (desktop, -1, "KDE") != NULL; } static void add_category (BzFlathubState *self, const char *name, JsonNode *node, GHashTable *quality_set, gboolean is_json_object, QualityMode quality_mode, gboolean is_spotlight) { JsonObject *object = NULL; JsonObjectIter iter = { 0 }; JsonArray *hits_array = NULL; const char *key = NULL; const char *app = NULL; g_autoptr (BzFlathubCategory) category = NULL; g_autoptr (GtkStringList) store = NULL; g_autoptr (GtkStringList) quality_store = NULL; g_autoptr (GPtrArray) quality_apps = NULL; guint app_count = 0; guint quality_count = 0; guint random_index = 0; guint i = 0; int total_entries = 0; category = bz_flathub_category_new (); store = gtk_string_list_new (NULL); quality_store = gtk_string_list_new (NULL); bz_flathub_category_set_name (category, name); bz_flathub_category_set_is_spotlight (category, is_spotlight); bz_flathub_category_set_applications (category, G_LIST_MODEL (store)); object = json_node_get_object (node); if (is_json_object) { if (quality_mode == QUALITY_MODE_RANDOM) quality_apps = g_ptr_array_new_with_free_func (g_free); json_object_iter_init (&iter, object); while (json_object_iter_next (&iter, &key, NULL)) { gtk_string_list_append (store, key); if (g_hash_table_contains (quality_set, key)) { if (quality_mode == QUALITY_MODE_RANDOM) g_ptr_array_add (quality_apps, g_strdup (key)); else if (quality_mode == QUALITY_MODE_FIRST) gtk_string_list_append (quality_store, key); } app_count++; } total_entries = json_object_get_size (object); } else { if (quality_mode == QUALITY_MODE_RANDOM) quality_apps = g_ptr_array_new_with_free_func (g_free); hits_array = json_object_get_array_member (object, "hits"); app_count = json_array_get_length (hits_array); for (i = 0; i < app_count; i++) { JsonObject *element = NULL; const char *app_id = NULL; element = json_array_get_object_element (hits_array, i); app_id = json_object_get_string_member (element, "app_id"); gtk_string_list_append (store, app_id); if (g_hash_table_contains (quality_set, app_id)) { if (quality_mode == QUALITY_MODE_RANDOM) g_ptr_array_add (quality_apps, g_strdup (app_id)); else if (quality_mode == QUALITY_MODE_FIRST) gtk_string_list_append (quality_store, app_id); } } total_entries = json_object_get_int_member (object, "totalHits"); } if (quality_mode == QUALITY_MODE_RANDOM && quality_apps != NULL) { quality_count = MIN (7, quality_apps->len); for (i = 0; i < quality_count; i++) { random_index = g_random_int_range (0, quality_apps->len); app = g_ptr_array_index (quality_apps, random_index); gtk_string_list_append (quality_store, app); g_ptr_array_remove_index_fast (quality_apps, random_index); } } bz_flathub_category_set_total_entries (category, total_entries); bz_flathub_category_set_quality_applications (category, G_LIST_MODEL (quality_store)); g_list_store_append (self->categories, category); } static DexFuture * initialize_fiber (GWeakRef *wr) { g_autoptr (BzFlathubState) self = NULL; g_autoptr (GError) local_error = NULL; gboolean result = FALSE; gboolean is_kde = is_kde_plasma (); g_autoptr (GHashTable) quality_set = NULL; g_autoptr (DexFuture) aotd_f = NULL; g_autoptr (DexFuture) aotw_f = NULL; g_autoptr (DexFuture) categories_f = NULL; g_autoptr (DexFuture) updated_f = NULL; g_autoptr (DexFuture) added_f = NULL; g_autoptr (DexFuture) popular_f = NULL; g_autoptr (DexFuture) trending_f = NULL; g_autoptr (DexFuture) mobile_f = NULL; g_autoptr (DexFuture) passing_f = NULL; g_autoptr (DexFuture) adwaita_f = NULL; g_autoptr (DexFuture) toolkit_f = NULL; bz_weak_get_or_return_reject (self, wr); quality_set = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); #define ADD_REQUEST(_var, ...) \ G_STMT_START \ { \ g_autofree char *_request = NULL; \ \ _request = g_strdup_printf (__VA_ARGS__); \ (_var) = bz_query_flathub_v2_json_take (g_steal_pointer (&_request)); \ if (!dex_await (dex_ref ((_var)), &local_error)) \ { \ g_warning ("Failed to complete request to flathub: %s", local_error->message); \ return dex_future_new_for_error (g_steal_pointer (&local_error)); \ } \ } \ G_STMT_END if (is_kde) ADD_REQUEST (toolkit_f, "/collection/developer/kde?locale=en"); else { adwaita_f = bz_https_query_json (ADWAITA_URL "/api/apps"); if (!dex_await (dex_ref (adwaita_f), &local_error)) { g_warning ("Failed to complete request to arewelibadwaitayet: %s", local_error->message); g_clear_error (&local_error); adwaita_f = NULL; } } ADD_REQUEST (passing_f, "/quality-moderation/passing-apps?page=1&page_size=%d", QUALITY_MODERATION_PAGE_SIZE); ADD_REQUEST (aotd_f, "/app-picks/app-of-the-day/%s", self->for_day); ADD_REQUEST (aotw_f, "/app-picks/apps-of-the-week/%s", self->for_day); ADD_REQUEST (categories_f, "/collection/category"); ADD_REQUEST (updated_f, "/collection/recently-updated?page=0&per_page=%d", COLLECTION_FETCH_SIZE); ADD_REQUEST (added_f, "/collection/recently-added?page=0&per_page=%d", COLLECTION_FETCH_SIZE); ADD_REQUEST (popular_f, "/collection/popular?page=0&per_page=%d", COLLECTION_FETCH_SIZE); ADD_REQUEST (trending_f, "/collection/trending?page=0&per_page=%d", COLLECTION_FETCH_SIZE); ADD_REQUEST (mobile_f, "/collection/mobile?page=0&per_page=%d", COLLECTION_FETCH_SIZE); #undef ADD_REQUEST #define GET_BOXED(_future) g_value_get_boxed (dex_future_get_value ((_future), NULL)) { JsonObject *object = NULL; JsonArray *array = NULL; guint length = 0; object = json_node_get_object (GET_BOXED (passing_f)); array = json_object_get_array_member (object, "apps"); length = json_array_get_length (array); for (guint i = 0; i < length; i++) { const char *app_id = NULL; app_id = json_array_get_string_element (array, i); g_hash_table_replace (quality_set, g_strdup (app_id), NULL); } } { JsonObject *object = NULL; object = json_node_get_object (GET_BOXED (aotd_f)); self->app_of_the_day = g_strdup (json_object_get_string_member (object, "app_id")); } { JsonObject *object = NULL; JsonArray *array = NULL; guint length = 0; object = json_node_get_object (GET_BOXED (aotw_f)); array = json_object_get_array_member (object, "apps"); length = json_array_get_length (array); for (guint i = 0; i < length; i++) { JsonObject *element = NULL; element = json_array_get_object_element (array, i); gtk_string_list_append ( self->apps_of_the_week, json_object_get_string_member (element, "app_id")); } } add_category (self, "trending", GET_BOXED (trending_f), quality_set, FALSE, QUALITY_MODE_NONE, TRUE); add_category (self, "popular", GET_BOXED (popular_f), quality_set, FALSE, QUALITY_MODE_NONE, TRUE); add_category (self, "recently-added", GET_BOXED (added_f), quality_set, FALSE, QUALITY_MODE_NONE, TRUE); add_category (self, "recently-updated", GET_BOXED (updated_f), quality_set, FALSE, QUALITY_MODE_NONE, TRUE); add_category (self, "mobile", GET_BOXED (mobile_f), quality_set, FALSE, QUALITY_MODE_NONE, TRUE); { static const char *categories[] = { "audiovideo", "development", "education", "game", "graphics", "network", "office", "science", "system", "utility" }; g_autoptr (GPtrArray) category_futures = NULL; category_futures = g_ptr_array_new_with_free_func (dex_unref); for (guint i = 0; i < G_N_ELEMENTS (categories); i++) { g_autofree char *request = NULL; g_autoptr (DexFuture) future = NULL; request = g_strdup_printf ( "/collection/category/%s?page=0&per_page=%d", categories[i], CATEGORY_FETCH_SIZE); future = bz_query_flathub_v2_json_take (g_steal_pointer (&request)); result = dex_await (dex_ref (future), &local_error); if (!result) { g_warning ("Failed to complete request to flathub: %s", local_error->message); return dex_future_new_for_error (g_steal_pointer (&local_error)); } g_ptr_array_add (category_futures, dex_ref (future)); } for (guint i = 0; i < G_N_ELEMENTS (categories); i++) { DexFuture *future = NULL; JsonNode *node = NULL; future = g_ptr_array_index (category_futures, i); node = GET_BOXED (future); add_category (self, categories[i], node, quality_set, FALSE, QUALITY_MODE_FIRST, FALSE); } } if (is_kde) add_category (self, "kde", GET_BOXED (toolkit_f), quality_set, FALSE, QUALITY_MODE_RANDOM, FALSE); else if (adwaita_f != NULL) add_category (self, "adwaita", GET_BOXED (adwaita_f), quality_set, TRUE, QUALITY_MODE_RANDOM, FALSE); return dex_future_new_true (); } static DexFuture * initialize_finally (DexFuture *future, GWeakRef *wr) { g_autoptr (BzFlathubState) self = NULL; bz_weak_get_or_return_reject (self, wr); if (dex_future_is_resolved (future)) { guint n_categories = 0; n_categories = g_list_model_get_n_items (G_LIST_MODEL (self->categories)); for (guint i = 0; i < n_categories; i++) { g_autoptr (BzFlathubCategory) category = NULL; category = g_list_model_get_item (G_LIST_MODEL (self->categories), i); g_object_bind_property (self, "map-factory", category, "map-factory", G_BINDING_SYNC_CREATE); } g_debug ("Done syncing flathub state; notifying property listeners..."); notify_all (self); } else clear (self); return dex_ref (future); } static DexFuture * search_collection_fiber (char *route) { g_autoptr (GError) local_error = NULL; g_autoptr (GtkStringList) results = NULL; g_autoptr (JsonNode) node = NULL; g_autofree char *request = NULL; JsonObject *object = NULL; JsonArray *array = NULL; guint length = 0; request = g_strdup_printf ("%s&page=1&per_page=%d&locale=en", route, KEYWORD_SEARCH_PAGE_SIZE); node = dex_await_boxed ( bz_query_flathub_v2_json_take ( g_steal_pointer (&request)), &local_error); if (node == NULL) return dex_future_new_for_error (g_steal_pointer (&local_error)); results = gtk_string_list_new (NULL); object = json_node_get_object (node); array = json_object_get_array_member (object, "hits"); length = json_array_get_length (array); for (guint i = 0; i < length; i++) { JsonObject *element = NULL; const char *app_id = NULL; element = json_array_get_object_element (array, i); app_id = json_object_get_string_member (element, "app_id"); gtk_string_list_append (results, app_id); } return dex_future_new_take_object (g_steal_pointer (&results)); } static DexFuture * search_collection_finally (DexFuture *future, GWeakRef *wr) { g_autoptr (BzFlathubState) self = NULL; const GValue *value = NULL; GListModel *model = NULL; bz_weak_get_or_return_reject (self, wr); value = dex_future_get_value (future, NULL); if (value == NULL) return dex_ref (future); model = g_value_get_object (value); if (self->map_factory != NULL) return dex_future_new_take_object ( bz_application_map_factory_generate (self->map_factory, model)); return dex_ref (future); } DexFuture * bz_flathub_state_search_collection (BzFlathubState *self, const char *route) { g_autoptr (DexFuture) future = NULL; dex_return_error_if_fail (BZ_IS_FLATHUB_STATE (self)); dex_return_error_if_fail (route != NULL); future = dex_scheduler_spawn ( bz_get_io_scheduler (), bz_get_dex_stack_size (), (DexFiberFunc) search_collection_fiber, g_strdup (route), g_free); future = dex_future_finally ( future, (DexFutureCallback) search_collection_finally, bz_track_weak (self), bz_weak_release); return g_steal_pointer (&future); } static void notify_all (BzFlathubState *self) { g_object_notify_by_pspec (G_OBJECT (self), props[PROP_FOR_DAY]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_HAS_CONNECTION_ERROR]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_APP_OF_THE_DAY]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_APP_OF_THE_DAY_GROUP]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_APPS_OF_THE_WEEK]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_APPS_OF_THE_DAY_WEEK]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CATEGORIES]); } static void clear (BzFlathubState *self) { g_clear_pointer (&self->for_day, g_free); g_clear_pointer (&self->app_of_the_day, g_free); g_clear_pointer (&self->apps_of_the_week, g_object_unref); g_clear_pointer (&self->categories, g_object_unref); self->has_connection_error = FALSE; } /* End of bz-flathub-state.c */ bazaar-orig-v0.7.14/src/bz-rich-app-tile.c0000664000175000017500000002164215166123241017147 0ustar hasanhasan/* bz-rich-app-tile.c * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-rich-app-tile.h" #include "bz-entry.h" #include "bz-rounded-picture.h" #include "bz-themed-entry-group-rect.h" #include "bz-util.h" #include struct _BzRichAppTile { BzListTile parent_instance; BzEntryGroup *group; BzEntry *ui_entry; DexFuture *ui_entry_resolve; gboolean removable_at_start; GtkWidget *picture_box; }; G_DEFINE_FINAL_TYPE (BzRichAppTile, bz_rich_app_tile, BZ_TYPE_LIST_TILE); enum { PROP_0, PROP_GROUP, PROP_UI_ENTRY, PROP_REMOVABLE_AT_START, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void update_ui_entry (BzRichAppTile *self); static DexFuture * ui_entry_resolved_finally (DexFuture *future, GWeakRef *wr) { g_autoptr (BzRichAppTile) self = NULL; const GValue *value = NULL; bz_weak_get_or_return_reject (self, wr); value = dex_future_get_value (future, NULL); if (value != NULL) { BzEntry *ui_entry = g_value_get_object (value); g_set_object (&self->ui_entry, ui_entry); } else { g_clear_object (&self->ui_entry); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_UI_ENTRY]); return NULL; } static void update_ui_entry (BzRichAppTile *self) { g_autoptr (BzResult) ui_entry_result = NULL; dex_clear (&self->ui_entry_resolve); if (self->ui_entry != NULL) { g_clear_object (&self->ui_entry); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_UI_ENTRY]); } ui_entry_result = bz_entry_group_dup_ui_entry (self->group); self->ui_entry_resolve = dex_future_finally ( bz_result_dup_future (ui_entry_result), (DexFutureCallback) ui_entry_resolved_finally, bz_track_weak (self), bz_weak_release); } static void bz_rich_app_tile_dispose (GObject *object) { BzRichAppTile *self = BZ_RICH_APP_TILE (object); g_clear_object (&self->group); g_clear_object (&self->ui_entry); dex_clear (&self->ui_entry_resolve); G_OBJECT_CLASS (bz_rich_app_tile_parent_class)->dispose (object); } static void bz_rich_app_tile_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzRichAppTile *self = BZ_RICH_APP_TILE (object); switch (prop_id) { case PROP_GROUP: g_value_set_object (value, bz_rich_app_tile_get_group (self)); break; case PROP_UI_ENTRY: g_value_set_object (value, self->ui_entry); break; case PROP_REMOVABLE_AT_START: g_value_set_boolean (value, self->removable_at_start); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_rich_app_tile_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzRichAppTile *self = BZ_RICH_APP_TILE (object); switch (prop_id) { case PROP_GROUP: bz_rich_app_tile_set_group (self, g_value_get_object (value)); break; case PROP_UI_ENTRY: case PROP_REMOVABLE_AT_START: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static gboolean is_null (gpointer object, GObject *value) { return value == NULL; } static gboolean is_zero (gpointer object, int value) { return value == 0; } static gboolean logical_and (gpointer object, gboolean value1, gboolean value2) { return value1 && value2; } static void install_button_clicked_cb (BzRichAppTile *self, GtkButton *button) { gtk_widget_activate_action (GTK_WIDGET (self), "window.install-group", "(sb)", bz_entry_group_get_id (self->group), FALSE); } static void remove_button_clicked_cb (BzRichAppTile *self, GtkButton *button) { gtk_widget_activate_action (GTK_WIDGET (self), "window.remove-group", "(sb)", bz_entry_group_get_id (self->group), FALSE); } static void run_button_clicked_cb (BzRichAppTile *self, GtkButton *button) { gtk_widget_activate_action (GTK_WIDGET (self), "window.launch-group", "s", bz_entry_group_get_id (self->group)); } static void bz_rich_app_tile_class_init (BzRichAppTileClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bz_rich_app_tile_set_property; object_class->get_property = bz_rich_app_tile_get_property; object_class->dispose = bz_rich_app_tile_dispose; props[PROP_GROUP] = g_param_spec_object ( "group", NULL, NULL, BZ_TYPE_ENTRY_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_UI_ENTRY] = g_param_spec_object ( "ui-entry", NULL, NULL, BZ_TYPE_ENTRY, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_REMOVABLE_AT_START] = g_param_spec_boolean ( "removable-at-start", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_LIST_TILE); g_type_ensure (BZ_TYPE_ROUNDED_PICTURE); g_type_ensure (BZ_TYPE_THEMED_ENTRY_GROUP_RECT); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-rich-app-tile.ui"); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, is_null); gtk_widget_class_bind_template_callback (widget_class, is_zero); gtk_widget_class_bind_template_callback (widget_class, logical_and); gtk_widget_class_bind_template_callback (widget_class, install_button_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, remove_button_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, run_button_clicked_cb); gtk_widget_class_bind_template_child (widget_class, BzRichAppTile, picture_box); gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_BUTTON); } static void bz_rich_app_tile_init (BzRichAppTile *self) { gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_rich_app_tile_new (void) { return g_object_new (BZ_TYPE_RICH_APP_TILE, NULL); } BzEntryGroup * bz_rich_app_tile_get_group (BzRichAppTile *self) { g_return_val_if_fail (BZ_IS_RICH_APP_TILE (self), NULL); return self->group; } void bz_rich_app_tile_set_group (BzRichAppTile *self, BzEntryGroup *group) { const char *title = NULL; gboolean verified = FALSE; gboolean removable_at_start = FALSE; g_autofree char *label = NULL; g_return_if_fail (BZ_IS_RICH_APP_TILE (self)); g_clear_object (&self->group); if (group != NULL) { self->group = g_object_ref (group); title = bz_entry_group_get_title (self->group); verified = bz_entry_group_get_is_verified (self->group); removable_at_start = bz_entry_group_get_removable (self->group) != 0; if (self->removable_at_start != removable_at_start) { self->removable_at_start = removable_at_start; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_REMOVABLE_AT_START]); } if (verified) { label = g_strdup_printf ("%s, %s", title, _ ("Verified")); gtk_accessible_update_property (GTK_ACCESSIBLE (self), GTK_ACCESSIBLE_PROPERTY_LABEL, label, -1); } else { gtk_accessible_update_property (GTK_ACCESSIBLE (self), GTK_ACCESSIBLE_PROPERTY_LABEL, title, -1); } } update_ui_entry (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_GROUP]); } /* End of bz-rich-app-tile.c */ bazaar-orig-v0.7.14/src/style.css0000664000175000017500000004575715166123241015623 0ustar hasanhasan.bz-monospace { font-family: monospace; } .bz-debug { background: linear-gradient(to top, #ffaf4c, #ffc04c); border-color: black; border-radius: 6px; border-style: solid; border-width: 1px; color: black; padding: 3px; } .bz-debug button { border-color: black; border-style: dashed; border-width: 1px; border-radius: 3px; padding-top: 0px; padding-bottom: 0px; padding-left: 2px; padding-right: 2px; } .bz-donations-dialog { background: linear-gradient(to bottom left, #1f2d8f, #159eff); color: white; } .bz-donations-banner { --banner-color: var(--accent-bg-color); } .updates-amount { background-color: white; color: var(--accent-bg-color); font-size: 0.60em; border-radius: 9999px; font-weight: 900; } .updates-amount-border { background-color: var(--accent-bg-color); border-radius: 9999px; } .search-box { outline: 0 solid transparent; outline-offset: 6px; transition-property: outline, outline-offset; transition-duration: 200ms; padding: 8px 12px; border-radius: 9999px; background-color: var(--card-bg-color); } .search-box:focus-within { outline-color: color-mix(in srgb, var(--accent-color), transparent); outline-offset: 0; outline-width: 2px; } @media (prefers-color-scheme: light) { .search-box { background-color: var(--shade-color); } } .search-box > text placeholder { opacity: 0.55; } .searchbar-button, .searchbar-button > button { min-height: 24px; min-width: 24px; } .search-pill { font-weight: 450; } .search-grid { background-color: var(--window-bg-color); } .search-grid > child { padding: 0; margin: 6px 6px; border-radius: 12px; transition: background-color 200ms; } .narrow .search-grid > child { margin: 6px 12px; } .card-row-btn { border-radius: 0; } .screenshot { border-radius: 20px; } .browser-banner { border-radius: 25px; background-color: transparent; } .browser-banner-title { font-size: 3.2em; font-weight: bolder; } .browser-banner-subtitle { font-size: 2.0em; font-weight: bold; } .browser-banner-description { font-size: 1.33em; font-weight: normal; } .installed-size { font-weight: 500; } .verified { color: @blue_2; } .app-developer link{ color: @blue_2; text-decoration: none; } .support { --accent-fg-color : #f06292; --accent-bg-color : alpha(#f06292, 0.25); --accent-color : #f06292; } .favorite { --accent-fg-color: @accent_bg_color; --accent-bg-color : alpha(@accent_bg_color, 0.25); --accent-color: @accent_color; } .favorite * { --accent-fg-color: @accent_fg_color; --accent-bg-color: @accent_bg_color; --accent-color: @accent_color; } .orange { --accent-fg-color: @orange_5; --accent-color: alpha(@orange_5, 0.25); --accent-bg-color: @orange_5; } .green { --accent-fg-color : #8ff0a4; --accent-bg-color : alpha(#2ec27e, 0.25); --accent-color : #8ff0a4; } .blue { --accent-fg-color : #99c1f1; --accent-bg-color : alpha(#1a5fb4, 0.25); --accent-color : #99c1f1; } .dark-blue { --accent-fg-color : #99c1f1; --accent-bg-color : #1a5fb4; --accent-color : #99c1f1; } @media (prefers-color-scheme: light) { .green { --accent-fg-color : #2ec27e; --accent-bg-color : alpha(#8ff0a4, 0.25); --accent-color : #2ec27e; } .blue { --accent-fg-color : #1a5fb4; --accent-bg-color : alpha(#99c1f1, 0.25); --accent-color : #1a5fb4; } .dark-blue { --accent-fg-color : #1C71D8; --accent-bg-color : #1C71D8; --accent-color : #1C71D8; } } .grey { --accent-color: alpha(@window_fg_color,0.75); --accent-bg-color: @window_fg_color; } .grey.colored { --accent-fg-color : @window_fg_color; --accent-bg-color : alpha(@window_fg_color,0.05); --accent-color : alpha(@window_fg_color,0.75); } .circular-lozenge.green, .lozenge.green { color: @green_5; background-color: alpha(@green_3, .25); } .circular-lozenge.yellow, .lozenge.yellow { color: #ae7b03; background: alpha(@yellow_5, .25); } .circular-lozenge.orange, .lozenge.orange { color: @orange_5; background-color: alpha(@orange_4, .25); } .circular-lozenge.red, .lozenge.red { color: @red_4; background-color: alpha(@red_2, .25); } .circular-lozenge.grey, .lozenge.grey { color: #323237; background-color: alpha(@dark_3, .25); } @media (prefers-color-scheme: dark) { .circular-lozenge.green, .lozenge.green { color: @green_1; background-color: alpha(@green_4, .25); } .circular-lozenge.yellow, .lozenge.yellow { color: @yellow_2; background: alpha(#cd9309, .25); } .circular-lozenge.orange, .lozenge.orange { color: @orange_1; } .circular-lozenge.red, .lozenge.red { color: #ff7b63; } .circular-lozenge.grey, .lozenge.grey { color: @window_fg_color; background-color: alpha(@light_5, .25); } } .floating-tooltip { background-color: var(--dialog-bg-color); } .floating-tooltip .monospace { font-size: 1em; } .flathub { --accent-color: alpha(@window_fg_color,0.75); --accent-bg-color: @window_fg_color; } .flathub-lotion { color: #fafafa; } .flathub-gunmetal { color: #251f32; } @media (prefers-color-scheme: dark) { .flathub { --accent-color: alpha(#fafafa,0.75); --accent-bg-color: #7847b8; } } global-progress { color: transparent; } global-progress > *:first-child > * { background: var(--flag-gradient, var(--accent-bg-color)); } global-progress image { color: var(--window-fg-color); } .global-progress-button { padding: 5px; } .global-progress-bg { opacity: 0.5; } .lozenge { font-size: 18px; font-weight: bold; border-radius: 99999px; padding: 5px 11px; min-width: 18px; min-height: 22px; color: var(--accent-color); background-color: alpha(var(--accent-bg-color),0.15); transition: background-color 150ms ease; } .lozenge.small { padding: 1px 9px; font-size: 12px; font-weight: bold; } .lozenge-ring-button { padding: 0; border-radius: 999999px; background: transparent; } .circular-lozenge { font-weight: bold; border-radius: 99999px; padding: 9px 11px; min-width: 18px; min-height: 22px; color: var(--accent-color); background-color: alpha(var(--accent-bg-color),0.15); } .circular-lozenge.large { font-size: 24px; padding: 15px 18px; min-width: 24px; min-height: 30px; } button.context-tile:hover .lozenge { background-color: alpha(var(--accent-bg-color),0.25); } button.context-tile:active .lozenge { background-color: alpha(var(--accent-bg-color),0.35); } .small-pill { padding: 2px 12px; border-radius: 99999px; } .medium-pill { border-radius: 99999px; } .colored { background-color: var(--accent-bg-color); color: var(--accent-color); } .card.colored { background-color: alpha(var(--accent-bg-color),0.15); color: var(--accent-color); } .small-pill.dimmed { background-color: alpha(@theme_fg_color, 0.15); } .small-pill.error { background-color: alpha(@error_bg_color, 0.15); } .installed-pill { background-color: alpha(@success_bg_color, 0.15); color: @success_color; font-weight: 500; font-size: 0.9em; padding: 2px 7px 2px 4.5px; } .sp-section .installed-pill { background-color: alpha(@window_fg_color, 0.10); color: alpha(@window_fg_color, 0.75); } .download-size-pill{ padding: 2px 8px; } .flathub-page-section { border-radius: 10px; } .transaction-list-view row { margin: 0; padding: 0; } window.narrow .app-title { font-size: 16pt; } .developer-badge > button { padding: 0; background-color: transparent; } .developer-badge:focus > button { border-radius: 5px; } window.narrow .app-developer { font-size: small; } .context-tile { box-shadow: none; padding: 4px; } button.context-tile { background-color: transparent; } .context-tile-text { font-size: 10pt; font-weight: 500; } .wide-image { margin-top: -28px; margin-bottom: -28px; } .screenshot-carousel.frame { border-width: 1px 0; } .screenshot-carousel button{ margin: 12px; } .carousel-box { background-color: var(--view-bg-color); } toggle-group.huge, toggle-group.huge * { border-radius: 9999px; } .huge > toggle { padding: 3px 12px; } .otg { background: linear-gradient(to right, #2f3d9f, #682889); } .wlg { background: linear-gradient(to right, #821756, #136673); } .sp-section .card:not(:hover):not(:active) { background: transparent; } .sp-section .card { box-shadow: none; } @media (prefers-color-scheme: light) { .otg { background: linear-gradient(to right, #c6eaf8, #c4f3c9); } .wlg { background: linear-gradient(to right, #fdcde0, #b0e5f0); } .sp-section .card:hover { background: rgba(255, 255, 255, 0.50); } .sp-section .card:active { background: rgba(255, 255, 255, 0.75); } } .sp-section-image { margin-top: -95px; margin-bottom: -95px; } .sp-section-title { font-size: 3.5em; } .decorated-screenshot { margin: 0; padding: 0; background-color: transparent; } .indicator-box button { margin: 0 4px 4px 0; } .pip-button.osd-box { padding: 0; } .pip-button > button { margin: 5px; } window, headerbar, .global-search { transition: background-color 0.2s ease; } .header-osd windowcontrols button image { background-color: rgba(0, 0, 0, 0.65); color: white; background-image: none; } .osd-box { border-radius: 12px; background-color: rgba(0, 0, 0, 0.65); padding: 6px; color: white; } .view-dark { background-color: black; color: white; } .header-osd box.horizontal:not(.end) { background-color: rgba(0, 0, 0, 0.65); border-radius: 10px; } .accent-button { border-radius: 9999px; padding: 3px; background: var(--flag-gradient, var(--accent-bg-color)); min-width: 32px; min-height: 32px; outline: none; background-clip: content-box; background-origin: content-box; box-shadow: none; transition: transform 0.3s ease; } .accent-button.horizontal { transform: rotate(-90deg); } .accent-button-box > flowboxchild { padding: 0; background-color: transparent; } .accent-button:checked { box-shadow: 0 0 0 3px var(--accent-bg-color); } .accent-button:focus:focus-visible { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-color) 30%, transparent); } .accent-button:checked:focus:focus-visible { box-shadow: 0 0 0 3px var(--accent-bg-color), 0 0 0 6px color-mix(in srgb, var(--accent-color) 30%, transparent); } /* Category buttons styling modified from GNOME Software*/ .category-tile { font-weight: 700; font-size: 13pt; color: white; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); padding-left: 32px; padding-right: 32px; outline-offset: 2px; } @media (prefers-contrast: more) { .category-tile { box-shadow: none; } } window.narrow .category-tile { font-size: 14pt; padding-left: 24px; padding-right: 24px; } /* All background gradients are at 135deg for consistency */ .category-tile.category-recently-updated { background: linear-gradient(135deg, #f9ef69, #26a269); color: #0c3020; text-shadow: 0 1px rgba(255, 255, 255, 0.35); } .category-tile.category-recently-updated:hover { background: linear-gradient(135deg, shade(#f9ef69, 1.1), shade(#26a269, 1.1)); } .category-tile.category-recently-updated:active { background: linear-gradient(135deg, shade(#f9ef69, 0.95), shade(#26a269, 0.95)); } .category-tile.category-recently-added { background: linear-gradient(135deg, #99a3eb, #495ade); } .category-tile.category-recently-added:hover { background: linear-gradient(135deg, shade(#99a3eb, 1.1), shade(#495ade, 1.1)); } .category-tile.category-recently-added:active { background: linear-gradient(135deg, shade(#99a3eb, .95), shade(#495ade, .95)); } .category-tile.category-trending { background: linear-gradient(135deg, #99c1f1, #3584e4); } .category-tile.category-trending:hover { background: linear-gradient(135deg, shade(#99c1f1, 1.1), shade(#3584e4, 1.1)); } .category-tile.category-trending:active { background: linear-gradient(135deg, shade(#99c1f1, .95), shade(#3584e4, .95)); } .category-tile.category-popular { background: linear-gradient(135deg, #f7ef74, #ffbf6f); color: rgba(0, 0, 0, 0.8); text-shadow: 0 1px rgba(255, 255, 255, 0.35); } .category-tile.category-popular:hover { background: linear-gradient(135deg, shade(#f7ef74, 1.1), shade(#ffbf6f, 1.1)); } .category-tile.category-popular:active { background: linear-gradient(135deg, shade(#f7ef74, .95), shade(#ffbf6f, .95)); } .category-tile.category-mobile { background: linear-gradient(135deg, #c6eaf8, #c4f3c9); color: rgba(0, 0, 0, 0.8); text-shadow: 0 1px rgba(255, 255, 255, 0.35); } .category-tile.category-mobile:hover { background: linear-gradient(135deg, shade(#c6eaf8, 1.1), shade(#c4f3c9, 1.1)); } .category-tile.category-mobile:active { background: linear-gradient(135deg, shade(#c6eaf8, .95), shade(#c4f3c9, .95)); } .category-tile.category-graphics { background: linear-gradient(135deg, #ce8cd7 0%, #2861c6 100%); } .category-tile.category-graphics:hover { background: linear-gradient(135deg, shade(#ce8cd7, 1.07) 0%, shade(#2861c6, 1.1) 100%); } .category-tile.category-graphics:active { background: linear-gradient(135deg, shade(#ce8cd7, .95) 0%, shade(#2861c6, .95) 100%); } .category-tile.category-development { background: linear-gradient(135deg, #444449 30%, #333337 100%); } .category-tile.category-development:hover { background: linear-gradient(135deg, shade(#444449, 1.06) 30%, shade(#333337, 1.06) 100%); } .category-tile.category-development:active { background: linear-gradient(135deg, shade(#444449, .95) 30%, shade(#333337, .95) 100%); } .category-tile.category-education { background: linear-gradient(135deg, #2ec27e 30%, #27a66c 100%); } .category-tile.category-education:hover { background: linear-gradient(135deg, shade(#2ec27e, 1.06) 30%, shade(#27a66c, 1.06) 100%); } .category-tile.category-education:active { background: linear-gradient(135deg, shade(#2ec27e, .95) 30%, shade(#27a66c, .95) 100%); } .category-tile.category-game { background: linear-gradient(135deg, #f9e2a7 0%, #eb5ec3 50%, #6d53e0 100%); color: #393484; text-shadow: 0 1px rgba(255, 255, 255, 0.35); } .category-tile.category-game:hover { background: linear-gradient(135deg, shade(#f9e2a7, 1.07) 0%, shade(#eb5ec3, 1.07) 50%, shade(#6d53e0, 1.07) 100%); } .category-tile.category-game:active { background: linear-gradient(135deg, shade(#f9e2a7, .97) 0%, shade(#eb5ec3, .95) 50%, shade(#6d53e0, 1.07) 100%); } .category-tile.category-network { background: linear-gradient(135deg, #ff6b35, #ed333b); } .category-tile.category-network:hover { background: linear-gradient(135deg, shade(#ff6b35, 1.1), shade(#ed333b, 1.1)); } .category-tile.category-network:active { background: linear-gradient(135deg, shade(#ff6b35, .95), shade(#ed333b, .95)); } .category-tile.category-office { padding: 1px; color: #1c71d8; text-shadow: 0 1px rgba(255, 255, 255, 0.35); background-color: #fdf8d7; background-image: linear-gradient(#deddda 1px, transparent 1px), linear-gradient(90deg, #deddda 1px, transparent 1px); background-size: 10px 10px, 10px 10px; background-position: -1px -4px, center -1px; } .category-tile.category-office:hover { background-color: shade(#fdf8d7, 1.03); background-image: linear-gradient(shade(#deddda, 1.04) 1px, transparent 1px), linear-gradient(90deg, shade(#deddda, 1.04) 1px, transparent 1px); } .category-tile.category-office:active { background-color: shade(#fdf8d7, .93); background-image: linear-gradient(shade(#deddda, .97) 1px, transparent 1px), linear-gradient(90deg, shade(#deddda, .97) 1px, transparent 1px); } .category-tile.category-audiovideo { background: linear-gradient(135deg, #ffcd3c 0%, #ff6b35 100%); } .category-tile.category-audiovideo:hover { background: linear-gradient(135deg, shade(#ffcd3c, 1.08) 0%, shade(#ff6b35, 1.08) 100%); } .category-tile.category-audiovideo:active { background: linear-gradient(135deg, shade(#ffcd3c, .95) 0%, shade(#ff6b35, .95) 100%); } .category-tile.category-science { background: linear-gradient(135deg, #8ff0a4 0%, #1c71d8 100%); } .category-tile.category-science:hover { background: linear-gradient(135deg, shade(#8ff0a4, 1.1) 0%, shade(#1c71d8, 1.1) 100%); } .category-tile.category-science:active { background: linear-gradient(135deg, shade(#8ff0a4, .95) 0%, shade(#1c71d8, .95) 100%); } .category-tile.category-system { background: linear-gradient(135deg, #6c757d 0%, #495057 100%); } .category-tile.category-system:hover { background: linear-gradient(135deg, shade(#6c757d, 1.15) 0%, shade(#495057, 1.15) 100%); } .category-tile.category-system:active { background: linear-gradient(135deg, shade(#6c757d, .95) 0%, shade(#495057, .95) 100%); } .category-tile.category-utility { color: #ee5f50; text-shadow: 0 1px rgba(255, 255, 255, 0.35); background: linear-gradient(135deg, #f6f5f4 0%, #deddda 100%); } .category-tile.category-utility:hover { background: linear-gradient(135deg, shade(#f6f5f4, 1.08) 0%, shade(#deddda, 1.08) 100%); } .category-tile.category-utility:active { background: linear-gradient(135deg, shade(#f6f5f4, .95) 0%, shade(#deddda, .95) 100%); } .category-tile.category-adwaita { text-shadow: 0 1px rgba(255, 255, 255, 0.35); background: linear-gradient(45deg, #1c71d8 0%, #57e289 100%); } .category-tile.category-adwaita:hover { background: linear-gradient(45deg, shade(#1c71d8, 1.08) 0%, shade(#57e289, 1.08) 100%); } .category-tile.category-adwaita:active { background: linear-gradient(45deg, shade(#1c71d8, .95) 0%, shade(#57e289, .95) 100%); } .category-tile.category-kde { text-shadow: 0 1px rgba(255, 255, 255, 0.35); background: linear-gradient(135deg, #3584e4 0%, #704dac 100%); } .category-tile.category-kde:hover { background: linear-gradient(135deg, shade(#3584e4, 1.08) 0%, shade(#704dac, 1.08) 100%); } .category-tile.category-kde:active { background: linear-gradient(135deg, shade(#3584e4, .95) 0%, shade(#704dac, .95) 100%); } .category-tile.category-adwaita image, .category-tile.category-kde image { -gtk-icon-shadow: none; } .installed-list-view > * { padding: 0; transition: background-color 200ms; min-height: 0; margin: 5px 4.5px; } .installed-section { padding-top: 0; } .narrow .installed-list-view > * { margin: 4px 4.5px; } .no-vertical-margin > row.hidden { margin-top: 0px; margin-bottom: 0px; } .no-vertical-margin > row:not(.hidden) { margin-bottom: 6px; } .user-data-list-view > * { margin: 0; } .user-data-list-view row { min-height: 0; } .no-min-height { min-height: 0; } .transaction-tile-title { font-size: 1.05em; font-weight: 450; } .operations { background-color: rgba(255, 255, 255, 0.040); border-radius: 0px 0px 12px 12px; } @media (prefers-color-scheme: light) { .operations { background-color: rgba(0, 0, 0, 0.050); } } .ops-toggle { transition: transform 200ms ease; transform: rotate(90deg); } .ops-toggle:checked, .ops-toggle.rotated { transform: rotate(270deg); } @media (prefers-color-scheme: dark) { separator { opacity: 0.5; } } .disable-adw-flow-box-styling { background-color: transparent; box-shadow: none; padding: 0; } curated-list-view, curated-list-view list { background: var(--bg-color); } bazaar-orig-v0.7.14/src/bz-login-page.blp0000664000175000017500000000557115166123241017071 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzLoginPage: Adw.NavigationPage { title: _("Connect to Flathub"); child: Adw.ToolbarView { [top] Adw.HeaderBar {} content: Stack main_stack { transition-type: crossfade; StackPage { name: "loading"; child: Adw.Spinner { hexpand: true; vexpand: true; halign: center; valign: center; width-request: 64; height-request: 64; }; } StackPage { name: "error"; child: Adw.StatusPage error_status_page { icon-name: "computer-fail-symbolic"; title: _("Something Went Wrong"); }; } StackPage { name: "start"; child: Adw.Clamp { child: Adw.StatusPage { icon-name: "flathub-symbolic"; title: _("Connect to Flathub"); description: _("Connect your Flathub account to Bazaar to manage your favorited apps."); child: Adw.PreferencesGroup provider_preferences_group { margin-start: 10; margin-end: 10; hexpand: true; halign: fill; }; }; }; } StackPage { name: "browser"; child: ScrolledWindow browser_scroll { vexpand: true; }; } StackPage { name: "finish"; child: ScrolledWindow { hscrollbar-policy: never; child: Adw.Clamp { maximum-size: 600; child: Box { orientation: vertical; vexpand: true; halign: center; valign: center; Box { orientation: vertical; spacing: 15; halign: center; valign: center; Adw.Avatar { size: 96; show-initials: true; text: bind template.auth-state as <$BzAuthState>.name; custom-image: bind template.auth-state as <$BzAuthState>.paintable; } Label { halign: center; label: bind $format_greeting(template.auth-state as <$BzAuthState>.name as ) as ; wrap: true; wrap-mode: word_char; justify: center; styles [ "title-1", ] } } Box { orientation: horizontal; spacing: 10; halign: center; margin-top: 20; Button { label: _("Finish"); clicked => $on_close_clicked(); styles [ "pill", ] } } }; }; }; } }; }; }bazaar-orig-v0.7.14/src/bz-favorites-page.h0000664000175000017500000000210015166123241017416 0ustar hasanhasan/* bz-favorites-page.h * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-state-info.h" G_BEGIN_DECLS #define BZ_TYPE_FAVORITES_PAGE (bz_favorites_page_get_type ()) G_DECLARE_FINAL_TYPE (BzFavoritesPage, bz_favorites_page, BZ, FAVORITES_PAGE, AdwNavigationPage) GtkWidget *bz_favorites_page_new (BzStateInfo *state); G_END_DECLS bazaar-orig-v0.7.14/src/bz-favorite-button.c0000664000175000017500000003145215166123241017641 0ustar hasanhasan/* bz-favorite-button.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include #include "bz-entry.h" #include "bz-env.h" #include "bz-error.h" #include "bz-favorite-button.h" #include "bz-global-net.h" #include "bz-state-info.h" struct _BzFavoriteButton { GtkButton parent_instance; BzEntry *entry; BzStateInfo *state; GtkBox *box; GtkImage *icon; GtkRevealer *count_revealer; GtkLabel *count_label; GtkStack *stack; gboolean is_favorited; }; G_DEFINE_FINAL_TYPE (BzFavoriteButton, bz_favorite_button, GTK_TYPE_BUTTON) enum { PROP_0, PROP_ENTRY, PROP_STATE, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static DexFuture * fetch_favorite_status_fiber (BzFavoriteButton *button); static DexFuture * toggle_favorite_fiber (BzFavoriteButton *button); static void button_clicked_cb (BzFavoriteButton *self, GtkButton *button); static void update_icon (BzFavoriteButton *self); static void update_count (BzFavoriteButton *self); static void on_login_button_clicked (GtkButton *button, GtkPopover *popover); static void show_login_popover (BzFavoriteButton *self); static gboolean is_positive (gpointer object, int value); static char * format_favorites_count (gpointer object, int count); static void bz_favorite_button_dispose (GObject *object) { BzFavoriteButton *self = BZ_FAVORITE_BUTTON (object); g_clear_object (&self->entry); g_clear_object (&self->state); G_OBJECT_CLASS (bz_favorite_button_parent_class)->dispose (object); } static void bz_favorite_button_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzFavoriteButton *self = BZ_FAVORITE_BUTTON (object); switch (prop_id) { case PROP_ENTRY: g_value_set_object (value, bz_favorite_button_get_entry (self)); break; case PROP_STATE: g_value_set_object (value, bz_favorite_button_get_state (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_favorite_button_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzFavoriteButton *self = BZ_FAVORITE_BUTTON (object); switch (prop_id) { case PROP_ENTRY: bz_favorite_button_set_entry (self, g_value_get_object (value)); break; case PROP_STATE: bz_favorite_button_set_state (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_favorite_button_class_init (BzFavoriteButtonClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_favorite_button_dispose; object_class->get_property = bz_favorite_button_get_property; object_class->set_property = bz_favorite_button_set_property; props[PROP_ENTRY] = g_param_spec_object ( "entry", NULL, NULL, BZ_TYPE_ENTRY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_STATE] = g_param_spec_object ( "state", NULL, NULL, BZ_TYPE_STATE_INFO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-favorite-button.ui"); gtk_widget_class_bind_template_child (widget_class, BzFavoriteButton, box); gtk_widget_class_bind_template_child (widget_class, BzFavoriteButton, icon); gtk_widget_class_bind_template_child (widget_class, BzFavoriteButton, count_revealer); gtk_widget_class_bind_template_child (widget_class, BzFavoriteButton, count_label); gtk_widget_class_bind_template_child (widget_class, BzFavoriteButton, stack); gtk_widget_class_bind_template_callback (widget_class, is_positive); gtk_widget_class_bind_template_callback (widget_class, format_favorites_count); gtk_widget_class_bind_template_callback (widget_class, button_clicked_cb); } static void bz_favorite_button_init (BzFavoriteButton *self) { gtk_widget_init_template (GTK_WIDGET (self)); self->is_favorited = FALSE; } GtkWidget * bz_favorite_button_new (void) { return g_object_new (BZ_TYPE_FAVORITE_BUTTON, NULL); } void bz_favorite_button_set_entry (BzFavoriteButton *self, BzEntry *entry) { g_return_if_fail (BZ_IS_FAVORITE_BUTTON (self)); g_return_if_fail (entry == NULL || BZ_IS_ENTRY (entry)); if (g_set_object (&self->entry, entry)) { update_count (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ENTRY]); if (self->state != NULL && self->entry != NULL) { dex_future_disown (dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) fetch_favorite_status_fiber, g_object_ref (self), g_object_unref)); } } } BzEntry * bz_favorite_button_get_entry (BzFavoriteButton *self) { g_return_val_if_fail (BZ_IS_FAVORITE_BUTTON (self), NULL); return self->entry; } void bz_favorite_button_set_state (BzFavoriteButton *self, BzStateInfo *state) { g_return_if_fail (BZ_IS_FAVORITE_BUTTON (self)); g_return_if_fail (state == NULL || BZ_IS_STATE_INFO (state)); if (g_set_object (&self->state, state)) { g_object_notify_by_pspec (G_OBJECT (self), props[PROP_STATE]); if (self->state != NULL && self->entry != NULL) { dex_future_disown (dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) fetch_favorite_status_fiber, g_object_ref (self), g_object_unref)); } } } BzStateInfo * bz_favorite_button_get_state (BzFavoriteButton *self) { g_return_val_if_fail (BZ_IS_FAVORITE_BUTTON (self), NULL); return self->state; } static gboolean is_positive (gpointer object, int value) { return value > 0; } static char * format_favorites_count (gpointer object, int count) { if (count >= 1000000) return g_strdup_printf ("%.1fM", count / 1000000.0); else if (count >= 1000) return g_strdup_printf ("%.1fK", count / 1000.0); else return g_strdup_printf ("%d", count); } static void update_icon (BzFavoriteButton *self) { if (self->is_favorited) gtk_image_set_from_icon_name (self->icon, "bookmark-filled-symbolic"); else gtk_image_set_from_icon_name (self->icon, "bookmark-outline-symbolic"); } static void update_count (BzFavoriteButton *self) { int count = 0; if (self->entry != NULL) g_object_get (self->entry, "favorites-count", &count, NULL); gtk_revealer_set_reveal_child (self->count_revealer, count > 0); if (count > 0) { g_autofree char *formatted = format_favorites_count (NULL, count); gtk_label_set_label (self->count_label, formatted); } } static DexFuture * fetch_favorite_status_fiber (BzFavoriteButton *button) { g_autoptr (GError) local_error = NULL; g_autoptr (JsonNode) node = NULL; g_autofree char *request = NULL; BzAuthState *auth_state = NULL; const char *token = NULL; const char *app_id = NULL; if (button->state == NULL || button->entry == NULL) return NULL; auth_state = bz_state_info_get_auth_state (button->state); if (!bz_auth_state_is_authenticated (auth_state)) return NULL; token = bz_auth_state_get_token (auth_state); if (token == NULL) return NULL; g_object_get (button->entry, "id", &app_id, NULL); request = g_strdup_printf ("/favorites/%s", app_id); node = dex_await_boxed ( bz_query_flathub_v2_json_authenticated (request, token), &local_error); if (local_error == NULL && node != NULL && JSON_NODE_HOLDS_VALUE (node)) { button->is_favorited = json_node_get_boolean (node); update_icon (button); } return NULL; } static DexFuture * toggle_favorite_fiber (BzFavoriteButton *button) { g_autoptr (GError) local_error = NULL; g_autofree char *request = NULL; BzAuthState *auth_state = NULL; const char *token = NULL; const char *app_id = NULL; int current_count = 0; if (button->state == NULL || button->entry == NULL) goto err; auth_state = bz_state_info_get_auth_state (button->state); if (!bz_auth_state_is_authenticated (auth_state)) goto err; token = bz_auth_state_get_token (auth_state); if (token == NULL) goto err; g_object_get (button->entry, "id", &app_id, "favorites-count", ¤t_count, NULL); if (button->is_favorited) request = g_strdup_printf ("/favorites/%s/remove", app_id); else request = g_strdup_printf ("/favorites/%s/add", app_id); if (button->is_favorited) dex_await ( bz_query_flathub_v2_json_authenticated_delete (request, token), &local_error); else dex_await ( bz_query_flathub_v2_json_authenticated_post (request, token), &local_error); if (local_error != NULL) { GtkWidget *window = NULL; gtk_stack_set_visible_child_name (button->stack, "content"); window = gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_WINDOW); if (window != NULL) bz_show_error_for_widget (window, _ ("Failed to update favorite"), local_error->message); } else { button->is_favorited = !button->is_favorited; g_object_set (button->entry, "favorites-count", button->is_favorited ? current_count + 1 : current_count - 1, NULL); update_icon (button); update_count (button); gtk_stack_set_visible_child_name (button->stack, "content"); } return NULL; err: gtk_stack_set_visible_child_name (button->stack, "content"); return NULL; } static void on_login_button_clicked (GtkButton *button, GtkPopover *popover) { gtk_popover_popdown (popover); } static void show_login_popover (BzFavoriteButton *self) { GtkWidget *popover; GtkWidget *box; GtkWidget *label; GtkWidget *button; popover = gtk_popover_new (); gtk_widget_set_parent (popover, GTK_WIDGET (self)); box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_widget_set_margin_top (box, 6); gtk_widget_set_margin_bottom (box, 6); gtk_widget_set_margin_start (box, 6); gtk_widget_set_margin_end (box, 6); label = gtk_label_new (_ ("Log in with Flathub to manage favorites")); gtk_label_set_wrap (GTK_LABEL (label), TRUE); gtk_label_set_max_width_chars (GTK_LABEL (label), 17); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER); gtk_box_append (GTK_BOX (box), label); button = gtk_button_new_with_label (_ ("Log In")); gtk_widget_add_css_class (button, "suggested-action"); gtk_actionable_set_action_name (GTK_ACTIONABLE (button), "app.flathub-login"); g_signal_connect (button, "clicked", G_CALLBACK (on_login_button_clicked), popover); gtk_box_append (GTK_BOX (box), button); gtk_popover_set_child (GTK_POPOVER (popover), box); gtk_popover_popup (GTK_POPOVER (popover)); } static void button_clicked_cb (BzFavoriteButton *self, GtkButton *button) { BzAuthState *auth_state = NULL; if (self->state == NULL) return; auth_state = bz_state_info_get_auth_state (self->state); if (!bz_auth_state_is_authenticated (auth_state)) { show_login_popover (self); return; } gtk_stack_set_visible_child_name (self->stack, "spinner"); dex_future_disown (dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) toggle_favorite_fiber, g_object_ref (self), g_object_unref)); } bazaar-orig-v0.7.14/src/bz-data-graph.h0000664000175000017500000000461315166123241016525 0ustar hasanhasan/* bz-data-graph.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_DATA_GRAPH (bz_data_graph_get_type ()) G_DECLARE_FINAL_TYPE (BzDataGraph, bz_data_graph, BZ, DATA_GRAPH, GtkWidget) GtkWidget * bz_data_graph_new (void); GListModel * bz_data_graph_get_model (BzDataGraph *self); const char * bz_data_graph_get_independent_axis_label (BzDataGraph *self); const char * bz_data_graph_get_dependent_axis_label (BzDataGraph *self); int bz_data_graph_get_independent_decimals (BzDataGraph *self); int bz_data_graph_get_dependent_decimals (BzDataGraph *self); double bz_data_graph_get_transition_progress (BzDataGraph *self); void bz_data_graph_set_model (BzDataGraph *self, GListModel *model); void bz_data_graph_set_independent_axis_label (BzDataGraph *self, const char *independent_axis_label); void bz_data_graph_set_dependent_axis_label (BzDataGraph *self, const char *dependent_axis_label); void bz_data_graph_set_independent_decimals (BzDataGraph *self, int independent_decimals); void bz_data_graph_set_dependent_decimals (BzDataGraph *self, int dependent_decimals); const char *bz_data_graph_get_tooltip_prefix (BzDataGraph *self); void bz_data_graph_set_tooltip_prefix (BzDataGraph *self, const char *tooltip_prefix); void bz_data_graph_set_transition_progress (BzDataGraph *self, double transition_progress); void bz_data_graph_animate_open (BzDataGraph *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-stats-dialog.blp0000664000175000017500000000413115166123241017431 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzStatsDialog: Adw.BreakpointBin { width-request: 360; height-request: 450; child: Adw.ToolbarView { bottom-bar-style: raised_border; [top] Adw.HeaderBar { title-widget: Adw.ViewSwitcher switcher_title { visible: bind $invert_boolean($is_null(template.country-model) as ) as ; stack: stack; policy: wide; }; } content: Box { orientation: vertical; Adw.ViewStack stack { vexpand: true; Adw.ViewStackPage { name: "graph"; title: _("Timeline"); icon-name: "graph2-symbolic"; child: Box { orientation: vertical; Label { label: bind $format_total_downloads(template.total-downloads) as ; halign: end; hexpand: true; margin-end: 34; margin-bottom: 2; styles ["dimmed"] } $BzDataGraph graph { model: bind template.model; tooltip-prefix: _("Installs:"); vexpand: true; hexpand: true; } }; } Adw.ViewStackPage { name: "map"; title: _("World"); icon-name: "globe-symbolic"; child: Box { orientation: vertical; margin-top:10; margin-bottom: 10; $BzWorldMap world_map { model: bind template.country-model; vexpand: true; } Label { label: _("Since 4/15/2024"); halign: center; styles [ "dimmed", "caption" ] } }; } } Adw.ViewSwitcherBar switcher_bar { visible: bind $invert_boolean($is_null(template.country-model) as ) as ; stack: stack; } }; }; Adw.Breakpoint { condition ("max-width: 450sp") setters { switcher_title.stack: null; switcher_bar.reveal: true; } } }bazaar-orig-v0.7.14/src/bz-preferences-dialog.blp0000664000175000017500000000504515166123241020601 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzPreferencesDialog: Adw.PreferencesDialog { content-height: 500; search-enabled: true; width-request: 350; height-request: 100; Adw.Breakpoint { condition ("max-width: 625sp") setters { flag_buttons_box.max-children-per-line: 6; } } Adw.PreferencesPage { title: _("Preferences"); use-underline: true; banner: Adw.Banner { sensitive: bind $invert_boolean(template.state as <$BzStateInfo>.syncing as ) as ; revealed: bind template.state as <$BzStateInfo>.metered_connection as ; title: _("Network connection is metered — automatic store data refresh is paused"); button-label: _("Refresh Manually"); action-name: "app.sync-remotes"; }; Adw.PreferencesGroup { title: _("Content Filters"); Adw.SwitchRow only_foss_switch { title: _("Free Software Only"); subtitle: _("Hide proprietary applications when browsing and searching"); } Adw.SwitchRow only_flathub_switch { title: _("Flathub Results Only"); subtitle: _("Limit search and browse results to applications only available on Flathub"); } Adw.SwitchRow only_verified_switch { title: _("Verified Results Only"); subtitle: _("Hide results that are not verified on Flathub"); } Adw.SwitchRow hide_eol_switch { title: _("Hide EOL Apps"); subtitle: _("Hide apps which are no longer supported by their developers"); } } Adw.PreferencesGroup { title: _("Search"); Adw.SwitchRow search_debounce_switch { title: _("Delay Search Results"); subtitle: _("Improve results performance by debouncing search terms"); } } Adw.PreferencesGroup { title: _("Progress Bar"); description: _("Choose a theme for the progress bar!"); Adw.ActionRow { child: Box { margin-top: 6; margin-bottom: 6; halign: center; FlowBox flag_buttons_box { styles [ "accent-button-box", ] orientation: horizontal; column-spacing: 4; row-spacing: 4; halign: center; homogeneous: true; max-children-per-line: 12; selection-mode: none; } }; } Adw.SwitchRow rotate_switch { title: _("Vertical Stripes"); subtitle: _("Display flag colors from left to right"); notify::active => $on_rotate_switch_changed(); } } } } bazaar-orig-v0.7.14/src/bz-install-controls.blp0000664000175000017500000001126715166123241020355 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzInstallControls: Box { homogeneous: bind $invert_boolean(template.wide) as ; spacing: bind $choose(template.wide, 10, 8) as ; hexpand: bind $invert_boolean(template.wide) as ; valign: center; Stack { transition-type: crossfade; visible-child-name: bind $get_visible_page(template.entry-group as <$BzEntryGroup>.installable, template.entry-group as <$BzEntryGroup>.removable, template.state as <$BzStateInfo>.available-updates) as ; hexpand: bind $invert_boolean(template.wide) as ; hhomogeneous: false; StackPage install { name: "install"; child: Button install_button { styles [ "suggested-action", "pill", ] margin-top: 3; margin-bottom: 3; margin-start: 3; margin-end: 3; has-tooltip: true; hexpand: bind $invert_boolean(template.wide) as ; halign: bind $choose(template.wide, 2, 0) as ; sensitive: bind $invert_boolean($is_zero(template.entry-group as <$BzEntryGroup>.installable-and-available) as ) as ; label: _("_Install"); use-underline: true; clicked => $install_cb(template); }; } StackPage open { name: "open"; child: Box { spacing: bind $choose(template.wide, 10, 8) as ; homogeneous: bind $invert_boolean(template.wide) as ; halign: bind $choose(template.wide, 2, 0) as ; margin-top: 3; margin-bottom: 3; margin-start: 3; margin-end: 3; Button open_button { styles [ "pill", ] visible: bind $invert_boolean($is_blocked(template.state as <$BzStateInfo>.parental-blocked-ids, template.entry-group as <$BzEntryGroup>) as ) as ; has-tooltip: true; hexpand: bind $invert_boolean(template.wide) as ; label: _("_Open"); use-underline: true; sensitive: bind $invert_boolean($is_zero(template.entry-group as <$BzEntryGroup>.removable-and-available) as ) as ; clicked => $run_cb(template); } Button { styles [ "destructive-action", "circular", ] width-request: bind $choose(template.wide, 45, -1) as ; hexpand: bind $invert_boolean(template.wide) as ; has-tooltip: bind template.wide as ; tooltip-text: _("Uninstall Application"); sensitive: bind $invert_boolean($is_zero(template.entry-group as <$BzEntryGroup>.removable-and-available) as ) as ; clicked => $remove_cb(template); child: Box { halign: center; hexpand: true; Label { visible: bind $invert_boolean(template.wide) as ; label: _("_Remove"); use-underline: true; } Image { visible: bind template.wide as ; icon-name: "user-trash-symbolic"; } }; } }; } StackPage update { name: "update"; child: Box { spacing: bind $choose(template.wide, 10, 8) as ; homogeneous: bind $invert_boolean(template.wide) as ; halign: bind $choose(template.wide, 2, 0) as ; margin-top: 3; margin-bottom: 3; margin-start: 3; margin-end: 3; Button update_button { styles [ "pill", "suggested-action" ] hexpand: bind $invert_boolean(template.wide) as ; label: _("Update"); clicked => $update_cb(template); } Button { styles [ "destructive-action", "circular", ] width-request: bind $choose(template.wide, 45, -1) as ; hexpand: bind $invert_boolean(template.wide) as ; has-tooltip: bind template.wide as ; tooltip-text: _("Uninstall Application"); sensitive: bind $invert_boolean($is_zero(template.entry-group as <$BzEntryGroup>.removable-and-available) as ) as ; clicked => $remove_cb(template); child: Box { halign: center; hexpand: true; Label { visible: bind $invert_boolean(template.wide) as ; label: _("Remove"); } Image { visible: bind template.wide as ; icon-name: "user-trash-symbolic"; } }; } }; } StackPage empty { name: "empty"; child: Adw.Bin {}; } } }bazaar-orig-v0.7.14/src/bz-flathub-page.h0000664000175000017500000000225715166123241017056 0ustar hasanhasan/* bz-flathub-page.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-state-info.h" G_BEGIN_DECLS #define BZ_TYPE_FLATHUB_PAGE (bz_flathub_page_get_type ()) G_DECLARE_FINAL_TYPE (BzFlathubPage, bz_flathub_page, BZ, FLATHUB_PAGE, AdwBin) GtkWidget * bz_flathub_page_new (void); void bz_flathub_page_set_state (BzFlathubPage *self, BzStateInfo *state); BzStateInfo * bz_flathub_page_get_state (BzFlathubPage *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-util.h0000664000175000017500000002147415166123241015476 0ustar hasanhasan/* bz-util.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #define bz_maybe(_ptr, _func) ((_ptr) != NULL ? (_func) ((_ptr)) : NULL) #define bz_maybe_strdup(_ptr) bz_maybe (_ptr, g_strdup) #define bz_maybe_ref(_ptr, _ref) ((typeof (_ptr)) bz_maybe (_ptr, _ref)) #define bz_object_maybe_ref(_obj) bz_maybe_ref ((_obj), g_object_ref) #define bz_dex_maybe_ref(_obj) bz_maybe_ref ((_obj), dex_ref) #define BZ_RELEASE_DATA(name, unref) \ if ((unref) != NULL) \ { \ g_clear_pointer (&self->name, (unref)); \ } #define BZ_RELEASE_UTAG(name, remove) \ if ((remove) != NULL) \ { \ g_clear_handle_id (&self->name, (remove)); \ } /* va args = releases */ #define BZ_DEFINE_DATA(name, Name, layout, ...) \ typedef struct _##Name##Data Name##Data; \ struct _##Name##Data \ { \ gatomicrefcount rc; \ struct layout; \ }; \ G_GNUC_UNUSED \ static inline Name##Data * \ name##_data_new (void) \ { \ Name##Data *data = NULL; \ data = g_new0 (typeof (*data), 1); \ g_atomic_ref_count_init (&data->rc); \ return data; \ } \ G_GNUC_UNUSED \ static inline Name##Data * \ name##_data_ref (gpointer ptr) \ { \ Name##Data *self = ptr; \ g_atomic_ref_count_inc (&self->rc); \ return self; \ } \ G_GNUC_UNUSED \ static void \ name##_data_deinit (gpointer ptr) \ { \ Name##Data *self = ptr; \ __VA_ARGS__ \ } \ G_GNUC_UNUSED \ static void \ name##_data_unref (gpointer ptr) \ { \ Name##Data *self = ptr; \ if (g_atomic_ref_count_dec (&self->rc)) \ { \ name##_data_deinit (self); \ g_free (self); \ } \ } \ G_GNUC_UNUSED \ static void \ name##_data_unref_closure (gpointer data, \ GClosure *closure) \ { \ name##_data_unref (data); \ } \ G_DEFINE_AUTOPTR_CLEANUP_FUNC (Name##Data, name##_data_unref); /* Be careful with deadlocks */ typedef DexFuture BzGuard; static inline void bz_guard_destroy (BzGuard *guard) { if (dex_future_is_pending (guard)) dex_promise_resolve_boolean (DEX_PROMISE (guard), TRUE); dex_unref (guard); } G_DEFINE_AUTOPTR_CLEANUP_FUNC (BzGuard, bz_guard_destroy); #define bz_clear_guard(_pp) g_clear_pointer (_pp, bz_guard_destroy) #define BZ_BEGIN_GUARD_WITH_CONTEXT(_guard, _mutex, _gate) \ G_STMT_START \ { \ g_autoptr (GMutexLocker) _locker = NULL; \ g_autoptr (DexFuture) _wait = NULL; \ \ _locker = g_mutex_locker_new (_mutex); \ if (*(_guard) == NULL) \ *(_guard) = (DexFuture *) dex_promise_new (); \ if (*(_gate) != NULL) \ { \ if (dex_future_is_pending (*(_gate))) \ _wait = g_steal_pointer (_gate); \ else \ dex_clear (_gate); \ } \ *(_gate) = dex_ref (*(_guard)); \ g_clear_pointer (&_locker, g_mutex_locker_free); \ \ if (_wait != NULL) \ dex_await (g_steal_pointer (&_wait), NULL); \ } \ G_STMT_END #define BZ_BEGIN_GUARD(_guard) \ G_STMT_START \ { \ static GMutex _mutex = { 0 }; \ static BzGuard *_gate = NULL; \ BZ_BEGIN_GUARD_WITH_CONTEXT (_guard, &_mutex, &_gate); \ } \ G_STMT_END /* Use with dex_scheduler_spawn */ G_GNUC_UNUSED static GWeakRef * bz_track_weak (gpointer object) { GWeakRef *wr = NULL; if (object == NULL) return NULL; wr = g_new0 (typeof (*wr), 1); g_weak_ref_init (wr, object); return wr; } G_GNUC_UNUSED static void bz_weak_release (gpointer ptr) { GWeakRef *wr = ptr; g_weak_ref_clear (wr); g_free (wr); } #define bz_weak_get_or_return(self, wr) \ G_STMT_START \ { \ (self) = g_weak_ref_get (wr); \ if ((self) == NULL) \ return; \ } \ G_STMT_END #define bz_weak_get_or_return_reject(self, wr) \ G_STMT_START \ { \ (self) = g_weak_ref_get (wr); \ if ((self) == NULL) \ return dex_future_new_reject ( \ G_IO_ERROR, \ G_IO_ERROR_CANCELLED, \ "Object was discarded"); \ } \ G_STMT_END G_GNUC_UNUSED static void _bz_debug_print_when_disposed_cb (gpointer ptr); BZ_DEFINE_DATA ( _bz_debug_dispose_cb, _BzDebugDisposeCb, { GType type; const char *loc; guint64 time; }, _bz_debug_print_when_disposed_cb (self);) G_GNUC_UNUSED static void _bz_debug_print_when_disposed_cb (gpointer ptr) { _BzDebugDisposeCbData *data = ptr; g_print ("%zu OBJECT DISPOSE: type %s; from %s at %zu\n", g_get_monotonic_time (), g_type_name (data->type), data->loc, data->time); } #define BZ_DEBUG_PRINT_WHEN_DISPOSED(_object) \ G_STMT_START \ { \ g_autoptr (_BzDebugDisposeCbData) _data = NULL; \ \ _data = _bz_debug_dispose_cb_data_new (); \ _data->type = G_OBJECT_TYPE (_object); \ _data->loc = G_STRLOC; \ _data->time = g_get_monotonic_time (); \ \ g_object_set_data_full ( \ G_OBJECT (_object), \ "BZ_DEBUG_PRINT_WHEN_DISPOSED", \ _bz_debug_dispose_cb_data_ref (_data), \ _bz_debug_dispose_cb_data_unref); \ } \ G_STMT_END bazaar-orig-v0.7.14/src/bz-transaction-manager.c0000664000175000017500000006320515166123241020447 0ustar hasanhasan/* bz-transaction-manager.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::TRANSACTIONS" #include "config.h" #include #include "bz-backend-transaction-op-payload.h" #include "bz-backend-transaction-op-progress-payload.h" #include "bz-env.h" #include "bz-marshalers.h" #include "bz-transaction-manager.h" #include "bz-util.h" /* clang-format off */ G_DEFINE_QUARK (bz-transaction-mgr-error-quark, bz_transaction_mgr_error); /* clang-format on */ enum { HOOK_CONTINUE, HOOK_STOP, HOOK_CONFIRM, HOOK_DENY, }; static inline void finish_queued_schedule_data (gpointer ptr); BZ_DEFINE_DATA ( queued_schedule, QueuedSchedule, { GWeakRef *self; BzTransaction *transaction; DexPromise *promise; GTimer *timer; }, finish_queued_schedule_data (self);) struct _BzTransactionManager { GObject parent_instance; BzMainConfig *config; BzBackend *backend; gboolean paused; GListStore *transactions; double current_progress; gboolean pending; QueuedScheduleData *current; DexFuture *loop; GtkFlattenListModel *all_trackers; GtkFilterListModel *install_trackers; GtkFilterListModel *removal_trackers; GQueue queue; }; G_DEFINE_FINAL_TYPE (BzTransactionManager, bz_transaction_manager, G_TYPE_OBJECT) enum { PROP_0, PROP_CONFIG, PROP_BACKEND, PROP_PAUSED, PROP_TRANSACTIONS, PROP_HAS_TRANSACTIONS, PROP_ACTIVE, PROP_PENDING, PROP_CURRENT_PROGRESS, PROP_INSTALL_TRACKERS, PROP_REMOVAL_TRACKERS, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; enum { SIGNAL_SUCCESS, SIGNAL_FAILURE, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL]; static DexFuture * transaction_fiber (QueuedScheduleData *data); static DexFuture * transaction_finally (DexFuture *future, QueuedScheduleData *data); static DexFuture * then_loop_cb (DexFuture *future, GWeakRef *wr); static DexFuture * dispatch_next (BzTransactionManager *self); static void bz_transaction_manager_dispose (GObject *object) { BzTransactionManager *self = BZ_TRANSACTION_MANAGER (object); g_clear_object (&self->config); g_clear_object (&self->backend); g_clear_object (&self->transactions); g_queue_clear_full (&self->queue, queued_schedule_data_unref); g_clear_pointer (&self->current, queued_schedule_data_unref); dex_clear (&self->loop); G_OBJECT_CLASS (bz_transaction_manager_parent_class)->dispose (object); } static void bz_transaction_manager_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzTransactionManager *self = BZ_TRANSACTION_MANAGER (object); switch (prop_id) { case PROP_CONFIG: g_value_set_boxed (value, bz_transaction_manager_get_config (self)); break; case PROP_BACKEND: g_value_set_object (value, bz_transaction_manager_get_backend (self)); break; case PROP_PAUSED: g_value_set_boolean (value, bz_transaction_manager_get_paused (self)); break; case PROP_TRANSACTIONS: g_value_set_object (value, self->transactions); break; case PROP_HAS_TRANSACTIONS: g_value_set_boolean (value, bz_transaction_manager_get_has_transactions (self)); break; case PROP_ACTIVE: g_value_set_boolean (value, bz_transaction_manager_get_active (self)); break; case PROP_PENDING: g_value_set_boolean (value, bz_transaction_manager_get_pending (self)); break; case PROP_CURRENT_PROGRESS: g_value_set_double (value, self->current_progress); break; case PROP_INSTALL_TRACKERS: g_value_set_object (value, self->install_trackers); break; case PROP_REMOVAL_TRACKERS: g_value_set_object (value, self->removal_trackers); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_transaction_manager_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzTransactionManager *self = BZ_TRANSACTION_MANAGER (object); switch (prop_id) { case PROP_CONFIG: bz_transaction_manager_set_config (self, g_value_get_boxed (value)); break; case PROP_BACKEND: bz_transaction_manager_set_backend (self, g_value_get_object (value)); break; case PROP_PAUSED: bz_transaction_manager_set_paused (self, g_value_get_boolean (value)); break; case PROP_TRANSACTIONS: case PROP_HAS_TRANSACTIONS: case PROP_ACTIVE: case PROP_PENDING: case PROP_CURRENT_PROGRESS: case PROP_INSTALL_TRACKERS: case PROP_REMOVAL_TRACKERS: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static gboolean filter_install_trackers (gpointer item, gpointer user_data) { BzTransactionEntryTracker *tracker = NULL; BzTransactionEntryKind kind = 0; tracker = BZ_TRANSACTION_ENTRY_TRACKER (item); if (tracker == NULL) return FALSE; kind = bz_transaction_entry_tracker_get_kind (tracker); return kind == BZ_TRANSACTION_ENTRY_KIND_INSTALL || kind == BZ_TRANSACTION_ENTRY_KIND_UPDATE; } static gboolean filter_removal_trackers (gpointer item, gpointer user_data) { BzTransactionEntryTracker *tracker = NULL; tracker = BZ_TRANSACTION_ENTRY_TRACKER (item); if (tracker == NULL) return FALSE; return bz_transaction_entry_tracker_get_kind (tracker) == BZ_TRANSACTION_ENTRY_KIND_REMOVAL; } static gpointer get_trackers_model (gpointer item, gpointer user_data) { BzTransaction *transaction = NULL; g_autoptr (GListModel) trackers = NULL; transaction = BZ_TRANSACTION (item); if (transaction == NULL) return NULL; trackers = g_object_ref (bz_transaction_get_trackers (transaction)); g_object_unref (item); return g_steal_pointer (&trackers); } static void bz_transaction_manager_class_init (BzTransactionManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = bz_transaction_manager_dispose; object_class->get_property = bz_transaction_manager_get_property; object_class->set_property = bz_transaction_manager_set_property; props[PROP_CONFIG] = g_param_spec_object ( "config", NULL, NULL, BZ_TYPE_MAIN_CONFIG, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_BACKEND] = g_param_spec_object ( "backend", NULL, NULL, BZ_TYPE_BACKEND, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_PAUSED] = g_param_spec_boolean ( "paused", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_TRANSACTIONS] = g_param_spec_object ( "transactions", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_HAS_TRANSACTIONS] = g_param_spec_boolean ( "has-transactions", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_ACTIVE] = g_param_spec_boolean ( "active", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_PENDING] = g_param_spec_boolean ( "pending", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_CURRENT_PROGRESS] = g_param_spec_double ( "current-progress", NULL, NULL, 0.0, 1.0, 0.0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_INSTALL_TRACKERS] = g_param_spec_object ( "install-trackers", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_REMOVAL_TRACKERS] = g_param_spec_object ( "removal-trackers", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); signals[SIGNAL_SUCCESS] = g_signal_new ( "success", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, BZ_TYPE_TRANSACTION, 0); g_signal_set_va_marshaller ( signals[SIGNAL_SUCCESS], G_TYPE_FROM_CLASS (klass), bz_marshal_VOID__OBJECT_BOXEDv); signals[SIGNAL_FAILURE] = g_signal_new ( "failure", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, BZ_TYPE_TRANSACTION, 0); g_signal_set_va_marshaller ( signals[SIGNAL_FAILURE], G_TYPE_FROM_CLASS (klass), g_cclosure_marshal_VOID__OBJECTv); } static void bz_transaction_manager_init (BzTransactionManager *self) { GtkCustomFilter *install_filter; GtkCustomFilter *removal_filter; GtkMapListModel *map_model; self->transactions = g_list_store_new (BZ_TYPE_TRANSACTION); g_queue_init (&self->queue); map_model = gtk_map_list_model_new ( g_object_ref (G_LIST_MODEL (self->transactions)), get_trackers_model, NULL, NULL); self->all_trackers = gtk_flatten_list_model_new (G_LIST_MODEL (map_model)); install_filter = gtk_custom_filter_new ( filter_install_trackers, NULL, NULL); self->install_trackers = gtk_filter_list_model_new ( g_object_ref (G_LIST_MODEL (self->all_trackers)), GTK_FILTER (install_filter)); removal_filter = gtk_custom_filter_new ( filter_removal_trackers, NULL, NULL); self->removal_trackers = gtk_filter_list_model_new ( g_object_ref (G_LIST_MODEL (self->all_trackers)), GTK_FILTER (removal_filter)); } BzTransactionManager * bz_transaction_manager_new (void) { return g_object_new (BZ_TYPE_TRANSACTION_MANAGER, NULL); } void bz_transaction_manager_set_config (BzTransactionManager *self, BzMainConfig *config) { g_return_if_fail (BZ_IS_TRANSACTION_MANAGER (self)); g_clear_object (&self->config); if (config != NULL) self->config = g_object_ref (config); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CONFIG]); } BzMainConfig * bz_transaction_manager_get_config (BzTransactionManager *self) { g_return_val_if_fail (BZ_IS_TRANSACTION_MANAGER (self), NULL); return self->config; } void bz_transaction_manager_set_backend (BzTransactionManager *self, BzBackend *backend) { g_return_if_fail (BZ_IS_TRANSACTION_MANAGER (self)); g_return_if_fail (backend == NULL || BZ_IS_BACKEND (backend)); g_clear_object (&self->backend); if (backend != NULL) self->backend = g_object_ref (backend); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_BACKEND]); } BzBackend * bz_transaction_manager_get_backend (BzTransactionManager *self) { g_return_val_if_fail (BZ_IS_TRANSACTION_MANAGER (self), NULL); return self->backend; } void bz_transaction_manager_set_paused (BzTransactionManager *self, gboolean paused) { g_return_if_fail (BZ_IS_TRANSACTION_MANAGER (self)); if (!!self->paused == !!paused) return; self->paused = paused; if (!paused) dex_future_disown (dispatch_next (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PAUSED]); } gboolean bz_transaction_manager_get_paused (BzTransactionManager *self) { g_return_val_if_fail (BZ_IS_TRANSACTION_MANAGER (self), FALSE); return self->paused; } gboolean bz_transaction_manager_get_active (BzTransactionManager *self) { g_return_val_if_fail (BZ_IS_TRANSACTION_MANAGER (self), FALSE); return self->loop != NULL; } gboolean bz_transaction_manager_get_pending (BzTransactionManager *self) { g_return_val_if_fail (BZ_IS_TRANSACTION_MANAGER (self), FALSE); return self->loop != NULL && self->pending; } gboolean bz_transaction_manager_get_has_transactions (BzTransactionManager *self) { g_return_val_if_fail (BZ_IS_TRANSACTION_MANAGER (self), FALSE); return g_list_model_get_n_items (G_LIST_MODEL (self->transactions)) > 0; } DexFuture * bz_transaction_manager_add (BzTransactionManager *self, BzTransaction *transaction) { g_autoptr (QueuedScheduleData) data = NULL; dex_return_error_if_fail (BZ_IS_TRANSACTION_MANAGER (self)); dex_return_error_if_fail (self->backend != NULL); dex_return_error_if_fail (BZ_IS_TRANSACTION (transaction)); bz_transaction_hold (transaction); if (self->queue.length > 0) { BzTransaction *to_merge[2] = { 0 }; g_autoptr (BzTransaction) new_transaction = NULL; guint position = 0; data = g_queue_pop_head (&self->queue); g_list_store_find (self->transactions, data->transaction, &position); g_assert (position != G_MAXUINT); to_merge[0] = g_steal_pointer (&data->transaction); to_merge[1] = g_object_ref (transaction); new_transaction = bz_transaction_new_merged (to_merge, G_N_ELEMENTS (to_merge)); g_list_store_splice (self->transactions, position, 1, (gpointer *) &new_transaction, 1); for (guint i = 0; i < G_N_ELEMENTS (to_merge); i++) g_object_unref (to_merge[i]); data->transaction = g_steal_pointer (&new_transaction); } else { data = queued_schedule_data_new (); data->self = bz_track_weak (self); data->transaction = g_object_ref (transaction); data->promise = dex_promise_new_cancellable (); g_list_store_insert (self->transactions, 0, transaction); } g_queue_push_head (&self->queue, queued_schedule_data_ref (data)); if (self->loop == NULL && !self->paused) dex_future_disown (dispatch_next (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_HAS_TRANSACTIONS]); return dex_ref (data->promise); } void bz_transaction_manager_cancel_current (BzTransactionManager *self) { g_return_if_fail (BZ_IS_TRANSACTION_MANAGER (self)); if (self->current == NULL) return; dex_promise_reject ( self->current->promise, g_error_new (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled by API")); g_object_set ( self->current->transaction, "status", "Cancelled", "progress", 1.0, "finished", TRUE, "success", FALSE, "error", "Cancelled by API", NULL); g_clear_pointer (&self->current, queued_schedule_data_unref); dex_clear (&self->loop); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ACTIVE]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PENDING]); } void bz_transaction_manager_clear_finished (BzTransactionManager *self) { guint n_items = 0; gboolean had_items = FALSE; g_return_if_fail (BZ_IS_TRANSACTION_MANAGER (self)); n_items = g_list_model_get_n_items (G_LIST_MODEL (self->transactions)); had_items = n_items > 0; for (guint i = 0; i < n_items;) { g_autoptr (BzTransaction) transaction = NULL; gboolean finished = FALSE; transaction = g_list_model_get_item (G_LIST_MODEL (self->transactions), i); g_object_get (transaction, "finished", &finished, NULL); if (finished) { g_list_store_remove (self->transactions, i); n_items--; } else i++; } if (had_items && n_items == 0) g_object_notify_by_pspec (G_OBJECT (self), props[PROP_HAS_TRANSACTIONS]); } static DexFuture * transaction_fiber (QueuedScheduleData *data) { g_autoptr (BzTransactionManager) self = NULL; BzTransaction *transaction = data->transaction; DexPromise *promise = data->promise; g_autoptr (GError) local_error = NULL; gboolean result = FALSE; g_autoptr (GListStore) store = NULL; g_autoptr (DexChannel) channel = NULL; g_autoptr (DexFuture) future = NULL; g_autoptr (GHashTable) op_set = NULL; g_autoptr (GHashTable) pending_set = NULL; GHashTableIter iter = { 0 }; bz_weak_get_or_return_reject (self, data->self); g_object_set ( transaction, "status", "Starting up...", "progress", 0.0, NULL); self->current_progress = 0.0; self->pending = TRUE; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ACTIVE]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PENDING]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CURRENT_PROGRESS]); store = g_list_store_new (BZ_TYPE_TRANSACTION); g_list_store_append (store, transaction); channel = dex_channel_new (0); future = bz_backend_merge_and_schedule_transactions ( self->backend, G_LIST_MODEL (store), channel, dex_promise_get_cancellable (promise)); op_set = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL); pending_set = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL); for (;;) { g_autoptr (GObject) object = NULL; object = dex_await_object (dex_channel_receive (channel), NULL); if (object == NULL) break; if (BZ_IS_BACKEND_TRANSACTION_OP_PAYLOAD (object)) { if (g_hash_table_contains (op_set, object)) { g_autofree char *error = NULL; error = g_object_steal_data (object, "error"); if (error != NULL) bz_transaction_error_out_task ( transaction, BZ_BACKEND_TRANSACTION_OP_PAYLOAD (object), error); else bz_transaction_finish_task ( transaction, BZ_BACKEND_TRANSACTION_OP_PAYLOAD (object)); g_hash_table_remove (op_set, object); if (g_hash_table_contains (pending_set, object)) { g_hash_table_remove (pending_set, object); self->pending = g_hash_table_size (pending_set) == g_hash_table_size (op_set); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PENDING]); } } else { bz_transaction_add_task ( transaction, BZ_BACKEND_TRANSACTION_OP_PAYLOAD (object)); g_hash_table_replace (op_set, g_object_ref (object), NULL); } } else if (BZ_IS_BACKEND_TRANSACTION_OP_PROGRESS_PAYLOAD (object)) { const char *status = NULL; gboolean is_estimating = FALSE; double total_progress = 0.0; bz_transaction_update_task ( transaction, BZ_BACKEND_TRANSACTION_OP_PROGRESS_PAYLOAD (object)); status = bz_backend_transaction_op_progress_payload_get_status ( BZ_BACKEND_TRANSACTION_OP_PROGRESS_PAYLOAD (object)); is_estimating = bz_backend_transaction_op_progress_payload_get_is_estimating ( BZ_BACKEND_TRANSACTION_OP_PROGRESS_PAYLOAD (object)); total_progress = bz_backend_transaction_op_progress_payload_get_total_progress ( BZ_BACKEND_TRANSACTION_OP_PROGRESS_PAYLOAD (object)); g_object_set ( transaction, "pending", is_estimating, "status", status, "progress", total_progress, NULL); self->current_progress = total_progress; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CURRENT_PROGRESS]); if (is_estimating && !g_hash_table_contains (pending_set, object)) { g_hash_table_replace (pending_set, g_object_ref (object), NULL); self->pending = g_hash_table_size (pending_set) == g_hash_table_size (op_set); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PENDING]); } else if (!is_estimating && g_hash_table_contains (pending_set, object)) { g_hash_table_remove (pending_set, object); self->pending = g_hash_table_size (pending_set) == g_hash_table_size (op_set); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PENDING]); } } } /* Finish off tasks that may not have received a final update */ g_hash_table_iter_init (&iter, op_set); for (;;) { BzBackendTransactionOpPayload *payload = NULL; gpointer dummy = NULL; if (!g_hash_table_iter_next ( &iter, (gpointer *) &payload, (gpointer *) &dummy)) break; bz_transaction_error_out_task (transaction, payload, "Cancelled"); } result = dex_await (g_steal_pointer (&future), &local_error); if (!result) return dex_future_new_for_error (g_steal_pointer (&local_error)); return dex_future_new_true (); } static DexFuture * transaction_finally (DexFuture *future, QueuedScheduleData *data) { g_autoptr (BzTransactionManager) self = NULL; g_autoptr (GError) local_error = NULL; BzTransaction *transaction = data->transaction; DexPromise *promise = data->promise; GTimer *timer = data->timer; const GValue *value = NULL; g_autofree char *status = NULL; bz_weak_get_or_return_reject (self, data->self); g_timer_stop (timer); status = g_strdup_printf ( _ ("Finished in %.02f seconds"), g_timer_elapsed (data->timer, NULL)); value = dex_future_get_value (future, &local_error); g_object_set ( transaction, "status", status, "progress", 1.0, "finished", TRUE, "success", value != NULL, "error", local_error != NULL ? local_error->message : NULL, NULL); self->current_progress = 1.0; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CURRENT_PROGRESS]); if (value != NULL) { g_signal_emit (self, signals[SIGNAL_SUCCESS], 0, transaction); dex_promise_resolve_boolean (promise, TRUE); } else { g_warning ("Transaction failed to complete: %s", local_error->message); g_signal_emit (self, signals[SIGNAL_FAILURE], 0, transaction); dex_promise_resolve_boolean (promise, FALSE); } return dex_future_new_true (); } static DexFuture * then_loop_cb (DexFuture *future, GWeakRef *wr) { g_autoptr (BzTransactionManager) self = NULL; bz_weak_get_or_return_reject (self, wr); g_clear_pointer (&self->current, queued_schedule_data_unref); return dispatch_next (self); } static DexFuture * dispatch_next (BzTransactionManager *self) { g_autoptr (QueuedScheduleData) data = NULL; g_autoptr (DexFuture) future = NULL; if (self->queue.length == 0 || self->paused) { dex_clear (&self->loop); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ACTIVE]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PENDING]); if (self->queue.length == 0) return dex_future_new_reject (G_IO_ERROR, G_IO_ERROR_UNKNOWN, "No more futures in queue"); if (self->paused) return dex_future_new_reject (G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Paused"); } if (self->current != NULL) { QueuedScheduleData *peek = NULL; peek = g_queue_peek_head (&self->queue); return dex_ref (peek->promise); } data = g_queue_pop_tail (&self->queue); g_clear_pointer (&data->timer, g_timer_destroy); data->timer = g_timer_new (); future = dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) transaction_fiber, queued_schedule_data_ref (data), queued_schedule_data_unref); future = dex_future_finally ( future, (DexFutureCallback) transaction_finally, queued_schedule_data_ref (data), queued_schedule_data_unref); future = dex_future_first ( future, dex_ref (data->promise), NULL); self->current = queued_schedule_data_ref (data); if (self->loop == NULL) self->loop = dex_future_then_loop ( dex_ref (future), (DexFutureCallback) then_loop_cb, bz_track_weak (self), bz_weak_release); return dex_ref (future); } static inline void finish_queued_schedule_data (gpointer ptr) { QueuedScheduleData *data = ptr; g_clear_pointer (&data->self, bz_weak_release); if (data->transaction != NULL) bz_transaction_release (data->transaction); g_clear_object (&data->transaction); if (data->promise != NULL && dex_future_is_pending (DEX_FUTURE (data->promise))) dex_promise_reject ( data->promise, g_error_new (G_IO_ERROR, G_IO_ERROR_CANCELLED, "User data was destroyed")); dex_clear (&data->promise); g_clear_pointer (&data->timer, g_timer_destroy); } bazaar-orig-v0.7.14/src/bz-context-tile.c0000664000175000017500000001675215166123241017136 0ustar hasanhasan/* bz-context-tile.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-context-tile.h" #include struct _BzContextTile { GtkButton parent_instance; char *lozenge_style; /* Template widgets */ GtkButton *ring_button; GtkBox *lozenge; GtkLabel *label; }; G_DEFINE_FINAL_TYPE (BzContextTile, bz_context_tile, GTK_TYPE_BUTTON) enum { PROP_0, PROP_LOZENGE_CHILD, PROP_LABEL, PROP_LOZENGE_STYLE, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bz_context_tile_dispose (GObject *object) { BzContextTile *self = BZ_CONTEXT_TILE (object); g_clear_pointer (&self->lozenge_style, g_free); gtk_widget_dispose_template (GTK_WIDGET (self), BZ_TYPE_CONTEXT_TILE); G_OBJECT_CLASS (bz_context_tile_parent_class)->dispose (object); } static void bz_context_tile_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzContextTile *self = BZ_CONTEXT_TILE (object); switch (prop_id) { case PROP_LOZENGE_CHILD: g_value_set_object (value, bz_context_tile_get_lozenge_child (self)); break; case PROP_LABEL: g_value_set_string (value, bz_context_tile_get_label (self)); break; case PROP_LOZENGE_STYLE: g_value_set_string (value, bz_context_tile_get_lozenge_style (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_context_tile_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzContextTile *self = BZ_CONTEXT_TILE (object); switch (prop_id) { case PROP_LOZENGE_CHILD: bz_context_tile_set_lozenge_child (self, g_value_get_object (value)); break; case PROP_LABEL: bz_context_tile_set_label (self, g_value_get_string (value)); break; case PROP_LOZENGE_STYLE: bz_context_tile_set_lozenge_style (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_context_tile_class_init (BzContextTileClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bz_context_tile_set_property; object_class->get_property = bz_context_tile_get_property; object_class->dispose = bz_context_tile_dispose; props[PROP_LOZENGE_CHILD] = g_param_spec_object ( "lozenge-child", NULL, NULL, GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_LABEL] = g_param_spec_string ( "label", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_LOZENGE_STYLE] = g_param_spec_string ( "lozenge-style", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-context-tile.ui"); gtk_widget_class_bind_template_child (widget_class, BzContextTile, lozenge); gtk_widget_class_bind_template_child (widget_class, BzContextTile, label); gtk_widget_class_bind_template_child (widget_class, BzContextTile, ring_button); } static void on_enter_notify (GtkEventController *controller, gpointer user_data) { g_autoptr (GdkCursor) cursor = gdk_cursor_new_from_name ("pointer", NULL); gtk_widget_set_cursor (GTK_WIDGET (user_data), cursor); } static void on_leave_notify (GtkEventController *controller, gpointer user_data) { gtk_widget_set_cursor (GTK_WIDGET (user_data), NULL); } static void on_ring_button_clicked (GtkButton *ring_button, gpointer user_data) { BzContextTile *self = BZ_CONTEXT_TILE (user_data); g_signal_emit_by_name (self, "clicked"); } static void bz_context_tile_init (BzContextTile *self) { GtkEventController *enter_leave = gtk_event_controller_motion_new (); gtk_widget_init_template (GTK_WIDGET (self)); g_signal_connect (self->ring_button, "clicked", G_CALLBACK (on_ring_button_clicked), self); g_signal_connect (enter_leave, "enter", G_CALLBACK (on_enter_notify), GTK_WIDGET (self)); g_signal_connect (enter_leave, "leave", G_CALLBACK (on_leave_notify), GTK_WIDGET (self)); gtk_widget_add_controller (GTK_WIDGET (self), enter_leave); } BzContextTile * bz_context_tile_new (void) { return g_object_new (BZ_TYPE_CONTEXT_TILE, NULL); } GtkWidget * bz_context_tile_get_lozenge_child (BzContextTile *self) { g_return_val_if_fail (BZ_IS_CONTEXT_TILE (self), NULL); return gtk_widget_get_first_child (GTK_WIDGET (self->lozenge)); } void bz_context_tile_set_lozenge_child (BzContextTile *self, GtkWidget *child) { GtkWidget *old_child; g_return_if_fail (BZ_IS_CONTEXT_TILE (self)); old_child = gtk_widget_get_first_child (GTK_WIDGET (self->lozenge)); if (old_child == child) return; if (old_child != NULL) gtk_box_remove (self->lozenge, old_child); if (child != NULL) gtk_box_append (self->lozenge, child); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_LOZENGE_CHILD]); } const char * bz_context_tile_get_label (BzContextTile *self) { g_return_val_if_fail (BZ_IS_CONTEXT_TILE (self), NULL); return gtk_label_get_label (self->label); } void bz_context_tile_set_label (BzContextTile *self, const char *label) { g_return_if_fail (BZ_IS_CONTEXT_TILE (self)); if (g_strcmp0 (gtk_label_get_label (self->label), label) == 0) return; gtk_label_set_label (self->label, label); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_LABEL]); } const char * bz_context_tile_get_lozenge_style (BzContextTile *self) { g_return_val_if_fail (BZ_IS_CONTEXT_TILE (self), NULL); return self->lozenge_style; } void bz_context_tile_set_lozenge_style (BzContextTile *self, const char *style) { g_return_if_fail (BZ_IS_CONTEXT_TILE (self)); if (style != NULL && *style == '\0') style = NULL; if (g_strcmp0 (self->lozenge_style, style) == 0) return; if (self->lozenge_style != NULL) gtk_widget_remove_css_class (GTK_WIDGET (self->lozenge), self->lozenge_style); g_clear_pointer (&self->lozenge_style, g_free); if (style != NULL) { self->lozenge_style = g_strdup (style); gtk_widget_add_css_class (GTK_WIDGET (self->lozenge), self->lozenge_style); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_LOZENGE_STYLE]); } bazaar-orig-v0.7.14/src/bz-hardware-support-dialog.c0000664000175000017500000002351515166123241021256 0ustar hasanhasan/* bz-hardware-support-dialog.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-hardware-support-dialog.h" #include "bz-context-row.h" #include "bz-lozenge.h" #include struct _BzHardwareSupportDialog { AdwDialog parent_instance; BzEntry *entry; gulong entry_notify_handler; /* Template widgets */ BzLozenge *lozenge; GtkListBox *list; }; G_DEFINE_FINAL_TYPE (BzHardwareSupportDialog, bz_hardware_support_dialog, ADW_TYPE_DIALOG) enum { PROP_0, PROP_ENTRY, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; typedef struct { const gchar *icon_name; const gchar *title; BzControlType control_flag; const gchar *required_subtitle; const gchar *recommended_subtitle; const gchar *supported_subtitle; const gchar *unsupported_subtitle; } ControlInfo; static const ControlInfo control_infos[] = { { "input-keyboard-symbolic", N_ ("Keyboard support"), BZ_CONTROL_KEYBOARD, N_ ("Requires keyboards"), N_ ("Recommends keyboards"), N_ ("Supports keyboards"), N_ ("Unknown support for keyboards") }, { "input-mouse-symbolic", N_ ("Mouse support"), BZ_CONTROL_POINTING, N_ ("Requires mice or pointing devices"), N_ ("Recommends mice or pointing devices"), N_ ("Supports mice or pointing devices"), N_ ("Unknown support for mice or pointing devices") }, { "device-support-touch-symbolic", N_ ("Touchscreen support"), BZ_CONTROL_TOUCH, N_ ("Requires touchscreens"), N_ ("Recommends touchscreens"), N_ ("Supports touchscreens"), N_ ("Unknown support for touchscreens") } }; static BzImportance get_control_importance (guint required_controls, guint recommended_controls, guint supported_controls, BzControlType control_flag) { if (required_controls & control_flag) return BZ_IMPORTANCE_IMPORTANT; else if (recommended_controls & control_flag) return BZ_IMPORTANCE_INFORMATION; else if (supported_controls & control_flag) return BZ_IMPORTANCE_UNIMPORTANT; else return BZ_IMPORTANCE_NEUTRAL; } static const gchar * get_subtitle_for_importance (const ControlInfo *info, BzImportance importance) { switch (importance) { case BZ_IMPORTANCE_IMPORTANT: return _ (info->required_subtitle); case BZ_IMPORTANCE_INFORMATION: return _ (info->recommended_subtitle); case BZ_IMPORTANCE_UNIMPORTANT: return _ (info->supported_subtitle); case BZ_IMPORTANCE_NEUTRAL: return _ (info->unsupported_subtitle); case BZ_IMPORTANCE_WARNING: default: g_assert_not_reached (); } } static void add_control_row (BzHardwareSupportDialog *self, const ControlInfo *info, BzImportance importance) { AdwActionRow *row; const gchar *subtitle; subtitle = get_subtitle_for_importance (info, importance); row = bz_context_row_new (info->icon_name, importance, _ (info->title), subtitle); gtk_list_box_append (self->list, GTK_WIDGET (row)); } static void update_list (BzHardwareSupportDialog *self) { GtkWidget *child; AdwActionRow *row; guint required_controls; guint recommended_controls; guint supported_controls; gboolean is_mobile_friendly; while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->list))) != NULL) gtk_list_box_remove (self->list, child); if (self->entry == NULL) return; required_controls = bz_entry_get_required_controls (self->entry); recommended_controls = bz_entry_get_recommended_controls (self->entry); supported_controls = bz_entry_get_supported_controls (self->entry); is_mobile_friendly = bz_entry_get_is_mobile_friendly (self->entry); row = bz_context_row_new ("phone-symbolic", is_mobile_friendly ? BZ_IMPORTANCE_UNIMPORTANT : BZ_IMPORTANCE_NEUTRAL, _ ("Mobile support"), is_mobile_friendly ? _ ("Works on mobile devices") : _ ("May not work well on mobile devices")); gtk_list_box_append (self->list, GTK_WIDGET (row)); row = bz_context_row_new ("device-support-desktop-symbolic", BZ_IMPORTANCE_UNIMPORTANT, _ ("Desktop support"), _ ("Works well on large screens")); gtk_list_box_append (self->list, GTK_WIDGET (row)); for (gsize i = 0; i < G_N_ELEMENTS (control_infos); i++) { BzImportance importance; importance = get_control_importance (required_controls, recommended_controls, supported_controls, control_infos[i].control_flag); add_control_row (self, &control_infos[i], importance); } } static void update_header (BzHardwareSupportDialog *self) { const gchar *icon_names[2]; g_autofree gchar *title_text = NULL; BzImportance importance; guint required_controls; gboolean is_mobile_friendly; if (self->entry == NULL) return; required_controls = bz_entry_get_required_controls (self->entry); is_mobile_friendly = bz_entry_get_is_mobile_friendly (self->entry); if (required_controls != BZ_CONTROL_NONE || !is_mobile_friendly) { icon_names[0] = "dialog-warning-symbolic"; icon_names[1] = NULL; title_text = g_strdup_printf (_ ("%s works best on specific hardware"), bz_entry_get_title (self->entry)); importance = BZ_IMPORTANCE_NEUTRAL; } else { icon_names[0] = "device-supported-symbolic"; icon_names[1] = NULL; title_text = g_strdup_printf (_ ("%s works on most devices"), bz_entry_get_title (self->entry)); importance = BZ_IMPORTANCE_UNIMPORTANT; } bz_lozenge_set_icon_names (self->lozenge, icon_names); bz_lozenge_set_title (self->lozenge, title_text); bz_lozenge_set_importance (self->lozenge, importance); } static void update_ui (BzHardwareSupportDialog *self) { update_list (self); update_header (self); } static void entry_notify_cb (GObject *obj, GParamSpec *pspec, gpointer user_data) { BzHardwareSupportDialog *self = BZ_HARDWARE_SUPPORT_DIALOG (user_data); update_ui (self); } static void bz_hardware_support_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzHardwareSupportDialog *self = BZ_HARDWARE_SUPPORT_DIALOG (object); switch (prop_id) { case PROP_ENTRY: self->entry = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_hardware_support_dialog_constructed (GObject *object) { BzHardwareSupportDialog *self = BZ_HARDWARE_SUPPORT_DIALOG (object); G_OBJECT_CLASS (bz_hardware_support_dialog_parent_class)->constructed (object); if (self->entry != NULL) { self->entry_notify_handler = g_signal_connect (self->entry, "notify", G_CALLBACK (entry_notify_cb), self); update_ui (self); } } static void bz_hardware_support_dialog_dispose (GObject *object) { BzHardwareSupportDialog *self = BZ_HARDWARE_SUPPORT_DIALOG (object); g_clear_signal_handler (&self->entry_notify_handler, self->entry); g_clear_object (&self->entry); gtk_widget_dispose_template (GTK_WIDGET (self), BZ_TYPE_HARDWARE_SUPPORT_DIALOG); G_OBJECT_CLASS (bz_hardware_support_dialog_parent_class)->dispose (object); } static void bz_hardware_support_dialog_class_init (BzHardwareSupportDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bz_hardware_support_dialog_set_property; object_class->constructed = bz_hardware_support_dialog_constructed; object_class->dispose = bz_hardware_support_dialog_dispose; props[PROP_ENTRY] = g_param_spec_object ( "entry", NULL, NULL, BZ_TYPE_ENTRY, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_LOZENGE); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-hardware-support-dialog.ui"); gtk_widget_class_bind_template_child (widget_class, BzHardwareSupportDialog, lozenge); gtk_widget_class_bind_template_child (widget_class, BzHardwareSupportDialog, list); } static void bz_hardware_support_dialog_init (BzHardwareSupportDialog *self) { gtk_widget_init_template (GTK_WIDGET (self)); } BzHardwareSupportDialog * bz_hardware_support_dialog_new (BzEntry *entry) { return g_object_new (BZ_TYPE_HARDWARE_SUPPORT_DIALOG, "entry", entry, NULL); } bazaar-orig-v0.7.14/src/bz-rich-app-tile.blp0000664000175000017500000001235715166123241017505 0ustar hasanhasanusing Gtk 4.0; template $BzRichAppTile: $BzListTile { overflow: hidden; accessibility { described-by: description; } child: Box { orientation: vertical; styles [ "rich-tile-card", ] $BzThemedEntryGroupRect picture_box { height-request: 200; styles [ "rich-screenshot-box", ] group: bind template.group as <$BzEntryGroup>; child: Box { margin-start: 12; margin-end: 12; margin-top: 12; margin-bottom: 12; Image { icon-name: "image-missing-symbolic"; pixel-size: 96; halign: center; valign: center; hexpand: true; visible: bind $is_null(template.ui-entry as <$BzEntry>.thumbnail-paintable) as ; } $BzRoundedPicture { halign: center; hexpand: true; valign: center; paintable: bind template.ui-entry as <$BzEntry>.thumbnail-paintable; radius: 6; visible: bind $invert_boolean($is_null(template.ui-entry as <$BzEntry>.thumbnail-paintable) as ) as ; } }; } Box { margin-start: 12; margin-end: 12; margin-top: 12; margin-bottom: 12; orientation: horizontal; spacing: 15; height-request: 64; Image { pixel-size: 64; paintable: bind template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable; visible: bind $invert_boolean($is_null(template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable) as ) as ; styles [ "icon-dropshadow", ] } Box { valign: center; hexpand: true; orientation: vertical; spacing: 5; Box { spacing: 6; Label title { css-name: "app-tile-title"; styles [ "heading", ] xalign: 0.0; ellipsize: end; label: bind template.group as <$BzEntryGroup>.title; max-width-chars: 18; } Image { styles [ "verified", ] visible: bind template.group as <$BzEntryGroup>.is-verified; icon-name: "verified-checkmark-symbolic"; pixel-size: 14; accessibility { label: _("Verified"); } } } Label description { visible: bind $is_null(template.group as <$BzEntryGroup>.eol) as ; css-name: "app-tile-description"; xalign: 0.0; yalign: 0.0; wrap: true; wrap-mode: word_char; ellipsize: end; vexpand: true; lines: 2; max-width-chars: 15; single-line-mode: true; label: bind template.group as <$BzEntryGroup>.description; styles [ "dimmed", ] } Label { visible: bind $invert_boolean($is_null(template.group as <$BzEntryGroup>.eol) as ) as ; css-name: "app-tile-description"; xalign: 0.0; yalign: 0.0; wrap: true; wrap-mode: word_char; ellipsize: end; vexpand: true; lines: 2; max-width-chars: 15; single-line-mode: true; label: _("Stopped Receiving Updates"); styles [ "warning", ] } } Box { Button { visible: bind $logical_and($invert_boolean($is_zero(template.group as <$BzEntryGroup>.installable) as ) as , $is_zero(template.group as <$BzEntryGroup>.removable) as ) as ; sensitive: bind $invert_boolean($is_zero(template.group as <$BzEntryGroup>.installable-and-available) as ) as ; styles [ "medium-pill", ] label: _("Get"); valign: center; clicked => $install_button_clicked_cb(template); } Button { visible: bind $logical_and($invert_boolean($is_zero(template.group as <$BzEntryGroup>.removable) as ) as , template.removable-at-start) as ; sensitive: bind $logical_and($invert_boolean($is_zero(template.group as <$BzEntryGroup>.removable-and-available) as ) as , template.removable-at-start) as ; styles [ "circular" ] icon-name: "user-trash-symbolic"; has-tooltip: true; tooltip-text: _("Uninstall"); valign: center; clicked => $remove_button_clicked_cb(template); } Button { visible: bind $logical_and($invert_boolean($is_zero(template.group as <$BzEntryGroup>.removable) as ) as , $invert_boolean(template.removable-at-start) as ) as ; sensitive: bind $logical_and($invert_boolean($is_zero(template.group as <$BzEntryGroup>.removable-and-available) as ) as , $invert_boolean(template.removable-at-start) as ) as ; styles [ "medium-pill", ] label: _("Open"); valign: center; clicked => $run_button_clicked_cb(template); } } } }; } bazaar-orig-v0.7.14/src/bz-addons-dialog.c0000664000175000017500000005556215166123241017226 0ustar hasanhasan/* bz-addons-dialog.c * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include "bz-addon-tile.h" #include "bz-addons-dialog.h" #include "bz-app-size-dialog.h" #include "bz-application-map-factory.h" #include "bz-application.h" #include "bz-appstream-description-render.h" #include "bz-context-tile-callbacks.h" #include "bz-context-tile.h" #include "bz-entry-group.h" #include "bz-fading-clamp.h" #include "bz-flatpak-entry.h" #include "bz-install-controls.h" #include "bz-license-dialog.h" #include "bz-result.h" #include "bz-share-list.h" #include "bz-state-info.h" #include "bz-stats-dialog.h" #include "bz-template-callbacks.h" #include "bz-util.h" struct _BzAddonsDialog { AdwDialog parent_instance; GListModel *addon_groups; BzEntryGroup *selected_group; BzResult *selected_ui_entry; DexFuture *selected_ui_future; BzResult *parent_ui_entry; DexFuture *parent_ui_future; AdwAnimation *width_animation; AdwAnimation *height_animation; /* Template widgets */ AdwNavigationView *navigation_view; GtkToggleButton *description_toggle; AdwClamp *full_view_clamp; AdwClamp *list_clamp; GtkCustomSorter *sorter; }; G_DEFINE_FINAL_TYPE (BzAddonsDialog, bz_addons_dialog, ADW_TYPE_DIALOG) enum { PROP_0, PROP_ADDON_GROUPS, PROP_SELECTED_GROUP, PROP_SELECTED_UI_ENTRY, PROP_PARENT_UI_ENTRY, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static char *format_parent_title (gpointer object, const char *title); static int get_description_max_height (gpointer object, gboolean active); static char *get_description_toggle_text (gpointer object, gboolean active); static void size_cb (BzAddonsDialog *self, GtkButton *button); static void license_cb (BzAddonsDialog *self, GtkButton *button); static void dl_stats_cb (BzAddonsDialog *self, GtkButton *button); static void animate_to_size (BzAddonsDialog *self); static void on_visible_page_tag_changed (AdwNavigationView *nav_view, GParamSpec *pspec, BzAddonsDialog *self); static char *get_install_stack_page (gpointer object, int installable, int removable); static void install_cb (GtkButton *button, BzAddonsDialog *self); static void remove_cb (GtkButton *button, BzAddonsDialog *self); static void run_cb (GtkButton *button, BzAddonsDialog *self); static DexFuture *on_parent_ui_entry_resolved (DexFuture *future, GWeakRef *wr); static DexFuture *on_selected_ui_entry_resolved (DexFuture *future, GWeakRef *wr); static void set_selected_group (BzAddonsDialog *self, BzEntryGroup *group); static void tile_activated_cb (BzAddonTile *tile); static int sort_func (BzEntryGroup *a, BzEntryGroup *b, BzAddonsDialog *self); static void bz_addons_dialog_dispose (GObject *object) { BzAddonsDialog *self = BZ_ADDONS_DIALOG (object); dex_clear (&self->selected_ui_future); dex_clear (&self->parent_ui_future); g_clear_object (&self->addon_groups); g_clear_object (&self->selected_group); g_clear_object (&self->selected_ui_entry); g_clear_object (&self->parent_ui_entry); g_clear_object (&self->width_animation); g_clear_object (&self->height_animation); G_OBJECT_CLASS (bz_addons_dialog_parent_class)->dispose (object); } static void bz_addons_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzAddonsDialog *self = BZ_ADDONS_DIALOG (object); switch (prop_id) { case PROP_ADDON_GROUPS: g_value_set_object (value, self->addon_groups); break; case PROP_SELECTED_GROUP: g_value_set_object (value, self->selected_group); break; case PROP_SELECTED_UI_ENTRY: g_value_set_object (value, self->selected_ui_entry); break; case PROP_PARENT_UI_ENTRY: g_value_set_object (value, self->parent_ui_entry); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_addons_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzAddonsDialog *self = BZ_ADDONS_DIALOG (object); switch (prop_id) { case PROP_ADDON_GROUPS: g_clear_object (&self->addon_groups); self->addon_groups = g_value_dup_object (value); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ADDON_GROUPS]); break; case PROP_SELECTED_GROUP: g_clear_object (&self->selected_group); self->selected_group = g_value_dup_object (value); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SELECTED_GROUP]); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_addons_dialog_class_init (BzAddonsDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_addons_dialog_dispose; object_class->get_property = bz_addons_dialog_get_property; object_class->set_property = bz_addons_dialog_set_property; props[PROP_ADDON_GROUPS] = g_param_spec_object ( "addon-groups", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_SELECTED_GROUP] = g_param_spec_object ( "selected-group", NULL, NULL, BZ_TYPE_ENTRY_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_SELECTED_UI_ENTRY] = g_param_spec_object ( "selected-ui-entry", NULL, NULL, BZ_TYPE_RESULT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_PARENT_UI_ENTRY] = g_param_spec_object ( "parent-ui-entry", NULL, NULL, BZ_TYPE_RESULT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_ADDON_TILE); g_type_ensure (BZ_TYPE_APPSTREAM_DESCRIPTION_RENDER); g_type_ensure (BZ_TYPE_CONTEXT_TILE); g_type_ensure (BZ_TYPE_ENTRY); g_type_ensure (BZ_TYPE_ENTRY_GROUP); g_type_ensure (BZ_TYPE_FADING_CLAMP); g_type_ensure (BZ_TYPE_FLATPAK_ENTRY); g_type_ensure (BZ_TYPE_INSTALL_CONTROLS); g_type_ensure (BZ_TYPE_RESULT); g_type_ensure (BZ_TYPE_SHARE_LIST); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-addons-dialog.ui"); bz_widget_class_bind_all_util_callbacks (widget_class); bz_widget_class_bind_all_context_tile_callbacks (widget_class); gtk_widget_class_bind_template_child (widget_class, BzAddonsDialog, navigation_view); gtk_widget_class_bind_template_child (widget_class, BzAddonsDialog, description_toggle); gtk_widget_class_bind_template_child (widget_class, BzAddonsDialog, full_view_clamp); gtk_widget_class_bind_template_child (widget_class, BzAddonsDialog, list_clamp); gtk_widget_class_bind_template_child (widget_class, BzAddonsDialog, sorter); gtk_widget_class_bind_template_callback (widget_class, tile_activated_cb); gtk_widget_class_bind_template_callback (widget_class, on_visible_page_tag_changed); gtk_widget_class_bind_template_callback (widget_class, format_parent_title); gtk_widget_class_bind_template_callback (widget_class, get_description_max_height); gtk_widget_class_bind_template_callback (widget_class, get_description_toggle_text); gtk_widget_class_bind_template_callback (widget_class, get_install_stack_page); gtk_widget_class_bind_template_callback (widget_class, install_cb); gtk_widget_class_bind_template_callback (widget_class, remove_cb); gtk_widget_class_bind_template_callback (widget_class, run_cb); gtk_widget_class_bind_template_callback (widget_class, license_cb); gtk_widget_class_bind_template_callback (widget_class, size_cb); gtk_widget_class_bind_template_callback (widget_class, dl_stats_cb); } static void bz_addons_dialog_init (BzAddonsDialog *self) { AdwAnimationTarget *width_target = NULL; AdwAnimationTarget *height_target = NULL; gtk_widget_init_template (GTK_WIDGET (self)); width_target = adw_property_animation_target_new (G_OBJECT (self), "content-width"); self->width_animation = adw_timed_animation_new (GTK_WIDGET (self), 0, 0, 300, width_target); height_target = adw_property_animation_target_new (G_OBJECT (self), "content-height"); self->height_animation = adw_timed_animation_new (GTK_WIDGET (self), 0, 0, 300, height_target); g_signal_connect_swapped (self, "map", G_CALLBACK (animate_to_size), self); gtk_custom_sorter_set_sort_func (self->sorter, (GCompareDataFunc) sort_func, self, NULL); } AdwDialog * bz_addons_dialog_new (BzEntryGroup *group) { GListModel *ids = NULL; GListModel *groups = NULL; BzApplicationMapFactory *factory = NULL; BzAddonsDialog *self = NULL; ids = bz_entry_group_get_addon_group_ids (group); if (ids != NULL) { factory = bz_state_info_get_application_factory (bz_state_info_get_default ()); if (factory != NULL) groups = bz_application_map_factory_generate (factory, ids); } self = g_object_new ( BZ_TYPE_ADDONS_DIALOG, "addon-groups", groups, NULL); if (groups == NULL || g_list_model_get_n_items (groups) == 0) adw_navigation_view_replace (self->navigation_view, (AdwNavigationPage *[]) { adw_navigation_view_find_page (self->navigation_view, "empty") }, 1); else if (g_list_model_get_n_items (groups) == 1) { g_autoptr (BzEntryGroup) single = g_list_model_get_item (groups, 0); AdwNavigationPage *full_view_page = NULL; set_selected_group (self, single); full_view_page = adw_navigation_view_find_page (self->navigation_view, "full-view"); adw_navigation_view_replace (self->navigation_view, &full_view_page, 1); } return ADW_DIALOG (self); } AdwDialog * bz_addons_dialog_new_single (BzEntryGroup *group) { BzAddonsDialog *self = NULL; AdwNavigationPage *full_view = NULL; self = g_object_new (BZ_TYPE_ADDONS_DIALOG, NULL); set_selected_group (self, group); full_view = adw_navigation_view_find_page (self->navigation_view, "full-view"); adw_navigation_view_replace (self->navigation_view, &full_view, 1); return ADW_DIALOG (self); } static char * format_parent_title (gpointer object, const char *title) { if (title == NULL || *title == '\0') return g_strdup (""); return g_strdup_printf (_ ("Add-on for %s"), title); } static int get_description_max_height (gpointer object, gboolean active) { return active ? 10000 : 170; } static char * get_description_toggle_text (gpointer object, gboolean active) { return g_strdup (active ? _ ("Show Less") : _ ("Show More")); } static void size_cb (BzAddonsDialog *self, GtkButton *button) { AdwNavigationPage *page = NULL; if (self->selected_group == NULL) return; page = bz_app_size_page_new (self->selected_group); adw_navigation_view_push (self->navigation_view, page); } static void license_cb (BzAddonsDialog *self, GtkButton *button) { AdwNavigationPage *page = NULL; BzEntry *ui_entry = NULL; if (self->selected_ui_entry == NULL) return; ui_entry = bz_result_get_object (self->selected_ui_entry); if (ui_entry == NULL) return; page = bz_license_page_new (ui_entry); adw_navigation_view_push (self->navigation_view, page); } static void dl_stats_cb (BzAddonsDialog *self, GtkButton *button) { BzStatsDialog *bin = NULL; AdwNavigationPage *page = NULL; BzEntry *ui_entry = NULL; if (self->selected_ui_entry == NULL) return; ui_entry = bz_result_get_object (self->selected_ui_entry); if (ui_entry == NULL) return; bin = BZ_STATS_DIALOG (bz_stats_dialog_new (NULL, NULL, 0)); page = adw_navigation_page_new (GTK_WIDGET (bin), _ ("Download Stats")); adw_navigation_page_set_tag (page, "stats"); g_object_bind_property (ui_entry, "download-stats", bin, "model", G_BINDING_SYNC_CREATE); g_object_bind_property (ui_entry, "total-downloads", bin, "total-downloads", G_BINDING_SYNC_CREATE); adw_navigation_view_push (self->navigation_view, page); bz_stats_dialog_animate_open (bin); } static void animate_to_size (BzAddonsDialog *self) { const char *tag = NULL; int target_width = 0; int target_height = 0; int nat = 0; int cur_width = 0; int measure_for = 0; int cur_w = 0; int cur_h = 0; int delta_w = 0; int delta_h = 0; int delta = 0; guint duration = 0; tag = adw_navigation_view_get_visible_page_tag (self->navigation_view); if (g_strcmp0 (tag, "list") == 0) { cur_width = gtk_widget_get_width (GTK_WIDGET (self)); target_width = 500; measure_for = MAX (-1, MIN (target_width, cur_width) - 48); gtk_widget_measure (GTK_WIDGET (self->list_clamp), GTK_ORIENTATION_VERTICAL, measure_for, NULL, &nat, NULL, NULL); target_height = CLAMP (nat + 50, 150, 600); } else if (g_strcmp0 (tag, "full-view") == 0) { cur_width = gtk_widget_get_width (GTK_WIDGET (self)); target_width = 500; measure_for = MAX (-1, MIN (target_width, cur_width) - 48); gtk_widget_measure (GTK_WIDGET (self->full_view_clamp), GTK_ORIENTATION_VERTICAL, measure_for, NULL, &nat, NULL, NULL); target_height = CLAMP (nat + 50, 300, 700); } else if (g_strcmp0 (tag, "app-size") == 0) { target_width = 500; target_height = 300; } else if (g_strcmp0 (tag, "license") == 0) { cur_width = gtk_widget_get_width (GTK_WIDGET (self)); target_width = 400; measure_for = target_width - 48; gtk_widget_measure (GTK_WIDGET (self->navigation_view), GTK_ORIENTATION_VERTICAL, measure_for, NULL, &nat, NULL, NULL); target_height = CLAMP (nat, 300, 700); } else if (g_strcmp0 (tag, "stats") == 0) { target_width = 1250; target_height = 750; } else if (g_strcmp0 (tag, "empty") == 0) { target_width = 500; target_height = 500; } else return; cur_w = adw_dialog_get_content_width (ADW_DIALOG (self)); cur_h = adw_dialog_get_content_height (ADW_DIALOG (self)); delta_w = ABS (target_width - cur_w); delta_h = ABS (target_height - cur_h); delta = MAX (delta_w, delta_h); duration = (guint) CLAMP (delta * 0.6, 200, (target_width < cur_w || target_height < cur_h) ? 300 : 600); adw_timed_animation_set_duration (ADW_TIMED_ANIMATION (self->width_animation), duration); adw_timed_animation_set_duration (ADW_TIMED_ANIMATION (self->height_animation), duration); adw_timed_animation_set_value_from (ADW_TIMED_ANIMATION (self->width_animation), cur_w); adw_timed_animation_set_value_to (ADW_TIMED_ANIMATION (self->width_animation), target_width); adw_timed_animation_set_value_from (ADW_TIMED_ANIMATION (self->height_animation), cur_h); adw_timed_animation_set_value_to (ADW_TIMED_ANIMATION (self->height_animation), target_height); adw_animation_play (self->width_animation); adw_animation_play (self->height_animation); } static void on_visible_page_tag_changed (AdwNavigationView *nav_view, GParamSpec *pspec, BzAddonsDialog *self) { g_idle_add_once ((GSourceOnceFunc) animate_to_size, self); } static char * get_install_stack_page (gpointer object, int installable, int removable) { if (removable > 0) return g_strdup ("open"); else if (installable > 0) return g_strdup ("install"); else return g_strdup ("empty"); } static void install_cb (GtkButton *button, BzAddonsDialog *self) { if (self->selected_group == NULL) return; gtk_widget_activate_action (GTK_WIDGET (self), "window.install-group", "(sb)", bz_entry_group_get_id (self->selected_group), TRUE); } static void remove_cb (GtkButton *button, BzAddonsDialog *self) { if (self->selected_group == NULL) return; gtk_widget_activate_action (GTK_WIDGET (self), "window.remove-group", "(sb)", bz_entry_group_get_id (self->selected_group), TRUE); } static void run_cb (GtkButton *button, BzAddonsDialog *self) { BzEntry *entry = NULL; entry = bz_result_get_object (self->parent_ui_entry); gtk_widget_activate_action (GTK_WIDGET (self), "window.launch-group", "s", bz_entry_get_id (entry)); } static DexFuture * on_parent_ui_entry_resolved (DexFuture *future, GWeakRef *wr) { g_autoptr (BzAddonsDialog) self = NULL; bz_weak_get_or_return_reject (self, wr); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PARENT_UI_ENTRY]); return dex_future_new_for_boolean (TRUE); } static DexFuture * on_selected_ui_entry_resolved (DexFuture *future, GWeakRef *wr) { g_autoptr (BzAddonsDialog) self = NULL; const GValue *value = NULL; g_autoptr (BzEntry) ui_entry = NULL; const char *ref = NULL; g_auto (GStrv) parts = NULL; BzApplicationMapFactory *factory = NULL; GtkStringObject *item = NULL; BzEntryGroup *parent_group = NULL; bz_weak_get_or_return_reject (self, wr); value = dex_future_get_value (future, NULL); if (value == NULL || !G_VALUE_HOLDS_OBJECT (value)) return dex_future_new_for_boolean (TRUE); ui_entry = g_value_dup_object (value); if (ui_entry == NULL || !BZ_IS_FLATPAK_ENTRY (ui_entry)) return dex_future_new_for_boolean (TRUE); ref = bz_flatpak_entry_get_addon_extension_of_ref (BZ_FLATPAK_ENTRY (ui_entry)); if (ref == NULL) return dex_future_new_for_boolean (TRUE); parts = g_strsplit (ref, "/", -1); if (parts[0] == NULL || parts[1] == NULL) return dex_future_new_for_boolean (TRUE); factory = bz_state_info_get_application_factory (bz_state_info_get_default ()); item = gtk_string_object_new (parts[1]); parent_group = bz_application_map_factory_convert_one (factory, item); if (parent_group == NULL) return dex_future_new_for_boolean (TRUE); g_clear_object (&self->parent_ui_entry); self->parent_ui_entry = bz_entry_group_dup_ui_entry (parent_group); if (self->parent_ui_entry == NULL) return dex_future_new_for_boolean (TRUE); if (bz_result_get_resolved (self->parent_ui_entry)) { g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PARENT_UI_ENTRY]); } else { g_autoptr (DexFuture) parent_future = NULL; GWeakRef *parent_wr = NULL; parent_future = bz_result_dup_future (self->parent_ui_entry); parent_wr = bz_track_weak (self); parent_future = dex_future_then ( parent_future, (DexFutureCallback) on_parent_ui_entry_resolved, parent_wr, bz_weak_release); dex_clear (&self->parent_ui_future); self->parent_ui_future = g_steal_pointer (&parent_future); } return dex_future_new_for_boolean (TRUE); } static void set_selected_group (BzAddonsDialog *self, BzEntryGroup *group) { dex_clear (&self->selected_ui_future); dex_clear (&self->parent_ui_future); g_clear_object (&self->selected_group); g_clear_object (&self->selected_ui_entry); g_clear_object (&self->parent_ui_entry); gtk_toggle_button_set_active (self->description_toggle, FALSE); if (group == NULL) return; self->selected_group = g_object_ref (group); self->selected_ui_entry = bz_entry_group_dup_ui_entry (group); if (self->selected_ui_entry == NULL) goto notify; if (bz_result_get_resolved (self->selected_ui_entry)) { g_autoptr (BzEntry) entry = NULL; g_autoptr (DexFuture) object_future = NULL; GWeakRef *wr = NULL; entry = g_object_ref (bz_result_get_object (self->selected_ui_entry)); object_future = dex_future_new_for_object (entry); wr = bz_track_weak (self); dex_unref (on_selected_ui_entry_resolved (object_future, wr)); bz_weak_release (wr); } else { g_autoptr (DexFuture) ui_future = NULL; GWeakRef *wr = NULL; ui_future = bz_result_dup_future (self->selected_ui_entry); wr = bz_track_weak (self); ui_future = dex_future_then ( ui_future, (DexFutureCallback) on_selected_ui_entry_resolved, wr, bz_weak_release); self->selected_ui_future = g_steal_pointer (&ui_future); } notify: g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SELECTED_GROUP]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SELECTED_UI_ENTRY]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PARENT_UI_ENTRY]); } static void tile_activated_cb (BzAddonTile *tile) { BzAddonsDialog *self = NULL; BzEntryGroup *group = NULL; self = BZ_ADDONS_DIALOG (gtk_widget_get_ancestor (GTK_WIDGET (tile), BZ_TYPE_ADDONS_DIALOG)); if (self == NULL) return; group = bz_addon_tile_get_group (tile); if (group == NULL) return; set_selected_group (self, group); adw_navigation_view_push_by_tag (self->navigation_view, "full-view"); } static int sort_func (BzEntryGroup *a, BzEntryGroup *b, BzAddonsDialog *self) { const char *desc_a = NULL; const char *desc_b = NULL; gboolean has_a = FALSE; gboolean has_b = FALSE; int result = 0; desc_a = bz_entry_group_get_description (a); desc_b = bz_entry_group_get_description (b); has_a = desc_a != NULL && *desc_a != '\0'; has_b = desc_b != NULL && *desc_b != '\0'; if (has_a != has_b) result = has_b - has_a; else result = g_utf8_collate (bz_entry_group_get_title (a), bz_entry_group_get_title (b)); return result; } bazaar-orig-v0.7.14/src/bz-curated-app-tile.c0000664000175000017500000001104215166123241017642 0ustar hasanhasan/* bz-curated-app-tile.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-curated-app-tile.h" #include "bz-app-tile.h" struct _BzCuratedAppTile { AdwBin parent_instance; BzEntryGroup *group; }; G_DEFINE_FINAL_TYPE (BzCuratedAppTile, bz_curated_app_tile, ADW_TYPE_BIN); enum { PROP_0, PROP_GROUP, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; enum { SIGNAL_CLICKED, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL]; static void bz_curated_app_tile_dispose (GObject *object) { BzCuratedAppTile *self = BZ_CURATED_APP_TILE (object); g_clear_pointer (&self->group, g_object_unref); G_OBJECT_CLASS (bz_curated_app_tile_parent_class)->dispose (object); } static void bz_curated_app_tile_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzCuratedAppTile *self = BZ_CURATED_APP_TILE (object); switch (prop_id) { case PROP_GROUP: g_value_set_object (value, bz_curated_app_tile_get_group (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_curated_app_tile_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzCuratedAppTile *self = BZ_CURATED_APP_TILE (object); switch (prop_id) { case PROP_GROUP: bz_curated_app_tile_set_group (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void clicked_cb (BzCuratedAppTile *self, BzAppTile *tile) { g_signal_emit (self, signals[SIGNAL_CLICKED], 0, NULL); } static void bz_curated_app_tile_class_init (BzCuratedAppTileClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bz_curated_app_tile_set_property; object_class->get_property = bz_curated_app_tile_get_property; object_class->dispose = bz_curated_app_tile_dispose; props[PROP_GROUP] = g_param_spec_object ( "group", NULL, NULL, BZ_TYPE_ENTRY_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); signals[SIGNAL_CLICKED] = g_signal_new ( "clicked", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 1, BZ_TYPE_ENTRY); g_signal_set_va_marshaller ( signals[SIGNAL_CLICKED], G_TYPE_FROM_CLASS (klass), g_cclosure_marshal_VOID__VOIDv); gtk_widget_class_set_css_name (widget_class, "app-tile"); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-curated-app-tile.ui"); gtk_widget_class_bind_template_callback (widget_class, clicked_cb); } static void bz_curated_app_tile_init (BzCuratedAppTile *self) { gtk_widget_init_template (GTK_WIDGET (self)); } BzCuratedAppTile * bz_curated_app_tile_new (void) { return g_object_new (BZ_TYPE_CURATED_APP_TILE, NULL); } BzEntryGroup * bz_curated_app_tile_get_group (BzCuratedAppTile *self) { g_return_val_if_fail (BZ_IS_CURATED_APP_TILE (self), NULL); return self->group; } void bz_curated_app_tile_set_group (BzCuratedAppTile *self, BzEntryGroup *group) { g_return_if_fail (BZ_IS_CURATED_APP_TILE (self)); g_clear_pointer (&self->group, g_object_unref); if (group != NULL) self->group = g_object_ref (group); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_GROUP]); } /* End of bz-curated-app-tile.c */ bazaar-orig-v0.7.14/src/bz-releases-list.blp0000664000175000017500000000112115166123241017606 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzReleasesList: Adw.Bin { visible: false; child: Box { orientation: vertical; spacing: 12; ListBox preview_box { styles [ "boxed-list", ] selection-mode: none; valign: start; } ListBox show_all_box { visible: false; styles [ "boxed-list", ] selection-mode: none; Adw.ButtonRow { title: _("_Version History"); use-underline: true; activated => $show_all_releases_cb(); end-icon-name: "go-next-symbolic"; } } }; } bazaar-orig-v0.7.14/src/bz-stats-dialog.h0000664000175000017500000000224515166123241017107 0ustar hasanhasan/* bz-stats-dialog.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_STATS_DIALOG (bz_stats_dialog_get_type ()) G_DECLARE_FINAL_TYPE (BzStatsDialog, bz_stats_dialog, BZ, STATS_DIALOG, AdwBreakpointBin) AdwBreakpointBin * bz_stats_dialog_new (GListModel *model, GListModel *country_model, int total_downloads); void bz_stats_dialog_animate_open (BzStatsDialog *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-error.c0000664000175000017500000000746315166123241015647 0ustar hasanhasan/* bz-error.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include #include "bz-error-dialog.h" #include "bz-error.h" #include "bz-window.h" static void show_alert (GtkWidget *widget, const char *title, const char *text); static void await_alert_response (AdwAlertDialog *alert, gchar *response, DexPromise *promise); static void unref_dex_closure (gpointer data, GClosure *closure); void bz_show_error_for_widget (GtkWidget *widget, const char *title, const char *text) { g_return_if_fail (GTK_IS_WIDGET (widget)); g_return_if_fail (text != NULL); show_alert (widget, title, text); } static void on_toast_button_clicked (AdwToast *toast, GtkWidget *widget) { BzErrorDialog *dialog; const char *title = NULL; const char *text = NULL; if (!GTK_IS_WIDGET (widget)) return; title = g_object_get_data (G_OBJECT (toast), "title"); text = g_object_get_data (G_OBJECT (toast), "text"); dialog = bz_error_dialog_new (title ? title : _ ("Details"), text ? text : ""); adw_dialog_present (ADW_DIALOG (dialog), widget); } static void show_alert (GtkWidget *widget, const char *title, const char *text) { BzWindow *window = NULL; AdwToast *toast = NULL; g_autofree char *toast_title = NULL; window = BZ_WINDOW (gtk_widget_get_ancestor (widget, BZ_TYPE_WINDOW)); if (window == NULL) return; toast_title = g_strdup_printf ("%s", title); toast = adw_toast_new (toast_title); adw_toast_set_button_label (toast, _ ("Details")); adw_toast_set_priority (toast, ADW_TOAST_PRIORITY_HIGH); adw_toast_set_timeout (toast, 5); g_object_set_data_full (G_OBJECT (toast), "title", g_strdup (title), g_free); g_object_set_data_full (G_OBJECT (toast), "text", g_strdup (text), g_free); g_signal_connect (toast, "button-clicked", G_CALLBACK (on_toast_button_clicked), widget); bz_window_add_toast (window, toast); } DexFuture * bz_make_alert_dialog_future (AdwAlertDialog *dialog) { g_autoptr (DexPromise) promise = NULL; dex_return_error_if_fail (ADW_IS_ALERT_DIALOG (dialog)); promise = dex_promise_new (); g_signal_connect_data ( dialog, "response", G_CALLBACK (await_alert_response), dex_ref (promise), unref_dex_closure, G_CONNECT_DEFAULT); return DEX_FUTURE (g_steal_pointer (&promise)); } static void await_alert_response (AdwAlertDialog *alert, gchar *response, DexPromise *promise) { dex_promise_resolve_string (promise, g_strdup (response)); } static void unref_dex_closure (gpointer data, GClosure *closure) { DexPromise *promise = data; if (dex_future_is_pending (DEX_FUTURE (promise))) dex_promise_reject ( promise, g_error_new ( DEX_ERROR, DEX_ERROR_UNKNOWN, "The signal was disconnected")); dex_unref (promise); } bazaar-orig-v0.7.14/src/bz-appstream-description-render.blp0000664000175000017500000000041115166123241022625 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzAppstreamDescriptionRender: Adw.Bin { child: Box { orientation: vertical; TextView text_view { editable: false; cursor-visible: false; wrap-mode: word_char; height-request: 25; } }; }bazaar-orig-v0.7.14/src/bz-hook.txt0000664000175000017500000000112015166123241016033 0ustar hasanhasanprefix=bz name=hook parent-prefix=g parent-name=object author=AUTOGEN include= include="bz-hook-dialog.h" ensure=BZ_TYPE_HOOK_DIALOG ensure=BZ_TYPE_HOOK_DIALOG_OPTION enum=bz hook_signal view_app before_transaction after_transaction enum=bz hook_return_status continue stop confirm deny enum=bz hook_transaction_type install update removal property=id char G_TYPE_STRING string property=when BzHookSignal BZ_TYPE_HOOK_SIGNAL enum property=dialogs GListModel G_TYPE_LIST_MODEL object property=shell char G_TYPE_STRING string property=check_appid_regex char G_TYPE_STRING string bazaar-orig-v0.7.14/src/bz-addons-dialog.h0000664000175000017500000000214115166123241017214 0ustar hasanhasan/* bz-addons-dialog.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-entry-group.h" G_BEGIN_DECLS #define BZ_TYPE_ADDONS_DIALOG (bz_addons_dialog_get_type ()) G_DECLARE_FINAL_TYPE (BzAddonsDialog, bz_addons_dialog, BZ, ADDONS_DIALOG, AdwDialog) AdwDialog * bz_addons_dialog_new (BzEntryGroup *group); AdwDialog * bz_addons_dialog_new_single (BzEntryGroup *group); G_END_DECLS bazaar-orig-v0.7.14/src/bz-hook-dialog-option.txt0000664000175000017500000000034315166123241020604 0ustar hasanhasanprefix=bz name=hook_dialog_option parent-prefix=g parent-name=object author=AUTOGEN include= property=id char G_TYPE_STRING string property=string char G_TYPE_STRING string property=style char G_TYPE_STRING string bazaar-orig-v0.7.14/src/main-config-schema.xml0000664000175000017500000000116615166123241020102 0ustar hasanhasan bazaar-orig-v0.7.14/src/bz-window.h0000664000175000017500000000332415166123241016022 0ustar hasanhasan/* bz-window.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-state-info.h" G_BEGIN_DECLS #define BZ_TYPE_WINDOW (bz_window_get_type ()) G_DECLARE_FINAL_TYPE (BzWindow, bz_window, BZ, WINDOW, AdwApplicationWindow) BzWindow * bz_window_new (BzStateInfo *state); void bz_window_search (BzWindow *self, const char *text); void bz_window_push_update_dialog (BzWindow *self); void bz_window_show_entry (BzWindow *self, BzEntry *entry); void bz_window_show_group (BzWindow *self, BzEntryGroup *group); void bz_window_show_app_id (BzWindow *self, const char *app_id); void bz_window_push_page (BzWindow *self, AdwNavigationPage *page); void bz_window_add_toast (BzWindow *self, AdwToast *toast); void bz_window_bulk_install (BzWindow *self, GListModel *groups); BzStateInfo * bz_window_get_state_info (BzWindow *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-addon-tile.c0000664000175000017500000001444015166123241016527 0ustar hasanhasan/* bz-addon-tile.c * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-addon-tile.h" #include "bz-entry-group.h" #include "bz-state-info.h" #include "bz-window.h" struct _BzAddonTile { BzListTile parent_instance; BzEntryGroup *group; GtkButton *install_remove_button; }; G_DEFINE_FINAL_TYPE (BzAddonTile, bz_addon_tile, BZ_TYPE_LIST_TILE) enum { PROP_0, PROP_GROUP, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void install_remove_cb (BzAddonTile *self, GtkButton *button) { int removable = 0; if (self->group == NULL) return; removable = bz_entry_group_get_removable (self->group); if (removable > 0) gtk_widget_activate_action (GTK_WIDGET (self), "window.remove-group", "(sb)", bz_entry_group_get_id (self->group), FALSE); else gtk_widget_activate_action (GTK_WIDGET (self), "window.install-group", "(sb)", bz_entry_group_get_id (self->group), TRUE); } static void bz_addon_tile_dispose (GObject *object) { BzAddonTile *self = BZ_ADDON_TILE (object); g_clear_object (&self->group); G_OBJECT_CLASS (bz_addon_tile_parent_class)->dispose (object); } static void bz_addon_tile_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzAddonTile *self = BZ_ADDON_TILE (object); switch (prop_id) { case PROP_GROUP: g_value_set_object (value, bz_addon_tile_get_group (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_addon_tile_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzAddonTile *self = BZ_ADDON_TILE (object); switch (prop_id) { case PROP_GROUP: bz_addon_tile_set_group (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static gboolean is_zero (gpointer object, int value) { return value == 0; } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static gboolean is_null (gpointer object, GObject *value) { return value == NULL; } static gboolean is_empty (gpointer object, const char *str) { return str == NULL || str[0] == '\0'; } static gboolean logical_and (gpointer object, gboolean value1, gboolean value2) { return value1 && value2; } static char * get_install_remove_tooltip (gpointer object, int removable) { if (removable > 0) return g_strdup (_ ("Uninstall")); else return g_strdup (_ ("Install")); } static char * get_install_remove_icon (gpointer object, int removable) { if (removable > 0) return g_strdup ("user-trash-symbolic"); else return g_strdup ("document-save-symbolic"); } static gboolean switch_bool (gpointer object, gboolean condition, gboolean true_value, gboolean false_value) { return condition ? true_value : false_value; } static void bz_addon_tile_class_init (BzAddonTileClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_addon_tile_dispose; object_class->get_property = bz_addon_tile_get_property; object_class->set_property = bz_addon_tile_set_property; props[PROP_GROUP] = g_param_spec_object ( "group", NULL, NULL, BZ_TYPE_ENTRY_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_LIST_TILE); g_type_ensure (BZ_TYPE_ENTRY_GROUP); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-addon-tile.ui"); gtk_widget_class_bind_template_child (widget_class, BzAddonTile, install_remove_button); gtk_widget_class_bind_template_callback (widget_class, is_zero); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, is_null); gtk_widget_class_bind_template_callback (widget_class, logical_and); gtk_widget_class_bind_template_callback (widget_class, is_empty); gtk_widget_class_bind_template_callback (widget_class, get_install_remove_tooltip); gtk_widget_class_bind_template_callback (widget_class, get_install_remove_icon); gtk_widget_class_bind_template_callback (widget_class, switch_bool); gtk_widget_class_bind_template_callback (widget_class, install_remove_cb); gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_BUTTON); } static void bz_addon_tile_init (BzAddonTile *self) { gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_addon_tile_new (void) { return g_object_new (BZ_TYPE_ADDON_TILE, NULL); } void bz_addon_tile_set_group (BzAddonTile *self, BzEntryGroup *group) { g_return_if_fail (BZ_IS_ADDON_TILE (self)); g_return_if_fail (group == NULL || BZ_IS_ENTRY_GROUP (group)); g_clear_object (&self->group); if (group != NULL) self->group = g_object_ref (group); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_GROUP]); } BzEntryGroup * bz_addon_tile_get_group (BzAddonTile *self) { g_return_val_if_fail (BZ_IS_ADDON_TILE (self), NULL); return self->group; } bazaar-orig-v0.7.14/src/bz-favorites-page.c0000664000175000017500000003106215166123241017422 0ustar hasanhasan/* bz-favorites-page.c * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include #include "bz-application-map-factory.h" #include "bz-env.h" #include "bz-error.h" #include "bz-favorites-page.h" #include "bz-favorites-tile.h" #include "bz-global-net.h" #include "bz-io.h" #include "bz-util.h" struct _BzFavoritesPage { AdwNavigationPage parent_instance; BzStateInfo *state; GListModel *model; GListModel *favorites; gboolean show_sidebar; AdwViewStack *stack; }; G_DEFINE_FINAL_TYPE (BzFavoritesPage, bz_favorites_page, ADW_TYPE_NAVIGATION_PAGE) enum { PROP_0, PROP_STATE, PROP_MODEL, PROP_FAVORITES, PROP_SHOW_SIDEBAR, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static DexFuture * fetch_favorites_fiber (GWeakRef *wr); static void favorites_changed (BzFavoritesPage *self, guint position, guint removed, guint added, GListModel *model); static void set_page (BzFavoritesPage *self); static void bz_favorites_page_dispose (GObject *object) { BzFavoritesPage *self = BZ_FAVORITES_PAGE (object); if (self->favorites != NULL) g_signal_handlers_disconnect_by_func (self->favorites, favorites_changed, self); g_clear_object (&self->favorites); g_clear_object (&self->model); g_clear_object (&self->state); G_OBJECT_CLASS (bz_favorites_page_parent_class)->dispose (object); } static void bz_favorites_page_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzFavoritesPage *self = BZ_FAVORITES_PAGE (object); switch (prop_id) { case PROP_STATE: g_value_set_object (value, self->state); break; case PROP_MODEL: g_value_set_object (value, self->model); break; case PROP_FAVORITES: g_value_set_object (value, self->favorites); break; case PROP_SHOW_SIDEBAR: g_value_set_boolean (value, self->show_sidebar); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_favorites_page_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzFavoritesPage *self = BZ_FAVORITES_PAGE (object); switch (prop_id) { case PROP_STATE: self->state = g_value_dup_object (value); break; case PROP_SHOW_SIDEBAR: self->show_sidebar = g_value_get_boolean (value); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SHOW_SIDEBAR]); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_favorites_page_constructed (GObject *object) { BzFavoritesPage *self = BZ_FAVORITES_PAGE (object); g_autoptr (DexFuture) future = NULL; G_OBJECT_CLASS (bz_favorites_page_parent_class)->constructed (object); future = dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) fetch_favorites_fiber, bz_track_weak (self), bz_weak_release); dex_future_disown (g_steal_pointer (&future)); } static gboolean is_zero (gpointer object, int value) { return value == 0; } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static gboolean is_empty (gpointer object, GListModel *model) { if (model == NULL) return TRUE; return g_list_model_get_n_items (model) == 0; } static gboolean is_favorited (GListModel *favorites, BzEntryGroup *group) { if (favorites == NULL || group == NULL) return FALSE; return g_list_store_find (G_LIST_STORE (favorites), group, NULL); } static void tile_activated_cb (BzFavoritesTile *tile) { BzEntryGroup *group = NULL; g_assert (BZ_IS_FAVORITES_TILE (tile)); group = bz_favorites_tile_get_group (tile); if (group == NULL) return; gtk_widget_activate_action (GTK_WIDGET (tile), "window.show-group", "s", bz_entry_group_get_id (group)); } static void unfavorite_cb (BzFavoritesTile *tile, BzEntryGroup *group, gpointer user_data) { BzFavoritesPage *self = NULL; guint position = 0; g_assert (BZ_IS_FAVORITES_TILE (tile)); g_assert (BZ_IS_ENTRY_GROUP (group)); self = BZ_FAVORITES_PAGE (gtk_widget_get_ancestor (GTK_WIDGET (tile), BZ_TYPE_FAVORITES_PAGE)); if (self == NULL) return; if (self->favorites == NULL) return; if (g_list_store_find (G_LIST_STORE (self->favorites), group, &position)) { g_list_store_remove (G_LIST_STORE (self->favorites), position); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_FAVORITES]); } } static void install_all_cb (BzFavoritesPage *self, GtkButton *button) { GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("as")); guint n_items = 0; g_return_if_fail (BZ_IS_FAVORITES_PAGE (self)); if (self->model == NULL || self->favorites == NULL) return; n_items = g_list_model_get_n_items (self->favorites); for (guint i = 0; i < n_items; i++) { g_autoptr (BzEntryGroup) group = NULL; group = g_list_model_get_item (self->favorites, i); if (!is_favorited (self->favorites, group)) continue; g_variant_builder_add (&builder, "s", bz_entry_group_get_id (group)); } gtk_widget_activate_action (GTK_WIDGET (self), "window.bulk-install", "as", &builder); } static void bz_favorites_page_class_init (BzFavoritesPageClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_favorites_page_dispose; object_class->constructed = bz_favorites_page_constructed; object_class->get_property = bz_favorites_page_get_property; object_class->set_property = bz_favorites_page_set_property; props[PROP_STATE] = g_param_spec_object ( "state", NULL, NULL, BZ_TYPE_STATE_INFO, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); props[PROP_MODEL] = g_param_spec_object ( "model", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_FAVORITES] = g_param_spec_object ( "favorites", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_SHOW_SIDEBAR] = g_param_spec_boolean ( "show-sidebar", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_FAVORITES_TILE); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-favorites-page.ui"); gtk_widget_class_bind_template_child (widget_class, BzFavoritesPage, stack); gtk_widget_class_bind_template_callback (widget_class, is_zero); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, is_empty); gtk_widget_class_bind_template_callback (widget_class, tile_activated_cb); gtk_widget_class_bind_template_callback (widget_class, unfavorite_cb); gtk_widget_class_bind_template_callback (widget_class, install_all_cb); } static void bz_favorites_page_init (BzFavoritesPage *self) { gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_favorites_page_new (BzStateInfo *state) { return g_object_new (BZ_TYPE_FAVORITES_PAGE, "state", state, NULL); } static void favorites_changed (BzFavoritesPage *self, guint position, guint removed, guint added, GListModel *model) { set_page (self); } static void set_page (BzFavoritesPage *self) { if (self->favorites != NULL && g_list_model_get_n_items (self->favorites) > 0) adw_view_stack_set_visible_child_name (self->stack, "content"); else adw_view_stack_set_visible_child_name (self->stack, "empty"); } static int compare_entry_groups_by_title (BzEntryGroup *group_a, BzEntryGroup *group_b) { const char *title_a = bz_entry_group_get_title (group_a); const char *title_b = bz_entry_group_get_title (group_b); return g_utf8_collate (title_a, title_b); } static DexFuture * fetch_favorites_fiber (GWeakRef *wr) { g_autoptr (BzFavoritesPage) self = NULL; g_autoptr (GError) local_error = NULL; g_autoptr (GtkStringList) id_list = NULL; g_autoptr (GListModel) model = NULL; g_autoptr (GListStore) sorted_store = NULL; g_autoptr (GListStore) favorites_store = NULL; g_autoptr (JsonNode) node = NULL; BzApplicationMapFactory *factory = NULL; BzAuthState *auth_state = NULL; const char *token = NULL; JsonArray *array = NULL; guint n_favorites = 0; guint n_items = 0; self = g_weak_ref_get (wr); if (self == NULL) return dex_future_new_reject (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Page destroyed"); id_list = gtk_string_list_new (NULL); auth_state = bz_state_info_get_auth_state (self->state); token = bz_auth_state_get_token (auth_state); if (token != NULL && bz_auth_state_is_authenticated (auth_state)) { node = dex_await_boxed ( bz_query_flathub_v2_json_authenticated ("/favorites", token), &local_error); if (node == NULL) { g_warning ("Failed to fetch favorites from Flathub: %s", local_error->message); goto done; } if (!JSON_NODE_HOLDS_ARRAY (node)) { g_warning ("Unexpected response format from Flathub favorites API"); goto done; } array = json_node_get_array (node); n_favorites = json_array_get_length (array); for (guint i = 0; i < n_favorites; i++) { JsonObject *favorite_obj = NULL; const char *app_id = NULL; favorite_obj = json_array_get_object_element (array, i); app_id = json_object_get_string_member (favorite_obj, "app_id"); if (app_id != NULL) gtk_string_list_append (id_list, app_id); } } done: factory = bz_state_info_get_application_factory (self->state); model = bz_application_map_factory_generate (factory, G_LIST_MODEL (id_list)); sorted_store = g_list_store_new (BZ_TYPE_ENTRY_GROUP); favorites_store = g_list_store_new (BZ_TYPE_ENTRY_GROUP); n_items = g_list_model_get_n_items (model); for (guint i = 0; i < n_items; i++) { g_autoptr (BzEntryGroup) group = g_list_model_get_item (model, i); g_list_store_append (sorted_store, group); g_list_store_append (favorites_store, group); } g_list_store_sort (sorted_store, (GCompareDataFunc) compare_entry_groups_by_title, NULL); g_clear_object (&self->model); self->model = G_LIST_MODEL (g_steal_pointer (&sorted_store)); if (self->favorites != NULL) g_signal_handlers_disconnect_by_func (self->favorites, favorites_changed, self); g_clear_object (&self->favorites); self->favorites = G_LIST_MODEL (g_steal_pointer (&favorites_store)); g_signal_connect_swapped (self->favorites, "items-changed", G_CALLBACK (favorites_changed), self); set_page (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MODEL]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_FAVORITES]); return dex_future_new_true (); } bazaar-orig-v0.7.14/src/bz-world-map-parser.h0000664000175000017500000000257515166123241017716 0ustar hasanhasan/* bz-world-map-parser.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_WORLD_MAP_PARSER (bz_world_map_parser_get_type ()) G_DECLARE_FINAL_TYPE (BzWorldMapParser, bz_world_map_parser, BZ, WORLD_MAP_PARSER, GObject) BzWorldMapParser *bz_world_map_parser_new (void); gboolean bz_world_map_parser_load_from_resource (BzWorldMapParser *self, const char *resource_path, GError **error); GListModel *bz_world_map_parser_get_countries (BzWorldMapParser *self); G_END_DECLS bazaar-orig-v0.7.14/src/shortcuts-dialog.blp0000664000175000017500000000206115166123241017720 0ustar hasanhasanusing Gtk 4.0; using Adw 1; Adw.ShortcutsDialog shortcuts_dialog { Adw.ShortcutsSection general_section { title: C_("shortcut window", "General"); Adw.ShortcutsItem { title: C_("shortcut window", "Open Search Page"); action-name: "app.search('')"; } Adw.ShortcutsItem { title: C_("shortcut window", "Open Library Page"); action-name: "window.open-library"; accelerator: "d"; } Adw.ShortcutsItem { title: C_("shortcut window", "Refresh"); action-name: "app.sync-remotes"; } Adw.ShortcutsItem { title: C_("shortcut window", "Open Preferences"); action-name: "app.preferences"; } Adw.ShortcutsItem { title: C_("shortcut window", "Show Shortcuts"); action-name: "app.shortcuts"; } Adw.ShortcutsItem { title: C_("shortcut window", "Close Window"); action-name: "window.quit"; accelerator: "w"; } Adw.ShortcutsItem { title: C_("shortcut window", "Quit Bazaar"); action-name: "app.quit"; } } } bazaar-orig-v0.7.14/src/bz-inspector.blp0000664000175000017500000001763415166123241017060 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzInspector: Adw.Window { title: "Bazaar Inspector"; default-width: 800; default-height: 1000; width-request: 300; height-request: 600; Adw.ToolbarView { top-bar-style: raised_border; bottom-bar-style: raised_border; reveal-bottom-bars: false; content: Box { orientation: vertical; width-request: 100; spacing: 10; Box { styles [ "bz-debug" ] orientation: vertical; Box { orientation: horizontal; spacing: 10; Label { styles [ "heading" ] label: "Background Task Info:"; xalign: 0.0; } Label { label: bind template.state as <$BzStateInfo>.background-task-label as ; xalign: 0.0; } } Box { orientation: horizontal; spacing: 10; Label { styles [ "heading" ] label: "Active Entry Objects in Memory:"; xalign: 0.0; } Label { label: bind $format_uint(template.state as <$BzStateInfo>.cache-manager as <$BzEntryCacheManager>.living-entries) as ; xalign: 0.0; } } } Box { orientation: vertical; spacing: 3; CheckButton debug_mode_check { label: "Enable Global Debug Mode"; } CheckButton disable_blocklists_check { label: "Disable All Blocklists"; } } Box { orientation: vertical; spacing: 3; Label { styles [ "heading" ] label: "Active Blocklists (YAML)"; xalign: 0.0; } ScrolledWindow { propagate-natural-height: true; child: ListView { model: NoSelection { model: bind template.state as <$BzStateInfo>.blocklists; }; factory: string_list_factory; }; } } Box { orientation: vertical; spacing: 3; Label { styles [ "heading" ] label: "Active Blocklists (TXT)"; xalign: 0.0; } ScrolledWindow { propagate-natural-height: true; child: ListView { model: NoSelection { model: bind template.state as <$BzStateInfo>.txt-blocklists; }; factory: string_list_factory; }; } } Box { orientation: vertical; spacing: 3; Label { styles [ "heading" ] label: "Active Curated-Configs"; xalign: 0.0; } ScrolledWindow { propagate-natural-height: true; child: ListView { model: NoSelection { model: bind template.state as <$BzStateInfo>.curated-configs; }; factory: string_list_factory; }; } } Box { orientation: vertical; spacing: 3; Box { orientation: horizontal; spacing: 10; Label { styles [ "heading" ] label: "Max Age Rating:"; xalign: 0.0; } Label { label: bind $format_int(template.state as <$BzStateInfo>.parental-age-rating) as ; xalign: 0.0; } } Label { styles [ "heading" ] label: "Restricted App IDs"; xalign: 0.0; } ScrolledWindow { propagate-natural-height: true; child: ListView { model: NoSelection { model: bind template.state as <$BzStateInfo>.parental-blocked-ids; }; factory: plain_string_list_factory; }; } } Label { styles [ "heading" ] margin-top: 10; label: "All Entry Groups"; xalign: 0.0; } Box { orientation: horizontal; spacing: 5; CheckButton { label: "Preview"; notify::active => $preview_changed(template); } Entry search_entry { hexpand: true; margin-start: 5; margin-end: 5; margin-top: 5; margin-bottom: 5; placeholder-text: "Filter..."; changed => $entry_changed(template); } } ScrolledWindow { vscrollbar-policy: always; propagate-natural-height: true; child: ListView { model: SingleSelection groups_selection { model: FilterListModel filter_model { model: bind template.state as <$BzStateInfo>.all-entry-groups; }; notify::selected-item => $selected_group_changed(template); }; factory: BuilderListItemFactory { template ListItem { activatable: false; child: Expander { label: bind template.item as <$BzEntryGroup>.id as ; child: Box { orientation: vertical; Separator {} ScrolledWindow { propagate-natural-height: true; child: ListView { model: NoSelection { model: bind template.item as <$BzEntryGroup>.model; }; factory: BuilderListItemFactory { template ListItem { activatable: false; child: Box { orientation: horizontal; Label { hexpand: true; ellipsize: end; xalign: 0.0; label: bind template.item as <$GtkStringObject>.string as ; } Button { label: "Decache and Inspect"; clicked => $decache_and_inspect_cb(template); } }; } }; }; } Separator {} }; }; } }; }; } }; [top] Adw.HeaderBar top_header_bar {} } } BuilderListItemFactory string_list_factory { template ListItem { selectable: false; activatable: false; child: Box { orientation: horizontal; spacing: 10; Label { styles [ "dimmed", "bz-monospace", ] width-request: 30; label: bind $format_uint(template.position) as ; xalign: 1.0; } Label { styles [ "bz-monospace", ] hexpand: true; margin-top: 2; margin-bottom: 2; xalign: 0.0; selectable: true; label: bind template.item as <$GtkStringObject>.string as ; } Button { label: "Open"; clicked => $open_file_externally_cb(template); } }; } } BuilderListItemFactory plain_string_list_factory { template ListItem { selectable: false; activatable: false; child: Box { orientation: horizontal; spacing: 10; Label { styles [ "dimmed", "bz-monospace", ] width-request: 30; label: bind $format_uint(template.position) as ; xalign: 1.0; } Label { styles [ "bz-monospace", ] hexpand: true; margin-top: 2; margin-bottom: 2; xalign: 0.0; selectable: true; label: bind template.item as <$GtkStringObject>.string as ; } }; } } bazaar-orig-v0.7.14/src/bz-license-dialog.h0000664000175000017500000000213015166123241017364 0ustar hasanhasan/* bz-license-dialog.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry.h" #include G_BEGIN_DECLS #define BZ_TYPE_LICENSE_DIALOG (bz_license_dialog_get_type ()) G_DECLARE_FINAL_TYPE (BzLicenseDialog, bz_license_dialog, BZ, LICENSE_DIALOG, AdwBin) AdwDialog * bz_license_dialog_new (BzEntry *entry); AdwNavigationPage * bz_license_page_new (BzEntry *entry); G_END_DECLS bazaar-orig-v0.7.14/src/bz-transaction-dialog.h0000664000175000017500000000254215166123241020276 0ustar hasanhasan/* bz-transaction-dialog.h * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-bulk-install-dialog-result.h" #include "bz-entry-group.h" #include "bz-transaction-dialog-result.h" G_BEGIN_DECLS DexFuture *bz_transaction_dialog_show (GtkWidget *parent, BzEntry *entry, BzEntryGroup *group, gboolean remove, gboolean auto_confirm); DexFuture *bz_bulk_install_dialog_show (GtkWidget *parent, GListModel *groups); G_END_DECLS bazaar-orig-v0.7.14/src/bz-progress-bar.blp0000664000175000017500000000013715166123241017446 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzProgressBar: Adw.Bin { child: ProgressBar bar {}; } bazaar-orig-v0.7.14/src/bz-newline-parser.c0000664000175000017500000001125015166123241017436 0ustar hasanhasan/* bz-newline-parser.c * * Copyright 2025 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::NEWLINE-TXT-PARSER" #include "config.h" #include "bz-hash-table-object.h" #include "bz-newline-parser.h" #include "bz-parser.h" struct _BzNewlineParser { GObject parent_instance; gboolean comments; guint max_lines; }; static void parser_iface_init (BzParserInterface *iface); G_DEFINE_FINAL_TYPE_WITH_CODE ( BzNewlineParser, bz_newline_parser, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (BZ_TYPE_PARSER, parser_iface_init)) static void destroy_gvalue (GValue *value); static void bz_newline_parser_dispose (GObject *object) { BzNewlineParser *self = BZ_NEWLINE_PARSER (object); (void) self; G_OBJECT_CLASS (bz_newline_parser_parent_class)->dispose (object); } static void bz_newline_parser_class_init (BzNewlineParserClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = bz_newline_parser_dispose; } static void bz_newline_parser_init (BzNewlineParser *self) { } static GHashTable * bz_newline_parser_real_process_bytes (BzParser *iface_self, GBytes *bytes, GError **error) { BzNewlineParser *self = BZ_NEWLINE_PARSER (iface_self); gsize size = 0; const guchar *data = NULL; g_autofree char *contents = NULL; g_autoptr (GHashTable) set = NULL; guint n_ids = 0; char *beg = NULL; char *end = NULL; g_autoptr (BzHashTableObject) obj = NULL; GValue *value = NULL; g_autoptr (GHashTable) ret = NULL; g_return_val_if_fail (BZ_IS_NEWLINE_PARSER (self), NULL); g_return_val_if_fail (bytes != NULL, NULL); data = g_bytes_get_data (bytes, &size); contents = g_memdup2 (data, size + 1); contents[size] = '\0'; set = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); for (beg = contents, end = g_utf8_strchr (beg, -1, '\n'); beg != NULL && *beg != '\0'; beg = end + 1, end = g_utf8_strchr (beg, -1, '\n')) { g_autofree char *line = NULL; if (end == NULL) g_warning ("Data has no terminating newline"); if ((self->comments && g_str_has_prefix (beg, "#")) || (end != NULL && end - beg <= 1) || (end == NULL && *beg == '\0')) { if (end != NULL) continue; else break; } if (end != NULL) line = g_strndup (beg, end - beg); else line = g_strdup (beg); if (g_hash_table_contains (set, line)) g_warning ("Duplicate line %s detected in data", line); else g_hash_table_replace (set, g_steal_pointer (&line), NULL); if (end == NULL) break; if (self->max_lines > 0 && ++n_ids > self->max_lines) { g_warning ("Data has a lot of lines, automatically " "truncating to %d", self->max_lines); break; } } obj = bz_hash_table_object_new (); bz_hash_table_object_set_hash_table (obj, set); value = g_new0 (typeof (*value), 1); g_value_init (value, G_TYPE_OBJECT); g_value_set_object (value, obj); ret = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) destroy_gvalue); g_hash_table_replace (ret, g_strdup ("/"), g_steal_pointer (&value)); return g_steal_pointer (&ret); } static void parser_iface_init (BzParserInterface *iface) { iface->process_bytes = bz_newline_parser_real_process_bytes; } BzNewlineParser * bz_newline_parser_new (gboolean comments, guint max_lines) { BzNewlineParser *parser = NULL; parser = g_object_new (BZ_TYPE_NEWLINE_PARSER, NULL); parser->comments = comments; parser->max_lines = max_lines; return parser; } static void destroy_gvalue (GValue *value) { g_value_unset (value); g_free (value); } bazaar-orig-v0.7.14/src/bz-transaction.c0000664000175000017500000006134515166123241017042 0ustar hasanhasan/* bz-transaction.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ /* TODO: This file probably needs to be rewritten */ #include "config.h" #include #include "bz-transaction.h" typedef struct { GListStore *installs; GListStore *updates; GListStore *removals; char *name; gboolean pending; GListStore *current_tasks; GListStore *finished_tasks; GListStore *trackers; char *status; double progress; gboolean finished; gboolean success; char *error; } BzTransactionPrivate; G_DEFINE_TYPE_WITH_PRIVATE (BzTransaction, bz_transaction, G_TYPE_OBJECT) enum { PROP_0, PROP_NAME, PROP_INSTALLS, PROP_UPDATES, PROP_REMOVALS, PROP_PENDING, PROP_CURRENT_OPS, PROP_FINISHED_OPS, PROP_TRACKERS, PROP_STATUS, PROP_PROGRESS, PROP_FINISHED, PROP_SUCCESS, PROP_ERROR, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void finish (BzTransactionPrivate *priv); static gboolean find_payload_eq_func (BzTransactionTask *task, gpointer none, BzBackendTransactionOpPayload *payload); static gboolean find_entry_eq_func (BzTransactionEntryTracker *tracker, gpointer none, BzEntry *entry); static gboolean find_and_maybe_transfer (GListStore *from, GListStore *to, gpointer lookup, GEqualFuncFull eql, gpointer *out); static void tracker_update (BzTransactionPrivate *priv, BzBackendTransactionOpPayload *payload, gboolean transfer); static void bz_transaction_dispose (GObject *object) { BzTransaction *self = BZ_TRANSACTION (object); BzTransactionPrivate *priv = bz_transaction_get_instance_private (self); g_clear_pointer (&priv->name, g_free); g_clear_object (&priv->installs); g_clear_object (&priv->updates); g_clear_object (&priv->removals); g_clear_object (&priv->current_tasks); g_clear_object (&priv->finished_tasks); g_clear_object (&priv->trackers); g_clear_pointer (&priv->status, g_free); g_clear_pointer (&priv->error, g_free); G_OBJECT_CLASS (bz_transaction_parent_class)->dispose (object); } static void bz_transaction_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzTransaction *self = BZ_TRANSACTION (object); BzTransactionPrivate *priv = bz_transaction_get_instance_private (self); switch (prop_id) { case PROP_NAME: g_value_set_string (value, priv->name); break; case PROP_INSTALLS: g_value_set_object (value, priv->installs); break; case PROP_UPDATES: g_value_set_object (value, priv->updates); break; case PROP_REMOVALS: g_value_set_object (value, priv->removals); break; case PROP_PENDING: g_value_set_boolean (value, priv->pending); break; case PROP_CURRENT_OPS: g_value_set_object (value, priv->current_tasks); break; case PROP_FINISHED_OPS: g_value_set_object (value, priv->finished_tasks); break; case PROP_TRACKERS: g_value_set_object (value, priv->trackers); break; case PROP_STATUS: g_value_set_string (value, priv->status); break; case PROP_PROGRESS: g_value_set_double (value, priv->progress); break; case PROP_FINISHED: g_value_set_boolean (value, priv->finished); break; case PROP_SUCCESS: g_value_set_boolean (value, priv->success); break; case PROP_ERROR: g_value_set_string (value, priv->error); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_transaction_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzTransaction *self = BZ_TRANSACTION (object); BzTransactionPrivate *priv = bz_transaction_get_instance_private (self); switch (prop_id) { case PROP_NAME: g_clear_pointer (&priv->name, g_free); priv->name = g_value_dup_string (value); break; case PROP_INSTALLS: g_clear_object (&priv->installs); priv->installs = g_value_dup_object (value); break; case PROP_UPDATES: g_clear_object (&priv->updates); priv->updates = g_value_dup_object (value); break; case PROP_REMOVALS: g_clear_object (&priv->removals); priv->removals = g_value_dup_object (value); break; case PROP_PENDING: priv->pending = g_value_get_boolean (value); break; case PROP_STATUS: g_clear_pointer (&priv->status, g_free); priv->status = g_value_dup_string (value); break; case PROP_PROGRESS: priv->progress = g_value_get_double (value); break; case PROP_FINISHED: priv->finished = g_value_get_boolean (value); if (priv->finished) finish (priv); break; case PROP_SUCCESS: priv->success = g_value_get_boolean (value); break; case PROP_ERROR: g_clear_pointer (&priv->error, g_free); priv->error = g_value_dup_string (value); break; case PROP_CURRENT_OPS: case PROP_FINISHED_OPS: case PROP_TRACKERS: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_transaction_class_init (BzTransactionClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bz_transaction_set_property; object_class->get_property = bz_transaction_get_property; object_class->dispose = bz_transaction_dispose; props[PROP_NAME] = g_param_spec_string ( "name", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_INSTALLS] = g_param_spec_object ( "installs", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_UPDATES] = g_param_spec_object ( "updates", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_REMOVALS] = g_param_spec_object ( "removals", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_PENDING] = g_param_spec_boolean ( "pending", NULL, NULL, TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_CURRENT_OPS] = g_param_spec_object ( "current-ops", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_FINISHED_OPS] = g_param_spec_object ( "finished-ops", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_TRACKERS] = g_param_spec_object ( "trackers", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); props[PROP_STATUS] = g_param_spec_string ( "status", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_PROGRESS] = g_param_spec_double ( "progress", NULL, NULL, 0.0, 1.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_FINISHED] = g_param_spec_boolean ( "finished", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_SUCCESS] = g_param_spec_boolean ( "success", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_ERROR] = g_param_spec_string ( "error", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_transaction_init (BzTransaction *self) { BzTransactionPrivate *priv = NULL; g_autoptr (GDateTime) now = NULL; priv = bz_transaction_get_instance_private (self); now = g_date_time_new_now_local (); priv->name = g_date_time_format (now, "%X"); priv->installs = g_list_store_new (BZ_TYPE_ENTRY); priv->updates = g_list_store_new (BZ_TYPE_ENTRY); priv->removals = g_list_store_new (BZ_TYPE_ENTRY); priv->pending = TRUE; priv->current_tasks = g_list_store_new (BZ_TYPE_TRANSACTION_TASK); priv->finished_tasks = g_list_store_new (BZ_TYPE_TRANSACTION_TASK); priv->trackers = g_list_store_new (BZ_TYPE_TRANSACTION_ENTRY_TRACKER); priv->status = g_strdup (_ ("Pending")); priv->success = TRUE; } BzTransaction * bz_transaction_new_full (BzEntry **installs, guint n_installs, BzEntry **updates, guint n_updates, BzEntry **removals, guint n_removals) { g_autoptr (BzTransaction) self = NULL; BzTransactionPrivate *priv = NULL; g_return_val_if_fail ((installs != NULL && n_installs > 0) || (updates != NULL && n_updates > 0) || (removals != NULL && n_removals > 0), NULL); for (guint i = 0; i < n_installs; i++) g_return_val_if_fail (BZ_IS_ENTRY (installs[i]), NULL); for (guint i = 0; i < n_updates; i++) g_return_val_if_fail (BZ_IS_ENTRY (updates[i]), NULL); for (guint i = 0; i < n_removals; i++) g_return_val_if_fail (BZ_IS_ENTRY (removals[i]), NULL); self = g_object_new (BZ_TYPE_TRANSACTION, NULL); priv = bz_transaction_get_instance_private (self); #define ADD_ENTRY(type, entry, transaction_type) \ G_STMT_START \ { \ g_autoptr (BzTransactionEntryTracker) tracker = NULL; \ g_autoptr (GListStore) current_ops = NULL; \ g_autoptr (GListStore) finished_ops = NULL; \ \ g_list_store_append (priv->type, (entry)); \ \ tracker = bz_transaction_entry_tracker_new (); \ current_ops = g_list_store_new (BZ_TYPE_TRANSACTION_TASK); \ finished_ops = g_list_store_new (BZ_TYPE_TRANSACTION_TASK); \ \ bz_transaction_entry_tracker_set_entry (tracker, (entry)); \ bz_transaction_entry_tracker_set_current_ops (tracker, G_LIST_MODEL (current_ops)); \ bz_transaction_entry_tracker_set_finished_ops (tracker, G_LIST_MODEL (finished_ops)); \ bz_transaction_entry_tracker_set_kind (tracker, transaction_type); \ bz_transaction_entry_tracker_set_status (tracker, BZ_TRANSACTION_ENTRY_STATUS_QUEUED); \ \ g_list_store_append (priv->trackers, tracker); \ } \ G_STMT_END for (guint i = 0; i < n_installs; i++) ADD_ENTRY (installs, installs[i], BZ_TRANSACTION_ENTRY_KIND_INSTALL); for (guint i = 0; i < n_updates; i++) ADD_ENTRY (updates, updates[i], BZ_TRANSACTION_ENTRY_KIND_UPDATE); for (guint i = 0; i < n_removals; i++) ADD_ENTRY (removals, removals[i], BZ_TRANSACTION_ENTRY_KIND_REMOVAL); #undef ADD_ENTRY return g_steal_pointer (&self); } BzTransaction * bz_transaction_new_merged (BzTransaction **transactions, guint n_transactions) { g_autoptr (GPtrArray) installs_pa = NULL; g_autoptr (GPtrArray) updates_pa = NULL; g_autoptr (GPtrArray) removals_pa = NULL; g_return_val_if_fail (transactions != NULL, NULL); g_return_val_if_fail (n_transactions >= 2, NULL); installs_pa = g_ptr_array_new_with_free_func (g_object_unref); updates_pa = g_ptr_array_new_with_free_func (g_object_unref); removals_pa = g_ptr_array_new_with_free_func (g_object_unref); for (guint i = 0; i < n_transactions; i++) { GListModel *installs = NULL; GListModel *updates = NULL; GListModel *removals = NULL; guint n_installs = 0; guint n_updates = 0; guint n_removals = 0; installs = bz_transaction_get_installs (transactions[i]); updates = bz_transaction_get_updates (transactions[i]); removals = bz_transaction_get_removals (transactions[i]); if (installs != NULL) n_installs = g_list_model_get_n_items (installs); if (updates != NULL) n_updates = g_list_model_get_n_items (updates); if (removals != NULL) n_removals = g_list_model_get_n_items (removals); for (guint j = 0; j < n_installs; j++) g_ptr_array_add (installs_pa, g_list_model_get_item (installs, j)); for (guint j = 0; j < n_updates; j++) g_ptr_array_add (updates_pa, g_list_model_get_item (updates, j)); for (guint j = 0; j < n_removals; j++) g_ptr_array_add (removals_pa, g_list_model_get_item (removals, j)); } return bz_transaction_new_full ( (BzEntry **) installs_pa->pdata, installs_pa->len, (BzEntry **) updates_pa->pdata, updates_pa->len, (BzEntry **) removals_pa->pdata, removals_pa->len); } GListModel * bz_transaction_get_installs (BzTransaction *self) { BzTransactionPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_TRANSACTION (self), NULL); priv = bz_transaction_get_instance_private (self); return G_LIST_MODEL (priv->installs); } GListModel * bz_transaction_get_updates (BzTransaction *self) { BzTransactionPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_TRANSACTION (self), NULL); priv = bz_transaction_get_instance_private (self); return G_LIST_MODEL (priv->updates); } GListModel * bz_transaction_get_removals (BzTransaction *self) { BzTransactionPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_TRANSACTION (self), NULL); priv = bz_transaction_get_instance_private (self); return G_LIST_MODEL (priv->removals); } GListModel * bz_transaction_get_trackers (BzTransaction *self) { BzTransactionPrivate *priv = NULL; g_return_val_if_fail (BZ_IS_TRANSACTION (self), NULL); priv = bz_transaction_get_instance_private (self); return G_LIST_MODEL (priv->trackers); } void bz_transaction_hold (BzTransaction *self) { BzTransactionPrivate *priv = NULL; g_return_if_fail (BZ_IS_TRANSACTION (self)); priv = bz_transaction_get_instance_private (self); #define HOLD_MODEL(_model) \ if ((_model) != NULL) \ { \ guint n_items = 0; \ \ n_items = g_list_model_get_n_items (G_LIST_MODEL ((_model))); \ for (guint i = 0; i < n_items; i++) \ { \ g_autoptr (BzEntry) entry = NULL; \ \ entry = g_list_model_get_item (G_LIST_MODEL ((_model)), i); \ bz_entry_hold (entry); \ } \ } HOLD_MODEL (priv->installs); HOLD_MODEL (priv->updates); HOLD_MODEL (priv->removals); #undef HOLD_MODEL } void bz_transaction_release (BzTransaction *self) { BzTransactionPrivate *priv = NULL; g_return_if_fail (BZ_IS_TRANSACTION (self)); priv = bz_transaction_get_instance_private (self); #define RELEASE_MODEL(_model) \ if ((_model) != NULL) \ { \ guint n_items = 0; \ \ n_items = g_list_model_get_n_items (G_LIST_MODEL ((_model))); \ for (guint i = 0; i < n_items; i++) \ { \ g_autoptr (BzEntry) entry = NULL; \ \ entry = g_list_model_get_item (G_LIST_MODEL ((_model)), i); \ bz_entry_release (entry); \ } \ } RELEASE_MODEL (priv->installs); RELEASE_MODEL (priv->updates); RELEASE_MODEL (priv->removals); #undef RELEASE_MODEL } void bz_transaction_add_task (BzTransaction *self, BzBackendTransactionOpPayload *payload) { BzTransactionPrivate *priv = NULL; g_autoptr (BzTransactionTask) task = NULL; BzEntry *entry = NULL; g_autoptr (BzTransactionEntryTracker) tracker = NULL; gboolean result = FALSE; g_return_if_fail (BZ_IS_TRANSACTION (self)); g_return_if_fail (BZ_IS_BACKEND_TRANSACTION_OP_PAYLOAD (payload)); priv = bz_transaction_get_instance_private (self); task = bz_transaction_task_new (); bz_transaction_task_set_op (task, payload); g_list_store_append (priv->current_tasks, task); entry = bz_backend_transaction_op_payload_get_entry (payload); result = find_and_maybe_transfer ( priv->trackers, NULL, entry, (GEqualFuncFull) find_entry_eq_func, (gpointer *) &tracker); if (result) { GListModel *current_ops = NULL; if (bz_transaction_entry_tracker_get_kind (tracker) == BZ_TRANSACTION_ENTRY_KIND_UPDATE) bz_backend_transaction_op_payload_set_download_size (payload, (guint64) -1); current_ops = bz_transaction_entry_tracker_get_current_ops (tracker); g_list_store_append (G_LIST_STORE (current_ops), task); g_object_notify (G_OBJECT (tracker), "current-ops"); } } void bz_transaction_update_task (BzTransaction *self, BzBackendTransactionOpProgressPayload *payload) { BzTransactionPrivate *priv = NULL; BzBackendTransactionOpPayload *op = NULL; g_autoptr (BzTransactionTask) task = NULL; gboolean result = FALSE; g_return_if_fail (BZ_IS_TRANSACTION (self)); g_return_if_fail (BZ_IS_BACKEND_TRANSACTION_OP_PROGRESS_PAYLOAD (payload)); priv = bz_transaction_get_instance_private (self); op = bz_backend_transaction_op_progress_payload_get_op (payload); result = find_and_maybe_transfer ( priv->current_tasks, NULL, op, (GEqualFuncFull) find_payload_eq_func, (gpointer *) &task); if (result) bz_transaction_task_set_last_progress (task, payload); tracker_update (priv, op, FALSE); } void bz_transaction_finish_task (BzTransaction *self, BzBackendTransactionOpPayload *payload) { BzTransactionPrivate *priv = NULL; g_return_if_fail (BZ_IS_TRANSACTION (self)); g_return_if_fail (BZ_IS_BACKEND_TRANSACTION_OP_PAYLOAD (payload)); priv = bz_transaction_get_instance_private (self); find_and_maybe_transfer ( priv->current_tasks, priv->finished_tasks, payload, (GEqualFuncFull) find_payload_eq_func, NULL); tracker_update (priv, payload, TRUE); } void bz_transaction_error_out_task (BzTransaction *self, BzBackendTransactionOpPayload *payload, const char *message) { BzTransactionPrivate *priv = NULL; gboolean result = FALSE; g_autoptr (BzTransactionTask) task = NULL; g_return_if_fail (BZ_IS_TRANSACTION (self)); g_return_if_fail (BZ_IS_BACKEND_TRANSACTION_OP_PAYLOAD (payload)); g_return_if_fail (message != NULL); priv = bz_transaction_get_instance_private (self); result = find_and_maybe_transfer ( priv->current_tasks, priv->finished_tasks, payload, (GEqualFuncFull) find_payload_eq_func, (gpointer *) &task); if (result) bz_transaction_task_set_error (task, message); tracker_update (priv, payload, TRUE); } static void finish (BzTransactionPrivate *priv) { guint n_trackers = 0; n_trackers = g_list_model_get_n_items (G_LIST_MODEL (priv->trackers)); for (guint i = 0; i < n_trackers; i++) { g_autoptr (BzTransactionEntryTracker) tracker = NULL; tracker = g_list_model_get_item (G_LIST_MODEL (priv->trackers), i); bz_transaction_entry_tracker_set_status (tracker, BZ_TRANSACTION_ENTRY_STATUS_DONE); } } static gboolean find_payload_eq_func (BzTransactionTask *task, gpointer none, BzBackendTransactionOpPayload *payload) { return bz_transaction_task_get_op (task) == payload; } static gboolean find_entry_eq_func (BzTransactionEntryTracker *tracker, gpointer none, BzEntry *entry) { return bz_transaction_entry_tracker_get_entry (tracker) == entry; } /* This kinda sucks */ static gboolean find_and_maybe_transfer (GListStore *from, GListStore *to, gpointer lookup, GEqualFuncFull eql, gpointer *out) { guint op_pos = 0; gboolean found = FALSE; g_autoptr (GObject) object = NULL; found = g_list_store_find_with_equal_func_full (from, NULL, eql, lookup, &op_pos); if (!found) return FALSE; object = g_list_model_get_item (G_LIST_MODEL (from), op_pos); if (to != NULL) { /* transfer if `to` is provided */ g_list_store_remove (from, op_pos); g_list_store_append (to, object); } if (out != NULL) *out = g_steal_pointer (&object); return TRUE; } static void tracker_update (BzTransactionPrivate *priv, BzBackendTransactionOpPayload *payload, gboolean transfer) { BzEntry *entry = NULL; g_autoptr (BzTransactionEntryTracker) tracker = NULL; gboolean result = FALSE; entry = bz_backend_transaction_op_payload_get_entry (payload); result = find_and_maybe_transfer ( priv->trackers, NULL, entry, (GEqualFuncFull) find_entry_eq_func, (gpointer *) &tracker); if (result) { if (transfer) { GListModel *from = NULL; GListModel *to = NULL; bz_transaction_entry_tracker_set_status (tracker, BZ_TRANSACTION_ENTRY_STATUS_DONE); from = bz_transaction_entry_tracker_get_current_ops (tracker); to = bz_transaction_entry_tracker_get_finished_ops (tracker); result = find_and_maybe_transfer ( G_LIST_STORE (from), G_LIST_STORE (to), payload, (GEqualFuncFull) find_payload_eq_func, NULL); g_object_notify (G_OBJECT (tracker), "current-ops"); g_object_notify (G_OBJECT (tracker), "finished-ops"); } else bz_transaction_entry_tracker_set_status (tracker, BZ_TRANSACTION_ENTRY_STATUS_ONGOING); } } bazaar-orig-v0.7.14/src/bz-search-bias.txt0000664000175000017500000000072215166123241017263 0ustar hasanhasanprefix=bz name=search_bias parent-prefix=g parent-name=object author=AUTOGEN include= include="bz-linear-function.h" include="bz-exponential-function.h" property=regex char G_TYPE_STRING string property=convert_to char G_TYPE_STRING string property=linear_boost BzLinearFunction BZ_TYPE_LINEAR_FUNCTION object property=exponential_boost BzExponentialFunction BZ_TYPE_EXPONENTIAL_FUNCTION object property=boost_appids GListModel G_TYPE_LIST_MODEL object bazaar-orig-v0.7.14/src/bz-entry-cache-manager.h0000664000175000017500000000365015166123241020327 0ustar hasanhasan/* bz-entry-cache-manager.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-entry.h" G_BEGIN_DECLS #define BZ_ENTRY_CACHE_ERROR (bz_entry_cache_error_quark ()) GQuark bz_entry_cache_error_quark (void); typedef enum { BZ_ENTRY_CACHE_ERROR_CACHE_FAILED = 0, BZ_ENTRY_CACHE_ERROR_DECACHE_FAILED, BZ_ENTRY_CACHE_ERROR_ENUMERATE_FAILED, } BzEntry_CacheError; #define BZ_TYPE_ENTRY_CACHE_MANAGER (bz_entry_cache_manager_get_type ()) G_DECLARE_FINAL_TYPE (BzEntryCacheManager, bz_entry_cache_manager, BZ, ENTRY_CACHE_MANAGER, GObject) BzEntryCacheManager * bz_entry_cache_manager_new (void); guint bz_entry_cache_manager_get_living_entries (BzEntryCacheManager *self); DexFuture * bz_entry_cache_manager_add (BzEntryCacheManager *self, BzEntry *entry); DexFuture * bz_entry_cache_manager_get (BzEntryCacheManager *self, const char *unique_id); DexFuture * bz_entry_cache_manager_get_by_checksum (BzEntryCacheManager *self, const char *unique_id_checksum); DexFuture * bz_entry_cache_manager_enumerate_disk (BzEntryCacheManager *self); G_END_DECLS /* End of bz-entry-cache-manager.h */ bazaar-orig-v0.7.14/src/bz-error-dialog.c0000664000175000017500000000601615166123241017075 0ustar hasanhasan/* bz-error-dialog.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include #include "bz-error-dialog.h" struct _BzErrorDialog { AdwDialog parent_instance; AdwToastOverlay *toast_overlay; GtkLabel *error_title; GtkTextView *text_view; }; G_DEFINE_FINAL_TYPE (BzErrorDialog, bz_error_dialog, ADW_TYPE_DIALOG) static void on_copy_button_clicked (GtkButton *button, BzErrorDialog *self) { GtkTextBuffer *buffer = NULL; GtkTextIter start = { 0 }; GtkTextIter end = { 0 }; g_autofree char *text = NULL; GdkClipboard *clipboard = NULL; g_autoptr (AdwToast) toast = NULL; buffer = gtk_text_view_get_buffer (self->text_view); gtk_text_buffer_get_bounds (buffer, &start, &end); text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); clipboard = gdk_display_get_clipboard (gdk_display_get_default ()); gdk_clipboard_set_text (clipboard, text); toast = adw_toast_new (_ ("Copied!")); adw_toast_set_timeout (toast, 2); adw_toast_overlay_add_toast (self->toast_overlay, g_steal_pointer (&toast)); } static void bz_error_dialog_class_init (BzErrorDialogClass *klass) { GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-error-dialog.ui"); gtk_widget_class_bind_template_child (widget_class, BzErrorDialog, toast_overlay); gtk_widget_class_bind_template_child (widget_class, BzErrorDialog, error_title); gtk_widget_class_bind_template_child (widget_class, BzErrorDialog, text_view); gtk_widget_class_bind_template_callback (widget_class, on_copy_button_clicked); } static void bz_error_dialog_init (BzErrorDialog *self) { gtk_widget_init_template (GTK_WIDGET (self)); } BzErrorDialog * bz_error_dialog_new (const char *title, const char *text) { BzErrorDialog *self; GtkTextBuffer *buffer; GtkTextIter iter; g_return_val_if_fail (title != NULL, NULL); g_return_val_if_fail (text != NULL, NULL); self = g_object_new (BZ_TYPE_ERROR_DIALOG, NULL); gtk_label_set_text (self->error_title, title); buffer = gtk_text_view_get_buffer (self->text_view); gtk_text_buffer_get_start_iter (buffer, &iter); gtk_text_buffer_insert (buffer, &iter, text, -1); return self; } bazaar-orig-v0.7.14/src/bz-flatpak-entry.h0000664000175000017500000000404615166123241017276 0ustar hasanhasan/* bz-flatpak-entry.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry.h" #include "bz-flatpak-instance.h" #include "bz-result.h" G_BEGIN_DECLS #define BZ_TYPE_FLATPAK_ENTRY (bz_flatpak_entry_get_type ()) G_DECLARE_FINAL_TYPE (BzFlatpakEntry, bz_flatpak_entry, BZ, FLATPAK_ENTRY, BzEntry) char * bz_flatpak_id_format_unique (const char *flatpak_id, gboolean user); gboolean bz_flatpak_entry_is_user (BzFlatpakEntry *self); const char * bz_flatpak_entry_get_flatpak_name (BzFlatpakEntry *self); const char * bz_flatpak_entry_get_flatpak_id (BzFlatpakEntry *self); const char * bz_flatpak_entry_get_flatpak_version (BzFlatpakEntry *self); const char * bz_flatpak_entry_get_application_name (BzFlatpakEntry *self); const char * bz_flatpak_entry_get_application_runtime (BzFlatpakEntry *self); const char * bz_flatpak_entry_get_runtime_name (BzFlatpakEntry *self); BzResult * bz_flatpak_entry_dup_runtime_result (BzFlatpakEntry *self); gboolean bz_flatpak_entry_is_bundle (BzFlatpakEntry *self); gboolean bz_flatpak_entry_is_installed_ref (BzFlatpakEntry *self); const char * bz_flatpak_entry_get_addon_extension_of_ref (BzFlatpakEntry *self); gboolean bz_flatpak_entry_launch (BzFlatpakEntry *self, BzFlatpakInstance *flatpak, GError **error); G_END_DECLS bazaar-orig-v0.7.14/src/bz-pride-flag-stripe-spec.txt0000664000175000017500000000030015166123241021340 0ustar hasanhasanprefix=bz name=pride_flag_stripe_spec parent-prefix=g parent-name=object author=AUTOGEN include= property=rgba char G_TYPE_STRING string property=size double G_TYPE_DOUBLE double bazaar-orig-v0.7.14/src/bz-zoom.h0000664000175000017500000000326315166123241015501 0ustar hasanhasan/* bz-zoom.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_ZOOM (bz_zoom_get_type ()) G_DECLARE_FINAL_TYPE (BzZoom, bz_zoom, BZ, ZOOM, GtkWidget) GtkWidget *bz_zoom_new (void); GtkWidget *bz_zoom_get_child (BzZoom *self); void bz_zoom_set_child (BzZoom *self, GtkWidget *child); double bz_zoom_get_zoom_level (BzZoom *self); void bz_zoom_set_zoom_level (BzZoom *self, double zoom_level); double bz_zoom_get_min_zoom (BzZoom *self); void bz_zoom_set_min_zoom (BzZoom *self, double min_zoom); double bz_zoom_get_max_zoom (BzZoom *self); void bz_zoom_set_max_zoom (BzZoom *self, double max_zoom); gboolean bz_zoom_is_transformed (BzZoom *self); void bz_zoom_zoom_in (BzZoom *self); void bz_zoom_zoom_out (BzZoom *self); void bz_zoom_reset (BzZoom *self); void bz_zoom_fit_to_window (BzZoom *self); G_END_DECLS bazaar-orig-v0.7.14/src/progress-bar-designs/0000775000175000017500000000000015166123241017767 5ustar hasanhasanbazaar-orig-v0.7.14/src/progress-bar-designs/meson.build0000664000175000017500000000002015166123241022121 0ustar hasanhasansubdir('pride') bazaar-orig-v0.7.14/src/progress-bar-designs/common.h0000664000175000017500000000144215166123241021431 0ustar hasanhasan/* progress-bar-designs/common.h * * Copyright 2025 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "pride/pride.h" bazaar-orig-v0.7.14/src/progress-bar-designs/pride/0000775000175000017500000000000015166123241021072 5ustar hasanhasanbazaar-orig-v0.7.14/src/progress-bar-designs/pride/meson.build0000664000175000017500000000004415166123241023232 0ustar hasanhasanbz_sources += files( 'pride.c', ) bazaar-orig-v0.7.14/src/progress-bar-designs/pride/pride.c0000664000175000017500000001777315166123241022360 0ustar hasanhasan/* progress-bar-designs/pride/pride.c * * Copyright 2025 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include "bz-parser.h" #include "bz-pride-flag-config.h" #include "bz-yaml-parser.h" #include "pride.h" static void generate_flag_css (GString *css, const char *id, const char *direction, gboolean homogeneous, GListModel *stripes); GtkStyleProvider * bz_get_pride_style_provider (void) { static GtkCssProvider *provider = NULL; if (g_once_init_enter_pointer (&provider)) { g_autoptr (GError) local_error = NULL; g_autoptr (GBytes) config_bytes = NULL; g_autoptr (BzYamlParser) parser = NULL; g_autoptr (GHashTable) parse_results = NULL; g_autoptr (BzPrideFlagConfig) config = NULL; g_autoptr (GtkCssProvider) tmp = NULL; config_bytes = g_resources_lookup_data ( "/io/github/kolunmi/Bazaar/pride-flags.yaml", G_RESOURCE_LOOKUP_FLAGS_NONE, NULL); g_assert (config_bytes != NULL); g_type_ensure (BZ_TYPE_PRIDE_FLAG_CONFIG); g_type_ensure (BZ_TYPE_PRIDE_FLAG_SPEC); g_type_ensure (BZ_TYPE_PRIDE_FLAG_STRIPE_SPEC); parser = bz_yaml_parser_new_for_resource_schema ( "/io/github/kolunmi/Bazaar/pride-flag-config-schema.xml"); parse_results = bz_parser_process_bytes ( BZ_PARSER (parser), config_bytes, &local_error); if (parse_results == NULL) g_critical ("Could not parse internal 'pride-flags.yaml': %s", local_error->message); g_assert (parse_results != NULL); config = g_value_dup_object (g_hash_table_lookup (parse_results, "/")); tmp = gtk_css_provider_new (); if (config != NULL) { GListModel *flag_specs = NULL; flag_specs = bz_pride_flag_config_get_flag_specs (config); if (flag_specs != NULL) { g_autoptr (GString) css = NULL; guint n_flag_specs = 0; css = g_string_new (NULL); n_flag_specs = g_list_model_get_n_items (flag_specs); for (guint i = 0; i < n_flag_specs; i++) { g_autoptr (BzPrideFlagSpec) flag_spec = NULL; const char *id = NULL; const char *name = NULL; gboolean homogeneous = FALSE; GListModel *stripes = NULL; const char *direction = NULL; flag_spec = g_list_model_get_item (flag_specs, i); id = bz_pride_flag_spec_get_id (flag_spec); name = bz_pride_flag_spec_get_name (flag_spec); homogeneous = bz_pride_flag_spec_get_homogeneous (flag_spec); stripes = bz_pride_flag_spec_get_stripes (flag_spec); direction = bz_pride_flag_spec_get_direction (flag_spec); if (id == NULL) { g_critical ("Flag spec with index %d lacks an id, skipping it", i); continue; } if (name == NULL) { g_critical ("Flag spec \"%s\" lacks an name, skipping it", id); continue; } if (stripes == NULL) { g_critical ("Flag spec \"%s\" lacks a strip list, skipping it", id); continue; } if (direction == NULL) direction = "to bottom"; generate_flag_css (css, id, direction, homogeneous, stripes); { g_autofree char *horizontal_id = NULL; const char *horizontal_direction = NULL; horizontal_id = g_strdup_printf ("%s-horizontal", id); if (g_strcmp0 (direction, "to bottom") == 0) horizontal_direction = "to right"; else if (g_strcmp0 (direction, "to top") == 0) horizontal_direction = "to left"; else if (g_strcmp0 (direction, "to left") == 0) horizontal_direction = "to top"; else if (g_strcmp0 (direction, "to right") == 0) horizontal_direction = "to bottom"; else horizontal_direction = "to right"; generate_flag_css (css, horizontal_id, horizontal_direction, homogeneous, stripes); } } if (css->len > 0) gtk_css_provider_load_from_string (tmp, css->str); } } g_once_init_leave_pointer (&provider, g_steal_pointer (&tmp)); } return GTK_STYLE_PROVIDER (provider); } char * bz_dup_css_class_for_pride_id (const char *id) { g_return_val_if_fail (id != NULL, NULL); return g_strdup_printf ("%s-theme", id); } static void generate_flag_css (GString *css, const char *id, const char *direction, gboolean homogeneous, GListModel *stripes) { g_autoptr (GString) stripe_css = NULL; guint n_stripes = 0; double cur_offset = 0.0; gboolean skip = FALSE; stripe_css = g_string_new (NULL); g_string_append_printf (stripe_css, ".%s-theme { ", id); g_string_append_printf (stripe_css, "--flag-gradient: linear-gradient(%s", direction); n_stripes = g_list_model_get_n_items (stripes); for (guint j = 0; j < n_stripes; j++) { g_autoptr (BzPrideFlagStripeSpec) stripe_spec = NULL; const char *rgba_spec = NULL; double size = 0.0; GdkRGBA rgba = { 0 }; stripe_spec = g_list_model_get_item (stripes, j); rgba_spec = bz_pride_flag_stripe_spec_get_rgba (stripe_spec); size = bz_pride_flag_stripe_spec_get_size (stripe_spec); if (rgba_spec == NULL) { g_critical ("Flag spec \"%s\" has a stripe spec which lacks an rgba spec, skipping it", id); skip = TRUE; break; } if (!gdk_rgba_parse (&rgba, rgba_spec)) { g_critical ("Flag spec \"%s\" has a stripe spec which has an invalid rgba spec, skipping it", id); skip = TRUE; break; } if (!homogeneous && (size <= 0.0 || size > 1.0)) { g_critical ("Flag spec \"%s\" has a stripe spec which has an out of bounds size, skipping it", id); skip = TRUE; break; } g_string_append_printf (stripe_css, ", %s %d%%", rgba_spec, (int) round (cur_offset * 100.0)); cur_offset += homogeneous ? 1.0 / (double) n_stripes : size; if (cur_offset > 1.0) { g_critical ("Flag spec \"%s\" has a stripe spec which exceeds the height of the flag, skipping it", id); skip = TRUE; break; } g_string_append_printf (stripe_css, ", %s %d%%", rgba_spec, (int) round (cur_offset * 100.0)); } if (skip) return; g_string_append (stripe_css, "); }\n"); g_string_append_len (css, stripe_css->str, stripe_css->len); } bazaar-orig-v0.7.14/src/progress-bar-designs/pride/pride-flags.yaml0000664000175000017500000001621515166123241024160 0ustar hasanhasanflag-specs: - # the internal ID of the flag; this should match the gsettings file at # /data/io.github.kolunmi.Bazaar.gschema.xml id: "pride-rainbow-flag" # the user-facing name name: "Pride Rainbow Flag" # (optional) set to true if the flag is homogeneous, or put more # shrimply(🦐) each stripe has the same vertical size homogeneous: true # the direction in which the stripes are drawn (css format) direction: to bottom # list of stripe specs stripes: &pride-rainbow-flag-stripes - # all stripes must provide the `rgba` field, which will is the color of # the stripe. Many formats are supported for this; here is a snippet # from the GDK source, listing the formats: # # - A standard name (Taken from the CSS specification). # - A hexadecimal value in the form “#rgb”, “#rrggbb”, # “#rrrgggbbb” or ”#rrrrggggbbbb” # - A hexadecimal value in the form “#rgba”, “#rrggbbaa”, # or ”#rrrrggggbbbbaaaa” # - A RGB color in the form “rgb(r,g,b)” (In this case the color # will have full opacity) # - A RGBA color in the form “rgba(r,g,b,a)” # - A HSL color in the form "hsl(hue, saturation, lightness)" # - A HSLA color in the form "hsla(hue, saturation, lightness, alpha)" # # for more information, see # https://docs.gtk.org/gdk4/method.RGBA.parse.html rgba: "#E40303" # if the above `homogeneous` field is set to `true`, then this field can # be omitted. otherwise, this value is a floating point number from 0.0 # to 1.0 representing the size of this stripe as a percentage of the # flag's pixel height in the UI. so if this strip should take up 20% of # the vertical space, put `0.2`, as shown here. Since the `homogeneous` # field was set to `true` on this flag, this is ignored size: 0.2 - rgba: "#FF8C00" - rgba: "#FFED00" - rgba: "#008026" - rgba: "#24408E" - rgba: "#732982" - id: "lesbian-pride-flag" name: "Lesbian Pride Flag" homogeneous: true direction: to bottom stripes: &lesbian-flag-stripes - rgba: "#D62800" - rgba: "#EF7627" - rgba: "#FF9B56" - rgba: "#FFFFFF" - rgba: "#D162A4" - rgba: "#B55690" - rgba: "#A30262" - id: "gay-pride-flag" name: "Gay Pride Flag" homogeneous: true direction: to bottom stripes: &gay-pride-flag-stripes - rgba: "#018E71" - rgba: "#21CFAC" - rgba: "#9AE9C3" - rgba: "#FFFFFF" - rgba: "#7CAFE4" - rgba: "#4F47CC" - rgba: "#3C1379" - id: "transgender-flag" name: "Transgender Flag" homogeneous: true direction: to bottom stripes: &transgender-flag-stripes - rgba: "#5BCEFA" - rgba: "#F5A9B8" - rgba: "#FFFFFF" - rgba: "#F5A9B8" - rgba: "#5BCEFA" - id: "nonbinary-flag" name: "Nonbinary Flag" homogeneous: true direction: to bottom stripes: &nonbinary-flag-stripes - rgba: "#FCF434" - rgba: "#FFFFFF" - rgba: "#9C59D1" - rgba: "#2C2C2C" - id: "bisexual-flag" name: "Bisexual Flag" direction: to bottom stripes: &bisexual-flag-stripes - rgba: "#D60270" size: 0.4 - rgba: "#9B4F96" size: 0.2 - rgba: "#0038A8" size: 0.4 - id: "asexual-flag" name: "Asexual Flag" homogeneous: true direction: to bottom stripes: &asexual-flag-stripes - rgba: "#000000" - rgba: "#A3A3A3" - rgba: "#FFFFFF" - rgba: "#810081" - id: "pansexual-flag" name: "Pansexual Flag" homogeneous: true direction: to bottom stripes: &pansexual-flag-stripes - rgba: "#FF218C" - rgba: "#FFD800" - rgba: "#21B1FF" - id: "aromantic-flag" name: "Aromantic Flag" homogeneous: true direction: to bottom stripes: &aromantic-flag-stripes - rgba: "#3DA542" - rgba: "#A7D379" - rgba: "#FFFFFF" - rgba: "#A9A9A9" - rgba: "#000000" - id: "genderfluid-flag" name: "Genderfluid Flag" homogeneous: true direction: to bottom stripes: &genderfluid-flag-stripes - rgba: "#FF76A4" - rgba: "#FFFFFF" - rgba: "#C011D7" - rgba: "#000000" - rgba: "#2F3CBE" - id: "polysexual-flag" name: "Polysexual Flag" homogeneous: true direction: to bottom stripes: &polysexual-flag-stripes - rgba: "#F61CB9" - rgba: "#07D569" - rgba: "#1C92F6" - id: "omnisexual-flag" name: "Omnisexual Flag" homogeneous: true direction: to bottom stripes: &omnisexual-flag-stripes - rgba: "#FF9CCE" - rgba: "#FF52BF" - rgba: "#200044" - rgba: "#675FFF" - rgba: "#8DA7FF" - id: "aroace-flag" name: "Aroace Flag" homogeneous: true direction: to bottom stripes: &aroace-flag-stripes - rgba: "#E28C00" - rgba: "#ECCD00" - rgba: "#FFFFFF" - rgba: "#62AEDC" - rgba: "#203856" - id: "agender-flag" name: "Agender Flag" homogeneous: true direction: to bottom stripes: &agender-flag-stripes - rgba: "#000000" - rgba: "#BCC4C7" - rgba: "#FFFFFF" - rgba: "#B7F684" - rgba: "#FFFFFF" - rgba: "#BCC4C7" - rgba: "#000000" - id: "genderqueer-flag" name: "Genderqueer Flag" homogeneous: true direction: to bottom stripes: &genderqueer-flag-stripes - rgba: "#B57EDC" - rgba: "#FFFFFF" - rgba: "#4A8123" - id: "intersex-flag" name: "Intersex Flag" direction: to bottom stripes: &intersex-flag-stripes - rgba: "#FFD800" size: 0.4 - rgba: "#7902AA" size: 0.2 - rgba: "#FFD800" size: 0.4 - id: "demigender-flag" name: "Demigender Flag" homogeneous: true direction: to bottom stripes: &demigender-flag-stripes - rgba: "#7F7F7F" - rgba: "#C3C3C3" - rgba: "#FBFF74" - rgba: "#FFFFFF" - rgba: "#FBFF74" - rgba: "#C3C3C3" - rgba: "#7F7F7F" - id: "biromantic-flag" name: "Biromantic Flag" homogeneous: true direction: to bottom stripes: &biromantic-flag-stripes - rgba: "#8869A5" - rgba: "#D8A7D8" - rgba: "#FFFFFF" - rgba: "#FDB18D" - rgba: "#151638" - id: "disability-flag" name: "Disability Flag" homogeneous: true direction: to bottom stripes: &disability-flag-stripes - rgba: "#595959" - rgba: "#CF7280" - rgba: "#EEDE77" - rgba: "#E8E8E8" - rgba: "#7BC2E0" - rgba: "#3BB07D" - rgba: "#595959" - id: "femboy-flag" name: "Femboy Flag" homogeneous: true direction: to bottom stripes: &femboy-flag-stripes - rgba: "#D460A7" - rgba: "#E4ADCD" - rgba: "#FFFFFF" - rgba: "#57CEF8" - rgba: "#FFFFFF" - rgba: "#E4ADCD" - rgba: "#D460A7" - id: "neutrois-flag" name: "Neutrois Flag" homogeneous: true direction: to bottom stripes: &neutrois-flag-stripes - rgba: "rgb(255,255,255)" - rgba: "rgb(31,159,0)" - rgba: "rgb(0,0,0)" bazaar-orig-v0.7.14/src/progress-bar-designs/pride/pride.h0000664000175000017500000000165715166123241022357 0ustar hasanhasan/* progress-bar-designs/pride/pride.h * * Copyright 2025 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS GtkStyleProvider * bz_get_pride_style_provider (void); char * bz_dup_css_class_for_pride_id (const char *id); G_END_DECLS bazaar-orig-v0.7.14/src/bz-transaction-dialog.c0000664000175000017500000005407715166123241020303 0ustar hasanhasan/* bz-transaction-dialog.c * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include "bz-application.h" #include "bz-entry-selection-row.h" #include "bz-env.h" #include "bz-error.h" #include "bz-flatpak-entry.h" #include "bz-safety-calculator.h" #include "bz-state-info.h" #include "bz-transaction-dialog.h" #include "bz-transaction-list-dialog.h" #include "bz-util.h" static gboolean should_skip_entry (BzEntry *entry, gboolean remove) { gboolean is_installed; if (bz_entry_is_holding (entry)) return TRUE; if (!remove && BZ_IS_FLATPAK_ENTRY (entry) && bz_flatpak_entry_is_installed_ref (BZ_FLATPAK_ENTRY (entry))) return TRUE; is_installed = bz_entry_is_installed (entry); return (!remove && is_installed) || (remove && !is_installed); } static GtkWidget * create_entry_radio_button (BzEntry *entry, GtkWidget **out_radio) { BzStateInfo *state_info = NULL; GListModel *repositories = NULL; g_autoptr (BzRepository) repo = NULL; BzEntrySelectionRow *row = NULL; GtkCheckButton *radio = NULL; state_info = bz_state_info_get_default (); repositories = bz_state_info_get_repositories (state_info); if (repositories != NULL) repo = bz_entry_get_repository (entry, repositories); row = bz_entry_selection_row_new (BZ_FLATPAK_ENTRY (entry), repo); radio = bz_entry_selection_row_get_radio (row); if (out_radio != NULL) *out_radio = GTK_WIDGET (radio); return GTK_WIDGET (row); } static GPtrArray * create_entry_radio_buttons (AdwAlertDialog *alert, GListStore *store, gboolean remove) { g_autoptr (GPtrArray) radios = NULL; GtkWidget *container = NULL; container = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); radios = g_ptr_array_new (); if (store != NULL) { guint n_total_entries = g_list_model_get_n_items (G_LIST_MODEL (store)); if (n_total_entries > 1) { GtkWidget *listbox = NULL; GtkCheckButton *first_valid_radio = NULL; GtkCheckButton *dummy_radio = NULL; listbox = gtk_list_box_new (); gtk_list_box_set_selection_mode (GTK_LIST_BOX (listbox), GTK_SELECTION_NONE); gtk_widget_add_css_class (listbox, "boxed-list"); dummy_radio = GTK_CHECK_BUTTON (gtk_check_button_new ()); for (guint i = 0; i < n_total_entries; i++) { g_autoptr (BzEntry) entry = NULL; GtkWidget *row = NULL; GtkWidget *radio = NULL; gboolean should_skip = FALSE; entry = g_list_model_get_item (G_LIST_MODEL (store), i); should_skip = should_skip_entry (entry, remove); row = create_entry_radio_button (entry, &radio); g_ptr_array_add (radios, radio); gtk_check_button_set_group (GTK_CHECK_BUTTON (radio), dummy_radio); if (should_skip) { gtk_widget_set_sensitive (row, FALSE); gtk_widget_set_sensitive (radio, FALSE); } else { if (first_valid_radio == NULL) { gtk_check_button_set_active (GTK_CHECK_BUTTON (radio), TRUE); first_valid_radio = (GtkCheckButton *) radio; } } gtk_list_box_append (GTK_LIST_BOX (listbox), row); } gtk_box_append (GTK_BOX (container), listbox); } } if (remove) { GtkWidget *listbox = NULL; GtkWidget *keep_data_row = NULL; GtkWidget *delete_data_row = NULL; GtkWidget *keep_radio = NULL; GtkWidget *delete_radio = NULL; listbox = gtk_list_box_new (); gtk_list_box_set_selection_mode (GTK_LIST_BOX (listbox), GTK_SELECTION_NONE); gtk_widget_add_css_class (listbox, "boxed-list"); keep_data_row = adw_action_row_new (); adw_preferences_row_set_title (ADW_PREFERENCES_ROW (keep_data_row), _ ("Keep User Data")); adw_action_row_set_subtitle (ADW_ACTION_ROW (keep_data_row), _ ("Allow restoring personal settings & content")); keep_radio = gtk_check_button_new (); gtk_widget_set_valign (keep_radio, GTK_ALIGN_CENTER); gtk_check_button_set_active (GTK_CHECK_BUTTON (keep_radio), TRUE); adw_action_row_add_prefix (ADW_ACTION_ROW (keep_data_row), keep_radio); adw_action_row_set_activatable_widget (ADW_ACTION_ROW (keep_data_row), keep_radio); gtk_list_box_append (GTK_LIST_BOX (listbox), keep_data_row); delete_data_row = adw_action_row_new (); adw_preferences_row_set_title (ADW_PREFERENCES_ROW (delete_data_row), _ ("Delete All Data")); adw_action_row_set_subtitle (ADW_ACTION_ROW (delete_data_row), _ ("Permanently erase user data to save space")); delete_radio = gtk_check_button_new (); gtk_widget_set_valign (delete_radio, GTK_ALIGN_CENTER); gtk_check_button_set_group (GTK_CHECK_BUTTON (delete_radio), GTK_CHECK_BUTTON (keep_radio)); adw_action_row_add_prefix (ADW_ACTION_ROW (delete_data_row), delete_radio); adw_action_row_set_activatable_widget (ADW_ACTION_ROW (delete_data_row), delete_radio); gtk_list_box_append (GTK_LIST_BOX (listbox), delete_data_row); g_ptr_array_add (radios, keep_radio); g_ptr_array_add (radios, delete_radio); gtk_box_append (GTK_BOX (container), listbox); } adw_alert_dialog_set_extra_child (alert, container); return g_steal_pointer (&radios); } static void configure_install_dialog (AdwAlertDialog *alert, const char *title, const char *id, gboolean has_multiple_entries) { g_autofree char *heading = NULL; heading = g_strdup_printf (_ ("Install %s?"), title); adw_alert_dialog_set_heading (alert, heading); if (has_multiple_entries) adw_alert_dialog_set_body (alert, _ ("Select which version to install. May install additional shared components")); else adw_alert_dialog_set_body (alert, _ ("May install additional shared components")); adw_alert_dialog_add_responses (alert, "cancel", _ ("_Cancel"), "install", _ ("_Install"), NULL); adw_alert_dialog_set_response_appearance (alert, "install", ADW_RESPONSE_SUGGESTED); adw_alert_dialog_set_default_response (alert, "install"); adw_alert_dialog_set_close_response (alert, "cancel"); } static void configure_remove_dialog (AdwAlertDialog *alert, const char *title, const char *id, gboolean has_multiple_entries) { g_autofree char *heading = NULL; g_autofree char *body = NULL; heading = g_strdup_printf (_ ("Remove %s?"), title); if (has_multiple_entries) body = g_strdup (_ ("Select which version to remove.")); else body = g_strdup_printf (_ ("It will not be possible to use %s after it is uninstalled."), title); adw_alert_dialog_set_heading (alert, heading); adw_alert_dialog_set_body (alert, body); adw_alert_dialog_add_responses (alert, "cancel", _ ("_Cancel"), "remove", _ ("_Remove"), NULL); adw_alert_dialog_set_response_appearance (alert, "remove", ADW_RESPONSE_DESTRUCTIVE); adw_alert_dialog_set_default_response (alert, "remove"); adw_alert_dialog_set_close_response (alert, "cancel"); } static void configure_high_risk_warning_dialog (AdwAlertDialog *alert, const char *title, BzHighRiskGroup risk_groups) { g_autofree char *heading = NULL; g_autofree char *body = NULL; heading = g_strdup_printf (_ ("“%s” is High Risk"), title); if (risk_groups & BZ_HIGH_RISK_GROUP_DISK) { body = g_strdup (_ ("This app has full access to your system, including all " "your files, browser history, saved passwords, and " "more. It also has access to the internet, meaning it " "could send your data to outside parties.\n\n" "Because the app is proprietary, it can not be audited " "for what it does with these permissions.")); } else if (risk_groups & BZ_HIGH_RISK_GROUP_X11) { body = g_strdup (_ ("This app uses the legacy X11 windowing system, which " "allows it to record all keystrokes, capture screenshots, " "and monitor other applications. It also has access " "to the internet, meaning it could send your data to " "outside parties.\n\n" "Because the app is proprietary, it can not be audited " "for what it does with these permissions.")); } adw_alert_dialog_set_heading (alert, heading); adw_alert_dialog_set_body (alert, body); adw_alert_dialog_set_body_use_markup (alert, TRUE); adw_alert_dialog_set_prefer_wide_layout (alert, TRUE); adw_alert_dialog_add_responses (alert, "cancel", _ ("_Cancel"), "install", _ ("_Install Anyway"), NULL); adw_alert_dialog_set_response_appearance (alert, "install", ADW_RESPONSE_DESTRUCTIVE); adw_alert_dialog_set_default_response (alert, "cancel"); adw_alert_dialog_set_close_response (alert, "cancel"); } static BzHighRiskGroup get_entry_high_risk_groups (BzEntry *entry) { if (bz_entry_get_is_foss (entry)) return BZ_HIGH_RISK_GROUP_NONE; return bz_safety_calculator_get_high_risk_groups (entry); } BZ_DEFINE_DATA ( show_dialog, ShowDialog, { GtkWidget *parent; BzEntry *entry; BzEntryGroup *group; gboolean remove; gboolean auto_confirm; }, BZ_RELEASE_DATA (entry, g_object_unref); BZ_RELEASE_DATA (group, g_object_unref)) static DexFuture * show_dialog_fiber (ShowDialogData *data) { g_autoptr (GError) local_error = NULL; g_autoptr (GListStore) store = NULL; const char *title = NULL; const char *id = NULL; g_autoptr (AdwDialog) alert = NULL; g_autoptr (AdwDialog) risk_alert = NULL; g_autoptr (GPtrArray) radios = NULL; g_autofree char *dialog_response = NULL; g_autofree char *risk_response = NULL; g_autoptr (BzTransactionDialogResult) result = NULL; g_autoptr (BzEntry) check_entry = NULL; BzHighRiskGroup risk_groups = BZ_HIGH_RISK_GROUP_NONE; guint n_total_entries = 0; gboolean confirmed = 0; result = bz_transaction_dialog_result_new (); if (data->group != NULL) { store = dex_await_object (bz_entry_group_dup_all_into_store (data->group), &local_error); if (store == NULL) { bz_show_error_for_widget (data->parent, _ ("Failed to load transaction dialog"), local_error->message); return dex_future_new_for_error (g_steal_pointer (&local_error)); } for (guint i = g_list_model_get_n_items (G_LIST_MODEL (store)); i > 0; i--) { g_autoptr (BzEntry) entry = NULL; entry = g_list_model_get_item (G_LIST_MODEL (store), i - 1); if (BZ_IS_FLATPAK_ENTRY (entry) && bz_flatpak_entry_is_installed_ref (BZ_FLATPAK_ENTRY (entry)) && (!data->remove || !bz_entry_is_installed (entry))) g_list_store_remove (store, i - 1); } title = bz_entry_group_get_title (data->group); id = bz_entry_group_get_id (data->group); n_total_entries = g_list_model_get_n_items (G_LIST_MODEL (store)); if (n_total_entries > 0) check_entry = g_list_model_get_item (G_LIST_MODEL (store), 0); } else { title = bz_entry_get_title (data->entry); id = bz_entry_get_id (data->entry); check_entry = g_object_ref (data->entry); } if (!data->remove && check_entry != NULL) risk_groups = get_entry_high_risk_groups (check_entry); if (risk_groups != BZ_HIGH_RISK_GROUP_NONE) { risk_alert = g_object_ref_sink (adw_alert_dialog_new (NULL, NULL)); configure_high_risk_warning_dialog (ADW_ALERT_DIALOG (risk_alert), title, risk_groups); adw_dialog_present (risk_alert, data->parent); risk_response = dex_await_string ( bz_make_alert_dialog_future (ADW_ALERT_DIALOG (risk_alert)), &local_error); if (risk_response == NULL) return dex_future_new_for_error (g_steal_pointer (&local_error)); if (g_strcmp0 (risk_response, "install") != 0) { bz_transaction_dialog_result_set_confirmed (result, FALSE); return dex_future_new_for_object (result); } data->auto_confirm = TRUE; } alert = g_object_ref_sink (adw_alert_dialog_new (NULL, NULL)); if (data->remove) configure_remove_dialog (ADW_ALERT_DIALOG (alert), title, id, n_total_entries > 1); else configure_install_dialog (ADW_ALERT_DIALOG (alert), title, id, n_total_entries > 1); radios = create_entry_radio_buttons (ADW_ALERT_DIALOG (alert), store, data->remove); if (!data->remove && data->auto_confirm && radios->len <= 1) { dialog_response = g_strdup ("install"); g_ptr_array_set_size (radios, 0); g_clear_object (&alert); } else if (data->remove && data->auto_confirm && radios->len <= 1) { dialog_response = g_strdup ("remove"); g_ptr_array_set_size (radios, 0); g_clear_object (&alert); } else { adw_dialog_present (alert, data->parent); dialog_response = dex_await_string ( bz_make_alert_dialog_future (ADW_ALERT_DIALOG (alert)), &local_error); if (dialog_response == NULL) return dex_future_new_for_error (g_steal_pointer (&local_error)); if (data->remove && radios->len >= 2) { GtkCheckButton *delete_radio = g_ptr_array_index (radios, radios->len - 1); bz_transaction_dialog_result_set_delete_user_data (result, gtk_check_button_get_active (delete_radio)); } } confirmed = (g_strcmp0 (dialog_response, "install") == 0) || (g_strcmp0 (dialog_response, "remove") == 0); bz_transaction_dialog_result_set_confirmed (result, confirmed); if (!confirmed) return dex_future_new_for_object (result); if (data->group != NULL) { guint n_entries = g_list_model_get_n_items (G_LIST_MODEL (store)); for (guint i = 0; i < MIN (n_entries, radios->len); i++) { GtkCheckButton *check = g_ptr_array_index (radios, i); if (gtk_check_button_get_active (check)) { g_autoptr (BzEntry) entry = NULL; entry = g_list_model_get_item (G_LIST_MODEL (store), i); bz_transaction_dialog_result_set_selected_entry (result, entry); break; } } if (bz_transaction_dialog_result_get_selected_entry (result) == NULL && n_entries > 0) { g_autoptr (BzEntry) entry = NULL; entry = g_list_model_get_item (G_LIST_MODEL (store), 0); bz_transaction_dialog_result_set_selected_entry (result, entry); } } else bz_transaction_dialog_result_set_selected_entry (result, data->entry); return dex_future_new_for_object (result); } DexFuture * bz_transaction_dialog_show (GtkWidget *parent, BzEntry *entry, BzEntryGroup *group, gboolean remove, gboolean auto_confirm) { g_autoptr (ShowDialogData) data = NULL; g_return_val_if_fail (GTK_IS_WIDGET (parent), NULL); g_return_val_if_fail (entry != NULL || group != NULL, NULL); data = show_dialog_data_new (); data->parent = parent; data->entry = bz_object_maybe_ref (entry); data->group = bz_object_maybe_ref (group); data->remove = remove; data->auto_confirm = auto_confirm; return dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) show_dialog_fiber, g_steal_pointer (&data), show_dialog_data_unref); } BZ_DEFINE_DATA ( bulk_install_dialog, BulkInstallDialog, { GtkWidget *parent; GListModel *groups; }, BZ_RELEASE_DATA (groups, g_object_unref)); static DexFuture * bulk_install_dialog_fiber (BulkInstallDialogData *data) { g_autoptr (GError) local_error = NULL; g_autoptr (BzBulkInstallDialogResult) result = NULL; g_autoptr (GPtrArray) resolved_entries = NULL; g_autoptr (GListStore) entries_store = NULL; AdwDialog *dialog = NULL; g_autofree char *dialog_response = NULL; g_autofree char *heading = NULL; guint n_groups = 0; gboolean confirmed = FALSE; result = bz_bulk_install_dialog_result_new (); resolved_entries = g_ptr_array_new_with_free_func (g_object_unref); if (data->groups == NULL) { bz_bulk_install_dialog_result_set_confirmed (result, FALSE); return dex_future_new_for_object (result); } n_groups = g_list_model_get_n_items (data->groups); for (guint i = 0; i < n_groups; i++) { g_autoptr (BzEntryGroup) group = NULL; g_autoptr (GListStore) store = NULL; g_autoptr (BzEntry) entry = NULL; group = g_list_model_get_item (data->groups, i); if (bz_entry_group_get_removable (group) > 0) continue; store = dex_await_object (bz_entry_group_dup_all_into_store (group), &local_error); if (store == NULL || g_list_model_get_n_items (G_LIST_MODEL (store)) == 0) continue; entry = g_list_model_get_item (G_LIST_MODEL (store), 0); if (entry == NULL) continue; if (bz_entry_is_installed (entry) || bz_entry_is_holding (entry)) continue; g_ptr_array_add (resolved_entries, g_object_ref (entry)); } if (resolved_entries->len == 0) { g_autoptr (AdwDialog) info_alert = NULL; info_alert = g_object_ref_sink (adw_alert_dialog_new ( _ ("All apps are already installed"), NULL)); adw_alert_dialog_add_response (ADW_ALERT_DIALOG (info_alert), "ok", _ ("_OK")); adw_alert_dialog_set_default_response (ADW_ALERT_DIALOG (info_alert), "ok"); adw_alert_dialog_set_close_response (ADW_ALERT_DIALOG (info_alert), "ok"); adw_dialog_present (info_alert, data->parent); dex_await (bz_make_alert_dialog_future (ADW_ALERT_DIALOG (info_alert)), NULL); bz_bulk_install_dialog_result_set_confirmed (result, FALSE); return dex_future_new_for_object (result); } entries_store = g_list_store_new (BZ_TYPE_ENTRY); for (guint i = 0; i < resolved_entries->len; i++) g_list_store_append (entries_store, g_ptr_array_index (resolved_entries, i)); heading = g_strdup_printf (ngettext ("Install %u App?", "Install %u Apps?", resolved_entries->len), resolved_entries->len); dialog = bz_transaction_list_dialog_new ( G_LIST_MODEL (entries_store), heading, _ ("The following will be installed. Additional shared components may also be installed"), _ ("%d addons will be installed."), _ ("Additionally, addons will be installed."), _ ("_Cancel"), _ ("_Install All")); adw_alert_dialog_set_default_response (ADW_ALERT_DIALOG (dialog), "confirm"); adw_alert_dialog_set_close_response (ADW_ALERT_DIALOG (dialog), "cancel"); adw_dialog_present (dialog, data->parent); dialog_response = dex_await_string ( bz_make_alert_dialog_future (ADW_ALERT_DIALOG (dialog)), &local_error); if (dialog_response == NULL) return dex_future_new_for_error (g_steal_pointer (&local_error)); confirmed = bz_transaction_list_dialog_was_confirmed ( BZ_TRANSACTION_LIST_DIALOG (dialog)); bz_bulk_install_dialog_result_set_confirmed (result, confirmed); if (confirmed) { g_autoptr (GListStore) store = NULL; store = g_list_store_new (BZ_TYPE_ENTRY); for (guint i = 0; i < resolved_entries->len; i++) { BzEntry *entry = g_ptr_array_index (resolved_entries, i); g_list_store_append (store, entry); } bz_bulk_install_dialog_result_set_entries (result, G_LIST_MODEL (store)); } return dex_future_new_for_object (result); } DexFuture * bz_bulk_install_dialog_show (GtkWidget *parent, GListModel *groups) { g_autoptr (BulkInstallDialogData) data = NULL; g_return_val_if_fail (GTK_IS_WIDGET (parent), NULL); g_return_val_if_fail (G_IS_LIST_MODEL (groups), NULL); data = bulk_install_dialog_data_new (); data->parent = parent; data->groups = g_object_ref (groups); return dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) bulk_install_dialog_fiber, g_steal_pointer (&data), bulk_install_dialog_data_unref); } bazaar-orig-v0.7.14/src/bz-curated-markdown-info.txt0000664000175000017500000000020215166123241021273 0ustar hasanhasanprefix=bz name=curated_markdown_info parent-prefix=g parent-name=object author=AUTOGEN property=string char G_TYPE_STRING string bazaar-orig-v0.7.14/src/bz-entry-inspector.c0000664000175000017500000001264315166123241017657 0ustar hasanhasan/* bz-entry-inspector.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-entry-inspector.h" #include "bz-entry.h" #include "bz-serializable.h" struct _BzEntryInspector { AdwWindow parent_instance; BzResult *result; /* Template widgets */ GtkTextBuffer *text_buffer; GtkCheckButton *convert_to_json; }; G_DEFINE_FINAL_TYPE (BzEntryInspector, bz_entry_inspector, ADW_TYPE_WINDOW); enum { PROP_0, PROP_RESULT, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bz_entry_inspector_dispose (GObject *object) { BzEntryInspector *self = BZ_ENTRY_INSPECTOR (object); g_clear_pointer (&self->result, g_object_unref); G_OBJECT_CLASS (bz_entry_inspector_parent_class)->dispose (object); } static void bz_entry_inspector_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzEntryInspector *self = BZ_ENTRY_INSPECTOR (object); switch (prop_id) { case PROP_RESULT: g_value_set_object (value, bz_entry_inspector_get_result (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_entry_inspector_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzEntryInspector *self = BZ_ENTRY_INSPECTOR (object); switch (prop_id) { case PROP_RESULT: bz_entry_inspector_set_result (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void gen_serialized (BzEntryInspector *self, GtkButton *button) { if (bz_result_get_resolved (self->result)) { BzEntry *entry = NULL; g_autoptr (GVariantBuilder) builder = NULL; g_autoptr (GVariant) variant = NULL; g_autofree char *string = NULL; entry = bz_result_get_object (self->result); builder = g_variant_builder_new (G_VARIANT_TYPE_VARDICT); bz_serializable_serialize (BZ_SERIALIZABLE (entry), builder); variant = g_variant_builder_end (builder); if (gtk_check_button_get_active (self->convert_to_json)) { g_autoptr (JsonNode) node = NULL; g_autoptr (JsonGenerator) generator = NULL; node = json_gvariant_serialize (variant); generator = json_generator_new (); json_generator_set_pretty (generator, TRUE); json_generator_set_root (generator, node); string = json_generator_to_data (generator, NULL); } else string = g_variant_print (variant, FALSE); gtk_text_buffer_set_text (self->text_buffer, string, -1); } else gtk_text_buffer_set_text (self->text_buffer, "!!! The entry has not resolved", -1); } static void bz_entry_inspector_class_init (BzEntryInspectorClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bz_entry_inspector_set_property; object_class->get_property = bz_entry_inspector_get_property; object_class->dispose = bz_entry_inspector_dispose; props[PROP_RESULT] = g_param_spec_object ( "result", NULL, NULL, BZ_TYPE_RESULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-entry-inspector.ui"); gtk_widget_class_bind_template_child (widget_class, BzEntryInspector, text_buffer); gtk_widget_class_bind_template_child (widget_class, BzEntryInspector, convert_to_json); gtk_widget_class_bind_template_callback (widget_class, gen_serialized); } static void bz_entry_inspector_init (BzEntryInspector *self) { gtk_widget_init_template (GTK_WIDGET (self)); } BzEntryInspector * bz_entry_inspector_new (void) { return g_object_new (BZ_TYPE_ENTRY_INSPECTOR, NULL); } BzResult * bz_entry_inspector_get_result (BzEntryInspector *self) { g_return_val_if_fail (BZ_IS_ENTRY_INSPECTOR (self), NULL); return self->result; } void bz_entry_inspector_set_result (BzEntryInspector *self, BzResult *result) { g_return_if_fail (BZ_IS_ENTRY_INSPECTOR (self)); g_clear_pointer (&self->result, g_object_unref); if (result != NULL) self->result = g_object_ref (result); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_RESULT]); } /* End of bz-entry-inspector.c */ bazaar-orig-v0.7.14/src/bz-preferences-dialog.c0000664000175000017500000002743515166123241020255 0ustar hasanhasan/* bz-preferences-dialog.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-preferences-dialog.h" #include typedef struct { const char *id; const char *style_class; const char *tooltip; } BarTheme; static const BarTheme bar_themes[] = { { "accent-color", "accent-color-theme", N_ ("Accent Color") }, { "pride-rainbow-flag", "pride-rainbow-flag-theme", N_ ("Pride Colors") }, { "lesbian-pride-flag", "lesbian-pride-flag-theme", N_ ("Lesbian Pride Colors") }, { "gay-pride-flag", "gay-pride-flag-theme", N_ ("Male Homosexual Pride Colors") }, { "transgender-flag", "transgender-flag-theme", N_ ("Transgender Pride Colors") }, { "nonbinary-flag", "nonbinary-flag-theme", N_ ("Nonbinary Pride Colors") }, { "bisexual-flag", "bisexual-flag-theme", N_ ("Bisexual Pride Colors") }, { "asexual-flag", "asexual-flag-theme", N_ ("Asexual Pride Colors") }, { "pansexual-flag", "pansexual-flag-theme", N_ ("Pansexual Pride Colors") }, { "aromantic-flag", "aromantic-flag-theme", N_ ("Aromantic Pride Colors") }, { "genderfluid-flag", "genderfluid-flag-theme", N_ ("Genderfluid Pride Colors") }, { "polysexual-flag", "polysexual-flag-theme", N_ ("Polysexual Pride Colors") }, { "omnisexual-flag", "omnisexual-flag-theme", N_ ("Omnisexual Pride Colors") }, { "aroace-flag", "aroace-flag-theme", N_ ("Aroace Pride Colors") }, { "agender-flag", "agender-flag-theme", N_ ("Agender Pride Colors") }, { "genderqueer-flag", "genderqueer-flag-theme", N_ ("Genderqueer Pride Colors") }, { "intersex-flag", "intersex-flag-theme", N_ ("Intersex Pride Colors") }, { "demigender-flag", "demigender-flag-theme", N_ ("Demigender Pride Colors") }, { "biromantic-flag", "biromantic-flag-theme", N_ ("Biromantic Pride Colors") }, { "disability-flag", "disability-flag-theme", N_ ("Disability Pride Colors") }, { "femboy-flag", "femboy-flag-theme", N_ ("Femboy Pride Colors") }, { "neutrois-flag", "neutrois-flag-theme", N_ ("Neutrois Pride Colors") }, }; struct _BzPreferencesDialog { AdwPreferencesDialog parent_instance; BzStateInfo *state; GSettings *settings; /* Template widgets */ AdwSwitchRow *only_foss_switch; AdwSwitchRow *only_flathub_switch; AdwSwitchRow *only_verified_switch; AdwSwitchRow *search_debounce_switch; GtkFlowBox *flag_buttons_box; AdwSwitchRow *hide_eol_switch; AdwSwitchRow *rotate_switch; GtkToggleButton *flag_buttons[G_N_ELEMENTS (bar_themes)]; }; G_DEFINE_FINAL_TYPE (BzPreferencesDialog, bz_preferences_dialog, ADW_TYPE_PREFERENCES_DIALOG) enum { PROP_0, PROP_STATE, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bind_settings (BzPreferencesDialog *self); static void create_flag_buttons (BzPreferencesDialog *self); static void bz_preferences_dialog_dispose (GObject *object) { BzPreferencesDialog *self = BZ_PREFERENCES_DIALOG (object); g_clear_object (&self->state); g_clear_object (&self->settings); G_OBJECT_CLASS (bz_preferences_dialog_parent_class)->dispose (object); } static void flag_button_toggled (GtkToggleButton *button, BzPreferencesDialog *self) { const char *theme_id = NULL; if (!gtk_toggle_button_get_active (button)) return; theme_id = g_object_get_data (G_OBJECT (button), "theme-id"); if (theme_id != NULL) { g_settings_set_string (self->settings, "global-progress-bar-theme", theme_id); } } static void global_progress_theme_settings_changed (BzPreferencesDialog *self, const char *key, GSettings *settings) { const char *theme = NULL; theme = g_settings_get_string (self->settings, "global-progress-bar-theme"); for (guint i = 0; i < G_N_ELEMENTS (bar_themes); i++) { if (g_strcmp0 (theme, bar_themes[i].id) == 0) { gtk_toggle_button_set_active (self->flag_buttons[i], TRUE); break; } } } static void on_rotate_switch_changed (AdwSwitchRow *row, GParamSpec *pspec, BzPreferencesDialog *self) { gboolean active = FALSE; active = adw_switch_row_get_active (row); for (guint i = 0; i < G_N_ELEMENTS (bar_themes); i++) { if (active) gtk_widget_add_css_class (GTK_WIDGET (self->flag_buttons[i]), "horizontal"); else gtk_widget_remove_css_class (GTK_WIDGET (self->flag_buttons[i]), "horizontal"); } } static void create_flag_buttons (BzPreferencesDialog *self) { GtkToggleButton *first_button = NULL; for (guint i = 0; i < G_N_ELEMENTS (bar_themes); i++) { GtkToggleButton *button = NULL; button = GTK_TOGGLE_BUTTON (gtk_toggle_button_new ()); gtk_widget_set_tooltip_text (GTK_WIDGET (button), Q_ (bar_themes[i].tooltip)); gtk_widget_add_css_class (GTK_WIDGET (button), "accent-button"); gtk_widget_add_css_class (GTK_WIDGET (button), bar_themes[i].style_class); g_object_set_data_full (G_OBJECT (button), "theme-id", g_strdup (bar_themes[i].id), g_free); if (i == 0) { first_button = button; } else { gtk_toggle_button_set_group (button, first_button); } g_signal_connect (button, "toggled", G_CALLBACK (flag_button_toggled), self); self->flag_buttons[i] = button; gtk_flow_box_append (self->flag_buttons_box, GTK_WIDGET (button)); } } static void bind_settings (BzPreferencesDialog *self) { if (self->settings == NULL) return; /* Bind all boolean settings to their respective switches */ g_settings_bind (self->settings, "show-only-foss", self->only_foss_switch, "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (self->settings, "show-only-flathub", self->only_flathub_switch, "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (self->settings, "show-only-verified", self->only_verified_switch, "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (self->settings, "search-debounce", self->search_debounce_switch, "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (self->settings, "hide-eol", self->hide_eol_switch, "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (self->settings, "rotate-flag", self->rotate_switch, "active", G_SETTINGS_BIND_DEFAULT); if (adw_switch_row_get_active (self->rotate_switch)) { for (guint i = 0; i < G_N_ELEMENTS (bar_themes); i++) { gtk_widget_add_css_class (GTK_WIDGET (self->flag_buttons[i]), "horizontal"); } } g_signal_connect_object ( self->settings, "changed::global-progress-bar-theme", G_CALLBACK (global_progress_theme_settings_changed), self, G_CONNECT_SWAPPED); global_progress_theme_settings_changed (self, "global-progress-bar-theme", self->settings); } static void bz_preferences_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzPreferencesDialog *self = BZ_PREFERENCES_DIALOG (object); switch (prop_id) { case PROP_STATE: g_value_set_object (value, self->state); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_preferences_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { case PROP_STATE: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static void bz_preferences_dialog_class_init (BzPreferencesDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bz_preferences_dialog_set_property; object_class->get_property = bz_preferences_dialog_get_property; object_class->dispose = bz_preferences_dialog_dispose; props[PROP_STATE] = g_param_spec_object ( "state", NULL, NULL, BZ_TYPE_STATE_INFO, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-preferences-dialog.ui"); gtk_widget_class_bind_template_child (widget_class, BzPreferencesDialog, only_foss_switch); gtk_widget_class_bind_template_child (widget_class, BzPreferencesDialog, only_flathub_switch); gtk_widget_class_bind_template_child (widget_class, BzPreferencesDialog, only_verified_switch); gtk_widget_class_bind_template_child (widget_class, BzPreferencesDialog, search_debounce_switch); gtk_widget_class_bind_template_child (widget_class, BzPreferencesDialog, flag_buttons_box); gtk_widget_class_bind_template_child (widget_class, BzPreferencesDialog, hide_eol_switch); gtk_widget_class_bind_template_child (widget_class, BzPreferencesDialog, rotate_switch); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, on_rotate_switch_changed); } static void bz_preferences_dialog_init (BzPreferencesDialog *self) { gtk_widget_init_template (GTK_WIDGET (self)); create_flag_buttons (self); } AdwDialog * bz_preferences_dialog_new (BzStateInfo *state) { BzPreferencesDialog *dialog = NULL; g_return_val_if_fail (BZ_IS_STATE_INFO (state), NULL); dialog = g_object_new (BZ_TYPE_PREFERENCES_DIALOG, NULL); dialog->state = g_object_ref (state); g_object_get (state, "settings", &dialog->settings, NULL); bind_settings (dialog); return ADW_DIALOG (dialog); } bazaar-orig-v0.7.14/src/bz-group-tile-css-watcher.c0000664000175000017500000002353215166123241021021 0ustar hasanhasan/* bz-group-tile-css-watcher.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-group-tile-css-watcher.h" #define LUMINANCE_THRESHOLD 130.0 struct _BzGroupTileCssWatcher { GObject parent_instance; GWeakRef widget; BzEntryGroup *group; GtkCssProvider *css; char *light_class; char *dark_class; char *light_text_class; char *dark_text_class; }; G_DEFINE_FINAL_TYPE (BzGroupTileCssWatcher, bz_group_tile_css_watcher, G_TYPE_OBJECT); enum { PROP_0, PROP_WIDGET, PROP_GROUP, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void refresh (BzGroupTileCssWatcher *self); static void clear (BzGroupTileCssWatcher *self); static void bz_group_tile_css_watcher_dispose (GObject *object) { BzGroupTileCssWatcher *self = BZ_GROUP_TILE_CSS_WATCHER (object); clear (self); g_weak_ref_clear (&self->widget); g_clear_pointer (&self->group, g_object_unref); G_OBJECT_CLASS (bz_group_tile_css_watcher_parent_class)->dispose (object); } static void bz_group_tile_css_watcher_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzGroupTileCssWatcher *self = BZ_GROUP_TILE_CSS_WATCHER (object); switch (prop_id) { case PROP_WIDGET: g_value_take_object (value, bz_group_tile_css_watcher_dup_widget (self)); break; case PROP_GROUP: g_value_set_object (value, bz_group_tile_css_watcher_get_group (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_group_tile_css_watcher_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzGroupTileCssWatcher *self = BZ_GROUP_TILE_CSS_WATCHER (object); switch (prop_id) { case PROP_WIDGET: bz_group_tile_css_watcher_set_widget (self, g_value_get_object (value)); break; case PROP_GROUP: bz_group_tile_css_watcher_set_group (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_group_tile_css_watcher_class_init (BzGroupTileCssWatcherClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bz_group_tile_css_watcher_set_property; object_class->get_property = bz_group_tile_css_watcher_get_property; object_class->dispose = bz_group_tile_css_watcher_dispose; props[PROP_WIDGET] = g_param_spec_object ( "widget", NULL, NULL, GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_GROUP] = g_param_spec_object ( "group", NULL, NULL, BZ_TYPE_ENTRY_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); } static void dark_changed (BzGroupTileCssWatcher *self, GParamSpec *pspec, AdwStyleManager *mgr) { g_autoptr (GtkWidget) widget = NULL; gboolean is_dark; if (self->css == NULL) return; widget = g_weak_ref_get (&self->widget); if (widget == NULL) return; is_dark = adw_style_manager_get_dark (adw_style_manager_get_default ()); gtk_widget_remove_css_class (widget, self->light_class); gtk_widget_remove_css_class (widget, self->dark_class); gtk_widget_remove_css_class (widget, self->light_text_class); gtk_widget_remove_css_class (widget, self->dark_text_class); gtk_widget_add_css_class (widget, is_dark ? self->dark_class : self->light_class); gtk_widget_add_css_class (widget, is_dark ? self->dark_text_class : self->light_text_class); } static void bz_group_tile_css_watcher_init (BzGroupTileCssWatcher *self) { g_weak_ref_init (&self->widget, NULL); g_signal_connect_object ( adw_style_manager_get_default (), "notify::dark", G_CALLBACK (dark_changed), self, G_CONNECT_SWAPPED); } BzGroupTileCssWatcher * bz_group_tile_css_watcher_new (void) { return g_object_new (BZ_TYPE_GROUP_TILE_CSS_WATCHER, NULL); } GtkWidget * bz_group_tile_css_watcher_dup_widget (BzGroupTileCssWatcher *self) { g_return_val_if_fail (BZ_IS_GROUP_TILE_CSS_WATCHER (self), NULL); return g_weak_ref_get (&self->widget); } BzEntryGroup * bz_group_tile_css_watcher_get_group (BzGroupTileCssWatcher *self) { g_return_val_if_fail (BZ_IS_GROUP_TILE_CSS_WATCHER (self), NULL); return self->group; } void bz_group_tile_css_watcher_set_widget (BzGroupTileCssWatcher *self, GtkWidget *widget) { g_return_if_fail (BZ_IS_GROUP_TILE_CSS_WATCHER (self)); g_weak_ref_clear (&self->widget); if (widget != NULL) g_weak_ref_init (&self->widget, widget); refresh (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_WIDGET]); } void bz_group_tile_css_watcher_set_group (BzGroupTileCssWatcher *self, BzEntryGroup *group) { g_return_if_fail (BZ_IS_GROUP_TILE_CSS_WATCHER (self)); g_clear_pointer (&self->group, g_object_unref); if (group != NULL) self->group = g_object_ref (group); refresh (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_GROUP]); } static gdouble get_luminance (GdkRGBA *rgba) { return (0.299 * rgba->red * 255.0) + (0.587 * rgba->green * 255.0) + (0.114 * rgba->blue * 255.0); } static gboolean color_is_light (const char *hex_color) { GdkRGBA rgba; gdouble luminance; if (hex_color == NULL || !gdk_rgba_parse (&rgba, hex_color)) return FALSE; luminance = get_luminance (&rgba); return luminance > LUMINANCE_THRESHOLD; } static void refresh (BzGroupTileCssWatcher *self) { g_autoptr (GtkWidget) widget = NULL; const char *id = NULL; const char *light_accent_color = NULL; const char *dark_accent_color = NULL; clear (self); widget = g_weak_ref_get (&self->widget); if (self->group == NULL || widget == NULL) return; id = bz_entry_group_get_id (self->group); light_accent_color = bz_entry_group_get_light_accent_color (self->group); dark_accent_color = bz_entry_group_get_dark_accent_color (self->group); if (light_accent_color != NULL || dark_accent_color != NULL) { g_autoptr (GString) fixed_id = NULL; g_autofree char *css_string = NULL; gboolean is_dark; fixed_id = g_string_new (id); g_string_replace (fixed_id, ".", "--", 0); self->light_class = g_strdup_printf ("%s-light", fixed_id->str); self->dark_class = g_strdup_printf ("%s-dark", fixed_id->str); self->light_text_class = g_strdup ( color_is_light (light_accent_color != NULL ? light_accent_color : dark_accent_color) ? "flathub-gunmetal" : "flathub-lotion"); self->dark_text_class = g_strdup ( color_is_light (dark_accent_color != NULL ? dark_accent_color : light_accent_color) ? "flathub-gunmetal" : "flathub-lotion"); css_string = g_strdup_printf ( ".%s{background-color:%s;}\n" ".%s{background-color:%s;}", self->light_class, light_accent_color != NULL ? light_accent_color : dark_accent_color, self->dark_class, dark_accent_color != NULL ? dark_accent_color : light_accent_color); self->css = gtk_css_provider_new (); gtk_css_provider_load_from_string ( self->css, css_string); gtk_style_context_add_provider_for_display ( gdk_display_get_default (), GTK_STYLE_PROVIDER (self->css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); is_dark = adw_style_manager_get_dark (adw_style_manager_get_default ()); gtk_widget_add_css_class (widget, is_dark ? self->dark_class : self->light_class); gtk_widget_add_css_class (widget, is_dark ? self->dark_text_class : self->light_text_class); } } static void clear (BzGroupTileCssWatcher *self) { g_autoptr (GtkWidget) widget = NULL; widget = g_weak_ref_get (&self->widget); if (widget != NULL) { if (self->light_class != NULL) gtk_widget_remove_css_class (widget, self->light_class); if (self->dark_class != NULL) gtk_widget_remove_css_class (widget, self->dark_class); if (self->light_text_class != NULL) gtk_widget_remove_css_class (widget, self->light_text_class); if (self->dark_text_class != NULL) gtk_widget_remove_css_class (widget, self->dark_text_class); } g_clear_pointer (&self->light_class, g_free); g_clear_pointer (&self->dark_class, g_free); g_clear_pointer (&self->light_text_class, g_free); g_clear_pointer (&self->dark_text_class, g_free); if (self->css != NULL) gtk_style_context_remove_provider_for_display ( gdk_display_get_default (), GTK_STYLE_PROVIDER (self->css)); g_clear_pointer (&self->css, g_object_unref); } /* End of bz-group-tile-css-watcher.c */ bazaar-orig-v0.7.14/src/bz-transaction-task.txt0000664000175000017500000000065615166123241020375 0ustar hasanhasanprefix=bz name=transaction_task parent-prefix=g parent-name=object author=AUTOGEN include="bz-backend-transaction-op-payload.h" include="bz-backend-transaction-op-progress-payload.h" property=op BzBackendTransactionOpPayload BZ_TYPE_BACKEND_TRANSACTION_OP_PAYLOAD object property=last_progress BzBackendTransactionOpProgressPayload BZ_TYPE_BACKEND_TRANSACTION_OP_PROGRESS_PAYLOAD object property=error char G_TYPE_STRING string bazaar-orig-v0.7.14/src/bz-internal-config.txt0000664000175000017500000000033115166123241020155 0ustar hasanhasanprefix=bz name=internal_config parent-prefix=g parent-name=object author=AUTOGEN include= include="bz-search-bias.h" ensure=BZ_TYPE_SEARCH_BIAS property=search_biases GListModel G_TYPE_LIST_MODEL object bazaar-orig-v0.7.14/src/bz-entry-group.h0000664000175000017500000000754515166123241017017 0ustar hasanhasan/* bz-entry-group.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-application-map-factory.h" #include "bz-entry.h" #include "bz-result.h" G_BEGIN_DECLS #define BZ_TYPE_ENTRY_GROUP (bz_entry_group_get_type ()) G_DECLARE_FINAL_TYPE (BzEntryGroup, bz_entry_group, BZ, ENTRY_GROUP, GObject) BzEntryGroup * bz_entry_group_new (BzApplicationMapFactory *factory); BzEntryGroup * bz_entry_group_new_for_single_entry (BzEntry *entry); /* Only necessary if reading props from another thread, writing is always prohibited */ GMutexLocker * bz_entry_group_lock (BzEntryGroup *self); GListModel * bz_entry_group_get_model (BzEntryGroup *self); GListModel * bz_entry_group_get_installed_versions (BzEntryGroup *self); const char * bz_entry_group_get_id (BzEntryGroup *self); const char * bz_entry_group_get_title (BzEntryGroup *self); const char * bz_entry_group_get_developer (BzEntryGroup *self); const char * bz_entry_group_get_description (BzEntryGroup *self); GIcon * bz_entry_group_get_mini_icon (BzEntryGroup *self); gboolean bz_entry_group_get_is_floss (BzEntryGroup *self); const char * bz_entry_group_get_light_accent_color (BzEntryGroup *self); const char * bz_entry_group_get_dark_accent_color (BzEntryGroup *self); gboolean bz_entry_group_get_is_flathub (BzEntryGroup *self); gboolean bz_entry_group_get_is_verified (BzEntryGroup *self); const char * bz_entry_group_get_search_tokens (BzEntryGroup *self); const char * bz_entry_group_get_eol (BzEntryGroup *self); guint64 bz_entry_group_get_installed_size (BzEntryGroup *self); GListModel * bz_entry_group_get_addon_group_ids (BzEntryGroup *self); void bz_entry_group_append_addon_group_id (BzEntryGroup *self, const char *id); int bz_entry_group_get_n_addons (BzEntryGroup *self); const char * bz_entry_group_get_donation_url (BzEntryGroup *self); gboolean bz_entry_group_has_category (BzEntryGroup *self, const char *name); BzCategoryFlags bz_entry_group_get_categories (BzEntryGroup *self); int bz_entry_group_get_content_age_rating (BzEntryGroup *self); BzResult * bz_entry_group_dup_ui_entry (BzEntryGroup *self); char * bz_entry_group_dup_ui_entry_id (BzEntryGroup *self); int bz_entry_group_get_installable (BzEntryGroup *self); int bz_entry_group_get_updatable (BzEntryGroup *self); int bz_entry_group_get_removable (BzEntryGroup *self); int bz_entry_group_get_installable_and_available (BzEntryGroup *self); int bz_entry_group_get_updatable_and_available (BzEntryGroup *self); int bz_entry_group_get_removable_and_available (BzEntryGroup *self); gboolean bz_entry_group_is_searchable (BzEntryGroup *self); gboolean bz_entry_group_is_addon (BzEntryGroup *self); guint64 bz_entry_group_get_user_data_size (BzEntryGroup *self); void bz_entry_group_reap_user_data (BzEntryGroup *self); void bz_entry_group_add (BzEntryGroup *self, BzEntry *entry, BzEntry *runtime, gboolean ignore_eol); void bz_entry_group_connect_living (BzEntryGroup *self, BzEntry *entry); DexFuture * bz_entry_group_dup_all_into_store (BzEntryGroup *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-error.h0000664000175000017500000000202415166123241015640 0ustar hasanhasan/* bz-error.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include G_BEGIN_DECLS void bz_show_error_for_widget (GtkWidget *widget, const char *title, const char *text); DexFuture * bz_make_alert_dialog_future (AdwAlertDialog *dialog); G_END_DECLS bazaar-orig-v0.7.14/src/bz-search-engine.c0000664000175000017500000006532115166123241017223 0ustar hasanhasan/* bz-search-engine.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::SEARCH-ENGINE" #include "bz-search-engine.h" #include "bz-entry-group.h" #include "bz-env.h" #include "bz-finished-search-query.h" #include "bz-search-result.h" #include "bz-util.h" struct _BzSearchEngine { GObject parent_instance; GListModel *model; GListModel *biases; GPtrArray *biases_mirror; }; G_DEFINE_FINAL_TYPE (BzSearchEngine, bz_search_engine, G_TYPE_OBJECT); enum { PROP_0, PROP_MODEL, PROP_BIASES, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void biases_changed (BzSearchEngine *self, guint position, guint removed, guint added, GListModel *model); static double test_strings (const char *query, const char *against, gssize accept_min_size); typedef struct { guint idx; double val; } Score; static gint cmp_scores (Score *a, Score *b); enum { LINEAR, EXPONENTIAL, }; BZ_DEFINE_DATA ( bias, Bias, { gboolean invalid; GRegex *regex; char *convert_to; GHashTable *boost; int boost_kind; union { struct { double slope; double y_intercept; } linear_boost; struct { double factor; double y_intercept; } exponential_boost; }; }, BZ_RELEASE_DATA (regex, g_regex_unref); BZ_RELEASE_DATA (convert_to, g_free); BZ_RELEASE_DATA (boost, g_hash_table_unref)); BZ_DEFINE_DATA ( query_task, QueryTask, { char **terms; GPtrArray *snapshot; GPtrArray *biases; }, BZ_RELEASE_DATA (terms, g_strfreev); BZ_RELEASE_DATA (snapshot, g_ptr_array_unref); BZ_RELEASE_DATA (biases, g_ptr_array_unref)) static DexFuture * query_task_fiber (QueryTaskData *data); BZ_DEFINE_DATA ( query_sub_task, QuerySubTask, { char *query_utf8; GPtrArray *shallow_mirror; double threshold; guint work_offset; guint work_length; GPtrArray *active_biases; }, BZ_RELEASE_DATA (query_utf8, g_free); BZ_RELEASE_DATA (shallow_mirror, g_ptr_array_unref); BZ_RELEASE_DATA (active_biases, g_ptr_array_unref)); static DexFuture * query_sub_task_fiber (QuerySubTaskData *data); static inline GUnicodeType utf8_char_class (const char *s, gunichar *ch_out); static inline const char * utf8_skip_to_next_of_class (const char **s, GUnicodeType class, gsize *read_utf8); static void bz_search_engine_dispose (GObject *object) { BzSearchEngine *self = BZ_SEARCH_ENGINE (object); if (self->biases != NULL) g_signal_handlers_disconnect_by_func (self->biases, biases_changed, self); g_clear_object (&self->model); g_clear_object (&self->biases); g_clear_pointer (&self->biases_mirror, g_ptr_array_unref); G_OBJECT_CLASS (bz_search_engine_parent_class)->dispose (object); } static void bz_search_engine_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzSearchEngine *self = BZ_SEARCH_ENGINE (object); switch (prop_id) { case PROP_MODEL: g_value_set_object (value, bz_search_engine_get_model (self)); break; case PROP_BIASES: g_value_set_object (value, bz_search_engine_get_biases (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_search_engine_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzSearchEngine *self = BZ_SEARCH_ENGINE (object); switch (prop_id) { case PROP_MODEL: bz_search_engine_set_model (self, g_value_get_object (value)); break; case PROP_BIASES: bz_search_engine_set_biases (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_search_engine_class_init (BzSearchEngineClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bz_search_engine_set_property; object_class->get_property = bz_search_engine_get_property; object_class->dispose = bz_search_engine_dispose; props[PROP_MODEL] = g_param_spec_object ( "model", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_BIASES] = g_param_spec_object ( "biases", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_search_engine_init (BzSearchEngine *self) { self->biases_mirror = g_ptr_array_new_with_free_func (bias_data_unref); } BzSearchEngine * bz_search_engine_new (void) { return g_object_new (BZ_TYPE_SEARCH_ENGINE, NULL); } GListModel * bz_search_engine_get_biases (BzSearchEngine *self) { g_return_val_if_fail (BZ_IS_SEARCH_ENGINE (self), NULL); return self->biases; } void bz_search_engine_set_biases (BzSearchEngine *self, GListModel *biases) { g_return_if_fail (BZ_IS_SEARCH_ENGINE (self)); g_return_if_fail (biases == NULL || G_IS_LIST_MODEL (biases)); if (self->biases != NULL) g_signal_handlers_disconnect_by_func (self->biases, biases_changed, self); g_clear_object (&self->biases); g_ptr_array_set_size (self->biases_mirror, 0); if (biases != NULL) { guint n_biases = 0; self->biases = g_object_ref (biases); n_biases = g_list_model_get_n_items (biases); biases_changed (self, 0, 0, n_biases, biases); g_signal_connect_swapped ( biases, "items-changed", G_CALLBACK (biases_changed), self); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_BIASES]); } GListModel * bz_search_engine_get_model (BzSearchEngine *self) { g_return_val_if_fail (BZ_IS_SEARCH_ENGINE (self), NULL); return self->model; } void bz_search_engine_set_model (BzSearchEngine *self, GListModel *model) { g_return_if_fail (BZ_IS_SEARCH_ENGINE (self)); g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model)); g_clear_object (&self->model); if (model != NULL) self->model = g_object_ref (model); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MODEL]); } DexFuture * bz_search_engine_query (BzSearchEngine *self, const char *const *terms) { guint n_groups = 0; dex_return_error_if_fail (BZ_IS_SEARCH_ENGINE (self)); dex_return_error_if_fail (terms != NULL && *terms != NULL); if (self->model != NULL) n_groups = g_list_model_get_n_items (self->model); if (self->model == NULL || n_groups == 0 || **terms == '\0') { g_autoptr (GPtrArray) results = NULL; g_autoptr (BzFinishedSearchQuery) finished = NULL; results = g_ptr_array_new_with_free_func (g_object_unref); g_ptr_array_set_size (results, n_groups); for (guint i = 0; i < results->len; i++) { g_autoptr (BzEntryGroup) group = NULL; g_autoptr (BzSearchResult) result = NULL; group = g_list_model_get_item (self->model, i); result = bz_search_result_new (); bz_search_result_set_group (result, group); bz_search_result_set_original_index (result, i); g_ptr_array_index (results, i) = g_steal_pointer (&result); } finished = bz_finished_search_query_new (); bz_finished_search_query_set_interpreted_query (finished, ""); bz_finished_search_query_set_results (finished, results); bz_finished_search_query_set_n_results (finished, n_groups); bz_finished_search_query_set_elapsed (finished, 0.0); return dex_future_new_for_object (finished); } else { g_autoptr (GPtrArray) snapshot = NULL; g_autoptr (QueryTaskData) data = NULL; snapshot = g_ptr_array_new_with_free_func (g_object_unref); g_ptr_array_set_size (snapshot, n_groups); for (guint i = 0; i < snapshot->len; i++) g_ptr_array_index (snapshot, i) = g_list_model_get_item (self->model, i); data = query_task_data_new (); data->terms = g_strdupv ((gchar **) terms); data->snapshot = g_steal_pointer (&snapshot); data->biases = g_ptr_array_ref (self->biases_mirror); return dex_scheduler_spawn ( dex_thread_pool_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) query_task_fiber, query_task_data_ref (data), query_task_data_unref); } } static void biases_changed (BzSearchEngine *self, guint position, guint removed, guint added, GListModel *model) { g_autoptr (GPtrArray) new_mirror = NULL; /* Since `self->biases_mirror` is used in other threads, it should be immutable after its construction; so we have to make a new mirror upon every change */ new_mirror = g_ptr_array_new_with_free_func (bias_data_unref); g_ptr_array_set_size (new_mirror, self->biases_mirror->len + added - removed); #define COPY_OVER(_old_idx, _new_idx, _len) \ for (guint _i = 0; _i < (_len); _i++) \ { \ BiasData *_data = NULL; \ BiasData **_loc = NULL; \ \ _data = g_ptr_array_index (self->biases_mirror, (_old_idx) + _i); \ _loc = (BiasData **) &g_ptr_array_index (new_mirror, (_new_idx) + _i); \ *_loc = bias_data_ref (_data); \ } COPY_OVER (0, 0, position); COPY_OVER (position + removed, position + added, self->biases_mirror->len - (position + removed)); #undef COPY_OVER for (guint i = 0; i < added; i++) { g_autoptr (GError) local_error = NULL; BiasData **loc = NULL; g_autoptr (BzSearchBias) bias = NULL; const char *regex_string = NULL; const char *convert_to = NULL; GListModel *boost_appids = NULL; BzLinearFunction *linear_function = NULL; BzExponentialFunction *exponential_function = NULL; g_autoptr (GRegex) regex = NULL; g_autoptr (GHashTable) boost = NULL; g_autoptr (BiasData) data = NULL; loc = (BiasData **) &g_ptr_array_index (new_mirror, position + i); bias = g_list_model_get_item (model, position + i); regex_string = bz_search_bias_get_regex (bias); convert_to = bz_search_bias_get_convert_to (bias); boost_appids = bz_search_bias_get_boost_appids (bias); linear_function = bz_search_bias_get_linear_boost (bias); exponential_function = bz_search_bias_get_exponential_boost (bias); #define SKIP() \ G_STMT_START \ { \ g_autoptr (BiasData) _data = NULL; \ \ _data = bias_data_new (); \ _data->invalid = TRUE; \ *loc = bias_data_ref (_data); \ } \ G_STMT_END if (regex_string == NULL || (convert_to == NULL && (boost_appids == NULL || (linear_function == NULL && exponential_function == NULL)))) { g_critical ("Bias is incomplete! Skipping..."); SKIP (); continue; } if (linear_function != NULL && exponential_function != NULL) { g_critical ("Search bias can only have one boost function! Skipping..."); SKIP (); continue; } regex = g_regex_new ( regex_string, G_REGEX_OPTIMIZE, G_REGEX_MATCH_DEFAULT, &local_error); if (regex == NULL) { g_critical ("Bias regex \"%s\" is invalid: %s", regex_string, local_error->message); SKIP (); continue; } #undef SKIP if (boost_appids != NULL) { guint n_appids = 0; n_appids = g_list_model_get_n_items (boost_appids); if (n_appids > 0) { boost = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); for (guint j = 0; j < n_appids; j++) { g_autoptr (GtkStringObject) string = NULL; const char *appid = NULL; string = g_list_model_get_item (boost_appids, j); appid = gtk_string_object_get_string (string); g_hash_table_replace (boost, g_strdup (appid), NULL); } } } data = bias_data_new (); data->regex = g_regex_ref (regex); data->convert_to = bz_maybe_strdup (convert_to); data->boost = bz_maybe_ref (boost, g_hash_table_ref); if (linear_function != NULL) { data->boost_kind = LINEAR; data->linear_boost.slope = bz_linear_function_get_slope (linear_function); data->linear_boost.y_intercept = bz_linear_function_get_y_intercept (linear_function); } if (exponential_function != NULL) { data->boost_kind = EXPONENTIAL; data->exponential_boost.factor = bz_exponential_function_get_factor (exponential_function); data->exponential_boost.y_intercept = bz_exponential_function_get_y_intercept (exponential_function); } *loc = bias_data_ref (data); } g_clear_pointer (&self->biases_mirror, g_ptr_array_unref); self->biases_mirror = g_steal_pointer (&new_mirror); } static DexFuture * query_task_fiber (QueryTaskData *data) { char **terms = data->terms; GPtrArray *shallow_mirror = data->snapshot; GPtrArray *biases = data->biases; g_autoptr (GError) local_error = NULL; gboolean result = FALSE; g_autoptr (GTimer) timer = NULL; g_autofree char *query_utf8 = NULL; guint n_sub_tasks = 0; guint scores_per_task = 0; g_autoptr (GPtrArray) active_biases = NULL; g_autoptr (GPtrArray) sub_futures = NULL; g_autoptr (GArray) scores = NULL; g_autoptr (GPtrArray) results = NULL; g_autoptr (BzFinishedSearchQuery) finished = NULL; timer = g_timer_new (); query_utf8 = g_strjoinv (" ", terms); n_sub_tasks = MAX (1, MIN (shallow_mirror->len / 512, g_get_num_processors ())); scores_per_task = shallow_mirror->len / n_sub_tasks; active_biases = g_ptr_array_new_with_free_func (bias_data_unref); for (guint i = 0; i < biases->len; i++) { BiasData *bias = NULL; bias = g_ptr_array_index (biases, i); if (bias->invalid) continue; if (!g_regex_match (bias->regex, query_utf8, G_REGEX_MATCH_DEFAULT, NULL)) continue; if (bias->convert_to != NULL) { g_autofree char *tmp = NULL; tmp = g_regex_replace ( bias->regex, query_utf8, -1, 0, bias->convert_to, G_REGEX_MATCH_DEFAULT, NULL); if (tmp != NULL) { g_clear_pointer (&query_utf8, g_free); query_utf8 = g_steal_pointer (&tmp); } } g_ptr_array_add (active_biases, bias_data_ref (bias)); } sub_futures = g_ptr_array_new_with_free_func (dex_unref); for (guint i = 0; i < n_sub_tasks; i++) { g_autoptr (QuerySubTaskData) sub_data = NULL; g_autoptr (DexFuture) future = NULL; sub_data = query_sub_task_data_new (); sub_data->query_utf8 = g_strdup (query_utf8); sub_data->shallow_mirror = g_ptr_array_ref (shallow_mirror); sub_data->threshold = 1.0; sub_data->work_offset = i * scores_per_task; sub_data->work_length = scores_per_task; sub_data->active_biases = g_ptr_array_ref (active_biases); if (i >= n_sub_tasks - 1) sub_data->work_length += shallow_mirror->len % n_sub_tasks; future = dex_scheduler_spawn ( dex_thread_pool_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) query_sub_task_fiber, query_sub_task_data_ref (sub_data), query_sub_task_data_unref); g_ptr_array_add (sub_futures, g_steal_pointer (&future)); } result = dex_await (dex_future_allv ( (DexFuture *const *) sub_futures->pdata, sub_futures->len), &local_error); if (!result) return dex_future_new_for_error (g_steal_pointer (&local_error)); scores = g_array_new (FALSE, FALSE, sizeof (Score)); for (guint i = 0; i < sub_futures->len; i++) { DexFuture *future = NULL; GArray *scores_out = NULL; future = g_ptr_array_index (sub_futures, i); scores_out = g_value_get_boxed (dex_future_get_value (future, NULL)); if (scores_out->len > 0) g_array_append_vals (scores, scores_out->data, scores_out->len); } if (scores->len > 0) g_array_sort (scores, (GCompareFunc) cmp_scores); results = g_ptr_array_new_with_free_func (g_object_unref); g_ptr_array_set_size (results, scores->len); for (guint i = 0; i < scores->len; i++) { Score *score = NULL; BzEntryGroup *group = NULL; g_autoptr (BzSearchResult) search_result = NULL; score = &g_array_index (scores, Score, i); group = g_ptr_array_index (shallow_mirror, score->idx); search_result = bz_search_result_new (); bz_search_result_set_group (search_result, group); bz_search_result_set_original_index (search_result, score->idx); bz_search_result_set_score (search_result, score->val); g_ptr_array_index (results, i) = g_steal_pointer (&search_result); } finished = bz_finished_search_query_new (); bz_finished_search_query_set_interpreted_query (finished, query_utf8); bz_finished_search_query_set_results (finished, results); bz_finished_search_query_set_n_results (finished, results->len); bz_finished_search_query_set_elapsed (finished, g_timer_elapsed (timer, NULL)); return dex_future_new_for_object (finished); } static DexFuture * query_sub_task_fiber (QuerySubTaskData *data) { GPtrArray *shallow_mirror = data->shallow_mirror; char *query_utf8 = data->query_utf8; double threshold = data->threshold; guint work_offset = data->work_offset; guint work_length = data->work_length; GPtrArray *active_biases = data->active_biases; g_autoptr (GArray) scores_out = NULL; scores_out = g_array_new (FALSE, FALSE, sizeof (Score)); for (guint i = 0; i < work_length; i++) { g_autoptr (GMutexLocker) locker = NULL; BzEntryGroup *group = NULL; const char *id = NULL; const char *title = NULL; double score = 0.0; group = g_ptr_array_index (shallow_mirror, work_offset + i); locker = bz_entry_group_lock (group); if (!bz_entry_group_is_searchable (group)) continue; id = bz_entry_group_get_id (group); title = bz_entry_group_get_title (group); if ((id != NULL && g_strcmp0 (query_utf8, id) == 0) || (title != NULL && strcasecmp (query_utf8, title) == 0)) score = (double) G_MAXINT; else { const char *developer = NULL; const char *description = NULL; const char *search_tokens = NULL; developer = bz_entry_group_get_developer (group); description = bz_entry_group_get_description (group); search_tokens = bz_entry_group_get_search_tokens (group); #define EVALUATE_STRING(_s, _accept_min_size) \ ((_s) != NULL \ ? (test_strings (query_utf8, (_s), (_accept_min_size))) \ : 0.0) score += EVALUATE_STRING (title, 2) * 2.0; score += EVALUATE_STRING (developer, 2) * 1.0; score += EVALUATE_STRING (description, 3) * 1.0; score += EVALUATE_STRING (search_tokens, -1) * 1.5; #undef EVALUATE_STRING } for (guint j = 0; j < active_biases->len; j++) { BiasData *bias = NULL; bias = g_ptr_array_index (active_biases, j); if (bias->boost == NULL) continue; if (!g_hash_table_contains (bias->boost, id)) continue; switch (bias->boost_kind) { case LINEAR: score = bias->linear_boost.slope * score + bias->linear_boost.y_intercept; break; case EXPONENTIAL: score = pow (bias->exponential_boost.factor, score) * bias->exponential_boost.y_intercept; break; default: break; } } if (score > threshold) { Score append = { 0 }; append.idx = work_offset + i; append.val = score; g_array_append_val (scores_out, append); } } return dex_future_new_take_boxed (G_TYPE_ARRAY, g_steal_pointer (&scores_out)); } #define UTF8_FOREACH_FORWARD(_var, _s) \ for (const char *_var = (_s); \ _var != NULL && *_var != '\0'; \ _var = g_utf8_next_char (_var)) #define UTF8_FOREACH_FORWARD_WITH_END(_var, _s, _end) \ for (const char *_var = (_s); \ _var != NULL && *_var != '\0' && _var < (_end); \ _var = g_utf8_next_char (_var)) #define UTF8_FOREACH_BACKWARD(_var, _s, _start) \ for (const char *_var = (_s); \ _var != NULL && _var >= (_start); \ _var = g_utf8_prev_char (_var)) #define UTF8_FOREACH_TOKEN_FORWARDS(_start_var, _end_var, _s, _token_len) \ for (const char *_start_var = (_s), *_end_var = utf8_skip_to_next_of_class (&_start_var, G_UNICODE_SPACE_SEPARATOR, (_token_len)); \ _start_var != NULL && *_start_var != '\0'; \ _start_var = _end_var, _end_var = utf8_skip_to_next_of_class (&_start_var, G_UNICODE_SPACE_SEPARATOR, (_token_len))) static double test_strings (const char *query, const char *against, gssize accept_min_size) { double score = 0.0; gsize query_tok_utf8_len = 0; gsize against_tok_utf8_len = 0; UTF8_FOREACH_TOKEN_FORWARDS (query_tok_start, query_tok_end, query, &query_tok_utf8_len) { gboolean query_token_has_match = FALSE; UTF8_FOREACH_TOKEN_FORWARDS (against_tok_start, against_tok_end, against, &against_tok_utf8_len) { gboolean match = FALSE; gsize consumed = 0; if (accept_min_size > 0 && against_tok_utf8_len < accept_min_size) continue; UTF8_FOREACH_FORWARD_WITH_END (against_ptr, against_tok_start, against_tok_end) { const char *against_check_ptr = NULL; gunichar against_ch = 0; if (query_tok_utf8_len > against_tok_utf8_len - consumed) break; match = TRUE; against_check_ptr = against_ptr; against_ch = g_unichar_tolower (g_utf8_get_char (against_ptr)); UTF8_FOREACH_FORWARD_WITH_END (query_ptr, query_tok_start, query_tok_end) { gunichar query_ch = 0; query_ch = g_unichar_tolower (g_utf8_get_char (query_ptr)); if (against_ch != query_ch) { match = FALSE; break; } against_check_ptr = g_utf8_next_char (against_check_ptr); against_ch = g_unichar_tolower (g_utf8_get_char (against_check_ptr)); } if (match) break; else consumed++; } if (match) { score += (double) (query_tok_utf8_len * query_tok_utf8_len) / (double) against_tok_utf8_len; query_token_has_match = TRUE; } } if (!query_token_has_match) { score = 0.0; break; } } return score; } static inline GUnicodeType utf8_char_class (const char *s, gunichar *ch_out) { gunichar ch = 0; GUnicodeType cl = 0; ch = g_utf8_get_char (s); cl = g_unichar_type (ch); if (ch_out != NULL) *ch_out = ch; return cl; } static inline const char * utf8_skip_to_next_of_class (const char **s, GUnicodeType class, gsize *read_utf8) { gboolean skipped = FALSE; if (read_utf8 != NULL) *read_utf8 = 0; UTF8_FOREACH_FORWARD (p, *s) { if (utf8_char_class (p, NULL) == class) { if (skipped) return p; } else { if (!skipped) { *s = p; skipped = TRUE; } if (read_utf8 != NULL) (*read_utf8)++; } } /* return the end of the string if nothing was found */ return *s + strlen (*s); } static gint cmp_scores (Score *a, Score *b) { return (b->val - a->val < 0.0) ? -1 : 1; } /* End of bz-search-engine.c */ bazaar-orig-v0.7.14/src/bz-login-page.c0000664000175000017500000005400015166123241016525 0ustar hasanhasan/* bz-login-page.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include #include #include #include "bz-auth-state.h" #include "bz-flathub-auth-provider.h" #include "bz-global-net.h" #include "bz-login-page.h" #include "bz-util.h" struct _BzLoginPage { AdwNavigationPage parent_instance; BzAuthState *auth_state; WebKitWebView *webview; gboolean webkit_loaded; SoupSession *session; SoupCookieJar *cookie_jar; GList *providers; BzFlathubAuthProvider *current_provider; char *auth_redirect_url; char *session_cookie; GDateTime *session_cookie_expires; gboolean oauth_completed; GtkStack *main_stack; AdwStatusPage *error_status_page; AdwPreferencesGroup *provider_preferences_group; GtkScrolledWindow *browser_scroll; }; G_DEFINE_FINAL_TYPE (BzLoginPage, bz_login_page, ADW_TYPE_NAVIGATION_PAGE) enum { PROP_0, PROP_AUTH_STATE, N_PROPS }; static GParamSpec *properties[N_PROPS]; static WebKitNetworkSession * get_shared_network_session (void) { static WebKitNetworkSession *shared_session = NULL; if (g_once_init_enter (&shared_session)) { g_autofree char *data_dir = NULL; g_autoptr (WebKitNetworkSession) session = NULL; data_dir = g_build_filename (g_get_user_data_dir (), "io.github.kolunmi.Bazaar", "webkit-data", NULL); session = webkit_network_session_new (data_dir, NULL); g_once_init_leave (&shared_session, g_steal_pointer (&session)); } return shared_session; } static void show_error_take (BzLoginPage *self, char *message) { g_autofree char *escaped_message = NULL; gtk_stack_set_visible_child_name (self->main_stack, "error"); escaped_message = g_markup_escape_text (message, -1); adw_status_page_set_description (self->error_status_page, escaped_message); g_free (message); } static JsonObject * parse_json_response (GBytes *bytes, GError **error) { gboolean result = FALSE; g_autoptr (JsonParser) parser = NULL; JsonNode *root = NULL; parser = json_parser_new (); result = json_parser_load_from_data ( parser, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), error); if (!result) return NULL; root = json_parser_get_root (parser); return json_node_dup_object (root); } static SoupMessage * create_flathub_request (const char *method, const char *route) { g_autofree char *url = NULL; g_autoptr (SoupMessage) msg = NULL; url = g_strdup_printf ("https://flathub.org/api/v2%s", route); msg = soup_message_new (method, url); soup_message_headers_append (soup_message_get_request_headers (msg), "accept", "application/json"); return g_steal_pointer (&msg); } static void load_webkit_library (BzLoginPage *self) { WebKitNetworkSession *network_session = NULL; if (self->webkit_loaded) return; network_session = get_shared_network_session (); self->webview = g_object_new ( WEBKIT_TYPE_WEB_VIEW, "network-session", network_session, NULL); gtk_scrolled_window_set_child ( self->browser_scroll, GTK_WIDGET (self->webview)); self->webkit_loaded = TRUE; } static void on_user_info_loaded (GObject *source_object, GAsyncResult *res, GWeakRef *wr); static void on_oauth_complete (GObject *source_object, GAsyncResult *res, GWeakRef *wr); static void complete_oauth (BzLoginPage *self, const char *code, const char *state, const char *error) { g_autoptr (JsonBuilder) builder = NULL; g_autoptr (JsonGenerator) generator = NULL; g_autofree char *route = NULL; g_autofree char *json_data = NULL; g_autoptr (SoupMessage) msg = NULL; gtk_stack_set_visible_child_name (self->main_stack, "loading"); builder = json_builder_new (); json_builder_begin_object (builder); if (error != NULL) { json_builder_set_member_name (builder, "state"); json_builder_add_string_value (builder, state); json_builder_set_member_name (builder, "error"); json_builder_add_string_value (builder, error); } else { json_builder_set_member_name (builder, "code"); json_builder_add_string_value (builder, code); json_builder_set_member_name (builder, "state"); json_builder_add_string_value (builder, state); } json_builder_end_object (builder); generator = json_generator_new (); json_generator_set_root (generator, json_builder_get_root (builder)); json_data = json_generator_to_data (generator, NULL); route = g_strdup_printf ("/auth/login/%s", bz_flathub_auth_provider_get_method (self->current_provider)); msg = soup_message_new ("POST", g_strdup_printf ("https://flathub.org/api/v2%s", route)); soup_message_headers_append (soup_message_get_request_headers (msg), "accept", "application/json"); soup_message_headers_append (soup_message_get_request_headers (msg), "Content-Type", "application/json"); soup_message_set_request_body_from_bytes (msg, "application/json", g_bytes_new (json_data, strlen (json_data))); soup_session_send_and_read_async ( self->session, msg, G_PRIORITY_DEFAULT, NULL, (GAsyncReadyCallback) on_oauth_complete, bz_track_weak (self)); } static gboolean on_decide_policy (BzLoginPage *self, WebKitPolicyDecision *decision, WebKitPolicyDecisionType decision_type, WebKitWebView *webview) { WebKitNavigationAction *nav_action = NULL; WebKitURIRequest *request = NULL; const char *uri = NULL; g_autoptr (GUri) parsed_uri = NULL; g_autoptr (GHashTable) params = NULL; const char *code = NULL; const char *state = NULL; const char *error = NULL; if (decision_type != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION) return FALSE; nav_action = webkit_navigation_policy_decision_get_navigation_action ( WEBKIT_NAVIGATION_POLICY_DECISION (decision)); request = webkit_navigation_action_get_request (nav_action); uri = webkit_uri_request_get_uri (request); if (uri == NULL || strstr (uri, "flathub.org") == NULL || strstr (uri, "/login/") == NULL) return FALSE; parsed_uri = g_uri_parse (uri, G_URI_FLAGS_NONE, NULL); if (parsed_uri == NULL) return FALSE; params = g_uri_parse_params (g_uri_get_query (parsed_uri), -1, "&", G_URI_PARAMS_NONE, NULL); if (params == NULL) return FALSE; code = g_hash_table_lookup (params, "code"); state = g_hash_table_lookup (params, "state"); error = g_hash_table_lookup (params, "error"); if ((code != NULL && state != NULL && !self->oauth_completed) || (error != NULL && state != NULL && !self->oauth_completed)) { self->oauth_completed = TRUE; webkit_policy_decision_ignore (decision); complete_oauth (self, code, state, error); return TRUE; } return FALSE; } static void get_user_info (BzLoginPage *self) { g_autoptr (SoupMessage) msg = NULL; msg = create_flathub_request ("GET", "/auth/userinfo"); soup_session_send_and_read_async ( self->session, msg, G_PRIORITY_DEFAULT, NULL, (GAsyncReadyCallback) on_user_info_loaded, bz_track_weak (self)); } static void on_oauth_complete (GObject *source_object, GAsyncResult *res, GWeakRef *wr) { g_autoptr (BzLoginPage) self = NULL; g_autoptr (GError) local_error = NULL; g_autoptr (GBytes) bytes = NULL; g_autoptr (JsonObject) obj = NULL; const char *status = NULL; g_autoslist (SoupCookie) cookies = NULL; self = g_weak_ref_get (wr); if (self == NULL) goto done; bytes = soup_session_send_and_read_finish ( SOUP_SESSION (source_object), res, &local_error); if (bytes == NULL) { g_warning ("OAuth complete error: %s", local_error->message); show_error_take (self, g_strdup_printf ("Error: %s", local_error->message)); goto done; } obj = parse_json_response (bytes, &local_error); if (obj == NULL) { g_warning ("Failed to parse OAuth response: %s", local_error->message); show_error_take (self, g_strdup_printf ("Error: %s", local_error->message)); goto done; } status = json_object_get_string_member (obj, "status"); cookies = soup_cookie_jar_all_cookies (self->cookie_jar); for (GSList *l = cookies; l != NULL; l = l->next) { SoupCookie *cookie = l->data; if (g_strcmp0 (soup_cookie_get_name (cookie), "session") == 0) { g_clear_pointer (&self->session_cookie, g_free); self->session_cookie = g_strdup (soup_cookie_get_value (cookie)); g_clear_pointer (&self->session_cookie_expires, g_date_time_unref); self->session_cookie_expires = g_date_time_ref (soup_cookie_get_expires (cookie)); } } if (g_strcmp0 (status, "ok") == 0 || g_strcmp0 (status, "success") == 0) get_user_info (self); else show_error_take (self, g_strdup ("Authentication failed")); done: bz_weak_release (wr); } static void on_user_info_loaded (GObject *source_object, GAsyncResult *res, GWeakRef *wr) { g_autoptr (BzLoginPage) self = NULL; g_autoptr (GBytes) bytes = NULL; g_autoptr (GError) error = NULL; g_autoptr (JsonObject) obj = NULL; JsonObject *default_account = NULL; const char *displayname = NULL; const char *avatar_url = NULL; self = g_weak_ref_get (wr); if (self == NULL) goto done; if (self->webview != NULL) webkit_web_view_load_uri (self->webview, "about:blank"); bytes = soup_session_send_and_read_finish (SOUP_SESSION (source_object), res, &error); if (error != NULL) { g_warning ("User info load error: %s", error->message); show_error_take (self, g_strdup_printf ("Error: %s", error->message)); goto done; } obj = parse_json_response (bytes, &error); if (obj == NULL) { g_warning ("Failed to parse user info: %s", error->message); show_error_take (self, g_strdup_printf ("Error: %s", error->message)); goto done; } displayname = json_object_get_string_member (obj, "displayname"); if (json_object_has_member (obj, "default_account")) { default_account = json_object_get_object_member (obj, "default_account"); if (displayname == NULL && json_object_has_member (default_account, "login")) displayname = json_object_get_string_member (default_account, "login"); if (json_object_has_member (default_account, "avatar")) avatar_url = json_object_get_string_member (default_account, "avatar"); } if (displayname == NULL) displayname = "N/A"; if (self->auth_state != NULL) bz_auth_state_set_authenticated (self->auth_state, displayname, self->session_cookie, self->session_cookie_expires, avatar_url); gtk_stack_set_visible_child_name (self->main_stack, "finish"); done: bz_weak_release (wr); } static void on_login_response (GObject *source_object, GAsyncResult *res, GWeakRef *wr) { g_autoptr (BzLoginPage) self = NULL; g_autoptr (GError) local_error = NULL; g_autoptr (GBytes) bytes = NULL; g_autoptr (JsonObject) obj = NULL; const char *redirect = NULL; self = g_weak_ref_get (wr); if (self == NULL) goto done; bytes = soup_session_send_and_read_finish ( SOUP_SESSION (source_object), res, &local_error); if (bytes == NULL) { show_error_take (self, g_strdup_printf ("Error: %s", local_error->message)); goto done; } obj = parse_json_response (bytes, &local_error); if (obj == NULL) { show_error_take (self, g_strdup_printf ("Error: %s", local_error->message)); goto done; } redirect = json_object_get_string_member (obj, "redirect"); if (redirect == NULL) { show_error_take (self, g_strdup ("Error: No redirect URL received")); goto done; } g_clear_pointer (&self->auth_redirect_url, g_free); self->auth_redirect_url = g_strdup (redirect); load_webkit_library (self); g_signal_connect_swapped ( self->webview, "decide-policy", G_CALLBACK (on_decide_policy), self); gtk_stack_set_visible_child_name (self->main_stack, "browser"); webkit_web_view_load_uri (self->webview, self->auth_redirect_url); done: bz_weak_release (wr); } static void on_provider_row_activated (BzLoginPage *self, GtkButton *button) { BzFlathubAuthProvider *provider = NULL; g_autoptr (SoupMessage) msg = NULL; g_autofree char *route = NULL; provider = g_object_get_data (G_OBJECT (button), "provider"); if (provider == NULL) return; self->current_provider = provider; self->oauth_completed = FALSE; gtk_stack_set_visible_child_name (self->main_stack, "loading"); route = g_strdup_printf ("/auth/login/%s", bz_flathub_auth_provider_get_method (provider)); msg = create_flathub_request ("GET", route); soup_session_send_and_read_async ( self->session, msg, G_PRIORITY_DEFAULT, NULL, (GAsyncReadyCallback) on_login_response, bz_track_weak (self)); } static void on_providers_loaded (GObject *source_object, GAsyncResult *res, GWeakRef *wr) { g_autoptr (BzLoginPage) self = NULL; g_autoptr (GError) local_error = NULL; g_autoptr (GBytes) bytes = NULL; g_autoptr (JsonParser) parser = NULL; JsonNode *root; JsonArray *array; self = g_weak_ref_get (wr); if (self == NULL) goto done; bytes = soup_session_send_and_read_finish (SOUP_SESSION (source_object), res, &local_error); if (bytes == NULL) { show_error_take (self, g_strdup_printf ("Error loading providers: %s", local_error->message)); goto done; } parser = json_parser_new (); if (!json_parser_load_from_data (parser, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), &local_error)) { show_error_take (self, g_strdup_printf ("Error parsing providers: %s", local_error->message)); goto done; } root = json_parser_get_root (parser); array = json_node_get_array (root); for (guint i = 0; i < json_array_get_length (array); i++) { JsonObject *provider_obj = NULL; g_autoptr (BzFlathubAuthProvider) provider = NULL; const char *method = NULL; const char *name = NULL; GtkWidget *row = NULL; GtkWidget *prefix_icon = NULL; GtkWidget *suffix_icon = NULL; g_autofree char *icon_name = NULL; provider_obj = json_array_get_object_element (array, i); provider = bz_flathub_auth_provider_new (); method = json_object_get_string_member (provider_obj, "method"); name = json_object_get_string_member (provider_obj, "name"); row = adw_action_row_new (); icon_name = g_strdup_printf ("io.github.kolunmi.Bazaar.%s", method); bz_flathub_auth_provider_set_name (provider, name); bz_flathub_auth_provider_set_method (provider, method); self->providers = g_list_append (self->providers, g_object_ref (provider)); adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), name); prefix_icon = gtk_image_new_from_icon_name (icon_name); gtk_image_set_icon_size (GTK_IMAGE (prefix_icon), GTK_ICON_SIZE_LARGE); gtk_widget_add_css_class (prefix_icon, "lowres-icon"); adw_action_row_add_prefix (ADW_ACTION_ROW (row), prefix_icon); suffix_icon = gtk_image_new_from_icon_name ("go-next-symbolic"); adw_action_row_add_suffix (ADW_ACTION_ROW (row), suffix_icon); g_object_set_data_full (G_OBJECT (row), "provider", g_object_ref (provider), g_object_unref); gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), true); g_signal_connect_swapped (row, "activated", G_CALLBACK (on_provider_row_activated), self); adw_preferences_group_add (self->provider_preferences_group, row); } gtk_stack_set_visible_child_name (self->main_stack, "start"); done: bz_weak_release (wr); } static void load_providers (BzLoginPage *self) { g_autoptr (SoupMessage) msg = NULL; gtk_stack_set_visible_child_name (self->main_stack, "loading"); msg = create_flathub_request ("GET", "/auth/login"); soup_session_send_and_read_async ( self->session, msg, G_PRIORITY_DEFAULT, NULL, (GAsyncReadyCallback) on_providers_loaded, bz_track_weak (self)); } static void on_close_clicked (GtkButton *button, BzLoginPage *self) { GtkWidget *navigation_view = NULL; navigation_view = gtk_widget_get_ancestor (GTK_WIDGET (self), ADW_TYPE_NAVIGATION_VIEW); if (navigation_view != NULL) adw_navigation_view_pop (ADW_NAVIGATION_VIEW (navigation_view)); } static void bz_login_page_dispose (GObject *object) { BzLoginPage *self = BZ_LOGIN_PAGE (object); g_clear_object (&self->auth_state); g_clear_object (&self->session); g_clear_object (&self->cookie_jar); g_clear_pointer (&self->session_cookie_expires, g_date_time_unref); g_clear_pointer (&self->auth_redirect_url, g_free); g_clear_pointer (&self->session_cookie, g_free); if (self->providers != NULL) { g_list_free_full (self->providers, (GDestroyNotify) g_object_unref); self->providers = NULL; } G_OBJECT_CLASS (bz_login_page_parent_class)->dispose (object); } static void bz_login_page_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzLoginPage *self = BZ_LOGIN_PAGE (object); switch (prop_id) { case PROP_AUTH_STATE: g_value_set_object (value, self->auth_state); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_login_page_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzLoginPage *self = BZ_LOGIN_PAGE (object); switch (prop_id) { case PROP_AUTH_STATE: g_set_object (&self->auth_state, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static char * format_greeting (gpointer object, const char *name) { if (name == NULL || name[0] == '\0') return g_strdup (" "); return g_strdup_printf (_ ("Hello, %s!"), name); } static void bz_login_page_class_init (BzLoginPageClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_login_page_dispose; object_class->get_property = bz_login_page_get_property; object_class->set_property = bz_login_page_set_property; properties[PROP_AUTH_STATE] = g_param_spec_object ( "auth-state", NULL, NULL, BZ_TYPE_AUTH_STATE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPS, properties); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-login-page.ui"); gtk_widget_class_bind_template_child (widget_class, BzLoginPage, main_stack); gtk_widget_class_bind_template_child (widget_class, BzLoginPage, error_status_page); gtk_widget_class_bind_template_child (widget_class, BzLoginPage, provider_preferences_group); gtk_widget_class_bind_template_child (widget_class, BzLoginPage, browser_scroll); gtk_widget_class_bind_template_callback (widget_class, on_close_clicked); gtk_widget_class_bind_template_callback (widget_class, format_greeting); } static void bz_login_page_init (BzLoginPage *self) { gtk_widget_init_template (GTK_WIDGET (self)); self->session = soup_session_new (); soup_session_set_proxy_resolver (self->session, bz_get_default_proxy_resolver ()); self->cookie_jar = soup_cookie_jar_new (); soup_cookie_jar_set_accept_policy (self->cookie_jar, SOUP_COOKIE_JAR_ACCEPT_ALWAYS); soup_session_add_feature (self->session, SOUP_SESSION_FEATURE (self->cookie_jar)); self->webkit_loaded = FALSE; self->oauth_completed = FALSE; load_providers (self); } AdwNavigationPage * bz_login_page_new (BzAuthState *auth_state) { return g_object_new (BZ_TYPE_LOGIN_PAGE, "auth-state", auth_state, NULL); } bazaar-orig-v0.7.14/src/bz-yaml-parser.h0000664000175000017500000000233215166123241016745 0ustar hasanhasan/* bz-yaml-parser.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_YAML_ERROR (bz_yaml_error_quark ()) GQuark bz_yaml_error_quark (void); typedef enum { BZ_YAML_ERROR_INVALID_YAML = 0, BZ_YAML_ERROR_DOES_NOT_CONFORM, BZ_YAML_ERROR_BAD_SCALAR, } BzYamlError; #define BZ_TYPE_YAML_PARSER (bz_yaml_parser_get_type ()) G_DECLARE_FINAL_TYPE (BzYamlParser, bz_yaml_parser, BZ, YAML_PARSER, GObject) BzYamlParser * bz_yaml_parser_new_for_resource_schema (const char *path); G_END_DECLS bazaar-orig-v0.7.14/src/bz-row-view.h0000664000175000017500000000222015166123241016264 0ustar hasanhasan/* bz-row-view.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-curated-row.h" G_BEGIN_DECLS #define BZ_TYPE_ROW_VIEW (bz_row_view_get_type ()) G_DECLARE_FINAL_TYPE (BzRowView, bz_row_view, BZ, ROW_VIEW, AdwBin) GtkWidget * bz_row_view_new (BzCuratedRow *row); void bz_row_view_set_row (BzRowView *self, BzCuratedRow *row); BzCuratedRow * bz_row_view_get_row (BzRowView *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-progress-bar.c0000664000175000017500000001165415166123241017121 0ustar hasanhasan/* bz-progress-bar.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include "bz-progress-bar.h" struct _BzProgressBar { AdwBin parent_instance; double fraction; AdwAnimation *animation; /* Template widgets */ GtkProgressBar *bar; }; G_DEFINE_FINAL_TYPE (BzProgressBar, bz_progress_bar, ADW_TYPE_BIN) enum { PROP_0, PROP_FRACTION, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bz_progress_bar_dispose (GObject *object) { BzProgressBar *self = BZ_PROGRESS_BAR (object); g_clear_object (&self->animation); G_OBJECT_CLASS (bz_progress_bar_parent_class)->dispose (object); } static void bz_progress_bar_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzProgressBar *self = BZ_PROGRESS_BAR (object); switch (prop_id) { case PROP_FRACTION: g_value_set_double (value, bz_progress_bar_get_fraction (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_progress_bar_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzProgressBar *self = BZ_PROGRESS_BAR (object); switch (prop_id) { case PROP_FRACTION: bz_progress_bar_set_fraction (self, g_value_get_double (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_progress_bar_class_init (BzProgressBarClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_progress_bar_dispose; object_class->get_property = bz_progress_bar_get_property; object_class->set_property = bz_progress_bar_set_property; props[PROP_FRACTION] = g_param_spec_double ( "fraction", NULL, NULL, 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-progress-bar.ui"); gtk_widget_class_bind_template_child (widget_class, BzProgressBar, bar); } static void bz_progress_bar_init (BzProgressBar *self) { AdwAnimationTarget *target = NULL; AdwSpringParams *spring = NULL; gtk_widget_init_template (GTK_WIDGET (self)); target = adw_property_animation_target_new (G_OBJECT (self->bar), "fraction"); spring = adw_spring_params_new (1.0, 0.5, 200.0); self->animation = adw_spring_animation_new ( GTK_WIDGET (self), 0.0, 0.0, spring, target); adw_spring_animation_set_epsilon ( ADW_SPRING_ANIMATION (self->animation), 0.00025); } GtkWidget * bz_progress_bar_new (void) { return g_object_new (BZ_TYPE_PROGRESS_BAR, NULL); } void bz_progress_bar_set_fraction (BzProgressBar *self, double fraction) { double last = 0.0; double current = 0.0; g_return_if_fail (BZ_IS_PROGRESS_BAR (self)); last = self->fraction; self->fraction = CLAMP (fraction, 0.0, 1.0); current = gtk_progress_bar_get_fraction (self->bar); if (self->fraction < last || G_APPROX_VALUE (last, self->fraction, 0.001)) { adw_animation_reset (self->animation); gtk_progress_bar_set_fraction (self->bar, self->fraction); } else { adw_spring_animation_set_value_from ( ADW_SPRING_ANIMATION (self->animation), current); adw_spring_animation_set_value_to ( ADW_SPRING_ANIMATION (self->animation), self->fraction); adw_spring_animation_set_initial_velocity ( ADW_SPRING_ANIMATION (self->animation), adw_spring_animation_get_velocity ( ADW_SPRING_ANIMATION (self->animation))); adw_animation_play (self->animation); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_FRACTION]); } double bz_progress_bar_get_fraction (BzProgressBar *self) { g_return_val_if_fail (BZ_IS_PROGRESS_BAR (self), 0.0); return self->fraction; } bazaar-orig-v0.7.14/src/bz-transaction-list-dialog.blp0000664000175000017500000000427315166123241021600 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzTransactionListDialog: Adw.AlertDialog { extra-child: ScrolledWindow { width-request: 300; propagate-natural-height: true; overflow: hidden; vexpand: true; hscrollbar-policy: never; child: Box { orientation: vertical; spacing: 5; ListView list_view { styles [ "navigation-sidebar", ] model: NoSelection selection_model {}; factory: BuilderListItemFactory { template ListItem { activatable: false; child: Box { orientation: horizontal; margin-top: 5; margin-bottom: 5; spacing: 6; Image { icon-size: large; paintable: bind template.item as <$BzEntry>.icon-paintable; visible: bind $invert_boolean($is_null(template.item as <$BzEntry>.icon-paintable) as ) as ; } Image { icon-size: large; icon-name: "application-x-executable"; visible: bind $is_null(template.item as <$BzEntry>.icon-paintable) as ; } Box { orientation: vertical; spacing: 3; Label { styles [ "heading", ] hexpand: true; xalign: 0.0; ellipsize: end; single-line-mode: true; label: bind template.item as <$BzEntry>.title; } Label { styles [ "dimmed", ] hexpand: true; xalign: 0.0; wrap: true; wrap-mode: word_char; single-line-mode: true; selectable: true; label: bind template.item as <$BzEntry>.id; } } }; } }; } Label secondary_label { styles [ "dimmed", ] visible: false; wrap: true; justify: center; } }; }; }bazaar-orig-v0.7.14/src/bz-list-tile.c0000664000175000017500000001504715166123241016421 0ustar hasanhasan/* bz-list-tile.c * * Copyright 2025 Hari Rana * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-list-tile.h" typedef struct { GtkWidget *child; } BzListTilePrivate; G_DEFINE_TYPE_WITH_PRIVATE (BzListTile, bz_list_tile, GTK_TYPE_WIDGET) enum { PROP_0, PROP_CHILD, LAST_PROP }; static GParamSpec *props[LAST_PROP]; enum { ACTIVATED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0, }; static void on_gesture_click_released (BzListTile *self, gint n_press, gdouble x, gdouble y, GtkGestureClick *gesture); static void bz_list_tile_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzListTile *self = BZ_LIST_TILE (object); switch (prop_id) { case PROP_CHILD: g_value_set_object (value, bz_list_tile_get_child (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_list_tile_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzListTile *self = BZ_LIST_TILE (object); switch (prop_id) { case PROP_CHILD: bz_list_tile_set_child (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_list_tile_dispose (GObject *object) { BzListTile *self = BZ_LIST_TILE (object); BzListTilePrivate *priv = bz_list_tile_get_instance_private (self); g_clear_pointer (&priv->child, gtk_widget_unparent); G_OBJECT_CLASS (bz_list_tile_parent_class)->dispose (object); } static void bz_list_tile_class_init (BzListTileClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->get_property = bz_list_tile_get_property; object_class->set_property = bz_list_tile_set_property; object_class->dispose = bz_list_tile_dispose; /** * BzListTile:child: * * The child widget. */ props[PROP_CHILD] = g_param_spec_object ("child", NULL, NULL, GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); /** * BzListTile::activated: * * This signal is emitted after the tile has been activated. */ signals[ACTIVATED] = g_signal_new ("activated", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); { g_autoptr (GtkShortcutAction) activate_action = NULL; const guint activate_keyvals[] = { GDK_KEY_space, GDK_KEY_KP_Space, GDK_KEY_Return, GDK_KEY_ISO_Enter, GDK_KEY_KP_Enter, }; activate_action = gtk_signal_action_new ("activated"); for (size_t i = 0; i < G_N_ELEMENTS (activate_keyvals); i++) { g_autoptr (GtkShortcut) activate_shortcut = NULL; activate_shortcut = gtk_shortcut_new (gtk_keyval_trigger_new (activate_keyvals[i], 0), g_object_ref (activate_action)); gtk_widget_class_add_shortcut (widget_class, activate_shortcut); } } gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT); } static void bz_list_tile_init (BzListTile *self) { GtkGesture *gesture_click; gtk_widget_add_css_class (GTK_WIDGET (self), "card"); gtk_widget_add_css_class (GTK_WIDGET (self), "activatable"); gesture_click = gtk_gesture_click_new (); g_signal_connect_swapped (gesture_click, "released", G_CALLBACK (on_gesture_click_released), self); gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture_click)); gtk_widget_set_focusable (GTK_WIDGET (self), TRUE); gtk_widget_set_receives_default (GTK_WIDGET (self), TRUE); } /** * bz_list_tile_new: * * Create a new #BzListTile. * * Returns: (transfer full): a newly created #BzListTile */ BzListTile * bz_list_tile_new (void) { return g_object_new (BZ_TYPE_LIST_TILE, NULL); } /** * bz_list_tile_get_child: * @self: a #BzListTile * * Get the child associated with @self. * * Returns: (transfer none) (nullable): the child */ GtkWidget * bz_list_tile_get_child (BzListTile *self) { BzListTilePrivate *priv; g_assert (BZ_IS_LIST_TILE (self)); priv = bz_list_tile_get_instance_private (self); return priv->child; } /** * bz_list_tile_set_child: * @self: a #BzListTile * @child: (transfer none): the child * * Set the child to associate with @self. */ void bz_list_tile_set_child (BzListTile *self, GtkWidget *child) { BzListTilePrivate *priv; g_assert (BZ_IS_LIST_TILE (self)); priv = bz_list_tile_get_instance_private (self); /* Since this is not a library, there is no point in safeguarding it */ priv->child = child; gtk_widget_set_parent (child, GTK_WIDGET (self)); } static void on_gesture_click_released (BzListTile *self, gint n_press, gdouble x, gdouble y, GtkGestureClick *gesture) { if (gtk_widget_contains (GTK_WIDGET (self), x, y)) { gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED); if (!gtk_widget_grab_focus (GTK_WIDGET (self))) g_assert_not_reached (); g_signal_emit (self, signals[ACTIVATED], 0); } else { gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED); } } bazaar-orig-v0.7.14/src/bz-library-page.blp0000664000175000017500000002352315166123241017422 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzLibraryPage: Adw.Bin { child: Box { orientation: vertical; Adw.Clamp search_box_clamp { margin-start: 12; margin-end: 12; maximum-size: 375; visible: bind template.has-apps; child: Adw.Bin { halign: fill; margin-top: 10; margin-bottom: 10; child: Box { orientation: horizontal; spacing: 8; height-request: 40; Image { icon-name: "system-search-symbolic"; } Text search_bar { hexpand: true; placeholder-text: _("Search installed apps"); notify::text => $search_text_changed(template); } Button clear_button { icon-name: "edit-clear-symbolic"; visible: bind $not($is_empty_string(search_bar.text) as ) as ; styles [ "flat", "circular", "searchbar-button", ] clicked => $reset_search_cb(template); accessibility { label: _("Clear search"); } } styles [ "search-box", ] }; }; } Adw.ViewStack stack { enable-transitions: true; transition-duration: 400; Adw.ViewStackPage { name: "empty"; title: _("Empty"); child: Adw.StatusPage { icon-name: "library-symbolic"; title: _("No Apps Found"); description: ""; }; } Adw.ViewStackPage { name: "no-results"; title: _("No Results"); child: Adw.StatusPage { icon-name: "library-symbolic"; title: _("No Results"); description: bind $no_results_found_subtitle(search_bar.text) as ; child: Button { styles [ "pill", ] halign: center; label: "Search Store Instead"; clicked => $global_search_cb(template); }; }; } Adw.ViewStackPage { name: "content"; // Translators: . title: _("Library"); child: ScrolledWindow scroll{ hscrollbar-policy: never; child: Adw.Clamp { vexpand: true; maximum-size: 650; child: Box margin_box { orientation: vertical; margin-start: 9; margin-end: 9; Box non_search_content { orientation: vertical; visible: bind $is_empty_string(search_bar.text) as ; Revealer { reveal-child: bind $invert_boolean($is_empty(template.state as <$BzStateInfo>.available-updates) as ) as ; transition-type: slide_down; child: Box { orientation: vertical; spacing: 8; margin-top: 15; Label { label: _("Pending Updates"); xalign: 0; margin-start: 12; margin-top: 15; styles [ "heading", "h4", ] } $BzUpdatesCard { state: bind template.state; update => $updates_card_update_cb(template); } }; } Revealer { reveal-child: bind $invert_boolean($is_zero(template.state as <$BzStateInfo>.transaction-manager as <$BzTransactionManager>.install-trackers as .n-items) as ) as ; transition-type: slide_down; child: Box { margin-top: 15; orientation: vertical; Label install_label { label: _("Downloads"); xalign: 0; margin-start: 12; styles [ "heading", "h4", ] } ListView install_list_view { styles [ "navigation-sidebar", "installed-list-view", ] model: NoSelection { model: bind template.state as <$BzStateInfo>.transaction-manager as <$BzTransactionManager>.install-trackers; }; factory: BuilderListItemFactory { template ListItem { activatable: false; child: $BzTransactionTile { tracker: bind template.item; activated => $tile_activated_cb(); }; } }; } }; } Revealer { reveal-child: bind $invert_boolean($is_zero(template.state as <$BzStateInfo>.transaction-manager as <$BzTransactionManager>.removal-trackers as .n-items) as ) as ; transition-type: slide_down; child: Box { margin-top: 15; orientation: vertical; Label removal_label { label: _("Recently Uninstalled"); xalign: 0; margin-start: 12; styles [ "heading", "h4", ] } ListView removal_list_view { styles [ "navigation-sidebar", "installed-list-view", ] model: NoSelection { model: bind template.state as <$BzStateInfo>.transaction-manager as <$BzTransactionManager>.removal-trackers; }; factory: BuilderListItemFactory { template ListItem { activatable: false; child: $BzTransactionTile { tracker: bind template.item; activated => $tile_activated_cb(); }; } }; } }; } Revealer { reveal-child: bind template.state as <$BzStateInfo>.transaction-manager as <$BzTransactionManager>.has-transactions; margin-bottom: 15; transition-type: slide_down; child: ListBox { margin-bottom: 16; margin-top: 4; margin-start: 4; margin-end: 4; selection-mode: none; styles [ "boxed-list", ] Adw.ButtonRow { title: _("Clear Finished Tasks"); activated => $clear_tasks_cb(template); styles [ "error", ] } }; } Box { margin-start: 12; margin-end: 4; Label { label: _("Installed Apps"); xalign: 0; visible: bind template.has-apps; hexpand: true; margin-top: 4; styles [ "heading", "h4", ] } MenuButton { icon-name: "sliders-horizontal-symbolic"; popover: sort_popover; styles ["flat"] } } } ListView list_view { styles [ "navigation-sidebar", "installed-list-view", "installed-section" ] visible: bind template.has-apps; model: NoSelection { model: FilterListModel filter_model { filter: CustomFilter filter {}; model: SortListModel sort_model { sorter: CustomSorter sorter {}; model: bind template.model; }; notify::n-items => $n_filtered_items_changed(template); }; }; factory: BuilderListItemFactory { template ListItem { activatable: false; selectable: false; focusable: false; child: $BzInstalledTile { group: bind template.item as <$BzEntryGroup>; activated => $tile_activated_cb(); }; } }; } }; }; }; } } }; } Popover sort_popover { child: Box { orientation: vertical; spacing: 6; margin-top: 8; margin-bottom: 8; margin-start: 8; margin-end: 16; Label { label: _("Sort By"); wrap: true; wrap-mode: word_char; xalign: 0; margin-start: 28; styles [ "heading", "h4", "dimmed" ] } CheckButton sort_name { label: _("Name"); active: true; toggled => $sort_changed_cb(template); } CheckButton sort_size { label: _("Size"); group: sort_name; toggled => $sort_changed_cb(template); } }; }bazaar-orig-v0.7.14/src/bz-curated-app-tile.blp0000664000175000017500000000024615166123241020201 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzCuratedAppTile: Adw.Bin { child: $BzAppTile { group: bind template.group; clicked => $clicked_cb(template); }; } bazaar-orig-v0.7.14/src/bz-search-page.blp0000664000175000017500000002466215166123241017230 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzSearchPage: Adw.Bin { child: Adw.BreakpointBin { width-request: 360; height-request: 100; Adw.Breakpoint { condition ("max-width: 1000sp") setters { grid_view.min-columns: 2; grid_view.max-columns: 2; clamp_scrollable.maximum-size: 700; } } Adw.Breakpoint { condition ("max-width: 700sp") setters { empty_box.margin-start: 10; empty_box.margin-end: 10; empty_box.margin-top: 5; search_box_clamp.margin-start: 12; search_box_clamp.margin-end: 12; grid_view.min-columns: 1; grid_view.max-columns: 1; clamp_scrollable.maximum-size: 400; } } child: Box { orientation: vertical; Adw.Clamp search_box_clamp { margin-start: 12; margin-end: 12; maximum-size: 375; child: Adw.Bin { halign: fill; margin-top: 10; margin-bottom: 10; child: Box { spacing: 8; height-request: 40; Image { icon-name: "system-search-symbolic"; } Text search_bar { hexpand: true; placeholder-text: _("Search Apps, Games, Software"); } Adw.Spinner search_busy { visible: false; width-request: 16; height-request: 16; } MenuButton filter_button { visible: bind $is_valid_string(search_bar.text) as ; icon-name: "sliders-horizontal-symbolic"; tooltip-text: _("Search Filters"); popover: $BzSearchFilterPopover filter_popover { notify::has-active-filters => $has_active_filters_cb(); }; styles [ "flat", "circular", "searchbar-button", ] accessibility { label: _("Filters"); } } Button clear_button { visible: bind $is_valid_string(search_bar.text) as ; icon-name: "edit-clear-symbolic"; styles [ "flat", "circular", "searchbar-button", ] clicked => $reset_search_cb(template); accessibility { label: _("Clear Search"); } } styles [ "search-box", ] }; }; } Adw.Clamp { margin-start: 12; margin-end: 12; maximum-size: 375; child: Box { margin-start: 12; margin-end: 12; margin-top: 6; margin-bottom: 6; styles [ "bz-debug", ] orientation: vertical; spacing: 5; visible: bind template.state as <$BzStateInfo>.debug_mode; Box { orientation: horizontal; spacing: 10; Label { label: "Interpreted Query:"; } Label { styles [ "caption-heading", ] label: bind template.current-query as <$BzFinishedSearchQuery>.interpreted-query; } } Box { orientation: horizontal; spacing: 10; Label { label: "# of Results:"; } Label { styles [ "caption-heading", ] label: bind $format_uint(template.current-query as <$BzFinishedSearchQuery>.n-results as ) as ; } } Box { orientation: horizontal; spacing: 10; Label { label: "Seconds Elapsed:"; } Label { styles [ "caption-heading", ] label: bind $format_double(template.current-query as <$BzFinishedSearchQuery>.elapsed as ) as ; } } }; } Stack search_stack { transition-type: crossfade; StackPage { name: "empty"; child: Box { orientation: vertical; vexpand: true; Adw.StatusPage { visible: bind $is_empty(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories) as ; hexpand: true; vexpand: true; icon-name: "system-search-symbolic"; title: _("Categories Unavailable"); description: _("Search for apps using the search bar above."); } ScrolledWindow { hscrollbar-policy: never; vexpand: true; visible: bind $invert_boolean($is_empty(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories) as ) as ; child: Adw.Clamp { maximum-size: 1000; tightening-threshold: 900; valign: start; child: Box empty_box { margin-start: 30; margin-end: 30; margin-top: 16; margin-bottom: 50; orientation: vertical; $BzSearchPillList { margin-bottom: 25; activated => $pill_list_cb(template); } Label { label: _("Browse Categories"); halign: start; margin-bottom: 12; margin-start: 4; wrap: true; wrap-mode: word_char; styles [ "heading", ] } $BzDynamicListView { styles [ "flathub-page-section", ] hexpand: true; max-children-per-line: 4; scroll: false; noscroll-kind: flow-box; child-type: "BzCategoryTile"; child-prop: "category"; model: bind template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories; bind-widget => $bind_category_tile_cb(template); unbind-widget => $unbind_category_tile_cb(template); } }; }; } }; } StackPage { name: "results"; child: Box content_box { orientation: horizontal; visible: bind $invert_boolean($is_null(grid_view.model as .selected-item) as ) as ; ScrolledWindow entry_grid_scroll { hexpand: true; vexpand: true; hscrollbar-policy: never; child: Adw.ClampScrollable clamp_scrollable { maximum-size: 1000; tightening-threshold: 900; child: GridView grid_view { styles [ "search-grid", ] min-columns: 3; max-columns: 3; factory: BuilderListItemFactory { template ListItem { child: Box { orientation: vertical; spacing: 5; $BzRichAppTile { group: bind template.item as <$BzSearchResult>.group as <$BzEntryGroup>; activated => $tile_activated_cb(template); } Box { styles [ "bz-debug", ] visible: bind template.item as <$BzSearchResult>.state as <$BzStateInfo>.debug_mode; orientation: vertical; spacing: 2; Box { orientation: horizontal; spacing: 10; Label { label: "Result Score:"; } Label { styles [ "caption-heading", ] label: bind $format_double(template.item as <$BzSearchResult>.score as ) as ; } } Separator { margin-bottom: 5; } Box { orientation: horizontal; spacing: 10; Label { styles [ "bz-monospace", ] hexpand: true; xalign: 0.0; label: bind template.item as <$BzSearchResult>.group as <$BzEntryGroup>.id; selectable: true; wrap: true; wrap-mode: char; } Button { icon-name: "edit-copy-symbolic"; clicked => $copy_id_cb(template); } } Box { orientation: horizontal; spacing: 10; Button { hexpand: true; halign: end; label: "Inspect UI Entry"; clicked => $debug_id_inspect_cb(template); } } } }; } }; }; }; } }; } StackPage { name: "no-results"; child: Adw.StatusPage { vexpand: true; icon-name: "edit-find-symbolic"; title: _("No Applications Found"); description: bind $no_results_found_subtitle(search_bar.text) as ; }; } } }; }; } bazaar-orig-v0.7.14/src/bz-tag-list.c0000664000175000017500000002522715166123241016240 0ustar hasanhasan/* bz-tag-list.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include #include "bz-apps-page.h" #include "bz-flathub-state.h" #include "bz-tag-list.h" #include "bz-util.h" #include "bz-window.h" struct _BzTagList { GtkBox parent_instance; GListModel *model; GtkWidget *prefix; BzFlathubState *flathub_state; DexFuture *task; }; G_DEFINE_FINAL_TYPE (BzTagList, bz_tag_list, GTK_TYPE_BOX); enum { PROP_0, PROP_MODEL, PROP_PREFIX, PROP_FLATHUB_STATE, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static DexFuture * search_finally (DexFuture *future, GWeakRef *wr) { g_autoptr (BzTagList) self = NULL; g_autoptr (GError) local_error = NULL; GtkRoot *root = NULL; const GValue *value = NULL; bz_weak_get_or_return_reject (self, wr); root = gtk_widget_get_root (GTK_WIDGET (self)); value = dex_future_get_value (future, &local_error); if (value != NULL) { GListModel *model = NULL; guint n_items = 0; model = g_value_get_object (value); n_items = g_list_model_get_n_items (model); if (n_items <= 1) { AdwToast *toast = adw_toast_new (_ ("No Results Found")); bz_window_add_toast (BZ_WINDOW (root), toast); } else { const char *tag = NULL; g_autofree char *title = NULL; g_autofree char *subtitle = NULL; AdwNavigationPage *apps_page = NULL; GtkWidget *nav_view = NULL; tag = g_object_get_data (G_OBJECT (self), "current-tag"); title = g_strdup_printf (_ ("Apps Tagged \"%s\""), tag); subtitle = g_strdup_printf (_ ("%d Applications"), n_items); apps_page = bz_apps_page_new (title, model); bz_apps_page_set_subtitle (BZ_APPS_PAGE (apps_page), subtitle); nav_view = gtk_widget_get_ancestor (GTK_WIDGET (self), ADW_TYPE_NAVIGATION_VIEW); adw_navigation_view_push (ADW_NAVIGATION_VIEW (nav_view), apps_page); } } else { AdwToast *toast = adw_toast_new (_ ("Search failed")); bz_window_add_toast (BZ_WINDOW (root), toast); g_warning ("Search failed: %s", local_error->message); } dex_clear (&self->task); return dex_future_new_true (); } static void tag_button_clicked_cb (BzTagList *self, GtkButton *button) { g_autoptr (BzResult) result = NULL; g_autoptr (DexFuture) future = NULL; const char *tag = NULL; g_autofree char *route = NULL; g_return_if_fail (BZ_IS_TAG_LIST (self)); g_return_if_fail (GTK_IS_BUTTON (button)); if (self->flathub_state == NULL) return; if (self->task != NULL) return; tag = gtk_button_get_label (button); if (tag == NULL || *tag == '\0') return; g_object_set_data_full (G_OBJECT (self), "current-tag", g_strdup (tag), g_free); route = g_strdup_printf ("/collection/keyword?keyword=%s", tag); future = bz_flathub_state_search_collection (self->flathub_state, route); future = dex_future_finally ( future, (DexFutureCallback) search_finally, bz_track_weak (self), bz_weak_release); self->task = g_steal_pointer (&future); } static void rebuild_tags (BzTagList *self) { GtkWidget *child; guint n_items; dex_clear (&self->task); while ((child = gtk_widget_get_first_child (GTK_WIDGET (self))) != NULL) { if (child == self->prefix) { child = gtk_widget_get_next_sibling (child); if (child == NULL) break; } gtk_box_remove (GTK_BOX (self), child); } if (self->model == NULL) { gtk_widget_set_visible (GTK_WIDGET (self), FALSE); return; } n_items = g_list_model_get_n_items (self->model); if (n_items == 0) { gtk_widget_set_visible (GTK_WIDGET (self), FALSE); return; } gtk_widget_set_visible (GTK_WIDGET (self), TRUE); for (guint i = 0; i < n_items; i++) { g_autoptr (GtkStringObject) item = NULL; const char *tag; GtkWidget *button; item = g_list_model_get_item (self->model, i); if (item == NULL) continue; tag = gtk_string_object_get_string (item); if (tag == NULL || *tag == '\0') continue; button = gtk_button_new_with_label (tag); gtk_widget_add_css_class (button, "small-pill"); g_signal_connect_swapped (button, "clicked", G_CALLBACK (tag_button_clicked_cb), self); gtk_box_append (GTK_BOX (self), button); } } static void on_items_changed (BzTagList *self, guint position, guint removed, guint added, GListModel *model) { rebuild_tags (self); } static void bz_tag_list_dispose (GObject *object) { BzTagList *self = BZ_TAG_LIST (object); dex_clear (&self->task); if (self->model != NULL) g_signal_handlers_disconnect_by_func (self->model, on_items_changed, self); g_clear_object (&self->model); g_clear_object (&self->flathub_state); g_clear_pointer (&self->prefix, gtk_widget_unparent); G_OBJECT_CLASS (bz_tag_list_parent_class)->dispose (object); } static void bz_tag_list_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzTagList *self = BZ_TAG_LIST (object); switch (prop_id) { case PROP_MODEL: g_value_set_object (value, bz_tag_list_get_model (self)); break; case PROP_PREFIX: g_value_set_object (value, bz_tag_list_get_prefix (self)); break; case PROP_FLATHUB_STATE: g_value_set_object (value, bz_tag_list_get_flathub_state (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_tag_list_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzTagList *self = BZ_TAG_LIST (object); switch (prop_id) { case PROP_MODEL: bz_tag_list_set_model (self, g_value_get_object (value)); break; case PROP_PREFIX: bz_tag_list_set_prefix (self, g_value_get_object (value)); break; case PROP_FLATHUB_STATE: bz_tag_list_set_flathub_state (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_tag_list_class_init (BzTagListClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bz_tag_list_set_property; object_class->get_property = bz_tag_list_get_property; object_class->dispose = bz_tag_list_dispose; props[PROP_MODEL] = g_param_spec_object ( "model", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_PREFIX] = g_param_spec_object ( "prefix", NULL, NULL, GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_FLATHUB_STATE] = g_param_spec_object ( "flathub-state", NULL, NULL, BZ_TYPE_FLATHUB_STATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_tag_list_init (BzTagList *self) { GtkLayoutManager *layout; gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_HORIZONTAL); gtk_widget_set_visible (GTK_WIDGET (self), FALSE); layout = GTK_LAYOUT_MANAGER (adw_wrap_layout_new ()); adw_wrap_layout_set_child_spacing (ADW_WRAP_LAYOUT (layout), 8); adw_wrap_layout_set_line_spacing (ADW_WRAP_LAYOUT (layout), 8); gtk_widget_set_layout_manager (GTK_WIDGET (self), layout); } GtkWidget * bz_tag_list_new (void) { return g_object_new (BZ_TYPE_TAG_LIST, NULL); } GListModel * bz_tag_list_get_model (BzTagList *self) { g_return_val_if_fail (BZ_IS_TAG_LIST (self), NULL); return self->model; } void bz_tag_list_set_model (BzTagList *self, GListModel *model) { g_return_if_fail (BZ_IS_TAG_LIST (self)); g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model)); if (self->model != NULL) g_signal_handlers_disconnect_by_func (self->model, on_items_changed, self); g_clear_object (&self->model); if (model != NULL) { self->model = g_object_ref (model); g_signal_connect_swapped ( self->model, "items-changed", G_CALLBACK (on_items_changed), self); } rebuild_tags (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MODEL]); } GtkWidget * bz_tag_list_get_prefix (BzTagList *self) { g_return_val_if_fail (BZ_IS_TAG_LIST (self), NULL); return self->prefix; } void bz_tag_list_set_prefix (BzTagList *self, GtkWidget *prefix) { g_return_if_fail (BZ_IS_TAG_LIST (self)); g_return_if_fail (prefix == NULL || GTK_IS_WIDGET (prefix)); if (self->prefix != NULL) gtk_widget_unparent (self->prefix); self->prefix = prefix; if (self->prefix != NULL) gtk_widget_set_parent (self->prefix, GTK_WIDGET (self)); rebuild_tags (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_PREFIX]); } BzFlathubState * bz_tag_list_get_flathub_state (BzTagList *self) { g_return_val_if_fail (BZ_IS_TAG_LIST (self), NULL); return self->flathub_state; } void bz_tag_list_set_flathub_state (BzTagList *self, BzFlathubState *flathub_state) { g_return_if_fail (BZ_IS_TAG_LIST (self)); g_return_if_fail (flathub_state == NULL || BZ_IS_FLATHUB_STATE (flathub_state)); g_clear_object (&self->flathub_state); if (flathub_state != NULL) self->flathub_state = g_object_ref (flathub_state); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_FLATHUB_STATE]); } bazaar-orig-v0.7.14/src/bz-global-progress.h0000664000175000017500000000373015166123241017616 0ustar hasanhasan/* bz-global-progress.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-state-info.h" G_BEGIN_DECLS #define BZ_TYPE_GLOBAL_PROGRESS (bz_global_progress_get_type ()) G_DECLARE_FINAL_TYPE (BzGlobalProgress, bz_global_progress, BZ, GLOBAL_PROGRESS, AdwBin) GtkWidget * bz_global_progress_new (void); void bz_global_progress_set_active (BzGlobalProgress *self, gboolean active); gboolean bz_global_progress_get_active (BzGlobalProgress *self); void bz_global_progress_set_pending (BzGlobalProgress *self, gboolean pending); gboolean bz_global_progress_get_pending (BzGlobalProgress *self); void bz_global_progress_set_expand_size (BzGlobalProgress *self, int expand_size); int bz_global_progress_get_expand_size (BzGlobalProgress *self); void bz_global_progress_set_state (BzGlobalProgress *self, BzStateInfo *state); BzStateInfo * bz_global_progress_get_state (BzGlobalProgress *self); void bz_global_progress_set_settings (BzGlobalProgress *self, GSettings *settings); GSettings * bz_global_progress_get_settings (BzGlobalProgress *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-row-view.blp0000664000175000017500000000060515166123241016617 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzRowView: Adw.Bin { child: $BzDynamicListView { hexpand: true; scroll: false; noscroll-kind: h-box; child-type: "BzSectionView"; child-prop: "section"; bind-widget => $bind_section_view_cb(template); unbind-widget => $unbind_section_view_cb(template); model: bind template.row as <$BzCuratedRow>.sections; }; } bazaar-orig-v0.7.14/src/bz-install-controls.c0000664000175000017500000002546615166123241020030 0ustar hasanhasan/* bz-install-controls.c * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include "bz-install-controls.h" #include "bz-state-info.h" #include "bz-template-callbacks.h" #include "bz-util.h" struct _BzInstallControls { GtkBox parent_instance; BzEntryGroup *group; BzStateInfo *state; gboolean wide; /* Template widgets */ GtkWidget *open_button; GtkWidget *install_button; }; G_DEFINE_FINAL_TYPE (BzInstallControls, bz_install_controls, GTK_TYPE_BOX) enum { PROP_0, PROP_WIDE, PROP_ENTRY_GROUP, PROP_STATE, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; enum { SIGNAL_UPDATE, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL]; static void install_cb (BzInstallControls *self, GtkButton *button) { if (self->group == NULL) return; gtk_widget_activate_action (GTK_WIDGET (self), "window.install-group", "(sb)", bz_entry_group_get_id (self->group), TRUE); } static void remove_cb (BzInstallControls *self, GtkButton *button) { if (self->group == NULL) return; gtk_widget_activate_action (GTK_WIDGET (self), "window.remove-group", "(sb)", bz_entry_group_get_id (self->group), TRUE); } static void run_cb (BzInstallControls *self, GtkButton *button) { if (self->group == NULL) return; gtk_widget_activate_action (GTK_WIDGET (self), "window.launch-group", "s", bz_entry_group_get_id (self->group)); } static GListStore * find_matching_updates (BzInstallControls *self, GListModel *available_updates) { const char *group_id = NULL; guint n_items = 0; GListStore *store = NULL; if (self->group == NULL || available_updates == NULL) return NULL; group_id = bz_entry_group_get_id (self->group); n_items = g_list_model_get_n_items (available_updates); store = g_list_store_new (BZ_TYPE_ENTRY); for (guint i = 0; i < n_items; i++) { g_autoptr (BzEntry) entry = NULL; const char *id = NULL; entry = g_list_model_get_item (available_updates, i); id = bz_entry_get_id (entry); if (g_strcmp0 (id, group_id) == 0) g_list_store_append (store, entry); } if (g_list_model_get_n_items (G_LIST_MODEL (store)) == 0) g_clear_object (&store); return store; } static void update_cb (BzInstallControls *self, GtkButton *button) { GListModel *available_updates = NULL; g_autoptr (GListStore) store = NULL; if (self->state == NULL) return; available_updates = bz_state_info_get_available_updates (self->state); store = find_matching_updates (self, available_updates); if (store != NULL) g_signal_emit (self, signals[SIGNAL_UPDATE], 0, G_LIST_MODEL (store)); } static char * get_visible_page (gpointer object, int installable, int removable, GListModel *available_updates) { BzInstallControls *self = BZ_INSTALL_CONTROLS (object); g_autoptr (GListStore) store = NULL; if (removable > 0) { store = find_matching_updates (self, available_updates); return g_strdup (store != NULL ? "update" : "open"); } else if (installable > 0) return g_strdup ("install"); else return g_strdup ("empty"); } static gboolean is_blocked (gpointer object, GListModel *parental_blocked, BzEntryGroup *group) { const char *id = NULL; if (parental_blocked == NULL || group == NULL) return FALSE; id = bz_entry_group_get_id (group); if (id == NULL) return FALSE; for (guint i = 0; i < g_list_model_get_n_items (parental_blocked); i++) { g_autoptr (GtkStringObject) obj = g_list_model_get_item (parental_blocked, i); if (strstr (gtk_string_object_get_string (obj), id) != NULL) return TRUE; } return FALSE; } static gboolean idle_grab_focus (GWeakRef *wr) { g_autoptr (BzInstallControls) self = NULL; self = g_weak_ref_get (wr); if (self == NULL) goto done; if (gtk_widget_is_visible (GTK_WIDGET (self))) gtk_widget_grab_focus (self->group != NULL && bz_entry_group_get_removable (self->group) > 0 ? self->open_button : self->install_button); done: return G_SOURCE_REMOVE; } static void bz_install_controls_dispose (GObject *object) { BzInstallControls *self = BZ_INSTALL_CONTROLS (object); g_clear_object (&self->group); g_clear_object (&self->state); G_OBJECT_CLASS (bz_install_controls_parent_class)->dispose (object); } static void bz_install_controls_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzInstallControls *self = BZ_INSTALL_CONTROLS (object); switch (prop_id) { case PROP_WIDE: g_value_set_boolean (value, self->wide); break; case PROP_ENTRY_GROUP: g_value_set_object (value, self->group); break; case PROP_STATE: g_value_set_object (value, self->state); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_install_controls_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzInstallControls *self = BZ_INSTALL_CONTROLS (object); switch (prop_id) { case PROP_WIDE: bz_install_controls_set_wide (self, g_value_get_boolean (value)); break; case PROP_ENTRY_GROUP: bz_install_controls_set_entry_group (self, g_value_get_object (value)); break; case PROP_STATE: bz_install_controls_set_state (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_install_controls_class_init (BzInstallControlsClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_install_controls_dispose; object_class->get_property = bz_install_controls_get_property; object_class->set_property = bz_install_controls_set_property; props[PROP_WIDE] = g_param_spec_boolean ( "wide", NULL, NULL, TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_ENTRY_GROUP] = g_param_spec_object ( "entry-group", NULL, NULL, BZ_TYPE_ENTRY_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_STATE] = g_param_spec_object ( "state", NULL, NULL, BZ_TYPE_STATE_INFO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); signals[SIGNAL_UPDATE] = g_signal_new ( "update", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_LIST_MODEL); g_signal_set_va_marshaller ( signals[SIGNAL_UPDATE], G_TYPE_FROM_CLASS (klass), g_cclosure_marshal_VOID__OBJECTv); g_type_ensure (BZ_TYPE_ENTRY_GROUP); g_type_ensure (BZ_TYPE_STATE_INFO); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-install-controls.ui"); bz_widget_class_bind_all_util_callbacks (widget_class); gtk_widget_class_bind_template_child (widget_class, BzInstallControls, open_button); gtk_widget_class_bind_template_child (widget_class, BzInstallControls, install_button); gtk_widget_class_bind_template_callback (widget_class, install_cb); gtk_widget_class_bind_template_callback (widget_class, remove_cb); gtk_widget_class_bind_template_callback (widget_class, run_cb); gtk_widget_class_bind_template_callback (widget_class, update_cb); gtk_widget_class_bind_template_callback (widget_class, get_visible_page); gtk_widget_class_bind_template_callback (widget_class, is_blocked); } static void bz_install_controls_init (BzInstallControls *self) { self->wide = TRUE; gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_install_controls_new (void) { return g_object_new (BZ_TYPE_INSTALL_CONTROLS, NULL); } gboolean bz_install_controls_get_wide (BzInstallControls *self) { g_return_val_if_fail (BZ_IS_INSTALL_CONTROLS (self), FALSE); return self->wide; } void bz_install_controls_set_wide (BzInstallControls *self, gboolean wide) { g_return_if_fail (BZ_IS_INSTALL_CONTROLS (self)); wide = !!wide; if (self->wide == wide) return; self->wide = wide; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_WIDE]); } BzEntryGroup * bz_install_controls_get_entry_group (BzInstallControls *self) { g_return_val_if_fail (BZ_IS_INSTALL_CONTROLS (self), NULL); return self->group; } void bz_install_controls_set_entry_group (BzInstallControls *self, BzEntryGroup *group) { g_return_if_fail (BZ_IS_INSTALL_CONTROLS (self)); if (self->group == group) return; g_clear_object (&self->group); if (group != NULL) self->group = g_object_ref (group); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ENTRY_GROUP]); if (group != NULL) g_idle_add_full ( G_PRIORITY_DEFAULT_IDLE, (GSourceFunc) idle_grab_focus, bz_track_weak (self), bz_weak_release); } BzStateInfo * bz_install_controls_get_state (BzInstallControls *self) { g_return_val_if_fail (BZ_IS_INSTALL_CONTROLS (self), NULL); return self->state; } void bz_install_controls_set_state (BzInstallControls *self, BzStateInfo *state) { g_return_if_fail (BZ_IS_INSTALL_CONTROLS (self)); g_clear_object (&self->state); if (state != NULL) self->state = g_object_ref (state); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_STATE]); } bazaar-orig-v0.7.14/src/bz-serializable.h0000664000175000017500000000302615166123241017160 0ustar hasanhasan/* bz-serializable.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_SERIALIZABLE (bz_serializable_get_type ()) G_DECLARE_INTERFACE (BzSerializable, bz_serializable, BZ, SERIALIZABLE, GObject) struct _BzSerializableInterface { GTypeInterface parent_iface; void (*serialize) (BzSerializable *self, GVariantBuilder *builder); gboolean (*deserialize) (BzSerializable *self, GVariant *import, GError **error); }; void bz_serializable_serialize (BzSerializable *self, GVariantBuilder *builder); gboolean bz_serializable_deserialize (BzSerializable *self, GVariant *import, GError **error); G_END_DECLS bazaar-orig-v0.7.14/src/bz-favorites-tile.blp0000664000175000017500000001015115166123241017772 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzFavoritesTile: $BzListTile { accessibility { labelled-by: title_label; described-by: description_label; } child: Box { orientation: horizontal; spacing: 10; Picture icon_picture { margin-start: 10; margin-top: 10; margin-bottom: 10; height-request: 48; width-request: 48; paintable: bind template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable; visible: bind $invert_boolean($is_null(template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable) as ) as ; styles ["icon-dropshadow"] } Image fallback_icon { margin-start: 10; margin-top: 10; margin-bottom: 10; height-request: 48; width-request: 48; pixel-size: 48; icon-name: "application-x-executable"; visible: bind $is_null(template.group as <$BzEntryGroup>.ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable) as ; styles ["icon-dropshadow"] } Box { orientation: vertical; valign: center; spacing: 4; Label title_label { xalign: 0.0; ellipsize: end; single-line-mode: true; has-tooltip: true; tooltip-text: bind template.group as <$BzEntryGroup>.id; label: bind template.group as <$BzEntryGroup>.title; } Label description_label { halign: start; label: bind template.group as <$BzEntryGroup>.description; xalign: 0.0; ellipsize: end; single-line-mode: true; styles ["dim-label", "caption"] } } Button support_button { styles [ "circular", "flat", "suggested-action", "support" ] has-tooltip: true; tooltip-text: _("Support This Application"); width-request: 32; height-request: 32; valign: center; icon-name: "heart-filled-symbolic"; visible: bind $invert_boolean($is_null(template.group as <$BzEntryGroup>.donation-url) as ) as ; clicked => $support_cb() swapped; } Box { orientation: horizontal; spacing: 8; margin-end: 8; hexpand: true; halign: end; Button install_remove_button { styles [ "flat", ] width-request: 32; height-request: 32; valign: center; has-tooltip: true; visible: bind $invert_boolean($logical_and($is_zero(template.group as <$BzEntryGroup>.removable) as , $is_zero(template.group as <$BzEntryGroup>.installable) as ) as ) as ; tooltip-text: bind $get_install_remove_tooltip(template.group as <$BzEntryGroup>.removable) as ; sensitive: bind $switch_bool( template.group as <$BzEntryGroup>.removable, $invert_boolean($is_zero(template.group as <$BzEntryGroup>.removable-and-available) as ) as , $invert_boolean($is_zero(template.group as <$BzEntryGroup>.installable-and-available) as ) as , ) as ; icon-name: bind $get_install_remove_icon(template.group as <$BzEntryGroup>.removable) as ; clicked => $install_remove_cb() swapped; } Stack unfavorite_stack { transition-type: crossfade; StackPage { name: "button"; child: Button unfavorite_button { styles [ "flat", ] width-request: 32; height-request: 32; valign: center; has-tooltip: true; tooltip-text: _("Remove From Favorites"); icon-name: "bookmark-filled-symbolic"; clicked => $unfavorite_cb() swapped; }; } StackPage { name: "spinner"; child: Adw.Spinner { halign: center; width-request: 16; }; } } Image { pixel-size: 14; icon-name: "go-next-symbolic"; margin-end: 4; styles ["dimmed"] } } }; } bazaar-orig-v0.7.14/src/bz-blocklist.txt0000664000175000017500000000074015166123241017070 0ustar hasanhasanprefix=bz name=blocklist parent-prefix=g parent-name=object author=AUTOGEN include= include="bz-blocklist-condition.h" ensure=BZ_TYPE_BLOCKLIST_CONDITION property=priority int G_TYPE_INT int property=conditions GListModel G_TYPE_LIST_MODEL object property=allow GListModel G_TYPE_LIST_MODEL object property=allow_regex GListModel G_TYPE_LIST_MODEL object property=block GListModel G_TYPE_LIST_MODEL object property=block_regex GListModel G_TYPE_LIST_MODEL object bazaar-orig-v0.7.14/src/bz-hook-dialog.txt0000664000175000017500000000070415166123241017277 0ustar hasanhasanprefix=bz name=hook_dialog parent-prefix=g parent-name=object author=AUTOGEN include= include="bz-hook-dialog-option.h" ensure=BZ_TYPE_HOOK_DIALOG_OPTION property=id char G_TYPE_STRING string property=title char G_TYPE_STRING string property=body char G_TYPE_STRING string property=body_use_markup gboolean G_TYPE_BOOLEAN boolean property=options GListModel G_TYPE_LIST_MODEL object property=default_response_id char G_TYPE_STRING string bazaar-orig-v0.7.14/src/bz-themed-entry-group-rect.c0000664000175000017500000001706015166123241021202 0ustar hasanhasan/* bz-themed-entry-group-rect.c * * Copyright 2025 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-themed-entry-group-rect.h" struct _BzThemedEntryGroupRect { GtkWidget parent_instance; GtkWidget *child; BzEntryGroup *group; }; G_DEFINE_FINAL_TYPE (BzThemedEntryGroupRect, bz_themed_entry_group_rect, GTK_TYPE_WIDGET); enum { PROP_0, PROP_CHILD, PROP_GROUP, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bz_themed_entry_group_rect_dispose (GObject *object) { BzThemedEntryGroupRect *self = BZ_THEMED_ENTRY_GROUP_RECT (object); g_clear_pointer (&self->child, gtk_widget_unparent); g_clear_pointer (&self->group, g_object_unref); G_OBJECT_CLASS (bz_themed_entry_group_rect_parent_class)->dispose (object); } static void bz_themed_entry_group_rect_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzThemedEntryGroupRect *self = BZ_THEMED_ENTRY_GROUP_RECT (object); switch (prop_id) { case PROP_CHILD: g_value_set_object (value, bz_themed_entry_group_rect_get_child (self)); break; case PROP_GROUP: g_value_set_object (value, bz_themed_entry_group_rect_get_group (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_themed_entry_group_rect_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzThemedEntryGroupRect *self = BZ_THEMED_ENTRY_GROUP_RECT (object); switch (prop_id) { case PROP_CHILD: bz_themed_entry_group_rect_set_child (self, g_value_get_object (value)); break; case PROP_GROUP: bz_themed_entry_group_rect_set_group (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_themed_entry_group_rect_allocate (GtkWidget *widget, int width, int height, int baseline) { BzThemedEntryGroupRect *self = BZ_THEMED_ENTRY_GROUP_RECT (widget); if (self->child != NULL) gtk_widget_allocate (self->child, width, height, baseline, NULL); gtk_widget_queue_draw (widget); } static void bz_themed_entry_group_rect_snapshot (GtkWidget *widget, GtkSnapshot *snapshot) { BzThemedEntryGroupRect *self = BZ_THEMED_ENTRY_GROUP_RECT (widget); double widget_width = 0.0; double widget_height = 0.0; const char *light_color = NULL; const char *dark_color = NULL; GdkRGBA light_rgba = { 0 }; GdkRGBA dark_rgba = { 0 }; gboolean is_dark = FALSE; widget_width = (double) gtk_widget_get_width (widget); widget_height = (double) gtk_widget_get_height (widget); if (self->group != NULL) { light_color = bz_entry_group_get_light_accent_color (self->group); dark_color = bz_entry_group_get_dark_accent_color (self->group); } if (light_color != NULL) gdk_rgba_parse (&light_rgba, light_color); else gdk_rgba_parse (&light_rgba, "#ebebed"); if (dark_color != NULL) gdk_rgba_parse (&dark_rgba, dark_color); else gdk_rgba_parse (&dark_rgba, "#2e2e32"); is_dark = adw_style_manager_get_dark (adw_style_manager_get_default ()); gtk_snapshot_push_opacity (snapshot, 0.70); gtk_snapshot_append_color ( snapshot, is_dark ? &dark_rgba : &light_rgba, &GRAPHENE_RECT_INIT (0.0, 0.0, widget_width, widget_height)); gtk_snapshot_pop (snapshot); if (self->child != NULL) gtk_widget_snapshot_child (widget, self->child, snapshot); } static void bz_themed_entry_group_rect_class_init (BzThemedEntryGroupRectClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bz_themed_entry_group_rect_set_property; object_class->get_property = bz_themed_entry_group_rect_get_property; object_class->dispose = bz_themed_entry_group_rect_dispose; widget_class->size_allocate = bz_themed_entry_group_rect_allocate; widget_class->snapshot = bz_themed_entry_group_rect_snapshot; props[PROP_CHILD] = g_param_spec_object ( "child", NULL, NULL, GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_GROUP] = g_param_spec_object ( "group", NULL, NULL, BZ_TYPE_ENTRY_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); } static void dark_changed (BzThemedEntryGroupRect *self, GParamSpec *pspec, AdwStyleManager *mgr) { gtk_widget_queue_draw (GTK_WIDGET (self)); } static void bz_themed_entry_group_rect_init (BzThemedEntryGroupRect *self) { g_signal_connect_object ( adw_style_manager_get_default (), "notify::dark", G_CALLBACK (dark_changed), self, G_CONNECT_SWAPPED); } GtkWidget * bz_themed_entry_group_rect_new (void) { return g_object_new (BZ_TYPE_THEMED_ENTRY_GROUP_RECT, NULL); } BzEntryGroup * bz_themed_entry_group_rect_get_group (BzThemedEntryGroupRect *self) { g_return_val_if_fail (BZ_IS_THEMED_ENTRY_GROUP_RECT (self), NULL); return self->group; } void bz_themed_entry_group_rect_set_group (BzThemedEntryGroupRect *self, BzEntryGroup *group) { g_return_if_fail (BZ_IS_THEMED_ENTRY_GROUP_RECT (self)); g_clear_pointer (&self->group, g_object_unref); if (group != NULL) self->group = g_object_ref (group); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_GROUP]); } GtkWidget * bz_themed_entry_group_rect_get_child (BzThemedEntryGroupRect *self) { g_return_val_if_fail (BZ_IS_THEMED_ENTRY_GROUP_RECT (self), NULL); return self->child; } void bz_themed_entry_group_rect_set_child (BzThemedEntryGroupRect *self, GtkWidget *child) { g_return_if_fail (BZ_THEMED_ENTRY_GROUP_RECT (self)); g_return_if_fail (child == NULL || GTK_IS_WIDGET (child)); if (self->child == child) return; if (child != NULL) g_return_if_fail (gtk_widget_get_parent (child) == NULL); g_clear_pointer (&self->child, gtk_widget_unparent); self->child = child; if (child != NULL) gtk_widget_set_parent (child, GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CHILD]); } /* End of bz-themed-entry-group-rect.c */ bazaar-orig-v0.7.14/src/bz-result.h0000664000175000017500000000243315166123241016031 0ustar hasanhasan/* bz-result.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_RESULT (bz_result_get_type ()) G_DECLARE_FINAL_TYPE (BzResult, bz_result, BZ, RESULT, GObject) BzResult * bz_result_new (DexFuture *future); gboolean bz_result_get_pending (BzResult *self); gboolean bz_result_get_resolved (BzResult *self); gboolean bz_result_get_rejected (BzResult *self); gpointer bz_result_get_object (BzResult *self); const char * bz_result_get_message (BzResult *self); DexFuture * bz_result_dup_future (BzResult *self); G_END_DECLS /* End of bz-result.h */ bazaar-orig-v0.7.14/src/bz-updates-card.h0000664000175000017500000000226215166123241017067 0ustar hasanhasan/* bz-updates-card.h * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-state-info.h" #include G_BEGIN_DECLS #define BZ_TYPE_UPDATES_CARD (bz_updates_card_get_type ()) G_DECLARE_FINAL_TYPE (BzUpdatesCard, bz_updates_card, BZ, UPDATES_CARD, AdwBin) GtkWidget * bz_updates_card_new (void); void bz_updates_card_set_state (BzUpdatesCard *self, BzStateInfo *state); BzStateInfo * bz_updates_card_get_state (BzUpdatesCard *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-inhibited-scrollable.c0000664000175000017500000003470015166123241020567 0ustar hasanhasan/* bz-inhibited-scrollable.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ /* This is a complete hack but I * don't see any other way to prevent * the annoying jumping in GtkListView etc */ #include "config.h" #include "bz-inhibited-scrollable.h" struct _BzInhibitedScrollable { GtkWidget parent_instance; GtkScrollable *child; GtkScrollablePolicy hscroll_policy; GtkScrollablePolicy vscroll_policy; GtkAdjustment *hadjustment; GtkAdjustment *vadjustment; GtkAdjustment *child_hadjustment; GtkAdjustment *child_vadjustment; GBinding *hscroll_policy_bind; GBinding *vscroll_policy_bind; struct { GBinding *lower; GBinding *upper; GBinding *page_increment; GBinding *step_increment; GBinding *page_size; GBinding *value; } vadjustment_binds; struct { GBinding *lower; GBinding *upper; GBinding *page_increment; GBinding *step_increment; GBinding *page_size; GBinding *value; } hadjustment_binds; }; static void scrollable_iface_init (GtkScrollableInterface *iface); G_DEFINE_FINAL_TYPE_WITH_CODE ( BzInhibitedScrollable, bz_inhibited_scrollable, GTK_TYPE_WIDGET, G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, scrollable_iface_init)) enum { PROP_0, PROP_SCROLLABLE, LAST_PROP, PROP_HADJUSTMENT, PROP_VADJUSTMENT, PROP_HSCROLL_POLICY, PROP_VSCROLL_POLICY, }; static GParamSpec *props[LAST_PROP] = { 0 }; static void child_adjustment_value_changed (BzInhibitedScrollable *self, GtkAdjustment *adjustment); static void setup_hadjustments (BzInhibitedScrollable *self); static void setup_vadjustments (BzInhibitedScrollable *self); static void clear_bindings (BzInhibitedScrollable *self); static void bz_inhibited_scrollable_dispose (GObject *object) { BzInhibitedScrollable *self = BZ_INHIBITED_SCROLLABLE (object); clear_bindings (self); g_clear_object (&self->hadjustment); g_clear_object (&self->vadjustment); g_clear_pointer ((GtkWidget **) &self->child, gtk_widget_unparent); G_OBJECT_CLASS (bz_inhibited_scrollable_parent_class)->dispose (object); } static void bz_inhibited_scrollable_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzInhibitedScrollable *self = BZ_INHIBITED_SCROLLABLE (object); switch (prop_id) { case PROP_SCROLLABLE: g_value_set_object (value, bz_inhibited_scrollable_get_scrollable (self)); break; case PROP_HADJUSTMENT: g_value_set_object (value, self->hadjustment); break; case PROP_VADJUSTMENT: g_value_set_object (value, self->vadjustment); break; case PROP_HSCROLL_POLICY: g_value_set_enum (value, self->hscroll_policy); break; case PROP_VSCROLL_POLICY: g_value_set_enum (value, self->vscroll_policy); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_inhibited_scrollable_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzInhibitedScrollable *self = BZ_INHIBITED_SCROLLABLE (object); switch (prop_id) { case PROP_SCROLLABLE: bz_inhibited_scrollable_set_scrollable (self, g_value_get_object (value)); break; case PROP_HADJUSTMENT: g_clear_object (&self->hadjustment); self->hadjustment = g_value_dup_object (value); setup_hadjustments (self); break; case PROP_VADJUSTMENT: g_clear_object (&self->vadjustment); self->vadjustment = g_value_dup_object (value); setup_vadjustments (self); break; case PROP_HSCROLL_POLICY: self->hscroll_policy = g_value_get_enum (value); break; case PROP_VSCROLL_POLICY: self->vscroll_policy = g_value_get_enum (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_inhibited_scrollable_size_allocate (GtkWidget *widget, int width, int height, int baseline) { BzInhibitedScrollable *self = BZ_INHIBITED_SCROLLABLE (widget); if (self->child != NULL && gtk_widget_should_layout (GTK_WIDGET (self->child))) gtk_widget_allocate (GTK_WIDGET (self->child), width, height, baseline, NULL); } static void bz_inhibited_scrollable_class_init (BzInhibitedScrollableClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_inhibited_scrollable_dispose; object_class->get_property = bz_inhibited_scrollable_get_property; object_class->set_property = bz_inhibited_scrollable_set_property; props[PROP_SCROLLABLE] = g_param_spec_object ( "scrollable", NULL, NULL, GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); g_object_class_override_property (object_class, PROP_HADJUSTMENT, "hadjustment"); g_object_class_override_property (object_class, PROP_VADJUSTMENT, "vadjustment"); g_object_class_override_property (object_class, PROP_HSCROLL_POLICY, "hscroll-policy"); g_object_class_override_property (object_class, PROP_VSCROLL_POLICY, "vscroll-policy"); widget_class->size_allocate = bz_inhibited_scrollable_size_allocate; } static void bz_inhibited_scrollable_init (BzInhibitedScrollable *self) { } static gboolean scrollable_get_border (GtkScrollable *scrollable, GtkBorder *border) { BzInhibitedScrollable *self = BZ_INHIBITED_SCROLLABLE (scrollable); if (self->child != NULL) return gtk_scrollable_get_border (self->child, border); else return FALSE; } static void scrollable_iface_init (GtkScrollableInterface *iface) { iface->get_border = scrollable_get_border; } GtkWidget * bz_inhibited_scrollable_new (void) { return g_object_new (BZ_TYPE_INHIBITED_SCROLLABLE, NULL); } void bz_inhibited_scrollable_set_scrollable (BzInhibitedScrollable *self, GtkScrollable *child) { g_return_if_fail (BZ_IS_INHIBITED_SCROLLABLE (self)); g_return_if_fail (child == NULL || GTK_IS_SCROLLABLE (child)); if (self->child == child) return; if (child != NULL) g_return_if_fail (gtk_widget_get_parent (GTK_WIDGET (child)) == NULL); clear_bindings (self); g_clear_pointer ((GtkWidget **) &self->child, gtk_widget_unparent); self->child = child; if (child != NULL) { gtk_widget_set_parent (GTK_WIDGET (child), GTK_WIDGET (self)); self->hscroll_policy_bind = g_object_bind_property ( self, "hscroll-policy", self->child, "hscroll-policy", G_BINDING_SYNC_CREATE); self->vscroll_policy_bind = g_object_bind_property ( self, "vscroll-policy", self->child, "vscroll-policy", G_BINDING_SYNC_CREATE); setup_hadjustments (self); setup_vadjustments (self); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SCROLLABLE]); } GtkScrollable * bz_inhibited_scrollable_get_scrollable (BzInhibitedScrollable *self) { g_return_val_if_fail (BZ_IS_INHIBITED_SCROLLABLE (self), NULL); return self->child; } static void child_adjustment_value_changed (BzInhibitedScrollable *self, GtkAdjustment *adjustment) { GtkAdjustment *parent_adjustment = NULL; double child_value = 0.0; double forced_value = 0.0; if (adjustment == self->child_vadjustment) parent_adjustment = self->vadjustment; else parent_adjustment = self->hadjustment; child_value = gtk_adjustment_get_value (adjustment); forced_value = gtk_adjustment_get_value (parent_adjustment); if (child_value != forced_value) gtk_adjustment_set_value (adjustment, forced_value); } static void setup_hadjustments (BzInhibitedScrollable *self) { g_clear_object (&self->hadjustment_binds.lower); g_clear_object (&self->hadjustment_binds.upper); g_clear_object (&self->hadjustment_binds.page_increment); g_clear_object (&self->hadjustment_binds.step_increment); g_clear_object (&self->hadjustment_binds.page_size); g_clear_object (&self->hadjustment_binds.value); if (self->child_hadjustment != NULL) g_signal_handlers_disconnect_by_func ( self->child_hadjustment, child_adjustment_value_changed, self); g_clear_object (&self->child_hadjustment); if (self->child != NULL && self->hadjustment != NULL) { self->child_hadjustment = g_object_ref_sink (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); g_signal_connect_swapped (self->child_hadjustment, "value-changed", G_CALLBACK (child_adjustment_value_changed), self); self->hadjustment_binds.lower = g_object_bind_property ( self->hadjustment, "lower", self->child_hadjustment, "lower", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); self->hadjustment_binds.upper = g_object_bind_property ( self->hadjustment, "upper", self->child_hadjustment, "upper", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); self->hadjustment_binds.page_increment = g_object_bind_property ( self->hadjustment, "page-increment", self->child_hadjustment, "page-increment", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); self->hadjustment_binds.step_increment = g_object_bind_property ( self->hadjustment, "step-increment", self->child_hadjustment, "step-increment", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); self->hadjustment_binds.page_size = g_object_bind_property ( self->hadjustment, "page-size", self->child_hadjustment, "page-size", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); self->hadjustment_binds.value = g_object_bind_property ( self->hadjustment, "value", self->child_hadjustment, "value", G_BINDING_SYNC_CREATE); gtk_scrollable_set_hadjustment (self->child, self->child_hadjustment); } } static void setup_vadjustments (BzInhibitedScrollable *self) { g_clear_object (&self->vadjustment_binds.lower); g_clear_object (&self->vadjustment_binds.upper); g_clear_object (&self->vadjustment_binds.page_increment); g_clear_object (&self->vadjustment_binds.step_increment); g_clear_object (&self->vadjustment_binds.page_size); g_clear_object (&self->vadjustment_binds.value); if (self->child_vadjustment != NULL) g_signal_handlers_disconnect_by_func ( self->child_vadjustment, child_adjustment_value_changed, self); g_clear_object (&self->child_vadjustment); if (self->child != NULL && self->vadjustment != NULL) { self->child_vadjustment = g_object_ref_sink (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); g_signal_connect_swapped (self->child_vadjustment, "value-changed", G_CALLBACK (child_adjustment_value_changed), self); self->vadjustment_binds.lower = g_object_bind_property ( self->vadjustment, "lower", self->child_vadjustment, "lower", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); self->vadjustment_binds.upper = g_object_bind_property ( self->vadjustment, "upper", self->child_vadjustment, "upper", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); self->vadjustment_binds.page_increment = g_object_bind_property ( self->vadjustment, "page-increment", self->child_vadjustment, "page-increment", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); self->vadjustment_binds.step_increment = g_object_bind_property ( self->vadjustment, "step-increment", self->child_vadjustment, "step-increment", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); self->vadjustment_binds.page_size = g_object_bind_property ( self->vadjustment, "page-size", self->child_vadjustment, "page-size", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); self->vadjustment_binds.value = g_object_bind_property ( self->vadjustment, "value", self->child_vadjustment, "value", G_BINDING_SYNC_CREATE); gtk_scrollable_set_vadjustment (self->child, self->child_vadjustment); } } static void clear_bindings (BzInhibitedScrollable *self) { g_clear_object (&self->hscroll_policy_bind); g_clear_object (&self->vscroll_policy_bind); g_clear_object (&self->hadjustment_binds.lower); g_clear_object (&self->hadjustment_binds.upper); g_clear_object (&self->hadjustment_binds.page_increment); g_clear_object (&self->hadjustment_binds.step_increment); g_clear_object (&self->hadjustment_binds.page_size); g_clear_object (&self->hadjustment_binds.value); g_clear_object (&self->vadjustment_binds.lower); g_clear_object (&self->vadjustment_binds.upper); g_clear_object (&self->vadjustment_binds.page_increment); g_clear_object (&self->vadjustment_binds.step_increment); g_clear_object (&self->vadjustment_binds.page_size); g_clear_object (&self->vadjustment_binds.value); if (self->child_hadjustment != NULL) g_signal_handlers_disconnect_by_func ( self->child_hadjustment, child_adjustment_value_changed, self); g_clear_object (&self->child_hadjustment); if (self->child_vadjustment != NULL) g_signal_handlers_disconnect_by_func ( self->child_vadjustment, child_adjustment_value_changed, self); g_clear_object (&self->child_vadjustment); } bazaar-orig-v0.7.14/src/bz-rich-app-tile.h0000664000175000017500000000244015166123241017147 0ustar hasanhasan/* bz-rich-app-tile.h * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "adwaita.h" #include #include "bz-entry-group.h" #include "bz-list-tile.h" G_BEGIN_DECLS #define BZ_TYPE_RICH_APP_TILE (bz_rich_app_tile_get_type ()) G_DECLARE_FINAL_TYPE (BzRichAppTile, bz_rich_app_tile, BZ, RICH_APP_TILE, BzListTile) GtkWidget * bz_rich_app_tile_new (void); BzEntryGroup * bz_rich_app_tile_get_group (BzRichAppTile *self); void bz_rich_app_tile_set_group (BzRichAppTile *self, BzEntryGroup *group); G_END_DECLS /* End of bz-rich-app-tile.h */ bazaar-orig-v0.7.14/src/bz-lozenge.h0000664000175000017500000000313015166123241016151 0ustar hasanhasan/* bz-lozenge.h * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-context-row.h" #include G_BEGIN_DECLS #define BZ_TYPE_LOZENGE (bz_lozenge_get_type ()) G_DECLARE_FINAL_TYPE (BzLozenge, bz_lozenge, BZ, LOZENGE, GtkBox) GtkWidget *bz_lozenge_new (void); void bz_lozenge_set_title (BzLozenge *self, const gchar *title); const gchar * bz_lozenge_get_title (BzLozenge *self); void bz_lozenge_set_label (BzLozenge *self, const gchar *label); const gchar * bz_lozenge_get_label (BzLozenge *self); void bz_lozenge_set_icon_names (BzLozenge *self, const gchar *const *icon_names); gchar ** bz_lozenge_get_icon_names (BzLozenge *self); void bz_lozenge_set_importance (BzLozenge *self, BzImportance importance); BzImportance bz_lozenge_get_importance (BzLozenge *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-spdx.h0000664000175000017500000000200315166123241015462 0ustar hasanhasan/* bz-spdx.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS gboolean bz_spdx_is_valid (const char *license_id); char * bz_spdx_get_url (const char *license_id); char * bz_spdx_get_name (const char *license_id); gboolean bz_spdx_is_proprietary (const char *license_id); G_END_DECLS bazaar-orig-v0.7.14/src/bz-world-map-parser.c0000664000175000017500000000773115166123241017710 0ustar hasanhasan/* bz-world-map-parser.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-country.h" #include "bz-world-map-parser.h" struct _BzWorldMapParser { GObject parent_instance; GListStore *countries; }; G_DEFINE_FINAL_TYPE (BzWorldMapParser, bz_world_map_parser, G_TYPE_OBJECT) static const char *get_translated_name (GVariant *translations, const char *fallback_name); static void bz_world_map_parser_dispose (GObject *object) { BzWorldMapParser *self = BZ_WORLD_MAP_PARSER (object); g_clear_object (&self->countries); G_OBJECT_CLASS (bz_world_map_parser_parent_class)->dispose (object); } static void bz_world_map_parser_class_init (BzWorldMapParserClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = bz_world_map_parser_dispose; } static void bz_world_map_parser_init (BzWorldMapParser *self) { self->countries = g_list_store_new (BZ_TYPE_COUNTRY); } BzWorldMapParser * bz_world_map_parser_new (void) { return g_object_new (BZ_TYPE_WORLD_MAP_PARSER, NULL); } gboolean bz_world_map_parser_load_from_resource (BzWorldMapParser *self, const char *resource_path, GError **error) { g_autoptr (GBytes) bytes = NULL; g_autoptr (GVariant) data = NULL; GVariantIter iter = { 0 }; const char *name = NULL; const char *iso_code = NULL; GVariant *translations = NULL; GVariant *coordinates = NULL; g_return_val_if_fail (BZ_IS_WORLD_MAP_PARSER (self), FALSE); g_return_val_if_fail (resource_path != NULL, FALSE); bytes = g_resources_lookup_data (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, error); if (bytes == NULL) return FALSE; data = g_variant_new_from_bytes (G_VARIANT_TYPE ("a(ssa{ss}aaa(dd))"), bytes, TRUE); g_list_store_remove_all (self->countries); g_variant_iter_init (&iter, data); while (g_variant_iter_next (&iter, "(&s&s@a{ss}@aaa(dd))", &name, &iso_code, &translations, &coordinates)) { g_autoptr (BzCountry) country = NULL; const char *display_name = NULL; display_name = get_translated_name (translations, name); country = bz_country_new (); bz_country_set_name (country, display_name); bz_country_set_iso_code (country, iso_code); bz_country_set_coordinates (country, coordinates); g_list_store_append (self->countries, country); g_variant_unref (translations); g_variant_unref (coordinates); } return TRUE; } GListModel * bz_world_map_parser_get_countries (BzWorldMapParser *self) { g_return_val_if_fail (BZ_IS_WORLD_MAP_PARSER (self), NULL); return G_LIST_MODEL (self->countries); } static const char * get_translated_name (GVariant *translations, const char *fallback_name) { const char *const *language_names = NULL; language_names = g_get_language_names (); for (guint i = 0; language_names[i] != NULL; i++) { const char *translated = NULL; if (g_variant_lookup (translations, language_names[i], "&s", &translated)) return translated; } return fallback_name; } bazaar-orig-v0.7.14/src/bz-world-map.h0000664000175000017500000000216215166123241016414 0ustar hasanhasan/* bz-world-map.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_WORLD_MAP (bz_world_map_get_type ()) G_DECLARE_FINAL_TYPE (BzWorldMap, bz_world_map, BZ, WORLD_MAP, GtkWidget) GtkWidget * bz_world_map_new (void); GListModel * bz_world_map_get_model (BzWorldMap *self); void bz_world_map_set_model (BzWorldMap *self, GListModel *model); G_END_DECLS bazaar-orig-v0.7.14/src/bz-full-view.h0000664000175000017500000000307615166123241016431 0ustar hasanhasan/* bz-full-view.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-entry-group.h" #include "bz-transaction-manager.h" G_BEGIN_DECLS #define BZ_TYPE_FULL_VIEW (bz_full_view_get_type ()) G_DECLARE_FINAL_TYPE (BzFullView, bz_full_view, BZ, FULL_VIEW, AdwBin) GtkWidget * bz_full_view_new (void); void bz_full_view_set_transaction_manager (BzFullView *self, BzTransactionManager *group); BzTransactionManager * bz_full_view_get_transaction_manager (BzFullView *self); void bz_full_view_set_entry_group (BzFullView *self, BzEntryGroup *group); BzEntryGroup * bz_full_view_get_entry_group (BzFullView *self); void bz_full_view_set_debounce (BzFullView *self, gboolean debounce); gboolean bz_full_view_get_debounce (BzFullView *self); G_END_DECLS bazaar-orig-v0.7.14/src/shell-search-provider-dbus-interfaces.xml0000664000175000017500000000350315166123241023730 0ustar hasanhasan bazaar-orig-v0.7.14/src/bz-donations-dialog.h0000664000175000017500000000210215166123241017737 0ustar hasanhasan/* bz-donations-dialog.h * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-state-info.h" G_BEGIN_DECLS #define BZ_TYPE_DONATIONS_DIALOG (bz_donations_dialog_get_type ()) G_DECLARE_FINAL_TYPE (BzDonationsDialog, bz_donations_dialog, BZ, DONATIONS_DIALOG, AdwDialog) AdwDialog * bz_donations_dialog_new (void); G_END_DECLS /* End of bz-donations-dialog.h */ bazaar-orig-v0.7.14/src/bz-app-size-dialog.h0000664000175000017500000000217615166123241017504 0ustar hasanhasan/* bz-app-size-dialog.h * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry-group.h" #include G_BEGIN_DECLS #define BZ_TYPE_APP_SIZE_DIALOG (bz_app_size_dialog_get_type ()) G_DECLARE_FINAL_TYPE (BzAppSizeDialog, bz_app_size_dialog, BZ, APP_SIZE_DIALOG, AdwBin) AdwDialog * bz_app_size_dialog_new (BzEntryGroup *group); AdwNavigationPage * bz_app_size_page_new (BzEntryGroup *group); G_END_DECLS bazaar-orig-v0.7.14/src/bz-login-page.h0000664000175000017500000000204115166123241016530 0ustar hasanhasan/* bz-login-page.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-auth-state.h" #include G_BEGIN_DECLS #define BZ_TYPE_LOGIN_PAGE (bz_login_page_get_type ()) G_DECLARE_FINAL_TYPE (BzLoginPage, bz_login_page, BZ, LOGIN_PAGE, AdwNavigationPage) AdwNavigationPage *bz_login_page_new (BzAuthState *auth_state); G_END_DECLS bazaar-orig-v0.7.14/src/bz-safety-calculator.c0000664000175000017500000006277115166123241020143 0ustar hasanhasan/* bz-safety-calculator.c * * Copyright 2026 Alexander Vanhee * Copyright (C) 2022 Red Hat * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include "bz-app-permissions.h" #include "bz-context-row.h" #include "bz-safety-calculator.h" #include "bz-safety-row.h" static char * format_bus_policy_title (const BzBusPolicy *bus_policy); static const char * format_bus_policy_subtitle (const BzBusPolicy *bus_policy); static void add_row_if_permission (GListStore *store, gboolean has_permission, BzImportance item_rating, const char *icon_name_with_permission, const char *title_with_permission, const char *description_with_permission, const char *icon_name_without_permission, const char *title_without_permission, const char *description_without_permission); static gboolean lookup_well_known_bus_policy (const char *bus_name, const char **out_title, const char **out_description); GListModel * bz_safety_calculator_analyze_entry (BzEntry *entry) { GListStore *store = NULL; BzAppPermissions *permissions = NULL; BzAppPermissionsFlags perm_flags = BZ_APP_PERMISSIONS_FLAGS_NONE; gboolean is_verified = FALSE; gboolean is_foss = FALSE; const GPtrArray *filesystem_read = NULL; const GPtrArray *filesystem_full = NULL; const BzBusPolicy *const *bus_policies = NULL; size_t n_bus_policies = 0; gboolean has_system_tray = FALSE; guint i = 0; g_return_val_if_fail (BZ_IS_ENTRY (entry), NULL); store = g_list_store_new (BZ_TYPE_SAFETY_ROW); is_verified = bz_entry_is_verified (entry); is_foss = bz_entry_get_is_foss (entry); g_object_get (entry, "permissions", &permissions, NULL); if (permissions != NULL) perm_flags = bz_app_permissions_get_flags (permissions); if (permissions == NULL) { add_row_if_permission (store, TRUE, BZ_IMPORTANCE_WARNING, "channel-insecure-symbolic", _ ("Unknown Permissions"), _ ("Permissions are missing for this app."), NULL, NULL, NULL); } else { filesystem_read = bz_app_permissions_get_filesystem_read (permissions); filesystem_full = bz_app_permissions_get_filesystem_full (permissions); bus_policies = bz_app_permissions_get_bus_policies (permissions, &n_bus_policies); add_row_if_permission (store, bz_app_permissions_is_empty (permissions), BZ_IMPORTANCE_UNIMPORTANT, "permissions-sandboxed-symbolic", _ ("No Permissions"), _ ("App is fully sandboxed"), NULL, NULL, NULL); add_row_if_permission (store, (perm_flags & BZ_APP_PERMISSIONS_FLAGS_NETWORK) != 0, BZ_IMPORTANCE_INFORMATION, "network-wireless-symbolic", _ ("Network Access"), _ ("Can access the internet"), "network-wireless-disabled-symbolic", _ ("No Network Access"), _ ("Cannot access the internet")); add_row_if_permission (store, (perm_flags & BZ_APP_PERMISSIONS_FLAGS_DEVICES) != 0, BZ_IMPORTANCE_WARNING, "camera-photo-symbolic", _ ("User Device Access"), _ ("Can access devices such as webcams or gaming controllers"), "camera-disabled-symbolic", _ ("No User Device Access"), _ ("Cannot access devices such as webcams or gaming controllers")); add_row_if_permission (store, (perm_flags & BZ_APP_PERMISSIONS_FLAGS_INPUT_DEVICES) != 0, BZ_IMPORTANCE_INFORMATION, "input-keyboard-symbolic", _ ("Input Device Access"), _ ("Can access input devices"), NULL, NULL, NULL); add_row_if_permission (store, (perm_flags & BZ_APP_PERMISSIONS_FLAGS_AUDIO_DEVICES) != 0, BZ_IMPORTANCE_INFORMATION, "permissions-microphone-symbolic", _ ("Microphone Access and Audio Playback"), _ ("Can listen using microphones and play audio without asking permission"), NULL, NULL, NULL); add_row_if_permission (store, (perm_flags & BZ_APP_PERMISSIONS_FLAGS_SYSTEM_DEVICES) != 0, BZ_IMPORTANCE_WARNING, "permissions-system-devices-symbolic", _ ("System Device Access"), _ ("Can access system devices which require elevated permissions"), NULL, NULL, NULL); add_row_if_permission (store, (perm_flags & BZ_APP_PERMISSIONS_FLAGS_SCREEN) != 0, BZ_IMPORTANCE_WARNING, "permissions-screen-contents-symbolic", _ ("Screen Contents Access"), _ ("Can access the contents of the screen or other windows"), NULL, NULL, NULL); add_row_if_permission (store, (perm_flags & BZ_APP_PERMISSIONS_FLAGS_X11) != 0, BZ_IMPORTANCE_IMPORTANT, "permissions-legacy-windowing-system-symbolic", _ ("Legacy Windowing System"), _ ("Always uses a legacy windowing system (X11)"), NULL, NULL, NULL); add_row_if_permission (store, (perm_flags & BZ_APP_PERMISSIONS_FLAGS_ESCAPE_SANDBOX) != 0, BZ_IMPORTANCE_IMPORTANT, "earth-symbolic", _ ("Arbitrary Permissions"), _ ("Can acquire arbitrary permissions"), NULL, NULL, NULL); add_row_if_permission (store, (perm_flags & BZ_APP_PERMISSIONS_FLAGS_SETTINGS) != 0, BZ_IMPORTANCE_WARNING, "emblem-system-symbolic", _ ("User Settings"), _ ("Can access and change user settings"), NULL, NULL, NULL); add_row_if_permission (store, (perm_flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL) != 0, BZ_IMPORTANCE_IMPORTANT, "drive-harddisk-symbolic", _ ("Full File System Read/Write Access"), _ ("Can read and write all data on the file system"), NULL, NULL, NULL); add_row_if_permission (store, ((perm_flags & BZ_APP_PERMISSIONS_FLAGS_HOME_FULL) != 0 && !(perm_flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL)), BZ_IMPORTANCE_IMPORTANT, "user-home-symbolic", _ ("Home Folder Read/Write Access"), _ ("Can read and write all data in your home directory"), NULL, NULL, NULL); add_row_if_permission (store, ((perm_flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ) != 0 && !(perm_flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL)), BZ_IMPORTANCE_IMPORTANT, "folder-symbolic", _ ("Full File System Read Access"), _ ("Can read all data on the file system"), NULL, NULL, NULL); add_row_if_permission (store, ((perm_flags & BZ_APP_PERMISSIONS_FLAGS_HOME_READ) != 0 && !(perm_flags & (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL | BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ))), BZ_IMPORTANCE_IMPORTANT, "user-home-symbolic", _ ("Home Folder Read Access"), _ ("Can read all data in your home directory"), NULL, NULL, NULL); add_row_if_permission (store, ((perm_flags & BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_FULL) != 0 && !(perm_flags & (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL | BZ_APP_PERMISSIONS_FLAGS_HOME_FULL))), BZ_IMPORTANCE_WARNING, "folder-download-symbolic", _ ("Download Folder Read/Write Access"), _ ("Can read and write all data in your downloads directory"), NULL, NULL, NULL); add_row_if_permission (store, ((perm_flags & BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_READ) != 0 && !(perm_flags & (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL | BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ | BZ_APP_PERMISSIONS_FLAGS_HOME_FULL | BZ_APP_PERMISSIONS_FLAGS_HOME_READ))), BZ_IMPORTANCE_WARNING, "folder-download-symbolic", _ ("Download Folder Read Access"), _ ("Can read all data in your downloads directory"), NULL, NULL, NULL); for (i = 0; filesystem_full != NULL && i < filesystem_full->len; i++) { const BzFilesystemPath *path = g_ptr_array_index (filesystem_full, i); g_autofree char *fs_title = bz_filesystem_path_to_display_string (path); const char *fs_icon = bz_filesystem_path_to_icon_name (path); add_row_if_permission (store, TRUE, BZ_IMPORTANCE_WARNING, fs_icon, fs_title, _ ("Can read and write all data in the directory"), NULL, NULL, NULL); } for (i = 0; filesystem_read != NULL && i < filesystem_read->len; i++) { const BzFilesystemPath *path = g_ptr_array_index (filesystem_read, i); g_autofree char *fs_title = bz_filesystem_path_to_display_string (path); const char *fs_icon = bz_filesystem_path_to_icon_name (path); add_row_if_permission (store, TRUE, BZ_IMPORTANCE_WARNING, fs_icon, fs_title, _ ("Can read all data in the directory"), NULL, NULL, NULL); } add_row_if_permission (store, !(perm_flags & (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL | BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ | BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_OTHER | BZ_APP_PERMISSIONS_FLAGS_HOME_FULL | BZ_APP_PERMISSIONS_FLAGS_HOME_READ | BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_FULL | BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_READ)) && filesystem_read == NULL && filesystem_full == NULL, BZ_IMPORTANCE_UNIMPORTANT, "folder-symbolic", _ ("No File System Access"), _ ("Cannot access the file system at all"), NULL, NULL, NULL); add_row_if_permission (store, (perm_flags & BZ_APP_PERMISSIONS_FLAGS_SYSTEM_BUS) != 0, BZ_IMPORTANCE_WARNING, "emblem-system-symbolic", _ ("Uses System Services"), _ ("Can request data from non-portal system services"), NULL, NULL, NULL); add_row_if_permission (store, (perm_flags & BZ_APP_PERMISSIONS_FLAGS_SESSION_BUS) != 0, BZ_IMPORTANCE_WARNING, "emblem-system-symbolic", _ ("Uses Session Services"), _ ("Can request data from non-portal session services"), NULL, NULL, NULL); for (i = 0; i < n_bus_policies; i++) { const BzBusPolicy *policy = bus_policies[i]; const char *well_known_title = NULL; const char *well_known_desc = NULL; g_autofree char *bus_title = NULL; const char *bus_description = NULL; gboolean is_system_tray = FALSE; is_system_tray = g_str_equal (policy->bus_name, "org.kde.StatusNotifierWatcher") || g_str_equal (policy->bus_name, "com.canonical.indicator.application"); if (is_system_tray && has_system_tray) // if not filtered, then there would be 2 entries for tray icon continue; if (is_system_tray) has_system_tray = TRUE; if (lookup_well_known_bus_policy (policy->bus_name, &well_known_title, &well_known_desc)) { bus_title = g_strdup (well_known_title); bus_description = well_known_desc; } else { bus_title = format_bus_policy_title (policy); bus_description = format_bus_policy_subtitle (policy); } add_row_if_permission (store, TRUE, BZ_IMPORTANCE_WARNING, "emblem-system-symbolic", bus_title, bus_description, NULL, NULL, NULL); } add_row_if_permission (store, !(perm_flags & (BZ_APP_PERMISSIONS_FLAGS_SYSTEM_BUS | BZ_APP_PERMISSIONS_FLAGS_SESSION_BUS | BZ_APP_PERMISSIONS_FLAGS_BUS_POLICY_OTHER)) && n_bus_policies == 0, BZ_IMPORTANCE_UNIMPORTANT, "emblem-system-symbolic", _ ("No Service Access"), _ ("Cannot access non-portal session or system services at all"), NULL, NULL, NULL); } add_row_if_permission (store, is_verified, BZ_IMPORTANCE_UNIMPORTANT, "verified-checkmark-symbolic", _ ("Verified App Developer"), _ ("The developer of this app has been verified to be who they say they are"), NULL, NULL, NULL); if (!is_foss) { add_row_if_permission (store, TRUE, BZ_IMPORTANCE_INFORMATION, "proprietary-code-symbolic", _ ("Proprietary Code"), _ ("The source code is not public, so it cannot be independently audited and might be unsafe"), NULL, NULL, NULL); } else { add_row_if_permission (store, FALSE, BZ_IMPORTANCE_NEUTRAL, NULL, NULL, NULL, "auditable-code-symbolic", _ ("Auditable Code"), _ ("The source code is public and can be independently audited, which makes the app more likely to be safe")); } g_clear_object (&permissions); return G_LIST_MODEL (store); } char * bz_safety_calculator_get_top_icon (BzEntry *entry, int index) { g_autoptr (GListModel) model = NULL; const char *icons[2] = { NULL, NULL }; guint icon_count = 0; guint n_items = 0; BzImportance priorities[] = { BZ_IMPORTANCE_IMPORTANT, BZ_IMPORTANCE_WARNING, BZ_IMPORTANCE_INFORMATION }; g_return_val_if_fail (BZ_IS_ENTRY (entry), NULL); if (index < 0 || index > 1) return NULL; model = bz_safety_calculator_analyze_entry (entry); n_items = g_list_model_get_n_items (model); for (guint priority_idx = 0; priority_idx < 3 && icon_count < 2; priority_idx++) { BzImportance current_priority = priorities[priority_idx]; for (guint i = 0; i < n_items && icon_count < 2; i++) { g_autoptr (BzSafetyRow) row = g_list_model_get_item (model, i); BzImportance importance = BZ_IMPORTANCE_UNIMPORTANT; const char *icon_name = NULL; gboolean duplicate = FALSE; g_object_get (row, "importance", &importance, "icon-name", &icon_name, NULL); if (importance != current_priority) continue; if (icon_name == NULL || *icon_name == '\0') continue; for (guint j = 0; j < icon_count; j++) { if (g_strcmp0 (icons[j], icon_name) == 0) { duplicate = TRUE; break; } } if (!duplicate) { icons[icon_count] = icon_name; icon_count++; } } } if (icon_count == 0 || icons[index] == NULL) return NULL; return g_strdup (icons[index]); } BzImportance bz_safety_calculator_calculate_rating (BzEntry *entry) { g_autoptr (GListModel) model = NULL; BzImportance max_rating = BZ_IMPORTANCE_UNIMPORTANT; guint n_items = 0; guint i = 0; gboolean is_foss = FALSE; g_return_val_if_fail (BZ_IS_ENTRY (entry), BZ_IMPORTANCE_UNIMPORTANT); model = bz_safety_calculator_analyze_entry (entry); n_items = g_list_model_get_n_items (model); is_foss = bz_entry_get_is_foss (entry); for (i = 0; i < n_items; i++) { g_autoptr (BzSafetyRow) row = g_list_model_get_item (model, i); BzImportance rating = BZ_IMPORTANCE_UNIMPORTANT; g_object_get (row, "importance", &rating, NULL); max_rating = MAX (max_rating, rating); } if (is_foss && max_rating == BZ_IMPORTANCE_WARNING) { max_rating = BZ_IMPORTANCE_INFORMATION; } if (is_foss && max_rating == BZ_IMPORTANCE_IMPORTANT) { max_rating = BZ_IMPORTANCE_WARNING; } return max_rating; } BzHighRiskGroup bz_safety_calculator_get_high_risk_groups (BzEntry *entry) { BzAppPermissions *permissions = NULL; BzAppPermissionsFlags perm_flags = BZ_APP_PERMISSIONS_FLAGS_NONE; BzHighRiskGroup result = BZ_HIGH_RISK_GROUP_NONE; g_return_val_if_fail (BZ_IS_ENTRY (entry), BZ_HIGH_RISK_GROUP_NONE); g_object_get (entry, "permissions", &permissions, NULL); if (permissions == NULL) return BZ_HIGH_RISK_GROUP_NONE; perm_flags = bz_app_permissions_get_flags (permissions); if (perm_flags & BZ_APP_PERMISSIONS_FLAGS_X11) result |= BZ_HIGH_RISK_GROUP_X11; if (perm_flags & (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL | BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ | BZ_APP_PERMISSIONS_FLAGS_HOME_FULL | BZ_APP_PERMISSIONS_FLAGS_HOME_READ | BZ_APP_PERMISSIONS_FLAGS_ESCAPE_SANDBOX)) result |= BZ_HIGH_RISK_GROUP_DISK; g_clear_object (&permissions); return result; } static char * format_bus_policy_title (const BzBusPolicy *bus_policy) { if (bus_policy->bus_type == G_BUS_TYPE_SYSTEM) { return g_strdup_printf (_ ("Use the %s System Service"), bus_policy->bus_name); } else if (bus_policy->bus_type == G_BUS_TYPE_SESSION) { return g_strdup_printf (_ ("Use the %s Session Service"), bus_policy->bus_name); } else { return g_strdup_printf (_ ("Use the %s Service"), bus_policy->bus_name); } } static const char * format_bus_policy_subtitle (const BzBusPolicy *bus_policy) { switch (bus_policy->permission) { case BZ_BUS_POLICY_PERMISSION_SEE: return _ ("Can see the non-portal service"); case BZ_BUS_POLICY_PERMISSION_TALK: return _ ("Can talk to the non-portal service"); case BZ_BUS_POLICY_PERMISSION_OWN: return _ ("Can own the non-portal service"); case BZ_BUS_POLICY_PERMISSION_NONE: case BZ_BUS_POLICY_PERMISSION_UNKNOWN: default: g_assert_not_reached (); } } static gboolean lookup_well_known_bus_policy (const char *bus_name, const char **out_title, const char **out_description) { if (g_str_equal (bus_name, "com.canonical.AppMenu.Registrar")) { *out_title = _ ("Global Menu Integration"); *out_description = _ ("Can display its menus in a global menu bar"); return TRUE; } if (g_str_equal (bus_name, "org.kde.kconfig.notify")) { *out_title = _ ("KDE Settings Integration"); *out_description = _ ("Can detect when KDE desktop settings change"); return TRUE; } if (g_str_equal (bus_name, "org.kde.KGlobalSettings")) { *out_title = _ ("KDE Global Settings"); *out_description = _ ("Can read KDE desktop preferences like fonts and colors"); return TRUE; } if (g_str_equal (bus_name, "org.freedesktop.secrets")) { *out_title = _ ("Secret Storage Service"); *out_description = _ ("Can store and retrieve its own passwords using the system keyring"); return TRUE; } if (g_str_equal (bus_name, "org.freedesktop.Notifications")) { *out_title = _ ("Desktop Notifications Service"); *out_description = _ ("Can send desktop notifications"); return TRUE; } if (g_str_equal (bus_name, "org.kde.StatusNotifierWatcher") || g_str_equal (bus_name, "com.canonical.indicator.application")) { *out_title = _ ("System Tray Integration"); *out_description = _ ("Can display an icon in the system tray"); return TRUE; } if (g_str_equal (bus_name, "org.kde.kdeconnect")) { *out_title = _ ("KDE Connect Integration"); *out_description = _ ("Can interact with devices paired via KDE Connect"); return TRUE; } return FALSE; } static void add_row_if_permission (GListStore *store, gboolean has_permission, BzImportance item_rating, const char *icon_name_with_permission, const char *title_with_permission, const char *description_with_permission, const char *icon_name_without_permission, const char *title_without_permission, const char *description_without_permission) { BzSafetyRow *row = NULL; if (!has_permission && title_without_permission == NULL) return; row = bz_safety_row_new (); g_object_set (row, "importance", has_permission ? item_rating : BZ_IMPORTANCE_UNIMPORTANT, "icon-name", has_permission ? icon_name_with_permission : icon_name_without_permission, "title", has_permission ? title_with_permission : title_without_permission, "subtitle", has_permission ? description_with_permission : description_without_permission, NULL); g_list_store_append (store, row); g_object_unref (row); } bazaar-orig-v0.7.14/src/bz-dynamic-list-view.h0000664000175000017500000000667415166123241020073 0ustar hasanhasan/* bz-dynamic-list-view.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS typedef enum { BZ_DYNAMIC_LIST_VIEW_KIND_HBOX, BZ_DYNAMIC_LIST_VIEW_KIND_VBOX, BZ_DYNAMIC_LIST_VIEW_KIND_LIST_BOX, BZ_DYNAMIC_LIST_VIEW_KIND_FLOW_BOX, BZ_DYNAMIC_LIST_VIEW_KIND_CAROUSEL, /*< private >*/ BZ_DYNAMIC_LIST_VIEW_N_KINDS, } BzDynamicListViewKind; GType bz_dynamic_list_view_kind_get_type (void); #define BZ_TYPE_DYNAMIC_LIST_VIEW_KIND (bz_dynamic_list_view_kind_get_type ()) #define BZ_TYPE_DYNAMIC_LIST_VIEW (bz_dynamic_list_view_get_type ()) G_DECLARE_FINAL_TYPE (BzDynamicListView, bz_dynamic_list_view, BZ, DYNAMIC_LIST_VIEW, AdwBin) BzDynamicListView * bz_dynamic_list_view_new (void); GListModel * bz_dynamic_list_view_get_model (BzDynamicListView *self); gboolean bz_dynamic_list_view_get_scroll (BzDynamicListView *self); BzDynamicListViewKind bz_dynamic_list_view_get_noscroll_kind (BzDynamicListView *self); const char * bz_dynamic_list_view_get_child_type (BzDynamicListView *self); const char * bz_dynamic_list_view_get_child_prop (BzDynamicListView *self); const char * bz_dynamic_list_view_get_object_prop (BzDynamicListView *self); void bz_dynamic_list_view_set_model (BzDynamicListView *self, GListModel *model); void bz_dynamic_list_view_set_scroll (BzDynamicListView *self, gboolean scroll); void bz_dynamic_list_view_set_noscroll_kind (BzDynamicListView *self, BzDynamicListViewKind noscroll_kind); void bz_dynamic_list_view_set_child_type (BzDynamicListView *self, const char *child_type); void bz_dynamic_list_view_set_child_prop (BzDynamicListView *self, const char *child_prop); void bz_dynamic_list_view_set_object_prop (BzDynamicListView *self, const char *object_prop); guint bz_dynamic_list_view_get_max_children_per_line (BzDynamicListView *self); void bz_dynamic_list_view_set_max_children_per_line (BzDynamicListView *self, guint max_children); guint bz_dynamic_list_view_get_row_spacing (BzDynamicListView *self); void bz_dynamic_list_view_set_row_spacing (BzDynamicListView *self, guint row_spacing); guint bz_dynamic_list_view_get_column_spacing (BzDynamicListView *self); void bz_dynamic_list_view_set_column_spacing (BzDynamicListView *self, guint column_spacing); GtkAdjustment *bz_dynamic_list_view_get_vadjustment (BzDynamicListView *self); G_END_DECLS /* End of bz-dynamic-list-view.h */ bazaar-orig-v0.7.14/src/bz-all-apps-page.blp0000664000175000017500000000562115166123241017466 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzAllAppsPage: Adw.NavigationPage { Adw.ToolbarView { [top] Adw.HeaderBar { [end] MenuButton { primary: true; icon-name: "open-menu-symbolic"; has-tooltip: true; tooltip-text: _("Main Menu"); menu-model: menu { section { item { label: _("_Donate to Bazaar ❤️"); action: "app.donate"; } } section { item { label: _("_Refresh"); action: "app.sync-remotes"; } item { label: _("_Preferences"); action: "app.preferences"; } item { label: _("_Login With Flathub"); action: "app.flathub-login"; hidden-when: "action-disabled"; } item { label: _("_Manage Leftover User Data"); action: "window.user-data"; } item { label: _("_Keyboard Shortcuts"); action: "app.shortcuts"; } item { label: _("_About Bazaar"); action: "app.about"; } } section { item { label: _("_Quit Bazaar"); action: "app.quit"; } } }; } } content: Adw.BreakpointBin { width-request: 360; height-request: 100; child: ScrolledWindow { hexpand: true; vexpand: true; hscrollbar-policy: never; child: Adw.ClampScrollable clamp_scrollable { maximum-size: 1500; tightening-threshold: 1400; child: GridView grid_view { styles [ "search-grid", ] min-columns: 4; max-columns: 4; margin-start: 30; margin-end: 30; enable-rubberband: false; single-click-activate: true; factory: BuilderListItemFactory { template ListItem { child: $BzAppTile { group: bind template.item as <$BzEntryGroup>; clicked => $tile_clicked_cb(template); }; } }; }; }; }; Adw.Breakpoint { condition ("max-width: 1300px") setters { grid_view.min-columns: 3; grid_view.max-columns: 3; } } Adw.Breakpoint { condition ("max-width: 900px") setters { grid_view.min-columns: 2; grid_view.max-columns: 2; } } Adw.Breakpoint { condition ("max-width: 700px") setters { grid_view.margin-start: 3; grid_view.margin-end: 3; grid_view.min-columns: 1; grid_view.max-columns: 1; } } }; } } bazaar-orig-v0.7.14/src/bz-age-rating-attribute.txt0000664000175000017500000000052715166123241021124 0ustar hasanhasanprefix=bz name=age_rating_attribute parent-prefix=g parent-name=object author=AUTOGEN include="bz-context-row.h" property=importance BzImportance BZ_TYPE_IMPORTANCE enum property=id char G_TYPE_STRING string property=title char G_TYPE_STRING string property=description char G_TYPE_STRING string property=icon_name char G_TYPE_STRING string bazaar-orig-v0.7.14/src/bz-section-view.c0000664000175000017500000003461115166123241017125 0ustar hasanhasan/* bz-section-view.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-application.h" #include "bz-async-texture.h" #include "bz-curated-app-tile.h" #include "bz-curated-section.h" #include "bz-dynamic-list-view.h" #include "bz-entry-group.h" #include "bz-section-view.h" #include "bz-window.h" struct _BzSectionView { AdwBin parent_instance; BzCuratedSection *section; GListModel *classes; AdwStyleManager *style_manager; GListModel *applied_classes; /* Template widgets */ GtkOverlay *banner_text_overlay; GtkBox *banner_text_bg; GtkBox *banner_text; }; G_DEFINE_FINAL_TYPE (BzSectionView, bz_section_view, ADW_TYPE_BIN) enum { PROP_0, PROP_SECTION, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; enum { SIGNAL_GROUP_ACTIVATED, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL]; static void tile_clicked (BzEntryGroup *group, GtkButton *button); static void dark_changed (BzSectionView *self, GParamSpec *pspec, AdwStyleManager *mgr); static void refresh_dark_light_classes (BzSectionView *self, AdwStyleManager *mgr); static BzAsyncTexture * choose_image (const char *default_variant_uri, const char *light_variant_uri, const char *dark_variant_uri); static void bz_section_view_dispose (GObject *object) { BzSectionView *self = BZ_SECTION_VIEW (object); g_signal_handlers_disconnect_by_func ( self->style_manager, dark_changed, self); g_clear_object (&self->section); g_clear_object (&self->classes); g_clear_object (&self->style_manager); g_clear_object (&self->applied_classes); G_OBJECT_CLASS (bz_section_view_parent_class)->dispose (object); } static void bz_section_view_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzSectionView *self = BZ_SECTION_VIEW (object); switch (prop_id) { case PROP_SECTION: g_value_set_object (value, bz_section_view_get_section (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_section_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzSectionView *self = BZ_SECTION_VIEW (object); switch (prop_id) { case PROP_SECTION: bz_section_view_set_section (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static gboolean is_null (gpointer object, GObject *value) { return value == NULL; } static BzAsyncTexture * get_banner (gpointer object, BzCuratedCategoryInfo *info) { const char *banner = NULL; const char *light_banner = NULL; const char *dark_banner = NULL; if (!BZ_IS_CURATED_CATEGORY_INFO (info)) return NULL; banner = bz_curated_category_info_get_banner (info); light_banner = bz_curated_category_info_get_light_banner (info); dark_banner = bz_curated_category_info_get_dark_banner (info); return choose_image (banner, light_banner, dark_banner); } static BzAsyncTexture * get_image (gpointer object, BzCuratedImageInfo *info) { const char *image = NULL; const char *light_image = NULL; const char *dark_image = NULL; if (!BZ_IS_CURATED_IMAGE_INFO (info)) return NULL; image = bz_curated_image_info_get_uri (info); light_image = bz_curated_image_info_get_light_uri (info); dark_image = bz_curated_image_info_get_dark_uri (info); return choose_image (image, light_image, dark_image); } static int clamp_banner_height (gpointer object, int value) { if (value == 0) return 300; return CLAMP (value, 100, 1000); } static int clamp_image_dimension (gpointer object, int value) { if (value == 0) return 200; return CLAMP (value, 100, 1000); } static GListModel * convert_to_groups (gpointer object, GListModel *value) { BzStateInfo *info = NULL; BzApplicationMapFactory *factory = NULL; info = bz_state_info_get_default (); factory = bz_state_info_get_application_factory (info); return bz_application_map_factory_generate (factory, value); } static void bind_widget_cb (BzSectionView *self, BzCuratedAppTile *tile, BzEntryGroup *group, BzDynamicListView *view) { g_signal_connect_swapped (tile, "clicked", G_CALLBACK (tile_clicked), group); } static void unbind_widget_cb (BzSectionView *self, BzCuratedAppTile *tile, BzEntryGroup *group, BzDynamicListView *view) { g_signal_handlers_disconnect_by_func (tile, G_CALLBACK (tile_clicked), group); } static void install_all_clicked (BzSectionView *self, GtkButton *button) { GtkWidget *window = NULL; BzCuratedCategoryInfo *category = NULL; GListModel *appids = NULL; guint n_appids = 0; BzStateInfo *info = NULL; BzApplicationMapFactory *factory = NULL; g_autoptr (GListModel) groups = NULL; window = gtk_widget_get_ancestor (GTK_WIDGET (self), BZ_TYPE_WINDOW); if (window == NULL) return; /* If the button is visible and the user clicked it, this must be non-null */ category = bz_curated_section_get_category (self->section); appids = bz_curated_category_info_get_appids (category); if (appids == NULL) return; n_appids = g_list_model_get_n_items (appids); if (n_appids == 0) return; /* TODO: bind state via object properties */ info = bz_state_info_get_default (); factory = bz_state_info_get_application_factory (info); groups = bz_application_map_factory_generate (factory, appids); /* TODO: use signals to chain up the blueprints; it is cleaner, but more work... :( */ bz_window_bulk_install (BZ_WINDOW (window), groups); } static void bz_section_view_class_init (BzSectionViewClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_section_view_dispose; object_class->get_property = bz_section_view_get_property; object_class->set_property = bz_section_view_set_property; props[PROP_SECTION] = g_param_spec_object ( "section", NULL, NULL, BZ_TYPE_CURATED_SECTION, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); signals[SIGNAL_GROUP_ACTIVATED] = g_signal_new ( "group-activated", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, BZ_TYPE_ENTRY_GROUP); g_signal_set_va_marshaller ( signals[SIGNAL_GROUP_ACTIVATED], G_TYPE_FROM_CLASS (klass), g_cclosure_marshal_VOID__OBJECTv); g_type_ensure (BZ_TYPE_CURATED_APP_TILE); g_type_ensure (BZ_TYPE_DYNAMIC_LIST_VIEW); g_type_ensure (BZ_TYPE_ASYNC_TEXTURE); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-section-view.ui"); gtk_widget_class_bind_template_child (widget_class, BzSectionView, banner_text_overlay); gtk_widget_class_bind_template_child (widget_class, BzSectionView, banner_text_bg); gtk_widget_class_bind_template_child (widget_class, BzSectionView, banner_text); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, is_null); gtk_widget_class_bind_template_callback (widget_class, get_banner); gtk_widget_class_bind_template_callback (widget_class, get_image); gtk_widget_class_bind_template_callback (widget_class, clamp_banner_height); gtk_widget_class_bind_template_callback (widget_class, clamp_image_dimension); gtk_widget_class_bind_template_callback (widget_class, convert_to_groups); gtk_widget_class_bind_template_callback (widget_class, bind_widget_cb); gtk_widget_class_bind_template_callback (widget_class, unbind_widget_cb); gtk_widget_class_bind_template_callback (widget_class, install_all_clicked); } static void dark_changed (BzSectionView *self, GParamSpec *pspec, AdwStyleManager *mgr) { refresh_dark_light_classes (self, mgr); if (self->section != NULL) { g_object_notify (G_OBJECT (self->section), "category"); g_object_notify (G_OBJECT (self->section), "markdown"); g_object_notify (G_OBJECT (self->section), "image"); } } static void bz_section_view_init (BzSectionView *self) { gtk_widget_init_template (GTK_WIDGET (self)); gtk_overlay_set_measure_overlay ( self->banner_text_overlay, GTK_WIDGET (self->banner_text), TRUE); gtk_overlay_set_clip_overlay ( self->banner_text_overlay, GTK_WIDGET (self->banner_text), TRUE); self->style_manager = g_object_ref ( adw_style_manager_get_default ()); g_signal_connect_swapped ( self->style_manager, "notify::dark", G_CALLBACK (dark_changed), self); } GtkWidget * bz_section_view_new (BzCuratedSection *section) { return g_object_new ( BZ_TYPE_SECTION_VIEW, "section", section, NULL); } void bz_section_view_set_section (BzSectionView *self, BzCuratedSection *section) { g_return_if_fail (BZ_IS_SECTION_VIEW (self)); g_return_if_fail (section == NULL || BZ_IS_CURATED_SECTION (section)); g_clear_object (&self->section); if (self->classes != NULL) { guint n_classes = 0; n_classes = g_list_model_get_n_items (self->classes); for (guint i = 0; i < n_classes; i++) { g_autoptr (GtkStringObject) string = NULL; const char *class = NULL; string = g_list_model_get_item (self->classes, i); class = gtk_string_object_get_string (string); gtk_widget_remove_css_class (GTK_WIDGET (self), class); } } g_clear_object (&self->classes); if (section != NULL) { self->section = g_object_ref (section); g_object_get (section, "classes", &self->classes, NULL); if (self->classes != NULL) { guint n_classes = 0; n_classes = g_list_model_get_n_items (self->classes); for (guint i = 0; i < n_classes; i++) { g_autoptr (GtkStringObject) string = NULL; const char *class = NULL; string = g_list_model_get_item (self->classes, i); class = gtk_string_object_get_string (string); gtk_widget_add_css_class (GTK_WIDGET (self), class); } } refresh_dark_light_classes (self, NULL); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SECTION]); } BzCuratedSection * bz_section_view_get_section (BzSectionView *self) { g_return_val_if_fail (BZ_IS_SECTION_VIEW (self), NULL); return self->section; } static void tile_clicked (BzEntryGroup *group, GtkButton *button) { GtkWidget *self = NULL; self = gtk_widget_get_ancestor (GTK_WIDGET (button), BZ_TYPE_SECTION_VIEW); g_signal_emit (self, signals[SIGNAL_GROUP_ACTIVATED], 0, group); } static void refresh_dark_light_classes (BzSectionView *self, AdwStyleManager *mgr) { if (self->applied_classes != NULL) { guint n_applied_classes = 0; n_applied_classes = g_list_model_get_n_items (self->applied_classes); for (guint i = 0; i < n_applied_classes; i++) { g_autoptr (GtkStringObject) string = NULL; const char *class = NULL; string = g_list_model_get_item (self->applied_classes, i); class = gtk_string_object_get_string (string); gtk_widget_remove_css_class (GTK_WIDGET (self), class); } } g_clear_object (&self->applied_classes); if (self->section == NULL) return; if (mgr == NULL) mgr = adw_style_manager_get_default (); if (adw_style_manager_get_dark (mgr)) g_object_get (self->section, "dark-classes", &self->applied_classes, NULL); else g_object_get (self->section, "light-classes", &self->applied_classes, NULL); if (self->applied_classes != NULL) { guint n_classes = 0; n_classes = g_list_model_get_n_items (self->applied_classes); for (guint i = 0; i < n_classes; i++) { g_autoptr (GtkStringObject) string = NULL; const char *class = NULL; string = g_list_model_get_item (self->applied_classes, i); class = gtk_string_object_get_string (string); gtk_widget_add_css_class (GTK_WIDGET (self), class); } } } static BzAsyncTexture * choose_image (const char *default_variant_uri, const char *light_variant_uri, const char *dark_variant_uri) { gboolean is_dark = FALSE; const char *uri = NULL; g_autoptr (GFile) source = NULL; g_autoptr (GdkPaintable) paintable = NULL; is_dark = adw_style_manager_get_dark (adw_style_manager_get_default ()); if (is_dark) uri = dark_variant_uri; else uri = light_variant_uri; if (uri == NULL) uri = default_variant_uri; if (uri == NULL) return NULL; source = g_file_new_for_uri (uri); return bz_async_texture_new_lazy (source, NULL); } bazaar-orig-v0.7.14/src/bz-transaction.h0000664000175000017500000000474515166123241017050 0ustar hasanhasan/* bz-transaction.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry.h" #include "bz-transaction-entry-tracker.h" #include "bz-transaction-task.h" G_BEGIN_DECLS #define BZ_TYPE_TRANSACTION (bz_transaction_get_type ()) G_DECLARE_DERIVABLE_TYPE (BzTransaction, bz_transaction, BZ, TRANSACTION, GObject) struct _BzTransactionClass { GObjectClass parent_class; }; BzTransaction * bz_transaction_new_full (BzEntry **installs, guint n_installs, BzEntry **updates, guint n_updates, BzEntry **removals, guint n_removals); BzTransaction * bz_transaction_new_merged (BzTransaction **transactions, guint n_transactions); GListModel * bz_transaction_get_installs (BzTransaction *self); GListModel * bz_transaction_get_updates (BzTransaction *self); GListModel * bz_transaction_get_removals (BzTransaction *self); GListModel * bz_transaction_get_trackers (BzTransaction *self); void bz_transaction_hold (BzTransaction *self); void bz_transaction_release (BzTransaction *self); void bz_transaction_add_task (BzTransaction *self, BzBackendTransactionOpPayload *payload); void bz_transaction_update_task (BzTransaction *self, BzBackendTransactionOpProgressPayload *payload); void bz_transaction_finish_task (BzTransaction *self, BzBackendTransactionOpPayload *payload); void bz_transaction_error_out_task (BzTransaction *self, BzBackendTransactionOpPayload *payload, const char *message); G_END_DECLS bazaar-orig-v0.7.14/src/bz-flathub-auth-provider.txt0000664000175000017500000000025115166123241021313 0ustar hasanhasanprefix=bz name=flathub_auth_provider parent-prefix=g parent-name=object author=AUTOGEN property=method char G_TYPE_STRING string property=name char G_TYPE_STRING string bazaar-orig-v0.7.14/src/bz-country.txt0000664000175000017500000000043415166123241016605 0ustar hasanhasanprefix=bz name=country parent-prefix=g parent-name=object author=AUTOGEN property=name char G_TYPE_STRING string property=iso_code char G_TYPE_STRING string property=coordinates GVariant G_TYPE_VARIANT variant g_variant_unref g_variant_ref property=value double G_TYPE_DOUBLE double bazaar-orig-v0.7.14/src/bz-section-view.h0000664000175000017500000000233415166123241017127 0ustar hasanhasan/* bz-section-view.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-curated-section.h" G_BEGIN_DECLS #define BZ_TYPE_SECTION_VIEW (bz_section_view_get_type ()) G_DECLARE_FINAL_TYPE (BzSectionView, bz_section_view, BZ, SECTION_VIEW, AdwBin) GtkWidget * bz_section_view_new (BzCuratedSection *section); void bz_section_view_set_section (BzSectionView *self, BzCuratedSection *section); BzCuratedSection * bz_section_view_get_section (BzSectionView *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-library-page.h0000664000175000017500000000334115166123241017070 0ustar hasanhasan/* bz-library-page.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-state-info.h" G_BEGIN_DECLS #define BZ_TYPE_LIBRARY_PAGE (bz_library_page_get_type ()) G_DECLARE_FINAL_TYPE (BzLibraryPage, bz_library_page, BZ, LIBRARY_PAGE, AdwBin) GtkWidget * bz_library_page_new (void); void bz_library_page_set_model (BzLibraryPage *self, GListModel *model); GListModel * bz_library_page_get_model (BzLibraryPage *self); void bz_library_page_set_transactions (BzLibraryPage *self, BzTransactionManager *transactions); BzTransactionManager * bz_library_page_get_transactions (BzLibraryPage *self); void bz_library_page_set_state (BzLibraryPage *self, BzStateInfo *state); BzStateInfo * bz_library_page_get_state (BzLibraryPage *self); gboolean bz_library_page_ensure_active (BzLibraryPage *self, const char *initial); void bz_library_page_reset_search (BzLibraryPage *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-content-provider.h0000664000175000017500000000301015166123241020005 0ustar hasanhasan/* bz-content-provider.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-parser.h" G_BEGIN_DECLS #define BZ_TYPE_CONTENT_PROVIDER (bz_content_provider_get_type ()) G_DECLARE_FINAL_TYPE (BzContentProvider, bz_content_provider, BZ, CONTENT_PROVIDER, GObject) BzContentProvider * bz_content_provider_new (void); void bz_content_provider_set_input_files (BzContentProvider *self, GListModel *input_files); GListModel * bz_content_provider_get_input_files (BzContentProvider *self); void bz_content_provider_set_parser (BzContentProvider *self, BzParser *parser); BzParser * bz_content_provider_get_parser (BzContentProvider *self); gboolean bz_content_provider_get_has_inputs (BzContentProvider *self); G_END_DECLS bazaar-orig-v0.7.14/src/bz-full-view.c0000664000175000017500000006056515166123241016432 0ustar hasanhasan/* bz-full-view.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::FULL-VIEW-WIDGET" #include #include #include "bz-age-rating-dialog.h" #include "bz-app-size-dialog.h" #include "bz-app-tile.h" #include "bz-apps-page.h" #include "bz-appstream-description-render.h" #include "bz-context-tile.h" #include "bz-context-tile-callbacks.h" #include "bz-developer-badge.h" #include "bz-dynamic-list-view.h" #include "bz-entry-inspector.h" #include "bz-error.h" #include "bz-fading-clamp.h" #include "bz-favorite-button.h" #include "bz-flatpak-entry.h" #include "bz-full-view.h" #include "bz-hardware-support-dialog.h" #include "bz-install-controls.h" #include "bz-license-dialog.h" #include "bz-releases-list.h" #include "bz-safety-calculator.h" #include "bz-safety-dialog.h" #include "bz-screenshot-page.h" #include "bz-screenshots-carousel.h" #include "bz-section-view.h" #include "bz-share-list.h" #include "bz-spdx.h" #include "bz-state-info.h" #include "bz-stats-dialog.h" #include "bz-tag-list.h" #include "bz-template-callbacks.h" #include "bz-util.h" struct _BzFullView { AdwBin parent_instance; BzStateInfo *state; BzTransactionManager *transactions; BzEntryGroup *group; DexFuture *ui_future; BzResult *ui_entry; BzResult *runtime; BzResult *group_model; gboolean show_sidebar; GMenuModel *main_menu; /* Template widgets */ GtkScrolledWindow *main_scroll; AdwViewStack *stack; GtkWidget *shadow_overlay; GtkToggleButton *description_toggle; }; G_DEFINE_FINAL_TYPE (BzFullView, bz_full_view, ADW_TYPE_BIN) enum { PROP_0, PROP_STATE, PROP_ENTRY_GROUP, PROP_UI_ENTRY, PROP_MAIN_MENU, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; enum { SIGNAL_UPDATE, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL]; static void bz_full_view_dispose (GObject *object) { BzFullView *self = BZ_FULL_VIEW (object); dex_clear (&self->ui_future); g_clear_object (&self->state); g_clear_object (&self->transactions); g_clear_object (&self->group); g_clear_object (&self->ui_entry); g_clear_object (&self->runtime); g_clear_object (&self->group_model); g_clear_object (&self->main_menu); G_OBJECT_CLASS (bz_full_view_parent_class)->dispose (object); } static void bz_full_view_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzFullView *self = BZ_FULL_VIEW (object); switch (prop_id) { case PROP_STATE: g_value_set_object (value, self->state); break; case PROP_ENTRY_GROUP: g_value_set_object (value, bz_full_view_get_entry_group (self)); break; case PROP_UI_ENTRY: g_value_set_object (value, self->ui_entry); break; case PROP_MAIN_MENU: g_value_set_object (value, self->main_menu); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_full_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzFullView *self = BZ_FULL_VIEW (object); switch (prop_id) { case PROP_STATE: g_clear_object (&self->state); self->state = g_value_dup_object (value); break; case PROP_ENTRY_GROUP: bz_full_view_set_entry_group (self, g_value_get_object (value)); break; case PROP_MAIN_MENU: g_clear_object (&self->main_menu); self->main_menu = g_value_dup_object (value); break; case PROP_UI_ENTRY: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static gboolean is_scrolled_down (gpointer object, double value) { return value > 100.0; } static char * format_as_link (gpointer object, const char *value) { if (value != NULL) return g_strdup_printf ("%s", value, value, value); else return g_strdup (_ ("No URL")); } static gboolean has_link (gpointer object, const char *license) { if (license == NULL || *license == '\0') return FALSE; return bz_spdx_is_valid (license); } static char * pick_license_warning (gpointer object, gboolean value) { return value ? g_strdup (_ ("This application has a FLOSS license, meaning the source code can be audited for safety.")) : g_strdup (_ ("This application has a proprietary license, meaning the source code is developed privately and cannot be audited by an independent third party.")); } static char * format_other_apps_label (gpointer object, const char *developer) { if (!developer || *developer == '\0') return g_strdup (_ ("More Apps")); return g_strdup_printf (_ ("More Apps by %s"), developer); } static char * format_more_other_apps_label (gpointer object, const char *developer) { if (!developer || *developer == '\0') return g_strdup (_ ("Other Apps by this Developer")); return g_strdup_printf (_ ("Other Apps by %s"), developer); } static char * format_leftover_label (gpointer object, const char *name, guint64 size) { g_autofree char *formatted_size = NULL; formatted_size = g_format_size (size); return g_strdup_printf (_ ("%s is not installed, but it still has %s of data present."), name, formatted_size); } static gpointer filter_own_app_id (BzEntry *entry, GtkStringList *app_ids) { const char *own_id; g_autoptr (GtkStringList) filtered = NULL; guint n_items = 0; if (!BZ_IS_ENTRY (entry) || !GTK_IS_STRING_LIST (app_ids)) return NULL; own_id = bz_entry_get_id (entry); if (!own_id) return NULL; filtered = gtk_string_list_new (NULL); n_items = g_list_model_get_n_items (G_LIST_MODEL (app_ids)); for (guint i = 0; i < n_items; i++) { const char *id = NULL; id = gtk_string_list_get_string (app_ids, i); if (g_strcmp0 (id, own_id) != 0) gtk_string_list_append (filtered, id); } if (g_list_model_get_n_items (G_LIST_MODEL (filtered)) > 0) return g_steal_pointer (&filtered); else return NULL; } static GListModel * get_developer_apps_entries (gpointer object, GtkStringList *app_ids, BzEntry *entry) { BzFullView *self = BZ_FULL_VIEW (object); g_autoptr (GtkStringList) filtered = filter_own_app_id (BZ_ENTRY (entry), app_ids); BzApplicationMapFactory *factory; if (!filtered) return NULL; factory = bz_state_info_get_application_factory (self->state); if (!factory) return NULL; return bz_application_map_factory_generate (factory, G_LIST_MODEL (filtered)); } static int get_dev_apps_max_children_per_line (gpointer object, GListModel *model) { if (!model) return 3; return g_list_model_get_n_items (model) > 2 ? 3 : 2; } static void more_apps_button_clicked_cb (BzFullView *self, GtkButton *button) { g_autoptr (GListModel) model = NULL; guint n_items; g_autofree char *title = NULL; g_autofree char *subtitle = NULL; AdwNavigationPage *apps_page = NULL; GtkWidget *nav_view = NULL; g_autoptr (GListModel) app_ids = NULL; BzEntry *entry = NULL; const char *developer = NULL; g_return_if_fail (BZ_IS_FULL_VIEW (self)); g_return_if_fail (GTK_IS_BUTTON (button)); entry = bz_result_get_object (self->ui_entry); if (entry == NULL) return; g_object_get (entry, "developer-apps", &app_ids, NULL); model = bz_application_map_factory_generate ( bz_state_info_get_application_factory (self->state), app_ids); n_items = g_list_model_get_n_items (model); developer = bz_entry_get_developer (entry); if (developer != NULL && *developer != '\0') title = g_strdup_printf (_ ("Other Apps by %s"), developer); else title = g_strdup (_ ("Other Apps")); subtitle = g_strdup_printf (ngettext ("%d Application", "%d Applications", n_items), n_items); apps_page = bz_apps_page_new (title, model); bz_apps_page_set_subtitle (BZ_APPS_PAGE (apps_page), subtitle); nav_view = gtk_widget_get_ancestor (GTK_WIDGET (self), ADW_TYPE_NAVIGATION_VIEW); if (nav_view != NULL) adw_navigation_view_push (ADW_NAVIGATION_VIEW (nav_view), apps_page); } static void app_tile_clicked_cb (BzFullView *self, BzAppTile *tile) { BzEntryGroup *group = bz_app_tile_get_group (tile); bz_full_view_set_entry_group (self, group); } static void bind_app_tile_cb (BzFullView *self, BzAppTile *tile, BzEntryGroup *group, BzDynamicListView *view) { g_signal_connect_swapped (tile, "clicked", G_CALLBACK (app_tile_clicked_cb), self); } static void unbind_app_tile_cb (BzFullView *self, BzAppTile *tile, BzEntryGroup *group, BzDynamicListView *view) { g_signal_handlers_disconnect_by_func (tile, G_CALLBACK (app_tile_clicked_cb), self); } static void open_url_cb (BzFullView *self, AdwActionRow *row) { BzEntry *entry = NULL; const char *url = NULL; entry = BZ_ENTRY (bz_result_get_object (self->ui_entry)); url = bz_entry_get_url (entry); if (url != NULL && *url != '\0') g_app_info_launch_default_for_uri (url, NULL, NULL); else g_warning ("Invalid or empty URL provided for Flathub URL CB"); } static void license_cb (BzFullView *self, GtkButton *button) { AdwDialog *dialog = NULL; BzEntry *ui_entry = NULL; if (self->group == NULL) return; ui_entry = bz_result_get_object (self->ui_entry); if (ui_entry == NULL) return; dialog = bz_license_dialog_new (ui_entry); adw_dialog_present (dialog, GTK_WIDGET (self)); } static void age_rating_cb (BzFullView *self, GtkButton *button) { BzAgeRatingDialog *dialog = NULL; BzEntry *ui_entry = NULL; if (self->group == NULL) return; ui_entry = bz_result_get_object (self->ui_entry); if (ui_entry == NULL) return; dialog = bz_age_rating_dialog_new (ui_entry); adw_dialog_present (ADW_DIALOG (dialog), GTK_WIDGET (self)); } static void dl_stats_cb (BzFullView *self, GtkButton *button) { AdwDialog *dialog = NULL; AdwBreakpointBin *bin = NULL; BzEntry *ui_entry = NULL; if (self->group == NULL) return; ui_entry = bz_result_get_object (self->ui_entry); bin = bz_stats_dialog_new (NULL, NULL, 0); dialog = adw_dialog_new (); adw_dialog_set_content_width (dialog, 1250); adw_dialog_set_content_height (dialog, 750); adw_dialog_set_child (dialog, GTK_WIDGET (bin)); g_object_bind_property (ui_entry, "download-stats", bin, "model", G_BINDING_SYNC_CREATE); g_object_bind_property (ui_entry, "download-stats-per-country", bin, "country-model", G_BINDING_SYNC_CREATE); g_object_bind_property (ui_entry, "total-downloads", bin, "total-downloads", G_BINDING_SYNC_CREATE); adw_dialog_present (dialog, GTK_WIDGET (self)); bz_stats_dialog_animate_open (BZ_STATS_DIALOG (bin)); } static void screenshot_clicked_cb (BzFullView *self, guint index, BzScreenshotsCarousel *carousel) { GListModel *screenshots = NULL; GListModel *captions = NULL; AdwNavigationPage *page = NULL; GtkWidget *nav_view = NULL; BzEntry *entry = NULL; screenshots = bz_screenshots_carousel_get_model (carousel); if (screenshots == NULL) return; if (self->ui_entry != NULL) { entry = bz_result_get_object (self->ui_entry); if (entry != NULL) g_object_get (entry, "screenshot-captions", &captions, NULL); } page = bz_screenshot_page_new (screenshots, captions, index); g_clear_object (&captions); nav_view = gtk_widget_get_ancestor (GTK_WIDGET (self), ADW_TYPE_NAVIGATION_VIEW); if (nav_view != NULL) adw_navigation_view_push (ADW_NAVIGATION_VIEW (nav_view), page); } static void size_cb (BzFullView *self, GtkButton *button) { AdwDialog *size_dialog = NULL; if (self->group == NULL) return; size_dialog = bz_app_size_dialog_new (self->group); adw_dialog_present (size_dialog, GTK_WIDGET (self)); } static void formfactor_cb (BzFullView *self, GtkButton *button) { AdwDialog *dialog = NULL; BzEntry *ui_entry = NULL; if (self->group == NULL) return; ui_entry = bz_result_get_object (self->ui_entry); dialog = ADW_DIALOG (bz_hardware_support_dialog_new (ui_entry)); adw_dialog_present (dialog, GTK_WIDGET (self)); } static void safety_cb (BzFullView *self, GtkButton *button) { AdwDialog *dialog = NULL; if (self->group == NULL) return; dialog = ADW_DIALOG (bz_safety_dialog_new (self->group)); adw_dialog_present (dialog, GTK_WIDGET (self)); } static void update_cb (BzFullView *self, GListModel *entries, BzInstallControls *controls) { g_signal_emit (self, signals[SIGNAL_UPDATE], 0, entries); } static void delete_user_data_cb (BzFullView *self, GtkButton *button) { g_return_if_fail (BZ_IS_FULL_VIEW (self)); if (self->group == NULL) return; bz_entry_group_reap_user_data (self->group); } static void support_cb (BzFullView *self, GtkButton *button) { BzEntry *entry = NULL; entry = bz_result_get_object (self->ui_entry); if (entry != NULL) { const char *url = NULL; url = bz_entry_get_donation_url (entry); g_app_info_launch_default_for_uri (url, NULL, NULL); } } static void install_addons_cb (BzFullView *self, GtkButton *button) { if (self->group == NULL) return; gtk_widget_activate_action (GTK_WIDGET (self), "window.addons-group", "s", bz_entry_group_get_id (self->group)); } static int get_description_max_height (gpointer object, gboolean active) { return active ? 10000 : 170; } static char * get_description_toggle_text (gpointer object, gboolean active) { return g_strdup (active ? _ ("Show Less") : _ ("Show More")); } static void copy_id_cb (BzFullView *self, GtkButton *button) { const char *id = NULL; GdkClipboard *clipboard = NULL; if (self->group == NULL) return; id = bz_entry_group_get_id (self->group); clipboard = gdk_display_get_clipboard (gdk_display_get_default ()); gdk_clipboard_set_text (clipboard, id); } static void debug_id_inspect_cb (BzFullView *self, GtkButton *button) { g_autofree char *unique_id = NULL; g_autoptr (GtkStringObject) string = NULL; g_autoptr (BzResult) result = NULL; if (self->group == NULL) return; unique_id = bz_entry_group_dup_ui_entry_id (self->group); result = bz_application_map_factory_convert_one ( bz_state_info_get_entry_factory (self->state), gtk_string_object_new (unique_id)); if (result != NULL) { BzEntryInspector *inspector = NULL; inspector = bz_entry_inspector_new (); bz_entry_inspector_set_result (inspector, result); gtk_window_present (GTK_WINDOW (inspector)); } } static void bz_full_view_class_init (BzFullViewClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_full_view_dispose; object_class->get_property = bz_full_view_get_property; object_class->set_property = bz_full_view_set_property; props[PROP_STATE] = g_param_spec_object ( "state", NULL, NULL, BZ_TYPE_STATE_INFO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); props[PROP_ENTRY_GROUP] = g_param_spec_object ( "entry-group", NULL, NULL, BZ_TYPE_ENTRY_GROUP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_UI_ENTRY] = g_param_spec_object ( "ui-entry", NULL, NULL, BZ_TYPE_RESULT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_MAIN_MENU] = g_param_spec_object ( "main-menu", NULL, NULL, G_TYPE_MENU_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); signals[SIGNAL_UPDATE] = g_signal_new ( "update", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_LIST_MODEL); g_signal_set_va_marshaller ( signals[SIGNAL_UPDATE], G_TYPE_FROM_CLASS (klass), g_cclosure_marshal_VOID__OBJECTv); g_type_ensure (BZ_TYPE_APPSTREAM_DESCRIPTION_RENDER); g_type_ensure (BZ_TYPE_DEVELOPER_BADGE); g_type_ensure (BZ_TYPE_DYNAMIC_LIST_VIEW); g_type_ensure (BZ_TYPE_ENTRY); g_type_ensure (BZ_TYPE_ENTRY_GROUP); g_type_ensure (BZ_TYPE_FADING_CLAMP); g_type_ensure (BZ_TYPE_FAVORITE_BUTTON); g_type_ensure (BZ_TYPE_FLATPAK_ENTRY); g_type_ensure (BZ_TYPE_HARDWARE_SUPPORT_DIALOG); g_type_ensure (BZ_TYPE_INSTALL_CONTROLS); g_type_ensure (BZ_TYPE_SECTION_VIEW); g_type_ensure (BZ_TYPE_RELEASES_LIST); g_type_ensure (BZ_TYPE_SCREENSHOTS_CAROUSEL); g_type_ensure (BZ_TYPE_SHARE_LIST); g_type_ensure (BZ_TYPE_TAG_LIST); g_type_ensure (BZ_TYPE_CONTEXT_TILE); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-full-view.ui"); bz_widget_class_bind_all_util_callbacks (widget_class); bz_widget_class_bind_all_context_tile_callbacks (widget_class); gtk_widget_class_bind_template_child (widget_class, BzFullView, stack); gtk_widget_class_bind_template_child (widget_class, BzFullView, main_scroll); gtk_widget_class_bind_template_child (widget_class, BzFullView, shadow_overlay); gtk_widget_class_bind_template_child (widget_class, BzFullView, description_toggle); gtk_widget_class_bind_template_callback (widget_class, is_scrolled_down); gtk_widget_class_bind_template_callback (widget_class, age_rating_cb); gtk_widget_class_bind_template_callback (widget_class, format_as_link); gtk_widget_class_bind_template_callback (widget_class, has_link); gtk_widget_class_bind_template_callback (widget_class, format_leftover_label); gtk_widget_class_bind_template_callback (widget_class, format_other_apps_label); gtk_widget_class_bind_template_callback (widget_class, format_more_other_apps_label); gtk_widget_class_bind_template_callback (widget_class, get_developer_apps_entries); gtk_widget_class_bind_template_callback (widget_class, get_dev_apps_max_children_per_line); gtk_widget_class_bind_template_callback (widget_class, more_apps_button_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, open_url_cb); gtk_widget_class_bind_template_callback (widget_class, license_cb); gtk_widget_class_bind_template_callback (widget_class, dl_stats_cb); gtk_widget_class_bind_template_callback (widget_class, screenshot_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, size_cb); gtk_widget_class_bind_template_callback (widget_class, formfactor_cb); gtk_widget_class_bind_template_callback (widget_class, safety_cb); gtk_widget_class_bind_template_callback (widget_class, update_cb); gtk_widget_class_bind_template_callback (widget_class, delete_user_data_cb); gtk_widget_class_bind_template_callback (widget_class, support_cb); gtk_widget_class_bind_template_callback (widget_class, pick_license_warning); gtk_widget_class_bind_template_callback (widget_class, install_addons_cb); gtk_widget_class_bind_template_callback (widget_class, bind_app_tile_cb); gtk_widget_class_bind_template_callback (widget_class, unbind_app_tile_cb); gtk_widget_class_bind_template_callback (widget_class, get_description_max_height); gtk_widget_class_bind_template_callback (widget_class, get_description_toggle_text); gtk_widget_class_bind_template_callback (widget_class, copy_id_cb); gtk_widget_class_bind_template_callback (widget_class, debug_id_inspect_cb); } static void bz_full_view_init (BzFullView *self) { gtk_widget_init_template (GTK_WIDGET (self)); } GtkWidget * bz_full_view_new (void) { return g_object_new (BZ_TYPE_FULL_VIEW, NULL); } static DexFuture * on_ui_entry_resolved (DexFuture *future, GWeakRef *wr) { g_autoptr (BzFullView) self = NULL; BzEntry *ui_entry = NULL; g_autoptr (BzResult) runtime_result = NULL; const GValue *value = NULL; bz_weak_get_or_return_reject (self, wr); value = dex_future_get_value (future, NULL); if (value != NULL && G_VALUE_HOLDS_OBJECT (value)) { ui_entry = g_value_get_object (value); if (BZ_IS_FLATPAK_ENTRY (ui_entry)) self->runtime = bz_flatpak_entry_dup_runtime_result (BZ_FLATPAK_ENTRY (ui_entry)); } return dex_future_new_for_boolean (TRUE); } void bz_full_view_set_entry_group (BzFullView *self, BzEntryGroup *group) { g_return_if_fail (BZ_IS_FULL_VIEW (self)); g_return_if_fail (group == NULL || BZ_IS_ENTRY_GROUP (group)); if (group == self->group) return; dex_clear (&self->ui_future); g_clear_object (&self->group); g_clear_object (&self->ui_entry); g_clear_object (&self->runtime); g_clear_object (&self->group_model); gtk_toggle_button_set_active (self->description_toggle, FALSE); if (group != NULL) { self->group = g_object_ref (group); self->ui_entry = bz_entry_group_dup_ui_entry (group); if (self->ui_entry != NULL && bz_result_get_resolved (self->ui_entry)) { BzEntry *entry = NULL; g_autoptr (GListStore) store = NULL; g_autoptr (DexFuture) future = NULL; g_autoptr (DexFuture) object_future = NULL; GWeakRef *wr = NULL; entry = bz_result_get_object (self->ui_entry); store = g_list_store_new (BZ_TYPE_ENTRY); g_list_store_append (store, entry); future = dex_future_new_for_object (store); self->group_model = bz_result_new (future); object_future = dex_future_new_for_object (entry); wr = bz_track_weak (self); dex_unref (on_ui_entry_resolved (object_future, wr)); bz_weak_release (wr); } else { g_autoptr (DexFuture) future = NULL; future = bz_entry_group_dup_all_into_store (group); self->group_model = bz_result_new (future); if (self->ui_entry != NULL) { g_autoptr (DexFuture) ui_future = NULL; ui_future = bz_result_dup_future (self->ui_entry); ui_future = dex_future_then ( ui_future, (DexFutureCallback) on_ui_entry_resolved, bz_track_weak (self), bz_weak_release); self->ui_future = g_steal_pointer (&ui_future); } } adw_view_stack_set_visible_child_name (self->stack, "content"); } else adw_view_stack_set_visible_child_name (self->stack, "empty"); gtk_adjustment_set_value (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (self->main_scroll)), 0.0); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ENTRY_GROUP]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_UI_ENTRY]); } BzEntryGroup * bz_full_view_get_entry_group (BzFullView *self) { g_return_val_if_fail (BZ_IS_FULL_VIEW (self), NULL); return self->group; } bazaar-orig-v0.7.14/src/bz-entry-cache-manager.c0000664000175000017500000007322515166123241020327 0ustar hasanhasan/* bz-entry-cache-manager.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::ENTRY-CACHE" #define BAZAAR_MODULE "entry-cache" #define MAX_CONCURRENT_WRITES 16 #define WATCH_CLEANUP_INTERVAL_MSEC 5000 #include #include "bz-entry-cache-manager.h" #include "bz-env.h" #include "bz-flatpak-entry.h" #include "bz-io.h" #include "bz-serializable.h" #include "bz-util.h" /* clang-format off */ G_DEFINE_QUARK (bz-entry-cache-error-quark, bz_entry_cache_error); /* clang-format on */ BZ_DEFINE_DATA ( ongoing_task, OngoingTask, { GWeakRef *self; DexScheduler *scheduler; DexPromise *init; GHashTable *alive_hash; GHashTable *writing_hash; GHashTable *reading_hash; BzGuard *ongoing_gates[MAX_CONCURRENT_WRITES]; GMutex ongoing_mutexes[MAX_CONCURRENT_WRITES]; guint ongoing_queued[MAX_CONCURRENT_WRITES]; GMutex ongoing_queueing_mutex; BzGuard *alive_gate; GMutex alive_mutex; BzGuard *reading_gate; GMutex reading_mutex; BzGuard *writing_gate; GMutex writing_mutex; }, BZ_RELEASE_DATA (self, bz_weak_release); BZ_RELEASE_DATA (scheduler, dex_unref); BZ_RELEASE_DATA (init, dex_unref); BZ_RELEASE_DATA (alive_hash, g_hash_table_unref); BZ_RELEASE_DATA (writing_hash, g_hash_table_unref); BZ_RELEASE_DATA (reading_hash, g_hash_table_unref); for (guint i = 0; i < G_N_ELEMENTS (self->ongoing_gates); i++) BZ_RELEASE_DATA (ongoing_gates[i], bz_guard_destroy); for (guint i = 0; i < G_N_ELEMENTS (self->ongoing_mutexes); i++) g_mutex_clear (&self->ongoing_mutexes[i]); g_mutex_clear (&self->ongoing_queueing_mutex); BZ_RELEASE_DATA (alive_gate, bz_guard_destroy); BZ_RELEASE_DATA (reading_gate, bz_guard_destroy); BZ_RELEASE_DATA (writing_gate, bz_guard_destroy); g_mutex_clear (&self->alive_mutex); g_mutex_clear (&self->reading_mutex); g_mutex_clear (&self->writing_mutex);); struct _BzEntryCacheManager { GObject parent_instance; GMutex mutex; guint living_entries; DexScheduler *scheduler; guint64 memory_usage; OngoingTaskData *task_data; DexFuture *watch_task; }; G_DEFINE_FINAL_TYPE (BzEntryCacheManager, bz_entry_cache_manager, G_TYPE_OBJECT); enum { PROP_0, PROP_LIVING_ENTRIES, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static DexFuture * watch_init_fiber (OngoingTaskData *task_data); static DexFuture * watch_cb (DexFuture *future, OngoingTaskData *task_data); static DexFuture * watch_work_fiber (OngoingTaskData *task_data); static DexFuture * notify_props_fiber (GWeakRef *wr); BZ_DEFINE_DATA ( living_entry, LivingEntry, { GWeakRef wr; BzGuard *gate; GMutex mutex; GTimer *cached; }, BZ_RELEASE_DATA (gate, bz_guard_destroy); g_mutex_clear (&self->mutex); g_weak_ref_clear (&self->wr); BZ_RELEASE_DATA (cached, g_timer_destroy)); BZ_DEFINE_DATA ( write_task, WriteTask, { OngoingTaskData *task_data; char *unique_id_checksum; BzEntry *entry; }, BZ_RELEASE_DATA (task_data, ongoing_task_data_unref); BZ_RELEASE_DATA (unique_id_checksum, g_free); BZ_RELEASE_DATA (entry, g_object_unref);) static DexFuture * write_task_fiber (WriteTaskData *data); BZ_DEFINE_DATA ( read_task, ReadTask, { OngoingTaskData *task_data; char *unique_id_checksum; }, BZ_RELEASE_DATA (task_data, ongoing_task_data_unref); BZ_RELEASE_DATA (unique_id_checksum, g_free)) static DexFuture * read_task_fiber (ReadTaskData *data); static DexFuture * enumerate_disk_fiber (OngoingTaskData *data); static void bz_entry_cache_manager_dispose (GObject *object) { BzEntryCacheManager *self = BZ_ENTRY_CACHE_MANAGER (object); g_mutex_clear (&self->mutex); dex_clear (&self->scheduler); dex_clear (&self->watch_task); g_clear_pointer (&self->task_data, ongoing_task_data_unref); G_OBJECT_CLASS (bz_entry_cache_manager_parent_class)->dispose (object); } static void bz_entry_cache_manager_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzEntryCacheManager *self = BZ_ENTRY_CACHE_MANAGER (object); switch (prop_id) { case PROP_LIVING_ENTRIES: g_value_set_uint (value, bz_entry_cache_manager_get_living_entries (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_entry_cache_manager_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzEntryCacheManager *self = BZ_ENTRY_CACHE_MANAGER (object); (void) self; switch (prop_id) { case PROP_LIVING_ENTRIES: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_entry_cache_manager_class_init (BzEntryCacheManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bz_entry_cache_manager_set_property; object_class->get_property = bz_entry_cache_manager_get_property; object_class->dispose = bz_entry_cache_manager_dispose; props[PROP_LIVING_ENTRIES] = g_param_spec_uint ( "living-entries", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_entry_cache_manager_init (BzEntryCacheManager *self) { static DexScheduler *global_scheduler = NULL; g_autoptr (OngoingTaskData) task_data = NULL; if (g_once_init_enter_pointer (&global_scheduler)) g_once_init_leave_pointer (&global_scheduler, dex_thread_pool_scheduler_new ()); g_mutex_init (&self->mutex); self->scheduler = dex_ref (global_scheduler); self->memory_usage = 0; task_data = ongoing_task_data_new (); task_data->self = bz_track_weak (self); task_data->scheduler = dex_ref (self->scheduler); task_data->init = dex_promise_new (); task_data->alive_hash = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, living_entry_data_unref); task_data->writing_hash = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, dex_unref); task_data->reading_hash = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, dex_unref); for (guint i = 0; i < G_N_ELEMENTS (task_data->ongoing_mutexes); i++) g_mutex_init (&task_data->ongoing_mutexes[i]); g_mutex_init (&task_data->ongoing_queueing_mutex); g_mutex_init (&task_data->alive_mutex); g_mutex_init (&task_data->reading_mutex); g_mutex_init (&task_data->writing_mutex); self->task_data = g_steal_pointer (&task_data); self->watch_task = dex_scheduler_spawn ( self->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) watch_init_fiber, ongoing_task_data_ref (self->task_data), ongoing_task_data_unref); } BzEntryCacheManager * bz_entry_cache_manager_new (void) { return g_object_new (BZ_TYPE_ENTRY_CACHE_MANAGER, NULL); } guint bz_entry_cache_manager_get_living_entries (BzEntryCacheManager *self) { g_autoptr (GMutexLocker) locker = NULL; g_return_val_if_fail (BZ_IS_ENTRY_CACHE_MANAGER (self), 0); locker = g_mutex_locker_new (&self->mutex); return self->living_entries; } DexFuture * bz_entry_cache_manager_add (BzEntryCacheManager *self, BzEntry *entry) { g_autoptr (WriteTaskData) data = NULL; g_autoptr (DexFuture) future = NULL; dex_return_error_if_fail (BZ_IS_ENTRY_CACHE_MANAGER (self)); dex_return_error_if_fail (BZ_IS_ENTRY (entry)); dex_return_error_if_fail (!bz_entry_is_holding (entry)); data = write_task_data_new (); data->task_data = ongoing_task_data_ref (self->task_data); data->unique_id_checksum = g_strdup (bz_entry_get_unique_id_checksum (entry)); data->entry = g_object_ref (entry); future = dex_scheduler_spawn ( self->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) write_task_fiber, write_task_data_ref (data), write_task_data_unref); return g_steal_pointer (&future); } DexFuture * bz_entry_cache_manager_get (BzEntryCacheManager *self, const char *unique_id) { g_autoptr (ReadTaskData) data = NULL; g_autoptr (DexFuture) future = NULL; dex_return_error_if_fail (BZ_IS_ENTRY_CACHE_MANAGER (self)); dex_return_error_if_fail (unique_id != NULL); data = read_task_data_new (); data->task_data = ongoing_task_data_ref (self->task_data); data->unique_id_checksum = g_compute_checksum_for_string (G_CHECKSUM_MD5, unique_id, -1); future = dex_scheduler_spawn ( self->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) read_task_fiber, read_task_data_ref (data), read_task_data_unref); return g_steal_pointer (&future); } DexFuture * bz_entry_cache_manager_get_by_checksum (BzEntryCacheManager *self, const char *unique_id_checksum) { g_autoptr (ReadTaskData) data = NULL; g_autoptr (DexFuture) future = NULL; dex_return_error_if_fail (BZ_IS_ENTRY_CACHE_MANAGER (self)); dex_return_error_if_fail (unique_id_checksum != NULL); data = read_task_data_new (); data->task_data = ongoing_task_data_ref (self->task_data); data->unique_id_checksum = g_strdup (unique_id_checksum); future = dex_scheduler_spawn ( self->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) read_task_fiber, read_task_data_ref (data), read_task_data_unref); return g_steal_pointer (&future); } DexFuture * bz_entry_cache_manager_enumerate_disk (BzEntryCacheManager *self) { g_autoptr (DexFuture) future = NULL; dex_return_error_if_fail (BZ_IS_ENTRY_CACHE_MANAGER (self)); future = dex_scheduler_spawn ( self->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) enumerate_disk_fiber, ongoing_task_data_ref (self->task_data), ongoing_task_data_unref); return g_steal_pointer (&future); } static DexFuture * write_task_fiber (WriteTaskData *data) { OngoingTaskData *task_data = data->task_data; char *unique_id_checksum = data->unique_id_checksum; BzEntry *entry = data->entry; g_autoptr (GError) local_error = NULL; g_autoptr (BzGuard) slot_guard = NULL; g_autoptr (BzGuard) other_guard = NULL; g_autoptr (GMutexLocker) locker = NULL; guint slot_queued = G_MAXUINT; guint slot_index = 0; DexFuture *writing_future = NULL; g_autoptr (LivingEntryData) living = NULL; g_autoptr (DexPromise) promise = NULL; g_autoptr (GVariantBuilder) builder = NULL; g_autoptr (GVariant) variant = NULL; g_autoptr (GBytes) bytes = NULL; gsize bytes_size = 0; gconstpointer bytes_data = 0; g_autofree char *main_cache = NULL; g_autoptr (GFile) parent_file = NULL; g_autofree char *save_file_path = NULL; g_autoptr (GFile) save_file = NULL; gsize existing_contents_size = 0; g_autofree char *existing_contents = NULL; g_autoptr (GFileOutputStream) output = NULL; gssize bytes_written = 0; gboolean result = FALSE; g_autoptr (GError) ret_error = NULL; if (!BZ_IS_FLATPAK_ENTRY (entry)) return dex_future_new_reject ( BZ_ENTRY_CACHE_ERROR, BZ_ENTRY_CACHE_ERROR_CACHE_FAILED, "Entry with unique ID checksum '%s' cannot be " "cached because it is not a flatpak entry", unique_id_checksum); /* Rate limit to reduce competition for resources * when refresh triggers a flood of requests * * Here we make sure to pick the slot with the * least tasks waiting in line */ locker = g_mutex_locker_new (&task_data->ongoing_queueing_mutex); for (guint i = 0; i < G_N_ELEMENTS (task_data->ongoing_gates); i++) { if (task_data->ongoing_queued[i] < slot_queued) { slot_queued = task_data->ongoing_queued[i]; slot_index = i; } } task_data->ongoing_queued[slot_index]++; g_clear_pointer (&locker, g_mutex_locker_free); BZ_BEGIN_GUARD_WITH_CONTEXT (&slot_guard, &task_data->ongoing_mutexes[slot_index], &task_data->ongoing_gates[slot_index]); locker = g_mutex_locker_new (&task_data->ongoing_queueing_mutex); task_data->ongoing_queued[slot_index]--; g_clear_pointer (&locker, g_mutex_locker_free); dex_await (dex_ref (task_data->init), NULL); BZ_BEGIN_GUARD_WITH_CONTEXT (&other_guard, &task_data->writing_mutex, &task_data->writing_gate); { writing_future = g_hash_table_lookup (task_data->writing_hash, unique_id_checksum); if (writing_future != NULL) return dex_future_new_reject ( BZ_ENTRY_CACHE_ERROR, BZ_ENTRY_CACHE_ERROR_CACHE_FAILED, "Entry with unique ID '%s' is already being cached right now", unique_id_checksum); promise = dex_promise_new (); g_hash_table_replace (task_data->writing_hash, g_strdup (unique_id_checksum), dex_ref (promise)); } bz_clear_guard (&other_guard); BZ_BEGIN_GUARD_WITH_CONTEXT (&other_guard, &task_data->alive_mutex, &task_data->alive_gate); { living = g_hash_table_lookup (task_data->alive_hash, unique_id_checksum); if (living != NULL) living_entry_data_ref (living); else { living = living_entry_data_new (); g_weak_ref_init (&living->wr, NULL); g_mutex_init (&living->mutex); living->cached = g_timer_new (); g_hash_table_replace (task_data->alive_hash, g_strdup (unique_id_checksum), living_entry_data_ref (living)); } } bz_clear_guard (&other_guard); BZ_BEGIN_GUARD_WITH_CONTEXT (&other_guard, &living->mutex, &living->gate); { builder = g_variant_builder_new (G_VARIANT_TYPE_VARDICT); bz_serializable_serialize (BZ_SERIALIZABLE (entry), builder); variant = g_variant_builder_end (builder); bytes = g_variant_get_data_as_bytes (variant); bytes_data = g_bytes_get_data (bytes, &bytes_size); main_cache = bz_dup_module_dir (); parent_file = g_file_new_for_path (main_cache); result = g_file_make_directory_with_parents (parent_file, NULL, &local_error); if (!result) { if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS)) g_clear_pointer (&local_error, g_error_free); else { ret_error = g_error_new ( BZ_ENTRY_CACHE_ERROR, BZ_ENTRY_CACHE_ERROR_CACHE_FAILED, "Failed to make parent directory '%s' when caching '%s': %s", main_cache, unique_id_checksum, local_error->message); goto done; } } save_file_path = g_build_filename (main_cache, unique_id_checksum, NULL); save_file = g_file_new_for_path (save_file_path); result = g_file_get_contents ( save_file_path, &existing_contents, &existing_contents_size, NULL); /* Only write if the file has definitely changed */ if (!result || existing_contents_size != bytes_size || memcmp (existing_contents, bytes_data, bytes_size) != 0) { output = g_file_replace ( save_file, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL, &local_error); if (output == NULL) { ret_error = g_error_new ( BZ_ENTRY_CACHE_ERROR, BZ_ENTRY_CACHE_ERROR_CACHE_FAILED, "Failed to open write stream when caching '%s': %s", unique_id_checksum, local_error->message); goto done; } bytes_written = g_output_stream_write_bytes (G_OUTPUT_STREAM (output), bytes, NULL, &local_error); if (bytes_written < 0) { ret_error = g_error_new ( BZ_ENTRY_CACHE_ERROR, BZ_ENTRY_CACHE_ERROR_CACHE_FAILED, "Failed to write data to stream when caching '%s': %s", unique_id_checksum, local_error->message); goto done; } result = g_output_stream_close (G_OUTPUT_STREAM (output), NULL, &local_error); if (!result) { ret_error = g_error_new ( BZ_ENTRY_CACHE_ERROR, BZ_ENTRY_CACHE_ERROR_CACHE_FAILED, "Failed to close stream when caching '%s': %s", unique_id_checksum, local_error->message); goto done; } } g_timer_start (living->cached); } done: bz_clear_guard (&slot_guard); BZ_BEGIN_GUARD_WITH_CONTEXT (&other_guard, &task_data->writing_mutex, &task_data->writing_gate); { if (ret_error != NULL) dex_promise_reject (promise, g_error_copy (ret_error)); else dex_promise_resolve_boolean (promise, TRUE); g_hash_table_remove (task_data->writing_hash, unique_id_checksum); } bz_clear_guard (&other_guard); if (ret_error != NULL) return dex_future_new_for_error (g_steal_pointer (&ret_error)); else return dex_future_new_true (); } static DexFuture * read_task_fiber (ReadTaskData *data) { OngoingTaskData *task_data = data->task_data; char *unique_id_checksum = data->unique_id_checksum; g_autoptr (GError) local_error = NULL; g_autoptr (BzGuard) guard = NULL; g_autoptr (GMutexLocker) locker = NULL; g_autoptr (DexFuture) writing_future = NULL; g_autoptr (LivingEntryData) living = NULL; DexFuture *reading_future = NULL; g_autoptr (DexPromise) promise = NULL; g_autofree char *main_cache = NULL; g_autofree char *path = NULL; g_autoptr (GFile) file = NULL; g_autoptr (GBytes) bytes = NULL; g_autoptr (GVariant) variant = NULL; g_autoptr (BzFlatpakEntry) entry = NULL; gboolean result = FALSE; g_autoptr (GError) ret_error = NULL; dex_await (dex_ref (task_data->init), NULL); BZ_BEGIN_GUARD_WITH_CONTEXT (&guard, &task_data->writing_mutex, &task_data->writing_gate); { writing_future = g_hash_table_lookup (task_data->writing_hash, unique_id_checksum); if (writing_future != NULL) { dex_ref (writing_future); bz_clear_guard (&guard); dex_await (g_steal_pointer (&writing_future), NULL); } } bz_clear_guard (&guard); BZ_BEGIN_GUARD_WITH_CONTEXT (&guard, &task_data->reading_mutex, &task_data->reading_gate); { reading_future = g_hash_table_lookup (task_data->reading_hash, unique_id_checksum); if (reading_future != NULL) return dex_ref (reading_future); promise = dex_promise_new (); g_hash_table_replace (task_data->reading_hash, g_strdup (unique_id_checksum), dex_ref (promise)); } bz_clear_guard (&guard); BZ_BEGIN_GUARD_WITH_CONTEXT (&guard, &task_data->alive_mutex, &task_data->alive_gate); { living = g_hash_table_lookup (task_data->alive_hash, unique_id_checksum); if (living != NULL) { g_autoptr (BzEntry) living_entry = NULL; living_entry_data_ref (living); bz_clear_guard (&guard); BZ_BEGIN_GUARD_WITH_CONTEXT (&guard, &living->mutex, &living->gate); living_entry = g_weak_ref_get (&living->wr); if (living_entry != NULL) { bz_clear_guard (&guard); BZ_BEGIN_GUARD_WITH_CONTEXT (&guard, &task_data->reading_mutex, &task_data->reading_gate); { g_hash_table_remove (task_data->reading_hash, unique_id_checksum); } bz_clear_guard (&guard); dex_promise_resolve_object (promise, g_object_ref (living_entry)); return dex_future_new_for_object (living_entry); } } else { living = living_entry_data_new (); g_weak_ref_init (&living->wr, NULL); g_mutex_init (&living->mutex); living->cached = g_timer_new (); g_hash_table_replace (task_data->alive_hash, g_strdup (unique_id_checksum), living_entry_data_ref (living)); bz_clear_guard (&guard); BZ_BEGIN_GUARD_WITH_CONTEXT (&guard, &living->mutex, &living->gate); } } /* living data was guarded */ main_cache = bz_dup_module_dir (); path = g_build_filename (main_cache, unique_id_checksum, NULL); file = g_file_new_for_path (path); bytes = g_file_load_bytes (file, NULL, NULL, &local_error); if (bytes == NULL) { ret_error = g_error_new ( BZ_ENTRY_CACHE_ERROR, BZ_ENTRY_CACHE_ERROR_DECACHE_FAILED, "Failed to de-cache variant from file: %s", local_error->message); goto done; } variant = g_variant_new_from_bytes (G_VARIANT_TYPE_VARDICT, bytes, FALSE); if (variant == NULL) { ret_error = g_error_new ( BZ_ENTRY_CACHE_ERROR, BZ_ENTRY_CACHE_ERROR_DECACHE_FAILED, "Failed to interpret variant from %s: %s", path, local_error->message); goto done; } entry = g_object_new (BZ_TYPE_FLATPAK_ENTRY, NULL); result = bz_serializable_deserialize (BZ_SERIALIZABLE (entry), variant, &local_error); if (!result) { ret_error = g_error_new ( BZ_ENTRY_CACHE_ERROR, BZ_ENTRY_CACHE_ERROR_DECACHE_FAILED, "Failed to deserialize entry from %s: %s", path, local_error->message); goto done; } g_weak_ref_init (&living->wr, entry); done: BZ_BEGIN_GUARD_WITH_CONTEXT (&guard, &task_data->reading_mutex, &task_data->reading_gate); { if (ret_error != NULL) dex_promise_reject (promise, g_error_copy (ret_error)); else dex_promise_resolve_object (promise, g_object_ref (entry)); g_hash_table_remove (task_data->reading_hash, unique_id_checksum); } bz_clear_guard (&guard); if (ret_error != NULL) return dex_future_new_for_error (g_steal_pointer (&ret_error)); else return dex_future_new_for_object (entry); } static DexFuture * enumerate_disk_fiber (OngoingTaskData *data) { g_autoptr (GError) local_error = NULL; g_autoptr (BzGuard) guard = NULL; g_autoptr (GHashTable) set = NULL; g_autofree char *main_cache = NULL; g_autoptr (GFile) main_cache_file = NULL; g_autoptr (GFileEnumerator) enumerator = NULL; set = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); BZ_BEGIN_GUARD_WITH_CONTEXT (&guard, &data->alive_mutex, &data->alive_gate); BZ_BEGIN_GUARD_WITH_CONTEXT (&guard, &data->reading_mutex, &data->reading_gate); BZ_BEGIN_GUARD_WITH_CONTEXT (&guard, &data->writing_mutex, &data->writing_gate); main_cache = bz_dup_module_dir (); if (!g_file_test (main_cache, G_FILE_TEST_EXISTS)) goto done; main_cache_file = g_file_new_for_path (main_cache); enumerator = g_file_enumerate_children ( main_cache_file, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK "," G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error); if (enumerator == NULL) return dex_future_new_reject ( BZ_ENTRY_CACHE_ERROR, BZ_ENTRY_CACHE_ERROR_ENUMERATE_FAILED, "Could not initialize directory enumerator at %s: %s", main_cache, local_error->message); for (;;) { g_autoptr (GFileInfo) info = NULL; g_autoptr (GFile) child = NULL; g_autofree char *basename = NULL; info = g_file_enumerator_next_file (enumerator, NULL, &local_error); if (info == NULL) { if (local_error != NULL) return dex_future_new_reject ( BZ_ENTRY_CACHE_ERROR, BZ_ENTRY_CACHE_ERROR_ENUMERATE_FAILED, "Could not enumerate children of cache directory at %s: %s", main_cache, local_error->message); else break; } child = g_file_enumerator_get_child (enumerator, info); if (g_file_info_get_is_symlink (info) || g_file_info_get_file_type (info) != G_FILE_TYPE_REGULAR) continue; basename = g_file_get_basename (child); if (basename != NULL) g_hash_table_replace (set, g_steal_pointer (&basename), NULL); } done: return dex_future_new_take_boxed (G_TYPE_HASH_TABLE, g_steal_pointer (&set)); } static DexFuture * watch_init_fiber (OngoingTaskData *task_data) { // bz_discard_module_dir (); dex_promise_resolve_boolean (task_data->init, TRUE); return dex_future_finally_loop ( dex_timeout_new_msec (WATCH_CLEANUP_INTERVAL_MSEC), (DexFutureCallback) watch_cb, ongoing_task_data_ref (task_data), ongoing_task_data_unref); } static DexFuture * watch_cb (DexFuture *future, OngoingTaskData *task_data) { return dex_scheduler_spawn ( task_data->scheduler, bz_get_dex_stack_size (), (DexFiberFunc) watch_work_fiber, ongoing_task_data_ref (task_data), ongoing_task_data_unref); } static DexFuture * watch_work_fiber (OngoingTaskData *task_data) { g_autoptr (BzEntryCacheManager) self = NULL; g_autoptr (BzGuard) guard0 = NULL; GHashTableIter iter = { 0 }; g_autoptr (GTimer) timer = NULL; guint total = 0; guint active = 0; guint alive = 0; guint pruned = 0; timer = g_timer_new (); BZ_BEGIN_GUARD_WITH_CONTEXT (&guard0, &task_data->alive_mutex, &task_data->alive_gate); BZ_BEGIN_GUARD_WITH_CONTEXT (&guard0, &task_data->reading_mutex, &task_data->reading_gate); BZ_BEGIN_GUARD_WITH_CONTEXT (&guard0, &task_data->writing_mutex, &task_data->writing_gate); g_hash_table_iter_init (&iter, task_data->alive_hash); for (;;) { char *unique_id_checksum = NULL; LivingEntryData *living = NULL; g_autoptr (BzGuard) guard1 = NULL; g_autoptr (BzEntry) entry = NULL; if (!g_hash_table_iter_next (&iter, (gpointer *) &unique_id_checksum, (gpointer *) &living)) break; total++; if (g_hash_table_contains (task_data->reading_hash, unique_id_checksum) || g_hash_table_contains (task_data->writing_hash, unique_id_checksum)) { active++; continue; } BZ_BEGIN_GUARD_WITH_CONTEXT (&guard1, &living->mutex, &living->gate); entry = g_weak_ref_get (&living->wr); if (entry != NULL) alive++; else { bz_clear_guard (&guard1); g_hash_table_iter_remove (&iter); pruned++; } } bz_clear_guard (&guard0); #ifdef __GLIBC__ malloc_trim (0); #endif g_debug ("Sweep report: finished in %.4f seconds, including time to acquire guards\n" " Out of a total of %d entries considered:\n" " %d were skipped due to active tasks being associated with them\n" " %d application entries were otherwise kept alive\n" " %d entries were forgotten by the application and were pruned\n" " Another sweep will take place in %d msec", g_timer_elapsed (timer, NULL), total, active, alive, pruned, WATCH_CLEANUP_INTERVAL_MSEC); bz_weak_get_or_return_reject (self, task_data->self); g_mutex_lock (&self->mutex); self->living_entries = active + alive; g_mutex_unlock (&self->mutex); dex_future_disown (dex_scheduler_spawn ( dex_scheduler_get_default (), bz_get_dex_stack_size (), (DexFiberFunc) notify_props_fiber, bz_track_weak (self), bz_weak_release)); return dex_timeout_new_msec (WATCH_CLEANUP_INTERVAL_MSEC); } static DexFuture * notify_props_fiber (GWeakRef *wr) { g_autoptr (BzEntryCacheManager) self = NULL; bz_weak_get_or_return_reject (self, wr); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_LIVING_ENTRIES]); return dex_future_new_true (); } /* End of bz-entry-cache-manager.c */ bazaar-orig-v0.7.14/src/bz-pride-flag-spec.txt0000664000175000017500000000063115166123241020043 0ustar hasanhasanprefix=bz name=pride_flag_spec parent-prefix=g parent-name=object author=AUTOGEN include= include="bz-pride-flag-stripe-spec.h" ensure=BZ_TYPE_PRIDE_FLAG_STRIPE_SPEC property=id char G_TYPE_STRING string property=name char G_TYPE_STRING string property=homogeneous gboolean G_TYPE_BOOLEAN boolean property=direction char G_TYPE_STRING string property=stripes GListModel G_TYPE_LIST_MODEL object bazaar-orig-v0.7.14/src/bz-featured-carousel.c0000664000175000017500000002773315166123241020132 0ustar hasanhasan/* bz-featured-carousel.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-entry-group.h" #include "bz-featured-carousel.h" #include "bz-featured-tile.h" #include "bz-template-callbacks.h" #define FEATURED_ROTATE_TIME 5 #define MANUAL_ROTATE_RECOVER_TIME 7.5 struct _BzFeaturedCarousel { GtkBox parent_instance; GListModel *model; gboolean is_aotd; guint rotation_timer_source; GTimer *time_since_manual_rotate; BgeCarousel *carousel; GtkSingleSelection *selection; GtkButton *next_button; GtkButton *previous_button; }; G_DEFINE_FINAL_TYPE (BzFeaturedCarousel, bz_featured_carousel, GTK_TYPE_BOX) enum { PROP_0, PROP_MODEL, PROP_IS_AOTD, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { NULL, }; static void update_buttons_for_tile (BzFeaturedCarousel *self) { GtkWidget *child = NULL; const char *class_name = NULL; guint index = 0; index = gtk_single_selection_get_selected (self->selection); child = bge_carousel_get_nth_page (self->carousel, index); if (child == NULL) return; class_name = gtk_widget_has_css_class (child, "flathub-lotion") ? "flathub-lotion" : "flathub-gunmetal"; gtk_widget_remove_css_class (GTK_WIDGET (self->next_button), "flathub-lotion"); gtk_widget_remove_css_class (GTK_WIDGET (self->next_button), "flathub-gunmetal"); gtk_widget_remove_css_class (GTK_WIDGET (self->previous_button), "flathub-lotion"); gtk_widget_remove_css_class (GTK_WIDGET (self->previous_button), "flathub-gunmetal"); gtk_widget_add_css_class (GTK_WIDGET (self->next_button), class_name); gtk_widget_add_css_class (GTK_WIDGET (self->previous_button), class_name); } static void on_style_changed (AdwStyleManager *style_manager, GParamSpec *pspec, BzFeaturedCarousel *self) { g_idle_add_once ((GSourceOnceFunc) update_buttons_for_tile, self); } static void on_notify_selected (BzFeaturedCarousel *self, GParamSpec *pspec, GtkSingleSelection *selection) { g_timer_start (self->time_since_manual_rotate); update_buttons_for_tile (self); } static void show_relative_page (BzFeaturedCarousel *self, gint delta, gboolean use_custom_spring) { guint n_pages; guint current_page; guint new_page; n_pages = g_list_model_get_n_items (G_LIST_MODEL (self->selection)); if (n_pages == 0) return; current_page = gtk_single_selection_get_selected (self->selection); new_page = (n_pages + current_page + delta) % n_pages; g_signal_handlers_block_by_func (self->selection, on_notify_selected, self); gtk_single_selection_set_selected (self->selection, new_page); g_signal_handlers_unblock_by_func (self->selection, on_notify_selected, self); update_buttons_for_tile (self); } static gboolean rotate_cb (gpointer user_data) { BzFeaturedCarousel *self = BZ_FEATURED_CAROUSEL (user_data); double elapsed = 0.0; elapsed = g_timer_elapsed (self->time_since_manual_rotate, NULL); if (elapsed > MANUAL_ROTATE_RECOVER_TIME) show_relative_page (self, +1, TRUE); return G_SOURCE_CONTINUE; } static void next_button_clicked_cb (GtkButton *button, gpointer user_data) { BzFeaturedCarousel *self; self = BZ_FEATURED_CAROUSEL (user_data); show_relative_page (self, +1, FALSE); } static void previous_button_clicked_cb (GtkButton *button, gpointer user_data) { BzFeaturedCarousel *self; self = BZ_FEATURED_CAROUSEL (user_data); show_relative_page (self, -1, FALSE); } static void tile_clicked_cb (BzFeaturedTile *tile, gpointer user_data) { BzEntryGroup *group = NULL; group = bz_featured_tile_get_group (tile); gtk_widget_activate_action (GTK_WIDGET (user_data), "window.show-group", "s", bz_entry_group_get_id (group)); } static gboolean key_pressed_cb (GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, BzFeaturedCarousel *self) { if (gtk_widget_is_visible (GTK_WIDGET (self->previous_button)) && gtk_widget_is_sensitive (GTK_WIDGET (self->previous_button)) && ((gtk_widget_get_direction (GTK_WIDGET (self->previous_button)) == GTK_TEXT_DIR_LTR && keyval == GDK_KEY_Left) || (gtk_widget_get_direction (GTK_WIDGET (self->previous_button)) == GTK_TEXT_DIR_RTL && keyval == GDK_KEY_Right))) { gtk_widget_activate (GTK_WIDGET (self->previous_button)); return GDK_EVENT_STOP; } if (gtk_widget_is_visible (GTK_WIDGET (self->next_button)) && gtk_widget_is_sensitive (GTK_WIDGET (self->next_button)) && ((gtk_widget_get_direction (GTK_WIDGET (self->next_button)) == GTK_TEXT_DIR_LTR && keyval == GDK_KEY_Right) || (gtk_widget_get_direction (GTK_WIDGET (self->next_button)) == GTK_TEXT_DIR_RTL && keyval == GDK_KEY_Left))) { gtk_widget_activate (GTK_WIDGET (self->next_button)); return GDK_EVENT_STOP; } return GDK_EVENT_PROPAGATE; } static void bz_featured_carousel_dispose (GObject *object) { BzFeaturedCarousel *self = BZ_FEATURED_CAROUSEL (object); g_signal_handlers_disconnect_by_func (adw_style_manager_get_default (), on_style_changed, self); g_clear_handle_id (&self->rotation_timer_source, g_source_remove); g_clear_pointer (&self->time_since_manual_rotate, g_timer_destroy); g_clear_object (&self->model); G_OBJECT_CLASS (bz_featured_carousel_parent_class)->dispose (object); } static void bz_featured_carousel_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzFeaturedCarousel *self; self = BZ_FEATURED_CAROUSEL (object); switch (prop_id) { case PROP_MODEL: g_value_set_object (value, bz_featured_carousel_get_model (self)); break; case PROP_IS_AOTD: g_value_set_boolean (value, bz_featured_carousel_get_is_aotd (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void bz_featured_carousel_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzFeaturedCarousel *self; self = BZ_FEATURED_CAROUSEL (object); switch (prop_id) { case PROP_MODEL: bz_featured_carousel_set_model (self, g_value_get_object (value)); break; case PROP_IS_AOTD: bz_featured_carousel_set_is_aotd (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GtkWidget * on_create_widget (BzFeaturedCarousel *self, BzEntryGroup *group, BgeCarousel *carousel) { BzFeaturedTile *tile = NULL; tile = bz_featured_tile_new (group); g_object_bind_property (self, "is-aotd", tile, "is-aotd", G_BINDING_SYNC_CREATE); gtk_widget_set_hexpand (GTK_WIDGET (tile), TRUE); gtk_widget_set_vexpand (GTK_WIDGET (tile), TRUE); gtk_widget_set_can_focus (GTK_WIDGET (tile), FALSE); g_signal_connect (tile, "clicked", G_CALLBACK (tile_clicked_cb), self); return GTK_WIDGET (tile); } static void on_remove_widget (BzFeaturedCarousel *self, BzFeaturedTile *tile, BzEntryGroup *group, BgeCarousel *carousel) { } static void bz_featured_carousel_class_init (BzFeaturedCarouselClass *klass) { GObjectClass *object_class; GtkWidgetClass *widget_class; object_class = G_OBJECT_CLASS (klass); widget_class = GTK_WIDGET_CLASS (klass); object_class->get_property = bz_featured_carousel_get_property; object_class->set_property = bz_featured_carousel_set_property; object_class->dispose = bz_featured_carousel_dispose; props[PROP_MODEL] = g_param_spec_object ("model", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); props[PROP_IS_AOTD] = g_param_spec_boolean ("is-aotd", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-featured-carousel.ui"); gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP); bz_widget_class_bind_all_util_callbacks (widget_class); gtk_widget_class_bind_template_child (widget_class, BzFeaturedCarousel, carousel); gtk_widget_class_bind_template_child (widget_class, BzFeaturedCarousel, selection); gtk_widget_class_bind_template_child (widget_class, BzFeaturedCarousel, next_button); gtk_widget_class_bind_template_child (widget_class, BzFeaturedCarousel, previous_button); gtk_widget_class_bind_template_callback (widget_class, on_create_widget); gtk_widget_class_bind_template_callback (widget_class, on_remove_widget); gtk_widget_class_bind_template_callback (widget_class, on_notify_selected); gtk_widget_class_bind_template_callback (widget_class, next_button_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, previous_button_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, key_pressed_cb); } static void bz_featured_carousel_init (BzFeaturedCarousel *self) { gtk_widget_init_template (GTK_WIDGET (self)); self->rotation_timer_source = g_timeout_add_seconds ( FEATURED_ROTATE_TIME, rotate_cb, self); self->time_since_manual_rotate = g_timer_new (); g_signal_connect (adw_style_manager_get_default (), "notify::dark", G_CALLBACK (on_style_changed), self); } BzFeaturedCarousel * bz_featured_carousel_new (void) { return g_object_new (BZ_TYPE_FEATURED_CAROUSEL, NULL); } GListModel * bz_featured_carousel_get_model (BzFeaturedCarousel *self) { g_return_val_if_fail (BZ_IS_FEATURED_CAROUSEL (self), NULL); return self->model; } void bz_featured_carousel_set_model (BzFeaturedCarousel *self, GListModel *model) { g_return_if_fail (BZ_IS_FEATURED_CAROUSEL (self)); g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model)); if (model != NULL && model == self->model) return; g_clear_object (&self->model); if (model != NULL) self->model = g_object_ref (model); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MODEL]); } gboolean bz_featured_carousel_get_is_aotd (BzFeaturedCarousel *self) { g_return_val_if_fail (BZ_IS_FEATURED_CAROUSEL (self), FALSE); return self->is_aotd; } void bz_featured_carousel_set_is_aotd (BzFeaturedCarousel *self, gboolean is_aotd) { g_return_if_fail (BZ_IS_FEATURED_CAROUSEL (self)); if (self->is_aotd == is_aotd) return; self->is_aotd = is_aotd; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_IS_AOTD]); } bazaar-orig-v0.7.14/src/internal-config.yaml0000664000175000017500000000313615166123241017675 0ustar hasanhasansearch-biases: # Brief regex review: # `^` indicates the beginning of the string # `$` indicates the end of the string # `\b` indicates a word boundary # `(?i)` means case insensitive - regex: ^(?i)browser$ convert-to: web browser boost-appids: - app.zen_browser.zen - io.github.ungoogled_software.ungoogled_chromium - org.chromium.Chromium - org.gnome.Epiphany - org.kde.falkon - org.mozilla.firefox - org.torproject.torbrowser-launcher linear-boost: slope: 1.333 y-intercept: 40.0 - regex: \b(?i)vm\b convert-to: virtual machine boost-appids: - org.virt_manager.virt-manager - org.gnome.Boxes linear-boost: slope: 1.0 y-intercept: 50.0 - regex: \b(?i)ide\b convert-to: develop boost-appids: - com.visualstudio.code - com.vscodium.codium - dev.zed.Zed - org.gnome.Builder - org.kde.kdevelop linear-boost: slope: 1.0 y-intercept: 10.0 - regex: \b(?i)daw\b boost-appids: # these don't normally show, despite being DAWs - fm.reaper.Reaper - io.lmms.LMMS linear-boost: slope: 1.0 y-intercept: 20.0 - regex: \b(?i)photoshop\b boost-appids: - org.gimp.GIMP linear-boost: slope: 1.0 y-intercept: 20.0 - regex: \b(?i)illustrator\b boost-appids: - org.inkscape.Inkscape linear-boost: slope: 1.0 y-intercept: 20.0 - regex: \b(?i)dl\b convert-to: download - regex: \b(?i)yt\b convert-to: youtube - regex: \b(?i)vids?\b convert-to: video bazaar-orig-v0.7.14/src/bz-addons-dialog.blp0000664000175000017500000003346715166123241017561 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzAddonsDialog: Adw.Dialog { content-width: 500; content-height: 550; child: Adw.ToastOverlay { child:Adw.NavigationView navigation_view { notify::visible-page-tag => $on_visible_page_tag_changed(); Adw.NavigationPage { tag: "list"; title: _("Manage Add-Ons"); child: Adw.ToolbarView { [top] Adw.HeaderBar { title-widget: Label { styles ["heading"] label: _("Manage Add-Ons"); }; } content: ScrolledWindow { propagate-natural-height: true; vexpand: true; hscrollbar-policy: never; child: Adw.Clamp list_clamp { maximum-size: 450; tightening-threshold: 500; margin-start: 6; margin-end: 6; margin-bottom: 12; child: ListView { styles [ "navigation-sidebar", "installed-list-view", ] model: NoSelection { model: SortListModel { sorter: CustomSorter sorter {}; model: bind template.addon-groups; }; }; factory: BuilderListItemFactory { template ListItem { activatable: false; selectable: false; focusable: false; child: $BzAddonTile { group: bind template.item as <$BzEntryGroup>; activated => $tile_activated_cb(); }; } }; }; }; }; }; } Adw.NavigationPage { tag: "empty"; title: _("Manage Add-Ons"); child: Adw.ToolbarView { [top] Adw.HeaderBar { show-title: false; } content: Adw.StatusPage { icon-name: "application-x-addon-symbolic"; title: _("No Add-Ons Visible"); description: _("Your current filter preferences are hiding all known add-ons. Try adjusting them."); }; }; } Adw.NavigationPage { tag: "full-view"; title: bind try { template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.title, _("Add-on Page") }; child: Adw.ToolbarView { [top] Adw.HeaderBar { show-title: false; } content: ScrolledWindow { vexpand: true; hscrollbar-policy: never; child: Adw.Clamp { maximum-size: 450; tightening-threshold: 500; margin-start: 12; margin-end: 12; child: Box full_view_clamp { orientation: vertical; spacing: 4; margin-top: 12; Box { halign: center; spacing: 8; orientation: vertical; margin-bottom: 12; Image { pixel-size: 96; paintable: bind template.parent-ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable; visible: bind $invert_boolean($is_null(template.parent-ui-entry as <$BzResult>.object as <$BzEntry>.icon-paintable) as ) as ; styles ["icon-dropshadow"] } Box { orientation: vertical; valign: center; halign: center; spacing: 2; margin-bottom: 8; Label { label: bind template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.title; justify: center; max-width-chars: 25; wrap: true; wrap-mode: word_char; styles ["title-3"] } Label { label: bind $format_parent_title(template.parent-ui-entry as <$BzResult>.object as <$BzEntry>.title) as ; justify: center; styles ["dim-label"] } } } Box { homogeneous: true; margin-bottom: 12; orientation: horizontal; halign: fill; styles ["app-context-bar"] $BzContextTile { label: bind $get_size_label($is_zero(template.selected-group as <$BzEntryGroup>.removable) as ) as ; clicked => $size_cb(template); has-tooltip: true; tooltip-text: bind $format_size_tooltip(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.size) as ; lozenge-style: "grey"; sensitive: bind $invert_boolean($is_zero($get_size_type(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>, $is_zero(template.selected-group as <$BzEntryGroup>.removable) as ) as ) as ) as ; lozenge-child: Label { justify: center; label: bind $format_size($get_size_type(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>, $is_zero(template.selected-group as <$BzEntryGroup>.removable) as ) as ) as ; lines: 3; ellipsize: end; halign: center; wrap: true; xalign: 0.5; use-markup: true; }; } $BzContextTile { label: bind $get_license_label(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>) as ; clicked => $license_cb(template); lozenge-style: bind $bool_to_string(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.is-floss, "grey", "warning") as ; has-tooltip: true; tooltip-text: bind $format_license_tooltip(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>) as ; lozenge-child: Box { spacing: 6; Image { icon-name: bind $get_license_icon(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.is-floss, 0) as ; } Image { icon-name: bind $get_license_icon(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.is-floss, 1) as ; } }; } $BzContextTile { can-target: bind $invert_boolean($is_null(template.selected-ui-entry) as ) as ; sensitive: bind $invert_boolean($is_null(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.recent-downloads) as ) as ; label: _("Downloads/Month"); clicked => $dl_stats_cb(template); has-tooltip: bind $invert_boolean($is_null(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.recent-downloads) as ) as ; tooltip-text: bind $format_recent_downloads_tooltip(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.recent-downloads) as ; lozenge-style: "grey"; lozenge-child: Label { justify: center; label: bind $format_recent_downloads(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.recent-downloads) as ; halign: center; use-markup: true; }; } } Box { visible: bind $invert_boolean($is_null(template.selected-group as <$BzEntryGroup>.eol) as ) as ; orientation: vertical; spacing: 8; styles [ "card", "colored", "warning", ] Label { label: _("Stopped Receiving Core Updates"); margin-top: 8; margin-start: 8; margin-end: 8; wrap: true; wrap-mode: word_char; justify: center; styles [ "title-4", ] } Label { label: _("This add-on uses a runtime that no longer receives updates or security fixes. It may become unsafe to use."); margin-bottom: 8; margin-start: 8; margin-end: 8; wrap: true; wrap-mode: word_char; justify: center; } } Label { visible: bind $logical_and($invert_boolean($is_null(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.description) as ) as , $is_null(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.long-description) as ) as ; label: bind template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.description; wrap: true; wrap-mode: word_char; justify: center; halign: center; margin-bottom: 6; styles ["dimmed"] } Stack { transition-type: crossfade; halign: center; margin-top: 6; margin-bottom: 8; visible-child-name: bind $get_install_stack_page(template.selected-group as <$BzEntryGroup>.installable, template.selected-group as <$BzEntryGroup>.removable) as ; StackPage { name: "install"; child: Button { margin-top: 6; margin-bottom: 6; margin-start: 6; margin-end: 6; styles ["pill", "suggested-action"] label: _("Install"); sensitive: bind $invert_boolean($is_zero(template.selected-group as <$BzEntryGroup>.installable-and-available) as ) as ; clicked => $install_cb(); }; } StackPage { name: "open"; child: Box { spacing: 8; margin-top: 6; margin-bottom: 6; margin-start: 6; margin-end: 6; Button { styles ["pill"] label: _("Open"); sensitive: bind $invert_boolean($is_zero(template.selected-group as <$BzEntryGroup>.removable-and-available) as ) as ; clicked => $run_cb(); } Button { styles ["pill", "destructive-action"] label: _("Remove"); sensitive: bind $invert_boolean($is_zero(template.selected-group as <$BzEntryGroup>.removable-and-available) as ) as ; clicked => $remove_cb(); } }; } StackPage { name: "empty"; child: Adw.Bin {}; } } Label { visible: bind $logical_and($invert_boolean($is_null(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.description) as ) as , $invert_boolean($is_null(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.long-description) as ) as ) as ; label: bind template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.description; wrap: true; wrap-mode: word_char; xalign: 0; halign: fill; margin-top: 12; margin-bottom: 4; styles ["title-4"] } $BzFadingClamp fading_clamp { visible: bind $invert_boolean($is_null(template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.long-description) as ) as ; max-height: bind $get_description_max_height(description_toggle.active) as ; min-max-height: 170; child: $BzAppstreamDescriptionRender { appstream-description: bind template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.long-description; }; } ToggleButton description_toggle { styles ["circular"] visible: bind fading_clamp.will-change; halign: center; child: Label { label: bind $get_description_toggle_text(description_toggle.active) as ; margin-start: 16; margin-end: 16; }; margin-bottom: 12; } $BzShareList { urls: bind template.selected-ui-entry as <$BzResult>.object as <$BzEntry>.share-urls; margin-bottom: 24; } }; }; }; }; } }; }; }bazaar-orig-v0.7.14/src/bz-category-tile.c0000664000175000017500000001075315166123241017262 0ustar hasanhasan/* bz-category-tile.c * * Copyright 2025 Adam Masciola, Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-category-tile.h" struct _BzCategoryTile { GtkButton parent_instance; BzFlathubCategory *category; }; G_DEFINE_FINAL_TYPE (BzCategoryTile, bz_category_tile, GTK_TYPE_BUTTON); enum { PROP_0, PROP_CATEGORY, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void bz_category_tile_dispose (GObject *object) { BzCategoryTile *self = BZ_CATEGORY_TILE (object); g_clear_object (&self->category); G_OBJECT_CLASS (bz_category_tile_parent_class)->dispose (object); } static void bz_category_tile_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzCategoryTile *self = BZ_CATEGORY_TILE (object); switch (prop_id) { case PROP_CATEGORY: g_value_set_object (value, bz_category_tile_get_category (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_category_tile_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzCategoryTile *self = BZ_CATEGORY_TILE (object); switch (prop_id) { case PROP_CATEGORY: bz_category_tile_set_category (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static gboolean is_null (gpointer object, GObject *value) { return value == NULL; } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static void bz_category_tile_class_init (BzCategoryTileClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bz_category_tile_set_property; object_class->get_property = bz_category_tile_get_property; object_class->dispose = bz_category_tile_dispose; props[PROP_CATEGORY] = g_param_spec_object ( "category", NULL, NULL, BZ_TYPE_FLATHUB_CATEGORY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-category-tile.ui"); gtk_widget_class_bind_template_callback (widget_class, is_null); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); } static void bz_category_tile_init (BzCategoryTile *self) { gtk_widget_init_template (GTK_WIDGET (self)); gtk_widget_add_css_class (GTK_WIDGET (self), "category-tile"); } GtkWidget * bz_category_tile_new (void) { return g_object_new (BZ_TYPE_CATEGORY_TILE, NULL); } BzFlathubCategory * bz_category_tile_get_category (BzCategoryTile *self) { g_return_val_if_fail (BZ_IS_CATEGORY_TILE (self), NULL); return self->category; } void bz_category_tile_set_category (BzCategoryTile *self, BzFlathubCategory *category) { const char *category_name; g_autofree char *css_class = NULL; g_return_if_fail (BZ_IS_CATEGORY_TILE (self)); g_clear_object (&self->category); if (category != NULL) { self->category = g_object_ref (category); category_name = bz_flathub_category_get_name (category); if (category_name != NULL) { g_autofree char *lowercase_name = g_ascii_strdown (category_name, -1); css_class = g_strdup_printf ("category-%s", lowercase_name); g_strdelimit (css_class, " &/", '-'); gtk_widget_add_css_class (GTK_WIDGET (self), css_class); } } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CATEGORY]); }bazaar-orig-v0.7.14/src/bz-addon-tile.blp0000664000175000017500000000535515166123241017067 0ustar hasanhasanusing Gtk 4.0; template $BzAddonTile: $BzListTile { accessibility { labelled-by: title_label; described-by: description_label; } child: Box { orientation: horizontal; spacing: 10; height-request: 64; Box { orientation: vertical; valign: center; spacing: 4; margin-start: 10; Label title_label { xalign: 0.0; ellipsize: end; single-line-mode: true; has-tooltip: true; tooltip-text: bind template.group as <$BzEntryGroup>.id; label: bind template.group as <$BzEntryGroup>.title; } Label description_label { halign: start; label: bind template.group as <$BzEntryGroup>.description; visible: bind $logical_and($invert_boolean(eol_label.visible) as , $invert_boolean($is_empty(template.group as <$BzEntryGroup>.description) as ) as ) as ; xalign: 0.0; ellipsize: end; single-line-mode: true; styles ["dim-label", "caption"] } Label eol_label{ visible: bind $invert_boolean($is_null(template.group as <$BzEntryGroup>.eol) as ) as ; wrap: true; wrap-mode: word_char; ellipsize: end; vexpand: true; lines: 2; single-line-mode: true; halign: start; hexpand: true; label: _("Stopped Receiving Updates"); styles [ "warning", ] } } Box { orientation: horizontal; spacing: 8; margin-end: 8; hexpand: true; halign: end; Button install_remove_button { styles ["flat"] width-request: 32; height-request: 32; valign: center; has-tooltip: true; visible: bind $invert_boolean($logical_and($is_zero(template.group as <$BzEntryGroup>.removable) as , $is_zero(template.group as <$BzEntryGroup>.installable) as ) as ) as ; tooltip-text: bind $get_install_remove_tooltip(template.group as <$BzEntryGroup>.removable) as ; sensitive: bind $switch_bool( template.group as <$BzEntryGroup>.removable, $invert_boolean($is_zero(template.group as <$BzEntryGroup>.removable-and-available) as ) as , $invert_boolean($is_zero(template.group as <$BzEntryGroup>.installable-and-available) as ) as , ) as ; icon-name: bind $get_install_remove_icon(template.group as <$BzEntryGroup>.removable) as ; clicked => $install_remove_cb() swapped; } Image { pixel-size: 14; icon-name: "go-next-symbolic"; margin-end: 4; styles ["dimmed"] } } }; }bazaar-orig-v0.7.14/src/bz-io.h0000664000175000017500000000467015166123241015127 0ustar hasanhasan/* bz-io.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include G_BEGIN_DECLS char * bz_dup_user_data_path (const char *app_id); DexScheduler * bz_get_io_scheduler (void); void bz_reap_file (GFile *file); void bz_reap_path (const char *path); DexFuture * bz_reap_file_dex (GFile *file); DexFuture * bz_reap_path_dex (const char *path); DexFuture * bz_reap_user_data_dex (const char *app_id); DexFuture * bz_get_user_data_size_dex (const char *app_id); DexFuture * bz_get_user_data_ids_dex (void); char * bz_dup_root_cache_dir (void); char * bz_dup_cache_dir (const char *submodule); #define bz_dup_module_dir() bz_dup_cache_dir (BAZAAR_MODULE) #define bz_discard_path(_path) \ G_STMT_START \ { \ if (g_file_test ((_path), G_FILE_TEST_IS_DIR)) \ bz_reap_path ((_path)); \ else if (g_file_test ((_path), G_FILE_TEST_EXISTS)) \ { \ g_autoptr (GFile) file = NULL; \ \ file = g_file_new_for_path ((_path)); \ g_file_delete (file, NULL, NULL); \ } \ } \ G_STMT_END #define bz_discard_module_dir() \ G_STMT_START \ { \ g_autofree char *_path = NULL; \ \ _path = bz_dup_module_dir (); \ bz_discard_path (_path); \ } \ G_STMT_END G_END_DECLS bazaar-orig-v0.7.14/src/bz-fading-clamp.c0000664000175000017500000002750215166123241017034 0ustar hasanhasan/* bz-fading-clamp.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-fading-clamp.h" #include "bz-util.h" #define FADE_HEIGHT 75 #define CLAMP_LEEWAY 100 struct _BzFadingClamp { GtkWidget parent_instance; BgeAnimation *animation; GtkWidget *child; int max_height; int min_max_height; int current_height; int allocated_width; gboolean animating_max_height; gboolean will_change; }; enum { PROP_0, PROP_CHILD, PROP_MAX_HEIGHT, PROP_MIN_MAX_HEIGHT, PROP_WILL_CHANGE, N_PROPS }; static GParamSpec *properties[N_PROPS]; G_DEFINE_TYPE (BzFadingClamp, bz_fading_clamp, GTK_TYPE_WIDGET) static void animate (BzFadingClamp *self, const char *key, double value, gpointer user_data) { self->current_height = round (value); gtk_widget_queue_resize (GTK_WIDGET (self)); } static DexFuture * animation_finally (DexFuture *future, GWeakRef *wr) { g_autoptr (BzFadingClamp) self = NULL; bz_weak_get_or_return_reject (self, wr); self->animating_max_height = FALSE; return dex_future_new_true (); } static void bz_fading_clamp_update_will_change (BzFadingClamp *self) { gboolean new_value = FALSE; int natural_height; int width; if (self->child) { if (self->allocated_width > 0) width = self->allocated_width; else gtk_widget_measure (self->child, GTK_ORIENTATION_HORIZONTAL, -1, NULL, &width, NULL, NULL); gtk_widget_measure (self->child, GTK_ORIENTATION_VERTICAL, width, NULL, &natural_height, NULL, NULL); new_value = natural_height > self->min_max_height + CLAMP_LEEWAY; } if (self->will_change != new_value) { self->will_change = new_value; g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_WILL_CHANGE]); } } static void bz_fading_clamp_dispose (GObject *object) { BzFadingClamp *self = BZ_FADING_CLAMP (object); g_clear_object (&self->animation); g_clear_pointer (&self->child, gtk_widget_unparent); G_OBJECT_CLASS (bz_fading_clamp_parent_class)->dispose (object); } static void bz_fading_clamp_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzFadingClamp *self = BZ_FADING_CLAMP (object); switch (prop_id) { case PROP_CHILD: g_value_set_object (value, self->child); break; case PROP_MAX_HEIGHT: g_value_set_int (value, self->max_height); break; case PROP_MIN_MAX_HEIGHT: g_value_set_int (value, self->min_max_height); break; case PROP_WILL_CHANGE: g_value_set_boolean (value, self->will_change); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_fading_clamp_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzFadingClamp *self = BZ_FADING_CLAMP (object); switch (prop_id) { case PROP_CHILD: bz_fading_clamp_set_child (self, g_value_get_object (value)); break; case PROP_MAX_HEIGHT: bz_fading_clamp_set_max_height (self, g_value_get_int (value)); break; case PROP_MIN_MAX_HEIGHT: self->min_max_height = g_value_get_int (value); bz_fading_clamp_update_will_change (self); gtk_widget_queue_resize (GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MIN_MAX_HEIGHT]); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static GtkSizeRequestMode bz_fading_clamp_get_request_mode (GtkWidget *widget) { return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; } static void bz_fading_clamp_measure (GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline) { int target_height; BzFadingClamp *self = BZ_FADING_CLAMP (widget); if (!self->child) { *minimum = 0; *natural = 0; return; } if (orientation == GTK_ORIENTATION_HORIZONTAL) gtk_widget_measure (self->child, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline); else { gtk_widget_measure (self->child, GTK_ORIENTATION_VERTICAL, for_size, minimum, natural, minimum_baseline, natural_baseline); if (*natural <= self->max_height + CLAMP_LEEWAY) target_height = *natural; else target_height = self->max_height; bz_fading_clamp_update_will_change (self); if (!self->animating_max_height) self->current_height = target_height; *minimum = self->current_height; *natural = self->current_height; } } static void bz_fading_clamp_size_allocate (GtkWidget *widget, int width, int height, int baseline) { BzFadingClamp *self = BZ_FADING_CLAMP (widget); if (self->allocated_width != width) { self->allocated_width = width; bz_fading_clamp_update_will_change (self); } if (self->child) { int child_height = 0; int natural_height = 0; gtk_widget_measure (self->child, GTK_ORIENTATION_VERTICAL, width, NULL, &natural_height, NULL, NULL); if (natural_height > height) child_height = natural_height; else child_height = height; gtk_widget_allocate (self->child, width, child_height, baseline, NULL); } } static void bz_fading_clamp_snapshot (GtkWidget *widget, GtkSnapshot *snapshot) { BzFadingClamp *self = BZ_FADING_CLAMP (widget); int width, height, natural_height; int gradient_start; graphene_rect_t gradient_rect; GskColorStop stops[2]; graphene_point_t start_point, end_point; int effective_fade_height; float stop_offset; if (!self->child || !gtk_widget_get_visible (self->child)) return; width = gtk_widget_get_width (widget); height = gtk_widget_get_height (widget); if (height <= 0) return; gtk_widget_measure (self->child, GTK_ORIENTATION_VERTICAL, width, NULL, &natural_height, NULL, NULL); if (natural_height <= height) { gtk_widget_snapshot_child (widget, self->child, snapshot); return; } effective_fade_height = MIN (natural_height - height, FADE_HEIGHT); gtk_snapshot_push_mask (snapshot, GSK_MASK_MODE_ALPHA); gradient_start = height - effective_fade_height; graphene_rect_init (&gradient_rect, 0, 0, width, height); stop_offset = CLAMP ((float) gradient_start / height, 0.0f, 1.0f); stops[0] = (GskColorStop) { stop_offset, { 1, 1, 1, 1 } }; stops[1] = (GskColorStop) { 1.0, { 1, 1, 1, 0 } }; graphene_point_init (&start_point, 0, 0); graphene_point_init (&end_point, 0, height); gtk_snapshot_append_linear_gradient (snapshot, &gradient_rect, &start_point, &end_point, stops, 2); gtk_snapshot_pop (snapshot); gtk_widget_snapshot_child (widget, self->child, snapshot); gtk_snapshot_pop (snapshot); } static void bz_fading_clamp_class_init (BzFadingClampClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_fading_clamp_dispose; object_class->get_property = bz_fading_clamp_get_property; object_class->set_property = bz_fading_clamp_set_property; widget_class->get_request_mode = bz_fading_clamp_get_request_mode; widget_class->measure = bz_fading_clamp_measure; widget_class->size_allocate = bz_fading_clamp_size_allocate; widget_class->snapshot = bz_fading_clamp_snapshot; properties[PROP_CHILD] = g_param_spec_object ("child", NULL, NULL, GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); properties[PROP_MAX_HEIGHT] = g_param_spec_int ("max-height", NULL, NULL, 0, G_MAXINT, 300, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); properties[PROP_MIN_MAX_HEIGHT] = g_param_spec_int ("min-max-height", NULL, NULL, 0, G_MAXINT, 150, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); properties[PROP_WILL_CHANGE] = g_param_spec_boolean ("will-change", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, N_PROPS, properties); } static void bz_fading_clamp_init (BzFadingClamp *self) { self->animation = bge_animation_new (GTK_WIDGET (self)); self->max_height = 300; self->min_max_height = 150; self->current_height = 0; self->allocated_width = 0; self->animating_max_height = FALSE; self->will_change = FALSE; } GtkWidget * bz_fading_clamp_new (void) { return g_object_new (BZ_TYPE_FADING_CLAMP, NULL); } void bz_fading_clamp_set_child (BzFadingClamp *self, GtkWidget *child) { g_return_if_fail (BZ_IS_FADING_CLAMP (self)); g_return_if_fail (child == NULL || GTK_IS_WIDGET (child)); if (self->child == child) return; g_clear_pointer (&self->child, gtk_widget_unparent); if (child) { self->child = child; gtk_widget_set_parent (child, GTK_WIDGET (self)); self->current_height = 0; } bz_fading_clamp_update_will_change (self); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CHILD]); gtk_widget_queue_resize (GTK_WIDGET (self)); } GtkWidget * bz_fading_clamp_get_child (BzFadingClamp *self) { g_return_val_if_fail (BZ_IS_FADING_CLAMP (self), NULL); return self->child; } void bz_fading_clamp_set_max_height (BzFadingClamp *self, int max_height) { int natural_height = 0; int target_height = 0; int width = 0; g_autoptr (DexFuture) future = NULL; g_return_if_fail (BZ_IS_FADING_CLAMP (self)); if (self->max_height == max_height) return; self->max_height = max_height; if (self->child) { if (self->allocated_width > 0) width = self->allocated_width; else gtk_widget_measure (self->child, GTK_ORIENTATION_HORIZONTAL, -1, NULL, &width, NULL, NULL); gtk_widget_measure (self->child, GTK_ORIENTATION_VERTICAL, width, NULL, &natural_height, NULL, NULL); if (natural_height <= max_height + CLAMP_LEEWAY) target_height = natural_height; else target_height = max_height; } else { target_height = max_height; } self->animating_max_height = TRUE; future = bge_animation_add_spring ( self->animation, "height", self->current_height, target_height, 1.25, 1.0, 800.0, (BgeAnimationCallback) animate, NULL, NULL, NULL); future = dex_future_finally ( future, (DexFutureCallback) animation_finally, bz_track_weak (self), bz_weak_release); dex_future_disown (g_steal_pointer (&future)); bz_fading_clamp_update_will_change (self); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MAX_HEIGHT]); } int bz_fading_clamp_get_max_height (BzFadingClamp *self) { g_return_val_if_fail (BZ_IS_FADING_CLAMP (self), 0); return self->max_height; } bazaar-orig-v0.7.14/src/bz-entry-selection-row.blp0000664000175000017500000000106315166123241020770 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzEntrySelectionRow: Adw.ActionRow { activatable-widget: radio; [prefix] CheckButton radio { valign: center; } [suffix] Image { visible: bind template.repository as <$BzRepository>.is-user; icon-name: "person-symbolic"; has-tooltip: true; tooltip-text: _("For This User Only"); } title: bind template.repository as <$BzRepository>.title; subtitle: bind $get_subtitle(template.entry as <$BzFlatpakEntry>.flatpak-version, template.repository as <$BzRepository>.is-user) as ; } bazaar-orig-v0.7.14/src/bz-search-pill-list.c0000664000175000017500000001462515166123241017670 0ustar hasanhasan/* bz-search-pill-list.c * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include "bz-search-pill-list.h" struct _BzSearchPillList { GtkBox parent_instance; }; G_DEFINE_FINAL_TYPE (BzSearchPillList, bz_search_pill_list, GTK_TYPE_BOX) enum { SIGNAL_ACTIVATED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL]; static void pill_button_clicked_cb (BzSearchPillList *self, GtkButton *button); static void bz_search_pill_list_class_init (BzSearchPillListClass *klass) { signals[SIGNAL_ACTIVATED] = g_signal_new ("activated", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); } static void bz_search_pill_list_init (BzSearchPillList *self) { GtkLayoutManager *layout = NULL; static const char *pills[] = { /* Translators: Search suggestion: the english text will be used for the search regardless of what you put here, so don't worry about the string yielding poor search results. Focus on correctness and friendliness, etc */ N_ ("Browser"), /* Translators: Search suggestion: the english text will be used for the search regardless of what you put here, so don't worry about the string yielding poor search results. Focus on correctness and friendliness, etc */ N_ ("Video"), /* Translators: Search suggestion: the english text will be used for the search regardless of what you put here, so don't worry about the string yielding poor search results. Focus on correctness and friendliness, etc */ N_ ("Music"), /* Translators: Search suggestion: the english text will be used for the search regardless of what you put here, so don't worry about the string yielding poor search results. Focus on correctness and friendliness, etc */ N_ ("Office"), /* Translators: Search suggestion: the english text will be used for the search regardless of what you put here, so don't worry about the string yielding poor search results. Focus on correctness and friendliness, etc */ N_ ("PDF"), /* Translators: Search suggestion: the english text will be used for the search regardless of what you put here, so don't worry about the string yielding poor search results. Focus on correctness and friendliness, etc */ N_ ("Calendar"), /* Translators: Search suggestion: the english text will be used for the search regardless of what you put here, so don't worry about the string yielding poor search results. Focus on correctness and friendliness, etc */ N_ ("Messaging"), /* Translators: Search suggestion: the english text will be used for the search regardless of what you put here, so don't worry about the string yielding poor search results. Focus on correctness and friendliness, etc */ N_ ("Steam"), /* Translators: Search suggestion: the english text will be used for the search regardless of what you put here, so don't worry about the string yielding poor search results. Focus on correctness and friendliness, etc */ N_ ("Paint"), /* Translators: Search suggestion: the english text will be used for the search regardless of what you put here, so don't worry about the string yielding poor search results. Focus on correctness and friendliness, etc */ N_ ("VPN"), /* Translators: Search suggestion: the english text will be used for the search regardless of what you put here, so don't worry about the string yielding poor search results. Focus on correctness and friendliness, etc */ N_ ("Torrent"), /* Translators: Search suggestion: the english text will be used for the search regardless of what you put here, so don't worry about the string yielding poor search results. Focus on correctness and friendliness, etc */ N_ ("Minecraft"), /* Translators: Search suggestion: the english text will be used for the search regardless of what you put here, so don't worry about the string yielding poor search results. Focus on correctness and friendliness, etc */ N_ ("Emulator"), /* This array MUST be NULL terminated */ NULL }; gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_HORIZONTAL); layout = GTK_LAYOUT_MANAGER (adw_wrap_layout_new ()); adw_wrap_layout_set_child_spacing (ADW_WRAP_LAYOUT (layout), 10); adw_wrap_layout_set_line_spacing (ADW_WRAP_LAYOUT (layout), 8); adw_wrap_layout_set_justify (ADW_WRAP_LAYOUT (layout), ADW_JUSTIFY_FILL); gtk_widget_set_layout_manager (GTK_WIDGET (self), layout); for (guint i = 0; pills[i] != NULL; i++) { GtkWidget *button = NULL; button = gtk_button_new_with_label (Q_ (pills[i])); gtk_widget_add_css_class (button, "small-pill"); gtk_widget_add_css_class (button, "search-pill"); g_signal_connect_swapped (button, "clicked", G_CALLBACK (pill_button_clicked_cb), self); g_object_set_data_full (G_OBJECT (button), "search-token", g_strdup (pills[i]), g_free); gtk_box_append (GTK_BOX (self), button); } } GtkWidget * bz_search_pill_list_new (void) { return g_object_new (BZ_TYPE_SEARCH_PILL_LIST, NULL); } static void pill_button_clicked_cb (BzSearchPillList *self, GtkButton *button) { const char *search_token = NULL; search_token = g_object_get_data (G_OBJECT (button), "search-token"); g_signal_emit (self, signals[SIGNAL_ACTIVATED], 0, search_token); } bazaar-orig-v0.7.14/src/bz-malcontent-service.c0000664000175000017500000001540115166123241020307 0ustar hasanhasan/* bz-malcontent-service.c * * Copyright 2026 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include #include #include "bz-malcontent-service.h" struct _BzMalcontentService { GObject parent_instance; MctManager *manager; BzStateInfo *state; GDBusConnection *bus; MctAppFilter *filter; gulong changed_id; }; G_DEFINE_FINAL_TYPE (BzMalcontentService, bz_malcontent_service, G_TYPE_OBJECT) static void fetch_blocked_ids (BzMalcontentService *self); static void apply_filter (BzMalcontentService *self, MctAppFilter *filter); static void on_filter_loaded (GObject *source, GAsyncResult *result, gpointer user_data); static void on_filter_changed (MctManager *manager, guint64 user_id, gpointer user_data); static void bz_malcontent_service_dispose (GObject *object) { BzMalcontentService *self = NULL; self = BZ_MALCONTENT_SERVICE (object); g_signal_handler_disconnect (self->manager, self->changed_id); g_clear_object (&self->manager); g_clear_object (&self->state); g_clear_object (&self->bus); g_clear_pointer (&self->filter, mct_app_filter_unref); G_OBJECT_CLASS (bz_malcontent_service_parent_class)->dispose (object); } static void bz_malcontent_service_class_init (BzMalcontentServiceClass *klass) { G_OBJECT_CLASS (klass)->dispose = bz_malcontent_service_dispose; } static void bz_malcontent_service_init (BzMalcontentService *self) { } BzMalcontentService * bz_malcontent_service_new (GDBusConnection *bus, BzStateInfo *state) { BzMalcontentService *self = NULL; self = g_object_new (BZ_TYPE_MALCONTENT_SERVICE, NULL); self->state = g_object_ref (state); self->bus = g_object_ref (bus); self->manager = mct_manager_new (bus); self->changed_id = g_signal_connect (self->manager, "app-filter-changed", G_CALLBACK (on_filter_changed), self); return self; } void bz_malcontent_service_start (BzMalcontentService *self) { mct_manager_get_app_filter_async (self->manager, getuid (), MCT_MANAGER_GET_VALUE_FLAGS_INTERACTIVE, NULL, on_filter_loaded, self); } static void fetch_blocked_ids (BzMalcontentService *self) { g_autoptr (GError) local_error = NULL; g_autoptr (GVariant) result = NULL; g_autoptr (GVariant) prop = NULL; g_autoptr (GVariant) filter_tuple = NULL; g_autoptr (GtkStringList) blocked = NULL; g_autofree char *object_path = NULL; gboolean is_allowlist = FALSE; GVariantIter *iter = NULL; const char *ref = NULL; object_path = g_strdup_printf ("/org/freedesktop/Accounts/User%d", (int) getuid ()); result = g_dbus_connection_call_sync ( self->bus, "org.freedesktop.Accounts", object_path, "org.freedesktop.DBus.Properties", "Get", g_variant_new ("(ss)", "com.endlessm.ParentalControls.AppFilter", "AppFilter"), G_VARIANT_TYPE ("(v)"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &local_error); if (result == NULL) { g_warning ("failed to fetch malcontent AppFilter from D-Bus: %s", local_error->message); return; } prop = g_variant_get_child_value (result, 0); filter_tuple = g_variant_get_variant (prop); g_variant_get (filter_tuple, "(bas)", &is_allowlist, &iter); blocked = gtk_string_list_new (NULL); while (g_variant_iter_next (iter, "s", &ref)) gtk_string_list_append (blocked, ref); g_variant_iter_free (iter); bz_state_info_set_parental_blocked_ids (self->state, G_LIST_MODEL (blocked)); } static void apply_filter (BzMalcontentService *self, MctAppFilter *filter) { const char *const *oars_sections = NULL; int max_age = -1; g_clear_pointer (&self->filter, mct_app_filter_unref); self->filter = mct_app_filter_ref (filter); oars_sections = mct_app_filter_get_oars_sections (self->filter); for (gsize i = 0; oars_sections[i] != NULL; i++) { MctAppFilterOarsValue filter_value; int section_age; filter_value = mct_app_filter_get_oars_value (self->filter, oars_sections[i]); if (filter_value == MCT_APP_FILTER_OARS_VALUE_UNKNOWN) continue; section_age = as_content_rating_attribute_to_csm_age (oars_sections[i], (AsContentRatingValue) filter_value); if (section_age > max_age) max_age = section_age; } bz_state_info_set_parental_age_rating (self->state, max_age); fetch_blocked_ids (self); } static void on_filter_loaded (GObject *source, GAsyncResult *result, gpointer user_data) { BzMalcontentService *self = NULL; g_autoptr (MctAppFilter) filter = NULL; g_autoptr (GError) local_error = NULL; self = user_data; filter = mct_manager_get_app_filter_finish (self->manager, result, &local_error); if (filter != NULL) apply_filter (self, filter); else g_warning ("Failed to load malcontent app filter: %s", local_error->message); } static void on_filter_changed (MctManager *manager, guint64 user_id, gpointer user_data) { BzMalcontentService *self = NULL; self = user_data; if (user_id != (guint64) getuid ()) return; mct_manager_get_app_filter_async (self->manager, getuid (), MCT_MANAGER_GET_VALUE_FLAGS_NONE, NULL, on_filter_loaded, self); } bazaar-orig-v0.7.14/src/bz-async-texture.h0000664000175000017500000000344415166123241017331 0ustar hasanhasan/* bz-async-texture.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include G_BEGIN_DECLS #define BZ_TYPE_ASYNC_TEXTURE (bz_async_texture_get_type ()) G_DECLARE_FINAL_TYPE (BzAsyncTexture, bz_async_texture, BZ, ASYNC_TEXTURE, GObject) BzAsyncTexture * bz_async_texture_new (GFile *source, GFile *cache_into); BzAsyncTexture * bz_async_texture_new_lazy (GFile *source, GFile *cache_into); GFile * bz_async_texture_get_source (BzAsyncTexture *self); const char * bz_async_texture_get_source_uri (BzAsyncTexture *self); GFile * bz_async_texture_get_cache_into (BzAsyncTexture *self); const char * bz_async_texture_get_cache_into_path (BzAsyncTexture *self); gboolean bz_async_texture_get_loaded (BzAsyncTexture *self); GdkTexture * bz_async_texture_dup_texture (BzAsyncTexture *self); DexFuture * bz_async_texture_dup_future (BzAsyncTexture *self); void bz_async_texture_ensure (BzAsyncTexture *self); void bz_async_texture_cancel (BzAsyncTexture *self); gboolean bz_async_texture_is_loading (BzAsyncTexture *self); G_END_DECLS bazaar-orig-v0.7.14/src/gen_gobject.sh0000775000175000017500000004766315166123241016554 0ustar hasanhasan#!/bin/sh # gen_gobject.sh # author: kolunmi die() { echo "Usage: $0 [--header|--code] [spec] [output]" 1>&2 echo " [--header|--code] whether to output the header (.h) or code (.c)" 1>&2 echo " [spec] spec keyfile" 1>&2 echo " [output] output file" 1>&2 echo "" 1>&2 echo " The spec file should contain these keys:" 1>&2 echo " [prefix] lower case prefix, EX: my" 1>&2 echo " [name] lower case class name, EX: class" 1>&2 echo " [parent-prefix] prefix of parent class, EX: g" 1>&2 echo " [parent-name] name of parent class, EX: object" 1>&2 echo " [author] author name, EX: " 1>&2 echo " [include] #include for the header file (can have multiple)" 1>&2 echo " EX: " 1>&2 echo " EX: \"my-other-class.h\"" 1>&2 echo " [enum] declare an enum type (can have multiple)" 1>&2 echo " EX: my fruit_type apple orange pear" 1>&2 echo " [ensure] ensure another type (can have multiple), EX: GTK_TYPE_WIDGET" 1>&2 echo " [property] property spec (can have multiple), EX: (see below)" 1>&2 echo "" 1>&2 echo " The properties are parsed with the form:" 1>&2 echo " [name] [ctype] [gtype] [spec-type] [free (optional)] [ref (optional)]" 1>&2 echo " EX: my_widget GtkWidget GTK_TYPE_WIDGET object" 1>&2 echo " EX: my_string char G_TYPE_STRING string" 1>&2 echo " EX: my_int int G_TYPE_INT int" 1>&2 echo " EX: my_ptr_array GPtrArray G_TYPE_PTR_ARRAY boxed g_ptr_array_unref g_ptr_array_ref" 1>&2 echo "" 1>&2 echo "$@, aborting!" 1>&2 exit 1 } if [ "$#" -ne 3 ]; then die wrong number of args fi OUTPUT_TYPE="$1" SPEC_FILE="$2" OUTPUT_FILE="$3" if [ -z "$OUTPUT_TYPE" ] || [ -z "$SPEC_FILE" ] || [ -z "$OUTPUT_FILE" ]; then die one or more args are empty fi case "$OUTPUT_TYPE" in --header|--code) ;; *) die arg 1 must be '--header' or '--code' ;; esac if ! [ -f "$SPEC_FILE" ]; then die "$SPEC_FILE isn't a file" fi # if [ -e "$OUTPUT_FILE" ]; then # die "$OUTPUT_FILE already exists" # fi unset PREF unset NAME unset PAR_PREF unset PAR_NAME unset AUTHOR unset INCLUDES unset ENSURES unset ENUMS unset PROPS while IFS= read -r line; do [ -z "$line" ] && continue KEY="${line%%=*}" VAL="${line#*=}" case "$KEY" in prefix) PREF="$VAL" ;; name) NAME="$VAL" ;; parent-prefix) PAR_PREF="$VAL" ;; parent-name) PAR_NAME="$VAL" ;; author) AUTHOR="$VAL" ;; include) if [ -n "$INCLUDES" ]; then INCLUDES="${INCLUDES} #include ${VAL}" else INCLUDES="#include ${VAL}" fi ;; enum) if [ -n "$ENUMS" ]; then ENUMS="${ENUMS} ${VAL}" else ENUMS="$VAL" fi ;; ensure) if [ -n "$ENSURES" ]; then ENSURES="${ENSURES} g_type_ensure (${VAL});" else ENSURES=" g_type_ensure (${VAL});" fi ;; property) if [ -n "$PROPS" ]; then PROPS="${PROPS} ${VAL}" else PROPS="$VAL" fi ;; *) die "unknown key '${KEY}' in ${SPEC_FILE}" ;; esac done < "$SPEC_FILE" if [ -z "$PREF" ] || [ -z "$NAME" ] || [ -z "$PAR_PREF" ] || [ -z "$PAR_NAME" ] || [ -z "$AUTHOR" ] || [ -z "$PROPS" ]; then die "one or more params in $SPEC_FILE are empty" fi case "$OUTPUT_TYPE" in --header) H_FILE="$OUTPUT_FILE" C_FILE="${OUTPUT_FILE%\.h}.c" ;; --code) H_FILE="${OUTPUT_FILE%\.c}.h" C_FILE="$OUTPUT_FILE" ;; esac to_upper() { echo "$1" | tr '[a-z]' '[A-Z]' } to_pascal() { echo "$1" | sed 's/[^_]\+/\L\u&/g' | tr -d '_' } to_hyphened() { echo "$1" | tr '_' '-' } SNAKE="${PREF}_${NAME}" MACRO_PREF="$(to_upper "${PREF}")" MACRO_NAME="$(to_upper "${NAME}")" MACRO="${MACRO_PREF}_${MACRO_NAME}" TYPE="${MACRO_PREF}_TYPE_${MACRO_NAME}" PASCAL="$(to_pascal "${SNAKE}")" HYPHEN_NAME="$(to_hyphened "${NAME}")" HYPHEN="$(to_hyphened "${PREF}")-${HYPHEN_NAME}" PAR_SNAKE="${PAR_PREF}_${PAR_NAME}" PAR_MACRO_PREF="$(to_upper "${PAR_PREF}")" PAR_MACRO_NAME="$(to_upper "${PAR_NAME}")" PAR_MACRO="${PAR_MACRO_PREF}_${PAR_MACRO_NAME}" PAR_TYPE="${PAR_MACRO_PREF}_TYPE_${PAR_MACRO_NAME}" PAR_PASCAL="$(to_pascal "${PAR_SNAKE}")" PAR_HYPHEN_NAME="$(to_hyphened "${PAR_NAME}")" PAR_HYPHEN="$(to_hyphened "${PAR_PREF}")-${PAR_HYPHEN_NAME}" YEAR="$(date +'%Y')" print_enums () { HEADER="$1" [ -z "$ENUMS" ] && return if [ "$HEADER" = header ]; then while IFS= read -r line; do set -- $line LOC_PREF="$1" LOC_NAME="$2" LOC_SNAKE="${LOC_PREF}_${LOC_NAME}" LOC_SNAKE_UPPER="$(to_upper "$LOC_SNAKE")" LOC_TYPE="$(to_upper "$LOC_PREF")_TYPE_$(to_upper "$LOC_NAME")" LOC_PASCAL="$(to_pascal "${LOC_SNAKE}")" shift 2 printf 'typedef enum\n{\n' for enum in "$@"; do LOC_ENUM_SYMBOL="${LOC_SNAKE_UPPER}_$(to_upper "$enum")" printf ' %s,\n' "$LOC_ENUM_SYMBOL" done printf '} %s;\n' "$LOC_PASCAL" printf 'GType %s_get_type (void);\n' "$LOC_SNAKE" printf '#define %s (%s_get_type ())\n\n' "$LOC_TYPE" "$LOC_SNAKE" done <%s, ' "${LOC_NAME}" if [ -n "$LOC_FREE" ]; then printf "$LOC_FREE" else case "$LOC_PTYPE" in string) printf 'g_free' ;; *) printf 'g_object_unref' ;; esac fi printf ');\n' ;; esac done <%s;\n' "$LOC_NAME" printf '}\n\n' fi done <%s' "$LOC_NAME" "$LOC_NAME" ;; string) if [ "$TAKE" = take ]; then printf '%s != NULL && self->%s != NULL && g_strcmp0(%s, self->%s) == 0' "$LOC_NAME" "$LOC_NAME" "$LOC_NAME" "$LOC_NAME" else printf '%s == self->%s || (%s != NULL && self->%s != NULL && g_strcmp0(%s, self->%s) == 0)' "$LOC_NAME" "$LOC_NAME" "$LOC_NAME" "$LOC_NAME" "$LOC_NAME" "$LOC_NAME" fi ;; *) printf '%s == self->%s' "$LOC_NAME" "$LOC_NAME" ;; esac if [ "$TAKE" = take ]; then printf '){\n ' case "$LOC_PTYPE" in char|uchar|boolean|int|uint|long|ulong|int64|uint64|unichar|enum|flags|float|double) ;; *) if [ -n "$LOC_FREE" ]; then printf "$LOC_FREE" else case "$LOC_PTYPE" in string) printf 'g_free' ;; *) printf 'g_object_unref' ;; esac fi printf ' (%s);\n' "$LOC_NAME" ;; esac printf ' return;\n }\n\n' else printf ')\n return;\n\n' fi case "$LOC_PTYPE" in char|uchar|boolean|int|uint|long|ulong|int64|uint64|unichar|enum|flags|float|double) ;; *) printf ' g_clear_pointer (&self->%s, ' "$LOC_NAME" if [ -n "$LOC_FREE" ]; then printf "$LOC_FREE" else case "$LOC_PTYPE" in string) printf 'g_free' ;; *) printf 'g_object_unref' ;; esac fi printf ');\n' printf ' if (%s != NULL)\n ' "$LOC_NAME" ;; esac if [ "$TAKE" = take ]; then printf ' self->%s = %s' "$LOC_NAME" "$LOC_NAME" else printf ' self->%s = ' "$LOC_NAME" if [ -n "$LOC_REF" ]; then printf '%s (%s)' "$LOC_REF" "$LOC_NAME" else case "$LOC_PTYPE" in char|uchar|boolean|int|uint|long|ulong|int64|uint64|unichar|enum|flags|float|double) printf '%s' "$LOC_NAME" ;; string) printf 'g_strdup (%s)' "$LOC_NAME" ;; *) printf 'g_object_ref (%s)' "$LOC_NAME" ;; esac fi fi printf ';\n\n' printf ' g_object_notify_by_pspec (G_OBJECT (self), props[PROP_%s]);\n' "$(to_upper $LOC_NAME)" printf '}\n\n' fi done < "$H_FILE" <. * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include $INCLUDES G_BEGIN_DECLS $(print_enums header) #define $TYPE (${SNAKE}_get_type ()) G_DECLARE_FINAL_TYPE ($PASCAL, $SNAKE, $MACRO_PREF, $MACRO_NAME, $PAR_PASCAL) $(print_functions header) $(print_get_property_methods header) $(print_set_property_methods header) $(print_set_property_methods header take) G_END_DECLS /* End of $H_FILE */ EOF [ "$OUTPUT_TYPE" = --code ] && cat > "$C_FILE" <. * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "$H_FILE" $(print_enums) struct _${PASCAL} { $PAR_PASCAL parent_instance; $(print_struct) }; G_DEFINE_FINAL_TYPE ($PASCAL, $SNAKE, $PAR_TYPE); enum { $(print_prop_enums) }; static GParamSpec *props[LAST_PROP] = { 0 }; static void ${SNAKE}_dispose (GObject *object) { $PASCAL *self = $MACRO (object); $(print_dispose) G_OBJECT_CLASS (${SNAKE}_parent_class)->dispose (object); } static void ${SNAKE}_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { $PASCAL *self = $MACRO (object); switch (prop_id) { $(print_get_property) default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void ${SNAKE}_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { $PASCAL *self = $MACRO (object); switch (prop_id) { $(print_set_property) default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void ${SNAKE}_class_init (${PASCAL}Class *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); $ENSURES object_class->set_property = ${SNAKE}_set_property; object_class->get_property = ${SNAKE}_get_property; object_class->dispose = ${SNAKE}_dispose; $(print_init_properties) g_object_class_install_properties (object_class, LAST_PROP, props); } static void ${SNAKE}_init (${PASCAL} *self) { } $(print_functions) $(print_get_property_methods) $(print_set_property_methods) $(print_set_property_methods '' take) /* End of $C_FILE */ EOF exit 0 bazaar-orig-v0.7.14/src/bz-flathub-state.h0000664000175000017500000000410115166123241017250 0ustar hasanhasan/* bz-flathub-state.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-application-map-factory.h" #include "bz-entry-group.h" G_BEGIN_DECLS #define BZ_TYPE_FLATHUB_STATE (bz_flathub_state_get_type ()) G_DECLARE_FINAL_TYPE (BzFlathubState, bz_flathub_state, BZ, FLATHUB_STATE, GObject) BzFlathubState * bz_flathub_state_new (void); DexFuture * bz_flathub_state_set_for_day (BzFlathubState *self, const char *for_day); void bz_flathub_state_set_map_factory (BzFlathubState *self, BzApplicationMapFactory *map_factory); const char * bz_flathub_state_get_for_day (BzFlathubState *self); BzApplicationMapFactory * bz_flathub_state_get_map_factory (BzFlathubState *self); const char * bz_flathub_state_get_app_of_the_day (BzFlathubState *self); BzEntryGroup * bz_flathub_state_dup_app_of_the_day_group (BzFlathubState *self); GListModel * bz_flathub_state_dup_apps_of_the_week (BzFlathubState *self); GListModel * bz_flathub_state_get_categories (BzFlathubState *self); gboolean bz_flathub_state_get_has_connection_error (BzFlathubState *self); DexFuture * bz_flathub_state_update_to_today (BzFlathubState *self); DexFuture * bz_flathub_state_search_collection (BzFlathubState *self, const char *route); G_END_DECLS /* End of bz-flathub-state.h */ bazaar-orig-v0.7.14/src/bz-entry.h0000664000175000017500000001240315166123241015652 0ustar hasanhasan/* bz-entry.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include #include #include "bz-repository.h" #include "bz-category-flags.h" G_BEGIN_DECLS typedef enum { BZ_ENTRY_KIND_APPLICATION = 1 << 0, BZ_ENTRY_KIND_RUNTIME = 1 << 1, BZ_ENTRY_KIND_ADDON = 1 << 2, } BzEntryKind; GType bz_entry_kind_get_type (void); #define BZ_TYPE_ENTRY_KIND (bz_entry_kind_get_type ()) typedef enum { BZ_CONTROL_NONE = 0, BZ_CONTROL_POINTING = 1 << 0, BZ_CONTROL_KEYBOARD = 1 << 1, BZ_CONTROL_CONSOLE = 1 << 2, BZ_CONTROL_TABLET = 1 << 3, BZ_CONTROL_TOUCH = 1 << 4, BZ_CONTROL_GAMEPAD = 1 << 5, BZ_CONTROL_TV_REMOTE = 1 << 6, BZ_CONTROL_VOICE = 1 << 7, BZ_CONTROL_VISION = 1 << 8, } BzControlType; GType bz_control_type_get_type (void); #define BZ_TYPE_CONTROL_TYPE (bz_control_type_get_type ()) typedef enum { BZ_RELATION_REQUIRES, BZ_RELATION_RECOMMENDS, BZ_RELATION_SUPPORTS, } BzRelationType; GType bz_relation_type_get_type (void); #define BZ_TYPE_RELATION_TYPE (bz_relation_type_get_type ()) #define BZ_TYPE_ENTRY (bz_entry_get_type ()) G_DECLARE_DERIVABLE_TYPE (BzEntry, bz_entry, BZ, ENTRY, GObject) struct _BzEntryClass { GObjectClass parent_class; }; void bz_entry_hold (BzEntry *self); void bz_entry_release (BzEntry *self); gboolean bz_entry_is_holding (BzEntry *self); gboolean bz_entry_is_installed (BzEntry *self); const char * bz_entry_get_installed_version (BzEntry *self); void bz_entry_set_installed_version (BzEntry *self, const char *version); void bz_entry_set_installed (BzEntry *self, gboolean installed); gboolean bz_entry_is_searchable (BzEntry *self); gboolean bz_entry_is_of_kinds (BzEntry *self, guint kinds); void bz_entry_append_addon (BzEntry *self, const char *id); GListModel * bz_entry_get_addons (BzEntry *self); const char * bz_entry_get_id (BzEntry *self); const char * bz_entry_get_unique_id (BzEntry *self); const char * bz_entry_get_unique_id_checksum (BzEntry *self); const char * bz_entry_get_title (BzEntry *self); const char * bz_entry_get_developer (BzEntry *self); GList * bz_entry_get_developer_apps (BzEntry *self); const char * bz_entry_get_eol (BzEntry *self); const char * bz_entry_get_description (BzEntry *self); gboolean bz_entry_is_verified (BzEntry *self); const char * bz_entry_get_long_description (BzEntry *self); const char * bz_entry_get_remote_repo_name (BzEntry *self); guint64 bz_entry_get_size (BzEntry *self); guint64 bz_entry_get_installed_size (BzEntry *self); GdkPaintable * bz_entry_get_icon_paintable (BzEntry *self); GListModel * bz_entry_get_screenshot_paintables (BzEntry *self); GIcon * bz_entry_get_mini_icon (BzEntry *self); const char * bz_entry_get_search_tokens (BzEntry *self); GListModel * bz_entry_get_share_urls (BzEntry *self); const char * bz_entry_get_url (BzEntry *self); const char * bz_entry_get_donation_url (BzEntry *self); const char * bz_entry_get_forge_url (BzEntry *self); BzRepository * bz_entry_get_repository (BzEntry *self, GListModel *repos); gboolean bz_entry_get_is_foss (BzEntry *self); const char * bz_entry_get_light_accent_color (BzEntry *self); const char * bz_entry_get_dark_accent_color (BzEntry *self); gboolean bz_entry_get_is_flathub (BzEntry *self); gboolean bz_entry_get_is_mobile_friendly (BzEntry *self); guint bz_entry_get_required_controls (BzEntry *self); guint bz_entry_get_recommended_controls (BzEntry *self); guint bz_entry_get_supported_controls (BzEntry *self); gboolean bz_entry_has_control (BzEntry *self, BzControlType control, BzRelationType relation); gint bz_entry_get_min_display_length (BzEntry *self); gint bz_entry_get_max_display_length (BzEntry *self); gboolean bz_entry_supports_form_factor (BzEntry *self, guint available_controls, gint display_length); gint bz_entry_get_age_rating (BzEntry *self); AsContentRating * bz_entry_get_content_rating (BzEntry *self); BzCategoryFlags bz_entry_get_category_flags (BzEntry *self); gint bz_entry_calc_usefulness (BzEntry *self); void bz_entry_serialize (BzEntry *self, GVariantBuilder *builder); gboolean bz_entry_deserialize (BzEntry *self, GVariant *import, GError **error); GIcon * bz_load_mini_icon_sync (const char *unique_id_checksum, const char *path); G_END_DECLS bazaar-orig-v0.7.14/src/bz-search-filter-popover.blp0000664000175000017500000000266515166123241021270 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzSearchFilterPopover: Gtk.Popover { child: ScrolledWindow { propagate-natural-height: true; propagate-natural-width: true; child: Box { orientation: vertical; spacing: 12; margin-top: 12; margin-bottom: 12; margin-start: 12; margin-end: 12; Label { label: _("Filters"); halign: start; styles [ "heading", ] } Adw.WrapBox { justify: fill; child-spacing: 6; line-spacing: 6; natural-line-length: 320; justify-last-line: true; Button verified_button { name: "verified"; label: _("_Verified"); clicked => $on_filter_button_clicked(); use-underline: true; } Button free_button { name: "free"; label: _("_Free/Open"); clicked => $on_filter_button_clicked(); use-underline: true; } Button non_eol_button { name: "non-eol"; label: _("Non-_EOL"); clicked => $on_filter_button_clicked(); use-underline: true; } } Label { label: _("Categories"); halign: start; styles [ "heading", ] } Adw.WrapBox wrap_box { justify: fill; child-spacing: 6; line-spacing: 6; natural-line-length: 320; } }; }; } bazaar-orig-v0.7.14/src/bz-flathub-page.blp0000664000175000017500000004706315166123241017410 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzFlathubPage: Adw.Bin { child: Adw.BreakpointBin { width-request: 360; height-request: 100; child: Adw.BreakpointBin { width-request: 360; height-request: 100; child: Adw.ViewStack stack { enable-transitions: true; transition-duration: 400; Adw.ViewStackPage { name: "empty"; title: _("Empty"); child: Adw.StatusPage { icon-name: "flathub-symbolic"; title: _("Flathub Not Added"); description: _("The Flathub remote was not found on any of your Flatpak installations"); }; } Adw.ViewStackPage { name: "offline"; title: _("Offline"); child: Adw.StatusPage { icon-name: "connected-squares-x"; title: _("Offline"); description: _("Flathub returned an error"); child: Button { styles ["pill"] halign: center; sensitive: bind $invert_boolean(template.state as <$BzStateInfo>.syncing as ) as ; label: _("Retry Flathub Connection"); action-name: "app.sync-remotes"; }; }; } Adw.ViewStackPage { name: "content"; title: _("Browser"); child: Box { Adw.StatusPage { visible: bind template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.has-connection-error; hexpand: true; icon-name: "flathub-symbolic"; title: _("Flathub Unavailable"); description: _("We could not connect to Flathub. You can still manage and search for applications."); child: Button { label: _("Search Apps"); halign: center; clicked => $open_search_cb(template); styles ["pill"] }; } ScrolledWindow { visible: bind $invert_boolean(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.has-connection-error) as ; styles [ "transparent", ] hscrollbar-policy: never; child: Adw.ClampScrollable { maximum-size: 1500; tightening-threshold: 1400; child: Viewport { child: Box content_box { margin-start: 30; margin-end: 30; margin-top: 5; margin-bottom: 50; orientation: vertical; spacing: 15; $BzFeaturedCarousel { styles [ "flathub-page-section", ] margin-top: 16; margin-bottom: 3; hexpand: true; model: bind template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.apps_of_the_week; } Box section_toggles_box { halign: center; width-request: 800; Adw.ToggleGroup section_toggles { hexpand: true; halign: fill; homogeneous: true; styles [ "round", "huge" ] Adw.Toggle { label: _("Trending"); name: "trending"; enabled: bind $invert_boolean($is_null($get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "trending") as <$BzFlathubCategory>) as ) as ; } Adw.Toggle { label: _("Popular"); name: "popular"; enabled: bind $invert_boolean($is_null($get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "popular") as <$BzFlathubCategory>) as ) as ; } Adw.Toggle { label: _("New"); name: "recently-added"; enabled: bind $invert_boolean($is_null($get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "recently-added") as <$BzFlathubCategory>) as ) as ; } Adw.Toggle { label: _("Updated"); name: "recently-updated"; enabled: bind $invert_boolean($is_null($get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "recently-updated") as <$BzFlathubCategory>) as ) as ; } } } Adw.ViewStack sections_stack { enable-transitions: true; transition-duration: 300; visible-child-name: bind section_toggles.active-name bidirectional; Adw.ViewStackPage { name: "trending"; title: _("Trending"); child: $BzFlathubCategorySection section_trending { category: bind $get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "trending") as <$BzFlathubCategory>; min-items: 12; }; } Adw.ViewStackPage { name: "recently-updated"; title: _("Recently Updated"); child: $BzFlathubCategorySection section_recently_updated { category: bind $get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "recently-updated") as <$BzFlathubCategory>; min-items: 12; }; } Adw.ViewStackPage { name: "recently-added"; title: _("Recently Added"); child: $BzFlathubCategorySection section_recently_added { category: bind $get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "recently-added") as <$BzFlathubCategory>; min-items: 12; }; } Adw.ViewStackPage { name: "popular"; title: _("Popular"); child: $BzFlathubCategorySection section_popular { category: bind $get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "popular") as <$BzFlathubCategory>; min-items: 12; }; } } $BzFlathubCategorySection section_productivity { category: bind $get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "office") as <$BzFlathubCategory>; } $BzFeaturedCarousel { styles [ "flathub-page-section", ] margin-top: 16; margin-bottom: 8; hexpand: true; model: SliceListModel { offset: 0; size: 1; model: bind template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.apps_of_the_day_week; }; is-aotd: true; } $BzFlathubCategorySection section_graphics { category: bind $get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "graphics") as <$BzFlathubCategory>; } $BzFlathubCategorySection section_audiovideo { category: bind $get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "audiovideo") as <$BzFlathubCategory>; } Box otg_box { visible: bind $invert_boolean($is_null($get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "mobile") as <$BzFlathubCategory>) as ) as ; margin-top: 8; margin-bottom: 8; styles [ "sp-section", "otg", "card", ] Box otg_padding_box { orientation: horizontal; margin-start: 24; margin-end: 24; margin-top: 24; margin-bottom: 24; Box otg_title_box { orientation: vertical; spacing: 12; width-request: 285; valign: center; Image otg_image { icon-name: "on-the-go-symbolic"; can-target: false; pixel-size: 256; margin-bottom: 10; halign: start; styles [ "sp-section-image", ] } Label otg_title { label: _("On the Go"); halign: start; wrap: true; wrap-mode: word_char; styles [ "sp-section-title", "title-1", ] } Label otg_subtitle { label: _("Apps for your Linux phones and tablets"); halign: start; wrap: true; wrap-mode: word_char; } Button otg_more_button_top { styles [ "pill", ] label: _("More Mobile Apps"); halign: start; valign: center; clicked => $show_more_mobile_cb(template); } } $BzDynamicListView otg_list { styles [ "flathub-page-section", ] hexpand: true; scroll: false; noscroll-kind: flow-box; child-type: "BzAppTile"; child-prop: "group"; max-children-per-line: 3; model: SliceListModel otg_slice { offset: 0; size: 9; model: bind $get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "mobile") as <$BzFlathubCategory>.applications; }; bind-widget => $bind_widget_cb(template); unbind-widget => $unbind_widget_cb(template); } Button otg_more_button_bottom { styles [ "pill", ] visible: false; label: _("More Mobile Apps"); halign: center; valign: center; margin-bottom: 12; clicked => $show_more_mobile_cb(template); } } } $BzFlathubCategorySection section_education { category: bind $get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "education") as <$BzFlathubCategory>; } $BzFlathubCategorySection section_network { category: bind $get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "network") as <$BzFlathubCategory>; } Box { visible: bind $invert_boolean($is_null($get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "game") as <$BzFlathubCategory>) as ) as ; margin-top: 8; margin-bottom: 8; styles [ "sp-section", "wlg", "card", ] Box gaming_padding_box { orientation: vertical; margin-start: 24; margin-end: 24; margin-top: 24; margin-bottom: 24; Box { orientation: vertical; spacing: 12; width-request: 285; margin-bottom: 12; valign: center; Image { icon-name: "we-love-games-symbolic"; can-target: false; pixel-size: 256; margin-bottom: 10; halign: center; styles [ "sp-section-image", ] } Label { label: _("We​ ♥​ Games"); halign: center; justify: center; wrap: true; wrap-mode: word_char; styles [ "sp-section-title", "title-1", ] } Label { label: _("Games and apps to run your favorite titles"); halign: center; justify: center; wrap: true; wrap-mode: word_char; } } $BzDynamicListView game_list { styles [ "flathub-page-section", ] hexpand: true; scroll: false; noscroll-kind: flow-box; child-type: "BzAppTile"; child-prop: "group"; max-children-per-line: 4; model: SliceListModel game_slice { offset: 0; size: 12; model: bind $get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "game") as <$BzFlathubCategory>.applications; }; bind-widget => $bind_widget_cb(template); unbind-widget => $unbind_widget_cb(template); } Button { styles [ "pill", ] label: _("More Games"); halign: center; valign: center; margin-top: 12; margin-bottom: 12; clicked => $show_more_gaming_cb(template); } } } $BzFlathubCategorySection section_development { category: bind $get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "development") as <$BzFlathubCategory>; } $BzFlathubCategorySection section_science { category: bind $get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "science") as <$BzFlathubCategory>; } $BzFlathubCategorySection section_system { category: bind $get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "system") as <$BzFlathubCategory>; } $BzFlathubCategorySection section_utility { category: bind $get_category_by_name_cb(template.state as <$BzStateInfo>.flathub as <$BzFlathubState>.categories, "utility") as <$BzFlathubCategory>; } }; }; }; } }; } }; Adw.Breakpoint { condition ("max-width: 1250sp") setters { otg_list.max-children-per-line: 2; otg_slice.size: 6; } } Adw.Breakpoint { condition ("max-width: 700px") setters { content_box.margin-start: 10; content_box.margin-end: 10; otg_padding_box.margin-start: 6; otg_padding_box.margin-end: 6; otg_padding_box.margin-bottom: 6; gaming_padding_box.margin-start: 6; gaming_padding_box.margin-end: 6; gaming_padding_box.margin-bottom: 6; section_toggles.homogeneous: false; section_trending.compact: true; section_popular.compact: true; section_recently_added.compact: true; section_recently_updated.compact: true; section_productivity.compact: true; section_graphics.compact: true; section_audiovideo.compact: true; section_education.compact: true; section_network.compact: true; section_development.compact: true; section_science.compact: true; section_system.compact: true; section_utility.compact: true; otg_slice.size: 6; game_slice.size: 6; } } }; Adw.Breakpoint { condition ("max-width: 970sp") setters { section_toggles_box.width-request: -1; otg_padding_box.orientation: vertical; otg_padding_box.spacing: 6; otg_title_box.halign: center; otg_title_box.width-request: -1; otg_title.justify: center; otg_subtitle.justify: center; otg_image.halign: center; otg_image.margin-top: 15; otg_image.margin-bottom: 5; otg_title.halign: center; otg_subtitle.halign: center; otg_more_button_bottom.visible: true; otg_more_button_top.visible: false; } } }; } bazaar-orig-v0.7.14/src/bz-license-dialog.c0000664000175000017500000002250415166123241017366 0ustar hasanhasan/* bz-license-dialog.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include #include "bz-entry.h" #include "bz-license-dialog.h" #include "bz-lozenge.h" #include "bz-spdx.h" #include "bz-url.h" struct _BzLicenseDialog { AdwBin parent_instance; BzEntry *entry; }; G_DEFINE_FINAL_TYPE (BzLicenseDialog, bz_license_dialog, ADW_TYPE_BIN) enum { PROP_0, PROP_ENTRY, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { NULL }; static void bz_license_dialog_dispose (GObject *object) { BzLicenseDialog *self = NULL; self = BZ_LICENSE_DIALOG (object); g_clear_object (&self->entry); G_OBJECT_CLASS (bz_license_dialog_parent_class)->dispose (object); } static void bz_license_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzLicenseDialog *self = NULL; self = BZ_LICENSE_DIALOG (object); switch (prop_id) { case PROP_ENTRY: g_value_set_object (value, self->entry); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_license_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzLicenseDialog *self = NULL; self = BZ_LICENSE_DIALOG (object); switch (prop_id) { case PROP_ENTRY: g_clear_object (&self->entry); self->entry = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static gboolean invert_boolean (gpointer object, gboolean value) { return !value; } static char * get_label_cb (gpointer object, BzEntry *entry) { g_autofree char *license = NULL; gboolean is_floss = FALSE; if (entry == NULL) return g_strdup (""); g_object_get ( entry, "is-floss", &is_floss, "project-license", &license, NULL); if (license == NULL || *license == '\0') return g_strdup (_ ("Unknown License")); if (is_floss) return g_strdup (_ ("Community Built")); if (bz_spdx_is_proprietary (license)) return g_strdup (_ ("Proprietary")); return g_strdup (_ ("Special License")); } static char * get_involved_tooltip (gpointer object, BzEntry *entry) { g_autoptr (GListModel) share_urls = NULL; g_autoptr (BzUrl) first_url = NULL; const char *url = NULL; if (entry == NULL) return NULL; g_object_get (entry, "share-urls", &share_urls, NULL); if (share_urls == NULL || g_list_model_get_n_items (share_urls) < 1) return NULL; first_url = g_list_model_get_item (share_urls, 1); url = bz_url_get_url (first_url); if (url != NULL && *url != '\0') return g_strdup (url); return NULL; } static char * format_license_link (const char *license) { g_autofree char *license_name = NULL; g_autofree char *license_url = NULL; if (!bz_spdx_is_valid (license)) return g_strdup (license); license_name = bz_spdx_get_name (license); if (license_name == NULL || *license_name == '\0') { g_clear_pointer (&license_name, g_free); license_name = g_strdup (license); } license_url = bz_spdx_get_url (license); return g_strdup_printf ("%s", license_url, license_name); } static char * get_license_info (gpointer object, BzEntry *entry) { g_autofree char *license = NULL; gboolean is_floss = FALSE; g_autofree char *link = NULL; if (entry == NULL) return g_strdup (""); g_object_get ( entry, "is-floss", &is_floss, "project-license", &license, NULL); if (license == NULL || *license == '\0') { if (is_floss) return g_strdup (_ ("This app is developed in the open by an international community.\n\n" "You can participate and help make it even better.")); else return g_strdup (_ ("The license of this app is not known")); } if (is_floss) { link = format_license_link (license); return g_strdup_printf (_ ("This app is developed in the open by an international community, " "and released under the %s license.\n\n" "You can participate and help make it even better."), link); } if (bz_spdx_is_proprietary (license)) { return g_strdup (_ ("This app is not developed in the open, so only its developers know how it works. " "It may be insecure in ways that are hard to detect, and it may change without oversight.\n\n" "You may or may not be able to contribute to this app.")); } link = format_license_link (license); return g_strdup_printf (_ ("This app is developed under the special license %s.\n\n" "You may or may not be able to contribute to this app."), link); } static void contribute_cb (BzLicenseDialog *self) { g_autoptr (GListModel) share_urls = NULL; g_autoptr (BzUrl) first_url = NULL; const char *url = NULL; g_object_get (self->entry, "share-urls", &share_urls, NULL); if (share_urls == NULL || g_list_model_get_n_items (share_urls) < 1) return; first_url = g_list_model_get_item (share_urls, 1); url = bz_url_get_url (first_url); if (url != NULL && *url != '\0') g_app_info_launch_default_for_uri (url, NULL, NULL); } static char * get_eula_url (BzEntry *entry) { g_autofree char *license = NULL; const char *url = NULL; if (entry == NULL) return NULL; g_object_get (entry, "project-license", &license, NULL); if (license == NULL || !g_str_has_prefix (license, "LicenseRef-proprietary=")) return NULL; url = license + strlen ("LicenseRef-proprietary="); return (*url != '\0') ? g_strdup (url) : NULL; } static gboolean should_show_eula (gpointer object, BzEntry *entry) { g_autofree char *url = get_eula_url (entry); return url != NULL; } static char * eula_tooltip (gpointer object, BzEntry *entry) { return get_eula_url (entry); } static void eula_cb (BzLicenseDialog *self) { g_autofree char *url = get_eula_url (self->entry); if (url != NULL) g_app_info_launch_default_for_uri (url, NULL, NULL); } static void bz_license_dialog_class_init (BzLicenseDialogClass *klass) { GObjectClass *object_class = NULL; GtkWidgetClass *widget_class = NULL; object_class = G_OBJECT_CLASS (klass); widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_license_dialog_dispose; object_class->get_property = bz_license_dialog_get_property; object_class->set_property = bz_license_dialog_set_property; props[PROP_ENTRY] = g_param_spec_object ( "entry", NULL, NULL, BZ_TYPE_ENTRY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BZ_TYPE_LOZENGE); gtk_widget_class_set_template_from_resource ( widget_class, "/io/github/kolunmi/Bazaar/bz-license-dialog.ui"); gtk_widget_class_bind_template_callback (widget_class, invert_boolean); gtk_widget_class_bind_template_callback (widget_class, get_label_cb); gtk_widget_class_bind_template_callback (widget_class, get_license_info); gtk_widget_class_bind_template_callback (widget_class, get_involved_tooltip); gtk_widget_class_bind_template_callback (widget_class, should_show_eula); gtk_widget_class_bind_template_callback (widget_class, eula_tooltip); gtk_widget_class_bind_template_callback (widget_class, contribute_cb); gtk_widget_class_bind_template_callback (widget_class, eula_cb); } static void bz_license_dialog_init (BzLicenseDialog *self) { gtk_widget_init_template (GTK_WIDGET (self)); } AdwDialog * bz_license_dialog_new (BzEntry *entry) { BzLicenseDialog *widget = NULL; AdwDialog *dialog = NULL; widget = g_object_new (BZ_TYPE_LICENSE_DIALOG, "entry", entry, NULL); dialog = adw_dialog_new (); adw_dialog_set_content_width (dialog, 400); adw_dialog_set_child (dialog, GTK_WIDGET (widget)); return dialog; } AdwNavigationPage * bz_license_page_new (BzEntry *entry) { BzLicenseDialog *widget = NULL; AdwNavigationPage *page = NULL; widget = g_object_new (BZ_TYPE_LICENSE_DIALOG, "entry", entry, NULL); page = adw_navigation_page_new (GTK_WIDGET (widget), _ ("License")); adw_navigation_page_set_tag (page, "license"); return page; } bazaar-orig-v0.7.14/src/bz-global-progress.wdgt0000664000175000017500000001101015166123241020322 0ustar hasanhasandefwidget "Global Progress Widget" { reference state : "BzStateInfo"; var t : "BgeWdgtTime"; var fg : "GtkFixed"; var bg : "GtkFixed"; var fg-x : "gdouble"; var fg-y : "gdouble"; var fg-w : "gdouble"; var fg-h : "gdouble"; var fg-corner : "gdouble"; var bg-x : "gdouble"; var bg-y : "gdouble"; var bg-w : "gdouble"; var bg-h : "gdouble"; var bg-corner : "gdouble"; var opacity : "gdouble"; var ww : "gdouble"; var animated-progress : "gdouble"; init { measure -1, ww, -1, -1; set t = #(notify-msec = 10;); set fg = #child/(""()); allocate fg fg-w, fg-h, #(translate(#GraphenePoint(fg-x, fg-y));); set bg = #child/(""("global-progress-bg")); allocate bg bg-w, bg-h, #(translate(#GraphenePoint(bg-x, bg-y));); set animated-progress = #transition(state:transaction-manager:current-progress, 1.1, 0.1, 10.0); snapshot { with opacity(opacity) { with rounded-clip( #GrapheneRect(bg-x, bg-y, bg-w, bg-h), #GrapheneSize(bg-corner, bg-corner), #GrapheneSize(bg-corner, bg-corner), #GrapheneSize(bg-corner, bg-corner), #GrapheneSize(bg-corner, bg-corner), ) { do-child bg; } with rounded-clip( #GrapheneRect(fg-x, fg-y, fg-w, fg-h), #GrapheneSize(fg-corner, fg-corner), #GrapheneSize(fg-corner, fg-corner), #GrapheneSize(fg-corner, fg-corner), #GrapheneSize(fg-corner, fg-corner), ) { do-child fg; } } } } state-default "inactive" { set fg-x = #eval(#(%width%)/2.0); set fg-y = #eval(#(%height%)/2.0); set fg-w = 0.0; set fg-h = 0.0; set fg-corner = 0.0; set bg-x = #eval(#(%width%)/2.0); set bg-y = #eval(#(%height%)/2.0); set bg-w = 0.0; set bg-h = 0.0; set bg-corner = 0.0; set opacity = 0.0; set ww = 0.0; transition-spring fg-x 1.5, 1.0, 100.0; transition-spring fg-y 1.0, 0.5, 100.0; transition-spring fg-w 1.0, 0.5, 100.0; transition-spring fg-h 1.0, 0.5, 100.0; transition-spring fg-corner 1.0, 0.5, 100.0; transition-spring bg-x 1.5, 1.0, 100.0; transition-spring bg-y 1.0, 0.5, 100.0; transition-spring bg-w 1.0, 0.5, 100.0; transition-spring bg-h 1.0, 0.5, 100.0; transition-spring bg-corner 1.0, 0.5, 100.0; transition-spring opacity 1.5, 0.1, 100.0; transition-spring ww 1.2, 0.1, 100.0; } state "pending" { set fg-x = #eval(#(%height%)*0.2 + (0.5+0.5*sin(3.0*#(t:time))) * 0.35*(#(%width%)-#(%height%)*0.4)); set fg-y = #eval(#(%height%)*0.2); set fg-w = #eval(0.65*(#(%width%)-#(%height%)*0.4)); set fg-h = #eval(#(%height%)*0.6); set fg-corner = #eval(#(bg-corner)- 0.1*#(%height%)); set bg-x = #eval(#(%height%)*0.1); set bg-y = #eval(#(%height%)*0.1); set bg-w = #eval(#(%width%)-#(%height%)*0.2); set bg-h = #eval(#(%height%)*0.8); set bg-corner = #eval(#(%height%)*0.25); set opacity = 1.0; set ww = 100.0; transition-spring fg-x 1.0, 0.5, 50.0; transition-spring fg-y 1.0, 0.5, 50.0; transition-spring fg-w 1.0, 0.5, 50.0; transition-spring fg-h 1.0, 0.5, 50.0; transition-spring fg-corner 0.8, 0.5, 100.0; transition-spring bg-x 1.0, 0.2, 300.0; transition-spring bg-y 1.0, 0.2, 300.0; transition-spring bg-w 1.0, 0.2, 300.0; transition-spring bg-h 1.0, 0.2, 300.0; transition-spring bg-corner 0.8, 0.5, 100.0; transition-spring opacity 1.0, 0.5, 100.0; transition-spring ww 0.8, 0.2, 20.0; } state "fraction" { set fg-x = #eval(#(%height%)*0.1); set fg-y = #eval(#(%height%)*0.1); set fg-w = #eval((#(%width%)-#(%height%)*0.2) * #(animated-progress)); set fg-h = #eval(#(%height%)*0.8); set fg-corner = #eval(#(%height%)*0.2); set bg-x = 0.0; set bg-y = 0.0; set bg-w = %width%; set bg-h = %height%; set bg-corner = #eval(#(%height%)*0.25); set opacity = 1.0; set ww = 100.0; transition-spring fg-x 1.0, 0.5, 50.0; transition-spring fg-y 1.0, 0.5, 50.0; transition-spring fg-w 1.0, 0.5, 50.0; transition-spring fg-h 1.0, 0.5, 50.0; transition-spring fg-corner 1.0, 2.0, 50.0; transition-spring bg-x 1.0, 0.2, 300.0; transition-spring bg-y 1.0, 0.2, 300.0; transition-spring bg-w 1.0, 0.2, 300.0; transition-spring bg-h 1.0, 0.2, 300.0; transition-spring bg-corner 1.0, 2.0, 50.0; transition-spring opacity 1.0, 0.5, 100.0; transition-spring ww 0.8, 0.2, 20.0; } } bazaar-orig-v0.7.14/src/bz-favorites-page.blp0000664000175000017500000000711415166123241017756 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzFavoritesPage: Adw.NavigationPage { title: _("Favorites"); Adw.ToolbarView { [top] Adw.HeaderBar { [end] Button install_all_button { styles [ "flat", ] has-tooltip: true; tooltip-text: _("Install All"); icon-name: "list-add-symbolic"; sensitive: bind $invert_boolean($is_empty(template.favorites) as ) as ; clicked => $install_all_cb() swapped; } [end] Button progress_button { styles [ "flat", "global-progress-button", ] can-focus: bind template.state as <$BzStateInfo>.transaction-manager as <$BzTransactionManager>.active; can-target: bind progress_button.can-focus; action-name: "window.open-library"; has-tooltip: true; tooltip-text: _("Open App Library"); child: $BzGlobalProgress { expand-size: 125; state: bind template.state as <$BzStateInfo>; active: bind template.state as <$BzStateInfo>.transaction-manager as <$BzTransactionManager>.active; pending: bind template.state as <$BzStateInfo>.transaction-manager as <$BzTransactionManager>.pending; settings: bind template.state as <$BzStateInfo>.settings; }; } } content: Adw.BreakpointBin { width-request: 360; height-request: 100; child: Adw.ViewStack stack { enable-transitions: true; transition-duration: 400; Adw.ViewStackPage { name: "loading"; title: _("Loading"); child: Adw.Spinner { halign: fill; valign: center; width-request: 64; height-request: 64; margin-bottom: 18; }; } Adw.ViewStackPage { name: "empty"; title: _("Empty"); child: Adw.StatusPage { icon-name: "starred-symbolic"; title: _("No Favorites"); description: _("Applications you mark as favorite will appear here"); }; } Adw.ViewStackPage { name: "content"; title: _("Favorites"); child: ScrolledWindow { hscrollbar-policy: never; child: Adw.ClampScrollable { maximum-size: 650; child: ListView list_view { styles [ "navigation-sidebar", "installed-list-view", "no-vertical-margin" ] margin-start: 25; margin-end: 25; overflow: visible; model: NoSelection { model: bind template.model; }; factory: BuilderListItemFactory { template ListItem { activatable: true; selectable: false; focusable: true; child: Revealer { reveal-child: true; overflow: visible; child: $BzFavoritesTile { group: bind template.item as <$BzEntryGroup>; activated => $tile_activated_cb(); unfavorited => $unfavorite_cb(); }; }; } }; }; }; }; } }; Adw.Breakpoint { condition ("max-width: 700px") setters { list_view.margin-start: 8; list_view.margin-end: 8; } } }; } } bazaar-orig-v0.7.14/src/bz-app-permissions.h0000664000175000017500000001455315166123241017652 0ustar hasanhasan/* bz-app-permissions.h * * Copyright 2026 Alexander Vanhee * Copyright (C) 2022 Red Hat * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include G_BEGIN_DECLS #define BZ_TYPE_APP_PERMISSIONS (bz_app_permissions_get_type ()) G_DECLARE_FINAL_TYPE (BzAppPermissions, bz_app_permissions, BZ, APP_PERMISSIONS, GObject) typedef enum { BZ_APP_PERMISSIONS_FLAGS_NONE = 0, BZ_APP_PERMISSIONS_FLAGS_NETWORK = 1 << 0, BZ_APP_PERMISSIONS_FLAGS_SYSTEM_BUS = 1 << 1, BZ_APP_PERMISSIONS_FLAGS_SESSION_BUS = 1 << 2, BZ_APP_PERMISSIONS_FLAGS_DEVICES = 1 << 3, BZ_APP_PERMISSIONS_FLAGS_HOME_FULL = 1 << 4, BZ_APP_PERMISSIONS_FLAGS_HOME_READ = 1 << 5, BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL = 1 << 6, BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ = 1 << 7, BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_FULL = 1 << 8, BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_READ = 1 << 9, BZ_APP_PERMISSIONS_FLAGS_SETTINGS = 1 << 10, BZ_APP_PERMISSIONS_FLAGS_X11 = 1 << 11, BZ_APP_PERMISSIONS_FLAGS_ESCAPE_SANDBOX = 1 << 12, BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_OTHER = 1 << 13, BZ_APP_PERMISSIONS_FLAGS_BUS_POLICY_OTHER = 1 << 14, BZ_APP_PERMISSIONS_FLAGS_AUDIO_DEVICES = 1 << 15, BZ_APP_PERMISSIONS_FLAGS_INPUT_DEVICES = 1 << 16, BZ_APP_PERMISSIONS_FLAGS_SYSTEM_DEVICES = 1 << 17, BZ_APP_PERMISSIONS_FLAGS_SCREEN = 1 << 18, } BzAppPermissionsFlags; #define BZ_TYPE_APP_PERMISSIONS_FLAGS (bz_app_permissions_flags_get_type ()) typedef enum { BZ_FILESYSTEM_PATH_SYSTEM_ROOT, BZ_FILESYSTEM_PATH_HOME_SUBDIR, BZ_FILESYSTEM_PATH_HOST_OS, BZ_FILESYSTEM_PATH_HOST_ETC, BZ_FILESYSTEM_PATH_XDG_DESKTOP, BZ_FILESYSTEM_PATH_XDG_DOCUMENTS, BZ_FILESYSTEM_PATH_XDG_MUSIC, BZ_FILESYSTEM_PATH_XDG_PICTURES, BZ_FILESYSTEM_PATH_XDG_PUBLIC_SHARE, BZ_FILESYSTEM_PATH_XDG_VIDEOS, BZ_FILESYSTEM_PATH_XDG_TEMPLATES, BZ_FILESYSTEM_PATH_XDG_CACHE, BZ_FILESYSTEM_PATH_XDG_CONFIG, BZ_FILESYSTEM_PATH_XDG_DATA, BZ_FILESYSTEM_PATH_XDG_RUN, BZ_FILESYSTEM_PATH_CUSTOM, } BzFilesystemPathType; #define BZ_TYPE_FILESYSTEM_PATH_TYPE (bz_filesystem_path_type_get_type ()) typedef enum { BZ_BUS_POLICY_PERMISSION_UNKNOWN = 0, BZ_BUS_POLICY_PERMISSION_NONE, BZ_BUS_POLICY_PERMISSION_SEE, BZ_BUS_POLICY_PERMISSION_TALK, BZ_BUS_POLICY_PERMISSION_OWN, } BzBusPolicyPermission; #define BZ_TYPE_BUS_POLICY_PERMISSION (bz_bus_policy_permission_get_type ()) typedef struct { BzFilesystemPathType type; char *subpath; } BzFilesystemPath; typedef struct { GBusType bus_type; char *bus_name; BzBusPolicyPermission permission; } BzBusPolicy; GType bz_app_permissions_flags_get_type (void) G_GNUC_CONST; GType bz_safety_rating_get_type (void) G_GNUC_CONST; GType bz_filesystem_path_type_get_type (void) G_GNUC_CONST; GType bz_bus_policy_permission_get_type (void) G_GNUC_CONST; BzFilesystemPath * bz_filesystem_path_new (BzFilesystemPathType type, const char *subpath); void bz_filesystem_path_free (BzFilesystemPath *self); char * bz_filesystem_path_to_display_string (const BzFilesystemPath *path); const char * bz_filesystem_path_to_icon_name (const BzFilesystemPath *path); BzBusPolicy * bz_bus_policy_new (GBusType bus_type, const char *bus_name, BzBusPolicyPermission permission); void bz_bus_policy_free (BzBusPolicy *self); G_DEFINE_AUTOPTR_CLEANUP_FUNC (BzFilesystemPath, bz_filesystem_path_free) G_DEFINE_AUTOPTR_CLEANUP_FUNC (BzBusPolicy, bz_bus_policy_free) BzAppPermissions * bz_app_permissions_new (void); BzAppPermissions * bz_app_permissions_new_from_metadata (GKeyFile *keyfile, GError **error); void bz_app_permissions_seal (BzAppPermissions *self); gboolean bz_app_permissions_is_sealed (BzAppPermissions *self); gboolean bz_app_permissions_is_empty (BzAppPermissions *self); void bz_app_permissions_set_flags (BzAppPermissions *self, BzAppPermissionsFlags flags); BzAppPermissionsFlags bz_app_permissions_get_flags (BzAppPermissions *self); void bz_app_permissions_add_flag (BzAppPermissions *self, BzAppPermissionsFlags flags); void bz_app_permissions_remove_flag (BzAppPermissions *self, BzAppPermissionsFlags flags); void bz_app_permissions_add_filesystem_read (BzAppPermissions *self, BzFilesystemPathType type, const char *subpath); const GPtrArray * bz_app_permissions_get_filesystem_read (BzAppPermissions *self); void bz_app_permissions_add_filesystem_full (BzAppPermissions *self, BzFilesystemPathType type, const char *subpath); const GPtrArray * bz_app_permissions_get_filesystem_full (BzAppPermissions *self); void bz_app_permissions_add_bus_policy (BzAppPermissions *self, GBusType bus_type, const char *bus_name, BzBusPolicyPermission permission); const BzBusPolicy *const * bz_app_permissions_get_bus_policies (BzAppPermissions *self, size_t *out_n_bus_policies); void bz_app_permissions_serialize (BzAppPermissions *self, GVariantBuilder *builder); gboolean bz_app_permissions_deserialize (BzAppPermissions *self, GVariant *import, GError **error); G_END_DECLS bazaar-orig-v0.7.14/src/bz-decorated-screenshot.h0000664000175000017500000000256115166123241020622 0ustar hasanhasan/* bz-decorated-screenshot.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-async-texture.h" #include G_BEGIN_DECLS #define BZ_TYPE_DECORATED_SCREENSHOT (bz_decorated_screenshot_get_type ()) G_DECLARE_FINAL_TYPE (BzDecoratedScreenshot, bz_decorated_screenshot, BZ, DECORATED_SCREENSHOT, GtkButton) BzDecoratedScreenshot * bz_decorated_screenshot_new (void); BzAsyncTexture * bz_decorated_screenshot_get_async_texture (BzDecoratedScreenshot *self); void bz_decorated_screenshot_set_async_texture (BzDecoratedScreenshot *self, BzAsyncTexture *async_texture); G_END_DECLS /* End of bz-decorated-screenshot.h */ bazaar-orig-v0.7.14/src/bz-themed-entry-group-rect.h0000664000175000017500000000310015166123241021175 0ustar hasanhasan/* bz-themed-entry-group-rect.h * * Copyright 2025 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-entry-group.h" G_BEGIN_DECLS #define BZ_TYPE_THEMED_ENTRY_GROUP_RECT (bz_themed_entry_group_rect_get_type ()) G_DECLARE_FINAL_TYPE (BzThemedEntryGroupRect, bz_themed_entry_group_rect, BZ, THEMED_ENTRY_GROUP_RECT, GtkWidget) GtkWidget * bz_themed_entry_group_rect_new (void); BzEntryGroup * bz_themed_entry_group_rect_get_group (BzThemedEntryGroupRect *self); void bz_themed_entry_group_rect_set_group (BzThemedEntryGroupRect *self, BzEntryGroup *group); GtkWidget * bz_themed_entry_group_rect_get_child (BzThemedEntryGroupRect *self); void bz_themed_entry_group_rect_set_child (BzThemedEntryGroupRect *self, GtkWidget *child); G_END_DECLS /* End of bz-themed-entry-group-rect.h */ bazaar-orig-v0.7.14/src/bz-flathub-category.h0000664000175000017500000000575715166123241017767 0ustar hasanhasan/* bz-flathub-category.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-application-map-factory.h" G_BEGIN_DECLS #define BZ_TYPE_FLATHUB_CATEGORY (bz_flathub_category_get_type ()) G_DECLARE_FINAL_TYPE (BzFlathubCategory, bz_flathub_category, BZ, FLATHUB_CATEGORY, GObject) BzFlathubCategory * bz_flathub_category_new (void); BzApplicationMapFactory * bz_flathub_category_get_map_factory (BzFlathubCategory *self); const char * bz_flathub_category_get_name (BzFlathubCategory *self); GListModel * bz_flathub_category_dup_applications (BzFlathubCategory *self); GListModel * bz_flathub_category_dup_quality_applications (BzFlathubCategory *self); void bz_flathub_category_set_map_factory (BzFlathubCategory *self, BzApplicationMapFactory *map_factory); void bz_flathub_category_set_name (BzFlathubCategory *self, const char *name); void bz_flathub_category_set_applications (BzFlathubCategory *self, GListModel *applications); void bz_flathub_category_set_quality_applications (BzFlathubCategory *self, GListModel *applications); const char * bz_flathub_category_get_display_name (BzFlathubCategory *self); const char * bz_flathub_category_get_short_name (BzFlathubCategory *self); const char * bz_flathub_category_get_more_of_name (BzFlathubCategory *self); gboolean bz_flathub_category_get_is_xdg (BzFlathubCategory *self); const char * bz_flathub_category_get_symbolic_icon_name (BzFlathubCategory *self); const char * bz_flathub_category_get_icon_name (BzFlathubCategory *self); int bz_flathub_category_get_total_entries (BzFlathubCategory *self); void bz_flathub_category_set_total_entries (BzFlathubCategory *self, int total_entries); gboolean bz_flathub_category_get_is_spotlight (BzFlathubCategory *self); void bz_flathub_category_set_is_spotlight (BzFlathubCategory *self, gboolean is_spotlight); GListModel * bz_flathub_category_get_subcategories (BzFlathubCategory *self); GListModel * bz_flathub_category_list_from_appstream (GPtrArray *as_categories); G_END_DECLS /* End of bz-flathub-category.h */ bazaar-orig-v0.7.14/src/bz-application-map-factory.c0000664000175000017500000000766215166123241021242 0ustar hasanhasan/* bz-application-map-factory.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bz-application-map-factory.h" #include "bz-util.h" struct _BzApplicationMapFactory { GObject parent_instance; GtkMapListModelMapFunc func; gpointer user_data; GDestroyNotify ref_user_data; GDestroyNotify unref_user_data; GtkFilter *filter; }; G_DEFINE_FINAL_TYPE (BzApplicationMapFactory, bz_application_map_factory, G_TYPE_OBJECT); static void bz_application_map_factory_dispose (GObject *object) { BzApplicationMapFactory *self = BZ_APPLICATION_MAP_FACTORY (object); g_clear_object (&self->filter); if (self->unref_user_data != NULL) g_clear_pointer (&self->user_data, self->unref_user_data); G_OBJECT_CLASS (bz_application_map_factory_parent_class)->dispose (object); } static void bz_application_map_factory_class_init (BzApplicationMapFactoryClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = bz_application_map_factory_dispose; } static void bz_application_map_factory_init (BzApplicationMapFactory *self) { } BzApplicationMapFactory * bz_application_map_factory_new (GtkMapListModelMapFunc func, gpointer user_data, GDestroyNotify ref_user_data, GDestroyNotify unref_user_data, GtkFilter *filter) { BzApplicationMapFactory *self = NULL; g_return_val_if_fail (func != NULL, NULL); g_return_val_if_fail (filter == NULL || GTK_IS_FILTER (filter), NULL); self = g_object_new (BZ_TYPE_APPLICATION_MAP_FACTORY, NULL); self->func = func; self->user_data = user_data; self->ref_user_data = ref_user_data; self->unref_user_data = unref_user_data; self->filter = bz_maybe_ref (filter, g_object_ref_sink); return self; } GListModel * bz_application_map_factory_generate (BzApplicationMapFactory *self, GListModel *model) { g_autoptr (GListModel) backing = NULL; GtkMapListModel *map_model = NULL; g_return_val_if_fail (BZ_IS_APPLICATION_MAP_FACTORY (self), NULL); g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL); if (self->filter != NULL) { GtkFilterListModel *filter_model = NULL; filter_model = gtk_filter_list_model_new ( g_object_ref (model), g_object_ref (self->filter)); backing = G_LIST_MODEL (filter_model); } else backing = g_object_ref (model); if (self->ref_user_data != NULL && self->unref_user_data != NULL) self->ref_user_data (self->user_data); map_model = gtk_map_list_model_new ( g_steal_pointer (&backing), self->func, self->user_data, self->ref_user_data != NULL ? self->unref_user_data : NULL); return G_LIST_MODEL (map_model); } gpointer bz_application_map_factory_convert_one (BzApplicationMapFactory *self, gpointer item) { g_return_val_if_fail (BZ_IS_APPLICATION_MAP_FACTORY (self), NULL); g_return_val_if_fail (item != NULL, NULL); return self->func (item, self->user_data); } /* End of bz-application-map-factory.c */ bazaar-orig-v0.7.14/src/bz-async-texture.c0000664000175000017500000010234615166123241017325 0ustar hasanhasan/* bz-async-texture.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::ASYNC-TEXTURE" #define MAX_CONCURRENT_GLYCIN 32 #define CACHE_INVALID_AGE (G_TIME_SPAN_DAY * 1) #define HTTP_TIMEOUT_SECONDS 5 #define MAX_LOAD_RETRIES 3 #define RETRY_INTERVAL_SECONDS 1 #define TEXTURE_LINGER_SECONDS 2 #include "config.h" #include #include #include "bz-async-texture.h" #include "bz-download-worker.h" #include "bz-env.h" #include "bz-io.h" #include "bz-util.h" BZ_DEFINE_DATA ( cache_entry, CacheEntry, { GdkTexture *texture; DexFuture *linger_timeout; }, BZ_RELEASE_DATA (texture, g_object_unref); BZ_RELEASE_DATA (linger_timeout, dex_unref)); static GMutex texture_cache_mutex = { 0 }; static GHashTable *texture_cache = NULL; static void texture_cache_ensure (void); static DexFuture * linger_timeout_finally (DexFuture *future, char *uri); static GdkTexture * texture_cache_acquire (const char *uri); static void texture_cache_store (const char *uri, GdkTexture *texture); static void texture_cache_release (const char *uri); BZ_DEFINE_DATA ( load, Load, { GFile *source; char *source_uri; GFile *cache_into; char *cache_into_path; GCancellable *cancellable; int retries; GWeakRef self; }, BZ_RELEASE_DATA (source, g_object_unref); BZ_RELEASE_DATA (source_uri, g_free); BZ_RELEASE_DATA (cache_into, g_object_unref); BZ_RELEASE_DATA (cache_into_path, g_free); BZ_RELEASE_DATA (cancellable, g_object_unref); g_weak_ref_clear (&self->self);) struct _BzAsyncTexture { GObject parent_instance; GFile *source; char *source_uri; GFile *cache_into; char *cache_into_path; gboolean lazy; DexFuture *task; GCancellable *cancellable; int retries; DexFuture *retry_future; GdkPaintable *paintable; GMutex mutex; gboolean cache_acquired; }; static void paintable_iface_init (GdkPaintableInterface *iface); G_DEFINE_TYPE_WITH_CODE ( BzAsyncTexture, bz_async_texture, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE, paintable_iface_init)) enum { PROP_0, PROP_SOURCE, PROP_CACHE_INTO, PROP_LOADED, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static DexFuture * load_fiber_work (LoadData *data); static DexFuture * load_finally (DexFuture *future, LoadData *data); static void maybe_load (BzAsyncTexture *self); static DexFuture * retry_cb (DexFuture *future, LoadData *data); static gboolean idle_notify (BzAsyncTexture *self); static GMutex debug_n_textures_mutex = { 0 }; static gsize debug_n_textures = 0; static void bz_async_texture_dispose (GObject *object) { BzAsyncTexture *self = BZ_ASYNC_TEXTURE (object); if (self->cancellable != NULL) g_cancellable_cancel (self->cancellable); dex_clear (&self->task); g_clear_object (&self->cancellable); dex_clear (&self->retry_future); g_clear_object (&self->source); if (self->cache_acquired && self->source_uri != NULL) { texture_cache_release (self->source_uri); self->cache_acquired = FALSE; } g_clear_pointer (&self->source_uri, g_free); g_clear_object (&self->cache_into); g_clear_pointer (&self->cache_into_path, g_free); g_clear_object (&self->paintable); g_mutex_clear (&self->mutex); if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN)) { g_mutex_lock (&debug_n_textures_mutex); debug_n_textures--; g_debug ("%zu %s object(s) in memory", debug_n_textures, g_type_name (BZ_TYPE_ASYNC_TEXTURE)); g_mutex_unlock (&debug_n_textures_mutex); } G_OBJECT_CLASS (bz_async_texture_parent_class)->dispose (object); } static void bz_async_texture_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzAsyncTexture *self = BZ_ASYNC_TEXTURE (object); switch (prop_id) { case PROP_SOURCE: g_value_set_object (value, bz_async_texture_get_source (self)); break; case PROP_CACHE_INTO: g_value_set_object (value, bz_async_texture_get_cache_into (self)); break; case PROP_LOADED: g_value_set_boolean (value, bz_async_texture_get_loaded (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_async_texture_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { // BzAsyncTexture *self = BZ_ASYNC_TEXTURE (object); switch (prop_id) { case PROP_SOURCE: case PROP_CACHE_INTO: case PROP_LOADED: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_async_texture_class_init (BzAsyncTextureClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = bz_async_texture_dispose; object_class->get_property = bz_async_texture_get_property; object_class->set_property = bz_async_texture_set_property; props[PROP_SOURCE] = g_param_spec_object ( "source", NULL, NULL, G_TYPE_FILE, G_PARAM_READABLE); props[PROP_CACHE_INTO] = g_param_spec_object ( "cache-into", NULL, NULL, G_TYPE_FILE, G_PARAM_READABLE); props[PROP_LOADED] = g_param_spec_boolean ( "loaded", NULL, NULL, FALSE, G_PARAM_READABLE); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bz_async_texture_init (BzAsyncTexture *self) { self->retries = 0; self->paintable = NULL; self->cache_acquired = FALSE; g_mutex_init (&self->mutex); if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN)) { g_mutex_lock (&debug_n_textures_mutex); debug_n_textures++; g_mutex_unlock (&debug_n_textures_mutex); } } static void paintable_snapshot (GdkPaintable *paintable, GdkSnapshot *snapshot, double width, double height) { BzAsyncTexture *self = BZ_ASYNC_TEXTURE (paintable); g_autoptr (GMutexLocker) locker = NULL; locker = g_mutex_locker_new (&self->mutex); maybe_load (self); if (self->paintable != NULL) gdk_paintable_snapshot (self->paintable, snapshot, width, height); } static GdkPaintable * paintable_get_current_image (GdkPaintable *paintable) { BzAsyncTexture *self = BZ_ASYNC_TEXTURE (paintable); g_autoptr (GMutexLocker) locker = NULL; locker = g_mutex_locker_new (&self->mutex); maybe_load (self); if (self->paintable != NULL) return gdk_paintable_get_current_image (self->paintable); return NULL; } static GdkPaintableFlags paintable_get_flags (GdkPaintable *paintable) { BzAsyncTexture *self = BZ_ASYNC_TEXTURE (paintable); g_autoptr (GMutexLocker) locker = NULL; locker = g_mutex_locker_new (&self->mutex); maybe_load (self); return 0; } static int paintable_get_intrinsic_width (GdkPaintable *paintable) { BzAsyncTexture *self = BZ_ASYNC_TEXTURE (paintable); g_autoptr (GMutexLocker) locker = NULL; locker = g_mutex_locker_new (&self->mutex); maybe_load (self); if (self->paintable != NULL) return gdk_paintable_get_intrinsic_width (self->paintable); return 0; } static int paintable_get_intrinsic_height (GdkPaintable *paintable) { BzAsyncTexture *self = BZ_ASYNC_TEXTURE (paintable); g_autoptr (GMutexLocker) locker = NULL; locker = g_mutex_locker_new (&self->mutex); maybe_load (self); if (self->paintable != NULL) return gdk_paintable_get_intrinsic_height (self->paintable); return 0; } static double paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable) { BzAsyncTexture *self = BZ_ASYNC_TEXTURE (paintable); g_autoptr (GMutexLocker) locker = NULL; locker = g_mutex_locker_new (&self->mutex); maybe_load (self); if (self->paintable != NULL) return gdk_paintable_get_intrinsic_aspect_ratio (self->paintable); return 0.0; } static void paintable_iface_init (GdkPaintableInterface *iface) { iface->snapshot = paintable_snapshot; iface->get_current_image = paintable_get_current_image; iface->get_flags = paintable_get_flags; iface->get_intrinsic_width = paintable_get_intrinsic_width; iface->get_intrinsic_height = paintable_get_intrinsic_height; iface->get_intrinsic_aspect_ratio = paintable_get_intrinsic_aspect_ratio; } BzAsyncTexture * bz_async_texture_new (GFile *source, GFile *cache_into) { BzAsyncTexture *self = NULL; g_return_val_if_fail (G_IS_FILE (source), NULL); g_return_val_if_fail (cache_into == NULL || G_IS_FILE (cache_into), NULL); self = g_object_new (BZ_TYPE_ASYNC_TEXTURE, NULL); self->source = g_object_ref (source); self->source_uri = g_file_get_uri (source); self->cache_into = bz_object_maybe_ref (cache_into); self->cache_into_path = bz_maybe (cache_into, g_file_get_path); self->lazy = FALSE; maybe_load (self); return self; } BzAsyncTexture * bz_async_texture_new_lazy (GFile *source, GFile *cache_into) { BzAsyncTexture *self = NULL; g_return_val_if_fail (G_IS_FILE (source), NULL); g_return_val_if_fail (cache_into == NULL || G_IS_FILE (cache_into), NULL); self = g_object_new (BZ_TYPE_ASYNC_TEXTURE, NULL); self->source = g_object_ref (source); self->source_uri = g_file_get_uri (source); self->cache_into = bz_object_maybe_ref (cache_into); self->cache_into_path = bz_maybe (cache_into, g_file_get_path); self->lazy = TRUE; return self; } GFile * bz_async_texture_get_source (BzAsyncTexture *self) { g_return_val_if_fail (BZ_IS_ASYNC_TEXTURE (self), FALSE); return self->source; } const char * bz_async_texture_get_source_uri (BzAsyncTexture *self) { g_return_val_if_fail (BZ_IS_ASYNC_TEXTURE (self), FALSE); return self->source_uri; } GFile * bz_async_texture_get_cache_into (BzAsyncTexture *self) { g_return_val_if_fail (BZ_IS_ASYNC_TEXTURE (self), FALSE); return self->cache_into; } const char * bz_async_texture_get_cache_into_path (BzAsyncTexture *self) { g_return_val_if_fail (BZ_IS_ASYNC_TEXTURE (self), FALSE); return self->cache_into_path; } gboolean bz_async_texture_get_loaded (BzAsyncTexture *self) { g_autoptr (GMutexLocker) locker = NULL; g_return_val_if_fail (BZ_IS_ASYNC_TEXTURE (self), FALSE); locker = g_mutex_locker_new (&self->mutex); return GDK_IS_TEXTURE (self->paintable); } GdkTexture * bz_async_texture_dup_texture (BzAsyncTexture *self) { g_autoptr (GMutexLocker) locker = NULL; g_return_val_if_fail (BZ_IS_ASYNC_TEXTURE (self), NULL); locker = g_mutex_locker_new (&self->mutex); if (GDK_IS_TEXTURE (self->paintable)) return (GdkTexture *) g_object_ref (self->paintable); else return NULL; } DexFuture * bz_async_texture_dup_future (BzAsyncTexture *self) { g_autoptr (GMutexLocker) locker = NULL; g_return_val_if_fail (BZ_IS_ASYNC_TEXTURE (self), NULL); locker = g_mutex_locker_new (&self->mutex); maybe_load (self); if (self->task != NULL) return dex_ref (self->task); else if (GDK_IS_TEXTURE (self->paintable)) return dex_future_new_for_object (self->paintable); else return dex_future_new_reject ( G_IO_ERROR, G_IO_ERROR_FAILED, "texture is in an invalid state"); } void bz_async_texture_ensure (BzAsyncTexture *self) { g_autoptr (GMutexLocker) locker = NULL; g_return_if_fail (BZ_IS_ASYNC_TEXTURE (self)); locker = g_mutex_locker_new (&self->mutex); maybe_load (self); } void bz_async_texture_cancel (BzAsyncTexture *self) { g_return_if_fail (BZ_IS_ASYNC_TEXTURE (self)); if (self->cancellable != NULL) g_cancellable_cancel (self->cancellable); dex_clear (&self->task); g_clear_object (&self->cancellable); self->retries = G_MAXINT; } gboolean bz_async_texture_is_loading (BzAsyncTexture *self) { g_return_val_if_fail (BZ_IS_ASYNC_TEXTURE (self), FALSE); return self->task != NULL && dex_future_is_pending (self->task); } static void maybe_load (BzAsyncTexture *self) { g_autoptr (LoadData) data = NULL; g_autoptr (DexFuture) future = NULL; if (GDK_IS_TEXTURE (self->paintable) || (self->task != NULL && dex_future_is_pending (self->task)) || self->retries >= MAX_LOAD_RETRIES) return; if (!self->cache_acquired) { g_autoptr (GdkTexture) cached = NULL; cached = texture_cache_acquire (self->source_uri); if (cached != NULL) { g_clear_object (&self->paintable); self->paintable = (GdkPaintable *) g_object_ref (cached); self->cache_acquired = TRUE; g_idle_add_full ( G_PRIORITY_DEFAULT_IDLE, (GSourceFunc) idle_notify, g_object_ref (self), g_object_unref); return; } } if (self->cancellable != NULL) g_cancellable_cancel (self->cancellable); dex_clear (&self->task); g_clear_object (&self->cancellable); self->cancellable = g_cancellable_new (); data = load_data_new (); data->source = g_object_ref (self->source); data->source_uri = g_strdup (self->source_uri); data->cache_into = bz_object_maybe_ref (self->cache_into); data->cache_into_path = bz_maybe_strdup (self->cache_into_path); data->cancellable = g_object_ref (self->cancellable); data->retries = self->retries; g_weak_ref_init (&data->self, self); future = dex_scheduler_spawn ( bz_get_io_scheduler (), bz_get_dex_stack_size (), (DexFiberFunc) load_fiber_work, load_data_ref (data), load_data_unref); future = dex_future_finally ( future, (DexFutureCallback) load_finally, load_data_ref (data), load_data_unref); self->task = g_steal_pointer (&future); } static DexFuture * load_fiber_work (LoadData *data) { static GMutex queueing_mutex = { 0 }; static guint concurrent_io = 8; static guint io_queued[MAX_CONCURRENT_GLYCIN] = { 0 }; static BzGuard *io_gates[MAX_CONCURRENT_GLYCIN] = { 0 }; static GMutex io_mutexes[MAX_CONCURRENT_GLYCIN] = { 0 }; static guint concurrent_glycin = 0; static guint glycin_queued[MAX_CONCURRENT_GLYCIN] = { 0 }; static BzGuard *glycin_gates[MAX_CONCURRENT_GLYCIN] = { 0 }; static GMutex glycin_mutexes[MAX_CONCURRENT_GLYCIN] = { 0 }; GFile *source = data->source; char *source_uri = data->source_uri; GFile *cache_into = data->cache_into; char *cache_into_path = data->cache_into_path; GCancellable *cancellable = data->cancellable; gboolean result = FALSE; g_autoptr (GError) local_error = NULL; g_autoptr (GMutexLocker) locker = NULL; g_autoptr (BzGuard) slot_guard = NULL; guint slot_queued = G_MAXUINT; gboolean is_http = FALSE; g_autoptr (GDateTime) now = NULL; g_autofree char *async_tex_data_path = NULL; g_autoptr (GFile) async_tex_data_file = NULL; g_autoptr (GdkTexture) texture = NULL; g_autoptr (GlyFrame) frame = NULL; locker = g_mutex_locker_new (&queueing_mutex); if (concurrent_glycin == 0) { /* Ensure we don't overload the system with work; aim for # of logical processors divided by 2 See: https://github.com/bazaar-org/bazaar/issues/497 https://docs.gtk.org/glib/func.get_num_processors.html Eva Thu, 23 Oct 2025 14:19:44 -0700 */ concurrent_glycin = MIN ( MAX_CONCURRENT_GLYCIN, MAX (1, g_get_num_processors () / 2)); g_debug ("Allowing %d concurrent texture glycin", concurrent_glycin); } g_clear_pointer (&locker, g_mutex_locker_free); #define FIND_LOCK(name, _idx) \ G_STMT_START \ { \ locker = g_mutex_locker_new (&queueing_mutex); \ \ for (guint i = 0; i < concurrent_##name; i++) \ { \ if (name##_queued[i] < slot_queued) \ { \ slot_queued = name##_queued[i]; \ (_idx) = i; \ } \ } \ \ name##_queued[(_idx)]++; \ g_clear_pointer (&locker, g_mutex_locker_free); \ } \ G_STMT_END #define FINISH_LOCK(name, _idx) \ G_STMT_START \ { \ locker = g_mutex_locker_new (&queueing_mutex); \ name##_queued[(_idx)]--; \ g_clear_pointer (&locker, g_mutex_locker_free); \ } \ G_STMT_END #define RATE_LIMIT_BEGIN(name) \ G_STMT_START \ { \ guint _slot_index = 0; \ \ FIND_LOCK (name, _slot_index); \ BZ_BEGIN_GUARD_WITH_CONTEXT (&slot_guard, \ &name##_mutexes[_slot_index], \ &name##_gates[_slot_index]); \ FINISH_LOCK (name, _slot_index); \ } \ G_STMT_END #define RATE_LIMIT_END() bz_clear_guard (&slot_guard) is_http = g_str_has_prefix (source_uri, "http"); now = g_date_time_new_now_utc (); if (cache_into != NULL) { async_tex_data_path = g_strdup_printf ("%s.bz-async-texture-data", cache_into_path); async_tex_data_file = g_file_new_for_path (async_tex_data_path); } if (cache_into != NULL) { RATE_LIMIT_BEGIN (io); if (g_file_query_exists (cache_into, NULL) && g_file_query_exists (async_tex_data_file, NULL)) { g_autoptr (GBytes) bytes = NULL; g_autoptr (GVariant) variant = NULL; GTimeSpan age_span = 0; g_autoptr (GlyLoader) loader = NULL; g_autoptr (GlyImage) image = NULL; bytes = g_file_load_bytes (async_tex_data_file, NULL, NULL, &local_error); if (bytes != NULL) variant = g_variant_new_from_bytes (G_VARIANT_TYPE ("a{sv}"), bytes, FALSE); if (variant != NULL) { gint64 birth_unix_stamp = 0; g_autoptr (GDateTime) birth_date_time = NULL; if (g_variant_lookup ( variant, "birth-unix-stamp", "x", &birth_unix_stamp)) { birth_date_time = g_date_time_new_from_unix_utc (birth_unix_stamp); age_span = g_date_time_difference (now, birth_date_time); } else local_error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "key \"birth-unix-stamp\" was not found"); } if (variant != NULL && age_span > 0) { if (age_span < CACHE_INVALID_AGE) { RATE_LIMIT_END (); RATE_LIMIT_BEGIN (glycin); loader = gly_loader_new (cache_into); /* We assume we exported this file, so uhhh it is safe to not use sandboxing, since it is faster :-) */ gly_loader_set_sandbox_selector (loader, GLY_SANDBOX_SELECTOR_NOT_SANDBOXED); image = gly_loader_load (loader, &local_error); if (image != NULL) frame = gly_image_next_frame (image, &local_error); RATE_LIMIT_END (); RATE_LIMIT_BEGIN (io); } else g_debug ("Metadata file %s for cached texture at %s indicates this resource is too old (GTimeSpan: %zu), " "reaping and fetching from original source at %s instead", async_tex_data_path, cache_into_path, age_span, source_uri); } else { g_warning ("Couldn't load associated metadata file %s for cached texture at %s, " "reaping and fetching from original source at %s instead: %s", async_tex_data_path, cache_into_path, source_uri, local_error != NULL ? local_error->message : "variant parse failed"); g_clear_pointer (&local_error, g_error_free); } if (frame == NULL) { if (local_error != NULL) g_warning ("An attempt to revive cached texture at %s has failed, " "reaping and fetching from original source at %s instead: %s", cache_into_path, source_uri, local_error->message); g_clear_pointer (&local_error, g_error_free); if (!g_file_delete (cache_into, NULL, &local_error)) { g_warning ("Couldn't reap cached texture at %s, this " "might lead to unexpected behavior: %s", cache_into_path, local_error->message); g_clear_pointer (&local_error, g_error_free); } } } RATE_LIMIT_END (); } if (frame == NULL) { g_autoptr (GFile) load_file = NULL; g_autoptr (GlyLoader) loader = NULL; g_autoptr (GlyImage) image = NULL; if (cache_into != NULL) { g_autoptr (GFile) parent = NULL; gboolean reconstruct = FALSE; parent = g_file_get_parent (cache_into); RATE_LIMIT_BEGIN (io); if (g_file_query_exists (parent, NULL)) { GFileType parent_type = G_FILE_TYPE_UNKNOWN; parent_type = g_file_query_file_type (parent, G_FILE_QUERY_INFO_NONE, NULL); if (parent_type != G_FILE_TYPE_DIRECTORY) { reconstruct = TRUE; result = g_file_delete (parent, cancellable, &local_error); if (!result) return dex_future_new_for_error (g_steal_pointer (&local_error)); } } else reconstruct = TRUE; if (reconstruct) { result = g_file_make_directory_with_parents ( parent, cancellable, &local_error); if (!result) { if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS)) g_clear_pointer (&local_error, g_error_free); else return dex_future_new_for_error (g_steal_pointer (&local_error)); } } RATE_LIMIT_END (); } if (is_http) { if (cache_into != NULL) load_file = g_object_ref (cache_into); else { g_autofree char *basename = NULL; g_autofree char *tmpl = NULL; g_autoptr (GFileIOStream) io = NULL; RATE_LIMIT_BEGIN (io); basename = g_file_get_basename (source); tmpl = g_strdup_printf ("XXXXXX-%s", basename); load_file = g_file_new_tmp (tmpl, &io, &local_error); if (load_file == NULL) return dex_future_new_for_error (g_steal_pointer (&local_error)); g_io_stream_close (G_IO_STREAM (io), NULL, NULL); RATE_LIMIT_END (); } result = dex_await ( dex_future_first ( bz_download_worker_invoke ( bz_download_worker_get_default (), source, load_file), /* increase the timeout as more failures stack up */ dex_timeout_new_seconds ((data->retries + 1) * HTTP_TIMEOUT_SECONDS), NULL), &local_error); if (!result) return dex_future_new_for_error (g_steal_pointer (&local_error)); } else { if (cache_into != NULL) { RATE_LIMIT_BEGIN (io); result = g_file_copy ( source, cache_into, G_FILE_COPY_OVERWRITE | G_FILE_COPY_ALL_METADATA, cancellable, NULL, NULL, &local_error); if (!result) return dex_future_new_for_error (g_steal_pointer (&local_error)); RATE_LIMIT_END (); load_file = g_object_ref (cache_into); } else load_file = g_object_ref (source); } RATE_LIMIT_BEGIN (glycin); loader = gly_loader_new (load_file); #ifdef SANDBOXED_LIBFLATPAK gly_loader_set_sandbox_selector (loader, GLY_SANDBOX_SELECTOR_NOT_SANDBOXED); #endif image = gly_loader_load (loader, &local_error); if (is_http && cache_into == NULL) /* delete tmp file */ g_file_delete (load_file, NULL, NULL); if (image == NULL || local_error != NULL) return dex_future_new_for_error (g_steal_pointer (&local_error)); frame = gly_image_next_frame (image, &local_error); if (frame == NULL) return dex_future_new_for_error (g_steal_pointer (&local_error)); RATE_LIMIT_END (); if (async_tex_data_file != NULL) { g_autoptr (GVariantBuilder) builder = NULL; g_autoptr (GVariant) variant = NULL; g_autoptr (GBytes) bytes = NULL; g_autoptr (GFileOutputStream) output = NULL; builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add ( builder, "{sv}", "birth-unix-stamp", g_variant_new_int64 (g_date_time_to_unix (now))); variant = g_variant_builder_end (builder); bytes = g_variant_get_data_as_bytes (variant); RATE_LIMIT_BEGIN (io); output = g_file_replace ( async_tex_data_file, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL, &local_error); if (output != NULL) { gssize bytes_written = 0; bytes_written = g_output_stream_write_bytes (G_OUTPUT_STREAM (output), bytes, NULL, &local_error); if (bytes_written > 0) g_output_stream_close (G_OUTPUT_STREAM (output), NULL, &local_error); } RATE_LIMIT_END (); if (local_error != NULL) g_warning ("Failed to write async-tex cache metadata to %s ;" "The image will be fully reloaded next time: %s", async_tex_data_path, local_error->message); g_clear_pointer (&local_error, g_error_free); } } texture = gly_gtk_frame_get_texture (frame); if (texture == NULL) return dex_future_new_reject ( G_IO_ERROR, G_IO_ERROR_FAILED, "texture loading failed"); return dex_future_new_for_object (texture); } static DexFuture * load_finally (DexFuture *future, LoadData *data) { g_autoptr (GError) local_error = NULL; g_autoptr (BzAsyncTexture) self = NULL; g_autoptr (GMutexLocker) locker = NULL; bz_weak_get_or_return_reject (self, &data->self); locker = g_mutex_locker_new (&self->mutex); dex_clear (&self->task); if (dex_future_is_resolved (future)) { GdkTexture *texture = NULL; texture = g_value_get_object (dex_future_get_value (future, NULL)); g_clear_object (&self->paintable); self->paintable = g_object_ref (GDK_PAINTABLE (texture)); if (!self->cache_acquired) { texture_cache_store (self->source_uri, texture); self->cache_acquired = TRUE; } g_idle_add_full ( G_PRIORITY_DEFAULT_IDLE, (GSourceFunc) idle_notify, g_object_ref (self), g_object_unref); return dex_future_new_for_object (self->paintable); } else { dex_future_get_value (future, &local_error); if (self->retries < MAX_LOAD_RETRIES) { if (self->retries == MAX_LOAD_RETRIES - 1) g_warning ("Loading %s failed: %s. Retrying in %d seconds. This will " "be the last retry, after which this texture will remain invalid", self->source_uri, local_error != NULL ? local_error->message : "unknown error", RETRY_INTERVAL_SECONDS); else g_warning ("Loading %s failed: %s. Retrying in %d seconds. Retries left: %d", self->source_uri, local_error != NULL ? local_error->message : "unknown error", RETRY_INTERVAL_SECONDS, MAX_LOAD_RETRIES - self->retries); self->retries++; dex_clear (&self->retry_future); self->retry_future = dex_future_then ( dex_timeout_new_seconds (RETRY_INTERVAL_SECONDS), (DexFutureCallback) retry_cb, load_data_ref (data), load_data_unref); } return dex_ref (future); } } static DexFuture * retry_cb (DexFuture *future, LoadData *data) { g_autoptr (BzAsyncTexture) self = NULL; g_autoptr (GMutexLocker) locker = NULL; bz_weak_get_or_return_reject (self, &data->self); locker = g_mutex_locker_new (&self->mutex); dex_clear (&self->retry_future); maybe_load (self); return NULL; } static gboolean idle_notify (BzAsyncTexture *self) { g_object_notify_by_pspec (G_OBJECT (self), props[PROP_LOADED]); gdk_paintable_invalidate_contents (GDK_PAINTABLE (self)); gdk_paintable_invalidate_size (GDK_PAINTABLE (self)); return G_SOURCE_REMOVE; } static void texture_cache_ensure (void) { if (texture_cache == NULL) texture_cache = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, cache_entry_data_unref); } static DexFuture * linger_timeout_finally (DexFuture *future, char *uri) { g_mutex_lock (&texture_cache_mutex); texture_cache_ensure (); g_hash_table_remove (texture_cache, uri); g_debug ("Texture cache: evicted '%s' after linger (table size: %u)", uri, g_hash_table_size (texture_cache)); g_mutex_unlock (&texture_cache_mutex); return dex_future_new_true (); } static GdkTexture * texture_cache_acquire (const char *uri) { g_autoptr (GMutexLocker) locker = NULL; CacheEntryData *data = NULL; locker = g_mutex_locker_new (&texture_cache_mutex); texture_cache_ensure (); data = g_hash_table_lookup (texture_cache, uri); if (data != NULL) { dex_clear (&data->linger_timeout); return g_object_ref (data->texture); } else return NULL; } static void texture_cache_store (const char *uri, GdkTexture *texture) { g_autoptr (CacheEntryData) data = NULL; g_mutex_lock (&texture_cache_mutex); texture_cache_ensure (); data = cache_entry_data_new (); data->texture = g_object_ref (texture); g_hash_table_replace ( texture_cache, g_strdup (uri), cache_entry_data_ref (data)); g_mutex_unlock (&texture_cache_mutex); } static void texture_cache_release (const char *uri) { g_autoptr (GMutexLocker) locker = NULL; CacheEntryData *data = NULL; g_autoptr (DexFuture) future = NULL; locker = g_mutex_locker_new (&texture_cache_mutex); texture_cache_ensure (); data = g_hash_table_lookup (texture_cache, uri); if (data == NULL) return; dex_clear (&data->linger_timeout); future = dex_timeout_new_seconds (TEXTURE_LINGER_SECONDS); future = dex_future_finally ( future, (DexFutureCallback) linger_timeout_finally, g_strdup (uri), g_free); data->linger_timeout = dex_ref (future); } bazaar-orig-v0.7.14/src/bz-donations-dialog.blp0000664000175000017500000000624315166123241020277 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzDonationsDialog: Adw.Dialog { width-request: 450; follows-content-size: true; child: Adw.ToolbarView { [top] Adw.HeaderBar { show-title: false; } content: ScrolledWindow { hscrollbar-policy: never; vscrollbar-policy: automatic; propagate-natural-height: true; min-content-height: 500; child: Box { orientation: vertical; Box { orientation: vertical; margin-start: 40; margin-end: 40; margin-top: 20; margin-bottom: 20; Label title { styles [ "title-1", ] wrap: true; justify: center; margin-bottom: 5; } Label subtitle { styles [ "dimmed", ] wrap: true; justify: center; margin-bottom: 15; } $BzAppstreamDescriptionRender { vexpand: true; appstream-description: bind template.release-notes; } Button release_button { styles [ "pill", ] margin-top: 15; margin-start: 25; margin-end: 20; margin-bottom: 15; halign: center; has-tooltip: true; clicked => $release_page_clicked(template); child: Box { orientation: horizontal; spacing: 10; Label { label: _("Full Release Notes"); wrap: true; wrap-mode: word_char; justify: right; } Image { icon-name: "external-link-symbolic"; } }; } } Adw.Bin { styles [ "bz-donations-dialog", ] child: Box { orientation: vertical; margin-start: 25; margin-end: 25; margin-top: 20; margin-bottom: 20; Label { styles [ "title-1", ] margin-top: 10; margin-bottom: 20; halign: center; wrap: true; justify: center; label: _("This release was made possible by users like you!"); } Label { margin-bottom: 20; wrap: true; justify: center; use-markup: true; label: _("I love making Bazaar, but I cannot do it alone. Help support further development by donating on Ko-Fi."); } Button donate_button { styles [ "pill", ] margin-start: 20; margin-end: 20; margin-bottom: 20; halign: center; has-tooltip: true; child: Adw.ButtonContent { label: _("Donate to Bazaar"); icon-name: "heart-filled-symbolic"; }; clicked => $donate_clicked(template); } }; } }; }; }; } bazaar-orig-v0.7.14/src/bz-download-worker.h0000664000175000017500000000304615166123241017632 0ustar hasanhasan/* bz-download-worker.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include G_BEGIN_DECLS #define BZ_TYPE_DOWNLOAD_WORKER (bz_download_worker_get_type ()) G_DECLARE_FINAL_TYPE (BzDownloadWorker, bz_download_worker, BZ, DOWNLOAD_WORKER, GObject) BzDownloadWorker * bz_download_worker_new (const char *name, GError **error); const char * bz_download_worker_get_name (BzDownloadWorker *self); void bz_download_worker_set_name (BzDownloadWorker *self, const char *name); DexFuture * bz_download_worker_invoke (BzDownloadWorker *self, GFile *src, GFile *dest); BzDownloadWorker * bz_download_worker_get_default (void); void bz_reap_default_download_workers (void); G_END_DECLS /* End of bz-download-worker.h */ bazaar-orig-v0.7.14/src/bz-appstream-description-render.c0000664000175000017500000004647415166123241022315 0ustar hasanhasan/* bz-appstream-description-render.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BAZAAR::APPSTREAM-DESCRIPTION-RENDER" #include "config.h" #include #include "bz-appstream-description-render.h" enum { NO_ELEMENT, PARAGRAPH, ORDERED_LIST, UNORDERED_LIST, LIST_ITEM, CODE, EMPHASIS, }; struct _BzAppstreamDescriptionRender { AdwBin parent_instance; char *appstream_description; /* Template widgets */ GtkTextView *text_view; }; G_DEFINE_FINAL_TYPE (BzAppstreamDescriptionRender, bz_appstream_description_render, ADW_TYPE_BIN); enum { PROP_0, PROP_APPSTREAM_DESCRIPTION, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void setup_text_tags (GtkTextBuffer *buffer); static void regenerate (BzAppstreamDescriptionRender *self); static void insert (BzAppstreamDescriptionRender *self, GtkTextBuffer *buffer, GtkTextIter *iter, const char *text); static void compile (BzAppstreamDescriptionRender *self, XbNode *node, GtkTextBuffer *buffer, GtkTextIter *iter, int parent_kind, int idx, gboolean is_last_sibling); static char * normalize_whitespace (const char *text); static const char * get_link_at_coords (GtkTextView *text_view, double x, double y); static void on_click_released (GtkGestureClick *gesture, int n_press, double x, double y, GtkTextView *text_view); static void on_motion (GtkEventControllerMotion *controller, double x, double y, GtkTextView *text_view); static void bz_appstream_description_render_dispose (GObject *object) { BzAppstreamDescriptionRender *self = BZ_APPSTREAM_DESCRIPTION_RENDER (object); g_clear_pointer (&self->appstream_description, g_free); G_OBJECT_CLASS (bz_appstream_description_render_parent_class)->dispose (object); } static void bz_appstream_description_render_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzAppstreamDescriptionRender *self = BZ_APPSTREAM_DESCRIPTION_RENDER (object); switch (prop_id) { case PROP_APPSTREAM_DESCRIPTION: g_value_set_string (value, bz_appstream_description_render_get_appstream_description (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_appstream_description_render_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzAppstreamDescriptionRender *self = BZ_APPSTREAM_DESCRIPTION_RENDER (object); switch (prop_id) { case PROP_APPSTREAM_DESCRIPTION: bz_appstream_description_render_set_appstream_description (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_appstream_description_render_class_init (BzAppstreamDescriptionRenderClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bz_appstream_description_render_set_property; object_class->get_property = bz_appstream_description_render_get_property; object_class->dispose = bz_appstream_description_render_dispose; props[PROP_APPSTREAM_DESCRIPTION] = g_param_spec_string ( "appstream-description", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-appstream-description-render.ui"); gtk_widget_class_bind_template_child (widget_class, BzAppstreamDescriptionRender, text_view); } static void setup_text_tags (GtkTextBuffer *buffer) { gtk_text_buffer_create_tag (buffer, "code", "family", "monospace", NULL); gtk_text_buffer_create_tag (buffer, "emphasis", "weight", PANGO_WEIGHT_BOLD, NULL); gtk_text_buffer_create_tag (buffer, "paragraph", "pixels-below-lines", 12, NULL); gtk_text_buffer_create_tag (buffer, "list-item-ul", "left-margin", 10, "pixels-below-lines", 4, "indent", -12, NULL); gtk_text_buffer_create_tag (buffer, "list-item-ol", "left-margin", 10, "pixels-below-lines", 4, "indent", -18, NULL); gtk_text_buffer_create_tag (buffer, "list-number", "family", "monospace", "foreground", "gray", NULL); } static void bz_appstream_description_render_init (BzAppstreamDescriptionRender *self) { GtkTextBuffer *buffer = NULL; GtkGesture *click = NULL; GtkEventController *motion = NULL; AdwStyleManager *style_manager = NULL; gtk_widget_init_template (GTK_WIDGET (self)); buffer = gtk_text_view_get_buffer (self->text_view); setup_text_tags (buffer); gtk_widget_remove_css_class (GTK_WIDGET (self->text_view), "view"); click = gtk_gesture_click_new (); gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (click), GDK_BUTTON_PRIMARY); g_signal_connect (click, "released", G_CALLBACK (on_click_released), self->text_view); gtk_widget_add_controller (GTK_WIDGET (self->text_view), GTK_EVENT_CONTROLLER (click)); motion = gtk_event_controller_motion_new (); g_signal_connect (motion, "motion", G_CALLBACK (on_motion), self->text_view); gtk_widget_add_controller (GTK_WIDGET (self->text_view), motion); style_manager = adw_style_manager_get_default (); g_signal_connect_object (style_manager, "notify::accent-color", G_CALLBACK (regenerate), self, G_CONNECT_SWAPPED); } static const char * get_link_at_coords (GtkTextView *text_view, double x, double y) { GtkTextIter iter = { 0 }; int bx = 0; int by = 0; g_autoptr (GSList) tags = NULL; GSList *l = NULL; const char *href = NULL; gtk_text_view_window_to_buffer_coords (text_view, GTK_TEXT_WINDOW_WIDGET, (int) x, (int) y, &bx, &by); gtk_text_view_get_iter_at_location (text_view, &iter, bx, by); tags = gtk_text_iter_get_tags (&iter); for (l = tags; l != NULL; l = l->next) { href = g_object_get_data (G_OBJECT (l->data), "href"); if (href != NULL) return href; } return NULL; } static void on_click_released (GtkGestureClick *gesture, int n_press, double x, double y, GtkTextView *text_view) { const char *href = NULL; g_autoptr (GtkUriLauncher) launcher = NULL; GtkWindow *root = NULL; href = get_link_at_coords (text_view, x, y); if (href == NULL) return; launcher = gtk_uri_launcher_new (href); root = GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (text_view))); gtk_uri_launcher_launch (launcher, root, NULL, NULL, NULL); } static void on_motion (GtkEventControllerMotion *controller, double x, double y, GtkTextView *text_view) { if (get_link_at_coords (text_view, x, y) != NULL) gtk_widget_set_cursor_from_name (GTK_WIDGET (text_view), "pointer"); else gtk_widget_set_cursor (GTK_WIDGET (text_view), NULL); } BzAppstreamDescriptionRender * bz_appstream_description_render_new (void) { return g_object_new (BZ_TYPE_APPSTREAM_DESCRIPTION_RENDER, NULL); } const char * bz_appstream_description_render_get_appstream_description (BzAppstreamDescriptionRender *self) { g_return_val_if_fail (BZ_IS_APPSTREAM_DESCRIPTION_RENDER (self), NULL); return self->appstream_description; } void bz_appstream_description_render_set_appstream_description (BzAppstreamDescriptionRender *self, const char *appstream_description) { g_return_if_fail (BZ_IS_APPSTREAM_DESCRIPTION_RENDER (self)); g_clear_pointer (&self->appstream_description, g_free); if (appstream_description != NULL) self->appstream_description = g_strdup (appstream_description); regenerate (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_APPSTREAM_DESCRIPTION]); } static void regenerate (BzAppstreamDescriptionRender *self) { g_autoptr (GError) local_error = NULL; g_autoptr (XbSilo) silo = NULL; g_autoptr (XbNode) root = NULL; GtkTextBuffer *buffer = NULL; GtkTextIter iter = { 0 }; int node_count = 0; buffer = gtk_text_view_get_buffer (self->text_view); gtk_text_buffer_set_text (buffer, "", 0); if (self->appstream_description == NULL) return; silo = xb_silo_new_from_xml (self->appstream_description, &local_error); if (silo == NULL) { g_warning ("Failed to parse appstream description XML: %s", local_error->message); return; } gtk_text_buffer_get_end_iter (buffer, &iter); root = xb_silo_get_root (silo); for (XbNode *n = g_object_ref (root); n != NULL;) { XbNode *last = NULL; node_count++; last = n; n = xb_node_get_next (n); g_object_unref (last); } for (int i = 0; root != NULL; i++) { g_autoptr (XbNode) next = NULL; gboolean is_last = (i == node_count - 1); compile (self, root, buffer, &iter, NO_ELEMENT, i, is_last); next = xb_node_get_next (root); g_object_unref (root); root = g_steal_pointer (&next); } } static void insert_url (BzAppstreamDescriptionRender *self, GtkTextBuffer *buffer, GtkTextIter *iter, const char *url) { g_autoptr (GdkRGBA) rgba = NULL; GtkTextTag *tag = NULL; GtkTextMark *mark = NULL; GtkTextIter start = { 0 }; rgba = adw_style_manager_get_accent_color_rgba (adw_style_manager_get_default ()); tag = gtk_text_buffer_create_tag (buffer, NULL, "foreground-rgba", rgba, "underline", PANGO_UNDERLINE_SINGLE, NULL); g_object_set_data_full (G_OBJECT (tag), "href", g_strdup (url), g_free); mark = gtk_text_buffer_create_mark (buffer, NULL, iter, TRUE); gtk_text_buffer_insert (buffer, iter, url, -1); gtk_text_buffer_get_iter_at_mark (buffer, &start, mark); gtk_text_buffer_apply_tag (buffer, tag, &start, iter); gtk_text_buffer_delete_mark (buffer, mark); } static void insert (BzAppstreamDescriptionRender *self, GtkTextBuffer *buffer, GtkTextIter *iter, const char *text) { g_auto (GStrv) parts = NULL; const char *p = NULL; const char *http = NULL; const char *https = NULL; const char *url_start = NULL; const char *url_end = NULL; const char *chunk = NULL; GtkTextMark *m = NULL; GtkTextIter si = { 0 }; g_autofree char *url = NULL; int j = 0; parts = g_strsplit (text, "**", -1); for (j = 0; parts[j] != NULL; j++) { chunk = parts[j]; if (j % 2 != 0) { m = gtk_text_buffer_create_mark (buffer, NULL, iter, TRUE); gtk_text_buffer_insert (buffer, iter, chunk, -1); gtk_text_buffer_get_iter_at_mark (buffer, &si, m); gtk_text_buffer_apply_tag_by_name (buffer, "emphasis", &si, iter); gtk_text_buffer_delete_mark (buffer, m); continue; } p = chunk; while (*p != '\0') { http = strstr (p, "http://"); https = strstr (p, "https://"); url_start = (http != NULL && (https == NULL || http < https)) ? http : https; if (url_start == NULL) { gtk_text_buffer_insert (buffer, iter, p, -1); break; } if (url_start > p) gtk_text_buffer_insert (buffer, iter, p, (int) (url_start - p)); url_end = url_start; while (*url_end != '\0' && !g_unichar_isspace (g_utf8_get_char (url_end))) url_end = g_utf8_next_char (url_end); url = g_strndup (url_start, url_end - url_start); for (char *end = url + strlen (url) - 1; end >= url && strchr (").,!?", *end) != NULL; end--) { *end = '\0'; url_end--; } insert_url (self, buffer, iter, url); p = url_end; } } } static void compile (BzAppstreamDescriptionRender *self, XbNode *node, GtkTextBuffer *buffer, GtkTextIter *iter, int parent_kind, int idx, gboolean is_last_sibling) { const char *element = NULL; const char *text = NULL; XbNode *child = NULL; int kind = NO_ELEMENT; GtkTextMark *start_mark = NULL; int child_count = 0; element = xb_node_get_element (node); text = xb_node_get_text (node); child = xb_node_get_child (node); kind = NO_ELEMENT; start_mark = NULL; if (element != NULL) { if (g_strcmp0 (element, "p") == 0) { kind = PARAGRAPH; start_mark = gtk_text_buffer_create_mark (buffer, NULL, iter, TRUE); } else if (g_strcmp0 (element, "ol") == 0) kind = ORDERED_LIST; else if (g_strcmp0 (element, "ul") == 0) kind = UNORDERED_LIST; else if (g_strcmp0 (element, "li") == 0) { kind = LIST_ITEM; start_mark = gtk_text_buffer_create_mark (buffer, NULL, iter, TRUE); if (parent_kind == ORDERED_LIST) { g_autofree char *prefix = NULL; GtkTextMark *prefix_start_mark; GtkTextIter prefix_start_iter; prefix_start_mark = gtk_text_buffer_create_mark (buffer, NULL, iter, TRUE); prefix = g_strdup_printf ("%d.", idx + 1); gtk_text_buffer_insert (buffer, iter, prefix, -1); gtk_text_buffer_get_iter_at_mark (buffer, &prefix_start_iter, prefix_start_mark); gtk_text_buffer_apply_tag_by_name (buffer, "list-number", &prefix_start_iter, iter); gtk_text_buffer_delete_mark (buffer, prefix_start_mark); } else gtk_text_buffer_insert (buffer, iter, "• ", -1); } else if (g_strcmp0 (element, "code") == 0) { kind = CODE; start_mark = gtk_text_buffer_create_mark (buffer, NULL, iter, TRUE); } else if (g_strcmp0 (element, "em") == 0) { kind = EMPHASIS; start_mark = gtk_text_buffer_create_mark (buffer, NULL, iter, TRUE); } } if (text != NULL) { g_autofree char *normalized = NULL; normalized = normalize_whitespace (text); if (normalized != NULL && *normalized != '\0') insert (self, buffer, iter, normalized); } for (int i = 0; child != NULL; i++) { const char *tail = NULL; XbNode *next = NULL; next = xb_node_get_next (child); compile (self, child, buffer, iter, kind, i, next == NULL); tail = xb_node_get_tail (child); if (tail != NULL) { g_autofree char *normalized = NULL; normalized = normalize_whitespace (tail); if (normalized != NULL && *normalized != '\0') insert (self, buffer, iter, normalized); } g_object_unref (child); child = next; child_count++; } if (start_mark != NULL) { GtkTextIter start_iter = { 0 }; gtk_text_buffer_get_iter_at_mark (buffer, &start_iter, start_mark); if (kind == CODE) gtk_text_buffer_apply_tag_by_name (buffer, "code", &start_iter, iter); else if (kind == EMPHASIS) gtk_text_buffer_apply_tag_by_name (buffer, "emphasis", &start_iter, iter); else if (kind == PARAGRAPH) gtk_text_buffer_apply_tag_by_name (buffer, "paragraph", &start_iter, iter); else if (kind == LIST_ITEM) { const char *tag_name = NULL; tag_name = (parent_kind == ORDERED_LIST) ? "list-item-ol" : "list-item-ul"; gtk_text_buffer_apply_tag_by_name (buffer, tag_name, &start_iter, iter); gtk_text_buffer_insert (buffer, iter, "\n", 1); } gtk_text_buffer_delete_mark (buffer, start_mark); } if (kind == PARAGRAPH && !is_last_sibling) gtk_text_buffer_insert (buffer, iter, "\n", 1); else if ((kind == ORDERED_LIST || kind == UNORDERED_LIST) && !is_last_sibling && child_count > 0) gtk_text_buffer_insert (buffer, iter, "\n", 1); } static char * normalize_whitespace (const char *text) { g_autoptr (GString) result = NULL; gboolean in_space = FALSE; gboolean at_start = TRUE; if (text == NULL) return NULL; result = g_string_new (NULL); for (const char *p = text; p != NULL && *p != '\0'; p = g_utf8_next_char (p)) { gunichar ch = 0; ch = g_utf8_get_char (p); if (g_unichar_isspace (ch)) { if (!at_start && !in_space) in_space = TRUE; } else { if (!at_start && in_space) g_string_append_c (result, ' '); g_string_append_unichar (result, ch); in_space = FALSE; at_start = FALSE; } } return g_string_free (g_steal_pointer (&result), FALSE); } /* End of bz-appstream-description-render.c */ bazaar-orig-v0.7.14/src/bz-developer-badge.h0000664000175000017500000000233515166123241017541 0ustar hasanhasan/* bz-developer-badge.h * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bz-entry.h" #include G_BEGIN_DECLS #define BZ_TYPE_DEVELOPER_BADGE (bz_developer_badge_get_type ()) G_DECLARE_FINAL_TYPE (BzDeveloperBadge, bz_developer_badge, BZ, DEVELOPER_BADGE, GtkButton) GtkWidget *bz_developer_badge_new (void); BzEntry *bz_developer_badge_get_entry (BzDeveloperBadge *self); void bz_developer_badge_set_entry (BzDeveloperBadge *self, BzEntry *entry); G_END_DECLS bazaar-orig-v0.7.14/src/bz-transaction-tile.blp0000664000175000017500000003054315166123241020324 0ustar hasanhasanusing Gtk 4.0; using Adw 1; template $BzTransactionTile: $BzListTile { child: Adw.Bin { child: Box { orientation: vertical; Box { orientation: horizontal; spacing: 10; margin-top: 10; margin-bottom: 10; margin-start: 10; margin-end: 4; Image { paintable: bind $get_main_icon(template.tracker) as <$GdkPaintable>; pixel-size: 64; valign: start; halign: start; styles [ "icon-dropshadow", ] } Box { valign: center; orientation: vertical; Label { styles [ "transaction-tile-title", ] hexpand: true; ellipsize: end; xalign: 0.0; label: bind template.tracker as <$BzTransactionEntryTracker>.entry as <$BzEntry>.title as ; } Revealer progress_bars_revealer { reveal-child: bind $list_has_items(template.tracker as <$BzTransactionEntryTracker>.current-ops) as ; transition-type: slide_down; styles [ "no-min-height", ] child: ListView { styles [ "navigation-sidebar", "installed-list-view", "user-data-list-view" ] visible: bind $invert_boolean($is_transaction_tracker_removal(template.tracker) as ) as ; model: NoSelection { model: bind template.tracker as <$BzTransactionEntryTracker>.current-ops; }; factory: BuilderListItemFactory { template ListItem { activatable: false; child: Box { orientation: vertical; spacing: 3; $BzProgressBar { hexpand: "true"; fraction: bind template.item as <$BzTransactionTask>.last-progress as <$BzBackendTransactionOpProgressPayload>.progress; } Label { styles [ "dimmed", "caption-heading", ] hexpand: true; xalign: 0; ellipsize: end; single-line-mode: true; label: bind $format_download_progress(template.item as <$BzTransactionTask>.last-progress as <$BzBackendTransactionOpProgressPayload>.bytes-transferred, template.item as <$BzTransactionTask>.op as <$BzBackendTransactionOpPayload>.download-size) as ; } }; } }; }; } Revealer { reveal-child: bind progress_bars_revealer.reveal-child inverted; child: Box { orientation: horizontal; layout-manager: Adw.WrapLayout { child-spacing: 4; line-spacing: 0; }; Box { visible: bind $is_entry_addon(template.tracker) as ; halign: start; spacing: 4; margin-top: 8; styles [ "green", "colored", "small-pill", "download-size-pill", ] Image { icon-name: "puzzle-piece-symbolic"; pixel-size: 12; } Label { styles [ "caption-heading", ] valign: center; xalign: 0.0; label: _("App Add-On"); } } Box { visible: bind $is_both($is_entry_runtime(template.tracker) as , $invert_boolean($is_entry_addon(template.tracker) as ) as ) as ; halign: start; spacing: 4; margin-top: 8; styles [ "blue", "colored", "small-pill", "download-size-pill", ] Image { icon-name: "application-x-sharedlib-symbolic"; pixel-size: 12; } Label { styles [ "caption-heading", ] valign: center; xalign: 0.0; label: _("Runtime"); } } Box { visible: bind $is_queued(template.tracker as <$BzTransactionEntryTracker>.status as <$BzTransactionEntryStatus>) as ; halign: start; spacing: 4; margin-top: 8; styles [ "grey", "colored", "small-pill", "download-size-pill", ] Label { styles [ "caption-heading", ] valign: center; xalign: 0.0; label: _("In Queue"); } } Box { visible: bind $is_completed(template.tracker as <$BzTransactionEntryTracker>.status as <$BzTransactionEntryStatus>) as ; halign: start; spacing: 4; margin-top: 8; styles [ "grey", "colored", "small-pill", "download-size-pill", ] Label { styles [ "caption-heading", ] valign: center; xalign: 0.0; label: _("Done"); } } Box { visible: bind $is_transaction_tracker_errored(template.tracker as <$BzTransactionEntryTracker>.finished-ops) as ; halign: start; spacing: 4; margin-top: 8; styles [ "error", "colored", "small-pill", "download-size-pill", ] Label { styles [ "caption-heading", ] valign: center; xalign: 0.0; label: _("Error"); } } Box { halign: start; spacing: 4; margin-top: 8; styles [ "installed-pill", "small-pill", "download-size-pill", ] visible: bind $is_transaction_tracker_removal(template.tracker) as ; Label { styles [ "caption-heading", ] valign: center; xalign: 0.0; label: bind $format_removal_size(template.tracker as <$BzTransactionEntryTracker>.entry as <$BzEntry>.installed-size) as ; } } }; } } Box { orientation: horizontal; spacing: 5; Button { visible: bind $is_both( $is_both($is_entry_application(template.tracker as <$BzTransactionEntryTracker>) as ,$is_completed(template.tracker as <$BzTransactionEntryTracker>.status as <$BzTransactionEntryStatus>) as ) as , $is_transaction_tracker_install(template.tracker as <$BzTransactionEntryTracker>) as ) as ; valign: center; label: _("Open"); clicked => $run_cb(template); styles [ "medium-pill", ] } Button { visible: bind $is_ongoing(template.tracker as <$BzTransactionEntryTracker>.status as <$BzTransactionEntryStatus>) as ; icon-name: "media-playback-stop-symbolic"; has-tooltip: true; valign: center; tooltip-text: _("Cancel Transaction"); clicked => $cancel_cb(template); styles [ "flat", ] } ToggleButton toggle { sensitive: bind $invert_boolean($is_empty(template.tracker as <$BzTransactionEntryTracker>.finished-ops) as ) as ; child: Image { pixel-size: 14; icon-name: "go-next-symbolic"; styles [ "accent", ] }; valign: center; styles [ "flat", "circular", "ops-toggle", ] } } } Revealer { reveal-child: bind toggle.active; child: Box { orientation: vertical; styles [ "operations", ] Separator {} ListView { styles [ "navigation-sidebar", "installed-list-view", ] model: NoSelection { model: bind template.tracker as <$BzTransactionEntryTracker>.finished-ops; }; factory: BuilderListItemFactory { template ListItem { activatable: false; child: Box { orientation: horizontal; spacing: 10; margin-start: 7; margin-end: 7; Image { styles [ "success", ] valign: center; icon-name: "check-plain-symbolic"; visible: bind $is_null(template.item as <$BzTransactionTask>.error) as ; } Image { styles [ "error", ] valign: center; icon-name: "cross-large-circle-filled-symbolic"; visible: bind $invert_boolean($is_null(template.item as <$BzTransactionTask>.error) as ) as ; } Box { valign: center; orientation: horizontal; spacing: 5; hexpand: true; Label { styles [ "dimmed", ] valign: center; hexpand: true; xalign: 0.0; ellipsize: end; single-line-mode: true; label: bind template.item as <$BzTransactionTask>.op as <$BzBackendTransactionOpPayload>.name; visible: bind $is_null(template.item as <$BzTransactionTask>.error) as ; } Label { styles [ "error", ] valign: center; hexpand: true; xalign: 0.0; ellipsize: end; single-line-mode: true; label: bind template.item as <$BzTransactionTask>.op as <$BzBackendTransactionOpPayload>.name; visible: bind $invert_boolean($is_null(template.item as <$BzTransactionTask>.error) as ) as ; has-tooltip: true; tooltip-text: bind template.item as <$BzTransactionTask>.error as ; } Button { icon-name: "info-outline-symbolic"; clicked => $error_clicked_cb(template); visible: bind $invert_boolean($is_null(template.item as <$BzTransactionTask>.error) as ) as ; has-tooltip: true; tooltip-text: _("Show Error Info"); styles [ "error", "flat", ] } } }; } }; } }; } }; }; } bazaar-orig-v0.7.14/src/bz-world-map.c0000664000175000017500000005346715166123241016425 0ustar hasanhasan/* bz-world-map.c * * Copyright 2025 Alexander Vanhee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include #include #include "bz-country-data-point.h" #include "bz-country.h" #include "bz-world-map-parser.h" #include "bz-world-map.h" #define OPACITY_MULTIPLIER 2 struct _BzWorldMap { GtkWidget parent_instance; BzWorldMapParser *parser; GListModel *countries; GListModel *model; double min_lon; double max_lon; double min_lat; double max_lat; GskPath **country_paths; guint *path_to_country; guint n_paths; gboolean cache_valid; GtkEventController *motion; GtkGesture *gesture; double offset_x; double offset_y; double scale; int hovered_country; double motion_x; double motion_y; guint max_downloads; GtkWidget *tooltip_box; GtkWidget *tooltip_label1; GtkWidget *tooltip_prefix_label; GtkWidget *tooltip_label2; }; G_DEFINE_FINAL_TYPE (BzWorldMap, bz_world_map, GTK_TYPE_WIDGET) enum { PROP_0, PROP_MODEL, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static guint get_downloads_for_country (BzWorldMap *self, const char *iso_code) { guint n_items = 0; if (self->model == NULL) return 0; n_items = g_list_model_get_n_items (self->model); for (guint i = 0; i < n_items; i++) { g_autoptr (BzCountryDataPoint) point = g_list_model_get_item (self->model, i); const char *country_code = bz_country_data_point_get_country_code (point); if (g_strcmp0 (country_code, iso_code) == 0) return bz_country_data_point_get_downloads (point); } return 0; } static void calculate_max_downloads (BzWorldMap *self) { guint n_items = 0; self->max_downloads = 0; if (self->model == NULL) return; n_items = g_list_model_get_n_items (self->model); for (guint i = 0; i < n_items; i++) { g_autoptr (BzCountryDataPoint) point = g_list_model_get_item (self->model, i); guint downloads = bz_country_data_point_get_downloads (point); if (downloads > self->max_downloads) self->max_downloads = downloads; } } static void calculate_bounds (BzWorldMap *self) { guint n_items = 0; if (self->countries == NULL) return; n_items = g_list_model_get_n_items (self->countries); self->min_lon = 180.0; self->max_lon = -180.0; self->min_lat = 90.0; self->max_lat = -90.0; for (guint i = 0; i < n_items; i++) { g_autoptr (BzCountry) country = g_list_model_get_item (self->countries, i); GVariant *coordinates = bz_country_get_coordinates (country); GVariantIter poly_iter, ring_iter, point_iter; GVariant *polygon = NULL; GVariant *ring = NULL; double lon, lat; if (coordinates == NULL) continue; g_variant_iter_init (&poly_iter, coordinates); while ((polygon = g_variant_iter_next_value (&poly_iter))) { g_variant_iter_init (&ring_iter, polygon); while ((ring = g_variant_iter_next_value (&ring_iter))) { g_variant_iter_init (&point_iter, ring); while (g_variant_iter_next (&point_iter, "(dd)", &lon, &lat)) { if (lon < self->min_lon) self->min_lon = lon; if (lon > self->max_lon) self->max_lon = lon; if (lat < self->min_lat) self->min_lat = lat; if (lat > self->max_lat) self->max_lat = lat; } g_clear_pointer (&ring, g_variant_unref); } g_clear_pointer (&polygon, g_variant_unref); } } } static void project_point (BzWorldMap *self, double lon, double lat, double width, double height, double *x, double *y) { double lon_range = self->max_lon - self->min_lon; double lat_range = self->max_lat - self->min_lat; *x = ((lon - self->min_lon) / lon_range) * width; *y = height - ((lat - self->min_lat) / lat_range) * height; } static void calculate_transform (BzWorldMap *self, double widget_width, double widget_height, double map_width, double map_height) { double scale_x = widget_width / map_width; double scale_y = widget_height / map_height; self->scale = MIN (scale_x, scale_y); self->offset_x = (widget_width - map_width * self->scale) / 2.0; self->offset_y = (widget_height - map_height * self->scale) / 2.0; } static void build_paths (BzWorldMap *self, double width, double height) { guint n_items = 0; guint path_index = 0; if (self->countries == NULL) return; if (self->country_paths != NULL) { for (guint i = 0; i < self->n_paths; i++) g_clear_pointer (&self->country_paths[i], gsk_path_unref); g_clear_pointer (&self->country_paths, g_free); } g_clear_pointer (&self->path_to_country, g_free); n_items = g_list_model_get_n_items (self->countries); self->n_paths = 0; for (guint i = 0; i < n_items; i++) { g_autoptr (BzCountry) country = NULL; GVariant *coordinates = NULL; GVariantIter poly_iter = { 0 }; GVariant *polygon = NULL; country = g_list_model_get_item (self->countries, i); coordinates = bz_country_get_coordinates (country); if (coordinates == NULL) continue; g_variant_iter_init (&poly_iter, coordinates); while ((polygon = g_variant_iter_next_value (&poly_iter))) { self->n_paths += g_variant_n_children (polygon); g_clear_pointer (&polygon, g_variant_unref); } } self->country_paths = g_new0 (GskPath *, self->n_paths); self->path_to_country = g_new0 (guint, self->n_paths); for (guint i = 0; i < n_items; i++) { g_autoptr (BzCountry) country = NULL; GVariant *coordinates = NULL; GVariantIter poly_iter = { 0 }; GVariant *polygon = NULL; country = g_list_model_get_item (self->countries, i); coordinates = bz_country_get_coordinates (country); if (coordinates == NULL) continue; g_variant_iter_init (&poly_iter, coordinates); while ((polygon = g_variant_iter_next_value (&poly_iter))) { GVariantIter ring_iter = { 0 }; GVariant *ring = NULL; g_variant_iter_init (&ring_iter, polygon); while ((ring = g_variant_iter_next_value (&ring_iter))) { g_autoptr (GskPathBuilder) builder = NULL; GVariantIter point_iter = { 0 }; double lon = 0.0; double lat = 0.0; gboolean first = TRUE; builder = gsk_path_builder_new (); g_variant_iter_init (&point_iter, ring); while (g_variant_iter_next (&point_iter, "(dd)", &lon, &lat)) { double x = 0.0; double y = 0.0; project_point (self, lon, lat, width, height, &x, &y); if (first) { gsk_path_builder_move_to (builder, x, y); first = FALSE; } else { gsk_path_builder_line_to (builder, x, y); } } gsk_path_builder_close (builder); self->country_paths[path_index] = gsk_path_builder_to_path (builder); self->path_to_country[path_index] = i; path_index++; g_clear_pointer (&ring, g_variant_unref); } g_clear_pointer (&polygon, g_variant_unref); } } self->cache_valid = TRUE; } static void invalidate_cache (BzWorldMap *self) { self->cache_valid = FALSE; gtk_widget_queue_draw (GTK_WIDGET (self)); } static void on_style_changed (AdwStyleManager *style_manager, GParamSpec *pspec, BzWorldMap *self) { invalidate_cache (self); } static void update_hovered_country (BzWorldMap *self, double x, double y) { double map_x; double map_y; map_x = (x - self->offset_x) / self->scale; map_y = (y - self->offset_y) / self->scale; self->motion_x = x; self->motion_y = y; self->hovered_country = -1; for (guint i = 0; i < self->n_paths; i++) { if (gsk_path_in_fill (self->country_paths[i], &GRAPHENE_POINT_INIT (map_x, map_y), GSK_FILL_RULE_WINDING)) { self->hovered_country = self->path_to_country[i]; break; } } } static void motion_event (BzWorldMap *self, gdouble x, gdouble y, GtkEventControllerMotion *controller) { int old_hovered; old_hovered = self->hovered_country; update_hovered_country (self, x, y); if (old_hovered != self->hovered_country || self->hovered_country >= 0) gtk_widget_queue_draw (GTK_WIDGET (self)); } static void motion_leave (BzWorldMap *self, GtkEventControllerMotion *controller) { if (self->hovered_country != -1) { self->hovered_country = -1; self->motion_x = -1.0; self->motion_y = -1.0; gtk_widget_queue_draw (GTK_WIDGET (self)); } } static void gesture_begin (BzWorldMap *self, double start_x, double start_y, GtkGestureDrag *gesture) { update_hovered_country (self, start_x, start_y); gtk_widget_queue_draw (GTK_WIDGET (self)); } static void gesture_update (BzWorldMap *self, double offset_x, double offset_y, GtkGestureDrag *gesture) { double start_x; double start_y; gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y); update_hovered_country (self, start_x + offset_x, start_y + offset_y); gtk_widget_queue_draw (GTK_WIDGET (self)); } static void gesture_end (BzWorldMap *self, double offset_x, double offset_y, GtkGestureDrag *gesture) { gtk_widget_queue_draw (GTK_WIDGET (self)); } static void bz_world_map_dispose (GObject *object) { BzWorldMap *self = BZ_WORLD_MAP (object); g_signal_handlers_disconnect_by_func (adw_style_manager_get_default (), on_style_changed, self); if (self->country_paths != NULL) { for (guint i = 0; i < self->n_paths; i++) g_clear_pointer (&self->country_paths[i], gsk_path_unref); g_free (self->country_paths); self->country_paths = NULL; } if (self->path_to_country != NULL) { g_free (self->path_to_country); self->path_to_country = NULL; } if (self->tooltip_box != NULL) gtk_widget_unparent (self->tooltip_box); g_clear_object (&self->countries); g_clear_object (&self->model); G_OBJECT_CLASS (bz_world_map_parent_class)->dispose (object); } static void bz_world_map_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzWorldMap *self = BZ_WORLD_MAP (object); switch (prop_id) { case PROP_MODEL: g_value_set_object (value, self->model); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_world_map_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzWorldMap *self = BZ_WORLD_MAP (object); switch (prop_id) { case PROP_MODEL: g_clear_object (&self->model); self->model = g_value_dup_object (value); calculate_max_downloads (self); gtk_widget_queue_draw (GTK_WIDGET (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_world_map_size_allocate (GtkWidget *widget, int width, int height, int baseline) { BzWorldMap *self = BZ_WORLD_MAP (widget); invalidate_cache (self); } static void bz_world_map_snapshot (GtkWidget *widget, GtkSnapshot *snapshot) { BzWorldMap *self = BZ_WORLD_MAP (widget); double widget_width = gtk_widget_get_width (widget); double widget_height = gtk_widget_get_height (widget); AdwStyleManager *style_manager = adw_style_manager_get_default (); g_autoptr (GdkRGBA) accent_color = adw_style_manager_get_accent_color_rgba (style_manager); GdkRGBA stroke_color = { 0 }; g_autoptr (GskStroke) stroke = gsk_stroke_new (0.5); g_autoptr (GskStroke) hover_stroke = gsk_stroke_new (1.5); double map_width = 1000.0; double map_height = 500.0; if (self->countries == NULL) return; gtk_widget_get_color (widget, &stroke_color); stroke_color.alpha = 0.3; if (!self->cache_valid) build_paths (self, map_width, map_height); calculate_transform (self, widget_width, widget_height, map_width, map_height); gtk_snapshot_save (snapshot); gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (self->offset_x, self->offset_y)); gtk_snapshot_scale (snapshot, self->scale, self->scale); for (guint i = 0; i < self->n_paths; i++) { guint country_idx = self->path_to_country[i]; g_autoptr (BzCountry) country = g_list_model_get_item (self->countries, country_idx); const char *iso_code = bz_country_get_iso_code (country); guint downloads = get_downloads_for_country (self, iso_code); GdkRGBA fill_color = *accent_color; if (self->max_downloads > 0 && downloads > 0) { double ratio = (double) downloads / (double) self->max_downloads; fill_color.alpha = CLAMP (ratio * OPACITY_MULTIPLIER, 0.1, 1.0); } else { fill_color.alpha = 0.0; } gtk_snapshot_append_fill (snapshot, self->country_paths[i], GSK_FILL_RULE_WINDING, &fill_color); gtk_snapshot_append_stroke (snapshot, self->country_paths[i], stroke, &stroke_color); } gtk_snapshot_restore (snapshot); if (self->hovered_country >= 0) { GdkRGBA hover_color = stroke_color; hover_color.alpha = 1.0; gtk_snapshot_save (snapshot); gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (self->offset_x, self->offset_y)); gtk_snapshot_scale (snapshot, self->scale, self->scale); for (guint i = 0; i < self->n_paths; i++) { if (self->path_to_country[i] == (guint) self->hovered_country) { gtk_snapshot_append_stroke (snapshot, self->country_paths[i], hover_stroke, &hover_color); } } gtk_snapshot_restore (snapshot); } if (self->hovered_country >= 0 && self->motion_x >= 0.0 && self->motion_y >= 0.0) { g_autoptr (BzCountry) country = g_list_model_get_item (self->countries, self->hovered_country); const char *iso_code = bz_country_get_iso_code (country); guint download_number = get_downloads_for_country (self, iso_code); const char *country_name = bz_country_get_name (country); g_autofree char *label1_text = g_strdup_printf ("%s", country_name); g_autofree char *label2_text = g_strdup_printf ("%'u", download_number); GtkRequisition natural_size; double card_x = 0.0; double card_y = 0.0; gtk_label_set_markup (GTK_LABEL (self->tooltip_label1), label1_text); gtk_label_set_text (GTK_LABEL (self->tooltip_prefix_label), C_ ("As in, \"100 Downloads\"", "Downloads")); gtk_label_set_text (GTK_LABEL (self->tooltip_label2), label2_text); gtk_widget_get_preferred_size (self->tooltip_box, NULL, &natural_size); gtk_widget_allocate (self->tooltip_box, natural_size.width, natural_size.height, -1, NULL); if (self->motion_x > widget_width / 2.0) card_x = self->motion_x - natural_size.width - 10.0; else card_x = self->motion_x + 10.0; card_y = self->motion_y + 10.0; gtk_snapshot_save (snapshot); gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (card_x, card_y)); gtk_widget_snapshot_child (widget, self->tooltip_box, snapshot); gtk_snapshot_restore (snapshot); } } static void bz_world_map_class_init (BzWorldMapClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_world_map_dispose; object_class->get_property = bz_world_map_get_property; object_class->set_property = bz_world_map_set_property; props[PROP_MODEL] = g_param_spec_object ( "model", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); widget_class->snapshot = bz_world_map_snapshot; widget_class->size_allocate = bz_world_map_size_allocate; } static void bz_world_map_init (BzWorldMap *self) { AdwStyleManager *style_manager = adw_style_manager_get_default (); g_autoptr (GError) error = NULL; GtkWidget *inner_box = NULL; GtkWidget *label2_box = NULL; self->parser = bz_world_map_parser_new (); self->hovered_country = -1; self->motion_x = -1.0; self->motion_y = -1.0; self->max_downloads = 0; self->motion = gtk_event_controller_motion_new (); g_signal_connect_swapped (self->motion, "motion", G_CALLBACK (motion_event), self); g_signal_connect_swapped (self->motion, "leave", G_CALLBACK (motion_leave), self); gtk_widget_add_controller (GTK_WIDGET (self), self->motion); self->gesture = gtk_gesture_drag_new (); gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (self->gesture), TRUE); g_signal_connect_swapped (self->gesture, "drag-begin", G_CALLBACK (gesture_begin), self); g_signal_connect_swapped (self->gesture, "drag-update", G_CALLBACK (gesture_update), self); g_signal_connect_swapped (self->gesture, "drag-end", G_CALLBACK (gesture_end), self); gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (self->gesture)); self->tooltip_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_widget_add_css_class (self->tooltip_box, "floating-tooltip"); gtk_widget_add_css_class (self->tooltip_box, "card"); inner_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4); gtk_widget_set_margin_start (inner_box, 12); gtk_widget_set_margin_end (inner_box, 12); gtk_widget_set_margin_top (inner_box, 12); gtk_widget_set_margin_bottom (inner_box, 12); self->tooltip_label1 = gtk_label_new (""); gtk_widget_add_css_class (self->tooltip_label1, "heading"); gtk_label_set_xalign (GTK_LABEL (self->tooltip_label1), 0.0); gtk_label_set_use_markup (GTK_LABEL (self->tooltip_label1), TRUE); gtk_box_append (GTK_BOX (inner_box), self->tooltip_label1); label2_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); self->tooltip_label2 = gtk_label_new (""); gtk_widget_add_css_class (self->tooltip_label2, "monospace"); gtk_label_set_xalign (GTK_LABEL (self->tooltip_label2), 0.0); gtk_box_append (GTK_BOX (label2_box), self->tooltip_label2); self->tooltip_prefix_label = gtk_label_new (""); gtk_widget_add_css_class (self->tooltip_prefix_label, "body"); gtk_widget_add_css_class (self->tooltip_prefix_label, "dim-label"); gtk_label_set_xalign (GTK_LABEL (self->tooltip_prefix_label), 0.0); gtk_box_append (GTK_BOX (label2_box), self->tooltip_prefix_label); gtk_box_append (GTK_BOX (inner_box), label2_box); gtk_box_append (GTK_BOX (self->tooltip_box), inner_box); gtk_widget_set_parent (self->tooltip_box, GTK_WIDGET (self)); g_signal_connect (style_manager, "notify::dark", G_CALLBACK (on_style_changed), self); g_signal_connect (style_manager, "notify::accent-color", G_CALLBACK (on_style_changed), self); if (bz_world_map_parser_load_from_resource (self->parser, "/io/github/kolunmi/Bazaar/countries.gvariant", &error)) { self->countries = g_object_ref (bz_world_map_parser_get_countries (self->parser)); calculate_bounds (self); g_clear_object (&self->parser); } else { g_warning ("BzWorldMap: Failed to load countries: %s", error->message); g_clear_object (&self->parser); } } GtkWidget * bz_world_map_new (void) { return g_object_new (BZ_TYPE_WORLD_MAP, NULL); } bazaar-orig-v0.7.14/src/bz-library-page.c0000664000175000017500000004317315166123241017072 0ustar hasanhasan/* bz-library-page.c * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "bz-entry-group.h" #include "bz-installed-tile.h" #include "bz-library-page.h" #include "bz-section-view.h" #include "bz-template-callbacks.h" #include "bz-transaction-tile.h" #include "bz-updates-card.h" #include "bz-util.h" struct _BzLibraryPage { AdwBin parent_instance; GListModel *model; BzTransactionManager *transactions; BzStateInfo *state; /* Template widgets */ AdwViewStack *stack; GtkText *search_bar; GtkScrolledWindow *scroll; GtkFilterListModel *filter_model; GtkCustomFilter *filter; GtkListView *list_view; GtkSortListModel *sort_model; GtkCustomSorter *sorter; GtkCheckButton *sort_name; GtkCheckButton *sort_size; }; G_DEFINE_FINAL_TYPE (BzLibraryPage, bz_library_page, ADW_TYPE_BIN) enum { PROP_0, PROP_MODEL, PROP_TRANSACTIONS, PROP_STATE, PROP_HAS_APPS, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; enum { SIGNAL_UPDATE, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL]; static void items_changed (BzLibraryPage *self, guint position, guint removed, guint added, GListModel *model); static void has_transactions_changed (BzLibraryPage *self, GParamSpec *pspec, BzTransactionManager *transactions); static void set_page (BzLibraryPage *self); static gboolean set_page_idle_cb (BzLibraryPage *self); static gboolean filter (BzEntryGroup *group, BzLibraryPage *self); static void bz_library_page_dispose (GObject *object) { BzLibraryPage *self = BZ_LIBRARY_PAGE (object); if (self->model != NULL) g_signal_handlers_disconnect_by_func (self->model, items_changed, self); if (self->transactions != NULL) g_signal_handlers_disconnect_by_func (self->transactions, has_transactions_changed, self); g_clear_object (&self->model); g_clear_object (&self->transactions); g_clear_object (&self->state); G_OBJECT_CLASS (bz_library_page_parent_class)->dispose (object); } static void bz_library_page_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BzLibraryPage *self = BZ_LIBRARY_PAGE (object); switch (prop_id) { case PROP_MODEL: g_value_set_object (value, bz_library_page_get_model (self)); break; case PROP_TRANSACTIONS: g_value_set_object (value, bz_library_page_get_transactions (self)); break; case PROP_STATE: g_value_set_object (value, bz_library_page_get_state (self)); break; case PROP_HAS_APPS: { guint n_apps = 0; if (self->model != NULL) n_apps = g_list_model_get_n_items (self->model); g_value_set_boolean (value, n_apps > 0); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bz_library_page_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BzLibraryPage *self = BZ_LIBRARY_PAGE (object); switch (prop_id) { case PROP_MODEL: bz_library_page_set_model (self, g_value_get_object (value)); break; case PROP_TRANSACTIONS: bz_library_page_set_transactions (self, g_value_get_object (value)); break; case PROP_STATE: bz_library_page_set_state (self, g_value_get_object (value)); break; case PROP_HAS_APPS: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static char * no_results_found_subtitle (gpointer object, const char *search_text) { if (search_text == NULL || *search_text == '\0') return g_strdup (""); return g_strdup_printf (_ ("No matches found for \"%s\" in the list of installed apps"), search_text); } static char * format_update_count (gpointer object, GListModel *updates) { guint n_updates = 0; if (updates == NULL) return g_strdup (""); n_updates = g_list_model_get_n_items (updates); return g_strdup_printf (ngettext ("%u Available Update", "%u Available Updates", n_updates), n_updates); } static void tile_activated_cb (BzListTile *tile) { BzLibraryPage *self = NULL; BzEntryGroup *group = NULL; g_assert (BZ_IS_LIST_TILE (tile)); self = (BzLibraryPage *) gtk_widget_get_ancestor (GTK_WIDGET (tile), BZ_TYPE_LIBRARY_PAGE); if (self == NULL) return; if (BZ_IS_INSTALLED_TILE (tile)) { group = bz_installed_tile_get_group (BZ_INSTALLED_TILE (tile)); } else if (BZ_IS_TRANSACTION_TILE (tile)) { BzTransactionEntryTracker *tracker = NULL; BzEntry *entry = NULL; tracker = bz_transaction_tile_get_tracker (BZ_TRANSACTION_TILE (tile)); if (tracker == NULL) return; entry = bz_transaction_entry_tracker_get_entry (tracker); group = bz_application_map_factory_convert_one ( bz_state_info_get_application_factory (self->state), gtk_string_object_new (bz_entry_get_id (entry))); } else return; if (group == NULL) return; gtk_widget_activate_action (GTK_WIDGET (self), "window.show-group", "s", bz_entry_group_get_id (group)); } static void search_text_changed (BzLibraryPage *self, GParamSpec *pspec, GtkEntry *entry) { gtk_filter_changed (GTK_FILTER (self->filter), GTK_FILTER_CHANGE_DIFFERENT); set_page (self); } static void reset_search_cb (BzLibraryPage *self, GtkButton *button) { gtk_text_set_buffer (self->search_bar, NULL); } static void n_filtered_items_changed (BzLibraryPage *self, GParamSpec *pspec, GtkFilterListModel *model) { set_page (self); } static void clear_tasks_cb (BzLibraryPage *self) { BzTransactionManager *manager = NULL; if (self->state == NULL) return; manager = bz_state_info_get_transaction_manager (self->state); if (manager != NULL) bz_transaction_manager_clear_finished (manager); } static void updates_card_update_cb (BzLibraryPage *self, GListModel *entries, BzUpdatesCard *card) { g_signal_emit (self, signals[SIGNAL_UPDATE], 0, entries); } static void global_search_cb (BzLibraryPage *self, GtkButton *button) { const char *text = NULL; text = gtk_editable_get_text (GTK_EDITABLE (self->search_bar)); if (text != NULL && *text != '\0') gtk_widget_activate_action (GTK_WIDGET (self), "app.search", "s", text); gtk_editable_set_text (GTK_EDITABLE (self->search_bar), ""); } static int sort_func (BzEntryGroup *a, BzEntryGroup *b, BzLibraryPage *self) { if (gtk_check_button_get_active (self->sort_size)) { guint64 size_a = 0; guint64 size_b = 0; size_a = bz_entry_group_get_installed_size (a); size_b = bz_entry_group_get_installed_size (b); return size_a > size_b ? -1 : size_a < size_b ? 1 : 0; } return g_utf8_collate (bz_entry_group_get_title (a), bz_entry_group_get_title (b)); } static void sort_changed_cb (BzLibraryPage *self, GtkCheckButton *button) { gtk_sorter_changed (GTK_SORTER (self->sorter), GTK_SORTER_CHANGE_DIFFERENT); } static void bz_library_page_class_init (BzLibraryPageClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = bz_library_page_dispose; object_class->get_property = bz_library_page_get_property; object_class->set_property = bz_library_page_set_property; props[PROP_MODEL] = g_param_spec_object ( "model", NULL, NULL, G_TYPE_LIST_MODEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_TRANSACTIONS] = g_param_spec_object ( "transactions", NULL, NULL, BZ_TYPE_TRANSACTION_MANAGER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_STATE] = g_param_spec_object ( "state", NULL, NULL, BZ_TYPE_STATE_INFO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_HAS_APPS] = g_param_spec_boolean ( "has-apps", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); signals[SIGNAL_UPDATE] = g_signal_new ( "update", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_LIST_MODEL); g_signal_set_va_marshaller ( signals[SIGNAL_UPDATE], G_TYPE_FROM_CLASS (klass), g_cclosure_marshal_VOID__OBJECTv); g_type_ensure (BZ_TYPE_SECTION_VIEW); g_type_ensure (BZ_TYPE_ENTRY_GROUP); g_type_ensure (BZ_TYPE_INSTALLED_TILE); g_type_ensure (BZ_TYPE_TRANSACTION_TILE); g_type_ensure (BZ_TYPE_UPDATES_CARD); gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-library-page.ui"); bz_widget_class_bind_all_util_callbacks (widget_class); gtk_widget_class_bind_template_child (widget_class, BzLibraryPage, stack); gtk_widget_class_bind_template_child (widget_class, BzLibraryPage, search_bar); gtk_widget_class_bind_template_child (widget_class, BzLibraryPage, scroll); gtk_widget_class_bind_template_child (widget_class, BzLibraryPage, filter_model); gtk_widget_class_bind_template_child (widget_class, BzLibraryPage, filter); gtk_widget_class_bind_template_child (widget_class, BzLibraryPage, list_view); gtk_widget_class_bind_template_child (widget_class, BzLibraryPage, sort_model); gtk_widget_class_bind_template_child (widget_class, BzLibraryPage, sorter); gtk_widget_class_bind_template_child (widget_class, BzLibraryPage, sort_name); gtk_widget_class_bind_template_child (widget_class, BzLibraryPage, sort_size); gtk_widget_class_bind_template_callback (widget_class, no_results_found_subtitle); gtk_widget_class_bind_template_callback (widget_class, format_update_count); gtk_widget_class_bind_template_callback (widget_class, tile_activated_cb); gtk_widget_class_bind_template_callback (widget_class, reset_search_cb); gtk_widget_class_bind_template_callback (widget_class, search_text_changed); gtk_widget_class_bind_template_callback (widget_class, n_filtered_items_changed); gtk_widget_class_bind_template_callback (widget_class, clear_tasks_cb); gtk_widget_class_bind_template_callback (widget_class, updates_card_update_cb); gtk_widget_class_bind_template_callback (widget_class, global_search_cb); gtk_widget_class_bind_template_callback (widget_class, sort_changed_cb); } static void bz_library_page_init (BzLibraryPage *self) { gtk_widget_init_template (GTK_WIDGET (self)); gtk_custom_filter_set_filter_func ( self->filter, (GtkCustomFilterFunc) filter, self, NULL); gtk_custom_sorter_set_sort_func ( self->sorter, (GCompareDataFunc) sort_func, self, NULL); } GtkWidget * bz_library_page_new (void) { return g_object_new (BZ_TYPE_LIBRARY_PAGE, NULL); } void bz_library_page_set_model (BzLibraryPage *self, GListModel *model) { g_return_if_fail (BZ_IS_LIBRARY_PAGE (self)); g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model)); if (self->model != NULL) g_signal_handlers_disconnect_by_func (self->model, items_changed, self); g_clear_object (&self->model); if (model != NULL) { self->model = g_object_ref (model); g_signal_connect_swapped (model, "items-changed", G_CALLBACK (items_changed), self); } g_idle_add_full ( G_PRIORITY_DEFAULT, (GSourceFunc) set_page_idle_cb, g_object_ref (self), g_object_unref); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MODEL]); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_HAS_APPS]); } GListModel * bz_library_page_get_model (BzLibraryPage *self) { g_return_val_if_fail (BZ_IS_LIBRARY_PAGE (self), NULL); return self->model; } void bz_library_page_set_transactions (BzLibraryPage *self, BzTransactionManager *transactions) { g_return_if_fail (BZ_IS_LIBRARY_PAGE (self)); g_return_if_fail (transactions == NULL || BZ_IS_TRANSACTION_MANAGER (transactions)); if (self->transactions != NULL) g_signal_handlers_disconnect_by_func (self->transactions, has_transactions_changed, self); g_clear_object (&self->transactions); if (transactions != NULL) { self->transactions = g_object_ref (transactions); g_signal_connect_swapped ( transactions, "notify::has-transactions", G_CALLBACK (has_transactions_changed), self); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TRANSACTIONS]); } BzTransactionManager * bz_library_page_get_transactions (BzLibraryPage *self) { g_return_val_if_fail (BZ_IS_LIBRARY_PAGE (self), NULL); return self->transactions; } void bz_library_page_set_state (BzLibraryPage *self, BzStateInfo *state) { g_return_if_fail (BZ_IS_LIBRARY_PAGE (self)); g_return_if_fail (state == NULL || BZ_IS_STATE_INFO (state)); g_clear_object (&self->state); if (state != NULL) self->state = g_object_ref (state); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_STATE]); } BzStateInfo * bz_library_page_get_state (BzLibraryPage *self) { g_return_val_if_fail (BZ_IS_LIBRARY_PAGE (self), NULL); return self->state; } gboolean bz_library_page_ensure_active (BzLibraryPage *self, const char *initial) { const char *text = NULL; g_return_val_if_fail (BZ_IS_LIBRARY_PAGE (self), FALSE); text = gtk_editable_get_text (GTK_EDITABLE (self->search_bar)); if (text != NULL && *text != '\0' && gtk_widget_has_focus (GTK_WIDGET (self->search_bar))) return FALSE; gtk_widget_grab_focus (GTK_WIDGET (self->search_bar)); gtk_editable_set_text (GTK_EDITABLE (self->search_bar), initial); if (initial != NULL) gtk_editable_set_position (GTK_EDITABLE (self->search_bar), g_utf8_strlen (initial, -1)); return TRUE; } void bz_library_page_reset_search (BzLibraryPage *self) { GtkAdjustment *vadjustment = NULL; g_return_if_fail (BZ_IS_LIBRARY_PAGE (self)); vadjustment = gtk_scrolled_window_get_vadjustment (self->scroll); gtk_adjustment_set_value (vadjustment, 0.0); gtk_text_set_buffer (self->search_bar, NULL); } static void items_changed (BzLibraryPage *self, guint position, guint removed, guint added, GListModel *model) { set_page (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_HAS_APPS]); } static void has_transactions_changed (BzLibraryPage *self, GParamSpec *pspec, BzTransactionManager *transactions) { set_page (self); } static void set_page (BzLibraryPage *self) { guint n_apps = 0; guint n_filtered = 0; gboolean has_transactions = FALSE; if (self->model != NULL) { n_apps = g_list_model_get_n_items (self->model); n_filtered = g_list_model_get_n_items (G_LIST_MODEL (self->filter_model)); } if (self->state != NULL) { BzTransactionManager *manager = NULL; manager = bz_state_info_get_transaction_manager (self->state); has_transactions = bz_transaction_manager_get_has_transactions (manager); } if (n_apps == 0 && !has_transactions) { gtk_editable_set_text (GTK_EDITABLE (self->search_bar), ""); adw_view_stack_set_visible_child_name (self->stack, "empty"); } else if (n_apps > 0 && n_filtered == 0) adw_view_stack_set_visible_child_name (self->stack, "no-results"); else adw_view_stack_set_visible_child_name (self->stack, "content"); } static gboolean set_page_idle_cb (BzLibraryPage *self) { set_page (self); return G_SOURCE_REMOVE; } static gboolean filter (BzEntryGroup *group, BzLibraryPage *self) { const char *id = NULL; const char *title = NULL; const char *text = NULL; if (bz_entry_group_is_addon (group)) return FALSE; id = bz_entry_group_get_id (group); title = bz_entry_group_get_title (group); text = gtk_editable_get_text (GTK_EDITABLE (self->search_bar)); if (text != NULL && *text != '\0') return strcasestr (id, text) != NULL || strcasestr (title, text) != NULL; else return TRUE; } bazaar-orig-v0.7.14/src/bz-root-curated-config.txt0000664000175000017500000000040215166123241020750 0ustar hasanhasanprefix=bz name=root_curated_config parent-prefix=g parent-name=object author=AUTOGEN include="bz-curated-row.h" property=css char G_TYPE_STRING string property=templates GListModel G_TYPE_LIST_MODEL object property=rows GListModel G_TYPE_LIST_MODEL object bazaar-orig-v0.7.14/src/bz-curated-image-info.txt0000664000175000017500000000063115166123241020541 0ustar hasanhasanprefix=bz name=curated_image_info parent-prefix=g parent-name=object author=AUTOGEN include= property=uri char G_TYPE_STRING string property=light_uri char G_TYPE_STRING string property=dark_uri char G_TYPE_STRING string property=width int G_TYPE_INT int property=height int G_TYPE_INT int property=can_shrink gboolean G_TYPE_BOOLEAN boolean property=fit GtkContentFit GTK_TYPE_CONTENT_FIT enum bazaar-orig-v0.7.14/src/bz-group-tile-css-watcher.h0000664000175000017500000000310215166123241021015 0ustar hasanhasan/* bz-group-tile-css-watcher.h * * Copyright 2025 Adam Masciola * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include "bz-entry-group.h" G_BEGIN_DECLS #define BZ_TYPE_GROUP_TILE_CSS_WATCHER (bz_group_tile_css_watcher_get_type ()) G_DECLARE_FINAL_TYPE (BzGroupTileCssWatcher, bz_group_tile_css_watcher, BZ, GROUP_TILE_CSS_WATCHER, GObject) BzGroupTileCssWatcher * bz_group_tile_css_watcher_new (void); GtkWidget * bz_group_tile_css_watcher_dup_widget (BzGroupTileCssWatcher *self); BzEntryGroup * bz_group_tile_css_watcher_get_group (BzGroupTileCssWatcher *self); void bz_group_tile_css_watcher_set_widget (BzGroupTileCssWatcher *self, GtkWidget *widget); void bz_group_tile_css_watcher_set_group (BzGroupTileCssWatcher *self, BzEntryGroup *group); G_END_DECLS /* End of bz-group-tile-css-watcher.h */ bazaar-orig-v0.7.14/subprojects/0000775000175000017500000000000015166123241015503 5ustar hasanhasanbazaar-orig-v0.7.14/subprojects/.wraplock0000664000175000017500000000000015166123241017314 0ustar hasanhasanbazaar-orig-v0.7.14/subprojects/.gitignore0000664000175000017500000000002315166123241017466 0ustar hasanhasanblueprint-compiler bazaar-orig-v0.7.14/subprojects/blueprint-compiler.wrap0000664000175000017500000000026115166123241022211 0ustar hasanhasan[wrap-git] directory = blueprint-compiler url = https://gitlab.gnome.org/GNOME/blueprint-compiler.git revision = v0.20.0 depth = 1 [provide] program_names = blueprint-compiler bazaar-orig-v0.7.14/data/0000775000175000017500000000000015166123241014051 5ustar hasanhasanbazaar-orig-v0.7.14/data/meson.build0000664000175000017500000000344115166123241016215 0ustar hasanhasandesktop_file = i18n.merge_file( input: 'io.github.kolunmi.Bazaar.desktop.in', output: 'io.github.kolunmi.Bazaar.desktop', type: 'desktop', po_dir: '../po', install: true, install_dir: get_option('datadir') / 'applications' ) desktop_utils = find_program('desktop-file-validate', required: false) if desktop_utils.found() test('Validate desktop file', desktop_utils, args: [desktop_file]) endif appstream_file = i18n.merge_file( input: 'io.github.kolunmi.Bazaar.metainfo.xml.in', output: 'io.github.kolunmi.Bazaar.metainfo.xml', po_dir: '../po', install: true, install_dir: get_option('datadir') / 'metainfo' ) appstreamcli = find_program('appstreamcli', required: false, disabler: true) test('Validate appstream file', appstreamcli, args: ['validate', '--no-net', '--explain', appstream_file]) install_data('io.github.kolunmi.Bazaar.gschema.xml', install_dir: get_option('datadir') / 'glib-2.0' / 'schemas' ) compile_schemas = find_program('glib-compile-schemas', required: false, disabler: true) test('Validate schema file', compile_schemas, args: ['--strict', '--dry-run', meson.current_source_dir()]) service_conf = configuration_data() service_conf.set('bindir', get_option('prefix') / get_option('bindir')) configure_file( input: 'io.github.kolunmi.Bazaar.service.in', output: 'io.github.kolunmi.Bazaar.service', configuration: service_conf, install_dir: get_option('prefix') / 'lib' / 'systemd' / 'user' ) service_conf = configuration_data() configure_file( input: 'io.github.kolunmi.Bazaar.search-provider.ini.in', output: 'io.github.kolunmi.Bazaar.search-provider.ini', configuration: service_conf, install_dir: get_option('datadir') / 'gnome-shell' / 'search-providers' ) subdir('icons') subdir('dbus') bazaar-orig-v0.7.14/data/dbus/0000775000175000017500000000000015166123241015006 5ustar hasanhasanbazaar-orig-v0.7.14/data/dbus/meson.build0000664000175000017500000000047015166123241017151 0ustar hasanhasanservice_conf = configuration_data() service_conf.set('bindir', get_option('prefix') / get_option('bindir')) configure_file( input: 'io.github.kolunmi.Bazaar.service.in', output: 'io.github.kolunmi.Bazaar.service', configuration: service_conf, install_dir: get_option('datadir') / 'dbus-1' / 'services' ) bazaar-orig-v0.7.14/data/dbus/io.github.kolunmi.Bazaar.service.in0000664000175000017500000000017315166123241023542 0ustar hasanhasan[D-BUS Service] Name=io.github.kolunmi.Bazaar SystemdService=io.github.kolunmi.Bazaar.service Exec=@bindir@/bazaar service bazaar-orig-v0.7.14/data/icons/0000775000175000017500000000000015166123241015164 5ustar hasanhasanbazaar-orig-v0.7.14/data/icons/meson.build0000664000175000017500000000107315166123241017327 0ustar hasanhasanapplication_id = 'io.github.kolunmi.Bazaar' scalable_dir = 'hicolor' / 'scalable' / 'apps' if get_option('development') icon_file = '@0@.Devel.svg'.format(application_id) else icon_file = '@0@.svg'.format(application_id) endif install_data( scalable_dir / icon_file, install_dir: get_option('datadir') / 'icons' / scalable_dir, rename: '@0@.svg'.format(application_id) ) symbolic_dir = 'hicolor' / 'symbolic' / 'apps' install_data( symbolic_dir / ('@0@-symbolic.svg').format(application_id), install_dir: get_option('datadir') / 'icons' / symbolic_dir ) bazaar-orig-v0.7.14/data/icons/hicolor/0000775000175000017500000000000015166123241016623 5ustar hasanhasanbazaar-orig-v0.7.14/data/icons/hicolor/scalable/0000775000175000017500000000000015166123241020371 5ustar hasanhasanbazaar-orig-v0.7.14/data/icons/hicolor/scalable/apps/0000775000175000017500000000000015166123241021334 5ustar hasanhasanbazaar-orig-v0.7.14/data/icons/hicolor/scalable/apps/io.github.kolunmi.Bazaar.Devel.svg0000664000175000017500000001025515166123241027662 0ustar hasanhasanbazaar-orig-v0.7.14/data/icons/hicolor/scalable/apps/io.github.kolunmi.Bazaar.svg0000664000175000017500000001030515166123241026620 0ustar hasanhasanbazaar-orig-v0.7.14/data/icons/hicolor/symbolic/0000775000175000017500000000000015166123241020444 5ustar hasanhasanbazaar-orig-v0.7.14/data/icons/hicolor/symbolic/apps/0000775000175000017500000000000015166123241021407 5ustar hasanhasanbazaar-orig-v0.7.14/data/icons/hicolor/symbolic/apps/io.github.kolunmi.Bazaar-symbolic.svg0000664000175000017500000000473015166123241030517 0ustar hasanhasan bazaar-orig-v0.7.14/data/icons/io.github.kolunmi.Bazaar.Source.svg0000664000175000017500000074461215166123241023726 0ustar hasanhasan Adwaita Icon Template image/svg+xml GNOME Design Team Adwaita Icon Template Hicolor Symbolic bazaar-orig-v0.7.14/data/io.github.kolunmi.Bazaar.gschema.xml0000664000175000017500000000623015166123241022746 0ustar hasanhasan true

Hide EOL Entries Hide EOL entries and entries depending on them false Only Show Free Software Hide proprietary software false Show Only Flathub Content Hide applications which do not originate from Flathub false Show Only Verified Content Hide applications which are not verified on Flathub true Debounce Search Inputs Add a delay before searching to prevent instant replies while typing 'accent-color' Global Progress Bar Theme Describes the look of the global progress bar false Rotate selected flag by 90 degrees (1220, 900) Saved Window Dimensions The window dimensions to be used by the next Bazaar window true Force Adwaita Icon Theme Override the icon theme with Adwaita true Show Permission Warning Banner Show a warning banner on the permissions page bazaar-orig-v0.7.14/data/io.github.kolunmi.Bazaar.metainfo.xml.in0000664000175000017500000006100315166123241023545 0ustar hasanhasan io.github.kolunmi.Bazaar CC0-1.0 GPL-3.0-or-later Bazaar Discover and manage applications

A fast and modern app store for Linux with a focus on discovering and installing Flatpak apps and addons, particularly from Flathub.

  • Queue multiple installs and keep browsing
  • Easily view app permissions
  • Sign in to Flathub to view and manage your favorites
  • Search apps directly from GNOME Shell
pointing keyboard touch 360 Adam Masciola https://usebazaar.org/ https://github.com/bazaar-org/bazaar https://github.com/bazaar-org/bazaar/issues https://github.com/bazaar-org/bazaar/tree/master/po https://github.com/bazaar-org/bazaar/blob/master/README.md https://github.com/bazaar-org/bazaar/discussions https://github.com/sponsors/kolunmi https://github.com/kolunmi https://github.com/bazaar-org/bazaar bazaar io.github.kolunmi.Bazaar.desktop #ffbe6f #c11c2b https://github.com/user-attachments/assets/b7d749fb-ecc0-4f3e-a965-15b6771c54d3 The home page displaying Flathub apps https://github.com/user-attachments/assets/7d306fbe-e1a7-4c74-91b2-f5061aba2c56 Exhibit app page https://github.com/user-attachments/assets/a25269a3-0560-4d75-9166-a38bc7a7f429 Library page https://github.com/user-attachments/assets/733bff33-a206-43b9-bbaf-08df9d1c65f3 Search page https://github.com/user-attachments/assets/fd721125-1842-4cf1-9ab3-a70ef6b9ce10 Category page https://github.com/bazaar-org/bazaar/releases/tag/v0.7.14

New Features

  • Rework the add-ons dialog
  • Add a gradient under the download timeline
  • Add a filter button to the search page
  • Add a button to show the EULA for some proprietary apps
  • Make the names of verified developers clickable links

Fixes

  • Fix the colours of the update card
  • Make the update banner follow the accent colour

Thanks for reading, and have a great day!

https://github.com/bazaar-org/bazaar/releases/tag/v0.7.13

Changes

  • Update to GNOME 50 Runtime
  • Force Adwaita icon theme to ensure consistency
  • Add support for clickable links in app descriptions
  • Add timed lingering cache to async textures, thereby reducing image flickering
  • Add ability to sort installed apps by size in library view
  • Add BAZAAR_N_DOWNLOAD_WORKERS envvar support

Bug Fixes

  • Fix double shadow around update cards
  • Fix global progress button displaying a focus ring when invisible
  • Fix incorrect total size displayed on update tasks
  • Fix empty UI when Flathub hasn't finished syncing yet

Thanks for reading and have a great day!

https://github.com/bazaar-org/bazaar/releases/tag/v0.7.11

This release contains many technical improvements. This changelog reflects roughly 2 weeks of work.

Changes

  • Respect system parental controls settings
  • Reap download workers when all windows are closed, reducing total memory usage
  • Add mnemonics to full app view
  • Many updates to language translations

Bug Fixes

  • Fix broken library page when backing installed apps model is empty
  • Fix int casting bug that was causing RetroDeck to appear to be 18.4 exabytes
  • Make "all apps" category pages respect global filters
  • Fix some text wrapping issues

Thanks for reading and have a great day!

https://github.com/bazaar-org/bazaar/releases/tag/v0.7.10

This release fixes some bugs and greatly improves search functionality.

If you missed the previous release, in 0.7.9 we also added the ability to cancel transactions in the library view, a brand new screenshots carousel, search suggestion buttons, and app runtime size information. You can also now skip confirmation dialogs by holding shift as you start a transaction.

Thanks for reading!

https://github.com/bazaar-org/bazaar/releases/tag/v0.7.9

**New Features**

  • Search suggestion pills
  • **Cancel installation** transactions
  • Skip dialogs by pressing shift
  • Runtime size info for app pages

**Updated**

  • Redesigned "What's New" dialog
  • Improved search results by utilizing Flathub rankings
  • Improved screenshots carousel
https://github.com/bazaar-org/bazaar/releases/tag/v0.7.8

This release lets you view and remove user-scoped installed apps from the library page in the Flatpak version of the app. Installing from user remotes is not supported yet.

https://github.com/bazaar-org/bazaar/releases/tag/v0.7.7

This release comes with the following improvements:

  • Merges the task sidebar and install page into the library page
  • Add installed version numbers of each app on the library and app pages
  • Add donations dialog
  • Fix broken addon and runtime eol detection
  • Add `enable-bulk-install` key to curated sections
  • Add `override-eol-markings` main config string list
https://github.com/bazaar-org/bazaar/releases/tag/v0.7.6

This release comes with the following improvements:

  • Improve context dialogs
  • Fix leftover data bar being shown prematurely
  • Have a rotation toggle for flags
  • Add hard check to prevent removing Bazaar flatpak
  • Improve download statistics tooltips
  • Add read support for flatpak bundles
  • Fix critical output sometimes during transactions
  • Fix error popover refusing to spawn in transaction sidebar
https://github.com/bazaar-org/bazaar/releases/tag/v0.7.5

Minor bugfix release

https://github.com/bazaar-org/bazaar/releases/tag/v0.7.4

This release comes with the following improvements:

  • Fix issue where installed page is empty on opening second window
  • Fix screenshot flickering in search results
  • Fix pride flags sometimes not showing on certain locales
  • Add "Install all" to favorites page
https://github.com/bazaar-org/bazaar/releases/tag/v0.7.3

This release comes with the following improvements:

  • Trash user data instead of deleting
  • Tweaks to permissions dialog
  • Fix broken EOL filtering
  • Add text filter to installed page
  • Add optional translations mappings for string properties in YAML configs
  • Hide EOL apps by default
  • Many other minor bug fixes and improvements
https://github.com/bazaar-org/bazaar/releases/tag/v0.7.2

This small release ensures the new icon is rendered correctly on KDE Plasma.

https://github.com/bazaar-org/bazaar/releases/tag/v0.7.1

This release comes with the following improvements:

  • New market stall icon
  • Remove Flathub styling
  • Add horizontal versions of pride flags
  • Text selection in app descriptions can be made across paragraph breaks
  • Support YAML anchors and aliases in config parsing
  • Drastically reduce disk cache writes over time by skipping unchanged entries
  • Show background status in popover
  • Add app permission system
  • Add back release URLs
  • Fix sync-remotes action in shortcut dialog
  • Fix visual hiccups in comet animations
https://github.com/bazaar-org/bazaar/releases/tag/v0.7.0

This release comes with the following improvements:

  • Flathub account support with the ability to manage bookmarks
  • Flathub bookmarks replace star count; you can add or remove bookmarks from app pages
  • An "Only Show Verified" option
  • Exhaustive category pages for most categories
  • An "Adwaita" or "KDE" category shown based on desktop environment
  • Updated installed indicator for app tiles
  • 3 new flag options
  • Fixed GNOME search provider to show the app page instead of search
  • Fixed issue where flatpakref URIs did not open when the app wasn't running in the background
  • Fixed issue where some proprietary apps were marked as "Special License"
  • Fixed issue where graphs did not work with touch
https://github.com/bazaar-org/bazaar/releases/tag/v0.6.3

Another quick release to restore alphabetical sorting on the installed page

https://github.com/bazaar-org/bazaar/releases/tag/v0.6.2

Quick release to allow manual refresh if flathub is being flaky

https://github.com/bazaar-org/bazaar/releases/tag/v0.6.1

This release comes with the following improvements:

  • Fix frequent disk writes; set refresh frequency to 1 day rather than 1 hour
  • Add "Delete User Data" option when uninstalling an application
  • Version cache to prevent incompatibility between Bazaar versions
https://github.com/bazaar-org/bazaar/releases/tag/v0.6.0

This release comes with the following improvements:

  • Reworked loading to be substantially faster after first start via async loading
  • A gaming section on the Flathub page
  • Improved UI on mobile, especially on app pages
  • Verified badges next to most places where apps are shown
  • A popover that explains what verification and non-verification mean
  • An "other apps by" page for when a developer has more than 6 apps
  • Tags that show other apps with the same tag when pressed
  • An age rating dialog
  • Changed search filters into global content filters
  • 5 new pride flags
https://github.com/bazaar-org/bazaar/releases/tag/v0.5.10

This release comes with the following improvements:

  • Add "hide-eol" preferences option to prevent Bazaar from showing end-of-life applications or applications which depend on end-of-life runtimes
  • Fix global progress bar theme sometimes not syncing with preferences
  • Show version next to addon name in the addons dialog
https://github.com/bazaar-org/bazaar/releases/tag/v0.5.9

This release comes with the following improvements:

  • Add "On the go" section and mobile cateogry
  • Greatly decrease reported memory usage
  • Rework search UI
  • Rework page stack navigation
  • Change screenshot dialog to page
https://github.com/bazaar-org/bazaar/releases/tag/v0.5.8

This release comes with the following improvements:

  • Fix slow/inconsistent image loading
  • Fix context row in full view
https://github.com/bazaar-org/bazaar/releases/tag/v0.5.7

This release comes with the following improvements:

  • Rework full view layout
  • Improve progress bar theme selection
  • Reduce quantity and improve quality of search results
  • Allow the application window to fit on mobile screen sizes
https://github.com/bazaar-org/bazaar/releases/tag/v0.5.6

This release comes with the following improvements:

  • Add interactive screenshot dialog
  • Fix empty update dialogs
  • Greatly improve look of app description rendering
  • Add pending state to the global progress bar
  • Add featured apps carousel
https://github.com/bazaar-org/bazaar/releases/tag/v0.5.5

More improvements:

  • Improve design of transaction dialog
  • Update remove button pulse effect and comet size curve
  • Reap and reload cached textures after a day
  • Eliminate some crashes caused by race conditions
  • Change preferences group to context bar in full view
  • Switch side panels to sidebars and use flat header bar designs
  • Add really useful app size dialog :)
https://github.com/bazaar-org/bazaar/releases/tag/v0.5.4

Some improvements:

  • Make the global progress bar customizable with pride flags! Check preferences
  • Add a new world map page to the download statistics dialog
  • Allow clicking on entries on transaction sidebar to navigate to the original store page
  • Add Alexander Vanhee to the developer credits
https://github.com/bazaar-org/bazaar/releases/tag/v0.5.3

Some improvements:

  • Overhaul download history graph; make it interactive
  • Smarter "back" functionality
  • Hide bottom bar more often on small window sizes
  • Make "light-banner" and "dark-banner" keys available to curated configs
https://github.com/bazaar-org/bazaar/releases/tag/v0.5.2

This release includes:

  • 553d041 * chore(po): update Ukrainian translation (#408)
  • 711732a * Rework Version History (#407)
  • d2d3771 * Calculate detailed app tiles text color based on luminance of background accent color (#405)
  • 3787e6e * Save window size in gsettings
  • 18ba76c * AsyncTexture: increase HTTP timeout to 5 seconds
  • 980f752 * SearchWidget: prevent invalid item selection
  • ab95593 * Add installed icons to app tiles (#404)
  • 203754b * (UI) Improve visiblility of add-on feature (#403)
  • 069ce61 * fix installed page list outline ring (#402)
  • da9f7b8 * (UX) Refine the Flathub views to be denser and have less partial lines (#401)
  • a6939ba * fix(po): fix Ukrainian translation (#400)
  • 35c9611 * decrease app-tile description width reqs
  • 6098be7 * chore(po): update Polish translation (#397)
  • 2944d1e * change per section limit to 12 from 9 (#396)
  • 0b04284 * Update Japanese Translation (#394)
  • fa60f4f * Move to brand new shiny Adw.ShortcutsDialog (#395)
https://github.com/bazaar-org/bazaar/releases/tag/v0.5.1 https://github.com/bazaar-org/bazaar/releases/tag/v0.5.0 https://github.com/bazaar-org/bazaar/releases/tag/v0.4.11 https://github.com/bazaar-org/bazaar/releases/tag/v0.4.10 https://github.com/bazaar-org/bazaar/releases/tag/v0.4.9 https://github.com/bazaar-org/bazaar/releases/tag/v0.4.8 https://github.com/bazaar-org/bazaar/releases/tag/v0.4.7 https://github.com/bazaar-org/bazaar/releases/tag/v0.4.6 https://github.com/bazaar-org/bazaar/releases/tag/v0.4.5 https://github.com/bazaar-org/bazaar/releases/tag/v0.4.4 https://github.com/bazaar-org/bazaar/releases/tag/v0.4.3 https://github.com/bazaar-org/bazaar/releases/tag/v0.4.2 https://github.com/bazaar-org/bazaar/releases/tag/v0.4.1 https://github.com/bazaar-org/bazaar/releases/tag/v0.4.0 https://github.com/bazaar-org/bazaar/releases/tag/v0.3.2 https://github.com/bazaar-org/bazaar/releases/tag/v0.3.1 https://github.com/bazaar-org/bazaar/releases/tag/v0.3.0 https://github.com/bazaar-org/bazaar/releases/tag/v0.2.3 https://github.com/bazaar-org/bazaar/releases/tag/v0.2.2 https://github.com/bazaar-org/bazaar/releases/tag/v0.2.1 https://github.com/bazaar-org/bazaar/releases/tag/v0.2.0 https://github.com/bazaar-org/bazaar/releases/tag/v0.1.0
bazaar-orig-v0.7.14/data/io.github.kolunmi.Bazaar.desktop.in0000664000175000017500000000075115166123241022620 0ustar hasanhasan[Desktop Entry] Name=Bazaar Comment=Add, remove or update flatpak software on this computer Exec=bazaar %U Icon=io.github.kolunmi.Bazaar Terminal=false Type=Application Categories=Utility; Keywords=GTK;System;PackageManager;Discover;Flatpak;Software;Store; StartupNotify=true MimeType=x-scheme-handler/appstream;x-scheme-handler/flatpak;x-scheme-handler/flatpak+https; Actions=new-window; X-Purism-FormFactor=Workstation;Mobile; [Desktop Action new-window] Name=New Window Exec=bazaar %U bazaar-orig-v0.7.14/data/io.github.kolunmi.Bazaar.service.in0000664000175000017500000000023615166123241022605 0ustar hasanhasan[Unit] Description=Bazaar Service PartOf=graphical-session.target [Service] Type=dbus BusName=io.github.kolunmi.Bazaar ExecStart=@bindir@/bazaar --no-window bazaar-orig-v0.7.14/data/io.github.kolunmi.Bazaar.search-provider.ini.in0000664000175000017500000000024115166123241025014 0ustar hasanhasan[Shell Search Provider] DesktopId=io.github.kolunmi.Bazaar.desktop BusName=io.github.kolunmi.Bazaar ObjectPath=/io/github/kolunmi/Bazaar/SearchProvider Version=2bazaar-orig-v0.7.14/po/0000775000175000017500000000000015166123241013556 5ustar hasanhasanbazaar-orig-v0.7.14/po/cs.po0000664000175000017500000027010615166123241014531 0ustar hasanhasan# Czech translations for bazaar package. # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # Vlastimil Dědek , 2025. # Pavel Borecki , 2026. # Daniel Rusek , 2026. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-09 11:14+0200\n" "PO-Revision-Date: 2026-04-09 11:28+0200\n" "Last-Translator: Daniel Rusek \n" "Language-Team: Czech\n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" "X-Generator: Poedit 3.9\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:46 #: src/bz-window.c:377 src/bz-window.c:378 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "" "Přidávejte, odstraňujte nebo aktualizujte software z flatpaků na tomto " "počítači" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;Systém;SprávceBalíčků;Discover;Flatpak;Software;Obchod;" #: data/io.github.kolunmi.Bazaar.desktop.in:16 msgid "New Window" msgstr "Nové okno" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and manage applications" msgstr "Objevujte a spravujte aplikace" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A fast and modern app store for Linux with a focus on discovering and " "installing Flatpak apps and addons, particularly from Flathub." msgstr "" "Rychlý a moderní obchod s aplikacemi pro Linux se zaměřením na objevování a " "instalaci aplikací a doplňků Flatpaku, zejména z Flathubu." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:15 msgid "Queue multiple installs and keep browsing" msgstr "Zařaďte více instalací do fronty a pokračujte v prohlížení" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:16 msgid "Easily view app permissions" msgstr "Jednoduše si zobrazte oprávnění aplikací" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:17 msgid "Sign in to Flathub to view and manage your favorites" msgstr "" "Přihlaste se pomocí Flathubu pro zobrazení a správu oblíbených aplikací" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:18 msgid "Search apps directly from GNOME Shell" msgstr "Vyhledávejte aplikace přímo z GNOME Shellu" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:30 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:55 msgid "The home page displaying Flathub apps" msgstr "Domovská stránka zobrazující aplikace Flathubu" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:59 msgid "Exhibit app page" msgstr "Stránka aplikace Exhibit" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:63 msgid "Library page" msgstr "Stránka knihovny" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:67 msgid "Search page" msgstr "Stránka hledání" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:71 msgid "Category page" msgstr "Stránka kategorií" #: src/bz-addon-tile.blp:49 src/bz-installed-tile.blp:64 #: src/bz-rich-app-tile.blp:140 msgid "Stopped Receiving Updates" msgstr "Příjem aktualizací zastaven" #: src/bz-addon-tile.c:148 src/bz-favorites-tile.c:157 #: src/bz-rich-app-tile.blp:172 msgid "Uninstall" msgstr "Odinstalovat" #: src/bz-addon-tile.c:150 src/bz-addons-dialog.blp:262 #: src/bz-favorites-tile.c:159 msgid "Install" msgstr "Instalovat" #: src/bz-addons-dialog.blp:14 src/bz-addons-dialog.blp:21 #: src/bz-full-view.blp:627 src/bz-installed-tile.blp:101 msgid "Manage Add-Ons" msgstr "Spravovat doplňky" #: src/bz-addons-dialog.blp:70 msgid "Add-on Page" msgstr "Stránka doplňků" #: src/bz-addons-dialog.blp:184 src/bz-full-view.blp:426 msgid "Downloads/Month" msgstr "Stažení/měsíc" #: src/bz-addons-dialog.blp:211 src/bz-full-view.blp:461 msgid "Stopped Receiving Core Updates" msgstr "Příjem základních aktualizací zastaven" #: src/bz-addons-dialog.blp:225 msgid "" "This add-on uses a runtime that no longer receives updates or security " "fixes. It may become unsafe to use." msgstr "" "Tento doplněk používá běhové prostředí, které již nedostává aktualizace ani " "opravy zabezpečení. Jeho používání nemusí být bezpečné." #: src/bz-addons-dialog.blp:279 src/bz-rich-app-tile.blp:185 #: src/bz-transaction-tile.blp:272 msgid "Open" msgstr "Otevřít" #: src/bz-addons-dialog.blp:286 src/bz-install-controls.blp:141 #: src/bz-installed-tile.blp:114 msgid "Remove" msgstr "Odebrat" #: src/bz-addons-dialog.c:321 #, c-format msgid "Add-on for %s" msgstr "Doplněk pro %s" #: src/bz-addons-dialog.c:335 src/bz-full-view.c:577 msgid "Show Less" msgstr "Zobrazit méně" #: src/bz-addons-dialog.c:335 src/bz-full-view.c:577 msgid "Show More" msgstr "Zobrazit více" #: src/bz-addons-dialog.c:385 msgid "Download Stats" msgstr "Statistiky stahování" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 #: src/bz-age-rating-dialog.c:736 src/bz-context-tile-callbacks.c:186 #: src/bz-context-tile-callbacks.c:193 msgid "Age Rating" msgstr "Vhodné od věku" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "Kreslené násilí" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "Bez informací o kresleném násilí" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "Násilí ve fantasy" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "Bez informací o násilí ve fantasy" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "Realistické násilí" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "Bez informací o realistickém násilí" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "Násilí zobrazující krvácení" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "Bez informací o krvácení" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "Sexuální násilí" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "Bez informací o sexuálním násilí" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "Alkohol" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "Bez informací o odkazech na alkohol" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "Narkotika" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "Bez informací o odkazech na nezákonné drogy" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "Tabák" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "Bez informací o odkazech na tabákové produkty" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "Nahota" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "Bez informací o nahotě jakéhokoliv typu" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "Sexuální tématika" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "Bez informací o odkazech na nebo vyobrazení sexuální tématiky" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "Vulgarismy" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "Bez informací o vulgaritách jakéhokoliv typu" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "Nepřiměřený humor" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "Bez informací o nepřiměřeném humoru" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "Diskriminace" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "Bez informací o diskriminačních projevech jakéhokoliv typu" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "Reklamy" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "Bez informací o reklamách jakéhokoliv typu" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "Hazard" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "Bez informací o hazardu jakéhokoliv typu" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "Nakupování" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "Bez informací o možnosti utrácet peníze" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "Konverzace mezi uživateli" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "Bez informací o způsobech konverzace mezi uživateli" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "Hlasová konverzace mezi uživateli" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "Bez informací o způsobech hlasové komunikace mezi uživateli" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 msgid "Contact Details" msgstr "Kontaktní údaje" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "" "Bez informací o sdílení uživatelských jmen ze sociálních sítí nebo e-" "mailových adres" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "Identifikační údaje" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "Bez informací o sdílení údajů o uživatelích se třetími stranami" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "Sdílení polohy" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "Bez informací o sdílení fyzické polohy s ostatními uživateli" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "Prostituce" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "Bez informací o odkazech na prostituci" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "Cizoložství" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "Bez informací o odkazech na cizoložství" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "Sexualizované postavy" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "Bez informací o sexualizovaných postavách" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 msgid "Desecration" msgstr "Znesvěcení" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "Bez informací o odkazech na znesvěcení" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "Lidské ostatky" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "Bez informací o viditelných ostatcích mrtvých lidí" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "Otroctví" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "Bez informací o odkazech na otroctví" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "Neobsahuje odkazy na drogy" #: src/bz-age-rating-dialog.c:426 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "Neobsahuje nadávky, vulgarity ani jiné hrubé výrazy" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "Neobsahuje reklamy ani peněžní operace" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "Neobsahuje sex a nahotu" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "Neobsahuje funkci neusměrňované konverzace" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "Neobsahuje násilí" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "Drogy" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "Hrubé výrazy" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "Peníze" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "Sociální sítě" #: src/bz-age-rating-dialog.c:479 msgid "Violence" msgstr "Násilí" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:686 src/bz-context-tile-callbacks.c:176 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:711 msgctxt "Age rating" msgid "All" msgstr "Vše" #: src/bz-age-rating-dialog.c:747 #, c-format msgid "%s has an unknown age rating" msgstr "Aplikace %s má neznámé věkové hodnocení" #: src/bz-age-rating-dialog.c:753 #, c-format msgid "%s is suitable for everyone" msgstr "Aplikace %s je vhodná pro každého" #: src/bz-age-rating-dialog.c:756 #, c-format msgid "%s is suitable for young children" msgstr "Aplikace %s je vhodná pro malé děti" #: src/bz-age-rating-dialog.c:759 #, c-format msgid "%s is suitable for children" msgstr "Aplikace %s je vhodná pro děti" #: src/bz-age-rating-dialog.c:762 #, c-format msgid "%s is suitable for teenagers" msgstr "Aplikace %s je vhodná pro dospívající mládež" #: src/bz-age-rating-dialog.c:765 #, c-format msgid "%s is suitable for adults" msgstr "Aplikace %s je vhodná pro dospělé" #: src/bz-age-rating-dialog.c:768 #, c-format msgid "%s is suitable for %s" msgstr "Aplikace %s je vhodná pro %s" #: src/bz-age-rating-dialog.c:862 #, c-format msgid "%s • %s" msgstr "%s • %s" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:29 #: src/bz-user-data-page.blp:15 src/bz-window.blp:239 msgid "Main Menu" msgstr "Hlavní nabídka" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 #: src/bz-user-data-page.blp:19 src/bz-window.blp:328 msgid "_Donate to Bazaar ❤️" msgstr "Po_dpořit Bazaar ❤️" #: src/bz-all-apps-page.blp:25 src/bz-apps-page.blp:25 #: src/bz-user-data-page.blp:26 src/bz-window.blp:335 msgid "_Refresh" msgstr "_Obnovit" #: src/bz-all-apps-page.blp:30 src/bz-apps-page.blp:30 #: src/bz-user-data-page.blp:31 src/bz-window.blp:340 msgid "_Preferences" msgstr "_Předvolby" #: src/bz-all-apps-page.blp:35 src/bz-apps-page.blp:35 #: src/bz-user-data-page.blp:36 src/bz-window.blp:345 msgid "_Login With Flathub" msgstr "Přih_lásit se pomocí Flathubu" #: src/bz-all-apps-page.blp:41 src/bz-apps-page.blp:41 #: src/bz-user-data-page.blp:42 src/bz-window.blp:351 msgid "_Manage Leftover User Data" msgstr "Sp_ravovat zbylá uživatelská data" #: src/bz-all-apps-page.blp:46 src/bz-apps-page.blp:46 #: src/bz-user-data-page.blp:47 src/bz-window.blp:356 msgid "_Keyboard Shortcuts" msgstr "_Klávesové zkratky" #: src/bz-all-apps-page.blp:51 src/bz-apps-page.blp:51 #: src/bz-user-data-page.blp:52 src/bz-window.blp:361 msgid "_About Bazaar" msgstr "O _aplikaci Bazaar" #: src/bz-all-apps-page.blp:58 src/bz-apps-page.blp:58 #: src/bz-user-data-page.blp:59 src/bz-window.blp:368 msgid "_Quit Bazaar" msgstr "_Ukončit Bazaar" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "Systémová složka %s" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "Podsložka %s v domovské složce" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "Složky hostitelského systému" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "Konfigurace hostitelského systému z /etc" #: src/bz-app-permissions.c:169 #, c-format msgid "Desktop subfolder %s" msgstr "Podsložka %s ve složce plochy" #: src/bz-app-permissions.c:170 msgid "Desktop folder" msgstr "Složka plochy" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "Podsložka %s ve složce dokumentů" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "Složka dokumentů" #: src/bz-app-permissions.c:177 #, c-format msgid "Music subfolder %s" msgstr "Podsložka %s ve složce hudby" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "Složka hudby" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "Podsložka %s ve složce obrázků" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "Složka obrázků" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "Podsložka %s ve složce veřejně sdílených" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "Složka veřejně sdílených" #: src/bz-app-permissions.c:189 #, c-format msgid "Videos subfolder %s" msgstr "Podsložka %s ve složce videí" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "Složka videí" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "Podsložka %s ve složce šablon" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "Složka šablon" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "Podsložka %s ve složce uživatelské mezipaměti" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "Složka uživatelské mezipaměti" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "Podsložka %s ve složce uživatelské konfigurace" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "Složka uživatelské konfigurace" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "Podsložka %s ve složce uživatelských dat" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "Složka uživatelských dat" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "Podsložka %s v uživatelské složce pro běh aplikací" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "Uživatelská složka pro běh aplikací" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "Přístup k souborovému systému v %s" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "Neznámá cesta souborového systému" #: src/bz-app-size-dialog.blp:26 src/bz-app-size-dialog.blp:52 msgid "Download Size" msgstr "Stahovaná velikost" #: src/bz-app-size-dialog.blp:53 msgid "Amount to download from the internet" msgstr "Velikost ke stažení z internetu" #: src/bz-app-size-dialog.blp:73 msgid "Installed Size" msgstr "Instalovaná velikost" #: src/bz-app-size-dialog.blp:74 msgid "Size on Disk" msgstr "Velikost na disku" #: src/bz-app-size-dialog.blp:121 msgid "Open user data folder" msgstr "Otevřít složku uživatelských dat" #: src/bz-app-size-dialog.blp:131 msgid "User Data Size" msgstr "Velikost uživatelských dat" #: src/bz-app-size-dialog.blp:132 msgid "Caches, settings, and other app data" msgstr "Mezipaměti, nastavení a další data aplikací" #: src/bz-app-size-dialog.c:99 msgid "Installed Runtime Size" msgstr "Instalovaná velikost prostředí" #: src/bz-app-size-dialog.c:99 msgid "Runtime Download Size" msgstr "Stahovaná velikost prostředí" #: src/bz-app-size-dialog.c:204 msgid "App Size" msgstr "Velikost aplikace" #: src/bz-app-tile.blp:57 src/bz-developer-badge.c:98 #: src/bz-rich-app-tile.blp:104 src/bz-rich-app-tile.c:304 msgid "Verified" msgstr "Ověřeno" #. Translators: As in 'The app is installed'. #: src/bz-app-tile.blp:88 src/bz-context-tile-callbacks.c:135 #: src/bz-releases-list.c:205 msgid "Installed" msgstr "Nainstalováno" #: src/bz-apps-page.blp:142 msgid "Show All" msgstr "Zobrazit vše" #: src/bz-apps-page.c:229 #, c-format msgid "All \"%s\"" msgstr "Všechny „%s“" #: src/bz-apps-page.c:478 src/bz-tag-list.c:91 #, c-format msgid "%d Applications" msgstr "%d aplikací" #: src/bz-application.c:707 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:708 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #: src/bz-application.c:728 msgid "The Bazaar Contributors" msgstr "Přispěvatelé aplikace Bazaar" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:731 msgid "translator-credits" msgstr "" "Vlastimil Dědek , 2025\n" "Pavel Borecki , 2026\n" "Daniel Rusek , 2026" #: src/bz-application.c:741 msgid "Special Thanks" msgstr "Zvláštní poděkování patří" #: src/bz-application.c:799 msgid "Logged Out Successfully!" msgstr "Úspěšně odhlášeni!" #: src/bz-application.c:922 msgid "Performing setup…" msgstr "Provádí se nastavení…" #: src/bz-application.c:1006 msgid "Set Up System Flathub?" msgstr "Nastavit systémový Flathub?" #: src/bz-application.c:1009 msgid "" "The system Flathub remote is not set up. Bazaar requires Flathub to be " "configured on the system Flatpak installation to browse and install " "applications.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Systémový repozitář Flathub není nastaven. Bazaar vyžaduje, aby byl Flathub " "nastaven na systémové Flatpak instalaci pro procházení a instalaci " "aplikací.\n" "\n" "Bazaar můžete i nadále používat k procházení a odstraňování již " "nainstalovaných aplikací." #: src/bz-application.c:1016 msgid "Set Up Flathub?" msgstr "Nastavit Flathub?" #: src/bz-application.c:1019 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub není v tomto systému nastaven. Pokud není k dispozici, nebudete moci " "procházet a instalovat aplikace v Bazaaru.\n" "\n" "Bazaar můžete i nadále používat k procházení a odstraňování již " "nainstalovaných aplikací." #: src/bz-application.c:1025 msgid "Later" msgstr "Později" #: src/bz-application.c:1026 msgid "Set Up Flathub" msgstr "Nastavit Flathub" #: src/bz-application.c:1315 msgid "A backend error occurred" msgstr "Došlo k chybě backendu" #: src/bz-application.c:1511 src/bz-application.c:3420 src/bz-window.blp:70 msgid "Refreshing…" msgstr "Obnovuje se…" #: src/bz-application.c:1663 src/bz-application.c:3418 #, c-format msgid "Loading %d apps…" msgstr "Načítá se %d aplikací…" #: src/bz-application.c:1666 msgid "Checking for updates…" msgstr "Kontrolují se aktualizace…" #: src/bz-application.c:1729 msgid "Failed to open .flatpakref" msgstr "Nezdařilo se otevřít soubor .flatpakref" #: src/bz-application.c:1785 msgid "An initialization error occurred" msgstr "Došlo k chybě inicializace" #: src/bz-application.c:2183 msgid "Failed to check for updates" msgstr "Nezdařilo se zkontrolovat aktualizace" #: src/bz-application.c:3191 msgid "Could not find app" msgstr "Nezdařilo se najít aplikaci" #: src/bz-application.c:3422 msgid "Writing to cache…" msgstr "Zapisuje se do mezipaměti…" #: src/bz-appstream-parser.c:302 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Stránka na Flathubu" #: src/bz-appstream-parser.c:323 msgctxt "Project URL Type" msgid "Project Website" msgstr "Stránky projektu" #: src/bz-appstream-parser.c:327 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Sledování problémů" #: src/bz-appstream-parser.c:331 msgctxt "Project URL Type" msgid "FAQ" msgstr "Časté otázky" #: src/bz-appstream-parser.c:335 msgctxt "Project URL Type" msgid "Help" msgstr "Nápověda" #: src/bz-appstream-parser.c:339 msgctxt "Project URL Type" msgid "Donate" msgstr "Věnovat dar" #: src/bz-appstream-parser.c:345 msgctxt "Project URL Type" msgid "Translate" msgstr "Překlad" #: src/bz-appstream-parser.c:349 msgctxt "Project URL Type" msgid "Contact" msgstr "Kontakt" #: src/bz-appstream-parser.c:353 msgctxt "Project URL Type" msgid "Source Code" msgstr "Zdrojový kód" #: src/bz-appstream-parser.c:359 msgctxt "Project URL Type" msgid "Contribute" msgstr "Přispět" #: src/bz-context-tile-callbacks.c:68 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-context-tile-callbacks.c:75 #, c-format msgid "%.*fM" msgstr "%.*f mil." #. Translators: K is the suffix for thousands #: src/bz-context-tile-callbacks.c:82 #, c-format msgid "%.*fK" msgstr "%.*f tis." #: src/bz-context-tile-callbacks.c:92 #, c-format msgid "%d downloads in the last month" msgstr "%d stažení za poslední měsíc" #: src/bz-context-tile-callbacks.c:104 src/bz-context-tile-callbacks.c:389 #: src/bz-context-tile-callbacks.c:406 msgid "N/A" msgstr "N/A" #: src/bz-context-tile-callbacks.c:132 #, c-format msgid "+%s runtime" msgstr "+ prostředí %s" #: src/bz-context-tile-callbacks.c:135 msgid "Download" msgstr "Stáhnout" #: src/bz-context-tile-callbacks.c:155 msgid "Size information unavailable" msgstr "Informace o velikosti nejsou k dispozici" #: src/bz-context-tile-callbacks.c:158 #, c-format msgid "Download size of %s" msgstr "Stahovaná velikost %s" #: src/bz-context-tile-callbacks.c:191 msgid "All Ages" msgstr "Libovolný věk" #: src/bz-context-tile-callbacks.c:203 msgid "Age rating information unavailable" msgstr "Hodnocení věku není k dispozici" #: src/bz-context-tile-callbacks.c:208 msgid "Suitable for all ages" msgstr "Vhodné pro všechny věkové skupiny" #: src/bz-context-tile-callbacks.c:210 #, c-format msgid "Suitable for ages %d and up" msgstr "Vhodné pro věk %d a více" #: src/bz-context-tile-callbacks.c:243 src/bz-context-tile-callbacks.c:248 #: src/bz-context-tile-callbacks.c:276 src/bz-context-tile-callbacks.c:284 msgid "Unknown" msgstr "Neznámé" #: src/bz-context-tile-callbacks.c:253 #, c-format msgid "Free software licensed under %s" msgstr "Svobodný software licencovaný pod %s" #: src/bz-context-tile-callbacks.c:258 msgid "Free software" msgstr "Svobodný software" #: src/bz-context-tile-callbacks.c:261 msgid "Proprietary Software" msgstr "Uzavřený software" #: src/bz-context-tile-callbacks.c:264 #, c-format msgid "Special License: %s" msgstr "Zvláštní licence: %s" #: src/bz-context-tile-callbacks.c:281 msgid "Free" msgstr "Svobodné" #: src/bz-context-tile-callbacks.c:287 src/bz-license-dialog.c:133 msgid "Proprietary" msgstr "Uzavřené" #: src/bz-context-tile-callbacks.c:289 src/bz-license-dialog.c:135 msgid "Special License" msgstr "Zvláštní licence" #: src/bz-context-tile-callbacks.c:309 msgid "Adaptive" msgstr "Adaptivní" #: src/bz-context-tile-callbacks.c:309 msgid "Desktop Only" msgstr "Pouze pro PC" #: src/bz-context-tile-callbacks.c:315 msgid "Works on desktop, tablets, and phones" msgstr "Funguje na PC, tabletech a telefonech" #: src/bz-context-tile-callbacks.c:316 msgid "May not work on mobile devices" msgstr "Možná nefunguje na mobilních zařízeních" #: src/bz-context-tile-callbacks.c:396 src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "Bezpečné" #: src/bz-context-tile-callbacks.c:398 src/bz-context-tile-callbacks.c:400 msgid "Low Risk" msgstr "Nízké riziko" #: src/bz-context-tile-callbacks.c:402 msgid "Medium Risk" msgstr "Střední riziko" #: src/bz-context-tile-callbacks.c:404 msgid "High Risk" msgstr "Vysoké riziko" #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:68 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:62 #: src/bz-library-page.blp:65 src/bz-user-data-page.blp:86 msgid "Empty" msgstr "Prázdné" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "Žádné vybrané aplikace" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "V tomto systému nejsou k dispozici žádné informace o vybraných aplikacích. " "Aplikace si stále můžete prohlížet na Flathubu" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "Procházet Flathub" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "Off-line" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 #: src/bz-search-pill-list.c:67 msgid "Browser" msgstr "Prohlížeč" #: src/bz-developer-badge.c:94 src/bz-developer-badge.c:98 msgid "Not Verified" msgstr "Neověřeno" #: src/bz-developer-badge.c:210 msgid "Developer information not available." msgstr "Informace o vývojáři nejsou k dispozici." #: src/bz-developer-badge.c:216 src/bz-developer-badge.c:230 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "" "Vlastnictví ID aplikace %s nebylo ověřeno a může se jednat o komunitní " "balíček." #: src/bz-developer-badge.c:234 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "Vlastnictví ID aplikace %s bylo ručně ověřeno týmem Flathubu." #: src/bz-developer-badge.c:250 #, c-format msgid "" "The ownership of the %1$s app ID has been verified by %2$s on " "%3$s." msgstr "" "Vlastnictví ID aplikace %1$s bylo ověřeno uživatelem %2$s na %3$s." #: src/bz-developer-badge.c:257 #, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "Vlastnictví ID aplikace %1$s bylo ověřeno pomocí %2$s." #: src/bz-developer-badge.c:261 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "Vlastnictví ID aplikace %s bylo ověřeno." #: src/bz-donations-dialog.blp:74 msgid "Full Release Notes" msgstr "Úplné poznámky k vydání" #: src/bz-donations-dialog.blp:108 msgid "This release was made possible by users like you!" msgstr "Toto vydání bylo možné díky uživatelům, jako jste vy!" #: src/bz-donations-dialog.blp:116 msgid "" "I love making Bazaar, but I cannot do it alone. Help support further " "development by donating on Ko-Fi." msgstr "" "Miluji vytváření Bazaaru, ale nedokážu to sám. Pomozte podpořit další vývoj " "darováním na Ko-Fi." #: src/bz-donations-dialog.blp:131 msgid "Donate to Bazaar" msgstr "Podpořit Bazaar" #. Translators: the %s format specifier will be something along the lines of "0.7.6" etc #: src/bz-donations-dialog.c:227 #, c-format msgid "What's New in %s?" msgstr "Co je nového ve verzi %s?" #. Translators: this is a release date label, like "Released February 9, 2026" #: src/bz-donations-dialog.c:243 msgid "Released %B %-e, %Y" msgstr "Vydáno %-e. %B %Y" #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "Vyberte instalaci" #: src/bz-entry-group-util.c:76 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "" "Máte nainstalováno několik verzí této aplikace. S kterou chcete pokračovat?" #: src/bz-entry-group-util.c:80 msgid "Cancel" msgstr "Zrušit" #: src/bz-entry-selection-row.blp:17 msgid "For This User Only" msgstr "Pouze pro tohoto uživatele" #: src/bz-entry-selection-row.c:112 msgid "this user" msgstr "tento uživatel" #: src/bz-entry-selection-row.c:112 msgid "all users" msgstr "všichni uživatelé" #: src/bz-error.c:69 src/bz-error.c:88 src/bz-error-dialog.blp:36 #: src/bz-safety-dialog.blp:50 msgid "Details" msgstr "Podrobnosti" #: src/bz-error-dialog.blp:47 msgid "Copy" msgstr "Kopírovat" #: src/bz-error-dialog.c:56 src/bz-share-list.c:62 msgid "Copied!" msgstr "Zkopírováno!" #: src/bz-favorite-button.c:388 msgid "Failed to update favorite" msgstr "Aktualizace oblíbených se nezdařila" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "Přihlaste se pomocí Flathubu pro správu oblíbených aplikací" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "Přihlásit se" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "Počet oblíbených" #: src/bz-favorites-tile.c:357 msgid "Failed to remove favorite" msgstr "Odebrání z oblíbených se nezdařilo" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:78 msgid "Support This Application" msgstr "Podpořit tuto aplikaci" #: src/bz-favorites-tile.blp:119 msgid "Remove From Favorites" msgstr "Odebrat z oblíbených" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:78 #: src/bz-window.blp:386 msgid "Favorites" msgstr "Oblíbené" #: src/bz-favorites-page.blp:17 src/bz-section-view.blp:144 msgid "Install All" msgstr "Instalovat vše" #: src/bz-favorites-page.blp:34 src/bz-full-view.blp:45 src/bz-window.blp:255 msgid "Open App Library" msgstr "Otevřít knihovnu aplikací" #: src/bz-favorites-page.blp:56 src/bz-user-data-page.blp:75 msgid "Loading" msgstr "Načítání" #: src/bz-favorites-page.blp:71 msgid "No Favorites" msgstr "Žádné oblíbené aplikace" #: src/bz-favorites-page.blp:72 msgid "Applications you mark as favorite will appear here" msgstr "Aplikace, které označíte jako oblíbené, se zobrazí zde" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "Předchozí" #: src/bz-featured-carousel.blp:54 msgid "Next" msgstr "Další" #: src/bz-featured-tile.blp:90 msgid "App of the Day" msgstr "Aplikace dne" #: src/bz-flathub-category.c:89 msgid "Editing" msgstr "Úprava" #: src/bz-flathub-category.c:90 msgid "Midi" msgstr "Midi" #: src/bz-flathub-category.c:91 msgid "Mixer" msgstr "Mixer" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-flathub-category.c:92 src/bz-search-pill-list.c:77 msgid "Music" msgstr "Hudba" #: src/bz-flathub-category.c:93 msgid "Player" msgstr "Přehrávač" #: src/bz-flathub-category.c:94 msgid "Recorder" msgstr "Záznamník" #: src/bz-flathub-category.c:95 msgid "Sequencer" msgstr "Sekvencer" #: src/bz-flathub-category.c:96 msgid "Tuner" msgstr "Tuner" #: src/bz-flathub-category.c:97 msgid "TV" msgstr "TV" #: src/bz-flathub-category.c:102 msgid "Emulation" msgstr "Emulace" #: src/bz-flathub-category.c:103 msgid "Action" msgstr "Akční" #: src/bz-flathub-category.c:104 msgid "Adventure" msgstr "Adventury" #: src/bz-flathub-category.c:105 msgid "Arcade" msgstr "Arkádové" #: src/bz-flathub-category.c:106 msgid "Blocks" msgstr "Blokové" #: src/bz-flathub-category.c:107 msgid "Board" msgstr "Deskové" #: src/bz-flathub-category.c:108 msgid "Card" msgstr "Karetní" #: src/bz-flathub-category.c:109 msgid "Kids" msgstr "Dětské" #: src/bz-flathub-category.c:110 msgid "Logic" msgstr "Logické" #: src/bz-flathub-category.c:111 msgid "Role Playing" msgstr "Na hrdiny" #: src/bz-flathub-category.c:112 msgid "Shooter" msgstr "Střílečky" #: src/bz-flathub-category.c:113 msgid "Simulation" msgstr "Simulace" #: src/bz-flathub-category.c:114 msgid "Sports" msgstr "Sporty" #: src/bz-flathub-category.c:115 msgid "Strategy" msgstr "Strategické" #: src/bz-flathub-category.c:120 msgid "Audio & Video" msgstr "Audio a video" #: src/bz-flathub-category.c:120 msgid "Media" msgstr "Multimédia" #: src/bz-flathub-category.c:120 msgid "More Audio & Video" msgstr "Více z Audio a video" #: src/bz-flathub-category.c:121 msgid "Developer Tools" msgstr "Vývojářské nástroje" #: src/bz-flathub-category.c:121 msgid "Develop" msgstr "Vývoj" #: src/bz-flathub-category.c:121 msgid "More Developer Tools" msgstr "Více z Vývojářské nástroje" #: src/bz-flathub-category.c:122 msgid "Education" msgstr "Vzdělávání" #: src/bz-flathub-category.c:122 msgid "Learn" msgstr "Učení" #: src/bz-flathub-category.c:122 msgid "More Education" msgstr "Více z Vzdělávání" #: src/bz-flathub-category.c:123 msgid "Gaming" msgstr "Hraní her" #: src/bz-flathub-category.c:123 msgid "Play" msgstr "Hraní" #: src/bz-flathub-category.c:123 msgid "More Gaming" msgstr "Více z Hraní her" #: src/bz-flathub-category.c:124 msgid "Graphics & Photography" msgstr "Grafika a fotografie" #: src/bz-flathub-category.c:124 msgid "Create" msgstr "Vytváření" #: src/bz-flathub-category.c:124 msgid "More Graphics & Photography" msgstr "Více z Grafika a fotografie" #: src/bz-flathub-category.c:125 msgid "Networking" msgstr "Síť" #: src/bz-flathub-category.c:125 msgid "Internet" msgstr "Internet" #: src/bz-flathub-category.c:125 msgid "More Networking" msgstr "Více z Síť" #: src/bz-flathub-category.c:126 msgid "Productivity" msgstr "Produktivita" #: src/bz-flathub-category.c:126 msgid "Work" msgstr "Práce" #: src/bz-flathub-category.c:126 msgid "More Productivity" msgstr "Více z Produktivita" #: src/bz-flathub-category.c:127 msgid "Science" msgstr "Věda" #: src/bz-flathub-category.c:127 msgid "More Science" msgstr "Více z Věda" #: src/bz-flathub-category.c:128 msgid "System" msgstr "Systém" #: src/bz-flathub-category.c:128 msgid "More System" msgstr "Více z Systém" #: src/bz-flathub-category.c:129 msgid "Utilities" msgstr "Utility" #: src/bz-flathub-category.c:129 msgid "Tools" msgstr "Nástroje" #: src/bz-flathub-category.c:129 msgid "More Utilities" msgstr "Více z Utility" #: src/bz-flathub-category.c:130 src/bz-flathub-page.blp:116 #: src/bz-flathub-page.blp:148 msgid "Trending" msgstr "Trendy" #: src/bz-flathub-category.c:130 msgid "More Trending" msgstr "Více z Trendů" #: src/bz-flathub-category.c:131 src/bz-flathub-page.blp:122 #: src/bz-flathub-page.blp:178 msgid "Popular" msgstr "Populární" #: src/bz-flathub-category.c:131 msgid "More Popular" msgstr "Více z Populárních" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:168 msgid "Recently Added" msgstr "Nedávno přidané" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:128 msgid "New" msgstr "Nové" #: src/bz-flathub-category.c:132 msgid "More New" msgstr "Více z Nových" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:158 msgid "Recently Updated" msgstr "Nedávno aktualizované" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:134 msgid "Updated" msgstr "Aktualizované" #: src/bz-flathub-category.c:133 msgid "More Updated" msgstr "Více z Aktualizovaných" #: src/bz-flathub-category.c:134 msgid "Mobile" msgstr "Mobilní" #: src/bz-flathub-category.c:134 msgid "More Mobile" msgstr "Více z Mobilních" #: src/bz-flathub-category.c:135 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:135 msgid "More Adwaita" msgstr "Více z Adwaita" #: src/bz-flathub-category.c:136 msgid "KDE Apps" msgstr "KDE aplikace" #: src/bz-flathub-category.c:136 msgid "More KDE Apps" msgstr "Více z KDE aplikací" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Flathub nebyl přidán" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "Repozitář Flathubu nebyl nalezen v žádné z vašich instalací Flatpaku" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "Flathub vrátil chybu" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "Znovu zkusit připojení k Flathubu" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Flathub není k dispozici" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" "Nepodařilo se nám připojit k Flathubu. Stále však můžete spravovat a " "vyhledávat aplikace." #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "Hledat aplikace" #: src/bz-flathub-page.blp:255 msgid "On the Go" msgstr "Na cestách" #: src/bz-flathub-page.blp:267 msgid "Apps for your Linux phones and tablets" msgstr "Aplikace pro vaše linuxové telefony a tablety" #: src/bz-flathub-page.blp:278 src/bz-flathub-page.blp:313 msgid "More Mobile Apps" msgstr "Více z Mobilních aplikací" #: src/bz-flathub-page.blp:369 msgid "We​ ♥​ Games" msgstr "Máme ♥​ hry" #: src/bz-flathub-page.blp:382 msgid "Games and apps to run your favorite titles" msgstr "Hry a aplikace pro spuštění vašich oblíbených titulů" #: src/bz-flathub-page.blp:416 msgid "More Games" msgstr "Více z Her" #: src/bz-full-view.blp:66 src/bz-library-page.blp:76 #: src/bz-library-page.blp:80 msgid "No Results" msgstr "Žádné výsledky" #: src/bz-full-view.blp:67 msgid "Try a different search query" msgstr "Zkuste jiný dotaz" #: src/bz-full-view.blp:73 msgid "Content" msgstr "Obsah" #: src/bz-full-view.blp:131 msgid "Installing .flatpak bundles is not yet supported" msgstr "Instalace souborů balíčků .flatpak zatím není podporována" #: src/bz-full-view.blp:257 msgid "_Support" msgstr "_Podpořit" #: src/bz-full-view.blp:475 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "Tato aplikace používá běhové prostředí, které již nedostává aktualizace ani " "opravy zabezpečení. Její používání nemusí být bezpečné." #: src/bz-full-view.blp:562 msgid "Trash Data" msgstr "Vymazat data" #: src/bz-full-view.blp:702 msgid "Tags:" msgstr "Štítky:" #: src/bz-full-view.c:189 msgid "No URL" msgstr "Žádná adresa URL" #: src/bz-full-view.c:207 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Tato aplikace má licenci FLOSS. To znamená, že její zdrojový kód může být " "ověřen pro bezpečnost." #: src/bz-full-view.c:208 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Tato aplikace má proprietární licenci. To znamená, že její zdrojový kód je " "vyvíjen v soukromí a nemůže být ověřen třetí stranou." #: src/bz-full-view.c:215 msgid "More Apps" msgstr "Více aplikací" #: src/bz-full-view.c:216 #, c-format msgid "More Apps by %s" msgstr "Více aplikací od %s" #: src/bz-full-view.c:223 msgid "Other Apps by this Developer" msgstr "Další aplikace od tohoto vývojáře" #: src/bz-full-view.c:225 src/bz-full-view.c:324 #, c-format msgid "Other Apps by %s" msgstr "Další aplikace od %s" #: src/bz-full-view.c:234 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "" "Aplikace %s není nainstalována, ale má stále k dispozici %s dat." #: src/bz-full-view.c:326 msgid "Other Apps" msgstr "Další aplikace" #: src/bz-full-view.c:328 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d aplikace" msgstr[1] "%d aplikace" msgstr[2] "%d aplikací" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 msgid "Hardware Support" msgstr "Podpora hardwaru" #: src/bz-hardware-support-dialog.c:62 msgid "Keyboard support" msgstr "Podpora klávesnice" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "Vyžaduje klávesnice" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "Doporučuje klávesnice" #: src/bz-hardware-support-dialog.c:66 msgid "Supports keyboards" msgstr "Podporuje klávesnice" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "Neznámá podpora klávesnic" #: src/bz-hardware-support-dialog.c:69 msgid "Mouse support" msgstr "Podpora myši" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "Vyžaduje myši nebo ukazovátka" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "Doporučuje myši nebo ukazovátka" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "Podporuje myši nebo ukazovátka" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "Neznámá podpora myší nebo ukazovátek" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "Podpora dotykových obrazovek" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "Vyžaduje dotykové obrazovky" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "Doporučuje dotykové obrazovky" #: src/bz-hardware-support-dialog.c:80 msgid "Supports touchscreens" msgstr "Podporuje dotykové obrazovky" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "Neznámá podpora dotykových obrazovek" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "Podpora pro mobilní zařízení" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "Funguje na mobilních zařízeních" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "Nemusí fungovat dobře na mobilních zařízeních" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "Podpora pro PC" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "Funguje dobře na velkých obrazovkách" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "Aplikace %s funguje nejlépe na konkrétním hardware" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "Aplikace %s funguje na většině zařízení" #: src/bz-install-controls.blp:34 src/bz-transaction-dialog.c:202 msgid "_Install" msgstr "_Instalovat" #: src/bz-install-controls.blp:60 msgid "_Open" msgstr "_Otevřít" #: src/bz-install-controls.blp:75 src/bz-install-controls.blp:131 msgid "Uninstall Application" msgstr "Odinstalovat aplikaci" #: src/bz-install-controls.blp:85 src/bz-transaction-dialog.c:231 msgid "_Remove" msgstr "Odeb_rat" #: src/bz-install-controls.blp:118 src/bz-updates-card.c:161 #: src/bz-updates-card.c:180 msgid "Update" msgstr "Aktualizovat" #: src/bz-library-page.blp:31 msgid "Search installed apps" msgstr "hledat nainstalované aplikace" #: src/bz-library-page.blp:48 msgid "Clear search" msgstr "Vymazat hledání" #: src/bz-library-page.blp:69 msgid "No Apps Found" msgstr "Nenalezeny žádné aplikace" #. Translators: . #: src/bz-library-page.blp:98 src/bz-window.blp:112 msgid "Library" msgstr "Knihovna" #: src/bz-library-page.blp:126 msgid "Pending Updates" msgstr "Čekající aktualizace" #: src/bz-library-page.blp:153 msgid "Downloads" msgstr "Stažení" #: src/bz-library-page.blp:196 msgid "Recently Uninstalled" msgstr "Nedávno odinstalované" #: src/bz-library-page.blp:247 msgid "Clear Finished Tasks" msgstr "Vymazat dokončené úlohy" #: src/bz-library-page.blp:260 msgid "Installed Apps" msgstr "Nainstalované aplikace" #: src/bz-library-page.blp:333 msgid "Sort By" msgstr "Řadit podle" #: src/bz-library-page.blp:347 msgid "Name" msgstr "Název" #: src/bz-library-page.blp:353 msgid "Size" msgstr "Velikost" #: src/bz-library-page.c:180 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "Žádné shody pro výraz „%s“ v seznamu nainstalovaných aplikací" #: src/bz-library-page.c:193 src/bz-updates-card.c:426 #, c-format msgid "%u Available Update" msgid_plural "%u Available Updates" msgstr[0] "%u dostupná aktualizace" msgstr[1] "%u dostupné aktualizace" msgstr[2] "%u dostupných aktualizací" #: src/bz-license-dialog.blp:94 msgid "Get Involved" msgstr "Zapojit se" #: src/bz-license-dialog.blp:111 msgid "Learn More" msgstr "Zjistit více" #: src/bz-license-dialog.c:127 msgid "Unknown License" msgstr "Neznámá licence" #: src/bz-license-dialog.c:130 msgid "Community Built" msgstr "Vybudováno komunitou" #: src/bz-license-dialog.c:203 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Tato aplikace je otevřeně vyvíjena mezinárodní komunitou.\n" "\n" "Můžete se zapojit a pomoci ji ještě vylepšit." #: src/bz-license-dialog.c:206 msgid "The license of this app is not known" msgstr "Licence této aplikace není známa" #: src/bz-license-dialog.c:212 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Tato aplikace je otevřeně vyvíjena mezinárodní komunitou a je uvolněna pod " "licencí %s.\n" "\n" "Můžete se zapojit a pomoci ji ještě vylepšit." #: src/bz-license-dialog.c:220 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Tato aplikace není vyvíjena otevřeně, takže o jejím fungování vědí pouze " "její vývojáři. Může být nezabezpečena způsobem, který je těžké odhalit, a " "může se měnit, aniž byste o tom věděli.\n" "\n" "Můžete nebo nemusíte být schopni do této aplikace přispívat." #: src/bz-license-dialog.c:226 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Tato aplikace je vyvíjena pod zvláštní licencí %s.\n" "\n" "Můžete nebo nemusíte být schopni do této aplikace přispívat." #: src/bz-license-dialog.c:356 src/bz-safety-dialog.blp:53 msgid "License" msgstr "Licence" #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 msgid "Connect to Flathub" msgstr "Připojit se k Flathubu" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "Něco se pokazilo" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "" "Propojte svůj účet Flathub s Bazaarem pro správu svých oblíbených aplikací." #: src/bz-login-page.blp:110 msgid "Finish" msgstr "Dokončit" #: src/bz-login-page.c:664 #, c-format msgid "Hello, %s!" msgstr "Ahoj, %s!" #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Předvolby" #: src/bz-preferences-dialog.blp:25 msgid "Network connection is metered — automatic store data refresh is paused" msgstr "" "Připojení k síti je měřené – automatické obnovení dat obchodu je pozastaveno" #: src/bz-preferences-dialog.blp:26 src/bz-window.blp:282 msgid "Refresh Manually" msgstr "Obnovit ručně" #: src/bz-preferences-dialog.blp:31 msgid "Content Filters" msgstr "Filtry obsahu" #: src/bz-preferences-dialog.blp:34 msgid "Free Software Only" msgstr "Pouze svobodný software" #: src/bz-preferences-dialog.blp:35 msgid "Hide proprietary applications when browsing and searching" msgstr "Skrýt uzavřené aplikace z výsledků vyhledávání" #: src/bz-preferences-dialog.blp:39 msgid "Flathub Results Only" msgstr "Pouze výsledky z Flathubu" #: src/bz-preferences-dialog.blp:40 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "" "Omezit výsledky vyhledávání a procházení pouze na aplikace dostupné na " "Flathubu" #: src/bz-preferences-dialog.blp:44 msgid "Verified Results Only" msgstr "Pouze ověřené výsledky" #: src/bz-preferences-dialog.blp:45 msgid "Hide results that are not verified on Flathub" msgstr "Skrýt výsledky, které nejsou ověřeny na Flathubu" #: src/bz-preferences-dialog.blp:49 msgid "Hide EOL Apps" msgstr "Skrýt zastaralé aplikace" #: src/bz-preferences-dialog.blp:50 msgid "Hide apps which are no longer supported by their developers" msgstr "Skrýt aplikace, které již nejsou podporované jejich vývojáři" #: src/bz-preferences-dialog.blp:55 src/bz-window.blp:127 msgid "Search" msgstr "Vyhledávání" #: src/bz-preferences-dialog.blp:58 msgid "Delay Search Results" msgstr "Zpozdit výsledky vyhledávání" #: src/bz-preferences-dialog.blp:59 msgid "Improve results performance by debouncing search terms" msgstr "Vylepšit výsledky vyhledávání pomocí odstraňování rušivých dotazů" #: src/bz-preferences-dialog.blp:64 msgid "Progress Bar" msgstr "Ukazatel postupu" #: src/bz-preferences-dialog.blp:65 msgid "Choose a theme for the progress bar!" msgstr "Vyberte téma pro ukazatel postupu!" #: src/bz-preferences-dialog.blp:89 msgid "Vertical Stripes" msgstr "Svislé pruhy" #: src/bz-preferences-dialog.blp:90 msgid "Display flag colors from left to right" msgstr "Zobrazit barvy vlajky zleva doprava" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Barevný odstín" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Barvy hrdosti" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "Barvy lesbické hrdosti" #: src/bz-preferences-dialog.c:35 msgid "Male Homosexual Pride Colors" msgstr "Barvy mužské homosexuální hrdosti" #: src/bz-preferences-dialog.c:36 msgid "Transgender Pride Colors" msgstr "Barvy transgender hrdosti" #: src/bz-preferences-dialog.c:37 msgid "Nonbinary Pride Colors" msgstr "Barvy nebinární hrdosti" #: src/bz-preferences-dialog.c:38 msgid "Bisexual Pride Colors" msgstr "Barvy bisexuální hrdosti" #: src/bz-preferences-dialog.c:39 msgid "Asexual Pride Colors" msgstr "Barvy asexuální hrdosti" #: src/bz-preferences-dialog.c:40 msgid "Pansexual Pride Colors" msgstr "Barvy pansexuální hrdosti" #: src/bz-preferences-dialog.c:41 msgid "Aromantic Pride Colors" msgstr "Barvy aromatické hrdosti" #: src/bz-preferences-dialog.c:42 msgid "Genderfluid Pride Colors" msgstr "Barvy genderfluidní hrdosti" #: src/bz-preferences-dialog.c:43 msgid "Polysexual Pride Colors" msgstr "Barvy polysexuální hrdosti" #: src/bz-preferences-dialog.c:44 msgid "Omnisexual Pride Colors" msgstr "Barvy omnisexuální hrdosti" #: src/bz-preferences-dialog.c:45 msgid "Aroace Pride Colors" msgstr "Barvy aroace hrdosti" #: src/bz-preferences-dialog.c:46 msgid "Agender Pride Colors" msgstr "Barvy agenderové hrdosti" #: src/bz-preferences-dialog.c:47 msgid "Genderqueer Pride Colors" msgstr "Barvy genderqueer hrdosti" #: src/bz-preferences-dialog.c:48 msgid "Intersex Pride Colors" msgstr "Barvy intersexuální hrdosti" #: src/bz-preferences-dialog.c:49 msgid "Demigender Pride Colors" msgstr "Barvy demigenderové hrdosti" #: src/bz-preferences-dialog.c:50 msgid "Biromantic Pride Colors" msgstr "Barvy biromantické hrdosti" #: src/bz-preferences-dialog.c:51 msgid "Disability Pride Colors" msgstr "Barvy hrdosti invalidů" #: src/bz-preferences-dialog.c:52 msgid "Femboy Pride Colors" msgstr "Barvy hrdosti femboyů" #: src/bz-preferences-dialog.c:53 msgid "Neutrois Pride Colors" msgstr "Barvy neutrois hrdosti" #: src/bz-releases-dialog.blp:5 src/bz-updates-card.c:152 msgid "Version History" msgstr "Historie verzí" #: src/bz-releases-list.blp:27 msgid "_Version History" msgstr "Historie _verzí" #. Translators: something happened less than a day ago #: src/bz-releases-list.c:122 msgid "Today" msgstr "dnes" #. Translators: something happened more than a day ago but less than 2 days ago #: src/bz-releases-list.c:125 msgid "Yesterday" msgstr "včera" #. Translators: something happened days ago #: src/bz-releases-list.c:128 #, c-format msgid "%d day ago" msgid_plural "%d days ago" msgstr[0] "před %d dnem" msgstr[1] "před %d dny" msgstr[2] "před %d dny" #. Translators: something happened weeks ago #: src/bz-releases-list.c:131 #, c-format msgid "%d week ago" msgid_plural "%d weeks ago" msgstr[0] "před %d týdnem" msgstr[1] "před %d týdny" msgstr[2] "před %d týdny" #. Translators: something happened months ago #: src/bz-releases-list.c:134 #, c-format msgid "%d month ago" msgid_plural "%d months ago" msgstr[0] "před %d měsícem" msgstr[1] "před %d měsíci" msgstr[2] "před %d měsíci" #. Translators: something happened years ago #: src/bz-releases-list.c:137 #, c-format msgid "%d year ago" msgid_plural "%d years ago" msgstr[0] "před %d rokem" msgstr[1] "před %d roky" msgstr[2] "před %d lety" #. TRANSLATORS: This is the date string with: day number, month name, year. #. i.e. "22 March 2026" #: src/bz-releases-list.c:155 msgid "%e %B %Y" msgstr "%e. %B %Y" #: src/bz-releases-list.c:195 #, c-format msgid "Version %s" msgstr "Verze %s" #: src/bz-releases-list.c:250 msgid "No details for this release" msgstr "Žádné informace o této verzi" #: src/bz-releases-list.c:262 msgid "Get More Information" msgstr "Získat více informací" #: src/bz-rich-app-tile.blp:157 msgid "Get" msgstr "Získat" #: src/bz-safety-calculator.c:82 msgid "Unknown Permissions" msgstr "Neznámá oprávnění" #: src/bz-safety-calculator.c:83 msgid "Permissions are missing for this app." msgstr "Pro tuto aplikaci chybí oprávnění." #: src/bz-safety-calculator.c:96 msgid "No Permissions" msgstr "Žádná oprávnění" #: src/bz-safety-calculator.c:97 msgid "App is fully sandboxed" msgstr "Aplikace je v plně izolovaném prostředí" #: src/bz-safety-calculator.c:103 msgid "Network Access" msgstr "Přístup k síti" #: src/bz-safety-calculator.c:104 msgid "Can access the internet" msgstr "Může přistupovat k internetu" #: src/bz-safety-calculator.c:106 msgid "No Network Access" msgstr "Žádný přístup k síti" #: src/bz-safety-calculator.c:107 msgid "Cannot access the internet" msgstr "Nemůže přistupovat k internetu" #: src/bz-safety-calculator.c:112 msgid "User Device Access" msgstr "Přístup k uživatelským zařízením" #: src/bz-safety-calculator.c:113 msgid "Can access devices such as webcams or gaming controllers" msgstr "Může přistupovat k zařízením jako jsou webkamery nebo herní ovladače" #: src/bz-safety-calculator.c:115 msgid "No User Device Access" msgstr "Žádný přístup k uživatelským zařízením" #: src/bz-safety-calculator.c:116 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "Nemůže přistupovat k zařízením jako jsou webkamery nebo herní ovladače" #: src/bz-safety-calculator.c:121 msgid "Input Device Access" msgstr "Přístup ke vstupním zařízením" #: src/bz-safety-calculator.c:122 msgid "Can access input devices" msgstr "Může přistupovat ke vstupním zařízením" #: src/bz-safety-calculator.c:128 msgid "Microphone Access and Audio Playback" msgstr "Přístup k mikrofonu a přehrávání zvuku" #: src/bz-safety-calculator.c:129 msgid "Can listen using microphones and play audio without asking permission" msgstr "" "Může poslouchat pomocí mikrofonů a přehrávat zvuk bez žádosti o povolení" #: src/bz-safety-calculator.c:135 msgid "System Device Access" msgstr "Přístup k systémovým zařízením" #: src/bz-safety-calculator.c:136 msgid "Can access system devices which require elevated permissions" msgstr "" "Může přistupovat k systémovým zařízením, která vyžadují zvýšená oprávnění" #: src/bz-safety-calculator.c:142 msgid "Screen Contents Access" msgstr "Přístup k obsahu obrazovky" #: src/bz-safety-calculator.c:143 msgid "Can access the contents of the screen or other windows" msgstr "Může přistupovat k obsahu obrazovky nebo jiných oken" #: src/bz-safety-calculator.c:149 msgid "Legacy Windowing System" msgstr "Zastaralý zobrazovací systém" #: src/bz-safety-calculator.c:150 msgid "Always uses a legacy windowing system (X11)" msgstr "Vždy používá starý zobrazovací systém (X11)" #: src/bz-safety-calculator.c:156 msgid "Arbitrary Permissions" msgstr "Libovolná oprávnění" #: src/bz-safety-calculator.c:157 msgid "Can acquire arbitrary permissions" msgstr "Může získat libovolná oprávnění" #: src/bz-safety-calculator.c:163 msgid "User Settings" msgstr "Nastavení uživatele" #: src/bz-safety-calculator.c:164 msgid "Can access and change user settings" msgstr "Může zobrazovat a měnit uživatelská nastavení" #: src/bz-safety-calculator.c:170 msgid "Full File System Read/Write Access" msgstr "Plný přístup k souborovému systému pro čtení/zápis" #: src/bz-safety-calculator.c:171 msgid "Can read and write all data on the file system" msgstr "Může číst a zapisovat všechna data v souborovém systému" #: src/bz-safety-calculator.c:178 msgid "Home Folder Read/Write Access" msgstr "Přístup k domovské složce pro čtení/zápis" #: src/bz-safety-calculator.c:179 msgid "Can read and write all data in your home directory" msgstr "Může číst a zapisovat všechna data ve vaší domovské složce" #: src/bz-safety-calculator.c:186 msgid "Full File System Read Access" msgstr "Plný přístup k souborovému systému pro čtení" #: src/bz-safety-calculator.c:187 msgid "Can read all data on the file system" msgstr "Může číst všechna data v souborovém systému" #: src/bz-safety-calculator.c:195 msgid "Home Folder Read Access" msgstr "Přístup k domovské složce pro čtení" #: src/bz-safety-calculator.c:196 msgid "Can read all data in your home directory" msgstr "Může číst všechna data ve vaší domovské složce" #: src/bz-safety-calculator.c:204 msgid "Download Folder Read/Write Access" msgstr "Přístup ke složce se staženými soubory pro čtení/zápis" #: src/bz-safety-calculator.c:205 msgid "Can read and write all data in your downloads directory" msgstr "Může číst a zapisovat všechna data ve vaší složce se staženými soubory" #: src/bz-safety-calculator.c:215 msgid "Download Folder Read Access" msgstr "Přístup ke složce se staženými soubory pro čtení" #: src/bz-safety-calculator.c:216 msgid "Can read all data in your downloads directory" msgstr "Může číst všechna data ve vaší složce se staženými soubory" #: src/bz-safety-calculator.c:229 msgid "Can read and write all data in the directory" msgstr "Může číst a zapisovat všechna data ve složce" #: src/bz-safety-calculator.c:243 msgid "Can read all data in the directory" msgstr "Může číst všechna data ve složce" #: src/bz-safety-calculator.c:258 msgid "No File System Access" msgstr "Žádný přístup k souborovému systému" #: src/bz-safety-calculator.c:259 msgid "Cannot access the file system at all" msgstr "Vůbec nemůže přistupovat k souborovému systému" #: src/bz-safety-calculator.c:266 msgid "Uses System Services" msgstr "Využívá služby systému" #: src/bz-safety-calculator.c:267 msgid "Can request data from non-portal system services" msgstr "Může si vyžádat data ze služeb systému mimo portál" #: src/bz-safety-calculator.c:273 msgid "Uses Session Services" msgstr "Využívá služby sezení" #: src/bz-safety-calculator.c:274 msgid "Can request data from non-portal session services" msgstr "Může si vyžádat data ze služeb sezení mimo portál" #: src/bz-safety-calculator.c:322 msgid "No Service Access" msgstr "Žádný přístup ke službám" #: src/bz-safety-calculator.c:323 msgid "Cannot access non-portal session or system services at all" msgstr "Nemůže přistupovat ke službám sezení nebo systému mimo portál" #: src/bz-safety-calculator.c:331 msgid "Verified App Developer" msgstr "Ověřený vývojář aplikace" #: src/bz-safety-calculator.c:332 msgid "The developer of this app has been verified to be who they say they are" msgstr "Vývojář této aplikace byl ověřen jako ten, za koho se vydává" #: src/bz-safety-calculator.c:341 msgid "Proprietary Code" msgstr "Uzavřený kód" #: src/bz-safety-calculator.c:342 msgid "" "The source code is not public, so it cannot be independently audited and " "might be unsafe" msgstr "" "Zdrojový kód není veřejný, takže jej nelze nezávisle zkontrolovat a nemusí " "být bezpečný" #: src/bz-safety-calculator.c:352 msgid "Auditable Code" msgstr "Otevřený kód" #: src/bz-safety-calculator.c:353 msgid "" "The source code is public and can be independently audited, which makes the " "app more likely to be safe" msgstr "" "Zdrojový kód je veřejný a může být nezávisle kontrolován, což zvyšuje " "pravděpodobnost, že je aplikace bezpečná" #: src/bz-safety-calculator.c:493 #, c-format msgid "Use the %s System Service" msgstr "Použít službu systému %s" #: src/bz-safety-calculator.c:497 #, c-format msgid "Use the %s Session Service" msgstr "Použít službu sezení %s" #: src/bz-safety-calculator.c:501 #, c-format msgid "Use the %s Service" msgstr "Použít službu %s" #: src/bz-safety-calculator.c:511 msgid "Can see the non-portal service" msgstr "Může vidět službu mimo portál" #: src/bz-safety-calculator.c:513 msgid "Can talk to the non-portal service" msgstr "Může komunikovat se službou mimo portál" #: src/bz-safety-calculator.c:515 msgid "Can own the non-portal service" msgstr "Může vlastnit službu mimo portál" #: src/bz-safety-calculator.c:530 msgid "Global Menu Integration" msgstr "Integrace globální nabídky" #: src/bz-safety-calculator.c:531 msgid "Can display its menus in a global menu bar" msgstr "Může zobrazit své nabídky v globálním panelu nabídek" #: src/bz-safety-calculator.c:536 msgid "KDE Settings Integration" msgstr "Integrace nastavení KDE" #: src/bz-safety-calculator.c:537 msgid "Can detect when KDE desktop settings change" msgstr "Může detekovat změnu nastavení plochy KDE" #: src/bz-safety-calculator.c:542 msgid "KDE Global Settings" msgstr "Globální nastavení KDE" #: src/bz-safety-calculator.c:543 msgid "Can read KDE desktop preferences like fonts and colors" msgstr "Může číst nastavení plochy KDE, jako jsou písma a barvy" #: src/bz-safety-calculator.c:548 msgid "Secret Storage Service" msgstr "Úložiště služby utajení" #: src/bz-safety-calculator.c:549 msgid "Can store and retrieve its own passwords using the system keyring" msgstr "Může ukládat a načítat vlastní hesla pomocí systémové klíčenky" #: src/bz-safety-calculator.c:554 msgid "Desktop Notifications Service" msgstr "Služba upozornění plochy" #: src/bz-safety-calculator.c:555 msgid "Can send desktop notifications" msgstr "Může zasílat upozornění plochy" #: src/bz-safety-calculator.c:561 msgid "System Tray Integration" msgstr "Integrace do oznamovací oblasti systému" #: src/bz-safety-calculator.c:562 msgid "Can display an icon in the system tray" msgstr "Může zobrazit ikonu v systémové oznamovací oblasti" #: src/bz-safety-calculator.c:567 msgid "KDE Connect Integration" msgstr "Integrace KDE Connect" #: src/bz-safety-calculator.c:568 msgid "Can interact with devices paired via KDE Connect" msgstr "Může komunikovat se zařízeními spárovanými přes KDE Connect" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "Bezpečnost" #: src/bz-safety-dialog.blp:63 msgid "App ID" msgstr "ID aplikace" #: src/bz-safety-dialog.blp:73 msgid "SDK" msgstr "SDK" #: src/bz-safety-dialog.blp:104 msgid "" "This app uses an outdated version of the software platform (SDK) and might " "contain bugs or security vulnerabilities which will not be fixed." msgstr "" "Tato aplikace používá zastaralou verzi softwarové platformy (SDK) a může " "obsahovat chyby nebo slabá místa zabezpečení, která nebudou opravena." #: src/bz-safety-dialog.c:227 #, c-format msgid "%s is Safe" msgstr "Aplikace %s je bezpečná" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s has no Unsafe Permissions" msgstr "Aplikace %s nemá žádná nebezpečná oprávnění" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Probably Safe" msgstr "Aplikace %s je pravděpodobně bezpečná" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Possibly Unsafe" msgstr "Aplikace %s pravděpodobně není bezpečná" #: src/bz-safety-dialog.c:247 #, c-format msgid "%s is Unsafe" msgstr "Aplikace %s není bezpečná" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "Snímky obrazovky" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "Předchozí snímek obrazovky" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "Následující snímek obrazovky" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "Kopírovat obrázek" #: src/bz-screenshot-page.blp:150 msgid "Reset View" msgstr "Původní" #: src/bz-screenshot-page.blp:161 msgid "Zoom Out" msgstr "Oddálit" #: src/bz-screenshot-page.blp:171 msgid "Zoom In" msgstr "Přiblížit" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "Prohlížeč snímků obrazovky" #: src/bz-screenshots-carousel.blp:117 msgid "Open Screenshot Viewer" msgstr "Otevřít prohlížeč snímků obrazovky" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:72 msgid "Video" msgstr "Video" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:82 msgid "Office" msgstr "Kancelář" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:87 msgid "PDF" msgstr "PDF" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:92 msgid "Calendar" msgstr "Kalendář" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:97 msgid "Messaging" msgstr "Zasílání zpráv" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:102 msgid "Steam" msgstr "Steam" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:107 msgid "Paint" msgstr "Malování" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:112 msgid "VPN" msgstr "VPN" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:117 msgid "Torrent" msgstr "Torrent" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:122 msgid "Minecraft" msgstr "Minecraft" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:127 msgid "Emulator" msgstr "Emulátor" #: src/bz-search-page.blp:57 msgid "Search Apps, Games, Software" msgstr "hledat aplikace, hry, software" #: src/bz-search-page.blp:79 msgid "Clear Search" msgstr "Vymazat hledání" #: src/bz-search-page.blp:171 msgid "Categories Unavailable" msgstr "Kategorie nejsou k dispozici" #: src/bz-search-page.blp:172 msgid "Search for apps using the search bar above." msgstr "Vyhledejte aplikace pomocí vyhledávacího panelu výše." #: src/bz-search-page.blp:198 msgid "Browse Categories" msgstr "Procházet kategorie" #: src/bz-search-page.blp:340 msgid "No Applications Found" msgstr "Nenalezeny žádné aplikace" #: src/bz-search-page.c:244 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "Žádné výsledky pro „%s“ v Flathubu" #: src/bz-share-list.c:123 msgid "Copy Link" msgstr "Kopírovat odkaz" #: src/bz-share-list.c:134 msgid "Open Link" msgstr "Otevřít odkaz" #: src/bz-stats-dialog.blp:27 msgid "Timeline" msgstr "Časová osa" #: src/bz-stats-dialog.blp:45 msgid "Installs:" msgstr "Počet instalací:" #: src/bz-stats-dialog.blp:54 msgid "World" msgstr "Svět" #: src/bz-stats-dialog.blp:68 msgid "Since 4/15/2024" msgstr "Od 15. 4. 2024" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:125 #, c-format msgid "%.2fM Total Installs" msgstr "%.2f mil. celkových instalací" #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:128 #, c-format msgid "%.2fK Total Installs" msgstr "%.2f tis. celkových instalací" #: src/bz-stats-dialog.c:130 #, c-format msgid "%'d Total Installs" msgstr "%'d celkových instalací" #: src/bz-tag-list.c:78 msgid "No Results Found" msgstr "Nenalezeny žádné výsledky" #: src/bz-tag-list.c:90 #, c-format msgid "Apps Tagged \"%s\"" msgstr "Aplikace se štítkem „%s“" #: src/bz-tag-list.c:103 msgid "Search failed" msgstr "Vyhledávání se nezdařilo" #: src/bz-transaction-dialog.c:155 msgid "Keep User Data" msgstr "Ponechat uživatelská data" #: src/bz-transaction-dialog.c:156 msgid "Allow restoring personal settings & content" msgstr "Povolit obnovení uživatelských nastavení a obsahu" #: src/bz-transaction-dialog.c:165 msgid "Delete All Data" msgstr "Odstranit všechna data" #: src/bz-transaction-dialog.c:166 msgid "Permanently erase user data to save space" msgstr "Trvale odstranit uživatelská data, aby se ušetřilo místo" #: src/bz-transaction-dialog.c:191 #, c-format msgid "Install %s?" msgstr "Nainstalovat %s?" #: src/bz-transaction-dialog.c:196 msgid "" "Select which version to install. May install additional shared components" msgstr "" "Vyberte verzi, kterou chcete nainstalovat. Může dojít k instalaci dalších " "sdílených komponent" #: src/bz-transaction-dialog.c:198 msgid "May install additional shared components" msgstr "Může nainstalovat dodatečné sdílené komponenty" #: src/bz-transaction-dialog.c:201 src/bz-transaction-dialog.c:230 #: src/bz-transaction-dialog.c:275 src/bz-transaction-dialog.c:578 msgid "_Cancel" msgstr "_Zrušit" #: src/bz-transaction-dialog.c:219 #, c-format msgid "Remove %s?" msgstr "Odebrat %s?" #: src/bz-transaction-dialog.c:222 msgid "Select which version to remove." msgstr "Vyberte, kterou verzi chcete odebrat." #: src/bz-transaction-dialog.c:224 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "Po odinstalování nebude možné aplikaci %s používat." #: src/bz-transaction-dialog.c:247 #, c-format msgid "“%s” is High Risk" msgstr "Aplikace „%s“ je vysoce riziková" #: src/bz-transaction-dialog.c:251 msgid "" "This app has full access to your system, including all your files, " "browser history, saved passwords, and more. It also has access to the " "internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Tato aplikace má plný přístup k vašemu systému, včetně všech vašich " "souborů, historie prohlížení, uložených hesel a dalších údajů. Má také " "přístup k internetu, což znamená, že může odesílat vaše data externím " "stranám.\n" "\n" "Protože je aplikace uzavřený software, nelze auditovat, co s těmito " "oprávněními dělá." #: src/bz-transaction-dialog.c:260 msgid "" "This app uses the legacy X11 windowing system, which allows it to record " "all keystrokes, capture screenshots, and monitor other applications. It " "also has access to the internet, meaning it could send your data to outside " "parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Tato aplikace používá starší okenní systém X11, který jí umožňuje " "zaznamenávat všechny stisky kláves, pořizovat snímky obrazovky a " "monitorovat další aplikace. Má také přístup k internetu, což znamená, že " "může odesílat vaše data externím stranám.\n" "\n" "Protože je aplikace uzavřený software, nelze auditovat, co s těmito " "oprávněními dělá." #: src/bz-transaction-dialog.c:276 msgid "_Install Anyway" msgstr "Přesto na_instalovat" #: src/bz-transaction-dialog.c:331 msgid "Failed to load transaction dialog" msgstr "Nezdařilo se načíst dialogové okno transakce" #: src/bz-transaction-dialog.c:549 msgid "All apps are already installed" msgstr "Všechny aplikace jsou již nainstalovány" #: src/bz-transaction-dialog.c:551 msgid "_OK" msgstr "_Budiž" #: src/bz-transaction-dialog.c:567 #, c-format msgid "Install %u App?" msgid_plural "Install %u Apps?" msgstr[0] "Nainstalovat %u aplikaci?" msgstr[1] "Nainstalovat %u aplikace?" msgstr[2] "Nainstalovat %u aplikací?" #: src/bz-transaction-dialog.c:575 msgid "" "The following will be installed. Additional shared components may also be " "installed" msgstr "" "Následující aplikace budou nainstalovány. Mohou být také nainstalovány další " "sdílené komponenty" #: src/bz-transaction-dialog.c:576 #, c-format msgid "%d addons will be installed." msgstr "Bude nainstalováno %d doplňků." #: src/bz-transaction-dialog.c:577 msgid "Additionally, addons will be installed." msgstr "Kromě toho budou nainstalovány doplňky." #: src/bz-transaction-dialog.c:579 msgid "_Install All" msgstr "_Instalovat vše" #: src/bz-transaction-manager.c:766 #, c-format msgid "Finished in %.02f seconds" msgstr "Dokončeno v %.02f sekundách" #: src/bz-transaction-tile.blp:129 msgid "App Add-On" msgstr "Doplněk aplikace" #: src/bz-transaction-tile.blp:158 msgid "Runtime" msgstr "Prostředí" #: src/bz-transaction-tile.blp:182 msgid "In Queue" msgstr "Ve frontě" #: src/bz-transaction-tile.blp:206 msgid "Done" msgstr "Hotovo" #: src/bz-transaction-tile.blp:230 msgid "Error" msgstr "Chyba" #: src/bz-transaction-tile.blp:286 msgid "Cancel Transaction" msgstr "Zrušit transakci" #: src/bz-transaction-tile.blp:410 msgid "Show Error Info" msgstr "Zobrazit informace o chybě" #: src/bz-transaction-tile.c:107 #, c-format msgid "%s Freed" msgstr "%s uvolněno" #: src/bz-transaction-tile.c:362 src/bz-transaction-tile.c:365 msgid "Transaction Error" msgstr "Chyba transakce" #: src/bz-transaction.c:342 msgid "Pending" msgstr "Čeká" #: src/bz-updates-card.blp:22 msgid "_Update All" msgstr "Akt_ualizovat vše" #: src/bz-updates-card.c:208 #, c-format msgid "%u Runtime Update" msgid_plural "%u Runtime Updates" msgstr[0] "%u aktualizace prostředí" msgstr[1] "%u aktualizace prostředí" msgstr[2] "%u aktualizací prostředí" #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "Správa zbylých uživatelských dat" #: src/bz-user-data-page.blp:89 msgid "No User Data Found" msgstr "Nenalezena žádná uživatelská data" #: src/bz-user-data-page.blp:94 msgid "User Data" msgstr "Uživatelská data" #: src/bz-user-data-tile.c:144 #, c-format msgid "Trashed User Data for %s" msgstr "Uživatelská data aplikace %s byla vymazána" #: src/bz-user-data-tile.blp:74 msgid "Trash User Data" msgstr "Vymazat uživatelská data" #: src/bz-window.blp:88 msgid "Curated" msgstr "Vybrané" #: src/bz-window.blp:100 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:220 msgid "Refresh completed!" msgstr "Obnovení dokončeno!" #: src/bz-window.blp:273 msgid "You are running a new version of Bazaar!" msgstr "Používáte novou verzi Bazaaru!" #: src/bz-window.blp:274 msgid "See What's New" msgstr "Podívejte se, co je nového" #: src/bz-window.blp:281 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "" "Máte připojení k síti, ale prohlížíte si verzi Flathubu uloženou v mezipaměti" #: src/bz-window.blp:393 msgid "Log Out" msgstr "Odhlásit se" #. Translators: %s is the title of the current page #: src/bz-window.c:380 #, c-format msgid "Bazaar — %s" msgstr "Bazaar – %s" #: src/bz-window.c:544 src/bz-window.c:561 msgid "Failed to launch application" msgstr "Aplikaci se nezdařilo spustit" #: src/bz-window.c:766 msgid "You can't remove Bazaar from Bazaar!" msgstr "Bazaar nelze odstranit z Bazaaru!" #: src/bz-window.c:1051 src/bz-window.c:1085 msgid "Can't do that right now!" msgstr "Toto teď nelze provést!" #: src/bz-world-map.c:595 msgctxt "As in, \"100 Downloads\"" msgid "Downloads" msgstr "stažení" #: src/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Obecné" #: src/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Page" msgstr "Otevřít stránku vyhledávání" #: src/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Library Page" msgstr "Otevřít stránku knihovny" #: src/shortcuts-dialog.blp:20 msgctxt "shortcut window" msgid "Refresh" msgstr "Obnovit" #: src/shortcuts-dialog.blp:25 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Otevřít předvolby" #: src/shortcuts-dialog.blp:30 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Zobrazit zkratky" #: src/shortcuts-dialog.blp:35 msgctxt "shortcut window" msgid "Close Window" msgstr "Zavřít okno" #: src/shortcuts-dialog.blp:41 msgctxt "shortcut window" msgid "Quit Bazaar" msgstr "Ukončit Bazaar" #~ msgid "Fractal permissions page" #~ msgstr "Stránka oprávnění aplikace Fractal" #~ msgid "Manage Permissions" #~ msgstr "Spravovat oprávnění" #~ msgid "Show Other Options…" #~ msgstr "Zobrazit další možnosti…" #~ msgid "Edit Permissions" #~ msgstr "Upravit oprávnění" #~ msgid "Reset to defaults" #~ msgstr "Vrátit na výchozí" #~ msgid "New Entry" #~ msgstr "Nová položka" #~ msgid "Invalid Format" #~ msgstr "Neplatný formát" #~ msgid "Reset to default" #~ msgstr "Vrátit na výchozí" #~ msgid "Permissions" #~ msgstr "Oprávnění" #~ msgid "" #~ "Modifying permissions may cause apps to break or be less secure. Do not " #~ "make bug reports with them modified!" #~ msgstr "" #~ "Úprava oprávnění může způsobit selhání aplikací nebo snížení jejich " #~ "bezpečnosti. Neohlašujte chyby, pokud jsou oprávnění upravena!" #~ msgid "OK" #~ msgstr "Budiž" #~ msgid "Reset" #~ msgstr "Výchozí" #~ msgid "General" #~ msgstr "Obecné" #~ msgid "Network" #~ msgstr "Síť" #~ msgid "Share the host's network access" #~ msgstr "Sdílení síťového přístupu hostitele" #~ msgid "Audio Server" #~ msgstr "Zvukový server" #~ msgid "" #~ "Play and record sound, enabling this bypasses the individual permissions" #~ msgstr "Přehrávání a nahrávání zvuku, obchází individuální oprávnění" #~ msgid "Bluetooth" #~ msgstr "Bluetooth" #~ msgid "Manage both Bluetooth devices and settings" #~ msgstr "Správa nastavení a zařízení Bluetooth" #~ msgid "Printing" #~ msgstr "Tisk" #~ msgid "Access the system's printing system" #~ msgstr "Přístup k tiskovému systému" #~ msgid "Devices" #~ msgstr "Zařízení" #~ msgid "Smart Cards" #~ msgstr "Čipové karty" #~ msgid "Access smart card readers via PC/SC" #~ msgstr "Přístup ke čtečkám čipových karet přes PC/SC" #~ msgid "All Devices" #~ msgstr "Všechna zařízení" #~ msgid "Access all devices such as webcam, GPU, etc." #~ msgstr "Přístup ke všem zařízením jako jsou webkamera, grafická karta atd." #~ msgid "GPU Acceleration" #~ msgstr "Akcelerace GPU" #~ msgid "Access GPU rendering" #~ msgstr "Přístup k vykreslování na GPU" #~ msgid "USB Devices" #~ msgstr "Zařízení USB" #~ msgid "Manage USB devices directly" #~ msgstr "Přímá správa zařízení USB" #~ msgid "Input Devices" #~ msgstr "Vstupní zařízení" #~ msgid "Access Input devices" #~ msgstr "Přístup ke vstupním zařízením" #~ msgid "KVM Virtualization" #~ msgstr "Virtualizace KVM" #~ msgid "Access KVM for virtual machines" #~ msgstr "Přístup k KVM pro virtuální stroje" #~ msgid "Shared Memory" #~ msgstr "Sdílená paměť" #~ msgid "Create shared memory objects" #~ msgstr "Vytváření objektů sdílené paměti" #~ msgid "Filesystem" #~ msgstr "Souborový systém" #~ msgid "Host Filesystem" #~ msgstr "Souborový systém hostitele" #~ msgid "Full access to the entire filesystem" #~ msgstr "Plný přístup k celému souborovému systému" #~ msgid "Home Folder" #~ msgstr "Domovská složka" #~ msgid "Full access to your home directory" #~ msgstr "Plný přístup k vaší domovské složce" #~ msgid "Access the Downloads folder" #~ msgstr "Přístup ke složce Stažené" #~ msgid "Other Paths" #~ msgstr "Další cesty" #~ msgid "Grant access to additional files and folders" #~ msgstr "Udělit přístup k dalším souborům a složkám" #~ msgid "Advanced System Access" #~ msgstr "Pokročilý přístup k systému" #~ msgid "Inter-process Communication" #~ msgstr "Meziprocesová komunikace" #~ msgid "Share IPC namespace with the host" #~ msgstr "Sdílení jmenného prostoru IPC s hostitelem" #~ msgid "SSH Authentication" #~ msgstr "Ověřování SSH" #~ msgid "Access the SSH authentication agent" #~ msgstr "Přístup k ověřovacímu agentu SSH" #~ msgid "GPG Agent" #~ msgstr "Agent GPG" #~ msgid "" #~ "Access the GPG agent for things like encryption and git commit signing" #~ msgstr "" #~ "Přístup k agentu GPG, například pro šifrování a podepisování commitů gitu" #~ msgid "Session Bus Policy" #~ msgstr "Zásady sběrnice sezení" #~ msgid "Full Access" #~ msgstr "Plný přístup" #~ msgid "Give full access to the D-Bus session bus" #~ msgstr "Umožnit plný přístup ke sběrnici sezení D-Bus" #~ msgid "Talk" #~ msgstr "Komunikace" #~ msgid "Names on the session bus the app is allowed to send messages to" #~ msgstr "Jména na sběrnici sezení, kterým aplikace smí odesílat zprávy" #~ msgid "Own" #~ msgstr "Vlastnění" #~ msgid "Names on the session bus the app is allowed to claim ownership of" #~ msgstr "" #~ "Jména na sběrnici sezení, ke kterým si aplikace smí nárokovat vlastnictví" #~ msgid "System Bus Policy" #~ msgstr "Zásady systémové sběrnice" #~ msgid "Give full access to the D-Bus system bus" #~ msgstr "Umožnit plný přístup k systémové sběrnici D-Bus" #~ msgid "Names on the system bus the app is allowed to send messages to" #~ msgstr "Jména na systémové sběrnici, kterým aplikace smí odesílat zprávy" #~ msgid "Names on the system bus the app is allowed to claim ownership of" #~ msgstr "" #~ "Jména na systémové sběrnici, ke kterým si aplikace smí nárokovat " #~ "vlastnictví" #~ msgid "Developer Options" #~ msgstr "Možnosti pro vývojáře" #~ msgid "Wayland Windowing System" #~ msgstr "Okenní systém Wayland" #~ msgid "Show windows using Wayland" #~ msgstr "Zobrazovat okna pomocí Waylandu" #~ msgid "X11 Windowing System" #~ msgstr "Okenní systém X11" #~ msgid "Show windows using X11" #~ msgstr "Zobrazovat okna pomocí X11" #~ msgid "Fallback X11 Windowing System" #~ msgstr "Záložní okenní systém X11" #~ msgid "Show windows using X11 if Wayland is not available" #~ msgstr "Zobrazovat okna pomocí X11, pokud Wayland není k dispozici" #~ msgid "Development Syscalls" #~ msgstr "Vývojářská systémová volání" #~ msgid "Access development syscalls such as ptrace" #~ msgstr "Přístup k vývojářským systémovým voláním, jako je ptrace" #~ msgid "Multiarch" #~ msgstr "Multiarch" #~ msgid "Run multiarch / multilib binaries" #~ msgstr "Spouštění binárních souborů multiarch / multilib" #~ msgid "CAN Bus" #~ msgstr "Sběrnice CAN" #~ msgid "Access the CAN bus" #~ msgstr "Přístup k sběrnici CAN" #~ msgid "Per-App Shared Memory" #~ msgstr "Sdílená paměť pro jednotlivé aplikace" #~ msgid "Share /dev/shm between app instances & subsandboxes" #~ msgstr "Sdílení /dev/shm mezi instancemi aplikací a subsandboxy" #~ msgid "Variables" #~ msgstr "Proměnné" #~ msgid "Environment variables to set in the application" #~ msgstr "Proměnné prostředí, které se mají nastavit v aplikaci" #~ msgid "Permissions reset!" #~ msgstr "Oprávnění resetována!" #~ msgid "Undo" #~ msgstr "Zpět" #~ msgid "Hide Developer Options" #~ msgstr "Skrýt možnosti pro vývojáře" #~ msgid "Show Developer Options" #~ msgstr "Zobrazit možnosti pro vývojáře" #~ msgid "Background" #~ msgstr "Pozadí" #~ msgid "Notifications" #~ msgstr "Upozornění" #~ msgid "Speakers" #~ msgstr "Reproduktory" #~ msgid "Camera" #~ msgstr "Kamera" #~ msgid "Location" #~ msgstr "Umístění" #~ msgid "Microphone" #~ msgstr "Mikrofon" bazaar-orig-v0.7.14/po/fa_IR.po0000664000175000017500000004115215166123241015101 0ustar hasanhasan# Persian translations for bazaar package. # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # Goudarz Jafari , 2025. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-07-14 09:23+0330\n" "PO-Revision-Date: 2025-07-14 16:34+0330\n" "Last-Translator: Goudarz Jafari \n" "Language-Team: none\n" "Language: fa_IR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.6\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:5 msgid "Bazaar" msgstr "بازار" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "افزودن، حذف یا به‌روزرسانی نرم‌افزارهای Flatpak در این رایانه" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;سیستم;مدیر بسته‌ها;کشف ;کردن;Flatpak;نرم‌افزار;فروشگاه;" #: data/io.github.kolunmi.Bazaar.gschema.xml:6 msgid "Show Animated Background" msgstr "نمایش پس‌زمینه متحرک" #: data/io.github.kolunmi.Bazaar.gschema.xml:7 msgid "Whether to show the animated icon background on the home page" msgstr "آیا پس‌زمینه‌ی نماد متحرک در صفحه‌ی اصلی نمایش داده شود" #. FIXME: add descriptions and summary #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:9 msgid "Keep the summary shorter, between 10 and 35 characters" msgstr "خلاصه را کوتاه نگه دارید، بین ۱۰ تا ۳۵ نویسه" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:11 msgid "No description" msgstr "بدون توضیح" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:41 msgid "Main Bazaar window showing Blender" msgstr "پنجره‌ی اصلی بازار که Blender را نمایش می‌دهد" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:50 msgid "Release description" msgstr "توضیح‌های نگارش" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:52 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:53 msgid "List of changes" msgstr "فهرست تغییرات" #: src/bz-addons-dialog.blp:13 src/bz-installed-page.blp:162 #: src/bz-installed-page.blp:174 msgid "Manage Addons" msgstr "مدیریت افزونه‌ها" #: src/bz-app-tile.blp:65 src/bz-full-view.blp:139 msgid "This flatpak is verified by the original developers of the software." msgstr "این Flatpak توسط توسعه‌دهندگان اصلی نرم‌افزار تایید شده است." #: src/bz-application.c:1194 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:481 msgid "translator-credits" msgstr "Goudarz Jafari" #: src/bz-application.c:1199 msgctxt "About Dialog Translator Credit" msgid "Ahmed Najmawi" msgstr "Ahmed Najmawi" #: src/bz-application.c:1200 msgctxt "About Dialog Translator Credit" msgid "AtomHare" msgstr "AtomHare" #: src/bz-application.c:1201 msgctxt "About Dialog Translator Credit" msgid "Jill Fiore" msgstr "Jill Fiore" #: src/bz-application.c:1202 msgctxt "About Dialog Translator Credit" msgid "Lucosec" msgstr "Lucosec" #: src/bz-application.c:1203 msgctxt "About Dialog Translator Credit" msgid "Shihfu Juan" msgstr "Shihfu Juan" #: src/bz-application.c:1204 msgctxt "About Dialog Translator Credit" msgid "Vlastimil Dědek" msgstr "Vlastimil Dědek" #: src/bz-application.c:1205 msgctxt "About Dialog Translator Credit" msgid "asen23" msgstr "asen23" #: src/bz-application.c:1206 msgctxt "About Dialog Translator Credit" msgid "renner" msgstr "renner" #: src/bz-application.c:1207 msgctxt "About Dialog Translator Credit" msgid "robotta" msgstr "robotta" #: src/bz-application.c:1223 msgid "Adam Masciola" msgstr "Adam Masciola" #: src/bz-browse-widget.blp:11 src/bz-full-view.blp:11 #: src/bz-installed-page.blp:11 src/bz-window.blp:32 msgid "Empty" msgstr "خالی" #: src/bz-browse-widget.blp:15 msgid "No Curated Applications" msgstr "هنوز هیچ برنامه‌ی پیشنهادی‌ای وجود ندارد" #: src/bz-browse-widget.blp:16 msgid "" "Bazaar was not provided a curated content configuration. Contact your " "operating system's support channels for assistance." msgstr "" "هیچ پیکربندی‌ای برای محتوای انتخاب‌شده به بازار ارائه نشده است. برای دریافت " "کمک با پشتیبانی سیستم‌عامل خود تماس بگیرید." #: src/bz-browse-widget.blp:22 src/bz-flathub-page.blp:11 msgid "Browser" msgstr "مرورگر" #: src/bz-error.c:45 msgid "An Error Occurred" msgstr "یک خطا رخ داد" #: src/bz-error.c:51 msgid "Close" msgstr "بستن" #: src/bz-error.c:52 msgid "Copy and Close" msgstr "رونوشت و بستن" #: src/bz-flathub-page.blp:41 msgid "Apps Of The Week" msgstr "برنامه‌های هفته" #: src/bz-flathub-page.blp:85 msgid "Trending" msgstr "محبوب‌ها" #: src/bz-flathub-page.blp:117 msgid "Recently Updated" msgstr "اخیرا به‌روزرسانی‌شده" #: src/bz-flathub-page.blp:149 msgid "Recently Added" msgstr "اخیرا افزوده‌شده" #: src/bz-flathub-page.blp:181 msgid "Popular" msgstr "پرطرفدار" #: src/bz-full-view.blp:15 msgid "No Results" msgstr "نتیجه‌ای یافت نشد" #: src/bz-full-view.blp:16 msgid "Try a different search query" msgstr "از یک عبارت دیگر برای جستجو استفاده کنید" #: src/bz-full-view.blp:22 src/bz-window.blp:42 msgid "Content" msgstr "محتوا" #: src/bz-full-view.blp:180 msgid "Run this application" msgstr "اجرای این برنامه" #: src/bz-full-view.blp:204 msgid "Download and install this application" msgstr "بارگیری و نصب این برنامه" #: src/bz-full-view.blp:222 src/bz-window.c:987 msgid "Install" msgstr "نصب" #: src/bz-full-view.blp:236 msgid "Uninstall this application" msgstr "این برنامه را حذف کن" #: src/bz-full-view.blp:262 msgid "Share this application" msgstr "هم‌رسانی این برنامه" #: src/bz-full-view.blp:274 msgid "" "The number of downloads in the last 30 days. Click to view this " "application's download statistics." msgstr "" "تعداد بارگیری در ۳۰ روز گذشته. برای مشاهده‌ی آمار بارگیری این برنامه کلیک " "کنید." #: src/bz-full-view.blp:316 msgid "Support this developer" msgstr "حمایت از این توسعه‌دهنده" #: src/bz-full-view.blp:329 msgid "Support" msgstr "پشتیبانی" #: src/bz-full-view.blp:387 msgid "Remote repo name" msgstr "نام مخزن راه‌دور" #: src/bz-full-view.blp:400 msgid "Project URL" msgstr "نشانی اینترنتی پروژه" #: src/bz-full-view.blp:412 msgid "Download size" msgstr "اندازه‌ی بارگیری" #: src/bz-full-view.c:214 #, c-format msgid "Released %x" msgstr "منتشر شده در %x" #: src/bz-full-view.c:225 msgid "No URL" msgstr "بدون نشانی اینترنتی" #: src/bz-full-view.c:233 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "این برنامه دارای مجوز FLOSS است، به این معنا که کد منبع آن برای ایمنی قابل " "بررسی است." #: src/bz-full-view.c:234 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "این برنامه دارای مجوز مالکیتی است، به این معنا که کد منبع آن به‌صورت خصوصی " "توسعه یافته و توسط طرف ثالث مستقل قابل بررسی نیست." #: src/bz-installed-page.blp:15 msgid "No Flatpaks Installed" msgstr "هیچ Flatpakی نصب نشده است" #: src/bz-installed-page.blp:21 src/bz-window.blp:201 src/bz-window.blp:336 msgid "Installed" msgstr "نصب شده" #: src/bz-installed-page.blp:143 msgid "More actions" msgstr "اقدام‌های بیشتر" #: src/bz-installed-page.blp:187 src/bz-installed-page.blp:198 msgid "Edit Permissions" msgstr "ویرایش مجوزها" #: src/bz-preferences-dialog.blp:9 msgid "Preferences" msgstr "تنظیمات" #: src/bz-preferences-dialog.blp:13 msgid "How the application looks" msgstr "ظاهر برنامه" #: src/bz-preferences-dialog.blp:14 msgid "Appearance" msgstr "ظاهر" #: src/bz-preferences-dialog.blp:17 msgid "Show animated background" msgstr "نمایش پس‌زمینه متحرک" #: src/bz-search-widget.blp:69 msgid "Type to filter" msgstr "برای فیلتر کردن تایپ کنید" #: src/bz-search-widget.blp:98 src/bz-search-widget.blp:115 msgid "Search Options" msgstr "گزینه‌های جستجو" #: src/bz-search-widget.blp:119 msgid "Exclude results with proprietary licenses" msgstr "حذف نتایج دارای مجوز مالکیتی" #: src/bz-search-widget.blp:124 msgid "Exclude results not originating from Flathub" msgstr "حذف نتایجی که از Flathub منشا نگرفته‌اند" #: src/bz-search-widget.blp:139 msgid "Advanced" msgstr "پیشرفته" #: src/bz-search-widget.blp:143 msgid "Match using regular expressions" msgstr "همسان‌سازی با استفاده از عبارات باقاعده" #: src/bz-search-widget.blp:148 msgid "Hide filtering and sorting behind a crossfade effect" msgstr "پنهان‌سازی فیلتر و مرتب‌سازی با افکت محوشونده" #: src/bz-search-widget.blp:153 msgid "Debounce input to prevent instant replies" msgstr "مکث ورودی برای جلوگیری از پاسخ فوری" #: src/bz-share-dialog.blp:13 msgid "Share" msgstr "هم‌رسانی" #: src/bz-share-dialog.blp:64 msgid "Copy this link" msgstr "رونوشت این پیوند" #: src/bz-share-dialog.blp:71 msgid "Open this link externally" msgstr "این پیوند را در بیرون از این برنامه باز کنید" #: src/bz-stats-dialog.blp:15 msgid "Downloads Over Time" msgstr "بارگیری‌ها در طول زمان" #: src/bz-stats-dialog.blp:31 msgid "Minimize Lower Bound" msgstr "کاهش حد پایین" #: src/bz-stats-dialog.blp:36 msgid "Maximize Upper Bound" msgstr "افزایش حد بالا" #: src/bz-transaction-manager.c:451 #, c-format msgid "Finished in %.02f seconds" msgstr "اتمام در %.02f ثانیه" #: src/bz-transaction-view.blp:34 msgid "Installing" msgstr "در حال نصب" #: src/bz-transaction-view.blp:63 msgid "Updating" msgstr "در حال به‌روزرسانی" #: src/bz-transaction-view.blp:92 msgid "Removing" msgstr "در حال حذف" #: src/bz-transaction.c:268 msgid "Pending" msgstr "در انتظار" #: src/bz-update-dialog.blp:6 msgid "Later" msgstr "بعداً" #: src/bz-update-dialog.blp:7 msgid "Install Now" msgstr "اکنون نصب شود" #: src/bz-update-dialog.blp:10 msgid "Updates Are Available" msgstr "به‌روزرسانی‌ها در دسترس‌اند" #: src/bz-update-dialog.blp:11 msgid "" "The following applications are eligible for updates. Would you like to " "install them?" msgstr "برنامه‌های زیر واجد شرایط به‌روزرسانی هستند. آیا مایل به نصب آن‌ها هستید؟" #: src/bz-update-dialog.c:135 #, c-format msgid "" "%d runtimes and/or addons are eligible for updates. Would you like to " "install them?" msgstr "" "%d محیط اجرایی و/یا افزونه برای به‌روزرسانی واجد شرایط هستند. آیا مایل به نصب " "آن‌ها هستید؟" #: src/bz-update-dialog.c:143 #, c-format msgid "Additionally, %d runtimes and/or addons will be updated." msgstr "علاوه بر این، %d محیط اجرایی و/یا افزونه به‌روزرسانی خواهند شد." #: src/bz-window.blp:36 msgid "Transactions Will Appear Here" msgstr "تراکنش‌ها اینجا ظاهر خواهند شد" #: src/bz-window.blp:97 msgid "Halt the execution of transactions" msgstr "توقف اجرای تراکنش‌ها" #: src/bz-window.blp:105 msgid "Clear all finished transactions" msgstr "پاک‌سازی همه‌ی تراکنش‌های پایان‌یافته" #: src/bz-window.blp:136 src/bz-window.blp:140 msgid "Offline" msgstr "آفلاین" #: src/bz-window.blp:146 msgid "Loading" msgstr "در حال بارگذاری" #: src/bz-window.blp:170 msgid "Browse" msgstr "مرور" #: src/bz-window.blp:180 msgid "App View" msgstr "نمایش برنامه" #: src/bz-window.blp:191 src/bz-window.blp:315 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:220 msgid "Go Back" msgstr "بازگشت" #: src/bz-window.blp:228 msgid "Refresh" msgstr "تازه‌سازی" #: src/bz-window.blp:237 msgid "Search" msgstr "جست‌وجو" #: src/bz-window.blp:249 msgid "Update" msgstr "به‌روزرسانی" #: src/bz-window.blp:263 msgid "Checking for updates" msgstr "در حال بررسی برای به‌روزرسانی‌ها" #: src/bz-window.blp:279 msgid "View curated applications" msgstr "مشاهده‌ی برنامه‌های منتخب" #: src/bz-window.blp:294 msgid "Curated" msgstr "منتخب" #: src/bz-window.blp:300 msgid "View the latest on Flathub" msgstr "مشاهده‌ی آخرین‌ها در Flathub" #: src/bz-window.blp:321 msgid "View installed applications" msgstr "مشاهده‌ی برنامه‌های نصب‌شده" #: src/bz-window.blp:350 msgid "Main Menu" msgstr "منوی اصلی" #: src/bz-window.blp:361 msgid "Toggle transaction sidebar" msgstr "نمایش یا پنهان کردن نوار جانبی تراکنش‌ها" #: src/bz-window.blp:400 msgid "Up to date!" msgstr "به‌روز است!" #: src/bz-window.blp:425 msgid "_Keyboard Shortcuts" msgstr "_میان‌برهای صفحه‌کلید" #: src/bz-window.blp:430 msgid "_About Bazaar" msgstr "_درباره‌ی بازار" #: src/bz-window.blp:435 msgid "_Donate to Bazaar ❤️" msgstr "_به بازار اهدا کنید ❤️" #: src/bz-window.c:856 msgid "" "The ability to inspect and install local .flatpak bundle files is coming " "soon! In the meantime, try running\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "on the command line." msgstr "" "قابلیت بررسی و نصب پرونده‌های محلی .flatpak به‌زودی ارائه خواهد شد! در این " "فاصله، دستور\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" " را در خط فرمان امتحان کنید." #: src/bz-window.c:927 msgid "Can't do that right now!" msgstr "فعلا امکان انجام این کار وجود ندارد!" #: src/bz-window.c:940 msgid "Confirm Action" msgstr "تایید عملیات" #: src/bz-window.c:958 #, c-format msgid "" "You are about to remove the following Flatpak:\n" "\n" "%s\n" "%s\n" "\n" "Are you sure?" msgstr "" "شما در حال حذف Flatpak زیر هستید:\n" "\n" "%s\n" "%s\n" "\n" "آیا مطمئن هستید؟" #: src/bz-window.c:966 src/bz-window.c:986 msgid "Cancel" msgstr "لغو" #: src/bz-window.c:967 msgid "Remove" msgstr "حذف" #: src/bz-window.c:978 #, c-format msgid "" "You are about to install the following Flatpak:\n" "\n" "%s\n" "%s\n" "\n" "Are you sure?" msgstr "" "شما در حال نصب Flatpak زیر هستید:\n" "\n" "%s\n" "%s\n" "\n" "آیا مطمئن هستید؟" #: src/bz-window.c:1012 msgid "More details" msgstr "جزئیات بیشتر" #: src/bz-window.c:1138 msgid "Resume the execution of transactions" msgstr "ادامه دادن اجرای تراکنش‌ها" #: src/bz-window.c:1144 msgid "Pause the execution of transactions" msgstr "توقف اجرای تراکنش‌ها" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "عمومی" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "باز کردن پنجره جست‌وجو" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Refresh" msgstr "تازه‌سازی" #: src/gtk/help-overlay.blp:24 msgctxt "shortcut window" msgid "Toggle Transaction Manager" msgstr "نمایش یا پنهان کردن مدیر تراکنش" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "نمایش میان‌برها" #: src/gtk/help-overlay.blp:34 msgctxt "shortcut window" msgid "Quit" msgstr "خروج" bazaar-orig-v0.7.14/po/meson.build0000664000175000017500000000004715166123241015721 0ustar hasanhasani18n.gettext('bazaar', preset: 'glib') bazaar-orig-v0.7.14/po/fr.po0000664000175000017500000025371315166123241014540 0ustar hasanhasan# French translations for Bazaar. # Copyright (C) 2025-2026 The Bazaar Contributors # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # Atom <29772841+AtomHare@users.noreply.github.com>, 2025. # Léane GRASSER , 2025. # Irénée THIRION , 2026. # Mimolet , 2025-2026. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-08 09:52+0200\n" "PO-Revision-Date: 2026-04-08 18:12+0200\n" "Last-Translator: Mimolet \n" "Language-Team: French\n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Gtranslator 50.0\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:46 #: src/bz-window.c:377 src/bz-window.c:378 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "Ajoutez, désinstallez ou mettez à jour vos applications flatpak" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "" "GTK;System;Système;PackageManager;Gestionnaire de " "paquets;Discover;Découvrir;Flatpak;Software;Applis;Logiciel;Store;Magasin;Logithèque;" #: data/io.github.kolunmi.Bazaar.desktop.in:16 msgid "New Window" msgstr "Nouvelle fenêtre" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and manage applications" msgstr "Découvrez et gérez des applications" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A fast and modern app store for Linux with a focus on discovering and " "installing Flatpak apps and addons, particularly from Flathub." msgstr "" "Une logithèque rapide et moderne pour Linux, spécialement conçue pour " "découvrir et installer des applications et des extensions Flatpak, notamment " "celles disponibles sur Flathub." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:15 msgid "Queue multiple installs and keep browsing" msgstr "Gérez plusieurs installations en même temps tout en naviguant" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:16 msgid "Easily view app permissions" msgstr "Consultez facilement les autorisations des applications" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:17 msgid "Sign in to Flathub to view and manage your favorites" msgstr "Connectez-vous à Flathub pour consulter et gérer vos favoris" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:18 msgid "Search apps directly from GNOME Shell" msgstr "Recherchez des applications directement depuis le Shell GNOME" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:30 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:55 msgid "The home page displaying Flathub apps" msgstr "Page d’accueil affichant les applis de Flathub" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:59 msgid "Exhibit app page" msgstr "Page de l’appli Exhibit" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:63 msgid "Library page" msgstr "Page Bibliothèque" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:67 msgid "Search page" msgstr "Page Recherche" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:71 msgid "Category page" msgstr "Page Catégorie" #: src/bz-addons-dialog.blp:16 src/bz-full-view.blp:627 #: src/bz-installed-tile.blp:101 msgid "Manage Add-Ons" msgstr "Gérer les extensions" #: src/bz-addons-dialog.c:94 src/bz-install-controls.blp:141 #: src/bz-installed-tile.blp:114 msgid "Remove" msgstr "Désinstaller" #: src/bz-addons-dialog.c:99 src/bz-favorites-tile.c:159 msgid "Install" msgstr "Installer" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 #: src/bz-age-rating-dialog.c:736 src/bz-full-view.c:333 src/bz-full-view.c:340 msgid "Age Rating" msgstr "Limite d’âge" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "Violence animée" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "Aucune information concernant de la violence animée" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "Violence fictive" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "Aucune information concernant des scènes de violence fictive" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "Violence réaliste" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "Aucune information concernant des scènes de violence réaliste" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "Violence sanglante" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "Aucune information concernant des scènes de violence sanglante" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "Violence sexuelle" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "Aucune information concernant des scènes de violence sexuelle" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "Alcool" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "Aucune information concernant des références à l’alcool" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "Stupéfiants" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "Aucune information concernant des références aux drogues illicites" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "Tabac" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "Aucune information concernant des références aux produits du tabac" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "Nudité" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "Aucune information concernant des formes de nudité" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "Thèmes sexuels" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "" "Aucune information concernant des références ou scènes à caractère sexuel" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "Vulgarité" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "Aucune information concernant des formes de vulgarité" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "Humour inapproprié" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "Aucune information concernant de l’humour inapproprié" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "Discrimination" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "Aucune information concernant un langage à caractère discriminatoire" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "Publicité" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "Aucune information concernant des formes de publicité" # Fait parti du système d'estimation d'âge et n'est pas une catégorie # (d'où l'utilisation du singuler par rapport au pluriel) #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "Jeu d’argent" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "Aucune information concernant les jeux d’argent" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "Achat" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "Aucune information concernant la faculté de dépenser de l’argent" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "Discussions entre utilisateurs" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "" "Aucune information concernant des moyens de discuter avec d’autres " "utilisateurs" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "Discussions vocales entre utilisateurs" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "" "Aucune information concernant les moyens de parler avec d’autres utilisateurs" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 msgid "Contact Details" msgstr "Détails des contacts" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "" "Aucune information concernant le partage de pseudonymes ou d’adresses " "courriel" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "Données d’identification" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "" "Aucune information concernant le partage d’information utilisateur avec des " "tiers" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "Partage de position" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "" "Aucune information concernant la possibilité de partager sa position avec " "d’autres utilisateurs" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "Prostitution" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "Aucune information concernant des références à la prostitution" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "Adultère" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "Aucune information concernant des références à l’adultère" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "Personnage sexualisés" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "Aucune information concernant des personnages sexualisés" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 msgid "Desecration" msgstr "Profanation" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "Aucune information concernant des formes de profanation" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "Restes humains" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "Aucune information concernant la visibilité de restes humains" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "Esclavage" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "Aucune information concernant des références à l’esclavage" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "N’inclut pas de références aux drogues" #: src/bz-age-rating-dialog.c:426 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "" "Ne comporte pas de jurons, blasphèmes ou d’autres formes de langage grossier" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "N’inclut pas de publicité, ni de transactions monétaires" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "N’inclut pas de sexe, ni de nudité" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "N’inclut pas de fonctionnalités de discussion non modérées" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "N’inclut pas de violence" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "Drogues" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "Langage grossier" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "Monétisation" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "Social" #: src/bz-age-rating-dialog.c:479 msgid "Violence" msgstr "Violence" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:686 src/bz-full-view.c:323 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:711 msgctxt "Age rating" msgid "All" msgstr "Tout" #: src/bz-age-rating-dialog.c:747 #, c-format msgid "%s has an unknown age rating" msgstr "%s a une limite d’âge inconnue" #: src/bz-age-rating-dialog.c:753 #, c-format msgid "%s is suitable for everyone" msgstr "%s convient à tout le monde" #: src/bz-age-rating-dialog.c:756 #, c-format msgid "%s is suitable for young children" msgstr "%s convient aux jeunes enfants" #: src/bz-age-rating-dialog.c:759 #, c-format msgid "%s is suitable for children" msgstr "%s convient aux enfants" #: src/bz-age-rating-dialog.c:762 #, c-format msgid "%s is suitable for teenagers" msgstr "%s convient aux adolescents" #: src/bz-age-rating-dialog.c:765 #, c-format msgid "%s is suitable for adults" msgstr "%s convient aux adultes" #: src/bz-age-rating-dialog.c:768 #, c-format msgid "%s is suitable for %s" msgstr "%s convient aux %s" #: src/bz-age-rating-dialog.c:862 #, c-format msgid "%s • %s" msgstr "%s • %s" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:29 #: src/bz-user-data-page.blp:15 src/bz-window.blp:239 msgid "Main Menu" msgstr "Menu principal" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 #: src/bz-user-data-page.blp:19 src/bz-window.blp:328 msgid "_Donate to Bazaar ❤️" msgstr "_Faire un don à Bazaar ❤️" #: src/bz-all-apps-page.blp:25 src/bz-apps-page.blp:25 #: src/bz-user-data-page.blp:26 src/bz-window.blp:335 msgid "_Refresh" msgstr "_Actualiser" #: src/bz-all-apps-page.blp:30 src/bz-apps-page.blp:30 #: src/bz-user-data-page.blp:31 src/bz-window.blp:340 msgid "_Preferences" msgstr "_Préférences" #: src/bz-all-apps-page.blp:35 src/bz-apps-page.blp:35 #: src/bz-user-data-page.blp:36 src/bz-window.blp:345 msgid "_Login With Flathub" msgstr "Se _connecter avec Flathub" #: src/bz-all-apps-page.blp:41 src/bz-apps-page.blp:41 #: src/bz-user-data-page.blp:42 src/bz-window.blp:351 msgid "_Manage Leftover User Data" msgstr "_Gérer les données utilisateurs orphelines" #: src/bz-all-apps-page.blp:46 src/bz-apps-page.blp:46 #: src/bz-user-data-page.blp:47 src/bz-window.blp:356 msgid "_Keyboard Shortcuts" msgstr "_Raccourcis clavier" #: src/bz-all-apps-page.blp:51 src/bz-apps-page.blp:51 #: src/bz-user-data-page.blp:52 src/bz-window.blp:361 msgid "_About Bazaar" msgstr "À _propos de Bazaar" #: src/bz-all-apps-page.blp:58 src/bz-apps-page.blp:58 #: src/bz-user-data-page.blp:59 src/bz-window.blp:368 msgid "_Quit Bazaar" msgstr "_Quitter Bazaar" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "Accès au répertoire %s (Système)" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "Sous-dossier %s (Dossier Personnel)" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "Dossiers du système hôte" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "Configuration du système hôte à partir de /etc" #: src/bz-app-permissions.c:169 #, c-format msgid "Desktop subfolder %s" msgstr "Sous-dossier %s (Bureau)" #: src/bz-app-permissions.c:170 msgid "Desktop folder" msgstr "Dossier Bureau" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "Sous-dossier %s (Documents)" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "Dossier Documents" #: src/bz-app-permissions.c:177 #, c-format msgid "Music subfolder %s" msgstr "Sous-dossier %s (Musique)" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "Dossier Musique" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "Sous-dossier %s (Images)" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "Dossier Images" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "Sous-dossier %s (Public)" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "Dossier Public" #: src/bz-app-permissions.c:189 #, c-format msgid "Videos subfolder %s" msgstr "Sous-dossier %s (Vidéos)" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "Dossier Vidéos" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "Sous-dossier %s (Modèles)" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "Dossier Modèles" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "Sous-dossier %s (cache utilisateur)" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "Dossier du cache utilisateur" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "Sous-dossier %s (configuration utilisateur)" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "Dossier de configuration utilisateur" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "Sous-dossier %s (données utilisateur)" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "Dossier des données utilisateur" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "Sous-dossier %s (environnement d’exécution utilisateur)" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "Dossier d’envionnement d’exécution utilisateur" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "Accès à %s dans le système de fichiers" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "Chemin d’accès au système de fichiers inconnu" #: src/bz-app-size-dialog.blp:29 src/bz-app-size-dialog.blp:55 msgid "Download Size" msgstr "Taille du téléchargement" #: src/bz-app-size-dialog.blp:56 msgid "Amount to download from the internet" msgstr "Volume à télécharger depuis Internet" #: src/bz-app-size-dialog.blp:76 msgid "Installed Size" msgstr "Taille après installation" #: src/bz-app-size-dialog.blp:77 msgid "Size on Disk" msgstr "Taille sur le disque" #: src/bz-app-size-dialog.blp:125 msgid "Open user data folder" msgstr "Ouvrir le dossier des données utilisateur" #: src/bz-app-size-dialog.blp:135 msgid "User Data Size" msgstr "Taille des données utilisateur" #: src/bz-app-size-dialog.blp:136 msgid "Caches, settings, and other app data" msgstr "Caches, paramètres et autres données" #: src/bz-app-size-dialog.c:99 msgid "Installed Runtime Size" msgstr "Taille de l'environnement d’exécution" #: src/bz-app-size-dialog.c:99 msgid "Runtime Download Size" msgstr "Taille du téléchargement de l'environnement d’exécution" #: src/bz-app-tile.blp:57 src/bz-developer-badge.c:98 #: src/bz-rich-app-tile.blp:104 src/bz-rich-app-tile.c:304 msgid "Verified" msgstr "Verifié" #. Translators: As in 'The app is installed'. #: src/bz-app-tile.blp:88 src/bz-full-view.c:282 src/bz-releases-list.c:205 msgid "Installed" msgstr "Installée" #: src/bz-apps-page.blp:142 msgid "Show All" msgstr "Tout afficher" #: src/bz-apps-page.c:229 #, c-format msgid "All \"%s\"" msgstr "Toutes les applis « %s »" #: src/bz-apps-page.c:478 src/bz-tag-list.c:91 #, c-format msgid "%d Applications" msgstr "%d applications" #: src/bz-application.c:695 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:696 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #: src/bz-application.c:716 msgid "The Bazaar Contributors" msgstr "Les Contributeurs de Bazaar" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:719 msgid "translator-credits" msgstr "" "Atom <29772841+AtomHare@users.noreply.github.com>, 2025\n" "Léane GRASSER , 2025\n" "Mimolet , 2025-2026\n" "Irénée THIRION , 2026" #: src/bz-application.c:729 msgid "Special Thanks" msgstr "Remerciements particuliers à" #: src/bz-application.c:787 msgid "Logged Out Successfully!" msgstr "Déconnexion réussie !" #: src/bz-application.c:910 msgid "Performing setup…" msgstr "Configuration en cours…" #: src/bz-application.c:994 msgid "Set Up System Flathub?" msgstr "Configurer Flathub sur le système ? " #: src/bz-application.c:997 msgid "" "The system Flathub remote is not set up. Bazaar requires Flathub to be " "configured on the system Flatpak installation to browse and install " "applications.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Le dépôt d'applications Flathub n’a pas été configuré sur ce système. Bazaar " "a besoin que Flathub soit configuré pour parcourir et installer des " "applications.\n" "\n" "Vous pouvez toujours utiliser Bazaar pour parcourir et désinstaller des " "applis déjà installées." #: src/bz-application.c:1004 msgid "Set Up Flathub?" msgstr "Configurer Flathub ?" #: src/bz-application.c:1007 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub n’a pas été configuré sur ce système. Vous ne pourrez pas parcourir " "et installer des applications dans Bazaar s’il est indisponible.\n" "\n" "Vous pouvez toujours utiliser Bazaar pour parcourir et désinstaller des " "applis déjà installées." #: src/bz-application.c:1013 msgid "Later" msgstr "Plus tard" #: src/bz-application.c:1014 msgid "Set Up Flathub" msgstr "Configurer Flathub" #: src/bz-application.c:1303 msgid "A backend error occurred" msgstr "Une erreur de backend est survenue" #: src/bz-application.c:1499 src/bz-application.c:3357 src/bz-window.blp:70 msgid "Refreshing…" msgstr "Actualisation…" #: src/bz-application.c:1651 src/bz-application.c:3355 #, c-format msgid "Loading %d apps…" msgstr "Chargement de %d applis…" #: src/bz-application.c:1654 msgid "Checking for updates…" msgstr "Recherche de mises à jour…" #: src/bz-application.c:1717 msgid "Failed to open .flatpakref" msgstr "Échec de l’ouverture du .flatpakref" #: src/bz-application.c:1773 msgid "An initialization error occurred" msgstr "Une erreur d'initialisation s'est produite" #: src/bz-application.c:2123 msgid "Failed to check for updates" msgstr "Échec de la vérification des mises à jour" #: src/bz-application.c:3128 msgid "Could not find app" msgstr "Impossible de trouver l'application" #: src/bz-application.c:3359 msgid "Writing to cache…" msgstr "Écriture dans le cache…" #: src/bz-appstream-parser.c:302 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Page Flathub" #: src/bz-appstream-parser.c:323 msgctxt "Project URL Type" msgid "Project Website" msgstr "Site du projet" #: src/bz-appstream-parser.c:327 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Signaler un problème" #: src/bz-appstream-parser.c:331 msgctxt "Project URL Type" msgid "FAQ" msgstr "FAQ" #: src/bz-appstream-parser.c:335 msgctxt "Project URL Type" msgid "Help" msgstr "Aide" #: src/bz-appstream-parser.c:339 msgctxt "Project URL Type" msgid "Donate" msgstr "Faire un don" #: src/bz-appstream-parser.c:345 msgctxt "Project URL Type" msgid "Translate" msgstr "Traduire" #: src/bz-appstream-parser.c:349 msgctxt "Project URL Type" msgid "Contact" msgstr "Contact" #: src/bz-appstream-parser.c:353 msgctxt "Project URL Type" msgid "Source Code" msgstr "Code Source" #: src/bz-appstream-parser.c:359 msgctxt "Project URL Type" msgid "Contribute" msgstr "Contribuer" #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:68 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:62 #: src/bz-library-page.blp:65 src/bz-user-data-page.blp:86 msgid "Empty" msgstr "Vide" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "Aucune sélection" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "Votre système ne recommande pas d’applications en particulier, mais vous " "pouvez toujours en chercher sur Flathub" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "Parcourir Flathub" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "Hors-ligne" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 #: src/bz-search-pill-list.c:67 msgid "Browser" msgstr "Navigateur" #: src/bz-developer-badge.c:94 src/bz-developer-badge.c:98 msgid "Not Verified" msgstr "Non-vérifié" #: src/bz-developer-badge.c:210 msgid "Developer information not available." msgstr "Informations sur le développeur non disponibles." #: src/bz-developer-badge.c:216 src/bz-developer-badge.c:230 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "" "La propriété de l’identifiant applicatif %s n’a pas été vérifiée et il " "pourrait s’agir d’un paquet géré par la communauté." #: src/bz-developer-badge.c:234 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "" "La propriété de l’identifiant applicatif %s a été vérifiée manuellement par " "l’équipe de Flathub." #: src/bz-developer-badge.c:250 #, c-format msgid "" "The ownership of the %1$s app ID has been verified by %2$s on " "%3$s." msgstr "" "La propriété de l’identifiant applicatif %1$s a été vérifiée par %2$s " "sur %3$s." #: src/bz-developer-badge.c:257 #, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "" "La propriété de l’identifiant applicatif %1$s a été vérifiée en utilisant " "%2$s." #: src/bz-developer-badge.c:261 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "La propriété de l’identifiant applicatif %s a été vérifiée." #: src/bz-donations-dialog.blp:74 msgid "Full Release Notes" msgstr "Notes de version complètes" #: src/bz-donations-dialog.blp:108 msgid "This release was made possible by users like you!" msgstr "Bazaar existe grâce à vous !" #: src/bz-donations-dialog.blp:116 msgid "" "I love making Bazaar, but I cannot do it alone. Help support further " "development by donating on Ko-Fi." msgstr "" "J'adore travailler sur Bazaar, mais je ne peux pas y arriver seule. Vous " "pouvez m'aider à poursuivre le développement en faisant un don sur Ko-Fi." #: src/bz-donations-dialog.blp:131 msgid "Donate to Bazaar" msgstr "Faire un don à Bazaar" #. Translators: the %s format specifier will be something along the lines of "0.7.6" etc #: src/bz-donations-dialog.c:227 #, c-format msgid "What's New in %s?" msgstr "Quoi de neuf en %s ?" #. Translators: this is a release date label, like "Released February 9, 2026" #: src/bz-donations-dialog.c:243 msgid "Released %B %-e, %Y" msgstr "Publié le %-e %B %Y" #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "Choisissez une installation" #: src/bz-entry-group-util.c:76 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "" "Plusieurs versions de cette application sont installées. Avec quelle version " "souhaitez-vous poursuivre ?" #: src/bz-entry-group-util.c:80 msgid "Cancel" msgstr "Annuler" #: src/bz-entry-selection-row.blp:17 msgid "For This User Only" msgstr "Pour cet utilisateur seulement" #: src/bz-entry-selection-row.c:112 msgid "this user" msgstr "cet utilisateur" #: src/bz-entry-selection-row.c:112 msgid "all users" msgstr "tous les utilisateurs" #: src/bz-error.c:69 src/bz-error.c:88 src/bz-error-dialog.blp:36 #: src/bz-safety-dialog.blp:50 msgid "Details" msgstr "Détails" #: src/bz-error-dialog.blp:47 msgid "Copy" msgstr "Copier" #: src/bz-error-dialog.c:56 src/bz-share-list.c:64 msgid "Copied!" msgstr "Copié !" #: src/bz-favorite-button.c:388 msgid "Failed to update favorite" msgstr "Échec de la mise à jour des favoris" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "Connectez-vous avec Flathub pour gérer vos favoris" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "Se connecter" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "Nombre de favoris" #: src/bz-favorites-tile.c:157 src/bz-rich-app-tile.blp:172 msgid "Uninstall" msgstr "Désinstaller" #: src/bz-favorites-tile.c:357 msgid "Failed to remove favorite" msgstr "Échec de la suppression du favori" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:78 msgid "Support This Application" msgstr "Soutenez cette application" #: src/bz-favorites-tile.blp:119 msgid "Remove From Favorites" msgstr "Retirer des favoris" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:78 #: src/bz-window.blp:386 msgid "Favorites" msgstr "Favoris" #: src/bz-favorites-page.blp:17 src/bz-section-view.blp:144 msgid "Install All" msgstr "Tout installer" #: src/bz-favorites-page.blp:34 src/bz-full-view.blp:45 src/bz-window.blp:255 msgid "Open App Library" msgstr "Ouvrir la bibliothèque" #: src/bz-favorites-page.blp:56 src/bz-user-data-page.blp:75 msgid "Loading" msgstr "Chargement" #: src/bz-favorites-page.blp:71 msgid "No Favorites" msgstr "Pas de favoris" #: src/bz-favorites-page.blp:72 msgid "Applications you mark as favorite will appear here" msgstr "Les applications que vous marquerez comme favorites apparaîtront ici" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "Précédent" #: src/bz-featured-carousel.blp:54 msgid "Next" msgstr "Suivant" #: src/bz-featured-tile.blp:90 msgid "App of the Day" msgstr "Appli du jour" #: src/bz-flathub-category.c:89 msgid "Editing" msgstr "Édition" #: src/bz-flathub-category.c:90 msgid "Midi" msgstr "Midi" #: src/bz-flathub-category.c:91 msgid "Mixer" msgstr "Mixage" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-flathub-category.c:92 src/bz-search-pill-list.c:77 msgid "Music" msgstr "Musique" #: src/bz-flathub-category.c:93 msgid "Player" msgstr "Lecteur" #: src/bz-flathub-category.c:94 msgid "Recorder" msgstr "Enregistreur" #: src/bz-flathub-category.c:95 msgid "Sequencer" msgstr "Séquenceur" #: src/bz-flathub-category.c:96 msgid "Tuner" msgstr "Accordeur" #: src/bz-flathub-category.c:97 msgid "TV" msgstr "TV" #: src/bz-flathub-category.c:102 msgid "Emulation" msgstr "Émulateurs" #: src/bz-flathub-category.c:103 msgid "Action" msgstr "Action" #: src/bz-flathub-category.c:104 msgid "Adventure" msgstr "Aventure" #: src/bz-flathub-category.c:105 msgid "Arcade" msgstr "Arcade" #: src/bz-flathub-category.c:106 msgid "Blocks" msgstr "Blocs" #: src/bz-flathub-category.c:107 msgid "Board" msgstr "Plateau" #: src/bz-flathub-category.c:108 msgid "Card" msgstr "Jeux de cartes" #: src/bz-flathub-category.c:109 msgid "Kids" msgstr "Jeux pour enfants" #: src/bz-flathub-category.c:110 msgid "Logic" msgstr "Logique" #: src/bz-flathub-category.c:111 msgid "Role Playing" msgstr "Jeux de rôle" #: src/bz-flathub-category.c:112 msgid "Shooter" msgstr "Jeux de tir" #: src/bz-flathub-category.c:113 msgid "Simulation" msgstr "Simulation" #: src/bz-flathub-category.c:114 msgid "Sports" msgstr "Sports" #: src/bz-flathub-category.c:115 msgid "Strategy" msgstr "Jeux de stratégie" #: src/bz-flathub-category.c:120 msgid "Audio & Video" msgstr "Audio & Vidéo" #: src/bz-flathub-category.c:120 msgid "Media" msgstr "Média" #: src/bz-flathub-category.c:120 msgid "More Audio & Video" msgstr "Plus d’applis audio & vidéo" #: src/bz-flathub-category.c:121 msgid "Developer Tools" msgstr "Outils de Développement" #: src/bz-flathub-category.c:121 msgid "Develop" msgstr "Développer" #: src/bz-flathub-category.c:121 msgid "More Developer Tools" msgstr "Plus d’outils de développement" #: src/bz-flathub-category.c:122 msgid "Education" msgstr "Éducation" #: src/bz-flathub-category.c:122 msgid "Learn" msgstr "Apprendre" #: src/bz-flathub-category.c:122 msgid "More Education" msgstr "Plus d’applis éducatives" #: src/bz-flathub-category.c:123 msgid "Gaming" msgstr "Jeux vidéos" #: src/bz-flathub-category.c:123 msgid "Play" msgstr "Jouer" #: src/bz-flathub-category.c:123 msgid "More Gaming" msgstr "Plus de jeux" #: src/bz-flathub-category.c:124 msgid "Graphics & Photography" msgstr "Graphisme & Photographie" #: src/bz-flathub-category.c:124 msgid "Create" msgstr "Créer" #: src/bz-flathub-category.c:124 msgid "More Graphics & Photography" msgstr "Plus d’applis de graphisme et photographie" #: src/bz-flathub-category.c:125 msgid "Networking" msgstr "Réseau" #: src/bz-flathub-category.c:125 msgid "Internet" msgstr "Internet" #: src/bz-flathub-category.c:125 msgid "More Networking" msgstr "Plus d’applis réseau" #: src/bz-flathub-category.c:126 msgid "Productivity" msgstr "Productivité" #: src/bz-flathub-category.c:126 msgid "Work" msgstr "Travailler" #: src/bz-flathub-category.c:126 msgid "More Productivity" msgstr "Plus d’applis de productivité" #: src/bz-flathub-category.c:127 msgid "Science" msgstr "Sciences" #: src/bz-flathub-category.c:127 msgid "More Science" msgstr "Plus d’applis scientifiques" #: src/bz-flathub-category.c:128 msgid "System" msgstr "Système" #: src/bz-flathub-category.c:128 msgid "More System" msgstr "Plus d’applis système" #: src/bz-flathub-category.c:129 msgid "Utilities" msgstr "Utilitaires" #: src/bz-flathub-category.c:129 msgid "Tools" msgstr "Outils" #: src/bz-flathub-category.c:129 msgid "More Utilities" msgstr "Plus d’utilitaires" #: src/bz-flathub-category.c:130 src/bz-flathub-page.blp:116 #: src/bz-flathub-page.blp:148 msgid "Trending" msgstr "Tendances" #: src/bz-flathub-category.c:130 msgid "More Trending" msgstr "Plus de tendances" #: src/bz-flathub-category.c:131 src/bz-flathub-page.blp:122 #: src/bz-flathub-page.blp:178 msgid "Popular" msgstr "Populaires" #: src/bz-flathub-category.c:131 msgid "More Popular" msgstr "Plus d’applis populaires" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:168 msgid "Recently Added" msgstr "Ajoutées récemment" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:128 msgid "New" msgstr "Nouveautés" #: src/bz-flathub-category.c:132 msgid "More New" msgstr "Plus de nouveautés" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:158 msgid "Recently Updated" msgstr "Mises à jour récemment" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:134 msgid "Updated" msgstr "Mises à jour" #: src/bz-flathub-category.c:133 msgid "More Updated" msgstr "Plus d’applis mises à jour" #: src/bz-flathub-category.c:134 msgid "Mobile" msgstr "Mobile" #: src/bz-flathub-category.c:134 msgid "More Mobile" msgstr "Plus d’applis mobiles" #: src/bz-flathub-category.c:135 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:135 msgid "More Adwaita" msgstr "Plus d’applis Adwaita" #: src/bz-flathub-category.c:136 msgid "KDE Apps" msgstr "KDE" #: src/bz-flathub-category.c:136 msgid "More KDE Apps" msgstr "Plus d’applis KDE" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Flathub n’a pas été ajouté" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "" "Le dépôt Flathub n’a été trouvé dans aucune de vos installations Flatpak" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "Flathub a renvoyé une erreur" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "Réessayer de se connecter à Flathub" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Flathub est indisponible" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" "Nous n’avons pas pu nous connecter à Flathub. Vous pouvez toujours gérer et " "rechercher des applications." #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "Rechercher des applis" #: src/bz-flathub-page.blp:255 msgid "On the Go" msgstr "Sur tous vos écrans" #: src/bz-flathub-page.blp:267 msgid "Apps for your Linux phones and tablets" msgstr "Applis pour vos téléphones et tablettes Linux" #: src/bz-flathub-page.blp:278 src/bz-flathub-page.blp:313 msgid "More Mobile Apps" msgstr "Plus d’applis mobiles" #: src/bz-flathub-page.blp:369 msgid "We​ ♥​ Games" msgstr "Nous + jeux = ♥" #: src/bz-flathub-page.blp:382 msgid "Games and apps to run your favorite titles" msgstr "Jeux et applis pour lancer vos titres préférés" #: src/bz-flathub-page.blp:416 msgid "More Games" msgstr "Plus de jeux" #: src/bz-full-view.blp:66 src/bz-library-page.blp:76 #: src/bz-library-page.blp:80 msgid "No Results" msgstr "Aucun résultat" #: src/bz-full-view.blp:67 msgid "Try a different search query" msgstr "Essayez une autre recherche" #: src/bz-full-view.blp:73 msgid "Content" msgstr "Contenu" #: src/bz-full-view.blp:131 msgid "Installing .flatpak bundles is not yet supported" msgstr "L’installation de lots .flatpak n’est pas encore prise en charge" #: src/bz-full-view.blp:257 msgid "_Support" msgstr "_Soutenir" #: src/bz-full-view.blp:426 msgid "Downloads/Month" msgstr "Téléchargements par mois" #: src/bz-full-view.blp:461 msgid "Stopped Receiving Core Updates" msgstr "Ne reçoit plus de mises à jour essentielles" #: src/bz-full-view.blp:475 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "L’environnement d’exécution utilisé par cette appli ne reçoit plus de mises " "à jour de sécurité. Son utilisation pourrait devenir risquée." #: src/bz-full-view.blp:562 msgid "Trash Data" msgstr "Supprimer les données" #: src/bz-full-view.blp:702 msgid "Tags:" msgstr "Étiquettes :" #: src/bz-full-view.c:215 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:222 #, c-format msgid "%.*fM" msgstr "%.*f Mio." #. Translators: K is the suffix for thousands #: src/bz-full-view.c:229 #, c-format msgid "%.*fK" msgstr "%.*f mil." #: src/bz-full-view.c:239 #, c-format msgid "%d downloads in the last month" msgstr "%d téléchargements au cours du dernier mois" #: src/bz-full-view.c:251 src/bz-full-view.c:592 src/bz-full-view.c:609 msgid "N/A" msgstr "Inconnu" #: src/bz-full-view.c:279 #, c-format msgid "+%s runtime" msgstr "+%s d'environnement d’exécution" #: src/bz-full-view.c:282 msgid "Download" msgstr "Taille" #: src/bz-full-view.c:302 msgid "Size information unavailable" msgstr "Informations sur la taille non disponibles" #: src/bz-full-view.c:305 #, c-format msgid "Download size of %s" msgstr "Taille du téléchargement de %s" #: src/bz-full-view.c:338 msgid "All Ages" msgstr "Tout public" #: src/bz-full-view.c:350 msgid "Age rating information unavailable" msgstr "Informations sur la limite d’âge non disponibles" #: src/bz-full-view.c:355 msgid "Suitable for all ages" msgstr "Convient à tout public" #: src/bz-full-view.c:357 #, c-format msgid "Suitable for ages %d and up" msgstr "Approprié dès %d ans et plus" #: src/bz-full-view.c:390 src/bz-full-view.c:395 src/bz-full-view.c:423 #: src/bz-full-view.c:431 msgid "Unknown" msgstr "Inconnue" #: src/bz-full-view.c:400 #, c-format msgid "Free software licensed under %s" msgstr "Logiciel libre sous licence %s" #: src/bz-full-view.c:405 msgid "Free software" msgstr "Logiciel libre" #: src/bz-full-view.c:408 msgid "Proprietary Software" msgstr "Logiciel propriétaire" #: src/bz-full-view.c:411 #, c-format msgid "Special License: %s" msgstr "Licence spéciale : %s" #: src/bz-full-view.c:428 msgid "Free" msgstr "Libre" #: src/bz-full-view.c:434 src/bz-license-dialog.c:132 msgid "Proprietary" msgstr "Propriétaire" #: src/bz-full-view.c:436 src/bz-license-dialog.c:134 msgid "Special License" msgstr "Licence spéciale" #: src/bz-full-view.c:456 msgid "Adaptive" msgstr "Adaptatif" #: src/bz-full-view.c:456 msgid "Desktop Only" msgstr "Ordinateur uniquement" #: src/bz-full-view.c:462 msgid "Works on desktop, tablets, and phones" msgstr "Fonctionne sur ordinateur, tablette et téléphone" #: src/bz-full-view.c:463 msgid "May not work on mobile devices" msgstr "Peut ne pas fonctionner sur les appareils mobiles" #: src/bz-full-view.c:474 msgid "No URL" msgstr "Aucune URL" #: src/bz-full-view.c:492 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Cette application est sous une licence FLOSS, la fiabilité de son code " "source peut donc être auditée." #: src/bz-full-view.c:493 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Cette application est soumise à une licence propriétaire, son code source " "est donc privé et ne peut pas être audité par un tiers indépendant." #: src/bz-full-view.c:500 msgid "More Apps" msgstr "Plus d’applis" #: src/bz-full-view.c:501 #, c-format msgid "More Apps by %s" msgstr "Plus d’applis par %s" #: src/bz-full-view.c:508 msgid "Other Apps by this Developer" msgstr "D’autres applis de ce développeur" #: src/bz-full-view.c:510 src/bz-full-view.c:700 #, c-format msgid "Other Apps by %s" msgstr "D’autres applis par %s" #: src/bz-full-view.c:519 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "%s n’est pas installé, mais a toujours %s de données présentes." #: src/bz-full-view.c:599 src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "Sûr" #: src/bz-full-view.c:601 src/bz-full-view.c:603 msgid "Low Risk" msgstr "Risque faible" #: src/bz-full-view.c:605 msgid "Medium Risk" msgstr "Risque moyen" #: src/bz-full-view.c:607 msgid "High Risk" msgstr "Risque élevé" #: src/bz-full-view.c:702 msgid "Other Apps" msgstr "D’autres applis" #: src/bz-full-view.c:704 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d application" msgstr[1] "%d applications" #: src/bz-full-view.c:948 msgid "Show Less" msgstr "Montrer moins" #: src/bz-full-view.c:948 msgid "Show More" msgstr "Montrer plus" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 msgid "Hardware Support" msgstr "Support matériel" #: src/bz-hardware-support-dialog.c:62 msgid "Keyboard support" msgstr "Prise en charge des claviers" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "Requiert un clavier" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "Recommande l’utilisation d’un clavier" #: src/bz-hardware-support-dialog.c:66 msgid "Supports keyboards" msgstr "Prend en charge les claviers" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "Prise en charge des claviers inconnue" #: src/bz-hardware-support-dialog.c:69 msgid "Mouse support" msgstr "Prise en charge des souris" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "Nécessite une souris ou un pointeur" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "Recommande l’utilisation d’une souris ou d’un pointeur" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "Prend en charge les souris et pointeurs" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "Prise en charge des souris et pointeurs inconnue" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "Prise en charge des écrans tactiles" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "Requiert un écran tactile" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "Recommande l’utilisation d’un écran tactile" #: src/bz-hardware-support-dialog.c:80 msgid "Supports touchscreens" msgstr "Prend en charge les écrans tactiles" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "Prise en charge des écrans tactiles inconnue" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "Prise en charge des appareils mobiles" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "Fonctionne sur les appareils mobiles" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "Pourrait ne pas fonctionner correctement sur les appareils mobiles" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "Prise en charge des ordinateurs" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "Fonctionne bien sur les écrans large" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "%s fonctionne mieux sur du matériel spécifique" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "%s fonctionne sur la plupart des appareils" #: src/bz-install-controls.blp:34 src/bz-transaction-dialog.c:202 msgid "_Install" msgstr "_Installer" #: src/bz-install-controls.blp:60 msgid "_Open" msgstr "_Ouvrir" #: src/bz-install-controls.blp:75 src/bz-install-controls.blp:131 msgid "Uninstall Application" msgstr "Désinstaller l’application" #: src/bz-install-controls.blp:85 src/bz-transaction-dialog.c:231 msgid "_Remove" msgstr "_Désinstaller" #: src/bz-install-controls.blp:118 src/bz-updates-card.blp:184 #: src/bz-updates-card.blp:212 msgid "Update" msgstr "Mettre à jour" #: src/bz-installed-tile.blp:64 src/bz-rich-app-tile.blp:140 msgid "Stopped Receiving Updates" msgstr "Ne reçoit plus de mises à jour" #: src/bz-library-page.blp:31 msgid "Search installed apps" msgstr "Rechercher des applis installées" #: src/bz-library-page.blp:48 msgid "Clear search" msgstr "Effacer la recherche" #: src/bz-library-page.blp:69 msgid "No Apps Found" msgstr "Aucune appli trouvée" # "Bibliothèque" est trop long sous un format "mobile" #. Translators: . #: src/bz-library-page.blp:98 src/bz-window.blp:112 msgid "Library" msgstr "Bibliothèque" #: src/bz-library-page.blp:126 msgid "Pending Updates" msgstr "Mises à jour en attente" #: src/bz-library-page.blp:153 msgid "Downloads" msgstr "Téléchargements" #: src/bz-library-page.blp:196 msgid "Recently Uninstalled" msgstr "Désinstallées récemment" #: src/bz-library-page.blp:247 msgid "Clear Finished Tasks" msgstr "Effacer les tâches effectuées" #: src/bz-library-page.blp:260 msgid "Installed Apps" msgstr "Applis installées" #: src/bz-library-page.blp:333 msgid "Sort By" msgstr "Trier par" #: src/bz-library-page.blp:347 msgid "Name" msgstr "Nom" #: src/bz-library-page.blp:353 msgid "Size" msgstr "Taille" #: src/bz-library-page.c:180 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "Aucune application installée ne correspond à « %s »" #: src/bz-library-page.c:193 src/bz-updates-card.c:257 #, c-format msgid "%u Available Update" msgid_plural "%u Available Updates" msgstr[0] "%u mise à jour disponible" msgstr[1] "%u mises à jour disponibles" #: src/bz-license-dialog.blp:95 msgid "Get Involved" msgstr "S’impliquer" #: src/bz-license-dialog.blp:112 msgid "Learn More" msgstr "En savoir plus" #: src/bz-license-dialog.c:126 msgid "Unknown License" msgstr "Licence inconnue" #: src/bz-license-dialog.c:129 msgid "Community Built" msgstr "Construite par la communauté" #: src/bz-license-dialog.c:202 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Cette appli est développée de manière ouverte par une communauté " "internationale.\n" "\n" "Vous pouvez participer à son amélioration." #: src/bz-license-dialog.c:205 msgid "The license of this app is not known" msgstr "La licence de cette appli est inconnue" #: src/bz-license-dialog.c:211 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Cette appli est développée de manière ouverte par une communauté " "internationale, et publiée sous la licence %s.\n" "\n" "Vous pouvez participer à son amélioration." #: src/bz-license-dialog.c:219 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Cette appli n’est pas développée de manière ouverte : seuls ses développeurs " "connaissent son fonctionnement. Elle est susceptible de comporter des " "failles de sécurité difficiles à détecter et peut changer sans aucun " "contrôle préalable.\n" "\n" "Vous ne pourrez peut-être pas contribuer à cette application." #: src/bz-license-dialog.c:225 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Cette appli est développée sous la licence spéciale %s.\n" "\n" "Vous ne pourrez peut-être pas contribuer à cette application." #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 msgid "Connect to Flathub" msgstr "Se connecter à Flathub" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "Une erreur s’est produite" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "" "Connectez votre compte Flathub à Bazaar pour gérer vos applications " "favorites." #: src/bz-login-page.blp:110 msgid "Finish" msgstr "Terminer" #: src/bz-login-page.c:664 #, c-format msgid "Hello, %s!" msgstr "Bonjour, %s !" #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Préférences" #: src/bz-preferences-dialog.blp:25 msgid "Network connection is metered — automatic store data refresh is paused" msgstr "" "La connexion réseau est limitée — l’actualisation automatique de la " "logithèque est suspendue" #: src/bz-preferences-dialog.blp:26 src/bz-window.blp:282 msgid "Refresh Manually" msgstr "Actualiser manuellement" #: src/bz-preferences-dialog.blp:31 msgid "Content Filters" msgstr "Filtres de contenus" #: src/bz-preferences-dialog.blp:34 msgid "Free Software Only" msgstr "Logiciels libres seulement" #: src/bz-preferences-dialog.blp:35 msgid "Hide proprietary applications when browsing and searching" msgstr "Masque les applications propriétaires dans les résultats de recherche" #: src/bz-preferences-dialog.blp:39 msgid "Flathub Results Only" msgstr "Logiciels Flathub seulement" #: src/bz-preferences-dialog.blp:40 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "" "Limite les résultats de recherche aux applications disponibles sur Flathub" #: src/bz-preferences-dialog.blp:44 msgid "Verified Results Only" msgstr "Résultats vérifiés seulement" #: src/bz-preferences-dialog.blp:45 msgid "Hide results that are not verified on Flathub" msgstr "Masque les résultats non vérifiés sur Flathub" #: src/bz-preferences-dialog.blp:49 msgid "Hide EOL Apps" msgstr "Masquer les applis en fin de vie" #: src/bz-preferences-dialog.blp:50 msgid "Hide apps which are no longer supported by their developers" msgstr "" "Masque les applis qui ne sont plus prises en charge par leurs développeurs" #: src/bz-preferences-dialog.blp:55 src/bz-window.blp:127 msgid "Search" msgstr "Recherche" #: src/bz-preferences-dialog.blp:58 msgid "Delay Search Results" msgstr "Retarder l’affichage des résultats de recherche" #: src/bz-preferences-dialog.blp:59 msgid "Improve results performance by debouncing search terms" msgstr "Améliore la performance des résultats en rajoutant un anti-rebond" #: src/bz-preferences-dialog.blp:64 msgid "Progress Bar" msgstr "Barre de progression" #: src/bz-preferences-dialog.blp:65 msgid "Choose a theme for the progress bar!" msgstr "Choisissez un thème pour la barre de progression !" #: src/bz-preferences-dialog.blp:89 msgid "Vertical Stripes" msgstr "Motifs verticaux" #: src/bz-preferences-dialog.blp:90 msgid "Display flag colors from left to right" msgstr "Affiche les couleurs des drapeaux de gauche à droite" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Couleur d’accentuation" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Couleurs de la fierté" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "Couleurs de la fierté lesbienne" #: src/bz-preferences-dialog.c:35 msgid "Male Homosexual Pride Colors" msgstr "Couleurs de la fierté homosexuelle" #: src/bz-preferences-dialog.c:36 msgid "Transgender Pride Colors" msgstr "Couleurs de la fierté transgenre" #: src/bz-preferences-dialog.c:37 msgid "Nonbinary Pride Colors" msgstr "Couleurs de la fierté non binaire" #: src/bz-preferences-dialog.c:38 msgid "Bisexual Pride Colors" msgstr "Couleurs de la fierté bisexuelle" #: src/bz-preferences-dialog.c:39 msgid "Asexual Pride Colors" msgstr "Couleurs de la fierté asexuelle" #: src/bz-preferences-dialog.c:40 msgid "Pansexual Pride Colors" msgstr "Couleurs de la fierté pansexuelle" #: src/bz-preferences-dialog.c:41 msgid "Aromantic Pride Colors" msgstr "Couleurs de la fierté aromantique" #: src/bz-preferences-dialog.c:42 msgid "Genderfluid Pride Colors" msgstr "Couleurs de la fierté fluide" #: src/bz-preferences-dialog.c:43 msgid "Polysexual Pride Colors" msgstr "Couleurs de la fierté polysexuelle" #: src/bz-preferences-dialog.c:44 msgid "Omnisexual Pride Colors" msgstr "Couleurs de la fierté omnisexuelle" #: src/bz-preferences-dialog.c:45 msgid "Aroace Pride Colors" msgstr "Couleurs de la fierté aroace" #: src/bz-preferences-dialog.c:46 msgid "Agender Pride Colors" msgstr "Couleurs du drapeau agenre" #: src/bz-preferences-dialog.c:47 msgid "Genderqueer Pride Colors" msgstr "Couleurs du drapeau genderqueer" #: src/bz-preferences-dialog.c:48 msgid "Intersex Pride Colors" msgstr "Couleurs du drapeau intersexe" #: src/bz-preferences-dialog.c:49 msgid "Demigender Pride Colors" msgstr "Couleurs du drapeau demi-genre" #: src/bz-preferences-dialog.c:50 msgid "Biromantic Pride Colors" msgstr "Couleurs du drapeau biromantique" #: src/bz-preferences-dialog.c:51 msgid "Disability Pride Colors" msgstr "Couleurs de la fierté des personnes en situation de handicap" #: src/bz-preferences-dialog.c:52 msgid "Femboy Pride Colors" msgstr "Couleurs de la fierté femboy" #: src/bz-preferences-dialog.c:53 msgid "Neutrois Pride Colors" msgstr "Couleurs du drapeau neutrois" #: src/bz-releases-dialog.blp:5 src/bz-updates-card.blp:171 msgid "Version History" msgstr "Historique des versions" #: src/bz-releases-list.blp:27 msgid "_Version History" msgstr "_Historique des versions" #. Translators: something happened less than a day ago #: src/bz-releases-list.c:122 msgid "Today" msgstr "Aujourd'hui" #. Translators: something happened more than a day ago but less than 2 days ago #: src/bz-releases-list.c:125 msgid "Yesterday" msgstr "Hier" #. Translators: something happened days ago #: src/bz-releases-list.c:128 #, c-format msgid "%d day ago" msgid_plural "%d days ago" msgstr[0] "Il y a %d jour" msgstr[1] "Il y a %d jours" #. Translators: something happened weeks ago #: src/bz-releases-list.c:131 #, c-format msgid "%d week ago" msgid_plural "%d weeks ago" msgstr[0] "Il y a %d semaine" msgstr[1] "Il y a %d semaines" #. Translators: something happened months ago #: src/bz-releases-list.c:134 #, c-format msgid "%d month ago" msgid_plural "%d months ago" msgstr[0] "Il y a %d mois" msgstr[1] "Il y a %d mois" #. Translators: something happened years ago #: src/bz-releases-list.c:137 #, c-format msgid "%d year ago" msgid_plural "%d years ago" msgstr[0] "Il y a %d an" msgstr[1] "Il y a %d ans" #. TRANSLATORS: This is the date string with: day number, month name, year. #. i.e. "22 March 2026" #: src/bz-releases-list.c:155 msgid "%e %B %Y" msgstr "%e %B %Y" #: src/bz-releases-list.c:195 #, c-format msgid "Version %s" msgstr "Version %s" #: src/bz-releases-list.c:250 msgid "No details for this release" msgstr "Aucun détail à propos de cette version" #: src/bz-releases-list.c:262 msgid "Get More Information" msgstr "Obtenir plus d’informations" # Dans le contexte d'App Store - "Get" serait plutôt traduit en "Télécharger" ou comme ici en "Installer" #: src/bz-rich-app-tile.blp:157 msgid "Get" msgstr "Installer" #: src/bz-rich-app-tile.blp:185 src/bz-transaction-tile.blp:272 msgid "Open" msgstr "Ouvrir" #: src/bz-safety-calculator.c:82 msgid "Unknown Permissions" msgstr "Autorisations inconnues" #: src/bz-safety-calculator.c:83 msgid "Permissions are missing for this app." msgstr "Des autorisations sont manquantes pour cette application." #: src/bz-safety-calculator.c:96 msgid "No Permissions" msgstr "Aucune autorisation" #: src/bz-safety-calculator.c:97 msgid "App is fully sandboxed" msgstr "L’application est entièrement sandboxée" #: src/bz-safety-calculator.c:103 msgid "Network Access" msgstr "Accès à Internet" #: src/bz-safety-calculator.c:104 msgid "Can access the internet" msgstr "Peut accéder à Internet" #: src/bz-safety-calculator.c:106 msgid "No Network Access" msgstr "Aucun accès Internet" #: src/bz-safety-calculator.c:107 msgid "Cannot access the internet" msgstr "Ne peut pas accéder à Internet" #: src/bz-safety-calculator.c:112 msgid "User Device Access" msgstr "Accès à l’appareil de l’utilisateur" #: src/bz-safety-calculator.c:113 msgid "Can access devices such as webcams or gaming controllers" msgstr "" "Peut accéder à des périphériques tels que des webcams ou des manettes de jeu" #: src/bz-safety-calculator.c:115 msgid "No User Device Access" msgstr "Aucun accès aux périphériques" #: src/bz-safety-calculator.c:116 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "" "Ne peut pas accéder aux périphériques système qui nécessitent des " "autorisations élevées" #: src/bz-safety-calculator.c:121 msgid "Input Device Access" msgstr "Accès aux périphériques d’entrée" #: src/bz-safety-calculator.c:122 msgid "Can access input devices" msgstr "Peut accéder aux périphériques d’entrée" #: src/bz-safety-calculator.c:128 msgid "Microphone Access and Audio Playback" msgstr "Accès au microphone et à la lecture audio" #: src/bz-safety-calculator.c:129 msgid "Can listen using microphones and play audio without asking permission" msgstr "" "A accès aux microphones connectés et peut lire des fichiers audio sans " "demander l’autorisation" #: src/bz-safety-calculator.c:135 msgid "System Device Access" msgstr "Accès aux périphériques du système" #: src/bz-safety-calculator.c:136 msgid "Can access system devices which require elevated permissions" msgstr "" "Peut accéder aux périphériques du système qui nécessitent des autorisations " "élevées" #: src/bz-safety-calculator.c:142 msgid "Screen Contents Access" msgstr "Accès au contenu de l’écran" #: src/bz-safety-calculator.c:143 msgid "Can access the contents of the screen or other windows" msgstr "Peut accéder au contenu de l’écran ou d’autres fenêtres" #: src/bz-safety-calculator.c:149 msgid "Legacy Windowing System" msgstr "Système de fenêtrage ancien" #: src/bz-safety-calculator.c:150 msgid "Always uses a legacy windowing system (X11)" msgstr "Utilise toujours un ancien système de fenêtrage (X11)" #: src/bz-safety-calculator.c:156 msgid "Arbitrary Permissions" msgstr "Autorisations arbitraires" #: src/bz-safety-calculator.c:157 msgid "Can acquire arbitrary permissions" msgstr "Peut obtenir des autorisations arbitraires" #: src/bz-safety-calculator.c:163 msgid "User Settings" msgstr "Paramètres utilisateur" #: src/bz-safety-calculator.c:164 msgid "Can access and change user settings" msgstr "Peut accéder aux paramètres utilisateur et les modifier" #: src/bz-safety-calculator.c:170 msgid "Full File System Read/Write Access" msgstr "Accès complet en lecture/écriture au système de fichiers" #: src/bz-safety-calculator.c:171 msgid "Can read and write all data on the file system" msgstr "Peut lire et écrire tout le contenu du système de fichiers" #: src/bz-safety-calculator.c:178 msgid "Home Folder Read/Write Access" msgstr "Accès en lecture/écriture au dossier personnel" #: src/bz-safety-calculator.c:179 msgid "Can read and write all data in your home directory" msgstr "Peut lire et écrire tout le contenu de votre dossier personnel" #: src/bz-safety-calculator.c:186 msgid "Full File System Read Access" msgstr "Accès complet en lecture au système de fichiers" #: src/bz-safety-calculator.c:187 msgid "Can read all data on the file system" msgstr "Peut lire tout le contenu du système de fichiers" #: src/bz-safety-calculator.c:195 msgid "Home Folder Read Access" msgstr "Accès en lecture au dossier personnel" #: src/bz-safety-calculator.c:196 msgid "Can read all data in your home directory" msgstr "Peut lire tout le contenu de votre dossier personnel" #: src/bz-safety-calculator.c:204 msgid "Download Folder Read/Write Access" msgstr "Accès en lecture/écriture au dossier Téléchargements" #: src/bz-safety-calculator.c:205 msgid "Can read and write all data in your downloads directory" msgstr "Peut lire et écrire tout le contenu de votre dossier Téléchargements" #: src/bz-safety-calculator.c:215 msgid "Download Folder Read Access" msgstr "Accès en lecture au dossier Téléchargements" #: src/bz-safety-calculator.c:216 msgid "Can read all data in your downloads directory" msgstr "Peut lire tout le contenu de votre dossier Téléchargements" #: src/bz-safety-calculator.c:229 msgid "Can read and write all data in the directory" msgstr "Peut lire et écrire tout le contenu du répertoire" #: src/bz-safety-calculator.c:243 msgid "Can read all data in the directory" msgstr "Peut lire tout le contenu du répertoire" #: src/bz-safety-calculator.c:258 msgid "No File System Access" msgstr "Aucun accès au système de fichiers" #: src/bz-safety-calculator.c:259 msgid "Cannot access the file system at all" msgstr "Ne peut pas accéder au système de fichiers" #: src/bz-safety-calculator.c:266 msgid "Uses System Services" msgstr "Utilise les services système" #: src/bz-safety-calculator.c:267 msgid "Can request data from non-portal system services" msgstr "Peut demander des données à des services système hors portail" #: src/bz-safety-calculator.c:273 msgid "Uses Session Services" msgstr "Utilise les services de la session utilisateur" #: src/bz-safety-calculator.c:274 msgid "Can request data from non-portal session services" msgstr "Peut demander des données à des services de session hors portail" #: src/bz-safety-calculator.c:322 msgid "No Service Access" msgstr "Aucun accès aux services" #: src/bz-safety-calculator.c:323 msgid "Cannot access non-portal session or system services at all" msgstr "" "Ne peut ni accéder à des services de session, ni à des services système hors " "portail" #: src/bz-safety-calculator.c:331 msgid "Verified App Developer" msgstr "Développeur vérifié" #: src/bz-safety-calculator.c:332 msgid "The developer of this app has been verified to be who they say they are" msgstr "L’identité du développeur de cette application a été vérifiée" #: src/bz-safety-calculator.c:341 msgid "Proprietary Code" msgstr "Code propriétaire" #: src/bz-safety-calculator.c:342 msgid "" "The source code is not public, so it cannot be independently audited and " "might be unsafe" msgstr "" "Le code source n’est pas public, il ne peut donc pas être vérifié de manière " "indépendante et pourrait ne pas être sécurisé" #: src/bz-safety-calculator.c:352 msgid "Auditable Code" msgstr "Code vérifiable" #: src/bz-safety-calculator.c:353 msgid "" "The source code is public and can be independently audited, which makes the " "app more likely to be safe" msgstr "" "Le code source est public et peut être vérifié de manière indépendante, ce " "qui rend l’application plus sûre" #: src/bz-safety-calculator.c:493 #, c-format msgid "Use the %s System Service" msgstr "Utilise le service système %s" #: src/bz-safety-calculator.c:497 #, c-format msgid "Use the %s Session Service" msgstr "Utilise le service de session %s" #: src/bz-safety-calculator.c:501 #, c-format msgid "Use the %s Service" msgstr "Utilise le service %s" #: src/bz-safety-calculator.c:511 msgid "Can see the non-portal service" msgstr "Peut détecter ce service hors portail" #: src/bz-safety-calculator.c:513 msgid "Can talk to the non-portal service" msgstr "Peut communiquer à ce service hors portail" #: src/bz-safety-calculator.c:515 msgid "Can own the non-portal service" msgstr "Peut posséder ce service hors portail" #: src/bz-safety-calculator.c:530 msgid "Global Menu Integration" msgstr "Intégration au menu global" #: src/bz-safety-calculator.c:531 msgid "Can display its menus in a global menu bar" msgstr "Peut afficher ses menus dans une barre de menus globale" #: src/bz-safety-calculator.c:536 msgid "KDE Settings Integration" msgstr "Intégration aux paramètres KDE" #: src/bz-safety-calculator.c:537 msgid "Can detect when KDE desktop settings change" msgstr "Peut détecter lorsque les paramètres du bureau KDE changent" #: src/bz-safety-calculator.c:542 msgid "KDE Global Settings" msgstr "Paramètres généraux KDE" #: src/bz-safety-calculator.c:543 msgid "Can read KDE desktop preferences like fonts and colors" msgstr "" "Peut lire les préférences du bureau KDE telles que les polices et les " "couleurs" #: src/bz-safety-calculator.c:548 msgid "Secret Storage Service" msgstr "Service de stockage secret" #: src/bz-safety-calculator.c:549 msgid "Can store and retrieve its own passwords using the system keyring" msgstr "" "Peut stocker et récupérer ses propres mots de passe à l’aide du trousseau " "système" #: src/bz-safety-calculator.c:554 msgid "Desktop Notifications Service" msgstr "Service de notifications sur le bureau" #: src/bz-safety-calculator.c:555 msgid "Can send desktop notifications" msgstr "Peut envoyer des notifications sur le bureau" #: src/bz-safety-calculator.c:561 msgid "System Tray Integration" msgstr "Intégration dans la barre d’état système" #: src/bz-safety-calculator.c:562 msgid "Can display an icon in the system tray" msgstr "Peut afficher une icône dans la barre d’état système" #: src/bz-safety-calculator.c:567 msgid "KDE Connect Integration" msgstr "Intégration de KDE Connect" #: src/bz-safety-calculator.c:568 msgid "Can interact with devices paired via KDE Connect" msgstr "Peut interagir avec les appareils connectés avec KDE Connect" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "Sécurité" #: src/bz-safety-dialog.blp:53 msgid "License" msgstr "Licence" #: src/bz-safety-dialog.blp:63 msgid "App ID" msgstr "Identifiant applicatif" #: src/bz-safety-dialog.blp:73 msgid "SDK" msgstr "Plateforme logicielle" #: src/bz-safety-dialog.blp:104 msgid "" "This app uses an outdated version of the software platform (SDK) and might " "contain bugs or security vulnerabilities which will not be fixed." msgstr "" "Cette application utilise une version obsolète de la plateforme logicielle " "(SDK) et peut contenir des bogues ou des failles de sécurité qui ne seront " "pas corrigés." #: src/bz-safety-dialog.c:227 #, c-format msgid "%s is Safe" msgstr "%s est sûr" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s has no Unsafe Permissions" msgstr "%s n’a pas d’autorisations à risque" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Probably Safe" msgstr "%s est probablement sûr" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Possibly Unsafe" msgstr "%s pourrait ne pas être sûr" #: src/bz-safety-dialog.c:247 #, c-format msgid "%s is Unsafe" msgstr "%s n’est pas sûr" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "Captures d’écran" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "Capture d’écran précédente" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "Capture d’écran suivante" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "Copier l’image" #: src/bz-screenshot-page.blp:150 msgid "Reset View" msgstr "Réinitialiser l’affichage" #: src/bz-screenshot-page.blp:161 msgid "Zoom Out" msgstr "Zoom arrière" #: src/bz-screenshot-page.blp:171 msgid "Zoom In" msgstr "Zoom avant" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "Carrousel de captures d’écran" #: src/bz-screenshots-carousel.blp:117 msgid "Open Screenshot Viewer" msgstr "Ouvrir la visionneuse de captures d’écran" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:72 msgid "Video" msgstr "Vidéo" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:82 msgid "Office" msgstr "Bureautique" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:87 msgid "PDF" msgstr "PDF" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:92 msgid "Calendar" msgstr "Calendrier" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:97 msgid "Messaging" msgstr "Messagerie" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:102 msgid "Steam" msgstr "Steam" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:107 msgid "Paint" msgstr "Dessin" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:112 msgid "VPN" msgstr "VPN" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:117 msgid "Torrent" msgstr "Torrent" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:122 msgid "Minecraft" msgstr "Minecraft" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:127 msgid "Emulator" msgstr "Émulateur" #: src/bz-search-page.blp:57 msgid "Search Apps, Games, Software" msgstr "Rechercher applis, jeux et logiciels" #: src/bz-search-page.blp:79 msgid "Clear Search" msgstr "Effacer la recherche" #: src/bz-search-page.blp:171 msgid "Categories Unavailable" msgstr "Catégories non disponibles" #: src/bz-search-page.blp:172 msgid "Search for apps using the search bar above." msgstr "Cherchez des applis en utilisant l'onglet « Rechercher »." #: src/bz-search-page.blp:198 msgid "Browse Categories" msgstr "Parcourir les catégories" #: src/bz-search-page.blp:340 msgid "No Applications Found" msgstr "Aucune application trouvée" #: src/bz-search-page.c:244 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "Aucun résultat trouvé pour « %s » dans Flathub" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "Copier le lien" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Ouvrir le lien" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "Chronologie" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "Installations :" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "Monde" #: src/bz-stats-dialog.blp:69 msgid "Since 4/15/2024" msgstr "Depuis le 15 Avril 2024" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:124 #, c-format msgid "%.2fM Total Installs" msgstr "%.2f Mio installations en tout" #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:127 #, c-format msgid "%.2fK Total Installs" msgstr "%.2f mil. installations en tout" #: src/bz-stats-dialog.c:129 #, c-format msgid "%'d Total Installs" msgstr "%'d téléchargements en tout" #: src/bz-tag-list.c:78 msgid "No Results Found" msgstr "Aucun résultat trouvé" #: src/bz-tag-list.c:90 #, c-format msgid "Apps Tagged \"%s\"" msgstr "Applis étiquetées « %s »" #: src/bz-tag-list.c:103 msgid "Search failed" msgstr "La recherche a échoué" #: src/bz-transaction-dialog.c:155 msgid "Keep User Data" msgstr "Conserver les données utilisateur" #: src/bz-transaction-dialog.c:156 msgid "Allow restoring personal settings & content" msgstr "Permet la restauration des paramètres et du contenu" #: src/bz-transaction-dialog.c:165 msgid "Delete All Data" msgstr "Supprimer les données" #: src/bz-transaction-dialog.c:166 msgid "Permanently erase user data to save space" msgstr "" "Supprime définitivement les données de l’appli pour libérer de l’espace" #: src/bz-transaction-dialog.c:191 #, c-format msgid "Install %s?" msgstr "Installer %s ?" #: src/bz-transaction-dialog.c:196 msgid "" "Select which version to install. May install additional shared components" msgstr "" "Sélectionnez la version à installer. Pourrait installer des composants " "partagés supplémentaires" #: src/bz-transaction-dialog.c:198 msgid "May install additional shared components" msgstr "Pourrait installer des composants partagés supplémentaires" #: src/bz-transaction-dialog.c:201 src/bz-transaction-dialog.c:230 #: src/bz-transaction-dialog.c:275 src/bz-transaction-dialog.c:578 msgid "_Cancel" msgstr "_Annuler" #: src/bz-transaction-dialog.c:219 #, c-format msgid "Remove %s?" msgstr "Désinstaller %s ?" #: src/bz-transaction-dialog.c:222 msgid "Select which version to remove." msgstr "Sélectionnez la version à désinstaller." #: src/bz-transaction-dialog.c:224 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "Il ne sera plus possible d’utiliser %s après sa désinstallation." #: src/bz-transaction-dialog.c:247 #, c-format msgid "“%s” is High Risk" msgstr "« %s » présente un risque élevé" #: src/bz-transaction-dialog.c:251 msgid "" "This app has full access to your system, including all your files, " "browser history, saved passwords, and more. It also has access to the " "internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Cette application dispose d’un accès complet à votre système, y compris à " "tous vos fichiers, à l’historique de votre navigateur, à vos mots de " "passe enregistrés, etc. Elle a également accès à Internet, ce qui " "signifie qu’elle pourrait envoyer vos données à des tiers.\n" "\n" "Comme cette application est propriétaire, il est impossible de vérifier ce " "qu’elle fait avec ces autorisations." #: src/bz-transaction-dialog.c:260 msgid "" "This app uses the legacy X11 windowing system, which allows it to record " "all keystrokes, capture screenshots, and monitor other applications. It " "also has access to the internet, meaning it could send your data to outside " "parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Cette application utilise l’ancien système de fenêtrage X11, qui lui permet " "d’enregistrer toutes les frappes au clavier, de faire des captures " "d’écran et de surveiller d’autres applications. Elle a également accès à " "Internet, ce qui signifie qu’elle pourrait envoyer vos données à des tiers.\n" "\n" "Comme cette application est propriétaire, il est impossible de vérifier ce " "qu’elle fait avec ces autorisations." #: src/bz-transaction-dialog.c:276 msgid "_Install Anyway" msgstr "_Installer quand même" #: src/bz-transaction-dialog.c:331 msgid "Failed to load transaction dialog" msgstr "Échec du chargement du dialogue de la transaction" #: src/bz-transaction-dialog.c:549 msgid "All apps are already installed" msgstr "Toutes les applis sont déjà installées" #: src/bz-transaction-dialog.c:551 msgid "_OK" msgstr "D’_accord" #: src/bz-transaction-dialog.c:567 #, c-format msgid "Install %u App?" msgid_plural "Install %u Apps?" msgstr[0] "Installer %u appli ?" msgstr[1] "Installer %u applis ?" #: src/bz-transaction-dialog.c:575 msgid "" "The following will be installed. Additional shared components may also be " "installed" msgstr "" "Les applications suivantes seront installées. Des composants partagés " "supplémentaires pourraient également être installés" #: src/bz-transaction-dialog.c:576 #, c-format msgid "%d addons will be installed." msgstr "%d extensions seront installées." #: src/bz-transaction-dialog.c:577 msgid "Additionally, addons will be installed." msgstr "Des extensions seront aussi installées." #: src/bz-transaction-dialog.c:579 msgid "_Install All" msgstr "_Tout installer" #: src/bz-transaction-manager.c:766 #, c-format msgid "Finished in %.02f seconds" msgstr "Terminé en %.02f secondes" #: src/bz-transaction-tile.blp:129 msgid "App Add-On" msgstr "Extension de l’appli" #: src/bz-transaction-tile.blp:158 msgid "Runtime" msgstr "Environnement d’exécution" #: src/bz-transaction-tile.blp:182 msgid "In Queue" msgstr "En attente" #: src/bz-transaction-tile.blp:206 msgid "Done" msgstr "Terminé" #: src/bz-transaction-tile.blp:230 msgid "Error" msgstr "Erreur" #: src/bz-transaction-tile.blp:286 msgid "Cancel Transaction" msgstr "Annuler la tâche" #: src/bz-transaction-tile.blp:410 msgid "Show Error Info" msgstr "Afficher les informations sur l'erreur" # Pluriel car on parle d'octets #: src/bz-transaction-tile.c:107 #, c-format msgid "%s Freed" msgstr "%s libérés" #: src/bz-transaction-tile.c:362 src/bz-transaction-tile.c:365 msgid "Transaction Error" msgstr "Erreur de transaction" #: src/bz-transaction.c:342 msgid "Pending" msgstr "En attente" #: src/bz-updates-card.blp:40 msgid "_Update All" msgstr "Tout _mettre à jour" #: src/bz-updates-card.c:293 #, c-format msgid "%u Runtime Update" msgid_plural "%u Runtime Updates" msgstr[0] "%u mise à jour d'environnement d’exécution " msgstr[1] "%u mises à jour d'environnement d’exécution " #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "Nettoyer les données orphelines" #: src/bz-user-data-page.blp:89 msgid "No User Data Found" msgstr "Pas de données orphelines trouvées" #: src/bz-user-data-page.blp:94 msgid "User Data" msgstr "Données utilisateur" #: src/bz-user-data-tile.c:144 #, c-format msgid "Trashed User Data for %s" msgstr "Les données utilisateur de %s ont été mise à la corbeille" #: src/bz-user-data-tile.blp:74 msgid "Trash User Data" msgstr "Mettre les données utilisateurs à la corbeille" #: src/bz-window.blp:88 msgid "Curated" msgstr "Sélection" #: src/bz-window.blp:100 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:220 msgid "Refresh completed!" msgstr "Actualisation terminée !" #: src/bz-window.blp:273 msgid "You are running a new version of Bazaar!" msgstr "Bazaar a été mis à jour !" #: src/bz-window.blp:274 msgid "See What's New" msgstr "Voir les nouveautés" #: src/bz-window.blp:281 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "" "Vous disposez d’une connexion réseau, mais consultez une version mise en " "cache de Flathub" #: src/bz-window.blp:393 msgid "Log Out" msgstr "Se déconnecter" #. Translators: %s is the title of the current page #: src/bz-window.c:380 #, c-format msgid "Bazaar — %s" msgstr "Bazaar — %s" #: src/bz-window.c:487 msgid "Failed to load add-ons" msgstr "Échec du chargement des modules complémentaires" #: src/bz-window.c:601 src/bz-window.c:618 msgid "Failed to launch application" msgstr "Échec du lancement de l'application" #: src/bz-window.c:823 msgid "You can't remove Bazaar from Bazaar!" msgstr "Vous ne pouvez supprimer Bazaar depuis Bazaar !" #: src/bz-window.c:1108 src/bz-window.c:1142 msgid "Can't do that right now!" msgstr "Impossible de faire ceci pour le moment !" #: src/bz-world-map.c:595 msgctxt "As in, \"100 Downloads\"" msgid "Downloads" msgstr "téléchargements" #: src/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Général" #: src/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Page" msgstr "Ouvrir la page Recherche" #: src/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Library Page" msgstr "Ouvrir la page Bibliothèque" #: src/shortcuts-dialog.blp:20 msgctxt "shortcut window" msgid "Refresh" msgstr "Actualiser" #: src/shortcuts-dialog.blp:25 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Ouvrir les préférences" #: src/shortcuts-dialog.blp:30 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Afficher les raccourcis" #: src/shortcuts-dialog.blp:35 msgctxt "shortcut window" msgid "Close Window" msgstr "Fermer la fenêtre" #: src/shortcuts-dialog.blp:41 msgctxt "shortcut window" msgid "Quit Bazaar" msgstr "Quitter Bazaar" bazaar-orig-v0.7.14/po/pt_PT.po0000664000175000017500000025642415166123241015161 0ustar hasanhasan# Portuguese translations for bazaar package # Tradução portuguesa (Portugal) para o pacote bazaar. # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-01-27 19:32+0000\n" "PO-Revision-Date: 2025-07-15 11:36+0100\n" "Last-Translator: Eduardo Correia (Azenyr)\n" "Language-Team: Portuguese (Portugal)\n" "Language: pt_PT\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:5 #: src/bz-window.blp:233 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "Adicionar, remover ou atualizar software flatpak neste computador" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;Sistema;GestorDePacotes;Discover;Flatpak;Aplicações;Loja;" #: data/io.github.kolunmi.Bazaar.desktop.in:15 msgid "New Window" msgstr "Nova Janela" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and install applications" msgstr "Descobrir e instalar aplicações" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 #, fuzzy msgid "" "A new app store for Linux with a focus on discovering and installing " "applications and addons from Flatpak remotes, particularly Flathub." msgstr "" "Uma nova loja de aplicações para Linux com foco em descobrir e instalar " "aplicações e extensões (add-ons) a partir de repositórios Flatpak, " "principalmente do Flathub." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:14 #, fuzzy msgid "" "It emphasizes supporting the developers who make the Linux desktop possible. " "Bazaar features a \"curated\" tab that can be configured by distributors to " "allow for a more localized experience." msgstr "" "Prioritiza o suporte aos desenvolvedores que juntos tornam o Linux em " "computadores possível. O Bazaar apresenta a secção \"Recomendadas\" que pode " "ser configurada pelos distribuidores para permitir uma experiência mais " "personalizada." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:29 src/bz-application.c:706 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:54 #, fuzzy msgid "The home page displaying Flathub apps" msgstr "A vista inicial a demonstrar apps do Flathub" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:58 msgid "Nucleus app page" msgstr "Página da app Nucleus" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:62 #, fuzzy msgid "Search page" msgstr "Página de pesquisa" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:66 msgid "Category page" msgstr "Página das categorias" #: src/bz-addons-dialog.blp:14 src/bz-full-view.blp:701 #: src/bz-installed-tile.blp:99 #, fuzzy msgid "Manage Add-ons" msgstr "Gerir Extensões" #: src/bz-addons-dialog.c:90 src/bz-full-view.blp:488 #: src/bz-installed-tile.blp:117 src/bz-transaction-dialog.c:242 #: src/bz-transaction-view.blp:277 msgid "Remove" msgstr "Remover" #: src/bz-addons-dialog.c:95 src/bz-favorites-tile.c:174 #: src/bz-full-view.blp:255 src/bz-full-view.blp:475 #: src/bz-transaction-dialog.c:213 src/bz-transaction-view.blp:225 msgid "Install" msgstr "Instalar" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 #: src/bz-age-rating-dialog.c:726 src/bz-full-view.c:346 src/bz-full-view.c:353 msgid "Age Rating" msgstr "classificação etária" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "Violência em desenhos animados" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "Sem informação sobre violência em desenhos animados" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "Violência em fantasia" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "Sem informação sobre violência em fantasia" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "Violência realista" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "Sem informação sobre violência realista" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "Violência que mostre sangue" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "Sem informação sobre violência que mostre sangue" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "Violência sexual" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "Sem informação sobre violência sexual" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "Álcool" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "Sem informação sobre referências a álcool" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "Narcóticos (Drogas)" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "Sem informação sobre referências a drogas" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "Tabaco" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "Sem informação sobre referências a produtos de tabaco" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "Nudez" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "Sem informação sobre nudez de qualquer tipo" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "Temas sexuais" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "Sem informação sobre referências ou representações de temas sexuais" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "Linguagem obscena" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "Sem informação sobre uso de linguagem obscena de qualquer tipo" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "Humor inapropriado" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "Sem informação sobre uso de humor inapropriado" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "Discriminação" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "Sem informação sobre liguagem discriminatória de qualquer tipo" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "Publicidades" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "Sem informação sobre publicidade de qualquer tipo" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "Apostas (Jogos de azar)" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "Sem informação sobre apostas ou jogos de azar de qualquer tipo" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "Compras" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "Sem informação sobre a possibilidade de gastar dinheiro" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "Conversas entre utilizadores" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "" "Sem informação sobre a possibilidade de conversar com outros utilizadores" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "Conversas por áudio entre utilizadores" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "Sem informação sobre conversas por áudio entre utilizadores" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 #, fuzzy msgid "Contact Details" msgstr "Detalhes de contacto" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "" "Sem informação sobre a partilha social de nomes de utilizador ou emails" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "Informação pessoal identificável" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "Sem informação sobre a partilha de informação pessoal com terceiros" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "Partilha de localização" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "" "Sem informação sobre a possibilidade de partilhar a localização física com " "outros utilizadores" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "Prostituição" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "Sem informação sobre referências a prostituição" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "Adultério" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "Sem informação sobre referências a adultério" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "Conteúdos sexualizados" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "Sem informação sobre referências a conteúdos sexualizados" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 #, fuzzy msgid "Desecration" msgstr "Profanação" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "Sem informação sobre referências a profanação" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "Visibilidade de restos humanos" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "Sem informação sobre restos humanos visíveis" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "Escravidão" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "Sem informação sobre referências a escravidão" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "Não inclui referências a uso de drogas" #: src/bz-age-rating-dialog.c:426 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "" "Não inclui liguagem palavrões, asneiras, ou qualquer outro tipo de liguagem " "obscena" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "Não inclui publicidade ou transações monetárias" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "Não inclui sexo nem nudez" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "Não inclui capacidade de conversas por chat sem controlo" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "Não inclui violência" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "Drogas" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "Linguagem obscena" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "Dinheiro" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "Social" #: src/bz-age-rating-dialog.c:479 #, fuzzy msgid "Violence" msgstr "Violência" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:676 src/bz-full-view.c:336 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:701 msgctxt "Age rating" msgid "All" msgstr "Todas as idades" #: src/bz-age-rating-dialog.c:737 #, c-format msgid "%s has an unknown age rating" msgstr "%s tem uma classificação etária desconhecida" #: src/bz-age-rating-dialog.c:743 #, c-format msgid "%s is suitable for everyone" msgstr "%s é apropriado para todas as idades" #: src/bz-age-rating-dialog.c:746 #, c-format msgid "%s is suitable for young children" msgstr "%s é apropriado para crianças pequenas" #: src/bz-age-rating-dialog.c:749 #, c-format msgid "%s is suitable for children" msgstr "%s é apropriado para crianças" #: src/bz-age-rating-dialog.c:752 #, fuzzy, c-format msgid "%s is suitable for teenagers" msgstr "%s é apropriado para adolescentes" #: src/bz-age-rating-dialog.c:755 #, fuzzy, c-format msgid "%s is suitable for adults" msgstr "%s é apropriado para adultos" #: src/bz-age-rating-dialog.c:758 #, fuzzy, c-format msgid "%s is suitable for %s" msgstr "%s é apropriado para %s" #: src/bz-age-rating-dialog.c:852 #, c-format msgid "%s • %s" msgstr "%s • %s" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:43 #: src/bz-user-data-page.blp:15 src/bz-window.blp:483 msgid "Main Menu" msgstr "Menu Principal" #: src/bz-all-apps-page.blp:17 src/bz-apps-page.blp:17 #: src/bz-user-data-page.blp:18 src/bz-window.blp:556 msgid "_Donate to Bazaar ❤️" msgstr "_Efetuar uma doação para o Bazaar ❤️" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 #: src/bz-user-data-page.blp:19 #, fuzzy msgid "_Refresh Content" msgstr "_Recarregar conteúdo" #: src/bz-all-apps-page.blp:22 src/bz-apps-page.blp:22 #: src/bz-user-data-page.blp:22 src/bz-window.blp:563 #, fuzzy msgid "_Preferences" msgstr "_Definições" #: src/bz-all-apps-page.blp:23 src/bz-apps-page.blp:23 #: src/bz-user-data-page.blp:23 src/bz-window.blp:584 msgid "_Keyboard Shortcuts" msgstr "_Atalhos de teclado" #: src/bz-all-apps-page.blp:24 src/bz-apps-page.blp:24 #: src/bz-user-data-page.blp:24 src/bz-window.blp:589 msgid "_About Bazaar" msgstr "_Acerca do bazaar" #: src/bz-all-apps-page.blp:28 src/bz-apps-page.blp:28 #: src/bz-user-data-page.blp:27 src/bz-window.blp:596 #, fuzzy msgid "_Quit Bazaar" msgstr "_Sair do bazaar" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "Pasta do sistema %s" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "Subpasta pessoal %s" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "Pastas do sistema principal" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "Definições do sistema principal provenientes de /etc" #: src/bz-app-permissions.c:169 #, fuzzy, c-format msgid "Desktop subfolder %s" msgstr "Subpasta do ambiente de trabalho %s" #: src/bz-app-permissions.c:170 #, fuzzy msgid "Desktop folder" msgstr "Pasta do computador" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "Subpasta documentos %s" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "Pasta documentos" #: src/bz-app-permissions.c:177 #, c-format msgid "Music subfolder %s" msgstr "Subpasta música %s" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "Pasta música" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "Subpasta imagens %s" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "Pasta imagens" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "Subpasta partilha %s" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "Pasta partilha" #: src/bz-app-permissions.c:189 #, c-format msgid "Videos subfolder %s" msgstr "Subpasta vídeos %s" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "Pasta vídeos" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "Subpasta templates %s" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "Pasta templates" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "Subpasta cache do utilizador %s" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "Pasta cache do utilizador" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "Subpasta das definições do utilizador %s" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "Pasta das definições do utilizador" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "Subpasta dos dados do utilizador %s" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "Pasta dos dados do utilizador" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "Subpasta runtime do utilizador %s" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "Pasta runtime do utilizador" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "Acesso ao sistema de ficheiros para %s" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "Caminho de localização desconhecido" #: src/bz-app-size-dialog.blp:29 src/bz-app-size-dialog.blp:55 #, fuzzy msgid "Download Size" msgstr "Tamanho da transferência" #: src/bz-app-size-dialog.blp:56 msgid "Amount to download from the internet" msgstr "Tamanho para transferência da internet" #: src/bz-app-size-dialog.blp:76 #, fuzzy msgid "Installed Size" msgstr "Tamanho da instalação" #: src/bz-app-size-dialog.blp:77 msgid "Size on Disk" msgstr "Tamanho no disco" #: src/bz-app-size-dialog.blp:99 #, fuzzy msgid "User Data Size" msgstr "Dados de utilizador" #: src/bz-app-size-dialog.blp:100 msgid "Caches, settings, and other app data" msgstr "Ficheiros temporários, definições e outros dados da app" #. Translators: As in 'The app is installed'. #. Translators: . #: src/bz-app-tile.blp:86 src/bz-full-view.c:295 src/bz-installed-page.blp:86 #: src/bz-window.blp:299 msgid "Installed" msgstr "Instalado" #: src/bz-apps-page.blp:110 msgid "Show All" msgstr "Mostrar tudo" #: src/bz-apps-page.c:243 #, fuzzy, c-format msgid "All \"%s\"" msgstr "Todas de \"%s\"" #: src/bz-apps-page.c:530 src/bz-tag-list.c:109 #, fuzzy, c-format msgid "%d Applications" msgstr "%d aplicações" #: src/bz-application.c:677 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:678 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:709 msgid "translator-credits" msgstr "" #: src/bz-application.c:720 msgid "Special Thanks" msgstr "Agradecimentos especiais" #: src/bz-application.c:778 msgid "Logged Out Successfully!" msgstr "Sessão terminada com sucesso!" #: src/bz-application.c:906 msgid "Performing setup..." msgstr "A configurar..." #: src/bz-application.c:985 src/bz-application.c:994 #, fuzzy msgid "Set Up Flathub" msgstr "Adicionar o Flathub" #: src/bz-application.c:988 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "O Flathub não está configurado neste sistema. Pode ainda assim navegar e " "instalar apps no Bazaar.\n" "\n" "Pode mesmo assim utilizar o Bazzar para navegar e remover apps já instaladas." #: src/bz-application.c:993 src/bz-window.c:875 msgid "Later" msgstr "Mais tarde" #: src/bz-application.c:1393 src/bz-application.c:3072 msgid "Synchronizing..." msgstr "A sincronizar..." #: src/bz-application.c:1534 src/bz-application.c:3068 #, fuzzy, c-format msgid "Receiving %d entries..." msgstr "A receber %d itens..." #: src/bz-application.c:1539 #, fuzzy msgid "Checking for updates" msgstr "A procurar atualizações..." #: src/bz-application.c:3074 msgid "Indexing Data..." msgstr "A indexar dados..." #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:75 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:53 #: src/bz-installed-page.blp:63 src/bz-user-data-page.blp:52 #: src/bz-window.blp:183 msgid "Empty" msgstr "Vazio" #: src/bz-curated-view.blp:15 #, fuzzy msgid "No Curation" msgstr "Sem Aplicações Recomendadas" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "De momento, não existe sistema de recomendações configurado neste sistema. " "Pode mesmo assim navegar e instalar aplicações na tab Flathub." #: src/bz-curated-view.blp:18 #, fuzzy msgid "Browse Flathub" msgstr "Navegar pelo Flathub" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "Sem Ligação (Offline)" #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 msgid "Browser" msgstr "Explorador" #: src/bz-developer-badge.c:131 msgid "Developer information not available." msgstr "Informações de desenvolvedor não disponíveis." #: src/bz-developer-badge.c:137 src/bz-developer-badge.c:151 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "" "A propriedade do ID da app %s não foi verificada pelo que poderá ser uma " "aplicação da comunidade." #: src/bz-developer-badge.c:155 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "" "A propriedade do ID da app %s foi verificada manualmente pela equipa do " "Flathub." #: src/bz-developer-badge.c:161 #, fuzzy, c-format msgid "" "The ownership of the %1$s app ID has been verified by %2$s on " "%3$s." msgstr "" "A propriedade do ID da app %s foi verificada por %s em %s" #: src/bz-developer-badge.c:168 #, fuzzy, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "A propriedade do ID da app %s foi verificada usando %s" #: src/bz-developer-badge.c:172 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "A propriedade do ID da app %s foi verificado." #: src/bz-entry-group-util.c:73 #, fuzzy msgid "Choose an Installation" msgstr "Escolha uma instalação" #: src/bz-entry-group-util.c:76 #, fuzzy msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "" "Parece que tem múltiplas versões desta app instaladas. Com qual delas " "gostaria de continuar? " #: src/bz-entry-group-util.c:80 src/bz-transaction-dialog.c:212 #: src/bz-transaction-dialog.c:241 src/bz-transaction-dialog.c:286 #: src/bz-transaction-dialog.c:595 msgid "Cancel" msgstr "Cancelar" #: src/bz-entry-selection-row.blp:17 msgid "For this user only" msgstr "Apenas para este utilizador" #: src/bz-entry-selection-row.c:112 msgid "this user" msgstr "este utilizador" #: src/bz-entry-selection-row.c:112 msgid "all users" msgstr "todos os utilizadores" #: src/bz-error.c:68 msgid "An Error Occurred" msgstr "Ocorreu Um Erro" #: src/bz-error.c:89 msgid "Close" msgstr "Fechar" #: src/bz-error.c:90 msgid "Copy and Close" msgstr "Copiar e Fechar" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "Entre com a conta Flathub para gerir os seus favoritos" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "Entrar" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "Contagem de favoritos" #: src/bz-favorites-tile.c:172 #, fuzzy msgid "Uninstall" msgstr "Desinstalar" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:75 #, fuzzy msgid "Support this application" msgstr "Apoiar esta aplicação" #: src/bz-favorites-tile.blp:119 msgid "Remove from Favorites" msgstr "Remover dos favoritos" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:85 #: src/bz-window.blp:614 msgid "Favorites" msgstr "Favoritos" #: src/bz-favorites-page.blp:22 src/bz-full-view.blp:20 src/bz-window.blp:126 #: src/bz-window.blp:460 msgid "Toggle transaction sidebar" msgstr "Alternar a barra lateral de transações" #: src/bz-favorites-page.blp:46 src/bz-transaction-dialog.c:596 #, fuzzy msgid "Install All" msgstr "Instalar" #: src/bz-favorites-page.blp:63 src/bz-user-data-page.blp:41 msgid "Loading" msgstr "A carregar" #: src/bz-favorites-page.blp:78 msgid "No Favorites" msgstr "Sem favoritos" #: src/bz-favorites-page.blp:79 msgid "Applications you mark as favorite will appear here" msgstr "Aplicações que marque como favoritas irão aparecer aqui" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "Anterior" #: src/bz-featured-carousel.blp:53 msgid "Next" msgstr "Seguinte" #: src/bz-featured-tile.blp:88 msgid "App of the Day" msgstr "App do Dia" #: src/bz-flathub-category.c:89 #, fuzzy msgid "Editing" msgstr "Edição" #: src/bz-flathub-category.c:90 msgid "Midi" msgstr "MIDI" #: src/bz-flathub-category.c:91 msgid "Mixer" msgstr "Mixagem" #: src/bz-flathub-category.c:92 msgid "Music" msgstr "Música" #: src/bz-flathub-category.c:93 #, fuzzy msgid "Player" msgstr "Jogar" #: src/bz-flathub-category.c:94 msgid "Recorder" msgstr "Gravador" #: src/bz-flathub-category.c:95 #, fuzzy msgid "Sequencer" msgstr "Sequenciador" #: src/bz-flathub-category.c:96 msgid "Tuner" msgstr "Sintetizador" #: src/bz-flathub-category.c:97 msgid "TV" msgstr "TV" #: src/bz-flathub-category.c:102 #, fuzzy msgid "Emulation" msgstr "Emulação" #: src/bz-flathub-category.c:103 #, fuzzy msgid "Action" msgstr "Ação" #: src/bz-flathub-category.c:104 msgid "Adventure" msgstr "Aventura" #: src/bz-flathub-category.c:105 msgid "Arcade" msgstr "Arcada" #: src/bz-flathub-category.c:106 msgid "Blocks" msgstr "Blocos" #: src/bz-flathub-category.c:107 msgid "Board" msgstr "Tabuleiro" #: src/bz-flathub-category.c:108 msgid "Card" msgstr "Cartas" #: src/bz-flathub-category.c:109 msgid "Kids" msgstr "Crianças" #: src/bz-flathub-category.c:110 msgid "Logic" msgstr "Lógica" #: src/bz-flathub-category.c:111 msgid "Role Playing" msgstr "Atuação (Role Playing)" #: src/bz-flathub-category.c:112 msgid "Shooter" msgstr "Tiros" #: src/bz-flathub-category.c:113 #, fuzzy msgid "Simulation" msgstr "Simulação" #: src/bz-flathub-category.c:114 #, fuzzy msgid "Sports" msgstr "Desporto" #: src/bz-flathub-category.c:115 msgid "Strategy" msgstr "Estratégia" #: src/bz-flathub-category.c:120 msgid "Audio & Video" msgstr "Áudio e Vídeo" #: src/bz-flathub-category.c:120 msgid "Media" msgstr "Multimédia" #: src/bz-flathub-category.c:120 msgid "More Audio & Video" msgstr "Ver mais áudio e vídeo" #: src/bz-flathub-category.c:121 msgid "Developer Tools" msgstr "Ferramentas para desenvolvedores" #: src/bz-flathub-category.c:121 msgid "Develop" msgstr "Desenvolver" #: src/bz-flathub-category.c:121 msgid "More Developer Tools" msgstr "Ver mais ferramentas para desenvolvedores" #: src/bz-flathub-category.c:122 msgid "Education" msgstr "Educação" #: src/bz-flathub-category.c:122 msgid "Learn" msgstr "Aprender" #: src/bz-flathub-category.c:122 #, fuzzy msgid "More Education" msgstr "Ver mais educação" #: src/bz-flathub-category.c:123 msgid "Gaming" msgstr "Jogos" #: src/bz-flathub-category.c:123 msgid "Play" msgstr "Jogar" #: src/bz-flathub-category.c:123 #, fuzzy msgid "More Gaming" msgstr "Ver mais jogos" #: src/bz-flathub-category.c:124 msgid "Graphics & Photography" msgstr "Gráficos e fotografia" #: src/bz-flathub-category.c:124 msgid "Create" msgstr "Criar" #: src/bz-flathub-category.c:124 msgid "More Graphics & Photography" msgstr "Ver mais gráficos e fotografia" #: src/bz-flathub-category.c:125 msgid "Networking" msgstr "Redes e comunicações" #: src/bz-flathub-category.c:125 msgid "Internet" msgstr "Internet" #: src/bz-flathub-category.c:125 msgid "More Networking" msgstr "Ver mais redes e comunicações" #: src/bz-flathub-category.c:126 msgid "Productivity" msgstr "Produtividade" #: src/bz-flathub-category.c:126 msgid "Work" msgstr "Trabalhar" #: src/bz-flathub-category.c:126 msgid "More Productivity" msgstr "Ver mais produtividade" #: src/bz-flathub-category.c:127 msgid "Science" msgstr "Ciência" #: src/bz-flathub-category.c:127 #, fuzzy msgid "More Science" msgstr "Ver mais ciência" #: src/bz-flathub-category.c:128 msgid "System" msgstr "Sistema" #: src/bz-flathub-category.c:128 msgid "More System" msgstr "Mais sistema" #: src/bz-flathub-category.c:129 msgid "Utilities" msgstr "Utilitários" #: src/bz-flathub-category.c:129 msgid "Tools" msgstr "Ferramentas" #: src/bz-flathub-category.c:129 #, fuzzy msgid "More Utilities" msgstr "Ver mais utilitários" #: src/bz-flathub-category.c:130 src/bz-flathub-page.blp:119 #: src/bz-flathub-page.blp:152 msgid "Trending" msgstr "Tendências" #: src/bz-flathub-category.c:130 #, fuzzy msgid "More Trending" msgstr "Mais tendências" #: src/bz-flathub-category.c:131 src/bz-flathub-page.blp:125 #: src/bz-flathub-page.blp:185 msgid "Popular" msgstr "Populares" #: src/bz-flathub-category.c:131 #, fuzzy msgid "More Popular" msgstr "Mais Populares" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:174 msgid "Recently Added" msgstr "Adicionadas Recentemente" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:131 msgid "New" msgstr "Novas" #: src/bz-flathub-category.c:132 #, fuzzy msgid "More New" msgstr "Ver mais adicionadas recentemente" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:163 msgid "Recently Updated" msgstr "Atualizadas Recentemente" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:137 #, fuzzy msgid "Updated" msgstr "Atualizadas" #: src/bz-flathub-category.c:133 #, fuzzy msgid "More Updated" msgstr "Ver mais atualizadas recentemente" #: src/bz-flathub-category.c:134 msgid "Mobile" msgstr "Mobile" #: src/bz-flathub-category.c:134 #, fuzzy msgid "More Mobile" msgstr "Ver mais mobile" #: src/bz-flathub-category.c:135 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:135 #, fuzzy msgid "More Adwaita" msgstr "Ver mais adwaita" #: src/bz-flathub-category.c:136 msgid "KDE Apps" msgstr "Apps KDE" #: src/bz-flathub-category.c:136 #, fuzzy msgid "More KDE Apps" msgstr "Ver mais apps KDE" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "O repositório Flathub não foi adicionado" #: src/bz-flathub-page.blp:24 #, fuzzy msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "" "O repositório Flathub não foi encontrado em nenhuma das suas instalações " "Flatpak" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "O Flathub devolveu um erro" #: src/bz-flathub-page.blp:41 #, fuzzy msgid "Retry Flathub Connection" msgstr "Tentar novamente a conexão com o Flathub" #: src/bz-flathub-page.blp:57 #, fuzzy msgid "Flathub Unavailable" msgstr "Flathub não disponível" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" "Não foi possível conectar com o Flathub. Pode ainda assim gerir e pesquisar " "por aplicações." #: src/bz-flathub-page.blp:61 #, fuzzy msgid "Search Apps" msgstr "Pesquisar aplicações" #: src/bz-flathub-page.blp:270 #, fuzzy msgid "On the Go" msgstr "Fora de casa" #: src/bz-flathub-page.blp:282 msgid "Apps for your Linux phones and tablets" msgstr "Apps para o seu telemóvel e tablet Linux" #: src/bz-flathub-page.blp:293 src/bz-flathub-page.blp:328 #, fuzzy msgid "More Mobile Apps" msgstr "Mais apps mobile" #: src/bz-flathub-page.blp:388 msgid "We​ ♥​ Games" msgstr "Todos ♥ Jogos" #: src/bz-flathub-page.blp:401 msgid "Games and apps to run your favorite titles" msgstr "Jogos e apps para gerir e correr os seus jogos favoritos" #: src/bz-flathub-page.blp:435 #, fuzzy msgid "More Games" msgstr "Ver mais jogos" #: src/bz-full-view.blp:57 src/bz-installed-page.blp:74 #: src/bz-installed-page.blp:78 msgid "No Results" msgstr "Sem Resultados" #: src/bz-full-view.blp:58 msgid "Try a different search query" msgstr "Tente termos de pesquisa diferentes" #: src/bz-full-view.blp:64 src/bz-window.blp:193 msgid "Content" msgstr "Conteúdo" #: src/bz-full-view.blp:123 msgid "Installing .flatpak bundles is not yet supported" msgstr "A instalação de pacotes .flatpak ainda não é suportada." #: src/bz-full-view.blp:216 msgid "Support" msgstr "Apoiar" #: src/bz-full-view.blp:239 src/bz-full-view.blp:499 msgid "Open" msgstr "Abrir" #: src/bz-full-view.blp:252 src/bz-full-view.blp:472 #, fuzzy msgid "Download & Install Application" msgstr "Transferir e instalar a aplicação" #: src/bz-full-view.blp:267 #, fuzzy msgid "Uninstall Application" msgstr "Desinstalar a aplicação" #: src/bz-full-view.blp:282 src/bz-full-view.blp:514 msgid "Install Other Version" msgstr "Instalar outra versão" #: src/bz-full-view.blp:436 #, fuzzy msgid "Downloads/Month" msgstr "Transferências/Mês" #: src/bz-full-view.blp:533 msgid "Stopped Receiving Core Updates" msgstr "Deixou de receber atualizações base" #: src/bz-full-view.blp:547 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "Esta app usa um runtime (serviço de execução) que já não está a receber " "atualizações nem correções de segurança. Pode tornar-se perigoso a usar no " "futuro." #: src/bz-full-view.blp:636 #, fuzzy msgid "Trash Data" msgstr "Dados de utilizador" #: src/bz-full-view.blp:776 msgid "Tags:" msgstr "Etiquetas:" #: src/bz-full-view.c:235 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:242 #, c-format msgid "%.*fM" msgstr "%.*f M" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:249 #, c-format msgid "%.*fK" msgstr "%.*f mil" #: src/bz-full-view.c:259 #, c-format msgid "%d downloads in the last 30 days" msgstr "%d transferências nos últimos 30 dias" #: src/bz-full-view.c:271 src/bz-full-view.c:605 src/bz-full-view.c:622 msgid "N/A" msgstr "N/A" #. Translators: . #: src/bz-full-view.c:295 #, fuzzy msgid "Download" msgstr "Transferir" #: src/bz-full-view.c:315 #, fuzzy msgid "Size information unavailable" msgstr "Classificação etária não disponível" #: src/bz-full-view.c:318 #, fuzzy, c-format msgid "Download size of %s" msgstr "%s de tamanho da transferência" #: src/bz-full-view.c:351 msgid "All Ages" msgstr "Todas as idades" #: src/bz-full-view.c:363 msgid "Age rating information unavailable" msgstr "Classificação etária não disponível" #: src/bz-full-view.c:368 msgid "Suitable for all ages" msgstr "Adequado a todas as idades" #: src/bz-full-view.c:370 #, c-format msgid "Suitable for ages %d and up" msgstr "Adequado a %d anos ou acima" #: src/bz-full-view.c:403 src/bz-full-view.c:408 src/bz-full-view.c:436 #: src/bz-full-view.c:447 msgid "Unknown" msgstr "Desconhecido" #: src/bz-full-view.c:413 #, c-format msgid "Free software licensed under %s" msgstr "Software livre licenciado sob %s" #: src/bz-full-view.c:418 #, fuzzy msgid "Free software" msgstr "Software livre" #: src/bz-full-view.c:421 msgid "Proprietary Software" msgstr "Software proprietário" #: src/bz-full-view.c:424 #, c-format msgid "Special License: %s" msgstr "Licença Especial: %s" #: src/bz-full-view.c:441 msgid "Free" msgstr "Livre" #: src/bz-full-view.c:444 src/bz-license-dialog.c:132 msgid "Proprietary" msgstr "Proprietário" #: src/bz-full-view.c:449 src/bz-license-dialog.c:134 msgid "Special License" msgstr "Licença Especial" #: src/bz-full-view.c:469 msgid "Adaptive" msgstr "Adaptável" #: src/bz-full-view.c:469 msgid "Desktop Only" msgstr "Apenas computador" #: src/bz-full-view.c:475 msgid "Works on desktop, tablets, and phones" msgstr "Funciona em computador, tablets e telemóveis" #: src/bz-full-view.c:476 msgid "May not work on mobile devices" msgstr "Poderá não funcionar em telemóveis" #: src/bz-full-view.c:487 msgid "No URL" msgstr "Sem URL" #: src/bz-full-view.c:505 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Esta aplicação tem uma licença livre de código aberto (FOSS), o que " "significa que o código fonte pode ser auditável para verificações de " "segurança." #: src/bz-full-view.c:506 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Esta aplicação tem uma licença proprietária, o que significa que o código " "fonte é privado e não pode ser auditável nem verificado por terceiros." #: src/bz-full-view.c:513 #, fuzzy msgid "More Apps" msgstr "Mais apps" #: src/bz-full-view.c:514 #, fuzzy, c-format msgid "More Apps by %s" msgstr "Mais apps de %s" #: src/bz-full-view.c:521 msgid "Other Apps by this Developer" msgstr "Outras apps deste desenvolvedor" #: src/bz-full-view.c:523 src/bz-full-view.c:723 #, c-format msgid "Other Apps by %s" msgstr "Outras apps de %s" #: src/bz-full-view.c:532 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "%s não está instalado(a), mais ainda tem %s de dados presentes." #: src/bz-full-view.c:612 src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "Seguro" #: src/bz-full-view.c:614 src/bz-full-view.c:616 msgid "Low Risk" msgstr "Baixo Risco" #: src/bz-full-view.c:618 msgid "Medium Risk" msgstr "Médio Risco" #: src/bz-full-view.c:620 msgid "High Risk" msgstr "Alto Risco" #: src/bz-full-view.c:725 msgid "Other Apps" msgstr "Outras apps" #: src/bz-full-view.c:727 #, fuzzy, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d aplicação" msgstr[1] "%d aplicações" #: src/bz-full-view.c:1066 msgid "Show Less" msgstr "Mostrar menos" #: src/bz-full-view.c:1066 #, fuzzy msgid "Show More" msgstr "Mostrar mais" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 #, fuzzy msgid "Hardware Support" msgstr "Suporte de hardware" #: src/bz-hardware-support-dialog.c:62 #, fuzzy msgid "Keyboard support" msgstr "Suporte de teclado" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "Requer um teclado" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "Recomenda um teclado" #: src/bz-hardware-support-dialog.c:66 #, fuzzy msgid "Supports keyboards" msgstr "Suporta teclados" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "Suporte a teclados desconhecido" #: src/bz-hardware-support-dialog.c:69 #, fuzzy msgid "Mouse support" msgstr "Suporte a rato" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "Requer um rato ou dispositivo de apontar" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "Recomenda um rato ou dispostivo de apontar" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "Suporta ratos ou dispostivos de apontar" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "Suporte a ratos ou dispostivos de apontar desconhecido" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "Suporte a ecrã táctil" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "Requer ecrã táctil" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "Recomenda ecrã táctil" #: src/bz-hardware-support-dialog.c:80 #, fuzzy msgid "Supports touchscreens" msgstr "Suporta ecrãs tácteis" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "Suporte a ecrãs tácteis desconhecido" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "Suporte a dispositivos móveis" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "Funciona em todos os dispositivos móveis" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "Pode não funcionar perfeitamente em alguns dispositivos móveis" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "Suporte a computador desktop" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "Funciona bem em ecrãs grandes" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "%s funciona melhor em hardware específico" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "%s funciona bem na maior parte dos dispositivos" #: src/bz-installed-page.blp:28 #, fuzzy msgid "Search installed apps" msgstr "Ver as aplicações instaladas" #: src/bz-installed-page.blp:67 #, fuzzy msgid "No Apps Found" msgstr "Não foram encontradas aplicações" #: src/bz-installed-page.c:157 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "Sem resultados para \"%s\" na lista de apps instaladas" #: src/bz-installed-tile.blp:61 src/bz-rich-app-tile.blp:136 #, fuzzy msgid "Stopped Receiving Updates" msgstr "A transferir itens" #: src/bz-license-dialog.blp:95 msgid "Get Involved" msgstr "Envolver-se" #: src/bz-license-dialog.c:126 #, fuzzy msgid "Unknown License" msgstr "Licença desconhecida" #: src/bz-license-dialog.c:129 msgid "Community Built" msgstr "Feito pela comunidade" #: src/bz-license-dialog.c:202 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Esta app é desenvolvida em código aberto por uma comunidade internacional de " "desenvolvedores e apoiantes como você.\n" "\n" "Poderá participar e ajudar a tornar esta app ainda melhor." #: src/bz-license-dialog.c:205 msgid "The license of this app is not known" msgstr "A licença desta app não é conhecida" #: src/bz-license-dialog.c:211 #, fuzzy, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Esta app é desenvolvida em código aberto por uma comunidade internacional de " "desenvolvedores e apoiantes como você, e publicada sob a licença %s.\n" "\n" "Poderá participar e ajudar a tornar esta app ainda melhor." #: src/bz-license-dialog.c:219 #, fuzzy msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Esta app não é desenvolvida com o código aberto, pelo que apenas os seus " "desenvolvedores têm acesso à forma como a mesma funciona. Isto pode ser " "inseguro em certas formas difíceis de detectar, e o funcionamento pode mudar " "sem aviso prévio.\n" "\n" "Poderá ou não conseguir contribuir para o desenvolvimento desta app." #: src/bz-license-dialog.c:225 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Esta app foi desenvolvida sub a licença especial %s.\n" "\n" "Poderá ou não conseguir contribuir para o desenvolvimento desta app." #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 #, fuzzy msgid "Connect to Flathub" msgstr "Navegar pelo Flathub" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "Algo correu mal" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "" "Conecte a sua conta Flathub ao Bazaar para gerir as suas apps favoritas." #: src/bz-login-page.blp:108 msgid "Finish" msgstr "Terminar" #: src/bz-login-page.c:663 #, c-format msgid "Hello, %s!" msgstr "Olá, %s!" #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Definições" #: src/bz-preferences-dialog.blp:25 msgid "Network connection is metered — automatic store data sync is paused" msgstr "" "A conexão de internet atual está definida como limitada - a sincronização " "automática de dados da loja foi pausada" #: src/bz-preferences-dialog.blp:26 src/bz-window.blp:494 msgid "Sync Manually" msgstr "Sincronizar manualmente" #: src/bz-preferences-dialog.blp:31 #, fuzzy msgid "Content Filters" msgstr "Filtragem de Conteúdo" #: src/bz-preferences-dialog.blp:34 msgid "Free Software Only" msgstr "Apenas software livre" #: src/bz-preferences-dialog.blp:35 #, fuzzy msgid "Hide proprietary applications when browsing and searching" msgstr "Ocultar software proprietário dos resultados de pesquisa" #: src/bz-preferences-dialog.blp:39 msgid "Flathub Results Only" msgstr "Apenas resultados do Flathub" #: src/bz-preferences-dialog.blp:40 #, fuzzy msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "Limitar a pesquisa e navegação apenas a apps disponíveis no Flathub" #: src/bz-preferences-dialog.blp:44 #, fuzzy msgid "Verified Results Only" msgstr "Apenas apps verificadas do Flathub" #: src/bz-preferences-dialog.blp:45 #, fuzzy msgid "Hide results that are not verified on Flathub" msgstr "Excluir da pesquisa resultados que não sejam do Flathub" #: src/bz-preferences-dialog.blp:49 msgid "Hide EOL Apps" msgstr "Ocultar apps em fim de vida (EOL)" #: src/bz-preferences-dialog.blp:50 msgid "Hide apps which are no longer supported by their developers" msgstr "" "Ocultar apps que já não estejam a receber suporte dos seus desenvolvedores" #: src/bz-preferences-dialog.blp:55 src/bz-window.blp:314 msgid "Search" msgstr "Pesquisar" #: src/bz-preferences-dialog.blp:58 msgid "Delay Search Results" msgstr "Atrasar resultados de pesquisa" #: src/bz-preferences-dialog.blp:59 msgid "Improve results performance by debouncing search terms" msgstr "" "Melhorar o desempenho da lista de resultados ao atrasar a entrada de texto " "da pesquisa" #: src/bz-preferences-dialog.blp:64 msgid "Progress Bar" msgstr "Barra de progresso" #: src/bz-preferences-dialog.blp:65 msgid "Choose a theme for the progress bar!" msgstr "Escolha um tema para a barra de progresso" #: src/bz-preferences-dialog.blp:89 msgid "Vertical Stripes" msgstr "Riscas Verticais" #: src/bz-preferences-dialog.blp:90 msgid "Display flag colors from left to right" msgstr "Mostrar as cores das bandeiras da esquerda para a direita" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Cor de destaque" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:35 msgid "Male Homosexual Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:36 msgid "Transgender Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:37 msgid "Nonbinary Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:38 msgid "Bisexual Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:39 msgid "Asexual Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:40 msgid "Pansexual Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:41 msgid "Aromantic Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:42 msgid "Genderfluid Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:43 msgid "Polysexual Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:44 msgid "Omnisexual Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:45 msgid "Aroace Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:46 msgid "Agender Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:47 msgid "Genderqueer Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:48 msgid "Intersex Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:49 msgid "Demigender Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:50 msgid "Biromantic Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:51 msgid "Disability Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:52 msgid "Femboy Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:53 msgid "Neutrois Pride Colors" msgstr "" #: src/bz-releases-dialog.blp:5 src/bz-releases-list.blp:28 msgid "Version History" msgstr "Histórico de versões" #: src/bz-releases-list.c:136 #, c-format msgid "Version %s" msgstr "Versão %s" #: src/bz-releases-list.c:173 msgid "No details for this release" msgstr "Sem detalhes sobre esta versão" #: src/bz-releases-list.c:185 #, fuzzy msgid "Get More Information" msgstr "Obter mais informações" #: src/bz-rich-app-tile.blp:153 msgid "Get" msgstr "Obter" #: src/bz-safety-calculator.c:82 #, fuzzy msgid "Unknown Permissions" msgstr "Permissões Desconhecidas" #: src/bz-safety-calculator.c:83 msgid "Permissions are missing for this app." msgstr "As permissões estão em falta para esta app." #: src/bz-safety-calculator.c:96 #, fuzzy msgid "No Permissions" msgstr "Sem Permissões" #: src/bz-safety-calculator.c:97 msgid "App is fully sandboxed" msgstr "A app é completamente sandboxed (isolada do sistema)" #: src/bz-safety-calculator.c:103 msgid "Network Access" msgstr "Acesso à internet" #: src/bz-safety-calculator.c:104 msgid "Can access the internet" msgstr "Pode aceder à internet" #: src/bz-safety-calculator.c:106 msgid "No Network Access" msgstr "Sem acesso à internet" #: src/bz-safety-calculator.c:107 msgid "Cannot access the internet" msgstr "Não pode aceder à internet" #: src/bz-safety-calculator.c:112 msgid "User Device Access" msgstr "Acesso a dispositivos do utilizador" #: src/bz-safety-calculator.c:113 msgid "Can access devices such as webcams or gaming controllers" msgstr "Pode aceder a dispositivos como câmaras ou comandos de jogos" #: src/bz-safety-calculator.c:115 msgid "No User Device Access" msgstr "Sem acesso a dispositivos do utilizador" #: src/bz-safety-calculator.c:116 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "Não pode aceder a dispositivos como câmaras ou comandos de jogos" #: src/bz-safety-calculator.c:121 msgid "Input Device Access" msgstr "Acesso a dispositivos de introdução" #: src/bz-safety-calculator.c:122 msgid "Can access input devices" msgstr "Pode aceder a dispositivos de introdução como rato e teclado" #: src/bz-safety-calculator.c:128 msgid "Microphone Access and Audio Playback" msgstr "Acesso a microfone e reprodução de áudio" #: src/bz-safety-calculator.c:129 msgid "Can listen using microphones and play audio without asking permission" msgstr "Pode aceder a microfones e reproduzir som sem necessitar de permissão" #: src/bz-safety-calculator.c:135 msgid "System Device Access" msgstr "Acesso a dispositivos de sistema" #: src/bz-safety-calculator.c:136 msgid "Can access system devices which require elevated permissions" msgstr "" "Pode aceder a dispositivos de sistema que requeiram permissões elevadas" #: src/bz-safety-calculator.c:142 msgid "Screen Contents Access" msgstr "Acesso ao conteúdo do ecrã" #: src/bz-safety-calculator.c:143 msgid "Can access the contents of the screen or other windows" msgstr "Pode aceder ao conteúdo do ecrã ou de outras janelas" #: src/bz-safety-calculator.c:149 msgid "Legacy Windowing System" msgstr "Sistema de janelas antigo (legacy)" #: src/bz-safety-calculator.c:150 #, fuzzy msgid "Always uses a legacy windowing system (X11)" msgstr "Usa um sistema de janelas antigo (legacy)" #: src/bz-safety-calculator.c:156 #, fuzzy msgid "Arbitrary Permissions" msgstr "Permissões arbitrárias" #: src/bz-safety-calculator.c:157 msgid "Can acquire arbitrary permissions" msgstr "Pode obter permissões arbitrárias" #: src/bz-safety-calculator.c:163 msgid "User Settings" msgstr "Definições do utilizador" #: src/bz-safety-calculator.c:164 msgid "Can access and change user settings" msgstr "Pode aceder e alterar definições do utilizador" #: src/bz-safety-calculator.c:170 msgid "Full File System Read/Write Access" msgstr "Acesso completo de leitura e escrita ao sistema de ficheiros" #: src/bz-safety-calculator.c:171 msgid "Can read and write all data on the file system" msgstr "Pode aceder, alterar ou apagar quaisquer dados no sistema de ficheiros" #: src/bz-safety-calculator.c:178 msgid "Home Folder Read/Write Access" msgstr "Acesso de leitura/escrita à pasta pessoal (Home)" #: src/bz-safety-calculator.c:179 msgid "Can read and write all data in your home directory" msgstr "Pode aceder, alterar ou apagar quaisquer dados na pasta pessoal" #: src/bz-safety-calculator.c:186 msgid "Full File System Read Access" msgstr "Acesso de leitura a todo o sistema" #: src/bz-safety-calculator.c:187 msgid "Can read all data on the file system" msgstr "" "Pode ler e aceder (mas não alterar/apagar) a quaisquer dados em qualquer " "parte do sistema de ficheiros" #: src/bz-safety-calculator.c:195 msgid "Home Folder Read Access" msgstr "Acesso de leitura à pasta pessoal (Home)" #: src/bz-safety-calculator.c:196 msgid "Can read all data in your home directory" msgstr "" "Pode ler e aceder (mas não alterar/apagar) a quaisquer dados na pasta " "pessoal do seu utilizador" #: src/bz-safety-calculator.c:204 msgid "Download Folder Read/Write Access" msgstr "Acesso completo de leitura/escrita à pasta Transferências" #: src/bz-safety-calculator.c:205 msgid "Can read and write all data in your downloads directory" msgstr "" "Pode aceder, alterar ou apagar quaisquer dados na sua pasta Transferências" #: src/bz-safety-calculator.c:215 msgid "Download Folder Read Access" msgstr "Acesso de leitura à pasta Transferências" #: src/bz-safety-calculator.c:216 msgid "Can read all data in your downloads directory" msgstr "" "Pode ler e aceder (mas não alterar/apagar) a quaisquer dados na sua pasta " "Transferências" #: src/bz-safety-calculator.c:229 msgid "Can read and write all data in the directory" msgstr "" "Pode aceder, alterar ou apagar quaisquer dados nesta pasta ou diretório" #: src/bz-safety-calculator.c:243 msgid "Can read all data in the directory" msgstr "" "Pode ler e aceder (mas não alterar/apagar) a quaisquer dados nesta pasta ou " "diretório" #: src/bz-safety-calculator.c:258 msgid "No File System Access" msgstr "Sem acesso completo ao sistema de ficheiros" #: src/bz-safety-calculator.c:259 msgid "Cannot access the file system at all" msgstr "Não pode aceder de todo ao sistema de ficheiros" #: src/bz-safety-calculator.c:266 msgid "Uses System Services" msgstr "Usa serviços de sistema" #: src/bz-safety-calculator.c:267 msgid "Can request data from non-portal system services" msgstr "Pode pedir dados para serviços de sistema fora do portal" #: src/bz-safety-calculator.c:273 msgid "Uses Session Services" msgstr "Usa serviços de sessão" #: src/bz-safety-calculator.c:274 msgid "Can request data from non-portal session services" msgstr "Pode pedir dados para serviços de sessão fora do portal" #: src/bz-safety-calculator.c:322 msgid "No Service Access" msgstr "Sem acesso a serviços" #: src/bz-safety-calculator.c:323 msgid "Cannot access non-portal session or system services at all" msgstr "" "Não pode de todo aceder a serviços fora do portal sejam de sistema ou de " "sessão" #: src/bz-safety-calculator.c:331 #, fuzzy msgid "Verified App Developer" msgstr "" "Este flatpak foi verificado pelos desenvolvedores originais do software." #: src/bz-safety-calculator.c:332 msgid "The developer of this app has been verified to be who they say they are" msgstr "O desenvolvedor desta app foi verificado como sendo quem realmente diz" #: src/bz-safety-calculator.c:341 #, fuzzy msgid "Proprietary Code" msgstr "Código Proprietário" #: src/bz-safety-calculator.c:342 msgid "" "The source code is not public, so it cannot be independently audited and " "might be unsafe" msgstr "" "O código-fonte não é público, pelo que não pode ser verificado nem testado " "por terceiros e poderá ser inseguro" #: src/bz-safety-calculator.c:352 msgid "Auditable Code" msgstr "Código-fonte auditável" #: src/bz-safety-calculator.c:353 msgid "" "The source code is public and can be independently audited, which makes the " "app more likely to be safe" msgstr "" "Este código-fonte é público e pode ser testado e verificado de forma " "independente o que ajuda a verificar se esta app é segura" #: src/bz-safety-calculator.c:493 #, c-format msgid "Use the %s System Service" msgstr "Usa o serviço de sistema %s" #: src/bz-safety-calculator.c:497 #, c-format msgid "Use the %s Session Service" msgstr "Usa o serviço de sessão %s" #: src/bz-safety-calculator.c:501 #, c-format msgid "Use the %s Service" msgstr "Usa o serviço %s" #: src/bz-safety-calculator.c:511 msgid "Can see the non-portal service" msgstr "Pode ver o serviço fora do portal" #: src/bz-safety-calculator.c:513 msgid "Can talk to the non-portal service" msgstr "Pode comunicar com o serviço fora do portal" #: src/bz-safety-calculator.c:515 msgid "Can own the non-portal service" msgstr "Pode ser proprietário do serviço fora do portal" #: src/bz-safety-calculator.c:530 #, fuzzy msgid "Global Menu Integration" msgstr "Integração com o menu global" #: src/bz-safety-calculator.c:531 msgid "Can display its menus in a global menu bar" msgstr "Pode mostrar os seus próprios menus na barra de menu global" #: src/bz-safety-calculator.c:536 msgid "KDE Settings Integration" msgstr "Integração com as definições do KDE" #: src/bz-safety-calculator.c:537 msgid "Can detect when KDE desktop settings change" msgstr "Pode detectar quando definições do KDE são alteradas" #: src/bz-safety-calculator.c:542 msgid "KDE Global Settings" msgstr "Definições globais do KDE" #: src/bz-safety-calculator.c:543 msgid "Can read KDE desktop preferences like fonts and colors" msgstr "Pode ler personalizações do KDE como fontes ou tema de cores" #: src/bz-safety-calculator.c:548 #, fuzzy msgid "Secret Storage Service" msgstr "Serviço de armazenamento secreto" #: src/bz-safety-calculator.c:549 msgid "Can store and retrieve its own passwords using the system keyring" msgstr "Pode guardar e obter as suas próprias passwords através do chaveiro do sistema" #: src/bz-safety-calculator.c:554 msgid "Desktop Notifications Service" msgstr "Notificações do ambiente de trabalho" #: src/bz-safety-calculator.c:555 msgid "Can send desktop notifications" msgstr "Pode enviar notificações de ambiente de trabalho" #: src/bz-safety-calculator.c:561 msgid "System Tray Integration" msgstr "Integração com a barra de estado" #: src/bz-safety-calculator.c:562 msgid "Can display an icon in the system tray" msgstr "Pode mostrar um ícone na barra de estado" #: src/bz-safety-calculator.c:567 msgid "KDE Connect Integration" msgstr "Integração KDE Connect" #: src/bz-safety-calculator.c:568 msgid "Can interact with devices paired via KDE Connect" msgstr "Pode interagir com dispositivos via KDE Connect" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "Segurança" #: src/bz-safety-dialog.blp:50 msgid "Details" msgstr "Detalhes" #: src/bz-safety-dialog.blp:53 msgid "License" msgstr "Licença" #: src/bz-safety-dialog.blp:63 msgid "App ID" msgstr "ID da app" #: src/bz-safety-dialog.blp:73 msgid "SDK" msgstr "SDK" #: src/bz-safety-dialog.blp:101 msgid "" "This app uses an outdated version of the software platform (SDK) and might " "contain bugs or security vulnerabilities which will not be fixed." msgstr "" "Esta app usa uma versão de software de desenvolvimento (SDK) desatualizada e " "pode por isso conter problemas ou vulnerabilidades de segurança que nunca " "serão resolvidas." #: src/bz-safety-dialog.c:227 #, c-format msgid "%s is Safe" msgstr "%s é seguro(a)" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s has no Unsafe Permissions" msgstr "%s tem permissões inseguras" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Probably Safe" msgstr "%s é provavelmente seguro(a)" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Possibly Unsafe" msgstr "%s poderá ser inseguro(a)" #: src/bz-safety-dialog.c:247 #, c-format msgid "%s is Unsafe" msgstr "%s é inseguro(a)" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "Capturas de ecrã" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "Captura anterior" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "Captura seguinte" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "Copiar imagem" #: src/bz-screenshot-page.blp:147 msgid "Reset View" msgstr "Redefinir vista" #: src/bz-screenshot-page.blp:158 msgid "Zoom Out" msgstr "Afastar o zoom" #: src/bz-screenshot-page.blp:168 msgid "Zoom In" msgstr "Aproximar o zoom" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "Carrossel de capturas de ecrã" #: src/bz-screenshots-carousel.blp:103 msgid "Open Screenshot Viewer" msgstr "Abrir o visualizador de capturas de ecrã" #: src/bz-search-widget.blp:57 msgid "Search Apps, Games, Software" msgstr "Procure apps, jogos e software" #: src/bz-search-widget.blp:96 #, fuzzy msgid "Categories Unavailable" msgstr "Categorias não disponíveis" #: src/bz-search-widget.blp:97 msgid "Search for apps using the search bar above." msgstr "Pesquise por apps usando a barra de pesquisa acima." #: src/bz-search-widget.blp:181 #, fuzzy msgid "No Applications Found" msgstr "Não foram encontradas aplicações" #: src/bz-search-widget.c:241 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "Sem resultados para \"%s\" no Flathub" #: src/bz-share-list.c:64 msgid "Copied!" msgstr "Copiado!" #: src/bz-share-list.c:116 #, fuzzy msgid "Copy Link" msgstr "Copiar a ligação" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Abrir a ligação" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "Linha do tempo" #: src/bz-stats-dialog.blp:46 #, fuzzy msgid "Installs:" msgstr "Instalações:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "Mundo" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:124 #, c-format msgid "%.2fM Total Installs" msgstr "%.2f milhões de instalações totais" #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:127 #, c-format msgid "%.2fK Total Installs" msgstr "%.2f mil instalações totais" #: src/bz-stats-dialog.c:129 #, c-format msgid "%'d Total Installs" msgstr "%'d instalações totais" #: src/bz-tag-list.c:96 #, fuzzy msgid "No Results Found" msgstr "Sem Resultados" #: src/bz-tag-list.c:108 #, c-format msgid "Apps Tagged \"%s\"" msgstr "Apps etiquetadas com \"%s\"" #: src/bz-tag-list.c:124 #, fuzzy msgid "Search failed" msgstr "A pesquisa falhou" #: src/bz-transaction-dialog.c:166 msgid "Keep Data" msgstr "Manter dados" #: src/bz-transaction-dialog.c:167 msgid "Allow restoring settings and content" msgstr "Permitir o restauro de definições e conteúdo" #: src/bz-transaction-dialog.c:176 msgid "Delete Data" msgstr "Apagar dados" #: src/bz-transaction-dialog.c:177 msgid "Permanently remove app data to save space" msgstr "Remover permanentemente todos os dados da app para poupar espaço" #: src/bz-transaction-dialog.c:202 #, fuzzy, c-format msgid "Install %s?" msgstr "Instalar %s ?" #: src/bz-transaction-dialog.c:207 #, fuzzy msgid "" "Select which version to install. May install additional shared components" msgstr "Poderá instalar componentes adicionais" #: src/bz-transaction-dialog.c:209 msgid "May install additional shared components" msgstr "Poderá instalar componentes adicionais" #: src/bz-transaction-dialog.c:230 #, fuzzy, c-format msgid "Remove %s?" msgstr "Remover %s ?" #: src/bz-transaction-dialog.c:233 msgid "Select which version to remove." msgstr "Selecione qual versão a remover." #: src/bz-transaction-dialog.c:235 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "Não será mais possível usar %s após ser desinstalado(a)." #: src/bz-transaction-dialog.c:258 #, c-format msgid "“%s” is High Risk" msgstr "“%s” é de alto risco" #: src/bz-transaction-dialog.c:262 msgid "" "This app has full access to your system, including all your files, " "browser history, saved passwords, and more. It also has access to the " "internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Esta app tem acesso completo de leitura e escrita ao sistema, incluindo " "todos os seus ficheiros, históricos, passes guardadas, e muito mais. " "Também tem acesso à internet, pelo que poderá enviar estes e quaisquer dados " "para terceiros.\n" "\n" "Por a app ser proprietária de código fechado, não se pode verificar o que é " "que a mesma faz com estas permissões e estes dados." #: src/bz-transaction-dialog.c:271 #, fuzzy msgid "" "This app uses the legacy X11 windowing system, which allows it to record " "all keystrokes, capture screenshots, and monitor other applications. It " "also has access to the internet, meaning it could send your data to outside " "parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Esta app tem acesso completo de leitura e escrita ao sistema, incluindo " "todos os seus ficheiros, históricos, passes guardadas, e muito mais. " "Também tem acesso à internet, pelo que poderá enviar estes e quaisquer dados " "para terceiros.\n" "\n" "Por a app ser proprietária de código fechado, não se pode verificar o que é " "que a mesma faz com estas permissões e estes dados." #: src/bz-transaction-dialog.c:287 #, fuzzy msgid "Install Anyway" msgstr "Instalar mesmo assim" #: src/bz-transaction-dialog.c:566 msgid "All apps are already installed" msgstr "As apps já estão todas instaladas" #: src/bz-transaction-dialog.c:568 msgid "OK" msgstr "OK" #: src/bz-transaction-dialog.c:584 #, fuzzy, c-format msgid "Install %u App?" msgid_plural "Install %u Apps?" msgstr[0] "Instalar %s ?" msgstr[1] "Instalar %s ?" #: src/bz-transaction-dialog.c:592 msgid "" "The following will be installed. Additional shared components may also be " "installed" msgstr "Os seguintes itens serão instalados. Componentes partilhados adicionais " "também poderão ser instalados, conforme necessário." #: src/bz-transaction-dialog.c:593 #, c-format msgid "%d addons will be installed." msgstr "%d extensão(ões) será(ão) instalada(s)." #: src/bz-transaction-dialog.c:594 #, fuzzy msgid "Additionally, addons will be installed." msgstr "" "%d serviços de execução (runtimes) e/ou extensões relacionados(as) também " "serão atualizados(as)." #: src/bz-transaction-manager.c:1150 #, c-format msgid "Finished in %.02f seconds" msgstr "Concluído em %.02f segundos" #: src/bz-transaction-view.blp:95 msgid "App Add-on" msgstr "Extras da app" #: src/bz-transaction-view.blp:120 msgid "Runtime" msgstr "Serviço de execução (Runtime)" #: src/bz-transaction-view.blp:146 src/bz-transaction-view.blp:172 #, fuzzy msgid "Install Size" msgstr "Tamanho da instalação" #: src/bz-transaction-view.blp:187 src/bz-transaction-view.blp:238 #: src/bz-transaction-view.blp:264 src/bz-transaction.c:342 msgid "Pending" msgstr "Pendente" #: src/bz-transaction-view.blp:199 msgid "Ongoing" msgstr "Em andamento" #: src/bz-transaction-view.blp:212 msgid "Finished" msgstr "Terminado" #: src/bz-transaction-view.blp:251 msgid "Update" msgstr "Atualizar" #: src/bz-transaction-view.c:135 #, c-format msgid "Transferred %s so far" msgstr "%s transferidos até agora" #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "Gerir Dados Obsoletos(as)" #: src/bz-user-data-page.blp:55 msgid "No User Data found" msgstr "Não foram encontrados dados de utilizador" #: src/bz-user-data-page.blp:60 msgid "User Data" msgstr "Dados de utilizador" #: src/bz-user-data-tile.c:144 #, fuzzy, c-format msgid "Trashed User Data for %s" msgstr "Removido os dados de utilizador de %s" #: src/bz-user-data-tile.blp:74 #, fuzzy msgid "Trash User Data" msgstr "Dados de utilizador" #: src/bz-window.blp:107 msgid "Tasks" msgstr "Tarefas" #: src/bz-window.blp:163 msgid "Stop Active Tasks" msgstr "Parar as tarefas ativas" #: src/bz-window.blp:171 msgid "Clear History" msgstr "Limpar o histórico de tarefas" #: src/bz-window.blp:187 msgid "No Tasks Yet" msgstr "Ainda sem tarefas" #: src/bz-window.blp:257 #, fuzzy msgid "Refreshing Store Content" msgstr "Recarregar o conteúdo da loja" #: src/bz-window.blp:273 msgid "Curated" msgstr "Recomendadas" #: src/bz-window.blp:286 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:435 msgid "No background tasks!" msgstr "Sem tarefas de fundo!" #: src/bz-window.blp:493 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "" "Tem uma conexão à internet ativa mas está a ver uma versão anterior em cache " "do Flathub" #: src/bz-window.blp:568 #, fuzzy msgid "_Login with Flathub" msgstr "_Entrar com uma conta no Flathub" #: src/bz-window.blp:574 msgid "_Manage Leftover User Data" msgstr "_Gerir dados deixados para trás" #: src/bz-window.blp:579 msgid "_Synchronize Remotes" msgstr "_Sincronizar os repositórios" #: src/bz-window.blp:620 msgid "Log Out" msgstr "Terminar sessão" #: src/bz-window.c:440 #, fuzzy, c-format msgid "%d Update Available" msgid_plural "%d Updates Available" msgstr[0] "%d atualização disponível" msgstr[1] "%d atualizações disponíveis" #: src/bz-window.c:734 msgid "You can't remove Bazaar from Bazaar!" msgstr "Não pode remover o Bazaar pelo Bazaar!" #: src/bz-window.c:871 msgid "Updates Are Available" msgstr "Estão Disponíveis Atualizações" #: src/bz-window.c:872 msgid "" "The following applications are eligible for updates. Would you like to " "install them?" msgstr "" "As seguintes aplicações têm atualizações disponíveis. Deseja instalá-las " "agora?" #: src/bz-window.c:873 #, c-format msgid "" "%d runtimes and/or addons are eligible for updates. Would you like to " "install them?" msgstr "" "Existe(m) %d serviços de execução (runtimes) e/ou extensões com atualizações " "disponíveis. Deseja atualizá-los(as) agora?" #: src/bz-window.c:874 #, c-format msgid "Additionally, %d runtimes and/or addons will be updated." msgstr "" "%d serviços de execução (runtimes) e/ou extensões relacionados(as) também " "serão atualizados(as)." #: src/bz-window.c:876 #, fuzzy msgid "Update Now" msgstr "Atualizar agora" #: src/bz-window.c:1036 src/bz-window.c:1086 msgid "Can't do that right now!" msgstr "Não é possível fazer isso neste momento!" #: src/bz-window.c:1161 msgid "Resume Current Tasks" msgstr "Retomar as tarefas atuais" #: src/bz-window.c:1167 msgid "Pause Current Tasks" msgstr "Pausar as tarefas atuais" #: src/bz-world-map.c:587 #, fuzzy msgid "Downloads" msgstr "Transferir" #: src/gtk/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Geral" #: src/gtk/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "Abrir a Janela de Pesquisa" #: src/gtk/shortcuts-dialog.blp:14 #, fuzzy msgctxt "shortcut window" msgid "Open Preferences" msgstr "Abrir as definições" #: src/gtk/shortcuts-dialog.blp:19 msgctxt "shortcut window" msgid "Synchronize Remotes" msgstr "Sincronizar os repositórios" #: src/gtk/shortcuts-dialog.blp:24 msgctxt "shortcut window" msgid "Toggle Transaction Manager" msgstr "Alternar o Gestor de Transações" #: src/gtk/shortcuts-dialog.blp:29 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Mostrar os Atalhos" #: src/gtk/shortcuts-dialog.blp:34 msgctxt "shortcut window" msgid "Quit" msgstr "Sair" #~ msgid "Hide EOL Entries" #~ msgstr "Ocultar apps em fim de vida (EOL)" #~ msgid "Hide EOL entries and entries depending on them" #~ msgstr "Ocultar apps em fim de vida (EOL) e items que dependam destas" #~ msgid "Only Show Free Software" #~ msgstr "Mostrar apenas software livre" #, fuzzy #~ msgid "Hide proprietary software" #~ msgstr "Ocultar software proprietário" #~ msgid "Show Only Flathub Content" #~ msgstr "Mostrar apenas conteúdo do Flathub" #, fuzzy #~ msgid "Hide applications which do not originate from Flathub" #~ msgstr "Ocultar apps que não sejam do Flathub" #, fuzzy #~ msgid "Show Only Verified Content" #~ msgstr "Mostrar apenas apps verificadas" #~ msgid "Hide applications which are not verified on Flathub" #~ msgstr "Ocultar apps que não estejam verificadas no Flathub" #~ msgid "Debounce Search Inputs" #~ msgstr "Suavizar a entrar de texto na pesquisa" #, fuzzy #~ msgid "Add a delay before searching to prevent instant replies while typing" #~ msgstr "Atrasar a entrada de texto para evitar resultados instantâneos" #~ msgid "Global Progress Bar Theme" #~ msgstr "Tema da barra de progresso global" #~ msgid "Describes the look of the global progress bar" #~ msgstr "Descreve o aspeto da barra de progresso global" #~ msgid "Saved Window Dimensions" #~ msgstr "Guardar dimensões da janela" #~ msgid "The window dimensions to be used by the next Bazaar window" #~ msgstr "As dimensões a serem usadas por novas janelas do Bazaar" #~ msgid "?" #~ msgstr "?" #~ msgid "" #~ "This functionality is currently disabled. It is recommended you download " #~ "and install Flatseal to manage app permissions." #~ msgstr "" #~ "Esta funcionalidade está atualmente desativada. É recomendado que " #~ "transfira e instale a aplicação Flatseal para gerir as permissões das " #~ "aplicações Flatpak." #~ msgid "Entry Inspector" #~ msgstr "Inspetor de Itens" #~ msgid "Serialize" #~ msgstr "Serializar" #~ msgid "Convert to JSON" #~ msgstr "Converter para JSON" #~ msgid "More Mobile apps" #~ msgstr "Mais apps mobile" #, fuzzy #~ msgctxt "Project URL Type" #~ msgid "Flathub Page" #~ msgstr "Página do Flathub" #, fuzzy #~ msgctxt "Project URL Type" #~ msgid "Project Website" #~ msgstr "Página do Projeto" #~ msgctxt "Project URL Type" #~ msgid "Issue Tracker" #~ msgstr "Issue Tracker" #~ msgctxt "Project URL Type" #~ msgid "FAQ" #~ msgstr "Perguntas Frequentes (FAQ)" #~ msgctxt "Project URL Type" #~ msgid "Help" #~ msgstr "Ajuda" #~ msgctxt "Project URL Type" #~ msgid "Donate" #~ msgstr "Donativos" #~ msgctxt "Project URL Type" #~ msgid "Translate" #~ msgstr "Traduções" #, fuzzy #~ msgctxt "Project URL Type" #~ msgid "Contact" #~ msgstr "Contacto" #~ msgctxt "Project URL Type" #~ msgid "Source Code" #~ msgstr "Código-fonte" #~ msgctxt "Project URL Type" #~ msgid "Contribute" #~ msgstr "Contruibuir" #~ msgid "Size" #~ msgstr "Tamanho" #~ msgid "Bazaar Inspector" #~ msgstr "Inspector do Bazaar" #~ msgid "Background Task Info:" #~ msgstr "Info da tarefa em plano de fundo:" #~ msgid "Enable Global Debug Mode" #~ msgstr "Ligar o Modo de Depuração Global" #~ msgid "Active Blocklists" #~ msgstr "Listas de bloqueio ativas" #~ msgid "Active Curated-Configs" #~ msgstr "Configurações ativas de recomendações de apps" #~ msgid "All Entry Groups" #~ msgstr "Todos os grupos de itens" #~ msgid "Filter..." #~ msgstr "Filtrar..." #~ msgid "Decache and Inspect" #~ msgstr "Retirar da cache e inspeccionar" #~ msgid "No Flatpaks Installed" #~ msgstr "Não Existem Flatpaks Instalados" #~ msgid "Connect with Flathub" #~ msgstr "Conectar com o Flathub" #, fuzzy #~ msgid "Remove User Data" #~ msgstr "Remover os dados de utilizador" #~ msgid "Inspect UI Entry" #~ msgstr "Inspecionar o item de UI" #~ msgid "All Debug Actions" #~ msgstr "Todas as ações de depuração" #, fuzzy #~ msgid "Open Bazaar Inspector" #~ msgstr "Abrir o inspector do Bazaar" #~ msgid "" #~ "The ability to inspect and install local .flatpak bundle files is coming " #~ "soon! In the meantime, try running\n" #~ "\n" #~ "flatpak install --bundle your-bundle.flatpak\n" #~ "\n" #~ "on the command line." #~ msgstr "" #~ "A funcionalidade de verificar e instalar ficheiros/conjuntos .flatpak " #~ "está a caminho! Enquanto não está disponível, experimente executar o " #~ "comando\n" #~ "\n" #~ "flatpak install --bundle .flatpak\n" #~ "\n" #~ "a partir do terminal." #, c-format #~ msgid "%s: %'u downloads" #~ msgstr "%s: %'u transferências" #~ msgid "Show Git Forge Star Counts" #~ msgstr "Ver o total de estrelas do Git Forge" #~ msgid "" #~ "Whether to attempt to detect and show \"star counts\" for projects in the " #~ "full view" #~ msgstr "" #~ "Tentar detectar e mostrar a contagem de estrelas para projetos na vista " #~ "completa" #~ msgid "Hide proprietary software when searching" #~ msgstr "Ocultar software proprietário ao pesquisar" #~ msgid "Filter search results to only show applications available on Flathub" #~ msgstr "" #~ "Mostrar apenas resultados de pesquisa para aplicações disponíveis no " #~ "Flathub" #~ msgid "Of the size of human DNA" #~ msgstr "Do tamanho do ADN humano" #~ msgid "3 billion base pairs" #~ msgstr "3 mil milhões de pares-base" #~ msgid "Of the Linux Kernel" #~ msgstr "Do Kernel do Linux" #~ msgid "Of the Apollo 11 guidance computer" #~ msgstr "Do computador guia Apollo 11" #~ msgid "Total ROM and RAM" #~ msgstr "Memória ROM e RAM total" #~ msgid "Of the original Super Mario Bros" #~ msgstr "Do Super Mario Bros original" #~ msgid "On the NES" #~ msgstr "Na consola NES" #~ msgid "Of the size of Wikipedia" #~ msgstr "Do tamanho da Wikipedia" #~ msgid "Without any media" #~ msgstr "Sem nenhuma multimédia" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Ahmed Najmawi" #~ msgstr "Ahmed Najmawi" #~ msgctxt "About Dialog Translator Credit" #~ msgid "AtomHare" #~ msgstr "AtomHare" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Azenyr" #~ msgstr "Eduardo Correia (Azenyr)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Jill Fiore (Lumaeris)" #~ msgstr "Jill Fiore" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Lucosec" #~ msgstr "Lucosec" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Shihfu Juan" #~ msgstr "Shihfu Juan" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Vlastimil Dědek" #~ msgstr "Vlastimil Dědek" #~ msgctxt "About Dialog Translator Credit" #~ msgid "asen23" #~ msgstr "asen23" #~ msgctxt "About Dialog Translator Credit" #~ msgid "renner" #~ msgstr "renner" #~ msgctxt "About Dialog Translator Credit" #~ msgid "robotta" #~ msgstr "robotta" #~ msgid "Constructing Flatpak instance..." #~ msgstr "A construir a instância Flatpak..." #~ msgid "Reusing last Flatpak instance..." #~ msgstr "A reutilizar a última instância Flatpak..." #~ msgid "Flathub is not registered on this system" #~ msgstr "O Flathub não está configurado neste sistema" #~ msgid "" #~ "Would you like to add Flathub as a remote? If you decline, the Flathub " #~ "page will not be available. You can change this later." #~ msgstr "" #~ "Gostaria de adicionar o repositório Flathub a este sistema? Se recusar, a " #~ "página do Flathub ficará indisponível. Pode alterar esta escolha mais " #~ "tarde." #~ msgid "Add Flathub" #~ msgstr "Adicionar o Flathub" #, c-format #~ msgid "Identifying installed entries..." #~ msgstr "A identificar conteúdo instalado..." #, c-format #~ msgid "" #~ "Beginning remote entry retrieval while referencing %d blocklist(s)..." #~ msgstr "" #~ "A iniciar a obtenção de dados dos repositórios enquanto se referencia %d " #~ "lista(s) de bloqueio..." #, c-format #~ msgid "%'d of %'d" #~ msgstr "%'d de %'d" #, c-format #~ msgid "Waiting for background indexing tasks to catch up..." #~ msgstr "" #~ "A esperar que as tarefas de indexação a decorrer de fundo avancem..." #, c-format #~ msgid "Completed initialization in %0.2f seconds" #~ msgstr "Inicialização terminada em %0.2f segundos" #~ msgid "Repository Star Count" #~ msgstr "Contagem de estrelas do repositório" #, c-format #~ msgid "%.2f M" #~ msgstr "%.2f M" #, c-format #~ msgid "%.2f K" #~ msgstr "%.2f K" #~ msgid "Run this application" #~ msgstr "Executar a aplicação" #~ msgid "Run" #~ msgstr "Executar" #~ msgid "View Store Page" #~ msgstr "Ver a página na loja" #~ msgid "Application Details" #~ msgstr "Detalhes da aplicação" #~ msgid "Display Star Count" #~ msgstr "Mostrar a contagem de estrelas" #~ msgid "Show the star count of an application's source code repository" #~ msgstr "Mostrar o total de estrelas do repositório do código da aplicação" #~ msgid "" #~ "Bazaar can fetch and display the star count from an application's source " #~ "code repository on a remote Git forge. \n" #~ " For projects on GitHub, rate limits may cause them not to appear." #~ msgstr "" #~ "O Bazaar pode obter e mostrar a contagem de estrelas do respetivo " #~ "repositório Git de código fonte de uma aplicação. \n" #~ "Para projetos do Github, poderão ser aplicados limites de pedidos pelo " #~ "mesmo que poderão fazer com que as estrelas deixem de aparecer " #~ "temporariamente." #~ msgctxt "shortcut window" #~ msgid "Refresh" #~ msgstr "Recarregar" #~ msgid "Show Animated Background" #~ msgstr "Mostrar Imagem de Fundo Animada" #~ msgid "Whether to show the animated icon background on the home page" #~ msgstr "Mostrar o ícone de imagem de fundo animada na página inicial" #~ msgid "Calligraphy application page" #~ msgstr "Página da aplicação Calligraphy" #~ msgid "Download graph for Blender" #~ msgstr "Gráfico de transferências para o Blender" #, c-format #~ msgid "Received %'d entries out of %'d (%0.1f seconds elapsed)" #~ msgstr "" #~ "Foram recebidos %'d itens de um total de %'d (%0.1f segundos decorridos)" #~ msgid "" #~ "Bazaar was not provided a curated content configuration. Contact your " #~ "operating system's support channels for assistance." #~ msgstr "" #~ "O Bazaar não tem uma definição para conteúdo recomendado. Contacte os " #~ "canais de suporte do seu sistema operativo para mais ajuda. " #~ msgid "Apps Of The Week" #~ msgstr "Aplicações da Semana" #~ msgid "" #~ "The number of downloads in the last 30 days. Click to view this " #~ "application's download statistics." #~ msgstr "" #~ "Número de transferências dos últimos 30 dias. Clique para ver as " #~ "estatísticas desta aplicação." #~ msgid "Remote repo name" #~ msgstr "Nome do repositório remoto" #, c-format #~ msgid "Released %x" #~ msgstr "Lançado a %x" #~ msgid "How the application looks" #~ msgstr "A aparência da aplicação" #~ msgid "Appearance" #~ msgstr "Aparência" #~ msgid "Show animated background" #~ msgstr "Mostrar imagem de fundo animada" #~ msgid "Type to filter" #~ msgstr "Escreva para procurar" #~ msgid "Exclude results with proprietary licenses" #~ msgstr "Excluir da pesquisa resultados com licenças proprietárias" #~ msgid "Advanced" #~ msgstr "Avançado" #~ msgid "Share" #~ msgstr "Partilhar" #~ msgid "Open this link externally" #~ msgstr "Abrir a ligação externamente" #~ msgid "Downloads Over Time" #~ msgstr "Transferências ao Longo do Tempo" #~ msgid "Minimize Lower Bound" #~ msgstr "Minimizar o limite inferior" #~ msgid "Maximize Upper Bound" #~ msgstr "Maximizar o limite superior" #~ msgid "Installing" #~ msgstr "A Instalar" #~ msgid "Removing" #~ msgstr "A Remover" #~ msgid "Transactions Will Appear Here" #~ msgstr "As Transações Irão Aparecer Aqui" #~ msgid "Halt the execution of transactions" #~ msgstr "Interromper a execução das transações" #~ msgid "Clear all finished transactions" #~ msgstr "Limpar as transações finalizadas" #~ msgid "Browse" #~ msgstr "Explorar" #~ msgid "App View" #~ msgstr "Vista de Aplicação" #~ msgid "Go Back" #~ msgstr "Voltar" #~ msgid "View the latest on Flathub" #~ msgstr "Ver as novidades do Flathub" #~ msgid "Up to date!" #~ msgstr "Atualizado!" #~ msgid "Confirm Action" #~ msgstr "Confirmar Ação" #, c-format #~ msgid "" #~ "You are about to remove the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "Irá a remover a seguinte aplicação Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Deseja continuar?" #, c-format #~ msgid "" #~ "You are about to install the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "Irá instalar a seguinte aplicação Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Deseja continuar?" #~ msgid "Resume the execution of transactions" #~ msgstr "Retomar a execução das transações" #~ msgid "Pause the execution of transactions" #~ msgstr "Colocar a execução das transações em pausa" #~ msgid "Keep the summary shorter, between 10 and 35 characters" #~ msgstr "Mantenha o resumo curto, entre 10 e 35 caracteres" #~ msgid "Main Bazaar window showing Blender" #~ msgstr "Janela principal do Bazaar a mostrar o Blender" #~ msgid "Match using regular expressions" #~ msgstr "Corresponder através de expressões regulares" #~ msgid "Hide filtering and sorting behind a crossfade effect" #~ msgstr "" #~ "Ocultar filtragem e ordenação através de um efeito visual de transição " #~ "crossfade" bazaar-orig-v0.7.14/po/nl.po0000664000175000017500000021105015166123241014526 0ustar hasanhasan# Dutch translations for bazaar package. # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # #: src/bz-installed-page.blp:68 msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-01-10 20:06+0100\n" "PO-Revision-Date: 2025-07-15 07:56+0200\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:5 #: src/bz-window.blp:233 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "" "Voeg flatpak software toe, verwijder deze of update deze op deze computer" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;Systeem;Pakketbeheer;Ontdekken;Flatpak;Software;Winkel;" #: data/io.github.kolunmi.Bazaar.desktop.in:15 msgid "New Window" msgstr "Nieuw Venster" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and install applications" msgstr "Ontdek en installeer applicaties" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A new app store for Linux with a focus on discovering and installing " "applications and addons from Flatpak remotes, particularly Flathub." msgstr "" "Een nieuwe appstore voor GNOME, gericht op het ontdekken en installeren van " "applicaties en add-ons van Flatpak bronnen, vooral Flathub." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:14 msgid "" "It emphasizes supporting the developers who make the Linux desktop possible. " "Bazaar features a \"curated\" tab that can be configured by distributors to " "allow for a more localized experience." msgstr "" "Het legt de nadruk op het ondersteunen van de ontwikkelaars die de Linux " "desktop mogelijk maken. Bazaar heeft een \"gecureerde\" tab die door " "distributeurs kan worden aangepast voor een meer gelokaliseerde ervaring." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:29 src/bz-application.c:697 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:54 msgid "The home page displaying Flathub apps" msgstr "Het startscherm dat Flathub apps weergeeft" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:58 msgid "Nucleus app page" msgstr "Nucleus apppagina" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:62 msgid "Search page" msgstr "Zoekpagina" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:66 msgid "Category page" msgstr "Categoriepagina" #: src/bz-addons-dialog.blp:14 src/bz-full-view.blp:694 #: src/bz-installed-tile.blp:99 msgid "Manage Add-ons" msgstr "Beheer Addons" #: src/bz-addons-dialog.c:90 src/bz-full-view.blp:482 #: src/bz-installed-tile.blp:117 src/bz-transaction-dialog.c:224 #: src/bz-transaction-view.blp:277 msgid "Remove" msgstr "Verwijder" #: src/bz-addons-dialog.c:95 src/bz-favorites-tile.c:166 #: src/bz-full-view.blp:249 src/bz-full-view.blp:469 #: src/bz-transaction-dialog.c:201 src/bz-transaction-view.blp:225 msgid "Install" msgstr "Installeren" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 #: src/bz-age-rating-dialog.c:726 src/bz-full-view.c:409 src/bz-full-view.c:416 msgid "Age Rating" msgstr "Leeftijdsadvies" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "Stripgeweld" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "Geen informatie over stripgeweld" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "Fantasiegeweld" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "Geen informatie over fantasiegeweld" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "Realistisch geweld" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "Geen informatie over realistisch geweld" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "Geweld met bloedvergieten" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "Geen informatie over geweld met bloedvergieten" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "Seksueel geweld" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "Geen informatie over seksueel geweld" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "Alcohol" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "Geen informatie over verwijzingen naar alcohol" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "Drugs" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "Geen informatie over verwijzingen naar illegale drugs" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "Tabak" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "Geen informatie over verwijzingen naar tabaksproducten" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "Naaktheid" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "Geen informatie over enige naaktheid" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "Seksuele thema’s" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "Geen informatie over seksueel verwijzingen of afbeeldingen" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "Grof Taalgebruik" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "Geen informatie over grof taalgebruik" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "Ongepaste humor" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "Geen informatie over ongepaste humor" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "Discriminatie" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "Geen informatie over discriminerend taalgebruik" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "Reclame" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "Geen informatie over enige reclame" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "Gokken" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "Geen informatie over gokken" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "Aankopen" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "Geen informatie over de mogelijkheid om echt geld uit te geven" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "Gesprekken tussen gebruikers" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "Geen informatie over mogelijkheden om met andere gebruikers te chatten" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "Audiogesprekken tussen gebruikers" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "Geen informatie over mogelijkheden om met andere gebruikers te praten" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 msgid "Contact Details" msgstr "Contactgegevens" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "" "Geen informatie over het delen van gebruikersnamen van sociale netwerken of " "e-mailadressen" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "Identificerende informatie" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "Geen informatie over het delen van gebruikersinformatie met derden" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "Locatie delen" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "" "Geen informatie over het delen van de fysieke locatie met andere gebruikers" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "Prostitutie" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "Geen informatie over verwijzingen naar prostitutie" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "Overspel" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "Geen informatie over verwijzingen naar overspel" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "Geseksualiseerde personages" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "Geen informatie over geseksualiseerde personages" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 msgid "Desecration" msgstr "Heiligschennis" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "Geen informatie over verwijzingen naar heiligschennis" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "Menselijke overblijfselen" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "Geen informatie over zichtbare overblijfselen van dode mensen" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "Slavernij" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "Geen informatie over verwijzingen naar slavernij" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "Bevat geen verwijzingen naar drugs" #: src/bz-age-rating-dialog.c:426 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "Bevat geen scheldwoorden of ander grof taalgebruik" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "Bevat geen reclame of monetaire transacties" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "Bevat geen seks of naaktheid" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "" "Bevat geen niet-gecontroleerde gespreksfunctionaliteit tussen gebruikers" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "Bevat geen geweld" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "Drugs" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "Grof taalgebruik" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "Geld" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "Sociaal" #: src/bz-age-rating-dialog.c:479 msgid "Violence" msgstr "Geweld" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:676 src/bz-full-view.c:399 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:701 msgctxt "Age rating" msgid "All" msgstr "Alle" #: src/bz-age-rating-dialog.c:737 #, c-format msgid "%s has an unknown age rating" msgstr "%s heeft een onbekende leeftijdsclassificatie" #: src/bz-age-rating-dialog.c:743 #, c-format msgid "%s is suitable for everyone" msgstr "%s is geschikt voor iedereen" #: src/bz-age-rating-dialog.c:746 #, c-format msgid "%s is suitable for young children" msgstr "%s is geschikt voor jonge kinderen" #: src/bz-age-rating-dialog.c:749 #, c-format msgid "%s is suitable for children" msgstr "%s is geschikt voor kinderen" #: src/bz-age-rating-dialog.c:752 #, c-format msgid "%s is suitable for teenagers" msgstr "%s is geschikt voor tieners" #: src/bz-age-rating-dialog.c:755 #, c-format msgid "%s is suitable for adults" msgstr "%s is geschikt voor volwassenen" #: src/bz-age-rating-dialog.c:758 #, c-format msgid "%s is suitable for %s" msgstr "%s is geschikt voor %s" #: src/bz-age-rating-dialog.c:849 #, c-format msgid "%s • %s" msgstr "%s • %s" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:43 #: src/bz-user-data-page.blp:15 src/bz-window.blp:480 msgid "Main Menu" msgstr "Hoofdmenu" #: src/bz-all-apps-page.blp:17 src/bz-apps-page.blp:17 #: src/bz-user-data-page.blp:18 src/bz-window.blp:553 msgid "_Donate to Bazaar ❤️" msgstr "_Doneer aan Bazaar ❤️" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 #: src/bz-user-data-page.blp:19 msgid "_Refresh Content" msgstr "_Inhoud verversen" #: src/bz-all-apps-page.blp:22 src/bz-apps-page.blp:22 #: src/bz-user-data-page.blp:22 src/bz-window.blp:560 msgid "_Preferences" msgstr "_Voorkeuren" #: src/bz-all-apps-page.blp:23 src/bz-apps-page.blp:23 #: src/bz-user-data-page.blp:23 src/bz-window.blp:581 msgid "_Keyboard Shortcuts" msgstr "_Snelkoppelingen Toetsenbord" #: src/bz-all-apps-page.blp:24 src/bz-apps-page.blp:24 #: src/bz-user-data-page.blp:24 src/bz-window.blp:586 msgid "_About Bazaar" msgstr "_Over Bazaar" #: src/bz-all-apps-page.blp:28 src/bz-apps-page.blp:28 #: src/bz-user-data-page.blp:27 src/bz-window.blp:593 msgid "_Quit Bazaar" msgstr "_Sluit Bazaar" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "Systeemmap %s" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "Home submap %s" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "Systeemmappen van host" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "Systeemconfiguratie van host in /etc" #: src/bz-app-permissions.c:169 #, c-format msgid "Desktop subfolder %s" msgstr "Bureaublad-submap %s" #: src/bz-app-permissions.c:170 msgid "Desktop folder" msgstr "Bureaublad-map" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "Bureaublad-submap %s" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "Documenten-map" #: src/bz-app-permissions.c:177 #, c-format msgid "Music subfolder %s" msgstr "Muziek-submap %s" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "Muziek-map" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "Afbeeldingen-submap %s" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "Afbeeldingen-map" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "Openbaar-submap %s" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "Openbaar-map" #: src/bz-app-permissions.c:189 #, c-format msgid "Videos subfolder %s" msgstr "Video’s-submap %s" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "Video’s-map" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "Sjablonen-submap %s" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "Sjablonen-map" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "Cache-submap %s van gebruiker" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "Cachemap van gebruiker" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "Configuratie-submap %s van gebruiker" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "Configuratiemap van gebruiker" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "Gegevens-submap %s van gebruiker" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "Gegevensmap van gebruiker" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "Runtime-submap %s van gebruiker" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "Runtime-map van gebruiker" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "Toegang tot %s in bestandssysteem" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "Onbekend bestandspad" #: src/bz-app-size-dialog.blp:29 src/bz-app-size-dialog.blp:55 msgid "Download Size" msgstr "Download Grootte" #: src/bz-app-size-dialog.blp:56 msgid "Amount to download from the internet" msgstr "Te downloaden hoeveelheid van internet" #: src/bz-app-size-dialog.blp:76 msgid "Installed Size" msgstr "Geïnstalleerde Grootte" #: src/bz-app-size-dialog.blp:77 msgid "Size on Disk" msgstr "Grootte op schijf" #: src/bz-app-size-dialog.blp:99 msgid "User Data Size" msgstr "Grootte Gebruikersgegevens" #: src/bz-app-size-dialog.blp:100 msgid "Caches, settings, and other app data" msgstr "Caches, instellingen en andere app-data" #: src/bz-app-tile.blp:85 src/bz-full-view.c:363 src/bz-installed-page.blp:85 #: src/bz-window.blp:296 msgid "Installed" msgstr "Geïnstalleerd" #: src/bz-apps-page.blp:103 msgid "Show All" msgstr "Toon Alle" #: src/bz-apps-page.c:232 #, c-format msgid "All \"%s\"" msgstr "Alle \"%s\"" #: src/bz-apps-page.c:506 src/bz-tag-list.c:109 #, c-format msgid "%d Applications" msgstr "%d Applicaties" #: src/bz-application.c:668 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:669 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:700 msgid "translator-credits" msgstr "Alexander Vanhee, 2025" #: src/bz-application.c:711 msgid "Special Thanks" msgstr "Speciale Dank" #: src/bz-application.c:769 msgid "Logged Out Successfully!" msgstr "Succesvol Uitgelogd!" #: src/bz-application.c:896 msgid "Performing setup..." msgstr "Setup aan het uitvoeren..." #: src/bz-application.c:975 src/bz-application.c:984 msgid "Set Up Flathub" msgstr "Flathub instellen" #: src/bz-application.c:978 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub is niet ingesteld op dit systeem. Je kunt geen applicaties in Bazaar " "browsen en installeren als het niet beschikbaar is.\n" "\n" "Je kunt Bazaar nog steeds gebruiken om reeds geïnstalleerde apps te bekijken " "en verwijderen." #: src/bz-application.c:983 src/bz-update-dialog.blp:6 msgid "Later" msgstr "Later" #: src/bz-application.c:1385 src/bz-application.c:3059 msgid "Synchronizing..." msgstr "Synchroniseren..." #: src/bz-application.c:1524 src/bz-application.c:3055 #, c-format msgid "Receiving %d entries..." msgstr "%d items ontvangen..." #: src/bz-application.c:1529 msgid "Checking for updates" msgstr "Controleren op updates" #: src/bz-application.c:3061 msgid "Indexing Data..." msgstr "Gegevens aan het Indexeren..." #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:65 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:53 #: src/bz-installed-page.blp:63 src/bz-user-data-page.blp:52 #: src/bz-window.blp:183 msgid "Empty" msgstr "Leeg" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "Geen Gecureerde Apps" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "Er is geen curatie-info beschikbaar op dit systeem. Je kan nog steeds apps " "op Flathub bekijken" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "Naar Flathub" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "Offline" #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 msgid "Browser" msgstr "Browser" #: src/bz-developer-badge.c:131 msgid "Developer information not available." msgstr "Ontwikkelaarsinformatie niet beschikbaar." #: src/bz-developer-badge.c:137 src/bz-developer-badge.c:151 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "" "Het eigendom van de %s app-ID is niet geverifieerd en het kan een " "communitypakket zijn." #: src/bz-developer-badge.c:155 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "" "Het eigendom van de %s app-ID is handmatig geverifieerd door het Flathub-" "team." #: src/bz-developer-badge.c:161 #, c-format msgid "" "The ownership of the %1$s app ID has been verified by %2$s on " "%3$s." msgstr "" "Het eigendom van de %1$s app-ID is geverifieerd door %2$s op %3$s." #: src/bz-developer-badge.c:168 #, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "Het eigendom van de %1$s app-ID is geverifieerd met %2$s." #: src/bz-developer-badge.c:172 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "Het eigendom van de %s app-ID is geverifieerd." #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "Kies een Installatie" #: src/bz-entry-group-util.c:76 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "" "Je hebt meerdere versies van deze app geïnstalleerd. Welke wil je gebruiken?" #: src/bz-entry-group-util.c:80 src/bz-transaction-dialog.c:200 #: src/bz-transaction-dialog.c:223 src/bz-transaction-dialog.c:253 msgid "Cancel" msgstr "Annuleer" #: src/bz-error.c:68 msgid "An Error Occurred" msgstr "Er is een fout opgetreden" #: src/bz-error.c:89 msgid "Close" msgstr "Sluiten" #: src/bz-error.c:90 msgid "Copy and Close" msgstr "Kopieren en Sluiten" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "Log in met Flathub om favorieten te beheren" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "Log In" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "Aantal favorieten" #: src/bz-favorites-tile.c:164 msgid "Uninstall" msgstr "Verwijderen" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:75 msgid "Support this application" msgstr "Ondersteun deze applicatie" #: src/bz-favorites-tile.blp:118 msgid "Remove from Favorites" msgstr "Verwijder van Favorieten" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:75 #: src/bz-window.blp:611 msgid "Favorites" msgstr "Favorieten" #: src/bz-favorites-page.blp:22 src/bz-full-view.blp:20 src/bz-window.blp:126 #: src/bz-window.blp:457 msgid "Toggle transaction sidebar" msgstr "Schakel Transactie-zijbalk" #: src/bz-favorites-page.blp:53 src/bz-user-data-page.blp:41 msgid "Loading" msgstr "Laden" #: src/bz-favorites-page.blp:68 msgid "No Favorites" msgstr "Geen Favorieten" #: src/bz-favorites-page.blp:69 msgid "Applications you mark as favorite will appear here" msgstr "Applicaties die je als favoriet markeert verschijnen hier" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "Vorige" #: src/bz-featured-carousel.blp:53 msgid "Next" msgstr "Volgende" #: src/bz-featured-tile.blp:88 msgid "App of the Day" msgstr "App van de Dag" #: src/bz-flathub-category.c:79 msgid "Audio & Video" msgstr "Audio & Video" #: src/bz-flathub-category.c:79 msgid "Media" msgstr "Media" #: src/bz-flathub-category.c:79 msgid "More Audio & Video" msgstr "Meer Audio & Video" #: src/bz-flathub-category.c:80 msgid "Developer Tools" msgstr "Ontwikkeltools" #: src/bz-flathub-category.c:80 msgid "Develop" msgstr "Ontwikkel" #: src/bz-flathub-category.c:80 msgid "More Developer Tools" msgstr "Meer Ontwikkeltools" #: src/bz-flathub-category.c:81 msgid "Education" msgstr "Educatie" #: src/bz-flathub-category.c:81 msgid "Learn" msgstr "Leren" #: src/bz-flathub-category.c:81 msgid "More Education" msgstr "Meer Educatie" #: src/bz-flathub-category.c:82 msgid "Gaming" msgstr "Gaming" #: src/bz-flathub-category.c:82 msgid "Play" msgstr "Spelen" #: src/bz-flathub-category.c:82 msgid "More Gaming" msgstr "Meer Gaming" #: src/bz-flathub-category.c:83 msgid "Graphics & Photography" msgstr "Grafisch & Fotografie" #: src/bz-flathub-category.c:83 msgid "Create" msgstr "Creëren" #: src/bz-flathub-category.c:83 msgid "More Graphics & Photography" msgstr "Meer Grafisch & Fotografie" #: src/bz-flathub-category.c:84 msgid "Networking" msgstr "Netwerken" #: src/bz-flathub-category.c:84 msgid "Internet" msgstr "Internet" #: src/bz-flathub-category.c:84 msgid "More Networking" msgstr "Meer Netwerken" #: src/bz-flathub-category.c:85 msgid "Productivity" msgstr "Productiviteit" #: src/bz-flathub-category.c:85 msgid "Work" msgstr "Werk" #: src/bz-flathub-category.c:85 msgid "More Productivity" msgstr "Meer Productiviteit" #: src/bz-flathub-category.c:86 msgid "Science" msgstr "Wetenschap" #: src/bz-flathub-category.c:86 msgid "More Science" msgstr "Meer Wetenschap" #: src/bz-flathub-category.c:87 msgid "System" msgstr "Systeem" #: src/bz-flathub-category.c:87 msgid "More System" msgstr "Meer Systeem" #: src/bz-flathub-category.c:88 msgid "Utilities" msgstr "Tools" #: src/bz-flathub-category.c:88 msgid "Tools" msgstr "Tools" #: src/bz-flathub-category.c:88 msgid "More Utilities" msgstr "Meer Tools" #: src/bz-flathub-category.c:89 src/bz-flathub-page.blp:119 #: src/bz-flathub-page.blp:152 msgid "Trending" msgstr "Trending" #: src/bz-flathub-category.c:89 msgid "More Trending" msgstr "Meer Trending" #: src/bz-flathub-category.c:90 src/bz-flathub-page.blp:125 #: src/bz-flathub-page.blp:185 msgid "Popular" msgstr "Populair" #: src/bz-flathub-category.c:90 msgid "More Popular" msgstr "Meer Populair" #: src/bz-flathub-category.c:91 src/bz-flathub-page.blp:174 msgid "Recently Added" msgstr "Recent Toegevoegd" #: src/bz-flathub-category.c:91 src/bz-flathub-page.blp:131 msgid "New" msgstr "Nieuw" #: src/bz-flathub-category.c:91 msgid "More New" msgstr "Meer Niewe" #: src/bz-flathub-category.c:92 src/bz-flathub-page.blp:163 msgid "Recently Updated" msgstr "Onlangs Bijgewerkt" #: src/bz-flathub-category.c:92 src/bz-flathub-page.blp:137 msgid "Updated" msgstr "Bijgewerkt" #: src/bz-flathub-category.c:92 msgid "More Updated" msgstr "Meer Bijgewerkt" #: src/bz-flathub-category.c:93 msgid "Mobile" msgstr "Onderweg" #: src/bz-flathub-category.c:93 msgid "More Mobile" msgstr "Meer Onderweg" #: src/bz-flathub-category.c:94 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:94 msgid "More Adwaita" msgstr "Meer Adwaita" #: src/bz-flathub-category.c:95 msgid "KDE Apps" msgstr "KDE Apps" #: src/bz-flathub-category.c:95 msgid "More KDE Apps" msgstr "Meer KDE Apps" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Flathub Niet Toegevoegd" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "De Flathub remote is op geen van je Flatpak installaties teruggevonden" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "Flathub gaf een foutmelding" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "Flathub-verbinding opnieuw proberen" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Flathub Onbeschikbaar" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" "We konden geen verbinding maken met Flathub. Je kunt nog steeds applicaties " "beheren en zoeken." #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "Apps Zoeken" #: src/bz-flathub-page.blp:270 msgid "On the Go" msgstr "Onderweg" #: src/bz-flathub-page.blp:282 msgid "Apps for your Linux phones and tablets" msgstr "Apps voor je Linux telefoons en tablets" #: src/bz-flathub-page.blp:293 src/bz-flathub-page.blp:328 msgid "More Mobile Apps" msgstr "Meer Mobiele Apps" #: src/bz-flathub-page.blp:388 msgid "We​ ♥​ Games" msgstr "We​ ♥​ Games" #: src/bz-flathub-page.blp:401 msgid "Games and apps to run your favorite titles" msgstr "Games en apps om je favoriete titels te spelen" #: src/bz-flathub-page.blp:435 msgid "More Games" msgstr "Meer Gaming" #: src/bz-flatpak-entry.c:608 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Flathub Pagina" #: src/bz-flatpak-entry.c:629 msgctxt "Project URL Type" msgid "Project Website" msgstr "Projectwebsite" #: src/bz-flatpak-entry.c:633 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Probleemtracker" #: src/bz-flatpak-entry.c:637 msgctxt "Project URL Type" msgid "FAQ" msgstr "Veelgestelde Vragen" #: src/bz-flatpak-entry.c:641 msgctxt "Project URL Type" msgid "Help" msgstr "Hulp" #: src/bz-flatpak-entry.c:645 msgctxt "Project URL Type" msgid "Donate" msgstr "Doneer" #: src/bz-flatpak-entry.c:651 msgctxt "Project URL Type" msgid "Translate" msgstr "Vertalen" #: src/bz-flatpak-entry.c:655 msgctxt "Project URL Type" msgid "Contact" msgstr "Contact" #: src/bz-flatpak-entry.c:659 msgctxt "Project URL Type" msgid "Source Code" msgstr "Broncode" #: src/bz-flatpak-entry.c:665 msgctxt "Project URL Type" msgid "Contribute" msgstr "Brijdragen" #: src/bz-full-view.blp:57 src/bz-installed-page.blp:74 #: src/bz-installed-page.blp:78 msgid "No Results" msgstr "Geen Resultaten" #: src/bz-full-view.blp:58 msgid "Try a different search query" msgstr "Probeer een andere zoekterm" #: src/bz-full-view.blp:64 src/bz-window.blp:193 msgid "Content" msgstr "Content" #: src/bz-full-view.blp:210 msgid "Support" msgstr "Steunen" #: src/bz-full-view.blp:233 src/bz-full-view.blp:493 msgid "Open" msgstr "Openen" #: src/bz-full-view.blp:246 src/bz-full-view.blp:466 msgid "Download & Install Application" msgstr "App Downloaden & Uitvoeren" #: src/bz-full-view.blp:261 msgid "Uninstall Application" msgstr "Verwijder deze Applicatie" #: src/bz-full-view.blp:276 src/bz-full-view.blp:508 msgid "Install Other Version" msgstr "Installeer Andere Versie" #: src/bz-full-view.blp:430 msgid "Downloads /mo" msgstr "Downloads p/m" #: src/bz-full-view.blp:527 msgid "Stopped Receiving Core Updates" msgstr "Core-updates Gestopt" #: src/bz-full-view.blp:541 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "Deze app gebruikt een runtime die geen updates of beveiligingsfixes meer " "ontvangt. Het kan onveilig worden om te gebruiken." #: src/bz-full-view.blp:627 msgid "Trash Data" msgstr "Naar Prullenbak" #: src/bz-full-view.blp:761 msgid "Tags:" msgstr "Tags:" #: src/bz-full-view.c:307 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:314 #, c-format msgid "%.*fM" msgstr "%.*fM" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:321 #, c-format msgid "%.*fK" msgstr "%.*fK" #: src/bz-full-view.c:331 #, c-format msgid "%d downloads in the last 30 days" msgstr "%d downloads in de afgelopen 30 dagen" #: src/bz-full-view.c:363 msgid "Download" msgstr "Download" #: src/bz-full-view.c:381 #, c-format msgid "Download size of %s" msgstr "Downloadgrootte van %s" #: src/bz-full-view.c:414 msgid "All Ages" msgstr "Iedereen" #: src/bz-full-view.c:426 msgid "Age rating information unavailable" msgstr "Leeftijdsclassificatie niet beschikbaar" #: src/bz-full-view.c:431 msgid "Suitable for all ages" msgstr "Geschikt voor alle leeftijden" #: src/bz-full-view.c:433 #, c-format msgid "Suitable for ages %d and up" msgstr "Geschikt voor %d jarigen en ouder" #: src/bz-full-view.c:466 src/bz-full-view.c:471 src/bz-full-view.c:499 #: src/bz-full-view.c:510 msgid "Unknown" msgstr "Onbekend" #: src/bz-full-view.c:476 #, c-format msgid "Free software licensed under %s" msgstr "Vrije software gelicentieerd onder %s" #: src/bz-full-view.c:481 msgid "Free software" msgstr "Alleen Vrije Software" #: src/bz-full-view.c:484 msgid "Proprietary Software" msgstr "Propriëtaire Software" #: src/bz-full-view.c:487 #, c-format msgid "Special License: %s" msgstr "Speciale licentie: %s" #: src/bz-full-view.c:504 msgid "Free" msgstr "Vrij" #: src/bz-full-view.c:507 src/bz-license-dialog.c:190 msgid "Proprietary" msgstr "Propriëtair" #: src/bz-full-view.c:512 src/bz-license-dialog.c:192 msgid "Special License" msgstr "Speciale licentie" #: src/bz-full-view.c:532 msgid "Adaptive" msgstr "Adaptief" #: src/bz-full-view.c:532 msgid "Desktop Only" msgstr "Alleen Desktop" #: src/bz-full-view.c:538 msgid "Works on desktop, tablets, and phones" msgstr "Werkt op desktop, tablets en telefoons" #: src/bz-full-view.c:539 msgid "May not work on mobile devices" msgstr "Werkt mogelijk niet op mobiele apparaten" #: src/bz-full-view.c:550 msgid "No URL" msgstr "Geen URL" #: src/bz-full-view.c:568 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Deze applicatie heeft een FLOSS licentie, wat betekent dat de broncode " "gecontroleerd kan worden op veiligheid" #: src/bz-full-view.c:569 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Deze applicatie heeft een proprietary-licentie, wat betekent dat de broncode " "privé wordt ontwikkeld en niet gecontroleerd kan worden door een derde " "partij." #: src/bz-full-view.c:576 msgid "More Apps" msgstr "Meer Apps" #: src/bz-full-view.c:577 #, c-format msgid "More Apps by %s" msgstr "Andere Apps van %s" #: src/bz-full-view.c:584 msgid "Other Apps by this Developer" msgstr "Andere Apps van deze Ontwikkelaar" #: src/bz-full-view.c:586 src/bz-full-view.c:786 #, c-format msgid "Other Apps by %s" msgstr "Andere Apps van %s" #: src/bz-full-view.c:595 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "%s is niet geïnstalleerd, maar heeft nog %s aan gegevens." #: src/bz-full-view.c:668 src/bz-full-view.c:685 msgid "N/A" msgstr "N.b." #: src/bz-full-view.c:675 src/bz-full-view.c:677 src/bz-full-view.c:679 msgid "Low Risk" msgstr "Laag risico" #: src/bz-full-view.c:681 msgid "Medium Risk" msgstr "Gemiddeld risico" #: src/bz-full-view.c:683 msgid "High Risk" msgstr "Hoog risico" #: src/bz-full-view.c:788 msgid "Other Apps" msgstr "Andere Apps" #: src/bz-full-view.c:790 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d Applicatie" msgstr[1] "%d Applicaties" #: src/bz-full-view.c:1129 msgid "Show Less" msgstr "Minder Weergeven" #: src/bz-full-view.c:1129 msgid "Show More" msgstr "Meer Weergeven" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 msgid "Hardware Support" msgstr "Hardwareondersteuning" #: src/bz-hardware-support-dialog.c:62 msgid "Keyboard support" msgstr "Toetsenbordondersteuning" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "Vereist toetsenbord" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "Toetsenbord aanbevolen" #: src/bz-hardware-support-dialog.c:66 msgid "Supports keyboards" msgstr "Ondersteunt toetsenborden" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "Onbekende ondersteuning voor toetsenborden" #: src/bz-hardware-support-dialog.c:69 msgid "Mouse support" msgstr "Muisondersteuning" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "Vereist muis of aanwijzingsapparaat" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "Muis of aanwijzingsapparaat aanbevolen" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "Ondersteunt muis of aanwijzingsapparaten" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "Onbekende ondersteuning voor muis of aanwijzingsapparaten" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "Touchscreen-ondersteuning" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "Vereist touchscreen" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "Touchscreens aanbevolen" #: src/bz-hardware-support-dialog.c:80 msgid "Supports touchscreens" msgstr "Ondersteunt touchscreens" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "Onbekende ondersteuning voor touchscreens" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "Mobiele ondersteuning" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "Werkt op mobiele apparaten" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "Werkt mogelijk niet goed op mobiele apparaten" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "Desktopondersteuning" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "Werkt goed op grote schermen" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "%s werkt het beste op specifieke hardware" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "%s werkt op de meeste apparaten" #: src/bz-installed-page.blp:28 msgid "Search installed apps" msgstr "Doorzoek geïnstalleerde apps" #: src/bz-installed-page.blp:67 msgid "No Apps Found" msgstr "Geen Applicaties Gevonden" #: src/bz-installed-page.c:154 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "" "Geen resultaten gevonden voor \"%s\" in de lijst met geïnstalleerde apps" #: src/bz-installed-tile.blp:61 src/bz-rich-app-tile.blp:137 msgid "Stopped Receiving Updates" msgstr "Gestopt met ontvangen van updates" #: src/bz-license-dialog.blp:95 msgid "Get Involved" msgstr "Doe mee" #: src/bz-license-dialog.c:184 msgid "Unknown License" msgstr "Onbekende licentie" #: src/bz-license-dialog.c:187 msgid "Community Built" msgstr "Door Community Gebouwd" #: src/bz-license-dialog.c:235 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Deze app wordt openbaar ontwikkeld door een internationale gemeenschap.\n" "\n" "Je kunt dus deelnemen en helpen om de app nog beter te maken." #: src/bz-license-dialog.c:238 msgid "The license of this app is not known" msgstr "De licentie van deze app is niet bekend" #: src/bz-license-dialog.c:244 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Deze app wordt openbaar ontwikkeld door een internationale community en " "uitgebracht onder de %s licentie.\n" "\n" "Je kunt deelnemen en helpen om de app nog beter te maken." #: src/bz-license-dialog.c:252 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Deze app wordt niet openbaar ontwikkeld, dus alleen de ontwikkelaars weten " "hoe het werkt. De app kan op moeilijk te detecteren manieren onveilig zijn " "en kan zonder toezicht veranderen.\n" "\n" "Je kunt mogelijk niet bijdragen aan deze app." #: src/bz-license-dialog.c:258 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Deze app is ontwikkeld onder de speciale licentie %s.\n" "\n" "Je kunt mogelijk niet bijdragen aan deze app." #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 msgid "Connect to Flathub" msgstr "Verbind met Flathub" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "Er Ging Iets Mis" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "Verbind je Flathub-account met Bazaar om je favoriete apps te beheren." #: src/bz-login-page.blp:108 msgid "Finish" msgstr "Voltooi" #: src/bz-login-page.c:663 #, c-format msgid "Hello, %s!" msgstr "Hallo, %s!" #: src/bz-preferences-dialog.blp:20 msgid "Preferences" msgstr "Voorkeuren" #: src/bz-preferences-dialog.blp:26 msgid "Network connection is metered — automatic store data sync is paused" msgstr "" "Netwerkverbinding is gemeten — automatische synchronisatie van " "winkelgegevens is gepauzeerd" #: src/bz-preferences-dialog.blp:27 src/bz-window.blp:491 msgid "Sync Manually" msgstr "Handmatig synchroniseren" #: src/bz-preferences-dialog.blp:32 msgid "Content Filters" msgstr "Content Filters" #: src/bz-preferences-dialog.blp:35 msgid "Free Software Only" msgstr "Alleen Vrije Software" #: src/bz-preferences-dialog.blp:36 msgid "Hide proprietary applications when browsing and searching" msgstr "Verberg propriëtaire applicaties bij browsen en zoeken" #: src/bz-preferences-dialog.blp:40 msgid "Flathub Results Only" msgstr "Alleen Flathub Resultaten" #: src/bz-preferences-dialog.blp:41 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "" "Beperk zoek- en browseresultaten tot applicaties die alleen op Flathub " "beschikbaar zijn" #: src/bz-preferences-dialog.blp:45 msgid "Verified Results Only" msgstr "Alleen Geverifieerde Resultaten" #: src/bz-preferences-dialog.blp:46 msgid "Hide results that are not verified on Flathub" msgstr "Verberg resultaten die niet geverifieerd zijn op Flathub" #: src/bz-preferences-dialog.blp:50 msgid "Hide EOL Apps" msgstr "Verberg EOL-apps" #: src/bz-preferences-dialog.blp:51 msgid "Hide apps which are no longer supported by their developers" msgstr "Verberg apps die niet langer ondersteund worden door hun ontwikkelaars" #: src/bz-preferences-dialog.blp:56 src/bz-window.blp:311 msgid "Search" msgstr "Zoeken" #: src/bz-preferences-dialog.blp:59 msgid "Delay Search Results" msgstr "Vertraag Zoekresultaten" #: src/bz-preferences-dialog.blp:60 msgid "Improve results performance by debouncing search terms" msgstr "Verbeter zoekprestaties door zoektermen te debouncen" #: src/bz-preferences-dialog.blp:65 msgid "Progress Bar" msgstr "Voortgangsbalk" #: src/bz-preferences-dialog.blp:66 msgid "Choose a theme for the progress bar!" msgstr "Kies een thema voor de voortgangsbalk!" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Accentkleur" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Pride kleuren" #: src/bz-preferences-dialog.c:34 msgid "Pride Colors (Horizontal)" msgstr "Pride Kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:35 msgid "Lesbian Pride Colors" msgstr "Lesbische Pride kleuren" #: src/bz-preferences-dialog.c:36 msgid "Lesbian Pride Colors (Horizontal)" msgstr "Lesbische Pride kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:37 msgid "Male Homosexual Pride Colors" msgstr "Mannelijke Homoseksuele Pride Kleuren" #: src/bz-preferences-dialog.c:38 msgid "Male Homosexual Pride Colors (Horizontal)" msgstr "Mannelijke Homoseksuele Pride Kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:39 msgid "Transgender Pride Colors" msgstr "Transgender Pride Kleuren" #: src/bz-preferences-dialog.c:40 msgid "Transgender Pride Colors (Horizontal)" msgstr "Transgender Pride Kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:41 msgid "Nonbinary Pride Colors" msgstr "Nonbinaire Pride Kleuren" #: src/bz-preferences-dialog.c:42 msgid "Nonbinary Pride Colors (Horizontal)" msgstr "Nonbinaire Pride Kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:43 msgid "Bisexual Pride Colors" msgstr "Biseksuele Pride Kleuren" #: src/bz-preferences-dialog.c:44 msgid "Bisexual Pride Colors (Horizontal)" msgstr "Biseksuele Pride Kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:45 msgid "Asexual Pride Colors" msgstr "Aseksuele Pride Kleuren" #: src/bz-preferences-dialog.c:46 msgid "Asexual Pride Colors (Horizontal)" msgstr "Aseksuele Pride Kleuren (Horizontal)" #: src/bz-preferences-dialog.c:47 msgid "Pansexual Pride Colors" msgstr "Panseksuele Pride Kleuren" #: src/bz-preferences-dialog.c:48 msgid "Pansexual Pride Colors (Horizontal)" msgstr "Panseksuele Pride Kleuren (Horizontal)" #: src/bz-preferences-dialog.c:49 msgid "Aromantic Pride Colors" msgstr "Aromantische Pride Kleuren" #: src/bz-preferences-dialog.c:50 msgid "Aromantic Pride Colors (Horizontal)" msgstr "Aromantische Pride Kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:51 msgid "Genderfluid Pride Colors" msgstr "Genderfluïde Pride Kleuren" #: src/bz-preferences-dialog.c:52 msgid "Genderfluid Pride Colors (Horizontal)" msgstr "Genderfluïde Pride Kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:53 msgid "Polysexual Pride Colors" msgstr "Polyseksuele Pride Kleuren" #: src/bz-preferences-dialog.c:54 msgid "Polysexual Pride Colors (Horizontal)" msgstr "Polyseksuele Pride Kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:55 msgid "Omnisexual Pride Colors" msgstr "Omniseksuele Pride Kleuren" #: src/bz-preferences-dialog.c:56 msgid "Omnisexual Pride Colors (Horizontal)" msgstr "Omniseksuele Pride Kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:57 msgid "Aroace Pride Colors" msgstr "Aroace Pride Kleuren" #: src/bz-preferences-dialog.c:58 msgid "Aroace Pride Colors (Horizontal)" msgstr "Aroace Pride Kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:59 msgid "Agender Pride Colors" msgstr "Agender Pride Kleuren" #: src/bz-preferences-dialog.c:60 msgid "Agender Pride Colors (Horizontal)" msgstr "Agender Pride Kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:61 msgid "Genderqueer Pride Colors" msgstr "Genderqueer Pride Kleuren" #: src/bz-preferences-dialog.c:62 msgid "Genderqueer Pride Colors (Horizontal)" msgstr "Genderqueer Pride Kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:63 msgid "Intersex Pride Colors" msgstr "Intersekse Pride Kleuren" #: src/bz-preferences-dialog.c:64 msgid "Intersex Pride Colors (Horizontal)" msgstr "Intersekse Pride Kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:65 msgid "Demigender Pride Colors" msgstr "Demigender Pride Kleuren" #: src/bz-preferences-dialog.c:66 msgid "Demigender Pride Colors (Horizontal)" msgstr "Demigender Pride Kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:67 msgid "Biromantic Pride Colors" msgstr "Biromantische Pride Kleuren" #: src/bz-preferences-dialog.c:68 msgid "Biromantic Pride Colors (Horizontal)" msgstr "Biromantische Pride Kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:69 msgid "Disability Pride Colors" msgstr "Disability Pride Kleuren" #: src/bz-preferences-dialog.c:70 msgid "Disability Pride Colors (Horizontal)" msgstr "Disability Pride Kleuren (Horizontaal)" #: src/bz-preferences-dialog.c:71 msgid "Femboy Pride Colors" msgstr "Femboy Pride Kleuren" #: src/bz-preferences-dialog.c:72 msgid "Femboy Pride Colors (Horizontal)" msgstr "Femboy Pride Kleuren (Horizontaal)" #: src/bz-releases-dialog.blp:5 src/bz-releases-list.blp:27 msgid "Version History" msgstr "Versie Geschiedenis" #: src/bz-releases-list.c:136 #, c-format msgid "Version %s" msgstr "Versie %s" #: src/bz-releases-list.c:174 msgid "No details for this release" msgstr "Geen details voor deze versie" #: src/bz-releases-list.c:186 msgid "Get More Information" msgstr "Meer Informatie" #: src/bz-rich-app-tile.blp:154 msgid "Get" msgstr "Haal" #: src/bz-safety-calculator.c:77 msgid "Unknown Permissions" msgstr "Onbekende Machtigingen" #: src/bz-safety-calculator.c:78 msgid "Permissions are missing for this app." msgstr "Machtigingen ontbreken voor deze app." #: src/bz-safety-calculator.c:91 msgid "No Permissions" msgstr "Geen machtigingen" #: src/bz-safety-calculator.c:92 msgid "App is fully sandboxed" msgstr "Toepassing bevindt zich volledig in een zandbak" #: src/bz-safety-calculator.c:98 msgid "Network Access" msgstr "Netwerktoegang" #: src/bz-safety-calculator.c:99 msgid "Can access the internet" msgstr "Heeft toegang tot het internet" #: src/bz-safety-calculator.c:101 msgid "No Network Access" msgstr "Geen netwerktoegang" #: src/bz-safety-calculator.c:102 msgid "Cannot access the internet" msgstr "Heeft geen toegang tot het internet" #: src/bz-safety-calculator.c:107 msgid "User Device Access" msgstr "Gebruikerstoegang tot apparaat" #: src/bz-safety-calculator.c:108 msgid "Can access devices such as webcams or gaming controllers" msgstr "Kan toegang verkrijgen tot apparaten zoals webcams of spelcontrollers" #: src/bz-safety-calculator.c:110 msgid "No User Device Access" msgstr "Geen gebruikerstoegang tot apparaat" #: src/bz-safety-calculator.c:111 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "" "Kan geen toegang verkrijgen tot apparaten zoals webcams of spelcontrollers" #: src/bz-safety-calculator.c:116 msgid "Input Device Access" msgstr "Toegang tot invoerapparaten" #: src/bz-safety-calculator.c:117 msgid "Can access input devices" msgstr "Heeft toegang tot invoerapparaten" #: src/bz-safety-calculator.c:123 msgid "Microphone Access and Audio Playback" msgstr "Toegang tot microfoon en audio afspelen" #: src/bz-safety-calculator.c:124 msgid "Can listen using microphones and play audio without asking permission" msgstr "" "Kan naar microfoons luisteren en audio afspelen zonder toestemming te vragen" #: src/bz-safety-calculator.c:130 msgid "System Device Access" msgstr "Systeemtoegang tot apparaat" #: src/bz-safety-calculator.c:131 msgid "Can access system devices which require elevated permissions" msgstr "" "Kan naar microfoons luisteren en audio afspelen zonder toestemming te vragen" #: src/bz-safety-calculator.c:137 msgid "Screen Contents Access" msgstr "Toegang tot scherminhoud" #: src/bz-safety-calculator.c:138 msgid "Can access the contents of the screen or other windows" msgstr "Kan de inhoud van het scherm of andere vensters benaderen" #: src/bz-safety-calculator.c:144 msgid "Legacy Windowing System" msgstr "Verouderd venstersysteem" #: src/bz-safety-calculator.c:145 msgid "Uses a legacy windowing system" msgstr "Gebruikt een verouderd venstersysteem" #: src/bz-safety-calculator.c:151 msgid "Arbitrary Permissions" msgstr "Willekeurige toegangsrechten" #: src/bz-safety-calculator.c:152 msgid "Can acquire arbitrary permissions" msgstr "Kan willekeurige toegangsrechten verkrijgen" #: src/bz-safety-calculator.c:158 msgid "User Settings" msgstr "Gebruikersinstellingen" #: src/bz-safety-calculator.c:159 msgid "Can access and change user settings" msgstr "Heeft toegang tot gebruikersinstellingen en kan die wijzigen" #: src/bz-safety-calculator.c:165 msgid "Full File System Read/Write Access" msgstr "Lees- en schrijftoegang tot volledig bestandssysteem" #: src/bz-safety-calculator.c:166 msgid "Can read and write all data on the file system" msgstr "Kan alle gegevens op het bestandssysteem lezen en schrijven" #: src/bz-safety-calculator.c:173 msgid "Home Folder Read/Write Access" msgstr "Lees- en schrijftoegang tot home map" #: src/bz-safety-calculator.c:174 msgid "Can read and write all data in your home directory" msgstr "Kan alle gegevens in uw persoonlijke map lezen en schrijven" #: src/bz-safety-calculator.c:181 msgid "Full File System Read Access" msgstr "Leestoegang tot volledig bestandssysteem" #: src/bz-safety-calculator.c:182 msgid "Can read all data on the file system" msgstr "Kan alle gegevens op het bestandssysteem lezen" #: src/bz-safety-calculator.c:190 msgid "Home Folder Read Access" msgstr "Leestoegang tot home map" #: src/bz-safety-calculator.c:191 msgid "Can read all data in your home directory" msgstr "Kan alle gegevens in uw home map lezen" #: src/bz-safety-calculator.c:199 msgid "Download Folder Read/Write Access" msgstr "Lees- en schrijftoegang tot downloadmap" #: src/bz-safety-calculator.c:200 msgid "Can read and write all data in your downloads directory" msgstr "Kan alle gegevens in uw downloadmap lezen en schrijven" #: src/bz-safety-calculator.c:210 msgid "Download Folder Read Access" msgstr "Leestoegang tot downloadmap" #: src/bz-safety-calculator.c:211 msgid "Can read all data in your downloads directory" msgstr "Kan alle gegevens in uw downloadmap lezen" #: src/bz-safety-calculator.c:224 msgid "Can read and write all data in the directory" msgstr "Kan alle gegevens in de map lezen en schrijven" #: src/bz-safety-calculator.c:238 msgid "Can read all data in the directory" msgstr "Kan alle gegevens in de map lezen" #: src/bz-safety-calculator.c:253 msgid "No File System Access" msgstr "Geen toegang tot bestandssysteem" #: src/bz-safety-calculator.c:254 msgid "Cannot access the file system at all" msgstr "Heeft geen enkele toegang tot het bestandssysteem" #: src/bz-safety-calculator.c:261 msgid "Uses System Services" msgstr "Gebruikt systeemdiensten" #: src/bz-safety-calculator.c:262 msgid "Can request data from non-portal system services" msgstr "Kan gegevens opvragen van niet-portal-sessiediensten" #: src/bz-safety-calculator.c:268 msgid "Uses Session Services" msgstr "Gebruikt sessiediensten" #: src/bz-safety-calculator.c:269 msgid "Can request data from non-portal session services" msgstr "Kan gegevens opvragen van niet-portal-sessiediensten" #: src/bz-safety-calculator.c:294 msgid "No Service Access" msgstr "Geen diensttoegang" #: src/bz-safety-calculator.c:295 msgid "Cannot access non-portal session or system services at all" msgstr "Heeft geen enkele toegang tot niet-portal-sessie- of systeemdiensten" #: src/bz-safety-calculator.c:303 msgid "Verified App Developer" msgstr "Geverifieerde App-ontwikkelaar" #: src/bz-safety-calculator.c:304 msgid "The developer of this app has been verified to be who they say they are" msgstr "" "De ontwikkelaar van deze app is geverifieerd en is wie ze zeggen te zijn" #: src/bz-safety-calculator.c:313 msgid "Proprietary Code" msgstr "Propriëtaire Code" #: src/bz-safety-calculator.c:314 msgid "" "The source code is not public, so it cannot be independently audited and " "might be unsafe" msgstr "" "De broncode is niet publiek, dus kan niet onafhankelijk gecontroleerd worden " "en kan onveilig zijn" #: src/bz-safety-calculator.c:324 msgid "Auditable Code" msgstr "Controleerbare Code" #: src/bz-safety-calculator.c:325 msgid "" "The source code is public and can be independently audited, which makes the " "app more likely to be safe" msgstr "" "De broncode is publiek en kan onafhankelijk gecontroleerd worden, wat de app " "waarschijnlijk veiliger maakt" #: src/bz-safety-calculator.c:435 #, c-format msgid "Use the %s System Service" msgstr "Gebruikt de %s-systeemdienst" #: src/bz-safety-calculator.c:439 #, c-format msgid "Use the %s Session Service" msgstr "Gebruikt de %s-sessiedienst" #: src/bz-safety-calculator.c:443 #, c-format msgid "Use the %s Service" msgstr "Gebruikt de %s-dienst" #: src/bz-safety-calculator.c:453 msgid "Can see the non-portal service" msgstr "Kan de niet-portal-dienst zien" #: src/bz-safety-calculator.c:455 msgid "Can talk to the non-portal service" msgstr "Kan praten met de niet-portal-dienst" #: src/bz-safety-calculator.c:457 msgid "Can own the non-portal service" msgstr "Kan eigenaar zijn van de niet-portal-dienst" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "Veiligheid" #: src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "Veilig" #: src/bz-safety-dialog.blp:50 msgid "Details" msgstr "Gegevens" #: src/bz-safety-dialog.blp:53 msgid "License" msgstr "Licentie" #: src/bz-safety-dialog.blp:62 msgid "App ID" msgstr "App ID" #: src/bz-safety-dialog.blp:71 msgid "SDK" msgstr "SDK" #: src/bz-safety-dialog.blp:98 msgid "" "This app uses an outdated version of the software platform (SDK) and might " "contain bugs or security vulnerabilities which will not be fixed." msgstr "" "Deze app gebruikt een verouderde versie van het softwareplatform (SDK) en " "kan bugs of beveiligingskwetsbaarheden bevatten die niet zullen worden " "opgelost." #: src/bz-safety-dialog.c:222 #, c-format msgid "%s is Safe" msgstr "%s is veilig" #: src/bz-safety-dialog.c:227 #, c-format msgid "%s has no Unsafe Permissions" msgstr "%s geeft geen onveilige permissies" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s is Probably Safe" msgstr "%s is waarschijnlijk veilig" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Possibly Unsafe" msgstr "%s is mogelijk onveilig" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Unsafe" msgstr "%s is onveilig" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "Schermafbeeldingen" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "Vorige schermafbeelding" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "Volgende schermafbeelding" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "Afbeelding kopiëren" #: src/bz-screenshot-page.blp:147 msgid "Reset View" msgstr "Weergave resetten" #: src/bz-screenshot-page.blp:158 msgid "Zoom Out" msgstr "Uitzoomen" #: src/bz-screenshot-page.blp:168 msgid "Zoom In" msgstr "Inzoomen" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "Schermafbeeldingen carrousel" #: src/bz-screenshots-carousel.blp:103 msgid "Open Screenshot Viewer" msgstr "Schermafbeeldingsviewer openen" #: src/bz-search-widget.blp:107 msgid "Search Apps, Games, Software" msgstr "Zoek Apps, Games, Software" #: src/bz-search-widget.blp:146 msgid "Categories Unavailable" msgstr "Categorieën niet beschikbaar" #: src/bz-search-widget.blp:147 msgid "Search for apps using the search bar above." msgstr "Zoek naar apps met de zoekbalk hierboven." #: src/bz-search-widget.blp:231 msgid "No Applications Found" msgstr "Geen Applicaties Gevonden" #: src/bz-search-widget.c:241 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "Geen resultaten voor \"%s\" op Flathub" #: src/bz-share-list.c:64 msgid "Copied!" msgstr "Gekopieerd!" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "Kopieer Link" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Open Link" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "Tijdlijn" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "Installaties:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "Kaart" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:124 #, c-format msgid "%.2fM Total Installs" msgstr "%.2fM Totale Installaties" #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:127 #, c-format msgid "%.2fK Total Installs" msgstr "%.2fK Totale Installaties" #: src/bz-stats-dialog.c:129 #, c-format msgid "%'d Total Installs" msgstr "%'d Totale Installaties" #: src/bz-tag-list.c:96 msgid "No Results Found" msgstr "Geen Resultaten Gevonden" #: src/bz-tag-list.c:108 #, c-format msgid "Apps Tagged \"%s\"" msgstr "Apps getagd met \"%s\"" #: src/bz-tag-list.c:124 msgid "Search failed" msgstr "Zoeken mislukt" #: src/bz-transaction-dialog.c:159 msgid "Keep Data" msgstr "Gegevens behouden" #: src/bz-transaction-dialog.c:160 msgid "Allow restoring settings and content" msgstr "Herstel van instellingen en inhoud toestaan" #: src/bz-transaction-dialog.c:169 msgid "Delete Data" msgstr "Data Verwijderen" #: src/bz-transaction-dialog.c:170 msgid "Permanently remove app data to save space" msgstr "App-gegevens permanent verwijderen om ruimte te besparen" #: src/bz-transaction-dialog.c:194 #, c-format msgid "Install %s?" msgstr "%s Installeren?" #: src/bz-transaction-dialog.c:197 msgid "May install additional shared components" msgstr "Kan extra gedeelde componenten installeren" #: src/bz-transaction-dialog.c:216 #, c-format msgid "Remove %s?" msgstr "%s Verwijderen?" #: src/bz-transaction-dialog.c:220 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "Het zal niet mogelijk zijn om %s te gebruiken na deïnstallatie." #: src/bz-transaction-dialog.c:239 #, c-format msgid "“%s” is High Risk" msgstr "“%s” is Hoog Risico" #: src/bz-transaction-dialog.c:240 msgid "" "This app has full access to your system, including all your files, " "browser history, saved passwords, and more. It also has access to the " "internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Deze app heeft volledige toegang tot je systeem, inclusief al je " "bestanden, browsergeschiedenis, opgeslagen wachtwoorden en meer. Het " "heeft ook toegang tot internet, wat betekent dat het je gegevens naar " "externe partijen kan versturen.\n" "\n" "Omdat de app propriëtair is, kan het ook niet gecontroleerd worden wat het " "doet met deze machtigingen." #: src/bz-transaction-dialog.c:254 msgid "Install Anyway" msgstr "Installeer Toch" #: src/bz-transaction-manager.c:1148 #, c-format msgid "Finished in %.02f seconds" msgstr "Geslaagd in %.02f seconden" #: src/bz-transaction-view.blp:95 msgid "App Add-on" msgstr "App Add-on" #: src/bz-transaction-view.blp:120 msgid "Runtime" msgstr "Runtime" #: src/bz-transaction-view.blp:146 src/bz-transaction-view.blp:172 msgid "Install Size" msgstr "Geïnstalleerde Grootte" #: src/bz-transaction-view.blp:187 src/bz-transaction-view.blp:238 #: src/bz-transaction-view.blp:264 src/bz-transaction.c:342 msgid "Pending" msgstr "In Afwachting" #: src/bz-transaction-view.blp:199 msgid "Ongoing" msgstr "Bezig" #: src/bz-transaction-view.blp:212 msgid "Finished" msgstr "Voltooid" #: src/bz-transaction-view.blp:251 msgid "Update" msgstr "Update" #: src/bz-transaction-view.c:135 #, c-format msgid "Transferred %s so far" msgstr "Tot nu toe %s overgedragen" #: src/bz-update-dialog.blp:7 msgid "Update Now" msgstr "Update Nu" #: src/bz-update-dialog.blp:10 msgid "Updates Are Available" msgstr "Er zijn Updates Beschikbaar" #: src/bz-update-dialog.blp:11 msgid "" "The following applications are eligible for updates. Would you like to " "install them?" msgstr "" "De volgende applicaties hebben updates beschikbaar. Wil je deze Installeren?" #: src/bz-update-dialog.c:135 #, c-format msgid "" "%d runtimes and/or addons are eligible for updates. Would you like to " "install them?" msgstr "%d runtimes en/of add-ons hebben updates. Wil je deze nu installeren?" #: src/bz-update-dialog.c:143 #, c-format msgid "Additionally, %d runtimes and/or addons will be updated." msgstr "Daarnaast zullen %d runtimes en/of add-ons worden bijgewerkt." #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "Restgebruikersgegevens Beheren" #: src/bz-user-data-page.blp:55 msgid "No User Data found" msgstr "Geen gebruikersgegevens gevonden" #: src/bz-user-data-page.blp:60 msgid "User Data" msgstr "Gebruikersgegevens" #: src/bz-user-data-tile.c:144 #, c-format msgid "Trashed User Data for %s" msgstr "Gebruikersgegevens verwijderd voor %s" #: src/bz-user-data-tile.blp:74 msgid "Trash User Data" msgstr "Gebruikersgegevens verwijderen" #: src/bz-window.blp:107 msgid "Tasks" msgstr "Taken" #: src/bz-window.blp:163 msgid "Stop Active Tasks" msgstr "Stop Bezige Taken" #: src/bz-window.blp:171 msgid "Clear History" msgstr "Geschiedenis Wissen" #: src/bz-window.blp:187 msgid "No Tasks Yet" msgstr "Nog Geen Taken" #: src/bz-window.blp:257 msgid "Refreshing Store Content" msgstr "Winkelinhoud aan het verversen" #: src/bz-window.blp:271 msgid "Curated" msgstr "Gecureerd" #: src/bz-window.blp:284 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:432 msgid "No background tasks!" msgstr "Geen achtergrondtaken!" #: src/bz-window.blp:490 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "" "Je hebt een netwerkverbinding maar bekijkt een gecachte versie van Flathub" #: src/bz-window.blp:565 msgid "_Login with Flathub" msgstr "_Inloggen met Flathub" #: src/bz-window.blp:571 msgid "_Manage Leftover User Data" msgstr "Restgegevens _Beheren" #: src/bz-window.blp:576 msgid "_Synchronize Remotes" msgstr "Remotes _synchroniseren" #: src/bz-window.blp:617 msgid "Log Out" msgstr "Uitloggen" #: src/bz-window.c:435 #, c-format msgid "%d Update Available" msgid_plural "%d Updates Available" msgstr[0] "%d update beschikbaar" msgstr[1] "%d updates beschikbaar" #: src/bz-window.c:872 msgid "" "The ability to inspect and install local .flatpak bundle files is coming " "soon! In the meantime, try running\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "on the command line." msgstr "" "De mogelijkheid om lokale .flatpak bestanden te inspecteren en te " "installeren komt er binnenkort aan\n" "Flatpak install -bundle jouw-bundle.flatpak\n" "\n" "in de command line" #: src/bz-window.c:1010 msgid "Can't do that right now!" msgstr "Dit is nu niet mogelijk!" #: src/bz-window.c:1080 msgid "Resume Current Tasks" msgstr "Huidige Taken Hervatten" #: src/bz-window.c:1086 msgid "Pause Current Tasks" msgstr "Huidige Taken Pauzeren" #: src/bz-world-map.c:572 #, c-format msgid "%s: %'u downloads" msgstr "%s: %'u downloads" #: src/gtk/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Algemeen" #: src/gtk/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "Open zoekdialoog" #: src/gtk/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Voorkeuren" #: src/gtk/shortcuts-dialog.blp:19 msgctxt "shortcut window" msgid "Synchronize Remotes" msgstr "Remotes Synchroniseren" #: src/gtk/shortcuts-dialog.blp:24 msgctxt "shortcut window" msgid "Toggle Transaction Manager" msgstr "Schakel Transactiebeheerder" #: src/gtk/shortcuts-dialog.blp:29 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Toon Snelkoppelingen" #: src/gtk/shortcuts-dialog.blp:34 msgctxt "shortcut window" msgid "Quit" msgstr "Sluit Af" bazaar-orig-v0.7.14/po/de.po0000664000175000017500000023114015166123241014507 0ustar hasanhasan# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # # SPDX-FileCopyrightText: 2025, 2026 renner # renner , 2025. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-01-23 18:17+0100\n" "PO-Revision-Date: 2026-01-23 20:42+0100\n" "Last-Translator: renner \n" "Language-Team: German\n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Lokalize 25.12.1\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:5 #: src/bz-window.blp:233 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "Hinzufügen, Entfernen oder Aktualisieren von Apps auf diesem Computer" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;System;Paketverwaltung;Discover;Flatpak;Software;Store;" #: data/io.github.kolunmi.Bazaar.desktop.in:15 msgid "New Window" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and install applications" msgstr "Apps entdecken und installieren" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A new app store for Linux with a focus on discovering and installing " "applications and addons from Flatpak remotes, particularly Flathub." msgstr "" "Ein neuer App Store für GNOME mit Schwerpunkt auf der Suche und Installation " "von Apps und Erweiterungen aus Flatpak-Remotes, insbesondere Flathub." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:14 msgid "" "It emphasizes supporting the developers who make the Linux desktop possible. " "Bazaar features a \"curated\" tab that can be configured by distributors to " "allow for a more localized experience." msgstr "" "Es legt Wert darauf, die Entwickler zu unterstützen, die den Linux-Desktop " "möglich machen. Bazaar verfügt über ein „vorgestellt”-Unterfenster, der von " "Distributoren eingerichtet werden kann, um eine lokalisiertere Erfahrung zu " "ermöglichen." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:29 src/bz-application.c:706 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:54 msgid "The home page displaying Flathub apps" msgstr "Die Startseite mit den Flathub-Apps" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:58 msgid "Nucleus app page" msgstr "Seite der Nucleus App" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:62 msgid "Search page" msgstr "Auf Seite suchen" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:66 msgid "Category page" msgstr "Kategorienseite" #: src/bz-addons-dialog.blp:14 src/bz-full-view.blp:697 #: src/bz-installed-tile.blp:99 msgid "Manage Add-ons" msgstr "Erweiterungen verwalten" #: src/bz-addons-dialog.c:90 src/bz-full-view.blp:482 #: src/bz-installed-tile.blp:117 src/bz-transaction-dialog.c:225 #: src/bz-transaction-view.blp:277 msgid "Remove" msgstr "Entfernen" #: src/bz-addons-dialog.c:95 src/bz-favorites-tile.c:174 #: src/bz-full-view.blp:249 src/bz-full-view.blp:469 #: src/bz-transaction-dialog.c:202 src/bz-transaction-view.blp:225 msgid "Install" msgstr "Installieren" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 #: src/bz-age-rating-dialog.c:726 src/bz-full-view.c:338 src/bz-full-view.c:345 msgid "Age Rating" msgstr "Alterseinstufung" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "Cartoon-Gewalt" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "Keine Informationen über Cartoon-Gewalt" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "Fantasie-Gewalt" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "Keine Informationen über Fantasie-Gewalt" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "Realistische Gewalt" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "Keine Informationen über realistische Gewaltdarstellung" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "Darstellung von Blutvergießen" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "Keine Informationen über Blutvergießen" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "Sexuelle Gewalt" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "Keine Informationen über Sexuelle Gewalt" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "Alkohol" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "Keine Informationen über Alkohol" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "Betäubungsmittel" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "Keine Informationen über unerlaubten Drogen/Medikamente" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "Tabak" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "Keine Informationen über Tabakprodukte" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "Nacktheit" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "Keine Informationen über Nacktszenen irgendeiner Form" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "Sexuelle Themen" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "Keine Informationen über Anspielungen oder Darstellungen sexueller Natur" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "Obszönität" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "Keine Informationen über Obszönität irgendeiner Art" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "Unangemessener Humor" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "Keine Informationen über unangemessenen Humor" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "Diskriminierung" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "Keine Informationen über diskriminierender Sprache irgendeiner Art" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "Werbung" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "Keine Informationen über Werbung irgendeiner Art" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "Glücksspiel" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "Keine Informationen über Glücksspiel irgendeiner Art" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "Einkauf" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "Keine Informationen über die Möglichkeit, reales Geld auszugeben" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "Mit anderen Nutzern chatten" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "Keine Informationen über die Möglichkeit, mit anderen Nutzern zu chatten." #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "Audio-Chat zwischen Nutzern" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "Keine Informationen über die Möglichkeit, mit anderen Nutzern zu sprechen" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 msgid "Contact Details" msgstr "Kontaktdetails" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "" "Keine Informationen über das Teilen von Benutzernamen und E-Mail-Adressen " "über soziale Netzwerke" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "Identifizierende Informationen" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "Keine Informationen über das Teilen von Benutzerinformationen mit Dritten" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "Standortfreigabe" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "" "Keine Informationen über das Teilen des physischen Aufenthaltsortes mit " "anderen Nutzern" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "Prostitution" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "Keine Informationen über die Erwähnung von Prostitution" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "Ehebruch" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "Keine Informationen über die Erwähnung von Ehebruch" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "Sexualisierten Figuren" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "Keine Informationen über sexualisierte Figuren" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 msgid "Desecration" msgstr "Schändung" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "Keine Informationen über Erwähnungen von Schändung" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "Menschliche Überreste" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "Keine Informationen über sichtbare menschliche Überreste" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "Sklaverei" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "Keine Informationen über die Erwähnung von Sklaverei" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "Enthält keine Erwähnungen von Drogen" #: src/bz-age-rating-dialog.c:426 msgid "Does not include swearing, profanity, and other kinds of strong language" msgstr "" "Enthält keine Schimpfwörter, Obszönitäten und andere Arten von vulgärer " "Sprache" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "Enthält keine Werbung oder Geldtransaktionen" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "Enthält keine sexuellen Inhalte oder Nacktheit" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "Enthält keine unkontrollierte Chat-Funktion" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "Enthält keine Gewalt" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "Drogen" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "Kraftwörter" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "Geld" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "Soziales" #: src/bz-age-rating-dialog.c:479 msgid "Violence" msgstr "Gewalt" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:676 src/bz-full-view.c:328 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:701 msgctxt "Age rating" msgid "All" msgstr "Alle" #: src/bz-age-rating-dialog.c:737 #, c-format msgid "%s has an unknown age rating" msgstr "%s hat ein unbekannte Alterseinstufung" #: src/bz-age-rating-dialog.c:743 #, c-format msgid "%s is suitable for everyone" msgstr "%s ist für alle geeignet" #: src/bz-age-rating-dialog.c:746 #, c-format msgid "%s is suitable for young children" msgstr "%s ist für junge Kinder geeignet" #: src/bz-age-rating-dialog.c:749 #, c-format msgid "%s is suitable for children" msgstr "%s ist für Kinder geeignet" #: src/bz-age-rating-dialog.c:752 #, c-format msgid "%s is suitable for teenagers" msgstr "%s ist für Jugendliche geeignet" #: src/bz-age-rating-dialog.c:755 #, c-format msgid "%s is suitable for adults" msgstr "%s ist für Erwachsene geeignet" #: src/bz-age-rating-dialog.c:758 #, c-format msgid "%s is suitable for %s" msgstr "%s is geeignet für %s" #: src/bz-age-rating-dialog.c:852 #, c-format msgid "%s • %s" msgstr "%s • %s" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:43 #: src/bz-user-data-page.blp:15 src/bz-window.blp:483 msgid "Main Menu" msgstr "Hauptmenü" #: src/bz-all-apps-page.blp:17 src/bz-apps-page.blp:17 #: src/bz-user-data-page.blp:18 src/bz-window.blp:556 msgid "_Donate to Bazaar ❤️" msgstr "An Bazaar _spenden ❤️" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 #: src/bz-user-data-page.blp:19 #, fuzzy msgid "_Refresh Content" msgstr "Store-Inhalt aktualisieren" #: src/bz-all-apps-page.blp:22 src/bz-apps-page.blp:22 #: src/bz-user-data-page.blp:22 src/bz-window.blp:563 msgid "_Preferences" msgstr "_Einstellungen" #: src/bz-all-apps-page.blp:23 src/bz-apps-page.blp:23 #: src/bz-user-data-page.blp:23 src/bz-window.blp:584 msgid "_Keyboard Shortcuts" msgstr "_Tastaturkurzbefehle" #: src/bz-all-apps-page.blp:24 src/bz-apps-page.blp:24 #: src/bz-user-data-page.blp:24 src/bz-window.blp:589 msgid "_About Bazaar" msgstr "Ü_ber Bazaar" #: src/bz-all-apps-page.blp:28 src/bz-apps-page.blp:28 #: src/bz-user-data-page.blp:27 src/bz-window.blp:596 msgid "_Quit Bazaar" msgstr "Bazaar b_eenden" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "" #: src/bz-app-permissions.c:169 #, fuzzy, c-format msgid "Desktop subfolder %s" msgstr "Desktop-Unterstützung" #: src/bz-app-permissions.c:170 #, fuzzy msgid "Desktop folder" msgstr "Desktop-Unterstützung" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "Dokumentenordner" #: src/bz-app-permissions.c:177 #, fuzzy, c-format msgid "Music subfolder %s" msgstr "%s is geeignet für %s" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "Musikordner" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "Bilderordner" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "Öffentlicher Ordner" #: src/bz-app-permissions.c:189 #, fuzzy, c-format msgid "Videos subfolder %s" msgstr "%s is geeignet für %s" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "Videoordner" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "Vorlagenordner" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "" #: src/bz-app-size-dialog.blp:29 src/bz-app-size-dialog.blp:55 msgid "Download Size" msgstr "Downloadgröße" #: src/bz-app-size-dialog.blp:56 msgid "Amount to download from the internet" msgstr "" #: src/bz-app-size-dialog.blp:76 #, fuzzy msgid "Installed Size" msgstr "Installationsgöße" #: src/bz-app-size-dialog.blp:77 msgid "Size on Disk" msgstr "" #: src/bz-app-size-dialog.blp:99 #, fuzzy msgid "User Data Size" msgstr "Installationsgöße" #: src/bz-app-size-dialog.blp:100 msgid "Caches, settings, and other app data" msgstr "" #. Translators: As in 'The app is installed'. #. Translators: . #: src/bz-app-tile.blp:86 src/bz-full-view.c:292 src/bz-installed-page.blp:86 #: src/bz-window.blp:299 msgid "Installed" msgstr "Installiert" #: src/bz-apps-page.blp:103 msgid "Show All" msgstr "Alle anzeigen" #: src/bz-apps-page.c:232 #, fuzzy, c-format msgid "All \"%s\"" msgstr "Alle Altersgruppen" #: src/bz-apps-page.c:506 src/bz-tag-list.c:109 #, c-format msgid "%d Applications" msgstr "%d Apps" #: src/bz-application.c:677 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:678 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:709 msgid "translator-credits" msgstr "" "renner\n" "Mandarinoo" #: src/bz-application.c:720 msgid "Special Thanks" msgstr "" #: src/bz-application.c:778 msgid "Logged Out Successfully!" msgstr "" #: src/bz-application.c:905 msgid "Performing setup..." msgstr "Einrichtung wird durchgeführt …" #: src/bz-application.c:984 src/bz-application.c:993 msgid "Set Up Flathub" msgstr "Flathub einrichten" #: src/bz-application.c:987 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" #: src/bz-application.c:992 src/bz-window.c:875 msgid "Later" msgstr "Später" #: src/bz-application.c:1380 src/bz-application.c:3086 msgid "Synchronizing..." msgstr "Abgleichen …" #: src/bz-application.c:1521 src/bz-application.c:3082 #, c-format msgid "Receiving %d entries..." msgstr "%d Einträge empfangen …" #: src/bz-application.c:1526 #, fuzzy msgid "Checking for updates" msgstr "Es wird nach Aktualisierungen gesucht …" #: src/bz-application.c:3088 msgid "Indexing Data..." msgstr "" #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:75 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:53 #: src/bz-installed-page.blp:63 src/bz-user-data-page.blp:52 #: src/bz-window.blp:183 msgid "Empty" msgstr "Leer" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "Keine vorgestellten Apps" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "Flathub durchsuchen" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "Offline" #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 msgid "Browser" msgstr "Browser" #: src/bz-developer-badge.c:131 msgid "Developer information not available." msgstr "" #: src/bz-developer-badge.c:137 src/bz-developer-badge.c:151 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "" #: src/bz-developer-badge.c:155 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "" #: src/bz-developer-badge.c:161 #, c-format msgid "" "The ownership of the %1$s app ID has been verified by %2$s on " "%3$s." msgstr "" #: src/bz-developer-badge.c:168 #, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "" #: src/bz-developer-badge.c:172 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "" #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "Installationsart auswählen" #: src/bz-entry-group-util.c:76 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "" "Sie haben mehrere Versionen dieser App installiert.Mit welcher möchten " "Sie fortfahren?" #: src/bz-entry-group-util.c:80 src/bz-transaction-dialog.c:201 #: src/bz-transaction-dialog.c:224 src/bz-transaction-dialog.c:269 #: src/bz-transaction-dialog.c:576 msgid "Cancel" msgstr "Abbrechen" #: src/bz-error.c:68 msgid "An Error Occurred" msgstr "Es ist ein Fehler aufgetreten" #: src/bz-error.c:89 msgid "Close" msgstr "Schließen" #: src/bz-error.c:90 msgid "Copy and Close" msgstr "Kopieren und Schließen" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "Anmelden" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "" #: src/bz-favorites-tile.c:172 msgid "Uninstall" msgstr "Deinstallieren" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:75 msgid "Support this application" msgstr "Diese App unterstützen" #: src/bz-favorites-tile.blp:119 msgid "Remove from Favorites" msgstr "" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:85 #: src/bz-window.blp:614 msgid "Favorites" msgstr "" #: src/bz-favorites-page.blp:22 src/bz-full-view.blp:20 src/bz-window.blp:126 #: src/bz-window.blp:460 msgid "Toggle transaction sidebar" msgstr "Seitenleiste für Transaktionen anzeigen" #: src/bz-favorites-page.blp:46 src/bz-transaction-dialog.c:577 msgid "Install All" msgstr "Alle installieren" #: src/bz-favorites-page.blp:63 src/bz-user-data-page.blp:41 msgid "Loading" msgstr "Wird geladen" #: src/bz-favorites-page.blp:78 msgid "No Favorites" msgstr "" #: src/bz-favorites-page.blp:79 msgid "Applications you mark as favorite will appear here" msgstr "" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "Zurück" #: src/bz-featured-carousel.blp:53 msgid "Next" msgstr "Weiter" #: src/bz-featured-tile.blp:88 msgid "App of the Day" msgstr "App des Tages" #: src/bz-flathub-category.c:79 msgid "Audio & Video" msgstr "Audio & Video" #: src/bz-flathub-category.c:79 msgid "Media" msgstr "Media" #: src/bz-flathub-category.c:79 msgid "More Audio & Video" msgstr "Mehr Audio & Video" #: src/bz-flathub-category.c:80 msgid "Developer Tools" msgstr "Entwicklungswerkzeuge" #: src/bz-flathub-category.c:80 msgid "Develop" msgstr "Entwickeln" #: src/bz-flathub-category.c:80 msgid "More Developer Tools" msgstr "Mehr Entwicklerwerkzeuge" #: src/bz-flathub-category.c:81 msgid "Education" msgstr "Bildung" #: src/bz-flathub-category.c:81 msgid "Learn" msgstr "Lerne" #: src/bz-flathub-category.c:81 msgid "More Education" msgstr "Mehr Bildung" #: src/bz-flathub-category.c:82 msgid "Gaming" msgstr "Gaming" #: src/bz-flathub-category.c:82 msgid "Play" msgstr "Spielen" #: src/bz-flathub-category.c:82 msgid "More Gaming" msgstr "Mehr Gaming" #: src/bz-flathub-category.c:83 msgid "Graphics & Photography" msgstr "" #: src/bz-flathub-category.c:83 msgid "Create" msgstr "Erstelle" #: src/bz-flathub-category.c:83 msgid "More Graphics & Photography" msgstr "" #: src/bz-flathub-category.c:84 msgid "Networking" msgstr "Netzwerk" #: src/bz-flathub-category.c:84 msgid "Internet" msgstr "Internet" #: src/bz-flathub-category.c:84 msgid "More Networking" msgstr "Mehr Netzwerk" #: src/bz-flathub-category.c:85 msgid "Productivity" msgstr "Produktivität" #: src/bz-flathub-category.c:85 msgid "Work" msgstr "Arbeit" #: src/bz-flathub-category.c:85 msgid "More Productivity" msgstr "Mehr Produktivität" #: src/bz-flathub-category.c:86 msgid "Science" msgstr "Wissenschaft" #: src/bz-flathub-category.c:86 msgid "More Science" msgstr "Mehr Wissenschaft" #: src/bz-flathub-category.c:87 msgid "System" msgstr "System" #: src/bz-flathub-category.c:87 msgid "More System" msgstr "Mehr System" #: src/bz-flathub-category.c:88 msgid "Utilities" msgstr "Dienstprogramme" #: src/bz-flathub-category.c:88 msgid "Tools" msgstr "Werkzeuge" #: src/bz-flathub-category.c:88 msgid "More Utilities" msgstr "Mehr Dienstprogramme" #: src/bz-flathub-category.c:89 src/bz-flathub-page.blp:119 #: src/bz-flathub-page.blp:152 msgid "Trending" msgstr "Im Trend" #: src/bz-flathub-category.c:89 msgid "More Trending" msgstr "Mehr von „Im Trend“" #: src/bz-flathub-category.c:90 src/bz-flathub-page.blp:125 #: src/bz-flathub-page.blp:185 msgid "Popular" msgstr "Beliebt" #: src/bz-flathub-category.c:90 msgid "More Popular" msgstr "Mehr von „Beliebt“" #: src/bz-flathub-category.c:91 src/bz-flathub-page.blp:174 msgid "Recently Added" msgstr "Kürzlich hinzugefügt" #: src/bz-flathub-category.c:91 src/bz-flathub-page.blp:131 msgid "New" msgstr "Kürzlich hinzugefügt" #: src/bz-flathub-category.c:91 msgid "More New" msgstr "Mehr von „Kürzlich hinzugefügt“" #: src/bz-flathub-category.c:92 src/bz-flathub-page.blp:163 msgid "Recently Updated" msgstr "Kürzlich aktualisiert" #: src/bz-flathub-category.c:92 src/bz-flathub-page.blp:137 msgid "Updated" msgstr "Kürzlich aktualisiert" #: src/bz-flathub-category.c:92 msgid "More Updated" msgstr "Mehr von „Kürzlich aktualisiert“" #: src/bz-flathub-category.c:93 msgid "Mobile" msgstr "Mobil" #: src/bz-flathub-category.c:93 msgid "More Mobile" msgstr "Mehr Mobil" #: src/bz-flathub-category.c:94 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:94 #, fuzzy msgid "More Adwaita" msgstr "Mehr von „Kürzlich aktualisiert“" #: src/bz-flathub-category.c:95 msgid "KDE Apps" msgstr "KDE-Apps" #: src/bz-flathub-category.c:95 msgid "More KDE Apps" msgstr "Mehr Apps" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Flathub wurde nicht hinzugefügt" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "Flathub wurde auf keiner Ihrer Flatpak-Installationen gefunden." #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "Nur Flathub-Apps anzeigen" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Flathub nicht erreichbar" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "Anwedungen suchen" #: src/bz-flathub-page.blp:270 msgid "On the Go" msgstr "Unterwegs" #: src/bz-flathub-page.blp:282 msgid "Apps for your Linux phones and tablets" msgstr "" #: src/bz-flathub-page.blp:293 src/bz-flathub-page.blp:328 msgid "More Mobile Apps" msgstr "Mehr Mobile Apps" #: src/bz-flathub-page.blp:388 msgid "We​ ♥​ Games" msgstr "Wir ♥​ Spiele" #: src/bz-flathub-page.blp:401 msgid "Games and apps to run your favorite titles" msgstr "" #: src/bz-flathub-page.blp:435 msgid "More Games" msgstr "Mehr Spiele" #: src/bz-flatpak-entry.c:663 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Flathub-Seite" #: src/bz-flatpak-entry.c:684 msgctxt "Project URL Type" msgid "Project Website" msgstr "Projekt-Webseite" #: src/bz-flatpak-entry.c:688 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Bugtracker" #: src/bz-flatpak-entry.c:692 msgctxt "Project URL Type" msgid "FAQ" msgstr "FAQ" #: src/bz-flatpak-entry.c:696 msgctxt "Project URL Type" msgid "Help" msgstr "Hilfe" #: src/bz-flatpak-entry.c:700 msgctxt "Project URL Type" msgid "Donate" msgstr "Spenden" #: src/bz-flatpak-entry.c:706 msgctxt "Project URL Type" msgid "Translate" msgstr "Übersetzen" #: src/bz-flatpak-entry.c:710 msgctxt "Project URL Type" msgid "Contact" msgstr "Kontakt" #: src/bz-flatpak-entry.c:714 msgctxt "Project URL Type" msgid "Source Code" msgstr "Quellcode" #: src/bz-flatpak-entry.c:720 msgctxt "Project URL Type" msgid "Contribute" msgstr "Mitmachen" #: src/bz-full-view.blp:57 src/bz-installed-page.blp:74 #: src/bz-installed-page.blp:78 msgid "No Results" msgstr "Keine Ergebnisse" #: src/bz-full-view.blp:58 msgid "Try a different search query" msgstr "Versuchen Sie eine andere Suchanfrage" #: src/bz-full-view.blp:64 src/bz-window.blp:193 msgid "Content" msgstr "Inhalt" #: src/bz-full-view.blp:210 msgid "Support" msgstr "Unterstützen" #: src/bz-full-view.blp:233 src/bz-full-view.blp:493 msgid "Open" msgstr "Öffnen" #: src/bz-full-view.blp:246 src/bz-full-view.blp:466 msgid "Download & Install Application" msgstr "Apps herunterladen & installieren" #: src/bz-full-view.blp:261 msgid "Uninstall Application" msgstr "App deinstallieren" #: src/bz-full-view.blp:276 src/bz-full-view.blp:508 msgid "Install Other Version" msgstr "Andere Version installieren" #: src/bz-full-view.blp:430 msgid "Downloads /mo" msgstr "Downloads/Monat" #: src/bz-full-view.blp:527 msgid "Stopped Receiving Core Updates" msgstr "" #: src/bz-full-view.blp:541 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "Diese App verwendet eine Laufzeitumgebung, die keine Updates und " "Sicherheitsaktualisierungen mehr enthält. Sie könnte unsicher zu verwenden " "werden." #: src/bz-full-view.blp:630 msgid "Trash Data" msgstr "" #: src/bz-full-view.blp:772 msgid "Tags:" msgstr "Stichwörter:" #: src/bz-full-view.c:235 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:242 #, c-format msgid "%.*fM" msgstr "" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:249 #, c-format msgid "%.*fK" msgstr "" #: src/bz-full-view.c:259 #, c-format msgid "%d downloads in the last 30 days" msgstr "" #. Translators: . #: src/bz-full-view.c:292 #, fuzzy msgid "Download" msgstr "Downloadgröße" #: src/bz-full-view.c:310 #, c-format msgid "Download size of %s" msgstr "Downloadgröße von %s" #: src/bz-full-view.c:343 msgid "All Ages" msgstr "Alle Altersgruppen" #: src/bz-full-view.c:355 msgid "Age rating information unavailable" msgstr "" #: src/bz-full-view.c:360 msgid "Suitable for all ages" msgstr "Geeignet für alle Altersgruppen" #: src/bz-full-view.c:362 #, c-format msgid "Suitable for ages %d and up" msgstr "" #: src/bz-full-view.c:395 src/bz-full-view.c:400 src/bz-full-view.c:428 #: src/bz-full-view.c:439 msgid "Unknown" msgstr "Unbekannt" #: src/bz-full-view.c:405 #, c-format msgid "Free software licensed under %s" msgstr "Freie Software lizenziert unter %s" #: src/bz-full-view.c:410 #, fuzzy msgid "Free software" msgstr "Nur freie Software" #: src/bz-full-view.c:413 msgid "Proprietary Software" msgstr "Proprietäre Software" #: src/bz-full-view.c:416 #, c-format msgid "Special License: %s" msgstr "Besondere Lizenz: %s" #: src/bz-full-view.c:433 msgid "Free" msgstr "Frei" #: src/bz-full-view.c:436 src/bz-license-dialog.c:190 msgid "Proprietary" msgstr "Proprietär" #: src/bz-full-view.c:441 src/bz-license-dialog.c:192 msgid "Special License" msgstr "Besondere Lizenz" #: src/bz-full-view.c:461 msgid "Adaptive" msgstr "Adaptiv" #: src/bz-full-view.c:461 msgid "Desktop Only" msgstr "" #: src/bz-full-view.c:467 msgid "Works on desktop, tablets, and phones" msgstr "" #: src/bz-full-view.c:468 msgid "May not work on mobile devices" msgstr "" #: src/bz-full-view.c:479 msgid "No URL" msgstr "Keine URL" #: src/bz-full-view.c:497 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Diese App steht unter einer FLOSS-Lizenz, was bedeutet, dass der " "Quellcode auf Sicherheit geprüft werden kann." #: src/bz-full-view.c:498 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Diese App hat eine proprietäre Lizenz, das bedeute, dass der Quellcode " "privat entwickelt wird und kann nicht von einer unabhängigen dritten Partei " "überprüft werden." #: src/bz-full-view.c:505 msgid "More Apps" msgstr "Mehr Apps" #: src/bz-full-view.c:506 #, c-format msgid "More Apps by %s" msgstr "Mehr Apps von %s" #: src/bz-full-view.c:513 msgid "Other Apps by this Developer" msgstr "Andere Apps von diesem Entwickler" #: src/bz-full-view.c:515 src/bz-full-view.c:715 #, c-format msgid "Other Apps by %s" msgstr "Andere Apps von %s" #: src/bz-full-view.c:524 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "" #: src/bz-full-view.c:597 src/bz-full-view.c:614 msgid "N/A" msgstr "N/V" #: src/bz-full-view.c:604 src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "Sicher" #: src/bz-full-view.c:606 src/bz-full-view.c:608 msgid "Low Risk" msgstr "Geringes Risiko" #: src/bz-full-view.c:610 msgid "Medium Risk" msgstr "Mittleres Risiko" #: src/bz-full-view.c:612 msgid "High Risk" msgstr "Hohes Risiko" #: src/bz-full-view.c:717 msgid "Other Apps" msgstr "Andere Apps" #: src/bz-full-view.c:719 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d App" msgstr[1] "%d Apps" #: src/bz-full-view.c:1058 msgid "Show Less" msgstr "Weniger anzeigen" #: src/bz-full-view.c:1058 msgid "Show More" msgstr "Mehr anzeigen" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 msgid "Hardware Support" msgstr "Hardwareunterstützung" #: src/bz-hardware-support-dialog.c:62 msgid "Keyboard support" msgstr "Tastaturunterstützung" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "Benötigt Tastatur" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "Tastatur empfohlen" #: src/bz-hardware-support-dialog.c:66 msgid "Supports keyboards" msgstr "Unterstützt Tastaturen" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "Tastaturunterstützung unbekannt" #: src/bz-hardware-support-dialog.c:69 msgid "Mouse support" msgstr "Mausunterstützung" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "Benötigt Maus oder anderes Zeigegerät" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "Maus oder anderes Zeigegerät empfohlen" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "Unterstützt Mäuse und andere Zeigegeräte" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "Mausunterstützung unbekannt" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "Touchscreen-Unterstützung" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "Benötigt einen Touchscreen" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "Empfiehlt Touchscreen" #: src/bz-hardware-support-dialog.c:80 msgid "Supports touchscreens" msgstr "Unterstützt Touchscreens" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "Touchscreen-Unterstützung unbekannt" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "Mobilgeräteunterstützung" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "Funktioniert auf Mobilgeräten" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "Könnte auf Mobilgeräten nicht gut funktionieren" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "Desktop-Unterstützung" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "Funktioniert gut auf großen Bildschirmen" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "" #: src/bz-installed-page.blp:28 msgid "Search installed apps" msgstr "Installierte Apps anzeigen" #: src/bz-installed-page.blp:67 msgid "No Apps Found" msgstr "Keine Apps gefunden" #: src/bz-installed-page.c:157 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "" #: src/bz-installed-tile.blp:61 src/bz-rich-app-tile.blp:136 msgid "Stopped Receiving Updates" msgstr "Erhält keine Aktualisierungen mehr" #: src/bz-license-dialog.blp:95 msgid "Get Involved" msgstr "Machen Sie mit" #: src/bz-license-dialog.c:184 #, fuzzy msgid "Unknown License" msgstr "Unbekannt" #: src/bz-license-dialog.c:187 msgid "Community Built" msgstr "Entwickelt von der Gemeinschaft" #: src/bz-license-dialog.c:235 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" #: src/bz-license-dialog.c:238 msgid "The license of this app is not known" msgstr "" #: src/bz-license-dialog.c:244 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" #: src/bz-license-dialog.c:252 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" #: src/bz-license-dialog.c:258 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 #, fuzzy msgid "Connect to Flathub" msgstr "Flathub einrichten" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "Leider ist ein Fehler aufgetreten" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "" #: src/bz-login-page.blp:108 msgid "Finish" msgstr "Fertigstellen" #: src/bz-login-page.c:663 #, c-format msgid "Hello, %s!" msgstr "" #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Einstellungen" #: src/bz-preferences-dialog.blp:25 msgid "Network connection is metered — automatic store data sync is paused" msgstr "" #: src/bz-preferences-dialog.blp:26 src/bz-window.blp:494 msgid "Sync Manually" msgstr "" #: src/bz-preferences-dialog.blp:31 msgid "Content Filters" msgstr "Inhaltsfilter" #: src/bz-preferences-dialog.blp:34 msgid "Free Software Only" msgstr "Nur freie Software" #: src/bz-preferences-dialog.blp:35 msgid "Hide proprietary applications when browsing and searching" msgstr "" "Proprietäre Apps beim Durchsuchen und bei den Suchergebnissen " "ausblenden" #: src/bz-preferences-dialog.blp:39 msgid "Flathub Results Only" msgstr "Nur Flathub Ergebnisse" #: src/bz-preferences-dialog.blp:40 msgid "Limit search and browse results to applications only available on Flathub" msgstr "Suchergebnisse auf Apps beschränken, die auf Flathub verfügbar sind" #: src/bz-preferences-dialog.blp:44 #, fuzzy msgid "Verified Results Only" msgstr "Nur Flathub Ergebnisse" #: src/bz-preferences-dialog.blp:45 msgid "Hide results that are not verified on Flathub" msgstr "Apps ausschließen, die nicht von Flathub stammen" #: src/bz-preferences-dialog.blp:49 msgid "Hide EOL Apps" msgstr "EOL-Apps ausblenden" #: src/bz-preferences-dialog.blp:50 msgid "Hide apps which are no longer supported by their developers" msgstr "" #: src/bz-preferences-dialog.blp:55 src/bz-window.blp:314 msgid "Search" msgstr "Suchen" #: src/bz-preferences-dialog.blp:58 msgid "Delay Search Results" msgstr "Suchergebnisse verzögern" #: src/bz-preferences-dialog.blp:59 msgid "Improve results performance by debouncing search terms" msgstr "" #: src/bz-preferences-dialog.blp:64 msgid "Progress Bar" msgstr "Fortschrittsbalken" #: src/bz-preferences-dialog.blp:65 msgid "Choose a theme for the progress bar!" msgstr "Wählen Sie ein tolles Design für den globalen Fortschrittsbalken." #: src/bz-preferences-dialog.blp:89 msgid "Vertical Stripes" msgstr "" #: src/bz-preferences-dialog.blp:90 msgid "Display flag colors from top to bottom" msgstr "" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Akzentfarbe" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Pride-Farben" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "Lesben-Pride-Flagge" #: src/bz-preferences-dialog.c:35 #, fuzzy msgid "Male Homosexual Pride Colors" msgstr "Pansexuellenflagge" #: src/bz-preferences-dialog.c:36 msgid "Transgender Pride Colors" msgstr "Transgender-Flagge" #: src/bz-preferences-dialog.c:37 msgid "Nonbinary Pride Colors" msgstr "Nichtbinären-Flagge" #: src/bz-preferences-dialog.c:38 msgid "Bisexual Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:39 msgid "Asexual Pride Colors" msgstr "" #: src/bz-preferences-dialog.c:40 msgid "Pansexual Pride Colors" msgstr "Pansexuellenflagge" #: src/bz-preferences-dialog.c:41 msgid "Aromantic Pride Colors" msgstr "Aromantischenflagge" #: src/bz-preferences-dialog.c:42 msgid "Genderfluid Pride Colors" msgstr "Genderfluidenflagge" #: src/bz-preferences-dialog.c:43 msgid "Polysexual Pride Colors" msgstr "Polysexuellenflagge" #: src/bz-preferences-dialog.c:44 msgid "Omnisexual Pride Colors" msgstr "Omnisexuellenflagge" #: src/bz-preferences-dialog.c:45 #, fuzzy msgid "Aroace Pride Colors" msgstr "Aromantischenflagge" #: src/bz-preferences-dialog.c:46 #, fuzzy msgid "Agender Pride Colors" msgstr "Transgender-Flagge" #: src/bz-preferences-dialog.c:47 #, fuzzy msgid "Genderqueer Pride Colors" msgstr "Genderfluidenflagge" #: src/bz-preferences-dialog.c:48 #, fuzzy msgid "Intersex Pride Colors" msgstr "Pansexuellenflagge" #: src/bz-preferences-dialog.c:49 #, fuzzy msgid "Demigender Pride Colors" msgstr "Transgender-Flagge" #: src/bz-preferences-dialog.c:50 #, fuzzy msgid "Biromantic Pride Colors" msgstr "Aromantischenflagge" #: src/bz-preferences-dialog.c:51 #, fuzzy msgid "Disability Pride Colors" msgstr "Lesben-Pride-Flagge" #: src/bz-preferences-dialog.c:52 #, fuzzy msgid "Femboy Pride Colors" msgstr "Pride-Farben" #: src/bz-preferences-dialog.c:53 #, fuzzy msgid "Neutrois Pride Colors" msgstr "Nichtbinären-Flagge" #: src/bz-releases-dialog.blp:5 src/bz-releases-list.blp:27 msgid "Version History" msgstr "Versionsgeschichte" #: src/bz-releases-list.c:135 #, c-format msgid "Version %s" msgstr "Version: %s" #: src/bz-releases-list.c:173 msgid "No details for this release" msgstr "Keine Details für diese Veröffentlichung" #: src/bz-releases-list.c:185 #, fuzzy msgid "Get More Information" msgstr "Identifizierende Informationen" #: src/bz-rich-app-tile.blp:153 msgid "Get" msgstr "Installieren" #: src/bz-safety-calculator.c:82 #, fuzzy msgid "Unknown Permissions" msgstr "Berechtigungen bearbeiten" #: src/bz-safety-calculator.c:83 msgid "Permissions are missing for this app." msgstr "" #: src/bz-safety-calculator.c:96 msgid "No Permissions" msgstr "Keine Berechtigungen" #: src/bz-safety-calculator.c:97 msgid "App is fully sandboxed" msgstr "App ist vollständig isoliert" #: src/bz-safety-calculator.c:103 msgid "Network Access" msgstr "Netzwerk-Zugriff" #: src/bz-safety-calculator.c:104 msgid "Can access the internet" msgstr "Hat Zugriff auf das Internet" #: src/bz-safety-calculator.c:106 msgid "No Network Access" msgstr "Kein Netzwerk-Zugriff" #: src/bz-safety-calculator.c:107 msgid "Cannot access the internet" msgstr "Hat keinen Zugriff auf das Internet" #: src/bz-safety-calculator.c:112 msgid "User Device Access" msgstr "" #: src/bz-safety-calculator.c:113 msgid "Can access devices such as webcams or gaming controllers" msgstr "" #: src/bz-safety-calculator.c:115 msgid "No User Device Access" msgstr "" #: src/bz-safety-calculator.c:116 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "" #: src/bz-safety-calculator.c:121 msgid "Input Device Access" msgstr "" #: src/bz-safety-calculator.c:122 msgid "Can access input devices" msgstr "" #: src/bz-safety-calculator.c:128 msgid "Microphone Access and Audio Playback" msgstr "" #: src/bz-safety-calculator.c:129 msgid "Can listen using microphones and play audio without asking permission" msgstr "" #: src/bz-safety-calculator.c:135 msgid "System Device Access" msgstr "" #: src/bz-safety-calculator.c:136 msgid "Can access system devices which require elevated permissions" msgstr "" #: src/bz-safety-calculator.c:142 msgid "Screen Contents Access" msgstr "" #: src/bz-safety-calculator.c:143 msgid "Can access the contents of the screen or other windows" msgstr "" #: src/bz-safety-calculator.c:149 msgid "Legacy Windowing System" msgstr "" #: src/bz-safety-calculator.c:150 msgid "Always uses a legacy windowing system (X11)" msgstr "" #: src/bz-safety-calculator.c:156 #, fuzzy msgid "Arbitrary Permissions" msgstr "Berechtigungen bearbeiten" #: src/bz-safety-calculator.c:157 msgid "Can acquire arbitrary permissions" msgstr "" #: src/bz-safety-calculator.c:163 msgid "User Settings" msgstr "" #: src/bz-safety-calculator.c:164 msgid "Can access and change user settings" msgstr "" #: src/bz-safety-calculator.c:170 msgid "Full File System Read/Write Access" msgstr "" #: src/bz-safety-calculator.c:171 msgid "Can read and write all data on the file system" msgstr "" #: src/bz-safety-calculator.c:178 msgid "Home Folder Read/Write Access" msgstr "" #: src/bz-safety-calculator.c:179 msgid "Can read and write all data in your home directory" msgstr "" #: src/bz-safety-calculator.c:186 msgid "Full File System Read Access" msgstr "" #: src/bz-safety-calculator.c:187 msgid "Can read all data on the file system" msgstr "" #: src/bz-safety-calculator.c:195 msgid "Home Folder Read Access" msgstr "" #: src/bz-safety-calculator.c:196 msgid "Can read all data in your home directory" msgstr "" #: src/bz-safety-calculator.c:204 msgid "Download Folder Read/Write Access" msgstr "" #: src/bz-safety-calculator.c:205 msgid "Can read and write all data in your downloads directory" msgstr "" #: src/bz-safety-calculator.c:215 msgid "Download Folder Read Access" msgstr "" #: src/bz-safety-calculator.c:216 msgid "Can read all data in your downloads directory" msgstr "" #: src/bz-safety-calculator.c:229 msgid "Can read and write all data in the directory" msgstr "" #: src/bz-safety-calculator.c:243 msgid "Can read all data in the directory" msgstr "" #: src/bz-safety-calculator.c:258 msgid "No File System Access" msgstr "Kein Dateisystemzugriff" #: src/bz-safety-calculator.c:259 msgid "Cannot access the file system at all" msgstr "" #: src/bz-safety-calculator.c:266 msgid "Uses System Services" msgstr "" #: src/bz-safety-calculator.c:267 msgid "Can request data from non-portal system services" msgstr "" #: src/bz-safety-calculator.c:273 msgid "Uses Session Services" msgstr "" #: src/bz-safety-calculator.c:274 msgid "Can request data from non-portal session services" msgstr "" #: src/bz-safety-calculator.c:322 msgid "No Service Access" msgstr "" #: src/bz-safety-calculator.c:323 msgid "Cannot access non-portal session or system services at all" msgstr "" #: src/bz-safety-calculator.c:331 #, fuzzy msgid "Verified App Developer" msgstr "Andere Apps von diesem Entwickler" #: src/bz-safety-calculator.c:332 msgid "The developer of this app has been verified to be who they say they are" msgstr "" #: src/bz-safety-calculator.c:341 msgid "Proprietary Code" msgstr "Proprietärer Code" #: src/bz-safety-calculator.c:342 msgid "" "The source code is not public, so it cannot be independently audited and " "might be unsafe" msgstr "" #: src/bz-safety-calculator.c:352 msgid "Auditable Code" msgstr "Auditierbarer Code" #: src/bz-safety-calculator.c:353 msgid "" "The source code is public and can be independently audited, which makes the " "app more likely to be safe" msgstr "" #: src/bz-safety-calculator.c:493 #, c-format msgid "Use the %s System Service" msgstr "" #: src/bz-safety-calculator.c:497 #, c-format msgid "Use the %s Session Service" msgstr "" #: src/bz-safety-calculator.c:501 #, c-format msgid "Use the %s Service" msgstr "" #: src/bz-safety-calculator.c:511 msgid "Can see the non-portal service" msgstr "" #: src/bz-safety-calculator.c:513 msgid "Can talk to the non-portal service" msgstr "" #: src/bz-safety-calculator.c:515 msgid "Can own the non-portal service" msgstr "" #: src/bz-safety-calculator.c:530 msgid "Global Menu Integration" msgstr "" #: src/bz-safety-calculator.c:531 msgid "Can display its menus in a global menu bar" msgstr "" #: src/bz-safety-calculator.c:536 msgid "KDE Settings Integration" msgstr "" #: src/bz-safety-calculator.c:537 msgid "Can detect when KDE desktop settings change" msgstr "" #: src/bz-safety-calculator.c:542 msgid "KDE Global Settings" msgstr "" #: src/bz-safety-calculator.c:543 msgid "Can read KDE desktop preferences like fonts and colors" msgstr "" #: src/bz-safety-calculator.c:548 msgid "Secret Storage Service" msgstr "" #: src/bz-safety-calculator.c:549 msgid "Can store and retrieve its own passwords using the system keyring" msgstr "" #: src/bz-safety-calculator.c:554 msgid "Desktop Notifications Service" msgstr "" #: src/bz-safety-calculator.c:555 msgid "Can send desktop notifications" msgstr "" #: src/bz-safety-calculator.c:561 msgid "System Tray Integration" msgstr "" #: src/bz-safety-calculator.c:562 msgid "Can display an icon in the system tray" msgstr "" #: src/bz-safety-calculator.c:567 msgid "KDE Connect Integration" msgstr "KDE Connect-Integration" #: src/bz-safety-calculator.c:568 msgid "Can interact with devices paired via KDE Connect" msgstr "" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "Sicherheit" #: src/bz-safety-dialog.blp:50 msgid "Details" msgstr "Details" #: src/bz-safety-dialog.blp:53 msgid "License" msgstr "Lizenz" #: src/bz-safety-dialog.blp:62 msgid "App ID" msgstr "App-ID" #: src/bz-safety-dialog.blp:71 msgid "SDK" msgstr "" #: src/bz-safety-dialog.blp:98 msgid "" "This app uses an outdated version of the software platform (SDK) and might " "contain bugs or security vulnerabilities which will not be fixed." msgstr "" #: src/bz-safety-dialog.c:227 #, c-format msgid "%s is Safe" msgstr "" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s has no Unsafe Permissions" msgstr "" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Probably Safe" msgstr "" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Possibly Unsafe" msgstr "" #: src/bz-safety-dialog.c:247 #, c-format msgid "%s is Unsafe" msgstr "" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "Bild kopieren" #: src/bz-screenshot-page.blp:147 msgid "Reset View" msgstr "Ansicht zurücksetzen" #: src/bz-screenshot-page.blp:158 msgid "Zoom Out" msgstr "Verkleinern" #: src/bz-screenshot-page.blp:168 msgid "Zoom In" msgstr "Vergrößern" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "" #: src/bz-screenshots-carousel.blp:103 msgid "Open Screenshot Viewer" msgstr "" #: src/bz-search-widget.blp:57 msgid "Search Apps, Games, Software" msgstr "Nach Apps, Spielen und Software suchen" #: src/bz-search-widget.blp:96 msgid "Categories Unavailable" msgstr "Kategorien nicht verfügbar" #: src/bz-search-widget.blp:97 msgid "Search for apps using the search bar above." msgstr "" #: src/bz-search-widget.blp:181 msgid "No Applications Found" msgstr "Keine App gefunden" #: src/bz-search-widget.c:241 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "" #: src/bz-share-list.c:64 msgid "Copied!" msgstr "Kopiert." #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "Link kopieren" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Link öffnen" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "Zeitleiste" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "Installationen:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "Welt" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:124 #, c-format msgid "%.2fM Total Installs" msgstr "" #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:127 #, c-format msgid "%.2fK Total Installs" msgstr "" #: src/bz-stats-dialog.c:129 #, c-format msgid "%'d Total Installs" msgstr "" #: src/bz-tag-list.c:96 msgid "No Results Found" msgstr "Keine Ergebnisse gefunden" #: src/bz-tag-list.c:108 #, c-format msgid "Apps Tagged \"%s\"" msgstr "" #: src/bz-tag-list.c:124 msgid "Search failed" msgstr "Suchen fehlgeschlagen" #: src/bz-transaction-dialog.c:160 msgid "Keep Data" msgstr "Daten behalten" #: src/bz-transaction-dialog.c:161 msgid "Allow restoring settings and content" msgstr "" #: src/bz-transaction-dialog.c:170 msgid "Delete Data" msgstr "Daten löschen" #: src/bz-transaction-dialog.c:171 msgid "Permanently remove app data to save space" msgstr "" #: src/bz-transaction-dialog.c:195 #, c-format msgid "Install %s?" msgstr "%s installieren?" #: src/bz-transaction-dialog.c:198 msgid "May install additional shared components" msgstr "Es könnten zusätzliche gemeinsam genutzte Komponenten installiert werden" #: src/bz-transaction-dialog.c:217 #, c-format msgid "Remove %s?" msgstr "%s entfernen?" #: src/bz-transaction-dialog.c:221 #, fuzzy, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "" "Es wird nicht mehr möglich sein, %s nach der Deinstallation auszuführen.\n" "\n" "Einstellungen und Benutzerdaten werden behalten werden." #: src/bz-transaction-dialog.c:241 #, c-format msgid "“%s” is High Risk" msgstr "" #: src/bz-transaction-dialog.c:245 msgid "" "This app has full access to your system, including all your files, " "browser history, saved passwords, and more. It also has access to the " "internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" #: src/bz-transaction-dialog.c:254 msgid "" "This app uses the legacy X11 windowing system, which allows it to record " "all keystrokes, capture screenshots, and monitor other applications. It " "also has access to the internet, meaning it could send your data to outside " "parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" #: src/bz-transaction-dialog.c:270 msgid "Install Anyway" msgstr "Trotzdem installieren" #: src/bz-transaction-dialog.c:547 msgid "All apps are already installed" msgstr "" #: src/bz-transaction-dialog.c:549 msgid "OK" msgstr "OK" #: src/bz-transaction-dialog.c:565 #, fuzzy, c-format msgid "Install %u App?" msgid_plural "Install %u Apps?" msgstr[0] "%s installieren?" msgstr[1] "%s installieren?" #: src/bz-transaction-dialog.c:573 msgid "" "The following will be installed. Additional shared components may also be " "installed" msgstr "" #: src/bz-transaction-dialog.c:574 #, c-format msgid "%d addons will be installed." msgstr "" #: src/bz-transaction-dialog.c:575 #, fuzzy msgid "Additionally, addons will be installed." msgstr "Zusätzlich werden %d Laufzeitumgebungen und/oder Erweiterungen aktualisiert." #: src/bz-transaction-manager.c:1150 #, c-format msgid "Finished in %.02f seconds" msgstr "In %.02f Sekunden abgeschlossen" #: src/bz-transaction-view.blp:95 msgid "App Add-on" msgstr "App Erweiterung" #: src/bz-transaction-view.blp:120 msgid "Runtime" msgstr "Laufzeitumgebung" #: src/bz-transaction-view.blp:146 src/bz-transaction-view.blp:172 msgid "Install Size" msgstr "Installationsgöße" #: src/bz-transaction-view.blp:187 src/bz-transaction-view.blp:238 #: src/bz-transaction-view.blp:264 src/bz-transaction.c:342 msgid "Pending" msgstr "Ausstehend" #: src/bz-transaction-view.blp:199 msgid "Ongoing" msgstr "" #: src/bz-transaction-view.blp:212 msgid "Finished" msgstr "" #: src/bz-transaction-view.blp:251 msgid "Update" msgstr "Aktualisieren" #: src/bz-transaction-view.c:135 #, c-format msgid "Transferred %s so far" msgstr "%s bis jetzt übertragen" #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "" #: src/bz-user-data-page.blp:55 msgid "No User Data found" msgstr "" #: src/bz-user-data-page.blp:60 msgid "User Data" msgstr "" #: src/bz-user-data-tile.c:144 #, c-format msgid "Trashed User Data for %s" msgstr "" #: src/bz-user-data-tile.blp:74 msgid "Trash User Data" msgstr "" #: src/bz-window.blp:107 msgid "Tasks" msgstr "Aufgaben" #: src/bz-window.blp:163 msgid "Stop Active Tasks" msgstr "Aktiven Aufgaben stoppen" #: src/bz-window.blp:171 msgid "Clear History" msgstr "Verlauf leeren" #: src/bz-window.blp:187 msgid "No Tasks Yet" msgstr "Noch keine Aufgaben" #: src/bz-window.blp:257 msgid "Refreshing Store Content" msgstr "Store-Inhalt aktualisieren" #: src/bz-window.blp:273 msgid "Curated" msgstr "Vorgestellt" #: src/bz-window.blp:286 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:435 msgid "No background tasks!" msgstr "" #: src/bz-window.blp:493 msgid "You have a network connection but are viewing a cached version of Flathub" msgstr "" #: src/bz-window.blp:568 msgid "_Login with Flathub" msgstr "Mit Flathub _anmelden" #: src/bz-window.blp:574 msgid "_Manage Leftover User Data" msgstr "" #: src/bz-window.blp:579 msgid "_Synchronize Remotes" msgstr "" #: src/bz-window.blp:620 msgid "Log Out" msgstr "Abmelden" #: src/bz-window.c:440 #, fuzzy, c-format msgid "%d Update Available" msgid_plural "%d Updates Available" msgstr[0] "Es sind Aktualisierungen verfügbar" msgstr[1] "Es sind Aktualisierungen verfügbar" #: src/bz-window.c:734 msgid "You can't remove Bazaar from Bazaar!" msgstr "" #: src/bz-window.c:871 msgid "Updates Are Available" msgstr "Es sind Aktualisierungen verfügbar" #: src/bz-window.c:872 msgid "" "The following applications are eligible for updates. Would you like to " "install them?" msgstr "" "Für die folgenden Apps sind Aktualisierungen erhältlich. Möchten Sie " "diese installieren?" #: src/bz-window.c:873 #, c-format msgid "" "%d runtimes and/or addons are eligible for updates. Would you like to " "install them?" msgstr "" "%d Laufzeitumgebungen und/oder Erweiterungen haben neue Aktualisierungen " "erhalten. Möchten Sie diese installieren?" #: src/bz-window.c:874 #, c-format msgid "Additionally, %d runtimes and/or addons will be updated." msgstr "Zusätzlich werden %d Laufzeitumgebungen und/oder Erweiterungen aktualisiert." #: src/bz-window.c:876 msgid "Update Now" msgstr "Jetzt aktualisieren" #: src/bz-window.c:891 msgid "" "The ability to inspect and install local .flatpak bundle files is coming " "soon! In the meantime, try running\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "on the command line." msgstr "" "Die Möglichkeit, lokale .flatpak-Bundle-Dateien zu überprüfen und zu " "installieren, wird in Kürze verfügbar sein!\n" "In der Zwischenzeit können Sie versuchen, folgenden Befehl in der " "Befehlszeile auszuführen:\n" "\n" "flatpak install --bundle dein-bundle.flatpak" #: src/bz-window.c:1030 src/bz-window.c:1080 msgid "Can't do that right now!" msgstr "Das kann momentan nicht getan werden." #: src/bz-window.c:1155 msgid "Resume Current Tasks" msgstr "Die aktuelle Ausgabe fortsetzen" #: src/bz-window.c:1161 msgid "Pause Current Tasks" msgstr "Die aktuelle Aufgabe pausieren" #: src/bz-world-map.c:587 msgid "Downloads" msgstr "Downloads" #: src/gtk/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Allgemein" #: src/gtk/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "Suchdialog öffnen" #: src/gtk/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Einstellungen öffnen" #: src/gtk/shortcuts-dialog.blp:19 msgctxt "shortcut window" msgid "Synchronize Remotes" msgstr "" #: src/gtk/shortcuts-dialog.blp:24 msgctxt "shortcut window" msgid "Toggle Transaction Manager" msgstr "Transaktionsverwaltung umschalten" #: src/gtk/shortcuts-dialog.blp:29 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Kurzbefehle anzeigen" #: src/gtk/shortcuts-dialog.blp:34 msgctxt "shortcut window" msgid "Quit" msgstr "Beenden" #~ msgid "Hide EOL Entries" #~ msgstr "EOL-Einträge ausblenden" #~ msgid "Hide EOL entries and entries depending on them" #~ msgstr "EOL-Einträge und davon abhängige Einträge ausblenden" #~ msgid "Show Git Forge Star Counts" #~ msgstr "Git Forge Sterneanzahl anzeigen" #~ msgid "" #~ "Whether to attempt to detect and show \"star counts\" for projects in the " #~ "full view" #~ msgstr "" #~ "Ob versucht werden soll, die Sternanzahl für Projekte in der Vollansicht " #~ "anzuzeigen" #~ msgid "Only Show Free Software" #~ msgstr "Nur freie Software anzeigen" #~ msgid "Hide proprietary software" #~ msgstr "Proprietäre Software ausblenden" #~ msgid "Debounce Search Inputs" #~ msgstr "Sucheingaben verzögern" #~ msgid "Add a delay before searching to prevent instant replies while typing" #~ msgstr "" #~ "Eine Verzögerung hinzufügen, um sofortige Antworten während der Eingabe " #~ "zu verhindern" #~ msgid "Global Progress Bar Theme" #~ msgstr "Globales Fortschrittsbalken-Design" #~ msgid "Describes the look of the global progress bar" #~ msgstr "Beschreibt das Aussehen des globalen Fortschrittsbalkens" #~ msgid "Saved Window Dimensions" #~ msgstr "Gespeicherte Fensterabmessungen" #~ msgid "The window dimensions to be used by the next Bazaar window" #~ msgstr "" #~ "Die Fensterabmessungen, die vom nächsten Bazaar-Fenster verwendet werden " #~ "sollen" #~ msgid "?" #~ msgstr "?" #, c-format #~ msgid "%s is suitable for toddlers" #~ msgstr "%s ist für Kleinkinder geeignet" #~ msgid "--- MB" #~ msgstr "--- MB" #~ msgid "Of the size of human DNA" #~ msgstr "Der Größe der menschlichen DNA" #~ msgid "3 billion base pairs" #~ msgstr "3 Milliarden Basenpaare" #~ msgid "Of the Linux Kernel" #~ msgstr "Des Linux Kernels" #~ msgid "linux-6.17.tar.xz" #~ msgstr "linux-6.17.tar.xz" #~ msgid "Of the Apollo 11 guidance computer" #~ msgstr "Des Apollo 11 Guidance-Computers" #~ msgid "Total ROM and RAM" #~ msgstr "Gesamt-ROM und RAM" #~ msgid "Of the original Super Mario Bros" #~ msgstr "Des ursprünglichen Super Mario Bros." #~ msgid "On the NES" #~ msgstr "Auf dem NES" #~ msgid "Of the size of Wikipedia" #~ msgstr "Der Größe von Wikipedia" #~ msgid "Without any media" #~ msgstr "Ohne jegliche Medien" #~ msgid "" #~ "This functionality is currently disabled. It is recommended you download " #~ "and install Flatseal to manage app permissions." #~ msgstr "" #~ "Diese Funktion ist derzeit nicht freigeschaltet. Es wird empfohlen, " #~ "Flatseal herunterzuladen und zu installieren, um Berechtigungen von " #~ "Anwendungen einzustellen." #~ msgid "Entry Inspector" #~ msgstr "Eintragsinspektor" #~ msgid "Serialize" #~ msgstr "Serialisierung der Anfrage ist fehlgeschlagen" #~ msgid "Convert to JSON" #~ msgstr "In JSON umwandeln" #~ msgid "We ♥ Games" #~ msgstr "Wir ♥ Spiele" #~ msgid "Repository Star Count" #~ msgstr "Repository Sterneanzahl" #~ msgid "Size" #~ msgstr "Größe" #~ msgid "Bazaar Inspector" #~ msgstr "Bazaar-Inspektor" #~ msgid "Active Blocklists" #~ msgstr "Aktive Blocklisten" #~ msgid "Active Curated-Configs" #~ msgstr "Aktive Vorgestellte Einrichtung" #~ msgid "All Entry Groups" #~ msgstr "Alle Eintragsgruppen" #~ msgid "Filter..." #~ msgstr "Filtern ..." #~ msgid "Decache and Inspect" #~ msgstr "Entcachen und Inspizieren" #~ msgid "No Flatpaks Installed" #~ msgstr "Keine Anwendungen installiert" #~ msgid "Application Details" #~ msgstr "Anwendungsdetails" #~ msgid "Display Star Count" #~ msgstr "Sterneanzahl anzeigen" #~ msgid "Open Bazaar Inspector" #~ msgstr "Bazaar-Inspektor öffnen" #, c-format #~ msgid "%s: %'u downloads" #~ msgstr "%s: %u Downloads" #~ msgctxt "shortcut window" #~ msgid "Refresh" #~ msgstr "Aktualisieren" #~ msgid "Hide proprietary software when searching" #~ msgstr "Proprietäre Anwendungen in Suchergebnissen ausblenden" #~ msgid "Filter search results to only show applications available on Flathub" #~ msgstr "" #~ "Suchergebnisse auf Anwendungen beschränken, die auf Flathub verfügbar sind" #~ msgid "Constructing Flatpak instance..." #~ msgstr "Flatpak-Instanz wird erstellt …" #~ msgid "Reusing last Flatpak instance..." #~ msgstr "Letzte Flatpak-Instanz wiederverwenden …" #~ msgid "Flathub is not registered on this system" #~ msgstr "Flathub ist auf diesem System nicht eingerichtet" #~ msgid "" #~ "Would you like to add Flathub as a remote? If you decline, the Flathub " #~ "page will not be available. You can change this later." #~ msgstr "" #~ "Möchten Sie Flathub hinzufügen? Wenn Sie ablehnen, ist die Flathub-Seite " #~ "nicht verfügbar. Sie können dies später ändern." #~ msgid "Add Flathub" #~ msgstr "Flathub hinzufügen" #~ msgid "Identifying installed entries..." #~ msgstr "Installierte Einträge werden erkannt …" #, c-format #~ msgid "%'d of %'d" #~ msgstr "%'d von %'d" #, c-format #~ msgid "Waiting for background indexing tasks to catch up..." #~ msgstr "Warten auf Hintergrund-Indizierung …" #, c-format #~ msgid "Completed initialization in %0.2f seconds" #~ msgstr "Initialisierung in %0.2f Sekunden abgeschlossen" #~ msgid "Verified by the original developers" #~ msgstr "" #~ "Diese Anwendung wurde von den ursprünglichen Entwicklern der Software " #~ "verifiziert." #~ msgid "Manage Addons" #~ msgstr "Erweiterungen verwalten" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Ahmed Najmawi" #~ msgstr "Ahmed Najmawi" #~ msgctxt "About Dialog Translator Credit" #~ msgid "AtomHare" #~ msgstr "AtomHare" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Azenyr" #~ msgstr "Azenyr" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Goudarz Jafari" #~ msgstr "Goudarz Jafari" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Jill Fiore (Lumaeris)" #~ msgstr "Jill Fiore (Lumaeris)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "João Victor (Leal)" #~ msgstr "João Victor (Leal)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "KiKaraage" #~ msgstr "KiKaraage" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Lucosec" #~ msgstr "Lucosec" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Léane GRASSER" #~ msgstr "Léane GRASSER" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Marcel Mrówka (Microwave)" #~ msgstr "Marcel Mrówka (Microwave)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Peter Dave Hello" #~ msgstr "Peter Dave Hello" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Pietro F." #~ msgstr "Pietro F." #~ msgctxt "About Dialog Translator Credit" #~ msgid "Shihfu Juan" #~ msgstr "Shihfu Juan" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Shinsei" #~ msgstr "Shinsei" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Vlastimil Dědek" #~ msgstr "Vlastimil Dědek" #~ msgctxt "About Dialog Translator Credit" #~ msgid "asen23" #~ msgstr "asen23" #~ msgctxt "About Dialog Translator Credit" #~ msgid "camegone" #~ msgstr "camegone" #~ msgctxt "About Dialog Translator Credit" #~ msgid "renner" #~ msgstr "renner" #~ msgctxt "About Dialog Translator Credit" #~ msgid "robotta" #~ msgstr "robotta" #, c-format #~ msgid "" #~ "Beginning remote entry retrieval while referencing %d blocklist(s)..." #~ msgstr "" #~ "Abfragenbeginn der Gegenstelleneinträge unter Bezugnahme auf %d " #~ "Blockliste(n) …" #~ msgid "" #~ "Bazaar was not provided a curated content configuration. Contact your " #~ "operating system's support channels for assistance." #~ msgstr "" #~ "Bazaar wurde nicht mit vorgestellten Inhalten eingerichtet. Nehmen Sie " #~ "Kontakt mit den Entwicklern Ihres Betriebssystems auf, um Hilfe zu " #~ "erhalten." #~ msgid "Games" #~ msgstr "Spiele" #~ msgid "Graphics" #~ msgstr "Grafik" #~ msgid "Office" #~ msgstr "Büro" #~ msgctxt "Project URL Type" #~ msgid "Homepage" #~ msgstr "Startseite" #~ msgid "Share this application" #~ msgstr "Diese Anwendung teilen" #~ msgid "Excludes shared components" #~ msgstr "Gemeinsame Komponenten ausgeschlossen" #~ msgid "Source code may not be available" #~ msgstr "Der Quellcode ist möglicherweise nicht verfügbar." #~ msgid "Click for details" #~ msgstr "Klicken Sie, um Details anzusehen" #~ msgid "Repositories" #~ msgstr "Repositories" #~ msgid "Open in browser" #~ msgstr "Im Webbrowser öffnen" #, c-format #~ msgid "%'d Monthly Downloads" #~ msgstr "%'d monatliche Downloads" #~ msgid "%B %-d, %Y" #~ msgstr "%B %-d, %Y" #~ msgid "%B %-d" #~ msgstr "%B %-d" #~ msgid "Run this application" #~ msgstr "Diese Anwendung ausführen" #~ msgid "Run" #~ msgstr "Ausführen" #~ msgid "View Store Page" #~ msgstr "Store-Seite anzeigen" #~ msgid "Git Forge Star Counts" #~ msgstr "Git Forge Sterneanzahl" #~ msgid "Not having a GitHub access token may trigger rate limits" #~ msgstr "" #~ "Wenn Sie keinen GitHub-Token haben, kann dies zu Ratenbegrenzungen führen." #~ msgid "Show Only Flathub Apps" #~ msgstr "Nur Flathub-Anwendungen anzeigen" #~ msgid "Wait for a brief pause to reduce system load" #~ msgstr "EIne kurze Weile warten, um die Systemlast zu verringern" #~ msgid "Theme" #~ msgstr "Design" #~ msgid "Pride Rainbow Flag" #~ msgstr "Pride-Regenbogenflagge" #~ msgid "Bisexual Flag" #~ msgstr "Bisexuellenflagge" #~ msgid "Asexual Flag" #~ msgstr "Asexuellenflagge" #~ msgid "Share" #~ msgstr "Teilen" #~ msgid "Transactions" #~ msgstr "Aufgaben" #~ msgid "Browse" #~ msgstr "Durchsuchen" #~ msgid "App View" #~ msgstr "Anwendungsansicht" #~ msgid "Go Back" #~ msgstr "Zurück" #~ msgid "View curated applications" #~ msgstr "Vorgestellte Anwendungen ansehen" #~ msgid "View the latest on Flathub" #~ msgstr "Das neueste auf Flathub ansehen" #~ msgid "_Quit Service" #~ msgstr "Dienst _beenden" #~ msgid "Up to date!" #~ msgstr "Auf neuestem Stand" #~ msgid "Settings & user data will be kept" #~ msgstr "Einstellungen und Benutzerdaten werden beibehalten" #~ msgid "Show Animated Background" #~ msgstr "Animierten Hintergrund anzeigen" #~ msgid "Whether to show the animated icon background on the home page" #~ msgstr "Den animierten Hintergrund auf der Startseite anzeigen" #~ msgid "" #~ "It emphasizes supporting the developers who make the Linux desktop " #~ "possible." #~ msgstr "" #~ "Es legt Wert darauf, die Entwickler zu unterstützen, die den Linux-" #~ "Desktop möglich machen." #~ msgid "Calligraphy application page" #~ msgstr "Calligraphy" #~ msgid "Download graph for Blender" #~ msgstr "Downloadkurve für Blender" #, c-format #~ msgid "Received %'d entries out of %'d (%0.1f seconds elapsed)" #~ msgstr "%'d Einträge von %'d empfangen (%0.1f Sekunden vergangen)" #~ msgid "Apps Of The Week" #~ msgstr "Anwendungen der Woche" #~ msgid "" #~ "The number of downloads in the last 30 days. Click to view this " #~ "application's download statistics." #~ msgstr "" #~ "Die Anzahl der Downloads in den letzten 30 Tagen. Klicken Sie hier, um " #~ "die Download-Statistiken für diese Anwendung anzuzeigen." #~ msgid "Remote repo name" #~ msgstr "Namen des Repository" #, c-format #~ msgid "Released %x" #~ msgstr "Veröffentlicht %x" #~ msgid "How the application looks" #~ msgstr "Wie die Anwendung aussieht" #~ msgid "Appearance" #~ msgstr "Erscheinungsbild" #~ msgid "Show animated background" #~ msgstr "Animierten Hintergrund anzeigen" #~ msgid "Type to filter" #~ msgstr "Zum Filtern hier tippen" #~ msgid "Exclude results with proprietary licenses" #~ msgstr "Ergebnisse mit proprietären Lizenzen ausschließen" #~ msgid "Advanced" #~ msgstr "Erweitert" #~ msgid "Open this link externally" #~ msgstr "Diesen Link extern öffnen" #~ msgid "Downloads Over Time" #~ msgstr "Downloads im Laufe der Zeit" #~ msgid "Minimize Lower Bound" #~ msgstr "Untere Grenze verringern" #~ msgid "Maximize Upper Bound" #~ msgstr "Obere Grenze vergrößern" #~ msgid "Installing" #~ msgstr "Wird installiert" #~ msgid "Updating" #~ msgstr "Wird aktualisiert" #~ msgid "Removing" #~ msgstr "Wird entfernt" #~ msgid "Transactions Will Appear Here" #~ msgstr "Transaktionen werden hier erscheinen" #~ msgid "Halt the execution of transactions" #~ msgstr "Die Ausführung von Transaktionen anhalten" #~ msgid "Clear all finished transactions" #~ msgstr "Alle abgeschlossenen Transaktionen leeren" #~ msgid "Confirm Action" #~ msgstr "Aktion bestätigen" #, c-format #~ msgid "" #~ "You are about to remove the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "Sie sind dabei, die folgende Anwendung zu entfernen:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Sind Sie sich sicher?" #, c-format #~ msgid "" #~ "You are about to install the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "Sie sind dabei, die folgende Anwendung zu installieren:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Sind Sie sich sicher?" #~ msgid "Resume the execution of transactions" #~ msgstr "Die Ausführung von Transaktionen fortsetzen" #~ msgid "Pause the execution of transactions" #~ msgstr "Die Ausführung von Transaktionen pausieren" #~ msgid "Main Bazaar window showing Blender" #~ msgstr "Bazaar-Hauptfenster zeigt Blender" #~ msgid "Match using regular expressions" #~ msgstr "Übereinstimmung mit regulären Ausdrücken" #~ msgid "Hide filtering and sorting behind a crossfade effect" #~ msgstr "" #~ "Filterung und Sortierung hinter einem Überblendungseffekt verstecken" bazaar-orig-v0.7.14/po/pt_BR.po0000664000175000017500000027264515166123241015144 0ustar hasanhasan# Portuguese translations for bazaar package # Traduções em português brasileiro para o pacote bazaar. # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # Rin Koito , 2025-2026. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-02-15 10:28-0400\n" "PO-Revision-Date: 2026-02-15 22:10-0400\n" "Last-Translator: Rin Koito \n" "Language-Team: Brazilian Portuguese\n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Gtranslator 49.0\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:6 #: src/bz-window.blp:111 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "Adicione, remova ou atualize flatpaks neste computador" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;Sistema;GerenciadorDePacotes;Discover;Flatpak;Aplicativos;Loja;" #: data/io.github.kolunmi.Bazaar.desktop.in:15 msgid "New Window" msgstr "Nova Janela" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and install applications" msgstr "Descobrir e instalar aplicativos" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A new app store for Linux with a focus on discovering and installing " "applications and addons from Flatpak remotes, particularly Flathub." msgstr "" "Uma nova loja de aplicativos para Linux, focada em descobrir e instalar " "aplicativos e complementos de repositórios de Flatpak, particularmente o " "Flathub." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:14 msgid "" "It emphasizes supporting the developers who make the Linux desktop possible. " "Bazaar features a \"curated\" tab that can be configured by distributors to " "allow for a more localized experience." msgstr "" "Isso enfatiza o apoio aos desenvolvedores que tornam o desktop Linux " "possível. Bazaar provê uma seção de \"recomendados\" que pode ser " "configurada por distribuidores para entregar uma experiência mais localizada." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:54 msgid "The home page displaying Flathub apps" msgstr "A página inicial exibindo aplicativos do Flathub" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:58 msgid "Exhibit app page" msgstr "Exibir página do app" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:62 msgid "Library page" msgstr "Página da Biblioteca" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:66 msgid "Search page" msgstr "Página de Pesquisa" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:70 msgid "Category page" msgstr "Página de Catergorias" #: src/bz-addons-dialog.blp:16 src/bz-full-view.blp:708 #: src/bz-installed-tile.blp:101 msgid "Manage Add-ons" msgstr "Gerenciar Extensões" #: src/bz-addons-dialog.c:94 src/bz-full-view.blp:495 #: src/bz-installed-tile.blp:119 src/bz-transaction-dialog.c:231 msgid "Remove" msgstr "Remover" #: src/bz-addons-dialog.c:99 src/bz-favorites-tile.c:159 #: src/bz-full-view.blp:262 src/bz-full-view.blp:482 #: src/bz-transaction-dialog.c:202 msgid "Install" msgstr "Instalar" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 #: src/bz-age-rating-dialog.c:726 src/bz-full-view.c:338 src/bz-full-view.c:345 msgid "Age Rating" msgstr "Classificação Indicativa" # https://pt.wikipedia.org/wiki/Sistema_de_Classifica%C3%A7%C3%A3o_Indicativa_Brasileiro #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "Violência Caricata" # https://pt.wikipedia.org/wiki/Sistema_de_Classifica%C3%A7%C3%A3o_Indicativa_Brasileiro #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "Sem informações acerca de violência caricata" # https://pt.wikipedia.org/wiki/Sistema_de_Classifica%C3%A7%C3%A3o_Indicativa_Brasileiro #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "Violência Fantasiosa" # https://pt.wikipedia.org/wiki/Sistema_de_Classifica%C3%A7%C3%A3o_Indicativa_Brasileiro #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "Sem informações acerca de violência fantasiosa" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "Violência Realista" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "Sem informações acerca de violência realista" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "Violência com Presença de Sangue" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "Sem informações acerca de violência com presença de sangue" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "Violência Sexual" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "Sem informações acerca de violência sexual" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "Álcool" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "Sem informações acerca de referências à álcool" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "Narcóticos" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "Sem informações acerca de referências a drogas ilícitas" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "Tabaco" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "Sem informações acerca de referências a produtos de tabaco" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "Nudez" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "Sem informações acerca de nenhum tipo de nudez" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "Temas Sexuais" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "" "Sem informações acerca de referências ou retratações a nenhum tipo de " "natureza sexual" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "Profanidade" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "Sem informações acerca de nenhum tipo de profanidade" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "Humor Inapropriado" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "Sem informações acerca de humor inapropriado" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "Discriminação" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "Sem informações acerca de nenhum tipo de linguagem discriminatória" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "Propaganda" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "Sem informações acerca de nenhum tipo de propaganda" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "Apostas ou Jogos de Azar" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "Sem informações acerca de nenhum tipo de apostas ou jogos de azar" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "Compras" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "Sem informações acerca de possibilidades de gastar dinheiro" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "Mensagens Entre Usuários" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "Sem informações acerca de formas de se comunicar com outros usuários" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "Comunicações de Áudio Entre Usuários" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "" "Sem informações acerca de formas de se comunicar por áudio com outros " "usuários" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 msgid "Contact Details" msgstr "Detalhes de Contato" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "" "Sem informações acerca de compartilhamento de nomes de usuário de redes " "sociais ou endereços de e-mail" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "Informações de Identidade" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "" "Sem informações acerca de compartilhamento de informações de usuário com " "terceiros" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "Compartilhamento de Localização" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "" "Sem informações acerca de compartilhamento de localização com outros usuários" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "Prostituição" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "Sem informações acerca de referências a prostituição" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "Adultério" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "Sem informações acerca de referências a adultério" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "Personagens Sexualizados" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "Sem informações acerca de personagens sexualizados" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 msgid "Desecration" msgstr "Profanação" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "Sem informações acerca de referências a profanação" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "Restos Humanos" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "Sem informações acerca de restos humanos mortos visíveis" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "Escravidão" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "Sem informações acerca de referências a escravidão" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "Não inclui referências a drogas" #: src/bz-age-rating-dialog.c:426 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "" "Não inclui linguagem de teor ofensivo, profanidade e nenhum outro tipo de " "linguagem inapropriada" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "Não inclui anúncios ou transações monetárias" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "Não inclui sexo ou nudez" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "Não inclui funcionalidade não controlada de comunicação" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "Não inclui violência" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "Drogas" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "Linguagem Imprópria" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "Dinheiro" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "Social" #: src/bz-age-rating-dialog.c:479 msgid "Violence" msgstr "Violência" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:676 src/bz-full-view.c:328 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:701 msgctxt "Age rating" msgid "All" msgstr "Livre" #: src/bz-age-rating-dialog.c:737 #, c-format msgid "%s has an unknown age rating" msgstr "%s possui classificação indicativa desconhecida" #: src/bz-age-rating-dialog.c:743 #, c-format msgid "%s is suitable for everyone" msgstr "%s é adequado para todos" #: src/bz-age-rating-dialog.c:746 #, c-format msgid "%s is suitable for young children" msgstr "%s é adequado para crianças pequenas" #: src/bz-age-rating-dialog.c:749 #, c-format msgid "%s is suitable for children" msgstr "%s é adequado para crianças" #: src/bz-age-rating-dialog.c:752 #, c-format msgid "%s is suitable for teenagers" msgstr "%s é adequado para adolecentes" #: src/bz-age-rating-dialog.c:755 #, c-format msgid "%s is suitable for adults" msgstr "%s é adequado para adultos" #: src/bz-age-rating-dialog.c:758 #, c-format msgid "%s is suitable for %s" msgstr "%s é adequado para %s" #: src/bz-age-rating-dialog.c:852 #, c-format msgid "%s • %s" msgstr "%s • %s" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:29 #: src/bz-user-data-page.blp:15 src/bz-window.blp:292 msgid "Main Menu" msgstr "Menu Principal" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 #: src/bz-user-data-page.blp:19 src/bz-window.blp:384 msgid "_Donate to Bazaar ❤️" msgstr "_Doar para o Bazaar ❤️" #: src/bz-all-apps-page.blp:25 src/bz-apps-page.blp:25 #: src/bz-user-data-page.blp:26 src/bz-window.blp:391 msgid "_Preferences" msgstr "_Preferências" #: src/bz-all-apps-page.blp:30 src/bz-apps-page.blp:30 #: src/bz-user-data-page.blp:31 src/bz-window.blp:396 msgid "_Login with Flathub" msgstr "_Entrar com Flathub" #: src/bz-all-apps-page.blp:36 src/bz-apps-page.blp:36 #: src/bz-user-data-page.blp:37 src/bz-window.blp:402 msgid "_Manage Leftover User Data" msgstr "_Gerenciar Dados de Usuário Restantes" #: src/bz-all-apps-page.blp:41 src/bz-apps-page.blp:41 #: src/bz-user-data-page.blp:42 src/bz-window.blp:407 msgid "_Synchronize Remotes" msgstr "_Sincronizar Repositórios" #: src/bz-all-apps-page.blp:46 src/bz-apps-page.blp:46 #: src/bz-user-data-page.blp:47 src/bz-window.blp:412 msgid "_Keyboard Shortcuts" msgstr "_Atalhos de Teclado" #: src/bz-all-apps-page.blp:51 src/bz-apps-page.blp:51 #: src/bz-user-data-page.blp:52 src/bz-window.blp:417 msgid "_About Bazaar" msgstr "_Sobre o Bazaar" #: src/bz-all-apps-page.blp:58 src/bz-apps-page.blp:58 #: src/bz-user-data-page.blp:59 src/bz-window.blp:424 msgid "_Quit Bazaar" msgstr "_Sair do Bazaar" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "Pasta do Sistema %s" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "Subpasta da Pasta pessoal %s" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "Pastas host do sistema" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "Configurações host do sistema de /etc" #: src/bz-app-permissions.c:169 #, c-format msgid "Desktop subfolder %s" msgstr "Subpasta do Desktop %s" #: src/bz-app-permissions.c:170 msgid "Desktop folder" msgstr "Pasta do Desktop" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "Subpasta de Documentos %s" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "Pasta de Documentos" #: src/bz-app-permissions.c:177 #, c-format msgid "Music subfolder %s" msgstr "Subpasta de Músicas %s" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "Pasta de Músicas" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "Subpasta de images %s" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "Pasta de imagens" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "Subpasta de Compartilhamento Público %s" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "Pasta de Compartilhamento Público" #: src/bz-app-permissions.c:189 #, c-format msgid "Videos subfolder %s" msgstr "Subpasta de Vídeos %s" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "Pasta de Vídeos" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "Subpasta de Modelos %s" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "Pasta de Modelos" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "Subpasta de cache de usuário %s" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "Pasta de cache de usuário" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "Subpasta de configuração de usuário %s" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "Pasta de configuração de usuário" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "Subpasta de dados de usuário %s" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "Pasta de dados de usuário" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "Subpasta de runtime de usuário %s" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "Pasta de runtime de usuário" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "Acesso ao sistema de arquivos para %s" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "Diretório do sistema de arquivos desconhecido" #: src/bz-app-size-dialog.blp:29 src/bz-app-size-dialog.blp:55 msgid "Download Size" msgstr "Tamanho do Download" #: src/bz-app-size-dialog.blp:56 msgid "Amount to download from the internet" msgstr "Quantidade a ser baixada da internet" #: src/bz-app-size-dialog.blp:76 msgid "Installed Size" msgstr "Tamanho Instalado" #: src/bz-app-size-dialog.blp:77 msgid "Size on Disk" msgstr "Tamanho no Disco" #: src/bz-app-size-dialog.blp:99 msgid "User Data Size" msgstr "Tamanho dos Dados de Usuário" #: src/bz-app-size-dialog.blp:100 msgid "Caches, settings, and other app data" msgstr "Caches, configurações e outros dados do app" #. Translators: As in 'The app is installed'. #: src/bz-app-tile.blp:86 src/bz-full-view.c:287 src/bz-releases-list.c:178 msgid "Installed" msgstr "Instalados" #: src/bz-apps-page.blp:142 msgid "Show All" msgstr "Mostrar Tudo" #: src/bz-apps-page.c:243 #, c-format msgid "All \"%s\"" msgstr "Todos \"%s\"" #: src/bz-apps-page.c:530 src/bz-tag-list.c:109 #, c-format msgid "%d Applications" msgstr "%d Aplicativos" #: src/bz-application.c:674 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:675 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #: src/bz-application.c:703 msgid "Adam Masciola" msgstr "Adam Masciola" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:706 msgid "translator-credits" msgstr "" "João Victor , 2025\n" "Rin Koito , 2025" #: src/bz-application.c:717 msgid "Special Thanks" msgstr "Agradecimentos Especiais" #: src/bz-application.c:775 msgid "Logged Out Successfully!" msgstr "Desconectado com Sucesso!" #: src/bz-application.c:898 msgid "Performing setup..." msgstr "Realizando configuração" #: src/bz-application.c:981 src/bz-application.c:990 msgid "Set Up Flathub" msgstr "Configurando Flathub" #: src/bz-application.c:984 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub não configurado neste sistema. Você não poderá navegar e instalar " "aplicativos no Bazaar se estiver indisponível.\n" "\n" "Você ainda pode utilizar o Bazaar para navegador e remover aplicativos já " "instalados." #: src/bz-application.c:989 msgid "Later" msgstr "Depois" #: src/bz-application.c:1399 src/bz-application.c:3116 msgid "Synchronizing..." msgstr "Sincronizando..." #: src/bz-application.c:1546 src/bz-application.c:3112 #, c-format msgid "Receiving %d entries..." msgstr "Obtendo %d entradas" #: src/bz-application.c:1551 msgid "Checking for updates" msgstr "Verificando atualizações" #: src/bz-application.c:3118 msgid "Indexing Data..." msgstr "Indexando Dados..." #: src/bz-appstream-parser.c:265 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Página do Flathub" #: src/bz-appstream-parser.c:286 msgctxt "Project URL Type" msgid "Project Website" msgstr "Site do Projeto" #: src/bz-appstream-parser.c:290 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Rastreador de problemas" #: src/bz-appstream-parser.c:294 msgctxt "Project URL Type" msgid "FAQ" msgstr "Perguntas Mais Frequentes" #: src/bz-appstream-parser.c:298 msgctxt "Project URL Type" msgid "Help" msgstr "Ajuda" #: src/bz-appstream-parser.c:302 msgctxt "Project URL Type" msgid "Donate" msgstr "Doar" #: src/bz-appstream-parser.c:308 msgctxt "Project URL Type" msgid "Translate" msgstr "Traduzir" #: src/bz-appstream-parser.c:312 msgctxt "Project URL Type" msgid "Contact" msgstr "Contatar" #: src/bz-appstream-parser.c:316 msgctxt "Project URL Type" msgid "Source Code" msgstr "Código Fonte" #: src/bz-appstream-parser.c:322 msgctxt "Project URL Type" msgid "Contribute" msgstr "Contribuir" #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:68 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:61 #: src/bz-library-page.blp:59 src/bz-user-data-page.blp:86 msgid "Empty" msgstr "Vazio" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "Sem Recomendações" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "Não há informação curada neste sistema. Você ainda pode navegar por no " "Flathub" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "Navegar Flathub" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "Offline" #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 msgid "Browser" msgstr "Navegador" #: src/bz-developer-badge.c:131 msgid "Developer information not available." msgstr "Informações sobre desenvolveres não está disponível" #: src/bz-developer-badge.c:137 src/bz-developer-badge.c:151 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "" "A propriedade do ID do aplicativo %s não foi verificada e talvez seja um " "pacote da comunidade." #: src/bz-developer-badge.c:155 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "" "A propriedade do ID do aplicativo %s foi manualmente verificada pelo time do " "Flathub." #: src/bz-developer-badge.c:161 #, c-format msgid "" "The ownership of the %1$s app ID has been verified by %2$s on " "%3$s." msgstr "" "A propriedade do ID do aplicativo %1$s foi verificada por %2$s em " "%3$s." #: src/bz-developer-badge.c:168 #, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "A propriedade do ID do aplicativo %1$s foi verificada utilizando %2$s." #: src/bz-developer-badge.c:172 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "A propriedade do ID do aplicativo %s foi verificada." #: src/bz-donations-dialog.blp:47 msgid "View the Release Page" msgstr "Visualizar Página de Lançamento" #: src/bz-donations-dialog.blp:69 msgid "This Bazaar Release Was Made Possible By Users Like You!" msgstr "Esta Versão do Bazaar Foi Possível Graças A Usuários Como Você!" #: src/bz-donations-dialog.blp:77 msgid "" "I love making Bazaar, but I cannot do it alone. If you would like to help " "support further development, please consider donating to the project at my " "ko-fi:" msgstr "" "Eu amo fazer o Bazaar, mas eu não consigo fazê-lo sem ajuda. Se você quiser " "ajudar o desenvolvimento, por favor, considere doar para o projeto no meu ko-" "fi:" #: src/bz-donations-dialog.blp:87 msgid "Donate to Bazaar" msgstr "_Doar para o Bazaar" #. Translators: the %s format specifier will be something along the lines of "0.7.6" etc #: src/bz-donations-dialog.c:156 #, c-format msgid "What's New in Version %s?" msgstr "O Que Tem na Nova Versão %s?" #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "Escolha uma Instalação" #: src/bz-entry-group-util.c:76 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "" "Você tem várias versões deste aplicativo instaladas. Com qual você gostaria " "de prosseguir?" #: src/bz-entry-group-util.c:80 src/bz-transaction-dialog.c:201 #: src/bz-transaction-dialog.c:230 src/bz-transaction-dialog.c:275 #: src/bz-transaction-dialog.c:578 msgid "Cancel" msgstr "Cancelar" #: src/bz-entry-selection-row.blp:17 msgid "For this user only" msgstr "Somente para este usuário" #: src/bz-entry-selection-row.c:112 msgid "this user" msgstr "este usuário" #: src/bz-entry-selection-row.c:112 msgid "all users" msgstr "todos usuários" #: src/bz-error.c:68 msgid "An Error Occurred" msgstr "Um Erro Ocorreu" #: src/bz-error.c:89 msgid "Close" msgstr "Fechar" #: src/bz-error.c:90 msgid "Copy and Close" msgstr "Copiar e Fechar" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "Faça login com o Flathub para gerenciar seus favoritos" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "Entrar" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "Contagem de Favoritos" #: src/bz-favorites-tile.c:157 msgid "Uninstall" msgstr "Desinstalar" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:77 msgid "Support this application" msgstr "Apoiar este aplicativo" #: src/bz-favorites-tile.blp:119 msgid "Remove from Favorites" msgstr "Remover dos Favoritos" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:78 #: src/bz-window.blp:442 msgid "Favorites" msgstr "Favoritos" #: src/bz-favorites-page.blp:17 src/bz-section-view.blp:144 #: src/bz-transaction-dialog.c:579 msgid "Install All" msgstr "Instalar Todos" #: src/bz-favorites-page.blp:34 src/bz-full-view.blp:44 src/bz-window.blp:307 msgid "Open App Library" msgstr "Abrir Biblioteca de Apps" #: src/bz-favorites-page.blp:56 src/bz-user-data-page.blp:75 msgid "Loading" msgstr "Carregando" #: src/bz-favorites-page.blp:71 msgid "No Favorites" msgstr "Sem Favoritos" #: src/bz-favorites-page.blp:72 msgid "Applications you mark as favorite will appear here" msgstr "Aplicativos que você marcar como favoritos aparecerão aqui" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "Anterior" #: src/bz-featured-carousel.blp:53 msgid "Next" msgstr "Próximo" #: src/bz-featured-tile.blp:88 msgid "App of the Day" msgstr "Aplicativo do Dia" #: src/bz-flathub-category.c:89 msgid "Editing" msgstr "Editação" #: src/bz-flathub-category.c:90 msgid "Midi" msgstr "Midi" #: src/bz-flathub-category.c:91 msgid "Mixer" msgstr "Mixagem" #: src/bz-flathub-category.c:92 msgid "Music" msgstr "Música" #: src/bz-flathub-category.c:93 msgid "Player" msgstr "Reprodutor de Mídia" #: src/bz-flathub-category.c:94 msgid "Recorder" msgstr "Gravador" #: src/bz-flathub-category.c:95 msgid "Sequencer" msgstr "Sequenciador" #: src/bz-flathub-category.c:96 msgid "Tuner" msgstr "Sintonizador" #: src/bz-flathub-category.c:97 msgid "TV" msgstr "TV" #: src/bz-flathub-category.c:102 msgid "Emulation" msgstr "Emulação" #: src/bz-flathub-category.c:103 msgid "Action" msgstr "Ação" #: src/bz-flathub-category.c:104 msgid "Adventure" msgstr "Aventura" #: src/bz-flathub-category.c:105 msgid "Arcade" msgstr "Arcade" #: src/bz-flathub-category.c:106 msgid "Blocks" msgstr "Blocos" #: src/bz-flathub-category.c:107 msgid "Board" msgstr "Tabuleiro" #: src/bz-flathub-category.c:108 msgid "Card" msgstr "Carta" #: src/bz-flathub-category.c:109 msgid "Kids" msgstr "Crianças" #: src/bz-flathub-category.c:110 msgid "Logic" msgstr "Lógica" #: src/bz-flathub-category.c:111 msgid "Role Playing" msgstr "Role Playing" #: src/bz-flathub-category.c:112 msgid "Shooter" msgstr "Tiro" #: src/bz-flathub-category.c:113 msgid "Simulation" msgstr "Simulação" #: src/bz-flathub-category.c:114 msgid "Sports" msgstr "Estportes" #: src/bz-flathub-category.c:115 msgid "Strategy" msgstr "Estratégia" #: src/bz-flathub-category.c:120 msgid "Audio & Video" msgstr "Áudio & Vídeo" #: src/bz-flathub-category.c:120 msgid "Media" msgstr "Mídia" #: src/bz-flathub-category.c:120 msgid "More Audio & Video" msgstr "Mais Áudio e Vídeo" #: src/bz-flathub-category.c:121 msgid "Developer Tools" msgstr "Ferramentas de desenvolvedores" #: src/bz-flathub-category.c:121 msgid "Develop" msgstr "Desenvolver" #: src/bz-flathub-category.c:121 msgid "More Developer Tools" msgstr "Mais Ferramentas de desenvolvedores" #: src/bz-flathub-category.c:122 msgid "Education" msgstr "Educação" #: src/bz-flathub-category.c:122 msgid "Learn" msgstr "Aprender" #: src/bz-flathub-category.c:122 msgid "More Education" msgstr "Mais Educação" #: src/bz-flathub-category.c:123 msgid "Gaming" msgstr "Jogos" #: src/bz-flathub-category.c:123 msgid "Play" msgstr "Jogar" #: src/bz-flathub-category.c:123 msgid "More Gaming" msgstr "Mais Jogos" #: src/bz-flathub-category.c:124 msgid "Graphics & Photography" msgstr "Gráficos e Fotografia" #: src/bz-flathub-category.c:124 msgid "Create" msgstr "Criar" #: src/bz-flathub-category.c:124 msgid "More Graphics & Photography" msgstr "Mais Gráficos e Fotografia" #: src/bz-flathub-category.c:125 msgid "Networking" msgstr "Conectividade" #: src/bz-flathub-category.c:125 msgid "Internet" msgstr "Comunicação" #: src/bz-flathub-category.c:125 msgid "More Networking" msgstr "Mais Comunicação" #: src/bz-flathub-category.c:126 msgid "Productivity" msgstr "Produtividade" #: src/bz-flathub-category.c:126 msgid "Work" msgstr "Trabalho" #: src/bz-flathub-category.c:126 msgid "More Productivity" msgstr "Mais Produtividade" #: src/bz-flathub-category.c:127 msgid "Science" msgstr "Ciência" #: src/bz-flathub-category.c:127 msgid "More Science" msgstr "Mais Ciência" #: src/bz-flathub-category.c:128 msgid "System" msgstr "Sistema" #: src/bz-flathub-category.c:128 msgid "More System" msgstr "Mais Sistema" #: src/bz-flathub-category.c:129 msgid "Utilities" msgstr "Utilitários" #: src/bz-flathub-category.c:129 msgid "Tools" msgstr "Ferramentas" #: src/bz-flathub-category.c:129 msgid "More Utilities" msgstr "Mais Utilitários" #: src/bz-flathub-category.c:130 src/bz-flathub-page.blp:119 #: src/bz-flathub-page.blp:152 msgid "Trending" msgstr "Em Alta" #: src/bz-flathub-category.c:130 msgid "More Trending" msgstr "Mais Em Alta" #: src/bz-flathub-category.c:131 src/bz-flathub-page.blp:125 #: src/bz-flathub-page.blp:185 msgid "Popular" msgstr "Populares" #: src/bz-flathub-category.c:131 msgid "More Popular" msgstr "Mais Populares" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:174 msgid "Recently Added" msgstr "Recentemente Adicionados" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:131 msgid "New" msgstr "Novos" #: src/bz-flathub-category.c:132 msgid "More New" msgstr "Mais Novos" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:163 msgid "Recently Updated" msgstr "Recentemente Atualizados" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:137 msgid "Updated" msgstr "Atualizados" #: src/bz-flathub-category.c:133 msgid "More Updated" msgstr "Mais Atualizados" #: src/bz-flathub-category.c:134 msgid "Mobile" msgstr "Aplicativos Móveis" #: src/bz-flathub-category.c:134 msgid "More Mobile" msgstr "Mais Aplicativos Móveis" #: src/bz-flathub-category.c:135 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:135 msgid "More Adwaita" msgstr "Mais Adwaita" #: src/bz-flathub-category.c:136 msgid "KDE Apps" msgstr "Apps KDE" #: src/bz-flathub-category.c:136 msgid "More KDE Apps" msgstr "Mais Apps KDE" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Flathub não Adicionado" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "" "O repositório do Flathub não foi encontrado por nenhuma de suas instalações " "de Flatpak" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "Flathub retornou um erro" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "Tentar conexão ao Flathub novamente" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Flathub Indisponível" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" "Não conseguimos conectar ao Flathub. Você ainda pode gerenciar e pesquisar " "por aplicativos." #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "Procurar Apps" #: src/bz-flathub-page.blp:270 msgid "On the Go" msgstr "Em movimento" #: src/bz-flathub-page.blp:282 msgid "Apps for your Linux phones and tablets" msgstr "Aplicativos para seus telefones e tablets Linux" #: src/bz-flathub-page.blp:293 src/bz-flathub-page.blp:328 msgid "More Mobile Apps" msgstr "Mais Aplicativos Móveis" #: src/bz-flathub-page.blp:388 msgid "We​ ♥​ Games" msgstr "Nós♥Jogos" #: src/bz-flathub-page.blp:401 msgid "Games and apps to run your favorite titles" msgstr "Jogos e aplicativos para rodar seus títulos favoritos" #: src/bz-flathub-page.blp:435 msgid "More Games" msgstr "Mais Jogos" #: src/bz-full-view.blp:65 src/bz-library-page.blp:70 #: src/bz-library-page.blp:74 msgid "No Results" msgstr "Sem Resultados" #: src/bz-full-view.blp:66 msgid "Try a different search query" msgstr "Tente outro termo de pesquisa" #: src/bz-full-view.blp:72 msgid "Content" msgstr "Conteúdo" #: src/bz-full-view.blp:130 msgid "Installing .flatpak bundles is not yet supported" msgstr "Instalar bundles .flatpak ainda não é suportado" #: src/bz-full-view.blp:223 msgid "Support" msgstr "Apoiar" #: src/bz-full-view.blp:246 src/bz-full-view.blp:506 msgid "Open" msgstr "Abrir" #: src/bz-full-view.blp:259 src/bz-full-view.blp:479 msgid "Download & Install Application" msgstr "Baixar & Instalar Aplicativo" #: src/bz-full-view.blp:274 msgid "Uninstall Application" msgstr "Desinstalar Aplicativo" #: src/bz-full-view.blp:289 src/bz-full-view.blp:521 msgid "Install Other Version" msgstr "Instalar Outra Versão" #: src/bz-full-view.blp:443 msgid "Downloads/Month" msgstr "Downloads/Mês" #: src/bz-full-view.blp:540 msgid "Stopped Receiving Core Updates" msgstr "Parou de receber atualizações críticas" #: src/bz-full-view.blp:554 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "Este aplicativo utiliza um runtime que não recebe mais atualizações ou " "atualizações de segurança. Talvez se torne inseguro para uso." #: src/bz-full-view.blp:643 msgid "Trash Data" msgstr "Deletar dados" #: src/bz-full-view.blp:784 msgid "Tags:" msgstr "Etiquetas:" #: src/bz-full-view.c:227 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:234 #, c-format msgid "%.*fM" msgstr "%.*fM" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:241 #, c-format msgid "%.*fK" msgstr "%.*fK" #: src/bz-full-view.c:251 #, c-format msgid "%d downloads in the last 30 days" msgstr "%d downloads nos últimos 30 dias" #: src/bz-full-view.c:263 src/bz-full-view.c:597 src/bz-full-view.c:614 msgid "N/A" msgstr "N/A" #. Translators: . #: src/bz-full-view.c:287 msgid "Download" msgstr "Download" #: src/bz-full-view.c:307 msgid "Size information unavailable" msgstr "Informação sobre o tamanho não disponível" #: src/bz-full-view.c:310 #, c-format msgid "Download size of %s" msgstr "Tamanho do download de %s" #: src/bz-full-view.c:343 msgid "All Ages" msgstr "Todas as idades" #: src/bz-full-view.c:355 msgid "Age rating information unavailable" msgstr "Classificação indicativa indisponível" #: src/bz-full-view.c:360 msgid "Suitable for all ages" msgstr "Adequado para todas as idades" #: src/bz-full-view.c:362 #, c-format msgid "Suitable for ages %d and up" msgstr "Adequado para idades de %d anos ou mais" #: src/bz-full-view.c:395 src/bz-full-view.c:400 src/bz-full-view.c:428 #: src/bz-full-view.c:439 msgid "Unknown" msgstr "Desconhecido" #: src/bz-full-view.c:405 #, c-format msgid "Free software licensed under %s" msgstr "Software livre sob a licença %s" #: src/bz-full-view.c:410 msgid "Free software" msgstr "Software Livre" #: src/bz-full-view.c:413 msgid "Proprietary Software" msgstr "Software Proprietário" #: src/bz-full-view.c:416 #, c-format msgid "Special License: %s" msgstr "Licença Especial: %s" #: src/bz-full-view.c:433 msgid "Free" msgstr "Livre" #: src/bz-full-view.c:436 src/bz-license-dialog.c:132 msgid "Proprietary" msgstr "Proprietário" #: src/bz-full-view.c:441 src/bz-license-dialog.c:134 msgid "Special License" msgstr "Licença Especial" #: src/bz-full-view.c:461 msgid "Adaptive" msgstr "Adaptativo" #: src/bz-full-view.c:461 msgid "Desktop Only" msgstr "Somente Desktop" #: src/bz-full-view.c:467 msgid "Works on desktop, tablets, and phones" msgstr "Funciona em desktops, tablets e celulares" #: src/bz-full-view.c:468 msgid "May not work on mobile devices" msgstr "Talvez não funcione em dispositivos móveis" #: src/bz-full-view.c:479 msgid "No URL" msgstr "Sem URL" #: src/bz-full-view.c:497 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Este aplicativo tem uma licença livre e de código aberto, o que significa " "que o código fonte pode ser auditável por segurança." #: src/bz-full-view.c:498 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Este aplicativo tem uma licença proprietária, o que significa que o código " "fonte é desenvolvido de maneira privada e não pode ser auditável por " "terceiros." #: src/bz-full-view.c:505 msgid "More Apps" msgstr "Mais Aplicativos" #: src/bz-full-view.c:506 #, c-format msgid "More Apps by %s" msgstr "Mais Aplicativos de %s" #: src/bz-full-view.c:513 msgid "Other Apps by this Developer" msgstr "Outros Aplicativos Deste Desenvolvedor" #: src/bz-full-view.c:515 src/bz-full-view.c:715 #, c-format msgid "Other Apps by %s" msgstr "Outros Aplicativos de %s" #: src/bz-full-view.c:524 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "%s não está instalado, mas ainda possui %s de dados presentes." #: src/bz-full-view.c:604 src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "Seguro" #: src/bz-full-view.c:606 src/bz-full-view.c:608 msgid "Low Risk" msgstr "Baixo Risco" #: src/bz-full-view.c:610 msgid "Medium Risk" msgstr "Médio Risco" #: src/bz-full-view.c:612 msgid "High Risk" msgstr "Alto Risco" #: src/bz-full-view.c:717 msgid "Other Apps" msgstr "Outros Aplicativos" #: src/bz-full-view.c:719 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d Aplicativo" msgstr[1] "%d Aplicativos" #: src/bz-full-view.c:1058 msgid "Show Less" msgstr "Mostrar Menos" #: src/bz-full-view.c:1058 msgid "Show More" msgstr "Mostrar Mais" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 msgid "Hardware Support" msgstr "Suporte a Hardware" #: src/bz-hardware-support-dialog.c:62 msgid "Keyboard support" msgstr "Suporte a Teclado" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "Precisa de teclado" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "Teclado recomendado" #: src/bz-hardware-support-dialog.c:66 msgid "Supports keyboards" msgstr "Suporta teclados" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "Suporte a teclado desconhecido" #: src/bz-hardware-support-dialog.c:69 msgid "Mouse support" msgstr "Suporte a mouse" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "Precisa de mouse ou dispositivo de indicação" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "Recomenda mouse ou dispositivo de indicação" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "Suporta mouse ou dispositivo de indicação" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "Suporte para mouses ou dispositivos de indicação desconhecido" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "Suporte a tela sensível ao toque" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "Precisa de tela sensível ao toque" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "Recomenda tela sensível ao toque" #: src/bz-hardware-support-dialog.c:80 msgid "Supports touchscreens" msgstr "Suporta tela sensível ao toque" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "Suporte a telas sensíveis ao toque desconhecido" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "Suporte a dispositivos móveis" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "Funciona em dispositivos móveis" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "Talvez não funcione bem em dispositivos móveis" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "Suporte a Desktop" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "Funciona bem em telas grandes" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "%s funciona melhor em hardwares específicos" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "%s funciona na maioria dos dispositivos" #: src/bz-installed-tile.blp:63 src/bz-rich-app-tile.blp:136 msgid "Stopped Receiving Updates" msgstr "Parou de Receber Atualizações" #: src/bz-library-page.blp:29 msgid "Search installed apps" msgstr "Pesquisar apps instalados" #: src/bz-library-page.blp:63 msgid "No Apps Found" msgstr "Nenhum App Encontrado" #. Translators: . #: src/bz-library-page.blp:82 src/bz-window.blp:179 msgid "Library" msgstr "Biblioteca" #: src/bz-library-page.blp:110 msgid "Pending Updates" msgstr "Atualizações pendentes" #: src/bz-library-page.blp:137 msgid "Downloads" msgstr "Downloads" #: src/bz-library-page.blp:180 msgid "Recently Uninstalled" msgstr "Recentemente Desinstalado" #: src/bz-library-page.blp:231 msgid "Clear Finished Tasks" msgstr "Limpar Tarefas Finalizadas" #: src/bz-library-page.blp:242 msgid "Installed Apps" msgstr "Apps Instalados" #: src/bz-library-page.c:153 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "Nenhum resultado encontrado para \"%s\" na lista de apps instalados" #: src/bz-library-page.c:166 src/bz-updates-card.c:257 #, c-format msgid "%u Available Update" msgid_plural "%u Available Updates" msgstr[0] "%u Atualização Disponível" msgstr[1] "%u Atualizações Disponíveis" #: src/bz-license-dialog.blp:95 msgid "Get Involved" msgstr "Envolva-se" #: src/bz-license-dialog.c:126 msgid "Unknown License" msgstr "Licença Desconhecida" #: src/bz-license-dialog.c:129 msgid "Community Built" msgstr "Feito pela Comunidade" #: src/bz-license-dialog.c:202 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Este aplicativo é desenvolvido em aberto por uma comunidade internacional.\n" "\n" "Você pode participar e ajudar a o tornar ainda melhor." #: src/bz-license-dialog.c:205 msgid "The license of this app is not known" msgstr "A licença deste aplicativo é desconhecida" #: src/bz-license-dialog.c:211 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Este aplicativo é desenvolvido em aberto por uma comunidade internacional e " "é distribuído sob a licença %s.\n" "\n" "Você pode participar e ajudar a torná-lo ainda melhor." #: src/bz-license-dialog.c:219 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Este aplicativo não é desenvolvido em código aberto, então somente os " "desenvolvedores sabem como ele funciona. Ele talvez seja inseguro de formas " "que são difíceis de detectar e pode mudar sem supervisão.\n" "\n" "Você talvez não possa contribuir para este aplicativo." #: src/bz-license-dialog.c:225 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Este aplicativo é desenvolvido sob a licença especial %s.\n" "\n" "Você talvez não possa contribuir para este aplicativo." #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 msgid "Connect to Flathub" msgstr "Conectar-se ao Flathub" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "Algo Deu Errado" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "" "Connect sua conta do Flathub ao Bazaar para gerenciar seus apps favoritos." #: src/bz-login-page.blp:108 msgid "Finish" msgstr "Finalizar" #: src/bz-login-page.c:664 #, c-format msgid "Hello, %s!" msgstr "Olá, %s!" #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Preferências" #: src/bz-preferences-dialog.blp:25 msgid "Network connection is metered — automatic store data sync is paused" msgstr "" "Sua conexão é limitada - sincronização de dados automática da loja pausada" #: src/bz-preferences-dialog.blp:26 src/bz-window.blp:334 msgid "Sync Manually" msgstr "Sincronizar Manualmente" #: src/bz-preferences-dialog.blp:31 msgid "Content Filters" msgstr "Filtros de Conteúdo" #: src/bz-preferences-dialog.blp:34 msgid "Free Software Only" msgstr "Somente Software Livre" #: src/bz-preferences-dialog.blp:35 msgid "Hide proprietary applications when browsing and searching" msgstr "" "Ocultar aplicativos proprietários dos resultados de navegação e pesquisa" #: src/bz-preferences-dialog.blp:39 msgid "Flathub Results Only" msgstr "Somente Resultados do Flathub" #: src/bz-preferences-dialog.blp:40 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "" "Limitar resultados de navegação e pesquisa aos aplicativos disponíveis no " "Flathub" #: src/bz-preferences-dialog.blp:44 msgid "Verified Results Only" msgstr "Somente Resultados Verificados" #: src/bz-preferences-dialog.blp:45 msgid "Hide results that are not verified on Flathub" msgstr "Ocultar resultados que não são verificados no Flathub" #: src/bz-preferences-dialog.blp:49 msgid "Hide EOL Apps" msgstr "Ocultar Aplicativos em fim de vida (EOL)" #: src/bz-preferences-dialog.blp:50 msgid "Hide apps which are no longer supported by their developers" msgstr "" "Ocultar aplicativos que não são mais suportados por seus desenvolvedores" #: src/bz-preferences-dialog.blp:55 src/bz-window.blp:197 msgid "Search" msgstr "Pesquisar" #: src/bz-preferences-dialog.blp:58 msgid "Delay Search Results" msgstr "Atrasar Resultados de Pesquisa" #: src/bz-preferences-dialog.blp:59 msgid "Improve results performance by debouncing search terms" msgstr "" "Melhorar resultados de performance utilizando debouncing nos termos " "pesquisados" #: src/bz-preferences-dialog.blp:64 msgid "Progress Bar" msgstr "Barra de Progresso" #: src/bz-preferences-dialog.blp:65 msgid "Choose a theme for the progress bar!" msgstr "Escolha um tema para a barra de progresso!" #: src/bz-preferences-dialog.blp:89 msgid "Vertical Stripes" msgstr "Listras Verticais" #: src/bz-preferences-dialog.blp:90 msgid "Display flag colors from left to right" msgstr "Mostrar as cores das bandeiras da esquerda para a direita" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Cor de destaque" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Cores de Orgulho" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "Cores do Orgulho Lésbico" #: src/bz-preferences-dialog.c:35 msgid "Male Homosexual Pride Colors" msgstr "Cores do Orgulho Homossexual Masculino" #: src/bz-preferences-dialog.c:36 msgid "Transgender Pride Colors" msgstr "Cores do Orgulho Transgênero" #: src/bz-preferences-dialog.c:37 msgid "Nonbinary Pride Colors" msgstr "Cores do Orgulho Não Binário" #: src/bz-preferences-dialog.c:38 msgid "Bisexual Pride Colors" msgstr "Cores do Orgulho Bisexual" #: src/bz-preferences-dialog.c:39 msgid "Asexual Pride Colors" msgstr "Cores do Orgulho Asexual" #: src/bz-preferences-dialog.c:40 msgid "Pansexual Pride Colors" msgstr "Cores do Orgulho Pansexual" #: src/bz-preferences-dialog.c:41 msgid "Aromantic Pride Colors" msgstr "Cores do Orgulho Arromântico" #: src/bz-preferences-dialog.c:42 msgid "Genderfluid Pride Colors" msgstr "Cores do Orgulho Gênero Fluído" #: src/bz-preferences-dialog.c:43 msgid "Polysexual Pride Colors" msgstr "Cores do Orgulho Polissexual" #: src/bz-preferences-dialog.c:44 msgid "Omnisexual Pride Colors" msgstr "Cores do Orgulho Omnissexual" #: src/bz-preferences-dialog.c:45 msgid "Aroace Pride Colors" msgstr "Cores do Orgulho Aroace" #: src/bz-preferences-dialog.c:46 msgid "Agender Pride Colors" msgstr "Cores do Orgulho Agênero" #: src/bz-preferences-dialog.c:47 msgid "Genderqueer Pride Colors" msgstr "Cores do Orgulho Genderqueer" #: src/bz-preferences-dialog.c:48 msgid "Intersex Pride Colors" msgstr "Cores do Orgulho Intersexo" #: src/bz-preferences-dialog.c:49 msgid "Demigender Pride Colors" msgstr "Cores do Orgulho Demigênero" #: src/bz-preferences-dialog.c:50 msgid "Biromantic Pride Colors" msgstr "Cores do Orgulho Birromântico" #: src/bz-preferences-dialog.c:51 msgid "Disability Pride Colors" msgstr "Cores do Orgulho da Deficiência" #: src/bz-preferences-dialog.c:52 msgid "Femboy Pride Colors" msgstr "Cores do Orgulho Femboy" #: src/bz-preferences-dialog.c:53 msgid "Neutrois Pride Colors" msgstr "Cores do Orgulho Neutrois" #: src/bz-releases-dialog.blp:5 src/bz-releases-list.blp:28 #: src/bz-updates-card.blp:150 msgid "Version History" msgstr "Histórico de Versão" #: src/bz-releases-list.c:168 #, c-format msgid "Version %s" msgstr "Versão %s" #: src/bz-releases-list.c:220 msgid "No details for this release" msgstr "Não há detalhes para este lançamento" #: src/bz-releases-list.c:232 msgid "Get More Information" msgstr "Obter mais informações" #: src/bz-rich-app-tile.blp:153 msgid "Get" msgstr "Obter" #: src/bz-safety-calculator.c:82 msgid "Unknown Permissions" msgstr "Permissões Desconhecidas" #: src/bz-safety-calculator.c:83 msgid "Permissions are missing for this app." msgstr "Estão faltando permissões para este aplicativo." #: src/bz-safety-calculator.c:96 msgid "No Permissions" msgstr "Sem Permissões" #: src/bz-safety-calculator.c:97 msgid "App is fully sandboxed" msgstr "App não é completamente isolado" #: src/bz-safety-calculator.c:103 msgid "Network Access" msgstr "Acesso à Internet" #: src/bz-safety-calculator.c:104 msgid "Can access the internet" msgstr "Pode acessar a internet" #: src/bz-safety-calculator.c:106 msgid "No Network Access" msgstr "Sem Acesso à Rede" #: src/bz-safety-calculator.c:107 msgid "Cannot access the internet" msgstr "Não pode acessar a internet" #: src/bz-safety-calculator.c:112 msgid "User Device Access" msgstr "Acesso a Dispositivos de Usuário" #: src/bz-safety-calculator.c:113 msgid "Can access devices such as webcams or gaming controllers" msgstr "Pode acessar dispositivos como webcams ou controles de jogos" #: src/bz-safety-calculator.c:115 msgid "No User Device Access" msgstr "Sem Acesso a Dispositivos de Usuário" #: src/bz-safety-calculator.c:116 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "Não pode acessar dispositivos como webcams ou controles de jogos" #: src/bz-safety-calculator.c:121 msgid "Input Device Access" msgstr "Acesso a Dispositivos de Entrada" #: src/bz-safety-calculator.c:122 msgid "Can access input devices" msgstr "Pode acessar dispositivos de entrada" #: src/bz-safety-calculator.c:128 msgid "Microphone Access and Audio Playback" msgstr "Acesso a Microfone e Tocar Áudio" #: src/bz-safety-calculator.c:129 msgid "Can listen using microphones and play audio without asking permission" msgstr "Pode ouvir usando microfones e tocar áudio sem pedir permissão" #: src/bz-safety-calculator.c:135 msgid "System Device Access" msgstr "Acesso a Dispositivo do Sistema" #: src/bz-safety-calculator.c:136 msgid "Can access system devices which require elevated permissions" msgstr "Pode acessar dispositivos do sistema que requerem permissões elevadas" #: src/bz-safety-calculator.c:142 msgid "Screen Contents Access" msgstr "Acesso a Conteúdos da Tela" #: src/bz-safety-calculator.c:143 msgid "Can access the contents of the screen or other windows" msgstr "Pode acessar os conteúdos da tela e de outras janelas" #: src/bz-safety-calculator.c:149 msgid "Legacy Windowing System" msgstr "Sistema de Janelas Legado" #: src/bz-safety-calculator.c:150 msgid "Always uses a legacy windowing system (X11)" msgstr "Sempre usa um sistema de janelas legado (X11)" #: src/bz-safety-calculator.c:156 msgid "Arbitrary Permissions" msgstr "Permissões Arbitrárias" #: src/bz-safety-calculator.c:157 msgid "Can acquire arbitrary permissions" msgstr "Pode adquirir permissões arbitrárias" #: src/bz-safety-calculator.c:163 msgid "User Settings" msgstr "Configurações de Usuário" #: src/bz-safety-calculator.c:164 msgid "Can access and change user settings" msgstr "Pode acessar e mudar configurações de usuário" #: src/bz-safety-calculator.c:170 msgid "Full File System Read/Write Access" msgstr "Acesso Total de Leitura/Escrita ao Sistema de Arquivos" #: src/bz-safety-calculator.c:171 msgid "Can read and write all data on the file system" msgstr "Pode ler e escrever todos os dados no sistema de arquivos" #: src/bz-safety-calculator.c:178 msgid "Home Folder Read/Write Access" msgstr "Acesso de Leitura/Escrita à Pasta Pessoal" #: src/bz-safety-calculator.c:179 msgid "Can read and write all data in your home directory" msgstr "Pode ler e escrever todos os dados na sua pasta pessoal" #: src/bz-safety-calculator.c:186 msgid "Full File System Read Access" msgstr "Acesso Total de Leitura ao Sistema de Arquivos" #: src/bz-safety-calculator.c:187 msgid "Can read all data on the file system" msgstr "Pode ler todos os dados no sistema de arquivos" #: src/bz-safety-calculator.c:195 msgid "Home Folder Read Access" msgstr "Acesso de Leitura à Pasta Pessoal" #: src/bz-safety-calculator.c:196 msgid "Can read all data in your home directory" msgstr "Pode ler todos os dados na sua pasta pessoal" #: src/bz-safety-calculator.c:204 msgid "Download Folder Read/Write Access" msgstr "Acesso de Leitura/Escrita à Pasta de Download" #: src/bz-safety-calculator.c:205 msgid "Can read and write all data in your downloads directory" msgstr "Pode ler e escrever todos os dados na sua pasta de downloads" #: src/bz-safety-calculator.c:215 msgid "Download Folder Read Access" msgstr "Acesso de Leitura à Pasta de Downloads" #: src/bz-safety-calculator.c:216 msgid "Can read all data in your downloads directory" msgstr "Pode ler todos os dados na sua pasta de downloads" #: src/bz-safety-calculator.c:229 msgid "Can read and write all data in the directory" msgstr "Pode ler e escrever todos os dados na sua pasta de downloads" #: src/bz-safety-calculator.c:243 msgid "Can read all data in the directory" msgstr "Pode ler todos os dados no diretório" #: src/bz-safety-calculator.c:258 msgid "No File System Access" msgstr "Sem Acesso ao Sistema de Arquivos" #: src/bz-safety-calculator.c:259 msgid "Cannot access the file system at all" msgstr "Não pode acessar o sistema de arquivos de maneira alguma" #: src/bz-safety-calculator.c:266 msgid "Uses System Services" msgstr "Usa Serviços do Sistema" #: src/bz-safety-calculator.c:267 msgid "Can request data from non-portal system services" msgstr "Pode solicitar dados de serviços do sistema que não utilizam portais" #: src/bz-safety-calculator.c:273 msgid "Uses Session Services" msgstr "Usa Serviços de Sessão" #: src/bz-safety-calculator.c:274 msgid "Can request data from non-portal session services" msgstr "Pode solicitar dados de serviços de sessão que não utilizam portais" #: src/bz-safety-calculator.c:322 msgid "No Service Access" msgstr "Sem Acesso a Serviços" #: src/bz-safety-calculator.c:323 msgid "Cannot access non-portal session or system services at all" msgstr "Não pode acessar servições de sessão ou do sistema de maneira alguma" #: src/bz-safety-calculator.c:331 msgid "Verified App Developer" msgstr "Desenvolvedor do App Verificado" #: src/bz-safety-calculator.c:332 msgid "The developer of this app has been verified to be who they say they are" msgstr "O desenvolvedor deste app foi verificado e é quem diz ser" #: src/bz-safety-calculator.c:341 msgid "Proprietary Code" msgstr "Código Proprietário" #: src/bz-safety-calculator.c:342 msgid "" "The source code is not public, so it cannot be independently audited and " "might be unsafe" msgstr "" "O código fonte não é público, então não pode ser auditado independentemente " "e pode ser inseguro" #: src/bz-safety-calculator.c:352 msgid "Auditable Code" msgstr "Código Auditável" #: src/bz-safety-calculator.c:353 msgid "" "The source code is public and can be independently audited, which makes the " "app more likely to be safe" msgstr "" "O código fonte é público e pode ser auditado independentemente, o que torna " "o app potencialmente seguro" #: src/bz-safety-calculator.c:493 #, c-format msgid "Use the %s System Service" msgstr "Usa o Serviço do Sistema %s" #: src/bz-safety-calculator.c:497 #, c-format msgid "Use the %s Session Service" msgstr "Usa a Serviço de Sessão %s" #: src/bz-safety-calculator.c:501 #, c-format msgid "Use the %s Service" msgstr "Usa o Serviço %s" #: src/bz-safety-calculator.c:511 msgid "Can see the non-portal service" msgstr "Pode ver serviços que não usam portais" #: src/bz-safety-calculator.c:513 msgid "Can talk to the non-portal service" msgstr "Pode se comunicar com serviços que não utilizam portais" #: src/bz-safety-calculator.c:515 msgid "Can own the non-portal service" msgstr "Pode ter um serviço que não utiliza portais" #: src/bz-safety-calculator.c:530 msgid "Global Menu Integration" msgstr "Integração de Menu Global" #: src/bz-safety-calculator.c:531 msgid "Can display its menus in a global menu bar" msgstr "Pode mostrar seus menus em uma menu de barra global" #: src/bz-safety-calculator.c:536 msgid "KDE Settings Integration" msgstr "Integração de Configurações do KDE" #: src/bz-safety-calculator.c:537 msgid "Can detect when KDE desktop settings change" msgstr "Pode detectar quando configurações do desktop KDE mudam" #: src/bz-safety-calculator.c:542 msgid "KDE Global Settings" msgstr "Configurações Globais do KDE" #: src/bz-safety-calculator.c:543 msgid "Can read KDE desktop preferences like fonts and colors" msgstr "Pode ler preferência do desktop KDE como fontes e cores" #: src/bz-safety-calculator.c:548 msgid "Secret Storage Service" msgstr "Serviço de Armazenamento Secreto" #: src/bz-safety-calculator.c:549 msgid "Can store and retrieve its own passwords using the system keyring" msgstr "" "Pode guardar e recuperar suas próprias senhas usando o keyring do sistema" #: src/bz-safety-calculator.c:554 msgid "Desktop Notifications Service" msgstr "Serviço de Notificações do Desktop" #: src/bz-safety-calculator.c:555 msgid "Can send desktop notifications" msgstr "Pode mandar notificações de desktop" #: src/bz-safety-calculator.c:561 msgid "System Tray Integration" msgstr "Integração com a Bandeja do Sistema" #: src/bz-safety-calculator.c:562 msgid "Can display an icon in the system tray" msgstr "Pode mostrar um ícone na bandeja do sistema" #: src/bz-safety-calculator.c:567 msgid "KDE Connect Integration" msgstr "Integração com KDE Connect" #: src/bz-safety-calculator.c:568 msgid "Can interact with devices paired via KDE Connect" msgstr "Pode interagir com dispositivos pareados via KDE Connect" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "Segurança" #: src/bz-safety-dialog.blp:50 msgid "Details" msgstr "Detalhes" #: src/bz-safety-dialog.blp:53 msgid "License" msgstr "Licença" #: src/bz-safety-dialog.blp:63 msgid "App ID" msgstr "ID do App" #: src/bz-safety-dialog.blp:73 msgid "SDK" msgstr "SDK" #: src/bz-safety-dialog.blp:101 msgid "" "This app uses an outdated version of the software platform (SDK) and might " "contain bugs or security vulnerabilities which will not be fixed." msgstr "" "Este app utiliza uma versão desatualizada da plataforma de software (SDK) e " "pode conter bugs ou vunerabilidades de segurança que talvez não estejam " "consertadas." #: src/bz-safety-dialog.c:227 #, c-format msgid "%s is Safe" msgstr "%s é Seguro" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s has no Unsafe Permissions" msgstr "%s não possui Permissões Inseguras" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Probably Safe" msgstr "%s é Provavelmente Seguro" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Possibly Unsafe" msgstr "%s é Possivelmente Inseguro" #: src/bz-safety-dialog.c:247 #, c-format msgid "%s is Unsafe" msgstr "%s é Inseguro" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "Capturas de tela" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "Captura de tela anterior" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "Próxima captura de tela" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "Copiar Image" #: src/bz-screenshot-page.blp:147 msgid "Reset View" msgstr "Redefinir Visualização" #: src/bz-screenshot-page.blp:158 msgid "Zoom Out" msgstr "Diminuir Zoom" #: src/bz-screenshot-page.blp:168 msgid "Zoom In" msgstr "Aumentar Zoom" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "Carrossel de Capturas de Tela" #: src/bz-screenshots-carousel.blp:112 msgid "Open Screenshot Viewer" msgstr "Abrir Visualizador de Imagens" #: src/bz-search-widget.blp:57 msgid "Search Apps, Games, Software" msgstr "Pesquisar Aplicativos, Jogos e Softwares" #: src/bz-search-widget.blp:96 msgid "Categories Unavailable" msgstr "Atualizações Indisponíveis" #: src/bz-search-widget.blp:97 msgid "Search for apps using the search bar above." msgstr "Pesquisa por aplicativos utilizando a barra de pesquisa acima." #: src/bz-search-widget.blp:181 msgid "No Applications Found" msgstr "Nenhum Aplicativo Encontrado" #: src/bz-search-widget.c:241 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "Sem resultados para \"%s\" no Flathub" #: src/bz-share-list.c:64 msgid "Copied!" msgstr "Copiado!" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "Copiar Link" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Abrir Link" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "Linha do tempo" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "Instalações:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "Mundo" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:124 #, c-format msgid "%.2fM Total Installs" msgstr "%.2fM de Instalações Totais" #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:127 #, c-format msgid "%.2fK Total Installs" msgstr "%.2fK de Instalações Totais" #: src/bz-stats-dialog.c:129 #, c-format msgid "%'d Total Installs" msgstr "%'d de Instalações Totais" #: src/bz-tag-list.c:96 msgid "No Results Found" msgstr "Nenhum Resultado Encontrado" #: src/bz-tag-list.c:108 #, c-format msgid "Apps Tagged \"%s\"" msgstr "Aplicativos com a etiqueta \"%s\"" #: src/bz-tag-list.c:124 msgid "Search failed" msgstr "A pesquisa falhou" #: src/bz-transaction-dialog.c:155 msgid "Keep Data" msgstr "Manter Dados" #: src/bz-transaction-dialog.c:156 msgid "Allow restoring settings and content" msgstr "Habilita restauração de configuração e conteúdo" #: src/bz-transaction-dialog.c:165 msgid "Delete Data" msgstr "Excluir Dados" #: src/bz-transaction-dialog.c:166 msgid "Permanently remove app data to save space" msgstr "Remove permanentemente os dados do aplicativo para liberar espaço" #: src/bz-transaction-dialog.c:191 #, c-format msgid "Install %s?" msgstr "Instalar %s?" #: src/bz-transaction-dialog.c:196 msgid "" "Select which version to install. May install additional shared components" msgstr "" "Selecione qual versão para instalar. Talvez haja a instalação de componente " "compartilhados adicionais" #: src/bz-transaction-dialog.c:198 msgid "May install additional shared components" msgstr "Pode instalar componentes compartilhados adicionais" #: src/bz-transaction-dialog.c:219 #, c-format msgid "Remove %s?" msgstr "Remover %s?" #: src/bz-transaction-dialog.c:222 msgid "Select which version to remove." msgstr "Selecione qual versão para remover." #: src/bz-transaction-dialog.c:224 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "Não será possível utilizar %s após ser desinstalado." #: src/bz-transaction-dialog.c:247 #, c-format msgid "“%s” is High Risk" msgstr "\"%s\" é de Alto Risco" #: src/bz-transaction-dialog.c:251 msgid "" "This app has full access to your system, including all your files, " "browser history, saved passwords, and more. It also has access to the " "internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Este app possui acesso total ao seu sistema, incluindo todos os seus " "arquivos, histórico de navegação, senhas salvas e mais. Também possui " "acesso à internet, o que significa que também pode enviar seus dados para " "terceiros.\n" "\n" "Por este app ser proprietário, não é possível auditar o que faz com estas " "permissões." #: src/bz-transaction-dialog.c:260 msgid "" "This app uses the legacy X11 windowing system, which allows it to record " "all keystrokes, capture screenshots, and monitor other applications. It " "also has access to the internet, meaning it could send your data to outside " "parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Este app utilizado o sistema de janelas legado X11, o qual permite gravar " "todas as teclas pressionadas, capturar tela e monitorar outros " "aplicativos. Também possui acesso à internet, o que significa que também " "pode enviar seus dados para terceiros.\n" "\n" "Por este app ser proprietário, não é possível auditar o que faz com estas " "permissões." #: src/bz-transaction-dialog.c:276 msgid "Install Anyway" msgstr "Instalar de Qualquer Maneira" #: src/bz-transaction-dialog.c:549 msgid "All apps are already installed" msgstr "Todos os apps já estão instalados" #: src/bz-transaction-dialog.c:551 msgid "OK" msgstr "OK" #: src/bz-transaction-dialog.c:567 #, c-format msgid "Install %u App?" msgid_plural "Install %u Apps?" msgstr[0] "Instalar Aplicativo %u?" msgstr[1] "Instalar Aplicativos %u?" #: src/bz-transaction-dialog.c:575 msgid "" "The following will be installed. Additional shared components may also be " "installed" msgstr "" "Os seguintes aplicativos serão instalados. Componentes compartilhados " "adicionais também podem ser instalados" #: src/bz-transaction-dialog.c:576 #, c-format msgid "%d addons will be installed." msgstr "%d addons serão instalados." #: src/bz-transaction-dialog.c:577 msgid "Additionally, addons will be installed." msgstr "Adicionalmente, %d addons serão instalados." #: src/bz-transaction-manager.c:1251 #, c-format msgid "Finished in %.02f seconds" msgstr "Concluído em %.02f segundos" #: src/bz-transaction-tile.blp:125 msgid "App Add-on" msgstr "Extensões do aplicativo" #: src/bz-transaction-tile.blp:154 msgid "Runtime" msgstr "Runtime" #: src/bz-transaction-tile.blp:178 msgid "In Queue" msgstr "Em Fila" #: src/bz-transaction-tile.blp:202 msgid "Done" msgstr "Concluído" #: src/bz-transaction-tile.blp:226 msgid "Error" msgstr "Erro" #: src/bz-transaction-tile.blp:267 msgid "Open App" msgstr "Abrir App" #: src/bz-transaction-tile.c:110 #, c-format msgid "%s Freed" msgstr "%s Liberados" #: src/bz-transaction.c:342 msgid "Pending" msgstr "Pendente" #: src/bz-updates-card.blp:36 msgid "Update All" msgstr "Atualizar Todos" #: src/bz-updates-card.blp:161 src/bz-updates-card.blp:186 msgid "Update" msgstr "Atualizar" #: src/bz-updates-card.c:293 #, c-format msgid "%u Runtime Update" msgid_plural "%u Runtime Updates" msgstr[0] "%u Atualização de Runtime" msgstr[1] "%u Atualizações de Runtime" #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "Gerenciar Dados de Usuário Restantes" #: src/bz-user-data-page.blp:89 msgid "No User Data found" msgstr "Nenhum Dado de Usuário Encontrado" #: src/bz-user-data-page.blp:94 msgid "User Data" msgstr "Dados de Usuário" #: src/bz-user-data-tile.c:144 #, c-format msgid "Trashed User Data for %s" msgstr "Apagar Dados de Usuário de %s" #: src/bz-user-data-tile.blp:74 msgid "Trash User Data" msgstr "Apagar Dados de Usuário" #: src/bz-window.blp:135 msgid "Refreshing Store Content" msgstr "Recarregando o Conteúdo da Loja" #: src/bz-window.blp:153 msgid "Curated" msgstr "Recomendados" #: src/bz-window.blp:166 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:273 msgid "No background tasks!" msgstr "Sem atividades em segundo plano!" #: src/bz-window.blp:325 msgid "You are running a new version of Bazaar!" msgstr "Você está utilizando a nova versão do Bazaar!" #: src/bz-window.blp:326 msgid "See What's New" msgstr "Veja O Que Há de Novo" #: src/bz-window.blp:333 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "" "Você possui conexão à internet, mas está vendo uma versão em cache do Flathub" #: src/bz-window.blp:449 msgid "Log Out" msgstr "Desconectar" #: src/bz-window.c:666 msgid "You can't remove Bazaar from Bazaar!" msgstr "Você não pode remover o Bazaar pelo Bazaar!" #: src/bz-window.c:874 src/bz-window.c:908 msgid "Can't do that right now!" msgstr "Não consigo fazer isso agora!" #: src/bz-world-map.c:587 msgctxt "As in, \"100 Downloads\"" msgid "Downloads" msgstr "Downloads" #: src/gtk/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Geral" #: src/gtk/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "Abrir Diálogo de Pesquisa" #: src/gtk/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Abrir Preferências" #: src/gtk/shortcuts-dialog.blp:19 msgctxt "shortcut window" msgid "Synchronize Remotes" msgstr "Sincronizar Repositórios" #: src/gtk/shortcuts-dialog.blp:24 msgctxt "shortcut window" msgid "Open Library" msgstr "Abrir Biblioteca" #: src/gtk/shortcuts-dialog.blp:30 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Mostrar Atalhos" #: src/gtk/shortcuts-dialog.blp:35 msgctxt "shortcut window" msgid "Quit" msgstr "Sair" #~ msgid "Nucleus app page" #~ msgstr "Página do aplicativo Nucleus" #~ msgid "Toggle transaction sidebar" #~ msgstr "Alternar barra lateral de transações" #~ msgid "Install Size" #~ msgstr "Tamanho da Instalação" #, fuzzy #~ msgid "Finished" #~ msgstr "Tarefas finalizadas" #, c-format #~ msgid "Transferred %s so far" #~ msgstr "%s transferidos até agora" #, c-format #~ msgid "%d Update Available" #~ msgid_plural "%d Updates Available" #~ msgstr[0] "%d Atualização Disponível" #~ msgstr[1] "%d Atualizações Disponíveis" #~ msgid "Updates Are Available" #~ msgstr "Atualizações Estão Disponíveis" #~ msgid "" #~ "The following applications are eligible for updates. Would you like to " #~ "install them?" #~ msgstr "" #~ "Os seguintes aplicativos podem ser atualizados. Você gostaria de instalá-" #~ "los?" #, c-format #~ msgid "" #~ "%d runtimes and/or addons are eligible for updates. Would you like to " #~ "install them?" #~ msgstr "" #~ "%d runtimes e/ou extensões podem ser atualizados. Você gostaria de " #~ "instalá-los?" #, c-format #~ msgid "Additionally, %d runtimes and/or addons will be updated." #~ msgstr "Adicionalmente, %d runtimes e/ou extensões serão atualizados." #~ msgid "Update Now" #~ msgstr "Atualizar Agora" #~ msgctxt "shortcut window" #~ msgid "Toggle Transaction Manager" #~ msgstr "Alternar Gerenciador de Transações" # https://pt.wikipedia.org/wiki/Fim_de_vida_(produto) #~ msgid "Hide EOL Entries" #~ msgstr "Esconder entradas em fim de vida (EOL)" # https://pt.wikipedia.org/wiki/Fim_de_vida_(produto) #~ msgid "Hide EOL entries and entries depending on them" #~ msgstr "Esconder entradas em fim de vida (EOL) e entradas dependentes delas" #~ msgid "Show Git Forge Star Counts" #~ msgstr "Exibir a contagem de estrelas de plataformas Git" #~ msgid "" #~ "Whether to attempt to detect and show \"star counts\" for projects in the " #~ "full view" #~ msgstr "" #~ "Se deve fazer a tentativa de detectar e mostrar a \"contagem de " #~ "estrelas\" para projetos na visualização completa" #~ msgid "Only Show Free Software" #~ msgstr "Mostrar apenas softwares livres" #~ msgid "Hide proprietary software" #~ msgstr "Ocultar softwares proprietários" #~ msgid "Show Only Flathub Content" #~ msgstr "Mostrar Apenas Conteúdos do Flathub" #~ msgid "Debounce Search Inputs" #~ msgstr "Entrada de Pesquisa com Atraso" #~ msgid "Add a delay before searching to prevent instant replies while typing" #~ msgstr "" #~ "Adiciona um delay antes de pesquisar para evitar múltiplas respostas " #~ "enquanto digita" #~ msgid "Global Progress Bar Theme" #~ msgstr "Tema da Barra de Progresso Global" #~ msgid "Describes the look of the global progress bar" #~ msgstr "Descreve a aparência da barra de progresso global" #~ msgid "Saved Window Dimensions" #~ msgstr "Dimensões da Janela Salvas" #~ msgid "The window dimensions to be used by the next Bazaar window" #~ msgstr "" #~ "As dimensões da janela a serem utilizadas pela próxima janela do Bazaar" #~ msgid "?" #~ msgstr "?" #, c-format #~ msgid "%s is suitable for toddlers" #~ msgstr "%s é adequado para crianças de um a três anos" #~ msgid "--- MB" #~ msgstr "--- MB" #~ msgid "Of the size of human DNA" #~ msgstr "Do tamanho do DNA humano" #~ msgid "3 billion base pairs" #~ msgstr "3 bilhões de pares de bases" #~ msgid "Of the Linux Kernel" #~ msgstr "Do Kernel Linux" #~ msgid "linux-6.17.tar.xz" #~ msgstr "linux-6.17.tar.xz" #~ msgid "Of the Apollo 11 guidance computer" #~ msgstr "Do computador de orientação da Apollo 11" #~ msgid "Total ROM and RAM" #~ msgstr "Total de ROM e RAM" #~ msgid "Of the original Super Mario Bros" #~ msgstr "Do Super Mario Bros original" #~ msgid "On the NES" #~ msgstr "No NES" #~ msgid "Of the size of Wikipedia" #~ msgstr "Do tamanho da Wikipedia" #~ msgid "Without any media" #~ msgstr "Sem nenhuma mídia" #~ msgid "_Refresh Content" #~ msgstr "_Recarregar Conteúdo" #~ msgid "" #~ "This functionality is currently disabled. It is recommended you download " #~ "and install Flatseal to manage app permissions." #~ msgstr "" #~ "Esta funcionalidade está atualmente desativada. É recomendado baixar e " #~ "instalar o Flatseal para gerenciar permissões de aplicativos." #~ msgid "Entry Inspector" #~ msgstr "Inspetor de entrada" #~ msgid "Serialize" #~ msgstr "Serializar" #~ msgid "Convert to JSON" #~ msgstr "Converter para JSON" #~ msgid "More Mobile apps" #~ msgstr "Mais Aplicativos Móveis" #~ msgid "Repository Star Count" #~ msgstr "Contagem de Estrelas do Repositório" #~ msgid "Size" #~ msgstr "Tamanho" #~ msgid "Bazaar Inspector" #~ msgstr "Inspetor do Bazaar" #~ msgid "Enable Global Debug Mode" #~ msgstr "Habilitar Modo de Depuração Global" #~ msgid "Active Blocklists" #~ msgstr "Listas de Bloqueio Ativas" #~ msgid "Active Curated-Configs" #~ msgstr "Configurações de Listas Recomendadas Ativas" #~ msgid "All Entry Groups" #~ msgstr "Todos os Grupos de Entradas" #~ msgid "Filter..." #~ msgstr "Filtrar..." #~ msgid "Decache and Inspect" #~ msgstr "Limpar Cache e Inspecionar" #~ msgid "No Flatpaks Installed" #~ msgstr "Sem Flatpaks Instalados" #~ msgid "Application Details" #~ msgstr "Detalhes do Aplicativo" #~ msgid "Display Star Count" #~ msgstr "Mostrar Contagem de Estrelas" #~ msgid "Show the star count of an application's source code repository" #~ msgstr "" #~ "Mostrar a contagem de estrelas do repositório código fonte da aplicação" #~ msgid "" #~ "Bazaar can fetch and display the star count from an application's source " #~ "code repository on a remote Git forge. \n" #~ " For projects on GitHub, rate limits may cause them not to appear." #~ msgstr "" #~ "Bazaar pode verificar e mostrar a contagem de estrelas do repositório " #~ "código fonte da aplicação em uma forja git externa.\n" #~ " Para projetos no GitHub, limites de taxa talvez façam com que elas não " #~ "apareçam." #~ msgid "Remove User Data" #~ msgstr "Remover Dados de Usuário" #~ msgid "Inspect UI Entry" #~ msgstr "Inspecionar Entrada de UI" #~ msgid "All Debug Actions" #~ msgstr "Depurar todas as ações" #~ msgid "Tasks" #~ msgstr "Tarefas" #~ msgid "Stop Active Tasks" #~ msgstr "Parar Tarefas Ativas" #~ msgid "Clear History" #~ msgstr "Limpar Histórico" #~ msgid "No Tasks Yet" #~ msgstr "Nenhuma Tarefa Ainda" #~ msgid "Open Bazaar Inspector" #~ msgstr "Abrir Inspetor do Bazaar" #~ msgid "" #~ "The ability to inspect and install local .flatpak bundle files is coming " #~ "soon! In the meantime, try running\n" #~ "\n" #~ "flatpak install --bundle your-bundle.flatpak\n" #~ "\n" #~ "on the command line." #~ msgstr "" #~ "A funcionalidade de inspecionar e instalar pacotes .flatpak está chegando " #~ "em breve! Por enquanto, insira\n" #~ "\n" #~ "flatpak install --bundle seu-pacote.flatpak\n" #~ "\n" #~ "em seu terminal." #~ msgid "Resume Current Tasks" #~ msgstr "Retomar Tarefas Atuais" #~ msgid "Pause Current Tasks" #~ msgstr "Pausar Tarefas Atuais" #, c-format #~ msgid "%s: %'u downloads" #~ msgstr "%s: %'u downloads" #~ msgctxt "shortcut window" #~ msgid "Refresh" #~ msgstr "Recarregar" #~ msgid "We ♥ Games" #~ msgstr "Nós ♥ Jogos" #, c-format #~ msgid "%.2fM" #~ msgstr "%.2fM" #, c-format #~ msgid "%.2fK" #~ msgstr "%.2fK" #~ msgid "Sync" #~ msgstr "Sincronizar" #~ msgid "Filter search results to only show applications available on Flathub" #~ msgstr "" #~ "Filtra resultados de pesquisa para exibir apenas aplicativos disponíveis " #~ "no Flathub" #~ msgid "Manage Addons" #~ msgstr "Gerenciar Extensões" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Ahmed Najmawi" #~ msgstr "Ahmed Najmawi" #~ msgctxt "About Dialog Translator Credit" #~ msgid "AtomHare" #~ msgstr "AtomHare" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Azenyr" #~ msgstr "Azenyr" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Goudarz Jafari" #~ msgstr "Goudarz Jafari" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Jill Fiore (Lumaeris)" #~ msgstr "Jill Fiore (Lumaeris)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "João Victor (Leal)" #~ msgstr "João Victor (Leal)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "KiKaraage" #~ msgstr "KiKaraage" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Lucosec" #~ msgstr "Lucosec" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Léane GRASSER" #~ msgstr "Léane GRASSER" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Marcel Mrówka (Microwave)" #~ msgstr "Marcel Mrówka (Microwave)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Peter Dave Hello" #~ msgstr "Peter Dave Hello" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Pietro F." #~ msgstr "Pietro F." #~ msgctxt "About Dialog Translator Credit" #~ msgid "Sabri Ünal" #~ msgstr "Sabri Ünal" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Shihfu Juan" #~ msgstr "Shihfu Juan" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Shinsei" #~ msgstr "Shinsei" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Vlastimil Dědek" #~ msgstr "Vlastimil Dědek" #~ msgctxt "About Dialog Translator Credit" #~ msgid "asen23" #~ msgstr "asen23" #~ msgctxt "About Dialog Translator Credit" #~ msgid "camegone" #~ msgstr "camegone" #~ msgctxt "About Dialog Translator Credit" #~ msgid "renner" #~ msgstr "renner" #~ msgctxt "About Dialog Translator Credit" #~ msgid "robotta" #~ msgstr "robotta" #~ msgid "Constructing Flatpak instance..." #~ msgstr "Construindo instância de Flatpak..." #~ msgid "Reusing last Flatpak instance..." #~ msgstr "Reutilizando última instância de Flatpak..." #~ msgid "Flathub is not registered on this system" #~ msgstr "Flathub não está registrado neste sistema" #~ msgid "" #~ "Would you like to add Flathub as a remote? If you decline, the Flathub " #~ "page will not be available. You can change this later." #~ msgstr "" #~ "Você gostaria de adicionar o repositório do Flathub? Se recusar, a página " #~ "do Flathub não estará disponível. Você pode alterar isso depois." #~ msgid "Add Flathub" #~ msgstr "Adicionar Flathub" #, c-format #~ msgid "Identifying installed entries..." #~ msgstr "Identificando entradas instaladas..." #, c-format #~ msgid "" #~ "Beginning remote entry retrieval while referencing %d blocklist(s)..." #~ msgstr "" #~ "Iniciando a obtenção de entradas remotas, consultando %d lista(s) de " #~ "bloqueio..." #, c-format #~ msgid "%'d of %'d" #~ msgstr "%'d de %'d" #, c-format #~ msgid "Waiting for background indexing tasks to catch up..." #~ msgstr "Aguardando tarefas de indexação em segundo plano..." #, c-format #~ msgid "Completed initialization in %0.2f seconds" #~ msgstr "Inicialização completada em %0.2f segundos" #~ msgid "" #~ "Bazaar was not provided a curated content configuration. Contact your " #~ "operating system's support channels for assistance." #~ msgstr "" #~ "O Bazaar não recebeu uma configuração de conteúdo recomendado. Contate os " #~ "canais de suporte do seu sistema operacional para receber assistência." #~ msgid "Graphics" #~ msgstr "Gráficos" #~ msgid "Office" #~ msgstr "Produtividade" #~ msgctxt "Project URL Type" #~ msgid "Homepage" #~ msgstr "Página Inicial" #~ msgid "This flatpak is verified by the original developers of the software." #~ msgstr "" #~ "Este flatpak foi verificado pelos desenvolvedores originais do software." #~ msgid "Share this application" #~ msgstr "Compartilhar este aplicativo" #~ msgid "Excludes shared components" #~ msgstr "Exclui componentes compartilhados" #~ msgid "Source code may not be available" #~ msgstr "O código-fonte pode não estar disponível" #~ msgid "Click for details" #~ msgstr "Clique para mais detalhes" #~ msgid "Repositories" #~ msgstr "Repositórios" #~ msgid "Open in browser" #~ msgstr "Abrir no navegador" #, c-format #~ msgid "%'d Monthly Downloads" #~ msgstr "%'d Downloads Mensais" #~ msgid "%B %-d, %Y" #~ msgstr "%-d de %B , %Y" #~ msgid "%B %-d" #~ msgstr "%-d de %B" #~ msgid "Run this application" #~ msgstr "Executar este aplicativo" #~ msgid "Run" #~ msgstr "Executar" #~ msgid "Git Forge Star Counts" #~ msgstr "Contagem de Estrelas de Plataformas Git" #~ msgid "Not having a GitHub access token may trigger rate limits" #~ msgstr "Não ter um token de acesso do GitHub pode acionar limites de taxa" #~ msgid "Show Only Flathub Apps" #~ msgstr "Mostrar Apenas Apps Flathub" #~ msgid "Wait for a brief pause to reduce system load" #~ msgstr "Aguarde uma breve pausa para reduzir a carga do sistema" #~ msgid "Theme" #~ msgstr "Tema" #~ msgid "Pride Rainbow Flag" #~ msgstr "Bandeira do Orgulho Arco-Íris" #~ msgid "Bisexual Flag" #~ msgstr "Bandeira Bissexual" #~ msgid "Asexual Flag" #~ msgstr "Bandeira Assexual" #~ msgid "Share" #~ msgstr "Compartilhar" #~ msgid "Browse" #~ msgstr "Navegar" #~ msgid "App View" #~ msgstr "Visualização de Aplicativo" #~ msgid "Go Back" #~ msgstr "Voltar" #~ msgid "View curated applications" #~ msgstr "Ver aplicativos recomendados" #~ msgid "View the latest on Flathub" #~ msgstr "Ver os últimos do Flathub" #~ msgid "_Quit Service" #~ msgstr "_Sair do Serviço" #~ msgid "Settings & user data will be kept" #~ msgstr "As configurações e os dados do usuário serão mantidos" #~ msgid "Calligraphy application page" #~ msgstr "Página de aplicativo de caligragia" #~ msgid "Download graph for Blender" #~ msgstr "Gráfico de Downloads para o Blender" #~ msgid "Open this image in the default image viewer" #~ msgstr "Abra essa imagem no visualizador de imagens padrão" #~ msgid "Copy this image to the clipboard" #~ msgstr "Copiar para área de transferência" #~ msgid "Apps Of The Week" #~ msgstr "Aplicativos da Semana" #~ msgid "Download Statistics" #~ msgstr "Estatísticas de Download" #~ msgid "Show Downloads Over Time" #~ msgstr "Mostrar downloads ao longo do tempo" #~ msgid "Remote repo name" #~ msgstr "Nome do repositório remoto" #, c-format #~ msgid "Released %x" #~ msgstr "Lançado em %x" #~ msgid "Downloads Over Time" #~ msgstr "Downloads ao Longo do Tempo" #~ msgid "Minimize Lower Bound" #~ msgstr "Minimizar o Limite Inferior" #~ msgid "Maximize Upper Bound" #~ msgstr "Maximizar o Limite Superior" #~ msgid "Updated Size" #~ msgstr "Tamanho Atualizado" #~ msgid "Freed Space" #~ msgstr "Espaço Liberado" #~ msgid "Transactions Will Appear Here" #~ msgstr "As Transações Aparecerão Aqui" #~ msgid "Halt the execution of transactions" #~ msgstr "Interromper a execução das transações" #~ msgid "Up to date!" #~ msgstr "Já está atualizado!" #~ msgid "Confirm Action" #~ msgstr "Confirmar Ação" #, c-format #~ msgid "" #~ "You are about to remove the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "Você está prestes a remover o seguinte Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Você tem certeza?" #, c-format #~ msgid "" #~ "You are about to install the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "Você está prestes a instalar o seguinte Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Você tem certeza?" #~ msgid "Resume the execution of transactions" #~ msgstr "Retomar a execução de transações" #~ msgid "Pause the execution of transactions" #~ msgstr "Pausar a execução de transações" #~ msgctxt "Project URL Type" #~ msgid "VCS Browser" #~ msgstr "Navegador" #~ msgid "Full Application View" #~ msgstr "Visualização Completa do Aplicativo" #~ msgid "Change what content is shown when viewing applications" #~ msgstr "Mudar qual conteúdo é mostrado ao visualizar aplicativos" #~ msgid "" #~ "If you do not have an access token, turning this setting on may cause " #~ "GitHub to eventually rate limit you." #~ msgstr "" #~ "Se você não tiver um token de acesso, ativar esta configuração pode fazer " #~ "com que o GitHub eventualmente limite suas requisições." #~ msgid "Type to filter" #~ msgstr "Digite para filtrar" #~ msgid "Exclude results with proprietary licenses" #~ msgstr "Excluir resultados com licenças proprietárias" #~ msgid "Advanced" #~ msgstr "Avançado" #~ msgid "Open this link externally" #~ msgstr "Abrir este link externamente" #, c-format #~ msgid "Received %'d entries out of %'d (%0.1f seconds elapsed)" #~ msgstr "" #~ "%'d entradas recebidas de um total de %'d (%0.1f segundos decorridos)" #~ msgid "VCS Forge Star Count" #~ msgstr "Contagem de Estrelas da Plataforma de VCS" #~ msgid "This application does not provide a donation link" #~ msgstr "Este aplicativo não provê um link para doações" #, c-format #~ msgid "" #~ "\"%s\" does not provide a donations link. This does not mean you cannot " #~ "support them! Try looking at their project page for " #~ "more information." #~ msgstr "" #~ "\"%s\" não provê um link para doações. Isso não quer dizer que você não " #~ "possá apoiá-lo! Tente procurar na página do projeto " #~ "para mais informações." #, c-format #~ msgid "" #~ "\"%s\" does not provide a donations link. This does not mean you cannot " #~ "support them! Try finding their project page for more information." #~ msgstr "" #~ "\"%s\" não provê um link para doações. Isso não quer dizer que você não " #~ "possá apoiá-lo! Tente procurar na página do projeto para mais informações." #~ msgid "Installing" #~ msgstr "Instalando" #~ msgid "Removing" #~ msgstr "Removendo" #~ msgid "Show Animated Background" #~ msgstr "Mostrar Plano de Fundo Animado" #~ msgid "Whether to show the animated icon background on the home page" #~ msgstr "Se deseja mostrar ícone de plano de fundo animado na página inicial" #~ msgid "Keep the summary shorter, between 10 and 35 characters" #~ msgstr "Mantenha o resumo curto, entre 10 e 35 caracteres" #~ msgid "Main Bazaar window showing Blender" #~ msgstr "Janela principal do Bazaar mostrando o Blender" #~ msgid "" #~ "The number of downloads in the last 30 days. Click to view this " #~ "application's download statistics." #~ msgstr "" #~ "O número de downloads dos últimos 30 dias. Clique para ver as " #~ "estatísticas de download deste aplicativo." #~ msgid "How the application looks" #~ msgstr "Como o aplicativo se parece" #~ msgid "Appearance" #~ msgstr "Aparência" #~ msgid "Show animated background" #~ msgstr "Mostrar plano de fundo animado" #~ msgid "Match using regular expressions" #~ msgstr "Corresponder utilizando expressões regulares" #~ msgid "Hide filtering and sorting behind a crossfade effect" #~ msgstr "" #~ "Ocultar filtragem e ordenação usando um efeito de transição crossfade" bazaar-orig-v0.7.14/po/it.po0000664000175000017500000013175415166123241014545 0ustar hasanhasan# Italian translations for bazaar package. # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # Pietro F. , 2025. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-11-11 10:39+0100\n" "PO-Revision-Date: 2025-11-11 11:25+0100\n" "Last-Translator: Pietro F. \n" "Language-Team: Italian\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 49.0\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:5 #: src/bz-window.blp:225 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "" "Aggiunge, rimuove o aggiorna le applicazioni flatpak su questo computer" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" #: data/io.github.kolunmi.Bazaar.gschema.xml:6 msgid "Hide EOL Entries" msgstr "Nascondi voci EOL" #: data/io.github.kolunmi.Bazaar.gschema.xml:7 msgid "Hide EOL entries and entries depending on them" msgstr "Nascondi voci EOL e voci che dipendono da esse" #: data/io.github.kolunmi.Bazaar.gschema.xml:11 msgid "Show Git Forge Star Counts" msgstr "Mostra il numero di stelle su Git Forge" #: data/io.github.kolunmi.Bazaar.gschema.xml:12 msgid "" "Whether to attempt to detect and show \"star counts\" for projects in the " "full view" msgstr "" "Se tentare di rilevare e mostrare il “numero di stelle” per i progetti nella " "vista completa" #: data/io.github.kolunmi.Bazaar.gschema.xml:16 msgid "Only Show Free Software" msgstr "Mostra solo Free Software" #: data/io.github.kolunmi.Bazaar.gschema.xml:17 msgid "Hide proprietary software when searching" msgstr "nascondi software proprietario durante la ricerca" #: data/io.github.kolunmi.Bazaar.gschema.xml:21 msgid "Show Only Flathub Content" msgstr "Mostra solo i contenuti di Flathub" #: data/io.github.kolunmi.Bazaar.gschema.xml:22 msgid "Filter search results to only show applications available on Flathub" msgstr "" "Filtra i risultati della ricerca per mostrare solo le applicazioni " "disponibili su Flathub" #: data/io.github.kolunmi.Bazaar.gschema.xml:26 msgid "Debounce Search Inputs" msgstr "Ricerca senza rimbalzo" #: data/io.github.kolunmi.Bazaar.gschema.xml:27 msgid "Add a delay before searching to prevent instant replies while typing" msgstr "" "Aggiungere un ritardo nell'elaborazione dei dati per evitare risultati " "immediati" #: data/io.github.kolunmi.Bazaar.gschema.xml:45 msgid "Global Progress Bar Theme" msgstr "Tema barra di avanzamento globale" #: data/io.github.kolunmi.Bazaar.gschema.xml:46 msgid "Describes the look of the global progress bar" msgstr "Descrive l'aspetto della barra di avanzamento globale" #: data/io.github.kolunmi.Bazaar.gschema.xml:50 msgid "Saved Window Dimensions" msgstr "Dimensioni finestra salvate" #: data/io.github.kolunmi.Bazaar.gschema.xml:51 msgid "The window dimensions to be used by the next Bazaar window" msgstr "" "Le dimensioni della finestra da utilizzare per la prossima finestra Bazaar" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and install applications" msgstr "Scopri e installa applicazioni" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A new app store for GNOME with a focus on discovering and installing " "applications and addons from Flatpak remotes, particularly Flathub." msgstr "" "Un nuovo app store per GNOME incentrato sulla ricerca e l'installazione di " "applicazioni e componenti aggiuntivi dai repository remoti Flatpak, in " "particolare Flathub." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:14 msgid "" "It emphasizes supporting the developers who make the Linux desktop possible. " "Bazaar features a \"curated\" tab that can be configured by distributors to " "allow for a more localized experience." msgstr "" "Sottolinea l'importanza di supportare gli sviluppatori che rendono possibile " "il desktop Linux. Bazaar presenta una scheda “Consigliate” che può essere " "configurata dai distributori per consentire un'esperienza più personalizzata." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:29 src/bz-application.c:494 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:54 msgid "The home page displaying Flathub apps" msgstr "La schermata iniziale che mostra le app di Flathub" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:58 msgid "Nucleus app page" msgstr "Pagina dell'app Nucleus" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:62 msgid "Search page" msgstr "Pagina di Ricerca" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:66 msgid "Category page" msgstr "Pagina delle Categorie" #: src/bz-addons-dialog.blp:14 src/bz-full-view.blp:582 msgid "Manage Add-ons" msgstr "Gestisce estensioni" #: src/bz-addons-dialog.c:88 src/bz-transaction-view.blp:212 #: src/bz-window.c:1101 msgid "Remove" msgstr "Rimuovi" #: src/bz-addons-dialog.c:93 src/bz-full-view.blp:289 #: src/bz-transaction-view.blp:186 src/bz-window.c:1077 msgid "Install" msgstr "Installa" #: src/bz-app-size-dialog.c:55 msgid "Of the size of human DNA" msgstr "Delle dimensioni del DNA umano" #: src/bz-app-size-dialog.c:55 msgid "3 billion base pairs" msgstr "3 miliardi di coppie di basi" #: src/bz-app-size-dialog.c:56 msgid "Of the Linux Kernel" msgstr "Del kernel Linux" #: src/bz-app-size-dialog.c:56 msgid "linux-6.17.tar.xz" msgstr "linux-6.17.tar.xz" #: src/bz-app-size-dialog.c:57 msgid "Of the Apollo 11 guidance computer" msgstr "Del computer di bordo dell'Apollo 11" #: src/bz-app-size-dialog.c:57 msgid "Total ROM and RAM" msgstr "ROM e RAM totali" #: src/bz-app-size-dialog.c:58 msgid "Of the original Super Mario Bros" msgstr "Dell'originale Super Mario Bros." #: src/bz-app-size-dialog.c:58 msgid "On the NES" msgstr "Su NES" #: src/bz-app-size-dialog.c:59 msgid "Of the size of Wikipedia" msgstr "Delle dimensioni di Wikipedia" #: src/bz-app-size-dialog.c:59 msgid "Without any media" msgstr "Senza alcun media" #: src/bz-app-size-dialog.blp:43 msgid "--- MB" msgstr "--- MB" #: src/bz-app-size-dialog.blp:53 msgid "Download Size" msgstr "Dimensione Download" #: src/bz-application.c:416 msgid "" "This functionality is currently disabled. It is recommended you download and " "install Flatseal to manage app permissions." msgstr "" "Questa funzionalità è attualmente disabilitata. Si consiglia di scaricare e " "installare Flatseal per gestire le autorizzazioni delle app." #: src/bz-application.c:479 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:480 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:497 msgid "translator-credits" msgstr "Pietro F. , 2025" #: src/bz-application.c:1069 msgid "Constructing Flatpak instance..." msgstr "Creazione dell'istanza Flatpak..." #: src/bz-application.c:1086 msgid "Reusing last Flatpak instance..." msgstr "Riutilizzo dell'ultima istanza Flatpak..." #: src/bz-application.c:1111 msgid "Flathub is not registered on this system" msgstr "Flathub non è registrato su questo sistema" #: src/bz-application.c:1114 msgid "" "Would you like to add Flathub as a remote? If you decline, the Flathub page " "will not be available. You can change this later." msgstr "" "Vuoi aggiungere Flathub come repository remoto? Se rifiuti, la pagina " "Flathub non sarà disponibile. Puoi cambiare questa impostazione in un " "secondo momento." #: src/bz-application.c:1119 src/bz-update-dialog.blp:6 msgid "Later" msgstr "Dopo" #: src/bz-application.c:1120 msgid "Add Flathub" msgstr "Aggiungi Flathub" #: src/bz-application.c:1152 msgid "Identifying installed entries..." msgstr "Identificazione delle voci installate..." #: src/bz-application.c:1176 msgid "Receiving Entries" msgstr "Ricezione delle voci" #: src/bz-application.c:1333 #, c-format msgid "%'d of %'d" msgstr "%'d di %'d" #: src/bz-application.c:1346 #, c-format msgid "Waiting for background indexing tasks to catch up..." msgstr "" "In attesa che le attività di indicizzazione in background vengano " "completate..." #: src/bz-application.c:1388 #, c-format msgid "Completed initialization in %0.2f seconds" msgstr "Inizializzazione completata in %0.2f secondi" #: src/bz-application.c:1393 src/bz-application.c:1548 msgid "Checking for updates..." msgstr "Controllo degli aggiornamenti..." #: src/bz-application.c:1432 msgid "Synchronizing..." msgstr "Sincronizzazione..." #: src/bz-browse-widget.blp:11 src/bz-flathub-page.blp:19 #: src/bz-full-view.blp:53 src/bz-installed-page.blp:15 src/bz-window.blp:174 msgid "Empty" msgstr "Vuoto" #: src/bz-browse-widget.blp:15 msgid "No Curation" msgstr "Non ci sono Applicazioni Consigliate" #: src/bz-browse-widget.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "Non sono disponibili informazioni sulle app consigliate per questo sistema. " "È comunque possibile sfogliare le applicazioni su Flathub" #: src/bz-browse-widget.blp:18 msgid "Browse Flathub" msgstr "Esplora Flathub" #: src/bz-browse-widget.blp:29 src/bz-browse-widget.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "Nessuna connessione" #: src/bz-browse-widget.blp:39 src/bz-flathub-page.blp:40 msgid "Browser" msgstr "Browser" #: src/bz-entry-inspector.blp:5 msgid "Entry Inspector" msgstr "Ispettore delle voci" #: src/bz-entry-inspector.blp:76 msgid "Serialize" msgstr "Serializza" #: src/bz-entry-inspector.blp:80 msgid "Convert to JSON" msgstr "Converti in JSON" #: src/bz-error.c:68 msgid "An Error Occurred" msgstr "Si è verificato un errore" #: src/bz-error.c:89 msgid "Close" msgstr "Chiudi" #: src/bz-error.c:90 msgid "Copy and Close" msgstr "Copia e Chiudi" #: src/bz-featured-tile.blp:88 msgid "App of the Day" msgstr "App del Giorno" #: src/bz-flathub-category.c:66 msgid "Audio & Video" msgstr "Audio & Video" #: src/bz-flathub-category.c:66 msgid "Media" msgstr "Media" #: src/bz-flathub-category.c:66 msgid "More Audio & Video" msgstr "Più Audio & Video" #: src/bz-flathub-category.c:67 msgid "Developer Tools" msgstr "Strumenti per Sviluppatori" #: src/bz-flathub-category.c:67 msgid "Develop" msgstr "Sviluppa" #: src/bz-flathub-category.c:67 msgid "More Developer Tools" msgstr "Più Strumenti per Sviluppatori" #: src/bz-flathub-category.c:68 msgid "Education" msgstr "Educazione" #: src/bz-flathub-category.c:68 msgid "Learn" msgstr "Impara" #: src/bz-flathub-category.c:68 msgid "More Education" msgstr "Più Educazione" #: src/bz-flathub-category.c:69 msgid "Gaming" msgstr "Gaming" #: src/bz-flathub-category.c:69 msgid "Play" msgstr "Gioca" #: src/bz-flathub-category.c:69 msgid "More Gaming" msgstr "Più Gaming" #: src/bz-flathub-category.c:70 msgid "Graphics & Photography" msgstr "Grafica & Fotografia" #: src/bz-flathub-category.c:70 msgid "Create" msgstr "Crea" #: src/bz-flathub-category.c:70 msgid "More Graphics & Photography" msgstr "Più Grafica & Fotografia" #: src/bz-flathub-category.c:71 msgid "Networking" msgstr "Networking" #: src/bz-flathub-category.c:71 msgid "Internet" msgstr "Internet" #: src/bz-flathub-category.c:71 msgid "More Networking" msgstr "Più Networking" #: src/bz-flathub-category.c:72 msgid "Productivity" msgstr "Produttività" #: src/bz-flathub-category.c:72 msgid "Work" msgstr "Lavoro" #: src/bz-flathub-category.c:72 msgid "More Productivity" msgstr "Più Produttività" #: src/bz-flathub-category.c:73 msgid "Science" msgstr "Scienza" #: src/bz-flathub-category.c:73 msgid "More Science" msgstr "Più Scienza" #: src/bz-flathub-category.c:74 msgid "System" msgstr "Sistema" #: src/bz-flathub-category.c:74 msgid "More System" msgstr "Più Sistema" #: src/bz-flathub-category.c:75 msgid "Utilities" msgstr "Utilità" #: src/bz-flathub-category.c:75 msgid "Tools" msgstr "Strumenti" #: src/bz-flathub-category.c:75 msgid "More Utilities" msgstr "Più Utilità" #: src/bz-flathub-category.c:76 src/bz-flathub-page.blp:109 #: src/bz-flathub-page.blp:142 msgid "Trending" msgstr "In Tendenza" #: src/bz-flathub-category.c:76 msgid "More Trending" msgstr "Più In Tendenza" #: src/bz-flathub-category.c:77 src/bz-flathub-page.blp:115 #: src/bz-flathub-page.blp:175 msgid "Popular" msgstr "Popolari" #: src/bz-flathub-category.c:77 msgid "More Popular" msgstr "Più Popolari" #: src/bz-flathub-category.c:78 src/bz-flathub-page.blp:164 msgid "Recently Added" msgstr "Aggiunte Recentemente" #: src/bz-flathub-category.c:78 src/bz-flathub-page.blp:121 msgid "New" msgstr "Nuove" #: src/bz-flathub-category.c:78 msgid "More New" msgstr "Più Nuove" #: src/bz-flathub-category.c:79 src/bz-flathub-page.blp:153 msgid "Recently Updated" msgstr "Aggiornate Recentemente" #: src/bz-flathub-category.c:79 src/bz-flathub-page.blp:127 msgid "Updated" msgstr "Aggiornate" #: src/bz-flathub-category.c:79 msgid "More Updated" msgstr "Più Aggiornate Recentemente" #: src/bz-flathub-category.c:80 msgid "Mobile" msgstr "Mobile" #: src/bz-flathub-category.c:80 msgid "More Mobile" msgstr "Più Mobile" #: src/bz-flathub-category-section.c:132 src/bz-search-widget.c:314 #, c-format msgid "%d applications" msgstr "%d applicazioni" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Flathub non aggiunto" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "" "Il repository remoto Flathub non è stato trovato in nessuna delle tue " "installazioni Flatpak" #: src/bz-flathub-page.blp:48 msgid "Flathub Unavailable" msgstr "Flathub non disponibile" #: src/bz-flathub-page.blp:49 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" "Impossibile connettersi a Flathub. È comunque possibile gestire e cercare le " "applicazioni." #: src/bz-flathub-page.blp:52 msgid "Search Apps" msgstr "Cerca Applicazioni" #: src/bz-flathub-page.blp:266 msgid "On the go" msgstr "On the go" #: src/bz-flathub-page.blp:278 msgid "Apps for your Linux phones and tablets" msgstr "App per il tuo telefono o tablet Linux" #: src/bz-flathub-page.blp:289 src/bz-flathub-page.blp:324 msgid "More Mobile apps" msgstr "Più App Mobile" #: src/bz-flathub-page.c:204 msgid "Mobile Apps" msgstr "App Mobile" #: src/bz-flatpak-entry.c:554 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Pagina Flathub" #: src/bz-flatpak-entry.c:575 msgctxt "Project URL Type" msgid "Project Website" msgstr "Sito del Progetto" #: src/bz-flatpak-entry.c:579 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Segnala un problema" #: src/bz-flatpak-entry.c:583 msgctxt "Project URL Type" msgid "FAQ" msgstr "FAQ" #: src/bz-flatpak-entry.c:587 msgctxt "Project URL Type" msgid "Help" msgstr "Aiuto" #: src/bz-flatpak-entry.c:591 msgctxt "Project URL Type" msgid "Donate" msgstr "Dona" #: src/bz-flatpak-entry.c:597 msgctxt "Project URL Type" msgid "Translate" msgstr "Traduci" #: src/bz-flatpak-entry.c:601 msgctxt "Project URL Type" msgid "Contact" msgstr "Contatta" #: src/bz-flatpak-entry.c:605 msgctxt "Project URL Type" msgid "Source Code" msgstr "Codice Sorgente" #: src/bz-flatpak-entry.c:611 msgctxt "Project URL Type" msgid "Contribute" msgstr "Contribuisci" #: src/bz-full-view.blp:20 src/bz-window.blp:117 src/bz-window.blp:394 msgid "Toggle transaction sidebar" msgstr "Mostra o Nasconde il menu delle operazioni" #: src/bz-full-view.blp:43 src/bz-window.blp:417 msgid "Main Menu" msgstr "Menu Principale" #: src/bz-full-view.blp:57 msgid "No Results" msgstr "Nessun risultato" #: src/bz-full-view.blp:58 msgid "Try a different search query" msgstr "Prova con una ricerca diversa" #: src/bz-full-view.blp:64 src/bz-window.blp:184 msgid "Content" msgstr "Contenuto" #: src/bz-full-view.blp:196 msgid "Verified by the original developers" msgstr "Verificato dagli sviluppatori originali" #: src/bz-full-view.blp:223 msgid "Support" msgstr "Supporta" #: src/bz-full-view.blp:243 msgid "Repository Star Count" msgstr "Numero di stelle del repository" #: src/bz-full-view.blp:273 msgid "Open" msgstr "Apri" #: src/bz-full-view.blp:286 msgid "Download & Install Application" msgstr "Installa questa applicazione" #: src/bz-full-view.blp:301 msgid "Uninstall Application" msgstr "Disinstalla questa applicazione" #: src/bz-full-view.blp:316 msgid "Install Other Version" msgstr "Installa altra versione" #: src/bz-full-view.blp:340 msgid "Size" msgstr "Peso" #: src/bz-full-view.blp:456 msgid "Downloads /mo" msgstr "Download /mo" #: src/bz-full-view.c:284 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:288 #, c-format msgid "%.2fM" msgstr "%.2fM" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:291 #, c-format msgid "%.2fK" msgstr "%.2fK" #: src/bz-full-view.c:300 #, c-format msgid "%d downloads in the last 30 days" msgstr "%'d download negli ultimi 30 giorni" #: src/bz-full-view.c:321 #, c-format msgid "Download size of %s" msgstr "Dimensioni Download di %s" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-full-view.c:331 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-full-view.c:339 msgid "All Ages" msgstr "Tutte le Età" #: src/bz-full-view.c:341 msgid "Age Rating" msgstr "Fascia d'Età" #: src/bz-full-view.c:349 msgid "Suitable for all ages" msgstr "Adatto per tutte le età" #: src/bz-full-view.c:351 #, c-format msgid "Suitable for ages %d and up" msgstr "Adatto per %d anni in sù" #: src/bz-full-view.c:375 msgid "Unknown" msgstr "Sconosciuto" #: src/bz-full-view.c:378 msgid "Proprietary Software" msgstr "Software Propietario" #: src/bz-full-view.c:382 #, c-format msgid "Free software licensed under %s" msgstr "Free software sotto licenza %s" #: src/bz-full-view.c:390 msgid "Free" msgstr "Free" #: src/bz-full-view.c:390 msgid "Proprietary" msgstr "Propietario" #: src/bz-full-view.c:410 msgid "Adaptive" msgstr "Adattiva" #: src/bz-full-view.c:410 msgid "Desktop Only" msgstr "Solo Desktop" #: src/bz-full-view.c:416 msgid "Works on desktop, tablets, and phones" msgstr "Funziona su desktop, tablet e telefoni" #: src/bz-full-view.c:417 msgid "May not work on mobile devices" msgstr "Potrebbe non funzionare su dispositvi mobili" #: src/bz-full-view.c:428 msgid "No URL" msgstr "Nessun URL" #: src/bz-full-view.c:446 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Questa applicazione ha una licenza FLOSS, il che significa che il codice " "sorgente può essere controllato per sicurezza." #: src/bz-full-view.c:447 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Questa applicazione ha una licenza proprietaria, il che significa che il " "codice sorgente è sviluppato privatamente e non può essere verificato da una " "terza parte indipendente." #: src/bz-full-view.c:454 msgid "Other Apps by this Developer" msgstr "Altre App di questo Sviluppatore" #: src/bz-full-view.c:456 #, c-format msgid "Other Apps by %s" msgstr "Altre App di %s" #: src/bz-full-view.c:828 msgid "Show Less" msgstr "Mostra di meno" #: src/bz-full-view.c:828 msgid "Show More" msgstr "Mostra di più" #: src/bz-hardware-support-dialog.c:69 msgid "Keyboard support" msgstr "Supporto per le tastiere" #: src/bz-hardware-support-dialog.c:71 msgid "Requires keyboards" msgstr "Richiede le tastiere" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends keyboards" msgstr "Raccomanda le tastiere" #: src/bz-hardware-support-dialog.c:73 msgid "Supports keyboards" msgstr "Supporto per le tastiere" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for keyboards" msgstr "Supporto sconosciuto per le tastiere" #: src/bz-hardware-support-dialog.c:76 msgid "Mouse support" msgstr "Supporto Mouse" #: src/bz-hardware-support-dialog.c:78 msgid "Requires mice or pointing devices" msgstr "Richiede mouse o dispositivi di puntamento" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends mice or pointing devices" msgstr "Raccomanda mouse o dispositivi di puntamento" #: src/bz-hardware-support-dialog.c:80 msgid "Supports mice or pointing devices" msgstr "Supporto per mouse o dispositivi di puntamento" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for mice or pointing devices" msgstr "Supporto sconosciuto per mouse o dispositivi di puntamento" #: src/bz-hardware-support-dialog.c:83 msgid "Touchscreen support" msgstr "Supporto per schermi touchscreen" #: src/bz-hardware-support-dialog.c:85 msgid "Requires touchscreens" msgstr "Richiede schermi touchscreen" #: src/bz-hardware-support-dialog.c:86 msgid "Recommends touchscreens" msgstr "Raccomanda schermi touchscreen" #: src/bz-hardware-support-dialog.c:87 msgid "Supports touchscreens" msgstr "Supporto touchscreen" #: src/bz-hardware-support-dialog.c:88 msgid "Unknown support for touchscreens" msgstr "Supporto sconosciuto per schermi touchscreen" #: src/bz-hardware-support-dialog.c:192 msgid "Mobile support" msgstr "Supporto per dispositivi mobili" #: src/bz-hardware-support-dialog.c:193 msgid "Works on mobile devices" msgstr "Funziona su dispositivi mobili" #: src/bz-hardware-support-dialog.c:193 msgid "May not work well on mobile devices" msgstr "Potrebbe non funzionare su dispositivi mobili" #: src/bz-hardware-support-dialog.c:198 msgid "Desktop support" msgstr "Supporto Desktop" #: src/bz-hardware-support-dialog.c:199 msgid "Works well on large screens" msgstr "Ottimizzato per grandi schermi" #: src/bz-hardware-support-dialog.c:233 #, c-format msgid "%s works best on specific hardware" msgstr "%s funziona al meglio su hardware specifico" #: src/bz-hardware-support-dialog.c:240 #, c-format msgid "%s works on most devices" msgstr "%s funziona sulla maggior parte dei dispositivi" #: src/bz-hardware-support-dialog.blp:6 src/bz-hardware-support-dialog.blp:47 msgid "Hardware Support" msgstr "Supporto Hardware" #: src/bz-inspector.blp:5 msgid "Bazaar Inspector" msgstr "Ispettore di Bazaar" #: src/bz-inspector.blp:22 msgid "Enable Global Debug Mode" msgstr "Abilita Modalità di Debug globale" #: src/bz-inspector.blp:29 msgid "Active Blocklists" msgstr "Blocklist attive" #: src/bz-inspector.blp:46 msgid "Active Curated-Configs" msgstr "Configurazioni attive per Consigliate" #: src/bz-inspector.blp:64 msgid "All Entry Groups" msgstr "Tutti i gruppi di voci" #: src/bz-inspector.blp:72 msgid "Filter..." msgstr "Filtra..." #: src/bz-inspector.blp:113 msgid "Decache and Inspect" msgstr "Elimina la cache ed Ispeziona" #: src/bz-installed-page.blp:19 msgid "No Flatpaks Installed" msgstr "Nessun Flatpak Installato" #: src/bz-installed-page.blp:25 src/bz-window.blp:319 msgid "Installed" msgstr "Installate" #: src/bz-installed-page.c:406 msgid "Choose an Installation" msgstr "Scegli un installazione" #: src/bz-installed-page.c:409 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with? " msgstr "" "Hai installato più versioni di questa app. Con quale desideri procedere? " #: src/bz-installed-page.c:413 src/bz-window.c:1076 src/bz-window.c:1100 msgid "Cancel" msgstr "Annulla" #: src/bz-license-dialog.c:115 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may not be able to contribute to this app." msgstr "" "Questa app non è sviluppata in modo trasparente, quindi solo i suoi " "sviluppatori sanno come funziona. Potrebbe essere insicura in modi difficili " "da rilevare e potrebbe cambiare senza preavviso o supervisione." #: src/bz-license-dialog.c:124 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Questa app è sviluppata apertamente da una comunità internazionale.\n" "\n" "Puoi partecipare e contribuire a renderla ancora migliore." #: src/bz-license-dialog.c:135 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Questa applicazione è sviluppata apertamente da una comunità internazionale " "e rilasciata con licenza %s.\n" "\n" "Puoi partecipare e contribuire a migliorarla." #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Preferenze" #: src/bz-preferences-dialog.blp:23 src/bz-window.blp:334 msgid "Search" msgstr "Cerca" #: src/bz-preferences-dialog.blp:26 msgid "Free Software Only" msgstr "Solo Free Software" #: src/bz-preferences-dialog.blp:27 msgid "Hide proprietary applications from search results" msgstr "Nascondi applicazioni proprietarie dai risultati di ricerca" #: src/bz-preferences-dialog.blp:31 msgid "Flathub Results Only" msgstr "Solo risultati da Flathub" #: src/bz-preferences-dialog.blp:32 msgid "Limit search results to applications only available on Flathub" msgstr "" "Limita i risultati della ricerca alle applicazioni disponibili su Flathub" #: src/bz-preferences-dialog.blp:36 msgid "Delay Search Results" msgstr "Mostra Risultati di Ricerca" #: src/bz-preferences-dialog.blp:37 msgid "Improve results performance by debouncing search terms" msgstr "" "Migliorare le prestazioni dei risultati applicando il debouncing ai termini " "di ricerca" #: src/bz-preferences-dialog.blp:42 msgid "Application Details" msgstr "Dettagli dell'app" #: src/bz-preferences-dialog.blp:45 msgid "Display Star Count" msgstr "Mostra conteggio stelle" #: src/bz-preferences-dialog.blp:46 msgid "Show the star count of an application's source code repository" msgstr "" "Mostra il numero di stelle del repository del codice sorgente di " "un'applicazione" #: src/bz-preferences-dialog.blp:71 msgid "Progress Bar" msgstr "Barra di avanzamento" #: src/bz-preferences-dialog.blp:72 msgid "Choose a theme for the progress bar!" msgstr "Scegli un tema per la barra di avanzamento!" #: src/bz-preferences-dialog.blp:98 msgid "End of Life Apps" msgstr "App Obsolete" #: src/bz-preferences-dialog.blp:101 msgid "Hide EOL Apps" msgstr "Nascondi App obsolete" #: src/bz-preferences-dialog.blp:102 msgid "Hide apps which are no longer supported by their developers" msgstr "Nascondi le app non più supportate dagli sviluppatori" #: src/bz-preferences-dialog.blp:116 msgid "" "Bazaar can fetch and display the star count from an application's source " "code repository on a remote Git forge. \n" " For projects on GitHub, rate limits may cause them not to appear." msgstr "" "Bazaar può recuperare e visualizzare il numero di stelle dal repository del " "codice sorgente di un'applicazione su una piattaforma Git remota.\n" "Per i progetti su GitHub, i limiti di richieste potrebbero impedirne la " "visualizzazione." #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Colore d'accento" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Colori Pride" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "Colori lesbian pride" #: src/bz-preferences-dialog.c:35 msgid "Transgender Pride Colors" msgstr "Colori transgender pride" #: src/bz-preferences-dialog.c:36 msgid "Nonbinary Pride Colors" msgstr "Colori nonbinary pride" #: src/bz-preferences-dialog.c:37 msgid "Bisexual Pride Colors" msgstr "Colori bisexual pride" #: src/bz-preferences-dialog.c:38 msgid "Asexual Pride Colors" msgstr "Colori asexual pride" #: src/bz-preferences-dialog.c:39 msgid "Pansexual Pride Colors" msgstr "" "Non sono disponibili informazioni sulla curatela per questo sistema. È " "comunque possibile sfogliare le applicazioni su Flathub" #: src/bz-preferences-dialog.c:40 msgid "Aromantic Pride Colors" msgstr "Colori aromantic pride" #: src/bz-preferences-dialog.c:41 msgid "Genderfluid Pride Colors" msgstr "Colori genderfluid pride" #: src/bz-preferences-dialog.c:42 msgid "Polysexual Pride Colors" msgstr "Colori polysexual pride" #: src/bz-preferences-dialog.c:43 msgid "Omnisexual Pride Colors" msgstr "Colori omnisexual pride" #: src/bz-releases-dialog.blp:5 src/bz-releases-list.blp:26 msgid "Version History" msgstr "Cronologia delle Versioni" #: src/bz-releases-list.c:128 #, c-format msgid "Version %s" msgstr "Versione %s" #: src/bz-releases-list.c:153 msgid "No details for this release" msgstr "Nessun dettaglio per questa versione" #: src/bz-rich-app-tile.blp:103 msgid "Get" msgstr "Ottieni" #: src/bz-search-widget.blp:105 msgid "Search Apps, Games, Software" msgstr "Cerca App, Giochi, Software" #: src/bz-search-widget.blp:149 msgid "Categories Unavailable" msgstr "Categorie non disponibili" #: src/bz-search-widget.blp:150 msgid "Search for apps using the search bar above." msgstr "Cerca le app digitando nella barra di ricerca superiore." #: src/bz-search-widget.blp:233 msgid "No Applications Found" msgstr "Nessuna Applicazione Trovata" #: src/bz-search-widget.c:225 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "Nessun risultato per \"%s\" in Flathub" #: src/bz-share-list.c:64 msgid "Copied!" msgstr "Copiato!" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "Copia Link" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Apri Link" #: src/bz-stats-dialog.blp:26 msgid "Timeline" msgstr "Cronologia" #: src/bz-stats-dialog.blp:31 msgid "Installs:" msgstr "Installazioni:" #: src/bz-stats-dialog.blp:37 msgid "World" msgstr "Mondiale" #: src/bz-transaction-manager.c:1140 #, c-format msgid "Finished in %.02f seconds" msgstr "Finito in %.02f secondi" #: src/bz-transaction-view.blp:94 msgid "App Add-on" msgstr "Estensioni dell'App" #: src/bz-transaction-view.blp:119 msgid "Runtime" msgstr "Runtime" #: src/bz-transaction-view.blp:145 src/bz-transaction-view.blp:171 msgid "Install Size" msgstr "Dimensione di Installazione" #: src/bz-transaction-view.blp:199 src/bz-window.blp:355 msgid "Update" msgstr "Aggiorna" #: src/bz-transaction-view.c:139 #, c-format msgid "Transferred %s so far" msgstr "Trasferito %s finora" #: src/bz-transaction.c:336 msgid "Pending" msgstr "In attesa" #: src/bz-update-dialog.blp:7 msgid "Install Now" msgstr "Installa ora" #: src/bz-update-dialog.blp:10 msgid "Updates Are Available" msgstr "Sono disponibili aggiornamenti" #: src/bz-update-dialog.blp:11 msgid "" "The following applications are eligible for updates. Would you like to " "install them?" msgstr "Le seguenti applicazioni possono essere aggiornate. Vuoi installarle?" #: src/bz-update-dialog.c:134 #, c-format msgid "" "%d runtimes and/or addons are eligible for updates. Would you like to " "install them?" msgstr "" "%d I runtime e/o i componenti aggiuntivi possono essere aggiornati. Vuoi " "installarli?" #: src/bz-update-dialog.c:142 #, c-format msgid "Additionally, %d runtimes and/or addons will be updated." msgstr "Inoltre, verranno aggiornati %d runtime e/o componenti aggiuntivi." #: src/bz-window.blp:66 msgid "Inspect UI Entry" msgstr "Ispeziona voci UI" #: src/bz-window.blp:73 msgid "All Debug Actions" msgstr "Tutte le Azioni di Debug" #: src/bz-window.blp:98 msgid "Tasks" msgstr "Attività" #: src/bz-window.blp:154 msgid "Stop Active Tasks" msgstr "Interrompi attività attive" #: src/bz-window.blp:162 msgid "Clear History" msgstr "Cancella cronologia" #: src/bz-window.blp:178 msgid "No Tasks Yet" msgstr "Nessuna attività ancora" #: src/bz-window.blp:293 msgid "Curated" msgstr "Consigliate" #: src/bz-window.blp:306 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:481 msgid "_Donate to Bazaar ❤️" msgstr "_Dona a Bazaar ❤️" #: src/bz-window.blp:486 msgid "_Refresh Content" msgstr "_Ricarica Contenuto" #: src/bz-window.blp:493 msgid "_Preferences" msgstr "_Preferenze" #: src/bz-window.blp:498 msgid "_Keyboard Shortcuts" msgstr "_Scorciatoie da tastiera" #: src/bz-window.blp:503 msgid "_About Bazaar" msgstr "_Info su Bazaar" #: src/bz-window.blp:510 msgid "_Quit Bazaar" msgstr "_Chiude Bazaar" #: src/bz-window.blp:519 msgid "Open Bazaar Inspector" msgstr "Apri Ispettore di Bazaar" #: src/bz-window.c:819 msgid "" "The ability to inspect and install local .flatpak bundle files is coming " "soon! In the meantime, try running\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "on the command line." msgstr "" "La possibilità di ispezionare e installare i file bundle .flatpak locali è " "in arrivo! Nel frattempo, provate a eseguire\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "alla riga di comando." #: src/bz-window.c:941 msgid "Can't do that right now!" msgstr "Non posso farlo adesso!" #: src/bz-window.c:1070 #, c-format msgid "Install %s?" msgstr "Installare %s?" #: src/bz-window.c:1073 msgid "May install additional shared components" msgstr "È possibile installare componenti condivisi aggiuntivi" #: src/bz-window.c:1092 #, c-format msgid "Remove %s?" msgstr "Rimuovere %s?" #: src/bz-window.c:1096 #, c-format msgid "" "It will not be possible to use %s after it is uninstalled.\n" "\n" "Settings and user data will be kept." msgstr "" "Non sarà possibile usare %s dopo la disinstallazione.\n" "\n" "Le impostazioni e i dati utente verranno conservati." #: src/bz-window.c:1262 msgid "Resume Current Tasks" msgstr "Riprendi attività correnti" #: src/bz-window.c:1268 msgid "Pause Current Tasks" msgstr "Sospendi attività correnti" #: src/bz-world-map.c:523 #, c-format msgid "%s: %'u downloads" msgstr "%s: %'u download" #: src/gtk/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Generali" #: src/gtk/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "Apre la barra di ricerca" #: src/gtk/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Apri le Preferenze" #: src/gtk/shortcuts-dialog.blp:19 msgctxt "shortcut window" msgid "Refresh" msgstr "Ricarica" #: src/gtk/shortcuts-dialog.blp:24 msgctxt "shortcut window" msgid "Toggle Transaction Manager" msgstr "Mostra o Nasconde menu delle operazioni" #: src/gtk/shortcuts-dialog.blp:29 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Mostra scorciatoie da tastiera" #: src/gtk/shortcuts-dialog.blp:34 msgctxt "shortcut window" msgid "Quit" msgstr "Esce" #~ msgid "Searching for Blender" #~ msgstr "Ricerca di Blender" #~ msgid "Manage Addons" #~ msgstr "Gestione delle estensioni" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Ahmed Najmawi" #~ msgstr "Ahmed Najmawi" #~ msgctxt "About Dialog Translator Credit" #~ msgid "AtomHare" #~ msgstr "AtomHare" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Azenyr" #~ msgstr "Azenyr" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Goudarz Jafari" #~ msgstr "Goudarz Jafari" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Jill Fiore (Lumaeris)" #~ msgstr "Jill Fiore (Lumaeris)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "João Victor (Leal)" #~ msgstr "João Victor (Leal)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "KiKaraage" #~ msgstr "KiKaraage" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Lucosec" #~ msgstr "Lucosec" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Léane GRASSER" #~ msgstr "Léane GRASSER" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Marcel Mrówka (Microwave)" #~ msgstr "Marcel Mrówka (Microwave)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Peter Dave Hello" #~ msgstr "Peter Dave Hello" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Pietro F." #~ msgstr "Pietro F." #~ msgctxt "About Dialog Translator Credit" #~ msgid "Shihfu Juan" #~ msgstr "Shihfu Juan" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Shinsei" #~ msgstr "Shinsei" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Vlastimil Dědek" #~ msgstr "Vlastimil Dědek" #~ msgctxt "About Dialog Translator Credit" #~ msgid "asen23" #~ msgstr "asen23" #~ msgctxt "About Dialog Translator Credit" #~ msgid "camegone" #~ msgstr "camegone" #~ msgctxt "About Dialog Translator Credit" #~ msgid "renner" #~ msgstr "renner" #~ msgctxt "About Dialog Translator Credit" #~ msgid "robotta" #~ msgstr "robotta" #, c-format #~ msgid "" #~ "Beginning remote entry retrieval while referencing %d blocklist(s)..." #~ msgstr "" #~ "Avvio recupero delle voci remote facendo riferimento a %d blocklist..." #~ msgid "" #~ "Bazaar was not provided a curated content configuration. Contact your " #~ "operating system's support channels for assistance." #~ msgstr "" #~ "Non è stata fornita alcuna configurazione di contenuti consigliati per " #~ "Bazaar. Per assistenza, contattare il supporto del sistema operativo." #~ msgid "Games" #~ msgstr "Giochi" #~ msgid "Graphics" #~ msgstr "Grafica e Fotografia" #~ msgid "Office" #~ msgstr "Produttività" #~ msgctxt "Project URL Type" #~ msgid "Homepage" #~ msgstr "Sito del Progetto" #~ msgid "Share this application" #~ msgstr "Condividi questa applicazione" #~ msgid "Excludes shared components" #~ msgstr "Esclude componenti condivisi" #~ msgid "Source code may not be available" #~ msgstr "Il codice sorgente potrebbe non essere disponibile" #~ msgid "Click for details" #~ msgstr "Clicca per maggiori dettagli" #~ msgid "Repositories" #~ msgstr "Repository" #~ msgid "Open in browser" #~ msgstr "Apri nel browser" #, c-format #~ msgid "%'d Monthly Downloads" #~ msgstr "%'d Download Mensili" #~ msgid "%B %-d, %Y" #~ msgstr "%B %-d, %Y" #~ msgid "%B %-d" #~ msgstr "%B %-d" #~ msgid "Support this application" #~ msgstr "Supporta questa applicazione" #~ msgid "Run this application" #~ msgstr "Avvia questa applicazione" #~ msgid "Run" #~ msgstr "Avvia" #~ msgid "View Store Page" #~ msgstr "Mostra dettagli nello Store" #~ msgid "Git Forge Star Counts" #~ msgstr "Numero di stelle Git Forge" #~ msgid "Not having a GitHub access token may trigger rate limits" #~ msgstr "" #~ "La mancanza di un token di accesso GitHub può causare limiti di velocità" #~ msgid "Show Only Flathub Apps" #~ msgstr "Mostra solo applicazioni da Flathub" #~ msgid "Wait for a brief pause to reduce system load" #~ msgstr "Attendere una breve pausa per ridurre il carico del sistema." #~ msgid "Theme" #~ msgstr "Tema" #~ msgid "Pride Rainbow Flag" #~ msgstr "Bandiera arcobaleno" #~ msgid "Bisexual Flag" #~ msgstr "Bandiera bisessuale" #~ msgid "Asexual Flag" #~ msgstr "Bandiera asessuale" #~ msgid "Share" #~ msgstr "Condividi" #~ msgid "Error Details" #~ msgstr "Dettagli dell'errore" #~ msgid "Transactions" #~ msgstr "Transazioni" #~ msgid "Loading" #~ msgstr "Caricamento" #~ msgid "Browse" #~ msgstr "Esplora" #~ msgid "App View" #~ msgstr "Vista dell'App" #~ msgid "Go Back" #~ msgstr "Vai indietro" #~ msgid "View curated applications" #~ msgstr "Visualizza applicazioni consigliate" #~ msgid "View the latest on Flathub" #~ msgstr "Visualizza le ultime novità di Flathub" #~ msgid "View installed applications" #~ msgstr "Visualizza applicazioni installate" #~ msgid "_Quit Service" #~ msgstr "_Esce dal servizio" #~ msgid "Up to date!" #~ msgstr "Aggiornato!" #~ msgid "Settings & user data will be kept" #~ msgstr "Le impostazioni e i dati utente saranno conservati" #~ msgid "Calligraphy application page" #~ msgstr "Pagina dell'applicazione Calligraphy" #~ msgid "Download graph for Blender" #~ msgstr "Grafico dei download di Blender" #~ msgid "Open this image in the default image viewer" #~ msgstr "Apri questa immagine nel visualizzatore di immagini di default" #~ msgid "Copy this image to the clipboard" #~ msgstr "Copia questa immagine negli appunti" #~ msgid "App Details" #~ msgstr "Dettagli dell'app" #~ msgid "License" #~ msgstr "Licenza" #~ msgid "Download Statistics" #~ msgstr "Statistiche di Download" #~ msgid "Show Downloads Over Time" #~ msgstr "Mostra download nel tempo" #~ msgid "Remote repo name" #~ msgstr "Nome del repository remoto" #~ msgid "Updated Size" #~ msgstr "Dimensione dell'aggiornamento" #~ msgid "Freed Space" #~ msgstr "Spazio liberato" #~ msgid "Transactions Will Appear Here" #~ msgstr "Le operazioni appariranno qui" #~ msgid "Halt the execution of transactions" #~ msgstr "Ferma l'esecuzione delle operazioni" #~ msgid "Clear all finished transactions" #~ msgstr "Cancella tutte le operazioni completate" #~ msgid "Resume the execution of transactions" #~ msgstr "Riprende l'esecuzione delle operazioni" #~ msgid "Pause the execution of transactions" #~ msgstr "Mette in pausa l'esecuzione delle operazioni" #~ msgid "Downloads Over Time" #~ msgstr "Download nel tempo" #~ msgid "Confirm Action" #~ msgstr "Conferma Azione" #, c-format #~ msgid "" #~ "You are about to remove the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "Stai per disinstallare il seguente Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Sei sicuro?" #, c-format #~ msgid "" #~ "You are about to install the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "Stai per installare il seguente Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Sei sicuro?" #~ msgid "Apps Of The Week" #~ msgstr "Applicazioni della Settimana" #, c-format #~ msgid "Released %x" #~ msgstr "Rilasciata il %x" #~ msgid "Minimize Lower Bound" #~ msgstr "Minimizzare il limite inferiore" #~ msgid "Maximize Upper Bound" #~ msgstr "Massimizzare il limite superiore" #~ msgctxt "Project URL Type" #~ msgid "VCS Browser" #~ msgstr "Sfoglia il codice sorgente" #~ msgid "Full Application View" #~ msgstr "Vista completa dell'applicazione" #~ msgid "Change what content is shown when viewing applications" #~ msgstr "" #~ "Modifica i contenuti visualizzati durante la visualizzazione delle " #~ "applicazioni" #~ msgid "" #~ "If you do not have an access token, turning this setting on may cause " #~ "GitHub to eventually rate limit you." #~ msgstr "" #~ "Se non disponi di un token di accesso, attivando questa impostazione " #~ "GitHub potrebbe eventualmente limitare la tua velocità di accesso." #~ msgid "Type to filter" #~ msgstr "Digita per cercare" #~ msgid "Exclude results with proprietary licenses" #~ msgstr "Escludi risultati con licenza proprietaria" #~ msgid "Exclude results not originating from Flathub" #~ msgstr "Escludi risultati non provenienti da Flathub" #~ msgid "Advanced" #~ msgstr "Avanzate" #~ msgid "Open this link externally" #~ msgstr "Aprire questo link in un'applicazione esterna" #, c-format #~ msgid "Received %'d entries out of %'d (%0.1f seconds elapsed)" #~ msgstr "Ricevute %'d voci su %'d (%.1f secondi trascorsi)" #~ msgid "Finished Tasks" #~ msgstr "Operazioni Completate" #, c-format #~ msgid "%s to install" #~ msgstr "%s da installare" #~ msgid "Open in Image Viewer" #~ msgstr "Apri nel Visualizzatore Immagini" #~ msgid "Installing" #~ msgstr "Installazione" #~ msgid "Updating" #~ msgstr "Aggiornamento" #~ msgid "Removing" #~ msgstr "Rimozione" #~ msgid "Show Animated Background" #~ msgstr "Mostra sfondo animato" #~ msgid "Whether to show the animated icon background on the home page" #~ msgstr "Mostrare o nascondere lo sfondo animato sulla pagina iniziale" #~ msgid "" #~ "The number of downloads in the last 30 days. Click to view this " #~ "application's download statistics." #~ msgstr "" #~ "Il numero di download negli ultimi 30 giorni. Clicca per vedere le " #~ "statistiche." #~ msgid "This application does not provide a donation link" #~ msgstr "Questa applicazione non fornisce un link per le donazioni" #~ msgid "Edit Permissions" #~ msgstr "Modifica le autorizzazioni" #, c-format #~ msgid "" #~ "\"%s\" does not provide a donations link. This does not mean you cannot " #~ "support them! Try looking at their project page for " #~ "more information." #~ msgstr "" #~ "“%s” non fornisce un link per le donazioni. Ciò non significa che non " #~ "puoi sostenerli! Prova a consultare la loro pagina del " #~ "progetto per ulteriori informazioni." #, c-format #~ msgid "" #~ "\"%s\" does not provide a donations link. This does not mean you cannot " #~ "support them! Try finding their project page for more information." #~ msgstr "" #~ "“%s” non fornisce un link per le donazioni. Ciò non significa che non " #~ "puoi sostenerli! Prova a cercare la pagina del loro progetto per " #~ "ulteriori informazioni." #~ msgid "How the application looks" #~ msgstr "Aspetto dell'applicazione" #~ msgid "Appearance" #~ msgstr "Aspetto" #~ msgid "Show animated background" #~ msgstr "Mostra sfondo animato" #~ msgid "Keep the summary shorter, between 10 and 35 characters" #~ msgstr "Mantenere la descrizione breve, tra i 10 e i 35 caratteri." #~ msgid "No description" #~ msgstr "Nessuna descrizione" #~ msgid "Main Bazaar window showing Blender" #~ msgstr "Finestra principale di Bazaar nella pagina di Blender" #~ msgid "Match using regular expressions" #~ msgstr "Corrispondenza tramite espressioni regolari" #~ msgid "Hide filtering and sorting behind a crossfade effect" #~ msgstr "" #~ "Nascondere il filtro e l'ordinamento con un effetto di dissolvenza " #~ "incrociata" bazaar-orig-v0.7.14/po/id.po0000664000175000017500000027417015166123241014525 0ustar hasanhasan# Indonesian translations for bazaar package. # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # # SPDX-FileCopyrightText: 2025 asen23 # KiKaraage , 2025-2026. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-03-24 10:16+0700\n" "PO-Revision-Date: 2026-03-30 02:31+0700\n" "Last-Translator: KiKaraage \n" "Language-Team: Indonesian\n" "Language: id\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Gtranslator 50.0\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:46 #: src/bz-window.c:377 src/bz-window.c:378 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "Tambah, hapus atau perbarui aplikasi Flatpak pada komputer ini" # Added "Aplikasi" and "Pusat Aplikasi" (App Center) to search queries #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;Sistem;PackageManager;Discover;Flatpak;Aplikasi;Toko;PerangkatLunak;PusatAplikasi;ManajerPaket;" #: data/io.github.kolunmi.Bazaar.desktop.in:16 msgid "New Window" msgstr "Jendela Baru" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and manage applications" msgstr "Temukan dan pasang aplikasi" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A fast and modern app store for Linux with a focus on discovering and " "installing Flatpak apps and addons, particularly from Flathub." msgstr "" "Toko aplikasi Linux yang cepat dan modern, berfokus pada kemudahan menemukan " "serta memasang aplikasi dan modul tambahan Flatpak, terutama dari Flathub." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:15 msgid "Queue multiple installs and keep browsing" msgstr "Pasang beberapa aplikasi sekaligus dan lanjut menjelajah" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:16 msgid "Easily view app permissions" msgstr "Dapat melihat izin aplikasi secara mudah" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:17 msgid "Sign in to Flathub to view and manage your favorites" msgstr "Masuk dengan Flathub untuk lihat dan kelola aplikasi favoritmu" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:18 msgid "Search apps directly from GNOME Shell" msgstr "Cari aplikasi langsung dari bilah pencarian GNOME" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:30 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:55 msgid "The home page displaying Flathub apps" msgstr "Tampilan muka dengan daftar aplikasi dari Flathub" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:59 msgid "Exhibit app page" msgstr "Tampilan halaman detail aplikasi" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:63 msgid "Library page" msgstr "Halaman pustaka aplikasi" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:67 msgid "Search page" msgstr "Tampilan pencarian aplikasi" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:71 msgid "Category page" msgstr "Tampilan kategori aplikasi" #: src/bz-addons-dialog.blp:16 src/bz-full-view.blp:627 #: src/bz-installed-tile.blp:101 msgid "Manage Add-Ons" msgstr "Kelola Modul Tambahan" #: src/bz-addons-dialog.c:94 src/bz-install-controls.blp:137 #: src/bz-installed-tile.blp:114 msgid "Remove" msgstr "Hapus" #: src/bz-addons-dialog.c:99 src/bz-favorites-tile.c:159 msgid "Install" msgstr "Pasang" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 #: src/bz-age-rating-dialog.c:736 src/bz-full-view.c:333 src/bz-full-view.c:340 msgid "Age Rating" msgstr "Peringkat Usia" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "Kekerasan (Kartun)" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "Tidak ada info mengenai penggambaran kekerasan berbentuk kartun" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "Kekerasan (Fantasi)" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "Tidak ada info mengenai penggambaran kekerasan berbentuk fantasi" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "Kekerasan (Nyata)" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "Tidak ada info mengenai penggambaran kekerasan realistik" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "Kekerasan Menggambarkan Pertumpahan Darah" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "Tidak ada info mengenai penggambaran pertumpahan darah" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "Kekerasan Seksual" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "Tidak ada info mengenai penggambaran kekerasan seksual" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "Minuman Keras" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "" "Tidak ada info mengenai penggambaran/penyebutan terkait minuman beralkohol" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "Narkotika" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "" "Tidak ada info mengenai referensi terkait narkotika dan obat-obatan terlarang" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "Rokok" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "Tidak ada info mengenai referensi terkait rokok " #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "Ketelanjangan" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "Tidak ada info mengenai segala bentuk ketelanjangan" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "Tema Seksual" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "" "Tidak ada info mengenai segala bentuk referensi atau penggambaran seksual " #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "Kata-Kata Kasar" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "Tidak ada info mengenai segala penggunaan kata-kata kasar" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "Humor Tidak Pantas" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "Tidak ada info mengenai penggunaan humor yang tidak pantas" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "Diskriminasi" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "Tidak ada info mengenai segala penggunaan bahasa yang diskriminatif" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "Iklan" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "Tidak ada info mengenai semua bentuk iklan" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "Judi" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "" "Tidak ada info mengenai segala penyebutan dan penggambaran terkait judi" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "Jual Beli" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "Tidak ada info mengenai kemampuan transaksi atau pembelian" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "Obrolan Antar Pengguna" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "Tidak ada info mengenai cara melakukan obrolan dengan pengguna lain" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "Panggilan Antar Pengguna" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "" "Tidak ada info mengenai cara melakukan panggilan suara dengan pengguna lain" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 msgid "Contact Details" msgstr "Rincian Kontak" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "" "Tidak ada info terkait tindakan berbagi nama pengguna di media sosial atau " "alamat email" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "Informasi Identifikasi" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "" "Tidak ada info terkait tindakan membagikan info pengguna dengan pihak ketiga " #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "Berbagi Lokasi" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "Tidak ada info mengenai tindakan berbagi lokasi dengan pengguna lain" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "Prostitusi" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "Tidak ada info mengenai penyebutan referensi terkait prostitusi" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "Zina" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "Tidak ada info mengenai penyebutan referensi terkait perzinaan" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "Karakter yang Diseksualisasi" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "Tidak ada info mengenai karakter yang diseksualisasikan" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 msgid "Desecration" msgstr "Penistaan" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "Tidak ada info mengenai penyebutan referensi terkait penistaan" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "Jasad Manusia" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "Tidak ada info mengenai terlihatnya sisa-sisa jasad manusia" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "Perbudakan" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "Tidak ada info mengenai penyebutan referensi terkait perbudakan" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "Tidak memuat referensi terkait obat-obatan terlarang" #: src/bz-age-rating-dialog.c:426 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "Tidak memuat penggunaan kata-kata kasar dan umpatan" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "Tidak memuat iklan atau transaksi keuangan" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "Tidak memuat konten seksual" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "Tidak memuat kemampuan obrolan tanpa moderasi" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "Tidak memuat konten kekerasan" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "Obat Terlarang" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "Kata-Kata Kasar" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "Uang" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "Sosial" #: src/bz-age-rating-dialog.c:479 msgid "Violence" msgstr "Kekerasan" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:686 src/bz-full-view.c:323 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:711 msgctxt "Age rating" msgid "All" msgstr "Semua" #: src/bz-age-rating-dialog.c:747 #, c-format msgid "%s has an unknown age rating" msgstr "Peringkat usia untuk %s tidak diketahui" #: src/bz-age-rating-dialog.c:753 #, c-format msgid "%s is suitable for everyone" msgstr "%s cocok untuk semua usia" #: src/bz-age-rating-dialog.c:756 #, c-format msgid "%s is suitable for young children" msgstr "%s diperbolehkan untuk usia balita" #: src/bz-age-rating-dialog.c:759 #, c-format msgid "%s is suitable for children" msgstr "%s diperbolehkan untuk usia anak-anak" #: src/bz-age-rating-dialog.c:762 #, c-format msgid "%s is suitable for teenagers" msgstr "%s diperbolehkan untuk usia remaja" #: src/bz-age-rating-dialog.c:765 #, c-format msgid "%s is suitable for adults" msgstr "%s diperbolehkan untuk usia dewasa" #: src/bz-age-rating-dialog.c:768 #, c-format msgid "%s is suitable for %s" msgstr "%s diperbolehkan untuk usia %s" #: src/bz-age-rating-dialog.c:862 #, c-format msgid "%s • %s" msgstr "%s • %s" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:29 #: src/bz-user-data-page.blp:15 src/bz-window.blp:239 msgid "Main Menu" msgstr "Menu Utama" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 #: src/bz-user-data-page.blp:19 src/bz-window.blp:328 msgid "_Donate to Bazaar ❤️" msgstr "_Donasi ke Bazaar ❤️" #: src/bz-all-apps-page.blp:25 src/bz-apps-page.blp:25 #: src/bz-user-data-page.blp:26 src/bz-window.blp:335 msgid "_Refresh" msgstr "_Muat Ulang" #: src/bz-all-apps-page.blp:30 src/bz-apps-page.blp:30 #: src/bz-user-data-page.blp:31 src/bz-window.blp:340 msgid "_Preferences" msgstr "_Pengaturan" #: src/bz-all-apps-page.blp:35 src/bz-apps-page.blp:35 #: src/bz-user-data-page.blp:36 src/bz-window.blp:345 msgid "_Login With Flathub" msgstr "_Masuk Dengan Flathub" #: src/bz-all-apps-page.blp:41 src/bz-apps-page.blp:41 #: src/bz-user-data-page.blp:42 src/bz-window.blp:351 msgid "_Manage Leftover User Data" msgstr "_Kelola Sisa Data Pengguna" #: src/bz-all-apps-page.blp:46 src/bz-apps-page.blp:46 #: src/bz-user-data-page.blp:47 src/bz-window.blp:356 msgid "_Keyboard Shortcuts" msgstr "_Pintasan Papan Tik" #: src/bz-all-apps-page.blp:51 src/bz-apps-page.blp:51 #: src/bz-user-data-page.blp:52 src/bz-window.blp:361 msgid "_About Bazaar" msgstr "_Tentang Bazaar" #: src/bz-all-apps-page.blp:58 src/bz-apps-page.blp:58 #: src/bz-user-data-page.blp:59 src/bz-window.blp:368 msgid "_Quit Bazaar" msgstr "_Tutup Bazaar" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "Folder sistem %s" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "Subfolder beranda %s" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "Folder sistem utama" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "Konfigurasi sistem utama dari /etc" #: src/bz-app-permissions.c:169 #, c-format msgid "Desktop subfolder %s" msgstr "Subfolder desktop %s" #: src/bz-app-permissions.c:170 msgid "Desktop folder" msgstr "Folder desktop" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "Subfolder dokumen %s" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "Folder dokumen" #: src/bz-app-permissions.c:177 #, c-format msgid "Music subfolder %s" msgstr "Subfolder musik %s" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "Folder musik" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "Subfolder gambar %s" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "Folder gambar" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "Subfolder Berkas Publik %s" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "Folder Berkas Publik" #: src/bz-app-permissions.c:189 #, c-format msgid "Videos subfolder %s" msgstr "Subfolder video %s" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "Folder video" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "Subfolder templat %s" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "Folder templat" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "Subfolder cache pengguna %s" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "Folder cache pengguna" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "Subfolder konfigurasi pengguna %s" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "Folder konfigurasi pengguna" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "Subfolder data pengguna %s" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "Folder data pengguna" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "Subfolder tempokerja pengguna %s" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "Folder tempokerja pengguna" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "Akses sistem file ke %s" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "Jalur sistem file tidak diketahui" #: src/bz-app-size-dialog.blp:29 src/bz-app-size-dialog.blp:55 msgid "Download Size" msgstr "Ukuran Unduh" #: src/bz-app-size-dialog.blp:56 msgid "Amount to download from the internet" msgstr "Ukuran yang diunduh dari internet" #: src/bz-app-size-dialog.blp:76 msgid "Installed Size" msgstr "Ukuran Terpasang" #: src/bz-app-size-dialog.blp:77 msgid "Size on Disk" msgstr "Ukuran Tersimpan" #: src/bz-app-size-dialog.blp:125 msgid "Open user data folder" msgstr "Buka folder data pengguna" #: src/bz-app-size-dialog.blp:135 msgid "User Data Size" msgstr "Ukuran Data Pengguna" #: src/bz-app-size-dialog.blp:136 msgid "Caches, settings, and other app data" msgstr "Cache, konfigurasi, dan data aplikasi lainnya" #: src/bz-app-size-dialog.c:99 msgid "Installed Runtime Size" msgstr "Ukuran Tempokerja Terpasang" #: src/bz-app-size-dialog.c:99 msgid "Runtime Download Size" msgstr "Ukuran Unduh Tempokerja" #: src/bz-app-tile.blp:57 src/bz-developer-badge.c:98 #: src/bz-rich-app-tile.blp:104 src/bz-rich-app-tile.c:304 msgid "Verified" msgstr "Terverifikasi" #. Translators: As in 'The app is installed'. #: src/bz-app-tile.blp:88 src/bz-full-view.c:282 src/bz-releases-list.c:205 msgid "Installed" msgstr "Terpasang" #: src/bz-apps-page.blp:142 msgid "Show All" msgstr "Tunjukkan Semua" #: src/bz-apps-page.c:229 #, c-format msgid "All \"%s\"" msgstr "Semua \"%s\"" #: src/bz-apps-page.c:478 src/bz-tag-list.c:91 #, c-format msgid "%d Applications" msgstr "%d Aplikasi" #: src/bz-application.c:695 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:696 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #: src/bz-application.c:716 msgid "The Bazaar Contributors" msgstr "Kontributor Bazaar" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:719 msgid "translator-credits" msgstr "KiKaraage , 2025" #: src/bz-application.c:729 msgid "Special Thanks" msgstr "Terima Kasih Khusus" #: src/bz-application.c:787 msgid "Logged Out Successfully!" msgstr "Akun Berhasil Dikeluarkan!" #: src/bz-application.c:910 msgid "Performing setup…" msgstr "Melakukan pengaturan..." #: src/bz-application.c:994 msgid "Set Up System Flathub?" msgstr "Atur Flathub pada Sistem?" #: src/bz-application.c:997 msgid "" "The system Flathub remote is not set up. Bazaar requires Flathub to be " "configured on the system Flatpak installation to browse and install " "applications.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub belum diatur sebagai sumber Flatpak pada sistem ini. Bazaar " "membutuhkan Flathub terkonfigurasi sebagai sumber Flatpak sistem untuk " "mencari dan memasang aplikasi.\n" "\n" "Anda masih dapat menggunakan Bazaar untuk mencari dan menghapus aplikasi " "terpasang." #: src/bz-application.c:1004 msgid "Set Up Flathub?" msgstr "Atur Flathub?" #: src/bz-application.c:1007 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub belum diatur pada sistem ini. Anda tidak dapat mencari dan memasang " "aplikasi lewat Bazaar jika Flathub belum tersedia.\n" "\n" "Anda masih dapat menggunakan Bazaar untuk mencari dan menghapus aplikasi " "terpasang." #: src/bz-application.c:1013 msgid "Later" msgstr "Nanti" #: src/bz-application.c:1014 msgid "Set Up Flathub" msgstr "Atur Flathub" #: src/bz-application.c:1303 msgid "A backend error occurred" msgstr "Terjadi kegagalan latar belakang" #: src/bz-application.c:1499 src/bz-application.c:3357 src/bz-window.blp:70 msgid "Refreshing…" msgstr "Memuat ulang..." #: src/bz-application.c:1651 src/bz-application.c:3355 #, c-format msgid "Loading %d apps…" msgstr "%d aplikasi dimuat..." #: src/bz-application.c:1654 msgid "Checking for updates…" msgstr "Memeriksa pembaruan..." #: src/bz-application.c:1717 msgid "Failed to open .flatpakref" msgstr "Gagal membuka .flatpakref" #: src/bz-application.c:1773 msgid "An initialization error occurred" msgstr "Terjadi kegagalan initialisasi" #: src/bz-application.c:2123 msgid "Failed to check for updates" msgstr "Gagal memeriksa pembaruan" #: src/bz-application.c:3128 msgid "Could not find app" msgstr "Tidak dapat mencari aplikasi" #: src/bz-application.c:3359 msgid "Writing to cache…" msgstr "Menulis cache..." #: src/bz-appstream-parser.c:302 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Halaman Flathub" #: src/bz-appstream-parser.c:323 msgctxt "Project URL Type" msgid "Project Website" msgstr "Situs Web Proyek" #: src/bz-appstream-parser.c:327 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Pelacak Masalah" #: src/bz-appstream-parser.c:331 msgctxt "Project URL Type" msgid "FAQ" msgstr "Pertanyaan Jamak" #: src/bz-appstream-parser.c:335 msgctxt "Project URL Type" msgid "Help" msgstr "Bantuan" #: src/bz-appstream-parser.c:339 msgctxt "Project URL Type" msgid "Donate" msgstr "Sumbang" #: src/bz-appstream-parser.c:345 msgctxt "Project URL Type" msgid "Translate" msgstr "Terjemahkan" #: src/bz-appstream-parser.c:349 msgctxt "Project URL Type" msgid "Contact" msgstr "Kontak" #: src/bz-appstream-parser.c:353 msgctxt "Project URL Type" msgid "Source Code" msgstr "Kode Sumber" #: src/bz-appstream-parser.c:359 msgctxt "Project URL Type" msgid "Contribute" msgstr "Berkontribusi" #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:68 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:62 #: src/bz-library-page.blp:65 src/bz-user-data-page.blp:86 msgid "Empty" msgstr "Kosong" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "Pilihan Belum Tersedia" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "Info aplikasi pilihan tidak tersedia pada sistem ini. Anda masih dapat " "menjelajahi aplikasi dari Flathub" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "Jelajah Flathub" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "Tidak Ada Jaringan" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 #: src/bz-search-pill-list.c:67 msgid "Browser" msgstr "Peramban" #: src/bz-developer-badge.c:94 src/bz-developer-badge.c:98 msgid "Not Verified" msgstr "Tidak Terverifikasi" #: src/bz-developer-badge.c:145 msgid "Developer information not available." msgstr "Informasi pengembang tidak tersedia." #: src/bz-developer-badge.c:151 src/bz-developer-badge.c:165 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "" "Kepemilikan ID aplikasi %s belum diverifikasi, kemungkinan dikemas dalam " "skala komunitas." #: src/bz-developer-badge.c:169 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "" "Kepemilikan ID aplikasi %s telah diverifikasi secara manual \n" " tim Flathub." #: src/bz-developer-badge.c:175 #, c-format msgid "" "The ownership of the %1$s app ID has been verified by %2$s on " "%3$s." msgstr "" "Kepemilikan ID aplikasi %1$s telah diverifikasi oleh %2$s di %3$s." #: src/bz-developer-badge.c:182 #, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "Kepemilikan ID aplikasi %1$s telah diverifikasi menggunakan %2$s." #: src/bz-developer-badge.c:186 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "Kepemilikan ID aplikasi %s telah diverifikasi." #: src/bz-donations-dialog.blp:74 msgid "Full Release Notes" msgstr "Catatan Rilis Lengkap" #: src/bz-donations-dialog.blp:108 msgid "This release was made possible by users like you!" msgstr "Versi ini dapat rilis karena dukungan Anda!" #: src/bz-donations-dialog.blp:116 msgid "" "I love making Bazaar, but I cannot do it alone. Help support further " "development by donating on Ko-Fi." msgstr "" "Saya cinta Bazaar, namun saya tidak dapat mengembangkannya sendiri. Jika " "Anda ingin membantu pengembangan lebih lanjut, mari berdonasi lewat Ko-fi:" #: src/bz-donations-dialog.blp:131 msgid "Donate to Bazaar" msgstr "Donasi ke Bazaar" #. Translators: the %s format specifier will be something along the lines of "0.7.6" etc #: src/bz-donations-dialog.c:227 #, c-format msgid "What's New in %s?" msgstr "Apa Yang Baru di %s?" #. Translators: this is a release date label, like "Released February 9, 2026" #: src/bz-donations-dialog.c:243 msgid "Released %B %-e, %Y" msgstr "Dirilis pada %-e %B %Y" #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "Pilih Pemasangan" #: src/bz-entry-group-util.c:76 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "" "Anda telah memasang beberapa versi aplikasi ini. Versi mana yang ingin Anda " "gunakan?" #: src/bz-entry-group-util.c:80 msgid "Cancel" msgstr "Batal" #: src/bz-entry-selection-row.blp:17 msgid "For This User Only" msgstr "Hanya untuk pengguna ini" #: src/bz-entry-selection-row.c:112 msgid "this user" msgstr "pengguna ini" #: src/bz-entry-selection-row.c:112 msgid "all users" msgstr "semua pengguna" #: src/bz-error.c:69 src/bz-error.c:88 src/bz-error-dialog.blp:36 #: src/bz-safety-dialog.blp:50 msgid "Details" msgstr "Rincian" #: src/bz-error-dialog.blp:47 msgid "Copy" msgstr "Salin" #: src/bz-error-dialog.c:56 src/bz-share-list.c:64 msgid "Copied!" msgstr "Tersalin!" #: src/bz-favorite-button.c:388 msgid "Failed to update favorite" msgstr "Gagal memperbarui daftar favorit" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "Masuk dengan Flathub dan kelola aplikasi favorit" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "Masuk" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "Jumlah Favorit" #: src/bz-favorites-tile.c:157 src/bz-rich-app-tile.blp:172 msgid "Uninstall" msgstr "Bongkar" #: src/bz-favorites-tile.c:357 msgid "Failed to remove favorite" msgstr "Gagal melepas status favorit" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:78 msgid "Support This Application" msgstr "Dukung Aplikasi Ini" #: src/bz-favorites-tile.blp:119 msgid "Remove From Favorites" msgstr "Hapus dari Favorit" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:78 #: src/bz-window.blp:386 msgid "Favorites" msgstr "Aplikasi Favorit" #: src/bz-favorites-page.blp:17 src/bz-section-view.blp:144 msgid "Install All" msgstr "Pasang Semua" #: src/bz-favorites-page.blp:34 src/bz-full-view.blp:45 src/bz-window.blp:255 msgid "Open App Library" msgstr "Buka Pustaka Aplikasi" #: src/bz-favorites-page.blp:56 src/bz-user-data-page.blp:75 msgid "Loading" msgstr "Memuat" #: src/bz-favorites-page.blp:71 msgid "No Favorites" msgstr "Tidak Ada Favorit" #: src/bz-favorites-page.blp:72 msgid "Applications you mark as favorite will appear here" msgstr "Aplikasi yang Anda tandai sebagai favorit akan muncul di sini" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "Sebelumnya" #: src/bz-featured-carousel.blp:54 msgid "Next" msgstr "Selanjutnya" #: src/bz-featured-tile.blp:90 msgid "App of the Day" msgstr "Aplikasi Hari Ini" #: src/bz-flathub-category.c:89 msgid "Editing" msgstr "Penyunting" #: src/bz-flathub-category.c:90 msgid "Midi" msgstr "Midi" #: src/bz-flathub-category.c:91 msgid "Mixer" msgstr "Mixer" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-flathub-category.c:92 src/bz-search-pill-list.c:77 msgid "Music" msgstr "Musik" #: src/bz-flathub-category.c:93 msgid "Player" msgstr "Pemutar" #: src/bz-flathub-category.c:94 msgid "Recorder" msgstr "Perekam" #: src/bz-flathub-category.c:95 msgid "Sequencer" msgstr "Pengurut" #: src/bz-flathub-category.c:96 msgid "Tuner" msgstr "Pengontrol" #: src/bz-flathub-category.c:97 msgid "TV" msgstr "TV" #: src/bz-flathub-category.c:102 msgid "Emulation" msgstr "Emulasi" #: src/bz-flathub-category.c:103 msgid "Action" msgstr "Aksi" #: src/bz-flathub-category.c:104 msgid "Adventure" msgstr "Petualangan" #: src/bz-flathub-category.c:105 msgid "Arcade" msgstr "Arkade" #: src/bz-flathub-category.c:106 msgid "Blocks" msgstr "Blok" #: src/bz-flathub-category.c:107 msgid "Board" msgstr "Papan" #: src/bz-flathub-category.c:108 msgid "Card" msgstr "Kartu" #: src/bz-flathub-category.c:109 msgid "Kids" msgstr "Anak-Anak" #: src/bz-flathub-category.c:110 msgid "Logic" msgstr "Logika" #: src/bz-flathub-category.c:111 msgid "Role Playing" msgstr "Bermain Peran" #: src/bz-flathub-category.c:112 msgid "Shooter" msgstr "Penembak" #: src/bz-flathub-category.c:113 msgid "Simulation" msgstr "Simulasi" #: src/bz-flathub-category.c:114 msgid "Sports" msgstr "Olahraga" #: src/bz-flathub-category.c:115 msgid "Strategy" msgstr "Strategi" #: src/bz-flathub-category.c:120 msgid "Audio & Video" msgstr "Audio & Video" #: src/bz-flathub-category.c:120 msgid "Media" msgstr "Putar Media" #: src/bz-flathub-category.c:120 msgid "More Audio & Video" msgstr "Apl Audio & Video Lain" #: src/bz-flathub-category.c:121 msgid "Developer Tools" msgstr "Alat Pengembangan" #: src/bz-flathub-category.c:121 msgid "Develop" msgstr "Kembangkan" #: src/bz-flathub-category.c:121 msgid "More Developer Tools" msgstr "Apl Pengembangan Lain" #: src/bz-flathub-category.c:122 msgid "Education" msgstr "Edukasi" #: src/bz-flathub-category.c:122 msgid "Learn" msgstr "Belajar" #: src/bz-flathub-category.c:122 msgid "More Education" msgstr "Apl Edukasi Lain" #: src/bz-flathub-category.c:123 msgid "Gaming" msgstr "Permainan" #: src/bz-flathub-category.c:123 msgid "Play" msgstr "Bermain" #: src/bz-flathub-category.c:123 msgid "More Gaming" msgstr "Permainan Lainnya" #: src/bz-flathub-category.c:124 msgid "Graphics & Photography" msgstr "Grafis & Fotografi" #: src/bz-flathub-category.c:124 msgid "Create" msgstr "Berkreasi" #: src/bz-flathub-category.c:124 msgid "More Graphics & Photography" msgstr "Apl Grafis & Foto Lain" #: src/bz-flathub-category.c:125 msgid "Networking" msgstr "Jaringan" #: src/bz-flathub-category.c:125 msgid "Internet" msgstr "Internet" #: src/bz-flathub-category.c:125 msgid "More Networking" msgstr "Apl Jaringan Lain" #: src/bz-flathub-category.c:126 msgid "Productivity" msgstr "Produktivitas" #: src/bz-flathub-category.c:126 msgid "Work" msgstr "Bekerja" #: src/bz-flathub-category.c:126 msgid "More Productivity" msgstr "Apl Produktivitas Lain" #: src/bz-flathub-category.c:127 msgid "Science" msgstr "Ilmu Pengetahuan" #: src/bz-flathub-category.c:127 msgid "More Science" msgstr "Apl Ilmu Pengetahuan Lain" #: src/bz-flathub-category.c:128 msgid "System" msgstr "Sistem" #: src/bz-flathub-category.c:128 msgid "More System" msgstr "Apl Sistem Lain" #: src/bz-flathub-category.c:129 msgid "Utilities" msgstr "Utilitas" #: src/bz-flathub-category.c:129 msgid "Tools" msgstr "Alat" #: src/bz-flathub-category.c:129 msgid "More Utilities" msgstr "Apl Utilitas Lain" #: src/bz-flathub-category.c:130 src/bz-flathub-page.blp:119 #: src/bz-flathub-page.blp:152 msgid "Trending" msgstr "Sedang Tren" #: src/bz-flathub-category.c:130 msgid "More Trending" msgstr "Aplikasi Tren Lainnya" #: src/bz-flathub-category.c:131 src/bz-flathub-page.blp:125 #: src/bz-flathub-page.blp:182 msgid "Popular" msgstr "Populer" #: src/bz-flathub-category.c:131 msgid "More Popular" msgstr "Apl Populer Lainnya" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:172 msgid "Recently Added" msgstr "Baru Saja Rilis" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:131 msgid "New" msgstr "Baru" #: src/bz-flathub-category.c:132 msgid "More New" msgstr "Apl Baru Lainnya" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:162 msgid "Recently Updated" msgstr "Baru Dimutakhirkan" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:137 msgid "Updated" msgstr "Diperbarui" #: src/bz-flathub-category.c:133 msgid "More Updated" msgstr "Apl Mutakhir Lainnya" #: src/bz-flathub-category.c:134 msgid "Mobile" msgstr "Untuk Ponsel" #: src/bz-flathub-category.c:134 msgid "More Mobile" msgstr "Apl Ponsel Lainnya" #: src/bz-flathub-category.c:135 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:135 msgid "More Adwaita" msgstr "Apl Adwaita Lainnya" #: src/bz-flathub-category.c:136 msgid "KDE Apps" msgstr "Aplikasi KDE" #: src/bz-flathub-category.c:136 msgid "More KDE Apps" msgstr "Apl KDE Lainnya" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Flathub Belum Ditambahkan" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "Remote Flathub tidak ditemukan pada seluruh pemasangan Flatpak Anda" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "Terdapat kesalahan pada Flathub" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "Hubungkan Kembali Flathub" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Flathub Tidak Tersedia" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" "Bazaar tidak dapat terhubung ke Flathub. Anda masih dapat mencari dan " "mengelola aplikasi." #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "Cari Aplikasi" #: src/bz-flathub-page.blp:263 msgid "On the Go" msgstr "Di Mana Saja" #: src/bz-flathub-page.blp:275 msgid "Apps for your Linux phones and tablets" msgstr "Aplikasi untuk ponsel dan tablet Linux Anda" #: src/bz-flathub-page.blp:286 src/bz-flathub-page.blp:321 msgid "More Mobile Apps" msgstr "Apl Ponsel Lainnya" #: src/bz-flathub-page.blp:379 msgid "We​ ♥​ Games" msgstr "Kita ♥​ Main" #: src/bz-flathub-page.blp:392 msgid "Games and apps to run your favorite titles" msgstr "Permainan dan aplikasi untuk memainkan judul-judul favoritmu" #: src/bz-flathub-page.blp:426 msgid "More Games" msgstr "Permainan Lainnya" #: src/bz-full-view.blp:66 src/bz-library-page.blp:76 #: src/bz-library-page.blp:80 msgid "No Results" msgstr "Tidak Ada Hasil" #: src/bz-full-view.blp:67 msgid "Try a different search query" msgstr "Coba gunakan kata kunci lainnya" #: src/bz-full-view.blp:73 msgid "Content" msgstr "Konten" #: src/bz-full-view.blp:131 msgid "Installing .flatpak bundles is not yet supported" msgstr "Saat ini pemasangan bundel .flatpak belum didukung" #: src/bz-full-view.blp:257 msgid "_Support" msgstr "_Dukung" #: src/bz-full-view.blp:426 msgid "Downloads/Month" msgstr "Unduhan/Bulan" #: src/bz-full-view.blp:461 msgid "Stopped Receiving Core Updates" msgstr "Berhenti Menerima Pembaruan Utama" #: src/bz-full-view.blp:475 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "Aplikasi ini menggunakan tempokerja (runtime) yang sudah tidak menerima " "pembaruan maupun perbaikan keamanan. Aplikasi ini mungkin tidak aman saat " "digunakan." #: src/bz-full-view.blp:562 msgid "Trash Data" msgstr "Buang Data" #: src/bz-full-view.blp:702 msgid "Tags:" msgstr "Label:" #: src/bz-full-view.c:215 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:222 #, c-format msgid "%.*fM" msgstr "%.*fjt" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:229 #, c-format msgid "%.*fK" msgstr "%.*frb" #: src/bz-full-view.c:239 #, c-format msgid "%d downloads in the last month" msgstr "%d unduhan dalam sebulan terakhir" #: src/bz-full-view.c:251 src/bz-full-view.c:592 src/bz-full-view.c:609 msgid "N/A" msgstr "Nihil" #: src/bz-full-view.c:279 #, c-format msgid "+%s runtime" msgstr "+%s Tempokerja (Runtime)" #: src/bz-full-view.c:282 msgid "Download" msgstr "Ukuran Unduh" #: src/bz-full-view.c:302 msgid "Size information unavailable" msgstr "Info ukuran apl tidak tersedia" #: src/bz-full-view.c:305 #, c-format msgid "Download size of %s" msgstr "Ukuran unduhan %s" #: src/bz-full-view.c:338 msgid "All Ages" msgstr "Semua Usia" #: src/bz-full-view.c:350 msgid "Age rating information unavailable" msgstr "Info panduan usia tidak tersedia" #: src/bz-full-view.c:355 msgid "Suitable for all ages" msgstr "Cocok untuk semua usia" #: src/bz-full-view.c:357 #, c-format msgid "Suitable for ages %d and up" msgstr "Cocok untuk usia %d ke atas" #: src/bz-full-view.c:390 src/bz-full-view.c:395 src/bz-full-view.c:423 #: src/bz-full-view.c:431 msgid "Unknown" msgstr "Tidak Diketahui" #: src/bz-full-view.c:400 #, c-format msgid "Free software licensed under %s" msgstr "Aplikasi bebas di bawah lisensi %s" #: src/bz-full-view.c:405 msgid "Free software" msgstr "Aplikasi bebas" #: src/bz-full-view.c:408 msgid "Proprietary Software" msgstr "Aplikasi dengan hak cipta khusus" #: src/bz-full-view.c:411 #, c-format msgid "Special License: %s" msgstr "Lisensi Khusus: %s" #: src/bz-full-view.c:428 msgid "Free" msgstr "Bebas" #: src/bz-full-view.c:434 src/bz-license-dialog.c:132 msgid "Proprietary" msgstr "Proprietari" #: src/bz-full-view.c:436 src/bz-license-dialog.c:134 msgid "Special License" msgstr "Lisensi Khusus" #: src/bz-full-view.c:456 msgid "Adaptive" msgstr "Adaptif" #: src/bz-full-view.c:456 msgid "Desktop Only" msgstr "Hanya Desktop" #: src/bz-full-view.c:462 msgid "Works on desktop, tablets, and phones" msgstr "Bekerja di desktop, tablet dan ponsel" #: src/bz-full-view.c:463 msgid "May not work on mobile devices" msgstr "Mungkin tidak bekerja optimal di ponsel" #: src/bz-full-view.c:474 msgid "No URL" msgstr "Tidak ada URL" #: src/bz-full-view.c:492 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Aplikasi ini memiliki lisensi FLOSS, sehingga kode sumbernya dapat diaudit " "secara bebas dan terbuka." #: src/bz-full-view.c:493 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Aplikasi ini memiliki lisensi proprietari, dikembangkan secara tertutup " "dengan kode sumber aplikasi yang tidak bisa diaudit secara independen." #: src/bz-full-view.c:500 msgid "More Apps" msgstr "Aplikasi Lainnya" #: src/bz-full-view.c:501 #, c-format msgid "More Apps by %s" msgstr "Aplikasi Lain dari %s" #: src/bz-full-view.c:508 msgid "Other Apps by this Developer" msgstr "Jelajah lebih dari pengembang ini" #: src/bz-full-view.c:510 src/bz-full-view.c:693 #, c-format msgid "Other Apps by %s" msgstr "Jelajah lebih dari %s" #: src/bz-full-view.c:519 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "" "%s sudah tidak terpasang, namun masih memiliki %s data tersimpan." #: src/bz-full-view.c:599 src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "Aman" #: src/bz-full-view.c:601 src/bz-full-view.c:603 msgid "Low Risk" msgstr "Risiko Rendah" #: src/bz-full-view.c:605 msgid "Medium Risk" msgstr "Risiko Sedang" #: src/bz-full-view.c:607 msgid "High Risk" msgstr "Risiko Tinggi" #: src/bz-full-view.c:695 msgid "Other Apps" msgstr "Aplikasi Lain" #: src/bz-full-view.c:697 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d Aplikasi" #: src/bz-full-view.c:941 msgid "Show Less" msgstr "Sembunyikan" #: src/bz-full-view.c:941 msgid "Show More" msgstr "Tampilkan Lebih Banyak" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 msgid "Hardware Support" msgstr "Dukungan Perangkat" #: src/bz-hardware-support-dialog.c:62 msgid "Keyboard support" msgstr "Pintasan papan tik" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "Membutuhkan papan tik" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "Direkomendasikan menggunakan papan tik" #: src/bz-hardware-support-dialog.c:66 msgid "Supports keyboards" msgstr "Mendukung papan tik" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "Dukungan papan tik tidak diketahui" #: src/bz-hardware-support-dialog.c:69 msgid "Mouse support" msgstr "Dukungan tetikus" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "Membutuhkan tetikus atau alat penunjuk" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "Direkomendasikan menggunakan tetikus atau alat penunjuk" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "Mendukung tetikus atau alat penunjuk" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "Dukungan untuk tetikus atau alat penunjuk tidak diketahui" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "Dukungan layar sentuh" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "Membutuhkan layar sentuh" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "Direkomedasikan menggunakan layar sentuh" #: src/bz-hardware-support-dialog.c:80 msgid "Supports touchscreens" msgstr "Mendukung layar sentuh" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "Dukungan untuk layar sentuh tidak diketahui" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "Dukungan ponsel" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "Bekerja di ponsel" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "Mungkin tidak bekerja optimal di ponsel" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "Dukungan desktop" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "Bekerja optimal di layar lebar" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "%s bekerja optimal pada perangkat tertentu" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "%s bekerja baik pada sebagian besar perangkat" #: src/bz-install-controls.blp:33 msgid "Download & Install Application" msgstr "Unduh & Pasang Aplikasi" #: src/bz-install-controls.blp:35 src/bz-transaction-dialog.c:202 msgid "_Install" msgstr "_Pasang" #: src/bz-install-controls.blp:61 msgid "_Open" msgstr "_Buka" #: src/bz-install-controls.blp:76 src/bz-install-controls.blp:127 msgid "Uninstall Application" msgstr "Hapus Pemasangan Aplikasi" #: src/bz-install-controls.blp:86 src/bz-transaction-dialog.c:231 msgid "_Remove" msgstr "_Hapus" #: src/bz-install-controls.blp:114 src/bz-updates-card.blp:184 #: src/bz-updates-card.blp:212 msgid "Update" msgstr "Perbarui" #: src/bz-installed-tile.blp:64 src/bz-rich-app-tile.blp:140 msgid "Stopped Receiving Updates" msgstr "Berhenti Menerima Pembaruan" #: src/bz-library-page.blp:31 msgid "Search installed apps" msgstr "Cari aplikasi terpasang" #: src/bz-library-page.blp:48 msgid "Clear search" msgstr "Bersihkan pencarian" #: src/bz-library-page.blp:69 msgid "No Apps Found" msgstr "Tidak Ada Aplikasi Tersedia" #. Translators: . #: src/bz-library-page.blp:98 src/bz-window.blp:112 msgid "Library" msgstr "Pustaka" #: src/bz-library-page.blp:126 msgid "Pending Updates" msgstr "Pembaruan Tertunda" #: src/bz-library-page.blp:153 msgid "Downloads" msgstr "Unduhan" #: src/bz-library-page.blp:196 msgid "Recently Uninstalled" msgstr "Baru Dihapus" #: src/bz-library-page.blp:247 msgid "Clear Finished Tasks" msgstr "Bersihkan Transaksi Lama" #: src/bz-library-page.blp:260 msgid "Installed Apps" msgstr "Aplikasi Terpasang" #: src/bz-library-page.blp:333 msgid "Sort By" msgstr "Urutkan" #: src/bz-library-page.blp:347 msgid "Name" msgstr "Nama" #: src/bz-library-page.blp:353 msgid "Size" msgstr "Ukuran" #: src/bz-library-page.c:180 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "Tidak ada hasil yang cocok untuk \"%s\" dari aplikasi terpasang" #: src/bz-library-page.c:193 src/bz-updates-card.c:257 #, c-format msgid "%u Available Update" msgid_plural "%u Available Updates" msgstr[0] "%u Pembaruan Tersedia" #: src/bz-license-dialog.blp:95 msgid "Get Involved" msgstr "Mari Berpartisipasi" #: src/bz-license-dialog.c:126 msgid "Unknown License" msgstr "Lisensi Tidak Diketahui" #: src/bz-license-dialog.c:129 msgid "Community Built" msgstr "Dibangun Bersama" #: src/bz-license-dialog.c:202 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Aplikasi ini dikembangkan secara terbuka oleh komunitas dari seluruh dunia.\n" "\n" "Anda dapat berpartisipasi dan ikut membuatnya lebih baik." #: src/bz-license-dialog.c:205 msgid "The license of this app is not known" msgstr "Lisensi aplikasi ini tidak diketahui" #: src/bz-license-dialog.c:211 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Aplikasi ini dikembangkan secara terbuka oleh komunitas dari seluruh dunia, " "dan dirilis di bawah lisensi %s.\n" "\n" "Anda dapat berpartisipasi membuat aplikasi ini lebih baik." #: src/bz-license-dialog.c:219 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Aplikasi ini tidak dikembangkan secara terbuka, sehingga hanya pihak " "pengembang yang memahami penuh cara kerjanya. Pengawasan keamanan aplikasi " "ini mungkin lebih sulit, dan statusnya dapat berubah sewaktu-waktu.\n" "\n" "Anda mungkin tidak dapat berkontribusi pada aplikasi ini." #: src/bz-license-dialog.c:225 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Aplikasi ini dikembangkan di bawah lisensi khusus %s.\n" "\n" "Anda mungkin dapat atau tidak dapat berkontribusi pada aplikasi ini." #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 msgid "Connect to Flathub" msgstr "Hubungkan ke Flathub" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "Terjadi Kesalahan" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "" "Hubungkan akun Flatpak ke Bazaar untuk mengelola aplikasi favorit Anda." #: src/bz-login-page.blp:110 msgid "Finish" msgstr "Selesai" #: src/bz-login-page.c:664 #, c-format msgid "Hello, %s!" msgstr "Halo, %s!" #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Preferensi" #: src/bz-preferences-dialog.blp:25 msgid "Network connection is metered — automatic store data refresh is paused" msgstr "Koneksi jaringan dibatasi — sinkronisasi data otomatis saat ini dijeda" #: src/bz-preferences-dialog.blp:26 src/bz-window.blp:282 msgid "Refresh Manually" msgstr "Segarkan Langsung" #: src/bz-preferences-dialog.blp:31 msgid "Content Filters" msgstr "Saringan Konten" #: src/bz-preferences-dialog.blp:34 msgid "Free Software Only" msgstr "Sembunyikan Aplikasi Sumber Tertutup" #: src/bz-preferences-dialog.blp:35 msgid "Hide proprietary applications when browsing and searching" msgstr "Hanya tampilkan aplikasi bersumber terbuka pada hasil cari/jelajah" #: src/bz-preferences-dialog.blp:39 msgid "Flathub Results Only" msgstr "Hanya Tampilkan Aplikasi Flathub" #: src/bz-preferences-dialog.blp:40 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "Batasi hasil cari/jelajah hanya pada aplikasi yang tersedia di Flathub" #: src/bz-preferences-dialog.blp:44 msgid "Verified Results Only" msgstr "Hanya Tampilkan Apl Terverifikasi" #: src/bz-preferences-dialog.blp:45 msgid "Hide results that are not verified on Flathub" msgstr "Sembunyikan aplikasi tanpa verifikasi Flathub" #: src/bz-preferences-dialog.blp:49 msgid "Hide EOL Apps" msgstr "Sembunyikan Aplikasi Tanpa Dukungan" #: src/bz-preferences-dialog.blp:50 msgid "Hide apps which are no longer supported by their developers" msgstr "Sembunyikan aplikasi yang sudah tidak didukung oleh para pengembangnya" #: src/bz-preferences-dialog.blp:55 src/bz-window.blp:127 msgid "Search" msgstr "Cari" #: src/bz-preferences-dialog.blp:58 msgid "Delay Search Results" msgstr "Tunda Hasil Pencarian" #: src/bz-preferences-dialog.blp:59 msgid "Improve results performance by debouncing search terms" msgstr "" "Tingkatkan performa pencarian dengan menunda pemuatan istilah pencarian" #: src/bz-preferences-dialog.blp:64 msgid "Progress Bar" msgstr "Bilah Kemajuan" #: src/bz-preferences-dialog.blp:65 msgid "Choose a theme for the progress bar!" msgstr "Pilihlah tema favorit Anda!" #: src/bz-preferences-dialog.blp:89 msgid "Vertical Stripes" msgstr "Strip Vertikal" #: src/bz-preferences-dialog.blp:90 msgid "Display flag colors from left to right" msgstr "Tampilkan warna bendera dari kiri ke kanan" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Warna Aksen" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Warna Kebanggaan" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "Warna Bangga Lesbian" #: src/bz-preferences-dialog.c:35 msgid "Male Homosexual Pride Colors" msgstr "Warna Bangga Homoseksual Pria" #: src/bz-preferences-dialog.c:36 msgid "Transgender Pride Colors" msgstr "Warna Bangga Transgender" #: src/bz-preferences-dialog.c:37 msgid "Nonbinary Pride Colors" msgstr "Warna Bangga Nonbiner" #: src/bz-preferences-dialog.c:38 msgid "Bisexual Pride Colors" msgstr "Warna Bangga Biseksual" #: src/bz-preferences-dialog.c:39 msgid "Asexual Pride Colors" msgstr "Warna Bangga Aseksual" #: src/bz-preferences-dialog.c:40 msgid "Pansexual Pride Colors" msgstr "Warna Bangga Panseksual" #: src/bz-preferences-dialog.c:41 msgid "Aromantic Pride Colors" msgstr "Warna Bangga Aromantik" #: src/bz-preferences-dialog.c:42 msgid "Genderfluid Pride Colors" msgstr "Warna Bangga Fluiditas Gender " #: src/bz-preferences-dialog.c:43 msgid "Polysexual Pride Colors" msgstr "Warna Bangga Poliseksual" #: src/bz-preferences-dialog.c:44 msgid "Omnisexual Pride Colors" msgstr "Warna Bangga Omniseksual" #: src/bz-preferences-dialog.c:45 msgid "Aroace Pride Colors" msgstr "Warna Bangga Aromantik-Aseksual" #: src/bz-preferences-dialog.c:46 msgid "Agender Pride Colors" msgstr "Warna Bangga Agender" #: src/bz-preferences-dialog.c:47 msgid "Genderqueer Pride Colors" msgstr "Warna Bangga Genderqueer" #: src/bz-preferences-dialog.c:48 msgid "Intersex Pride Colors" msgstr "Warna Bangga Interseks" #: src/bz-preferences-dialog.c:49 msgid "Demigender Pride Colors" msgstr "Warna Bangga Demigender" #: src/bz-preferences-dialog.c:50 msgid "Biromantic Pride Colors" msgstr "Warna Bangga Biromantik" #: src/bz-preferences-dialog.c:51 msgid "Disability Pride Colors" msgstr "Warna Bangga Disabilitas" #: src/bz-preferences-dialog.c:52 msgid "Femboy Pride Colors" msgstr "Warna Bangga Waria" #: src/bz-preferences-dialog.c:53 msgid "Neutrois Pride Colors" msgstr "Warna Bangga Netrois" #: src/bz-releases-dialog.blp:5 src/bz-updates-card.blp:171 msgid "Version History" msgstr "Riwayat Versi" #: src/bz-releases-list.blp:27 msgid "_Version History" msgstr "_Riwayat Versi" #. Translators: something happened less than a day ago #: src/bz-releases-list.c:122 msgid "Today" msgstr "Hari Ini" #. Translators: something happened more than a day ago but less than 2 days ago #: src/bz-releases-list.c:125 msgid "Yesterday" msgstr "Kemarin" #. Translators: something happened days ago #: src/bz-releases-list.c:128 #, c-format msgid "%d day ago" msgid_plural "%d days ago" msgstr[0] "%d hari lalu" #. Translators: something happened weeks ago #: src/bz-releases-list.c:131 #, c-format msgid "%d week ago" msgid_plural "%d weeks ago" msgstr[0] "%d minggu lalu" #. Translators: something happened months ago #: src/bz-releases-list.c:134 #, c-format msgid "%d month ago" msgid_plural "%d months ago" msgstr[0] "%d bulan lalu" #. Translators: something happened years ago #: src/bz-releases-list.c:137 #, c-format msgid "%d year ago" msgid_plural "%d years ago" msgstr[0] "%d tahun lalu" #. TRANSLATORS: This is the date string with: day number, month name, year. #. i.e. "22 March 2026" #: src/bz-releases-list.c:155 msgid "%e %B %Y" msgstr "%e %B %Y" #: src/bz-releases-list.c:195 #, c-format msgid "Version %s" msgstr "Versi %s" #: src/bz-releases-list.c:250 msgid "No details for this release" msgstr "Tidak ada detail untuk rilisan ini" #: src/bz-releases-list.c:262 msgid "Get More Information" msgstr "Info Lebih Lanjut" #: src/bz-rich-app-tile.blp:157 msgid "Get" msgstr "Pasang" #: src/bz-rich-app-tile.blp:185 src/bz-transaction-tile.blp:272 msgid "Open" msgstr "Buka" #: src/bz-safety-calculator.c:82 msgid "Unknown Permissions" msgstr "Izin Tidak Jelas" #: src/bz-safety-calculator.c:83 msgid "Permissions are missing for this app." msgstr "Izin aplikasi ini tidak diketahui" #: src/bz-safety-calculator.c:96 msgid "No Permissions" msgstr "Tidak Ada Izin" #: src/bz-safety-calculator.c:97 msgid "App is fully sandboxed" msgstr "Aplikasi ini sepenuhnya terisolasi" #: src/bz-safety-calculator.c:103 msgid "Network Access" msgstr "Akses Jaringan" #: src/bz-safety-calculator.c:104 msgid "Can access the internet" msgstr "Dapat mengakses internet" #: src/bz-safety-calculator.c:106 msgid "No Network Access" msgstr "Tidak Ada Akses Jaringan" #: src/bz-safety-calculator.c:107 msgid "Cannot access the internet" msgstr "Tidak dapat mengakses internet" #: src/bz-safety-calculator.c:112 msgid "User Device Access" msgstr "Akses Perangkat Pengguna" #: src/bz-safety-calculator.c:113 msgid "Can access devices such as webcams or gaming controllers" msgstr "Dapat mengakses perangkat seperti kamera atau pengontrol mainan" #: src/bz-safety-calculator.c:115 msgid "No User Device Access" msgstr "Tidak Ada Akses Perangkat Pengguna" #: src/bz-safety-calculator.c:116 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "Tidak dapat mengakses perangkat seperti kamera atau pengontrol mainan" #: src/bz-safety-calculator.c:121 msgid "Input Device Access" msgstr "Akses Perangkat Masukan" #: src/bz-safety-calculator.c:122 msgid "Can access input devices" msgstr "Dapat mengakses perangkat masukan" #: src/bz-safety-calculator.c:128 msgid "Microphone Access and Audio Playback" msgstr "Akses Mikrofon dan Pemutaran Suara" #: src/bz-safety-calculator.c:129 msgid "Can listen using microphones and play audio without asking permission" msgstr "Dapat mengakses mikrofon dan memutar suara tanpa permintaan izin" #: src/bz-safety-calculator.c:135 msgid "System Device Access" msgstr "Akses Perangkat Sistem" #: src/bz-safety-calculator.c:136 msgid "Can access system devices which require elevated permissions" msgstr "Dapat mengakses perangkat sistem yang membutuhkan izin lebih lanjut" #: src/bz-safety-calculator.c:142 msgid "Screen Contents Access" msgstr "Akses Konten Layar" #: src/bz-safety-calculator.c:143 msgid "Can access the contents of the screen or other windows" msgstr "Dapat mengakses konten dari layar, termasuk jendela aplikasi lain" #: src/bz-safety-calculator.c:149 msgid "Legacy Windowing System" msgstr "Sistem Jendela Lawas" #: src/bz-safety-calculator.c:150 msgid "Always uses a legacy windowing system (X11)" msgstr "Selalu menggunakan sistem jendela lawas X11" #: src/bz-safety-calculator.c:156 msgid "Arbitrary Permissions" msgstr "Izin Sewenang-wenang" #: src/bz-safety-calculator.c:157 msgid "Can acquire arbitrary permissions" msgstr "Dapat memperoleh izin sewenang-wenang" #: src/bz-safety-calculator.c:163 msgid "User Settings" msgstr "Akses Konfigurasi Pengguna" #: src/bz-safety-calculator.c:164 msgid "Can access and change user settings" msgstr "Dapat mengakses dan mengubah konfigurasi pengguna" #: src/bz-safety-calculator.c:170 msgid "Full File System Read/Write Access" msgstr "Akses Baca/Tulis Penuh pada Sistem Berkas" #: src/bz-safety-calculator.c:171 msgid "Can read and write all data on the file system" msgstr "" "Memiliki akses baca dan tulis untuk semua data pada sistem perangkat ini" #: src/bz-safety-calculator.c:178 msgid "Home Folder Read/Write Access" msgstr "Akses Baca/Tulis Direktori Rumah" #: src/bz-safety-calculator.c:179 msgid "Can read and write all data in your home directory" msgstr "" "Memiliki akses baca dan tulis untuk semua data pada direktori Rumah " "perangkat ini" #: src/bz-safety-calculator.c:186 msgid "Full File System Read Access" msgstr "Akses Baca Penuh dalam Sistem Berkas" #: src/bz-safety-calculator.c:187 msgid "Can read all data on the file system" msgstr "Memiliki akses baca untuk semua data pada sistem perangkat ini" #: src/bz-safety-calculator.c:195 msgid "Home Folder Read Access" msgstr "Akses Baca Direktori Rumah" #: src/bz-safety-calculator.c:196 msgid "Can read all data in your home directory" msgstr "" "Memiliki akses baca untuk semua data pada direktori Rumah perangkat ini" #: src/bz-safety-calculator.c:204 msgid "Download Folder Read/Write Access" msgstr "Akses Baca/Tulis Folder Unduhan" #: src/bz-safety-calculator.c:205 msgid "Can read and write all data in your downloads directory" msgstr "" "Memiliki akses baca dan tulis untuk semua data pada direktori Unduhan " "perangkat ini" #: src/bz-safety-calculator.c:215 msgid "Download Folder Read Access" msgstr "Akses Baca Folder Unduhan" #: src/bz-safety-calculator.c:216 msgid "Can read all data in your downloads directory" msgstr "Memiliki akses baca untuk semua data di direktori Unduhan Anda" #: src/bz-safety-calculator.c:229 msgid "Can read and write all data in the directory" msgstr "Memiliki akses baca dan tulis untuk semua data pada direktori ini" #: src/bz-safety-calculator.c:243 msgid "Can read all data in the directory" msgstr "Memiliki akses baca untuk semua data pada direktori ini" #: src/bz-safety-calculator.c:258 msgid "No File System Access" msgstr "Tidak Ada Akses Sistem Berkas" #: src/bz-safety-calculator.c:259 msgid "Cannot access the file system at all" msgstr "Tidak dapat mengakses sistem berkas sama sekali" #: src/bz-safety-calculator.c:266 msgid "Uses System Services" msgstr "Menggunakan Layanan Sistem" #: src/bz-safety-calculator.c:267 msgid "Can request data from non-portal system services" msgstr "Dapat meminta data dari layanan sistem di luar portal XDG" #: src/bz-safety-calculator.c:273 msgid "Uses Session Services" msgstr "Menggunakan Layanan Sesi" #: src/bz-safety-calculator.c:274 msgid "Can request data from non-portal session services" msgstr "Dapat meminta data dari layanan sesi di luar portal XDG" #: src/bz-safety-calculator.c:322 msgid "No Service Access" msgstr "Tidak Ada Akses Layanan" #: src/bz-safety-calculator.c:323 msgid "Cannot access non-portal session or system services at all" msgstr "Tidak dapat mengakses layanan sistem atau sesi non-portal sama sekali" #: src/bz-safety-calculator.c:331 msgid "Verified App Developer" msgstr "Pengembang Terverifikasi" #: src/bz-safety-calculator.c:332 msgid "The developer of this app has been verified to be who they say they are" msgstr "Pengembang aplikasi ini sudah terverifikasi oleh Flathub" #: src/bz-safety-calculator.c:341 msgid "Proprietary Code" msgstr "Kode Proprietari" #: src/bz-safety-calculator.c:342 msgid "" "The source code is not public, so it cannot be independently audited and " "might be unsafe" msgstr "" "Kode sumber aplikasi ini tidak bersifat publik, sehingga aplikasi ini tidak " "dapat diaudit secara independen dan mungkin tidak aman" #: src/bz-safety-calculator.c:352 msgid "Auditable Code" msgstr "Kode Dapat Diaudit" #: src/bz-safety-calculator.c:353 msgid "" "The source code is public and can be independently audited, which makes the " "app more likely to be safe" msgstr "" "Kode sumber aplikasi ini bersifat publik dan dapat diaudit secara " "independen, sehingga kemungkinan besar aplikasi ini aman" #: src/bz-safety-calculator.c:493 #, c-format msgid "Use the %s System Service" msgstr "Menggunakan Layanan Sistem %s" #: src/bz-safety-calculator.c:497 #, c-format msgid "Use the %s Session Service" msgstr "Menggunakan Layanan Sesi %s" #: src/bz-safety-calculator.c:501 #, c-format msgid "Use the %s Service" msgstr "Menggunakan Layanan %s" #: src/bz-safety-calculator.c:511 msgid "Can see the non-portal service" msgstr "Dapat melihat layanan di luar portal XDG" #: src/bz-safety-calculator.c:513 msgid "Can talk to the non-portal service" msgstr "Dapat berkomunikasi dengan layanan di luar portal XDG" #: src/bz-safety-calculator.c:515 msgid "Can own the non-portal service" msgstr "Dapat memiliki layanan di luar portal XDG" #: src/bz-safety-calculator.c:530 msgid "Global Menu Integration" msgstr "Integrasi Menu Global" #: src/bz-safety-calculator.c:531 msgid "Can display its menus in a global menu bar" msgstr "Dapat menampilkan opsi aplikasi pada bilah menu global" #: src/bz-safety-calculator.c:536 msgid "KDE Settings Integration" msgstr "Integrasi Pengaturan KDE" #: src/bz-safety-calculator.c:537 msgid "Can detect when KDE desktop settings change" msgstr "Dapat mendeteksi ketika terdapat perubahan konfigurasi desktop KDE" #: src/bz-safety-calculator.c:542 msgid "KDE Global Settings" msgstr "Pengaturan Global KDE" #: src/bz-safety-calculator.c:543 msgid "Can read KDE desktop preferences like fonts and colors" msgstr "Dapat membaca preferensi desktop KDE, seperti font dan tema warna" #: src/bz-safety-calculator.c:548 msgid "Secret Storage Service" msgstr "Layanan Penyimpanan Sandi" #: src/bz-safety-calculator.c:549 msgid "Can store and retrieve its own passwords using the system keyring" msgstr "" "Dapat menyimpan dan mengambil kata sandi menggunakan penyimpanan kunci sistem" #: src/bz-safety-calculator.c:554 msgid "Desktop Notifications Service" msgstr "Layanan Notifikasi Desktop" #: src/bz-safety-calculator.c:555 msgid "Can send desktop notifications" msgstr "Dapat mengirim notifikasi desktop" #: src/bz-safety-calculator.c:561 msgid "System Tray Integration" msgstr "Integrasi Baki Sistem" #: src/bz-safety-calculator.c:562 msgid "Can display an icon in the system tray" msgstr "Dapat menampilkan ikon pada baki sistem" #: src/bz-safety-calculator.c:567 msgid "KDE Connect Integration" msgstr "Integrasi KDE Connect" #: src/bz-safety-calculator.c:568 msgid "Can interact with devices paired via KDE Connect" msgstr "" "Dapat berinteraksi dengan perangkat yang terkoneksi melalui KDE Connect" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "Keamanan" #: src/bz-safety-dialog.blp:53 msgid "License" msgstr "Lisensi" #: src/bz-safety-dialog.blp:63 msgid "App ID" msgstr "ID Aplikasi" #: src/bz-safety-dialog.blp:73 msgid "SDK" msgstr "SDK" #: src/bz-safety-dialog.blp:104 msgid "" "This app uses an outdated version of the software platform (SDK) and might " "contain bugs or security vulnerabilities which will not be fixed." msgstr "" "Aplikasi ini menggunakan versi platform aplikasi (SDK) usang dan mungkin " "memiliki gangguan atau kerentanan keamanan yang tak diperbaiki." #: src/bz-safety-dialog.c:227 #, c-format msgid "%s is Safe" msgstr "%s aman untuk dipasang" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s has no Unsafe Permissions" msgstr "%s tidak memiliki izin berbahaya" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Probably Safe" msgstr "%s mungkin aman untuk dipasang" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Possibly Unsafe" msgstr "%s mungkin tidak aman untuk dipasang" #: src/bz-safety-dialog.c:247 #, c-format msgid "%s is Unsafe" msgstr "%s tidak aman untuk dipasang" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "Tangkapan Layar" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "Tangkapan Layar Sebelumnya" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "Tangkapan Layar Selanjutnya" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "Salin Gambar" #: src/bz-screenshot-page.blp:147 msgid "Reset View" msgstr "Kembalikan Skala Tampilan" #: src/bz-screenshot-page.blp:158 msgid "Zoom Out" msgstr "Perkecil Tampilan" #: src/bz-screenshot-page.blp:168 msgid "Zoom In" msgstr "Perbesar Tampilan" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "Karosel Tangkapan Layar" #: src/bz-screenshots-carousel.blp:117 msgid "Open Screenshot Viewer" msgstr "Tampilkan Tangkapan Layar" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:72 msgid "Video" msgstr "Video" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:82 msgid "Office" msgstr "Perkantoran" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:87 msgid "PDF" msgstr "PDF" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:92 msgid "Calendar" msgstr "Kalender" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:97 msgid "Messaging" msgstr "Komunikasi" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:102 msgid "Steam" msgstr "Steam" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:107 msgid "Paint" msgstr "Seni Lukis" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:112 msgid "VPN" msgstr "VPN" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:117 msgid "Torrent" msgstr "Torrent" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:122 msgid "Minecraft" msgstr "Minecraft" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:127 msgid "Emulator" msgstr "Emulator" #: src/bz-search-page.blp:57 msgid "Search Apps, Games, Software" msgstr "Cari Aplikasi dan Permainan" #: src/bz-search-page.blp:79 msgid "Clear Search" msgstr "Bersihkan Pencarian" #: src/bz-search-page.blp:171 msgid "Categories Unavailable" msgstr "Kategori Tidak Tersedia" #: src/bz-search-page.blp:172 msgid "Search for apps using the search bar above." msgstr "Cari aplikasi menggunakan bilah pencarian di atas. " #: src/bz-search-page.blp:198 msgid "Browse Categories" msgstr "Jelajahi Kategori" #: src/bz-search-page.blp:340 msgid "No Applications Found" msgstr "Tidak Ada Aplikasi Tersedia" #: src/bz-search-page.c:244 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "Tidak ada hasil untuk \"%s\" di Flathub" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "Salin Tautan" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Buka Tautan" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "Linimasa" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "Jumlah Pemasangan:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "Dunia" #: src/bz-stats-dialog.blp:69 msgid "Since 4/15/2024" msgstr "Sejak 15/4/2024" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:124 #, c-format msgid "%.2fM Total Installs" msgstr "%.2fM Pemasangan Total" #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:127 #, c-format msgid "%.2fK Total Installs" msgstr "%.2frb Pemasangan Total" #: src/bz-stats-dialog.c:129 #, c-format msgid "%'d Total Installs" msgstr "%'d Pemasangan Total" #: src/bz-tag-list.c:78 msgid "No Results Found" msgstr "Tidak Ada Hasil" #: src/bz-tag-list.c:90 #, c-format msgid "Apps Tagged \"%s\"" msgstr "Aplikasi Berlabel \"%s\"" #: src/bz-tag-list.c:103 msgid "Search failed" msgstr "Pencarian gagal" #: src/bz-transaction-dialog.c:155 msgid "Keep User Data" msgstr "Simpan Data Pengguna" #: src/bz-transaction-dialog.c:156 msgid "Allow restoring personal settings & content" msgstr "Izinkan pemulihan data & pengaturan personal" #: src/bz-transaction-dialog.c:165 msgid "Delete All Data" msgstr "Hapus Semua Data" #: src/bz-transaction-dialog.c:166 msgid "Permanently erase user data to save space" msgstr "Hapus permanen data aplikasi untuk menghemat ruang" #: src/bz-transaction-dialog.c:191 #, c-format msgid "Install %s?" msgstr "Pasang %s?" #: src/bz-transaction-dialog.c:196 msgid "" "Select which version to install. May install additional shared components" msgstr "" "Pilih versi pemasangan. Mungkin membutuhkan pemasangan komponen tambahan" #: src/bz-transaction-dialog.c:198 msgid "May install additional shared components" msgstr "Mungkin membutuhkan pemasangan komponen tambahan" #: src/bz-transaction-dialog.c:201 src/bz-transaction-dialog.c:230 #: src/bz-transaction-dialog.c:275 src/bz-transaction-dialog.c:578 msgid "_Cancel" msgstr "_Batal" #: src/bz-transaction-dialog.c:219 #, c-format msgid "Remove %s?" msgstr "Hapus %s?" #: src/bz-transaction-dialog.c:222 msgid "Select which version to remove." msgstr "Pilih versi aplikasi yang akan dihapus." #: src/bz-transaction-dialog.c:224 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "Setelah dihapus, aplikasi %s tidak akan bisa digunakan." #: src/bz-transaction-dialog.c:247 #, c-format msgid "“%s” is High Risk" msgstr "\"%s\" memiliki risiko tinggi" #: src/bz-transaction-dialog.c:251 msgid "" "This app has full access to your system, including all your files, " "browser history, saved passwords, and more. It also has access to the " "internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Aplikasi ini memiliki akses penuh pada sistem Anda, termasuk semua file, " "riwayat peramban, kata sandi tersimpan, dan data lainnya. Aplikasi ini " "juga memiliki akses internet, yang memungkinkannya mengirim data Anda ke " "pihak luar. \n" "\n" "Karena kode sumbernya tidak terbuka, aplikasi ini tidak dapat diaudit " "terkait penggunaan izin-izin tersebut." #: src/bz-transaction-dialog.c:260 msgid "" "This app uses the legacy X11 windowing system, which allows it to record " "all keystrokes, capture screenshots, and monitor other applications. It " "also has access to the internet, meaning it could send your data to outside " "parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Aplikasi ini menggunakan sistem jendela lawas X11, yang memungkinkannya " "merekam semua penekanan tombol, mengambil tangkapan layar, dan memantau " "aplikasi lain. Aplikasi ini juga memiliki akses internet, yang " "memungkinkannya mengirim data Anda ke pihak luar.\n" "\n" "Karena kode sumbernya tidak terbuka, aplikasi ini tidak dapat diaudit " "terkait penggunaan izin-izin tersebut." #: src/bz-transaction-dialog.c:276 msgid "_Install Anyway" msgstr "_Tetap Pasang" #: src/bz-transaction-dialog.c:331 msgid "Failed to load transaction dialog" msgstr "Gagal memuat dialog" #: src/bz-transaction-dialog.c:549 msgid "All apps are already installed" msgstr "Semua aplikasi sudah terpasang." #: src/bz-transaction-dialog.c:551 msgid "_OK" msgstr "_Ya" # %u is the number of apps to install, so the strings might have singular and plural versions depend on your language. #: src/bz-transaction-dialog.c:567 #, c-format msgid "Install %u App?" msgid_plural "Install %u Apps?" msgstr[0] "Pasang %u Aplikasi?" #: src/bz-transaction-dialog.c:575 msgid "" "The following will be installed. Additional shared components may also be " "installed" msgstr "" "Aplikasi berikut akan dipasang, termasuk komponen tambahan jika tersedia" #: src/bz-transaction-dialog.c:576 #, c-format msgid "%d addons will be installed." msgstr "%d komponen tambahan akan dipasang." #: src/bz-transaction-dialog.c:577 msgid "Additionally, addons will be installed." msgstr "Selain itu, komponen tambahan juga akan dipasang." #: src/bz-transaction-dialog.c:579 msgid "_Install All" msgstr "_Pasang Semua" #: src/bz-transaction-manager.c:766 #, c-format msgid "Finished in %.02f seconds" msgstr "Selesai dalam %.02f detik" #: src/bz-transaction-tile.blp:129 msgid "App Add-On" msgstr "Modul Aplikasi" #: src/bz-transaction-tile.blp:158 msgid "Runtime" msgstr "Tempokerja (Runtime)" #: src/bz-transaction-tile.blp:182 msgid "In Queue" msgstr "Dalam Antrian" #: src/bz-transaction-tile.blp:206 msgid "Done" msgstr "Selesai" #: src/bz-transaction-tile.blp:230 msgid "Error" msgstr "Terjadi Kesalahan" #: src/bz-transaction-tile.blp:286 msgid "Cancel Transaction" msgstr "Batalkan Proses" #: src/bz-transaction-tile.blp:410 msgid "Show Error Info" msgstr "Tampilkan Info Galat" #: src/bz-transaction-tile.c:107 #, c-format msgid "%s Freed" msgstr "%s Bebas" #: src/bz-transaction-tile.c:362 src/bz-transaction-tile.c:365 msgid "Transaction Error" msgstr "Terjadi Kegagalan" #: src/bz-transaction.c:342 msgid "Pending" msgstr "Ditunda" #: src/bz-updates-card.blp:40 msgid "_Update All" msgstr "_Perbarui Semua" #: src/bz-updates-card.c:293 #, c-format msgid "%u Runtime Update" msgid_plural "%u Runtime Updates" msgstr[0] "%u Tempokerja Baru" #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "Kelola Sisa Data Pengguna" #: src/bz-user-data-page.blp:89 msgid "No User Data Found" msgstr "Data Pengguna Tidak Ditemukan" #: src/bz-user-data-page.blp:94 msgid "User Data" msgstr "Data Pengguna" #: src/bz-user-data-tile.c:144 #, c-format msgid "Trashed User Data for %s" msgstr "Data aplikasi %s telah dihapus." #: src/bz-user-data-tile.blp:74 msgid "Trash User Data" msgstr "Hapus Data Pengguna" #: src/bz-window.blp:88 msgid "Curated" msgstr "Pilihan" #: src/bz-window.blp:100 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:220 msgid "Refresh completed!" msgstr "Penyegaran berhasil!" #: src/bz-window.blp:273 msgid "You are running a new version of Bazaar!" msgstr "Versi terbaru Bazaar telah terpasang!" #: src/bz-window.blp:274 msgid "See What's New" msgstr "Lihat Yang Baru" #: src/bz-window.blp:281 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "Saat ini Bazaar belum memuat halaman Flathub terbaru" #: src/bz-window.blp:393 msgid "Log Out" msgstr "Keluar" #. Translators: %s is the title of the current page #: src/bz-window.c:380 #, c-format msgid "Bazaar — %s" msgstr "Bazaar — %s" #: src/bz-window.c:487 msgid "Failed to load add-ons" msgstr "Gagal memuat modul tambahan" #: src/bz-window.c:601 src/bz-window.c:618 msgid "Failed to launch application" msgstr "Gagal menjalankan aplikasi" #: src/bz-window.c:823 msgid "You can't remove Bazaar from Bazaar!" msgstr "Anda tidak dapat menghapus Bazaar dari dalam Bazaar." #: src/bz-window.c:1108 src/bz-window.c:1142 msgid "Can't do that right now!" msgstr "Tunggu hingga Bazaar selesai memuat" #: src/bz-world-map.c:595 msgctxt "As in, \"100 Downloads\"" msgid "Downloads" msgstr "Unduhan" #: src/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Umum" #: src/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Page" msgstr "Buka Halaman Pencarian" #: src/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Library Page" msgstr "Buka Halaman Pustaka" #: src/shortcuts-dialog.blp:20 msgctxt "shortcut window" msgid "Refresh" msgstr "Muat ulang" #: src/shortcuts-dialog.blp:25 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Buka Pengaturan" #: src/shortcuts-dialog.blp:30 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Tampilkan Pintasan" #: src/shortcuts-dialog.blp:35 msgctxt "shortcut window" msgid "Close Window" msgstr "Tutup Jendela" #: src/shortcuts-dialog.blp:41 msgctxt "shortcut window" msgid "Quit Bazaar" msgstr "Keluar dari Bazaar" #~ msgid "" #~ "It emphasizes supporting the developers who make the Linux desktop " #~ "possible. Bazaar features a \"curated\" tab that can be configured by " #~ "distributors to allow for a more localized experience." #~ msgstr "" #~ "Bazaar menekankan pentingnya mendukung para pengembang yang telah " #~ "memajukan desktop Linux. Bazaar juga memberi ruang distributor untuk " #~ "melakukan kurasi aplikasi \"pilihan\" untuk pengguna. " #~ msgid "_Synchronize Remotes" #~ msgstr "_Sinkronkan Dengan Server" #~ msgid "Synchronizing..." #~ msgstr "Mengsinkronkan..." #, c-format #~ msgid "Receiving %d entries..." #~ msgstr "%d entri tersisa..." #~ msgid "Indexing Data..." #~ msgstr "Mengindeks Data..." #~ msgid "Install Other Version" #~ msgstr "Pasang Versi Lain" #~ msgid "Keep Data" #~ msgstr "Simpan Data" #~ msgid "Open App" #~ msgstr "Buka Aplikasi" #~ msgid "Refreshing Store Content" #~ msgstr "Memuat Ulang Konten Bazaar" #~ msgid "No background tasks!" #~ msgstr "Tidak ada proses latar belakang!" #~ msgctxt "shortcut window" #~ msgid "Synchronize Remotes" #~ msgstr "Sinkronkan Dengan Server" #~ msgctxt "shortcut window" #~ msgid "Quit" #~ msgstr "Keluar" #~ msgid "Nucleus app page" #~ msgstr "Tampilan halaman detail aplikasi" #~ msgid "Close" #~ msgstr "Tutup" #~ msgid "Copy and Close" #~ msgstr "Salin dan Tutup" #~ msgid "Toggle transaction sidebar" #~ msgstr "Tampil/sembunyikan bilah samping transaksi" #~ msgid "Install Size" #~ msgstr "Ukuran Terpasang" #~ msgid "Ongoing" #~ msgstr "Saat Ini" #~ msgid "Finished" #~ msgstr "Selesai" #, c-format #~ msgid "Transferred %s so far" #~ msgstr "Telah mentransfer %s sejauh ini" #, c-format #~ msgid "%d Update Available" #~ msgid_plural "%d Updates Available" #~ msgstr[0] "%d Pemutakhiran Tersedia" #~ msgid "Updates Are Available" #~ msgstr "Terdapat Pemutakhiran" #~ msgid "" #~ "The following applications are eligible for updates. Would you like to " #~ "install them?" #~ msgstr "" #~ "Aplikasi berikut memiliki pemutakhiran. Apakah anda ingin memasangnya?" #, c-format #~ msgid "" #~ "%d runtimes and/or addons are eligible for updates. Would you like to " #~ "install them?" #~ msgstr "" #~ "%d tempokerja dan/atau modul tambahan memiliki pemutakhiran. Apakah Anda " #~ "ingin memasangnya?" #, c-format #~ msgid "Additionally, %d runtimes and/or addons will be updated." #~ msgstr "" #~ "Selain itu, %d tempokerja dan/atau modul tambahan akan dimutakhirkan." #~ msgid "Update Now" #~ msgstr "Mutakhirkan Sekarang" #~ msgctxt "shortcut window" #~ msgid "Toggle Transaction Manager" #~ msgstr "Tampilkan/sembunyikan Manajer Transaksi" #~ msgid "Hide EOL Entries" #~ msgstr "Sembunyikan Aplikasi Tanpa Dukungan" #~ msgid "Hide EOL entries and entries depending on them" #~ msgstr "Sembunyikan aplikasi dan dependensi tanpa dukungan mutakhir" #~ msgid "Show Git Forge Star Counts" #~ msgstr "Tunjukkan Jumlah Bintang Repo" #~ msgid "" #~ "Whether to attempt to detect and show \"star counts\" for projects in the " #~ "full view" #~ msgstr "" #~ "Deteksi dan tampilkan data \"jumlah bintang\" repositori git saat memuat " #~ "halaman detail aplikasi" #~ msgid "Only Show Free Software" #~ msgstr "Sembunyikan Aplikasi Sumber Tertutup" #~ msgid "Hide proprietary software" #~ msgstr "Hanya tampilkan aplikasi dengan lisensi sumber terbuka" #~ msgid "Debounce Search Inputs" #~ msgstr "Tunda Masukan Pencarian" #~ msgid "Add a delay before searching to prevent instant replies while typing" #~ msgstr "" #~ "Tunda masukan saat mengetik untuk mencegah hasil pencarian muncul terlalu " #~ "cepat" #~ msgid "Global Progress Bar Theme" #~ msgstr "Tema Bilah Kemajuan" #~ msgid "Describes the look of the global progress bar" #~ msgstr "Pilih tampilan bilah kemajuan Bazaar" #~ msgid "Saved Window Dimensions" #~ msgstr "Dimensi Jendela Tersimpan" #~ msgid "The window dimensions to be used by the next Bazaar window" #~ msgstr "Dimensi jendela saat membuka jendela Bazaar berikutnya" #~ msgid "?" #~ msgstr "?" #, c-format #~ msgid "%s is suitable for toddlers" #~ msgstr "%s cocok untuk usia batita" #~ msgid "--- MB" #~ msgstr "--- MB" #~ msgid "Of the size of human DNA" #~ msgstr "Dari ukuran DNA manusia" #~ msgid "3 billion base pairs" #~ msgstr "3 miliar pasangan basa" #~ msgid "Of the Linux Kernel" #~ msgstr "Dari ukuran kernel Linux" #~ msgid "linux-6.17.tar.xz" #~ msgstr "linux-6.17.tar.xz" #~ msgid "Of the Apollo 11 guidance computer" #~ msgstr "Dari ukuran RAM dan ROM komputer pemandu Apollo 11" #~ msgid "Total ROM and RAM" #~ msgstr "Pada misi pendaratan manusia pertama di Bulan" #~ msgid "Of the original Super Mario Bros" #~ msgstr "Dari ukuran gim Super Mario Bros asli" #~ msgid "On the NES" #~ msgstr "pada konsol NES" #~ msgid "Of the size of Wikipedia" #~ msgstr "Dari ukuran seluruh artikel Wikipedia" #~ msgid "Without any media" #~ msgstr "Tanpa file media sama sekali" #~ msgid "" #~ "This functionality is currently disabled. It is recommended you download " #~ "and install Flatseal to manage app permissions." #~ msgstr "" #~ "Fitur ini sedang dinonaktifkan. Silahkan unduh dan pasang Flatseal untuk " #~ "mengatur perizinan aplikasi. " #~ msgid "Entry Inspector" #~ msgstr "Periksa Masukan" #~ msgid "Serialize" #~ msgstr "Serialisasikan" #~ msgid "Convert to JSON" #~ msgstr "Ubah ke JSON" #~ msgid "More Mobile apps" #~ msgstr "Aplikasi Ponsel lainnya" #~ msgid "We ♥ Games" #~ msgstr "Kami ♥ Main" #~ msgid "Repository Star Count" #~ msgstr "Jumlah Bintang Repositori" #, c-format #~ msgid "%.2fM" #~ msgstr "%.2fM" #, c-format #~ msgid "%.2fK" #~ msgstr "%.2fK" #~ msgid "Bazaar Inspector" #~ msgstr "Pemeriksa Bazaar" #~ msgid "Enable Global Debug Mode" #~ msgstr "Nyalakan Mode Debug Global" #~ msgid "Active Blocklists" #~ msgstr "Daftar Blok Aktif" #~ msgid "Active Curated-Configs" #~ msgstr "Konfigurasi Kurasi Aktif" #~ msgid "All Entry Groups" #~ msgstr "Seluruh Grup Masukan" #~ msgid "Filter..." #~ msgstr "Saring..." #~ msgid "Decache and Inspect" #~ msgstr "Hapus Cache dan Periksa" #~ msgid "No Flatpaks Installed" #~ msgstr "Tidak Ada Flatpak Terpasang" #~ msgid "Application Details" #~ msgstr "Detail Aplikasi" #~ msgid "Display Star Count" #~ msgstr "Tunjukkan Jumlah Bintang Repo" #~ msgid "Show the star count of an application's source code repository" #~ msgstr "Tunjukkan jumlah bintang dari repositori sumber aplikasi" #~ msgid "" #~ "Bazaar can fetch and display the star count from an application's source " #~ "code repository on a remote Git forge. \n" #~ " For projects on GitHub, rate limits may cause them not to appear." #~ msgstr "" #~ "Bazaar dapat mengambil dan menampilkan jumlah bintang dari repositori Git " #~ "sumber kode aplikasi.\n" #~ "Untuk aplikasi dari GitHub, terdapat potensi terbatasnya muatan yang " #~ "mungkin menghambat munculnya data ini." #~ msgid "Inspect UI Entry" #~ msgstr "Periksa Masukan Antarmuka" #~ msgid "All Debug Actions" #~ msgstr "Semua Tindakan Debug" #~ msgid "Tasks" #~ msgstr "Proses" #~ msgid "Stop Active Tasks" #~ msgstr "Hentikan Proses Aktif" #~ msgid "No Tasks Yet" #~ msgstr "Tidak ada proses berlangsung" #~ msgid "Sync" #~ msgstr "Sinkronisasi" #~ msgid "Open Bazaar Inspector" #~ msgstr "Buka Pemeriksa Bazaar" #~ msgid "" #~ "The ability to inspect and install local .flatpak bundle files is coming " #~ "soon! In the meantime, try running\n" #~ "\n" #~ "flatpak install --bundle your-bundle.flatpak\n" #~ "\n" #~ "on the command line." #~ msgstr "" #~ "Kemampuan membuka dan memasang file .flatpak secara lokal segera hadir! " #~ "Saat ini, coba jalankan\n" #~ "\n" #~ "flatpak install --bundle your-bundle.flatpak\n" #~ "\n" #~ "pada baris perintah." #~ msgid "Resume Current Tasks" #~ msgstr "Lanjutkan Proses Ini" #~ msgid "Pause Current Tasks" #~ msgstr "Jeda Proses Ini" #, c-format #~ msgid "%s: %'u downloads" #~ msgstr "%s: %'u unduhan" #~ msgid "Show Animated Background" #~ msgstr "Tampilkan Animasi Latar Belakang" #~ msgid "Whether to show the animated icon background on the home page" #~ msgstr "Tampilkan animasi ikon latar belakang pada halaman utama" #~ msgid "Keep the summary shorter, between 10 and 35 characters" #~ msgstr "Buat ringkasan pendek berkisar antara 10-35 karakter" #~ msgid "Main Bazaar window showing Blender" #~ msgstr "Jendela utama Bazaar yang menampilkan Blender" #~ msgid "This flatpak is verified by the original developers of the software." #~ msgstr "Flatpak ini telah diverifikasi oleh pengembang perangkat lunak asli" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Ahmed Najmawi" #~ msgstr "Ahmed Najmawi" #~ msgctxt "About Dialog Translator Credit" #~ msgid "AtomHare" #~ msgstr "AtomHare" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Jill Fiore" #~ msgstr "Jill Fiore" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Lucosec" #~ msgstr "Lucosec" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Shihfu Juan" #~ msgstr "Shihfu Juan" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Vlastimil Dědek" #~ msgstr "Vlastimil Dědek" #~ msgctxt "About Dialog Translator Credit" #~ msgid "asen23" #~ msgstr "asen23" #~ msgctxt "About Dialog Translator Credit" #~ msgid "renner" #~ msgstr "renner" #~ msgctxt "About Dialog Translator Credit" #~ msgid "robotta" #~ msgstr "robotta" #~ msgid "" #~ "Bazaar was not provided a curated content configuration. Contact your " #~ "operating system's support channels for assistance." #~ msgstr "" #~ "Konfigurasi kurasi konten Bazaar saat ini belum tersedia. Hubungi sistem " #~ "operasi anda untuk mendukung fitur ini." #~ msgid "Apps Of The Week" #~ msgstr "Aplikasi Minggu Ini" #~ msgid "" #~ "The number of downloads in the last 30 days. Click to view this " #~ "application's download statistics." #~ msgstr "" #~ "Jumlah unduhan pada 30 hari terakhir. Klik untuk melihat statistik " #~ "unduhan aplikasi ini." #~ msgid "Remote repo name" #~ msgstr "Nama repo remote" #~ msgid "How the application looks" #~ msgstr "Tampilan aplikasi" #~ msgid "Appearance" #~ msgstr "Tampilan" #~ msgid "Show animated background" #~ msgstr "Tampilkan animasi latar belakang" #~ msgid "Type to filter" #~ msgstr "Ketik untuk mencari" #~ msgid "Exclude results with proprietary licenses" #~ msgstr "Sembunyikan aplikasi berlisensi proprietari" #~ msgid "Advanced" #~ msgstr "Opsi Lanjutan" #~ msgid "Match using regular expressions" #~ msgstr "Cocokkan dengan ekspresi reguler (regex)" #~ msgid "Hide filtering and sorting behind a crossfade effect" #~ msgstr "Sembunyikan hasil pencarian dan sortir di balik transisi pemuatan" #~ msgid "Share" #~ msgstr "Bagikan" #~ msgid "Open this link externally" #~ msgstr "Buka tautan ini secara eksternal" #~ msgid "Downloads Over Time" #~ msgstr "Unduhan seiring waktu" #~ msgid "Minimize Lower Bound" #~ msgstr "Perkecil batas bawah" #~ msgid "Maximize Upper Bound" #~ msgstr "Perbesar batas atas" #~ msgid "Installing" #~ msgstr "Sedang dipasang" #~ msgid "Removing" #~ msgstr "Sedang dihapus" #~ msgid "Transactions Will Appear Here" #~ msgstr "Transaksi akan muncul di sini" #~ msgid "Halt the execution of transactions" #~ msgstr "Hentikan proses transaksi" #~ msgid "Browse" #~ msgstr "Telusuri" #~ msgid "App View" #~ msgstr "Tampilan Aplikasi" #~ msgid "Go Back" #~ msgstr "Kembali" #~ msgid "View curated applications" #~ msgstr "Lihat aplikasi pilihan" #~ msgid "View the latest on Flathub" #~ msgstr "Lihat yang terbaru dari Flathub" #~ msgid "Up to date!" #~ msgstr "Versi terkini sudah dimuat!" #~ msgid "Confirm Action" #~ msgstr "Konfirmasi Aksi" #, c-format #~ msgid "" #~ "You are about to remove the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "Anda akan menghapus Flatpak berikut:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Apakah Anda yakin?" #, c-format #~ msgid "" #~ "You are about to install the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "Anda akan memasang Flatpak berikut:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Apakah Anda yakin?" #~ msgid "Resume the execution of transactions" #~ msgstr "Lanjutkan proses transaksi" #~ msgid "Pause the execution of transactions" #~ msgstr "Hentikan sementara proses transaksi" bazaar-orig-v0.7.14/po/be.po0000664000175000017500000030613715166123241014516 0ustar hasanhasan# Belarusian translations for bazaar package. # Copyright (C) 2026 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2026. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-03-01 06:45+0100\n" "PO-Revision-Date: 2026-03-01 21:34+0100\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: be\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Poedit 3.8\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:6 #: src/bz-window.blp:110 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "Дадавайце, выдаляйце або абнаўляйце праграмы ў фармаце flatpak на гэтым камп’ютары" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;System;PackageManager;Discover;Flatpak;Software;Store;Сістэма;ПакетныМенеджар;Пакеты;Магазін;Крама;Флатпак;Праграмы;ПЗ;" #: data/io.github.kolunmi.Bazaar.desktop.in:15 msgid "New Window" msgstr "Новае акно" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and install applications" msgstr "Знаходзьце і ўсталёўвайце праграмы" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A new app store for Linux with a focus on discovering and installing applications and addons from Flatpak remotes, particularly " "Flathub." msgstr "" "Новая крама праграм для Linux з фокусам на тым, каб адкрываць і ўсталёўваць праграмы і дадаткі з аддаленых сервераў Flatpak (у " "прыватнасці — Flathub)." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:14 msgid "" "It emphasizes supporting the developers who make the Linux desktop possible. Bazaar features a \"curated\" tab that can be " "configured by distributors to allow for a more localized experience." msgstr "" "Яна робіць акцэнт на падтрымцы распрацоўшчыкаў, якія робяць магчымым Linux для настольных камп’ютараў. Bazaar вылучае ўкладку " "\"падабраныя\" праграмы, якую могуць канфігураваць пастаўшчыкі для больш цэласнага вопыту карыстання дыстрыбутывам." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:29 src/bz-application.c:699 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:54 msgid "The home page displaying Flathub apps" msgstr "Галоўная старонка паказвае праграмы з Flathub" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:58 msgid "Exhibit app page" msgstr "Дэманстрацыйная старонка праграмы" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:62 msgid "Library page" msgstr "Старонка бібліятэкі" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:66 msgid "Search page" msgstr "Старонка пошуку" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:70 msgid "Category page" msgstr "Старонка катэгорыі" #: src/bz-addons-dialog.blp:16 src/bz-full-view.blp:606 src/bz-installed-tile.blp:101 msgid "Manage Add-Ons" msgstr "Кіраваць дадаткамі" #: src/bz-addons-dialog.c:94 src/bz-install-controls.blp:78 src/bz-install-controls.blp:128 src/bz-installed-tile.blp:119 #: src/bz-transaction-dialog.c:231 msgid "Remove" msgstr "Выдаліць" #: src/bz-addons-dialog.c:99 src/bz-favorites-tile.c:159 src/bz-install-controls.blp:34 src/bz-transaction-dialog.c:202 msgid "Install" msgstr "Усталяваць" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 src/bz-age-rating-dialog.c:726 src/bz-full-view.c:333 #: src/bz-full-view.c:340 msgid "Age Rating" msgstr "Узроставы рэйтынг" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "Мультыплікацыйны гвалт" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "Няма звестак наконт сцэн гвалту мультыплікацыйнага характару" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "Фантазійны гвалт" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "Няма звестак наконт сцэн гвалту фантазійнага характару" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "Рэалістычны гвалт" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "Няма звестак наконт сцэн з рэалістычным гвалтам" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "Гвалт з кровапраліццем" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "Няма звестак наконт сцэн гвалту з кровапраліццем" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "Сексуальны гвалт" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "Няма звестак наконт сцэн з сексуальным гвалтам" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "Алкаголь" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "Няма звестак наконт згадвання алкагольных напояў" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "Наркотыкі" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "Няма звестак наконт згадвання забароненых наркотыкаў" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "Табак" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "Няма звестак наконт згадвання тытунёвых вырабаў" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "Аголенасць" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "Няма звестак наконт сцэн агалення" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "Сексуальныя сцэны" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "Няма звестак наконт згадванняў або выяў сексуальнага характару" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "Нецэнзурная лексіка" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "Няма звестак наконт нецэнзурнай лексікі любога кшталту" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "Недарэчны гумар" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "Няма звестак наконт недарэчнага гумару" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "Дыскрымінацыя" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "Няма звестак наконт моўнай дыскрымінацыі любога кшталту" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "Рэклама" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "Няма звестак наконт рэкламы любога кшталту" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "Азартныя гульні" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "Няма звестак наконт азартных гульняў любога кшталту" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "Купля за рэальныя грошы" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "Няма звестак наконт магчымасці траціць грошы" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "Чат паміж карыстальнікамі" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "Няма звестак наконт магчымасці вядзення размоў у чаце з іншымі карыстальнікамі" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "Аўдыячат паміж карыстальнікамі" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "Няма звестак наконт магчымасці вядзення размоў у аўдыячаце з іншымі карыстальнікамі" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 msgid "Contact Details" msgstr "Кантактныя звесткі" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "No information regarding sharing of social network usernames or email addresses" msgstr "Няма звестак наконт абагульвання імёнаў карыстальнікаў сацыяльнай сеткі або адрасоў электроннай пошты" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "Ідэнфікацыйныя звесткі" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "Няма звестак наконт перадачы даных карыстальніка староннім асобам" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "Абагульванне месцазнаходжання" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "Няма звестак наконт перадачы фізічнага месцазнаходжання іншым карыстальнікам" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "Прастытуцыя" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "Няма звестак наконт згадвання прастытуцыі" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "Сямейная нявернасць" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "Няма звестак наконт згадвання сямейнай нявернасці" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "Сексуалізаваныя персанажы" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "Няма звестак наконт сексуалізаваных персанажаў" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 msgid "Desecration" msgstr "Апаганьванне" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "Няма звестак наконт згадванняў пра апаганьванне" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "Парэшткі памерлых людзей" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "Няма звестак наконт бачных парэшткаў памерлых людзей" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "Рабства" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "Няма звестак наконт згадвання пра рабства" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "Не ўтрымлівае згадванняў пра наркотыкі" #: src/bz-age-rating-dialog.c:426 msgid "Does not include swearing, profanity, and other kinds of strong language" msgstr "Не ўтрымлівае лаянкі, нецэнзурнай і непрыстойнай лексікі" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "Не ўтрымлівае рэкламы або грашовых аперацый" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "Не ўтрымлівае сцэн сексу або агалення" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "Не ўтрымлівае бескантрольных функцый чата" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "Не ўтрымлівае сцэн гвалту" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "Наркотыкі" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "Лаянка" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "Грошы" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "Сувязь" #: src/bz-age-rating-dialog.c:479 msgid "Violence" msgstr "Гвалт" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:676 src/bz-full-view.c:323 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:701 msgctxt "Age rating" msgid "All" msgstr "Усе" #: src/bz-age-rating-dialog.c:737 #, c-format msgid "%s has an unknown age rating" msgstr "Узроставы рэйтынг \"%s\" невядомы" #: src/bz-age-rating-dialog.c:743 #, c-format msgid "%s is suitable for everyone" msgstr "\"%s\" прыдатна для ўсіх" #: src/bz-age-rating-dialog.c:746 #, c-format msgid "%s is suitable for young children" msgstr "\"%s\" прыдатна для дзяцей школьнага ўзросту (6+)" #: src/bz-age-rating-dialog.c:749 #, c-format msgid "%s is suitable for children" msgstr "\"%s\" прыдатна для дзяцей школьнага ўзросту (12+)" #: src/bz-age-rating-dialog.c:752 #, c-format msgid "%s is suitable for teenagers" msgstr "\"%s\" прыдатна для дзяцей старэйшага ўзросту (16+)" #: src/bz-age-rating-dialog.c:755 #, c-format msgid "%s is suitable for adults" msgstr "\"%s\" прыдатна для дарослых (18+)" #: src/bz-age-rating-dialog.c:758 #, c-format msgid "%s is suitable for %s" msgstr "\"%s\" прыдатна для %s" #: src/bz-age-rating-dialog.c:852 #, c-format msgid "%s • %s" msgstr "%s • %s" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:29 src/bz-user-data-page.blp:15 src/bz-window.blp:285 msgid "Main Menu" msgstr "Галоўнае меню" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 src/bz-user-data-page.blp:19 src/bz-window.blp:374 msgid "_Donate to Bazaar ❤️" msgstr "Па_дтрымаць Bazaar ❤️" #: src/bz-all-apps-page.blp:25 src/bz-apps-page.blp:25 src/bz-user-data-page.blp:26 src/bz-window.blp:381 msgid "_Refresh" msgstr "_Абнавіць" #: src/bz-all-apps-page.blp:30 src/bz-apps-page.blp:30 src/bz-user-data-page.blp:31 src/bz-window.blp:386 msgid "_Preferences" msgstr "_Параметры" #: src/bz-all-apps-page.blp:35 src/bz-apps-page.blp:35 src/bz-user-data-page.blp:36 src/bz-window.blp:391 msgid "_Login With Flathub" msgstr "_Увайсці праз Flathub" #: src/bz-all-apps-page.blp:41 src/bz-apps-page.blp:41 src/bz-user-data-page.blp:42 src/bz-window.blp:397 msgid "_Manage Leftover User Data" msgstr "_Кіраваць астаткамі даных карыстальніка" #: src/bz-all-apps-page.blp:46 src/bz-apps-page.blp:46 src/bz-user-data-page.blp:47 src/bz-window.blp:402 msgid "_Keyboard Shortcuts" msgstr "_Спалучэнні клавіш" #: src/bz-all-apps-page.blp:51 src/bz-apps-page.blp:51 src/bz-user-data-page.blp:52 src/bz-window.blp:407 msgid "_About Bazaar" msgstr "П_ра Bazaar" #: src/bz-all-apps-page.blp:58 src/bz-apps-page.blp:58 src/bz-user-data-page.blp:59 src/bz-window.blp:414 msgid "_Quit Bazaar" msgstr "_Выйсці з Bazaar" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "Сістэмная папка %s" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "Падпапка ў папцы \"Галоўная\" %s" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "Папкі сістэмы-хоста" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "Канфігурацыя сістэмы-хоста з /etc" #: src/bz-app-permissions.c:169 #, c-format msgid "Desktop subfolder %s" msgstr "Падпапка ў папцы працоўнага стала %s" #: src/bz-app-permissions.c:170 msgid "Desktop folder" msgstr "Папка працоўнага стала" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "Падпапка ў папцы \"Дакументы\" %s" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "Папка \"Дакументы\"" #: src/bz-app-permissions.c:177 #, c-format msgid "Music subfolder %s" msgstr "Падпапка ў папцы \"Музыка\" %s" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "Папка \"Музыка\"" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "Падпапка ў папцы \"Відарысы\" %s" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "Папка \"Відарысы\"" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "Падпапка ў папцы \"Публічныя файлы\" %s" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "Папка \"Публічныя файлы\"" #: src/bz-app-permissions.c:189 #, c-format msgid "Videos subfolder %s" msgstr "Падпапка \"Відэа\" %s" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "Папка \"Відэа\"" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "Падпапка \"Шаблоны\" %s" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "Папка \"Шаблоны\"" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "Падпапка з кэшам карыстальніка %s" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "Папка з кэшам карыстальніка" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "Падпапка ў папцы канфігурацыі карыстальніка %s" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "Папка канфігурацыі карыстальніка" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "Падпапка ў папцы даных карыстальніка %s" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "Папка даных карыстальніка" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "Падпапка ў папцы карыстальніцкага асяроддзя выканання %s" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "Папка карыстальніцкага асяроддзя выканання" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "Доступ файлавай сістэмы да %s" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "Невядомы шлях у файлавай сістэме" #: src/bz-app-size-dialog.blp:29 src/bz-app-size-dialog.blp:55 msgid "Download Size" msgstr "Памер спампоўвання" #: src/bz-app-size-dialog.blp:56 msgid "Amount to download from the internet" msgstr "Па даных да спампоўвання з інтэрнэту" #: src/bz-app-size-dialog.blp:76 msgid "Installed Size" msgstr "Памер усталёўкі" #: src/bz-app-size-dialog.blp:77 msgid "Size on Disk" msgstr "Памер на дыску" #: src/bz-app-size-dialog.blp:125 msgid "Open user data folder" msgstr "Адкрыць папку даных карыстальніка" #: src/bz-app-size-dialog.blp:135 msgid "User Data Size" msgstr "Памер даных карыстальніка" #: src/bz-app-size-dialog.blp:136 msgid "Caches, settings, and other app data" msgstr "Кэш, налады і іншыя даныя праграм" #: src/bz-app-size-dialog.c:99 msgid "Installed Runtime Size" msgstr "Памер усталяванага асяроддзя выканання" #: src/bz-app-size-dialog.c:99 msgid "Runtime Download Size" msgstr "Памер спрампаванага асяроддзя выканання" #: src/bz-app-tile.blp:57 src/bz-developer-badge.c:98 src/bz-rich-app-tile.blp:103 src/bz-rich-app-tile.c:275 msgid "Verified" msgstr "Спраўджана" #. Translators: As in 'The app is installed'. #: src/bz-app-tile.blp:89 src/bz-full-view.c:282 src/bz-releases-list.c:178 msgid "Installed" msgstr "Усталявана" #: src/bz-apps-page.blp:141 msgid "Show All" msgstr "Паказаць усё" #: src/bz-apps-page.c:229 #, c-format msgid "All \"%s\"" msgstr "Усё \"%s\"" #: src/bz-apps-page.c:498 src/bz-tag-list.c:109 #, c-format msgid "%d Applications" msgstr "Колькасць праграм: %d" #: src/bz-application.c:678 #, fuzzy msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:679 #, fuzzy msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:702 msgid "translator-credits" msgstr "Аляксандр Клюеў , 2026" #: src/bz-application.c:712 msgid "Special Thanks" msgstr "Асаблівая падзяка" #: src/bz-application.c:770 msgid "Logged Out Successfully!" msgstr "Выхад выкананы!" #: src/bz-application.c:893 msgid "Performing setup…" msgstr "Выконваецца наладжванне…" #: src/bz-application.c:977 msgid "Set Up System Flathub?" msgstr "Наладзіць Flathub на ўзроўні сістэмы?" #: src/bz-application.c:980 msgid "" "The system Flathub remote is not set up. Bazaar requires Flathub to be configured on the system Flatpak installation to browse " "and install applications.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Аддалены сервер Flathub не наладжаны для гэтай сістэмы. Для прагляду і ўсталёўвання праграм, Bazaar патрабуе канфігурацыі Flathub " "у сістэмнай ўсталёўцы Flatpak.\n" "\n" "Вы ўсё яшчэ зможаце выкарыстоўваць Bazaar для прагляду і выдалення ўжо ўсталяваных праграм." #: src/bz-application.c:987 msgid "Set Up Flathub?" msgstr "Наладзіць Flathub?" #: src/bz-application.c:990 msgid "" "Flathub is not set up on this system. You will not be able to browse and install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub не наладжаны для гэтай сістэмы. Вы не зможаце праглядаць і ўсталёўваць праграм у Bazaar, калі гэты сервіс не будзе " "даступны.\n" "\n" "Вы ўсё яшчэ зможаце выкарыстоўваць Bazaar для прагляду і выдалення ўжо ўсталяваных праграм." #: src/bz-application.c:996 msgid "Later" msgstr "Пазней" #: src/bz-application.c:997 msgid "Set Up Flathub" msgstr "Наладзіць Flathub" #: src/bz-application.c:1280 msgid "A backend error occurred" msgstr "Адбылася памылка на сервернай частцы" #: src/bz-application.c:1406 src/bz-application.c:3178 src/bz-window.blp:134 msgid "Refreshing…" msgstr "Ідзе абнаўленне…" #: src/bz-application.c:1552 src/bz-application.c:3176 #, c-format msgid "Loading %d apps…" msgstr "Ідзе загрузка праграм (%d)…" #: src/bz-application.c:1556 msgid "Checking for updates…" msgstr "Ідзе праверка абнаўленняў…" #: src/bz-application.c:1612 msgid "Failed to open .flatpakref" msgstr "Не ўдалося адкрыць .flatpakref" #: src/bz-application.c:1666 msgid "An initialization error occurred" msgstr "Адбылася памылка ініцыялізацыі" #: src/bz-application.c:2004 msgid "Failed to check for updates" msgstr "Не ўдалося праверыць абнаўленні" #: src/bz-application.c:2961 msgid "Could not find app" msgstr "Не ўдалося знайсці праграму" #: src/bz-application.c:3180 msgid "Writing to cache…" msgstr "Ідзе запіс у кэш…" #: src/bz-appstream-parser.c:304 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Старонка Flathub" #: src/bz-appstream-parser.c:325 msgctxt "Project URL Type" msgid "Project Website" msgstr "Вэб-сайт праекта" #: src/bz-appstream-parser.c:329 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Трэкер памылак" #: src/bz-appstream-parser.c:333 msgctxt "Project URL Type" msgid "FAQ" msgstr "Пытанні і адказы" #: src/bz-appstream-parser.c:337 msgctxt "Project URL Type" msgid "Help" msgstr "Даведка" #: src/bz-appstream-parser.c:341 msgctxt "Project URL Type" msgid "Donate" msgstr "Ахвяраваць" #: src/bz-appstream-parser.c:347 msgctxt "Project URL Type" msgid "Translate" msgstr "Перакласці" #: src/bz-appstream-parser.c:351 msgctxt "Project URL Type" msgid "Contact" msgstr "Звязацца" #: src/bz-appstream-parser.c:355 msgctxt "Project URL Type" msgid "Source Code" msgstr "Зыходны код" #: src/bz-appstream-parser.c:361 msgctxt "Project URL Type" msgid "Contribute" msgstr "Зрабіць унёсак" #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:68 src/bz-flathub-page.blp:19 src/bz-full-view.blp:61 #: src/bz-library-page.blp:65 src/bz-user-data-page.blp:86 msgid "Empty" msgstr "Пуста" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "Няма падборкі" #: src/bz-curated-view.blp:16 msgid "There is no curation information provided on this system. You can still browse applications on Flathub" msgstr "На гэтай сістэме не падаецца інфармацыі адносна падабраных праграм. Вы ўсё яшчэ можаце праглядаць праграмы ў Flathub" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "Праглядзець Flathub" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "Па-за сеткай" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 src/bz-search-pill-list.c:67 msgid "Browser" msgstr "Вэб-браўзер" #: src/bz-developer-badge.c:92 src/bz-developer-badge.c:98 msgid "Not Verified" msgstr "Не спраўджана" #: src/bz-developer-badge.c:145 msgid "Developer information not available." msgstr "Звесткі пра распрацоўшчыка недаступныя." #: src/bz-developer-badge.c:151 src/bz-developer-badge.c:165 #, c-format msgid "The ownership of the %s app ID has not been verified and it may be a community package." msgstr "Правы ўласнасці для ідэнтыфікатара праграмы \"%s\" не спраўджаны, таму, імаверна, гэта пакет ад супольнасці." #: src/bz-developer-badge.c:169 #, c-format msgid "The ownership of the %s app ID has been manually verified by the Flathub team." msgstr "Правы ўласнасці для ідэнтыфікатара праграмы \"%s\" былі спраўджаны ўручную камандай Flathub." #: src/bz-developer-badge.c:175 #, c-format msgid "The ownership of the %1$s app ID has been verified by %2$s on %3$s." msgstr "Правы ўласнасці для ідэнтыфікатара праграмы \"%1$s\" былі спраўджаны %2$s %3$s." #: src/bz-developer-badge.c:182 #, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "Правы ўласнасці для ідэнтыфікатара праграмы \"%1$s\" былі спраўджаны з дапамогай %2$s." #: src/bz-developer-badge.c:186 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "Правы ўласнасці для ідэнтыфікатара праграмы \"%s\" былі спраўджаны." #: src/bz-donations-dialog.blp:74 msgid "Full Release Notes" msgstr "Поўныя нататкі да выпуску" #: src/bz-donations-dialog.blp:105 msgid "This release was made possible by users like you!" msgstr "Гэты выпуск Bazaar стаў магчымым дзякуючы такім людзям, як вы!" #: src/bz-donations-dialog.blp:113 msgid "I love making Bazaar, but I cannot do it alone. Help support further development by donating on Ko-Fi." msgstr "" "Мне падабаецца ствараць Bazaar, але я не магу рабіць гэта ўадзіночку. Падтрымайце развіццё праекта ў будучыні, пакінуўшы " "ахвяраванне на старонцы Ko-Fi." #: src/bz-donations-dialog.blp:128 msgid "Donate to Bazaar" msgstr "Падтрымаць Bazaar" #. Translators: the %s format specifier will be something along the lines of "0.7.6" etc #: src/bz-donations-dialog.c:227 #, c-format msgid "What's New in %s?" msgstr "Што новага ў версіі %s?" #. Translators: this is a release date label, like "Released February 9, 2026" #: src/bz-donations-dialog.c:243 msgid "Released %B %-e, %Y" msgstr "Выпушчана %e %B %Y" #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "Выберыце ўсталёўку" #: src/bz-entry-group-util.c:76 msgid "You have multiple versions of this app installed. Which one would you like to proceed with?" msgstr "У вас усталявана некалькі версій гэтай праграмы. Якую з іх вы хацелі бы пакінуць на будучыню?" #: src/bz-entry-group-util.c:80 src/bz-transaction-dialog.c:201 src/bz-transaction-dialog.c:230 src/bz-transaction-dialog.c:275 #: src/bz-transaction-dialog.c:578 msgid "Cancel" msgstr "Скасаваць" #: src/bz-entry-selection-row.blp:17 msgid "For This User Only" msgstr "Толькі для гэтага карыстальніка" #: src/bz-entry-selection-row.c:112 msgid "this user" msgstr "гэты карыстальнік" #: src/bz-entry-selection-row.c:112 msgid "all users" msgstr "усе карыстальнікі" #: src/bz-error.c:69 src/bz-error.c:88 src/bz-error-dialog.blp:36 src/bz-safety-dialog.blp:50 msgid "Details" msgstr "Падрабязныя звесткі" #: src/bz-error-dialog.blp:47 msgid "Copy" msgstr "Скапіяваць" #: src/bz-error-dialog.c:56 src/bz-share-list.c:64 msgid "Copied!" msgstr "Скапіявана!" #: src/bz-favorite-button.c:388 msgid "Failed to update favorite" msgstr "Не ўдалося абнавіць спіс упадабаных" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "Увайдзіце ў Flathub, каб кіраваць абранымі" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "Увайсці" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "Колькасць упадабанняў" #: src/bz-favorites-tile.c:157 src/bz-rich-app-tile.blp:171 msgid "Uninstall" msgstr "Выдаліць" #: src/bz-favorites-tile.c:357 msgid "Failed to remove favorite" msgstr "Не ўдалося выдаліць з упадабаных" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:77 msgid "Support This Application" msgstr "Падтрымаць гэту праграму" #: src/bz-favorites-tile.blp:119 msgid "Remove From Favorites" msgstr "Выдаліць з упадабаных" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:78 src/bz-window.blp:432 msgid "Favorites" msgstr "Упадабаныя" #: src/bz-favorites-page.blp:17 src/bz-section-view.blp:144 src/bz-transaction-dialog.c:579 msgid "Install All" msgstr "Усталяваць усе" #: src/bz-favorites-page.blp:34 src/bz-full-view.blp:44 src/bz-window.blp:301 msgid "Open App Library" msgstr "Адкрыць бібліятэку праграм" #: src/bz-favorites-page.blp:56 src/bz-user-data-page.blp:75 msgid "Loading" msgstr "Ідзе загрузка" #: src/bz-favorites-page.blp:71 msgid "No Favorites" msgstr "Няма ўпадабаных" #: src/bz-favorites-page.blp:72 msgid "Applications you mark as favorite will appear here" msgstr "Тут будуць паказвацца праграмы, якія вы пазначылі як упадабаныя" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "Папярэдняя" #: src/bz-featured-carousel.blp:53 msgid "Next" msgstr "Наступная" #: src/bz-featured-tile.blp:88 msgid "App of the Day" msgstr "Праграмы дня" #: src/bz-flathub-category.c:89 msgid "Editing" msgstr "Рэдагаванне" #: src/bz-flathub-category.c:90 msgid "Midi" msgstr "Midi" #: src/bz-flathub-category.c:91 msgid "Mixer" msgstr "Мікшар" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-flathub-category.c:92 src/bz-search-pill-list.c:77 msgid "Music" msgstr "Музыка" #: src/bz-flathub-category.c:93 msgid "Player" msgstr "Прайгравальнік" #: src/bz-flathub-category.c:94 msgid "Recorder" msgstr "Праграма запісу гуку" #: src/bz-flathub-category.c:95 msgid "Sequencer" msgstr "Секвенсар" #: src/bz-flathub-category.c:96 msgid "Tuner" msgstr "Цюнер" #: src/bz-flathub-category.c:97 msgid "TV" msgstr "Тэлебачанне" #: src/bz-flathub-category.c:102 msgid "Emulation" msgstr "Эмуляцыя" #: src/bz-flathub-category.c:103 msgid "Action" msgstr "Экшн" #: src/bz-flathub-category.c:104 msgid "Adventure" msgstr "Прыгоды" #: src/bz-flathub-category.c:105 msgid "Arcade" msgstr "Аркады" #: src/bz-flathub-category.c:106 msgid "Blocks" msgstr "Блокі" #: src/bz-flathub-category.c:107 msgid "Board" msgstr "Настольныя" #: src/bz-flathub-category.c:108 msgid "Card" msgstr "Картачныя" #: src/bz-flathub-category.c:109 msgid "Kids" msgstr "Для дзяцей" #: src/bz-flathub-category.c:110 msgid "Logic" msgstr "На логіку" #: src/bz-flathub-category.c:111 msgid "Role Playing" msgstr "Ролевыя" #: src/bz-flathub-category.c:112 msgid "Shooter" msgstr "Шутары" #: src/bz-flathub-category.c:113 msgid "Simulation" msgstr "Сімулятары" #: src/bz-flathub-category.c:114 msgid "Sports" msgstr "Спорт" #: src/bz-flathub-category.c:115 msgid "Strategy" msgstr "Стратэгіі" #: src/bz-flathub-category.c:120 msgid "Audio & Video" msgstr "Аўдыя і відэа" #: src/bz-flathub-category.c:120 msgid "Media" msgstr "Мультымедыя" #: src/bz-flathub-category.c:120 msgid "More Audio & Video" msgstr "Больш аўдыя і відэа" #: src/bz-flathub-category.c:121 msgid "Developer Tools" msgstr "Інструменты распрацоўшчыка" #: src/bz-flathub-category.c:121 msgid "Develop" msgstr "Распрацоўка" #: src/bz-flathub-category.c:121 msgid "More Developer Tools" msgstr "Больш інструментаў распрацоўшчыка" #: src/bz-flathub-category.c:122 msgid "Education" msgstr "Адукацыя" #: src/bz-flathub-category.c:122 msgid "Learn" msgstr "Навучанне" #: src/bz-flathub-category.c:122 msgid "More Education" msgstr "Больш з адукацыі" #: src/bz-flathub-category.c:123 msgid "Gaming" msgstr "Гульні" #: src/bz-flathub-category.c:123 msgid "Play" msgstr "Гуляць" #: src/bz-flathub-category.c:123 msgid "More Gaming" msgstr "Больш гульняў" #: src/bz-flathub-category.c:124 msgid "Graphics & Photography" msgstr "Графіка і фатаграфія" #: src/bz-flathub-category.c:124 msgid "Create" msgstr "Творчасць" #: src/bz-flathub-category.c:124 msgid "More Graphics & Photography" msgstr "Больш графікі і фатаграфіі" #: src/bz-flathub-category.c:125 msgid "Networking" msgstr "Сеткі" #: src/bz-flathub-category.c:125 msgid "Internet" msgstr "Інтэрнэт" #: src/bz-flathub-category.c:125 msgid "More Networking" msgstr "Больш сеткавага" #: src/bz-flathub-category.c:126 msgid "Productivity" msgstr "Прадукцыйнасць" #: src/bz-flathub-category.c:126 msgid "Work" msgstr "Для працы" #: src/bz-flathub-category.c:126 msgid "More Productivity" msgstr "Больш для прадукцыйнасці" #: src/bz-flathub-category.c:127 msgid "Science" msgstr "Навука" #: src/bz-flathub-category.c:127 msgid "More Science" msgstr "Больш навуковага" #: src/bz-flathub-category.c:128 msgid "System" msgstr "Сістэмнае" #: src/bz-flathub-category.c:128 msgid "More System" msgstr "Больш сістэмнага" #: src/bz-flathub-category.c:129 msgid "Utilities" msgstr "Утыліты" #: src/bz-flathub-category.c:129 msgid "Tools" msgstr "Інструменты" #: src/bz-flathub-category.c:129 msgid "More Utilities" msgstr "Больш утыліт" #: src/bz-flathub-category.c:130 src/bz-flathub-page.blp:118 src/bz-flathub-page.blp:151 msgid "Trending" msgstr "У трэндзе" #: src/bz-flathub-category.c:130 msgid "More Trending" msgstr "Больш у трэндзе" #: src/bz-flathub-category.c:131 src/bz-flathub-page.blp:124 src/bz-flathub-page.blp:181 msgid "Popular" msgstr "Папулярныя" #: src/bz-flathub-category.c:131 msgid "More Popular" msgstr "Больш папулярных" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:171 msgid "Recently Added" msgstr "Нядаўна дададзеныя" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:130 msgid "New" msgstr "Новыя" #: src/bz-flathub-category.c:132 msgid "More New" msgstr "Больш новых" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:161 msgid "Recently Updated" msgstr "Нядаўна абноўленыя" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:136 msgid "Updated" msgstr "Абноўленыя" #: src/bz-flathub-category.c:133 msgid "More Updated" msgstr "Больш абноўленых" #: src/bz-flathub-category.c:134 msgid "Mobile" msgstr "Мабільныя" #: src/bz-flathub-category.c:134 msgid "More Mobile" msgstr "Больш мабільных" #: src/bz-flathub-category.c:135 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:135 msgid "More Adwaita" msgstr "Больш з тэмай Adwaita" #: src/bz-flathub-category.c:136 msgid "KDE Apps" msgstr "Праграмы KDE" #: src/bz-flathub-category.c:136 msgid "More KDE Apps" msgstr "Больш праграм KDE" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Flathub не дададзены" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "Аддалены сервер Flathub не быў знойдзены на якой-небудзь з вашых усталёвак Flatpak" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "Flathub вярнуў памылку" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "Паўтарыце спробу злучэння з Flathub" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Flathub не даступны" #: src/bz-flathub-page.blp:58 msgid "We could not connect to Flathub. You can still manage and search for applications." msgstr "Не атрымалася падключыцца да Flathub. Вы ўсё яшчэ можаце кіраваць праграмамі і шукаць іх." #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "Шукаць праграмы" #: src/bz-flathub-page.blp:261 msgid "On the Go" msgstr "На хаду" #: src/bz-flathub-page.blp:273 msgid "Apps for your Linux phones and tablets" msgstr "Праграмы для вашых тэлефонаў і планшэтаў на Linux" #: src/bz-flathub-page.blp:284 src/bz-flathub-page.blp:319 msgid "More Mobile Apps" msgstr "Больш мабільных праграм" #: src/bz-flathub-page.blp:377 msgid "We​ ♥​ Games" msgstr "Мы​ ♥​ гульні" #: src/bz-flathub-page.blp:390 msgid "Games and apps to run your favorite titles" msgstr "Гульні і праграмы для запуску вашых любімых гульняў" #: src/bz-flathub-page.blp:424 msgid "More Games" msgstr "Больш гульняў" #: src/bz-full-view.blp:65 src/bz-library-page.blp:76 src/bz-library-page.blp:80 msgid "No Results" msgstr "Нічога не знойдзена" #: src/bz-full-view.blp:66 msgid "Try a different search query" msgstr "Паспрабуйце іншы запыт" #: src/bz-full-view.blp:72 msgid "Content" msgstr "Змесціва" #: src/bz-full-view.blp:130 msgid "Installing .flatpak bundles is not yet supported" msgstr "Усталяванне .flatpak-набораў яшчэ не падтрымліваецца" #: src/bz-full-view.blp:234 msgid "Support" msgstr "Падтрымаць" #: src/bz-full-view.blp:404 msgid "Downloads/Month" msgstr "Спампоўванняў у месяц" #: src/bz-full-view.blp:440 msgid "Stopped Receiving Core Updates" msgstr "Атрыманне абнаўленняў ядра спынена" #: src/bz-full-view.blp:454 msgid "This app uses a runtime that no longer receives updates or security fixes. It may become unsafe to use." msgstr "" "Асяроддзе выканання гэтай праграмы больш не атрымлівае абнаўленняў і выпраўленняў, звязаных з бяспекай. Праграма можа стаць " "небяспечнай для выкарыстання." #: src/bz-full-view.blp:541 msgid "Trash Data" msgstr "Смеццевыя даныя" #: src/bz-full-view.blp:682 msgid "Tags:" msgstr "Цэтлікі:" #: src/bz-full-view.c:215 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:222 #, c-format msgid "%.*fM" msgstr "%.*f млн." #. Translators: K is the suffix for thousands #: src/bz-full-view.c:229 #, c-format msgid "%.*fK" msgstr "%.*f тыс." #: src/bz-full-view.c:239 #, c-format msgid "%d downloads in the last 30 days" msgstr "Спампоўванняў за апошнія 30 дзён: %d" #: src/bz-full-view.c:251 src/bz-full-view.c:592 src/bz-full-view.c:609 msgid "N/A" msgstr "N/A" #: src/bz-full-view.c:279 #, c-format msgid "+%s runtime" msgstr "+%s асяроддзе выканання" #: src/bz-full-view.c:282 msgid "Download" msgstr "Спампаваць" #: src/bz-full-view.c:302 msgid "Size information unavailable" msgstr "Інфармацыя пра памер недаступна" #: src/bz-full-view.c:305 #, c-format msgid "Download size of %s" msgstr "Памер спампоўвання для %s" #: src/bz-full-view.c:338 msgid "All Ages" msgstr "Для ўсіх узростаў" #: src/bz-full-view.c:350 msgid "Age rating information unavailable" msgstr "Інфармацыя пра ўзроставы рэйтынг недаступна" #: src/bz-full-view.c:355 msgid "Suitable for all ages" msgstr "Пасуе для ўсіх узростаў" #: src/bz-full-view.c:357 #, c-format msgid "Suitable for ages %d and up" msgstr "Пасуе для ўсіх узростаў ад %d гадоў" #: src/bz-full-view.c:390 src/bz-full-view.c:395 src/bz-full-view.c:423 src/bz-full-view.c:434 msgid "Unknown" msgstr "Невядомы" #: src/bz-full-view.c:400 #, c-format msgid "Free software licensed under %s" msgstr "Свабоднае ПЗ пад ліцэнзіяй %s" #: src/bz-full-view.c:405 msgid "Free software" msgstr "Свабоднае ПЗ" #: src/bz-full-view.c:408 msgid "Proprietary Software" msgstr "Прапрыетарнае ПЗ" #: src/bz-full-view.c:411 #, c-format msgid "Special License: %s" msgstr "Спецыяльная ліцэнзія: %s" #: src/bz-full-view.c:428 msgid "Free" msgstr "Вольная" #: src/bz-full-view.c:431 src/bz-license-dialog.c:132 msgid "Proprietary" msgstr "Прапрыетарная" #: src/bz-full-view.c:436 src/bz-license-dialog.c:134 msgid "Special License" msgstr "Спецыяльная ліцэнзія" #: src/bz-full-view.c:456 msgid "Adaptive" msgstr "Адаптыўная" #: src/bz-full-view.c:456 msgid "Desktop Only" msgstr "Толькі для настольных камп’ютараў" #: src/bz-full-view.c:462 msgid "Works on desktop, tablets, and phones" msgstr "Працуе на настольных камп’ютарах, планшэтах і тэлефонах" #: src/bz-full-view.c:463 msgid "May not work on mobile devices" msgstr "Можа не працаваць на мабільных прыладах" #: src/bz-full-view.c:474 msgid "No URL" msgstr "Няма URL-адраса" #: src/bz-full-view.c:492 msgid "This application has a FLOSS license, meaning the source code can be audited for safety." msgstr "" "Гэта праграма мае FLOSS-ліцэнзію (свабоднае ПЗ з адкрытым зыходным кодам). Гэта азначае, што магчымы аўдыт бяспекі для зыходнага " "кода праграмы." #: src/bz-full-view.c:493 msgid "" "This application has a proprietary license, meaning the source code is developed privately and cannot be audited by an " "independent third party." msgstr "" "Ліцэнзія гэтай праграмы — прапрыетарная. Гэта азначае, што зыходны код праграмы распрацоўваецца прыватна, а незалежны аўдыт для " "яго немагчымы." #: src/bz-full-view.c:500 msgid "More Apps" msgstr "Больш праграм" #: src/bz-full-view.c:501 #, c-format msgid "More Apps by %s" msgstr "Боль праграм ад %s" #: src/bz-full-view.c:508 msgid "Other Apps by this Developer" msgstr "Іншыя праграмы ад гэтага распрацоўшчыка" #: src/bz-full-view.c:510 src/bz-full-view.c:700 #, c-format msgid "Other Apps by %s" msgstr "Іншыя праграмы ад %s" #: src/bz-full-view.c:519 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "Праграма \"%s\" не ўсталявана, але на прыладзе ўсё яшчэ застаецца %s звязаных з ёю даных." #: src/bz-full-view.c:599 src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "Бяспечная" #: src/bz-full-view.c:601 src/bz-full-view.c:603 msgid "Low Risk" msgstr "Нізкая рызыка" #: src/bz-full-view.c:605 msgid "Medium Risk" msgstr "Сярэдняя рызыка" #: src/bz-full-view.c:607 msgid "High Risk" msgstr "Высокая рызыка" #: src/bz-full-view.c:702 msgid "Other Apps" msgstr "Іншыя праграмы" #: src/bz-full-view.c:704 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d праграма" msgstr[1] "%d праграмы" msgstr[2] "%d праграм" #: src/bz-full-view.c:931 src/bz-transaction-tile.c:340 msgid "Failed to launch application" msgstr "Не ўдалося запусціць праграму" #: src/bz-full-view.c:996 msgid "Show Less" msgstr "Паказаць менш" #: src/bz-full-view.c:996 msgid "Show More" msgstr "Паказаць больш" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 msgid "Hardware Support" msgstr "Падтрымка абсталявання" #: src/bz-hardware-support-dialog.c:62 msgid "Keyboard support" msgstr "Падтрымка клавіятур" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "Патрабуюцца клавіятуры" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "Рэкамендуецца ўжыванне клавіятур" #: src/bz-hardware-support-dialog.c:66 msgid "Supports keyboards" msgstr "Клавіятуры падтрымліваюцца" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "Няма звестак пра падтрымку клавіятур" #: src/bz-hardware-support-dialog.c:69 msgid "Mouse support" msgstr "Падтрымка мышы" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "Патрабуецца мыш або ўказальныя прылады" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "Рэкамендуецца ўжыванне мышы або ўказальных прылад" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "Мыш або ўказальныя прылады падтрымліваюцца" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "Няма звестак пра падтрымку мышы або ўказальных прылад" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "Падтрымка сэнсарнага экрана" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "Патрэбны сэнсарны экран" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "Рэкамендуецца ўжыванне сэнсарнага экрана" #: src/bz-hardware-support-dialog.c:80 msgid "Supports touchscreens" msgstr "Сэнсарныя экраны падтрымліваюцца" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "Невядома пра падтрымку сэнсарных экранаў" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "Мабільныя прылад" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "Працуе на мабільных прыладах" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "Можа працаваць не лепшым чынам на мабільных прыладах" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "Падтрымка стацыянарных прылад" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "Добра працуе на вялікіх экранах" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "%s працуе на асаблівым абсталяванні" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "%s працуе на большасці прылад" #: src/bz-install-controls.blp:32 msgid "Download & Install Application" msgstr "Спампаваць і ўсталяваць праграму" #: src/bz-install-controls.blp:54 msgid "Open" msgstr "Адкрыць" #: src/bz-install-controls.blp:68 src/bz-install-controls.blp:118 msgid "Uninstall Application" msgstr "Выдаліць праграму" #: src/bz-install-controls.blp:105 src/bz-updates-card.blp:161 src/bz-updates-card.blp:186 msgid "Update" msgstr "Абнавіць" #: src/bz-install-controls.blp:155 msgid "Install Other Version" msgstr "Усталяваць іншую версію" #: src/bz-installed-tile.blp:63 src/bz-rich-app-tile.blp:139 msgid "Stopped Receiving Updates" msgstr "Спынена атрыманне абнаўленняў" #: src/bz-library-page.blp:31 msgid "Search installed apps" msgstr "Пошук усталяваных праграм" #: src/bz-library-page.blp:48 msgid "Clear search" msgstr "Ачысціць пошук" #: src/bz-library-page.blp:69 msgid "No Apps Found" msgstr "Праграм не знойдзена" #. Translators: . #: src/bz-library-page.blp:98 src/bz-window.blp:176 msgid "Library" msgstr "Бібліятэка" #: src/bz-library-page.blp:126 msgid "Pending Updates" msgstr "Абнаўленні ў чаканні" #: src/bz-library-page.blp:153 msgid "Downloads" msgstr "Спампоўкі" #: src/bz-library-page.blp:196 msgid "Recently Uninstalled" msgstr "Нядаўна выдаленае" #: src/bz-library-page.blp:247 msgid "Clear Finished Tasks" msgstr "Ачысціць завершаныя задачы" #: src/bz-library-page.blp:258 msgid "Installed Apps" msgstr "Усталяваныя праграмы" #: src/bz-library-page.c:175 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "У спісе ўсталяваных праграм нічога не знойдзена для запыту \"%s\"" #: src/bz-library-page.c:188 src/bz-updates-card.c:257 #, c-format msgid "%u Available Update" msgid_plural "%u Available Updates" msgstr[0] "Даступна %u абнаўленне" msgstr[1] "Даступна %u абнаўленні" msgstr[2] "Даступна %u абнаўленняў" #: src/bz-license-dialog.blp:95 msgid "Get Involved" msgstr "Прыняць удзел" #: src/bz-license-dialog.c:126 msgid "Unknown License" msgstr "Невядомая ліцэнзія" #: src/bz-license-dialog.c:129 msgid "Community Built" msgstr "Зборка ад супольнасці" #: src/bz-license-dialog.c:202 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Гэта праграма распрацоўваецца адкрытай міжнароднай супольнасцю.\n" "\n" "Вы можаце прыняць удзел у распрацоўцы і дапамагчы палепшыць яе." #: src/bz-license-dialog.c:205 msgid "The license of this app is not known" msgstr "Ліцэнзія для гэтай праграмы невядомая" #: src/bz-license-dialog.c:211 #, c-format msgid "" "This app is developed in the open by an international community, and released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Гэта праграма распрацоўваецца адкрытай міжнароднай супольнасцю і распаўсюджваецца пад ліцэнзіяй %s.\n" "\n" "Вы можаце прыняць удзел у распрацоўцы і дапамагчы палепшыць яе." #: src/bz-license-dialog.c:219 msgid "" "This app is not developed in the open, so only its developers know how it works. It may be insecure in ways that are hard to " "detect, and it may change without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Гэта праграма распрацоўваецца закрытым чынам, таму толькі яе стваральнікі ведаюць, як яна працуе. Гэта можа несці з сабой " "небяспеку, якую цяжка выявіць, а сама праграма можа змяняцца без нагляду.\n" "\n" "У вас можа як быць, так і не быць магчымасці ўдзелу ў распрацоўцы гэтай праграмы." #: src/bz-license-dialog.c:225 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Гэта праграма распрацоўваецца пад спецыяльнай ліцэнзіяй %s.\n" "\n" "Вы не зможаце прыняць удзелу ў яе распрацоўцы." #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 msgid "Connect to Flathub" msgstr "Злучыцца з Flathub" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "Нешта пайшло не так" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "Падключыце свой уліковы запіс Flathub да Bazaar, каб кіраваць сваімі праграмамі ў спісе абраных." #: src/bz-login-page.blp:108 msgid "Finish" msgstr "Скончыць" #: src/bz-login-page.c:664 #, c-format msgid "Hello, %s!" msgstr "Вітаем, %s!" #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Параметры" #: src/bz-preferences-dialog.blp:25 msgid "Network connection is metered — automatic store data refresh is paused" msgstr "Падключэнне да сеткі з падлікам трафіка — аўтаматычная сінхранізацыя даных крамы прыпынена" #: src/bz-preferences-dialog.blp:26 src/bz-window.blp:328 msgid "Refresh Manually" msgstr "Сінхранізаваць уручную" #: src/bz-preferences-dialog.blp:31 msgid "Content Filters" msgstr "Фільтры змесціва" #: src/bz-preferences-dialog.blp:34 msgid "Free Software Only" msgstr "Толькі свабоднае праграмнае забеспячэ" #: src/bz-preferences-dialog.blp:35 msgid "Hide proprietary applications when browsing and searching" msgstr "Схаваць падчас прагляду і пошуку прапрыетарныя праграмы" #: src/bz-preferences-dialog.blp:39 msgid "Flathub Results Only" msgstr "Толькі вынікі з Flathub" #: src/bz-preferences-dialog.blp:40 msgid "Limit search and browse results to applications only available on Flathub" msgstr "Абмежаваць пошук і прагляд вынікаў праграмамі, якія даступныя толькі на Flathub" #: src/bz-preferences-dialog.blp:44 msgid "Verified Results Only" msgstr "Толькі спраўджаныя вынікі" #: src/bz-preferences-dialog.blp:45 msgid "Hide results that are not verified on Flathub" msgstr "Схаваць вынікі, якія не спраўджаны на Flathub" #: src/bz-preferences-dialog.blp:49 msgid "Hide EOL Apps" msgstr "Схаваць праграмы напрыканцы тэрміну службы" #: src/bz-preferences-dialog.blp:50 msgid "Hide apps which are no longer supported by their developers" msgstr "Схаваць праграмы, якія больш не падтрымліваюцца іх распрацоўшчыкамі" #: src/bz-preferences-dialog.blp:55 src/bz-window.blp:191 msgid "Search" msgstr "Пошук" #: src/bz-preferences-dialog.blp:58 msgid "Delay Search Results" msgstr "Адкладваць паказванне вынікаў пошуку" #: src/bz-preferences-dialog.blp:59 msgid "Improve results performance by debouncing search terms" msgstr "Палепшыце якасць пошуку з прадухіленнем пошуку памылковых значэнняў" #: src/bz-preferences-dialog.blp:64 msgid "Progress Bar" msgstr "Індыкатар выканання" #: src/bz-preferences-dialog.blp:65 msgid "Choose a theme for the progress bar!" msgstr "Выберыце тэму індыкатара выканання!" #: src/bz-preferences-dialog.blp:89 msgid "Vertical Stripes" msgstr "Вертыкальныя палосы" #: src/bz-preferences-dialog.blp:90 msgid "Display flag colors from left to right" msgstr "Паказваць колеры сцяга злева направа" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Колер акцэнту" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Колеры гонару" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "Колеры гонару — лесбіянкі" #: src/bz-preferences-dialog.c:35 msgid "Male Homosexual Pride Colors" msgstr "Колеры гонару — мужчыны гомасексуалы" #: src/bz-preferences-dialog.c:36 msgid "Transgender Pride Colors" msgstr "Колеры гонару — трансгендары" #: src/bz-preferences-dialog.c:37 msgid "Nonbinary Pride Colors" msgstr "Колеры гонару — небінарныя асобы" #: src/bz-preferences-dialog.c:38 msgid "Bisexual Pride Colors" msgstr "Колеры гонару — бісексуалы" #: src/bz-preferences-dialog.c:39 msgid "Asexual Pride Colors" msgstr "Колеры гонару — асексуалы" #: src/bz-preferences-dialog.c:40 msgid "Pansexual Pride Colors" msgstr "Колеры гонару — пансексуалы" #: src/bz-preferences-dialog.c:41 msgid "Aromantic Pride Colors" msgstr "Колеры гонару — арамантычныя асобы" #: src/bz-preferences-dialog.c:42 msgid "Genderfluid Pride Colors" msgstr "Колеры гонару — гендарфлюідныя асобы" #: src/bz-preferences-dialog.c:43 msgid "Polysexual Pride Colors" msgstr "Колеры гонару — полісексуальныя асобы" #: src/bz-preferences-dialog.c:44 msgid "Omnisexual Pride Colors" msgstr "Колеры гонару — омнісексуальныя асобы" #: src/bz-preferences-dialog.c:45 msgid "Aroace Pride Colors" msgstr "Колеры гонару — арамантычныя асексуальныя асобы" #: src/bz-preferences-dialog.c:46 msgid "Agender Pride Colors" msgstr "Колеры гонару — агендарныя асобы" #: src/bz-preferences-dialog.c:47 msgid "Genderqueer Pride Colors" msgstr "Колеры гонару — гендарквіры" #: src/bz-preferences-dialog.c:48 msgid "Intersex Pride Colors" msgstr "Колеры гонару — інтэрсексуалы" #: src/bz-preferences-dialog.c:49 msgid "Demigender Pride Colors" msgstr "Колеры гонару — дэмігендарныя асобы" #: src/bz-preferences-dialog.c:50 msgid "Biromantic Pride Colors" msgstr "Колеры гонару — бірамантычныя асобы" #: src/bz-preferences-dialog.c:51 msgid "Disability Pride Colors" msgstr "Колеры гонару — асобы з асаблівымі патрэбамі" #: src/bz-preferences-dialog.c:52 msgid "Femboy Pride Colors" msgstr "Колеры гонару — фембоі" #: src/bz-preferences-dialog.c:53 msgid "Neutrois Pride Colors" msgstr "Колеры гонару — пазагендарныя асобы" #: src/bz-releases-dialog.blp:5 src/bz-releases-list.blp:28 src/bz-updates-card.blp:150 msgid "Version History" msgstr "Гісторыя версій" #. Translators: This is a date format for timestamps from the current year. Used in the app releases section. #. * %B is the full month name, %e is the day. #. * Example: "October 1" #. * See https://docs.gtk.org/glib/method.DateTime.format.html for format options #. * Please modify to make it sound natural in your locale. #. * #: src/bz-releases-list.c:121 msgid "%e %B" msgstr "%e %B" #. Translators: This is a date format for timestamps from previous years. Used in the app releases section. #. * %B is the full month name, %e is the day, %Y is the year. #. * Example: "October 1, 2025" #. * See https://docs.gtk.org/glib/method.DateTime.format.html for format options #. * Please modify to make it sound natural in your locale. #. * #: src/bz-releases-list.c:129 msgid "%e %B %Y" msgstr "%e %B %Y" #: src/bz-releases-list.c:168 #, c-format msgid "Version %s" msgstr "Версія %s" #: src/bz-releases-list.c:220 msgid "No details for this release" msgstr "Пра гэта выданне няма звестак" #: src/bz-releases-list.c:232 msgid "Get More Information" msgstr "Атрымаць больш інфармацыі" #: src/bz-rich-app-tile.blp:156 msgid "Get" msgstr "Атрымаць" #: src/bz-safety-calculator.c:82 msgid "Unknown Permissions" msgstr "Дазволы невядомыя" #: src/bz-safety-calculator.c:83 msgid "Permissions are missing for this app." msgstr "Не хапае дазволаў для гэтай праграмы." #: src/bz-safety-calculator.c:96 msgid "No Permissions" msgstr "Не патрабуе дазволаў" #: src/bz-safety-calculator.c:97 msgid "App is fully sandboxed" msgstr "Праграма цалкам выконваецца ў «пясочніцы»" #: src/bz-safety-calculator.c:103 msgid "Network Access" msgstr "Доступ да сеткі" #: src/bz-safety-calculator.c:104 msgid "Can access the internet" msgstr "Мае доступ да інтэрнэту" #: src/bz-safety-calculator.c:106 msgid "No Network Access" msgstr "Без доступу да сеткі" #: src/bz-safety-calculator.c:107 msgid "Cannot access the internet" msgstr "Не мае доступу да інтэрнэту" #: src/bz-safety-calculator.c:112 msgid "User Device Access" msgstr "Доступ да прылад карыстальніка" #: src/bz-safety-calculator.c:113 msgid "Can access devices such as webcams or gaming controllers" msgstr "Мае доступ да прылад накшталт вэб-камер або гульнявых кантролераў" #: src/bz-safety-calculator.c:115 msgid "No User Device Access" msgstr "Без доступу да прылад карыстальніка" #: src/bz-safety-calculator.c:116 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "Не мае доступу да прылад накшталт вэб-камер або гульнявых кантролераў" #: src/bz-safety-calculator.c:121 msgid "Input Device Access" msgstr "Доступ да прылад уводу" #: src/bz-safety-calculator.c:122 msgid "Can access input devices" msgstr "Мае доступ да прылад уводу" #: src/bz-safety-calculator.c:128 msgid "Microphone Access and Audio Playback" msgstr "Доступ да мікрафона і прайгравання аўдыя" #: src/bz-safety-calculator.c:129 msgid "Can listen using microphones and play audio without asking permission" msgstr "Можа весці праслухоўванне праз мікрафон і прайграваць аўдыя не пытаючы дазволу" #: src/bz-safety-calculator.c:135 msgid "System Device Access" msgstr "Доступ да сістэмных прылад" #: src/bz-safety-calculator.c:136 msgid "Can access system devices which require elevated permissions" msgstr "Мае доступ да сістэмных прылад, якія патрабуюць павышанага ўзроўню дазволаў" #: src/bz-safety-calculator.c:142 msgid "Screen Contents Access" msgstr "Доступ да змесціва экрана" #: src/bz-safety-calculator.c:143 msgid "Can access the contents of the screen or other windows" msgstr "Мае доступ да змесціва экрана або іншых акон" #: src/bz-safety-calculator.c:149 msgid "Legacy Windowing System" msgstr "Састарэлы аконны інтэрфейс" #: src/bz-safety-calculator.c:150 msgid "Always uses a legacy windowing system (X11)" msgstr "Заўсёды выкарыстоўвае састарэлую сістэму кіравання вокнамі (X11)" #: src/bz-safety-calculator.c:156 msgid "Arbitrary Permissions" msgstr "Адвольныя дазволы" #: src/bz-safety-calculator.c:157 msgid "Can acquire arbitrary permissions" msgstr "Можа атрымліваць адвольныя дазволы" #: src/bz-safety-calculator.c:163 msgid "User Settings" msgstr "Налады карыстальніка" #: src/bz-safety-calculator.c:164 msgid "Can access and change user settings" msgstr "Можа праглядаць і змяняць налады карыстальніка" #: src/bz-safety-calculator.c:170 msgid "Full File System Read/Write Access" msgstr "Чытанне і запіс даных ва усёй файлавай сістэме" #: src/bz-safety-calculator.c:171 msgid "Can read and write all data on the file system" msgstr "Мае доступ да чытання і запісу даных ва усёй файлавай сістэме" #: src/bz-safety-calculator.c:178 msgid "Home Folder Read/Write Access" msgstr "Чытанне і запіс даных ў галоўнай папцы" #: src/bz-safety-calculator.c:179 msgid "Can read and write all data in your home directory" msgstr "Мае доступ да чытання і запісу даных ў галоўнай папцы" #: src/bz-safety-calculator.c:186 msgid "Full File System Read Access" msgstr "Чытанне даных ва ўсёй файлавай сістэме" #: src/bz-safety-calculator.c:187 msgid "Can read all data on the file system" msgstr "Мае доступ да чытання даных ва усёй файлавай сістэме" #: src/bz-safety-calculator.c:195 msgid "Home Folder Read Access" msgstr "Чытанне даных у галоўнай папцы" #: src/bz-safety-calculator.c:196 msgid "Can read all data in your home directory" msgstr "Мае доступ да чытання ў галоўнай папцы" #: src/bz-safety-calculator.c:204 msgid "Download Folder Read/Write Access" msgstr "Чытанне і запіс даных у папцы спамповак" #: src/bz-safety-calculator.c:205 msgid "Can read and write all data in your downloads directory" msgstr "Мае доступ да чытання і запісу даных у папцы спамповак" #: src/bz-safety-calculator.c:215 msgid "Download Folder Read Access" msgstr "Чытанне даных ў папцы спамповак" #: src/bz-safety-calculator.c:216 msgid "Can read all data in your downloads directory" msgstr "Мае доступ да чытання даных ў папцы спамповак" #: src/bz-safety-calculator.c:229 msgid "Can read and write all data in the directory" msgstr "Мае доступ да чытання і запісу даных у каталогу" #: src/bz-safety-calculator.c:243 msgid "Can read all data in the directory" msgstr "Мае доступ да чытання даных у каталогу" #: src/bz-safety-calculator.c:258 msgid "No File System Access" msgstr "Без доступу да файлавай сістэмы" #: src/bz-safety-calculator.c:259 msgid "Cannot access the file system at all" msgstr "Не мае доступу да ўсёй файлавай сістэмы" #: src/bz-safety-calculator.c:266 msgid "Uses System Services" msgstr "Выкарыстоўвае сістэмныя сэрвісы" #: src/bz-safety-calculator.c:267 msgid "Can request data from non-portal system services" msgstr "Можа запытваць даныя з сістэмных сэрвісаў, якія не звязаны з парталам" #: src/bz-safety-calculator.c:273 msgid "Uses Session Services" msgstr "Выкарыстоўвае сэрвісы сеанса" #: src/bz-safety-calculator.c:274 msgid "Can request data from non-portal session services" msgstr "Можа запытваць даныя з сэрвісаў сеанса, якія не звязаны з парталам" #: src/bz-safety-calculator.c:322 msgid "No Service Access" msgstr "Без доступу да сэрвісаў" #: src/bz-safety-calculator.c:323 msgid "Cannot access non-portal session or system services at all" msgstr "Не можа запытваць даныя з сэрвісаў сеанса або сістэмных сэрвісаў, якія не звязаны з парталам" #: src/bz-safety-calculator.c:331 msgid "Verified App Developer" msgstr "Спраўджаны распрацоўшчык" #: src/bz-safety-calculator.c:332 msgid "The developer of this app has been verified to be who they say they are" msgstr "Распрацоўшчык гэтай праграмы прайшоў спраўджанне асобы" #: src/bz-safety-calculator.c:341 msgid "Proprietary Code" msgstr "Прапрыетарны код" #: src/bz-safety-calculator.c:342 msgid "The source code is not public, so it cannot be independently audited and might be unsafe" msgstr "Зыходны код праграмы не даступны для публікі, яго нельга праверыць незалежна, таму праграма можа быць небяспечнай" #: src/bz-safety-calculator.c:352 msgid "Auditable Code" msgstr "Правяральны код" #: src/bz-safety-calculator.c:353 msgid "The source code is public and can be independently audited, which makes the app more likely to be safe" msgstr "Зыходны код праграмы даступны для публікі, яго можна праверыць незалежна, таму з большай верагоднасцю праграма бяспечная" #: src/bz-safety-calculator.c:493 #, c-format msgid "Use the %s System Service" msgstr "Выкарыстоўвае сістэмны сэрвіс %s" #: src/bz-safety-calculator.c:497 #, c-format msgid "Use the %s Session Service" msgstr "Выкарыстоўвае сэрвіс сеанса %s" #: src/bz-safety-calculator.c:501 #, c-format msgid "Use the %s Service" msgstr "Выкарыстоўвае сервіс %s" #: src/bz-safety-calculator.c:511 msgid "Can see the non-portal service" msgstr "Можа праглядаць сэрвіс, які не звязаны з парталам" #: src/bz-safety-calculator.c:513 msgid "Can talk to the non-portal service" msgstr "Можа адпраўляць паведамленні сэрвісу, які не звязаны з парталам" #: src/bz-safety-calculator.c:515 msgid "Can own the non-portal service" msgstr "Можа валодаць сэрвісам, які не звязаны з парталам" #: src/bz-safety-calculator.c:530 msgid "Global Menu Integration" msgstr "Інтэграцыя з глабальным меню" #: src/bz-safety-calculator.c:531 msgid "Can display its menus in a global menu bar" msgstr "Можа паказваць свае меню ў панэлі глабальнага меню" #: src/bz-safety-calculator.c:536 msgid "KDE Settings Integration" msgstr "Інтэграцыя ў наладамі KDE" #: src/bz-safety-calculator.c:537 msgid "Can detect when KDE desktop settings change" msgstr "Можа адсочваць змены ў наладах асяроддзя KDE" #: src/bz-safety-calculator.c:542 msgid "KDE Global Settings" msgstr "Глабальныя налады KDE" #: src/bz-safety-calculator.c:543 msgid "Can read KDE desktop preferences like fonts and colors" msgstr "Можа чытаць такія параметры асяроддзя KDE, як выбар шрыфтоў і колераў" #: src/bz-safety-calculator.c:548 msgid "Secret Storage Service" msgstr "Служба сховішча сакрэтаў" #: src/bz-safety-calculator.c:549 msgid "Can store and retrieve its own passwords using the system keyring" msgstr "Можа захоўваць і атрымліваць уласныя паролі з дапамогай набору сістэмных ключоў" #: src/bz-safety-calculator.c:554 msgid "Desktop Notifications Service" msgstr "Сэрвіс апавяшчэнняў на працоўным стале" #: src/bz-safety-calculator.c:555 msgid "Can send desktop notifications" msgstr "Можа адпраўляць апавяшчэнні на працоўным стале" #: src/bz-safety-calculator.c:561 msgid "System Tray Integration" msgstr "Інтэграцыя з панэллю заданняў" #: src/bz-safety-calculator.c:562 msgid "Can display an icon in the system tray" msgstr "Можа паказваць значок у панэлі заданняў" #: src/bz-safety-calculator.c:567 msgid "KDE Connect Integration" msgstr "Інтэграцыя з KDE Connect" #: src/bz-safety-calculator.c:568 msgid "Can interact with devices paired via KDE Connect" msgstr "Можа ўзаемадзейнічаць з прыладамі, спалучанымі праз KDE Connect" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "Бяспека" #: src/bz-safety-dialog.blp:53 msgid "License" msgstr "Ліцэнзія" #: src/bz-safety-dialog.blp:63 msgid "App ID" msgstr "ID праграмы" #: src/bz-safety-dialog.blp:73 msgid "SDK" msgstr "SDK" #: src/bz-safety-dialog.blp:104 msgid "" "This app uses an outdated version of the software platform (SDK) and might contain bugs or security vulnerabilities which will " "not be fixed." msgstr "" "Гэта праграма выкарыстоўвае састарэлую версію праграмнай платформы (SDK) і, імаврна, утрымлівае памылкі або пагрозы для бяспекі, " "якія немагчыма выправіць." #: src/bz-safety-dialog.c:227 #, c-format msgid "%s is Safe" msgstr "%s у бяспецы" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s has no Unsafe Permissions" msgstr "%s не мае небяспечных дазволаў" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Probably Safe" msgstr "%s імаверна бяспечная" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Possibly Unsafe" msgstr "%s можа несці небяспеку" #: src/bz-safety-dialog.c:247 #, c-format msgid "%s is Unsafe" msgstr "%s небяспечная" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "Здымкі экрана" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "Папярэдні здымак" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "Наступны здымак" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "Скапіяваць відарыс" #: src/bz-screenshot-page.blp:147 msgid "Reset View" msgstr "Скінуць від" #: src/bz-screenshot-page.blp:158 msgid "Zoom Out" msgstr "Паменшыць" #: src/bz-screenshot-page.blp:168 msgid "Zoom In" msgstr "Павялічыць" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "Карусель здымкаў экрана" #: src/bz-screenshots-carousel.blp:112 msgid "Open Screenshot Viewer" msgstr "Адкрыць прагляд здымкаў экрана" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:72 msgid "Video" msgstr "Відэа" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:82 msgid "Office" msgstr "Офіс" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:87 msgid "PDF" msgstr "PDF" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:92 msgid "Calendar" msgstr "Каляндар" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:97 msgid "Messaging" msgstr "Паведамленні" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:102 msgid "Steam" msgstr "Steam" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:107 msgid "Paint" msgstr "Маляванне" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:112 msgid "VPN" msgstr "VPN" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:117 msgid "Torrent" msgstr "Torrent" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:122 msgid "Minecraft" msgstr "Minecraft" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:127 msgid "Emulator" msgstr "Эмулятар" #: src/bz-search-widget.blp:57 msgid "Search Apps, Games, Software" msgstr "Пошук праграм і гульняў" #: src/bz-search-widget.blp:79 msgid "Clear Search" msgstr "Ачысціць пошук" #: src/bz-search-widget.blp:167 msgid "Categories Unavailable" msgstr "Катэгорыі не даступныя" #: src/bz-search-widget.blp:168 msgid "Search for apps using the search bar above." msgstr "Шукайце праграмы, выкарыстоўваючы панэль зверху." #: src/bz-search-widget.blp:193 msgid "Browse Categories" msgstr "Агляд катэгорый" #: src/bz-search-widget.blp:316 msgid "No Applications Found" msgstr "Праграм не знойдзена" #: src/bz-search-widget.c:243 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "Для запыту \"%s\" на Flathub нічога не знайшлося" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "Скапіяваць спасылку" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Адкрыць спасылку" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "Часавая шкала" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "Усталяванняў:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "У свеце" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:124 #, c-format msgid "%.2fM Total Installs" msgstr "Усяго ўсталяванняў — %.2f млн." #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:127 #, c-format msgid "%.2fK Total Installs" msgstr "Усяго ўсталяванняў — %.2f тыс." #: src/bz-stats-dialog.c:129 #, c-format msgid "%'d Total Installs" msgstr "Усяго ўсталяванняў — %'d" #: src/bz-tag-list.c:96 msgid "No Results Found" msgstr "Няма вынікаў" #: src/bz-tag-list.c:108 #, c-format msgid "Apps Tagged \"%s\"" msgstr "Праграмы з цэтлікам \"%s\"" #: src/bz-tag-list.c:124 msgid "Search failed" msgstr "Памылка пошуку" #: src/bz-transaction-dialog.c:155 msgid "Keep User Data" msgstr "Пакінуць даныя карыстальніка" #: src/bz-transaction-dialog.c:156 msgid "Allow restoring personal settings & content" msgstr "Дазволіць аднаўляць персанальныя налады і змесціва" #: src/bz-transaction-dialog.c:165 msgid "Delete All Data" msgstr "Выдаліць усе даныя" #: src/bz-transaction-dialog.c:166 msgid "Permanently erase user data to save space" msgstr "Незваротна выдаліць даныя карыстальніка, каб зберагчы месца" #: src/bz-transaction-dialog.c:191 #, c-format msgid "Install %s?" msgstr "Усталяваць \"%s\"?" #: src/bz-transaction-dialog.c:196 msgid "Select which version to install. May install additional shared components" msgstr "Выберыце, якую версію ўсталяваць. Могуць усталявацца дадатковыя абагуленыя кампаненты" #: src/bz-transaction-dialog.c:198 msgid "May install additional shared components" msgstr "Можа ўсталяваць дадатковыя абагуленыя кампаненты" #: src/bz-transaction-dialog.c:219 #, c-format msgid "Remove %s?" msgstr "Выдаліць \"%s\"?" #: src/bz-transaction-dialog.c:222 msgid "Select which version to remove." msgstr "Выберыце, якую версію выдаліць." #: src/bz-transaction-dialog.c:224 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "Праграму %s нельга будзе выкарыстоўваць пасля выдалення." #: src/bz-transaction-dialog.c:247 #, c-format msgid "“%s” is High Risk" msgstr "Праграма \"%s\" нясе высокія рызыкі" #: src/bz-transaction-dialog.c:251 msgid "" "This app has full access to your system, including all your files, browser history, saved passwords, and more. It also has " "access to the internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with these permissions." msgstr "" "Гэта праграма мае поўны доступ да сістэмы, у тым ліку да ўсіх вашых файлаў, гісторыі браўзера, захаваных пароляў і не " "толькі. Таксама, яна мае доступ да інтэрнэту, што азначае, што яна можа адпраўляць вашы даныя знешнім суб’ектам.\n" "\n" "З-за таго, што праграма з’яўляецца прапрыетарнай, немагчыма правесці праверку таго, што яна робіць з гэтымі дазволамі." #: src/bz-transaction-dialog.c:260 msgid "" "This app uses the legacy X11 windowing system, which allows it to record all keystrokes, capture screenshots, and monitor " "other applications. It also has access to the internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with these permissions." msgstr "" "Гэта праграма выкарыстоўвае састарэлую версію сістэмы кіравання вокнамі X11, у якой ёсць дазвол на запісванне ўсіх спалучэнняў " "клавіш, стварэнне здымкаў экрана і сачыць за іншымі праграмамі. Таксама, яна мае доступ да інтэрнэту, што азначае, што яна " "можа адпраўляць вашы даныя знешнім суб’ектам.\n" "\n" "З-за таго, што праграма з’яўляецца прапрыетарнай, немагчыма правесці праверку таго, што яна робіць з гэтымі дазволамі." #: src/bz-transaction-dialog.c:276 msgid "Install Anyway" msgstr "Усё адно ўсталяваць" #: src/bz-transaction-dialog.c:331 msgid "Failed to load transaction dialog" msgstr "Не ўдалося загрузіць дыялог трансакцыі" #: src/bz-transaction-dialog.c:549 msgid "All apps are already installed" msgstr "Усе праграмы ўсталяваны" #: src/bz-transaction-dialog.c:551 msgid "OK" msgstr "OK" #: src/bz-transaction-dialog.c:567 #, c-format msgid "Install %u App?" msgid_plural "Install %u Apps?" msgstr[0] "Усталяваць %u праграму?" msgstr[1] "Усталяваць %u праграмы?" msgstr[2] "Усталяваць %u праграм?" #: src/bz-transaction-dialog.c:575 msgid "The following will be installed. Additional shared components may also be installed" msgstr "Будуць усталяваны наступныя праграмы. Разам з імі могуць усталявацца дадатковыя агульныя кампаненты" #: src/bz-transaction-dialog.c:576 #, c-format msgid "%d addons will be installed." msgstr "Будзе ўсталявана столькі дадаткаў: %d." #: src/bz-transaction-dialog.c:577 msgid "Additionally, addons will be installed." msgstr "Таксама будуць усталяваны дадаткі." #: src/bz-transaction-manager.c:766 #, c-format msgid "Finished in %.02f seconds" msgstr "Завершана за %.02f сек" #: src/bz-transaction-tile.blp:126 msgid "App Add-On" msgstr "Дадатак да праграмы" #: src/bz-transaction-tile.blp:155 msgid "Runtime" msgstr "Асяроддзе выканання" #: src/bz-transaction-tile.blp:179 msgid "In Queue" msgstr "У чарзе" #: src/bz-transaction-tile.blp:203 msgid "Done" msgstr "Зроблена" #: src/bz-transaction-tile.blp:227 msgid "Error" msgstr "Памылка" #: src/bz-transaction-tile.blp:271 msgid "Open App" msgstr "Адкрыць праграму" #: src/bz-transaction-tile.blp:285 msgid "Cancel Transaction" msgstr "Скасаваць трансакцыю" #: src/bz-transaction-tile.blp:409 msgid "Show Error Info" msgstr "Паказаць звесткі пра памылку" #: src/bz-transaction-tile.c:112 #, c-format msgid "%s Freed" msgstr "Вызвалена месца: %s" #: src/bz-transaction-tile.c:398 src/bz-transaction-tile.c:401 msgid "Transaction Error" msgstr "Памылка трансакцыі" #: src/bz-transaction.c:342 msgid "Pending" msgstr "У чаканні" #: src/bz-updates-card.blp:36 msgid "Update All" msgstr "Абнавіць усе" #: src/bz-updates-card.c:293 #, c-format msgid "%u Runtime Update" msgid_plural "%u Runtime Updates" msgstr[0] "%u абнаўленне асяроддзя выканання" msgstr[1] "%u абнаўленні асяроддзя выканання" msgstr[2] "%u абнаўленняў асяроддзя выканання" #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "Кіраваць астаткамі даных карыстальніка" #: src/bz-user-data-page.blp:89 msgid "No User Data Found" msgstr "Даных карыстальніка не знойдзена" #: src/bz-user-data-page.blp:94 msgid "User Data" msgstr "Даныя карыстальніка" #: src/bz-user-data-tile.c:144 #, c-format msgid "Trashed User Data for %s" msgstr "Перамешчаныя даныя карыстальніка для %s" #: src/bz-user-data-tile.blp:74 msgid "Trash User Data" msgstr "Перамясціць даныя карыстальніка ў сметніцу" #: src/bz-window.blp:152 msgid "Curated" msgstr "Падабраныя" #: src/bz-window.blp:164 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:266 msgid "Refresh completed!" msgstr "Абнаўленне скончана!" #: src/bz-window.blp:319 msgid "You are running a new version of Bazaar!" msgstr "Вы запусцілі новую версію Bazaar!" #: src/bz-window.blp:320 msgid "See What's New" msgstr "Паглядзець, што новага" #: src/bz-window.blp:327 msgid "You have a network connection but are viewing a cached version of Flathub" msgstr "У вас ёсць злучэнне з сеткай, але вы праглядаеце версію Flathub у кэшы" #: src/bz-window.blp:439 msgid "Log Out" msgstr "Выйсці" #: src/bz-window.c:473 msgid "Failed to load add-ons" msgstr "Не ўдалося загрузіць дадаткі" #: src/bz-window.c:763 msgid "You can't remove Bazaar from Bazaar!" msgstr "Вы не можаце выдаліць Bazaar, карыстаючыся Bazaar!" #: src/bz-window.c:1055 src/bz-window.c:1089 msgid "Can't do that right now!" msgstr "У гэты момант дзеянне немагчымае!" #: src/bz-world-map.c:587 msgctxt "As in, \"100 Downloads\"" msgid "Downloads" msgstr "Спампоўкі" #: src/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Асноўнае" #: src/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Refresh" msgstr "Абнавіць" #: src/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Адкрыць параметры" #: src/shortcuts-dialog.blp:19 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "Адкрыць дыялог пошуку" #: src/shortcuts-dialog.blp:24 msgctxt "shortcut window" msgid "Open Library" msgstr "Адкрыць бібліятэку" #: src/shortcuts-dialog.blp:30 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Паказаць спалучэнні клавіш" #: src/shortcuts-dialog.blp:35 msgctxt "shortcut window" msgid "Close Window" msgstr "Закрыць акно" #: src/shortcuts-dialog.blp:41 msgctxt "shortcut window" msgid "Quit Bazaar" msgstr "Выйсці з Bazaar" #~ msgid "_Synchronize Remotes" #~ msgstr "Сін_хранізацыя з аддаленымі серверамі" #~ msgid "Synchronizing..." #~ msgstr "Ідзе сінхранізацыя..." #, c-format #~ msgid "Receiving %d entries..." #~ msgstr "Ідзе атрыманне запісаў (%d)..." #~ msgid "Indexing Data..." #~ msgstr "Ідзе індэксаванне даных..." #~ msgid "View the Release Page" #~ msgstr "Праглядзець старонку выпуску" #~ msgid "Close" #~ msgstr "Закрыць" #~ msgid "Copy and Close" #~ msgstr "Скапіяваць і закрыць" #~ msgid "Keep Data" #~ msgstr "Пакінуць даныя" #~ msgid "Refreshing Store Content" #~ msgstr "Ідзе абнаўленне змесціва крамы" #~ msgid "No background tasks!" #~ msgstr "Няма фонавых задач!" #~ msgctxt "shortcut window" #~ msgid "Synchronize Remotes" #~ msgstr "Сінхранізацыя з аддаленымі серверамі" #~ msgctxt "shortcut window" #~ msgid "Quit" #~ msgstr "Выйсці" bazaar-orig-v0.7.14/po/tr.po0000664000175000017500000024356715166123241014564 0ustar hasanhasan# Turkish translation for io.github.kolunmi.Bazaar. # Copyright (C) 2025-2026 io.github.kolunmi.Bazaar's COPYRIGHT HOLDER # This file is distributed under the same license as the io.github.kolunmi.Bazaar package. # # Sabri Ünal , 2025-2026. # msgid "" msgstr "" "Project-Id-Version: io.github.kolunmi.Bazaar master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-01 10:05+0300\n" "PO-Revision-Date: 2026-04-02 18:40+0300\n" "Last-Translator: Sabri Ünal \n" "Language-Team: Turkish \n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Poedit 3.9\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:46 #: src/bz-window.c:377 src/bz-window.c:378 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "Bu bilgisayara flatpak yazılımı ekle, kaldır ya da güncelle" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "" "GTK;System;PackageManager;Discover;Flatpak;Software;Store;Sistem;Paket " "Yöneticisi;Keşfet;Yazılımlar;Mağaza;Çarşı;" #: data/io.github.kolunmi.Bazaar.desktop.in:16 msgid "New Window" msgstr "Yeni Pencere" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and manage applications" msgstr "Uygulamaları keşfet ve yönet" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A fast and modern app store for Linux with a focus on discovering and " "installing Flatpak apps and addons, particularly from Flathub." msgstr "" "Özellikle Flathubʼdan Flatpak uygulamalarını ve eklentilerini keşfetmeye ve " "kurmaya odaklanan, Linux için hızlı ve modern uygulama mağazası." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:15 msgid "Queue multiple installs and keep browsing" msgstr "Birden çok kurulumu kuyruklar ve gezinmeye devam et" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:16 msgid "Easily view app permissions" msgstr "Uygulama izinlerini kolayca görüntüle" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:17 msgid "Sign in to Flathub to view and manage your favorites" msgstr "Gözdelerinizi görüntülemek ve yönetmek için Flathub ile oturum açın" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:18 msgid "Search apps directly from GNOME Shell" msgstr "Uygulamaları GNOME Shell üstünden ara" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:30 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:55 msgid "The home page displaying Flathub apps" msgstr "Flathub uygulamalarını görüntüleyen ana görünüm" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:59 msgid "Exhibit app page" msgstr "Uygulama sergisi sayfası" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:63 msgid "Library page" msgstr "Kitaplık sayfası" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:67 msgid "Search page" msgstr "Arama sayfası" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:71 msgid "Category page" msgstr "Kategori sayfası" #: src/bz-addons-dialog.blp:16 src/bz-full-view.blp:627 #: src/bz-installed-tile.blp:101 msgid "Manage Add-Ons" msgstr "Eklentileri Yönet" #: src/bz-addons-dialog.c:94 src/bz-install-controls.blp:142 #: src/bz-installed-tile.blp:114 msgid "Remove" msgstr "Kaldır" #: src/bz-addons-dialog.c:99 src/bz-favorites-tile.c:159 msgid "Install" msgstr "Kur" # Arayüzde sığmadığı için new line eklendi #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 #: src/bz-age-rating-dialog.c:736 src/bz-full-view.c:333 src/bz-full-view.c:340 msgid "Age Rating" msgstr "" "Yaş\n" "Derecelendirmesi" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "Çizgi Dizisi Şiddeti" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "Çizgi dizisi şiddetiyle ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "Fantezi Şiddeti" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "Fantezi şiddetiyle ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "Gerçekçi Şiddet" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "Gerçekçi şiddetle ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "Kan Dökülmesini Betimleyen Şiddet" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "Kan dökülmesiyle ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "Cinsel Şiddet" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "Cinsel şiddetle ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "Alkol" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "Alkole atıflarla ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "Uyuşturucu" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "Yasadışı ilaçlara atıflarla ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "Tütün" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "Tütün ürünlerine atıflarla ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "Çıplaklık" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "Herhangi biçimde çıplaklıkla ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "Cinsel Temalar" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "Cinsel doğaya atıf ya da betimlemelerle ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "Sövgü" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "Herhangi türde küfürlerle ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "Uygunsuz Mizah" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "Uygunsuz mizahla ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "Ayrımcılık" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "Herhangi türde ayrımcı dille ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "Reklam" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "Herhangi türde reklamla ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "Kumar" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "Herhangi türde kumarla ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "Satın Alım" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "Para harcama yeteneğiyle ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "Kullanıcılar Arası Sohbet" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "Diğer kullanıcılarla sohbet etme yollarıyla ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "Kullanıcılar Arası Sesli Sohbet" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "Diğer kullanıcılarla konuşma yollarıyla ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 msgid "Contact Details" msgstr "Kişi Ayrıntıları" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "" "Sosyal ağ kullanıcı adlarının ya da e-posta adreslerinin paylaşımıyla ilgili " "bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "Tanımlayıcı Bilgiler" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "Üçüncü şahıslarla kullanıcı bilgisi paylaşımıyla ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "Konum Paylaşımı" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "Diğer kullanıcılarla fiziksel konum paylaşımıyla ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "Fuhuş" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "Fuhşa atıflarla ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "Zina" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "Eş aldatmaya atıflarla ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "Cinselleştirilmiş Karakterler" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "Cinselleştirilmiş karakterlerle ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 msgid "Desecration" msgstr "Saygısızlık" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "Kutsala saygısızlığa atıflarla ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "İnsan Kalıntıları" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "Görününür ölü insan kalıntılarıyla ilgili bilgi yok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "Kölelik" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "Köleliğe atıflarla ilgili bilgi yok" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "Yasadışı ilaçlara atıf içermez" #: src/bz-age-rating-dialog.c:426 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "Küfür, sövgü ve diğer türlerde sert dil içermez" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "Reklam ya da parasal işlemler içermez" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "Cinsellik ya da çıplaklık içermez" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "Denetimsiz sohbet işlevi içermez" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "Şiddet içermez" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "Uyuşturucu" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "Sert Dil" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "Para" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "Sosyal" #: src/bz-age-rating-dialog.c:479 msgid "Violence" msgstr "Şiddet" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:686 src/bz-full-view.c:323 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:711 msgctxt "Age rating" msgid "All" msgstr "Tümü" #: src/bz-age-rating-dialog.c:747 #, c-format msgid "%s has an unknown age rating" msgstr "%s yaş derecelendirmesi bilinmiyor" #: src/bz-age-rating-dialog.c:753 #, c-format msgid "%s is suitable for everyone" msgstr "%s, herkese uygundur" #: src/bz-age-rating-dialog.c:756 #, c-format msgid "%s is suitable for young children" msgstr "%s, küçük çocuklara uygundur" #: src/bz-age-rating-dialog.c:759 #, c-format msgid "%s is suitable for children" msgstr "%s, çocuklara uygundur" #: src/bz-age-rating-dialog.c:762 #, c-format msgid "%s is suitable for teenagers" msgstr "%s, ergenlere uygundur" #: src/bz-age-rating-dialog.c:765 #, c-format msgid "%s is suitable for adults" msgstr "%s, yetişkinlere uygundur" #: src/bz-age-rating-dialog.c:768 #, c-format msgid "%s is suitable for %s" msgstr "%s, %s için uygundur" #: src/bz-age-rating-dialog.c:862 #, c-format msgid "%s • %s" msgstr "%s • %s" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:29 #: src/bz-user-data-page.blp:15 src/bz-window.blp:239 msgid "Main Menu" msgstr "Ana Menü" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 #: src/bz-user-data-page.blp:19 src/bz-window.blp:328 msgid "_Donate to Bazaar ❤️" msgstr "Bazaarʼa _Bağış Yap ❤️" #: src/bz-all-apps-page.blp:25 src/bz-apps-page.blp:25 #: src/bz-user-data-page.blp:26 src/bz-window.blp:335 msgid "_Refresh" msgstr "_Yenile" #: src/bz-all-apps-page.blp:30 src/bz-apps-page.blp:30 #: src/bz-user-data-page.blp:31 src/bz-window.blp:340 msgid "_Preferences" msgstr "_Tercihler" #: src/bz-all-apps-page.blp:35 src/bz-apps-page.blp:35 #: src/bz-user-data-page.blp:36 src/bz-window.blp:345 msgid "_Login With Flathub" msgstr "Flathub İle _Oturum Aç" #: src/bz-all-apps-page.blp:41 src/bz-apps-page.blp:41 #: src/bz-user-data-page.blp:42 src/bz-window.blp:351 msgid "_Manage Leftover User Data" msgstr "Artık Kullanıcı Verisini _Yönet" #: src/bz-all-apps-page.blp:46 src/bz-apps-page.blp:46 #: src/bz-user-data-page.blp:47 src/bz-window.blp:356 msgid "_Keyboard Shortcuts" msgstr "_Klavye Kısayolları" #: src/bz-all-apps-page.blp:51 src/bz-apps-page.blp:51 #: src/bz-user-data-page.blp:52 src/bz-window.blp:361 msgid "_About Bazaar" msgstr "Bazaar _Hakkında" #: src/bz-all-apps-page.blp:58 src/bz-apps-page.blp:58 #: src/bz-user-data-page.blp:59 src/bz-window.blp:368 msgid "_Quit Bazaar" msgstr "Bazaarʼdan Çı_k" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "Sistem klasörü %s" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "Ev alt klasörü %s" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "Ana makine sistem klasörleri" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "/etc dizininden ana makine sistem yapılandırması" #: src/bz-app-permissions.c:169 #, c-format msgid "Desktop subfolder %s" msgstr "Masaüstü alt klasörü %s" #: src/bz-app-permissions.c:170 msgid "Desktop folder" msgstr "Masaüstü klasörü" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "Belgeler alt klasörü %s" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "Belgeler klasörü" #: src/bz-app-permissions.c:177 #, c-format msgid "Music subfolder %s" msgstr "Müzik alt klasörü %s" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "Müzik klasörü" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "Resimler alt klasörü %s" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "Resimler klasörü" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "Paylaşılanlar alt klasörü %s" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "Paylaşılanlar klasörü" #: src/bz-app-permissions.c:189 #, c-format msgid "Videos subfolder %s" msgstr "Videolar alt klasörü %s" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "Videolar klasörü" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "Şablonlar alt klasörü %s" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "Şablonlar klasörü" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "Kullanıcı ön bellek alt klasörü %s" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "Kullanıcı ön bellek klasörü" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "Kullanıcı yapılandırma alt klasörü %s" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "Kullanıcı yapılandırma klasörü" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "Kullanıcı verisi alt klasörü %s" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "Kullanıcı veri klasörü" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "Kullanıcı çalışma zamanı alt klasörü %s" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "Kullanıcı çalışma zamanı klasörü" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "Dosya sistemi erişimi %s" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "Bilinmeyen dosya sistemi yolu" #: src/bz-app-size-dialog.blp:29 src/bz-app-size-dialog.blp:55 msgid "Download Size" msgstr "İndirme Boyutu" #: src/bz-app-size-dialog.blp:56 msgid "Amount to download from the internet" msgstr "İnternetten indirilecek miktar" #: src/bz-app-size-dialog.blp:76 msgid "Installed Size" msgstr "Kurulu Boyut" # Kasten daha açıklayıcı bir çeviri kullanıldı #: src/bz-app-size-dialog.blp:77 msgid "Size on Disk" msgstr "Diskteki kapladığı alan" #: src/bz-app-size-dialog.blp:125 msgid "Open user data folder" msgstr "Kullanıcı veri klasörünü aç" #: src/bz-app-size-dialog.blp:135 msgid "User Data Size" msgstr "Kullanıcı Verisi Boyutu" #: src/bz-app-size-dialog.blp:136 msgid "Caches, settings, and other app data" msgstr "Önbellekler, ayarlar ve diğer uygulama verileri" #: src/bz-app-size-dialog.c:99 msgid "Installed Runtime Size" msgstr "Çalışma Zamanı Kurulum Boyutu" #: src/bz-app-size-dialog.c:99 msgid "Runtime Download Size" msgstr "Çalışma Zamanı İndirme Boyutu" #: src/bz-app-tile.blp:57 src/bz-developer-badge.c:98 #: src/bz-rich-app-tile.blp:104 src/bz-rich-app-tile.c:304 msgid "Verified" msgstr "Doğrulanmış" #. Translators: As in 'The app is installed'. #: src/bz-app-tile.blp:88 src/bz-full-view.c:282 src/bz-releases-list.c:205 msgid "Installed" msgstr "Kurulu" #: src/bz-apps-page.blp:142 msgid "Show All" msgstr "Tümünü Göster" #: src/bz-apps-page.c:229 #, c-format msgid "All \"%s\"" msgstr "Tüm \"%s\"" #: src/bz-apps-page.c:478 src/bz-tag-list.c:91 #, c-format msgid "%d Applications" msgstr "%d Uygulama" #: src/bz-application.c:695 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:696 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #: src/bz-application.c:716 msgid "The Bazaar Contributors" msgstr "Bazaar Katkıcıları" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:719 msgid "translator-credits" msgstr "Sabri Ünal , 2025-2026" #: src/bz-application.c:729 msgid "Special Thanks" msgstr "Özel Teşekkürler" #: src/bz-application.c:787 msgid "Logged Out Successfully!" msgstr "Oturum Kapatıldı!" #: src/bz-application.c:910 msgid "Performing setup…" msgstr "Kurulum gerçekleştiriliyor…" #: src/bz-application.c:994 msgid "Set Up System Flathub?" msgstr "Sistem Flathubʼı Kurulsun Mu?" #: src/bz-application.c:997 msgid "" "The system Flathub remote is not set up. Bazaar requires Flathub to be " "configured on the system Flatpak installation to browse and install " "applications.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub sistem uzağı kurulmamış. Bazaar, uygulamalara göz atmak ve kurmak " "için Flatpak kurulumunda Flathubʼın sistem geneli olarak yapılandırılmış " "olmasını gerektirir. \n" "\n" "Yine de Bazaarʼı kullanarak zaten kurulmuş uygulamalara göz atabilir ve " "kaldırabilirsiniz." #: src/bz-application.c:1004 msgid "Set Up Flathub?" msgstr "Flathub Kurulsun Mu?" #: src/bz-application.c:1007 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub bu sistemde kurulmamış. Bu sebeple Bazaar uygulamalara göz atamaz ve " "kuramaz.\n" "\n" "Yine de Bazaarʼı kullanarak zaten kurulmuş uygulamalara göz atabilir ve " "kaldırabilirsiniz." #: src/bz-application.c:1013 msgid "Later" msgstr "Sonra" #: src/bz-application.c:1014 msgid "Set Up Flathub" msgstr "Flathubʼı Kur" #: src/bz-application.c:1303 msgid "A backend error occurred" msgstr "Arka uç hatası oluştu" #: src/bz-application.c:1499 src/bz-application.c:3357 src/bz-window.blp:70 msgid "Refreshing…" msgstr "Yenileniyor…" #: src/bz-application.c:1651 src/bz-application.c:3355 #, c-format msgid "Loading %d apps…" msgstr "%d uygulama yükleniyor…" #: src/bz-application.c:1654 msgid "Checking for updates…" msgstr "Güncellemeler denetleniyor…" #: src/bz-application.c:1717 msgid "Failed to open .flatpakref" msgstr ".flatpakref dosyası açılamadı" #: src/bz-application.c:1773 msgid "An initialization error occurred" msgstr "İlklendirme hatası oluştu" #: src/bz-application.c:2123 msgid "Failed to check for updates" msgstr "Güncellemeler denetlenemedi" #: src/bz-application.c:3128 msgid "Could not find app" msgstr "Uygulama bulunamadı" #: src/bz-application.c:3359 msgid "Writing to cache…" msgstr "Ön belleğe yazılıyor…" #: src/bz-appstream-parser.c:302 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Flathub Sayfası" #: src/bz-appstream-parser.c:323 msgctxt "Project URL Type" msgid "Project Website" msgstr "Proje Web Sitesi" #: src/bz-appstream-parser.c:327 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Sorun İzleyici" #: src/bz-appstream-parser.c:331 msgctxt "Project URL Type" msgid "FAQ" msgstr "SSS" #: src/bz-appstream-parser.c:335 msgctxt "Project URL Type" msgid "Help" msgstr "Yardım" #: src/bz-appstream-parser.c:339 msgctxt "Project URL Type" msgid "Donate" msgstr "Bağış" #: src/bz-appstream-parser.c:345 msgctxt "Project URL Type" msgid "Translate" msgstr "Çevir" #: src/bz-appstream-parser.c:349 msgctxt "Project URL Type" msgid "Contact" msgstr "İletişim" #: src/bz-appstream-parser.c:353 msgctxt "Project URL Type" msgid "Source Code" msgstr "Kaynak Kodu" #: src/bz-appstream-parser.c:359 msgctxt "Project URL Type" msgid "Contribute" msgstr "Katkı Ver" #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:68 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:62 #: src/bz-library-page.blp:65 src/bz-user-data-page.blp:86 msgid "Empty" msgstr "Boş" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "Uygulama Seçkisi Yok" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "Bu sistemde uygulama seçkisi bilgisi sağlanmamaktadır. Flathubʼda " "uygulamalara yine de göz atabilirsiniz" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "Flathubʼa Göz At" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "Çevrim Dışı" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 #: src/bz-search-pill-list.c:67 msgid "Browser" msgstr "Tarayıcı" #: src/bz-developer-badge.c:94 src/bz-developer-badge.c:98 msgid "Not Verified" msgstr "Doğrulanmamış" #: src/bz-developer-badge.c:145 msgid "Developer information not available." msgstr "Geliştirici bilgisi yok." #: src/bz-developer-badge.c:151 src/bz-developer-badge.c:165 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "" "%s uygulama kimliğinin sahipliği doğrulanmadı ve topluluk paketlemesi " "olabilir." #: src/bz-developer-badge.c:169 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "" "%s uygulama kimliğinin sahipliği Flathub ekibi tarafından elle doğrulandı." #: src/bz-developer-badge.c:175 #, c-format msgid "" "The ownership of the %1$s app ID has been verified by %2$s on " "%3$s." msgstr "" "%1$s uygulama kimliğinin sahipliği %2$s tarafından %3$s " "sitesinden doğrulandı." #: src/bz-developer-badge.c:182 #, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "%1$s uygulama kimliğinin sahipliği %2$s kullanılarak doğrulandı." #: src/bz-developer-badge.c:186 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "%s uygulama kimliğinin sahipliği doğrulandı." #: src/bz-donations-dialog.blp:74 msgid "Full Release Notes" msgstr "Tam Sürüm Notları" #: src/bz-donations-dialog.blp:108 msgid "This release was made possible by users like you!" msgstr "Bu sürüm, sizin gibi kullanıcılar sayesinde mümkün oldu!" #: src/bz-donations-dialog.blp:116 msgid "" "I love making Bazaar, but I cannot do it alone. Help support further " "development by donating on Ko-Fi." msgstr "" "Bazaar uygulamasını geliştirmeyi çok seviyorum, yine de bunu tek başıma " "yapamam. Ko-Fi ile bağış yaparak geliştirilmesine destek olun." #: src/bz-donations-dialog.blp:131 msgid "Donate to Bazaar" msgstr "Bazaarʼa Bağış Yap" #. Translators: the %s format specifier will be something along the lines of "0.7.6" etc #: src/bz-donations-dialog.c:227 #, c-format msgid "What's New in %s?" msgstr "%s ile neler yeni?" #. Translators: this is a release date label, like "Released February 9, 2026" #: src/bz-donations-dialog.c:243 msgid "Released %B %-e, %Y" msgstr "Yayın tarihi: %-e %B %Y" #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "Kurulum Seç" #: src/bz-entry-group-util.c:76 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "" "Bu uygulamanın birden çok sürümü kurulu. Hangisiyle devam etmek istersiniz?" #: src/bz-entry-group-util.c:80 msgid "Cancel" msgstr "İptal" #: src/bz-entry-selection-row.blp:17 msgid "For This User Only" msgstr "Yalnızca Bu Kullanıcı İçin" #: src/bz-entry-selection-row.c:112 msgid "this user" msgstr "bu kullanıcı" #: src/bz-entry-selection-row.c:112 msgid "all users" msgstr "tüm kullanıcılar" #: src/bz-error.c:69 src/bz-error.c:88 src/bz-error-dialog.blp:36 #: src/bz-safety-dialog.blp:50 msgid "Details" msgstr "Ayrıntılar" #: src/bz-error-dialog.blp:47 msgid "Copy" msgstr "Kopyala" #: src/bz-error-dialog.c:56 src/bz-share-list.c:64 msgid "Copied!" msgstr "Kopyalandı!" #: src/bz-favorite-button.c:388 msgid "Failed to update favorite" msgstr "Gözde güncellenemedi" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "Gözdeleri yönetmek için Flathub ile oturum aç" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "Oturum Aç" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "Gözde Sayısı" #: src/bz-favorites-tile.c:157 src/bz-rich-app-tile.blp:172 msgid "Uninstall" msgstr "Kaldır" #: src/bz-favorites-tile.c:357 msgid "Failed to remove favorite" msgstr "Gözdelerden kaldırılamadı" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:78 msgid "Support This Application" msgstr "Bu Uygulamayı Destekle" #: src/bz-favorites-tile.blp:119 msgid "Remove From Favorites" msgstr "Gözdelerden Kaldır" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:78 #: src/bz-window.blp:386 msgid "Favorites" msgstr "Gözdeler" #: src/bz-favorites-page.blp:17 src/bz-section-view.blp:144 msgid "Install All" msgstr "Tümünü Kur" #: src/bz-favorites-page.blp:34 src/bz-full-view.blp:45 src/bz-window.blp:255 msgid "Open App Library" msgstr "Uygulama Kitaplığını Aç" #: src/bz-favorites-page.blp:56 src/bz-user-data-page.blp:75 msgid "Loading" msgstr "Yükleniyor" #: src/bz-favorites-page.blp:71 msgid "No Favorites" msgstr "Gözde Yok" #: src/bz-favorites-page.blp:72 msgid "Applications you mark as favorite will appear here" msgstr "Gözde olarak imlediğiniz uygulamalar burada görünecek" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "Önceki" #: src/bz-featured-carousel.blp:54 msgid "Next" msgstr "Sonraki" #: src/bz-featured-tile.blp:90 msgid "App of the Day" msgstr "Günün Uygulaması" #: src/bz-flathub-category.c:89 msgid "Editing" msgstr "Düzenleme" #: src/bz-flathub-category.c:90 msgid "Midi" msgstr "Midi" #: src/bz-flathub-category.c:91 msgid "Mixer" msgstr "Mixer" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-flathub-category.c:92 src/bz-search-pill-list.c:77 msgid "Music" msgstr "Müzik" #: src/bz-flathub-category.c:93 msgid "Player" msgstr "Oynatıcı" #: src/bz-flathub-category.c:94 msgid "Recorder" msgstr "Kaydedici" #: src/bz-flathub-category.c:95 msgid "Sequencer" msgstr "Ardışımlayıcı" #: src/bz-flathub-category.c:96 msgid "Tuner" msgstr "İnce Ayar" #: src/bz-flathub-category.c:97 msgid "TV" msgstr "TV" #: src/bz-flathub-category.c:102 msgid "Emulation" msgstr "Öykünme" #: src/bz-flathub-category.c:103 msgid "Action" msgstr "Aksiyon" #: src/bz-flathub-category.c:104 msgid "Adventure" msgstr "Macera" #: src/bz-flathub-category.c:105 msgid "Arcade" msgstr "Atari" #: src/bz-flathub-category.c:106 msgid "Blocks" msgstr "Bloklar" #: src/bz-flathub-category.c:107 msgid "Board" msgstr "Tahta" #: src/bz-flathub-category.c:108 msgid "Card" msgstr "Kart" #: src/bz-flathub-category.c:109 msgid "Kids" msgstr "Çocuk" #: src/bz-flathub-category.c:110 msgid "Logic" msgstr "Mantık" #: src/bz-flathub-category.c:111 msgid "Role Playing" msgstr "Rol Yapma" #: src/bz-flathub-category.c:112 msgid "Shooter" msgstr "Atış" #: src/bz-flathub-category.c:113 msgid "Simulation" msgstr "Simulasyon" #: src/bz-flathub-category.c:114 msgid "Sports" msgstr "Spor" #: src/bz-flathub-category.c:115 msgid "Strategy" msgstr "Strateji" #: src/bz-flathub-category.c:120 msgid "Audio & Video" msgstr "Ses ve Video" #: src/bz-flathub-category.c:120 msgid "Media" msgstr "Ortam" #: src/bz-flathub-category.c:120 msgid "More Audio & Video" msgstr "Ses ve Video" #: src/bz-flathub-category.c:121 msgid "Developer Tools" msgstr "Geliştirici Araçları" #: src/bz-flathub-category.c:121 msgid "Develop" msgstr "Geliştir" #: src/bz-flathub-category.c:121 msgid "More Developer Tools" msgstr "Daha Çok Geliştirici Araçları" #: src/bz-flathub-category.c:122 msgid "Education" msgstr "Eğitim" #: src/bz-flathub-category.c:122 msgid "Learn" msgstr "Öğren" #: src/bz-flathub-category.c:122 msgid "More Education" msgstr "Eğitim" #: src/bz-flathub-category.c:123 msgid "Gaming" msgstr "Oyun" # Oyun Oyna anlamında Oyna, Oynat değil! #: src/bz-flathub-category.c:123 msgid "Play" msgstr "Oyna" #: src/bz-flathub-category.c:123 msgid "More Gaming" msgstr "Daha Çok Oyun" #: src/bz-flathub-category.c:124 msgid "Graphics & Photography" msgstr "Grafikler ve Fotoğrafçılık" #: src/bz-flathub-category.c:124 msgid "Create" msgstr "Oluştur" #: src/bz-flathub-category.c:124 msgid "More Graphics & Photography" msgstr "Daha Çok Grafikler ve Fotoğrafçılık" #: src/bz-flathub-category.c:125 msgid "Networking" msgstr "Ağ" #: src/bz-flathub-category.c:125 msgid "Internet" msgstr "İnternet" #: src/bz-flathub-category.c:125 msgid "More Networking" msgstr "Ağ" #: src/bz-flathub-category.c:126 msgid "Productivity" msgstr "Verimlilik" #: src/bz-flathub-category.c:126 msgid "Work" msgstr "İş" #: src/bz-flathub-category.c:126 msgid "More Productivity" msgstr "Daha Çok Verimlilik" #: src/bz-flathub-category.c:127 msgid "Science" msgstr "Bilim" #: src/bz-flathub-category.c:127 msgid "More Science" msgstr "Bilim" #: src/bz-flathub-category.c:128 msgid "System" msgstr "Sistem" #: src/bz-flathub-category.c:128 msgid "More System" msgstr "Sistem" #: src/bz-flathub-category.c:129 msgid "Utilities" msgstr "Araçlar" #: src/bz-flathub-category.c:129 msgid "Tools" msgstr "Araçlar" #: src/bz-flathub-category.c:129 msgid "More Utilities" msgstr "Daha Çok Araçlar" #: src/bz-flathub-category.c:130 src/bz-flathub-page.blp:119 #: src/bz-flathub-page.blp:152 msgid "Trending" msgstr "Trend" #: src/bz-flathub-category.c:130 msgid "More Trending" msgstr "Daha Çok Trend" #: src/bz-flathub-category.c:131 src/bz-flathub-page.blp:125 #: src/bz-flathub-page.blp:182 msgid "Popular" msgstr "Popüler" #: src/bz-flathub-category.c:131 msgid "More Popular" msgstr "Daha Çok Popüler" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:172 msgid "Recently Added" msgstr "Son Eklenenler" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:131 msgid "New" msgstr "Yeni" #: src/bz-flathub-category.c:132 msgid "More New" msgstr "Daha Çok Yeni" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:162 msgid "Recently Updated" msgstr "Son Güncellenenler" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:137 msgid "Updated" msgstr "Güncellendi" #: src/bz-flathub-category.c:133 msgid "More Updated" msgstr "Daha Çok Güncellenenler" #: src/bz-flathub-category.c:134 msgid "Mobile" msgstr "Mobil" #: src/bz-flathub-category.c:134 msgid "More Mobile" msgstr "Daha Çok Mobil" #: src/bz-flathub-category.c:135 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:135 msgid "More Adwaita" msgstr "Daha Çok Adwaita" #: src/bz-flathub-category.c:136 msgid "KDE Apps" msgstr "KDE Uygulamaları" #: src/bz-flathub-category.c:136 msgid "More KDE Apps" msgstr "Daha Çok KDE Uygulaması" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Flathub Eklenmedi" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "Flatpak kurulumlarınızda Flathub uzağı bulunamadı" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "Flathub hata döndürdü" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "Flathub Bağlantısını Yeniden Dene" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Flathub Kullanılamıyor" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" "Flathubʼa bağlanamadık. Yine de uygulamaları yönetebilir ve arayabilirsiniz." #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "Uygulamaları Ara" #: src/bz-flathub-page.blp:263 msgid "On the Go" msgstr "Hareket Halindeyken" #: src/bz-flathub-page.blp:275 msgid "Apps for your Linux phones and tablets" msgstr "Linux telefonlarınız ve tabletleriniz için uygulamalar" #: src/bz-flathub-page.blp:286 src/bz-flathub-page.blp:321 msgid "More Mobile Apps" msgstr "Daha Çok Mobil Uygulama" #: src/bz-flathub-page.blp:379 msgid "We​ ♥​ Games" msgstr "Oyunları Severiz ♥​" #: src/bz-flathub-page.blp:392 msgid "Games and apps to run your favorite titles" msgstr "Sevdiğiniz oyunları çalıştırabileceğiniz oyunlar ve uygulamalar" #: src/bz-flathub-page.blp:426 msgid "More Games" msgstr "Daha Çok Oyun" #: src/bz-full-view.blp:66 src/bz-library-page.blp:76 #: src/bz-library-page.blp:80 msgid "No Results" msgstr "Sonuç Yok" #: src/bz-full-view.blp:67 msgid "Try a different search query" msgstr "Başka arama deneyin" #: src/bz-full-view.blp:73 msgid "Content" msgstr "İçerik" #: src/bz-full-view.blp:131 msgid "Installing .flatpak bundles is not yet supported" msgstr ".flatpak destelerinin kurulumu henüz desteklenmiyor" #: src/bz-full-view.blp:257 msgid "_Support" msgstr "_Destekle" #: src/bz-full-view.blp:426 msgid "Downloads/Month" msgstr "İndirme/Ay" #: src/bz-full-view.blp:461 msgid "Stopped Receiving Core Updates" msgstr "Çekirdek Güncellemelerinin Alınması Durduruldu" #: src/bz-full-view.blp:475 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "Bu uygulama, artık güncelleme ya da güvenlik düzeltmesi almayan bir çalışma " "zamanı kullanıyor. Kullanımı güvenli olmayabilir." #: src/bz-full-view.blp:562 msgid "Trash Data" msgstr "Çöp Verisi" #: src/bz-full-view.blp:702 msgid "Tags:" msgstr "Etiketler:" #: src/bz-full-view.c:215 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:222 #, c-format msgid "%.*fM" msgstr "%.*fM" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:229 #, c-format msgid "%.*fK" msgstr "%.*fK" #: src/bz-full-view.c:239 #, c-format msgid "%d downloads in the last month" msgstr "Son ay içinde %d indirme" #: src/bz-full-view.c:251 src/bz-full-view.c:592 src/bz-full-view.c:609 msgid "N/A" msgstr "Yok" #: src/bz-full-view.c:279 #, c-format msgid "+%s runtime" msgstr "+%s çalışma zamanı" #: src/bz-full-view.c:282 msgid "Download" msgstr "İndirme Boyutu" #: src/bz-full-view.c:302 msgid "Size information unavailable" msgstr "Boyut bilgisi yok" #: src/bz-full-view.c:305 #, c-format msgid "Download size of %s" msgstr "%s İndirme Boyutu" #: src/bz-full-view.c:338 msgid "All Ages" msgstr "Tüm Yaşlar" #: src/bz-full-view.c:350 msgid "Age rating information unavailable" msgstr "Yaş derecelendirme bilgisi yok" #: src/bz-full-view.c:355 msgid "Suitable for all ages" msgstr "Tüm yaşlar için uygun" #: src/bz-full-view.c:357 #, c-format msgid "Suitable for ages %d and up" msgstr "%d ve üstü yaşlar için uygun" #: src/bz-full-view.c:390 src/bz-full-view.c:395 src/bz-full-view.c:423 #: src/bz-full-view.c:431 msgid "Unknown" msgstr "Bilinmiyor" #: src/bz-full-view.c:400 #, c-format msgid "Free software licensed under %s" msgstr "%s altında lisanslanmış özgür yazılım" #: src/bz-full-view.c:405 msgid "Free software" msgstr "Özgür yazılım" #: src/bz-full-view.c:408 msgid "Proprietary Software" msgstr "Sahipli Yazılım" #: src/bz-full-view.c:411 #, c-format msgid "Special License: %s" msgstr "Özel Lisans: %s" #: src/bz-full-view.c:428 msgid "Free" msgstr "Özgür" #: src/bz-full-view.c:434 src/bz-license-dialog.c:132 msgid "Proprietary" msgstr "Sahipli" #: src/bz-full-view.c:436 src/bz-license-dialog.c:134 msgid "Special License" msgstr "Özel Lisans" #: src/bz-full-view.c:456 msgid "Adaptive" msgstr "Uyarlanır" # Arayüzde sığmadığı için new line eklendi #: src/bz-full-view.c:456 msgid "Desktop Only" msgstr "" "Yalnızca\n" "Masaüstü" #: src/bz-full-view.c:462 msgid "Works on desktop, tablets, and phones" msgstr "Telefonlarda, tabletlerde ve masaüstülerde çalışır" #: src/bz-full-view.c:463 msgid "May not work on mobile devices" msgstr "Mobil aygıtlarda çalışmayabilir" #: src/bz-full-view.c:474 msgid "No URL" msgstr "URL Yok" #: src/bz-full-view.c:492 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Bu uygulama FLOSS (Özgür ya da Açık Kaynak Yazılım) lisansına sahip, yani " "kaynak kodu güvenlik açısından denetlenebilir." #: src/bz-full-view.c:493 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Bu uygulama sahipli lisansa sahip, yani kaynak kodu özel olarak " "geliştirilmiştir ve bağımsız üçüncü tarafca denetlenemez." #: src/bz-full-view.c:500 msgid "More Apps" msgstr "Daha Çok Uygulama" #: src/bz-full-view.c:501 #, c-format msgid "More Apps by %s" msgstr "Daha Çok %s Uygulamaları" #: src/bz-full-view.c:508 msgid "Other Apps by this Developer" msgstr "Bu Geliştiricinin Diğer Uygulamaları" #: src/bz-full-view.c:510 src/bz-full-view.c:693 #, c-format msgid "Other Apps by %s" msgstr "Diğer %s Uygulamaları" #: src/bz-full-view.c:519 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "%s kurulmamış, ancak yine de %s verisi var." #: src/bz-full-view.c:599 src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "Güvenli" #: src/bz-full-view.c:601 src/bz-full-view.c:603 msgid "Low Risk" msgstr "Düşük Risk" #: src/bz-full-view.c:605 msgid "Medium Risk" msgstr "Orta Risk" #: src/bz-full-view.c:607 msgid "High Risk" msgstr "Yüksek Risk" #: src/bz-full-view.c:695 msgid "Other Apps" msgstr "Diğer Uygulamalar" #: src/bz-full-view.c:697 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d Uygulama" #: src/bz-full-view.c:941 msgid "Show Less" msgstr "Daha Az Göster" #: src/bz-full-view.c:941 msgid "Show More" msgstr "Daha Çok Göster" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 msgid "Hardware Support" msgstr "Donanım Desteği" #: src/bz-hardware-support-dialog.c:62 msgid "Keyboard support" msgstr "Klavye desteği" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "Klavye gerektirir" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "Klavye kullanımı önerilir" #: src/bz-hardware-support-dialog.c:66 msgid "Supports keyboards" msgstr "Klavyeleri destekler" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "Klavye desteği bilinmiyor" #: src/bz-hardware-support-dialog.c:69 msgid "Mouse support" msgstr "Fare desteği" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "Fare ya da işaretleme aygıtları gerektirir" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "Fare ya da işaretleme aygıtları önerilir" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "Fare ve işaretleme aygıtlarını destekler" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "Fare ya da işaretleme aygıtları desteği bilinmiyor" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "Dokunmatik ekran desteği" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "Dokunmatik ekran gerektirir" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "Dokunmatik ekran önerilir" #: src/bz-hardware-support-dialog.c:80 msgid "Supports touchscreens" msgstr "Dokunmatik ekranı destekler" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "Dokunmatik ekran desteği bilinmiyor" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "Mobil desteği" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "Mobil aygıtlarda çalışır" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "Mobil aygıtlarda iyi çalışmayabilir" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "Masaüstü desteği" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "Büyük ekranlarda iyi çalışır" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "%s belirli donanımlarda daha iyi çalışır" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "%s çoğu aygıtta çalışır" #: src/bz-install-controls.blp:33 msgid "Download & Install Application" msgstr "Uygulama İndir ve Kur" #: src/bz-install-controls.blp:35 src/bz-transaction-dialog.c:202 msgid "_Install" msgstr "_Kur" #: src/bz-install-controls.blp:61 msgid "_Open" msgstr "_Aç" #: src/bz-install-controls.blp:76 src/bz-install-controls.blp:132 msgid "Uninstall Application" msgstr "Uygulamayı Kaldır" #: src/bz-install-controls.blp:86 src/bz-transaction-dialog.c:231 msgid "_Remove" msgstr "_Kaldır" #: src/bz-install-controls.blp:119 src/bz-updates-card.blp:184 #: src/bz-updates-card.blp:212 msgid "Update" msgstr "Güncelle" #: src/bz-installed-tile.blp:64 src/bz-rich-app-tile.blp:140 msgid "Stopped Receiving Updates" msgstr "Güncellemelerin Alınması Durduruldu" #: src/bz-library-page.blp:31 msgid "Search installed apps" msgstr "Kurulu uygulamaları ara" #: src/bz-library-page.blp:48 msgid "Clear search" msgstr "Aramayı temizle" #: src/bz-library-page.blp:69 msgid "No Apps Found" msgstr "Uygulama Bulunamadı" #. Translators: . #: src/bz-library-page.blp:98 src/bz-window.blp:112 msgid "Library" msgstr "Kitaplık" #: src/bz-library-page.blp:126 msgid "Pending Updates" msgstr "Güncellemeler Bekliyor" #: src/bz-library-page.blp:153 msgid "Downloads" msgstr "İndirmeler" #: src/bz-library-page.blp:196 msgid "Recently Uninstalled" msgstr "Son Kaldırılanlar" #: src/bz-library-page.blp:247 msgid "Clear Finished Tasks" msgstr "Tamamlanan Görevleri Temizle" #: src/bz-library-page.blp:260 msgid "Installed Apps" msgstr "Kurulu Uygulamalar" #: src/bz-library-page.blp:333 msgid "Sort By" msgstr "Sırala" #: src/bz-library-page.blp:347 msgid "Name" msgstr "Ad" #: src/bz-library-page.blp:353 msgid "Size" msgstr "Boyut" #: src/bz-library-page.c:180 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "Kurulu uygulamalar listesinde \"%s\" ile eşleşen hiçbir öge bulunamadı" #: src/bz-library-page.c:193 src/bz-updates-card.c:257 #, c-format msgid "%u Available Update" msgid_plural "%u Available Updates" msgstr[0] "%u Güncelleme Var" #: src/bz-license-dialog.blp:95 msgid "Get Involved" msgstr "Katılım Sağlayın" #: src/bz-license-dialog.c:126 msgid "Unknown License" msgstr "Bilinmeyen Lisans" #: src/bz-license-dialog.c:129 msgid "Community Built" msgstr "Topluluk İnşası" #: src/bz-license-dialog.c:202 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Bu uygulama, uluslararası bir topluluk tarafından açık şekilde " "geliştirilmiştir. \n" "\n" "Katılarak daha iyi olmasını sağlayabilirsiniz." #: src/bz-license-dialog.c:205 msgid "The license of this app is not known" msgstr "Uygulamanın lisansı bilinmiyor" #: src/bz-license-dialog.c:211 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Bu uygulama, uluslararası bir topluluk tarafından açık şekilde geliştirilmiş " "ve %s lisansıyla dağıtılmıştır.\n" "\n" "Katılarak daha iyi olmasını sağlayabilirsiniz." #: src/bz-license-dialog.c:219 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Bu uygulama açık olarak geliştirilmemiştir, nasıl çalıştığını yalnızca kendi " "geliştiricileri bilir. Saptanması zor biçimde güvensiz olabilir ve " "gözetimsizce değişebilir.\n" "\n" "Bu uygulamaya katkıda bulunabilir ya da bulunamayabilirsiniz." #: src/bz-license-dialog.c:225 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Bu uygulama özel “%s” lisansı altında geliştirilmiştir.\n" "\n" "Bu uygulamaya katkıda bulunabilir ya da bulunamayabilirsiniz." #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 msgid "Connect to Flathub" msgstr "Flathubʼa Bağlan" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "Bir Şeyler Yanlış Gitti" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "Flathub hesabınızı Bazaarʼa bağlayarak gözde uygulamalarınızı yönetin." #: src/bz-login-page.blp:110 msgid "Finish" msgstr "Bitti" #: src/bz-login-page.c:664 #, c-format msgid "Hello, %s!" msgstr "Merhaba, %s!" #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Tercihler" #: src/bz-preferences-dialog.blp:25 msgid "Network connection is metered — automatic store data refresh is paused" msgstr "" "Ağ bağlantısı ölçülü — kendiliğinden mağaza verilerinin yenilenmesi " "duraklatıldı" #: src/bz-preferences-dialog.blp:26 src/bz-window.blp:282 msgid "Refresh Manually" msgstr "Elle Yenile" #: src/bz-preferences-dialog.blp:31 msgid "Content Filters" msgstr "İçerik Süzgeçleri" #: src/bz-preferences-dialog.blp:34 msgid "Free Software Only" msgstr "Yalnızca Özgür Yazılımlar" #: src/bz-preferences-dialog.blp:35 msgid "Hide proprietary applications when browsing and searching" msgstr "Göz atarken ve arama yaparken sahipli uygulamaları gizle" #: src/bz-preferences-dialog.blp:39 msgid "Flathub Results Only" msgstr "Yalnızca Flathub Sonuçları" #: src/bz-preferences-dialog.blp:40 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "" "Arama ve gözatma sonuçlarını yalnızca Flathubʼda bulunan uygulamalarla " "sınırla" #: src/bz-preferences-dialog.blp:44 msgid "Verified Results Only" msgstr "Yalnızca Doğrulanmış Sonuçlar" #: src/bz-preferences-dialog.blp:45 msgid "Hide results that are not verified on Flathub" msgstr "Flathubʼda doğrulanmamış sonuçları gizle" #: src/bz-preferences-dialog.blp:49 msgid "Hide EOL Apps" msgstr "Ömrünün Sonuna Gelmiş Uygulamaları Gizle" #: src/bz-preferences-dialog.blp:50 msgid "Hide apps which are no longer supported by their developers" msgstr "Geliştiricilerince artık desteklenmeyen uygulamaları gizle" #: src/bz-preferences-dialog.blp:55 src/bz-window.blp:127 msgid "Search" msgstr "Ara" #: src/bz-preferences-dialog.blp:58 msgid "Delay Search Results" msgstr "Arama Sonuçlarını Geciktir" #: src/bz-preferences-dialog.blp:59 msgid "Improve results performance by debouncing search terms" msgstr "Arama terimlerini geciktirerek sonuç başarımını iyileştir" #: src/bz-preferences-dialog.blp:64 msgid "Progress Bar" msgstr "İlerleme Çubuğu" #: src/bz-preferences-dialog.blp:65 msgid "Choose a theme for the progress bar!" msgstr "İlerleme çubuğu için tema seç!" #: src/bz-preferences-dialog.blp:89 msgid "Vertical Stripes" msgstr "Dikey Çizgiler" #: src/bz-preferences-dialog.blp:90 msgid "Display flag colors from left to right" msgstr "Bayrak renklerini soldan sağa görüntüle" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Vurgu Rengi" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Pride Colors" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "Lesbian Pride Colors" #: src/bz-preferences-dialog.c:35 msgid "Male Homosexual Pride Colors" msgstr "Male Homosexual Pride Colors" #: src/bz-preferences-dialog.c:36 msgid "Transgender Pride Colors" msgstr "Transgender Pride Colors" #: src/bz-preferences-dialog.c:37 msgid "Nonbinary Pride Colors" msgstr "Nonbinary Pride Colors" #: src/bz-preferences-dialog.c:38 msgid "Bisexual Pride Colors" msgstr "Bisexual Pride Colors" #: src/bz-preferences-dialog.c:39 msgid "Asexual Pride Colors" msgstr "Asexual Pride Colors" #: src/bz-preferences-dialog.c:40 msgid "Pansexual Pride Colors" msgstr "Pansexual Pride Colors" #: src/bz-preferences-dialog.c:41 msgid "Aromantic Pride Colors" msgstr "Aromantic Pride Colors" #: src/bz-preferences-dialog.c:42 msgid "Genderfluid Pride Colors" msgstr "Genderfluid Pride Colors" #: src/bz-preferences-dialog.c:43 msgid "Polysexual Pride Colors" msgstr "Polysexual Pride Colors" #: src/bz-preferences-dialog.c:44 msgid "Omnisexual Pride Colors" msgstr "Omnisexual Pride Colors" #: src/bz-preferences-dialog.c:45 msgid "Aroace Pride Colors" msgstr "Aroace Pride Colors" #: src/bz-preferences-dialog.c:46 msgid "Agender Pride Colors" msgstr "Agender Pride Colors" #: src/bz-preferences-dialog.c:47 msgid "Genderqueer Pride Colors" msgstr "Genderqueer Pride Colors" #: src/bz-preferences-dialog.c:48 msgid "Intersex Pride Colors" msgstr "Intersex Pride Colors" #: src/bz-preferences-dialog.c:49 msgid "Demigender Pride Colors" msgstr "Demigender Pride Colors" #: src/bz-preferences-dialog.c:50 msgid "Biromantic Pride Colors" msgstr "Biromantic Pride Colors" #: src/bz-preferences-dialog.c:51 msgid "Disability Pride Colors" msgstr "Disability Pride Colors" #: src/bz-preferences-dialog.c:52 msgid "Femboy Pride Colors" msgstr "Femboy Pride Colors" #: src/bz-preferences-dialog.c:53 msgid "Neutrois Pride Colors" msgstr "Neutrois Pride Colors" #: src/bz-releases-dialog.blp:5 src/bz-updates-card.blp:171 msgid "Version History" msgstr "Sürüm Geçmişi" #: src/bz-releases-list.blp:27 msgid "_Version History" msgstr "_Sürüm Geçmişi" #. Translators: something happened less than a day ago #: src/bz-releases-list.c:122 msgid "Today" msgstr "Bugün" #. Translators: something happened more than a day ago but less than 2 days ago #: src/bz-releases-list.c:125 msgid "Yesterday" msgstr "Dün" #. Translators: something happened days ago #: src/bz-releases-list.c:128 #, c-format msgid "%d day ago" msgid_plural "%d days ago" msgstr[0] "%d gün önce" #. Translators: something happened weeks ago #: src/bz-releases-list.c:131 #, c-format msgid "%d week ago" msgid_plural "%d weeks ago" msgstr[0] "%d hafta önce" #. Translators: something happened months ago #: src/bz-releases-list.c:134 #, c-format msgid "%d month ago" msgid_plural "%d months ago" msgstr[0] "%d ay önce" #. Translators: something happened years ago #: src/bz-releases-list.c:137 #, c-format msgid "%d year ago" msgid_plural "%d years ago" msgstr[0] "%d yıl önce" #. TRANSLATORS: This is the date string with: day number, month name, year. #. i.e. "22 March 2026" #: src/bz-releases-list.c:155 msgid "%e %B %Y" msgstr "%e %B %Y" #: src/bz-releases-list.c:195 #, c-format msgid "Version %s" msgstr "Sürüm %s" #: src/bz-releases-list.c:250 msgid "No details for this release" msgstr "Bu sürüm için ayrıntı yok" #: src/bz-releases-list.c:262 msgid "Get More Information" msgstr "Daha Çok Bilgi" #: src/bz-rich-app-tile.blp:157 msgid "Get" msgstr "Al" #: src/bz-rich-app-tile.blp:185 src/bz-transaction-tile.blp:272 msgid "Open" msgstr "Aç" #: src/bz-safety-calculator.c:82 msgid "Unknown Permissions" msgstr "Bilinmeyen İzinler" #: src/bz-safety-calculator.c:83 msgid "Permissions are missing for this app." msgstr "Bu uygulama için izinler eksik." #: src/bz-safety-calculator.c:96 msgid "No Permissions" msgstr "İzin Yok" #: src/bz-safety-calculator.c:97 msgid "App is fully sandboxed" msgstr "Uygulama tümüyle yalıtılmış alandadır" #: src/bz-safety-calculator.c:103 msgid "Network Access" msgstr "Ağ Erişimi" #: src/bz-safety-calculator.c:104 msgid "Can access the internet" msgstr "İnternete erişebilir" #: src/bz-safety-calculator.c:106 msgid "No Network Access" msgstr "Ağ Erişimi Yok" #: src/bz-safety-calculator.c:107 msgid "Cannot access the internet" msgstr "İnternete erişemez" #: src/bz-safety-calculator.c:112 msgid "User Device Access" msgstr "Kullanıcı Aygıtı Erişimi" #: src/bz-safety-calculator.c:113 msgid "Can access devices such as webcams or gaming controllers" msgstr "Web kameraları veya oyun denetçileri gibi aygıtlara erişebilir" #: src/bz-safety-calculator.c:115 msgid "No User Device Access" msgstr "Kullanıcı Aygıtı Erişimi Yok" #: src/bz-safety-calculator.c:116 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "Web kameraları veya oyun denetçileri gibi aygıtlara erişemez" #: src/bz-safety-calculator.c:121 msgid "Input Device Access" msgstr "Girdi Aygıtı Erişimi" #: src/bz-safety-calculator.c:122 msgid "Can access input devices" msgstr "Girdi aygıtlarına erişebilir" #: src/bz-safety-calculator.c:128 msgid "Microphone Access and Audio Playback" msgstr "Mikrofon Erişimi ve Ses Oynatımı" #: src/bz-safety-calculator.c:129 msgid "Can listen using microphones and play audio without asking permission" msgstr "İzin istemeden mikrofonlarla dinleyebilir ve sesleri oynatabilir" #: src/bz-safety-calculator.c:135 msgid "System Device Access" msgstr "Sistem Aygıtı Erişimi" #: src/bz-safety-calculator.c:136 msgid "Can access system devices which require elevated permissions" msgstr "Yükseltilmiş izinler gerektiren sistem aygıtlarına erişebilir" #: src/bz-safety-calculator.c:142 msgid "Screen Contents Access" msgstr "Ekran İçerikleri Erişimi" #: src/bz-safety-calculator.c:143 msgid "Can access the contents of the screen or other windows" msgstr "Ekranın ya da diğer pencerelerin içeriklerine erişebilir" #: src/bz-safety-calculator.c:149 msgid "Legacy Windowing System" msgstr "Eski Pencereleme Sistemi" #: src/bz-safety-calculator.c:150 msgid "Always uses a legacy windowing system (X11)" msgstr "Daima eski pencereleme sistemi kullanır (X11)" #: src/bz-safety-calculator.c:156 msgid "Arbitrary Permissions" msgstr "İsteğe Bağlı İzinler" #: src/bz-safety-calculator.c:157 msgid "Can acquire arbitrary permissions" msgstr "İsteğe bağlı izinler edinir" #: src/bz-safety-calculator.c:163 msgid "User Settings" msgstr "Kullanıcı Ayarları" #: src/bz-safety-calculator.c:164 msgid "Can access and change user settings" msgstr "Kullanıcı ayarlarına erişebilir ve değiştirebilir" #: src/bz-safety-calculator.c:170 msgid "Full File System Read/Write Access" msgstr "Tüm Dosya Sistemini Okuma/Yazma Erişimi" #: src/bz-safety-calculator.c:171 msgid "Can read and write all data on the file system" msgstr "Dosya sistemindeki tüm veriyi okuyabilir ve yazabilir" #: src/bz-safety-calculator.c:178 msgid "Home Folder Read/Write Access" msgstr "Ev Klasörü Okuma/Yazma Erişimi" #: src/bz-safety-calculator.c:179 msgid "Can read and write all data in your home directory" msgstr "Ev dizininizdeki tüm veriyi okuyabilir ve yazabilir" #: src/bz-safety-calculator.c:186 msgid "Full File System Read Access" msgstr "Tüm Dosya Sistemini Okuma Erişimi" #: src/bz-safety-calculator.c:187 msgid "Can read all data on the file system" msgstr "Dosya sistemindeki tüm veriyi okuyabilir" #: src/bz-safety-calculator.c:195 msgid "Home Folder Read Access" msgstr "Ev Klasörü Okuma Erişimi" #: src/bz-safety-calculator.c:196 msgid "Can read all data in your home directory" msgstr "Ev dizininizdeki tüm verinizi okuyabilir" #: src/bz-safety-calculator.c:204 msgid "Download Folder Read/Write Access" msgstr "İndirilenler Klasörü Okuma/Yazma Erişimi" #: src/bz-safety-calculator.c:205 msgid "Can read and write all data in your downloads directory" msgstr "İndirilenler dizininizdeki tüm veriyi okuyabilir ve yazabilir" #: src/bz-safety-calculator.c:215 msgid "Download Folder Read Access" msgstr "İndirilenler Klasörü Okuma Erişimi" #: src/bz-safety-calculator.c:216 msgid "Can read all data in your downloads directory" msgstr "İndirilenler dizininizdeki tüm veriyi okuyabilir" #: src/bz-safety-calculator.c:229 msgid "Can read and write all data in the directory" msgstr "Dizindeki tüm veriyi okuyabilir ve yazabilir" #: src/bz-safety-calculator.c:243 msgid "Can read all data in the directory" msgstr "Dizindeki tüm veriyi okuyabilir" #: src/bz-safety-calculator.c:258 msgid "No File System Access" msgstr "Dosya Sistemi Erişimi Yok" #: src/bz-safety-calculator.c:259 msgid "Cannot access the file system at all" msgstr "Dosya sistemine asla erişemez" #: src/bz-safety-calculator.c:266 msgid "Uses System Services" msgstr "Sistem Hizmetlerini Kullanır" #: src/bz-safety-calculator.c:267 msgid "Can request data from non-portal system services" msgstr "Kapı dışı sistem hizmetlerinden veri isteyebilir" #: src/bz-safety-calculator.c:273 msgid "Uses Session Services" msgstr "Oturum Hizmetlerini Kullanır" #: src/bz-safety-calculator.c:274 msgid "Can request data from non-portal session services" msgstr "Kapı dışı oturum hizmetlerinden veri isteyebilir" #: src/bz-safety-calculator.c:322 msgid "No Service Access" msgstr "Hizmet Erişimi Yok" #: src/bz-safety-calculator.c:323 msgid "Cannot access non-portal session or system services at all" msgstr "Kapı dışı oturum ya da sistem hizmetlerine asla erişemez" #: src/bz-safety-calculator.c:331 msgid "Verified App Developer" msgstr "Doğrulanmış Uygulama Geliştiricileri" #: src/bz-safety-calculator.c:332 msgid "The developer of this app has been verified to be who they say they are" msgstr "Bu uygulamanın geliştiricisinin söylediği kişi olduğu doğrulandı" #: src/bz-safety-calculator.c:341 msgid "Proprietary Code" msgstr "Sahipli Kod" #: src/bz-safety-calculator.c:342 msgid "" "The source code is not public, so it cannot be independently audited and " "might be unsafe" msgstr "" "Kaynak kod halka açık değildir, bu nedenle bağımsızca denetlenemez ve " "güvenilir olmayabilir" #: src/bz-safety-calculator.c:352 msgid "Auditable Code" msgstr "Denetlenebilir Kod" #: src/bz-safety-calculator.c:353 msgid "" "The source code is public and can be independently audited, which makes the " "app more likely to be safe" msgstr "" "Kaynak kod halka açıktır ve bağımsızca denetlenebilir, bu uygulamayı daha " "güvenilir kılar" #: src/bz-safety-calculator.c:493 #, c-format msgid "Use the %s System Service" msgstr "%s Sistem Hizmetini Kullan" #: src/bz-safety-calculator.c:497 #, c-format msgid "Use the %s Session Service" msgstr "%s Oturum Hizmetini Kullan" #: src/bz-safety-calculator.c:501 #, c-format msgid "Use the %s Service" msgstr "%s Hizmetini Kullan" #: src/bz-safety-calculator.c:511 msgid "Can see the non-portal service" msgstr "Kapı dışı hizmetleri görebilir" #: src/bz-safety-calculator.c:513 msgid "Can talk to the non-portal service" msgstr "Kapı dışı hizmetlere konuşabilir" #: src/bz-safety-calculator.c:515 msgid "Can own the non-portal service" msgstr "Kapı dışı hizmet edinebilir" #: src/bz-safety-calculator.c:530 msgid "Global Menu Integration" msgstr "Küresel Menü Tümleşimi" #: src/bz-safety-calculator.c:531 msgid "Can display its menus in a global menu bar" msgstr "Menülerini genel menü çubuğunda görüntüleyebilir" #: src/bz-safety-calculator.c:536 msgid "KDE Settings Integration" msgstr "KDE Ayarları Tümleşimi" #: src/bz-safety-calculator.c:537 msgid "Can detect when KDE desktop settings change" msgstr "KDE masaüstü ayarları değiştiğinde algılayabilir" #: src/bz-safety-calculator.c:542 msgid "KDE Global Settings" msgstr "KDE Genel Ayarlar" #: src/bz-safety-calculator.c:543 msgid "Can read KDE desktop preferences like fonts and colors" msgstr "KDE masaüstü tercihlerini (yazı tipleri ve renkler gibi) okuyabilir" #: src/bz-safety-calculator.c:548 msgid "Secret Storage Service" msgstr "Gizli Depolama Hizmeti" #: src/bz-safety-calculator.c:549 msgid "Can store and retrieve its own passwords using the system keyring" msgstr "" "Sistem anahtarlığı kullanarak kendi parolalarını saklayabilir ve geri " "getirebilir" #: src/bz-safety-calculator.c:554 msgid "Desktop Notifications Service" msgstr "Masaüstü Bildirim Hizmeti" #: src/bz-safety-calculator.c:555 msgid "Can send desktop notifications" msgstr "Masaüstü bildirimleri gönderebilir" #: src/bz-safety-calculator.c:561 msgid "System Tray Integration" msgstr "Sistem Tepsisi Tümleşimi" #: src/bz-safety-calculator.c:562 msgid "Can display an icon in the system tray" msgstr "Sistem tepsisinde simge gösterebilir" #: src/bz-safety-calculator.c:567 msgid "KDE Connect Integration" msgstr "KDE Connect Tümleşimi" #: src/bz-safety-calculator.c:568 msgid "Can interact with devices paired via KDE Connect" msgstr "KDE Connect aracılığıyla eşleştirilen aygıtlarla etkileşime girebilir" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "Güvenlik" #: src/bz-safety-dialog.blp:53 msgid "License" msgstr "Lisans" #: src/bz-safety-dialog.blp:63 msgid "App ID" msgstr "Uygulama Kimliği" #: src/bz-safety-dialog.blp:73 msgid "SDK" msgstr "SDK" # SDK vurgusu hatalı. Yazılımları genelde Platform ile paketleniyor, SDK ise derlenirken kullanılıyor. #: src/bz-safety-dialog.blp:104 msgid "" "This app uses an outdated version of the software platform (SDK) and might " "contain bugs or security vulnerabilities which will not be fixed." msgstr "" "Bu uygulama, çalışma ortamının eski sürümünü kullanıyor ve düzeltilmeyecek " "hatalar ya da güvenlik açıkları içerebilir." #: src/bz-safety-dialog.c:227 #, c-format msgid "%s is Safe" msgstr "%s Güvenilir" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s has no Unsafe Permissions" msgstr "%s Güvenli Olmayan İzinleri Yok" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Probably Safe" msgstr "%s Muhtemelen Güvenli" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Possibly Unsafe" msgstr "%s Güvenilir Olmayabilir" #: src/bz-safety-dialog.c:247 #, c-format msgid "%s is Unsafe" msgstr "%s Güvenilir Değil" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "Ekran Görüntüleri" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "Önceki Ekran Görüntüsü" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "Sonraki Ekran Görüntüsü" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "Resmi Kopyala" #: src/bz-screenshot-page.blp:147 msgid "Reset View" msgstr "Görünümü Sıfırla" #: src/bz-screenshot-page.blp:158 msgid "Zoom Out" msgstr "Uzaklaştır" #: src/bz-screenshot-page.blp:168 msgid "Zoom In" msgstr "Yakınlaştır" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "Ekran Görüntüsü Sergisi" #: src/bz-screenshots-carousel.blp:117 msgid "Open Screenshot Viewer" msgstr "Ekran Görüntüsü Görüntüleyiciyi Aç" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:72 msgid "Video" msgstr "Video" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:82 msgid "Office" msgstr "Ofis" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:87 msgid "PDF" msgstr "PDF" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:92 msgid "Calendar" msgstr "Takvim" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:97 msgid "Messaging" msgstr "İletişim" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:102 msgid "Steam" msgstr "Steam" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:107 msgid "Paint" msgstr "Boyama" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:112 msgid "VPN" msgstr "VPN" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:117 msgid "Torrent" msgstr "Torrent" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:122 msgid "Minecraft" msgstr "Minecraft" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:127 msgid "Emulator" msgstr "Öykünücü" #: src/bz-search-page.blp:57 msgid "Search Apps, Games, Software" msgstr "Uygulamaları, Oyunları, Yazılımları Ara" #: src/bz-search-page.blp:79 msgid "Clear Search" msgstr "Aramayı Temizle" #: src/bz-search-page.blp:171 msgid "Categories Unavailable" msgstr "Kategoriler Kullanılamıyor" #: src/bz-search-page.blp:172 msgid "Search for apps using the search bar above." msgstr "Yukarıdaki arama çubuğunu kullanarak uygulamaları ara." #: src/bz-search-page.blp:198 msgid "Browse Categories" msgstr "Kategorilere Göz At" #: src/bz-search-page.blp:340 msgid "No Applications Found" msgstr "Uygulama Bulunamadı." #: src/bz-search-page.c:244 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "Flathubʼda \"%s\" için sonuç bulunamadı" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "Bağlantıyı Kopyala" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Bağlantıyı Aç" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "Zaman çizgisi" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "Kurulumlar:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "Dünya" #: src/bz-stats-dialog.blp:69 msgid "Since 4/15/2024" msgstr "15 Nisan 2024 tarihinden beri" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:124 #, c-format msgid "%.2fM Total Installs" msgstr "%.2fM Toplam Kurulum" #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:127 #, c-format msgid "%.2fK Total Installs" msgstr "%.2fK Toplam Kurulum" #: src/bz-stats-dialog.c:129 #, c-format msgid "%'d Total Installs" msgstr "%'d Toplam Kurulum" #: src/bz-tag-list.c:78 msgid "No Results Found" msgstr "Hiçbir Sonuç Bulunamadı" #: src/bz-tag-list.c:90 #, c-format msgid "Apps Tagged \"%s\"" msgstr "\"%s\" Etiketli Uygulamalar" #: src/bz-tag-list.c:103 msgid "Search failed" msgstr "Arama başarısız" #: src/bz-transaction-dialog.c:155 msgid "Keep User Data" msgstr "Kullanıcı Verisini Tut" #: src/bz-transaction-dialog.c:156 msgid "Allow restoring personal settings & content" msgstr "Kişisel ayarların ve içeriğin geri yüklenmesine izin ver" #: src/bz-transaction-dialog.c:165 msgid "Delete All Data" msgstr "Tüm Verileri Sil" #: src/bz-transaction-dialog.c:166 msgid "Permanently erase user data to save space" msgstr "Disk alanını korumak için kullanıcı verisini sil" #: src/bz-transaction-dialog.c:191 #, c-format msgid "Install %s?" msgstr "%s Kurulsun Mu?" #: src/bz-transaction-dialog.c:196 msgid "" "Select which version to install. May install additional shared components" msgstr "Hangi sürümün kurulacağını seç. Ek paylaşımlı bileşenler kurabilir" #: src/bz-transaction-dialog.c:198 msgid "May install additional shared components" msgstr "Ek paylaşımlı bileşenler kurabilir" #: src/bz-transaction-dialog.c:201 src/bz-transaction-dialog.c:230 #: src/bz-transaction-dialog.c:275 src/bz-transaction-dialog.c:578 msgid "_Cancel" msgstr "İ_ptal" #: src/bz-transaction-dialog.c:219 #, c-format msgid "Remove %s?" msgstr "%s Kaldırılsın Mı?" #: src/bz-transaction-dialog.c:222 msgid "Select which version to remove." msgstr "Hangi sürümün kaldırılacağını seç." #: src/bz-transaction-dialog.c:224 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "Kaldırıldıktan sonra %s artık kullanılamayacak." #: src/bz-transaction-dialog.c:247 #, c-format msgid "“%s” is High Risk" msgstr "“%s” Çok Riskli" #: src/bz-transaction-dialog.c:251 msgid "" "This app has full access to your system, including all your files, " "browser history, saved passwords, and more. It also has access to the " "internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Bu uygulama, tüm dosyalarınız, tarayıcı geçmişiniz, kaydedilmiş " "parolalarınız ve daha fazlası üzerinde sisteminize tam erişimi var. " "Ayrıca internete de erişebilir, yani verilerinizi dış taraflara " "gönderebilir.\n" "\n" "Uygulama sahipli olduğundan, bu izinlerle ne yaptığı denetlenemez." #: src/bz-transaction-dialog.c:260 msgid "" "This app uses the legacy X11 windowing system, which allows it to record " "all keystrokes, capture screenshots, and monitor other applications. It " "also has access to the internet, meaning it could send your data to outside " "parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Bu uygulama, tüm tuş darbelerini kaydetmeye, ekran görüntülerini " "yakalamaya ve diğer uygulamaları izlemeye izin veren eski X11 pencere " "sistemini kullanır. Ayrıca internete erişimi var, yani verilerinizi dış " "taraflara gönderebilir.\n" "\n" "Uygulama sahipli olduğundan, bu izinlerle ne yaptığı denetlenemez." #: src/bz-transaction-dialog.c:276 msgid "_Install Anyway" msgstr "Yine De _Kur" #: src/bz-transaction-dialog.c:331 msgid "Failed to load transaction dialog" msgstr "İşlem iletişim kutusu yüklenemedi" #: src/bz-transaction-dialog.c:549 msgid "All apps are already installed" msgstr "Tüm uygulamalar zaten kurulmuş" #: src/bz-transaction-dialog.c:551 msgid "_OK" msgstr "_Tamam" #: src/bz-transaction-dialog.c:567 #, c-format msgid "Install %u App?" msgid_plural "Install %u Apps?" msgstr[0] "%u Uygulama Kurulsun Mu?" #: src/bz-transaction-dialog.c:575 msgid "" "The following will be installed. Additional shared components may also be " "installed" msgstr "Aşağıdakiler yüklenecek. Ek ortak bileşenler de kurulabilir" #: src/bz-transaction-dialog.c:576 #, c-format msgid "%d addons will be installed." msgstr "%d eklenti kurulacak." #: src/bz-transaction-dialog.c:577 msgid "Additionally, addons will be installed." msgstr "Ayrıca, uzantılar kurulacak." #: src/bz-transaction-dialog.c:579 msgid "_Install All" msgstr "Tümünü _Kur" #: src/bz-transaction-manager.c:766 #, c-format msgid "Finished in %.02f seconds" msgstr "%.02f saniyede bitti" #: src/bz-transaction-tile.blp:129 msgid "App Add-On" msgstr "Uygulama Eklentisi" #: src/bz-transaction-tile.blp:158 msgid "Runtime" msgstr "Çalışma Zamanı" #: src/bz-transaction-tile.blp:182 msgid "In Queue" msgstr "Kuyrukta" #: src/bz-transaction-tile.blp:206 msgid "Done" msgstr "Bitti" #: src/bz-transaction-tile.blp:230 msgid "Error" msgstr "Hata" #: src/bz-transaction-tile.blp:286 msgid "Cancel Transaction" msgstr "İşlemi İptal Et" #: src/bz-transaction-tile.blp:410 msgid "Show Error Info" msgstr "Hata Bilgisini Göster" #: src/bz-transaction-tile.c:107 #, c-format msgid "%s Freed" msgstr "%s Temizlendi" # Transaction dese de para ile ilgisi yok. O sebeple sadece İşlemler diye çevirdim. #: src/bz-transaction-tile.c:362 src/bz-transaction-tile.c:365 msgid "Transaction Error" msgstr "İşlem Hatası" #: src/bz-transaction.c:342 msgid "Pending" msgstr "Beklemede" #: src/bz-updates-card.blp:40 msgid "_Update All" msgstr "Tümünü _Güncelle" #: src/bz-updates-card.c:293 #, c-format msgid "%u Runtime Update" msgid_plural "%u Runtime Updates" msgstr[0] "%u Çalışma Zamanı Güncellemesi" #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "Artık Kullanıcı Verisini Yönet" #: src/bz-user-data-page.blp:89 msgid "No User Data Found" msgstr "Kullanıcı Verisi bulunamadı" #: src/bz-user-data-page.blp:94 msgid "User Data" msgstr "Kullanıcı Verisi" #: src/bz-user-data-tile.c:144 #, c-format msgid "Trashed User Data for %s" msgstr "%s İçin Kullanıcı Verisi Çöpe Taşındı" #: src/bz-user-data-tile.blp:74 msgid "Trash User Data" msgstr "Kullanıcı Verisini Çöpe Taşı" #: src/bz-window.blp:88 msgid "Curated" msgstr "Özelleştirilmiş" #: src/bz-window.blp:100 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:220 msgid "Refresh completed!" msgstr "Yenileme tamamlandı!" #: src/bz-window.blp:273 msgid "You are running a new version of Bazaar!" msgstr "Bazaarʼın yeni bir sürümünü kullanıyorsunuz!" #: src/bz-window.blp:274 msgid "See What's New" msgstr "Neler Yeni Gör" #: src/bz-window.blp:281 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "" "Ağ bağlantınız var ancak Flathubʼın önbelleklenmiş sürümünü görüntülüyorsunuz" #: src/bz-window.blp:393 msgid "Log Out" msgstr "Oturumu Kapat" #. Translators: %s is the title of the current page #: src/bz-window.c:380 #, c-format msgid "Bazaar — %s" msgstr "Bazaar — %s" #: src/bz-window.c:487 msgid "Failed to load add-ons" msgstr "Eklentiler yüklenemedi" #: src/bz-window.c:601 src/bz-window.c:618 msgid "Failed to launch application" msgstr "Uygulama başlatılamadı" #: src/bz-window.c:823 msgid "You can't remove Bazaar from Bazaar!" msgstr "Bazaarʼı Bazaar ile kaldıramazsınız!" #: src/bz-window.c:1108 src/bz-window.c:1142 msgid "Can't do that right now!" msgstr "Şimdi yapma!" #: src/bz-world-map.c:595 msgctxt "As in, \"100 Downloads\"" msgid "Downloads" msgstr "İndirme" #: src/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Genel" #: src/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Page" msgstr "Arama Sayfasını Aç" #: src/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Library Page" msgstr "Kitaplık Sayfasını Aç" #: src/shortcuts-dialog.blp:20 msgctxt "shortcut window" msgid "Refresh" msgstr "Yenile" #: src/shortcuts-dialog.blp:25 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Tercihleri Aç" #: src/shortcuts-dialog.blp:30 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Kısayolları Göster" #: src/shortcuts-dialog.blp:35 msgctxt "shortcut window" msgid "Close Window" msgstr "Pencereyi Kapat" #: src/shortcuts-dialog.blp:41 msgctxt "shortcut window" msgid "Quit Bazaar" msgstr "Bazaarʼdan Çık" bazaar-orig-v0.7.14/po/hu.po0000664000175000017500000010317315166123241014537 0ustar hasanhasan# Hungarian translations for bazaar package. # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # Benedek Dévényi , 2025. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-10-31 23:45+0100\n" "PO-Revision-Date: 2025-11-02 20:12+0100\n" "Last-Translator: Benedek Dévényi \n" "Language-Team: Hungarian\n" "Language: hu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 49.0\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:5 #: src/bz-window.blp:56 msgid "Bazaar" msgstr "Bazár" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "Flatpak alkalmazások telepítése, eltávolítása és frissítése" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;System;PackageManager;Discover;Flatpak;Software;Store;rendszer;csomagkezelő;felfedezés;szoftver;áruház;bolt;" #: data/io.github.kolunmi.Bazaar.gschema.xml:6 msgid "Show Git Forge Star Counts" msgstr "" #: data/io.github.kolunmi.Bazaar.gschema.xml:7 msgid "" "Whether to attempt to detect and show \"star counts\" for projects in the " "full view" msgstr "" #: data/io.github.kolunmi.Bazaar.gschema.xml:11 msgid "Only Show Free Software" msgstr "" #: data/io.github.kolunmi.Bazaar.gschema.xml:12 msgid "Hide proprietary software when searching" msgstr "" #: data/io.github.kolunmi.Bazaar.gschema.xml:16 msgid "Show Only Flathub Content" msgstr "" #: data/io.github.kolunmi.Bazaar.gschema.xml:17 msgid "Filter search results to only show applications available on Flathub" msgstr "" #: data/io.github.kolunmi.Bazaar.gschema.xml:21 msgid "Debounce Search Inputs" msgstr "" #: data/io.github.kolunmi.Bazaar.gschema.xml:22 msgid "Add a delay before searching to prevent instant replies while typing" msgstr "" #: data/io.github.kolunmi.Bazaar.gschema.xml:40 msgid "Global Progress Bar Theme" msgstr "" #: data/io.github.kolunmi.Bazaar.gschema.xml:41 msgid "Describes the look of the global progress bar" msgstr "" #: data/io.github.kolunmi.Bazaar.gschema.xml:45 msgid "Saved Window Dimensions" msgstr "" #: data/io.github.kolunmi.Bazaar.gschema.xml:46 msgid "The window dimensions to be used by the next Bazaar window" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and install applications" msgstr "Alkalmazások felfedezése és telepítése" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A new app store for GNOME with a focus on discovering and installing " "applications and addons from Flatpak remotes, particularly Flathub." msgstr "" "Egy új alkalmazásbolt GNOME-ra, amelynek fókuszában a Flatpak adattárakból, " "kifejezetten a Flathubról származó alkalmazások és kiegészítők felfedezése " "és telepítése áll." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:14 msgid "" "It emphasizes supporting the developers who make the Linux desktop possible. " "Bazaar features a \"curated\" tab that can be configured by distributors to " "allow for a more localized experience." msgstr "" "Hangsúlyozza a Linuxos asztali rendszereket létrehozó fejlesztők " "támogatását. A Bazár egy „válogatott” füllel is rendelkezik, amelyet a " "disztrók konfigurálhatnak, hogy lokalizáltabb élményt nyújtsanak." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:29 src/bz-application.c:506 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:54 msgid "The home view displaying Flathub apps" msgstr "A kezdőképernyő Flathub alkalmazásokkal" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:58 msgid "Nucleus app page" msgstr "Alkalmazásoldal a Nucleus alkalmazással" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:62 msgid "Searching for Blender" msgstr "Keresés a Blenderre" #: src/bz-addons-dialog.blp:14 src/bz-full-view.blp:527 #: src/bz-installed-page.blp:132 msgid "Manage Add-ons" msgstr "Kiegészítők kezelése" #: src/bz-addons-dialog.c:88 src/bz-installed-page.blp:158 #: src/bz-transaction-view.blp:212 src/bz-window.c:1125 msgid "Remove" msgstr "Eltávolítás" #: src/bz-addons-dialog.c:95 src/bz-full-view.blp:244 #: src/bz-transaction-view.blp:186 src/bz-window.c:1103 msgid "Install" msgstr "Telepítés" #: src/bz-app-size-dialog.c:55 msgid "Of the size of human DNA" msgstr "Az emberi DNS méretéhez képest" #: src/bz-app-size-dialog.c:55 msgid "3 billion base pairs" msgstr "3 milliárd bázispár" #: src/bz-app-size-dialog.c:56 msgid "Of the Linux Kernel" msgstr "A Linux Kernelhez képest" #: src/bz-app-size-dialog.c:56 msgid "linux-6.17.tar.xz" msgstr "linux-6.17.tar.xz" #: src/bz-app-size-dialog.c:57 msgid "Of the Apollo 11 guidance computer" msgstr "Az Apollo 11 irányító számítógépéhez képest" #: src/bz-app-size-dialog.c:57 msgid "Total ROM and RAM" msgstr "A teljes ROM és RAM" #: src/bz-app-size-dialog.c:58 msgid "Of the original Super Mario Bros" msgstr "Az eredeti Super Mario Bros méretéhez képest" #: src/bz-app-size-dialog.c:58 msgid "On the NES" msgstr "A NES-en" #: src/bz-app-size-dialog.c:59 msgid "Of the size of Wikipedia" msgstr "A Wikipédia méretéhez képest" #: src/bz-app-size-dialog.c:59 msgid "Without any media" msgstr "Minden média nélkül" #: src/bz-app-size-dialog.blp:43 msgid "--- MB" msgstr "--- MB" #: src/bz-app-size-dialog.blp:53 msgid "Download Size" msgstr "Letöltési méret" #: src/bz-application.c:401 msgid "" "This functionality is currently disabled. It is recommended you download and " "install Flatseal to manage app permissions." msgstr "" "Ez a funkció jelenleg nem elérhető. Javasoljuk, hogy telepítsd a Flatseal " "alkalmazást az alkalmazások engedélyeinek kezeléséhez." #: src/bz-application.c:465 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:466 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:481 msgid "translator-credits" msgstr "Benedek Dévényi , 2025" #: src/bz-application.c:471 msgctxt "About Dialog Translator Credit" msgid "Ahmed Najmawi" msgstr "Ahmed Najmawi" #: src/bz-application.c:472 msgctxt "About Dialog Translator Credit" msgid "AtomHare" msgstr "AtomHare" #: src/bz-application.c:473 msgctxt "About Dialog Translator Credit" msgid "Azenyr" msgstr "Azenyr" #: src/bz-application.c:474 msgctxt "About Dialog Translator Credit" msgid "Goudarz Jafari" msgstr "Goudarz Jafari" #: src/bz-application.c:475 msgctxt "About Dialog Translator Credit" msgid "Jill Fiore (Lumaeris)" msgstr "Jill Fiore (Lumaeris)" #: src/bz-application.c:476 msgctxt "About Dialog Translator Credit" msgid "João Victor (Leal)" msgstr "João Victor (Leal)" #: src/bz-application.c:477 msgctxt "About Dialog Translator Credit" msgid "KiKaraage" msgstr "KiKaraage" #: src/bz-application.c:478 msgctxt "About Dialog Translator Credit" msgid "Lucosec" msgstr "Lucosec" #: src/bz-application.c:479 msgctxt "About Dialog Translator Credit" msgid "Léane GRASSER" msgstr "Léane GRASSER" #: src/bz-application.c:480 msgctxt "About Dialog Translator Credit" msgid "Marcel Mrówka (Microwave)" msgstr "Marcel Mrówka (Microwave)" #: src/bz-application.c:481 msgctxt "About Dialog Translator Credit" msgid "Peter Dave Hello" msgstr "Peter Dave Hello" #: src/bz-application.c:482 msgctxt "About Dialog Translator Credit" msgid "Pietro F." msgstr "Pietro F." #: src/bz-application.c:483 msgctxt "About Dialog Translator Credit" msgid "Sabri Ünal" msgstr "Sabri Ünal" #: src/bz-application.c:484 msgctxt "About Dialog Translator Credit" msgid "Shihfu Juan" msgstr "Shihfu Juan" #: src/bz-application.c:485 msgctxt "About Dialog Translator Credit" msgid "Shinsei" msgstr "Shinsei" #: src/bz-application.c:486 msgctxt "About Dialog Translator Credit" msgid "Vlastimil Dědek" msgstr "Vlastimil Dědek" #: src/bz-application.c:487 msgctxt "About Dialog Translator Credit" msgid "asen23" msgstr "asen23" #: src/bz-application.c:488 msgctxt "About Dialog Translator Credit" msgid "camegone" msgstr "camegone" #: src/bz-application.c:489 msgctxt "About Dialog Translator Credit" msgid "renner" msgstr "renner" #: src/bz-application.c:490 msgctxt "About Dialog Translator Credit" msgid "robotta" msgstr "robotta" #: src/bz-application.c:1033 msgid "Constructing Flatpak instance..." msgstr "Flatpak példány létrehozása…" #: src/bz-application.c:1050 msgid "Reusing last Flatpak instance..." msgstr "Legutóbbi Flatpak példány újrafelhasználása…" #: src/bz-application.c:1075 msgid "Flathub is not registered on this system" msgstr "A Flathub nincs beállítva ezen a rendszeren" #: src/bz-application.c:1078 msgid "" "Would you like to add Flathub as a remote? If you decline, the Flathub page " "will not be available. You can change this later." msgstr "" "Szeretnéd engedélyezni a Flathub távoli adattárat? Ha ezt nem teszed meg, a " "Flathub fül nem lesz elérhető. Később ezt bármikor megváltoztathatod." #: src/bz-application.c:1083 src/bz-update-dialog.blp:6 msgid "Later" msgstr "Később" #: src/bz-application.c:1084 msgid "Add Flathub" msgstr "Flathub engedélyezése" #: src/bz-application.c:1116 #, c-format msgid "Identifying installed entries..." msgstr "Telepített tételek beazonosítása…" #: src/bz-application.c:1128 #, c-format msgid "Beginning remote entry retrieval while referencing %d blocklist(s)..." msgstr "Távoli tételek lekérésének megkezdése, %d tiltólista hivatkozásával…" #: src/bz-application.c:1276 #, c-format msgid "Receiving Entries" msgstr "Tételek fogadása" #: src/bz-application.c:1277 #, c-format msgid "%'d of %'d" msgstr "%'d/%'d" #: src/bz-application.c:1288 #, c-format msgid "Waiting for background indexing tasks to catch up..." msgstr "Várakozás a háttérben futó indexelési feladatok befejezésére…" #: src/bz-application.c:1329 #, c-format msgid "Completed initialization in %0.2f seconds" msgstr "Az indítás %0.2f másodperc alatt befejeződött" #: src/bz-application.c:1334 src/bz-application.c:1489 msgid "Checking for updates..." msgstr "Frissítések keresése…" #: src/bz-application.c:1373 msgid "Synchronizing..." msgstr "Szinkronizálás…" #: src/bz-browse-widget.blp:11 src/bz-flathub-page.blp:19 #: src/bz-full-view.blp:10 src/bz-installed-page.blp:15 src/bz-window.blp:161 msgid "Empty" msgstr "Üres" #: src/bz-browse-widget.blp:15 msgid "No Curated Applications" msgstr "Nincsenek válogatott alkalmazások" #: src/bz-browse-widget.blp:16 msgid "" "Bazaar was not provided a curated content configuration. Contact your " "operating system's support channels for assistance." msgstr "" "A Bazaar nem talál válogatott tartalomkonfigurációt. Segítségért fordulj az " "operációs rendszer támogatási csatornáihoz." #: src/bz-browse-widget.blp:22 src/bz-flathub-page.blp:30 msgid "Browser" msgstr "Böngésző" #: src/bz-entry-inspector.blp:5 msgid "Entry Inspector" msgstr "" #: src/bz-entry-inspector.blp:76 msgid "Serialize" msgstr "" #: src/bz-entry-inspector.blp:80 msgid "Convert to JSON" msgstr "" #: src/bz-error.c:68 msgid "An Error Occurred" msgstr "Hiba történt" #: src/bz-error.c:89 msgid "Close" msgstr "Bezárás" #: src/bz-error.c:90 msgid "Copy and Close" msgstr "Másolás és bezárás" #: src/bz-featured-tile.blp:89 msgid "App of the Day" msgstr "A nap alkalmazása" #: src/bz-flathub-category.c:325 msgid "Audio & Video" msgstr "Hang és videó" #: src/bz-flathub-category.c:327 msgid "Developer Tools" msgstr "Fejlesztői eszközök" #: src/bz-flathub-category.c:329 msgid "Education" msgstr "Oktatás" #: src/bz-flathub-category.c:331 msgid "Gaming" msgstr "Játék" #: src/bz-flathub-category.c:333 msgid "Graphics & Photography" msgstr "Grafika és fényképezés" #: src/bz-flathub-category.c:335 msgid "Networking" msgstr "Hálózat" #: src/bz-flathub-category.c:337 msgid "Productivity" msgstr "Produktivitás" #: src/bz-flathub-category.c:339 msgid "Science" msgstr "Tudomány" #: src/bz-flathub-category.c:341 msgid "System" msgstr "Rendszer" #: src/bz-flathub-category.c:343 msgid "Utilities" msgstr "Segédprogramok" #: src/bz-flathub-category-section.c:137 #, c-format msgid "%d applications" msgstr "%d alkalmazás" #: src/bz-flathub-category-section.c:336 #, c-format msgid "More %s" msgstr "Még több %s" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "A Flathub nincs engedélyezve" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "A Flathub adattár nem található egyik Flatpak telepítéseden sem" #: src/bz-flathub-page.blp:80 src/bz-flathub-page.blp:109 #: src/bz-flathub-page.c:168 msgid "Trending" msgstr "Felkapott" #: src/bz-flathub-page.blp:85 src/bz-flathub-page.blp:235 #: src/bz-flathub-page.c:198 msgid "Popular" msgstr "Népszerű" #: src/bz-flathub-page.blp:90 msgid "New" msgstr "Új" #: src/bz-flathub-page.blp:95 msgid "Updated" msgstr "Frissített" #: src/bz-flathub-page.blp:141 msgid "More Trending" msgstr "Még több felkapott" #: src/bz-flathub-page.blp:151 src/bz-flathub-page.c:178 msgid "Recently Updated" msgstr "Nemrég frissített" #: src/bz-flathub-page.blp:183 msgid "More Updated" msgstr "Még több frissített" #: src/bz-flathub-page.blp:193 src/bz-flathub-page.c:188 msgid "Recently Added" msgstr "Nemrég hozzáadott" #: src/bz-flathub-page.blp:225 msgid "More New" msgstr "Még több új" #: src/bz-flathub-page.blp:267 msgid "More Popular" msgstr "Még több népszerű" #: src/bz-flathub-page.blp:356 msgid "On the go" msgstr "Útközben" #: src/bz-flathub-page.blp:368 msgid "Apps for your Linux phones and tablets" msgstr "Alkalmazások Linux telefonokra és táblagépekre" #: src/bz-flathub-page.blp:379 src/bz-flathub-page.blp:414 msgid "More Mobile apps" msgstr "Még több mobilapp" #: src/bz-flathub-page.c:208 msgid "Mobile Apps" msgstr "Mobilappok" #: src/bz-flatpak-entry.c:552 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Flathub oldal" #: src/bz-flatpak-entry.c:573 msgctxt "Project URL Type" msgid "Project Website" msgstr "Projekt honlapja" #: src/bz-flatpak-entry.c:577 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Hiba bejelentése" #: src/bz-flatpak-entry.c:581 msgctxt "Project URL Type" msgid "FAQ" msgstr "GYIK" #: src/bz-flatpak-entry.c:585 msgctxt "Project URL Type" msgid "Help" msgstr "Segítség" #: src/bz-flatpak-entry.c:589 msgctxt "Project URL Type" msgid "Donate" msgstr "Adományozás" #: src/bz-flatpak-entry.c:595 msgctxt "Project URL Type" msgid "Translate" msgstr "Segítség a fordításban" #: src/bz-flatpak-entry.c:599 msgctxt "Project URL Type" msgid "Contact" msgstr "Kapcsolat" #: src/bz-flatpak-entry.c:603 msgctxt "Project URL Type" msgid "Source Code" msgstr "Forráskód" #: src/bz-flatpak-entry.c:609 msgctxt "Project URL Type" msgid "Contribute" msgstr "Hozzájárulás" #: src/bz-full-view.blp:14 msgid "No Results" msgstr "Nincs találat" #: src/bz-full-view.blp:15 msgid "Try a different search query" msgstr "Próbálkozz más keresőkifejezéssel" #: src/bz-full-view.blp:21 src/bz-window.blp:171 msgid "Content" msgstr "Tartalom" #: src/bz-full-view.blp:151 msgid "Verified by the original developers" msgstr "Az eredeti fejlesztők által hitelesítve" #: src/bz-full-view.blp:178 msgid "Support" msgstr "Támogatás" #: src/bz-full-view.blp:198 msgid "Repository Star Count" msgstr "Adattár csillagszámlálója" #: src/bz-full-view.blp:228 msgid "Open" msgstr "Megnyitás" #: src/bz-full-view.blp:241 msgid "Download & Install Application" msgstr "Alkalmazás letöltése és telepítése" #: src/bz-full-view.blp:256 msgid "Uninstall Application" msgstr "Alkalmazás eltávolítása" #: src/bz-full-view.blp:271 msgid "Install Other Version" msgstr "Másik verzió telepítése" #: src/bz-full-view.blp:295 msgid "Download" msgstr "Letöltés" #: src/bz-full-view.blp:411 msgid "Downloads/mo" msgstr "Letöltés/hó" #: src/bz-full-view.c:261 msgid "---" msgstr "---" #. Translators: M is the suffix for millions, \xC2\xA0 is a non-breaking space #: src/bz-full-view.c:265 #, c-format msgid "%.2f M" msgstr "%.2f m" #. Translators: K is the suffix for thousands, \xC2\xA0 is a non-breaking space #: src/bz-full-view.c:268 #, c-format msgid "%.2f K" msgstr "%.2f e" #: src/bz-full-view.c:277 #, c-format msgid "%d downloads in the last 30 days" msgstr "%d letöltés az elmúlt 30 napban" #: src/bz-full-view.c:298 #, c-format msgid "Download size of %s" msgstr "Letöltés mérete: %s" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-full-view.c:308 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-full-view.c:316 msgid "All Ages" msgstr "Minden életkor" #: src/bz-full-view.c:318 msgid "Age Rating" msgstr "Korhatár" #: src/bz-full-view.c:326 msgid "Suitable for all ages" msgstr "Minden korosztály számára alkalmas" #: src/bz-full-view.c:328 #, c-format msgid "Suitable for ages %d and up" msgstr "%d éves kortól ajánlott" #: src/bz-full-view.c:348 msgid "Unknown" msgstr "Ismeretlen" #: src/bz-full-view.c:351 msgid "Proprietary Software" msgstr "Zárt forráskódú szoftver" #: src/bz-full-view.c:355 #, c-format msgid "Free software licensed under %s" msgstr "Szabad szoftver a(z) %s licenc alatt" #: src/bz-full-view.c:363 msgid "Free" msgstr "Szabad" #: src/bz-full-view.c:363 msgid "Proprietary" msgstr "Védett" #: src/bz-full-view.c:383 msgid "Adaptive" msgstr "Alkalmazkodó" #: src/bz-full-view.c:383 msgid "Desktop Only" msgstr "Csak asztali" #: src/bz-full-view.c:389 msgid "Works on desktop, tablets, and phones" msgstr "Működik asztali számítógépen, táblagépen és mobiltelefonon" #: src/bz-full-view.c:390 msgid "May not work on mobile devices" msgstr "Lehet, hogy nem működik mobileszközökön" #: src/bz-full-view.c:401 msgid "No URL" msgstr "Nincs URL" #: src/bz-full-view.c:419 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Ez az alkalmazás Szabad és Nyílt Forráskódú licenccel rendelkezik, ami azt " "jelenti, hogy által a forráskód biztonsági szempontból bárki által " "ellenőrizhető." #: src/bz-full-view.c:420 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Ez az alkalmazás kereskedelmi licenccel rendelkezik, ami azt jelenti, hogy a " "forráskód magántulajdonban van, és független harmadik fél nem ellenőrizheti." #: src/bz-full-view.c:676 msgid "Show Less" msgstr "Kevesebb mutatása" #: src/bz-full-view.c:676 msgid "Show More" msgstr "Több mutatása" #: src/bz-hardware-support-dialog.c:69 msgid "Keyboard support" msgstr "Billentyűzet támogatás" #: src/bz-hardware-support-dialog.c:71 msgid "Requires keyboards" msgstr "Billentyűzet szükséges" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends keyboards" msgstr "Billentyűzet ajánlott" #: src/bz-hardware-support-dialog.c:73 msgid "Supports keyboards" msgstr "Billentyűzet használható" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for keyboards" msgstr "Billentyűzet támogatás ismeretlen" #: src/bz-hardware-support-dialog.c:76 msgid "Mouse support" msgstr "Egér támogatás" #: src/bz-hardware-support-dialog.c:78 msgid "Requires mice or pointing devices" msgstr "Egér vagy mutatóeszköz szükséges" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends mice or pointing devices" msgstr "Egér vagy mutatóeszköz ajánlott" #: src/bz-hardware-support-dialog.c:80 msgid "Supports mice or pointing devices" msgstr "Egér vagy mutatóeszköz használható" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for mice or pointing devices" msgstr "Egér vagy mutatóeszköz támogatás ismeretlen" #: src/bz-hardware-support-dialog.c:83 msgid "Touchscreen support" msgstr "Érintőképernyő támogatás" #: src/bz-hardware-support-dialog.c:85 msgid "Requires touchscreens" msgstr "Érintőképernyő szükséges" #: src/bz-hardware-support-dialog.c:86 msgid "Recommends touchscreens" msgstr "Érintőképernyő ajánlott" #: src/bz-hardware-support-dialog.c:87 msgid "Supports touchscreens" msgstr "Érintőképernyő használható" #: src/bz-hardware-support-dialog.c:88 msgid "Unknown support for touchscreens" msgstr "Érintőképernyő támogatás ismeretlen" #: src/bz-hardware-support-dialog.c:192 msgid "Mobile support" msgstr "Mobil támogatás" #: src/bz-hardware-support-dialog.c:193 msgid "Works on mobile devices" msgstr "Működik mobileszközökön" #: src/bz-hardware-support-dialog.c:193 msgid "May not work well on mobile devices" msgstr "Lehet, hogy nem működik jól mobileszközökön" #: src/bz-hardware-support-dialog.c:198 msgid "Desktop support" msgstr "Asztali támogatás" #: src/bz-hardware-support-dialog.c:199 msgid "Works well on large screens" msgstr "Jól működik nagy kijelzőkön" #: src/bz-hardware-support-dialog.c:233 #, c-format msgid "%s works best on specific hardware" msgstr "%s csak bizonyos eszközökön működik jól" #: src/bz-hardware-support-dialog.c:240 #, c-format msgid "%s works on most devices" msgstr "%s a legtöbb eszközön működik" #: src/bz-hardware-support-dialog.blp:6 src/bz-hardware-support-dialog.blp:47 msgid "Hardware Support" msgstr "Hardver támogatás" #: src/bz-inspector.blp:5 msgid "Bazaar Inspector" msgstr "" #: src/bz-inspector.blp:22 msgid "Active Blocklists" msgstr "" #: src/bz-inspector.blp:44 msgid "Active Curated-Configs" msgstr "" #: src/bz-inspector.blp:66 msgid "All Entry Groups" msgstr "" #: src/bz-inspector.blp:69 msgid "Filter..." msgstr "" #: src/bz-inspector.blp:110 msgid "Decache and Inspect" msgstr "" #: src/bz-installed-page.blp:19 msgid "No Flatpaks Installed" msgstr "Nincs telepített Flatpak" #: src/bz-installed-page.blp:25 src/bz-window.blp:305 src/bz-window.blp:399 msgid "Installed" msgstr "Telepítve" #: src/bz-installed-page.blp:108 msgid "Support this application" msgstr "Alkalmazás támogatása" #: src/bz-installed-page.blp:185 msgid "More actions" msgstr "További lehetőségek" #: src/bz-installed-page.blp:204 msgid "Run this application" msgstr "Alkalmazás futtatása" #: src/bz-installed-page.blp:216 msgid "Run" msgstr "Futtatás" #: src/bz-installed-page.blp:228 src/bz-installed-page.blp:239 msgid "View Store Page" msgstr "Alkalmazásoldal megnyitása" #: src/bz-installed-page.c:649 msgid "Choose an Installation" msgstr "Telepítés kiválasztása" #: src/bz-installed-page.c:652 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with? " msgstr "" "Ennek az alkalmazásnak több verziója is telepítve van. Melyikkel szeretnéd " "folytatni?" #: src/bz-installed-page.c:656 src/bz-window.c:1102 src/bz-window.c:1124 msgid "Cancel" msgstr "Mégse" #: src/bz-license-dialog.c:115 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may not be able to contribute to this app." msgstr "" "Ez az alkalmazás zárt fejlesztésű, ezért csak a fejlesztői ismerik a belső " "működését. Lehetnek olyan biztonsági hiányosságai, amelyek nehezen " "észlelhetők, illetve a működése észrevétlenül megváltozhat.\n" "\n" "Nem tudsz hozzájárulni az alkalmazás fejlesztéséhez." #: src/bz-license-dialog.c:124 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Ezt az alkalmazást egy nemzetközi közösség nyíltan fejleszti.\n" "\n" "Te is csatlakozhatsz és segíthetsz még jobbá tenni." #: src/bz-license-dialog.c:135 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Ezt az alkalmazást egy nemzetközi közösség nyíltan fejleszti, és a(z) %s teszi elérhetővé.\n" "\n" "Te is csatlakozhatsz és segíthetsz még jobbá tenni." #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Beállítások" #: src/bz-preferences-dialog.blp:23 src/bz-window.blp:48 src/bz-window.blp:337 msgid "Search" msgstr "Keresés" #: src/bz-preferences-dialog.blp:26 msgid "Free Software Only" msgstr "Csak szabad szoftver" #: src/bz-preferences-dialog.blp:27 msgid "Hide proprietary applications from search results" msgstr "Zárt forráskódú alkalmazások elrejtése a keresési eredményekből" #: src/bz-preferences-dialog.blp:31 msgid "Flathub Results Only" msgstr "Csak Flathub eredmények" #: src/bz-preferences-dialog.blp:32 msgid "Limit search results to applications only available on Flathub" msgstr "Keresés korlátozása a Flathubon elérhető alkalmazásokra" #: src/bz-preferences-dialog.blp:36 msgid "Delay Search Results" msgstr "Keresés késleltetése" #: src/bz-preferences-dialog.blp:37 msgid "Improve results performance by debouncing search terms" msgstr "" "Keresés teljesítményének javítása a keresőkifejezések pergésmentesítésével" #: src/bz-preferences-dialog.blp:42 msgid "Application Details" msgstr "Alkalmazás részletei" #: src/bz-preferences-dialog.blp:45 msgid "Display Star Count" msgstr "Csillagszámláló mutatása" #: src/bz-preferences-dialog.blp:46 msgid "Show the star count of an application's source code repository" msgstr "Az alkalmazás forráskód-adattára csillagszámának megjelenítése" #: src/bz-preferences-dialog.blp:71 msgid "Progress Bar" msgstr "Folyamatjelző" #: src/bz-preferences-dialog.blp:72 msgid "Choose a theme for the progress bar!" msgstr "Válassz témát a folyamatjelző sávoknak" #: src/bz-preferences-dialog.blp:107 msgid "" "Bazaar can fetch and display the star count from an application's source " "code repository on a remote Git forge. \n" " For projects on GitHub, rate limits may cause them not to appear." msgstr "" "A Bazár letölti és megjeleníti a csillagok számát egy alkalmazás forráskód-" "adattárából a távoli Git forge-on. \n" " A GitHubon található projektek esetében a használati korlát miatt " "előfordulhat, hogy nem mindig sikerül betölteni." #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Kiemelőszín" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Pride színek" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "Lezbikus színek" #: src/bz-preferences-dialog.c:35 msgid "Transgender Pride Colors" msgstr "Transzgender színek" #: src/bz-preferences-dialog.c:36 msgid "Nonbinary Pride Colors" msgstr "Nonbináris színek" #: src/bz-preferences-dialog.c:37 msgid "Bisexual Pride Colors" msgstr "Biszexuális színek" #: src/bz-preferences-dialog.c:38 msgid "Asexual Pride Colors" msgstr "Aszexuális színek" #: src/bz-preferences-dialog.c:39 msgid "Pansexual Pride Colors" msgstr "Pánszexuális színek" #: src/bz-preferences-dialog.c:40 msgid "Aromantic Pride Colors" msgstr "Aromantikus színek" #: src/bz-preferences-dialog.c:41 msgid "Genderfluid Pride Colors" msgstr "Genderfluid színek" #: src/bz-preferences-dialog.c:42 msgid "Polysexual Pride Colors" msgstr "Poliszexuális színek" #: src/bz-preferences-dialog.c:43 msgid "Omnisexual Pride Colors" msgstr "Omniszexuális színek" #: src/bz-releases-dialog.blp:5 src/bz-releases-list.blp:26 msgid "Version History" msgstr "Verziótörténet" #: src/bz-releases-list.c:128 #, c-format msgid "Version %s" msgstr "%s verzió" #: src/bz-releases-list.c:153 msgid "No details for this release" msgstr "Nincsenek részletek ehhez a kiadáshoz" #: src/bz-search-widget.blp:69 msgid "Search Apps" msgstr "Alkalmazások keresése" #: src/bz-share-list.c:64 msgid "Copied!" msgstr "Másolva!" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "Hivatkozás másolása" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Hivatkozás megnyitása" #: src/bz-stats-dialog.blp:26 msgid "Timeline" msgstr "Idővonal" #: src/bz-stats-dialog.blp:31 msgid "Installs:" msgstr "Telepítés:" #: src/bz-stats-dialog.blp:37 msgid "World" msgstr "Térkép" #: src/bz-transaction-manager.c:1140 #, c-format msgid "Finished in %.02f seconds" msgstr "Befejezve %.02f másodperc alatt" #: src/bz-transaction-view.blp:94 msgid "App Add-on" msgstr "Alkalmazás kiegészítő" #: src/bz-transaction-view.blp:119 msgid "Runtime" msgstr "Futtatókörnyezet" #: src/bz-transaction-view.blp:145 src/bz-transaction-view.blp:171 msgid "Install Size" msgstr "Telepített méret" #: src/bz-transaction-view.blp:199 src/bz-window.blp:350 msgid "Update" msgstr "Frissítés" #: src/bz-transaction-view.c:139 #, c-format msgid "Transferred %s so far" msgstr "Eddig átvíve: %s" #: src/bz-transaction.c:336 msgid "Pending" msgstr "Függőben" #: src/bz-update-dialog.blp:7 msgid "Install Now" msgstr "Telepítés most" #: src/bz-update-dialog.blp:10 msgid "Updates Are Available" msgstr "Frissítések elérhetők" #: src/bz-update-dialog.blp:11 msgid "" "The following applications are eligible for updates. Would you like to " "install them?" msgstr "" "A következő alkalmazások frissítésre várnak. Szeretnéd telepíteni őket?" #: src/bz-update-dialog.c:134 #, c-format msgid "" "%d runtimes and/or addons are eligible for updates. Would you like to " "install them?" msgstr "" "%d futtatókörnyezet és/vagy kiegészítőhöz érhető el frissítés. Szeretnéd " "telepíteni ezeket?" #: src/bz-update-dialog.c:142 #, c-format msgid "Additionally, %d runtimes and/or addons will be updated." msgstr "További %d futtatókörnyezet és/vagy kiegészítő frissítve lesz." #: src/bz-window.blp:63 msgid "Go Home" msgstr "Vissza a kezdőoldalra" #: src/bz-window.blp:86 msgid "Tasks" msgstr "Feladatok" #: src/bz-window.blp:105 src/bz-window.blp:418 msgid "Toggle transaction sidebar" msgstr "Tranzakciók megjelenítése/elrejtése" #: src/bz-window.blp:141 msgid "Stop Active Tasks" msgstr "Futó feladatok leállítása" #: src/bz-window.blp:149 msgid "Clear History" msgstr "Előzmények törlése" #: src/bz-window.blp:165 msgid "No Tasks Yet" msgstr "Nincsenek feladatok" #: src/bz-window.blp:219 src/bz-window.blp:223 msgid "Offline" msgstr "Offline" #: src/bz-window.blp:229 msgid "Loading" msgstr "Betöltés" #: src/bz-window.blp:270 msgid "Browse" msgstr "Böngészés" #: src/bz-window.blp:280 msgid "App View" msgstr "Alkalmazás nézet" #: src/bz-window.blp:295 src/bz-window.blp:392 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:325 msgid "Go Back" msgstr "Vissza" #: src/bz-window.blp:381 msgid "View curated applications" msgstr "Válogatott alkalmazások megtekintése" #: src/bz-window.blp:385 msgid "Curated" msgstr "Válogatott" #: src/bz-window.blp:389 msgid "View the latest on Flathub" msgstr "Legújabb Flathub alkalmazások megtekintése" #: src/bz-window.blp:396 msgid "View installed applications" msgstr "Telepített alkalmazások megtekintése" #: src/bz-window.blp:441 msgid "Main Menu" msgstr "Főmenü" #: src/bz-window.blp:486 msgid "_Donate to Bazaar ❤️" msgstr "A Bazár _támogatása ❤️" #: src/bz-window.blp:491 msgid "_Refresh Content" msgstr "Ú_jratöltés" #: src/bz-window.blp:498 msgid "_Preferences" msgstr "_Beállítások" #: src/bz-window.blp:503 msgid "_Keyboard Shortcuts" msgstr "_Gyorsbillentyűk" #: src/bz-window.blp:508 msgid "_About Bazaar" msgstr "A Bazár _névjegye" #: src/bz-window.blp:515 msgid "_Quit Bazaar" msgstr "_Kilépés" #: src/bz-window.c:827 msgid "" "The ability to inspect and install local .flatpak bundle files is coming " "soon! In the meantime, try running\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "on the command line." msgstr "" "Hamarosan elérhető lesz a helyi .flatpak csomagfájlok ellenőrzésének és " "telepítésének lehetősége! Addig is próbáld meg futtatni a\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "parancsot a parancssorban." #: src/bz-window.c:967 msgid "Can't do that right now!" msgstr "Ezt most nem lehetséges!" #: src/bz-window.c:1096 #, c-format msgid "Install %s?" msgstr "%s telepítése" #: src/bz-window.c:1099 msgid "May install additional shared components" msgstr "További megosztott összetevők telepíthetők" #: src/bz-window.c:1118 #, c-format msgid "Remove %s?" msgstr "Remove %s?" #: src/bz-window.c:1121 msgid "Settings & user data will be kept" msgstr "A beállítások és a felhasználói adatok megmaradnak" #: src/bz-window.c:1289 msgid "Resume Current Tasks" msgstr "Feladatok folytatása" #: src/bz-window.c:1295 msgid "Pause Current Tasks" msgstr "Feladatok szüneteltetése" #: src/bz-world-map.c:523 #, c-format msgid "%s: %'u downloads" msgstr "%s: %'u downloads" #: src/gtk/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Általános" #: src/gtk/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "Keresőablak megnyitása" #: src/gtk/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Beállítások megnyitása" #: src/gtk/shortcuts-dialog.blp:19 msgctxt "shortcut window" msgid "Refresh" msgstr "Újratöltés" #: src/gtk/shortcuts-dialog.blp:24 msgctxt "shortcut window" msgid "Toggle Transaction Manager" msgstr "Tranzakciókezelő megjelenítése/elrejtése" #: src/gtk/shortcuts-dialog.blp:29 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Gyorsbillentyűk" #: src/gtk/shortcuts-dialog.blp:34 msgctxt "shortcut window" msgid "Quit" msgstr "Kilépés" bazaar-orig-v0.7.14/po/el.po0000664000175000017500000017556715166123241014543 0ustar hasanhasan# Greek translations for bazaar package. # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-12-18 02:22+0200\n" "PO-Revision-Date: 2025-12-18 04:30+0200\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: el\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.8\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:5 #: src/bz-window.blp:234 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "" "Προσθήκη, αφαίρεση ή ενημέρωση λογισμικού flatpak σε αυτόν τον υπολογιστή" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "" "GTK;Σύστημα;Διαχειριστής πακέτων;Ανακάλυψη;Flatpak;Λογισμικό;Κατάστημα;" #: data/io.github.kolunmi.Bazaar.gschema.xml:6 msgid "Hide EOL Entries" msgstr "Απόκρυψη καταχωρήσεων EOL" #: data/io.github.kolunmi.Bazaar.gschema.xml:7 msgid "Hide EOL entries and entries depending on them" msgstr "Απόκρυψη καταχωρήσεων EOL και καταχωρήσεων που εξαρτώνται από αυτές" #: data/io.github.kolunmi.Bazaar.gschema.xml:11 msgid "Only Show Free Software" msgstr "Εμφάνιση μόνο δωρεάν λογισμικού" #: data/io.github.kolunmi.Bazaar.gschema.xml:12 msgid "Hide proprietary software" msgstr "Απόκρυψη ιδιόκτητου λογισμικού" #: data/io.github.kolunmi.Bazaar.gschema.xml:16 msgid "Show Only Flathub Content" msgstr "Εμφάνιση μόνο περιεχομένου Flathub" #: data/io.github.kolunmi.Bazaar.gschema.xml:17 msgid "Hide applications which do not originate from Flathub" msgstr "Απόκρυψη εφαρμογών που δεν προέρχονται από το Flathub" #: data/io.github.kolunmi.Bazaar.gschema.xml:21 msgid "Debounce Search Inputs" msgstr "Αναζήτηση εισόδων χωρίς αναπήδηση" #: data/io.github.kolunmi.Bazaar.gschema.xml:22 msgid "Add a delay before searching to prevent instant replies while typing" msgstr "" "Προσθέστε μια καθυστέρηση πριν από την αναζήτηση για να αποτρέψετε τις " "άμεσες απαντήσεις κατά την πληκτρολόγηση" #: data/io.github.kolunmi.Bazaar.gschema.xml:46 msgid "Global Progress Bar Theme" msgstr "Καθολικό θέμα μπάρας προόδου" #: data/io.github.kolunmi.Bazaar.gschema.xml:47 msgid "Describes the look of the global progress bar" msgstr "Περιγράφει την εμφάνιση της καθολικής μπάρας προόδου" #: data/io.github.kolunmi.Bazaar.gschema.xml:51 msgid "Saved Window Dimensions" msgstr "Αποθηκευμένες διαστάσεις παραθύρου" #: data/io.github.kolunmi.Bazaar.gschema.xml:52 msgid "The window dimensions to be used by the next Bazaar window" msgstr "" "Οι διαστάσεις του παραθύρου που θα χρησιμοποιηθούν από το επόμενο παράθυρο " "Bazaar" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and install applications" msgstr "Ανακαλύψτε και εγκαταστήστε εφαρμογές" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A new app store for GNOME with a focus on discovering and installing " "applications and addons from Flatpak remotes, particularly Flathub." msgstr "" "Ένα νέο κατάστημα εφαρμογών για το GNOME με έμφαση στην αναζήτηση και " "εγκατάσταση εφαρμογών και πρόσθετων από απομακρυσμένους διακομιστές Flatpak, " "ιδίως το Flathub." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:14 msgid "" "It emphasizes supporting the developers who make the Linux desktop possible. " "Bazaar features a \"curated\" tab that can be configured by distributors to " "allow for a more localized experience." msgstr "" "Δίνει έμφαση στην υποστήριξη των προγραμματιστών που καθιστούν δυνατή τη " "λειτουργία του Linux desktop. Το Bazaar διαθέτει μια καρτέλα \"curated\" που " "μπορεί να διαμορφωθεί από τους διανομείς ώστε να προσφέρει μια πιο τοπική " "εμπειρία." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:54 msgid "The home page displaying Flathub apps" msgstr "Η αρχική σελίδα που εμφανίζει τις εφαρμογές Flathub" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:58 msgid "Nucleus app page" msgstr "Σελίδα εφαρμογής Nucleus" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:62 msgid "Search page" msgstr "Σελίδα αναζήτησης" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:66 msgid "Category page" msgstr "Σελίδα κατηγορίας" #: src/bz-addons-dialog.blp:14 src/bz-full-view.blp:711 #: src/bz-installed-tile.blp:99 msgid "Manage Add-ons" msgstr "Διαχείριση πρόσθετων" #: src/bz-addons-dialog.c:90 src/bz-full-view.blp:502 #: src/bz-installed-tile.blp:117 src/bz-transaction-view.blp:213 #: src/bz-window.c:1294 msgid "Remove" msgstr "Κατάργηση" #: src/bz-addons-dialog.c:95 src/bz-full-view.blp:274 src/bz-full-view.blp:489 #: src/bz-transaction-view.blp:187 src/bz-window.c:1271 msgid "Install" msgstr "Εγκατάσταση" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:50 #: src/bz-full-view.c:373 src/bz-full-view.c:380 msgid "Age Rating" msgstr "Βαθμολογία ηλικίας" #: src/bz-age-rating-dialog.blp:40 src/bz-age-rating-dialog.c:790 msgid "?" msgstr "?" #: src/bz-age-rating-dialog.c:139 msgid "Cartoon Violence" msgstr "Βία στα κινούμενα σχέδια" #: src/bz-age-rating-dialog.c:140 msgid "No information regarding cartoon violence" msgstr "Δεν υπάρχουν πληροφορίες σχετικά με τη βία στα κινούμενα σχέδια" #: src/bz-age-rating-dialog.c:143 msgid "Fantasy Violence" msgstr "Φανταστική βία" #: src/bz-age-rating-dialog.c:144 msgid "No information regarding fantasy violence" msgstr "Δεν υπάρχουν πληροφορίες σχετικά με τη φανταστική βία" #: src/bz-age-rating-dialog.c:147 msgid "Realistic Violence" msgstr "Ρεαλιστική βία" #: src/bz-age-rating-dialog.c:148 msgid "No information regarding realistic violence" msgstr "Δεν υπάρχουν πληροφορίες σχετικά με ρεαλιστική βία" #: src/bz-age-rating-dialog.c:151 msgid "Violence Depicting Bloodshed" msgstr "Βία που απεικονίζει αιματοχυσία" #: src/bz-age-rating-dialog.c:152 msgid "No information regarding bloodshed" msgstr "Δεν υπάρχουν πληροφορίες σχετικά με βία που απεικονίζει αιματοχυσία" #: src/bz-age-rating-dialog.c:155 msgid "Sexual Violence" msgstr "Σεξουαλική βία" #: src/bz-age-rating-dialog.c:156 msgid "No information regarding sexual violence" msgstr "Δεν υπάρχουν πληροφορίες σχετικά με σεξουαλική βία" #: src/bz-age-rating-dialog.c:159 msgid "Alcohol" msgstr "Αλκοόλ" #: src/bz-age-rating-dialog.c:160 msgid "No information regarding references to alcohol" msgstr "Δεν υπάρχουν πληροφορίες σχετικά με αναφορές στο αλκοόλ" #: src/bz-age-rating-dialog.c:163 msgid "Narcotics" msgstr "Ναρκωτικά" #: src/bz-age-rating-dialog.c:164 msgid "No information regarding references to illicit drugs" msgstr "" "Δεν υπάρχουν πληροφορίες σχετικά με αναφορές σε παράνομες ναρκωτικές ουσίες" #: src/bz-age-rating-dialog.c:167 msgid "Tobacco" msgstr "Καπνός" #: src/bz-age-rating-dialog.c:168 msgid "No information regarding references to tobacco products" msgstr "Δεν υπάρχουν πληροφορίες σχετικά με αναφορές σε προϊόντα καπνού" #: src/bz-age-rating-dialog.c:171 src/bz-age-rating-dialog.c:358 msgid "Nudity" msgstr "Γυμνότητα" #: src/bz-age-rating-dialog.c:172 msgid "No information regarding nudity of any sort" msgstr "Καμία πληροφορία σχετικά με γυμνότητα οποιουδήποτε είδους" #: src/bz-age-rating-dialog.c:175 msgid "Sexual Themes" msgstr "Σεξουαλικά θέματα" #: src/bz-age-rating-dialog.c:176 msgid "No information regarding references to or depictions of sexual nature" msgstr "" "Δεν υπάρχουν πληροφορίες σχετικά με αναφορές ή απεικονίσεις σεξουαλικού " "χαρακτήρα" #: src/bz-age-rating-dialog.c:179 msgid "Profanity" msgstr "Βωμολοχίες" #: src/bz-age-rating-dialog.c:180 msgid "No information regarding profanity of any kind" msgstr "Δεν υπάρχουν πληροφορίες σχετικά με οποιαδήποτε μορφή βωμολοχίας" #: src/bz-age-rating-dialog.c:183 msgid "Inappropriate Humor" msgstr "Ακατάλληλο χιούμορ" #: src/bz-age-rating-dialog.c:184 msgid "No information regarding inappropriate humor" msgstr "Δεν υπάρχουν πληροφορίες σχετικά με ακατάλληλο χιούμορ" #: src/bz-age-rating-dialog.c:187 msgid "Discrimination" msgstr "Διακρίσεις" #: src/bz-age-rating-dialog.c:188 msgid "No information regarding discriminatory language of any kind" msgstr "Καμία πληροφορία σχετικά με διακριτική γλώσσα οποιουδήποτε είδους" #: src/bz-age-rating-dialog.c:191 msgid "Advertising" msgstr "Διαφήμιση" #: src/bz-age-rating-dialog.c:192 msgid "No information regarding advertising of any kind" msgstr "Καμία πληροφορία σχετικά με διαφημίσεις οποιουδήποτε είδους" #: src/bz-age-rating-dialog.c:195 msgid "Gambling" msgstr "Τυχερά παιχνίδια" #: src/bz-age-rating-dialog.c:196 msgid "No information regarding gambling of any kind" msgstr "Καμία πληροφορία σχετικά με τυχερά παιχνίδια οποιουδήποτε είδους" #: src/bz-age-rating-dialog.c:199 msgid "Purchasing" msgstr "Αγορές" #: src/bz-age-rating-dialog.c:200 msgid "No information regarding the ability to spend money" msgstr "Δεν υπάρχουν πληροφορίες σχετικά με τη δυνατότητα δαπάνης χρημάτων" #: src/bz-age-rating-dialog.c:203 msgid "Chat Between Users" msgstr "Συνομιλία μεταξύ χρηστών" #: src/bz-age-rating-dialog.c:204 msgid "No information regarding ways to chat with other users" msgstr "" "Δεν υπάρχουν πληροφορίες σχετικά με τους τρόπους επικοινωνίας με άλλους " "χρήστες" #: src/bz-age-rating-dialog.c:207 msgid "Audio Chat Between Users" msgstr "Ηχητική συνομιλία μεταξύ χρηστών" #: src/bz-age-rating-dialog.c:208 msgid "No information regarding ways to talk with other users" msgstr "" "Δεν υπάρχουν πληροφορίες σχετικά με τους τρόπους επικοινωνίας με άλλους " "χρήστες" #: src/bz-age-rating-dialog.c:211 msgid "Contact Details" msgstr "Στοιχεία επικοινωνίας" #: src/bz-age-rating-dialog.c:212 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "" "Δεν υπάρχουν πληροφορίες σχετικά με την κοινοποίηση ονομάτων χρήστη " "κοινωνικών δικτύων ή διευθύνσεων ηλεκτρονικού ταχυδρομείου" #: src/bz-age-rating-dialog.c:215 msgid "Identifying Information" msgstr "Πληροφορίες ταυτοποίησης" #: src/bz-age-rating-dialog.c:216 msgid "No information regarding sharing of user information with third parties" msgstr "" "Δεν υπάρχουν πληροφορίες σχετικά με την κοινοποίηση πληροφοριών χρηστών σε " "τρίτους" #: src/bz-age-rating-dialog.c:219 msgid "Location Sharing" msgstr "Κοινή χρήση τοποθεσίας" #: src/bz-age-rating-dialog.c:220 msgid "No information regarding sharing of physical location with other users" msgstr "" "Δεν υπάρχουν πληροφορίες σχετικά με την κοινοποίηση της φυσικής τοποθεσίας " "σε άλλους χρήστες" #: src/bz-age-rating-dialog.c:223 msgid "Prostitution" msgstr "Πορνεία" #: src/bz-age-rating-dialog.c:224 msgid "No information regarding references to prostitution" msgstr "Δεν υπάρχουν πληροφορίες σχετικά με αναφορές σε πορνεία" #: src/bz-age-rating-dialog.c:227 msgid "Adultery" msgstr "Μοιχεία" #: src/bz-age-rating-dialog.c:228 msgid "No information regarding references to adultery" msgstr "Δεν υπάρχουν πληροφορίες σχετικά με αναφορές σε μοιχεία" #: src/bz-age-rating-dialog.c:231 msgid "Sexualized Characters" msgstr "Σεξουαλικοποιημένοι χαρακτήρες" #: src/bz-age-rating-dialog.c:232 msgid "No information regarding sexualized characters" msgstr "Δεν υπάρχουν πληροφορίες σχετικά με Σεξουαλικοποιημένους χαρακτήρες" #: src/bz-age-rating-dialog.c:235 msgid "Desecration" msgstr "Βεβήλωση" #: src/bz-age-rating-dialog.c:236 msgid "No information regarding references to desecration" msgstr "Δεν υπάρχουν πληροφορίες σχετικά με αναφορές σε βεβήλωση" #: src/bz-age-rating-dialog.c:239 msgid "Human Remains" msgstr "Ανθρώπινα λείψανα" #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "Δεν υπάρχουν πληροφορίες σχετικά με ορατά ανθρώπινα λείψανα" #: src/bz-age-rating-dialog.c:243 msgid "Slavery" msgstr "Δουλεία" #: src/bz-age-rating-dialog.c:244 msgid "No information regarding references to slavery" msgstr "Δεν υπάρχουν πληροφορίες σχετικά με αναφορές στη δουλεία" #: src/bz-age-rating-dialog.c:307 msgid "Does not include references to drugs" msgstr "Δεν περιλαμβάνει αναφορές σε φάρμακα" #: src/bz-age-rating-dialog.c:309 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "" "Δεν περιλαμβάνει βρισιές, χυδαίες εκφράσεις και άλλα είδη σκληρής γλώσσας" #: src/bz-age-rating-dialog.c:311 msgid "Does not include ads or monetary transactions" msgstr "Δεν περιλαμβάνει διαφημίσεις ή χρηματικές συναλλαγές" #: src/bz-age-rating-dialog.c:313 msgid "Does not include sex or nudity" msgstr "Δεν περιλαμβάνει σεξ ή γυμνότητα" #: src/bz-age-rating-dialog.c:315 msgid "Does not include uncontrolled chat functionality" msgstr "Δεν περιλαμβάνει λειτουργία ανεξέλεγκτης συνομιλίας" #: src/bz-age-rating-dialog.c:317 msgid "Does not include violence" msgstr "Δεν περιλαμβάνει βία" #: src/bz-age-rating-dialog.c:352 msgid "Drugs" msgstr "Ναρκωτικά" #: src/bz-age-rating-dialog.c:354 msgid "Strong Language" msgstr "Σκληρή γλώσσα" #: src/bz-age-rating-dialog.c:356 msgid "Money" msgstr "Χρήματα" #: src/bz-age-rating-dialog.c:360 msgid "Social" msgstr "Κοινωνικά" #: src/bz-age-rating-dialog.c:362 msgid "Violence" msgstr "Βία" #: src/bz-age-rating-dialog.c:564 #, c-format msgid "%s • %s" msgstr "%s • %s" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:752 src/bz-full-view.c:363 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:782 msgctxt "Age rating" msgid "All" msgstr "Όλα" #: src/bz-age-rating-dialog.c:846 #, c-format msgid "%s has an unknown age rating" msgstr "Το %s έχει άγνωστη ηλικιακή βαθμολογία" #: src/bz-age-rating-dialog.c:854 #, c-format msgid "%s is suitable for everyone" msgstr "Το %s είναι κατάλληλο για όλους" #: src/bz-age-rating-dialog.c:857 #, c-format msgid "%s is suitable for toddlers" msgstr "Το %s είναι κατάλληλο για νήπια" #: src/bz-age-rating-dialog.c:860 #, c-format msgid "%s is suitable for young children" msgstr "Το %s είναι κατάλληλο για μικρά παιδιά" #: src/bz-age-rating-dialog.c:863 #, c-format msgid "%s is suitable for children" msgstr "Το %s είναι κατάλληλο για παιδιά" #: src/bz-age-rating-dialog.c:866 #, c-format msgid "%s is suitable for teenagers" msgstr "Το %s είναι κατάλληλο για εφήβους" #: src/bz-age-rating-dialog.c:869 #, c-format msgid "%s is suitable for adults" msgstr "Το %s είναι κατάλληλο για ενήλικες" #: src/bz-age-rating-dialog.c:872 #, c-format msgid "%s is suitable for %s" msgstr "Το %s είναι κατάλληλο για %s" #: src/bz-app-size-dialog.blp:43 msgid "--- MB" msgstr "--- MB" #: src/bz-app-size-dialog.blp:53 msgid "Download Size" msgstr "Μέγεθος λήψης" #: src/bz-app-size-dialog.c:55 msgid "Of the size of human DNA" msgstr "Του μεγέθους του ανθρώπινου DNA" #: src/bz-app-size-dialog.c:55 msgid "3 billion base pairs" msgstr "3 δισεκατομμύρια ζεύγη βάσεων" #: src/bz-app-size-dialog.c:56 msgid "Of the Linux Kernel" msgstr "Του πυρήνα Linux" #: src/bz-app-size-dialog.c:56 msgid "linux-6.17.tar.xz" msgstr "linux-6.17.tar.xz" #: src/bz-app-size-dialog.c:57 msgid "Of the Apollo 11 guidance computer" msgstr "Του υπολογιστή πλοήγησης του Apollo 11" #: src/bz-app-size-dialog.c:57 msgid "Total ROM and RAM" msgstr "Συνολική ROM και RAM" #: src/bz-app-size-dialog.c:58 msgid "Of the original Super Mario Bros" msgstr "Από το αρχικό Super Mario Bros" #: src/bz-app-size-dialog.c:58 msgid "On the NES" msgstr "Στο NES" #: src/bz-app-size-dialog.c:59 msgid "Of the size of Wikipedia" msgstr "Του μεγέθους της Wikipedia" #: src/bz-app-size-dialog.c:59 msgid "Without any media" msgstr "Χωρίς κανένα πολυμέσο" #: src/bz-app-tile.blp:84 src/bz-installed-page.blp:25 src/bz-window.blp:298 msgid "Installed" msgstr "Εγκατεστημένες" #: src/bz-apps-page.blp:14 src/bz-full-view.blp:43 src/bz-user-data-page.blp:15 #: src/bz-window.blp:443 msgid "Main Menu" msgstr "Κύριο μενού" #: src/bz-apps-page.blp:17 src/bz-user-data-page.blp:18 src/bz-window.blp:522 msgid "_Donate to Bazaar ❤️" msgstr "_Δωρίστε στο Bazaar ❤️" #: src/bz-apps-page.blp:18 src/bz-user-data-page.blp:19 msgid "_Refresh Content" msgstr "_Ανανέωση περιεχομένου" #: src/bz-apps-page.blp:22 src/bz-user-data-page.blp:22 src/bz-window.blp:529 msgid "_Preferences" msgstr "_Προτιμήσεις" #: src/bz-apps-page.blp:23 src/bz-user-data-page.blp:23 src/bz-window.blp:550 msgid "_Keyboard Shortcuts" msgstr "_Συντομεύσεις πληκτρολογίου" #: src/bz-apps-page.blp:24 src/bz-user-data-page.blp:24 src/bz-window.blp:555 msgid "_About Bazaar" msgstr "_Σχετικά με το Bazaar" #: src/bz-apps-page.blp:28 src/bz-user-data-page.blp:27 src/bz-window.blp:562 msgid "_Quit Bazaar" msgstr "_Κλείστε το Bazaar" #: src/bz-application.c:577 msgid "" "This functionality is currently disabled. It is recommended you download and " "install Flatseal to manage app permissions." msgstr "" "Αυτή η λειτουργία είναι προς το παρόν απενεργοποιημένη. Συνιστάται να " "κατεβάσετε και να εγκαταστήσετε το Flatseal για να διαχειριστείτε τις άδειες " "της εφαρμογής." #: src/bz-application.c:659 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:660 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #: src/bz-application.c:682 msgid "Adam Masciola" msgstr "Adam Masciola" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:685 msgid "translator-credits" msgstr "Xarishark-Zacharias Xenakis" #: src/bz-application.c:749 msgid "Logged Out Successfully!" msgstr "Αποσύνδεση με επιτυχία!" #: src/bz-application.c:855 msgid "Performing setup..." msgstr "Εκτέλεση εγκατάστασης..." #: src/bz-application.c:934 src/bz-application.c:943 msgid "Set Up Flathub" msgstr "Ρύθμιση του Flathub" #: src/bz-application.c:937 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Το Flathub δεν είναι εγκατεστημένο σε αυτό το σύστημα. Δεν θα μπορείτε να " "περιηγηθείτε και να εγκαταστήσετε εφαρμογές στο Bazaar εάν δεν είναι " "διαθέσιμο.\n" "\n" "Μπορείτε ακόμα να χρησιμοποιήσετε το Bazaar για να περιηγηθείτε και να " "καταργήσετε ήδη εγκατεστημένες εφαρμογές." #: src/bz-application.c:942 src/bz-update-dialog.blp:6 msgid "Later" msgstr "Αργότερα" #: src/bz-application.c:1344 msgid "Synchronizing..." msgstr "Συγχρονισμός..." #: src/bz-application.c:1483 #, c-format msgid "Receiving %d entries..." msgstr "Λήψη %d καταχωρήσεων..." #: src/bz-application.c:1488 msgid "Checking for updates" msgstr "Έλεγχος για ενημερώσεις" #: src/bz-curated-view.blp:11 src/bz-flathub-page.blp:19 #: src/bz-full-view.blp:53 src/bz-installed-page.blp:15 #: src/bz-user-data-page.blp:52 src/bz-window.blp:183 msgid "Empty" msgstr "Άδειο" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "Χωρίς επιμέλεια" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "Δεν παρέχονται πληροφορίες σχετικά με την επιμέλεια σε αυτό το σύστημα. " "Μπορείτε να συνεχίσετε να περιηγείστε στις εφαρμογές στο Flathub" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "Περιήγηση στο Flathub" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "Εκτός σύνδεσης" #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 msgid "Browser" msgstr "Πρόγραμμα περιήγησης" #: src/bz-developer-badge.c:131 msgid "Developer information not available." msgstr "Οι πληροφορίες για τον προγραμματιστή δεν είναι διαθέσιμες." #: src/bz-developer-badge.c:137 src/bz-developer-badge.c:151 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "" "Η ιδιοκτησία του αναγνωριστικού εφαρμογής %s δεν έχει επαληθευτεί και " "ενδέχεται να πρόκειται για πακέτο κοινότητας." #: src/bz-developer-badge.c:155 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "" "Η ιδιοκτησία του αναγνωριστικού εφαρμογής %s έχει επαληθευτεί χειροκίνητα " "από την ομάδα του Flathub." #: src/bz-developer-badge.c:161 #, c-format msgid "" "The ownership of the %s app ID has been verified by %s on %s." msgstr "" "Η ιδιοκτησία του αναγνωριστικού εφαρμογής %s έχει επαληθευτεί από τον %s στις %s." #: src/bz-developer-badge.c:168 #, c-format msgid "The ownership of the %s app ID has been verified using %s." msgstr "" "Η ιδιοκτησία του αναγνωριστικού εφαρμογής %s έχει επαληθευτεί " "χρησιμοποιώντας το %s." #: src/bz-developer-badge.c:172 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "Η ιδιοκτησία του αναγνωριστικού εφαρμογής %s έχει επαληθευτεί." #: src/bz-entry-inspector.blp:5 msgid "Entry Inspector" msgstr "Επιθεωρητής εισόδου" #: src/bz-entry-inspector.blp:76 msgid "Serialize" msgstr "Σειριοποίηση" #: src/bz-entry-inspector.blp:80 msgid "Convert to JSON" msgstr "Μετατροπή σε JSON" #: src/bz-error.c:68 msgid "An Error Occurred" msgstr "Παρουσιάστηκε σφάλμα" #: src/bz-error.c:89 msgid "Close" msgstr "Κλείσιμο" #: src/bz-error.c:90 msgid "Copy and Close" msgstr "Αντιγραφή και κλείσιμο" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "Προηγούμενο" #: src/bz-featured-carousel.blp:53 msgid "Next" msgstr "Επόμενο" #: src/bz-featured-tile.blp:88 msgid "App of the Day" msgstr "Εφαρμογή της ημέρας" #: src/bz-flathub-category.c:78 msgid "Audio & Video" msgstr "Ήχος & Βίντεο" #: src/bz-flathub-category.c:78 msgid "Media" msgstr "Πολυμέσα" #: src/bz-flathub-category.c:78 msgid "More Audio & Video" msgstr "Περισσότερα Ήχος & Βίντεο" #: src/bz-flathub-category.c:79 msgid "Developer Tools" msgstr "Εργαλεία προγραμματιστή" #: src/bz-flathub-category.c:79 msgid "Develop" msgstr "Προγραμματισμός" #: src/bz-flathub-category.c:79 msgid "More Developer Tools" msgstr "Περισσότερα εργαλεία προγραμματιστή" #: src/bz-flathub-category.c:80 msgid "Education" msgstr "Εκπαίδευση" #: src/bz-flathub-category.c:80 msgid "Learn" msgstr "Μάθηση" #: src/bz-flathub-category.c:80 msgid "More Education" msgstr "Περισσότερη Μάθηση" #: src/bz-flathub-category.c:81 msgid "Gaming" msgstr "Παιχνίδια" #: src/bz-flathub-category.c:81 msgid "Play" msgstr "Παιχνίδι" #: src/bz-flathub-category.c:81 msgid "More Gaming" msgstr "Περισσότερα παιχνίδια" #: src/bz-flathub-category.c:82 msgid "Graphics & Photography" msgstr "Γραφικά & Φωτογραφία" #: src/bz-flathub-category.c:82 msgid "Create" msgstr "Δημιουργία" #: src/bz-flathub-category.c:82 msgid "More Graphics & Photography" msgstr "Περισσότερα Γραφικά & Φωτογραφία" #: src/bz-flathub-category.c:83 msgid "Networking" msgstr "Δικτύωση" #: src/bz-flathub-category.c:83 msgid "Internet" msgstr "Διαδίκτυο" #: src/bz-flathub-category.c:83 msgid "More Networking" msgstr "Περισσότερη Δικτύωση" #: src/bz-flathub-category.c:84 msgid "Productivity" msgstr "Παραγωγικότητα" #: src/bz-flathub-category.c:84 msgid "Work" msgstr "Εργασία" #: src/bz-flathub-category.c:84 msgid "More Productivity" msgstr "Περισσότερη Παραγωγικότητα" #: src/bz-flathub-category.c:85 msgid "Science" msgstr "Επιστήμη" #: src/bz-flathub-category.c:85 msgid "More Science" msgstr "Περισσότερη Επιστήμη" #: src/bz-flathub-category.c:86 msgid "System" msgstr "Σύστημα" #: src/bz-flathub-category.c:86 msgid "More System" msgstr "Περισσότερο Σύστημα" #: src/bz-flathub-category.c:87 msgid "Utilities" msgstr "Βοηθητικά προγράμματα" #: src/bz-flathub-category.c:87 msgid "Tools" msgstr "Εργαλεία" #: src/bz-flathub-category.c:87 msgid "More Utilities" msgstr "Περισσότερα βοηθητικά προγράμματα" #: src/bz-flathub-category.c:88 src/bz-flathub-page.blp:119 #: src/bz-flathub-page.blp:152 msgid "Trending" msgstr "Τάσεις" #: src/bz-flathub-category.c:88 msgid "More Trending" msgstr "Περισσότερες Τάσεις" #: src/bz-flathub-category.c:89 src/bz-flathub-page.blp:125 #: src/bz-flathub-page.blp:185 msgid "Popular" msgstr "Δημοφιλείς" #: src/bz-flathub-category.c:89 msgid "More Popular" msgstr "Περισσότερα Δημοφιλή" #: src/bz-flathub-category.c:90 src/bz-flathub-page.blp:174 msgid "Recently Added" msgstr "Πρόσφατα Προστέθηκαν" #: src/bz-flathub-category.c:90 src/bz-flathub-page.blp:131 msgid "New" msgstr "Νέες" #: src/bz-flathub-category.c:90 msgid "More New" msgstr "Περισσότερες Νέες" #: src/bz-flathub-category.c:91 src/bz-flathub-page.blp:163 msgid "Recently Updated" msgstr "Πρόσφατα Ενημερωμένες" #: src/bz-flathub-category.c:91 src/bz-flathub-page.blp:137 msgid "Updated" msgstr "Ενημερωμένες" #: src/bz-flathub-category.c:91 msgid "More Updated" msgstr "Περισσότερες Ενημερωμένες" #: src/bz-flathub-category.c:92 msgid "Mobile" msgstr "Κινητό" #: src/bz-flathub-category.c:92 msgid "More Mobile" msgstr "Περισσότερα για κινητό" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Το Flathub δεν έχει προστεθεί" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "" "O απομακρυσμένος διακομιστής Flathub δεν βρέθηκε σε καμία από τις " "εγκαταστάσεις Flatpak σας" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "Το Flathub επέστρεψε ένα σφάλμα" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "Επανάληψη σύνδεσης με το Flathub" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Το Flathub δεν είναι διαθέσιμο" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" "Δεν μπορέσαμε να συνδεθούμε στο Flathub. Μπορείτε ακόμα να διαχειριστείτε " "και να αναζητήσετε εφαρμογές." #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "Αναζήτηση εφαρμογών" #: src/bz-flathub-page.blp:270 msgid "On the Go" msgstr "Εν κινήσει" #: src/bz-flathub-page.blp:282 msgid "Apps for your Linux phones and tablets" msgstr "Εφαρμογές για τα τηλέφωνα και τα tablet σας με Linux" #: src/bz-flathub-page.blp:293 msgid "More Mobile Apps" msgstr "Περισσότερες εφαρμογές για κινητά" #: src/bz-flathub-page.blp:328 msgid "More Mobile apps" msgstr "Περισσότερες εφαρμογές για κινητά" #: src/bz-flathub-page.blp:388 msgid "We​ ♥​ Games" msgstr "♥ τα παιχνίδια" #: src/bz-flathub-page.blp:401 msgid "Games and apps to run your favorite titles" msgstr "Παιχνίδια και εφαρμογές για να τρέξετε τους αγαπημένους σας τίτλους" #: src/bz-flathub-page.blp:435 msgid "More Games" msgstr "Περισσότερα παιχνίδια" #: src/bz-flatpak-entry.c:600 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Σελίδα Flathub" #: src/bz-flatpak-entry.c:621 msgctxt "Project URL Type" msgid "Project Website" msgstr "Ιστοσελίδα του έργου" #: src/bz-flatpak-entry.c:625 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Παρακολούθηση ζητημάτων" #: src/bz-flatpak-entry.c:629 msgctxt "Project URL Type" msgid "FAQ" msgstr "FAQ" #: src/bz-flatpak-entry.c:633 msgctxt "Project URL Type" msgid "Help" msgstr "Βοήθεια" #: src/bz-flatpak-entry.c:637 msgctxt "Project URL Type" msgid "Donate" msgstr "Δωρεά" #: src/bz-flatpak-entry.c:643 msgctxt "Project URL Type" msgid "Translate" msgstr "Μετάφραση" #: src/bz-flatpak-entry.c:647 msgctxt "Project URL Type" msgid "Contact" msgstr "Επικοινωνία" #: src/bz-flatpak-entry.c:651 msgctxt "Project URL Type" msgid "Source Code" msgstr "Πηγαίος κώδικας" #: src/bz-flatpak-entry.c:657 msgctxt "Project URL Type" msgid "Contribute" msgstr "Συνεισφέρετε" #: src/bz-full-view.blp:20 src/bz-window.blp:126 src/bz-window.blp:420 msgid "Toggle transaction sidebar" msgstr "Εναλλαγή πλευρικής γραμμής συναλλαγών" #: src/bz-full-view.blp:57 msgid "No Results" msgstr "Κανένα αποτέλεσμα" #: src/bz-full-view.blp:58 msgid "Try a different search query" msgstr "Δοκιμάστε μια διαφορετική αναζήτηση" #: src/bz-full-view.blp:64 src/bz-window.blp:193 msgid "Content" msgstr "Περιεχόμενο" #: src/bz-full-view.blp:210 msgid "Support" msgstr "Υποστήριξη" #: src/bz-full-view.blp:226 msgid "Favorite Count" msgstr "Αριθμός αγαπημένων" #: src/bz-full-view.blp:258 src/bz-full-view.blp:513 msgid "Open" msgstr "Ανοιχτό" #: src/bz-full-view.blp:271 src/bz-full-view.blp:486 msgid "Download & Install Application" msgstr "Λήψη και εγκατάσταση εφαρμογής" #: src/bz-full-view.blp:286 msgid "Uninstall Application" msgstr "Απεγκατάσταση εφαρμογής" #: src/bz-full-view.blp:301 src/bz-full-view.blp:528 msgid "Install Other Version" msgstr "Εγκατάσταση άλλης έκδοσης" #: src/bz-full-view.blp:325 msgid "Size" msgstr "Μέγεθος" #: src/bz-full-view.blp:430 msgid "Downloads /mo" msgstr "Λήψεις /mo" #: src/bz-full-view.blp:547 msgid "Stopped Receiving Core Updates" msgstr "Δεν λαμβάνετε πλέον βασικές ενημερώσεις" #: src/bz-full-view.blp:561 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "Αυτή η εφαρμογή χρησιμοποιεί ένα περιβάλλον εκτέλεσης που δεν λαμβάνει πλέον " "ενημερώσεις ή διορθώσεις ασφαλείας. Η χρήση της ενδέχεται να μην είναι " "ασφαλής." #: src/bz-full-view.blp:644 src/bz-window.c:1240 msgid "Delete Data" msgstr "Διαγραφή δεδομένων" #: src/bz-full-view.blp:778 msgid "Tags:" msgstr "Ετικέτες:" #: src/bz-full-view.c:289 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:296 #, c-format msgid "%.*fM" msgstr "%.*fM" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:303 #, c-format msgid "%.*fK" msgstr "%.*fK" #: src/bz-full-view.c:313 #, c-format msgid "%d downloads in the last 30 days" msgstr "%d λήψεις τις τελευταίες 30 ημέρες" #: src/bz-full-view.c:345 #, c-format msgid "Download size of %s" msgstr "Μέγεθος λήψης του %s" #: src/bz-full-view.c:378 msgid "All Ages" msgstr "Όλες οι ηλικίες" #: src/bz-full-view.c:390 msgid "Age rating information unavailable" msgstr "Πληροφορίες σχετικά με την ηλικιακή βαθμολογία δεν είναι διαθέσιμες" #: src/bz-full-view.c:395 msgid "Suitable for all ages" msgstr "Κατάλληλο για όλες τις ηλικίες" #: src/bz-full-view.c:397 #, c-format msgid "Suitable for ages %d and up" msgstr "Κατάλληλο για ηλικίες %d και άνω" #: src/bz-full-view.c:430 src/bz-full-view.c:435 src/bz-full-view.c:463 #: src/bz-full-view.c:474 msgid "Unknown" msgstr "Άγνωστο" #: src/bz-full-view.c:440 #, c-format msgid "Free software licensed under %s" msgstr "Ελεύθερο λογισμικό με άδεια χρήσης %s" #: src/bz-full-view.c:445 msgid "Free software" msgstr "Ελεύθερο λογισμικό" #: src/bz-full-view.c:448 msgid "Proprietary Software" msgstr "Ιδιόκτητο λογισμικό" #: src/bz-full-view.c:451 #, c-format msgid "Special License: %s" msgstr "Ειδική άδεια: %s" #: src/bz-full-view.c:468 msgid "Free" msgstr "Ελεύθερο" #: src/bz-full-view.c:471 src/bz-license-dialog.c:118 msgid "Proprietary" msgstr "Ιδιόκτητο" #: src/bz-full-view.c:476 src/bz-license-dialog.c:120 msgid "Special License" msgstr "Ειδική άδεια" #: src/bz-full-view.c:496 msgid "Adaptive" msgstr "Προσαρμοστικό" #: src/bz-full-view.c:496 msgid "Desktop Only" msgstr "Μόνο για επιτραπέζιους υπολογιστές" #: src/bz-full-view.c:502 msgid "Works on desktop, tablets, and phones" msgstr "Λειτουργεί σε επιτραπέζιους υπολογιστές, tablet και κινητά τηλέφωνα" #: src/bz-full-view.c:503 msgid "May not work on mobile devices" msgstr "Ενδέχεται να μην λειτουργεί σε κινητές συσκευές" #: src/bz-full-view.c:514 msgid "No URL" msgstr "Χωρίς διεύθυνση URL" #: src/bz-full-view.c:532 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Αυτή η εφαρμογή διαθέτει άδεια FLOSS, που σημαίνει ότι ο πηγαίος κώδικας " "μπορεί να ελεγχθεί για λόγους ασφαλείας." #: src/bz-full-view.c:533 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Αυτή η εφαρμογή διαθέτει ιδιόκτητη άδεια χρήσης, που σημαίνει ότι ο πηγαίος " "κώδικας έχει αναπτυχθεί ιδιωτικά και δεν μπορεί να ελεγχθεί από ανεξάρτητο " "τρίτο μέρος." #: src/bz-full-view.c:540 msgid "More Apps" msgstr "Περισσότερες εφαρμογές" #: src/bz-full-view.c:541 #, c-format msgid "More Apps by %s" msgstr "Περισσότερες εφαρμογές από %s" #: src/bz-full-view.c:548 msgid "Other Apps by this Developer" msgstr "Άλλες εφαρμογές από αυτόν τον προγραμματιστή" #: src/bz-full-view.c:550 src/bz-full-view.c:658 #, c-format msgid "Other Apps by %s" msgstr "Άλλες εφαρμογές από %s" #: src/bz-full-view.c:558 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "" "Το %s δεν είναι εγκατεστημένο, αλλά εξακολουθεί να περιέχει %s " "δεδομένων." #: src/bz-full-view.c:660 msgid "Other Apps" msgstr "Άλλες εφαρμογές" #: src/bz-full-view.c:662 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d Εφαρμογή" msgstr[1] "%d Εφαρμογές" #: src/bz-full-view.c:1010 msgid "Show Less" msgstr "Εμφάνιση λιγότερων" #: src/bz-full-view.c:1010 msgid "Show More" msgstr "Εμφάνιση περισσότερων" #: src/bz-hardware-support-dialog.blp:6 src/bz-hardware-support-dialog.blp:47 msgid "Hardware Support" msgstr "Υποστήριξη υλικού" #: src/bz-hardware-support-dialog.c:69 msgid "Keyboard support" msgstr "Υποστήριξη πληκτρολογίου" #: src/bz-hardware-support-dialog.c:71 msgid "Requires keyboards" msgstr "Απαιτεί πληκτρολόγια" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends keyboards" msgstr "Συνιστά πληκτρολόγια" #: src/bz-hardware-support-dialog.c:73 msgid "Supports keyboards" msgstr "Υποστηρίζει πληκτρολόγια" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for keyboards" msgstr "Άγνωστη υποστήριξη για πληκτρολόγια" #: src/bz-hardware-support-dialog.c:76 msgid "Mouse support" msgstr "Υποστήριξη ποντικιού" #: src/bz-hardware-support-dialog.c:78 msgid "Requires mice or pointing devices" msgstr "Απαιτεί ποντίκια ή συσκευές κατάδειξης" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends mice or pointing devices" msgstr "Συνιστά ποντίκια ή συσκευές κατάδειξης" #: src/bz-hardware-support-dialog.c:80 msgid "Supports mice or pointing devices" msgstr "Υποστηρίζει ποντίκια ή συσκευές κατάδειξης" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for mice or pointing devices" msgstr "Άγνωστη υποστήριξη για ποντίκια ή συσκευές κατάδειξης" #: src/bz-hardware-support-dialog.c:83 msgid "Touchscreen support" msgstr "Υποστήριξη οθόνης αφής" #: src/bz-hardware-support-dialog.c:85 msgid "Requires touchscreens" msgstr "Απαιτεί οθόνες αφής" #: src/bz-hardware-support-dialog.c:86 msgid "Recommends touchscreens" msgstr "Συνιστά οθόνες αφής" #: src/bz-hardware-support-dialog.c:87 msgid "Supports touchscreens" msgstr "Υποστηρίζει οθόνες αφής" #: src/bz-hardware-support-dialog.c:88 msgid "Unknown support for touchscreens" msgstr "Άγνωστη υποστήριξη για οθόνες αφής" #: src/bz-hardware-support-dialog.c:192 msgid "Mobile support" msgstr "Υποστήριξη για κινητά" #: src/bz-hardware-support-dialog.c:193 msgid "Works on mobile devices" msgstr "Λειτουργεί σε κινητές συσκευές" #: src/bz-hardware-support-dialog.c:193 msgid "May not work well on mobile devices" msgstr "Μπορεί να μην λειτουργεί καλά σε κινητές συσκευές" #: src/bz-hardware-support-dialog.c:198 msgid "Desktop support" msgstr "Υποστήριξη επιτραπέζιων υπολογιστών" #: src/bz-hardware-support-dialog.c:199 msgid "Works well on large screens" msgstr "Λειτουργεί καλά σε μεγάλες οθόνες" #: src/bz-hardware-support-dialog.c:233 #, c-format msgid "%s works best on specific hardware" msgstr "Το %s λειτουργεί καλύτερα σε συγκεκριμένο υλικό" #: src/bz-hardware-support-dialog.c:240 #, c-format msgid "%s works on most devices" msgstr "Το %s λειτουργεί στις περισσότερες συσκευές" #: src/bz-inspector.blp:5 msgid "Bazaar Inspector" msgstr "Επιθεωρητής Bazaar" #: src/bz-inspector.blp:33 msgid "Background Task Info:" msgstr "Πληροφορίες για την εργασία παρασκηνίου:" #: src/bz-inspector.blp:43 msgid "Enable Global Debug Mode" msgstr "Ενεργοποίηση καθολικής λειτουργίας αποσφαλμάτωσης" #: src/bz-inspector.blp:50 msgid "Active Blocklists" msgstr "Ενεργές λίστες αποκλεισμένων" #: src/bz-inspector.blp:67 msgid "Active Curated-Configs" msgstr "Ενεργές Επιμελημένες-Ρυθμίσεις" #: src/bz-inspector.blp:85 msgid "All Entry Groups" msgstr "Όλες οι ομάδες εισόδου" #: src/bz-inspector.blp:93 msgid "Filter..." msgstr "Φίλτρο..." #: src/bz-inspector.blp:134 msgid "Decache and Inspect" msgstr "Καθαρισμός cache και Έλεγχος" #: src/bz-installed-page.blp:19 msgid "No Flatpaks Installed" msgstr "Δεν έχουν εγκατασταθεί Flatpaks" #: src/bz-installed-page.c:395 msgid "Choose an Installation" msgstr "Επιλέξτε μια εγκατάσταση" #: src/bz-installed-page.c:398 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with? " msgstr "" "Έχετε εγκαταστήσει πολλές εκδόσεις αυτής της εφαρμογής. Με ποια από αυτές " "θέλετε να συνεχίσετε; " #: src/bz-installed-page.c:402 src/bz-window.c:1270 src/bz-window.c:1293 msgid "Cancel" msgstr "Ακύρωση" #: src/bz-installed-tile.blp:61 src/bz-rich-app-tile.blp:137 msgid "Stopped Receiving Updates" msgstr "Δεν λαμβάνετε πλέον ενημερώσεις" #: src/bz-installed-tile.blp:75 msgid "Support this application" msgstr "Υποστηρίξτε αυτήν την εφαρμογή" #: src/bz-license-dialog.blp:160 msgid "Get Involved" msgstr "Συμμετέχε" #: src/bz-license-dialog.c:107 src/bz-license-dialog.c:112 msgid "Unknown License" msgstr "Άγνωστη άδεια χρήσης" #: src/bz-license-dialog.c:115 msgid "Community Built" msgstr "Δημιουργήθηκε από την Κοινότητα" #: src/bz-license-dialog.c:148 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Αυτή η εφαρμογή έχει αναπτυχθεί ανοιχτά από μια διεθνή κοινότητα και " "διατίθεται με άδεια χρήσης %s.\n" "\n" "Μπορείτε να συμμετάσχετε και να βοηθήσετε να γίνει ακόμα καλύτερη." #: src/bz-license-dialog.c:156 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Αυτή η εφαρμογή έχει αναπτυχθεί ανοιχτά από μια διεθνή κοινότητα.\n" "\n" "Μπορείτε να συμμετάσχετε και να βοηθήσετε να γίνει ακόμα καλύτερη." #: src/bz-license-dialog.c:161 msgid "The license of this app is not known" msgstr "Η άδεια χρήσης αυτής της εφαρμογής δεν είναι γνωστή" #: src/bz-license-dialog.c:165 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Αυτή η εφαρμογή δεν έχει αναπτυχθεί ανοιχτά, επομένως μόνο οι " "προγραμματιστές της γνωρίζουν πώς λειτουργεί. Μπορεί να είναι ανασφαλής με " "τρόπους που είναι δύσκολο να εντοπιστούν και μπορεί να αλλάξει χωρίς " "εποπτεία.\n" "\n" "Μπορεί να έχετε ή να μην έχετε τη δυνατότητα να συνεισφέρετε σε αυτήν την " "εφαρμογή." #: src/bz-license-dialog.c:174 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Αυτή η εφαρμογή έχει αναπτυχθεί με την ειδική άδεια %s.\n" "\n" "Μπορεί να έχετε ή να μην έχετε τη δυνατότητα να συνεισφέρετε σε αυτήν την " "εφαρμογή." #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Προτιμήσεις" #: src/bz-preferences-dialog.blp:23 msgid "Content Filters" msgstr "Φίλτρα περιεχομένου" #: src/bz-preferences-dialog.blp:26 msgid "Free Software Only" msgstr "Μόνο ελεύθερο λογισμικό" #: src/bz-preferences-dialog.blp:27 msgid "Hide proprietary applications when browsing and searching" msgstr "Απόκρυψη ιδιόκτητων εφαρμογών κατά την περιήγηση και την αναζήτηση" #: src/bz-preferences-dialog.blp:31 msgid "Flathub Results Only" msgstr "Αποτελέσματα μόνο από το Flathub" #: src/bz-preferences-dialog.blp:32 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "" "Περιορίστε τα αποτελέσματα αναζήτησης και περιήγησης σε εφαρμογές που είναι " "διαθέσιμες μόνο στο Flathub" #: src/bz-preferences-dialog.blp:36 msgid "Hide EOL Apps" msgstr "Απόκρυψη εφαρμογών EOL" #: src/bz-preferences-dialog.blp:37 msgid "Hide apps which are no longer supported by their developers" msgstr "" "Απόκρυψη εφαρμογών που δεν υποστηρίζονται πλέον από τους προγραμματιστές τους" #: src/bz-preferences-dialog.blp:42 src/bz-window.blp:313 msgid "Search" msgstr "Αναζήτηση" #: src/bz-preferences-dialog.blp:45 msgid "Delay Search Results" msgstr "Αναβολή αποτελεσμάτων αναζήτησης" #: src/bz-preferences-dialog.blp:46 msgid "Improve results performance by debouncing search terms" msgstr "" "Βελτιώστε την απόδοση των αποτελεσμάτων με την απομάκρυνση των όρων " "αναζήτησης" #: src/bz-preferences-dialog.blp:51 msgid "Progress Bar" msgstr "Μπάρα προόδου" #: src/bz-preferences-dialog.blp:52 msgid "Choose a theme for the progress bar!" msgstr "Επιλέξτε ένα θέμα για τη μπάρα προόδου!" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Χρώμα έμφασης" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Χρώματα υπερηφάνειας" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "Χρώματα Υπερηφάνειας Λεσβιών" #: src/bz-preferences-dialog.c:35 msgid "Transgender Pride Colors" msgstr "Χρώματα Υπερηφάνειας Τρανς" #: src/bz-preferences-dialog.c:36 msgid "Nonbinary Pride Colors" msgstr "Χρώματα Υπερηφάνειας Nonbinary" #: src/bz-preferences-dialog.c:37 msgid "Bisexual Pride Colors" msgstr "Χρώματα Υπερηφάνειας Bisexual" #: src/bz-preferences-dialog.c:38 msgid "Asexual Pride Colors" msgstr "Χρώματα Υπερηφάνειας Asexual" #: src/bz-preferences-dialog.c:39 msgid "Pansexual Pride Colors" msgstr "Χρώματα Υπερηφάνειας Pansexual" #: src/bz-preferences-dialog.c:40 msgid "Aromantic Pride Colors" msgstr "Χρώματα Υπερηφάνειας Aromantic" #: src/bz-preferences-dialog.c:41 msgid "Genderfluid Pride Colors" msgstr "Χρώματα Υπερηφάνειας Genderfluid" #: src/bz-preferences-dialog.c:42 msgid "Polysexual Pride Colors" msgstr "Χρώματα Υπερηφάνειας Polysexual" #: src/bz-preferences-dialog.c:43 msgid "Omnisexual Pride Colors" msgstr "Χρώματα Υπερηφάνειας Omnisexual" #: src/bz-preferences-dialog.c:44 msgid "Aroace Pride Colors" msgstr "Χρώματα Υπερηφάνειας Aroace" #: src/bz-preferences-dialog.c:45 msgid "Agender Pride Colors" msgstr "Χρώματα Υπερηφάνειας Agender" #: src/bz-preferences-dialog.c:46 msgid "Genderqueer Pride Colors" msgstr "Χρώματα Υπερηφάνειας Genderqueer" #: src/bz-preferences-dialog.c:47 msgid "Intersex Pride Colors" msgstr "Χρώματα Υπερηφάνειας Intersex" #: src/bz-preferences-dialog.c:48 msgid "Demigender Pride Colors" msgstr "Χρώματα Υπερηφάνειας Demigender" #: src/bz-preferences-dialog.c:49 msgid "Biromantic Pride Colors" msgstr "Χρώματα Υπερηφάνειας Biromantic" #: src/bz-releases-dialog.blp:5 src/bz-releases-list.blp:26 msgid "Version History" msgstr "Ιστορικό εκδόσεων" #: src/bz-releases-list.c:128 #, c-format msgid "Version %s" msgstr "Έκδοση %s" #: src/bz-releases-list.c:153 msgid "No details for this release" msgstr "Δεν υπάρχουν λεπτομέρειες για αυτήν την έκδοση" #: src/bz-rich-app-tile.blp:154 msgid "Get" msgstr "Λήψη" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "Στιγμιότυπα οθόνης" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "Προηγούμενο στιγμιότυπο οθόνης" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "Επόμενο στιγμιότυπο οθόνης" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "Αντιγραφή εικόνας" #: src/bz-screenshot-page.blp:147 msgid "Reset View" msgstr "Επαναφορά προβολής" #: src/bz-screenshot-page.blp:158 msgid "Zoom Out" msgstr "Σμίκρυνση" #: src/bz-screenshot-page.blp:168 msgid "Zoom In" msgstr "Μεγέθυνση" #: src/bz-screenshots-carousel.blp:6 msgid "Screenshots Carousel" msgstr "Καρουζέλ Στιγμιότυπων Οθόνης" #: src/bz-screenshots-carousel.blp:104 msgid "Open Screenshot Viewer" msgstr "Άνοιγμα προγράμματος προβολής στιγμιότυπων οθόνης" #: src/bz-search-widget.blp:106 msgid "Search Apps, Games, Software" msgstr "Αναζήτηση εφαρμογών, παιχνιδιών, λογισμικού" #: src/bz-search-widget.blp:150 msgid "Categories Unavailable" msgstr "Κατηγορίες Μη διαθέσιμες" #: src/bz-search-widget.blp:151 msgid "Search for apps using the search bar above." msgstr "Αναζητήστε εφαρμογές χρησιμοποιώντας τη γραμμή αναζήτησης παραπάνω." #: src/bz-search-widget.blp:235 msgid "No Applications Found" msgstr "Δεν βρέθηκαν εφαρμογές" #: src/bz-search-widget.c:241 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "Δεν βρέθηκαν αποτελέσματα για το \"%s\" στο Flathub" #: src/bz-share-list.c:64 msgid "Copied!" msgstr "Αντιγράφηκε!" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "Αντιγραφή συνδέσμου" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Άνοιγμα συνδέσμου" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "Χρονοδιάγραμμα" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "Εγκαταστάσεις:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "Κόσμος" #: src/bz-tag-list.c:96 msgid "No Results Found" msgstr "Δεν βρέθηκαν αποτελέσματα" #: src/bz-tag-list.c:108 #, c-format msgid "Apps Tagged \"%s\"" msgstr "Εφαρμογές με ετικέτα \"%s\"" #: src/bz-tag-list.c:109 #, c-format msgid "%d Applications" msgstr "%d Εφαρμογές" #: src/bz-tag-list.c:124 msgid "Search failed" msgstr "Η αναζήτηση απέτυχε" #: src/bz-transaction-manager.c:1135 #, c-format msgid "Finished in %.02f seconds" msgstr "Ολοκληρώθηκε σε %.02f δευτερόλεπτα" #: src/bz-transaction-view.blp:95 msgid "App Add-on" msgstr "Πρόσθετο εφαρμογής" #: src/bz-transaction-view.blp:120 msgid "Runtime" msgstr "Περιβάλλον εκτέλεσης" #: src/bz-transaction-view.blp:146 src/bz-transaction-view.blp:172 msgid "Install Size" msgstr "Μέγεθος εγκατάστασης" #: src/bz-transaction-view.blp:200 msgid "Update" msgstr "Ενημέρωση" #: src/bz-transaction-view.c:139 #, c-format msgid "Transferred %s so far" msgstr "Μεταφέρθηκαν %s μέχρι τώρα" #: src/bz-transaction.c:336 msgid "Pending" msgstr "Σε εκκρεμότητα" #: src/bz-update-dialog.blp:7 msgid "Install Now" msgstr "Εγκατάσταση τώρα" #: src/bz-update-dialog.blp:10 msgid "Updates Are Available" msgstr "Διατίθενται ενημερώσεις" #: src/bz-update-dialog.blp:11 msgid "" "The following applications are eligible for updates. Would you like to " "install them?" msgstr "" "Οι ακόλουθες εφαρμογές είναι επιλέξιμες για ενημερώσεις. Θέλετε να τις " "εγκαταστήσετε;" #: src/bz-update-dialog.c:134 #, c-format msgid "" "%d runtimes and/or addons are eligible for updates. Would you like to " "install them?" msgstr "" "%d περιβάλλοντα εκτέλεσης και/ή πρόσθετα είναι επιλέξιμα για ενημερώσεις. " "Θέλετε να τα εγκαταστήσετε;" #: src/bz-update-dialog.c:142 #, c-format msgid "Additionally, %d runtimes and/or addons will be updated." msgstr "Επιπλέον, θα ενημερωθούν %d περιβάλλοντα εκτέλεσης και/ή πρόσθετα." #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "Διαχείριση υπολειπόμενων δεδομένων χρήστη" #: src/bz-user-data-page.blp:41 msgid "Loading" msgstr "Φόρτωση" #: src/bz-user-data-page.blp:55 msgid "No User Data found" msgstr "Δεν βρέθηκαν δεδομένα χρήστη" #: src/bz-user-data-page.blp:60 msgid "User Data" msgstr "Δεδομένα χρήστη" #: src/bz-user-data-tile.c:144 #, c-format msgid "Removed User Data for %s" msgstr "Διαγράφηκαν τα δεδομένα χρήστη για %s" #: src/bz-user-data-tile.blp:74 msgid "Remove User Data" msgstr "Κατάργηση δεδομένων χρήστη" #: src/bz-window.blp:66 msgid "Inspect UI Entry" msgstr "Επιθεώρηση εισόδου UI" #: src/bz-window.blp:73 msgid "All Debug Actions" msgstr "Όλες οι ενέργειες εντοπισμού σφαλμάτων" #: src/bz-window.blp:107 msgid "Tasks" msgstr "Εργασίες" #: src/bz-window.blp:163 msgid "Stop Active Tasks" msgstr "Διακοπή ενεργών εργασιών" #: src/bz-window.blp:171 msgid "Clear History" msgstr "Εκκαθάριση ιστορικού" #: src/bz-window.blp:187 msgid "No Tasks Yet" msgstr "Δεν υπάρχουν ακόμη εργασίες" #: src/bz-window.blp:258 msgid "Refreshing Store Content" msgstr "Ανανέωση περιεχομένου καταστήματος" #: src/bz-window.blp:273 msgid "Curated" msgstr "Επιμελημένες" #: src/bz-window.blp:286 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:450 msgid "Network connection is metered — automatic store data sync is paused" msgstr "" "Η σύνδεση δικτύου μετράται — η αυτόματη συγχρονισμός δεδομένων του " "καταστήματος έχει παυθεί" #: src/bz-window.blp:451 src/bz-window.blp:460 msgid "Sync Manually" msgstr "Χειροκίνητος συγχρονισμός" #: src/bz-window.blp:459 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "" "Έχετε σύνδεση στο δίκτυο, αλλά βλέπετε μια προσωρινά αποθηκευμένη έκδοση του " "Flathub" #: src/bz-window.blp:534 msgid "_Login with Flathub" msgstr "_Σύνδεση με το Flathub" #: src/bz-window.blp:540 msgid "_Manage Leftover User Data" msgstr "_Διαχείριση υπολειπόμενων δεδομένων χρήστη" #: src/bz-window.blp:545 msgid "_Synchronize Remotes" msgstr "_Συγχρονισμός απομακρυσμένου διακομιστής" #: src/bz-window.blp:571 msgid "Open Bazaar Inspector" msgstr "Άνοιγμα Επιθεωρητή Bazaar" #: src/bz-window.blp:580 msgid "Log Out" msgstr "Αποσύνδεση" #: src/bz-window.c:475 #, c-format msgid "%d Update Available" msgid_plural "%d Updates Available" msgstr[0] "%d Διαθέσιμη ενημέρωση" msgstr[1] "%d Διαθέσιμες ενημερώσεις" #: src/bz-window.c:973 msgid "" "The ability to inspect and install local .flatpak bundle files is coming " "soon! In the meantime, try running\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "on the command line." msgstr "" "Η δυνατότητα ελέγχου και εγκατάστασης τοπικών αρχείων πακέτων .flatpak θα " "είναι διαθέσιμη σύντομα! Εν τω μεταξύ, δοκιμάστε να εκτελέσετε την εντολή\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "στη γραμμή εντολών." #: src/bz-window.c:1100 msgid "Can't do that right now!" msgstr "Δεν μπορεί να γίνει αυτή τη στιγμή!" #: src/bz-window.c:1231 msgid "Keep Data" msgstr "Διατήρηση δεδομένων" #: src/bz-window.c:1232 msgid "Allow restoring settings and content" msgstr "Επιτρέψτε την επαναφορά ρυθμίσεων και περιεχομένου" #: src/bz-window.c:1241 msgid "Permanently remove app data to save space" msgstr "Διαγράψτε μόνιμα τα δεδομένα των εφαρμογών για να εξοικονομήσετε χώρο" #: src/bz-window.c:1264 #, c-format msgid "Install %s?" msgstr "Εγκατάσταση %s?" #: src/bz-window.c:1267 msgid "May install additional shared components" msgstr "Μπορεί να εγκαταστήσει επιπλέον κοινόχρηστα στοιχεία" #: src/bz-window.c:1286 #, c-format msgid "Remove %s?" msgstr "Αφαίρεση %s?" #: src/bz-window.c:1290 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "Δεν θα είναι δυνατή η χρήση του %s μετά την απεγκατάστασή του." #: src/bz-window.c:1353 msgid "Resume Current Tasks" msgstr "Συνέχιση τρεχουσών εργασιών" #: src/bz-window.c:1359 msgid "Pause Current Tasks" msgstr "Παύση τρέχουσων εργασιών" #: src/bz-world-map.c:572 #, c-format msgid "%s: %'u downloads" msgstr "%s: %'u λήψεις" #: src/gtk/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Γενικά" #: src/gtk/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "Άνοιγμα Διαλόγου Αναζήτησης" #: src/gtk/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Άνοιγμα Προτιμήσεων" #: src/gtk/shortcuts-dialog.blp:19 msgctxt "shortcut window" msgid "Refresh" msgstr "Ανανέωση" #: src/gtk/shortcuts-dialog.blp:24 msgctxt "shortcut window" msgid "Toggle Transaction Manager" msgstr "Εναλλαγή Διαχειριστή Συναλλαγών" #: src/gtk/shortcuts-dialog.blp:29 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Εμφάνιση συντομεύσεων" #: src/gtk/shortcuts-dialog.blp:34 msgctxt "shortcut window" msgid "Quit" msgstr "Έξοδος" bazaar-orig-v0.7.14/po/vi.po0000664000175000017500000013760615166123241014551 0ustar hasanhasan# Vietnamese translations for bazaar package. # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # Loc Huynh , 2025. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-12-02 18:34+0700\n" "PO-Revision-Date: 2025-12-10 18:23+0700\n" "Last-Translator: Loc Huynh \n" "Language-Team: Vietnamese \n" "Language: vi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Gtranslator 49.0\n" #: data/io.github.kolunmi.Bazaar.desktop.in:3 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:5 #: src/bz-window.blp:234 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:4 msgid "Add, remove or update flatpak software on this computer" msgstr "Thêm, xóa hoặc cập nhật phần mềm Flatpak trên máy tính này" #: data/io.github.kolunmi.Bazaar.desktop.in:10 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "" "GTK;System;PackageManager;Discover;Flatpak;Software;Store;Trình quản lý gói; " "Khám phá; Phần mềm; Cửa hàng;" #: data/io.github.kolunmi.Bazaar.gschema.xml:6 msgid "Hide EOL Entries" msgstr "Ẩn các mục EOL" #: data/io.github.kolunmi.Bazaar.gschema.xml:7 msgid "Hide EOL entries and entries depending on them" msgstr "Ẩn các mục EOL và các mục phụ thuộc vào chúng" #: data/io.github.kolunmi.Bazaar.gschema.xml:11 msgid "Show Git Forge Star Counts" msgstr "Hiển thị số sao trên Git Forge" #: data/io.github.kolunmi.Bazaar.gschema.xml:12 msgid "" "Whether to attempt to detect and show \"star counts\" for projects in the " "full view" msgstr "" "Có cố gắng phát hiện và hiển thị \"số sao\" cho các dự án trong chế độ xem " "chi tiết hay không" #: data/io.github.kolunmi.Bazaar.gschema.xml:16 msgid "Only Show Free Software" msgstr "Chỉ hiển thị phần mềm miễn phí" #: data/io.github.kolunmi.Bazaar.gschema.xml:17 msgid "Hide proprietary software" msgstr "Ẩn phần mềm độc quyền" #: data/io.github.kolunmi.Bazaar.gschema.xml:21 msgid "Show Only Flathub Content" msgstr "Chỉ hiển thị nội dung Flathub" #: data/io.github.kolunmi.Bazaar.gschema.xml:22 msgid "Hide applications which do not originate from Flathub" msgstr "Ẩn các ứng dụng không có nguồn gốc từ Flathub" #: data/io.github.kolunmi.Bazaar.gschema.xml:26 msgid "Debounce Search Inputs" msgstr "Trì hoãn tìm kiếm" #: data/io.github.kolunmi.Bazaar.gschema.xml:27 msgid "Add a delay before searching to prevent instant replies while typing" msgstr "Thêm độ trễ trước khi tìm kiếm để tránh phản hồi tức thì khi đang gõ" #: data/io.github.kolunmi.Bazaar.gschema.xml:51 msgid "Global Progress Bar Theme" msgstr "Chủ đề thanh tiến trình toàn cục" #: data/io.github.kolunmi.Bazaar.gschema.xml:52 msgid "Describes the look of the global progress bar" msgstr "Mô tả giao diện của thanh tiến trình toàn cục" #: data/io.github.kolunmi.Bazaar.gschema.xml:56 msgid "Saved Window Dimensions" msgstr "Kích thước cửa sổ đã lưu" #: data/io.github.kolunmi.Bazaar.gschema.xml:57 msgid "The window dimensions to be used by the next Bazaar window" msgstr "Kích thước cửa sổ sẽ được sử dụng cho cửa sổ Bazaar tiếp theo" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and install applications" msgstr "Khám phá và cài đặt ứng dụng" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A new app store for GNOME with a focus on discovering and installing " "applications and addons from Flatpak remotes, particularly Flathub." msgstr "" "Một cửa hàng ứng dụng mới cho GNOME tập trung vào việc khám phá và cài đặt " "ứng dụng cùng tiện ích mở rộng từ các remote Flatpak, đặc biệt là Flathub." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:14 msgid "" "It emphasizes supporting the developers who make the Linux desktop possible. " "Bazaar features a \"curated\" tab that can be configured by distributors to " "allow for a more localized experience." msgstr "" "Nó nhấn mạnh việc hỗ trợ các nhà phát triển làm nên môi trường desktop " "Linux. Bazaar có tab \"chọn lọc\" có thể được nhà phân phối cấu hình để mang " "lại trải nghiệm địa phương hóa tốt hơn." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:29 src/bz-application.c:661 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:54 msgid "The home page displaying Flathub apps" msgstr "Trang chủ hiển thị các ứng dụng Flathub" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:58 msgid "Nucleus app page" msgstr "Trang ứng dụng Nucleus" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:62 msgid "Search page" msgstr "Trang tìm kiếm" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:66 msgid "Category page" msgstr "Trang danh mục" #: src/bz-addons-dialog.blp:14 src/bz-full-view.blp:668 msgid "Manage Add-ons" msgstr "Quản lý tiện ích mở rộng" #: src/bz-addons-dialog.c:90 src/bz-full-view.blp:505 #: src/bz-transaction-view.blp:212 src/bz-window.c:1125 msgid "Remove" msgstr "Gỡ bỏ" #: src/bz-addons-dialog.c:95 src/bz-full-view.blp:277 src/bz-full-view.blp:492 #: src/bz-transaction-view.blp:186 src/bz-window.c:1102 msgid "Install" msgstr "Cài đặt" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:50 #: src/bz-full-view.c:385 src/bz-full-view.c:392 msgid "Age Rating" msgstr "Xếp hạng độ tuổi" #: src/bz-age-rating-dialog.blp:40 src/bz-age-rating-dialog.c:790 msgid "?" msgstr "?" #: src/bz-age-rating-dialog.c:139 msgid "Cartoon Violence" msgstr "Bạo lực hoạt hình" #: src/bz-age-rating-dialog.c:140 msgid "No information regarding cartoon violence" msgstr "Không có thông tin về bạo lực hoạt hình" #: src/bz-age-rating-dialog.c:143 msgid "Fantasy Violence" msgstr "Bạo lực giả tưởng" #: src/bz-age-rating-dialog.c:144 msgid "No information regarding fantasy violence" msgstr "Không có thông tin về bạo lực giả tưởng" #: src/bz-age-rating-dialog.c:147 msgid "Realistic Violence" msgstr "Bạo lực thực tế" #: src/bz-age-rating-dialog.c:148 msgid "No information regarding realistic violence" msgstr "Không có thông tin về bạo lực thực tế" #: src/bz-age-rating-dialog.c:151 msgid "Violence Depicting Bloodshed" msgstr "Bạo lực có máu" #: src/bz-age-rating-dialog.c:152 msgid "No information regarding bloodshed" msgstr "Không có thông tin về cảnh đổ máu" #: src/bz-age-rating-dialog.c:155 msgid "Sexual Violence" msgstr "Bạo lực tình dục" #: src/bz-age-rating-dialog.c:156 msgid "No information regarding sexual violence" msgstr "Không có thông tin về bạo lực tình dục" #: src/bz-age-rating-dialog.c:159 msgid "Alcohol" msgstr "Rượu bia" #: src/bz-age-rating-dialog.c:160 msgid "No information regarding references to alcohol" msgstr "Không có thông tin về đề cập đến rượu bia" #: src/bz-age-rating-dialog.c:163 msgid "Narcotics" msgstr "Ma túy" #: src/bz-age-rating-dialog.c:164 msgid "No information regarding references to illicit drugs" msgstr "Không có thông tin về đề cập đến ma túy" #: src/bz-age-rating-dialog.c:167 msgid "Tobacco" msgstr "Thuốc lá" #: src/bz-age-rating-dialog.c:168 msgid "No information regarding references to tobacco products" msgstr "Không có thông tin về đề cập đến sản phẩm thuốc lá" #: src/bz-age-rating-dialog.c:171 src/bz-age-rating-dialog.c:358 msgid "Nudity" msgstr "Khỏa thân" #: src/bz-age-rating-dialog.c:172 msgid "No information regarding nudity of any sort" msgstr "Không có thông tin về cảnh khỏa thân" #: src/bz-age-rating-dialog.c:175 msgid "Sexual Themes" msgstr "Chủ đề tình dục" #: src/bz-age-rating-dialog.c:176 msgid "No information regarding references to or depictions of sexual nature" msgstr "Không có thông tin về đề cập hoặc mô tả tính chất tình dục" #: src/bz-age-rating-dialog.c:179 msgid "Profanity" msgstr "Ngôn từ thô tục" #: src/bz-age-rating-dialog.c:180 msgid "No information regarding profanity of any kind" msgstr "Không có thông tin về ngôn từ thô tục" #: src/bz-age-rating-dialog.c:183 msgid "Inappropriate Humor" msgstr "Hài không phù hợp" #: src/bz-age-rating-dialog.c:184 msgid "No information regarding inappropriate humor" msgstr "Không có thông tin về hài không phù hợp" #: src/bz-age-rating-dialog.c:187 msgid "Discrimination" msgstr "Kỳ thị" #: src/bz-age-rating-dialog.c:188 msgid "No information regarding discriminatory language of any kind" msgstr "Không có thông tin về ngôn ngữ kỳ thị" #: src/bz-age-rating-dialog.c:191 msgid "Advertising" msgstr "Quảng cáo" #: src/bz-age-rating-dialog.c:192 msgid "No information regarding advertising of any kind" msgstr "Không có thông tin về quảng cáo" #: src/bz-age-rating-dialog.c:195 msgid "Gambling" msgstr "Cờ bạc" #: src/bz-age-rating-dialog.c:196 msgid "No information regarding gambling of any kind" msgstr "Không có thông tin về cờ bạc" #: src/bz-age-rating-dialog.c:199 msgid "Purchasing" msgstr "Mua hàng" #: src/bz-age-rating-dialog.c:200 msgid "No information regarding the ability to spend money" msgstr "Không có thông tin về khả năng chi tiêu tiền" #: src/bz-age-rating-dialog.c:203 msgid "Chat Between Users" msgstr "Trò chuyện giữa người dùng" #: src/bz-age-rating-dialog.c:204 msgid "No information regarding ways to chat with other users" msgstr "Không có thông tin về cách trò chuyện với người dùng khác" #: src/bz-age-rating-dialog.c:207 msgid "Audio Chat Between Users" msgstr "Trò chuyện âm thanh giữa người dùng" #: src/bz-age-rating-dialog.c:208 msgid "No information regarding ways to talk with other users" msgstr "Không có thông tin về cách nói chuyện với người dùng khác" #: src/bz-age-rating-dialog.c:211 msgid "Contact Details" msgstr "Thông tin liên hệ" #: src/bz-age-rating-dialog.c:212 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "" "Không có thông tin về việc chia sẻ tên người dùng mạng xã hội hoặc địa chỉ " "email" #: src/bz-age-rating-dialog.c:215 msgid "Identifying Information" msgstr "Thông tin nhận dạng" #: src/bz-age-rating-dialog.c:216 msgid "No information regarding sharing of user information with third parties" msgstr "Không có thông tin về việc chia sẻ thông tin người dùng với bên thứ ba" #: src/bz-age-rating-dialog.c:219 msgid "Location Sharing" msgstr "Chia sẻ vị trí" #: src/bz-age-rating-dialog.c:220 msgid "No information regarding sharing of physical location with other users" msgstr "Không có thông tin về việc chia sẻ vị trí thực với người dùng khác" #: src/bz-age-rating-dialog.c:223 msgid "Prostitution" msgstr "Mại dâm" #: src/bz-age-rating-dialog.c:224 msgid "No information regarding references to prostitution" msgstr "Không có thông tin về đề cập đến mại dâm" #: src/bz-age-rating-dialog.c:227 msgid "Adultery" msgstr "Ngoại tình" #: src/bz-age-rating-dialog.c:228 msgid "No information regarding references to adultery" msgstr "Không có thông tin về đề cập đến ngoại tình" #: src/bz-age-rating-dialog.c:231 msgid "Sexualized Characters" msgstr "Nhân vật tình dục hóa" #: src/bz-age-rating-dialog.c:232 msgid "No information regarding sexualized characters" msgstr "Không có thông tin về nhân vật tình dục hóa" #: src/bz-age-rating-dialog.c:235 msgid "Desecration" msgstr "Báng bổ" #: src/bz-age-rating-dialog.c:236 msgid "No information regarding references to desecration" msgstr "Không có thông tin về đề cập đến báng bổ" #: src/bz-age-rating-dialog.c:239 msgid "Human Remains" msgstr "Xác người" #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "Không có thông tin về hiển thị xác người chết" #: src/bz-age-rating-dialog.c:243 msgid "Slavery" msgstr "Nô lệ" #: src/bz-age-rating-dialog.c:244 msgid "No information regarding references to slavery" msgstr "Không có thông tin về đề cập đến chế độ nô lệ" #: src/bz-age-rating-dialog.c:307 msgid "Does not include references to drugs" msgstr "Không đề cập đến ma túy" #: src/bz-age-rating-dialog.c:309 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "Không chứa chửi thề, ngôn từ thô tục và các loại ngôn ngữ mạnh khác" #: src/bz-age-rating-dialog.c:311 msgid "Does not include ads or monetary transactions" msgstr "Không chứa quảng cáo hoặc giao dịch tiền tệ" #: src/bz-age-rating-dialog.c:313 msgid "Does not include sex or nudity" msgstr "Không chứa tình dục hoặc khỏa thân" #: src/bz-age-rating-dialog.c:315 msgid "Does not include uncontrolled chat functionality" msgstr "Không có chức năng trò chuyện không kiểm soát" #: src/bz-age-rating-dialog.c:317 msgid "Does not include violence" msgstr "Không chứa bạo lực" #: src/bz-age-rating-dialog.c:352 msgid "Drugs" msgstr "Ma túy" #: src/bz-age-rating-dialog.c:354 msgid "Strong Language" msgstr "Ngôn ngữ mạnh" #: src/bz-age-rating-dialog.c:356 msgid "Money" msgstr "Tiền bạc" #: src/bz-age-rating-dialog.c:360 msgid "Social" msgstr "Xã hội" #: src/bz-age-rating-dialog.c:362 msgid "Violence" msgstr "Bạo lực" #: src/bz-age-rating-dialog.c:564 #, c-format msgid "%s • %s" msgstr "%s • %s" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:752 src/bz-full-view.c:375 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:782 msgctxt "Age rating" msgid "All" msgstr "Mọi lứa tuổi" #: src/bz-age-rating-dialog.c:846 #, c-format msgid "%s has an unknown age rating" msgstr "%s có xếp hạng độ tuổi không xác định" #: src/bz-age-rating-dialog.c:854 #, c-format msgid "%s is suitable for everyone" msgstr "%s phù hợp với mọi người" #: src/bz-age-rating-dialog.c:857 #, c-format msgid "%s is suitable for toddlers" msgstr "%s phù hợp với trẻ mẫu giáo" #: src/bz-age-rating-dialog.c:860 #, c-format msgid "%s is suitable for young children" msgstr "%s phù hợp với trẻ nhỏ" #: src/bz-age-rating-dialog.c:863 #, c-format msgid "%s is suitable for children" msgstr "%s phù hợp với trẻ em" #: src/bz-age-rating-dialog.c:866 #, c-format msgid "%s is suitable for teenagers" msgstr "%s phù hợp với thiếu niên" #: src/bz-age-rating-dialog.c:869 #, c-format msgid "%s is suitable for adults" msgstr "%s phù hợp với người lớn" #: src/bz-age-rating-dialog.c:872 #, c-format msgid "%s is suitable for %s" msgstr "%s phù hợp với %s" #: src/bz-app-size-dialog.blp:43 msgid "--- MB" msgstr "--- MB" #: src/bz-app-size-dialog.blp:53 msgid "Download Size" msgstr "Kích thước tải về" #: src/bz-app-size-dialog.c:55 msgid "Of the size of human DNA" msgstr "Kích thước của DNA người" #: src/bz-app-size-dialog.c:55 msgid "3 billion base pairs" msgstr "3 tỷ cặp base" #: src/bz-app-size-dialog.c:56 msgid "Of the Linux Kernel" msgstr "Kích thước của Linux Kernel" #: src/bz-app-size-dialog.c:56 msgid "linux-6.17.tar.xz" msgstr "linux-6.17.tar.xz" #: src/bz-app-size-dialog.c:57 msgid "Of the Apollo 11 guidance computer" msgstr "Kích thước của máy tính dẫn đường Apollo 11" #: src/bz-app-size-dialog.c:57 msgid "Total ROM and RAM" msgstr "Tổng ROM và RAM" #: src/bz-app-size-dialog.c:58 msgid "Of the original Super Mario Bros" msgstr "Kích thước của Super Mario Bros gốc" #: src/bz-app-size-dialog.c:58 msgid "On the NES" msgstr "Trên NES" #: src/bz-app-size-dialog.c:59 msgid "Of the size of Wikipedia" msgstr "Kích thước của Wikipedia" #: src/bz-app-size-dialog.c:59 msgid "Without any media" msgstr "Không có media" #: src/bz-application.c:556 msgid "" "This functionality is currently disabled. It is recommended you download and " "install Flatseal to manage app permissions." msgstr "" "Chức năng này hiện bị tắt. Khuyến nghị bạn tải và cài Flatseal để quản lý " "quyền ứng dụng." #: src/bz-application.c:638 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:639 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:664 msgid "translator-credits" msgstr "Loc Huynh , 2025" #: src/bz-application.c:788 msgid "Performing setup..." msgstr "Đang thực hiện thiết lập..." #: src/bz-application.c:817 src/bz-application.c:826 msgid "Set Up Flathub" msgstr "Thiết lập Flathub" #: src/bz-application.c:820 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub chưa được thiết lập trên hệ thống này. Bạn sẽ không thể duyệt và cài " "đặt ứng dụng trong Bazaar nếu nó không khả dụng.\n" "\n" "Bạn vẫn có thể dùng Bazaar để duyệt và gỡ bỏ các ứng dụng đã cài." #: src/bz-application.c:825 src/bz-update-dialog.blp:6 msgid "Later" msgstr "Để sau" #: src/bz-application.c:1225 msgid "Synchronizing..." msgstr "Đang đồng bộ hóa..." #: src/bz-application.c:1364 #, c-format msgid "Receiving %d entries..." msgstr "Đang nhận %d mục..." #: src/bz-application.c:1369 msgid "Checking for updates..." msgstr "Đang kiểm tra cập nhật..." #: src/bz-curated-view.blp:11 src/bz-flathub-page.blp:19 #: src/bz-full-view.blp:54 src/bz-installed-page.blp:15 src/bz-window.blp:183 msgid "Empty" msgstr "Trống" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "Không có lựa chọn" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "Không có thông tin chọn lọc trên hệ thống này. Bạn vẫn có thể duyệt ứng dụng " "trên Flathub" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "Duyệt Flathub" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "Ngoại tuyến" #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:40 msgid "Browser" msgstr "Trình duyệt" #: src/bz-developer-badge.c:131 msgid "Developer information not available." msgstr "Thông tin nhà phát triển không khả dụng." #: src/bz-developer-badge.c:137 src/bz-developer-badge.c:151 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "" "Quyền sở hữu ID ứng dụng %s chưa được xác minh và có thể là gói cộng đồng." #: src/bz-developer-badge.c:155 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "Quyền sở hữu ID ứng dụng %s đã được đội ngũ Flathub xác minh thủ công." #: src/bz-developer-badge.c:161 #, c-format msgid "" "The ownership of the %s app ID has been verified by %s on %s." msgstr "Quyền sở hữu ID ứng dụng %s đã được %s xác minh trên %s." #: src/bz-developer-badge.c:168 #, c-format msgid "The ownership of the %s app ID has been verified using %s." msgstr "Quyền sở hữu ID ứng dụng %s đã được xác minh bằng %s." #: src/bz-developer-badge.c:172 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "Quyền sở hữu ID ứng dụng %s đã được xác minh." #: src/bz-entry-inspector.blp:5 msgid "Entry Inspector" msgstr "Trình kiểm tra mục" #: src/bz-entry-inspector.blp:76 msgid "Serialize" msgstr "Chuyển thành chuỗi" #: src/bz-entry-inspector.blp:80 msgid "Convert to JSON" msgstr "Chuyển sang JSON" #: src/bz-error.c:68 msgid "An Error Occurred" msgstr "Đã xảy ra lỗi" #: src/bz-error.c:89 msgid "Close" msgstr "Đóng" #: src/bz-error.c:90 msgid "Copy and Close" msgstr "Sao chép và đóng" #: src/bz-featured-tile.blp:88 msgid "App of the Day" msgstr "Ứng dụng của ngày" #: src/bz-flathub-category.c:78 msgid "Audio & Video" msgstr "Âm thanh & Video" #: src/bz-flathub-category.c:78 msgid "Media" msgstr "Đa phương tiện" #: src/bz-flathub-category.c:78 msgid "More Audio & Video" msgstr "Thêm Âm thanh & Video" #: src/bz-flathub-category.c:79 msgid "Developer Tools" msgstr "Công cụ phát triển" #: src/bz-flathub-category.c:79 msgid "Develop" msgstr "Phát triển" #: src/bz-flathub-category.c:79 msgid "More Developer Tools" msgstr "Thêm Công cụ phát triển" #: src/bz-flathub-category.c:80 msgid "Education" msgstr "Giáo dục" #: src/bz-flathub-category.c:80 msgid "Learn" msgstr "Học tập" #: src/bz-flathub-category.c:80 msgid "More Education" msgstr "Thêm Giáo dục" #: src/bz-flathub-category.c:81 msgid "Gaming" msgstr "Trò chơi" #: src/bz-flathub-category.c:81 msgid "Play" msgstr "Chơi" #: src/bz-flathub-category.c:81 msgid "More Gaming" msgstr "Thêm Trò chơi" #: src/bz-flathub-category.c:82 msgid "Graphics & Photography" msgstr "Đồ họa & Nhiếp ảnh" #: src/bz-flathub-category.c:82 msgid "Create" msgstr "Sáng tạo" #: src/bz-flathub-category.c:82 msgid "More Graphics & Photography" msgstr "Thêm Đồ họa & Nhiếp ảnh" #: src/bz-flathub-category.c:83 msgid "Networking" msgstr "Mạng" #: src/bz-flathub-category.c:83 msgid "Internet" msgstr "Internet" #: src/bz-flathub-category.c:83 msgid "More Networking" msgstr "Thêm Mạng" #: src/bz-flathub-category.c:84 msgid "Productivity" msgstr "Năng suất" #: src/bz-flathub-category.c:84 msgid "Work" msgstr "Công việc" #: src/bz-flathub-category.c:84 msgid "More Productivity" msgstr "Thêm Năng suất" #: src/bz-flathub-category.c:85 msgid "Science" msgstr "Khoa học" #: src/bz-flathub-category.c:85 msgid "More Science" msgstr "Thêm Khoa học" #: src/bz-flathub-category.c:86 msgid "System" msgstr "Hệ thống" #: src/bz-flathub-category.c:86 msgid "More System" msgstr "Thêm Hệ thống" #: src/bz-flathub-category.c:87 msgid "Utilities" msgstr "Tiện ích" #: src/bz-flathub-category.c:87 msgid "Tools" msgstr "Công cụ" #: src/bz-flathub-category.c:87 msgid "More Utilities" msgstr "Thêm Tiện ích" #: src/bz-flathub-category.c:88 src/bz-flathub-page.blp:110 #: src/bz-flathub-page.blp:143 msgid "Trending" msgstr "Thịnh hành" #: src/bz-flathub-category.c:88 msgid "More Trending" msgstr "Thêm Thịnh hành" #: src/bz-flathub-category.c:89 src/bz-flathub-page.blp:116 #: src/bz-flathub-page.blp:176 msgid "Popular" msgstr "Phổ biến" #: src/bz-flathub-category.c:89 msgid "More Popular" msgstr "Thêm Phổ biến" #: src/bz-flathub-category.c:90 src/bz-flathub-page.blp:165 msgid "Recently Added" msgstr "Mới thêm gần đây" #: src/bz-flathub-category.c:90 src/bz-flathub-page.blp:122 msgid "New" msgstr "Mới" #: src/bz-flathub-category.c:90 msgid "More New" msgstr "Thêm Mới" #: src/bz-flathub-category.c:91 src/bz-flathub-page.blp:154 msgid "Recently Updated" msgstr "Mới cập nhật gần đây" #: src/bz-flathub-category.c:91 src/bz-flathub-page.blp:128 msgid "Updated" msgstr "Đã cập nhật" #: src/bz-flathub-category.c:91 msgid "More Updated" msgstr "Thêm Đã cập nhật" #: src/bz-flathub-category.c:92 msgid "Mobile" msgstr "Di động" #: src/bz-flathub-category.c:92 msgid "More Mobile" msgstr "Thêm Di động" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Flathub chưa được thêm" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "Remote Flathub không được tìm thấy trong bất kỳ cài đặt Flatpak nào" #: src/bz-flathub-page.blp:48 msgid "Flathub Unavailable" msgstr "Flathub không khả dụng" #: src/bz-flathub-page.blp:49 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" "Không thể kết nối đến Flathub. Bạn vẫn có thể quản lý và tìm kiếm ứng dụng." #: src/bz-flathub-page.blp:52 msgid "Search Apps" msgstr "Tìm kiếm ứng dụng" #: src/bz-flathub-page.blp:261 msgid "On the Go" msgstr "Di động" #: src/bz-flathub-page.blp:273 msgid "Apps for your Linux phones and tablets" msgstr "Ứng dụng cho điện thoại và máy tính bảng Linux" #: src/bz-flathub-page.blp:284 msgid "More Mobile Apps" msgstr "Thêm Ứng dụng di động" #: src/bz-flathub-page.blp:319 msgid "More Mobile apps" msgstr "Thêm ứng dụng di động" #: src/bz-flathub-page.blp:379 msgid "We ♥ Games" msgstr "We ♥ Games" #: src/bz-flathub-page.blp:392 msgid "Games and apps to run your favorite titles" msgstr "Trò chơi và ứng dụng để chạy các tựa game yêu thích" #: src/bz-flathub-page.blp:426 msgid "More Games" msgstr "Thêm Trò chơi" #: src/bz-flatpak-entry.c:574 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Trang Flathub" #: src/bz-flatpak-entry.c:595 msgctxt "Project URL Type" msgid "Project Website" msgstr "Trang web dự án" #: src/bz-flatpak-entry.c:599 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Theo dõi lỗi" #: src/bz-flatpak-entry.c:603 msgctxt "Project URL Type" msgid "FAQ" msgstr "Câu hỏi thường gặp" #: src/bz-flatpak-entry.c:607 msgctxt "Project URL Type" msgid "Help" msgstr "Trợ giúp" #: src/bz-flatpak-entry.c:611 msgctxt "Project URL Type" msgid "Donate" msgstr "Quyên góp" #: src/bz-flatpak-entry.c:617 msgctxt "Project URL Type" msgid "Translate" msgstr "Dịch thuật" #: src/bz-flatpak-entry.c:621 msgctxt "Project URL Type" msgid "Contact" msgstr "Liên hệ" #: src/bz-flatpak-entry.c:625 msgctxt "Project URL Type" msgid "Source Code" msgstr "Mã nguồn" #: src/bz-flatpak-entry.c:631 msgctxt "Project URL Type" msgid "Contribute" msgstr "Đóng góp" #: src/bz-full-view.blp:21 src/bz-window.blp:126 src/bz-window.blp:380 msgid "Toggle transaction sidebar" msgstr "Bật/tắt thanh bên giao dịch" #: src/bz-full-view.blp:44 src/bz-window.blp:403 msgid "Main Menu" msgstr "Menu chính" #: src/bz-full-view.blp:58 msgid "No Results" msgstr "Không có kết quả" #: src/bz-full-view.blp:59 msgid "Try a different search query" msgstr "Thử truy vấn tìm kiếm khác" #: src/bz-full-view.blp:65 src/bz-window.blp:193 msgid "Content" msgstr "Nội dung" #: src/bz-full-view.blp:211 msgid "Support" msgstr "Hỗ trợ" #: src/bz-full-view.blp:231 msgid "Repository Star Count" msgstr "Số sao kho lưu trữ" #: src/bz-full-view.blp:261 src/bz-full-view.blp:516 msgid "Open" msgstr "Mở" #: src/bz-full-view.blp:274 src/bz-full-view.blp:489 msgid "Download & Install Application" msgstr "Tải xuống & cài đặt ứng dụng" #: src/bz-full-view.blp:289 msgid "Uninstall Application" msgstr "Gỡ cài đặt ứng dụng" #: src/bz-full-view.blp:304 src/bz-full-view.blp:531 msgid "Install Other Version" msgstr "Cài đặt phiên bản khác" #: src/bz-full-view.blp:328 msgid "Size" msgstr "Kích thước" #: src/bz-full-view.blp:433 msgid "Downloads /mo" msgstr "Lượt tải/tháng" #: src/bz-full-view.blp:550 msgid "Stopped Receiving Core Updates" msgstr "Ngừng nhận cập nhật lõi" #: src/bz-full-view.blp:564 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "Ứng dụng này dùng runtime không còn nhận cập nhật hoặc vá bảo mật. Có thể " "trở nên không an toàn khi sử dụng." #: src/bz-full-view.blp:735 msgid "Tags:" msgstr "Thẻ:" #: src/bz-full-view.c:301 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:308 #, c-format msgid "%.*fM" msgstr "%.*fM" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:315 #, c-format msgid "%.*fK" msgstr "%.*fK" #: src/bz-full-view.c:325 #, c-format msgid "%d downloads in the last 30 days" msgstr "%d lượt tải trong 30 ngày qua" #: src/bz-full-view.c:357 #, c-format msgid "Download size of %s" msgstr "Kích thước tải về %s" #: src/bz-full-view.c:390 msgid "All Ages" msgstr "Mọi lứa tuổi" #: src/bz-full-view.c:402 msgid "Age rating information unavailable" msgstr "Thông tin xếp hạng độ tuổi không khả dụng" #: src/bz-full-view.c:407 msgid "Suitable for all ages" msgstr "Phù hợp với mọi lứa tuổi" #: src/bz-full-view.c:409 #, c-format msgid "Suitable for ages %d and up" msgstr "Phù hợp từ %d tuổi trở lên" #: src/bz-full-view.c:440 msgid "Unknown" msgstr "Không xác định" #: src/bz-full-view.c:443 msgid "Proprietary Software" msgstr "Phần mềm độc quyền" #: src/bz-full-view.c:447 #, c-format msgid "Free software licensed under %s" msgstr "Phần mềm miễn phí theo giấy phép %s" #: src/bz-full-view.c:455 msgid "Free" msgstr "Miễn phí" #: src/bz-full-view.c:455 src/bz-license-dialog.blp:135 msgid "Proprietary" msgstr "Độc quyền" #: src/bz-full-view.c:475 msgid "Adaptive" msgstr "Thích ứng" #: src/bz-full-view.c:475 msgid "Desktop Only" msgstr "Chỉ máy tính để bàn" #: src/bz-full-view.c:481 msgid "Works on desktop, tablets, and phones" msgstr "Hoạt động trên máy tính để bàn, máy tính bảng và điện thoại" #: src/bz-full-view.c:482 msgid "May not work on mobile devices" msgstr "Có thể không hoạt động tốt trên thiết bị di động" #: src/bz-full-view.c:493 msgid "No URL" msgstr "Không có URL" #: src/bz-full-view.c:511 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Ứng dụng này có giấy phép FLOSS, nghĩa là mã nguồn có thể được kiểm tra để " "đảm bảo an toàn." #: src/bz-full-view.c:512 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Ứng dụng này có giấy phép độc quyền, nghĩa là mã nguồn được phát triển riêng " "tư và không thể được kiểm tra bởi bên thứ ba độc lập." #: src/bz-full-view.c:519 msgid "More Apps" msgstr "Thêm Ứng dụng" #: src/bz-full-view.c:520 #, c-format msgid "More Apps by %s" msgstr "Thêm Ứng dụng từ %s" #: src/bz-full-view.c:527 msgid "Other Apps by this Developer" msgstr "Ứng dụng khác từ nhà phát triển này" #: src/bz-full-view.c:529 src/bz-full-view.c:629 #, c-format msgid "Other Apps by %s" msgstr "Ứng dụng khác từ %s" #: src/bz-full-view.c:631 msgid "Other Apps" msgstr "Ứng dụng khác" #: src/bz-full-view.c:633 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d ứng dụng" #: src/bz-full-view.c:972 msgid "Show Less" msgstr "Thu gọn" #: src/bz-full-view.c:972 msgid "Show More" msgstr "Hiện thêm" #: src/bz-hardware-support-dialog.blp:6 src/bz-hardware-support-dialog.blp:47 msgid "Hardware Support" msgstr "Hỗ trợ phần cứng" #: src/bz-hardware-support-dialog.c:69 msgid "Keyboard support" msgstr "Hỗ trợ bàn phím" #: src/bz-hardware-support-dialog.c:71 msgid "Requires keyboards" msgstr "Yêu cầu bàn phím" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends keyboards" msgstr "Khuyến nghị bàn phím" #: src/bz-hardware-support-dialog.c:73 msgid "Supports keyboards" msgstr "Hỗ trợ bàn phím" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for keyboards" msgstr "Hỗ trợ bàn phím không xác định" #: src/bz-hardware-support-dialog.c:76 msgid "Mouse support" msgstr "Hỗ trợ chuột" #: src/bz-hardware-support-dialog.c:78 msgid "Requires mice or pointing devices" msgstr "Yêu cầu chuột hoặc thiết bị trỏ" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends mice or pointing devices" msgstr "Khuyến nghị chuột hoặc thiết bị trỏ" #: src/bz-hardware-support-dialog.c:80 msgid "Supports mice or pointing devices" msgstr "Hỗ trợ chuột hoặc thiết bị trỏ" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for mice or pointing devices" msgstr "Hỗ trợ chuột hoặc thiết bị trỏ không xác định" #: src/bz-hardware-support-dialog.c:83 msgid "Touchscreen support" msgstr "Hỗ trợ màn hình cảm ứng" #: src/bz-hardware-support-dialog.c:85 msgid "Requires touchscreens" msgstr "Yêu cầu màn hình cảm ứng" #: src/bz-hardware-support-dialog.c:86 msgid "Recommends touchscreens" msgstr "Khuyến nghị màn hình cảm ứng" #: src/bz-hardware-support-dialog.c:87 msgid "Supports touchscreens" msgstr "Hỗ trợ màn hình cảm ứng" #: src/bz-hardware-support-dialog.c:88 msgid "Unknown support for touchscreens" msgstr "Hỗ trợ màn hình cảm ứng không xác định" #: src/bz-hardware-support-dialog.c:192 msgid "Mobile support" msgstr "Hỗ trợ di động" #: src/bz-hardware-support-dialog.c:193 msgid "Works on mobile devices" msgstr "Hoạt động trên thiết bị di động" #: src/bz-hardware-support-dialog.c:193 msgid "May not work well on mobile devices" msgstr "Có thể không hoạt động tốt trên thiết bị di động" #: src/bz-hardware-support-dialog.c:198 msgid "Desktop support" msgstr "Hỗ trợ máy tính để bàn" #: src/bz-hardware-support-dialog.c:199 msgid "Works well on large screens" msgstr "Hoạt động tốt trên màn hình lớn" #: src/bz-hardware-support-dialog.c:233 #, c-format msgid "%s works best on specific hardware" msgstr "%s hoạt động tốt nhất trên phần cứng cụ thể" #: src/bz-hardware-support-dialog.c:240 #, c-format msgid "%s works on most devices" msgstr "%s hoạt động trên hầu hết thiết bị" #: src/bz-inspector.blp:5 msgid "Bazaar Inspector" msgstr "Trình kiểm tra Bazaar" #: src/bz-inspector.blp:33 msgid "Background Task Info:" msgstr "Thông tin tác vụ nền:" #: src/bz-inspector.blp:43 msgid "Enable Global Debug Mode" msgstr "Bật chế độ gỡ lỗi toàn cục" #: src/bz-inspector.blp:50 msgid "Active Blocklists" msgstr "Danh sách chặn hoạt động" #: src/bz-inspector.blp:67 msgid "Active Curated-Configs" msgstr "Cấu hình chọn lọc hoạt động" #: src/bz-inspector.blp:85 msgid "All Entry Groups" msgstr "Tất cả nhóm mục" #: src/bz-inspector.blp:93 msgid "Filter..." msgstr "Lọc..." #: src/bz-inspector.blp:134 msgid "Decache and Inspect" msgstr "Xóa bộ đệm và kiểm tra" #: src/bz-installed-page.blp:19 msgid "No Flatpaks Installed" msgstr "Chưa cài Flatpak nào" #: src/bz-installed-page.blp:25 src/bz-window.blp:298 msgid "Installed" msgstr "Đã cài đặt" #: src/bz-installed-page.c:395 msgid "Choose an Installation" msgstr "Chọn cài đặt" #: src/bz-installed-page.c:398 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with? " msgstr "" "Bạn đã cài nhiều phiên bản của ứng dụng này. Bạn muốn tiếp tục với phiên bản " "nào? " #: src/bz-installed-page.c:402 src/bz-window.c:1101 src/bz-window.c:1124 msgid "Cancel" msgstr "Hủy" #: src/bz-license-dialog.blp:77 msgid "Community Built" msgstr "Do cộng đồng xây dựng" #: src/bz-license-dialog.blp:176 msgid "Get Involved" msgstr "Tham gia" #: src/bz-license-dialog.c:115 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may not be able to contribute to this app." msgstr "" "Ứng dụng này không được phát triển công khai, chỉ nhà phát triển biết cách " "nó hoạt động. Có thể không an toàn theo cách khó phát hiện và có thể thay " "đổi mà không được giám sát.\n" "\n" "Bạn có thể không đóng góp được cho ứng dụng này." #: src/bz-license-dialog.c:124 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Ứng dụng này được cộng đồng quốc tế phát triển công khai.\n" "\n" "Bạn có thể tham gia và giúp nó tốt hơn." #: src/bz-license-dialog.c:135 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Ứng dụng này được cộng đồng quốc tế phát triển công khai và phát hành theo " "giấy phép %s.\n" "\n" "Bạn có thể tham gia và giúp nó tốt hơn." #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Tùy chỉnh" #: src/bz-preferences-dialog.blp:23 msgid "Content Filters" msgstr "Bộ lọc nội dung" #: src/bz-preferences-dialog.blp:26 msgid "Free Software Only" msgstr "Chỉ phần mềm miễn phí" #: src/bz-preferences-dialog.blp:27 msgid "Hide proprietary applications when browsing and searching" msgstr "Ẩn ứng dụng độc quyền khi duyệt và tìm kiếm" #: src/bz-preferences-dialog.blp:31 msgid "Flathub Results Only" msgstr "Chỉ kết quả Flathub" #: src/bz-preferences-dialog.blp:32 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "Giới hạn kết quả tìm kiếm và duyệt chỉ ở ứng dụng có trên Flathub" #: src/bz-preferences-dialog.blp:36 msgid "Hide EOL Apps" msgstr "Ẩn ứng dụng EOL" #: src/bz-preferences-dialog.blp:37 msgid "Hide apps which are no longer supported by their developers" msgstr "Ẩn ứng dụng không còn được nhà phát triển hỗ trợ" #: src/bz-preferences-dialog.blp:42 src/bz-window.blp:313 msgid "Search" msgstr "Tìm kiếm" #: src/bz-preferences-dialog.blp:45 msgid "Delay Search Results" msgstr "Trì hoãn kết quả tìm kiếm" #: src/bz-preferences-dialog.blp:46 msgid "Improve results performance by debouncing search terms" msgstr "Cải thiện hiệu suất kết quả bằng cách trì hoãn từ khóa tìm kiếm" #: src/bz-preferences-dialog.blp:51 msgid "Application Details" msgstr "Chi tiết ứng dụng" #: src/bz-preferences-dialog.blp:54 msgid "Display Star Count" msgstr "Hiển thị số sao" #: src/bz-preferences-dialog.blp:55 msgid "Show the star count of an application's source code repository" msgstr "Hiển thị số sao của kho mã nguồn ứng dụng" #: src/bz-preferences-dialog.blp:80 msgid "Progress Bar" msgstr "Thanh tiến trình" #: src/bz-preferences-dialog.blp:81 msgid "Choose a theme for the progress bar!" msgstr "Chọn chủ đề cho thanh tiến trình!" #: src/bz-preferences-dialog.blp:116 msgid "" "Bazaar can fetch and display the star count from an application's source " "code repository on a remote Git forge. \n" " For projects on GitHub, rate limits may cause them not to appear." msgstr "" "Bazaar có thể lấy và hiển thị số sao từ kho mã nguồn ứng dụng trên git forge " "từ xa.\n" "Đối với dự án trên GitHub, giới hạn tốc độ có thể khiến chúng không xuất " "hiện." #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Màu nổi bật" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Màu cờ LGBT+" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "Màu cờ Lesbian" #: src/bz-preferences-dialog.c:35 msgid "Transgender Pride Colors" msgstr "Màu cờ Transgender" #: src/bz-preferences-dialog.c:36 msgid "Nonbinary Pride Colors" msgstr "Màu cờ Nonbinary" #: src/bz-preferences-dialog.c:37 msgid "Bisexual Pride Colors" msgstr "Màu cờ Bisexual" #: src/bz-preferences-dialog.c:38 msgid "Asexual Pride Colors" msgstr "Màu cờ Asexual" #: src/bz-preferences-dialog.c:39 msgid "Pansexual Pride Colors" msgstr "Màu cờ Pansexual" #: src/bz-preferences-dialog.c:40 msgid "Aromantic Pride Colors" msgstr "Màu cờ Aromantic" #: src/bz-preferences-dialog.c:41 msgid "Genderfluid Pride Colors" msgstr "Màu cờ Genderfluid" #: src/bz-preferences-dialog.c:42 msgid "Polysexual Pride Colors" msgstr "Màu cờ Polysexual" #: src/bz-preferences-dialog.c:43 msgid "Omnisexual Pride Colors" msgstr "Màu cờ Omnisexual" #: src/bz-preferences-dialog.c:44 msgid "Aroace Pride Colors" msgstr "Màu cờ Aroace" #: src/bz-preferences-dialog.c:45 msgid "Agender Pride Colors" msgstr "Màu cờ Agender" #: src/bz-preferences-dialog.c:46 msgid "Genderqueer Pride Colors" msgstr "Màu cờ Genderqueer" #: src/bz-preferences-dialog.c:47 msgid "Intersex Pride Colors" msgstr "Màu cờ Intersex" #: src/bz-preferences-dialog.c:48 msgid "Demigender Pride Colors" msgstr "Màu cờ Demigender" #: src/bz-preferences-dialog.c:49 msgid "Biromantic Pride Colors" msgstr "Màu cờ Biromantic" #: src/bz-releases-dialog.blp:5 src/bz-releases-list.blp:26 msgid "Version History" msgstr "Lịch sử phiên bản" #: src/bz-releases-list.c:128 #, c-format msgid "Version %s" msgstr "Phiên bản %s" #: src/bz-releases-list.c:153 msgid "No details for this release" msgstr "Không có chi tiết cho bản phát hành này" #: src/bz-rich-app-tile.blp:137 msgid "Stopped Receiving Updates" msgstr "Ngừng nhận cập nhật" #: src/bz-rich-app-tile.blp:154 msgid "Get" msgstr "Tải" #: src/bz-search-widget.blp:105 msgid "Search Apps, Games, Software" msgstr "Tìm kiếm ứng dụng, trò chơi, phần mềm" #: src/bz-search-widget.blp:149 msgid "Categories Unavailable" msgstr "Danh mục không khả dụng" #: src/bz-search-widget.blp:150 msgid "Search for apps using the search bar above." msgstr "Tìm kiếm ứng dụng bằng thanh tìm kiếm phía trên." #: src/bz-search-widget.blp:234 msgid "No Applications Found" msgstr "Không tìm thấy ứng dụng" #: src/bz-search-widget.c:241 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "Không tìm thấy kết quả cho \"%s\" trên Flathub" #: src/bz-share-list.c:64 msgid "Copied!" msgstr "Đã sao chép!" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "Sao chép liên kết" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Mở liên kết" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "Dòng thời gian" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "Cài đặt:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "Thế giới" #: src/bz-tag-list.c:96 msgid "No Results Found" msgstr "Không tìm thấy kết quả" #: src/bz-tag-list.c:108 #, c-format msgid "Apps Tagged \"%s\"" msgstr "Ứng dụng có thẻ \"%s\"" #: src/bz-tag-list.c:109 #, c-format msgid "%d Applications" msgstr "%d ứng dụng" #: src/bz-tag-list.c:124 msgid "Search failed" msgstr "Tìm kiếm thất bại" #: src/bz-transaction-manager.c:1132 #, c-format msgid "Finished in %.02f seconds" msgstr "Hoàn thành trong %.02f giây" #: src/bz-transaction-view.blp:94 msgid "App Add-on" msgstr "Tiện ích mở rộng ứng dụng" #: src/bz-transaction-view.blp:119 msgid "Runtime" msgstr "Runtime" #: src/bz-transaction-view.blp:145 src/bz-transaction-view.blp:171 msgid "Install Size" msgstr "Kích thước cài đặt" #: src/bz-transaction-view.blp:199 src/bz-window.blp:346 msgid "Update" msgstr "Cập nhật" #: src/bz-transaction-view.c:139 #, c-format msgid "Transferred %s so far" msgstr "Đã truyền %s" #: src/bz-transaction.c:336 msgid "Pending" msgstr "Đang chờ" #: src/bz-update-dialog.blp:7 msgid "Install Now" msgstr "Cài đặt ngay" #: src/bz-update-dialog.blp:10 msgid "Updates Are Available" msgstr "Có bản cập nhật" #: src/bz-update-dialog.blp:11 msgid "" "The following applications are eligible for updates. Would you like to " "install them?" msgstr "" "Các ứng dụng sau đủ điều kiện cập nhật. Bạn có muốn cài đặt chúng không?" #: src/bz-update-dialog.c:134 #, c-format msgid "" "%d runtimes and/or addons are eligible for updates. Would you like to " "install them?" msgstr "" "%d runtime và/hoặc tiện ích mở rộng đủ điều kiện cập nhật. Bạn có muốn cài " "đặt chúng không?" #: src/bz-update-dialog.c:142 #, c-format msgid "Additionally, %d runtimes and/or addons will be updated." msgstr "Ngoài ra, %d runtime và/hoặc tiện ích mở rộng sẽ được cập nhật." #: src/bz-window.blp:66 msgid "Inspect UI Entry" msgstr "Kiểm tra mục giao diện" #: src/bz-window.blp:73 msgid "All Debug Actions" msgstr "Tất cả hành động gỡ lỗi" #: src/bz-window.blp:107 msgid "Tasks" msgstr "Tác vụ" #: src/bz-window.blp:163 msgid "Stop Active Tasks" msgstr "Dừng tác vụ đang chạy" #: src/bz-window.blp:171 msgid "Clear History" msgstr "Xóa lịch sử" #: src/bz-window.blp:187 msgid "No Tasks Yet" msgstr "Chưa có tác vụ" #: src/bz-window.blp:258 msgid "Refreshing Store Content" msgstr "Đang làm mới nội dung cửa hàng" #: src/bz-window.blp:273 msgid "Curated" msgstr "Chọn lọc" #: src/bz-window.blp:286 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:330 msgid "Sync" msgstr "Đồng bộ" #: src/bz-window.blp:466 msgid "_Donate to Bazaar ❤️" msgstr "_Quyên góp cho Bazaar ❤️" #: src/bz-window.blp:473 msgid "_Preferences" msgstr "_Tùy chỉnh" #: src/bz-window.blp:478 msgid "_Keyboard Shortcuts" msgstr "_Phím tắt" #: src/bz-window.blp:483 msgid "_About Bazaar" msgstr "_Giới thiệu Bazaar" #: src/bz-window.blp:490 msgid "_Quit Bazaar" msgstr "Thoát _Bazaar" #: src/bz-window.blp:499 msgid "Open Bazaar Inspector" msgstr "Mở Trình kiểm tra Bazaar" #: src/bz-window.c:844 msgid "" "The ability to inspect and install local .flatpak bundle files is coming " "soon! In the meantime, try running\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "on the command line." msgstr "" "Khả năng kiểm tra và cài đặt tập tin .flatpak bundle cục bộ sẽ sớm có! Trong " "lúc chờ đợi, hãy thử chạy\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "trên dòng lệnh." #: src/bz-window.c:966 msgid "Can't do that right now!" msgstr "Hiện không thể thực hiện!" #: src/bz-window.c:1095 #, c-format msgid "Install %s?" msgstr "Cài đặt %s?" #: src/bz-window.c:1098 msgid "May install additional shared components" msgstr "Có thể cài đặt thêm thành phần chia sẻ" #: src/bz-window.c:1117 #, c-format msgid "Remove %s?" msgstr "Gỡ bỏ %s?" #: src/bz-window.c:1121 #, c-format msgid "" "It will not be possible to use %s after it is uninstalled.\n" "\n" "Settings and user data will be kept." msgstr "" "Sẽ không thể sử dụng %s sau khi gỡ bỏ.\n" "\n" "Cài đặt và dữ liệu người dùng sẽ được giữ lại." #: src/bz-window.c:1286 msgid "Resume Current Tasks" msgstr "Tiếp tục tác vụ hiện tại" #: src/bz-window.c:1292 msgid "Pause Current Tasks" msgstr "Tạm dừng tác vụ hiện tại" #: src/bz-world-map.c:523 #, c-format msgid "%s: %'u downloads" msgstr "%s: %'u lượt tải" #: src/gtk/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Chung" #: src/gtk/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "Mở hộp thoại tìm kiếm" #: src/gtk/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Mở tùy chỉnh" #: src/gtk/shortcuts-dialog.blp:19 msgctxt "shortcut window" msgid "Refresh" msgstr "Làm mới" #: src/gtk/shortcuts-dialog.blp:24 msgctxt "shortcut window" msgid "Toggle Transaction Manager" msgstr "Bật/tắt quản lý giao dịch" #: src/gtk/shortcuts-dialog.blp:29 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Hiển thị phím tắt" #: src/gtk/shortcuts-dialog.blp:34 msgctxt "shortcut window" msgid "Quit" msgstr "Thoát" bazaar-orig-v0.7.14/po/ja.po0000664000175000017500000037741215166123241014526 0ustar hasanhasan# SPDX-FileCopyrightText: 2025 Japanese translations for bazaar package # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # # SPDX-FileCopyrightText: 2025 camegone msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-03-23 21:48+0900\n" "PO-Revision-Date: 2026-03-23 22:46+0900\n" "Last-Translator: camegone \n" "Language-Team: Japanese \n" "Language: ja\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Poedit 3.0.1\n" #: data/io.github.kolunmi.Bazaar.desktop.in:3 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:46 #: src/bz-window.c:377 src/bz-window.c:378 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:4 msgid "Add, remove or update flatpak software on this computer" msgstr "flatpakのソフトウェアをこのコンピューターに追加、削除します" #: data/io.github.kolunmi.Bazaar.desktop.in:10 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "" #: data/io.github.kolunmi.Bazaar.desktop.in:17 msgid "New Window" msgstr "新しいウィンドウ" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and manage applications" msgstr "アプリケーションを検索したり、管理したりする" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A fast and modern app store for Linux with a focus on discovering and " "installing Flatpak apps and addons, particularly from Flathub." msgstr "" "Linux 用の高速で新しいアプリストアです。Flatpak のアプリケーションやアドオン" "を検索、インストールすることに特化していて、主に Flathub を利用します。" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:15 msgid "Queue multiple installs and keep browsing" msgstr "ダウンロードタスクをキューに入れて、ブラウジングを続行しよう" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:16 msgid "Easily view app permissions" msgstr "簡単にアプリの権限を表示して、編集する" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:17 msgid "Sign in to Flathub to view and manage your favorites" msgstr "Flathub にログインしてお気に入りを管理、表示する" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:18 msgid "Search apps directly from GNOME Shell" msgstr "GNOME シェルから直接検索する" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:55 msgid "The home page displaying Flathub apps" msgstr "Flathub のアプリを表示しているホームページ" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:59 msgid "Exhibit app page" msgstr "Exhibit のアプリページ" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:63 msgid "Library page" msgstr "ライブラリーページ" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:67 msgid "Search page" msgstr "検索ページ" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:71 msgid "Category page" msgstr "カテゴリーページ" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:79 msgid "" "This release contains many technical improvements. This changelog reflects " "roughly 2 weeks of work." msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:83 msgid "Changes" msgstr "変更点" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:87 msgid "Respect system parental controls settings" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:88 msgid "" "Reap download workers when all windows are closed, reducing total memory " "usage" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:89 msgid "Add mnemonics to full app view" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:90 msgid "Many updates to language translations" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:92 msgid "Bug Fixes" msgstr "バグ修正" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:96 msgid "Fix broken library page when backing installed apps model is empty" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:97 msgid "" "Fix int casting bug that was causing RetroDeck to appear to be 18.4 exabytes" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:98 msgid "Make \"all apps\" category pages respect global filters" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:99 msgid "Fix some text wrapping issues" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:101 msgid "Thanks for reading and have a great day!" msgstr "読んでくれてありがとう! 良い一日を!" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:109 msgid "This release fixes some bugs and greatly improves search functionality." msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:113 msgid "" "If you missed the previous release, in 0.7.9 we also added the ability to " "cancel transactions in the library view, a brand new screenshots carousel, " "search suggestion buttons, and app runtime size information. You can also " "now skip confirmation dialogs by holding shift as you start a transaction." msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:120 msgid "Thanks for reading!" msgstr "読んでくれてありがとう!" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:128 msgid "**New Features**" msgstr "**新機能**" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:130 msgid "Search suggestion pills" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:131 #, fuzzy msgid "**Cancel installation** transactions" msgstr "現在進行中のダウンロードを停止" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:132 msgid "Skip dialogs by pressing shift" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:133 msgid "Runtime size info for app pages" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:135 msgid "**Updated**" msgstr "**更新点**" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:137 msgid "Redesigned \"What's New\" dialog" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:138 msgid "Improved search results by utilizing Flathub rankings" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:139 #, fuzzy msgid "Improved screenshots carousel" msgstr "スクリーンショット カルーセル" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:146 msgid "" "This release lets you view and remove user-scoped installed apps from the " "library page in the Flatpak version of the app. Installing from user remotes " "is not supported yet." msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:155 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:169 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:191 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:203 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:224 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:243 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:274 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:285 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:303 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:314 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:327 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:337 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:349 msgid "This release comes with the following improvements:" msgstr "このリリースには以下の改善点が含まれています:" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:157 msgid "Merges the task sidebar and install page into the library page" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:158 msgid "Add installed version numbers of each app on the library and app pages" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:159 #, fuzzy msgid "Add donations dialog" msgstr "年齢レーティングダイアログ" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:160 msgid "Fix broken addon and runtime eol detection" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:161 msgid "Add `enable-bulk-install` key to curated sections" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:162 msgid "Add `override-eol-markings` main config string list" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:171 msgid "Improve context dialogs" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:172 msgid "Fix leftover data bar being shown prematurely" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:173 msgid "Have a rotation toggle for flags" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:174 msgid "Add hard check to prevent removing Bazaar flatpak" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:175 #, fuzzy msgid "Improve download statistics tooltips" msgstr "ダウンロードの統計" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:176 msgid "Add read support for flatpak bundles" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:177 msgid "Fix critical output sometimes during transactions" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:178 msgid "Fix error popover refusing to spawn in transaction sidebar" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:185 msgid "Minor bugfix release" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:193 msgid "Fix issue where installed page is empty on opening second window" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:194 msgid "Fix screenshot flickering in search results" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:195 msgid "Fix pride flags sometimes not showing on certain locales" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:196 msgid "Add \"Install all\" to favorites page" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:205 msgid "Trash user data instead of deleting" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:206 msgid "Tweaks to permissions dialog" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:207 msgid "Fix broken EOL filtering" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:208 msgid "Add text filter to installed page" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:209 msgid "" "Add optional translations mappings for string properties in YAML configs" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:210 msgid "Hide EOL apps by default" msgstr "更新終了のアプリをデフォルトで非表示" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:211 msgid "Many other minor bug fixes and improvements" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:218 msgid "" "This small release ensures the new icon is rendered correctly on KDE Plasma." msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:226 msgid "New market stall icon" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:227 msgid "Remove Flathub styling" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:228 msgid "Add horizontal versions of pride flags" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:229 msgid "Text selection in app descriptions can be made across paragraph breaks" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:230 msgid "Support YAML anchors and aliases in config parsing" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:231 msgid "" "Drastically reduce disk cache writes over time by skipping unchanged entries" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:232 msgid "Show background status in popover" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:233 msgid "Add app permission system" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:234 msgid "Add back release URLs" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:235 msgid "Fix sync-remotes action in shortcut dialog" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:236 msgid "Fix visual hiccups in comet animations" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:245 msgid "Flathub account support with the ability to manage bookmarks" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:246 msgid "" "Flathub bookmarks replace star count; you can add or remove bookmarks from " "app pages" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:247 msgid "An \"Only Show Verified\" option" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:248 msgid "Exhaustive category pages for most categories" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:249 msgid "An \"Adwaita\" or \"KDE\" category shown based on desktop environment" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:250 msgid "Updated installed indicator for app tiles" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:251 msgid "3 new flag options" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:252 msgid "Fixed GNOME search provider to show the app page instead of search" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:253 msgid "" "Fixed issue where flatpakref URIs did not open when the app wasn't running " "in the background" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:254 msgid "" "Fixed issue where some proprietary apps were marked as \"Special License\"" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:255 msgid "Fixed issue where graphs did not work with touch" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:262 msgid "" "Another quick release to restore alphabetical sorting on the installed page" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:268 msgid "Quick release to allow manual refresh if flathub is being flaky" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:276 msgid "" "Fix frequent disk writes; set refresh frequency to 1 day rather than 1 hour" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:277 msgid "Add \"Delete User Data\" option when uninstalling an application" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:278 msgid "Version cache to prevent incompatibility between Bazaar versions" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:287 msgid "" "Reworked loading to be substantially faster after first start via async " "loading" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:288 msgid "A gaming section on the Flathub page" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:289 msgid "Improved UI on mobile, especially on app pages" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:290 msgid "Verified badges next to most places where apps are shown" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:291 msgid "A popover that explains what verification and non-verification mean" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:292 msgid "An \"other apps by\" page for when a developer has more than 6 apps" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:293 msgid "Tags that show other apps with the same tag when pressed" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:294 msgid "An age rating dialog" msgstr "年齢レーティングダイアログ" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:295 msgid "Changed search filters into global content filters" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:296 msgid "5 new pride flags" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:305 msgid "" "Add \"hide-eol\" preferences option to prevent Bazaar from showing end-of-" "life applications or applications which depend on end-of-life runtimes" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:306 msgid "Fix global progress bar theme sometimes not syncing with preferences" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:307 msgid "Show version next to addon name in the addons dialog" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:316 msgid "Add \"On the go\" section and mobile cateogry" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:317 msgid "Greatly decrease reported memory usage" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:318 msgid "Rework search UI" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:319 msgid "Rework page stack navigation" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:320 msgid "Change screenshot dialog to page" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:329 msgid "Fix slow/inconsistent image loading" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:330 msgid "Fix context row in full view" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:339 msgid "Rework full view layout" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:340 msgid "Improve progress bar theme selection" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:341 msgid "Reduce quantity and improve quality of search results" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:342 msgid "Allow the application window to fit on mobile screen sizes" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:351 msgid "Add interactive screenshot dialog" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:352 msgid "Fix empty update dialogs" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:353 msgid "Greatly improve look of app description rendering" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:354 msgid "Add pending state to the global progress bar" msgstr "全体のプログレスバーに中止の状態を追加しました" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:355 msgid "Add featured apps carousel" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:362 msgid "More improvements:" msgstr "改善点:" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:364 msgid "Improve design of transaction dialog" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:365 msgid "Update remove button pulse effect and comet size curve" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:366 msgid "Reap and reload cached textures after a day" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:367 msgid "Eliminate some crashes caused by race conditions" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:368 msgid "Change preferences group to context bar in full view" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:369 msgid "Switch side panels to sidebars and use flat header bar designs" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:370 msgid "Add really useful app size dialog :)" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:377 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:389 msgid "Some improvements:" msgstr "改善点:" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:379 msgid "" "Make the global progress bar customizable with pride flags! Check preferences" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:380 msgid "Add a new world map page to the download statistics dialog" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:381 msgid "" "Allow clicking on entries on transaction sidebar to navigate to the original " "store page" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:382 msgid "Add Alexander Vanhee to the developer credits" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:391 msgid "Overhaul download history graph; make it interactive" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:392 msgid "Smarter \"back\" functionality" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:393 msgid "Hide bottom bar more often on small window sizes" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:394 msgid "" "Make \"light-banner\" and \"dark-banner\" keys available to curated configs" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:401 msgid "This release includes:" msgstr "今回のリリースに含まれる変更:" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:403 msgid "553d041 * chore(po): update Ukrainian translation (#408)" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:404 msgid "711732a * Rework Version History (#407)" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:405 msgid "" "d2d3771 * Calculate detailed app tiles text color based on luminance of " "background accent color (#405)" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:406 msgid "3787e6e * Save window size in gsettings" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:407 msgid "18ba76c * AsyncTexture: increase HTTP timeout to 5 seconds" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:408 msgid "980f752 * SearchWidget: prevent invalid item selection" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:409 msgid "ab95593 * Add installed icons to app tiles (#404)" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:410 msgid "203754b * (UI) Improve visiblility of add-on feature (#403)" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:411 msgid "069ce61 * fix installed page list outline ring (#402)" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:412 msgid "" "da9f7b8 * (UX) Refine the Flathub views to be denser and have less partial " "lines (#401)" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:413 msgid "a6939ba * fix(po): fix Ukrainian translation (#400)" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:414 msgid "35c9611 * decrease app-tile description width reqs" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:415 msgid "6098be7 * chore(po): update Polish translation (#397)" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:416 msgid "2944d1e * change per section limit to 12 from 9 (#396)" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:417 msgid "0b04284 * Update Japanese Translation (#394)" msgstr "" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:418 msgid "fa60f4f * Move to brand new shiny Adw.ShortcutsDialog (#395)" msgstr "" #: src/bz-addons-dialog.blp:16 src/bz-full-view.blp:627 #: src/bz-installed-tile.blp:101 msgid "Manage Add-Ons" msgstr "アドオンを管理する" #: src/bz-addons-dialog.c:94 src/bz-install-controls.blp:137 #: src/bz-installed-tile.blp:114 msgid "Remove" msgstr "削除する" #: src/bz-addons-dialog.c:99 src/bz-favorites-tile.c:159 msgid "Install" msgstr "インストール" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 #: src/bz-age-rating-dialog.c:736 src/bz-full-view.c:333 src/bz-full-view.c:340 msgid "Age Rating" msgstr "年齢レーティング" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "カートゥーン調の暴力" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "カートゥーン調の暴力に関する情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "ファンタジー風の暴力" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "ファンタジー風の暴力に関する情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "リアルな暴力" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "リアルな暴力に関する情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "流血表現を含む暴力" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "流血表現に関する情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "性的暴力" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "性的暴力に関する情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "アルコール" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "アルコールに関する描写の情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "麻薬" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "麻薬に関する描写の情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "タバコ" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "タバコに関する描写の情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "ヌード" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "あらゆるヌード描写に関する情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "性的なテーマ" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "性的な要素や描写に関する情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "不適切な言葉" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "あらゆる不適切な言葉、行動に関する描写の情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "不適切なユーモア" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "不適切なユーモアに反する描写が含まれているかの情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "差別" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "あらゆる差別的な言葉に関する描写が含まれているかの情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "広告" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "あらゆる広告が含まれているかについての情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "ギャンブル" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "あらゆる種類のギャンブル描写が含まれているかの情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "購入" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "お金を払うことができるかについての情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "ユーザー同士のチャット" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "他のユーザーとチャットをする方法があるかについての情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "ユーザー同士のボイスチャット" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "他のユーザーと会話をする方法があるかについての情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 msgid "Contact Details" msgstr "連絡先" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "" "SNS のユーザーネームや、e-メールアドレスを共有することについての情報はありま" "せん" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "特定可能な情報" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "ユーザーの情報を第三者と共有することに関しての情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "位置情報の共有" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "他のユーザーと物理的な位置情報を共有することについての情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "売春" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "売春に関する描写についての情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "姦通" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "姦通 (不倫) に関する描写の情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "性的特徴付けられたキャラクター" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "性的特徴付けられたキャラクターについての情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 msgid "Desecration" msgstr "冒涜" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "" "冒涜的な描写が含まれているかの冒涜的な描写が含まれているかの情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "人の死体" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "人の死体に関する表示についての情報はありません" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "奴隷制度" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "奴隷に関する描写が含まれているかの情報はありません" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "ドラッグの描写は含まれていません" #: src/bz-age-rating-dialog.c:426 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "汚い言葉や不適切な言葉、乱暴な言葉は含まれていません" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "広告やアプリ内での取引は含まれていません" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "性的描写やヌードは含まれていません" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "無制限のチャット機能は含まれていません" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "暴力描写は含まれていません" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "ドラッグ" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "乱暴な言葉" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "お金" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "ソーシャル" #: src/bz-age-rating-dialog.c:479 msgid "Violence" msgstr "暴力" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:686 src/bz-full-view.c:323 #, c-format msgid "%d+" msgstr "" #: src/bz-age-rating-dialog.c:711 msgctxt "Age rating" msgid "All" msgstr "全年齢" #: src/bz-age-rating-dialog.c:747 #, c-format msgid "%s has an unknown age rating" msgstr "%s の年齢レーティングは不明です" #: src/bz-age-rating-dialog.c:753 #, c-format msgid "%s is suitable for everyone" msgstr "%s は全ての年齢のユーザーに適している" #: src/bz-age-rating-dialog.c:756 #, c-format msgid "%s is suitable for young children" msgstr "%s は小さな子供のユーザーに適している" #: src/bz-age-rating-dialog.c:759 #, c-format msgid "%s is suitable for children" msgstr "%s は子供のユーザーに適している" #: src/bz-age-rating-dialog.c:762 #, c-format msgid "%s is suitable for teenagers" msgstr "%s はティーンエイジのユーザーに適している" #: src/bz-age-rating-dialog.c:765 #, c-format msgid "%s is suitable for adults" msgstr "%s は大人のユーザーに適している" #: src/bz-age-rating-dialog.c:768 #, c-format msgid "%s is suitable for %s" msgstr "%s は %s のユーザーに適している" #: src/bz-age-rating-dialog.c:862 #, c-format msgid "%s • %s" msgstr "" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:29 #: src/bz-user-data-page.blp:15 src/bz-window.blp:239 msgid "Main Menu" msgstr "メインメニュー" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 #: src/bz-user-data-page.blp:19 src/bz-window.blp:328 msgid "_Donate to Bazaar ❤️" msgstr "Bazaar に寄付する❤️(_D)" #: src/bz-all-apps-page.blp:25 src/bz-apps-page.blp:25 #: src/bz-user-data-page.blp:26 src/bz-window.blp:335 msgid "_Refresh" msgstr "再読み込み(_R)" #: src/bz-all-apps-page.blp:30 src/bz-apps-page.blp:30 #: src/bz-user-data-page.blp:31 src/bz-window.blp:340 msgid "_Preferences" msgstr "設定(_P)" #: src/bz-all-apps-page.blp:35 src/bz-apps-page.blp:35 #: src/bz-user-data-page.blp:36 src/bz-window.blp:345 msgid "_Login With Flathub" msgstr "Flathub にログイン(_L)" #: src/bz-all-apps-page.blp:41 src/bz-apps-page.blp:41 #: src/bz-user-data-page.blp:42 src/bz-window.blp:351 msgid "_Manage Leftover User Data" msgstr "残存しているユーザーデータを管理(_M)" #: src/bz-all-apps-page.blp:46 src/bz-apps-page.blp:46 #: src/bz-user-data-page.blp:47 src/bz-window.blp:356 msgid "_Keyboard Shortcuts" msgstr "キーボードショートカット(_K)" #: src/bz-all-apps-page.blp:51 src/bz-apps-page.blp:51 #: src/bz-user-data-page.blp:52 src/bz-window.blp:361 msgid "_About Bazaar" msgstr "Bazaar について(_A)" #: src/bz-all-apps-page.blp:58 src/bz-apps-page.blp:58 #: src/bz-user-data-page.blp:59 src/bz-window.blp:368 msgid "_Quit Bazaar" msgstr "Bazaar を終了(_Q)" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "システムフォルダー %s" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "ホームのサブフォルダー %s" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "ホストシステムのフォルダー" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "/etc ディレクトリにあるホストシステムの設定" #: src/bz-app-permissions.c:169 #, c-format msgid "Desktop subfolder %s" msgstr "デスクトップ内のサブフォルダー %s" #: src/bz-app-permissions.c:170 msgid "Desktop folder" msgstr "デスクトップのフォルダー" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "ドキュメント内のサブフォルダー %s" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "ドキュメントのフォルダー" #: src/bz-app-permissions.c:177 #, c-format msgid "Music subfolder %s" msgstr "ミュージック内のサブフォルダー %s" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "ミュージックのフォルダー" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "ピクチャ内のサブフォルダー %s" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "ピクチャのフォルダー" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "公開フォルダー内のサブフォルダー %s" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "公開フォルダー" #: src/bz-app-permissions.c:189 #, c-format msgid "Videos subfolder %s" msgstr "ビデオ内のサブフォルダー %s" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "ビデオのフォルダー" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "テンプレート内のサブフォルダー %s" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "テンプレートのフォルダー" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "ユーザーキャッシュ内のサブフォルダー %s" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "ユーザーのキャッシュフォルダー" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "ユーザー設定内のサブフォルダー %s" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "ユーザー設定のフォルダー" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "ユーザーデータ内のサブフォルダー %s" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "ユーザーデータのフォルダー" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "ユーザーランタイム内のサブフォルダー %s" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "ユーザーランタイムのフォルダー" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "%s へのファイルシステム アクセス" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "不明なファイルシステムのパス" #: src/bz-app-size-dialog.blp:29 src/bz-app-size-dialog.blp:55 msgid "Download Size" msgstr "ダウンロードサイズ" #: src/bz-app-size-dialog.blp:56 msgid "Amount to download from the internet" msgstr "インターネットからダウンロードするデータの量" #: src/bz-app-size-dialog.blp:76 msgid "Installed Size" msgstr "インストール済みのサイズ" #: src/bz-app-size-dialog.blp:77 msgid "Size on Disk" msgstr "ディスク上のサイズ" #: src/bz-app-size-dialog.blp:125 msgid "Open user data folder" msgstr "ユーザーデータのフォルダーを開く" #: src/bz-app-size-dialog.blp:135 msgid "User Data Size" msgstr "ユーザーデータのサイズ" #: src/bz-app-size-dialog.blp:136 msgid "Caches, settings, and other app data" msgstr "キャッシュや設定、その他のアプリデータ" #: src/bz-app-size-dialog.c:99 msgid "Installed Runtime Size" msgstr "インストール済みランタイムのサイズ" #: src/bz-app-size-dialog.c:99 msgid "Runtime Download Size" msgstr "ランタイムのダウンロードサイズ" #: src/bz-app-tile.blp:57 src/bz-developer-badge.c:98 #: src/bz-rich-app-tile.blp:104 src/bz-rich-app-tile.c:304 msgid "Verified" msgstr "認証済み" #. Translators: As in 'The app is installed'. #: src/bz-app-tile.blp:88 src/bz-full-view.c:282 src/bz-releases-list.c:205 msgid "Installed" msgstr "インストール済み" #: src/bz-apps-page.blp:142 msgid "Show All" msgstr "すべて表示" #: src/bz-apps-page.c:229 #, c-format msgid "All \"%s\"" msgstr "全ての「%s」" #: src/bz-apps-page.c:478 src/bz-tag-list.c:91 #, c-format msgid "%d Applications" msgstr "アプリケーション総数: %d" #: src/bz-application.c:695 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "" #: src/bz-application.c:696 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "" #: src/bz-application.c:716 msgid "The Bazaar Contributors" msgstr "Bazzar の貢献者たち" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:719 msgid "translator-credits" msgstr "camegone, 2025" #: src/bz-application.c:729 msgid "Special Thanks" msgstr "スペシャルサンクス" #: src/bz-application.c:787 msgid "Logged Out Successfully!" msgstr "正常にログアウトされました!" #: src/bz-application.c:910 msgid "Performing setup…" msgstr "セットアップの実行中…" #: src/bz-application.c:994 msgid "Set Up System Flathub?" msgstr "システムに Flathub をセットアップしますか?" #: src/bz-application.c:997 msgid "" "The system Flathub remote is not set up. Bazaar requires Flathub to be " "configured on the system Flatpak installation to browse and install " "applications.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub リモートはあなたのシステムでセットアップされていません。Bazaar でアプ" "リを検索したりインストールするためには、システムに Flathub をセットアップする" "必要があります。 \n" "\n" "あなたは引き続き Bazaar でインストール済みのアプリを検索したり削除することが" "できます。" #: src/bz-application.c:1004 msgid "Set Up Flathub?" msgstr "Flathub をセットアップしますか?" #: src/bz-application.c:1007 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub はあなたのシステムでセットアップされていません。Flathub が利用できな" "い場合、アプリを検索したりインストールすることができません。\n" "\n" "あなたは引き続き Bazaar でインストール済みのアプリを検索したり削除することが" "できます。" #: src/bz-application.c:1013 msgid "Later" msgstr "後で" #: src/bz-application.c:1014 msgid "Set Up Flathub" msgstr "Flathub をセットアップする" #: src/bz-application.c:1303 msgid "A backend error occurred" msgstr "バックエンドのエラーが発生しました" #: src/bz-application.c:1499 src/bz-application.c:3357 src/bz-window.blp:70 msgid "Refreshing…" msgstr "再読み込み中…" #: src/bz-application.c:1651 src/bz-application.c:3355 #, c-format msgid "Loading %d apps…" msgstr "%d 個のアプリをロード中…" #: src/bz-application.c:1654 msgid "Checking for updates…" msgstr "更新を確認中…" #: src/bz-application.c:1717 msgid "Failed to open .flatpakref" msgstr ".flatpakref を開けませんでした" #: src/bz-application.c:1773 msgid "An initialization error occurred" msgstr "初期化中にエラーが発生しました" #: src/bz-application.c:2123 msgid "Failed to check for updates" msgstr "更新の確認に失敗しました" #: src/bz-application.c:3128 msgid "Could not find app" msgstr "アプリが見つかりませんでした" #: src/bz-application.c:3359 msgid "Writing to cache…" msgstr "キャッシュを書き込み中…" #: src/bz-appstream-parser.c:302 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Flathub ページ" #: src/bz-appstream-parser.c:323 msgctxt "Project URL Type" msgid "Project Website" msgstr "プロジェクトのウェブサイト" #: src/bz-appstream-parser.c:327 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "バグトラッカー" #: src/bz-appstream-parser.c:331 msgctxt "Project URL Type" msgid "FAQ" msgstr "よくある質問" #: src/bz-appstream-parser.c:335 msgctxt "Project URL Type" msgid "Help" msgstr "ヘルプ" #: src/bz-appstream-parser.c:339 msgctxt "Project URL Type" msgid "Donate" msgstr "寄付" #: src/bz-appstream-parser.c:345 msgctxt "Project URL Type" msgid "Translate" msgstr "翻訳" #: src/bz-appstream-parser.c:349 msgctxt "Project URL Type" msgid "Contact" msgstr "連絡先" #: src/bz-appstream-parser.c:353 msgctxt "Project URL Type" msgid "Source Code" msgstr "ソースコード" #: src/bz-appstream-parser.c:359 msgctxt "Project URL Type" msgid "Contribute" msgstr "貢献する" #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:68 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:62 #: src/bz-library-page.blp:65 src/bz-user-data-page.blp:86 msgid "Empty" msgstr "空" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "特選アプリなし" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "特選アプリの情報がこのシステム向けに提供されていません。ですが Flathub のアプ" "リを閲覧することはできます" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "Flathub を閲覧" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "オフライン" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 #: src/bz-search-pill-list.c:67 msgid "Browser" msgstr "ブラウザー" #: src/bz-developer-badge.c:94 src/bz-developer-badge.c:98 msgid "Not Verified" msgstr "認証なし" #: src/bz-developer-badge.c:145 msgid "Developer information not available." msgstr "開発者に関する情報がありません。" #: src/bz-developer-badge.c:151 src/bz-developer-badge.c:165 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "" "このアプリ ID、%s の所有権は検証されておらず、コミュニティのパッケージである" "可能性があります。" #: src/bz-developer-badge.c:169 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "このアプリ ID、%s の所有権は Flathub のチームが手動で検証済みです。" #: src/bz-developer-badge.c:175 #, c-format msgid "" "The ownership of the %1$s app ID has been verified by %2$s on " "%3$s." msgstr "" "このアプリ ID、%1$s の所有権は %3$s に所属する %2$s によって検" "証済みです。" #: src/bz-developer-badge.c:182 #, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "このアプリ ID、%1$s の所有権は、%2$s を使って検証済みです。" #: src/bz-developer-badge.c:186 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "このアプリ ID、%s の所有権は検証済みです。" #: src/bz-donations-dialog.blp:74 msgid "Full Release Notes" msgstr "更新履歴の全文" #: src/bz-donations-dialog.blp:108 msgid "This release was made possible by users like you!" msgstr "この新バージョンはあなたのようなユーザーのおかげで実現しました!" #: src/bz-donations-dialog.blp:116 msgid "" "I love making Bazaar, but I cannot do it alone. Help support further " "development by donating on Ko-Fi." msgstr "" "私は Bazaar の開発が好きですが、それは私一人だけではできません。もしあなたが" "将来的な開発の継続を支援したいなら、ko-fi でプロジェクトを支援することを検討" "してください。" #: src/bz-donations-dialog.blp:131 msgid "Donate to Bazaar" msgstr "Bazaar に寄付する" #. Translators: the %s format specifier will be something along the lines of "0.7.6" etc #: src/bz-donations-dialog.c:227 #, c-format msgid "What's New in %s?" msgstr "バージョン %s での変更点は何?" #. Translators: this is a release date label, like "Released February 9, 2026" #: src/bz-donations-dialog.c:243 msgid "Released %B %-e, %Y" msgstr "リリース日: %Y/%0m/%0d" #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "インストールの選択" #: src/bz-entry-group-util.c:76 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "" "あなたはこのアプリの複数のバージョンをインストールしています。どれを選択して" "続けますか?" #: src/bz-entry-group-util.c:80 msgid "Cancel" msgstr "キャンセル" #: src/bz-entry-selection-row.blp:17 msgid "For This User Only" msgstr "このユーザーのみ" #: src/bz-entry-selection-row.c:112 msgid "this user" msgstr "このユーザー" #: src/bz-entry-selection-row.c:112 msgid "all users" msgstr "全てのユーザー" #: src/bz-error.c:69 src/bz-error.c:88 src/bz-error-dialog.blp:36 #: src/bz-safety-dialog.blp:50 msgid "Details" msgstr "詳細" #: src/bz-error-dialog.blp:47 msgid "Copy" msgstr "コピーする" #: src/bz-error-dialog.c:56 src/bz-share-list.c:64 msgid "Copied!" msgstr "コピーしました!" #: src/bz-favorite-button.c:388 msgid "Failed to update favorite" msgstr "お気に入りを更新できませんでした" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "Flathub にログインしてお気に入りを管理する" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "ログイン" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "お気に入りされた数" #: src/bz-favorites-tile.c:157 src/bz-rich-app-tile.blp:172 msgid "Uninstall" msgstr "アンインストール" #: src/bz-favorites-tile.c:357 msgid "Failed to remove favorite" msgstr "お気に入りから削除できませんでした" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:78 msgid "Support This Application" msgstr "このアプリケーションを支援する" #: src/bz-favorites-tile.blp:119 msgid "Remove From Favorites" msgstr "お気に入りから削除" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:78 #: src/bz-window.blp:386 msgid "Favorites" msgstr "お気に入り" #: src/bz-favorites-page.blp:17 src/bz-section-view.blp:144 msgid "Install All" msgstr "全てインストール" #: src/bz-favorites-page.blp:34 src/bz-full-view.blp:45 src/bz-window.blp:255 msgid "Open App Library" msgstr "アプリ ライブラリを開く" #: src/bz-favorites-page.blp:56 src/bz-user-data-page.blp:75 msgid "Loading" msgstr "読み込み中" #: src/bz-favorites-page.blp:71 msgid "No Favorites" msgstr "お気に入りがありません" #: src/bz-favorites-page.blp:72 msgid "Applications you mark as favorite will appear here" msgstr "あなたがお気に入りマークをつけたアプリがここに表示されます" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "前へ" #: src/bz-featured-carousel.blp:54 msgid "Next" msgstr "次へ" #: src/bz-featured-tile.blp:90 msgid "App of the Day" msgstr "今日のアプリ" #: src/bz-flathub-category.c:89 msgid "Editing" msgstr "編集" #: src/bz-flathub-category.c:90 msgid "Midi" msgstr "Midi" #: src/bz-flathub-category.c:91 msgid "Mixer" msgstr "ミキサー" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-flathub-category.c:92 src/bz-search-pill-list.c:77 msgid "Music" msgstr "音楽" #: src/bz-flathub-category.c:93 msgid "Player" msgstr "プレーヤー" #: src/bz-flathub-category.c:94 msgid "Recorder" msgstr "レコーダー" #: src/bz-flathub-category.c:95 msgid "Sequencer" msgstr "シーケンサー" #: src/bz-flathub-category.c:96 msgid "Tuner" msgstr "チューナー" #: src/bz-flathub-category.c:97 msgid "TV" msgstr "テレビ" #: src/bz-flathub-category.c:102 msgid "Emulation" msgstr "エミュレーター" #: src/bz-flathub-category.c:103 msgid "Action" msgstr "アクション" #: src/bz-flathub-category.c:104 msgid "Adventure" msgstr "アドベンチャー" #: src/bz-flathub-category.c:105 msgid "Arcade" msgstr "アーケード" #: src/bz-flathub-category.c:106 msgid "Blocks" msgstr "ブロック" #: src/bz-flathub-category.c:107 msgid "Board" msgstr "ボードゲーム" #: src/bz-flathub-category.c:108 msgid "Card" msgstr "カードゲーム" #: src/bz-flathub-category.c:109 msgid "Kids" msgstr "子供向け" #: src/bz-flathub-category.c:110 msgid "Logic" msgstr "論理" #: src/bz-flathub-category.c:111 msgid "Role Playing" msgstr "ロールプレイング" #: src/bz-flathub-category.c:112 msgid "Shooter" msgstr "射撃系" #: src/bz-flathub-category.c:113 msgid "Simulation" msgstr "シミュレーション" #: src/bz-flathub-category.c:114 msgid "Sports" msgstr "スポーツ" #: src/bz-flathub-category.c:115 msgid "Strategy" msgstr "戦略" #: src/bz-flathub-category.c:120 msgid "Audio & Video" msgstr "映像や音楽" #: src/bz-flathub-category.c:120 msgid "Media" msgstr "メディア" #: src/bz-flathub-category.c:120 msgid "More Audio & Video" msgstr "映像や音楽をもっと見る" #: src/bz-flathub-category.c:121 msgid "Developer Tools" msgstr "開発ツール" #: src/bz-flathub-category.c:121 msgid "Develop" msgstr "開発" #: src/bz-flathub-category.c:121 msgid "More Developer Tools" msgstr "開発ツールをもっと見る" #: src/bz-flathub-category.c:122 msgid "Education" msgstr "教育" #: src/bz-flathub-category.c:122 msgid "Learn" msgstr "学ぶ" #: src/bz-flathub-category.c:122 msgid "More Education" msgstr "教育アプリをもっと見る" #: src/bz-flathub-category.c:123 msgid "Gaming" msgstr "ゲーム" #: src/bz-flathub-category.c:123 msgid "Play" msgstr "遊ぶ" #: src/bz-flathub-category.c:123 msgid "More Gaming" msgstr "ゲームをもっと見る" #: src/bz-flathub-category.c:124 msgid "Graphics & Photography" msgstr "画像や写真" #: src/bz-flathub-category.c:124 msgid "Create" msgstr "創作する" #: src/bz-flathub-category.c:124 msgid "More Graphics & Photography" msgstr "画像や写真関連のアプリをもっと見る" #: src/bz-flathub-category.c:125 msgid "Networking" msgstr "ネットワーク" #: src/bz-flathub-category.c:125 msgid "Internet" msgstr "インターネット" #: src/bz-flathub-category.c:125 msgid "More Networking" msgstr "ネットワーク関連のアプリをもっと見る" #: src/bz-flathub-category.c:126 msgid "Productivity" msgstr "生産性向上" #: src/bz-flathub-category.c:126 msgid "Work" msgstr "働く" #: src/bz-flathub-category.c:126 msgid "More Productivity" msgstr "生産性向上アプリをもっと見る" #: src/bz-flathub-category.c:127 msgid "Science" msgstr "科学" #: src/bz-flathub-category.c:127 msgid "More Science" msgstr "科学アプリをもっと見る" #: src/bz-flathub-category.c:128 msgid "System" msgstr "システム" #: src/bz-flathub-category.c:128 msgid "More System" msgstr "システムアプリをもっと見る" #: src/bz-flathub-category.c:129 msgid "Utilities" msgstr "便利ツール" #: src/bz-flathub-category.c:129 msgid "Tools" msgstr "ツール" #: src/bz-flathub-category.c:129 msgid "More Utilities" msgstr "便利ツールをもっと見る" #: src/bz-flathub-category.c:130 src/bz-flathub-page.blp:119 #: src/bz-flathub-page.blp:152 msgid "Trending" msgstr "話題のアプリ" #: src/bz-flathub-category.c:130 msgid "More Trending" msgstr "話題のアプリをもっと見る" #: src/bz-flathub-category.c:131 src/bz-flathub-page.blp:125 #: src/bz-flathub-page.blp:182 msgid "Popular" msgstr "人気のアプリ" #: src/bz-flathub-category.c:131 msgid "More Popular" msgstr "人気アプリをもっと見る" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:172 msgid "Recently Added" msgstr "最近追加されたアプリ" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:131 msgid "New" msgstr "新しいアプリ" #: src/bz-flathub-category.c:132 msgid "More New" msgstr "新着アプリをもっと見る" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:162 msgid "Recently Updated" msgstr "最近更新されたアプリ" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:137 msgid "Updated" msgstr "更新されたアプリ" #: src/bz-flathub-category.c:133 msgid "More Updated" msgstr "更新されたものをもっと見る" #: src/bz-flathub-category.c:134 msgid "Mobile" msgstr "モバイル" #: src/bz-flathub-category.c:134 msgid "More Mobile" msgstr "モバイル対応アプリをもっと見る" #: src/bz-flathub-category.c:135 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:135 msgid "More Adwaita" msgstr "Adwaita をもっと見る" #: src/bz-flathub-category.c:136 msgid "KDE Apps" msgstr "KDE アプリ" #: src/bz-flathub-category.c:136 msgid "More KDE Apps" msgstr "KDE のアプリをもっと見る" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Flathub が見つかりません" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "" "このコンピューター上のどの Flatpak にも Flathub リモートレポジトリが見つかり" "ませんでした" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "Flathub がエラーを返しました" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "Flathub への接続を再試行" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Flathub が利用不可" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" "Flathub に接続できませんでした。アプリの管理と検索はすることができます。" #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "アプリ検索" #: src/bz-flathub-page.blp:263 msgid "On the Go" msgstr "どこでも一緒" #: src/bz-flathub-page.blp:275 msgid "Apps for your Linux phones and tablets" msgstr "Linux フォンやタブレット向けのアプリ" #: src/bz-flathub-page.blp:286 src/bz-flathub-page.blp:321 msgid "More Mobile Apps" msgstr "モバイル対応アプリをもっと見る" #: src/bz-flathub-page.blp:379 msgid "We​ ♥​ Games" msgstr "" #: src/bz-flathub-page.blp:392 msgid "Games and apps to run your favorite titles" msgstr "ゲームやお気に入りのタイトルを遊ぶためのアプリ" #: src/bz-flathub-page.blp:426 msgid "More Games" msgstr "ゲームをもっと見る" #: src/bz-full-view.blp:66 src/bz-library-page.blp:76 #: src/bz-library-page.blp:80 msgid "No Results" msgstr "結果無し" #: src/bz-full-view.blp:67 msgid "Try a different search query" msgstr "別の語句で検索してみてください" #: src/bz-full-view.blp:73 msgid "Content" msgstr "内容" #: src/bz-full-view.blp:131 msgid "Installing .flatpak bundles is not yet supported" msgstr "" ".flatpak 形式のバンドルをインストールする機能はまだサポートされていません" #: src/bz-full-view.blp:257 msgid "_Support" msgstr "支援する(_S)" #: src/bz-full-view.blp:426 msgid "Downloads/Month" msgstr "月あたりのダウンロード数" #: src/bz-full-view.blp:461 msgid "Stopped Receiving Core Updates" msgstr "コアアップデートの提供終了" #: src/bz-full-view.blp:475 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "このアプリは更新やセキュリティ修正の提供が終了したランタイムを使用していま" "す。 将来的に使用することが安全でなくなる可能性があります。" #: src/bz-full-view.blp:562 msgid "Trash Data" msgstr "データをゴミ箱に移動" #: src/bz-full-view.blp:702 msgid "Tags:" msgstr "タグ:" #: src/bz-full-view.c:215 msgid "---" msgstr "" #. Translators: M is the suffix for millions #: src/bz-full-view.c:222 #, c-format msgid "%.*fM" msgstr "" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:229 #, c-format msgid "%.*fK" msgstr "" #: src/bz-full-view.c:239 #, c-format msgid "%d downloads in the last month" msgstr "過去1ヶ月の間に %d ダウンロード" #: src/bz-full-view.c:251 src/bz-full-view.c:592 src/bz-full-view.c:609 msgid "N/A" msgstr "利用不能" #: src/bz-full-view.c:279 #, c-format msgid "+%s runtime" msgstr "+%s ランタイム" #: src/bz-full-view.c:282 msgid "Download" msgstr "ダウンロード" #: src/bz-full-view.c:302 msgid "Size information unavailable" msgstr "サイズの情報がありません" #: src/bz-full-view.c:305 #, c-format msgid "Download size of %s" msgstr "ダウンロードサイズ: %s" #: src/bz-full-view.c:338 msgid "All Ages" msgstr "全年齢" #: src/bz-full-view.c:350 msgid "Age rating information unavailable" msgstr "年齢レーティングの情報がありません" #: src/bz-full-view.c:355 msgid "Suitable for all ages" msgstr "全ての年齢のユーザーに適している" #: src/bz-full-view.c:357 #, c-format msgid "Suitable for ages %d and up" msgstr "%d 歳以上のユーザーに適している" #: src/bz-full-view.c:390 src/bz-full-view.c:395 src/bz-full-view.c:423 #: src/bz-full-view.c:431 msgid "Unknown" msgstr "不明" #: src/bz-full-view.c:400 #, c-format msgid "Free software licensed under %s" msgstr "%s ライセンスのもと公開されているフリーソフト" #: src/bz-full-view.c:405 msgid "Free software" msgstr "フリーのソフトウェア" #: src/bz-full-view.c:408 msgid "Proprietary Software" msgstr "プロプライエタリ ソフトウェア" #: src/bz-full-view.c:411 #, c-format msgid "Special License: %s" msgstr "特別なライセンス: %s" #: src/bz-full-view.c:428 msgid "Free" msgstr "フリー" #: src/bz-full-view.c:434 src/bz-license-dialog.c:132 msgid "Proprietary" msgstr "プロプライエタリ" #: src/bz-full-view.c:436 src/bz-license-dialog.c:134 msgid "Special License" msgstr "特別なライセンス" #: src/bz-full-view.c:456 msgid "Adaptive" msgstr "幅広いデバイスに対応" #: src/bz-full-view.c:456 msgid "Desktop Only" msgstr "デスクトップのみ" #: src/bz-full-view.c:462 msgid "Works on desktop, tablets, and phones" msgstr "デスクトップ、タブレット、携帯電話で動きます" #: src/bz-full-view.c:463 msgid "May not work on mobile devices" msgstr "モバイル端末では動かない可能性があります" #: src/bz-full-view.c:474 msgid "No URL" msgstr "URL がありません" #: src/bz-full-view.c:492 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "このアプリケーションはフリーのOSSライセンスで公開されており、安全のためにソー" "スコードを確認することができます。" #: src/bz-full-view.c:493 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "このアプリケーションはプロプライエタリなライセンスで公開されており、ソース" "コードはプライベートで開発されているため、独立した第三者による検査を受けるこ" "とができません。" #: src/bz-full-view.c:500 msgid "More Apps" msgstr "アプリをもっと見る" #: src/bz-full-view.c:501 #, c-format msgid "More Apps by %s" msgstr "%s のアプリをもっと見る" #: src/bz-full-view.c:508 msgid "Other Apps by this Developer" msgstr "この開発者の別のアプリ" #: src/bz-full-view.c:510 src/bz-full-view.c:693 #, c-format msgid "Other Apps by %s" msgstr "%s の別のアプリ" #: src/bz-full-view.c:519 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "" "%s はインストールされていませんが、%s のデータは残存しています。" #: src/bz-full-view.c:599 src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "安全" #: src/bz-full-view.c:601 src/bz-full-view.c:603 msgid "Low Risk" msgstr "低いリスク" #: src/bz-full-view.c:605 msgid "Medium Risk" msgstr "中間のリスク" #: src/bz-full-view.c:607 msgid "High Risk" msgstr "高いリスク" #: src/bz-full-view.c:695 msgid "Other Apps" msgstr "他のアプリ" #: src/bz-full-view.c:697 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "アプリケーション総数: %d" #: src/bz-full-view.c:941 msgid "Show Less" msgstr "折り畳む" #: src/bz-full-view.c:941 msgid "Show More" msgstr "もっと見る" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 msgid "Hardware Support" msgstr "ハードウェアのサポート" #: src/bz-hardware-support-dialog.c:62 msgid "Keyboard support" msgstr "キーボードのサポート" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "キーボードの使用が必須" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "キーボードの使用を推奨" #: src/bz-hardware-support-dialog.c:66 msgid "Supports keyboards" msgstr "キーボードが使用可能" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "キーボードのサポート状況が不明" #: src/bz-hardware-support-dialog.c:69 msgid "Mouse support" msgstr "マウスのサポート" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "マウス等のポインティングデバイスの使用が必須" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "マウス等のポインティングデバイスの使用を推奨" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "マウス等のポインティングデバイスが使用可能" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "マウス等のポインティングデバイスのサポート状況が不明" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "タッチスクリーンのサポート" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "タッチスクリーンの使用が必須" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "タッチスクリーンの使用を推奨" #: src/bz-hardware-support-dialog.c:80 msgid "Supports touchscreens" msgstr "タッチスクリーンが使用可能" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "タッチスクリーンのサポート状況が不明" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "モバイル端末のサポート" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "モバイル端末で使用可能" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "モバイル端末では動かない可能性があります" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "デスクトップのサポート" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "大きな画面で快適に動作します" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "%s は特定のデバイスが搭載された端末で快適に動作します" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "%s はほとんどのデバイスで動作します" #: src/bz-install-controls.blp:33 msgid "Download & Install Application" msgstr "アプリケーションをダウンロードしてインストールする" #: src/bz-install-controls.blp:35 src/bz-transaction-dialog.c:202 msgid "_Install" msgstr "インストール(_I)" #: src/bz-install-controls.blp:61 msgid "_Open" msgstr "開く(_O)" #: src/bz-install-controls.blp:76 src/bz-install-controls.blp:127 msgid "Uninstall Application" msgstr "このアプリケーションをアンインストール" #: src/bz-install-controls.blp:86 src/bz-transaction-dialog.c:231 msgid "_Remove" msgstr "削除する(_R)" #: src/bz-install-controls.blp:114 src/bz-updates-card.blp:184 #: src/bz-updates-card.blp:212 msgid "Update" msgstr "更新" #: src/bz-installed-tile.blp:64 src/bz-rich-app-tile.blp:140 msgid "Stopped Receiving Updates" msgstr "更新の提供終了" #: src/bz-library-page.blp:31 msgid "Search installed apps" msgstr "インストール済みのアプリを検索" #: src/bz-library-page.blp:48 msgid "Clear search" msgstr "検索を削除" #: src/bz-library-page.blp:69 msgid "No Apps Found" msgstr "アプリケーションがありません" #. Translators: . #: src/bz-library-page.blp:98 src/bz-window.blp:112 msgid "Library" msgstr "ライブラリー" #: src/bz-library-page.blp:126 msgid "Pending Updates" msgstr "実行待ちの更新" #: src/bz-library-page.blp:153 msgid "Downloads" msgstr "ダウンロード一覧" #: src/bz-library-page.blp:196 msgid "Recently Uninstalled" msgstr "最近アンインストールされたアプリ" #: src/bz-library-page.blp:247 msgid "Clear Finished Tasks" msgstr "完了したタスクを削除" #: src/bz-library-page.blp:260 msgid "Installed Apps" msgstr "インストール済みのアプリ" #: src/bz-library-page.blp:333 msgid "Sort By" msgstr "ソート順" #: src/bz-library-page.blp:347 msgid "Name" msgstr "名前" #: src/bz-library-page.blp:353 msgid "Size" msgstr "サイズ" #: src/bz-library-page.c:180 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "" "インストール済みのアプリ一覧には、「%s」という単語は見つかりませんでした" #: src/bz-library-page.c:193 src/bz-updates-card.c:257 #, c-format msgid "%u Available Update" msgid_plural "%u Available Updates" msgstr[0] "%u 件の利用可能なアップデート" #: src/bz-license-dialog.blp:95 msgid "Get Involved" msgstr "参加する" #: src/bz-license-dialog.c:126 msgid "Unknown License" msgstr "不明なライセンス" #: src/bz-license-dialog.c:129 msgid "Community Built" msgstr "コミュニティーによって作られました" #: src/bz-license-dialog.c:202 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "このアプリは国際的なコミュニティによってオープンに開発されています。\n" "\n" "あなたは開発に参加して機能改善の手助けができます。" #: src/bz-license-dialog.c:205 msgid "The license of this app is not known" msgstr "このアプリのライセンスは不明です" #: src/bz-license-dialog.c:211 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "このアプリは国際的なコミュニティによってオープンに開発されていて、%s ライセン" "スのもとで公開されています。\n" "\n" "あなたは開発に参加して機能改善の手助けができます。" #: src/bz-license-dialog.c:219 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "このアプリはオープンソースとして開発されていないため、開発者しかどんな処理を" "行っているかを知ることができません。これによってセキュリティ上の脅威を発見す" "ることが難しくなったり、外部の監視無しに悪意のあるコードに変更される可能性が" "あります。\n" "\n" "あなたはこのアプリに対しての貢献を行うことができないかもしれません。" #: src/bz-license-dialog.c:225 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "このアプリは特別なライセンス、%s の下開発されています。\n" "あなたはこのアプリに対して貢献を行うことができないかもしれません。" #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 msgid "Connect to Flathub" msgstr "Flathub に接続する" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "不明なエラーが発生しました" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "" "あなたの Flathub アカウントを Bazzar へ接続して、お気に入りのアプリを管理しよ" "う。" #: src/bz-login-page.blp:110 msgid "Finish" msgstr "完了" #: src/bz-login-page.c:664 #, c-format msgid "Hello, %s!" msgstr "ようこそ、%s!" #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "設定" #: src/bz-preferences-dialog.blp:25 msgid "Network connection is metered — automatic store data refresh is paused" msgstr "" "従量課金のネットワークに接続しています — ストア情報の自動読み込みは一時停止さ" "れています" #: src/bz-preferences-dialog.blp:26 src/bz-window.blp:282 msgid "Refresh Manually" msgstr "手動で同期する" #: src/bz-preferences-dialog.blp:31 msgid "Content Filters" msgstr "コンテンツフィルター" #: src/bz-preferences-dialog.blp:34 msgid "Free Software Only" msgstr "フリーのソフトウェアのみ表示" #: src/bz-preferences-dialog.blp:35 msgid "Hide proprietary applications when browsing and searching" msgstr "プロプライエタリのソフトウェアを検索結果から除外する" #: src/bz-preferences-dialog.blp:39 msgid "Flathub Results Only" msgstr "Flathub からの検索結果のみ表示" #: src/bz-preferences-dialog.blp:40 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "検索結果を Flathub で利用可能なアプリのみに限定する" #: src/bz-preferences-dialog.blp:44 msgid "Verified Results Only" msgstr "検証済みの検索結果のみ表示" #: src/bz-preferences-dialog.blp:45 msgid "Hide results that are not verified on Flathub" msgstr "Flathub で検証されていないアプリケーションを非表示にする" #: src/bz-preferences-dialog.blp:49 msgid "Hide EOL Apps" msgstr "更新終了のアプリを非表示" #: src/bz-preferences-dialog.blp:50 msgid "Hide apps which are no longer supported by their developers" msgstr "開発者によるサポートが終了したアプリを非表示にする" #: src/bz-preferences-dialog.blp:55 src/bz-window.blp:127 msgid "Search" msgstr "検索" #: src/bz-preferences-dialog.blp:58 msgid "Delay Search Results" msgstr "検索の遅延" #: src/bz-preferences-dialog.blp:59 msgid "Improve results performance by debouncing search terms" msgstr "" "入力から検索までをわずかに遅延させることで検索のパフォーマンスを向上させる" #: src/bz-preferences-dialog.blp:64 msgid "Progress Bar" msgstr "プログレスバー" #: src/bz-preferences-dialog.blp:65 msgid "Choose a theme for the progress bar!" msgstr "プログレスバーを好きなテーマで彩りましょう!" #: src/bz-preferences-dialog.blp:89 msgid "Vertical Stripes" msgstr "垂直のストライプ" #: src/bz-preferences-dialog.blp:90 msgid "Display flag colors from left to right" msgstr "旗の色を左から右へと表示します" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "アクセントカラー" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "プライドカラー" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "レズビアン プライド カラー" #: src/bz-preferences-dialog.c:35 msgid "Male Homosexual Pride Colors" msgstr "男性 ホモセクシャル プライド カラー" #: src/bz-preferences-dialog.c:36 msgid "Transgender Pride Colors" msgstr "トランスジェンダー プライド カラー" #: src/bz-preferences-dialog.c:37 msgid "Nonbinary Pride Colors" msgstr "ノンバイナリー プライド カラー" #: src/bz-preferences-dialog.c:38 msgid "Bisexual Pride Colors" msgstr "バイセクシュアル プライド カラー" #: src/bz-preferences-dialog.c:39 msgid "Asexual Pride Colors" msgstr "アセクシュアル プライド カラー" #: src/bz-preferences-dialog.c:40 msgid "Pansexual Pride Colors" msgstr "パンセクシュアル プライド カラー" #: src/bz-preferences-dialog.c:41 msgid "Aromantic Pride Colors" msgstr "アロマンティック プライド カラー" #: src/bz-preferences-dialog.c:42 msgid "Genderfluid Pride Colors" msgstr "ジェンダーフルイド プライド カラー" #: src/bz-preferences-dialog.c:43 msgid "Polysexual Pride Colors" msgstr "ポリセクシュアル プライド カラー" #: src/bz-preferences-dialog.c:44 msgid "Omnisexual Pride Colors" msgstr "オムニセクシュアル プライド カラー" #: src/bz-preferences-dialog.c:45 msgid "Aroace Pride Colors" msgstr "アロエース プライド カラー" #: src/bz-preferences-dialog.c:46 msgid "Agender Pride Colors" msgstr "アジェンダー プライド カラー" #: src/bz-preferences-dialog.c:47 msgid "Genderqueer Pride Colors" msgstr "ジェンダークィア プライド カラー" #: src/bz-preferences-dialog.c:48 msgid "Intersex Pride Colors" msgstr "インターセックス プライド カラー" #: src/bz-preferences-dialog.c:49 msgid "Demigender Pride Colors" msgstr "デミジェンダー プライド カラー" #: src/bz-preferences-dialog.c:50 msgid "Biromantic Pride Colors" msgstr "バイロマンティック プライド カラー" #: src/bz-preferences-dialog.c:51 msgid "Disability Pride Colors" msgstr "ディスアビリティー プライド カラー" #: src/bz-preferences-dialog.c:52 msgid "Femboy Pride Colors" msgstr "フェムボーイ プライドカラー" #: src/bz-preferences-dialog.c:53 msgid "Neutrois Pride Colors" msgstr "ニュートロワ プライド カラー" #: src/bz-releases-dialog.blp:5 src/bz-updates-card.blp:171 msgid "Version History" msgstr "バージョン履歴" #: src/bz-releases-list.blp:27 msgid "_Version History" msgstr "バージョン履歴(_V)" #. Translators: something happened less than a day ago #: src/bz-releases-list.c:122 msgid "Today" msgstr "今日" #. Translators: something happened more than a day ago but less than 2 days ago #: src/bz-releases-list.c:125 msgid "Yesterday" msgstr "昨日" #. Translators: something happened days ago #: src/bz-releases-list.c:128 #, c-format msgid "%d day ago" msgid_plural "%d days ago" msgstr[0] "%d 日前" #. Translators: something happened weeks ago #: src/bz-releases-list.c:131 #, c-format msgid "%d week ago" msgid_plural "%d weeks ago" msgstr[0] "%d 週間前" #. Translators: something happened months ago #: src/bz-releases-list.c:134 #, c-format msgid "%d month ago" msgid_plural "%d months ago" msgstr[0] "%d ヶ月前" #. Translators: something happened years ago #: src/bz-releases-list.c:137 #, c-format msgid "%d year ago" msgid_plural "%d years ago" msgstr[0] "%d 年前" #. TRANSLATORS: This is the date string with: day number, month name, year. #. i.e. "22 March 2026" #: src/bz-releases-list.c:155 msgid "%e %B %Y" msgstr "%Y/%0m/%0d" #: src/bz-releases-list.c:195 #, c-format msgid "Version %s" msgstr "バージョン %s" #: src/bz-releases-list.c:250 msgid "No details for this release" msgstr "このリリースの詳細情報がありません" #: src/bz-releases-list.c:262 msgid "Get More Information" msgstr "詳細情報を確認する" #: src/bz-rich-app-tile.blp:157 msgid "Get" msgstr "入手" #: src/bz-rich-app-tile.blp:185 src/bz-transaction-tile.blp:272 msgid "Open" msgstr "開く" #: src/bz-safety-calculator.c:82 msgid "Unknown Permissions" msgstr "不明な権限" #: src/bz-safety-calculator.c:83 msgid "Permissions are missing for this app." msgstr "このアプリの動作に必要な権限が許可されていません。" #: src/bz-safety-calculator.c:96 msgid "No Permissions" msgstr "使用する権限なし" #: src/bz-safety-calculator.c:97 msgid "App is fully sandboxed" msgstr "アプリは完全にサンドボックス化 (隔離) されています" #: src/bz-safety-calculator.c:103 msgid "Network Access" msgstr "ネットワーク アクセス" #: src/bz-safety-calculator.c:104 msgid "Can access the internet" msgstr "インターネットに接続する" #: src/bz-safety-calculator.c:106 msgid "No Network Access" msgstr "ネットワーク アクセスなし" #: src/bz-safety-calculator.c:107 msgid "Cannot access the internet" msgstr "インターネットに接続しない" #: src/bz-safety-calculator.c:112 msgid "User Device Access" msgstr "ユーザーデバイスへのアクセス" #: src/bz-safety-calculator.c:113 msgid "Can access devices such as webcams or gaming controllers" msgstr "ウェブカメラやゲーム用コントローラーのようなデバイスにアクセスできます" #: src/bz-safety-calculator.c:115 msgid "No User Device Access" msgstr "ユーザーデバイスへのアクセスなし" #: src/bz-safety-calculator.c:116 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "" "ウェブカメラやゲーム用コントローラーのようなデバイスにアクセスできません" #: src/bz-safety-calculator.c:121 msgid "Input Device Access" msgstr "入力デバイスへのアクセス" #: src/bz-safety-calculator.c:122 msgid "Can access input devices" msgstr "入力デバイスへアクセスできます" #: src/bz-safety-calculator.c:128 msgid "Microphone Access and Audio Playback" msgstr "マイクへのアクセスと音声再生" #: src/bz-safety-calculator.c:129 msgid "Can listen using microphones and play audio without asking permission" msgstr "マイクの入力へのアクセスと音声再生を許可なく行えます" #: src/bz-safety-calculator.c:135 msgid "System Device Access" msgstr "システムデバイスへのアクセス" #: src/bz-safety-calculator.c:136 msgid "Can access system devices which require elevated permissions" msgstr "特権を要求されるシステムデバイスにアクセスすることができます" #: src/bz-safety-calculator.c:142 msgid "Screen Contents Access" msgstr "画面の内容へのアクセス" #: src/bz-safety-calculator.c:143 msgid "Can access the contents of the screen or other windows" msgstr "画面や他のウィンドウに表示されている内容へのアクセスができます" #: src/bz-safety-calculator.c:149 msgid "Legacy Windowing System" msgstr "古いウィンドウシステム" #: src/bz-safety-calculator.c:150 msgid "Always uses a legacy windowing system (X11)" msgstr "常に古いウィンドウシステム (X11) を使用します" #: src/bz-safety-calculator.c:156 msgid "Arbitrary Permissions" msgstr "任意の権限" #: src/bz-safety-calculator.c:157 msgid "Can acquire arbitrary permissions" msgstr "任意のあらゆる権限を取得することができます" #: src/bz-safety-calculator.c:163 msgid "User Settings" msgstr "ユーザー設定" #: src/bz-safety-calculator.c:164 msgid "Can access and change user settings" msgstr "ユーザーの設定へのアクセスと変更ができます" #: src/bz-safety-calculator.c:170 msgid "Full File System Read/Write Access" msgstr "ファイルシステム全体の読み書きアクセス" #: src/bz-safety-calculator.c:171 msgid "Can read and write all data on the file system" msgstr "ファイルシステム上全てのファイルの読み書きができます" #: src/bz-safety-calculator.c:178 msgid "Home Folder Read/Write Access" msgstr "ホームフォルダーの読み書きアクセス" #: src/bz-safety-calculator.c:179 msgid "Can read and write all data in your home directory" msgstr "あなたのホームディレクトリ内の全てのデータを読み書きできます" #: src/bz-safety-calculator.c:186 msgid "Full File System Read Access" msgstr "ファイルシステム全体の読み込みアクセス" #: src/bz-safety-calculator.c:187 msgid "Can read all data on the file system" msgstr "ファイルシステム上全てのデータを読み込みできます" #: src/bz-safety-calculator.c:195 msgid "Home Folder Read Access" msgstr "ホームフォルダーの読み込みアクセス" #: src/bz-safety-calculator.c:196 msgid "Can read all data in your home directory" msgstr "あなたのホームディレクトリ内の全てのデータの読み込みができます" #: src/bz-safety-calculator.c:204 msgid "Download Folder Read/Write Access" msgstr "ダウンロードフォルダーの読み書きアクセス" #: src/bz-safety-calculator.c:205 msgid "Can read and write all data in your downloads directory" msgstr "あなたのダウンロード ディレクトリ内の全てのデータを読み書きできます" #: src/bz-safety-calculator.c:215 msgid "Download Folder Read Access" msgstr "ダウンロードフォルダーの読み込みアクセス" #: src/bz-safety-calculator.c:216 msgid "Can read all data in your downloads directory" msgstr "あなたのダウンロード ディレクトリ内の全てのデータを読みこみできます" #: src/bz-safety-calculator.c:229 msgid "Can read and write all data in the directory" msgstr "このディレクトリ内の全てのデータを読み書きできます" #: src/bz-safety-calculator.c:243 msgid "Can read all data in the directory" msgstr "このディレクトリ内の全てのデータの読み込みができます" #: src/bz-safety-calculator.c:258 msgid "No File System Access" msgstr "ファイルシステムへのアクセスなし" #: src/bz-safety-calculator.c:259 msgid "Cannot access the file system at all" msgstr "ファイルシステムへのアクセスは全く行いません" #: src/bz-safety-calculator.c:266 msgid "Uses System Services" msgstr "システムサービスを使用" #: src/bz-safety-calculator.c:267 msgid "Can request data from non-portal system services" msgstr "Portal 以外のシステムサービスへデータをリクエストできます" #: src/bz-safety-calculator.c:273 msgid "Uses Session Services" msgstr "セッション サービスを使用" #: src/bz-safety-calculator.c:274 msgid "Can request data from non-portal session services" msgstr "Portal 以外のセッション サービスへデータをリクエストできます" #: src/bz-safety-calculator.c:322 msgid "No Service Access" msgstr "サービスへのアクセスなし" #: src/bz-safety-calculator.c:323 msgid "Cannot access non-portal session or system services at all" msgstr "" "Portal 以外のシステムやセッションのサービスへのアクセスを全く行いません" #: src/bz-safety-calculator.c:331 msgid "Verified App Developer" msgstr "検証済みアプリ開発者" #: src/bz-safety-calculator.c:332 msgid "The developer of this app has been verified to be who they say they are" msgstr "このアプリの開発者はなりすましではないことが確認されています" #: src/bz-safety-calculator.c:341 msgid "Proprietary Code" msgstr "プロプライエタリなコード" #: src/bz-safety-calculator.c:342 msgid "" "The source code is not public, so it cannot be independently audited and " "might be unsafe" msgstr "" "ソースコードが公開されていないため、個別に監査することができず、脆弱である可" "能性があります" #: src/bz-safety-calculator.c:352 msgid "Auditable Code" msgstr "検査可能なコード" #: src/bz-safety-calculator.c:353 msgid "" "The source code is public and can be independently audited, which makes the " "app more likely to be safe" msgstr "" "このアプリのソースコードは公開されており、自主的に検査可能なため、安全な可能" "性が高いです" #: src/bz-safety-calculator.c:493 #, c-format msgid "Use the %s System Service" msgstr "システムサービス %s を使用" #: src/bz-safety-calculator.c:497 #, c-format msgid "Use the %s Session Service" msgstr "セッション サービス %s を使用" #: src/bz-safety-calculator.c:501 #, c-format msgid "Use the %s Service" msgstr "サービス %s を使用" #: src/bz-safety-calculator.c:511 msgid "Can see the non-portal service" msgstr "Portal 以外のサービスを見ることができます" #: src/bz-safety-calculator.c:513 msgid "Can talk to the non-portal service" msgstr "Portal 以外のサービスと通信できます" #: src/bz-safety-calculator.c:515 msgid "Can own the non-portal service" msgstr "Portal 以外のサービスを保有できます" #: src/bz-safety-calculator.c:530 msgid "Global Menu Integration" msgstr "グローバル メニュー統合" #: src/bz-safety-calculator.c:531 msgid "Can display its menus in a global menu bar" msgstr "グローバルなメニューバーに追加のメニューを表示できます" #: src/bz-safety-calculator.c:536 msgid "KDE Settings Integration" msgstr "KDE 設定統合" #: src/bz-safety-calculator.c:537 msgid "Can detect when KDE desktop settings change" msgstr "KDE デスクトップの設定が変更されたときに検知できます" #: src/bz-safety-calculator.c:542 msgid "KDE Global Settings" msgstr "KDE のグローバル設定" #: src/bz-safety-calculator.c:543 msgid "Can read KDE desktop preferences like fonts and colors" msgstr "KDE デスクトップの設定 (フォントやカラーなど) を読み込むことができます" #: src/bz-safety-calculator.c:548 msgid "Secret Storage Service" msgstr "シークレット ストレージ サービス" #: src/bz-safety-calculator.c:549 msgid "Can store and retrieve its own passwords using the system keyring" msgstr "" "システムのキーリングを使用して、パスワードを保存または引き出すことができます" #: src/bz-safety-calculator.c:554 msgid "Desktop Notifications Service" msgstr "デスクトップ通知サービス" #: src/bz-safety-calculator.c:555 msgid "Can send desktop notifications" msgstr "デスクトップに通知を送信できます" #: src/bz-safety-calculator.c:561 msgid "System Tray Integration" msgstr "システムトレイ統合" #: src/bz-safety-calculator.c:562 msgid "Can display an icon in the system tray" msgstr "システムトレイにアイコンを表示できます" #: src/bz-safety-calculator.c:567 msgid "KDE Connect Integration" msgstr "KDE コネクト統合" #: src/bz-safety-calculator.c:568 msgid "Can interact with devices paired via KDE Connect" msgstr "KDE コネクトでペアリングされたデバイスと通信することができます" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "安全性" #: src/bz-safety-dialog.blp:53 msgid "License" msgstr "ライセンス" #: src/bz-safety-dialog.blp:63 msgid "App ID" msgstr "アプリ ID" #: src/bz-safety-dialog.blp:73 msgid "SDK" msgstr "SDK" #: src/bz-safety-dialog.blp:104 msgid "" "This app uses an outdated version of the software platform (SDK) and might " "contain bugs or security vulnerabilities which will not be fixed." msgstr "" "このアプリは古いバージョンのソフトウェア開発キット (SDK) を使用しており、バグ" "や脆弱性などの修正が提供されないままになっている可能性があります。" #: src/bz-safety-dialog.c:227 #, c-format msgid "%s is Safe" msgstr "%s は安全です" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s has no Unsafe Permissions" msgstr "%s は危険な権限を使用していません" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Probably Safe" msgstr "%s はおそらく安全です" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Possibly Unsafe" msgstr "%s はおそらく安全ではありません" #: src/bz-safety-dialog.c:247 #, c-format msgid "%s is Unsafe" msgstr "%s は安全ではありません" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "スクリーンショット" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "前のスクリーンショット" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "次のスクリーンショット" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "画像をコピー" #: src/bz-screenshot-page.blp:147 msgid "Reset View" msgstr "表示をリセット" #: src/bz-screenshot-page.blp:158 msgid "Zoom Out" msgstr "ズームアウト" #: src/bz-screenshot-page.blp:168 msgid "Zoom In" msgstr "ズームイン" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "スクリーンショット カルーセル" #: src/bz-screenshots-carousel.blp:117 msgid "Open Screenshot Viewer" msgstr "スクリーンショットビューアを開く" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:72 msgid "Video" msgstr "動画" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:82 msgid "Office" msgstr "オフィス" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:87 msgid "PDF" msgstr "PDF" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:92 msgid "Calendar" msgstr "カレンダー" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:97 msgid "Messaging" msgstr "メッセージ" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:102 msgid "Steam" msgstr "Steam" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:107 msgid "Paint" msgstr "お絵描き" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:112 msgid "VPN" msgstr "VPN" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:117 msgid "Torrent" msgstr "Torrent" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:122 msgid "Minecraft" msgstr "Minecraft" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:127 msgid "Emulator" msgstr "エミュレーター" #: src/bz-search-page.blp:57 msgid "Search Apps, Games, Software" msgstr "アプリ、ゲーム、ソフトウェアを検索" #: src/bz-search-page.blp:79 msgid "Clear Search" msgstr "検索を削除" #: src/bz-search-page.blp:171 msgid "Categories Unavailable" msgstr "カテゴリーが利用不能です" #: src/bz-search-page.blp:172 msgid "Search for apps using the search bar above." msgstr "画面上側にある検索バーを使用してアプリを検索する。" #: src/bz-search-page.blp:198 msgid "Browse Categories" msgstr "カテゴリー一覧" #: src/bz-search-page.blp:340 msgid "No Applications Found" msgstr "アプリケーションがありません" #: src/bz-search-page.c:244 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "「%s」という検索語句に合致するアプリは、Flathub にありませんでした" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "リンクをコピーする" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "リンクを開く" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "時系列" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "インストール数:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "地域別" #: src/bz-stats-dialog.blp:69 msgid "Since 4/15/2024" msgstr "2024/04/15 から" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:124 #, c-format msgid "%.2fM Total Installs" msgstr "総ダウンロード回数: %.2fM 回" #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:127 #, c-format msgid "%.2fK Total Installs" msgstr "総ダウンロード回数: %.2fK 回" #: src/bz-stats-dialog.c:129 #, c-format msgid "%'d Total Installs" msgstr "総ダウンロード回数: %'d 回" #: src/bz-tag-list.c:78 msgid "No Results Found" msgstr "検索結果無し" #: src/bz-tag-list.c:90 #, c-format msgid "Apps Tagged \"%s\"" msgstr "\"%s\" タグのついたアプリ" #: src/bz-tag-list.c:103 msgid "Search failed" msgstr "検索に失敗しました" #: src/bz-transaction-dialog.c:155 msgid "Keep User Data" msgstr "ユーザーデータを保持" #: src/bz-transaction-dialog.c:156 msgid "Allow restoring personal settings & content" msgstr "設定やコンテンツをまた使うことのできるように保持する" #: src/bz-transaction-dialog.c:165 msgid "Delete All Data" msgstr "全てのデータを削除" #: src/bz-transaction-dialog.c:166 msgid "Permanently erase user data to save space" msgstr "アプリのデータを永久に削除して容量を確保する" #: src/bz-transaction-dialog.c:191 #, c-format msgid "Install %s?" msgstr "%s をインストールしますか?" #: src/bz-transaction-dialog.c:196 msgid "" "Select which version to install. May install additional shared components" msgstr "" "どのバージョンをインストールするかを選択してください。追加の共有のコンポーネ" "ントがインストールされることがあります" #: src/bz-transaction-dialog.c:198 msgid "May install additional shared components" msgstr "追加の共有コンポーネントがインストールされることがあります" #: src/bz-transaction-dialog.c:201 src/bz-transaction-dialog.c:230 #: src/bz-transaction-dialog.c:275 src/bz-transaction-dialog.c:578 msgid "_Cancel" msgstr "キャンセル(_C)" #: src/bz-transaction-dialog.c:219 #, c-format msgid "Remove %s?" msgstr "%s を削除しますか?" #: src/bz-transaction-dialog.c:222 msgid "Select which version to remove." msgstr "削除するバージョンを選択してください。" #: src/bz-transaction-dialog.c:224 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "%s をアンインストールした後は、利用できなくなります。" #: src/bz-transaction-dialog.c:247 #, c-format msgid "“%s” is High Risk" msgstr "「%s」は高リスクです" #: src/bz-transaction-dialog.c:251 msgid "" "This app has full access to your system, including all your files, " "browser history, saved passwords, and more. It also has access to the " "internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "このアプリはあなたのシステムに完全なアクセスが可能であり、これはあなたの" "ファイル、ブラウザの閲覧履歴、保存したパスワード にアクセス可能なうえ、イ" "ンターネットに接続して第三者へあなたのデータを送信可能であることを意味しま" "す。\n" "\n" "このアプリはプロプライエタリであり、取得した権限で何を行っているかを検査する" "ことができません。" #: src/bz-transaction-dialog.c:260 msgid "" "This app uses the legacy X11 windowing system, which allows it to record " "all keystrokes, capture screenshots, and monitor other applications. It " "also has access to the internet, meaning it could send your data to outside " "parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "このアプリは古い X11 ウィンドウシステムを使用しており、全てのキーストロー" "クを記録したり、スクリーンショットを撮ったり、他のアプリケーションを監視する" "ことができます。さらに、インターネットに接続可能なため、第三者にあなたの" "データを送信可能なことを意味します。\n" "\n" "このアプリはプロプライエタリであり、取得した権限で何を行っているかを検査する" "ことができません。" #: src/bz-transaction-dialog.c:276 msgid "_Install Anyway" msgstr "それでもインストールする(_I)" #: src/bz-transaction-dialog.c:331 msgid "Failed to load transaction dialog" msgstr "ファイル操作のダイアログを読み込むことができませんでした" #: src/bz-transaction-dialog.c:549 msgid "All apps are already installed" msgstr "全てのアプリがすでにインストール済みです" #: src/bz-transaction-dialog.c:551 msgid "_OK" msgstr "OK(_O)" #: src/bz-transaction-dialog.c:567 #, c-format msgid "Install %u App?" msgid_plural "Install %u Apps?" msgstr[0] "%u 個のアプリをインストールしますか?" #: src/bz-transaction-dialog.c:575 msgid "" "The following will be installed. Additional shared components may also be " "installed" msgstr "" "以下のものがインストールされます。追加の共有コンポーネントがインストールされ" "ることがあります" #: src/bz-transaction-dialog.c:576 #, c-format msgid "%d addons will be installed." msgstr "%d 個のアドオンがインストールされます。" #: src/bz-transaction-dialog.c:577 msgid "Additionally, addons will be installed." msgstr "追加で、いくつかのアドオンがインストールされます。" #: src/bz-transaction-dialog.c:579 msgid "_Install All" msgstr "全てインストール(_I)" #: src/bz-transaction-manager.c:766 #, c-format msgid "Finished in %.02f seconds" msgstr "%.02f 秒で完了しました" #: src/bz-transaction-tile.blp:129 msgid "App Add-On" msgstr "アプリ アドオン" #: src/bz-transaction-tile.blp:158 msgid "Runtime" msgstr "ランタイム" #: src/bz-transaction-tile.blp:182 msgid "In Queue" msgstr "順番待ち" #: src/bz-transaction-tile.blp:206 msgid "Done" msgstr "完了" #: src/bz-transaction-tile.blp:230 msgid "Error" msgstr "エラー" #: src/bz-transaction-tile.blp:286 msgid "Cancel Transaction" msgstr "ファイル操作をキャンセル" #: src/bz-transaction-tile.blp:410 msgid "Show Error Info" msgstr "エラーの詳細を表示" #: src/bz-transaction-tile.c:107 #, c-format msgid "%s Freed" msgstr "%s を解放しました" #: src/bz-transaction-tile.c:362 src/bz-transaction-tile.c:365 msgid "Transaction Error" msgstr "ファイル操作のエラー" #: src/bz-transaction.c:342 msgid "Pending" msgstr "一時停止中" #: src/bz-updates-card.blp:40 msgid "_Update All" msgstr "全て更新(_U)" #: src/bz-updates-card.c:293 #, c-format msgid "%u Runtime Update" msgid_plural "%u Runtime Updates" msgstr[0] "%u 件のランタイムのアップデート" #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "残存するユーザーデータを管理" #: src/bz-user-data-page.blp:89 msgid "No User Data Found" msgstr "ユーザーデータが見つかりませんでした" #: src/bz-user-data-page.blp:94 msgid "User Data" msgstr "ユーザーデータ" #: src/bz-user-data-tile.c:144 #, c-format msgid "Trashed User Data for %s" msgstr "%s のユーザーデータをゴミ箱に移す" #: src/bz-user-data-tile.blp:74 msgid "Trash User Data" msgstr "ユーザーデータをゴミ箱に移動" #: src/bz-window.blp:88 msgid "Curated" msgstr "特選アプリ" #: src/bz-window.blp:100 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:220 msgid "Refresh completed!" msgstr "再読み込み完了!" #: src/bz-window.blp:273 msgid "You are running a new version of Bazaar!" msgstr "Bazaar のバージョンが新しくなりました!" #: src/bz-window.blp:274 msgid "See What's New" msgstr "変更点を見る" #: src/bz-window.blp:281 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "" "ネットワークに接続されていますが、キャッシュされた Flathub を表示しています" #: src/bz-window.blp:393 msgid "Log Out" msgstr "ログアウト" #. Translators: %s is the title of the current page #: src/bz-window.c:380 #, c-format msgid "Bazaar — %s" msgstr "Bazaar — %s" #: src/bz-window.c:487 msgid "Failed to load add-ons" msgstr "アドオンの読み込みに失敗しました" #: src/bz-window.c:601 src/bz-window.c:618 msgid "Failed to launch application" msgstr "アプリケーションの起動失敗" #: src/bz-window.c:823 msgid "You can't remove Bazaar from Bazaar!" msgstr "Bazaar を使って Bazaar を削除することはできません!" #: src/bz-window.c:1108 src/bz-window.c:1142 msgid "Can't do that right now!" msgstr "今すぐにはできません!" #: src/bz-world-map.c:595 msgctxt "As in, \"100 Downloads\"" msgid "Downloads" msgstr "ダウンロード" #: src/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "一般" #: src/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Page" msgstr "検索ページを表示" #: src/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Library Page" msgstr "ライブラリ ページを開く" #: src/shortcuts-dialog.blp:20 msgctxt "shortcut window" msgid "Refresh" msgstr "再読み込み" #: src/shortcuts-dialog.blp:25 msgctxt "shortcut window" msgid "Open Preferences" msgstr "設定を開く" #: src/shortcuts-dialog.blp:30 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "ショートカットを表示" #: src/shortcuts-dialog.blp:35 msgctxt "shortcut window" msgid "Close Window" msgstr "ウィンドウを閉じる" #: src/shortcuts-dialog.blp:41 msgctxt "shortcut window" msgid "Quit Bazaar" msgstr "Bazaar を終了" #~ msgid "" #~ "It emphasizes supporting the developers who make the Linux desktop " #~ "possible. Bazaar features a \"curated\" tab that can be configured by " #~ "distributors to allow for a more localized experience." #~ msgstr "" #~ "Linux のデスクトップを開発している開発者たちを支援することは重要です。" #~ "Bazaar ではディストリビューターが管理できる「特選アプリ」タブによってユー" #~ "ザーの体験を最適化することを可能にします。" #~ msgid "Install Other Version" #~ msgstr "ほかのバージョンをインストール" #~ msgid "%e %B" #~ msgstr "%0m/%0d" #~ msgid "Keep Data" #~ msgstr "データを保持" #~ msgid "Open App" #~ msgstr "アプリを開く" #~ msgid "Support this application" #~ msgstr "このアプリケーションを支援する" #~ msgid "Manage Add-ons" #~ msgstr "アドオンを管理する" #~ msgid "_Login with Flathub" #~ msgstr "Flathub にログイン(_L)" #~ msgid "_Synchronize Remotes" #~ msgstr "リモートと同期(_S)" #~ msgid "Synchronizing..." #~ msgstr "同期中..." #, c-format #~ msgid "Receiving %d entries..." #~ msgstr "%d 件のエントリを受信中..." #~ msgid "Indexing Data..." #~ msgstr "データをインデックス中..." #~ msgid "View the Release Page" #~ msgstr "リリースページを表示" #~ msgid "Close" #~ msgstr "閉じる" #~ msgid "Copy and Close" #~ msgstr "コピーして閉じる" #~ msgid "Refreshing Store Content" #~ msgstr "ストアの内容を再読み込み中" #~ msgid "No background tasks!" #~ msgstr "バックグラウンドタスクがありません!" #~ msgctxt "shortcut window" #~ msgid "Synchronize Remotes" #~ msgstr "リモートと同期" #~ msgctxt "shortcut window" #~ msgid "Quit" #~ msgstr "アプリを閉じる" #~ msgid "Nucleus app page" #~ msgstr "Nucleus アプリページ" #, fuzzy #~ msgid "Better track installed versions of apps" #~ msgstr "インストール済みのアプリを検索" #~ msgid "Toggle transaction sidebar" #~ msgstr "ダウンロードのサイドバーを表示/非表示" #~ msgid "Install Size" #~ msgstr "インストールサイズ" #~ msgid "Ongoing" #~ msgstr "進行中" #~ msgid "Finished" #~ msgstr "完了済み" #, c-format #~ msgid "Transferred %s so far" #~ msgstr "%s 転送済み" #~ msgid "Tasks" #~ msgstr "タスク" #~ msgid "Stop Active Tasks" #~ msgstr "現在進行中のタスクを停止" #~ msgid "No Tasks Yet" #~ msgstr "タスクがありません" #, c-format #~ msgid "%d Update Available" #~ msgid_plural "%d Updates Available" #~ msgstr[0] "%d 件の更新が利用可能です" #~ msgid "Updates Are Available" #~ msgstr "更新が利用可能です" #~ msgid "" #~ "The following applications are eligible for updates. Would you like to " #~ "install them?" #~ msgstr "" #~ "以下のアプリケーションが更新の対象になっています。インストールしてもよろし" #~ "いですか?" #, c-format #~ msgid "" #~ "%d runtimes and/or addons are eligible for updates. Would you like to " #~ "install them?" #~ msgstr "" #~ "%d 個のランタイムやアドオンが更新の対象になっています。インストールしても" #~ "よろしいですか?" #, c-format #~ msgid "Additionally, %d runtimes and/or addons will be updated." #~ msgstr "さらに %d 個のランタイムや、アドオンが更新されます。" #~ msgid "Update Now" #~ msgstr "今すぐ更新" #~ msgid "Resume Current Tasks" #~ msgstr "中止中のタスクを再開" #~ msgid "Pause Current Tasks" #~ msgstr "現在のタスクを一時停止" #~ msgctxt "shortcut window" #~ msgid "Toggle Transaction Manager" #~ msgstr "ダウンロードマネージャーの表示/非表示" #~ msgid "Pride Colors (Horizontal)" #~ msgstr "プライドカラー (水平)" #~ msgid "Lesbian Pride Colors (Horizontal)" #~ msgstr "レズビアン プライド カラー (水平)" #~ msgid "Male Homosexual Pride Colors (Horizontal)" #~ msgstr "男性 ホモセクシャル プライド カラー (水平)" #~ msgid "Transgender Pride Colors (Horizontal)" #~ msgstr "トランスジェンダー プライド カラー (水平)" #~ msgid "Nonbinary Pride Colors (Horizontal)" #~ msgstr "ノンバイナリー プライド カラー (水平)" #~ msgid "Bisexual Pride Colors (Horizontal)" #~ msgstr "バイセクシュアル プライド カラー (水平)" #~ msgid "Asexual Pride Colors (Horizontal)" #~ msgstr "アセクシュアル プライド カラー (水平)" #~ msgid "Pansexual Pride Colors (Horizontal)" #~ msgstr "パンセクシュアル プライド カラー (水平)" #~ msgid "Aromantic Pride Colors (Horizontal)" #~ msgstr "アロマンティック プライド カラー (水平)" #~ msgid "Genderfluid Pride Colors (Horizontal)" #~ msgstr "ジェンダーフルイド プライド カラー (水平)" #~ msgid "Polysexual Pride Colors (Horizontal)" #~ msgstr "ポリセクシュアル プライド カラー (水平)" #~ msgid "Omnisexual Pride Colors (Horizontal)" #~ msgstr "オムニセクシュアル プライド カラー (水平)" #~ msgid "Aroace Pride Colors (Horizontal)" #~ msgstr "アロエース プライド カラー (水平)" #~ msgid "Agender Pride Colors (Horizontal)" #~ msgstr "アジェンダー プライド カラー (水平)" #~ msgid "Genderqueer Pride Colors (Horizontal)" #~ msgstr "ジェンダークィア プライド カラー (水平)" #~ msgid "Intersex Pride Colors (Horizontal)" #~ msgstr "インターセックス プライド カラー (水平)" #~ msgid "Demigender Pride Colors (Horizontal)" #~ msgstr "デミジェンダー プライド カラー (水平)" #~ msgid "Biromantic Pride Colors (Horizontal)" #~ msgstr "バイロマンティック プライド カラー (水平)" #~ msgid "Disability Pride Colors (Horizontal)" #~ msgstr "ディスアビリティー プライド カラー (水平)" #~ msgid "Femboy Pride Colors (Horizontal)" #~ msgstr "フェムボーイ プライドカラー (水平)" #~ msgid "" #~ "The ability to inspect and install local .flatpak bundle files is coming " #~ "soon! In the meantime, try running\n" #~ "\n" #~ "flatpak install --bundle your-bundle.flatpak\n" #~ "\n" #~ "on the command line." #~ msgstr "" #~ "ローカルの flatpak バンドルファイルを表示、インストールする機能は近日追加" #~ "予定です! しばらくの間は代わりに、\n" #~ "\n" #~ "flatpak install --bundle バンドルファイル名.flatpak\n" #~ "\n" #~ "をコマンドラインで実行してください。" #, c-format #~ msgid "%s: %'u downloads" #~ msgstr "%s: %'u ダウンロード" #~ msgid "Hide EOL Entries" #~ msgstr "更新終了のエントリを非表示" #~ msgid "Hide EOL entries and entries depending on them" #~ msgstr "更新が終了したエントリや、それに依存しているエントリを非表示にする" #~ msgid "Only Show Free Software" #~ msgstr "フリーのソフトウェアのみ表示" #~ msgid "Hide proprietary software" #~ msgstr "プロプライエタリ ソフトウェアを非表示" #~ msgid "Show Only Flathub Content" #~ msgstr "Flathub の内容のみ表示" #~ msgid "Debounce Search Inputs" #~ msgstr "検索の遅延" #~ msgid "Add a delay before searching to prevent instant replies while typing" #~ msgstr "" #~ "入力してから検索されるまでに遅延を設け、即座に結果が表示されないようにする" #~ msgid "Global Progress Bar Theme" #~ msgstr "全体のプログレスバーのテーマ" #~ msgid "Describes the look of the global progress bar" #~ msgstr "全体のプログレスバーの見た目を変更する" #~ msgid "Saved Window Dimensions" #~ msgstr "保存したウィンドウサイズ" #~ msgid "The window dimensions to be used by the next Bazaar window" #~ msgstr "次回 Bazaar のウィンドウを表示する時に使用されるウィンドウの寸法" #, c-format #~ msgid "%s is suitable for toddlers" #~ msgstr "%s は幼児のユーザーに適している" #~ msgid "Of the size of human DNA" #~ msgstr "人間のDNAのサイズに対する割合" #~ msgid "3 billion base pairs" #~ msgstr "30億塩基対" #~ msgid "Of the Linux Kernel" #~ msgstr "linuxのカーネルに対する割合" #~ msgid "Of the Apollo 11 guidance computer" #~ msgstr "アポロ11号のガイダンスコンピュータに対する割合" #~ msgid "Total ROM and RAM" #~ msgstr "ROMとRAMの合計" #~ msgid "Of the original Super Mario Bros" #~ msgstr "初代スーパーマリオブラザーズに対する割合" #~ msgid "On the NES" #~ msgstr "ファミコン版" #~ msgid "Of the size of Wikipedia" #~ msgstr "Wikipedia のサイズに対する割合" #~ msgid "Without any media" #~ msgstr "画像や音声などを除いたサイズ" #~ msgid "" #~ "This functionality is currently disabled. It is recommended you download " #~ "and install Flatseal to manage app permissions." #~ msgstr "" #~ "この機能は現在無効になっています。アプリの権限を管理するためには、" #~ "Flatseal をインストールすることを推奨します。" #~ msgid "Entry Inspector" #~ msgstr "エントリのインスペクター" #~ msgid "Serialize" #~ msgstr "シリアライズ" #~ msgid "Convert to JSON" #~ msgstr "JSON に変換する" #~ msgid "More Mobile apps" #~ msgstr "モバイル対応アプリをもっと見る" #~ msgid "Bazaar Inspector" #~ msgstr "Bazaar インスペクター" #~ msgid "Enable Global Debug Mode" #~ msgstr "全域のデバッグモードを有効化" #~ msgid "Active Blocklists" #~ msgstr "有効なブラックリスト" #~ msgid "Active Curated-Configs" #~ msgstr "有効な特選アプリの設定" #~ msgid "All Entry Groups" #~ msgstr "全てのエントリグループ" #~ msgid "Filter..." #~ msgstr "検索..." #~ msgid "No Flatpaks Installed" #~ msgstr "Flatpak がインストールされていません" #~ msgid "Inspect UI Entry" #~ msgstr "UI エントリを検査" #~ msgid "All Debug Actions" #~ msgstr "すべてのデバッグオプション" #~ msgid "Open Bazaar Inspector" #~ msgstr "Bazaar インスペクターを開く" #~ msgid "Show Git Forge Star Counts" #~ msgstr "Git Forge のスター数を表示" #~ msgid "" #~ "Whether to attempt to detect and show \"star counts\" for projects in the " #~ "full view" #~ msgstr "「スターの数」をプロジェクトの詳細画面で表示するかどうか" #~ msgid "Repository Star Count" #~ msgstr "リポジトリーのスター数" #~ msgid "Application Details" #~ msgstr "アプリケーションの詳細" #~ msgid "Display Star Count" #~ msgstr "スターの数を表示" #~ msgid "Show the star count of an application's source code repository" #~ msgstr "アプリのソースコードがあるリポジトリのスターの数を表示する" #~ msgid "" #~ "Bazaar can fetch and display the star count from an application's source " #~ "code repository on a remote Git forge. \n" #~ " For projects on GitHub, rate limits may cause them not to appear." #~ msgstr "" #~ "Bazzarは Git forge のリモートにあるアプリケーションのリポジトリに付けられ" #~ "たスターの数を取得して、表示できます。\n" #~ "GitHub のプロジェクトでは、レート制限により表示されないことがあります。" #~ msgid "Mobile Apps" #~ msgstr "モバイル対応アプリ" #~ msgid "Verified by the original developers" #~ msgstr "オリジナルの開発者によって検証済みです" #~ msgid "Hide proprietary software when searching" #~ msgstr "検索結果からプロプライエタリのソフトウェアを除外します" #~ msgid "Filter search results to only show applications available on Flathub" #~ msgstr "検索結果を Flathub で利用可能なアプリのみに限定する" #~ msgid "Constructing Flatpak instance..." #~ msgstr "Flatpak のインスタンスを生成中..." #~ msgid "Reusing last Flatpak instance..." #~ msgstr "Flatpak のインスタンスを再利用中..." #~ msgid "Flathub is not registered on this system" #~ msgstr "Flathub がシステムに登録されていません" #~ msgid "" #~ "Would you like to add Flathub as a remote? If you decline, the Flathub " #~ "page will not be available. You can change this later." #~ msgstr "" #~ "Flathub をリモートのリポジトリに追加しますか? 拒否した場合、Flathub ページ" #~ "は利用できません。これは、あとから変更可能です。" #~ msgid "Add Flathub" #~ msgstr "Flathub を追加" #, c-format #~ msgid "Identifying installed entries..." #~ msgstr "インストール済みのエントリを特定中..." #, c-format #~ msgid "" #~ "Beginning remote entry retrieval while referencing %d blocklist(s)..." #~ msgstr "" #~ "%d 件のブロックリストを参照しながらリモートのエントリの取得開始中..." #, c-format #~ msgid "%'d of %'d" #~ msgstr "%'d / %'d" #, c-format #~ msgid "Waiting for background indexing tasks to catch up..." #~ msgstr "バックグラウンドのインデックス処理が終了するのを待っています..." #, c-format #~ msgid "Completed initialization in %0.2f seconds" #~ msgstr "%0.2f で初期化を完了しました" #~ msgid "" #~ "Bazaar was not provided a curated content configuration. Contact your " #~ "operating system's support channels for assistance." #~ msgstr "" #~ "Bazaar が読み込める特選アプリの情報がありませんでした。あなたが使用してい" #~ "る OS のサポートチャンネルに連絡してください。" #~ msgid "More actions" #~ msgstr "詳細コマンド" #~ msgid "Run this application" #~ msgstr "このアプリケーションを実行する" #~ msgid "Run" #~ msgstr "実行" #~ msgid "Git Forge Star Counts" #~ msgstr "Git Forge のスター数" #~ msgid "Not having a GitHub access token may trigger rate limits" #~ msgstr "" #~ "GitHub のアクセストークン無しではレート制限の原因となる可能性があります" #~ msgid "Show Only Flathub Apps" #~ msgstr "Flathub のアプリのみ表示" #~ msgid "Wait for a brief pause to reduce system load" #~ msgstr "システムの負荷を減らすため、少しの待ち時間を追加する" #~ msgid "Go Home" #~ msgstr "ホームに戻る" #~ msgid "Browse" #~ msgstr "ブラウズ" #~ msgid "App View" #~ msgstr "アプリ表示" #~ msgid "Go Back" #~ msgstr "戻る" #~ msgid "View curated applications" #~ msgstr "厳選されたアプリケーションを表示する" #~ msgid "View the latest on Flathub" #~ msgstr "Flathub の最新のアプリを表示する" #~ msgid "Settings & user data will be kept" #~ msgstr "設定とユーザーデータは保持されます" #~ msgid "Pride Rainbow Flag" #~ msgstr "プライドレインボー フラッグ" #~ msgid "Bisexual Flag" #~ msgstr "バイセクシュアル フラッグ" #~ msgid "Asexual Flag" #~ msgstr "アセクシュアル フラッグ" #~ msgid "_Quit Service" #~ msgstr "_サービスの停止" #~ msgid "Games" #~ msgstr "ゲーム" #~ msgid "Graphics" #~ msgstr "グラフィック" #~ msgctxt "Project URL Type" #~ msgid "Homepage" #~ msgstr "ホームページ" #~ msgid "Excludes shared components" #~ msgstr "共有のコンポーネントを除く" #~ msgid "Source code may not be available" #~ msgstr "ソースコードを入手できないことがあります" #~ msgid "Click for details" #~ msgstr "クリックで詳細を開く" #~ msgid "Repositories" #~ msgstr "リポジトリー" #~ msgid "Open in browser" #~ msgstr "ブラウザーで開く" #, c-format #~ msgid "%'d Monthly Downloads" #~ msgstr "月間 %'d ダウンロード" #~ msgid "Theme" #~ msgstr "テーマ" #~ msgid "Share" #~ msgstr "共有" #~ msgid "Manage Addons" #~ msgstr "アドオンを管理する" #~ msgid "%B %-d" #~ msgstr "%0m/%0d" #~ msgid "Up to date!" #~ msgstr "最新です!" #~ msgid "Calligraphy application page" #~ msgstr "カリグラフィーのアプリケーションページ" #~ msgid "Download graph for Blender" #~ msgstr "Blender のグラフをダウンロード" #~ msgid "Open this image in the default image viewer" #~ msgstr "この画像をデフォルトの画像ビューアーで開く" #~ msgid "Copy this image to the clipboard" #~ msgstr "この画像をクリップボードにコピーする" #~ msgid "Show Downloads Over Time" #~ msgstr "過去の期間に対するダウンロード数のグラフを表示する" #~ msgid "Remote repo name" #~ msgstr "リモートのリポジトリーの名前" #~ msgid "Updated Size" #~ msgstr "更新後のサイズ" #~ msgid "Freed Space" #~ msgstr "解放された容量" #~ msgid "Transactions Will Appear Here" #~ msgstr "ダウンロードはここに表示されます" #~ msgid "Resume the execution of transactions" #~ msgstr "ダウンロードを再開する" #~ msgid "Pause the execution of transactions" #~ msgstr "実行中のダウンロードを一時停止する" #~ msgid "Downloads Over Time" #~ msgstr "ダウンロード数の推移" #~ msgid "Minimize Lower Bound" #~ msgstr "グラフの下限を最小化" #~ msgid "Maximize Upper Bound" #~ msgstr "グラフの上限を最大化" #~ msgid "Confirm Action" #~ msgstr "操作の確認" #, c-format #~ msgid "" #~ "You are about to remove the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "あなたは以下の Flatpak をアンインストールしようとしています:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "アンインストールしてもよろしいですか?" #, c-format #~ msgid "" #~ "You are about to install the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "あなたは以下の Flatpak をインストールしようとしています:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "インストールしてもよろしいですか?" #~ msgid "Apps Of The Week" #~ msgstr "今週のアプリ" #~ msgctxt "Project URL Type" #~ msgid "VCS Browser" #~ msgstr "VCS ブラウザー" #~ msgid "Full Application View" #~ msgstr "アプリケーションページの表示" #~ msgid "Change what content is shown when viewing applications" #~ msgstr "アプリケーションを見ているときに表示される内容を変更します" #~ msgid "" #~ "If you do not have an access token, turning this setting on may cause " #~ "GitHub to eventually rate limit you." #~ msgstr "" #~ "あなたがアクセストークンを持っていない場合、この設定をオンにしていると " #~ "Github からレート制限をされる恐れがあります。" #~ msgid "Type to filter" #~ msgstr "入力して検索" #~ msgid "Exclude results with proprietary licenses" #~ msgstr "プロプライエタリなライセンスの結果を除外" #~ msgid "Advanced" #~ msgstr "高度なオプション" #~ msgid "Open this link externally" #~ msgstr "このリンクを外部で開く" bazaar-orig-v0.7.14/po/es.po0000664000175000017500000011425415166123241014534 0ustar hasanhasan# SPDX-FileCopyrightText: 2025 Spanish translations for bazaar package # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # # SPDX-FileCopyrightText: 2025 robotta # robotta <>, 2025. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-10-30 01:38+0100\n" "PO-Revision-Date: 2025-10-30 12:15+0100\n" "Last-Translator: robotta <>\n" "Language-Team: Spanish\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 49.0\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:5 #: src/bz-window.blp:56 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "Añade, elimine o actualice programas flatpak en este ordenador" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;Sistema;GestorDePaquetes;Discover;Flatpak;Software;Store;" #: data/io.github.kolunmi.Bazaar.gschema.xml:6 msgid "Show Git Forge Star Counts" msgstr "Mostrar las estadísticas de los forks de Git" #: data/io.github.kolunmi.Bazaar.gschema.xml:7 msgid "" "Whether to attempt to detect and show \"star counts\" for projects in the " "full view" msgstr "" "Decidir si intentar detectar y mostrar la cantidad de estrellas de los " "proyectos en vista completa" #: data/io.github.kolunmi.Bazaar.gschema.xml:11 #: src/bz-preferences-dialog.blp:35 msgid "Only Show Free Software" msgstr "Solo mostrar Software Libre" #: data/io.github.kolunmi.Bazaar.gschema.xml:12 msgid "Hide proprietary software when searching" msgstr "Ocultar software propietario al buscar" #: data/io.github.kolunmi.Bazaar.gschema.xml:16 msgid "Show Only Flathub Content" msgstr "Mostrar solo contenido de Flathub" #: data/io.github.kolunmi.Bazaar.gschema.xml:17 msgid "Filter search results to only show applications available on Flathub" msgstr "" "Filtrar los resultados de búsqueda para que solo aparezcan aplicaciones que " "están en Flathub" #: data/io.github.kolunmi.Bazaar.gschema.xml:21 msgid "Debounce Search Inputs" msgstr "Rebotar los inputs de búsqueda" #: data/io.github.kolunmi.Bazaar.gschema.xml:22 msgid "Add a delay before searching to prevent instant replies while typing" msgstr "" "Aplicar un pequeño retardo al escribir para evitar resultados instantáneos" #: data/io.github.kolunmi.Bazaar.gschema.xml:40 msgid "Global Progress Bar Theme" msgstr "Tema de la barra de progreso global" #: data/io.github.kolunmi.Bazaar.gschema.xml:41 msgid "Describes the look of the global progress bar" msgstr "Describe como se ve la barra de progreso global" #: data/io.github.kolunmi.Bazaar.gschema.xml:45 msgid "Saved Window Dimensions" msgstr "Dimensiones de ventana guardadas" #: data/io.github.kolunmi.Bazaar.gschema.xml:46 msgid "The window dimensions to be used by the next Bazaar window" msgstr "Las dimensiones de la venta que usará la siguiente ventana de Bazaar" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and install applications" msgstr "Descubrir e instalar aplicaciones" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A new app store for GNOME with a focus on discovering and installing " "applications and addons from Flatpak remotes, particularly Flathub." msgstr "" "Una nueva tienda de aplicaciones para GNOME, enfocada a descubrir e instalar " "aplicaciones y complementos de repositorios flatpaks, particularmente de " "Flathub." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:14 msgid "" "It emphasizes supporting the developers who make the Linux desktop possible. " "Bazaar features a \"curated\" tab that can be configured by distributors to " "allow for a more localized experience." msgstr "" "Enfatiza el apoyar a los desarrolladores que hacen que Linux en el " "escritorio sea posible. Bazaar contiene una lista de aplicaciones " "\"Elegidas\" que puede ser configurada por distribuidores para ofrecer una " "experiencia más centrada a sus usuarios." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:29 src/bz-application.c:505 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:54 msgid "The home view displaying Flathub apps" msgstr "La vista principal mostrando aplicaciones de Flathub y sus categorías." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:58 msgid "Nucleus app page" msgstr "Página de Nucleus" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:62 msgid "Searching for Blender" msgstr "Buscando Blender" #: src/bz-addons-dialog.blp:14 src/bz-full-view.blp:271 #: src/bz-installed-page.blp:132 msgid "Manage Add-ons" msgstr "Gestionar los complementos" #: src/bz-addons-dialog.c:88 src/bz-installed-page.blp:158 #: src/bz-transaction-view.blp:212 src/bz-window.c:1125 msgid "Remove" msgstr "Eliminar" #: src/bz-addons-dialog.c:95 src/bz-full-view.blp:244 #: src/bz-transaction-view.blp:186 src/bz-window.c:1103 msgid "Install" msgstr "Instalar" #: src/bz-app-size-dialog.c:55 msgid "Of the size of human DNA" msgstr "Del tamaño del ADN humano" #: src/bz-app-size-dialog.c:55 msgid "3 billion base pairs" msgstr "3 billones de pares base" #: src/bz-app-size-dialog.c:56 msgid "Of the Linux Kernel" msgstr "del kernel de Linux" #: src/bz-app-size-dialog.c:56 msgid "linux-6.17.tar.xz" msgstr "linux-6.17.tar.xz" #: src/bz-app-size-dialog.c:57 msgid "Of the Apollo 11 guidance computer" msgstr "del ordenador guía Apollo 11" #: src/bz-app-size-dialog.c:57 msgid "Total ROM and RAM" msgstr "ROM y RAM total" #: src/bz-app-size-dialog.c:58 msgid "Of the original Super Mario Bros" msgstr "del Super Mario Bros original" #: src/bz-app-size-dialog.c:58 msgid "On the NES" msgstr "En la NES" #: src/bz-app-size-dialog.c:59 msgid "Of the size of Wikipedia" msgstr "Del tamaño de Wikipedia" #: src/bz-app-size-dialog.c:59 msgid "Without any media" msgstr "Sin nada" #: src/bz-app-size-dialog.blp:43 msgid "--- MB" msgstr "--- MB" #: src/bz-app-size-dialog.blp:53 msgid "Download Size" msgstr "Tamaño de la descarga" #: src/bz-application.c:400 msgid "" "This functionality is currently disabled. It is recommended you download and " "install Flatseal to manage app permissions." msgstr "" "Esta funcionalidad está desactivada. Se recomienda que descargues e " "installes Flatseal para modificar los permisos de la aplicación." #: src/bz-application.c:464 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:465 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:481 msgid "translator-credits" msgstr "robotta" #: src/bz-application.c:470 msgctxt "About Dialog Translator Credit" msgid "Ahmed Najmawi" msgstr "Ahmed Najmawi" #: src/bz-application.c:471 msgctxt "About Dialog Translator Credit" msgid "AtomHare" msgstr "AtomHare" #: src/bz-application.c:472 msgctxt "About Dialog Translator Credit" msgid "Azenyr" msgstr "Azenyr" #: src/bz-application.c:473 msgctxt "About Dialog Translator Credit" msgid "Goudarz Jafari" msgstr "Goudarz Jafari" #: src/bz-application.c:474 msgctxt "About Dialog Translator Credit" msgid "Jill Fiore (Lumaeris)" msgstr "Jill Fiore (Lumaeris)" #: src/bz-application.c:475 msgctxt "About Dialog Translator Credit" msgid "João Victor (Leal)" msgstr "João Victor (Leal)" #: src/bz-application.c:476 msgctxt "About Dialog Translator Credit" msgid "KiKaraage" msgstr "KiKaraage" #: src/bz-application.c:477 msgctxt "About Dialog Translator Credit" msgid "Lucosec" msgstr "Lucosec" #: src/bz-application.c:478 msgctxt "About Dialog Translator Credit" msgid "Léane GRASSER" msgstr "Léane GRASSER" #: src/bz-application.c:479 msgctxt "About Dialog Translator Credit" msgid "Marcel Mrówka (Microwave)" msgstr "Marcel Mrówka (Microwave)" #: src/bz-application.c:480 msgctxt "About Dialog Translator Credit" msgid "Peter Dave Hello" msgstr "Peter Dave Hello" #: src/bz-application.c:481 msgctxt "About Dialog Translator Credit" msgid "Pietro F." msgstr "Pietro F." #: src/bz-application.c:482 msgctxt "About Dialog Translator Credit" msgid "Sabri Ünal" msgstr "Sabri Ünal" #: src/bz-application.c:483 msgctxt "About Dialog Translator Credit" msgid "Shihfu Juan" msgstr "Shihfu Juan" #: src/bz-application.c:484 msgctxt "About Dialog Translator Credit" msgid "Shinsei" msgstr "Shinsei" #: src/bz-application.c:485 msgctxt "About Dialog Translator Credit" msgid "Vlastimil Dědek" msgstr "Vlastimil Dědek" #: src/bz-application.c:486 msgctxt "About Dialog Translator Credit" msgid "asen23" msgstr "asen23" #: src/bz-application.c:487 msgctxt "About Dialog Translator Credit" msgid "camegone" msgstr "camegone" #: src/bz-application.c:488 msgctxt "About Dialog Translator Credit" msgid "renner" msgstr "renner" #: src/bz-application.c:489 msgctxt "About Dialog Translator Credit" msgid "robotta" msgstr "robotta" #: src/bz-application.c:1032 msgid "Constructing Flatpak instance..." msgstr "Construyendo instancia de Flatpak..." #: src/bz-application.c:1049 msgid "Reusing last Flatpak instance..." msgstr "Reutilizando la última instancia de Flatpak..." #: src/bz-application.c:1074 msgid "Flathub is not registered on this system" msgstr "Flathub no está registrado en este sistema" #: src/bz-application.c:1077 msgid "" "Would you like to add Flathub as a remote? If you decline, the Flathub page " "will not be available. You can change this later." msgstr "" "Le gustaría añadir Flathub como un repositorio? De lo contrario, la página " "de Flathub no estará disponible. Puede cambiarlo más tarde." #: src/bz-application.c:1082 src/bz-update-dialog.blp:6 msgid "Later" msgstr "Más tarde" #: src/bz-application.c:1083 msgid "Add Flathub" msgstr "Añadir Flathub" #: src/bz-application.c:1115 #, c-format msgid "Identifying installed entries..." msgstr "Identificando las entradas instaladas..." #: src/bz-application.c:1127 #, c-format msgid "Beginning remote entry retrieval while referencing %d blocklist(s)..." msgstr "" "Empezando la recuperación de entradas mientras se referencia %d bloqueada(as)" #: src/bz-application.c:1275 #, c-format msgid "Receiving Entries" msgstr "Recibiendo entradas..." #: src/bz-application.c:1276 #, c-format msgid "%'d of %'d" msgstr "%'d de %'d" #: src/bz-application.c:1286 #, c-format msgid "Waiting for background indexing tasks to catch up..." msgstr "Esperando que las tareas en segundo plano se pongan al día..." #: src/bz-application.c:1322 #, c-format msgid "Completed initialization in %0.2f seconds" msgstr "Se ha completado el inicio en %0.2f segundos" #: src/bz-application.c:1327 src/bz-application.c:1482 msgid "Checking for updates..." msgstr "Viendo si hay actualizaciones..." #: src/bz-application.c:1366 msgid "Synchronizing..." msgstr "Sincronizando..." #: src/bz-browse-widget.blp:11 src/bz-flathub-page.blp:15 #: src/bz-full-view.blp:10 src/bz-installed-page.blp:15 src/bz-window.blp:161 msgid "Empty" msgstr "Vacío" #: src/bz-browse-widget.blp:15 msgid "No Curated Applications" msgstr "Aplicaciones no seleccionadas " #: src/bz-browse-widget.blp:16 msgid "" "Bazaar was not provided a curated content configuration. Contact your " "operating system's support channels for assistance." msgstr "" "Bazaar no ha recibido una configuración dedicada para contenido " "seleccionado. Contacta con los canales de soporte de tu sistema operativo " "para soliticar asistencia." #: src/bz-browse-widget.blp:22 src/bz-flathub-page.blp:26 msgid "Browser" msgstr "Buscador" #: src/bz-entry-inspector.blp:5 msgid "Entry Inspector" msgstr "Inspeccionar entrada" #: src/bz-entry-inspector.blp:76 msgid "Serialize" msgstr "Serializar" #: src/bz-entry-inspector.blp:80 msgid "Convert to JSON" msgstr "Convertir a JSON" #: src/bz-error.c:68 msgid "An Error Occurred" msgstr "Ha ocurrido un error" #: src/bz-error.c:89 msgid "Close" msgstr "Cerrar" #: src/bz-error.c:90 msgid "Copy and Close" msgstr "Copiar y Cerrar" #: src/bz-featured-tile.blp:89 msgid "App of the Day" msgstr "Aplicación del día" #: src/bz-flathub-category.c:325 msgid "Audio & Video" msgstr "Audio y Video" #: src/bz-flathub-category.c:327 msgid "Developer Tools" msgstr "Herramientas de Desarollo" #: src/bz-flathub-category.c:329 msgid "Education" msgstr "Educación" #: src/bz-flathub-category.c:331 msgid "Gaming" msgstr "Gaming" #: src/bz-flathub-category.c:333 msgid "Graphics & Photography" msgstr "Fotografía y Edición de gráficos" #: src/bz-flathub-category.c:335 msgid "Networking" msgstr "Conexiones y Redes" #: src/bz-flathub-category.c:337 msgid "Productivity" msgstr "Productividad" #: src/bz-flathub-category.c:339 msgid "Science" msgstr "Ciencia" #: src/bz-flathub-category.c:341 msgid "System" msgstr "Sistema" #: src/bz-flathub-category.c:343 msgid "Utilities" msgstr "Utilidades" #: src/bz-flathub-category-section.c:137 #, c-format msgid "%d applications" msgstr "%d aplicaciones" #: src/bz-flathub-category-section.c:336 #, c-format msgid "More %s" msgstr "Más %s" #: src/bz-flathub-page.blp:19 msgid "Flathub Not Added" msgstr "Flathub no está añadido" #: src/bz-flathub-page.blp:20 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "" "El remoto de Flathub no se encontró en ninguna de sus instalaciones de " "Flatpak." #: src/bz-flathub-page.blp:71 src/bz-flathub-page.blp:99 #: src/bz-flathub-page.c:168 msgid "Trending" msgstr "De moda" #: src/bz-flathub-page.blp:76 src/bz-flathub-page.blp:225 #: src/bz-flathub-page.c:198 msgid "Popular" msgstr "Populares" #: src/bz-flathub-page.blp:81 msgid "New" msgstr "Nuevo" #: src/bz-flathub-page.blp:86 msgid "Updated" msgstr "Actualizado" #: src/bz-flathub-page.blp:131 msgid "More Trending" msgstr "Ver más artículos de moda" #: src/bz-flathub-page.blp:141 src/bz-flathub-page.c:178 msgid "Recently Updated" msgstr "Actualizadas recientemente" #: src/bz-flathub-page.blp:173 msgid "More Updated" msgstr "Ver más actualizadas recientemente" #: src/bz-flathub-page.blp:183 src/bz-flathub-page.c:188 msgid "Recently Added" msgstr "Recién sacados del horno" #: src/bz-flathub-page.blp:215 msgid "More New" msgstr "Ver más aplicaciones nuevas" #: src/bz-flathub-page.blp:257 msgid "More Popular" msgstr "Ver más populares" #: src/bz-flatpak-entry.c:552 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Página de Flathub" #: src/bz-flatpak-entry.c:573 msgctxt "Project URL Type" msgid "Project Website" msgstr "Página del proyecto" #: src/bz-flatpak-entry.c:577 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Rastreador de problemas" #: src/bz-flatpak-entry.c:581 msgctxt "Project URL Type" msgid "FAQ" msgstr "Preguntas Frecuentes" #: src/bz-flatpak-entry.c:585 msgctxt "Project URL Type" msgid "Help" msgstr "Ayuda" #: src/bz-flatpak-entry.c:589 msgctxt "Project URL Type" msgid "Donate" msgstr "Donar" #: src/bz-flatpak-entry.c:595 msgctxt "Project URL Type" msgid "Translate" msgstr "Traducir" #: src/bz-flatpak-entry.c:599 msgctxt "Project URL Type" msgid "Contact" msgstr "Contactar" #: src/bz-flatpak-entry.c:603 msgctxt "Project URL Type" msgid "Source Code" msgstr "Código fuente" #: src/bz-flatpak-entry.c:609 msgctxt "Project URL Type" msgid "Contribute" msgstr "Contribuir" #: src/bz-full-view.blp:14 msgid "No Results" msgstr "Sin Resultados" #: src/bz-full-view.blp:15 msgid "Try a different search query" msgstr "Prueba con un término de búsqueda diferente" #: src/bz-full-view.blp:21 src/bz-window.blp:171 msgid "Content" msgstr "Contenido" #: src/bz-full-view.blp:151 msgid "Verified by the original developers" msgstr "Verificado por los desarrolladores originales de este programa" #: src/bz-full-view.blp:178 msgid "Support" msgstr "Apoyar" #: src/bz-full-view.blp:198 msgid "Repository Star Count" msgstr "Cantidad de estrellas de este repositorio" #: src/bz-full-view.blp:228 msgid "Open" msgstr "Abrir" #: src/bz-full-view.blp:241 msgid "Download & Install Application" msgstr "Descargar e instalar la aplicación" #: src/bz-full-view.blp:256 msgid "Uninstall Application" msgstr "Desinstalar la aplicación" #: src/bz-full-view.blp:284 msgid "Install Other Version" msgstr "Instalar otra versión" #: src/bz-full-view.blp:308 msgid "Download" msgstr "Tamaño" #: src/bz-full-view.blp:424 msgid "Downloads/mo" msgstr "Descargas por mes" #: src/bz-full-view.c:259 msgid "---" msgstr "---" #. Translators: M is the suffix for millions, \xC2\xA0 is a non-breaking space #: src/bz-full-view.c:263 #, c-format msgid "%.2f M" msgstr "%.2f M" #. Translators: K is the suffix for thousands, \xC2\xA0 is a non-breaking space #: src/bz-full-view.c:266 #, c-format msgid "%.2f K" msgstr "%.2f K" #: src/bz-full-view.c:275 #, c-format msgid "%d downloads in the last 30 days" msgstr "%d descargas en los últimos 30 días" #: src/bz-full-view.c:296 #, c-format msgid "Download size of %s" msgstr "Tamaño de la descarga de %s" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-full-view.c:306 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-full-view.c:314 msgid "All Ages" msgstr "Para todas las edades" #: src/bz-full-view.c:316 msgid "Age Rating" msgstr "Calificación por edades" #: src/bz-full-view.c:324 msgid "Suitable for all ages" msgstr "Apto para todas las edades" #: src/bz-full-view.c:326 #, c-format msgid "Suitable for ages %d and up" msgstr "Apto para mayores de %d" #: src/bz-full-view.c:346 msgid "Unknown" msgstr "Desconocido" #: src/bz-full-view.c:349 msgid "Proprietary Software" msgstr "Software Propietario" #: src/bz-full-view.c:353 #, c-format msgid "Free software licensed under %s" msgstr "Software libre licendiado bajo %s" #: src/bz-full-view.c:361 msgid "Free" msgstr "Libre" #: src/bz-full-view.c:361 msgid "Proprietary" msgstr "Propietario" #: src/bz-full-view.c:381 msgid "Adaptive" msgstr "Adaptativo" #: src/bz-full-view.c:381 msgid "Desktop Only" msgstr "Sólo para escritorio" #: src/bz-full-view.c:387 msgid "Works on desktop, tablets, and phones" msgstr "Funciona en escritorio, tablets y móviles" #: src/bz-full-view.c:388 msgid "May not work on mobile devices" msgstr "Puede que no funcione en móviles" #: src/bz-full-view.c:399 msgid "No URL" msgstr "Sin enlace" #: src/bz-full-view.c:417 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Esta aplicación tiene una licencia FLOSS, lo que significa que el código " "fuente puede ser ojeado por seguridad." #: src/bz-full-view.c:418 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Esta aplicación tiene una licencia propietaria, lo que significa que el " "código fuente se desarolla de manera privada y no puede ser ojeado por " "ningún equipo de terceros." #: src/bz-hardware-support-dialog.c:69 msgid "Keyboard support" msgstr "Soporte de Teclado" #: src/bz-hardware-support-dialog.c:71 msgid "Requires keyboards" msgstr "Requiere teclado" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends keyboards" msgstr "Recomienda teclado" #: src/bz-hardware-support-dialog.c:73 msgid "Supports keyboards" msgstr "Soporta teclado" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for keyboards" msgstr "Soporte desconocido de teclado" #: src/bz-hardware-support-dialog.c:76 msgid "Mouse support" msgstr "Soporta ratón" #: src/bz-hardware-support-dialog.c:78 msgid "Requires mice or pointing devices" msgstr "Requiere ratón o puntero" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends mice or pointing devices" msgstr "Recomienda ratón o puntero" #: src/bz-hardware-support-dialog.c:80 msgid "Supports mice or pointing devices" msgstr "Soporta ratón o puntero" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for mice or pointing devices" msgstr "Soporte desconocido de ratón o puntero" #: src/bz-hardware-support-dialog.c:83 msgid "Touchscreen support" msgstr "Soporta pantalla táctil" #: src/bz-hardware-support-dialog.c:85 msgid "Requires touchscreens" msgstr "Requiere pantalla táctil" #: src/bz-hardware-support-dialog.c:86 msgid "Recommends touchscreens" msgstr "Recomienda pantalla táctil" #: src/bz-hardware-support-dialog.c:87 msgid "Supports touchscreens" msgstr "Soporta pantalla táctil" #: src/bz-hardware-support-dialog.c:88 msgid "Unknown support for touchscreens" msgstr "Soporte desconocido de pantalla táctil" #: src/bz-hardware-support-dialog.c:192 msgid "Mobile support" msgstr "Soporte de móviles" #: src/bz-hardware-support-dialog.c:193 msgid "Works on mobile devices" msgstr "Funciona en móviles" #: src/bz-hardware-support-dialog.c:193 msgid "May not work well on mobile devices" msgstr "Puede no funcionar bien en móviles" #: src/bz-hardware-support-dialog.c:198 msgid "Desktop support" msgstr "Soporte de escritorio" #: src/bz-hardware-support-dialog.c:199 msgid "Works well on large screens" msgstr "Funciona bien en pantallas grandes" #: src/bz-hardware-support-dialog.c:233 #, c-format msgid "%s works best on specific hardware" msgstr "%s funcionan bien en hardware específico" #: src/bz-hardware-support-dialog.c:240 #, c-format msgid "%s works on most devices" msgstr "%s funcionan en la mayoría de dispositivos" #: src/bz-hardware-support-dialog.blp:6 src/bz-hardware-support-dialog.blp:47 msgid "Hardware Support" msgstr "Soporte de hardware" #: src/bz-inspector.blp:5 msgid "Bazaar Inspector" msgstr "Inspector de Bazaar" #: src/bz-inspector.blp:22 msgid "Active Blocklists" msgstr "Listas bloqueadas activas" #: src/bz-inspector.blp:44 msgid "Active Curated-Configs" msgstr "Configuraciones de selecciones activas" #: src/bz-inspector.blp:66 msgid "All Entry Groups" msgstr "Grupos con todas las entradas" #: src/bz-inspector.blp:69 msgid "Filter..." msgstr "Filtrar..." #: src/bz-inspector.blp:110 msgid "Decache and Inspect" msgstr "Inspeccionar y borrar caché" #: src/bz-installed-page.blp:19 msgid "No Flatpaks Installed" msgstr "No hay flatpaks instalados" #: src/bz-installed-page.blp:25 src/bz-window.blp:305 src/bz-window.blp:399 msgid "Installed" msgstr "Instalados" #: src/bz-installed-page.blp:108 msgid "Support this application" msgstr "Apoyar esta aplicación" #: src/bz-installed-page.blp:185 msgid "More actions" msgstr "Más acciones" #: src/bz-installed-page.blp:204 msgid "Run this application" msgstr "Iniciar esta aplicación" #: src/bz-installed-page.blp:216 msgid "Run" msgstr "Iniciar" #: src/bz-installed-page.blp:228 src/bz-installed-page.blp:239 msgid "View Store Page" msgstr "Mirar en la tienda" #: src/bz-installed-page.c:649 msgid "Choose an Installation" msgstr "Elije una instalación" #: src/bz-installed-page.c:652 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with? " msgstr "" "Cuenta con varias versiones instaladas de esta aplicación. Con cual quiere " "proceder?" #: src/bz-installed-page.c:656 src/bz-window.c:1102 src/bz-window.c:1124 msgid "Cancel" msgstr "Cancelar" #: src/bz-license-dialog.c:115 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may not be able to contribute to this app." msgstr "" "Esta aplicación no se desarrolla en código abierto, así que solo sus " "desarrolladores saben como funciona. Puede ser insegura de manera que es " "difícil de detectar, y puede cambiar sin previo aviso.\n" "\n" "Puede que no pueda contribuir a esta aplicación. " #: src/bz-license-dialog.c:124 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Esta aplicación se desarrolla en código abierto por una comunidad " "internacional.\n" "\n" "Puede contribuir a esta aplicación y ayudar a mejorarla." #: src/bz-license-dialog.c:135 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Esta aplicación se desarrolla en código abierto por una comunidad " "internacional, y se lanza bajo la licencia %s\n" "\n" "Puede contribuir a esta aplicación y ayudar a mejorarla." #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Ajustes" #: src/bz-preferences-dialog.blp:23 msgid "Application Details" msgstr "Detalles de la aplicación" #: src/bz-preferences-dialog.blp:26 msgid "Git Forge Star Counts" msgstr "Contador de estrellas de la forja de Git" #: src/bz-preferences-dialog.blp:27 msgid "Not having a GitHub access token may trigger rate limits" msgstr "" "El no tener acceso al token de Github puede ocasionar límites de " "clasificaciones" #: src/bz-preferences-dialog.blp:32 src/bz-window.blp:48 src/bz-window.blp:337 msgid "Search" msgstr "Buscar" #: src/bz-preferences-dialog.blp:36 msgid "Hide proprietary applications from search results" msgstr "No mostrar aplicaciones propietarias en los resultados de búsqueda" #: src/bz-preferences-dialog.blp:40 msgid "Show Only Flathub Apps" msgstr "Mostrar únicamente aplicaciones de Flathub" #: src/bz-preferences-dialog.blp:41 msgid "Limit search results to applications available on Flathub" msgstr "" "Limitar los resultados de búsqueda a sólo aplicaciones disponibles en Flathub" #: src/bz-preferences-dialog.blp:45 msgid "Debounce Search Results" msgstr "Retrasar la ejecución de las búsquedas" #: src/bz-preferences-dialog.blp:46 msgid "Wait for a brief pause to reduce system load" msgstr "Esperar por una breve pausa para reducir la carga en el sistema" #: src/bz-preferences-dialog.blp:51 msgid "Progress Bar" msgstr "Barra de progreso " #: src/bz-preferences-dialog.blp:52 msgid "Choose a theme for the progress bar!" msgstr "Escoja un tema para la barra de progreso!" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Color de realce personal" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Colores del Orgullo" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "Colores del Orgullo Lésbico" #: src/bz-preferences-dialog.c:35 msgid "Transgender Pride Colors" msgstr "Colores del Orgullo Transgénero" #: src/bz-preferences-dialog.c:36 msgid "Nonbinary Pride Colors" msgstr "Colores del Orgullo No Binario" #: src/bz-preferences-dialog.c:37 msgid "Bisexual Pride Colors" msgstr "Colores del Orgullo Bisexual" #: src/bz-preferences-dialog.c:38 msgid "Asexual Pride Colors" msgstr "Colores del Orgullo Asexual" #: src/bz-preferences-dialog.c:39 msgid "Pansexual Pride Colors" msgstr "Colores del Orgullo Pansexual" #: src/bz-preferences-dialog.c:40 msgid "Aromantic Pride Colors" msgstr "Colores del Orgullo Aromántico" #: src/bz-preferences-dialog.c:41 msgid "Genderfluid Pride Colors" msgstr "Colores del Orgullo de Género fluído" #: src/bz-preferences-dialog.c:42 msgid "Polysexual Pride Colors" msgstr "Colores del Orgullo Polisexual" #: src/bz-preferences-dialog.c:43 msgid "Omnisexual Pride Colors" msgstr "Colores del Orgullo Omnisexual " #: src/bz-releases-dialog.blp:5 src/bz-releases-list.blp:25 msgid "Version History" msgstr "Historial de versiones" #: src/bz-releases-list.c:128 #, c-format msgid "Version %s" msgstr "Versión %s" #: src/bz-releases-list.c:153 msgid "No details for this release" msgstr "No hay detalles de este lanzamiento" #: src/bz-search-widget.blp:69 msgid "Search Apps" msgstr "Buscar Aplicaciones" #: src/bz-share-list.c:64 msgid "Copied!" msgstr "Copiada!" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "Copiar enlace" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Abrir enlace" #: src/bz-stats-dialog.blp:26 msgid "Timeline" msgstr "Línea de tiempo" #: src/bz-stats-dialog.blp:31 msgid "Installs:" msgstr "Instalaciones:" #: src/bz-stats-dialog.blp:37 msgid "World" msgstr "Global" #: src/bz-transaction-manager.c:1140 #, c-format msgid "Finished in %.02f seconds" msgstr "Terminado en %.02f segundos" #: src/bz-transaction-view.blp:94 msgid "App Add-on" msgstr "Complementos para la aplicación" #: src/bz-transaction-view.blp:119 msgid "Runtime" msgstr "Tiempo de ejecución" #: src/bz-transaction-view.blp:145 src/bz-transaction-view.blp:171 msgid "Install Size" msgstr "Tamaño de instalación" #: src/bz-transaction-view.blp:199 src/bz-window.blp:350 msgid "Update" msgstr "Actualizar" #: src/bz-transaction-view.c:139 #, c-format msgid "Transferred %s so far" msgstr "Transferidos %s por ahora" #: src/bz-transaction.c:336 msgid "Pending" msgstr "Pendiente" #: src/bz-update-dialog.blp:7 msgid "Install Now" msgstr "Instalar ahora" #: src/bz-update-dialog.blp:10 msgid "Updates Are Available" msgstr "Hay actualizaciones disponibles" #: src/bz-update-dialog.blp:11 msgid "" "The following applications are eligible for updates. Would you like to " "install them?" msgstr "" "Las siguientes aplicaciones pueden ser actualizadas. ¿Le gustaría " "actualizarlas?" #: src/bz-update-dialog.c:134 #, c-format msgid "" "%d runtimes and/or addons are eligible for updates. Would you like to " "install them?" msgstr "" "%d tiempos de ejecución y / o los complementos pueden ser actualizados. ¿Le " "gustaría actualizarlos?" #: src/bz-update-dialog.c:142 #, c-format msgid "Additionally, %d runtimes and/or addons will be updated." msgstr "" "Adicionalmente, %d tiempos de ejecución y / o los complementos serán " "actualizados." #: src/bz-window.blp:63 msgid "Go Home" msgstr "Ir a Inicio" #: src/bz-window.blp:86 msgid "Tasks" msgstr "Tareas" #: src/bz-window.blp:105 src/bz-window.blp:418 msgid "Toggle transaction sidebar" msgstr "Mostrar la barra lateral de las transacciones" #: src/bz-window.blp:141 msgid "Stop Active Tasks" msgstr "Detener tareas activas" #: src/bz-window.blp:149 msgid "Clear History" msgstr "Limpiar el historial" #: src/bz-window.blp:165 msgid "No Tasks Yet" msgstr "No hay tareas" #: src/bz-window.blp:219 src/bz-window.blp:223 msgid "Offline" msgstr "Sin Internet" #: src/bz-window.blp:229 msgid "Loading" msgstr "Cargando" #: src/bz-window.blp:270 msgid "Browse" msgstr "Navegar" #: src/bz-window.blp:280 msgid "App View" msgstr "Vista de Aplicación" #: src/bz-window.blp:295 src/bz-window.blp:392 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:325 msgid "Go Back" msgstr "Ir atrás" #: src/bz-window.blp:381 msgid "View curated applications" msgstr "Ver las aplicaciones seleccionadas" #: src/bz-window.blp:385 msgid "Curated" msgstr "Seleccionado" #: src/bz-window.blp:389 msgid "View the latest on Flathub" msgstr "Ver lo último en Flathub" #: src/bz-window.blp:396 msgid "View installed applications" msgstr "Ver aplicaciones instaladas" #: src/bz-window.blp:441 msgid "Main Menu" msgstr "Menú Principal" #: src/bz-window.blp:486 msgid "_Donate to Bazaar ❤️" msgstr "_Hacer un donativo a Bazaar ❤️" #: src/bz-window.blp:491 msgid "_Refresh Content" msgstr "_Actualizar el contenido" #: src/bz-window.blp:498 msgid "_Preferences" msgstr "_Preferencias" #: src/bz-window.blp:503 msgid "_Keyboard Shortcuts" msgstr "_Atajos de Teclado" #: src/bz-window.blp:508 msgid "_About Bazaar" msgstr "_Sobre Bazaar" #: src/bz-window.blp:515 msgid "_Quit Bazaar" msgstr "_Salir de Bazaar" #: src/bz-window.c:827 msgid "" "The ability to inspect and install local .flatpak bundle files is coming " "soon! In the meantime, try running\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "on the command line." msgstr "" "La opción de inspeccionar e instalar colleciones de .flatpak llegará pronto! " "De mientras, pruebe a iniciar\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "en el terminal." #: src/bz-window.c:967 msgid "Can't do that right now!" msgstr "¡No se puede hacer eso ahora mismo!" #: src/bz-window.c:1096 #, c-format msgid "Install %s?" msgstr "Instalar %s?" #: src/bz-window.c:1099 msgid "May install additional shared components" msgstr "Puede que instale componentes compartidos adicionales" #: src/bz-window.c:1118 #, c-format msgid "Remove %s?" msgstr "Eliminar %s?" #: src/bz-window.c:1121 msgid "Settings & user data will be kept" msgstr "Los ajustes personales y datos de usuario se mantendrán" #: src/bz-window.c:1289 msgid "Resume Current Tasks" msgstr "Reanudar las tareas" #: src/bz-window.c:1295 msgid "Pause Current Tasks" msgstr "Pausar las tareas" #: src/bz-world-map.c:523 #, c-format msgid "%s: %'u downloads" msgstr "%s: %'u descargas" #: src/gtk/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "General" #: src/gtk/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "Abrir la barra de búsqueda" #: src/gtk/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Abrir ajustes" #: src/gtk/shortcuts-dialog.blp:19 msgctxt "shortcut window" msgid "Refresh" msgstr "Refrescar" #: src/gtk/shortcuts-dialog.blp:24 msgctxt "shortcut window" msgid "Toggle Transaction Manager" msgstr "Mostrar el administrador de transacciones" #: src/gtk/shortcuts-dialog.blp:29 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Mostrar atajos" #: src/gtk/shortcuts-dialog.blp:34 msgctxt "shortcut window" msgid "Quit" msgstr "Salir" #~ msgid "Calligraphy application page" #~ msgstr "Página de la aplicación \"Calligraphy\"" #~ msgid "Download graph for Blender" #~ msgstr "Gráfica de descargas de Blender" #~ msgid "Manage Addons" #~ msgstr "Gestionar complementos" #~ msgid "Open this image in the default image viewer" #~ msgstr "Abrir esta imagen en el mostrador de imágenes por defecto" #~ msgid "Copy this image to the clipboard" #~ msgstr "Copiar esta imagen al portapapeles" #~ msgid "Games" #~ msgstr "Juegos" #~ msgid "Graphics" #~ msgstr "Gráficos" #~ msgid "Office" #~ msgstr "Ofimática" #~ msgid "Categories" #~ msgstr "Categorías" #~ msgctxt "Project URL Type" #~ msgid "Homepage" #~ msgstr "Inicio" #~ msgid "Share this application" #~ msgstr "Compartir esta aplicación" #~ msgid "Excludes shared components" #~ msgstr "Excluye componentes compartidos" #~ msgid "Free Software" #~ msgstr "Software Libre" #~ msgid "in the last month" #~ msgstr "En el último mes" #~ msgid "Repositories" #~ msgstr "Repositorios" #~ msgid "Open in browser" #~ msgstr "Abrir en el navegador" #~ msgid "--- Downloads" #~ msgstr "--- Descargas" #~ msgid "%B %-d, %Y" #~ msgstr "%-d %B, %Y" #~ msgid "%B %-d" #~ msgstr "%-d %B" #~ msgid "Theme" #~ msgstr "Tema" #~ msgid "Pride Rainbow Flag" #~ msgstr "Bandera del Orgullo" #~ msgid "Bisexual Flag" #~ msgstr "Bandera Bisexual" #~ msgid "Asexual Flag" #~ msgstr "Bandera Asexual" #~ msgid "Share" #~ msgstr "Compartir" #~ msgid "Updated Size" #~ msgstr "Tamaño de actualización" #~ msgid "Freed Space" #~ msgstr "Espacio libre" #~ msgid "Error Details" #~ msgstr "Detalles del error" #~ msgid "Transactions Will Appear Here" #~ msgstr "Las transacciones aparecerán aquí" #~ msgid "Halt the execution of transactions" #~ msgstr "Cortar las transacciones en curso" #~ msgid "Clear all finished transactions" #~ msgstr "Limpiar todas las transacciones completas" #~ msgid "_Quit Service" #~ msgstr "_Terminar el proceso" #~ msgid "Up to date!" #~ msgstr "Al día!" #~ msgid "Resume the execution of transactions" #~ msgstr "Continuar con las transacciones" #~ msgid "Pause the execution of transactions" #~ msgstr "Pausar las transacciones" #~ msgid "Show Animated Background" #~ msgstr "Mostrar fondo animado" #~ msgid "Whether to show the animated icon background on the home page" #~ msgstr " Añade un fondo de iconos animado en la pantalla de inicio" #~ msgid "Keep the summary shorter, between 10 and 35 characters" #~ msgstr "Mantener la descripción corta, alrededor de 10 a 35 caracteres" #~ msgid "No description" #~ msgstr "Sin descripción" #~ msgid "Main Bazaar window showing Blender" #~ msgstr "La ventana principal de Bazaar mostrando Blender" #~ msgid "Apps Of The Week" #~ msgstr "Aplicaciones de la semana" #~ msgid "" #~ "The number of downloads in the last 30 days. Click to view this " #~ "application's download statistics." #~ msgstr "" #~ "El número de descargas en los últimos 30 días. Haga click aquí para ver " #~ "las estadísticas de descargas de esta aplicación." #~ msgid "Remote repo name" #~ msgstr "Nombre del repositorio remoto" #, c-format #~ msgid "Released %x" #~ msgstr "Lanzado el %x" #~ msgid "Edit Permissions" #~ msgstr "Editar permisos" #~ msgid "How the application looks" #~ msgstr "Cómo se ve la aplicación" #~ msgid "Appearance" #~ msgstr "Apariencia" #~ msgid "Show animated background" #~ msgstr "Mostrar fondo animado" #~ msgid "Type to filter" #~ msgstr "Escribe para filtrar" #~ msgid "Exclude results with proprietary licenses" #~ msgstr "No inclúir resultados con licencia propietaria" #~ msgid "Exclude results not originating from Flathub" #~ msgstr "No incluir resultados ajenos a Flathub" #~ msgid "Advanced" #~ msgstr "Avanzado" #~ msgid "Match using regular expressions" #~ msgstr "Coincidir usando expresiones comunes" #~ msgid "Hide filtering and sorting behind a crossfade effect" #~ msgstr "Esconder el filtrar y ordenar con un efecto crossfade" #~ msgid "Open this link externally" #~ msgstr "Abrir este enlace externamente" #~ msgid "Downloads Over Time" #~ msgstr "Descargas con el paso del tiempo" #~ msgid "Minimize Lower Bound" #~ msgstr "Minimizar el límite inferior" #~ msgid "Maximize Upper Bound" #~ msgstr "Maximiza el límite superior" #~ msgid "Installing" #~ msgstr "Instalando" #~ msgid "Updating" #~ msgstr "Actualizando" #~ msgid "Removing" #~ msgstr "Eliminando" #~ msgid "Refresh" #~ msgstr "Refrescar" #~ msgid "Confirm Action" #~ msgstr "Confirmar" #, c-format #~ msgid "" #~ "You are about to remove the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "Está a punto de eliminar el Flatpak a continuación:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "¿Está seguro?" #, c-format #~ msgid "" #~ "You are about to install the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "Está a punto de instalar el Flatpak a continuación:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "¿Está seguro?" bazaar-orig-v0.7.14/po/LINGUAS0000664000175000017500000000021415166123241014600 0ustar hasanhasan# Please keep this file sorted alphabetically. ar be bg bs cs de el es fa_IR fr ga hu id it ja kw nl pl pt_BR pt_PT ru tr uk vi zh_CN zh_TW bazaar-orig-v0.7.14/po/bs.po0000664000175000017500000003471115166123241014530 0ustar hasanhasan# Bosnian translations for bazaar package. # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Manually modified from a previous translation, 2025. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-09-02 08:40+0200\n" "PO-Revision-Date: 2025-09-02 09:06+0200\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: bs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Poedit 3.6\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:5 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "Dodajte, uklonite ili ažurirajte flatpak softver na ovom računaru" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;Sistem;UpraviteljPaketa;Otkrijte;Flatpak;Softver;Prodavnica;" #: data/io.github.kolunmi.Bazaar.gschema.xml:6 msgid "Show Animated Background" msgstr "Prikaži animiranu pozadinu" #: data/io.github.kolunmi.Bazaar.gschema.xml:7 msgid "Whether to show the animated icon background on the home page" msgstr "Da li već prikazati animiranu pozadinu ikone na početnoj stranici" #. FIXME: add descriptions and summary #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:9 msgid "Keep the summary shorter, between 10 and 35 characters" msgstr "Sažetak neka bude kraći, između 10 i 35 znakova" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:11 msgid "No description" msgstr "Nema opisa" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:15 src/bz-application.c:1215 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:41 msgid "Main Bazaar window showing Blender" msgstr "Glavni prozor Bazaara koji prikazuje Blender" #: src/bz-addons-dialog.blp:13 src/bz-installed-page.blp:162 #: src/bz-installed-page.blp:174 msgid "Manage Addons" msgstr "Upravljanje dodacima" #: src/bz-app-tile.blp:65 src/bz-full-view.blp:139 msgid "This flatpak is verified by the original developers of the software." msgstr "Ovaj flatpak je verifikovan od strane originalnih programera softvera." #: src/bz-application.c:1186 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:481 msgid "translator-credits" msgstr "SecularSteve" #: src/bz-application.c:1191 msgctxt "About Dialog Translator Credit" msgid "Ahmed Najmawi" msgstr "Ahmed Najmawi" #: src/bz-application.c:1192 msgctxt "About Dialog Translator Credit" msgid "AtomHare" msgstr "AtomHare" #: src/bz-application.c:1193 msgctxt "About Dialog Translator Credit" msgid "Jill Fiore" msgstr "Jill Fiore" #: src/bz-application.c:1194 msgctxt "About Dialog Translator Credit" msgid "Lucosec" msgstr "Lucosec" #: src/bz-application.c:1195 msgctxt "About Dialog Translator Credit" msgid "Shihfu Juan" msgstr "Shihfu Juan" #: src/bz-application.c:1196 msgctxt "About Dialog Translator Credit" msgid "Vlastimil Dědek" msgstr "Vlastimil Dědek" #: src/bz-application.c:1197 msgctxt "About Dialog Translator Credit" msgid "asen23" msgstr "asen23" #: src/bz-application.c:1198 msgctxt "About Dialog Translator Credit" msgid "renner" msgstr "renner" #: src/bz-application.c:1199 msgctxt "About Dialog Translator Credit" msgid "robotta" msgstr "robotta" #: src/bz-browse-widget.blp:11 src/bz-full-view.blp:11 #: src/bz-installed-page.blp:11 src/bz-window.blp:32 msgid "Empty" msgstr "Prazno" #: src/bz-browse-widget.blp:15 msgid "No Curated Applications" msgstr "Nema izloženih aplikacija" #: src/bz-browse-widget.blp:16 msgid "Bazaar was not provided a curated content configuration. Contact your operating system's support channels for assistance." msgstr "Bazaaru nije pružena konfiguracija izloženog sadržaja. Za pomoć kontaktirajte kanale podrške vašeg operativnog sistema." #: src/bz-browse-widget.blp:22 src/bz-flathub-page.blp:11 msgid "Browser" msgstr "Pretraživač" #: src/bz-error.c:45 msgid "An Error Occurred" msgstr "Došlo je do greške" #: src/bz-error.c:51 msgid "Close" msgstr "Zatvori" #: src/bz-error.c:52 msgid "Copy and Close" msgstr "Kopiraj i zatvori" #: src/bz-flathub-page.blp:41 msgid "Apps Of The Week" msgstr "Aplikacije sedmice" #: src/bz-flathub-page.blp:85 msgid "Trending" msgstr "U trendu" #: src/bz-flathub-page.blp:117 msgid "Recently Updated" msgstr "Zadnje ažurirano" #: src/bz-flathub-page.blp:149 msgid "Recently Added" msgstr "Zadnje dodano" #: src/bz-flathub-page.blp:181 msgid "Popular" msgstr "Popularno" #: src/bz-full-view.blp:15 msgid "No Results" msgstr "Nema rezultata" #: src/bz-full-view.blp:16 msgid "Try a different search query" msgstr "Pokušajte s drugim upitom za pretragu" #: src/bz-full-view.blp:22 src/bz-window.blp:42 msgid "Content" msgstr "Sadržaj" #: src/bz-full-view.blp:180 msgid "Run this application" msgstr "Pokreni ovu aplikaciju" #: src/bz-full-view.blp:204 msgid "Download and install this application" msgstr "Preuzmite i instalirajte ovu aplikaciju" #: src/bz-full-view.blp:222 src/bz-window.c:987 msgid "Install" msgstr "Instaliraj" #: src/bz-full-view.blp:236 msgid "Uninstall this application" msgstr "Deinstalirajte ovu aplikaciju" #: src/bz-full-view.blp:262 msgid "Share this application" msgstr "Podijelite ovu aplikaciju" #: src/bz-full-view.blp:274 msgid "The number of downloads in the last 30 days. Click to view this application's download statistics." msgstr "Broj preuzimanja u posljednjih 30 dana. Kliknite za pregled statistike preuzimanja ove aplikacije." #: src/bz-full-view.blp:316 msgid "Support this developer" msgstr "Podržite ovog programera" #: src/bz-full-view.blp:329 msgid "Support" msgstr "Podrška" #: src/bz-full-view.blp:387 msgid "Remote repo name" msgstr "Naziv udaljenog repozitorija" #: src/bz-full-view.blp:400 msgid "Project URL" msgstr "URL projekta" #: src/bz-full-view.blp:412 msgid "Download size" msgstr "Veličina preuzimanja" #: src/bz-full-view.c:214 #, c-format msgid "Released %x" msgstr "Objavljeno %x" #: src/bz-full-view.c:225 msgid "No URL" msgstr "Nema URL-a" #: src/bz-full-view.c:233 msgid "This application has a FLOSS license, meaning the source code can be audited for safety." msgstr "Ova aplikacija ima FLOSS licencu, što znači da se izvorni kod može revidirati radi sigurnosti." #: src/bz-full-view.c:234 msgid "This application has a proprietary license, meaning the source code is developed privately and cannot be audited by an independent third party." msgstr "Ova aplikacija ima vlasničku licencu, što znači da je izvorni kod razvijen privatno i ne može ga revidirati nezavisna treća strana." #: src/bz-installed-page.blp:15 msgid "No Flatpaks Installed" msgstr "Nema instaliranih Flatpak uređaja" #: src/bz-installed-page.blp:21 src/bz-window.blp:201 src/bz-window.blp:336 msgid "Installed" msgstr "Instalirano" #: src/bz-installed-page.blp:143 msgid "More actions" msgstr "Više akcija" #: src/bz-installed-page.blp:187 src/bz-installed-page.blp:198 msgid "Edit Permissions" msgstr "Uredi dozvole" #: src/bz-preferences-dialog.blp:9 msgid "Preferences" msgstr "Postavke" #: src/bz-preferences-dialog.blp:13 msgid "How the application looks" msgstr "Kako izgleda aplikacija" #: src/bz-preferences-dialog.blp:14 msgid "Appearance" msgstr "Izgled" #: src/bz-preferences-dialog.blp:17 msgid "Show animated background" msgstr "Prikaži animiranu pozadinu" #: src/bz-search-widget.blp:69 msgid "Type to filter" msgstr "Upišite tekst za filtriranje" #: src/bz-search-widget.blp:98 src/bz-search-widget.blp:115 msgid "Search Options" msgstr "Opcije pretrage" #: src/bz-search-widget.blp:119 msgid "Exclude results with proprietary licenses" msgstr "Isključi rezultate s vlasničkim licencama" #: src/bz-search-widget.blp:124 msgid "Exclude results not originating from Flathub" msgstr "Isključi rezultate koji ne potiču sa Flathub-a" #: src/bz-search-widget.blp:139 msgid "Advanced" msgstr "Napredno" #: src/bz-search-widget.blp:143 msgid "Match using regular expressions" msgstr "Uparivanje pomoću običnih izraza" #: src/bz-search-widget.blp:148 msgid "Hide filtering and sorting behind a crossfade effect" msgstr "Sakrij filtriranje i sortiranje iza efekta prelaza" #: src/bz-search-widget.blp:153 msgid "Debounce input to prevent instant replies" msgstr "Otodskočite unos kako bi se spriječili brzi odgovori" #: src/bz-share-dialog.blp:13 msgid "Share" msgstr "Podijeli" #: src/bz-share-dialog.blp:64 msgid "Copy this link" msgstr "Kopiraj ovu vezu" #: src/bz-share-dialog.blp:71 msgid "Open this link externally" msgstr "Otvorite ovu vezu eksterno" #: src/bz-stats-dialog.blp:15 msgid "Downloads Over Time" msgstr "Preuzimanja tokom vremena" #: src/bz-stats-dialog.blp:31 msgid "Minimize Lower Bound" msgstr "Minimiziraj donju granicu" #: src/bz-stats-dialog.blp:36 msgid "Maximize Upper Bound" msgstr "Maksimiziraj gornju granicu" #: src/bz-transaction-manager.c:451 #, c-format msgid "Finished in %.02f seconds" msgstr "Završeno za %.02f sekundi" #: src/bz-transaction-view.blp:34 msgid "Installing" msgstr "Instaliranje" #: src/bz-transaction-view.blp:63 msgid "Updating" msgstr "Ažuriranje" #: src/bz-transaction-view.blp:92 msgid "Removing" msgstr "Uklanjanje" #: src/bz-transaction.c:268 msgid "Pending" msgstr "Na čekanju" #: src/bz-update-dialog.blp:6 msgid "Later" msgstr "Kasnije" #: src/bz-update-dialog.blp:7 msgid "Install Now" msgstr "Instaliraj odmah" #: src/bz-update-dialog.blp:10 msgid "Updates Are Available" msgstr "Dostupna su ažuriranja" #: src/bz-update-dialog.blp:11 msgid "The following applications are eligible for updates. Would you like to install them?" msgstr "Sljedeće aplikacije ispunjavaju uslove za ažuriranja. Želite li ih instalirati?" #: src/bz-update-dialog.c:135 #, c-format msgid "%d runtimes and/or addons are eligible for updates. Would you like to install them?" msgstr "%d okruženja za izvršavanje i/ili dodaci ispunjavaju uslove za ažuriranja. Želite li ih instalirati?" #: src/bz-update-dialog.c:143 #, c-format msgid "Additionally, %d runtimes and/or addons will be updated." msgstr "Pored toga, ažurirat će se i sljedeći broj runtime okruženja i/ili dodataka: %d." #: src/bz-window.blp:36 msgid "Transactions Will Appear Here" msgstr "Transakcije će se pojaviti ovdje" #: src/bz-window.blp:97 msgid "Halt the execution of transactions" msgstr "Zaustaviti izvršenje transakcija" #: src/bz-window.blp:105 msgid "Clear all finished transactions" msgstr "Obriši sve završene transakcije" #: src/bz-window.blp:136 src/bz-window.blp:140 msgid "Offline" msgstr "Bez mreže" #: src/bz-window.blp:146 msgid "Loading" msgstr "Učitavanje" #: src/bz-window.blp:170 msgid "Browse" msgstr "Pregledaj" #: src/bz-window.blp:180 msgid "App View" msgstr "Prikaz aplikacije" #: src/bz-window.blp:191 src/bz-window.blp:315 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:220 msgid "Go Back" msgstr "Idi nazad" #: src/bz-window.blp:228 msgid "Refresh" msgstr "Osvježi" #: src/bz-window.blp:237 msgid "Search" msgstr "Pretraži" #: src/bz-window.blp:249 msgid "Update" msgstr "Ažuriraj" #: src/bz-window.blp:263 msgid "Checking for updates" msgstr "Provjera ažuriranja" #: src/bz-window.blp:279 msgid "View curated applications" msgstr "Pogledajte izložene aplikacije" #: src/bz-window.blp:294 msgid "Curated" msgstr "Izloženo" #: src/bz-window.blp:300 msgid "View the latest on Flathub" msgstr "Pogledajte najnovije na Flathub-u" #: src/bz-window.blp:321 msgid "View installed applications" msgstr "Pogledajte instalirane aplikacije" #: src/bz-window.blp:350 msgid "Main Menu" msgstr "Glavni meni" #: src/bz-window.blp:361 msgid "Toggle transaction sidebar" msgstr "Uključi/isključi bočnu traku transakcija" #: src/bz-window.blp:400 msgid "Up to date!" msgstr "Ažurno!" #: src/bz-window.blp:425 msgid "_Keyboard Shortcuts" msgstr "_Prečice na tastaturi" #: src/bz-window.blp:430 msgid "_About Bazaar" msgstr "_O Bazaar-u" #: src/bz-window.blp:435 msgid "_Donate to Bazaar ❤️" msgstr "_Donirajte Bazaaru ❤️" #: src/bz-window.c:856 msgid "" "The ability to inspect and install local .flatpak bundle files is coming soon! In the meantime, try running\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "on the command line." msgstr "" "Mogućnost pregleda i instaliranja lokalnih .flatpak datoteka paketa uskoro stiže! U međuvremenu, pokušajte pokrenuti\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "u komandnom redu." #: src/bz-window.c:927 msgid "Can't do that right now!" msgstr "To se sada ne može uraditi!" #: src/bz-window.c:940 msgid "Confirm Action" msgstr "Potvrdi radnju" #: src/bz-window.c:958 #, c-format msgid "" "You are about to remove the following Flatpak:\n" "\n" "%s\n" "%s\n" "\n" "Are you sure?" msgstr "" "Namjeravate ukloniti sljedeći Flatpak:\n" "\n" "%s\n" "%s\n" "\n" "Jeste li sigurni?" #: src/bz-window.c:966 src/bz-window.c:986 msgid "Cancel" msgstr "Otkaži" #: src/bz-window.c:967 msgid "Remove" msgstr "Ukloni" #: src/bz-window.c:978 #, c-format msgid "" "You are about to install the following Flatpak:\n" "\n" "%s\n" "%s\n" "\n" "Are you sure?" msgstr "" "Instalirat ćete sljedeći Flatpak:\n" "\n" "%s\n" "%s\n" "\n" "Jeste li sigurni?" #: src/bz-window.c:1012 msgid "More details" msgstr "Više detalja" #: src/bz-window.c:1138 msgid "Resume the execution of transactions" msgstr "Nastavite izvršavanje transakcija" #: src/bz-window.c:1144 msgid "Pause the execution of transactions" msgstr "Pauzirajte izvršavanje transakcija" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "Općenito" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "Otvori dijalog za pretragu" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Refresh" msgstr "Osvježi" #: src/gtk/help-overlay.blp:24 msgctxt "shortcut window" msgid "Toggle Transaction Manager" msgstr "Uključi/isključi Upravitelja za transakcije" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Prikaži prečice" #: src/gtk/help-overlay.blp:34 msgctxt "shortcut window" msgid "Quit" msgstr "Odustani" bazaar-orig-v0.7.14/po/ar.po0000664000175000017500000030442015166123241014523 0ustar hasanhasan# Arabic translations for bazaar package. # Copyright (C) 2025 bazaar's COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Ahmed Najmawi , 2025. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-02-14 09:05+0300\n" "PO-Revision-Date: 2026-02-14 13:41+0300\n" "Last-Translator: Ahmed Najmawi \n" "Language-Team: Arabic\n" "Language: ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " "&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5);\n" "X-Generator: Poedit 3.8\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:6 #: src/bz-window.blp:111 msgid "Bazaar" msgstr "بازار" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "أضِف، أو أزل، أو حدث برمجيات فلاتباك على هذا الحاسوب" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK؛ النظام؛ مدير الحزم؛ اكتشاف؛ فلات باك؛ البرامج؛ المتجر؛" #: data/io.github.kolunmi.Bazaar.desktop.in:15 msgid "New Window" msgstr "نافذة جديدة" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and install applications" msgstr "استكشف ونصِّب التطبيقات" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A new app store for Linux with a focus on discovering and installing " "applications and addons from Flatpak remotes, particularly Flathub." msgstr "" "متجر تطبيقات جديد للينوكس يركز على استكشاف وتنصيب التطبيقات والإضافات من " "فلاتباك، وبالأخص مستودع فلاتهَب." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:14 msgid "" "It emphasizes supporting the developers who make the Linux desktop possible. " "Bazaar features a \"curated\" tab that can be configured by distributors to " "allow for a more localized experience." msgstr "" "يُشدِّد «بازار» على دعم المطورين الواقفين وراء إتاحة سطح مكتب لينكس، ويضم لسانًا " "للمحتوى المنتقى يمكن للموزِّعين إعداده لتوفير تجربة استخدام أكثر مواءمة." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:29 src/bz-application.c:703 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:54 msgid "The home page displaying Flathub apps" msgstr "الصفحة الرئيسية وهي تعرض تطبيقات فلاتهَب" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:58 msgid "Exhibit app page" msgstr "صفحة معرض التطبيق" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:62 msgid "Library page" msgstr "صفحة المكتبة" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:66 msgid "Search page" msgstr "صفحة البحث" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:70 msgid "Category page" msgstr "صفحة التصنيفات" #: src/bz-addons-dialog.blp:16 src/bz-full-view.blp:708 #: src/bz-installed-tile.blp:101 msgid "Manage Add-ons" msgstr "أدِر الإضافات" #: src/bz-addons-dialog.c:94 src/bz-full-view.blp:495 #: src/bz-installed-tile.blp:119 src/bz-transaction-dialog.c:231 msgid "Remove" msgstr "أزِل" #: src/bz-addons-dialog.c:99 src/bz-favorites-tile.c:174 #: src/bz-full-view.blp:262 src/bz-full-view.blp:482 #: src/bz-transaction-dialog.c:202 msgid "Install" msgstr "نصِّب" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 #: src/bz-age-rating-dialog.c:726 src/bz-full-view.c:338 src/bz-full-view.c:345 msgid "Age Rating" msgstr "التصنيف العمري" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "عنف الرسوم المتحركة" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "لا توجد معلومات بخصوص العنف في الرسوم المتحركة" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "عنف خيالي" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "لا توجد معلومات بخصوص العنف الخيالي" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "عنف واقعي" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "لا توجد معلومات بخصوص العنف الواقعي" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "العنف الذي يصور إراقة الدماء" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "لا توجد معلومات بخصوص العنف الذي يصور إراقة الدماء" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "عنف الجنسي" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "لا توجد معلومات بخصوص العنف الجنسي" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "كحول" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "لا توجد معلومات بخصوص الكحول" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "المخدرات" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "لا توجد معلومات بخصوص الإشارات إلى المخدرات غير المشروعة" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "تبغ" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "لا توجد معلومات بخصوص استخدام التبغ" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "تعري" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "لا توجد معلومات بخصوص التعري بأي شكل" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "المواضيع الجنسية" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "لا توجد معلومات بخصوص المواضيع الجنسية" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "ألفاظ بذيئة" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "لا توجد معلومات بخصوص الألفاظ البذيئة بأي شكل من الأشكال" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "فكاهة غير لائقة" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "لا توجد معلومات بخصوص الفكاهة الغير لائقة" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "تمييز" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "لا توجد معلومات بخصوص استخدام لغة التمييز بأي شكل" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "إعلانات" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "لا توجد معلومات بخصوص الإعلانات بأي شكل" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "مقامرة" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "لا توجد معلومات بخصوص المقامرة بأي شكل" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "شراء" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "لا توجد معلومات بخصوص القدرة على دفع الأمواب" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "الدردشة بين المستخدمين" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "لا توجد معلومات بخصوص الدردشة بين المستخدمين" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "المحادثة الصوتية بين المستخدمين" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "لا توجد معلومات بخصوص المحادثة الصوتية بين المستخدمين" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 msgid "Contact Details" msgstr "معلومات التواصل" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "لا توجد معلومات بخصوص مشاركة معلومات اسم المستخدم أو البريد الإلكتروني" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "معلومات التعريف" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "لا توجد معلومات بخصوص مشاركة معلومات المستخدم مع طرف ثالث" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "مشاركة الموقع" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "لا توجد معلومات بخصوص مشاركة الموقع مع مستخدمين آخرين" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "دعارة" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "لا توجد معلومات بخصوص الدعارة" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "الزنا" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "لا توجد معلومات بخصوص الزنا" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "شخصيات ذات طابع جنسي" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "لا توجد معلومات بخصوص شخصيات ذات طابع جنسي" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 msgid "Desecration" msgstr "تدنيس" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "لا توجد معلومات بخصوص التدنيس" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "بقايا بشرية" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "لا توجد معلومات بخصوص البقايا البشرية" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "عبودية" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "لا توجد معلومات بخصوص العبودية" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "لا يتضمن إشارات إلى المخدرات" #: src/bz-age-rating-dialog.c:426 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "لا يتضمن قذف, شتم, وأي شكل من أشكال التعدي اللفظي" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "لا يتضمن إعلانات أو المعاملات المالية" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "لا يتضمن جنس أو تعري" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "لا يتضمن دردشة غير قابلة للتحكم" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "لا يتضمن عنف" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "مخدرات" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "تعدي لفظي" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "مال" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "إجتماعي" #: src/bz-age-rating-dialog.c:479 msgid "Violence" msgstr "عنف" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:676 src/bz-full-view.c:328 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:701 msgctxt "Age rating" msgid "All" msgstr "جميع الأعمار" #: src/bz-age-rating-dialog.c:737 #, c-format msgid "%s has an unknown age rating" msgstr "%s التصنيف العمري غير محدد" #: src/bz-age-rating-dialog.c:743 #, c-format msgid "%s is suitable for everyone" msgstr "%s مناسب للجميع" #: src/bz-age-rating-dialog.c:746 #, c-format msgid "%s is suitable for young children" msgstr "%s مناسب للأطفال الصغار" #: src/bz-age-rating-dialog.c:749 #, c-format msgid "%s is suitable for children" msgstr "%s مناسب للأطفال" #: src/bz-age-rating-dialog.c:752 #, c-format msgid "%s is suitable for teenagers" msgstr "%s مناسب للمراهقين" #: src/bz-age-rating-dialog.c:755 #, c-format msgid "%s is suitable for adults" msgstr "%s مناسب للبالغين" #: src/bz-age-rating-dialog.c:758 #, c-format msgid "%s is suitable for %s" msgstr "%s مناسب للـ %s" #: src/bz-age-rating-dialog.c:852 #, c-format msgid "%s • %s" msgstr "%s • %s" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:29 #: src/bz-user-data-page.blp:15 src/bz-window.blp:292 msgid "Main Menu" msgstr "القائمة الرئيسة" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 #: src/bz-user-data-page.blp:19 src/bz-window.blp:384 msgid "_Donate to Bazaar ❤️" msgstr "ت_برَّع إلى بازار ❤️" #: src/bz-all-apps-page.blp:25 src/bz-apps-page.blp:25 #: src/bz-user-data-page.blp:26 src/bz-window.blp:391 msgid "_Preferences" msgstr "ال_تفضيلات" #: src/bz-all-apps-page.blp:30 src/bz-apps-page.blp:30 #: src/bz-user-data-page.blp:31 src/bz-window.blp:396 msgid "_Login with Flathub" msgstr "_تسجيل الدخول بفلاتهب" #: src/bz-all-apps-page.blp:36 src/bz-apps-page.blp:36 #: src/bz-user-data-page.blp:37 src/bz-window.blp:402 msgid "_Manage Leftover User Data" msgstr "_أدر معلوماتك" #: src/bz-all-apps-page.blp:41 src/bz-apps-page.blp:41 #: src/bz-user-data-page.blp:42 src/bz-window.blp:407 msgid "_Synchronize Remotes" msgstr "مزامنة" #: src/bz-all-apps-page.blp:46 src/bz-apps-page.blp:46 #: src/bz-user-data-page.blp:47 src/bz-window.blp:412 msgid "_Keyboard Shortcuts" msgstr "ا_ختصارات لوحة المفاتيح" #: src/bz-all-apps-page.blp:51 src/bz-apps-page.blp:51 #: src/bz-user-data-page.blp:52 src/bz-window.blp:417 msgid "_About Bazaar" msgstr "_عَنْ بازار" #: src/bz-all-apps-page.blp:58 src/bz-apps-page.blp:58 #: src/bz-user-data-page.blp:59 src/bz-window.blp:424 msgid "_Quit Bazaar" msgstr "_أخرج من بازار" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "مجلد النظام %s" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "المجلد ضمن الرئيسي %s" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "مجلدات نظام المستضيف" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "تكوين نظام المضيف من /etc" #: src/bz-app-permissions.c:169 #, c-format msgid "Desktop subfolder %s" msgstr "المجلد ضمن سطح المكتب %s" #: src/bz-app-permissions.c:170 msgid "Desktop folder" msgstr "مجلد سطح المكتب" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "المجلد ضمن المستندات %s" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "مجلد المستندات" #: src/bz-app-permissions.c:177 #, c-format msgid "Music subfolder %s" msgstr "المجلد ضمن الموسيقا %s" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "مجلد الموسيقا" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "المجلد ضمن الصور %s" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "مجلد الصور" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "المجلد ضمن المشاركة العامة %s" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "مجلد المشاركة العامة" #: src/bz-app-permissions.c:189 #, c-format msgid "Videos subfolder %s" msgstr "المجلد ضمن الفيديو %s" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "مجلد الفيديو" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "المجلد ضمن القوالب %s" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "مجلد القوالب" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "المجلد ضمن ذاكرة التخزين المؤقت %s" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "مجلد الذاكرة المؤقتة للمستخدم" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "المجلد ضمن لإعدادات المستخدم %s" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "مجلد إعدادات المستخدم" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "المجلد ضمن بيانات المستخدم %s" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "مجلد بيانات المستخدم" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "المجلد ضمن وقت تشغيل المستخدم %s" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "مجلد وقت تشغيل المستخدم" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "صلاحيات ملفات النظام لـ %s" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "مسار ملف النظام غير معروف" #: src/bz-app-size-dialog.blp:29 src/bz-app-size-dialog.blp:55 msgid "Download Size" msgstr "حجم التنزيل" #: src/bz-app-size-dialog.blp:56 msgid "Amount to download from the internet" msgstr "الكمية المطلوب تنزيلها من الإنترنت" #: src/bz-app-size-dialog.blp:76 msgid "Installed Size" msgstr "حجم التنصيب" #: src/bz-app-size-dialog.blp:77 msgid "Size on Disk" msgstr "الحجم على القرص" #: src/bz-app-size-dialog.blp:99 msgid "User Data Size" msgstr "حجم بيانات المستخدم" #: src/bz-app-size-dialog.blp:100 msgid "Caches, settings, and other app data" msgstr "الذاكرة المؤقتة, الإعدادات, ومعلومات التطبيق الأخرى" #. Translators: As in 'The app is installed'. #: src/bz-app-tile.blp:86 src/bz-full-view.c:287 src/bz-releases-list.c:178 msgid "Installed" msgstr "المنصَّبة" #: src/bz-apps-page.blp:142 msgid "Show All" msgstr "عرض الكل" #: src/bz-apps-page.c:243 #, c-format msgid "All \"%s\"" msgstr "كل \"%s\"" #: src/bz-apps-page.c:530 src/bz-tag-list.c:109 #, c-format msgid "%d Applications" msgstr "%d تطبيقات" #: src/bz-application.c:674 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:675 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:706 msgid "translator-credits" msgstr "" "أحمد النجماوي \n" "أنس داوود آغا " #: src/bz-application.c:717 msgid "Special Thanks" msgstr "شكر خاص" #: src/bz-application.c:775 msgid "Logged Out Successfully!" msgstr "نجح تسجيل الخروج!" #: src/bz-application.c:898 msgid "Performing setup..." msgstr "يتم التنصيب..." #: src/bz-application.c:981 src/bz-application.c:990 msgid "Set Up Flathub" msgstr "نصِّب فلاتهب" #: src/bz-application.c:984 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "فلاتهب لم يتم تنصيبه على النظام. لن تستطيع تصفح و تنصيب تطبيقات بازار اذا لم " "توجد.\n" "\n" "يمكنك استخدام بازار لتصفح وحذف التطبيقات المحملة." #: src/bz-application.c:989 msgid "Later" msgstr "لاحقًا" #: src/bz-application.c:1399 src/bz-application.c:3116 msgid "Synchronizing..." msgstr "يُزامن..." #: src/bz-application.c:1546 src/bz-application.c:3112 #, c-format msgid "Receiving %d entries..." msgstr "استلام %d المدخلات..." #: src/bz-application.c:1551 msgid "Checking for updates" msgstr "التحقق من التحديثات" #: src/bz-application.c:3118 msgid "Indexing Data..." msgstr "فهرسة البيانات..." #: src/bz-appstream-parser.c:265 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "صفحة فلاتهَب" #: src/bz-appstream-parser.c:286 msgctxt "Project URL Type" msgid "Project Website" msgstr "موقع المشروع" #: src/bz-appstream-parser.c:290 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "متعقب العلل" #: src/bz-appstream-parser.c:294 msgctxt "Project URL Type" msgid "FAQ" msgstr "الأسئلة الشائعة" #: src/bz-appstream-parser.c:298 msgctxt "Project URL Type" msgid "Help" msgstr "المساعدة" #: src/bz-appstream-parser.c:302 msgctxt "Project URL Type" msgid "Donate" msgstr "التبرع" #: src/bz-appstream-parser.c:308 msgctxt "Project URL Type" msgid "Translate" msgstr "الترجمة" #: src/bz-appstream-parser.c:312 msgctxt "Project URL Type" msgid "Contact" msgstr "التواصل" #: src/bz-appstream-parser.c:316 msgctxt "Project URL Type" msgid "Source Code" msgstr "المصدر البرمجي" #: src/bz-appstream-parser.c:322 msgctxt "Project URL Type" msgid "Contribute" msgstr "المساهمة" #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:68 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:61 #: src/bz-library-page.blp:59 src/bz-user-data-page.blp:86 msgid "Empty" msgstr "فارغ" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "لا يوجد تنسيق" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "لا تتوفر معلومات عن التنسيق في هذا النظام. لا يزال بإمكانك تصفح التطبيقات " "على فلاتهب" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "تصفح فلاتهَب" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "غير متصل" #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 msgid "Browser" msgstr "المتصفح" #: src/bz-developer-badge.c:131 msgid "Developer information not available." msgstr "معلومات المطور غير متاحة." #: src/bz-developer-badge.c:137 src/bz-developer-badge.c:151 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "لم يتم التحقق من ملكية معرف التطبيق %s وقد يكون حزمة مجتمعية." #: src/bz-developer-badge.c:155 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "تم التحقق يدويًا من ملكية معرف التطبيق %s بواسطة فريق فلاتهب." #: src/bz-developer-badge.c:161 #, c-format msgid "" "The ownership of the %1$s app ID has been verified by %2$s on " "%3$s." msgstr "" "تم التحقق من ملكية معرف التطبيق %1$s بواسطة %2$s في %3$s." #: src/bz-developer-badge.c:168 #, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "تم التحقق من ملكية معرف التطبيق %1$s باستخدام %2$s." #: src/bz-developer-badge.c:172 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "تم التحقق من ملكية معرف التطبيق %s." #: src/bz-donations-dialog.blp:47 msgid "View the Release Page" msgstr "أظهِر صفحة الاطلاق" #: src/bz-donations-dialog.blp:69 msgid "This Bazaar Release Was Made Possible By Users Like You!" msgstr "تم إطلاق هذا الإصدار من بازار بفضل مستخدمين مثلك!" #: src/bz-donations-dialog.blp:77 msgid "" "I love making Bazaar, but I cannot do it alone. If you would like to help " "support further development, please consider donating to the project at my " "ko-fi:" msgstr "" "أحبّ تصميم بازار، لكنني لا أستطيع القيام بذلك بمفردي. إذا كنتم ترغبون في دعم " "تطويره، يُرجى التبرع للمشروع عبر حسابي على Ko-fi:" #: src/bz-donations-dialog.blp:87 msgid "Donate to Bazaar" msgstr "تبرَّع إلى بازار" #. Translators: the %s format specifier will be something along the lines of "0.7.6" etc #: src/bz-donations-dialog.c:156 #, c-format msgid "What's New in Version %s?" msgstr "ما الجديد في هذا الإصدار %s؟" #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "اختر تنصيبًا" #: src/bz-entry-group-util.c:76 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "لديك عدة إصدارات منصَّبة من هذا التطبيق. أي واحد ستشرع به؟" #: src/bz-entry-group-util.c:80 src/bz-transaction-dialog.c:201 #: src/bz-transaction-dialog.c:230 src/bz-transaction-dialog.c:275 #: src/bz-transaction-dialog.c:578 msgid "Cancel" msgstr "إلغاء" #: src/bz-entry-selection-row.blp:17 msgid "For this user only" msgstr "لهذا المستخدم فقط" #: src/bz-entry-selection-row.c:112 msgid "this user" msgstr "هذا المستخدم" #: src/bz-entry-selection-row.c:112 msgid "all users" msgstr "جميع المستخدمين" #: src/bz-error.c:68 msgid "An Error Occurred" msgstr "حدث خطأ" #: src/bz-error.c:89 msgid "Close" msgstr "أغلِق" #: src/bz-error.c:90 msgid "Copy and Close" msgstr "انسخ وأغلِق" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "سجّل الدخول باستخدام فلاتهب لإدارة المفضلة" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "تسجيل الدخول" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "عدد المفضلة" #: src/bz-favorites-tile.c:172 msgid "Uninstall" msgstr "إزالة" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:77 msgid "Support this application" msgstr "ادعم هذا التطبيق" #: src/bz-favorites-tile.blp:119 msgid "Remove from Favorites" msgstr "حذف من المفضلة" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:78 #: src/bz-window.blp:442 msgid "Favorites" msgstr "المفضلة" #: src/bz-favorites-page.blp:22 src/bz-full-view.blp:44 src/bz-window.blp:307 msgid "Open App Library" msgstr "افتح مكتبة التطبيقات" #: src/bz-favorites-page.blp:39 src/bz-section-view.blp:144 #: src/bz-transaction-dialog.c:579 msgid "Install All" msgstr "نصِّب الكل" #: src/bz-favorites-page.blp:56 src/bz-user-data-page.blp:75 msgid "Loading" msgstr "يحمِّل" #: src/bz-favorites-page.blp:71 msgid "No Favorites" msgstr "لا يوجد تفضلات" #: src/bz-favorites-page.blp:72 msgid "Applications you mark as favorite will appear here" msgstr "ستظهر التطبيقات التي تضع عليها علامة \"مفضلة\" هنا" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "السابق" #: src/bz-featured-carousel.blp:53 msgid "Next" msgstr "التالي" #: src/bz-featured-tile.blp:88 msgid "App of the Day" msgstr "تطبيق اليوم" #: src/bz-flathub-category.c:89 msgid "Editing" msgstr "يعدل" #: src/bz-flathub-category.c:90 msgid "Midi" msgstr "Midi" #: src/bz-flathub-category.c:91 msgid "Mixer" msgstr "خلاط" #: src/bz-flathub-category.c:92 msgid "Music" msgstr "موسيقا" #: src/bz-flathub-category.c:93 msgid "Player" msgstr "مشغل" #: src/bz-flathub-category.c:94 msgid "Recorder" msgstr "مسجل" #: src/bz-flathub-category.c:95 msgid "Sequencer" msgstr "جهاز التسلسل" #: src/bz-flathub-category.c:96 msgid "Tuner" msgstr "موالف" #: src/bz-flathub-category.c:97 msgid "TV" msgstr "تلفاز" #: src/bz-flathub-category.c:102 msgid "Emulation" msgstr "محاكاة" #: src/bz-flathub-category.c:103 msgid "Action" msgstr "حماسي" #: src/bz-flathub-category.c:104 msgid "Adventure" msgstr "مغامرة" #: src/bz-flathub-category.c:105 msgid "Arcade" msgstr "آركيد" #: src/bz-flathub-category.c:106 msgid "Blocks" msgstr "مكعبات" #: src/bz-flathub-category.c:107 msgid "Board" msgstr "طاولة" #: src/bz-flathub-category.c:108 msgid "Card" msgstr "ورق" #: src/bz-flathub-category.c:109 msgid "Kids" msgstr "أطفال" #: src/bz-flathub-category.c:110 msgid "Logic" msgstr "منطق" #: src/bz-flathub-category.c:111 msgid "Role Playing" msgstr "لعب الأدوار" #: src/bz-flathub-category.c:112 msgid "Shooter" msgstr "رماية" #: src/bz-flathub-category.c:113 msgid "Simulation" msgstr "محاكاة" #: src/bz-flathub-category.c:114 msgid "Sports" msgstr "رياضة" #: src/bz-flathub-category.c:115 msgid "Strategy" msgstr "استراتيجية" #: src/bz-flathub-category.c:120 msgid "Audio & Video" msgstr "صوت وفيديو" #: src/bz-flathub-category.c:120 msgid "Media" msgstr "وسائط متعددة" #: src/bz-flathub-category.c:120 msgid "More Audio & Video" msgstr "المزيد من الصوت وفيديو" #: src/bz-flathub-category.c:121 msgid "Developer Tools" msgstr "أدوات المطوريين" #: src/bz-flathub-category.c:121 msgid "Develop" msgstr "تطوير" #: src/bz-flathub-category.c:121 msgid "More Developer Tools" msgstr "المزيد من أدوات المطوريين" #: src/bz-flathub-category.c:122 msgid "Education" msgstr "تعليمية" #: src/bz-flathub-category.c:122 msgid "Learn" msgstr "تعلَّم" #: src/bz-flathub-category.c:122 msgid "More Education" msgstr "المزيد من التطبيقات التعليمية" #: src/bz-flathub-category.c:123 msgid "Gaming" msgstr "ألعاب" #: src/bz-flathub-category.c:123 msgid "Play" msgstr "لعب" #: src/bz-flathub-category.c:123 msgid "More Gaming" msgstr "المزيد من الألعاب" #: src/bz-flathub-category.c:124 msgid "Graphics & Photography" msgstr "الرسومات والصور" #: src/bz-flathub-category.c:124 msgid "Create" msgstr "صمِّم" #: src/bz-flathub-category.c:124 msgid "More Graphics & Photography" msgstr "المزيد من الرسومات والصور" #: src/bz-flathub-category.c:125 msgid "Networking" msgstr "شبكي" #: src/bz-flathub-category.c:125 msgid "Internet" msgstr "شبكي" #: src/bz-flathub-category.c:125 msgid "More Networking" msgstr "المزيد من التطبيقات الشبكية" #: src/bz-flathub-category.c:126 msgid "Productivity" msgstr "إنتاجية" #: src/bz-flathub-category.c:126 msgid "Work" msgstr "عمل" #: src/bz-flathub-category.c:126 msgid "More Productivity" msgstr "المزيد من تطبيقات الإنتاجية" #: src/bz-flathub-category.c:127 msgid "Science" msgstr "علمي" #: src/bz-flathub-category.c:127 msgid "More Science" msgstr "المزيد من التطبيقات العلمية" #: src/bz-flathub-category.c:128 msgid "System" msgstr "نظام" #: src/bz-flathub-category.c:128 msgid "More System" msgstr "المزيد من تطبيقات النظام" #: src/bz-flathub-category.c:129 msgid "Utilities" msgstr "أدوات" #: src/bz-flathub-category.c:129 msgid "Tools" msgstr "أدوات" #: src/bz-flathub-category.c:129 msgid "More Utilities" msgstr "المزيد من الأدوات" #: src/bz-flathub-category.c:130 src/bz-flathub-page.blp:119 #: src/bz-flathub-page.blp:152 msgid "Trending" msgstr "الرائجة" #: src/bz-flathub-category.c:130 msgid "More Trending" msgstr "المزيد من التطبيقات الرائجة" #: src/bz-flathub-category.c:131 src/bz-flathub-page.blp:125 #: src/bz-flathub-page.blp:185 msgid "Popular" msgstr "الشائعة" #: src/bz-flathub-category.c:131 msgid "More Popular" msgstr "المزيد من التطبيقات الشائعة" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:174 msgid "Recently Added" msgstr "أُضيفت مؤخرًا" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:131 msgid "New" msgstr "جديد" #: src/bz-flathub-category.c:132 msgid "More New" msgstr "المزيد من الجديد" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:163 msgid "Recently Updated" msgstr "حُدِّثت مؤخرًا" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:137 msgid "Updated" msgstr "حدثَّ مؤخرا" #: src/bz-flathub-category.c:133 msgid "More Updated" msgstr "المزيد من التطبيقات المُحدَّثة مؤخرا" #: src/bz-flathub-category.c:134 msgid "Mobile" msgstr "جهاز الهاتف" #: src/bz-flathub-category.c:134 msgid "More Mobile" msgstr "المزيد من التطبيقات أجهزة الهاتف" #: src/bz-flathub-category.c:135 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:135 msgid "More Adwaita" msgstr "المزيد من Adwaita" #: src/bz-flathub-category.c:136 msgid "KDE Apps" msgstr "تطبيقات بيئة سطح مكتب KDE" #: src/bz-flathub-category.c:136 msgid "More KDE Apps" msgstr "المزيد من تطبيقات بيئة سطح مكتب KDE" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "لم يُضف فلاتهَب" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "" "لم يتم العثور على جهاز التحكم عن بعد فلاتهب في أي من عمليات تثبيت فلاتباك " "الخاصة بك" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "حصل خطأ في فلاتهب" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "أعد محاولة الاتصال بفلاتهب" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "فلاتهب غير متوفر" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" "لم نتمكن من الاتصال بـفلاتهب. لا يزال بإمكانك إدارة التطبيقات والبحث عنها." #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "ابحث التطبيقات" #: src/bz-flathub-page.blp:270 msgid "On the Go" msgstr "أثناء التنقل" #: src/bz-flathub-page.blp:282 msgid "Apps for your Linux phones and tablets" msgstr "تطبيقات لأجل هواتف لينكس وأجهزتها اللوحية" #: src/bz-flathub-page.blp:293 src/bz-flathub-page.blp:328 msgid "More Mobile Apps" msgstr "المزيد من تطبيقات هواتف لينكس" #: src/bz-flathub-page.blp:388 msgid "We​ ♥​ Games" msgstr "نحن ♥ الألعاب" #: src/bz-flathub-page.blp:401 msgid "Games and apps to run your favorite titles" msgstr "ألعاب وتطبيقات لتشغل عناوينك المفضلة" #: src/bz-flathub-page.blp:435 msgid "More Games" msgstr "المزيد من الألعاب" #: src/bz-full-view.blp:65 src/bz-library-page.blp:70 #: src/bz-library-page.blp:74 msgid "No Results" msgstr "لا توجد نتائج" #: src/bz-full-view.blp:66 msgid "Try a different search query" msgstr "جرِّب عبارة بحث مختلفة" #: src/bz-full-view.blp:72 msgid "Content" msgstr "المحتوى" #: src/bz-full-view.blp:130 msgid "Installing .flatpak bundles is not yet supported" msgstr "تثبيت حزم فلاتباك غير مدعوم حاليًا" #: src/bz-full-view.blp:223 msgid "Support" msgstr "ادعَم" #: src/bz-full-view.blp:246 src/bz-full-view.blp:506 msgid "Open" msgstr "افتح" #: src/bz-full-view.blp:259 src/bz-full-view.blp:479 msgid "Download & Install Application" msgstr "نزِّل التطبيق ونصِّبه" #: src/bz-full-view.blp:274 msgid "Uninstall Application" msgstr "أزِل التطبيق" #: src/bz-full-view.blp:289 src/bz-full-view.blp:521 msgid "Install Other Version" msgstr "نصِّب إصدارًا آخر" #: src/bz-full-view.blp:443 msgid "Downloads/Month" msgstr "تنزيلات\\شهر" #: src/bz-full-view.blp:540 msgid "Stopped Receiving Core Updates" msgstr "توقف عن تلقي التحديثات الأساسية" #: src/bz-full-view.blp:554 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "يستخدم هذا التطبيق بيئة تشغيل لم تعد تتلقى تحديثات أو إصلاحات أمنية. قد يصبح " "استخدامه غير آمن." #: src/bz-full-view.blp:643 msgid "Trash Data" msgstr "بيانات المهملات" #: src/bz-full-view.blp:784 msgid "Tags:" msgstr "الوسوم:" #: src/bz-full-view.c:227 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:234 #, c-format msgid "%.*fM" msgstr "%.*fM" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:241 #, c-format msgid "%.*fK" msgstr "%.*fK" #: src/bz-full-view.c:251 #, c-format msgid "%d downloads in the last 30 days" msgstr "عدد التنزيلات %d في آخر 30 يومًا" #: src/bz-full-view.c:263 src/bz-full-view.c:597 src/bz-full-view.c:614 msgid "N/A" msgstr "غير متوفر" #. Translators: . #: src/bz-full-view.c:287 msgid "Download" msgstr "تحميل" #: src/bz-full-view.c:307 msgid "Size information unavailable" msgstr "معلومات المقاس غير متوفرة" #: src/bz-full-view.c:310 #, c-format msgid "Download size of %s" msgstr "حجم التنزيل %s" #: src/bz-full-view.c:343 msgid "All Ages" msgstr "جميع الأعمار" #: src/bz-full-view.c:355 msgid "Age rating information unavailable" msgstr "لا توجد معلومات للتصنيف العمري" #: src/bz-full-view.c:360 msgid "Suitable for all ages" msgstr "مناسب لجميع الأعمار" #: src/bz-full-view.c:362 #, c-format msgid "Suitable for ages %d and up" msgstr "مناسب للأعمار من %d سنوات فما فوق" #: src/bz-full-view.c:395 src/bz-full-view.c:400 src/bz-full-view.c:428 #: src/bz-full-view.c:439 msgid "Unknown" msgstr "مجهول" #: src/bz-full-view.c:405 #, c-format msgid "Free software licensed under %s" msgstr "برامج مجانية مرخصة بموجب %s" #: src/bz-full-view.c:410 msgid "Free software" msgstr "برمجية مجانية" #: src/bz-full-view.c:413 msgid "Proprietary Software" msgstr "برمجية محتكرة" #: src/bz-full-view.c:416 #, c-format msgid "Special License: %s" msgstr "رخصة خاصة: %s" #: src/bz-full-view.c:433 msgid "Free" msgstr "مجاني" #: src/bz-full-view.c:436 src/bz-license-dialog.c:132 msgid "Proprietary" msgstr "محتكرة" #: src/bz-full-view.c:441 src/bz-license-dialog.c:134 msgid "Special License" msgstr "ترخيص خاص" #: src/bz-full-view.c:461 msgid "Adaptive" msgstr "متكيف" #: src/bz-full-view.c:461 msgid "Desktop Only" msgstr "سطح المكتب فقط" #: src/bz-full-view.c:467 msgid "Works on desktop, tablets, and phones" msgstr "يعمل على أجهزة الكمبيوتر المكتبية والأجهزة اللوحية والهواتف" #: src/bz-full-view.c:468 msgid "May not work on mobile devices" msgstr "قد لا يعمل على أجهزة الهاتف" #: src/bz-full-view.c:479 msgid "No URL" msgstr "لا رابط" #: src/bz-full-view.c:497 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "هذا التطبيق مرخص تحت رخصة حرَّة، مما يعني أنه يمكن فحص المصدر البرمجي أمنيًا." #: src/bz-full-view.c:498 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "هذا التطبيق مرخص تحت رخصة احتكارية، مما يعني أنه يطوَّر بشكل خاص ولا يمكن " "الوصول للمصدر البرمجي أو فحصه أمنيًا بواسطة طرف ثالث." #: src/bz-full-view.c:505 msgid "More Apps" msgstr "المزيد من التطبيقات" #: src/bz-full-view.c:506 #, c-format msgid "More Apps by %s" msgstr "المزيد من تطبيقات %s" #: src/bz-full-view.c:513 msgid "Other Apps by this Developer" msgstr "تطبيقات أخرى من هذا المطور" #: src/bz-full-view.c:515 src/bz-full-view.c:715 #, c-format msgid "Other Apps by %s" msgstr "تطبيقات أخرى من %s" #: src/bz-full-view.c:524 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "لم يتم تثبيت %s، ولكن لا يزال يحتوي على %s من البيانات." #: src/bz-full-view.c:604 src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "آمن" #: src/bz-full-view.c:606 src/bz-full-view.c:608 msgid "Low Risk" msgstr "خطورة متدنية" #: src/bz-full-view.c:610 msgid "Medium Risk" msgstr "خطورة متوسطة" #: src/bz-full-view.c:612 msgid "High Risk" msgstr "خطورة عالية" #: src/bz-full-view.c:717 msgid "Other Apps" msgstr "تطبيقات أخرى" #: src/bz-full-view.c:719 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d تطبيق" msgstr[1] "%d تطبيق" msgstr[2] "%d تطبيقات" msgstr[3] "%d تطبيقات" msgstr[4] "%d تطبيقات" msgstr[5] "%d تطبيقات" #: src/bz-full-view.c:1058 msgid "Show Less" msgstr "عرض أقل" #: src/bz-full-view.c:1058 msgid "Show More" msgstr "عرض المزيد" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 msgid "Hardware Support" msgstr "دعم الأجهزة" #: src/bz-hardware-support-dialog.c:62 msgid "Keyboard support" msgstr "دعم لوحة المفاتيح" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "يتطلب استخدام لوحة مفاتيح" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "يفضل استخدام لوحة مفاتيح" #: src/bz-hardware-support-dialog.c:66 msgid "Supports keyboards" msgstr "يدعم استخدام لوحة المفاتيح" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "لا توجد معلومات دعم لوحة المفاتيح" #: src/bz-hardware-support-dialog.c:69 msgid "Mouse support" msgstr "دعم الفأرة" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "يتطلب استخدام الفأرة أو أجهزة تأشير" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "يفضَّل استخدام الفأرة أو أجهزة تأشير" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "يدعم الفأرة أو أجهزة التأشير" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "لا توجد معلومات دعم الفأرة أو أجهزة التأشير" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "دعم شاشة اللمس" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "يتطلب استخدام شاشة اللمس" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "يُفضَّل استخدام شاشة اللمس" #: src/bz-hardware-support-dialog.c:80 msgid "Supports touchscreens" msgstr "يدعم شاشة اللمس" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "لا توجد معلومات دعم شاشة اللمس" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "دعم أجهزة الهاتف" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "يعمل على أجهزة الهاتف" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "قد لا يعمل على أجهزة الهاتف" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "دعم أجهزة سطح المكتب" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "يعمل على الشاشة كبيرة الحجم" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "يعمل %s بشكل أفضل على أجهزة محددة" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "يعمل %s على معظم الأجهزة" #: src/bz-installed-tile.blp:63 src/bz-rich-app-tile.blp:136 msgid "Stopped Receiving Updates" msgstr "توقف عن استقبال التحديثات" #: src/bz-library-page.blp:29 msgid "Search installed apps" msgstr "ابحث في التطبيقات المنصبة" #: src/bz-library-page.blp:63 msgid "No Apps Found" msgstr "لا توجد تطبيقات" #. Translators: . #: src/bz-library-page.blp:82 src/bz-window.blp:179 msgid "Library" msgstr "المكتبة" #: src/bz-library-page.blp:110 msgid "Pending Updates" msgstr "التحديثات المنتظرة" #: src/bz-library-page.blp:137 msgid "Downloads" msgstr "التنزيلات" #: src/bz-library-page.blp:180 msgid "Recently Uninstalled" msgstr "حذفت مؤخرًا" #: src/bz-library-page.blp:231 msgid "Clear Finished Tasks" msgstr "امحُ كل العمليات المنتهية" #: src/bz-library-page.blp:242 msgid "Installed Apps" msgstr "التطبيقات المنصَّبة" #: src/bz-library-page.c:153 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "لا يوجد نتائج للبحث عن \"%s\" في التطبيقات المنصبة" #: src/bz-library-page.c:166 src/bz-updates-card.c:257 #, c-format msgid "%u Available Update" msgid_plural "%u Available Updates" msgstr[0] "%u تحديث متوفر" msgstr[1] "%u تحديث متوفر" msgstr[2] "%u تحديثات متوفر" msgstr[3] "%u تحديثات متوفر" msgstr[4] "%u تحديثات متوفر" msgstr[5] "%u تحديثات متوفر" #: src/bz-license-dialog.blp:95 msgid "Get Involved" msgstr "شارك" #: src/bz-license-dialog.c:126 msgid "Unknown License" msgstr "الترخيص غير معروف" #: src/bz-license-dialog.c:129 msgid "Community Built" msgstr "من إنشاء المجتمع" #: src/bz-license-dialog.c:202 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "تم تطوير هذا التطبيق من قبل مجتمع دولي.\n" "\n" "يمكنك المساعدة في جعله أفضل." #: src/bz-license-dialog.c:205 msgid "The license of this app is not known" msgstr "ترخيص هذا التطبيق غير معروف" #: src/bz-license-dialog.c:211 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "تم تطوير هذا التطبيق من قبل مجتمع دولي, وإطلاقه تحت ترخيص %s.\n" "\n" "يمكنك المساعدة في جعله أفضل." #: src/bz-license-dialog.c:219 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "هذا التطبيق ليس مفتوح المصدر، لذا لا يعرف طريقة عمله إلا مطوروه. قد يكون غير " "آمن بطرق يصعب اكتشافها، وقد يتغير دون رقابة.\n" "\n" "قد تتمكن أو لا تتمكن من المساهمة في تطوير هذا التطبيق." #: src/bz-license-dialog.c:225 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "تم تطوير هذا التطبيق بموجب ترخيص خاص %s.\n" "\n" "قد تتمكن أو لا تتمكن من المساهمة في هذا التطبيق." #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 msgid "Connect to Flathub" msgstr "اربط بفلاتهب" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "حدث خطأ" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "اربط حسابك على فلاتهب ببازار لادارة تطبيقاتك المفضلة." #: src/bz-login-page.blp:108 msgid "Finish" msgstr "انتهاء" #: src/bz-login-page.c:664 #, c-format msgid "Hello, %s!" msgstr "مرحبا, %s!" #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "التفضيلات" #: src/bz-preferences-dialog.blp:25 msgid "Network connection is metered — automatic store data sync is paused" msgstr "" "يتم تحديد تكلفة الاتصال بالشبكة - تم إيقاف مزامنة بيانات المتجر التلقائية " "مؤقتًا" #: src/bz-preferences-dialog.blp:26 src/bz-window.blp:334 msgid "Sync Manually" msgstr "زامن" #: src/bz-preferences-dialog.blp:31 msgid "Content Filters" msgstr "فلاتر المحتوى" #: src/bz-preferences-dialog.blp:34 msgid "Free Software Only" msgstr "برمجيات مجانية فقط" #: src/bz-preferences-dialog.blp:35 msgid "Hide proprietary applications when browsing and searching" msgstr "إخفاء التطبيقات المحتكرة من نتائج البحث" #: src/bz-preferences-dialog.blp:39 msgid "Flathub Results Only" msgstr "نتائج من فلاتهب فقط" #: src/bz-preferences-dialog.blp:40 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "قيِّد نتائج البحث إلى التطبيقات المتوفرة على فلاتهَب فقط" #: src/bz-preferences-dialog.blp:44 msgid "Verified Results Only" msgstr "نتائج موثقة فقط" #: src/bz-preferences-dialog.blp:45 msgid "Hide results that are not verified on Flathub" msgstr "استبعِد النتائج التي ليست موثقة من فلاتهَب" #: src/bz-preferences-dialog.blp:49 msgid "Hide EOL Apps" msgstr "إخفاء تطبيقات نهاية العمر الافتراضي" #: src/bz-preferences-dialog.blp:50 msgid "Hide apps which are no longer supported by their developers" msgstr "أخف التطبيقات التي لم تعد مدعومة من مطوريها" #: src/bz-preferences-dialog.blp:55 src/bz-window.blp:197 msgid "Search" msgstr "ابحث" #: src/bz-preferences-dialog.blp:58 msgid "Delay Search Results" msgstr "تأخير نتائج البحث" #: src/bz-preferences-dialog.blp:59 msgid "Improve results performance by debouncing search terms" msgstr "تحسين أداء نتائج البحث عن طريق تقليل ارتداد مصطلحات البحث" #: src/bz-preferences-dialog.blp:64 msgid "Progress Bar" msgstr "شريط التقدم" #: src/bz-preferences-dialog.blp:65 msgid "Choose a theme for the progress bar!" msgstr "حدد سمة لشريط التحميل العام!" #: src/bz-preferences-dialog.blp:89 msgid "Vertical Stripes" msgstr "خطوط عمودية" #: src/bz-preferences-dialog.blp:90 msgid "Display flag colors from left to right" msgstr "اعرض ألوان العلم من اليسار إلى اليمين" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "لون النظام" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "الوان الفخر" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "الوان فخر السحاقيات" #: src/bz-preferences-dialog.c:35 msgid "Male Homosexual Pride Colors" msgstr "ألوان فخر المثليين الذكور" #: src/bz-preferences-dialog.c:36 msgid "Transgender Pride Colors" msgstr "ألوان فخر المتحولين جنسياً" #: src/bz-preferences-dialog.c:37 msgid "Nonbinary Pride Colors" msgstr "ألوان فخر غير الثنائيين" #: src/bz-preferences-dialog.c:38 msgid "Bisexual Pride Colors" msgstr "ألوان فخر ثنائيي الجنس" #: src/bz-preferences-dialog.c:39 msgid "Asexual Pride Colors" msgstr "ألوان فخر اللاجنسيين" #: src/bz-preferences-dialog.c:40 msgid "Pansexual Pride Colors" msgstr "ألوان فخر الجنسانية الشاملة" #: src/bz-preferences-dialog.c:41 msgid "Aromantic Pride Colors" msgstr "ألوان فخر اللاجنسيين" #: src/bz-preferences-dialog.c:42 msgid "Genderfluid Pride Colors" msgstr "ألوان فخر الهوية الجندرية المتغيرة" #: src/bz-preferences-dialog.c:43 msgid "Polysexual Pride Colors" msgstr "ألوان فخر تعدد الميول الجنسية" #: src/bz-preferences-dialog.c:44 msgid "Omnisexual Pride Colors" msgstr "ألوان فخر الجنس الشامل" #: src/bz-preferences-dialog.c:45 msgid "Aroace Pride Colors" msgstr "ألوان فخر الأرومانسيين واللا رومانسيين" #: src/bz-preferences-dialog.c:46 msgid "Agender Pride Colors" msgstr "ألوان فخر اللاجنسيين" #: src/bz-preferences-dialog.c:47 msgid "Genderqueer Pride Colors" msgstr "ألوان فخر الجندر كوير" #: src/bz-preferences-dialog.c:48 msgid "Intersex Pride Colors" msgstr "ألوان فخر ثنائيي الجنس" #: src/bz-preferences-dialog.c:49 msgid "Demigender Pride Colors" msgstr "ألوان فخر الجنس الجزئي" #: src/bz-preferences-dialog.c:50 msgid "Biromantic Pride Colors" msgstr "ألوان فخر ثنائيي الميول الرومانسية" #: src/bz-preferences-dialog.c:51 msgid "Disability Pride Colors" msgstr "ألوان فخر ذوي الإعاقة" #: src/bz-preferences-dialog.c:52 msgid "Femboy Pride Colors" msgstr "ألوان فخر الفيمبوي" #: src/bz-preferences-dialog.c:53 msgid "Neutrois Pride Colors" msgstr "ألوان فخر النيوتروا" #: src/bz-releases-dialog.blp:5 src/bz-releases-list.blp:28 #: src/bz-updates-card.blp:150 msgid "Version History" msgstr "تاريخ الاصدارات" #: src/bz-releases-list.c:168 #, c-format msgid "Version %s" msgstr "الإصدار %s" #: src/bz-releases-list.c:220 msgid "No details for this release" msgstr "لا تفاصيل لهذه الإصدارة" #: src/bz-releases-list.c:232 msgid "Get More Information" msgstr "احصل على معلومات اضافية" #: src/bz-rich-app-tile.blp:153 msgid "Get" msgstr "يحصل" #: src/bz-safety-calculator.c:82 msgid "Unknown Permissions" msgstr "أذونات غير معروفة" #: src/bz-safety-calculator.c:83 msgid "Permissions are missing for this app." msgstr "أذونات مفقودة للتطبيق." #: src/bz-safety-calculator.c:96 msgid "No Permissions" msgstr "لا أذونات" #: src/bz-safety-calculator.c:97 msgid "App is fully sandboxed" msgstr "التطبيق معزول بالكامل" #: src/bz-safety-calculator.c:103 msgid "Network Access" msgstr "اتصال بالشبكة" #: src/bz-safety-calculator.c:104 msgid "Can access the internet" msgstr "قادر على الوصول للشبكة" #: src/bz-safety-calculator.c:106 msgid "No Network Access" msgstr "لا يوجد وصول للشبكة" #: src/bz-safety-calculator.c:107 msgid "Cannot access the internet" msgstr "غير قادر على الوصول للشبكة" #: src/bz-safety-calculator.c:112 msgid "User Device Access" msgstr "الوصول لجهاز المستخدم" #: src/bz-safety-calculator.c:113 msgid "Can access devices such as webcams or gaming controllers" msgstr "قادر على الوصول للأجهزة مثل الكاميرا وأيادي اللعب" #: src/bz-safety-calculator.c:115 msgid "No User Device Access" msgstr "غير قادر على الوصول لجهاز المستخدم" #: src/bz-safety-calculator.c:116 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "غير قادر على الوصول لأجهزة كالكاميرا أو كونترولر الألعاب" #: src/bz-safety-calculator.c:121 msgid "Input Device Access" msgstr "الوصول لأجهزة الدخل" #: src/bz-safety-calculator.c:122 msgid "Can access input devices" msgstr "قادر على الوصول لأجهزة الدخل" #: src/bz-safety-calculator.c:128 msgid "Microphone Access and Audio Playback" msgstr "الوصول للميكروفون وتشغيل الصوت" #: src/bz-safety-calculator.c:129 msgid "Can listen using microphones and play audio without asking permission" msgstr "قادر على الاستماع باستخدام الميكروفونات وتشغيل الصوت دون طلب إذن" #: src/bz-safety-calculator.c:135 msgid "System Device Access" msgstr "الوصول إلى أجهزة النظام" #: src/bz-safety-calculator.c:136 msgid "Can access system devices which require elevated permissions" msgstr "يمكنه الوصول إلى أجهزة النظام التي تتطلب صلاحيات موسعة" #: src/bz-safety-calculator.c:142 msgid "Screen Contents Access" msgstr "الوصول إلى محتويات الشاشة" #: src/bz-safety-calculator.c:143 msgid "Can access the contents of the screen or other windows" msgstr "يمكن الوصول إلى محتويات الشاشة أو النوافذ الأخرى" #: src/bz-safety-calculator.c:149 msgid "Legacy Windowing System" msgstr "نظام نوافذ قديم" #: src/bz-safety-calculator.c:150 msgid "Always uses a legacy windowing system (X11)" msgstr "دائما يستخدم نظام النوافذ (X11) القديم" #: src/bz-safety-calculator.c:156 msgid "Arbitrary Permissions" msgstr "أذونات تعسفية" #: src/bz-safety-calculator.c:157 msgid "Can acquire arbitrary permissions" msgstr "يمكن الحصول على أذونات تعسفية" #: src/bz-safety-calculator.c:163 msgid "User Settings" msgstr "إعدادات المستخدم" #: src/bz-safety-calculator.c:164 msgid "Can access and change user settings" msgstr "قادر على الوصول وتعديل إعدادات المستخدم" #: src/bz-safety-calculator.c:170 msgid "Full File System Read/Write Access" msgstr "وصول كامل لقراءة وكتابة ملفات النظام" #: src/bz-safety-calculator.c:171 msgid "Can read and write all data on the file system" msgstr "قادر على قراءة وكتابة جميع البيانات التي على بيانات النظام" #: src/bz-safety-calculator.c:178 msgid "Home Folder Read/Write Access" msgstr "إمكانية الوصول للقراءة/الكتابة إلى المجلد الرئيسي" #: src/bz-safety-calculator.c:179 msgid "Can read and write all data in your home directory" msgstr "يمكنك قراءة وكتابة جميع البيانات في دليل المستخدم الخاص بك" #: src/bz-safety-calculator.c:186 msgid "Full File System Read Access" msgstr "وصول كامل لقراءة ملفات النظام" #: src/bz-safety-calculator.c:187 msgid "Can read all data on the file system" msgstr "يمكن قراءة جميع البيانات الموجودة على نظام الملفات" #: src/bz-safety-calculator.c:195 msgid "Home Folder Read Access" msgstr "إمكانية قراءة المجلد الرئيسي" #: src/bz-safety-calculator.c:196 msgid "Can read all data in your home directory" msgstr "يمكن قراءة جميع البيانات في مجلدك الرئيسي" #: src/bz-safety-calculator.c:204 msgid "Download Folder Read/Write Access" msgstr "إمكانية قراءة/كتابة مجلد التنزيل" #: src/bz-safety-calculator.c:205 msgid "Can read and write all data in your downloads directory" msgstr "يمكنك قراءة وكتابة جميع البيانات في مجلد التنزيلات الخاص بك" #: src/bz-safety-calculator.c:215 msgid "Download Folder Read Access" msgstr "إمكانية قراءة مجلد التنزيل" #: src/bz-safety-calculator.c:216 msgid "Can read all data in your downloads directory" msgstr "قادر على قراءة جميع البيانات في مجلد التحميلات" #: src/bz-safety-calculator.c:229 msgid "Can read and write all data in the directory" msgstr "قادر على قراءة وكتابة البيانات ضمن هذا المجلد" #: src/bz-safety-calculator.c:243 msgid "Can read all data in the directory" msgstr "قادر على قراءة البيانات ضمن هذا المجلد" #: src/bz-safety-calculator.c:258 msgid "No File System Access" msgstr "لا يوجد وصول لملفات النظام" #: src/bz-safety-calculator.c:259 msgid "Cannot access the file system at all" msgstr "غير قادر على الوصول لملفات النظام على الإطلاق" #: src/bz-safety-calculator.c:266 msgid "Uses System Services" msgstr "يستخدم خدمات النظام" #: src/bz-safety-calculator.c:267 msgid "Can request data from non-portal system services" msgstr "يمكن طلب البيانات من خدمات النظام غير التابعة للبوابة" #: src/bz-safety-calculator.c:273 msgid "Uses Session Services" msgstr "يستخدم خدمات الجلسة" #: src/bz-safety-calculator.c:274 msgid "Can request data from non-portal session services" msgstr "يمكن طلب البيانات من خدمات جلسات غير تابعة للبوابة" #: src/bz-safety-calculator.c:322 msgid "No Service Access" msgstr "لا يوجد وصول للخدمات" #: src/bz-safety-calculator.c:323 msgid "Cannot access non-portal session or system services at all" msgstr "" "لا يمكن الوصول إلى جلسات أو خدمات النظام غير التابعة للبوابة على الإطلاق" #: src/bz-safety-calculator.c:331 msgid "Verified App Developer" msgstr "مطور تطبيقات موثق" #: src/bz-safety-calculator.c:332 msgid "The developer of this app has been verified to be who they say they are" msgstr "تم التحقق من هوية مطور هذا التطبيق" #: src/bz-safety-calculator.c:341 msgid "Proprietary Code" msgstr "كود محتكر" #: src/bz-safety-calculator.c:342 msgid "" "The source code is not public, so it cannot be independently audited and " "might be unsafe" msgstr "" "الكود المصدري غير متاح للعامة ويمكن مراجعته بشكل مستقل، مما يعني أن التطبيق " "قد يكون غير آمن" #: src/bz-safety-calculator.c:352 msgid "Auditable Code" msgstr "كود قابل للتدقيق" #: src/bz-safety-calculator.c:353 msgid "" "The source code is public and can be independently audited, which makes the " "app more likely to be safe" msgstr "" "الكود المصدري متاح للعامة ويمكن مراجعته بشكل مستقل، مما يجعل التطبيق أكثر " "أمانًا" #: src/bz-safety-calculator.c:493 #, c-format msgid "Use the %s System Service" msgstr "يمكنه استخدام خدمة النظام: %s" #: src/bz-safety-calculator.c:497 #, c-format msgid "Use the %s Session Service" msgstr "يمكنه استخدام جلسة الخدمة: %s" #: src/bz-safety-calculator.c:501 #, c-format msgid "Use the %s Service" msgstr "يمكنه استخدام خدمة: %s" #: src/bz-safety-calculator.c:511 msgid "Can see the non-portal service" msgstr "يمكنه رؤية الخدمة غير التابعة للبوابة" #: src/bz-safety-calculator.c:513 msgid "Can talk to the non-portal service" msgstr "يمكنه التحدث مع الخدمة غير التابعة للبوابة" #: src/bz-safety-calculator.c:515 msgid "Can own the non-portal service" msgstr "يمكنه امتلاك الخدمة غير التابعة للبوابة" #: src/bz-safety-calculator.c:530 msgid "Global Menu Integration" msgstr "تكامل القوائم العامة" #: src/bz-safety-calculator.c:531 msgid "Can display its menus in a global menu bar" msgstr "قادر على عرض قوائمه في شريط القوائم العام" #: src/bz-safety-calculator.c:536 msgid "KDE Settings Integration" msgstr "تكامل إعدادات KDE" #: src/bz-safety-calculator.c:537 msgid "Can detect when KDE desktop settings change" msgstr "قادر على تحديد التغيرات في إعدادات سطح مكتب KDE" #: src/bz-safety-calculator.c:542 msgid "KDE Global Settings" msgstr "الإعدادات العامة لـKDE" #: src/bz-safety-calculator.c:543 msgid "Can read KDE desktop preferences like fonts and colors" msgstr "قادر على قراءة تفضيلات سطح مكتب KDE مثل الخطوط والألوان" #: src/bz-safety-calculator.c:548 msgid "Secret Storage Service" msgstr "خدمة تخزين الأسرار" #: src/bz-safety-calculator.c:549 msgid "Can store and retrieve its own passwords using the system keyring" msgstr "" "قادر على تخزين واستعادة كلمات المرور الخاصة به باستخدام سلسلة مفاتيح النظام" #: src/bz-safety-calculator.c:554 msgid "Desktop Notifications Service" msgstr "خدمة إشعارات سطح المكتب" #: src/bz-safety-calculator.c:555 msgid "Can send desktop notifications" msgstr "يستطيع إرسال إشعارات لسطح المكتب" #: src/bz-safety-calculator.c:561 msgid "System Tray Integration" msgstr "تكامل شريط النظام" #: src/bz-safety-calculator.c:562 msgid "Can display an icon in the system tray" msgstr "قادر على عرض أيقونة في شريط النظام" #: src/bz-safety-calculator.c:567 msgid "KDE Connect Integration" msgstr "تكامل KDE Connect" #: src/bz-safety-calculator.c:568 msgid "Can interact with devices paired via KDE Connect" msgstr "قادر على التفاعل مع الأجهزة المرتبطة عن طريق KDE Connect" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "الأمن" #: src/bz-safety-dialog.blp:50 msgid "Details" msgstr "التفاصيل" #: src/bz-safety-dialog.blp:53 msgid "License" msgstr "الرخصة" #: src/bz-safety-dialog.blp:63 msgid "App ID" msgstr "معرف التطبيق" #: src/bz-safety-dialog.blp:73 msgid "SDK" msgstr "حزمة التطوير البرمجية" #: src/bz-safety-dialog.blp:101 msgid "" "This app uses an outdated version of the software platform (SDK) and might " "contain bugs or security vulnerabilities which will not be fixed." msgstr "" "يستخدم هذا التطبيق إصدارًا قديمًا من منصة البرامج (حزمة تطوير برمجية) وقد " "يحتوي على أخطاء أو ثغرات أمنية لن يتم إصلاحها." #: src/bz-safety-dialog.c:227 #, c-format msgid "%s is Safe" msgstr "%s آمن" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s has no Unsafe Permissions" msgstr "%s لا يملك أذونات آمنة" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Probably Safe" msgstr "%s آمن غالبا" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Possibly Unsafe" msgstr "%s يمكن أن يكون آمن" #: src/bz-safety-dialog.c:247 #, c-format msgid "%s is Unsafe" msgstr "%s غير آمن" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "لقطات الشاشة" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "لقطة الشاشة السابقة" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "لقطة الشاشة التالية" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "نسخ الصورة" #: src/bz-screenshot-page.blp:147 msgid "Reset View" msgstr "إعادة ضبط" #: src/bz-screenshot-page.blp:158 msgid "Zoom Out" msgstr "تصغير" #: src/bz-screenshot-page.blp:168 msgid "Zoom In" msgstr "تكبير" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "عرض لقطات الشاشة" #: src/bz-screenshots-carousel.blp:112 msgid "Open Screenshot Viewer" msgstr "افتح عارض لقطات الشاشة" #: src/bz-search-widget.blp:57 msgid "Search Apps, Games, Software" msgstr "ابحث عن التطبيقات, الألعاب, البرامج" #: src/bz-search-widget.blp:96 msgid "Categories Unavailable" msgstr "التصنيف غير متوفر" #: src/bz-search-widget.blp:97 msgid "Search for apps using the search bar above." msgstr "ابحث عن التطبيقات من خلال حقل البحث في الأعلى." #: src/bz-search-widget.blp:181 msgid "No Applications Found" msgstr "لم يتم العثور على تطبيق" #: src/bz-search-widget.c:241 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "لا يوجد نتائج لـ \"%s\" في فلاتهب" #: src/bz-share-list.c:64 msgid "Copied!" msgstr "نُسِخ!" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "انسخ الوصلة" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "افتح الوصلة" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "الخط الزمني" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "التنصيبات:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "العالم" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:124 #, c-format msgid "%.2fM Total Installs" msgstr "%.2fM كامل التنزيلات" #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:127 #, c-format msgid "%.2fK Total Installs" msgstr "%.2fK كامل التنزيلات" #: src/bz-stats-dialog.c:129 #, c-format msgid "%'d Total Installs" msgstr "%'d كامل التنزيلات" #: src/bz-tag-list.c:96 msgid "No Results Found" msgstr "لا توجد نتائج" #: src/bz-tag-list.c:108 #, c-format msgid "Apps Tagged \"%s\"" msgstr "التطبيقات الموسومة \"%s\"" #: src/bz-tag-list.c:124 msgid "Search failed" msgstr "فشل البحث" #: src/bz-transaction-dialog.c:155 msgid "Keep Data" msgstr "الحفاظ على المعلومات" #: src/bz-transaction-dialog.c:156 msgid "Allow restoring settings and content" msgstr "السماح باستعادة الإعدادات والمحتوى" #: src/bz-transaction-dialog.c:165 msgid "Delete Data" msgstr "حذف المعلومات" #: src/bz-transaction-dialog.c:166 msgid "Permanently remove app data to save space" msgstr "أزِل معلومات التطبيق نهائيا للحفاظ على مساحة التخزين" #: src/bz-transaction-dialog.c:191 #, c-format msgid "Install %s?" msgstr "أتُنصِّب %s؟" #: src/bz-transaction-dialog.c:196 msgid "" "Select which version to install. May install additional shared components" msgstr "حدد الإصدار الذي ترغب في تنصيبه. قد تُنصَّب مكونات إضافية مشتركة" #: src/bz-transaction-dialog.c:198 msgid "May install additional shared components" msgstr "قد تُنصَّب مكونات إضافية مشتركة" #: src/bz-transaction-dialog.c:219 #, c-format msgid "Remove %s?" msgstr "أتُزيل %s؟" #: src/bz-transaction-dialog.c:222 msgid "Select which version to remove." msgstr "حدد الإصدار الذي تود حذفه." #: src/bz-transaction-dialog.c:224 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "لن تستطيع استخدام %s بعد إزالته." #: src/bz-transaction-dialog.c:247 #, c-format msgid "“%s” is High Risk" msgstr "“%s” خطر جدا" #: src/bz-transaction-dialog.c:251 msgid "" "This app has full access to your system, including all your files, " "browser history, saved passwords, and more. It also has access to the " "internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "هذا التطبيق يملك صلاحيات كاملة على نظامك منها ملفاتك, معلومات تصفحك, " "كلمات مرورك المحفوظة,و المزيد. وأيضا يملك صلاحية وصول للشبكة, قد يعني " "ذلك إرسال معلوماتك لجهات خارجية.\n" "\n" "لأن التطبيق محتكر، فلا يمكن تدقيقه لمعرفة ما يفعله بهذه الأذونات." #: src/bz-transaction-dialog.c:260 msgid "" "This app uses the legacy X11 windowing system, which allows it to record " "all keystrokes, capture screenshots, and monitor other applications. It " "also has access to the internet, meaning it could send your data to outside " "parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "هذا التطبيق يستخدم نظام النوافذ X11, مما يسمح له بـ تسجيل جميع ضغطات " "الأزرار, تسجيل لقطات الشاشة, ومراقبة التطبيقات الأخرى. كما يمكنه أيضا " "الوصول للشبكة, مما يعني إمكانية إرسال بياناتك الشخصية لأطراف خارجية.\n" "لأن التطبيق محتكر، فلا يمكن تدقيقه لمعرفة ما يفعله بهذه الأذونات." #: src/bz-transaction-dialog.c:276 msgid "Install Anyway" msgstr "نصِّب على كل حال" #: src/bz-transaction-dialog.c:549 msgid "All apps are already installed" msgstr "تم تنصيب جميع التطبيقات" #: src/bz-transaction-dialog.c:551 msgid "OK" msgstr "حسناً" #: src/bz-transaction-dialog.c:567 #, c-format msgid "Install %u App?" msgid_plural "Install %u Apps?" msgstr[0] "أتُنصِّب %u التطبيق؟" msgstr[1] "أتُنصِّب %u التطبيق؟" msgstr[2] "أتُنصِّب %u التطبيقات؟" msgstr[3] "أتُنصِّب %u التطبيقات؟" msgstr[4] "أتُنصِّب %u التطبيقات؟" msgstr[5] "أتُنصِّب %u التطبيقات؟" #: src/bz-transaction-dialog.c:575 msgid "" "The following will be installed. Additional shared components may also be " "installed" msgstr "سيتم تنصيب التالي. برمجيات تشاركية إضافية قد يتم تنصيبها" #: src/bz-transaction-dialog.c:576 #, c-format msgid "%d addons will be installed." msgstr "%d إضافات ستنصَّب." #: src/bz-transaction-dialog.c:577 msgid "Additionally, addons will be installed." msgstr "بالإضافة إلى ذلك، ستنصَّب %d من بيئات التشغيل و\\أو الإضافات." #: src/bz-transaction-manager.c:1251 #, c-format msgid "Finished in %.02f seconds" msgstr "انتهى خلال %.02f ثانية" #: src/bz-transaction-tile.blp:125 msgid "App Add-on" msgstr "إضافات التطبيق" #: src/bz-transaction-tile.blp:154 msgid "Runtime" msgstr "وقت التشغيل" #: src/bz-transaction-tile.blp:178 msgid "In Queue" msgstr "في الطابور" #: src/bz-transaction-tile.blp:202 msgid "Done" msgstr "انتهاء" #: src/bz-transaction-tile.blp:226 msgid "Error" msgstr "خطأ" #: src/bz-transaction-tile.blp:267 msgid "Open App" msgstr "افتح التطبيق" #: src/bz-transaction-tile.c:110 #, c-format msgid "%s Freed" msgstr "%s ذاكرة محررة" #: src/bz-transaction.c:342 msgid "Pending" msgstr "ينتظر" #: src/bz-updates-card.blp:36 msgid "Update All" msgstr "حدِّث الكل" #: src/bz-updates-card.blp:161 src/bz-updates-card.blp:186 msgid "Update" msgstr "حدِّث" #: src/bz-updates-card.c:293 #, c-format msgid "%u Runtime Update" msgid_plural "%u Runtime Updates" msgstr[0] "%u تحديث وقت التشغيل" msgstr[1] "%u تحديث وقت التشغيل" msgstr[2] "%u تحديثات وقت التشغيل" msgstr[3] "%u تحديثات وقت التشغيل" msgstr[4] "%u تحديثات وقت التشغيل" msgstr[5] "%u تحديثات وقت التشغيل" #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "أدر معلوماتك" #: src/bz-user-data-page.blp:89 msgid "No User Data found" msgstr "لم يتم العثور على معلومات المستخدم" #: src/bz-user-data-page.blp:94 msgid "User Data" msgstr "معلومات المستخدم" #: src/bz-user-data-tile.c:144 #, c-format msgid "Trashed User Data for %s" msgstr "معلومات المستخدم المهملة لـ %s" #: src/bz-user-data-tile.blp:74 msgid "Trash User Data" msgstr "معلومات المستخدم المهملة" #: src/bz-window.blp:135 msgid "Refreshing Store Content" msgstr "تحديث محتوى المتجر" #: src/bz-window.blp:153 msgid "Curated" msgstr "المنتقاة" #: src/bz-window.blp:166 msgid "Flathub" msgstr "فلاتهَب" #: src/bz-window.blp:273 msgid "No background tasks!" msgstr "لا توجد مهمات في الخلفية!" #: src/bz-window.blp:325 msgid "You are running a new version of Bazaar!" msgstr "انت تشغل نسخة حديثة من بازار!" #: src/bz-window.blp:326 msgid "See What's New" msgstr "تعرف على أحدث التطبيقات" #: src/bz-window.blp:333 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "لديك اتصال بالشبكة ولكن يتم عرض نسخة مسجلة من فلاتهب" #: src/bz-window.blp:449 msgid "Log Out" msgstr "تسجيل الخروج" #: src/bz-window.c:683 msgid "You can't remove Bazaar from Bazaar!" msgstr "لا يمكنك حذف بازار من بازار!" #: src/bz-window.c:891 src/bz-window.c:925 msgid "Can't do that right now!" msgstr "لا يمكن فعل ذلك الآن!" #: src/bz-world-map.c:587 msgctxt "As in, \"100 Downloads\"" msgid "Downloads" msgstr "التنزيلات" #: src/gtk/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "عام" #: src/gtk/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "افتح البحث" #: src/gtk/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Preferences" msgstr "افتح التفضيلات" #: src/gtk/shortcuts-dialog.blp:19 msgctxt "shortcut window" msgid "Synchronize Remotes" msgstr "المزامنة" #: src/gtk/shortcuts-dialog.blp:24 msgctxt "shortcut window" msgid "Open Library" msgstr "افتح المكتبة" #: src/gtk/shortcuts-dialog.blp:30 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "أظهِر الاختصارات" #: src/gtk/shortcuts-dialog.blp:35 msgctxt "shortcut window" msgid "Quit" msgstr "الخروج" #~ msgid "Show Git Forge Star Counts" #~ msgstr "إظهار نجوم مستودع جِت" #~ msgid "" #~ "Whether to attempt to detect and show \"star counts\" for projects in the " #~ "full view" #~ msgstr "أيظهر مقدار نجوم مستودع جِت للمشروع أم لا؟" #~ msgid "Only Show Free Software" #~ msgstr "إظهار البرمجيات الحرة حصرًا" #~ msgid "Hide proprietary software when searching" #~ msgstr "يخفي البرمجيات المحتكرة عند البحث" #~ msgid "Filter search results to only show applications available on Flathub" #~ msgstr "يرشِّح نتائج البحث لتظهر التطبيقات المتوفرة على فلاتهَب حصرًا" #~ msgid "Debounce Search Inputs" #~ msgstr "تجاهل ارتداد مدخلات البحث" #~ msgid "Add a delay before searching to prevent instant replies while typing" #~ msgstr "يؤخر إظهار النتائج لمنع ظهورها فوريًا أثناء الكتابة" #~ msgid "Global Progress Bar Theme" #~ msgstr "سمة شريط التقدم العامة" #~ msgid "Describes the look of the global progress bar" #~ msgstr "يشرح المظهر العام لشريط التقدم" #~ msgid "Saved Window Dimensions" #~ msgstr "أبعاد النافذة المحفوظة" #~ msgid "The window dimensions to be used by the next Bazaar window" #~ msgstr "أبعاد النافذة التي ستستخدمها نافذة بازار التالية" #~ msgid "Nucleus app page" #~ msgstr "صفحة تطبيق «Nucleus»" #~ msgid "Manage Addons" #~ msgstr "أدِر الإضافات" #~ msgid "Of the size of human DNA" #~ msgstr "من حجم الحمض الريبي النووي منزوع الأكسجين للإنسان" #~ msgid "3 billion base pairs" #~ msgstr "3 مليارات زوج قاعدي" #~ msgid "Of the Linux Kernel" #~ msgstr "من نواة لينكس" #~ msgid "linux-6.17.tar.xz" #~ msgstr "linux-6.17.tar.xz" #~ msgid "Of the Apollo 11 guidance computer" #~ msgstr "من حاسوب توجيه أبولو 11" #~ msgid "Total ROM and RAM" #~ msgstr "إجمالي ذاكرة القراءة والذاكرة العشوائية" #~ msgid "Of the original Super Mario Bros" #~ msgstr "من لعبة «سوبر ماريو بروز» الأصلية" #~ msgid "Of the size of Wikipedia" #~ msgstr "من حجم ويكيبيديا" #~ msgid "Without any media" #~ msgstr "دون أي وسائط" #~ msgid "" #~ "This functionality is currently disabled. It is recommended you download " #~ "and install Flatseal to manage app permissions." #~ msgstr "" #~ "هذه الوظيفة معطَّلة حاليًا. ينصح بتنصيب «فلاتسيل» لإدارة أذونات التطبيق." #~ msgctxt "About Dialog Translator Credit" #~ msgid "Ahmed Najmawi" #~ msgstr "أحمد النجماوي" #~ msgctxt "About Dialog Translator Credit" #~ msgid "AtomHare" #~ msgstr "AtomHare" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Azenyr" #~ msgstr "AtomHare" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Goudarz Jafari" #~ msgstr "Goudarz Jafari" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Jill Fiore (Lumaeris)" #~ msgstr "Jill Fiore (Lumaeris)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "João Victor (Leal)" #~ msgstr "João Victor (Leal)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "KiKaraage" #~ msgstr "KiKaraage" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Lucosec" #~ msgstr "Lucosec" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Léane GRASSER" #~ msgstr "Léane GRASSER" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Marcel Mrówka (Microwave)" #~ msgstr "Marcel Mrówka (Microwave)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Peter Dave Hello" #~ msgstr "Peter Dave Hello" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Pietro F." #~ msgstr "Pietro F." #~ msgctxt "About Dialog Translator Credit" #~ msgid "Shihfu Juan" #~ msgstr "Shihfu Juan" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Shinsei" #~ msgstr "Shinsei" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Vlastimil Dědek" #~ msgstr "Vlastimil Dědek" #~ msgctxt "About Dialog Translator Credit" #~ msgid "asen23" #~ msgstr "asen23" #~ msgctxt "About Dialog Translator Credit" #~ msgid "camegone" #~ msgstr "camegone" #~ msgctxt "About Dialog Translator Credit" #~ msgid "renner" #~ msgstr "renner" #~ msgctxt "About Dialog Translator Credit" #~ msgid "robotta" #~ msgstr "robotta" #~ msgid "Constructing Flatpak instance..." #~ msgstr "تُبنى نسخة فلاتباك..." #~ msgid "Reusing last Flatpak instance..." #~ msgstr "يعاد استخدام آخر نسخة فلاتباك..." #~ msgid "Flathub is not registered on this system" #~ msgstr "لم يُسجِّل فلاتهَب على هذا النظام" #~ msgid "" #~ "Would you like to add Flathub as a remote? If you decline, the Flathub " #~ "page will not be available. You can change this later." #~ msgstr "" #~ "أتود إضافة فلاتهَب كمستودع؟ لن تتوفر صفحة فلاتهَب إن رفضت ذلك. يمكنك تغيير " #~ "ذلك لاحقًا." #~ msgid "Add Flathub" #~ msgstr "أضِف فلاتهَب" #, c-format #~ msgid "Identifying installed entries..." #~ msgstr "يتعرف على المدخلات المنصَّبة..." #, c-format #~ msgid "" #~ "Beginning remote entry retrieval while referencing %d blocklist(s)..." #~ msgstr "يبدأ جلب مدخلات المستودع أثناء إحالة %d قائمة حجب..." #, c-format #~ msgid "%'d of %'d" #~ msgstr "%'d من %'d" #, c-format #~ msgid "Waiting for background indexing tasks to catch up..." #~ msgstr "ينتظر اكتمال مهام فهرسة الخلفية..." #, c-format #~ msgid "Completed initialization in %0.2f seconds" #~ msgstr "اكتمل التمهيد خلال %0.2f ثانية" #~ msgid "" #~ "Bazaar was not provided a curated content configuration. Contact your " #~ "operating system's support channels for assistance." #~ msgstr "" #~ "لم يُزوَّد بازار بإعدادات محتوى منتقى. تواصل مع قنوات دعم نظام تشغيلك للحصول " #~ "على المساعدة." #~ msgid "Entry Inspector" #~ msgstr "فاحص المدخلات" #~ msgid "Serialize" #~ msgstr "سَلسِل" #~ msgid "Convert to JSON" #~ msgstr "حوِّل إلى JSON" #~ msgid "Graphics" #~ msgstr "رسوميات" #~ msgid "Office" #~ msgstr "مكتب" #~ msgctxt "Project URL Type" #~ msgid "Homepage" #~ msgstr "الصفحة الرئيسة" #~ msgid "This flatpak is verified by the original developers of the software." #~ msgstr "وثَّق مطوروا البرمجية فلاتباك هذا." #~ msgid "Repository Star Count" #~ msgstr "نجوم المستودع" #~ msgid "Share this application" #~ msgstr "شارِك هذا التطبيق" #~ msgid "Excludes shared components" #~ msgstr "يستبعد المكونات المشتركة" #~ msgid "Source code may not be available" #~ msgstr "قد لا يتوفر المصدر البرمجي" #~ msgid "Click for details" #~ msgstr "انقر للتفاصيل" #~ msgid "Repositories" #~ msgstr "المستودعات" #~ msgid "Open in browser" #~ msgstr "افتح في المتصفح" #, c-format #~ msgid "%'d Monthly Downloads" #~ msgstr "%'d تنزيل شهري" #~ msgid "%B %-d, %Y" #~ msgstr "%-Od %B، %OY" #~ msgid "%B %-d" #~ msgstr "%-Od %B" #~ msgid "Bazaar Inspector" #~ msgstr "متعقب «بازار»" #~ msgid "Active Blocklists" #~ msgstr "قوائم الحجب النشطة" #~ msgid "Active Curated-Configs" #~ msgstr "ضبط التطبيقات «المنتقاة» النشط" #~ msgid "All Entry Groups" #~ msgstr "جميع مجموعات المدخلات" #~ msgid "Filter..." #~ msgstr "رشِّح..." #~ msgid "Decache and Inspect" #~ msgstr "امحُ الاختزان وافحص" #~ msgid "No Flatpaks Installed" #~ msgstr "لا حزم فلاتباك منصَّبة" #~ msgid "Run this application" #~ msgstr "شغِّل هذا التطبيق" #~ msgid "Run" #~ msgstr "شغِّل" #~ msgid "Application Details" #~ msgstr "تفاصيل التطبيق" #~ msgid "Git Forge Star Counts" #~ msgstr "نجوم مستودع جِت" #~ msgid "Not having a GitHub access token may trigger rate limits" #~ msgstr "قد يُحدّ وصولك إن لم يكن لديك رمز وصول جِت‌هَب" #~ msgid "Show Only Flathub Apps" #~ msgstr "إظهار تطبيقات فلاتهَب حصرًا" #~ msgid "Wait for a brief pause to reduce system load" #~ msgstr "ينتظر وهلة لتخفيف حِمل النظام عند البحث" #~ msgid "Theme" #~ msgstr "السمة" #~ msgid "Pride Rainbow Flag" #~ msgstr "علم فخر قوس قزح" #~ msgid "Bisexual Flag" #~ msgstr "علم ازدواج التوجه الجنسي" #~ msgid "Asexual Flag" #~ msgstr "علم اللاجنسية" #~ msgid "Share" #~ msgstr "شارِك" #, c-format #~ msgid "Transferred %s so far" #~ msgstr "نُقِل %s حتى الآن" #~ msgid "" #~ "The following applications are eligible for updates. Would you like to " #~ "install them?" #~ msgstr "التطبيقات التالية متاحة للتحديث. أتنصبها؟" #, c-format #~ msgid "" #~ "%d runtimes and/or addons are eligible for updates. Would you like to " #~ "install them?" #~ msgstr "تتوفر تحديثات ل‍ %d من بيئات التشغيل و\\أو الإضافات. أتنصبها؟" #~ msgid "Transactions" #~ msgstr "العمليات" #~ msgid "Toggle transaction sidebar" #~ msgstr "بدِّل الشريط الجانبي للعمليات" #~ msgid "Stop Active Tasks" #~ msgstr "أوقف المهام النشطة" #~ msgid "Clear History" #~ msgstr "امحُ التأريخ" #~ msgid "No Tasks Yet" #~ msgstr "لا توجد مهام حتى الآن" #~ msgid "Browse" #~ msgstr "تصفَّح" #~ msgid "App View" #~ msgstr "منظور التطبيق" #~ msgid "Go Back" #~ msgstr "ارجِع" #~ msgid "View curated applications" #~ msgstr "اعرِض التطبيقات المنتقاة" #~ msgid "View the latest on Flathub" #~ msgstr "اعرِض آخر المستجدات على فلاتهَب" #~ msgid "_Quit Service" #~ msgstr "أ_نهِ الخدمة" #~ msgid "Up to date!" #~ msgstr "مُحدَّث!" #~ msgid "" #~ "The ability to inspect and install local .flatpak bundle files is coming " #~ "soon! In the meantime, try running\n" #~ "\n" #~ "flatpak install --bundle your-bundle.flatpak\n" #~ "\n" #~ "on the command line." #~ msgstr "" #~ "قابلة فحص وتنصيب ملفات حزم .flatpak قادمة. أثناء ذلك، يمكنك تشغيل\n" #~ "\n" #~ "flatpak install --bundle your-bundle.flatpak\n" #~ "\n" #~ "في الطرفية." #~ msgid "Settings & user data will be kept" #~ msgstr "ستبقى الإعدادات وبيانات المستخدم مخزَّنة" #~ msgid "Resume Current Tasks" #~ msgstr "استأنف المهام الحالية" #~ msgid "Pause Current Tasks" #~ msgstr "ألبث المهام الحالية" #, c-format #~ msgid "%s: %'u downloads" #~ msgstr "%s: %'u تنزيل" #~ msgctxt "shortcut window" #~ msgid "Refresh" #~ msgstr "أعِد التحميل" #~ msgctxt "shortcut window" #~ msgid "Toggle Transaction Manager" #~ msgstr "بدِّل مدير المعاملات" #~ msgid "Calligraphy application page" #~ msgstr "صفحة تطبيق «كالِغرَفي»" #~ msgid "Download graph for Blender" #~ msgstr "تنزيل رسم بياني ل‍«بلندر»" #~ msgid "Open this image in the default image viewer" #~ msgstr "افتح هذه الصورة في عارض الصور المبدئي" #~ msgid "Copy this image to the clipboard" #~ msgstr "انسخ هذه الصورة إلى الحافظة" #~ msgid "Download Statistics" #~ msgstr "إحصاءات التنزيل" #~ msgid "Show Downloads Over Time" #~ msgstr "أظهِر التنزيلات عبر الزمن" #~ msgid "Remote repo name" #~ msgstr "اسم المستودع" #~ msgid "Updated Size" #~ msgstr "الحجم المحدَّث" #~ msgid "Freed Space" #~ msgstr "المساحة المفرغة" #~ msgid "Transactions Will Appear Here" #~ msgstr "ستظهر العمليات هنا" #~ msgid "Halt the execution of transactions" #~ msgstr "أوقِف تنفيذ العمليات" #~ msgid "Resume the execution of transactions" #~ msgstr "استَئنف تنفيذ العمليات" #~ msgid "Pause the execution of transactions" #~ msgstr "أوقِف تنفيذ العمليات مؤقتًا" #~ msgid "Apps Of The Week" #~ msgstr "تطبيقات الأسبوع" #, c-format #~ msgid "Released %x" #~ msgstr "أُصدِر في %x" #~ msgid "Downloads Over Time" #~ msgstr "التنزيلات عبر الزمن" #~ msgid "Minimize Lower Bound" #~ msgstr "صغِّر الحد الأدنى" #~ msgid "Maximize Upper Bound" #~ msgstr "كبِّر الحد الأعلى" #~ msgid "Confirm Action" #~ msgstr "تأكيد الإجراء" #, c-format #~ msgid "" #~ "You are about to remove the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "أنت على وشك إزالة حزمة فلاتباك التالية:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "أمتأكد؟" #, c-format #~ msgid "" #~ "You are about to install the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "أنت على وشك تنصيب حزمة فلاتباك التالية:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "أمتأكد؟" #~ msgctxt "Project URL Type" #~ msgid "VCS Browser" #~ msgstr "المستودع" #~ msgid "Full Application View" #~ msgstr "عرض التطبيق الكامل" #~ msgid "Change what content is shown when viewing applications" #~ msgstr "يغيِّر المحتوى المعروض عند إظهار التطبيقات" #~ msgid "" #~ "If you do not have an access token, turning this setting on may cause " #~ "GitHub to eventually rate limit you." #~ msgstr "" #~ "قد يؤدي تفعيل هذا الإعداد إلى حدِّك من الوصول إلى GitHub إن لم يكن لديك رمز " #~ "وصول." #~ msgid "Type to filter" #~ msgstr "اكتب للترشيح" #~ msgid "Exclude results with proprietary licenses" #~ msgstr "استبعِد النتائج ذات الرخص الاحتكارية" #~ msgid "Advanced" #~ msgstr "متقدم" #~ msgid "Open this link externally" #~ msgstr "افتح هذه الوصلة خارجيًا" #, c-format #~ msgid "Received %'d entries out of %'d (%0.1f seconds elapsed)" #~ msgstr "استُلمت %'d من أصل %'d (انقضت %0.1f ثانية)" #~ msgid "Installing" #~ msgstr "ينصَّب" #~ msgid "Removing" #~ msgstr "يُزال" #~ msgid "Show Animated Background" #~ msgstr "إظهار الخلفية المتحركة" #~ msgid "Whether to show the animated icon background on the home page" #~ msgstr "أتُعرَض خلفية الأيقونات المتحركة في الصفحة الرئيسة أم لا" #~ msgid "" #~ "The number of downloads in the last 30 days. Click to view this " #~ "application's download statistics." #~ msgstr "عدد التنزيلات في آخر 30 يومًا. انقر لعرض إحصائيات تنزيل هذا التطبيق." #~ msgid "How the application looks" #~ msgstr "كيف يبدو التطبيق" #~ msgid "Appearance" #~ msgstr "المظهر" #~ msgid "Show animated background" #~ msgstr "إظهار الخلفية المتحركة" #~ msgid "Keep the summary shorter, between 10 and 35 characters" #~ msgstr "أبقِ الملخص مختصرًا، بين 10 و 35 حرفًا" #~ msgid "Main Bazaar window showing Blender" #~ msgstr "نافذة بازار الرئيسية تعرض تطبيق بلندر" #~ msgid "Match using regular expressions" #~ msgstr "طابِق باستخدام التعابير النمطية" #~ msgid "Hide filtering and sorting behind a crossfade effect" #~ msgstr "أخفِ الترشيح والفرز خلف تأثير التلاشي المتداخل" bazaar-orig-v0.7.14/po/.gitignore0000664000175000017500000000001215166123241015537 0ustar hasanhasanbazaar.potbazaar-orig-v0.7.14/po/pl.po0000664000175000017500000032523315166123241014541 0ustar hasanhasan# SPDX-FileCopyrightText: 2025 Polish translations for bazaar package # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # # SPDX-FileCopyrightText: 2025, 2026 Microwave msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-03-24 04:16+0100\n" "PO-Revision-Date: 2026-03-28 08:18+0100\n" "Last-Translator: Marcel Mrówka \n" "Language-Team: Polish <>\n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 |" "| n%100>=20) ? 1 : 2);\n" "X-Generator: Lokalize 25.12.2\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:46 #: src/bz-window.c:377 src/bz-window.c:378 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "Zarządzaj oprogramowaniem flatpak na tym komputerze" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "" "GTK;System;PackageManager;Discover;Flatpak;Software;Store;Marketplace;Zarządza" "nieOprogramowaniem;Odkryj;Odkrywaj;Odkrywca;Oprogramowanie;Sklep;Bazar;Sklepza" "plikacjami;AppStore;Play;Aplikacja;Aplikacje;Rynek;Targ;Bazar;Giełda;Apki;Apka" ";Program;Pobieranie;Pobierz;Instalowanie;Instaluj;Instalacja;" #: data/io.github.kolunmi.Bazaar.desktop.in:16 msgid "New Window" msgstr "Nowe okno" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and manage applications" msgstr "Odkrywaj i zarządzaj aplikacjami" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A fast and modern app store for Linux with a focus on discovering and " "installing Flatpak apps and addons, particularly from Flathub." msgstr "" "Nowoczesny, szybki sklep z aplikacjami na Linuxa z naciskiem na odkrywanie " "oraz instalowanie aplikacji i dodatków z repozytoriów flatpak, głównie z " "Flathuba" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:15 msgid "Queue multiple installs and keep browsing" msgstr "Ustawiaj w kolejce kilka instalacji i nadal przeglądaj" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:16 msgid "Easily view app permissions" msgstr "Łatwo przeglądaj uprawnienia aplikacji" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:17 msgid "Sign in to Flathub to view and manage your favorites" msgstr "Zaloguj się do konta Flathub, aby zarządzać ulubionymi" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:18 msgid "Search apps directly from GNOME Shell" msgstr "Wyszukuj aplikacje prościutko z GNOME Shell" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:30 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:55 msgid "The home page displaying Flathub apps" msgstr "Widok domowy pokazujący aplikacje z Flathuba" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:59 msgid "Exhibit app page" msgstr "Strona aplikacji Exhibit" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:63 msgid "Library page" msgstr "Strona biblioteki" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:67 msgid "Search page" msgstr "Strona wyszukiwania" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:71 msgid "Category page" msgstr "Strona kategorii" #: src/bz-addons-dialog.blp:16 src/bz-full-view.blp:627 #: src/bz-installed-tile.blp:101 msgid "Manage Add-Ons" msgstr "Zarządzaj dodatkami" #: src/bz-addons-dialog.c:94 src/bz-install-controls.blp:137 #: src/bz-installed-tile.blp:114 msgid "Remove" msgstr "Usuń" #: src/bz-addons-dialog.c:99 src/bz-favorites-tile.c:159 msgid "Install" msgstr "Zainstaluj" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 #: src/bz-age-rating-dialog.c:736 src/bz-full-view.c:333 src/bz-full-view.c:340 msgid "Age Rating" msgstr "Próg wiekowy" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "Kreskówkowa przemoc" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "Brak informacji o występowaniu kreskówkowej przemocy" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "Fantastyczna przemoc" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "Brak informacji o występowaniu fantastycznej przemocy" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "Realistyczna przemoc" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "Brak informacji o występowaniu realistycznej przemocy" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "Przemoc z ukazaniem krwawienia" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "Brak informacji o występowaniu przemocy z krwawieniem" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "Przemoc seksualna" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "Brak informacji o występowaniu przemocy seksualnej" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "Alkohol" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "Brak informacji o występowaniu odniesień do alkoholu" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "Narkotyki" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "Brak informacji o występowaniu odniesień do narkotyków" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "Tytoń" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "Brak informacji o występowaniu odniesień do tytoniu" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "Nagość" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "Brak informacji o występowaniu nagości" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "Motywy seksualne" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "" "Brak informacji o występowaniu odniesień lub przedstawień natury seksualnej" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "Wulgaryzmy" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "Brak informacji o występowaniu wulgaryzmów" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "Nieodpowiedni humor" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "Brak informacji o występowaniu nieodpowiedniego humoru" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "Dyskryminacja" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "Brak informacji o występowaniu dyskryminacji" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "Reklamy" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "Brak informacji o występowaniu reklam" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "Hazard" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "Brak informacji o występowaniu hazardu" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "Zakupy" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "Brak informacji o możliwości robienia zakupów" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "Rozmowy między użytkownikami" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "Brak informacji o możliwości rozmawiania z innymi użytkownikami" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "Rozmowy głosowe między użytkownikami" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "" "Brak informacji o możliwości prowadzenia rozmów głosowych z innymi " "użytkownikami" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 msgid "Contact Details" msgstr "Przekazywanie informacji kontaktowych" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "" "Brak informacji o przekazywaniu nazw użytkowników na portalach " "społecznościowych, czy też adresów e-mail" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "Przekazywanie danych osobowych" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "" "Brak informacji o wysyłaniu osobom trzecim danych osobowych użytkowników" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "Udostępnianie lokalizacji" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "Brak informacji o udostępnianiu lokalizacji użytkownika z innymi" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "Prostytucja" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "Brak informacji o występowaniu odniesień do prostytucji" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "Cudzołóstwo" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "Brak informacji o występowaniu odniesień do cudzołóstwa" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "Seksualizowanie postacie" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "Brak informacji o występowaniu seksualizowanych postaci" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 msgid "Desecration" msgstr "Profanacja" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "Brak informacji o występowaniu odniesień do profanacji" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "Zwłoki" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "Brak informacji o występowaniu zwłok" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "Niewolnictwo" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "Brak informacji o występowaniu odniesień do niewolnictwa" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "Nie zawiera odniesień do narkotyków" #: src/bz-age-rating-dialog.c:426 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "Nie zawiera przekleństw, profanacji i innych rodzajów mocnego języka" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "Nie zawiera reklam i możliwości wykonywania zakupów" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "Nie zawiera seksu i nagości" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "Nie zawiera niekontrolowanej funkcji chatu" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "Nie zawiera przemocy" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "Używki" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "Mocny język" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "Pieniądze" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "Społeczność" #: src/bz-age-rating-dialog.c:479 msgid "Violence" msgstr "Przemoc" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:686 src/bz-full-view.c:323 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:711 msgctxt "Age rating" msgid "All" msgstr "3+" #: src/bz-age-rating-dialog.c:747 #, c-format msgid "%s has an unknown age rating" msgstr "Aplikacja %s nie posiada progu wiekowego" #: src/bz-age-rating-dialog.c:753 #, c-format msgid "%s is suitable for everyone" msgstr "Aplikacja %s jest odpowiednia dla wszystkich" #: src/bz-age-rating-dialog.c:756 #, c-format msgid "%s is suitable for young children" msgstr "Aplikacja %s jest odpowiednia dla młodszych dzieci" #: src/bz-age-rating-dialog.c:759 #, c-format msgid "%s is suitable for children" msgstr "Aplikacja %s jest odpowiednia dla dzieci" #: src/bz-age-rating-dialog.c:762 #, c-format msgid "%s is suitable for teenagers" msgstr "Aplikacja %s jest odpowiednia dla nastolatków" #: src/bz-age-rating-dialog.c:765 #, c-format msgid "%s is suitable for adults" msgstr "Aplikacja %s jest odpowiednia dla dorosłych" #: src/bz-age-rating-dialog.c:768 #, c-format msgid "%s is suitable for %s" msgstr "Aplikacja %s jest odpowiednia dla %s" #: src/bz-age-rating-dialog.c:862 #, c-format msgid "%s • %s" msgstr "%s • %s" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:29 #: src/bz-user-data-page.blp:15 src/bz-window.blp:239 msgid "Main Menu" msgstr "Menu główne" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 #: src/bz-user-data-page.blp:19 src/bz-window.blp:328 msgid "_Donate to Bazaar ❤️" msgstr "Przekaż _darowiznę ❤️" #: src/bz-all-apps-page.blp:25 src/bz-apps-page.blp:25 #: src/bz-user-data-page.blp:26 src/bz-window.blp:335 msgid "_Refresh" msgstr "_Odśwież" #: src/bz-all-apps-page.blp:30 src/bz-apps-page.blp:30 #: src/bz-user-data-page.blp:31 src/bz-window.blp:340 msgid "_Preferences" msgstr "_Preferencje" #: src/bz-all-apps-page.blp:35 src/bz-apps-page.blp:35 #: src/bz-user-data-page.blp:36 src/bz-window.blp:345 msgid "_Login With Flathub" msgstr "Za_loguj się do Flathub" #: src/bz-all-apps-page.blp:41 src/bz-apps-page.blp:41 #: src/bz-user-data-page.blp:42 src/bz-window.blp:351 msgid "_Manage Leftover User Data" msgstr "Zarządzaj pozostały_mi danymi" #: src/bz-all-apps-page.blp:46 src/bz-apps-page.blp:46 #: src/bz-user-data-page.blp:47 src/bz-window.blp:356 msgid "_Keyboard Shortcuts" msgstr "Skróty _klawiszowe" #: src/bz-all-apps-page.blp:51 src/bz-apps-page.blp:51 #: src/bz-user-data-page.blp:52 src/bz-window.blp:361 msgid "_About Bazaar" msgstr "O _aplikacji Bazaar" #: src/bz-all-apps-page.blp:58 src/bz-apps-page.blp:58 #: src/bz-user-data-page.blp:59 src/bz-window.blp:368 msgid "_Quit Bazaar" msgstr "_Zamknij Bazaar" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "Folder systemowy %s" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "Podfolder katalogu domowego %s" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "Foldery systemu hostowego" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "Konfiguracja systemu hostowego z /etc" #: src/bz-app-permissions.c:169 #, c-format msgid "Desktop subfolder %s" msgstr "Podfolder pulpitu %s" #: src/bz-app-permissions.c:170 msgid "Desktop folder" msgstr "Folder pulpitu" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "Podfolder dokumentów %s" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "Folder dokumentów" #: src/bz-app-permissions.c:177 #, c-format msgid "Music subfolder %s" msgstr "Podfolder muzyki %s" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "Folder muzyki" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "Podfolder obrazów %s" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "Folder obrazów" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "Podfolder publicznego udostępniania %s" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "Folder publicznego udostępniania" #: src/bz-app-permissions.c:189 #, c-format msgid "Videos subfolder %s" msgstr "Podfolder filmów %s" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "Folder filmów" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "Podfolder szablonów %s" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "Folder szablonów" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "Podfolder pamięci podręcznej użytkownika %s" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "Folder pamięci podręcznej" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "Podfolder konfiguracji użytkownika %s" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "Folder konfiguracji użytkownika" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "Podfolder danych użytkownika %s" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "Folder danych użytkownika" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "Podfolder bibliotek użytkownika %s" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "Folder bibliotek użytkownika" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "Dostęp systemu plików do %s" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "Nieznana ścieżka systemu plików" #: src/bz-app-size-dialog.blp:29 src/bz-app-size-dialog.blp:55 msgid "Download Size" msgstr "Rozmiar do pobrania" #: src/bz-app-size-dialog.blp:56 msgid "Amount to download from the internet" msgstr "Ilość do pobrania z internetu" #: src/bz-app-size-dialog.blp:76 msgid "Installed Size" msgstr "Rozmiar po instalacji" #: src/bz-app-size-dialog.blp:77 msgid "Size on Disk" msgstr "Rozmiar na dysku" #: src/bz-app-size-dialog.blp:125 msgid "Open user data folder" msgstr "Otwórz folder danych użytkownika" #: src/bz-app-size-dialog.blp:135 msgid "User Data Size" msgstr "Rozmiar danych użytkownika" #: src/bz-app-size-dialog.blp:136 msgid "Caches, settings, and other app data" msgstr "Pamięć podręczna, ustawienia i inne dane aplikacji" #: src/bz-app-size-dialog.c:99 msgid "Installed Runtime Size" msgstr "Rozmiar bibliotek po instalacji" #: src/bz-app-size-dialog.c:99 msgid "Runtime Download Size" msgstr "Rozmiar bibliotek do pobrania" #: src/bz-app-tile.blp:57 src/bz-developer-badge.c:98 #: src/bz-rich-app-tile.blp:104 src/bz-rich-app-tile.c:304 msgid "Verified" msgstr "Zweryfikowane" #. Translators: As in 'The app is installed'. #: src/bz-app-tile.blp:88 src/bz-full-view.c:282 src/bz-releases-list.c:205 msgid "Installed" msgstr "Zainstalowane" #: src/bz-apps-page.blp:142 msgid "Show All" msgstr "Pokaż wszystkie" #: src/bz-apps-page.c:229 #, c-format msgid "All \"%s\"" msgstr "Wszystkie aplikacje dot. \"%s\"" #: src/bz-apps-page.c:478 src/bz-tag-list.c:91 #, c-format msgid "%d Applications" msgstr "%d aplikacji" #: src/bz-application.c:695 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:696 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #: src/bz-application.c:716 msgid "The Bazaar Contributors" msgstr "Kontrybutorzy Bazaaru" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:719 msgid "translator-credits" msgstr "Marcel Mrówka (Microwave) , 2025, 2026" #: src/bz-application.c:729 msgid "Special Thanks" msgstr "Specjalne podziękowania" #: src/bz-application.c:787 msgid "Logged Out Successfully!" msgstr "Wylogowano pomyślnie!" #: src/bz-application.c:910 msgid "Performing setup…" msgstr "Konfigurowanie…" #: src/bz-application.c:994 msgid "Set Up System Flathub?" msgstr "Skonfigurować Flathub systemowo?" #: src/bz-application.c:997 msgid "" "The system Flathub remote is not set up. Bazaar requires Flathub to be " "configured on the system Flatpak installation to browse and install " "applications.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Repozytorium Flathuba na poziomie systemu nie jest skonfigurowane. Bazaar " "wymaga Flathuba skonfigurowanego na systemowej instalacji Flatpaka, aby móc " "przeglądać oraz instalować aplikacje.\n" "\n" "Nadal możesz używać Bazaaru do przeglądania i usuwania już zainstalowanych " "aplikacji." #: src/bz-application.c:1004 msgid "Set Up Flathub?" msgstr "Skonfigurować Flathub?" #: src/bz-application.c:1007 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub nie jest skonfigurowany na tym urządzeniu. Nie będziesz mógł " "przeglądać i instalować aplikacji w Bazaarze, jeśli jest niedostępny.\n" "\n" "Nadal możesz używać Bazaaru do przeglądania i usuwania już zainstalowanych " "aplikacji." #: src/bz-application.c:1013 msgid "Later" msgstr "Później" #: src/bz-application.c:1014 msgid "Set Up Flathub" msgstr "Skonfiguruj Flathub" #: src/bz-application.c:1303 msgid "A backend error occurred" msgstr "Wystąpił błąd w backendzie" #: src/bz-application.c:1499 src/bz-application.c:3357 src/bz-window.blp:70 msgid "Refreshing…" msgstr "Odświeżanie…" #: src/bz-application.c:1651 src/bz-application.c:3355 #, c-format msgid "Loading %d apps…" msgstr "Ładowanie %d aplikacji…" #: src/bz-application.c:1654 msgid "Checking for updates…" msgstr "Sprawdzanie dostępności aktualizacji…" #: src/bz-application.c:1717 msgid "Failed to open .flatpakref" msgstr "Otwieranie pliku .flatpakref nie powiodło się" #: src/bz-application.c:1773 msgid "An initialization error occurred" msgstr "Wystąpił błąd inicjalizacji" #: src/bz-application.c:2123 msgid "Failed to check for updates" msgstr "Sprawdzanie dostępności aktualizacji nie powiodło się" #: src/bz-application.c:3128 msgid "Could not find app" msgstr "Nie można znaleźć aplikacji" #: src/bz-application.c:3359 msgid "Writing to cache…" msgstr "Zapisywanie do pamięci podręcznej…" #: src/bz-appstream-parser.c:302 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Strona Flathub" #: src/bz-appstream-parser.c:323 msgctxt "Project URL Type" msgid "Project Website" msgstr "Strona projektu" #: src/bz-appstream-parser.c:327 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Issue Tracker" #: src/bz-appstream-parser.c:331 msgctxt "Project URL Type" msgid "FAQ" msgstr "FAQ" #: src/bz-appstream-parser.c:335 msgctxt "Project URL Type" msgid "Help" msgstr "Pomoc" #: src/bz-appstream-parser.c:339 msgctxt "Project URL Type" msgid "Donate" msgstr "Przekaż darowiznę" #: src/bz-appstream-parser.c:345 msgctxt "Project URL Type" msgid "Translate" msgstr "Tłumacz" #: src/bz-appstream-parser.c:349 msgctxt "Project URL Type" msgid "Contact" msgstr "Skontaktuj się" #: src/bz-appstream-parser.c:353 msgctxt "Project URL Type" msgid "Source Code" msgstr "Kod źródłowy" #: src/bz-appstream-parser.c:359 msgctxt "Project URL Type" msgid "Contribute" msgstr "Miej wkład" #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:68 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:62 #: src/bz-library-page.blp:65 src/bz-user-data-page.blp:86 msgid "Empty" msgstr "Puste" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "Brak polecanych" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "Plik konfiguracji polecanych nie jest dostępny na tym systemie. Możesz nadal " "przeglądać aplikacje na Flathubie." #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "Przeglądaj Flathub'a" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "Offline" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 #: src/bz-search-pill-list.c:67 msgid "Browser" msgstr "Przeglądarka" #: src/bz-developer-badge.c:94 src/bz-developer-badge.c:98 msgid "Not Verified" msgstr "Nie zweryfikowane" #: src/bz-developer-badge.c:145 msgid "Developer information not available." msgstr "Informacja o twórcy jest nie dostępna" #: src/bz-developer-badge.c:151 src/bz-developer-badge.c:165 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "" "Własność identyfikatora aplikacji %s nie została zweryfikowana i może być " "pakietem zbudowanym przez społeczność." #: src/bz-developer-badge.c:169 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "" "Własność identyfikatora aplikacji %s została zweryfikowana ręcznie przez " "zespół Flathub" #: src/bz-developer-badge.c:175 #, c-format msgid "" "The ownership of the %1$s app ID has been verified by %2$s on " "%3$s." msgstr "" "Własność identyfikatora aplikacji %1$s została zweryfikowana przez %2$s na %s." #: src/bz-developer-badge.c:182 #, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "" "Własność identyfikatora aplikacji %1$s została zweryfikowana przy użyciu " "%2$s." #: src/bz-developer-badge.c:186 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "Własność identyfikatora aplikacji %s została zweryfikowana." #: src/bz-donations-dialog.blp:74 msgid "Full Release Notes" msgstr "Pełne notatki o wydaniu" #: src/bz-donations-dialog.blp:108 msgid "This release was made possible by users like you!" msgstr "To wydanie było możliwe dzięki użytkownikom takim jak ty!" #: src/bz-donations-dialog.blp:116 msgid "" "I love making Bazaar, but I cannot do it alone. Help support further " "development by donating on Ko-Fi." msgstr "" "Kocham tworzyć Bazaar, lecz nie mogę robić tego bez niczyjej pomocy. Wspomóż " "dalszy rozwój aplikacji, przekazując darowiznę na Ko-Fi." #: src/bz-donations-dialog.blp:131 msgid "Donate to Bazaar" msgstr "Wesprzyj Bazaar" #. Translators: the %s format specifier will be something along the lines of "0.7.6" etc #: src/bz-donations-dialog.c:227 #, c-format msgid "What's New in %s?" msgstr "Co nowego w wersji %s?" #. Translators: this is a release date label, like "Released February 9, 2026" #: src/bz-donations-dialog.c:243 msgid "Released %B %-e, %Y" msgstr "Wydano %-e %B, %Y" #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "Wybierz instalację" #: src/bz-entry-group-util.c:76 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "" "Masz zainstalowanych kilka wersji tej aplikacji. Z którą chciałbyś " "kontynuować?" #: src/bz-entry-group-util.c:80 msgid "Cancel" msgstr "Anuluj" #: src/bz-entry-selection-row.blp:17 msgid "For This User Only" msgstr "Tylko dla tego użytkownika" #: src/bz-entry-selection-row.c:112 msgid "this user" msgstr "ten użytkownik" #: src/bz-entry-selection-row.c:112 msgid "all users" msgstr "wszyscy użytkownicy" #: src/bz-error.c:69 src/bz-error.c:88 src/bz-error-dialog.blp:36 #: src/bz-safety-dialog.blp:50 msgid "Details" msgstr "Szczegóły" #: src/bz-error-dialog.blp:47 msgid "Copy" msgstr "Kopiuj" #: src/bz-error-dialog.c:56 src/bz-share-list.c:64 msgid "Copied!" msgstr "Skopiowano!" #: src/bz-favorite-button.c:388 msgid "Failed to update favorite" msgstr "Aktualizacja polubienia się nie powiodła" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "Zaloguj się do konta Flathub, aby zarządzać ulubionymi" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "Zaloguj" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "Liczba polubień" #: src/bz-favorites-tile.c:157 src/bz-rich-app-tile.blp:172 msgid "Uninstall" msgstr "Odinstaluj" #: src/bz-favorites-tile.c:357 msgid "Failed to remove favorite" msgstr "Usunięcie z ulubionych się nie powiodło" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:78 msgid "Support This Application" msgstr "Wesprzyj tą aplikację" #: src/bz-favorites-tile.blp:119 msgid "Remove From Favorites" msgstr "Usuń z ulubionych" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:78 #: src/bz-window.blp:386 msgid "Favorites" msgstr "Ulubione" #: src/bz-favorites-page.blp:17 src/bz-section-view.blp:144 msgid "Install All" msgstr "Zainstaluj wszystkie" #: src/bz-favorites-page.blp:34 src/bz-full-view.blp:45 src/bz-window.blp:255 msgid "Open App Library" msgstr "Otwórz bibliotekę aplikacji" #: src/bz-favorites-page.blp:56 src/bz-user-data-page.blp:75 msgid "Loading" msgstr "Ładowanie" #: src/bz-favorites-page.blp:71 msgid "No Favorites" msgstr "Brak ulubionych" #: src/bz-favorites-page.blp:72 msgid "Applications you mark as favorite will appear here" msgstr "Aplikacje, które oznaczysz jako ulubione będą się tutaj ukazywać" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "Wstecz" #: src/bz-featured-carousel.blp:54 msgid "Next" msgstr "Dalej" #: src/bz-featured-tile.blp:90 msgid "App of the Day" msgstr "Aplikacja dnia" #: src/bz-flathub-category.c:89 msgid "Editing" msgstr "Edytowanie" #: src/bz-flathub-category.c:90 msgid "Midi" msgstr "Midi" #: src/bz-flathub-category.c:91 msgid "Mixer" msgstr "Mikser" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-flathub-category.c:92 src/bz-search-pill-list.c:77 msgid "Music" msgstr "Muzyka" #: src/bz-flathub-category.c:93 msgid "Player" msgstr "Gracz" #: src/bz-flathub-category.c:94 msgid "Recorder" msgstr "Nagrywarka" #: src/bz-flathub-category.c:95 msgid "Sequencer" msgstr "Sekwencer" #: src/bz-flathub-category.c:96 msgid "Tuner" msgstr "Tuner" #: src/bz-flathub-category.c:97 msgid "TV" msgstr "Telewizja" #: src/bz-flathub-category.c:102 msgid "Emulation" msgstr "Emulacja" #: src/bz-flathub-category.c:103 msgid "Action" msgstr "Akcja" #: src/bz-flathub-category.c:104 msgid "Adventure" msgstr "Przygoda" #: src/bz-flathub-category.c:105 msgid "Arcade" msgstr "Automatowe" #: src/bz-flathub-category.c:106 msgid "Blocks" msgstr "Klocki" #: src/bz-flathub-category.c:107 msgid "Board" msgstr "Planszówki" #: src/bz-flathub-category.c:108 msgid "Card" msgstr "Karciane" #: src/bz-flathub-category.c:109 msgid "Kids" msgstr "Dla dzieci" #: src/bz-flathub-category.c:110 msgid "Logic" msgstr "Logiczne" #: src/bz-flathub-category.c:111 msgid "Role Playing" msgstr "RPG" #: src/bz-flathub-category.c:112 msgid "Shooter" msgstr "Strzelanki" #: src/bz-flathub-category.c:113 msgid "Simulation" msgstr "Symulacja" #: src/bz-flathub-category.c:114 msgid "Sports" msgstr "Sporty" #: src/bz-flathub-category.c:115 msgid "Strategy" msgstr "Strategiczne" #: src/bz-flathub-category.c:120 msgid "Audio & Video" msgstr "Audio i wideo" #: src/bz-flathub-category.c:120 msgid "Media" msgstr "Multimedia" #: src/bz-flathub-category.c:120 msgid "More Audio & Video" msgstr "Więcej aplikacji multimedialnych" #: src/bz-flathub-category.c:121 msgid "Developer Tools" msgstr "Narzędzia programistyczne" #: src/bz-flathub-category.c:121 msgid "Develop" msgstr "Programowanie" #: src/bz-flathub-category.c:121 msgid "More Developer Tools" msgstr "Więcej narzędzi programistycznych" #: src/bz-flathub-category.c:122 msgid "Education" msgstr "Edukacja" #: src/bz-flathub-category.c:122 msgid "Learn" msgstr "Ucz się" #: src/bz-flathub-category.c:122 msgid "More Education" msgstr "Więcej aplikacji dot. edukacji" #: src/bz-flathub-category.c:123 msgid "Gaming" msgstr "Gry" #: src/bz-flathub-category.c:123 msgid "Play" msgstr "Graj" #: src/bz-flathub-category.c:123 msgid "More Gaming" msgstr "Więcej gier" #: src/bz-flathub-category.c:124 msgid "Graphics & Photography" msgstr "Grafika i fotografia" #: src/bz-flathub-category.c:124 msgid "Create" msgstr "Twórz" #: src/bz-flathub-category.c:124 msgid "More Graphics & Photography" msgstr "Więcej aplikacji dot. grafiki i fotografii" #: src/bz-flathub-category.c:125 msgid "Networking" msgstr "Narzędzia sieciowe" #: src/bz-flathub-category.c:125 msgid "Internet" msgstr "Internet" #: src/bz-flathub-category.c:125 msgid "More Networking" msgstr "Więcej narzędzi sieciowych" #: src/bz-flathub-category.c:126 msgid "Productivity" msgstr "Produktywność" #: src/bz-flathub-category.c:126 msgid "Work" msgstr "Pracuj" #: src/bz-flathub-category.c:126 msgid "More Productivity" msgstr "Więcej aplikacji dot. produktywności" #: src/bz-flathub-category.c:127 msgid "Science" msgstr "Nauka" #: src/bz-flathub-category.c:127 msgid "More Science" msgstr "Więcej aplikacji dot. nauki" #: src/bz-flathub-category.c:128 msgid "System" msgstr "System" #: src/bz-flathub-category.c:128 msgid "More System" msgstr "Więcej aplikacji dot. systemu" #: src/bz-flathub-category.c:129 msgid "Utilities" msgstr "Narzędzia" #: src/bz-flathub-category.c:129 msgid "Tools" msgstr "Narzędzia" #: src/bz-flathub-category.c:129 msgid "More Utilities" msgstr "Więcej narzędzi" #: src/bz-flathub-category.c:130 src/bz-flathub-page.blp:119 #: src/bz-flathub-page.blp:152 msgid "Trending" msgstr "Trendujące" #: src/bz-flathub-category.c:130 msgid "More Trending" msgstr "Więcej trendujących" #: src/bz-flathub-category.c:131 src/bz-flathub-page.blp:125 #: src/bz-flathub-page.blp:182 msgid "Popular" msgstr "Popularne" #: src/bz-flathub-category.c:131 msgid "More Popular" msgstr "Więcej popularnych" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:172 msgid "Recently Added" msgstr "Niedawno dodane" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:131 msgid "New" msgstr "Nowe" #: src/bz-flathub-category.c:132 msgid "More New" msgstr "Więcej nowych" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:162 msgid "Recently Updated" msgstr "Niedawno zaktualizowane" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:137 msgid "Updated" msgstr "Zaktualizowane" #: src/bz-flathub-category.c:133 msgid "More Updated" msgstr "Więcej zaktualizowanych" #: src/bz-flathub-category.c:134 msgid "Mobile" msgstr "Mobilne" #: src/bz-flathub-category.c:134 msgid "More Mobile" msgstr "Więcej mobilnych" #: src/bz-flathub-category.c:135 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:135 msgid "More Adwaita" msgstr "Więcej aplikacji Adwaita" #: src/bz-flathub-category.c:136 msgid "KDE Apps" msgstr "Od KDE" #: src/bz-flathub-category.c:136 msgid "More KDE Apps" msgstr "Więcej aplikacji od KDE" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Flathub nie został dodany" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "Nie znaleziono Flathuba na żadnej z twoich instalacji flatpaka." #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "Flathub zwrócił błąd" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "Spróbuj ponownie połączyć się z Flathub" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Flathub jest niedostępny" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" "Nie mogliśmy się połączyć z Flathub. Nadal możesz wyszukiwać i zarządzać " "aplikacjami." #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "Wyszukuj aplikacji" #: src/bz-flathub-page.blp:263 msgid "On the Go" msgstr "W biegu" #: src/bz-flathub-page.blp:275 msgid "Apps for your Linux phones and tablets" msgstr "Aplikacje na twoje urządzenia mobilne z Linuxem" #: src/bz-flathub-page.blp:286 src/bz-flathub-page.blp:321 msgid "More Mobile Apps" msgstr "Więcej aplikacji mobilnych" #: src/bz-flathub-page.blp:379 msgid "We​ ♥​ Games" msgstr "My ♥ gry" #: src/bz-flathub-page.blp:392 msgid "Games and apps to run your favorite titles" msgstr "Gry i aplikacje do uruchamiania twoich ulubionych pozycji" #: src/bz-flathub-page.blp:426 msgid "More Games" msgstr "Więcej gier" #: src/bz-full-view.blp:66 src/bz-library-page.blp:76 #: src/bz-library-page.blp:80 msgid "No Results" msgstr "Brak wyników" #: src/bz-full-view.blp:67 msgid "Try a different search query" msgstr "Spróbuj wyszukać coś innego" #: src/bz-full-view.blp:73 msgid "Content" msgstr "Zawartość" #: src/bz-full-view.blp:131 msgid "Installing .flatpak bundles is not yet supported" msgstr "Instalowanie pakietów .flatpak nie jest jeszcze wspierane" #: src/bz-full-view.blp:257 msgid "_Support" msgstr "We_sprzyj" #: src/bz-full-view.blp:426 msgid "Downloads/Month" msgstr "Pobrań/m-c" #: src/bz-full-view.blp:461 msgid "Stopped Receiving Core Updates" msgstr "Nie otrzymuje podstawowych aktualizacji" #: src/bz-full-view.blp:475 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "Ta aplikacja wykorzystuje bibliotekę, która już nie otrzymuje aktualizacji " "lub poprawek zabezpieczeń. Może się stać niebezpieczna." #: src/bz-full-view.blp:562 msgid "Trash Data" msgstr "Przenieś dane do kosza" #: src/bz-full-view.blp:702 msgid "Tags:" msgstr "Identyfikatory:" #: src/bz-full-view.c:215 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:222 #, c-format msgid "%.*fM" msgstr "%.*f mln" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:229 #, c-format msgid "%.*fK" msgstr "%.*f tys." #: src/bz-full-view.c:239 #, c-format msgid "%d downloads in the last month" msgstr "%'d pobrań w ciągu zeszłego miesiąca" #: src/bz-full-view.c:251 src/bz-full-view.c:592 src/bz-full-view.c:609 msgid "N/A" msgstr "Niedostępne" #: src/bz-full-view.c:279 #, c-format msgid "+%s runtime" msgstr "+%s bibliotek" #: src/bz-full-view.c:282 msgid "Download" msgstr "Rozmiar do pobrania" #: src/bz-full-view.c:302 msgid "Size information unavailable" msgstr "Informacja o rozmiarze jest nie dostępna" #: src/bz-full-view.c:305 #, c-format msgid "Download size of %s" msgstr "Rozmiar do pobrania %s" #: src/bz-full-view.c:338 msgid "All Ages" msgstr "Próg wiekowy" #: src/bz-full-view.c:350 msgid "Age rating information unavailable" msgstr "Informacja o progu wiekowym jest nie dostępna" #: src/bz-full-view.c:355 msgid "Suitable for all ages" msgstr "Odpowiednie od 3 lat" #: src/bz-full-view.c:357 #, c-format msgid "Suitable for ages %d and up" msgstr "Odpowiednie od %d lat" #: src/bz-full-view.c:390 src/bz-full-view.c:395 src/bz-full-view.c:423 #: src/bz-full-view.c:431 msgid "Unknown" msgstr "Nieznane" #: src/bz-full-view.c:400 #, c-format msgid "Free software licensed under %s" msgstr "Wolne oprogramowanie pod licencją %s" #: src/bz-full-view.c:405 msgid "Free software" msgstr "Wolne oprogramowanie" #: src/bz-full-view.c:408 msgid "Proprietary Software" msgstr "Oprogramowanie własnościowe" #: src/bz-full-view.c:411 #, c-format msgid "Special License: %s" msgstr "Licencja specjalna: %s" #: src/bz-full-view.c:428 msgid "Free" msgstr "Wolne" #: src/bz-full-view.c:434 src/bz-license-dialog.c:132 msgid "Proprietary" msgstr "Własnościowe" #: src/bz-full-view.c:436 src/bz-license-dialog.c:134 msgid "Special License" msgstr "Licencja specjalna" #: src/bz-full-view.c:456 msgid "Adaptive" msgstr "" "Na różne\n" "urządzenia" #: src/bz-full-view.c:456 msgid "Desktop Only" msgstr "" "Tylko na\n" "komputery" #: src/bz-full-view.c:462 msgid "Works on desktop, tablets, and phones" msgstr "Działa na komputerach, tabletach i telefonach" #: src/bz-full-view.c:463 msgid "May not work on mobile devices" msgstr "Może nie działać na urządzeniach mobilnych" #: src/bz-full-view.c:474 msgid "No URL" msgstr "Brak adresu URL" #: src/bz-full-view.c:492 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Ta aplikacja ma licencję FLOSS — oznacza to, że jej kod źródłowy może być " "audytowany pod kątem bezpieczeństwa." #: src/bz-full-view.c:493 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Ta aplikacja ma licencję własnościową — oznacza to, że jej kod źródłowy jest " "tworzony prywatnie i niezależne osoby trzecie nie mogą go audytować." #: src/bz-full-view.c:500 msgid "More Apps" msgstr "Więcej aplikacji" #: src/bz-full-view.c:501 #, c-format msgid "More Apps by %s" msgstr "Więcej aplikacji od %s" #: src/bz-full-view.c:508 msgid "Other Apps by this Developer" msgstr "Inne aplikacje od tego twórcy" #: src/bz-full-view.c:510 src/bz-full-view.c:693 #, c-format msgid "Other Apps by %s" msgstr "Inne aplikacje od %s" #: src/bz-full-view.c:519 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "" "Aplikacja %s nie jest zainstalowana, lecz nadal ma %s obecnych danych." #: src/bz-full-view.c:599 src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "Bezpieczna" #: src/bz-full-view.c:601 src/bz-full-view.c:603 msgid "Low Risk" msgstr "Niskie ryzyko" #: src/bz-full-view.c:605 msgid "Medium Risk" msgstr "Średnie ryzyko" #: src/bz-full-view.c:607 msgid "High Risk" msgstr "Wysokie ryzyko" #: src/bz-full-view.c:695 msgid "Other Apps" msgstr "Inne aplikacje" #: src/bz-full-view.c:697 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d aplikacja" msgstr[1] "%d aplikacje" msgstr[2] "%d aplikacji" #: src/bz-full-view.c:941 msgid "Show Less" msgstr "Pokaż mniej" #: src/bz-full-view.c:941 msgid "Show More" msgstr "Pokaż więcej" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 msgid "Hardware Support" msgstr "Wsparcie sprzętu" #: src/bz-hardware-support-dialog.c:62 msgid "Keyboard support" msgstr "Wsparcie klawiatury" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "Wymaga posiadania klawiatury" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "Zaleca posiadanie klawiatury" #: src/bz-hardware-support-dialog.c:66 msgid "Supports keyboards" msgstr "Wspiera klawiaturę" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "Wsparcie klawiatur jest nieznane" #: src/bz-hardware-support-dialog.c:69 msgid "Mouse support" msgstr "Wsparcie myszki" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "Wymaga myszki lub innego urządzenia wskazującego" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "Zaleca korzystanie z myszki lub innego urządzenia wskazującego" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "Wspiera myszki i inne urządzenia wskazujące" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "Wsparcie myszek i innych urządzeń wskazujących jest nieznane" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "Wsparcie ekranów dotykowych" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "Wymaga ekranu dotykowego" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "Zaleca korzystanie z ekranu dotykowego" #: src/bz-hardware-support-dialog.c:80 msgid "Supports touchscreens" msgstr "Wspira ekrany dotykowe" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "Wsparcie ekranów dotykowych jest nieznane" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "Wsparcie urządzeń mobilnych" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "Działa na urządzeniach mobilnych" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "Może nie działać najlepiej na urządzeniach mobilnych" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "Wsparcie komputerów" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "Doskonale działa na dużych ekranach" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "Aplikacja %s działa najlepiej na konkretnym sprzęcie" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "Aplikacja %s działa na większości urządzeń" #: src/bz-install-controls.blp:33 msgid "Download & Install Application" msgstr "Pobierz i zainstaluj aplikację" #: src/bz-install-controls.blp:35 src/bz-transaction-dialog.c:202 msgid "_Install" msgstr "Za_instaluj" #: src/bz-install-controls.blp:61 msgid "_Open" msgstr "_Otwórz" #: src/bz-install-controls.blp:76 src/bz-install-controls.blp:127 msgid "Uninstall Application" msgstr "Odinstaluj aplikację" #: src/bz-install-controls.blp:86 src/bz-transaction-dialog.c:231 msgid "_Remove" msgstr "_Usuń" #: src/bz-install-controls.blp:114 src/bz-updates-card.blp:184 #: src/bz-updates-card.blp:212 msgid "Update" msgstr "Aktualizuj" #: src/bz-installed-tile.blp:64 src/bz-rich-app-tile.blp:140 msgid "Stopped Receiving Updates" msgstr "Zatrzymano otrzymywanie wystąpień" #: src/bz-library-page.blp:31 msgid "Search installed apps" msgstr "Wyszukuj zainstalowanych aplikacji" #: src/bz-library-page.blp:48 msgid "Clear search" msgstr "Wyczyść wyszukiwanie" #: src/bz-library-page.blp:69 msgid "No Apps Found" msgstr "Nie znaleziono aplikacji" #. Translators: . #: src/bz-library-page.blp:98 src/bz-window.blp:112 msgid "Library" msgstr "Biblioteka" #: src/bz-library-page.blp:126 msgid "Pending Updates" msgstr "Aktualizacje w toku" #: src/bz-library-page.blp:153 msgid "Downloads" msgstr "Pobrania" #: src/bz-library-page.blp:196 msgid "Recently Uninstalled" msgstr "Niedawno odinstalowane" #: src/bz-library-page.blp:247 msgid "Clear Finished Tasks" msgstr "Wyczyść zakończone zadania" #: src/bz-library-page.blp:260 msgid "Installed Apps" msgstr "Zainstalowane aplikacje" #: src/bz-library-page.blp:333 msgid "Sort By" msgstr "Sortuj wg" #: src/bz-library-page.blp:347 msgid "Name" msgstr "Nazwa" #: src/bz-library-page.blp:353 msgid "Size" msgstr "Rozmiar" #: src/bz-library-page.c:180 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "Brak wyników dla \"%s\" na liście zainstalowanych aplikacji" #: src/bz-library-page.c:193 src/bz-updates-card.c:257 #, c-format msgid "%u Available Update" msgid_plural "%u Available Updates" msgstr[0] "%u aktualizacja dostępna" msgstr[1] "%u aktualizacje dostępne" msgstr[2] "%u aktualizacji dostępnych" #: src/bz-license-dialog.blp:95 msgid "Get Involved" msgstr "Miej wkład" #: src/bz-license-dialog.c:126 msgid "Unknown License" msgstr "Nieznana licencja" #: src/bz-license-dialog.c:129 msgid "Community Built" msgstr "Stworzone przez społeczność" #: src/bz-license-dialog.c:202 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Ta aplikacja jest tworzona jako wolna przez międzynarodową społeczność.\n" "\n" "Możesz mieć wkład w proces tworzenia i ulepszania jej." #: src/bz-license-dialog.c:205 msgid "The license of this app is not known" msgstr "Licencja tej aplikacji jest nieznana." #: src/bz-license-dialog.c:211 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Ta aplikacja jest tworzona jako wolna przez międzynarodową społeczność i " "jest wydawana z licencją %s.\n" "\n" "Możesz mieć wkład w ulepszaniu jej." #: src/bz-license-dialog.c:219 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Ta aplikacja nie jest tworzona jako wolna, zatem tylko jej twórcy wiedzą jak " "działa. Może być niewykrywalnie niebezpieczna, oraz zmieniać się bez " "ostrzeżenia.\n" "\n" "Nie będziesz mógł mieć wkładu w procesie tworzenia tej aplikacji." #: src/bz-license-dialog.c:225 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Ta aplikacja jest tworzona i wydawana pod licencją specjalną %s\n" "\n" "Nie wiemy, czy będziesz mógł mieć wkładu w procesie tworzenia jej." #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 msgid "Connect to Flathub" msgstr "Połącz z Flathub" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "Coś poszło nie tak" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "" "Zaloguj się swoim kontem Flathub w Bazaarze, aby zarządzać swoimi ulubionymi " "aplikacjami." #: src/bz-login-page.blp:110 msgid "Finish" msgstr "Zakończ" #: src/bz-login-page.c:664 #, c-format msgid "Hello, %s!" msgstr "Cześć, %s!" #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Preferencje" #: src/bz-preferences-dialog.blp:25 msgid "Network connection is metered — automatic store data refresh is paused" msgstr "" "Wykryto taryfowe połączenie internetowe - zatrzymano automatyczną " "synchronizację danych sklepowych" #: src/bz-preferences-dialog.blp:26 src/bz-window.blp:282 msgid "Refresh Manually" msgstr "Odśwież ręcznie" #: src/bz-preferences-dialog.blp:31 msgid "Content Filters" msgstr "Filtry zawartości" #: src/bz-preferences-dialog.blp:34 msgid "Free Software Only" msgstr "Tylko wolne oprogramowanie" #: src/bz-preferences-dialog.blp:35 msgid "Hide proprietary applications when browsing and searching" msgstr "Ukrywaj aplikacje własnościowe podczas przeglądania i wyszukiwania" #: src/bz-preferences-dialog.blp:39 msgid "Flathub Results Only" msgstr "Tylko wyniki z Flathuba" #: src/bz-preferences-dialog.blp:40 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "" "Limituj wyniki wyszukiwania i przeglądania, tak aby pokazywać tylko " "aplikacje dostępne na Flathubie" #: src/bz-preferences-dialog.blp:44 msgid "Verified Results Only" msgstr "Tylko zweryfikowane wyniki" #: src/bz-preferences-dialog.blp:45 msgid "Hide results that are not verified on Flathub" msgstr "Ukrywaj niezweryfikowane aplikacje" #: src/bz-preferences-dialog.blp:49 msgid "Hide EOL Apps" msgstr "Ukrywaj aplikacje z brakiem wsparcia" #: src/bz-preferences-dialog.blp:50 msgid "Hide apps which are no longer supported by their developers" msgstr "Ukrywaj aplikacje nie otrzymujące już aktualizacji od swoich twórców" #: src/bz-preferences-dialog.blp:55 src/bz-window.blp:127 msgid "Search" msgstr "Wyszukaj" #: src/bz-preferences-dialog.blp:58 msgid "Delay Search Results" msgstr "Opóźniaj wyniki wyszukiwania" #: src/bz-preferences-dialog.blp:59 msgid "Improve results performance by debouncing search terms" msgstr "Ulepsz wydajność wyszukiwania opóźniając wyniki" #: src/bz-preferences-dialog.blp:64 msgid "Progress Bar" msgstr "Pasek postępu" #: src/bz-preferences-dialog.blp:65 msgid "Choose a theme for the progress bar!" msgstr "Wybierz motyw paska postępu!" #: src/bz-preferences-dialog.blp:89 msgid "Vertical Stripes" msgstr "Pionowe paski" #: src/bz-preferences-dialog.blp:90 msgid "Display flag colors from left to right" msgstr "Wyświetlaj kolory flag od lewej do prawej" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Kolor akcentowy" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Kolory dumy" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "Kolory dumy lesbijek" #: src/bz-preferences-dialog.c:35 msgid "Male Homosexual Pride Colors" msgstr "Kolory dumy mężczyzn homoseksualnych" #: src/bz-preferences-dialog.c:36 msgid "Transgender Pride Colors" msgstr "Kolory dumy osób transpłciowych" #: src/bz-preferences-dialog.c:37 msgid "Nonbinary Pride Colors" msgstr "Kolory dumy osób niebinarnych" #: src/bz-preferences-dialog.c:38 msgid "Bisexual Pride Colors" msgstr "Kolory dumy osób biseksualnych" #: src/bz-preferences-dialog.c:39 msgid "Asexual Pride Colors" msgstr "Kolory dumy osób aseksualnych" #: src/bz-preferences-dialog.c:40 msgid "Pansexual Pride Colors" msgstr "Kolory dumy osób panseksualnych" #: src/bz-preferences-dialog.c:41 msgid "Aromantic Pride Colors" msgstr "Kolory dumy osób aromantycznych" #: src/bz-preferences-dialog.c:42 msgid "Genderfluid Pride Colors" msgstr "Kolory dumy osób genderfluidalnych" #: src/bz-preferences-dialog.c:43 msgid "Polysexual Pride Colors" msgstr "Kolory dumy osób polyseksualnych" #: src/bz-preferences-dialog.c:44 msgid "Omnisexual Pride Colors" msgstr "Kolory dumy osób omniseksualnych" #: src/bz-preferences-dialog.c:45 msgid "Aroace Pride Colors" msgstr "Kolory dumy osób aromantyczno-seksualnych" #: src/bz-preferences-dialog.c:46 msgid "Agender Pride Colors" msgstr "Kolory dumy osób bezpłciowych" #: src/bz-preferences-dialog.c:47 msgid "Genderqueer Pride Colors" msgstr "Kolory dumy osób genderqueerowych" #: src/bz-preferences-dialog.c:48 msgid "Intersex Pride Colors" msgstr "Kolory dumy osób interseksualnych" #: src/bz-preferences-dialog.c:49 msgid "Demigender Pride Colors" msgstr "Kolory dumy osób półpłciowych" #: src/bz-preferences-dialog.c:50 msgid "Biromantic Pride Colors" msgstr "Kolory dumy osób biomantycznych" #: src/bz-preferences-dialog.c:51 msgid "Disability Pride Colors" msgstr "Kolory dumy osób niepełnosprawnych" #: src/bz-preferences-dialog.c:52 msgid "Femboy Pride Colors" msgstr "Kolory dumy fembojów" #: src/bz-preferences-dialog.c:53 msgid "Neutrois Pride Colors" msgstr "Kolory dumy osób neutroidalnych" #: src/bz-releases-dialog.blp:5 src/bz-updates-card.blp:171 msgid "Version History" msgstr "Historia wersji" #: src/bz-releases-list.blp:27 msgid "_Version History" msgstr "Historia _wersji" #. Translators: something happened less than a day ago #: src/bz-releases-list.c:122 msgid "Today" msgstr "Dzisiaj" #. Translators: something happened more than a day ago but less than 2 days ago #: src/bz-releases-list.c:125 msgid "Yesterday" msgstr "Wczoraj" #. Translators: something happened days ago #: src/bz-releases-list.c:128 #, c-format msgid "%d day ago" msgid_plural "%d days ago" msgstr[0] "%d dzień temu" msgstr[1] "%d dni temu" msgstr[2] "%d dni temu" #. Translators: something happened weeks ago #: src/bz-releases-list.c:131 #, c-format msgid "%d week ago" msgid_plural "%d weeks ago" msgstr[0] "%d tydzień temu" msgstr[1] "%d tygodnie temu" msgstr[2] "%d tygodni temu" #. Translators: something happened months ago #: src/bz-releases-list.c:134 #, c-format msgid "%d month ago" msgid_plural "%d months ago" msgstr[0] "%d miesiąc temu" msgstr[1] "%d miesiące temu" msgstr[2] "%d miesięcy temu" #. Translators: something happened years ago #: src/bz-releases-list.c:137 #, c-format msgid "%d year ago" msgid_plural "%d years ago" msgstr[0] "%d rok temu" msgstr[1] "%d lata temu" msgstr[2] "%d lat temu" #. TRANSLATORS: This is the date string with: day number, month name, year. #. i.e. "22 March 2026" #: src/bz-releases-list.c:155 msgid "%e %B %Y" msgstr "%e %B %Y" #: src/bz-releases-list.c:195 #, c-format msgid "Version %s" msgstr "Wersja %s" #: src/bz-releases-list.c:250 msgid "No details for this release" msgstr "Brak szczegółów dla tego wydania" #: src/bz-releases-list.c:262 msgid "Get More Information" msgstr "Dowiedz się więcej" #: src/bz-rich-app-tile.blp:157 msgid "Get" msgstr "Pobierz" #: src/bz-rich-app-tile.blp:185 src/bz-transaction-tile.blp:272 msgid "Open" msgstr "Otwórz" #: src/bz-safety-calculator.c:82 msgid "Unknown Permissions" msgstr "Nieznane uprawnienia" #: src/bz-safety-calculator.c:83 msgid "Permissions are missing for this app." msgstr "Brakuje uprawnień tej aplikacji." #: src/bz-safety-calculator.c:96 msgid "No Permissions" msgstr "Brak uprawnień" #: src/bz-safety-calculator.c:97 msgid "App is fully sandboxed" msgstr "Aplikacja jest w pełni uruchamiana w środowisku piaskownicy" #: src/bz-safety-calculator.c:103 msgid "Network Access" msgstr "Dostęp do sieci" #: src/bz-safety-calculator.c:104 msgid "Can access the internet" msgstr "Ma dostęp do internetu" #: src/bz-safety-calculator.c:106 msgid "No Network Access" msgstr "Nie potrzebuje internetu" #: src/bz-safety-calculator.c:107 msgid "Cannot access the internet" msgstr "Nie ma dostępu do internetu" #: src/bz-safety-calculator.c:112 msgid "User Device Access" msgstr "Dostęp do urządzeń użytkownika" #: src/bz-safety-calculator.c:113 msgid "Can access devices such as webcams or gaming controllers" msgstr "" "Może uzyskać dostęp do urządzeń takich jak kamerki internetowe i kontrolery " "do gier" #: src/bz-safety-calculator.c:115 msgid "No User Device Access" msgstr "Brak dostępu do urządzeń użytkownika" #: src/bz-safety-calculator.c:116 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "" "Nie może uzyskać dostęp do urządzeń takich jak kamerki internetowe i " "kontrolery do gier" #: src/bz-safety-calculator.c:121 msgid "Input Device Access" msgstr "Dostęp do urządzeń wprowadzania" #: src/bz-safety-calculator.c:122 msgid "Can access input devices" msgstr "Ma dostęp do urządzeń wprowadzania" #: src/bz-safety-calculator.c:128 msgid "Microphone Access and Audio Playback" msgstr "Dostęp do mikrofonu i odtwarzania dźwięku" #: src/bz-safety-calculator.c:129 msgid "Can listen using microphones and play audio without asking permission" msgstr "" "Może słuchać przy użyciu mikrofonów i odtwarzać dźwięk bez proszenia o " "pozwolenie" #: src/bz-safety-calculator.c:135 msgid "System Device Access" msgstr "Dostęp do urządzeń systemowych" #: src/bz-safety-calculator.c:136 msgid "Can access system devices which require elevated permissions" msgstr "" "Może uzyskać dostęp do urządzeń systemowych, które wymagają wysokich " "uprawnień" #: src/bz-safety-calculator.c:142 msgid "Screen Contents Access" msgstr "Dostęp do zawartości ekranu" #: src/bz-safety-calculator.c:143 msgid "Can access the contents of the screen or other windows" msgstr "Ma dostęp do zawartości ekranu i innych okien" #: src/bz-safety-calculator.c:149 msgid "Legacy Windowing System" msgstr "Przestarzały system okien" #: src/bz-safety-calculator.c:150 msgid "Always uses a legacy windowing system (X11)" msgstr "Zawsze wykorzystuje przestarzały system okien (X11)" #: src/bz-safety-calculator.c:156 msgid "Arbitrary Permissions" msgstr "Samowolne uprawnienia" #: src/bz-safety-calculator.c:157 msgid "Can acquire arbitrary permissions" msgstr "Może uzyskać samowolne uprawnienia" #: src/bz-safety-calculator.c:163 msgid "User Settings" msgstr "Ustawienia użytkownika" #: src/bz-safety-calculator.c:164 msgid "Can access and change user settings" msgstr "Ma dostęp do ustawień użytkownika i może je zmieniać" #: src/bz-safety-calculator.c:170 msgid "Full File System Read/Write Access" msgstr "Pełny dostęp do systemu plików" #: src/bz-safety-calculator.c:171 msgid "Can read and write all data on the file system" msgstr "Może odczytywać i zapisywać wszystkie dane na systemie plików" #: src/bz-safety-calculator.c:178 msgid "Home Folder Read/Write Access" msgstr "Dostęp do katalogu domowego" #: src/bz-safety-calculator.c:179 msgid "Can read and write all data in your home directory" msgstr "Może odczytywać i zapisywać wszystkie dane w twoim katalogu domowym" #: src/bz-safety-calculator.c:186 msgid "Full File System Read Access" msgstr "Pełny dostęp do odczytu systemu plików" #: src/bz-safety-calculator.c:187 msgid "Can read all data on the file system" msgstr "Może odczytywać wszystkie dane na systemie plików" #: src/bz-safety-calculator.c:195 msgid "Home Folder Read Access" msgstr "Dostęp do odczytu katalogu domowego" #: src/bz-safety-calculator.c:196 msgid "Can read all data in your home directory" msgstr "Może odczytywać dane w twoim katalogu domowym" #: src/bz-safety-calculator.c:204 msgid "Download Folder Read/Write Access" msgstr "Dostęp do folderu pobranych" #: src/bz-safety-calculator.c:205 msgid "Can read and write all data in your downloads directory" msgstr "Może odczytywać i zapisywać wszystkie dane w twoim folderze pobranych" #: src/bz-safety-calculator.c:215 msgid "Download Folder Read Access" msgstr "Dostęp do odczytu folderu pobranych" #: src/bz-safety-calculator.c:216 msgid "Can read all data in your downloads directory" msgstr "Może odczytywać dane w twoim folderze pobranych" #: src/bz-safety-calculator.c:229 msgid "Can read and write all data in the directory" msgstr "Może odczytywać i zapisywać wszystkie dane w katalogu" #: src/bz-safety-calculator.c:243 msgid "Can read all data in the directory" msgstr "Może odczytywać wszystkie dane w katalogu" #: src/bz-safety-calculator.c:258 msgid "No File System Access" msgstr "Brak dostępu do systemu plików" #: src/bz-safety-calculator.c:259 msgid "Cannot access the file system at all" msgstr "Absolutnie nie ma dostępu do systemu plików" #: src/bz-safety-calculator.c:266 msgid "Uses System Services" msgstr "Wykorzystuje usługi systemowe" #: src/bz-safety-calculator.c:267 msgid "Can request data from non-portal system services" msgstr "Może prosić o dane z poza-portalowych usług systemowych" #: src/bz-safety-calculator.c:273 msgid "Uses Session Services" msgstr "Usługi sesji użytkownika" #: src/bz-safety-calculator.c:274 msgid "Can request data from non-portal session services" msgstr "Może prosić o dane z poza-portalowych usług" #: src/bz-safety-calculator.c:322 msgid "No Service Access" msgstr "Brak dostępu do usług" #: src/bz-safety-calculator.c:323 msgid "Cannot access non-portal session or system services at all" msgstr "Absolutnie nie ma dostępu do usług systemowych, ani sesji" #: src/bz-safety-calculator.c:331 msgid "Verified App Developer" msgstr "Zweryfikowany twórca aplikacji" #: src/bz-safety-calculator.c:332 msgid "The developer of this app has been verified to be who they say they are" msgstr "" "Twórca tej aplikacji został zweryfikowany pod względem czy są kim za kogo " "się uważają" #: src/bz-safety-calculator.c:341 msgid "Proprietary Code" msgstr "Własnościowy kod" #: src/bz-safety-calculator.c:342 msgid "" "The source code is not public, so it cannot be independently audited and " "might be unsafe" msgstr "" "Kod źródłowy nie jest publiczny, więc nie może być niezależnie audytowany, " "co sprawia, że aplikacja może być niebezpieczna" #: src/bz-safety-calculator.c:352 msgid "Auditable Code" msgstr "Audytowalny" #: src/bz-safety-calculator.c:353 msgid "" "The source code is public and can be independently audited, which makes the " "app more likely to be safe" msgstr "" "Kod źródłowy jest publiczny i może być niezależnie audytowany, co sprawia, " "że aplikacja jest raczej bardziej bezpieczna" #: src/bz-safety-calculator.c:493 #, c-format msgid "Use the %s System Service" msgstr "Korzysta z usługi systemowej %s" #: src/bz-safety-calculator.c:497 #, c-format msgid "Use the %s Session Service" msgstr "Korzysta z usługi sesji %s" #: src/bz-safety-calculator.c:501 #, c-format msgid "Use the %s Service" msgstr "Korzysta z usługi %s" #: src/bz-safety-calculator.c:511 msgid "Can see the non-portal service" msgstr "Może widzieć poza-portalowe usługi" #: src/bz-safety-calculator.c:513 msgid "Can talk to the non-portal service" msgstr "Może rozmawiać z poza-portalowymi usługami" #: src/bz-safety-calculator.c:515 msgid "Can own the non-portal service" msgstr "Może posiadać poza-portalowe usługi" #: src/bz-safety-calculator.c:530 msgid "Global Menu Integration" msgstr "Integracja z globalnym menu" #: src/bz-safety-calculator.c:531 msgid "Can display its menus in a global menu bar" msgstr "Może wyświetlać swoje menu w globalnym pasku menu" #: src/bz-safety-calculator.c:536 msgid "KDE Settings Integration" msgstr "Integracja z ustawieniami KDE" #: src/bz-safety-calculator.c:537 msgid "Can detect when KDE desktop settings change" msgstr "Może wykryć kiedy ustawienia pulpitu KDE się zmieniają" #: src/bz-safety-calculator.c:542 msgid "KDE Global Settings" msgstr "Globalne ustawienia KDE" #: src/bz-safety-calculator.c:543 msgid "Can read KDE desktop preferences like fonts and colors" msgstr "Może odczytywać preferencje pulpitu KDE, rzeczy jak czcionki i kolory" #: src/bz-safety-calculator.c:548 msgid "Secret Storage Service" msgstr "Usługa tajemnej pamięci" #: src/bz-safety-calculator.c:549 msgid "Can store and retrieve its own passwords using the system keyring" msgstr "" "Może przechowywać i otrzymywać swoje hasła korzystając z systemowego pęku " "kluczy" #: src/bz-safety-calculator.c:554 msgid "Desktop Notifications Service" msgstr "Usługa powiadomień pulpitowych" #: src/bz-safety-calculator.c:555 msgid "Can send desktop notifications" msgstr "Może wysyłać powiadomienia pulpitowe" #: src/bz-safety-calculator.c:561 msgid "System Tray Integration" msgstr "Integracja z zasobnikiem systemowym" #: src/bz-safety-calculator.c:562 msgid "Can display an icon in the system tray" msgstr "Może wyświetlać ikonę w zasobniku systemowym" #: src/bz-safety-calculator.c:567 msgid "KDE Connect Integration" msgstr "Integracja z KDE Connect" #: src/bz-safety-calculator.c:568 msgid "Can interact with devices paired via KDE Connect" msgstr "Może komunikować się z urządzeniami połączonymi przez KDE Connect" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "Bezpieczeństwo" #: src/bz-safety-dialog.blp:53 msgid "License" msgstr "Licencja" #: src/bz-safety-dialog.blp:63 msgid "App ID" msgstr "Identyfikator aplikacji" #: src/bz-safety-dialog.blp:73 msgid "SDK" msgstr "SDK" #: src/bz-safety-dialog.blp:104 msgid "" "This app uses an outdated version of the software platform (SDK) and might " "contain bugs or security vulnerabilities which will not be fixed." msgstr "" "Ta aplikacja wykorzystuje przestarzałą wersję środowiska programowania (SDK) " "i może zawierać błędy i luki bezpieczeństwa, które nie zostaną naprawione." #: src/bz-safety-dialog.c:227 #, c-format msgid "%s is Safe" msgstr "Aplikacja %s jest bezpieczna" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s has no Unsafe Permissions" msgstr "Aplikacja %s nie posiada niebezpiecznych uprawnień" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Probably Safe" msgstr "Aplikacja %s jest prawdopodobnie bezpieczna" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Possibly Unsafe" msgstr "Aplikacja %s jest prawdopodobnie niebezpieczna" #: src/bz-safety-dialog.c:247 #, c-format msgid "%s is Unsafe" msgstr "Aplikacja %s jest niebezpieczna" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "Zrzuty ekranu" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "Wstecz" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "Dalej" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "Kopiuj obraz" #: src/bz-screenshot-page.blp:147 msgid "Reset View" msgstr "Zresetuj widok" #: src/bz-screenshot-page.blp:158 msgid "Zoom Out" msgstr "Oddal" #: src/bz-screenshot-page.blp:168 msgid "Zoom In" msgstr "Przybliż" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "Karuzela zrzutów ekranu" #: src/bz-screenshots-carousel.blp:117 msgid "Open Screenshot Viewer" msgstr "Otwórz przeglądarkę zrzutów ekranu" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:72 msgid "Video" msgstr "Filmy" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:82 msgid "Office" msgstr "Biuro" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:87 msgid "PDF" msgstr "PDF" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:92 msgid "Calendar" msgstr "Kalendarz" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:97 msgid "Messaging" msgstr "Komunikatory" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:102 msgid "Steam" msgstr "Steam" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:107 msgid "Paint" msgstr "Rysowanie" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:112 msgid "VPN" msgstr "VPN" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:117 msgid "Torrent" msgstr "Torrent" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:122 msgid "Minecraft" msgstr "Minecraft" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:127 msgid "Emulator" msgstr "Emulator" #: src/bz-search-page.blp:57 msgid "Search Apps, Games, Software" msgstr "Wyszukuj aplikacje, gry i oprogramowanie" #: src/bz-search-page.blp:79 msgid "Clear Search" msgstr "Wyczyść wyszukiwanie" #: src/bz-search-page.blp:171 msgid "Categories Unavailable" msgstr "Kategorie są niedostępne" #: src/bz-search-page.blp:172 msgid "Search for apps using the search bar above." msgstr "Wyszukuj aplikacje korzystając z powyższego paska wyszukiwania" #: src/bz-search-page.blp:198 msgid "Browse Categories" msgstr "Przeglądaj kategorie" #: src/bz-search-page.blp:340 msgid "No Applications Found" msgstr "Nie znaleziono aplikacji" #: src/bz-search-page.c:244 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "Brak wyników dotyczących \"%s\" na Flathubie" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "Kopiuj łącze" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Otwórz łącze" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "Oś czasowa" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "Instaluje:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "Świat" #: src/bz-stats-dialog.blp:69 msgid "Since 4/15/2024" msgstr "Od 15.04.2024" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:124 #, c-format msgid "%.2fM Total Installs" msgstr "Suma instalacji: %.2f mln" #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:127 #, c-format msgid "%.2fK Total Installs" msgstr "Suma instalacji: %.2f tys." #: src/bz-stats-dialog.c:129 #, c-format msgid "%'d Total Installs" msgstr "Suma instalacji: %'d" #: src/bz-tag-list.c:78 msgid "No Results Found" msgstr "Brak wyników" #: src/bz-tag-list.c:90 #, c-format msgid "Apps Tagged \"%s\"" msgstr "Aplikacje z identyfikatorem \"%s\"" #: src/bz-tag-list.c:103 msgid "Search failed" msgstr "Wyszukiwanie nie powiodło się" #: src/bz-transaction-dialog.c:155 msgid "Keep User Data" msgstr "Usuń dane użytkownika" #: src/bz-transaction-dialog.c:156 msgid "Allow restoring personal settings & content" msgstr "Pozwól na przywracanie ustawień i zawartości" #: src/bz-transaction-dialog.c:165 msgid "Delete All Data" msgstr "Usuń wszystkie dane" #: src/bz-transaction-dialog.c:166 msgid "Permanently erase user data to save space" msgstr "Usuń dane aplikacji na zawsze, aby zaoszczędzić miejsce" #: src/bz-transaction-dialog.c:191 #, c-format msgid "Install %s?" msgstr "Zainstalować aplikację %s?" #: src/bz-transaction-dialog.c:196 msgid "" "Select which version to install. May install additional shared components" msgstr "" "Wybierz wersję do zainstalowania. Może zainstalować dodatkowe współdzielone " "komponenty" #: src/bz-transaction-dialog.c:198 msgid "May install additional shared components" msgstr "Może zainstalować dodatkowe współdzielone komponenty" #: src/bz-transaction-dialog.c:201 src/bz-transaction-dialog.c:230 #: src/bz-transaction-dialog.c:275 src/bz-transaction-dialog.c:578 msgid "_Cancel" msgstr "_Anuluj" #: src/bz-transaction-dialog.c:219 #, c-format msgid "Remove %s?" msgstr "Usunąć aplikację %s?" #: src/bz-transaction-dialog.c:222 msgid "Select which version to remove." msgstr "Wybierz wersję do usunięcia." #: src/bz-transaction-dialog.c:224 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "Nie będzie można korzystać z aplikacji %s po odinstalowaniu jej." #: src/bz-transaction-dialog.c:247 #, c-format msgid "“%s” is High Risk" msgstr "Aplikacja %s jest wysokim zagrożeniem" #: src/bz-transaction-dialog.c:251 msgid "" "This app has full access to your system, including all your files, " "browser history, saved passwords, and more. It also has access to the " "internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Ta aplikacja ma pełny dostęp do twojego systemu, w tym twoich plików, " "historii przeglądania, zapisanych haseł i wielu innych. Posiada również " "dostęp do internetu, co oznacza, że może wysyłać twoje dane do osób " "trzecich.\n" "\n" "Ponieważ ta aplikacja jest własnościowa, nie może być audytowana pod " "względem tego co robi z tymi uprawnieniami." #: src/bz-transaction-dialog.c:260 msgid "" "This app uses the legacy X11 windowing system, which allows it to record " "all keystrokes, capture screenshots, and monitor other applications. It " "also has access to the internet, meaning it could send your data to outside " "parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Ta aplikacja wykorzystuje przestarzały system okien X11, który pozwala jej " "na rejestrowanie wszystkich wciśnięć klawiszy, robienia zrzutów ekranu i " "monitorowania innych aplikacji Posiada również dostęp do internetu, co " "oznacza, że może wysyłać twoje dane do osób trzecich.\n" "\n" "Ponieważ ta aplikacja jest własnościowa, nie może być audytowana pod " "względem tego co robi z tymi uprawnieniami." #: src/bz-transaction-dialog.c:276 msgid "_Install Anyway" msgstr "Za_instaluj mimo to" #: src/bz-transaction-dialog.c:331 msgid "Failed to load transaction dialog" msgstr "Ładowanie okna transakcji nie powiodło się" #: src/bz-transaction-dialog.c:549 msgid "All apps are already installed" msgstr "Wszystkie aplikacje są już zainstalowane" #: src/bz-transaction-dialog.c:551 msgid "_OK" msgstr "_OK" #: src/bz-transaction-dialog.c:567 #, c-format msgid "Install %u App?" msgid_plural "Install %u Apps?" msgstr[0] "Zainstalować %u aplikację?" msgstr[1] "Zainstalować %u aplikacje?" msgstr[2] "Zainstalować %u aplikacji?" #: src/bz-transaction-dialog.c:575 msgid "" "The following will be installed. Additional shared components may also be " "installed" msgstr "" "Następujące zostanie zainstalowane. Dodatkowe współdzielone składniki mogą " "również być zainstalowane." #: src/bz-transaction-dialog.c:576 #, c-format msgid "%d addons will be installed." msgstr "Dodatki do zainstalowania: %d" #: src/bz-transaction-dialog.c:577 msgid "Additionally, addons will be installed." msgstr "Dodatkowo, następująca liczba dodatków zostanie zainstalowana: %d." #: src/bz-transaction-dialog.c:579 msgid "_Install All" msgstr "Za_instaluj wszystkie" #: src/bz-transaction-manager.c:766 #, c-format msgid "Finished in %.02f seconds" msgstr "Ukończono w %.02f sek." #: src/bz-transaction-tile.blp:129 msgid "App Add-On" msgstr "Dodatek aplikacji" #: src/bz-transaction-tile.blp:158 msgid "Runtime" msgstr "Biblioteka" #: src/bz-transaction-tile.blp:182 msgid "In Queue" msgstr "W kolejce" #: src/bz-transaction-tile.blp:206 msgid "Done" msgstr "Gotowe" #: src/bz-transaction-tile.blp:230 msgid "Error" msgstr "Bład" #: src/bz-transaction-tile.blp:286 msgid "Cancel Transaction" msgstr "Anuluj transakcję" #: src/bz-transaction-tile.blp:410 msgid "Show Error Info" msgstr "Pokaż szczegóły błędu" #: src/bz-transaction-tile.c:107 #, c-format msgid "%s Freed" msgstr "Zwolniono %s" #: src/bz-transaction-tile.c:362 src/bz-transaction-tile.c:365 msgid "Transaction Error" msgstr "Błąd transakcji" #: src/bz-transaction.c:342 msgid "Pending" msgstr "Oczekujące" #: src/bz-updates-card.blp:40 msgid "_Update All" msgstr "Akt_ualizuj wszystkie" #: src/bz-updates-card.c:293 #, c-format msgid "%u Runtime Update" msgid_plural "%u Runtime Updates" msgstr[0] "%u aktualizacja biblioteki" msgstr[1] "%u aktualizacje bibliotek" msgstr[2] "%u aktualizacji bibliotek" #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "Zarządzaj pozostałymi danymi" #: src/bz-user-data-page.blp:89 msgid "No User Data Found" msgstr "Nie znaleziono pozostałych danych" #: src/bz-user-data-page.blp:94 msgid "User Data" msgstr "Dane użytkownika" #: src/bz-user-data-tile.c:144 #, c-format msgid "Trashed User Data for %s" msgstr "Przeniesiono do kosza dane użytkownika aplikacji %s" #: src/bz-user-data-tile.blp:74 msgid "Trash User Data" msgstr "Przenieś do kosza dane użytkownika" #: src/bz-window.blp:88 msgid "Curated" msgstr "Polecane" #: src/bz-window.blp:100 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:220 msgid "Refresh completed!" msgstr "Ukończono odświeżanie!" #: src/bz-window.blp:273 msgid "You are running a new version of Bazaar!" msgstr "Odpaliłeś nowiutką wersję Bazaaru!" #: src/bz-window.blp:274 msgid "See What's New" msgstr "Zobacz co nowego" #: src/bz-window.blp:281 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "" "Masz połączenie z internetem, ale przeglądasz wersję Flathuba, która została " "zapisana w pamięci twojego komputera" #: src/bz-window.blp:393 msgid "Log Out" msgstr "Wyloguj się" #. Translators: %s is the title of the current page #: src/bz-window.c:380 #, c-format msgid "Bazaar — %s" msgstr "Bazaar — %s" #: src/bz-window.c:487 msgid "Failed to load add-ons" msgstr "Ładowanie dodatków się nie powiodło" #: src/bz-window.c:601 src/bz-window.c:618 msgid "Failed to launch application" msgstr "Uruchomienie aplikacji się nie powiodło" #: src/bz-window.c:823 msgid "You can't remove Bazaar from Bazaar!" msgstr "Nie możesz usunąć Bazaaru z poziomu Bazaaru!" #: src/bz-window.c:1108 src/bz-window.c:1142 msgid "Can't do that right now!" msgstr "Nie możesz tego teraz zrobić!" #: src/bz-world-map.c:595 msgctxt "As in, \"100 Downloads\"" msgid "Downloads" msgstr "Pobrań" #: src/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Ogólne" #: src/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Page" msgstr "Otwórz stronę wyszukiwania" #: src/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Library Page" msgstr "Otwórz stronę biblioteki" #: src/shortcuts-dialog.blp:20 msgctxt "shortcut window" msgid "Refresh" msgstr "Odśwież" #: src/shortcuts-dialog.blp:25 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Otwórz preferencje" #: src/shortcuts-dialog.blp:30 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Pokaż skróty" #: src/shortcuts-dialog.blp:35 msgctxt "shortcut window" msgid "Close Window" msgstr "Zamknij okno" #: src/shortcuts-dialog.blp:41 msgctxt "shortcut window" msgid "Quit Bazaar" msgstr "Zamknij Bazaar" #~ msgid "%e %B" #~ msgstr "%e %B" #~ msgid "" #~ "It emphasizes supporting the developers who make the Linux desktop " #~ "possible. Bazaar features a \"curated\" tab that can be configured by " #~ "distributors to allow for a more localized experience." #~ msgstr "" #~ "Podkreśla też potrzebę wspierania twórców aplikacji na Linuxa. Bazaar " #~ "posiada stronę \"polecane\", która może być konfigurowana przez " #~ "dystrybutorów pozwalając na bardziej lokalne doświadczenia." #~ msgid "Install Other Version" #~ msgstr "Zainstaluj inną wersję" #~ msgid "Keep Data" #~ msgstr "Zachowaj dane" #~ msgid "Open App" #~ msgstr "Otwórz aplikację" #~ msgid "_Synchronize Remotes" #~ msgstr "Z_synchronizuj repozytoria" #~ msgid "Synchronizing..." #~ msgstr "Synchronizowanie..." #, c-format #~ msgid "Receiving %d entries..." #~ msgstr "Otrzymywanie %d wystąpień..." #~ msgid "Indexing Data..." #~ msgstr "Indeksowanie danych..." #~ msgid "Refreshing Store Content" #~ msgstr "Odświeżanie zawartości" #~ msgid "No background tasks!" #~ msgstr "Brak zadań w tle!" #~ msgctxt "shortcut window" #~ msgid "Synchronize Remotes" #~ msgstr "Zsynchronizuj repozytoria" #~ msgctxt "shortcut window" #~ msgid "Quit" #~ msgstr "Wyjdź" #~ msgid "View the Release Page" #~ msgstr "Pokaż stronę wydania" #~ msgid "Close" #~ msgstr "Zamknij" #~ msgid "Copy and Close" #~ msgstr "Kopiuj i zamknij" #~ msgid "Nucleus app page" #~ msgstr "Strona aplikacji Nucleus" #~ msgid "Toggle transaction sidebar" #~ msgstr "Włącz pasek boczny transakcji" #~ msgctxt "Project URL Type" #~ msgid "Manifest" #~ msgstr "Manifest" #~ msgid "Install Size" #~ msgstr "Rozmiar po instalacji" #~ msgid "Ongoing" #~ msgstr "Trwające" #~ msgid "Finished" #~ msgstr "Zakończone" #, c-format #~ msgid "Transferred %s so far" #~ msgstr "Do tej pory przeniesiono %s" #~ msgid "Tasks" #~ msgstr "Zadania" #~ msgid "Stop Active Tasks" #~ msgstr "Zatrzymaj aktywne zadania" #~ msgid "No Tasks Yet" #~ msgstr "Brak zadań" #, c-format #~ msgid "%d Update Available" #~ msgid_plural "%d Updates Available" #~ msgstr[0] "%d aktualizacja dostepna" #~ msgstr[1] "%d aktualizacje dostępne" #~ msgstr[2] "%d aktualizacji dostępnych" #~ msgid "Updates Are Available" #~ msgstr "Dostępne są aktualizacje" #~ msgid "" #~ "The following applications are eligible for updates. Would you like to " #~ "install them?" #~ msgstr "" #~ "Następujące aplikacje mają dostępne aktualizacje. Czy chcesz je " #~ "zainstalować?" #, c-format #~ msgid "" #~ "%d runtimes and/or addons are eligible for updates. Would you like to " #~ "install them?" #~ msgstr "" #~ "Jest dostępna następująca liczba aktualizacji dla bibliotek i/lub " #~ "dodatków: %d. Czy chcesz je zainstalować?" #, c-format #~ msgid "Additionally, %d runtimes and/or addons will be updated." #~ msgstr "" #~ "Dodatkowo, następująca liczba bibliotek i/lub dodatków zostanie " #~ "zaktualizowana: %d." #~ msgid "Update Now" #~ msgstr "Aktualizuj teraz" #~ msgid "" #~ "The ability to inspect and install local .flatpak bundle files is coming " #~ "soon! In the meantime, try running\n" #~ "\n" #~ "flatpak install --bundle your-bundle.flatpak\n" #~ "\n" #~ "on the command line." #~ msgstr "" #~ "Możliwość wyświetlania i instalowania lokalnych plików .flatpak będzie " #~ "niedługo dostępna! Tymczasem, możesz uruchomić z poziomu terminala\n" #~ "\n" #~ "flatpak install --bundle twoj-pakiet.flatpak" #~ msgid "Resume Current Tasks" #~ msgstr "Kontynuuj wykonywanie zadań" #~ msgid "Pause Current Tasks" #~ msgstr "Zapauzuj wykonywanie zadań" #~ msgctxt "shortcut window" #~ msgid "Toggle Transaction Manager" #~ msgstr "Włącz menedżera transakcji" #~ msgid "Pride Colors (Horizontal)" #~ msgstr "Kolory dumy (poziome)" #~ msgid "Lesbian Pride Colors (Horizontal)" #~ msgstr "Kolory dumy lesbijek (poziome)" #~ msgid "Male Homosexual Pride Colors (Horizontal)" #~ msgstr "Kolory dumy mężczyzn homoseksualnych (poziome)" #~ msgid "Transgender Pride Colors (Horizontal)" #~ msgstr "Kolory dumy osób transpłciowych (poziome)" #~ msgid "Nonbinary Pride Colors (Horizontal)" #~ msgstr "Kolory dumy osób niebinarnych (poziome)" #~ msgid "Bisexual Pride Colors (Horizontal)" #~ msgstr "Kolory dumy osób biseksualnych (poziome)" #~ msgid "Asexual Pride Colors (Horizontal)" #~ msgstr "Kolory dumy osób aseksualnych (poziome)" #~ msgid "Pansexual Pride Colors (Horizontal)" #~ msgstr "Kolory dumy osób panseksualnych (poziome)" #~ msgid "Aromantic Pride Colors (Horizontal)" #~ msgstr "Kolory dumy osób aromantycznych (poziome)" #~ msgid "Genderfluid Pride Colors (Horizontal)" #~ msgstr "Kolory dumy osób genderfluidalnych (poziome)" #~ msgid "Polysexual Pride Colors (Horizontal)" #~ msgstr "Kolory dumy osób polyseksualnych (poziome)" #~ msgid "Omnisexual Pride Colors (Horizontal)" #~ msgstr "Kolory dumy osób omniseksualnych (poziome)" #~ msgid "Aroace Pride Colors (Horizontal)" #~ msgstr "Kolory dumy osób aromantyczno-seksualnych (poziome)" #~ msgid "Agender Pride Colors (Horizontal)" #~ msgstr "Kolory dumy osób bezpłciowych (poziome)" #~ msgid "Genderqueer Pride Colors (Horizontal)" #~ msgstr "Kolory dumy osób genderqueerowych (poziome)" #~ msgid "Intersex Pride Colors (Horizontal)" #~ msgstr "Kolory dumy osób interseksualnych (poziome)" #~ msgid "Demigender Pride Colors (Horizontal)" #~ msgstr "Kolory dumy osób półpłciowych (poziome)" #~ msgid "Biromantic Pride Colors (Horizontal)" #~ msgstr "Kolory dumy osób biomantycznych (poziome)" #~ msgid "Disability Pride Colors (Horizontal)" #~ msgstr "Kolory dumy osób niepełnosprawnych (poziome)" #~ msgid "Femboy Pride Colors (Horizontal)" #~ msgstr "Kolory dumy fembojów (poziome)" #, c-format #~ msgid "%s: %'u downloads" #~ msgstr "%s: %'u pobrań" #~ msgid "Hide EOL Entries" #~ msgstr "Ukrywaj wystąpienia z brakiem wsparcia" #~ msgid "Hide EOL entries and entries depending on them" #~ msgstr "Ukrywaj wystąpienia z brakiem wsparcia" #~ msgid "Only Show Free Software" #~ msgstr "Pokazuj tylko wolne oprogramowanie" #~ msgid "Hide proprietary software" #~ msgstr "Ukrywaj oprogramowanie własnościowe" #~ msgid "Show Only Flathub Content" #~ msgstr "Pokazuj tylko zawartość z Flathuba" #~ msgid "Hide applications which do not originate from Flathub" #~ msgstr "Ukrywaj aplikacje nie pochodzące z Flathuba" #~ msgid "Show Only Verified Content" #~ msgstr "Pokazuj tylko zawartość zweryfikowaną" #~ msgid "Hide applications which are not verified on Flathub" #~ msgstr "Ukrywaj aplikacje nie będące zweryfikowane na Flathubie" #~ msgid "Debounce Search Inputs" #~ msgstr "Opóźniaj wyszukiwanie podczas wpisywania" #~ msgid "Add a delay before searching to prevent instant replies while typing" #~ msgstr "" #~ "Dodaj opóźnienie przed wyszukiwaniem, aby zapobiec natychmiastowym " #~ "odpowiedziom podczas wpisywania" #~ msgid "Global Progress Bar Theme" #~ msgstr "Globalny motyw paska postępu" #~ msgid "Describes the look of the global progress bar" #~ msgstr "Określa wygląd paska postępu w całej aplikacji" #~ msgid "Saved Window Dimensions" #~ msgstr "Zapisane wymiary okna" #~ msgid "The window dimensions to be used by the next Bazaar window" #~ msgstr "" #~ "Wymiary okna, które zostaną użyte przy następnym uruchomieniu Bazaaru" #~ msgid "?" #~ msgstr "?" #~ msgid "" #~ "This functionality is currently disabled. It is recommended you download " #~ "and install Flatseal to manage app permissions." #~ msgstr "" #~ "Ta funkcja jest na ten moment wyłączona. Zalecamy, abyś zainstalował " #~ "Flatseal, aby zarządzać uprawnieniami twoich aplikacji." #~ msgid "Entry Inspector" #~ msgstr "Inspektor wystąpień" #~ msgid "Serialize" #~ msgstr "Serializuj" #~ msgid "Convert to JSON" #~ msgstr "Przekonwertuj na JSON" #~ msgid "More Mobile apps" #~ msgstr "Więcej aplikacji mobilnych" #~ msgid "Bazaar Inspector" #~ msgstr "Inspektor Bazaaru" #~ msgid "Background Task Info:" #~ msgstr "Informacje o zadaniu w tle:" #~ msgid "Enable Global Debug Mode" #~ msgstr "Włącz globalny tryb debugowania" #~ msgid "Active Blocklists" #~ msgstr "Aktywne listy blokowania" #~ msgid "Active Curated-Configs" #~ msgstr "Aktywne konfiguracje strony \"Polecane\"" #~ msgid "All Entry Groups" #~ msgstr "Wszystkie grupy wystąpień" #~ msgid "Filter..." #~ msgstr "Filtruj..." #~ msgid "Decache and Inspect" #~ msgstr "Wyczyść pamięć podręczną i inspektuj" #~ msgid "No Flatpaks Installed" #~ msgstr "Nie zainstalowano żadnych Flatpaków" #~ msgid "Connect with Flathub" #~ msgstr "Połącz z Flathub" #~ msgid "Inspect UI Entry" #~ msgstr "Zbadaj element interfejsu" #~ msgid "All Debug Actions" #~ msgstr "Wszystkie działania debugowania" #~ msgid "Open Bazaar Inspector" #~ msgstr "Otwórz inspektora Bazaaru" #, c-format #~ msgid "%s is suitable for toddlers" #~ msgstr "%s jest odpowiednie dla małych dzieci" #~ msgid "--- MB" #~ msgstr "--- MB" #~ msgid "Of the size of human DNA" #~ msgstr "rozmiaru DNA człowieka" #~ msgid "3 billion base pairs" #~ msgstr "3 miliardy par zasadowych" #~ msgid "Of the Linux Kernel" #~ msgstr "jądra Linuksa" #~ msgid "linux-6.17.tar.xz" #~ msgstr "linux-6.17.tar.xz" #~ msgid "Of the Apollo 11 guidance computer" #~ msgstr "komputera naprowadzającego Apollo 11" #~ msgid "Total ROM and RAM" #~ msgstr "RAMu i ROMu razem" #~ msgid "Of the original Super Mario Bros" #~ msgstr "oryginalnej wersji Super Mario Bros" #~ msgid "On the NES" #~ msgstr "na konsoli NES" #~ msgid "Of the size of Wikipedia" #~ msgstr "rozmiaru Wikipedii" #~ msgid "Without any media" #~ msgstr "bez żadnych multimediów" #~ msgid "Show Git Forge Star Counts" #~ msgstr "Pokaż ilość gwiazdek na git" #~ msgid "" #~ "Whether to attempt to detect and show \"star counts\" for projects in the " #~ "full view" #~ msgstr "" #~ "Stwierdź, czy Bazaar ma próbwać wykryć i pokazać \"ilość gwiazdek\" dla " #~ "projektów w pełwnym widoku" #~ msgid "Mobile Apps" #~ msgstr "Aplikacje mobilne" #~ msgid "Repository Star Count" #~ msgstr "Liczba gwiazdek repozytorium" #, c-format #~ msgid "%.2fM" #~ msgstr "%.2f mln" #, c-format #~ msgid "%.2fK" #~ msgstr "%.2f tys." #~ msgid "Application Details" #~ msgstr "Szczegóły aplikacji" #~ msgid "Display Star Count" #~ msgstr "Pokaż liczbę gwiazdek repozytorium" #~ msgid "Show the star count of an application's source code repository" #~ msgstr "Pokaż licznik ukazujący liczbę gwiazdek repozytorium aplikacji" #~ msgid "" #~ "Bazaar can fetch and display the star count from an application's source " #~ "code repository on a remote Git forge. \n" #~ " For projects on GitHub, rate limits may cause them not to appear." #~ msgstr "" #~ "Bazaar może pokazywać ilość gwiazdek z repozytorium aplikacji na " #~ "serwisach Git. Projekty z repozytoriamu na GitHubie, mogą zostać " #~ "ograniczone,\n" #~ "więc licznik może się nie pokazać." #~ msgid "Hide proprietary software when searching" #~ msgstr "Ukrywaj oprogramowanie własnościowe podczas wyszukiwania" #~ msgid "Filter search results to only show applications available on Flathub" #~ msgstr "" #~ "Filtruj wyniki wyszukiwania, tak aby pokazywać tylko aplikacje dostępne " #~ "na Flathubie" #~ msgid "Verified by the original developers" #~ msgstr "Zweryfikowane przez oryginalnych twórców " #~ msgid "End of Life Apps" #~ msgstr "Aplikacje z brakiem wsparcia" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Ahmed Najmawi" #~ msgstr "Ahmed Najmawi" #~ msgctxt "About Dialog Translator Credit" #~ msgid "AtomHare" #~ msgstr "AtomHare" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Azenyr" #~ msgstr "Azenyr" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Goudarz Jafari" #~ msgstr "Goudarz Jafari" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Jill Fiore (Lumaeris)" #~ msgstr "Jill Fiore (Lumaeris)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "João Victor (Leal)" #~ msgstr "João Victor (Leal)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "KiKaraage" #~ msgstr "KiKaraage" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Lucosec" #~ msgstr "Lucosec" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Léane GRASSER" #~ msgstr "Léane GRASSER" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Marcel Mrówka (Microwave)" #~ msgstr "Marcel Mrówka (Microwave)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Peter Dave Hello" #~ msgstr "Peter Dave Hello" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Pietro F." #~ msgstr "Pietro F." #~ msgctxt "About Dialog Translator Credit" #~ msgid "Sabri Ünal" #~ msgstr "Sabri Ünal" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Shihfu Juan" #~ msgstr "Shihfu Juan" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Shinsei" #~ msgstr "Shinsei" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Vlastimil Dědek" #~ msgstr "Vlastimil Dědek" #~ msgctxt "About Dialog Translator Credit" #~ msgid "asen23" #~ msgstr "asen23" #~ msgctxt "About Dialog Translator Credit" #~ msgid "camegone" #~ msgstr "camegone" #~ msgctxt "About Dialog Translator Credit" #~ msgid "renner" #~ msgstr "renner" #~ msgctxt "About Dialog Translator Credit" #~ msgid "robotta" #~ msgstr "robotta" #~ msgid "Constructing Flatpak instance..." #~ msgstr "Przygotywywanie instancji Flatpaka..." #~ msgid "Reusing last Flatpak instance..." #~ msgstr "Ponowne wykorzystywanie ostatniej instancji Flatpaka..." #~ msgid "Flathub is not registered on this system" #~ msgstr "Flathub nie jest zarejestrwowany na tym komputerze" #~ msgid "" #~ "Would you like to add Flathub as a remote? If you decline, the Flathub " #~ "page will not be available. You can change this later." #~ msgstr "" #~ "Czy chcesz dodać Flathub do listy repozytoriów flatpak? Jeśli tego nie " #~ "zrobisz strona \"Flathub\" nie będzie dostępna. Możesz to zmienić w " #~ "dowolnym momencie." #~ msgid "Add Flathub" #~ msgstr "Dodaj Flathub" #, c-format #~ msgid "Identifying installed entries..." #~ msgstr "Identyfikowanie zainstalowanych wystąpień..." #, c-format #~ msgid "" #~ "Beginning remote entry retrieval while referencing %d blocklist(s)..." #~ msgstr "" #~ "Rozpoczynanie otrzymywania zdalnych wystąpień odnosząc się do %d list(y) " #~ "blokowania..." #, c-format #~ msgid "%'d of %'d" #~ msgstr "%'d z %'d" #, c-format #~ msgid "Waiting for background indexing tasks to catch up..." #~ msgstr "Oczekiwanie na zakończenie indeksowania w tle..." #, c-format #~ msgid "Completed initialization in %0.2f seconds" #~ msgstr "Zakończono inicjalizację w %0.2f sek." #~ msgid "More actions" #~ msgstr "Więcej zadań" #~ msgid "Run this application" #~ msgstr "Uruchom tą aplikację" #~ msgid "Run" #~ msgstr "Uruchom" #~ msgid "Settings & user data will be kept" #~ msgstr "Ustawiania i dane użytkownika zostaną zachowane" #~ msgid "" #~ "Bazaar was not provided a curated content configuration. Contact your " #~ "operating system's support channels for assistance." #~ msgstr "" #~ "Nie dołączono konfiguracji polecanych aplikacji do Bazaaru. Skontakuj się " #~ "z kanałami pomocy swojej dystrybucji, aby uzyskać pomoc." #~ msgid "Game" #~ msgstr "Gry" #~ msgid "Visual" #~ msgstr "Grafika" #~ msgid "Git Forge Star Counts" #~ msgstr "Licznik gwiazdek na git" #~ msgid "Not having a GitHub access token may trigger rate limits" #~ msgstr "" #~ "Nie posiadanie tokenu dostępu Githuba może spowodoać blokowanie próśb" #~ msgid "Show Only Flathub Apps" #~ msgstr "Pokazuj tylko aplikacje z Flathuba" #~ msgid "Wait for a brief pause to reduce system load" #~ msgstr "Poczekaj przez chilkę, aby zmniejszyć obciążenie systemu" #~ msgid "Pride Rainbow Flag" #~ msgstr "Tęczowa flaga dumy" #~ msgid "Bisexual Flag" #~ msgstr "Flaga osób biseksualnych" #~ msgid "Asexual Flag" #~ msgstr "Flaga osób aseksualnych" #~ msgid "Go Home" #~ msgstr "Powróć do strony domowej" #~ msgid "Browse" #~ msgstr "Przeglądaj" #~ msgid "App View" #~ msgstr "Widok aplikacji" #~ msgid "Go Back" #~ msgstr "Powrót" #~ msgid "View curated applications" #~ msgstr "Przeglądaj polecane aplikacje" #~ msgid "View the latest on Flathub" #~ msgstr "Przeglądaj najnowsze z Flathuba" #~ msgid "_Quit Service" #~ msgstr "_Zakończ usługę" #~ msgid "Graphics" #~ msgstr "Grafika" #~ msgctxt "Project URL Type" #~ msgid "Homepage" #~ msgstr "Strona domowa" #~ msgid "Excludes shared components" #~ msgstr "Wyklucza współdzielone komponenty" #~ msgid "Source code may not be available" #~ msgstr "Kod źródłowy, może nie być dostępny" #~ msgid "Click for details" #~ msgstr "Kliknij, aby uzyskać informacje" #~ msgid "Repositories" #~ msgstr "Repozytoria" #~ msgid "Open in browser" #~ msgstr "Otwórz w przeglądarce" #, c-format #~ msgid "%'d Monthly Downloads" #~ msgstr "%'d miesięcznych pobrań" #~ msgid "Theme" #~ msgstr "Motyw" #~ msgid "Share" #~ msgstr "Podziel się" #~ msgid "Calligraphy application page" #~ msgstr "Strona aplikacji Calligraphy" #~ msgid "Download graph for Blender" #~ msgstr "Wykres pobrań Blendera" #~ msgid "Manage Addons" #~ msgstr "Zarządzaj dodatkami" #~ msgid "Open this image in the default image viewer" #~ msgstr "Otwórz ten obraz w domyślnej przeglądarce zdjęć" #~ msgid "Copy this image to the clipboard" #~ msgstr "Skopiuj ten obraz do schowka" #~ msgid "Download Statistics" #~ msgstr "Statystyki pobrań" #~ msgid "Show Downloads Over Time" #~ msgstr "Pokaż pobrania na przestrzeni czasu" #~ msgid "Remote repo name" #~ msgstr "Nazwa repozytorium" #~ msgid "%B %-d" #~ msgstr "%-d %B" #~ msgid "Downloads Over Time" #~ msgstr "Pobrania na przestrzeni czasu" #~ msgid "Updated Size" #~ msgstr "Rozmiar po aktualizacji" #~ msgid "Freed Space" #~ msgstr "Zwolnione miejsce" #~ msgid "Transactions Will Appear Here" #~ msgstr "Tutaj pojawią się transakcje" #~ msgid "Halt the execution of transactions" #~ msgstr "Zatrzymaj wykonywanie transakcji" #~ msgid "Up to date!" #~ msgstr "Wszystko zaktualizowane!" #~ msgid "Confirm Action" #~ msgstr "Zatwierdź zadanie" #, c-format #~ msgid "" #~ "You are about to remove the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "Masz zamiar usunąć następujący Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Czy na pewno chcesz to zrobić?" #, c-format #~ msgid "" #~ "You are about to install the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "Masz zamiar zainstalować następujący Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Czy na pewno chcesz to zrobić?" #~ msgid "Resume the execution of transactions" #~ msgstr "Wznów wykonywanie transakcji" #~ msgid "Pause the execution of transactions" #~ msgstr "Zatrzymaj wykonywanie transakcji" #~ msgid "Apps Of The Week" #~ msgstr "Polecane w tym tygodniu" #~ msgid "Minimize Lower Bound" #~ msgstr "Zminimalizuj dolną granicę" #~ msgid "Maximize Upper Bound" #~ msgstr "Zmaksymalizuj górną granicę" #~ msgctxt "Project URL Type" #~ msgid "VCS Browser" #~ msgstr "Przeglądarka VCS" #~ msgid "Full Application View" #~ msgstr "Pełny widok aplikacji" #~ msgid "Change what content is shown when viewing applications" #~ msgstr "Zmień co się pokazuje podczas wyświetlania aplikacji" #~ msgid "" #~ "If you do not have an access token, turning this setting on may cause " #~ "GitHub to eventually rate limit you." #~ msgstr "" #~ "Jeśli nie posiadasz tokenu dostępu włączenie tego ustawienia może " #~ "sprawić, że Github może zacząć blokować twoje żądania" #~ msgid "Type to filter" #~ msgstr "Pisz, aby filtrować" #~ msgid "Exclude results with proprietary licenses" #~ msgstr "Odrzuć wyniki z licencjami własnościowymi" #~ msgid "Advanced" #~ msgstr "Zaawansowane" #~ msgid "Open this link externally" #~ msgstr "Otwórz to łącze w przeglądarce" #, c-format #~ msgid "Received %'d entries out of %'d (%0.1f seconds elapsed)" #~ msgstr "Otrzymano %'d z %'d wystąpień (minęło %0.1f sek.)" #~ msgid "VCS Forge Star Count" #~ msgstr "Licznik gwiazdek na VCS" #~ msgid "This application does not provide a donation link" #~ msgstr "Ta aplikacja nie posiada łącza do strony przekazywania darowizny" #, c-format #~ msgid "" #~ "\"%s\" does not provide a donations link. This does not mean you cannot " #~ "support them! Try looking at their project page for " #~ "more information." #~ msgstr "" #~ "\"%s\" nie posiada łącza do strony przekazywaina darowizny. Oznacza to, " #~ "że nie możesz wesprzeć tej aplikacji. Zajrzyj do a href=\"%s\">strony " #~ "projektu, aby dowiedzieć się więcej." #, c-format #~ msgid "" #~ "\"%s\" does not provide a donations link. This does not mean you cannot " #~ "support them! Try finding their project page for more information." #~ msgstr "" #~ "\"%s\" nie posiada łącza do strony przekazywaina darowizny. Oznacza to, " #~ "że nie możesz wesprzeć tej aplikacji. Spróbój znaleźć stronę projektu tej " #~ "aplikacji, aby dowiedzieć się więcej." #~ msgid "Installing" #~ msgstr "Instalowanie" #~ msgid "Removing" #~ msgstr "Usuwanie" #~ msgid "Show Animated Background" #~ msgstr "Pokaż animowane tła" #~ msgid "Whether to show the animated icon background on the home page" #~ msgstr "" #~ "Wybierz czy chcesz, aby pokazywać animowane tła ikon na stronie domowej" #~ msgid "" #~ "The number of downloads in the last 30 days. Click to view this " #~ "application's download statistics." #~ msgstr "" #~ "Jest to liczba pobrań z ostatnich 30 dni. Naciśnij, aby zobaczyć " #~ "statystyki pobrań tej aplikacji." #~ msgid "How the application looks" #~ msgstr "Jak aplikacja się prezentuje" #~ msgid "Appearance" #~ msgstr "Wygląd" #~ msgid "Show animated background" #~ msgstr "Pokaż animowane tła" #~ msgid "Keep the summary shorter, between 10 and 35 characters" #~ msgstr "Proszę skrócić podsumowanie, powinno mieć między 10 a 35 znaków." #~ msgid "Main Bazaar window showing Blender" #~ msgstr "Główne okno Bazaaru pokazujące Blendera" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Microwave" #~ msgstr "Microwave" #~ msgid "Match using regular expressions" #~ msgstr "Porównywaj używając zwyczajnych wyrażeń" #~ msgid "Hide filtering and sorting behind a crossfade effect" #~ msgstr "Ukryj filtrowanie i sortowanie za efektem przejścia" bazaar-orig-v0.7.14/po/ru.po0000664000175000017500000031363615166123241014560 0ustar hasanhasan# Russian translations for bazaar package. # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # # SPDX-FileCopyrightText: 2025, 2026 Jill Fiore # Jill Fiore , 2025-2026. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-10 14:20+0700\n" "PO-Revision-Date: 2026-04-10 14:24+0700\n" "Last-Translator: Jill Fiore \n" "Language-Team: Russian\n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Gtranslator 50.0\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:46 #: src/bz-window.c:377 src/bz-window.c:378 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "" "Установка, удаление или обновление Flatpak приложений на этом компьютере" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;Система;УправлениеПакетами;Discover;Flatpak;Приложения;Магазин;" #: data/io.github.kolunmi.Bazaar.desktop.in:16 msgid "New Window" msgstr "Новое окно" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and manage applications" msgstr "Поиск и управление приложениями" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A fast and modern app store for Linux with a focus on discovering and " "installing Flatpak apps and addons, particularly from Flathub." msgstr "" "Быстрый и современный магазин приложений для Linux с фокусом на поиске, " "установке приложений и дополнений из Flatpak репозиторий, в частности с " "Flathub." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:15 msgid "Queue multiple installs and keep browsing" msgstr "" "Добавьте несколько установок в очередь и продолжайте просматривать страницы" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:16 msgid "Easily view app permissions" msgstr "Просто просматривайте разрешения приложений" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:17 msgid "Sign in to Flathub to view and manage your favorites" msgstr "" "Войдите в Flathub для просмотра и управления вашими избранными приложениями" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:18 msgid "Search apps directly from GNOME Shell" msgstr "Поиск приложения напрямую с GNOME Shell" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:30 msgid "Adam Masciola" msgstr "Адам Масциола" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:55 msgid "The home page displaying Flathub apps" msgstr "Главная страница, отображающая приложения Flathub" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:59 msgid "Exhibit app page" msgstr "Страница приложения Exhibit" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:63 msgid "Library page" msgstr "Страница библиотеки" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:67 msgid "Search page" msgstr "Страница поиска" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:71 msgid "Category page" msgstr "Страница категорий" #: src/bz-addon-tile.blp:49 src/bz-installed-tile.blp:64 #: src/bz-rich-app-tile.blp:140 msgid "Stopped Receiving Updates" msgstr "Прекращено получение обновлений" #: src/bz-addon-tile.c:155 src/bz-favorites-tile.c:157 #: src/bz-rich-app-tile.blp:172 msgid "Uninstall" msgstr "Удалить" #: src/bz-addon-tile.c:157 src/bz-addons-dialog.blp:280 #: src/bz-favorites-tile.c:159 msgid "Install" msgstr "Установить" #: src/bz-addons-dialog.blp:14 src/bz-addons-dialog.blp:21 #: src/bz-addons-dialog.blp:70 src/bz-full-view.blp:627 #: src/bz-installed-tile.blp:101 msgid "Manage Add-Ons" msgstr "Управление дополнениями" #: src/bz-addons-dialog.blp:80 msgid "No Add-Ons Visible" msgstr "Нет видимых дополнений" #: src/bz-addons-dialog.blp:81 msgid "" "Your current filter preferences are hiding all known add-ons. Try adjusting " "them." msgstr "" "Ваши параметры фильтра скрывают все известные дополнения. Попробуйте " "изменить их." #: src/bz-addons-dialog.blp:88 msgid "Add-on Page" msgstr "Страница дополнений" #: src/bz-addons-dialog.blp:202 src/bz-full-view.blp:426 msgid "Downloads/Month" msgstr "Загрузок в месяц" #: src/bz-addons-dialog.blp:229 src/bz-full-view.blp:461 msgid "Stopped Receiving Core Updates" msgstr "Прекращено получение основных обновлений" #: src/bz-addons-dialog.blp:243 msgid "" "This add-on uses a runtime that no longer receives updates or security " "fixes. It may become unsafe to use." msgstr "" "Это дополнение использует среду выполнения, которая больше не получает " "обновления или исправления ошибок безопасности. Оно может стать небезопасным " "для использования." #: src/bz-addons-dialog.blp:297 src/bz-rich-app-tile.blp:185 #: src/bz-transaction-tile.blp:272 msgid "Open" msgstr "Открыть" #: src/bz-addons-dialog.blp:304 src/bz-install-controls.blp:141 #: src/bz-installed-tile.blp:114 msgid "Remove" msgstr "Удалить" #: src/bz-addons-dialog.c:325 #, c-format msgid "Add-on for %s" msgstr "Дополнение к %s" #: src/bz-addons-dialog.c:339 src/bz-full-view.c:577 msgid "Show Less" msgstr "Показать меньше" #: src/bz-addons-dialog.c:339 src/bz-full-view.c:577 msgid "Show More" msgstr "Показать больше" #: src/bz-addons-dialog.c:389 msgid "Download Stats" msgstr "Статистика загрузок" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 #: src/bz-age-rating-dialog.c:736 src/bz-context-tile-callbacks.c:186 #: src/bz-context-tile-callbacks.c:193 msgid "Age Rating" msgstr "Возраст" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "Мультипликационное насилие" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "Нет информации о мультипликационном насилии" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "Фэнтезийное насилие" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "Нет информации о фэнтезийном насилии" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "Реалистичное насилие" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "Нет информации о реалистичном насилии" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "Кровопролитие" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "Нет информации о кровопролитии" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "Сексуальное насилие" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "Нет информации о сексуальном насилии" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "Алкоголь" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "Нет информации о упоминании алкоголя" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "Наркотики" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "Нет информации о упоминании наркотических средств" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "Табак" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "Нет информации о упоминании табачных изделий" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "Нагота" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "Нет информации о наготе любого рода" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "Сексуальные темы" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "" "Нет информации о упоминании или показе изображений сексуального характера" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "Ненормативная лексика" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "Нет информации о ненормативной лексике в любом виде" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "Неприемлемый юмор" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "Нет информации о неприемоемом юморе" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "Дискриминация" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "Нет информации о дискриминации в любом виде" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "Реклама" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "Нет информации о рекламе в любом виде" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "Азартные игры" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "Нет информации о азартных играх в любом виде" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "Покупка" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "Нет информации о возможности тратить деньги" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "Общение между пользователями" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "Нет инфорамции о возможностях общаться с другими пользователями" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "Аудиочат между пользователями" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "Нет информации о возможности разговаривать с другими пользователями" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 msgid "Contact Details" msgstr "Контактная информация" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "" "Нет информации о распространении имён пользователей или адресов электронной " "почты" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "Идентифицирующая информация" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "" "Нет информации о распространении пользовательских данных с другими лицами" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "Распространение местоположения" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "" "Нет информации о распространении физического местоположения с другими " "пользователями" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "Проституция" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "Нет информации о упоминании проституции" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "Прелюбодеяние" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "Нет информации о упоминании прелюбодеяния" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "Сексуализированные персонажи" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "Нет информации о сексуализированных персонажей" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 msgid "Desecration" msgstr "Осквернение" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "Нет информации о осквернении" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "Останки человека" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "Нет информации о видимости останков человека" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "Рабство" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "Нет информации о упоминании рабства" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "Не содержит упоминания наркотических средств" #: src/bz-age-rating-dialog.c:426 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "" "Не содержит ругательство, ненормативную лексику, и любых видов грубой речи" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "Не содержит рекламу или денежные транзакции" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "Не содержит секс или наготу" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "Не содержит функциональность немодерируемого чата" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "Не содержит насилие" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "Наркотики" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "Грубая речь" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "Деньги" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "Общение" #: src/bz-age-rating-dialog.c:479 msgid "Violence" msgstr "Насилие" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:686 src/bz-context-tile-callbacks.c:176 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:711 msgctxt "Age rating" msgid "All" msgstr "Все" #: src/bz-age-rating-dialog.c:747 #, c-format msgid "%s has an unknown age rating" msgstr "%s имеет неизвестное возрастное ограничение" #: src/bz-age-rating-dialog.c:753 #, c-format msgid "%s is suitable for everyone" msgstr "%s предназначено для всех возрастов" #: src/bz-age-rating-dialog.c:756 #, c-format msgid "%s is suitable for young children" msgstr "%s предназначено для маленьких детей" #: src/bz-age-rating-dialog.c:759 #, c-format msgid "%s is suitable for children" msgstr "%s предназначено для детей" #: src/bz-age-rating-dialog.c:762 #, c-format msgid "%s is suitable for teenagers" msgstr "%s предназначено для подростков" #: src/bz-age-rating-dialog.c:765 #, c-format msgid "%s is suitable for adults" msgstr "%s предназначено для взрослых" #: src/bz-age-rating-dialog.c:768 #, c-format msgid "%s is suitable for %s" msgstr "%s предназначено для %s" #: src/bz-age-rating-dialog.c:862 #, c-format msgid "%s • %s" msgstr "%s • %s" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:29 #: src/bz-user-data-page.blp:15 src/bz-window.blp:239 msgid "Main Menu" msgstr "Главное меню" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 #: src/bz-user-data-page.blp:19 src/bz-window.blp:328 msgid "_Donate to Bazaar ❤️" msgstr "_Поддержать Bazaar ❤️" #: src/bz-all-apps-page.blp:25 src/bz-apps-page.blp:25 #: src/bz-user-data-page.blp:26 src/bz-window.blp:335 msgid "_Refresh" msgstr "_Обновить" #: src/bz-all-apps-page.blp:30 src/bz-apps-page.blp:30 #: src/bz-user-data-page.blp:31 src/bz-window.blp:340 msgid "_Preferences" msgstr "П_араметры" #: src/bz-all-apps-page.blp:35 src/bz-apps-page.blp:35 #: src/bz-user-data-page.blp:36 src/bz-window.blp:345 msgid "_Login With Flathub" msgstr "_Войти в Flathub" #: src/bz-all-apps-page.blp:41 src/bz-apps-page.blp:41 #: src/bz-user-data-page.blp:42 src/bz-window.blp:351 msgid "_Manage Leftover User Data" msgstr "_Управлять оставшимися данными" #: src/bz-all-apps-page.blp:46 src/bz-apps-page.blp:46 #: src/bz-user-data-page.blp:47 src/bz-window.blp:356 msgid "_Keyboard Shortcuts" msgstr "_Сочетание клавиш" #: src/bz-all-apps-page.blp:51 src/bz-apps-page.blp:51 #: src/bz-user-data-page.blp:52 src/bz-window.blp:361 msgid "_About Bazaar" msgstr "О _Bazaar" #: src/bz-all-apps-page.blp:58 src/bz-apps-page.blp:58 #: src/bz-user-data-page.blp:59 src/bz-window.blp:368 msgid "_Quit Bazaar" msgstr "_Завершить Bazaar" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "Системная папка %s" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "Домашняя подпапка %s" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "Системные папки хоста" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "Системная конфигурация хоста из /etc" #: src/bz-app-permissions.c:169 #, c-format msgid "Desktop subfolder %s" msgstr "Подпапка рабочего стола %s" #: src/bz-app-permissions.c:170 msgid "Desktop folder" msgstr "Папка рабочего стола" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "Подпапка документов %s" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "Папка документов" #: src/bz-app-permissions.c:177 #, c-format msgid "Music subfolder %s" msgstr "Подпапка музыки %s" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "Папка музыки" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "Подпапка изображений %s" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "Папка изображений" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "Подпапка общего доступа %s" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "Папка общего доступа" #: src/bz-app-permissions.c:189 #, c-format msgid "Videos subfolder %s" msgstr "Подпапка с видео %s" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "Папка с видео" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "Подпапка шаблонов %s" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "Папка шаблонов" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "Подпапка пользовательского кэша %s" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "Папка пользовательского кэша" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "Подпапка пользовательской конфигурации %s" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "Папка пользовательской конфигурации" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "Подпапка пользовательских данных %s" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "Папка пользовательских данных" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "Подпапка пользовательской среды выполнения %s" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "Папка пользовательской среды выполнения" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "Доступ к файловой системе в %s" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "Неизвестный путь файловой системы" #: src/bz-app-size-dialog.blp:26 src/bz-app-size-dialog.blp:52 msgid "Download Size" msgstr "Размер скачивания" #: src/bz-app-size-dialog.blp:53 msgid "Amount to download from the internet" msgstr "Размер скачивания из интернета" #: src/bz-app-size-dialog.blp:73 msgid "Installed Size" msgstr "Размер установки" #: src/bz-app-size-dialog.blp:74 msgid "Size on Disk" msgstr "Размер на диске" #: src/bz-app-size-dialog.blp:121 msgid "Open user data folder" msgstr "Открыть папку пользовательских данных" #: src/bz-app-size-dialog.blp:131 msgid "User Data Size" msgstr "Размер пользовательских данных" #: src/bz-app-size-dialog.blp:132 msgid "Caches, settings, and other app data" msgstr "Кэши, настройки и другие пользовательские данные" #: src/bz-app-size-dialog.c:99 msgid "Installed Runtime Size" msgstr "Размер установленной среды выполнения" #: src/bz-app-size-dialog.c:99 msgid "Runtime Download Size" msgstr "Размер скачивания среды выполнения" #: src/bz-app-size-dialog.c:204 msgid "App Size" msgstr "Размер приложения" #: src/bz-app-tile.blp:57 src/bz-developer-badge.c:98 #: src/bz-rich-app-tile.blp:104 src/bz-rich-app-tile.c:304 msgid "Verified" msgstr "Подтверждено" #. Translators: As in 'The app is installed'. #: src/bz-app-tile.blp:88 src/bz-context-tile-callbacks.c:135 #: src/bz-releases-list.c:205 msgid "Installed" msgstr "Установлено" #: src/bz-apps-page.blp:142 msgid "Show All" msgstr "Показать все" #: src/bz-apps-page.c:229 #, c-format msgid "All \"%s\"" msgstr "Все \"%s\"" #: src/bz-apps-page.c:478 src/bz-tag-list.c:91 #, c-format msgid "%d Applications" msgstr "%d приложений" #: src/bz-application.c:707 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Адам Масциола " #: src/bz-application.c:708 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Александр Фанхе" #: src/bz-application.c:728 msgid "The Bazaar Contributors" msgstr "Разработчики Bazaar" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:731 msgid "translator-credits" msgstr "Джилл Фиори , 2025, 2026" #: src/bz-application.c:741 msgid "Special Thanks" msgstr "Особая благодарность" #: src/bz-application.c:799 msgid "Logged Out Successfully!" msgstr "Выход из аккаунта выполнен успешно!" #: src/bz-application.c:922 msgid "Performing setup…" msgstr "Выполняется настройка…" #: src/bz-application.c:1006 msgid "Set Up System Flathub?" msgstr "Добавить системный Flathub?" #: src/bz-application.c:1009 msgid "" "The system Flathub remote is not set up. Bazaar requires Flathub to be " "configured on the system Flatpak installation to browse and install " "applications.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Системный Flathub не был добавлен. Bazaar требует наличия Flathub в " "системной установке Flatpak для поиска и установки приложений.\n" "\n" "Вы по-прежнему можете использовать Bazaar для обзора и удаления уже " "установленных приложений." #: src/bz-application.c:1016 msgid "Set Up Flathub?" msgstr "Добавить Flathub?" #: src/bz-application.c:1019 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub не был добавлен в данную систему. Вы не сможете искать и " "устанавливать приложения в Bazaar пока он недоступен.\n" "\n" "Вы по-прежнему можете использовать Bazaar для обзора и удаления уже " "установленных приложений." #: src/bz-application.c:1025 msgid "Later" msgstr "Позже" #: src/bz-application.c:1026 msgid "Set Up Flathub" msgstr "Добавить Flathub" #: src/bz-application.c:1315 msgid "A backend error occurred" msgstr "Произошла ошибка бэкэнда" #: src/bz-application.c:1511 src/bz-application.c:3420 src/bz-window.blp:70 msgid "Refreshing…" msgstr "Обновление…" #: src/bz-application.c:1663 src/bz-application.c:3418 #, c-format msgid "Loading %d apps…" msgstr "Загрузка %d приложений…" #: src/bz-application.c:1666 msgid "Checking for updates…" msgstr "Проверка на наличие обновлений…" #: src/bz-application.c:1729 msgid "Failed to open .flatpakref" msgstr "Невозможно открыть .flatpakref" #: src/bz-application.c:1785 msgid "An initialization error occurred" msgstr "Произошла ошибка инициализации" #: src/bz-application.c:2183 msgid "Failed to check for updates" msgstr "Невозможно проверить на наличие обновлений" #: src/bz-application.c:3191 msgid "Could not find app" msgstr "Не удалось найти приложение" #: src/bz-application.c:3422 msgid "Writing to cache…" msgstr "Запись в кэш…" #: src/bz-appstream-parser.c:302 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Страница Flathub" #: src/bz-appstream-parser.c:323 msgctxt "Project URL Type" msgid "Project Website" msgstr "Веб-сайт проекта" #: src/bz-appstream-parser.c:327 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Отслеживание ошибок" #: src/bz-appstream-parser.c:331 msgctxt "Project URL Type" msgid "FAQ" msgstr "Часто задаваемые вопросы" #: src/bz-appstream-parser.c:335 msgctxt "Project URL Type" msgid "Help" msgstr "Помощь" #: src/bz-appstream-parser.c:339 msgctxt "Project URL Type" msgid "Donate" msgstr "Пожертвовать" #: src/bz-appstream-parser.c:345 msgctxt "Project URL Type" msgid "Translate" msgstr "Перевод" #: src/bz-appstream-parser.c:349 msgctxt "Project URL Type" msgid "Contact" msgstr "Связаться" #: src/bz-appstream-parser.c:353 msgctxt "Project URL Type" msgid "Source Code" msgstr "Исходный код" #: src/bz-appstream-parser.c:359 msgctxt "Project URL Type" msgid "Contribute" msgstr "Внести вклад" #: src/bz-context-tile-callbacks.c:68 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-context-tile-callbacks.c:75 #, c-format msgid "%.*fM" msgstr "%.*f мил." #. Translators: K is the suffix for thousands #: src/bz-context-tile-callbacks.c:82 #, c-format msgid "%.*fK" msgstr "%.*f тыс." #: src/bz-context-tile-callbacks.c:92 #, c-format msgid "%d downloads in the last month" msgstr "%d загрузок за последний месяц" #: src/bz-context-tile-callbacks.c:104 src/bz-context-tile-callbacks.c:389 #: src/bz-context-tile-callbacks.c:406 msgid "N/A" msgstr "Н/Д" #: src/bz-context-tile-callbacks.c:132 #, c-format msgid "+%s runtime" msgstr "+%s среды выполнения" #: src/bz-context-tile-callbacks.c:135 msgid "Download" msgstr "Скачивание" #: src/bz-context-tile-callbacks.c:155 msgid "Size information unavailable" msgstr "Информация о размере недоступна" #: src/bz-context-tile-callbacks.c:158 #, c-format msgid "Download size of %s" msgstr "Размер скачивания %s" #: src/bz-context-tile-callbacks.c:191 msgid "All Ages" msgstr "Для всех" #: src/bz-context-tile-callbacks.c:203 msgid "Age rating information unavailable" msgstr "Информация о возрастном ограничении недоступна" #: src/bz-context-tile-callbacks.c:208 msgid "Suitable for all ages" msgstr "Предназначено для всех возрастов" #: src/bz-context-tile-callbacks.c:210 #, c-format msgid "Suitable for ages %d and up" msgstr "Предназначено для лиц старше %d лет" #: src/bz-context-tile-callbacks.c:243 src/bz-context-tile-callbacks.c:248 #: src/bz-context-tile-callbacks.c:276 src/bz-context-tile-callbacks.c:284 msgid "Unknown" msgstr "Неизвестно" #: src/bz-context-tile-callbacks.c:253 #, c-format msgid "Free software licensed under %s" msgstr "Свободное программное обеспечение, лицензированное под %s" #: src/bz-context-tile-callbacks.c:258 msgid "Free software" msgstr "Cвободное программное обеспечение" #: src/bz-context-tile-callbacks.c:261 msgid "Proprietary Software" msgstr "Проприетарное программное обеспечение" #: src/bz-context-tile-callbacks.c:264 #, c-format msgid "Special License: %s" msgstr "Специальная лицензия: %s" #: src/bz-context-tile-callbacks.c:281 msgid "Free" msgstr "Свободное" #: src/bz-context-tile-callbacks.c:287 src/bz-license-dialog.c:133 msgid "Proprietary" msgstr "Проприетарное" #: src/bz-context-tile-callbacks.c:289 src/bz-license-dialog.c:135 msgid "Special License" msgstr "Специальная лицензия" #: src/bz-context-tile-callbacks.c:309 msgid "Adaptive" msgstr "Адаптивное" #: src/bz-context-tile-callbacks.c:309 msgid "Desktop Only" msgstr "Только для ПК" #: src/bz-context-tile-callbacks.c:315 msgid "Works on desktop, tablets, and phones" msgstr "Работает на настольных компьютерах, планшетах и телефонах" #: src/bz-context-tile-callbacks.c:316 msgid "May not work on mobile devices" msgstr "Может не работать на мобильных устройствах" #: src/bz-context-tile-callbacks.c:396 src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "Безопасно" #: src/bz-context-tile-callbacks.c:398 src/bz-context-tile-callbacks.c:400 msgid "Low Risk" msgstr "Низкий риск" #: src/bz-context-tile-callbacks.c:402 msgid "Medium Risk" msgstr "Средний риск" #: src/bz-context-tile-callbacks.c:404 msgid "High Risk" msgstr "Высокий риск" #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:68 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:62 #: src/bz-library-page.blp:65 src/bz-user-data-page.blp:86 msgid "Empty" msgstr "Пусто" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "Нет курации" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "Отсутствует информация о курируемых приложениях в данной системе. Вы всё ещё " "можете поискать приложения во вкладке Flathub" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "Открыть Flathub" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "Нет интернета" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 #: src/bz-search-pill-list.c:67 msgid "Browser" msgstr "Браузеры" #: src/bz-developer-badge.c:94 src/bz-developer-badge.c:98 msgid "Not Verified" msgstr "Не подтверждено" #: src/bz-developer-badge.c:210 msgid "Developer information not available." msgstr "Информация о разработчике недоступна." #: src/bz-developer-badge.c:216 src/bz-developer-badge.c:230 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "" "Право собственности на ID приложения %s не было подтверждено, это приложение " "может быть неофициальным." #: src/bz-developer-badge.c:234 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "" "Право собственности на ID приложения %s было подтверждено командой Flathub." #: src/bz-developer-badge.c:250 #, c-format msgid "" "The ownership of the %1$s app ID has been verified by %2$s on " "%3$s." msgstr "" "Право собственности на ID приложения %1$s было подтверждено %2$s на " "%3$s." #: src/bz-developer-badge.c:257 #, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "" "Право собственности на ID приложения %1$s было подтверждено используя %2$s." #: src/bz-developer-badge.c:261 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "Право собственности на ID приложения %s было подтверждено." #: src/bz-donations-dialog.blp:74 msgid "Full Release Notes" msgstr "Полные изменения выпуска" #: src/bz-donations-dialog.blp:108 msgid "This release was made possible by users like you!" msgstr "Этот выпуск был сделан благодаря таким пользователям, как Вы!" #: src/bz-donations-dialog.blp:116 msgid "" "I love making Bazaar, but I cannot do it alone. Help support further " "development by donating on Ko-Fi." msgstr "" "Мне нравится делать Bazaar, но я не могу это делать в одиночку. Поддержите " "дальнейшую разработку пожертвовав средства в мой Ko-Fi." #: src/bz-donations-dialog.blp:131 msgid "Donate to Bazaar" msgstr "Поддержать Bazaar" #. Translators: the %s format specifier will be something along the lines of "0.7.6" etc #: src/bz-donations-dialog.c:227 #, c-format msgid "What's New in %s?" msgstr "Что нового в %s?" #. Translators: this is a release date label, like "Released February 9, 2026" #: src/bz-donations-dialog.c:243 msgid "Released %B %-e, %Y" msgstr "Выпущено %-e %B, %Y" #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "Выбор установки" #: src/bz-entry-group-util.c:76 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "" "Вы установили несколько версий данного приложения. Какое вы хотите выбрать " "для продолжения?" #: src/bz-entry-group-util.c:80 msgid "Cancel" msgstr "Отмена" #: src/bz-entry-selection-row.blp:17 msgid "For This User Only" msgstr "Только для этого пользователя" #: src/bz-entry-selection-row.c:112 msgid "this user" msgstr "этот пользователь" #: src/bz-entry-selection-row.c:112 msgid "all users" msgstr "все пользователи" #: src/bz-error.c:69 src/bz-error.c:88 src/bz-error-dialog.blp:36 #: src/bz-safety-dialog.blp:50 msgid "Details" msgstr "Детали" #: src/bz-error-dialog.blp:47 msgid "Copy" msgstr "Скопировать" #: src/bz-error-dialog.c:56 src/bz-share-list.c:62 msgid "Copied!" msgstr "Скопировано!" #: src/bz-favorite-button.c:388 msgid "Failed to update favorite" msgstr "Не удалось добавить в избранные" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "Войдите в Flathub для управления избранными приложениями" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "Войти" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "Число избранных" #: src/bz-favorites-tile.c:357 msgid "Failed to remove favorite" msgstr "Не удалось удалить из избранных" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:78 msgid "Support This Application" msgstr "Поддержать это приложение" #: src/bz-favorites-tile.blp:119 msgid "Remove From Favorites" msgstr "Удалить из избранных" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:78 #: src/bz-window.blp:386 msgid "Favorites" msgstr "Избранные" #: src/bz-favorites-page.blp:17 src/bz-section-view.blp:144 msgid "Install All" msgstr "Установить все" #: src/bz-favorites-page.blp:34 src/bz-full-view.blp:45 src/bz-window.blp:255 msgid "Open App Library" msgstr "Открыть библиотеку приложений" #: src/bz-favorites-page.blp:56 src/bz-user-data-page.blp:75 msgid "Loading" msgstr "Загрузка" #: src/bz-favorites-page.blp:71 msgid "No Favorites" msgstr "Нет избранных" #: src/bz-favorites-page.blp:72 msgid "Applications you mark as favorite will appear here" msgstr "Приложения помеченные как избранные будут показаны здесь" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "Предыдущий" #: src/bz-featured-carousel.blp:54 msgid "Next" msgstr "Следующий" #: src/bz-featured-tile.blp:90 msgid "App of the Day" msgstr "Приложение дня" #: src/bz-flathub-category.c:93 msgid "Editing" msgstr "Монтаж" #: src/bz-flathub-category.c:94 msgid "Midi" msgstr "Midi" #: src/bz-flathub-category.c:95 msgid "Mixer" msgstr "Микшеры" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-flathub-category.c:96 src/bz-search-pill-list.c:77 msgid "Music" msgstr "Музыка" #: src/bz-flathub-category.c:97 msgid "Player" msgstr "Проигрыватели" #: src/bz-flathub-category.c:98 msgid "Recorder" msgstr "Звукозапись" #: src/bz-flathub-category.c:99 msgid "Sequencer" msgstr "Секвенсоры" #: src/bz-flathub-category.c:100 msgid "Tuner" msgstr "Тюнеры" #: src/bz-flathub-category.c:101 msgid "TV" msgstr "ТВ" #: src/bz-flathub-category.c:106 msgid "Emulation" msgstr "Эмуляторы" #: src/bz-flathub-category.c:107 msgid "Action" msgstr "Экшен" #: src/bz-flathub-category.c:108 msgid "Adventure" msgstr "Приключения" #: src/bz-flathub-category.c:109 msgid "Arcade" msgstr "Аркады" #: src/bz-flathub-category.c:110 msgid "Blocks" msgstr "Блоки" #: src/bz-flathub-category.c:111 msgid "Board" msgstr "Настольные" #: src/bz-flathub-category.c:112 msgid "Card" msgstr "Карточные" #: src/bz-flathub-category.c:113 msgid "Kids" msgstr "Для детей" #: src/bz-flathub-category.c:114 msgid "Logic" msgstr "Логические" #: src/bz-flathub-category.c:115 msgid "Role Playing" msgstr "Ролевые" #: src/bz-flathub-category.c:116 msgid "Shooter" msgstr "Шутеры" #: src/bz-flathub-category.c:117 msgid "Simulation" msgstr "Симуляторы" #: src/bz-flathub-category.c:118 msgid "Sports" msgstr "Спортивные" #: src/bz-flathub-category.c:119 msgid "Strategy" msgstr "Стратегии" #: src/bz-flathub-category.c:124 msgid "Audio & Video" msgstr "Аудио и видео" #: src/bz-flathub-category.c:124 msgid "Media" msgstr "Медиа" #: src/bz-flathub-category.c:124 msgid "More Audio & Video" msgstr "Больше приложений для аудио и видео" #: src/bz-flathub-category.c:125 msgid "Developer Tools" msgstr "Инструменты разработчика" #: src/bz-flathub-category.c:125 msgid "Develop" msgstr "Разработчикам" #: src/bz-flathub-category.c:125 msgid "More Developer Tools" msgstr "Больше приложений для разработки" #: src/bz-flathub-category.c:126 msgid "Education" msgstr "Образование" #: src/bz-flathub-category.c:126 msgid "Learn" msgstr "Обучение" #: src/bz-flathub-category.c:126 msgid "More Education" msgstr "Больше образовательных приложений" #: src/bz-flathub-category.c:127 msgid "Gaming" msgstr "Игры" #: src/bz-flathub-category.c:127 msgid "Play" msgstr "Игры" #: src/bz-flathub-category.c:127 msgid "More Gaming" msgstr "Больше игр" #: src/bz-flathub-category.c:128 msgid "Graphics & Photography" msgstr "Графика и фотография" #: src/bz-flathub-category.c:128 msgid "Create" msgstr "Творение" #: src/bz-flathub-category.c:128 msgid "More Graphics & Photography" msgstr "Больше приложений для графики" #: src/bz-flathub-category.c:129 msgid "Networking" msgstr "Сеть" #: src/bz-flathub-category.c:129 msgid "Internet" msgstr "Сеть" #: src/bz-flathub-category.c:129 msgid "More Networking" msgstr "Больше сетевых приложений" #: src/bz-flathub-category.c:130 msgid "Productivity" msgstr "Продуктивность" #: src/bz-flathub-category.c:130 msgid "Work" msgstr "Работа" #: src/bz-flathub-category.c:130 msgid "More Productivity" msgstr "Больше приложений для продуктивности" #: src/bz-flathub-category.c:131 msgid "Science" msgstr "Наука" #: src/bz-flathub-category.c:131 msgid "More Science" msgstr "Больше научных приложений" #: src/bz-flathub-category.c:132 msgid "System" msgstr "Система" #: src/bz-flathub-category.c:132 msgid "More System" msgstr "Больше системных приложений" #: src/bz-flathub-category.c:133 msgid "Utilities" msgstr "Утилиты" #: src/bz-flathub-category.c:133 msgid "Tools" msgstr "Утилиты" #: src/bz-flathub-category.c:133 msgid "More Utilities" msgstr "Больше утилит" #: src/bz-flathub-category.c:134 src/bz-flathub-page.blp:116 #: src/bz-flathub-page.blp:148 msgid "Trending" msgstr "В тренде" #: src/bz-flathub-category.c:134 msgid "More Trending" msgstr "Больше трендовых" #: src/bz-flathub-category.c:135 src/bz-flathub-page.blp:122 #: src/bz-flathub-page.blp:178 msgid "Popular" msgstr "Популярное" #: src/bz-flathub-category.c:135 msgid "More Popular" msgstr "Больше популярных" #: src/bz-flathub-category.c:136 src/bz-flathub-page.blp:168 msgid "Recently Added" msgstr "Недавно добавленные" #: src/bz-flathub-category.c:136 src/bz-flathub-page.blp:128 msgid "New" msgstr "Новое" #: src/bz-flathub-category.c:136 msgid "More New" msgstr "Больше новинок" #: src/bz-flathub-category.c:137 src/bz-flathub-page.blp:158 msgid "Recently Updated" msgstr "Недавно обновленные" #: src/bz-flathub-category.c:137 src/bz-flathub-page.blp:134 msgid "Updated" msgstr "Обновлённые" #: src/bz-flathub-category.c:137 msgid "More Updated" msgstr "Больше обновленных" #: src/bz-flathub-category.c:138 msgid "Mobile" msgstr "Мобильные" #: src/bz-flathub-category.c:138 msgid "More Mobile" msgstr "Больше мобильных приложений" #: src/bz-flathub-category.c:139 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:139 msgid "More Adwaita" msgstr "Больше Adwaita" #: src/bz-flathub-category.c:140 msgid "KDE Apps" msgstr "KDE приложения" #: src/bz-flathub-category.c:140 msgid "More KDE Apps" msgstr "Больше приложений к KDE" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Flathub не добавлен" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "Репозиторий Flathub не был найден среди ваших flatpak установок" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "Flathub вернул ошибку" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "Повторить подключение к Flathub" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Flathub недоступен" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" "Мы не можем подключиться к Flathub. Вы всё ещё можете управлять приложениями " "и искать их." #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "Поиск приложений" #: src/bz-flathub-page.blp:255 msgid "On the Go" msgstr "Всегда под рукой" #: src/bz-flathub-page.blp:267 msgid "Apps for your Linux phones and tablets" msgstr "Приложения для ваших телефонов и планшетов на Linux" #: src/bz-flathub-page.blp:278 src/bz-flathub-page.blp:313 msgid "More Mobile Apps" msgstr "Больше мобильных приложений" #: src/bz-flathub-page.blp:369 msgid "We​ ♥​ Games" msgstr "Мы ♥ Игры" #: src/bz-flathub-page.blp:382 msgid "Games and apps to run your favorite titles" msgstr "Игры и приложения для запуска ваших любимых тайтлов" #: src/bz-flathub-page.blp:416 msgid "More Games" msgstr "Больше игр" #: src/bz-full-view.blp:66 src/bz-library-page.blp:76 #: src/bz-library-page.blp:80 msgid "No Results" msgstr "Нет результатов" #: src/bz-full-view.blp:67 msgid "Try a different search query" msgstr "Попробуйте выполнить другой поисковый запрос" #: src/bz-full-view.blp:73 msgid "Content" msgstr "Содержимое" #: src/bz-full-view.blp:131 msgid "Installing .flatpak bundles is not yet supported" msgstr "Установка пакетов .flatpak пока не поддерживается" #: src/bz-full-view.blp:257 msgid "_Support" msgstr "_Поддержать" #: src/bz-full-view.blp:475 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "Это приложение использует среду выполнения, которая больше не получает " "обновления или исправления ошибок безопасности. Оно может стать небезопасным " "для использования." #: src/bz-full-view.blp:562 msgid "Trash Data" msgstr "Отправить в корзину" #: src/bz-full-view.blp:702 msgid "Tags:" msgstr "Метки:" #: src/bz-full-view.c:189 msgid "No URL" msgstr "Нет URL" #: src/bz-full-view.c:207 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Это приложение имеет лицензию FLOSS, что значит исходный код может быть " "проверен на безопасность." #: src/bz-full-view.c:208 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Это приложение имеет проприетарную лицензию, что значит исходный код " "разрабатывается в тайне и не может быть проверен независимой третьей " "стороной." #: src/bz-full-view.c:215 msgid "More Apps" msgstr "Больше приложений" #: src/bz-full-view.c:216 #, c-format msgid "More Apps by %s" msgstr "Больше приложений от %s" #: src/bz-full-view.c:223 msgid "Other Apps by this Developer" msgstr "Другие приложения от этого разработчика" #: src/bz-full-view.c:225 src/bz-full-view.c:324 #, c-format msgid "Other Apps by %s" msgstr "Другие приложения от %s" #: src/bz-full-view.c:234 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "" "%s не установлено, но пользовательские данные в размере %s ещё " "присутствуют." #: src/bz-full-view.c:326 msgid "Other Apps" msgstr "Другие приложения" #: src/bz-full-view.c:328 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d приложение" msgstr[1] "%d приложения" msgstr[2] "%d приложений" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 msgid "Hardware Support" msgstr "Поддержка оборудования" #: src/bz-hardware-support-dialog.c:62 msgid "Keyboard support" msgstr "Поддержка клавиатуры" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "Требуется использовать клавиатуру" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "Рекомендуется использовать клавиатуру" #: src/bz-hardware-support-dialog.c:66 msgid "Supports keyboards" msgstr "Поддерживает клавиатуру" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "Неизвестная поддержка клавиатуры" #: src/bz-hardware-support-dialog.c:69 msgid "Mouse support" msgstr "Поддержка мыши" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "Требуется использовать мышь или указательные устройства" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "Рекомендуется использовать мышь или указательные устройства" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "Поддерживает мышь или указательные устройства" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "Неизвестная поддержка мыши и указательных устройств" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "Поддержка сенсорного экрана" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "Требуется использовать сенсорный экран" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "Рекомендуется использовать сенсорный экран" #: src/bz-hardware-support-dialog.c:80 msgid "Supports touchscreens" msgstr "Поддерживает сенсорные экраны" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "Неизвестная поддержка сенсорных экран" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "Поддержка мобильных устройств" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "Работает на мобильных устройствах" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "Может не работать хорошо на мобильных устройствах" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "Поддержка настольных компьютеров" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "Работает хорошо на больших экранах" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "%s работает лучше на определённых устройствах" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "%s работает на большинстве устройств" #: src/bz-install-controls.blp:34 src/bz-transaction-dialog.c:202 msgid "_Install" msgstr "_Установить" #: src/bz-install-controls.blp:60 msgid "_Open" msgstr "_Открыть" #: src/bz-install-controls.blp:75 src/bz-install-controls.blp:131 msgid "Uninstall Application" msgstr "Удалить приложение" #: src/bz-install-controls.blp:85 src/bz-transaction-dialog.c:231 msgid "_Remove" msgstr "_Удалить" #: src/bz-install-controls.blp:118 src/bz-updates-card.c:161 #: src/bz-updates-card.c:180 msgid "Update" msgstr "Обновить" #: src/bz-library-page.blp:31 msgid "Search installed apps" msgstr "Поиск установленных приложений" #: src/bz-library-page.blp:48 msgid "Clear search" msgstr "Очистить поиск" #: src/bz-library-page.blp:69 msgid "No Apps Found" msgstr "Приложение не найдено" #. Translators: . #: src/bz-library-page.blp:98 src/bz-window.blp:112 msgid "Library" msgstr "Библиотека" #: src/bz-library-page.blp:126 msgid "Pending Updates" msgstr "Ожидают обновления" #: src/bz-library-page.blp:153 msgid "Downloads" msgstr "Загрузки" #: src/bz-library-page.blp:196 msgid "Recently Uninstalled" msgstr "Недавно удалённые" #: src/bz-library-page.blp:247 msgid "Clear Finished Tasks" msgstr "Очистить выполненные задачи" #: src/bz-library-page.blp:260 msgid "Installed Apps" msgstr "Установленные приложения" #: src/bz-library-page.blp:332 msgid "Sort By" msgstr "Сортирововать" #: src/bz-library-page.blp:346 msgid "Name" msgstr "Название" #: src/bz-library-page.blp:352 msgid "Size" msgstr "Размер" #: src/bz-library-page.c:180 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "Нет результатов по запросу \"%s\" в списке установленных приложений" #: src/bz-library-page.c:193 src/bz-updates-card.c:426 #, c-format msgid "%u Available Update" msgid_plural "%u Available Updates" msgstr[0] "Доступно %u обновление" msgstr[1] "Доступно %u обновления" msgstr[2] "Доступно %u обновлений" #: src/bz-license-dialog.blp:94 msgid "Get Involved" msgstr "Внести вклад" #: src/bz-license-dialog.blp:111 msgid "Learn More" msgstr "Узнать больше" #: src/bz-license-dialog.c:127 msgid "Unknown License" msgstr "Неизвестная лицензия" #: src/bz-license-dialog.c:130 msgid "Community Built" msgstr "Сделано сообществом" #: src/bz-license-dialog.c:203 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Это приложение разрабатывается открыто международным сообществом.\n" "\n" "Вы можете внести свой вклад и сделать это приложение ещё лучше." #: src/bz-license-dialog.c:206 msgid "The license of this app is not known" msgstr "Лицензия этого приложения неизвестна" #: src/bz-license-dialog.c:212 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Это приложение открыто разрабатывается международным сообществом и " "выпускается под лицензией %s.\n" "\n" "Вы можете внести свой вклад и сделать это приложение ещё лучше." #: src/bz-license-dialog.c:220 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Это приложение не разрабатывается открыто, поэтому только его разработчики " "знают как оно работает. Оно может быть небезопасным в некоторых местах, " "которые сложно опознать, и оно может измениться без предупреждения.\n" "\n" "Вы можете не иметь возможности внести вклад в это приложение." #: src/bz-license-dialog.c:226 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Это приложение разрабатывается под специальной лицензией %s.\n" "\n" "Вы можете не иметь возможности внести вклад в это приложение." #: src/bz-license-dialog.c:356 src/bz-safety-dialog.blp:53 msgid "License" msgstr "Лицензия" #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 msgid "Connect to Flathub" msgstr "Подключение к Flathub" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "Что-то пошло не так" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "" "Подключитесь к своему аккаунту Flathub в Bazaar для управления вашими " "избранными приложениями." #: src/bz-login-page.blp:110 msgid "Finish" msgstr "Завершить" #: src/bz-login-page.c:664 #, c-format msgid "Hello, %s!" msgstr "Приветствуем, %s!" #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Параметры" #: src/bz-preferences-dialog.blp:25 msgid "Network connection is metered — automatic store data refresh is paused" msgstr "" "Сетевое соединение ограничено — автоматическое обновление данных магазина " "приостановлена" #: src/bz-preferences-dialog.blp:26 src/bz-window.blp:282 msgid "Refresh Manually" msgstr "Обновить вручную" #: src/bz-preferences-dialog.blp:31 msgid "Content Filters" msgstr "Фильтры содержимого" #: src/bz-preferences-dialog.blp:34 msgid "Free Software Only" msgstr "Только свободные приложения" #: src/bz-preferences-dialog.blp:35 msgid "Hide proprietary applications when browsing and searching" msgstr "Скрыть проприетарные приложения при обзоре и поиске" #: src/bz-preferences-dialog.blp:39 msgid "Flathub Results Only" msgstr "Только результаты из Flathub" #: src/bz-preferences-dialog.blp:40 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "Ограничить обзор и результаты поиска только приложениями из Flathub" #: src/bz-preferences-dialog.blp:44 msgid "Verified Results Only" msgstr "Только подтверждённые результаты" #: src/bz-preferences-dialog.blp:45 msgid "Hide results that are not verified on Flathub" msgstr "Скрыть приложения, которые не являются подтверждёнными на Flathub" #: src/bz-preferences-dialog.blp:49 msgid "Hide EOL Apps" msgstr "Скрыть неподдерживаемые приложения" #: src/bz-preferences-dialog.blp:50 msgid "Hide apps which are no longer supported by their developers" msgstr "Скрыть приложения, которые больше не поддерживаются разработчиками" #: src/bz-preferences-dialog.blp:55 src/bz-window.blp:127 msgid "Search" msgstr "Поиск" #: src/bz-preferences-dialog.blp:58 msgid "Delay Search Results" msgstr "Увеличить задержку результатов поиска" #: src/bz-preferences-dialog.blp:59 msgid "Improve results performance by debouncing search terms" msgstr "" "Улучшить производительность показа результатов благодаря увеличению задержки " "ввода запроса" #: src/bz-preferences-dialog.blp:64 msgid "Progress Bar" msgstr "Полоса прогресса" #: src/bz-preferences-dialog.blp:65 msgid "Choose a theme for the progress bar!" msgstr "Выберите тему для полосы прогресса!" #: src/bz-preferences-dialog.blp:89 msgid "Vertical Stripes" msgstr "Вертикальные полосы" #: src/bz-preferences-dialog.blp:90 msgid "Display flag colors from left to right" msgstr "Отображать цвета флагов слева направо" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Цвет акцента" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Цвета гордости" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "Цвета гордости лесбиянок" #: src/bz-preferences-dialog.c:35 msgid "Male Homosexual Pride Colors" msgstr "Цвета гордости мужчин гомосексуалов" #: src/bz-preferences-dialog.c:36 msgid "Transgender Pride Colors" msgstr "Цвета гордости трансгендеров" #: src/bz-preferences-dialog.c:37 msgid "Nonbinary Pride Colors" msgstr "Цвета гордости небинарных" #: src/bz-preferences-dialog.c:38 msgid "Bisexual Pride Colors" msgstr "Цвета гордости бисексуалов" #: src/bz-preferences-dialog.c:39 msgid "Asexual Pride Colors" msgstr "Цвета гордости асексуалов" #: src/bz-preferences-dialog.c:40 msgid "Pansexual Pride Colors" msgstr "Цвета гордости пансексуалов" #: src/bz-preferences-dialog.c:41 msgid "Aromantic Pride Colors" msgstr "Цвета гордости аромантиков" #: src/bz-preferences-dialog.c:42 msgid "Genderfluid Pride Colors" msgstr "Цвета гордости гендерфлюид" #: src/bz-preferences-dialog.c:43 msgid "Polysexual Pride Colors" msgstr "Цвета гордости полисексуалов" #: src/bz-preferences-dialog.c:44 msgid "Omnisexual Pride Colors" msgstr "Цвета гордости омнисексуалов" #: src/bz-preferences-dialog.c:45 msgid "Aroace Pride Colors" msgstr "Цвета гордости ароэйс" #: src/bz-preferences-dialog.c:46 msgid "Agender Pride Colors" msgstr "Цвета гордости агендеров" #: src/bz-preferences-dialog.c:47 msgid "Genderqueer Pride Colors" msgstr "Цвета гордости гендерквиров" #: src/bz-preferences-dialog.c:48 msgid "Intersex Pride Colors" msgstr "Цвета гордости интерсекс" #: src/bz-preferences-dialog.c:49 msgid "Demigender Pride Colors" msgstr "Цвета гордости демигендеров" #: src/bz-preferences-dialog.c:50 msgid "Biromantic Pride Colors" msgstr "Цвета гордости биромантиков" #: src/bz-preferences-dialog.c:51 msgid "Disability Pride Colors" msgstr "Цвета гордости людей с ограниченными возможностями" #: src/bz-preferences-dialog.c:52 msgid "Femboy Pride Colors" msgstr "Цвета гордости фембоев" #: src/bz-preferences-dialog.c:53 msgid "Neutrois Pride Colors" msgstr "Цвета гордости нейтроис" #: src/bz-releases-dialog.blp:5 src/bz-updates-card.c:152 msgid "Version History" msgstr "История версий" #: src/bz-releases-list.blp:27 msgid "_Version History" msgstr "_История версий" #. Translators: something happened less than a day ago #: src/bz-releases-list.c:122 msgid "Today" msgstr "Сегодня" #. Translators: something happened more than a day ago but less than 2 days ago #: src/bz-releases-list.c:125 msgid "Yesterday" msgstr "Вчера" #. Translators: something happened days ago #: src/bz-releases-list.c:128 #, c-format msgid "%d day ago" msgid_plural "%d days ago" msgstr[0] "%d день назад" msgstr[1] "%d дня назад" msgstr[2] "%d дней назад" #. Translators: something happened weeks ago #: src/bz-releases-list.c:131 #, c-format msgid "%d week ago" msgid_plural "%d weeks ago" msgstr[0] "%d неделю назад" msgstr[1] "%d недели назад" msgstr[2] "%d недель назад" #. Translators: something happened months ago #: src/bz-releases-list.c:134 #, c-format msgid "%d month ago" msgid_plural "%d months ago" msgstr[0] "%d месяц назад" msgstr[1] "%d месяца назад" msgstr[2] "%d месяцев назад" #. Translators: something happened years ago #: src/bz-releases-list.c:137 #, c-format msgid "%d year ago" msgid_plural "%d years ago" msgstr[0] "%d год назад" msgstr[1] "%d года назад" msgstr[2] "%d лет назад" #. TRANSLATORS: This is the date string with: day number, month name, year. #. i.e. "22 March 2026" #: src/bz-releases-list.c:155 msgid "%e %B %Y" msgstr "%e %B %Y" #: src/bz-releases-list.c:195 #, c-format msgid "Version %s" msgstr "Версия %s" #: src/bz-releases-list.c:250 msgid "No details for this release" msgstr "Нет подробностей" #: src/bz-releases-list.c:262 msgid "Get More Information" msgstr "Получить дополнительную информацию" #: src/bz-rich-app-tile.blp:157 msgid "Get" msgstr "Скачать" #: src/bz-safety-calculator.c:82 msgid "Unknown Permissions" msgstr "Неизвестные разрешения" #: src/bz-safety-calculator.c:83 msgid "Permissions are missing for this app." msgstr "Разрешения для этого приложения отсутствуют." #: src/bz-safety-calculator.c:96 msgid "No Permissions" msgstr "Нет разрешений" #: src/bz-safety-calculator.c:97 msgid "App is fully sandboxed" msgstr "Приложение полностью изолировано" #: src/bz-safety-calculator.c:103 msgid "Network Access" msgstr "Доступ к сети" #: src/bz-safety-calculator.c:104 msgid "Can access the internet" msgstr "Может получить доступ к интернету" #: src/bz-safety-calculator.c:106 msgid "No Network Access" msgstr "Нет доступа к сети" #: src/bz-safety-calculator.c:107 msgid "Cannot access the internet" msgstr "Не может получить доступ к интернету" #: src/bz-safety-calculator.c:112 msgid "User Device Access" msgstr "Доступ к устройствам пользователя" #: src/bz-safety-calculator.c:113 msgid "Can access devices such as webcams or gaming controllers" msgstr "" "Может получить доступ к таким устройствам, как веб-камеры или игровые " "контроллеры" #: src/bz-safety-calculator.c:115 msgid "No User Device Access" msgstr "Нет доступа к устройствам пользователя" #: src/bz-safety-calculator.c:116 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "" "Не может получить доступ к таким устройствам, как веб-камеры или игровые " "контроллеры" #: src/bz-safety-calculator.c:121 msgid "Input Device Access" msgstr "Доступ к устройствам ввода" #: src/bz-safety-calculator.c:122 msgid "Can access input devices" msgstr "Может получить доступ к устройствам ввода" #: src/bz-safety-calculator.c:128 msgid "Microphone Access and Audio Playback" msgstr "Доступ к микрофону и воспроизведение звука" #: src/bz-safety-calculator.c:129 msgid "Can listen using microphones and play audio without asking permission" msgstr "Может слышать с помощью микрофона и воспроизводить звук без разрешения" #: src/bz-safety-calculator.c:135 msgid "System Device Access" msgstr "Доступ к системным устройствам" #: src/bz-safety-calculator.c:136 msgid "Can access system devices which require elevated permissions" msgstr "" "Может получить доступ к системным устройствам, требующие повышенные " "разрешения" #: src/bz-safety-calculator.c:142 msgid "Screen Contents Access" msgstr "Доступ к содержимому экрана" #: src/bz-safety-calculator.c:143 msgid "Can access the contents of the screen or other windows" msgstr "Может получить доступ к содержимому экрана или других окон" #: src/bz-safety-calculator.c:149 msgid "Legacy Windowing System" msgstr "Устаревшая оконная система" #: src/bz-safety-calculator.c:150 msgid "Always uses a legacy windowing system (X11)" msgstr "Использует устаревшую оконную систему постоянно (X11)" #: src/bz-safety-calculator.c:156 msgid "Arbitrary Permissions" msgstr "Произвольные разрешения" #: src/bz-safety-calculator.c:157 msgid "Can acquire arbitrary permissions" msgstr "Может получить произвольные разрешения" #: src/bz-safety-calculator.c:163 msgid "User Settings" msgstr "Пользовательские настройки" #: src/bz-safety-calculator.c:164 msgid "Can access and change user settings" msgstr "Может получить и изменить пользовательские настройки" #: src/bz-safety-calculator.c:170 msgid "Full File System Read/Write Access" msgstr "Полный доступ к файловой системе на чтение/запись" #: src/bz-safety-calculator.c:171 msgid "Can read and write all data on the file system" msgstr "Может читать и записывать все данные в файловой системе" #: src/bz-safety-calculator.c:178 msgid "Home Folder Read/Write Access" msgstr "Доступ к домашней папке для чтения/записи" #: src/bz-safety-calculator.c:179 msgid "Can read and write all data in your home directory" msgstr "Может читать и записывать все данные в вашей домашней папке" #: src/bz-safety-calculator.c:186 msgid "Full File System Read Access" msgstr "Полный доступ к файловой системе на чтение" #: src/bz-safety-calculator.c:187 msgid "Can read all data on the file system" msgstr "Может читать все данные в файловой системе" #: src/bz-safety-calculator.c:195 msgid "Home Folder Read Access" msgstr "Доступ на чтение домашней папки" #: src/bz-safety-calculator.c:196 msgid "Can read all data in your home directory" msgstr "Может читать все данные в вашей домашней папке" #: src/bz-safety-calculator.c:204 msgid "Download Folder Read/Write Access" msgstr "Доступ для чтения/записи в папку загрузки" #: src/bz-safety-calculator.c:205 msgid "Can read and write all data in your downloads directory" msgstr "Может читать и записывать все данные в вашей папке загрузки" #: src/bz-safety-calculator.c:215 msgid "Download Folder Read Access" msgstr "Доступ на чтение папки загрузки" #: src/bz-safety-calculator.c:216 msgid "Can read all data in your downloads directory" msgstr "Может читать все данные в вашей папке загрузки" #: src/bz-safety-calculator.c:229 msgid "Can read and write all data in the directory" msgstr "Может читать и записывать все данные в папке" #: src/bz-safety-calculator.c:243 msgid "Can read all data in the directory" msgstr "Может читать все данные в папке" #: src/bz-safety-calculator.c:258 msgid "No File System Access" msgstr "Нет доступа к файловой системе" #: src/bz-safety-calculator.c:259 msgid "Cannot access the file system at all" msgstr "Не может получить доступ к файловой системе" #: src/bz-safety-calculator.c:266 msgid "Uses System Services" msgstr "Использует системные службы" #: src/bz-safety-calculator.c:267 msgid "Can request data from non-portal system services" msgstr "Может запрашивать данные у системных служб, не относящихся к порталу" #: src/bz-safety-calculator.c:273 msgid "Uses Session Services" msgstr "Использует службы сеанса" #: src/bz-safety-calculator.c:274 msgid "Can request data from non-portal session services" msgstr "Может запрашивать данные у служб сеанса, не относящихся к порталу" #: src/bz-safety-calculator.c:322 msgid "No Service Access" msgstr "Нет доступа к службе" #: src/bz-safety-calculator.c:323 msgid "Cannot access non-portal session or system services at all" msgstr "" "Не может получить доступ к службам сеанса или системным, не относящимся к " "порталу" #: src/bz-safety-calculator.c:331 msgid "Verified App Developer" msgstr "Подтверждённый разработчик приложения" #: src/bz-safety-calculator.c:332 msgid "The developer of this app has been verified to be who they say they are" msgstr "" "Разработчик этого приложения подтвердил, что является тем, за кого себя " "выдает" #: src/bz-safety-calculator.c:341 msgid "Proprietary Code" msgstr "Проприетарный код" #: src/bz-safety-calculator.c:342 msgid "" "The source code is not public, so it cannot be independently audited and " "might be unsafe" msgstr "" "Исходный код не является открытым, поэтому не может быть подвергнут " "независимому аудиту и может быть небезопасным" #: src/bz-safety-calculator.c:352 msgid "Auditable Code" msgstr "Проверяемый код" #: src/bz-safety-calculator.c:353 msgid "" "The source code is public and can be independently audited, which makes the " "app more likely to be safe" msgstr "" "Исходный код является открытым и может быть подвергнут независимому аудиту, " "что повышает вероятность того, что приложение безопасно" #: src/bz-safety-calculator.c:493 #, c-format msgid "Use the %s System Service" msgstr "Использует системную службу %s" #: src/bz-safety-calculator.c:497 #, c-format msgid "Use the %s Session Service" msgstr "Использует службу сеанса %s" #: src/bz-safety-calculator.c:501 #, c-format msgid "Use the %s Service" msgstr "Использует службу %s" #: src/bz-safety-calculator.c:511 msgid "Can see the non-portal service" msgstr "Может просматривать службу, не относящуюся к порталу" #: src/bz-safety-calculator.c:513 msgid "Can talk to the non-portal service" msgstr "Может связаться со службой, не относящейся к порталу" #: src/bz-safety-calculator.c:515 msgid "Can own the non-portal service" msgstr "Может быть владельцем службы, не относящейся к порталу" #: src/bz-safety-calculator.c:530 msgid "Global Menu Integration" msgstr "Интеграция с глобальным меню" #: src/bz-safety-calculator.c:531 msgid "Can display its menus in a global menu bar" msgstr "Может показывать своё меню в глобальной полосе меню" #: src/bz-safety-calculator.c:536 msgid "KDE Settings Integration" msgstr "Интеграция с настройками KDE" #: src/bz-safety-calculator.c:537 msgid "Can detect when KDE desktop settings change" msgstr "Может определять изменение в настройках рабочего стола KDE" #: src/bz-safety-calculator.c:542 msgid "KDE Global Settings" msgstr "Глобальные параметры KDE" #: src/bz-safety-calculator.c:543 msgid "Can read KDE desktop preferences like fonts and colors" msgstr "Может читать параметры рабочего стола KDE как шрифты и цвета" #: src/bz-safety-calculator.c:548 msgid "Secret Storage Service" msgstr "Служба хранения секретов" #: src/bz-safety-calculator.c:549 msgid "Can store and retrieve its own passwords using the system keyring" msgstr "Может хранить и извлекать свои пароли используя системные ключи" #: src/bz-safety-calculator.c:554 msgid "Desktop Notifications Service" msgstr "Служба уведомлений рабочего стола" #: src/bz-safety-calculator.c:555 msgid "Can send desktop notifications" msgstr "Может отправлять уведомления на рабочий стол" #: src/bz-safety-calculator.c:561 msgid "System Tray Integration" msgstr "Интеграция с системным треем" #: src/bz-safety-calculator.c:562 msgid "Can display an icon in the system tray" msgstr "Может отображать иконку в системном треем" #: src/bz-safety-calculator.c:567 msgid "KDE Connect Integration" msgstr "Интеграция с KDE Connect" #: src/bz-safety-calculator.c:568 msgid "Can interact with devices paired via KDE Connect" msgstr "Может взаимодействовать с устройстами привязанным к KDE Connect" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "Безопасность" #: src/bz-safety-dialog.blp:63 msgid "App ID" msgstr "ID приложения" #: src/bz-safety-dialog.blp:73 msgid "SDK" msgstr "SDK" #: src/bz-safety-dialog.blp:104 msgid "" "This app uses an outdated version of the software platform (SDK) and might " "contain bugs or security vulnerabilities which will not be fixed." msgstr "" "Это приложение использует устаревшую версию платформа для разработки (SDK) и " "может иметь баги или уязвимости безопасности которые не были исправлены." #: src/bz-safety-dialog.c:227 #, c-format msgid "%s is Safe" msgstr "%s безопасное" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s has no Unsafe Permissions" msgstr "%s имеет небезопасные разрешения" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Probably Safe" msgstr "%s вероятно безопасное" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Possibly Unsafe" msgstr "%s вероятно небезопасное" #: src/bz-safety-dialog.c:247 #, c-format msgid "%s is Unsafe" msgstr "%s небезопасное" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "Скриншоты" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "Предыдущий скриншот" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "Следующий скриншот" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "Скопировать изображение" #: src/bz-screenshot-page.blp:150 msgid "Reset View" msgstr "Возобновить вид" #: src/bz-screenshot-page.blp:161 msgid "Zoom Out" msgstr "Отдалить" #: src/bz-screenshot-page.blp:171 msgid "Zoom In" msgstr "Приблизить" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "Карусель скриншотов" #: src/bz-screenshots-carousel.blp:117 msgid "Open Screenshot Viewer" msgstr "Открыть просмотрщик скриншотов" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:72 msgid "Video" msgstr "Видео" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:82 msgid "Office" msgstr "Офис" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:87 msgid "PDF" msgstr "PDF" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:92 msgid "Calendar" msgstr "Календарь" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:97 msgid "Messaging" msgstr "Общение" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:102 msgid "Steam" msgstr "Steam" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:107 msgid "Paint" msgstr "Рисование" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:112 msgid "VPN" msgstr "VPN" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:117 msgid "Torrent" msgstr "Торрент" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:122 msgid "Minecraft" msgstr "Minecraft" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:127 msgid "Emulator" msgstr "Эмуляторы" #: src/bz-search-filter-popover.blp:18 src/bz-search-page.blp:82 msgid "Filters" msgstr "Фильтры" #: src/bz-search-filter-popover.blp:35 msgid "_Verified" msgstr "_Подтвержденные" #: src/bz-search-filter-popover.blp:42 msgid "_Free/Open" msgstr "_Свободные" #: src/bz-search-filter-popover.blp:49 msgid "Non-_EOL" msgstr "П_оддерживаемые" #: src/bz-search-filter-popover.blp:56 msgid "Categories" msgstr "Категории" #: src/bz-search-page.blp:57 msgid "Search Apps, Games, Software" msgstr "Поиск приложений, игр, ПО" #: src/bz-search-page.blp:69 msgid "Search Filters" msgstr "Фильтры поиска" #: src/bz-search-page.blp:99 msgid "Clear Search" msgstr "Очистить поиск" #: src/bz-search-page.blp:191 msgid "Categories Unavailable" msgstr "Категории недоступны" #: src/bz-search-page.blp:192 msgid "Search for apps using the search bar above." msgstr "Попробуйте поискать приложения используя поле ввода запроса выше." #: src/bz-search-page.blp:218 msgid "Browse Categories" msgstr "Обзор категорий" #: src/bz-search-page.blp:360 msgid "No Applications Found" msgstr "Приложение не найдено" #: src/bz-search-page.c:247 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "Нет результатов по запросу \"%s\" в Flathub" #: src/bz-share-list.c:123 msgid "Copy Link" msgstr "Скопировать ссылку" #: src/bz-share-list.c:134 msgid "Open Link" msgstr "Открыть ссылку" #: src/bz-stats-dialog.blp:27 msgid "Timeline" msgstr "Временная шкала" #: src/bz-stats-dialog.blp:45 msgid "Installs:" msgstr "Установок:" #: src/bz-stats-dialog.blp:54 msgid "World" msgstr "Карта мира" #: src/bz-stats-dialog.blp:68 msgid "Since 4/15/2024" msgstr "С 15 апреля 2024" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:125 #, c-format msgid "%.2fM Total Installs" msgstr "%.2f миллионов общих установок" #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:128 #, c-format msgid "%.2fK Total Installs" msgstr "%.2f тысяч общих установок" #: src/bz-stats-dialog.c:130 #, c-format msgid "%'d Total Installs" msgstr "%'d общих установок" #: src/bz-tag-list.c:78 msgid "No Results Found" msgstr "Нет результатов" #: src/bz-tag-list.c:90 #, c-format msgid "Apps Tagged \"%s\"" msgstr "Приложения с меткой \"%s\"" #: src/bz-tag-list.c:103 msgid "Search failed" msgstr "Ошибка поиска" #: src/bz-transaction-dialog.c:155 msgid "Keep User Data" msgstr "Оставить пользовательские данные" #: src/bz-transaction-dialog.c:156 msgid "Allow restoring personal settings & content" msgstr "Возможно восстановление настроек и содержимого" #: src/bz-transaction-dialog.c:165 msgid "Delete All Data" msgstr "Удалить все данные" #: src/bz-transaction-dialog.c:166 msgid "Permanently erase user data to save space" msgstr "Навсегда удалить данные приложения для сохранения места" #: src/bz-transaction-dialog.c:191 #, c-format msgid "Install %s?" msgstr "Установить %s?" #: src/bz-transaction-dialog.c:196 msgid "" "Select which version to install. May install additional shared components" msgstr "" "Выберите какую версию установить. Может установить дополнительные общие " "компоненты" #: src/bz-transaction-dialog.c:198 msgid "May install additional shared components" msgstr "Может установить дополнительные общие компоненты" #: src/bz-transaction-dialog.c:201 src/bz-transaction-dialog.c:230 #: src/bz-transaction-dialog.c:275 src/bz-transaction-dialog.c:578 msgid "_Cancel" msgstr "_Отмена" #: src/bz-transaction-dialog.c:219 #, c-format msgid "Remove %s?" msgstr "Удалить %s?" #: src/bz-transaction-dialog.c:222 msgid "Select which version to remove." msgstr "Выберите какую версию удалить." #: src/bz-transaction-dialog.c:224 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "Станет невозможным использовать %s после его удаления." #: src/bz-transaction-dialog.c:247 #, c-format msgid "“%s” is High Risk" msgstr "“%s” под высоким риском" #: src/bz-transaction-dialog.c:251 msgid "" "This app has full access to your system, including all your files, " "browser history, saved passwords, and more. It also has access to the " "internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Это приложение имеет полный доступ к вашей системе, включая все ваши " "файлы, историю браузера, сохранённые пароли, и так далее. Оно также " "имеет доступ к интернету, что может означать отправку ваших данных третьим " "лицам.\n" "\n" "Так как это приложение является проприетарным, проверка на действия с такими " "разрешениями является невозможной." #: src/bz-transaction-dialog.c:260 msgid "" "This app uses the legacy X11 windowing system, which allows it to record " "all keystrokes, capture screenshots, and monitor other applications. It " "also has access to the internet, meaning it could send your data to outside " "parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Это приложение использует устаревшую оконную систему X11, которая получает " "доступ к записи всех нажатий клавиш, получению скриншотов и наблюдению " "над другими приложениями. Оно также имеет доступ к интернету, что может " "означать отправку ваших данных третьим лицам.\n" "\n" "Так как это приложение является проприетарным, проверка на действия с такими " "разрешениями является невозможной." #: src/bz-transaction-dialog.c:276 msgid "_Install Anyway" msgstr "_Всё равно установить" #: src/bz-transaction-dialog.c:331 msgid "Failed to load transaction dialog" msgstr "Не удалось загрузить диалог транзакции" #: src/bz-transaction-dialog.c:549 msgid "All apps are already installed" msgstr "Все приложения уже были установлены" #: src/bz-transaction-dialog.c:551 msgid "_OK" msgstr "_ОК" #: src/bz-transaction-dialog.c:567 #, c-format msgid "Install %u App?" msgid_plural "Install %u Apps?" msgstr[0] "Установить %u приложение?" msgstr[1] "Установить %u приложения?" msgstr[2] "Установить %u приложений?" #: src/bz-transaction-dialog.c:575 msgid "" "The following will be installed. Additional shared components may also be " "installed" msgstr "" "Перечисленное будет установлено. Дополнительные общие компоненты будут также " "установлены." #: src/bz-transaction-dialog.c:576 #, c-format msgid "%d addons will be installed." msgstr "%d дополнений будет установлено." #: src/bz-transaction-dialog.c:577 msgid "Additionally, addons will be installed." msgstr "Также будут установлены дополнения." #: src/bz-transaction-dialog.c:579 msgid "_Install All" msgstr "_Установить все" #: src/bz-transaction-manager.c:766 #, c-format msgid "Finished in %.02f seconds" msgstr "Закончено за %.02f секунд" #: src/bz-transaction-tile.blp:129 msgid "App Add-On" msgstr "Дополнение приложения" #: src/bz-transaction-tile.blp:158 msgid "Runtime" msgstr "Среда выполнения" #: src/bz-transaction-tile.blp:182 msgid "In Queue" msgstr "В очереди" #: src/bz-transaction-tile.blp:206 msgid "Done" msgstr "Готово" #: src/bz-transaction-tile.blp:230 msgid "Error" msgstr "Ошибка" #: src/bz-transaction-tile.blp:286 msgid "Cancel Transaction" msgstr "Отменить транзакцию" #: src/bz-transaction-tile.blp:410 msgid "Show Error Info" msgstr "Показать информацию об ошибке" #: src/bz-transaction-tile.c:107 #, c-format msgid "%s Freed" msgstr "%s очищено" #: src/bz-transaction-tile.c:362 src/bz-transaction-tile.c:365 msgid "Transaction Error" msgstr "Ошибка транзакции" #: src/bz-transaction.c:342 msgid "Pending" msgstr "В ожидании" #: src/bz-updates-card.blp:22 msgid "_Update All" msgstr "_Обновить все" #: src/bz-updates-card.c:208 #, c-format msgid "%u Runtime Update" msgid_plural "%u Runtime Updates" msgstr[0] "Обновление %u среды выполнения" msgstr[1] "Обновление %u сред выполнения" msgstr[2] "Обновление %u сред выполнения" #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "Управление оставшимися пользовательскими данными" #: src/bz-user-data-page.blp:89 msgid "No User Data Found" msgstr "Пользовательские данные не найдены" #: src/bz-user-data-page.blp:94 msgid "User Data" msgstr "Пользовательские данные" #: src/bz-user-data-tile.c:144 #, c-format msgid "Trashed User Data for %s" msgstr "Пользовательские данные к %s отправлены в корзину" #: src/bz-user-data-tile.blp:74 msgid "Trash User Data" msgstr "Отправить в корзину" #: src/bz-window.blp:88 msgid "Curated" msgstr "Курируемое" #: src/bz-window.blp:100 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:220 msgid "Refresh completed!" msgstr "Обновление завершено!" #: src/bz-window.blp:273 msgid "You are running a new version of Bazaar!" msgstr "Вы используете новую версию Bazaar!" #: src/bz-window.blp:274 msgid "See What's New" msgstr "Посмотреть что нового" #: src/bz-window.blp:281 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "" "Вы имеете сетевое подключение, но просматриваете кэшируемую версию Flathub" #: src/bz-window.blp:393 msgid "Log Out" msgstr "Выйти" #. Translators: %s is the title of the current page #: src/bz-window.c:380 #, c-format msgid "Bazaar — %s" msgstr "Bazaar — %s" #: src/bz-window.c:544 src/bz-window.c:561 msgid "Failed to launch application" msgstr "Не удалось запустить приложение" #: src/bz-window.c:766 msgid "You can't remove Bazaar from Bazaar!" msgstr "Вы не можете удалить Bazaar из Bazaar!" #: src/bz-window.c:1051 src/bz-window.c:1085 msgid "Can't do that right now!" msgstr "Нельзя сделать это прямо сейчас!" #: src/bz-world-map.c:595 msgctxt "As in, \"100 Downloads\"" msgid "Downloads" msgstr "загрузок" #: src/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Общее" #: src/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Page" msgstr "Открыть страницу поиска" #: src/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Library Page" msgstr "Открыть страницу библиотеки" #: src/shortcuts-dialog.blp:20 msgctxt "shortcut window" msgid "Refresh" msgstr "Обновить" #: src/shortcuts-dialog.blp:25 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Открыть параметры" #: src/shortcuts-dialog.blp:30 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Открыть сочетания клавиш" #: src/shortcuts-dialog.blp:35 msgctxt "shortcut window" msgid "Close Window" msgstr "Закрыть окно" #: src/shortcuts-dialog.blp:41 msgctxt "shortcut window" msgid "Quit Bazaar" msgstr "Завершить Bazaar" bazaar-orig-v0.7.14/po/uk.po0000664000175000017500000017254015166123241014546 0ustar hasanhasan# Ukrainian translations for bazaar package. # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # # SPDX-FileCopyrightText: 2025 faoquad msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-01-06 19:57+0200\n" "PO-Revision-Date: 2025-12-21 15:55+0200\n" "Last-Translator: faoquad \n" "Language-Team: Ukrainian <>\n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=" "4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Lokalize 25.12.0\n" #: data/io.github.kolunmi.Bazaar.desktop.in:3 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:5 #: src/bz-window.blp:234 msgid "Bazaar" msgstr "Базар" #: data/io.github.kolunmi.Bazaar.desktop.in:4 msgid "Add, remove or update flatpak software on this computer" msgstr "Встановлюйте, видаляйте та оновлюйте пакунки Flatpak на Ваш компʼютер" #: data/io.github.kolunmi.Bazaar.desktop.in:10 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "" "GTK;System;PackageManager;Discover;Flatpak;Software;Store;Магазин;Крамниця;" "Флатпак;Пакунки;Програми;" #: data/io.github.kolunmi.Bazaar.gschema.xml:6 msgid "Hide EOL Entries" msgstr "Сховати осиротілі надходження" #: data/io.github.kolunmi.Bazaar.gschema.xml:7 msgid "Hide EOL entries and entries depending on them" msgstr "Сховати осиротілі надходження та надходження, котрі залежать від них" #: data/io.github.kolunmi.Bazaar.gschema.xml:11 msgid "Only Show Free Software" msgstr "Показувати лише вільні застосунки" #: data/io.github.kolunmi.Bazaar.gschema.xml:12 msgid "Hide proprietary software" msgstr "Ховати власницькі застосунки" #: data/io.github.kolunmi.Bazaar.gschema.xml:16 msgid "Show Only Flathub Content" msgstr "Показувати лише вміст з Flathub" #: data/io.github.kolunmi.Bazaar.gschema.xml:17 msgid "Hide applications which do not originate from Flathub" msgstr "Ховати застосунки, що не походять із Flathub" #: data/io.github.kolunmi.Bazaar.gschema.xml:21 msgid "Debounce Search Inputs" msgstr "Чекати вводу" #: data/io.github.kolunmi.Bazaar.gschema.xml:22 msgid "Add a delay before searching to prevent instant replies while typing" msgstr "Чекати на закінчення вводу, аби попередити миттєві надходження." #: data/io.github.kolunmi.Bazaar.gschema.xml:46 msgid "Global Progress Bar Theme" msgstr "Загальний вигляд смужки поступу" #: data/io.github.kolunmi.Bazaar.gschema.xml:47 msgid "Describes the look of the global progress bar" msgstr "Описує вигляд загальної смужки поступу" #: data/io.github.kolunmi.Bazaar.gschema.xml:51 msgid "Saved Window Dimensions" msgstr "Збережені розміри вікна" #: data/io.github.kolunmi.Bazaar.gschema.xml:52 msgid "The window dimensions to be used by the next Bazaar window" msgstr "Розміри, що їх користуватиме наступне вікно Базару" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and install applications" msgstr "Знаходьте та встановлюйте застосунки" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A new app store for Linux with a focus on discovering and installing " "applications and addons from Flatpak remotes, particularly Flathub." msgstr "" "Нова крамниця застосунків для Linux, зосереджена на знаходженні та " "встановленні застосунків і розширень з віддалених сховищ Flatpak, зокрема " "Flathub." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:14 msgid "" "It emphasizes supporting the developers who make the Linux desktop possible. " "Bazaar features a \"curated\" tab that can be configured by distributors to " "allow for a more localized experience." msgstr "" "Базар наголошує на підтримці розробників, що роблять можливим Linux на " "стільничних компʼютерах. Він має вкладку \"підібраних\" застосунків, котра " "може бути налаштована дистрибутивами, аби створити цілісніший досвід." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:54 msgid "The home page displaying Flathub apps" msgstr "Домашня сторінка із застосунками з Flathub" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:58 msgid "Nucleus app page" msgstr "Сторінка застосунку Nucleus" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:62 msgid "Search page" msgstr "Сторінка пошуку" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:66 msgid "Category page" msgstr "Сторінка пошуку з категоріями" #: src/bz-addons-dialog.blp:14 src/bz-full-view.blp:686 #: src/bz-installed-tile.blp:99 msgid "Manage Add-ons" msgstr "Керувати розширеннями" #: src/bz-addons-dialog.c:90 src/bz-full-view.blp:477 #: src/bz-installed-tile.blp:117 src/bz-transaction-view.blp:213 #: src/bz-window.c:1314 msgid "Remove" msgstr "Видалити" #: src/bz-addons-dialog.c:95 src/bz-favorites-tile.c:166 #: src/bz-full-view.blp:249 src/bz-full-view.blp:464 #: src/bz-transaction-view.blp:187 src/bz-window.c:1291 msgid "Install" msgstr "Встановити" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:50 #: src/bz-full-view.c:374 src/bz-full-view.c:381 msgid "Age Rating" msgstr "Вікове обмеження" # хто я #: src/bz-age-rating-dialog.blp:40 src/bz-age-rating-dialog.c:790 msgid "?" msgstr "?" #: src/bz-age-rating-dialog.c:139 msgid "Cartoon Violence" msgstr "Анімована жорстокість" #: src/bz-age-rating-dialog.c:140 msgid "No information regarding cartoon violence" msgstr "Без даних щодо зображення анімованої жорстокости" #: src/bz-age-rating-dialog.c:143 msgid "Fantasy Violence" msgstr "Вигадана жорстокість" #: src/bz-age-rating-dialog.c:144 msgid "No information regarding fantasy violence" msgstr "Без даних щодо зображення вигаданої жорстокости" #: src/bz-age-rating-dialog.c:147 msgid "Realistic Violence" msgstr "Реалістична жорстокість" #: src/bz-age-rating-dialog.c:148 msgid "No information regarding realistic violence" msgstr "Без даних щодо зображення реалістичної жорстокости" #: src/bz-age-rating-dialog.c:151 msgid "Violence Depicting Bloodshed" msgstr "Жорстокість із зображенням кровопролиття" #: src/bz-age-rating-dialog.c:152 msgid "No information regarding bloodshed" msgstr "Без даних щодо зображення кровопролиття" #: src/bz-age-rating-dialog.c:155 msgid "Sexual Violence" msgstr "Сексуальне насильство" #: src/bz-age-rating-dialog.c:156 msgid "No information regarding sexual violence" msgstr "Без даних щодо згадок або зображення сексуального насильства" #: src/bz-age-rating-dialog.c:159 msgid "Alcohol" msgstr "Алкоголь" #: src/bz-age-rating-dialog.c:160 msgid "No information regarding references to alcohol" msgstr "Без даних щодо згадок або зображення алкоголю" #: src/bz-age-rating-dialog.c:163 msgid "Narcotics" msgstr "Заборонені речовини" # Тут поняття включає як заборонені, так і незаборонені речовини (алкоголь, тютюн тощо) #: src/bz-age-rating-dialog.c:164 msgid "No information regarding references to illicit drugs" msgstr "Без даних щодо згадок або зображення пʼянких речовин" #: src/bz-age-rating-dialog.c:167 msgid "Tobacco" msgstr "Тютюн" #: src/bz-age-rating-dialog.c:168 msgid "No information regarding references to tobacco products" msgstr "Без даних щодо згадок або зображення тютюнових виробів" #: src/bz-age-rating-dialog.c:171 src/bz-age-rating-dialog.c:358 msgid "Nudity" msgstr "Оголення" #: src/bz-age-rating-dialog.c:172 msgid "No information regarding nudity of any sort" msgstr "Без даних щодо зображення оголення" #: src/bz-age-rating-dialog.c:175 msgid "Sexual Themes" msgstr "Сексуальні теми" #: src/bz-age-rating-dialog.c:176 msgid "No information regarding references to or depictions of sexual nature" msgstr "Без даних щодо згадок або зображення сексуального характеру" #: src/bz-age-rating-dialog.c:179 msgid "Profanity" msgstr "Лайка" #: src/bz-age-rating-dialog.c:180 msgid "No information regarding profanity of any kind" msgstr "Без даних щодо грубощів або недоречного гумору" #: src/bz-age-rating-dialog.c:183 msgid "Inappropriate Humor" msgstr "Недоречний гумор" #: src/bz-age-rating-dialog.c:184 msgid "No information regarding inappropriate humor" msgstr "Без даних щодо використання недоречного гумору" #: src/bz-age-rating-dialog.c:187 msgid "Discrimination" msgstr "Дискримінація" #: src/bz-age-rating-dialog.c:188 msgid "No information regarding discriminatory language of any kind" msgstr "Без даних щодо використання дискримінаційної мови" #: src/bz-age-rating-dialog.c:191 msgid "Advertising" msgstr "Реклама" #: src/bz-age-rating-dialog.c:192 msgid "No information regarding advertising of any kind" msgstr "Без даних щодо рекламного вмісту" #: src/bz-age-rating-dialog.c:195 msgid "Gambling" msgstr "Азартний вміст" #: src/bz-age-rating-dialog.c:196 msgid "No information regarding gambling of any kind" msgstr "Без даних щодо азартного вмісту" #: src/bz-age-rating-dialog.c:199 msgid "Purchasing" msgstr "Покупки" #: src/bz-age-rating-dialog.c:200 msgid "No information regarding the ability to spend money" msgstr "Без даних щодо можливості витрачати гроші" #: src/bz-age-rating-dialog.c:203 msgid "Chat Between Users" msgstr "Розмови між користувачами" #: src/bz-age-rating-dialog.c:204 msgid "No information regarding ways to chat with other users" msgstr "Без даних щодо можливості спілкуватися з іншими користувачами" #: src/bz-age-rating-dialog.c:207 msgid "Audio Chat Between Users" msgstr "Голосові розмови між користувачами" #: src/bz-age-rating-dialog.c:208 msgid "No information regarding ways to talk with other users" msgstr "Без даних щодо голосового звʼязку з іншими користувачами" #: src/bz-age-rating-dialog.c:211 msgid "Contact Details" msgstr "Контактні дані" #: src/bz-age-rating-dialog.c:212 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "" "Без даних щодо розголошення облікових даних соцмереж або адрес електронної " "пошти" #: src/bz-age-rating-dialog.c:215 msgid "Identifying Information" msgstr "Виявні дані" #: src/bz-age-rating-dialog.c:216 msgid "No information regarding sharing of user information with third parties" msgstr "Без даних щодо розголошення користувацьких даних третім сторонам" #: src/bz-age-rating-dialog.c:219 msgid "Location Sharing" msgstr "Місцезнаходження" #: src/bz-age-rating-dialog.c:220 msgid "No information regarding sharing of physical location with other users" msgstr "Без даних щодо розголошення розташування іншим користувачам" #: src/bz-age-rating-dialog.c:223 msgid "Prostitution" msgstr "Проституція" #: src/bz-age-rating-dialog.c:224 msgid "No information regarding references to prostitution" msgstr "Без даних щодо згадок або зображення проституції" #: src/bz-age-rating-dialog.c:227 msgid "Adultery" msgstr "Подружня зрада" #: src/bz-age-rating-dialog.c:228 msgid "No information regarding references to adultery" msgstr "Без даних щодо згадок або зображення подружньої зради" #: src/bz-age-rating-dialog.c:231 msgid "Sexualized Characters" msgstr "Сексуалізовані персонажі" #: src/bz-age-rating-dialog.c:232 msgid "No information regarding sexualized characters" msgstr "Без даних щодо зображення сексуалізованих персонажів" # По-нашому не «кощунство». #: src/bz-age-rating-dialog.c:235 msgid "Desecration" msgstr "Блюзнірство" # По-нашому не «кощунство». #: src/bz-age-rating-dialog.c:236 msgid "No information regarding references to desecration" msgstr "Без даних щодо блюзнірства" #: src/bz-age-rating-dialog.c:239 msgid "Human Remains" msgstr "Людські рештки" #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "Без даних щодо зображення людських решток" #: src/bz-age-rating-dialog.c:243 msgid "Slavery" msgstr "Рабство" #: src/bz-age-rating-dialog.c:244 msgid "No information regarding references to slavery" msgstr "Без даних щодо згадок або зображення рабства" # Тут поняття включає як заборонені, так і незаборонені речовини (алкоголь, тютюн тощо) #: src/bz-age-rating-dialog.c:307 msgid "Does not include references to drugs" msgstr "Не містить згадок або зображення пʼянких речовин" #: src/bz-age-rating-dialog.c:309 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "Не містить грубощів або недоречного гумору" #: src/bz-age-rating-dialog.c:311 msgid "Does not include ads or monetary transactions" msgstr "Не містить реклами або грошових операцій" #: src/bz-age-rating-dialog.c:313 msgid "Does not include sex or nudity" msgstr "Не містить оголености або сексу" #: src/bz-age-rating-dialog.c:315 msgid "Does not include uncontrolled chat functionality" msgstr "Не має можливості спілкуватися з іншими користувачами" #: src/bz-age-rating-dialog.c:317 msgid "Does not include violence" msgstr "Не містить жорстокости" # Тут поняття включає як заборонені, так і незаборонені речовини (алкоголь, тютюн тощо) #: src/bz-age-rating-dialog.c:352 msgid "Drugs" msgstr "Речовини" # Як розумію, це включає лайливу мову та інші форми міцної мови. #: src/bz-age-rating-dialog.c:354 msgid "Strong Language" msgstr "Грубощі" #: src/bz-age-rating-dialog.c:356 msgid "Money" msgstr "Гроші" # Тут мається на увазі чат та інші види звʼязку з іншими людьми. #: src/bz-age-rating-dialog.c:360 msgid "Social" msgstr "Спілкування" #: src/bz-age-rating-dialog.c:362 msgid "Violence" msgstr "Жорстокість" #: src/bz-age-rating-dialog.c:564 #, c-format msgid "%s • %s" msgstr "%s • %s" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:752 src/bz-full-view.c:364 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:782 msgctxt "Age rating" msgid "All" msgstr "Без обмежень" #: src/bz-age-rating-dialog.c:846 #, c-format msgid "%s has an unknown age rating" msgstr "%s не вказує вікове обмеження" #: src/bz-age-rating-dialog.c:854 #, c-format msgid "%s is suitable for everyone" msgstr "%s пасує всім" #: src/bz-age-rating-dialog.c:857 #, c-format msgid "%s is suitable for toddlers" msgstr "%s пасує немовлям" #: src/bz-age-rating-dialog.c:860 #, c-format msgid "%s is suitable for young children" msgstr "%s пасує малим дітям" #: src/bz-age-rating-dialog.c:863 #, c-format msgid "%s is suitable for children" msgstr "%s пасує дітям" #: src/bz-age-rating-dialog.c:866 #, c-format msgid "%s is suitable for teenagers" msgstr "%s пасує підліткам" #: src/bz-age-rating-dialog.c:869 #, c-format msgid "%s is suitable for adults" msgstr "%s пасує дорослим" #: src/bz-age-rating-dialog.c:872 #, c-format msgid "%s is suitable for %s" msgstr "%s пасує %s" #: src/bz-app-size-dialog.blp:43 msgid "--- MB" msgstr "--- МБ" #: src/bz-app-size-dialog.blp:53 msgid "Download Size" msgstr "Розмір завантаження" #: src/bz-app-size-dialog.c:55 msgid "Of the size of human DNA" msgstr "від людської ДНК" #: src/bz-app-size-dialog.c:55 msgid "3 billion base pairs" msgstr "3 мільярди пар основ" #: src/bz-app-size-dialog.c:56 msgid "Of the Linux Kernel" msgstr "від ядра Linux" # Не потребує перекладу. #: src/bz-app-size-dialog.c:56 msgid "linux-6.17.tar.xz" msgstr "linux-6.17.tar.xz" #: src/bz-app-size-dialog.c:57 msgid "Of the Apollo 11 guidance computer" msgstr "від бортового обчислювача Apollo 11" #: src/bz-app-size-dialog.c:57 msgid "Total ROM and RAM" msgstr "увесь простір ПЗП та ОЗП" #: src/bz-app-size-dialog.c:58 msgid "Of the original Super Mario Bros" msgstr "від першого Super Mario Bros" #: src/bz-app-size-dialog.c:58 msgid "On the NES" msgstr "на NES" #: src/bz-app-size-dialog.c:59 msgid "Of the size of Wikipedia" msgstr "від усієї Вікіпедії" #: src/bz-app-size-dialog.c:59 msgid "Without any media" msgstr "без медіявмісту" #: src/bz-app-tile.blp:84 src/bz-installed-page.blp:25 src/bz-window.blp:298 msgid "Installed" msgstr "Встановлені" #: src/bz-apps-page.blp:14 src/bz-full-view.blp:43 src/bz-user-data-page.blp:15 #: src/bz-window.blp:443 msgid "Main Menu" msgstr "Головне меню" #: src/bz-apps-page.blp:17 src/bz-user-data-page.blp:18 src/bz-window.blp:522 msgid "_Donate to Bazaar ❤️" msgstr "_Пожертувати Базару ❤️" #: src/bz-apps-page.blp:18 src/bz-user-data-page.blp:19 msgid "_Refresh Content" msgstr "_Освіжити вміст" #: src/bz-apps-page.blp:22 src/bz-user-data-page.blp:22 src/bz-window.blp:529 msgid "_Preferences" msgstr "_Налаштування" #: src/bz-apps-page.blp:23 src/bz-user-data-page.blp:23 src/bz-window.blp:550 msgid "_Keyboard Shortcuts" msgstr "_Клавіатурні скорочення" #: src/bz-apps-page.blp:24 src/bz-user-data-page.blp:24 src/bz-window.blp:555 msgid "_About Bazaar" msgstr "_Про Базар" #: src/bz-apps-page.blp:28 src/bz-user-data-page.blp:27 src/bz-window.blp:562 msgid "_Quit Bazaar" msgstr "_Вийти" #: src/bz-application.c:578 msgid "" "This functionality is currently disabled. It is recommended you download and " "install Flatseal to manage app permissions." msgstr "" "Цю можливість наразі вимкнено. Для керування дозволами застосунків радимо " "встановити Flatseal." #: src/bz-application.c:660 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "" #: src/bz-application.c:661 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "" #: src/bz-application.c:683 msgid "Adam Masciola" msgstr "" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:686 msgid "translator-credits" msgstr "faoquad , 2025" #: src/bz-application.c:750 msgid "Logged Out Successfully!" msgstr "Ви вийшли з Flathub" #: src/bz-application.c:877 msgid "Performing setup..." msgstr "Налаштовуємо…" #: src/bz-application.c:956 src/bz-application.c:965 msgid "Set Up Flathub" msgstr "Налаштувати Flathub" #: src/bz-application.c:959 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub не налаштовано на цій системі. Ви не зможете шукати та встановлювати " "застосунки в Базарі. Проте, Ви зможете користати Базар для огляду та " "керування вже встановленими застосунками." #: src/bz-application.c:964 src/bz-update-dialog.blp:6 msgid "Later" msgstr "Пізніше" #: src/bz-application.c:1366 msgid "Synchronizing..." msgstr "Синхронізуємо…" #: src/bz-application.c:1505 #, c-format msgid "Receiving %d entries..." msgstr "Отримуємо %d надходжень…" #: src/bz-application.c:1510 msgid "Checking for updates" msgstr "Шукаємо оновлення" #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:65 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:53 #: src/bz-installed-page.blp:15 src/bz-user-data-page.blp:52 #: src/bz-window.blp:183 msgid "Empty" msgstr "Порожньо" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "Жодного підібраного вмісту" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "Ваша операційна система не надає підібранoго вмісту. Ви все ще можете шукати " "застосунки на Flathub" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "Оглянути Flathub" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "Поза мережею" #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 msgid "Browser" msgstr "Оглядач" #: src/bz-developer-badge.c:131 msgid "Developer information not available." msgstr "Відомості щодо розробників недоступні" #: src/bz-developer-badge.c:137 src/bz-developer-badge.c:151 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "" "Володіння ідентифікатором цього застосунку не було підтверджено. Можливо, " "цей пакунок було вивантажено спільнотою." #: src/bz-developer-badge.c:155 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "" "Володіння ідентифікатором %s було підтверджено власноруч командою Flathub." #: src/bz-developer-badge.c:161 #, c-format msgid "" "The ownership of the %s app ID has been verified by %s on %s." msgstr "Володіння ідентифікатором %s було підтверджено %s на %s." #: src/bz-developer-badge.c:168 #, c-format msgid "The ownership of the %s app ID has been verified using %s." msgstr "Володіння ідентифікатором %s було підтверджено з допомогою %s." #: src/bz-developer-badge.c:172 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "Володіння ідентифікатором %s було підтверджено." #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "Оберіть встановлення" #: src/bz-entry-group-util.c:76 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "" "Ви маєте декілька встановлених версій цього застосунку. З котрою з них Ви бажа" "єте продовжити?" #: src/bz-entry-group-util.c:80 src/bz-window.c:1290 src/bz-window.c:1313 msgid "Cancel" msgstr "Скасувати" #: src/bz-entry-inspector.blp:5 msgid "Entry Inspector" msgstr "Зневаджувач надходжень" #: src/bz-entry-inspector.blp:76 msgid "Serialize" msgstr "Серіалізувати" #: src/bz-entry-inspector.blp:80 msgid "Convert to JSON" msgstr "Перетворити в JSON" #: src/bz-error.c:68 msgid "An Error Occurred" msgstr "Виникла помилка" #: src/bz-error.c:89 msgid "Close" msgstr "Вийти" #: src/bz-error.c:90 msgid "Copy and Close" msgstr "Копіювати та вийти" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "Увійдіть із допомогою Flathub, аби керувати вподобаннями" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "Увійти" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "Кількість уподобань" #: src/bz-favorites-tile.c:164 msgid "Uninstall" msgstr "Видалити" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:75 msgid "Support this application" msgstr "Підтримати цей застосунок" #: src/bz-favorites-tile.blp:118 msgid "Remove from Favorites" msgstr "Прибрати з вподобаних" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:75 #: src/bz-window.blp:580 msgid "Favorites" msgstr "Вподобані" #: src/bz-favorites-page.blp:22 src/bz-full-view.blp:20 src/bz-window.blp:126 #: src/bz-window.blp:420 msgid "Toggle transaction sidebar" msgstr "Перемкнути віконце дій над застосунками" #: src/bz-favorites-page.blp:53 src/bz-user-data-page.blp:41 msgid "Loading" msgstr "Шукаємо" #: src/bz-favorites-page.blp:68 msgid "No Favorites" msgstr "Нічого не вподобано" #: src/bz-favorites-page.blp:69 msgid "Applications you mark as favorite will appear here" msgstr "Вподобані застосунки опинятимуться тут" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "Назад" #: src/bz-featured-carousel.blp:53 msgid "Next" msgstr "Далі" #: src/bz-featured-tile.blp:88 msgid "App of the Day" msgstr "Застосунок дня" #: src/bz-flathub-category.c:78 msgid "Audio & Video" msgstr "Звук та відео" #: src/bz-flathub-category.c:78 msgid "Media" msgstr "Медіа" #: src/bz-flathub-category.c:78 msgid "More Audio & Video" msgstr "Показати більше" #: src/bz-flathub-category.c:79 msgid "Developer Tools" msgstr "Розробка" #: src/bz-flathub-category.c:79 msgid "Develop" msgstr "Розробка" #: src/bz-flathub-category.c:79 msgid "More Developer Tools" msgstr "Показати більше" #: src/bz-flathub-category.c:80 msgid "Education" msgstr "Освіта" #: src/bz-flathub-category.c:80 msgid "Learn" msgstr "Освіта" #: src/bz-flathub-category.c:80 msgid "More Education" msgstr "Показати більше" #: src/bz-flathub-category.c:81 msgid "Gaming" msgstr "Ігри" #: src/bz-flathub-category.c:81 msgid "Play" msgstr "Ігри" #: src/bz-flathub-category.c:81 msgid "More Gaming" msgstr "Показати більше" #: src/bz-flathub-category.c:82 msgid "Graphics & Photography" msgstr "Графіка та фотографія" #: src/bz-flathub-category.c:82 msgid "Create" msgstr "Творчість" #: src/bz-flathub-category.c:82 msgid "More Graphics & Photography" msgstr "Показати більше" #: src/bz-flathub-category.c:83 msgid "Networking" msgstr "Мережа" #: src/bz-flathub-category.c:83 msgid "Internet" msgstr "Інтернет" #: src/bz-flathub-category.c:83 msgid "More Networking" msgstr "Показати більше" #: src/bz-flathub-category.c:84 msgid "Productivity" msgstr "Продуктивність" #: src/bz-flathub-category.c:84 msgid "Work" msgstr "Робота" #: src/bz-flathub-category.c:84 msgid "More Productivity" msgstr "Показати більше" #: src/bz-flathub-category.c:85 msgid "Science" msgstr "Наука" #: src/bz-flathub-category.c:85 msgid "More Science" msgstr "Показати більше" #: src/bz-flathub-category.c:86 msgid "System" msgstr "Система" #: src/bz-flathub-category.c:86 msgid "More System" msgstr "Показати більше" #: src/bz-flathub-category.c:87 msgid "Utilities" msgstr "Утиліти" #: src/bz-flathub-category.c:87 msgid "Tools" msgstr "Утиліти" #: src/bz-flathub-category.c:87 msgid "More Utilities" msgstr "Показати більше" #: src/bz-flathub-category.c:88 src/bz-flathub-page.blp:119 #: src/bz-flathub-page.blp:152 msgid "Trending" msgstr "Набирають популярність" #: src/bz-flathub-category.c:88 msgid "More Trending" msgstr "Показати більше" #: src/bz-flathub-category.c:89 src/bz-flathub-page.blp:125 #: src/bz-flathub-page.blp:185 msgid "Popular" msgstr "Популярні" #: src/bz-flathub-category.c:89 msgid "More Popular" msgstr "Показати більше" #: src/bz-flathub-category.c:90 src/bz-flathub-page.blp:174 msgid "Recently Added" msgstr "Нещодавно додані" #: src/bz-flathub-category.c:90 src/bz-flathub-page.blp:131 msgid "New" msgstr "Нові" #: src/bz-flathub-category.c:90 msgid "More New" msgstr "Показати більше" #: src/bz-flathub-category.c:91 src/bz-flathub-page.blp:163 msgid "Recently Updated" msgstr "Нещодавно оновлені" #: src/bz-flathub-category.c:91 src/bz-flathub-page.blp:137 msgid "Updated" msgstr "Оновлені" #: src/bz-flathub-category.c:91 msgid "More Updated" msgstr "Показати більше" #: src/bz-flathub-category.c:92 msgid "Mobile" msgstr "Мобільні пристрої" #: src/bz-flathub-category.c:92 msgid "More Mobile" msgstr "Показати більше" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Flathub не додано" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "Сховище Flathub не було знайдено на жодному з Ваших встановлень" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "Помилка Flathub" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "Спробувати зʼєднатися з Flathub іще раз" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Flathub недоступний" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" "Не вдалося зʼєднатися з Flathub. Ви все ще можете шукати застосунки та " "керувати ними." #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "Шукати застосунки" #: src/bz-flathub-page.blp:270 msgid "On the Go" msgstr "На ходу" #: src/bz-flathub-page.blp:282 msgid "Apps for your Linux phones and tablets" msgstr "Застосунки для Ваших смартфонів та планшетів на Linux" #: src/bz-flathub-page.blp:293 msgid "More Mobile Apps" msgstr "Показати більше" #: src/bz-flathub-page.blp:328 msgid "More Mobile apps" msgstr "Показати більше" #: src/bz-flathub-page.blp:388 msgid "We​ ♥​ Games" msgstr "Ми​ ♥​ ігри" #: src/bz-flathub-page.blp:401 msgid "Games and apps to run your favorite titles" msgstr "Улюблені ігри та застосунки для них" #: src/bz-flathub-page.blp:435 msgid "More Games" msgstr "Показати більше" #: src/bz-flatpak-entry.c:600 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Сторінка Flathub" #: src/bz-flatpak-entry.c:621 msgctxt "Project URL Type" msgid "Project Website" msgstr "URL проєкту" #: src/bz-flatpak-entry.c:625 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Відстеження помилок" #: src/bz-flatpak-entry.c:629 msgctxt "Project URL Type" msgid "FAQ" msgstr "ЧаПи" #: src/bz-flatpak-entry.c:633 msgctxt "Project URL Type" msgid "Help" msgstr "Допомога" #: src/bz-flatpak-entry.c:637 msgctxt "Project URL Type" msgid "Donate" msgstr "Пожертви" #: src/bz-flatpak-entry.c:643 msgctxt "Project URL Type" msgid "Translate" msgstr "Переклад" #: src/bz-flatpak-entry.c:647 msgctxt "Project URL Type" msgid "Contact" msgstr "Звʼязок" #: src/bz-flatpak-entry.c:651 msgctxt "Project URL Type" msgid "Source Code" msgstr "Початковий код" #: src/bz-flatpak-entry.c:657 msgctxt "Project URL Type" msgid "Contribute" msgstr "Долучитися" #: src/bz-full-view.blp:57 msgid "No Results" msgstr "Нічого не знайдено" #: src/bz-full-view.blp:58 msgid "Try a different search query" msgstr "Спробуйте інший запит" #: src/bz-full-view.blp:64 src/bz-window.blp:193 msgid "Content" msgstr "Вміст" #: src/bz-full-view.blp:210 msgid "Support" msgstr "Підтримати" #: src/bz-full-view.blp:233 src/bz-full-view.blp:488 msgid "Open" msgstr "Запустити" #: src/bz-full-view.blp:246 src/bz-full-view.blp:461 msgid "Download & Install Application" msgstr "Завантажити й встановити цей застосунок" #: src/bz-full-view.blp:261 msgid "Uninstall Application" msgstr "Видалити цей застосунок" #: src/bz-full-view.blp:276 src/bz-full-view.blp:503 msgid "Install Other Version" msgstr "Встановити іншу версію" #: src/bz-full-view.blp:300 msgid "Size" msgstr "Розмір" #: src/bz-full-view.blp:405 msgid "Downloads /mo" msgstr "зав/міс" #: src/bz-full-view.blp:522 msgid "Stopped Receiving Core Updates" msgstr "Більше не отримує оновлень середовища виконання" #: src/bz-full-view.blp:536 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "Цей застосунок використовує середовище виконання, котре більше не отримує " "оновлень або безпекових виправлень. Він може стати небезпечним до " "використання." #: src/bz-full-view.blp:619 src/bz-window.c:1260 msgid "Delete Data" msgstr "Видалити дані" #: src/bz-full-view.blp:753 msgid "Tags:" msgstr "Мітки:" #: src/bz-full-view.c:290 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:297 #, c-format msgid "%.*fM" msgstr "%.*f млн" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:304 #, c-format msgid "%.*fK" msgstr "%.*f тис." #: src/bz-full-view.c:314 #, c-format msgid "%d downloads in the last 30 days" msgstr "%d завантажень протягом останніх 30 днів" #: src/bz-full-view.c:346 #, c-format msgid "Download size of %s" msgstr "Розмір завантаження" #: src/bz-full-view.c:379 msgid "All Ages" msgstr "Без обмежень" #: src/bz-full-view.c:391 msgid "Age rating information unavailable" msgstr "Дані щодо вікового обмеження недоступні" #: src/bz-full-view.c:396 msgid "Suitable for all ages" msgstr "Без обмежень за віком" #: src/bz-full-view.c:398 #, c-format msgid "Suitable for ages %d and up" msgstr "%d та старше" #: src/bz-full-view.c:431 src/bz-full-view.c:436 src/bz-full-view.c:464 #: src/bz-full-view.c:475 msgid "Unknown" msgstr "Невідомо" #: src/bz-full-view.c:441 #, c-format msgid "Free software licensed under %s" msgstr "Вільне ПЗ за ліцензією %s" #: src/bz-full-view.c:446 msgid "Free software" msgstr "Вільне ПЗ" #: src/bz-full-view.c:449 msgid "Proprietary Software" msgstr "Власницька ліцензія" #: src/bz-full-view.c:452 #, c-format msgid "Special License: %s" msgstr "Власна ліцензія: %s" #: src/bz-full-view.c:469 msgid "Free" msgstr "Вільна ліцензія" #: src/bz-full-view.c:472 src/bz-license-dialog.c:118 msgid "Proprietary" msgstr "Власницька ліцензія" #: src/bz-full-view.c:477 src/bz-license-dialog.c:120 msgid "Special License" msgstr "Власна ліцензія" #: src/bz-full-view.c:497 msgid "Adaptive" msgstr "Адаптивний" #: src/bz-full-view.c:497 msgid "Desktop Only" msgstr "Лише для стільниць" #: src/bz-full-view.c:503 msgid "Works on desktop, tablets, and phones" msgstr "Працює на стільницях, планшетах і смартфонах" #: src/bz-full-view.c:504 msgid "May not work on mobile devices" msgstr "Може не працювати на мобільних пристроях" #: src/bz-full-view.c:515 msgid "No URL" msgstr "Без URL" #: src/bz-full-view.c:533 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Цей застосунок має вільну ліцензію. Це означає, що початковий код може бути " "перевірено на безпечність." #: src/bz-full-view.c:534 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Цей застосунок має невільну (власницьку) ліцензію. Це означає, що початковий " "код не є публічно доступним і не може бути перевіреним на безпечність." #: src/bz-full-view.c:541 msgid "More Apps" msgstr "Більше застосунків" #: src/bz-full-view.c:542 #, c-format msgid "More Apps by %s" msgstr "Більше від %s" #: src/bz-full-view.c:549 msgid "Other Apps by this Developer" msgstr "Більше від розробників" #: src/bz-full-view.c:551 src/bz-full-view.c:659 #, c-format msgid "Other Apps by %s" msgstr "Більше від %s" # Трохи довший переклад, аби зберегти статеву нейтральність назви самого застосунку. #: src/bz-full-view.c:559 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "" "Застосунок %s не встановлено, проте він має %s залишкових даних." #: src/bz-full-view.c:661 msgid "Other Apps" msgstr "Інші застосунки" #: src/bz-full-view.c:663 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d застосунок" msgstr[1] "%d застосунки" msgstr[2] "%d застосунків" #: src/bz-full-view.c:1011 msgid "Show Less" msgstr "Згорнути" #: src/bz-full-view.c:1011 msgid "Show More" msgstr "Розгорнути" #: src/bz-hardware-support-dialog.blp:6 src/bz-hardware-support-dialog.blp:47 msgid "Hardware Support" msgstr "Підтримка пристроїв" #: src/bz-hardware-support-dialog.c:69 msgid "Keyboard support" msgstr "Підтримка клавіатури" #: src/bz-hardware-support-dialog.c:71 msgid "Requires keyboards" msgstr "Вимагає клавіатуру" # Позначає, що застосунок ліпше працює з такими пристроями # Стан підтримки загалом описується іншим рядком #: src/bz-hardware-support-dialog.c:72 msgid "Recommends keyboards" msgstr "Бажана клавіатура" #: src/bz-hardware-support-dialog.c:73 msgid "Supports keyboards" msgstr "Підтримує клавіатуру" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for keyboards" msgstr "Сумісність із клавіатурами на вказана" #: src/bz-hardware-support-dialog.c:76 msgid "Mouse support" msgstr "Підтримка миші" #: src/bz-hardware-support-dialog.c:78 msgid "Requires mice or pointing devices" msgstr "Вимагає мишу або вказівний пристрій" # Позначає, що застосунок ліпше працює з такими пристроями # Стан підтримки загалом описується іншим рядком #: src/bz-hardware-support-dialog.c:79 msgid "Recommends mice or pointing devices" msgstr "Бажані миша або вказівний пристрій" #: src/bz-hardware-support-dialog.c:80 msgid "Supports mice or pointing devices" msgstr "Підтримує мишу або вказівний пристрій" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for mice or pointing devices" msgstr "Сумісність із мишами або вказівними пристроями не вказана" #: src/bz-hardware-support-dialog.c:83 msgid "Touchscreen support" msgstr "Підтримка сенсорних екранів" #: src/bz-hardware-support-dialog.c:85 msgid "Requires touchscreens" msgstr "Вимагає сенсорний екран" # Позначає, що застосунок ліпше працює з такими пристроями # Стан підтримки загалом описується іншим рядком #: src/bz-hardware-support-dialog.c:86 msgid "Recommends touchscreens" msgstr "Бажаний сенсорний екран" #: src/bz-hardware-support-dialog.c:87 msgid "Supports touchscreens" msgstr "Підтримує сенсорний екран" #: src/bz-hardware-support-dialog.c:88 msgid "Unknown support for touchscreens" msgstr "Сумісність із сенсорними екранами на вказана" #: src/bz-hardware-support-dialog.c:192 msgid "Mobile support" msgstr "Підтримка мобільних пристроїв" #: src/bz-hardware-support-dialog.c:193 msgid "Works on mobile devices" msgstr "Працює на мобільних пристроях" #: src/bz-hardware-support-dialog.c:193 msgid "May not work well on mobile devices" msgstr "Обмежена підтримка на мобільних пристроях" #: src/bz-hardware-support-dialog.c:198 msgid "Desktop support" msgstr "Підтримка стільниць" #: src/bz-hardware-support-dialog.c:199 msgid "Works well on large screens" msgstr "Працює добре на великих екранах" #: src/bz-hardware-support-dialog.c:233 #, c-format msgid "%s works best on specific hardware" msgstr "%s найліпше працює на певних пристроях" #: src/bz-hardware-support-dialog.c:240 #, c-format msgid "%s works on most devices" msgstr "%s працює на більшості пристроїв" #: src/bz-inspector.blp:5 msgid "Bazaar Inspector" msgstr "Зневаджувач" #: src/bz-inspector.blp:33 msgid "Background Task Info:" msgstr "Відомості про задачі у тлі:" #: src/bz-inspector.blp:43 msgid "Enable Global Debug Mode" msgstr "Увімкнути режим зневадження" #: src/bz-inspector.blp:50 msgid "Active Blocklists" msgstr "Задіяні чорні списки" #: src/bz-inspector.blp:67 msgid "Active Curated-Configs" msgstr "Задіяні налаштування підібраного вмісту" #: src/bz-inspector.blp:85 msgid "All Entry Groups" msgstr "Усі групи надходжень" #: src/bz-inspector.blp:93 msgid "Filter..." msgstr "Відсіяти…" #: src/bz-inspector.blp:134 msgid "Decache and Inspect" msgstr "Відкинути кеш та дослідити" #: src/bz-installed-page.blp:19 msgid "No Flatpaks Installed" msgstr "Не встановлено жодного пакунку Flatpak" #: src/bz-installed-tile.blp:61 src/bz-rich-app-tile.blp:137 msgid "Stopped Receiving Updates" msgstr "Більшe не отримує оновлень" #: src/bz-license-dialog.blp:160 msgid "Get Involved" msgstr "Долучитися" #: src/bz-license-dialog.c:107 src/bz-license-dialog.c:112 msgid "Unknown License" msgstr "Невідома ліцензія" #: src/bz-license-dialog.c:115 msgid "Community Built" msgstr "Розроблено спільнотою" # Згідно перекладу на Flathub #: src/bz-license-dialog.c:148 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Цей застосунок розробляється у відкритому доступі міжнародною спільнотою та " "випускається під %s.\n" "\n" "Ви можете долучитися до проєкту та зробити його ліпшим." # Згідно перекладу на Flathub #: src/bz-license-dialog.c:156 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Цей застосунок розробляється у відкритому доступі міжнародною спільнотою.\n" "\n" "Ви можете долучитися до проєкту та зробити його ліпшим." #: src/bz-license-dialog.c:161 msgid "The license of this app is not known" msgstr "Ліцензія цього застосунку невідома" # Згідно перекладу на Flathub #: src/bz-license-dialog.c:165 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Цей застосунок не розробляється у відкритому доступі, тому лише його " "розробники знають, як він працює. Він може мати вразливості, які важко " "виявити, і може змінюватися без нагляду.\n" "\n" "Ви можете не мати можливості долучитися до проєкту." #: src/bz-license-dialog.c:174 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Цей застосунок розробляється на умовах власної ліцензії %s.\n" "\n" "Ви можете не мати можливості долучитися до проєкту." #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Налаштування" #: src/bz-preferences-dialog.blp:23 msgid "Content Filters" msgstr "Відсіяти вміст" #: src/bz-preferences-dialog.blp:26 msgid "Free Software Only" msgstr "Вільна ліцензія" #: src/bz-preferences-dialog.blp:27 msgid "Hide proprietary applications when browsing and searching" msgstr "Ховати власницькі (пропрієтарні) застосунки з огляду та пошуку" #: src/bz-preferences-dialog.blp:31 msgid "Flathub Results Only" msgstr "Надходження лише з Flathub" #: src/bz-preferences-dialog.blp:32 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "" "Обмежити надходження у пошуку та огляді лише до тих, що походять з Flathub" #: src/bz-preferences-dialog.blp:36 msgid "Hide EOL Apps" msgstr "Сховати осиротілі застосунки" #: src/bz-preferences-dialog.blp:37 msgid "Hide apps which are no longer supported by their developers" msgstr "" "Сховати застосунки, котрі більше не підтримуються власними розробниками" #: src/bz-preferences-dialog.blp:42 src/bz-window.blp:313 msgid "Search" msgstr "Пошук" #: src/bz-preferences-dialog.blp:45 msgid "Delay Search Results" msgstr "Чекати вводу" #: src/bz-preferences-dialog.blp:46 msgid "Improve results performance by debouncing search terms" msgstr "Поліпшити швидкодію пошуку, затримуючи відправлення пошукових запитів" #: src/bz-preferences-dialog.blp:51 msgid "Progress Bar" msgstr "Смужка поступу" #: src/bz-preferences-dialog.blp:52 msgid "Choose a theme for the progress bar!" msgstr "Оберіть цікавий зовнішній вигляд для смужки поступу!" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Акцентний колір" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Барви Гордості" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "Лесбійський прапор" #: src/bz-preferences-dialog.c:35 msgid "Transgender Pride Colors" msgstr "Трансґендерний прапор" #: src/bz-preferences-dialog.c:36 msgid "Nonbinary Pride Colors" msgstr "Небінарний прапор" #: src/bz-preferences-dialog.c:37 msgid "Bisexual Pride Colors" msgstr "Бісексуальні барви Гордості" #: src/bz-preferences-dialog.c:38 msgid "Asexual Pride Colors" msgstr "Асексуальні барви Гордості" #: src/bz-preferences-dialog.c:39 msgid "Pansexual Pride Colors" msgstr "Пансексуальний прапор" #: src/bz-preferences-dialog.c:40 msgid "Aromantic Pride Colors" msgstr "Аромантичний прапор" #: src/bz-preferences-dialog.c:41 msgid "Genderfluid Pride Colors" msgstr "Ґендерфлюїдний прапор" #: src/bz-preferences-dialog.c:42 msgid "Polysexual Pride Colors" msgstr "Полісексуальний прапор" #: src/bz-preferences-dialog.c:43 msgid "Omnisexual Pride Colors" msgstr "Омнісексуальний прапор" #: src/bz-preferences-dialog.c:44 msgid "Aroace Pride Colors" msgstr "Прапор ароейс" #: src/bz-preferences-dialog.c:45 msgid "Agender Pride Colors" msgstr "Аґендерний прапор" #: src/bz-preferences-dialog.c:46 msgid "Genderqueer Pride Colors" msgstr "Ґендерквірний прапор" #: src/bz-preferences-dialog.c:47 msgid "Intersex Pride Colors" msgstr "Інтерсексуальний прапор" #: src/bz-preferences-dialog.c:48 msgid "Demigender Pride Colors" msgstr "Деміґендерний прапор" #: src/bz-preferences-dialog.c:49 msgid "Biromantic Pride Colors" msgstr "Біромантичний прапор" #: src/bz-releases-dialog.blp:5 src/bz-releases-list.blp:26 msgid "Version History" msgstr "Історія версій" #: src/bz-releases-list.c:128 #, c-format msgid "Version %s" msgstr "Версія %s" #: src/bz-releases-list.c:153 msgid "No details for this release" msgstr "Без подробиць" # Сирець підказує, що це кнопка завантаження #: src/bz-rich-app-tile.blp:154 msgid "Get" msgstr "Завантажити" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "Знімки" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "Попередній знімок" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "Наступний знімок" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "Копіювати знімок" #: src/bz-screenshot-page.blp:147 msgid "Reset View" msgstr "Відновити масштаб" #: src/bz-screenshot-page.blp:158 msgid "Zoom Out" msgstr "Віддалити" #: src/bz-screenshot-page.blp:168 msgid "Zoom In" msgstr "Наблизити" #: src/bz-screenshots-carousel.blp:6 msgid "Screenshots Carousel" msgstr "Карусель знімків" #: src/bz-screenshots-carousel.blp:104 msgid "Open Screenshot Viewer" msgstr "Відкрити переглядач знімків" #: src/bz-search-widget.blp:106 msgid "Search Apps, Games, Software" msgstr "Шукайте застосунки, ігри та програми" #: src/bz-search-widget.blp:150 msgid "Categories Unavailable" msgstr "Категорії недоступні" #: src/bz-search-widget.blp:151 msgid "Search for apps using the search bar above." msgstr "Шукайте застосунки за допомогою рядка згори." #: src/bz-search-widget.blp:235 msgid "No Applications Found" msgstr "Жодного підібраного застосунку" #: src/bz-search-widget.c:241 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "Не знайдено збігів для «%s» на Flathub" #: src/bz-share-list.c:64 msgid "Copied!" msgstr "Скопійовано!" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "Копіювати посилання" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Відкрити посилання" # https://slovotvir.org.ua/words/taimlain #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "Часоряд" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "Встановлень:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "Світ" #: src/bz-tag-list.c:96 msgid "No Results Found" msgstr "Нічого не знайдено" # Буквальний переклад дещо задовгий. #: src/bz-tag-list.c:108 #, c-format msgid "Apps Tagged \"%s\"" msgstr "Мітка «%s»" #: src/bz-tag-list.c:109 #, c-format msgid "%d Applications" msgstr "%d застосунків" #: src/bz-tag-list.c:124 msgid "Search failed" msgstr "Пошук завершився невдало" #: src/bz-transaction-manager.c:1135 #, c-format msgid "Finished in %.02f seconds" msgstr "Завершено за %.02f сек" #: src/bz-transaction-view.blp:95 msgid "App Add-on" msgstr "Розширення" #: src/bz-transaction-view.blp:120 msgid "Runtime" msgstr "Середовище виконання" #: src/bz-transaction-view.blp:146 src/bz-transaction-view.blp:172 msgid "Install Size" msgstr "Розмір встановлення" #: src/bz-transaction-view.blp:200 msgid "Update" msgstr "Оновлення" #: src/bz-transaction-view.c:139 #, c-format msgid "Transferred %s so far" msgstr "Наразі отримано %s" #: src/bz-transaction.c:336 msgid "Pending" msgstr "Очікуємо" #: src/bz-update-dialog.blp:7 msgid "Update Now" msgstr "Оновити зараз" #: src/bz-update-dialog.blp:10 msgid "Updates Are Available" msgstr "Доступні оновлення" #: src/bz-update-dialog.blp:11 msgid "" "The following applications are eligible for updates. Would you like to " "install them?" msgstr "Для цих застосунків доступні оновлення. Бажаєте встановити?" #: src/bz-update-dialog.c:134 #, c-format msgid "" "%d runtimes and/or addons are eligible for updates. Would you like to " "install them?" msgstr "" "Для %d середовищ виконання та/або розширень доступні оновлення. Бажаєте " "встановити?" #: src/bz-update-dialog.c:142 #, c-format msgid "Additionally, %d runtimes and/or addons will be updated." msgstr "Крім того, буде оновлено %d середовищ виконання та/або розширень." #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "Керувати залишковими даними" #: src/bz-user-data-page.blp:55 msgid "No User Data found" msgstr "Користувацьких даних не знайдено" #: src/bz-user-data-page.blp:60 msgid "User Data" msgstr "Користувацькі дані" #: src/bz-user-data-tile.c:144 #, c-format msgid "Removed User Data for %s" msgstr "Користувацькі дані %s було видалено" #: src/bz-user-data-tile.blp:74 msgid "Remove User Data" msgstr "Видалити користувацькі дані" #: src/bz-window.blp:66 msgid "Inspect UI Entry" msgstr "Дослідити рядок інтерфейсу" #: src/bz-window.blp:73 msgid "All Debug Actions" msgstr "Усі дії зневадження" #: src/bz-window.blp:107 msgid "Tasks" msgstr "Дії" #: src/bz-window.blp:163 msgid "Stop Active Tasks" msgstr "Зупинити активні дії" #: src/bz-window.blp:171 msgid "Clear History" msgstr "Очистити історію" #: src/bz-window.blp:187 msgid "No Tasks Yet" msgstr "Жодних дій" #: src/bz-window.blp:258 msgid "Refreshing Store Content" msgstr "Оновлюємо вміст крамниці" #: src/bz-window.blp:273 msgid "Curated" msgstr "Підібрані" #: src/bz-window.blp:286 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:450 msgid "Network connection is metered — automatic store data sync is paused" msgstr "Платне зʼєднання — автоматичне освіження вмісту крамниці призупинено" #: src/bz-window.blp:451 src/bz-window.blp:460 msgid "Sync Manually" msgstr "Освіжити власноруч" #: src/bz-window.blp:459 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "Ви маєте зʼєднання з мережею, але переглядаєте кешовану версію Flathub" #: src/bz-window.blp:534 msgid "_Login with Flathub" msgstr "_Увійти з допомогою Flathub" #: src/bz-window.blp:540 msgid "_Manage Leftover User Data" msgstr "_Керувати залишковими даними" #: src/bz-window.blp:545 msgid "_Synchronize Remotes" msgstr "_Освіжити віддалені сховища" #: src/bz-window.blp:571 msgid "Open Bazaar Inspector" msgstr "Відкрити зневаджувач" #: src/bz-window.blp:586 msgid "Log Out" msgstr "Вийти" #: src/bz-window.c:484 #, c-format msgid "%d Update Available" msgid_plural "%d Updates Available" msgstr[0] "Доступне %s оновлення" msgstr[1] "Доступні %s оновлення" msgstr[2] "Доступні %s оновлень" #: src/bz-window.c:982 msgid "" "The ability to inspect and install local .flatpak bundle files is coming " "soon! In the meantime, try running\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "on the command line." msgstr "" "Можливість оглянути та встановити локальні файл-пакунки .flatpak скоро буде " "доступна! Тим часом, спробуйте виконати команду\n" "\n" "flatpak install --bundle ваш-файл-пакунок.flatpak\n" "\n" "у терміналі." #: src/bz-window.c:1120 msgid "Can't do that right now!" msgstr "Наразі цього не можна зробити!" # Виглядає як заголовок «пташечки» у діалозі при видаленні застосунку. #: src/bz-window.c:1251 msgid "Keep Data" msgstr "Залишити дані" #: src/bz-window.c:1252 msgid "Allow restoring settings and content" msgstr "Залишити можливість відновити налаштування та вміст у майбутньому" #: src/bz-window.c:1261 msgid "Permanently remove app data to save space" msgstr "Назавжди видалити дані застосунку" #: src/bz-window.c:1284 #, c-format msgid "Install %s?" msgstr "Встановити %s?" #: src/bz-window.c:1287 msgid "May install additional shared components" msgstr "Можуть бути встановлені додаткові компоненти" #: src/bz-window.c:1306 #, c-format msgid "Remove %s?" msgstr "Видалити %s?" #: src/bz-window.c:1310 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "%s не можна буде користати після видалення." #: src/bz-window.c:1373 msgid "Resume Current Tasks" msgstr "Відновити активні дії" #: src/bz-window.c:1379 msgid "Pause Current Tasks" msgstr "Призупинити активні дії" #: src/bz-world-map.c:572 #, c-format msgid "%s: %'u downloads" msgstr "%s: %'u завантажень" #: src/gtk/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Загальні" #: src/gtk/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "Відкрити вікно пошуку" #: src/gtk/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Налаштування" #: src/gtk/shortcuts-dialog.blp:19 msgctxt "shortcut window" msgid "Refresh" msgstr "Освіжити" #: src/gtk/shortcuts-dialog.blp:24 msgctxt "shortcut window" msgid "Toggle Transaction Manager" msgstr "Перемкнути віконце дій над застосунками" #: src/gtk/shortcuts-dialog.blp:29 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Показати клавіатурні скорочення" #: src/gtk/shortcuts-dialog.blp:34 msgctxt "shortcut window" msgid "Quit" msgstr "Вийти" bazaar-orig-v0.7.14/po/zh_CN.po0000664000175000017500000022657115166123241015134 0ustar hasanhasan# Chinese translations for bazaar package # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Shinsei , 2025. # jiesou , 2026. # Mikosh <>, 2026. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-02-09 15:07+0000\n" "PO-Revision-Date: 2026-02-10 01:09+0800\n" "Last-Translator: jiesou \n" "Language-Team: Chinese (China)\n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Gtranslator 49.0\n" "Plural-Forms: nplurals=1; plural=0;\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:6 #: src/bz-window.blp:111 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "添加、卸载和更新此电脑上的 Flatpak 软件" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" #: data/io.github.kolunmi.Bazaar.desktop.in:15 msgid "New Window" msgstr "新窗口" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and install applications" msgstr "发现和安装应用" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A new app store for Linux with a focus on discovering and installing " "applications and addons from Flatpak remotes, particularly Flathub." msgstr "" "一款专为 Linux 设计的新应用商店,致力于从 Flatpak 远程仓库(特别是 Flathub)" "中发现并安装应用程序及插件。" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:14 msgid "" "It emphasizes supporting the developers who make the Linux desktop possible. " "Bazaar features a \"curated\" tab that can be configured by distributors to " "allow for a more localized experience." msgstr "" "其强调支持那些使 Linux 桌面成为可能的开发者。Bazaar 设有一个\"精选\"标签,可" "由发行商配置,以提供更本地化的体验。" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:29 src/bz-application.c:701 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:54 msgid "The home page displaying Flathub apps" msgstr "展示 Flathub 应用程序的主页" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:58 msgid "Nucleus app page" msgstr "Nucleus 应用页" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:62 msgid "Search page" msgstr "搜索页" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:66 msgid "Category page" msgstr "分类页" #: src/bz-addons-dialog.blp:16 src/bz-full-view.blp:695 #: src/bz-installed-tile.blp:101 msgid "Manage Add-ons" msgstr "管理附加组件" #: src/bz-addons-dialog.c:94 src/bz-full-view.blp:482 #: src/bz-installed-tile.blp:119 src/bz-transaction-dialog.c:227 msgid "Remove" msgstr "卸载" #: src/bz-addons-dialog.c:99 src/bz-favorites-tile.c:174 #: src/bz-full-view.blp:249 src/bz-full-view.blp:469 #: src/bz-transaction-dialog.c:198 msgid "Install" msgstr "安装" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 #: src/bz-age-rating-dialog.c:726 src/bz-full-view.c:331 src/bz-full-view.c:338 msgid "Age Rating" msgstr "年龄分级" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "卡通暴力" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "无卡通暴力相关信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "幻想暴力" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "无关于幻想暴力的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "写实暴力" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "无关于写实暴力的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "暴力描绘流血场面" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "无关于血腥的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "性暴力" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "无关于性暴力的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "酒精" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "无关于酒精的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "毒品" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "无使用非法药物的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "烟草" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "无关于烟草产品的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "裸露" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "无任何种类的裸体信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "性主题" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "无关于提及和描绘性的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "脏话" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "不含任何种类的脏话信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "不适当幽默" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "无关于不当幽默的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "歧视" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "无关于歧视语言的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "广告" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "无任任何广告信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "赌博" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "无任何赌博内容" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "购买" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "无关于花钱能力的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "用户间交流" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "无关于与其他用户文字交流方式的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "用户见语音交流" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "无关于与其他用户语音交流方式的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 msgid "Contact Details" msgstr "联系详情" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "未提供有关分享社交媒体用户名或电子邮件地址的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "识别信息" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "未提供与第三方共享用户信息的相关信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "位置共享" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "未提供与其他用户共享物理位置的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "卖淫" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "未提及有关卖淫的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "通奸" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "没有关于通奸相关信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "性化角色" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "未提供有关性化角色的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 msgid "Desecration" msgstr "亵渎" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "没有关于亵渎行为的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "人类遗骸" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "没有关于可见的人类遗骸的信息" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "奴隶制" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "不含提及奴隶制的信息" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "不包括对毒品的提及" #: src/bz-age-rating-dialog.c:426 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "不包括咒骂、脏话及其他类型的强烈言辞" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "不包括广告或货币交易" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "不包含性内容或裸露镜头" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "不包含不受控制的聊天功能" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "不包含暴力" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "药品" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "粗俗语言" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "金钱" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "社交" #: src/bz-age-rating-dialog.c:479 msgid "Violence" msgstr "暴力" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:676 src/bz-full-view.c:321 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:701 msgctxt "Age rating" msgid "All" msgstr "所有" #: src/bz-age-rating-dialog.c:737 #, c-format msgid "%s has an unknown age rating" msgstr "%s 的年龄分级未知" #: src/bz-age-rating-dialog.c:743 #, c-format msgid "%s is suitable for everyone" msgstr "%s 适合所有人" #: src/bz-age-rating-dialog.c:746 #, c-format msgid "%s is suitable for young children" msgstr "%s 适合幼儿使用" #: src/bz-age-rating-dialog.c:749 #, c-format msgid "%s is suitable for children" msgstr "%s 适合儿童" #: src/bz-age-rating-dialog.c:752 #, c-format msgid "%s is suitable for teenagers" msgstr "%s 适合青少年" #: src/bz-age-rating-dialog.c:755 #, c-format msgid "%s is suitable for adults" msgstr "%s 适合成人用户" #: src/bz-age-rating-dialog.c:758 #, c-format msgid "%s is suitable for %s" msgstr "%s 适合 %s" #: src/bz-age-rating-dialog.c:852 #, c-format msgid "%s • %s" msgstr "%s • %s" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:16 #: src/bz-user-data-page.blp:15 src/bz-window.blp:292 msgid "Main Menu" msgstr "主菜单" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 #: src/bz-user-data-page.blp:19 src/bz-window.blp:384 msgid "_Donate to Bazaar ❤️" msgstr "_向 Bazaar 捐助 ❤️" #: src/bz-all-apps-page.blp:25 src/bz-apps-page.blp:25 #: src/bz-user-data-page.blp:26 src/bz-window.blp:391 msgid "_Preferences" msgstr "_首选项" #: src/bz-all-apps-page.blp:30 src/bz-apps-page.blp:30 #: src/bz-user-data-page.blp:31 src/bz-window.blp:396 msgid "_Login with Flathub" msgstr "_用 Flathub 登录" #: src/bz-all-apps-page.blp:36 src/bz-apps-page.blp:36 #: src/bz-user-data-page.blp:37 src/bz-window.blp:402 msgid "_Manage Leftover User Data" msgstr "_管理遗留用户数据" #: src/bz-all-apps-page.blp:41 src/bz-apps-page.blp:41 #: src/bz-user-data-page.blp:42 src/bz-window.blp:407 msgid "_Synchronize Remotes" msgstr "_同步远程" #: src/bz-all-apps-page.blp:46 src/bz-apps-page.blp:46 #: src/bz-user-data-page.blp:47 src/bz-window.blp:412 msgid "_Keyboard Shortcuts" msgstr "_键盘快捷键" #: src/bz-all-apps-page.blp:51 src/bz-apps-page.blp:51 #: src/bz-user-data-page.blp:52 src/bz-window.blp:417 msgid "_About Bazaar" msgstr "_关于 Bazaar" #: src/bz-all-apps-page.blp:58 src/bz-apps-page.blp:58 #: src/bz-user-data-page.blp:59 src/bz-window.blp:424 msgid "_Quit Bazaar" msgstr "_退出 Bazaar" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "系统文件夹 %s" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "用户主文件夹 %s" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "主机系统文件夹" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "主机系统配置来自 /etc" #: src/bz-app-permissions.c:169 #, c-format msgid "Desktop subfolder %s" msgstr "桌面子文件夹 %s" #: src/bz-app-permissions.c:170 msgid "Desktop folder" msgstr "桌面文件夹" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "文档子文件夹 %s" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "文档文件夹" #: src/bz-app-permissions.c:177 #, c-format msgid "Music subfolder %s" msgstr "音乐子文件夹 %s" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "音乐文件夹" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "图片子文件夹 %s" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "图片文件夹" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "公共共享子文件夹 %s" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "公共共享文件夹" #: src/bz-app-permissions.c:189 #, c-format msgid "Videos subfolder %s" msgstr "视频子文件夹 %s" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "视频文件夹" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "模板子文件夹 %s" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "模板文件夹" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "用户缓存子文件夹 %s" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "用户缓存文件夹" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "用户配置子文件夹 %s" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "用户配置文件夹" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "用户数据子文件夹 %s" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "用户数据文件夹" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "用户运行时子文件夹 %s" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "用户运行时文件夹" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "对 %s 的文件系统访问" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "未知文件系统路径" #: src/bz-app-size-dialog.blp:29 src/bz-app-size-dialog.blp:55 msgid "Download Size" msgstr "下载大小" #: src/bz-app-size-dialog.blp:56 msgid "Amount to download from the internet" msgstr "从互联网下载的大小" #: src/bz-app-size-dialog.blp:76 msgid "Installed Size" msgstr "已安装占用" #: src/bz-app-size-dialog.blp:77 msgid "Size on Disk" msgstr "硬盘占用" #: src/bz-app-size-dialog.blp:99 msgid "User Data Size" msgstr "用户数据大小" #: src/bz-app-size-dialog.blp:100 msgid "Caches, settings, and other app data" msgstr "缓存、设置和其他应用数据" #. Translators: As in 'The app is installed'. #: src/bz-app-tile.blp:86 src/bz-full-view.c:280 src/bz-releases-list.c:178 msgid "Installed" msgstr "已安装" #: src/bz-apps-page.blp:142 msgid "Show All" msgstr "展示所有" #: src/bz-apps-page.c:243 #, c-format msgid "All \"%s\"" msgstr "所有 \"%s\"" #: src/bz-apps-page.c:530 src/bz-tag-list.c:109 #, c-format msgid "%d Applications" msgstr "%d 个应用" #: src/bz-application.c:672 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:673 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:704 msgid "translator-credits" msgstr "Shinsei , 2025" #: src/bz-application.c:715 msgid "Special Thanks" msgstr "特别感谢" #: src/bz-application.c:773 msgid "Logged Out Successfully!" msgstr "登出成功!" #: src/bz-application.c:896 msgid "Performing setup..." msgstr "正在执行设置..." #: src/bz-application.c:979 src/bz-application.c:988 msgid "Set Up Flathub" msgstr "注册 Flathub" #: src/bz-application.c:982 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "此系统未设置 Flathub。如果 Flathub 不可用,您将无法在 Bazaar 中浏览和安装应用" "程序。\n" "\n" "您仍可使用 Bazaar 浏览和卸载已安装的应用程序。" #: src/bz-application.c:987 msgid "Later" msgstr "稍后" #: src/bz-application.c:1397 src/bz-application.c:3087 msgid "Synchronizing..." msgstr "同步中……" #: src/bz-application.c:1544 src/bz-application.c:3083 #, c-format msgid "Receiving %d entries..." msgstr "正在接收 %d 个条目..." #: src/bz-application.c:1549 msgid "Checking for updates" msgstr "正在检查更新" #: src/bz-application.c:3089 msgid "Indexing Data..." msgstr "正在索引数据……" #: src/bz-appstream-parser.c:265 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Flathub 页面" #: src/bz-appstream-parser.c:286 msgctxt "Project URL Type" msgid "Project Website" msgstr "项目网站" #: src/bz-appstream-parser.c:290 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "问题追踪器" #: src/bz-appstream-parser.c:294 msgctxt "Project URL Type" msgid "FAQ" msgstr "FAQ" #: src/bz-appstream-parser.c:298 msgctxt "Project URL Type" msgid "Help" msgstr "帮助" #: src/bz-appstream-parser.c:302 msgctxt "Project URL Type" msgid "Donate" msgstr "捐助" #: src/bz-appstream-parser.c:308 msgctxt "Project URL Type" msgid "Translate" msgstr "翻译" #: src/bz-appstream-parser.c:312 msgctxt "Project URL Type" msgid "Contact" msgstr "联系" #: src/bz-appstream-parser.c:316 msgctxt "Project URL Type" msgid "Source Code" msgstr "源代码" #: src/bz-appstream-parser.c:322 msgctxt "Project URL Type" msgid "Contribute" msgstr "贡献" #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:68 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:48 #: src/bz-library-page.blp:59 src/bz-user-data-page.blp:86 msgid "Empty" msgstr "空" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "无精选应用程序" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "该系统未提供策展信息。您仍可在 Flathub 上浏览应用程序。" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "浏览 Flathub" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "离线" #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 msgid "Browser" msgstr "浏览器" #: src/bz-developer-badge.c:131 msgid "Developer information not available." msgstr "无法获取开发者信息" #: src/bz-developer-badge.c:137 src/bz-developer-badge.c:151 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "该 %s 应用 ID 的所有权尚未验证,可能是一个社区包。" #: src/bz-developer-badge.c:155 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "该 %s 应用 ID 的所有权已由 Flathub 团队手动验证。" #: src/bz-developer-badge.c:161 #, c-format msgid "" "The ownership of the %1$s app ID has been verified by %2$s on " "%3$s." msgstr "%1$s 应用 ID 的所有权已验证为是 %3$s 上的 %2$s。" #: src/bz-developer-badge.c:168 #, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "%1$s 应用 ID 的所有权已通过 %2$s 验证。" #: src/bz-developer-badge.c:172 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "该 %s 应用 ID 的所有权已通过验证。" #: src/bz-donations-dialog.blp:58 #, fuzzy msgid "This Bazaar Release Was Made Possible By Users Like You!" msgstr "正是有了像您这样的用户,Bazaar 才能顺利发行!" #: src/bz-donations-dialog.blp:66 #, fuzzy msgid "" "I love making Bazaar, but I cannot do it alone. If you would like to help " "support further development, please consider donating to the project at my " "ko-fi:" msgstr "" "我热爱开发 Bazaar,但我一个人的力量有限。如果您愿意支持后续的开发工作,请考虑" "在 ko-fi 捐助我:" #: src/bz-donations-dialog.blp:76 #, fuzzy msgid "Donate to Bazaar" msgstr "_向 Bazaar 捐助 ❤️" #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "选择和安装" #: src/bz-entry-group-util.c:76 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "您已安装此应用的多个版本。您希望用哪一个继续?" #: src/bz-entry-group-util.c:80 src/bz-transaction-dialog.c:197 #: src/bz-transaction-dialog.c:226 src/bz-transaction-dialog.c:271 #: src/bz-transaction-dialog.c:562 msgid "Cancel" msgstr "取消" #: src/bz-entry-selection-row.blp:17 msgid "For this user only" msgstr "仅适用于当前用户" #: src/bz-entry-selection-row.c:112 msgid "this user" msgstr "当前用户" #: src/bz-entry-selection-row.c:112 msgid "all users" msgstr "所有用户" #: src/bz-error.c:68 msgid "An Error Occurred" msgstr "一个错误发生了" #: src/bz-error.c:89 msgid "Close" msgstr "关闭" #: src/bz-error.c:90 msgid "Copy and Close" msgstr "复制并关闭" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "登录 Flathub 以管理收藏项目" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "登录" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "收藏数" #: src/bz-favorites-tile.c:172 msgid "Uninstall" msgstr "卸载" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:77 msgid "Support this application" msgstr "支持此应用程序" #: src/bz-favorites-tile.blp:119 msgid "Remove from Favorites" msgstr "从收藏中移除" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:78 #: src/bz-window.blp:442 msgid "Favorites" msgstr "收藏" #: src/bz-favorites-page.blp:22 src/bz-full-view.blp:31 src/bz-window.blp:307 #, fuzzy msgid "Open App Library" msgstr "打开应用库" #: src/bz-favorites-page.blp:39 src/bz-section-view.blp:144 #: src/bz-transaction-dialog.c:563 msgid "Install All" msgstr "安装全部" #: src/bz-favorites-page.blp:56 src/bz-user-data-page.blp:75 msgid "Loading" msgstr "加载中" #: src/bz-favorites-page.blp:71 msgid "No Favorites" msgstr "无收藏" #: src/bz-favorites-page.blp:72 msgid "Applications you mark as favorite will appear here" msgstr "您标记为收藏的应用程序将在此处显示" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "上一页" #: src/bz-featured-carousel.blp:53 msgid "Next" msgstr "下一页" #: src/bz-featured-tile.blp:88 msgid "App of the Day" msgstr "每日应用" #: src/bz-flathub-category.c:89 msgid "Editing" msgstr "编辑" #: src/bz-flathub-category.c:90 msgid "Midi" msgstr "MIDI" #: src/bz-flathub-category.c:91 msgid "Mixer" msgstr "调音" #: src/bz-flathub-category.c:92 msgid "Music" msgstr "音乐" #: src/bz-flathub-category.c:93 msgid "Player" msgstr "播放器" #: src/bz-flathub-category.c:94 msgid "Recorder" msgstr "录音" #: src/bz-flathub-category.c:95 msgid "Sequencer" msgstr "科学" #: src/bz-flathub-category.c:96 msgid "Tuner" msgstr "调谐器" #: src/bz-flathub-category.c:97 msgid "TV" msgstr "电视" #: src/bz-flathub-category.c:102 msgid "Emulation" msgstr "模拟器" #: src/bz-flathub-category.c:103 msgid "Action" msgstr "动作" #: src/bz-flathub-category.c:104 msgid "Adventure" msgstr "冒险" # 不用“街机“遵从 https://flathub.org/zh-Hans/apps/category/game/subcategories/ArcadeGame 的翻译 #: src/bz-flathub-category.c:105 msgid "Arcade" msgstr "游乐中心" #: src/bz-flathub-category.c:106 msgid "Blocks" msgstr "方块" #: src/bz-flathub-category.c:107 msgid "Board" msgstr "图板" #: src/bz-flathub-category.c:108 msgid "Card" msgstr "卡片" #: src/bz-flathub-category.c:109 msgid "Kids" msgstr "儿童" #: src/bz-flathub-category.c:110 msgid "Logic" msgstr "逻辑" #: src/bz-flathub-category.c:111 msgid "Role Playing" msgstr "角色扮演" #: src/bz-flathub-category.c:112 msgid "Shooter" msgstr "射手" #: src/bz-flathub-category.c:113 msgid "Simulation" msgstr "模拟" #: src/bz-flathub-category.c:114 msgid "Sports" msgstr "体育" #: src/bz-flathub-category.c:115 msgid "Strategy" msgstr "战略" #: src/bz-flathub-category.c:120 msgid "Audio & Video" msgstr "音频与视频" #: src/bz-flathub-category.c:120 msgid "Media" msgstr "媒体" #: src/bz-flathub-category.c:120 msgid "More Audio & Video" msgstr "更多音频与视频" #: src/bz-flathub-category.c:121 msgid "Developer Tools" msgstr "开发者工具" #: src/bz-flathub-category.c:121 msgid "Develop" msgstr "开发" #: src/bz-flathub-category.c:121 msgid "More Developer Tools" msgstr "更多开发者工具" #: src/bz-flathub-category.c:122 msgid "Education" msgstr "教育" #: src/bz-flathub-category.c:122 msgid "Learn" msgstr "学习" #: src/bz-flathub-category.c:122 msgid "More Education" msgstr "更多教育" #: src/bz-flathub-category.c:123 msgid "Gaming" msgstr "游戏" #: src/bz-flathub-category.c:123 msgid "Play" msgstr "游玩" #: src/bz-flathub-category.c:123 msgid "More Gaming" msgstr "更多游戏" #: src/bz-flathub-category.c:124 msgid "Graphics & Photography" msgstr "图形与摄影" #: src/bz-flathub-category.c:124 msgid "Create" msgstr "创造" #: src/bz-flathub-category.c:124 msgid "More Graphics & Photography" msgstr "更多图形与摄影" #: src/bz-flathub-category.c:125 msgid "Networking" msgstr "网络" #: src/bz-flathub-category.c:125 msgid "Internet" msgstr "互联网" #: src/bz-flathub-category.c:125 msgid "More Networking" msgstr "更多网络应用" #: src/bz-flathub-category.c:126 msgid "Productivity" msgstr "生产力" #: src/bz-flathub-category.c:126 msgid "Work" msgstr "工作" #: src/bz-flathub-category.c:126 msgid "More Productivity" msgstr "更多生产力" #: src/bz-flathub-category.c:127 msgid "Science" msgstr "科学" #: src/bz-flathub-category.c:127 msgid "More Science" msgstr "更多科学" #: src/bz-flathub-category.c:128 msgid "System" msgstr "系统" #: src/bz-flathub-category.c:128 msgid "More System" msgstr "更多系统" #: src/bz-flathub-category.c:129 msgid "Utilities" msgstr "实用工具" #: src/bz-flathub-category.c:129 msgid "Tools" msgstr "工具" #: src/bz-flathub-category.c:129 msgid "More Utilities" msgstr "更多实用工具" #: src/bz-flathub-category.c:130 src/bz-flathub-page.blp:119 #: src/bz-flathub-page.blp:152 msgid "Trending" msgstr "飙升" #: src/bz-flathub-category.c:130 msgid "More Trending" msgstr "更多飙升应用" #: src/bz-flathub-category.c:131 src/bz-flathub-page.blp:125 #: src/bz-flathub-page.blp:185 msgid "Popular" msgstr "人气" #: src/bz-flathub-category.c:131 msgid "More Popular" msgstr "更多人气应用" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:174 msgid "Recently Added" msgstr "最近添加" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:131 msgid "New" msgstr "新应用" #: src/bz-flathub-category.c:132 msgid "More New" msgstr "更多新应用" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:163 msgid "Recently Updated" msgstr "最近更新" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:137 msgid "Updated" msgstr "最近更新" #: src/bz-flathub-category.c:133 msgid "More Updated" msgstr "更多最近更新应用" #: src/bz-flathub-category.c:134 msgid "Mobile" msgstr "移动应用" #: src/bz-flathub-category.c:134 msgid "More Mobile" msgstr "更多移动应用" #: src/bz-flathub-category.c:135 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:135 msgid "More Adwaita" msgstr "更多 Adwaita 应用" #: src/bz-flathub-category.c:136 msgid "KDE Apps" msgstr "KDE 应用" #: src/bz-flathub-category.c:136 msgid "More KDE Apps" msgstr "更多 KDE 应用" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Flathub 未添加" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "您的 Flatpak 安装中未找到 Flathub 远程仓库" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "Flathub 返回错误" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "重试 Flathub 连接" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Flathub 不可用" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "我们无法连接到 Flathub。您仍然可以管理和搜索应用程序。" #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "搜索应用程序" #: src/bz-flathub-page.blp:270 msgid "On the Go" msgstr "随时随地" #: src/bz-flathub-page.blp:282 msgid "Apps for your Linux phones and tablets" msgstr "适用于您的 Linux 手机和平板电脑的应用" #: src/bz-flathub-page.blp:293 src/bz-flathub-page.blp:328 msgid "More Mobile Apps" msgstr "更多移动应用" #: src/bz-flathub-page.blp:388 msgid "We​ ♥​ Games" msgstr "我们 ♥ 游戏" #: src/bz-flathub-page.blp:401 msgid "Games and apps to run your favorite titles" msgstr "运行您喜爱的游戏和应用" #: src/bz-flathub-page.blp:435 msgid "More Games" msgstr "更多游戏" #: src/bz-full-view.blp:52 src/bz-library-page.blp:70 #: src/bz-library-page.blp:74 msgid "No Results" msgstr "无结果" #: src/bz-full-view.blp:53 msgid "Try a different search query" msgstr "尝试不同的搜索关键字" #: src/bz-full-view.blp:59 msgid "Content" msgstr "内容" #: src/bz-full-view.blp:117 msgid "Installing .flatpak bundles is not yet supported" msgstr "安装 .flatpak 包暂不支持" #: src/bz-full-view.blp:210 msgid "Support" msgstr "支持" #: src/bz-full-view.blp:233 src/bz-full-view.blp:493 msgid "Open" msgstr "打开" #: src/bz-full-view.blp:246 src/bz-full-view.blp:466 msgid "Download & Install Application" msgstr "下载并安装应用程序" #: src/bz-full-view.blp:261 msgid "Uninstall Application" msgstr "卸载此应用程序" #: src/bz-full-view.blp:276 src/bz-full-view.blp:508 msgid "Install Other Version" msgstr "安装其他版本" #: src/bz-full-view.blp:430 msgid "Downloads/Month" msgstr "次下载/月" #: src/bz-full-view.blp:527 msgid "Stopped Receiving Core Updates" msgstr "停止接收核心更新" #: src/bz-full-view.blp:541 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "此应用使用的运行时环境已不再接收更新或安全修复,继续使用可能存在安全隐患" #: src/bz-full-view.blp:630 msgid "Trash Data" msgstr "垃圾数据" #: src/bz-full-view.blp:771 msgid "Tags:" msgstr "标签:" #: src/bz-full-view.c:220 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:227 #, c-format msgid "%.*fM" msgstr "%.*fM" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:234 #, c-format msgid "%.*fK" msgstr "%.*fK" #: src/bz-full-view.c:244 #, c-format msgid "%d downloads in the last 30 days" msgstr "过去 30 天内下载 %d 次" #: src/bz-full-view.c:256 src/bz-full-view.c:590 src/bz-full-view.c:607 msgid "N/A" msgstr "N/A" #. Translators: . #: src/bz-full-view.c:280 msgid "Download" msgstr "下载" #: src/bz-full-view.c:300 msgid "Size information unavailable" msgstr "大小信息不可用" #: src/bz-full-view.c:303 #, c-format msgid "Download size of %s" msgstr "%s 的下载大小" #: src/bz-full-view.c:336 msgid "All Ages" msgstr "全年龄" #: src/bz-full-view.c:348 msgid "Age rating information unavailable" msgstr "年龄分级信息不可用" #: src/bz-full-view.c:353 msgid "Suitable for all ages" msgstr "适合全年龄段" #: src/bz-full-view.c:355 #, c-format msgid "Suitable for ages %d and up" msgstr "适合年龄为 %d 岁及以上" #: src/bz-full-view.c:388 src/bz-full-view.c:393 src/bz-full-view.c:421 #: src/bz-full-view.c:432 msgid "Unknown" msgstr "未知" #: src/bz-full-view.c:398 #, c-format msgid "Free software licensed under %s" msgstr "根据 %s 许可证授权的自由软件" #: src/bz-full-view.c:403 msgid "Free software" msgstr "自由软件" #: src/bz-full-view.c:406 msgid "Proprietary Software" msgstr "专有软件" #: src/bz-full-view.c:409 #, c-format msgid "Special License: %s" msgstr "特殊许可证: %s" #: src/bz-full-view.c:426 msgid "Free" msgstr "自由" #: src/bz-full-view.c:429 src/bz-license-dialog.c:132 msgid "Proprietary" msgstr "专有" #: src/bz-full-view.c:434 src/bz-license-dialog.c:134 msgid "Special License" msgstr "特殊许可" #: src/bz-full-view.c:454 msgid "Adaptive" msgstr "自适应" #: src/bz-full-view.c:454 msgid "Desktop Only" msgstr "仅桌面端" #: src/bz-full-view.c:460 msgid "Works on desktop, tablets, and phones" msgstr "适用于台式机、平板电脑和手机" #: src/bz-full-view.c:461 msgid "May not work on mobile devices" msgstr "可能无法在移动设备上使用" #: src/bz-full-view.c:472 msgid "No URL" msgstr "无链接" #: src/bz-full-view.c:490 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "该应用程序具有 FLOSS 许可证,这意味着可以审核源代码的安全性。" #: src/bz-full-view.c:491 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "该应用程序具有专有许可证,这意味着源代码是私人开发的,不能由独立的第三方审" "核。" #: src/bz-full-view.c:498 msgid "More Apps" msgstr "更多应用" #: src/bz-full-view.c:499 #, c-format msgid "More Apps by %s" msgstr "来自 %s 的更多应用" #: src/bz-full-view.c:506 msgid "Other Apps by this Developer" msgstr "该开发者的其他应用" #: src/bz-full-view.c:508 src/bz-full-view.c:708 #, c-format msgid "Other Apps by %s" msgstr "来自 %s 的其他应用" #: src/bz-full-view.c:517 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "%s 未安装,但仍存在 %s 的数据。" #: src/bz-full-view.c:597 src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "安全" #: src/bz-full-view.c:599 src/bz-full-view.c:601 msgid "Low Risk" msgstr "低风险" #: src/bz-full-view.c:603 msgid "Medium Risk" msgstr "中等风险" #: src/bz-full-view.c:605 msgid "High Risk" msgstr "高风险" #: src/bz-full-view.c:710 msgid "Other Apps" msgstr "其他应用" #: src/bz-full-view.c:712 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d 个应用" #: src/bz-full-view.c:1051 msgid "Show Less" msgstr "显示更少" #: src/bz-full-view.c:1051 msgid "Show More" msgstr "显示更多" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 msgid "Hardware Support" msgstr "硬件支持情况" #: src/bz-hardware-support-dialog.c:62 msgid "Keyboard support" msgstr "键盘支持情况" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "需要键盘" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "推荐键盘" #: src/bz-hardware-support-dialog.c:66 msgid "Supports keyboards" msgstr "支持键盘" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "键盘支持情况未知" #: src/bz-hardware-support-dialog.c:69 msgid "Mouse support" msgstr "鼠标支持情况" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "需要鼠标或指针设备" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "推荐鼠标或指针设备" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "支持鼠标或指针设备" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "鼠标或指针设备支持情况未知" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "触控支持情况" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "需要触控" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "推荐触控" #: src/bz-hardware-support-dialog.c:80 msgid "Supports touchscreens" msgstr "支持触控" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "触控支持情况未知" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "移动设备支持情况" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "可运行于移动设备" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "可能不支持移动设备" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "桌面端支持情况" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "大屏上运行良好" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "%s 在特定硬件上运行最佳" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "%s 在大多数设备正常工作" #: src/bz-installed-tile.blp:63 src/bz-rich-app-tile.blp:136 msgid "Stopped Receiving Updates" msgstr "停止接收更新" #: src/bz-library-page.blp:29 msgid "Search installed apps" msgstr "搜索已安装的应用程序" #: src/bz-library-page.blp:63 msgid "No Apps Found" msgstr "未找到应用程序" #. Translators: . #: src/bz-library-page.blp:82 src/bz-window.blp:179 #, fuzzy msgid "Library" msgstr "库" #: src/bz-library-page.blp:110 msgid "Pending Updates" msgstr "等待更新" #: src/bz-library-page.blp:137 msgid "Downloads" msgstr "下载" #: src/bz-library-page.blp:180 msgid "Recently Uninstalled" msgstr "最近卸载" #: src/bz-library-page.blp:231 msgid "Clear Finished Tasks" msgstr "清除所有已完成的事务" #: src/bz-library-page.blp:242 msgid "Installed Apps" msgstr "已安装" #: src/bz-library-page.c:152 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "在已安装应用列表中未找到与 “%s” 匹配的项目" #: src/bz-library-page.c:165 src/bz-updates-card.c:257 #, c-format msgid "%u Available Update" msgid_plural "%u Available Updates" msgstr[0] "%u 个可用更新" #: src/bz-license-dialog.blp:95 msgid "Get Involved" msgstr "参与进来" #: src/bz-license-dialog.c:126 msgid "Unknown License" msgstr "未知许可证" #: src/bz-license-dialog.c:129 msgid "Community Built" msgstr "社区共建" #: src/bz-license-dialog.c:202 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "此应用由一个国际社区以开源方式开发而成。\n" "\n" "您可以参与进来,帮助它变得更好。" #: src/bz-license-dialog.c:205 msgid "The license of this app is not known" msgstr "此应用的许可证未知" #: src/bz-license-dialog.c:211 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "此应用由国际社区开放开发,并根据 %s 许可证发布。\n" "\n" "您可以参与进来,帮助它变得更好。" #: src/bz-license-dialog.c:219 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "此应用未采用开放开发,因此只有开发者知道其运作机制。它可能存在难以察觉的安全" "漏洞,且可能在缺乏监管的情况下进行更改。\n" "\n" "您可能无法为本应用做出贡献。" #: src/bz-license-dialog.c:225 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "本应用基于特殊许可证 %s 开发。\n" "\n" "您可能无法为本应用做出贡献。" #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 msgid "Connect to Flathub" msgstr "连接到 Flathub" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "发生错误" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "将您的 Flathub 账户连接到 Bazaar,以便管理您收藏的应用程序。" #: src/bz-login-page.blp:108 msgid "Finish" msgstr "完成" #: src/bz-login-page.c:663 #, c-format msgid "Hello, %s!" msgstr "你好,%s!" #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "偏好设置" #: src/bz-preferences-dialog.blp:25 msgid "Network connection is metered — automatic store data sync is paused" msgstr "正在使用计费网络 - 自动储存数据同步已暂停" #: src/bz-preferences-dialog.blp:26 src/bz-window.blp:334 msgid "Sync Manually" msgstr "手动同步" #: src/bz-preferences-dialog.blp:31 msgid "Content Filters" msgstr "内容筛选" #: src/bz-preferences-dialog.blp:34 msgid "Free Software Only" msgstr "仅自由软件" #: src/bz-preferences-dialog.blp:35 msgid "Hide proprietary applications when browsing and searching" msgstr "浏览和搜索时隐藏专有软件" #: src/bz-preferences-dialog.blp:39 msgid "Flathub Results Only" msgstr "仅包含 Flathub 结果" #: src/bz-preferences-dialog.blp:40 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "限制搜索和浏览的应用仅可从 Flathub 获取" #: src/bz-preferences-dialog.blp:44 msgid "Verified Results Only" msgstr "仅显示已验证结果" #: src/bz-preferences-dialog.blp:45 msgid "Hide results that are not verified on Flathub" msgstr "隐藏未在 Flathub 上验证的结果" #: src/bz-preferences-dialog.blp:49 msgid "Hide EOL Apps" msgstr "隐藏终止支持的应用" #: src/bz-preferences-dialog.blp:50 msgid "Hide apps which are no longer supported by their developers" msgstr "隐藏开发者不再支持的应用" #: src/bz-preferences-dialog.blp:55 src/bz-window.blp:197 msgid "Search" msgstr "搜索" #: src/bz-preferences-dialog.blp:58 msgid "Delay Search Results" msgstr "延迟搜索结果" #: src/bz-preferences-dialog.blp:59 msgid "Improve results performance by debouncing search terms" msgstr "通过防抖搜索词提升结果性能" #: src/bz-preferences-dialog.blp:64 msgid "Progress Bar" msgstr "进度条" #: src/bz-preferences-dialog.blp:65 msgid "Choose a theme for the progress bar!" msgstr "为进度条选择主题!" #: src/bz-preferences-dialog.blp:89 msgid "Vertical Stripes" msgstr "竖条纹" #: src/bz-preferences-dialog.blp:90 msgid "Display flag colors from left to right" msgstr "从左至右显示旗帜颜色" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "强调色" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "骄傲色" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "女同性恋骄傲色彩" #: src/bz-preferences-dialog.c:35 msgid "Male Homosexual Pride Colors" msgstr "男同性恋骄傲色彩" #: src/bz-preferences-dialog.c:36 msgid "Transgender Pride Colors" msgstr "跨性别骄傲色" #: src/bz-preferences-dialog.c:37 msgid "Nonbinary Pride Colors" msgstr "非二元性别骄傲色彩" #: src/bz-preferences-dialog.c:38 msgid "Bisexual Pride Colors" msgstr "双性恋骄傲色彩" #: src/bz-preferences-dialog.c:39 msgid "Asexual Pride Colors" msgstr "无性恋骄傲色" #: src/bz-preferences-dialog.c:40 msgid "Pansexual Pride Colors" msgstr "泛性恋骄傲色" #: src/bz-preferences-dialog.c:41 msgid "Aromantic Pride Colors" msgstr "无浪漫倾向骄傲色" #: src/bz-preferences-dialog.c:42 msgid "Genderfluid Pride Colors" msgstr "性别流动骄傲色" #: src/bz-preferences-dialog.c:43 msgid "Polysexual Pride Colors" msgstr "多性恋骄傲色" #: src/bz-preferences-dialog.c:44 msgid "Omnisexual Pride Colors" msgstr "全性恋骄傲色彩" #: src/bz-preferences-dialog.c:45 msgid "Aroace Pride Colors" msgstr "无浪漫无性恋者骄傲色" #: src/bz-preferences-dialog.c:46 msgid "Agender Pride Colors" msgstr "无性别骄傲色" #: src/bz-preferences-dialog.c:47 msgid "Genderqueer Pride Colors" msgstr "性别酷儿骄傲色" #: src/bz-preferences-dialog.c:48 msgid "Intersex Pride Colors" msgstr "双性恋骄傲色" #: src/bz-preferences-dialog.c:49 msgid "Demigender Pride Colors" msgstr "半性别骄傲色" #: src/bz-preferences-dialog.c:50 msgid "Biromantic Pride Colors" msgstr "双浪漫骄傲色" #: src/bz-preferences-dialog.c:51 msgid "Disability Pride Colors" msgstr "残疾人骄傲色" #: src/bz-preferences-dialog.c:52 msgid "Femboy Pride Colors" msgstr "伪娘骄傲色" #: src/bz-preferences-dialog.c:53 msgid "Neutrois Pride Colors" msgstr "中性骄傲色" #: src/bz-releases-dialog.blp:5 src/bz-releases-list.blp:28 #: src/bz-updates-card.blp:150 msgid "Version History" msgstr "版本历史" #: src/bz-releases-list.c:168 #, c-format msgid "Version %s" msgstr "版本 %s" #: src/bz-releases-list.c:220 msgid "No details for this release" msgstr "未提供变更日志" #: src/bz-releases-list.c:232 msgid "Get More Information" msgstr "获得更多信息" #: src/bz-rich-app-tile.blp:153 msgid "Get" msgstr "获取" #: src/bz-safety-calculator.c:82 msgid "Unknown Permissions" msgstr "未知权限" #: src/bz-safety-calculator.c:83 msgid "Permissions are missing for this app." msgstr "此应用缺少必要的权限。" #: src/bz-safety-calculator.c:96 msgid "No Permissions" msgstr "没有权限" #: src/bz-safety-calculator.c:97 msgid "App is fully sandboxed" msgstr "应用已完全沙盒化" #: src/bz-safety-calculator.c:103 msgid "Network Access" msgstr "网络访问" #: src/bz-safety-calculator.c:104 msgid "Can access the internet" msgstr "可访问网络" #: src/bz-safety-calculator.c:106 msgid "No Network Access" msgstr "无网络访问" #: src/bz-safety-calculator.c:107 msgid "Cannot access the internet" msgstr "不能访问互联网" #: src/bz-safety-calculator.c:112 msgid "User Device Access" msgstr "用户设备访问" #: src/bz-safety-calculator.c:113 msgid "Can access devices such as webcams or gaming controllers" msgstr "可以访问网络摄像头或游戏控制器等硬件设备" #: src/bz-safety-calculator.c:115 msgid "No User Device Access" msgstr "无用户设备访问" #: src/bz-safety-calculator.c:116 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "应用不能访问网络摄像头或游戏控制器等任何用户设备" #: src/bz-safety-calculator.c:121 msgid "Input Device Access" msgstr "输入设备访问" #: src/bz-safety-calculator.c:122 msgid "Can access input devices" msgstr "可以访问输入设备" #: src/bz-safety-calculator.c:128 msgid "Microphone Access and Audio Playback" msgstr "麦克风访问和音频播放" #: src/bz-safety-calculator.c:129 msgid "Can listen using microphones and play audio without asking permission" msgstr "无需请求权限即可使用麦克风收听和播放音频" #: src/bz-safety-calculator.c:135 msgid "System Device Access" msgstr "系统设备访问" #: src/bz-safety-calculator.c:136 msgid "Can access system devices which require elevated permissions" msgstr "可以访问需要提升权限的系统设备" #: src/bz-safety-calculator.c:142 msgid "Screen Contents Access" msgstr "屏幕内容访问" #: src/bz-safety-calculator.c:143 msgid "Can access the contents of the screen or other windows" msgstr "可以访问屏幕或其他窗口的内容" #: src/bz-safety-calculator.c:149 msgid "Legacy Windowing System" msgstr "过时窗口系统" #: src/bz-safety-calculator.c:150 msgid "Always uses a legacy windowing system (X11)" msgstr "始终使用过时的窗口系统(X11)" #: src/bz-safety-calculator.c:156 msgid "Arbitrary Permissions" msgstr "任意权限" #: src/bz-safety-calculator.c:157 msgid "Can acquire arbitrary permissions" msgstr "可以获取任意权限" #: src/bz-safety-calculator.c:163 msgid "User Settings" msgstr "用户设置" #: src/bz-safety-calculator.c:164 msgid "Can access and change user settings" msgstr "可以访问和更改用户设置" #: src/bz-safety-calculator.c:170 msgid "Full File System Read/Write Access" msgstr "完全的文件系统读写权限" #: src/bz-safety-calculator.c:171 msgid "Can read and write all data on the file system" msgstr "可以读取和写入文件系统上的所有数据" #: src/bz-safety-calculator.c:178 msgid "Home Folder Read/Write Access" msgstr "主文件夹读写权限" #: src/bz-safety-calculator.c:179 msgid "Can read and write all data in your home directory" msgstr "可以读取和写入您主目录中的所有数据" #: src/bz-safety-calculator.c:186 msgid "Full File System Read Access" msgstr "完整文件系统读取访问" #: src/bz-safety-calculator.c:187 msgid "Can read all data on the file system" msgstr "可以读取文件系统上的所有数据" #: src/bz-safety-calculator.c:195 msgid "Home Folder Read Access" msgstr "主文件夹读取权限" #: src/bz-safety-calculator.c:196 msgid "Can read all data in your home directory" msgstr "可以读取您主目录中的所有数据" #: src/bz-safety-calculator.c:204 msgid "Download Folder Read/Write Access" msgstr "下载文件夹读写权限" #: src/bz-safety-calculator.c:205 msgid "Can read and write all data in your downloads directory" msgstr "可以读写下载文件夹中的所有数据" #: src/bz-safety-calculator.c:215 msgid "Download Folder Read Access" msgstr "下载文件夹读取权限" #: src/bz-safety-calculator.c:216 msgid "Can read all data in your downloads directory" msgstr "可以读取您下载目录中的所有数据" #: src/bz-safety-calculator.c:229 msgid "Can read and write all data in the directory" msgstr "可以读写目录中的所有数据" #: src/bz-safety-calculator.c:243 msgid "Can read all data in the directory" msgstr "可以读取目录中的所有数据" #: src/bz-safety-calculator.c:258 msgid "No File System Access" msgstr "无文件系统访问权限" #: src/bz-safety-calculator.c:259 msgid "Cannot access the file system at all" msgstr "完全无法访问文件系统" #: src/bz-safety-calculator.c:266 msgid "Uses System Services" msgstr "使用系统服务" #: src/bz-safety-calculator.c:267 msgid "Can request data from non-portal system services" msgstr "可从非门户系统服务请求数据" #: src/bz-safety-calculator.c:273 msgid "Uses Session Services" msgstr "使用会话服务" #: src/bz-safety-calculator.c:274 msgid "Can request data from non-portal session services" msgstr "可从非门户会话服务请求数据" #: src/bz-safety-calculator.c:322 msgid "No Service Access" msgstr "无服务访问" #: src/bz-safety-calculator.c:323 msgid "Cannot access non-portal session or system services at all" msgstr "完全无法访问非门户会话或系统服务" #: src/bz-safety-calculator.c:331 msgid "Verified App Developer" msgstr "软件开发者已验证" #: src/bz-safety-calculator.c:332 msgid "The developer of this app has been verified to be who they say they are" msgstr "软件开发者的身份已通过验证,使应用更安全" #: src/bz-safety-calculator.c:341 msgid "Proprietary Code" msgstr "专有代码" #: src/bz-safety-calculator.c:342 msgid "" "The source code is not public, so it cannot be independently audited and " "might be unsafe" msgstr "源代码未公开,因此无法进行独立审计,可能存在安全隐患" #: src/bz-safety-calculator.c:352 msgid "Auditable Code" msgstr "可审计代码" #: src/bz-safety-calculator.c:353 msgid "" "The source code is public and can be independently audited, which makes the " "app more likely to be safe" msgstr "源代码公开且可独立审计,这使得此应用更可能安全可靠" #: src/bz-safety-calculator.c:493 #, c-format msgid "Use the %s System Service" msgstr "使用 %s 系统服务" #: src/bz-safety-calculator.c:497 #, c-format msgid "Use the %s Session Service" msgstr "使用 %s 会话服务" #: src/bz-safety-calculator.c:501 #, c-format msgid "Use the %s Service" msgstr "使用 %s 服务" #: src/bz-safety-calculator.c:511 msgid "Can see the non-portal service" msgstr "可以看到非门户服务" #: src/bz-safety-calculator.c:513 msgid "Can talk to the non-portal service" msgstr "可与非门户服务进行对话" #: src/bz-safety-calculator.c:515 msgid "Can own the non-portal service" msgstr "可以拥有非门户服务" #: src/bz-safety-calculator.c:530 msgid "Global Menu Integration" msgstr "全局菜单集成" #: src/bz-safety-calculator.c:531 msgid "Can display its menus in a global menu bar" msgstr "可在全局菜单栏中显示其菜单" #: src/bz-safety-calculator.c:536 msgid "KDE Settings Integration" msgstr "KDE 设置集成" #: src/bz-safety-calculator.c:537 msgid "Can detect when KDE desktop settings change" msgstr "可检测 KDE 桌面设置何时发生变化" #: src/bz-safety-calculator.c:542 msgid "KDE Global Settings" msgstr "KDE 全局设置" #: src/bz-safety-calculator.c:543 msgid "Can read KDE desktop preferences like fonts and colors" msgstr "可读取 KDE 桌面偏好设置,如字体和颜色" #: src/bz-safety-calculator.c:548 msgid "Secret Storage Service" msgstr "秘密存储服务" #: src/bz-safety-calculator.c:549 msgid "Can store and retrieve its own passwords using the system keyring" msgstr "可使用系统密钥管理器存储和检索自身密码" #: src/bz-safety-calculator.c:554 msgid "Desktop Notifications Service" msgstr "桌面通知服务" #: src/bz-safety-calculator.c:555 msgid "Can send desktop notifications" msgstr "可以发送桌面通知" #: src/bz-safety-calculator.c:561 msgid "System Tray Integration" msgstr "系统托盘集成" #: src/bz-safety-calculator.c:562 msgid "Can display an icon in the system tray" msgstr "可在系统托盘中显示图标" #: src/bz-safety-calculator.c:567 msgid "KDE Connect Integration" msgstr "KDE Connect 集成" #: src/bz-safety-calculator.c:568 msgid "Can interact with devices paired via KDE Connect" msgstr "可与通过 KDE Connect 配对的设备进行交互" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "安全性" #: src/bz-safety-dialog.blp:50 msgid "Details" msgstr "详细信息" #: src/bz-safety-dialog.blp:53 msgid "License" msgstr "许可证" #: src/bz-safety-dialog.blp:63 msgid "App ID" msgstr "App ID" #: src/bz-safety-dialog.blp:73 msgid "SDK" msgstr "SDK" #: src/bz-safety-dialog.blp:101 msgid "" "This app uses an outdated version of the software platform (SDK) and might " "contain bugs or security vulnerabilities which will not be fixed." msgstr "" "此应用使用了过时的软件平台(SDK)版本,可能包含无法修复的错误或安全漏洞。" #: src/bz-safety-dialog.c:227 #, c-format msgid "%s is Safe" msgstr "%s 是安全的" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s has no Unsafe Permissions" msgstr "%s 没有不安全权限" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Probably Safe" msgstr "%s 很可能安全" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Possibly Unsafe" msgstr "%s 可能不安全" #: src/bz-safety-dialog.c:247 #, c-format msgid "%s is Unsafe" msgstr "%s 是不安全的" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "屏幕截图" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "上一个截图" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "下一个截图" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "复制图片" #: src/bz-screenshot-page.blp:147 msgid "Reset View" msgstr "重置视图" #: src/bz-screenshot-page.blp:158 msgid "Zoom Out" msgstr "缩小" #: src/bz-screenshot-page.blp:168 msgid "Zoom In" msgstr "放大" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "截图轮播" #: src/bz-screenshots-carousel.blp:103 msgid "Open Screenshot Viewer" msgstr "打开截图查看器" #: src/bz-search-widget.blp:57 msgid "Search Apps, Games, Software" msgstr "搜索应用、游戏、软件" #: src/bz-search-widget.blp:96 msgid "Categories Unavailable" msgstr "分类不可用" #: src/bz-search-widget.blp:97 msgid "Search for apps using the search bar above." msgstr "使用上方搜索栏搜索应用。" #: src/bz-search-widget.blp:181 msgid "No Applications Found" msgstr "未找到应用" #: src/bz-search-widget.c:241 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "在 Flathub 中未找到 “%s” 的结果" #: src/bz-share-list.c:64 msgid "Copied!" msgstr "已复制!" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "复制链接" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "打开链接" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "时间线" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "安装:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "世界" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:124 #, c-format msgid "%.2fM Total Installs" msgstr "%.2fM 总安装量" #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:127 #, c-format msgid "%.2fK Total Installs" msgstr "%.2fK 总安装量" #: src/bz-stats-dialog.c:129 #, c-format msgid "%'d Total Installs" msgstr "%'d 总安装量" #: src/bz-tag-list.c:96 msgid "No Results Found" msgstr "无结果" #: src/bz-tag-list.c:108 #, c-format msgid "Apps Tagged \"%s\"" msgstr "标记为 “%s” 的应用" #: src/bz-tag-list.c:124 msgid "Search failed" msgstr "搜索失败" #: src/bz-transaction-dialog.c:151 msgid "Keep Data" msgstr "保留数据" #: src/bz-transaction-dialog.c:152 msgid "Allow restoring settings and content" msgstr "允许恢复设置和内容" #: src/bz-transaction-dialog.c:161 msgid "Delete Data" msgstr "删除数据" #: src/bz-transaction-dialog.c:162 msgid "Permanently remove app data to save space" msgstr "永久删除应用数据以节省空间" #: src/bz-transaction-dialog.c:187 #, c-format msgid "Install %s?" msgstr "安装 %s ?" #: src/bz-transaction-dialog.c:192 msgid "" "Select which version to install. May install additional shared components" msgstr "选择你要安装的版本。可能还要安装共享组件" #: src/bz-transaction-dialog.c:194 msgid "May install additional shared components" msgstr "可能还要安装额外的共享组件" #: src/bz-transaction-dialog.c:215 #, c-format msgid "Remove %s?" msgstr "卸载 %s ?" #: src/bz-transaction-dialog.c:218 msgid "Select which version to remove." msgstr "选择你要卸载的版本" #: src/bz-transaction-dialog.c:220 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "卸载后将无法使用 %s" #: src/bz-transaction-dialog.c:243 #, c-format msgid "“%s” is High Risk" msgstr "“%s” 是高风险的" #: src/bz-transaction-dialog.c:247 msgid "" "This app has full access to your system, including all your files, " "browser history, saved passwords, and more. It also has access to the " "internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "此应用拥有对您系统的完全访问权限,包括您的所有文件、浏览历史、已保存密码等。它还能访问互联网,这意味着它可能将您的数据发送给第三方。\n" "\n" "由于该应用是专有的,其如何利用权限也无法审查。\t" #: src/bz-transaction-dialog.c:256 msgid "" "This app uses the legacy X11 windowing system, which allows it to record " "all keystrokes, capture screenshots, and monitor other applications. It " "also has access to the internet, meaning it could send your data to outside " "parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "此应用使用传统的 X11 窗口系统,这使其能够记录所有按键、截取屏幕截图并监控" "其他应用程序。同时,该应用具备网络访问权限,这意味着它可能将您的数据发送" "给外部。\n" "\n" "由于该应用是专有的,其如何利用权限也无法审查。" #: src/bz-transaction-dialog.c:272 msgid "Install Anyway" msgstr "坚持安装" #: src/bz-transaction-dialog.c:533 msgid "All apps are already installed" msgstr "所有应用都已经被安装" #: src/bz-transaction-dialog.c:535 msgid "OK" msgstr "好的" #: src/bz-transaction-dialog.c:551 #, c-format msgid "Install %u App?" msgid_plural "Install %u Apps?" msgstr[0] "安装 %u 应用?" #: src/bz-transaction-dialog.c:559 msgid "" "The following will be installed. Additional shared components may also be " "installed" msgstr "下列组件会被安装。可能还要安装共享组件" #: src/bz-transaction-dialog.c:560 #, c-format msgid "%d addons will be installed." msgstr "%d 附加组件将被安装" #: src/bz-transaction-dialog.c:561 msgid "Additionally, addons will be installed." msgstr "此外,附加组件将被安装" #: src/bz-transaction-manager.c:1248 #, c-format msgid "Finished in %.02f seconds" msgstr "在 %.02f 秒内完成" #: src/bz-transaction-tile.blp:125 msgid "App Add-on" msgstr "应用附加组件" #: src/bz-transaction-tile.blp:154 msgid "Runtime" msgstr "运行时" #: src/bz-transaction-tile.blp:178 msgid "In Queue" msgstr "队列中" #: src/bz-transaction-tile.blp:202 msgid "Done" msgstr "已完成" #: src/bz-transaction-tile.blp:243 msgid "Open App" msgstr "打开" #: src/bz-transaction-tile.c:110 #, c-format msgid "%s Freed" msgstr "%s 已释放" #: src/bz-transaction.c:342 msgid "Pending" msgstr "等待中" #: src/bz-updates-card.blp:36 msgid "Update All" msgstr "更新全部" #: src/bz-updates-card.blp:161 src/bz-updates-card.blp:186 msgid "Update" msgstr "更新" #: src/bz-updates-card.c:293 #, c-format msgid "%u Runtime Update" msgid_plural "%u Runtime Updates" msgstr[0] "%u 个运行时环境更新" #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "管理遗留用户数据" #: src/bz-user-data-page.blp:89 msgid "No User Data found" msgstr "未找到用户数据" #: src/bz-user-data-page.blp:94 msgid "User Data" msgstr "用户数据" #: src/bz-user-data-tile.c:144 #, c-format msgid "Trashed User Data for %s" msgstr "已删除 %s 的用户数据" #: src/bz-user-data-tile.blp:74 msgid "Trash User Data" msgstr "清除用户数据" #: src/bz-window.blp:135 msgid "Refreshing Store Content" msgstr "正在刷新商店内容" #: src/bz-window.blp:153 msgid "Curated" msgstr "精选" #: src/bz-window.blp:166 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:273 msgid "No background tasks!" msgstr "无后台任务!" #: src/bz-window.blp:325 msgid "You are running a new version of Bazaar!" msgstr "你正在运行新版本的 Bazaar!" #: src/bz-window.blp:326 msgid "See What's New" msgstr "看看更新了啥" #: src/bz-window.blp:333 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "您已连接网络,但正在查看 Flathub 的缓存版本" #: src/bz-window.blp:449 msgid "Log Out" msgstr "登出" #: src/bz-window.c:683 msgid "You can't remove Bazaar from Bazaar!" msgstr "你无法用 Bazaar 卸载 Bazaar!" #: src/bz-window.c:891 src/bz-window.c:925 msgid "Can't do that right now!" msgstr "现在还不能这么做!" #: src/bz-world-map.c:587 msgctxt "As in, \"100 Downloads\"" msgid "Downloads" msgstr "次下载" #: src/gtk/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "一般" #: src/gtk/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "打开搜索对话框" #: src/gtk/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Preferences" msgstr "打开偏好设置" #: src/gtk/shortcuts-dialog.blp:19 msgctxt "shortcut window" msgid "Synchronize Remotes" msgstr "从远程端同步" #: src/gtk/shortcuts-dialog.blp:24 #, fuzzy msgctxt "shortcut window" msgid "Open Library" msgstr "打开链接" #: src/gtk/shortcuts-dialog.blp:30 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "展示快捷键" #: src/gtk/shortcuts-dialog.blp:35 msgctxt "shortcut window" msgid "Quit" msgstr "退出" #~ msgid "_Refresh Content" #~ msgstr "_刷新内容" msgid "Toggle transaction sidebar" msgstr "切换事务侧面板" msgid "Install Size" msgstr "安装大小" msgid "Ongoing" msgstr "进行中" msgid "Finished" msgstr "已完成" #, c-format #~ msgid "Transferred %s so far" #~ msgstr "目前已传输 %s" msgid "Tasks" msgstr "任务" msgid "Stop Active Tasks" msgstr "停止当前任务" msgid "Clear History" msgstr "清除历史" msgid "No Tasks Yet" msgstr "当前无任务" #, c-format msgid "%d Update Available" msgid_plural "%d Updates Available" msgstr[0] "%d 个更新" msgid "Updates Are Available" msgstr "有可用更新" msgid "" "The following applications are eligible for updates. Would you like to " "install them?" msgstr "以下应用可进行更新。您想要安装它们吗?" #, c-format msgid "" "%d runtimes and/or addons are eligible for updates. Would you like to " "install them?" msgstr "%d 个运行时和/或插件可进行更新。您要安装它们吗?" #, c-format msgid "Additionally, %d runtimes and/or addons will be updated." msgstr "此外,%d 个运行时和/或插件也将被更新" msgid "Update Now" msgstr "立即更新" #~ msgid "" #~ "The ability to inspect and install local .flatpak bundle files is coming " #~ "soon! In the meantime, try running\n" #~ "\n" #~ "flatpak install --bundle your-bundle.flatpak\n" #~ "\n" #~ "on the command line." #~ msgstr "" #~ "检查和安装本地 .flatpak 包文件的功能即将推出!在此期间,请尝试在命令行运" #~ "行\n" #~ "\n" #~ "flatpak install --bundle your-bundle.flatpak\n" #~ "\n" #~ "以上命令。" msgid "Resume Current Tasks" msgstr "恢复当前任务" msgid "Pause Current Tasks" msgstr "暂停当前任务" msgctxt "shortcut window" msgid "Toggle Transaction Manager" msgstr "切换事务管理器" #~ msgid "Show Animated Background" #~ msgstr "展示动画背景" #~ msgid "Whether to show the animated icon background on the home page" #~ msgstr "是否在首页展示动画图标背景" #~ msgid "Keep the summary shorter, between 10 and 35 characters" #~ msgstr "保持摘要简短,在 10 至 35 字之间" #~ msgid "Main Bazaar window showing Blender" #~ msgstr "Bazaar 主窗口正在展示 Blender" #~ msgid "This flatpak is verified by the original developers of the software." #~ msgstr "此 Flatpak 已由软件原开发者认证。" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Ahmed Najmawi" #~ msgstr "Ahmed Najmawi" #~ msgctxt "About Dialog Translator Credit" #~ msgid "AtomHare" #~ msgstr "AtomHare" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Jill Fiore" #~ msgstr "Jill Fiore" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Lucosec" #~ msgstr "Lucosec" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Shihfu Juan" #~ msgstr "Shihfu Juan" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Vlastimil Dědek" #~ msgstr "Vlastimil Dědek" #~ msgctxt "About Dialog Translator Credit" #~ msgid "asen23" #~ msgstr "asen23" #~ msgctxt "About Dialog Translator Credit" #~ msgid "renner" #~ msgstr "renner" #~ msgctxt "About Dialog Translator Credit" #~ msgid "robotta" #~ msgstr "robotta" #~ msgid "" #~ "Bazaar was not provided a curated content configuration. Contact your " #~ "operating system's support channels for assistance." #~ msgstr "Bazaar 未被提供精选内容配置。联系您的操作系统的支持频道寻求协助。" #~ msgid "Apps Of The Week" #~ msgstr "本周热门应用程序" #~ msgid "Run this application" #~ msgstr "运行此应用程序" #~ msgid "" #~ "The number of downloads in the last 30 days. Click to view this " #~ "application's download statistics." #~ msgstr "过去 30 天的下载次数。点击查看此应用程序的下载统计信息。" #~ msgid "Remote repo name" #~ msgstr "远程仓库名" #, c-format #~ msgid "Released %x" #~ msgstr "发布于 %x" #~ msgid "No Flatpaks Installed" #~ msgstr "没有已安装的 Flatpak" #~ msgid "How the application looks" #~ msgstr "这个应用程序看起来怎么样" #~ msgid "Appearance" #~ msgstr "外观" #~ msgid "Show animated background" #~ msgstr "展示动画背景" #~ msgid "Type to filter" #~ msgstr "输入以筛选" #~ msgid "Exclude results with proprietary licenses" #~ msgstr "排除有专有许可证的结果" #~ msgid "Advanced" #~ msgstr "高级" #~ msgid "Match using regular expressions" #~ msgstr "使用正则表达式匹配" #~ msgid "Hide filtering and sorting behind a crossfade effect" #~ msgstr "隐藏交叉淡入淡出效果背后的过滤和排序" #~ msgid "Debounce input to prevent instant replies" #~ msgstr "消除输入抖动以防止立即回复" #~ msgid "Share" #~ msgstr "分享" #~ msgid "Open this link externally" #~ msgstr "在外部打开链接" #~ msgid "Downloads Over Time" #~ msgstr "下载趋势" #~ msgid "Minimize Lower Bound" #~ msgstr "调低下限" #~ msgid "Maximize Upper Bound" #~ msgstr "调低上限" msgid "Installing" msgstr "正在安装" msgid "Removing" msgstr "正在卸载" #~ msgid "Transactions Will Appear Here" #~ msgstr "事务会在此显示" #~ msgid "Halt the execution of transactions" #~ msgstr "停止执行事务" #~ msgid "Browse" #~ msgstr "浏览" #~ msgid "App View" #~ msgstr "App View" #~ msgid "Go Back" #~ msgstr "返回" #~ msgid "Refresh" #~ msgstr "刷新" #~ msgid "View curated applications" #~ msgstr "查看精选的应用程序" #~ msgid "View the latest on Flathub" #~ msgstr "在 Flathub 查看最新的" #~ msgid "Up to date!" #~ msgstr "最新!" #~ msgid "Confirm Action" #~ msgstr "确认操作" #, c-format #~ msgid "" #~ "You are about to remove the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "您将要卸载以下 Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "您确定吗?" #, c-format #~ msgid "" #~ "You are about to install the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "您将安装以下 Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "您确定吗?" #~ msgid "Resume the execution of transactions" #~ msgstr "恢复事务执行" #~ msgid "Pause the execution of transactions" #~ msgstr "暂停事务执行" #~ msgctxt "shortcut window" #~ msgid "Refresh" #~ msgstr "刷新" bazaar-orig-v0.7.14/po/kw.po0000664000175000017500000026111215166123241014542 0ustar hasanhasan# Cornish translations for bazaar package. # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # Flynn Peck , 2026. # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-03-24 03:16+0000\n" "PO-Revision-Date: 2026-03-25 16:46+0000\n" "Last-Translator: Flynn Peck \n" "Language-Team: kw\n" "Language: kw\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 50.0\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:46 #: src/bz-window.c:377 src/bz-window.c:378 msgid "Bazaar" msgstr "Basar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "Addya, remova, po nowedhi medhelweyth flatpak war'n amontyell ma" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;System;DyghtyerFardellow;Trovya;Flatpak;Medhelweyth;Gwerthji;" #: data/io.github.kolunmi.Bazaar.desktop.in:16 msgid "New Window" msgstr "Fenester Nowydh" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and manage applications" msgstr "Trovya ha dyghtya appys" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A fast and modern app store for Linux with a focus on discovering and " "installing Flatpak apps and addons, particularly from Flathub." msgstr "" "Gwerthji appys nowydh rag Linux gans fog war ow trovya hag ow lea appys hag " "ystynansow Flatpak, dres oll dhyworth Flathub." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:15 msgid "Queue multiple installs and keep browsing" msgstr "Lostya meur a leyansow ha pesya ow peuri" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:16 msgid "Easily view app permissions" msgstr "Gweles kummyasow app yn es" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:17 msgid "Sign in to Flathub to view and manage your favorites" msgstr "Omgelmi orth Flathub rag gweles ha dyghtya dha drudhyow" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:18 msgid "Search apps directly from GNOME Shell" msgstr "Hwilas appys dhyworth GNOME Shell yn distowgh" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:30 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:55 msgid "The home page displaying Flathub apps" msgstr "An folen chi ow displetya appys Flathub" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:59 msgid "Exhibit app page" msgstr "Folen app diskwedhyn" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:63 msgid "Library page" msgstr "Folen lyverva" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:67 msgid "Search page" msgstr "Folen hwithrans" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:71 msgid "Category page" msgstr "Folen klassys" #: src/bz-addons-dialog.blp:16 src/bz-full-view.blp:627 #: src/bz-installed-tile.blp:101 msgid "Manage Add-Ons" msgstr "Dyghtya Ystynansow" #: src/bz-addons-dialog.c:94 src/bz-install-controls.blp:137 #: src/bz-installed-tile.blp:114 msgid "Remove" msgstr "Remova" #: src/bz-addons-dialog.c:99 src/bz-favorites-tile.c:159 msgid "Install" msgstr "Lea" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 #: src/bz-age-rating-dialog.c:736 src/bz-full-view.c:333 src/bz-full-view.c:340 msgid "Age Rating" msgstr "Talvos Oos" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "Garowder Komik" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "Kedhlow vyth yn-kever garowder komik" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "Garowder Fantasi" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "Kedhlow vyth yn-kever garowder fantasi" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "Garowder Gwirvosek" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "Kedhlow vyth yn-kever garowder gwirvosek" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "Garowder rag Krow" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "Kedhlow vyth yn-kever krow" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "Garowder Reydhel" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "Kedhlow vyth yn-kever garowder reydhel" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "Las" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "Kedhlow vyth yn-kever kampollans dhe las" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "Droggya Anlaghel" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "Kedhlow vyth yn-kever kampollans dhe droggya anlaghel" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "Tobacko" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "Kedhlow vyth yn-kever kampollans dhe gwaren tobacko" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "Nothedh" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "Kedhlow vyth yn-kever kampollans dhe nothedh" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "Themow Reydhel" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "Kedhlow vyth yn-kever kampollans dhe po portrayansow a gnas reydhel" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "Koss" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "Kedhlow vyth yn-kever kossya" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "Hwarthuster na Gwiw" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "Kedhlow vyth yn-kever hwarthuster na gwiw" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "Disfaveryans" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "Kedhlow vyth yn-kever keskows disfaveryans" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "Argemynnow" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "Kedhlow vyth yn-kever argemynnow" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "Hapwaryans" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "Kedhlow vyth yn-kever hapwaryans" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "Prenyans" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "Kedhlow vyth yn-kever prenyans" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "Keskows ynter Devnydhyoryon" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "Kedhlow vyth yn-kever keskows ynter devnydhyoryon" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "Galow Pellgows ynter Devnydhyoryon" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "Kedhlow vyth yn-kever keskows ynter devnydhyoryon" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 msgid "Contact Details" msgstr "Kedhlow Kestav" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "Kedhlow vyth yn-kever kevrans a hanwyn usyer po ebost" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "Kedhlow Privedh" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "Kedhlow vyth yn-kever kevrans a kedhlow privedh gans tressa partiow" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "Kevrans Tyller" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "Kedhlow vyth yn-kever kevrans tyller gans devnydhyoryon erel" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "Horyans" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "Kedhlow vyth yn-kever kampollans dhe horyans" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "Avoutri" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "Kedhlow vyth yn-kever kampollans dhe avoutri" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "Warioryon Reydhel" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "Kedhlow vyth yn-kever warioryon reydhel" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 msgid "Desecration" msgstr "Defolyans" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "Kedhlow vyth yn-kever kampollans dhe defolyans" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "Korf Marow" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "Kedhlow vyth yn-kever korf marow a wel" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "Kethneth" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "Kedhlow vyth yn-kever kampollans dhe kethneth" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "Ny komprehendya kampollans dhe droggys" #: src/bz-age-rating-dialog.c:426 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "Ny komprehendya kossya" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "Ny komprehendya argemynnow po treuswriansow monesek" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "Ny komprehendya kyjyans po nothedh" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "Ny komprehendya keskows heb musur" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "Ny komprehendya garowder" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "Droggys" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "Koss" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "Mona" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "Kowethasek" #: src/bz-age-rating-dialog.c:479 msgid "Violence" msgstr "Garowder" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:686 src/bz-full-view.c:323 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:711 msgctxt "Age rating" msgid "All" msgstr "Oll" #: src/bz-age-rating-dialog.c:747 #, c-format msgid "%s has an unknown age rating" msgstr "%s kavos talvos oos ankoth" #: src/bz-age-rating-dialog.c:753 #, c-format msgid "%s is suitable for everyone" msgstr "%s yw fytti rag oll" #: src/bz-age-rating-dialog.c:756 #, c-format msgid "%s is suitable for young children" msgstr "%s yw fytti rag fleghes yowynk" #: src/bz-age-rating-dialog.c:759 #, c-format msgid "%s is suitable for children" msgstr "%s yw fytti rag fleghes" #: src/bz-age-rating-dialog.c:762 #, c-format msgid "%s is suitable for teenagers" msgstr "%s yw fytti rag degowogyon" #: src/bz-age-rating-dialog.c:765 #, c-format msgid "%s is suitable for adults" msgstr "%s yw fytti rag tevesigesow" #: src/bz-age-rating-dialog.c:768 #, c-format msgid "%s is suitable for %s" msgstr "%s yw fytti rag %s" #: src/bz-age-rating-dialog.c:862 #, c-format msgid "%s • %s" msgstr "%s • %s" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:29 #: src/bz-user-data-page.blp:15 src/bz-window.blp:239 msgid "Main Menu" msgstr "Rol Chif" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 #: src/bz-user-data-page.blp:19 src/bz-window.blp:328 msgid "_Donate to Bazaar ❤️" msgstr "_Argevri dhe Basar ❤️" #: src/bz-all-apps-page.blp:25 src/bz-apps-page.blp:25 #: src/bz-user-data-page.blp:26 src/bz-window.blp:335 msgid "_Refresh" msgstr "_Disegha" #: src/bz-all-apps-page.blp:30 src/bz-apps-page.blp:30 #: src/bz-user-data-page.blp:31 src/bz-window.blp:340 msgid "_Preferences" msgstr "_Settyansow" #: src/bz-all-apps-page.blp:35 src/bz-apps-page.blp:35 #: src/bz-user-data-page.blp:36 src/bz-window.blp:345 msgid "_Login With Flathub" msgstr "_Omgelmi Gans Flathub" #: src/bz-all-apps-page.blp:41 src/bz-apps-page.blp:41 #: src/bz-user-data-page.blp:42 src/bz-window.blp:351 msgid "_Manage Leftover User Data" msgstr "_Dyghtya Data Usyer Remenant" #: src/bz-all-apps-page.blp:46 src/bz-apps-page.blp:46 #: src/bz-user-data-page.blp:47 src/bz-window.blp:356 msgid "_Keyboard Shortcuts" msgstr "_Kesunyansow Bysowek" #: src/bz-all-apps-page.blp:51 src/bz-apps-page.blp:51 #: src/bz-user-data-page.blp:52 src/bz-window.blp:361 msgid "_About Bazaar" msgstr "_A-dro Basar" #: src/bz-all-apps-page.blp:58 src/bz-apps-page.blp:58 #: src/bz-user-data-page.blp:59 src/bz-window.blp:368 msgid "_Quit Bazaar" msgstr "_Kwytya Basar" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "Restrenva system %s" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "Isrestrenva tre %s" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "Restrenvaow system ost" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "Settyansow system ost dhyworth /etc" #: src/bz-app-permissions.c:169 #, c-format msgid "Desktop subfolder %s" msgstr "Isrestrenva desktop %s" #: src/bz-app-permissions.c:170 msgid "Desktop folder" msgstr "Restrenva desktop" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "Isrestrenva skrifow %s" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "Restrenva skrifow" #: src/bz-app-permissions.c:177 #, c-format msgid "Music subfolder %s" msgstr "Isrestrenva musik %s" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "Restrenva musik" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "Isrestrenva avenyow %s" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "Restrenva avenyow" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "Isrestrenva Kevren Poblek %s" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "Restrenva Kevren Poblek" #: src/bz-app-permissions.c:189 #, c-format msgid "Videos subfolder %s" msgstr "Isrestrenva gwydhyowyow %s" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "Restrenva gwydhyowyow" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "Isrestrenva ensampelys %s" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "Restrenva ensampelys" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "Isrestrenva sorn usyer %s" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "Restrenva sorn usyer" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "Isrestrenva settyansow usyer %s" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "Restrenva settyansow usyr" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "Isrestrenva data usyer %s" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "Restrenva Data Usyer" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "Isrestrenva kerghynnedh usyer %s" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "Restrenva kerghynnedh usyer" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "Hedhas restrenva dhe %s" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "Tyller restren ankoth" #: src/bz-app-size-dialog.blp:29 src/bz-app-size-dialog.blp:55 msgid "Download Size" msgstr "Braster Iskarg" #: src/bz-app-size-dialog.blp:56 msgid "Amount to download from the internet" msgstr "Myns rag iskarga dhyworth an kesrosweyth" #: src/bz-app-size-dialog.blp:76 msgid "Installed Size" msgstr "Braster Leys" #: src/bz-app-size-dialog.blp:77 msgid "Size on Disk" msgstr "Braster war Plasen" #: src/bz-app-size-dialog.blp:125 msgid "Open user data folder" msgstr "Ygeri restrenva data usyer" #: src/bz-app-size-dialog.blp:135 msgid "User Data Size" msgstr "Braster Data Usyer" #: src/bz-app-size-dialog.blp:136 msgid "Caches, settings, and other app data" msgstr "Sornow, settyansow, ha data appys aral" #: src/bz-app-size-dialog.c:99 msgid "Installed Runtime Size" msgstr "Braster Leys Kerghynnedh" #: src/bz-app-size-dialog.c:99 msgid "Runtime Download Size" msgstr "Braster Iskarg Kerghynnedh" #: src/bz-app-tile.blp:57 src/bz-developer-badge.c:98 #: src/bz-rich-app-tile.blp:104 src/bz-rich-app-tile.c:304 msgid "Verified" msgstr "Gwirhys" #. Translators: As in 'The app is installed'. #: src/bz-app-tile.blp:88 src/bz-full-view.c:282 src/bz-releases-list.c:205 msgid "Installed" msgstr "Leys" #: src/bz-apps-page.blp:142 msgid "Show All" msgstr "Diskwedhes Oll" #: src/bz-apps-page.c:229 #, c-format msgid "All \"%s\"" msgstr "Oll \"%s\"" #: src/bz-apps-page.c:478 src/bz-tag-list.c:91 #, c-format msgid "%d Applications" msgstr "%d Appys" #: src/bz-application.c:695 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:696 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #: src/bz-application.c:716 msgid "The Bazaar Contributors" msgstr "An Kevriysi Basar" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:719 msgid "translator-credits" msgstr "Flynn " #: src/bz-application.c:729 msgid "Special Thanks" msgstr "Grassow Arbennik" #: src/bz-application.c:787 msgid "Logged Out Successfully!" msgstr "Omdhigelmys yn Sewen!" #: src/bz-application.c:910 msgid "Performing setup…" msgstr "Ow gwruthyl selyans…" #: src/bz-application.c:994 msgid "Set Up System Flathub?" msgstr "Selya Flathub System?" #: src/bz-application.c:997 msgid "" "The system Flathub remote is not set up. Bazaar requires Flathub to be " "configured on the system Flatpak installation to browse and install " "applications.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "An repositori system Flathub yw anselys. Basar res Flathub bos selys war'n " "leyans Flatpak system rag peuri ha lea appys.\n" "\n" "Ty a yll devnydhya Basar hwath rag peuri ha remova appys leys seulabrys." #: src/bz-application.c:1004 msgid "Set Up Flathub?" msgstr "Selya Flathub?" #: src/bz-application.c:1007 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub yw anselys war'n system ma. Ty ny yllir peuri ha lea appys yn Basar " "mars yth yw ankavadow.\n" "\n" "Ty a yll devnydhya Basar hwath rag peuri ha remova appys leys seulabrys." #: src/bz-application.c:1013 msgid "Later" msgstr "Diwettha" #: src/bz-application.c:1014 msgid "Set Up Flathub" msgstr "Selya Flathub" #: src/bz-application.c:1303 msgid "A backend error occurred" msgstr "Yma error a-dhelergh" #: src/bz-application.c:1499 src/bz-application.c:3357 src/bz-window.blp:70 msgid "Refreshing…" msgstr "Ow Disegha…" #: src/bz-application.c:1651 src/bz-application.c:3355 #, c-format msgid "Loading %d apps…" msgstr "Ow karga %d appys…" #: src/bz-application.c:1654 msgid "Checking for updates…" msgstr "Ow checkya rag nowedhyansow…" #: src/bz-application.c:1717 msgid "Failed to open .flatpakref" msgstr "Ny yllir ygeri .flatpakref" #: src/bz-application.c:1773 msgid "An initialization error occurred" msgstr "Yma error dalleth" #: src/bz-application.c:2123 msgid "Failed to check for updates" msgstr "Ny yllir checkya rag nowedhyansow" #: src/bz-application.c:3128 msgid "Could not find app" msgstr "Ny yllir kavos app" #: src/bz-application.c:3359 msgid "Writing to cache…" msgstr "Ow skrifa dhe sorn…" #: src/bz-appstream-parser.c:302 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Folen Flathub" #: src/bz-appstream-parser.c:323 msgctxt "Project URL Type" msgid "Project Website" msgstr "Gwiasva Ragdres" #: src/bz-appstream-parser.c:327 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Rol Kudynnow" #: src/bz-appstream-parser.c:331 msgctxt "Project URL Type" msgid "FAQ" msgstr "Govynnow Kemmyn" #: src/bz-appstream-parser.c:335 msgctxt "Project URL Type" msgid "Help" msgstr "Gweres" #: src/bz-appstream-parser.c:339 msgctxt "Project URL Type" msgid "Donate" msgstr "Argevri" #: src/bz-appstream-parser.c:345 msgctxt "Project URL Type" msgid "Translate" msgstr "Treylya" #: src/bz-appstream-parser.c:349 msgctxt "Project URL Type" msgid "Contact" msgstr "Kestava" #: src/bz-appstream-parser.c:353 msgctxt "Project URL Type" msgid "Source Code" msgstr "Kod" #: src/bz-appstream-parser.c:359 msgctxt "Project URL Type" msgid "Contribute" msgstr "Kevri" #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:68 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:62 #: src/bz-library-page.blp:65 src/bz-user-data-page.blp:86 msgid "Empty" msgstr "Gwag" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "Dyghtyans Vyth" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "Yma kedhlow dyghtyans vyth provys war'n system ma. Ty a yll peuri appys war " "Flathub hwath" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "Peuri Flathub" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "Dhywarlinen" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 #: src/bz-search-pill-list.c:67 msgid "Browser" msgstr "Peurell" #: src/bz-developer-badge.c:94 src/bz-developer-badge.c:98 msgid "Not Verified" msgstr "Na Gwirhys" #: src/bz-developer-badge.c:145 msgid "Developer information not available." msgstr "Kedhlow awtour ankavadow." #: src/bz-developer-badge.c:151 src/bz-developer-badge.c:165 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "" "An perghenogeth a'n %s ID app yw angwirys hag yth yw fardel ansodhogel " "martesen." #: src/bz-developer-badge.c:169 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "" "An perghenogeth a'n %s ID app re gwirys dre dhorn gans an bagas Flathub." #: src/bz-developer-badge.c:175 #, c-format msgid "" "The ownership of the %1$s app ID has been verified by %2$s on " "%3$s." msgstr "" "An perghenogeth a'n %1$s ID app re gwirys gans %2$s war %3$s." #: src/bz-developer-badge.c:182 #, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "An perghenogeth a'n %1$s ID app re gwirys ow devnydhya %2$s." #: src/bz-developer-badge.c:186 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "An perghenogeth a'n %s ID app re gwirys." #: src/bz-donations-dialog.blp:74 msgid "Full Release Notes" msgstr "Notennow Dyllans Leun" #: src/bz-donations-dialog.blp:108 msgid "This release was made possible by users like you!" msgstr "An dyllans ma o gwrys possybyl gans usyoryon avel ty!" #: src/bz-donations-dialog.blp:116 msgid "" "I love making Bazaar, but I cannot do it alone. Help support further " "development by donating on Ko-Fi." msgstr "" "My a gar ow gul Basar, mes ny allav gul yth yn unsel. Gweres skoodhya " "displegyans pella gans owth argevri war Ko-Fi." #: src/bz-donations-dialog.blp:131 msgid "Donate to Bazaar" msgstr "Argevri dhe Basar" #. Translators: the %s format specifier will be something along the lines of "0.7.6" etc #: src/bz-donations-dialog.c:227 #, c-format msgid "What's New in %s?" msgstr "Pyth yw Nowydh yn %s?" #. Translators: this is a release date label, like "Released February 9, 2026" #: src/bz-donations-dialog.c:243 msgid "Released %B %-e, %Y" msgstr "Dyllys %-e ves %B, %Y" #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "Dewis Leyans" #: src/bz-entry-group-util.c:76 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "" "Ty kavos versyons liesek a'n app ma leys. Pyneyl a vynn'ta y gavos procedya " "gans?" #: src/bz-entry-group-util.c:80 msgid "Cancel" msgstr "Hedhi" #: src/bz-entry-selection-row.blp:17 msgid "For This User Only" msgstr "Rag An Usyer Ma Hepken" #: src/bz-entry-selection-row.c:112 msgid "this user" msgstr "an usyer" #: src/bz-entry-selection-row.c:112 msgid "all users" msgstr "oll usyoryon" #: src/bz-error.c:69 src/bz-error.c:88 src/bz-error-dialog.blp:36 #: src/bz-safety-dialog.blp:50 msgid "Details" msgstr "Manylyon" #: src/bz-error-dialog.blp:47 msgid "Copy" msgstr "Kopia" #: src/bz-error-dialog.c:56 src/bz-share-list.c:64 msgid "Copied!" msgstr "Kopys!" #: src/bz-favorite-button.c:388 msgid "Failed to update favorite" msgstr "Ny yllir nowedhi drudh" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "Omgelmi gans Flathub rag dyghtya drudhyow" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "Omgelmi" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "Somm Drudhyow" #: src/bz-favorites-tile.c:157 src/bz-rich-app-tile.blp:172 msgid "Uninstall" msgstr "Dilea" #: src/bz-favorites-tile.c:357 msgid "Failed to remove favorite" msgstr "Ny yllir remova drudh" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:78 msgid "Support This Application" msgstr "Skoodhya An App Ma" #: src/bz-favorites-tile.blp:119 msgid "Remove From Favorites" msgstr "Dilea Dhyworth Drudhyow" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:78 #: src/bz-window.blp:386 msgid "Favorites" msgstr "Drudhyow" #: src/bz-favorites-page.blp:17 src/bz-section-view.blp:144 msgid "Install All" msgstr "Lea Oll" #: src/bz-favorites-page.blp:34 src/bz-full-view.blp:45 src/bz-window.blp:255 msgid "Open App Library" msgstr "Ygeri Lyverva Appys" #: src/bz-favorites-page.blp:56 src/bz-user-data-page.blp:75 msgid "Loading" msgstr "Ow Karga" #: src/bz-favorites-page.blp:71 msgid "No Favorites" msgstr "Drudhyow Vyth" #: src/bz-favorites-page.blp:72 msgid "Applications you mark as favorite will appear here" msgstr "Appys ty merkya avel drudh a wra diskwedhes omma" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "Kyns" #: src/bz-featured-carousel.blp:54 msgid "Next" msgstr "Nessa" #: src/bz-featured-tile.blp:90 msgid "App of the Day" msgstr "App a'n Jydh" #: src/bz-flathub-category.c:89 msgid "Editing" msgstr "Ow Pennskrifa" #: src/bz-flathub-category.c:90 msgid "Midi" msgstr "Midi" #: src/bz-flathub-category.c:91 msgid "Mixer" msgstr "Kemyskell" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-flathub-category.c:92 src/bz-search-pill-list.c:77 msgid "Music" msgstr "Ilow" #: src/bz-flathub-category.c:93 msgid "Player" msgstr "Gwarier" #: src/bz-flathub-category.c:94 msgid "Recorder" msgstr "Rekordyer" #: src/bz-flathub-category.c:95 msgid "Sequencer" msgstr "Kevreser" #: src/bz-flathub-category.c:96 msgid "Tuner" msgstr "Tonyer" #: src/bz-flathub-category.c:97 msgid "TV" msgstr "Pellwolok" #: src/bz-flathub-category.c:102 msgid "Emulation" msgstr "Omhevelians" #: src/bz-flathub-category.c:103 msgid "Action" msgstr "Gwrians" #: src/bz-flathub-category.c:104 msgid "Adventure" msgstr "Aventur" #: src/bz-flathub-category.c:105 msgid "Arcade" msgstr "Arkade" #: src/bz-flathub-category.c:106 msgid "Blocks" msgstr "Stockow" #: src/bz-flathub-category.c:107 msgid "Board" msgstr "Bordh" #: src/bz-flathub-category.c:108 msgid "Card" msgstr "Karten" #: src/bz-flathub-category.c:109 msgid "Kids" msgstr "Fleghes" #: src/bz-flathub-category.c:110 msgid "Logic" msgstr "Lojyk" #: src/bz-flathub-category.c:111 msgid "Role Playing" msgstr "Rann" #: src/bz-flathub-category.c:112 msgid "Shooter" msgstr "Sether" #: src/bz-flathub-category.c:113 msgid "Simulation" msgstr "Hevelebyans" #: src/bz-flathub-category.c:114 msgid "Sports" msgstr "Sportys" #: src/bz-flathub-category.c:115 msgid "Strategy" msgstr "Strateji" #: src/bz-flathub-category.c:120 msgid "Audio & Video" msgstr "Son & Gwydhyow" #: src/bz-flathub-category.c:120 msgid "Media" msgstr "Media" #: src/bz-flathub-category.c:120 msgid "More Audio & Video" msgstr "Moy Son & Gwydhyow" #: src/bz-flathub-category.c:121 msgid "Developer Tools" msgstr "Toulys Amontydh" #: src/bz-flathub-category.c:121 msgid "Develop" msgstr "Displegya" #: src/bz-flathub-category.c:121 msgid "More Developer Tools" msgstr "Moy Toulys Amontydh" #: src/bz-flathub-category.c:122 msgid "Education" msgstr "Adhyskans" #: src/bz-flathub-category.c:122 msgid "Learn" msgstr "Dyski" #: src/bz-flathub-category.c:122 msgid "More Education" msgstr "Moy Adhyskans" #: src/bz-flathub-category.c:123 msgid "Gaming" msgstr "Gwariow" #: src/bz-flathub-category.c:123 msgid "Play" msgstr "Gwari" #: src/bz-flathub-category.c:123 msgid "More Gaming" msgstr "Moy Gwariow" #: src/bz-flathub-category.c:124 msgid "Graphics & Photography" msgstr "Grafek & Skeusenieth" #: src/bz-flathub-category.c:124 msgid "Create" msgstr "Gul" #: src/bz-flathub-category.c:124 msgid "More Graphics & Photography" msgstr "Moy Grafek & Skeusenieth" #: src/bz-flathub-category.c:125 msgid "Networking" msgstr "Rosweythyans" #: src/bz-flathub-category.c:125 msgid "Internet" msgstr "Kesrosweyth" #: src/bz-flathub-category.c:125 msgid "More Networking" msgstr "Moy Rosweythyans" #: src/bz-flathub-category.c:126 msgid "Productivity" msgstr "Askorruster" #: src/bz-flathub-category.c:126 msgid "Work" msgstr "Gonis" #: src/bz-flathub-category.c:126 msgid "More Productivity" msgstr "Moy Askorruster" #: src/bz-flathub-category.c:127 msgid "Science" msgstr "Godhonieth" #: src/bz-flathub-category.c:127 msgid "More Science" msgstr "Moy Godhonieth" #: src/bz-flathub-category.c:128 msgid "System" msgstr "Kevreyth" #: src/bz-flathub-category.c:128 msgid "More System" msgstr "Moy Kevreyth" #: src/bz-flathub-category.c:129 msgid "Utilities" msgstr "Lesow" #: src/bz-flathub-category.c:129 msgid "Tools" msgstr "Toulys" #: src/bz-flathub-category.c:129 msgid "More Utilities" msgstr "Moy Lesow" #: src/bz-flathub-category.c:130 src/bz-flathub-page.blp:119 #: src/bz-flathub-page.blp:152 msgid "Trending" msgstr "Gerys-da Lemmyn" #: src/bz-flathub-category.c:130 msgid "More Trending" msgstr "Moy Gerys-da Lemmyn" #: src/bz-flathub-category.c:131 src/bz-flathub-page.blp:125 #: src/bz-flathub-page.blp:182 msgid "Popular" msgstr "Gerys-da" #: src/bz-flathub-category.c:131 msgid "More Popular" msgstr "Moy Gerys-da" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:172 msgid "Recently Added" msgstr "Addya A-lergh" #: src/bz-flathub-category.c:132 src/bz-flathub-page.blp:131 msgid "New" msgstr "Nowydh" #: src/bz-flathub-category.c:132 msgid "More New" msgstr "Moy Nowydh" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:162 msgid "Recently Updated" msgstr "Nowedhys A-lergh" #: src/bz-flathub-category.c:133 src/bz-flathub-page.blp:137 msgid "Updated" msgstr "Nowedhys" #: src/bz-flathub-category.c:133 msgid "More Updated" msgstr "Moy Nowedhys" #: src/bz-flathub-category.c:134 msgid "Mobile" msgstr "Gwayadow" #: src/bz-flathub-category.c:134 msgid "More Mobile" msgstr "Moy Gwayadow" #: src/bz-flathub-category.c:135 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:135 msgid "More Adwaita" msgstr "Moy Adwaita" #: src/bz-flathub-category.c:136 msgid "KDE Apps" msgstr "Appys KDE" #: src/bz-flathub-category.c:136 msgid "More KDE Apps" msgstr "Moy Appys KDE" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Flathub heb Addya" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "An gwerthji Flathub na kavas war neb dha leyansow Flatpak" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "Flathub ri tre error" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "Hwilewgh arta Junyans Flathub" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Flathub Ankavadow" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "Ni ny yllir junya Flathub. Ty a yll dyghtya ha hwilas appys hwath." #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "Hwilas Appys" #: src/bz-flathub-page.blp:263 msgid "On the Go" msgstr "Gwayadow" #: src/bz-flathub-page.blp:275 msgid "Apps for your Linux phones and tablets" msgstr "Appys rag dha klapkodhow ha leghennow Linux" #: src/bz-flathub-page.blp:286 src/bz-flathub-page.blp:321 msgid "More Mobile Apps" msgstr "Moy Appys Gwayadow" #: src/bz-flathub-page.blp:379 msgid "We​ ♥​ Games" msgstr "Ni ♥ Gwariow​" #: src/bz-flathub-page.blp:392 msgid "Games and apps to run your favorite titles" msgstr "Gwariow hag appys rag eksekutya dha titlys drudh" #: src/bz-flathub-page.blp:426 msgid "More Games" msgstr "Moy Gwariow" #: src/bz-full-view.blp:66 src/bz-library-page.blp:76 #: src/bz-library-page.blp:80 msgid "No Results" msgstr "Sewyansow Vyth" #: src/bz-full-view.blp:67 msgid "Try a different search query" msgstr "Assaya hwithrans aral" #: src/bz-full-view.blp:73 msgid "Content" msgstr "Dalgh" #: src/bz-full-view.blp:131 msgid "Installing .flatpak bundles is not yet supported" msgstr "Ow lea fardellow .flatpak yw anskoodhys hwath" #: src/bz-full-view.blp:257 msgid "_Support" msgstr "_Skoodhya" #: src/bz-full-view.blp:426 msgid "Downloads/Month" msgstr "Iskargow/Mis" #: src/bz-full-view.blp:461 msgid "Stopped Receiving Core Updates" msgstr "Na Fella Ow Receva Nowedhyansow Kolonnen" #: src/bz-full-view.blp:475 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "An app ma devnydhya kerghynnedh na fella ow receva nowedhyansow po " "ewnheansow sawder. Yth bos martesen diantel rag devnydh." #: src/bz-full-view.blp:562 msgid "Trash Data" msgstr "Data Atal" #: src/bz-full-view.blp:702 msgid "Tags:" msgstr "Taggys:" #: src/bz-full-view.c:215 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:222 #, c-format msgid "%.*fM" msgstr "%.*fM" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:229 #, c-format msgid "%.*fK" msgstr "%.*fK" #: src/bz-full-view.c:239 #, c-format msgid "%d downloads in the last month" msgstr "%d iskargow y'n mis yw passys" #: src/bz-full-view.c:251 src/bz-full-view.c:592 src/bz-full-view.c:609 msgid "N/A" msgstr "Ankavadow" #: src/bz-full-view.c:279 #, c-format msgid "+%s runtime" msgstr "+%s kerghynnedh rag app" #: src/bz-full-view.c:282 msgid "Download" msgstr "Iskarg" #: src/bz-full-view.c:302 msgid "Size information unavailable" msgstr "Kedhlow braster ankavadow" #: src/bz-full-view.c:305 #, c-format msgid "Download size of %s" msgstr "Braster iskarg a %s" #: src/bz-full-view.c:338 msgid "All Ages" msgstr "Oll Osow" #: src/bz-full-view.c:350 msgid "Age rating information unavailable" msgstr "Kedhlow Talvos oos ankavadow" #: src/bz-full-view.c:355 msgid "Suitable for all ages" msgstr "Fytti rag oll osow" #: src/bz-full-view.c:357 #, c-format msgid "Suitable for ages %d and up" msgstr "Fytti rag osow %d ha war-vann" #: src/bz-full-view.c:390 src/bz-full-view.c:395 src/bz-full-view.c:423 #: src/bz-full-view.c:431 msgid "Unknown" msgstr "Ankoth" #: src/bz-full-view.c:400 #, c-format msgid "Free software licensed under %s" msgstr "Medhelweyth dhe wari kummya a-woles dhe %s" #: src/bz-full-view.c:405 msgid "Free software" msgstr "Medhelweyth dhe wari" #: src/bz-full-view.c:408 msgid "Proprietary Software" msgstr "Medhelweyth Perghenogel" #: src/bz-full-view.c:411 #, c-format msgid "Special License: %s" msgstr "Leshyans Arbennik: %s" #: src/bz-full-view.c:428 msgid "Free" msgstr "Dhe wari" #: src/bz-full-view.c:434 src/bz-license-dialog.c:132 msgid "Proprietary" msgstr "Perghenogel" #: src/bz-full-view.c:436 src/bz-license-dialog.c:134 msgid "Special License" msgstr "Leshyans Arbennik" #: src/bz-full-view.c:456 msgid "Adaptive" msgstr "Desedhadow" #: src/bz-full-view.c:456 msgid "Desktop Only" msgstr "Amontyell ik" #: src/bz-full-view.c:462 msgid "Works on desktop, tablets, and phones" msgstr "Gweythresek war amontyellow, leghennow, ha klapkodhow" #: src/bz-full-view.c:463 msgid "May not work on mobile devices" msgstr "Res angweythresek war devisyow gwayadow" #: src/bz-full-view.c:474 msgid "No URL" msgstr "Gorgevren Vyth" #: src/bz-full-view.c:492 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "An app ma kavos leshyans rydh, ytho an kod a yll bos arhwilys rag salowder." #: src/bz-full-view.c:493 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "An app ma kavos leshyans perghenogel, ytho an kod yw displegys privedh ha ny " "yllir bos arhwilys gans parti tressa anserghek." #: src/bz-full-view.c:500 msgid "More Apps" msgstr "Moy Appys" #: src/bz-full-view.c:501 #, c-format msgid "More Apps by %s" msgstr "Moy Appys gans %s" #: src/bz-full-view.c:508 msgid "Other Apps by this Developer" msgstr "Appys Aral gans an Awtour ma" #: src/bz-full-view.c:510 src/bz-full-view.c:693 #, c-format msgid "Other Apps by %s" msgstr "Appys Aral gans %s" #: src/bz-full-view.c:519 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "%s yw na leys, saw yth kavos %s a data remenant hwath." #: src/bz-full-view.c:599 src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "Saw" #: src/bz-full-view.c:601 src/bz-full-view.c:603 msgid "Low Risk" msgstr "Peryl Isel" #: src/bz-full-view.c:605 msgid "Medium Risk" msgstr "Peryl Kresek" #: src/bz-full-view.c:607 msgid "High Risk" msgstr "Peryl Ughel" #: src/bz-full-view.c:695 msgid "Other Apps" msgstr "Appys Aral" #: src/bz-full-view.c:697 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d App" msgstr[1] "%d Appys" #: src/bz-full-view.c:941 msgid "Show Less" msgstr "Diskwedhes Le" #: src/bz-full-view.c:941 msgid "Show More" msgstr "Diskwedhes Moy" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 msgid "Hardware Support" msgstr "Skoodhyans kalesweyth" #: src/bz-hardware-support-dialog.c:62 msgid "Keyboard support" msgstr "Skoodhyans bysowek" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "Rekwirya bysowegi" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "Komendya bysowegi" #: src/bz-hardware-support-dialog.c:66 msgid "Supports keyboards" msgstr "Skoodhya bysowegi" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "Skoodhyans ankoth rag bysowegi" #: src/bz-hardware-support-dialog.c:69 msgid "Mouse support" msgstr "Skoodhyans logosen" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "Rekwirya logosen po devisyow poyntya" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "Komendya logosen po devisyow poyntya" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "Skoodhya logosen po devisyow poyntya" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "Skoodhyans ankoth rag logosen po devisyow poyntya" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "Skoodhyans tochskrin" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "Rekwirya tochskrinyow" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "Komendya tochskrinyow" #: src/bz-hardware-support-dialog.c:80 msgid "Supports touchscreens" msgstr "Skoodhya tochskrinyow" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "Skoodhyans ankoth rag tochskrinyow" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "Skoodhyans klapkodh" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "Gweythresek war devisyow gwayadow" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "Res angweythresek war devisyow gwayadow" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "Skoodhyans amontyell" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "Gweythresek war skrinyow bras" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "%s gweythresek gwella war kalesweyth komparek" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "%s gweythresek war rann vrassa a devisyow" #: src/bz-install-controls.blp:33 msgid "Download & Install Application" msgstr "Iskarga & Lea App" #: src/bz-install-controls.blp:35 src/bz-transaction-dialog.c:202 msgid "_Install" msgstr "_Lea" #: src/bz-install-controls.blp:61 msgid "_Open" msgstr "_Ygeri" #: src/bz-install-controls.blp:76 src/bz-install-controls.blp:127 msgid "Uninstall Application" msgstr "Dilea App" #: src/bz-install-controls.blp:86 src/bz-transaction-dialog.c:231 msgid "_Remove" msgstr "_Remova" #: src/bz-install-controls.blp:114 src/bz-updates-card.blp:184 #: src/bz-updates-card.blp:212 msgid "Update" msgstr "Nowedhyans" #: src/bz-installed-tile.blp:64 src/bz-rich-app-tile.blp:140 msgid "Stopped Receiving Updates" msgstr "Nowedhys Namoy" #: src/bz-library-page.blp:31 msgid "Search installed apps" msgstr "Hwilas appys leys" #: src/bz-library-page.blp:48 msgid "Clear search" msgstr "Dilea hwithrans" #: src/bz-library-page.blp:69 msgid "No Apps Found" msgstr "Appys Kavas Vyth" #. Translators: . #: src/bz-library-page.blp:98 src/bz-window.blp:112 msgid "Library" msgstr "Lyverva" #: src/bz-library-page.blp:126 msgid "Pending Updates" msgstr "Nowedhyansow Ow Gortos" #: src/bz-library-page.blp:153 msgid "Downloads" msgstr "Iskargow" #: src/bz-library-page.blp:196 msgid "Recently Uninstalled" msgstr "Dileys A-Dhiwedhes" #: src/bz-library-page.blp:247 msgid "Clear Finished Tasks" msgstr "Dilea Oberennow Deu" #: src/bz-library-page.blp:260 msgid "Installed Apps" msgstr "Appys Leys" #: src/bz-library-page.blp:333 msgid "Sort By" msgstr "Sortya Gans" #: src/bz-library-page.blp:347 msgid "Name" msgstr "Hanow" #: src/bz-library-page.blp:353 msgid "Size" msgstr "Braster" #: src/bz-library-page.c:180 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "Parow vyth kavas rag \"%s\" y'n rol appys leys" #: src/bz-library-page.c:193 src/bz-updates-card.c:257 #, c-format msgid "%u Available Update" msgid_plural "%u Available Updates" msgstr[0] "%u Nowedhyans Kavadow" msgstr[1] "%u Nowedhyansow Kavadow" #: src/bz-license-dialog.blp:95 msgid "Get Involved" msgstr "Bos Omvyskys" #: src/bz-license-dialog.c:126 msgid "Unknown License" msgstr "Leshyans Ankoth" #: src/bz-license-dialog.c:129 msgid "Community Built" msgstr "Byldya gans an Kemeneth" #: src/bz-license-dialog.c:202 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "An app ma yw gwrys y'n poblek gans kemeneth keswlasek.\n" "\n" "Ty a yll kemeres rann ha gweres gwellhe yth." #: src/bz-license-dialog.c:205 msgid "The license of this app is not known" msgstr "An leshyans rag an app ma yw ankoth" #: src/bz-license-dialog.c:211 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "An app ma yw gwrys y'n poblek gans kemeneth keswlasek, ha dyllo a-woles " "dhe'n leshyans %s.\n" "\n" "Ty a yll kemeres rann ha gweres ow gwellhe yth." #: src/bz-license-dialog.c:219 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "An app ma yyw gwyrs na y'n poblek, ytho an awtours hepken aswon fatel yth " "oberi. Martesen, yth yw andhiogel yn agwedhow kales dhe helergi, hag yth a " "yll chanja heb ankov.\n" "\n" "Ty res po na res kevri dhe'n app ma." #: src/bz-license-dialog.c:225 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "An app ma yw gwyrs a-woles dhe'n leshyans arbennik %s.\n" "\n" "Ty a yll po na res kevri dhe'n app ma." #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 msgid "Connect to Flathub" msgstr "Junya dhe Flathub" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "Yma Hager Vargen" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "Junya dha akont Flathub dhe Basar rag dyghtya dha appys drudh." #: src/bz-login-page.blp:110 msgid "Finish" msgstr "Finsya" #: src/bz-login-page.c:664 #, c-format msgid "Hello, %s!" msgstr "Dydh dha, %s!" #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Settyansow" #: src/bz-preferences-dialog.blp:25 msgid "Network connection is metered — automatic store data refresh is paused" msgstr "" "Junyans kesrosweyth yw strothys — diseghans awtomatek dalgh gwerthji yw " "powesys" #: src/bz-preferences-dialog.blp:26 src/bz-window.blp:282 msgid "Refresh Manually" msgstr "Disegha dre Dhorn" #: src/bz-preferences-dialog.blp:31 msgid "Content Filters" msgstr "Sidhlow Dalgh" #: src/bz-preferences-dialog.blp:34 msgid "Free Software Only" msgstr "Medhelweyth Rydh" #: src/bz-preferences-dialog.blp:35 msgid "Hide proprietary applications when browsing and searching" msgstr "Kudha appys perghenogel dres ow peurya hag ow hwilas" #: src/bz-preferences-dialog.blp:39 msgid "Flathub Results Only" msgstr "Sewyasow Flathub Hepken" #: src/bz-preferences-dialog.blp:40 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "" "Finwetha sewyansow hwithrans ha peuryans dhe appys kavadow war Flathub hepken" #: src/bz-preferences-dialog.blp:44 msgid "Verified Results Only" msgstr "Sewyansow Gwirys Hepken" #: src/bz-preferences-dialog.blp:45 msgid "Hide results that are not verified on Flathub" msgstr "Kudha sewyansow na gwirys war Flathub" #: src/bz-preferences-dialog.blp:49 msgid "Hide EOL Apps" msgstr "Kudha Appys Marow" #: src/bz-preferences-dialog.blp:50 msgid "Hide apps which are no longer supported by their developers" msgstr "Kudha appys skoodhya na fella gans aga awtours" #: src/bz-preferences-dialog.blp:55 src/bz-window.blp:127 msgid "Search" msgstr "Hwithrans" #: src/bz-preferences-dialog.blp:58 msgid "Delay Search Results" msgstr "Delatya Sewyansow Hwithrans" #: src/bz-preferences-dialog.blp:59 msgid "Improve results performance by debouncing search terms" msgstr "Gwellhe skavder sewyasow gans ow kesunya geryow hwithrans" #: src/bz-preferences-dialog.blp:64 msgid "Progress Bar" msgstr "Barr Avonsyans" #: src/bz-preferences-dialog.blp:65 msgid "Choose a theme for the progress bar!" msgstr "Dewis thema rag an barr avonsyans!" #: src/bz-preferences-dialog.blp:89 msgid "Vertical Stripes" msgstr "Linennow Plommwedhek" #: src/bz-preferences-dialog.blp:90 msgid "Display flag colors from left to right" msgstr "Diskwedhes kolors baner dhyworth kledh dhe dyghow" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Kolor Usyer" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Kolors Gooth" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "Kolors Gooth Lesbian" #: src/bz-preferences-dialog.c:35 msgid "Male Homosexual Pride Colors" msgstr "Kolors Gooth Gourkethreydhel" #: src/bz-preferences-dialog.c:36 msgid "Transgender Pride Colors" msgstr "Kolors Gooth Treusreydhek" #: src/bz-preferences-dialog.c:37 msgid "Nonbinary Pride Colors" msgstr "Kolors Gooth na Den na Ben" #: src/bz-preferences-dialog.c:38 msgid "Bisexual Pride Colors" msgstr "Kolors Gooth Dewreydhel" #: src/bz-preferences-dialog.c:39 msgid "Asexual Pride Colors" msgstr "Kolors Gooth Anreydhel" #: src/bz-preferences-dialog.c:40 msgid "Pansexual Pride Colors" msgstr "Kolors Gooth Pubreydhek" #: src/bz-preferences-dialog.c:41 msgid "Aromantic Pride Colors" msgstr "Kolors Gooth Anromansek" #: src/bz-preferences-dialog.c:42 msgid "Genderfluid Pride Colors" msgstr "Kolors Gooth Reydh Chanjus" #: src/bz-preferences-dialog.c:43 msgid "Polysexual Pride Colors" msgstr "Kolors Gooth Liesreydhek" #: src/bz-preferences-dialog.c:44 msgid "Omnisexual Pride Colors" msgstr "Kolors Gooth Ollreydhek" #: src/bz-preferences-dialog.c:45 msgid "Aroace Pride Colors" msgstr "Kolors Gooth Anromansek hag Anreydhel" #: src/bz-preferences-dialog.c:46 msgid "Agender Pride Colors" msgstr "Kolors Gooth Anreydh" #: src/bz-preferences-dialog.c:47 msgid "Genderqueer Pride Colors" msgstr "Kolors Gooth na Den na Ben" #: src/bz-preferences-dialog.c:48 msgid "Intersex Pride Colors" msgstr "Kolors Gooth Hermaphroditek" #: src/bz-preferences-dialog.c:49 msgid "Demigender Pride Colors" msgstr "Kolors Gooth Hanterreydh" #: src/bz-preferences-dialog.c:50 msgid "Biromantic Pride Colors" msgstr "Kolors Gooth Dewromansek" #: src/bz-preferences-dialog.c:51 msgid "Disability Pride Colors" msgstr "Kolors Gooth Evredhyon" #: src/bz-preferences-dialog.c:52 msgid "Femboy Pride Colors" msgstr "Kolors Gooth Maw-Gwregel" #: src/bz-preferences-dialog.c:53 msgid "Neutrois Pride Colors" msgstr "Kolors Gooth Newtroys" #: src/bz-releases-dialog.blp:5 src/bz-updates-card.blp:171 msgid "Version History" msgstr "Istori Versyons" #: src/bz-releases-list.blp:27 msgid "_Version History" msgstr "Istori _Versyons" #. Translators: something happened less than a day ago #: src/bz-releases-list.c:122 msgid "Today" msgstr "Hedhyw" #. Translators: something happened more than a day ago but less than 2 days ago #: src/bz-releases-list.c:125 msgid "Yesterday" msgstr "De" #. Translators: something happened days ago #: src/bz-releases-list.c:128 #, c-format msgid "%d day ago" msgid_plural "%d days ago" msgstr[0] "Nans yw %d dydh" msgstr[1] "Nans yw %d dedhyow" #. Translators: something happened weeks ago #: src/bz-releases-list.c:131 #, c-format msgid "%d week ago" msgid_plural "%d weeks ago" msgstr[0] "Nans yw %d seythen" msgstr[1] "Nans yw %d seythennyow" #. Translators: something happened months ago #: src/bz-releases-list.c:134 #, c-format msgid "%d month ago" msgid_plural "%d months ago" msgstr[0] "Nans yw %d mis" msgstr[1] "Nans yw %d misyow" #. Translators: something happened years ago #: src/bz-releases-list.c:137 #, c-format msgid "%d year ago" msgid_plural "%d years ago" msgstr[0] "Nans yw %d bledhen" msgstr[1] "Nans yw %d bledhynnyow" #. TRANSLATORS: This is the date string with: day number, month name, year. #. i.e. "22 March 2026" #: src/bz-releases-list.c:155 msgid "%e %B %Y" msgstr "%e %B %Y" #: src/bz-releases-list.c:195 #, c-format msgid "Version %s" msgstr "Versyon %s" #: src/bz-releases-list.c:250 msgid "No details for this release" msgstr "Manylyon vyth rag an veryson ma" #: src/bz-releases-list.c:262 msgid "Get More Information" msgstr "Kerghes Moy Kedhlow" #: src/bz-rich-app-tile.blp:157 msgid "Get" msgstr "Kerghes" #: src/bz-rich-app-tile.blp:185 src/bz-transaction-tile.blp:272 msgid "Open" msgstr "Ygeri" #: src/bz-safety-calculator.c:82 msgid "Unknown Permissions" msgstr "Grontys Ankoth" #: src/bz-safety-calculator.c:83 msgid "Permissions are missing for this app." msgstr "Grontys fyllel rag an app ma." #: src/bz-safety-calculator.c:96 msgid "No Permissions" msgstr "Grontys Vyth" #: src/bz-safety-calculator.c:97 msgid "App is fully sandboxed" msgstr "App yw kontaynys yn leun" #: src/bz-safety-calculator.c:103 msgid "Network Access" msgstr "Hedhas Kesrosweyth" #: src/bz-safety-calculator.c:104 msgid "Can access the internet" msgstr "A yll drehedhes an kesrosweyth" #: src/bz-safety-calculator.c:106 msgid "No Network Access" msgstr "Hedhas Kesrosweyth Vyth" #: src/bz-safety-calculator.c:107 msgid "Cannot access the internet" msgstr "Ny yllir drehedhes an kesrosweyth" #: src/bz-safety-calculator.c:112 msgid "User Device Access" msgstr "Hedhas Devis Usyer" #: src/bz-safety-calculator.c:113 msgid "Can access devices such as webcams or gaming controllers" msgstr "A yll drehedhes devisyow kepar ha kameras po konsolen wariow gwydhyow" #: src/bz-safety-calculator.c:115 msgid "No User Device Access" msgstr "Hedhas Devis Usyer Vyth" #: src/bz-safety-calculator.c:116 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "" "Ny yllir drehedhes devisyow kepar ha kameras po konsolen wariow gwydhyow" #: src/bz-safety-calculator.c:121 msgid "Input Device Access" msgstr "Hedhas Devis Ynworrans" #: src/bz-safety-calculator.c:122 msgid "Can access input devices" msgstr "A yll drehedhes devisyow ynworrans" #: src/bz-safety-calculator.c:128 msgid "Microphone Access and Audio Playback" msgstr "Hedhas Korrgewsell Ha Seni Son" #: src/bz-safety-calculator.c:129 msgid "Can listen using microphones and play audio without asking permission" msgstr "A yll goslowes gans korrgewsellow ha seni son neb ow peji gront" #: src/bz-safety-calculator.c:135 msgid "System Device Access" msgstr "Hedhas Devis System" #: src/bz-safety-calculator.c:136 msgid "Can access system devices which require elevated permissions" msgstr "A yll drehedhes devisyow system may rekwirya grontys ughelhys" #: src/bz-safety-calculator.c:142 msgid "Screen Contents Access" msgstr "Hedhas Dalgh Skrin" #: src/bz-safety-calculator.c:143 msgid "Can access the contents of the screen or other windows" msgstr "A yll drehedhes an dalgh a'n skrin po fenestri aral" #: src/bz-safety-calculator.c:149 msgid "Legacy Windowing System" msgstr "System Fenester Anterrus" #: src/bz-safety-calculator.c:150 msgid "Always uses a legacy windowing system (X11)" msgstr "Devnydhya prest system fenester anterrus (X11)" #: src/bz-safety-calculator.c:156 msgid "Arbitrary Permissions" msgstr "Grontys Siansek" #: src/bz-safety-calculator.c:157 msgid "Can acquire arbitrary permissions" msgstr "A yll kavos grontys siansek" #: src/bz-safety-calculator.c:163 msgid "User Settings" msgstr "Settyansow Usyer" #: src/bz-safety-calculator.c:164 msgid "Can access and change user settings" msgstr "A yll drehedhes ha chanjya settyansow usyer" #: src/bz-safety-calculator.c:170 msgid "Full File System Read/Write Access" msgstr "Hedhas rag Redya/Skrifa System Restrenva Leun" #: src/bz-safety-calculator.c:171 msgid "Can read and write all data on the file system" msgstr "A yll redya ha skrifa oll data wa'n system restrenva" #: src/bz-safety-calculator.c:178 msgid "Home Folder Read/Write Access" msgstr "Hedhas rag Redya/Skrifa Restrenva Chi" #: src/bz-safety-calculator.c:179 msgid "Can read and write all data in your home directory" msgstr "A yll redya ha skrifa oll data yn dha restrenva tre" #: src/bz-safety-calculator.c:186 msgid "Full File System Read Access" msgstr "Hedhas rag Redya System Restrenva Leun" #: src/bz-safety-calculator.c:187 msgid "Can read all data on the file system" msgstr "A yll redya oll data y'n system restrenva" #: src/bz-safety-calculator.c:195 msgid "Home Folder Read Access" msgstr "Hedhas rag Redya Restrenva Tre" #: src/bz-safety-calculator.c:196 msgid "Can read all data in your home directory" msgstr "A yll redya oll data yn dha restrenva tre" #: src/bz-safety-calculator.c:204 msgid "Download Folder Read/Write Access" msgstr "Hedhas rag Redya/Skrifa yn Restrenva Iskargow" #: src/bz-safety-calculator.c:205 msgid "Can read and write all data in your downloads directory" msgstr "A yll redya ha skrifa oll data yn dha restrenva iskargow" #: src/bz-safety-calculator.c:215 msgid "Download Folder Read Access" msgstr "Hedhas rag Redya yn Restrenva Iskargow" #: src/bz-safety-calculator.c:216 msgid "Can read all data in your downloads directory" msgstr "A yll redya oll data yn dha restrenva iskargow" #: src/bz-safety-calculator.c:229 msgid "Can read and write all data in the directory" msgstr "A yll redya ha skrifa oll data y'n restrenva" #: src/bz-safety-calculator.c:243 msgid "Can read all data in the directory" msgstr "A yll redya oll data y'n restrenva" #: src/bz-safety-calculator.c:258 msgid "No File System Access" msgstr "Hedhas System Restrenva Vyth" #: src/bz-safety-calculator.c:259 msgid "Cannot access the file system at all" msgstr "Ny yllir drehedhes an system restrenva banna" #: src/bz-safety-calculator.c:266 msgid "Uses System Services" msgstr "Devnydhya Gonisyow System" #: src/bz-safety-calculator.c:267 msgid "Can request data from non-portal system services" msgstr "A yll govyn data dhyworth gonisyow anportal system" #: src/bz-safety-calculator.c:273 msgid "Uses Session Services" msgstr "Devnydhya Gonisyow Esedhek" #: src/bz-safety-calculator.c:274 msgid "Can request data from non-portal session services" msgstr "A yll govyn data dhyworth gonisyow anportal esedhek" #: src/bz-safety-calculator.c:322 msgid "No Service Access" msgstr "Hedhas Gonis Vyth" #: src/bz-safety-calculator.c:323 msgid "Cannot access non-portal session or system services at all" msgstr "Ny yllir drehedhes gonisyow anportal system po esedhek banna" #: src/bz-safety-calculator.c:331 msgid "Verified App Developer" msgstr "Awtour App Gwirys" #: src/bz-safety-calculator.c:332 msgid "The developer of this app has been verified to be who they say they are" msgstr "An awtour a'n app ma yw gwirys rag bos piw i onwul" #: src/bz-safety-calculator.c:341 msgid "Proprietary Code" msgstr "Kod Perghenogel" #: src/bz-safety-calculator.c:342 msgid "" "The source code is not public, so it cannot be independently audited and " "might be unsafe" msgstr "" "An kod yw anpoblek, ytho yth ny yllir bos arhwilys yn anserghek ha bos " "martesen diantel" #: src/bz-safety-calculator.c:352 msgid "Auditable Code" msgstr "Kod Arhwiladow" #: src/bz-safety-calculator.c:353 msgid "" "The source code is public and can be independently audited, which makes the " "app more likely to be safe" msgstr "" "An kod yw poblek hag a yll bos arhwilys yn anserghek, ytho an app ma yw saw " "moy gwirhaval" #: src/bz-safety-calculator.c:493 #, c-format msgid "Use the %s System Service" msgstr "Devnydhya an Gonis System %s" #: src/bz-safety-calculator.c:497 #, c-format msgid "Use the %s Session Service" msgstr "Devnydhya an Gonis Esedhek %s" #: src/bz-safety-calculator.c:501 #, c-format msgid "Use the %s Service" msgstr "Devnydhya an Gonis %s" #: src/bz-safety-calculator.c:511 msgid "Can see the non-portal service" msgstr "A yll gweles an gonis anportal" #: src/bz-safety-calculator.c:513 msgid "Can talk to the non-portal service" msgstr "A yll kewsel dhe'n gonis anportal" #: src/bz-safety-calculator.c:515 msgid "Can own the non-portal service" msgstr "A yll perghenna an gonis anportal" #: src/bz-safety-calculator.c:530 msgid "Global Menu Integration" msgstr "Oberyans Rol Olldalghus" #: src/bz-safety-calculator.c:531 msgid "Can display its menus in a global menu bar" msgstr "A yll diskwedhes rolyow yn barr rol olldalghus" #: src/bz-safety-calculator.c:536 msgid "KDE Settings Integration" msgstr "Oberyans Settyansow KDE" #: src/bz-safety-calculator.c:537 msgid "Can detect when KDE desktop settings change" msgstr "A yll helerghi pan settyansow KDE chanjya" #: src/bz-safety-calculator.c:542 msgid "KDE Global Settings" msgstr "Settyansow Olldalghus KDE" #: src/bz-safety-calculator.c:543 msgid "Can read KDE desktop preferences like fonts and colors" msgstr "A yll redya settyansow desktop KDE kepar ha fontow ha kolors" #: src/bz-safety-calculator.c:548 msgid "Secret Storage Service" msgstr "Gonis Gwithyans Kevrinyow" #: src/bz-safety-calculator.c:549 msgid "Can store and retrieve its own passwords using the system keyring" msgstr "" "A yll gwitha ha kerghes yth geryow-tremena ow devnydhya an alhwedhow-kylgh " "system" #: src/bz-safety-calculator.c:554 msgid "Desktop Notifications Service" msgstr "Gonis Gwarnyansow Desktop" #: src/bz-safety-calculator.c:555 msgid "Can send desktop notifications" msgstr "A yll danvon gwarnyansow desktop" #: src/bz-safety-calculator.c:561 msgid "System Tray Integration" msgstr "Oberyans Tallyour System" #: src/bz-safety-calculator.c:562 msgid "Can display an icon in the system tray" msgstr "A yll diskwedhes arwodhik y'n tallyour system" #: src/bz-safety-calculator.c:567 msgid "KDE Connect Integration" msgstr "Oberyans KDE Connect" #: src/bz-safety-calculator.c:568 msgid "Can interact with devices paired via KDE Connect" msgstr "A yll keskomunya gans devisyow junys dre KDE Connect" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "Sawder" #: src/bz-safety-dialog.blp:53 msgid "License" msgstr "Leshyans" #: src/bz-safety-dialog.blp:63 msgid "App ID" msgstr "ID App" #: src/bz-safety-dialog.blp:73 msgid "SDK" msgstr "SDK" #: src/bz-safety-dialog.blp:104 msgid "" "This app uses an outdated version of the software platform (SDK) and might " "contain bugs or security vulnerabilities which will not be fixed." msgstr "" "An app ma devnydhya versyon anterrus a'n kerghynnedh medhelweyth (SDK) ha " "kontaynya martesen kudynnow po goliadewderow sawder may na bos ewnhys." #: src/bz-safety-dialog.c:227 #, c-format msgid "%s is Safe" msgstr "%s yw Saw" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s has no Unsafe Permissions" msgstr "%s kavas Grontys Diantel Vyth" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Probably Safe" msgstr "%s yw Saw Dell Hevel" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Possibly Unsafe" msgstr "%s yw Saw Martesen" #: src/bz-safety-dialog.c:247 #, c-format msgid "%s is Unsafe" msgstr "%s yw Diantel" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "Imajys" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "Imach Kyns" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "Imach Nessa" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "Kopia Imach" #: src/bz-screenshot-page.blp:147 msgid "Reset View" msgstr "Dasgorra Gwel" #: src/bz-screenshot-page.blp:158 msgid "Zoom Out" msgstr "Lehe" #: src/bz-screenshot-page.blp:168 msgid "Zoom In" msgstr "Moghhe" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "Res A-dro Imajys" #: src/bz-screenshots-carousel.blp:117 msgid "Open Screenshot Viewer" msgstr "Ygeri Gwelell Imajys" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:72 msgid "Video" msgstr "Gwydhyow" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:82 msgid "Office" msgstr "Buro" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:87 msgid "PDF" msgstr "PDF" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:92 msgid "Calendar" msgstr "Kalender" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:97 msgid "Messaging" msgstr "Messajys" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:102 msgid "Steam" msgstr "Steam" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:107 msgid "Paint" msgstr "Liwa" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:112 msgid "VPN" msgstr "VPN" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:117 msgid "Torrent" msgstr "Keynres" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:122 msgid "Minecraft" msgstr "Minecraft" #. Translators: Search suggestion: the english text will be used for the #. search regardless of what you put here, so don't worry about the string #. yielding poor search results. Focus on correctness and friendliness, #. etc #: src/bz-search-pill-list.c:127 msgid "Emulator" msgstr "Omhevelians" #: src/bz-search-page.blp:57 msgid "Search Apps, Games, Software" msgstr "Hwials Appys, Gwariow, Medhelweyth" #: src/bz-search-page.blp:79 msgid "Clear Search" msgstr "Dilea Hwithrans" #: src/bz-search-page.blp:171 msgid "Categories Unavailable" msgstr "Klassys Ankavadow" #: src/bz-search-page.blp:172 msgid "Search for apps using the search bar above." msgstr "Hwilas rag appys gans an barr hwithrans a-ugh." #: src/bz-search-page.blp:198 msgid "Browse Categories" msgstr "Peuri Klassys" #: src/bz-search-page.blp:340 msgid "No Applications Found" msgstr "Appys Kavas Vyth" #: src/bz-search-page.c:244 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "Sewyansow kavas vyth rag \"%s\" yn Flathub" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "Kopia Gorgevren" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Ygeri Gorgevren" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "Linen Dermyn" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "Leyansow:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "Bys" #: src/bz-stats-dialog.blp:69 msgid "Since 4/15/2024" msgstr "A-dhia 15/4/2024" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:124 #, c-format msgid "%.2fM Total Installs" msgstr "%.2fM Somm Leyansow" #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:127 #, c-format msgid "%.2fK Total Installs" msgstr "%.2fk Somm Leyansow" #: src/bz-stats-dialog.c:129 #, c-format msgid "%'d Total Installs" msgstr "%'d Somm Leyansow" #: src/bz-tag-list.c:78 msgid "No Results Found" msgstr "Sewyansow Kavas Vyth" #: src/bz-tag-list.c:90 #, c-format msgid "Apps Tagged \"%s\"" msgstr "Appys Taggya avel \"%s\"" #: src/bz-tag-list.c:103 msgid "Search failed" msgstr "Hwithrans fyllis" #: src/bz-transaction-dialog.c:155 msgid "Keep User Data" msgstr "Gwitha Data Usyer" #: src/bz-transaction-dialog.c:156 msgid "Allow restoring personal settings & content" msgstr "Alowa ow daskor settyansow & dalgh personel" #: src/bz-transaction-dialog.c:165 msgid "Delete All Data" msgstr "Dilea Oll Data" #: src/bz-transaction-dialog.c:166 msgid "Permanently erase user data to save space" msgstr "Dilea yn fast data usyer rag erbysi dalghuster" #: src/bz-transaction-dialog.c:191 #, c-format msgid "Install %s?" msgstr "Lea %s?" #: src/bz-transaction-dialog.c:196 msgid "" "Select which version to install. May install additional shared components" msgstr "" "Dewis py versyon rag lea. Martesen a wra lea darnow kevrennys keworransel" #: src/bz-transaction-dialog.c:198 msgid "May install additional shared components" msgstr "Res lea darnow keworransel poblek" #: src/bz-transaction-dialog.c:201 src/bz-transaction-dialog.c:230 #: src/bz-transaction-dialog.c:275 src/bz-transaction-dialog.c:578 msgid "_Cancel" msgstr "_Hedhi" #: src/bz-transaction-dialog.c:219 #, c-format msgid "Remove %s?" msgstr "Remova %s?" #: src/bz-transaction-dialog.c:222 msgid "Select which version to remove." msgstr "Dewis mar verson rag remova." #: src/bz-transaction-dialog.c:224 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "Yth yw angalladow dhe devnydhya %s wosa yth yw dileys." #: src/bz-transaction-dialog.c:247 #, c-format msgid "“%s” is High Risk" msgstr "\"%s\" yw Peryl Ughel" #: src/bz-transaction-dialog.c:251 msgid "" "This app has full access to your system, including all your files, " "browser history, saved passwords, and more. It also has access to the " "internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "An app ma kavos hedhas leun dhe dha system, ow komprehendya oll dha " "restrennow, istori peurell, geryow-tremena sawys ha moy. Ynwedh, yth " "kavos hedhas kesrosweyth, ytho yth a yll danvon dha data dhe partiow " "tressa.\n" "\n" "Dre reson an app yw perghenogel, yth ny yllir bos arwhilys rag pyth yth gul " "gans an grontys ma." #: src/bz-transaction-dialog.c:260 msgid "" "This app uses the legacy X11 windowing system, which allows it to record " "all keystrokes, capture screenshots, and monitor other applications. It " "also has access to the internet, meaning it could send your data to outside " "parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "An app ma devnydhys an system fenestri anterrus X11, ytho yth a yll " "rekordya oll jynnskrifow, kemeres skrin-imajys, ha helerghi appys aral. Maga ta, yth a yll drehedhes an kesrosweyth, ytho yth a yll danvon dha " "data dhe partiow tressa.\n" "\n" "Dre reson an app yw perghenogel, yth ny yllir bos arwhilys rag pyth yth gul " "gans an grontys ma." #: src/bz-transaction-dialog.c:276 msgid "_Install Anyway" msgstr "_Lea yn neb Kas" #: src/bz-transaction-dialog.c:331 msgid "Failed to load transaction dialog" msgstr "Ny yllir karga fenester negys" #: src/bz-transaction-dialog.c:549 msgid "All apps are already installed" msgstr "Oll appys yw leys seulabrys" #: src/bz-transaction-dialog.c:551 msgid "_OK" msgstr "_Da Lowr" #: src/bz-transaction-dialog.c:567 #, c-format msgid "Install %u App?" msgid_plural "Install %u Apps?" msgstr[0] "Lea %u App?" msgstr[1] "Lea %u Appys?" #: src/bz-transaction-dialog.c:575 msgid "" "The following will be installed. Additional shared components may also be " "installed" msgstr "" "An taklow a sew a wra bos leys. Ynwedh, darnow kevrennys keworransel a wra " "leys martesen" #: src/bz-transaction-dialog.c:576 #, c-format msgid "%d addons will be installed." msgstr "%d ystynansow a wra bos leys." #: src/bz-transaction-dialog.c:577 msgid "Additionally, addons will be installed." msgstr "Ynwedh, ystyanansow a wra bos leys." #: src/bz-transaction-dialog.c:579 msgid "_Install All" msgstr "_Lea Oll" #: src/bz-transaction-manager.c:766 #, c-format msgid "Finished in %.02f seconds" msgstr "Deu yn %.02f eylennow" #: src/bz-transaction-tile.blp:129 msgid "App Add-On" msgstr "Ystynnans rag App" #: src/bz-transaction-tile.blp:158 msgid "Runtime" msgstr "Kerghynnedh rag App" #: src/bz-transaction-tile.blp:182 msgid "In Queue" msgstr "Yn Lost" #: src/bz-transaction-tile.blp:206 msgid "Done" msgstr "Deu" #: src/bz-transaction-tile.blp:230 msgid "Error" msgstr "Error" #: src/bz-transaction-tile.blp:286 msgid "Cancel Transaction" msgstr "Hedhi Negys" #: src/bz-transaction-tile.blp:410 msgid "Show Error Info" msgstr "Diskwedhes Kedhlow Error" #: src/bz-transaction-tile.c:107 #, c-format msgid "%s Freed" msgstr "%s Rythhys" #: src/bz-transaction-tile.c:362 src/bz-transaction-tile.c:365 msgid "Transaction Error" msgstr "Error Negys" #: src/bz-transaction.c:342 msgid "Pending" msgstr "Ow Gortos" #: src/bz-updates-card.blp:40 msgid "_Update All" msgstr "_Nowedhi Oll" #: src/bz-updates-card.c:293 #, c-format msgid "%u Runtime Update" msgid_plural "%u Runtime Updates" msgstr[0] "%u Nowedhyans Kerghynnedh" msgstr[1] "%u Nowedhyansow Kerghynnedh" #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "Dyghtya Data Usyer Remenant" #: src/bz-user-data-page.blp:89 msgid "No User Data Found" msgstr "Data Usyer Kavas Vyth" #: src/bz-user-data-page.blp:94 msgid "User Data" msgstr "Data Usyer" #: src/bz-user-data-tile.c:144 #, c-format msgid "Trashed User Data for %s" msgstr "Removys Data User rag %s" #: src/bz-user-data-tile.blp:74 msgid "Trash User Data" msgstr "Remova Data Usyer" #: src/bz-window.blp:88 msgid "Curated" msgstr "Dyghtys" #: src/bz-window.blp:100 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:220 msgid "Refresh completed!" msgstr "Diseghans deu!" #: src/bz-window.blp:273 msgid "You are running a new version of Bazaar!" msgstr "Owth eksekutya os ta versyon nowydh a Basar!" #: src/bz-window.blp:274 msgid "See What's New" msgstr "Pyth yw Nowydh" #: src/bz-window.blp:281 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "Ty kavos junyans kewrosweyth mes yw ow gweles versyon koth a Flathub" #: src/bz-window.blp:393 msgid "Log Out" msgstr "Omdhigelmi" #. Translators: %s is the title of the current page #: src/bz-window.c:380 #, c-format msgid "Bazaar — %s" msgstr "Basar — %s" #: src/bz-window.c:487 msgid "Failed to load add-ons" msgstr "Ny yllir karga ystynansow" #: src/bz-window.c:601 src/bz-window.c:618 msgid "Failed to launch application" msgstr "Ny yllir lonchya app" #: src/bz-window.c:823 msgid "You can't remove Bazaar from Bazaar!" msgstr "Ty ny yllir remova Basar dhyworth Basar!" #: src/bz-window.c:1108 src/bz-window.c:1142 msgid "Can't do that right now!" msgstr "Ny yllir gul an re na y'n eur ma" #: src/bz-world-map.c:595 msgctxt "As in, \"100 Downloads\"" msgid "Downloads" msgstr "Iskargow" #: src/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Ollgemmyn" #: src/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Page" msgstr "Ygeri Folen Hwithrans" #: src/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Library Page" msgstr "Ygeri Folen Lyverva" #: src/shortcuts-dialog.blp:20 msgctxt "shortcut window" msgid "Refresh" msgstr "Disegha" #: src/shortcuts-dialog.blp:25 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Ygeri Settyansow" #: src/shortcuts-dialog.blp:30 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Diskwedhes Kesunyansow Bysowek" #: src/shortcuts-dialog.blp:35 msgctxt "shortcut window" msgid "Close Window" msgstr "Degea Fenester" #: src/shortcuts-dialog.blp:41 msgctxt "shortcut window" msgid "Quit Bazaar" msgstr "Kwytya Basar" #~ msgid "" #~ "It emphasizes supporting the developers who make the Linux desktop " #~ "possible. Bazaar features a \"curated\" tab that can be configured by " #~ "distributors to allow for a more localized experience." #~ msgstr "" #~ "Yth posleva ow skoodhya an awtours neb a gul an ekokevreyth Linux. Basar " #~ "omdhiskwedhes an tabb \"dyghtys\" dre konfigurys gans lesrenyadesow dhe " #~ "alowa rag eksperyans leel." #~ msgid "%e %B" #~ msgstr "%e %B" #~ msgid "Install Other Version" #~ msgstr "Lea Versyon Aral" #~ msgid "Support this application" #~ msgstr "Skoodhya an app ma" #~ msgid "Manage Add-ons" #~ msgstr "Dyghtya Ystynansow" #~ msgid "Keep Data" #~ msgstr "Gwitha Data" #~ msgid "Open App" #~ msgstr "Ygeri App" #~ msgid "_Login with Flathub" #~ msgstr "_Omgelmi gans Flathub" #~ msgid "Nucleus app page" #~ msgstr "Folen app Nuklesen" #~ msgid "_Synchronize Remotes" #~ msgstr "_Kerghes Gwerthjiow" #~ msgid "Synchronizing..." #~ msgstr "Ow Kettermynyegi..." #, c-format #~ msgid "Receiving %d entries..." #~ msgstr "Ow receva %d enworrans manylyon..." #~ msgid "Indexing Data..." #~ msgstr "Ow Kevernya Data..." #~ msgid "Bazaar is a Passion Project" #~ msgstr "Basar yw Ragdres Passyon" #~ msgid "Support the Future of Linux App Distribution" #~ msgstr "Skoodhya an Termyn a Dheu a Lesrannans Appys Linux" #~ msgid "Disable the donations banner on startup" #~ msgstr "Ungallosegi an baner argevrohow dres dalleth" #~ msgid "Close" #~ msgstr "Kwytya" #~ msgid "Copy and Close" #~ msgstr "Dasskrifa ha Kwytya" #~ msgid "Refreshing Store Content" #~ msgstr "Ow Diseghow Dalgh Gwerthji" #~ msgid "No background tasks!" #~ msgstr "Oberennow vyth yn kilva!" #~ msgid "See More" #~ msgstr "Gweles Moy" #~ msgctxt "shortcut window" #~ msgid "Synchronize Remotes" #~ msgstr "_Kettermynyegi Gwerthjiow" #~ msgctxt "shortcut window" #~ msgid "Toggle Transaction Manager" #~ msgstr "Dewis Dyghtyer Treuswrians" #~ msgctxt "shortcut window" #~ msgid "Quit" #~ msgstr "Kwytya" #~ msgid "Install Size" #~ msgstr "Braster Lea" #~ msgid "Ongoing" #~ msgstr "Didorr" #~ msgid "Finished" #~ msgstr "Deu" #, c-format #~ msgid "Transferred %s so far" #~ msgstr "Treusperthi %s bys lemmyn" #~ msgid "Tasks" #~ msgstr "Oberennow" #~ msgid "Stop Active Tasks" #~ msgstr "Hedhi Oberennow Byw" #~ msgid "No Tasks Yet" #~ msgstr "Oberennow Vyth Hwath" #, c-format #~ msgid "%d Update Available" #~ msgid_plural "%d Updates Available" #~ msgstr[0] "%d Nowedh Kavadow" #~ msgstr[1] "%d Nowedhow Kavadow" #~ msgid "Updates Are Available" #~ msgstr "Nowedhow Kavadow" #~ msgid "" #~ "The following applications are eligible for updates. Would you like to " #~ "install them?" #~ msgstr "An appys a sew yw dewisadow rag nowedhow. A vynnsowgh lea y's?" #, c-format #~ msgid "" #~ "%d runtimes and/or addons are eligible for updates. Would you like to " #~ "install them?" #~ msgstr "" #~ "%d kerghynnedhow ha/po ystynnans yw dewisadow rag nowedhow. A vynnsowgh " #~ "lea y's?" #, c-format #~ msgid "Additionally, %d runtimes and/or addons will be updated." #~ msgstr "Dres hemma, %d kerghynnedhow ha/po ystyannans yw nowedhys." #~ msgid "Update Now" #~ msgstr "Nowedhi Lemmyn" #~ msgid "Resume Current Tasks" #~ msgstr "Daskemeres Oberennow A-Lemmyn" #~ msgid "Pause Current Tasks" #~ msgstr "Powes Oberennow A-Lemmyn" #~ msgid "" #~ "The ability to inspect and install local .flatpak bundle files is coming " #~ "soon! In the meantime, try running\n" #~ "\n" #~ "flatpak install --bundle your-bundle.flatpak\n" #~ "\n" #~ "on the command line." #~ msgstr "" #~ "An Gallos dhe hwithra ha lea restrennow .flatpak leel ow tos yn skon! Yn " #~ "kettermyn, tria owth eksekutya\n" #~ "\n" #~ "flatpak install --bundle agas-gronn.flatpak\n" #~ "\n" #~ "yn an linen arghadow." #~ msgid "Hide EOL Entries" #~ msgstr "Keles appys marow" #~ msgid "Hide EOL entries and entries depending on them" #~ msgstr "Keles appys marow hag appys serghek" #~ msgid "Only Show Free Software" #~ msgstr "Diskwedhes appys dhe wari hepken" #~ msgid "Hide proprietary software" #~ msgstr "Keles appys perghenogel" #~ msgid "Show Only Flathub Content" #~ msgstr "Diskwedhes synsas Flathub hepken" #~ msgid "Hide applications which do not originate from Flathub" #~ msgstr "Kudha appys may na dalleth dhyworth Flathub" #~ msgid "Show Only Verified Content" #~ msgstr "Diskwedhes Dalgh Flathub Hepken" #~ msgid "Hide applications which are not verified on Flathub" #~ msgstr "Kudha appys may na gwirys war Flathub" #~ msgid "Debounce Search Inputs" #~ msgstr "Kesunya Ynworransow Hwithrans" #~ msgid "Add a delay before searching to prevent instant replies while typing" #~ msgstr "" #~ "Addya unn ardak dherag hwilas rag preventya gorthebow desempis dres " #~ "jynnskrifa" #~ msgid "Global Progress Bar Theme" #~ msgstr "Thema Barr Avonsyans Olldalghus" #~ msgid "Describes the look of the global progress bar" #~ msgstr "Deskrifa an mir a an Barr Avonsyans Olldalghus" #~ msgid "Saved Window Dimensions" #~ msgstr "Sawys Braster Fenester" #~ msgid "The window dimensions to be used by the next Bazaar window" #~ msgstr "An braster fenester rag devnydh gans an fenester Basar nessa" #~ msgid "?" #~ msgstr "?" #~ msgid "" #~ "This functionality is currently disabled. It is recommended you download " #~ "and install Flatseal to manage app permissions." #~ msgstr "" #~ "An nas ma usi evredhek y'n eur ma. Y usi komendya dhe iskarga ha lea " #~ "Flatseal dhe dyghtya grontow appys." #~ msgid "Entry Inspector" #~ msgstr "Hwithrer Enworrans Manylyon" #~ msgid "Serialize" #~ msgstr "Kedreylya yn Baytys" #~ msgid "Convert to JSON" #~ msgstr "Kedreylya yn JSON" #~ msgid "More Mobile apps" #~ msgstr "Moy Appys Gwayadow" #~ msgid "Bazaar Inspector" #~ msgstr "Hwithrer Basar" #~ msgid "Background Task Info:" #~ msgstr "Kedhlow Oberennow Kilva:" #~ msgid "Enable Global Debug Mode" #~ msgstr "Gallosegi Prevessa Olldalghus" #~ msgid "Active Blocklists" #~ msgstr "Rol a Lettys Byw" #~ msgid "Active Curated-Configs" #~ msgstr "Settyansow Dyghtys Byw" #~ msgid "All Entry Groups" #~ msgstr "Oll Bagasow Enworrans Manylyon" #~ msgid "Filter..." #~ msgstr "Sidhla..." #~ msgid "Decache and Inspect" #~ msgstr "Dissorn ha Hwithra" #~ msgid "No Flatpaks Installed" #~ msgstr "Vyth Flatpakow Ynstallys" #~ msgid "Connect with Flathub" #~ msgstr "_Junya dhe Flathub" #~ msgid "Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth (Gorwelyek)" #~ msgid "Lesbian Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Lesbian (Gorwelyek)" #~ msgid "Male Homosexual Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Gourkethreydhel (Gorwelyek)" #~ msgid "Transgender Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Treusreydhek (Gorwelyek)" #~ msgid "Nonbinary Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth na Den na Ben (Gorwelyek)" #~ msgid "Bisexual Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Dewreydhel (Gorwelyek)" #~ msgid "Asexual Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Anreydhel (Gorwelyek)" #~ msgid "Pansexual Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Pubreydhek (Gorwelyek)" #~ msgid "Aromantic Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Anromansek (Gorwelyek)" #~ msgid "Genderfluid Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Reydh Chanjus (Gorwelyek)" #~ msgid "Polysexual Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Liesreydhek (Gorwelyek)" #~ msgid "Omnisexual Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Ollreydhek (Gorwelyek)" #~ msgid "Aroace Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Anromansek hag Anreydhel (Gorwelyek)" #~ msgid "Agender Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Anreydh (Gorwelyek)" #~ msgid "Genderqueer Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth na Den na Ben (Gorwelyek)" #~ msgid "Intersex Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Hermaphroditek (Gorwelyek)" #~ msgid "Demigender Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Hanterreydh (Gorwelyek)" #~ msgid "Biromantic Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Dewromansek (Gorwelyek)" #~ msgid "Disability Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Evredhyon (Gorwelyek)" #~ msgid "Femboy Pride Colors (Horizontal)" #~ msgstr "Kolors Gooth Maw-Gwregel (Gorwelyek)" #~ msgid "Inspect UI Entry" #~ msgstr "Hwithra Elven Ynterfas" #~ msgid "All Debug Actions" #~ msgstr "Oll Gwriansow Prevessa" #~ msgid "Open Bazaar Inspector" #~ msgstr "Ygeri Hwithrer Basar" #, c-format #~ msgid "%s: %'u downloads" #~ msgstr "%s: %'u iskargow" #, c-format #~ msgid "%s is suitable for toddlers" #~ msgstr "%s usi fytti rag fleghes vyghan" #~ msgid "--- MB" #~ msgstr "--- MB" #~ msgid "Of the size of human DNA" #~ msgstr "a an braster a DNA den" #~ msgid "3 billion base pairs" #~ msgstr "3 bilvil koplow ben" #~ msgid "Of the Linux Kernel" #~ msgstr "a an Bewyn Linux" #~ msgid "linux-6.17.tar.xz" #~ msgstr "linux-6.17.tar.xz" #~ msgid "Of the Apollo 11 guidance computer" #~ msgstr "a an amontyell Apollo 11" #~ msgid "Total ROM and RAM" #~ msgstr "Somm rag ROM ha RAM" #~ msgid "Of the original Super Mario Bros" #~ msgstr "a Super Mario Bros" #~ msgid "On the NES" #~ msgstr "yn an NES" #~ msgid "Of the size of Wikipedia" #~ msgstr "a an braster rag Wikipedya" #~ msgid "Without any media" #~ msgstr "Heb neb media" bazaar-orig-v0.7.14/po/POTFILES.in0000664000175000017500000000662415166123241015343 0ustar hasanhasan# List of source files containing translatable strings. # Please keep this file sorted alphabetically. data/io.github.kolunmi.Bazaar.desktop.in data/io.github.kolunmi.Bazaar.metainfo.xml.in src/bz-addon-tile.blp src/bz-addon-tile.c src/bz-addons-dialog.blp src/bz-addons-dialog.c src/bz-age-rating-dialog.blp src/bz-age-rating-dialog.c src/bz-all-apps-page.blp src/bz-all-apps-page.c src/bz-app-permissions.c src/bz-app-size-dialog.blp src/bz-app-size-dialog.c src/bz-app-tile.blp src/bz-app-tile.c src/bz-apps-page.blp src/bz-apps-page.c src/bz-application-map-factory.c src/bz-application.c src/bz-appstream-parser.c src/bz-async-texture.c src/bz-backend.c src/bz-comet-overlay.c src/bz-content-provider.c src/bz-context-tile.blp src/bz-context-tile.c src/bz-context-tile-callbacks.c src/bz-curated-view.blp src/bz-curated-view.c src/bz-data-graph.c src/bz-decorated-screenshot.blp src/bz-decorated-screenshot.c src/bz-developer-badge.blp src/bz-developer-badge.c src/bz-donations-dialog.blp src/bz-donations-dialog.c src/bz-download-worker.c src/bz-dynamic-list-view.c src/bz-entry-cache-manager.c src/bz-entry-group.c src/bz-entry-group-util.c src/bz-entry-inspector.blp src/bz-entry-inspector.c src/bz-entry-selection-row.blp src/bz-entry-selection-row.c src/bz-entry.c src/bz-env.c src/bz-error.c src/bz-error-dialog.blp src/bz-error-dialog.c src/bz-favorite-button.c src/bz-favorite-button.blp src/bz-favorites-tile.c src/bz-favorites-tile.blp src/bz-favorites-page.c src/bz-favorites-page.blp src/bz-featured-carousel.blp src/bz-featured-tile.blp src/bz-flathub-category-section.c src/bz-flathub-category.c src/bz-flathub-page.blp src/bz-flathub-page.c src/bz-flathub-state.c src/bz-flatpak-entry.c src/bz-flatpak-instance.c src/bz-full-view.blp src/bz-full-view.c src/bz-global-net.c src/bz-gnome-shell-search-provider.c src/bz-group-tile-css-watcher.c src/bz-hardware-support-dialog.blp src/bz-hardware-support-dialog.c src/bz-inhibited-scrollable.c src/bz-inspector.blp src/bz-inspector.c src/bz-install-controls.blp src/bz-install-controls.c src/bz-installed-tile.blp src/bz-installed-tile.c src/bz-io.c src/bz-library-page.blp src/bz-library-page.c src/bz-license-dialog.blp src/bz-license-dialog.c src/bz-license-dialog.h src/bz-login-page.blp src/bz-login-page.c src/bz-login-page.h src/bz-preferences-dialog.blp src/bz-preferences-dialog.c src/bz-progress-bar.blp src/bz-progress-bar.c src/bz-releases-dialog.blp src/bz-releases-list.blp src/bz-releases-list.c src/bz-result.c src/bz-rich-app-tile.blp src/bz-rich-app-tile.c src/bz-safety-calculator.c src/bz-safety-dialog.blp src/bz-safety-dialog.c src/bz-screenshot.c src/bz-screenshot-page.blp src/bz-screenshots-carousel.blp src/bz-search-engine.c src/bz-search-pill-list.c src/bz-search-filter-popover.blp src/bz-search-filter-popover.c src/bz-search-page.blp src/bz-search-page.c src/bz-section-view.blp src/bz-section-view.c src/bz-serializable.c src/bz-share-list.c src/bz-stats-dialog.blp src/bz-stats-dialog.c src/bz-tag-list.c src/bz-transaction-dialog.c src/bz-transaction-list-dialog.blp src/bz-transaction-list-dialog.c src/bz-transaction-manager.c src/bz-transaction-tile.blp src/bz-transaction-tile.c src/bz-transaction.c src/bz-updates-card.blp src/bz-updates-card.c src/bz-user-data-page.c src/bz-user-data-page.blp src/bz-user-data-tile.c src/bz-user-data-tile.blp src/bz-window.blp src/bz-window.c src/bz-world-map.c src/bz-yaml-parser.c src/dl-worker.c src/shortcuts-dialog.blp src/main.c bazaar-orig-v0.7.14/po/zh_TW.po0000664000175000017500000022610215166123241015154 0ustar hasanhasan# Traditional Chinese translations for bazaar package # Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # # SPDX-FileCopyrightText: 2025–2026 Shihfu Juan # SPDX-FileCopyrightText: 2025 Peter Dave Hello msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-01-24 01:17+0800\n" "PO-Revision-Date: 2026-01-24 21:23+0800\n" "Last-Translator: Shihfu Juan \n" "Language-Team: none\n" "Language: zh_TW\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Poedit 3.8\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:5 #: src/bz-window.blp:233 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "新增、移除或更新此電腦上的 Flatpak 軟體" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "" "GTK;System;PackageManager;Discover;Flatpak;Software;Store;套件管理;探索;軟體;" "商店;" #: data/io.github.kolunmi.Bazaar.desktop.in:15 msgid "New Window" msgstr "新視窗" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and install applications" msgstr "探索與安裝應用程式" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A new app store for Linux with a focus on discovering and installing " "applications and addons from Flatpak remotes, particularly Flathub." msgstr "" "為 Linux 打造的新應用程式商店,著重探索與安裝來自 Flatpak 遠端(特別是 " "Flathub)的應用程式與附加元件。" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:14 msgid "" "It emphasizes supporting the developers who make the Linux desktop possible. " "Bazaar features a \"curated\" tab that can be configured by distributors to " "allow for a more localized experience." msgstr "" "著重支援讓 Linux 桌面成真的開發者。Bazaar 提供「精選」分頁,發行商可設定以提" "供更在地化的體驗。" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:29 src/bz-application.c:706 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:54 msgid "The home page displaying Flathub apps" msgstr "展示 Flathub 應用程式的首頁" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:58 msgid "Nucleus app page" msgstr "Nucleus 應用程式頁面" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:62 msgid "Search page" msgstr "搜尋頁面" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:66 msgid "Category page" msgstr "類別頁面" #: src/bz-addons-dialog.blp:14 src/bz-full-view.blp:697 #: src/bz-installed-tile.blp:99 msgid "Manage Add-ons" msgstr "管理附加元件" #: src/bz-addons-dialog.c:90 src/bz-full-view.blp:482 #: src/bz-installed-tile.blp:117 src/bz-transaction-dialog.c:225 #: src/bz-transaction-view.blp:277 msgid "Remove" msgstr "移除" #: src/bz-addons-dialog.c:95 src/bz-favorites-tile.c:174 #: src/bz-full-view.blp:249 src/bz-full-view.blp:469 #: src/bz-transaction-dialog.c:202 src/bz-transaction-view.blp:225 msgid "Install" msgstr "安裝" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 #: src/bz-age-rating-dialog.c:726 src/bz-full-view.c:338 src/bz-full-view.c:345 msgid "Age Rating" msgstr "年齡分級" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "卡通暴力" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "未提供任何關於卡通暴力的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "幻想暴力" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "未提供任何關於幻想暴力的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "寫實暴力" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "未提供任何關於寫實暴力的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "含流血描寫的暴力內容" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "未提供任何關於流血場面的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "性暴力" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "未提供任何關於性暴力的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "酒精" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "未提供任何關於酒精相關內容的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "毒品" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "未提供任何關於非法藥物的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "菸草" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "未提供任何關於菸草製品的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "裸露" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "未提供任何關於裸露內容的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "性相關主題" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "未提供任何關於性相關描寫或暗示的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "粗俗用語" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "未提供任何關於粗俗用語的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "不當幽默" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "未提供任何關於不當幽默的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "歧視" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "未提供任何關於歧視性言語的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "廣告" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "未提供任何關於廣告內容的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "賭博" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "未提供任何關於賭博內容的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "付費購買" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "未提供任何關於金錢花費功能的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "使用者之間的文字聊天" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "未提供任何關於與其他使用者聊天方式的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "使用者之間的語音聊天" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "未提供任何關於與其他使用者語音交談方式的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 msgid "Contact Details" msgstr "聯絡資訊" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "未提供任何關於分享社群帳號或電子郵件地址的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "可識別個人身分的資訊" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "未提供任何關於與第三方分享使用者資訊的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "位置分享" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "未提供任何關於與其他使用者分享實際位置的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "性交易" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "未提供任何關於性交易相關內容的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "通姦" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "未提供任何關於通姦相關內容的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "性化角色" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "未提供任何關於性化角色的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 msgid "Desecration" msgstr "褻瀆" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "未提供任何關於褻瀆相關內容的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "人類遺骸" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "未提供任何關於可見人類遺骸的資訊" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "奴役" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "未提供任何關於奴役相關內容的資訊" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "不包含任何與毒品相關的內容" #: src/bz-age-rating-dialog.c:426 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "不包含髒話、粗俗用語或其他強烈語言" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "不包含廣告或金錢交易" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "不包含性內容或裸露描寫" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "不包含未受控管的通訊功能" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "不包含暴力內容" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "毒品" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "強烈語言" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "金錢" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "社交" #: src/bz-age-rating-dialog.c:479 msgid "Violence" msgstr "暴力" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:676 src/bz-full-view.c:328 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:701 msgctxt "Age rating" msgid "All" msgstr "所有年齡層" #: src/bz-age-rating-dialog.c:737 #, c-format msgid "%s has an unknown age rating" msgstr "%s 的年齡分級未知" #: src/bz-age-rating-dialog.c:743 #, c-format msgid "%s is suitable for everyone" msgstr "%s 適合所有年齡層" #: src/bz-age-rating-dialog.c:746 #, c-format msgid "%s is suitable for young children" msgstr "%s 適合幼童" #: src/bz-age-rating-dialog.c:749 #, c-format msgid "%s is suitable for children" msgstr "%s 適合兒童" #: src/bz-age-rating-dialog.c:752 #, c-format msgid "%s is suitable for teenagers" msgstr "%s 適合青少年" #: src/bz-age-rating-dialog.c:755 #, c-format msgid "%s is suitable for adults" msgstr "%s 適合成人" #: src/bz-age-rating-dialog.c:758 #, c-format msgid "%s is suitable for %s" msgstr "%s 適合 %s" #: src/bz-age-rating-dialog.c:852 #, c-format msgid "%s • %s" msgstr "%s • %s" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:43 #: src/bz-user-data-page.blp:15 src/bz-window.blp:483 msgid "Main Menu" msgstr "主選單" #: src/bz-all-apps-page.blp:17 src/bz-apps-page.blp:17 #: src/bz-user-data-page.blp:18 src/bz-window.blp:556 msgid "_Donate to Bazaar ❤️" msgstr "捐款給 Bazaar(&D) ❤️" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 #: src/bz-user-data-page.blp:19 msgid "_Refresh Content" msgstr "重新整理內容(&R)" #: src/bz-all-apps-page.blp:22 src/bz-apps-page.blp:22 #: src/bz-user-data-page.blp:22 src/bz-window.blp:563 msgid "_Preferences" msgstr "偏好設定(_P)" #: src/bz-all-apps-page.blp:23 src/bz-apps-page.blp:23 #: src/bz-user-data-page.blp:23 src/bz-window.blp:584 msgid "_Keyboard Shortcuts" msgstr "鍵盤快捷鍵(&K)" #: src/bz-all-apps-page.blp:24 src/bz-apps-page.blp:24 #: src/bz-user-data-page.blp:24 src/bz-window.blp:589 msgid "_About Bazaar" msgstr "關於 Bazaar(&A)" #: src/bz-all-apps-page.blp:28 src/bz-apps-page.blp:28 #: src/bz-user-data-page.blp:27 src/bz-window.blp:596 msgid "_Quit Bazaar" msgstr "退出 Bazaar(&Q)" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "系統資料夾 %s" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "家目錄子目錄 %s" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "主機系統資料夾" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "來自主機系統 /etc 中的系統設定" #: src/bz-app-permissions.c:169 #, c-format msgid "Desktop subfolder %s" msgstr "桌面子目錄 %s" #: src/bz-app-permissions.c:170 msgid "Desktop folder" msgstr "桌面資料夾" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "文件子目錄 %s" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "文件資料夾" #: src/bz-app-permissions.c:177 #, c-format msgid "Music subfolder %s" msgstr "音樂子目錄 %s" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "音樂資料夾" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "圖片子目錄 %s" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "圖片資料夾" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "公開資料夾子目錄 %s" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "公開資料夾" #: src/bz-app-permissions.c:189 #, c-format msgid "Videos subfolder %s" msgstr "影片子目錄 %s" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "影片資料夾" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "模版子目錄 %s" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "模版資料夾" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "使用者快取子目錄 %s" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "使用者快取資料夾" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "使用者設定子目錄 %s" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "使用者設定資料夾" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "使用者資料子目錄 %s" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "使用者資料資料夾" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "使用者執行環境子目錄 %s" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "使用者執行環境資料夾" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "對 %s 的檔案系統存取" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "未知的檔案系統目錄" #: src/bz-app-size-dialog.blp:29 src/bz-app-size-dialog.blp:55 msgid "Download Size" msgstr "下載大小" #: src/bz-app-size-dialog.blp:56 msgid "Amount to download from the internet" msgstr "從網際網路下載的大小" #: src/bz-app-size-dialog.blp:76 msgid "Installed Size" msgstr "安裝大小" #: src/bz-app-size-dialog.blp:77 msgid "Size on Disk" msgstr "磁碟上的大小" #: src/bz-app-size-dialog.blp:99 msgid "User Data Size" msgstr "使用者資料大小" #: src/bz-app-size-dialog.blp:100 msgid "Caches, settings, and other app data" msgstr "快取、設定以及其他應用程式資料" #. Translators: As in 'The app is installed'. #. Translators: . #: src/bz-app-tile.blp:86 src/bz-full-view.c:292 src/bz-installed-page.blp:86 #: src/bz-window.blp:299 msgid "Installed" msgstr "已安裝" #: src/bz-apps-page.blp:103 msgid "Show All" msgstr "顯示全部" #: src/bz-apps-page.c:232 #, c-format msgid "All \"%s\"" msgstr "全部 「%s」" #: src/bz-apps-page.c:506 src/bz-tag-list.c:109 #, c-format msgid "%d Applications" msgstr "%d 個應用程式" #: src/bz-application.c:677 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:678 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:709 msgid "translator-credits" msgstr "" "Shihfu Juan , 2025,2026\n" "Peter Dave Hello , 2025" #: src/bz-application.c:720 msgid "Special Thanks" msgstr "特別感謝" #: src/bz-application.c:778 msgid "Logged Out Successfully!" msgstr "已成功登出!" #: src/bz-application.c:905 msgid "Performing setup..." msgstr "正在進行設定..." #: src/bz-application.c:984 src/bz-application.c:993 msgid "Set Up Flathub" msgstr "設定 Flathub" #: src/bz-application.c:987 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Flathub 未在此系統上設定完成。若無法使用 Flathub,您將無法在 Bazaar 中瀏覽與" "安裝應用程式。\n" "\n" "您仍可使用 Bazaar 來瀏覽並移除已安裝的應用程式。" #: src/bz-application.c:992 src/bz-window.c:875 msgid "Later" msgstr "稍後" #: src/bz-application.c:1380 src/bz-application.c:3086 msgid "Synchronizing..." msgstr "同步中..." #: src/bz-application.c:1521 src/bz-application.c:3082 #, c-format msgid "Receiving %d entries..." msgstr "正在接收 %d 筆項目…" #: src/bz-application.c:1526 msgid "Checking for updates" msgstr "正在檢查更新" #: src/bz-application.c:3088 msgid "Indexing Data..." msgstr "正在索引資料…" #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:75 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:53 #: src/bz-installed-page.blp:63 src/bz-user-data-page.blp:52 #: src/bz-window.blp:183 msgid "Empty" msgstr "無內容" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "未經人工策選" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "此系統未提供平台審核資訊。你仍可在 Flathub 上瀏覽應用程式" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "瀏覽 Flathub" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "離線" #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 msgid "Browser" msgstr "瀏覽" #: src/bz-developer-badge.c:131 msgid "Developer information not available." msgstr "無法取得開發者資訊。" #: src/bz-developer-badge.c:137 src/bz-developer-badge.c:151 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "應用程式 ID %s 的所有權尚未經過驗證,可能為社群提供的套件。" #: src/bz-developer-badge.c:155 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "應用程式 ID %s 的所有權已由 Flathub 團隊人工驗證。" #: src/bz-developer-badge.c:161 #, c-format msgid "" "The ownership of the %1$s app ID has been verified by %2$s on " "%3$s." msgstr "應用程式 ID %1$s 的所有權已由 %2$s%3$s 驗證。" #: src/bz-developer-badge.c:168 #, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "應用程式 ID %1$s 的所有權已透過 %2$s 驗證。" #: src/bz-developer-badge.c:172 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "應用程式 ID %s 的所有權已完成驗證。" #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "選擇要使用的安裝項目" #: src/bz-entry-group-util.c:76 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "您已安裝此應用程式的多個版本。要繼續使用哪一個版本?" #: src/bz-entry-group-util.c:80 src/bz-transaction-dialog.c:201 #: src/bz-transaction-dialog.c:224 src/bz-transaction-dialog.c:269 #: src/bz-transaction-dialog.c:576 msgid "Cancel" msgstr "取消" #: src/bz-error.c:68 msgid "An Error Occurred" msgstr "發生錯誤" #: src/bz-error.c:89 msgid "Close" msgstr "關閉" #: src/bz-error.c:90 msgid "Copy and Close" msgstr "複製並關閉" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "登入至 Flathub 以管理最愛" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "登入" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "收藏數量" #: src/bz-favorites-tile.c:172 msgid "Uninstall" msgstr "解除安裝" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:75 msgid "Support this application" msgstr "支援此應用程式" #: src/bz-favorites-tile.blp:119 msgid "Remove from Favorites" msgstr "從收藏中移除" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:85 #: src/bz-window.blp:614 msgid "Favorites" msgstr "收藏" #: src/bz-favorites-page.blp:22 src/bz-full-view.blp:20 src/bz-window.blp:126 #: src/bz-window.blp:460 msgid "Toggle transaction sidebar" msgstr "切換作業側邊欄" #: src/bz-favorites-page.blp:46 src/bz-transaction-dialog.c:577 msgid "Install All" msgstr "安裝全部" #: src/bz-favorites-page.blp:63 src/bz-user-data-page.blp:41 msgid "Loading" msgstr "載入中" #: src/bz-favorites-page.blp:78 msgid "No Favorites" msgstr "沒有收藏" #: src/bz-favorites-page.blp:79 msgid "Applications you mark as favorite will appear here" msgstr "您所收藏的應用程式將會顯示在這裡" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "上一個" #: src/bz-featured-carousel.blp:53 msgid "Next" msgstr "下一個" #: src/bz-featured-tile.blp:88 msgid "App of the Day" msgstr "今日精選應用程式" #: src/bz-flathub-category.c:79 msgid "Audio & Video" msgstr "影音" #: src/bz-flathub-category.c:79 msgid "Media" msgstr "媒體" #: src/bz-flathub-category.c:79 msgid "More Audio & Video" msgstr "更多影音" #: src/bz-flathub-category.c:80 msgid "Developer Tools" msgstr "開發者工具" #: src/bz-flathub-category.c:80 msgid "Develop" msgstr "開發" #: src/bz-flathub-category.c:80 msgid "More Developer Tools" msgstr "更多開發者工具" #: src/bz-flathub-category.c:81 msgid "Education" msgstr "教育" #: src/bz-flathub-category.c:81 msgid "Learn" msgstr "學習" #: src/bz-flathub-category.c:81 msgid "More Education" msgstr "更多教育" #: src/bz-flathub-category.c:82 msgid "Gaming" msgstr "遊戲" #: src/bz-flathub-category.c:82 msgid "Play" msgstr "遊玩" #: src/bz-flathub-category.c:82 msgid "More Gaming" msgstr "更多遊戲" #: src/bz-flathub-category.c:83 msgid "Graphics & Photography" msgstr "圖像與攝影" #: src/bz-flathub-category.c:83 msgid "Create" msgstr "創作" #: src/bz-flathub-category.c:83 msgid "More Graphics & Photography" msgstr "更多圖像與攝影" #: src/bz-flathub-category.c:84 msgid "Networking" msgstr "網路" #: src/bz-flathub-category.c:84 msgid "Internet" msgstr "網際網路" #: src/bz-flathub-category.c:84 msgid "More Networking" msgstr "更多網路" #: src/bz-flathub-category.c:85 msgid "Productivity" msgstr "生產力" #: src/bz-flathub-category.c:85 msgid "Work" msgstr "工作" #: src/bz-flathub-category.c:85 msgid "More Productivity" msgstr "更多生產力" #: src/bz-flathub-category.c:86 msgid "Science" msgstr "科學" #: src/bz-flathub-category.c:86 msgid "More Science" msgstr "更多科學" #: src/bz-flathub-category.c:87 msgid "System" msgstr "系統" #: src/bz-flathub-category.c:87 msgid "More System" msgstr "更多系統" #: src/bz-flathub-category.c:88 msgid "Utilities" msgstr "工具程式" #: src/bz-flathub-category.c:88 msgid "Tools" msgstr "工具" #: src/bz-flathub-category.c:88 msgid "More Utilities" msgstr "更多工具程式" #: src/bz-flathub-category.c:89 src/bz-flathub-page.blp:119 #: src/bz-flathub-page.blp:152 msgid "Trending" msgstr "近期熱門" #: src/bz-flathub-category.c:89 msgid "More Trending" msgstr "更多近期熱門" #: src/bz-flathub-category.c:90 src/bz-flathub-page.blp:125 #: src/bz-flathub-page.blp:185 msgid "Popular" msgstr "最受歡迎" #: src/bz-flathub-category.c:90 msgid "More Popular" msgstr "更多最受歡迎" #: src/bz-flathub-category.c:91 src/bz-flathub-page.blp:174 msgid "Recently Added" msgstr "最近新增" #: src/bz-flathub-category.c:91 src/bz-flathub-page.blp:131 msgid "New" msgstr "最新" #: src/bz-flathub-category.c:91 msgid "More New" msgstr "更多最新" #: src/bz-flathub-category.c:92 src/bz-flathub-page.blp:163 msgid "Recently Updated" msgstr "最近更新" #: src/bz-flathub-category.c:92 src/bz-flathub-page.blp:137 msgid "Updated" msgstr "已更新" #: src/bz-flathub-category.c:92 msgid "More Updated" msgstr "更多更新" #: src/bz-flathub-category.c:93 msgid "Mobile" msgstr "行動裝置" #: src/bz-flathub-category.c:93 msgid "More Mobile" msgstr "更多行動裝置" #: src/bz-flathub-category.c:94 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:94 msgid "More Adwaita" msgstr "更多 Adwaita" #: src/bz-flathub-category.c:95 msgid "KDE Apps" msgstr "KDE 應用程式" #: src/bz-flathub-category.c:95 msgid "More KDE Apps" msgstr "更多 KDE 應用程式" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "尚未加入 Flathub" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "在您的任何 Flatpak 安裝中都找不到 Flathub 遠端" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "Flathub 回傳了錯誤" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "重新嘗試連線至 Flathub" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Flathub 無法使用" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "無法連線至 Flathub。您仍可管理並搜尋已安裝的應用程式。" #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "搜尋應用程式" #: src/bz-flathub-page.blp:270 msgid "On the Go" msgstr "隨時隨地" #: src/bz-flathub-page.blp:282 msgid "Apps for your Linux phones and tablets" msgstr "適用於您的 Linux 手機與平板的應用程式" #: src/bz-flathub-page.blp:293 src/bz-flathub-page.blp:328 msgid "More Mobile Apps" msgstr "更多行動應用程式" #: src/bz-flathub-page.blp:388 msgid "We​ ♥​ Games" msgstr "我們 ♥ 遊戲" #: src/bz-flathub-page.blp:401 msgid "Games and apps to run your favorite titles" msgstr "用來執行您最愛作品的遊戲與應用程式" #: src/bz-flathub-page.blp:435 msgid "More Games" msgstr "更多遊戲" #: src/bz-flatpak-entry.c:663 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Flathub 頁面" #: src/bz-flatpak-entry.c:684 msgctxt "Project URL Type" msgid "Project Website" msgstr "專案網址" #: src/bz-flatpak-entry.c:688 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "問題追蹤器" #: src/bz-flatpak-entry.c:692 msgctxt "Project URL Type" msgid "FAQ" msgstr "FAQ" #: src/bz-flatpak-entry.c:696 msgctxt "Project URL Type" msgid "Help" msgstr "幫助" #: src/bz-flatpak-entry.c:700 msgctxt "Project URL Type" msgid "Donate" msgstr "捐贈" #: src/bz-flatpak-entry.c:706 msgctxt "Project URL Type" msgid "Translate" msgstr "翻譯" #: src/bz-flatpak-entry.c:710 msgctxt "Project URL Type" msgid "Contact" msgstr "聯絡方式" #: src/bz-flatpak-entry.c:714 msgctxt "Project URL Type" msgid "Source Code" msgstr "原始碼" #: src/bz-flatpak-entry.c:720 msgctxt "Project URL Type" msgid "Contribute" msgstr "貢獻" #: src/bz-full-view.blp:57 src/bz-installed-page.blp:74 #: src/bz-installed-page.blp:78 msgid "No Results" msgstr "沒有結果" #: src/bz-full-view.blp:58 msgid "Try a different search query" msgstr "請嘗試不同的搜尋關鍵字" #: src/bz-full-view.blp:64 src/bz-window.blp:193 msgid "Content" msgstr "內容" #: src/bz-full-view.blp:210 msgid "Support" msgstr "贊助" #: src/bz-full-view.blp:233 src/bz-full-view.blp:493 msgid "Open" msgstr "打開" #: src/bz-full-view.blp:246 src/bz-full-view.blp:466 msgid "Download & Install Application" msgstr "下載並安裝應用程式" #: src/bz-full-view.blp:261 msgid "Uninstall Application" msgstr "移除應用程式" #: src/bz-full-view.blp:276 src/bz-full-view.blp:508 msgid "Install Other Version" msgstr "安裝其他版本" #: src/bz-full-view.blp:430 msgid "Downloads /mo" msgstr "每月下載次數" #: src/bz-full-view.blp:527 msgid "Stopped Receiving Core Updates" msgstr "已停止接收核心更新" #: src/bz-full-view.blp:541 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "此應用程式使用的執行環境已不再接收更新或安全修補,使用上可能存在安全風險。" #: src/bz-full-view.blp:630 msgid "Trash Data" msgstr "清除資料" #: src/bz-full-view.blp:772 msgid "Tags:" msgstr "標籤:" #: src/bz-full-view.c:235 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:242 #, c-format msgid "%.*fM" msgstr "%.*fM" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:249 #, c-format msgid "%.*fK" msgstr "%.*fK" #: src/bz-full-view.c:259 #, c-format msgid "%d downloads in the last 30 days" msgstr "在過去 30 天內有 %d 次下載" #. Translators: . #: src/bz-full-view.c:292 msgid "Download" msgstr "下載" #: src/bz-full-view.c:310 #, c-format msgid "Download size of %s" msgstr "下載 %s 的大小" #: src/bz-full-view.c:343 msgid "All Ages" msgstr "所有年齡層" #: src/bz-full-view.c:355 msgid "Age rating information unavailable" msgstr "年齡分級資訊未知" #: src/bz-full-view.c:360 msgid "Suitable for all ages" msgstr "適合所有年齡層" #: src/bz-full-view.c:362 #, c-format msgid "Suitable for ages %d and up" msgstr "適合 %d 歲以上" #: src/bz-full-view.c:395 src/bz-full-view.c:400 src/bz-full-view.c:428 #: src/bz-full-view.c:439 msgid "Unknown" msgstr "未知" #: src/bz-full-view.c:405 #, c-format msgid "Free software licensed under %s" msgstr "依 %s 授權的自由軟體" #: src/bz-full-view.c:410 msgid "Free software" msgstr "自由軟體" #: src/bz-full-view.c:413 msgid "Proprietary Software" msgstr "專有軟體" #: src/bz-full-view.c:416 #, c-format msgid "Special License: %s" msgstr "特殊授權:%s" #: src/bz-full-view.c:433 msgid "Free" msgstr "自由" #: src/bz-full-view.c:436 src/bz-license-dialog.c:190 msgid "Proprietary" msgstr "專有" #: src/bz-full-view.c:441 src/bz-license-dialog.c:192 msgid "Special License" msgstr "特殊授權" #: src/bz-full-view.c:461 msgid "Adaptive" msgstr "支援多裝置" #: src/bz-full-view.c:461 msgid "Desktop Only" msgstr "僅限桌面" #: src/bz-full-view.c:467 msgid "Works on desktop, tablets, and phones" msgstr "可在電腦、平板與手機上使用" #: src/bz-full-view.c:468 msgid "May not work on mobile devices" msgstr "可能無法在行動裝置上使用" #: src/bz-full-view.c:479 msgid "No URL" msgstr "沒有網址" #: src/bz-full-view.c:497 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "此應用程式具有 FLOSS 授權,這意味著其原始碼可供審查以確保安全性。" #: src/bz-full-view.c:498 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "此應用程式採用專有授權,表示其原始碼為私有,無法由第三方獨立審查。" #: src/bz-full-view.c:505 msgid "More Apps" msgstr "更多應用程式" #: src/bz-full-view.c:506 #, c-format msgid "More Apps by %s" msgstr "更多由 %s 製作的應用程式" #: src/bz-full-view.c:513 msgid "Other Apps by this Developer" msgstr "其他由此開發者製作的應用程式" #: src/bz-full-view.c:515 src/bz-full-view.c:715 #, c-format msgid "Other Apps by %s" msgstr "其他由 %s 製作的應用程式" #: src/bz-full-view.c:524 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "%s 並未安裝,但仍保留 %s 的資料。" #: src/bz-full-view.c:597 src/bz-full-view.c:614 msgid "N/A" msgstr "N/A" #: src/bz-full-view.c:604 src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "安全" #: src/bz-full-view.c:606 src/bz-full-view.c:608 msgid "Low Risk" msgstr "低風險" #: src/bz-full-view.c:610 msgid "Medium Risk" msgstr "中度風險" #: src/bz-full-view.c:612 msgid "High Risk" msgstr "高風險" #: src/bz-full-view.c:717 msgid "Other Apps" msgstr "其他應用程式" #: src/bz-full-view.c:719 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d 個應用程式" #: src/bz-full-view.c:1058 msgid "Show Less" msgstr "顯示更少" #: src/bz-full-view.c:1058 msgid "Show More" msgstr "顯示更多" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 msgid "Hardware Support" msgstr "硬體支援" #: src/bz-hardware-support-dialog.c:62 msgid "Keyboard support" msgstr "鍵盤支援" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "需要鍵盤" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "建議搭配鍵盤使用" #: src/bz-hardware-support-dialog.c:66 msgid "Supports keyboards" msgstr "支援鍵盤" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "鍵盤支援情況未知" #: src/bz-hardware-support-dialog.c:69 msgid "Mouse support" msgstr "滑鼠支援" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "需要滑鼠或指向性裝置" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "建議搭配滑鼠或指向性裝置" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "支援滑鼠或指向性裝置" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "滑鼠或指向性裝置支援情況未知" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "觸控螢幕支援" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "需要觸控螢幕" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "建議搭配觸控螢幕" #: src/bz-hardware-support-dialog.c:80 msgid "Supports touchscreens" msgstr "支援觸控螢幕" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "觸控螢幕支援情況未知" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "行動裝置支援" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "可在行動裝置上使用" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "在行動裝置上的使用體驗可能不佳" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "桌面電腦支援" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "在大螢幕上運作良好" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "%s 在特定硬體上可發揮最佳效能" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "%s 可在多數裝置上使用" #: src/bz-installed-page.blp:28 msgid "Search installed apps" msgstr "搜尋已安裝的應用程式" #: src/bz-installed-page.blp:67 msgid "No Apps Found" msgstr "找不到任何應用程式" #: src/bz-installed-page.c:157 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "在已安裝的應用程式清單中找不到符合「%s」的項目" #: src/bz-installed-tile.blp:61 src/bz-rich-app-tile.blp:136 msgid "Stopped Receiving Updates" msgstr "已停止接收更新" #: src/bz-license-dialog.blp:95 msgid "Get Involved" msgstr "參與貢獻" #: src/bz-license-dialog.c:184 msgid "Unknown License" msgstr "未知授權" #: src/bz-license-dialog.c:187 msgid "Community Built" msgstr "社群打造" #: src/bz-license-dialog.c:235 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "此應用程式由國際社群以開放方式開發。\n" "\n" "您可以參與貢獻,協助讓它變得更好。" #: src/bz-license-dialog.c:238 msgid "The license of this app is not known" msgstr "此應用程式的授權資訊未知" #: src/bz-license-dialog.c:244 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "此應用程式由國際社群以開放方式開發,並以 %s 授權釋出。\n" "\n" "您可以參與貢獻,協助讓它變得更好。" #: src/bz-license-dialog.c:252 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "此應用程式並非以開放方式開發,因此只有開發者知道其運作方式。它可能存在難以察" "覺的安全風險,且可能在缺乏監督的情況下變更。\n" "\n" "您可能可以,也可能無法對此應用程式做出貢獻。" #: src/bz-license-dialog.c:258 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "此應用程式採用特殊授權 %s 開發。\n" "\n" "您可能可以,也可能無法對此應用程式做出貢獻。" #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 msgid "Connect to Flathub" msgstr "連結至 Flathub" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "發生問題" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "將您的 Flathub 帳號連結至 Bazaar,以管理您加入收藏的應用程式。" #: src/bz-login-page.blp:108 msgid "Finish" msgstr "完成" #: src/bz-login-page.c:663 #, c-format msgid "Hello, %s!" msgstr "您好,%s!" #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "偏好設定" #: src/bz-preferences-dialog.blp:25 msgid "Network connection is metered — automatic store data sync is paused" msgstr "目前的網路連線為計量連線,已暫停商店資料的自動同步" #: src/bz-preferences-dialog.blp:26 src/bz-window.blp:494 msgid "Sync Manually" msgstr "手動同步" #: src/bz-preferences-dialog.blp:31 msgid "Content Filters" msgstr "內容篩選" #: src/bz-preferences-dialog.blp:34 msgid "Free Software Only" msgstr "僅顯示自由軟體" #: src/bz-preferences-dialog.blp:35 msgid "Hide proprietary applications when browsing and searching" msgstr "在瀏覽與搜尋時隱藏專有軟體應用程式" #: src/bz-preferences-dialog.blp:39 msgid "Flathub Results Only" msgstr "僅顯示 Flathub 結果" #: src/bz-preferences-dialog.blp:40 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "將搜尋與瀏覽結果限制為僅在 Flathub 上提供的應用程式" #: src/bz-preferences-dialog.blp:44 msgid "Verified Results Only" msgstr "僅顯示已驗證的結果" #: src/bz-preferences-dialog.blp:45 msgid "Hide results that are not verified on Flathub" msgstr "隱藏未經 Flathub 驗證的結果" #: src/bz-preferences-dialog.blp:49 msgid "Hide EOL Apps" msgstr "隱藏已終止支援的應用程式" #: src/bz-preferences-dialog.blp:50 msgid "Hide apps which are no longer supported by their developers" msgstr "隱藏已不再由開發者支援的應用程式" #: src/bz-preferences-dialog.blp:55 src/bz-window.blp:314 msgid "Search" msgstr "搜尋" #: src/bz-preferences-dialog.blp:58 msgid "Delay Search Results" msgstr "延遲顯示搜尋結果" #: src/bz-preferences-dialog.blp:59 msgid "Improve results performance by debouncing search terms" msgstr "透過延遲處理搜尋輸入以提升結果效能" #: src/bz-preferences-dialog.blp:64 msgid "Progress Bar" msgstr "進度列" #: src/bz-preferences-dialog.blp:65 msgid "Choose a theme for the progress bar!" msgstr "選擇進度列的主題!" #: src/bz-preferences-dialog.blp:89 msgid "Vertical Stripes" msgstr "垂直條紋" #: src/bz-preferences-dialog.blp:90 msgid "Display flag colors from top to bottom" msgstr "由上而下顯示旗幟配色" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "強調色" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "驕傲旗配色" #: src/bz-preferences-dialog.c:34 msgid "Lesbian Pride Colors" msgstr "女同志驕傲旗配色" #: src/bz-preferences-dialog.c:35 msgid "Male Homosexual Pride Colors" msgstr "男同志驕傲旗配色" #: src/bz-preferences-dialog.c:36 msgid "Transgender Pride Colors" msgstr "跨性別驕傲旗配色" #: src/bz-preferences-dialog.c:37 msgid "Nonbinary Pride Colors" msgstr "非二元性別驕傲旗配色" #: src/bz-preferences-dialog.c:38 msgid "Bisexual Pride Colors" msgstr "雙性戀驕傲旗配色" #: src/bz-preferences-dialog.c:39 msgid "Asexual Pride Colors" msgstr "無性戀驕傲旗配色" #: src/bz-preferences-dialog.c:40 msgid "Pansexual Pride Colors" msgstr "泛性戀驕傲旗配色" #: src/bz-preferences-dialog.c:41 msgid "Aromantic Pride Colors" msgstr "無浪漫傾向驕傲旗配色" #: src/bz-preferences-dialog.c:42 msgid "Genderfluid Pride Colors" msgstr "性別流動驕傲旗配色" #: src/bz-preferences-dialog.c:43 msgid "Polysexual Pride Colors" msgstr "多元性向驕傲旗配色" #: src/bz-preferences-dialog.c:44 msgid "Omnisexual Pride Colors" msgstr "全性向驕傲旗配色" #: src/bz-preferences-dialog.c:45 msgid "Aroace Pride Colors" msgstr "無浪漫/無性戀驕傲旗配色" #: src/bz-preferences-dialog.c:46 msgid "Agender Pride Colors" msgstr "無性別驕傲旗配色" #: src/bz-preferences-dialog.c:47 msgid "Genderqueer Pride Colors" msgstr "性別酷兒驕傲旗配色" #: src/bz-preferences-dialog.c:48 msgid "Intersex Pride Colors" msgstr "雙性人驕傲旗配色" #: src/bz-preferences-dialog.c:49 msgid "Demigender Pride Colors" msgstr "半性別驕傲旗配色" #: src/bz-preferences-dialog.c:50 msgid "Biromantic Pride Colors" msgstr "雙浪漫傾向驕傲旗配色" #: src/bz-preferences-dialog.c:51 msgid "Disability Pride Colors" msgstr "身心障礙驕傲旗配色" #: src/bz-preferences-dialog.c:52 msgid "Femboy Pride Colors" msgstr "女性氣質男性驕傲旗配色" #: src/bz-preferences-dialog.c:53 msgid "Neutrois Pride Colors" msgstr "中性性別驕傲旗配色" #: src/bz-releases-dialog.blp:5 src/bz-releases-list.blp:27 msgid "Version History" msgstr "版本紀錄" #: src/bz-releases-list.c:135 #, c-format msgid "Version %s" msgstr "版本 %s" #: src/bz-releases-list.c:173 msgid "No details for this release" msgstr "此版本沒有詳細資訊" #: src/bz-releases-list.c:185 msgid "Get More Information" msgstr "取得更多資訊" #: src/bz-rich-app-tile.blp:153 msgid "Get" msgstr "取得" #: src/bz-safety-calculator.c:82 msgid "Unknown Permissions" msgstr "未知的權限" #: src/bz-safety-calculator.c:83 msgid "Permissions are missing for this app." msgstr "此應用程式缺少權限資訊。" #: src/bz-safety-calculator.c:96 msgid "No Permissions" msgstr "無權限需求" #: src/bz-safety-calculator.c:97 msgid "App is fully sandboxed" msgstr "此應用程式已完全沙箱化" #: src/bz-safety-calculator.c:103 msgid "Network Access" msgstr "網路存取" #: src/bz-safety-calculator.c:104 msgid "Can access the internet" msgstr "可存取網際網路" #: src/bz-safety-calculator.c:106 msgid "No Network Access" msgstr "無網路存取" #: src/bz-safety-calculator.c:107 msgid "Cannot access the internet" msgstr "無法存取網際網路" #: src/bz-safety-calculator.c:112 msgid "User Device Access" msgstr "使用者裝置存取" #: src/bz-safety-calculator.c:113 msgid "Can access devices such as webcams or gaming controllers" msgstr "可存取如網路攝影機或遊戲控制器等裝置" #: src/bz-safety-calculator.c:115 msgid "No User Device Access" msgstr "無使用者裝置存取" #: src/bz-safety-calculator.c:116 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "無法存取如網路攝影機或遊戲控制器等裝置" #: src/bz-safety-calculator.c:121 msgid "Input Device Access" msgstr "輸入裝置存取" #: src/bz-safety-calculator.c:122 msgid "Can access input devices" msgstr "可存取輸入裝置" #: src/bz-safety-calculator.c:128 msgid "Microphone Access and Audio Playback" msgstr "麥克風存取與音訊播放" #: src/bz-safety-calculator.c:129 msgid "Can listen using microphones and play audio without asking permission" msgstr "可在未詢問權限的情況下使用麥克風收音並播放音訊" #: src/bz-safety-calculator.c:135 msgid "System Device Access" msgstr "系統裝置存取" #: src/bz-safety-calculator.c:136 msgid "Can access system devices which require elevated permissions" msgstr "可存取需要較高權限的系統裝置" #: src/bz-safety-calculator.c:142 msgid "Screen Contents Access" msgstr "螢幕內容存取" #: src/bz-safety-calculator.c:143 msgid "Can access the contents of the screen or other windows" msgstr "可存取螢幕或其他視窗的內容" #: src/bz-safety-calculator.c:149 msgid "Legacy Windowing System" msgstr "舊式視窗系統" #: src/bz-safety-calculator.c:150 msgid "Always uses a legacy windowing system (X11)" msgstr "一律使用舊式視窗系統(X11)" #: src/bz-safety-calculator.c:156 msgid "Arbitrary Permissions" msgstr "任意權限" #: src/bz-safety-calculator.c:157 msgid "Can acquire arbitrary permissions" msgstr "可取得任意權限" #: src/bz-safety-calculator.c:163 msgid "User Settings" msgstr "使用者設定" #: src/bz-safety-calculator.c:164 msgid "Can access and change user settings" msgstr "可存取並變更使用者設定" #: src/bz-safety-calculator.c:170 msgid "Full File System Read/Write Access" msgstr "完整檔案系統讀取/寫入權限" #: src/bz-safety-calculator.c:171 msgid "Can read and write all data on the file system" msgstr "可讀取與寫入檔案系統中的所有資料" #: src/bz-safety-calculator.c:178 msgid "Home Folder Read/Write Access" msgstr "家目錄讀取/寫入權限" #: src/bz-safety-calculator.c:179 msgid "Can read and write all data in your home directory" msgstr "可讀取與寫入您家目錄中的所有資料" #: src/bz-safety-calculator.c:186 msgid "Full File System Read Access" msgstr "完整檔案系統讀取權限" #: src/bz-safety-calculator.c:187 msgid "Can read all data on the file system" msgstr "可讀取檔案系統中的所有資料" #: src/bz-safety-calculator.c:195 msgid "Home Folder Read Access" msgstr "家目錄讀取權限" #: src/bz-safety-calculator.c:196 msgid "Can read all data in your home directory" msgstr "可讀取您家目錄中的所有資料" #: src/bz-safety-calculator.c:204 msgid "Download Folder Read/Write Access" msgstr "下載資料夾讀取/寫入權限" #: src/bz-safety-calculator.c:205 msgid "Can read and write all data in your downloads directory" msgstr "可讀取與寫入您下載資料夾中的所有資料" #: src/bz-safety-calculator.c:215 msgid "Download Folder Read Access" msgstr "下載資料夾讀取權限" #: src/bz-safety-calculator.c:216 msgid "Can read all data in your downloads directory" msgstr "可讀取您下載資料夾中的所有資料" #: src/bz-safety-calculator.c:229 msgid "Can read and write all data in the directory" msgstr "可讀取與寫入該目錄中的所有資料" #: src/bz-safety-calculator.c:243 msgid "Can read all data in the directory" msgstr "可讀取該目錄中的所有資料" #: src/bz-safety-calculator.c:258 msgid "No File System Access" msgstr "無檔案系統存取權限" #: src/bz-safety-calculator.c:259 msgid "Cannot access the file system at all" msgstr "完全無法存取檔案系統" #: src/bz-safety-calculator.c:266 msgid "Uses System Services" msgstr "使用系統服務" #: src/bz-safety-calculator.c:267 msgid "Can request data from non-portal system services" msgstr "可向非入口(non-portal)的系統服務請求資料" #: src/bz-safety-calculator.c:273 msgid "Uses Session Services" msgstr "使用工作階段服務" #: src/bz-safety-calculator.c:274 msgid "Can request data from non-portal session services" msgstr "可向非入口(non-portal)的工作階段服務請求資料" #: src/bz-safety-calculator.c:322 msgid "No Service Access" msgstr "無服務存取權限" #: src/bz-safety-calculator.c:323 msgid "Cannot access non-portal session or system services at all" msgstr "完全無法存取非入口(non-portal)的工作階段或系統服務" #: src/bz-safety-calculator.c:331 msgid "Verified App Developer" msgstr "已驗證的應用程式開發者" #: src/bz-safety-calculator.c:332 msgid "The developer of this app has been verified to be who they say they are" msgstr "此應用程式的開發者身分已通過驗證,確認與其所聲稱的身分相符" #: src/bz-safety-calculator.c:341 msgid "Proprietary Code" msgstr "專有程式碼" #: src/bz-safety-calculator.c:342 msgid "" "The source code is not public, so it cannot be independently audited and " "might be unsafe" msgstr "原始碼未公開,無法進行獨立稽核,可能存在安全風險" #: src/bz-safety-calculator.c:352 msgid "Auditable Code" msgstr "可稽核的程式碼" #: src/bz-safety-calculator.c:353 msgid "" "The source code is public and can be independently audited, which makes the " "app more likely to be safe" msgstr "原始碼已公開,且可進行獨立稽核,使此應用程式更可能是安全的" #: src/bz-safety-calculator.c:493 #, c-format msgid "Use the %s System Service" msgstr "使用 %s 系統服務" #: src/bz-safety-calculator.c:497 #, c-format msgid "Use the %s Session Service" msgstr "使用 %s 工作階段服務" #: src/bz-safety-calculator.c:501 #, c-format msgid "Use the %s Service" msgstr "使用 %s 服務" #: src/bz-safety-calculator.c:511 msgid "Can see the non-portal service" msgstr "可查看非入口(non-portal)服務" #: src/bz-safety-calculator.c:513 msgid "Can talk to the non-portal service" msgstr "可與非入口(non-portal)服務通訊" #: src/bz-safety-calculator.c:515 msgid "Can own the non-portal service" msgstr "可擁有非入口(non-portal)服務" #: src/bz-safety-calculator.c:530 msgid "Global Menu Integration" msgstr "全域選單整合" #: src/bz-safety-calculator.c:531 msgid "Can display its menus in a global menu bar" msgstr "可將選單顯示於全域選單列" #: src/bz-safety-calculator.c:536 msgid "KDE Settings Integration" msgstr "KDE 設定整合" #: src/bz-safety-calculator.c:537 msgid "Can detect when KDE desktop settings change" msgstr "可偵測 KDE 桌面設定的變更" #: src/bz-safety-calculator.c:542 msgid "KDE Global Settings" msgstr "KDE 全域設定" #: src/bz-safety-calculator.c:543 msgid "Can read KDE desktop preferences like fonts and colors" msgstr "可讀取 KDE 桌面偏好設定(如字型與色彩)" #: src/bz-safety-calculator.c:548 msgid "Secret Storage Service" msgstr "祕密儲存服務" #: src/bz-safety-calculator.c:549 msgid "Can store and retrieve its own passwords using the system keyring" msgstr "可使用系統鑰匙圈儲存並取回自身的密碼" #: src/bz-safety-calculator.c:554 msgid "Desktop Notifications Service" msgstr "桌面通知服務" #: src/bz-safety-calculator.c:555 msgid "Can send desktop notifications" msgstr "可傳送桌面通知" #: src/bz-safety-calculator.c:561 msgid "System Tray Integration" msgstr "系統匣整合" #: src/bz-safety-calculator.c:562 msgid "Can display an icon in the system tray" msgstr "可在系統匣中顯示圖示" #: src/bz-safety-calculator.c:567 msgid "KDE Connect Integration" msgstr "KDE Connect 整合" #: src/bz-safety-calculator.c:568 msgid "Can interact with devices paired via KDE Connect" msgstr "可與透過 KDE Connect 配對的裝置互動" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "安全性" #: src/bz-safety-dialog.blp:50 msgid "Details" msgstr "詳細資訊" #: src/bz-safety-dialog.blp:53 msgid "License" msgstr "授權" #: src/bz-safety-dialog.blp:62 msgid "App ID" msgstr "應用程式 ID" #: src/bz-safety-dialog.blp:71 msgid "SDK" msgstr "SDK" #: src/bz-safety-dialog.blp:98 msgid "" "This app uses an outdated version of the software platform (SDK) and might " "contain bugs or security vulnerabilities which will not be fixed." msgstr "" "此應用程式使用過時的軟體平台(SDK),可能包含不會再修復的錯誤或安全漏洞。" #: src/bz-safety-dialog.c:227 #, c-format msgid "%s is Safe" msgstr "%s 是安全的" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s has no Unsafe Permissions" msgstr "%s 沒有不安全的權限" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Probably Safe" msgstr "%s 可能是安全的" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Possibly Unsafe" msgstr "%s 可能不安全" #: src/bz-safety-dialog.c:247 #, c-format msgid "%s is Unsafe" msgstr "%s 不安全" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "螢幕截圖" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "上一張截圖" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "下一張截圖" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "複製圖片" #: src/bz-screenshot-page.blp:147 msgid "Reset View" msgstr "重設檢視" #: src/bz-screenshot-page.blp:158 msgid "Zoom Out" msgstr "縮小" #: src/bz-screenshot-page.blp:168 msgid "Zoom In" msgstr "放大" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "螢幕截圖輪播" #: src/bz-screenshots-carousel.blp:103 msgid "Open Screenshot Viewer" msgstr "開啟截圖檢視器" #: src/bz-search-widget.blp:57 msgid "Search Apps, Games, Software" msgstr "搜尋應用程式、遊戲與軟體" #: src/bz-search-widget.blp:96 msgid "Categories Unavailable" msgstr "分類無法使用" #: src/bz-search-widget.blp:97 msgid "Search for apps using the search bar above." msgstr "請使用上方的搜尋列搜尋應用程式。" #: src/bz-search-widget.blp:181 msgid "No Applications Found" msgstr "找不到任何應用程式" #: src/bz-search-widget.c:241 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "在 Flathub 中找不到符合「%s」的結果" #: src/bz-share-list.c:64 msgid "Copied!" msgstr "已複製!" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "複製連結" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "開啟連結" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "時間軸" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "安裝次數:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "全球" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:124 #, c-format msgid "%.2fM Total Installs" msgstr "總安裝次數 %.2fM" #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:127 #, c-format msgid "%.2fK Total Installs" msgstr "總安裝次數 %.2fK" #: src/bz-stats-dialog.c:129 #, c-format msgid "%'d Total Installs" msgstr "總安裝次數 %'d" #: src/bz-tag-list.c:96 msgid "No Results Found" msgstr "沒有找到結果" #: src/bz-tag-list.c:108 #, c-format msgid "Apps Tagged \"%s\"" msgstr "標記為「%s」的應用程式" #: src/bz-tag-list.c:124 msgid "Search failed" msgstr "搜尋失敗" #: src/bz-transaction-dialog.c:160 msgid "Keep Data" msgstr "保留資料" #: src/bz-transaction-dialog.c:161 msgid "Allow restoring settings and content" msgstr "允許還原設定與內容" #: src/bz-transaction-dialog.c:170 msgid "Delete Data" msgstr "刪除資料" #: src/bz-transaction-dialog.c:171 msgid "Permanently remove app data to save space" msgstr "永久移除應用程式資料以節省空間" #: src/bz-transaction-dialog.c:195 #, c-format msgid "Install %s?" msgstr "要安裝 %s 嗎?" #: src/bz-transaction-dialog.c:198 msgid "May install additional shared components" msgstr "可能會安裝額外的共用元件" #: src/bz-transaction-dialog.c:217 #, c-format msgid "Remove %s?" msgstr "要移除 %s 嗎?" #: src/bz-transaction-dialog.c:221 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "解除安裝後將無法再使用 %s。" #: src/bz-transaction-dialog.c:241 #, c-format msgid "“%s” is High Risk" msgstr "「%s」屬於高風險應用程式" #: src/bz-transaction-dialog.c:245 msgid "" "This app has full access to your system, including all your files, " "browser history, saved passwords, and more. It also has access to the " "internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "此應用程式對您的系統具有完整存取權限,包括所有檔案、瀏覽紀錄、已儲存的密碼" "等。同時也可存取網際網路,代表可能會將您的資料傳送給第三方。\n" "\n" "由於此應用程式為專有軟體,無法對其如何使用這些權限進行獨立審核。" #: src/bz-transaction-dialog.c:254 msgid "" "This app uses the legacy X11 windowing system, which allows it to record " "all keystrokes, capture screenshots, and monitor other applications. It " "also has access to the internet, meaning it could send your data to outside " "parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "此應用程式使用舊式的 X11 視窗系統,這使其能夠記錄所有鍵盤輸入、擷取螢幕畫" "面,並監控其他應用程式。同時也可存取網際網路,代表可能會將您的資料傳送給" "第三方。\n" "\n" "由於此應用程式為專有軟體,無法對其如何使用這些權限進行獨立審核。" #: src/bz-transaction-dialog.c:270 msgid "Install Anyway" msgstr "仍要安裝" #: src/bz-transaction-dialog.c:547 msgid "All apps are already installed" msgstr "所有應用程式皆已安裝" #: src/bz-transaction-dialog.c:549 msgid "OK" msgstr "OK" #: src/bz-transaction-dialog.c:565 #, c-format msgid "Install %u App?" msgid_plural "Install %u Apps?" msgstr[0] "要安裝 %u 個應用程式嗎?" #: src/bz-transaction-dialog.c:573 msgid "" "The following will be installed. Additional shared components may also be " "installed" msgstr "將會安裝以下項目,並且可能同時安裝額外的共用元件" #: src/bz-transaction-dialog.c:574 #, c-format msgid "%d addons will be installed." msgstr "將會安裝 %d 個附加元件。" #: src/bz-transaction-dialog.c:575 msgid "Additionally, addons will be installed." msgstr "此外,還會安裝附加元件。" #: src/bz-transaction-manager.c:1150 #, c-format msgid "Finished in %.02f seconds" msgstr "於 %.02f 秒完成" #: src/bz-transaction-view.blp:95 msgid "App Add-on" msgstr "應用程式附加元件" #: src/bz-transaction-view.blp:120 msgid "Runtime" msgstr "執行環境" #: src/bz-transaction-view.blp:146 src/bz-transaction-view.blp:172 msgid "Install Size" msgstr "安裝大小" #: src/bz-transaction-view.blp:187 src/bz-transaction-view.blp:238 #: src/bz-transaction-view.blp:264 src/bz-transaction.c:342 msgid "Pending" msgstr "等待中" #: src/bz-transaction-view.blp:199 msgid "Ongoing" msgstr "進行中" #: src/bz-transaction-view.blp:212 msgid "Finished" msgstr "已完成" #: src/bz-transaction-view.blp:251 msgid "Update" msgstr "更新" #: src/bz-transaction-view.c:135 #, c-format msgid "Transferred %s so far" msgstr "目前已傳輸 %s" #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "管理殘留的使用者資料" #: src/bz-user-data-page.blp:55 msgid "No User Data found" msgstr "找不到使用者資料" #: src/bz-user-data-page.blp:60 msgid "User Data" msgstr "使用者資料" #: src/bz-user-data-tile.c:144 #, c-format msgid "Trashed User Data for %s" msgstr "已將 %s 的使用者資料移至垃圾桶" #: src/bz-user-data-tile.blp:74 msgid "Trash User Data" msgstr "將使用者資料移至垃圾桶" #: src/bz-window.blp:107 msgid "Tasks" msgstr "工作" #: src/bz-window.blp:163 msgid "Stop Active Tasks" msgstr "停止進行中的工作" #: src/bz-window.blp:171 msgid "Clear History" msgstr "清除歷史紀錄" #: src/bz-window.blp:187 msgid "No Tasks Yet" msgstr "目前尚無工作" #: src/bz-window.blp:257 msgid "Refreshing Store Content" msgstr "正在重新整理商店內容" #: src/bz-window.blp:273 msgid "Curated" msgstr "精選" #: src/bz-window.blp:286 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:435 msgid "No background tasks!" msgstr "沒有背景工作!" #: src/bz-window.blp:493 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "您目前有網路連線,但正在檢視 Flathub 的快取版本" #: src/bz-window.blp:568 msgid "_Login with Flathub" msgstr "使用 Flathub 登入(_L)" #: src/bz-window.blp:574 msgid "_Manage Leftover User Data" msgstr "管理殘留的使用者資料(_M)" #: src/bz-window.blp:579 msgid "_Synchronize Remotes" msgstr "同步遠端(_S)" #: src/bz-window.blp:620 msgid "Log Out" msgstr "登出" #: src/bz-window.c:440 #, c-format msgid "%d Update Available" msgid_plural "%d Updates Available" msgstr[0] "有 %d 項更新可用" #: src/bz-window.c:734 msgid "You can't remove Bazaar from Bazaar!" msgstr "您無法在 Bazaar 中移除 Bazaar 本身!" #: src/bz-window.c:871 msgid "Updates Are Available" msgstr "有可用的更新" #: src/bz-window.c:872 msgid "" "The following applications are eligible for updates. Would you like to " "install them?" msgstr "下列應用程式可更新。是否要安裝?" #: src/bz-window.c:873 #, c-format msgid "" "%d runtimes and/or addons are eligible for updates. Would you like to " "install them?" msgstr "%d 個執行環境與/或附加元件可更新。是否要安裝?" #: src/bz-window.c:874 #, c-format msgid "Additionally, %d runtimes and/or addons will be updated." msgstr "此外,還有 %d 個執行環境與/或附加元件將會更新。" #: src/bz-window.c:876 msgid "Update Now" msgstr "現在更新" #: src/bz-window.c:891 msgid "" "The ability to inspect and install local .flatpak bundle files is coming " "soon! In the meantime, try running\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "on the command line." msgstr "" "檢視與安裝本機 .flatpak 封裝檔的功能即將推出!在此之前,請於命令列執行下列指" "令:\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "。" #: src/bz-window.c:1030 src/bz-window.c:1080 msgid "Can't do that right now!" msgstr "目前無法執行此動作!" #: src/bz-window.c:1155 msgid "Resume Current Tasks" msgstr "繼續目前的工作" #: src/bz-window.c:1161 msgid "Pause Current Tasks" msgstr "暫停目前的工作" #: src/bz-world-map.c:587 msgid "Downloads" msgstr "下載次數" #: src/gtk/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "一般" #: src/gtk/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "開啟搜尋對話方塊" #: src/gtk/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Preferences" msgstr "打開偏好設定" #: src/gtk/shortcuts-dialog.blp:19 msgctxt "shortcut window" msgid "Synchronize Remotes" msgstr "同步遠端" #: src/gtk/shortcuts-dialog.blp:24 msgctxt "shortcut window" msgid "Toggle Transaction Manager" msgstr "切換作業管理器" #: src/gtk/shortcuts-dialog.blp:29 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "顯示快捷鍵" #: src/gtk/shortcuts-dialog.blp:34 msgctxt "shortcut window" msgid "Quit" msgstr "離開" #~ msgid "Show Animated Background" #~ msgstr "顯示動畫背景" #~ msgid "Whether to show the animated icon background on the home page" #~ msgstr "是否在首頁顯示動態圖示背景" #~ msgid "Calligraphy application page" #~ msgstr "書法應用程式頁面" #~ msgid "Download graph for Blender" #~ msgstr "Blender 的下載圖表" #~ msgid "This flatpak is verified by the original developers of the software." #~ msgstr "此 Flatpak 已由該軟體原始開發者驗證。" #~ msgid "" #~ "This functionality is currently disabled. It is recommended you download " #~ "and install Flatseal to manage app permissions." #~ msgstr "此功能目前停用。建議下載並安裝 Flatseal 以管理應用程式權限。" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Ahmed Najmawi" #~ msgstr "Ahmed Najmawi" #~ msgctxt "About Dialog Translator Credit" #~ msgid "AtomHare" #~ msgstr "AtomHare" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Azenyr" #~ msgstr "Azenyr" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Goudarz Jafari" #~ msgstr "Goudarz Jafari" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Jill Fiore (Lumaeris)" #~ msgstr "Jill Fiore (Lumaeris)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "KiKaraage" #~ msgstr "KiKaraage" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Lucosec" #~ msgstr "Lucosec" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Léane GRASSER" #~ msgstr "Léane GRASSER" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Marcel Mrówka (Microwave)" #~ msgstr "Marcel Mrówka (Microwave)" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Pietro F." #~ msgstr "Pietro F." #~ msgctxt "About Dialog Translator Credit" #~ msgid "Shihfu Juan" #~ msgstr "Shihfu Juan" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Shinsei" #~ msgstr "Shinsei" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Vlastimil Dědek" #~ msgstr "Vlastimil Dědek" #~ msgctxt "About Dialog Translator Credit" #~ msgid "asen23" #~ msgstr "asen23" #~ msgctxt "About Dialog Translator Credit" #~ msgid "renner" #~ msgstr "renner" #~ msgctxt "About Dialog Translator Credit" #~ msgid "robotta" #~ msgstr "robotta" #~ msgctxt "About Dialog Translator Credit" #~ msgid "Peter Dave Hello" #~ msgstr "Peter Dave Hello" #~ msgid "Constructing Flatpak instance..." #~ msgstr "正在建立 Flatpak 執行個體..." #~ msgid "Reusing last Flatpak instance..." #~ msgstr "正在沿用上一個 Flatpak 執行個體..." #~ msgid "Flathub is not registered on this system" #~ msgstr "此系統未註冊 Flathub" #~ msgid "" #~ "Would you like to add Flathub as a remote? If you decline, the Flathub " #~ "page will not be available. You can change this later." #~ msgstr "" #~ "是否要加入 Flathub 作為遠端?若選擇略過,將無法使用 Flathub 頁面。之後仍可" #~ "變更。" #~ msgid "Add Flathub" #~ msgstr "加入 Flathub" #, c-format #~ msgid "" #~ "Beginning remote entry retrieval while referencing %d blocklist(s)..." #~ msgstr "開始擷取遠端項目,並參考 %d 份封鎖清單..." #, c-format #~ msgid "Received %'d entries out of %'d (%0.1f seconds elapsed)" #~ msgstr "已接收 %'d 個項目,共 %'d 個(耗時 %0.1f 秒)" #, c-format #~ msgid "Waiting for background indexing tasks to catch up..." #~ msgstr "正在等待背景索引作業追上進度..." #, c-format #~ msgid "Completed initialization in %0.2f seconds" #~ msgstr "初始化完成(%0.2f 秒)" #~ msgid "" #~ "Bazaar was not provided a curated content configuration. Contact your " #~ "operating system's support channels for assistance." #~ msgstr "未提供 Bazaar 的精選內容設定。請聯絡作業系統的支援管道以取得協助。" #~ msgid "Apps Of The Week" #~ msgstr "本週精選應用程式" #~ msgid "Run this application" #~ msgstr "執行應用程式" #~ msgid "" #~ "The number of downloads in the last 30 days. Click to view this " #~ "application's download statistics." #~ msgstr "過去 30 天的下載次數。請點選以檢視此應用程式的下載統計資料。" #~ msgid "VCS Forge Star Count" #~ msgstr "VCS 平台星星數" #~ msgid "Remote repo name" #~ msgstr "遠端儲存庫名稱" #, c-format #~ msgid "Released %x" #~ msgstr "於 %x 釋出" #~ msgid "No Flatpaks Installed" #~ msgstr "未安裝任何 Flatpak" #~ msgid "How the application looks" #~ msgstr "應用程式的外觀" #~ msgid "Appearance" #~ msgstr "外觀" #~ msgid "Show animated background" #~ msgstr "顯示動畫背景" #~ msgid "Type to filter" #~ msgstr "輸入以篩選" #~ msgid "Exclude results with proprietary licenses" #~ msgstr "排除具有專有授權的結果" #~ msgid "Advanced" #~ msgstr "進階" #~ msgid "Debounce input to prevent instant replies" #~ msgstr "對輸入套用去抖動,避免立即回應" #~ msgid "Share" #~ msgstr "分享" #~ msgid "Open this link externally" #~ msgstr "在外部開啟此連結" #~ msgid "Downloads Over Time" #~ msgstr "下載趨勢" #~ msgid "Minimize Lower Bound" #~ msgstr "降低下限" #~ msgid "Maximize Upper Bound" #~ msgstr "提高上限" #~ msgid "Installing" #~ msgstr "正在安裝" #~ msgid "Updating" #~ msgstr "正在更新" #~ msgid "Removing" #~ msgstr "正在移除" #~ msgid "Transactions Will Appear Here" #~ msgstr "作業佇列將顯示在這裡" #~ msgid "Halt the execution of transactions" #~ msgstr "停止執行中的作業" #~ msgid "Clear all finished transactions" #~ msgstr "清除所有已完成的作業" #~ msgid "Browse" #~ msgstr "瀏覽" #~ msgid "App View" #~ msgstr "應用程式檢視" #~ msgid "Go Back" #~ msgstr "上一頁" #~ msgid "View curated applications" #~ msgstr "檢視精選應用程式" #~ msgid "View the latest on Flathub" #~ msgstr "檢視 Flathub 最新內容" #~ msgid "Up to date!" #~ msgstr "已是最新!" #~ msgid "Confirm Action" #~ msgstr "確認動作" #, c-format #~ msgid "" #~ "You are about to remove the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "即將移除下列 Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "是否確定?" #, c-format #~ msgid "" #~ "You are about to install the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "即將安裝下列 Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "是否確定?" #~ msgid "Resume the execution of transactions" #~ msgstr "恢復執行中的作業" #~ msgid "Pause the execution of transactions" #~ msgstr "暫停執行中的作業" #~ msgctxt "shortcut window" #~ msgid "Refresh" #~ msgstr "重新整理" bazaar-orig-v0.7.14/po/ga.po0000664000175000017500000022164215166123241014514 0ustar hasanhasan# Irish translations for bazaar package. # Copyright (C) 2026 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2026. # # Aindriú Mac Giolla Eoin , 2026. #: src/bz-installed-page.blp:68 msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-01-11 20:42+0000\n" "PO-Revision-Date: 2026-01-12 18:32+0000\n" "Last-Translator: Aindriú Mac Giolla Eoin \n" "Language-Team: Irish \n" "Language: ga\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2;\n" "X-Generator: Weblate 5.15.1\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:5 #: src/bz-window.blp:233 msgid "Bazaar" msgstr "Bazaar" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "" "Bogearraí flatpak a chur leis, a bhaint nó a nuashonrú ar an ríomhaire seo" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;Córas;Bainisteoir Pacáistí;Faigh Amach;Flatpak;Bogearraí;Stór;" #: data/io.github.kolunmi.Bazaar.desktop.in:15 msgid "New Window" msgstr "Fuinneog Nua" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and install applications" msgstr "Aipeanna a aimsiú agus a shuiteáil" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "" "A new app store for Linux with a focus on discovering and installing " "applications and addons from Flatpak remotes, particularly Flathub." msgstr "" "Siopa aipeanna nua do Linux le fócas ar fheidhmchláir agus breiseáin a " "aimsiú agus a shuiteáil ó chianrialtáin Flatpak, go háirithe Flathub." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:14 msgid "" "It emphasizes supporting the developers who make the Linux desktop possible. " "Bazaar features a \"curated\" tab that can be configured by distributors to " "allow for a more localized experience." msgstr "" "Leagann sé béim ar thacaíocht a thabhairt do na forbróirí a chuireann ar " "chumas an deasc Linux a bheith indéanta. Tá cluaisín \"coimeádta\" ar fáil i " "Bazaar ar féidir le dáileoirí é a chumrú chun eispéireas níos logánta a " "cheadú." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:29 src/bz-application.c:697 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:54 msgid "The home page displaying Flathub apps" msgstr "An leathanach baile a thaispeánann aipeanna Flathub" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:58 msgid "Nucleus app page" msgstr "Leathanach aip Nucleus" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:62 msgid "Search page" msgstr "Leathanach cuardaigh" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:66 msgid "Category page" msgstr "Leathanach catagóire" #: src/bz-addons-dialog.blp:14 src/bz-full-view.blp:694 #: src/bz-installed-tile.blp:99 msgid "Manage Add-ons" msgstr "Bainistigh Breiseáin" #: src/bz-addons-dialog.c:90 src/bz-full-view.blp:482 #: src/bz-installed-tile.blp:117 src/bz-transaction-dialog.c:224 #: src/bz-transaction-view.blp:277 msgid "Remove" msgstr "Bain" #: src/bz-addons-dialog.c:95 src/bz-favorites-tile.c:166 #: src/bz-full-view.blp:249 src/bz-full-view.blp:469 #: src/bz-transaction-dialog.c:201 src/bz-transaction-view.blp:225 msgid "Install" msgstr "Suiteáil" #: src/bz-age-rating-dialog.blp:7 src/bz-age-rating-dialog.blp:31 #: src/bz-age-rating-dialog.c:726 src/bz-full-view.c:409 src/bz-full-view.c:416 msgid "Age Rating" msgstr "Rátáil Aois" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:88 msgid "Cartoon Violence" msgstr "Foréigean Cartúin" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:90 msgid "No information regarding cartoon violence" msgstr "Gan aon eolas maidir le foréigean cartúin" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:94 msgid "Fantasy Violence" msgstr "Foréigean Fantaisíochta" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:96 msgid "No information regarding fantasy violence" msgstr "Gan aon eolas maidir le foréigean fantaisíochta" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:100 msgid "Realistic Violence" msgstr "Foréigean Réalaíoch" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:102 msgid "No information regarding realistic violence" msgstr "Gan aon fhaisnéis maidir le foréigean réalaíoch" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:106 msgid "Violence Depicting Bloodshed" msgstr "Foréigean a léiríonn fuildhoirteadh" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:108 msgid "No information regarding bloodshed" msgstr "Gan aon eolas faoi fhuildhoirteadh" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:112 msgid "Sexual Violence" msgstr "Foréigean Gnéasach" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:114 msgid "No information regarding sexual violence" msgstr "Gan aon eolas maidir le foréigean gnéasach" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:118 msgid "Alcohol" msgstr "Alcól" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:120 msgid "No information regarding references to alcohol" msgstr "Gan aon fhaisnéis maidir le tagairtí d'alcól" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:124 msgid "Narcotics" msgstr "Támhshuanacha" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:126 msgid "No information regarding references to illicit drugs" msgstr "Gan aon fhaisnéis maidir le tagairtí do dhrugaí mídhleathacha" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:130 msgid "Tobacco" msgstr "Tobac" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:132 msgid "No information regarding references to tobacco products" msgstr "Gan aon fhaisnéis maidir le tagairtí do tháirgí tobac" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:136 src/bz-age-rating-dialog.c:475 msgid "Nudity" msgstr "Nochtacht" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:138 msgid "No information regarding nudity of any sort" msgstr "Gan aon fhaisnéis maidir le nochtas de chineál ar bith" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:142 msgid "Sexual Themes" msgstr "Téamaí Gnéis" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:144 msgid "No information regarding references to or depictions of sexual nature" msgstr "Gan aon fhaisnéis maidir le tagairtí nó léirithe de chineál gnéasach" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:148 msgid "Profanity" msgstr "Maslaí" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:150 msgid "No information regarding profanity of any kind" msgstr "Gan aon fhaisnéis maidir le maslaí de chineál ar bith" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:154 msgid "Inappropriate Humor" msgstr "Greann Míchuí" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:156 msgid "No information regarding inappropriate humor" msgstr "Gan aon eolas maidir le greann míchuí" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:160 msgid "Discrimination" msgstr "Idirdhealú" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:162 msgid "No information regarding discriminatory language of any kind" msgstr "Gan aon fhaisnéis maidir le teanga idirdhealaitheach d'aon chineál" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:166 msgid "Advertising" msgstr "Fógraíocht" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:168 msgid "No information regarding advertising of any kind" msgstr "Gan aon fhaisnéis maidir le fógraíocht d'aon chineál" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:172 msgid "Gambling" msgstr "Cearrbhachas" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:174 msgid "No information regarding gambling of any kind" msgstr "Gan aon fhaisnéis maidir le cearrbhachas d'aon chineál" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:178 msgid "Purchasing" msgstr "Ceannach" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:180 msgid "No information regarding the ability to spend money" msgstr "Gan aon eolas maidir leis an gcumas airgead a chaitheamh" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:184 msgid "Chat Between Users" msgstr "Comhrá idir Úsáideoirí" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:186 msgid "No information regarding ways to chat with other users" msgstr "" "Gan aon eolas maidir le bealaí chun comhrá a dhéanamh le húsáideoirí eile" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:190 msgid "Audio Chat Between Users" msgstr "Comhrá Fuaime Idir Úsáideoirí" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:192 msgid "No information regarding ways to talk with other users" msgstr "Gan aon eolas maidir le bealaí chun labhairt le húsáideoirí eile" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:196 msgid "Contact Details" msgstr "Sonraí Teagmhála" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:198 msgid "" "No information regarding sharing of social network usernames or email " "addresses" msgstr "" "Gan aon fhaisnéis maidir le hainmneacha úsáideora ná seoltaí ríomhphoist " "líonraí sóisialta a roinnt" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:202 msgid "Identifying Information" msgstr "Faisnéis Aitheantais" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:204 msgid "No information regarding sharing of user information with third parties" msgstr "" "Gan aon fhaisnéis maidir le faisnéis úsáideora a roinnt le tríú páirtithe" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:208 msgid "Location Sharing" msgstr "Comhroinnt Suímh" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:210 msgid "No information regarding sharing of physical location with other users" msgstr "" "Gan aon fhaisnéis maidir le suíomh fisiceach a roinnt le húsáideoirí eile" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:214 msgid "Prostitution" msgstr "Striapachas" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:216 msgid "No information regarding references to prostitution" msgstr "Gan aon fhaisnéis maidir le tagairtí do striapachas" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:220 msgid "Adultery" msgstr "Adaltranas" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:222 msgid "No information regarding references to adultery" msgstr "Gan aon fhaisnéis maidir le tagairtí d'adhaltranas" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:226 msgid "Sexualized Characters" msgstr "Carachtair Ghnéasaithe" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:228 msgid "No information regarding sexualized characters" msgstr "Gan aon fhaisnéis maidir le carachtair ghnéasaithe" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:232 msgid "Desecration" msgstr "Mí-naomhú" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:234 msgid "No information regarding references to desecration" msgstr "Gan aon fhaisnéis maidir le tagairtí do dhí-sheacracht" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:238 msgid "Human Remains" msgstr "Iarsmaí Daonna" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:240 msgid "No information regarding visible dead human remains" msgstr "Gan aon fhaisnéis maidir le hiarsmaí daonna marbha infheicthe" #. TRANSLATORS: content rating title, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:244 msgid "Slavery" msgstr "Sclábhaíocht" #. TRANSLATORS: content rating description, see https://hughsie.github.io/oars/ #: src/bz-age-rating-dialog.c:246 msgid "No information regarding references to slavery" msgstr "Gan aon fhaisnéis maidir le tagairtí don sclábhaíocht" #: src/bz-age-rating-dialog.c:424 msgid "Does not include references to drugs" msgstr "Ní áirítear tagairtí do dhrugaí" #: src/bz-age-rating-dialog.c:426 msgid "" "Does not include swearing, profanity, and other kinds of strong language" msgstr "Ní chuimsíonn sé mionnú, maslaí, agus cineálacha eile teanga ghéar" #: src/bz-age-rating-dialog.c:428 msgid "Does not include ads or monetary transactions" msgstr "Ní áirítear fógraí ná idirbhearta airgid" #: src/bz-age-rating-dialog.c:430 msgid "Does not include sex or nudity" msgstr "Ní chuimsíonn sé gnéas ná nochtas" #: src/bz-age-rating-dialog.c:432 msgid "Does not include uncontrolled chat functionality" msgstr "Ní chuimsíonn sé feidhmiúlacht comhrá neamhrialaithe" #: src/bz-age-rating-dialog.c:434 msgid "Does not include violence" msgstr "Ní áirítear foréigean" #: src/bz-age-rating-dialog.c:469 msgid "Drugs" msgstr "Drugaí" #: src/bz-age-rating-dialog.c:471 msgid "Strong Language" msgstr "Teanga Láidir" #: src/bz-age-rating-dialog.c:473 msgid "Money" msgstr "Airgead" #: src/bz-age-rating-dialog.c:477 msgid "Social" msgstr "Sóisialta" #: src/bz-age-rating-dialog.c:479 msgid "Violence" msgstr "Foréigean" #. Translators: Age rating format, e.g. "12+" for ages 12 and up #: src/bz-age-rating-dialog.c:676 src/bz-full-view.c:399 #, c-format msgid "%d+" msgstr "%d+" #: src/bz-age-rating-dialog.c:701 msgctxt "Age rating" msgid "All" msgstr "Gach" #: src/bz-age-rating-dialog.c:737 #, c-format msgid "%s has an unknown age rating" msgstr "Tá rátáil aoise anaithnid ag %s" #: src/bz-age-rating-dialog.c:743 #, c-format msgid "%s is suitable for everyone" msgstr "Tá %s oiriúnach do gach duine" #: src/bz-age-rating-dialog.c:746 #, c-format msgid "%s is suitable for young children" msgstr "Tá %s oiriúnach do leanaí óga" #: src/bz-age-rating-dialog.c:749 #, c-format msgid "%s is suitable for children" msgstr "Tá %s oiriúnach do pháistí" #: src/bz-age-rating-dialog.c:752 #, c-format msgid "%s is suitable for teenagers" msgstr "Tá %s oiriúnach do dhéagóirí" #: src/bz-age-rating-dialog.c:755 #, c-format msgid "%s is suitable for adults" msgstr "Tá %s oiriúnach do dhaoine fásta" #: src/bz-age-rating-dialog.c:758 #, c-format msgid "%s is suitable for %s" msgstr "Tá %s oiriúnach do %s" #: src/bz-age-rating-dialog.c:849 #, c-format msgid "%s • %s" msgstr "%s • %s" #: src/bz-all-apps-page.blp:13 src/bz-apps-page.blp:14 src/bz-full-view.blp:43 #: src/bz-user-data-page.blp:15 src/bz-window.blp:480 msgid "Main Menu" msgstr "Príomh-Roghchlár" #: src/bz-all-apps-page.blp:17 src/bz-apps-page.blp:17 #: src/bz-user-data-page.blp:18 src/bz-window.blp:553 msgid "_Donate to Bazaar ❤️" msgstr "_Tabhair síntiús do Bazaar ❤️" #: src/bz-all-apps-page.blp:18 src/bz-apps-page.blp:18 #: src/bz-user-data-page.blp:19 msgid "_Refresh Content" msgstr "_Athnuachan Ábhar" #: src/bz-all-apps-page.blp:22 src/bz-apps-page.blp:22 #: src/bz-user-data-page.blp:22 src/bz-window.blp:560 msgid "_Preferences" msgstr "_Sainroghanna" #: src/bz-all-apps-page.blp:23 src/bz-apps-page.blp:23 #: src/bz-user-data-page.blp:23 src/bz-window.blp:581 msgid "_Keyboard Shortcuts" msgstr "_Aicearraí Méarchláir" #: src/bz-all-apps-page.blp:24 src/bz-apps-page.blp:24 #: src/bz-user-data-page.blp:24 src/bz-window.blp:586 msgid "_About Bazaar" msgstr "_Maidir le Bazaar" #: src/bz-all-apps-page.blp:28 src/bz-apps-page.blp:28 #: src/bz-user-data-page.blp:27 src/bz-window.blp:593 msgid "_Quit Bazaar" msgstr "_Scoir den Bazaar" #: src/bz-app-permissions.c:160 #, c-format msgid "System folder %s" msgstr "Fillteán córais %s" #: src/bz-app-permissions.c:162 #, c-format msgid "Home subfolder %s" msgstr "Fo-fhillteán baile %s" #: src/bz-app-permissions.c:164 msgid "Host system folders" msgstr "Fillteáin chórais óstach" #: src/bz-app-permissions.c:166 msgid "Host system configuration from /etc" msgstr "Cumraíocht an chórais óstach ó /etc" #: src/bz-app-permissions.c:169 #, c-format msgid "Desktop subfolder %s" msgstr "Fo-fhillteán deisce %s" #: src/bz-app-permissions.c:170 msgid "Desktop folder" msgstr "Fillteán deisce" #: src/bz-app-permissions.c:173 #, c-format msgid "Documents subfolder %s" msgstr "Fo-fhillteán doiciméad %s" #: src/bz-app-permissions.c:174 msgid "Documents folder" msgstr "Fillteán na ndoiciméad" #: src/bz-app-permissions.c:177 #, c-format msgid "Music subfolder %s" msgstr "Fo-fhillteán ceoil %s" #: src/bz-app-permissions.c:178 msgid "Music folder" msgstr "Fillteán ceoil" #: src/bz-app-permissions.c:181 #, c-format msgid "Pictures subfolder %s" msgstr "Fo-fhillteán pictiúr %s" #: src/bz-app-permissions.c:182 msgid "Pictures folder" msgstr "Fillteán pictiúr" #: src/bz-app-permissions.c:185 #, c-format msgid "Public Share subfolder %s" msgstr "Fo-fhillteán Comhroinnte Poiblí %s" #: src/bz-app-permissions.c:186 msgid "Public Share folder" msgstr "Fillteán Comhroinnte Poiblí" #: src/bz-app-permissions.c:189 #, c-format msgid "Videos subfolder %s" msgstr "Fo-fhillteán físeáin %s" #: src/bz-app-permissions.c:190 msgid "Videos folder" msgstr "Fillteán físeáin" #: src/bz-app-permissions.c:193 #, c-format msgid "Templates subfolder %s" msgstr "Fo-fhillteán teimpléid %s" #: src/bz-app-permissions.c:194 msgid "Templates folder" msgstr "Fillteán teimpléid" #: src/bz-app-permissions.c:197 #, c-format msgid "User cache subfolder %s" msgstr "Fo-fhillteán taisce úsáideora %s" #: src/bz-app-permissions.c:198 msgid "User cache folder" msgstr "Fillteán taisce úsáideora" #: src/bz-app-permissions.c:201 #, c-format msgid "User configuration subfolder %s" msgstr "Fo-fhillteán cumraíochta úsáideora %s" #: src/bz-app-permissions.c:202 msgid "User configuration folder" msgstr "Fillteán cumraíochta úsáideora" #: src/bz-app-permissions.c:205 #, c-format msgid "User data subfolder %s" msgstr "Fo-fhillteán sonraí úsáideora %s" #: src/bz-app-permissions.c:206 msgid "User data folder" msgstr "Fillteán sonraí úsáideora" #: src/bz-app-permissions.c:209 #, c-format msgid "User runtime subfolder %s" msgstr "Fo-fhillteán ama rite úsáideora %s" #: src/bz-app-permissions.c:210 msgid "User runtime folder" msgstr "Fillteán rith-ama úsáideora" #: src/bz-app-permissions.c:212 #, c-format msgid "Filesystem access to %s" msgstr "Rochtain ar chóras comhad ar %s" #: src/bz-app-permissions.c:214 msgid "Unknown filesystem path" msgstr "Cosán anaithnid córas comhad" #: src/bz-app-size-dialog.blp:29 src/bz-app-size-dialog.blp:55 msgid "Download Size" msgstr "Méid Íoslódála" #: src/bz-app-size-dialog.blp:56 msgid "Amount to download from the internet" msgstr "Méid le híoslódáil ón idirlíon" #: src/bz-app-size-dialog.blp:76 msgid "Installed Size" msgstr "Méid Suiteáilte" #: src/bz-app-size-dialog.blp:77 msgid "Size on Disk" msgstr "Méid ar Diosca" #: src/bz-app-size-dialog.blp:99 msgid "User Data Size" msgstr "Méid Sonraí Úsáideora" #: src/bz-app-size-dialog.blp:100 msgid "Caches, settings, and other app data" msgstr "Taisceáin, socruithe, agus sonraí eile aipeanna" #: src/bz-app-tile.blp:85 src/bz-full-view.c:363 src/bz-installed-page.blp:85 #: src/bz-window.blp:296 msgid "Installed" msgstr "Suiteáilte" #: src/bz-apps-page.blp:103 msgid "Show All" msgstr "Taispeáin Gach Rud" #: src/bz-apps-page.c:232 #, c-format msgid "All \"%s\"" msgstr "Gach \"%s\"" #: src/bz-apps-page.c:506 src/bz-tag-list.c:109 #, c-format msgid "%d Applications" msgstr "%d Feidhmchlár" #: src/bz-application.c:668 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:669 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:700 msgid "translator-credits" msgstr "Aindriú Mac Giolla Eoin" #: src/bz-application.c:711 msgid "Special Thanks" msgstr "Buíochas Speisialta" #: src/bz-application.c:769 msgid "Logged Out Successfully!" msgstr "Logáilte Amach go Rathúil!" #: src/bz-application.c:896 msgid "Performing setup..." msgstr "Ag déanamh socraithe..." #: src/bz-application.c:975 src/bz-application.c:984 msgid "Set Up Flathub" msgstr "Socraigh Flathub" #: src/bz-application.c:978 msgid "" "Flathub is not set up on this system. You will not be able to browse and " "install applications in Bazaar if its unavailable.\n" "\n" "You can still use Bazaar to browse and remove already installed apps." msgstr "" "Níl Flathub socraithe ar an gcóras seo. Ní bheidh tú in ann brabhsáil agus " "feidhmchláir a shuiteáil i Bazaar mura bhfuil sé ar fáil.\n" "\n" "Is féidir leat Bazaar a úsáid fós chun brabhsáil agus aipeanna atá " "suiteáilte cheana féin a bhaint." #: src/bz-application.c:983 src/bz-update-dialog.blp:6 msgid "Later" msgstr "Níos déanaí" #: src/bz-application.c:1385 src/bz-application.c:3059 msgid "Synchronizing..." msgstr "Ag sioncrónú..." #: src/bz-application.c:1524 src/bz-application.c:3055 #, c-format msgid "Receiving %d entries..." msgstr "Ag fáil %d iontráil..." #: src/bz-application.c:1529 msgid "Checking for updates" msgstr "Ag seiceáil le haghaidh nuashonruithe" #: src/bz-application.c:3061 msgid "Indexing Data..." msgstr "Ag Innéacsú Sonraí..." #: src/bz-curated-view.blp:11 src/bz-favorites-page.blp:65 #: src/bz-flathub-page.blp:19 src/bz-full-view.blp:53 #: src/bz-installed-page.blp:63 src/bz-user-data-page.blp:52 #: src/bz-window.blp:183 msgid "Empty" msgstr "Folamh" #: src/bz-curated-view.blp:15 msgid "No Curation" msgstr "Gan Coimeádadh" #: src/bz-curated-view.blp:16 msgid "" "There is no curation information provided on this system. You can still " "browse applications on Flathub" msgstr "" "Níl aon fhaisnéis choimeádta curtha ar fáil ar an gcóras seo. Is féidir leat " "brabhsáil a dhéanamh ar fheidhmchláir ar Flathub fós" #: src/bz-curated-view.blp:18 msgid "Browse Flathub" msgstr "Brabhsáil Flathub" #: src/bz-curated-view.blp:29 src/bz-curated-view.blp:33 #: src/bz-flathub-page.blp:30 src/bz-flathub-page.blp:34 msgid "Offline" msgstr "As líne" #: src/bz-curated-view.blp:39 src/bz-flathub-page.blp:49 msgid "Browser" msgstr "Brabhsálaí" #: src/bz-developer-badge.c:131 msgid "Developer information not available." msgstr "Níl faisnéis forbróra ar fáil." #: src/bz-developer-badge.c:137 src/bz-developer-badge.c:151 #, c-format msgid "" "The ownership of the %s app ID has not been verified and it may be a " "community package." msgstr "" "Níl úinéireacht an aitheantais aip %s fíoraithe agus d'fhéadfadh gur " "pacáiste pobail atá ann." #: src/bz-developer-badge.c:155 #, c-format msgid "" "The ownership of the %s app ID has been manually verified by the Flathub " "team." msgstr "" "Tá úinéireacht an aitheantais aip %s fíoraithe de láimh ag foireann Flathub." #: src/bz-developer-badge.c:161 #, c-format msgid "" "The ownership of the %1$s app ID has been verified by %2$s on " "%3$s." msgstr "" "Tá úinéireacht an aitheantais aip %1$s fíoraithe ag %2$s ar %3$s." #: src/bz-developer-badge.c:168 #, c-format msgid "The ownership of the %1$s app ID has been verified using %2$s." msgstr "Tá úinéireacht ID an aip %1$s fíoraithe ag baint úsáide as %2$s." #: src/bz-developer-badge.c:172 #, c-format msgid "The ownership of the %s app ID has been verified." msgstr "Tá úinéireacht an aitheantais aip %s fíoraithe." #: src/bz-entry-group-util.c:73 msgid "Choose an Installation" msgstr "Roghnaigh Suiteáil" #: src/bz-entry-group-util.c:76 msgid "" "You have multiple versions of this app installed. Which one would you like " "to proceed with?" msgstr "" "Tá roinnt leaganacha den aip seo suiteáilte agat. Cé acu ceann ar mhaith " "leat leanúint ar aghaidh leis?" #: src/bz-entry-group-util.c:80 src/bz-transaction-dialog.c:200 #: src/bz-transaction-dialog.c:223 src/bz-transaction-dialog.c:268 msgid "Cancel" msgstr "Cealaigh" #: src/bz-error.c:68 msgid "An Error Occurred" msgstr "Tharla Earráid" #: src/bz-error.c:89 msgid "Close" msgstr "Dún" #: src/bz-error.c:90 msgid "Copy and Close" msgstr "Cóipeáil agus Dún" #: src/bz-favorite-button.c:434 msgid "Log in with Flathub to manage favorites" msgstr "Logáil isteach le Flathub chun na cinn is fearr leat a bhainistiú" #: src/bz-favorite-button.c:440 msgid "Log In" msgstr "Logáil Isteach" #: src/bz-favorite-button.blp:14 msgid "Favorite Count" msgstr "Líon na bhFear is Ansa liom" #: src/bz-favorites-tile.c:164 msgid "Uninstall" msgstr "Díshuiteáil" #: src/bz-favorites-tile.blp:70 src/bz-installed-tile.blp:75 msgid "Support this application" msgstr "Tacaigh leis an iarratas seo" #: src/bz-favorites-tile.blp:118 msgid "Remove from Favorites" msgstr "Bain as na Ceanáin" #: src/bz-favorites-page.blp:5 src/bz-favorites-page.blp:75 #: src/bz-window.blp:611 msgid "Favorites" msgstr "Ceanáin" #: src/bz-favorites-page.blp:22 src/bz-full-view.blp:20 src/bz-window.blp:126 #: src/bz-window.blp:457 msgid "Toggle transaction sidebar" msgstr "Scoránaigh an taobhbharra idirbhirt" #: src/bz-favorites-page.blp:53 src/bz-user-data-page.blp:41 msgid "Loading" msgstr "Ag luchtú" #: src/bz-favorites-page.blp:68 msgid "No Favorites" msgstr "Gan aon Ceanáin" #: src/bz-favorites-page.blp:69 msgid "Applications you mark as favorite will appear here" msgstr "Beidh feidhmchláir a mharcálann tú mar is fearr leat le feiceáil anseo" #: src/bz-featured-carousel.blp:31 msgid "Previous" msgstr "Roimhe Seo" #: src/bz-featured-carousel.blp:53 msgid "Next" msgstr "Ar Aghaidh" #: src/bz-featured-tile.blp:88 msgid "App of the Day" msgstr "Aip an Lae" #: src/bz-flathub-category.c:79 msgid "Audio & Video" msgstr "Fuaim & Físeán" #: src/bz-flathub-category.c:79 msgid "Media" msgstr "Meáin" #: src/bz-flathub-category.c:79 msgid "More Audio & Video" msgstr "Tuilleadh Fuaime & Físeáin" #: src/bz-flathub-category.c:80 msgid "Developer Tools" msgstr "Uirlisí Forbróra" #: src/bz-flathub-category.c:80 msgid "Develop" msgstr "Forbair" #: src/bz-flathub-category.c:80 msgid "More Developer Tools" msgstr "Tuilleadh Uirlisí Forbróra" #: src/bz-flathub-category.c:81 msgid "Education" msgstr "Oideachas" #: src/bz-flathub-category.c:81 msgid "Learn" msgstr "Foghlaim" #: src/bz-flathub-category.c:81 msgid "More Education" msgstr "Tuilleadh Oideachais" #: src/bz-flathub-category.c:82 msgid "Gaming" msgstr "Cluichíocht" #: src/bz-flathub-category.c:82 msgid "Play" msgstr "Imir" #: src/bz-flathub-category.c:82 msgid "More Gaming" msgstr "Tuilleadh Cluichíocht" #: src/bz-flathub-category.c:83 msgid "Graphics & Photography" msgstr "Grafaicí & Grianghrafadóireacht" #: src/bz-flathub-category.c:83 msgid "Create" msgstr "Cruthaigh" #: src/bz-flathub-category.c:83 msgid "More Graphics & Photography" msgstr "Tuilleadh Grafaicí & Grianghrafadóireachta" #: src/bz-flathub-category.c:84 msgid "Networking" msgstr "Líonrú" #: src/bz-flathub-category.c:84 msgid "Internet" msgstr "Internet" #: src/bz-flathub-category.c:84 msgid "More Networking" msgstr "Tuilleadh Líonraithe" #: src/bz-flathub-category.c:85 msgid "Productivity" msgstr "Táirgiúlacht" #: src/bz-flathub-category.c:85 msgid "Work" msgstr "Obair" #: src/bz-flathub-category.c:85 msgid "More Productivity" msgstr "Tuilleadh Táirgiúlachta" #: src/bz-flathub-category.c:86 msgid "Science" msgstr "Eolaíocht" #: src/bz-flathub-category.c:86 msgid "More Science" msgstr "Tuilleadh Eolaíochta" #: src/bz-flathub-category.c:87 msgid "System" msgstr "Córas" #: src/bz-flathub-category.c:87 msgid "More System" msgstr "Tuilleadh Córas" #: src/bz-flathub-category.c:88 msgid "Utilities" msgstr "Fóntais" #: src/bz-flathub-category.c:88 msgid "Tools" msgstr "Uirlisí" #: src/bz-flathub-category.c:88 msgid "More Utilities" msgstr "Tuilleadh Fóntais" #: src/bz-flathub-category.c:89 src/bz-flathub-page.blp:119 #: src/bz-flathub-page.blp:152 msgid "Trending" msgstr "Ag treochtáil" #: src/bz-flathub-category.c:89 msgid "More Trending" msgstr "Tuilleadh Treochtaí" #: src/bz-flathub-category.c:90 src/bz-flathub-page.blp:125 #: src/bz-flathub-page.blp:185 msgid "Popular" msgstr "Coitianta" #: src/bz-flathub-category.c:90 msgid "More Popular" msgstr "Níos Coitianta" #: src/bz-flathub-category.c:91 src/bz-flathub-page.blp:174 msgid "Recently Added" msgstr "Curtha leis le Déanaí" #: src/bz-flathub-category.c:91 src/bz-flathub-page.blp:131 msgid "New" msgstr "Nua" #: src/bz-flathub-category.c:91 msgid "More New" msgstr "Tuilleadh Nua" #: src/bz-flathub-category.c:92 src/bz-flathub-page.blp:163 msgid "Recently Updated" msgstr "Nuashonraithe le Déanaí" #: src/bz-flathub-category.c:92 src/bz-flathub-page.blp:137 msgid "Updated" msgstr "Nuashonraithe" #: src/bz-flathub-category.c:92 msgid "More Updated" msgstr "Tuilleadh Nuashonraithe" #: src/bz-flathub-category.c:93 msgid "Mobile" msgstr "Soghluaiste" #: src/bz-flathub-category.c:93 msgid "More Mobile" msgstr "Níos Soghluaiste" #: src/bz-flathub-category.c:94 msgid "Adwaita" msgstr "Adwaita" #: src/bz-flathub-category.c:94 msgid "More Adwaita" msgstr "Tuilleadh Adwaita" #: src/bz-flathub-category.c:95 msgid "KDE Apps" msgstr "Aipeanna KDE" #: src/bz-flathub-category.c:95 msgid "More KDE Apps" msgstr "Tuilleadh Aipeanna KDE" #: src/bz-flathub-page.blp:23 msgid "Flathub Not Added" msgstr "Níor Cuireadh Flathub Leis" #: src/bz-flathub-page.blp:24 msgid "The Flathub remote was not found on any of your Flatpak installations" msgstr "" "Ní bhfuarthas an cianrialtán Flathub ar aon cheann de do shuiteálacha Flatpak" #: src/bz-flathub-page.blp:35 msgid "Flathub returned an error" msgstr "Thug Flathub earráid ar ais" #: src/bz-flathub-page.blp:41 msgid "Retry Flathub Connection" msgstr "Déan iarracht eile ar nasc Flathub" #: src/bz-flathub-page.blp:57 msgid "Flathub Unavailable" msgstr "Flathub Gan Fáil" #: src/bz-flathub-page.blp:58 msgid "" "We could not connect to Flathub. You can still manage and search for " "applications." msgstr "" "Ní raibh muid in ann ceangal le Flathub. Is féidir leat feidhmchláir a " "bhainistiú agus a chuardach fós." #: src/bz-flathub-page.blp:61 msgid "Search Apps" msgstr "Cuardaigh Aipeanna" #: src/bz-flathub-page.blp:270 msgid "On the Go" msgstr "Ar an mBóthar" #: src/bz-flathub-page.blp:282 msgid "Apps for your Linux phones and tablets" msgstr "Aipeanna do do ghutháin agus táibléid Linux" #: src/bz-flathub-page.blp:293 src/bz-flathub-page.blp:328 msgid "More Mobile Apps" msgstr "Tuilleadh Aipeanna Soghluaiste" #: src/bz-flathub-page.blp:388 msgid "We​ ♥​ Games" msgstr "Is breá linn ♥ Cluichí" #: src/bz-flathub-page.blp:401 msgid "Games and apps to run your favorite titles" msgstr "Cluichí agus aipeanna chun do theidil is fearr leat a rith" #: src/bz-flathub-page.blp:435 msgid "More Games" msgstr "Tuilleadh Cluichí" #: src/bz-flatpak-entry.c:590 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Leathanach Flathub" #: src/bz-flatpak-entry.c:611 msgctxt "Project URL Type" msgid "Project Website" msgstr "Suíomh Gréasáin an Tionscadail" #: src/bz-flatpak-entry.c:615 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Rianaitheoir Fadhbanna" #: src/bz-flatpak-entry.c:619 msgctxt "Project URL Type" msgid "FAQ" msgstr "Ceisteanna Coitianta" #: src/bz-flatpak-entry.c:623 msgctxt "Project URL Type" msgid "Help" msgstr "Cabhair" #: src/bz-flatpak-entry.c:627 msgctxt "Project URL Type" msgid "Donate" msgstr "Tabhair Síntiús" #: src/bz-flatpak-entry.c:633 msgctxt "Project URL Type" msgid "Translate" msgstr "Aistrigh" #: src/bz-flatpak-entry.c:637 msgctxt "Project URL Type" msgid "Contact" msgstr "Teagmháil" #: src/bz-flatpak-entry.c:641 msgctxt "Project URL Type" msgid "Source Code" msgstr "Cód Foinse" #: src/bz-flatpak-entry.c:647 msgctxt "Project URL Type" msgid "Contribute" msgstr "Cuir leis" #: src/bz-full-view.blp:57 src/bz-installed-page.blp:74 #: src/bz-installed-page.blp:78 msgid "No Results" msgstr "Gan Torthaí" #: src/bz-full-view.blp:58 msgid "Try a different search query" msgstr "Bain triail as ceist chuardaigh dhifriúil" #: src/bz-full-view.blp:64 src/bz-window.blp:193 msgid "Content" msgstr "Ábhar" #: src/bz-full-view.blp:210 msgid "Support" msgstr "Tacaíocht" #: src/bz-full-view.blp:233 src/bz-full-view.blp:493 msgid "Open" msgstr "Oscail" #: src/bz-full-view.blp:246 src/bz-full-view.blp:466 msgid "Download & Install Application" msgstr "Íoslódáil & Suiteáil Feidhmchlár" #: src/bz-full-view.blp:261 msgid "Uninstall Application" msgstr "Díshuiteáil Feidhmchlár" #: src/bz-full-view.blp:276 src/bz-full-view.blp:508 msgid "Install Other Version" msgstr "Suiteáil Leagan Eile" #: src/bz-full-view.blp:430 msgid "Downloads /mo" msgstr "Íoslódálacha /mí" #: src/bz-full-view.blp:527 msgid "Stopped Receiving Core Updates" msgstr "Stopadh ag fáil nuashonruithe lárnacha" #: src/bz-full-view.blp:541 msgid "" "This app uses a runtime that no longer receives updates or security fixes. " "It may become unsafe to use." msgstr "" "Úsáideann an aip seo am rith nach bhfaigheann nuashonruithe ná socruithe " "slándála a thuilleadh. D’fhéadfadh sé a bheith neamhshábháilte le húsáid." #: src/bz-full-view.blp:627 msgid "Trash Data" msgstr "Sonraí Bruscair" #: src/bz-full-view.blp:769 msgid "Tags:" msgstr "Clibeanna:" #: src/bz-full-view.c:307 msgid "---" msgstr "---" #. Translators: M is the suffix for millions #: src/bz-full-view.c:314 #, c-format msgid "%.*fM" msgstr "%.*fM" #. Translators: K is the suffix for thousands #: src/bz-full-view.c:321 #, c-format msgid "%.*fK" msgstr "%.*fK" #: src/bz-full-view.c:331 #, c-format msgid "%d downloads in the last 30 days" msgstr "%d íoslódálacha le 30 lá anuas" #: src/bz-full-view.c:363 msgid "Download" msgstr "Íoslódáil" #: src/bz-full-view.c:381 #, c-format msgid "Download size of %s" msgstr "Méid íoslódála %s" #: src/bz-full-view.c:414 msgid "All Ages" msgstr "Gach Aois" #: src/bz-full-view.c:426 msgid "Age rating information unavailable" msgstr "Níl faisnéis faoi rátáil aoise ar fáil" #: src/bz-full-view.c:431 msgid "Suitable for all ages" msgstr "Oiriúnach do gach aois" #: src/bz-full-view.c:433 #, c-format msgid "Suitable for ages %d and up" msgstr "Oiriúnach do dhaoine aois %d agus os a chionn" #: src/bz-full-view.c:466 src/bz-full-view.c:471 src/bz-full-view.c:499 #: src/bz-full-view.c:510 msgid "Unknown" msgstr "Anaithnid" #: src/bz-full-view.c:476 #, c-format msgid "Free software licensed under %s" msgstr "Bogearraí saor in aisce ceadúnaithe faoi %s" #: src/bz-full-view.c:481 msgid "Free software" msgstr "Bogearraí saor in aisce" #: src/bz-full-view.c:484 msgid "Proprietary Software" msgstr "Bogearraí Dílseánaigh" #: src/bz-full-view.c:487 #, c-format msgid "Special License: %s" msgstr "Ceadúnas Speisialta: %s" #: src/bz-full-view.c:504 msgid "Free" msgstr "Saor in aisce" #: src/bz-full-view.c:507 src/bz-license-dialog.c:190 msgid "Proprietary" msgstr "Dílseánaigh" #: src/bz-full-view.c:512 src/bz-license-dialog.c:192 msgid "Special License" msgstr "Ceadúnas Speisialta" #: src/bz-full-view.c:532 msgid "Adaptive" msgstr "Oiriúnaitheach" #: src/bz-full-view.c:532 msgid "Desktop Only" msgstr "Deasc Amháin" #: src/bz-full-view.c:538 msgid "Works on desktop, tablets, and phones" msgstr "Oibríonn sé ar dheasc, táibléid agus fóin" #: src/bz-full-view.c:539 msgid "May not work on mobile devices" msgstr "B’fhéidir nach n-oibreoidh sé ar ghléasanna soghluaiste" #: src/bz-full-view.c:550 msgid "No URL" msgstr "Gan URL" #: src/bz-full-view.c:568 msgid "" "This application has a FLOSS license, meaning the source code can be audited " "for safety." msgstr "" "Tá ceadúnas FLOSS ag an bhfeidhmchlár seo, rud a chiallaíonn gur féidir an " "cód foinse a iniúchadh ar mhaithe le sábháilteacht." #: src/bz-full-view.c:569 msgid "" "This application has a proprietary license, meaning the source code is " "developed privately and cannot be audited by an independent third party." msgstr "" "Tá ceadúnas dílseánaigh ag an bhfeidhmchlár seo, rud a chiallaíonn go " "bhforbraítear an cód foinse go príobháideach agus nach féidir le tríú páirtí " "neamhspleách é a iniúchadh." #: src/bz-full-view.c:576 msgid "More Apps" msgstr "Tuilleadh Aipeanna" #: src/bz-full-view.c:577 #, c-format msgid "More Apps by %s" msgstr "Tuilleadh Aipeanna ó %s" #: src/bz-full-view.c:584 msgid "Other Apps by this Developer" msgstr "Aipeanna Eile ón bhForbróir seo" #: src/bz-full-view.c:586 src/bz-full-view.c:786 #, c-format msgid "Other Apps by %s" msgstr "Aipeanna Eile ó %s" #: src/bz-full-view.c:595 #, c-format msgid "%s is not installed, but it still has %s of data present." msgstr "Níl %s suiteáilte, ach tá %s sonraí ann fós." #: src/bz-full-view.c:668 src/bz-full-view.c:685 msgid "N/A" msgstr "N/B" #: src/bz-full-view.c:675 src/bz-full-view.c:677 src/bz-full-view.c:679 msgid "Low Risk" msgstr "Riosca Íseal" #: src/bz-full-view.c:681 msgid "Medium Risk" msgstr "Riosca Meánach" #: src/bz-full-view.c:683 msgid "High Risk" msgstr "Ardriosca" #: src/bz-full-view.c:788 msgid "Other Apps" msgstr "Aipeanna Eile" #: src/bz-full-view.c:790 #, c-format msgid "%d Application" msgid_plural "%d Applications" msgstr[0] "%d Feidhmchlár" msgstr[1] "%d Feidhmchláir" msgstr[2] "%d Feidhmchláir" #: src/bz-full-view.c:1129 msgid "Show Less" msgstr "Taispeáin Níos Lú" #: src/bz-full-view.c:1129 msgid "Show More" msgstr "Taispeáin Tuilleadh" #: src/bz-hardware-support-dialog.blp:7 src/bz-hardware-support-dialog.blp:31 msgid "Hardware Support" msgstr "Tacaíocht Crua-earraí" #: src/bz-hardware-support-dialog.c:62 msgid "Keyboard support" msgstr "Tacaíocht méarchláir" #: src/bz-hardware-support-dialog.c:64 msgid "Requires keyboards" msgstr "Éilíonn méarchláir" #: src/bz-hardware-support-dialog.c:65 msgid "Recommends keyboards" msgstr "Molann méarchláir" #: src/bz-hardware-support-dialog.c:66 msgid "Supports keyboards" msgstr "Tacaíonn méarchláir" #: src/bz-hardware-support-dialog.c:67 msgid "Unknown support for keyboards" msgstr "Tacaíocht anaithnid do mhéarchláir" #: src/bz-hardware-support-dialog.c:69 msgid "Mouse support" msgstr "Tacaíocht luiche" #: src/bz-hardware-support-dialog.c:71 msgid "Requires mice or pointing devices" msgstr "Teastaíonn lucha nó gléasanna pointeála" #: src/bz-hardware-support-dialog.c:72 msgid "Recommends mice or pointing devices" msgstr "Molann lucha nó gléasanna pointeála" #: src/bz-hardware-support-dialog.c:73 msgid "Supports mice or pointing devices" msgstr "Tacaíonn sé le lucha nó le gléasanna pointeála" #: src/bz-hardware-support-dialog.c:74 msgid "Unknown support for mice or pointing devices" msgstr "Tacaíocht anaithnid do lucha nó do ghléasanna pointeála" #: src/bz-hardware-support-dialog.c:76 msgid "Touchscreen support" msgstr "Tacaíocht scáileáin tadhaill" #: src/bz-hardware-support-dialog.c:78 msgid "Requires touchscreens" msgstr "Éilíonn scáileáin tadhaill" #: src/bz-hardware-support-dialog.c:79 msgid "Recommends touchscreens" msgstr "Molann scáileáin tadhaill" #: src/bz-hardware-support-dialog.c:80 msgid "Supports touchscreens" msgstr "Tacaíonn sé le scáileáin tadhaill" #: src/bz-hardware-support-dialog.c:81 msgid "Unknown support for touchscreens" msgstr "Tacaíocht anaithnid do scáileáin tadhaill" #: src/bz-hardware-support-dialog.c:160 msgid "Mobile support" msgstr "Tacaíocht shoghluaiste" #: src/bz-hardware-support-dialog.c:161 msgid "Works on mobile devices" msgstr "Oibríonn sé ar ghléasanna soghluaiste" #: src/bz-hardware-support-dialog.c:161 msgid "May not work well on mobile devices" msgstr "B’fhéidir nach n-oibreoidh sé go maith ar ghléasanna soghluaiste" #: src/bz-hardware-support-dialog.c:166 msgid "Desktop support" msgstr "Tacaíocht deisce" #: src/bz-hardware-support-dialog.c:167 msgid "Works well on large screens" msgstr "Oibríonn go maith ar scáileáin mhóra" #: src/bz-hardware-support-dialog.c:201 #, c-format msgid "%s works best on specific hardware" msgstr "Oibríonn %s is fearr ar chrua-earraí sonracha" #: src/bz-hardware-support-dialog.c:209 #, c-format msgid "%s works on most devices" msgstr "Oibríonn %s ar an gcuid is mó de na gléasanna" #: src/bz-installed-page.blp:28 msgid "Search installed apps" msgstr "Cuardaigh aipeanna suiteáilte" #: src/bz-installed-page.blp:67 msgid "No Apps Found" msgstr "Níor aimsíodh aon aipeanna" #: src/bz-installed-page.c:154 #, c-format msgid "No matches found for \"%s\" in the list of installed apps" msgstr "" "Níor aimsíodh aon mheaitseálacha do \"%s\" i liosta na n-aipeanna suiteáilte" #: src/bz-installed-tile.blp:61 src/bz-rich-app-tile.blp:137 msgid "Stopped Receiving Updates" msgstr "Stopadh ag fáil nuashonruithe" #: src/bz-license-dialog.blp:95 msgid "Get Involved" msgstr "Bígí Páirteach" #: src/bz-license-dialog.c:184 msgid "Unknown License" msgstr "Ceadúnas Anaithnid" #: src/bz-license-dialog.c:187 msgid "Community Built" msgstr "Tógtha ag an bPobal" #: src/bz-license-dialog.c:235 msgid "" "This app is developed in the open by an international community.\n" "\n" "You can participate and help make it even better." msgstr "" "Forbraíodh an aip seo go hoscailte ag pobal idirnáisiúnta.\n" "\n" "Is féidir leat páirt a ghlacadh agus cabhrú le feabhas a chur uirthi." #: src/bz-license-dialog.c:238 msgid "The license of this app is not known" msgstr "Níl ceadúnas an aip seo ar eolas" #: src/bz-license-dialog.c:244 #, c-format msgid "" "This app is developed in the open by an international community, and " "released under the %s license.\n" "\n" "You can participate and help make it even better." msgstr "" "Forbraíodh an aip seo go hoscailte ag pobal idirnáisiúnta, agus eisíodh í " "faoin gceadúnas %s.\n" "\n" "Is féidir leat páirt a ghlacadh agus cabhrú le feabhas a chur uirthi." #: src/bz-license-dialog.c:252 msgid "" "This app is not developed in the open, so only its developers know how it " "works. It may be insecure in ways that are hard to detect, and it may change " "without oversight.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Níor forbraíodh an aip seo go hoscailte, mar sin níl a fhios ag ach a " "forbróirí conas a oibríonn sé. D’fhéadfadh sé a bheith neamhshábháilte ar " "bhealaí atá deacair a bhrath, agus d’fhéadfadh sé athrú gan mhaoirseacht.\n" "\n" "B’fhéidir go mbeidh tú in ann cur leis an aip seo nó nach mbeidh." #: src/bz-license-dialog.c:258 #, c-format msgid "" "This app is developed under the special license %s.\n" "\n" "You may or may not be able to contribute to this app." msgstr "" "Forbraíodh an aip seo faoin gceadúnas speisialta %s.\n" "\n" "B’fhéidir go mbeidh tú in ann cur leis an aip seo nó nach mbeidh." #: src/bz-login-page.blp:5 src/bz-login-page.blp:42 msgid "Connect to Flathub" msgstr "Ceangail le Flathub" #: src/bz-login-page.blp:32 msgid "Something Went Wrong" msgstr "Chuaigh rud éigin mícheart" #: src/bz-login-page.blp:43 msgid "Connect your Flathub account to Bazaar to manage your favorited apps." msgstr "" "Ceangail do chuntas Flathub le Bazaar chun do chuid aipeanna is fearr leat a " "bhainistiú." #: src/bz-login-page.blp:108 msgid "Finish" msgstr "Críochnaigh" #: src/bz-login-page.c:663 #, c-format msgid "Hello, %s!" msgstr "Haigh, %s!" #: src/bz-preferences-dialog.blp:19 msgid "Preferences" msgstr "Roghanna" #: src/bz-preferences-dialog.blp:25 msgid "Network connection is metered — automatic store data sync is paused" msgstr "" "Tá an nasc líonra méadraithe — tá sioncrónú uathoibríoch sonraí stórála ar " "sos" #: src/bz-preferences-dialog.blp:26 src/bz-window.blp:491 msgid "Sync Manually" msgstr "Sioncrónaigh de Láimh" #: src/bz-preferences-dialog.blp:31 msgid "Content Filters" msgstr "Scagairí Ábhair" #: src/bz-preferences-dialog.blp:34 msgid "Free Software Only" msgstr "Bogearraí Saor in Aisce Amháin" #: src/bz-preferences-dialog.blp:35 msgid "Hide proprietary applications when browsing and searching" msgstr "Folaigh feidhmchláir dhílseánaigh agus tú ag brabhsáil agus ag cuardach" #: src/bz-preferences-dialog.blp:39 msgid "Flathub Results Only" msgstr "Torthaí Flathub Amháin" #: src/bz-preferences-dialog.blp:40 msgid "" "Limit search and browse results to applications only available on Flathub" msgstr "" "Teorainn a chur le cuardach agus torthaí brabhsála d’fheidhmchláir atá ar " "fáil ar Flathub amháin" #: src/bz-preferences-dialog.blp:44 msgid "Verified Results Only" msgstr "Torthaí Fíoraithe Amháin" #: src/bz-preferences-dialog.blp:45 msgid "Hide results that are not verified on Flathub" msgstr "Folaigh torthaí nach bhfuil fíoraithe ar Flathub" #: src/bz-preferences-dialog.blp:49 msgid "Hide EOL Apps" msgstr "Folaigh Aipeanna EOL" #: src/bz-preferences-dialog.blp:50 msgid "Hide apps which are no longer supported by their developers" msgstr "Folaigh aipeanna nach dtacaíonn a bhforbróirí leo a thuilleadh" #: src/bz-preferences-dialog.blp:55 src/bz-window.blp:311 msgid "Search" msgstr "Cuardaigh" #: src/bz-preferences-dialog.blp:58 msgid "Delay Search Results" msgstr "Moill ar Thorthaí Cuardaigh" #: src/bz-preferences-dialog.blp:59 msgid "Improve results performance by debouncing search terms" msgstr "" "Feabhas a chur ar fheidhmíocht na dtorthaí trí théarmaí cuardaigh a dhí-" "bhreabadh" #: src/bz-preferences-dialog.blp:64 msgid "Progress Bar" msgstr "Barra Dul Chun Cinn" #: src/bz-preferences-dialog.blp:65 msgid "Choose a theme for the progress bar!" msgstr "Roghnaigh téama don bharra dul chun cinn!" #: src/bz-preferences-dialog.c:32 msgid "Accent Color" msgstr "Dath Aicinn" #: src/bz-preferences-dialog.c:33 msgid "Pride Colors" msgstr "Dathanna Bród" #: src/bz-preferences-dialog.c:34 msgid "Pride Colors (Horizontal)" msgstr "Dathanna Bród (Cothrománach)" #: src/bz-preferences-dialog.c:35 msgid "Lesbian Pride Colors" msgstr "Dathanna Bród Leispiach" #: src/bz-preferences-dialog.c:36 msgid "Lesbian Pride Colors (Horizontal)" msgstr "Dathanna Bród Leispiach (Cothrománach)" #: src/bz-preferences-dialog.c:37 msgid "Male Homosexual Pride Colors" msgstr "Dathanna Bród Fir Homaighnéasacha" #: src/bz-preferences-dialog.c:38 msgid "Male Homosexual Pride Colors (Horizontal)" msgstr "Dathanna Bród Fir Homaighnéasacha (Cothrománach)" #: src/bz-preferences-dialog.c:39 msgid "Transgender Pride Colors" msgstr "Dathanna Bród Trasinscne" #: src/bz-preferences-dialog.c:40 msgid "Transgender Pride Colors (Horizontal)" msgstr "Dathanna Bród Trasinscne (Cothrománach)" #: src/bz-preferences-dialog.c:41 msgid "Nonbinary Pride Colors" msgstr "Dathanna Bród Neamhdhénártha" #: src/bz-preferences-dialog.c:42 msgid "Nonbinary Pride Colors (Horizontal)" msgstr "Dathanna Bród Neamhdhénártha (Cothrománach)" #: src/bz-preferences-dialog.c:43 msgid "Bisexual Pride Colors" msgstr "Dathanna Bród Déghnéasacha" #: src/bz-preferences-dialog.c:44 msgid "Bisexual Pride Colors (Horizontal)" msgstr "Dathanna Bród Déghnéasacha (Cothrománach)" #: src/bz-preferences-dialog.c:45 msgid "Asexual Pride Colors" msgstr "Dathanna Bród Neamhghnéasacha" #: src/bz-preferences-dialog.c:46 msgid "Asexual Pride Colors (Horizontal)" msgstr "Dathanna Bród Asexual (Cothrománach)" #: src/bz-preferences-dialog.c:47 msgid "Pansexual Pride Colors" msgstr "Dathanna Bród Panghnéasacha" #: src/bz-preferences-dialog.c:48 msgid "Pansexual Pride Colors (Horizontal)" msgstr "Dathanna Bród Panghnéasacha (Cothrománach)" #: src/bz-preferences-dialog.c:49 msgid "Aromantic Pride Colors" msgstr "Dathanna Bród Cumhra" #: src/bz-preferences-dialog.c:50 msgid "Aromantic Pride Colors (Horizontal)" msgstr "Dathanna Bród Cumhra (Cothrománach)" #: src/bz-preferences-dialog.c:51 msgid "Genderfluid Pride Colors" msgstr "Dathanna Bród Inscnefluid" #: src/bz-preferences-dialog.c:52 msgid "Genderfluid Pride Colors (Horizontal)" msgstr "Dathanna Bród Inscnefluid (Cothrománach)" #: src/bz-preferences-dialog.c:53 msgid "Polysexual Pride Colors" msgstr "Dathanna Bród Ilghnéasacha" #: src/bz-preferences-dialog.c:54 msgid "Polysexual Pride Colors (Horizontal)" msgstr "Dathanna Bród Ilghnéasacha (Cothrománach)" #: src/bz-preferences-dialog.c:55 msgid "Omnisexual Pride Colors" msgstr "Dathanna Bród Uileghnéasacha" #: src/bz-preferences-dialog.c:56 msgid "Omnisexual Pride Colors (Horizontal)" msgstr "Dathanna Bród Uileghnéasacha (Cothrománach)" #: src/bz-preferences-dialog.c:57 msgid "Aroace Pride Colors" msgstr "Dathanna Bród Aroace" #: src/bz-preferences-dialog.c:58 msgid "Aroace Pride Colors (Horizontal)" msgstr "Dathanna Aroace Pride (Cothrománach)" #: src/bz-preferences-dialog.c:59 msgid "Agender Pride Colors" msgstr "Dathanna Bród Agender" #: src/bz-preferences-dialog.c:60 msgid "Agender Pride Colors (Horizontal)" msgstr "Dathanna Bród Agender (Cothrománach)" #: src/bz-preferences-dialog.c:61 msgid "Genderqueer Pride Colors" msgstr "Dathanna Bród Inscnequeer" #: src/bz-preferences-dialog.c:62 msgid "Genderqueer Pride Colors (Horizontal)" msgstr "Dathanna Bród Inscnequeer (Cothrománach)" #: src/bz-preferences-dialog.c:63 msgid "Intersex Pride Colors" msgstr "Dathanna Bród Idirghnéasacha" #: src/bz-preferences-dialog.c:64 msgid "Intersex Pride Colors (Horizontal)" msgstr "Dathanna Bród Idirghnéasacha (Cothrománach)" #: src/bz-preferences-dialog.c:65 msgid "Demigender Pride Colors" msgstr "Dathanna Bród Demi-Inscne" #: src/bz-preferences-dialog.c:66 msgid "Demigender Pride Colors (Horizontal)" msgstr "Dathanna Bród Demigender (Cothrománach)" #: src/bz-preferences-dialog.c:67 msgid "Biromantic Pride Colors" msgstr "Dathanna Bród Birománsacha" #: src/bz-preferences-dialog.c:68 msgid "Biromantic Pride Colors (Horizontal)" msgstr "Dathanna Bród Biormantach (Cothrománach)" #: src/bz-preferences-dialog.c:69 msgid "Disability Pride Colors" msgstr "Dathanna Bród Míchumais" #: src/bz-preferences-dialog.c:70 msgid "Disability Pride Colors (Horizontal)" msgstr "Dathanna Bród Míchumais (Cothrománach)" #: src/bz-preferences-dialog.c:71 msgid "Femboy Pride Colors" msgstr "Dathanna Bród Femboy" #: src/bz-preferences-dialog.c:72 msgid "Femboy Pride Colors (Horizontal)" msgstr "Dathanna Bród Femboy (Cothrománach)" #: src/bz-releases-dialog.blp:5 src/bz-releases-list.blp:27 msgid "Version History" msgstr "Stair Leagan" #: src/bz-releases-list.c:136 #, c-format msgid "Version %s" msgstr "Leagan %s" #: src/bz-releases-list.c:174 msgid "No details for this release" msgstr "Gan aon sonraí don eisiúint seo" #: src/bz-releases-list.c:186 msgid "Get More Information" msgstr "Faigh Tuilleadh Eolais" #: src/bz-rich-app-tile.blp:154 msgid "Get" msgstr "Faigh" #: src/bz-safety-calculator.c:77 msgid "Unknown Permissions" msgstr "Ceadanna Anaithnid" #: src/bz-safety-calculator.c:78 msgid "Permissions are missing for this app." msgstr "Tá ceadanna ar iarraidh don aip seo." #: src/bz-safety-calculator.c:91 msgid "No Permissions" msgstr "Gan Ceadanna" #: src/bz-safety-calculator.c:92 msgid "App is fully sandboxed" msgstr "Tá an aip bosca gainimh go hiomlán" #: src/bz-safety-calculator.c:98 msgid "Network Access" msgstr "Rochtain Líonra" #: src/bz-safety-calculator.c:99 msgid "Can access the internet" msgstr "Is féidir rochtain a fháil ar an idirlíon" #: src/bz-safety-calculator.c:101 msgid "No Network Access" msgstr "Gan Rochtain Líonra" #: src/bz-safety-calculator.c:102 msgid "Cannot access the internet" msgstr "Ní féidir rochtain a fháil ar an idirlíon" #: src/bz-safety-calculator.c:107 msgid "User Device Access" msgstr "Rochtain Gléas Úsáideora" #: src/bz-safety-calculator.c:108 msgid "Can access devices such as webcams or gaming controllers" msgstr "" "Is féidir rochtain a fháil ar fheistí ar nós ceamaraí gréasáin nó rialtóirí " "cearrbhachais" #: src/bz-safety-calculator.c:110 msgid "No User Device Access" msgstr "Gan Rochtain ar Ghléas Úsáideora" #: src/bz-safety-calculator.c:111 msgid "Cannot access devices such as webcams or gaming controllers" msgstr "" "Ní féidir rochtain a fháil ar fheistí ar nós ceamaraí gréasáin nó rialtóirí " "cearrbhachais" #: src/bz-safety-calculator.c:116 msgid "Input Device Access" msgstr "Rochtain ar Ghléas Ionchuir" #: src/bz-safety-calculator.c:117 msgid "Can access input devices" msgstr "Is féidir rochtain a fháil ar fheistí ionchuir" #: src/bz-safety-calculator.c:123 msgid "Microphone Access and Audio Playback" msgstr "Rochtain Micreafóin agus Athsheinm Fuaime" #: src/bz-safety-calculator.c:124 msgid "Can listen using microphones and play audio without asking permission" msgstr "" "Is féidir éisteacht le micreafóin agus fuaim a sheinm gan cead a iarraidh" #: src/bz-safety-calculator.c:130 msgid "System Device Access" msgstr "Rochtain ar Ghléas an Chórais" #: src/bz-safety-calculator.c:131 msgid "Can access system devices which require elevated permissions" msgstr "" "Is féidir rochtain a fháil ar ghléasanna córais a bhfuil ceadanna ardaithe " "ag teastáil uathu" #: src/bz-safety-calculator.c:137 msgid "Screen Contents Access" msgstr "Rochtain ar Ábhar an Scáileáin" #: src/bz-safety-calculator.c:138 msgid "Can access the contents of the screen or other windows" msgstr "Is féidir rochtain a fháil ar ábhar an scáileáin nó fuinneoga eile" #: src/bz-safety-calculator.c:144 msgid "Legacy Windowing System" msgstr "Córas Fuinneoige Oidhreachta" #: src/bz-safety-calculator.c:145 msgid "Uses a legacy windowing system" msgstr "Úsáideann córas fuinneoige oidhreachta" #: src/bz-safety-calculator.c:151 msgid "Arbitrary Permissions" msgstr "Ceadanna Treallacha" #: src/bz-safety-calculator.c:152 msgid "Can acquire arbitrary permissions" msgstr "Is féidir ceadanna treallacha a fháil" #: src/bz-safety-calculator.c:158 msgid "User Settings" msgstr "Socruithe Úsáideora" #: src/bz-safety-calculator.c:159 msgid "Can access and change user settings" msgstr "Is féidir rochtain a fháil ar shocruithe úsáideora agus iad a athrú" #: src/bz-safety-calculator.c:165 msgid "Full File System Read/Write Access" msgstr "Rochtain Léitheoireachta/Scríofa ar an gCóras Comhad Iomlán" #: src/bz-safety-calculator.c:166 msgid "Can read and write all data on the file system" msgstr "" "Is féidir leis na sonraí go léir ar an gcóras comhad a léamh agus a scríobh" #: src/bz-safety-calculator.c:173 msgid "Home Folder Read/Write Access" msgstr "Rochtain Léitheoireachta/Scríofa ar Fhillteán Baile" #: src/bz-safety-calculator.c:174 msgid "Can read and write all data in your home directory" msgstr "" "Is féidir leat na sonraí go léir i do eolaire baile a léamh agus a scríobh" #: src/bz-safety-calculator.c:181 msgid "Full File System Read Access" msgstr "Rochtain Léitheoireachta Iomlán an Chórais Comhad" #: src/bz-safety-calculator.c:182 msgid "Can read all data on the file system" msgstr "Is féidir leis na sonraí go léir ar an gcóras comhad a léamh" #: src/bz-safety-calculator.c:190 msgid "Home Folder Read Access" msgstr "Rochtain Léitheoireachta Fillteán Baile" #: src/bz-safety-calculator.c:191 msgid "Can read all data in your home directory" msgstr "Is féidir leat na sonraí go léir i do eolaire baile a léamh" #: src/bz-safety-calculator.c:199 msgid "Download Folder Read/Write Access" msgstr "Rochtain Léitheoireachta/Scríofa ar an bhFillteán Íoslódála" #: src/bz-safety-calculator.c:200 msgid "Can read and write all data in your downloads directory" msgstr "" "Is féidir leat na sonraí go léir i do eolaire íoslódálacha a léamh agus a " "scríobh" #: src/bz-safety-calculator.c:210 msgid "Download Folder Read Access" msgstr "Íoslódáil Rochtain Léitheoireachta Fillteáin" #: src/bz-safety-calculator.c:211 msgid "Can read all data in your downloads directory" msgstr "Is féidir leat na sonraí go léir i do chomhadlann íoslódálacha a léamh" #: src/bz-safety-calculator.c:224 msgid "Can read and write all data in the directory" msgstr "Is féidir na sonraí go léir san eolaire a léamh agus a scríobh" #: src/bz-safety-calculator.c:238 msgid "Can read all data in the directory" msgstr "Is féidir na sonraí go léir san eolaire a léamh" #: src/bz-safety-calculator.c:253 msgid "No File System Access" msgstr "Gan Rochtain ar Chóras Comhad" #: src/bz-safety-calculator.c:254 msgid "Cannot access the file system at all" msgstr "Ní féidir rochtain a fháil ar an gcóras comhad ar chor ar bith" #: src/bz-safety-calculator.c:261 msgid "Uses System Services" msgstr "Úsáideann Seirbhísí Córais" #: src/bz-safety-calculator.c:262 msgid "Can request data from non-portal system services" msgstr "Is féidir sonraí a iarraidh ó sheirbhísí córais neamh-thairsí" #: src/bz-safety-calculator.c:268 msgid "Uses Session Services" msgstr "Úsáideann Seirbhísí Seisiúin" #: src/bz-safety-calculator.c:269 msgid "Can request data from non-portal session services" msgstr "Is féidir sonraí a iarraidh ó sheirbhísí seisiúin neamh-thairseach" #: src/bz-safety-calculator.c:294 msgid "No Service Access" msgstr "Gan Rochtain Seirbhíse" #: src/bz-safety-calculator.c:295 msgid "Cannot access non-portal session or system services at all" msgstr "" "Ní féidir rochtain a fháil ar sheirbhísí seisiúin nó córais neamh-thairseach " "ar chor ar bith" #: src/bz-safety-calculator.c:303 msgid "Verified App Developer" msgstr "Forbróir Aipeanna Fíoraithe" #: src/bz-safety-calculator.c:304 msgid "The developer of this app has been verified to be who they say they are" msgstr "" "Tá sé fíoraithe gurb é forbróir an aip seo an duine a deir siad a bheith" #: src/bz-safety-calculator.c:313 msgid "Proprietary Code" msgstr "Cód Dílseánaigh" #: src/bz-safety-calculator.c:314 msgid "" "The source code is not public, so it cannot be independently audited and " "might be unsafe" msgstr "" "Níl an cód foinse poiblí, mar sin ní féidir é a iniúchadh go neamhspleách " "agus d'fhéadfadh sé a bheith neamhshábháilte" #: src/bz-safety-calculator.c:324 msgid "Auditable Code" msgstr "Cód Iniúchta" #: src/bz-safety-calculator.c:325 msgid "" "The source code is public and can be independently audited, which makes the " "app more likely to be safe" msgstr "" "Tá an cód foinse poiblí agus is féidir é a iniúchadh go neamhspleách, rud a " "fhágann go bhfuil an aip níos dóchúla a bheith sábháilte" #: src/bz-safety-calculator.c:465 #, c-format msgid "Use the %s System Service" msgstr "Bain úsáid as an Seirbhís Córais %s" #: src/bz-safety-calculator.c:469 #, c-format msgid "Use the %s Session Service" msgstr "Bain úsáid as an tSeirbhís Seisiúin %s" #: src/bz-safety-calculator.c:473 #, c-format msgid "Use the %s Service" msgstr "Bain úsáid as an tseirbhís %s" #: src/bz-safety-calculator.c:483 msgid "Can see the non-portal service" msgstr "Is féidir an tseirbhís neamh-thairseach a fheiceáil" #: src/bz-safety-calculator.c:485 msgid "Can talk to the non-portal service" msgstr "Is féidir labhairt leis an tseirbhís neamh-thairseach" #: src/bz-safety-calculator.c:487 msgid "Can own the non-portal service" msgstr "Is féidir leis an tseirbhís neamh-thairsí a bheith i seilbh" #: src/bz-safety-dialog.blp:7 msgid "Safety" msgstr "Sábháilteacht" #: src/bz-safety-dialog.blp:31 msgid "Safe" msgstr "Sábháilte" #: src/bz-safety-dialog.blp:50 msgid "Details" msgstr "Sonraí" #: src/bz-safety-dialog.blp:53 msgid "License" msgstr "Ceadúnas" #: src/bz-safety-dialog.blp:62 msgid "App ID" msgstr "Aitheantas Aipe" #: src/bz-safety-dialog.blp:71 msgid "SDK" msgstr "SDK" #: src/bz-safety-dialog.blp:98 msgid "" "This app uses an outdated version of the software platform (SDK) and might " "contain bugs or security vulnerabilities which will not be fixed." msgstr "" "Úsáideann an aip seo leagan atá as dáta den ardán bogearraí (SDK) agus " "d'fhéadfadh fabhtanna nó leochaileachtaí slándála a bheith ann nach ndéanfar " "a shocrú." #: src/bz-safety-dialog.c:222 #, c-format msgid "%s is Safe" msgstr "Tá %s sábháilte" #: src/bz-safety-dialog.c:227 #, c-format msgid "%s has no Unsafe Permissions" msgstr "Níl aon Cheadanna Neamhshábháilte ag %s" #: src/bz-safety-dialog.c:232 #, c-format msgid "%s is Probably Safe" msgstr "Is dócha go bhfuil %s sábháilte" #: src/bz-safety-dialog.c:237 #, c-format msgid "%s is Possibly Unsafe" msgstr "B’fhéidir go bhfuil %s neamhshábháilte" #: src/bz-safety-dialog.c:242 #, c-format msgid "%s is Unsafe" msgstr "Tá %s neamhshábháilte" #: src/bz-screenshot-page.blp:5 msgid "Screenshots" msgstr "Seat scáileáin" #: src/bz-screenshot-page.blp:61 msgid "Previous Screenshot" msgstr "An seat scáileán roimhe seo" #: src/bz-screenshot-page.blp:71 msgid "Next Screenshot" msgstr "An seat scáileán eile" #: src/bz-screenshot-page.blp:87 msgid "Copy Image" msgstr "Cóipeáil íomhá" #: src/bz-screenshot-page.blp:147 msgid "Reset View" msgstr "Athshocraigh an Amharc" #: src/bz-screenshot-page.blp:158 msgid "Zoom Out" msgstr "Súmáil amach" #: src/bz-screenshot-page.blp:168 msgid "Zoom In" msgstr "Súmáil isteach" #: src/bz-screenshots-carousel.blp:5 msgid "Screenshots Carousel" msgstr "Roithleagán Seat scáileáin" #: src/bz-screenshots-carousel.blp:103 msgid "Open Screenshot Viewer" msgstr "Oscail Amharcóir Seat scáileáin" #: src/bz-search-widget.blp:107 msgid "Search Apps, Games, Software" msgstr "Cuardaigh Aipeanna, Cluichí, Bogearraí" #: src/bz-search-widget.blp:146 msgid "Categories Unavailable" msgstr "Catagóirí Gan Fáil" #: src/bz-search-widget.blp:147 msgid "Search for apps using the search bar above." msgstr "Cuardaigh aipeanna ag baint úsáide as an mbarra cuardaigh thuas." #: src/bz-search-widget.blp:231 msgid "No Applications Found" msgstr "Níor aimsíodh aon fheidhmchláir" #: src/bz-search-widget.c:241 #, c-format msgid "No results found for \"%s\" in Flathub" msgstr "Níor aimsíodh aon torthaí le haghaidh \"%s\" i Flathub" #: src/bz-share-list.c:64 msgid "Copied!" msgstr "Cóipeáilte!" #: src/bz-share-list.c:116 msgid "Copy Link" msgstr "Cóipeáil Nasc" #: src/bz-share-list.c:127 msgid "Open Link" msgstr "Oscail an Nasc" #: src/bz-stats-dialog.blp:28 msgid "Timeline" msgstr "Amlíne" #: src/bz-stats-dialog.blp:46 msgid "Installs:" msgstr "Suiteálacha:" #: src/bz-stats-dialog.blp:55 msgid "World" msgstr "Domhan" #. Translators: M is the suffix for millions #: src/bz-stats-dialog.c:124 #, c-format msgid "%.2fM Total Installs" msgstr "%.2fM Suiteálacha Iomlána" #. Translators: K is the suffix for thousands #: src/bz-stats-dialog.c:127 #, c-format msgid "%.2fK Total Installs" msgstr "%.2fK Suiteálacha Iomlána" #: src/bz-stats-dialog.c:129 #, c-format msgid "%'d Total Installs" msgstr "%'d Suiteálacha Iomlána" #: src/bz-tag-list.c:96 msgid "No Results Found" msgstr "Níor aimsíodh aon torthaí" #: src/bz-tag-list.c:108 #, c-format msgid "Apps Tagged \"%s\"" msgstr "Aipeanna atá tagáilte \"%s\"" #: src/bz-tag-list.c:124 msgid "Search failed" msgstr "Theip ar an gcuardach" #: src/bz-transaction-dialog.c:159 msgid "Keep Data" msgstr "Coinnigh Sonraí" #: src/bz-transaction-dialog.c:160 msgid "Allow restoring settings and content" msgstr "Ceadaigh socruithe agus ábhar a athchóiriú" #: src/bz-transaction-dialog.c:169 msgid "Delete Data" msgstr "Scrios Sonraí" #: src/bz-transaction-dialog.c:170 msgid "Permanently remove app data to save space" msgstr "Bain sonraí aipeanna go buan chun spás a shábháil" #: src/bz-transaction-dialog.c:194 #, c-format msgid "Install %s?" msgstr "Suiteáil %s?" #: src/bz-transaction-dialog.c:197 msgid "May install additional shared components" msgstr "Féadfaidh sé comhpháirteanna comhroinnte breise a shuiteáil" #: src/bz-transaction-dialog.c:216 #, c-format msgid "Remove %s?" msgstr "Bain %s?" #: src/bz-transaction-dialog.c:220 #, c-format msgid "It will not be possible to use %s after it is uninstalled." msgstr "Ní bheidh sé indéanta %s a úsáid tar éis é a dhíshuiteáil." #: src/bz-transaction-dialog.c:240 #, c-format msgid "“%s” is High Risk" msgstr "Tá “%s” i mbaol ard" #: src/bz-transaction-dialog.c:244 msgid "" "This app has full access to your system, including all your files, " "browser history, saved passwords, and more. It also has access to the " "internet, meaning it could send your data to outside parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Tá rochtain iomlán ag an aip seo ar do chóras, lena n-áirítear do chuid " "comhad go léir, stair bhrabhsálaí, pasfhocail shábháilte, agus " "tuilleadh. Tá rochtain aici ar an idirlíon freisin, rud a chiallaíonn go " "bhféadfadh sí do shonraí a sheoladh chuig páirtithe seachtracha.\n" "\n" "Ós rud é gur aip dhílseánaigh í, ní féidir iniúchadh a dhéanamh uirthi " "maidir leis an méid a dhéanann sí leis na ceadanna seo." #: src/bz-transaction-dialog.c:253 msgid "" "This app uses the legacy X11 windowing system, which allows it to record " "all keystrokes, capture screenshots, and monitor other applications. It " "also has access to the internet, meaning it could send your data to outside " "parties.\n" "\n" "Because the app is proprietary, it can not be audited for what it does with " "these permissions." msgstr "" "Úsáideann an aip seo an seanchóras fuinneoige X11, rud a ligeann di gach " "eochairbhuille a thaifeadadh, scáileáin a ghabháil, agus monatóireacht a " "dhéanamh ar fheidhmchláir eile. Tá rochtain aici ar an idirlíon freisin, " "rud a chiallaíonn gur féidir léi do shonraí a sheoladh chuig páirtithe " "seachtracha.\n" "\n" "Ós rud é gur aip dhílseánaigh í, ní féidir iniúchadh a dhéanamh uirthi " "maidir leis an méid a dhéanann sí leis na ceadanna seo." #: src/bz-transaction-dialog.c:269 msgid "Install Anyway" msgstr "Suiteáil ar aon nós" #: src/bz-transaction-manager.c:1148 #, c-format msgid "Finished in %.02f seconds" msgstr "Críochnaithe i %.02f soicind" #: src/bz-transaction-view.blp:95 msgid "App Add-on" msgstr "Breiseán Aipe" #: src/bz-transaction-view.blp:120 msgid "Runtime" msgstr "Am rith" #: src/bz-transaction-view.blp:146 src/bz-transaction-view.blp:172 msgid "Install Size" msgstr "Méid Suiteála" #: src/bz-transaction-view.blp:187 src/bz-transaction-view.blp:238 #: src/bz-transaction-view.blp:264 src/bz-transaction.c:342 msgid "Pending" msgstr "Ar feitheamh" #: src/bz-transaction-view.blp:199 msgid "Ongoing" msgstr "Ar siúl" #: src/bz-transaction-view.blp:212 msgid "Finished" msgstr "Críochnaithe" #: src/bz-transaction-view.blp:251 msgid "Update" msgstr "Nuashonrú" #: src/bz-transaction-view.c:135 #, c-format msgid "Transferred %s so far" msgstr "Aistríodh %s go dtí seo" #: src/bz-update-dialog.blp:7 msgid "Update Now" msgstr "Nuashonraigh Anois" #: src/bz-update-dialog.blp:10 msgid "Updates Are Available" msgstr "Tá Nuashonruithe ar Fáil" #: src/bz-update-dialog.blp:11 msgid "" "The following applications are eligible for updates. Would you like to " "install them?" msgstr "" "Tá na feidhmchláir seo a leanas incháilithe le haghaidh nuashonruithe. Ar " "mhaith leat iad a shuiteáil?" #: src/bz-update-dialog.c:135 #, c-format msgid "" "%d runtimes and/or addons are eligible for updates. Would you like to " "install them?" msgstr "" "Tá %d rith-am agus/nó breiseán incháilithe le haghaidh nuashonruithe. Ar " "mhaith leat iad a shuiteáil?" #: src/bz-update-dialog.c:143 #, c-format msgid "Additionally, %d runtimes and/or addons will be updated." msgstr "Ina theannta sin, déanfar %d am rith agus/nó breiseán a nuashonrú." #: src/bz-user-data-page.blp:5 msgid "Manage Leftover User Data" msgstr "Bainistigh Sonraí Úsáideora atá Fágtha" #: src/bz-user-data-page.blp:55 msgid "No User Data found" msgstr "Níor aimsíodh aon sonraí úsáideora" #: src/bz-user-data-page.blp:60 msgid "User Data" msgstr "Sonraí Úsáideora" #: src/bz-user-data-tile.c:144 #, c-format msgid "Trashed User Data for %s" msgstr "Sonraí Úsáideora Bruscair do %s" #: src/bz-user-data-tile.blp:74 msgid "Trash User Data" msgstr "Bruscar Sonraí Úsáideora" #: src/bz-window.blp:107 msgid "Tasks" msgstr "Tascanna" #: src/bz-window.blp:163 msgid "Stop Active Tasks" msgstr "Stop Tascanna Gníomhacha" #: src/bz-window.blp:171 msgid "Clear History" msgstr "Glan an Stair" #: src/bz-window.blp:187 msgid "No Tasks Yet" msgstr "Gan aon tascanna fós" #: src/bz-window.blp:257 msgid "Refreshing Store Content" msgstr "Ábhar an tSiopa á Athnuachan" #: src/bz-window.blp:271 msgid "Curated" msgstr "Coimeádta" #: src/bz-window.blp:284 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:432 msgid "No background tasks!" msgstr "Gan aon tascanna cúlra!" #: src/bz-window.blp:490 msgid "" "You have a network connection but are viewing a cached version of Flathub" msgstr "" "Tá nasc líonra agat ach tá leagan taisceáilte de Flathub á fheiceáil agat" #: src/bz-window.blp:565 msgid "_Login with Flathub" msgstr "_Logáil isteach le Flathub" #: src/bz-window.blp:571 msgid "_Manage Leftover User Data" msgstr "_Bainistigh Sonraí Úsáideora atá Fágtha" #: src/bz-window.blp:576 msgid "_Synchronize Remotes" msgstr "_Sioncrónaigh Cianrialtáin" #: src/bz-window.blp:617 msgid "Log Out" msgstr "Logáil Amach" #: src/bz-window.c:435 #, c-format msgid "%d Update Available" msgid_plural "%d Updates Available" msgstr[0] "%d Nuashonrú Ar Fáil" msgstr[1] "%d Nuashonruithe Ar Fáil" msgstr[2] "%d Nuashonruithe Ar Fáil" #: src/bz-window.c:872 msgid "" "The ability to inspect and install local .flatpak bundle files is coming " "soon! In the meantime, try running\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "on the command line." msgstr "" "Beidh an cumas comhaid phacáiste .flatpak áitiúla a iniúchadh agus a " "shuiteáil ag teacht go luath! Idir an dá linn, bain triail as\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "a rith ar an líne ordaithe." #: src/bz-window.c:1010 msgid "Can't do that right now!" msgstr "Ní féidir liom é sin a dhéanamh faoi láthair!" #: src/bz-window.c:1080 msgid "Resume Current Tasks" msgstr "Lean ar aghaidh le Tascanna Reatha" #: src/bz-window.c:1086 msgid "Pause Current Tasks" msgstr "Cuir Tascanna Reatha ar Sos" #: src/bz-world-map.c:572 #, c-format msgid "%s: %'u downloads" msgstr "%s: %'u íoslódálacha" #: src/gtk/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Ginearálta" #: src/gtk/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "Oscail Dialóg Cuardaigh" #: src/gtk/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Open Preferences" msgstr "Oscail Roghanna" #: src/gtk/shortcuts-dialog.blp:19 msgctxt "shortcut window" msgid "Synchronize Remotes" msgstr "Sioncrónaigh Cianrialtáin" #: src/gtk/shortcuts-dialog.blp:24 msgctxt "shortcut window" msgid "Toggle Transaction Manager" msgstr "Bainisteoir Idirbheart a Athrú" #: src/gtk/shortcuts-dialog.blp:29 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Taispeáin Aicearraí" #: src/gtk/shortcuts-dialog.blp:34 msgctxt "shortcut window" msgid "Quit" msgstr "Scoir" bazaar-orig-v0.7.14/po/bg.po0000664000175000017500000011026115166123241014507 0ustar hasanhasan# Copyright (C) 2025 THE bazaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the bazaar package. # Automatically generated, 2025. # twlvnn kraftwerk , 2025 # msgid "" msgstr "" "Project-Id-Version: bazaar\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-10-18 06:40+0200\n" "PO-Revision-Date: 2025-10-19 11:04+0200\n" "Last-Translator: twlvnn kraftwerk \n" "Language-Team: Bulgarian\n" "Language: bg\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.8\n" #: data/io.github.kolunmi.Bazaar.desktop.in:2 data/io.github.kolunmi.Bazaar.metainfo.xml.in:7 src/bz-window.blp:5 src/bz-window.blp:51 msgid "Bazaar" msgstr "Базар" #: data/io.github.kolunmi.Bazaar.desktop.in:3 msgid "Add, remove or update flatpak software on this computer" msgstr "Добавяйте, премахвайте или обновете flatpak софтуер на този компютър" #: data/io.github.kolunmi.Bazaar.desktop.in:9 msgid "GTK;System;PackageManager;Discover;Flatpak;Software;Store;" msgstr "GTK;System;PackageManager;Discover;Flatpak;Software;Store;система;мениджър на пакети;откриване;софтуер;програми;" #: data/io.github.kolunmi.Bazaar.gschema.xml:6 msgid "Show Git Forge Star Counts" msgstr "Показване на броя на звездите в Git Forge" #: data/io.github.kolunmi.Bazaar.gschema.xml:7 msgid "Whether to attempt to detect and show \"star counts\" for projects in the full view" msgstr "Дали да се опита да се засече и покаже „броя на звездите“ за проектите в пълния изглед" #: data/io.github.kolunmi.Bazaar.gschema.xml:11 src/bz-preferences-dialog.blp:25 msgid "Only Show Free Software" msgstr "Показване само на свободен софтуер" #: data/io.github.kolunmi.Bazaar.gschema.xml:12 msgid "Hide proprietary software when searching" msgstr "Скриване на собственически софтуер при търсене" #: data/io.github.kolunmi.Bazaar.gschema.xml:16 msgid "Show Only Flathub Content" msgstr "Показване само на Flathub съдържание" #: data/io.github.kolunmi.Bazaar.gschema.xml:17 msgid "Filter search results to only show applications available on Flathub" msgstr "Филтриране на резултатите от търсенето, за да се показват само програмите, налични в Flathub" #: data/io.github.kolunmi.Bazaar.gschema.xml:21 msgid "Debounce Search Inputs" msgstr "Забавяне на входа за търсене" #: data/io.github.kolunmi.Bazaar.gschema.xml:22 msgid "Add a delay before searching to prevent instant replies while typing" msgstr "Добавяне на закъснение преди търсенето, за да се предотвратят незабавни резултати по време на писане" #: data/io.github.kolunmi.Bazaar.gschema.xml:40 msgid "Global Progress Bar Theme" msgstr "Тема за глобалната лента за напредък" #: data/io.github.kolunmi.Bazaar.gschema.xml:41 msgid "Describes the look of the global progress bar" msgstr "Описва вида на глобалната лента за напредък" #: data/io.github.kolunmi.Bazaar.gschema.xml:45 msgid "Saved Window Dimensions" msgstr "Запазени размери на прозореца" #: data/io.github.kolunmi.Bazaar.gschema.xml:46 msgid "The window dimensions to be used by the next Bazaar window" msgstr "Размерите на прозореца, които ще се използват от следващия прозорец на Базар" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:8 msgid "Discover and install applications" msgstr "Открийте и инсталирайте програми" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:10 msgid "A new app store for GNOME with a focus on discovering and installing applications and addons from Flatpak remotes, particularly Flathub." msgstr "" "Нов магазин за програми за GNOME, предназначен за откриването и инсталирането на програми и добавки от Flatpak отдалечени хранилища, по-" "специфично Flathub." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:14 msgid "" "It emphasizes supporting the developers who make the Linux desktop possible. Bazaar features a \"curated\" tab that can be configured by " "distributors to allow for a more localized experience." msgstr "" "Той взема под внимание подкрепата на разработчиците, които правят Луникс за настолни компютри възможен. Bazaar разполага с раздел „подбрани“, " "който може да бъде настроен от дистрибуторите, за да позволи по-специализирано потребителско изживяване." #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:22 src/bz-application.c:496 msgid "Adam Masciola" msgstr "Adam Masciola" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:47 msgid "The home view displaying Flathub apps" msgstr "Началната страница, показваща програми на Flathub" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:51 msgid "Nucleus app page" msgstr "Страницата на Nucleus" #: data/io.github.kolunmi.Bazaar.metainfo.xml.in:55 msgid "Searching for Blender" msgstr "Търсене за Blender" #: src/bz-addons-dialog.blp:13 msgid "Manage Addons" msgstr "Управление на добавки" #: src/bz-app-size-dialog.c:55 msgid "Of the size of human DNA" msgstr "" #: src/bz-app-size-dialog.c:55 msgid "3 billion base pairs" msgstr "" #: src/bz-app-size-dialog.c:56 msgid "Of the Linux Kernel" msgstr "" #: src/bz-app-size-dialog.c:56 msgid "linux-6.17.tar.xz" msgstr "linux-6.17.tar.xz" #: src/bz-app-size-dialog.c:57 msgid "Of the Apollo 11 guidance computer" msgstr "" #: src/bz-app-size-dialog.c:57 msgid "Total ROM and RAM" msgstr "" #: src/bz-app-size-dialog.c:58 msgid "Of the original Super Mario Bros" msgstr "" #: src/bz-app-size-dialog.c:58 msgid "On the NES" msgstr "" #: src/bz-app-size-dialog.c:59 msgid "Of the size of Wikipedia" msgstr "" #: src/bz-app-size-dialog.c:59 msgid "Without any media" msgstr "" #: src/bz-app-size-dialog.blp:43 msgid "--- MB" msgstr "--- МБ" #: src/bz-app-size-dialog.blp:53 src/bz-full-view.blp:351 msgid "Download Size" msgstr "Размер за изтегляне" #: src/bz-application.c:392 msgid "This functionality is currently disabled. It is recommended you download and install Flatseal to manage app permissions." msgstr "Тази функционалност е деактивирана в момента. Препоръчваме да изтеглите и инсталирате Flatseal, за да управлявате права̀та на програмите." #: src/bz-application.c:456 msgctxt "About Dialog Developer Credit" msgid "Adam Masciola " msgstr "Adam Masciola " #: src/bz-application.c:457 msgctxt "About Dialog Developer Credit" msgid "Alexander Vanhee" msgstr "Alexander Vanhee" #. Translators: Put one translator per line, in the form NAME , YEAR1, YEAR2 #: src/bz-application.c:481 msgid "translator-credits" msgstr "twlvnn kraftwerk" #: src/bz-application.c:462 msgctxt "About Dialog Translator Credit" msgid "Ahmed Najmawi" msgstr "Ahmed Najmawi" #: src/bz-application.c:463 msgctxt "About Dialog Translator Credit" msgid "AtomHare" msgstr "AtomHare" #: src/bz-application.c:464 msgctxt "About Dialog Translator Credit" msgid "Azenyr" msgstr "Azenyr" #: src/bz-application.c:465 msgctxt "About Dialog Translator Credit" msgid "Goudarz Jafari" msgstr "Goudarz Jafari" #: src/bz-application.c:466 msgctxt "About Dialog Translator Credit" msgid "Jill Fiore (Lumaeris)" msgstr "Jill Fiore (Lumaeris)" #: src/bz-application.c:467 msgctxt "About Dialog Translator Credit" msgid "João Victor (Leal)" msgstr "João Victor (Leal)" #: src/bz-application.c:468 msgctxt "About Dialog Translator Credit" msgid "KiKaraage" msgstr "KiKaraage" #: src/bz-application.c:469 msgctxt "About Dialog Translator Credit" msgid "Lucosec" msgstr "Lucosec" #: src/bz-application.c:470 msgctxt "About Dialog Translator Credit" msgid "Léane GRASSER" msgstr "Léane GRASSER" #: src/bz-application.c:471 msgctxt "About Dialog Translator Credit" msgid "Marcel Mrówka (Microwave)" msgstr "Marcel Mrówka (Microwave)" #: src/bz-application.c:472 msgctxt "About Dialog Translator Credit" msgid "Peter Dave Hello" msgstr "Peter Dave Hello" #: src/bz-application.c:473 msgctxt "About Dialog Translator Credit" msgid "Pietro F." msgstr "Pietro F." #: src/bz-application.c:474 msgctxt "About Dialog Translator Credit" msgid "Shihfu Juan" msgstr "Shihfu Juan" #: src/bz-application.c:475 msgctxt "About Dialog Translator Credit" msgid "Shinsei" msgstr "Shinsei" #: src/bz-application.c:476 msgctxt "About Dialog Translator Credit" msgid "Vlastimil Dědek" msgstr "Vlastimil Dědek" #: src/bz-application.c:477 msgctxt "About Dialog Translator Credit" msgid "asen23" msgstr "asen23" #: src/bz-application.c:478 msgctxt "About Dialog Translator Credit" msgid "camegone" msgstr "camegone" #: src/bz-application.c:479 msgctxt "About Dialog Translator Credit" msgid "renner" msgstr "renner" #: src/bz-application.c:480 msgctxt "About Dialog Translator Credit" msgid "robotta" msgstr "robotta" #: src/bz-application.c:1019 msgid "Constructing Flatpak instance..." msgstr "Изграждане на Flatpak инстанция..." #: src/bz-application.c:1036 msgid "Reusing last Flatpak instance..." msgstr "Преизползване на последната Flatpak инстанция…" #: src/bz-application.c:1061 msgid "Flathub is not registered on this system" msgstr "Flathub не е регистриран в тази система" #: src/bz-application.c:1064 msgid "Would you like to add Flathub as a remote? If you decline, the Flathub page will not be available. You can change this later." msgstr "" "Искате ли да добавите Flathub като отдалечено хранилище? Ако откажете, страницата на Flathub няма да бъде достъпна. Може да промените това по-" "късно." #: src/bz-application.c:1069 src/bz-update-dialog.blp:6 msgid "Later" msgstr "По-късно" #: src/bz-application.c:1070 msgid "Add Flathub" msgstr "Добавяне на Flathub" #: src/bz-application.c:1102 #, c-format msgid "Identifying installed entries..." msgstr "Идентифициране на инсталираните записи..." #: src/bz-application.c:1114 #, c-format msgid "Beginning remote entry retrieval while referencing %d blocklist(s)..." msgstr "Получаване на отдалечените записи и четене от %d списък(а) за блокиране..." #: src/bz-application.c:1262 #, c-format msgid "Receiving Entries" msgstr "Получаване на записите" #: src/bz-application.c:1263 #, c-format msgid "%'d of %'d" msgstr "%'d от %'d" #: src/bz-application.c:1273 #, c-format msgid "Waiting for background indexing tasks to catch up..." msgstr "Изчакване на задачите за индексиране във фона да настигнат…" #: src/bz-application.c:1309 #, c-format msgid "Completed initialization in %0.2f seconds" msgstr "Инициализацията завърши за %0.2f секунди" #: src/bz-application.c:1314 msgid "Checking for updates..." msgstr "Проверяване за обновления..." #: src/bz-application.c:1353 msgid "Synchronizing..." msgstr "Синхронизиране..." #: src/bz-browse-widget.blp:11 src/bz-flathub-page.blp:11 src/bz-full-view.blp:10 src/bz-installed-page.blp:11 src/bz-window.blp:151 msgid "Empty" msgstr "Празно" #: src/bz-browse-widget.blp:15 msgid "No Curated Applications" msgstr "Няма подбрани програми" #: src/bz-browse-widget.blp:16 msgid "Bazaar was not provided a curated content configuration. Contact your operating system's support channels for assistance." msgstr "Bazaar не разполага с настройки за подбрано съдържание. Свържете се с каналите за поддръжка на вашата операционна система за помощ." #: src/bz-browse-widget.blp:22 src/bz-flathub-page.blp:22 msgid "Browser" msgstr "Браузър" #: src/bz-entry-inspector.blp:5 msgid "Entry Inspector" msgstr "Инспектор на записите" #: src/bz-entry-inspector.blp:76 msgid "Serialize" msgstr "Сериализиране" #: src/bz-entry-inspector.blp:80 msgid "Convert to JSON" msgstr "Преобразуване в JSON" #: src/bz-error.c:68 msgid "An Error Occurred" msgstr "Възникна грешка" #: src/bz-error.c:89 msgid "Close" msgstr "Затваряне" #: src/bz-error.c:90 msgid "Copy and Close" msgstr "Копиране и затваряне" #: src/bz-flathub-category.c:290 msgid "Audio & Video" msgstr "Аудио & видео" #: src/bz-flathub-category.c:292 msgid "Development" msgstr "Разработка" #: src/bz-flathub-category.c:294 msgid "Education" msgstr "Образование" #: src/bz-flathub-category.c:296 msgid "Games" msgstr "Игри" #: src/bz-flathub-category.c:298 msgid "Graphics" msgstr "Графика" #: src/bz-flathub-category.c:300 msgid "Networking" msgstr "Интернет" #: src/bz-flathub-category.c:302 msgid "Office" msgstr "Офис" #: src/bz-flathub-category.c:304 msgid "Science" msgstr "Наука" #: src/bz-flathub-category.c:306 msgid "System" msgstr "Система" #: src/bz-flathub-category.c:308 msgid "Utilities" msgstr "Инструменти" #: src/bz-flathub-page.blp:15 msgid "Flathub Not Added" msgstr "Flathub не беше добавен" #: src/bz-flathub-page.blp:16 msgid "The Flathub remote was not found on any of your flatpak installations" msgstr "Отдалеченото Flathub хранилище не беше намерено в нито една от вашите инсталации на flatpak" #: src/bz-flathub-page.blp:70 src/bz-flathub-page.c:185 msgid "Trending" msgstr "Популярни" #: src/bz-flathub-page.blp:101 msgid "More Trending" msgstr "Още набиращи популярност" #: src/bz-flathub-page.blp:117 msgid "Categories" msgstr "Категории" #: src/bz-flathub-page.blp:154 src/bz-flathub-page.c:195 msgid "Recently Updated" msgstr "Наскоро обновени" #: src/bz-flathub-page.blp:185 msgid "More Updated" msgstr "Още обновени" #: src/bz-flathub-page.blp:206 src/bz-flathub-page.c:205 msgid "Recently Added" msgstr "Наскоро добавени" #: src/bz-flathub-page.blp:237 msgid "More Added" msgstr "Още добавени" #: src/bz-flathub-page.blp:258 src/bz-flathub-page.c:215 msgid "Popular" msgstr "Популярни" #: src/bz-flathub-page.blp:289 msgid "More Popular" msgstr "Още популярни" #: src/bz-flatpak-entry.c:507 msgctxt "Project URL Type" msgid "Flathub Page" msgstr "Flathub страницата" #: src/bz-flatpak-entry.c:526 msgctxt "Project URL Type" msgid "Homepage" msgstr "Начална страница" #: src/bz-flatpak-entry.c:529 msgctxt "Project URL Type" msgid "Issue Tracker" msgstr "Система за проблеми" #: src/bz-flatpak-entry.c:532 msgctxt "Project URL Type" msgid "FAQ" msgstr "ЧЗВ" #: src/bz-flatpak-entry.c:535 msgctxt "Project URL Type" msgid "Help" msgstr "Помощ" #: src/bz-flatpak-entry.c:538 msgctxt "Project URL Type" msgid "Donate" msgstr "Дарете" #: src/bz-flatpak-entry.c:543 msgctxt "Project URL Type" msgid "Translate" msgstr "Превод" #: src/bz-flatpak-entry.c:546 msgctxt "Project URL Type" msgid "Contact" msgstr "Контакти" #: src/bz-flatpak-entry.c:549 msgctxt "Project URL Type" msgid "Source Code" msgstr "Изходен код" #: src/bz-flatpak-entry.c:554 msgctxt "Project URL Type" msgid "Contribute" msgstr "Допринесете" #: src/bz-full-view.blp:14 msgid "No Results" msgstr "Няма резултати" #: src/bz-full-view.blp:15 msgid "Try a different search query" msgstr "Oпитайте различно търсене" #: src/bz-full-view.blp:21 src/bz-window.blp:161 msgid "Content" msgstr "Съдържание" #: src/bz-full-view.blp:129 msgid "This flatpak is verified by the original developers of the software." msgstr "Този flatpak е проверен от оригиналните разработчици на софтуера." #: src/bz-full-view.blp:156 msgid "Support" msgstr "Подкрепи" #: src/bz-full-view.blp:176 msgid "Repository Star Count" msgstr "Брой звезди на хранилището" #: src/bz-full-view.blp:207 msgid "Run Application" msgstr "Изпълняване на програмата" #: src/bz-full-view.blp:221 msgid "Download & Install Application" msgstr "Изтегляне и инсталиране на програмата" #: src/bz-full-view.blp:224 src/bz-transaction-view.blp:108 src/bz-window.c:1071 msgid "Install" msgstr "Инсталиране" #: src/bz-full-view.blp:236 msgid "Uninstall Application" msgstr "Деинсталиране на програмата" #: src/bz-full-view.blp:251 src/bz-installed-page.blp:125 msgid "Manage Add-ons" msgstr "Управление на добавки" #: src/bz-full-view.blp:264 msgid "Install Other Version" msgstr "Инсталиране на друга версия" #: src/bz-full-view.blp:279 msgid "Share this application" msgstr "Споделете тази програма" #: src/bz-full-view.blp:362 msgid "Excludes shared components" msgstr "Изключва споделени компоненти" #: src/bz-full-view.blp:418 msgid "Free Software" msgstr "Свободен софтуер" #: src/bz-full-view.blp:460 msgid "Proprietary" msgstr "Собственически" #: src/bz-full-view.blp:471 msgid "Source code may not be available" msgstr "Изходният код може да не е наличен" #: src/bz-full-view.blp:526 msgid "Click for details" msgstr "Натиснете за подробности" #: src/bz-full-view.blp:592 msgid "Repositories" msgstr "Хранилища" #: src/bz-full-view.blp:623 src/bz-full-view.blp:631 msgid "Project Website" msgstr "Уеб сайт на проекта" #: src/bz-full-view.blp:639 msgid "Open in browser" msgstr "Отваряне в Интернет браузър" #: src/bz-full-view.c:213 #, c-format msgid "%'d Monthly Downloads" msgstr "%'d месечни изтегляния" #: src/bz-full-view.c:215 msgid "--- Downloads" msgstr "--- изтегляния" #: src/bz-full-view.c:241 msgid "Unknown" msgstr "Неизвестно" #. Translators: This is a date format for timestamps from previous years. Used in the app releases section. #. * %B is the full month name, %e is the day, %Y is the year. #. * Example: "October 1, 2025" #. * See https://docs.gtk.org/glib/method.DateTime.format.html for format options #. * Please modify to make it sound natural in your locale. #. * #: src/bz-full-view.c:268 msgid "%B %-d, %Y" msgstr "%-d %B, %Y" #. Translators: This is a date format for timestamps from the current year. Used in the app releases section. #. * %B is the full month name, %e is the day. #. * Example: "October 1" #. * See https://docs.gtk.org/glib/method.DateTime.format.html for format options #. * Please modify to make it sound natural in your locale. #. * #: src/bz-full-view.c:276 msgid "%B %-d" msgstr "%-d %B" #: src/bz-full-view.c:287 msgid "No URL" msgstr "Няма адрес" #: src/bz-full-view.c:305 msgid "This application has a FLOSS license, meaning the source code can be audited for safety." msgstr "Това приложение има FLOSS лиценз, което означава, че изходният код може да бъде проверен за сигурност." #: src/bz-full-view.c:306 msgid "" "This application has a proprietary license, meaning the source code is developed privately and cannot be audited by an independent third party." msgstr "" "Тази програма има собственически лиценз, което означава, че изходният код е разработен частно и не може да бъде проверен от независими трети " "лица." #: src/bz-full-view.c:596 #, c-format msgid "Version %s" msgstr "Версия %s" #: src/bz-full-view.c:621 msgid "No details for this release" msgstr "Няма подробности за това издание" #: src/bz-inspector.blp:5 msgid "Bazaar Inspector" msgstr "Базар инспектор" #: src/bz-inspector.blp:22 msgid "Active Blocklists" msgstr "Активни списъци за блокиране" #: src/bz-inspector.blp:44 msgid "Active Curated-Configs" msgstr "" #: src/bz-inspector.blp:66 msgid "All Entry Groups" msgstr "Всички групи за запис" #: src/bz-inspector.blp:69 msgid "Filter..." msgstr "Филтриране…" #: src/bz-inspector.blp:110 msgid "Decache and Inspect" msgstr "Декаширане и изследване" #: src/bz-installed-page.blp:15 msgid "No Flatpaks Installed" msgstr "Няма инсталирани Flatpak програми" #: src/bz-installed-page.blp:21 src/bz-window.blp:302 src/bz-window.blp:395 msgid "Installed" msgstr "Инсталирани" #: src/bz-installed-page.blp:101 msgid "Support this application" msgstr "Подкрепете тази програма" #: src/bz-installed-page.blp:151 src/bz-window.c:1093 msgid "Remove" msgstr "Премахване" #: src/bz-installed-page.blp:178 msgid "More actions" msgstr "Допълнителни действия" #: src/bz-installed-page.blp:197 msgid "Run this application" msgstr "Изпълняване на тази програма" #: src/bz-installed-page.blp:209 msgid "Run" msgstr "Изпълняване" #: src/bz-installed-page.blp:221 src/bz-installed-page.blp:232 msgid "View Store Page" msgstr "Вижте страницата в магазина" #: src/bz-installed-page.c:649 msgid "Choose an Installation" msgstr "Изберете инсталация" #: src/bz-installed-page.c:652 msgid "You have multiple versions of this app installed. Which one would you like to proceed with? " msgstr "Имате инсталирани няколко версии на тази програма. Коя от тях искате да използвате? " #: src/bz-installed-page.c:656 src/bz-window.c:1070 src/bz-window.c:1092 msgid "Cancel" msgstr "Отказване" #: src/bz-preferences-dialog.blp:9 msgid "Preferences" msgstr "Настройки" #: src/bz-preferences-dialog.blp:13 msgid "Application Details" msgstr "Подробности за програмата" #: src/bz-preferences-dialog.blp:16 msgid "Git Forge Star Counts" msgstr "Брой звезди в Git Forge" #: src/bz-preferences-dialog.blp:17 msgid "Not having a GitHub access token may trigger rate limits" msgstr "Липсата на токен за достъп до GitHub може да доведе до ограничения на скоростта" #: src/bz-preferences-dialog.blp:22 src/bz-window.blp:43 src/bz-window.blp:58 src/bz-window.blp:334 msgid "Search" msgstr "Търсене" #: src/bz-preferences-dialog.blp:26 msgid "Hide proprietary applications from search results" msgstr "Скриване на собственическите програми от резултатите от търсенето" #: src/bz-preferences-dialog.blp:30 msgid "Show Only Flathub Apps" msgstr "Показване само на Flathub програми" #: src/bz-preferences-dialog.blp:31 msgid "Limit search results to applications available on Flathub" msgstr "Ограничаване на резултатите от търсенето до програмите, налични в Flathub" #: src/bz-preferences-dialog.blp:35 msgid "Debounce Search Results" msgstr "Забавяне на резултатите за търсене" #: src/bz-preferences-dialog.blp:36 msgid "Wait for a brief pause to reduce system load" msgstr "Изчакване за кратко, за да се намали натоварването на системата" #: src/bz-preferences-dialog.blp:41 msgid "Global Progress Bar" msgstr "Глобална лента за напредъка" #: src/bz-preferences-dialog.blp:44 msgid "Theme" msgstr "Тема" #: src/bz-preferences-dialog.blp:45 msgid "Choose a fun theme for the global progress bar!" msgstr "Изберете забавна тема за глобалната лента за напредъка!" #: src/bz-preferences-dialog.blp:48 msgid "Accent Color" msgstr "Акцентиращ цвят" #: src/bz-preferences-dialog.blp:49 msgid "Pride Rainbow Flag" msgstr "Прайд ЛГБТ флаг" #: src/bz-preferences-dialog.blp:50 msgid "Lesbian Pride Flag" msgstr "" #: src/bz-preferences-dialog.blp:51 msgid "Transgender Flag" msgstr "" #: src/bz-preferences-dialog.blp:52 msgid "Nonbinary Flag" msgstr "" #: src/bz-preferences-dialog.blp:53 msgid "Bisexual Flag" msgstr "" #: src/bz-preferences-dialog.blp:54 msgid "Asexual Flag" msgstr "" #: src/bz-preferences-dialog.blp:55 msgid "Pansexual Flag" msgstr "" #: src/bz-preferences-dialog.blp:56 msgid "Aromantic Flag" msgstr "" #: src/bz-preferences-dialog.blp:57 msgid "Genderfluid Flag" msgstr "" #: src/bz-preferences-dialog.blp:58 msgid "Polysexual Flag" msgstr "" #: src/bz-preferences-dialog.blp:59 msgid "Omnisexual Flag" msgstr "" #: src/bz-search-widget.blp:69 msgid "Search Apps" msgstr "Търсете програми" #: src/bz-share-dialog.blp:13 msgid "Share" msgstr "Споделяне" #: src/bz-share-dialog.c:62 msgid "Copied!" msgstr "Копирано!" #: src/bz-share-dialog.c:106 msgid "Copy Link" msgstr "Копиране на връзката" #: src/bz-share-dialog.c:117 msgid "Open Link" msgstr "Отваряне на връзката" #: src/bz-stats-dialog.blp:26 msgid "Timeline" msgstr "Хронология" #: src/bz-stats-dialog.blp:31 msgid "Installs:" msgstr "Инсталации:" #: src/bz-stats-dialog.blp:37 msgid "World" msgstr "Глобално" #: src/bz-transaction-manager.c:1140 #, c-format msgid "Finished in %.02f seconds" msgstr "Завърши за %.02f секунди" #: src/bz-transaction-view.blp:95 msgid "Install Size" msgstr "Размер за инсталирани" #: src/bz-transaction-view.blp:238 msgid "Error Details" msgstr "Подробности за грешката" #: src/bz-transaction-view.c:139 #, c-format msgid "Transferred %s so far" msgstr "Прехвърлени са %s до момента" #: src/bz-transaction.c:336 msgid "Pending" msgstr "В опашката" #: src/bz-update-dialog.blp:7 msgid "Install Now" msgstr "Инсталиране сега" #: src/bz-update-dialog.blp:10 msgid "Updates Are Available" msgstr "Налични са обновления" #: src/bz-update-dialog.blp:11 msgid "The following applications are eligible for updates. Would you like to install them?" msgstr "Следните програми имат обновления. Искате ли да ги инсталирате?" #: src/bz-update-dialog.c:134 #, c-format msgid "%d runtimes and/or addons are eligible for updates. Would you like to install them?" msgstr "%d среди за изпълнение и/или добавки имат обновления. Искате ли да ги инсталирате?" #: src/bz-update-dialog.c:142 #, c-format msgid "Additionally, %d runtimes and/or addons will be updated." msgstr "Освен това, %d среди за изпълнение и/или добавки ще бъдат обновени." #: src/bz-window.blp:80 msgid "Transactions" msgstr "Операции" #: src/bz-window.blp:95 src/bz-window.blp:414 msgid "Toggle transaction sidebar" msgstr "Превключване на страничната лента за операции" #: src/bz-window.blp:131 msgid "Stop Active Tasks" msgstr "Спиране на работещите задачи" #: src/bz-window.blp:139 msgid "Clear History" msgstr "Изчистване на историята" #: src/bz-window.blp:155 msgid "No Tasks Yet" msgstr "Все още няма задачи" #: src/bz-window.blp:210 src/bz-window.blp:214 msgid "Offline" msgstr "Няма връзка" #: src/bz-window.blp:220 msgid "Loading" msgstr "Зареждане" #: src/bz-window.blp:268 msgid "Browse" msgstr "Разглеждане" #: src/bz-window.blp:278 msgid "App View" msgstr "Изглед на програмата" #: src/bz-window.blp:292 src/bz-window.blp:388 msgid "Flathub" msgstr "Flathub" #: src/bz-window.blp:322 msgid "Go Back" msgstr "Назад" #: src/bz-window.blp:347 msgid "Update" msgstr "Обновяване" #: src/bz-window.blp:377 msgid "View curated applications" msgstr "Вижте подбрани програми" #: src/bz-window.blp:381 msgid "Curated" msgstr "Подбрани" #: src/bz-window.blp:385 msgid "View the latest on Flathub" msgstr "Вижте най-новите програми във Flathub" #: src/bz-window.blp:392 msgid "View installed applications" msgstr "Вижте инсталираните програми" #: src/bz-window.blp:437 msgid "Main Menu" msgstr "Основно меню" #: src/bz-window.blp:471 msgid "_Quit Service" msgstr "_Спиране на услугата" #: src/bz-window.blp:476 msgid "_Refresh Content" msgstr "_Опресняване на съдържанието" #: src/bz-window.blp:481 msgid "_Preferences" msgstr "_Настройки" #: src/bz-window.blp:486 msgid "_Keyboard Shortcuts" msgstr "_Клавишни комбинации" #: src/bz-window.blp:491 msgid "_About Bazaar" msgstr "_Относно Базар" #: src/bz-window.blp:496 msgid "_Donate to Bazaar ❤️" msgstr "_Дарете за Базар ❤️" #: src/bz-window.c:628 msgid "Up to date!" msgstr "Всичко е обновено!" #: src/bz-window.c:800 msgid "" "The ability to inspect and install local .flatpak bundle files is coming soon! In the meantime, try running\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "on the command line." msgstr "" "Функцията за проверяване и инсталиране на локални .flatpak пакетни файлове ще бъде достъпна скоро! Междувременно, опитайте да изпълните\n" "\n" "flatpak install --bundle your-bundle.flatpak\n" "\n" "в командния ред." #: src/bz-window.c:935 msgid "Can't do that right now!" msgstr "Това действие не може да се извърши сега!" #: src/bz-window.c:1064 #, c-format msgid "Install %s?" msgstr "Инсталиране на %s?" #: src/bz-window.c:1067 msgid "May install additional shared components" msgstr "Може да инсталира допълнителни споделени компоненти" #: src/bz-window.c:1086 #, c-format msgid "Remove %s?" msgstr "Премахване на %s?" #: src/bz-window.c:1089 msgid "Settings & user data will be kept" msgstr "Настройките и потребителските данни ще бъдат запазени" #: src/bz-window.c:1257 msgid "Resume Current Tasks" msgstr "Възобновяване на текущите задачи" #: src/bz-window.c:1263 msgid "Pause Current Tasks" msgstr "Пауза на текущите задачи" #: src/bz-world-map.c:523 #, c-format msgid "%s: %'u downloads" msgstr "%s: %'u изтегляния" #: src/gtk/shortcuts-dialog.blp:6 msgctxt "shortcut window" msgid "General" msgstr "Общи" #: src/gtk/shortcuts-dialog.blp:9 msgctxt "shortcut window" msgid "Open Search Dialog" msgstr "Отваряне на търсачката" #: src/gtk/shortcuts-dialog.blp:14 msgctxt "shortcut window" msgid "Refresh" msgstr "Опресняване" #: src/gtk/shortcuts-dialog.blp:19 msgctxt "shortcut window" msgid "Toggle Transaction Manager" msgstr "Превключване на мениджъра на операциите" #: src/gtk/shortcuts-dialog.blp:24 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Показване на клавишните комбинации" #: src/gtk/shortcuts-dialog.blp:29 msgctxt "shortcut window" msgid "Quit" msgstr "Спиране на програмата" #~ msgid "Show Animated Background" #~ msgstr "Animierten Hintergrund anzeigen" #~ msgid "Whether to show the animated icon background on the home page" #~ msgstr "Den animierten Hintergrund auf der Startseite anzeigen" #~ msgid "It emphasizes supporting the developers who make the Linux desktop possible." #~ msgstr "Es legt Wert darauf, die Entwickler zu unterstützen, die den Linux-Desktop möglich machen." #~ msgid "Calligraphy application page" #~ msgstr "Calligraphy" #~ msgid "Download graph for Blender" #~ msgstr "Downloadkurve für Blender" #, c-format #~ msgid "Received %'d entries out of %'d (%0.1f seconds elapsed)" #~ msgstr "%'d Einträge von %'d empfangen (%0.1f Sekunden vergangen)" #~ msgid "Apps Of The Week" #~ msgstr "Anwendungen der Woche" #~ msgid "Show More" #~ msgstr "Mehr anzeigen" #~ msgid "The number of downloads in the last 30 days. Click to view this application's download statistics." #~ msgstr "Die Anzahl der Downloads in den letzten 30 Tagen. Klicken Sie hier, um die Download-Statistiken für diese Anwendung anzuzeigen." #~ msgid "Support this developer" #~ msgstr "Diesen Entwickler unterstützen" #~ msgid "Remote repo name" #~ msgstr "Namen des Repository" #, c-format #~ msgid "Released %x" #~ msgstr "Veröffentlicht %x" #~ msgid "Edit Permissions" #~ msgstr "Berechtigungen bearbeiten" #~ msgid "How the application looks" #~ msgstr "Wie die Anwendung aussieht" #~ msgid "Appearance" #~ msgstr "Erscheinungsbild" #~ msgid "Show animated background" #~ msgstr "Animierten Hintergrund anzeigen" #~ msgid "Type to filter" #~ msgstr "Zum Filtern hier tippen" #~ msgid "Exclude results with proprietary licenses" #~ msgstr "Ergebnisse mit proprietären Lizenzen ausschließen" #~ msgid "Exclude results not originating from Flathub" #~ msgstr "Ergebnisse ausschließen, die nicht von Flathub stammen" #~ msgid "Advanced" #~ msgstr "Erweitert" #~ msgid "Open this link externally" #~ msgstr "Diesen Link extern öffnen" #~ msgid "Downloads Over Time" #~ msgstr "Downloads im Laufe der Zeit" #~ msgid "Minimize Lower Bound" #~ msgstr "Untere Grenze verringern" #~ msgid "Maximize Upper Bound" #~ msgstr "Obere Grenze vergrößern" #~ msgid "Installing" #~ msgstr "Wird installiert" #~ msgid "Updating" #~ msgstr "Wird aktualisiert" #~ msgid "Removing" #~ msgstr "Wird entfernt" #~ msgid "Transactions Will Appear Here" #~ msgstr "Transaktionen werden hier erscheinen" #~ msgid "Halt the execution of transactions" #~ msgstr "Die Ausführung von Transaktionen anhalten" #~ msgid "Clear all finished transactions" #~ msgstr "Alle abgeschlossenen Transaktionen leeren" #~ msgid "Confirm Action" #~ msgstr "Aktion bestätigen" #, c-format #~ msgid "" #~ "You are about to remove the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "Sie sind dabei, die folgende Anwendung zu entfernen:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Sind Sie sich sicher?" #, c-format #~ msgid "" #~ "You are about to install the following Flatpak:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Are you sure?" #~ msgstr "" #~ "Sie sind dabei, die folgende Anwendung zu installieren:\n" #~ "\n" #~ "%s\n" #~ "%s\n" #~ "\n" #~ "Sind Sie sich sicher?" #~ msgid "Resume the execution of transactions" #~ msgstr "Die Ausführung von Transaktionen fortsetzen" #~ msgid "Pause the execution of transactions" #~ msgstr "Die Ausführung von Transaktionen pausieren" #~ msgid "No description" #~ msgstr "Keine Beschreibung" #~ msgid "Main Bazaar window showing Blender" #~ msgstr "Bazaar-Hauptfenster zeigt Blender" #~ msgid "Match using regular expressions" #~ msgstr "Übereinstimmung mit regulären Ausdrücken" #~ msgid "Hide filtering and sorting behind a crossfade effect" #~ msgstr "Filterung und Sortierung hinter einem Überblendungseffekt verstecken" bazaar-orig-v0.7.14/.clang-format0000664000175000017500000000075315166123241015520 0ustar hasanhasanBasedOnStyle: GNU AlwaysBreakAfterDefinitionReturnType: All BreakBeforeBinaryOperators: None BinPackParameters: false SpaceAfterCStyleCast: true PointerAlignment: Right ColumnLimit: 0 AlignArrayOfStructures: Right AlignAfterOpenBracket: Align AlignConsecutiveAssignments: true AlignConsecutiveBitFields: true AlignConsecutiveDeclarations: true AlignConsecutiveMacros: true AllowShortCaseLabelsOnASingleLine: true AlignEscapedNewlines: true AlignOperands: true AlignTrailingComments: Always bazaar-orig-v0.7.14/build-aux/0000775000175000017500000000000015166123241015032 5ustar hasanhasanbazaar-orig-v0.7.14/build-aux/flatpak/0000775000175000017500000000000015166123241016454 5ustar hasanhasanbazaar-orig-v0.7.14/build-aux/flatpak/fusermount-wrapper.sh0000664000175000017500000000064315166123241022700 0ustar hasanhasan#!/bin/sh set -eo pipefail echo "Running fusermount wrapper, redirecting to host..." export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/flatpak/bus binary="fusermount" if flatpak-spawn --host fusermount3 --version &> /dev/null ; then binary="fusermount3" fi [ ! -z "$_FUSE_COMMFD" ] && export FD_ARGS="--env=_FUSE_COMMFD=${_FUSE_COMMFD} --forward-fd=${_FUSE_COMMFD}" exec flatpak-spawn --host ${FD_ARGS} "$binary" "$@" bazaar-orig-v0.7.14/build-aux/flatpak/fuse-2.9.2-closefrom.patch0000664000175000017500000000070015166123241023071 0ustar hasanhasan--- fuse-2.9.2/util/ulockmgr_server.c.closefromfix 2019-01-04 05:33:33.000000000 -0800 +++ fuse-2.9.2/util/ulockmgr_server.c 2022-07-12 12:29:56.445402244 -0700 @@ -124,7 +124,7 @@ return res; } -static int closefrom(int minfd) +static int _closefrom(int minfd) { DIR *dir = opendir("/proc/self/fd"); if (dir) { @@ -384,7 +384,7 @@ dup2(nullfd, 1); } close(3); - closefrom(5); + _closefrom(5); while (1) { char c; int sock; bazaar-orig-v0.7.14/build-aux/flatpak/flatpak-builder-tools/0000775000175000017500000000000015166123241022660 5ustar hasanhasanbazaar-orig-v0.7.14/build-aux/flatpak/fuse-disable-sys-mount-under-flatpak.patch0000664000175000017500000000116715166123241026554 0ustar hasanhasanFrom 1ec935f4abecd08957affc7b21bae6bf5be78931 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Thu, 12 Apr 2018 01:47:57 -0700 Subject: [PATCH] libfuse: disable sys mount under flatpak --- lib/mount.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/mount.c b/lib/mount.c index 7a18c11..1667db2 100644 --- a/lib/mount.c +++ b/lib/mount.c @@ -392,6 +392,9 @@ static int fuse_mount_sys(const char *mnt, struct mount_opts *mo, int fd; int res; + /* disable in flatpak */ + return -2; + if (!mnt) { fprintf(stderr, "fuse: missing mountpoint parameter\n"); return -1; -- 2.17.0.rc2 bazaar-orig-v0.7.14/build-aux/flatpak/fuse-2.9.2-namespace-conflict-fix.patch0000664000175000017500000000106415166123241025423 0ustar hasanhasandiff -up fuse-2.9.2/include/fuse_kernel.h.conflictfix fuse-2.9.2/include/fuse_kernel.h --- fuse-2.9.2/include/fuse_kernel.h.conflictfix 2013-06-26 09:31:57.862198038 -0400 +++ fuse-2.9.2/include/fuse_kernel.h 2013-06-26 09:32:19.679198365 -0400 @@ -88,12 +88,16 @@ #ifndef _LINUX_FUSE_H #define _LINUX_FUSE_H -#include +#ifdef __linux__ +#include +#else +#include #define __u64 uint64_t #define __s64 int64_t #define __u32 uint32_t #define __s32 int32_t #define __u16 uint16_t +#endif /* * Version negotiation: bazaar-orig-v0.7.14/build-aux/flatpak/io.github.kolunmi.Bazaar.json0000664000175000017500000004260515166123241024122 0ustar hasanhasan{ "id": "io.github.kolunmi.Bazaar", "runtime": "org.gnome.Platform", "runtime-version": "50", "sdk": "org.gnome.Sdk", "command": "bazaar", "sdk-extensions": [ "org.freedesktop.Sdk.Extension.llvm20" ], "tags": [ "nightly" ], "desktop-file-name-suffix": " (Nightly)", "finish-args": [ "--share=network", "--share=ipc", "--socket=fallback-x11", "--socket=wayland", "--device=dri", "--filesystem=/var/lib/flatpak", "--filesystem=xdg-data/flatpak", "--talk-name=org.freedesktop.Flatpak", "--system-talk-name=org.freedesktop.Flatpak.SystemHelper", "--filesystem=/var/tmp", "--filesystem=~/.var/app", "--system-talk-name=org.freedesktop.Accounts", "--talk-name=org.freedesktop.impl.portal.PermissionStore" ], "cleanup": [ "/share/zsh", "/share/gettext", "/include", "/lib/pkgconfig", "/lib/cmake", "/share/applications/mimeinfo.cache", "/share/bash-completion", "/share/zsh/site-functions", "/share/icons/hicolor/icon-theme.cache", "/share/man", "/share/pkgconfig", "*.la", "*.a" ], "modules": [ { "name": "blueprint-compiler", "buildsystem": "meson", "cleanup": [ "*" ], "sources": [ { "type": "git", "url": "https://gitlab.gnome.org/GNOME/blueprint-compiler.git", "commit": "31b62c24a72c1670d2d93dcdf2d130f1ae12778e", "tag": "v0.20.4", "x-checker-data": { "type": "git", "tag-template": "$version" } } ] }, { "name": "bazaar", "buildsystem": "meson", "build-options": { "append-path": "/usr/lib/sdk/llvm20/bin", "prepend-ld-library-path": "/usr/lib/sdk/llvm20/lib" }, "config-opts": [ "-Ddevelopment=true", "-Dsandboxed_libflatpak=true", "-Dhardcoded_main_config_path=/run/host/etc/bazaar/bazaar.yaml", "-Dhardcoded_content_config_path=/run/host/etc/bazaar/config.yaml", "-Dhardcoded_blocklist_path=/run/host/etc/bazaar/blocklist.txt" ], "sources": [ { "type": "dir", "path": "../.." } ], "modules": [ { "name": "md4c", "buildsystem": "cmake", "config-opts": [ "-DBUILD_MD2HTML_EXECUTABLE=Off" ], "sources": [ { "type": "git", "url": "https://github.com/mity/md4c.git", "commit": "729e6b8b320caa96328968ab27d7db2235e4fb47", "tag": "release-0.5.2", "x-checker-data": { "type": "git", "tag-pattern": "^release-([\\d.]+)$" } } ] }, { "name": "malcontent", "buildsystem": "meson", "config-opts": [ "-Dui=disabled", "-Dinstalled_tests=false" ], "sources": [ { "type": "git", "url": "https://gitlab.freedesktop.org/pwithnall/malcontent.git", "commit": "3ba80995bb25b7aeda7e21d547f9e39ff9a81736", "tag": "0.12.0" }, { "type": "shell", "commands": [ "sed -i \"/subdir('tests')/d\" libmalcontent/meson.build", "sed -i \"/subdir('tests')/d\" meson.build", "sed -i \"/subdir('pam')/d\" meson.build" ] } ] }, { "name": "flatpak", "buildsystem": "meson", "config-opts": [ "-Dgtkdoc=disabled", "-Ddocbook_docs=disabled", "-Dtests=false", "-Dman=disabled", "-Dseccomp=disabled", "-Dselinux_module=disabled", "-Dmalcontent=enabled", "-Dsandboxed_triggers=false", "-Dsystem_helper=enabled", "-Dsystemd=disabled", "-Dsystem_install_dir=/var/lib/flatpak", "-Dsystem_bubblewrap=bwrap", "-Dsystem_dbus_proxy=xdg-dbus-proxy", "--sysconfdir=/var/run/host/etc" ], "cleanup": [ "/bin/flatpak-bisect", "/bin/flatpak-coredumpctl", "/etc/profile.d", "/lib/systemd", "/share/dbus-1/interfaces/org.freedesktop.*", "/share/dbus-1/services/org.freedesktop.*", "/share/flatpak/triggers", "/share/gdm", "/share/zsh", "/share/fish", "/lib/sysusers.d", "/lib/tmpfiles.d" ], "post-install": [ "install -Dpm0755 -t /app/bin /usr/bin/update-{mime,desktop}-database" ], "sources": [ { "type": "git", "url": "https://github.com/flatpak/flatpak", "commit": "2c7f24dcbf45aaec453960b61d24574c4f489dae", "tag": "1.17.4", "x-checker-data": { "type": "git", "url-template": "$version", "is-important": true } } ], "modules": [ { "name": "python3-pyparsing", "buildsystem": "simple", "cleanup": [ "*" ], "build-commands": [ "pip3 install --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} pyparsing" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", "sha256": "c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", "x-checker-data": { "type": "pypi", "name": "pyparsing" } }, { "type": "file", "url": "https://files.pythonhosted.org/packages/69/59/b6fc2188dfc7ea4f936cd12b49d707f66a1cb7a1d2c16172963534db741b/flit_core-3.12.0.tar.gz", "sha256": "18f63100d6f94385c6ed57a72073443e1a71a4acb4339491615d0f16d6ff01b2", "x-checker-data": { "type": "pypi", "name": "flit_core" } } ] }, { "name": "python3-babel", "buildsystem": "simple", "cleanup": ["*"], "build-commands": [ "pip3 install --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} babel" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", "sha256": "e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", "x-checker-data": { "type": "pypi", "name": "babel" } } ] }, { "name": "polkit", "buildsystem": "meson", "config-opts": [ "-Dlibs-only=true", "-Dintrospection=false", "-Dauthfw=shadow" ], "rm-configure": true, "build-options": { "env": { "CFLAGS": "-Wno-implicit-function-declaration" } }, "cleanup": [ "/bin/*", "/etc/dbus-1", "/etc/pam.d", "/include", "/lib/pkgconfig", "/lib/polkit-1", "/share/dbus-1/system-services/*", "/share/polkit-1" ], "sources": [ { "type": "git", "url": "https://github.com/polkit-org/polkit", "commit": "9e4894c969eecf26a3ba762f4f7a268aa0fb3e51", "tag": "127", "x-checker-data": { "type": "git", "tag-pattern": "^([\\d.]+)$" } } ], "modules": [ { "name": "ostree", "build-options": { "env": { "BASH_COMPLETIONSDIR": "/app/share/bash-completion/completions" }, "config-opts": [ "--disable-man", "--enable-introspection=no", "--with-curl", "--without-libsystemd" ] }, "cleanup": [ "/bin", "/etc/grub.d", "/etc/ostree", "/share/ostree", "/libexec" ], "sources": [ { "type": "git", "url": "https://github.com/ostreedev/ostree", "tag": "v2025.7", "commit": "134d144cb52ff018cfedfb936b661189bccc76e6", "x-checker-data": { "type": "anitya", "project-id": 10899, "tag-template": "v$version", "is-important": true } } ], "modules": [ { "name": "libfuse", "build-options": { "env": { "MOUNT_FUSE_PATH": "../tmp/" } }, "config-opts": [ "UDEV_RULES_PATH=/app/etc/udev/rules.d", "INIT_D_PATH=/app/etc/init.d" ], "cleanup": [ "/bin/ulockmgr_server", "/etc" ], "post-install": [ "install -Dpm0755 ./fusermount-wrapper.sh /app/bin/fusermount" ], "sources": [ { "type": "archive", "url": "https://github.com/libfuse/libfuse/releases/download/fuse-2.9.9/fuse-2.9.9.tar.gz", "sha256": "d0e69d5d608cc22ff4843791ad097f554dd32540ddc9bed7638cc6fea7c1b4b5" }, { "type": "patch", "path": "fuse-2.9.2-namespace-conflict-fix.patch" }, { "type": "patch", "path": "fuse-disable-sys-mount-under-flatpak.patch" }, { "type": "patch", "path": "fuse-2.9.2-closefrom.patch" }, { "type": "file", "path": "fusermount-wrapper.sh" } ] } ] }, { "name": "xdg-dbus-proxy", "buildsystem": "meson", "config-opts": [ "-Dman=disabled", "-Dtests=false" ], "sources": [ { "type": "git", "url": "https://github.com/flatpak/xdg-dbus-proxy", "commit": "6a170fa77e3cbecb48f9dd2478fe5c0a119eb467", "tag": "0.1.7", "x-checker-data": { "type": "git", "url-template": "$version" } } ] } ] } ] } ] }, { "name": "bubblewrap", "buildsystem": "meson", "config-opts": [ "-Dman=disabled", "-Dselinux=disabled", "-Dtests=false" ], "sources": [ { "type": "git", "url": "https://github.com/containers/bubblewrap", "commit": "124c4cdf4321f63ef17a1cb0ce8f9dd45bd7adbe", "tag": "v0.11.1", "x-checker-data": { "type": "git", "url-template": "$version" } } ] } ] } bazaar-orig-v0.7.14/.github/0000775000175000017500000000000015166123241014500 5ustar hasanhasanbazaar-orig-v0.7.14/.github/ISSUE_TEMPLATE/0000775000175000017500000000000015166123241016663 5ustar hasanhasanbazaar-orig-v0.7.14/.github/ISSUE_TEMPLATE/bug_form.yml0000664000175000017500000000400015166123241021200 0ustar hasanhasanname: Bug Report description: Report an issue about using Bazaar body: - type: markdown attributes: value: | Thank you for taking the time to fill out this bug report! - type: textarea id: describe-bug attributes: label: Describe the bug description: A clear and concise description of what the bug is. If you are reporting a crash please take a look at https://github.com/bazaar-org/bazaar/blob/debug-symbols/docs/debugging.md#debugging-crashes placeholder: Tell us what happened! value: "When I entered 2 + 2, I got the answer 6." validations: required: true - type: input id: os attributes: label: OS description: Operating system (and desktop environment) placeholder: , validations: required: true - type: textarea id: version attributes: label: Version description: | Please check the current version of Bazaar (Main Window > About Bazaar) so we can more easily indentify issues. Output of `flatpak info io.github.kolunmi.Bazaar`. If you are on Bazzite or secureblue please run `rpm -qi bazaar` validations: required: true - type: textarea id: flatpak-remotes attributes: label: Configured Flatpak Remotes description: | Currently there are issues with user remotes. Please run `flatpak remotes`. placeholder: | Name Options flathub system validations: required: true - type: textarea id: hardware attributes: label: Hardware description: | If you are reporting performance issues or crashes then please fill this out. placeholder: | CPU: Ryzen 5 7600 GPU: RX 6750 XT RAM: 16GB validations: required: false - type: textarea id: extra-context attributes: label: Extra information or context description: Add any other context about the problem here. bazaar-orig-v0.7.14/.github/FUNDING.yml0000664000175000017500000000012015166123241016306 0ustar hasanhasangithub: [kolunmi] ko_fi: kolunmi custom: - https://ko-fi.com/alexandervanhee bazaar-orig-v0.7.14/.github/CODEOWNERS0000664000175000017500000000017615166123241016077 0ustar hasanhasan# All files * @kolunmi @AlexanderVanhee .github/workflows/ @renner0e @tulilirockz build-aux/flatpak/ @renner0e @tulilirockz bazaar-orig-v0.7.14/.github/workflows/0000775000175000017500000000000015166123241016535 5ustar hasanhasanbazaar-orig-v0.7.14/.github/workflows/build-flatpak.yml0000664000175000017500000000204215166123241021775 0ustar hasanhasanon: push: branches: [main] pull_request: paths-ignore: - "**.md" - "docs/*" - "screenshots/*" - "translators.sh" - ".github/ISSUE_TEMPLATE/**" name: CI Build Flatpak jobs: flatpak: name: "Flatpak" container: image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-50 options: --privileged strategy: matrix: variant: - arch: x86_64 runner: ubuntu-latest # no latest for ARM :( - arch: aarch64 runner: ubuntu-24.04-arm runs-on: ${{ matrix.variant.runner }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: submodules: recursive - uses: flatpak/flatpak-github-actions/flatpak-builder@92ae9851ad316786193b1fd3f40c4b51eb5cb101 # v6.6 with: bundle: Bazaar.flatpak manifest-path: build-aux/flatpak/io.github.kolunmi.Bazaar.json cache-key: flatpak-builder-046f9ec arch: ${{ matrix.variant.arch }} verbose: true bazaar-orig-v0.7.14/.github/workflows/flatpak-external-data-checker.yml0000664000175000017500000000205215166123241025032 0ustar hasanhasanname: Check for Flatpak dependency updates on: schedule: - cron: "0 0 * * *" # every day workflow_dispatch: jobs: flatpak-external-data-checker: runs-on: ubuntu-latest strategy: matrix: branch: [ main ] steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ matrix.branch }} - uses: docker://ghcr.io/flathub/flatpak-external-data-checker:latest env: GIT_AUTHOR_NAME: Flatpak External Data Checker GIT_COMMITTER_NAME: Flatpak External Data Checker # email sets "github-actions[bot]" as commit author, see https://github.community/t/github-actions-bot-email-address/17204/6 GIT_AUTHOR_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com GIT_COMMITTER_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: args: --update --never-fork --require-important-update build-aux/flatpak/io.github.kolunmi.Bazaar.json bazaar-orig-v0.7.14/version.sh0000775000175000017500000000077215166123241015172 0ustar hasanhasan#!/bin/sh INSTR="$1" VERSION=0.7.14 case "$INSTR" in get-vcs) VCS_VERSION="$(git -C "$MESON_SOURCE_ROOT" describe --always --dirty)" if [ -n "$VCS_VERSION" ]; then echo "${VERSION} (vcs=${VCS_VERSION})" else echo "${VERSION}" fi ;; get-gh-release) TAG="v${VERSION}" echo "https://github.com/bazaar-org/bazaar/releases/tag/${TAG}" ;; *) echo invalid arguments 1>&2 exit 1 ;; esac bazaar-orig-v0.7.14/docs/0000775000175000017500000000000015166123241014070 5ustar hasanhasanbazaar-orig-v0.7.14/docs/debugging.md0000664000175000017500000000401215166123241016342 0ustar hasanhasan# Debugging Bazaar ## Running Bazaar with Debug Messages Enabled You do this the same as with any other GLib application: ```sh pkill bazaar; env G_MESSAGES_DEBUG=all bazaar ``` This will produce a flood of output. If you know the specific log domain you want to see, you can replace `all` with that domain name, such as `flatpak` or `BAZAAR::CORE`. ## Bazaar Inspector Bazaar has its own inspector window, which you can spawn with the key combo `control+alt+shift+i`. This is meant to be useful for developers and distributors. The global debug mode toggle in this window basically just enables a bottom bar in each Bazaar window which displays useful information particular to that window and allows you to easily inspect the UI entry for the visible application. You can also disable blocklists from this window. This is a temporary internal property, not a configuration option; It will not be saved for the next Bazaar process. The rest of the contents of this window should be self-explanatory. ## Debugging Crashes ### Flatpak #### Installing the Debug Symbols This is mostly based on [flatpak docs](https://docs.flatpak.org/en/latest/debugging.html). Installing debug extensions so the stacktrace is actually useful for developers: ```sh flatpak install --include-debug --include-sdk io.github.kolunmi.Bazaar ``` You can remove all the gnome sdk and debug extensions again when you are finished with debugging. This is quite a big download, please have patience. #### Actually Start Debugging Bazaar starts a background service once started, make sure it is not running first: ```sh flatpak kill io.github.kolunmi.Bazaar ``` ```sh flatpak run --devel --command=bash io.github.kolunmi.Bazaar ``` This will get you a shell inside the flatpak sandbox: run this: `gdb /app/bin/bazaar` ```sh [📦 io.github.kolunmi.Bazaar ~]$ gdb /app/bin/bazaar ``` Actually run bazaar: ```sh $ (gdb) run ``` (reproduce the bug here so it crashes) after it crashed, retrieve the useful information: ```sh $ (gdb) thread apply all backtrace ``` bazaar-orig-v0.7.14/docs/overview.md0000664000175000017500000007324215166123241016270 0ustar hasanhasan# Bazaar Overview These docs are intended for distributors of Bazaar to learn how to configure the application. ## Features Here is a short list of some of the things Bazaar can do, beyond the basics of managing software through the GUI: * Queue an arbitrary number of transactions (a catch-all term for installations, updates, and removals) during which you may close all windows or continue to append new transactions freely * Display a "Curated" page which you may extensively customize with YAML. * This is a way to highlight applications which you believe might be of interest. * Curated configuration files are constantly monitored for filesystem events, changes immediately reflected in the GUI * Any number of curated configuration files; they will concatenate in the GUI in the order they were provided * Access data from [Flathub](https://flathub.org/), such as the latest or most popular applications, and allow users to sign in to Flathub to manage bookmarked applications * Run in the background and respond to desktop search queries with application info, using the same search routine as in-application - GNOME will work out of the box, as Bazaar implements the `org.gnome.Shell.SearchProvider2` dbus interface - KDE Plasma will require a [krunner plugin](https://github.com/ublue-os/krunner-bazaar) * Hide applications you do not want users to see with blocklists, which is useful for discouraging the use of certain packages which you deem to be broken. * Manage an arbitrary amount of windows and keep them synchronized * Communicate with, and invoke operations on, the main daemon through the command line ## CLI Usage You can start the bazaar daemon like this: ``` bazaar [ARGS] [PACKAGE PATH/URI] ``` To avoid spawning an initial window, use: ``` bazaar --no-window [ARGS] [PACKAGE PATH/URI] ``` `[PACKAGE PATH/URI]` could be a `.flatpakref` file. flatpak+https and regular https is supported. ## Comptime Configuration The only compile time meson option you should concern yourself with for production is `hardcoded_main_config_path`. This embeds a path to the main configuration file into Bazaar. If this is not defined at compile time, Bazaar will never attempt to read a main config. See the next section of this document to see an example config file. ## Main Configuration This is the primary YAML configuration file for bazaar, as designated by the `hardcoded_main_config_path` meson option. Here, you will point bazaar to where your other configs are located. You can also define hooks in this file. See the "Hooks" section of this document for an overview of the hooks system and an example of integration into the main config. ### Example ```yaml yaml-blocklist-paths: - /path/to/yaml/blocklist.yaml - /path/to/another/yaml/blocklist.yaml # Flatpak path with host-etc permission - /run/host/etc/bazaar/blocklist.yaml txt-blocklist-paths: - /path/to/txt/blocklist.txt - /path/to/another/txt/blocklist.txt # Flatpak path with host-etc permission - /run/host/etc/bazaar/blocklist.txt curated-config-paths: - /path/to/yaml/file.yaml - /path/to/another/yaml/file.yaml # Flatpak path with host-etc permission - /run/host/etc/bazaar/curated.yaml ``` ### EOL Overrides In this file, you can also specify a list of apps for which to hide EOL warnings and therefore prevent users from being deterred from installing them: ```yaml override-eol-markings: - com.obsproject.Studio - net.lutris.Lutris ``` (At the time of writing, the projects listed above rely on EOL runtimes but are otherwise widely used) ## Blocklists Blocklists are a way to ensure that users will never interact with a certain application inside Bazaar by searching or browsing, either on the Flathub page or via search. Blocked applications which are already installed still appear in the library or when there are updates available for them and via the system's flatpak configuration. Under no circumstance does Bazaar touch the underlying flatpak configuration in order to block or allow apps. The `flatpak` command line tool is unaffected. ### Blocklist Types There are two kinds of blocklists supported by Bazaar: #### YAML Blocklists For those who are learn more effectively by seeing an example: ```yaml blocklists: - priority: 0 block-regex: # block all ids matching this regex unconditionally - com\.place\..* - priority: -1 # lower number = more priority conditions: - match-locale: # only apply this rule if we have the Arabic locale regex: ar allow: - com.place.App3 - com.place.App5 allow-regex: - com\.place\..*\.ar - priority: -1 conditions: - match-locale: regex: en.* # invert the result of this condition; so all locales which don't match # the regex post-process: invert - match-envvar: var: PATH regex: .*/usr/local/bin.* block: - com.other.App1 allow: - com.place.App1 - com.place.App2 ``` YAML blocklists files are comprised of a list of sub "blocklists," which to Bazaar means a **list of appids to block or allow**. These are optionally **applied based on a list of provided conditions** and **composed with other blocklists in the list based on a priority**. Each blocklist may contain these fields: * `priority`: a number which tells Bazaar how to layer this blocklist with the others, or how "important" this blocklist is. **A lower number means more priority**. * `conditions`: a list of conditions to apply. Two condition types exist at the moment: `match-locale` and `match-envvar`. TODO: describe these * `block`: a list of appids to block. These are matched without regex. * `block-regex`: a list of appids to block. These allow regex syntax for special matching. * `allow`: a list of appids to allow. These are matched without regex. * `allow-regex`: a list of appids to allow. These allow regex syntax for special matching. #### Basic Newline Separated TXT Blocklists This type of blocklist is what Bazaar originally supported. They still function, but it is encouraged to use YAML blocklists if any sort of pattern matching or conditional inclusion is required. ``` # comments are supported com.jetbrains.CLion com.valvesoftware.Steam # empty lines are allowed io.neovim.nvim net.lutris.Lutris ``` Warning: **Incorrect Buzzer** TXT blocklists do not support regular expressions. This matches the literal text provided ``` com\.place\..* ``` ### Blocklist FAQ #### No Worky Check that the path of the blocklist exists and that Bazaar can access it. This command is useful for debugging this: ``` flatpak run --command=bash io.github.kolunmi.Bazaar ``` The `/etc` of the host system accessed from a Flatpak requires the `host-etc` permission. This means `/etc/bazaar/banner.png` turns into `/run/host/etc/bazaar/banner.png`. #### I want to to block a list of applications all the time, and also another list only on desktop environment X: Say you want to block Bazaar and Steam unconditionally and Kate and KWrite if the desktop is Plasma. You can use an environment variable condition to check the value of `XDG_CURRENT_DESKTOP`: ```yaml blocklists: - block: - io.github.kolunmi.Bazaar - com.valvesoftware.Steam - block: - org.kde.kate - org.kde.kwrite conditions: - match-envvar: var: XDG_CURRENT_DESKTOP regex: KDE ``` Let's add another for GNOME: ```yaml blocklists: - block: - io.github.kolunmi.Bazaar - com.valvesoftware.Steam - block: - org.kde.kate - org.kde.kwrite conditions: - match-envvar: var: XDG_CURRENT_DESKTOP regex: KDE - block: - org.gnome.eog - org.gnome.Extensions conditions: - match-envvar: var: XDG_CURRENT_DESKTOP regex: GNOME ``` #### What about blocking an application by default, but allowing it if a condition resolves to true? Taking from the previous example, let's allow Steam on KDE and GNOME, but block it on other desktops. We'll need to give the DE-specific blocklists more priority: ```yaml blocklists: - priority: 1 block: - io.github.kolunmi.Bazaar - com.valvesoftware.Steam - block: - org.kde.kate - org.kde.kwrite allow: - com.valvesoftware.Steam conditions: - match-envvar: var: XDG_CURRENT_DESKTOP regex: KDE - block: - org.gnome.eog - org.gnome.Extensions allow: - com.valvesoftware.Steam conditions: - match-envvar: var: XDG_CURRENT_DESKTOP regex: GNOME ``` You could also make a new blocklist matching both `KDE` and `GNOME`: ```yaml blocklists: - priority: 1 block: - io.github.kolunmi.Bazaar - com.valvesoftware.Steam - block: - org.kde.kate - org.kde.kwrite conditions: - match-envvar: var: XDG_CURRENT_DESKTOP regex: KDE - block: - org.gnome.eog - org.gnome.Extensions conditions: - match-envvar: var: XDG_CURRENT_DESKTOP regex: GNOME - allow: - com.valvesoftware.Steam conditions: - match-envvar: var: XDG_CURRENT_DESKTOP regex: KDE|GNOME ``` ## Curated Section If Bazaar is provided a non-zero amount of curated configs, an extra tab will appear on the window's header bar called "Curated". This section is intended for distributors to curate applications for users with a customizable interface. Curated configs are YAML files. They are constantly monitored by Bazaar for filesystem events, so when the config changes, Bazaar will automatically reload the content. Right now, curated configs are essentially composed of a list of "sections" which appear stacked on top of each other inside of a scrollable viewport in the order they appear in the YAML. Each section has certain properties you can customize, like a title, an image banner URI, and of course a list of appids. Bazaar maps the appids you provide to the best matching "entry group" from the table of applications it was able to pull from remote sources (Simply put, an entry group in Bazaar is a collection of applications which share the same appid but come from different sources or installations). The entry group has a designated "ui entry" which was previously determined in the refresh process to have the most useful content associated with it as it pertains to presenting things like icons, descriptions, screenshots, etc to the user. When the user selects the app in the section, they are brought to a "full view" where they can see a bunch of information stored inside or referenced by the ui entry and choose to invoke transactions on the entry group, like installation or removal. Additionally, curated configs allow you to define a css block from which you can reference classes inside sections and change the way gtk renders the content. ### Example Here are practical examples: - [Aurora](https://github.com/get-aurora-dev/common/tree/0d86028dd0d737d1d0eee08205c33fc91997f155/system_files/shared/etc/bazaar) - https://getaurora.dev - [Bluefin](https://github.com/projectbluefin/common/tree/a868eba107b91c4eae60b6d1d6d2e2cdf05eb1c8/system_files/bluefin/etc/bazaar) - https://projectbluefin.io - [Bazzite](https://github.com/ublue-os/bazzite/blob/4cb928b7268d0cae38592ff112e061f972caed63/system_files/desktop/shared/usr/share/ublue-os/bazaar) - https://bazzite.gg Here is a basic curated config: ```yaml # Some css names at your disposal: # - banner # - banner-text # - banners # - description # - subtitle # - title # - app-tile # - app-tile-title # - app-tile-verified-check # - app-tile-description # - app-tile-installed-indicator # - app-tile-installed-pill css: | .main-section { margin: 15px; border-radius: 25px; } .main-section banner-text { margin: 15px; color: white; } .background-1 { background: linear-gradient(45deg, #170a49, #52136c); } .background-1 title { border-bottom: 5px solid white; } .background-1 app-tile > button { background-color: alpha(white, 0.1); } .background-1 app-tile > button:hover { background-color: alpha(var(--accent-bg-color), 0.5); } .background-2 { background: linear-gradient(75deg, #51263c, #7104a9); } .background-2 app-tile > button:focus { background-color: alpha(var(--accent-bg-color), 0.5); } .background-2 app-tile-verified-check { color: orange; } rows: - sections: - expand-horizontally: true category: title: "My Favorite Apps" subtitle: "These are really good and you should download them!" # can be https as well # If you want this to work with the Flatpak then use this path # file:///run/host/etc/bazaar/banner-1.jxl banner: file:///home/kolunmi/banner-1.jxl # Dynamically switching between light/dark variants of banners light-banner: file:///home/kolunmi/banner-light.png dark-banner: file:///home/kolunmi/banner-dark.png # can be "fill", "contain", "cover", or "scale-down" # see https://docs.gtk.org/gtk4/enum.ContentFit.html banner-fit: contain # can be "fill", "start", "end", or "center" # see https://docs.gtk.org/gtk4/enum.Align.html # halign -> "horizontal alignment" banner-text-halign: start # valign -> "vertical alignment" banner-text-valign: center # size in pixels banner-height: 400 # "The horizontal alignment of the label text inside its size # allocation." # see https://docs.gtk.org/gtk4/property.Label.xalign.html banner-text-label-xalign: 0.0 # appid list appids: - com.usebottles.bottles - io.mgba.mGBA - net.pcsx2.PCSX2 - org.blender.Blender - org.desmume.DeSmuME - org.duckstation.DuckStation - org.freecad.FreeCAD # Show an "Install All" button enable-bulk-install: true # reference the classes we defined earlier classes: - main-section - background-1 # The `classes` key (above) is for styling which we want to apply # all the time. If you want a style class to only be active in # light or dark mode, use `light-classes` or `dark-classes`: light-classes: - light-section dark-classes: - dark-section - sections: - category: title: "Some more awesome apps!" subtitle: "These are also pretty cool" banner: file:///home/kolunmi/banner-2.png banner-fit: contain banner-text-halign: end banner-text-valign: center banner-text-label-xalign: 1.0 appids: - org.gimp.GIMP - org.gnome.Builder - org.gnome.Loupe - org.inkscape.Inkscape classes: - main-section - background-2 ``` ### Integrate the curated section + blocklist with the official Flatpak for Administrators/Vendors For more practical examples check out the configuration from [Bluefin](https://github.com/projectbluefin/common/tree/a868eba107b91c4eae60b6d1d6d2e2cdf05eb1c8/system_files/bluefin/etc/bazaar) and [Aurora](https://github.com/get-aurora-dev/common/tree/0d86028dd0d737d1d0eee08205c33fc91997f155/system_files/shared/etc/bazaar). Bazaar by default looks for a config file in `/etc/bazaar` or `/run/host/etc/bazaar` inside the sandbox, this is [configured on build time](https://github.com/flathub/io.github.kolunmi.Bazaar/blob/709faccd8c4198c5fdabf20eb4a98db98a5aa1c6/io.github.kolunmi.Bazaar.yaml#L43-L46) This needs permission to `/etc` which can be granted with the `filesystem=host-etc` permission, the build on Flathub doesn't have this permission by default. This is not super straightforward to setup currently as Flatpak doesn't support overriding permissions in `/etc` or `/usr` yet, so you have to resort to `systemd-tmpfiles` to create this permission override in `/var/lib/flatpak/overrides/io.github.kolunmi.Bazaar`. Here is how they did it: - [tmpfiles](https://github.com/get-aurora-dev/common/blob/0d86028dd0d737d1d0eee08205c33fc91997f155/system_files/shared/usr/lib/tmpfiles.d/bazaar-flatpak.conf) - [actual permission override](https://github.com/get-aurora-dev/common/blob/0d86028dd0d737d1d0eee08205c33fc91997f155/system_files/shared/usr/share/ublue-os/flatpak-overrides/io.github.kolunmi.Bazaar), the filepath for this doesn't really matter, just a way for you to ship the symlink with tmpfiles ## Hooks Hooks are an advanced feature of Bazaar. In essence, they allow you to programmatically react to events and define dialogs with which you can query user input. Currently, these are the event signals you can subscribe to: * `view-app`: run the hook when the user clicks on an app tile or otherwise views an application in the main app page * `before-transaction`: run the hook right as the user invokes a transaction * `after-transaction`: run the hook after a transaction completes Hooks are run like a signal emission. After an event occurs, hooks that are found to be of the appropriate type are evaluated in an order of priority. Higher priority hooks have the ability to stop the emission from propagating further downwards. In the case of some events, like "before-transaction", a hook can also hint to Bazaar some action to take, in this case whether the transaction should be aborted. A shell snippet which is defined by you is evaluated with `/bin/sh -c` multiple times over the course of a hook's execution. An invocation of the shell snippet is referred to as a "stage". Your shell snippet (which of course could just invoke another script written in whatever language you prefer) will be provided a number of environment variables which together will describe the current stage. Your snippet must react accordingly by printing a response to stdout, which Bazaar will read back. This opens up a lot of possibilities for customization; here are a few examples: * You would like a certain appid to be added to steam after the user installs it, so you register a hook on "after-transaction" to query the user's permission with a custom dialog. If they confirm, your script will go forward with the task of setting up a steam shortcut. * You would like to prevent users from installing a certain appid, as some other method of installation, such as a system package, would provide a superior experience. A blocklist could achieve this, but you don't like the idea of hiding anything from the user. A hook subscribed to the "before-transaction" event could issue a warning and ask for extra confirmation. If the user decides to listen to the warning, you can signal to Bazaar that the transaction should be aborted. Here is an overview of the environment variables the shell snippet will receive: * `BAZAAR_HOOK_INITIATED_UNIX_STAMP`: the unix timestamp in seconds at which this hook was first invoked (the number of seconds that have elapsed since 1970-01-01 00:00:00 UTC) * `BAZAAR_HOOK_INITIATED_UNIX_STAMP_USEC`: the unix timestamp in microseconds at which this hook was first invoked (the number of microseconds that have elapsed since 1970-01-01 00:00:00 UTC) * `BAZAAR_HOOK_STAGE_IDX`: the number of stages this hook has run so far * `BAZAAR_HOOK_ID`: the value of the "id" mapping * `BAZAAR_HOOK_TYPE`: the value of the "when" mapping * `BAZAAR_HOOK_WAS_ABORTED`: "true" if a dialog aborted the hook * `BAZAAR_HOOK_DIALOG_ID`: if applicable, the id of the current dialog * `BAZAAR_HOOK_DIALOG_RESPONSE_ID`: if applicable, the user response given through the current dialog * `BAZAAR_APPID`: if applicable, the appid of the entry Bazaar is currently dealing with. Use this for hooks that are not related to transactions. If your hook deals with transactions, such as `before-transaction` or `after-transaction`, use `BAZAAR_TS_APPID` instead. * `BAZAAR_TS_APPID`: if applicable, the appid of the entry Bazaar is currently dealing with. Use this for hooks that are related to transactions. If your hook does not deal with transactions, such as `view-app`, use `BAZAAR_APPID` instead. * `BAZAAR_TS_TYPE`: if applicable, the type of transaction being run. Can be "install", "update", or "removal". * `BAZAAR_HOOK_STAGE`: the stage at which the hook is running. This will indicate what the shell body is instructed to do at this time. The shell body must respond by outputting to stdout with a valid answer; the structure of a valid answer will depend on the stage, and if the structure is not valid the hook will be abandoned. The shell body might be run multiple times by Bazaar over the course of a hook with this variable set to differing values in order know how to orchestrate events in the UI, so the shell body must be able to branch depending on the value. The value may be any of the following: * `setup`: the hook is starting. Respond with "ok" to continue the execution of this hook, or "pass" to skip it and move on to the next registered hook * `setup-dialog` Bazaar is ready to ask the user a question with one of the dialogs you've defined inside the "dialogs" mapping. `BAZAAR_HOOK_DIALOG_ID` will tell you which one. Respond with "ok" to spawn the dialog, or "pass" to skip the dialog. * `teardown-dialog` Bazaar has received input from the user after asking them a question with one of the dialogs you've defined inside the "dialogs" mapping. `BAZAAR_HOOK_DIALOG_ID` will tell you which one. `BAZAAR_HOOK_DIALOG_RESPONSE_ID` will tell you the response the user chose. Respond with "ok" to continue, or "abort" to stop the execution of this hook. * `catch` One of your dialogs has aborted. This is your chance to handle the error. Respond with "recover" to continue, or "abort" to confirm that the execution of this hook should indeed skip to the teardown stage. * `action` Everything so far has gone according to plan, so it is time to take whatever external action this hook exists for. Bazaar requires no response at this time. * `teardown` The hook is cleaning up. Respond with "continue" to propagate the signal emission to lower priority hooks, or "stop" to indicate the emission should stop. Alternatively, if this hook type should hint to Bazaar an action to take (such as the "before-transaction" hook), respond with "confirm" to hint that the action should be taken, or "deny" to prevent the action from being taken. Both "confirm" and "deny" imply the effect of "stop", and "stop" implies "confirm". ### Example Hooks are defined in the main yaml config as indicated by the `hardcoded_main_config_path` comptime var. Here is a basic example demonstrating how to define a hook: `hardcoded_main_config_path`: ```yaml hooks: - id: handle-jetbrains when: before-transaction dialogs: - id: jetbrains-warning title: >- JetBrains IDEs are not supported in this format # If true, render inline markup commands in body; see # https://docs.gtk.org/Pango/pango_markup.html body-use-markup: true body: >- This is a JetBrains application and is not officially supported on Flatpak. We recommend using the Toolbox app to manage JetBrains IDEs. # Determines which option will be assumed if the user hits the # escape key or otherwise cancels the dialog default-response-id: cancel options: - id: cancel string: "Cancel" - id: goto-web string: "Download JetBrains Toolbox" # can be "destructive" or "suggested" or omit for no # styling style: suggested shell: exec /absolute/path/to/bazaar-jetbrains-hook.bash # This gives you the opportunity to add a basic regex check on an incoming # appid before incurring the overhead of spawning a subprocess. This # improves performance and reduces script boilerplate for long lists of # hooks that execute on specific appids. check-appid-regex: ^com\.jetbrains\..*$ ``` `/absolute/path/to/bazaar-jetbrains-hook.bash`: ```bash #!/usr/bin/env bash handle_setup_stage() { # only proceed if the user is installing something if [ "$BAZAAR_TS_TYPE" = install ]; then case "$BAZAAR_TS_APPID" in com\.jetbrains\.*) # since the appid belongs to jetbrains, we continue # with the hook echo 'ok' ;; *) # otherwise, skip this hook echo 'pass' ;; esac else echo 'pass' fi } handle_setup_dialog_stage() { # we don't need to do anything here right now, just let Bazaar # know we should continue setting up the dialog echo 'ok' } handle_teardown_dialog_stage() { case "$BAZAAR_HOOK_DIALOG_RESPONSE_ID" in goto-web) # if the user pressed "Download JetBrains Toolbox", # continue echo 'ok' ;; *) # otherwise, let's not do anything echo 'abort' ;; esac } handle_catch_stage() { # this only happens if the `teardown-dialog` stage echoed "abort", # we could echo "recover" at this point to still go to the # `action` stage, but we have no reason to do that right now echo 'abort' } handle_action_stage() { # this is where we do the thing! it is important to use `nohup` # here so bazaar doesn't hang nohup xdg-open 'https://www.jetbrains.com/toolbox-app/' } handle_teardown_stage() { # Let's always prevent the user from installing JetBrains stuff echo 'deny' } # Branch based on the stage case "$BAZAAR_HOOK_STAGE" in setup) handle_setup_stage ;; setup-dialog) handle_setup_dialog_stage ;; teardown-dialog) handle_teardown_dialog_stage ;; catch) handle_catch_stage ;; action) handle_action_stage ;; teardown) handle_teardown_stage ;; esac # exit successfully exit 0 ``` ## Search Biases Search biases are a mechanism provided by Bazaar to influence search results. Given a regex string with which to match a search query, a bias can replace the matched text with a new string and/or adjust the scores of certain appids according to a defined function if a match occurs. This is particularly useful in the following cases: * An application is, for example, an image editor, but doesn't show up in the results for "image editor" because its metadata doesn't contain those search tokens for whatever reason. A search bias can ensure that the app appears despite this. * You want an abbreviation or phrase to be expanded into a version which is more likely to yield better results. For example, Bazaar hardcodes the expansion of the abbreviation `dl` to `download`, which is more helpful when searching metadata. ### Boost Functions Right now, there are two kinds of boost functions you can specify to influence the score of certain appids in the event of a regex match: linear and exponential: #### Linear Linear functions require a `slope` and a `y-intercept` and are evaluated like this: ``` new-score = y-intercept + (slope * original-score) ``` #### Exponential Linear functions require a `factor` and a `y-intercept` and are evaluated like this: ``` new-score = y-intercept * (factor ^ original-score) ``` ### Examples Search biases are defined in the main yaml config as indicated by the `hardcoded_main_config_path` comptime var. Here is a basic example demonstrating how to define search biases: ```yaml search-biases: # Brief regex review: # `^` indicates the beginning of the string # `$` indicates the end of the string # `\b` indicates a word boundary # `(?i)` means case insensitive # Convert queries like "smb server" to "samba server" - regex: \b(?i)smb\b convert-to: samba # Give your favorite matrix clients a simple boost of 100.0 to their score - regex: \b(?i)matrix\b boost-appids: - org.gnome.Fractal - im.riot.Riot linear-boost: slope: 1.0 y-intercept: 100.0 # Convert the search _and_ boost appids - regex: ^(?i)deck$ convert-to: steam deck boost-appids: - com.github.Matoking.protontricks - com.steamgriddb.steam-rom-manager - com.valvesoftware.SteamLink linear-boost: slope: 1.2 y-intercept: 20.0 # Biases are applied in the order that you specify them, so in both the case # that the user types "deck" or "steam deck launcher", the following will be # applied: - regex: \bsteam deck\b boost-appids: - net.retrodeck.retrodeck exponential-boost: factor: 2.0 y-intercept: 5.0 ``` Pro tip: pressing `ctrl-alt-d` in Bazaar activates debug mode, which enables you to see the scores of app results on the search page. This is useful for debugging search biases! ## Translations in YAML Configs For any string scalar property in YAML configs parsed by bazaar, you can optionally provide a map of language code ids -> translated strings. This is for strings only, thus it doesn't apply to scalars which are explicitly parsed as numbers, etc. For instance, this is valid: ```yaml # ... category: title: "My Favorite Apps" subtitle: "These are really good and you should download them!" # ... ``` This is also valid: ```yaml # ... category: title: en: "My Favorite Apps" es: "Mis Aplicaciones Favoritas" ko: "내가 가장 좋아하는 앱들" subtitle: en: "These are really good and you should download them!" es: "¡Son realmente buenos y deberías descargarlos!" ko: "이것들은 정말 좋으니 꼭 다운로드하세요!" # ... ``` (I just used google translate for these, sorry if they are bad) bazaar-orig-v0.7.14/meson_options.txt0000664000175000017500000000212315166123241016573 0ustar hasanhasanoption('bge_only', type: 'boolean', value: false, description: 'Whether to restrict the build to libbge') option('hardcoded_main_config_path', type: 'string', value: '', description: 'Hardcoded absolute path to a main yaml config which will be read at runtime') option('hardcoded_blocklist_path', type: 'string', value: '', description: 'Hardcoded absolute path to a package name blocklist which will be read at runtime') option('hardcoded_content_config_path', type: 'string', value: '', description: 'Hardcoded absolute path to a yaml content configuration which will be read at runtime') option('im_a_translator', type: 'boolean', value: false, description: 'Whether to set up the environment for translation work') option('sandboxed_libflatpak', type: 'boolean', value: false, description: 'Whether to treat libflatpak as being sandboxed or not') option('development', type: 'boolean', value: false, description: 'If this is a development build') bazaar-orig-v0.7.14/CODESTYLE.md0000664000175000017500000000421615166123241015020 0ustar hasanhasan# Bazaar Code Style Rules Thanks for your interest in contributing to Bazaar! Here are the code style rules which you must adhere to in order to keep a clean and consistent codebase: ## Formatting Bazaar uses the GNU C style. The `.clang-format` file at the root project directory will configure `clang-format` to follow the proper conventions. ## General Rules * _Always_ prefer using `g_auto`, `g_autofree`, `g_autoptr`, `g_autolist`, and `g_autoslist` over calling `*_unref` or `*_free` manually. If a variable needs to escape the scope, either increment its reference count or use `g_steal_pointer`. * When you are otherwise forced to call `*_unref` or `*_free` manually, _always_ use `g_clear_pointer` or `g_clear_object`. This prevents use-after-free bugs. * _Always_ prefer using the libdex API over the older GTask API for async operations. It is cleaner and easier to read, and it prevents callbacks from cluttering the source file. This often means spawning a fiber and using `dex_await`. To wrap a call to a function which uses GTask, use [dex_async_pair_new](https://gnome.pages.gitlab.gnome.org/libdex/libdex-1/class.AsyncPair.html). See `src/bz-download-worker.c` for an example of this. * _Always_ declare variables first and initialize them to `0` or `NULL`. Function calls must not be made in the declaration section of a scope. * The general layout of a `.c` file must be in this order: 1. License comment with your name mentioned 2. `#include "config.h"` 3. Include external headers, like `#include ` 4. Include internal headers, like `#include "bz-env.h"` 5. If applicable, define the class's internal struct 6. If applicable, `G_DEFINE_TYPE (...)` or equivalent 7. If applicable, the property enums and `static GParamSpec *props[LAST_PROP] = { 0 };` 8. Declare static functions (which are not virtual methods) 9. If applicable, define class virtual methods (`dispose`, `class_init`, `snapshot`, etc) 10. Define the public API (non-`static` functions which were declared in this `.c` file's associated `.h` header file) 11. Define the static functions which were previously declared in this file bazaar-orig-v0.7.14/bge/0000775000175000017500000000000015166123241013675 5ustar hasanhasanbazaar-orig-v0.7.14/bge/meson.build0000664000175000017500000000327115166123241016042 0ustar hasanhasanapi_version = '0.1' bge_sources = [ 'libbge.c', 'bge-animation.c', 'bge-carousel.c', 'bge-markdown-render.c', ] bge_headers = [ 'bge.h', 'bge-animation.h', 'bge-carousel.h', ] subdir('wdgt') version_split = meson.project_version().split('.') version_conf = configuration_data() version_conf.set('VERSION', meson.project_version()) version_conf.set('MAJOR_VERSION', version_split[0]) version_conf.set('MINOR_VERSION', version_split[1]) version_conf.set('MICRO_VERSION', version_split[2]) configure_file( input: 'bge-version.h.in', output: 'bge-version.h', configuration: version_conf, install: true, install_dir: get_option('includedir') / 'bge' ) bge_deps = [ cc.find_library('m', required: true), dependency('gtk4', version: '>= 4.22.1'), dependency('libdex-1', version: '>= 1.0.0'), dependency('md4c', version: '>= 0.5.1'), ] bge_marshalers = gnome.genmarshal('bge-marshalers', sources: 'bge-marshalers.list', prefix: 'bge_marshal', valist_marshallers: true, ) bge_lib = shared_library( 'bge-' + api_version, bge_sources, bge_marshalers, dependencies: bge_deps, install: true, ) install_headers( bge_headers + files('bge-version-macros.h'), subdir: 'bge') pkg = import('pkgconfig') pkg.generate( description: 'A shared library for bge', libraries: bge_lib, name: 'libbge', filebase: 'bge-' + api_version, version: meson.project_version(), subdirs: 'bge', requires: ['gtk4', 'libdex-1'], install_dir: get_option('libdir') / 'pkgconfig' ) bge_dep = declare_dependency( link_with: bge_lib, dependencies: [bge_deps], include_directories : include_directories('..', '.'), ) subdir('demo') bazaar-orig-v0.7.14/bge/wdgt/0000775000175000017500000000000015166123241014642 5ustar hasanhasanbazaar-orig-v0.7.14/bge/wdgt/meson.build0000664000175000017500000000032015166123241016777 0ustar hasanhasanbge_sources += files( 'bge-wdgt-spec.c', 'bge-wdgt-time.c', 'bge-easing.c', ) bge_headers += files( 'bge-wdgt-spec.h', 'bge-wdgt-renderer.h', 'bge-wdgt-time.h', 'bge-easing.h', ) subdir('fmt') bazaar-orig-v0.7.14/bge/wdgt/bge-wdgt-spec.h0000664000175000017500000000341415166123241017445 0ustar hasanhasan/* bge-wdgt-spec.h * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #ifndef BGE_INSIDE #error "Only can be included directly." #endif G_BEGIN_DECLS #define BGE_TYPE_WDGT_SPEC (bge_wdgt_spec_get_type ()) G_DECLARE_FINAL_TYPE (BgeWdgtSpec, bge_wdgt_spec, BGE, WDGT_SPEC, GObject) BGE_AVAILABLE_IN_ALL BgeWdgtSpec * bge_wdgt_spec_new (void); BGE_AVAILABLE_IN_ALL BgeWdgtSpec * bge_wdgt_spec_new_for_string (const char *string, GError **error); BGE_AVAILABLE_IN_ALL BgeWdgtSpec * bge_wdgt_spec_new_for_resource (const char *resource, GError **error); BGE_AVAILABLE_IN_ALL const char * bge_wdgt_spec_get_name (BgeWdgtSpec *self); BGE_AVAILABLE_IN_ALL void bge_wdgt_spec_set_name (BgeWdgtSpec *self, const char *name); BGE_AVAILABLE_IN_ALL void bge_wdgt_spec_set_name_take (BgeWdgtSpec *self, char *name); #define bge_wdgt_spec_set_name_take_printf(self, ...) bge_wdgt_spec_set_name_take (self, g_strdup_printf (__VA_ARGS__)) G_END_DECLS /* End of bge-wdgt-spec.h */ bazaar-orig-v0.7.14/bge/wdgt/fmt/0000775000175000017500000000000015166123241015430 5ustar hasanhasanbazaar-orig-v0.7.14/bge/wdgt/fmt/meson.build0000664000175000017500000000004615166123241017572 0ustar hasanhasanbge_sources += files( 'parser.c', ) bazaar-orig-v0.7.14/bge/wdgt/fmt/parser.h0000664000175000017500000000157015166123241017100 0ustar hasanhasan/* parser.h * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bge.h" G_BEGIN_DECLS BgeWdgtSpec * bge_wdgt_parse_string (const char *string, GError **error); G_END_DECLS bazaar-orig-v0.7.14/bge/wdgt/fmt/parser.c0000664000175000017500000024312615166123241017100 0ustar hasanhasan/* parser.c * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "../bge-wdgt-spec-private.h" #include "bge-marshalers.h" #include "parser.h" #include "util.h" #define IS_EOF(_p) ((_p) == NULL || *(_p) == '\0') #define SINGLE_CHAR_TOKENS "{}()=:;," #define EVAL_SINGLE_CHAR_TOKENS "#(),+-*/^%" #define STR_DEFARRAY "defarray" #define STR_DEFWIDGET "defwidget" #define STR_FOREACH "%FOREACH" #define STR_VARIABLE "var" #define STR_REFERENCE "reference" #define STR_INIT "init" #define STR_STATE "state" #define STR_DEFAULT_STATE "state-default" #define STR_SET "set" #define STR_TRANSITION "transition" #define STR_TRANSITION_SPRING "transition-spring" #define STR_ALLOCATE "allocate" #define STR_MEASURE "measure" #define STR_SNAPSHOT "snapshot" typedef enum { TOKEN_PARSE_DEFAULT = 0, TOKEN_PARSE_QUOTED = 1 << 0, } TokenParseFlags; typedef enum { ARGS_PARSE_PARENS = 0, ARGS_PARSE_LEFT_ASSIGN, ARGS_PARSE_RIGHT_ASSIGN, } ArgsParseKind; typedef enum { OPERATOR_ADD = 0, OPERATOR_SUBTRACT, OPERATOR_MULTIPLY, OPERATOR_DIVIDE, OPERATOR_MODULUS, OPERATOR_POWER, } Operator; static const int operator_precedence[] = { [OPERATOR_ADD] = 0, [OPERATOR_SUBTRACT] = 0, [OPERATOR_MULTIPLY] = 1, [OPERATOR_DIVIDE] = 1, [OPERATOR_MODULUS] = 1, [OPERATOR_POWER] = 2, }; typedef struct { Operator op; guint pos; } EvalOperator; BGE_DEFINE_DATA ( eval_closure, EvalClosure, { GArray *ops; gdouble *workbuf0; gdouble *workbuf1; }, BGE_RELEASE_DATA (ops, g_array_unref); BGE_RELEASE_DATA (workbuf0, g_free); BGE_RELEASE_DATA (workbuf1, g_free)); static const char * parse_widget_block (const char *p, BgeWdgtSpec *spec, GHashTable *macro_arrays, GHashTable *macro_replacements, guint *n_anon_vals, GHashTable *type_hints, GError **error); static const char * parse_snapshot_block (const char *p, BgeWdgtSpec *spec, const char *state, GHashTable *macro_replacements, guint *n_anon_vals, GHashTable *type_hints, GError **error); static const char * parse_eval (const char *p, BgeWdgtSpec *spec, const char *state, GHashTable *macro_replacements, guint *n_anon_vals, GHashTable *type_hints, char **value_out, GError **error); static const char * parse_args (const char *p, BgeWdgtSpec *spec, const char *state, const char *enclosing_object, GHashTable *macro_replacements, guint *n_anon_vals, GHashTable *type_hints, const char *const *destinations, GType destinations_types[], guint n_destinations, char ***values_out, GType **types_out, guint *n_out, ArgsParseKind parse_kind, GError **error); static char * parse_token_fundamental (const char *token, BgeWdgtSpec *spec, guint *n_anon_vals, GError **error); static char * consume_token (const char **pp, const char *single_chars, TokenParseFlags flags, gboolean *was_quoted, GHashTable *macro_replacements, GError **error); static char * consume_token_inner (const char **pp, const char *single_chars, TokenParseFlags flags, gboolean *was_quoted, GError **error); static gdouble eval_closure (gpointer this, guint n_param_values, const GValue *param_values, EvalClosureData *data); static char * make_object_property_name (const char *object, const char *property, guint n); static char * make_widget_allocation_name (const char *widget, guint n); static char * make_widget_measurement_name (guint n); static char * make_anon_name (guint n); static gint cmp_operator (EvalOperator *a, EvalOperator *b); static void _marshal_DOUBLE__ARGS_DIRECT (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data); BgeWdgtSpec * bge_wdgt_parse_string (const char *string, GError **error) { g_autoptr (GError) local_error = NULL; gboolean result = FALSE; g_autoptr (BgeWdgtSpec) spec = NULL; g_autoptr (GHashTable) macro_arrays = NULL; g_autoptr (GHashTable) macro_replacements = NULL; guint n_anon_vals = 0; g_autoptr (GHashTable) type_hints = NULL; g_return_val_if_fail (string != NULL, FALSE); spec = bge_wdgt_spec_new (); macro_arrays = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_ptr_array_unref); macro_replacements = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, g_free); type_hints = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, NULL); #define RETURN_ERROR_UNLESS(_cond) \ G_STMT_START \ { \ if (!(_cond)) \ { \ g_set_error ( \ error, \ G_IO_ERROR, \ G_IO_ERROR_UNKNOWN, \ "%s", \ local_error != NULL \ ? local_error->message \ : "???"); \ return NULL; \ } \ } \ G_STMT_END #define EXPECT_TOKEN(_string, _token) \ G_STMT_START \ { \ if (g_strcmp0 ((_string), (_token)) != 0) \ { \ g_set_error ( \ error, \ G_IO_ERROR, \ G_IO_ERROR_UNKNOWN, \ "wdgt fmt parser error: " \ "expected token \"%s\", got \"%s\"", \ (_token), (_string)); \ return NULL; \ } \ } \ G_STMT_END #define UNEXPECTED_TOKEN(_token) \ G_STMT_START \ { \ g_set_error ( \ error, \ G_IO_ERROR, \ G_IO_ERROR_UNKNOWN, \ "Unexpected token \"%s\"", (_token)); \ return NULL; \ } \ G_STMT_END result = bge_wdgt_spec_add_measure_for_size_source_value ( spec, "%for-size%", &local_error); RETURN_ERROR_UNLESS (result); g_hash_table_replace ( type_hints, g_strdup ("%for-size%"), GSIZE_TO_POINTER (G_TYPE_INT)); result = bge_wdgt_spec_add_widget_width_source_value ( spec, "%width%", &local_error); RETURN_ERROR_UNLESS (result); g_hash_table_replace ( type_hints, g_strdup ("%width%"), GSIZE_TO_POINTER (G_TYPE_INT)); result = bge_wdgt_spec_add_widget_height_source_value ( spec, "%height%", &local_error); RETURN_ERROR_UNLESS (result); g_hash_table_replace ( type_hints, g_strdup ("%height%"), GSIZE_TO_POINTER (G_TYPE_INT)); for (const char *p = string; !IS_EOF (p);) { g_autofree char *token = NULL; token = consume_token ( &p, SINGLE_CHAR_TOKENS, TOKEN_PARSE_DEFAULT, NULL, NULL, NULL); if (token == NULL) break; #define GET_TOKEN_FULL(_token_out, _flags, _single_chars, _was_quoted) \ G_STMT_START \ { \ g_clear_pointer ((_token_out), g_free); \ *(_token_out) = consume_token ( \ &p, \ (_single_chars), \ (_flags), \ (_was_quoted), \ macro_replacements, \ &local_error); \ RETURN_ERROR_UNLESS (*(_token_out) != NULL); \ } \ G_STMT_END #define GET_TOKEN(_token_out, _flags) \ GET_TOKEN_FULL (_token_out, _flags, SINGLE_CHAR_TOKENS, NULL) #define GET_TOKEN_EXPECT(_token_out, _flags, _expect) \ G_STMT_START \ { \ GET_TOKEN ((_token_out), (_flags)); \ EXPECT_TOKEN (*(_token_out), (_expect)); \ } \ G_STMT_END if (g_strcmp0 (token, STR_DEFWIDGET) == 0) { g_autofree char *widget_name = NULL; GET_TOKEN (&widget_name, TOKEN_PARSE_QUOTED); bge_wdgt_spec_set_name (spec, widget_name); GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, "{"); p = parse_widget_block ( p, spec, macro_arrays, macro_replacements, &n_anon_vals, type_hints, &local_error); RETURN_ERROR_UNLESS (p != NULL); } else if (g_strcmp0 (token, STR_DEFARRAY) == 0) { g_autofree char *array_name = NULL; guint n_elements = 0; g_auto (GStrv) elements = NULL; g_autoptr (GPtrArray) array = NULL; GET_TOKEN (&array_name, TOKEN_PARSE_DEFAULT); GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, "("); p = parse_args (p, spec, NULL, NULL, macro_replacements, &n_anon_vals, type_hints, NULL, NULL, 0, &elements, NULL, &n_elements, ARGS_PARSE_PARENS, &local_error); RETURN_ERROR_UNLESS (p != NULL); array = g_ptr_array_new_take_null_terminated ( (gpointer *) g_steal_pointer (&elements), g_free); g_hash_table_replace ( macro_arrays, g_steal_pointer (&array_name), g_steal_pointer (&array)); } else UNEXPECTED_TOKEN (token); } return g_steal_pointer (&spec); } static const char * parse_widget_block (const char *p, BgeWdgtSpec *spec, GHashTable *macro_arrays, GHashTable *macro_replacements, guint *n_anon_vals, GHashTable *type_hints, GError **error) { g_autoptr (GError) local_error = NULL; gboolean result = FALSE; g_autofree char *token = NULL; for (;;) { GET_TOKEN (&token, TOKEN_PARSE_DEFAULT); if (g_strcmp0 (token, "}") == 0) return p; else if (g_strcmp0 (token, STR_FOREACH) == 0) { g_autofree char *var_name = NULL; g_autofree char *iterator_name = NULL; g_autofree char *iterator_paste_name = NULL; g_autofree char *array_name = NULL; GPtrArray *array = NULL; const char *fixed_p = NULL; GET_TOKEN (&var_name, TOKEN_PARSE_DEFAULT); GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, ","); GET_TOKEN (&iterator_name, TOKEN_PARSE_DEFAULT); GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, ","); GET_TOKEN (&iterator_paste_name, TOKEN_PARSE_DEFAULT); GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, "IN"); GET_TOKEN (&array_name, TOKEN_PARSE_DEFAULT); array = g_hash_table_lookup (macro_arrays, array_name); if (array == NULL) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "macro array \"%s\" is undefined", array_name); return NULL; } GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, "{"); fixed_p = p; for (guint i = 0; i < array->len; i++) { const char *element = NULL; g_autofree char *iterator = NULL; g_autofree char *iterator_paste = NULL; GValue iter_value = G_VALUE_INIT; element = g_ptr_array_index (array, i); g_hash_table_replace ( macro_replacements, g_strdup (var_name), g_strdup (element)); iterator = make_anon_name ((*n_anon_vals)++); g_value_set_uint (g_value_init (&iter_value, G_TYPE_UINT), i); result = bge_wdgt_spec_add_constant_source_value ( spec, iterator, &iter_value, &local_error); g_value_unset (&iter_value); RETURN_ERROR_UNLESS (result); g_hash_table_replace ( macro_replacements, g_strdup (iterator_name), g_steal_pointer (&iterator)); iterator_paste = g_strdup_printf ("%u", i); g_hash_table_replace ( macro_replacements, g_strdup (iterator_paste_name), g_steal_pointer (&iterator_paste)); p = parse_widget_block ( fixed_p, spec, macro_arrays, macro_replacements, n_anon_vals, type_hints, &local_error); RETURN_ERROR_UNLESS (p != NULL); } g_hash_table_remove (macro_replacements, var_name); g_hash_table_remove (macro_replacements, iterator_name); g_hash_table_remove (macro_replacements, iterator_paste_name); } else if (g_strcmp0 (token, STR_VARIABLE) == 0) { g_autofree char *name = NULL; g_autofree char *type_string = NULL; GType type = 0; GET_TOKEN (&name, TOKEN_PARSE_DEFAULT); GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, ":"); GET_TOKEN (&type_string, TOKEN_PARSE_QUOTED); GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, ";"); type = g_type_from_name (type_string); result = bge_wdgt_spec_add_variable_value ( spec, type, name, &local_error); RETURN_ERROR_UNLESS (result); g_hash_table_replace (type_hints, g_steal_pointer (&name), GSIZE_TO_POINTER (type)); } else if (g_strcmp0 (token, STR_REFERENCE) == 0) { g_autofree char *name = NULL; g_autofree char *type_string = NULL; GType type = 0; GET_TOKEN (&name, TOKEN_PARSE_DEFAULT); GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, ":"); GET_TOKEN (&type_string, TOKEN_PARSE_QUOTED); GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, ";"); type = g_type_from_name (type_string); result = bge_wdgt_spec_add_reference_object_value ( spec, type, name, &local_error); RETURN_ERROR_UNLESS (result); g_hash_table_replace (type_hints, g_steal_pointer (&name), GSIZE_TO_POINTER (type)); } else if (g_strcmp0 (token, STR_INIT) == 0 || g_strcmp0 (token, STR_STATE) == 0 || g_strcmp0 (token, STR_DEFAULT_STATE) == 0) { g_autofree char *state_name = NULL; if (g_strcmp0 (token, STR_INIT) != 0) { GET_TOKEN (&state_name, TOKEN_PARSE_QUOTED); result = bge_wdgt_spec_add_state ( spec, state_name, g_strcmp0 (token, STR_DEFAULT_STATE) == 0, &local_error); /* TODO: allow states to be redefined for macros, so they are just concatenated */ g_clear_error (&local_error); // RETURN_ERROR_UNLESS (result); } GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, "{"); for (;;) { GET_TOKEN (&token, TOKEN_PARSE_DEFAULT); if (g_strcmp0 (token, "}") == 0) break; else if (g_strcmp0 (token, STR_SNAPSHOT) == 0) { GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, "{"); p = parse_snapshot_block (p, spec, state_name, macro_replacements, n_anon_vals, type_hints, &local_error); RETURN_ERROR_UNLESS (p != NULL); } else if (g_strcmp0 (token, STR_SET) == 0) { guint n_dest_values = 0; g_auto (GStrv) dest_values = NULL; g_autofree GType *dest_types = NULL; guint n_src_values = 0; g_auto (GStrv) src_values = NULL; p = parse_args (p, spec, state_name, NULL, macro_replacements, n_anon_vals, type_hints, NULL, NULL, 0, &dest_values, &dest_types, &n_dest_values, ARGS_PARSE_LEFT_ASSIGN, &local_error); RETURN_ERROR_UNLESS (p != NULL); if (n_dest_values == 0) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Left assignment needs at least one argument"); return NULL; } p = parse_args (p, spec, state_name, NULL, macro_replacements, n_anon_vals, type_hints, (const char *const *) dest_values, dest_types, n_dest_values, &src_values, NULL, &n_src_values, ARGS_PARSE_RIGHT_ASSIGN, &local_error); RETURN_ERROR_UNLESS (p != NULL); if (n_src_values != n_dest_values) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Right assignment needs %d argument(s) " "to match the left side", n_dest_values); return NULL; } for (guint i = 0; i < n_dest_values; i++) { result = bge_wdgt_spec_set_value ( spec, state_name, dest_values[i], src_values[i], &local_error); RETURN_ERROR_UNLESS (result); } } else if (g_strcmp0 (token, STR_TRANSITION) == 0) { g_autofree char *transition_value = NULL; g_autofree char *transition_type = NULL; g_autofree char *transition_seconds = NULL; g_autoptr (GEnumClass) enum_class = NULL; GEnumValue *enum_value = NULL; g_autoptr (GVariant) seconds_variant = NULL; gdouble seconds = 0.0; GET_TOKEN (&transition_value, TOKEN_PARSE_DEFAULT); GET_TOKEN (&transition_type, TOKEN_PARSE_DEFAULT); GET_TOKEN (&transition_seconds, TOKEN_PARSE_DEFAULT); enum_class = g_type_class_ref (BGE_TYPE_EASING); enum_value = g_enum_get_value_by_nick (enum_class, transition_type); if (enum_value == NULL) enum_value = g_enum_get_value_by_name (enum_class, transition_type); if (enum_value == NULL) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "'%s' not found in enum type %s", transition_type, g_type_name (BGE_TYPE_EASING)); return NULL; } seconds_variant = g_variant_parse ( G_VARIANT_TYPE_DOUBLE, transition_seconds, NULL, NULL, &local_error); RETURN_ERROR_UNLESS (seconds_variant != NULL); seconds = g_variant_get_double (seconds_variant); result = bge_wdgt_spec_transition_value ( spec, state_name, transition_value, seconds, enum_value->value, &local_error); RETURN_ERROR_UNLESS (result); GET_TOKEN_EXPECT (&transition_seconds, TOKEN_PARSE_DEFAULT, ";"); } else if (g_strcmp0 (token, STR_TRANSITION_SPRING) == 0) { g_autofree char *transition_value = NULL; guint n_spec_values = 0; g_auto (GStrv) spec_values = NULL; GET_TOKEN (&transition_value, TOKEN_PARSE_DEFAULT); p = parse_args (p, spec, state_name, NULL, macro_replacements, n_anon_vals, type_hints, NULL, (GType[]){ G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE }, 3, &spec_values, NULL, &n_spec_values, ARGS_PARSE_RIGHT_ASSIGN, &local_error); RETURN_ERROR_UNLESS (p != NULL); if (n_spec_values != 3) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "spring transition spec needs 3 arguments " "(damping-ratio, mass, stiffness), got %u", n_spec_values); return NULL; } result = bge_wdgt_spec_transition_value_spring ( spec, state_name, transition_value, spec_values[0], spec_values[1], spec_values[2], &local_error); RETURN_ERROR_UNLESS (result); } else if (g_strcmp0 (token, STR_ALLOCATE) == 0) { g_autofree char *child_value = NULL; guint n_allocation_values = 0; g_auto (GStrv) allocation_values = NULL; GET_TOKEN (&child_value, TOKEN_PARSE_DEFAULT); p = parse_args (p, spec, state_name, NULL, macro_replacements, n_anon_vals, type_hints, NULL, (GType[]){ G_TYPE_INT, G_TYPE_INT, GSK_TYPE_TRANSFORM }, 3, &allocation_values, NULL, &n_allocation_values, ARGS_PARSE_RIGHT_ASSIGN, &local_error); RETURN_ERROR_UNLESS (p != NULL); if (n_allocation_values != 2 && n_allocation_values != 3) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "allocation needs 2 or 3 values, a width " "and height and one transform, got %u", n_allocation_values); return NULL; } for (guint i = 0; i < n_allocation_values; i++) { g_autofree char *allocation_key = NULL; allocation_key = make_widget_allocation_name (child_value, (*n_anon_vals)++); switch (i) { case 0: result = bge_wdgt_spec_add_allocation_width_value ( spec, allocation_key, child_value, &local_error); break; case 1: result = bge_wdgt_spec_add_allocation_height_value ( spec, allocation_key, child_value, &local_error); break; case 2: result = bge_wdgt_spec_add_allocation_transform_value ( spec, allocation_key, child_value, &local_error); break; default: g_assert_not_reached (); } RETURN_ERROR_UNLESS (result); result = bge_wdgt_spec_set_value ( spec, state_name, allocation_key, allocation_values[i], &local_error); RETURN_ERROR_UNLESS (result); } } else if (g_strcmp0 (token, STR_MEASURE) == 0) { guint n_measurement_values = 0; g_auto (GStrv) measurement_values = NULL; p = parse_args (p, spec, state_name, NULL, macro_replacements, n_anon_vals, type_hints, NULL, (GType[]){ G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT }, 4, &measurement_values, NULL, &n_measurement_values, ARGS_PARSE_RIGHT_ASSIGN, &local_error); RETURN_ERROR_UNLESS (p != NULL); if (n_measurement_values != 4) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "measurement needs 4 values, a " "minimum width, " "natural width, " "minimum height, " "and " "natural height, " "got %u", n_measurement_values); return NULL; } for (guint i = 0; i < n_measurement_values; i++) { g_autofree char *measurement_key = NULL; measurement_key = make_widget_measurement_name ((*n_anon_vals)++); switch (i) { case 0: result = bge_wdgt_spec_add_measure_value ( spec, measurement_key, BGE_WDGT_MEASURE_MINIMUM_WIDTH, &local_error); break; case 1: result = bge_wdgt_spec_add_measure_value ( spec, measurement_key, BGE_WDGT_MEASURE_NATURAL_WIDTH, &local_error); break; case 2: result = bge_wdgt_spec_add_measure_value ( spec, measurement_key, BGE_WDGT_MEASURE_MINIMUM_HEIGHT, &local_error); break; case 3: result = bge_wdgt_spec_add_measure_value ( spec, measurement_key, BGE_WDGT_MEASURE_NATURAL_HEIGHT, &local_error); break; default: g_assert_not_reached (); } RETURN_ERROR_UNLESS (result); result = bge_wdgt_spec_set_value ( spec, state_name, measurement_key, measurement_values[i], &local_error); RETURN_ERROR_UNLESS (result); } } else UNEXPECTED_TOKEN (token); } } else UNEXPECTED_TOKEN (token); } return p; } static const char * parse_snapshot_block (const char *p, BgeWdgtSpec *spec, const char *state, GHashTable *macro_replacements, guint *n_anon_vals, GHashTable *type_hints, GError **error) { g_autoptr (GError) local_error = NULL; gboolean result = FALSE; g_autofree char *token = NULL; for (;;) { g_autofree char *action = NULL; BgeWdgtSnapshotInstrKind kind = 0; g_autofree char *instr = NULL; guint n_args = 0; g_auto (GStrv) args = NULL; GET_TOKEN (&action, TOKEN_PARSE_DEFAULT); if (g_strcmp0 (action, "}") == 0) break; else if (g_strcmp0 (action, "save") == 0) kind = BGE_WDGT_SNAPSHOT_INSTR_SAVE; else if (g_strcmp0 (action, "with") == 0) kind = BGE_WDGT_SNAPSHOT_INSTR_PUSH; else if (g_strcmp0 (action, "add") == 0) kind = BGE_WDGT_SNAPSHOT_INSTR_APPEND; else if (g_strcmp0 (action, "move") == 0) kind = BGE_WDGT_SNAPSHOT_INSTR_TRANSFORM; else if (g_strcmp0 (action, "do-child") == 0) kind = BGE_WDGT_SNAPSHOT_INSTR_SNAPSHOT_CHILD; else UNEXPECTED_TOKEN (action); if (kind == BGE_WDGT_SNAPSHOT_INSTR_SAVE) { result = bge_wdgt_spec_append_snapshot_instr ( spec, state, BGE_WDGT_SNAPSHOT_INSTR_SAVE, "save", NULL, 0, &local_error); RETURN_ERROR_UNLESS (result); } else if (kind == BGE_WDGT_SNAPSHOT_INSTR_SNAPSHOT_CHILD) { p = parse_args (p, spec, state, NULL, macro_replacements, n_anon_vals, type_hints, NULL, NULL, 0, &args, NULL, &n_args, ARGS_PARSE_RIGHT_ASSIGN, &local_error); RETURN_ERROR_UNLESS (p != NULL); result = bge_wdgt_spec_append_snapshot_instr ( spec, state, BGE_WDGT_SNAPSHOT_INSTR_SNAPSHOT_CHILD, "do-child", (const char *const *) args, n_args, &local_error); RETURN_ERROR_UNLESS (result); } else { GET_TOKEN (&instr, TOKEN_PARSE_DEFAULT); GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, "("); p = parse_args (p, spec, state, NULL, macro_replacements, n_anon_vals, type_hints, NULL, NULL, 0, &args, NULL, &n_args, ARGS_PARSE_PARENS, &local_error); RETURN_ERROR_UNLESS (p != NULL); result = bge_wdgt_spec_append_snapshot_instr ( spec, state, kind, instr, (const char *const *) args, n_args, &local_error); RETURN_ERROR_UNLESS (result); } if (kind == BGE_WDGT_SNAPSHOT_INSTR_APPEND || kind == BGE_WDGT_SNAPSHOT_INSTR_TRANSFORM) GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, ";"); else if (kind == BGE_WDGT_SNAPSHOT_INSTR_PUSH) { GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, "{"); p = parse_snapshot_block (p, spec, state, macro_replacements, n_anon_vals, type_hints, &local_error); RETURN_ERROR_UNLESS (p != NULL); result = bge_wdgt_spec_append_snapshot_instr ( spec, state, BGE_WDGT_SNAPSHOT_INSTR_POP, "pop", NULL, 0, &local_error); RETURN_ERROR_UNLESS (result); } else if (kind == BGE_WDGT_SNAPSHOT_INSTR_SAVE) { GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, "{"); p = parse_snapshot_block (p, spec, state, macro_replacements, n_anon_vals, type_hints, &local_error); RETURN_ERROR_UNLESS (p != NULL); result = bge_wdgt_spec_append_snapshot_instr ( spec, state, BGE_WDGT_SNAPSHOT_INSTR_RESTORE, "restore", NULL, 0, &local_error); RETURN_ERROR_UNLESS (result); } } return p; } static gdouble floor_closure (gpointer this, gdouble x, gpointer data) { return floor (x); } static gdouble ceil_closure (gpointer this, gdouble x, gpointer data) { return ceil (x); } static gdouble sin_closure (gpointer this, gdouble x, gpointer data) { return sin (x); } static gdouble cos_closure (gpointer this, gdouble x, gpointer data) { return cos (x); } static const char * parse_eval (const char *p, BgeWdgtSpec *spec, const char *state, GHashTable *macro_replacements, guint *n_anon_vals, GHashTable *type_hints, char **value_out, GError **error) { g_autoptr (GError) local_error = NULL; gboolean result = FALSE; g_autofree char *token = NULL; g_autoptr (GPtrArray) values = NULL; g_autoptr (GArray) ops = NULL; g_autoptr (GArray) value_types = NULL; g_autofree char *key = NULL; g_autoptr (EvalClosureData) data = NULL; values = g_ptr_array_new_with_free_func (g_free); ops = g_array_new (FALSE, FALSE, sizeof (EvalOperator)); value_types = g_array_new (FALSE, FALSE, sizeof (GType)); #define GET_TOKEN_EVAL(_token_out, _flags) \ GET_TOKEN_FULL (_token_out, _flags, EVAL_SINGLE_CHAR_TOKENS, NULL) #define GET_TOKEN_EVAL_EXPECT(_token_out, _flags, _expect) \ G_STMT_START \ { \ GET_TOKEN_EVAL ((_token_out), (_flags)); \ EXPECT_TOKEN (*(_token_out), (_expect)); \ } \ G_STMT_END for (gboolean apply_negative = FALSE;;) { g_autofree char *value = NULL; Operator op = -1; gboolean expected_value = FALSE; GET_TOKEN_EVAL (&token, TOKEN_PARSE_DEFAULT); if (g_strcmp0 (token, ")") == 0) break; else if (g_strcmp0 (token, "(") == 0) { p = parse_eval (p, spec, state, macro_replacements, n_anon_vals, type_hints, &value, &local_error); RETURN_ERROR_UNLESS (p != NULL); } else if (g_strcmp0 (token, "#") == 0) { g_auto (GStrv) escape_args = NULL; guint n_escape_args = 0; GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, "("); p = parse_args (p, spec, state, NULL, macro_replacements, n_anon_vals, type_hints, NULL, (GType[]){ G_TYPE_DOUBLE }, 1, &escape_args, NULL, &n_escape_args, ARGS_PARSE_PARENS, &local_error); RETURN_ERROR_UNLESS (p != NULL); if (n_escape_args != 1) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "evaluation escape " "needs a single argument"); return NULL; } value = g_strdup (escape_args[0]); } else if (g_strcmp0 (token, "ceil") == 0 || g_strcmp0 (token, "floor") == 0 || g_strcmp0 (token, "sin") == 0 || g_strcmp0 (token, "cos") == 0) { GCallback cb = NULL; g_autofree char *arg = NULL; g_autofree char *math_func_key = NULL; if (g_strcmp0 (token, "ceil") == 0) cb = G_CALLBACK (ceil_closure); else if (g_strcmp0 (token, "floor") == 0) cb = G_CALLBACK (floor_closure); else if (g_strcmp0 (token, "sin") == 0) cb = G_CALLBACK (sin_closure); else if (g_strcmp0 (token, "cos") == 0) cb = G_CALLBACK (cos_closure); GET_TOKEN_EVAL_EXPECT (&token, TOKEN_PARSE_DEFAULT, "("); p = parse_eval (p, spec, state, macro_replacements, n_anon_vals, type_hints, &arg, &local_error); RETURN_ERROR_UNLESS (p != NULL); math_func_key = make_anon_name ((*n_anon_vals)++); result = bge_wdgt_spec_add_cclosure_source_value ( spec, math_func_key, G_TYPE_DOUBLE, bge_marshal_DOUBLE__DOUBLE, cb, (const char *const[]){ arg }, (GType[]){ G_TYPE_DOUBLE }, 1, NULL, NULL, &local_error); RETURN_ERROR_UNLESS (result); value = g_steal_pointer (&math_func_key); } else if (g_strcmp0 (token, "+") == 0) op = OPERATOR_ADD; else if (g_strcmp0 (token, "-") == 0) op = OPERATOR_SUBTRACT; else if (g_strcmp0 (token, "*") == 0) op = OPERATOR_MULTIPLY; else if (g_strcmp0 (token, "/") == 0) op = OPERATOR_DIVIDE; else if (g_strcmp0 (token, "%") == 0) op = OPERATOR_MODULUS; else if (g_strcmp0 (token, "^") == 0) op = OPERATOR_POWER; else { value = parse_token_fundamental ( token, spec, n_anon_vals, &local_error); RETURN_ERROR_UNLESS (value != NULL); } expected_value = values->len == ops->len; if (value != NULL) { GType type_double = G_TYPE_DOUBLE; if (!expected_value) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Expected operator, got \"%s\"", token); return NULL; } if (apply_negative) { GValue gvalue = G_VALUE_INIT; g_autofree char *negative_key = NULL; EvalOperator append = { 0 }; g_value_set_double (g_value_init (&gvalue, G_TYPE_DOUBLE), -1.0); negative_key = make_anon_name ((*n_anon_vals)++); result = bge_wdgt_spec_add_constant_source_value ( spec, negative_key, &gvalue, &local_error); g_value_unset (&gvalue); RETURN_ERROR_UNLESS (result); g_ptr_array_add (values, g_steal_pointer (&negative_key)); g_array_append_val (value_types, type_double); append.op = OPERATOR_MULTIPLY; append.pos = ops->len; g_array_append_val (ops, append); apply_negative = FALSE; } g_ptr_array_add (values, g_steal_pointer (&value)); g_array_append_val (value_types, type_double); } else if (op >= 0) { EvalOperator append = { 0 }; if (expected_value) { if (op == OPERATOR_SUBTRACT) apply_negative = !apply_negative; else if (op != OPERATOR_ADD) /* Allow adding `+` in front of numbers for alignment with negatives etc */ { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Expected value, got \"%s\"", token); return NULL; } } else { append.op = op; append.pos = ops->len; g_array_append_val (ops, append); } } } if (values->len == 0) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Empty evaluation block"); return NULL; } if (ops->len != values->len - 1) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Invalid syntax in evaluation block"); return NULL; } if (values->len == 1) { *value_out = g_ptr_array_steal_index (values, 0); return p; } g_array_sort (ops, (GCompareFunc) cmp_operator); data = eval_closure_data_new (); data->ops = g_array_ref (ops); data->workbuf0 = g_malloc0_n (values->len, sizeof (gdouble)); data->workbuf1 = g_malloc0_n (values->len, sizeof (gdouble)); key = make_anon_name ((*n_anon_vals)++); result = bge_wdgt_spec_add_cclosure_source_value ( spec, key, G_TYPE_DOUBLE, _marshal_DOUBLE__ARGS_DIRECT, G_CALLBACK (eval_closure), (const char *const *) values->pdata, (const GType *) (void *) value_types->data, values->len, eval_closure_data_ref (data), eval_closure_data_unref, &local_error); RETURN_ERROR_UNLESS (result); *value_out = g_steal_pointer (&key); return p; } static const char * parse_args (const char *p, BgeWdgtSpec *spec, const char *state, const char *enclosing_object, GHashTable *macro_replacements, guint *n_anon_vals, GHashTable *type_hints, const char *const *destinations, GType destinations_types[], guint n_destinations, char ***values_out, GType **types_out, guint *n_out, ArgsParseKind parse_kind, GError **error) { g_autoptr (GError) local_error = NULL; gboolean result = FALSE; g_autofree char *token = NULL; guint n_args = 0; g_autoptr (GStrvBuilder) builder = NULL; g_autoptr (GArray) types_array = NULL; builder = g_strv_builder_new (); types_array = g_array_new (FALSE, TRUE, sizeof (GType)); for (gboolean need_comma = FALSE, get_token = TRUE, was_quoted = FALSE; ;) { if (get_token) GET_TOKEN_FULL (&token, TOKEN_PARSE_DEFAULT, SINGLE_CHAR_TOKENS, &was_quoted); get_token = TRUE; if (was_quoted) { g_autofree char *tmp_token = NULL; g_autofree char *key = NULL; GValue value = { 0 }; g_value_set_string (g_value_init (&value, G_TYPE_STRING), token); key = make_anon_name ((*n_anon_vals)++); result = bge_wdgt_spec_add_constant_source_value ( spec, key, &value, &local_error); g_value_unset (&value); RETURN_ERROR_UNLESS (result); g_strv_builder_take (builder, g_steal_pointer (&key)); n_args++; need_comma = TRUE; } else if ((parse_kind == ARGS_PARSE_LEFT_ASSIGN && g_strcmp0 (token, "=") == 0) || (parse_kind == ARGS_PARSE_RIGHT_ASSIGN && g_strcmp0 (token, ";") == 0) || (parse_kind == ARGS_PARSE_PARENS && g_strcmp0 (token, ")") == 0)) break; else if (need_comma) { if (g_strcmp0 (token, ",") == 0) { need_comma = FALSE; continue; } else { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Arguments must be comma-separated"); return NULL; } } else if (g_strcmp0 (token, "#eval") == 0) { g_autofree char *key = NULL; GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, "("); p = parse_eval (p, spec, state, macro_replacements, n_anon_vals, type_hints, &key, &local_error); RETURN_ERROR_UNLESS (p != NULL); g_strv_builder_take (builder, g_steal_pointer (&key)); n_args++; need_comma = TRUE; } else if (g_strcmp0 (token, "#transition") == 0) { g_autofree char *key = NULL; guint n_spec_values = 0; g_auto (GStrv) spec_values = NULL; GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, "("); p = parse_args (p, spec, state, NULL, macro_replacements, n_anon_vals, type_hints, NULL, (GType[]){ G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE }, 4, &spec_values, NULL, &n_spec_values, ARGS_PARSE_PARENS, &local_error); RETURN_ERROR_UNLESS (p != NULL); if (n_spec_values != 4) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "#transition() needs 4 arguments " "(variable, damping-ratio, mass, stiffness), " "got %u", n_spec_values); return NULL; } key = make_anon_name ((*n_anon_vals)++); result = bge_wdgt_spec_add_track_transition_source_value ( spec, key, spec_values[0], spec_values[1], spec_values[2], spec_values[3], &local_error); RETURN_ERROR_UNLESS (result); g_strv_builder_take (builder, g_steal_pointer (&key)); n_args++; need_comma = TRUE; } else { g_autofree char *key = NULL; GType type = G_TYPE_INVALID; if (g_hash_table_contains (type_hints, token) || /* A macro placed this here */ g_utf8_strchr (token, -1, '@') != NULL) key = g_steal_pointer (&token); else { GType type_hint = G_TYPE_INVALID; gboolean expect_closing_paren = FALSE; gboolean is_child = FALSE; gboolean constant = FALSE; GValue value = G_VALUE_INIT; if (n_args < n_destinations) { if (destinations != NULL) type_hint = GPOINTER_TO_SIZE (g_hash_table_lookup ( type_hints, destinations[n_args])); if (type_hint == G_TYPE_INVALID && destinations_types != NULL) type_hint = destinations_types[n_args]; } if (g_str_has_prefix (token, "#")) { const char *type_name = token + 1; if (g_str_has_prefix (type_name, "child/")) { is_child = TRUE; type_name += strlen ("child/"); } if (*type_name == '\0') { if (type_hint == G_TYPE_INVALID) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Unable to guess type for value"); return NULL; } type = type_hint; } else { type = g_type_from_name (type_name); if (type == G_TYPE_INVALID) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Unknown type name \"%s\"", type_name); return NULL; } } GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, "("); expect_closing_paren = TRUE; } else type = type_hint; if (is_child && !g_type_is_a (type, GTK_TYPE_WIDGET)) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Children must be a widget type"); return NULL; } if (type == G_TYPE_INVALID) { if (expect_closing_paren) GET_TOKEN (&token, TOKEN_PARSE_DEFAULT); key = parse_token_fundamental (token, spec, n_anon_vals, &local_error); RETURN_ERROR_UNLESS (key != NULL); } else if (type == G_TYPE_STRING) { if (expect_closing_paren) GET_TOKEN (&token, TOKEN_PARSE_DEFAULT); g_value_set_string (g_value_init (&value, G_TYPE_STRING), token); constant = TRUE; if (expect_closing_paren) GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, ")"); } else if (type == G_TYPE_BOOLEAN) { if (expect_closing_paren) GET_TOKEN (&token, TOKEN_PARSE_DEFAULT); if (g_strcmp0 (token, "true") == 0) g_value_set_boolean (g_value_init (&value, G_TYPE_BOOLEAN), TRUE); else if (g_strcmp0 (token, "false") == 0) g_value_set_boolean (g_value_init (&value, G_TYPE_BOOLEAN), FALSE); else { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "a boolean value must be 'true' " "or 'false', got \"%s\"", token); return NULL; } constant = TRUE; if (expect_closing_paren) GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, ")"); } else if (type == G_TYPE_INT || type == G_TYPE_INT64 || type == G_TYPE_UINT || type == G_TYPE_UINT64 || type == G_TYPE_FLOAT || type == G_TYPE_DOUBLE) { const GVariantType *variant_type = NULL; g_autoptr (GVariant) variant = NULL; if (type == G_TYPE_INT) variant_type = G_VARIANT_TYPE_INT32; else if (type == G_TYPE_INT64) variant_type = G_VARIANT_TYPE_INT64; else if (type == G_TYPE_UINT) variant_type = G_VARIANT_TYPE_UINT32; else if (type == G_TYPE_UINT64) variant_type = G_VARIANT_TYPE_UINT64; else if (type == G_TYPE_FLOAT || type == G_TYPE_DOUBLE) variant_type = G_VARIANT_TYPE_DOUBLE; if (expect_closing_paren) GET_TOKEN (&token, TOKEN_PARSE_DEFAULT); variant = g_variant_parse (variant_type, token, NULL, NULL, &local_error); RETURN_ERROR_UNLESS (variant != NULL); if (type == G_TYPE_INT) g_value_set_int (g_value_init (&value, G_TYPE_INT), g_variant_get_int32 (variant)); else if (type == G_TYPE_INT64) g_value_set_int64 (g_value_init (&value, G_TYPE_INT64), g_variant_get_int64 (variant)); else if (type == G_TYPE_UINT) g_value_set_uint (g_value_init (&value, G_TYPE_UINT), g_variant_get_uint32 (variant)); else if (type == G_TYPE_UINT64) g_value_set_uint64 (g_value_init (&value, G_TYPE_UINT64), g_variant_get_uint64 (variant)); else if (type == G_TYPE_FLOAT) g_value_set_float (g_value_init (&value, G_TYPE_FLOAT), g_variant_get_double (variant)); else if (type == G_TYPE_DOUBLE) g_value_set_double (g_value_init (&value, G_TYPE_DOUBLE), g_variant_get_double (variant)); constant = TRUE; if (expect_closing_paren) GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, ")"); } else if (g_type_is_a (type, G_TYPE_ENUM)) { g_autoptr (GEnumClass) enum_class = NULL; GEnumValue *enum_value = NULL; if (expect_closing_paren) GET_TOKEN (&token, TOKEN_PARSE_DEFAULT); enum_class = g_type_class_ref (type); enum_value = g_enum_get_value_by_nick (enum_class, token); if (enum_value == NULL) enum_value = g_enum_get_value_by_name (enum_class, token); if (enum_value == NULL) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "\"%s\" not found in enum type %s", token, g_type_name (type)); return NULL; } g_value_set_enum (g_value_init (&value, type), enum_value->value); constant = TRUE; if (expect_closing_paren) GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, ")"); } else if (type == GDK_TYPE_RGBA) { GdkRGBA rgba = { 0 }; if (expect_closing_paren) GET_TOKEN (&token, TOKEN_PARSE_DEFAULT); result = gdk_rgba_parse (&rgba, token); if (!result) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "#color() specifier failed to " "parse color from string"); return NULL; } g_value_set_boxed (g_value_init (&value, GDK_TYPE_RGBA), &rgba); constant = TRUE; if (expect_closing_paren) GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, ")"); } else if (type == GRAPHENE_TYPE_POINT || type == GRAPHENE_TYPE_SIZE || type == GRAPHENE_TYPE_RECT) { g_auto (GStrv) component_args = NULL; guint n_component_args = 0; GType component_type = 0; if (!expect_closing_paren) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "type %s must be wrapped in #(...)", g_type_name (type)); return NULL; } p = parse_args (p, spec, state, enclosing_object, macro_replacements, n_anon_vals, type_hints, NULL, (GType[]){ G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE }, 4, &component_args, NULL, &n_component_args, ARGS_PARSE_PARENS, &local_error); RETURN_ERROR_UNLESS (p != NULL); if (type == GRAPHENE_TYPE_POINT) { switch (n_component_args) { case 2: component_type = GRAPHENE_TYPE_POINT; break; case 3: component_type = GRAPHENE_TYPE_POINT3D; break; default: g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "#point() specifier can have 2 or 3 arguments, got %u", n_component_args); return NULL; } } else if (type == GRAPHENE_TYPE_SIZE) { switch (n_component_args) { case 2: component_type = GRAPHENE_TYPE_SIZE; break; default: g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "#size() specifier can have 2 arguments, got %u", n_component_args); return NULL; } } else if (type == GRAPHENE_TYPE_RECT) { switch (n_component_args) { case 4: component_type = GRAPHENE_TYPE_RECT; break; default: g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "#rect() specifier can have 4 arguments, got %u", n_component_args); return NULL; } } key = make_anon_name ((*n_anon_vals)++); result = bge_wdgt_spec_add_component_source_value ( spec, key, component_type, (const char *const *) component_args, n_component_args, &local_error); RETURN_ERROR_UNLESS (result); } else if (g_type_is_a (type, G_TYPE_OBJECT)) { if (!expect_closing_paren) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "type %s must be wrapped in #(...)", g_type_name (type)); return NULL; } key = make_anon_name ((*n_anon_vals)++); if (is_child) { g_autofree char *builder_type = NULL; g_autoptr (GPtrArray) css_classes = NULL; GET_TOKEN (&builder_type, TOKEN_PARSE_QUOTED); if (*builder_type == '\0') g_clear_pointer (&builder_type, g_free); css_classes = g_ptr_array_new_with_free_func (g_free); GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, "("); for (;;) { GET_TOKEN (&token, TOKEN_PARSE_DEFAULT); if (g_strcmp0 (token, ")") == 0) break; g_ptr_array_add (css_classes, g_steal_pointer (&token)); } result = bge_wdgt_spec_add_child_source_value ( spec, key, type, enclosing_object, builder_type, (const char *const *) css_classes->pdata, css_classes->len, &local_error); RETURN_ERROR_UNLESS (result); } else { result = bge_wdgt_spec_add_instance_source_value ( spec, key, type, &local_error); RETURN_ERROR_UNLESS (result); } for (;;) { g_autofree char *property_name = NULL; g_autofree char *set_key = NULL; GType prop_type = G_TYPE_INVALID; g_auto (GStrv) value_args = NULL; guint n_value_args = 0; GET_TOKEN (&property_name, TOKEN_PARSE_DEFAULT); if (g_strcmp0 (property_name, ")") == 0) break; else if (g_strcmp0 (property_name, "%set") == 0) { GET_TOKEN (&set_key, TOKEN_PARSE_DEFAULT); prop_type = GPOINTER_TO_SIZE (g_hash_table_lookup (type_hints, set_key)); } else if (g_strcmp0 (property_name, "_") != 0) { set_key = make_object_property_name (key, property_name, (*n_anon_vals)++); result = bge_wdgt_spec_add_property_value ( spec, set_key, key, property_name, &prop_type, &local_error); RETURN_ERROR_UNLESS (result); } GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, "="); p = parse_args (p, spec, state, key, macro_replacements, n_anon_vals, type_hints, NULL, (GType[]){ prop_type }, 1, &value_args, NULL, &n_value_args, ARGS_PARSE_RIGHT_ASSIGN, &local_error); RETURN_ERROR_UNLESS (p != NULL); if (n_value_args != 1) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "property/child assignment " "needs a single argument, got %u", n_value_args); return NULL; } if (set_key != NULL) { result = bge_wdgt_spec_set_value (spec, state, set_key, value_args[0], &local_error); RETURN_ERROR_UNLESS (result); } } } else if (type == GSK_TYPE_TRANSFORM) { g_autofree char *last_key = NULL; if (!expect_closing_paren) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "type %s must be wrapped in #(...)", g_type_name (type)); return NULL; } last_key = make_anon_name ((*n_anon_vals)++); g_value_take_boxed (g_value_init (&value, GSK_TYPE_TRANSFORM), gsk_transform_new ()); result = bge_wdgt_spec_add_constant_source_value ( spec, last_key, &value, error); g_value_unset (&value); if (!result) return NULL; for (;;) { g_autofree char *instr = NULL; g_auto (GStrv) value_args = NULL; guint n_value_args = 0; g_autofree char *tmp_key = NULL; GET_TOKEN (&instr, TOKEN_PARSE_DEFAULT); if (g_strcmp0 (instr, ")") == 0) break; GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, "("); p = parse_args (p, spec, state, enclosing_object, macro_replacements, n_anon_vals, type_hints, NULL, NULL, 0, &value_args, NULL, &n_value_args, ARGS_PARSE_PARENS, &local_error); RETURN_ERROR_UNLESS (p != NULL); GET_TOKEN_EXPECT (&token, TOKEN_PARSE_DEFAULT, ";"); tmp_key = make_anon_name ((*n_anon_vals)++); result = bge_wdgt_spec_add_transform_source_value ( spec, tmp_key, last_key, instr, (const char *const *) value_args, n_value_args, &local_error); RETURN_ERROR_UNLESS (result); g_clear_pointer (&last_key, g_free); last_key = g_steal_pointer (&tmp_key); } key = g_steal_pointer (&last_key); } else { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Can't parse type %s", g_type_name (type)); return NULL; } if (constant) { key = make_anon_name ((*n_anon_vals)++); result = bge_wdgt_spec_add_constant_source_value ( spec, key, &value, &local_error); g_value_unset (&value); RETURN_ERROR_UNLESS (result); } } for (;;) { GET_TOKEN (&token, TOKEN_PARSE_DEFAULT); if (g_strcmp0 (token, ":") == 0) { g_autofree char *property = NULL; g_autofree char *name = NULL; GET_TOKEN (&property, TOKEN_PARSE_DEFAULT); name = make_object_property_name (key, property, (*n_anon_vals)++); result = bge_wdgt_spec_add_property_value ( spec, name, key, property, &type, &local_error); RETURN_ERROR_UNLESS (result); g_clear_pointer (&key, g_free); key = g_steal_pointer (&name); } else break; } get_token = FALSE; g_strv_builder_add (builder, key); g_array_append_val (types_array, type); n_args++; need_comma = TRUE; } } if (n_out != NULL) *n_out = n_args; if (values_out != NULL) *values_out = g_strv_builder_end (builder); if (types_out != NULL) *types_out = g_array_steal (types_array, NULL); return p; } #undef GET_TOKEN_EXPECT #undef GET_TOKEN #undef UNEXPECTED_TOKEN #undef EXPECT_TOKEN #undef RETURN_ERROR_UNLESS static char * parse_token_fundamental (const char *token, BgeWdgtSpec *spec, guint *n_anon_vals, GError **error) { g_autoptr (GError) local_error = NULL; gboolean result = FALSE; gunichar ch = 0; GValue value = { 0 }; g_autofree char *key = NULL; ch = g_utf8_get_char (token); if (ch == '-' || g_unichar_isdigit (ch)) { gboolean is_double = FALSE; g_autoptr (GVariant) variant = NULL; is_double = g_utf8_strchr (token, -1, '.') != NULL; if (is_double) variant = g_variant_parse (G_VARIANT_TYPE_DOUBLE, token, NULL, NULL, &local_error); else variant = g_variant_parse (G_VARIANT_TYPE_INT32, token, NULL, NULL, &local_error); if (variant == NULL) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Unable to parse number value '%s': %s", token, local_error->message); return NULL; } if (is_double) g_value_set_double (g_value_init (&value, G_TYPE_DOUBLE), g_variant_get_double (variant)); else g_value_set_int (g_value_init (&value, G_TYPE_INT), g_variant_get_int32 (variant)); } else if (g_strcmp0 (token, "true") == 0) g_value_set_boolean (g_value_init (&value, G_TYPE_BOOLEAN), TRUE); else if (g_strcmp0 (token, "false") == 0) g_value_set_boolean (g_value_init (&value, G_TYPE_BOOLEAN), FALSE); else return g_strdup (token); if (key == NULL) key = make_anon_name ((*n_anon_vals)++); result = bge_wdgt_spec_add_constant_source_value ( spec, key, &value, error); g_value_unset (&value); if (!result) return NULL; return g_steal_pointer (&key); } static char * consume_token (const char **pp, const char *single_chars, TokenParseFlags flags, gboolean *was_quoted, GHashTable *macro_replacements, GError **error) { g_autofree char *token = NULL; token = consume_token_inner (pp, single_chars, flags, was_quoted, error); if (token == NULL) return NULL; if (macro_replacements != NULL) { const char *replacement = NULL; replacement = g_hash_table_lookup (macro_replacements, token); if (replacement != NULL) return g_strdup (replacement); else { const char *replace_start = NULL; replace_start = g_utf8_strchr (token, -1, '@'); if (replace_start != NULL) { const char *last_end = token; g_autoptr (GString) string = NULL; string = g_string_new (NULL); for (;;) { g_autofree char *replace = NULL; const char *with = NULL; if (replace_start - last_end > 0) g_string_append_len (string, last_end, replace_start - last_end); replace_start++; last_end = g_utf8_strchr (replace_start, -1, '@'); if (last_end == NULL) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "error in macro expansion: " "unterminated replacement"); return NULL; } replace = g_strndup (replace_start, last_end - replace_start); with = g_hash_table_lookup (macro_replacements, replace); if (with == NULL) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "error in macro expansion: " "undefined string \"%s\"", replace); return NULL; } g_string_append (string, with); last_end++; replace_start = g_utf8_strchr (last_end, '@', -1); if (replace_start == NULL) break; } if (*last_end != '\0') g_string_append (string, last_end); return g_string_free_and_steal (g_steal_pointer (&string)); } } } return g_steal_pointer (&token); } static char * consume_token_inner (const char **pp, const char *single_chars, TokenParseFlags flags, gboolean *was_quoted, GError **error) { const char *p = *pp; gboolean hit_non_space = FALSE; if (was_quoted != NULL) *was_quoted = FALSE; #define UNEXPECTED_EOF \ G_STMT_START \ { \ g_set_error ( \ error, \ G_IO_ERROR, \ G_IO_ERROR_UNKNOWN, \ "Unexpected EOF"); \ return NULL; \ } \ G_STMT_END #define RETURN_TOKEN \ G_STMT_START \ { \ g_autofree char *_ret = NULL; \ \ _ret = g_strndup (*pp, p - *pp); \ *pp = p; \ return g_steal_pointer (&_ret); \ } \ G_STMT_END #define RETURN_TOKEN_ADJUST_NEXT_CHAR \ G_STMT_START \ { \ g_autofree char *_ret = NULL; \ \ _ret = g_strndup (*pp, p - *pp); \ *pp = g_utf8_next_char (p); \ return g_steal_pointer (&_ret); \ } \ G_STMT_END if (IS_EOF (p)) UNEXPECTED_EOF; for (; !IS_EOF (p); p = g_utf8_next_char (p)) { gunichar ch = 0; gboolean is_whitespace = FALSE; gboolean is_quotes = FALSE; ch = g_utf8_get_char (p); is_whitespace = ch == '\n' || g_unichar_isspace (ch); is_quotes = ch == '"'; if (is_whitespace) { if (!(flags & TOKEN_PARSE_QUOTED) && hit_non_space) RETURN_TOKEN; } else { if (is_quotes) { if (hit_non_space) { if (was_quoted != NULL) *was_quoted = TRUE; if (flags & TOKEN_PARSE_QUOTED) RETURN_TOKEN_ADJUST_NEXT_CHAR; else RETURN_TOKEN; } else { flags |= TOKEN_PARSE_QUOTED; *pp = g_utf8_next_char (p); if (IS_EOF (*pp)) UNEXPECTED_EOF; hit_non_space = TRUE; } } else if (flags & TOKEN_PARSE_QUOTED) { if (!hit_non_space) { g_set_error ( error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "Expected quote"); return NULL; } } else if (single_chars != NULL && g_utf8_strchr (single_chars, -1, ch) != NULL) { if (hit_non_space) RETURN_TOKEN; else { char buf[16] = { 0 }; g_unichar_to_utf8 (ch, buf); *pp = g_utf8_next_char (p); return g_strdup (buf); } } if (!hit_non_space) { *pp = p; hit_non_space = TRUE; } } } if (!(flags & TOKEN_PARSE_QUOTED) && hit_non_space) RETURN_TOKEN; UNEXPECTED_EOF; #undef RETURN_TOKEN_ADJUST_NEXT_CHAR #undef RETURN_TOKEN #undef UNEXPECTED_EOF } static gdouble eval_closure (gpointer this, guint n_param_values, const GValue *param_values, EvalClosureData *data) { GArray *ops = data->ops; gdouble *workbuf0 = data->workbuf0; gdouble *workbuf1 = data->workbuf1; gdouble result = 0.0; for (guint i = 0; i < n_param_values; i++) { workbuf0[i] = g_value_get_double (¶m_values[i]); workbuf1[i] = 1.0; } for (guint i = 0; i < ops->len; i++) { EvalOperator *op = NULL; guint left_idx = 0; guint right_idx = 0; gdouble left = 0.0; gdouble right = 0.0; op = &g_array_index (ops, EvalOperator, i); left_idx = op->pos; while (workbuf1[left_idx] < 0.0) { left_idx--; } right_idx = op->pos + 1; while (workbuf1[right_idx] < 0.0) { right_idx++; } left = workbuf0[left_idx]; right = workbuf0[right_idx]; switch (op->op) { case OPERATOR_ADD: result = left + right; break; case OPERATOR_SUBTRACT: result = left - right; break; case OPERATOR_MULTIPLY: result = left * right; break; case OPERATOR_DIVIDE: result = left / right; break; case OPERATOR_MODULUS: result = fmod (left, right); break; case OPERATOR_POWER: result = pow (left, right); break; default: g_assert_not_reached (); } workbuf0[left_idx] = result; workbuf1[left_idx] = 1.0; workbuf1[right_idx] = -1.0; } return result; } static char * make_object_property_name (const char *object, const char *property, guint n) { return g_strdup_printf ("prop@%u(%s).%s", n, object, property); } static char * make_widget_allocation_name (const char *widget, guint n) { return g_strdup_printf ("allocation@%u(%s)", n, widget); } static char * make_widget_measurement_name (guint n) { return g_strdup_printf ("measurement@%u", n); } static char * make_anon_name (guint n) { return g_strdup_printf ("anon@%u", n); } static gint cmp_operator (EvalOperator *a, EvalOperator *b) { int a_prec = 0; int b_prec = 0; a_prec = operator_precedence[a->op]; b_prec = operator_precedence[b->op]; return a_prec > b_prec ? -1 : 1; } static void _marshal_DOUBLE__ARGS_DIRECT (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef gdouble (*GMarshalFunc_DOUBLE__ARGS_DIRECT) (gpointer data1, guint n_param_values, const GValue *param_values, gpointer data2); GCClosure *cc = (GCClosure *) closure; gpointer data1, data2; GMarshalFunc_DOUBLE__ARGS_DIRECT callback; gdouble v_return; g_return_if_fail (return_value != NULL); g_return_if_fail (n_param_values >= 1); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_DOUBLE__ARGS_DIRECT) (marshal_data ? marshal_data : cc->callback); v_return = callback (data1, n_param_values - 1, param_values + 1, data2); g_value_set_double (return_value, v_return); } bazaar-orig-v0.7.14/bge/wdgt/bge-wdgt-time.c0000664000175000017500000001106015166123241017440 0ustar hasanhasan/* bge-wdgt-time.c * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "bge.h" struct _BgeWdgtTime { GObject parent_instance; guint notify_msec; GTimer *timer; guint source; }; G_DEFINE_FINAL_TYPE (BgeWdgtTime, bge_wdgt_time, G_TYPE_OBJECT); enum { PROP_0, PROP_TIME, PROP_NOTIFY_MSEC, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void make_timeout_source (BgeWdgtTime *self); static gboolean timeout_cb (BgeWdgtTime *self); static void bge_wdgt_time_dispose (GObject *object) { BgeWdgtTime *self = BGE_WDGT_TIME (object); g_clear_pointer (&self->timer, g_timer_destroy); g_clear_handle_id (&self->source, g_source_remove); G_OBJECT_CLASS (bge_wdgt_time_parent_class)->dispose (object); } static void bge_wdgt_time_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BgeWdgtTime *self = BGE_WDGT_TIME (object); switch (prop_id) { case PROP_TIME: g_value_set_double (value, bge_wdgt_time_get_time (self)); break; case PROP_NOTIFY_MSEC: g_value_set_uint (value, bge_wdgt_time_get_notify_msec (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bge_wdgt_time_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BgeWdgtTime *self = BGE_WDGT_TIME (object); switch (prop_id) { case PROP_NOTIFY_MSEC: bge_wdgt_time_set_notify_msec (self, g_value_get_uint (value)); break; case PROP_TIME: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bge_wdgt_time_class_init (BgeWdgtTimeClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bge_wdgt_time_set_property; object_class->get_property = bge_wdgt_time_get_property; object_class->dispose = bge_wdgt_time_dispose; props[PROP_TIME] = g_param_spec_double ( "time", NULL, NULL, 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_NOTIFY_MSEC] = g_param_spec_uint ( "notify-msec", NULL, NULL, 0, G_MAXUINT, 30, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bge_wdgt_time_init (BgeWdgtTime *self) { self->notify_msec = 30; self->timer = g_timer_new (); make_timeout_source (self); } BgeWdgtTime * bge_wdgt_time_new (void) { return g_object_new (BGE_TYPE_WDGT_TIME, NULL); } double bge_wdgt_time_get_time (BgeWdgtTime *self) { g_return_val_if_fail (BGE_IS_WDGT_TIME (self), 0.0); return g_timer_elapsed (self->timer, NULL); } guint bge_wdgt_time_get_notify_msec (BgeWdgtTime *self) { g_return_val_if_fail (BGE_IS_WDGT_TIME (self), 0); return self->notify_msec; } void bge_wdgt_time_set_notify_msec (BgeWdgtTime *self, guint notify_msec) { g_return_if_fail (BGE_IS_WDGT_TIME (self)); if (notify_msec == self->notify_msec) return; self->notify_msec = notify_msec; make_timeout_source (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NOTIFY_MSEC]); } static void make_timeout_source (BgeWdgtTime *self) { g_clear_handle_id (&self->source, g_source_remove); if (self->notify_msec > 0) self->source = g_timeout_add (self->notify_msec, (GSourceFunc) timeout_cb, self); } static gboolean timeout_cb (BgeWdgtTime *self) { g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TIME]); return G_SOURCE_CONTINUE; } /* End of bge-wdgt-time.c */ bazaar-orig-v0.7.14/bge/wdgt/bge-wdgt-spec.c0000664000175000017500000062575415166123241017461 0ustar hasanhasan/* bge-wdgt-spec.c * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include "../bge-animation-private.h" #include "bge-marshalers.h" #include "bge-wdgt-spec-private.h" #include "bge.h" #include "fmt/parser.h" #include "graphene-gobject.h" #include "util.h" #define ARGBUF_SIZE 128 static void _marshal_DIRECT__ARGS_DIRECT (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data); static void _marshal_BOXED__ARGS_DIRECT (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data); typedef enum { VALUE_OBJECT = 0, VALUE_CONSTANT, VALUE_COMPONENT, VALUE_TRANSFORM, VALUE_CLOSURE, VALUE_COERCION, VALUE_TRACK_TRANSITION, VALUE_SPECIAL, VALUE_VARIABLE, VALUE_REFERENCE_OBJECT, VALUE_PROPERTY, VALUE_CHILD, VALUE_ALLOCATION_WIDTH, VALUE_ALLOCATION_HEIGHT, VALUE_ALLOCATION_TRANSFORM, VALUE_MEASURE_MINIMUM_WIDTH, VALUE_MEASURE_NATURAL_WIDTH, VALUE_MEASURE_MINIMUM_HEIGHT, VALUE_MEASURE_NATURAL_HEIGHT, VALUE_MEASURE_FOR_SIZE, VALUE_WIDGET_WIDTH, VALUE_WIDGET_HEIGHT, } ValueKind; typedef enum { TRANSITION_EASE = 0, TRANSITION_SPRING, } TransitionKind; typedef GskTransform *(*TransformCallFunc) (GskTransform *next, const GValue args[]); typedef struct { const char *name; guint n_args; GType args[16]; gpointer func; TransformCallFunc call; } TransformInstr; typedef void (*SnapshotCallFunc) (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest); typedef struct { const char *name; guint n_args; guint n_rest; GType args[16]; gpointer func; SnapshotCallFunc call; } SnapshotInstr; static void deinit_value (gpointer ptr); BGE_DEFINE_DATA ( value, Value, { char *name; GType type; ValueKind kind; union { GValue constant; GPtrArray *component; struct { TransformCallFunc func; ValueData *next; GPtrArray *args; } transform; struct { GPtrArray *args; GClosureMarshal marshal; GCallback func; gpointer user_data; GDestroyNotify destroy_user_data; } closure; struct { ValueData *src; struct { ValueData *damping_ratio; ValueData *mass; ValueData *stiffness; } spring; } track_transition; BgeWdgtSpecialValue special; struct { ValueData *value; } coercion; struct { ValueData *object; char *prop_name; GParamFlags pspec_flags; } property; struct { ValueData *parent_widget; char *builder_type; GPtrArray *css_classes; } child; struct { ValueData *widget; } allocation; }; }, deinit_value (self);) static void deinit_value (gpointer ptr) { ValueData *value = ptr; g_clear_pointer (&value->name, g_free); switch (value->kind) { case VALUE_OBJECT: break; case VALUE_CONSTANT: g_value_unset (&value->constant); break; case VALUE_COMPONENT: g_clear_pointer (&value->component, g_ptr_array_unref); break; case VALUE_TRANSFORM: g_clear_pointer (&value->transform.next, value_data_unref); g_clear_pointer (&value->transform.args, g_ptr_array_unref); break; case VALUE_CLOSURE: g_clear_pointer (&value->closure.args, g_ptr_array_unref); if (value->closure.destroy_user_data != NULL) g_clear_pointer (&value->closure.user_data, value->closure.destroy_user_data); break; case VALUE_COERCION: g_clear_pointer (&value->coercion.value, value_data_unref); break; case VALUE_TRACK_TRANSITION: g_clear_pointer (&value->track_transition.src, value_data_unref); g_clear_pointer (&value->track_transition.spring.damping_ratio, value_data_unref); g_clear_pointer (&value->track_transition.spring.mass, value_data_unref); g_clear_pointer (&value->track_transition.spring.stiffness, value_data_unref); break; case VALUE_SPECIAL: break; case VALUE_VARIABLE: break; case VALUE_REFERENCE_OBJECT: break; case VALUE_PROPERTY: g_clear_pointer (&value->property.object, value_data_unref); g_clear_pointer (&value->property.prop_name, g_free); break; case VALUE_CHILD: g_clear_pointer (&value->child.parent_widget, value_data_unref); g_clear_pointer (&value->child.builder_type, g_free); g_clear_pointer (&value->child.css_classes, g_ptr_array_unref); break; case VALUE_ALLOCATION_WIDTH: case VALUE_ALLOCATION_HEIGHT: case VALUE_ALLOCATION_TRANSFORM: g_clear_pointer (&value->allocation.widget, value_data_unref); break; case VALUE_MEASURE_MINIMUM_WIDTH: case VALUE_MEASURE_NATURAL_WIDTH: case VALUE_MEASURE_MINIMUM_HEIGHT: case VALUE_MEASURE_NATURAL_HEIGHT: case VALUE_MEASURE_FOR_SIZE: case VALUE_WIDGET_WIDTH: case VALUE_WIDGET_HEIGHT: break; default: g_assert_not_reached (); } } static void deinit_transition (gpointer ptr); BGE_DEFINE_DATA ( transition, Transition, { TransitionKind kind; union { struct { double seconds; BgeEasing easing; } ease; struct { ValueData *damping_ratio; ValueData *mass; ValueData *stiffness; } spring; }; }, deinit_transition (self);) static void deinit_transition (gpointer ptr) { TransitionData *transition = ptr; switch (transition->kind) { case TRANSITION_EASE: break; case TRANSITION_SPRING: g_clear_pointer (&transition->spring.damping_ratio, value_data_unref); g_clear_pointer (&transition->spring.mass, value_data_unref); g_clear_pointer (&transition->spring.stiffness, value_data_unref); break; default: g_assert_not_reached (); } } BGE_DEFINE_DATA ( snapshot_call, SnapshotCall, { BgeWdgtSnapshotInstrKind kind; SnapshotCallFunc func; GPtrArray *args; GPtrArray *rest; ValueData *child; }, BGE_RELEASE_DATA (args, g_ptr_array_unref); BGE_RELEASE_DATA (rest, g_ptr_array_unref); BGE_RELEASE_DATA (child, value_data_unref)) BGE_DEFINE_DATA ( snapshot, Snapshot, { GPtrArray *calls; }, BGE_RELEASE_DATA (calls, g_ptr_array_unref)) BGE_DEFINE_DATA ( state, State, { char *name; GHashTable *setters; GHashTable *transitions; SnapshotData *snapshot; }, BGE_RELEASE_DATA (name, g_free); BGE_RELEASE_DATA (setters, g_hash_table_unref); BGE_RELEASE_DATA (transitions, g_hash_table_unref); BGE_RELEASE_DATA (snapshot, snapshot_data_unref)) /* --------------------------- */ /* Spec Builder Implementation */ /* --------------------------- */ struct _BgeWdgtSpec { GObject parent_instance; char *name; GHashTable *values; GPtrArray *anon_values; GHashTable *states; GPtrArray *children; GPtrArray *nonchildren; StateData *init_state; StateData *default_state; ValueData *reference; struct { ValueData *motion_x; ValueData *motion_y; } special_values; }; G_DEFINE_FINAL_TYPE (BgeWdgtSpec, bge_wdgt_spec, G_TYPE_OBJECT); enum { PROP_0, PROP_NAME, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static gboolean check_can_coerce_type (GType dest, GType src); static void coerce_value (const GValue *in, GType dest_type, GValue *out); static ValueData * wrap_coerce_value (BgeWdgtSpec *self, ValueData *value, GType dest_type); static gboolean lookup_transform_instr (const char *lookup_name, TransformInstr *out); static gboolean lookup_snapshot_push_instr (const char *lookup_name, SnapshotInstr *out); static gboolean lookup_snapshot_transform_instr (const char *lookup_name, SnapshotInstr *out); static gboolean lookup_snapshot_append_instr (const char *lookup_name, SnapshotInstr *out); static void ensure_state_snapshot (StateData *state); static void bge_wdgt_spec_dispose (GObject *object) { BgeWdgtSpec *self = BGE_WDGT_SPEC (object); g_clear_pointer (&self->name, g_free); g_clear_pointer (&self->values, g_hash_table_unref); g_clear_pointer (&self->anon_values, g_ptr_array_unref); g_clear_pointer (&self->states, g_hash_table_unref); g_clear_pointer (&self->children, g_ptr_array_unref); g_clear_pointer (&self->nonchildren, g_ptr_array_unref); g_clear_pointer (&self->init_state, state_data_unref); g_clear_pointer (&self->default_state, state_data_unref); g_clear_pointer (&self->reference, value_data_unref); G_OBJECT_CLASS (bge_wdgt_spec_parent_class)->dispose (object); } static void bge_wdgt_spec_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BgeWdgtSpec *self = BGE_WDGT_SPEC (object); switch (prop_id) { case PROP_NAME: g_value_set_string (value, bge_wdgt_spec_get_name (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bge_wdgt_spec_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BgeWdgtSpec *self = BGE_WDGT_SPEC (object); switch (prop_id) { case PROP_NAME: bge_wdgt_spec_set_name (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bge_wdgt_spec_class_init (BgeWdgtSpecClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bge_wdgt_spec_set_property; object_class->get_property = bge_wdgt_spec_get_property; object_class->dispose = bge_wdgt_spec_dispose; props[PROP_NAME] = g_param_spec_string ( "name", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); g_type_ensure (BGE_TYPE_EASING); g_type_ensure (BGE_TYPE_WDGT_TIME); /* Make sure these names are available for the parser */ g_type_ensure (GRAPHENE_TYPE_POINT); g_type_ensure (GRAPHENE_TYPE_POINT3D); g_type_ensure (GRAPHENE_TYPE_SIZE); g_type_ensure (GRAPHENE_TYPE_RECT); g_type_ensure (GRAPHENE_TYPE_VEC2); g_type_ensure (GRAPHENE_TYPE_VEC3); g_type_ensure (GRAPHENE_TYPE_VEC4); g_type_ensure (GRAPHENE_TYPE_QUAD); g_type_ensure (GRAPHENE_TYPE_QUATERNION); g_type_ensure (GRAPHENE_TYPE_MATRIX); g_type_ensure (GRAPHENE_TYPE_PLANE); g_type_ensure (GRAPHENE_TYPE_FRUSTUM); g_type_ensure (GRAPHENE_TYPE_SPHERE); g_type_ensure (GRAPHENE_TYPE_BOX); g_type_ensure (GRAPHENE_TYPE_TRIANGLE); g_type_ensure (GRAPHENE_TYPE_EULER); g_type_ensure (GRAPHENE_TYPE_RAY); /* Ensure GTK names are available for the parser */ g_type_ensure (gtk_at_context_get_type ()); g_type_ensure (gtk_about_dialog_get_type ()); g_type_ensure (gtk_accessible_get_type ()); g_type_ensure (gtk_accessible_announcement_priority_get_type ()); g_type_ensure (gtk_accessible_autocomplete_get_type ()); g_type_ensure (gtk_accessible_invalid_state_get_type ()); g_type_ensure (gtk_accessible_list_get_type ()); g_type_ensure (gtk_accessible_platform_state_get_type ()); g_type_ensure (gtk_accessible_property_get_type ()); g_type_ensure (gtk_accessible_range_get_type ()); g_type_ensure (gtk_accessible_relation_get_type ()); g_type_ensure (gtk_accessible_role_get_type ()); g_type_ensure (gtk_accessible_sort_get_type ()); g_type_ensure (gtk_accessible_state_get_type ()); g_type_ensure (gtk_accessible_text_get_type ()); g_type_ensure (gtk_accessible_text_content_change_get_type ()); g_type_ensure (gtk_accessible_text_granularity_get_type ()); g_type_ensure (gtk_accessible_tristate_get_type ()); g_type_ensure (gtk_action_bar_get_type ()); g_type_ensure (gtk_actionable_get_type ()); g_type_ensure (gtk_activate_action_get_type ()); g_type_ensure (gtk_adjustment_get_type ()); g_type_ensure (gtk_alert_dialog_get_type ()); g_type_ensure (gtk_align_get_type ()); g_type_ensure (gtk_alternative_trigger_get_type ()); g_type_ensure (gtk_any_filter_get_type ()); g_type_ensure (gtk_app_chooser_get_type ()); g_type_ensure (gtk_app_chooser_button_get_type ()); g_type_ensure (gtk_app_chooser_dialog_get_type ()); g_type_ensure (gtk_app_chooser_widget_get_type ()); g_type_ensure (gtk_application_get_type ()); g_type_ensure (gtk_application_inhibit_flags_get_type ()); g_type_ensure (gtk_application_window_get_type ()); g_type_ensure (gtk_arrow_type_get_type ()); g_type_ensure (gtk_aspect_frame_get_type ()); g_type_ensure (gtk_assistant_get_type ()); g_type_ensure (gtk_assistant_page_get_type ()); g_type_ensure (gtk_assistant_page_type_get_type ()); g_type_ensure (gtk_baseline_position_get_type ()); g_type_ensure (gtk_bin_layout_get_type ()); g_type_ensure (gtk_bitset_get_type ()); g_type_ensure (gtk_bitset_iter_get_type ()); g_type_ensure (gtk_bookmark_list_get_type ()); g_type_ensure (gtk_bool_filter_get_type ()); g_type_ensure (gtk_border_get_type ()); g_type_ensure (gtk_border_style_get_type ()); g_type_ensure (gtk_box_get_type ()); g_type_ensure (gtk_box_layout_get_type ()); g_type_ensure (gtk_buildable_get_type ()); g_type_ensure (gtk_builder_get_type ()); g_type_ensure (gtk_builder_cscope_get_type ()); g_type_ensure (gtk_builder_closure_flags_get_type ()); g_type_ensure (gtk_builder_error_get_type ()); g_type_ensure (gtk_builder_list_item_factory_get_type ()); g_type_ensure (gtk_builder_scope_get_type ()); g_type_ensure (gtk_button_get_type ()); g_type_ensure (gtk_buttons_type_get_type ()); g_type_ensure (gtk_cclosure_expression_get_type ()); g_type_ensure (gtk_calendar_get_type ()); g_type_ensure (gtk_callback_action_get_type ()); g_type_ensure (gtk_cell_area_get_type ()); g_type_ensure (gtk_cell_area_box_get_type ()); g_type_ensure (gtk_cell_area_context_get_type ()); g_type_ensure (gtk_cell_editable_get_type ()); g_type_ensure (gtk_cell_layout_get_type ()); g_type_ensure (gtk_cell_renderer_get_type ()); g_type_ensure (gtk_cell_renderer_accel_get_type ()); g_type_ensure (gtk_cell_renderer_accel_mode_get_type ()); g_type_ensure (gtk_cell_renderer_combo_get_type ()); g_type_ensure (gtk_cell_renderer_mode_get_type ()); g_type_ensure (gtk_cell_renderer_pixbuf_get_type ()); g_type_ensure (gtk_cell_renderer_progress_get_type ()); g_type_ensure (gtk_cell_renderer_spin_get_type ()); g_type_ensure (gtk_cell_renderer_spinner_get_type ()); g_type_ensure (gtk_cell_renderer_state_get_type ()); g_type_ensure (gtk_cell_renderer_text_get_type ()); g_type_ensure (gtk_cell_renderer_toggle_get_type ()); g_type_ensure (gtk_cell_view_get_type ()); g_type_ensure (gtk_center_box_get_type ()); g_type_ensure (gtk_center_layout_get_type ()); g_type_ensure (gtk_check_button_get_type ()); g_type_ensure (gtk_closure_expression_get_type ()); g_type_ensure (gtk_collation_get_type ()); g_type_ensure (gtk_color_button_get_type ()); g_type_ensure (gtk_color_chooser_get_type ()); g_type_ensure (gtk_color_chooser_dialog_get_type ()); g_type_ensure (gtk_color_chooser_widget_get_type ()); g_type_ensure (gtk_color_dialog_get_type ()); g_type_ensure (gtk_color_dialog_button_get_type ()); g_type_ensure (gtk_column_view_get_type ()); g_type_ensure (gtk_column_view_cell_get_type ()); g_type_ensure (gtk_column_view_column_get_type ()); g_type_ensure (gtk_column_view_row_get_type ()); g_type_ensure (gtk_column_view_sorter_get_type ()); g_type_ensure (gtk_combo_box_get_type ()); g_type_ensure (gtk_combo_box_text_get_type ()); g_type_ensure (gtk_constant_expression_get_type ()); g_type_ensure (gtk_constraint_get_type ()); g_type_ensure (gtk_constraint_attribute_get_type ()); g_type_ensure (gtk_constraint_guide_get_type ()); g_type_ensure (gtk_constraint_layout_get_type ()); g_type_ensure (gtk_constraint_layout_child_get_type ()); g_type_ensure (gtk_constraint_relation_get_type ()); g_type_ensure (gtk_constraint_strength_get_type ()); g_type_ensure (gtk_constraint_target_get_type ()); g_type_ensure (gtk_constraint_vfl_parser_error_get_type ()); g_type_ensure (gtk_content_fit_get_type ()); g_type_ensure (gtk_corner_type_get_type ()); g_type_ensure (gtk_css_provider_get_type ()); g_type_ensure (gtk_css_section_get_type ()); g_type_ensure (gtk_custom_filter_get_type ()); g_type_ensure (gtk_custom_layout_get_type ()); g_type_ensure (gtk_custom_sorter_get_type ()); g_type_ensure (gtk_debug_flags_get_type ()); g_type_ensure (gtk_delete_type_get_type ()); g_type_ensure (gtk_dialog_get_type ()); g_type_ensure (gtk_dialog_error_get_type ()); g_type_ensure (gtk_dialog_flags_get_type ()); g_type_ensure (gtk_direction_type_get_type ()); g_type_ensure (gtk_directory_list_get_type ()); g_type_ensure (gtk_drag_icon_get_type ()); g_type_ensure (gtk_drag_source_get_type ()); g_type_ensure (gtk_drawing_area_get_type ()); g_type_ensure (gtk_drop_controller_motion_get_type ()); g_type_ensure (gtk_drop_down_get_type ()); g_type_ensure (gtk_drop_target_get_type ()); g_type_ensure (gtk_drop_target_async_get_type ()); g_type_ensure (gtk_editable_get_type ()); g_type_ensure (gtk_editable_label_get_type ()); g_type_ensure (gtk_editable_properties_get_type ()); g_type_ensure (gtk_emoji_chooser_get_type ()); g_type_ensure (gtk_entry_get_type ()); g_type_ensure (gtk_entry_buffer_get_type ()); g_type_ensure (gtk_entry_completion_get_type ()); g_type_ensure (gtk_entry_icon_position_get_type ()); g_type_ensure (gtk_event_controller_get_type ()); g_type_ensure (gtk_event_controller_focus_get_type ()); g_type_ensure (gtk_event_controller_key_get_type ()); g_type_ensure (gtk_event_controller_legacy_get_type ()); g_type_ensure (gtk_event_controller_motion_get_type ()); g_type_ensure (gtk_event_controller_scroll_get_type ()); g_type_ensure (gtk_event_controller_scroll_flags_get_type ()); g_type_ensure (gtk_event_sequence_state_get_type ()); g_type_ensure (gtk_every_filter_get_type ()); g_type_ensure (gtk_expander_get_type ()); g_type_ensure (gtk_expression_get_type ()); g_type_ensure (gtk_expression_watch_get_type ()); g_type_ensure (gtk_file_chooser_get_type ()); g_type_ensure (gtk_file_chooser_action_get_type ()); g_type_ensure (gtk_file_chooser_dialog_get_type ()); g_type_ensure (gtk_file_chooser_error_get_type ()); g_type_ensure (gtk_file_chooser_native_get_type ()); g_type_ensure (gtk_file_chooser_widget_get_type ()); g_type_ensure (gtk_file_dialog_get_type ()); g_type_ensure (gtk_file_filter_get_type ()); g_type_ensure (gtk_file_launcher_get_type ()); g_type_ensure (gtk_filter_get_type ()); g_type_ensure (gtk_filter_change_get_type ()); g_type_ensure (gtk_filter_list_model_get_type ()); g_type_ensure (gtk_filter_match_get_type ()); g_type_ensure (gtk_fixed_get_type ()); g_type_ensure (gtk_fixed_layout_get_type ()); g_type_ensure (gtk_fixed_layout_child_get_type ()); g_type_ensure (gtk_flatten_list_model_get_type ()); g_type_ensure (gtk_flow_box_get_type ()); g_type_ensure (gtk_flow_box_child_get_type ()); g_type_ensure (gtk_font_button_get_type ()); g_type_ensure (gtk_font_chooser_get_type ()); g_type_ensure (gtk_font_chooser_dialog_get_type ()); g_type_ensure (gtk_font_chooser_level_get_type ()); g_type_ensure (gtk_font_chooser_widget_get_type ()); g_type_ensure (gtk_font_dialog_get_type ()); g_type_ensure (gtk_font_dialog_button_get_type ()); g_type_ensure (gtk_font_level_get_type ()); g_type_ensure (gtk_font_rendering_get_type ()); g_type_ensure (gtk_frame_get_type ()); g_type_ensure (gtk_gl_area_get_type ()); g_type_ensure (gtk_gesture_get_type ()); g_type_ensure (gtk_gesture_click_get_type ()); g_type_ensure (gtk_gesture_drag_get_type ()); g_type_ensure (gtk_gesture_long_press_get_type ()); g_type_ensure (gtk_gesture_pan_get_type ()); g_type_ensure (gtk_gesture_rotate_get_type ()); g_type_ensure (gtk_gesture_single_get_type ()); g_type_ensure (gtk_gesture_stylus_get_type ()); g_type_ensure (gtk_gesture_swipe_get_type ()); g_type_ensure (gtk_gesture_zoom_get_type ()); g_type_ensure (gtk_graphics_offload_get_type ()); g_type_ensure (gtk_graphics_offload_enabled_get_type ()); g_type_ensure (gtk_grid_get_type ()); g_type_ensure (gtk_grid_layout_get_type ()); g_type_ensure (gtk_grid_layout_child_get_type ()); g_type_ensure (gtk_grid_view_get_type ()); g_type_ensure (gtk_header_bar_get_type ()); g_type_ensure (gtk_im_context_get_type ()); g_type_ensure (gtk_im_context_simple_get_type ()); g_type_ensure (gtk_im_multicontext_get_type ()); g_type_ensure (gtk_icon_lookup_flags_get_type ()); g_type_ensure (gtk_icon_paintable_get_type ()); g_type_ensure (gtk_icon_size_get_type ()); g_type_ensure (gtk_icon_theme_get_type ()); g_type_ensure (gtk_icon_theme_error_get_type ()); g_type_ensure (gtk_icon_view_get_type ()); g_type_ensure (gtk_icon_view_drop_position_get_type ()); g_type_ensure (gtk_image_get_type ()); g_type_ensure (gtk_image_type_get_type ()); g_type_ensure (gtk_info_bar_get_type ()); g_type_ensure (gtk_input_hints_get_type ()); g_type_ensure (gtk_input_purpose_get_type ()); g_type_ensure (gtk_inscription_get_type ()); g_type_ensure (gtk_inscription_overflow_get_type ()); g_type_ensure (gtk_interface_color_scheme_get_type ()); g_type_ensure (gtk_interface_contrast_get_type ()); g_type_ensure (gtk_justification_get_type ()); g_type_ensure (gtk_keyval_trigger_get_type ()); g_type_ensure (gtk_label_get_type ()); g_type_ensure (gtk_layout_child_get_type ()); g_type_ensure (gtk_layout_manager_get_type ()); g_type_ensure (gtk_level_bar_get_type ()); g_type_ensure (gtk_level_bar_mode_get_type ()); g_type_ensure (gtk_license_get_type ()); g_type_ensure (gtk_link_button_get_type ()); g_type_ensure (gtk_list_base_get_type ()); g_type_ensure (gtk_list_box_get_type ()); g_type_ensure (gtk_list_box_row_get_type ()); g_type_ensure (gtk_list_header_get_type ()); g_type_ensure (gtk_list_item_get_type ()); g_type_ensure (gtk_list_item_factory_get_type ()); g_type_ensure (gtk_list_scroll_flags_get_type ()); g_type_ensure (gtk_list_store_get_type ()); g_type_ensure (gtk_list_tab_behavior_get_type ()); g_type_ensure (gtk_list_view_get_type ()); g_type_ensure (gtk_lock_button_get_type ()); g_type_ensure (gtk_map_list_model_get_type ()); g_type_ensure (gtk_media_controls_get_type ()); g_type_ensure (gtk_media_file_get_type ()); g_type_ensure (gtk_media_stream_get_type ()); g_type_ensure (gtk_menu_button_get_type ()); g_type_ensure (gtk_message_dialog_get_type ()); g_type_ensure (gtk_message_type_get_type ()); g_type_ensure (gtk_mnemonic_action_get_type ()); g_type_ensure (gtk_mnemonic_trigger_get_type ()); g_type_ensure (gtk_mount_operation_get_type ()); g_type_ensure (gtk_movement_step_get_type ()); g_type_ensure (gtk_multi_filter_get_type ()); g_type_ensure (gtk_multi_selection_get_type ()); g_type_ensure (gtk_multi_sorter_get_type ()); g_type_ensure (gtk_named_action_get_type ()); g_type_ensure (gtk_native_get_type ()); g_type_ensure (gtk_native_dialog_get_type ()); g_type_ensure (gtk_natural_wrap_mode_get_type ()); g_type_ensure (gtk_never_trigger_get_type ()); g_type_ensure (gtk_no_selection_get_type ()); g_type_ensure (gtk_notebook_get_type ()); g_type_ensure (gtk_notebook_page_get_type ()); g_type_ensure (gtk_notebook_tab_get_type ()); g_type_ensure (gtk_nothing_action_get_type ()); g_type_ensure (gtk_number_up_layout_get_type ()); g_type_ensure (gtk_numeric_sorter_get_type ()); g_type_ensure (gtk_object_expression_get_type ()); g_type_ensure (gtk_ordering_get_type ()); g_type_ensure (gtk_orientable_get_type ()); g_type_ensure (gtk_orientation_get_type ()); g_type_ensure (gtk_overflow_get_type ()); g_type_ensure (gtk_overlay_get_type ()); g_type_ensure (gtk_overlay_layout_get_type ()); g_type_ensure (gtk_overlay_layout_child_get_type ()); g_type_ensure (gtk_pack_type_get_type ()); g_type_ensure (gtk_pad_action_type_get_type ()); g_type_ensure (gtk_pad_controller_get_type ()); g_type_ensure (gtk_page_orientation_get_type ()); g_type_ensure (gtk_page_set_get_type ()); g_type_ensure (gtk_page_setup_get_type ()); g_type_ensure (gtk_pan_direction_get_type ()); g_type_ensure (gtk_paned_get_type ()); g_type_ensure (gtk_paper_size_get_type ()); g_type_ensure (gtk_param_expression_get_type ()); g_type_ensure (gtk_password_entry_get_type ()); g_type_ensure (gtk_password_entry_buffer_get_type ()); g_type_ensure (gtk_pick_flags_get_type ()); g_type_ensure (gtk_picture_get_type ()); g_type_ensure (gtk_policy_type_get_type ()); g_type_ensure (gtk_popover_get_type ()); g_type_ensure (gtk_popover_menu_get_type ()); g_type_ensure (gtk_popover_menu_bar_get_type ()); g_type_ensure (gtk_popover_menu_flags_get_type ()); g_type_ensure (gtk_position_type_get_type ()); g_type_ensure (gtk_print_context_get_type ()); g_type_ensure (gtk_print_dialog_get_type ()); g_type_ensure (gtk_print_duplex_get_type ()); g_type_ensure (gtk_print_error_get_type ()); g_type_ensure (gtk_print_operation_get_type ()); g_type_ensure (gtk_print_operation_action_get_type ()); g_type_ensure (gtk_print_operation_preview_get_type ()); g_type_ensure (gtk_print_operation_result_get_type ()); g_type_ensure (gtk_print_pages_get_type ()); g_type_ensure (gtk_print_quality_get_type ()); g_type_ensure (gtk_print_settings_get_type ()); g_type_ensure (gtk_print_setup_get_type ()); g_type_ensure (gtk_print_status_get_type ()); g_type_ensure (gtk_progress_bar_get_type ()); g_type_ensure (gtk_propagation_limit_get_type ()); g_type_ensure (gtk_propagation_phase_get_type ()); g_type_ensure (gtk_property_expression_get_type ()); g_type_ensure (gtk_range_get_type ()); g_type_ensure (gtk_recent_info_get_type ()); g_type_ensure (gtk_recent_manager_get_type ()); g_type_ensure (gtk_recent_manager_error_get_type ()); g_type_ensure (gtk_requisition_get_type ()); g_type_ensure (gtk_response_type_get_type ()); g_type_ensure (gtk_revealer_get_type ()); g_type_ensure (gtk_revealer_transition_type_get_type ()); g_type_ensure (gtk_root_get_type ()); g_type_ensure (gtk_scale_get_type ()); g_type_ensure (gtk_scale_button_get_type ()); g_type_ensure (gtk_scroll_info_get_type ()); g_type_ensure (gtk_scroll_step_get_type ()); g_type_ensure (gtk_scroll_type_get_type ()); g_type_ensure (gtk_scrollable_get_type ()); g_type_ensure (gtk_scrollable_policy_get_type ()); g_type_ensure (gtk_scrollbar_get_type ()); g_type_ensure (gtk_scrolled_window_get_type ()); g_type_ensure (gtk_search_bar_get_type ()); g_type_ensure (gtk_search_entry_get_type ()); g_type_ensure (gtk_section_model_get_type ()); g_type_ensure (gtk_selection_filter_model_get_type ()); g_type_ensure (gtk_selection_mode_get_type ()); g_type_ensure (gtk_selection_model_get_type ()); g_type_ensure (gtk_sensitivity_type_get_type ()); g_type_ensure (gtk_separator_get_type ()); g_type_ensure (gtk_settings_get_type ()); g_type_ensure (gtk_shortcut_get_type ()); g_type_ensure (gtk_shortcut_action_get_type ()); g_type_ensure (gtk_shortcut_action_flags_get_type ()); g_type_ensure (gtk_shortcut_controller_get_type ()); g_type_ensure (gtk_shortcut_label_get_type ()); g_type_ensure (gtk_shortcut_manager_get_type ()); g_type_ensure (gtk_shortcut_scope_get_type ()); g_type_ensure (gtk_shortcut_trigger_get_type ()); g_type_ensure (gtk_shortcut_type_get_type ()); g_type_ensure (gtk_shortcuts_group_get_type ()); g_type_ensure (gtk_shortcuts_section_get_type ()); g_type_ensure (gtk_shortcuts_shortcut_get_type ()); g_type_ensure (gtk_shortcuts_window_get_type ()); g_type_ensure (gtk_signal_action_get_type ()); g_type_ensure (gtk_signal_list_item_factory_get_type ()); g_type_ensure (gtk_single_selection_get_type ()); g_type_ensure (gtk_size_group_get_type ()); g_type_ensure (gtk_size_group_mode_get_type ()); g_type_ensure (gtk_size_request_mode_get_type ()); g_type_ensure (gtk_slice_list_model_get_type ()); g_type_ensure (gtk_snapshot_get_type ()); g_type_ensure (gtk_sort_list_model_get_type ()); g_type_ensure (gtk_sort_type_get_type ()); g_type_ensure (gtk_sorter_get_type ()); g_type_ensure (gtk_sorter_change_get_type ()); g_type_ensure (gtk_sorter_order_get_type ()); g_type_ensure (gtk_spin_button_get_type ()); g_type_ensure (gtk_spin_button_update_policy_get_type ()); g_type_ensure (gtk_spin_type_get_type ()); g_type_ensure (gtk_spinner_get_type ()); g_type_ensure (gtk_stack_get_type ()); g_type_ensure (gtk_stack_page_get_type ()); g_type_ensure (gtk_stack_sidebar_get_type ()); g_type_ensure (gtk_stack_switcher_get_type ()); g_type_ensure (gtk_stack_transition_type_get_type ()); g_type_ensure (gtk_state_flags_get_type ()); g_type_ensure (gtk_statusbar_get_type ()); g_type_ensure (gtk_string_filter_get_type ()); g_type_ensure (gtk_string_filter_match_mode_get_type ()); g_type_ensure (gtk_string_list_get_type ()); g_type_ensure (gtk_string_object_get_type ()); g_type_ensure (gtk_string_sorter_get_type ()); g_type_ensure (gtk_style_context_get_type ()); g_type_ensure (gtk_style_context_print_flags_get_type ()); g_type_ensure (gtk_style_provider_get_type ()); g_type_ensure (gtk_switch_get_type ()); g_type_ensure (gtk_symbolic_color_get_type ()); g_type_ensure (gtk_symbolic_paintable_get_type ()); g_type_ensure (gtk_system_setting_get_type ()); g_type_ensure (gtk_text_get_type ()); g_type_ensure (gtk_text_buffer_get_type ()); g_type_ensure (gtk_text_buffer_notify_flags_get_type ()); g_type_ensure (gtk_text_child_anchor_get_type ()); g_type_ensure (gtk_text_direction_get_type ()); g_type_ensure (gtk_text_extend_selection_get_type ()); g_type_ensure (gtk_text_iter_get_type ()); g_type_ensure (gtk_text_mark_get_type ()); g_type_ensure (gtk_text_search_flags_get_type ()); g_type_ensure (gtk_text_tag_get_type ()); g_type_ensure (gtk_text_tag_table_get_type ()); g_type_ensure (gtk_text_view_get_type ()); g_type_ensure (gtk_text_view_layer_get_type ()); g_type_ensure (gtk_text_window_type_get_type ()); g_type_ensure (gtk_toggle_button_get_type ()); g_type_ensure (gtk_tooltip_get_type ()); g_type_ensure (gtk_tree_expander_get_type ()); g_type_ensure (gtk_tree_iter_get_type ()); g_type_ensure (gtk_tree_list_model_get_type ()); g_type_ensure (gtk_tree_list_row_get_type ()); g_type_ensure (gtk_tree_list_row_sorter_get_type ()); g_type_ensure (gtk_tree_model_get_type ()); g_type_ensure (gtk_tree_model_filter_get_type ()); g_type_ensure (gtk_tree_model_flags_get_type ()); g_type_ensure (gtk_tree_model_sort_get_type ()); g_type_ensure (gtk_tree_path_get_type ()); g_type_ensure (gtk_tree_row_reference_get_type ()); g_type_ensure (gtk_tree_selection_get_type ()); g_type_ensure (gtk_tree_sortable_get_type ()); g_type_ensure (gtk_tree_store_get_type ()); g_type_ensure (gtk_tree_view_get_type ()); g_type_ensure (gtk_tree_view_column_get_type ()); g_type_ensure (gtk_tree_view_column_sizing_get_type ()); g_type_ensure (gtk_tree_view_drop_position_get_type ()); g_type_ensure (gtk_tree_view_grid_lines_get_type ()); g_type_ensure (gtk_unit_get_type ()); g_type_ensure (gtk_uri_launcher_get_type ()); g_type_ensure (gtk_video_get_type ()); g_type_ensure (gtk_viewport_get_type ()); g_type_ensure (gtk_volume_button_get_type ()); g_type_ensure (gtk_widget_get_type ()); g_type_ensure (gtk_widget_paintable_get_type ()); g_type_ensure (gtk_window_get_type ()); g_type_ensure (gtk_window_controls_get_type ()); g_type_ensure (gtk_window_gravity_get_type ()); g_type_ensure (gtk_window_group_get_type ()); g_type_ensure (gtk_window_handle_get_type ()); g_type_ensure (gtk_wrap_mode_get_type ()); } static void bge_wdgt_spec_init (BgeWdgtSpec *self) { self->values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, value_data_unref); self->anon_values = g_ptr_array_new_with_free_func (value_data_unref); self->states = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, state_data_unref); self->children = g_ptr_array_new_with_free_func (value_data_unref); self->nonchildren = g_ptr_array_new_with_free_func (value_data_unref); self->init_state = state_data_new (); self->init_state->name = g_strdup ("init"); self->init_state->setters = g_hash_table_new_full ( g_direct_hash, g_direct_equal, value_data_unref, value_data_unref); self->init_state->transitions = g_hash_table_new_full ( g_direct_hash, g_direct_equal, value_data_unref, transition_data_unref); ensure_state_snapshot (self->init_state); g_hash_table_replace (self->states, g_strdup ("init"), state_data_ref (self->init_state)); } BgeWdgtSpec * bge_wdgt_spec_new (void) { return g_object_new (BGE_TYPE_WDGT_SPEC, NULL); } BgeWdgtSpec * bge_wdgt_spec_new_for_string (const char *string, GError **error) { g_return_val_if_fail (string != NULL, NULL); return bge_wdgt_parse_string (string, error); } BgeWdgtSpec * bge_wdgt_spec_new_for_resource (const char *resource, GError **error) { g_autoptr (GBytes) bytes = NULL; gsize size = 0; gconstpointer data = NULL; g_return_val_if_fail (resource != NULL, NULL); bytes = g_resources_lookup_data (resource, G_RESOURCE_LOOKUP_FLAGS_NONE, error); if (bytes == NULL) return NULL; data = g_bytes_get_data (bytes, &size); return bge_wdgt_parse_string ((const char *) data, error); } const char * bge_wdgt_spec_get_name (BgeWdgtSpec *self) { g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), NULL); return self->name; } void bge_wdgt_spec_set_name (BgeWdgtSpec *self, const char *name) { g_return_if_fail (BGE_IS_WDGT_SPEC (self)); if (name == self->name || (name != NULL && self->name != NULL && g_strcmp0 (name, self->name) == 0)) return; g_clear_pointer (&self->name, g_free); if (name != NULL) self->name = g_strdup (name); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NAME]); } void bge_wdgt_spec_set_name_take (BgeWdgtSpec *self, char *name) { g_return_if_fail (BGE_IS_WDGT_SPEC (self)); if (name != NULL && self->name != NULL && g_strcmp0 (name, self->name) == 0) { g_free (name); return; } g_clear_pointer (&self->name, g_free); if (name != NULL) self->name = name; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NAME]); } gboolean bge_wdgt_spec_add_constant_source_value (BgeWdgtSpec *self, const char *name, const GValue *constant, GError **error) { g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (constant != NULL, FALSE); if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } value = value_data_new (); value->name = g_strdup (name); value->type = constant->g_type; value->kind = VALUE_CONSTANT; g_value_copy (constant, g_value_init (&value->constant, constant->g_type)); g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); return TRUE; } gboolean bge_wdgt_spec_add_component_source_value (BgeWdgtSpec *self, const char *name, GType type, const char *const *components, guint n_components, GError **error) { GType expected_types[ARGBUF_SIZE] = { 0 }; g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (components != NULL, FALSE); if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } if (type == GRAPHENE_TYPE_POINT) { if (n_components != 2) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "composed point value needs 2 arguments"); return FALSE; } expected_types[0] = G_TYPE_DOUBLE; expected_types[1] = G_TYPE_DOUBLE; } else if (type == GRAPHENE_TYPE_POINT3D) { if (n_components != 3) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "composed 3d point value needs 3 arguments"); return FALSE; } expected_types[0] = G_TYPE_DOUBLE; expected_types[1] = G_TYPE_DOUBLE; expected_types[2] = G_TYPE_DOUBLE; } else if (type == GRAPHENE_TYPE_SIZE) { if (n_components != 2) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "composed 2d size value needs 2 arguments"); return FALSE; } expected_types[0] = G_TYPE_DOUBLE; expected_types[1] = G_TYPE_DOUBLE; } else if (type == GRAPHENE_TYPE_RECT) { if (n_components != 4) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "composed rectangle value needs 4 arguments"); return FALSE; } expected_types[0] = G_TYPE_DOUBLE; expected_types[1] = G_TYPE_DOUBLE; expected_types[2] = G_TYPE_DOUBLE; expected_types[3] = G_TYPE_DOUBLE; } else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "type '%s' is not elligible for a component value", g_type_name (type)); return FALSE; } value = value_data_new (); value->name = g_strdup (name); value->type = type; value->kind = VALUE_COMPONENT; value->component = g_ptr_array_new_with_free_func (value_data_unref); for (guint i = 0; i < n_components; i++) { ValueData *value_data = NULL; value_data = g_hash_table_lookup (self->values, components[i]); if (value_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", components[i]); return FALSE; } if (!g_type_is_a (value_data->type, expected_types[i])) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "component %u for type %s " "must be of type %s, got %s", i, g_type_name (type), g_type_name (expected_types[i]), g_type_name (value_data->type)); return FALSE; } g_ptr_array_add (value->component, value_data_ref (value_data)); } g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); return TRUE; } gboolean bge_wdgt_spec_add_transform_source_value (BgeWdgtSpec *self, const char *name, const char *next, const char *instruction, const char *const *args, guint n_args, GError **error) { gboolean result = FALSE; ValueData *next_data = NULL; g_autoptr (ValueData) value = NULL; TransformInstr match = { 0 }; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (next != NULL, FALSE); g_return_val_if_fail (instruction != NULL, FALSE); g_return_val_if_fail (n_args == 0 || args != NULL, FALSE); if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } next_data = g_hash_table_lookup (self->values, next); if (next_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", next); return FALSE; } if (next_data->type != GSK_TYPE_TRANSFORM) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' must be of type %s to " "build a transform, got %s", next, g_type_name (GSK_TYPE_TRANSFORM), g_type_name (next_data->type)); return FALSE; } result = lookup_transform_instr (instruction, &match); if (!result) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "\"%s\" is not a valid transform builder instruction", instruction); return FALSE; } if (n_args != match.n_args) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "transform builder function %s requires %u " "arguments, got %u", match.name, match.n_args, n_args); return FALSE; } value = value_data_new (); value->name = g_strdup (name); value->type = GSK_TYPE_TRANSFORM; value->kind = VALUE_TRANSFORM; value->transform.func = match.call; value->transform.next = value_data_ref (next_data); value->transform.args = g_ptr_array_new_with_free_func (value_data_unref); for (guint i = 0; i < n_args; i++) { ValueData *value_data = NULL; value_data = g_hash_table_lookup (self->values, args[i]); if (value_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", args[i]); return FALSE; } if (!g_type_is_a (value_data->type, match.args[i])) { if (check_can_coerce_type (match.args[i], value_data->type)) g_ptr_array_add (value->transform.args, wrap_coerce_value (self, value_data, match.args[i])); else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "argument %u for snapshot instruction %s " "must be of type %s, got %s", i, match.name, g_type_name (match.args[i]), g_type_name (value_data->type)); return FALSE; } } else g_ptr_array_add (value->transform.args, value_data_ref (value_data)); } g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); return TRUE; } gboolean bge_wdgt_spec_add_instance_source_value (BgeWdgtSpec *self, const char *name, GType type, GError **error) { g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } if (!g_type_is_a (type, G_TYPE_OBJECT)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "type '%s' is not an object type", g_type_name (type)); return FALSE; } if (!G_TYPE_IS_INSTANTIATABLE (type) || G_TYPE_IS_ABSTRACT (type)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "type '%s' is not instantiable", g_type_name (type)); return FALSE; } value = value_data_new (); value->kind = VALUE_OBJECT; value->type = type; value->name = g_strdup (name); g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); g_ptr_array_add (self->nonchildren, value_data_ref (value)); return TRUE; } gboolean bge_wdgt_spec_add_child_source_value (BgeWdgtSpec *self, const char *name, GType type, const char *parent, const char *builder_type, const char *const *css_classes, guint n_css_classes, GError **error) { g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } if (!g_type_is_a (type, GTK_TYPE_WIDGET)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "type '%s' does not derive from GtkWidget", g_type_name (type)); return FALSE; } if (!G_TYPE_IS_INSTANTIATABLE (type) || G_TYPE_IS_ABSTRACT (type)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "type '%s' is not instantiable", g_type_name (type)); return FALSE; } value = value_data_new (); value->kind = VALUE_CHILD; value->type = type; value->name = g_strdup (name); value->child.builder_type = builder_type != NULL ? g_strdup (builder_type) : NULL; if (n_css_classes > 0 && css_classes != NULL) { value->child.css_classes = g_ptr_array_new_with_free_func (g_free); g_ptr_array_set_size (value->child.css_classes, n_css_classes); for (guint i = 0; i < n_css_classes; i++) { g_ptr_array_index (value->child.css_classes, i) = g_strdup (css_classes[i]); } } if (parent != NULL) { ValueData *parent_data = NULL; parent_data = g_hash_table_lookup (self->values, parent); if (parent_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", parent); return FALSE; } if (!g_type_is_a (parent_data->type, GTK_TYPE_BUILDABLE)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "parent widget '%s' is not of type %s", g_type_name (GTK_TYPE_BUILDABLE), parent); return FALSE; } value->child.parent_widget = value_data_ref (parent_data); } g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); g_ptr_array_add (self->children, value_data_ref (value)); return TRUE; } gboolean bge_wdgt_spec_add_cclosure_source_value (BgeWdgtSpec *self, const char *name, GType type, GClosureMarshal marshal, GCallback func, const char *const *args, const GType *arg_types, guint n_args, gpointer user_data, GDestroyNotify destroy_user_data, GError **error) { g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (func != NULL, FALSE); g_return_val_if_fail (args != NULL, FALSE); g_return_val_if_fail (n_args > 0, FALSE); if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); if (user_data != NULL && destroy_user_data != NULL) destroy_user_data (user_data); return FALSE; } if (!G_TYPE_IS_VALUE (type)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "invalid type '%s'", g_type_name (type)); if (user_data != NULL && destroy_user_data != NULL) destroy_user_data (user_data); return FALSE; } value = value_data_new (); value->kind = VALUE_CLOSURE; value->name = g_strdup (name); value->type = type; value->closure.marshal = marshal; value->closure.func = func; value->closure.args = g_ptr_array_new_with_free_func (value_data_unref); value->closure.user_data = user_data; value->closure.destroy_user_data = destroy_user_data; for (guint i = 0; i < n_args; i++) { ValueData *value_data = NULL; value_data = g_hash_table_lookup (self->values, args[i]); if (value_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", args[i]); return FALSE; } if (arg_types != NULL && !g_type_is_a (value_data->type, arg_types[i])) { if (check_can_coerce_type (arg_types[i], value_data->type)) g_ptr_array_add (value->closure.args, wrap_coerce_value (self, value_data, arg_types[i])); else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "component %u for type %s " "must be of type %s, got %s", i, g_type_name (type), g_type_name (arg_types[i]), g_type_name (value_data->type)); return FALSE; } } else g_ptr_array_add (value->closure.args, value_data_ref (value_data)); } g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); return TRUE; } gboolean bge_wdgt_spec_add_measure_for_size_source_value (BgeWdgtSpec *self, const char *name, GError **error) { g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } value = value_data_new (); value->name = g_strdup (name); value->kind = VALUE_MEASURE_FOR_SIZE; value->type = G_TYPE_INT; g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); return TRUE; } gboolean bge_wdgt_spec_add_widget_width_source_value (BgeWdgtSpec *self, const char *name, GError **error) { g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } value = value_data_new (); value->name = g_strdup (name); value->kind = VALUE_WIDGET_WIDTH; value->type = G_TYPE_DOUBLE; g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); return TRUE; } gboolean bge_wdgt_spec_add_widget_height_source_value (BgeWdgtSpec *self, const char *name, GError **error) { g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } value = value_data_new (); value->name = g_strdup (name); value->kind = VALUE_WIDGET_HEIGHT; value->type = G_TYPE_DOUBLE; g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); return TRUE; } gboolean bge_wdgt_spec_add_track_transition_source_value (BgeWdgtSpec *self, const char *name, const char *src, const char *damping_ratio, const char *mass, const char *stiffness, GError **error) { ValueData *src_value = NULL; g_autoptr (ValueData) coerced_src_value = NULL; ValueData *damping_ratio_value = NULL; g_autoptr (ValueData) coerced_damping_ratio_value = NULL; ValueData *mass_value = NULL; g_autoptr (ValueData) coerced_mass_value = NULL; ValueData *stiffness_value = NULL; g_autoptr (ValueData) coerced_stiffness_value = NULL; g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (src != NULL, FALSE); g_return_val_if_fail (damping_ratio != NULL, FALSE); g_return_val_if_fail (mass != NULL, FALSE); g_return_val_if_fail (stiffness != NULL, FALSE); if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } /* TODO clean up type checking process */ src_value = g_hash_table_lookup (self->values, src); if (src_value == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", src); return FALSE; } if (src_value->type != G_TYPE_DOUBLE) { if (check_can_coerce_type (G_TYPE_DOUBLE, src_value->type)) coerced_src_value = wrap_coerce_value (self, src_value, src_value->type); else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "source type %s cannot be transitioned", g_type_name (src_value->type)); return FALSE; } } damping_ratio_value = g_hash_table_lookup (self->values, damping_ratio); if (damping_ratio_value == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", damping_ratio); return FALSE; } if (damping_ratio_value->type != G_TYPE_DOUBLE) { if (check_can_coerce_type (G_TYPE_DOUBLE, damping_ratio_value->type)) coerced_damping_ratio_value = wrap_coerce_value (self, damping_ratio_value, damping_ratio_value->type); else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "damping ratio must be a double, got type %s", g_type_name (damping_ratio_value->type)); return FALSE; } } mass_value = g_hash_table_lookup (self->values, mass); if (mass_value == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", mass); return FALSE; } if (mass_value->type != G_TYPE_DOUBLE) { if (check_can_coerce_type (G_TYPE_DOUBLE, mass_value->type)) coerced_mass_value = wrap_coerce_value (self, mass_value, mass_value->type); else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "mass must be a double, got type %s", g_type_name (mass_value->type)); return FALSE; } } stiffness_value = g_hash_table_lookup (self->values, stiffness); if (stiffness_value == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", stiffness); return FALSE; } if (stiffness_value->type != G_TYPE_DOUBLE) { if (check_can_coerce_type (G_TYPE_DOUBLE, stiffness_value->type)) coerced_stiffness_value = wrap_coerce_value (self, stiffness_value, stiffness_value->type); else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "stiffness must be a double, got type %s", g_type_name (stiffness_value->type)); return FALSE; } } value = value_data_new (); value->name = g_strdup (name); value->kind = VALUE_TRACK_TRANSITION; value->type = G_TYPE_DOUBLE; value->track_transition.src = coerced_src_value != NULL ? value_data_ref (coerced_src_value) : value_data_ref (src_value); value->track_transition.spring.damping_ratio = coerced_damping_ratio_value != NULL ? value_data_ref (coerced_damping_ratio_value) : value_data_ref (damping_ratio_value); value->track_transition.spring.mass = coerced_mass_value != NULL ? value_data_ref (coerced_mass_value) : value_data_ref (mass_value); value->track_transition.spring.stiffness = coerced_stiffness_value != NULL ? value_data_ref (coerced_stiffness_value) : value_data_ref (stiffness_value); g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); return TRUE; } gboolean bge_wdgt_spec_add_special_source_value (BgeWdgtSpec *self, const char *name, BgeWdgtSpecialValue kind, GError **error) { g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } switch (kind) { case BGE_WDGT_SPECIAL_VALUE_MOTION_X: if (self->special_values.motion_x != NULL) value = value_data_ref (self->special_values.motion_x); break; case BGE_WDGT_SPECIAL_VALUE_MOTION_Y: if (self->special_values.motion_y != NULL) value = value_data_ref (self->special_values.motion_y); break; default: g_critical ("Invalid special value specified"); return FALSE; } if (value == NULL) { value = value_data_new (); value->name = g_strdup (name); value->kind = VALUE_SPECIAL; value->special = kind; switch (kind) { case BGE_WDGT_SPECIAL_VALUE_MOTION_X: self->special_values.motion_x = value_data_ref (value); break; case BGE_WDGT_SPECIAL_VALUE_MOTION_Y: self->special_values.motion_y = value_data_ref (value); break; default: g_assert_not_reached (); } } g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); return TRUE; } gboolean bge_wdgt_spec_add_variable_value (BgeWdgtSpec *self, GType type, const char *name, GError **error) { g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); if (!G_TYPE_IS_VALUE (type)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "type '%s' cannot be stored in value '%s'", g_type_name (type), name); return FALSE; } if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } value = value_data_new (); value->name = g_strdup (name); value->type = type; value->kind = VALUE_VARIABLE; g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); return TRUE; } gboolean bge_wdgt_spec_add_reference_object_value (BgeWdgtSpec *self, GType type, const char *name, GError **error) { g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); if (self->reference != NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "an object reference value has already been defined"); return FALSE; } if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } if (!g_type_is_a (type, G_TYPE_OBJECT)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "type '%s' cannot be stored in reference object value '%s'", g_type_name (type), name); return FALSE; } value = value_data_new (); value->name = g_strdup (name); value->type = type; value->kind = VALUE_REFERENCE_OBJECT; g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); self->reference = value_data_ref (value); return TRUE; } gboolean bge_wdgt_spec_add_property_value (BgeWdgtSpec *self, const char *name, const char *object, const char *property, GType *type_out, GError **error) { ValueData *object_value = NULL; ValueData *existing_value = NULL; g_autoptr (GTypeClass) type_class = NULL; GParamSpec *pspec = NULL; g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (object != NULL, FALSE); g_return_val_if_fail (property != NULL, FALSE); object_value = g_hash_table_lookup (self->values, object); if (object_value == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", object); return FALSE; } if (!g_type_is_a (object_value->type, G_TYPE_OBJECT)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is not an object", object); return FALSE; } existing_value = g_hash_table_lookup (self->values, name); if (existing_value != NULL) { if (existing_value->kind == VALUE_PROPERTY && existing_value->property.object == object_value && g_strcmp0 (existing_value->property.prop_name, property) == 0) return TRUE; else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } } type_class = g_type_class_ref (object_value->type); pspec = g_object_class_find_property (G_OBJECT_CLASS (type_class), property); if (pspec == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "property '%s' doesn't exist on type %s", property, g_type_name (object_value->type)); return FALSE; } value = value_data_new (); value->name = g_strdup (name); value->type = pspec->value_type; value->kind = VALUE_PROPERTY; value->property.object = value_data_ref (object_value); value->property.prop_name = g_strdup (property); value->property.pspec_flags = pspec->flags; g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); if (type_out != NULL) *type_out = pspec->value_type; return TRUE; } gboolean bge_wdgt_spec_add_allocation_width_value (BgeWdgtSpec *self, const char *name, const char *child, GError **error) { ValueData *child_value = NULL; g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (child != NULL, FALSE); if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } child_value = g_hash_table_lookup (self->values, child); if (child_value == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", child); return FALSE; } if (!g_type_is_a (child_value->type, GTK_TYPE_WIDGET)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is not a widget", child); return FALSE; } value = value_data_new (); value->name = g_strdup (name); value->type = G_TYPE_INT; value->kind = VALUE_ALLOCATION_WIDTH; value->allocation.widget = value_data_ref (child_value); g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); return TRUE; } gboolean bge_wdgt_spec_add_allocation_height_value (BgeWdgtSpec *self, const char *name, const char *child, GError **error) { ValueData *child_value = NULL; g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (child != NULL, FALSE); if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } child_value = g_hash_table_lookup (self->values, child); if (child_value == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", child); return FALSE; } if (!g_type_is_a (child_value->type, GTK_TYPE_WIDGET)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is not a widget", child); return FALSE; } value = value_data_new (); value->name = g_strdup (name); value->type = G_TYPE_INT; value->kind = VALUE_ALLOCATION_HEIGHT; value->allocation.widget = value_data_ref (child_value); g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); return TRUE; } gboolean bge_wdgt_spec_add_allocation_transform_value (BgeWdgtSpec *self, const char *name, const char *child, GError **error) { ValueData *child_value = NULL; g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (child != NULL, FALSE); if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } child_value = g_hash_table_lookup (self->values, child); if (child_value == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", child); return FALSE; } if (!g_type_is_a (child_value->type, GTK_TYPE_WIDGET)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is not a widget", child); return FALSE; } value = value_data_new (); value->name = g_strdup (name); value->type = GSK_TYPE_TRANSFORM; value->kind = VALUE_ALLOCATION_TRANSFORM; value->allocation.widget = value_data_ref (child_value); g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); return TRUE; } gboolean bge_wdgt_spec_add_measure_value (BgeWdgtSpec *self, const char *name, BgeWdgtMeasureKind kind, GError **error) { g_autoptr (ValueData) value = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); if (g_hash_table_contains (self->values, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' already exists", name); return FALSE; } value = value_data_new (); value->name = g_strdup (name); value->type = G_TYPE_INT; switch (kind) { case BGE_WDGT_MEASURE_MINIMUM_WIDTH: value->kind = VALUE_MEASURE_MINIMUM_WIDTH; break; case BGE_WDGT_MEASURE_NATURAL_WIDTH: value->kind = VALUE_MEASURE_NATURAL_WIDTH; break; case BGE_WDGT_MEASURE_MINIMUM_HEIGHT: value->kind = VALUE_MEASURE_MINIMUM_HEIGHT; break; case BGE_WDGT_MEASURE_NATURAL_HEIGHT: value->kind = VALUE_MEASURE_NATURAL_HEIGHT; break; default: { g_critical ("Passed an invalid measure kind"); return FALSE; } } g_hash_table_replace (self->values, g_strdup (name), value_data_ref (value)); return TRUE; } gboolean bge_wdgt_spec_add_state (BgeWdgtSpec *self, const char *name, gboolean default_state, GError **error) { g_autoptr (StateData) state = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); if (g_hash_table_contains (self->states, name)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "state '%s' already exists", name); return FALSE; } if (default_state && self->default_state != NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "default state already specified"); return FALSE; } state = state_data_new (); state->name = g_strdup (name); state->setters = g_hash_table_new_full ( g_direct_hash, g_direct_equal, value_data_unref, value_data_unref); state->transitions = g_hash_table_new_full ( g_direct_hash, g_direct_equal, value_data_unref, transition_data_unref); g_hash_table_replace (self->states, g_strdup (name), state_data_ref (state)); if (default_state) self->default_state = state_data_ref (state); return TRUE; } gboolean bge_wdgt_spec_set_value (BgeWdgtSpec *self, const char *state, const char *dest_value, const char *src_value, GError **error) { StateData *state_data = NULL; ValueData *dest_data = NULL; ValueData *src_data = NULL; g_autoptr (ValueData) coerced_src_data = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (dest_value != NULL, FALSE); g_return_val_if_fail (src_value != NULL, FALSE); if (state != NULL) state_data = g_hash_table_lookup (self->states, state); else state_data = self->init_state; dest_data = g_hash_table_lookup (self->values, dest_value); src_data = g_hash_table_lookup (self->values, src_value); if (state_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "state '%s' is undefined", state); return FALSE; } if (dest_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", dest_value); return FALSE; } if (src_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", src_value); return FALSE; } if (dest_data == src_data) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "cannot assign '%s' to itself", src_value); return FALSE; } if (!g_type_is_a (src_data->type, dest_data->type)) { if (check_can_coerce_type (dest_data->type, src_data->type)) coerced_src_data = wrap_coerce_value (self, src_data, dest_data->type); else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "source type %s cannot be assigned to destination type %s", g_type_name (src_data->type), g_type_name (dest_data->type)); return FALSE; } } if (dest_data->kind == VALUE_CONSTANT) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "cannot assign to a constant source value"); return FALSE; } if (dest_data->kind == VALUE_SPECIAL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "cannot assign to a special source value"); return FALSE; } if (dest_data->kind == VALUE_PROPERTY && !(dest_data->property.pspec_flags & G_PARAM_WRITABLE)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "property %s on type %s is not writable", dest_data->property.prop_name, g_type_name (dest_data->type)); return FALSE; } if (src_data->kind == VALUE_PROPERTY && !(src_data->property.pspec_flags & G_PARAM_READABLE)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "property %s on type %s is not writable", src_data->property.prop_name, g_type_name (src_data->type)); return FALSE; } g_hash_table_replace ( state_data->setters, value_data_ref (dest_data), coerced_src_data != NULL ? value_data_ref (coerced_src_data) : value_data_ref (src_data)); return TRUE; } gboolean bge_wdgt_spec_transition_value (BgeWdgtSpec *self, const char *state, const char *value, double seconds, BgeEasing easing, GError **error) { StateData *state_data = NULL; ValueData *value_data = NULL; g_autoptr (TransitionData) transition = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); /* state is required for transitions */ g_return_val_if_fail (state != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); if (seconds <= 0.0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "transition period must be greater than 0.0"); return FALSE; } state_data = g_hash_table_lookup (self->states, state); value_data = g_hash_table_lookup (self->values, value); if (state_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "state '%s' is undefined", state); return FALSE; } if (value_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", value); return FALSE; } if (value_data->type != G_TYPE_DOUBLE) /* TODO: support more types */ { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "type %s cannot be transitioned", g_type_name (value_data->type)); return FALSE; } transition = transition_data_new (); transition->kind = TRANSITION_EASE; transition->ease.seconds = seconds; transition->ease.easing = easing; g_hash_table_replace ( state_data->transitions, value_data_ref (value_data), transition_data_ref (transition)); /* We want the init state to track the transition as well in case of value overlays */ g_hash_table_replace ( self->init_state->transitions, value_data_ref (value_data), transition_data_ref (transition)); return TRUE; } gboolean bge_wdgt_spec_transition_value_spring (BgeWdgtSpec *self, const char *state, const char *value, const char *damping_ratio, const char *mass, const char *stiffness, GError **error) { StateData *state_data = NULL; ValueData *value_data = NULL; ValueData *damping_ratio_data = NULL; ValueData *mass_data = NULL; ValueData *stiffness_data = NULL; g_autoptr (TransitionData) transition = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); /* state is required for transitions */ g_return_val_if_fail (state != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); g_return_val_if_fail (damping_ratio != NULL, FALSE); g_return_val_if_fail (mass != NULL, FALSE); g_return_val_if_fail (stiffness != NULL, FALSE); state_data = g_hash_table_lookup (self->states, state); value_data = g_hash_table_lookup (self->values, value); damping_ratio_data = g_hash_table_lookup (self->values, damping_ratio); mass_data = g_hash_table_lookup (self->values, mass); stiffness_data = g_hash_table_lookup (self->values, stiffness); if (state_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "state '%s' is undefined", state); return FALSE; } if (value_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", value); return FALSE; } if (damping_ratio_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", damping_ratio); return FALSE; } if (mass_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", mass); return FALSE; } if (stiffness_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", stiffness); return FALSE; } if (value_data->type != G_TYPE_DOUBLE) /* TODO: support more types */ { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "type %s cannot be transitioned", g_type_name (value_data->type)); return FALSE; } if (damping_ratio_data->type != G_TYPE_DOUBLE) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "transition damping ratio must of type %s, got %s", g_type_name (G_TYPE_DOUBLE), g_type_name (damping_ratio_data->type)); return FALSE; } if (mass_data->type != G_TYPE_DOUBLE) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "transition mass must of type %s, got %s", g_type_name (G_TYPE_DOUBLE), g_type_name (mass_data->type)); return FALSE; } if (stiffness_data->type != G_TYPE_DOUBLE) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "transition stiffness must of type %s, got %s", g_type_name (G_TYPE_DOUBLE), g_type_name (stiffness_data->type)); return FALSE; } transition = transition_data_new (); transition->kind = TRANSITION_SPRING; transition->spring.damping_ratio = value_data_ref (damping_ratio_data); transition->spring.mass = value_data_ref (mass_data); transition->spring.stiffness = value_data_ref (stiffness_data); g_hash_table_replace ( state_data->transitions, value_data_ref (value_data), transition_data_ref (transition)); /* We want the init state to track the transition as well in case of value overlays */ g_hash_table_replace ( self->init_state->transitions, value_data_ref (value_data), transition_data_ref (transition)); return TRUE; } gboolean bge_wdgt_spec_append_snapshot_instr (BgeWdgtSpec *self, const char *state, BgeWdgtSnapshotInstrKind kind, const char *instr, const char *const *args, guint n_args, GError **error) { gboolean result = FALSE; StateData *state_data = NULL; SnapshotInstr match = { 0 }; guint match_rest_start = 0; g_autoptr (SnapshotCallData) call = NULL; g_return_val_if_fail (BGE_IS_WDGT_SPEC (self), FALSE); g_return_val_if_fail (instr != NULL, FALSE); g_return_val_if_fail (n_args == 0 || args != NULL, FALSE); if (state != NULL) { state_data = g_hash_table_lookup (self->states, state); if (state_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "state '%s' is undefined", state); return FALSE; } } else state_data = self->init_state; switch (kind) { case BGE_WDGT_SNAPSHOT_INSTR_PUSH: result = lookup_snapshot_push_instr (instr, &match); if (!result) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "\"%s\" is not a valid snapshot push instruction", instr); return FALSE; } break; case BGE_WDGT_SNAPSHOT_INSTR_TRANSFORM: result = lookup_snapshot_transform_instr (instr, &match); if (!result) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "\"%s\" is not a valid snapshot transform instruction", instr); return FALSE; } break; case BGE_WDGT_SNAPSHOT_INSTR_APPEND: result = lookup_snapshot_append_instr (instr, &match); if (!result) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "\"%s\" is not a valid snapshot append instruction", instr); return FALSE; } break; case BGE_WDGT_SNAPSHOT_INSTR_POP: case BGE_WDGT_SNAPSHOT_INSTR_SAVE: case BGE_WDGT_SNAPSHOT_INSTR_RESTORE: { call = snapshot_call_data_new (); call->kind = kind; ensure_state_snapshot (state_data); g_ptr_array_add (state_data->snapshot->calls, snapshot_call_data_ref (call)); } return TRUE; case BGE_WDGT_SNAPSHOT_INSTR_SNAPSHOT_CHILD: { ValueData *child = NULL; if (n_args != 1) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "child snapshot instruction requires " "a single argument"); return FALSE; } child = g_hash_table_lookup (self->values, args[0]); if (child == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", args[0]); return FALSE; } if (!g_type_is_a (child->type, GTK_TYPE_WIDGET)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is not a child", args[0]); return FALSE; } call = snapshot_call_data_new (); call->kind = kind; call->child = value_data_ref (child); ensure_state_snapshot (state_data); g_ptr_array_add (state_data->snapshot->calls, snapshot_call_data_ref (call)); } return TRUE; default: g_critical ("invalid snapshot instruction kind specified"); return FALSE; } match_rest_start = match.n_args - match.n_rest; if (n_args != match.n_args) { if (match.n_rest > 0 && n_args > match.n_args) { if ((n_args - match.n_args) % match.n_rest != 0) g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "snapshot instruction %s cannot handle %u " "trailing arguments", match.name, n_args - match.n_args); } else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "snapshot instruction %s requires %u " "arguments, got %u", match.name, match.n_args, n_args); return FALSE; } } call = snapshot_call_data_new (); call->kind = kind; call->func = match.call; call->args = g_ptr_array_new_with_free_func (value_data_unref); call->rest = g_ptr_array_new_with_free_func (value_data_unref); for (guint i = 0; i < n_args; i++) { ValueData *value_data = NULL; gboolean in_rest = FALSE; GType expected_type = 0; value_data = g_hash_table_lookup (self->values, args[i]); if (value_data == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "value '%s' is undefined", args[i]); return FALSE; } in_rest = i >= match_rest_start; if (in_rest) expected_type = match.args[match_rest_start + ((i - match_rest_start) % match.n_rest)]; else expected_type = match.args[i]; if (!g_type_is_a (value_data->type, expected_type)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "argument %u for snapshot instruction %s " "must be of type %s, got %s", i, match.name, g_type_name (expected_type), g_type_name (value_data->type)); return FALSE; } if (in_rest) g_ptr_array_add (call->rest, value_data_ref (value_data)); else g_ptr_array_add (call->args, value_data_ref (value_data)); } ensure_state_snapshot (state_data); g_ptr_array_add (state_data->snapshot->calls, snapshot_call_data_ref (call)); return TRUE; } static gboolean check_can_coerce_type (GType dest, GType src) { const struct { GType dest; GType src; } valid_pairings[] = { { G_TYPE_INT, G_TYPE_UINT }, { G_TYPE_INT, G_TYPE_FLOAT }, { G_TYPE_INT, G_TYPE_DOUBLE }, { G_TYPE_UINT, G_TYPE_INT }, { G_TYPE_UINT, G_TYPE_FLOAT }, { G_TYPE_UINT, G_TYPE_DOUBLE }, { G_TYPE_INT64, G_TYPE_INT }, { G_TYPE_INT64, G_TYPE_UINT }, { G_TYPE_INT64, G_TYPE_FLOAT }, { G_TYPE_INT64, G_TYPE_DOUBLE }, { G_TYPE_UINT64, G_TYPE_INT }, { G_TYPE_UINT64, G_TYPE_UINT }, { G_TYPE_UINT64, G_TYPE_INT64 }, { G_TYPE_UINT64, G_TYPE_FLOAT }, { G_TYPE_UINT64, G_TYPE_DOUBLE }, { G_TYPE_FLOAT, G_TYPE_INT }, { G_TYPE_FLOAT, G_TYPE_UINT }, { G_TYPE_FLOAT, G_TYPE_DOUBLE }, { G_TYPE_DOUBLE, G_TYPE_INT }, { G_TYPE_DOUBLE, G_TYPE_UINT }, { G_TYPE_DOUBLE, G_TYPE_FLOAT }, { G_TYPE_STRING, G_TYPE_INT }, { G_TYPE_STRING, G_TYPE_UINT }, { G_TYPE_STRING, G_TYPE_INT64 }, { G_TYPE_STRING, G_TYPE_UINT64 }, { G_TYPE_STRING, G_TYPE_FLOAT }, { G_TYPE_STRING, G_TYPE_DOUBLE }, }; for (guint i = 0; i < G_N_ELEMENTS (valid_pairings); i++) { if (dest == valid_pairings[i].dest && src == valid_pairings[i].src) return TRUE; } return FALSE; } static void coerce_value (const GValue *in, GType dest_type, GValue *out) { /* Not a switch for style, though not the case here GType macros can sometimes be non-compile-time constants */ if (dest_type == G_TYPE_INT) { int val = 0; if (in->g_type == G_TYPE_UINT) val = g_value_get_uint (in); else if (in->g_type == G_TYPE_FLOAT) val = round (g_value_get_float (in)); else if (in->g_type == G_TYPE_DOUBLE) val = round (g_value_get_double (in)); g_value_set_int (out, val); } else if (dest_type == G_TYPE_UINT) { guint val = 0; if (in->g_type == G_TYPE_INT) val = g_value_get_int (in); else if (in->g_type == G_TYPE_FLOAT) val = round (g_value_get_float (in)); else if (in->g_type == G_TYPE_DOUBLE) val = round (g_value_get_double (in)); g_value_set_uint (out, val); } else if (dest_type == G_TYPE_INT64) { gint64 val = 0; if (in->g_type == G_TYPE_INT) val = g_value_get_int (in); else if (in->g_type == G_TYPE_UINT) val = g_value_get_uint (in); else if (in->g_type == G_TYPE_FLOAT) val = round (g_value_get_float (in)); else if (in->g_type == G_TYPE_DOUBLE) val = round (g_value_get_double (in)); g_value_set_int64 (out, val); } else if (dest_type == G_TYPE_UINT64) { guint64 val = 0; if (in->g_type == G_TYPE_INT) val = g_value_get_int (in); else if (in->g_type == G_TYPE_UINT) val = g_value_get_uint (in); else if (in->g_type == G_TYPE_INT64) val = g_value_get_int64 (in); else if (in->g_type == G_TYPE_UINT64) val = round (g_value_get_float (in)); else if (in->g_type == G_TYPE_DOUBLE) val = round (g_value_get_double (in)); g_value_set_uint64 (out, val); } else if (dest_type == G_TYPE_FLOAT) { float val = 0; if (in->g_type == G_TYPE_INT) val = g_value_get_int (in); else if (in->g_type == G_TYPE_UINT) val = g_value_get_uint (in); else if (in->g_type == G_TYPE_DOUBLE) val = round (g_value_get_double (in)); g_value_set_float (out, val); } else if (dest_type == G_TYPE_DOUBLE) { double val = 0; if (in->g_type == G_TYPE_INT) val = g_value_get_int (in); else if (in->g_type == G_TYPE_UINT) val = g_value_get_uint (in); else if (in->g_type == G_TYPE_FLOAT) val = round (g_value_get_float (in)); g_value_set_double (out, val); } else if (dest_type == G_TYPE_STRING) { g_autofree char *val = NULL; if (in->g_type == G_TYPE_INT) val = g_strdup_printf ("%d", g_value_get_int (in)); else if (in->g_type == G_TYPE_UINT) val = g_strdup_printf ("%u", g_value_get_uint (in)); else if (in->g_type == G_TYPE_INT64) val = g_strdup_printf ("%zd", g_value_get_int64 (in)); else if (in->g_type == G_TYPE_UINT64) val = g_strdup_printf ("%zu", g_value_get_uint64 (in)); else if (in->g_type == G_TYPE_FLOAT) val = g_strdup_printf ("%f", g_value_get_float (in)); else if (in->g_type == G_TYPE_DOUBLE) val = g_strdup_printf ("%f", g_value_get_double (in)); g_value_take_string (out, g_steal_pointer (&val)); } } static ValueData * wrap_coerce_value (BgeWdgtSpec *self, ValueData *value, GType dest_type) { g_autoptr (ValueData) coerced = NULL; g_assert (!g_type_is_a (value->type, dest_type)); coerced = value_data_new (); coerced->type = dest_type; coerced->kind = VALUE_COERCION; coerced->coercion.value = value_data_ref (value); g_ptr_array_add (self->anon_values, value_data_ref (coerced)); return g_steal_pointer (&coerced); } static GskTransform * transform_instr_transform (GskTransform *next, const GValue args[]) { return gsk_transform_transform ( next, g_value_get_boxed (&args[0])); } static GskTransform * transform_instr_invert (GskTransform *next, const GValue args[]) { return gsk_transform_transform ( next, g_value_get_boxed (&args[0])); } static GskTransform * transform_instr_matrix (GskTransform *next, const GValue args[]) { return gsk_transform_matrix ( next, g_value_get_boxed (&args[0])); } static GskTransform * transform_instr_matrix_2d (GskTransform *next, const GValue args[]) { return gsk_transform_matrix_2d ( next, g_value_get_double (&args[0]), g_value_get_double (&args[1]), g_value_get_double (&args[2]), g_value_get_double (&args[3]), g_value_get_double (&args[4]), g_value_get_double (&args[5])); } static GskTransform * transform_instr_translate (GskTransform *next, const GValue args[]) { return gsk_transform_translate ( next, g_value_get_boxed (&args[0])); } static GskTransform * transform_instr_translate_3d (GskTransform *next, const GValue args[]) { return gsk_transform_translate_3d ( next, g_value_get_boxed (&args[0])); } static GskTransform * transform_instr_skew (GskTransform *next, const GValue args[]) { return gsk_transform_skew ( next, g_value_get_double (&args[0]), g_value_get_double (&args[1])); } static GskTransform * transform_instr_rotate (GskTransform *next, const GValue args[]) { return gsk_transform_rotate ( next, g_value_get_double (&args[0])); } static GskTransform * transform_instr_rotate_3d (GskTransform *next, const GValue args[]) { return gsk_transform_rotate_3d ( next, g_value_get_double (&args[0]), g_value_get_boxed (&args[1])); } static GskTransform * transform_instr_scale (GskTransform *next, const GValue args[]) { return gsk_transform_scale ( next, g_value_get_double (&args[0]), g_value_get_double (&args[1])); } static GskTransform * transform_instr_scale_3d (GskTransform *next, const GValue args[]) { return gsk_transform_scale_3d ( next, g_value_get_double (&args[0]), g_value_get_double (&args[1]), g_value_get_double (&args[2])); } static GskTransform * transform_instr_perspective (GskTransform *next, const GValue args[]) { return gsk_transform_perspective ( next, g_value_get_double (&args[0])); } static gboolean lookup_transform_instr (const char *lookup_name, TransformInstr *out) { TransformInstr instrs[] = { { "transform", 1, { GSK_TYPE_TRANSFORM, }, gsk_transform_transform, transform_instr_transform, }, { "invert", 0, {}, gsk_transform_invert, transform_instr_invert, }, { "matrix", 1, { GRAPHENE_TYPE_MATRIX, }, gsk_transform_matrix, transform_instr_matrix, }, { "matrix-2d", 6, { G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, }, gsk_transform_matrix_2d, transform_instr_matrix_2d, }, { "translate", 1, { GRAPHENE_TYPE_POINT, }, gsk_transform_translate, transform_instr_translate, }, { "translate-3d", 1, { GRAPHENE_TYPE_POINT3D, }, gsk_transform_translate_3d, transform_instr_translate_3d, }, { "skew", 2, { G_TYPE_DOUBLE, G_TYPE_DOUBLE, }, gsk_transform_skew, transform_instr_skew, }, { "rotate", 1, { G_TYPE_DOUBLE, }, gsk_transform_rotate, transform_instr_rotate, }, { "rotate-3d", 2, { G_TYPE_DOUBLE, GRAPHENE_TYPE_VEC3, }, gsk_transform_rotate_3d, transform_instr_rotate_3d, }, { "scale", 2, { G_TYPE_DOUBLE, G_TYPE_DOUBLE, }, gsk_transform_scale, transform_instr_scale, }, { "scale-3d", 3, { G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, }, gsk_transform_scale_3d, transform_instr_scale_3d, }, { "perspective", 1, { G_TYPE_DOUBLE, }, gsk_transform_perspective, transform_instr_perspective, }, }; for (guint i = 0; i < G_N_ELEMENTS (instrs); i++) { if (g_strcmp0 (lookup_name, instrs[i].name) == 0) { *out = instrs[i]; return TRUE; } } return FALSE; } static void snapshot_push_instr_opacity (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_push_opacity ( snapshot, g_value_get_double (&args[0])); } static void snapshot_push_instr_isolation (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_push_isolation ( snapshot, g_value_get_flags (&args[0])); } static void snapshot_push_instr_blur (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_push_blur ( snapshot, g_value_get_double (&args[0])); } static void snapshot_push_instr_color_matrix (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_push_color_matrix ( snapshot, g_value_get_boxed (&args[0]), g_value_get_boxed (&args[1])); } static void snapshot_push_instr_component_transfer (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_push_component_transfer ( snapshot, g_value_get_boxed (&args[0]), g_value_get_boxed (&args[1]), g_value_get_boxed (&args[2]), g_value_get_boxed (&args[3])); } static void snapshot_push_instr_repeat (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_push_repeat ( snapshot, g_value_get_boxed (&args[0]), g_value_get_boxed (&args[1])); } static void snapshot_push_instr_clip (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_push_clip ( snapshot, g_value_get_boxed (&args[0])); } static void snapshot_push_instr_rounded_clip (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { GskRoundedRect rrect = { 0 }; rrect.bounds = *(graphene_rect_t *) g_value_get_boxed (&args[0]); rrect.corner[0] = *(graphene_size_t *) g_value_get_boxed (&args[1]); rrect.corner[1] = *(graphene_size_t *) g_value_get_boxed (&args[2]); rrect.corner[2] = *(graphene_size_t *) g_value_get_boxed (&args[3]); rrect.corner[3] = *(graphene_size_t *) g_value_get_boxed (&args[4]); gtk_snapshot_push_rounded_clip ( snapshot, &rrect); } static void snapshot_push_instr_fill (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_push_fill ( snapshot, g_value_get_boxed (&args[0]), g_value_get_enum (&args[1])); } static void snapshot_push_instr_stroke (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_push_stroke ( snapshot, g_value_get_boxed (&args[0]), g_value_get_boxed (&args[1])); } static void snapshot_push_instr_shadow (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { guint n_shadows = 0; GskShadow shadows[ARGBUF_SIZE] = { 0 }; n_shadows = MIN (n_rest / 4, G_N_ELEMENTS (shadows)); for (guint i = 0; i < n_shadows; i++) { shadows[i].color = *(GdkRGBA *) g_value_get_boxed (&rest[i * 4 + 0]); shadows[i].dx = g_value_get_double (&rest[i * 4 + 1]); shadows[i].dy = g_value_get_double (&rest[i * 4 + 2]); shadows[i].radius = g_value_get_double (&rest[i * 4 + 3]); } gtk_snapshot_push_shadow ( snapshot, shadows, n_shadows); } static void snapshot_push_instr_blend (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_push_blend ( snapshot, g_value_get_enum (&args[0])); } static void snapshot_push_instr_mask (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_push_mask ( snapshot, g_value_get_enum (&args[0])); } static void snapshot_push_instr_copy (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_push_copy ( snapshot); } static void snapshot_push_instr_composite (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_push_composite ( snapshot, g_value_get_enum (&args[0])); } static void snapshot_push_instr_cross_fade (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_push_cross_fade ( snapshot, g_value_get_double (&args[0])); } static gboolean lookup_snapshot_push_instr (const char *lookup_name, SnapshotInstr *out) { SnapshotInstr instrs[] = { { "opacity", 1, 0, { G_TYPE_DOUBLE, }, gtk_snapshot_push_opacity, snapshot_push_instr_opacity, }, { "isolation", 1, 0, { GSK_TYPE_ISOLATION, }, gtk_snapshot_push_isolation, snapshot_push_instr_isolation, }, { "blur", 1, 0, { G_TYPE_DOUBLE, }, gtk_snapshot_push_blur, snapshot_push_instr_blur, }, { "color-matrix", 2, 0, { GRAPHENE_TYPE_MATRIX, GRAPHENE_TYPE_VEC4, }, gtk_snapshot_push_color_matrix, snapshot_push_instr_color_matrix, }, { "component-transfer", 4, 0, { GSK_TYPE_COMPONENT_TRANSFER, GSK_TYPE_COMPONENT_TRANSFER, GSK_TYPE_COMPONENT_TRANSFER, GSK_TYPE_COMPONENT_TRANSFER, }, gtk_snapshot_push_component_transfer, snapshot_push_instr_component_transfer, }, { "repeat", 2, 0, { GRAPHENE_TYPE_RECT, GRAPHENE_TYPE_RECT, }, gtk_snapshot_push_repeat, snapshot_push_instr_repeat, }, { "clip", 1, 0, { GRAPHENE_TYPE_RECT, }, gtk_snapshot_push_clip, snapshot_push_instr_clip, }, { "rounded-clip", 5, 0, { GRAPHENE_TYPE_RECT, GRAPHENE_TYPE_SIZE, GRAPHENE_TYPE_SIZE, GRAPHENE_TYPE_SIZE, GRAPHENE_TYPE_SIZE, }, gtk_snapshot_push_rounded_clip, snapshot_push_instr_rounded_clip, }, { "fill", 2, 0, { GSK_TYPE_PATH, GSK_TYPE_FILL_RULE, }, gtk_snapshot_push_fill, snapshot_push_instr_fill, }, { "stroke", 2, 0, { GSK_TYPE_PATH, GSK_TYPE_STROKE, }, gtk_snapshot_push_stroke, snapshot_push_instr_stroke, }, { "shadow", 4, 4, { GDK_TYPE_RGBA, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, }, gtk_snapshot_push_shadow, snapshot_push_instr_shadow, }, { "blend", 1, 0, { GSK_TYPE_BLEND_MODE, }, gtk_snapshot_push_blend, snapshot_push_instr_blend, }, { "mask", 1, 0, { GSK_TYPE_MASK_MODE, }, gtk_snapshot_push_mask, snapshot_push_instr_mask, }, { "copy", 0, 0, {}, gtk_snapshot_push_copy, snapshot_push_instr_copy, }, { "composite", 1, 0, { GSK_TYPE_PORTER_DUFF, }, gtk_snapshot_push_composite, snapshot_push_instr_composite, }, { "cross-fade", 1, 0, { G_TYPE_DOUBLE, }, gtk_snapshot_push_cross_fade, snapshot_push_instr_cross_fade, }, }; for (guint i = 0; i < G_N_ELEMENTS (instrs); i++) { if (g_strcmp0 (lookup_name, instrs[i].name) == 0) { *out = instrs[i]; return TRUE; } } return FALSE; } static void snapshot_transform_instr_transform (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_transform ( snapshot, g_value_get_boxed (&args[0])); } static void snapshot_transform_instr_transform_matrix (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_transform_matrix ( snapshot, g_value_get_boxed (&args[0])); } static void snapshot_transform_instr_translate (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_translate ( snapshot, g_value_get_boxed (&args[0])); } static void snapshot_transform_instr_translate_3d (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_translate_3d ( snapshot, g_value_get_boxed (&args[0])); } static void snapshot_transform_instr_rotate (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_rotate ( snapshot, g_value_get_double (&args[0])); } static void snapshot_transform_instr_rotate_3d (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_rotate_3d ( snapshot, g_value_get_double (&args[0]), g_value_get_boxed (&args[1])); } static void snapshot_transform_instr_scale (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_scale ( snapshot, g_value_get_double (&args[0]), g_value_get_double (&args[1])); } static void snapshot_transform_instr_scale_3d (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_scale_3d ( snapshot, g_value_get_double (&args[0]), g_value_get_double (&args[1]), g_value_get_double (&args[2])); } static void snapshot_transform_instr_perspective (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_scale_3d ( snapshot, g_value_get_double (&args[0]), g_value_get_double (&args[1]), g_value_get_double (&args[2])); } static gboolean lookup_snapshot_transform_instr (const char *lookup_name, SnapshotInstr *out) { SnapshotInstr instrs[] = { { "transform", 1, 0, { GSK_TYPE_TRANSFORM, }, gtk_snapshot_transform, snapshot_transform_instr_transform, }, { "transform-matrix", 1, 0, { GRAPHENE_TYPE_MATRIX, }, gtk_snapshot_transform_matrix, snapshot_transform_instr_transform_matrix, }, { "translate", 1, 0, { GRAPHENE_TYPE_POINT, }, gtk_snapshot_translate, snapshot_transform_instr_translate, }, { "translate-3d", 1, 0, { GRAPHENE_TYPE_POINT3D, }, gtk_snapshot_translate_3d, snapshot_transform_instr_translate_3d, }, { "rotate", 1, 0, { G_TYPE_DOUBLE, }, gtk_snapshot_rotate, snapshot_transform_instr_rotate, }, { "rotate-3d", 2, 0, { G_TYPE_DOUBLE, GRAPHENE_TYPE_VEC3, }, gtk_snapshot_rotate_3d, snapshot_transform_instr_rotate_3d, }, { "scale", 2, 0, { G_TYPE_DOUBLE, G_TYPE_DOUBLE, }, gtk_snapshot_scale, snapshot_transform_instr_scale, }, { "scale-3d", 3, 0, { G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, }, gtk_snapshot_scale_3d, snapshot_transform_instr_scale_3d, }, { "perspective", 1, 0, { G_TYPE_DOUBLE, }, gtk_snapshot_perspective, snapshot_transform_instr_perspective, }, }; for (guint i = 0; i < G_N_ELEMENTS (instrs); i++) { if (g_strcmp0 (lookup_name, instrs[i].name) == 0) { *out = instrs[i]; return TRUE; } } return FALSE; } static void snapshot_append_instr_node (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_append_node ( snapshot, g_value_get_boxed (&args[0])); } static void snapshot_append_instr_texture (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_append_texture ( snapshot, g_value_get_object (&args[0]), g_value_get_boxed (&args[1])); } static void snapshot_append_instr_scaled_texture (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_append_scaled_texture ( snapshot, g_value_get_object (&args[0]), g_value_get_enum (&args[1]), g_value_get_boxed (&args[2])); } static void snapshot_append_instr_color (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_append_color ( snapshot, g_value_get_boxed (&args[0]), g_value_get_boxed (&args[1])); } static void snapshot_append_instr_linear_gradient (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { guint n_stops = 0; GskColorStop stops[ARGBUF_SIZE] = { 0 }; n_stops = MIN (n_rest / 2, G_N_ELEMENTS (stops)); for (guint i = 0; i < n_stops; i++) { stops[i].offset = g_value_get_double (&rest[i * 2 + 0]); stops[i].color = *(GdkRGBA *) g_value_get_boxed (&rest[i * 2 + 1]); } gtk_snapshot_append_linear_gradient ( snapshot, g_value_get_boxed (&args[0]), g_value_get_boxed (&args[1]), g_value_get_boxed (&args[2]), stops, n_stops); } static void snapshot_append_instr_repeating_linear_gradient (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { guint n_stops = 0; GskColorStop stops[ARGBUF_SIZE] = { 0 }; n_stops = MIN (n_rest / 2, G_N_ELEMENTS (stops)); for (guint i = 0; i < n_stops; i++) { stops[i].offset = g_value_get_double (&rest[i * 2 + 0]); stops[i].color = *(GdkRGBA *) g_value_get_boxed (&rest[i * 2 + 1]); } gtk_snapshot_append_repeating_linear_gradient ( snapshot, g_value_get_boxed (&args[0]), g_value_get_boxed (&args[1]), g_value_get_boxed (&args[2]), stops, n_stops); } static void snapshot_append_instr_radial_gradient (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { guint n_stops = 0; GskColorStop stops[ARGBUF_SIZE] = { 0 }; n_stops = MIN (n_rest / 2, G_N_ELEMENTS (stops)); for (guint i = 0; i < n_stops; i++) { stops[i].offset = g_value_get_double (&rest[i * 2 + 0]); stops[i].color = *(GdkRGBA *) g_value_get_boxed (&rest[i * 2 + 1]); } gtk_snapshot_append_radial_gradient ( snapshot, g_value_get_boxed (&args[0]), g_value_get_boxed (&args[1]), g_value_get_double (&args[2]), g_value_get_double (&args[3]), g_value_get_double (&args[4]), g_value_get_double (&args[5]), stops, n_stops); } static void snapshot_append_instr_repeating_radial_gradient (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { guint n_stops = 0; GskColorStop stops[ARGBUF_SIZE] = { 0 }; n_stops = MIN (n_rest / 2, G_N_ELEMENTS (stops)); for (guint i = 0; i < n_stops; i++) { stops[i].offset = g_value_get_double (&rest[i * 2 + 0]); stops[i].color = *(GdkRGBA *) g_value_get_boxed (&rest[i * 2 + 1]); } gtk_snapshot_append_repeating_radial_gradient ( snapshot, g_value_get_boxed (&args[0]), g_value_get_boxed (&args[1]), g_value_get_double (&args[2]), g_value_get_double (&args[3]), g_value_get_double (&args[4]), g_value_get_double (&args[5]), stops, n_stops); } static void snapshot_append_instr_conic_gradient (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { guint n_stops = 0; GskColorStop stops[ARGBUF_SIZE] = { 0 }; n_stops = MIN (n_rest / 2, G_N_ELEMENTS (stops)); for (guint i = 0; i < n_stops; i++) { stops[i].offset = g_value_get_double (&rest[i * 2 + 0]); stops[i].color = *(GdkRGBA *) g_value_get_boxed (&rest[i * 2 + 1]); } gtk_snapshot_append_conic_gradient ( snapshot, g_value_get_boxed (&args[0]), g_value_get_boxed (&args[1]), g_value_get_double (&args[2]), stops, n_stops); } static void snapshot_append_instr_border (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { GskRoundedRect rrect = { 0 }; float border_width[4] = { 0 }; GdkRGBA border_color[4] = { 0 }; rrect.bounds = *(graphene_rect_t *) g_value_get_boxed (&args[0]); rrect.corner[0] = *(graphene_size_t *) g_value_get_boxed (&args[1]); rrect.corner[1] = *(graphene_size_t *) g_value_get_boxed (&args[2]); rrect.corner[2] = *(graphene_size_t *) g_value_get_boxed (&args[3]); rrect.corner[3] = *(graphene_size_t *) g_value_get_boxed (&args[4]); border_width[0] = g_value_get_double (&args[5]); border_width[1] = g_value_get_double (&args[6]); border_width[2] = g_value_get_double (&args[7]); border_width[3] = g_value_get_double (&args[8]); border_color[0] = *(GdkRGBA *) g_value_get_boxed (&args[9]); border_color[1] = *(GdkRGBA *) g_value_get_boxed (&args[10]); border_color[2] = *(GdkRGBA *) g_value_get_boxed (&args[11]); border_color[3] = *(GdkRGBA *) g_value_get_boxed (&args[12]); gtk_snapshot_append_border ( snapshot, &rrect, border_width, border_color); } static void snapshot_append_instr_inset_shadow (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { GskRoundedRect rrect = { 0 }; rrect.bounds = *(graphene_rect_t *) g_value_get_boxed (&args[0]); rrect.corner[0] = *(graphene_size_t *) g_value_get_boxed (&args[1]); rrect.corner[1] = *(graphene_size_t *) g_value_get_boxed (&args[2]); rrect.corner[2] = *(graphene_size_t *) g_value_get_boxed (&args[3]); rrect.corner[3] = *(graphene_size_t *) g_value_get_boxed (&args[4]); gtk_snapshot_append_inset_shadow ( snapshot, &rrect, g_value_get_boxed (&args[5]), g_value_get_double (&args[6]), g_value_get_double (&args[7]), g_value_get_double (&args[8]), g_value_get_double (&args[9])); } static void snapshot_append_instr_outset_shadow (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { GskRoundedRect rrect = { 0 }; rrect.bounds = *(graphene_rect_t *) g_value_get_boxed (&args[0]); rrect.corner[0] = *(graphene_size_t *) g_value_get_boxed (&args[1]); rrect.corner[1] = *(graphene_size_t *) g_value_get_boxed (&args[2]); rrect.corner[2] = *(graphene_size_t *) g_value_get_boxed (&args[3]); rrect.corner[3] = *(graphene_size_t *) g_value_get_boxed (&args[4]); gtk_snapshot_append_outset_shadow ( snapshot, &rrect, g_value_get_boxed (&args[5]), g_value_get_double (&args[6]), g_value_get_double (&args[7]), g_value_get_double (&args[8]), g_value_get_double (&args[9])); } static void snapshot_append_instr_layout (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_append_layout ( snapshot, g_value_get_object (&args[0]), g_value_get_boxed (&args[1])); } static void snapshot_append_instr_fill (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_append_fill ( snapshot, g_value_get_boxed (&args[0]), g_value_get_enum (&args[1]), g_value_get_boxed (&args[2])); } static void snapshot_append_instr_stroke (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_append_stroke ( snapshot, g_value_get_boxed (&args[0]), g_value_get_boxed (&args[1]), g_value_get_boxed (&args[2])); } static void snapshot_append_instr_paste (GtkSnapshot *snapshot, const GValue args[], const GValue rest[], guint n_rest) { gtk_snapshot_append_paste ( snapshot, g_value_get_boxed (&args[0]), g_value_get_uint64 (&args[1])); } static gboolean lookup_snapshot_append_instr (const char *lookup_name, SnapshotInstr *out) { SnapshotInstr instrs[] = { { "node", 1, 0, { GSK_TYPE_RENDER_NODE, }, gtk_snapshot_append_node, snapshot_append_instr_node, }, { "texture", 2, 0, { GDK_TYPE_TEXTURE, GRAPHENE_TYPE_RECT, }, gtk_snapshot_append_texture, snapshot_append_instr_texture, }, { "scaled-texture", 3, 0, { GDK_TYPE_TEXTURE, GSK_TYPE_SCALING_FILTER, GRAPHENE_TYPE_RECT, }, gtk_snapshot_append_scaled_texture, snapshot_append_instr_scaled_texture, }, { "color", 2, 0, { GDK_TYPE_RGBA, GRAPHENE_TYPE_RECT, }, gtk_snapshot_append_color, snapshot_append_instr_color, }, { "linear-gradient", 5, 2, { GRAPHENE_TYPE_RECT, GRAPHENE_TYPE_POINT, GRAPHENE_TYPE_POINT, G_TYPE_DOUBLE, GDK_TYPE_RGBA, }, gtk_snapshot_append_linear_gradient, snapshot_append_instr_linear_gradient, }, { "repeating-linear-gradient", 5, 2, { GRAPHENE_TYPE_RECT, GRAPHENE_TYPE_POINT, GRAPHENE_TYPE_POINT, G_TYPE_DOUBLE, GDK_TYPE_RGBA, }, gtk_snapshot_append_repeating_linear_gradient, snapshot_append_instr_repeating_linear_gradient, }, { "radial-gradient", 8, 2, { GRAPHENE_TYPE_RECT, GRAPHENE_TYPE_POINT, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, GDK_TYPE_RGBA, }, gtk_snapshot_append_radial_gradient, snapshot_append_instr_radial_gradient, }, { "repeating-radial-gradient", 8, 2, { GRAPHENE_TYPE_RECT, GRAPHENE_TYPE_POINT, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, GDK_TYPE_RGBA, }, gtk_snapshot_append_repeating_radial_gradient, snapshot_append_instr_repeating_radial_gradient, }, { "conic-gradient", 5, 2, { GRAPHENE_TYPE_RECT, GRAPHENE_TYPE_POINT, G_TYPE_DOUBLE, G_TYPE_DOUBLE, GDK_TYPE_RGBA, }, gtk_snapshot_append_conic_gradient, snapshot_append_instr_conic_gradient, }, { "border", 13, 0, { GRAPHENE_TYPE_RECT, GRAPHENE_TYPE_SIZE, GRAPHENE_TYPE_SIZE, GRAPHENE_TYPE_SIZE, GRAPHENE_TYPE_SIZE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, GDK_TYPE_RGBA, GDK_TYPE_RGBA, GDK_TYPE_RGBA, GDK_TYPE_RGBA, }, gtk_snapshot_append_border, snapshot_append_instr_border, }, { "inset-shadow", 10, 0, { GRAPHENE_TYPE_RECT, GRAPHENE_TYPE_SIZE, GRAPHENE_TYPE_SIZE, GRAPHENE_TYPE_SIZE, GRAPHENE_TYPE_SIZE, GDK_TYPE_RGBA, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, }, gtk_snapshot_append_inset_shadow, snapshot_append_instr_inset_shadow, }, { "outset-shadow", 10, 0, { GRAPHENE_TYPE_RECT, GRAPHENE_TYPE_SIZE, GRAPHENE_TYPE_SIZE, GRAPHENE_TYPE_SIZE, GRAPHENE_TYPE_SIZE, GDK_TYPE_RGBA, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, }, gtk_snapshot_append_outset_shadow, snapshot_append_instr_outset_shadow, }, { "layout", 2, 0, { PANGO_TYPE_LAYOUT, GDK_TYPE_RGBA, }, gtk_snapshot_append_layout, snapshot_append_instr_layout, }, { "fill", 3, 0, { GSK_TYPE_PATH, GSK_TYPE_FILL_RULE, GDK_TYPE_RGBA, }, gtk_snapshot_append_fill, snapshot_append_instr_fill, }, { "stroke", 3, 0, { GSK_TYPE_PATH, GSK_TYPE_STROKE, GDK_TYPE_RGBA, }, gtk_snapshot_append_stroke, snapshot_append_instr_stroke, }, { "paste", 2, 0, { GRAPHENE_TYPE_RECT, G_TYPE_UINT64, }, gtk_snapshot_append_paste, snapshot_append_instr_paste, }, }; for (guint i = 0; i < G_N_ELEMENTS (instrs); i++) { if (g_strcmp0 (lookup_name, instrs[i].name) == 0) { *out = instrs[i]; return TRUE; } } return FALSE; } static void ensure_state_snapshot (StateData *state) { if (state->snapshot != NULL) return; state->snapshot = snapshot_data_new (); state->snapshot->calls = g_ptr_array_new_with_free_func ( snapshot_call_data_unref); } /* ------------------------------ */ /* Widget Renderer Implementation */ /* ------------------------------ */ #define BGE_TYPE_WDGT_NOTIFIER (bge_wdgt_notifier_get_type ()) G_DECLARE_FINAL_TYPE (BgeWdgtNotifier, bge_wdgt_notifier, BGE, WDGT_NOTIFIER, GObject) struct _BgeWdgtNotifier { GObject parent_instance; double value; }; G_DEFINE_FINAL_TYPE (BgeWdgtNotifier, bge_wdgt_notifier, G_TYPE_OBJECT); enum { NOTIFIER_PROP_0, NOTIFIER_PROP_VALUE, LAST_NOTIFIER_PROP }; static GParamSpec *notifier_props[LAST_NOTIFIER_PROP] = { 0 }; static void bge_wdgt_notifier_dispose (GObject *object) { BgeWdgtNotifier *self = BGE_WDGT_NOTIFIER (object); (void) self; G_OBJECT_CLASS (bge_wdgt_notifier_parent_class)->dispose (object); } static void bge_wdgt_notifier_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BgeWdgtNotifier *self = BGE_WDGT_NOTIFIER (object); switch (prop_id) { case NOTIFIER_PROP_VALUE: g_value_set_double (value, self->value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bge_wdgt_notifier_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BgeWdgtNotifier *self = BGE_WDGT_NOTIFIER (object); switch (prop_id) { case NOTIFIER_PROP_VALUE: self->value = g_value_get_double (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bge_wdgt_notifier_class_init (BgeWdgtNotifierClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = bge_wdgt_notifier_set_property; object_class->get_property = bge_wdgt_notifier_get_property; object_class->dispose = bge_wdgt_notifier_dispose; notifier_props[NOTIFIER_PROP_VALUE] = g_param_spec_double ( "value", NULL, NULL, G_MININT, G_MAXINT, 0.0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, notifier_props); } static void bge_wdgt_notifier_init (BgeWdgtNotifier *self) { } /* --- */ BGE_DEFINE_DATA ( state_instance, StateInstance, { GHashTable *expressions; GHashTable *transitions; GPtrArray *snapshot_deps; }, BGE_RELEASE_DATA (expressions, g_hash_table_unref); BGE_RELEASE_DATA (transitions, g_hash_table_unref); BGE_RELEASE_DATA (snapshot_deps, g_ptr_array_unref)) struct _BgeWdgtRenderer { GtkWidget parent_instance; BgeWdgtSpec *spec; char *state; GObject *reference; GtkWidget *child; StateInstanceData *init_instance; GPtrArray *init_watches; StateData *active_state; StateInstanceData *active_instance; SnapshotData *active_snapshot; StateData *last_state; StateInstanceData *last_instance; GTimer *since_last_state; guint tick; gboolean had_tick_since_state_switch; GHashTable *objects; GPtrArray *children; GHashTable *allocations; GPtrArray *nonchildren; GHashTable *state_instances; GPtrArray *track_transitions; GPtrArray *bindings; GPtrArray *watches; BgeWdgtNotifier *reference_notifier; int measure_minimum_width; int measure_natural_width; int measure_minimum_height; int measure_natural_height; int current_measure_for_size; BgeWdgtNotifier *measure_for_size_notifier; int widget_width; int widget_height; BgeWdgtNotifier *widget_width_notifier; BgeWdgtNotifier *widget_height_notifier; }; G_DEFINE_FINAL_TYPE (BgeWdgtRenderer, bge_wdgt_renderer, GTK_TYPE_WIDGET); enum { RENDERER_PROP_0, RENDERER_PROP_SPEC, RENDERER_PROP_STATE, RENDERER_PROP_REFERENCE, RENDERER_PROP_CHILD, LAST_RENDERER_PROP }; static GParamSpec *renderer_props[LAST_RENDERER_PROP] = { 0 }; BGE_DEFINE_DATA ( watch_setter, WatchSetter, { BgeWdgtRenderer *self; StateData *state; StateInstanceData *instance; ValueData *dest; ValueData *src; }, BGE_RELEASE_DATA (state, state_data_unref); BGE_RELEASE_DATA (instance, state_instance_data_unref); BGE_RELEASE_DATA (dest, value_data_unref); BGE_RELEASE_DATA (src, value_data_unref)) BGE_DEFINE_DATA ( allocation, Allocation, { ValueData *width; ValueData *height; ValueData *transform; }, BGE_RELEASE_DATA (width, value_data_unref); BGE_RELEASE_DATA (height, value_data_unref); BGE_RELEASE_DATA (transform, value_data_unref)) typedef struct { double velocity; double est_duration; double cache_damping_ratio; double cache_mass; double cache_stiffness; } SpringCache; BGE_DEFINE_DATA ( transition_instance, TransitionInstance, { double value; double elapsed; BgeWdgtNotifier *notifier; SpringCache spring; }, BGE_RELEASE_DATA (notifier, g_object_unref)) BGE_DEFINE_DATA ( transition_closure, TransitionClosure, { StateData *state; StateInstanceData *instance; ValueData *value; }, BGE_RELEASE_DATA (state, state_data_unref); BGE_RELEASE_DATA (instance, state_instance_data_unref); BGE_RELEASE_DATA (value, value_data_unref)); BGE_DEFINE_DATA ( track_transition_closure, TrackTransitionClosure, { ValueData *value; GTimer *timer; BgeWdgtNotifier *notifier; double elapsed; double current; double target; double last; SpringCache spring; }, BGE_RELEASE_DATA (value, value_data_unref); BGE_RELEASE_DATA (notifier, g_object_unref); BGE_RELEASE_DATA (timer, g_timer_destroy)); static void regenerate (BgeWdgtRenderer *self); static void apply_state (BgeWdgtRenderer *self); static GtkExpression * ensure_expressions (BgeWdgtRenderer *self, ValueData *value, StateData *state, StateInstanceData *instance); static void set_value (BgeWdgtRenderer *self, StateData *state, StateInstanceData *instance, ValueData *dest, ValueData *src, GPtrArray *watches); static int resolve_value_int (BgeWdgtRenderer *self, ValueData *value, StateInstanceData *instance); static double resolve_value_double (BgeWdgtRenderer *self, ValueData *value, StateInstanceData *instance); static gpointer resolve_value_boxed_dup (BgeWdgtRenderer *self, ValueData *value, StateInstanceData *instance); static gpointer resolve_value_object_dup (BgeWdgtRenderer *self, ValueData *value, StateInstanceData *instance); static void discard_binding (gpointer ptr); static void discard_watch (gpointer ptr); static void prop_change_queue_draw (BgeWdgtRenderer *self); static void reset_setter (WatchSetterData *data); static void bge_wdgt_renderer_dispose (GObject *object) { BgeWdgtRenderer *self = BGE_WDGT_RENDERER (object); if (self->tick > 0) { gtk_widget_remove_tick_callback (GTK_WIDGET (self), self->tick); self->tick = 0; } g_clear_pointer (&self->spec, g_object_unref); g_clear_pointer (&self->state, g_free); g_clear_pointer (&self->reference, g_object_unref); g_clear_pointer (&self->child, gtk_widget_unparent); g_clear_pointer (&self->init_instance, state_instance_data_unref); g_clear_pointer (&self->init_watches, g_ptr_array_unref); g_clear_pointer (&self->active_state, state_data_unref); g_clear_pointer (&self->active_instance, state_instance_data_unref); g_clear_pointer (&self->active_snapshot, snapshot_data_unref); g_clear_pointer (&self->last_state, state_data_unref); g_clear_pointer (&self->last_instance, state_instance_data_unref); g_clear_pointer (&self->since_last_state, g_timer_destroy); g_clear_pointer (&self->objects, g_hash_table_unref); g_clear_pointer (&self->children, g_ptr_array_unref); g_clear_pointer (&self->allocations, g_hash_table_unref); g_clear_pointer (&self->nonchildren, g_ptr_array_unref); g_clear_pointer (&self->state_instances, g_hash_table_unref); g_clear_pointer (&self->track_transitions, g_ptr_array_unref); g_clear_pointer (&self->bindings, g_ptr_array_unref); g_clear_pointer (&self->watches, g_ptr_array_unref); g_clear_pointer (&self->reference_notifier, g_object_unref); g_clear_pointer (&self->measure_for_size_notifier, g_object_unref); g_clear_pointer (&self->widget_width_notifier, g_object_unref); g_clear_pointer (&self->widget_height_notifier, g_object_unref); G_OBJECT_CLASS (bge_wdgt_renderer_parent_class)->dispose (object); } static void bge_wdgt_renderer_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BgeWdgtRenderer *self = BGE_WDGT_RENDERER (object); switch (prop_id) { case RENDERER_PROP_SPEC: g_value_set_object (value, bge_wdgt_renderer_get_spec (self)); break; case RENDERER_PROP_STATE: g_value_set_string (value, bge_wdgt_renderer_get_state (self)); break; case RENDERER_PROP_REFERENCE: g_value_set_object (value, bge_wdgt_renderer_get_reference (self)); break; case RENDERER_PROP_CHILD: g_value_set_object (value, bge_wdgt_renderer_get_child (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bge_wdgt_renderer_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BgeWdgtRenderer *self = BGE_WDGT_RENDERER (object); switch (prop_id) { case RENDERER_PROP_SPEC: bge_wdgt_renderer_set_spec (self, g_value_get_object (value)); break; case RENDERER_PROP_STATE: bge_wdgt_renderer_set_state (self, g_value_get_string (value)); break; case RENDERER_PROP_REFERENCE: bge_wdgt_renderer_set_reference (self, g_value_get_object (value)); break; case RENDERER_PROP_CHILD: bge_wdgt_renderer_set_child (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bge_wdgt_renderer_measure (GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline) { BgeWdgtRenderer *self = BGE_WDGT_RENDERER (widget); self->current_measure_for_size = for_size; /* This will update our measurement values in self */ g_object_notify_by_pspec ( G_OBJECT (self->measure_for_size_notifier), notifier_props[NOTIFIER_PROP_VALUE]); switch (orientation) { case GTK_ORIENTATION_HORIZONTAL: *minimum = self->measure_minimum_width; *natural = self->measure_natural_width; break; case GTK_ORIENTATION_VERTICAL: *minimum = self->measure_minimum_height; *natural = self->measure_natural_height; break; default: g_assert_not_reached (); } // if (self->child != NULL) // gtk_widget_measure ( // GTK_WIDGET (self->child), // orientation, for_size, // minimum, natural, // minimum_baseline, natural_baseline); } static void bge_wdgt_renderer_size_allocate (GtkWidget *widget, int width, int height, int baseline) { BgeWdgtRenderer *self = BGE_WDGT_RENDERER (widget); self->widget_width = width; self->widget_height = height; g_object_notify_by_pspec ( G_OBJECT (self->widget_width_notifier), notifier_props[NOTIFIER_PROP_VALUE]); g_object_notify_by_pspec ( G_OBJECT (self->widget_height_notifier), notifier_props[NOTIFIER_PROP_VALUE]); if (self->child != NULL && gtk_widget_should_layout (self->child)) gtk_widget_allocate (self->child, width, height, baseline, NULL); for (guint i = 0; i < self->children->len; i++) { GtkWidget *child = NULL; AllocationData *allocation = NULL; int alloc_width = width; int alloc_height = height; g_autoptr (GskTransform) transform = NULL; child = g_ptr_array_index (self->children, i); allocation = g_hash_table_lookup (self->allocations, child); alloc_width = resolve_value_int ( self, allocation->width, self->active_instance != NULL ? self->active_instance : self->init_instance); alloc_height = resolve_value_int ( self, allocation->height, self->active_instance != NULL ? self->active_instance : self->init_instance); transform = resolve_value_boxed_dup ( self, allocation->transform, self->active_instance != NULL ? self->active_instance : self->init_instance); gtk_widget_allocate ( child, alloc_width, alloc_height, baseline, g_steal_pointer (&transform)); } } static void bge_wdgt_renderer_snapshot (GtkWidget *widget, GtkSnapshot *snapshot) { BgeWdgtRenderer *self = BGE_WDGT_RENDERER (widget); GPtrArray *calls = NULL; if (self->child != NULL) gtk_widget_snapshot_child (GTK_WIDGET (self), self->child, snapshot); if (self->active_state == NULL) return; if (self->active_snapshot != NULL) calls = self->active_snapshot->calls; if (calls != NULL) { for (guint i = 0; i < calls->len; i++) { SnapshotCallData *call = NULL; call = g_ptr_array_index (calls, i); switch (call->kind) { case BGE_WDGT_SNAPSHOT_INSTR_POP: gtk_snapshot_pop (snapshot); break; case BGE_WDGT_SNAPSHOT_INSTR_SAVE: gtk_snapshot_save (snapshot); break; case BGE_WDGT_SNAPSHOT_INSTR_RESTORE: gtk_snapshot_restore (snapshot); break; case BGE_WDGT_SNAPSHOT_INSTR_APPEND: case BGE_WDGT_SNAPSHOT_INSTR_PUSH: case BGE_WDGT_SNAPSHOT_INSTR_TRANSFORM: { GValue arg_values[ARGBUF_SIZE] = { 0 }; guint n_arg_values = 0; GValue rest_values[ARGBUF_SIZE] = { 0 }; guint n_rest_values = 0; n_arg_values = MIN (call->args->len, G_N_ELEMENTS (arg_values)); n_rest_values = MIN (call->rest->len, G_N_ELEMENTS (rest_values)); for (guint j = 0; j < n_arg_values; j++) { ValueData *value = NULL; GtkExpression *expression = NULL; value = g_ptr_array_index (call->args, j); expression = g_hash_table_lookup (self->active_instance->expressions, value); gtk_expression_evaluate (expression, self, &arg_values[j]); } for (guint j = 0; j < n_rest_values; j++) { ValueData *value = NULL; GtkExpression *expression = NULL; value = g_ptr_array_index (call->rest, j); expression = g_hash_table_lookup (self->active_instance->expressions, value); gtk_expression_evaluate (expression, self, &rest_values[j]); } call->func (snapshot, arg_values, rest_values, n_rest_values); for (guint j = 0; j < n_rest_values; j++) { g_value_unset (&rest_values[j]); } for (guint j = 0; j < n_arg_values; j++) { g_value_unset (&arg_values[j]); } } break; case BGE_WDGT_SNAPSHOT_INSTR_SNAPSHOT_CHILD: { GtkExpression *expression = NULL; GValue child_value = G_VALUE_INIT; GtkWidget *child = NULL; expression = g_hash_table_lookup ( self->active_instance->expressions, call->child); gtk_expression_evaluate (expression, self, &child_value); child = g_value_get_object (&child_value); if (child != NULL) { if (gtk_widget_get_parent (child) == GTK_WIDGET (self)) gtk_widget_snapshot_child (GTK_WIDGET (self), child, snapshot); else g_critical ("Trying to snapshot a widget which is " "not a direct child of this spec! Skipping"); } g_value_unset (&child_value); } break; default: break; } } } // for (guint i = 0; i < self->children->len; i++) // { // GtkWidget *child = NULL; // // child = g_ptr_array_index (self->children, i); // gtk_widget_snapshot_child (GTK_WIDGET (self), child, snapshot); // } } static void bge_wdgt_renderer_class_init (BgeWdgtRendererClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bge_wdgt_renderer_set_property; object_class->get_property = bge_wdgt_renderer_get_property; object_class->dispose = bge_wdgt_renderer_dispose; renderer_props[RENDERER_PROP_SPEC] = g_param_spec_object ( "spec", NULL, NULL, BGE_TYPE_WDGT_SPEC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); renderer_props[RENDERER_PROP_STATE] = g_param_spec_string ( "state", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); renderer_props[RENDERER_PROP_REFERENCE] = g_param_spec_object ( "reference", NULL, NULL, G_TYPE_OBJECT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); renderer_props[RENDERER_PROP_CHILD] = g_param_spec_object ( "child", NULL, NULL, GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_RENDERER_PROP, renderer_props); widget_class->measure = bge_wdgt_renderer_measure; widget_class->size_allocate = bge_wdgt_renderer_size_allocate; widget_class->snapshot = bge_wdgt_renderer_snapshot; g_type_ensure (BGE_TYPE_WDGT_NOTIFIER); } static gboolean tick_cb (BgeWdgtRenderer *self, GdkFrameClock *frame_clock, gpointer user_data) { GHashTableIter iter = { 0 }; double elapsed = 0.0; gboolean finished_all_state_transitions = TRUE; self->had_tick_since_state_switch = TRUE; for (guint i = 0; i < self->track_transitions->len;) { TrackTransitionClosureData *data = NULL; data = g_ptr_array_index (self->track_transitions, i); elapsed = g_timer_elapsed (data->timer, NULL); g_object_notify_by_pspec ( G_OBJECT (data->notifier), notifier_props[NOTIFIER_PROP_VALUE]); if (elapsed <= data->spring.est_duration) i++; else g_ptr_array_remove_index (self->track_transitions, i); } if (self->spec == NULL || self->active_state == NULL || self->active_instance == NULL || self->last_state == NULL || self->last_instance == NULL) return G_SOURCE_CONTINUE; elapsed = g_timer_elapsed (self->since_last_state, NULL); g_hash_table_iter_init (&iter, self->active_state->transitions); for (;;) { ValueData *value = NULL; TransitionData *transition = NULL; TransitionInstanceData *transition_instance = NULL; TransitionInstanceData *init_transition_instance = NULL; if (!g_hash_table_iter_next ( &iter, (gpointer *) &value, (gpointer *) &transition)) break; transition_instance = g_hash_table_lookup (self->active_instance->transitions, value); if (transition_instance != NULL) g_object_notify_by_pspec ( G_OBJECT (transition_instance->notifier), notifier_props[NOTIFIER_PROP_VALUE]); init_transition_instance = g_hash_table_lookup (self->init_instance->transitions, value); if (init_transition_instance != NULL) g_object_notify_by_pspec ( G_OBJECT (init_transition_instance->notifier), notifier_props[NOTIFIER_PROP_VALUE]); switch (transition->kind) { case TRANSITION_EASE: if (elapsed <= transition->ease.seconds) finished_all_state_transitions = FALSE; break; case TRANSITION_SPRING: if (transition_instance->spring.est_duration < 0.0 || elapsed <= transition_instance->spring.est_duration) finished_all_state_transitions = FALSE; break; default: g_assert_not_reached (); } } if (finished_all_state_transitions) { g_clear_pointer (&self->last_state, state_data_unref); g_clear_pointer (&self->last_instance, state_instance_data_unref); } return G_SOURCE_CONTINUE; } static void bge_wdgt_renderer_init (BgeWdgtRenderer *self) { self->init_watches = g_ptr_array_new_with_free_func (discard_watch); self->objects = g_hash_table_new_full ( g_direct_hash, g_direct_equal, value_data_unref, g_object_unref); self->children = g_ptr_array_new_with_free_func ( (GDestroyNotify) gtk_widget_unparent); self->allocations = g_hash_table_new_full ( g_direct_hash, g_direct_equal, g_object_unref, allocation_data_unref); self->nonchildren = g_ptr_array_new_with_free_func ( (GDestroyNotify) g_object_unref); self->state_instances = g_hash_table_new_full ( g_direct_hash, g_direct_equal, state_data_unref, state_instance_data_unref); self->track_transitions = g_ptr_array_new_with_free_func ( track_transition_closure_data_unref); self->bindings = g_ptr_array_new_with_free_func (discard_binding); self->watches = g_ptr_array_new_with_free_func (discard_watch); self->since_last_state = g_timer_new (); self->reference_notifier = g_object_new (BGE_TYPE_WDGT_NOTIFIER, NULL); self->measure_for_size_notifier = g_object_new (BGE_TYPE_WDGT_NOTIFIER, NULL); self->widget_width_notifier = g_object_new (BGE_TYPE_WDGT_NOTIFIER, NULL); self->widget_height_notifier = g_object_new (BGE_TYPE_WDGT_NOTIFIER, NULL); self->tick = gtk_widget_add_tick_callback ( GTK_WIDGET (self), (GtkTickCallback) tick_cb, NULL, NULL); } BgeWdgtRenderer * bge_wdgt_renderer_new (void) { return g_object_new (BGE_TYPE_WDGT_RENDERER, NULL); } BgeWdgtSpec * bge_wdgt_renderer_get_spec (BgeWdgtRenderer *self) { g_return_val_if_fail (BGE_IS_WDGT_RENDERER (self), NULL); return self->spec; } const char * bge_wdgt_renderer_get_state (BgeWdgtRenderer *self) { g_return_val_if_fail (BGE_IS_WDGT_RENDERER (self), NULL); return self->state; } GObject * bge_wdgt_renderer_get_reference (BgeWdgtRenderer *self) { g_return_val_if_fail (BGE_IS_WDGT_RENDERER (self), NULL); return self->reference; } GtkWidget * bge_wdgt_renderer_get_child (BgeWdgtRenderer *self) { g_return_val_if_fail (BGE_IS_WDGT_RENDERER (self), NULL); return self->child; } void bge_wdgt_renderer_set_spec (BgeWdgtRenderer *self, BgeWdgtSpec *spec) { GBinding *name_binding = NULL; g_return_if_fail (BGE_IS_WDGT_RENDERER (self)); g_return_if_fail (spec == NULL || BGE_IS_WDGT_SPEC (spec)); if (spec == self->spec) return; g_clear_pointer (&self->spec, g_object_unref); if (spec != NULL) self->spec = g_object_ref (spec); regenerate (self); apply_state (self); if (spec != NULL) { name_binding = g_object_bind_property (spec, "name", self, "name", G_BINDING_SYNC_CREATE); g_ptr_array_add (self->bindings, g_object_ref (name_binding)); } else gtk_widget_set_name (GTK_WIDGET (self), NULL); g_object_notify_by_pspec (G_OBJECT (self), renderer_props[RENDERER_PROP_SPEC]); } void bge_wdgt_renderer_set_state (BgeWdgtRenderer *self, const char *state) { g_return_if_fail (BGE_IS_WDGT_RENDERER (self)); if (state == self->state || (state != NULL && self->state != NULL && g_strcmp0 (state, self->state) == 0)) return; g_clear_pointer (&self->state, g_free); if (state != NULL) self->state = g_strdup (state); apply_state (self); g_object_notify_by_pspec (G_OBJECT (self), renderer_props[RENDERER_PROP_STATE]); } void bge_wdgt_renderer_set_reference (BgeWdgtRenderer *self, GObject *reference) { g_return_if_fail (BGE_IS_WDGT_RENDERER (self)); if (reference == self->reference) return; g_clear_pointer (&self->reference, g_object_unref); if (reference != NULL) self->reference = g_object_ref (reference); g_object_notify_by_pspec (G_OBJECT (self), renderer_props[RENDERER_PROP_REFERENCE]); g_object_notify_by_pspec (G_OBJECT (self->reference_notifier), notifier_props[NOTIFIER_PROP_VALUE]); } void bge_wdgt_renderer_set_child (BgeWdgtRenderer *self, GtkWidget *child) { g_return_if_fail (BGE_IS_WDGT_RENDERER (self)); if (self->child == child) return; if (child != NULL) g_return_if_fail (gtk_widget_get_parent (child) == NULL); g_clear_pointer (&self->child, gtk_widget_unparent); self->child = child; if (child != NULL) gtk_widget_set_parent (child, GTK_WIDGET (self)); g_object_notify_by_pspec (G_OBJECT (self), renderer_props[RENDERER_PROP_CHILD]); } void bge_wdgt_renderer_set_state_take (BgeWdgtRenderer *self, char *state) { g_return_if_fail (BGE_IS_WDGT_RENDERER (self)); if (state != NULL && self->state != NULL && g_strcmp0 (state, self->state) == 0) { g_free (state); return; } g_clear_pointer (&self->state, g_free); if (state != NULL) self->state = state; g_object_notify_by_pspec (G_OBJECT (self), renderer_props[RENDERER_PROP_STATE]); } gpointer bge_wdgt_renderer_lookup_object (BgeWdgtRenderer *self, const char *name) { ValueData *value = NULL; g_return_val_if_fail (BGE_IS_WDGT_RENDERER (self), NULL); g_return_val_if_fail (name != NULL, NULL); if (self->spec == NULL || self->active_instance == NULL) return NULL; value = g_hash_table_lookup (self->spec->values, name); if (value == NULL) return NULL; if (!g_type_is_a (value->type, G_TYPE_OBJECT)) return NULL; return resolve_value_object_dup (self, value, self->active_instance); } static void regenerate (BgeWdgtRenderer *self) { BgeWdgtSpec *spec = self->spec; g_autoptr (GtkBuilder) dummy_builder = NULL; GHashTableIter state_iter = { 0 }; GHashTableIter setters_iter = { 0 }; g_clear_pointer (&self->init_instance, state_instance_data_unref); g_ptr_array_set_size (self->init_watches, 0); g_hash_table_remove_all (self->state_instances); g_hash_table_remove_all (self->objects); g_ptr_array_set_size (self->children, 0); g_hash_table_remove_all (self->allocations); g_ptr_array_set_size (self->nonchildren, 0); g_ptr_array_set_size (self->track_transitions, 0); g_clear_pointer (&self->last_state, state_data_unref); g_clear_pointer (&self->last_instance, state_instance_data_unref); g_clear_pointer (&self->active_state, state_data_unref); g_clear_pointer (&self->active_instance, state_instance_data_unref); g_clear_pointer (&self->active_snapshot, snapshot_data_unref); g_ptr_array_set_size (self->bindings, 0); g_ptr_array_set_size (self->watches, 0); if (self->spec == NULL) return; for (guint i = 0; i < spec->nonchildren->len; i++) { ValueData *value = NULL; g_autoptr (GObject) object = NULL; value = g_ptr_array_index (spec->nonchildren, i); g_assert (value->kind == VALUE_OBJECT); object = g_object_new (value->type, NULL); if (g_type_is_a (value->type, G_TYPE_INITIALLY_UNOWNED)) g_object_ref_sink (object); g_hash_table_replace (self->objects, value_data_ref (value), g_object_ref (object)); g_ptr_array_add (self->nonchildren, g_object_ref (object)); } dummy_builder = gtk_builder_new (); for (guint i = 0; i < spec->children->len; i++) { ValueData *value = NULL; GtkWidget *widget = NULL; g_autoptr (AllocationData) allocation = NULL; value = g_ptr_array_index (spec->children, i); g_assert (value->kind == VALUE_CHILD); widget = g_object_new ( value->type, "name", value->name, NULL); if (value->child.css_classes != NULL) { for (guint j = 0; j < value->child.css_classes->len; j++) { const char *class = NULL; class = g_ptr_array_index (value->child.css_classes, j); gtk_widget_add_css_class (widget, class); } } if (value->child.parent_widget != NULL) { GtkWidget *parent_widget = NULL; parent_widget = g_hash_table_lookup ( self->objects, value->child.parent_widget); g_assert (parent_widget != NULL); GTK_BUILDABLE_GET_IFACE (parent_widget) ->add_child ( GTK_BUILDABLE (parent_widget), dummy_builder, G_OBJECT (widget), value->child.builder_type); } else { gtk_widget_set_parent (widget, GTK_WIDGET (self)); g_ptr_array_add (self->children, g_object_ref (widget)); } g_hash_table_replace (self->objects, value_data_ref (value), g_object_ref (widget)); allocation = allocation_data_new (); g_hash_table_replace (self->allocations, g_object_ref (widget), allocation_data_ref (allocation)); } g_hash_table_iter_init (&state_iter, spec->states); for (;;) { char *state_name = NULL; StateData *state = NULL; g_autoptr (StateInstanceData) instance = NULL; if (!g_hash_table_iter_next ( &state_iter, (gpointer *) &state_name, (gpointer *) &state)) break; instance = state_instance_data_new (); instance->expressions = g_hash_table_new_full ( g_direct_hash, g_direct_equal, value_data_unref, (GDestroyNotify) gtk_expression_unref); instance->transitions = g_hash_table_new_full ( g_direct_hash, g_direct_equal, value_data_unref, transition_instance_data_unref); instance->snapshot_deps = g_ptr_array_new_with_free_func ( (GDestroyNotify) gtk_expression_unref); g_hash_table_replace (self->state_instances, state_data_ref (state), state_instance_data_ref (instance)); if (state == spec->init_state) self->init_instance = state_instance_data_ref (instance); } /* Separate to ensure `self->init_instance` has been set */ g_hash_table_iter_init (&state_iter, spec->states); for (;;) { GHashTableIter value_iter = { 0 }; char *state_name = NULL; StateData *state = NULL; StateInstanceData *instance = NULL; if (!g_hash_table_iter_next ( &state_iter, (gpointer *) &state_name, (gpointer *) &state)) break; instance = g_hash_table_lookup (self->state_instances, state); g_assert (instance != NULL); g_hash_table_iter_init (&value_iter, spec->values); for (;;) { char *value_name = NULL; ValueData *value = NULL; g_autoptr (GtkExpression) expression = NULL; if (!g_hash_table_iter_next ( &value_iter, (gpointer *) &value_name, (gpointer *) &value)) break; expression = ensure_expressions (self, value, state, instance); } for (guint i = 0; i < spec->anon_values->len; i++) { ValueData *value = NULL; g_autoptr (GtkExpression) expression = NULL; value = g_ptr_array_index (spec->anon_values, i); expression = ensure_expressions (self, value, state, instance); } } g_hash_table_iter_init (&state_iter, spec->states); for (;;) { char *state_name = NULL; StateData *state = NULL; StateInstanceData *instance = NULL; StateData *snapshot_state = NULL; if (!g_hash_table_iter_next ( &state_iter, (gpointer *) &state_name, (gpointer *) &state)) break; instance = g_hash_table_lookup (self->state_instances, state); g_assert (instance != NULL); if (state->snapshot != NULL) snapshot_state = state; else /* If this state doesn't have snapshot instructions specified, fallback on using the init state */ snapshot_state = self->spec->init_state; for (guint i = 0; i < snapshot_state->snapshot->calls->len; i++) { SnapshotCallData *call = NULL; call = g_ptr_array_index (snapshot_state->snapshot->calls, i); if (call->args == NULL) /* pop, save, restore... */ continue; for (guint j = 0; j < call->args->len; j++) { ValueData *arg = NULL; gboolean found = FALSE; GtkExpression *expression = NULL; arg = g_ptr_array_index (call->args, j); expression = g_hash_table_lookup (instance->expressions, arg); g_assert (expression != NULL); for (guint k = 0; k < instance->snapshot_deps->len; k++) { GtkExpression *other = NULL; other = g_ptr_array_index (instance->snapshot_deps, k); if (expression == other) { found = TRUE; break; } } if (found) /* Ensure we don't duplicate deps */ continue; g_ptr_array_add (instance->snapshot_deps, gtk_expression_ref (expression)); } } } g_hash_table_iter_init ( &setters_iter, self->spec->init_state->setters); for (;;) { ValueData *dest = NULL; ValueData *src = NULL; if (!g_hash_table_iter_next ( &setters_iter, (gpointer *) &dest, (gpointer *) &src)) break; set_value ( self, self->spec->init_state, self->init_instance, dest, src, self->init_watches); } gtk_widget_queue_allocate (GTK_WIDGET (self)); gtk_widget_queue_draw (GTK_WIDGET (self)); } static void apply_state (BgeWdgtRenderer *self) { BgeWdgtSpec *spec = self->spec; StateData *state = NULL; StateInstanceData *instance = NULL; GHashTableIter iter = { 0 }; if (self->had_tick_since_state_switch) { g_clear_pointer (&self->last_state, state_data_unref); g_clear_pointer (&self->last_instance, state_instance_data_unref); if (self->active_state != NULL && self->active_instance != NULL) { self->last_state = g_steal_pointer (&self->active_state); self->last_instance = g_steal_pointer (&self->active_instance); } g_timer_start (self->since_last_state); self->had_tick_since_state_switch = FALSE; } g_clear_pointer (&self->active_state, state_data_unref); g_clear_pointer (&self->active_instance, state_instance_data_unref); g_clear_pointer (&self->active_snapshot, snapshot_data_unref); g_ptr_array_set_size (self->bindings, 0); g_ptr_array_set_size (self->watches, 0); gtk_widget_queue_draw (GTK_WIDGET (self)); if (self->spec == NULL || self->state == NULL) return; state = g_hash_table_lookup (spec->states, self->state); if (state == NULL) { g_critical ("state \"%s\" doesn't exist on spec \"%s\"", self->state, spec->name); return; } instance = g_hash_table_lookup (self->state_instances, state); g_assert (instance != NULL); self->active_state = state_data_ref (state); self->active_instance = state_instance_data_ref (instance); if (state->snapshot != NULL) self->active_snapshot = snapshot_data_ref (state->snapshot); else if (self->spec->init_state->snapshot != NULL) self->active_snapshot = snapshot_data_ref (self->spec->init_state->snapshot); g_hash_table_iter_init (&iter, state->setters); for (;;) { ValueData *dest = NULL; ValueData *src = NULL; TransitionInstanceData *transition_instance = NULL; if (!g_hash_table_iter_next ( &iter, (gpointer *) &dest, (gpointer *) &src)) break; set_value ( self, state, instance, dest, src, self->watches); transition_instance = g_hash_table_lookup (instance->transitions, dest); if (transition_instance != NULL) transition_instance->spring.est_duration = -1.0; } g_hash_table_iter_init (&iter, spec->init_state->setters); for (;;) { ValueData *dest = NULL; ValueData *src = NULL; if (!g_hash_table_iter_next ( &iter, (gpointer *) &dest, (gpointer *) &src)) break; set_value ( self, state, instance, dest, src, self->watches); } for (guint i = 0; i < instance->snapshot_deps->len; i++) { GtkExpression *expression = NULL; GtkExpressionWatch *watch = NULL; expression = g_ptr_array_index (instance->snapshot_deps, i); watch = gtk_expression_watch ( expression, self, (GtkExpressionNotify) prop_change_queue_draw, self, NULL); g_ptr_array_add (self->watches, watch); } gtk_widget_queue_allocate (GTK_WIDGET (self)); gtk_widget_queue_draw (GTK_WIDGET (self)); } static graphene_point_t * expression_create_point (gpointer object, double x, double y, gpointer user_data) { graphene_point_t *point = NULL; point = graphene_point_alloc (); point->x = x; point->y = y; return point; } static graphene_size_t * expression_create_size (gpointer object, double width, double height, gpointer user_data) { graphene_size_t *size = NULL; size = graphene_size_alloc (); size->width = width; size->height = height; return size; } static graphene_point3d_t * expression_create_point3d (gpointer object, double x, double y, double z, gpointer user_data) { graphene_point3d_t *point3d = NULL; point3d = graphene_point3d_alloc (); point3d->x = x; point3d->y = y; point3d->z = z; return point3d; } static graphene_rect_t * expression_create_rect (gpointer object, double x, double y, double width, double height, gpointer user_data) { graphene_rect_t *rect = NULL; rect = graphene_rect_alloc (); rect->origin.x = x; rect->origin.y = y; rect->size.width = width; rect->size.height = height; return rect; } static void expression_coerce_type (gpointer this, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer dest_type_ptr) { GType dest_type = GPOINTER_TO_SIZE (dest_type_ptr); coerce_value (¶m_values[0], dest_type, return_value); } static int expression_get_measure_for_size (BgeWdgtRenderer *this, double notify, gpointer user_data) { return this->current_measure_for_size; } static double expression_get_widget_width (BgeWdgtRenderer *this, double notify, gpointer user_data) { return (double) this->widget_width; } static double expression_get_widget_height (BgeWdgtRenderer *this, double notify, gpointer user_data) { return (double) this->widget_height; } static gpointer expression_get_reference_object (BgeWdgtRenderer *this, double notify, gpointer user_data) { return this->reference != NULL ? g_object_ref (this->reference) : NULL; } static double expression_adjust_state_transition (BgeWdgtRenderer *this, double in, double notifier, TransitionClosureData *data) { gboolean result = FALSE; TransitionData *transition = NULL; TransitionData *last_transition = NULL; TransitionInstanceData *transition_instance = NULL; TransitionInstanceData *last_transition_instance = NULL; ValueData *last_in_value = NULL; double last_in = 0.0; double elapsed = 0.0; double progress = 0.0; double interpolated_number = 0.0; g_assert (data->value->type == G_TYPE_DOUBLE); if (this->active_state == NULL || this->active_instance == NULL || this->last_state == NULL || this->last_instance == NULL) return in; if (data->instance != this->active_instance) { GtkExpression *corrected_in_expression = NULL; GValue corrected_in_resolved = G_VALUE_INIT; corrected_in_expression = g_hash_table_lookup ( this->active_instance->expressions, data->value); g_assert (corrected_in_expression != NULL); result = gtk_expression_evaluate ( corrected_in_expression, this, &corrected_in_resolved); if (result) in = g_value_get_double (&corrected_in_resolved); g_value_unset (&corrected_in_resolved); } transition = g_hash_table_lookup ( this->active_state->transitions, data->value); if (transition == NULL) return in; last_transition = g_hash_table_lookup ( this->last_state->transitions, data->value); transition_instance = g_hash_table_lookup ( this->active_instance->transitions, data->value); g_assert (transition_instance != NULL); last_transition_instance = g_hash_table_lookup ( this->last_instance->transitions, data->value); if (last_transition != NULL && last_transition_instance != NULL && last_transition->kind == TRANSITION_EASE && last_transition_instance->elapsed < last_transition->ease.seconds) last_in = last_transition_instance->value; else { last_in_value = g_hash_table_lookup (this->last_state->setters, data->value); if (last_in_value == NULL) return in; last_in = resolve_value_double (this, last_in_value, this->last_instance); } elapsed = g_timer_elapsed (this->since_last_state, NULL); transition_instance->elapsed = elapsed; switch (transition->kind) { case TRANSITION_SPRING: { double damping_ratio = 0.0; double mass = 0.0; double stiffness = 0.0; double damping = 0.0; damping_ratio = resolve_value_double ( this, transition->spring.damping_ratio, this->active_instance); mass = resolve_value_double ( this, transition->spring.mass, this->active_instance); stiffness = resolve_value_double ( this, transition->spring.stiffness, this->active_instance); damping = damping_ratio * (/* critical damping */ 2 * sqrt (mass * stiffness)); if (transition_instance->spring.est_duration < 0.0 || damping_ratio != transition_instance->spring.cache_damping_ratio || mass != transition_instance->spring.cache_mass || stiffness != transition_instance->spring.cache_stiffness) { if (last_transition != NULL && last_transition->kind == TRANSITION_SPRING) transition_instance->spring.velocity = last_transition_instance->spring.velocity; else transition_instance->spring.velocity = 0.0; transition_instance->spring.est_duration = spring_calculate_duration ( damping, mass, stiffness, last_in, in, FALSE); transition_instance->spring.cache_damping_ratio = damping_ratio; transition_instance->spring.cache_mass = mass; transition_instance->spring.cache_stiffness = stiffness; } if (elapsed >= transition_instance->spring.est_duration) interpolated_number = in; else interpolated_number = spring_oscillate ( damping, mass, stiffness, last_in, in, elapsed, &transition_instance->spring.velocity); } break; case TRANSITION_EASE: { if (elapsed >= transition->ease.seconds) interpolated_number = in; else { progress = bge_easing_ease (transition->ease.easing, elapsed / transition->ease.seconds); interpolated_number = last_in + progress * (in - last_in); } } break; default: g_assert_not_reached (); } transition_instance->value = interpolated_number; return interpolated_number; } static double expression_adjust_track_transition (BgeWdgtRenderer *this, double in, double damping_ratio, double mass, double stiffness, double notifier, TrackTransitionClosureData *data) { guint idx = 0; gboolean registered = FALSE; double damping = 0.0; g_assert (data->value->type == G_TYPE_DOUBLE); registered = g_ptr_array_find (this->track_transitions, data, &idx); if (!registered) g_ptr_array_add (this->track_transitions, track_transition_closure_data_ref (data)); damping = damping_ratio * (/* critical damping */ 2 * sqrt (mass * stiffness)); if (!registered || data->target != in || damping_ratio != data->spring.cache_damping_ratio || mass != data->spring.cache_mass || stiffness != data->spring.cache_stiffness) { data->target = in; data->last = data->current; data->elapsed = 0.0; g_timer_start (data->timer); data->spring.est_duration = spring_calculate_duration ( damping, mass, stiffness, data->last, data->target, FALSE); data->spring.cache_damping_ratio = damping_ratio; data->spring.cache_mass = mass; data->spring.cache_stiffness = stiffness; } else data->elapsed = g_timer_elapsed (data->timer, NULL); if (data->elapsed >= data->spring.est_duration) { data->current = data->target; data->last = data->target; } else data->current = spring_oscillate ( damping, mass, stiffness, data->last, data->target, data->elapsed, &data->spring.velocity); return data->current; } static GskTransform * expression_perform_transform (gpointer this, guint n_param_values, const GValue *param_values, TransformCallFunc func) { return func (g_value_dup_boxed (¶m_values[0]), param_values + 1); } static GtkExpression * ensure_expressions (BgeWdgtRenderer *self, ValueData *value, StateData *state, StateInstanceData *instance) { GtkExpression *cached = NULL; g_autoptr (GtkExpression) expression = NULL; TransitionData *transition = NULL; cached = g_hash_table_lookup (instance->expressions, value); if (cached != NULL) return gtk_expression_ref (cached); switch (value->kind) { case VALUE_CONSTANT: expression = gtk_constant_expression_new_for_value (&value->constant); break; case VALUE_OBJECT: case VALUE_CHILD: { gpointer object = NULL; object = g_hash_table_lookup (self->objects, value); g_assert (object != NULL); expression = gtk_constant_expression_new (value->type, object); } break; case VALUE_REFERENCE_OBJECT: { GtkExpression *notifier_constant = NULL; GtkExpression *notify_expression = NULL; notifier_constant = gtk_constant_expression_new ( BGE_TYPE_WDGT_NOTIFIER, self->reference_notifier); notify_expression = gtk_property_expression_new_for_pspec ( notifier_constant, notifier_props[NOTIFIER_PROP_VALUE]); expression = gtk_cclosure_expression_new ( value->type, bge_marshal_OBJECT__DOUBLE, 1, (GtkExpression *[]){ notify_expression }, G_CALLBACK (expression_get_reference_object), GSIZE_TO_POINTER (value->type), NULL); } break; case VALUE_VARIABLE: case VALUE_ALLOCATION_WIDTH: case VALUE_ALLOCATION_HEIGHT: case VALUE_ALLOCATION_TRANSFORM: case VALUE_MEASURE_MINIMUM_WIDTH: case VALUE_MEASURE_NATURAL_WIDTH: case VALUE_MEASURE_MINIMUM_HEIGHT: case VALUE_MEASURE_NATURAL_HEIGHT: { ValueData *holds = NULL; holds = g_hash_table_lookup (state->setters, value); if (holds == NULL) holds = g_hash_table_lookup (self->spec->init_state->setters, value); if (holds != NULL) expression = ensure_expressions (self, holds, state, instance); else { GValue empty_value = G_VALUE_INIT; g_value_init (&empty_value, value->type); expression = gtk_constant_expression_new_for_value (&empty_value); g_value_unset (&empty_value); } } break; case VALUE_MEASURE_FOR_SIZE: { GtkExpression *notifier_constant = NULL; GtkExpression *notify_expression = NULL; notifier_constant = gtk_constant_expression_new ( BGE_TYPE_WDGT_NOTIFIER, self->measure_for_size_notifier); notify_expression = gtk_property_expression_new_for_pspec ( notifier_constant, notifier_props[NOTIFIER_PROP_VALUE]); expression = gtk_cclosure_expression_new ( value->type, bge_marshal_INT__DOUBLE, 1, (GtkExpression *[]){ notify_expression }, G_CALLBACK (expression_get_measure_for_size), GSIZE_TO_POINTER (value->type), NULL); } break; case VALUE_WIDGET_WIDTH: { GtkExpression *notifier_constant = NULL; GtkExpression *notify_expression = NULL; notifier_constant = gtk_constant_expression_new ( BGE_TYPE_WDGT_NOTIFIER, self->widget_width_notifier); notify_expression = gtk_property_expression_new_for_pspec ( notifier_constant, notifier_props[NOTIFIER_PROP_VALUE]); expression = gtk_cclosure_expression_new ( value->type, bge_marshal_DOUBLE__DOUBLE, 1, (GtkExpression *[]){ notify_expression }, G_CALLBACK (expression_get_widget_width), GSIZE_TO_POINTER (value->type), NULL); } break; case VALUE_WIDGET_HEIGHT: { GtkExpression *notifier_constant = NULL; GtkExpression *notify_expression = NULL; notifier_constant = gtk_constant_expression_new ( BGE_TYPE_WDGT_NOTIFIER, self->widget_height_notifier); notify_expression = gtk_property_expression_new_for_pspec ( notifier_constant, notifier_props[NOTIFIER_PROP_VALUE]); expression = gtk_cclosure_expression_new ( value->type, bge_marshal_DOUBLE__DOUBLE, 1, (GtkExpression *[]){ notify_expression }, G_CALLBACK (expression_get_widget_height), GSIZE_TO_POINTER (value->type), NULL); } break; case VALUE_COERCION: { expression = ensure_expressions ( self, value->coercion.value, state, instance); expression = gtk_cclosure_expression_new ( value->type, _marshal_DIRECT__ARGS_DIRECT, 1, (GtkExpression *[]){ expression }, G_CALLBACK (expression_coerce_type), GSIZE_TO_POINTER (value->type), NULL); } break; case VALUE_TRACK_TRANSITION: { g_autoptr (BgeWdgtNotifier) notifier_object = NULL; GtkExpression *notifier_constant = NULL; GtkExpression *notify_expression = NULL; GtkExpression *damping_ratio_expression = NULL; GtkExpression *mass_expression = NULL; GtkExpression *stiffness_expression = NULL; g_autoptr (TrackTransitionClosureData) closure_data = NULL; notifier_object = g_object_new (BGE_TYPE_WDGT_NOTIFIER, NULL); notifier_constant = gtk_constant_expression_new ( BGE_TYPE_WDGT_NOTIFIER, notifier_object); notify_expression = gtk_property_expression_new_for_pspec ( notifier_constant, notifier_props[NOTIFIER_PROP_VALUE]); damping_ratio_expression = ensure_expressions ( self, value->track_transition.spring.damping_ratio, state, instance); mass_expression = ensure_expressions ( self, value->track_transition.spring.mass, state, instance); stiffness_expression = ensure_expressions ( self, value->track_transition.spring.stiffness, state, instance); closure_data = track_transition_closure_data_new (); closure_data->value = value_data_ref (value); closure_data->timer = g_timer_new (); closure_data->notifier = g_object_ref (notifier_object); expression = ensure_expressions ( self, value->track_transition.src, state, instance); expression = gtk_cclosure_expression_new ( value->type, bge_marshal_DOUBLE__DOUBLE_DOUBLE_DOUBLE_DOUBLE_DOUBLE, 5, (GtkExpression *[]){ expression, damping_ratio_expression, mass_expression, stiffness_expression, notify_expression }, G_CALLBACK (expression_adjust_track_transition), track_transition_closure_data_ref (closure_data), track_transition_closure_data_unref_closure); } break; case VALUE_COMPONENT: { g_autoptr (GPtrArray) params = NULL; GClosureMarshal marshal = NULL; GCallback callback = NULL; params = g_ptr_array_new (); for (guint i = 0; i < value->component->len; i++) { ValueData *member = NULL; g_autoptr (GtkExpression) member_expr = NULL; member = g_ptr_array_index (value->component, i); member_expr = ensure_expressions (self, member, state, instance); g_ptr_array_add (params, g_steal_pointer (&member_expr)); } if (value->type == GRAPHENE_TYPE_POINT) { marshal = bge_marshal_BOXED__DOUBLE_DOUBLE; callback = G_CALLBACK (expression_create_point); } else if (value->type == GRAPHENE_TYPE_SIZE) { marshal = bge_marshal_BOXED__DOUBLE_DOUBLE; callback = G_CALLBACK (expression_create_size); } else if (value->type == GRAPHENE_TYPE_POINT3D) { marshal = bge_marshal_BOXED__DOUBLE_DOUBLE_DOUBLE; callback = G_CALLBACK (expression_create_point3d); } else if (value->type == GRAPHENE_TYPE_RECT) { marshal = bge_marshal_BOXED__DOUBLE_DOUBLE_DOUBLE_DOUBLE; callback = G_CALLBACK (expression_create_rect); } else g_assert (FALSE); expression = gtk_cclosure_expression_new ( value->type, marshal, params->len, (GtkExpression **) params->pdata, callback, self, NULL); } break; case VALUE_TRANSFORM: { g_autoptr (GPtrArray) params = NULL; g_autoptr (GtkExpression) next_expr = NULL; params = g_ptr_array_new (); next_expr = ensure_expressions (self, value->transform.next, state, instance); g_ptr_array_add (params, g_steal_pointer (&next_expr)); for (guint i = 0; i < value->transform.args->len; i++) { ValueData *arg = NULL; g_autoptr (GtkExpression) arg_expr = NULL; arg = g_ptr_array_index (value->transform.args, i); arg_expr = ensure_expressions (self, arg, state, instance); g_ptr_array_add (params, g_steal_pointer (&arg_expr)); } expression = gtk_cclosure_expression_new ( value->type, _marshal_BOXED__ARGS_DIRECT, params->len, (GtkExpression **) params->pdata, G_CALLBACK (expression_perform_transform), value->transform.func, NULL); } break; case VALUE_CLOSURE: { g_autoptr (GPtrArray) params = NULL; params = g_ptr_array_new (); for (guint i = 0; i < value->closure.args->len; i++) { ValueData *arg = NULL; g_autoptr (GtkExpression) arg_expr = NULL; arg = g_ptr_array_index (value->closure.args, i); arg_expr = ensure_expressions (self, arg, state, instance); g_ptr_array_add (params, g_steal_pointer (&arg_expr)); } expression = gtk_cclosure_expression_new ( value->type, value->closure.marshal, params->len, (GtkExpression **) params->pdata, value->closure.func, value->closure.user_data, NULL); } break; case VALUE_PROPERTY: { g_autoptr (GtkExpression) object_expression = NULL; /* Mark subproperty values as dependencies as well */ object_expression = ensure_expressions ( self, value->property.object, state, instance); expression = gtk_property_expression_new ( value->property.object->type, g_steal_pointer (&object_expression), value->property.prop_name); } break; case VALUE_SPECIAL: g_assert (FALSE); break; default: g_assert_not_reached (); break; } transition = g_hash_table_lookup (state->transitions, value); if (value->type == G_TYPE_DOUBLE && transition != NULL) { g_autoptr (BgeWdgtNotifier) notifier_object = NULL; g_autoptr (TransitionInstanceData) instance_data = NULL; GtkExpression *notifier_constant = NULL; GtkExpression *notify_expression = NULL; g_autoptr (TransitionClosureData) closure_data = NULL; notifier_object = g_object_new (BGE_TYPE_WDGT_NOTIFIER, NULL); instance_data = transition_instance_data_new (); switch (transition->kind) { case TRANSITION_EASE: instance_data->elapsed = transition->ease.seconds; break; case TRANSITION_SPRING: instance_data->spring.est_duration = -1.0; break; default: g_assert_not_reached (); } instance_data->notifier = g_object_ref (notifier_object); g_hash_table_replace (instance->transitions, value_data_ref (value), transition_instance_data_ref (instance_data)); notifier_constant = gtk_constant_expression_new ( BGE_TYPE_WDGT_NOTIFIER, notifier_object); notify_expression = gtk_property_expression_new_for_pspec ( notifier_constant, notifier_props[NOTIFIER_PROP_VALUE]); closure_data = transition_closure_data_new (); closure_data->state = state_data_ref (state); closure_data->instance = state_instance_data_ref (instance); closure_data->value = value_data_ref (value); expression = gtk_cclosure_expression_new ( value->type, bge_marshal_DOUBLE__DOUBLE_DOUBLE, 2, (GtkExpression *[]){ expression, notify_expression }, G_CALLBACK (expression_adjust_state_transition), transition_closure_data_ref (closure_data), transition_closure_data_unref_closure); } g_hash_table_replace ( instance->expressions, value_data_ref (value), gtk_expression_ref (expression)); return gtk_expression_ref (expression); } static void set_value (BgeWdgtRenderer *self, StateData *state, StateInstanceData *instance, ValueData *dest, ValueData *src, GPtrArray *watches) { GtkExpression *src_expression = NULL; GtkExpression *dest_expression = NULL; src_expression = g_hash_table_lookup ( instance->expressions, src); g_assert (src_expression != NULL); dest_expression = g_hash_table_lookup ( instance->expressions, dest); g_assert (dest_expression != NULL); switch (dest->kind) { case VALUE_PROPERTY: { GtkExpression *dest_obj_expression = NULL; GValue dest_obj_resolved = G_VALUE_INIT; GObject *dest_obj = NULL; dest_obj_expression = g_hash_table_lookup ( instance->expressions, dest->property.object); g_assert (dest_obj_expression != NULL); gtk_expression_evaluate ( dest_obj_expression, self, &dest_obj_resolved); dest_obj = g_value_get_object (&dest_obj_resolved); if (dest_obj != NULL) { GValue src_resolved = G_VALUE_INIT; gtk_expression_evaluate ( src_expression, self, &src_resolved); g_object_set_property ( dest_obj, dest->property.prop_name, &src_resolved); g_value_unset (&src_resolved); } g_value_unset (&dest_obj_resolved); } break; case VALUE_ALLOCATION_WIDTH: case VALUE_ALLOCATION_HEIGHT: case VALUE_ALLOCATION_TRANSFORM: { GtkExpression *dest_widget_expression = NULL; GValue dest_widget_resolved = G_VALUE_INIT; GtkWidget *dest_widget = NULL; dest_widget_expression = g_hash_table_lookup ( instance->expressions, dest->allocation.widget); g_assert (dest_widget_expression != NULL); gtk_expression_evaluate ( dest_widget_expression, self, &dest_widget_resolved); dest_widget = g_value_get_object (&dest_widget_resolved); if (dest_widget != NULL) { AllocationData *allocation = NULL; allocation = g_hash_table_lookup (self->allocations, dest_widget); if (allocation != NULL) { switch (dest->kind) { case VALUE_ALLOCATION_WIDTH: g_clear_pointer (&allocation->width, value_data_unref); allocation->width = value_data_ref (src); break; case VALUE_ALLOCATION_HEIGHT: g_clear_pointer (&allocation->height, value_data_unref); allocation->height = value_data_ref (src); break; case VALUE_ALLOCATION_TRANSFORM: g_clear_pointer (&allocation->transform, value_data_unref); allocation->transform = value_data_ref (src); break; case VALUE_CHILD: case VALUE_CLOSURE: case VALUE_COERCION: case VALUE_COMPONENT: case VALUE_CONSTANT: case VALUE_MEASURE_FOR_SIZE: case VALUE_MEASURE_MINIMUM_HEIGHT: case VALUE_MEASURE_MINIMUM_WIDTH: case VALUE_MEASURE_NATURAL_HEIGHT: case VALUE_MEASURE_NATURAL_WIDTH: case VALUE_OBJECT: case VALUE_PROPERTY: case VALUE_REFERENCE_OBJECT: case VALUE_SPECIAL: case VALUE_TRACK_TRANSITION: case VALUE_TRANSFORM: case VALUE_VARIABLE: case VALUE_WIDGET_HEIGHT: case VALUE_WIDGET_WIDTH: default: g_assert_not_reached (); } gtk_widget_queue_allocate (GTK_WIDGET (self)); } } g_value_unset (&dest_widget_resolved); } break; case VALUE_MEASURE_MINIMUM_WIDTH: case VALUE_MEASURE_NATURAL_WIDTH: case VALUE_MEASURE_MINIMUM_HEIGHT: case VALUE_MEASURE_NATURAL_HEIGHT: { GValue src_resolved = G_VALUE_INIT; gtk_expression_evaluate ( src_expression, self, &src_resolved); switch (dest->kind) { case VALUE_MEASURE_MINIMUM_WIDTH: self->measure_minimum_width = g_value_get_int (&src_resolved); break; case VALUE_MEASURE_NATURAL_WIDTH: self->measure_natural_width = g_value_get_int (&src_resolved); break; case VALUE_MEASURE_MINIMUM_HEIGHT: self->measure_minimum_height = g_value_get_int (&src_resolved); break; case VALUE_MEASURE_NATURAL_HEIGHT: self->measure_natural_height = g_value_get_int (&src_resolved); break; case VALUE_ALLOCATION_HEIGHT: case VALUE_ALLOCATION_TRANSFORM: case VALUE_ALLOCATION_WIDTH: case VALUE_CHILD: case VALUE_CLOSURE: case VALUE_COERCION: case VALUE_COMPONENT: case VALUE_CONSTANT: case VALUE_MEASURE_FOR_SIZE: case VALUE_OBJECT: case VALUE_PROPERTY: case VALUE_REFERENCE_OBJECT: case VALUE_SPECIAL: case VALUE_TRACK_TRANSITION: case VALUE_TRANSFORM: case VALUE_VARIABLE: case VALUE_WIDGET_HEIGHT: case VALUE_WIDGET_WIDTH: default: g_assert_not_reached (); } g_value_unset (&src_resolved); gtk_widget_queue_resize (GTK_WIDGET (self)); } break; case VALUE_CHILD: case VALUE_CLOSURE: case VALUE_COERCION: case VALUE_COMPONENT: case VALUE_CONSTANT: case VALUE_MEASURE_FOR_SIZE: case VALUE_OBJECT: case VALUE_REFERENCE_OBJECT: case VALUE_SPECIAL: case VALUE_TRACK_TRANSITION: case VALUE_TRANSFORM: case VALUE_VARIABLE: case VALUE_WIDGET_HEIGHT: case VALUE_WIDGET_WIDTH: break; default: g_assert_not_reached (); } if (watches != NULL) { g_autoptr (WatchSetterData) watch_data = NULL; GtkExpressionWatch *watch = NULL; watch_data = watch_setter_data_new (); watch_data->self = self; watch_data->state = state_data_ref (state); watch_data->instance = state_instance_data_ref (instance); watch_data->dest = value_data_ref (dest); watch_data->src = value_data_ref (src); watch = gtk_expression_watch ( src_expression, self, (GtkExpressionNotify) reset_setter, watch_setter_data_ref (watch_data), watch_setter_data_unref); g_ptr_array_add (watches, watch); } } static int resolve_value_int (BgeWdgtRenderer *self, ValueData *value, StateInstanceData *instance) { GtkExpression *expression = NULL; GValue resolved = G_VALUE_INIT; int ret = 0.0; expression = g_hash_table_lookup (instance->expressions, value); g_assert (expression != NULL); gtk_expression_evaluate ( expression, self, &resolved); ret = g_value_get_int (&resolved); g_value_unset (&resolved); return ret; } static double resolve_value_double (BgeWdgtRenderer *self, ValueData *value, StateInstanceData *instance) { GtkExpression *expression = NULL; GValue resolved = G_VALUE_INIT; double ret = 0.0; expression = g_hash_table_lookup (instance->expressions, value); g_assert (expression != NULL); gtk_expression_evaluate ( expression, self, &resolved); ret = g_value_get_double (&resolved); g_value_unset (&resolved); return ret; } static gpointer resolve_value_boxed_dup (BgeWdgtRenderer *self, ValueData *value, StateInstanceData *instance) { GtkExpression *expression = NULL; GValue resolved = G_VALUE_INIT; gpointer ret = NULL; expression = g_hash_table_lookup (instance->expressions, value); g_assert (expression != NULL); gtk_expression_evaluate ( expression, self, &resolved); ret = g_value_dup_boxed (&resolved); g_value_unset (&resolved); return ret; } static gpointer resolve_value_object_dup (BgeWdgtRenderer *self, ValueData *value, StateInstanceData *instance) { GtkExpression *expression = NULL; GValue resolved = G_VALUE_INIT; gpointer ret = NULL; expression = g_hash_table_lookup (instance->expressions, value); g_assert (expression != NULL); gtk_expression_evaluate ( expression, self, &resolved); ret = g_value_dup_object (&resolved); g_value_unset (&resolved); return ret; } static void discard_binding (gpointer ptr) { GBinding *binding = ptr; g_binding_unbind (binding); g_object_unref (binding); } static void discard_watch (gpointer ptr) { GtkExpressionWatch *watch = ptr; /* unrefs for us */ gtk_expression_watch_unwatch (watch); } static void prop_change_queue_draw (BgeWdgtRenderer *self) { gtk_widget_queue_draw (GTK_WIDGET (self)); } static void reset_setter (WatchSetterData *data) { BgeWdgtRenderer *self = data->self; /* Active state watchers are "overlayed" over the permanent init state. Thus, if this is the init state and the active state also sets this value, we should avoid touching it */ if (self->active_state != NULL /* ? */ && data->state == self->spec->init_state && g_hash_table_contains ( self->active_state->setters, data->dest)) return; set_value ( data->self, data->state, data->instance, data->dest, data->src, NULL); } static void _marshal_DIRECT__ARGS_DIRECT (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef void (*GMarshalFunc_DIRECT__ARGS_DIRECT) (gpointer data1, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer data2); GCClosure *cc = (GCClosure *) closure; gpointer data1, data2; GMarshalFunc_DIRECT__ARGS_DIRECT callback; g_return_if_fail (return_value != NULL); g_return_if_fail (n_param_values >= 1); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_DIRECT__ARGS_DIRECT) (marshal_data ? marshal_data : cc->callback); callback (data1, return_value, n_param_values - 1, param_values + 1, data2); } static void _marshal_BOXED__ARGS_DIRECT (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef gpointer (*GMarshalFunc_BOXED__ARGS_DIRECT) (gpointer data1, guint n_param_values, const GValue *param_values, gpointer data2); GCClosure *cc = (GCClosure *) closure; gpointer data1, data2; GMarshalFunc_BOXED__ARGS_DIRECT callback; gpointer v_return; g_return_if_fail (return_value != NULL); g_return_if_fail (n_param_values >= 1); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_BOXED__ARGS_DIRECT) (marshal_data ? marshal_data : cc->callback); v_return = callback (data1, n_param_values - 1, param_values + 1, data2); g_value_take_boxed (return_value, v_return); } /* End of bge-wdgt-spec.c */ bazaar-orig-v0.7.14/bge/wdgt/bge-wdgt-time.h0000664000175000017500000000253715166123241017456 0ustar hasanhasan/* bge-wdgt-time.h * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #ifndef BGE_INSIDE #error "Only can be included directly." #endif G_BEGIN_DECLS #define BGE_TYPE_WDGT_TIME (bge_wdgt_time_get_type ()) G_DECLARE_FINAL_TYPE (BgeWdgtTime, bge_wdgt_time, BGE, WDGT_TIME, GObject) BGE_AVAILABLE_IN_ALL BgeWdgtTime * bge_wdgt_time_new (void); BGE_AVAILABLE_IN_ALL double bge_wdgt_time_get_time (BgeWdgtTime *self); BGE_AVAILABLE_IN_ALL guint bge_wdgt_time_get_notify_msec (BgeWdgtTime *self); BGE_AVAILABLE_IN_ALL void bge_wdgt_time_set_notify_msec (BgeWdgtTime *self, guint notify_msec); G_END_DECLS /* End of bge-wdgt-time.h */ bazaar-orig-v0.7.14/bge/wdgt/bge-wdgt-spec-private.h0000664000175000017500000002164615166123241021124 0ustar hasanhasan/* bge-wdgt-spec-private.h * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include "bge.h" G_BEGIN_DECLS typedef enum { BGE_WDGT_SPECIAL_VALUE_MOTION_X, BGE_WDGT_SPECIAL_VALUE_MOTION_Y, } BgeWdgtSpecialValue; typedef enum { BGE_WDGT_SNAPSHOT_INSTR_APPEND = 0, BGE_WDGT_SNAPSHOT_INSTR_PUSH, BGE_WDGT_SNAPSHOT_INSTR_POP, BGE_WDGT_SNAPSHOT_INSTR_SAVE, BGE_WDGT_SNAPSHOT_INSTR_TRANSFORM, BGE_WDGT_SNAPSHOT_INSTR_RESTORE, BGE_WDGT_SNAPSHOT_INSTR_SNAPSHOT_CHILD, } BgeWdgtSnapshotInstrKind; typedef enum { BGE_WDGT_MEASURE_MINIMUM_WIDTH, BGE_WDGT_MEASURE_NATURAL_WIDTH, BGE_WDGT_MEASURE_MINIMUM_HEIGHT, BGE_WDGT_MEASURE_NATURAL_HEIGHT, } BgeWdgtMeasureKind; gboolean bge_wdgt_spec_add_constant_source_value (BgeWdgtSpec *self, const char *name, const GValue *constant, GError **error); gboolean bge_wdgt_spec_add_component_source_value (BgeWdgtSpec *self, const char *name, GType type, const char *const *components, guint n_components, GError **error); gboolean bge_wdgt_spec_add_transform_source_value (BgeWdgtSpec *self, const char *name, const char *next, const char *instruction, const char *const *args, guint n_args, GError **error); gboolean bge_wdgt_spec_add_instance_source_value (BgeWdgtSpec *self, const char *name, GType type, GError **error); gboolean bge_wdgt_spec_add_child_source_value (BgeWdgtSpec *self, const char *name, GType type, const char *parent_widget, const char *builder_type, const char *const *css_classes, guint n_css_classes, GError **error); gboolean bge_wdgt_spec_add_cclosure_source_value (BgeWdgtSpec *self, const char *name, GType type, GClosureMarshal marshal, GCallback func, const char *const *args, const GType *arg_types, guint n_args, gpointer user_data, GDestroyNotify destroy_user_data, GError **error); gboolean bge_wdgt_spec_add_measure_for_size_source_value (BgeWdgtSpec *self, const char *name, GError **error); gboolean bge_wdgt_spec_add_widget_width_source_value (BgeWdgtSpec *self, const char *name, GError **error); gboolean bge_wdgt_spec_add_widget_height_source_value (BgeWdgtSpec *self, const char *name, GError **error); gboolean bge_wdgt_spec_add_track_transition_source_value (BgeWdgtSpec *self, const char *name, const char *src, const char *damping_ratio, const char *mass, const char *stiffness, GError **error); gboolean bge_wdgt_spec_add_special_source_value (BgeWdgtSpec *self, const char *name, BgeWdgtSpecialValue kind, GError **error); gboolean bge_wdgt_spec_add_variable_value (BgeWdgtSpec *self, GType type, const char *name, GError **error); gboolean bge_wdgt_spec_add_reference_object_value (BgeWdgtSpec *self, GType type, const char *name, GError **error); gboolean bge_wdgt_spec_add_property_value (BgeWdgtSpec *self, const char *name, const char *object, const char *property, GType *type_out, GError **error); gboolean bge_wdgt_spec_add_allocation_width_value (BgeWdgtSpec *self, const char *name, const char *child, GError **error); gboolean bge_wdgt_spec_add_allocation_height_value (BgeWdgtSpec *self, const char *name, const char *child, GError **error); gboolean bge_wdgt_spec_add_allocation_transform_value (BgeWdgtSpec *self, const char *name, const char *child, GError **error); gboolean bge_wdgt_spec_add_measure_value (BgeWdgtSpec *self, const char *name, BgeWdgtMeasureKind kind, GError **error); gboolean bge_wdgt_spec_add_state (BgeWdgtSpec *self, const char *name, gboolean default_state, GError **error); gboolean bge_wdgt_spec_set_value (BgeWdgtSpec *self, const char *state, const char *dest_value, const char *src_value, GError **error); gboolean bge_wdgt_spec_transition_value (BgeWdgtSpec *self, const char *state, const char *value, double seconds, BgeEasing easing, GError **error); gboolean bge_wdgt_spec_transition_value_spring (BgeWdgtSpec *self, const char *state, const char *value, const char *damping_ratio, const char *mass, const char *stiffness, GError **error); gboolean bge_wdgt_spec_append_snapshot_instr (BgeWdgtSpec *self, const char *state, BgeWdgtSnapshotInstrKind kind, const char *instr, const char *const *args, guint n_args, GError **error); G_END_DECLS /* End of bge-wdgt-spec-private.h */ bazaar-orig-v0.7.14/bge/wdgt/bge-easing.c0000664000175000017500000003775715166123241017032 0ustar hasanhasan/* TAKEN FROM LIBADWAITA */ /* * Copyright (C) 2021 Manuel Genovés * Copyright (C) 2021 Purism SPC * * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "bge.h" G_DEFINE_ENUM_TYPE ( BgeEasing, bge_easing, G_DEFINE_ENUM_VALUE (BGE_LINEAR, "linear"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_QUAD, "in-quad"), G_DEFINE_ENUM_VALUE (BGE_EASE_OUT_QUAD, "out-quad"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_OUT_QUAD, "in-out-quad"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_CUBIC, "in-cubic"), G_DEFINE_ENUM_VALUE (BGE_EASE_OUT_CUBIC, "out-cubic"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_OUT_CUBIC, "in-out-cubic"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_QUART, "in-quart"), G_DEFINE_ENUM_VALUE (BGE_EASE_OUT_QUART, "out-quart"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_OUT_QUART, "in-out-quart"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_QUINT, "in-quint"), G_DEFINE_ENUM_VALUE (BGE_EASE_OUT_QUINT, "out-quint"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_OUT_QUINT, "in-out-quint"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_SINE, "in-sine"), G_DEFINE_ENUM_VALUE (BGE_EASE_OUT_SINE, "out-sine"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_OUT_SINE, "in-out-sine"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_EXPO, "in-expo"), G_DEFINE_ENUM_VALUE (BGE_EASE_OUT_EXPO, "out-expo"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_OUT_EXPO, "in-out-expo"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_CIRC, "in-circ"), G_DEFINE_ENUM_VALUE (BGE_EASE_OUT_CIRC, "out-circ"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_OUT_CIRC, "in-out-circ"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_ELASTIC, "in-elastic"), G_DEFINE_ENUM_VALUE (BGE_EASE_OUT_ELASTIC, "out-elastic"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_OUT_ELASTIC, "in-out-elastic"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_BACK, "in-back"), G_DEFINE_ENUM_VALUE (BGE_EASE_OUT_BACK, "out-back"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_OUT_BACK, "in-out-back"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_BOUNCE, "in-bounce"), G_DEFINE_ENUM_VALUE (BGE_EASE_OUT_BOUNCE, "out-bounce"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_OUT_BOUNCE, "in-out-bounce"), G_DEFINE_ENUM_VALUE (BGE_EASE, "ease"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN, "ease-in"), G_DEFINE_ENUM_VALUE (BGE_EASE_OUT, "ease-out"), G_DEFINE_ENUM_VALUE (BGE_EASE_IN_OUT, "ease-in-out")); #include /* * Copied from: * https://gitlab.gnome.org/GNOME/clutter/-/blob/a236494ea7f31848b4a459dad41330f225137832/clutter/clutter-easing.c * https://gitlab.gnome.org/GNOME/clutter/-/blob/a236494ea7f31848b4a459dad41330f225137832/clutter/clutter-enums.h * * Copyright (C) 2011 Intel Corporation */ /** * BgeEasing: * @BGE_LINEAR: Linear tweening. * @BGE_EASE_IN_QUAD: Quadratic tweening. * @BGE_EASE_OUT_QUAD: Quadratic tweening, inverse of * [enum@Bge.Easing.ease-in-quad]. * @BGE_EASE_IN_OUT_QUAD: Quadratic tweening, combining * [enum@Bge.Easing.ease-in-quad] and [enum@Bge.Easing.ease-out-quad]. * @BGE_EASE_IN_CUBIC: Cubic tweening. * @BGE_EASE_OUT_CUBIC: Cubic tweening, inverse of * [enum@Bge.Easing.ease-in-cubic]. * @BGE_EASE_IN_OUT_CUBIC: Cubic tweening, combining * [enum@Bge.Easing.ease-in-cubic] and [enum@Bge.Easing.ease-out-cubic]. * @BGE_EASE_IN_QUART: Quartic tweening. * @BGE_EASE_OUT_QUART: Quartic tweening, inverse of * [enum@Bge.Easing.ease-in-quart]. * @BGE_EASE_IN_OUT_QUART: Quartic tweening, combining * [enum@Bge.Easing.ease-in-quart] and [enum@Bge.Easing.ease-out-quart]. * @BGE_EASE_IN_QUINT: Quintic tweening. * @BGE_EASE_OUT_QUINT: Quintic tweening, inverse of * [enum@Bge.Easing.ease-in-quint]. * @BGE_EASE_IN_OUT_QUINT: Quintic tweening, combining * [enum@Bge.Easing.ease-in-quint] and [enum@Bge.Easing.ease-out-quint]. * @BGE_EASE_IN_SINE: Sine wave tweening. * @BGE_EASE_OUT_SINE: Sine wave tweening, inverse of * [enum@Bge.Easing.ease-in-sine]. * @BGE_EASE_IN_OUT_SINE: Sine wave tweening, combining * [enum@Bge.Easing.ease-in-sine] and [enum@Bge.Easing.ease-out-sine]. * @BGE_EASE_IN_EXPO: Exponential tweening. * @BGE_EASE_OUT_EXPO: Exponential tweening, inverse of * [enum@Bge.Easing.ease-in-expo]. * @BGE_EASE_IN_OUT_EXPO: Exponential tweening, combining * [enum@Bge.Easing.ease-in-expo] and [enum@Bge.Easing.ease-out-expo]. * @BGE_EASE_IN_CIRC: Circular tweening. * @BGE_EASE_OUT_CIRC: Circular tweening, inverse of * [enum@Bge.Easing.ease-in-circ]. * @BGE_EASE_IN_OUT_CIRC: Circular tweening, combining * [enum@Bge.Easing.ease-in-circ] and [enum@Bge.Easing.ease-out-circ]. * @BGE_EASE_IN_ELASTIC: Elastic tweening, with offshoot on start. * @BGE_EASE_OUT_ELASTIC: Elastic tweening, with offshoot on end, inverse of * [enum@Bge.Easing.ease-in-elastic]. * @BGE_EASE_IN_OUT_ELASTIC: Elastic tweening, with offshoot on both ends, * combining [enum@Bge.Easing.ease-in-elastic] and * [enum@Bge.Easing.ease-out-elastic]. * @BGE_EASE_IN_BACK: Overshooting cubic tweening, with backtracking on start. * @BGE_EASE_OUT_BACK: Overshooting cubic tweening, with backtracking on end, * inverse of [enum@Bge.Easing.ease-in-back]. * @BGE_EASE_IN_OUT_BACK: Overshooting cubic tweening, with backtracking on both * ends, combining [enum@Bge.Easing.ease-in-back] and * [enum@Bge.Easing.ease-out-back]. * @BGE_EASE_IN_BOUNCE: Exponentially decaying parabolic (bounce) tweening, * on start. * @BGE_EASE_OUT_BOUNCE: Exponentially decaying parabolic (bounce) tweening, * with bounce on end, inverse of [enum@Bge.Easing.ease-in-bounce]. * @BGE_EASE_IN_OUT_BOUNCE: Exponentially decaying parabolic (bounce) tweening, * with bounce on both ends, combining [enum@Bge.Easing.ease-in-bounce] and * [enum@Bge.Easing.ease-out-bounce]. * * Describes the available easing functions for use with * [class@TimedAnimation]. * * New values may be added to this enumeration over time. */ /** * BGE_EASE: * * Cubic bezier tweening, with control points in (0.25, 0.1) and (0.25, 1.0). * * Increases in velocity towards the middle of the animation, slowing back down * at the end. * * Since: 1.7 */ /** * BGE_EASE_IN: * * Cubic bezier tweening, with control points in (0.42, 0.0) and (1.0, 1.0). * * Starts off slowly, with the speed of the animation increasing until complete. * * Since: 1.7 */ /** * BGE_EASE_OUT: * * Cubic bezier tweening, with control points in (0.0, 0.0) and (0.58, 1.0). * * Starts quickly, slowing down the animation until complete. * * Since: 1.7 */ /** * BGE_EASE_IN_OUT: * * Cubic bezier tweening, with control points in (0.42, 0.0) and (0.58, 1.0). * * Starts off slowly, speeds up in the middle, and then slows down again. * * Since: 1.7 */ static inline double linear (double t, double d) { return t / d; } static inline double ease_in_quad (double t, double d) { double p = t / d; return p * p; } static inline double ease_out_quad (double t, double d) { double p = t / d; return -1.0 * p * (p - 2); } static inline double ease_in_out_quad (double t, double d) { double p = t / (d / 2); if (p < 1) return 0.5 * p * p; p -= 1; return -0.5 * (p * (p - 2) - 1); } static inline double ease_in_cubic (double t, double d) { double p = t / d; return p * p * p; } static inline double ease_out_cubic (double t, double d) { double p = t / d - 1; return p * p * p + 1; } static inline double ease_in_out_cubic (double t, double d) { double p = t / (d / 2); if (p < 1) return 0.5 * p * p * p; p -= 2; return 0.5 * (p * p * p + 2); } static inline double ease_in_quart (double t, double d) { double p = t / d; return p * p * p * p; } static inline double ease_out_quart (double t, double d) { double p = t / d - 1; return -1.0 * (p * p * p * p - 1); } static inline double ease_in_out_quart (double t, double d) { double p = t / (d / 2); if (p < 1) return 0.5 * p * p * p * p; p -= 2; return -0.5 * (p * p * p * p - 2); } static inline double ease_in_quint (double t, double d) { double p = t / d; return p * p * p * p * p; } static inline double ease_out_quint (double t, double d) { double p = t / d - 1; return p * p * p * p * p + 1; } static inline double ease_in_out_quint (double t, double d) { double p = t / (d / 2); if (p < 1) return 0.5 * p * p * p * p * p; p -= 2; return 0.5 * (p * p * p * p * p + 2); } static inline double ease_in_sine (double t, double d) { return -1.0 * cos (t / d * G_PI_2) + 1.0; } static inline double ease_out_sine (double t, double d) { return sin (t / d * G_PI_2); } static inline double ease_in_out_sine (double t, double d) { return -0.5 * (cos (G_PI * t / d) - 1); } static inline double ease_in_expo (double t, double d) { return G_APPROX_VALUE (t, 0, DBL_EPSILON) ? 0.0 : pow (2, 10 * (t / d - 1)); } static double ease_out_expo (double t, double d) { return G_APPROX_VALUE (t, d, DBL_EPSILON) ? 1.0 : -pow (2, -10 * t / d) + 1; } static inline double ease_in_out_expo (double t, double d) { double p; if (G_APPROX_VALUE (t, 0, DBL_EPSILON)) return 0.0; if (G_APPROX_VALUE (t, d, DBL_EPSILON)) return 1.0; p = t / (d / 2); if (p < 1) return 0.5 * pow (2, 10 * (p - 1)); p -= 1; return 0.5 * (-pow (2, -10 * p) + 2); } static inline double ease_in_circ (double t, double d) { double p = t / d; return -1.0 * (sqrt (1 - p * p) - 1); } static inline double ease_out_circ (double t, double d) { double p = t / d - 1; return sqrt (1 - p * p); } static inline double ease_in_out_circ (double t, double d) { double p = t / (d / 2); if (p < 1) return -0.5 * (sqrt (1 - p * p) - 1); p -= 2; return 0.5 * (sqrt (1 - p * p) + 1); } static inline double ease_in_elastic (double t, double d) { double p = d * .3; double s = p / 4; double q = t / d; if (G_APPROX_VALUE (q, 1, DBL_EPSILON)) return 1.0; q -= 1; return -(pow (2, 10 * q) * sin ((q * d - s) * (2 * G_PI) / p)); } static inline double ease_out_elastic (double t, double d) { double p = d * .3; double s = p / 4; double q = t / d; if (G_APPROX_VALUE (q, 1, DBL_EPSILON)) return 1.0; return pow (2, -10 * q) * sin ((q * d - s) * (2 * G_PI) / p) + 1.0; } static inline double ease_in_out_elastic (double t, double d) { double p = d * (.3 * 1.5); double s = p / 4; double q = t / (d / 2); if (G_APPROX_VALUE (q, 2, DBL_EPSILON)) return 1.0; if (q < 1) { q -= 1; return -.5 * (pow (2, 10 * q) * sin ((q * d - s) * (2 * G_PI) / p)); } else { q -= 1; return pow (2, -10 * q) * sin ((q * d - s) * (2 * G_PI) / p) * .5 + 1.0; } } static inline double ease_in_back (double t, double d) { double p = t / d; return p * p * ((1.70158 + 1) * p - 1.70158); } static inline double ease_out_back (double t, double d) { double p = t / d - 1; return p * p * ((1.70158 + 1) * p + 1.70158) + 1; } static inline double ease_in_out_back (double t, double d) { double p = t / (d / 2); double s = 1.70158 * 1.525; if (p < 1) return 0.5 * (p * p * ((s + 1) * p - s)); p -= 2; return 0.5 * (p * p * ((s + 1) * p + s) + 2); } static inline double ease_out_bounce (double t, double d) { double p = t / d; if (p < (1 / 2.75)) { return 7.5625 * p * p; } else if (p < (2 / 2.75)) { p -= (1.5 / 2.75); return 7.5625 * p * p + .75; } else if (p < (2.5 / 2.75)) { p -= (2.25 / 2.75); return 7.5625 * p * p + .9375; } else { p -= (2.625 / 2.75); return 7.5625 * p * p + .984375; } } static inline double ease_in_bounce (double t, double d) { return 1.0 - ease_out_bounce (d - t, d); } static inline double ease_in_out_bounce (double t, double d) { if (t < d / 2) return ease_in_bounce (t * 2, d) * 0.5; else return ease_out_bounce (t * 2 - d, d) * 0.5 + 1.0 * 0.5; } static inline double x_for_t (double t, double x_1, double x_2) { double omt = 1.0 - t; return 3.0 * omt * omt * t * x_1 + 3.0 * omt * t * t * x_2 + t * t * t; } static inline double y_for_t (double t, double y_1, double y_2) { double omt = 1.0 - t; return 3.0 * omt * omt * t * y_1 + 3.0 * omt * t * t * y_2 + t * t * t; } static inline double t_for_x (double x, double x_1, double x_2) { double min_t = 0, max_t = 1; int i; for (i = 0; i < 30; ++i) { double guess_t = (min_t + max_t) / 2.0; double guess_x = x_for_t (guess_t, x_1, x_2); if (x < guess_x) max_t = guess_t; else min_t = guess_t; } return (min_t + max_t) / 2.0; } static double ease_cubic_bezier (double t, double d, double x_1, double y_1, double x_2, double y_2) { double p = t / d; if (G_APPROX_VALUE (p, 0.0, DBL_EPSILON)) return 0.0; if (G_APPROX_VALUE (p, 1.0, DBL_EPSILON)) return 1.0; return y_for_t (t_for_x (p, x_1, x_2), y_1, y_2); } /** * bge_easing_ease: * @self: an easing value * @value: a value to ease * * Computes easing with @easing for @value. * * @value should generally be in the [0, 1] range. * * Returns: the easing for @value */ double bge_easing_ease (BgeEasing self, double value) { switch (self) { case BGE_LINEAR: return linear (value, 1); case BGE_EASE_IN_QUAD: return ease_in_quad (value, 1); case BGE_EASE_OUT_QUAD: return ease_out_quad (value, 1); case BGE_EASE_IN_OUT_QUAD: return ease_in_out_quad (value, 1); case BGE_EASE_IN_CUBIC: return ease_in_cubic (value, 1); case BGE_EASE_OUT_CUBIC: return ease_out_cubic (value, 1); case BGE_EASE_IN_OUT_CUBIC: return ease_in_out_cubic (value, 1); case BGE_EASE_IN_QUART: return ease_in_quart (value, 1); case BGE_EASE_OUT_QUART: return ease_out_quart (value, 1); case BGE_EASE_IN_OUT_QUART: return ease_in_out_quart (value, 1); case BGE_EASE_IN_QUINT: return ease_in_quint (value, 1); case BGE_EASE_OUT_QUINT: return ease_out_quint (value, 1); case BGE_EASE_IN_OUT_QUINT: return ease_in_out_quint (value, 1); case BGE_EASE_IN_SINE: return ease_in_sine (value, 1); case BGE_EASE_OUT_SINE: return ease_out_sine (value, 1); case BGE_EASE_IN_OUT_SINE: return ease_in_out_sine (value, 1); case BGE_EASE_IN_EXPO: return ease_in_expo (value, 1); case BGE_EASE_OUT_EXPO: return ease_out_expo (value, 1); case BGE_EASE_IN_OUT_EXPO: return ease_in_out_expo (value, 1); case BGE_EASE_IN_CIRC: return ease_in_circ (value, 1); case BGE_EASE_OUT_CIRC: return ease_out_circ (value, 1); case BGE_EASE_IN_OUT_CIRC: return ease_in_out_circ (value, 1); case BGE_EASE_IN_ELASTIC: return ease_in_elastic (value, 1); case BGE_EASE_OUT_ELASTIC: return ease_out_elastic (value, 1); case BGE_EASE_IN_OUT_ELASTIC: return ease_in_out_elastic (value, 1); case BGE_EASE_IN_BACK: return ease_in_back (value, 1); case BGE_EASE_OUT_BACK: return ease_out_back (value, 1); case BGE_EASE_IN_OUT_BACK: return ease_in_out_back (value, 1); case BGE_EASE_IN_BOUNCE: return ease_in_bounce (value, 1); case BGE_EASE_OUT_BOUNCE: return ease_out_bounce (value, 1); case BGE_EASE_IN_OUT_BOUNCE: return ease_in_out_bounce (value, 1); case BGE_EASE: return ease_cubic_bezier (value, 1, 0.25, 0.1, 0.25, 1.0); case BGE_EASE_IN: return ease_cubic_bezier (value, 1, 0.42, 0.0, 1.0, 1.0); case BGE_EASE_OUT: return ease_cubic_bezier (value, 1, 0.0, 0.0, 0.58, 1.0); case BGE_EASE_IN_OUT: return ease_cubic_bezier (value, 1, 0.42, 0.0, 0.58, 1.0); default: g_assert_not_reached (); } } bazaar-orig-v0.7.14/bge/wdgt/bge-wdgt-renderer.h0000664000175000017500000000464115166123241020324 0ustar hasanhasan/* bge-wdgt-renderer.h * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #ifndef BGE_INSIDE #error "Only can be included directly." #endif #include "bge-wdgt-spec.h" G_BEGIN_DECLS #define BGE_TYPE_WDGT_RENDERER (bge_wdgt_renderer_get_type ()) G_DECLARE_FINAL_TYPE (BgeWdgtRenderer, bge_wdgt_renderer, BGE, WDGT_RENDERER, GtkWidget) BGE_AVAILABLE_IN_ALL BgeWdgtRenderer * bge_wdgt_renderer_new (void); BGE_AVAILABLE_IN_ALL BgeWdgtSpec * bge_wdgt_renderer_get_spec (BgeWdgtRenderer *self); BGE_AVAILABLE_IN_ALL const char * bge_wdgt_renderer_get_state (BgeWdgtRenderer *self); BGE_AVAILABLE_IN_ALL GObject * bge_wdgt_renderer_get_reference (BgeWdgtRenderer *self); BGE_AVAILABLE_IN_ALL GtkWidget * bge_wdgt_renderer_get_child (BgeWdgtRenderer *self); BGE_AVAILABLE_IN_ALL void bge_wdgt_renderer_set_spec (BgeWdgtRenderer *self, BgeWdgtSpec *spec); BGE_AVAILABLE_IN_ALL void bge_wdgt_renderer_set_state (BgeWdgtRenderer *self, const char *state); BGE_AVAILABLE_IN_ALL void bge_wdgt_renderer_set_reference (BgeWdgtRenderer *self, GObject *reference); BGE_AVAILABLE_IN_ALL void bge_wdgt_renderer_set_child (BgeWdgtRenderer *self, GtkWidget *child); BGE_AVAILABLE_IN_ALL void bge_wdgt_renderer_set_state_take (BgeWdgtRenderer *self, char *state); #define bge_wdgt_renderer_set_state_take_printf(self, ...) bge_wdgt_renderer_set_state_take (self, g_strdup_printf (__VA_ARGS__)) BGE_AVAILABLE_IN_ALL gpointer bge_wdgt_renderer_lookup_object (BgeWdgtRenderer *self, const char *name); G_END_DECLS /* End of bge-wdgt-renderer.h */ bazaar-orig-v0.7.14/bge/wdgt/bge-easing.h0000664000175000017500000000236115166123241017016 0ustar hasanhasan/* TAKEN FROM LIBADWAITA */ /* * Copyright (C) 2021 Manuel Genovés * Copyright (C) 2021 Purism SPC * * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #ifndef BGE_INSIDE #error "Only can be included directly." #endif G_BEGIN_DECLS typedef enum { BGE_LINEAR, BGE_EASE_IN_QUAD, BGE_EASE_OUT_QUAD, BGE_EASE_IN_OUT_QUAD, BGE_EASE_IN_CUBIC, BGE_EASE_OUT_CUBIC, BGE_EASE_IN_OUT_CUBIC, BGE_EASE_IN_QUART, BGE_EASE_OUT_QUART, BGE_EASE_IN_OUT_QUART, BGE_EASE_IN_QUINT, BGE_EASE_OUT_QUINT, BGE_EASE_IN_OUT_QUINT, BGE_EASE_IN_SINE, BGE_EASE_OUT_SINE, BGE_EASE_IN_OUT_SINE, BGE_EASE_IN_EXPO, BGE_EASE_OUT_EXPO, BGE_EASE_IN_OUT_EXPO, BGE_EASE_IN_CIRC, BGE_EASE_OUT_CIRC, BGE_EASE_IN_OUT_CIRC, BGE_EASE_IN_ELASTIC, BGE_EASE_OUT_ELASTIC, BGE_EASE_IN_OUT_ELASTIC, BGE_EASE_IN_BACK, BGE_EASE_OUT_BACK, BGE_EASE_IN_OUT_BACK, BGE_EASE_IN_BOUNCE, BGE_EASE_OUT_BOUNCE, BGE_EASE_IN_OUT_BOUNCE, BGE_EASE, BGE_EASE_IN, BGE_EASE_OUT, BGE_EASE_IN_OUT } BgeEasing; GType bge_easing_get_type (void); #define BGE_TYPE_EASING (bge_easing_get_type ()) BGE_AVAILABLE_IN_ALL double bge_easing_ease (BgeEasing self, double value); G_END_DECLS bazaar-orig-v0.7.14/bge/bge.h0000664000175000017500000000223015166123241014600 0ustar hasanhasan/* bge.h - Bazaar GTK Extensions * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include #include G_BEGIN_DECLS #define BGE_INSIDE #include "bge-version-macros.h" #include "bge-animation.h" #include "bge-carousel.h" #include "bge-markdown-render.h" #include "wdgt/bge-easing.h" #include "wdgt/bge-wdgt-renderer.h" #include "wdgt/bge-wdgt-spec.h" #include "wdgt/bge-wdgt-time.h" #undef BGE_INSIDE BGE_AVAILABLE_IN_ALL void bge_init (void); G_END_DECLS bazaar-orig-v0.7.14/bge/bge-markdown-render.h0000664000175000017500000000276515166123241017712 0ustar hasanhasan/* bge-markdown-render.h * * Copyright 2025 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #ifndef BGE_INSIDE #error "Only can be included directly." #endif G_BEGIN_DECLS #define BGE_TYPE_MARKDOWN_RENDER (bge_markdown_render_get_type ()) G_DECLARE_FINAL_TYPE (BgeMarkdownRender, bge_markdown_render, BGE, MARKDOWN_RENDER, GtkWidget) GtkWidget * bge_markdown_render_new (void); const char * bge_markdown_render_get_markdown (BgeMarkdownRender *self); gboolean bge_markdown_render_get_selectable (BgeMarkdownRender *self); void bge_markdown_render_set_markdown (BgeMarkdownRender *self, const char *markdown); void bge_markdown_render_set_selectable (BgeMarkdownRender *self, gboolean selectable); G_END_DECLS /* End of bge-markdown-render.h */ bazaar-orig-v0.7.14/bge/bge-animation-private.h0000664000175000017500000000314715166123241020235 0ustar hasanhasan/* bge-animation-private.h * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #include /* Copied with modifications from libadwaita */ double spring_oscillate (double damping, double mass, double stiffness, double from, double to, double time, double *velocity); /* Copied with modifications from libadwaita */ double spring_get_first_zero (double damping, double mass, double stiffness, double from, double to); /* Copied with modifications from libadwaita */ double spring_calculate_duration (double damping, double mass, double stiffness, double from, double to, gboolean clamp); bazaar-orig-v0.7.14/bge/bge-carousel.c0000664000175000017500000011305515166123241016416 0ustar hasanhasan/* bge-carousel.c * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ /** * BgeCarousel: * * Arranges widgets into a horizontal carousel */ #define G_LOG_DOMAIN "BGE::CAROUSEL" #include "bge.h" #include "bge-marshalers.h" #include "util.h" #define RAISE_FACTOR 0.025 /* `ratio < 1.0` means it overshoots */ #define ANIMATION_DAMPING_RATIO 1.15 struct _BgeCarousel { GtkWidget parent_instance; GtkEventController *motion; double motion_x; double motion_y; GtkEventController *scroll; gboolean scrolling; int hscroll_start; int hscroll_current; GtkGesture *drag; gboolean dragging; double drag_x; double drag_y; BgeAnimation *animation; gboolean allow_mouse_drag; gboolean allow_overshoot; gboolean allow_scroll_wheel; gboolean allow_raise; GtkSingleSelection *model; GPtrArray *mirror; GPtrArray *widgets; }; G_DEFINE_FINAL_TYPE (BgeCarousel, bge_carousel, GTK_TYPE_WIDGET); enum { PROP_0, PROP_ALLOW_MOUSE_DRAG, PROP_ALLOW_OVERSHOOT, PROP_ALLOW_SCROLL_WHEEL, PROP_ALLOW_RAISE, PROP_MODEL, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; enum { SIGNAL_CREATE_WIDGET, SIGNAL_REMOVE_WIDGET, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL]; BGE_DEFINE_DATA ( carousel_widget, CarouselWidget, { GtkWidget *widget; /* x/y interpreted as pixel units, width/height interpreted as percentages of the widget width/height */ graphene_rect_t rect; graphene_rect_t target; gboolean raised; DexCancellable *cancellable; }, BGE_RELEASE_DATA (widget, gtk_widget_unparent); BGE_RELEASE_DATA (cancellable, dex_unref)) static void items_changed (BgeCarousel *self, guint position, guint removed, guint added, GListModel *model); static void model_selected_changed (BgeCarousel *self, GParamSpec *pspec, GtkSingleSelection *selection); static void move_to_idx (BgeCarousel *self, guint idx, /* damping_ratio <= 0.0 means no animation */ double damping_ratio); static void animate (BgeCarousel *self, const char *key, double value, CarouselWidgetData *data); static void ensure_viewport (BgeCarousel *self, GtkSingleSelection *model, gboolean animate); static void motion_enter (BgeCarousel *self, gdouble x, gdouble y, GtkEventControllerMotion *controller); static void motion_event (BgeCarousel *self, gdouble x, gdouble y, GtkEventControllerMotion *controller); static void motion_leave (BgeCarousel *self, GtkEventControllerMotion *controller); static void update_motion (BgeCarousel *self, gdouble x, gdouble y); static void scroll_begin (BgeCarousel *self, GtkEventControllerScroll *controller); static void scroll_end (BgeCarousel *self, GtkEventControllerScroll *controller); static gboolean scroll (BgeCarousel *self, gdouble dx, gdouble dy, GtkEventControllerScroll *controller); static void drag_begin (BgeCarousel *self, gdouble start_x, gdouble start_y, GtkGestureDrag *gesture); static void drag_end (BgeCarousel *self, gdouble offset_x, gdouble offset_y, GtkGestureDrag *gesture); static void drag_update (BgeCarousel *self, gdouble offset_x, gdouble offset_y, GtkGestureDrag *gesture); static void finish_horizontal_gesture (BgeCarousel *self, int offset_x, int offset_y); static void bge_carousel_dispose (GObject *object) { BgeCarousel *self = BGE_CAROUSEL (object); if (self->model != NULL) { g_signal_handlers_disconnect_by_func (self->model, items_changed, self); g_signal_handlers_disconnect_by_func (self->model, model_selected_changed, self); } g_clear_pointer (&self->animation, g_object_unref); g_clear_pointer (&self->model, g_object_unref); g_clear_pointer (&self->mirror, g_ptr_array_unref); g_clear_pointer (&self->widgets, g_ptr_array_unref); G_OBJECT_CLASS (bge_carousel_parent_class)->dispose (object); } static void bge_carousel_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BgeCarousel *self = BGE_CAROUSEL (object); switch (prop_id) { case PROP_ALLOW_MOUSE_DRAG: g_value_set_boolean (value, bge_carousel_get_allow_mouse_drag (self)); break; case PROP_ALLOW_OVERSHOOT: g_value_set_boolean (value, bge_carousel_get_allow_overshoot (self)); break; case PROP_ALLOW_SCROLL_WHEEL: g_value_set_boolean (value, bge_carousel_get_allow_scroll_wheel (self)); break; case PROP_ALLOW_RAISE: g_value_set_boolean (value, bge_carousel_get_allow_raise (self)); break; case PROP_MODEL: g_value_set_object (value, bge_carousel_get_model (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bge_carousel_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BgeCarousel *self = BGE_CAROUSEL (object); switch (prop_id) { case PROP_ALLOW_MOUSE_DRAG: bge_carousel_set_allow_mouse_drag (self, g_value_get_boolean (value)); break; case PROP_ALLOW_OVERSHOOT: bge_carousel_set_allow_overshoot (self, g_value_get_boolean (value)); break; case PROP_ALLOW_SCROLL_WHEEL: bge_carousel_set_allow_scroll_wheel (self, g_value_get_boolean (value)); break; case PROP_ALLOW_RAISE: bge_carousel_set_allow_raise (self, g_value_get_boolean (value)); break; case PROP_MODEL: bge_carousel_set_model (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bge_carousel_measure (GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline) { BgeCarousel *self = BGE_CAROUSEL (widget); for (guint i = 0; i < self->widgets->len; i++) { CarouselWidgetData *child = NULL; int tmp_minimum = 0; int tmp_natural = 0; int tmp_minimum_baseline = 0; int tmp_natural_baseline = 0; child = g_ptr_array_index (self->widgets, i); gtk_widget_measure ( child->widget, orientation, for_size, &tmp_minimum, &tmp_natural, &tmp_minimum_baseline, &tmp_natural_baseline); if (tmp_minimum > 0 && tmp_minimum > *minimum) *minimum = tmp_minimum; if (tmp_natural > 0 && tmp_natural > *natural) *natural = tmp_natural; if (tmp_minimum_baseline > 0 && tmp_minimum_baseline > *minimum_baseline) *minimum_baseline = tmp_minimum_baseline; if (tmp_natural_baseline > 0 && tmp_natural_baseline > *natural_baseline) *natural_baseline = tmp_natural_baseline; } } static void bge_carousel_size_allocate (GtkWidget *widget, int width, int height, int baseline) { BgeCarousel *self = BGE_CAROUSEL (widget); ensure_viewport (self, self->model, FALSE); for (guint i = 0; i < self->widgets->len; i++) { CarouselWidgetData *child = NULL; g_autoptr (GskTransform) transform = NULL; child = g_ptr_array_index (self->widgets, i); transform = gsk_transform_translate ( gsk_transform_new (), &child->rect.origin); gtk_widget_allocate ( child->widget, child->rect.size.width, child->rect.size.height, baseline, g_steal_pointer (&transform)); } } static void bge_carousel_class_init (BgeCarouselClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bge_carousel_set_property; object_class->get_property = bge_carousel_get_property; object_class->dispose = bge_carousel_dispose; /** * BgeCarousel:allow-mouse-drag: * * Whether to allow dragging with the mouse. */ props[PROP_ALLOW_MOUSE_DRAG] = g_param_spec_boolean ( "allow-mouse-drag", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); /** * BgeCarousel:allow-overshoot: * * Whether to allow overshooting the ends of the carousel with drag/touchpad * input. Once the event completes, the carousel offset value will go back to * that of the start/end widget. Setting this value to FALSE will prevent this * widget from capturing input events which would result in an overshoot. */ props[PROP_ALLOW_OVERSHOOT] = g_param_spec_boolean ( "allow-overshoot", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); /** * BgeCarousel:allow-scroll-wheel: * * Whether to allow moving the carousel contents with the horizontal scroll * wheel. */ props[PROP_ALLOW_SCROLL_WHEEL] = g_param_spec_boolean ( "allow-scroll-wheel", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); /** * BgeCarousel:allow-raise: * * Whether to allow raise animations when motion input events hover over them * carousel widgets. */ props[PROP_ALLOW_RAISE] = g_param_spec_boolean ( "allow-raise", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); /** * BgeCarousel:model: * * The selection model for the carousel contents. */ props[PROP_MODEL] = g_param_spec_object ( "model", NULL, NULL, GTK_TYPE_SINGLE_SELECTION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); /** * BgeCarousel::create-widget: * @carousel: the object that received the signal * @object: a list item object from [property@Bge.Carousel:model] * * Emitted when an object is being bound to the carousel * * Return: a newly allocated widget to add to the carousel */ signals[SIGNAL_CREATE_WIDGET] = g_signal_new ( "create-widget", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, bge_marshal_OBJECT__OBJECT, GTK_TYPE_WIDGET, 1, G_TYPE_OBJECT); g_signal_set_va_marshaller ( signals[SIGNAL_CREATE_WIDGET], G_TYPE_FROM_CLASS (klass), bge_marshal_OBJECT__OBJECTv); /** * BgeCarousel::remove-widget: * @carousel: the object that received the signal * @widget: the widget which was created by [signal@Bge.Carousel::create-widget] * @object: a list item object from [property@Bge.Carousel:model] * * Emitted when an object is being unbound from the carousel */ signals[SIGNAL_REMOVE_WIDGET] = g_signal_new ( "remove-widget", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, bge_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 2, GTK_TYPE_WIDGET, G_TYPE_OBJECT); g_signal_set_va_marshaller ( signals[SIGNAL_REMOVE_WIDGET], G_TYPE_FROM_CLASS (klass), bge_marshal_VOID__OBJECT_OBJECTv); widget_class->measure = bge_carousel_measure; widget_class->size_allocate = bge_carousel_size_allocate; } static void bge_carousel_init (BgeCarousel *self) { self->animation = bge_animation_new (GTK_WIDGET (self)); self->mirror = g_ptr_array_new_with_free_func ( (GDestroyNotify) g_object_unref); self->widgets = g_ptr_array_new_with_free_func ( carousel_widget_data_unref); gtk_widget_set_overflow (GTK_WIDGET (self), GTK_OVERFLOW_HIDDEN); self->motion = gtk_event_controller_motion_new (); g_signal_connect_swapped (self->motion, "enter", G_CALLBACK (motion_enter), self); g_signal_connect_swapped (self->motion, "motion", G_CALLBACK (motion_event), self); g_signal_connect_swapped (self->motion, "leave", G_CALLBACK (motion_leave), self); gtk_widget_add_controller (GTK_WIDGET (self), self->motion); self->scroll = gtk_event_controller_scroll_new ( GTK_EVENT_CONTROLLER_SCROLL_HORIZONTAL | GTK_EVENT_CONTROLLER_SCROLL_KINETIC); g_signal_connect_swapped (self->scroll, "scroll-begin", G_CALLBACK (scroll_begin), self); g_signal_connect_swapped (self->scroll, "scroll-end", G_CALLBACK (scroll_end), self); g_signal_connect_swapped (self->scroll, "scroll", G_CALLBACK (scroll), self); gtk_widget_add_controller (GTK_WIDGET (self), self->scroll); self->drag = gtk_gesture_drag_new (); gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (self->drag), GTK_PHASE_CAPTURE); g_signal_connect_swapped (self->drag, "drag-begin", G_CALLBACK (drag_begin), self); g_signal_connect_swapped (self->drag, "drag-end", G_CALLBACK (drag_end), self); g_signal_connect_swapped (self->drag, "drag-update", G_CALLBACK (drag_update), self); gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (self->drag)); } /** * bge_carousel_new: * * Creates a new `BgeCarousel` object. * * Returns: The newly created `BgeCarousel` object. */ GtkWidget * bge_carousel_new (void) { return g_object_new (BGE_TYPE_CAROUSEL, NULL); } /** * bge_carousel_get_allow_mouse_drag: * @self: a `BgeCarousel` * * Gets [property@Bge.Carousel:allow-mouse-drag]. * * Returns: the value of the property */ gboolean bge_carousel_get_allow_mouse_drag (BgeCarousel *self) { g_return_val_if_fail (BGE_IS_CAROUSEL (self), FALSE); return self->allow_mouse_drag; } /** * bge_carousel_get_allow_overshoot: * @self: a `BgeCarousel` * * Gets [property@Bge.Carousel:allow-overshoot]. * * Returns: the value of the property */ gboolean bge_carousel_get_allow_overshoot (BgeCarousel *self) { g_return_val_if_fail (BGE_IS_CAROUSEL (self), FALSE); return self->allow_overshoot; } /** * bge_carousel_get_allow_scroll_wheel: * @self: a `BgeCarousel` * * Gets [property@Bge.Carousel:allow-scroll-wheel]. * * Returns: the value of the property */ gboolean bge_carousel_get_allow_scroll_wheel (BgeCarousel *self) { g_return_val_if_fail (BGE_IS_CAROUSEL (self), FALSE); return self->allow_scroll_wheel; } /** * bge_carousel_get_allow_raise: * @self: a `BgeCarousel` * * Gets [property@Bge.Carousel:allow-raise]. * * Returns: the value of the property */ gboolean bge_carousel_get_allow_raise (BgeCarousel *self) { g_return_val_if_fail (BGE_IS_CAROUSEL (self), FALSE); return self->allow_raise; } /** * bge_carousel_get_model: * @self: a `BgeCarousel` * * Gets [property@Bge.Carousel:model]. * * Returns: (nullable): the value of the property */ GtkSingleSelection * bge_carousel_get_model (BgeCarousel *self) { g_return_val_if_fail (BGE_IS_CAROUSEL (self), NULL); return self->model; } /** * bge_carousel_get_nth_page: * @self: a `BgeCarousel` * @index: Index of the page. * * Returns: (nullable) (transfer none): the page at @index, or NULL if out of bounds */ GtkWidget * bge_carousel_get_nth_page (BgeCarousel *self, guint index) { CarouselWidgetData *data = NULL; g_return_val_if_fail (BGE_IS_CAROUSEL (self), NULL); if (index >= self->widgets->len) return NULL; data = g_ptr_array_index (self->widgets, index); return data->widget; } /** * bge_carousel_set_allow_mouse_drag: * @self: a `BgeCarousel` * @allow_mouse_drag: a boolean * * Sets [property@Bge.Carousel:allow-mouse-drag]. */ void bge_carousel_set_allow_mouse_drag (BgeCarousel *self, gboolean allow_mouse_drag) { g_return_if_fail (BGE_IS_CAROUSEL (self)); if (!!allow_mouse_drag == !!self->allow_mouse_drag) return; self->allow_mouse_drag = allow_mouse_drag; if (!allow_mouse_drag && self->dragging) { self->dragging = FALSE; finish_horizontal_gesture (self, self->drag_x, self->drag_y); self->drag_x = 0.0; self->drag_y = 0.0; } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ALLOW_MOUSE_DRAG]); } /** * bge_carousel_set_allow_overshoot: * @self: a `BgeCarousel` * @allow_overshoot: a boolean * * Sets [property@Bge.Carousel:allow-overshoot]. */ void bge_carousel_set_allow_overshoot (BgeCarousel *self, gboolean allow_overshoot) { g_return_if_fail (BGE_IS_CAROUSEL (self)); if (!!allow_overshoot == !!self->allow_overshoot) return; self->allow_overshoot = allow_overshoot; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ALLOW_OVERSHOOT]); } /** * bge_carousel_set_allow_scroll_wheel: * @self: a `BgeCarousel` * @allow_scroll_wheel: a boolean * * Sets [property@Bge.Carousel:allow-scroll-wheel]. */ void bge_carousel_set_allow_scroll_wheel (BgeCarousel *self, gboolean allow_scroll_wheel) { g_return_if_fail (BGE_IS_CAROUSEL (self)); if (!!allow_scroll_wheel == !!self->allow_scroll_wheel) return; self->allow_scroll_wheel = allow_scroll_wheel; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ALLOW_SCROLL_WHEEL]); } /** * bge_carousel_set_allow_raise: * @self: a `BgeCarousel` * @allow_raise: a boolean * * Sets [property@Bge.Carousel:allow-raise]. */ void bge_carousel_set_allow_raise (BgeCarousel *self, gboolean allow_raise) { g_return_if_fail (BGE_IS_CAROUSEL (self)); if (!!allow_raise == !!self->allow_raise) return; self->allow_raise = allow_raise; if (self->model != NULL) ensure_viewport (self, self->model, TRUE); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ALLOW_RAISE]); } /** * bge_carousel_set_model: * @self: a `BgeCarousel` * @model: a `GtkSingleSelection` object * * Sets [property@Bge.Carousel:model]. */ void bge_carousel_set_model (BgeCarousel *self, GtkSingleSelection *model) { g_return_if_fail (BGE_IS_CAROUSEL (self)); g_return_if_fail (model == NULL || GTK_IS_SINGLE_SELECTION (model)); if (model == self->model) return; if (self->model != NULL) { g_signal_handlers_disconnect_by_func (self->model, items_changed, self); g_signal_handlers_disconnect_by_func (self->model, model_selected_changed, self); items_changed ( self, 0, g_list_model_get_n_items (G_LIST_MODEL (self->model)), 0, G_LIST_MODEL (self->model)); } g_clear_pointer (&self->model, g_object_unref); if (model != NULL) { self->model = g_object_ref (model); items_changed ( self, 0, 0, g_list_model_get_n_items (G_LIST_MODEL (model)), G_LIST_MODEL (model)); g_signal_connect_swapped ( model, "items-changed", G_CALLBACK (items_changed), self); g_signal_connect_swapped ( model, "notify::selected", G_CALLBACK (model_selected_changed), self); } g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MODEL]); } static void items_changed (BgeCarousel *self, guint position, guint removed, guint added, GListModel *model) { for (guint i = 0; i < removed; i++) { GObject *object = NULL; CarouselWidgetData *child = NULL; object = g_ptr_array_index (self->mirror, position + i); child = g_ptr_array_index (self->widgets, position + i); if (child->cancellable != NULL) dex_cancellable_cancel (child->cancellable); g_signal_emit (self, signals[SIGNAL_REMOVE_WIDGET], 0, child->widget, object); } if (removed > 0) { g_ptr_array_remove_range (self->mirror, position, removed); g_ptr_array_remove_range (self->widgets, position, removed); } for (guint i = 0; i < added; i++) { g_autoptr (GObject) object = NULL; GtkWidget *child = NULL; CarouselWidgetData *data = NULL; object = g_list_model_get_item (model, position + i); g_signal_emit (self, signals[SIGNAL_CREATE_WIDGET], 0, object, &child); if (child == NULL) { g_critical ("Failed to populate child for carousel widget"); child = gtk_fixed_new (); } if (position + i == 0) gtk_widget_set_parent (child, GTK_WIDGET (self)); else { CarouselWidgetData *prev = NULL; prev = g_ptr_array_index (self->widgets, position + i - 1); gtk_widget_insert_after (child, GTK_WIDGET (self), prev->widget); } data = carousel_widget_data_new (); data->widget = child; g_ptr_array_insert (self->mirror, position + i, g_object_ref (object)); g_ptr_array_insert (self->widgets, position + i, data); } ensure_viewport (self, GTK_SINGLE_SELECTION (model), FALSE); } static void model_selected_changed (BgeCarousel *self, GParamSpec *pspec, GtkSingleSelection *selection) { guint idx = 0; idx = gtk_single_selection_get_selected (selection); if (idx != G_MAXUINT) move_to_idx (self, idx, ANIMATION_DAMPING_RATIO); gtk_widget_queue_allocate (GTK_WIDGET (self)); } static void move_to_idx (BgeCarousel *self, guint idx, /* damping_ratio <= 0.0 means no animation */ double damping_ratio) { int width = 0; int height = 0; int offset = 0; width = gtk_widget_get_width (GTK_WIDGET (self)); height = gtk_widget_get_height (GTK_WIDGET (self)); if (width == 0 || height == 0) { gtk_widget_queue_allocate (GTK_WIDGET (self)); return; } offset = width / 2; if (self->scrolling) offset += self->hscroll_start - self->hscroll_current; if (self->dragging) offset += self->drag_x; for (guint i = 0; i <= idx; i++) { CarouselWidgetData *child = NULL; int hminimum = 0; int hnatural = 0; int unused = 0; int child_width = 0; child = g_ptr_array_index (self->widgets, i); gtk_widget_measure ( child->widget, GTK_ORIENTATION_HORIZONTAL, height, &hminimum, &hnatural, &unused, &unused); if (gtk_widget_get_hexpand (child->widget)) child_width = MAX (hminimum, width); else child_width = CLAMP (hnatural, hminimum, width); if (i == idx) offset -= child_width / 2; else offset -= child_width; } for (guint i = 0; i < self->widgets->len; i++) { CarouselWidgetData *child = NULL; int hminimum = 0; int hnatural = 0; int unused = 0; int rect_width = 0; int child_width = 0; int child_height = 0; int child_x = 0; int child_y = 0; graphene_rect_t target = { 0 }; gboolean avoid_animation = FALSE; child = g_ptr_array_index (self->widgets, i); gtk_widget_measure ( child->widget, GTK_ORIENTATION_HORIZONTAL, height, &hminimum, &hnatural, &unused, &unused); if (gtk_widget_get_hexpand (child->widget)) rect_width = MAX (hminimum, width); else rect_width = CLAMP (hnatural, hminimum, width); if (child->raised || !self->allow_raise) { child_width = rect_width; child_height = height; child_x = offset; child_y = 0; } else { child_height = round ((double) height * (1.0 - RAISE_FACTOR)); gtk_widget_measure ( child->widget, GTK_ORIENTATION_HORIZONTAL, child_height, &hminimum, &hnatural, &unused, &unused); child_width = CLAMP (hnatural, hminimum, width); child_x = offset + round ((double) (rect_width - child_width) * 0.5); child_y = round ((double) height * (0.5 * RAISE_FACTOR)); } target = GRAPHENE_RECT_INIT (child_x, child_y, child_width, child_height); avoid_animation = graphene_rect_equal (&target, &child->target); if ((damping_ratio < 0.0 && !avoid_animation) || graphene_rect_equal (graphene_rect_zero (), &child->rect)) { if (child->cancellable != NULL) dex_cancellable_cancel (child->cancellable); child->rect = target; child->target = target; } else if (avoid_animation) child->target = target; else { char buf[64] = { 0 }; dex_clear (&child->cancellable); child->cancellable = dex_cancellable_new (); #define MASS 1.0 #define STIFFNESS 800.0 /* pointer is to ensure a unique identifier so as not to overwrite any other child's key */ g_snprintf (buf, sizeof (buf), "x%p", child); dex_future_disown (bge_animation_add_spring ( self->animation, buf, child->rect.origin.x, target.origin.x, damping_ratio, MASS, STIFFNESS, (BgeAnimationCallback) animate, carousel_widget_data_ref (child), carousel_widget_data_unref, child->cancellable)); g_snprintf (buf, sizeof (buf), "y%p", child); dex_future_disown (bge_animation_add_spring ( self->animation, buf, child->rect.origin.y, target.origin.y, damping_ratio, MASS, STIFFNESS, (BgeAnimationCallback) animate, carousel_widget_data_ref (child), carousel_widget_data_unref, child->cancellable)); g_snprintf (buf, sizeof (buf), "w%p", child); dex_future_disown (bge_animation_add_spring ( self->animation, buf, child->rect.size.width, target.size.width, damping_ratio, MASS, STIFFNESS, (BgeAnimationCallback) animate, carousel_widget_data_ref (child), carousel_widget_data_unref, child->cancellable)); g_snprintf (buf, sizeof (buf), "h%p", child); dex_future_disown (bge_animation_add_spring ( self->animation, buf, child->rect.size.height, target.size.height, damping_ratio, MASS, STIFFNESS, (BgeAnimationCallback) animate, carousel_widget_data_ref (child), carousel_widget_data_unref, child->cancellable)); #undef STIFFNESS #undef MASS child->target = target; } offset += rect_width; } gtk_widget_queue_allocate (GTK_WIDGET (self)); } static void animate (BgeCarousel *self, const char *key, double value, CarouselWidgetData *data) { switch (*key) { case 'x': data->rect.origin.x = value; break; case 'y': data->rect.origin.y = value; break; case 'w': data->rect.size.width = value; break; case 'h': data->rect.size.height = value; break; default: g_assert_not_reached (); } gtk_widget_queue_allocate (GTK_WIDGET (self)); } static void ensure_viewport (BgeCarousel *self, GtkSingleSelection *model, gboolean animate) { guint n_items = 0; n_items = g_list_model_get_n_items (G_LIST_MODEL (model)); if (n_items > 0) { guint selected = 0; selected = gtk_single_selection_get_selected (model); if (selected == G_MAXUINT) { gtk_single_selection_set_selected (model, 0); move_to_idx (self, 0, animate ? ANIMATION_DAMPING_RATIO : -1.0); } else move_to_idx (self, selected, animate ? ANIMATION_DAMPING_RATIO : -1.0); } gtk_widget_queue_allocate (GTK_WIDGET (self)); } static void motion_enter (BgeCarousel *self, gdouble x, gdouble y, GtkEventControllerMotion *controller) { self->motion_x = x; self->motion_y = y; update_motion (self, x, y); } static void motion_event (BgeCarousel *self, gdouble x, gdouble y, GtkEventControllerMotion *controller) { self->motion_x = x; self->motion_y = y; update_motion (self, x, y); } static void motion_leave (BgeCarousel *self, GtkEventControllerMotion *controller) { if (self->dragging) return; self->motion_x = -1.0; self->motion_y = -1.0; update_motion (self, -1.0, -1.0); } static void update_motion (BgeCarousel *self, gdouble x, gdouble y) { graphene_point_t point = { 0 }; gboolean ensure = FALSE; point = GRAPHENE_POINT_INIT (x, y); if (self->scrolling) return; for (guint i = 0; i < self->widgets->len; i++) { CarouselWidgetData *child = NULL; gboolean contained = FALSE; child = g_ptr_array_index (self->widgets, i); contained = graphene_rect_contains_point (&child->target, &point); if (!!contained != !!child->raised) { child->raised = contained; ensure = TRUE; } } if (self->dragging) return; if (ensure) ensure_viewport (self, self->model, TRUE); } static void scroll_begin (BgeCarousel *self, GtkEventControllerScroll *controller) { self->scrolling = TRUE; self->hscroll_start = self->motion_x; self->hscroll_current = self->motion_x; } static void scroll_end (BgeCarousel *self, GtkEventControllerScroll *controller) { self->scrolling = FALSE; finish_horizontal_gesture ( self, self->hscroll_start - self->hscroll_current, 0); self->hscroll_start = -1; self->hscroll_current = -1; update_motion (self, self->motion_x, self->motion_y); } static gboolean scroll (BgeCarousel *self, gdouble dx, gdouble dy, GtkEventControllerScroll *controller) { guint n_items = 0; GdkDevice *device = NULL; GdkInputSource source = 0; if (self->model == NULL) { self->scrolling = FALSE; return FALSE; } n_items = g_list_model_get_n_items (G_LIST_MODEL (self->model)); if (n_items == 0) { self->scrolling = FALSE; return FALSE; } device = gtk_event_controller_get_current_event_device ( GTK_EVENT_CONTROLLER (controller)); source = gdk_device_get_source (device); switch (source) { case GDK_SOURCE_TOUCHPAD: case GDK_SOURCE_TRACKPOINT: { if (self->widgets->len > 0 && !self->allow_overshoot) { guint selection = 0; selection = gtk_single_selection_get_selected (self->model); if ((selection == 0 && self->hscroll_current + dx < 0) || (selection == self->widgets->len - 1 && self->hscroll_current + dx > 0)) { self->scrolling = FALSE; return FALSE; } } self->hscroll_current += dx; ensure_viewport (self, self->model, FALSE); } break; case GDK_SOURCE_MOUSE: case GDK_SOURCE_PEN: case GDK_SOURCE_KEYBOARD: case GDK_SOURCE_TOUCHSCREEN: case GDK_SOURCE_TABLET_PAD: default: { guint selected = 0; guint new_selected = 0; if (!self->allow_scroll_wheel) break; selected = gtk_single_selection_get_selected (self->model); if (dx > 0) new_selected = MIN (selected + 1, n_items - 1); else { if (selected == 0) new_selected = 0; else new_selected = selected - 1; } gtk_single_selection_set_selected (self->model, new_selected); } break; } return TRUE; } static void drag_begin (BgeCarousel *self, gdouble start_x, gdouble start_y, GtkGestureDrag *gesture) { if (!self->allow_mouse_drag) return; self->dragging = TRUE; if (self->model == NULL) return; ensure_viewport (self, self->model, TRUE); } static void drag_end (BgeCarousel *self, gdouble offset_x, gdouble offset_y, GtkGestureDrag *gesture) { if (!self->dragging) /* This situation will happen if the `allow-mouse-drag` prop is set to FALSE while a drag is taking place */ return; self->dragging = FALSE; finish_horizontal_gesture (self, self->drag_x, self->drag_y); self->drag_x = 0.0; self->drag_y = 0.0; if (offset_x < -3 || offset_x > 3 || offset_y < -3 || offset_y > 3) gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED); } static void drag_update (BgeCarousel *self, gdouble offset_x, gdouble offset_y, GtkGestureDrag *gesture) { if (!self->dragging) return; self->drag_x = offset_x; self->drag_y = offset_y; if (self->model == NULL) return; if (self->widgets->len > 0 && !self->allow_overshoot) { guint selected = 0; selected = gtk_single_selection_get_selected (self->model); if (selected == 0) self->drag_x = MIN (self->drag_x, 0.0); if (selected == self->widgets->len - 1) self->drag_x = MAX (self->drag_x, 0.0); } ensure_viewport (self, self->model, FALSE); } static void finish_horizontal_gesture (BgeCarousel *self, int offset_x, int offset_y) { guint selected = 0; double width = 0.0; guint new_selected = G_MAXUINT; int min_distance = G_MAXINT; if (self->model == NULL || self->widgets->len == 0) return; if (offset_x == 0) return; selected = gtk_single_selection_get_selected (self->model); width = gtk_widget_get_width (GTK_WIDGET (self)); for (guint i = 0; i < self->widgets->len; i++) { CarouselWidgetData *child = NULL; int left_distance = 0; int right_distance = 0; int distance_from_center = 0; child = g_ptr_array_index (self->widgets, i); if (child->rect.origin.x > width / 2.0) left_distance = child->rect.origin.x - width / 2.0; else left_distance = width / 2.0 - child->rect.origin.x; if ((child->rect.origin.x + child->rect.size.width) > width / 2.0) right_distance = (child->rect.origin.x + child->rect.size.width) - width / 2.0; else right_distance = width / 2.0 - (child->rect.origin.x + child->rect.size.width); distance_from_center = MIN (left_distance, right_distance); if (distance_from_center < min_distance) { new_selected = i; min_distance = distance_from_center; } } if (new_selected == selected) { /* Ensure dragging is not too stiff; meaning if we drag the content at least 15 pixels in either direction, it will automatically snap to the next widget */ if (offset_x > 15 && selected > 0) new_selected--; else if (offset_x < -15 && selected < self->widgets->len - 1) new_selected++; } if (new_selected == G_MAXUINT || new_selected == selected) ensure_viewport (self, self->model, TRUE); else gtk_single_selection_set_selected (self->model, new_selected); } /* End of bge-carousel.c */ bazaar-orig-v0.7.14/bge/bge-marshalers.list0000664000175000017500000000325415166123241017472 0ustar hasanhasan# see glib-genmarshal(1) for a detailed description of the file format, # possible parameter types are: # VOID indicates no return type, or no extra # parameters. if VOID is used as the parameter # list, no additional parameters may be present. # BOOLEAN for boolean types (gboolean) # CHAR for signed char types (char) # UCHAR for unsigned char types (guchar) # INT for signed integer types (int) # UINT for unsigned integer types (guint) # LONG for signed long integer types (glong) # ULONG for unsigned long integer types (gulong) # INT64 for signed 64bit integer types (gint64) # UINT64 for unsigned 64bit integer types (guint64) # ENUM for enumeration types (int) # FLAGS for flag enumeration types (guint) # FLOAT for single-precision float types (float) # DOUBLE for double-precision float types (double) # STRING for string types (char *) # BOXED for boxed (anonymous but reference counted) types (GBoxed*) # PARAM for GParamSpec or derived types (GParamSpec*) # POINTER for anonymous pointer types (gpointer) # OBJECT for GObject or derived types (GObject*) # VARIANT for GVariant types (GVariant*) # NONE deprecated alias for VOID # BOOL deprecated alias for BOOLEAN OBJECT:OBJECT VOID:OBJECT,OBJECT # for wdgt stuff # graphene types DOUBLE:DOUBLE DOUBLE:DOUBLE,DOUBLE DOUBLE:DOUBLE,DOUBLE,DOUBLE DOUBLE:DOUBLE,DOUBLE,DOUBLE,DOUBLE DOUBLE:DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE BOXED:DOUBLE,DOUBLE BOXED:DOUBLE,DOUBLE,DOUBLE BOXED:DOUBLE,DOUBLE,DOUBLE,DOUBLE INT:DOUBLE OBJECT:DOUBLE bazaar-orig-v0.7.14/bge/bge-version-macros.h0000664000175000017500000000462015166123241017552 0ustar hasanhasan/* bge-version-macros.h * * Copyright 2026 Eva M * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include #include "bge-version.h" #ifndef _BGE_EXTERN #define _BGE_EXTERN extern #endif #define BGE_VERSION_CUR_STABLE (G_ENCODE_VERSION (BGE_MAJOR_VERSION, 0)) #ifdef BGE_DISABLE_DEPRECATION_WARNINGS #define BGE_DEPRECATED _BGE_EXTERN #define BGE_DEPRECATED_FOR(f) _BGE_EXTERN #define BGE_UNAVAILABLE(maj, min) _BGE_EXTERN #else #define BGE_DEPRECATED G_DEPRECATED _BGE_EXTERN #define BGE_DEPRECATED_FOR(f) G_DEPRECATED_FOR (f) _BGE_EXTERN #define BGE_UNAVAILABLE(maj, min) G_UNAVAILABLE (maj, min) _BGE_EXTERN #endif #define BGE_VERSION_1_0 (G_ENCODE_VERSION (1, 0)) #if BGE_MAJOR_VERSION == BGE_VERSION_1_0 #define BGE_VERSION_PREV_STABLE (BGE_VERSION_1_0) #else #define BGE_VERSION_PREV_STABLE (G_ENCODE_VERSION (BGE_MAJOR_VERSION - 1, 0)) #endif #ifndef BGE_VERSION_MIN_REQUIRED #define BGE_VERSION_MIN_REQUIRED (BGE_VERSION_CUR_STABLE) #endif #ifndef BGE_VERSION_MAX_ALLOWED #if BGE_VERSION_MIN_REQUIRED > BGE_VERSION_PREV_STABLE #define BGE_VERSION_MAX_ALLOWED (BGE_VERSION_MIN_REQUIRED) #else #define BGE_VERSION_MAX_ALLOWED (BGE_VERSION_CUR_STABLE) #endif #endif #define BGE_AVAILABLE_IN_ALL _BGE_EXTERN #if BGE_VERSION_MIN_REQUIRED >= BGE_VERSION_1_0 #define BGE_DEPRECATED_IN_1_0 BGE_DEPRECATED #define BGE_DEPRECATED_IN_1_0_FOR(f) BGE_DEPRECATED_FOR (f) #else #define BGE_DEPRECATED_IN_1_0 _BGE_EXTERN #define BGE_DEPRECATED_IN_1_0_FOR(f) _BGE_EXTERN #endif #if BGE_VERSION_MAX_ALLOWED < BGE_VERSION_1_0 #define BGE_AVAILABLE_IN_1_0 BGE_UNAVAILABLE (1, 0) #else #define BGE_AVAILABLE_IN_1_0 _BGE_EXTERN #endif bazaar-orig-v0.7.14/bge/bge-carousel.h0000664000175000017500000000445115166123241016422 0ustar hasanhasan/* bge-carousel.h * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #ifndef BGE_INSIDE #error "Only can be included directly." #endif G_BEGIN_DECLS #define BGE_TYPE_CAROUSEL (bge_carousel_get_type ()) G_DECLARE_FINAL_TYPE (BgeCarousel, bge_carousel, BGE, CAROUSEL, GtkWidget) BGE_AVAILABLE_IN_ALL GtkWidget * bge_carousel_new (void); BGE_AVAILABLE_IN_ALL gboolean bge_carousel_get_allow_mouse_drag (BgeCarousel *self); BGE_AVAILABLE_IN_ALL gboolean bge_carousel_get_allow_overshoot (BgeCarousel *self); BGE_AVAILABLE_IN_ALL gboolean bge_carousel_get_allow_scroll_wheel (BgeCarousel *self); BGE_AVAILABLE_IN_ALL gboolean bge_carousel_get_allow_raise (BgeCarousel *self); BGE_AVAILABLE_IN_ALL GtkSingleSelection * bge_carousel_get_model (BgeCarousel *self); BGE_AVAILABLE_IN_ALL GtkWidget * bge_carousel_get_nth_page (BgeCarousel *self, guint index); BGE_AVAILABLE_IN_ALL void bge_carousel_set_allow_mouse_drag (BgeCarousel *self, gboolean allow_mouse_drag); BGE_AVAILABLE_IN_ALL void bge_carousel_set_allow_overshoot (BgeCarousel *self, gboolean allow_overshoot); BGE_AVAILABLE_IN_ALL void bge_carousel_set_allow_scroll_wheel (BgeCarousel *self, gboolean allow_scroll_wheel); BGE_AVAILABLE_IN_ALL void bge_carousel_set_allow_raise (BgeCarousel *self, gboolean allow_raise); BGE_AVAILABLE_IN_ALL void bge_carousel_set_model (BgeCarousel *self, GtkSingleSelection *model); G_END_DECLS /* End of bge-carousel.h */ bazaar-orig-v0.7.14/bge/util.h0000664000175000017500000000765215166123241015035 0ustar hasanhasan/* util.h * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #define BGE_RELEASE_DATA(name, unref) \ if ((unref) != NULL) \ { \ g_clear_pointer (&self->name, (unref)); \ } #define BGE_RELEASE_UTAG(name, remove) \ if ((remove) != NULL) \ { \ g_clear_handle_id (&self->name, (remove)); \ } /* va args = releases */ #define BGE_DEFINE_DATA(name, Name, layout, ...) \ typedef struct _##Name##Data Name##Data; \ struct _##Name##Data \ { \ gatomicrefcount rc; \ struct layout; \ }; \ G_GNUC_UNUSED \ static inline Name##Data * \ name##_data_new (void) \ { \ Name##Data *data = NULL; \ data = g_new0 (typeof (*data), 1); \ g_atomic_ref_count_init (&data->rc); \ return data; \ } \ G_GNUC_UNUSED \ static inline Name##Data * \ name##_data_ref (gpointer ptr) \ { \ Name##Data *self = ptr; \ g_atomic_ref_count_inc (&self->rc); \ return self; \ } \ G_GNUC_UNUSED \ static void \ name##_data_unref (gpointer ptr); \ G_GNUC_UNUSED \ static void \ name##_data_deinit (gpointer ptr) \ { \ Name##Data *self = ptr; \ __VA_ARGS__ \ } \ G_GNUC_UNUSED \ static void \ name##_data_unref (gpointer ptr) \ { \ Name##Data *self = ptr; \ if (g_atomic_ref_count_dec (&self->rc)) \ { \ name##_data_deinit (self); \ g_free (self); \ } \ } \ G_GNUC_UNUSED \ static void \ name##_data_unref_closure (gpointer data, \ GClosure *closure) \ { \ name##_data_unref (data); \ } \ G_DEFINE_AUTOPTR_CLEANUP_FUNC (Name##Data, name##_data_unref); bazaar-orig-v0.7.14/bge/bge-version.h.in0000664000175000017500000000475715166123241016710 0ustar hasanhasan/* bge-version.h.in * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #if !defined(BGE_INSIDE) && !defined(BGE_COMPILATION) # error "Only can be included directly." #endif /** * SECTION:bgeversion * @short_description: bge version checking * * bge provides macros to check the version of the library * at compile-time */ /** * BGE_MAJOR_VERSION: * * bge major version component (e.g. 1 if %BGE_VERSION is 1.2.3) */ #define BGE_MAJOR_VERSION (@MAJOR_VERSION@) /** * BGE_MINOR_VERSION: * * bge minor version component (e.g. 2 if %BGE_VERSION is 1.2.3) */ #define BGE_MINOR_VERSION (@MINOR_VERSION@) /** * BGE_MICRO_VERSION: * * bge micro version component (e.g. 3 if %BGE_VERSION is 1.2.3) */ #define BGE_MICRO_VERSION (@MICRO_VERSION@) /** * BGE_VERSION * * bge version. */ #define BGE_VERSION (@VERSION@) /** * BGE_VERSION_S: * * bge version, encoded as a string, useful for printing and * concatenation. */ #define BGE_VERSION_S "@VERSION@" #define BGE_ENCODE_VERSION(major,minor,micro) \ ((major) << 24 | (minor) << 16 | (micro) << 8) /** * BGE_VERSION_HEX: * * bge version, encoded as an hexadecimal number, useful for * integer comparisons. */ #define BGE_VERSION_HEX \ (BGE_ENCODE_VERSION (BGE_MAJOR_VERSION, BGE_MINOR_VERSION, BGE_MICRO_VERSION)) /** * BGE_CHECK_VERSION: * @major: required major version * @minor: required minor version * @micro: required micro version * * Compile-time version checking. Evaluates to %TRUE if the version * of bge is greater than the required one. */ #define BGE_CHECK_VERSION(major,minor,micro) \ (BGE_MAJOR_VERSION > (major) || \ (BGE_MAJOR_VERSION == (major) && BGE_MINOR_VERSION > (minor)) || \ (BGE_MAJOR_VERSION == (major) && BGE_MINOR_VERSION == (minor) && \ BGE_MICRO_VERSION >= (micro))) bazaar-orig-v0.7.14/bge/bge-animation.h0000664000175000017500000000430515166123241016562 0ustar hasanhasan/* bge-animation.h * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #pragma once #ifndef BGE_INSIDE #error "Only can be included directly." #endif G_BEGIN_DECLS #define BGE_TYPE_ANIMATION (bge_animation_get_type ()) G_DECLARE_FINAL_TYPE (BgeAnimation, bge_animation, BGE, ANIMATION, GObject) typedef void (*BgeAnimationCallback) (GtkWidget *widget, const char *key, double value, gpointer user_data); BGE_AVAILABLE_IN_ALL BgeAnimation * bge_animation_new (GtkWidget *widget); BGE_AVAILABLE_IN_ALL GtkWidget * bge_animation_dup_widget (BgeAnimation *self); BGE_AVAILABLE_IN_ALL G_GNUC_WARN_UNUSED_RESULT DexFuture * bge_animation_add_spring (BgeAnimation *self, const char *key, double from, double to, double damping_ratio, double mass, double stiffness, BgeAnimationCallback cb, gpointer user_data, GDestroyNotify destroy_data, DexCancellable *cancellable); BGE_AVAILABLE_IN_ALL void bge_animation_cancel (BgeAnimation *self, const char *key); BGE_AVAILABLE_IN_ALL void bge_animation_cancel_all (BgeAnimation *self); G_END_DECLS bazaar-orig-v0.7.14/bge/demo/0000775000175000017500000000000015166123241014621 5ustar hasanhasanbazaar-orig-v0.7.14/bge/demo/test.wdgt0000664000175000017500000000346515166123241016477 0ustar hasanhasandefwidget "My Widget" { reference ref-string : "GtkStringObject"; var t : "BgeWdgtTime"; var box : "GtkBox"; var cx : "gdouble"; var cy : "gdouble"; var w : "gdouble"; var h : "gdouble"; var corner : "gdouble"; var x : "gdouble"; var y : "gdouble"; init { set t = #(notify-msec = 10;); set box = #child/(""("gradient") orientation = vertical; _=#child/GtkLabel(""() margin-start = 10; margin-end = 10; margin-top = 10; margin-bottom = 10; label = ref-string:string; wrap = true; ); ); measure 200, 300, 200, 300; set x = #eval(#(cx)-#(w)/2.0); set y = #eval(#(cy)-#(h)/2.0); allocate box w, h, #(translate(#GraphenePoint(x, y));); snapshot { with rounded-clip( #GrapheneRect(x, y, w, h), #GrapheneSize(corner, corner), #GrapheneSize(corner, corner), #GrapheneSize(corner, corner), #GrapheneSize(corner, corner), ) { do-child box; } } } state-default "1" { set w = 100.0; set h = 100.0; set corner = 10.0; set cx = #eval(30.0*sin(#(t:time)) + #(%width%)/2.0); set cy = #eval(#(%height%)/2.0); transition-spring w 1.0, 0.5, 100.0; transition-spring h 1.0, 0.5, 100.0; transition-spring corner 1.0, 0.5, 100.0; transition-spring cx 1.0, 0.5, 100.0; transition-spring cy 1.0, 0.5, 100.0; } state "2" { set w = 200.0; set h = 200.0; set corner = 20.0; set cx = #eval(#(%width%)/2.0); set cy = #eval(#(%height%)/2.0); transition-spring w 0.9, 0.5, 100.0; transition-spring h 0.9, 0.5, 100.0; transition-spring corner 0.9, 0.5, 100.0; transition-spring cx 0.9, 0.5, 100.0; transition-spring cy 0.9, 0.5, 100.0; } } bazaar-orig-v0.7.14/bge/demo/meson.build0000664000175000017500000000104315166123241016761 0ustar hasanhasandemo_sources = files( 'demo.c', ) blueprints = custom_target( 'blueprints', input: files( 'window.blp', ), output: '.', command: [ find_program('blueprint-compiler', version: '>= 0.18.0'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@' ], ) demo_sources += gnome.compile_resources('demo-resources', 'demo.gresource.xml', c_name: 'demo', dependencies: blueprints ) demo_deps = [ bge_dep, ] demo = executable( 'bge-demo', demo_sources, dependencies: demo_deps, install: true, ) bazaar-orig-v0.7.14/bge/demo/demo.gresource.xml0000664000175000017500000000032415166123241020263 0ustar hasanhasan window.ui style.css test.wdgt bazaar-orig-v0.7.14/bge/demo/style.css0000664000175000017500000000032515166123241016473 0ustar hasanhasan.source-edit { font-family: monospace; font-size: large; } .debug { background-color: pink; } .gradient { background-image: linear-gradient(to bottom left, #1f2d8f, #159eff); color: white; } bazaar-orig-v0.7.14/bge/demo/demo.c0000664000175000017500000000754315166123241015722 0ustar hasanhasan/* demo.c * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #include static void on_activate (GtkApplication *app); static void on_buffer_changed (GtkTextBuffer *buffer, BgeWdgtRenderer *wdgt); int main (int argc, char **argv) { g_autoptr (GtkApplication) app = NULL; g_autoptr (GtkCssProvider) provider = NULL; bge_init (); app = gtk_application_new ( "io.github.kolunmi.BgeDemo", G_APPLICATION_NON_UNIQUE); g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); provider = gtk_css_provider_new (); gtk_css_provider_load_from_resource (provider, "/io/github/kolunmi/BgeDemo/style.css"); gtk_style_context_add_provider_for_display ( gdk_display_get_default (), GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); return g_application_run (G_APPLICATION (app), argc, argv); } static void on_activate (GtkApplication *app) { GtkWidget *window = NULL; GtkWidget *root = NULL; GtkTextBuffer *buffer = NULL; BgeWdgtRenderer *wdgt = NULL; g_autoptr (GtkStringObject) reference = NULL; g_autoptr (GtkBuilder) builder = NULL; g_autoptr (GtkBuilderScope) scope = NULL; g_autoptr (GBytes) wdgt_bytes = NULL; gsize wdgt_buffer_size = 0; gconstpointer wdgt_buffer = NULL; window = gtk_application_window_new (app); gtk_window_set_default_size (GTK_WINDOW (window), 1000, 500); scope = gtk_builder_cscope_new (); builder = gtk_builder_new (); gtk_builder_set_scope (builder, scope); gtk_builder_add_from_resource (builder, "/io/github/kolunmi/BgeDemo/window.ui", NULL); root = GTK_WIDGET (gtk_builder_get_object (builder, "root")); buffer = GTK_TEXT_BUFFER (gtk_builder_get_object (builder, "buffer")); wdgt = BGE_WDGT_RENDERER (gtk_builder_get_object (builder, "wdgt")); reference = gtk_string_object_new ("Hello from demo.c!!"); bge_wdgt_renderer_set_reference (wdgt, G_OBJECT (reference)); g_signal_connect ( buffer, "changed", G_CALLBACK (on_buffer_changed), wdgt); wdgt_bytes = g_resources_lookup_data ( "/io/github/kolunmi/BgeDemo/test.wdgt", G_RESOURCE_LOOKUP_FLAGS_NONE, NULL); g_assert (wdgt_bytes != NULL); wdgt_buffer = g_bytes_get_data (wdgt_bytes, &wdgt_buffer_size); gtk_text_buffer_set_text (buffer, wdgt_buffer, wdgt_buffer_size); gtk_window_set_child (GTK_WINDOW (window), g_object_ref_sink (root)); gtk_window_present (GTK_WINDOW (window)); } static void on_buffer_changed (GtkTextBuffer *buffer, BgeWdgtRenderer *wdgt) { g_autoptr (GError) local_error = NULL; g_autofree char *text = NULL; GtkTextIter start_iter = { 0 }; GtkTextIter end_iter = { 0 }; g_autoptr (BgeWdgtSpec) spec = NULL; gtk_text_buffer_get_start_iter (buffer, &start_iter); gtk_text_buffer_get_end_iter (buffer, &end_iter); text = gtk_text_buffer_get_text (buffer, &start_iter, &end_iter, FALSE); spec = bge_wdgt_spec_new_for_string (text, &local_error); if (spec == NULL) g_print ("Error!! %s\n", local_error->message); bge_wdgt_renderer_set_spec (wdgt, spec); } bazaar-orig-v0.7.14/bge/demo/window.blp0000664000175000017500000000107515166123241016632 0ustar hasanhasanusing Gtk 4.0; Box root { Paned { position: 400; start-child: ScrolledWindow { child: TextView { styles ["source-edit"] monospace: true; buffer: TextBuffer buffer { }; }; }; end-child: Box { orientation: vertical; $BgeWdgtRenderer wdgt { styles ["debug"] halign: center; valign: center; hexpand: true; vexpand: true; state: bind state_entry.text; } Entry state_entry { text: "1"; } }; shrink-end-child: false; } } bazaar-orig-v0.7.14/bge/libbge.c0000664000175000017500000000221115166123241015261 0ustar hasanhasan/* libbge.c * * Copyright 2025 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BGE::CORE" #include "bge.h" /** * bge_init: * * Initializes BGE (And GTK). * * This function must be called before using any other BGE functions. */ void bge_init (void) { gtk_init (); g_type_ensure (BGE_TYPE_ANIMATION); g_type_ensure (BGE_TYPE_CAROUSEL); g_type_ensure (BGE_TYPE_MARKDOWN_RENDER); g_type_ensure (BGE_TYPE_WDGT_TIME); g_type_ensure (BGE_TYPE_WDGT_RENDERER); } bazaar-orig-v0.7.14/bge/bge-markdown-render.c0000664000175000017500000005113415166123241017677 0ustar hasanhasan/* bge-markdown-render.c * * Copyright 2025 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "BGE::MARKDOWN-RENDER" #include #include "bge.h" #include "util.h" struct _BgeMarkdownRender { GtkWidget parent_instance; char *markdown; gboolean selectable; GtkTextView *text_view; }; G_DEFINE_FINAL_TYPE (BgeMarkdownRender, bge_markdown_render, GTK_TYPE_WIDGET); enum { PROP_0, PROP_MARKDOWN, PROP_SELECTABLE, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; static void regenerate (BgeMarkdownRender *self); BGE_DEFINE_DATA ( tag, Tag, { GtkTextTag *tag; int start; int end; }, BGE_RELEASE_DATA (tag, g_object_unref)); #define INIT_TAG_DATA_LOCATION(_loc, _buffer, ...) \ G_STMT_START \ { \ *(_loc) = tag_data_new (); \ g_object_get ((_buffer), "cursor-position", &(*(_loc))->start, NULL); \ (*(_loc))->end = -1; \ (*(_loc))->tag = gtk_text_buffer_create_tag ( \ (_buffer), NULL, \ "accumulative-margin", TRUE, \ ##__VA_ARGS__, NULL); \ } \ G_STMT_END typedef struct { GtkTextBuffer *buffer; char *beginning; GArray *block_stack; GArray *list_index_stack; GArray *list_prefix_stack; GPtrArray *tags; int indent; int running_list_index; } ParseCtx; static int enter_block (MD_BLOCKTYPE type, void *detail, void *user_data); static int leave_block (MD_BLOCKTYPE type, void *detail, void *user_data); static int enter_span (MD_SPANTYPE type, void *detail, void *user_data); static int leave_span (MD_SPANTYPE type, void *detail, void *user_data); static int text (MD_TEXTTYPE type, const MD_CHAR *buf, MD_SIZE size, void *user_data); static const MD_PARSER parser = { .flags = MD_FLAG_COLLAPSEWHITESPACE | MD_FLAG_NOHTMLBLOCKS | MD_FLAG_NOHTMLSPANS, .enter_block = enter_block, .leave_block = leave_block, .enter_span = enter_span, .leave_span = leave_span, .text = text, }; static void bge_markdown_render_dispose (GObject *object) { BgeMarkdownRender *self = BGE_MARKDOWN_RENDER (object); g_clear_pointer (&self->markdown, g_free); gtk_widget_unparent (GTK_WIDGET (self->text_view)); G_OBJECT_CLASS (bge_markdown_render_parent_class)->dispose (object); } static void bge_markdown_render_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BgeMarkdownRender *self = BGE_MARKDOWN_RENDER (object); switch (prop_id) { case PROP_MARKDOWN: g_value_set_string (value, bge_markdown_render_get_markdown (self)); break; case PROP_SELECTABLE: g_value_set_boolean (value, bge_markdown_render_get_selectable (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bge_markdown_render_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BgeMarkdownRender *self = BGE_MARKDOWN_RENDER (object); switch (prop_id) { case PROP_MARKDOWN: bge_markdown_render_set_markdown (self, g_value_get_string (value)); break; case PROP_SELECTABLE: bge_markdown_render_set_selectable (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void bge_markdown_render_measure (GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline) { BgeMarkdownRender *self = BGE_MARKDOWN_RENDER (widget); gtk_widget_measure ( GTK_WIDGET (self->text_view), orientation, for_size, minimum, natural, minimum_baseline, natural_baseline); } static void bge_markdown_render_size_allocate (GtkWidget *widget, int width, int height, int baseline) { BgeMarkdownRender *self = BGE_MARKDOWN_RENDER (widget); gtk_widget_allocate (GTK_WIDGET (self->text_view), width, height, baseline, NULL); } static void bge_markdown_render_class_init (BgeMarkdownRenderClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->set_property = bge_markdown_render_set_property; object_class->get_property = bge_markdown_render_get_property; object_class->dispose = bge_markdown_render_dispose; props[PROP_MARKDOWN] = g_param_spec_string ( "markdown", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); props[PROP_SELECTABLE] = g_param_spec_boolean ( "selectable", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, LAST_PROP, props); widget_class->measure = bge_markdown_render_measure; widget_class->size_allocate = bge_markdown_render_size_allocate; } static void bge_markdown_render_init (BgeMarkdownRender *self) { self->text_view = (GtkTextView *) gtk_text_view_new (); gtk_text_view_set_wrap_mode (self->text_view, GTK_WRAP_WORD_CHAR); gtk_text_view_set_editable (self->text_view, FALSE); gtk_widget_set_parent (GTK_WIDGET (self->text_view), GTK_WIDGET (self)); } GtkWidget * bge_markdown_render_new (void) { return g_object_new (BGE_TYPE_MARKDOWN_RENDER, NULL); } const char * bge_markdown_render_get_markdown (BgeMarkdownRender *self) { g_return_val_if_fail (BGE_IS_MARKDOWN_RENDER (self), NULL); return self->markdown; } gboolean bge_markdown_render_get_selectable (BgeMarkdownRender *self) { g_return_val_if_fail (BGE_IS_MARKDOWN_RENDER (self), FALSE); return self->selectable; } void bge_markdown_render_set_markdown (BgeMarkdownRender *self, const char *markdown) { g_return_if_fail (BGE_IS_MARKDOWN_RENDER (self)); g_clear_pointer (&self->markdown, g_free); if (markdown != NULL) self->markdown = g_strdup (markdown); regenerate (self); g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MARKDOWN]); } void bge_markdown_render_set_selectable (BgeMarkdownRender *self, gboolean selectable) { g_return_if_fail (BGE_IS_MARKDOWN_RENDER (self)); self->selectable = selectable; g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SELECTABLE]); } static void regenerate (BgeMarkdownRender *self) { int iresult = 0; ParseCtx ctx = { 0 }; if (self->markdown == NULL) return; ctx.buffer = gtk_text_buffer_new (NULL); ctx.beginning = self->markdown; ctx.block_stack = g_array_new (FALSE, TRUE, sizeof (int)); ctx.list_index_stack = g_array_new (FALSE, TRUE, sizeof (int)); ctx.list_prefix_stack = g_array_new (FALSE, TRUE, sizeof (MD_CHAR)); ctx.tags = g_ptr_array_new_with_free_func (tag_data_unref); ctx.indent = 0; ctx.running_list_index = -1; iresult = md_parse ( self->markdown, strlen (self->markdown), &parser, &ctx); if (iresult != 0) goto error; for (guint i = 0; i < ctx.tags->len; i++) { TagData *data = NULL; GtkTextIter start_iter = { 0 }; GtkTextIter end_iter = { 0 }; data = g_ptr_array_index (ctx.tags, i); gtk_text_buffer_get_iter_at_offset (ctx.buffer, &start_iter, data->start); gtk_text_buffer_get_iter_at_offset (ctx.buffer, &end_iter, data->end); gtk_text_buffer_apply_tag (ctx.buffer, g_object_ref (data->tag), &start_iter, &end_iter); } gtk_text_view_set_buffer (self->text_view, ctx.buffer); goto done; error: g_warning ("Failed to parse markdown text"); done: g_object_unref (ctx.buffer); g_array_unref (ctx.block_stack); g_array_unref (ctx.list_index_stack); g_array_unref (ctx.list_prefix_stack); g_ptr_array_unref (ctx.tags); } static int enter_block (MD_BLOCKTYPE type, void *detail, void *user_data) { ParseCtx *ctx = user_data; int parent = 0; int list_index = 0; MD_CHAR list_prefix = 0; g_autoptr (TagData) tag = NULL; if (ctx->block_stack->len > 0) parent = g_array_index (ctx->block_stack, int, ctx->block_stack->len - 1); if (ctx->list_index_stack->len > 0) list_index = g_array_index (ctx->list_index_stack, int, ctx->list_index_stack->len - 1); if (ctx->list_prefix_stack->len > 0) list_prefix = g_array_index (ctx->list_prefix_stack, MD_CHAR, ctx->list_prefix_stack->len - 1); switch (type) { case MD_BLOCK_DOC: break; case MD_BLOCK_QUOTE: INIT_TAG_DATA_LOCATION ( &tag, ctx->buffer, "left-margin", 50, "right-margin", 50, "justification", GTK_JUSTIFY_CENTER, "foreground", "gray", "weight", 600, "scale", 1.1, "style", PANGO_STYLE_ITALIC); break; case MD_BLOCK_UL: { MD_BLOCK_UL_DETAIL *ul_detail = detail; const int zero = 0; ctx->indent++; ctx->running_list_index = 0; g_array_append_val (ctx->list_index_stack, zero); g_array_append_val (ctx->list_prefix_stack, ul_detail->mark); INIT_TAG_DATA_LOCATION ( &tag, ctx->buffer, "left-margin", 25); } break; case MD_BLOCK_OL: { MD_BLOCK_OL_DETAIL *ol_detail = detail; const int zero = 0; ctx->indent++; ctx->running_list_index = 0; g_array_append_val (ctx->list_index_stack, zero); g_array_append_val (ctx->list_prefix_stack, ol_detail->mark_delimiter); INIT_TAG_DATA_LOCATION ( &tag, ctx->buffer, "left-margin", 25); } break; case MD_BLOCK_LI: { if (ctx->indent > 1 || list_index > 0) gtk_text_buffer_insert_at_cursor (ctx->buffer, "\n", -1); if (parent == MD_BLOCK_OL) { g_autofree char *prefix_text = NULL; INIT_TAG_DATA_LOCATION ( &tag, ctx->buffer, "indent", -18); prefix_text = g_strdup_printf ("%d%c ", list_index, list_prefix); gtk_text_buffer_insert_at_cursor (ctx->buffer, prefix_text, -1); } else { INIT_TAG_DATA_LOCATION ( &tag, ctx->buffer, "indent", -12); /* TODO: `ctx->list_prefix` is '-', '+', '*' maybe handle these? */ gtk_text_buffer_insert_at_cursor (ctx->buffer, "• ", -1); } } break; case MD_BLOCK_HR: gtk_text_buffer_insert_at_cursor (ctx->buffer, "\n", -1); break; case MD_BLOCK_H: { MD_BLOCK_H_DETAIL *h_detail = detail; gtk_text_buffer_insert_at_cursor (ctx->buffer, "\n", -1); INIT_TAG_DATA_LOCATION ( &tag, ctx->buffer, "scale", MAX (2.2 - 0.2 * (float) h_detail->level, 1.0), "pixels-below-lines", 10); } break; case MD_BLOCK_CODE: INIT_TAG_DATA_LOCATION ( &tag, ctx->buffer, "family", "monospace", "foreground", "gray"); break; case MD_BLOCK_P: if (parent != MD_BLOCK_LI) INIT_TAG_DATA_LOCATION ( &tag, ctx->buffer, "indent", 15, "pixels-below-lines", 4); break; case MD_BLOCK_HTML: case MD_BLOCK_TABLE: case MD_BLOCK_THEAD: case MD_BLOCK_TBODY: case MD_BLOCK_TR: case MD_BLOCK_TH: case MD_BLOCK_TD: default: break; } if (tag != NULL) g_ptr_array_add (ctx->tags, g_steal_pointer (&tag)); g_array_append_val (ctx->block_stack, type); return 0; } static int leave_block (MD_BLOCKTYPE type, void *detail, void *user_data) { ParseCtx *ctx = user_data; int parent = -1; #define TERMINATE_TAG_FROM_SET_PROP(_set_prop) \ for (guint i = ctx->tags->len; i > 0; i--) \ { \ TagData *data = NULL; \ gboolean set = FALSE; \ \ data = g_ptr_array_index (ctx->tags, i - 1); \ if (data->end >= 0) \ continue; \ \ g_object_get (data->tag, (_set_prop), &set, NULL); \ if (set) \ { \ g_object_get ( \ ctx->buffer, \ "cursor-position", &data->end, \ NULL); \ break; \ } \ } g_assert (ctx->block_stack->len > 0); parent = g_array_index (ctx->block_stack, int, ctx->block_stack->len - 1); if (parent >= 0) { switch (type) { case MD_BLOCK_DOC: break; case MD_BLOCK_QUOTE: TERMINATE_TAG_FROM_SET_PROP ("style-set"); gtk_text_buffer_insert_at_cursor (ctx->buffer, "\n\n", -1); break; case MD_BLOCK_UL: { // MD_BLOCK_UL_DETAIL *ul_detail = detail; TERMINATE_TAG_FROM_SET_PROP ("left-margin-set"); ctx->indent--; ctx->running_list_index = -1; g_array_set_size (ctx->list_index_stack, ctx->list_index_stack->len - 1); g_array_set_size (ctx->list_prefix_stack, ctx->list_prefix_stack->len - 1); if (ctx->indent == 0) gtk_text_buffer_insert_at_cursor (ctx->buffer, "\n\n", -1); } break; case MD_BLOCK_OL: { // MD_BLOCK_OL_DETAIL *ol_detail = detail; TERMINATE_TAG_FROM_SET_PROP ("left-margin-set"); ctx->indent--; ctx->running_list_index = -1; g_array_set_size (ctx->list_index_stack, ctx->list_index_stack->len - 1); g_array_set_size (ctx->list_prefix_stack, ctx->list_prefix_stack->len - 1); if (ctx->indent == 0) gtk_text_buffer_insert_at_cursor (ctx->buffer, "\n", -1); } break; case MD_BLOCK_LI: TERMINATE_TAG_FROM_SET_PROP ("indent-set"); ++g_array_index (ctx->list_index_stack, int, ctx->list_index_stack->len - 1); ctx->running_list_index++; break; case MD_BLOCK_HR: break; case MD_BLOCK_H: TERMINATE_TAG_FROM_SET_PROP ("scale-set"); gtk_text_buffer_insert_at_cursor (ctx->buffer, "\n", -1); break; case MD_BLOCK_CODE: TERMINATE_TAG_FROM_SET_PROP ("family-set"); gtk_text_buffer_insert_at_cursor (ctx->buffer, "\n", -1); break; case MD_BLOCK_P: if (parent != MD_BLOCK_LI) TERMINATE_TAG_FROM_SET_PROP ("indent-set"); if (ctx->running_list_index < 0) gtk_text_buffer_insert_at_cursor (ctx->buffer, "\n\n", -1); break; case MD_BLOCK_HTML: case MD_BLOCK_TABLE: case MD_BLOCK_THEAD: case MD_BLOCK_TBODY: case MD_BLOCK_TR: case MD_BLOCK_TH: case MD_BLOCK_TD: default: g_warning ("Unsupported markdown event (Did you use html/tables?)"); return 1; } } g_array_set_size (ctx->block_stack, ctx->block_stack->len - 1); return 0; } static int enter_span (MD_SPANTYPE type, void *detail, void *user_data) { ParseCtx *ctx = user_data; g_autoptr (TagData) tag = NULL; switch (type) { case MD_SPAN_EM: INIT_TAG_DATA_LOCATION (&tag, ctx->buffer, "weight", 600); break; case MD_SPAN_STRONG: INIT_TAG_DATA_LOCATION (&tag, ctx->buffer, "weight", 800); break; case MD_SPAN_A: { MD_SPAN_A_DETAIL *a_detail = detail; g_autofree char *href = NULL; g_autofree char *title = NULL; g_autofree char *xml = NULL; href = g_strndup (a_detail->href.text, a_detail->href.size); if (a_detail->title.text != NULL) title = g_strndup (a_detail->title.text, a_detail->title.size); xml = g_strdup_printf ( "", href, title != NULL ? title : href); gtk_text_buffer_insert_at_cursor (ctx->buffer, xml, -1); } break; case MD_SPAN_IMG: g_warning ("Images aren't implemented yet!"); break; case MD_SPAN_CODE: INIT_TAG_DATA_LOCATION (&tag, ctx->buffer, "family", "monospace"); break; case MD_SPAN_DEL: INIT_TAG_DATA_LOCATION (&tag, ctx->buffer, "strikethrough", TRUE); break; case MD_SPAN_U: INIT_TAG_DATA_LOCATION (&tag, ctx->buffer, "underline", TRUE); break; case MD_SPAN_LATEXMATH: case MD_SPAN_LATEXMATH_DISPLAY: case MD_SPAN_WIKILINK: default: g_warning ("Unsupported markdown event (Did you use latex/wikilinks?)"); return 1; break; } if (tag != NULL) g_ptr_array_add (ctx->tags, g_steal_pointer (&tag)); return 0; } static int leave_span (MD_SPANTYPE type, void *detail, void *user_data) { ParseCtx *ctx = user_data; switch (type) { case MD_SPAN_EM: TERMINATE_TAG_FROM_SET_PROP ("weight-set"); break; case MD_SPAN_STRONG: TERMINATE_TAG_FROM_SET_PROP ("weight-set"); break; case MD_SPAN_A: gtk_text_buffer_insert_at_cursor (ctx->buffer, "", -1); break; case MD_SPAN_IMG: // g_warning ("Images aren't implemented yet!"); break; case MD_SPAN_CODE: TERMINATE_TAG_FROM_SET_PROP ("family-set"); break; case MD_SPAN_DEL: TERMINATE_TAG_FROM_SET_PROP ("strikethrough-set"); break; case MD_SPAN_U: TERMINATE_TAG_FROM_SET_PROP ("underline-set"); break; case MD_SPAN_LATEXMATH: case MD_SPAN_LATEXMATH_DISPLAY: case MD_SPAN_WIKILINK: default: g_warning ("Unsupported markdown event (Did you use latex/wikilinks?)"); return 1; break; } return 0; } static int text (MD_TEXTTYPE type, const MD_CHAR *buf, MD_SIZE size, void *user_data) { ParseCtx *ctx = user_data; g_autofree char *escaped = NULL; if (type == MD_TEXT_SOFTBR) gtk_text_buffer_insert_at_cursor (ctx->buffer, " ", -1); else if (type == MD_TEXT_BR) gtk_text_buffer_insert_at_cursor (ctx->buffer, "\n", -1); else gtk_text_buffer_insert_at_cursor (ctx->buffer, buf, size); return 0; } /* End of bge-markdown-render.c */ bazaar-orig-v0.7.14/bge/bge-animation.c0000664000175000017500000005530015166123241016556 0ustar hasanhasan/* bge-animation.c * * Copyright 2026 Eva M * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ /* This animation implementation was originally from my other project, libpastry: https://github.com/kolunmi/libpastry */ /** * BgeAnimation: * * Manages animations for a widget. Individual value animations are tracked in a * hash map with string keys, allowing them to be easily restarted or replaced. */ #define G_LOG_DOMAIN "BGE::ANIMATION" #define DELTA 0.001 #define EPSILON 0.00001 #include "bge.h" #include "bge-animation-private.h" enum { PROP_0, PROP_WIDGET, LAST_PROP }; static GParamSpec *props[LAST_PROP] = { 0 }; struct _BgeAnimation { GObject parent_instance; GtkWidget *widget; GWeakRef wr; guint tag; GHashTable *data; GPtrArray *anonymous; }; G_DEFINE_FINAL_TYPE (BgeAnimation, bge_animation, G_TYPE_OBJECT) typedef struct { double from; double to; double damping_ratio; double mass; double stiffness; double damping; gboolean clamp; BgeAnimationCallback cb; gpointer user_data; GDestroyNotify destroy_data; double est_duration; GTimer *timer; double velocity; DexPromise *promise; DexCancellable *cancellable; } SpringData; static gboolean tick_cb (GtkWidget *widget, GdkFrameClock *frame_clock, GWeakRef *wr); static void destroy_spring_data (gpointer ptr); static void destroy_wr (gpointer ptr); static gboolean should_animate (GtkWidget *widget); static void dispose (GObject *object) { BgeAnimation *self = BGE_ANIMATION (object); g_autoptr (GtkWidget) widget = NULL; widget = g_weak_ref_get (&self->wr); if (widget != NULL) { gtk_widget_remove_tick_callback (widget, self->tag); self->tag = 0; } g_clear_object (&widget); g_weak_ref_clear (&self->wr); g_clear_object (&self->widget); g_clear_pointer (&self->data, g_hash_table_unref); g_clear_pointer (&self->anonymous, g_ptr_array_unref); G_OBJECT_CLASS (bge_animation_parent_class)->dispose (object); } static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { BgeAnimation *self = BGE_ANIMATION (object); switch (prop_id) { case PROP_WIDGET: g_value_take_object (value, bge_animation_dup_widget (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { BgeAnimation *self = BGE_ANIMATION (object); switch (prop_id) { case PROP_WIDGET: g_clear_object (&self->widget); self->widget = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void constructed (GObject *object) { BgeAnimation *self = BGE_ANIMATION (object); if (GTK_IS_WIDGET (self->widget)) { GWeakRef *wr = NULL; wr = g_new0 (typeof (*wr), 1); g_weak_ref_init (wr, self); self->tag = gtk_widget_add_tick_callback ( self->widget, (GtkTickCallback) tick_cb, wr, destroy_wr); } g_weak_ref_init (&self->wr, self->widget); g_clear_object (&self->widget); } static void bge_animation_class_init (BgeAnimationClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructed = constructed; object_class->set_property = set_property; object_class->get_property = get_property; object_class->dispose = dispose; /** * BgeAnimation:widget: * * The widget on which this animation is attached. */ props[PROP_WIDGET] = g_param_spec_object ( "widget", NULL, NULL, GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, props); } static void bge_animation_init (BgeAnimation *self) { g_weak_ref_init (&self->wr, NULL); self->data = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, destroy_spring_data); self->anonymous = g_ptr_array_new_with_free_func ( destroy_spring_data); } /** * bge_animation_new: * @widget: The widget onto which to attach the tick callback * * Creates a new `BgeAnimation` object. * * Returns: The newly created `BgeAnimation` object. */ BgeAnimation * bge_animation_new (GtkWidget *widget) { g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); return g_object_new ( BGE_TYPE_ANIMATION, "widget", widget, NULL); } /** * bge_animation_dup_widget: * @self: a `BgeAnimation` * * Gets the widget on which @self is attached. * * Returns: (nullable) (transfer full): the widget for @self */ GtkWidget * bge_animation_dup_widget (BgeAnimation *self) { g_return_val_if_fail (BGE_IS_ANIMATION (self), NULL); return g_weak_ref_get (&self->wr); } /** * bge_animation_add_spring: * @self: a `BgeAnimation` * @key: (nullable): a string ID to replace, or NULL for anonymous * @from: the start value * @to: the end value * @damping_ratio: the damping ratio * @mass: the mass * @stiffness: the stiffness * @cb: a tick callback * @user_data: (nullable): the user data pointer to be passed to @cb * @destroy_data: (nullable): the destruction function for @user_data * @cancellable: (nullable): a cancellable to cancel the operation * * Adds a one shot spring animation to @self. If @key is already running in * @self, then the old animation is replaced, maintaining the current velocity. * * Returns: (transfer full): a future which will resolve when the animation * completes, or reject when the animation is cancelled */ DexFuture * bge_animation_add_spring (BgeAnimation *self, const char *key, double from, double to, double damping_ratio, double mass, double stiffness, BgeAnimationCallback cb, gpointer user_data, GDestroyNotify destroy_data, DexCancellable *cancellable) { g_autoptr (GtkWidget) widget = NULL; dex_return_error_if_fail (BGE_IS_ANIMATION (self)); dex_return_error_if_fail (cb != NULL); widget = g_weak_ref_get (&self->wr); if (widget != NULL) { if (should_animate (widget)) { SpringData *data = NULL; if (key != NULL) /* reuse old data if possible */ data = g_hash_table_lookup (self->data, key); if (data != NULL) { if (data->user_data != NULL && data->destroy_data != NULL) /* we are going to overwrite this */ data->destroy_data (data->user_data); g_clear_pointer (&data->timer, g_timer_destroy); dex_clear (&data->cancellable); /* old velocity is retained */ } else { data = g_new0 (typeof (*data), 1); if (key != NULL) g_hash_table_replace (self->data, g_strdup (key), data); else g_ptr_array_add (self->anonymous, data); } data->from = from; data->to = to; data->damping_ratio = damping_ratio; data->mass = mass; data->stiffness = stiffness; data->cb = cb; data->user_data = user_data; data->destroy_data = destroy_data; data->damping = damping_ratio * (/* critical damping */ 2 * sqrt (mass * stiffness)); /* We'll fill this in on the first iteration */ data->timer = NULL; /* If this animation is being replaced, reuse the old promise */ if (data->promise == NULL || !dex_future_is_pending (DEX_FUTURE (data->promise))) { dex_clear (&data->promise); data->promise = dex_promise_new (); } if (cancellable != NULL) data->cancellable = dex_ref (cancellable); data->est_duration = spring_calculate_duration ( data->damping, data->mass, data->stiffness, data->from, data->to, data->clamp); cb (widget, key, from, user_data); return dex_ref (data->promise); } else /* If we shouldn't animate, just invoke the callback at the final value */ { cb (widget, key, to, user_data); if (user_data != NULL && destroy_data != NULL) destroy_data (user_data); return dex_future_new_true (); } } else { if (user_data != NULL && destroy_data != NULL) destroy_data (user_data); return dex_future_new_reject ( G_IO_ERROR, G_IO_ERROR_INVAL, "Animation's widget no longer exists"); } } /** * bge_animation_cancel: * @self: a `BgeAnimation` * @key: a string ID to remove * * If @key exists on @self, cancel the associated animation. */ void bge_animation_cancel (BgeAnimation *self, const char *key) { SpringData *data = NULL; g_autoptr (GtkWidget) widget = NULL; g_return_if_fail (BGE_IS_ANIMATION (self)); g_return_if_fail (key != NULL); data = g_hash_table_lookup (self->data, key); if (data == NULL) return; widget = g_weak_ref_get (&self->wr); if (widget != NULL) data->cb (widget, key, data->to, data->user_data); dex_promise_reject ( data->promise, g_error_new ( G_IO_ERROR, G_IO_ERROR_CANCELLED, "Animation was cancelled")); g_hash_table_remove (self->data, key); } /** * bge_animation_cancel_all: * @self: a `BgeAnimation` * * Cancel all animations on @self. */ void bge_animation_cancel_all (BgeAnimation *self) { GHashTableIter iter = { 0 }; g_autoptr (GtkWidget) widget = NULL; g_return_if_fail (BGE_IS_ANIMATION (self)); g_hash_table_iter_init (&iter, self->data); widget = g_weak_ref_get (&self->wr); for (;;) { char *key = NULL; SpringData *data = NULL; if (!g_hash_table_iter_next ( &iter, (gpointer *) &key, (gpointer *) &data)) break; if (widget != NULL) data->cb (widget, key, data->to, data->user_data); dex_promise_reject ( data->promise, g_error_new ( G_IO_ERROR, G_IO_ERROR_CANCELLED, "Animation was cancelled")); g_hash_table_iter_remove (&iter); } } static gboolean tick_cb (GtkWidget *widget, GdkFrameClock *frame_clock, GWeakRef *wr) { g_autoptr (BgeAnimation) self = NULL; gboolean cancel = FALSE; GHashTableIter iter = { 0 }; self = g_weak_ref_get (wr); if (self == NULL) return G_SOURCE_REMOVE; cancel = !should_animate (widget); #define UPDATE(_data, _out_value, _out_finished) \ G_STMT_START \ { \ if (cancel || \ ((_data)->cancellable != NULL && \ dex_future_is_rejected (DEX_FUTURE ((_data)->cancellable)))) \ (_out_finished) = TRUE; \ else \ { \ double elapsed = 0.0; \ \ if ((_data)->timer == NULL) \ { \ (_data)->timer = g_timer_new (); \ (_out_value) = (_data)->from; \ } \ else \ { \ elapsed = g_timer_elapsed ((_data)->timer, NULL); \ (_out_value) = spring_oscillate ( \ data->damping, \ data->mass, \ data->stiffness, \ data->from, \ data->to, \ elapsed, \ &(_data)->velocity); \ } \ \ (_out_finished) = elapsed >= (_data)->est_duration; \ } \ if ((_out_finished)) \ (_out_value) = (_data)->to; \ } \ G_STMT_END /* Named anims */ g_hash_table_iter_init (&iter, self->data); for (;;) { char *key = NULL; SpringData *data = NULL; double value = 0.0; gboolean finished = FALSE; if (!g_hash_table_iter_next ( &iter, (gpointer *) &key, (gpointer *) &data)) break; UPDATE (data, value, finished); data->cb (widget, key, value, data->user_data); if (finished) { if (dex_future_is_pending (DEX_FUTURE (data->promise))) dex_promise_resolve_boolean (data->promise, TRUE); g_hash_table_iter_remove (&iter); } } /* Anonymous anims */ for (guint i = 0; i < self->anonymous->len;) { SpringData *data = NULL; double value = 0.0; gboolean finished = FALSE; data = g_ptr_array_index (self->anonymous, i); UPDATE (data, value, finished); data->cb (widget, NULL, value, data->user_data); if (finished) { if (dex_future_is_pending (DEX_FUTURE (data->promise))) dex_promise_resolve_boolean (data->promise, TRUE); g_ptr_array_remove_index (self->anonymous, i); } else i++; } #undef UPDATE return G_SOURCE_CONTINUE; } /* COPIED FROM LIBADWAITA */ /* Based on RBBSpringAnimation from RBBAnimation, MIT license. * https://github.com/robb/RBBAnimation/blob/master/RBBAnimation/RBBSpringAnimation.m * * @offset: Starting value of the spring simulation. Use -1 for regular animations, * as the formulas are tailored to rest at 0 and the resulting evolution between * -1 and 0 will be lerped to the desired range afterwards. Otherwise use 0 for in-place * animations which already start at equilibrium */ double spring_oscillate (double damping, double mass, double stiffness, double from, double to, double time, double *velocity) { double b = damping; double m = mass; double k = stiffness; double v0 = 0.0; double beta = 0.0; double omega0 = 0.0; double x0 = 0.0; double envelope = 0.0; beta = b / (2 * m); omega0 = sqrt (k / m); x0 = from - to; envelope = exp (-beta * time); /* * Solutions of the form C1*e^(lambda1*x) + C2*e^(lambda2*x) * for the differential equation m*ẍ+b*ẋ+kx = 0 */ /* Critically damped */ /* DBL_EPSILON is too small for this specific comparison, so we use * FLT_EPSILON even though it's doubles */ if (G_APPROX_VALUE (beta, omega0, FLT_EPSILON)) { if (velocity != NULL) *velocity = envelope * (-beta * time * v0 - beta * beta * time * x0 + v0); return to + envelope * (x0 + (beta * x0 + v0) * time); } /* Underdamped */ if (beta < omega0) { double omega1 = 0.0; omega1 = sqrt ((omega0 * omega0) - (beta * beta)); if (velocity != NULL) *velocity = envelope * (v0 * cos (omega1 * time) - (x0 * omega1 + (beta * beta * x0 + beta * v0) / (omega1)) * sin (omega1 * time)); return to + envelope * (x0 * cos (omega1 * time) + ((beta * x0 + v0) / omega1) * sin (omega1 * time)); } /* Overdamped */ if (beta > omega0) { double omega2 = 0.0; omega2 = sqrt ((beta * beta) - (omega0 * omega0)); if (velocity != NULL) *velocity = envelope * (v0 * coshl (omega2 * time) + (omega2 * x0 - (beta * beta * x0 + beta * v0) / omega2) * sinhl (omega2 * time)); return to + envelope * (x0 * coshl (omega2 * time) + ((beta * x0 + v0) / omega2) * sinhl (omega2 * time)); } g_assert_not_reached (); } double spring_get_first_zero (double damping, double mass, double stiffness, double from, double to) { /* The first frame is not that important and we avoid finding the trivial 0 * for in-place animations. */ for (int i = 0; i < 20000; i++) { double y = 0.0; y = spring_oscillate ( damping, mass, stiffness, from, to, (double) i / 1000.0, NULL); if (!((to - from > DBL_EPSILON && to - y > EPSILON) || (from - to > DBL_EPSILON && y - to > EPSILON))) return y; } return 0.0; } double spring_calculate_duration (double damping, double mass, double stiffness, double from, double to, gboolean clamp) { double beta = 0.0; double omega0 = 0.0; double x0 = 0.0; double y0 = 0.0; double x1 = 0.0; double y1 = 0.0; double m = 0.0; beta = damping / (2 * mass); if (G_APPROX_VALUE (beta, 0, DBL_EPSILON) || beta < 0) return G_MAXDOUBLE; if (clamp) { if (G_APPROX_VALUE (to, from, DBL_EPSILON)) return 0; return spring_get_first_zero (damping, mass, stiffness, from, to); } omega0 = sqrt (stiffness / mass); /* * As first ansatz for the overdamped solution, * and general estimation for the oscillating ones * we take the value of the envelope when it's < epsilon */ x0 = -log (EPSILON) / beta; /* DBL_EPSILON is too small for this specific comparison, so we use * FLT_EPSILON even though it's doubles */ if (G_APPROX_VALUE (beta, omega0, FLT_EPSILON) || beta < omega0) return x0; /* * Since the overdamped solution decays way slower than the envelope * we need to use the value of the oscillation itself. * Newton's root finding method is a good candidate in this particular case: * https://en.wikipedia.org/wiki/Newton%27s_method */ y0 = spring_oscillate (damping, mass, stiffness, from, to, x0, NULL); m = (spring_oscillate ( damping, mass, stiffness, from, to, (x0 + DELTA), NULL) - y0) / DELTA; x1 = (to - y0 + m * x0) / m; y1 = spring_oscillate ( damping, mass, stiffness, from, to, x1, NULL); for (int i = 0; ABS (to - y1) > EPSILON && i < 1000; i++) { x0 = x1; y0 = y1; m = (spring_oscillate ( damping, mass, stiffness, from, to, x0 + DELTA, NULL) - y0) / DELTA; x1 = (to - y0 + m * x0) / m; y1 = spring_oscillate ( damping, mass, stiffness, from, to, x1, NULL); } if (ABS (to - y1) <= EPSILON) return x1; else return 0.0; } /* ///COPIED FROM LIBADWAITA */ static void destroy_spring_data (gpointer ptr) { SpringData *data = ptr; if (data->destroy_data != NULL && data->user_data != NULL) data->destroy_data (data->user_data); g_clear_pointer (&data->timer, g_timer_destroy); dex_clear (&data->promise); dex_clear (&data->cancellable); g_free (ptr); } static void destroy_wr (gpointer ptr) { GWeakRef *wr = ptr; g_weak_ref_clear (wr); g_free (ptr); } static gboolean should_animate (GtkWidget *widget) { GtkSettings *settings = NULL; gboolean enable_animations = FALSE; if (!gtk_widget_get_mapped (widget)) return FALSE; settings = gtk_widget_get_settings (widget); g_object_get ( settings, "gtk-enable-animations", &enable_animations, NULL); return enable_animations; } bazaar-orig-v0.7.14/bge/README.md0000664000175000017500000000003015166123241015145 0ustar hasanhasan# Bazaar GTK Extensions bazaar-orig-v0.7.14/.gitignore0000664000175000017500000000001515166123241015124 0ustar hasanhasanbuild .cache bazaar-orig-v0.7.14/.gitmodules0000664000175000017500000000021415166123241015312 0ustar hasanhasan[submodule "flatpak-builder-tools"] path = build-aux/flatpak/flatpak-builder-tools url = https://github.com/flatpak/flatpak-builder-tools bazaar-orig-v0.7.14/scripts/0000775000175000017500000000000015166123241014627 5ustar hasanhasanbazaar-orig-v0.7.14/scripts/countries.json.in0000664000175000017500000056767015166123241020167 0ustar hasanhasan{"features":[ { "N": "Fiji", "I": "FJ", "C": [[[[180, -16.067], [180, -16.555], [179.364, -16.801], [178.725, -17.012], [178.597, -16.639], [179.097, -16.434], [179.414, -16.379], [180, -16.067]]], [[[178.126, -17.505], [178.374, -17.34], [178.718, -17.628], [178.553, -18.151], [177.933, -18.288], [177.381, -18.164], [177.285, -17.725], [177.671, -17.381], [178.126, -17.505]]], [[[-179.793, -16.021], [-179.917, -16.502], [-180, -16.555], [-180, -16.067], [-179.793, -16.021]]]] }, { "N": "Tanzania", "I": "TZ", "C": [[[[33.904, -0.95], [34.073, -1.06], [37.699, -3.097], [37.767, -3.677], [39.202, -4.677], [38.741, -5.909], [38.8, -6.476], [39.44, -6.84], [39.47, -7.1], [39.195, -7.704], [39.252, -8.008], [39.187, -8.486], [39.536, -9.112], [39.95, -10.098], [40.317, -10.317], [40.317, -10.317], [39.521, -10.897], [38.428, -11.285], [37.828, -11.269], [37.471, -11.569], [36.775, -11.595], [36.514, -11.721], [35.312, -11.439], [34.56, -11.52], [34.28, -10.16], [33.941, -9.694], [33.74, -9.417], [32.759, -9.231], [32.192, -8.93], [31.556, -8.762], [31.158, -8.595], [30.74, -8.34], [30.74, -8.34], [30.2, -7.08], [29.62, -6.52], [29.42, -5.94], [29.52, -5.42], [29.34, -4.5], [29.754, -4.452], [30.116, -4.09], [30.506, -3.569], [30.752, -3.359], [30.743, -3.034], [30.528, -2.808], [30.47, -2.414], [30.47, -2.414], [30.758, -2.287], [30.816, -1.699], [30.419, -1.135], [30.77, -1.015], [31.866, -1.027], [33.904, -0.95]]]] }, { "N": "Western Sahara", "I": "EH", "C": [[[[-8.666, 27.656], [-8.665, 27.589], [-8.684, 27.396], [-8.687, 25.881], [-11.969, 25.933], [-11.937, 23.375], [-12.874, 23.285], [-13.119, 22.771], [-12.929, 21.327], [-16.845, 21.333], [-17.063, 21], [-17.02, 21.422], [-17.003, 21.421], [-14.751, 21.501], [-14.631, 21.861], [-14.221, 22.31], [-13.891, 23.691], [-12.501, 24.77], [-12.031, 26.031], [-11.718, 26.104], [-11.393, 26.883], [-10.551, 26.991], [-10.189, 26.861], [-9.735, 26.861], [-9.413, 27.088], [-8.795, 27.121], [-8.818, 27.656], [-8.666, 27.656]]]] }, { "N": "Canada", "I": "CA", "C": [[[[-122.84, 49], [-122.974, 49.003], [-124.91, 49.985], [-125.625, 50.417], [-127.436, 50.831], [-127.993, 51.716], [-127.85, 52.33], [-129.13, 52.755], [-129.305, 53.562], [-130.515, 54.288], [-130.536, 54.803], [-130.536, 54.803], [-129.98, 55.285], [-130.008, 55.916], [-131.708, 56.552], [-132.73, 57.693], [-133.356, 58.41], [-134.271, 58.861], [-134.945, 59.271], [-135.476, 59.788], [-136.48, 59.464], [-137.452, 58.905], [-138.341, 59.562], [-139.039, 60], [-140.013, 60.277], [-140.998, 60.306], [-140.993, 66], [-140.986, 69.712], [-140.986, 69.712], [-139.121, 69.471], [-137.546, 68.99], [-136.504, 68.898], [-135.626, 69.315], [-134.415, 69.627], [-132.929, 69.505], [-131.431, 69.945], [-129.795, 70.194], [-129.108, 69.779], [-128.362, 70.013], [-128.138, 70.484], [-127.447, 70.377], [-125.756, 69.481], [-124.425, 70.158], [-124.29, 69.4], [-123.061, 69.564], [-122.683, 69.856], [-121.472, 69.798], [-119.943, 69.378], [-117.603, 69.011], [-116.226, 68.842], [-115.247, 68.906], [-113.898, 68.399], [-115.305, 67.903], [-113.497, 67.688], [-110.798, 67.806], [-109.946, 67.981], [-108.88, 67.381], [-107.792, 67.887], [-108.813, 68.312], [-108.167, 68.654], [-106.95, 68.7], [-106.15, 68.8], [-105.343, 68.561], [-104.338, 68.018], [-103.221, 68.098], [-101.454, 67.647], [-99.902, 67.806], [-98.443, 67.782], [-98.559, 68.404], [-97.669, 68.579], [-96.12, 68.239], [-96.126, 67.293], [-95.489, 68.091], [-94.685, 68.064], [-94.233, 69.069], [-95.304, 69.686], [-96.471, 70.09], [-96.391, 71.195], [-95.209, 71.921], [-93.89, 71.76], [-92.878, 71.319], [-91.52, 70.191], [-92.407, 69.7], [-90.547, 69.498], [-90.552, 68.475], [-89.215, 69.259], [-88.02, 68.615], [-88.317, 67.873], [-87.35, 67.199], [-86.306, 67.921], [-85.577, 68.785], [-85.522, 69.882], [-84.101, 69.805], [-82.623, 69.658], [-81.28, 69.162], [-81.22, 68.666], [-81.964, 68.133], [-81.259, 67.597], [-81.387, 67.111], [-83.345, 66.412], [-84.735, 66.257], [-85.769, 66.558], [-86.068, 66.056], [-87.031, 65.213], [-87.323, 64.776], [-88.483, 64.099], [-89.914, 64.033], [-90.704, 63.61], [-90.77, 62.96], [-91.933, 62.835], [-93.157, 62.025], [-94.242, 60.899], [-94.629, 60.11], [-94.685, 58.949], [-93.215, 58.782], [-92.765, 57.846], [-92.297, 57.087], [-90.898, 57.285], [-89.04, 56.852], [-88.04, 56.472], [-87.324, 55.999], [-86.071, 55.724], [-85.012, 55.303], [-83.361, 55.245], [-82.273, 55.148], [-82.436, 54.282], [-82.125, 53.277], [-81.401, 52.158], [-79.913, 51.208], [-79.143, 51.534], [-78.602, 52.562], [-79.124, 54.141], [-79.83, 54.668], [-78.229, 55.136], [-77.096, 55.837], [-76.541, 56.534], [-76.623, 57.203], [-77.302, 58.052], [-78.517, 58.805], [-77.337, 59.853], [-77.773, 60.758], [-78.107, 62.32], [-77.411, 62.551], [-75.696, 62.278], [-74.668, 62.181], [-73.84, 62.444], [-72.909, 62.105], [-71.677, 61.525], [-71.374, 61.137], [-69.59, 61.061], [-69.62, 60.221], [-69.288, 58.957], [-68.375, 58.801], [-67.65, 58.212], [-66.202, 58.767], [-65.245, 59.871], [-64.584, 60.336], [-63.805, 59.443], [-62.502, 58.167], [-61.397, 56.967], [-61.799, 56.339], [-60.469, 55.775], [-59.57, 55.204], [-57.975, 54.945], [-57.333, 54.627], [-56.937, 53.78], [-56.158, 53.647], [-55.756, 53.27], [-55.683, 52.147], [-56.409, 51.771], [-57.127, 51.42], [-58.775, 51.064], [-60.033, 50.243], [-61.724, 50.08], [-63.863, 50.291], [-65.363, 50.298], [-66.399, 50.229], [-67.236, 49.512], [-68.511, 49.068], [-69.954, 47.745], [-71.105, 46.822], [-70.255, 46.986], [-68.65, 48.3], [-66.552, 49.133], [-65.056, 49.233], [-64.171, 48.742], [-65.115, 48.071], [-64.799, 46.993], [-64.472, 46.238], [-63.173, 45.739], [-61.521, 45.884], [-60.518, 47.008], [-60.449, 46.283], [-59.803, 45.92], [-61.04, 45.265], [-63.255, 44.67], [-64.247, 44.266], [-65.364, 43.545], [-66.123, 43.619], [-66.162, 44.465], [-64.425, 45.292], [-66.026, 45.259], [-67.137, 45.138], [-67.791, 45.703], [-67.79, 47.066], [-68.234, 47.355], [-68.905, 47.185], [-69.237, 47.448], [-70, 46.693], [-70.305, 45.915], [-70.66, 45.46], [-71.085, 45.305], [-71.405, 45.255], [-71.505, 45.008], [-73.348, 45.007], [-74.867, 45], [-75.318, 44.816], [-76.375, 44.096], [-76.5, 44.018], [-76.82, 43.629], [-77.738, 43.629], [-78.72, 43.625], [-79.172, 43.466], [-79.01, 43.27], [-78.92, 42.965], [-78.939, 42.864], [-80.247, 42.366], [-81.278, 42.209], [-82.439, 41.675], [-82.69, 41.675], [-83.03, 41.833], [-83.142, 41.976], [-83.12, 42.08], [-82.9, 42.43], [-82.43, 42.98], [-82.138, 43.571], [-82.338, 44.44], [-82.551, 45.348], [-83.593, 45.817], [-83.47, 45.995], [-83.616, 46.117], [-83.891, 46.117], [-84.092, 46.275], [-84.142, 46.512], [-84.337, 46.409], [-84.605, 46.44], [-84.544, 46.539], [-84.779, 46.637], [-84.876, 46.9], [-85.652, 47.22], [-86.462, 47.553], [-87.44, 47.94], [-88.378, 48.303], [-89.273, 48.02], [-89.6, 48.01], [-90.83, 48.27], [-91.64, 48.14], [-92.61, 48.45], [-93.631, 48.609], [-94.329, 48.671], [-94.64, 48.84], [-94.818, 49.389], [-95.156, 49.384], [-95.159, 49], [-97.229, 49.001], [-100.65, 49], [-104.048, 49], [-107.05, 49], [-110.05, 49], [-113, 49], [-116.048, 49], [-117.031, 49], [-120, 49], [-122.84, 49]]], [[[-83.994, 62.453], [-83.25, 62.914], [-81.877, 62.905], [-81.898, 62.711], [-83.069, 62.159], [-83.775, 62.182], [-83.994, 62.453]]], [[[-79.776, 72.803], [-80.876, 73.333], [-80.834, 73.693], [-80.353, 73.76], [-78.064, 73.652], [-76.34, 73.103], [-76.251, 72.826], [-77.314, 72.856], [-78.392, 72.877], [-79.486, 72.742], [-79.776, 72.803]]], [[[-80.315, 62.086], [-79.929, 62.386], [-79.52, 62.364], [-79.266, 62.159], [-79.658, 61.633], [-80.1, 61.718], [-80.362, 62.016], [-80.315, 62.086]]], [[[-93.613, 74.98], [-94.157, 74.592], [-95.609, 74.667], [-96.821, 74.928], [-96.289, 75.378], [-94.851, 75.647], [-93.978, 75.296], [-93.613, 74.98]]], [[[-93.84, 77.52], [-94.296, 77.491], [-96.17, 77.555], [-96.436, 77.835], [-94.423, 77.82], [-93.721, 77.634], [-93.84, 77.52]]], [[[-96.754, 78.766], [-95.559, 78.418], [-95.83, 78.057], [-97.31, 77.851], [-98.124, 78.083], [-98.553, 78.458], [-98.632, 78.872], [-97.337, 78.832], [-96.754, 78.766]]], [[[-88.15, 74.392], [-89.765, 74.516], [-92.422, 74.838], [-92.768, 75.387], [-92.89, 75.883], [-93.894, 76.319], [-95.962, 76.441], [-97.121, 76.751], [-96.745, 77.161], [-94.684, 77.098], [-93.574, 76.776], [-91.605, 76.779], [-90.742, 76.45], [-90.97, 76.074], [-89.822, 75.848], [-89.187, 75.61], [-87.838, 75.566], [-86.379, 75.482], [-84.79, 75.699], [-82.753, 75.784], [-81.129, 75.714], [-80.058, 75.337], [-79.834, 74.923], [-80.458, 74.657], [-81.949, 74.442], [-83.229, 74.564], [-86.097, 74.41], [-88.15, 74.392]]], [[[-111.264, 78.153], [-109.854, 77.996], [-110.187, 77.697], [-112.051, 77.409], [-113.534, 77.732], [-112.725, 78.051], [-111.264, 78.153]]], [[[-110.964, 78.804], [-109.663, 78.602], [-110.881, 78.407], [-112.542, 78.408], [-112.526, 78.551], [-111.5, 78.85], [-110.964, 78.804]]], [[[-55.6, 51.317], [-56.134, 50.687], [-56.796, 49.812], [-56.143, 50.15], [-55.471, 49.936], [-55.822, 49.587], [-54.935, 49.313], [-54.474, 49.557], [-53.477, 49.249], [-53.786, 48.517], [-53.086, 48.688], [-52.959, 48.157], [-52.648, 47.536], [-53.069, 46.655], [-53.521, 46.618], [-54.179, 46.807], [-53.962, 47.625], [-54.24, 47.752], [-55.401, 46.885], [-55.997, 46.92], [-55.291, 47.39], [-56.251, 47.633], [-57.325, 47.573], [-59.266, 47.603], [-59.419, 47.899], [-58.797, 48.252], [-59.232, 48.523], [-58.392, 49.126], [-57.359, 50.718], [-56.739, 51.287], [-55.871, 51.632], [-55.407, 51.588], [-55.6, 51.317]]], [[[-83.883, 65.11], [-82.788, 64.767], [-81.642, 64.455], [-81.553, 63.98], [-80.817, 64.057], [-80.103, 63.726], [-80.991, 63.411], [-82.547, 63.652], [-83.109, 64.102], [-84.1, 63.57], [-85.523, 63.052], [-85.867, 63.637], [-87.222, 63.541], [-86.353, 64.036], [-86.225, 64.823], [-85.884, 65.739], [-85.161, 65.657], [-84.976, 65.218], [-84.464, 65.372], [-83.883, 65.11]]], [[[-78.771, 72.352], [-77.825, 72.75], [-75.606, 72.244], [-74.229, 71.767], [-74.099, 71.331], [-72.242, 71.557], [-71.2, 70.92], [-68.786, 70.525], [-67.915, 70.122], [-66.969, 69.186], [-68.805, 68.72], [-66.45, 68.067], [-64.862, 67.848], [-63.425, 66.928], [-61.852, 66.862], [-62.163, 66.16], [-63.918, 64.999], [-65.149, 65.426], [-66.721, 66.388], [-68.015, 66.263], [-68.141, 65.69], [-67.09, 65.108], [-65.732, 64.648], [-65.32, 64.383], [-64.669, 63.393], [-65.014, 62.674], [-66.275, 62.945], [-68.783, 63.746], [-67.37, 62.884], [-66.328, 62.28], [-66.166, 61.931], [-68.877, 62.33], [-71.023, 62.911], [-72.235, 63.398], [-71.886, 63.68], [-73.378, 64.194], [-74.834, 64.679], [-74.819, 64.389], [-77.71, 64.23], [-78.556, 64.573], [-77.897, 65.309], [-76.018, 65.327], [-73.96, 65.455], [-74.294, 65.812], [-73.945, 66.311], [-72.651, 67.285], [-72.926, 67.727], [-73.312, 68.069], [-74.843, 68.555], [-76.869, 68.895], [-76.229, 69.148], [-77.287, 69.77], [-78.169, 69.826], [-78.957, 70.167], [-79.492, 69.872], [-81.305, 69.743], [-84.945, 69.967], [-87.06, 70.26], [-88.682, 70.411], [-89.513, 70.762], [-88.468, 71.218], [-89.888, 71.223], [-90.205, 72.235], [-89.437, 73.129], [-88.408, 73.538], [-85.826, 73.804], [-86.562, 73.157], [-85.774, 72.534], [-84.85, 73.34], [-82.316, 73.751], [-80.6, 72.717], [-80.749, 72.062], [-78.771, 72.352]]], [[[-94.504, 74.135], [-92.42, 74.1], [-90.51, 73.857], [-92.004, 72.966], [-93.196, 72.772], [-94.269, 72.025], [-95.41, 72.062], [-96.034, 72.94], [-96.018, 73.437], [-95.496, 73.862], [-94.504, 74.135]]], [[[-122.855, 76.117], [-122.855, 76.117], [-121.158, 76.865], [-119.104, 77.512], [-117.57, 77.498], [-116.199, 77.645], [-116.336, 76.877], [-117.106, 76.53], [-118.04, 76.481], [-119.899, 76.053], [-121.5, 75.9], [-122.855, 76.117]]], [[[-132.71, 54.04], [-131.75, 54.12], [-132.049, 52.985], [-131.179, 52.18], [-131.578, 52.182], [-132.18, 52.64], [-132.55, 53.1], [-133.055, 53.411], [-133.24, 53.851], [-133.18, 54.17], [-132.71, 54.04]]], [[[-105.492, 79.302], [-103.529, 79.165], [-100.825, 78.8], [-100.06, 78.325], [-99.671, 77.908], [-101.304, 78.019], [-102.95, 78.343], [-105.176, 78.38], [-104.21, 78.677], [-105.42, 78.918], [-105.492, 79.302]]], [[[-123.51, 48.51], [-124.013, 48.371], [-125.655, 48.825], [-125.955, 49.18], [-126.85, 49.53], [-127.03, 49.815], [-128.059, 49.995], [-128.445, 50.539], [-128.358, 50.771], [-127.309, 50.553], [-126.695, 50.401], [-125.755, 50.295], [-125.415, 49.95], [-124.921, 49.475], [-123.923, 49.062], [-123.51, 48.51]]], [[[-121.538, 74.449], [-120.11, 74.241], [-117.556, 74.186], [-116.584, 73.896], [-115.511, 73.475], [-116.768, 73.223], [-119.22, 72.52], [-120.46, 71.82], [-120.46, 71.384], [-123.092, 70.902], [-123.62, 71.34], [-125.929, 71.869], [-125.5, 72.292], [-124.807, 73.023], [-123.94, 73.68], [-124.918, 74.293], [-121.538, 74.449]]], [[[-107.819, 75.846], [-106.929, 76.013], [-105.881, 75.969], [-105.705, 75.48], [-106.313, 75.005], [-109.7, 74.85], [-112.223, 74.417], [-113.744, 74.394], [-113.871, 74.72], [-111.794, 75.162], [-116.312, 75.043], [-117.71, 75.222], [-116.346, 76.199], [-115.405, 76.479], [-112.591, 76.141], [-110.814, 75.549], [-109.067, 75.473], [-110.497, 76.43], [-109.581, 76.794], [-108.549, 76.678], [-108.211, 76.202], [-107.819, 75.846]]], [[[-106.523, 73.076], [-105.402, 72.673], [-104.775, 71.698], [-104.465, 70.993], [-102.785, 70.498], [-100.981, 70.024], [-101.089, 69.584], [-102.731, 69.504], [-102.093, 69.12], [-102.43, 68.753], [-104.24, 68.91], [-105.96, 69.18], [-107.123, 69.119], [-109, 68.78], [-111.534, 68.63], [-113.313, 68.536], [-113.855, 69.007], [-115.22, 69.28], [-116.108, 69.168], [-117.34, 69.96], [-116.675, 70.067], [-115.131, 70.237], [-113.721, 70.192], [-112.416, 70.366], [-114.35, 70.6], [-116.487, 70.52], [-117.905, 70.541], [-118.432, 70.909], [-116.113, 71.309], [-117.656, 71.295], [-119.402, 71.559], [-118.563, 72.308], [-117.866, 72.706], [-115.189, 73.315], [-114.167, 73.121], [-114.666, 72.653], [-112.441, 72.955], [-111.05, 72.45], [-109.92, 72.961], [-109.007, 72.633], [-108.188, 71.651], [-107.686, 72.065], [-108.396, 73.09], [-107.516, 73.236], [-106.523, 73.076]]], [[[-100.438, 72.706], [-101.54, 73.36], [-100.356, 73.844], [-99.164, 73.633], [-97.38, 73.76], [-97.12, 73.47], [-98.054, 72.991], [-96.54, 72.56], [-96.72, 71.66], [-98.36, 71.273], [-99.323, 71.356], [-100.015, 71.738], [-102.5, 72.51], [-102.48, 72.83], [-100.438, 72.706]]], [[[-106.6, 73.6], [-105.26, 73.64], [-104.5, 73.42], [-105.38, 72.76], [-106.94, 73.46], [-106.6, 73.6]]], [[[-98.5, 76.72], [-97.736, 76.257], [-97.704, 75.743], [-98.16, 75], [-99.809, 74.897], [-100.884, 75.057], [-100.863, 75.641], [-102.502, 75.564], [-102.566, 76.337], [-101.49, 76.305], [-99.983, 76.646], [-98.577, 76.589], [-98.5, 76.72]]], [[[-96.016, 80.602], [-95.323, 80.907], [-94.298, 80.977], [-94.735, 81.206], [-92.41, 81.257], [-91.133, 80.723], [-89.45, 80.509], [-87.81, 80.32], [-87.02, 79.66], [-85.814, 79.337], [-87.188, 79.039], [-89.035, 78.287], [-90.804, 78.215], [-92.877, 78.343], [-93.951, 78.751], [-93.936, 79.114], [-93.145, 79.38], [-94.974, 79.372], [-96.076, 79.705], [-96.71, 80.158], [-96.016, 80.602]]], [[[-91.587, 81.894], [-90.1, 82.085], [-88.932, 82.118], [-86.97, 82.28], [-85.5, 82.652], [-84.26, 82.6], [-83.18, 82.32], [-82.42, 82.86], [-81.1, 83.02], [-79.307, 83.131], [-76.25, 83.172], [-75.719, 83.064], [-72.832, 83.233], [-70.666, 83.17], [-68.5, 83.106], [-65.827, 83.028], [-63.68, 82.9], [-61.85, 82.629], [-61.894, 82.362], [-64.334, 81.928], [-66.753, 81.725], [-67.658, 81.501], [-65.48, 81.507], [-67.84, 80.9], [-69.47, 80.617], [-71.18, 79.8], [-73.243, 79.634], [-73.88, 79.43], [-76.908, 79.323], [-75.529, 79.198], [-76.22, 79.019], [-75.393, 78.526], [-76.344, 78.183], [-77.889, 77.9], [-78.363, 77.509], [-79.76, 77.21], [-79.62, 76.983], [-77.911, 77.022], [-77.889, 76.778], [-80.561, 76.178], [-83.174, 76.454], [-86.112, 76.299], [-87.6, 76.42], [-89.491, 76.472], [-89.616, 76.952], [-87.767, 77.178], [-88.26, 77.9], [-87.65, 77.97], [-84.976, 77.539], [-86.34, 78.18], [-87.962, 78.372], [-87.152, 78.759], [-85.379, 78.997], [-85.095, 79.345], [-86.507, 79.736], [-86.932, 80.251], [-84.198, 80.208], [-83.409, 80.1], [-81.848, 80.464], [-84.1, 80.58], [-87.599, 80.516], [-89.367, 80.856], [-90.2, 81.26], [-91.368, 81.553], [-91.587, 81.894]]], [[[-75.216, 67.444], [-75.866, 67.149], [-76.987, 67.099], [-77.236, 67.588], [-76.812, 68.149], [-75.895, 68.287], [-75.115, 68.01], [-75.103, 67.582], [-75.216, 67.444]]], [[[-96.257, 69.49], [-95.648, 69.108], [-96.27, 68.757], [-97.617, 69.06], [-98.432, 68.951], [-99.797, 69.4], [-98.917, 69.71], [-98.218, 70.144], [-97.157, 69.86], [-96.557, 69.68], [-96.257, 69.49]]], [[[-64.519, 49.873], [-64.173, 49.957], [-62.858, 49.706], [-61.836, 49.289], [-61.806, 49.105], [-62.293, 49.087], [-63.589, 49.401], [-64.519, 49.873]]], [[[-64.015, 47.036], [-63.664, 46.55], [-62.939, 46.416], [-62.012, 46.443], [-62.504, 46.033], [-62.874, 45.968], [-64.143, 46.393], [-64.393, 46.727], [-64.015, 47.036]]]] }, { "N": "United States", "I": "US", "C": [[[[-155.402, 20.08], [-155.225, 19.993], [-155.062, 19.859], [-154.807, 19.509], [-154.831, 19.453], [-155.222, 19.24], [-155.542, 19.083], [-155.688, 18.916], [-155.937, 19.059], [-155.908, 19.339], [-156.073, 19.703], [-156.024, 19.814], [-155.85, 19.977], [-155.919, 20.174], [-155.861, 20.267], [-155.785, 20.249], [-155.402, 20.08]]], [[[-155.996, 20.764], [-156.079, 20.644], [-156.414, 20.572], [-156.587, 20.783], [-156.702, 20.864], [-156.711, 20.927], [-156.613, 21.012], [-156.257, 20.917], [-155.996, 20.764]]], [[[-156.758, 21.177], [-156.789, 21.069], [-157.325, 21.098], [-157.25, 21.22], [-156.758, 21.177]]], [[[-158.025, 21.717], [-157.942, 21.653], [-157.653, 21.322], [-157.707, 21.264], [-157.779, 21.277], [-158.127, 21.312], [-158.254, 21.539], [-158.293, 21.579], [-158.025, 21.717]]], [[[-159.366, 22.215], [-159.345, 21.982], [-159.464, 21.883], [-159.801, 22.065], [-159.749, 22.138], [-159.596, 22.236], [-159.366, 22.215]]], [[[-166.468, 60.384], [-165.674, 60.294], [-165.579, 59.91], [-166.193, 59.754], [-166.848, 59.941], [-167.455, 60.213], [-166.468, 60.384]]], [[[-153.229, 57.969], [-152.565, 57.901], [-152.141, 57.591], [-153.006, 57.116], [-154.005, 56.735], [-154.516, 56.993], [-154.671, 57.461], [-153.763, 57.817], [-153.229, 57.969]]], [[[-140.986, 69.712], [-140.986, 69.712], [-140.993, 66], [-140.998, 60.306], [-140.013, 60.277], [-139.039, 60], [-138.341, 59.562], [-137.452, 58.905], [-136.48, 59.464], [-135.476, 59.788], [-134.945, 59.271], [-134.271, 58.861], [-133.356, 58.41], [-132.73, 57.693], [-131.708, 56.552], [-130.008, 55.916], [-129.98, 55.285], [-130.536, 54.803], [-130.536, 54.803], [-130.536, 54.803], [-131.086, 55.179], [-131.967, 55.498], [-132.25, 56.37], [-133.539, 57.179], [-134.078, 58.123], [-135.038, 58.188], [-136.628, 58.212], [-137.8, 58.5], [-139.868, 59.538], [-140.825, 59.728], [-142.574, 60.084], [-143.959, 59.999], [-145.926, 60.459], [-147.114, 60.885], [-148.224, 60.673], [-148.018, 59.978], [-148.571, 59.914], [-149.728, 59.706], [-150.608, 59.368], [-151.716, 59.156], [-151.859, 59.745], [-151.41, 60.726], [-150.347, 61.034], [-150.621, 61.284], [-151.896, 60.727], [-152.578, 60.062], [-154.019, 59.35], [-153.288, 58.865], [-154.232, 58.146], [-155.307, 57.728], [-156.308, 57.423], [-156.556, 56.98], [-158.117, 56.464], [-158.433, 55.994], [-159.603, 55.567], [-160.29, 55.644], [-161.223, 55.365], [-162.238, 55.024], [-163.069, 54.69], [-164.786, 54.404], [-164.942, 54.572], [-163.848, 55.039], [-162.87, 55.348], [-161.804, 55.895], [-160.564, 56.008], [-160.071, 56.418], [-158.684, 57.017], [-158.461, 57.217], [-157.723, 57.57], [-157.55, 58.328], [-157.042, 58.919], [-158.195, 58.616], [-158.517, 58.788], [-159.059, 58.424], [-159.712, 58.931], [-159.981, 58.573], [-160.355, 59.071], [-161.355, 58.671], [-161.969, 58.672], [-162.055, 59.267], [-161.874, 59.634], [-162.518, 59.99], [-163.818, 59.798], [-164.662, 60.267], [-165.346, 60.507], [-165.351, 61.074], [-166.121, 61.5], [-165.734, 62.075], [-164.919, 62.633], [-164.563, 63.146], [-163.753, 63.219], [-163.067, 63.059], [-162.261, 63.542], [-161.534, 63.456], [-160.773, 63.766], [-160.958, 64.223], [-161.518, 64.403], [-160.778, 64.789], [-161.392, 64.777], [-162.453, 64.559], [-162.758, 64.339], [-163.546, 64.559], [-164.961, 64.447], [-166.425, 64.687], [-166.845, 65.089], [-168.111, 65.67], [-166.705, 66.088], [-164.475, 66.577], [-163.653, 66.577], [-163.789, 66.077], [-161.678, 66.116], [-162.49, 66.736], [-163.72, 67.116], [-164.431, 67.616], [-165.39, 68.043], [-166.764, 68.359], [-166.205, 68.883], [-164.431, 68.916], [-163.169, 69.371], [-162.931, 69.858], [-161.909, 70.333], [-160.935, 70.448], [-159.039, 70.892], [-158.12, 70.825], [-156.581, 71.358], [-155.068, 71.148], [-154.344, 70.696], [-153.9, 70.89], [-152.21, 70.83], [-152.27, 70.6], [-150.74, 70.43], [-149.72, 70.53], [-147.613, 70.214], [-145.69, 70.12], [-144.92, 69.99], [-143.589, 70.153], [-142.073, 69.852], [-140.986, 69.712], [-140.986, 69.712]]], [[[-171.732, 63.783], [-171.114, 63.592], [-170.491, 63.695], [-169.683, 63.431], [-168.689, 63.298], [-168.772, 63.189], [-169.529, 62.977], [-170.291, 63.194], [-170.671, 63.376], [-171.553, 63.318], [-171.791, 63.406], [-171.732, 63.783]]], [[[-122.84, 49], [-120, 49], [-117.031, 49], [-116.048, 49], [-113, 49], [-110.05, 49], [-107.05, 49], [-104.048, 49], [-100.65, 49], [-97.229, 49.001], [-95.159, 49], [-95.156, 49.384], [-94.818, 49.389], [-94.64, 48.84], [-94.329, 48.671], [-93.631, 48.609], [-92.61, 48.45], [-91.64, 48.14], [-90.83, 48.27], [-89.6, 48.01], [-89.273, 48.02], [-88.378, 48.303], [-87.44, 47.94], [-86.462, 47.553], [-85.652, 47.22], [-84.876, 46.9], [-84.779, 46.637], [-84.544, 46.539], [-84.605, 46.44], [-84.337, 46.409], [-84.142, 46.512], [-84.092, 46.275], [-83.891, 46.117], [-83.616, 46.117], [-83.47, 45.995], [-83.593, 45.817], [-82.551, 45.348], [-82.338, 44.44], [-82.138, 43.571], [-82.43, 42.98], [-82.9, 42.43], [-83.12, 42.08], [-83.142, 41.976], [-83.03, 41.833], [-82.69, 41.675], [-82.439, 41.675], [-81.278, 42.209], [-80.247, 42.366], [-78.939, 42.864], [-78.92, 42.965], [-79.01, 43.27], [-79.172, 43.466], [-78.72, 43.625], [-77.738, 43.629], [-76.82, 43.629], [-76.5, 44.018], [-76.375, 44.096], [-75.318, 44.816], [-74.867, 45], [-73.348, 45.007], [-71.505, 45.008], [-71.405, 45.255], [-71.085, 45.305], [-70.66, 45.46], [-70.305, 45.915], [-70, 46.693], [-69.237, 47.448], [-68.905, 47.185], [-68.234, 47.355], [-67.79, 47.066], [-67.791, 45.703], [-67.137, 45.138], [-66.965, 44.81], [-68.033, 44.325], [-69.06, 43.98], [-70.116, 43.684], [-70.645, 43.09], [-70.815, 42.865], [-70.825, 42.335], [-70.495, 41.805], [-70.08, 41.78], [-70.185, 42.145], [-69.885, 41.923], [-69.965, 41.637], [-70.64, 41.475], [-71.12, 41.494], [-71.86, 41.32], [-72.295, 41.27], [-72.876, 41.221], [-73.71, 40.931], [-72.241, 41.119], [-71.945, 40.93], [-73.345, 40.63], [-73.982, 40.628], [-73.952, 40.751], [-74.257, 40.474], [-73.962, 40.428], [-74.178, 39.709], [-74.906, 38.94], [-74.98, 39.196], [-75.2, 39.248], [-75.528, 39.498], [-75.32, 38.96], [-75.072, 38.782], [-75.057, 38.404], [-75.377, 38.016], [-75.94, 37.217], [-76.031, 37.257], [-75.722, 37.937], [-76.233, 38.319], [-76.35, 39.15], [-76.543, 38.718], [-76.329, 38.083], [-76.99, 38.24], [-76.302, 37.918], [-76.259, 36.966], [-75.972, 36.897], [-75.868, 36.551], [-75.727, 35.551], [-76.363, 34.809], [-77.398, 34.512], [-78.055, 33.925], [-78.554, 33.861], [-79.061, 33.494], [-79.204, 33.158], [-80.301, 32.509], [-80.865, 32.033], [-81.336, 31.44], [-81.49, 30.73], [-81.314, 30.036], [-80.98, 29.18], [-80.536, 28.472], [-80.53, 28.04], [-80.057, 26.88], [-80.088, 26.206], [-80.132, 25.817], [-80.381, 25.206], [-80.68, 25.08], [-81.172, 25.201], [-81.33, 25.64], [-81.71, 25.87], [-82.24, 26.73], [-82.705, 27.495], [-82.855, 27.886], [-82.65, 28.55], [-82.93, 29.1], [-83.71, 29.937], [-84.1, 30.09], [-85.109, 29.636], [-85.288, 29.686], [-85.773, 30.153], [-86.4, 30.4], [-87.53, 30.274], [-88.418, 30.385], [-89.18, 30.316], [-89.594, 30.16], [-89.414, 29.894], [-89.43, 29.489], [-89.218, 29.291], [-89.408, 29.16], [-89.779, 29.307], [-90.155, 29.117], [-90.88, 29.149], [-91.627, 29.677], [-92.499, 29.552], [-93.226, 29.784], [-93.848, 29.714], [-94.69, 29.48], [-95.6, 28.739], [-96.594, 28.307], [-97.14, 27.83], [-97.37, 27.38], [-97.38, 26.69], [-97.33, 26.21], [-97.14, 25.87], [-97.53, 25.84], [-98.24, 26.06], [-99.02, 26.37], [-99.3, 26.84], [-99.52, 27.54], [-100.11, 28.11], [-100.456, 28.696], [-100.958, 29.381], [-101.662, 29.779], [-102.48, 29.76], [-103.11, 28.97], [-103.94, 29.27], [-104.457, 29.572], [-104.706, 30.122], [-105.037, 30.644], [-105.632, 31.084], [-106.143, 31.4], [-106.508, 31.755], [-108.24, 31.755], [-108.242, 31.342], [-109.035, 31.342], [-111.024, 31.335], [-113.305, 32.039], [-114.815, 32.525], [-114.721, 32.721], [-115.991, 32.612], [-117.128, 32.535], [-117.296, 33.046], [-117.944, 33.621], [-118.411, 33.741], [-118.52, 34.028], [-119.081, 34.078], [-119.439, 34.348], [-120.368, 34.447], [-120.623, 34.609], [-120.744, 35.157], [-121.715, 36.162], [-122.547, 37.552], [-122.512, 37.783], [-122.953, 38.114], [-123.727, 38.952], [-123.865, 39.767], [-124.398, 40.313], [-124.179, 41.142], [-124.214, 42], [-124.533, 42.766], [-124.142, 43.708], [-124.021, 44.616], [-123.899, 45.523], [-124.08, 46.865], [-124.396, 47.72], [-124.687, 48.184], [-124.566, 48.38], [-123.12, 48.04], [-122.587, 47.096], [-122.34, 47.36], [-122.5, 48.18], [-122.84, 49]]]] }, { "N": "Kazakhstan", "I": "KZ", "C": [[[[87.36, 49.215], [86.599, 48.549], [85.768, 48.456], [85.72, 47.453], [85.164, 47.001], [83.18, 47.33], [82.459, 45.54], [81.947, 45.317], [79.966, 44.918], [80.866, 43.18], [80.18, 42.92], [80.26, 42.35], [79.644, 42.497], [79.142, 42.856], [77.658, 42.961], [76, 42.988], [75.637, 42.878], [74.213, 43.298], [73.645, 43.091], [73.49, 42.501], [71.845, 42.845], [71.186, 42.704], [70.962, 42.266], [70.389, 42.081], [69.07, 41.384], [68.632, 40.669], [68.26, 40.662], [67.986, 41.136], [66.714, 41.168], [66.511, 41.988], [66.023, 41.995], [66.098, 42.998], [64.901, 43.728], [63.186, 43.65], [62.013, 43.504], [61.058, 44.406], [60.24, 44.784], [58.69, 45.5], [58.503, 45.587], [55.929, 44.996], [55.968, 41.309], [55.455, 41.26], [54.755, 42.044], [54.079, 42.324], [52.944, 42.116], [52.502, 41.783], [52.446, 42.027], [52.692, 42.444], [52.501, 42.792], [51.342, 43.133], [50.891, 44.031], [50.339, 44.284], [50.306, 44.61], [51.279, 44.515], [51.317, 45.246], [52.167, 45.408], [53.041, 45.259], [53.221, 46.235], [53.043, 46.853], [52.042, 46.805], [51.192, 47.049], [50.034, 46.609], [49.101, 46.399], [48.593, 46.561], [48.695, 47.076], [48.057, 47.744], [47.315, 47.716], [46.466, 48.394], [47.044, 49.152], [46.752, 49.356], [47.549, 50.455], [48.578, 49.875], [48.702, 50.605], [50.767, 51.693], [52.329, 51.719], [54.533, 51.026], [55.717, 50.622], [56.778, 51.044], [58.363, 51.064], [59.642, 50.545], [59.933, 50.842], [61.337, 50.799], [61.588, 51.273], [59.968, 51.96], [60.927, 52.448], [60.74, 52.72], [61.7, 52.98], [60.978, 53.665], [61.437, 54.006], [65.179, 54.354], [65.667, 54.601], [68.169, 54.97], [69.068, 55.385], [70.865, 55.17], [71.18, 54.133], [72.224, 54.377], [73.509, 54.036], [73.426, 53.49], [74.385, 53.547], [76.891, 54.491], [76.525, 54.177], [77.801, 53.404], [80.036, 50.865], [80.568, 51.388], [81.946, 50.812], [83.383, 51.069], [83.935, 50.889], [84.416, 50.311], [85.116, 50.117], [85.541, 49.693], [86.829, 49.827], [87.36, 49.215]]]] }, { "N": "Uzbekistan", "I": "UZ", "C": [[[[55.968, 41.309], [55.929, 44.996], [58.503, 45.587], [58.69, 45.5], [60.24, 44.784], [61.058, 44.406], [62.013, 43.504], [63.186, 43.65], [64.901, 43.728], [66.098, 42.998], [66.023, 41.995], [66.511, 41.988], [66.714, 41.168], [67.986, 41.136], [68.26, 40.662], [68.632, 40.669], [69.07, 41.384], [70.389, 42.081], [70.962, 42.266], [71.259, 42.168], [70.42, 41.52], [71.158, 41.144], [71.87, 41.393], [73.055, 40.866], [71.775, 40.146], [71.014, 40.244], [70.601, 40.219], [70.458, 40.496], [70.667, 40.96], [69.329, 40.728], [69.012, 40.086], [68.536, 39.533], [67.701, 39.58], [67.442, 39.14], [68.176, 38.902], [68.392, 38.157], [67.83, 37.145], [67.076, 37.356], [66.519, 37.363], [66.546, 37.975], [65.216, 38.403], [64.17, 38.892], [63.518, 39.363], [62.374, 40.054], [61.883, 41.085], [61.547, 41.266], [60.466, 41.22], [60.083, 41.425], [59.976, 42.223], [58.629, 42.752], [57.787, 42.171], [56.932, 41.826], [57.096, 41.322], [55.968, 41.309]]]] }, { "N": "Papua New Guinea", "I": "PG", "C": [[[[141, -2.6], [142.735, -3.289], [144.584, -3.861], [145.273, -4.374], [145.83, -4.876], [145.982, -5.466], [147.648, -6.084], [147.891, -6.614], [146.971, -6.722], [147.192, -7.388], [148.085, -8.044], [148.734, -9.105], [149.307, -9.071], [149.267, -9.514], [150.039, -9.684], [149.739, -9.873], [150.802, -10.294], [150.691, -10.583], [150.028, -10.652], [149.782, -10.393], [148.923, -10.281], [147.913, -10.13], [147.135, -9.492], [146.568, -8.943], [146.048, -8.067], [144.744, -7.63], [143.897, -7.915], [143.286, -8.245], [143.414, -8.983], [142.628, -9.327], [142.068, -9.16], [141.034, -9.118], [141.017, -5.859], [141, -2.6]]], [[[152.64, -3.66], [153.02, -3.98], [153.14, -4.5], [152.827, -4.766], [152.639, -4.176], [152.406, -3.79], [151.953, -3.462], [151.384, -3.035], [150.662, -2.741], [150.94, -2.5], [151.48, -2.78], [151.82, -3], [152.24, -3.24], [152.64, -3.66]]], [[[151.301, -5.841], [150.754, -6.084], [150.241, -6.318], [149.71, -6.317], [148.89, -6.026], [148.319, -5.747], [148.402, -5.438], [149.298, -5.584], [149.846, -5.506], [149.996, -5.026], [150.14, -5.001], [150.237, -5.532], [150.807, -5.456], [151.09, -5.114], [151.648, -4.757], [151.538, -4.168], [152.137, -4.149], [152.339, -4.313], [152.319, -4.868], [151.983, -5.478], [151.459, -5.56], [151.301, -5.841]]], [[[154.76, -5.34], [155.063, -5.567], [155.548, -6.201], [156.02, -6.54], [155.88, -6.82], [155.6, -6.92], [155.167, -6.536], [154.729, -5.901], [154.514, -5.139], [154.653, -5.042], [154.76, -5.34]]]] }, { "N": "Indonesia", "I": "ID", "C": [[[[141, -2.6], [141.017, -5.859], [141.034, -9.118], [140.143, -8.297], [139.128, -8.096], [138.881, -8.381], [137.614, -8.412], [138.039, -7.598], [138.669, -7.32], [138.408, -6.233], [137.928, -5.393], [135.989, -4.547], [135.165, -4.463], [133.663, -3.539], [133.368, -4.025], [132.984, -4.113], [132.757, -3.746], [132.754, -3.312], [131.99, -2.821], [133.067, -2.46], [133.78, -2.48], [133.696, -2.215], [132.232, -2.213], [131.836, -1.617], [130.943, -1.433], [130.52, -0.938], [131.868, -0.695], [132.38, -0.37], [133.986, -0.78], [134.143, -1.152], [134.423, -2.769], [135.458, -3.368], [136.293, -2.307], [137.441, -1.704], [138.33, -1.703], [139.185, -2.051], [139.927, -2.409], [141, -2.6]]], [[[124.969, -8.893], [125.07, -9.09], [125.089, -9.393], [124.436, -10.14], [123.58, -10.36], [123.46, -10.24], [123.55, -9.9], [123.98, -9.29], [124.969, -8.893]]], [[[134.21, -6.895], [134.113, -6.142], [134.29, -5.783], [134.5, -5.445], [134.727, -5.738], [134.725, -6.214], [134.21, -6.895]]], [[[117.882, 4.138], [117.313, 3.234], [118.048, 2.288], [117.876, 1.828], [118.997, 0.902], [117.812, 0.784], [117.478, 0.102], [117.522, -0.804], [116.56, -1.488], [116.534, -2.484], [116.148, -4.013], [116.001, -3.657], [114.865, -4.107], [114.469, -3.496], [113.756, -3.439], [113.257, -3.119], [112.068, -3.478], [111.703, -2.994], [111.048, -3.049], [110.224, -2.934], [110.071, -1.593], [109.572, -1.315], [109.092, -0.46], [108.953, 0.415], [109.069, 1.342], [109.663, 2.006], [109.83, 1.338], [110.514, 0.773], [111.159, 0.976], [111.798, 0.904], [112.38, 1.41], [112.86, 1.498], [113.806, 1.218], [114.621, 1.431], [115.134, 2.821], [115.519, 3.169], [115.866, 4.307], [117.015, 4.306], [117.882, 4.138]]], [[[129.371, -2.802], [130.471, -3.094], [130.835, -3.858], [129.991, -3.446], [129.155, -3.363], [128.591, -3.429], [127.899, -3.393], [128.136, -2.844], [129.371, -2.802]]], [[[126.875, -3.791], [126.184, -3.607], [125.989, -3.177], [127.001, -3.129], [127.249, -3.459], [126.875, -3.791]]], [[[127.932, 2.175], [128.004, 1.629], [128.595, 1.541], [128.688, 1.132], [128.636, 0.258], [128.12, 0.356], [127.968, -0.252], [128.38, -0.78], [128.1, -0.9], [127.696, -0.267], [127.399, 1.012], [127.601, 1.811], [127.932, 2.175]]], [[[122.928, 0.875], [124.078, 0.917], [125.066, 1.643], [125.241, 1.42], [124.437, 0.428], [123.686, 0.236], [122.723, 0.431], [121.057, 0.381], [120.183, 0.237], [120.041, -0.52], [120.936, -1.409], [121.476, -0.956], [123.341, -0.616], [123.258, -1.076], [122.823, -0.931], [122.389, -1.517], [121.508, -1.904], [122.455, -3.186], [122.272, -3.53], [123.171, -4.684], [123.162, -5.341], [122.629, -5.635], [122.236, -5.283], [122.72, -4.464], [121.738, -4.851], [121.489, -4.575], [121.619, -4.188], [120.898, -3.602], [120.972, -2.628], [120.305, -2.932], [120.39, -4.098], [120.431, -5.528], [119.797, -5.673], [119.367, -5.38], [119.654, -4.459], [119.499, -3.494], [119.078, -3.487], [118.768, -2.802], [119.181, -2.147], [119.323, -1.353], [119.826, 0.154], [120.036, 0.566], [120.886, 1.309], [121.667, 1.014], [122.928, 0.875]]], [[[120.295, -10.259], [118.968, -9.558], [119.9, -9.361], [120.426, -9.666], [120.776, -9.97], [120.716, -10.24], [120.295, -10.259]]], [[[121.342, -8.537], [122.007, -8.461], [122.904, -8.094], [122.757, -8.65], [121.254, -8.934], [119.924, -8.81], [119.921, -8.445], [120.715, -8.237], [121.342, -8.537]]], [[[118.261, -8.362], [118.878, -8.281], [119.127, -8.706], [117.97, -8.907], [117.278, -9.041], [116.74, -9.033], [117.084, -8.457], [117.632, -8.449], [117.9, -8.096], [118.261, -8.362]]], [[[108.487, -6.422], [108.623, -6.778], [110.539, -6.877], [110.76, -6.465], [112.615, -6.946], [112.979, -7.594], [114.479, -7.777], [115.706, -8.371], [114.565, -8.752], [113.465, -8.349], [112.56, -8.376], [111.522, -8.302], [110.586, -8.123], [109.428, -7.741], [108.694, -7.642], [108.278, -7.767], [106.454, -7.355], [106.281, -6.925], [105.365, -6.851], [106.052, -5.896], [107.265, -5.955], [108.072, -6.346], [108.487, -6.422]]], [[[104.37, -1.085], [104.539, -1.782], [104.888, -2.34], [105.622, -2.429], [106.109, -3.062], [105.857, -4.306], [105.818, -5.852], [104.71, -5.873], [103.868, -5.037], [102.584, -4.22], [102.156, -3.614], [101.399, -2.8], [100.903, -2.05], [100.142, -0.65], [99.264, 0.183], [98.97, 1.043], [98.601, 1.824], [97.7, 2.453], [97.177, 3.309], [96.424, 3.869], [95.381, 4.971], [95.293, 5.48], [95.937, 5.44], [97.485, 5.246], [98.369, 4.268], [99.143, 3.59], [99.694, 3.174], [100.641, 2.099], [101.658, 2.084], [102.498, 1.399], [103.077, 0.561], [103.838, 0.105], [103.438, -0.712], [104.011, -1.059], [104.37, -1.085]]]] }, { "N": "Argentina", "I": "AR", "C": [[[[-68.634, -52.636], [-68.25, -53.1], [-67.75, -53.85], [-66.45, -54.45], [-65.05, -54.7], [-65.5, -55.2], [-66.45, -55.25], [-66.96, -54.897], [-67.562, -54.87], [-68.633, -54.87], [-68.634, -52.636]]], [[[-57.625, -30.216], [-57.875, -31.017], [-58.142, -32.045], [-58.133, -33.041], [-58.35, -33.263], [-58.427, -33.909], [-58.495, -34.431], [-57.226, -35.288], [-57.362, -35.977], [-56.737, -36.413], [-56.788, -36.902], [-57.749, -38.184], [-59.232, -38.72], [-61.237, -38.928], [-62.336, -38.828], [-62.126, -39.424], [-62.331, -40.173], [-62.146, -40.677], [-62.746, -41.029], [-63.77, -41.167], [-64.732, -40.803], [-65.118, -41.064], [-64.979, -42.058], [-64.303, -42.359], [-63.756, -42.044], [-63.458, -42.563], [-64.379, -42.874], [-65.182, -43.495], [-65.329, -44.501], [-65.565, -45.037], [-66.51, -45.04], [-67.294, -45.552], [-67.581, -46.302], [-66.597, -47.034], [-65.641, -47.236], [-65.985, -48.133], [-67.166, -48.697], [-67.816, -49.87], [-68.729, -50.264], [-69.139, -50.733], [-68.816, -51.771], [-68.15, -52.35], [-68.572, -52.299], [-69.498, -52.143], [-71.915, -52.009], [-72.329, -51.426], [-72.31, -50.677], [-72.976, -50.741], [-73.328, -50.379], [-73.415, -49.318], [-72.648, -48.879], [-72.331, -48.244], [-72.447, -47.739], [-71.917, -46.885], [-71.552, -45.561], [-71.659, -44.974], [-71.223, -44.784], [-71.33, -44.408], [-71.794, -44.207], [-71.464, -43.788], [-71.915, -43.409], [-72.149, -42.255], [-71.747, -42.051], [-71.916, -40.832], [-71.681, -39.808], [-71.414, -38.916], [-70.815, -38.553], [-71.119, -37.577], [-71.122, -36.658], [-70.365, -36.005], [-70.388, -35.17], [-69.817, -34.194], [-69.815, -33.274], [-70.074, -33.091], [-70.535, -31.365], [-69.919, -30.336], [-70.014, -29.368], [-69.656, -28.459], [-69.001, -27.521], [-68.296, -26.899], [-68.595, -26.507], [-68.386, -26.185], [-68.418, -24.519], [-67.328, -24.025], [-66.985, -22.986], [-67.107, -22.736], [-66.273, -21.832], [-64.965, -22.076], [-64.377, -22.798], [-63.987, -21.994], [-62.846, -22.035], [-62.685, -22.249], [-60.847, -23.881], [-60.029, -24.033], [-58.807, -24.771], [-57.777, -25.162], [-57.634, -25.604], [-58.618, -27.124], [-57.61, -27.396], [-56.487, -27.548], [-55.696, -27.388], [-54.789, -26.622], [-54.625, -25.739], [-54.13, -25.548], [-53.628, -26.125], [-53.649, -26.923], [-54.491, -27.475], [-55.162, -27.882], [-56.291, -28.853], [-57.625, -30.216]]]] }, { "N": "Chile", "I": "CL", "C": [[[[-68.634, -52.636], [-68.633, -54.87], [-67.562, -54.87], [-66.96, -54.897], [-67.291, -55.301], [-68.149, -55.612], [-68.64, -55.58], [-69.232, -55.499], [-69.958, -55.198], [-71.006, -55.054], [-72.264, -54.495], [-73.285, -53.958], [-74.663, -52.837], [-73.838, -53.047], [-72.434, -53.715], [-71.108, -54.074], [-70.592, -53.616], [-70.267, -52.931], [-69.346, -52.518], [-68.634, -52.636]]], [[[-69.59, -17.58], [-69.1, -18.26], [-68.967, -18.982], [-68.442, -19.405], [-68.757, -20.373], [-68.22, -21.494], [-67.828, -22.873], [-67.107, -22.736], [-66.985, -22.986], [-67.328, -24.025], [-68.418, -24.519], [-68.386, -26.185], [-68.595, -26.507], [-68.296, -26.899], [-69.001, -27.521], [-69.656, -28.459], [-70.014, -29.368], [-69.919, -30.336], [-70.535, -31.365], [-70.074, -33.091], [-69.815, -33.274], [-69.817, -34.194], [-70.388, -35.17], [-70.365, -36.005], [-71.122, -36.658], [-71.119, -37.577], [-70.815, -38.553], [-71.414, -38.916], [-71.681, -39.808], [-71.916, -40.832], [-71.747, -42.051], [-72.149, -42.255], [-71.915, -43.409], [-71.464, -43.788], [-71.794, -44.207], [-71.33, -44.408], [-71.223, -44.784], [-71.659, -44.974], [-71.552, -45.561], [-71.917, -46.885], [-72.447, -47.739], [-72.331, -48.244], [-72.648, -48.879], [-73.415, -49.318], [-73.328, -50.379], [-72.976, -50.741], [-72.31, -50.677], [-72.329, -51.426], [-71.915, -52.009], [-69.498, -52.143], [-68.572, -52.299], [-69.461, -52.292], [-69.943, -52.538], [-70.845, -52.899], [-71.006, -53.833], [-71.43, -53.856], [-72.558, -53.531], [-73.703, -52.835], [-73.703, -52.835], [-74.947, -52.263], [-75.26, -51.629], [-74.977, -51.043], [-75.48, -50.378], [-75.608, -48.674], [-75.183, -47.712], [-74.127, -46.939], [-75.644, -46.648], [-74.692, -45.764], [-74.352, -44.103], [-73.24, -44.455], [-72.718, -42.383], [-73.389, -42.118], [-73.701, -43.366], [-74.332, -43.225], [-74.018, -41.795], [-73.677, -39.942], [-73.218, -39.259], [-73.506, -38.283], [-73.588, -37.156], [-73.167, -37.124], [-72.553, -35.509], [-71.862, -33.909], [-71.438, -32.419], [-71.669, -30.921], [-71.37, -30.096], [-71.49, -28.861], [-70.905, -27.64], [-70.725, -25.706], [-70.404, -23.629], [-70.091, -21.393], [-70.164, -19.756], [-70.373, -18.348], [-69.858, -18.093], [-69.59, -17.58]]]] }, { "N": "Democratic Republic of the Congo", "I": "CD", "C": [[[[29.34, -4.5], [29.52, -5.42], [29.42, -5.94], [29.62, -6.52], [30.2, -7.08], [30.74, -8.34], [30.74, -8.34], [30.346, -8.238], [29.003, -8.407], [28.735, -8.527], [28.45, -9.165], [28.674, -9.606], [28.496, -10.79], [28.372, -11.794], [28.642, -11.972], [29.342, -12.361], [29.616, -12.179], [29.7, -13.257], [28.934, -13.249], [28.524, -12.699], [28.155, -12.272], [27.389, -12.133], [27.164, -11.609], [26.553, -11.924], [25.752, -11.785], [25.418, -11.331], [24.783, -11.239], [24.315, -11.263], [24.257, -10.952], [23.912, -10.927], [23.457, -10.868], [22.837, -11.018], [22.403, -10.993], [22.155, -11.085], [22.209, -9.895], [21.875, -9.524], [21.802, -8.909], [21.949, -8.306], [21.746, -7.92], [21.728, -7.291], [20.515, -7.3], [20.602, -6.939], [20.092, -6.943], [20.038, -7.116], [19.418, -7.155], [19.167, -7.738], [19.017, -7.988], [18.464, -7.847], [18.134, -7.988], [17.473, -8.069], [17.09, -7.546], [16.86, -7.222], [16.573, -6.623], [16.327, -5.877], [13.376, -5.864], [13.025, -5.984], [12.735, -5.966], [12.322, -6.1], [12.182, -5.79], [12.437, -5.684], [12.468, -5.248], [12.632, -4.991], [12.996, -4.781], [13.258, -4.883], [13.6, -4.5], [14.145, -4.51], [14.209, -4.793], [14.583, -4.97], [15.171, -4.344], [15.754, -3.855], [16.006, -3.535], [15.973, -2.712], [16.407, -1.741], [16.865, -1.226], [17.524, -0.744], [17.639, -0.425], [17.664, -0.058], [17.827, 0.289], [17.774, 0.856], [17.899, 1.742], [18.094, 2.366], [18.394, 2.9], [18.453, 3.504], [18.543, 4.202], [18.932, 4.71], [19.468, 5.032], [20.291, 4.692], [20.928, 4.323], [21.659, 4.224], [22.405, 4.029], [22.704, 4.633], [22.841, 4.71], [23.297, 4.61], [24.411, 5.109], [24.805, 4.897], [25.129, 4.927], [25.279, 5.17], [25.65, 5.256], [26.403, 5.151], [27.044, 5.128], [27.374, 5.234], [27.98, 4.408], [28.429, 4.287], [28.697, 4.455], [29.159, 4.389], [29.716, 4.601], [29.954, 4.174], [30.834, 3.509], [30.834, 3.509], [30.773, 2.34], [31.174, 2.204], [30.853, 1.849], [30.469, 1.584], [30.086, 1.062], [29.876, 0.597], [29.82, -0.205], [29.588, -0.587], [29.579, -1.341], [29.292, -1.62], [29.255, -2.215], [29.117, -2.292], [29.025, -2.839], [29.276, -3.294], [29.34, -4.5]]]] }, { "N": "Somalia", "I": "SO", "C": [[[[41.585, -1.683], [40.993, -0.858], [40.981, 2.785], [41.855, 3.919], [42.129, 4.234], [42.77, 4.253], [43.661, 4.958], [44.964, 5.002], [47.789, 8.003], [48.487, 8.838], [48.938, 9.452], [48.938, 9.974], [48.938, 10.982], [48.942, 11.394], [48.948, 11.411], [48.948, 11.411], [49.268, 11.43], [49.729, 11.579], [50.259, 11.68], [50.732, 12.022], [51.111, 12.025], [51.134, 11.748], [51.042, 11.167], [51.045, 10.641], [50.834, 10.28], [50.552, 9.199], [50.071, 8.082], [49.453, 6.805], [48.595, 5.339], [47.741, 4.219], [46.565, 2.855], [45.564, 2.046], [44.068, 1.053], [43.136, 0.292], [42.042, -0.919], [41.811, -1.446], [41.585, -1.683]]]] }, { "N": "Kenya", "I": "KE", "C": [[[[39.202, -4.677], [37.767, -3.677], [37.699, -3.097], [34.073, -1.06], [33.904, -0.95], [33.894, 0.11], [34.18, 0.515], [34.672, 1.177], [35.036, 1.906], [34.596, 3.054], [34.479, 3.556], [34.005, 4.25], [34.62, 4.847], [35.298, 5.506], [35.817, 5.338], [35.817, 4.777], [36.159, 4.448], [36.855, 4.448], [38.121, 3.599], [38.437, 3.589], [38.671, 3.616], [38.893, 3.501], [39.559, 3.422], [39.855, 3.839], [40.768, 4.257], [41.172, 3.919], [41.855, 3.919], [40.981, 2.785], [40.993, -0.858], [41.585, -1.683], [40.885, -2.083], [40.638, -2.5], [40.263, -2.573], [40.121, -3.278], [39.8, -3.681], [39.605, -4.347], [39.202, -4.677]]]] }, { "N": "Sudan", "I": "SD", "C": [[[[24.567, 8.229], [23.806, 8.666], [23.459, 8.954], [23.395, 9.265], [23.557, 9.681], [23.554, 10.089], [22.978, 10.714], [22.864, 11.142], [22.876, 11.385], [22.509, 11.679], [22.498, 12.26], [22.288, 12.646], [21.937, 12.588], [22.038, 12.955], [22.297, 13.372], [22.183, 13.786], [22.512, 14.093], [22.304, 14.327], [22.568, 14.944], [23.025, 15.681], [23.887, 15.611], [23.838, 19.58], [23.85, 20], [25, 20.003], [25, 22], [29.02, 22], [32.9, 22], [36.866, 22], [37.189, 21.019], [36.969, 20.837], [37.115, 19.808], [37.482, 18.614], [37.863, 18.368], [38.41, 17.998], [37.904, 17.428], [37.167, 17.263], [36.853, 16.957], [36.754, 16.292], [36.323, 14.822], [36.43, 14.422], [36.27, 13.563], [35.864, 12.578], [35.26, 12.083], [34.832, 11.319], [34.731, 10.91], [34.257, 10.63], [33.962, 9.584], [33.975, 8.685], [33.963, 9.464], [33.825, 9.484], [33.842, 9.982], [33.722, 10.325], [33.207, 10.72], [33.087, 11.441], [33.207, 12.179], [32.743, 12.248], [32.675, 12.025], [32.074, 11.973], [32.314, 11.681], [32.4, 11.081], [31.851, 10.531], [31.353, 9.81], [30.838, 9.707], [29.997, 10.291], [29.619, 10.085], [29.516, 9.793], [29.001, 9.604], [28.967, 9.398], [27.971, 9.398], [27.834, 9.604], [27.113, 9.639], [26.752, 9.467], [26.477, 9.553], [25.962, 10.136], [25.791, 10.411], [25.07, 10.274], [24.795, 9.81], [24.537, 8.918], [24.194, 8.729], [23.887, 8.62], [24.567, 8.229]]]] }, { "N": "Chad", "I": "TD", "C": [[[[23.838, 19.58], [23.887, 15.611], [23.025, 15.681], [22.568, 14.944], [22.304, 14.327], [22.512, 14.093], [22.183, 13.786], [22.297, 13.372], [22.038, 12.955], [21.937, 12.588], [22.288, 12.646], [22.498, 12.26], [22.509, 11.679], [22.876, 11.385], [22.864, 11.142], [22.231, 10.972], [21.724, 10.567], [21.001, 9.476], [20.06, 9.013], [19.094, 9.075], [18.812, 8.983], [18.911, 8.631], [18.39, 8.281], [17.965, 7.891], [16.706, 7.508], [16.456, 7.735], [16.291, 7.754], [16.106, 7.497], [15.279, 7.422], [15.436, 7.693], [15.121, 8.382], [14.98, 8.796], [14.544, 8.966], [13.954, 9.549], [14.171, 10.021], [14.627, 9.921], [14.909, 9.992], [15.468, 9.982], [14.924, 10.891], [14.96, 11.556], [14.893, 12.219], [14.496, 12.859], [14.596, 13.33], [13.954, 13.353], [13.957, 13.997], [13.54, 14.367], [13.972, 15.684], [15.248, 16.627], [15.3, 17.928], [15.686, 19.957], [15.903, 20.388], [15.487, 20.73], [15.471, 21.048], [15.097, 21.309], [14.851, 22.863], [15.861, 23.41], [19.849, 21.495], [23.838, 19.58]]]] }, { "N": "Haiti", "I": "HT", "C": [[[[-71.712, 19.714], [-71.625, 19.17], [-71.701, 18.785], [-71.945, 18.617], [-71.688, 18.317], [-71.708, 18.045], [-72.372, 18.215], [-72.844, 18.146], [-73.455, 18.218], [-73.922, 18.031], [-74.458, 18.343], [-74.37, 18.665], [-73.45, 18.526], [-72.695, 18.446], [-72.335, 18.668], [-72.792, 19.102], [-72.784, 19.484], [-73.415, 19.64], [-73.19, 19.916], [-72.58, 19.872], [-71.712, 19.714]]]] }, { "N": "Dominican Republic", "I": "DO", "C": [[[[-71.708, 18.045], [-71.688, 18.317], [-71.945, 18.617], [-71.701, 18.785], [-71.625, 19.17], [-71.712, 19.714], [-71.587, 19.885], [-70.807, 19.88], [-70.214, 19.623], [-69.951, 19.648], [-69.769, 19.293], [-69.222, 19.313], [-69.254, 19.015], [-68.809, 18.979], [-68.318, 18.612], [-68.689, 18.205], [-69.165, 18.423], [-69.624, 18.381], [-69.953, 18.428], [-70.133, 18.246], [-70.517, 18.184], [-70.669, 18.427], [-71, 18.283], [-71.4, 17.599], [-71.658, 17.758], [-71.708, 18.045]]]] }, { "N": "Russia", "I": "RU", "C": [[[[178.725, 71.099], [180, 71.516], [180, 70.832], [178.903, 70.781], [178.725, 71.099]]], [[[93.778, 81.025], [95.941, 81.25], [97.884, 80.747], [100.187, 79.78], [99.94, 78.881], [97.758, 78.756], [94.973, 79.045], [93.313, 79.427], [92.545, 80.144], [91.181, 80.341], [93.778, 81.025]]], [[[102.838, 79.281], [105.372, 78.713], [105.075, 78.307], [99.438, 77.921], [101.265, 79.234], [102.086, 79.346], [102.838, 79.281]]], [[[138.831, 76.137], [141.472, 76.093], [145.086, 75.563], [144.3, 74.82], [140.614, 74.848], [138.955, 74.611], [136.974, 75.262], [137.512, 75.949], [138.831, 76.137]]], [[[148.222, 75.346], [150.732, 75.084], [149.576, 74.689], [147.977, 74.778], [146.119, 75.173], [146.358, 75.497], [148.222, 75.346]]], [[[139.863, 73.37], [140.812, 73.765], [142.062, 73.858], [143.483, 73.475], [143.604, 73.212], [142.088, 73.205], [140.038, 73.317], [139.863, 73.37]]], [[[44.847, 80.59], [46.799, 80.772], [48.318, 80.784], [48.523, 80.515], [49.097, 80.754], [50.04, 80.919], [51.523, 80.7], [51.136, 80.547], [49.794, 80.415], [48.894, 80.34], [48.755, 80.175], [47.586, 80.01], [46.503, 80.247], [47.072, 80.559], [44.847, 80.59]]], [[[22.731, 54.328], [20.892, 54.313], [19.661, 54.426], [19.888, 54.866], [21.268, 55.19], [22.316, 55.015], [22.758, 54.857], [22.651, 54.583], [22.731, 54.328]]], [[[53.508, 73.75], [55.902, 74.627], [55.632, 75.081], [57.869, 75.609], [61.17, 76.252], [64.498, 76.439], [66.211, 76.81], [68.157, 76.94], [68.852, 76.545], [68.181, 76.234], [64.637, 75.738], [61.584, 75.261], [58.477, 74.309], [56.987, 73.333], [55.419, 72.371], [55.623, 71.541], [57.536, 70.72], [56.945, 70.633], [53.677, 70.763], [53.412, 71.207], [51.602, 71.475], [51.456, 72.015], [52.478, 72.229], [52.444, 72.775], [54.428, 73.628], [53.508, 73.75]]], [[[142.915, 53.705], [143.261, 52.741], [143.235, 51.757], [143.648, 50.748], [144.654, 48.976], [143.174, 49.307], [142.559, 47.862], [143.533, 46.837], [143.505, 46.138], [142.748, 46.741], [142.092, 45.967], [141.907, 46.806], [142.018, 47.78], [141.904, 48.859], [142.136, 49.615], [142.18, 50.952], [141.594, 51.935], [141.683, 53.302], [142.607, 53.762], [142.21, 54.225], [142.655, 54.366], [142.915, 53.705]]], [[[-174.928, 67.206], [-175.014, 66.584], [-174.34, 66.336], [-174.572, 67.062], [-171.857, 66.913], [-169.9, 65.977], [-170.891, 65.541], [-172.53, 65.438], [-172.555, 64.461], [-172.955, 64.253], [-173.892, 64.283], [-174.654, 64.631], [-175.984, 64.923], [-176.207, 65.357], [-177.223, 65.52], [-178.36, 65.391], [-178.903, 65.74], [-178.686, 66.112], [-179.884, 65.875], [-179.433, 65.404], [-180, 64.98], [-180, 68.964], [-177.55, 68.2], [-174.928, 67.206]]], [[[-178.694, 70.893], [-180, 70.832], [-180, 71.516], [-179.872, 71.558], [-179.024, 71.556], [-177.578, 71.269], [-177.664, 71.133], [-178.694, 70.893]]], [[[49.101, 46.399], [48.645, 45.806], [47.676, 45.641], [46.682, 44.609], [47.591, 43.66], [47.493, 42.987], [48.584, 41.809], [48.584, 41.809], [47.987, 41.406], [47.816, 41.151], [47.373, 41.22], [46.686, 41.827], [46.405, 41.861], [45.776, 42.092], [45.47, 42.503], [44.538, 42.712], [43.931, 42.555], [43.756, 42.741], [42.394, 43.22], [40.922, 43.382], [40.077, 43.553], [39.955, 43.435], [38.68, 44.28], [37.539, 44.657], [36.675, 45.245], [37.403, 45.405], [38.233, 46.241], [37.674, 46.637], [39.148, 47.045], [39.121, 47.263], [38.224, 47.102], [38.255, 47.546], [38.771, 47.826], [39.738, 47.899], [39.896, 48.232], [39.675, 48.784], [40.081, 49.307], [40.069, 49.601], [38.595, 49.926], [38.011, 49.916], [37.393, 50.384], [36.626, 50.226], [35.356, 50.577], [35.378, 50.774], [35.022, 51.208], [34.225, 51.256], [34.142, 51.566], [34.392, 51.769], [33.753, 52.335], [32.716, 52.238], [32.412, 52.289], [32.159, 52.061], [31.786, 52.102], [31.786, 52.102], [31.54, 52.742], [31.305, 53.074], [31.498, 53.167], [32.305, 53.133], [32.694, 53.351], [32.406, 53.618], [31.731, 53.794], [31.791, 53.975], [31.384, 54.157], [30.758, 54.812], [30.972, 55.082], [30.874, 55.551], [29.896, 55.789], [29.372, 55.67], [29.23, 55.918], [28.177, 56.169], [27.855, 56.759], [27.77, 57.244], [27.288, 57.475], [27.717, 57.792], [27.42, 58.725], [28.132, 59.301], [27.981, 59.475], [27.981, 59.475], [29.118, 60.028], [28.07, 60.504], [28.07, 60.504], [30.211, 61.78], [31.14, 62.358], [31.516, 62.868], [30.036, 63.553], [30.445, 64.204], [29.544, 64.949], [30.218, 65.806], [29.055, 66.944], [29.977, 67.698], [28.446, 68.365], [28.592, 69.065], [29.4, 69.157], [31.101, 69.558], [31.101, 69.558], [32.133, 69.906], [33.775, 69.301], [36.514, 69.063], [40.292, 67.932], [41.06, 67.457], [41.126, 66.792], [40.016, 66.266], [38.383, 66], [33.919, 66.76], [33.184, 66.633], [34.815, 65.9], [34.879, 65.436], [34.944, 64.414], [36.231, 64.109], [37.013, 63.85], [37.142, 64.335], [36.54, 64.764], [37.176, 65.143], [39.593, 64.521], [40.436, 64.764], [39.763, 65.497], [42.093, 66.476], [43.016, 66.419], [43.95, 66.069], [44.532, 66.756], [43.698, 67.352], [44.188, 67.951], [43.453, 68.571], [46.25, 68.25], [46.821, 67.69], [45.555, 67.567], [45.562, 67.01], [46.349, 66.668], [47.894, 66.885], [48.139, 67.522], [50.228, 67.999], [53.717, 68.857], [54.472, 68.808], [53.486, 68.201], [54.726, 68.097], [55.443, 68.439], [57.317, 68.466], [58.802, 68.881], [59.941, 68.278], [61.078, 68.941], [60.03, 69.52], [60.55, 69.85], [63.504, 69.547], [64.888, 69.235], [68.512, 68.092], [69.181, 68.616], [68.164, 69.144], [68.135, 69.356], [66.93, 69.455], [67.26, 69.929], [66.725, 70.709], [66.695, 71.029], [68.54, 71.935], [69.196, 72.843], [69.94, 73.04], [72.588, 72.776], [72.796, 72.22], [71.848, 71.409], [72.47, 71.09], [72.792, 70.391], [72.565, 69.021], [73.668, 68.408], [73.239, 67.74], [71.28, 66.32], [72.423, 66.173], [72.821, 66.533], [73.921, 66.789], [74.187, 67.284], [75.052, 67.76], [74.469, 68.329], [74.936, 68.989], [73.842, 69.071], [73.602, 69.628], [74.4, 70.632], [73.101, 71.447], [74.891, 72.121], [74.659, 72.832], [75.158, 72.855], [75.684, 72.301], [75.289, 71.336], [76.359, 71.153], [75.903, 71.874], [77.577, 72.267], [79.652, 72.32], [81.5, 71.75], [80.611, 72.583], [80.511, 73.648], [82.25, 73.85], [84.655, 73.806], [86.822, 73.937], [86.01, 74.46], [87.167, 75.116], [88.316, 75.144], [90.26, 75.64], [92.901, 75.773], [93.234, 76.047], [95.86, 76.14], [96.678, 75.915], [98.923, 76.447], [100.76, 76.43], [101.035, 76.862], [101.991, 77.288], [104.352, 77.698], [106.067, 77.374], [104.705, 77.127], [106.97, 76.974], [107.24, 76.48], [108.154, 76.723], [111.077, 76.71], [113.332, 76.222], [114.134, 75.848], [113.885, 75.328], [112.779, 75.032], [110.151, 74.477], [109.4, 74.18], [110.64, 74.04], [112.119, 73.788], [113.02, 73.977], [113.53, 73.335], [113.969, 73.595], [115.568, 73.753], [118.776, 73.588], [119.02, 73.12], [123.201, 72.971], [123.258, 73.735], [125.38, 73.56], [126.976, 73.565], [128.591, 73.039], [129.052, 72.399], [128.46, 71.98], [129.716, 71.193], [131.289, 70.787], [132.254, 71.836], [133.858, 71.386], [135.562, 71.655], [137.498, 71.348], [138.234, 71.628], [139.87, 71.488], [139.148, 72.416], [140.468, 72.849], [149.5, 72.2], [150.351, 71.606], [152.969, 70.842], [157.007, 71.031], [158.998, 70.867], [159.83, 70.453], [159.709, 69.722], [160.941, 69.437], [162.279, 69.642], [164.052, 69.668], [165.94, 69.472], [167.836, 69.583], [169.578, 68.694], [170.817, 69.014], [170.008, 69.653], [170.453, 70.097], [173.644, 69.817], [175.724, 69.877], [178.6, 69.4], [180, 68.964], [180, 64.98], [179.993, 64.974], [178.707, 64.535], [177.411, 64.608], [178.313, 64.076], [178.908, 63.252], [179.37, 62.983], [179.486, 62.569], [179.228, 62.304], [177.364, 62.522], [174.569, 61.769], [173.68, 61.653], [172.15, 60.95], [170.698, 60.336], [170.331, 59.882], [168.9, 60.574], [166.295, 59.789], [165.84, 60.16], [164.877, 59.732], [163.539, 59.869], [163.217, 59.211], [162.017, 58.243], [162.053, 57.839], [163.192, 57.615], [163.058, 56.159], [162.13, 56.122], [161.701, 55.286], [162.117, 54.855], [160.369, 54.344], [160.022, 53.203], [158.531, 52.959], [158.231, 51.943], [156.79, 51.011], [156.42, 51.7], [155.992, 53.159], [155.434, 55.381], [155.914, 56.768], [156.758, 57.365], [156.81, 57.832], [158.364, 58.056], [160.151, 59.315], [161.872, 60.343], [163.67, 61.141], [164.474, 62.551], [163.258, 62.466], [162.658, 61.642], [160.121, 60.544], [159.302, 61.774], [156.721, 61.434], [154.218, 59.758], [155.044, 59.145], [152.812, 58.884], [151.266, 58.781], [151.338, 59.504], [149.784, 59.656], [148.545, 59.164], [145.487, 59.336], [142.198, 59.04], [138.958, 57.088], [135.126, 54.73], [136.702, 54.604], [137.193, 53.977], [138.165, 53.755], [138.805, 54.255], [139.902, 54.19], [141.345, 53.09], [141.379, 52.239], [140.597, 51.24], [140.513, 50.046], [140.062, 48.447], [138.555, 47], [138.22, 46.308], [136.862, 45.144], [135.515, 43.989], [134.869, 43.398], [133.537, 42.811], [132.906, 42.798], [132.278, 43.285], [130.936, 42.553], [130.78, 42.22], [130.78, 42.22], [130.78, 42.22], [130.78, 42.22], [130.64, 42.395], [130.64, 42.395], [130.634, 42.903], [131.145, 42.93], [131.289, 44.112], [131.025, 44.968], [131.883, 45.321], [133.097, 45.144], [133.77, 46.117], [134.112, 47.212], [134.501, 47.578], [135.026, 48.478], [133.374, 48.183], [132.507, 47.789], [130.987, 47.79], [130.582, 48.73], [129.398, 49.441], [127.657, 49.76], [127.287, 50.74], [126.939, 51.354], [126.564, 51.784], [125.946, 52.793], [125.068, 53.161], [123.571, 53.459], [122.246, 53.432], [121.003, 53.251], [120.177, 52.754], [120.726, 52.516], [120.738, 51.964], [120.182, 51.644], [119.279, 50.583], [119.288, 50.143], [117.879, 49.511], [116.679, 49.889], [115.486, 49.805], [114.962, 50.14], [114.362, 50.248], [112.898, 49.544], [111.581, 49.378], [110.662, 49.13], [109.402, 49.293], [108.475, 49.283], [107.868, 49.794], [106.889, 50.274], [105.887, 50.406], [104.622, 50.275], [103.677, 50.09], [102.256, 50.511], [102.065, 51.26], [100.889, 51.517], [99.982, 51.634], [98.861, 52.047], [97.826, 51.011], [98.232, 50.422], [97.26, 49.726], [95.814, 49.977], [94.816, 50.013], [94.148, 50.481], [93.104, 50.495], [92.235, 50.802], [90.714, 50.332], [88.806, 49.471], [87.751, 49.297], [87.36, 49.215], [86.829, 49.827], [85.541, 49.693], [85.116, 50.117], [84.416, 50.311], [83.935, 50.889], [83.383, 51.069], [81.946, 50.812], [80.568, 51.388], [80.036, 50.865], [77.801, 53.404], [76.525, 54.177], [76.891, 54.491], [74.385, 53.547], [73.426, 53.49], [73.509, 54.036], [72.224, 54.377], [71.18, 54.133], [70.865, 55.17], [69.068, 55.385], [68.169, 54.97], [65.667, 54.601], [65.179, 54.354], [61.437, 54.006], [60.978, 53.665], [61.7, 52.98], [60.74, 52.72], [60.927, 52.448], [59.968, 51.96], [61.588, 51.273], [61.337, 50.799], [59.933, 50.842], [59.642, 50.545], [58.363, 51.064], [56.778, 51.044], [55.717, 50.622], [54.533, 51.026], [52.329, 51.719], [50.767, 51.693], [48.702, 50.605], [48.578, 49.875], [47.549, 50.455], [46.752, 49.356], [47.044, 49.152], [46.466, 48.394], [47.315, 47.716], [48.057, 47.744], [48.695, 47.076], [48.593, 46.561], [49.101, 46.399]]]] }, { "N": "Bahamas", "I": "BS", "C": [[[[-78.98, 26.79], [-78.51, 26.87], [-77.85, 26.84], [-77.82, 26.58], [-78.91, 26.42], [-78.98, 26.79]]], [[[-77.79, 27.04], [-77, 26.59], [-77.173, 25.879], [-77.356, 26.007], [-77.34, 26.53], [-77.788, 26.925], [-77.79, 27.04]]], [[[-78.191, 25.21], [-77.89, 25.17], [-77.54, 24.34], [-77.535, 23.76], [-77.78, 23.71], [-78.034, 24.286], [-78.408, 24.576], [-78.191, 25.21]]]] }, { "N": "Falkland Islands", "I": "FK", "C": [[[[-61.2, -51.85], [-60, -51.25], [-59.15, -51.5], [-58.55, -51.1], [-57.75, -51.55], [-58.05, -51.9], [-59.4, -52.2], [-59.85, -51.85], [-60.7, -52.3], [-61.2, -51.85]]]] }, { "N": "Norway", "I": "NO", "C": [[[[15.143, 79.674], [15.523, 80.016], [16.991, 80.051], [18.252, 79.702], [21.544, 78.956], [19.027, 78.563], [18.472, 77.827], [17.594, 77.638], [17.118, 76.809], [15.913, 76.77], [13.763, 77.38], [14.67, 77.736], [13.171, 78.025], [11.222, 78.869], [10.445, 79.652], [13.171, 80.01], [13.719, 79.66], [15.143, 79.674]]], [[[27.408, 80.056], [25.925, 79.518], [23.024, 79.4], [20.075, 79.567], [19.897, 79.842], [18.462, 79.86], [17.368, 80.319], [20.456, 80.598], [21.908, 80.358], [22.919, 80.657], [25.448, 80.407], [27.408, 80.056]]], [[[24.724, 77.854], [22.49, 77.445], [20.726, 77.677], [21.416, 77.935], [20.812, 78.255], [22.884, 78.455], [23.281, 78.08], [24.724, 77.854]]], [[[31.101, 69.558], [29.4, 69.157], [28.592, 69.065], [29.016, 69.766], [27.732, 70.164], [26.18, 69.825], [25.689, 69.092], [24.736, 68.65], [23.662, 68.891], [22.356, 68.842], [21.245, 69.37], [20.646, 69.106], [20.025, 69.065], [19.879, 68.407], [17.994, 68.567], [17.729, 68.011], [16.769, 68.014], [16.109, 67.302], [15.108, 66.194], [13.556, 64.787], [13.92, 64.445], [13.572, 64.049], [12.58, 64.066], [11.931, 63.128], [11.992, 61.8], [12.631, 61.294], [12.3, 60.118], [11.468, 59.432], [11.027, 58.856], [10.357, 59.47], [8.382, 58.313], [7.049, 58.079], [5.666, 58.588], [5.308, 59.663], [4.992, 61.971], [5.913, 62.614], [8.553, 63.454], [10.528, 64.486], [12.358, 65.88], [14.761, 67.811], [16.436, 68.563], [19.184, 69.817], [21.378, 70.255], [23.024, 70.202], [24.547, 71.03], [26.37, 70.986], [28.166, 71.185], [31.293, 70.454], [30.005, 70.186], [31.101, 69.558]]]] }, { "N": "Greenland", "I": "GL", "C": [[[[-46.764, 82.628], [-43.406, 83.225], [-39.898, 83.18], [-38.622, 83.549], [-35.088, 83.645], [-27.1, 83.52], [-20.845, 82.727], [-22.692, 82.342], [-26.518, 82.298], [-31.9, 82.2], [-31.396, 82.022], [-27.857, 82.132], [-24.844, 81.787], [-22.903, 82.093], [-22.072, 81.734], [-23.17, 81.153], [-20.624, 81.525], [-15.768, 81.912], [-12.77, 81.719], [-12.209, 81.292], [-16.285, 80.58], [-16.85, 80.35], [-20.046, 80.177], [-17.73, 80.129], [-18.9, 79.4], [-19.705, 78.751], [-19.674, 77.639], [-18.473, 76.986], [-20.035, 76.944], [-21.679, 76.628], [-19.834, 76.098], [-19.599, 75.248], [-20.668, 75.156], [-19.373, 74.296], [-21.594, 74.224], [-20.435, 73.817], [-20.762, 73.464], [-22.172, 73.31], [-23.566, 73.307], [-22.313, 72.629], [-22.3, 72.184], [-24.278, 72.598], [-24.793, 72.33], [-23.443, 72.08], [-22.133, 71.469], [-21.754, 70.664], [-23.536, 70.471], [-24.307, 70.856], [-25.543, 71.431], [-25.201, 70.752], [-26.363, 70.226], [-23.727, 70.184], [-22.349, 70.129], [-25.029, 69.259], [-27.747, 68.47], [-30.674, 68.125], [-31.777, 68.121], [-32.811, 67.735], [-34.202, 66.68], [-36.353, 65.979], [-37.044, 65.938], [-38.375, 65.692], [-39.812, 65.458], [-40.669, 64.84], [-40.683, 64.139], [-41.189, 63.482], [-42.819, 62.682], [-42.417, 61.901], [-42.866, 61.074], [-43.378, 60.098], [-44.788, 60.037], [-46.264, 60.853], [-48.263, 60.858], [-49.233, 61.407], [-49.9, 62.383], [-51.633, 63.627], [-52.14, 64.278], [-52.277, 65.177], [-53.662, 66.1], [-53.302, 66.837], [-53.969, 67.189], [-52.98, 68.358], [-51.475, 68.73], [-51.08, 69.148], [-50.871, 69.929], [-52.014, 69.575], [-52.558, 69.426], [-53.456, 69.284], [-54.683, 69.61], [-54.75, 70.289], [-54.359, 70.821], [-53.431, 70.836], [-51.39, 70.57], [-53.109, 71.205], [-54.004, 71.547], [-55, 71.407], [-55.835, 71.654], [-54.718, 72.586], [-55.326, 72.959], [-56.12, 73.65], [-57.324, 74.71], [-58.597, 75.099], [-58.585, 75.517], [-61.269, 76.102], [-63.392, 76.175], [-66.064, 76.135], [-68.504, 76.061], [-69.665, 76.38], [-71.403, 77.009], [-68.777, 77.323], [-66.764, 77.376], [-71.043, 77.636], [-73.297, 78.044], [-73.159, 78.433], [-69.373, 78.914], [-65.711, 79.394], [-65.324, 79.758], [-68.023, 80.117], [-67.151, 80.516], [-63.689, 81.214], [-62.234, 81.321], [-62.651, 81.77], [-60.282, 82.034], [-57.207, 82.191], [-54.134, 82.2], [-53.043, 81.888], [-50.391, 82.439], [-48.004, 82.065], [-46.6, 81.986], [-44.523, 81.661], [-46.901, 82.2], [-46.764, 82.628]]]] }, { "N": "Timor-Leste", "I": "TL", "C": [[[[124.969, -8.893], [125.086, -8.657], [125.947, -8.432], [126.645, -8.398], [126.957, -8.273], [127.336, -8.397], [126.968, -8.668], [125.926, -9.106], [125.089, -9.393], [125.07, -9.09], [124.969, -8.893]]]] }, { "N": "South Africa", "I": "ZA", "C": [[[[16.345, -28.577], [16.824, -28.082], [17.219, -28.356], [17.387, -28.784], [17.836, -28.856], [18.465, -29.045], [19.002, -28.972], [19.895, -28.461], [19.896, -24.768], [20.166, -24.918], [20.759, -25.868], [20.666, -26.477], [20.89, -26.829], [21.606, -26.727], [22.106, -26.28], [22.58, -25.979], [22.824, -25.5], [23.312, -25.269], [23.734, -25.39], [24.211, -25.67], [25.025, -25.72], [25.665, -25.487], [25.766, -25.175], [25.942, -24.696], [26.486, -24.616], [26.786, -24.241], [27.119, -23.574], [28.017, -22.828], [29.432, -22.091], [29.839, -22.102], [30.323, -22.272], [30.66, -22.152], [31.191, -22.252], [31.67, -23.659], [31.931, -24.369], [31.752, -25.484], [31.838, -25.843], [31.333, -25.66], [31.044, -25.731], [30.95, -26.023], [30.677, -26.398], [30.686, -26.744], [31.283, -27.286], [31.868, -27.178], [32.072, -26.734], [32.83, -26.742], [32.58, -27.47], [32.462, -28.301], [32.203, -28.752], [31.521, -29.257], [31.326, -29.402], [30.902, -29.91], [30.623, -30.424], [30.056, -31.14], [28.926, -32.172], [28.22, -32.772], [27.465, -33.227], [26.419, -33.615], [25.91, -33.667], [25.781, -33.945], [25.173, -33.797], [24.678, -33.987], [23.594, -33.794], [22.988, -33.916], [22.574, -33.864], [21.543, -34.259], [20.689, -34.417], [20.071, -34.795], [19.616, -34.819], [19.193, -34.463], [18.855, -34.444], [18.425, -33.998], [18.377, -34.137], [18.244, -33.868], [18.25, -33.281], [17.925, -32.611], [18.248, -32.429], [18.222, -31.662], [17.567, -30.726], [17.064, -29.879], [17.063, -29.876], [16.345, -28.577]], [[28.978, -28.956], [28.542, -28.648], [28.074, -28.851], [27.533, -29.243], [26.999, -29.876], [27.749, -30.645], [28.107, -30.546], [28.291, -30.226], [28.848, -30.07], [29.018, -29.744], [29.325, -29.257], [28.978, -28.956]]]] }, { "N": "Lesotho", "I": "LS", "C": [[[[28.978, -28.956], [29.325, -29.257], [29.018, -29.744], [28.848, -30.07], [28.291, -30.226], [28.107, -30.546], [27.749, -30.645], [26.999, -29.876], [27.533, -29.243], [28.074, -28.851], [28.542, -28.648], [28.978, -28.956]]]] }, { "N": "Mexico", "I": "MX", "C": [[[[-117.128, 32.535], [-115.991, 32.612], [-114.721, 32.721], [-114.815, 32.525], [-113.305, 32.039], [-111.024, 31.335], [-109.035, 31.342], [-108.242, 31.342], [-108.24, 31.755], [-106.508, 31.755], [-106.143, 31.4], [-105.632, 31.084], [-105.037, 30.644], [-104.706, 30.122], [-104.457, 29.572], [-103.94, 29.27], [-103.11, 28.97], [-102.48, 29.76], [-101.662, 29.779], [-100.958, 29.381], [-100.456, 28.696], [-100.11, 28.11], [-99.52, 27.54], [-99.3, 26.84], [-99.02, 26.37], [-98.24, 26.06], [-97.53, 25.84], [-97.14, 25.87], [-97.528, 24.992], [-97.703, 24.272], [-97.776, 22.933], [-97.872, 22.444], [-97.699, 21.899], [-97.389, 21.411], [-97.189, 20.635], [-96.526, 19.891], [-96.292, 19.32], [-95.901, 18.828], [-94.839, 18.563], [-94.426, 18.144], [-93.549, 18.424], [-92.786, 18.525], [-92.037, 18.705], [-91.408, 18.876], [-90.772, 19.284], [-90.534, 19.867], [-90.451, 20.708], [-90.279, 21], [-89.601, 21.262], [-88.544, 21.494], [-87.658, 21.459], [-87.052, 21.544], [-86.812, 21.332], [-86.846, 20.85], [-87.383, 20.255], [-87.621, 19.647], [-87.437, 19.472], [-87.587, 19.04], [-87.837, 18.26], [-88.091, 18.517], [-88.3, 18.5], [-88.49, 18.487], [-88.848, 17.883], [-89.03, 18.002], [-89.151, 17.955], [-89.143, 17.808], [-90.068, 17.819], [-91.002, 17.818], [-91.002, 17.255], [-91.454, 17.252], [-91.082, 16.918], [-90.712, 16.687], [-90.601, 16.471], [-90.439, 16.41], [-90.464, 16.07], [-91.748, 16.067], [-92.229, 15.251], [-92.087, 15.065], [-92.203, 14.83], [-92.228, 14.539], [-93.359, 15.615], [-93.875, 15.94], [-94.692, 16.201], [-95.25, 16.128], [-96.053, 15.752], [-96.557, 15.654], [-97.264, 15.917], [-98.013, 16.107], [-98.948, 16.566], [-99.697, 16.706], [-100.829, 17.171], [-101.666, 17.649], [-101.919, 17.916], [-102.478, 17.976], [-103.501, 18.292], [-103.918, 18.749], [-104.992, 19.316], [-105.493, 19.947], [-105.731, 20.434], [-105.398, 20.532], [-105.501, 20.817], [-105.271, 21.076], [-105.266, 21.422], [-105.603, 21.871], [-105.693, 22.269], [-106.029, 22.774], [-106.91, 23.768], [-107.915, 24.549], [-108.402, 25.172], [-109.26, 25.581], [-109.444, 25.825], [-109.292, 26.443], [-109.801, 26.676], [-110.392, 27.162], [-110.641, 27.86], [-111.179, 27.941], [-111.76, 28.468], [-112.228, 28.954], [-112.272, 29.267], [-112.81, 30.021], [-113.164, 30.787], [-113.149, 31.171], [-113.872, 31.568], [-114.206, 31.524], [-114.776, 31.8], [-114.937, 31.393], [-114.771, 30.914], [-114.674, 30.163], [-114.331, 29.75], [-113.589, 29.062], [-113.424, 28.826], [-113.272, 28.755], [-113.14, 28.411], [-112.962, 28.425], [-112.762, 27.78], [-112.458, 27.526], [-112.245, 27.172], [-111.616, 26.663], [-111.285, 25.733], [-110.988, 25.295], [-110.71, 24.826], [-110.655, 24.299], [-110.173, 24.266], [-109.772, 23.811], [-109.409, 23.365], [-109.433, 23.186], [-109.854, 22.818], [-110.031, 22.823], [-110.295, 23.431], [-110.95, 24.001], [-111.671, 24.484], [-112.182, 24.738], [-112.149, 25.47], [-112.301, 26.012], [-112.777, 26.322], [-113.465, 26.768], [-113.597, 26.639], [-113.849, 26.9], [-114.466, 27.142], [-115.055, 27.723], [-114.982, 27.798], [-114.57, 27.741], [-114.199, 28.115], [-114.162, 28.566], [-114.932, 29.279], [-115.519, 29.556], [-115.887, 30.181], [-116.258, 30.836], [-116.722, 31.636], [-117.128, 32.535]]]] }, { "N": "Uruguay", "I": "UY", "C": [[[[-57.625, -30.216], [-56.976, -30.11], [-55.973, -30.883], [-55.602, -30.854], [-54.572, -31.495], [-53.788, -32.047], [-53.21, -32.728], [-53.651, -33.202], [-53.374, -33.768], [-53.806, -34.397], [-54.936, -34.953], [-55.674, -34.753], [-56.215, -34.86], [-57.14, -34.43], [-57.818, -34.463], [-58.427, -33.909], [-58.35, -33.263], [-58.133, -33.041], [-58.142, -32.045], [-57.875, -31.017], [-57.625, -30.216]]]] }, { "N": "Brazil", "I": "BR", "C": [[[[-53.374, -33.768], [-53.651, -33.202], [-53.21, -32.728], [-53.788, -32.047], [-54.572, -31.495], [-55.602, -30.854], [-55.973, -30.883], [-56.976, -30.11], [-57.625, -30.216], [-56.291, -28.853], [-55.162, -27.882], [-54.491, -27.475], [-53.649, -26.923], [-53.628, -26.125], [-54.13, -25.548], [-54.625, -25.739], [-54.429, -25.162], [-54.293, -24.571], [-54.293, -24.021], [-54.653, -23.84], [-55.028, -24.001], [-55.401, -23.957], [-55.518, -23.572], [-55.611, -22.656], [-55.798, -22.357], [-56.473, -22.086], [-56.882, -22.282], [-57.937, -22.09], [-57.871, -20.733], [-58.166, -20.177], [-57.854, -19.97], [-57.95, -19.4], [-57.676, -18.962], [-57.498, -18.174], [-57.735, -17.552], [-58.281, -17.272], [-58.388, -16.877], [-58.241, -16.3], [-60.158, -16.258], [-60.543, -15.094], [-60.251, -15.077], [-60.264, -14.646], [-60.459, -14.354], [-60.503, -13.776], [-61.084, -13.479], [-61.713, -13.489], [-62.127, -13.199], [-62.803, -13.001], [-63.196, -12.627], [-64.316, -12.462], [-65.402, -11.566], [-65.322, -10.896], [-65.445, -10.511], [-65.338, -9.762], [-66.647, -9.931], [-67.174, -10.307], [-68.048, -10.712], [-68.271, -11.015], [-68.786, -11.036], [-69.53, -10.952], [-70.094, -11.124], [-70.549, -11.009], [-70.482, -9.49], [-71.302, -10.079], [-72.185, -10.054], [-72.563, -9.52], [-73.227, -9.462], [-73.015, -9.033], [-73.571, -8.424], [-73.987, -7.524], [-73.723, -7.341], [-73.724, -6.919], [-73.12, -6.63], [-73.22, -6.089], [-72.965, -5.741], [-72.892, -5.275], [-71.748, -4.594], [-70.929, -4.402], [-70.795, -4.251], [-69.894, -4.298], [-69.444, -1.556], [-69.42, -1.123], [-69.577, -0.55], [-70.021, -0.185], [-70.016, 0.541], [-69.452, 0.706], [-69.252, 0.603], [-69.219, 0.986], [-69.805, 1.089], [-69.817, 1.715], [-67.869, 1.692], [-67.538, 2.037], [-67.26, 1.72], [-67.065, 1.13], [-66.876, 1.253], [-66.326, 0.724], [-65.548, 0.789], [-65.355, 1.095], [-64.611, 1.329], [-64.199, 1.493], [-64.083, 1.916], [-63.369, 2.201], [-63.423, 2.411], [-64.27, 2.497], [-64.409, 3.127], [-64.368, 3.797], [-64.816, 4.056], [-64.629, 4.148], [-63.888, 4.021], [-63.093, 3.771], [-62.805, 4.007], [-62.085, 4.162], [-60.967, 4.536], [-60.601, 4.918], [-60.734, 5.2], [-60.214, 5.244], [-59.981, 5.014], [-60.111, 4.575], [-59.767, 4.424], [-59.538, 3.959], [-59.815, 3.606], [-59.975, 2.755], [-59.719, 2.25], [-59.646, 1.787], [-59.031, 1.318], [-58.54, 1.268], [-58.429, 1.464], [-58.113, 1.507], [-57.661, 1.683], [-57.336, 1.949], [-56.783, 1.864], [-56.539, 1.9], [-55.996, 1.818], [-55.906, 2.022], [-56.073, 2.221], [-55.973, 2.51], [-55.57, 2.422], [-55.098, 2.524], [-54.525, 2.312], [-54.088, 2.106], [-53.779, 2.377], [-53.555, 2.335], [-53.418, 2.053], [-52.94, 2.125], [-52.556, 2.505], [-52.249, 3.241], [-51.658, 4.156], [-51.317, 4.203], [-51.07, 3.65], [-50.509, 1.902], [-49.974, 1.736], [-49.947, 1.046], [-50.699, 0.223], [-50.388, -0.078], [-48.621, -0.235], [-48.584, -1.238], [-47.825, -0.582], [-46.567, -0.941], [-44.906, -1.552], [-44.418, -2.138], [-44.582, -2.691], [-43.419, -2.383], [-41.473, -2.912], [-39.979, -2.873], [-38.5, -3.701], [-37.223, -4.821], [-36.453, -5.109], [-35.598, -5.15], [-35.235, -5.465], [-34.896, -6.738], [-34.73, -7.343], [-35.128, -8.996], [-35.637, -9.649], [-37.047, -11.041], [-37.684, -12.171], [-38.424, -13.038], [-38.674, -13.058], [-38.953, -13.793], [-38.882, -15.667], [-39.161, -17.208], [-39.267, -17.868], [-39.584, -18.262], [-39.761, -19.599], [-40.775, -20.905], [-40.945, -21.937], [-41.754, -22.371], [-41.988, -22.97], [-43.075, -22.968], [-44.648, -23.352], [-45.352, -23.797], [-46.472, -24.089], [-47.649, -24.885], [-48.495, -25.877], [-48.641, -26.624], [-48.475, -27.176], [-48.662, -28.186], [-48.888, -28.674], [-49.587, -29.224], [-50.697, -30.984], [-51.576, -31.778], [-52.256, -32.245], [-52.712, -33.197], [-53.374, -33.768]]]] }, { "N": "Bolivia", "I": "BO", "C": [[[[-69.53, -10.952], [-68.786, -11.036], [-68.271, -11.015], [-68.048, -10.712], [-67.174, -10.307], [-66.647, -9.931], [-65.338, -9.762], [-65.445, -10.511], [-65.322, -10.896], [-65.402, -11.566], [-64.316, -12.462], [-63.196, -12.627], [-62.803, -13.001], [-62.127, -13.199], [-61.713, -13.489], [-61.084, -13.479], [-60.503, -13.776], [-60.459, -14.354], [-60.264, -14.646], [-60.251, -15.077], [-60.543, -15.094], [-60.158, -16.258], [-58.241, -16.3], [-58.388, -16.877], [-58.281, -17.272], [-57.735, -17.552], [-57.498, -18.174], [-57.676, -18.962], [-57.95, -19.4], [-57.854, -19.97], [-58.166, -20.177], [-58.183, -19.868], [-59.115, -19.357], [-60.044, -19.343], [-61.786, -19.634], [-62.266, -20.514], [-62.291, -21.052], [-62.685, -22.249], [-62.846, -22.035], [-63.987, -21.994], [-64.377, -22.798], [-64.965, -22.076], [-66.273, -21.832], [-67.107, -22.736], [-67.828, -22.873], [-68.22, -21.494], [-68.757, -20.373], [-68.442, -19.405], [-68.967, -18.982], [-69.1, -18.26], [-69.59, -17.58], [-68.96, -16.501], [-69.39, -15.66], [-69.16, -15.324], [-69.34, -14.953], [-68.949, -14.454], [-68.929, -13.603], [-68.88, -12.9], [-68.665, -12.561], [-69.53, -10.952]]]] }, { "N": "Peru", "I": "PE", "C": [[[[-69.894, -4.298], [-70.795, -4.251], [-70.929, -4.402], [-71.748, -4.594], [-72.892, -5.275], [-72.965, -5.741], [-73.22, -6.089], [-73.12, -6.63], [-73.724, -6.919], [-73.723, -7.341], [-73.987, -7.524], [-73.571, -8.424], [-73.015, -9.033], [-73.227, -9.462], [-72.563, -9.52], [-72.185, -10.054], [-71.302, -10.079], [-70.482, -9.49], [-70.549, -11.009], [-70.094, -11.124], [-69.53, -10.952], [-68.665, -12.561], [-68.88, -12.9], [-68.929, -13.603], [-68.949, -14.454], [-69.34, -14.953], [-69.16, -15.324], [-69.39, -15.66], [-68.96, -16.501], [-69.59, -17.58], [-69.858, -18.093], [-70.373, -18.348], [-71.375, -17.774], [-71.462, -17.363], [-73.445, -16.359], [-75.238, -15.266], [-76.009, -14.649], [-76.423, -13.823], [-76.259, -13.535], [-77.106, -12.223], [-78.092, -10.378], [-79.037, -8.387], [-79.446, -7.931], [-79.761, -7.194], [-80.537, -6.542], [-81.25, -6.137], [-80.926, -5.691], [-81.411, -4.737], [-81.1, -4.036], [-80.303, -3.405], [-80.184, -3.821], [-80.469, -4.059], [-80.442, -4.426], [-80.029, -4.346], [-79.625, -4.454], [-79.205, -4.959], [-78.64, -4.548], [-78.451, -3.873], [-77.838, -3.003], [-76.635, -2.609], [-75.545, -1.562], [-75.234, -0.911], [-75.373, -0.152], [-75.107, -0.057], [-74.442, -0.531], [-74.122, -1.003], [-73.66, -1.26], [-73.07, -2.309], [-72.326, -2.434], [-71.775, -2.17], [-71.414, -2.343], [-70.813, -2.257], [-70.048, -2.725], [-70.693, -3.743], [-70.394, -3.767], [-69.894, -4.298]]]] }, { "N": "Colombia", "I": "CO", "C": [[[[-66.876, 1.253], [-67.065, 1.13], [-67.26, 1.72], [-67.538, 2.037], [-67.869, 1.692], [-69.817, 1.715], [-69.805, 1.089], [-69.219, 0.986], [-69.252, 0.603], [-69.452, 0.706], [-70.016, 0.541], [-70.021, -0.185], [-69.577, -0.55], [-69.42, -1.123], [-69.444, -1.556], [-69.894, -4.298], [-70.394, -3.767], [-70.693, -3.743], [-70.048, -2.725], [-70.813, -2.257], [-71.414, -2.343], [-71.775, -2.17], [-72.326, -2.434], [-73.07, -2.309], [-73.66, -1.26], [-74.122, -1.003], [-74.442, -0.531], [-75.107, -0.057], [-75.373, -0.152], [-75.801, 0.085], [-76.292, 0.416], [-76.576, 0.257], [-77.425, 0.396], [-77.669, 0.826], [-77.855, 0.81], [-78.855, 1.381], [-78.991, 1.691], [-78.618, 1.766], [-78.662, 2.267], [-78.428, 2.63], [-77.932, 2.697], [-77.51, 3.325], [-77.128, 3.85], [-77.496, 4.088], [-77.308, 4.668], [-77.533, 5.583], [-77.319, 5.845], [-77.477, 6.691], [-77.882, 7.224], [-77.753, 7.71], [-77.431, 7.638], [-77.243, 7.935], [-77.475, 8.524], [-77.353, 8.671], [-76.837, 8.639], [-76.086, 9.337], [-75.675, 9.443], [-75.665, 9.774], [-75.48, 10.619], [-74.907, 11.083], [-74.277, 11.102], [-74.197, 11.31], [-73.415, 11.227], [-72.628, 11.732], [-72.238, 11.956], [-71.754, 12.437], [-71.4, 12.376], [-71.137, 12.113], [-71.332, 11.776], [-71.974, 11.609], [-72.228, 11.109], [-72.615, 10.822], [-72.905, 10.45], [-73.028, 9.737], [-73.305, 9.152], [-72.789, 9.085], [-72.66, 8.625], [-72.44, 8.405], [-72.361, 8.003], [-72.48, 7.633], [-72.444, 7.424], [-72.198, 7.34], [-71.96, 6.992], [-70.674, 7.088], [-70.093, 6.96], [-69.389, 6.1], [-68.985, 6.207], [-68.265, 6.153], [-67.695, 6.267], [-67.341, 6.095], [-67.522, 5.557], [-67.745, 5.221], [-67.823, 4.504], [-67.622, 3.839], [-67.338, 3.542], [-67.303, 3.318], [-67.81, 2.821], [-67.447, 2.6], [-67.181, 2.251], [-66.876, 1.253]]]] }, { "N": "Panama", "I": "PA", "C": [[[[-77.353, 8.671], [-77.475, 8.524], [-77.243, 7.935], [-77.431, 7.638], [-77.753, 7.71], [-77.882, 7.224], [-78.215, 7.512], [-78.429, 8.052], [-78.182, 8.319], [-78.435, 8.388], [-78.622, 8.718], [-79.12, 8.996], [-79.558, 8.932], [-79.761, 8.585], [-80.164, 8.333], [-80.383, 8.298], [-80.481, 8.09], [-80.004, 7.548], [-80.277, 7.42], [-80.421, 7.272], [-80.886, 7.221], [-81.06, 7.818], [-81.19, 7.648], [-81.52, 7.707], [-81.721, 8.109], [-82.131, 8.175], [-82.391, 8.292], [-82.82, 8.291], [-82.851, 8.074], [-82.966, 8.225], [-82.913, 8.424], [-82.83, 8.626], [-82.869, 8.807], [-82.719, 8.926], [-82.927, 9.074], [-82.933, 9.477], [-82.546, 9.566], [-82.187, 9.207], [-82.208, 8.996], [-81.809, 8.951], [-81.714, 9.032], [-81.439, 8.786], [-80.947, 8.859], [-80.522, 9.111], [-79.915, 9.313], [-79.573, 9.612], [-79.021, 9.553], [-79.058, 9.455], [-78.501, 9.42], [-78.056, 9.248], [-77.73, 8.947], [-77.353, 8.671]]]] }, { "N": "Costa Rica", "I": "CR", "C": [[[[-82.546, 9.566], [-82.933, 9.477], [-82.927, 9.074], [-82.719, 8.926], [-82.869, 8.807], [-82.83, 8.626], [-82.913, 8.424], [-82.966, 8.225], [-83.508, 8.447], [-83.711, 8.657], [-83.596, 8.83], [-83.633, 9.051], [-83.91, 9.291], [-84.303, 9.487], [-84.648, 9.616], [-84.713, 9.908], [-84.976, 10.087], [-84.911, 9.796], [-85.111, 9.557], [-85.339, 9.835], [-85.661, 9.933], [-85.797, 10.135], [-85.792, 10.439], [-85.659, 10.754], [-85.942, 10.895], [-85.713, 11.088], [-85.562, 11.217], [-84.903, 10.952], [-84.673, 11.083], [-84.356, 10.999], [-84.19, 10.793], [-83.895, 10.727], [-83.656, 10.939], [-83.402, 10.395], [-83.016, 9.993], [-82.546, 9.566]]]] }, { "N": "Nicaragua", "I": "NI", "C": [[[[-83.656, 10.939], [-83.895, 10.727], [-84.19, 10.793], [-84.356, 10.999], [-84.673, 11.083], [-84.903, 10.952], [-85.562, 11.217], [-85.713, 11.088], [-86.058, 11.403], [-86.526, 11.807], [-86.746, 12.144], [-87.168, 12.458], [-87.668, 12.91], [-87.557, 13.065], [-87.392, 12.914], [-87.317, 12.985], [-87.006, 13.026], [-86.881, 13.254], [-86.734, 13.263], [-86.755, 13.755], [-86.521, 13.778], [-86.312, 13.771], [-86.096, 14.038], [-85.801, 13.836], [-85.699, 13.96], [-85.514, 14.079], [-85.165, 14.354], [-85.149, 14.56], [-85.053, 14.552], [-84.925, 14.79], [-84.82, 14.82], [-84.65, 14.667], [-84.449, 14.622], [-84.228, 14.749], [-83.976, 14.749], [-83.629, 14.88], [-83.49, 15.016], [-83.147, 14.996], [-83.233, 14.9], [-83.284, 14.677], [-83.182, 14.311], [-83.412, 13.97], [-83.52, 13.568], [-83.552, 13.127], [-83.499, 12.869], [-83.473, 12.419], [-83.626, 12.321], [-83.72, 11.893], [-83.651, 11.629], [-83.855, 11.373], [-83.809, 11.103], [-83.656, 10.939]]]] }, { "N": "Honduras", "I": "HN", "C": [[[[-83.147, 14.996], [-83.49, 15.016], [-83.629, 14.88], [-83.976, 14.749], [-84.228, 14.749], [-84.449, 14.622], [-84.65, 14.667], [-84.82, 14.82], [-84.925, 14.79], [-85.053, 14.552], [-85.149, 14.56], [-85.165, 14.354], [-85.514, 14.079], [-85.699, 13.96], [-85.801, 13.836], [-86.096, 14.038], [-86.312, 13.771], [-86.521, 13.778], [-86.755, 13.755], [-86.734, 13.263], [-86.881, 13.254], [-87.006, 13.026], [-87.317, 12.985], [-87.489, 13.298], [-87.793, 13.384], [-87.724, 13.785], [-87.86, 13.893], [-88.065, 13.965], [-88.504, 13.845], [-88.541, 13.98], [-88.843, 14.141], [-89.059, 14.34], [-89.353, 14.424], [-89.146, 14.678], [-89.225, 14.874], [-89.155, 15.066], [-88.681, 15.346], [-88.225, 15.728], [-88.121, 15.689], [-87.902, 15.864], [-87.616, 15.879], [-87.523, 15.797], [-87.368, 15.847], [-86.903, 15.757], [-86.441, 15.783], [-86.119, 15.893], [-86.002, 16.005], [-85.683, 15.954], [-85.444, 15.886], [-85.182, 15.909], [-84.984, 15.996], [-84.527, 15.857], [-84.368, 15.835], [-84.063, 15.648], [-83.774, 15.424], [-83.41, 15.271], [-83.147, 14.996]]]] }, { "N": "El Salvador", "I": "SV", "C": [[[[-89.353, 14.424], [-89.059, 14.34], [-88.843, 14.141], [-88.541, 13.98], [-88.504, 13.845], [-88.065, 13.965], [-87.86, 13.893], [-87.724, 13.785], [-87.793, 13.384], [-87.904, 13.149], [-88.483, 13.164], [-88.843, 13.26], [-89.257, 13.459], [-89.812, 13.521], [-90.096, 13.735], [-90.065, 13.882], [-89.722, 14.134], [-89.534, 14.245], [-89.587, 14.363], [-89.353, 14.424]]]] }, { "N": "Guatemala", "I": "GT", "C": [[[[-92.228, 14.539], [-92.203, 14.83], [-92.087, 15.065], [-92.229, 15.251], [-91.748, 16.067], [-90.464, 16.07], [-90.439, 16.41], [-90.601, 16.471], [-90.712, 16.687], [-91.082, 16.918], [-91.454, 17.252], [-91.002, 17.255], [-91.002, 17.818], [-90.068, 17.819], [-89.143, 17.808], [-89.151, 17.016], [-89.229, 15.887], [-88.931, 15.887], [-88.605, 15.706], [-88.518, 15.855], [-88.225, 15.728], [-88.681, 15.346], [-89.155, 15.066], [-89.225, 14.874], [-89.146, 14.678], [-89.353, 14.424], [-89.587, 14.363], [-89.534, 14.245], [-89.722, 14.134], [-90.065, 13.882], [-90.096, 13.735], [-90.609, 13.91], [-91.232, 13.928], [-91.69, 14.126], [-92.228, 14.539]]]] }, { "N": "Belize", "I": "BZ", "C": [[[[-89.143, 17.808], [-89.151, 17.955], [-89.03, 18.002], [-88.848, 17.883], [-88.49, 18.487], [-88.3, 18.5], [-88.296, 18.353], [-88.107, 18.349], [-88.123, 18.077], [-88.285, 17.644], [-88.198, 17.489], [-88.303, 17.132], [-88.24, 17.036], [-88.355, 16.531], [-88.552, 16.265], [-88.732, 16.234], [-88.931, 15.887], [-89.229, 15.887], [-89.151, 17.016], [-89.143, 17.808]]]] }, { "N": "Venezuela", "I": "VE", "C": [[[[-60.734, 5.2], [-60.601, 4.918], [-60.967, 4.536], [-62.085, 4.162], [-62.805, 4.007], [-63.093, 3.771], [-63.888, 4.021], [-64.629, 4.148], [-64.816, 4.056], [-64.368, 3.797], [-64.409, 3.127], [-64.27, 2.497], [-63.423, 2.411], [-63.369, 2.201], [-64.083, 1.916], [-64.199, 1.493], [-64.611, 1.329], [-65.355, 1.095], [-65.548, 0.789], [-66.326, 0.724], [-66.876, 1.253], [-67.181, 2.251], [-67.447, 2.6], [-67.81, 2.821], [-67.303, 3.318], [-67.338, 3.542], [-67.622, 3.839], [-67.823, 4.504], [-67.745, 5.221], [-67.522, 5.557], [-67.341, 6.095], [-67.695, 6.267], [-68.265, 6.153], [-68.985, 6.207], [-69.389, 6.1], [-70.093, 6.96], [-70.674, 7.088], [-71.96, 6.992], [-72.198, 7.34], [-72.444, 7.424], [-72.48, 7.633], [-72.361, 8.003], [-72.44, 8.405], [-72.66, 8.625], [-72.789, 9.085], [-73.305, 9.152], [-73.028, 9.737], [-72.905, 10.45], [-72.615, 10.822], [-72.228, 11.109], [-71.974, 11.609], [-71.332, 11.776], [-71.36, 11.54], [-71.947, 11.423], [-71.621, 10.969], [-71.633, 10.446], [-72.074, 9.866], [-71.696, 9.072], [-71.265, 9.137], [-71.04, 9.86], [-71.35, 10.212], [-71.401, 10.969], [-70.155, 11.375], [-70.294, 11.847], [-69.943, 12.162], [-69.584, 11.46], [-68.883, 11.443], [-68.233, 10.886], [-68.194, 10.555], [-67.296, 10.546], [-66.228, 10.649], [-65.655, 10.201], [-64.89, 10.077], [-64.329, 10.39], [-64.318, 10.641], [-63.079, 10.702], [-61.881, 10.716], [-62.73, 10.42], [-62.389, 9.948], [-61.589, 9.873], [-60.831, 9.381], [-60.671, 8.58], [-60.15, 8.603], [-59.758, 8.367], [-60.551, 7.78], [-60.638, 7.415], [-60.296, 7.044], [-60.544, 6.857], [-61.159, 6.696], [-61.139, 6.234], [-61.41, 5.959], [-60.734, 5.2]]]] }, { "N": "Guyana", "I": "GY", "C": [[[[-56.539, 1.9], [-56.783, 1.864], [-57.336, 1.949], [-57.661, 1.683], [-58.113, 1.507], [-58.429, 1.464], [-58.54, 1.268], [-59.031, 1.318], [-59.646, 1.787], [-59.719, 2.25], [-59.975, 2.755], [-59.815, 3.606], [-59.538, 3.959], [-59.767, 4.424], [-60.111, 4.575], [-59.981, 5.014], [-60.214, 5.244], [-60.734, 5.2], [-61.41, 5.959], [-61.139, 6.234], [-61.159, 6.696], [-60.544, 6.857], [-60.296, 7.044], [-60.638, 7.415], [-60.551, 7.78], [-59.758, 8.367], [-59.102, 7.999], [-58.483, 7.348], [-58.455, 6.833], [-58.078, 6.809], [-57.542, 6.321], [-57.147, 5.973], [-57.307, 5.074], [-57.914, 4.813], [-57.86, 4.577], [-58.045, 4.061], [-57.602, 3.335], [-57.281, 3.333], [-57.15, 2.769], [-56.539, 1.9]]]] }, { "N": "Suriname", "I": "SR", "C": [[[[-54.525, 2.312], [-55.098, 2.524], [-55.57, 2.422], [-55.973, 2.51], [-56.073, 2.221], [-55.906, 2.022], [-55.996, 1.818], [-56.539, 1.9], [-57.15, 2.769], [-57.281, 3.333], [-57.602, 3.335], [-58.045, 4.061], [-57.86, 4.577], [-57.914, 4.813], [-57.307, 5.074], [-57.147, 5.973], [-55.949, 5.773], [-55.842, 5.953], [-55.033, 6.025], [-53.958, 5.757], [-54.479, 4.897], [-54.4, 4.213], [-54.007, 3.62], [-54.182, 3.19], [-54.27, 2.732], [-54.525, 2.312]]]] }, { "N": "France", "I": "FR", "C": [[[[-51.658, 4.156], [-52.249, 3.241], [-52.556, 2.505], [-52.94, 2.125], [-53.418, 2.053], [-53.555, 2.335], [-53.779, 2.377], [-54.088, 2.106], [-54.525, 2.312], [-54.27, 2.732], [-54.182, 3.19], [-54.007, 3.62], [-54.4, 4.213], [-54.479, 4.897], [-53.958, 5.757], [-53.618, 5.647], [-52.882, 5.41], [-51.823, 4.566], [-51.658, 4.156]]], [[[8.746, 42.628], [9.39, 43.01], [9.56, 42.152], [9.23, 41.38], [8.776, 41.584], [8.544, 42.257], [8.746, 42.628]]], [[[6.186, 49.464], [6.658, 49.202], [8.099, 49.018], [7.594, 48.333], [7.467, 47.621], [7.192, 47.45], [6.737, 47.542], [6.769, 47.288], [6.037, 46.726], [6.023, 46.273], [6.5, 46.43], [6.844, 45.991], [6.802, 45.709], [7.097, 45.333], [6.75, 45.029], [7.008, 44.255], [7.55, 44.128], [7.435, 43.694], [6.529, 43.129], [4.557, 43.4], [3.1, 43.075], [2.986, 42.473], [1.827, 42.343], [0.702, 42.796], [0.338, 42.58], [-1.503, 43.034], [-1.901, 43.423], [-1.384, 44.023], [-1.194, 46.015], [-2.226, 47.064], [-2.963, 47.57], [-4.492, 47.955], [-4.592, 48.684], [-3.296, 48.902], [-1.617, 48.644], [-1.933, 49.776], [-0.989, 49.347], [1.339, 50.127], [1.639, 50.947], [2.514, 51.149], [2.658, 50.797], [3.123, 50.78], [3.588, 50.379], [4.286, 49.907], [4.799, 49.985], [5.674, 49.529], [5.898, 49.443], [6.186, 49.464]]], [[[8.746, 42.628], [9.39, 43.01], [9.56, 42.152], [9.23, 41.38], [8.776, 41.584], [8.544, 42.257], [8.746, 42.628]]]] }, { "N": "Ecuador", "I": "EC", "C": [[[[-75.373, -0.152], [-75.234, -0.911], [-75.545, -1.562], [-76.635, -2.609], [-77.838, -3.003], [-78.451, -3.873], [-78.64, -4.548], [-79.205, -4.959], [-79.625, -4.454], [-80.029, -4.346], [-80.442, -4.426], [-80.469, -4.059], [-80.184, -3.821], [-80.303, -3.405], [-79.77, -2.658], [-79.987, -2.221], [-80.369, -2.685], [-80.968, -2.247], [-80.765, -1.965], [-80.934, -1.057], [-80.583, -0.907], [-80.399, -0.284], [-80.021, 0.36], [-80.091, 0.768], [-79.543, 0.983], [-78.855, 1.381], [-77.855, 0.81], [-77.669, 0.826], [-77.425, 0.396], [-76.576, 0.257], [-76.292, 0.416], [-75.801, 0.085], [-75.373, -0.152]]]] }, { "N": "Puerto Rico", "I": "PR", "C": [[[[-66.282, 18.515], [-65.771, 18.427], [-65.591, 18.228], [-65.847, 17.976], [-66.6, 17.982], [-67.184, 17.947], [-67.242, 18.374], [-67.101, 18.521], [-66.282, 18.515]]]] }, { "N": "Jamaica", "I": "JM", "C": [[[[-77.57, 18.491], [-76.897, 18.401], [-76.365, 18.161], [-76.2, 17.887], [-76.903, 17.868], [-77.206, 17.701], [-77.766, 17.862], [-78.338, 18.226], [-78.218, 18.455], [-77.797, 18.524], [-77.57, 18.491]]]] }, { "N": "Cuba", "I": "CU", "C": [[[[-82.268, 23.189], [-81.404, 23.117], [-80.619, 23.106], [-79.68, 22.765], [-79.281, 22.399], [-78.347, 22.512], [-77.993, 22.277], [-77.146, 21.658], [-76.524, 21.207], [-76.195, 21.221], [-75.598, 21.017], [-75.671, 20.735], [-74.934, 20.694], [-74.178, 20.285], [-74.297, 20.05], [-74.962, 19.923], [-75.635, 19.874], [-76.324, 19.953], [-77.755, 19.855], [-77.085, 20.413], [-77.493, 20.673], [-78.137, 20.74], [-78.483, 21.029], [-78.72, 21.598], [-79.285, 21.559], [-80.217, 21.827], [-80.518, 22.037], [-81.821, 22.192], [-82.17, 22.387], [-81.795, 22.637], [-82.776, 22.688], [-83.494, 22.169], [-83.909, 22.155], [-84.052, 21.911], [-84.547, 21.801], [-84.975, 21.896], [-84.447, 22.205], [-84.23, 22.566], [-83.778, 22.788], [-83.268, 22.983], [-82.51, 23.079], [-82.268, 23.189]]]] }, { "N": "Zimbabwe", "I": "ZW", "C": [[[[31.191, -22.252], [30.66, -22.152], [30.323, -22.272], [29.839, -22.102], [29.432, -22.091], [28.795, -21.639], [28.021, -21.486], [27.727, -20.852], [27.725, -20.499], [27.297, -20.392], [26.165, -19.293], [25.85, -18.714], [25.649, -18.536], [25.264, -17.737], [26.382, -17.846], [26.707, -17.961], [27.044, -17.938], [27.598, -17.291], [28.468, -16.468], [28.826, -16.39], [28.947, -16.043], [29.517, -15.645], [30.274, -15.508], [30.339, -15.881], [31.173, -15.861], [31.636, -16.072], [31.852, -16.319], [32.328, -16.392], [32.848, -16.713], [32.85, -17.979], [32.655, -18.672], [32.612, -19.419], [32.773, -19.716], [32.66, -20.304], [32.509, -20.395], [32.245, -21.116], [31.191, -22.252]]]] }, { "N": "Botswana", "I": "BW", "C": [[[[29.432, -22.091], [28.017, -22.828], [27.119, -23.574], [26.786, -24.241], [26.486, -24.616], [25.942, -24.696], [25.766, -25.175], [25.665, -25.487], [25.025, -25.72], [24.211, -25.67], [23.734, -25.39], [23.312, -25.269], [22.824, -25.5], [22.58, -25.979], [22.106, -26.28], [21.606, -26.727], [20.89, -26.829], [20.666, -26.477], [20.759, -25.868], [20.166, -24.918], [19.896, -24.768], [19.895, -21.849], [20.881, -21.814], [20.911, -18.252], [21.655, -18.219], [23.197, -17.869], [23.579, -18.281], [24.217, -17.889], [24.521, -17.887], [25.084, -17.662], [25.264, -17.737], [25.649, -18.536], [25.85, -18.714], [26.165, -19.293], [27.297, -20.392], [27.725, -20.499], [27.727, -20.852], [28.021, -21.486], [28.795, -21.639], [29.432, -22.091]]]] }, { "N": "Namibia", "I": "NA", "C": [[[[19.896, -24.768], [19.895, -28.461], [19.002, -28.972], [18.465, -29.045], [17.836, -28.856], [17.387, -28.784], [17.219, -28.356], [16.824, -28.082], [16.345, -28.577], [15.602, -27.821], [15.21, -27.091], [14.99, -26.117], [14.743, -25.393], [14.408, -23.853], [14.386, -22.657], [14.258, -22.111], [13.869, -21.699], [13.352, -20.873], [12.827, -19.673], [12.609, -19.045], [11.795, -18.069], [11.734, -17.302], [12.215, -17.112], [12.814, -16.941], [13.462, -16.971], [14.059, -17.423], [14.21, -17.353], [18.263, -17.31], [18.956, -17.789], [21.377, -17.931], [23.215, -17.523], [24.034, -17.296], [24.682, -17.353], [25.077, -17.579], [25.084, -17.662], [24.521, -17.887], [24.217, -17.889], [23.579, -18.281], [23.197, -17.869], [21.655, -18.219], [20.911, -18.252], [20.881, -21.814], [19.895, -21.849], [19.896, -24.768]]]] }, { "N": "Senegal", "I": "SN", "C": [[[[-16.714, 13.595], [-17.126, 14.374], [-17.625, 14.73], [-17.185, 14.919], [-16.701, 15.622], [-16.463, 16.135], [-16.121, 16.456], [-15.624, 16.369], [-15.136, 16.587], [-14.577, 16.598], [-14.1, 16.304], [-13.436, 16.039], [-12.831, 15.304], [-12.171, 14.617], [-12.125, 13.995], [-11.928, 13.422], [-11.553, 13.141], [-11.468, 12.755], [-11.514, 12.443], [-11.658, 12.387], [-12.204, 12.466], [-12.279, 12.354], [-12.499, 12.332], [-13.218, 12.576], [-13.7, 12.586], [-15.548, 12.628], [-15.817, 12.516], [-16.148, 12.548], [-16.677, 12.385], [-16.842, 13.151], [-15.931, 13.13], [-15.691, 13.27], [-15.512, 13.279], [-15.141, 13.51], [-14.712, 13.298], [-14.278, 13.281], [-13.845, 13.505], [-14.047, 13.794], [-14.377, 13.626], [-14.687, 13.63], [-15.082, 13.876], [-15.399, 13.86], [-15.625, 13.624], [-16.714, 13.595]]]] }, { "N": "Mali", "I": "ML", "C": [[[[-11.514, 12.443], [-11.468, 12.755], [-11.553, 13.141], [-11.928, 13.422], [-12.125, 13.995], [-12.171, 14.617], [-11.834, 14.799], [-11.666, 15.388], [-11.349, 15.411], [-10.651, 15.133], [-10.087, 15.33], [-9.7, 15.264], [-9.55, 15.486], [-5.538, 15.502], [-5.315, 16.202], [-5.489, 16.325], [-5.971, 20.641], [-6.454, 24.957], [-4.923, 24.975], [-1.55, 22.793], [1.823, 20.611], [2.061, 20.142], [2.684, 19.856], [3.147, 19.694], [3.158, 19.057], [4.267, 19.155], [4.27, 16.852], [3.723, 16.184], [3.638, 15.568], [2.75, 15.41], [1.386, 15.324], [1.016, 14.968], [0.375, 14.929], [-0.266, 14.924], [-0.516, 15.116], [-1.066, 14.974], [-2.001, 14.559], [-2.192, 14.246], [-2.968, 13.798], [-3.104, 13.541], [-3.523, 13.338], [-4.006, 13.472], [-4.28, 13.228], [-4.427, 12.543], [-5.221, 11.714], [-5.198, 11.375], [-5.471, 10.951], [-5.404, 10.371], [-5.817, 10.223], [-6.05, 10.096], [-6.205, 10.524], [-6.494, 10.411], [-6.666, 10.431], [-6.851, 10.139], [-7.623, 10.147], [-7.9, 10.297], [-8.03, 10.207], [-8.335, 10.495], [-8.282, 10.793], [-8.407, 10.909], [-8.62, 10.811], [-8.581, 11.136], [-8.376, 11.394], [-8.786, 11.813], [-8.905, 12.088], [-9.127, 12.308], [-9.328, 12.334], [-9.568, 12.194], [-9.891, 12.06], [-10.165, 11.844], [-10.593, 11.924], [-10.871, 12.178], [-11.037, 12.211], [-11.298, 12.078], [-11.456, 12.077], [-11.514, 12.443]]]] }, { "N": "Mauritania", "I": "MR", "C": [[[[-17.063, 21], [-16.845, 21.333], [-12.929, 21.327], [-13.119, 22.771], [-12.874, 23.285], [-11.937, 23.375], [-11.969, 25.933], [-8.687, 25.881], [-8.684, 27.396], [-4.923, 24.975], [-6.454, 24.957], [-5.971, 20.641], [-5.489, 16.325], [-5.315, 16.202], [-5.538, 15.502], [-9.55, 15.486], [-9.7, 15.264], [-10.087, 15.33], [-10.651, 15.133], [-11.349, 15.411], [-11.666, 15.388], [-11.834, 14.799], [-12.171, 14.617], [-12.831, 15.304], [-13.436, 16.039], [-14.1, 16.304], [-14.577, 16.598], [-15.136, 16.587], [-15.624, 16.369], [-16.121, 16.456], [-16.463, 16.135], [-16.55, 16.674], [-16.271, 17.167], [-16.146, 18.108], [-16.257, 19.097], [-16.378, 19.594], [-16.278, 20.093], [-16.536, 20.568], [-17.063, 21]]]] }, { "N": "Benin", "I": "BJ", "C": [[[[2.692, 6.259], [1.865, 6.142], [1.619, 6.832], [1.664, 9.129], [1.463, 9.335], [1.425, 9.825], [1.078, 10.176], [0.772, 10.471], [0.9, 10.997], [1.243, 11.111], [1.447, 11.548], [1.936, 11.641], [2.154, 11.94], [2.49, 12.233], [2.849, 12.236], [3.611, 11.66], [3.572, 11.328], [3.797, 10.735], [3.6, 10.332], [3.705, 10.063], [3.22, 9.444], [2.912, 9.138], [2.724, 8.507], [2.749, 7.871], [2.692, 6.259]]]] }, { "N": "Niger", "I": "NE", "C": [[[[14.851, 22.863], [15.097, 21.309], [15.471, 21.048], [15.487, 20.73], [15.903, 20.388], [15.686, 19.957], [15.3, 17.928], [15.248, 16.627], [13.972, 15.684], [13.54, 14.367], [13.957, 13.997], [13.954, 13.353], [14.596, 13.33], [14.496, 12.859], [14.214, 12.802], [14.181, 12.484], [13.995, 12.462], [13.319, 13.556], [13.084, 13.596], [12.302, 13.037], [11.528, 13.329], [10.99, 13.387], [10.701, 13.247], [10.115, 13.277], [9.525, 12.851], [9.015, 12.827], [7.805, 13.344], [7.331, 13.098], [6.82, 13.115], [6.445, 13.493], [5.443, 13.866], [4.368, 13.747], [4.108, 13.531], [3.967, 12.956], [3.681, 12.553], [3.611, 11.66], [2.849, 12.236], [2.49, 12.233], [2.154, 11.94], [2.177, 12.625], [1.024, 12.852], [0.993, 13.336], [0.43, 13.989], [0.296, 14.444], [0.375, 14.929], [1.016, 14.968], [1.386, 15.324], [2.75, 15.41], [3.638, 15.568], [3.723, 16.184], [4.27, 16.852], [4.267, 19.155], [5.678, 19.601], [8.573, 21.566], [12, 23.472], [13.581, 23.041], [14.144, 22.491], [14.851, 22.863]]]] }, { "N": "Nigeria", "I": "NG", "C": [[[[2.692, 6.259], [2.749, 7.871], [2.724, 8.507], [2.912, 9.138], [3.22, 9.444], [3.705, 10.063], [3.6, 10.332], [3.797, 10.735], [3.572, 11.328], [3.611, 11.66], [3.681, 12.553], [3.967, 12.956], [4.108, 13.531], [4.368, 13.747], [5.443, 13.866], [6.445, 13.493], [6.82, 13.115], [7.331, 13.098], [7.805, 13.344], [9.015, 12.827], [9.525, 12.851], [10.115, 13.277], [10.701, 13.247], [10.99, 13.387], [11.528, 13.329], [12.302, 13.037], [13.084, 13.596], [13.319, 13.556], [13.995, 12.462], [14.181, 12.484], [14.577, 12.085], [14.468, 11.905], [14.415, 11.572], [13.573, 10.799], [13.309, 10.16], [13.168, 9.641], [12.955, 9.418], [12.754, 8.718], [12.219, 8.306], [12.064, 7.8], [11.839, 7.397], [11.746, 6.981], [11.059, 6.644], [10.497, 7.055], [10.118, 7.039], [9.523, 6.453], [9.233, 6.444], [8.758, 5.48], [8.5, 4.772], [7.462, 4.412], [7.083, 4.465], [6.698, 4.241], [5.898, 4.262], [5.363, 4.888], [5.034, 5.612], [4.326, 6.271], [3.574, 6.258], [2.692, 6.259]]]] }, { "N": "Cameroon", "I": "CM", "C": [[[[14.496, 12.859], [14.893, 12.219], [14.96, 11.556], [14.924, 10.891], [15.468, 9.982], [14.909, 9.992], [14.627, 9.921], [14.171, 10.021], [13.954, 9.549], [14.544, 8.966], [14.98, 8.796], [15.121, 8.382], [15.436, 7.693], [15.279, 7.422], [14.777, 6.408], [14.537, 6.227], [14.459, 5.452], [14.559, 5.031], [14.478, 4.733], [14.951, 4.21], [15.036, 3.851], [15.405, 3.335], [15.863, 3.014], [15.907, 2.557], [16.013, 2.268], [15.941, 1.728], [15.146, 1.964], [14.338, 2.228], [13.076, 2.267], [12.951, 2.322], [12.359, 2.193], [11.752, 2.327], [11.276, 2.261], [9.649, 2.284], [9.795, 3.073], [9.404, 3.735], [8.948, 3.904], [8.745, 4.352], [8.489, 4.496], [8.5, 4.772], [8.758, 5.48], [9.233, 6.444], [9.523, 6.453], [10.118, 7.039], [10.497, 7.055], [11.059, 6.644], [11.746, 6.981], [11.839, 7.397], [12.064, 7.8], [12.219, 8.306], [12.754, 8.718], [12.955, 9.418], [13.168, 9.641], [13.309, 10.16], [13.573, 10.799], [14.415, 11.572], [14.468, 11.905], [14.577, 12.085], [14.181, 12.484], [14.214, 12.802], [14.496, 12.859]]]] }, { "N": "Togo", "I": "TG", "C": [[[[0.9, 10.997], [0.772, 10.471], [1.078, 10.176], [1.425, 9.825], [1.463, 9.335], [1.664, 9.129], [1.619, 6.832], [1.865, 6.142], [1.06, 5.929], [0.837, 6.28], [0.57, 6.914], [0.491, 7.412], [0.712, 8.312], [0.461, 8.677], [0.366, 9.465], [0.368, 10.191], [-0.05, 10.707], [0.024, 11.019], [0.9, 10.997]]]] }, { "N": "Ghana", "I": "GH", "C": [[[[0.024, 11.019], [-0.05, 10.707], [0.368, 10.191], [0.366, 9.465], [0.461, 8.677], [0.712, 8.312], [0.491, 7.412], [0.57, 6.914], [0.837, 6.28], [1.06, 5.929], [-0.508, 5.343], [-1.064, 5.001], [-1.965, 4.71], [-2.856, 4.994], [-2.811, 5.389], [-3.244, 6.25], [-2.984, 7.38], [-2.562, 8.22], [-2.827, 9.642], [-2.964, 10.395], [-2.94, 10.963], [-1.203, 11.01], [-0.762, 10.937], [-0.439, 11.098], [0.024, 11.019]]]] }, { "N": "Côte d'Ivoire", "I": "CI", "C": [[[[-8.03, 10.207], [-7.9, 10.297], [-7.623, 10.147], [-6.851, 10.139], [-6.666, 10.431], [-6.494, 10.411], [-6.205, 10.524], [-6.05, 10.096], [-5.817, 10.223], [-5.404, 10.371], [-4.955, 10.153], [-4.78, 9.822], [-4.33, 9.611], [-3.98, 9.862], [-3.512, 9.9], [-2.827, 9.642], [-2.562, 8.22], [-2.984, 7.38], [-3.244, 6.25], [-2.811, 5.389], [-2.856, 4.994], [-3.311, 4.984], [-4.009, 5.18], [-4.65, 5.168], [-5.834, 4.994], [-6.529, 4.705], [-7.519, 4.338], [-7.712, 4.365], [-7.635, 5.188], [-7.54, 5.313], [-7.57, 5.707], [-7.994, 6.126], [-8.311, 6.193], [-8.603, 6.468], [-8.385, 6.912], [-8.485, 7.395], [-8.439, 7.686], [-8.281, 7.687], [-8.222, 8.123], [-8.299, 8.316], [-8.203, 8.455], [-7.832, 8.576], [-8.079, 9.376], [-8.31, 9.79], [-8.229, 10.129], [-8.03, 10.207]]]] }, { "N": "Guinea", "I": "GN", "C": [[[[-13.7, 12.586], [-13.218, 12.576], [-12.499, 12.332], [-12.279, 12.354], [-12.204, 12.466], [-11.658, 12.387], [-11.514, 12.443], [-11.456, 12.077], [-11.298, 12.078], [-11.037, 12.211], [-10.871, 12.178], [-10.593, 11.924], [-10.165, 11.844], [-9.891, 12.06], [-9.568, 12.194], [-9.328, 12.334], [-9.127, 12.308], [-8.905, 12.088], [-8.786, 11.813], [-8.376, 11.394], [-8.581, 11.136], [-8.62, 10.811], [-8.407, 10.909], [-8.282, 10.793], [-8.335, 10.495], [-8.03, 10.207], [-8.229, 10.129], [-8.31, 9.79], [-8.079, 9.376], [-7.832, 8.576], [-8.203, 8.455], [-8.299, 8.316], [-8.222, 8.123], [-8.281, 7.687], [-8.439, 7.686], [-8.722, 7.712], [-8.926, 7.309], [-9.209, 7.314], [-9.403, 7.527], [-9.337, 7.929], [-9.755, 8.541], [-10.017, 8.429], [-10.23, 8.406], [-10.505, 8.349], [-10.494, 8.716], [-10.655, 8.977], [-10.622, 9.268], [-10.839, 9.688], [-11.117, 10.046], [-11.917, 10.047], [-12.15, 9.859], [-12.426, 9.836], [-12.597, 9.62], [-12.712, 9.343], [-13.247, 8.903], [-13.685, 9.495], [-14.074, 9.886], [-14.33, 10.016], [-14.58, 10.214], [-14.693, 10.656], [-14.84, 10.877], [-15.13, 11.04], [-14.686, 11.528], [-14.382, 11.509], [-14.121, 11.677], [-13.901, 11.679], [-13.743, 11.811], [-13.828, 12.143], [-13.719, 12.247], [-13.7, 12.586]]]] }, { "N": "Guinea-Bissau", "I": "GW", "C": [[[[-16.677, 12.385], [-16.148, 12.548], [-15.817, 12.516], [-15.548, 12.628], [-13.7, 12.586], [-13.719, 12.247], [-13.828, 12.143], [-13.743, 11.811], [-13.901, 11.679], [-14.121, 11.677], [-14.382, 11.509], [-14.686, 11.528], [-15.13, 11.04], [-15.664, 11.458], [-16.085, 11.525], [-16.315, 11.807], [-16.309, 11.959], [-16.614, 12.171], [-16.677, 12.385]]]] }, { "N": "Liberia", "I": "LR", "C": [[[[-8.439, 7.686], [-8.485, 7.395], [-8.385, 6.912], [-8.603, 6.468], [-8.311, 6.193], [-7.994, 6.126], [-7.57, 5.707], [-7.54, 5.313], [-7.635, 5.188], [-7.712, 4.365], [-7.974, 4.356], [-9.005, 4.832], [-9.913, 5.594], [-10.765, 6.141], [-11.439, 6.786], [-11.2, 7.106], [-11.147, 7.397], [-10.696, 7.939], [-10.23, 8.406], [-10.017, 8.429], [-9.755, 8.541], [-9.337, 7.929], [-9.403, 7.527], [-9.209, 7.314], [-8.926, 7.309], [-8.722, 7.712], [-8.439, 7.686]]]] }, { "N": "Sierra Leone", "I": "SL", "C": [[[[-13.247, 8.903], [-12.712, 9.343], [-12.597, 9.62], [-12.426, 9.836], [-12.15, 9.859], [-11.917, 10.047], [-11.117, 10.046], [-10.839, 9.688], [-10.622, 9.268], [-10.655, 8.977], [-10.494, 8.716], [-10.505, 8.349], [-10.23, 8.406], [-10.696, 7.939], [-11.147, 7.397], [-11.2, 7.106], [-11.439, 6.786], [-11.708, 6.86], [-12.428, 7.263], [-12.949, 7.799], [-13.124, 8.164], [-13.247, 8.903]]]] }, { "N": "Burkina Faso", "I": "BF", "C": [[[[-5.404, 10.371], [-5.471, 10.951], [-5.198, 11.375], [-5.221, 11.714], [-4.427, 12.543], [-4.28, 13.228], [-4.006, 13.472], [-3.523, 13.338], [-3.104, 13.541], [-2.968, 13.798], [-2.192, 14.246], [-2.001, 14.559], [-1.066, 14.974], [-0.516, 15.116], [-0.266, 14.924], [0.375, 14.929], [0.296, 14.444], [0.43, 13.989], [0.993, 13.336], [1.024, 12.852], [2.177, 12.625], [2.154, 11.94], [1.936, 11.641], [1.447, 11.548], [1.243, 11.111], [0.9, 10.997], [0.024, 11.019], [-0.439, 11.098], [-0.762, 10.937], [-1.203, 11.01], [-2.94, 10.963], [-2.964, 10.395], [-2.827, 9.642], [-3.512, 9.9], [-3.98, 9.862], [-4.33, 9.611], [-4.78, 9.822], [-4.955, 10.153], [-5.404, 10.371]]]] }, { "N": "Central African Republic", "I": "CF", "C": [[[[27.374, 5.234], [27.044, 5.128], [26.403, 5.151], [25.65, 5.256], [25.279, 5.17], [25.129, 4.927], [24.805, 4.897], [24.411, 5.109], [23.297, 4.61], [22.841, 4.71], [22.704, 4.633], [22.405, 4.029], [21.659, 4.224], [20.928, 4.323], [20.291, 4.692], [19.468, 5.032], [18.932, 4.71], [18.543, 4.202], [18.453, 3.504], [17.81, 3.56], [17.133, 3.728], [16.537, 3.198], [16.013, 2.268], [15.907, 2.557], [15.863, 3.014], [15.405, 3.335], [15.036, 3.851], [14.951, 4.21], [14.478, 4.733], [14.559, 5.031], [14.459, 5.452], [14.537, 6.227], [14.777, 6.408], [15.279, 7.422], [16.106, 7.497], [16.291, 7.754], [16.456, 7.735], [16.706, 7.508], [17.965, 7.891], [18.39, 8.281], [18.911, 8.631], [18.812, 8.983], [19.094, 9.075], [20.06, 9.013], [21.001, 9.476], [21.724, 10.567], [22.231, 10.972], [22.864, 11.142], [22.978, 10.714], [23.554, 10.089], [23.557, 9.681], [23.395, 9.265], [23.459, 8.954], [23.806, 8.666], [24.567, 8.229], [25.115, 7.825], [25.124, 7.5], [25.797, 6.979], [26.213, 6.547], [26.466, 5.947], [27.213, 5.551], [27.374, 5.234]]]] }, { "N": "Republic of the Congo", "I": "CG", "C": [[[[18.453, 3.504], [18.394, 2.9], [18.094, 2.366], [17.899, 1.742], [17.774, 0.856], [17.827, 0.289], [17.664, -0.058], [17.639, -0.425], [17.524, -0.744], [16.865, -1.226], [16.407, -1.741], [15.973, -2.712], [16.006, -3.535], [15.754, -3.855], [15.171, -4.344], [14.583, -4.97], [14.209, -4.793], [14.145, -4.51], [13.6, -4.5], [13.258, -4.883], [12.996, -4.781], [12.621, -4.438], [12.319, -4.606], [11.915, -5.038], [11.094, -3.979], [11.855, -3.427], [11.478, -2.766], [11.821, -2.514], [12.496, -2.392], [12.575, -1.949], [13.11, -2.429], [13.992, -2.471], [14.299, -1.998], [14.425, -1.333], [14.316, -0.553], [13.843, 0.039], [14.276, 1.197], [14.027, 1.396], [13.283, 1.314], [13.003, 1.831], [13.076, 2.267], [14.338, 2.228], [15.146, 1.964], [15.941, 1.728], [16.013, 2.268], [16.537, 3.198], [17.133, 3.728], [17.81, 3.56], [18.453, 3.504]]]] }, { "N": "Gabon", "I": "GA", "C": [[[[11.276, 2.261], [11.752, 2.327], [12.359, 2.193], [12.951, 2.322], [13.076, 2.267], [13.003, 1.831], [13.283, 1.314], [14.027, 1.396], [14.276, 1.197], [13.843, 0.039], [14.316, -0.553], [14.425, -1.333], [14.299, -1.998], [13.992, -2.471], [13.11, -2.429], [12.575, -1.949], [12.496, -2.392], [11.821, -2.514], [11.478, -2.766], [11.855, -3.427], [11.094, -3.979], [10.066, -2.969], [9.405, -2.144], [8.798, -1.111], [8.83, -0.779], [9.048, -0.459], [9.291, 0.269], [9.493, 1.01], [9.83, 1.068], [11.285, 1.058], [11.276, 2.261]]]] }, { "N": "Equatorial Guinea", "I": "GQ", "C": [[[[9.649, 2.284], [11.276, 2.261], [11.285, 1.058], [9.83, 1.068], [9.493, 1.01], [9.306, 1.161], [9.649, 2.284]]]] }, { "N": "Zambia", "I": "ZM", "C": [[[[30.74, -8.34], [31.158, -8.595], [31.556, -8.762], [32.192, -8.93], [32.759, -9.231], [33.231, -9.677], [33.486, -10.526], [33.315, -10.797], [33.114, -11.607], [33.306, -12.436], [32.992, -12.784], [32.688, -13.713], [33.214, -13.972], [30.179, -14.796], [30.274, -15.508], [29.517, -15.645], [28.947, -16.043], [28.826, -16.39], [28.468, -16.468], [27.598, -17.291], [27.044, -17.938], [26.707, -17.961], [26.382, -17.846], [25.264, -17.737], [25.084, -17.662], [25.077, -17.579], [24.682, -17.353], [24.034, -17.296], [23.215, -17.523], [22.562, -16.898], [21.888, -16.08], [21.934, -12.898], [24.016, -12.911], [23.931, -12.566], [24.08, -12.191], [23.904, -11.722], [24.018, -11.237], [23.912, -10.927], [24.257, -10.952], [24.315, -11.263], [24.783, -11.239], [25.418, -11.331], [25.752, -11.785], [26.553, -11.924], [27.164, -11.609], [27.389, -12.133], [28.155, -12.272], [28.524, -12.699], [28.934, -13.249], [29.7, -13.257], [29.616, -12.179], [29.342, -12.361], [28.642, -11.972], [28.372, -11.794], [28.496, -10.79], [28.674, -9.606], [28.45, -9.165], [28.735, -8.527], [29.003, -8.407], [30.346, -8.238], [30.74, -8.34]]]] }, { "N": "Malawi", "I": "MW", "C": [[[[32.759, -9.231], [33.74, -9.417], [33.941, -9.694], [34.28, -10.16], [34.56, -11.52], [34.28, -12.28], [34.56, -13.58], [34.907, -13.565], [35.268, -13.888], [35.687, -14.611], [35.772, -15.897], [35.339, -16.107], [35.034, -16.801], [34.381, -16.184], [34.307, -15.479], [34.518, -15.014], [34.46, -14.613], [34.065, -14.36], [33.79, -14.452], [33.214, -13.972], [32.688, -13.713], [32.992, -12.784], [33.306, -12.436], [33.114, -11.607], [33.315, -10.797], [33.486, -10.526], [33.231, -9.677], [32.759, -9.231]]]] }, { "N": "Mozambique", "I": "MZ", "C": [[[[34.56, -11.52], [35.312, -11.439], [36.514, -11.721], [36.775, -11.595], [37.471, -11.569], [37.828, -11.269], [38.428, -11.285], [39.521, -10.897], [40.317, -10.317], [40.317, -10.317], [40.317, -10.317], [40.478, -10.765], [40.437, -11.762], [40.561, -12.639], [40.6, -14.202], [40.775, -14.692], [40.477, -15.406], [40.089, -16.101], [39.453, -16.721], [38.538, -17.101], [37.411, -17.586], [36.281, -18.66], [35.896, -18.842], [35.198, -19.553], [34.786, -19.784], [34.702, -20.497], [35.176, -21.254], [35.373, -21.841], [35.386, -22.14], [35.563, -22.09], [35.534, -23.071], [35.372, -23.535], [35.607, -23.707], [35.459, -24.123], [35.041, -24.478], [34.216, -24.816], [33.013, -25.358], [32.575, -25.727], [32.66, -26.149], [32.916, -26.216], [32.83, -26.742], [32.072, -26.734], [31.986, -26.292], [31.838, -25.843], [31.752, -25.484], [31.931, -24.369], [31.67, -23.659], [31.191, -22.252], [32.245, -21.116], [32.509, -20.395], [32.66, -20.304], [32.773, -19.716], [32.612, -19.419], [32.655, -18.672], [32.85, -17.979], [32.848, -16.713], [32.328, -16.392], [31.852, -16.319], [31.636, -16.072], [31.173, -15.861], [30.339, -15.881], [30.274, -15.508], [30.179, -14.796], [33.214, -13.972], [33.79, -14.452], [34.065, -14.36], [34.46, -14.613], [34.518, -15.014], [34.307, -15.479], [34.381, -16.184], [35.034, -16.801], [35.339, -16.107], [35.772, -15.897], [35.687, -14.611], [35.268, -13.888], [34.907, -13.565], [34.56, -13.58], [34.28, -12.28], [34.56, -11.52]]]] }, { "N": "Eswatini", "I": "SZ", "C": [[[[32.072, -26.734], [31.868, -27.178], [31.283, -27.286], [30.686, -26.744], [30.677, -26.398], [30.95, -26.023], [31.044, -25.731], [31.333, -25.66], [31.838, -25.843], [31.986, -26.292], [32.072, -26.734]]]] }, { "N": "Angola", "I": "AO", "C": [[[[12.996, -4.781], [12.632, -4.991], [12.468, -5.248], [12.437, -5.684], [12.182, -5.79], [11.915, -5.038], [12.319, -4.606], [12.621, -4.438], [12.996, -4.781]]], [[[12.322, -6.1], [12.735, -5.966], [13.025, -5.984], [13.376, -5.864], [16.327, -5.877], [16.573, -6.623], [16.86, -7.222], [17.09, -7.546], [17.473, -8.069], [18.134, -7.988], [18.464, -7.847], [19.017, -7.988], [19.167, -7.738], [19.418, -7.155], [20.038, -7.116], [20.092, -6.943], [20.602, -6.939], [20.515, -7.3], [21.728, -7.291], [21.746, -7.92], [21.949, -8.306], [21.802, -8.909], [21.875, -9.524], [22.209, -9.895], [22.155, -11.085], [22.403, -10.993], [22.837, -11.018], [23.457, -10.868], [23.912, -10.927], [24.018, -11.237], [23.904, -11.722], [24.08, -12.191], [23.931, -12.566], [24.016, -12.911], [21.934, -12.898], [21.888, -16.08], [22.562, -16.898], [23.215, -17.523], [21.377, -17.931], [18.956, -17.789], [18.263, -17.31], [14.21, -17.353], [14.059, -17.423], [13.462, -16.971], [12.814, -16.941], [12.215, -17.112], [11.734, -17.302], [11.64, -16.673], [11.779, -15.794], [12.124, -14.878], [12.176, -14.449], [12.5, -13.548], [12.738, -13.138], [13.313, -12.484], [13.634, -12.039], [13.739, -11.298], [13.686, -10.731], [13.387, -10.374], [13.121, -9.767], [12.875, -9.167], [12.929, -8.959], [13.236, -8.563], [12.933, -7.597], [12.728, -6.927], [12.227, -6.294], [12.322, -6.1]]]] }, { "N": "Burundi", "I": "BI", "C": [[[[30.47, -2.414], [30.528, -2.808], [30.743, -3.034], [30.752, -3.359], [30.506, -3.569], [30.116, -4.09], [29.754, -4.452], [29.34, -4.5], [29.276, -3.294], [29.025, -2.839], [29.632, -2.918], [29.938, -2.348], [30.47, -2.414]]]] }, { "N": "Israel", "I": "IL", "C": [[[[35.72, 32.709], [35.546, 32.394], [35.184, 32.533], [34.975, 31.867], [35.226, 31.754], [34.971, 31.617], [34.927, 31.353], [35.398, 31.489], [35.421, 31.1], [34.923, 29.501], [34.823, 29.761], [34.265, 31.219], [34.265, 31.219], [34.265, 31.219], [34.556, 31.549], [34.488, 31.606], [34.753, 32.073], [34.955, 32.827], [35.098, 33.081], [35.126, 33.091], [35.461, 33.089], [35.553, 33.264], [35.821, 33.277], [35.836, 32.868], [35.701, 32.716], [35.72, 32.709]]]] }, { "N": "Lebanon", "I": "LB", "C": [[[[35.821, 33.277], [35.553, 33.264], [35.461, 33.089], [35.126, 33.091], [35.482, 33.905], [35.98, 34.61], [35.998, 34.645], [36.448, 34.594], [36.612, 34.202], [36.066, 33.825], [35.821, 33.277]]]] }, { "N": "Madagascar", "I": "MG", "C": [[[[49.544, -12.47], [49.809, -12.895], [50.057, -13.556], [50.217, -14.759], [50.477, -15.227], [50.377, -15.706], [50.2, -16], [49.861, -15.414], [49.673, -15.71], [49.863, -16.451], [49.775, -16.875], [49.499, -17.106], [49.436, -17.953], [49.042, -19.119], [48.549, -20.497], [47.931, -22.392], [47.548, -23.782], [47.096, -24.942], [46.282, -25.178], [45.41, -25.601], [44.834, -25.346], [44.04, -24.988], [43.764, -24.461], [43.698, -23.574], [43.346, -22.777], [43.254, -22.057], [43.433, -21.336], [43.894, -21.163], [43.896, -20.83], [44.374, -20.072], [44.464, -19.435], [44.232, -18.962], [44.043, -18.331], [43.963, -17.41], [44.312, -16.85], [44.447, -16.216], [44.945, -16.179], [45.503, -15.974], [45.873, -15.793], [46.312, -15.78], [46.882, -15.21], [47.705, -14.594], [48.005, -14.091], [47.869, -13.664], [48.294, -13.784], [48.845, -13.089], [48.864, -12.488], [49.195, -12.041], [49.544, -12.47]]]] }, { "N": "Palestine", "I": "PS", "C": [[[[35.398, 31.489], [34.927, 31.353], [34.971, 31.617], [35.226, 31.754], [34.975, 31.867], [35.184, 32.533], [35.546, 32.394], [35.545, 31.783], [35.398, 31.489]]]] }, { "N": "The Gambia", "I": "GM", "C": [[[[-16.714, 13.595], [-15.625, 13.624], [-15.399, 13.86], [-15.082, 13.876], [-14.687, 13.63], [-14.377, 13.626], [-14.047, 13.794], [-13.845, 13.505], [-14.278, 13.281], [-14.712, 13.298], [-15.141, 13.51], [-15.512, 13.279], [-15.691, 13.27], [-15.931, 13.13], [-16.842, 13.151], [-16.714, 13.595]]]] }, { "N": "Tunisia", "I": "TN", "C": [[[[9.482, 30.308], [9.056, 32.103], [8.439, 32.506], [8.43, 32.748], [7.613, 33.344], [7.524, 34.097], [8.141, 34.655], [8.376, 35.48], [8.218, 36.433], [8.421, 36.946], [9.51, 37.35], [10.21, 37.23], [10.181, 36.724], [11.029, 37.092], [11.1, 36.9], [10.6, 36.41], [10.593, 35.947], [10.94, 35.699], [10.808, 34.834], [10.15, 34.331], [10.34, 33.786], [10.857, 33.769], [11.109, 33.293], [11.489, 33.137], [11.432, 32.369], [10.945, 32.082], [10.637, 31.761], [9.95, 31.376], [10.057, 30.962], [9.97, 30.539], [9.482, 30.308]]]] }, { "N": "Algeria", "I": "DZ", "C": [[[[-8.684, 27.396], [-8.665, 27.589], [-8.666, 27.656], [-8.674, 28.841], [-7.059, 29.579], [-6.061, 29.732], [-5.242, 30], [-4.86, 30.501], [-3.69, 30.897], [-3.647, 31.637], [-3.069, 31.724], [-2.617, 32.094], [-1.308, 32.263], [-1.125, 32.652], [-1.388, 32.864], [-1.733, 33.92], [-1.793, 34.528], [-2.17, 35.168], [-1.209, 35.715], [-0.127, 35.889], [0.504, 36.301], [1.467, 36.606], [3.162, 36.784], [4.816, 36.865], [5.32, 36.717], [6.262, 37.111], [7.33, 37.118], [7.737, 36.886], [8.421, 36.946], [8.218, 36.433], [8.376, 35.48], [8.141, 34.655], [7.524, 34.097], [7.613, 33.344], [8.43, 32.748], [8.439, 32.506], [9.056, 32.103], [9.482, 30.308], [9.806, 29.425], [9.86, 28.96], [9.684, 28.144], [9.756, 27.688], [9.629, 27.141], [9.716, 26.512], [9.319, 26.094], [9.911, 25.365], [9.948, 24.937], [10.304, 24.379], [10.771, 24.563], [11.561, 24.098], [12, 23.472], [8.573, 21.566], [5.678, 19.601], [4.267, 19.155], [3.158, 19.057], [3.147, 19.694], [2.684, 19.856], [2.061, 20.142], [1.823, 20.611], [-1.55, 22.793], [-4.923, 24.975], [-8.684, 27.396]]]] }, { "N": "Jordan", "I": "JO", "C": [[[[35.546, 32.394], [35.72, 32.709], [36.834, 32.313], [38.792, 33.379], [39.195, 32.161], [39.005, 32.01], [37.002, 31.508], [37.999, 30.508], [37.668, 30.339], [37.504, 30.004], [36.741, 29.865], [36.501, 29.505], [36.069, 29.197], [34.956, 29.357], [34.923, 29.501], [35.421, 31.1], [35.398, 31.489], [35.545, 31.783], [35.546, 32.394]]]] }, { "N": "United Arab Emirates", "I": "AE", "C": [[[[51.58, 24.245], [51.757, 24.294], [51.794, 24.02], [52.577, 24.177], [53.404, 24.151], [54.008, 24.122], [54.693, 24.798], [55.439, 25.439], [56.071, 26.055], [56.261, 25.715], [56.397, 24.925], [55.886, 24.921], [55.804, 24.27], [55.981, 24.131], [55.529, 23.934], [55.526, 23.525], [55.234, 23.111], [55.208, 22.708], [55.007, 22.497], [52.001, 23.001], [51.618, 24.014], [51.58, 24.245]]]] }, { "N": "Qatar", "I": "QA", "C": [[[[50.81, 24.755], [50.744, 25.482], [51.013, 26.007], [51.286, 26.115], [51.589, 25.801], [51.607, 25.216], [51.39, 24.627], [51.112, 24.556], [50.81, 24.755]]]] }, { "N": "Kuwait", "I": "KW", "C": [[[[47.975, 29.976], [48.183, 29.534], [48.094, 29.306], [48.416, 28.552], [47.709, 28.526], [47.46, 29.003], [46.569, 29.099], [47.303, 30.059], [47.975, 29.976]]]] }, { "N": "Iraq", "I": "IQ", "C": [[[[39.195, 32.161], [38.792, 33.379], [41.006, 34.419], [41.384, 35.628], [41.29, 36.359], [41.837, 36.606], [42.35, 37.23], [42.779, 37.385], [43.942, 37.256], [44.293, 37.002], [44.773, 37.17], [45.421, 35.978], [46.076, 35.677], [46.152, 35.093], [45.648, 34.748], [45.417, 33.968], [46.109, 33.017], [47.335, 32.469], [47.849, 31.709], [47.685, 30.985], [48.005, 30.985], [48.015, 30.452], [48.568, 29.927], [47.975, 29.976], [47.303, 30.059], [46.569, 29.099], [44.709, 29.179], [41.89, 31.19], [40.4, 31.89], [39.195, 32.161]]]] }, { "N": "Oman", "I": "OM", "C": [[[[55.208, 22.708], [55.234, 23.111], [55.526, 23.525], [55.529, 23.934], [55.981, 24.131], [55.804, 24.27], [55.886, 24.921], [56.397, 24.925], [56.845, 24.242], [57.403, 23.879], [58.137, 23.748], [58.729, 23.566], [59.181, 22.992], [59.45, 22.66], [59.808, 22.534], [59.806, 22.311], [59.442, 21.715], [59.282, 21.434], [58.861, 21.114], [58.488, 20.429], [58.034, 20.481], [57.826, 20.243], [57.666, 19.736], [57.789, 19.068], [57.694, 18.945], [57.234, 18.948], [56.61, 18.574], [56.512, 18.087], [56.284, 17.876], [55.661, 17.884], [55.27, 17.632], [55.275, 17.228], [54.791, 16.951], [54.239, 17.045], [53.571, 16.708], [53.109, 16.651], [52.782, 17.35], [52, 19], [55, 20], [55.667, 22], [55.208, 22.708]]], [[[56.261, 25.715], [56.071, 26.055], [56.362, 26.396], [56.486, 26.309], [56.391, 25.896], [56.261, 25.715]]]] }, { "N": "Vanuatu", "I": "VU", "C": [[[[167.217, -15.892], [167.845, -16.466], [167.515, -16.598], [167.18, -16.16], [167.217, -15.892]]], [[[166.793, -15.669], [166.65, -15.393], [166.629, -14.626], [167.108, -14.934], [167.27, -15.74], [167.001, -15.615], [166.793, -15.669]]]] }, { "N": "Cambodia", "I": "KH", "C": [[[[102.585, 12.187], [102.348, 13.394], [102.988, 14.226], [104.281, 14.417], [105.219, 14.273], [106.044, 13.881], [106.496, 14.571], [107.383, 14.202], [107.615, 13.536], [107.491, 12.337], [105.811, 11.568], [106.25, 10.962], [105.2, 10.889], [104.334, 10.487], [103.497, 10.633], [103.091, 11.154], [102.585, 12.187]]]] }, { "N": "Thailand", "I": "TH", "C": [[[[105.219, 14.273], [104.281, 14.417], [102.988, 14.226], [102.348, 13.394], [102.585, 12.187], [101.687, 12.646], [100.832, 12.627], [100.978, 13.413], [100.098, 13.407], [100.019, 12.307], [99.479, 10.846], [99.154, 9.963], [99.222, 9.239], [99.874, 9.208], [100.28, 8.295], [100.459, 7.43], [101.017, 6.857], [101.623, 6.741], [102.141, 6.222], [101.814, 5.811], [101.154, 5.691], [101.076, 6.205], [100.26, 6.643], [100.086, 6.464], [99.691, 6.848], [99.52, 7.343], [98.988, 7.908], [98.504, 8.382], [98.34, 7.795], [98.15, 8.35], [98.259, 8.974], [98.554, 9.933], [99.038, 10.961], [99.587, 11.893], [99.196, 12.805], [99.212, 13.269], [99.098, 13.828], [98.431, 14.622], [98.192, 15.124], [98.537, 15.308], [98.903, 16.178], [98.494, 16.838], [97.859, 17.568], [97.376, 18.445], [97.798, 18.627], [98.254, 19.708], [98.96, 19.753], [99.543, 20.187], [100.116, 20.418], [100.549, 20.109], [100.606, 19.508], [101.282, 19.463], [101.036, 18.409], [101.06, 17.512], [102.114, 18.109], [102.413, 17.933], [102.999, 17.962], [103.2, 18.31], [103.956, 18.241], [104.717, 17.429], [104.779, 16.442], [105.589, 15.57], [105.544, 14.724], [105.219, 14.273]]]] }, { "N": "Lao PDR", "I": "LA", "C": [[[[107.383, 14.202], [106.496, 14.571], [106.044, 13.881], [105.219, 14.273], [105.544, 14.724], [105.589, 15.57], [104.779, 16.442], [104.717, 17.429], [103.956, 18.241], [103.2, 18.31], [102.999, 17.962], [102.413, 17.933], [102.114, 18.109], [101.06, 17.512], [101.036, 18.409], [101.282, 19.463], [100.606, 19.508], [100.549, 20.109], [100.116, 20.418], [100.329, 20.786], [101.18, 21.437], [101.27, 21.202], [101.803, 21.174], [101.652, 22.318], [102.17, 22.465], [102.755, 21.675], [103.204, 20.767], [104.435, 20.759], [104.823, 19.887], [104.183, 19.625], [103.897, 19.265], [105.095, 18.667], [105.926, 17.485], [106.556, 16.604], [107.313, 15.909], [107.565, 15.202], [107.383, 14.202]]]] }, { "N": "Myanmar", "I": "MM", "C": [[[[100.116, 20.418], [99.543, 20.187], [98.96, 19.753], [98.254, 19.708], [97.798, 18.627], [97.376, 18.445], [97.859, 17.568], [98.494, 16.838], [98.903, 16.178], [98.537, 15.308], [98.192, 15.124], [98.431, 14.622], [99.098, 13.828], [99.212, 13.269], [99.196, 12.805], [99.587, 11.893], [99.038, 10.961], [98.554, 9.933], [98.457, 10.675], [98.765, 11.441], [98.428, 12.033], [98.51, 13.122], [98.104, 13.64], [97.778, 14.837], [97.597, 16.101], [97.165, 16.929], [96.506, 16.427], [95.369, 15.714], [94.808, 15.803], [94.189, 16.038], [94.533, 17.277], [94.325, 18.214], [93.541, 19.366], [93.663, 19.727], [93.078, 19.855], [92.369, 20.671], [92.303, 21.475], [92.652, 21.324], [92.673, 22.041], [93.166, 22.278], [93.06, 22.703], [93.286, 23.044], [93.325, 24.079], [94.107, 23.851], [94.553, 24.675], [94.603, 25.162], [95.155, 26.001], [95.125, 26.574], [96.419, 27.265], [97.134, 27.084], [97.052, 27.699], [97.403, 27.883], [97.327, 28.262], [97.912, 28.336], [98.246, 27.747], [98.683, 27.509], [98.712, 26.744], [98.672, 25.919], [97.725, 25.084], [97.605, 23.897], [98.66, 24.063], [98.899, 23.143], [99.532, 22.949], [99.241, 22.118], [99.983, 21.743], [100.417, 21.559], [101.15, 21.85], [101.18, 21.437], [100.329, 20.786], [100.116, 20.418]]]] }, { "N": "Vietnam", "I": "VN", "C": [[[[104.334, 10.487], [105.2, 10.889], [106.25, 10.962], [105.811, 11.568], [107.491, 12.337], [107.615, 13.536], [107.383, 14.202], [107.565, 15.202], [107.313, 15.909], [106.556, 16.604], [105.926, 17.485], [105.095, 18.667], [103.897, 19.265], [104.183, 19.625], [104.823, 19.887], [104.435, 20.759], [103.204, 20.767], [102.755, 21.675], [102.17, 22.465], [102.707, 22.709], [103.505, 22.704], [104.477, 22.819], [105.329, 23.352], [105.811, 22.977], [106.725, 22.794], [106.567, 22.218], [107.043, 21.812], [108.05, 21.552], [106.715, 20.697], [105.882, 19.752], [105.662, 19.058], [106.427, 18.004], [107.362, 16.697], [108.269, 16.08], [108.877, 15.277], [109.335, 13.426], [109.2, 11.667], [108.366, 11.008], [107.221, 10.364], [106.405, 9.531], [105.158, 8.6], [104.795, 9.241], [105.076, 9.918], [104.334, 10.487]]]] }, { "N": "Dem. Rep. Korea", "I": "KP", "C": [[[[130.78, 42.22], [130.78, 42.22], [130.78, 42.22], [130.78, 42.22]]], [[[130.64, 42.395], [130.64, 42.395], [130.78, 42.22], [130.4, 42.28], [129.966, 41.941], [129.667, 41.601], [129.705, 40.883], [129.188, 40.662], [129.01, 40.485], [128.633, 40.19], [127.967, 40.025], [127.533, 39.757], [127.502, 39.324], [127.385, 39.213], [127.783, 39.051], [128.35, 38.612], [128.206, 38.37], [127.78, 38.305], [127.073, 38.256], [126.684, 37.805], [126.237, 37.84], [126.175, 37.75], [125.689, 37.94], [125.568, 37.752], [125.275, 37.669], [125.24, 37.857], [124.981, 37.949], [124.712, 38.108], [124.986, 38.548], [125.222, 38.666], [125.133, 38.849], [125.387, 39.388], [125.321, 39.551], [124.737, 39.66], [124.266, 39.928], [125.08, 40.57], [126.182, 41.107], [126.869, 41.817], [127.344, 41.503], [128.208, 41.467], [128.052, 41.994], [129.597, 42.425], [129.994, 42.985], [130.64, 42.395]]]] }, { "N": "Republic of Korea", "I": "KR", "C": [[[[126.175, 37.75], [126.237, 37.84], [126.684, 37.805], [127.073, 38.256], [127.78, 38.305], [128.206, 38.37], [128.35, 38.612], [129.213, 37.432], [129.46, 36.784], [129.468, 35.632], [129.091, 35.082], [128.186, 34.89], [127.387, 34.476], [126.486, 34.39], [126.374, 34.935], [126.559, 35.685], [126.117, 36.725], [126.86, 36.894], [126.175, 37.75]]]] }, { "N": "Mongolia", "I": "MN", "C": [[[[87.751, 49.297], [88.806, 49.471], [90.714, 50.332], [92.235, 50.802], [93.104, 50.495], [94.148, 50.481], [94.816, 50.013], [95.814, 49.977], [97.26, 49.726], [98.232, 50.422], [97.826, 51.011], [98.861, 52.047], [99.982, 51.634], [100.889, 51.517], [102.065, 51.26], [102.256, 50.511], [103.677, 50.09], [104.622, 50.275], [105.887, 50.406], [106.889, 50.274], [107.868, 49.794], [108.475, 49.283], [109.402, 49.293], [110.662, 49.13], [111.581, 49.378], [112.898, 49.544], [114.362, 50.248], [114.962, 50.14], [115.486, 49.805], [116.679, 49.889], [116.192, 49.135], [115.485, 48.135], [115.743, 47.727], [116.309, 47.853], [117.296, 47.698], [118.064, 48.067], [118.867, 47.747], [119.773, 47.048], [119.663, 46.693], [118.874, 46.805], [117.422, 46.673], [116.718, 46.388], [115.985, 45.727], [114.46, 45.34], [113.464, 44.809], [112.436, 45.012], [111.873, 45.102], [111.348, 44.457], [111.668, 44.073], [111.83, 43.743], [111.13, 43.407], [110.412, 42.871], [109.244, 42.519], [107.745, 42.482], [106.129, 42.134], [104.965, 41.597], [104.522, 41.908], [103.312, 41.907], [101.833, 42.515], [100.846, 42.664], [99.516, 42.525], [97.452, 42.749], [96.349, 42.726], [95.762, 43.319], [95.307, 44.241], [94.689, 44.352], [93.481, 44.975], [92.134, 45.115], [90.946, 45.286], [90.586, 45.72], [90.971, 46.888], [90.281, 47.694], [88.854, 48.069], [88.014, 48.599], [87.751, 49.297]]]] }, { "N": "India", "I": "IN", "C": [[[[97.327, 28.262], [97.403, 27.883], [97.052, 27.699], [97.134, 27.084], [96.419, 27.265], [95.125, 26.574], [95.155, 26.001], [94.603, 25.162], [94.553, 24.675], [94.107, 23.851], [93.325, 24.079], [93.286, 23.044], [93.06, 22.703], [93.166, 22.278], [92.673, 22.041], [92.146, 23.627], [91.87, 23.624], [91.706, 22.985], [91.159, 23.504], [91.468, 24.073], [91.915, 24.13], [92.376, 24.977], [91.8, 25.147], [90.872, 25.133], [89.921, 25.27], [89.832, 25.965], [89.355, 26.014], [88.563, 26.447], [88.21, 25.768], [88.932, 25.239], [88.306, 24.866], [88.084, 24.502], [88.7, 24.234], [88.53, 23.631], [88.876, 22.879], [89.032, 22.056], [88.889, 21.691], [88.208, 21.703], [86.976, 21.496], [87.033, 20.743], [86.499, 20.152], [85.06, 19.479], [83.941, 18.302], [83.189, 17.671], [82.193, 17.017], [82.191, 16.557], [81.693, 16.31], [80.792, 15.952], [80.325, 15.899], [80.025, 15.136], [80.233, 13.836], [80.286, 13.006], [79.863, 12.056], [79.858, 10.357], [79.341, 10.309], [78.885, 9.546], [79.19, 9.217], [78.278, 8.933], [77.941, 8.253], [77.54, 7.966], [76.593, 8.899], [76.13, 10.3], [75.746, 11.308], [75.396, 11.781], [74.865, 12.742], [74.617, 13.993], [74.444, 14.617], [73.534, 15.991], [73.12, 17.929], [72.821, 19.208], [72.824, 20.42], [72.631, 21.356], [71.175, 20.757], [70.47, 20.877], [69.164, 22.089], [69.645, 22.451], [69.35, 22.843], [68.177, 23.692], [68.843, 24.359], [71.043, 24.357], [70.845, 25.215], [70.283, 25.722], [70.169, 26.492], [69.514, 26.941], [70.616, 27.989], [71.778, 27.913], [72.824, 28.962], [73.451, 29.976], [74.421, 30.98], [74.406, 31.693], [75.259, 32.271], [74.452, 32.765], [74.104, 33.441], [73.75, 34.318], [74.24, 34.749], [75.757, 34.505], [76.872, 34.654], [77.837, 35.494], [78.912, 34.322], [78.811, 33.506], [79.209, 32.994], [79.176, 32.484], [78.458, 32.618], [78.739, 31.516], [79.721, 30.883], [81.111, 30.183], [80.477, 29.73], [80.088, 28.794], [81.057, 28.416], [82, 27.925], [83.304, 27.365], [84.675, 27.235], [85.252, 26.726], [86.024, 26.631], [87.227, 26.398], [88.06, 26.415], [88.175, 26.81], [88.043, 27.446], [88.12, 27.877], [88.73, 28.087], [88.814, 27.299], [88.836, 27.099], [89.745, 26.719], [90.373, 26.876], [91.218, 26.809], [92.033, 26.838], [92.104, 27.453], [91.697, 27.772], [92.503, 27.897], [93.413, 28.641], [94.566, 29.277], [95.405, 29.032], [96.118, 29.453], [96.587, 28.831], [96.249, 28.411], [97.327, 28.262]]]] }, { "N": "Bangladesh", "I": "BD", "C": [[[[92.673, 22.041], [92.652, 21.324], [92.303, 21.475], [92.369, 20.671], [92.083, 21.192], [92.025, 21.702], [91.835, 22.183], [91.417, 22.765], [90.496, 22.805], [90.587, 22.393], [90.273, 21.836], [89.847, 22.039], [89.702, 21.857], [89.419, 21.966], [89.032, 22.056], [88.876, 22.879], [88.53, 23.631], [88.7, 24.234], [88.084, 24.502], [88.306, 24.866], [88.932, 25.239], [88.21, 25.768], [88.563, 26.447], [89.355, 26.014], [89.832, 25.965], [89.921, 25.27], [90.872, 25.133], [91.8, 25.147], [92.376, 24.977], [91.915, 24.13], [91.468, 24.073], [91.159, 23.504], [91.706, 22.985], [91.87, 23.624], [92.146, 23.627], [92.673, 22.041]]]] }, { "N": "Bhutan", "I": "BT", "C": [[[[91.697, 27.772], [92.104, 27.453], [92.033, 26.838], [91.218, 26.809], [90.373, 26.876], [89.745, 26.719], [88.836, 27.099], [88.814, 27.299], [89.476, 28.043], [90.016, 28.296], [90.731, 28.065], [91.259, 28.041], [91.697, 27.772]]]] }, { "N": "Nepal", "I": "NP", "C": [[[[88.12, 27.877], [88.043, 27.446], [88.175, 26.81], [88.06, 26.415], [87.227, 26.398], [86.024, 26.631], [85.252, 26.726], [84.675, 27.235], [83.304, 27.365], [82, 27.925], [81.057, 28.416], [80.088, 28.794], [80.477, 29.73], [81.111, 30.183], [81.526, 30.423], [82.328, 30.115], [83.337, 29.464], [83.899, 29.32], [84.235, 28.84], [85.012, 28.643], [85.823, 28.204], [86.955, 27.974], [88.12, 27.877]]]] }, { "N": "Pakistan", "I": "PK", "C": [[[[77.837, 35.494], [76.872, 34.654], [75.757, 34.505], [74.24, 34.749], [73.75, 34.318], [74.104, 33.441], [74.452, 32.765], [75.259, 32.271], [74.406, 31.693], [74.421, 30.98], [73.451, 29.976], [72.824, 28.962], [71.778, 27.913], [70.616, 27.989], [69.514, 26.941], [70.169, 26.492], [70.283, 25.722], [70.845, 25.215], [71.043, 24.357], [68.843, 24.359], [68.177, 23.692], [67.444, 23.945], [67.145, 24.664], [66.373, 25.425], [64.53, 25.237], [62.906, 25.218], [61.497, 25.078], [61.874, 26.24], [63.317, 26.757], [63.234, 27.217], [62.755, 27.379], [62.728, 28.26], [61.772, 28.699], [61.369, 29.303], [60.874, 29.829], [62.55, 29.319], [63.55, 29.468], [64.148, 29.341], [64.35, 29.56], [65.047, 29.472], [66.346, 29.888], [66.381, 30.739], [66.939, 31.305], [67.683, 31.303], [67.793, 31.583], [68.557, 31.713], [68.927, 31.62], [69.318, 31.901], [69.263, 32.502], [69.687, 33.105], [70.324, 33.359], [69.931, 34.02], [70.882, 33.989], [71.157, 34.349], [71.115, 34.733], [71.613, 35.153], [71.499, 35.651], [71.262, 36.074], [71.846, 36.51], [72.92, 36.72], [74.068, 36.836], [74.576, 37.021], [75.158, 37.133], [75.897, 36.667], [76.193, 35.898], [77.837, 35.494]]]] }, { "N": "Afghanistan", "I": "AF", "C": [[[[66.519, 37.363], [67.076, 37.356], [67.83, 37.145], [68.136, 37.023], [68.859, 37.344], [69.196, 37.151], [69.519, 37.609], [70.117, 37.588], [70.271, 37.735], [70.376, 38.138], [70.807, 38.486], [71.348, 38.259], [71.239, 37.953], [71.542, 37.906], [71.449, 37.066], [71.845, 36.738], [72.193, 36.948], [72.637, 37.048], [73.26, 37.495], [73.949, 37.422], [74.98, 37.42], [75.158, 37.133], [74.576, 37.021], [74.068, 36.836], [72.92, 36.72], [71.846, 36.51], [71.262, 36.074], [71.499, 35.651], [71.613, 35.153], [71.115, 34.733], [71.157, 34.349], [70.882, 33.989], [69.931, 34.02], [70.324, 33.359], [69.687, 33.105], [69.263, 32.502], [69.318, 31.901], [68.927, 31.62], [68.557, 31.713], [67.793, 31.583], [67.683, 31.303], [66.939, 31.305], [66.381, 30.739], [66.346, 29.888], [65.047, 29.472], [64.35, 29.56], [64.148, 29.341], [63.55, 29.468], [62.55, 29.319], [60.874, 29.829], [61.781, 30.736], [61.699, 31.38], [60.942, 31.548], [60.864, 32.183], [60.536, 32.981], [60.964, 33.529], [60.528, 33.676], [60.803, 34.404], [61.211, 35.65], [62.231, 35.271], [62.985, 35.404], [63.194, 35.857], [63.983, 36.008], [64.546, 36.312], [64.746, 37.112], [65.589, 37.305], [65.746, 37.661], [66.217, 37.394], [66.519, 37.363]]]] }, { "N": "Tajikistan", "I": "TJ", "C": [[[[67.83, 37.145], [68.392, 38.157], [68.176, 38.902], [67.442, 39.14], [67.701, 39.58], [68.536, 39.533], [69.012, 40.086], [69.329, 40.728], [70.667, 40.96], [70.458, 40.496], [70.601, 40.219], [71.014, 40.244], [70.648, 39.936], [69.56, 40.103], [69.465, 39.527], [70.549, 39.604], [71.785, 39.279], [73.675, 39.431], [73.929, 38.506], [74.258, 38.607], [74.865, 38.379], [74.83, 37.99], [74.98, 37.42], [73.949, 37.422], [73.26, 37.495], [72.637, 37.048], [72.193, 36.948], [71.845, 36.738], [71.449, 37.066], [71.542, 37.906], [71.239, 37.953], [71.348, 38.259], [70.807, 38.486], [70.376, 38.138], [70.271, 37.735], [70.117, 37.588], [69.519, 37.609], [69.196, 37.151], [68.859, 37.344], [68.136, 37.023], [67.83, 37.145]]]] }, { "N": "Kyrgyzstan", "I": "KG", "C": [[[[70.962, 42.266], [71.186, 42.704], [71.845, 42.845], [73.49, 42.501], [73.645, 43.091], [74.213, 43.298], [75.637, 42.878], [76, 42.988], [77.658, 42.961], [79.142, 42.856], [79.644, 42.497], [80.26, 42.35], [80.119, 42.124], [78.544, 41.582], [78.187, 41.185], [76.904, 41.066], [76.526, 40.428], [75.468, 40.562], [74.777, 40.366], [73.822, 39.894], [73.96, 39.66], [73.675, 39.431], [71.785, 39.279], [70.549, 39.604], [69.465, 39.527], [69.56, 40.103], [70.648, 39.936], [71.014, 40.244], [71.775, 40.146], [73.055, 40.866], [71.87, 41.393], [71.158, 41.144], [70.42, 41.52], [71.259, 42.168], [70.962, 42.266]]]] }, { "N": "Turkmenistan", "I": "TM", "C": [[[[52.502, 41.783], [52.944, 42.116], [54.079, 42.324], [54.755, 42.044], [55.455, 41.26], [55.968, 41.309], [57.096, 41.322], [56.932, 41.826], [57.787, 42.171], [58.629, 42.752], [59.976, 42.223], [60.083, 41.425], [60.466, 41.22], [61.547, 41.266], [61.883, 41.085], [62.374, 40.054], [63.518, 39.363], [64.17, 38.892], [65.216, 38.403], [66.546, 37.975], [66.519, 37.363], [66.217, 37.394], [65.746, 37.661], [65.589, 37.305], [64.746, 37.112], [64.546, 36.312], [63.983, 36.008], [63.194, 35.857], [62.985, 35.404], [62.231, 35.271], [61.211, 35.65], [61.123, 36.492], [60.378, 36.527], [59.235, 37.413], [58.436, 37.522], [57.33, 38.029], [56.619, 38.121], [56.18, 37.935], [55.512, 37.964], [54.8, 37.392], [53.922, 37.199], [53.736, 37.906], [53.881, 38.952], [53.101, 39.291], [53.358, 39.975], [52.694, 40.034], [52.915, 40.877], [53.858, 40.631], [54.737, 40.951], [54.008, 41.551], [53.722, 42.123], [52.917, 41.868], [52.815, 41.135], [52.502, 41.783]]]] }, { "N": "Iran", "I": "IR", "C": [[[[48.568, 29.927], [48.015, 30.452], [48.005, 30.985], [47.685, 30.985], [47.849, 31.709], [47.335, 32.469], [46.109, 33.017], [45.417, 33.968], [45.648, 34.748], [46.152, 35.093], [46.076, 35.677], [45.421, 35.978], [44.773, 37.17], [44.773, 37.17], [44.226, 37.972], [44.421, 38.281], [44.109, 39.428], [44.794, 39.713], [44.953, 39.336], [45.458, 38.874], [46.144, 38.741], [46.506, 38.771], [47.685, 39.508], [48.06, 39.582], [48.356, 39.289], [48.011, 38.794], [48.634, 38.27], [48.883, 38.32], [49.2, 37.583], [50.148, 37.375], [50.842, 36.873], [52.264, 36.7], [53.826, 36.965], [53.922, 37.199], [54.8, 37.392], [55.512, 37.964], [56.18, 37.935], [56.619, 38.121], [57.33, 38.029], [58.436, 37.522], [59.235, 37.413], [60.378, 36.527], [61.123, 36.492], [61.211, 35.65], [60.803, 34.404], [60.528, 33.676], [60.964, 33.529], [60.536, 32.981], [60.864, 32.183], [60.942, 31.548], [61.699, 31.38], [61.781, 30.736], [60.874, 29.829], [61.369, 29.303], [61.772, 28.699], [62.728, 28.26], [62.755, 27.379], [63.234, 27.217], [63.317, 26.757], [61.874, 26.24], [61.497, 25.078], [59.616, 25.38], [58.526, 25.61], [57.397, 25.74], [56.971, 26.966], [56.492, 27.143], [55.724, 26.965], [54.715, 26.481], [53.493, 26.812], [52.484, 27.581], [51.521, 27.866], [50.853, 28.815], [50.115, 30.148], [49.577, 29.986], [48.941, 30.317], [48.568, 29.927]]]] }, { "N": "Syria", "I": "SY", "C": [[[[35.72, 32.709], [35.701, 32.716], [35.836, 32.868], [35.821, 33.277], [36.066, 33.825], [36.612, 34.202], [36.448, 34.594], [35.998, 34.645], [35.905, 35.41], [36.15, 35.822], [36.418, 36.041], [36.685, 36.26], [36.739, 36.818], [37.067, 36.623], [38.168, 36.901], [38.7, 36.713], [39.523, 36.716], [40.673, 37.091], [41.212, 37.074], [42.35, 37.23], [41.837, 36.606], [41.29, 36.359], [41.384, 35.628], [41.006, 34.419], [38.792, 33.379], [36.834, 32.313], [35.72, 32.709]]]] }, { "N": "Armenia", "I": "AM", "C": [[[[46.506, 38.771], [46.144, 38.741], [45.735, 39.32], [45.74, 39.474], [45.298, 39.472], [45.002, 39.74], [44.794, 39.713], [44.4, 40.005], [43.656, 40.254], [43.753, 40.74], [43.583, 41.092], [44.972, 41.248], [45.179, 40.985], [45.56, 40.812], [45.359, 40.562], [45.892, 40.218], [45.61, 39.9], [46.035, 39.628], [46.483, 39.464], [46.506, 38.771]]]] }, { "N": "Sweden", "I": "SE", "C": [[[[11.027, 58.856], [11.468, 59.432], [12.3, 60.118], [12.631, 61.294], [11.992, 61.8], [11.931, 63.128], [12.58, 64.066], [13.572, 64.049], [13.92, 64.445], [13.556, 64.787], [15.108, 66.194], [16.109, 67.302], [16.769, 68.014], [17.729, 68.011], [17.994, 68.567], [19.879, 68.407], [20.025, 69.065], [20.646, 69.106], [21.979, 68.617], [23.539, 67.936], [23.566, 66.396], [23.903, 66.007], [22.183, 65.724], [21.214, 65.026], [21.37, 64.414], [19.779, 63.61], [17.848, 62.749], [17.12, 61.341], [17.831, 60.637], [18.788, 60.082], [17.869, 58.954], [16.829, 58.72], [16.448, 57.041], [15.88, 56.104], [14.667, 56.201], [14.101, 55.408], [12.943, 55.362], [12.625, 56.307], [11.788, 57.442], [11.027, 58.856]]]] }, { "N": "Belarus", "I": "BY", "C": [[[[28.177, 56.169], [29.23, 55.918], [29.372, 55.67], [29.896, 55.789], [30.874, 55.551], [30.972, 55.082], [30.758, 54.812], [31.384, 54.157], [31.791, 53.975], [31.731, 53.794], [32.406, 53.618], [32.694, 53.351], [32.305, 53.133], [31.498, 53.167], [31.305, 53.074], [31.54, 52.742], [31.786, 52.102], [31.786, 52.102], [30.928, 52.042], [30.619, 51.823], [30.555, 51.32], [30.157, 51.416], [29.255, 51.368], [28.993, 51.602], [28.618, 51.428], [28.242, 51.572], [27.454, 51.592], [26.338, 51.832], [25.328, 51.911], [24.553, 51.888], [24.005, 51.617], [23.527, 51.578], [23.508, 52.024], [23.199, 52.487], [23.799, 52.691], [23.805, 53.09], [23.528, 53.47], [23.484, 53.912], [24.451, 53.906], [25.536, 54.282], [25.768, 54.847], [26.588, 55.167], [26.494, 55.615], [27.102, 55.783], [28.177, 56.169]]]] }, { "N": "Ukraine", "I": "UA", "C": [[[[31.786, 52.102], [32.159, 52.061], [32.412, 52.289], [32.716, 52.238], [33.753, 52.335], [34.392, 51.769], [34.142, 51.566], [34.225, 51.256], [35.022, 51.208], [35.378, 50.774], [35.356, 50.577], [36.626, 50.226], [37.393, 50.384], [38.011, 49.916], [38.595, 49.926], [40.069, 49.601], [40.081, 49.307], [39.675, 48.784], [39.896, 48.232], [39.738, 47.899], [38.771, 47.826], [38.255, 47.546], [38.224, 47.102], [37.425, 47.022], [36.76, 46.699], [35.824, 46.646], [34.962, 46.273], [35.013, 45.738], [34.862, 45.768], [34.732, 45.966], [34.41, 46.005], [33.699, 46.22], [33.436, 45.972], [33.299, 46.081], [31.744, 46.333], [31.675, 46.706], [30.749, 46.583], [30.378, 46.032], [29.603, 45.293], [29.15, 45.465], [28.68, 45.304], [28.234, 45.488], [28.485, 45.597], [28.66, 45.94], [28.934, 46.259], [28.863, 46.438], [29.072, 46.518], [29.171, 46.379], [29.76, 46.35], [30.025, 46.424], [29.838, 46.525], [29.909, 46.674], [29.56, 46.929], [29.415, 47.347], [29.051, 47.51], [29.123, 47.849], [28.671, 48.118], [28.26, 48.156], [27.523, 48.467], [26.858, 48.368], [26.619, 48.221], [26.197, 48.221], [25.946, 47.987], [25.208, 47.891], [24.866, 47.738], [24.402, 47.982], [23.761, 47.986], [23.142, 48.096], [22.711, 47.882], [22.641, 48.15], [22.086, 48.422], [22.281, 48.825], [22.558, 49.086], [22.776, 49.027], [22.518, 49.477], [23.427, 50.309], [23.923, 50.425], [24.03, 50.705], [23.527, 51.578], [24.005, 51.617], [24.553, 51.888], [25.328, 51.911], [26.338, 51.832], [27.454, 51.592], [28.242, 51.572], [28.618, 51.428], [28.993, 51.602], [29.255, 51.368], [30.157, 51.416], [30.555, 51.32], [30.619, 51.823], [30.928, 52.042], [31.786, 52.102]]], [[[33.436, 45.972], [33.699, 46.22], [34.41, 46.005], [34.732, 45.966], [34.862, 45.768], [35.013, 45.738], [35.021, 45.651], [35.51, 45.41], [36.53, 45.47], [36.335, 45.113], [35.24, 44.94], [33.883, 44.361], [33.326, 44.565], [33.547, 45.035], [32.454, 45.327], [32.631, 45.519], [33.588, 45.852], [33.436, 45.972]]]] }, { "N": "Poland", "I": "PL", "C": [[[[23.484, 53.912], [23.528, 53.47], [23.805, 53.09], [23.799, 52.691], [23.199, 52.487], [23.508, 52.024], [23.527, 51.578], [24.03, 50.705], [23.923, 50.425], [23.427, 50.309], [22.518, 49.477], [22.776, 49.027], [22.558, 49.086], [21.608, 49.47], [20.888, 49.329], [20.416, 49.431], [19.825, 49.217], [19.321, 49.572], [18.91, 49.436], [18.853, 49.496], [18.393, 49.989], [17.649, 50.049], [17.555, 50.362], [16.869, 50.474], [16.719, 50.216], [16.176, 50.423], [16.239, 50.698], [15.491, 50.785], [15.017, 51.107], [14.607, 51.745], [14.685, 52.09], [14.438, 52.625], [14.075, 52.981], [14.353, 53.248], [14.12, 53.757], [14.803, 54.051], [16.363, 54.513], [17.623, 54.852], [18.621, 54.683], [18.696, 54.439], [19.661, 54.426], [20.892, 54.313], [22.731, 54.328], [23.244, 54.221], [23.484, 53.912]]]] }, { "N": "Austria", "I": "AT", "C": [[[[16.98, 48.123], [16.904, 47.715], [16.341, 47.713], [16.534, 47.496], [16.202, 46.852], [16.012, 46.684], [15.137, 46.659], [14.632, 46.432], [13.806, 46.509], [12.376, 46.768], [12.153, 47.115], [11.165, 46.942], [11.049, 46.751], [10.443, 46.894], [9.932, 46.921], [9.48, 47.103], [9.633, 47.348], [9.594, 47.525], [9.896, 47.58], [10.402, 47.302], [10.545, 47.566], [11.426, 47.524], [12.141, 47.703], [12.621, 47.672], [12.933, 47.468], [13.026, 47.638], [12.884, 48.289], [13.243, 48.416], [13.596, 48.877], [14.339, 48.555], [14.901, 48.964], [15.253, 49.039], [16.03, 48.734], [16.499, 48.786], [16.96, 48.597], [16.88, 48.47], [16.98, 48.123]]]] }, { "N": "Hungary", "I": "HU", "C": [[[[22.086, 48.422], [22.641, 48.15], [22.711, 47.882], [22.1, 47.672], [21.627, 46.994], [21.022, 46.316], [20.22, 46.127], [19.596, 46.172], [18.83, 45.909], [18.83, 45.909], [18.456, 45.759], [17.63, 45.952], [16.883, 46.381], [16.565, 46.504], [16.371, 46.841], [16.202, 46.852], [16.534, 47.496], [16.341, 47.713], [16.904, 47.715], [16.98, 48.123], [17.488, 47.867], [17.857, 47.758], [18.697, 47.881], [18.777, 48.082], [19.174, 48.111], [19.661, 48.267], [19.769, 48.203], [20.239, 48.328], [20.474, 48.563], [20.801, 48.624], [21.872, 48.32], [22.086, 48.422]]]] }, { "N": "Moldova", "I": "MD", "C": [[[[26.619, 48.221], [26.858, 48.368], [27.523, 48.467], [28.26, 48.156], [28.671, 48.118], [29.123, 47.849], [29.051, 47.51], [29.415, 47.347], [29.56, 46.929], [29.909, 46.674], [29.838, 46.525], [30.025, 46.424], [29.76, 46.35], [29.171, 46.379], [29.072, 46.518], [28.863, 46.438], [28.934, 46.259], [28.66, 45.94], [28.485, 45.597], [28.234, 45.488], [28.054, 45.945], [28.16, 46.372], [28.128, 46.81], [27.551, 47.405], [27.234, 47.827], [26.924, 48.123], [26.619, 48.221]]]] }, { "N": "Romania", "I": "RO", "C": [[[[28.234, 45.488], [28.68, 45.304], [29.15, 45.465], [29.603, 45.293], [29.627, 45.035], [29.142, 44.82], [28.838, 44.914], [28.558, 43.707], [27.97, 43.812], [27.242, 44.176], [26.065, 43.943], [25.569, 43.688], [24.101, 43.741], [23.332, 43.897], [22.945, 43.824], [22.657, 44.235], [22.474, 44.409], [22.706, 44.578], [22.459, 44.703], [22.145, 44.478], [21.562, 44.769], [21.484, 45.181], [20.874, 45.416], [20.762, 45.735], [20.22, 46.127], [21.022, 46.316], [21.627, 46.994], [22.1, 47.672], [22.711, 47.882], [23.142, 48.096], [23.761, 47.986], [24.402, 47.982], [24.866, 47.738], [25.208, 47.891], [25.946, 47.987], [26.197, 48.221], [26.619, 48.221], [26.924, 48.123], [27.234, 47.827], [27.551, 47.405], [28.128, 46.81], [28.16, 46.372], [28.054, 45.945], [28.234, 45.488]]]] }, { "N": "Lithuania", "I": "LT", "C": [[[[26.494, 55.615], [26.588, 55.167], [25.768, 54.847], [25.536, 54.282], [24.451, 53.906], [23.484, 53.912], [23.244, 54.221], [22.731, 54.328], [22.651, 54.583], [22.758, 54.857], [22.316, 55.015], [21.268, 55.19], [21.056, 56.031], [22.201, 56.338], [23.878, 56.274], [24.861, 56.373], [25.001, 56.165], [25.533, 56.1], [26.494, 55.615]]]] }, { "N": "Latvia", "I": "LV", "C": [[[[27.288, 57.475], [27.77, 57.244], [27.855, 56.759], [28.177, 56.169], [27.102, 55.783], [26.494, 55.615], [25.533, 56.1], [25.001, 56.165], [24.861, 56.373], [23.878, 56.274], [22.201, 56.338], [21.056, 56.031], [21.09, 56.784], [21.582, 57.412], [22.524, 57.753], [23.318, 57.006], [24.121, 57.026], [24.313, 57.793], [25.165, 57.97], [25.603, 57.848], [26.464, 57.476], [27.288, 57.475]]]] }, { "N": "Estonia", "I": "EE", "C": [[[[27.981, 59.475], [27.981, 59.475], [28.132, 59.301], [27.42, 58.725], [27.717, 57.792], [27.288, 57.475], [26.464, 57.476], [25.603, 57.848], [25.165, 57.97], [24.313, 57.793], [24.429, 58.383], [24.061, 58.257], [23.427, 58.613], [23.34, 59.187], [24.604, 59.466], [25.864, 59.611], [26.949, 59.446], [27.981, 59.475], [27.981, 59.475]]]] }, { "N": "Germany", "I": "DE", "C": [[[[14.12, 53.757], [14.353, 53.248], [14.075, 52.981], [14.438, 52.625], [14.685, 52.09], [14.607, 51.745], [15.017, 51.107], [14.571, 51.002], [14.307, 51.117], [14.056, 50.927], [13.338, 50.733], [12.967, 50.484], [12.24, 50.266], [12.415, 49.969], [12.521, 49.547], [13.031, 49.307], [13.596, 48.877], [13.243, 48.416], [12.884, 48.289], [13.026, 47.638], [12.933, 47.468], [12.621, 47.672], [12.141, 47.703], [11.426, 47.524], [10.545, 47.566], [10.402, 47.302], [9.896, 47.58], [9.594, 47.525], [8.523, 47.831], [8.317, 47.614], [7.467, 47.621], [7.594, 48.333], [8.099, 49.018], [6.658, 49.202], [6.186, 49.464], [6.243, 49.902], [6.043, 50.128], [6.157, 50.804], [5.989, 51.852], [6.589, 51.852], [6.843, 52.228], [7.092, 53.144], [6.905, 53.482], [7.1, 53.694], [7.936, 53.748], [8.122, 53.528], [8.801, 54.021], [8.572, 54.396], [8.526, 54.963], [9.282, 54.831], [9.922, 54.983], [9.94, 54.597], [10.95, 54.364], [10.939, 54.009], [11.956, 54.196], [12.518, 54.47], [13.647, 54.076], [14.12, 53.757]]]] }, { "N": "Bulgaria", "I": "BG", "C": [[[[22.657, 44.235], [22.945, 43.824], [23.332, 43.897], [24.101, 43.741], [25.569, 43.688], [26.065, 43.943], [27.242, 44.176], [27.97, 43.812], [28.558, 43.707], [28.039, 43.293], [27.674, 42.578], [27.997, 42.007], [27.136, 42.141], [26.117, 41.827], [26.106, 41.329], [25.197, 41.234], [24.493, 41.584], [23.692, 41.309], [22.952, 41.338], [22.881, 41.999], [22.381, 42.32], [22.545, 42.461], [22.437, 42.58], [22.605, 42.899], [22.986, 43.211], [22.5, 43.643], [22.41, 44.008], [22.657, 44.235]]]] }, { "N": "Greece", "I": "GR", "C": [[[[26.29, 35.3], [26.165, 35.005], [24.725, 34.92], [24.735, 35.085], [23.515, 35.28], [23.7, 35.705], [24.247, 35.368], [25.025, 35.425], [25.769, 35.354], [25.745, 35.18], [26.29, 35.3]]], [[[22.952, 41.338], [23.692, 41.309], [24.493, 41.584], [25.197, 41.234], [26.106, 41.329], [26.117, 41.827], [26.604, 41.562], [26.295, 40.936], [26.057, 40.824], [25.448, 40.853], [24.926, 40.947], [23.715, 40.687], [24.408, 40.125], [23.9, 39.962], [23.343, 39.961], [22.814, 40.476], [22.626, 40.257], [22.85, 39.659], [23.35, 39.19], [22.973, 38.971], [23.53, 38.51], [24.025, 38.22], [24.04, 37.655], [23.115, 37.92], [23.41, 37.41], [22.775, 37.305], [23.154, 36.423], [22.49, 36.41], [21.67, 36.845], [21.295, 37.645], [21.12, 38.31], [20.73, 38.77], [20.218, 39.34], [20.15, 39.625], [20.615, 40.11], [20.675, 40.435], [21, 40.58], [21.02, 40.843], [21.674, 40.931], [22.055, 41.15], [22.597, 41.13], [22.762, 41.305], [22.952, 41.338]]]] }, { "N": "Turkey", "I": "TR", "C": [[[[44.773, 37.17], [44.293, 37.002], [43.942, 37.256], [42.779, 37.385], [42.35, 37.23], [41.212, 37.074], [40.673, 37.091], [39.523, 36.716], [38.7, 36.713], [38.168, 36.901], [37.067, 36.623], [36.739, 36.818], [36.685, 36.26], [36.418, 36.041], [36.15, 35.822], [35.782, 36.275], [36.161, 36.651], [35.551, 36.565], [34.715, 36.796], [34.027, 36.22], [32.509, 36.108], [31.7, 36.644], [30.622, 36.678], [30.391, 36.263], [29.7, 36.144], [28.733, 36.677], [27.641, 36.659], [27.049, 37.653], [26.318, 38.208], [26.805, 38.986], [26.171, 39.464], [27.28, 40.42], [28.82, 40.46], [29.24, 41.22], [31.146, 41.088], [32.348, 41.736], [33.513, 42.019], [35.168, 42.04], [36.913, 41.335], [38.348, 40.949], [39.513, 41.103], [40.373, 41.014], [41.554, 41.536], [42.62, 41.583], [43.583, 41.092], [43.753, 40.74], [43.656, 40.254], [44.4, 40.005], [44.794, 39.713], [44.109, 39.428], [44.421, 38.281], [44.226, 37.972], [44.773, 37.17], [44.773, 37.17]]], [[[26.117, 41.827], [27.136, 42.141], [27.997, 42.007], [28.116, 41.623], [28.988, 41.3], [28.806, 41.055], [27.619, 41], [27.192, 40.691], [26.358, 40.152], [26.043, 40.618], [26.057, 40.824], [26.295, 40.936], [26.604, 41.562], [26.117, 41.827]]]] }, { "N": "Albania", "I": "AL", "C": [[[[21.02, 40.843], [21, 40.58], [20.675, 40.435], [20.615, 40.11], [20.15, 39.625], [19.98, 39.695], [19.96, 39.915], [19.406, 40.251], [19.319, 40.727], [19.404, 41.41], [19.54, 41.72], [19.372, 41.878], [19.372, 41.878], [19.304, 42.196], [19.738, 42.688], [19.802, 42.5], [20.071, 42.589], [20.284, 42.32], [20.523, 42.218], [20.59, 41.855], [20.59, 41.855], [20.463, 41.515], [20.605, 41.086], [21.02, 40.843]]]] }, { "N": "Croatia", "I": "HR", "C": [[[[16.565, 46.504], [16.883, 46.381], [17.63, 45.952], [18.456, 45.759], [18.83, 45.909], [19.073, 45.522], [19.39, 45.237], [19.005, 44.86], [18.553, 45.082], [17.862, 45.068], [17.002, 45.234], [16.535, 45.212], [16.318, 45.004], [15.959, 45.234], [15.75, 44.819], [16.24, 44.351], [16.456, 44.041], [16.916, 43.668], [17.297, 43.446], [17.675, 43.029], [18.56, 42.65], [18.45, 42.48], [18.45, 42.48], [17.51, 42.85], [16.93, 43.21], [16.015, 43.507], [15.174, 44.243], [15.376, 44.318], [14.92, 44.738], [14.902, 45.076], [14.259, 45.234], [13.952, 44.802], [13.657, 45.137], [13.679, 45.484], [13.715, 45.5], [14.412, 45.466], [14.595, 45.635], [14.935, 45.472], [15.328, 45.452], [15.324, 45.732], [15.672, 45.834], [15.769, 46.238], [16.565, 46.504]]]] }, { "N": "Switzerland", "I": "CH", "C": [[[[9.594, 47.525], [9.633, 47.348], [9.48, 47.103], [9.932, 46.921], [10.443, 46.894], [10.363, 46.484], [9.923, 46.315], [9.183, 46.44], [8.966, 46.037], [8.49, 46.005], [8.317, 46.164], [7.756, 45.824], [7.274, 45.777], [6.844, 45.991], [6.5, 46.43], [6.023, 46.273], [6.037, 46.726], [6.769, 47.288], [6.737, 47.542], [7.192, 47.45], [7.467, 47.621], [8.317, 47.614], [8.523, 47.831], [9.594, 47.525]]]] }, { "N": "Luxembourg", "I": "LU", "C": [[[[6.043, 50.128], [6.243, 49.902], [6.186, 49.464], [5.898, 49.443], [5.674, 49.529], [5.782, 50.09], [6.043, 50.128]]]] }, { "N": "Belgium", "I": "BE", "C": [[[[6.157, 50.804], [6.043, 50.128], [5.782, 50.09], [5.674, 49.529], [4.799, 49.985], [4.286, 49.907], [3.588, 50.379], [3.123, 50.78], [2.658, 50.797], [2.514, 51.149], [3.315, 51.346], [3.315, 51.346], [3.315, 51.346], [4.047, 51.267], [4.974, 51.475], [5.607, 51.037], [6.157, 50.804]]]] }, { "N": "Netherlands", "I": "NL", "C": [[[[6.905, 53.482], [7.092, 53.144], [6.843, 52.228], [6.589, 51.852], [5.989, 51.852], [6.157, 50.804], [5.607, 51.037], [4.974, 51.475], [4.047, 51.267], [3.315, 51.346], [3.315, 51.346], [3.83, 51.621], [4.706, 53.092], [6.074, 53.51], [6.905, 53.482]]]] }, { "N": "Portugal", "I": "PT", "C": [[[[-9.035, 41.881], [-8.672, 42.135], [-8.264, 42.28], [-8.013, 41.791], [-7.423, 41.792], [-7.251, 41.918], [-6.669, 41.883], [-6.389, 41.382], [-6.851, 41.111], [-6.864, 40.331], [-7.026, 40.185], [-7.067, 39.712], [-7.499, 39.63], [-7.098, 39.03], [-7.374, 38.373], [-7.029, 38.076], [-7.167, 37.804], [-7.537, 37.429], [-7.454, 37.098], [-7.856, 36.838], [-8.383, 36.979], [-8.899, 36.869], [-8.746, 37.651], [-8.84, 38.266], [-9.287, 38.358], [-9.527, 38.737], [-9.447, 39.392], [-9.048, 39.755], [-8.977, 40.159], [-8.769, 40.761], [-8.791, 41.184], [-8.991, 41.543], [-9.035, 41.881]]]] }, { "N": "Spain", "I": "ES", "C": [[[[-7.454, 37.098], [-7.537, 37.429], [-7.167, 37.804], [-7.029, 38.076], [-7.374, 38.373], [-7.098, 39.03], [-7.499, 39.63], [-7.067, 39.712], [-7.026, 40.185], [-6.864, 40.331], [-6.851, 41.111], [-6.389, 41.382], [-6.669, 41.883], [-7.251, 41.918], [-7.423, 41.792], [-8.013, 41.791], [-8.264, 42.28], [-8.672, 42.135], [-9.035, 41.881], [-8.984, 42.593], [-9.393, 43.027], [-7.978, 43.748], [-6.754, 43.568], [-5.412, 43.574], [-4.348, 43.403], [-3.518, 43.456], [-1.901, 43.423], [-1.503, 43.034], [0.338, 42.58], [0.702, 42.796], [1.827, 42.343], [2.986, 42.473], [3.039, 41.892], [2.092, 41.226], [0.811, 41.015], [0.721, 40.678], [0.107, 40.124], [-0.279, 39.31], [0.111, 38.739], [-0.467, 38.292], [-0.683, 37.642], [-1.438, 37.443], [-2.146, 36.674], [-3.416, 36.659], [-4.369, 36.678], [-4.995, 36.325], [-5.377, 35.947], [-5.866, 36.03], [-6.237, 36.368], [-6.52, 36.943], [-7.454, 37.098]]]] }, { "N": "Ireland", "I": "IE", "C": [[[[-6.198, 53.868], [-6.033, 53.153], [-6.789, 52.26], [-8.562, 51.669], [-9.977, 51.82], [-9.166, 52.865], [-9.689, 53.881], [-8.328, 54.665], [-7.572, 55.132], [-7.366, 54.596], [-7.572, 54.06], [-6.954, 54.074], [-6.198, 53.868]]]] }, { "N": "New Caledonia", "I": "NC", "C": [[[[165.78, -21.08], [166.6, -21.7], [167.12, -22.16], [166.74, -22.4], [166.19, -22.13], [165.474, -21.68], [164.83, -21.15], [164.168, -20.445], [164.03, -20.106], [164.46, -20.12], [165.02, -20.46], [165.46, -20.8], [165.78, -21.08]]]] }, { "N": "Solomon Islands", "I": "SB", "C": [[[[162.119, -10.483], [162.399, -10.826], [161.7, -10.82], [161.32, -10.205], [161.917, -10.447], [162.119, -10.483]]], [[[161.68, -9.6], [161.529, -9.784], [160.788, -8.918], [160.58, -8.32], [160.92, -8.32], [161.28, -9.12], [161.68, -9.6]]], [[[160.852, -9.873], [160.463, -9.895], [159.849, -9.794], [159.64, -9.64], [159.703, -9.243], [160.363, -9.4], [160.689, -9.61], [160.852, -9.873]]], [[[159.64, -8.02], [159.875, -8.337], [159.917, -8.538], [159.134, -8.114], [158.586, -7.755], [158.211, -7.422], [158.36, -7.32], [158.82, -7.56], [159.64, -8.02]]], [[[157.14, -7.022], [157.538, -7.348], [157.339, -7.405], [156.902, -7.177], [156.491, -6.766], [156.543, -6.599], [157.14, -7.022]]]] }, { "N": "New Zealand", "I": "NZ", "C": [[[[176.886, -40.066], [176.508, -40.605], [176.012, -41.29], [175.24, -41.688], [175.068, -41.426], [174.651, -41.282], [175.228, -40.459], [174.9, -39.909], [173.824, -39.509], [173.852, -39.147], [174.575, -38.798], [174.743, -38.028], [174.697, -37.381], [174.292, -36.711], [174.319, -36.535], [173.841, -36.122], [173.054, -35.237], [172.636, -34.529], [173.007, -34.451], [173.551, -35.006], [174.329, -35.265], [174.612, -36.156], [175.337, -37.209], [175.358, -36.526], [175.809, -36.799], [175.958, -37.555], [176.763, -37.881], [177.439, -37.961], [178.01, -37.58], [178.517, -37.695], [178.275, -38.583], [177.97, -39.166], [177.207, -39.146], [176.94, -39.45], [177.033, -39.88], [176.886, -40.066]]], [[[169.668, -43.555], [170.525, -43.032], [171.125, -42.513], [171.57, -41.767], [171.949, -41.514], [172.097, -40.956], [172.799, -40.494], [173.02, -40.919], [173.247, -41.332], [173.958, -40.927], [174.248, -41.349], [174.249, -41.77], [173.876, -42.233], [173.223, -42.97], [172.711, -43.372], [173.08, -43.853], [172.309, -43.866], [171.453, -44.243], [171.185, -44.897], [170.617, -45.909], [169.831, -46.356], [169.332, -46.641], [168.411, -46.62], [167.764, -46.29], [166.677, -46.22], [166.509, -45.853], [167.046, -45.111], [168.304, -44.124], [168.949, -43.936], [169.668, -43.555]]]] }, { "N": "Australia", "I": "AU", "C": [[[[147.689, -40.808], [148.289, -40.875], [148.36, -42.062], [148.017, -42.407], [147.914, -43.212], [147.565, -42.938], [146.87, -43.635], [146.663, -43.581], [146.048, -43.55], [145.432, -42.694], [145.295, -42.034], [144.718, -41.163], [144.744, -40.704], [145.398, -40.793], [146.364, -41.138], [146.909, -41.001], [147.689, -40.808]]], [[[126.149, -32.216], [125.089, -32.729], [124.222, -32.959], [124.029, -33.484], [123.66, -33.89], [122.811, -33.914], [122.183, -34.003], [121.299, -33.821], [120.58, -33.93], [119.894, -33.976], [119.299, -34.509], [119.007, -34.464], [118.506, -34.747], [118.025, -35.065], [117.296, -35.025], [116.625, -35.025], [115.564, -34.386], [115.027, -34.197], [115.049, -33.623], [115.545, -33.487], [115.715, -33.26], [115.679, -32.9], [115.802, -32.205], [115.69, -31.612], [115.161, -30.602], [114.997, -30.031], [115.04, -29.461], [114.642, -28.81], [114.616, -28.516], [114.174, -28.118], [114.049, -27.335], [113.477, -26.543], [113.339, -26.117], [113.778, -26.549], [113.441, -25.621], [113.937, -25.911], [114.233, -26.298], [114.216, -25.786], [113.721, -24.999], [113.625, -24.684], [113.394, -24.385], [113.502, -23.806], [113.707, -23.56], [113.843, -23.06], [113.737, -22.475], [114.15, -21.756], [114.225, -22.517], [114.648, -21.83], [115.46, -21.495], [115.947, -21.069], [116.712, -20.702], [117.166, -20.624], [117.442, -20.747], [118.23, -20.374], [118.836, -20.263], [118.988, -20.044], [119.252, -19.953], [119.805, -19.977], [120.856, -19.684], [121.4, -19.24], [121.655, -18.705], [122.242, -18.198], [122.287, -17.799], [122.313, -17.255], [123.013, -16.405], [123.434, -17.269], [123.859, -17.069], [123.503, -16.597], [123.817, -16.111], [124.258, -16.328], [124.38, -15.567], [124.926, -15.075], [125.167, -14.68], [125.67, -14.51], [125.686, -14.231], [126.125, -14.347], [126.143, -14.096], [126.583, -13.953], [127.066, -13.818], [127.805, -14.277], [128.36, -14.869], [128.986, -14.876], [129.621, -14.97], [129.41, -14.421], [129.889, -13.619], [130.339, -13.357], [130.184, -13.108], [130.618, -12.536], [131.223, -12.184], [131.735, -12.302], [132.575, -12.114], [132.557, -11.603], [131.825, -11.274], [132.357, -11.129], [133.02, -11.376], [133.551, -11.787], [134.393, -12.042], [134.679, -11.941], [135.298, -12.249], [135.883, -11.962], [136.258, -12.049], [136.492, -11.857], [136.952, -12.352], [136.685, -12.887], [136.305, -13.291], [135.962, -13.325], [136.078, -13.724], [135.784, -14.224], [135.429, -14.715], [135.5, -14.998], [136.295, -15.55], [137.065, -15.871], [137.58, -16.215], [138.303, -16.808], [138.585, -16.807], [139.109, -17.063], [139.261, -17.372], [140.215, -17.711], [140.875, -17.369], [141.071, -16.832], [141.274, -16.389], [141.398, -15.841], [141.702, -15.045], [141.563, -14.561], [141.636, -14.27], [141.52, -13.698], [141.651, -12.945], [141.843, -12.742], [141.687, -12.408], [141.929, -11.877], [142.118, -11.328], [142.144, -11.043], [142.515, -10.668], [142.797, -11.157], [142.867, -11.785], [143.116, -11.906], [143.159, -12.326], [143.522, -12.834], [143.597, -13.4], [143.562, -13.764], [143.922, -14.548], [144.564, -14.171], [144.895, -14.594], [145.375, -14.985], [145.272, -15.428], [145.485, -16.286], [145.637, -16.785], [145.889, -16.907], [146.16, -17.762], [146.064, -18.28], [146.387, -18.958], [147.471, -19.481], [148.178, -19.956], [148.848, -20.391], [148.717, -20.633], [149.289, -21.261], [149.678, -22.343], [150.077, -22.123], [150.483, -22.556], [150.727, -22.402], [150.9, -23.462], [151.609, -24.076], [152.074, -24.458], [152.855, -25.268], [153.136, -26.071], [153.162, -26.641], [153.093, -27.26], [153.569, -28.11], [153.512, -28.995], [153.339, -29.458], [153.069, -30.35], [153.09, -30.924], [152.892, -31.64], [152.45, -32.55], [151.709, -33.041], [151.344, -33.816], [151.011, -34.31], [150.714, -35.173], [150.328, -35.672], [150.075, -36.42], [149.946, -37.109], [149.997, -37.425], [149.424, -37.773], [148.305, -37.809], [147.382, -38.219], [146.922, -38.607], [146.318, -39.036], [145.49, -38.594], [144.877, -38.417], [145.032, -37.896], [144.486, -38.085], [143.61, -38.809], [142.745, -38.538], [142.178, -38.38], [141.607, -38.309], [140.639, -38.019], [139.992, -37.403], [139.807, -36.644], [139.574, -36.138], [139.083, -35.733], [138.121, -35.612], [138.449, -35.127], [138.208, -34.385], [137.719, -35.077], [136.829, -35.261], [137.352, -34.707], [137.504, -34.13], [137.89, -33.64], [137.81, -32.9], [136.997, -33.753], [136.372, -34.095], [135.989, -34.89], [135.208, -34.479], [135.239, -33.948], [134.613, -33.223], [134.086, -32.848], [134.274, -32.617], [132.991, -32.011], [132.288, -31.983], [131.326, -31.496], [129.536, -31.59], [128.241, -31.948], [127.103, -32.282], [126.149, -32.216]]]] }, { "N": "Sri Lanka", "I": "LK", "C": [[[[81.788, 7.523], [81.637, 6.482], [81.218, 6.197], [80.348, 5.968], [79.872, 6.763], [79.695, 8.201], [80.148, 9.824], [80.839, 9.268], [81.304, 8.564], [81.788, 7.523]]]] }, { "N": "China", "I": "CN", "C": [[[[109.475, 18.198], [108.655, 18.508], [108.626, 19.368], [109.119, 19.821], [110.212, 20.101], [110.787, 20.078], [111.01, 19.696], [110.571, 19.256], [110.339, 18.678], [109.475, 18.198]]], [[[80.26, 42.35], [80.18, 42.92], [80.866, 43.18], [79.966, 44.918], [81.947, 45.317], [82.459, 45.54], [83.18, 47.33], [85.164, 47.001], [85.72, 47.453], [85.768, 48.456], [86.599, 48.549], [87.36, 49.215], [87.751, 49.297], [88.014, 48.599], [88.854, 48.069], [90.281, 47.694], [90.971, 46.888], [90.586, 45.72], [90.946, 45.286], [92.134, 45.115], [93.481, 44.975], [94.689, 44.352], [95.307, 44.241], [95.762, 43.319], [96.349, 42.726], [97.452, 42.749], [99.516, 42.525], [100.846, 42.664], [101.833, 42.515], [103.312, 41.907], [104.522, 41.908], [104.965, 41.597], [106.129, 42.134], [107.745, 42.482], [109.244, 42.519], [110.412, 42.871], [111.13, 43.407], [111.83, 43.743], [111.668, 44.073], [111.348, 44.457], [111.873, 45.102], [112.436, 45.012], [113.464, 44.809], [114.46, 45.34], [115.985, 45.727], [116.718, 46.388], [117.422, 46.673], [118.874, 46.805], [119.663, 46.693], [119.773, 47.048], [118.867, 47.747], [118.064, 48.067], [117.296, 47.698], [116.309, 47.853], [115.743, 47.727], [115.485, 48.135], [116.192, 49.135], [116.679, 49.889], [117.879, 49.511], [119.288, 50.143], [119.279, 50.583], [120.182, 51.644], [120.738, 51.964], [120.726, 52.516], [120.177, 52.754], [121.003, 53.251], [122.246, 53.432], [123.571, 53.459], [125.068, 53.161], [125.946, 52.793], [126.564, 51.784], [126.939, 51.354], [127.287, 50.74], [127.657, 49.76], [129.398, 49.441], [130.582, 48.73], [130.987, 47.79], [132.507, 47.789], [133.374, 48.183], [135.026, 48.478], [134.501, 47.578], [134.112, 47.212], [133.77, 46.117], [133.097, 45.144], [131.883, 45.321], [131.025, 44.968], [131.289, 44.112], [131.145, 42.93], [130.634, 42.903], [130.64, 42.395], [129.994, 42.985], [129.597, 42.425], [128.052, 41.994], [128.208, 41.467], [127.344, 41.503], [126.869, 41.817], [126.182, 41.107], [125.08, 40.57], [124.266, 39.928], [122.868, 39.638], [122.131, 39.17], [121.055, 38.897], [121.586, 39.361], [121.377, 39.75], [122.169, 40.422], [121.64, 40.946], [120.769, 40.593], [119.64, 39.898], [119.023, 39.252], [118.043, 39.204], [117.533, 38.738], [118.06, 38.061], [118.878, 37.897], [118.912, 37.448], [119.703, 37.156], [120.823, 37.87], [121.711, 37.481], [122.358, 37.454], [122.52, 36.931], [121.104, 36.651], [120.637, 36.111], [119.665, 35.61], [119.151, 34.91], [120.228, 34.36], [120.62, 33.377], [121.229, 32.46], [121.908, 31.692], [121.892, 30.949], [121.264, 30.676], [121.504, 30.143], [122.092, 29.833], [121.938, 29.018], [121.684, 28.226], [121.126, 28.136], [120.395, 27.053], [119.585, 25.741], [118.657, 24.547], [117.282, 23.625], [115.891, 22.783], [114.764, 22.668], [114.153, 22.224], [113.807, 22.548], [113.241, 22.051], [111.844, 21.55], [110.785, 21.397], [110.444, 20.341], [109.89, 20.282], [109.628, 21.008], [109.864, 21.395], [108.523, 21.715], [108.05, 21.552], [107.043, 21.812], [106.567, 22.218], [106.725, 22.794], [105.811, 22.977], [105.329, 23.352], [104.477, 22.819], [103.505, 22.704], [102.707, 22.709], [102.17, 22.465], [101.652, 22.318], [101.803, 21.174], [101.27, 21.202], [101.18, 21.437], [101.15, 21.85], [100.417, 21.559], [99.983, 21.743], [99.241, 22.118], [99.532, 22.949], [98.899, 23.143], [98.66, 24.063], [97.605, 23.897], [97.725, 25.084], [98.672, 25.919], [98.712, 26.744], [98.683, 27.509], [98.246, 27.747], [97.912, 28.336], [97.327, 28.262], [96.249, 28.411], [96.587, 28.831], [96.118, 29.453], [95.405, 29.032], [94.566, 29.277], [93.413, 28.641], [92.503, 27.897], [91.697, 27.772], [91.259, 28.041], [90.731, 28.065], [90.016, 28.296], [89.476, 28.043], [88.814, 27.299], [88.73, 28.087], [88.12, 27.877], [86.955, 27.974], [85.823, 28.204], [85.012, 28.643], [84.235, 28.84], [83.899, 29.32], [83.337, 29.464], [82.328, 30.115], [81.526, 30.423], [81.111, 30.183], [79.721, 30.883], [78.739, 31.516], [78.458, 32.618], [79.176, 32.484], [79.209, 32.994], [78.811, 33.506], [78.912, 34.322], [77.837, 35.494], [76.193, 35.898], [75.897, 36.667], [75.158, 37.133], [74.98, 37.42], [74.83, 37.99], [74.865, 38.379], [74.258, 38.607], [73.929, 38.506], [73.675, 39.431], [73.96, 39.66], [73.822, 39.894], [74.777, 40.366], [75.468, 40.562], [76.526, 40.428], [76.904, 41.066], [78.187, 41.185], [78.544, 41.582], [80.119, 42.124], [80.26, 42.35]]]] }, { "N": "Taiwan", "I": "TW", "C": [[[[121.778, 24.394], [121.176, 22.791], [120.747, 21.971], [120.22, 22.815], [120.106, 23.556], [120.695, 24.538], [121.495, 25.295], [121.951, 24.998], [121.778, 24.394]]]] }, { "N": "Italy", "I": "IT", "C": [[[[10.443, 46.894], [11.049, 46.751], [11.165, 46.942], [12.153, 47.115], [12.376, 46.768], [13.806, 46.509], [13.698, 46.017], [13.938, 45.591], [13.142, 45.737], [12.329, 45.382], [12.384, 44.885], [12.261, 44.6], [12.589, 44.091], [13.527, 43.588], [14.03, 42.761], [15.143, 41.955], [15.926, 41.961], [16.17, 41.74], [15.889, 41.541], [16.785, 41.18], [17.519, 40.877], [18.377, 40.356], [18.48, 40.169], [18.293, 39.811], [17.738, 40.278], [16.87, 40.442], [16.449, 39.795], [17.171, 39.425], [17.053, 38.903], [16.635, 38.844], [16.101, 37.986], [15.684, 37.909], [15.688, 38.215], [15.892, 38.751], [16.109, 38.965], [15.719, 39.544], [15.414, 40.048], [14.998, 40.173], [14.703, 40.605], [14.061, 40.786], [13.628, 41.188], [12.888, 41.253], [12.107, 41.705], [11.192, 42.355], [10.512, 42.931], [10.2, 43.92], [9.702, 44.036], [8.889, 44.366], [8.429, 44.231], [7.851, 43.767], [7.435, 43.694], [7.55, 44.128], [7.008, 44.255], [6.75, 45.029], [7.097, 45.333], [6.802, 45.709], [6.844, 45.991], [7.274, 45.777], [7.756, 45.824], [8.317, 46.164], [8.49, 46.005], [8.966, 46.037], [9.183, 46.44], [9.923, 46.315], [10.363, 46.484], [10.443, 46.894]]], [[[14.761, 38.144], [15.52, 38.231], [15.16, 37.444], [15.31, 37.134], [15.1, 36.62], [14.335, 36.997], [13.827, 37.105], [12.431, 37.613], [12.571, 38.126], [13.741, 38.035], [14.761, 38.144]]], [[[8.71, 40.9], [9.21, 41.21], [9.81, 40.5], [9.67, 39.177], [9.215, 39.24], [8.807, 38.907], [8.428, 39.172], [8.388, 40.378], [8.16, 40.95], [8.71, 40.9]]]] }, { "N": "Denmark", "I": "DK", "C": [[[[9.922, 54.983], [9.282, 54.831], [8.526, 54.963], [8.12, 55.518], [8.09, 56.54], [8.257, 56.81], [8.543, 57.11], [9.424, 57.172], [9.776, 57.448], [10.58, 57.73], [10.546, 57.216], [10.25, 56.89], [10.37, 56.61], [10.912, 56.459], [10.668, 56.081], [10.37, 56.19], [9.65, 55.47], [9.922, 54.983]]], [[[12.371, 56.111], [12.69, 55.61], [12.09, 54.8], [11.044, 55.365], [10.904, 55.78], [12.371, 56.111]]]] }, { "N": "United Kingdom", "I": "GB", "C": [[[[-6.198, 53.868], [-6.954, 54.074], [-7.572, 54.06], [-7.366, 54.596], [-7.572, 55.132], [-6.734, 55.173], [-5.662, 54.555], [-6.198, 53.868]]], [[[-3.094, 53.405], [-3.092, 53.404], [-2.945, 53.985], [-3.615, 54.601], [-3.63, 54.615], [-4.844, 54.791], [-5.083, 55.062], [-4.719, 55.508], [-5.048, 55.784], [-5.586, 55.311], [-5.645, 56.275], [-6.15, 56.785], [-5.787, 57.819], [-5.01, 58.63], [-4.211, 58.551], [-3.005, 58.635], [-4.074, 57.553], [-3.055, 57.69], [-1.959, 57.685], [-2.22, 56.87], [-3.119, 55.974], [-2.085, 55.91], [-2.006, 55.805], [-1.115, 54.625], [-0.43, 54.464], [0.185, 53.325], [0.47, 52.93], [1.682, 52.74], [1.56, 52.1], [1.051, 51.807], [1.45, 51.289], [0.55, 50.766], [-0.788, 50.775], [-2.49, 50.5], [-2.956, 50.697], [-3.617, 50.228], [-4.543, 50.342], [-5.245, 49.96], [-5.777, 50.16], [-4.31, 51.21], [-3.415, 51.426], [-3.423, 51.427], [-4.984, 51.593], [-5.267, 51.991], [-4.222, 52.301], [-4.77, 52.84], [-4.58, 53.495], [-3.094, 53.405]]]] }, { "N": "Iceland", "I": "IS", "C": [[[[-14.509, 66.456], [-14.74, 65.809], [-13.61, 65.127], [-14.91, 64.364], [-17.794, 63.679], [-18.656, 63.496], [-19.973, 63.644], [-22.763, 63.96], [-21.778, 64.402], [-23.955, 64.891], [-22.184, 65.085], [-22.227, 65.379], [-24.326, 65.611], [-23.651, 66.263], [-22.135, 66.41], [-20.576, 65.732], [-19.057, 66.277], [-17.799, 65.994], [-16.168, 66.527], [-14.509, 66.456]]]] }, { "N": "Azerbaijan", "I": "AZ", "C": [[[[46.405, 41.861], [46.686, 41.827], [47.373, 41.22], [47.816, 41.151], [47.987, 41.406], [48.584, 41.809], [49.11, 41.282], [49.619, 40.573], [50.085, 40.526], [50.393, 40.257], [49.569, 40.176], [49.395, 39.399], [49.223, 39.049], [48.857, 38.815], [48.883, 38.32], [48.634, 38.27], [48.011, 38.794], [48.356, 39.289], [48.06, 39.582], [47.685, 39.508], [46.506, 38.771], [46.483, 39.464], [46.035, 39.628], [45.61, 39.9], [45.892, 40.218], [45.359, 40.562], [45.56, 40.812], [45.179, 40.985], [44.972, 41.248], [45.217, 41.411], [45.963, 41.124], [46.502, 41.064], [46.638, 41.182], [46.145, 41.723], [46.405, 41.861]]], [[[46.144, 38.741], [45.458, 38.874], [44.953, 39.336], [44.794, 39.713], [45.002, 39.74], [45.298, 39.472], [45.74, 39.474], [45.735, 39.32], [46.144, 38.741]]]] }, { "N": "Georgia", "I": "GE", "C": [[[[39.955, 43.435], [40.077, 43.553], [40.922, 43.382], [42.394, 43.22], [43.756, 42.741], [43.931, 42.555], [44.538, 42.712], [45.47, 42.503], [45.776, 42.092], [46.405, 41.861], [46.145, 41.723], [46.638, 41.182], [46.502, 41.064], [45.963, 41.124], [45.217, 41.411], [44.972, 41.248], [43.583, 41.092], [42.62, 41.583], [41.554, 41.536], [41.703, 41.963], [41.453, 42.645], [40.875, 43.014], [40.321, 43.129], [39.955, 43.435]]]] }, { "N": "Philippines", "I": "PH", "C": [[[[120.834, 12.704], [120.323, 13.466], [121.18, 13.43], [121.527, 13.07], [121.262, 12.206], [120.834, 12.704]]], [[[122.586, 9.981], [122.837, 10.261], [122.947, 10.882], [123.499, 10.941], [123.338, 10.267], [124.078, 11.233], [123.982, 10.279], [123.623, 9.95], [123.31, 9.318], [122.996, 9.022], [122.38, 9.713], [122.586, 9.981]]], [[[126.377, 8.415], [126.479, 7.75], [126.537, 7.189], [126.197, 6.274], [125.831, 7.294], [125.364, 6.786], [125.683, 6.05], [125.397, 5.581], [124.22, 6.161], [123.939, 6.885], [124.244, 7.361], [123.61, 7.834], [123.296, 7.419], [122.826, 7.457], [122.085, 6.899], [121.92, 7.192], [122.312, 8.035], [122.942, 8.316], [123.488, 8.693], [123.841, 8.24], [124.601, 8.514], [124.765, 8.96], [125.471, 8.987], [125.412, 9.76], [126.223, 9.286], [126.307, 8.782], [126.377, 8.415]]], [[[118.505, 9.316], [117.174, 8.367], [117.664, 9.067], [118.387, 9.684], [118.987, 10.376], [119.511, 11.37], [119.69, 10.554], [119.029, 10.004], [118.505, 9.316]]], [[[122.337, 18.225], [122.174, 17.81], [122.516, 17.094], [122.252, 16.262], [121.663, 15.931], [121.505, 15.125], [121.729, 14.328], [122.259, 14.218], [122.701, 14.337], [123.95, 13.782], [123.855, 13.238], [124.181, 12.998], [124.077, 12.537], [123.298, 13.028], [122.929, 13.553], [122.671, 13.186], [122.035, 13.784], [121.126, 13.637], [120.629, 13.858], [120.679, 14.271], [120.992, 14.525], [120.693, 14.757], [120.564, 14.396], [120.07, 14.971], [119.921, 15.406], [119.884, 16.364], [120.286, 16.035], [120.39, 17.599], [120.716, 18.505], [121.321, 18.504], [121.938, 18.219], [122.246, 18.479], [122.337, 18.225]]], [[[122.038, 11.416], [121.884, 11.892], [122.484, 11.582], [123.12, 11.584], [123.101, 11.166], [122.638, 10.741], [122.003, 10.441], [121.967, 10.906], [122.038, 11.416]]], [[[125.503, 12.163], [125.783, 11.046], [125.012, 11.311], [125.033, 10.976], [125.277, 10.359], [124.802, 10.135], [124.76, 10.838], [124.459, 10.89], [124.303, 11.495], [124.891, 11.416], [124.878, 11.794], [124.267, 12.558], [125.227, 12.536], [125.503, 12.163]]]] }, { "N": "Malaysia", "I": "MY", "C": [[[[100.086, 6.464], [100.26, 6.643], [101.076, 6.205], [101.154, 5.691], [101.814, 5.811], [102.141, 6.222], [102.371, 6.128], [102.962, 5.524], [103.381, 4.855], [103.439, 4.182], [103.332, 3.727], [103.429, 3.383], [103.502, 2.791], [103.855, 2.515], [104.248, 1.631], [104.229, 1.293], [103.52, 1.226], [102.574, 1.967], [101.391, 2.761], [101.274, 3.27], [100.695, 3.939], [100.557, 4.767], [100.197, 5.312], [100.306, 6.041], [100.086, 6.464]]], [[[117.882, 4.138], [117.015, 4.306], [115.866, 4.307], [115.519, 3.169], [115.134, 2.821], [114.621, 1.431], [113.806, 1.218], [112.86, 1.498], [112.38, 1.41], [111.798, 0.904], [111.159, 0.976], [110.514, 0.773], [109.83, 1.338], [109.663, 2.006], [110.396, 1.664], [111.169, 1.851], [111.37, 2.697], [111.797, 2.886], [112.996, 3.102], [113.713, 3.894], [114.204, 4.526], [114.66, 4.008], [114.87, 4.348], [115.347, 4.317], [115.406, 4.955], [115.451, 5.448], [116.221, 6.143], [116.725, 6.925], [117.13, 6.928], [117.643, 6.422], [117.689, 5.987], [118.348, 5.709], [119.182, 5.408], [119.111, 5.016], [118.44, 4.967], [118.618, 4.478], [117.882, 4.138]]]] }, { "N": "Brunei Darussalam", "I": "BN", "C": [[[[115.451, 5.448], [115.406, 4.955], [115.347, 4.317], [114.87, 4.348], [114.66, 4.008], [114.204, 4.526], [114.6, 4.9], [115.451, 5.448]]]] }, { "N": "Slovenia", "I": "SI", "C": [[[[13.806, 46.509], [14.632, 46.432], [15.137, 46.659], [16.012, 46.684], [16.202, 46.852], [16.371, 46.841], [16.565, 46.504], [15.769, 46.238], [15.672, 45.834], [15.324, 45.732], [15.328, 45.452], [14.935, 45.472], [14.595, 45.635], [14.412, 45.466], [13.715, 45.5], [13.938, 45.591], [13.698, 46.017], [13.806, 46.509]]]] }, { "N": "Finland", "I": "FI", "C": [[[[28.592, 69.065], [28.446, 68.365], [29.977, 67.698], [29.055, 66.944], [30.218, 65.806], [29.544, 64.949], [30.445, 64.204], [30.036, 63.553], [31.516, 62.868], [31.14, 62.358], [30.211, 61.78], [28.07, 60.504], [28.07, 60.504], [28.07, 60.504], [26.255, 60.424], [24.497, 60.057], [22.87, 59.846], [22.291, 60.392], [21.322, 60.72], [21.545, 61.705], [21.059, 62.607], [21.536, 63.19], [22.443, 63.818], [24.731, 64.902], [25.398, 65.111], [25.294, 65.534], [23.903, 66.007], [23.566, 66.396], [23.539, 67.936], [21.979, 68.617], [20.646, 69.106], [21.245, 69.37], [22.356, 68.842], [23.662, 68.891], [24.736, 68.65], [25.689, 69.092], [26.18, 69.825], [27.732, 70.164], [29.016, 69.766], [28.592, 69.065]]]] }, { "N": "Slovakia", "I": "SK", "C": [[[[22.558, 49.086], [22.281, 48.825], [22.086, 48.422], [21.872, 48.32], [20.801, 48.624], [20.474, 48.563], [20.239, 48.328], [19.769, 48.203], [19.661, 48.267], [19.174, 48.111], [18.777, 48.082], [18.697, 47.881], [17.857, 47.758], [17.488, 47.867], [16.98, 48.123], [16.88, 48.47], [16.96, 48.597], [17.102, 48.817], [17.545, 48.8], [17.886, 48.903], [17.914, 48.996], [18.105, 49.044], [18.17, 49.272], [18.4, 49.315], [18.555, 49.495], [18.853, 49.496], [18.91, 49.436], [19.321, 49.572], [19.825, 49.217], [20.416, 49.431], [20.888, 49.329], [21.608, 49.47], [22.558, 49.086]]]] }, { "N": "Czech Republic", "I": "CZ", "C": [[[[15.017, 51.107], [15.491, 50.785], [16.239, 50.698], [16.176, 50.423], [16.719, 50.216], [16.869, 50.474], [17.555, 50.362], [17.649, 50.049], [18.393, 49.989], [18.853, 49.496], [18.555, 49.495], [18.4, 49.315], [18.17, 49.272], [18.105, 49.044], [17.914, 48.996], [17.886, 48.903], [17.545, 48.8], [17.102, 48.817], [16.96, 48.597], [16.499, 48.786], [16.03, 48.734], [15.253, 49.039], [14.901, 48.964], [14.339, 48.555], [13.596, 48.877], [13.031, 49.307], [12.521, 49.547], [12.415, 49.969], [12.24, 50.266], [12.967, 50.484], [13.338, 50.733], [14.056, 50.927], [14.307, 51.117], [14.571, 51.002], [15.017, 51.107]]]] }, { "N": "Eritrea", "I": "ER", "C": [[[[36.43, 14.422], [36.323, 14.822], [36.754, 16.292], [36.853, 16.957], [37.167, 17.263], [37.904, 17.428], [38.41, 17.998], [38.991, 16.841], [39.266, 15.923], [39.814, 15.436], [41.179, 14.491], [41.735, 13.921], [42.277, 13.344], [42.59, 13], [43.081, 12.7], [42.78, 12.455], [42.352, 12.542], [42.01, 12.866], [41.599, 13.452], [41.155, 13.773], [40.897, 14.119], [40.026, 14.52], [39.341, 14.532], [39.099, 14.741], [38.513, 14.505], [37.906, 14.959], [37.594, 14.213], [36.43, 14.422]]]] }, { "N": "Japan", "I": "JP", "C": [[[[141.885, 39.181], [140.959, 38.174], [140.976, 37.142], [140.6, 36.344], [140.774, 35.843], [140.253, 35.138], [138.976, 34.668], [137.218, 34.606], [135.793, 33.465], [135.121, 33.849], [135.079, 34.597], [133.34, 34.376], [132.157, 33.905], [130.986, 33.886], [132, 33.15], [131.333, 31.45], [130.686, 31.03], [130.202, 31.418], [130.448, 32.319], [129.815, 32.61], [129.408, 33.296], [130.354, 33.604], [130.878, 34.233], [131.884, 34.75], [132.618, 35.433], [134.608, 35.732], [135.678, 35.527], [136.724, 37.305], [137.391, 36.827], [138.858, 37.827], [139.426, 38.216], [140.055, 39.439], [139.883, 40.563], [140.306, 41.195], [141.369, 41.379], [141.914, 39.992], [141.885, 39.181]]], [[[144.613, 43.961], [145.321, 44.385], [145.543, 43.262], [144.06, 42.988], [143.184, 41.995], [141.611, 42.679], [141.067, 41.585], [139.955, 41.57], [139.818, 42.564], [140.312, 43.333], [141.381, 43.389], [141.672, 44.772], [141.968, 45.551], [143.143, 44.51], [143.91, 44.174], [144.613, 43.961]]], [[[132.371, 33.464], [132.924, 34.06], [133.493, 33.945], [133.904, 34.365], [134.638, 34.149], [134.766, 33.806], [134.203, 33.201], [133.793, 33.522], [133.28, 33.29], [133.015, 32.705], [132.363, 32.989], [132.371, 33.464]]]] }, { "N": "Paraguay", "I": "PY", "C": [[[[-58.166, -20.177], [-57.871, -20.733], [-57.937, -22.09], [-56.882, -22.282], [-56.473, -22.086], [-55.798, -22.357], [-55.611, -22.656], [-55.518, -23.572], [-55.401, -23.957], [-55.028, -24.001], [-54.653, -23.84], [-54.293, -24.021], [-54.293, -24.571], [-54.429, -25.162], [-54.625, -25.739], [-54.789, -26.622], [-55.696, -27.388], [-56.487, -27.548], [-57.61, -27.396], [-58.618, -27.124], [-57.634, -25.604], [-57.777, -25.162], [-58.807, -24.771], [-60.029, -24.033], [-60.847, -23.881], [-62.685, -22.249], [-62.291, -21.052], [-62.266, -20.514], [-61.786, -19.634], [-60.044, -19.343], [-59.115, -19.357], [-58.183, -19.868], [-58.166, -20.177]]]] }, { "N": "Yemen", "I": "YE", "C": [[[[52, 19], [52.782, 17.35], [53.109, 16.651], [52.385, 16.382], [52.192, 15.938], [52.168, 15.597], [51.173, 15.175], [49.575, 14.709], [48.679, 14.003], [48.239, 13.948], [47.939, 14.007], [47.354, 13.592], [46.717, 13.4], [45.878, 13.348], [45.625, 13.291], [45.406, 13.027], [45.144, 12.954], [44.99, 12.7], [44.495, 12.722], [44.175, 12.586], [43.483, 12.637], [43.223, 13.221], [43.251, 13.768], [43.088, 14.063], [42.892, 14.802], [42.605, 15.213], [42.805, 15.262], [42.702, 15.719], [42.824, 15.912], [42.779, 16.348], [43.218, 16.667], [43.116, 17.088], [43.381, 17.58], [43.792, 17.32], [44.063, 17.41], [45.217, 17.433], [45.4, 17.333], [46.367, 17.233], [46.75, 17.283], [47, 16.95], [47.467, 17.117], [48.183, 18.167], [49.117, 18.617], [52, 19]]]] }, { "N": "Saudi Arabia", "I": "SA", "C": [[[[34.956, 29.357], [36.069, 29.197], [36.501, 29.505], [36.741, 29.865], [37.504, 30.004], [37.668, 30.339], [37.999, 30.508], [37.002, 31.508], [39.005, 32.01], [39.195, 32.161], [40.4, 31.89], [41.89, 31.19], [44.709, 29.179], [46.569, 29.099], [47.46, 29.003], [47.709, 28.526], [48.416, 28.552], [48.808, 27.69], [49.3, 27.461], [49.471, 27.11], [50.152, 26.69], [50.213, 26.277], [50.113, 25.944], [50.24, 25.608], [50.527, 25.328], [50.661, 25], [50.81, 24.755], [51.112, 24.556], [51.39, 24.627], [51.58, 24.245], [51.618, 24.014], [52.001, 23.001], [55.007, 22.497], [55.208, 22.708], [55.667, 22], [55, 20], [52, 19], [49.117, 18.617], [48.183, 18.167], [47.467, 17.117], [47, 16.95], [46.75, 17.283], [46.367, 17.233], [45.4, 17.333], [45.217, 17.433], [44.063, 17.41], [43.792, 17.32], [43.381, 17.58], [43.116, 17.088], [43.218, 16.667], [42.779, 16.348], [42.65, 16.775], [42.348, 17.076], [42.271, 17.475], [41.754, 17.833], [41.221, 18.672], [40.939, 19.486], [40.248, 20.175], [39.802, 20.339], [39.139, 21.292], [39.024, 21.987], [39.066, 22.58], [38.493, 23.688], [38.024, 24.079], [37.484, 24.285], [37.155, 24.858], [37.209, 25.085], [36.932, 25.603], [36.64, 25.826], [36.249, 26.57], [35.64, 27.377], [35.13, 28.063], [34.632, 28.059], [34.788, 28.607], [34.832, 28.957], [34.956, 29.357]]]] }, { "N": "Northern Cyprus", "I": "CYP", "C": [[[[32.732, 35.14], [32.802, 35.146], [32.947, 35.387], [33.667, 35.373], [34.576, 35.672], [33.901, 35.246], [33.974, 35.059], [33.866, 35.094], [33.675, 35.018], [33.526, 35.039], [33.476, 35], [33.456, 35.101], [33.384, 35.163], [33.191, 35.173], [32.92, 35.088], [32.732, 35.14]]]] }, { "N": "Cyprus", "I": "CY", "C": [[[[32.732, 35.14], [32.92, 35.088], [33.191, 35.173], [33.384, 35.163], [33.456, 35.101], [33.476, 35], [33.526, 35.039], [33.675, 35.018], [33.866, 35.094], [33.974, 35.059], [34.005, 34.978], [32.98, 34.572], [32.49, 34.702], [32.257, 35.103], [32.732, 35.14]]]] }, { "N": "Morocco", "I": "MA", "C": [[[[-2.17, 35.168], [-1.793, 34.528], [-1.733, 33.92], [-1.388, 32.864], [-1.125, 32.652], [-1.308, 32.263], [-2.617, 32.094], [-3.069, 31.724], [-3.647, 31.637], [-3.69, 30.897], [-4.86, 30.501], [-5.242, 30], [-6.061, 29.732], [-7.059, 29.579], [-8.674, 28.841], [-8.666, 27.656], [-8.818, 27.656], [-8.795, 27.121], [-9.413, 27.088], [-9.735, 26.861], [-10.189, 26.861], [-10.551, 26.991], [-11.393, 26.883], [-11.718, 26.104], [-12.031, 26.031], [-12.501, 24.77], [-13.891, 23.691], [-14.221, 22.31], [-14.631, 21.861], [-14.751, 21.501], [-17.003, 21.421], [-17.02, 21.422], [-16.973, 21.886], [-16.589, 22.158], [-16.262, 22.679], [-16.326, 23.018], [-15.983, 23.723], [-15.426, 24.359], [-15.089, 24.52], [-14.825, 25.104], [-14.801, 25.636], [-14.44, 26.254], [-13.774, 26.619], [-13.14, 27.64], [-13.122, 27.654], [-12.619, 28.038], [-11.689, 28.149], [-10.901, 28.832], [-10.4, 29.099], [-9.565, 29.934], [-9.815, 31.178], [-9.435, 32.038], [-9.301, 32.565], [-8.657, 33.24], [-7.654, 33.697], [-6.913, 34.11], [-6.244, 35.146], [-5.93, 35.76], [-5.194, 35.755], [-4.591, 35.331], [-3.64, 35.4], [-2.604, 35.179], [-2.17, 35.168]]]] }, { "N": "Egypt", "I": "EG", "C": [[[[36.866, 22], [32.9, 22], [29.02, 22], [25, 22], [25, 25.682], [25, 29.239], [24.7, 30.044], [24.958, 30.662], [24.803, 31.089], [25.165, 31.569], [26.495, 31.586], [27.458, 31.321], [28.45, 31.026], [28.914, 30.87], [29.683, 31.187], [30.095, 31.473], [30.977, 31.556], [31.688, 31.43], [31.96, 30.934], [32.192, 31.26], [32.994, 31.024], [33.773, 30.967], [34.265, 31.219], [34.265, 31.219], [34.823, 29.761], [34.923, 29.501], [34.642, 29.099], [34.427, 28.344], [34.155, 27.823], [33.921, 27.649], [33.588, 27.971], [33.137, 28.418], [32.423, 29.851], [32.32, 29.76], [32.735, 28.705], [33.349, 27.7], [34.105, 26.142], [34.474, 25.599], [34.795, 25.034], [35.692, 23.927], [35.494, 23.752], [35.526, 23.102], [36.691, 22.205], [36.866, 22]]]] }, { "N": "Libya", "I": "LY", "C": [[[[25, 22], [25, 20.003], [23.85, 20], [23.838, 19.58], [19.849, 21.495], [15.861, 23.41], [14.851, 22.863], [14.144, 22.491], [13.581, 23.041], [12, 23.472], [11.561, 24.098], [10.771, 24.563], [10.304, 24.379], [9.948, 24.937], [9.911, 25.365], [9.319, 26.094], [9.716, 26.512], [9.629, 27.141], [9.756, 27.688], [9.684, 28.144], [9.86, 28.96], [9.806, 29.425], [9.482, 30.308], [9.97, 30.539], [10.057, 30.962], [9.95, 31.376], [10.637, 31.761], [10.945, 32.082], [11.432, 32.369], [11.489, 33.137], [12.663, 32.793], [13.083, 32.879], [13.919, 32.712], [15.246, 32.265], [15.714, 31.376], [16.612, 31.182], [18.021, 30.764], [19.086, 30.266], [19.574, 30.526], [20.053, 30.986], [19.82, 31.752], [20.134, 32.238], [20.855, 32.707], [21.543, 32.843], [22.896, 32.639], [23.237, 32.191], [23.609, 32.187], [23.927, 32.017], [24.921, 31.899], [25.165, 31.569], [24.803, 31.089], [24.958, 30.662], [24.7, 30.044], [25, 29.239], [25, 25.682], [25, 22]]]] }, { "N": "Ethiopia", "I": "ET", "C": [[[[47.789, 8.003], [44.964, 5.002], [43.661, 4.958], [42.77, 4.253], [42.129, 4.234], [41.855, 3.919], [41.172, 3.919], [40.768, 4.257], [39.855, 3.839], [39.559, 3.422], [38.893, 3.501], [38.671, 3.616], [38.437, 3.589], [38.121, 3.599], [36.855, 4.448], [36.159, 4.448], [35.817, 4.777], [35.817, 5.338], [35.298, 5.506], [34.707, 6.594], [34.25, 6.826], [34.075, 7.226], [33.568, 7.713], [32.954, 7.785], [33.295, 8.355], [33.826, 8.379], [33.975, 8.685], [33.962, 9.584], [34.257, 10.63], [34.731, 10.91], [34.832, 11.319], [35.26, 12.083], [35.864, 12.578], [36.27, 13.563], [36.43, 14.422], [37.594, 14.213], [37.906, 14.959], [38.513, 14.505], [39.099, 14.741], [39.341, 14.532], [40.026, 14.52], [40.897, 14.119], [41.155, 13.773], [41.599, 13.452], [42.01, 12.866], [42.352, 12.542], [42, 12.1], [41.662, 11.631], [41.74, 11.355], [41.756, 11.051], [42.314, 11.034], [42.555, 11.105], [42.777, 10.927], [42.559, 10.573], [42.928, 10.022], [43.297, 9.54], [43.679, 9.184], [46.948, 7.997], [47.789, 8.003]]]] }, { "N": "Djibouti", "I": "DJ", "C": [[[[42.352, 12.542], [42.78, 12.455], [43.081, 12.7], [43.318, 12.39], [43.286, 11.975], [42.716, 11.736], [43.145, 11.462], [42.777, 10.927], [42.555, 11.105], [42.314, 11.034], [41.756, 11.051], [41.74, 11.355], [41.662, 11.631], [42, 12.1], [42.352, 12.542]]]] }, { "N": "Somaliland", "I": "SOM", "C": [[[[48.948, 11.411], [48.948, 11.411], [48.942, 11.394], [48.938, 10.982], [48.938, 9.974], [48.938, 9.452], [48.487, 8.838], [47.789, 8.003], [46.948, 7.997], [43.679, 9.184], [43.297, 9.54], [42.928, 10.022], [42.559, 10.573], [42.777, 10.927], [43.145, 11.462], [43.471, 11.278], [43.667, 10.864], [44.118, 10.446], [44.614, 10.442], [45.557, 10.698], [46.645, 10.817], [47.526, 11.127], [48.022, 11.193], [48.379, 11.375], [48.948, 11.411], [48.948, 11.411]]]] }, { "N": "Uganda", "I": "UG", "C": [[[[33.904, -0.95], [31.866, -1.027], [30.77, -1.015], [30.419, -1.135], [29.822, -1.443], [29.579, -1.341], [29.588, -0.587], [29.82, -0.205], [29.876, 0.597], [30.086, 1.062], [30.469, 1.584], [30.853, 1.849], [31.174, 2.204], [30.773, 2.34], [30.834, 3.509], [30.834, 3.509], [31.246, 3.782], [31.881, 3.558], [32.686, 3.792], [33.39, 3.79], [34.005, 4.25], [34.479, 3.556], [34.596, 3.054], [35.036, 1.906], [34.672, 1.177], [34.18, 0.515], [33.894, 0.11], [33.904, -0.95]]]] }, { "N": "Rwanda", "I": "RW", "C": [[[[30.419, -1.135], [30.816, -1.699], [30.758, -2.287], [30.47, -2.414], [30.47, -2.414], [29.938, -2.348], [29.632, -2.918], [29.025, -2.839], [29.117, -2.292], [29.255, -2.215], [29.292, -1.62], [29.579, -1.341], [29.822, -1.443], [30.419, -1.135]]]] }, { "N": "Bosnia and Herzegovina", "I": "BA", "C": [[[[18.56, 42.65], [17.675, 43.029], [17.297, 43.446], [16.916, 43.668], [16.456, 44.041], [16.24, 44.351], [15.75, 44.819], [15.959, 45.234], [16.318, 45.004], [16.535, 45.212], [17.002, 45.234], [17.862, 45.068], [18.553, 45.082], [19.005, 44.86], [19.005, 44.86], [19.368, 44.863], [19.118, 44.423], [19.6, 44.038], [19.454, 43.568], [19.219, 43.524], [19.032, 43.433], [18.706, 43.2], [18.56, 42.65]]]] }, { "N": "Macedonia", "I": "MK", "C": [[[[22.381, 42.32], [22.881, 41.999], [22.952, 41.338], [22.762, 41.305], [22.597, 41.13], [22.055, 41.15], [21.674, 40.931], [21.02, 40.843], [20.605, 41.086], [20.463, 41.515], [20.59, 41.855], [20.59, 41.855], [20.717, 41.847], [20.762, 42.052], [21.353, 42.207], [21.577, 42.245], [21.917, 42.304], [22.381, 42.32]]]] }, { "N": "Serbia", "I": "RS", "C": [[[[18.83, 45.909], [18.83, 45.909], [19.596, 46.172], [20.22, 46.127], [20.762, 45.735], [20.874, 45.416], [21.484, 45.181], [21.562, 44.769], [22.145, 44.478], [22.459, 44.703], [22.706, 44.578], [22.474, 44.409], [22.657, 44.235], [22.41, 44.008], [22.5, 43.643], [22.986, 43.211], [22.605, 42.899], [22.437, 42.58], [22.545, 42.461], [22.381, 42.32], [21.917, 42.304], [21.577, 42.245], [21.543, 42.32], [21.663, 42.439], [21.775, 42.683], [21.633, 42.677], [21.439, 42.863], [21.274, 42.91], [21.143, 43.069], [20.957, 43.131], [20.814, 43.272], [20.635, 43.217], [20.497, 42.885], [20.258, 42.813], [20.34, 42.899], [19.959, 43.106], [19.63, 43.214], [19.484, 43.352], [19.219, 43.524], [19.454, 43.568], [19.6, 44.038], [19.118, 44.423], [19.368, 44.863], [19.005, 44.86], [19.005, 44.86], [19.39, 45.237], [19.073, 45.522], [18.83, 45.909]]]] }, { "N": "Montenegro", "I": "ME", "C": [[[[20.071, 42.589], [19.802, 42.5], [19.738, 42.688], [19.304, 42.196], [19.372, 41.878], [19.162, 41.955], [18.882, 42.282], [18.45, 42.48], [18.56, 42.65], [18.706, 43.2], [19.032, 43.433], [19.219, 43.524], [19.484, 43.352], [19.63, 43.214], [19.959, 43.106], [20.34, 42.899], [20.258, 42.813], [20.071, 42.589]]]] }, { "N": "Kosovo", "I": "XK", "C": [[[[20.59, 41.855], [20.523, 42.218], [20.284, 42.32], [20.071, 42.589], [20.258, 42.813], [20.497, 42.885], [20.635, 43.217], [20.814, 43.272], [20.957, 43.131], [21.143, 43.069], [21.274, 42.91], [21.439, 42.863], [21.633, 42.677], [21.775, 42.683], [21.663, 42.439], [21.543, 42.32], [21.577, 42.245], [21.353, 42.207], [20.762, 42.052], [20.717, 41.847], [20.59, 41.855]]]] }, { "N": "Trinidad and Tobago", "I": "TT", "C": [[[[-61.68, 10.76], [-61.105, 10.89], [-60.895, 10.855], [-60.935, 10.11], [-61.77, 10], [-61.95, 10.09], [-61.66, 10.365], [-61.68, 10.76]]]] }, { "N": "South Sudan", "I": "SS", "C": [[[[30.834, 3.509], [29.954, 4.174], [29.716, 4.601], [29.159, 4.389], [28.697, 4.455], [28.429, 4.287], [27.98, 4.408], [27.374, 5.234], [27.213, 5.551], [26.466, 5.947], [26.213, 6.547], [25.797, 6.979], [25.124, 7.5], [25.115, 7.825], [24.567, 8.229], [23.887, 8.62], [24.194, 8.729], [24.537, 8.918], [24.795, 9.81], [25.07, 10.274], [25.791, 10.411], [25.962, 10.136], [26.477, 9.553], [26.752, 9.467], [27.113, 9.639], [27.834, 9.604], [27.971, 9.398], [28.967, 9.398], [29.001, 9.604], [29.516, 9.793], [29.619, 10.085], [29.997, 10.291], [30.838, 9.707], [31.353, 9.81], [31.851, 10.531], [32.4, 11.081], [32.314, 11.681], [32.074, 11.973], [32.675, 12.025], [32.743, 12.248], [33.207, 12.179], [33.087, 11.441], [33.207, 10.72], [33.722, 10.325], [33.842, 9.982], [33.825, 9.484], [33.963, 9.464], [33.975, 8.685], [33.826, 8.379], [33.295, 8.355], [32.954, 7.785], [33.568, 7.713], [34.075, 7.226], [34.25, 6.826], [34.707, 6.594], [35.298, 5.506], [34.62, 4.847], [34.005, 4.25], [33.39, 3.79], [32.686, 3.792], [31.881, 3.558], [31.246, 3.782], [30.834, 3.509]]]] } ]} bazaar-orig-v0.7.14/scripts/countries.py0000775000175000017500000001042215166123241017216 0ustar hasanhasan#!/usr/bin/env python3 import struct import json import sys from pathlib import Path try: from babel import Locale except ImportError: print("Error: babel library not found.") print("Install it with: pip install babel") sys.exit(1) try: import gi gi.require_version('GLib', '2.0') from gi.repository import GLib except ImportError: print("Error: PyGObject not found.") sys.exit(1) verbose = False def log(msg): if verbose: print(msg) def read_linguas(linguas_path): languages = [] with open(linguas_path, "r", encoding="utf-8") as f: for line in f: line = line.strip() if line and not line.startswith("#"): languages.append(line) return languages def normalize_locale_code(lang_code): locale_map = {"zh_CN": "zh_Hans_CN", "zh_TW": "zh_Hant_TW", "fa_IR": "fa_IR"} return locale_map.get(lang_code, lang_code) def get_country_translation(country_code, lang_code): try: normalized = normalize_locale_code(lang_code) if "_" in normalized: parts = normalized.split("_") if len(parts) == 3: locale = Locale(parts[0], script=parts[1], territory=parts[2]) else: lang, territory = parts[0], parts[1] locale = Locale(lang, territory=territory) else: locale = Locale(normalized) territory_name = locale.territories.get(country_code.upper()) return territory_name if territory_name else None except Exception as e: log(f"Warning: Could not get translation for {country_code} in {lang_code}: {e}") return None def build_variant(json_path, linguas_path): languages = read_linguas(linguas_path) log(f"Found {len(languages)} languages: {', '.join(languages)}") with open(json_path, "r", encoding="utf-8") as f: data = json.load(f) builder = GLib.VariantBuilder(GLib.VariantType.new("a(ssa{ss}aaa(dd))")) for feature in data.get("features", []): country_name = feature.get("N", "") country_code = feature.get("I", "") if not country_code: continue log(f"Processing: {country_name} ({country_code})") translations = {} for lang in languages: translation = get_country_translation(country_code, lang) translations[lang] = translation if translation else country_name coords_raw = feature.get("C", []) poly_builder = GLib.VariantBuilder(GLib.VariantType.new("aaa(dd)")) for polygon in coords_raw: ring_builder = GLib.VariantBuilder(GLib.VariantType.new("aa(dd)")) for ring in polygon: point_builder = GLib.VariantBuilder(GLib.VariantType.new("a(dd)")) for point in ring: point_builder.add_value(GLib.Variant("(dd)", (float(point[0]), float(point[1])))) ring_builder.add_value(point_builder.end()) poly_builder.add_value(ring_builder.end()) trans_variant = GLib.Variant("a{ss}", translations) coords_variant = poly_builder.end() entry = GLib.Variant.new_tuple( GLib.Variant("s", country_name), GLib.Variant("s", country_code), trans_variant, coords_variant, ) builder.add_value(entry) return builder.end() def main(): global verbose linguas_path = "../po/LINGUAS" json_path = "countries.json.in" output_path = "../src/countries.gvariant" if "--verbose" in sys.argv: verbose = True sys.argv.remove("--verbose") if len(sys.argv) > 1: json_path = sys.argv[1] if len(sys.argv) > 2: linguas_path = sys.argv[2] if len(sys.argv) > 3: output_path = sys.argv[3] if not Path(linguas_path).exists(): print(f"Error: LINGUAS file not found at {linguas_path}") sys.exit(1) if not Path(json_path).exists(): print(f"Error: JSON file not found at {json_path}") sys.exit(1) variant = build_variant(json_path, linguas_path) data = variant.get_data_as_bytes() with open(output_path, "wb") as f: f.write(data.get_data()) print(f"GVariant saved to: {output_path} ({GLib.format_size(data.get_size())})") if __name__ == "__main__": main() bazaar-orig-v0.7.14/scripts/install-deps/0000775000175000017500000000000015166123241017226 5ustar hasanhasanbazaar-orig-v0.7.14/scripts/install-deps/fedora-rawhide.sh0000775000175000017500000000066315166123241022453 0ustar hasanhasan#!/usr/bin/env bash DEPS=( meson ninja cmake blueprint-compiler desktop-file-utils gtk4-devel libadwaita-devel libdex-devel flatpak-devel libxmlb-devel appstream-devel glycin-devel glycin-gtk4-devel libyaml-devel libsoup3-devel json-glib-devel md4c-devel webkitgtk6.0-devel libsecret-devel libproxy-devel # lsp clangd ) dnf install ${DEPS[@]} bazaar-orig-v0.7.14/COPYING0000664000175000017500000010452015166123241014175 0ustar hasanhasan GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . bazaar-orig-v0.7.14/README.md0000664000175000017500000001607315166123241014426 0ustar hasanhasan


Bazaar

Discover and install applications

Screenshot showing Bazaar's Flathub page
> [!NOTE] > If you are a distributor/packager who would like to learn how to > customize Bazaar, take a look at the [docs](/docs/overview.md). > [!NOTE] > If you are interested in contributing code to Bazaar (Thank you!), > please see the [style rules](/CODESTYLE.md). > [!NOTE] > If you are interested in contributing translations to Bazaar (Thank > you!), please see the [translators introduction](/TRANSLATORS.md). Bazaar is a new app store for GNOME with a focus on discovering and installing applications and add-ons from Flatpak remotes, particularly [Flathub](https://flathub.org/). It emphasizes supporting the developers who make the Linux desktop possible. Bazaar features a "curated" tab that can be configured by distributors to allow for a more localized experience. Bazaar is fast and highly multi-threaded, guaranteeing a smooth experience in the user interface. You can queue as many downloads as you wish and run them while perusing Flathub's latest releases. This is due to the UI being completely decoupled from all backend operations. It runs as a service, meaning state will be maintained even if you close all windows, and implements the gnome-shell search provider dbus interface. A krunner [plugin](https://github.com/ublue-os/krunner-bazaar) is available for use on the KDE Plasma desktop. Thanks to [Tobias Bernard](https://tobiasbernard.com/), [Jakub Steiner](http://jimmac.eu), and [Sam Hewitt](https://snwh.org) for designing Bazaar's market stall icon. ### Installing Pre-built binaries are distributed via Flathub and GitHub actions: Get it on Flathub [![Build Flatpak and Upload Artifact](https://github.com/bazaar-org/bazaar/actions/workflows/build-flatpak.yml/badge.svg)](https://github.com/bazaar-org/bazaar/actions/workflows/build-flatpak.yml) There also exist packages for [Debian](https://tracker.debian.org/pkg/bazaar) and [Arch](https://archlinux.org/packages/extra/x86_64/bazaar/). These are not directly supported but should work fine. If you encounter a bug on any package of Bazaar other than the flatpak, ensure the bug also exists on the flatpak before reporting it here. ### Supporting If you would like to support me and the development of this application (Thank you!), I have a ko-fi here! [![Ko-Fi](https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge&logo=ko-fi&logoColor=white)](https://ko-fi.com/kolunmi) Thanks to everyone in the GNOME development community for creating such an awesome desktop environment! ### Contributing If you would like to try this project on your local machine, clone it on the cli and type these commands inside the project root: ```sh meson setup build --prefix=/usr --libdir=/usr/lib64 ninja -C build sudo ninja -C build install bazaar ``` You will need the following dependencies installed, along with a C compiler, meson, and ninja: | Dep Name | `pkg-config` Name | Min Version | Justification | |-------------------------------------------------------------------|-------------------|-------------|-----------------------------------------------------| | [gtk4](https://gitlab.gnome.org/GNOME/gtk/) | `gtk4` | `4.22.1` | GUI | | [libadwaita](https://gitlab.gnome.org/GNOME/libadwaita) | `libadwaita-1` | `1.8` | GNOME styling | | [libdex](https://gitlab.gnome.org/GNOME/libdex) | `libdex-1` | `1.0` | Async helpers | | [flatpak](https://github.com/flatpak/flatpak) | `flatpak` | `1.9` | Flatpak installation management | | [appstream](https://github.com/ximion/appstream) | `appstream` | `1.0` | Interpret application metadata | | [xmlb](https://github.com/hughsie/libxmlb) | `xmlb` | `0.3.4` | Handle binary xml appstream bundles/Parse plain xml | | [glycin](https://gitlab.gnome.org/GNOME/glycin) | `glycin-2` | `2.0` | Decode image URIs | | [glycin-gtk4](https://gitlab.gnome.org/GNOME/glycin) | `glycin-gtk4-2` | `2.0` | Convert glycin frames to texture representations | | [libyaml](https://github.com/yaml/libyaml) | `yaml-0.1` | `0.2.5` | Parse YAML configs | | [libsoup](https://gitlab.gnome.org/GNOME/libsoup) | `libsoup-3.0` | `3.6.0` | HTTP operations | | [json-glib](https://gitlab.gnome.org/GNOME/json-glib) | `json-glib-1.0` | `1.10.0` | Parse some HTTP replies | | [md4c](https://github.com/mity/md4c) | `md4c` | `0.5.1` | Parse markdown (.md) | | [webkitgtk](https://webkitgtk.org/) | `webkitgtk-6.0` | `2.50.2` | Render web views | | [libsecret](https://gitlab.gnome.org/GNOME/libsecret) | `libsecret-1` | `0.20` | Store Flathub account information | | [libproxy](https://github.com/libproxy/libproxy) | `libproxy-1.0` | `0.5` | Parse proxies for networking operations | | [malcontent](https://gitlab.freedesktop.org/pwithnall/malcontent) | `malcontent-0` | `0.12.0` | Adhere to system parental controls settings | #### Code of Conduct This project adheres to the [GNOME Code of Conduct](https://conduct.gnome.org/). By participating through any means, including PRs, Issues or Discussions, you are expected to uphold this code. ### What people are saying - [Why Bazaar Is the Best Flatpak App Store You’re Not Using](https://fossforce.com/2025/10/why-bazaar-is-the-best-flatpak-app-store-youre-not-using/) - [Bazaar is a game changer](https://gardinerbryant.com/linux-software-management-is-about-to-change-with-bazaar/) - [Bazaar is a Slick New Desktop Flathub Frontend](https://www.omgubuntu.co.uk/2025/08/bazaar-new-flatpak-app-store-gnome-linux) - [Bazaar Is the Flatpak Store GNOME Always Needed](https://linuxiac.com/bazaar-is-the-flatpak-store-gnome-always-needed/)