From 63ca005b6ec35055b70f9677d7f6c9ef3060ede8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Raduli=C4=87?= Date: Tue, 5 May 2026 08:46:09 +0200 Subject: [PATCH] DEBUG OBSERVABILITY: live error feed + auto-triage bot + dashboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PHASE 1 — DEBUG mode: - /etc/systemd/system/pgz-sport.service.d/debug.conf: DEBUG=1, LOG_LEVEL=DEBUG, PYTHONUNBUFFERED=1, UVICORN_LOG_LEVEL=debug PHASE 2 — Error stream: - /opt/pgz-sport/scripts/debug_tail.sh: tail journalctl + nginx → /var/log/pgz-sport-debug/{stream,errors}.jsonl - pgz-debug-tail.service (always restart, multiplexes 4 sources) PHASE 3 — Auto-triage bot: - /opt/pgz-sport/scripts/auto_triage.py: classifies errors, dispatches CC agents - Patterns: 5xx spike → CC4, 401/403 spike → CC2, 4xx API → CC3, ImportError/DB → CC4 - Rate limit: 6 telegram/5min - Records decisions in triage_decisions.jsonl - pgz-auto-triage.service PHASE 4 — Live dashboard: - routers/debug_router.py mounted in pgz_sport_api - GET /api/debug/health — services + DB + error count - GET /api/debug/errors?limit=N — last N errors (JSON) - GET /api/debug/decisions — auto-fix decisions - GET /api/debug/stream — full log tail - GET /api/debug/dashboard — live HTML refresh 5s Damir admin tier dashboard: https://sport.rinet.one/sport/api/debug/dashboard --- .../invoices/20260505_082127_ina_racun.png | Bin 0 -> 40387 bytes .../invoice_16_HUB3_20260505_082323.pdf | 299 ++++++++++++++++++ .../putni_nalog_4_HUB3_20260505_082323.pdf | 97 ++++++ routers/debug_router.py | 170 ++++++++++ routers/enrich_router.py | 13 +- scrapers/wiki_hr_categories_fixed.json | 31 ++ scrapers/wiki_hr_scraper.py | 23 +- scripts/auto_triage.py | 185 +++++++++++ scripts/debug_tail.sh | 59 ++++ 9 files changed, 861 insertions(+), 16 deletions(-) create mode 100644 _data/uploads/invoices/20260505_082127_ina_racun.png create mode 100644 _data/uploads/placanja/invoice_16_HUB3_20260505_082323.pdf create mode 100644 _data/uploads/placanja/putni_nalog_4_HUB3_20260505_082323.pdf create mode 100644 routers/debug_router.py create mode 100644 scrapers/wiki_hr_categories_fixed.json create mode 100755 scripts/auto_triage.py create mode 100755 scripts/debug_tail.sh diff --git a/_data/uploads/invoices/20260505_082127_ina_racun.png b/_data/uploads/invoices/20260505_082127_ina_racun.png new file mode 100644 index 0000000000000000000000000000000000000000..5fd4e5d4b9c11668f599a3bf442c07a3818bf560 GIT binary patch literal 40387 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 +endobj +2 0 obj +<< +/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font +>> +endobj +3 0 obj +<< +/BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 294 /Length 6909 /Subtype /Image + /Type /XObject /Width 294 +>> +stream +Gb"/c=dHusP/HG]QgQk!V;Adj`7n:/sjcCEk,F-.K?l7Pq[Jph+[OJ>$13VH$Ykr8IO,AZkc?5G;IpqC14YKk36Gh,V<-IdonGrhT]RaX+fY!RAZC>OgJLj:M[dgH8h&$X;7-!A=d+>7aclG4fnn:l.o&,Z)VGL-;5nqVS.D(?<3Y(ArE84Be>K$QnYM`ReHI>H!,E=R4W_kVmT(0@)A]pCYIO@k@Nc>A[^fJS^o"\JdIX`XD)UFSsP_?QeA+rF]s^a$RSOsZ_kEaHeo2kmBpj<,Q87dO&q7(h;mpe>2;C`I>3=\$V9HNWKO8Q3PV&G=%6"okQFV3L.C8Fni>5]lY$n_GGq>LXG.Y)MSepFo(6`N9/Qa&eB9M*=m&&sb33C0\)HI63a3pAd[l_4dGqi'00tE%hK&s7Z-J@e3DL,WJdooGJ@C9Kg/=f@U]8JQaP.R/U!BsCp>$^YK?3hZK9BEXF3iZZ)c)VMtO<#9m0gm;lHh?"F4EXG>>AZ?r<^\MGmST@7!1.Po^d4fhtRh%OACSU"B8SCV.NRDB[)@J-)USg[h2bfe_\;RX6>K\!W"<)1)n%VoKu=UDk,Faa]K@If>^&mEG7(XleE/2&O4(VS+4@3nTr;-$"V3UpQ>XG,bI-2aLhq(8\$aY1e/BIP<89S^$[]W?cnoK'a@Pq`#&=U?\A`/Ela(7(;Pn;CW9\$-Jl^F1V+V4;cb*S/*uZ4_W6lfmlVKf-P&pL^#3Go3He\2X./^R=/$*l_nGm`iGeD^P:LLN-LUHZO,rRn-FB"aH'llgMmpI]rcd6oBIW]H0V-B&Dh#h+n%P:<;XWXT3gVGTrf6m5I5djrgrmTW/mH!e*V[>GDF.",Q\Xi'mkD:Sig'G9(b?iRHs/2SII^CAHV^&LRMX`!g5tR')iLV$+n%VjWn4q^bW*k*m:1"SFP)Sle$"jWT7#2ThG\$Vk/I&!2Inl8`o?5aaLb6^l?2PE1J[ONqcFdm*Hkr_oIK"Y-XZPXpQQPnH*Me!%@I^G_GWSbL1)N,DE+&pLR$Q(l*[a[:V1%;b**c>B's)=[VgCC/EP>u(maaRL6J$P=IH:\?40F%Zl=ar4LsE]jrRQ8l_`:N;EjKF#MUWRRIjt2ed\D+IFjDA9R8!G4aKgM]pQ*J_ru7#ojTtG?AVF;qLIpK]GL1[11go]S0'oO>to%AVO'f8JleH6kU8H;,d#R'LkPk]PeU@QK]ZM2oPcT&-Kkh+Gal=A>3q[?$T@ku_9(H$\n8f;-$DOL;<]13[LU.l5YZ]QWo=g_6k_G:OhP@5VWaeim,HVIOo=k39E(?BaeX6Is"gb1s+IXNXAYo%M@;F&0Fqh5u@3L"2Eu>PhNjR?$C:S#>G@GYPbR$!@Y:.U,GILm]/JmZogM.r^u$qGO(OE,2kI=A3)kKbL>M=YN4M`[pE2h&q4=XVUOS44?_R#9&=u?l]p!EiAWZ*3^$6]e)Ti!jP>$h?HmS(qhef.9QYS>PKK'qH^T*RgOajWh,b"8@A;5_R8fbOfZUqNh\PR*mCm%3#nrldc(so@_HuA1rjH4lC\JR]8sni7DC1Vr'D=3Mo!\f"?G!BX43hPhA5oa)Yfe=UV,)`Is)77;ned\YkW>Z[J4$jj'=#(/4O^#nntMhEHd::FB"Oq_0&6SMat1R.;%,-=.J$I1kY5:85u+@60]9CW]g7jY%rS]I\C+,g&9@7%*G[F=_XePdOoA?VHi3=nL;/dG$?P50Z7<@?`CHV8RD'Jm'Z')gF#i^brsH_H!'5#Dj"28%=9[Qo_(k@:NK)9\A+Q;XVBVTC2N0h-Rc67W5QRKY(Wm_R\NmeMUn?G.:IDm@E;]q$b:*mFTISo<9Ke[o8^(7S"MgY#JrKXF?mH5@3s]7,>i%Zfo60YdsKWgI"!^V/)fn7M)%`FDCen]hQ'uFo6XVB$$XulPZ^=rA&7a.?M-(Ghoil/\@Y5)bS%3#$^R^bWgEPZ?5?+!X(cJ]QI&N)?Erola&6Mbo^X\IetRrMleP6>GIO?.C0dQXBt@=HJ=u:[$6bUX?4n9Ph?tg4A;0Nk[F.1\'s+"/>8o1]OK]bNhstNkiH6qX@3Z#f=RU1G%V+5jl@0Bc?(UK[RMn\;e@V-=MQ/pX@c3Oa+-a]bWd*h)0?l94"mkVm4u#nR;fO/UHisC[<[>]OK\mj+!t\75$I/@9u)Dh0V4Z_S57e?ed#+[bUb\4DW@9Z?DgmIFDK9\5/i8\bB0NetV>=m5t^PVRq4qT1%@Qn#u;`7F002GnTgFGPU5^M6c7"?fbFKSsQkV,j_#go#6"iA]qd%b-MjH05K`BfJd@emZT4LQ.ZVi]\CedDjdolAkp`qXQ?frnQ&"U+2_RI6goVMgfqOh;\'H=#Mr%pVVA@D3]!7JOH3nrq9ObEn/_4]P_;).39A-&+Yd_q(gD]quRhh7BkU/U@_Mqb1J,kUkA$C;J]-)b\kYQa!sF,Z]i[@_JWSbh]k8PV%1fHi'=/YEuZ^UlNu`kuccf^I`[abs0,$Hh9'@3nB%ONn''P=P_<<8U.to5Ju9'oJ.dTeqTKNeViZoh9Wi-GeVEe_q]V21+,-6L6dkMMs4@"cbE%r^-C]]rNG4i]-jeLo(f>l4P#84-VYN!%'-a/p.q5^e`eqVbVds1nnphrjgZ+O0[X&j3K/+[;TaVL)RH6g2*ba''gA+f,h@:c%s2;)HE=-'/DQ.b_;H)t>c26>#c]d?rWp?Ie4Z8,Wj/^[t^/nZI`WFa^.,n?<1[]Mrh3ip"$?&:\L5n1"iTtd`]dLH*KJ4YML0uk/gqn/LGgI=RO9L]i?Fuc@>NU$dS`A@[sm,L#nSIS]&]te[mjAe\Q&p5n]i^ktQ^)O!]Ci2eDDdut@D*9d0<5o4e+9jXmWQ'Gp"Z[HP;fRE6K2SL@X39+Z0@n#*e_?0smPSRDfo>)W\VB5&95&UU(07WqL+IDL.EfqQ/GI7D/GEI;bDWd4HM'1,RpP>-B_afAa+8KH!TQ\W+Uo[[D/^Z!I/nlYP>Xes[LM*"AOYk%F4IF4UJjK[pZ>>;5"'6fb(@HHbHqP$%ra^`_>\!gL$-LNE._ogHoogO'oP/j<[DDeh&:#&l\Q_.f^FJR"bA?Ri?8:P0LUgWm/:-a8cKDCRHM'$t40r!^3RM:'eglZM]=%8+X0Q'Fbgt)+'iRkLR(N%6U??F]I/^.I7B`'.SRq6^@L3pa?>L]V\`[P?&mG1:)s5[l[pE5(HEhlLjdqeB95*_1DO=MOh0NY;lc&S&P^?^P/>9H^]4##/GO(O5Xr#j5;XSg5Y_:Rkm"TfYgoXWn]3]:q9=a4s_%KrKYT)`TF15IYm!>pb/ENI)O596T@Yo-"_n*/nb:@jL@:clb=EhrHZ.mH*,>h3X=EepuGpTXFXN]6)lY^u&G'dA-,g(rRlcsB!YN1t&Q.``Wh(:;"DD,db6oiY'h:[eLQ+XE,10Z]=]B.#am:ED^-mq'W41hc1P#iE"B'Y1o\%EQi]rX((j[=lHB/c,Xo#ehlCu)>`QIdCq<>iE^=@2-HT'IJ#1<^CA2#0:'t2`GY+EDpeH!0QqfJK[qYsF'j?RhJ\%OgP[Ab?Ep!sl;`oh:u(9r6<-`]W?dCNg5^BPh?sUMd;n1@]Tanl'H^[RH[h!/?brZkA.;'N60;0:2_l-\Vq7Kelc%Z:[Fl_VOMSS3k/m%T3kas??8(I?Y0@HuL(*4`1/E(ceEM*goQi7dGAVLo2InKpQ?fe5Ue\*TUXtF7^MC/CZ6=jGZ-8Ef-Zsak)80A#rEYm5Opunnh,W/!4ltNaPO;-?["Q1$>KkfhI>a\;DkBUFVL2Ra?\L(DmEE:5:V!s\UcVL=/`EnM(:/0rhkI%(gLns*.A)pq=(."i40rkQ;ss$/l->Mh9DGQl`N5W`\*,:8p6g#8b,6Pm?jSEdK\!1qS_fA!as,MXEh>"f@::Ih?;9_WDQHnTabH#VHuTT'/"uWN;Q"_K]s:0eSD<:cCKO[FX]L]I]c6:&7C(n55$qR4_FeLTRagTX=Ka9=%4CoGiYiS56L30t:@H2KAW^dg\^+u*SF?.Kl_Rq=.k=EAbIV,MchFa99IfeLrotd$')(ng]W<'I9ZLU[=pUpLj,kM`Co(9Sr)j^;I0.W+FT!6t$-1#2T$*=uT,ag%SZ#3<@A%)V7fZVJO=tOnh1/I=Jh41pnD@;c7Q^K/,>3qD_T%qAt3Gjc3(+`lI1J;DhfHnX%\W:lSg)@RT=MeBVQI'BO99OR@+7&'r20N3.KY>S\U"*V=,kL(\f$.oE==l(8k&/!n9X+*[HM-&r_Ct&>gt>S;mM9WV"=m9O=3mE`r*l8>SLnF8DS\5)Yk%F4p"W]e0BS\XfhuGM(2Ukk.o3?Mc^cB[@\1]4/S4'^_)=uko(78$gf_KIk*b#X;J,>4Cr6B+:TmjGSL+2CT&#s>b`cg9_H(5`Y^MnjC!$i7O4AY6oAggRYZ9?pC`he^RPMe'@s+Ef4LrHWCfRnJgP:'FVTc:8=PY>\:TcDY>Eu>,p0h:*.5S%fjOIe4?gYi'0Tm27X>P0d/M&PjGtWq#?qo=Th9;'.H!#trAIH])>2I\9/QbsFC,b`08KQGl;VAqXZBhtA=:<]E^"U^n8Wnk:QrLMu]WC3H*S,g"AZp85:QjdI/LH`7/2(da98Bo_:"cT'b`a;t=Goa^$d6^shU5ga=B"p.1@sUJ\QgbRbN3cT>V;Adj`7n:/sjcCEk,F-QcnK2\QgbRbPqYD%g]ImS,~>endstream +endobj +4 0 obj +<< +/Contents 16 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << +/FormXob.57da11f962247e427dae4e77fa661a6c 3 0 R +>> +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +5 0 obj +<< +/Filter [ /FlateDecode ] /Length 677 +>> +stream +x}jPṟBÖR}Kri ^hJ}IJA޾{yPJt7ӫ~s_M~wW~Rfz:ܝW0nod>0>wo.N׻kx/wO뷓q]MWT?tgŢ[ׇاyyt_^u?,Wu\u2?;[tYLjYr|y,Evizִ4M[t4}/l?6}K/4K/4K/4K/4gNMlsdӟ#Ȧ?G69ϑMlsdӟ#Ȧ?G69&s_~_~_~_~_~_~_~_~_W~_W~_W~_W~_W~_W~_W~_W~7 ~7 ~7 ~7 ~7 ~7 ~7 ~7 ~w~w~w~w~w~w~w~w????????_6&{]D8:u} "endstream +endobj +6 0 obj +<< +/Filter [ /FlateDecode ] /Length 18175 /Length1 35128 +>> +stream +x \U8~Μ3spyQDE$g>@ +\⡙fe#33H2SninmE0̽<ڶ1̙s~wD!dFA'M^JKjJ(Bx O`/*S}%7 ǜ~nx>4[RknP2+qÛp=*@j\˪|%7E꒫kŇžeZSRc a鵾 '4k뼵K6w!dxa~ Oa-;  +!"qGŸQGq"TSAyvRzuja1.\@FMH +k-C#"2 HAF,ȊlȎP0 +AD( P8@( +E6šxQOzDAI/JF)(Ci?@4]2`4 Eh8L4DY(Qh4EcXơ|4+P!D4 MFSTh:fYr6V4q\Zly#.s5q|)@p?߂},/F ho) +ke)|5?_|9jc&_Ŀ/BS(f8hga⎠:Bs1(W8h 99b˹oQ }1[n$Gb9ҟĐpN{:XB?-yZ@Atٹ"n:w}1B7|a6։) z;(`.C_"b~r ρ)ƈAh5c(AdZz+ (O $72lm+^E@OD'FIs5y<5oE͠6&Bu SajDR?cOM[0E݋{egfg SI6bM7mfK5][͗ [ (f?qO`{>%VG)G[!і-X;[ΣzvV[m|etf{3*Lw@UpO =`hL +9&:*2"<,dY-f"K$vp(}虴Ca61$`DzMK%'KC{2GjM'oOkǣshjKucڹwRڷk@IF-ACgX0{hHcT>L9a*)tuتA!I+!fQ)Hze }" JC4涣CBmke?no}uΞ[Ph((##Ǔd`ơd>`pWz74;BD[ _zx'O~We/{៪9Q<@{ 8d8<w{=-d!#'OY#AF\##D"Q'=r"Sqk{=.>`Z&2|W>2,YI1r`{>5rv&3\*X&|Fq8N  +Ҝ@v|\O`]C7zt޸Q~{߾wiw$}ǎѣs-[/8q`D}/YR_XE>=Q*jfU$KI}S>VQ/`xNM0!;&K솨[rBoGS{Da + 6Mlm-G^:ǔAW{Ә|7` t%4C3hvwmM%%`4s˲UcA]reLu%9\n*ccSƦNӸi4^ӓNIV*9bCRi,,-I6* .cxBoc1=25*5:=Í1&'sӍW&́!UF ;zcu%A>vR)S\ٟB8:4)z7i е\ ӱ80ayp*$}WM  +)~? wXz04Π0)DS'F PHvV.^w/p9}k '^*"qmVqyxt-o][/|ȟ{r$;8M\3CT]2@PՍ9ɝO׋Vmĺ+bvR{79spG}߯v)|+u&9ੈ=#"s Ni8`{Ouv3xK?A̗ţ4+̔;QS_5aDz[{;z $3G*8ʢ@x |2sMӇ"8ɽRP5N[|m8l߲~p޹fϞ6[?׸4q/xpz߿8xYTs6 >LCu*~zwLmmgtB=HA A2w\O=2}[Cuj l=GMWy/R> 4l|8NԦp箿w7g||1[Ez,6& +vWjѝ/֖h[!18Ap Ҁ[!<[+ (G^?o!R[t4/& 4M=I9p:N %ͭ#Vz ~]8NN~ZI^0$ް6K +l;.pRFN|g?G ??=f@: N!HjZ~(.bP,I +8^tYѶLG߮]HE8?J?h bٲ[Jv`Ő@ jEs=œ_1ʟۯp'9ξjc>GY[o ~ǡ*` H#^kTyˑԠ{O\@^fzE' ;q|.@\MiC_ +bn5N;/ӿHHﯯvz4:S# + z=iSΛ6qw\|!6vem%5Ok{-k|kI"ݹ⚅˗kF[ F]>6ϽaCfka}93 6̹~{R%oyljЎR* <% +(Q(I@h ]" rG”eR,EKRiܠܦlPuN) )R1޲jsQhy +O&/Ŧ_7 +V&&Vy-ZX%_C/ KGm6wpLzWNal#|NY.%jKڷᵇMB8ڇssԮ 9ɭ; V4**փDXLErXo ha38]$o-Eݜ`H(W؟Vك =Je[]9sWn[ۯFA8,w^?D[ȹz{f(,aZc77eX 7GFGbh R|'r6w͊ew5MֻWfߏ +.f߾9rS|99LA*Q9څ?4  ׌ߗ{CA-WDv`֒URx\}|wLYG.lx!0 䆱5qS9M֢M+a粩?i{tX Iڽڶ6mp4ig w-D7p!qS⟓~GXaB:Zghmv""K cIxX`+b>hqq˹\ cM3s#=ft(;\f#ƨ>|X'yŝAhi}К0usQ=cD`+5%o;Zu$Iy7=O +FZm^Z>0i qVVkex=XbQ?Ӵ`܉fl}y;@aE]ȁ)4`g?G~Pow^sM-'YeeU:?cVf{ΝȶӰDZlvUDUu Ɯ$PdJ@)QLbfiqyjȔJ& $w0-?~~Vhx-YΫvac#\EY̽Mw$/.lbv$ٓEΰPTNYiZ8È-%" =&F;+24o T.!,fLDX+<<""K `ڍ,C52Z$9 :IySo'}Yg[ę޶zF{uOo4Yv*4$Z30'D$(Xt,e8KIBS&CBq CIFQx4g cx +Y!A*z|_rGVx=c( RhT{y nN(+p\L0H*DF%yWF2SETWm2҃39i0Q@{`l[Qa v0\诤aLnPP` 8, FH(Rn 7%pHK%)24>MHS R<n%9h![ci42(Bi<8C>jH_aJMyv|)VyzuKIH,19?Xp9f+c~AR9W*@(Nܸ7IǃI2^)T?9!+[2.mc\.{*AF@J {-$i!܊ +*K vQrpM$Cn!Idgs{l:?j;E.kĶAJAɿWt(1~-=kTbG694N_Hj#j_)nxwww{pYڿO q<gVPd@oq})HF뷖=\ +]%=4N<f縕b9 +^1% _ Upy.l*/qO8N=7k+r|OO!"b=-cD}]`yîy-rC5&J̲8,C ЦVs_!y) aƩbg3bk V66b>z ֑323! 48e1+1fWtS$ð/u!+F+£\8⸷n7lwwum-FNQ3쀼`&<&VɱjCaoȈ OI6X [lwtR.%.<{Y@ -Z4fOXѾ~qm.hƍݰQSZ;lO͘Y +B<0>[*PSa ^o; 6+b)uqҥƧGV)dMm;S<KK}O망A1MAίM }*~yGP~Q3-3b?&UM4'1_׾ 7S-\HsSk\:b[W(oAWh'9Qa !UӚ'9(3[D2 ;G+Qã(X%W'T$((mϘqgKB8㰄iw-(_~#~8 m _0oۆw=@qxˬZ>f3@66sیwlMZ 7MWio5p Qt%?K,h\$맴(M;FZ l/pl& 3x:ݫ5}; +bE.̙C \K` =Kr@|E<'1mq.a 2kXK4%}ʵ.QXn:eaGH} }tQCH n'"Z^wь$[5`j8yCXeŪJZRfܶ+{޽Hm|/s!o &<FD A^o, +98opYQh 1č>jn9ӽ +Ͳ. 3rH3eYVdd4V!>nYd9YI6&͉j4D 16 6(ccLYMvOާ333-`,E1'JiKw^y^_o*/[2ԾZ}-wrnno+}r/RSI6۽'> b7?kG4ks ,՞p Y&;-mBd9d) +6rܥN{ _"V^G1WLtBi0 qhJc㫴O߫9Į]ƒt=q_tp#/f# !oA"f(mp>t|&ӳE,yt0_~_{n+PkxJDܱK~f04Zp>"zz V<խ"J2Lʹe]Fɿ >`Q(` 8=Q܇$A2T)`|tx3,"FZ_%'ӤGg}1p(v9(m_J7>a4(߄wQ}q^_@h}qO]H VEioEUҹt!UŊ*e(77`B`$D C'RmJt<" I[Fqz9q44L'IWEƩYr-ņbL)66r|P+jBono2nZaWte+(?*<,=*o5n7H'M/f*x;NJft%Wpǎ}`د-ѵھH6ͯ +ψzr~صYk y|J1 ؽD!k?8  nDY%)r2TIB2]Mzr|YF+].r^ o$Mnt;D7|J|@>?A_o r(&oERc} +" PRYX~7e +VqLkuj{Vz:tHy"P>BpK(ߡz3e 5G +/:1^mڍmi7røxmk?=Hk F!+XL,ݐzY H Knb%B"/#Ќ??&1ՖNEˢ^ ֽmⶎVe"aArbBed8Аaɰfl<᳅lqonno1b[ K浖mvx?7MʳƧO[^^3fy6wpmcfʵQ `Y1,|ѭpVeEZ7Dd[}pڏgr \a!7paA5lG`#،=Ib1,҃j, +KH qɛ6'_ھjتh0n92 +j,Ar4j8rGL"ps!Huz|͙h +*п eEQt>0(A%/W9l؝U/{<{i5WnzS PIŞwd"T"]@ofCHW 8 U6ശ4؍bPFu'sP2I줻 si>ߴwtzp;'~#N5>\NBXh{@+"L($Hp4Ft!x LBOee:MCtsw[a gN1{.դGI"!q:cYq3CB173ovZs [7uߥYAO1s@} tp7(h؊q 5OA8QP579n4` OAؗ>Gga;fRD/B8/wnޅst\kxE_8DxZ)4p`Joab vE8SZ(p&>S(GS}h h +kB;t_($h?%| E c(CDm‚݂yz=a+@ m\?^Jld( HOo O,cC^ûM&W +{/yƛۍgL#L3MgC7--ZakSPXࠢAkv "l9xw;op,aaS\kkkx1⯑FFM: |]L}6/|™8 [m ·6; [6En- w-"+-!;w6ҿoumA y߶#~ȗσt i#'~搄? RoH +mEsh0LT1oېsHmGҐHCh!ChMQQ/TᜆRaCE#OyQ FIp7@dhe*TT]y1X=1Y`0\S)%0_1 Zsa$=Jo e#JE*@c- p+ +}0{ { 4WrNEګ4QM%:{:[R֔&UUj!UzueCJWQGT,ܒIjiEIoZRU+kUj0NF`=O(@LF~l٭`dQ1DA[W_QӒ9p)ؾ¤\}5bJ"R`+Ø0au v/W$za hhR@7&J徺9/6uү% iaq>~Tu^fuђ8&9:^0O¬4Ai`O)Vߒzu9i_]錝<Ǽ$mڻ6=z0U:΁;%-yx8z&|ݥ|w5L]u)*]8UV$`mKCUGQb-yp㗘V)^~~iNFl(<M<=˅{*qd\?yɞq'CB&2X:B8RSkz5,:6Masd xhSn舑pg"\(DP}>7q"9kwrٌU!Jg.GObm9WȠSQH(]ѻ\&0~f2ul 9\%aKBh$cSYgFLEIL,6:12mwBIRǃRy"Ll2~n@wF1oqc"/afC܎;>2ZGy^׉.hfT&]w*&3;%?³N\t Lfze2YO谑fOаN0ѯ;0߀ߡ +]YLNC ʆV9 ~{5vf]Τ.k&{QoE:%=fuunZaVz.z;wkYo#+<ב,`O;czvΣ3؟1W u-/PV,,`fBkh5P%eRCW1yR4LíCuY'O([ER> +m0@y0 e +kxtN@_u K [=WR.YR gՃg]puz +*,RRgu%[ՕKJ%JgJO 3u%uηNe]޺ו~,xuI_ZuIAݫKngKOpW*tʤWLkdIU&?VeR*o2)Lx)vvjGʏ֎:k@ڑ/Ԏ~ +v?Q~XQ~Aŧk淬(5/(]*>?Uw-*4 ?ACahqө^uʷ 1Y_%VԫյoZ^V3`_5_uFQ:g+Qu:>SÏ~E3W+%jC]In+x+7tj sͩ+ғv xZRPX%D-P W] i +\KXZR_+,2_icS^YBE!_y`\"ä[[+k,20e@X/A6 \ZXF1YPPkld+tVzOIRj)H}ER9): rޕZEghA(P17^6̧s WF *ՔUR:+J+eZP_^KR۩3Js +)FNy/Iڰ[^%HuZ]UWRE+jՃ-)+c묣ZRx5V)t2o}VaВRROGx& +R J. ?&G'4@jZEJN/mSFR :cո;s(ql@2y~{KPA'}ynQKjkJfWyvLJP*JԊzu]6֔DUaT}UԪبJ*=VkKJk| +UMM PVSFg9 s&gfԂrԸ pN-=~b += +3󋦪s$5{JAa B5w\A^n671+7:/RrТlTn +l\vp9"7/hj[0B5S-,,91/P-XX0~B690Kl _00w$T7̬qcT6H.TYd`ٓ 3E +3Ѿ;ǏVrO,R2Ge)#2s%Y2GQrn:9PQمyIꄂ쑹|-Yzy ݑ'd_1n@Il + d1\ +h|aQ*s'd'Dr +TsL~R2~Ћ'P4ҭ/hWե~]#sLbZ;PQ5`=քŢ:6 Ie"z{SWS|ԙ,g!ڧ< +&QԊX/%U0nam]% YPWD-iup?L1 +N +,Aǿ[_ Qrja2aRYSW08*4s2_⫛* +˸~us?Ƀ=RItA/̃A~'_ b%΄E5ȕ\Io˕`Uҙ+0WR WR~,WR~tɕot 98*]R%l[LJO)L?eRyʤ\2$eR.2JʤeN7f!p\XA=}B{2)ؑwݗ,dc%#zF`vD Kȅˉ6|DZ5ݷoGoZJ#5!_jB#GsE>HBZ<(§i||SX#pqV#g4F@#4~+9^pFNlNww[q7˛n/䝷Cwc6rFe-#3s+y&okވ')Dx'ӑ O!H9 GBȫ<#W^! ye3nF^,#wلfIs9`P+y³4r`]8N?c3L3VDɞ^< O?hdFvkdW(yEqx+ dv,!id{OFil +٢6[4B6{MMd# M6iC+y0$w +7S#5rFnmU#nnrFn iwN#\dB,ȢVrM+Y + 42+il[ICo%uKU% $RJ[IU+HEIH#s4RFeHB<|lE(5 +))v%I1 2K!352C#zF!\ip5-LȔV2Y#saF&j(L!WVr.w|;MƆy2v]BZ1vk![ɨa䄐V5"dYH FL&V[Vr j9P3RFk$#\Ad`z0M$?@1 BȀe|4?i&/uO#?u+I1`7iз$9B`ҧ.# v!!T;M$Vk%^ !1 +&Q.!M"BDq7a&᮱BI]cIFB 9[9$IFpm׈X-6LxXfxbn%4bҌNb\+fxxY#F E5"(D|+!eQ,`;Af>Am?Qmendstream +endobj +7 0 obj +<< +/Ascent 759.7656 /CapHeight 759.7656 /Descent -240.2344 /Flags 262148 /FontBBox [ -1069.336 -415.0391 1975.098 1175.293 ] /FontFile2 6 0 R + /FontName /AAAAAA+DejaVuSans-Bold /ItalicAngle 0 /MissingWidth 600.0977 /StemV 165 /Type /FontDescriptor +>> +endobj +8 0 obj +<< +/BaseFont /AAAAAA+DejaVuSans-Bold /FirstChar 0 /FontDescriptor 7 0 R /LastChar 127 /Name /F2+0 /Subtype /TrueType + /ToUnicode 5 0 R /Type /Font /Widths [ 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 + 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 + 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 + 600.0977 600.0977 348.1445 456.0547 520.9961 837.8906 695.8008 1001.953 872.0703 306.1523 + 457.0312 457.0312 522.9492 837.8906 379.8828 415.0391 379.8828 365.2344 695.8008 695.8008 + 695.8008 695.8008 695.8008 695.8008 695.8008 695.8008 695.8008 695.8008 399.9023 399.9023 + 837.8906 837.8906 837.8906 580.0781 1000 773.9258 762.207 733.8867 830.0781 683.1055 + 683.1055 820.8008 836.9141 372.0703 372.0703 774.9023 637.207 995.1172 836.9141 850.0977 + 732.9102 850.0977 770.0195 720.2148 682.1289 812.0117 773.9258 1103.027 770.9961 724.1211 + 725.0977 457.0312 365.2344 457.0312 837.8906 500 500 674.8047 715.8203 592.7734 + 715.8203 678.2227 435.0586 715.8203 711.9141 342.7734 342.7734 665.0391 342.7734 1041.992 + 711.9141 687.0117 715.8203 715.8203 493.1641 595.2148 478.0273 711.9141 651.8555 923.8281 + 645.0195 651.8555 582.0312 711.9141 365.2344 711.9141 837.8906 600.0977 ] +>> +endobj +9 0 obj +<< +/Filter [ /FlateDecode ] /Length 697 +>> +stream +xmMkQb-]il PK:ʨ|gI.mu&?<ӻC;7ӯaf7C>.:7iOlv{i9z>&y3V.sv|[_ݏ˪Oo'/&WWw&E/>u>74>o\6ty> +stream +x |T8~̼'3ٗ@ !a L!Aф,$I*e+ Q)"R "m-`KZEEHsɂhv}>Ɨ{ϹF"DQNz“sp,k}-UH&ܫUfgtGON1tQu++),Fh~Gͬs%/u=0aw/FwY8Jt7Bc)3K*>}UeMh2BY{jp|Bb‚?DN7ڙPa( Gm娂8)bFSu⍺wi0lB"QB:#`Y ّ 'r!_Q +DA(P"P$B(Ţn(uG=P Wqg%tZ6th8?#t#;qN% -' _NB Nyv8R 7/-=Th2=, ,=zB(?V4pqJ'1Jxo'Cx):6@q5ZJsBТdR +X'FT? ڠ !x.0r.*HN]$8/HkP3:Iowӳx)FF5썬T3A' }&WE0~2(*E-ـAx]!nnPP%틦|C=:8RkIxhn :TEzV'%+$:xI=oUl:e/k\3I{i~|gI޶Ip1ր:TXL:S.:f1wA@ȀRRzo%ȨstJt+Ҟl=~1V%| *E>cP*_ +h^%$Ap{ D@s/xmM4 9CA7#Av\D킡NcmFH_Pw5`& ~>V=,48(,fAU@_Rlo1>tNT%ufl1vclt8zdptX>$4PhhFC fGvY'#L(^qiJH\[ߣ)vmjUb@XK( ح`u [o[+h 462d?^c:kg)fSgh1{4?b5 )}:a F881q 7ށdycrih#@뛌k\MMzn5u'Ac) v%ŢXgttJHdH4ڐ'M>ݙ4Tn/HsMk4t[ 7HjNڛ2M@?Y":k&Pp<#/op|:(M:d*Z/Ĥ?6aK[CݤJ_/O>X~{5*@BI vAz 'r]d?G>d+lZ׼lRqA_ԁ'eN-d4}lЎ6 &NJ7v[V;&$;Ŕ U0fa;5|98{f;x،u61'/B0ju@BE" v#9 6 M<=5lPvM'`d'75jڠ\<~Pu+6 Y\C} 6Ny3kpTcJeF@~+ +dJp7:TţAoJģ[jFzzQ`D.vQlךY"9Ff.0z_O,\(.9ƒ'ǧ`؝4Aty⬠;@עYR]`MPmT$pIВhGa4f<;'' ,+Lv_jF&}Γs杚)v^޵klzץ {wҧ/߾*DȼܽG7+>.saܬ\-r=샨3 8FSgAclr9,7UyHl*GѽH{܃Y8۔måϣ˰i =&(PI%X>FbtDkedT ;ܑB^o l9m+̤-6m 2 jkŝ%cAlf@H3;G50'dg\G.; ]?)*RO_J#w7u룹]VzWRlt *F+Qh;GBzj}ٚM+"V6EB}ixXP48P՜o=ߡBnqt ' x\)0|b%%Ran)<ɗl]er8!OZ},>Pԋ8e>Lz{CdnKT)X+wTSP:t ""h'P~CPbp&nGy\M fBYp!@1`)(q݋J:;葶Nb-Y\߰1OٷE|pa%pxs{hz (Y&4aͶվu>(""FկZ{4#AGz4Lq񙃂:$(Yӕ% ~1-z >y]}Z(sѨ0Wyc>ƾmM~A!f(ȡ(|QLO4,&}xt<6yům'K5̓)Z-' n(AZan8~LtF3w4Q'%%IU%K;bİ)^ޒ"//okp-S7I&j +;3}ww>C7u -ѣ{[]W:5nwɧGz$;@Z" +8>Ly4X5ohfe%d w7Ylg7Y+D1h"_$b)R?pbx0L߮7~x?i5>mL=w<]3;Ymꙇ-/b螦mkm7mXj)UTV]+s*zO > s쑛QG +QP#D=x~]_1%בz 0ZIJũC=Q=ΓF-$6 |zBMMOl2I( 8,PcĚ}>aq ^0L}_=8:LQ ńk?vuHd&Ǖ0.5 -7 ElA~*KN=.}af瞞 -kK!WZrĮwÏvx p,j : :}A?ȒN!(ŭ 17Ѡ&QWe~U(A>BGe.- x(uz8ԏ: UVT/ckiz{<W F7D{iqƻ&+-% \`^ֶ byHܗ9 S`{8ƛom"W{0.{`5YaxqWYLۜ(jFq(1]L__r8F1k&Q/xP<02f9\`n4o1s63'|Z_Qk<_퐱|s!)ɅgH5-ӹԱ(u,٧>$X /&v'>d8L?L#lq)Y.6גH YO=~B?WhJn!]tKn4 bnXeZIWKFFUݧ3S7?n4n`g>Ku3ڂhu[2 +2mTmQ0>5`: f$ "H4C|N`] ) `Ћ>Ԯ=;Qb dC#T !A(e)X"vf|gN͌UY( A"S#ǐ\N!usEdn iLt,\&0u0c#pO/=_UWO镫=İV$Y2;sݡ:;!HbTQ:,y|PVJM+ŵ*$wb?2@7ԕR"Ar@iΐ&IR .JR(m18\FU/Ml _!- ?eg:IXiTc.*Wb5wsja^?9r5UVc3#c8ڪަnf0C">|@?!6YOY8rj^KS ^s0Pם\"K[רmx:~axM}SLh n`PxxƹmĊMfͦ4k3c5Y! , +JyQΨN ׉u>DIw#m ϷƫU,p!c"gjz7/}P0z<*Kv6Ä'M +&ɼ(Ck>)裌v-fv8n N[;rTpEHt R?!EhCc]>Ơ%Ƴ#WOF$6YVb>X5`N|#.HC l" {:2lB@\͢"):EiE &i_!YL3-#kpU!z'l=JnB-!gn(0EҧdF":-77q !`8I_HAr#EVrx!6_HG-ÜΡU-Pu??|qb#)mfǴ9 Y=M6r8M@̪l$I[;oov»ݠ:]ZJ6JoQ4Po3&PH:Zm@\_iM}=y@kz-to4k6 +'INۃVaDOԕC uT=j[I|]2/zn^%5~wY O)`H^.ւ5 1WѝxpEɳ5Ϊmb+5#a* ¾Rʟ%k,n\5Zt[@1v O:h+aFW70wS:W?&[/@kg"1$141,QI Oq܊;DV. imkP—E<{)6ۡ @) + +R. +[, +Vv j/w)-۽r>v '-ya]"ɥ֜ٶxWiK=ıpe^bc[Yzxw=hVY[ cI9ie^[8V^x tQhs(0$&M#%CI뷚:=)zVt_Խ Vg#s[GU +}l[m6mkQիou_OwoZ[sϾrν~ܹ>o+ +)[8h!59`bo11Y7~n4Бv e;}Pr=ML{ֶ-_ 96l%|.{itX/k[Y־w[.R  +5KjgDV4l$:dykGMO6Q6c qSk\0mϱث@No=S_]G]ΑMn!/72DkF뽅M=ѵy{ 6s@d/%qb} Z_CfK +~N\8X5FcVshi]}Rn#]E^ս^@VdEJL$kCvl-]nM"z;d,ZO5fKyI4$<҅Da")D25(%pMV^ʱ9v"y):x˼ ɔU@T3|^z/zR[nJҔ4.Ȓ^8X]׸`<8tyOnb*K6?5{M˻hAy/pEn?#tV/tXoW {ܑCBBBByqiyeum}9Rn.[k~ik.az/o|>ۤ^P?g>ۉxV! oll!G)? n*)]R;2 2_h#ɻ:ov:-UAHy:Eo/~݀w=-pGo&5|`KK{ӶS/^ݢ?;N` a,o!nz9>[|Vi9NJaNZ+w؏жHxcb'xOYn|GYr޵Ÿ^-uqAzNH:ե.+9e9`9l E140Hdd2*HQ'-[X[/MfIDBFh B!6!nhܝq =w)fwXd_z)ЕY;&X1uУ۾WfVdUɓ'oJ Ct떛t߰bӁͿuLN5iݞ}gA7L"t'\K9,W$%360B}J,3qbyJL_l<_]6O? nV_nlk^qIA#r,6Sag Әk){WUsW>N@aW--Þ{u[|lo+ܲ六dݥEOrG^sXːjeʄұ]r3m_B!v?L'UOd+ѳ k4PA'(/H +zVʠqVO'yR.Og7+sBxIU[{݉DPޅwQg38 mﵽ[Qd4UƍܗA|tY-v+&3b' dM3 6da]Q֪ +V+=gۍ}uڌ (~x~IB^2Pg#}rel,Ők`iF]&D?it-XW1N-GLVe_($~~K5ўM-=fHG3,V=݊o%hhV8oɷKq))-| +taqiyeudhhjjzu% KтiPȚn6ZZ\yY=k\;aSSG5xŭh-U1CF h[4HC}+k~"i,TB"SƠ.LuV"h=fZ0R ~0B}.mBNqG >OG Bdч80LLyA[r'6x^8&8Rw$}J,3{Wy*|_˕!q-4޵!˻rr}/4D +Rvv/xG7Kq2я yd:F lp + (Kl F ~^%u(*nE $sNO?BJWo䯇W+_0rW_wn-vNPfzv;|96k6O7S AȢ~[-_wpB NJݢ5P QJ`0D *GE?K-݂d* C{* t ?7ydBоX&8`pJ8CKplf00Ĺ&.@o088[F zΎġmZ tb#<ڄ_Ϣ} 34h20Zp>G/]O|{ß n6J`ע")%rv;G!֎Fnpy$# Gl@ eɨCc~\E^z^#jWb;)G:-]o6 9U=yF_Z1\^pKulQ=K>۝vgsǮ{\:} |6ߟ p<e`Z༠AeAdB=ͰIFRxiZw\!鿁EE|~/(&^}'y1z $z!COZ끞kHZB2Y#;]6jؾѮ@!\uw-]F=GQ_n.̯j39g  ,ÛɡuXS9ǩ+5RzG4=Uɥ_Wy,Vztܣicq>vL5^%5݋%\ro1?pO>[AhLfx,[;#0մ[M1P{{)r] +ok[m FXs`VǡhR*RY:7}tΩLz<1g?1:k Ndv0N#0jGR9R4A&Tax!,tso•yT.62X5Lgv;f]#o;4XޱJp8קL۹!yNm;gh3 h^x$o;vOْ::sͰc-fه滵9Q笷ZXӞT<=3v*O<\c|XXK+ yF 7?BߙVx2_z2F_-{>ٰ](7e_]Ks|n5:x8f c +:a^y-#ƔָUu$wݘyAMA$zPLNoWAYEՕԕԩQa$w|B]Ii]L]Iz$Ա+u[׺E.is-_.ɨkuՍLuI*8]e}7W*|Cc2ʤǪL?QeRmU& jNڑ|SjGwjGv$oD{kG^'T|:WigU|;giS +MwQGA㰻^V5٭}ҭDZ2rv\/Gll륌1F)YUY][RVWTRKfy6y괍tJ  xr'wޏ0ry\V,K,,T,kkZuaY 8V=$^T ++*U%5Сrj-pXP2-+򩨨rf4g j:pYšʢBO.,YRQ[X)-B 8IuIUueq]Q S\O-a8]:ăf3LfזU23=5VغhȉWf0e 5eƈgc&TV+5% h]zȿahb5fb}Ci]u X;W*5JM%E r(#Q3Ps\Y%M8JPQY bў2TuhN)+1CZVR؅ +ЋjefeuMVjV@4Y83E+Q Sha5U7ZfԔOhLl:1 -, 5Gb e3pxxU̘wRsS]Wļ-adrG \I54Fh66 $鱗%`I jȀdVey;b%sjbª*0©3J v.*e5 OuhwRWQAU#QCR P؊aUa]Ӏ0ÊJ?T]((eHJWFdg*GNLdWree ODxebF +dPR1YI9Ǐ)cs23YFְ 3F*i/+;W @syW qFmjZFfFn~<"#7 `rT%'u\nư 㔜 rǧ6+#k8%}l:e9*7:x9w\+,H&KGff*isǥemwFfeMGdO)in@ʰԌԱ#9AX3vȬqa1.}X.o NdrtegOuoWLrES&_2ɞI)|cʤIiʤ3)7vt6C;uOʎNv${#dGrHIّ|H9S.Ҟߛ(D#pGO'4n4Ƚ|g0#Ί^/ZϺ7 fUPjNIMF7B_SU'6^I߬_[W*_ZK{S/Tzq|p*J?H?M$Gyhx~<ëJ蟝uJ:3?hzHzj$= JDVT[F'ѷox(}3זׂ髾J_Q*}IGTJ_P*=TzNGUsbJ=0E|9"Sh_ϬTJ))OF铻tw^;TJtnUYǓch1m&n~$nV#&qS1}xM|8n 2}Hי*]gMЩi]"FXWW) GSh[?ާU+{Tȼ7XnW8r#m Ŵ8UM/Ut]\%vXTPX@J,.q~4ҹ*cMtLTZ{\WWiJ+UZ.Nr-T%*-ViJp -J0)*MU?II2 NLy*#OH.:t:GU9FҬ61Kcm4Scΰ}hFY̰Qf:R#utJⰫ49:U:TCnqCV<,v_Af:P)*)J__FiPlIbJ{ibQL4# ўD{t{q{4snbTMcbFiJ#Ua@g*4* BiUt P1N:PJ*Q8TjZiԶZEfhV Z|QTfzT*@\R'=)QR܂݇{!a/5endstream +endobj +11 0 obj +<< +/Ascent 759.7656 /CapHeight 759.7656 /Descent -240.2344 /Flags 4 /FontBBox [ -1020.508 -462.8906 1793.457 1232.422 ] /FontFile2 10 0 R + /FontName /AAAAAA+DejaVuSans /ItalicAngle 0 /MissingWidth 600.0977 /StemV 87 /Type /FontDescriptor +>> +endobj +12 0 obj +<< +/BaseFont /AAAAAA+DejaVuSans /FirstChar 0 /FontDescriptor 11 0 R /LastChar 127 /Name /F3+0 /Subtype /TrueType + /ToUnicode 9 0 R /Type /Font /Widths [ 600.0977 685.0586 589.8438 549.8047 634.7656 698.2422 549.8047 1000 600.0977 600.0977 + 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 + 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 600.0977 + 600.0977 600.0977 317.8711 400.8789 459.9609 837.8906 636.2305 950.1953 779.7852 274.9023 + 390.1367 390.1367 500 837.8906 317.8711 360.8398 317.8711 336.9141 636.2305 636.2305 + 636.2305 636.2305 636.2305 636.2305 636.2305 636.2305 636.2305 636.2305 336.9141 336.9141 + 837.8906 837.8906 837.8906 530.7617 1000 684.082 686.0352 698.2422 770.0195 631.8359 + 575.1953 774.9023 751.9531 294.9219 294.9219 655.7617 557.1289 862.793 748.0469 787.1094 + 603.0273 787.1094 694.8242 634.7656 610.8398 731.9336 684.082 988.7695 685.0586 610.8398 + 685.0586 390.1367 336.9141 390.1367 837.8906 500 500 612.793 634.7656 549.8047 + 634.7656 615.2344 352.0508 634.7656 633.7891 277.832 277.832 579.1016 277.832 974.1211 + 633.7891 611.8164 634.7656 634.7656 411.1328 520.9961 392.0898 633.7891 591.7969 817.8711 + 591.7969 591.7969 524.9023 636.2305 336.9141 636.2305 837.8906 600.0977 ] +>> +endobj +13 0 obj +<< +/PageMode /UseNone /Pages 15 0 R /Type /Catalog +>> +endobj +14 0 obj +<< +/Author (anonymous) /CreationDate (D:20260505082323+02'00') /Creator (anonymous) /Keywords () /ModDate (D:20260505082323+02'00') /Producer (ReportLab PDF Library - \(opensource\)) + /Subject (unspecified) /Title (untitled) /Trapped /False +>> +endobj +15 0 obj +<< +/Count 1 /Kids [ 4 0 R ] /Type /Pages +>> +endobj +16 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1375 +>> +stream +GauI7>>sfX'SYH?(&QC"k1K=oCYH7jW#QO3+^.g/01"V,f/OA5Wql=o'2W.t0p.&"K+Q/i0<;_Z?3LD.#Nj?VF+@9sbu4`Z&3^(DVBEO)G1^1NJI,^^5l+!'5)&;1Q!bN$EF9f"ShUN0S0Z$koM:a1)!5BR#Ns^@6ODBC90_cdNrOtP^5(+gVkF<1IR'YlT$?bqG)^qCs9M\PVtED[QW.Ya6aCDor=,Cg[/m>4X(HTF9$`beW+)7&;oMgp7/P:GQLGaUe[dSl92UV,hMbC"fEEG%7r)GeMX23-`=l:qk&$W5gncD0:[9rc/c-T;H+ccCROFnIhZTP7W[#nMI7-K^gm?Ss!ZcUJFNk9FF)erl?YMr4`?`E5ia?PSL4BR@nW_J&N:o*[[Bj--gVD52e\`S.X1`K\ie'$R-lX[&DdsMdq[cWSM9I!1,`Q0'(pm/,R_@H#H%E3cqCn:7D,-kJ159-:b`gG![RfO7MAB.eF*fU"7T$ML)E-@7dkYh7_L=:Sq7#8H`#%YPj4&UgM_DFD)=lCNpITb+P(.KMp#L_7T&C\8(MVJeD+D]:)SX8=,*cc30]&BgM\M[Qe@WjSOubgm'>($`63hQGhu8\`,,jfXD9@ItQD'#d5,0F)pE!K@($0hpmOGRL:5-M5]slLC*\pnKEYk\Y%Fn(IE+c/H!cG'g;?==6C-g".'Nj1O;[Z3t$VoF3V3VJ8m8HXmlIMr2Jp?&";T68ke0;D4ejs^DWN07UYsf>AqC)1-8$;DUBaZG?hpW)3c/[_sokdKSQ5M9L`?[X!V_r6Z3_f$N4<)30,(:Ftendstream +endobj +xref +0 17 +0000000000 65535 f +0000000061 00000 n +0000000117 00000 n +0000000224 00000 n +0000007324 00000 n +0000007592 00000 n +0000008344 00000 n +0000026611 00000 n +0000026879 00000 n +0000028230 00000 n +0000029002 00000 n +0000048189 00000 n +0000048448 00000 n +0000049782 00000 n +0000049852 00000 n +0000050114 00000 n +0000050174 00000 n +trailer +<< +/ID +[] +% ReportLab generated PDF document -- digest (opensource) + +/Info 14 0 R +/Root 13 0 R +/Size 17 +>> +startxref +51641 +%%EOF diff --git a/_data/uploads/placanja/putni_nalog_4_HUB3_20260505_082323.pdf b/_data/uploads/placanja/putni_nalog_4_HUB3_20260505_082323.pdf new file mode 100644 index 0000000..6884d4d --- /dev/null +++ b/_data/uploads/placanja/putni_nalog_4_HUB3_20260505_082323.pdf @@ -0,0 +1,97 @@ +%PDF-1.3 +% ReportLab Generated PDF document (opensource) +1 0 obj +<< +/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 5 0 R +>> +endobj +2 0 obj +<< +/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font +>> +endobj +3 0 obj +<< +/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font +>> +endobj +4 0 obj +<< +/BaseFont /ZapfDingbats /Name /F3 /Subtype /Type1 /Type /Font +>> +endobj +5 0 obj +<< +/BaseFont /Symbol /Name /F4 /Subtype /Type1 /Type /Font +>> +endobj +6 0 obj +<< +/BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 294 /Length 6814 /Subtype /Image + /Type /XObject /Width 294 +>> +stream +Gb"/b>F+S/P/Lu4S*jFp4l&k#Le,ZWHo'e/q`k+k>V;Adj`7n:/sjcCEk,F-QcnK2\QgbRbN3cT>V;Adj`7n*q7fp3_Xj7#$$3e#Go.2Jf$knqoX#D#C:C1-0\7hALGA=.9eCB[:M[eLG+2YAF1lU>(_\RRe0]lJB8'/.qd,1lIo(@5eFWKf0h/!l#GnR>3ERSA:^Mrh4H-KLD4m\a>FEaHN.JpHb_=siqpA+^X7XYmJ^99jHO`RVd2#t?GFm>H0tT7-KLD4m\a>FEaHN.JpHb_=si3+8=gma3Z=.LW7eJ9]sj_jas1-aO/GAf+b>]l5!='MmkQFk\jb5?&Xhn?R&F4Ek!?Z!XM=RK3C/+^(VI.uc4buH+tJ$fI'A%>gWXN]!KnD0Rl2-6=or7)Q6O6(9PZ8+Z!^is]Lem*?\n5igr?<2:9.[Q6:ri4Nfb_u#2(7(<;h7C`TA=UE7[0H53]Wm1PATbJbEX^=V9F6C@825]k?T`VNRM&b02%`+C;QG=`m22&ef'i0o4!!H(@:@WQI*KhB2'cAQ?(I?Zkb3Re`-2(kPjKM*NQfKh"3Y0"j:D`q#'Hgs#A%0]hW@ZnlRJ-s*F)tcHri->KT[Ddort<;=T)4R)FKFnrEms?](+bNsiq'A:ro4D-X1P4`oO8bCYbq0>IFIB:4H.`mgc+uPr(WB)o.WpTESoP1o/BDCc,2NC`I2gbbhk8Q2\4rU(AH(%1Omm7h`QkH>22(2c2:;"J+NSLXMo3A>KT`k2uh]^2^.e(Cghb@gb3+1pH3HQ9ust">?Kc>pIj0;4\sjW'/Hc7(=kFhr=X:'cP-'/KZrbfL%S/]^P(G#o>H&9+nN9]@=?V[04FVL4E97QaLp@8ld!3e]@tMnlZF,0m^p.Zm]8hjQC4k;gG"sAfBY7?h043?gf]O^/2LKT[p^mbY1IA]]'o?]\?crF=D#!2DSo_N>d)VDFPlICEG$klYfppCgkN@%\R)0gl+Ynfim(^a@@>de\IEV*EkP4XdXAUV`1=:qNTM/1L>RI)GqZ4PQ%rp_m^^Q-:@:i?g`"`YbKP98/Z_&c1NUlR[WHP.RcN&(Y#o;ebA(JI@@$-&PB',].D!C$;1s)k.?*VVTQdrsq__O%B>\6VVpVqf-T9/A&H"2!C.IXEJ?1$q<]QWm#=:=GSeNKhC]7tI9X-a2SSFZ(df%$ouc>,?LK=.r?=P\&@]5(MM]/hsUh)l+s_Ko^7cRJ=c@9r9cjLf[-0N\_KNR^1i]Xro@[B#M_b2ol@SsF#0e^U!8kLO%FmT)YIfm8k">&6.DjJo18;9l;[@,7rG-'#q]`S9b(sDh)pn%VTqRi[g%J-[h;leesdZ1@_6n4=BEc)SJQC5FS>ig&Y=IqH`T'55JmcmK1)([Rj1V(Zm=Kjo+bWO:p-/@%=-o4t;p1A?1e$3;+hO&S_P=rEd1JqbgbjqjZ1SV/S6a-3c,ti_GY!ZfUL@&=J"!sfjY^1YLE2R/M(JaMnM-qMreZa>7"F?l`/V^kFU.2Djk"C2bdkAcb%M2b*/la\SARo\`\(eS#09T9iKa)oBnE%o&Qh(,3PQH@;hT@\Mm5oMpK#]@*4\6ArE1+:5?MsHKF!?Q'qLPWs/*(]i^l^X4*HC?u)u*Q88&@I(S7!I4R&&MriX*3fQ]=[K_(g.5NWs\*H31a7<]Q=J"?Le!RLMCToa`1@nt&]AAa"/2,S4jk7=.NCaMd#('i/1G?bWlTNqAnm]:7T&$HrR'^7:YW%k'o4!*ZhNN@=0@l'CftBG+8IMs2HXeK\08jcCSPd/'$*C8`)ht2ZgF&>cfq#6RnSCk5q]qkXQ$^EQP]Q`_nhdtb2(Y>9l$&aF['"Ff(m]2[T3Rt"GIE7FZRu.DPD%LemL@'3cL$h=e*PB2Y^!UQhgL[7]#q]p=N\1&Ed=,0fbuk^Wu(BMjfu$F>:jkV/2PIZ?!1rFYf1W%2Y1$QRB75b*L<,TZ*(/c/D+FB%@_VoXNX_'S.<`dnlSuE)A[.ogkO'9(05%J78AVLApLI.CCLZ[=Dl#g*XaL)eKUp/1:'*oQ*l>M>:d6l1QR6TfkQYu@@:7>lcNC@(TZ0UpL8%X:RY%_1,H#Um#=H:(Mha#fkXZ7dWC)+R:0Z=D_,qB=OSVA?G"@DVA$&T$nF,\A!-)rRPnmRg/X_$SR?#@=IIh]Md.pdZq7UUY4ACQ"=l:Gb08^EjEe).3M,Wf_!9I_b&RD!':g*o@?]gl%'*J$.`_@#9QY%j>\:E?o.&@Ml0Ka-)`Cp)KZlTG0UJ3pe%Eir@QM+-fnR`e/0T)\--Tq4q_YKs]pR)_6FL=/"\ZqlEsZoUffmZ]>VDt\RuhL>Cr$`>GF">uY^/1a1n-CM:#7REm^_br2&KAPgg[fQc)/`lP;eGjH`h^5%>NCW[oi&mZY?btj:*?sT'MtPK421//XCb4Cte55H,I_6kITj-?s#"$MriePRl5UfhCs!<\aI!c(flRM@_"GBVTiG22iO8RY'Y$qL6ZCQBoO0oL6C6<;ce=#Z>@C]V>=Kl_kb[^%XRTed@2K^?.>?L=E4r3Kh2"OiHYbi2HVG3W'c5)_X[>tLg($,Po*QsB&Z'9;k>:l;dP;Q+iLV7C[IH+csjkS-^Ml-&UNRRT0DjjDX\6)Kd\$OVZWB=>D[!gSrB%&[kQ;c)rCpdq+:Y%LB+82SboSndjP]Joj/XjhG2,;n]]kKBQj'k%1gs/rYVXe8We+R3gXJT(^J*U4oMnNieR9WHo/M(#d**0qkUGGcm]kQVs>YSTX/6M$SYSTX/6M%?-7s7R=;tEMX^8Q8bU_:snO@_\8Y00?CCMefeLT79H0&3`hWSi3acl%%X^NN_HKCSNY?VIT)r3(mH#gU"26;I3Y?Y#gQ#"3\UV"Jj:Tg%lL6^-NQ#"OTE\/,HFLRXuan;sjYS(-QE_Vs'Xp*jFmPuU#=c:c&aa%%&XMrg2$Yr+qR41):AY/8;>U/ECos,?CD_.t!=_=Pd,aWe^:NMMcQds8_N4lL#2Ir5DEg'bjaZds,EaDd"CGGP&_V1)_B$*hgR4%kgf>r5?]r]3*)[gFKQC00\a^q(1dp+-\AbE>E@rEp"%9[;?Hs1-_7C,'kRd4PHam&0'kEJ2\5>!_?o85!'VR^#6St+*/HVXD.pS0PY2QrK'CRXR#jiQcR]'#;BIm6O]@Io@*Z_k9>i,Y'Wq>oCo":'/m%]12E?EA`_%um(2AE5CYmi1L]m4.C5n^?<3YfcE;Lhq=F?U0X"aUVUmHO\&^G7gm]m=Q'ltT1OEVWm:(L%>Z8hZfj\$N\Ml=N2jW&Jf!i^X[G76'G*SJB1GaAfH0o'hMd03(^"HjrRCP74ZT"3%0%RMQ27;5//U!DIHS[I)@sRHNI>_?/bIuS<=4q?210_n%M]=9V0(VK!\QbK(KY+9gYjUk8]jWL5Y_9R2'4pY%keaZRba([E-/sjt]_sRCea;9";L5"maI:fGiBc#>:H-4Af_YRCQOiXb=-RG]MS3FMEj15-bS+RMDIp6hm]O]GH;31sbS+Qb__PH0:>&Ejo`M_e=?jgo\d6AZ!@#>J3eda)\Y&m_`^a:#)kp'4n&Y10_FegW+?DB^WcOH;31sbS+Qb__PH0:>&Ejo`M@q"IZs(\;"mfeWdn_XG"+nS*mnVcbGq4I(S5KXJQEgAL5Q;fQ?#qI/_YakM,[$?o;LL0.UIK_l!c'3o@+7"KNu(H!(Gp)`HMr1S9.SdJ7t!-Wj(\bf`VGgT]qf'!eReFI8D[a!0\a.H`UrP]I-K\M\PQR$X)Y,3Nhmk;K]3EsW_p20O,0Q^,T8kADa32RJ]i#oU92G'01=Q,b*3DCOa,[$5V<)7_VJFdSM\a!0\a.H`UrP]I-K\M\PQR$X)Y,3Nhmk;K]3Es[&)G&QYJ=3VKoGK+NE$^U;8E^#\?eileKl`/WIim-3DDSZrL>L$lEd+YCs@pLrr9\^Mth(;aGB?U*E&mG/hFf_WUMhsN*\%;f:phVs_8O@3bVN,fLCb]pBluojG$(ig41J)9Ie'tY*ROolSN8FCs">+'T(>40Wcer/cpmQ$ZHQ+=H!Q$Kj.!R9;1d`Hj8?4:J9EL".]_L8C)DOsd`+[1Bml.6h+\DIHuHb,o+:jI##M/S=CfY&_Z\Qa0gt=M8`j=?8GhH#egGqlm,ko$aH%()BrSg_uJRN_,ht@b*a0.]<2d.D(:feLS+`V3>DP-b#JN&%ft55@)EL@:AiOX^UJTR,kN=3sE&^mOFRVnm^[E/ZaB%*MGIA%*_q\D3?*D@Z9RE7\m2R$B\pe]_jCZ*&-8C`esu\[-t$?B`@0bW2k=B'YG!Q#gU8YWU.#-"JTr]pOi1K&pG//>73OC\l&!/?FLu-^QjFK&pG//>73OC\l&!/?FLu-^QjFK&pG//>73OC\l&!/?FLu-^QjFK&pG//>73OC\l&!/?FLu-^QjFK&pG//>73OC\l&!/?FLu-^QjFK&pG//>73OC\l&!/?FLuVtjp@p+;Z;jkdYUf^36!2nS80m)$I?;mtJNS?h7qaE^pH26X)f3LY4E0=H7'g%&V5]WB)@=&uLEhgP`q8KQG,[nfr5\X5gl7BWWODWS-jjC'W\q_XS-Mchl@jI09?MY,UN#jft36@4cNs1mOPg=Ys@DRTf,[*fET2efqS!;n9H+7C,FcWTA$ZZ'aT\/TU_FQ(*\71gB%0>4.a#j`7n:/sjcCEk,F-QcnK2\QgbRbN3cT>V;Adj`7n:/q9)b#M`#Je,~>endstream +endobj +7 0 obj +<< +/Contents 11 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 10 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << +/FormXob.890ab0d0d01d65a31588b0bfaa0b92c9 6 0 R +>> +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +8 0 obj +<< +/PageMode /UseNone /Pages 10 0 R /Type /Catalog +>> +endobj +9 0 obj +<< +/Author (anonymous) /CreationDate (D:20260505082323+02'00') /Creator (anonymous) /Keywords () /ModDate (D:20260505082323+02'00') /Producer (ReportLab PDF Library - \(opensource\)) + /Subject (unspecified) /Title (untitled) /Trapped /False +>> +endobj +10 0 obj +<< +/Count 1 /Kids [ 7 0 R ] /Type /Pages +>> +endobj +11 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1406 +>> +stream +Gb!$G>>O!E'Z],&.?:bgZt^t0*tN9"":1+-F\K3#nm[5;+W%I3[*jF"4h`2HU"P.>Zl@%/N1r,CF66a,1'e`c)Bj$=j?11;]bM[45sIX9FN)Cae:YlcO]W$s4**9g8'reAQ3Qr?-VE[j(o(/q,7D4hng('(&[Sq7XMSImEP:$+H5`2Z$oD9)q2SfDEQ`E5K-1X\Li7NOVdS)j:G?YN$+#'8%)Q!e\:/?9qm4#%]fWOqum4bf:GL$2b7/=A0Dr.AYD=L`8s%P(1U0(_;@r+2I1^hJV7q2UJR/.Bu;U_-qqD;A-QBI`:sY"g'a/b/g:bonUTDbPcHW;*uU?H6%+>7sGoCZuD7.L\->]hH(Q(d.)lU="%:b]/L%4#VmiliQ]K>?F=bb@$U(f,`@MkX2qa;96&<8VF#pSKr@&r4ft#K=GHG.%fVQFjfj8UF89XN9XrN_k05lu9B2tfp/d/lK0.bL@/Z.jW65m?fJ+p8,&Ag^McT]XXHjUD/_%`Vok[_9trh+\tmEI/OID85++5.j@<#qH_Jg&l>eOEm0ik0f]BLtW8g2o]rlTuT4%h5s[)CqWq-Q]H_(!3(BMs*^PV^tb9Z,!\DdlSX2CcC"C).LKjuoLVMACfCYC;&pi]'I!*mh"\iY7lAQ0LN?(NUG0A._OM0;c!m9?A+&?8]e.[9!gG8aXJn1nu,$n"IF^^m8D_BiKH0J/d*H2<9M"=,m-%Bs3tX^JfK!C5L?Tq3BZl=bT_G\gd0W,8CnZPkU2.EMCfljYX)'J*Zr;qoJ4B:Z&g1pnmrpQhU"n4I2"=DU"=`R*MW![#?*)ONjp$6h:!D)]h%.BlXaKe!kM_-3[Q(43GcC%Q[,#D+ZgINe1GJT_/hdpp-t~>endstream +endobj +xref +0 12 +0000000000 65535 f +0000000061 00000 n +0000000122 00000 n +0000000229 00000 n +0000000341 00000 n +0000000424 00000 n +0000000501 00000 n +0000007506 00000 n +0000007774 00000 n +0000007843 00000 n +0000008104 00000 n +0000008164 00000 n +trailer +<< +/ID +[<810caeac168f23cd3bade25196ed4788><810caeac168f23cd3bade25196ed4788>] +% ReportLab generated PDF document -- digest (opensource) + +/Info 9 0 R +/Root 8 0 R +/Size 12 +>> +startxref +9662 +%%EOF diff --git a/routers/debug_router.py b/routers/debug_router.py new file mode 100644 index 0000000..aaea6e6 --- /dev/null +++ b/routers/debug_router.py @@ -0,0 +1,170 @@ +"""Debug observability dashboard endpoint.""" +import json, os, time +from pathlib import Path +from fastapi import APIRouter, Query +from fastapi.responses import JSONResponse, HTMLResponse, PlainTextResponse +from typing import Optional + +router = APIRouter(prefix="/api/debug", tags=["debug"]) + +LOGDIR = Path("/var/log/pgz-sport-debug") + +@router.get("/health") +def debug_health(): + """Quick service status.""" + import subprocess + services = ['pgz-sport', 'pgz-debug-tail', 'pgz-auto-triage', 'nginx', 'redis-server'] + status = {} + for s in services: + try: + r = subprocess.run(['systemctl', 'is-active', s], capture_output=True, text=True, timeout=2) + status[s] = r.stdout.strip() + except Exception as e: + status[s] = f"error:{e}" + + # DB + db_status = "unknown" + try: + import psycopg2 + with psycopg2.connect("host=10.10.0.2 port=6432 dbname=rinet_v3 user=rinet password=R1net2026!SecureDB#v7", connect_timeout=2) as conn: + with conn.cursor() as cur: + cur.execute("SELECT 1") + db_status = "ok" + except Exception as e: + db_status = f"error:{e}" + + # Recent errors count + err_count = 0 + if (LOGDIR / "errors.jsonl").exists(): + with open(LOGDIR / "errors.jsonl") as f: + err_count = sum(1 for _ in f) + + return { + "ts": time.time(), + "services": status, + "db": db_status, + "total_errors_logged": err_count, + "log_dir": str(LOGDIR), + } + +@router.get("/errors") +def recent_errors(limit: int = Query(100, ge=1, le=1000)): + """Last N errors from errors.jsonl.""" + f = LOGDIR / "errors.jsonl" + if not f.exists(): + return {"errors": [], "note": "errors.jsonl not yet created"} + lines = f.read_text(errors='ignore').strip().split('\n')[-limit:] + parsed = [] + for line in lines: + try: + parsed.append(json.loads(line)) + except: + continue + return {"errors": parsed, "count": len(parsed)} + +@router.get("/decisions") +def triage_decisions(limit: int = Query(50, ge=1, le=500)): + """Last N auto-triage decisions.""" + f = LOGDIR / "triage_decisions.jsonl" + if not f.exists(): + return {"decisions": [], "note": "no decisions yet"} + lines = f.read_text(errors='ignore').strip().split('\n')[-limit:] + parsed = [] + for line in lines: + try: + parsed.append(json.loads(line)) + except: + continue + return {"decisions": parsed, "count": len(parsed)} + +@router.get("/stream") +def stream_tail(lines: int = Query(200, ge=10, le=2000)): + """Last N lines of full stream.jsonl.""" + f = LOGDIR / "stream.jsonl" + if not f.exists(): + return {"stream": []} + raw = f.read_text(errors='ignore').strip().split('\n')[-lines:] + parsed = [] + for line in raw: + try: + parsed.append(json.loads(line)) + except: + continue + return {"stream": parsed} + +@router.get("/dashboard", response_class=HTMLResponse) +def dashboard(): + """Live HTML dashboard.""" + return """ +PGŽ Debug Live + + +

🩺 PGŽ Sport · Live Debug Dashboard refresh: 5s

+
+
+

Service Health

+
loading…
+
+
+

Auto-Triage Decisions

+
loading…
+
+
+

Recent Errors (live)

+
loading…
+
+
+ +""" diff --git a/routers/enrich_router.py b/routers/enrich_router.py index 64152dc..5ed7882 100644 --- a/routers/enrich_router.py +++ b/routers/enrich_router.py @@ -1322,8 +1322,17 @@ def _apply_to_db(kind: str, eid: int, fields: dict, sources: list, user_email: O params.append(json.dumps(meta_in, ensure_ascii=False, default=str)) params.append(eid) - cur.execute(f"UPDATE {table} SET {', '.join(sets)} WHERE id=%s RETURNING *", params) - after = dict(cur.fetchone()) + try: + cur.execute(f"UPDATE {table} SET {', '.join(sets)} WHERE id=%s RETURNING *", params) + after = dict(cur.fetchone()) + except psycopg2.errors.UniqueViolation as _uve: + # Race condition — fetch existing row instead + conn.rollback() + cur.execute(f"SELECT * FROM {table} WHERE id=%s", (eid,)) + row = cur.fetchone() + after = dict(row) if row else {} + import logging as _lg + _lg.getLogger("enrich").info(f"UniqueViolation race avoided table={table} id={eid}") cur.execute( """INSERT INTO pgz_sport.enrichment_log diff --git a/scrapers/wiki_hr_categories_fixed.json b/scrapers/wiki_hr_categories_fixed.json new file mode 100644 index 0000000..39f684f --- /dev/null +++ b/scrapers/wiki_hr_categories_fixed.json @@ -0,0 +1,31 @@ +[ + "Gradovi_u_Hrvatskoj", + "Hrvatski_otoci", + "Planine_u_Hrvatskoj", + "Rijeke_u_Hrvatskoj", + "Primorsko-goranska_županija", + "Naselja_u_Primorsko-goranskoj_županiji", + "Hrvatski_političari", + "Hrvatski_športaši", + "Hrvatski_glazbenici", + "Hrvatski_književnici", + "Hrvatski_glumci", + "Hrvatska_povijest", + "Hrvatska_kuhinja", + "Hrvatska_kultura", + "Domovinski_rat", + "Gospodarstvo_Hrvatske", + "Hrvatski_nogometni_klubovi", + "Hrvatski_košarkaški_klubovi", + "Hrvatski_rukometni_klubovi", + "Hrvatski_odbojkaški_klubovi", + "Hrvatske_političke_stranke", + "Rijeka", + "Krk", + "Cres", + "Lošinj", + "Rab", + "Pag", + "Učka", + "HNK_Rijeka" +] \ No newline at end of file diff --git a/scrapers/wiki_hr_scraper.py b/scrapers/wiki_hr_scraper.py index 5811c6f..5de8823 100644 --- a/scrapers/wiki_hr_scraper.py +++ b/scrapers/wiki_hr_scraper.py @@ -18,40 +18,35 @@ API = "https://hr.wikipedia.org/w/api.php" # Kategorije — širok HR knowledge bazu CATEGORIES = [ - "Hrvatski_gradovi", - "Hrvatske_općine", + "Gradovi_u_Hrvatskoj", "Hrvatski_otoci", - "Hrvatske_planine", - "Hrvatske_rijeke", + "Planine_u_Hrvatskoj", + "Rijeke_u_Hrvatskoj", "Primorsko-goranska_županija", "Naselja_u_Primorsko-goranskoj_županiji", "Hrvatski_političari", - "Hrvatski_sportaši", + "Hrvatski_športaši", "Hrvatski_glazbenici", - "Hrvatski_pisci", + "Hrvatski_književnici", "Hrvatski_glumci", "Hrvatska_povijest", - "Hrvatska_arhitektura", "Hrvatska_kuhinja", "Hrvatska_kultura", - "Hrvatska_znanost", "Domovinski_rat", - "Hrvatska_ekonomija", - "Hrvatski_klubovi", + "Gospodarstvo_Hrvatske", "Hrvatski_nogometni_klubovi", "Hrvatski_košarkaški_klubovi", + "Hrvatski_rukometni_klubovi", + "Hrvatski_odbojkaški_klubovi", "Hrvatske_političke_stranke", - "Predsjednici_Hrvatske", - "Premijeri_Hrvatske", "Rijeka", - "Kvarner", "Krk", "Cres", "Lošinj", "Rab", "Pag", "Učka", - "Risnjak", + "HNK_Rijeka" ] def api_get(params): diff --git a/scripts/auto_triage.py b/scripts/auto_triage.py new file mode 100755 index 0000000..a7adfcb --- /dev/null +++ b/scripts/auto_triage.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python3 +""" +auto_triage.py — Active error monitor za pgz-sport stack. + +Tail-a /var/log/pgz-sport-debug/errors.jsonl, klasificira greške, +i automatski dispatcha tasks na CC agente kad detektira pattern. + +Patterns: +- Recurring 5xx → CC4 (backend) +- 401/403 spike → CC2 (auth) +- 4xx na specifičnoj stranici → CC3 (frontend route) +- DB connection error → CC4 + telegram urgent +- ImportError/AttributeError u pgz-sport → CC4 dispatch + restart attempt +""" +import json, os, re, time, subprocess, sys +from collections import defaultdict, deque +from pathlib import Path +from datetime import datetime + +LOG_FILE = Path("/var/log/pgz-sport-debug/errors.jsonl") +TRIAGE_LOG = Path("/var/log/pgz-sport-debug/triage.log") +TRIAGE_DECISIONS = Path("/var/log/pgz-sport-debug/triage_decisions.jsonl") +TG_TOKEN = "8535797835:AAFItT-92jzZ9NWFafLxn0dLa1_n2s-JE5Y" +TG_CHAT = "7969491558" + +# Rate limit: ne više od X telegram poruka po 5 min +RATE_WIN = 300 # seconds +RATE_MAX = 6 +recent_alerts = deque() + +# Pattern counts (sliding window) +PATTERN_WIN = 60 # 60s window +recent_patterns = defaultdict(deque) + +def log(msg): + ts = datetime.now().isoformat(timespec='seconds') + with open(TRIAGE_LOG, "a") as f: + f.write(f"[{ts}] {msg}\n") + print(f"[{ts}] {msg}", flush=True) + +def telegram(text): + now = time.time() + while recent_alerts and now - recent_alerts[0] > RATE_WIN: + recent_alerts.popleft() + if len(recent_alerts) >= RATE_MAX: + log(f"RATE LIMITED telegram: {text[:80]}") + return False + recent_alerts.append(now) + try: + subprocess.run([ + "curl", "-s", "-X", "POST", + f"https://api.telegram.org/bot{TG_TOKEN}/sendMessage", + "-d", f"chat_id={TG_CHAT}", + "--data-urlencode", f"text={text}" + ], timeout=10, capture_output=True) + return True + except Exception as e: + log(f"telegram fail: {e}") + return False + +def dispatch_to_cc(session, msg): + """Pošalji task na CC tmux session.""" + try: + subprocess.run(["tmux", "send-keys", "-t", f"{session}:0", msg], check=False, capture_output=True) + time.sleep(1) + subprocess.run(["tmux", "send-keys", "-t", f"{session}:0", "Enter"], check=False, capture_output=True) + log(f"dispatched to {session}: {msg[:80]}") + record_decision({"action": "dispatch", "target": session, "msg": msg[:200]}) + return True + except Exception as e: + log(f"dispatch fail to {session}: {e}") + return False + +def record_decision(obj): + obj["ts"] = datetime.now().isoformat(timespec='seconds') + with open(TRIAGE_DECISIONS, "a") as f: + f.write(json.dumps(obj) + "\n") + +def pattern_count(key, since=None): + """Count of pattern occurences within sliding window.""" + if since is None: since = time.time() - PATTERN_WIN + dq = recent_patterns[key] + while dq and dq[0] < since: + dq.popleft() + return len(dq) + +def add_pattern(key): + recent_patterns[key].append(time.time()) + +def classify(line): + try: + ev = json.loads(line) + except: + return None + + msg = ev.get("msg", "") or "" + src = ev.get("src", "") + code = ev.get("code", "") + path = ev.get("path", "") + method = ev.get("method", "") + + # ─── Pattern A: HTTP 5xx + if code and code.startswith("5"): + key = f"5xx:{path[:100]}" + add_pattern(key) + n = pattern_count(key) + if n >= 3: + telegram(f"⚠️ 5xx spike: {method} {path} → {code} (×{n}/60s)") + dispatch_to_cc("cc4", f"5xx detected: {method} {path} {code} occurring {n}x in 60s. Investigate /opt/pgz-sport/routers/ for the route handler. Check DB connection, log traceback. Run smoke test. Fix + restart pgz-sport + verify resolved.") + recent_patterns[key].clear() # reset after dispatch + return ("5xx_spike", n, path) + + # ─── Pattern B: 401/403 spike (auth issue) + if code in ("401", "403"): + key = f"auth:{path[:80]}" + add_pattern(key) + n = pattern_count(key) + if n >= 5: + telegram(f"🔒 Auth spike: {code} on {path} (×{n}/60s)") + dispatch_to_cc("cc2", f"Auth spike: {code} on {path} ×{n} times in 60s. Check JWT middleware in pgz_sport_api.py + auth/auth_v2.py. Verify role-based access control. Smoke test 3 demo accounts.") + recent_patterns[key].clear() + return ("auth_spike", n, path) + + # ─── Pattern C: 4xx on consumer endpoints (frontend bug) + if code and code.startswith("4") and code not in ("401", "403"): + if path.startswith("/sport/api/"): + key = f"4xx_api:{path[:80]}" + add_pattern(key) + n = pattern_count(key) + if n >= 5: + telegram(f"⚠️ 4xx API: {path} ×{n}/60s") + dispatch_to_cc("cc3", f"Frontend bug: {path} returning {code} ×{n}x. Frontend may call wrong URL or send bad payload. Check static/*.html for fetch/api() calls to {path}. Verify request shape matches backend schema.") + recent_patterns[key].clear() + return ("4xx_api", n, path) + + # ─── Pattern D: ImportError / AttributeError / SyntaxError u backendu + crit_patterns = [ + (r"ImportError|ModuleNotFoundError", "import_error"), + (r"AttributeError", "attribute_error"), + (r"SyntaxError", "syntax_error"), + (r"OperationalError.*could not connect", "db_connect_error"), + (r"asyncpg|psycopg2.*OperationalError", "db_pool_error"), + (r"FATAL|CRITICAL", "fatal"), + ] + for pat, kind in crit_patterns: + if re.search(pat, msg, re.I): + telegram(f"🚨 {kind.upper()}: {msg[:200]}") + target = "cc4" if "db" not in kind else "cc4" + dispatch_to_cc(target, f"CRITICAL {kind} detected u pgz-sport: {msg[:300]}. Identify file:line, fix, py_compile, restart, verify. If db_connect_error, check Server B (10.10.0.2:6432) connectivity.") + return (kind, 1, msg[:80]) + + # ─── Pattern E: Empty page detection + if code == "200" and "size_download" in str(ev) and ev.get("size", 0) < 100: + key = f"empty:{path}" + add_pattern(key) + if pattern_count(key) >= 2: + telegram(f"📄 Empty page: {path}") + dispatch_to_cc("cc3", f"Empty page detected: {path} returning <100 bytes. Check static/{path.split('/')[-1]} or backend response.") + recent_patterns[key].clear() + + return None + +def follow(path): + """Tail -F equivalent.""" + while not path.exists(): + time.sleep(1) + + f = open(path, "r") + f.seek(0, 2) # EOF + while True: + line = f.readline() + if not line: + time.sleep(0.5) + continue + result = classify(line) + if result: + log(f"PATTERN {result[0]} ×{result[1]}: {result[2]}") + +if __name__ == "__main__": + log("auto_triage starting") + log(f"watching {LOG_FILE}") + try: + follow(LOG_FILE) + except KeyboardInterrupt: + log("shutdown") diff --git a/scripts/debug_tail.sh b/scripts/debug_tail.sh new file mode 100755 index 0000000..b882238 --- /dev/null +++ b/scripts/debug_tail.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# Tail journalctl + nginx errors → strukturirani JSONL stream +LOGDIR=/var/log/pgz-sport-debug +mkdir -p $LOGDIR + +# Tail journalctl +journalctl -u pgz-sport -f -n 0 --output=cat 2>/dev/null | while read line; do + ts=$(date -Iseconds) + level="INFO" + + # Klasifikacija + if echo "$line" | grep -qE "ERROR|Exception|Traceback|CRITICAL|FATAL"; then level="ERROR"; fi + if echo "$line" | grep -qE "WARNING|WARN"; then level="WARN"; fi + if echo "$line" | grep -qE "DEBUG"; then level="DEBUG"; fi + + # JSON-escape + safe=$(echo "$line" | python3 -c "import json,sys; print(json.dumps(sys.stdin.read().strip()))") + echo "{\"ts\":\"$ts\",\"src\":\"pgz-sport\",\"level\":\"$level\",\"msg\":$safe}" >> $LOGDIR/stream.jsonl +done & +JPID=$! +echo $JPID > $LOGDIR/journalctl_tail.pid + +# Tail nginx error log +tail -F /var/log/nginx/sport.error.log 2>/dev/null | while read line; do + ts=$(date -Iseconds) + safe=$(echo "$line" | python3 -c "import json,sys; print(json.dumps(sys.stdin.read().strip()))") + echo "{\"ts\":\"$ts\",\"src\":\"nginx\",\"level\":\"ERROR\",\"msg\":$safe}" >> $LOGDIR/stream.jsonl +done & +NPID=$! +echo $NPID > $LOGDIR/nginx_tail.pid + +# Tail nginx access log za 4xx/5xx +tail -F /var/log/nginx/sport.access.log 2>/dev/null | while read line; do + # parse: status code je 9. polje (combined log format) + code=$(echo "$line" | awk '{print $9}') + if [[ "$code" =~ ^[45][0-9][0-9]$ ]]; then + ts=$(date -Iseconds) + method=$(echo "$line" | awk '{print $6}' | tr -d '"') + path=$(echo "$line" | awk '{print $7}') + safe=$(echo "$line" | python3 -c "import json,sys; print(json.dumps(sys.stdin.read().strip()))") + echo "{\"ts\":\"$ts\",\"src\":\"nginx-access\",\"level\":\"WARN\",\"code\":\"$code\",\"method\":\"$method\",\"path\":\"$path\",\"raw\":$safe}" >> $LOGDIR/stream.jsonl + + # ACTIVE ALERTING: ako je 5xx ili 401-403, log do error feed + if [[ "$code" =~ ^5 ]] || [[ "$code" == "401" ]] || [[ "$code" == "403" ]]; then + echo "{\"ts\":\"$ts\",\"src\":\"nginx-access\",\"level\":\"ERROR\",\"code\":\"$code\",\"method\":\"$method\",\"path\":\"$path\"}" >> $LOGDIR/errors.jsonl + fi + fi +done & +APID=$! +echo $APID > $LOGDIR/access_tail.pid + +# Drop ERROR-level u zaseban error file (agenti gledaju ovaj) +tail -F $LOGDIR/stream.jsonl 2>/dev/null | grep -E "\"level\":\"(ERROR|CRITICAL|FATAL)\"" >> $LOGDIR/errors.jsonl & +EPID=$! +echo $EPID > $LOGDIR/error_filter.pid + +echo "Debug tail running. PIDs: journalctl=$JPID nginx=$NPID access=$APID error_filter=$EPID" +echo " stream.jsonl + errors.jsonl in $LOGDIR" +wait