chessx-1.0.0/data/images/FlagGermany.png000644 001750 001750 00000000221 12153133357 020667 0ustar00niklasniklas000000 000000 PNG  IHDR(bKGDFIDATH1 4$")n|/[))} 422wJaujMIENDB`chessx-1.0.0/data/themes/outline/000755 001750 001750 00000000000 12234477214 017474 5ustar00niklasniklas000000 000000 chessx-1.0.0/data/themes/shadow/merida.png000644 001750 001750 00000326456 10633464147 021273 0ustar00niklasniklas000000 000000 PNG  IHDR4RbKGD pHYs66BtIME u8& IDATx]wTWm"E`^{Tl15Xb5آbkE,},3 "d9μ}~ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ $@ >Ȥ)@ $@~v4m^H $@ $@q^J .H m $qT"H IޗFI4,V-T*H1D"3k,H '8ߵI E rhIII0":EDb4tVM)dI <<ܑ&+`wﺈ@f@ $YjJQ G&k $WZܹ0B"J%;0VPRY32HF3as8 6`UdH '8$އڬ. F?"b$}.27LO!C{$|,BDtcz=ݺu6mDcƌSҮ]|_ HS>gҼHODԿd$o!%44S@2$wd0Y$2jL9٦@)~,#ޣF1|5KII)0̷ ,#"0J8&..ȻثW&Qx"y{{L6M6f`83|k"†_Z0L0kF\Z_$ ޓFƯHRqՕ4 ={[〃)9j|J?2&Kf06988Gz^^Ts2QnnnǬ0>LVC ry%X}Qh(J(PEZ=oNh> 'Nphذ5_|EJ&ׄ|r{{…r_LV4 $ w0`m&qOloJ,)))Zoѵ0kry"´iO?h4}|aժUڵ+jܹsXw6NNNd2Y;^eƍ`=$||G>h4~/>*T`q˗/QP!DFF6*]U9>ľ*2P@9_xͶdIҌ} :npiT!C?+11&J0̃,1enDDtArtt tƋo߾j|M|Yh?~\aSrFPg! {2 7o4?Q혪h]6?2{s[+2NCD<${.mݺNJWK.QZZwFь뒙nZ|B)J~1gΜ w͙[N4>i?޽{)22O/GDDCܰ$=zDDݳ/_QxxxK޺sͅgs˚vHÔ#DINKD C~TMKK߫aÆq0;aBtzֲe F1_~Ν{)R?3mjYvt0 \ܹsCbӦMشij׮QFk׮ppp`ʕbG['6Gŋr de@&˗BrrraM ̭,'̽uh4uw(sܸq:UVER r;::N8p;N3';=jeT*y $$ƫWlupp?q9:::]\\~&@dd$&L`r2իeB!,, n2n0лwo\~]Vlٖ9RǞ 82dj'GGǑo!lܯX"T^fҥ]|3qX[.doI7P(rn]7oJo߆Re˖˗p[-ip`V0hăp5\~>D2ePzuTV *TRtFP6nܸ1F3BZw\NSP[ޔ!99y%rirDD۶m{gqZgϞbF6z^[0yk8*0F˗Dc FRRүz*2\#۷-(TN:ϴHX7'-*@#Uqӄ hРAdF!HN[/D,&XMD7XOMWGk$;Ƚ{n/6u͢… ŋmԑv"kONf[A@O "EdB2sL2d0nf {ag ***0Ӊ(EHmς! zyyYV떑%Cu%|c~(W\vݛbccx 8!C  Xc8RSS}h}yE^HƇA"FQ0 wܱ;'77n/ˣϷgmO<".o޼ ""ё#G(o޼rM'fvnl[l&%%!x"k׮QJ2ܛ%K'OrEcr"_*xs&73%ZR%h4',]8kTTT'///7l 4N2&MhL-VXP6 5o󄜜4ŋѣG!䆕+9Y$o.]d>{fC""L&)gayPa&M[PhNrj1&R&Qpp0G5:"dEʕA>Ct&듿?-ZwRDDt<+d 0 ȚKQ`r޽| X!"jiu֥ZW_}e gϞ̈́ҫW9s>GGGQ68[jѢE=T SfRjm &^oSD׵lْQի,; GN8QYl`&J@V;ʕ+x49eF3QNKdOf3dY?s.{fE4~xZf M8ZlIO><+$ddiZawQy'Ol)=XyVcT@W^-0|}}>˗zV)u:];rl1سg=9ē'dp J@YkZm/"$9ݻw|B=yd2 \+WlJO!&Ѻq&KN޼y,XDcezqh6իh4Zѐvɦ-iia<+c͐ΏOp,N8Zh44n86ڵ.\XJ8)'Oz_QQQ;_x=&&fZ7oޜɮgϞcbbď `2+h11>dGwwk6=|2bժUwrAooon?9p6 爈Ǝ+`7hЀbccOJRYjm"6mXWlYzM.]=z4ݽ{7@3MxtEp5;wݱXclٲ?7{._l 9jժUտA8z/9a0[,Ro6[ׅ 22zE.΋z/duT*t,7;u 05k,[W[*xtu0>d?~&\ڲe <<<2ѣGn z &R5~lGy;/._lƍh߾=L2طo :^|͛AӦMkמjl5yUT:uBpp0Ǝk}Æ ޽;Zn __)+W|TF$--qRRң_?~wjGJZecRJ:<?tҢ8:: ϟ?zܽ{UVk~&8`os  2l߿=z@jj{_5j`ܹss Xͥ`S((^}B/[ŋ``Ú}p{|}}Ν;`u0I/aP`AL8Lr #Lj_|90(Zf4K(p;ԩS-֬YÇ Dʕ~~~C?: m"+|_ȖT*iڷ Y?CprrB^޺ukSN.y5}f 7!@asNƏ5kf b̘1X`)))pqqqh K7 3^X1^4M?]ۻX0޵C.Ph @֒Q&ssw6>n8yܹ|EEEٸI>|\Y:ЩS'k-J_fF1-))XDDM65FzpE:TFU% Gƹ4[BXhfq=q Јݟ`, fiQ\ǘFNϞ=#^7K9s~yMJJ ͘1ckV[p7_PJJ %%%@zu&=zL9%:E),,Ǐ9s7oY0? ңe˖˖- jS%t>|: bΟ?hEFhlh#ǟ<~7[܊~ PsJiv"607nXhQ9s-[^V}8tsΨ_MPTϟ?GPD ncƌ . 11Ѵa\eʔѧOZXddÇ{@<(^H,AqN'IxyyY\pMћ}}iN\_^! 2‚ пرΝ_CB.O?ѿ( ۷W244tBL7'$$`ԨQj6/j*8q5jԩS_3P(-[6`0M6 ]vͬ?j֬ѤI? ,JHH?y.|X|9N>mwll, f񝏏z}ܹs_LӺu;884 ۷ŜT*|wؽ{7Ν;m۶{}FDD`رpqqo:&1bO'NPJ.]r Q瘘׫Vz3Y)~6$իW;uի[|w5G=+df  OLLl&Y02m A:[ն׻0>8 @RPi49l! L&4x`j6moh_#Fz)R7oNӧOaFɓ .6+A8opzX[???X|ٳ͵zB ,sY++_B,30sŊgsk.AkcttR#P,554ѴiFEф A6״hт4MG U9L. e׮kDD7o[LJ\BQQQw*U4 @? @֒bҤI_O ɐH3f̠`%v39ۚֈŵ<+Fg*}['p0 Fф ,y„ >`߀ /X:T8[Kld W~痩TRvwrrBǎ?Ȁ˔) 'v8aN d9_MvKNN>8 ժU3n޼Fj WZҥKcҤI0AAA֪U ޢ0c ^z>}^xÇcΜ9hѢ vAT:wmԨQ״KgϞݼy+Xŭ R|?Ç}סJСCuV/_F*U0f/_* XbΞ=kСC?k4Uu|9fˀF0knݲr8p;wF pwׯ_GժU =V֭aĈMo>\~B/\pKCXR[_(3cƌɓ'9 ̴e$"قM85kRe2xQaÆ8z5֮鉆 رcYzwapA n 1>XXI|VZ]ӧϬ%K<J$֢w{Nb{9,̯]EV/ޯP(J'%%ȑ#ؾ};*W NV+bժU8pV|F Ňp΁Dtʕ+g\J.t.P|ygϞ…XI!^:(9;' o9fCɐ[` l S0)KcOU9ysD'Zsٲem3cdvS-Z,XWMKK{0`)JAᮮ|rs\"2>{+V)H ("=ҞBc.` Nu~իWT*L0_SZ0ђHOƐq`:nPK'''O6)/:u ba mk=d~=O>TѼ wuuTj `w0b) `UK.m,_ ^tЁ i C6ŋ~)um{-gDEE$":}M%%%8raÆM@_FXXi"իW[EsE_aaay)GzZUb\ZU4FZUhrUagܜܹ3SOyjuܐ!Ch1?v^+TtL BR[zo>iDD 6ժU:-- BrrE7nDr[N[ܼ_|9PB̙iӦټ; ,(jɑ#G ɶ4id'MYfx4zqc4l0v*G@@bbbީŋ(^8>}zdɒ3D 'c53Wh<&ݿUVpʛ7/.^efaDDj׮m-qiԫW=z_!|~ixxc:Kbu|1r&YL>0H. :۸H}:tȮQBHכ%11\EYFƑ#GU3 =x`MSܹESzus]Ѩ9pZcד6řʹb.SJ]Vh4>ůh"G%""V9r`KJ0gASP=z0/:v%עE R 5j\BZ#,W4}iLLU"QF)(22Nz(={ܭ40zoO6m$u… s&AYcL.Su[^TF,7|Cqqqܾd ;mVnpI2ri[ixTf`ZjW%hLwm۶I&ۤIɓ'װxV&,/ K3w.+һ/rJV;;͛g+W&Fc7jTJ{ǎk/`L#Y&0I?\>;'V˗o ޽; &111طo*T RMf*T\QPpa,ZaaaY5׮]CF\تU/_ BY#T<IH>yħjժry11h"˖-)8888.^x)S|3ro1ִiϟ!M6a6{Z ۷33g\vU-a$3c)pB"ƍWEa%FlMʓ'O96|~:/^b6s]vL #Y "g0{}qe ٿ?t+JL:3g|۵kןvٴ1ܭ̊ >?@pp0.]d~#M{aժU7nѳgO̟?GšCPX1>v~W@Æ 9$,]aW^bE;w ݿٳyׯ_XY6d>$0-aرڵoƼy%CV0{l<۶m l/ |Ro#e2YF]"!!Bؼy3j׶L3Υ}лwoԭ[8q"޹RJٳo545k ϳg)YRRR%JdEĄSb69+V`жm[={JR? [`A G,vaxN<4W\VZ#G&\.GJ0|TV y`hU{`r7rrrr2eJE䘯VS12nܸOOϒuov{4 :ujϞ=c4P(d"„P=#VZd2<_|T/^ ooo!OR~tAAAǎK2Ya﯈/h e \d&a0a.a`خ֤xi-Z lS{P޾}3gδx 6`֬Yȕ+7oaaa6ĉL&6`{ymV`0cvXXXOz߿i;SSSG>z3JY4LoGGǡ||4hu\|8ps='''o={.\8ijemJ={9iի΋_Pl+TJT:k~իJ,뛿wuuVN;w%K S`&Mp!ԬY͚5/5jԕ,  2YDjńYf s0tP(J <؜d %%[ơCPNѣ+W.Oǎw #1k˫щ'֯_7*_|GGG :RLo߾S5\z5+cxs8q:w\wҤIW f`Zaܾ}ܗ7nܸGGGצM=z41|hѢŋ7?&i!"`~ϯTrVtRPT۷/Ο?;wӧP*VV*$$;h8wBR0P3Gܿ/_zxzz2L7)BJŋ)FV>88²e4<2wR:%K8={fjnnnؼy3VTb~ŋQ|f+SSSʕsܺurZΝBȬ9^&/"66rܜ$hϩX`jժƍCR;uTI&eC&M:PĈ9ME...r~VVSPPlɒ%ʕ+1!|m{J@Mijea͛P(l|TqF*X QJJJ^HA?^Nϟ4 }`, i!]+dX\ÇFn :$s1o޼LmzY}%Kvg80o7 q`!*؀j:OXh4tճJ SB|@;DD}%h^HRFz|D#/^޽{у7onT*IVҥK}uc;^40$$d +eʔ}_nݺSD7Vs \-111ŋjaȑ#۷rͿo}`k )$@7PMeZҪfdd^Fq%N3gܹsoS׮]e˖ԠAҥ ?V^MGXtiiiݻל}oWΝ]SjU59|pi%K,hԨA )&~^zh4&X3i…4tPj֬UTߟڶmKݻwo/zx%رkxs9țps 1c)RDt֭[7K1V@0aEhdd.]Bzm+<}֩j?1dȐf 7#щѣf{':vQ\\i4Byc@Qu0\>gݻ.DHDԷo_]D/Z/ԩSDDϯL繀J!|0_p@ ~,͛md4sLsgBBBWݫ)rg˴p%5fϞ=(%%fMΝKD :t>,kVai '`)i||="~s禤$ڳgfjF VyS_TT"m۶Y9g}|e:~f.l d.H:@7oޜ%":uKRXX?l]XF}xRw:^zYKiii9 \8W'  NHL!`'N(Fl"Rscz S˖-9KrWNƍP`0<}v߷orU*E?\@xx Ė-[XbڣG$})))o>5j` L&jժرc˗/gSwpD"ֵ7hS<_+wz&mڪUƍ3CRɓIVs G9s ?b {8Oi 0LKIlX={ *$86BA?DGG'4 r,s!WAҚՌVjE9I>+`0'"zMɓ'g)SӁ… Ν+ tI""zUww&,ZeeR/ fF7%%E0[x"IU(Yv(!!(7l0=* v gɓ|,}*Z*ުU+s gϞQLLSJ5e~L5߂ LR cW_}eyڵǘwe,]3%%.ф ,iݺu߭^?~|BHzFݺu0QbyѢEt޽}Ⱦk{w9 ^Oc3e`` ~&.9Ωa-ugYx겊8\Q=ಙa}M!aN>"ȑ# &2gL40 C}=|C!!!ԡCrpp`UT4|p6?+))i[۶m :ءM9!fD%"` rG&!L2.ʖ-K7n3ܹc"X Uu q 믿n*sjk֬S,t'=Cec9&B4 Xh9.`e* 90m7odhСhػwΖBFqӓ^xADDwTbB?P0UtӧTzuAbf!!!.e˖03r5*ݍsS IȰISˎ#7ˬc(ˌV`iW^BDT^=9޽;mذaВu;jA- IDATMhя5]~}""6lx SVqӔU0e˖}<~.]d)999*:6ʕ+ˉRSS-fwwwڳgE .~:Vnv?1+WLq3N`cxkܣ)|;Fe*WU.#<63Z`Sx… )_|=5%KlΠ۷[\Whw^)=zD'O&//:\rѤIiߵZkb/?OiemprqBqx7nܰQ|XnݻwgwC\\А!Cp¢pww3gϛ0>.O) OΝK$$$&… TX1QmŋiĈӠA3#i0K_Cc  9@Vχ\up E=zt;Aqǎ n4nج 9rj|t3+ddww­nݺ) C07'N OOO͟?J!͛TD 縸Ў;ĜjРA}J .DYHҧ",z/11>ƥ;vjurG"=֠!@"ݻ[o{Çt,c$3gΜBν%55d25S\uGDz'DD; 48`Ç>:ܯ]fΜ9ӄ/]Tp.7p융eݍS~xg1ܣ-"!/+a9+3hQgyܹs srYfDǏŋӜ9shȐ!Զm[ʹRSNw^t6.l2L#\^JnJM4%P(H"G:u#Fܹsi4~x MRٲe3e˖ƸM65Fz%!A#! B#DD.]8q1cٳgh4~ap?ƫs<~8'93fFu-Oe@,2 0lѢ 2}Qc9 B\\\Z]B!zȱ^,s dp{hdn~nH& ͏ѹ|ؕf[׹8״i%KLeBl}+B l̙Jh?_l0⋙W^Qqfa155ɴi:\KYY2 M*lr40k1a<̙3bŊҥKGoЅgqhƺ45HIIyLDԥKc…6Z6)_|J{h '?@ٙF#͜9sі0~!ܽN>=`2k͛7{ :y$7J.%Sfyg3*T@ӧO˗/Ṡ5QڵUT)z)V;M6EY XBFbQE"20 Cڵ OߨQ#ŋsY#2])Nwv~{A,*UhMwU-prƺF͇? (%K蛲*,sɏ&,,-s@6l1٥N>m+᷂ ۉ''dTgXOa7eqbf41XF0C "-Z4""Rϻu$ bnRyxV,xĉiDDΝnnnC/_2{T = @ݴ(":Bqٳ+H2Rwh޼y-[fiԩtΝ< ~պhѢmz}2ѬY\X ?=~aYfOVHDtyQ7BA:6mڎV؋,Zvv3gΔ3 ssy'''駟>6uVXbbŊe=FJmj׮M* V%"S< Ϛ.@ADDD;wLڡ>)?`0k׮6fNtpp{䷲~Vg-VAo߾%J|{ڵ ׮]CZ-7ԯ_?\pe˖EZZ~g]z٦i:q Dgx ``~#z=tbp Uv `֬Y6߿z Gܾ}b7W+ #'T̙35%:z ׯPTbʕXt) 'yc"$$Ħ0Cкukɩڵkɝ;w Q缆B݂s-22 .-^C,)) &L@Boڴ۷ףhѢ IrWWreo\J*Yvu,X-\Rt!"lܸ⾠ w6dB58%K7a0rHт}Ŋ\.O;zhxuur#+;̸;u2!|׸yŅyŋ1a„r9Kܾ};w룢pLe<[Y-hfq~5yc)ٴ!0( tɏ7 UɂysZ)FcQhhMqAk2%, UVMpO&"ˬfi4YmP6'fkK^!;g;y$уڷoO{g!ںuRRR?B&&%f(tPPP=nٸӑd2:w8oooUùֶjJЂaɉСCaNo߾=Ĵmaaa6FQ0ڋ*Bf͚ķ'224l/:5[Uu\>Ri1M4pvٹkŞ+3?0k5296BI5#*$btĉOJ_u5qBQpZG֍Z։u։Z-jXmmjZThYVe&|;o%|w;w.Q25Jߛ2e߱$Gw1B!i=t_]ɓQ-! !̙3y* ۧ1r#==wxH_ k7@Ç|)9n$**J/6~bw`` Y.\licb:b" 0B=@YXL 5dL.]yF} |boo_.8q"yݻ7oθ׬YNlV/m:&P):f.ݟD<==9o'Ju`z!RV'aR\ 6T*!'ggghHii){nF;\©b{!999fE?:Lp7'''VZ,F>}&`Ʒccɒ%$99z_zz#:)BV15.,pQZ.%w[BILLPSU%7-QQQ٘hpZdggk,ּysNteˉ'!u}_u%:߆24y6R?oo*TT]v8p R^֢3/ŊY7N[L#tvppX.m-?oݺuB#Sa0HpPGp1Rm]^Z- Τ{YHψ϶uV3T@'ϟ'SL!ӧO'ݫ>pB{E+j4oogR꩜RS ҥKo_|)xߋ&666,f\f>-݆zކb^ :T}x?9(r=ҹw^RSNS+ɴ^.g؊+W8iӆB /DJJ J/_>LgA*tc$999iʠiӦ hܹ#X=ztDm`>jW7vT{H[ Y&{jO)&DxڴiU呾}\mXb6lCP2}t-Y؟.I:> Hpp^蔧Oxi3{jlTEe`c3ٱF{EuEUEEE c9M 22B:^yt,%all pm ݻw:uߥK̟?vvvر;'bػw/JUilժUprr/+>rs1 Y[y񘨦qTvvvc%K9ѣX ~]Νď`-[޽{mbm(gGxsR.';{RĜ9s8?l2dggKWZ51sG}z1'=z1cte=gڵk{/ha_hԨ+ːfкun޽{VZZ|С{~w+q!===UD(7B͹5\ fۏ`C9rT*wbKKK;v 4|m6}M.c֭%$$U~/T*۱c````2w\_yIl+%#%%E0osy[n͡=VUOREN4[-{O|셕\2B[7\XN۷suOOOM 044Ν;yfdeeD3]\.,xi=/SSS,YDp<++ +V:u+|TL9|kџ 4h 8P.C:uH߸qRlǎP~⾾'z Ca7=o)o,_1l2Ԯ]eHHHG6*/(رc98&MtU)=njԨ3Bz\趛7oU)lJAhhPSSS[Bf̘O7o)S;S5T>P)>P.H$LիW 8G^tj+++:u ㉉  55UX`ffѣGؼy3˫ UjmQT.B"K/~ϟjժ׵IuX7D`hebMl :^ZkE, B\`F-P3;;[tRcFpp0:t耺ub˖-nI}CCCճ2u߷oahhhcǎxH˷0A6OFu ݻ99¨α]v@ڽ@>{1`(O=%֭[97 ** Æ lVbJÇ!HVZ|`kfff+`8888G:f̘WrO><RÇwj۶ms߹s'$`!"""]C?&  3|(Q(_ Pl_-8qFP`4lP_>}`ooս{:(%ҧ~(222J@s 0U4bV.Ʀ+Y+mSf .^I (Ion;==T*MOƅڨQ_rqq73̚5/98ZtRqR-[Ћއ͚52ĬLՍaÆE(&gJwZboo˗s]p pԩ^B,A\@6Ca[TYYYL0Z(3g΄É'FЋ. 5^ZZ.\__.  N [*ӳ\cccN:׬YӤiӦm 44 "),!ݰaç 77W9:uYX5U}6 y&:oۂۋ>窖cʔ)cwů*8~@RR`~6lݗ@RR>|3gv)6AEU-m&oPRU "-TZHQ k^P&%̻v4 d0ĦM8\jTD8Ueqz|VFFF} ƍ[6+Vpbc$2^zEDXۉy(@(7006_<<H*Ν;z0h"G&aΝXz5vyB!~o/XދD"i?3xFШQ V~!0ѣ׬Y/_J߱En8Vϟ~ ݺuz(І^nn#1bGU&ys1j+Ds0Q\%u .V$r&}m[Y2fO? ؽ{7 `mmmbŊ "wub0״m6#>,l)//o"r\H˓CriShuGR7*RpC IDATT* `nn짥! ...m7oJ)Y&|}}=z;vRajʻ~ ar1ctL{0BBBXYY3gr .d^B;ȧ;yO*`Ԡ)PP̗unڴg?~Y>}DYIĞy^^Jd]7TmBp !/2)fdd¦JJKK,ļfr]$[QKUgI5%+7aWV\ ȨU~N 4jҥzFKnn2*$Ev7Fѕ7 9rZ#p1Zn/m۶wδe¶K.=Y%{k bW)JQ&):LJ jAAAxLWI֪QF<bEEEɩEQTaaz[Wmii)l}}}{eׯsټy3LLL}vxPfNIIЗ4Y45d$`N0'N`;v̙3~<,a qBVkBx#B8*_~aԩðJgW&.Uj^E@zf\[|p)z.(RJQ(OOOcaˎ;8M4A*8uV̚5 4hx…IFɚhlH{WblllEO3gg ޅ piATO8QPCXufgg#''666ڵ˵kEFyq }V^% "T+#88IU*5k~7GR666x믿_y(`r)N-ZlPTʼnlOt C c CSTE(K. C_GATr лwomfJ=jb7n#ev18T4]ȷ~٧ry *y0JA m|~GQPXXi``(KDdOEa߾}022&$VtI :Z`G*C[vQe())|&4¶}weƌ4|+u9BQ;Bo1WTϞ=KKKyq>y&nܸQ-7 ޾}IAA%"4%yWJ{H6S'JcBX>]MLMM0`TiLlsڵl,yLQ*@ Wu???N~?ٷĉŽ hiѢ=6sXk!X 24PVgϞǎ*0LQFq>}0,f"mnhQ_ډj6w^ջ֭[(XhTZ4%9yh7p={f1 xxr0(>R@Yh_Փ/^jԮ] + %"##a,'O ( edgϞ1t:tgff&Ν;W(6aKTTEϞ=9u@Y?9ԨQ fJѣGr b@P7ىbggCTTg֕]Nfddܢ=8p"!$ ӧ2eNo[fϞ-F.[ Ua} L-吝]6A˜WYH} 'X1sS!ӧO$֬Y{Iu֭hݺ5&j=;wJ'Nl(,t j@}ݷG\ƍ8DFFrizDJE233K+,T _B?~ bz`РALB1-<6^ 1&0N8!_}AR#th⏄@Yp|ᇂ/+*gƹs;v숈9"""u…=W^Z0 ҥK{S (b>Uvڥי5k~~~O666Tdff3הAn888jݺu h:-/iX t{ٿ;)}ܹ380 &ڸ84ݻwךgׯ۷oСCeBFL&ǵZSRRٲxb`WP(^q\fhBr69I&%%%7)e  ߃6u+JA!PF W^}|ڵ,mc?O*дP<޺u ;v.:wV./nnn \~~qG@Z;&Fm0 R@YC ԩS/Rԥiee۷ 8[ߤs%GFF`э4 m & 㣏>GTI@r޽z;hBBBf:A8??өнYuIt U-`AoT*Et˖-066.MMMo!$$tn݂FQP̜93f\\\bddd`޼ycoosssս{ !dTX 6ABBNׯ%2eއJըQCpZŨQ9>p@l*?!C6r0#(2ٳg~[%))ӿ q)̜9S`6[HXqr0!.EڵR֨'O`ܸq5ˍ;3g 뢰THRA8-YfXBSx)}E,%%e Pf[t+d,tnllCҟ?TTDÂ-wM-Pz4{0L2b ΄/ )|||fdd744ٿ?ÄRcvZ Kw "رxUԩSoA:87C R(PejAË/*&&&8z(|}}cذafϞpDGGx!Pn]xyyaРAh׮&Mqq;wؠiӦF=~ZQɺuߣ~ LpMaDnnnxiz׽D.M{p=^zŋ[H$ݻWk5>C tѢEڔjR/"IOOeooS"֬Y#fׯf͚hܸ13g̙3ԩK 6<8{KGMP kd',% iR !wޜv۶mD_dk[n!7oA b%$LFC.Z6[LPVMT*U$!̙3s͛7<"ҩS'朆 gRȞ={FeȈ3">LRIQ9"z]t!P(&&&|`*1 pP@ VQX@P=X߿86 H=onp`Z=Lm%Eujo6j$,ҰaC6mQOz%IIIkӻT(dС϶SND&B" +uג#zK_*u}T*O)++;V222"?[i˗/SSS7vX,'Oebb@W4QIv,V?Y$EyXBɖ CCll,5j˗;v,.]$y:u0}tL6h+Joý (֭<JܹR Tj[̙3^`O[= }0s%''縵˗۸pxm`޽or#==/_DAA DKKK fffԩ:uFަ`ر64ٳgabbׯ'݁0_T[^Mn8Ξ=ӧk,׼ysoӧO'~޽;ݻݻwۢ5>˗/c޽0`5tv~aɓ'tRB qF1`xwǂOB,Ly 9r[y111Ut!w&%%% 6< 800:! ?j(R}GFFBٲeYR[*觶p @]ԖD V'}t-VZjUNy듐 {T*)--p9s4iDZHjj*! ~ `#@f0Jm-fpࠞhWEU³hM#={p[:uH@@i߾=100Ш[YYO?/DP(EEEäW^:y4H˖-ǯ^JuvV9 ycGuDLL =zBmb$''#99YsDWWWxyy^^^hҤ ZhT\;)uMHMӭEL&"MZ4o<x6Ixx@iiiT*I|9su^êU 8tR2D$%%jhh B^l QPPBd5GܹsL5hԫW9 &M-<<<(O yI[^M6jυyLL |}} 9kFhh(zY+JvZtcǎ<~۷Dž дiSoP(~+V S@6lX_nݺLV<~Г'O|UEMXd We:gQQǦgBt'=z|ܻiiiLқݻ1sL1###߿ƍdggl߾=49*lԩ EQCEXX7݋iӦux"z-8ݻ())QWBVzO5EZ}áx 6X2ToFj Ɏ;Z133s?&MB||ɮ]6B(ݷo_ܹsKKKEmn؋&QnW ϛ!urr2JJJbhhӳgO\|3cbb8n+"1 ئ3DUԶ~occ#ZB_Я_?αE3zĉr DYxykп x3v&MMe#&˖-\|ccZ* +VuUuoT ggg͍yW,--9mE^1}-??ϟ?GBBפ$5t@(ŢJw0he?ܺucbbмysN]~1Z1F||<Gjj=#<<<РA4hЀy.Z (iЯ]6-Z8R'rVcBkOE6[S`0yd;v277/_رclbbii6mڠm۶ѤI8;;kWw! 55=Bxx8"""!PGE֭?C1c"d2B"0bу УB ѡCDGGs>֭~'MD]4k 7oބ9ڷoqTTT(EQ*BTribhhXm$֭K>BHvvW^EZ7XS_nݺ X׬Y#h5kj1ɈQI&B~S"I%ѻ}?ldĉN@mbbr0vZrt*F9oX5sZ v2YG%VVVg&sx"PӮ]"bPPzNiinxMqN/BH{&rZ\. V /{cv,c[0Z_lv@XXFIb7b…zzb„ VvTIIl鲥_mٶ/rBYa+\ԕr䄩5FFF CBB0qD$///ܿ_dLxxx0U/^$W۷ӧOg /W^HOO/ׯwBHNN+Ytի'H$ɕ+WЫW/N\m44###p˗/{iժU9 7<}  b[je~bܸq8t#du޶b:t˗4XmC1oPВ_vڳoߎ/⭍[[[ntEEEL.t<++PR[naʕ.^!/0f_~掯.F,&ׯd UxРA6;wJIII޽`rrrBPPP\jԨ!zupp}u/V|JM=i6lp$P歠5ꝁ zy@#t޽\f31oBVDw̽ڵ++##㔡!l"KKKt/FXX={4\~D@@ƏN:nݺz.VZh۶-Fe˖!88W\/gb-$hii#(((BR =f(D8|Ʊ7F=&&&;%%% 9?S&}4y` ?G骤V083ʒ5b4ؘ;k,g587bwm4PT ) 'N D>V@" 88'O 2mܸ9^3iBU93fpg !6l-Z$>ђSr>2e >))lvݻbŊXy9s桡Ӎ͞?ݻ077DZcǪVETm3&$:V}bq錢te/o8_AmT*W^Unĉ(**… @n^տ޳Jbm}ȑJWWW /FNN\c[{8֩S| qydddpIO`jj*?tPȘ࿖x(4U6fn1A+Xo#A- `DDDdڟ,<@Q\YEUÜ4Kjj*V\`Ȑ!,Teܸq:t(تU3͙3g `2.*EEmcǎa̘1xTHA7~R/ش}x  R%]vJ埖8y$ 9 cӦMܹ30 <<9ڵ+tRN˗%&Mb7mTz̙6iii޽5.]N:U~)ϥecQ^7~ ~8vYfhժJJJC| 49>PiocM, ߓ.RDnn.RSShܺu .]ٳgq)/z*ܹ"99/_Daa;+ɷ[[[3@͛Yg~@D)[Ϫ^H^,\gشi{5'lڴ &&&l/͛pvvalO2@FCB<lGbܸqp!Jq!9Zwo>H$NX 29SN]5w~4xʨȩCUDD۷٥K㠠 NB6ܾ}}Pў.dyffΝ;8q3f\- mmm233ѣGqFx">N1mmm!-T4`ffnn>ge<5BBB _jH_޽{1yd;N֠i>FSLJSf< 6ϟ?YtC+ 㹰#ׯ_^z &ڵkhҤ{ s-@<_ek/Μ9sEQ晙 :/]JBBBxdd$޽-[bΜ9-DENbU~_xTQj`TTpNJWT0Y[[;t<~m *{J5XŊ P!+bIP0 bbbH 99̛H&i5V 5'xxxx0Q| 0^xj[~ .4]k^)lٲr_d BBB0pBۇ 6M6C^*-[i*J+kYtfB"'=cJlI*Q(-Zaee5n۶mƜ9sPPPPQ>}0GDDߩS':v%e&$1+L֭[ח2NKzoAm_=VVVj:]VL9!VVV2ai|o>|7ԩSs;;ӯ^""cZ[ MV, m |Amkƻ6)!D-&G- kkkXYYښ}D\"//yOo/^_xT*wQl޼VVV˗/o_\1yM ?ӳ#GZ7nF MeFEE !EŅ:7n?s7r XKȦk] JdmdgWNK"̌~O)bT*'eBpt|`|p\ ӧ9bRTɸqϰ'fdd ,, Foܸ1^^\R"^%G `RQ뒦wlp77.]Jڵ^WWWݻw#00cã BEDPQ>qA7D3 ⊀A! !wtUY;I穧{s9}$DGGci&|7s2Vq IDATaZm˖-(޽{o1bDdM7?|D0ZRE_~Aaay\cĈNG[W kllD^^rssq1"??Iijj–-[tR|cX/IPmOjl$uDNN ͛\x/^? !Cʕ+_1n&%&+V_diOET")) )))ׯ뇈A6ҶDF `*;wAZeIyyy\vjL =bl9-gFTTT6!!![zzXh3k&_vL׏`SoR+@ 9v oмћk;[%333{3xqqq31裏 /Ç;[nͱobdޗovo駟kذaؽ{7oEwwWV˅?-!C {z*Fq#" d`t_R@sD"#11BأD@ 44Tm6M>JJJx#"~)Mp-+V*&QG!B0l6cNqxvWya2jCnxh(Fg %==R D6'SNT⒋|U\*[|ݺuo[{Ztt:}ccuĈ_xbQSS8,XWRDUUUҥK 7o={ꫯb˖-NxԨQ{FtGaG0jP9 w@ >Nڊ |\rrrhc"##G^ZCfW^ugϞŁ+ǏGvv6ƌ˗Oرcy'F4J\j&eZ!1 0\zQ $CѣG/&m'ӥΈdp -441bғ;O8R꺪rGNL&bNil511%ȧ7ٜ 77שj@@M# =رc1{_\)NKjSA?Yl~_a '߸qcƍ?aq}q{ 0G#<BꜼW^?mEGy$nŷ?ƍ;w"00G'!"xO Q,O@s޽{D JKK_/py- pd2'BQWWի 0f\c>vU$ "zz+RMʱo߾._0k, 8ЉH*g.KHGnnS$HIIAyy+Hm#sG[]G^&|Ij5 {׉`ҥKL&= o/}#8pѣG 2f|嗎ǿ;Ǝ&|dBetjV8-,y[9mr=,&lkFڵkS~ể#)Bpp0!}OVVVY0aaa(-r tlaG0T* utz!?b$EQIP\\#G`ؾ}̬sbܹpMi4O?=GM ܴHHyskWdP$[bccwu9LQ)ShY㈍Ձ?,*zȎ^S$bqVg/øqzOKKC`` O{x  靺ɖ #5FHӝ.fǵَ3lv\3HᴘQbW3z+X& B2`?O=ԡz*788X;tАC5pI [o~KpppT]]̙ˬ駟Hr8G04\hAL oC]PlHdd䱣Gׯ"Fs\.4<8uv܉Gرc(((hBEo߾1bRSS1c v#G/|'"NX@(->BA!;w&d`矝>8u1u:ӝ Xٳ˗/8a6qJA2is` #'Nt^vVQo֊Bĉߺo#Bݹ+!D <ژ1czovv6 222><<\WUUŮf mtf J`'bB(tFZv&\DDZ[[kgeeUp΍`ؖ.]?~pxׯ_߭\ Jō`S+A8{?7rx=+++uРAT(18q;o;wtpgφ^wZ 33駟doLj#0l0Ŗ_~)شiө'N\!r|Meo|F4!БsZJ6]w(ً=`ɓ]Ƌ/0b]nnR̍ݞ =}]oBџl$מ˗/ hll=^cEQtw`={.>>ޣM'Ov!vNMMiOl6ǩT*MӸrkiii= (G3ɫW2@>w>~ƴAw)frY nO9\Nr\.* B ¶lٲ7o\ pVgF1h %ՉC"a֬Ys/EQ\}H3C{l߿_BP(zQ!"(h6Bfӛ7o\s8m N8_} 70)..nBppLѣ{OXx1rrr\Ɗ+0c ޽3fpDAN:4'Q]];wG]0@1Bw'1whhFi4FRie2E#l:뫫/̛7ɓ'm"sF2耀\bvNLH!TFp/:EQ-s|є)Szjcǎv[lnnn#DPJ՛rիCaaQTTpCOZU(d 99>|8bbb{ 78=ĉ'0tP,ZONNNiPZTg냨uRd2իGjAAAN׮]CTTBCCBJ. vd\.0 BCC,eC/F[4ϐMXo>d3W/#qqq1 f  H|SrA^Z㏧L\>1v#'I°vZf͚2/X, Fs=Wo1e=؅7xxɍ7ӧ1yd9ŋ.\pmԩS k׮kڴi0vX@~~~M ?Kvv,*8qbXFFFСCCzEEEEh4Vp8qj6Lc/LÝw*溍V",,z{ :<Ν zꅔ#))_xi?3&M ]z:Ƌmڢx/^ľ}o>deeyjEEE^KLLĸqǠAJ{~' :&L NRV^]rz>88GbP'QSS(t:s֑<Ѳ2wW_}-ȑ#NO:'|R3Xr%d2l||%*pi  ;s::mbrbl Qd^zC& >l6bb`0`0@#"" @RRr9%ɢe2YBj ARR233izbTBJ2RT:~_~EaÆabV^_м1|ڴi1o>~<NaQFaҤI=ʀmVfR  NmF.]L&[{*$M߰}v!??ߥɢT*`0`:}Add$ EB~V͛ ֭[\GuܗO0|pTTThϟ?3fK/!C $$D't.UUU(**qY9sgΜAAAaРA:t(̙iӦAPD{{ɒ%<6 :NCcC^^k9s&TE;m&Y1f|{FQΟ?G}TCљZ$oXM&\UkNGHHIsjr9Fۣeeer5MȖ,fhZ… c6o|C!q0 #==oM_NFvIyŰ>}.v]O]s=w;EQʲ2Str=B€TV=@xFz^jqf'Oɓ']^tӧ)Fq=~8;Dlݺթ ˗cٳgϞu]¾}0|?~]va׮]HNNѣ4; 8x <7"<< ,}݇Ԁx[L:55ݕHV ѻwo9Zv:d2FL&L&555(++Lvryŋ(**¬Y?B1ݬN@~d+aaa9r$RSS1`DGG#&& 2 q>}8z(.]zdggcĉ3gN2`CAHEQ.6';of÷Q U`eb`(,;b {1nf DȅCSRRf믿h"x@G 'ϹE/2dJRT{)++êUy Dll,Z- F#Q1ijjB~~>%ə3g⣏>r oذ%Հ1o&ys)))8t-[5hZh4X, ժ*;xw0obYŊKj/oY$: F1(rA-[ZXh{"ɔd MxORe>~8fΜɛ oR║JdggANNN$,_<ƿ˗/c: Mb Fdffsfx"9r$ҐtJ1z;vW_}r=mۆ_~[nɓ'LC=zdxMzÇC) P(0`CaÆ;p'jHLL'OtȣG"//O~ƒ>.))1פڼs%Pw|_dd$n,X&L@WϤGff&233aضmoTыk">>>&99YWXXpUOʙ{Bj=`0`0.M39 z/!:Hr6cƌ` h&9~4v"°vKs&P  @8 @L^^B9~ ?z~$%% VgggB84WxgסY`+5|hL FȂ ȗ_~Iz}Ɨ_~I}Yr4r("qqqo&=lWSSC)SDreo>r>}LZ-:t(?>Yr%ə3gM-fڵw}$44 )(( b4OϩH f5VilhllBJJJr]vZIV+ٻw/Yl=Fx=n0_\`zZ+Z BHee%(DDD%K_~X={>~r}:F: "嘈nzʃڢ9\QQQߤtsx k ~&DV)h5,ޓFKHHi}Y4zM0qDz9r[A4@s 1uTDGG;vI̚5QKH4 [nozwv"ZqKKK[`q;!Tӽr|<dq-`ҤIݒ\8 лwo"..={ >>>Vo[rp4Wi&̛7aaa5k{=޲]Y 9uaҤIwߍ۷L@"] kB?QNuRmeڃ`E #l2ŀCG w{BeۄϺnݺB1rss]t IDAT`L?tS~~N xꩧp~F=oի V_l̛7KtR~i$&&b4{rRT{~С@Je̝;aaaqFAV+;5k`Ĉӧ{1@'bhH޴ۘ9ydQcɒ%HJJBPP222dlذYYYRZZ;w^… 1``ԨQXb+Z<#..7t… %:uyy= }ZR1Jɓ';$4/ݐ.ᱮxwcك?ׯGvvqxDEE!22.#""$jd2(//---mqo<x'gy,jх+V,[w\>=33aB=`0dC(Z!$f{7R^^.L06f4_a1G4  F0f۲v\gnŗ aXS(7l؀;"._~%|I|8s߿޽{;FRRbcceױohh@ii)._˗/~'|"Yj֬Y,JEw}< 8mlla̝;3fp/}MMM .8Jږ6Od ӫ#11{/^~e1wT*QQQq[nًkĐ^pR zŋN4i/M6As(..Ʒ~xN`РAHIIADD!TɬU .j ZTMTbܹxѣGcʿ9y1#FxYRݴpBj…8rn݊,PTNCqRlvK%""cǎł 0ok,<>w}.9s&ҥKPM555=r[ mT V,암҇/L{\>p1<=`HCjmxQqCrrߓO>g}񚻮b€2 Ft:"""PUU% D٢RqF}C4i&6 %Kxm6mۆm۶9=jVu/gqz{A4O~hٔ< )^7,,ѣG7oe޽Th4:JF`s=|F{_Yfa/Y֭[K<}:p@awCZZ"-- 沲h4 Q4 -nצ0h ;cǎEFF4M.\Pqsh`B0݂p\zx 4 Bz=PĊHMMڵ뢀]jeGmnGAh!tV2L.D0{\Å9l?~嚚烃>yQ$# E`0(..dINB;Vr8۷Tffndzl6.[lɓq <~`ŋ[tr9ѷo_t:BԄ2={W^y?,6p?СCȏn^;/^믿RQTӧi_DAojj±c?7pDG^~e;ҫtn)c;6tA}EGGGGDDDt:?^`eqq1ˡd[)Q( Tt rҥӧO_ͭ޿z=Mg33ܲ|oODkAF*>hh'N3mڴ~\)#Cq"&LzTltuuucyyyCiii}vvvٶm.>}3Nܽ|6G<@^H<֝EaaaF~m>@HH_{3,[~ۏFŏV8  1|mJ ]`8 Ǯ]O^eXd/Ҡ,֭C~},%1(!N͠;Zlْ{'NXX`A7~ÇG$''ջw^a:5b >>x|A1ܗRv\ Ƽ $&&&i@&9_Zk׮ՔWה՗זZLt:O{L81ig3gN 0]0K$V/!*'\Z6OKK5p𤤤蠐VUjZFQ*J9&Fxd& "oMMM暚CuuիJCyyʕ+K. gΜYD< dIK0H3laBCH:&N%݃C ׯ_HBBBpLLLPTTTP^BBBt(%6UTT4՗6\p>??ԩSsk`xHGoc͚5AO=9}HYL&5**jsmmmh!fc5yyNM2]<Xm6[L&Kg;|ZHh Fo)P/dȱcϟ?뢢" z40T;!!A3nܸ^Æ 땜 MŋK>\_۾}ւ[v\qƅ6vءIIIrRwm׮]-//.--v…ӧOW9rõV]/jkdɒ[),yʔ)k潙E0L|gFn3^BA92(<<\sW\1swMp;kLL߬Ybe2iMrF]tFDX M7m4m͛dzm&Θ()Y$F.tK21%u!!R7%fpظ{#I9Q O4CzN Fr]ڄLP!xNLt/N3 .F1m<e#[o?쇿y?Pq&@ZǬFhVV&שAbK:Ͳ_ DlO&Xu -N0x p nWG>].$Z :nH3ǣixXK!~~~_~efzzoE_4߂K,BcI,41K g&ne˖>oMMMl<EgEx (OaGa :RAZdcq%%!B*F2T<7z!BDC ɠZ`ץ 1o>`@.h`tYMбF`x;."\aaa=`4r\ȗ2(񤅌$1Aً2 8 ȟ׋r2B:#š %nmp5gGu!#׃m&[/ܦ$@zkzzv#]9RBC*@c|+mp<\]6x]-#tM===D/Ky@2J``T){RFqQb_ vpƊ/VCCcc bVh=EQp_U D1l" .K JRm6t~ Oxm`8`Ks@:`KR=V%5Kb^Ieo2D:@9ODJ-XGңi-%!D2HggFǺbrtG0/s:XӃV;0|vEKhrOhiRB-\$;yk"s!^7NDLA]q`>/vK7?B2&AYR B=jI)$Cs6ab\TyNYy%%x=ɹ䂸Vy>.MV/.'^D'Պs#"#@|_7 kL`Zp㫪\[|+F0 U8HvN:yrILuf Vz=ݨռD͞<\\-z!|)m4hpdE/H0 ܕ\s"ы fwj!RR:Ó-汖JXIѣ a4|d源 |#g̵rXZ9XR-%Bͤ 5R 8Kn؁t6s qBvea,vRm;*!`l.L0lMG1PUI$蓻Tzܕ-ߒŅ`{!v+KȹxQܓ[w^Pw !;!dpMƺeW R. {/enKZuU ):=訧c 9P߼n()-ץftRʱ 9l 2/C[)DCg w$o?Sna]Flq4/:%tY̥zv=RT+cAZ]DR;CK Նz7࿭a;R*[-쌧s褻I+mGWևfte!HOCցl0ZKT)nth+^񳭀Fs_hwtpPmcR2@z542 »VTHي 1hk)8/ʼnSf{k[cOqOr@zJՋzw/]hTR=z&EsN mmgZ:})1ޅ1:j ^>3Ȇ'>]-:>=Sb6wK(ψ O|滧Mhk=87q|'>&[kmuF|O|#>O|t5ϛȄO|O| # K'=RdK'>醀]^> [ 6l6_g4Ξ=s[BK~C=-9t|'l}o>uHX,h/!pBrEEuu·O'>OK!ml}2O/(@UUU4H;X~">kG};yC#,"Xy9y3!B6BBg}Ҟ6kr~քW X{7.cTWWH)`ùsȚ5kHff&4h2d9s&yWɕ+W,d2}P!'W?G4:@l6B^Bbi:)b'>DBі^~~; x7-Kyr|@+W7TWW >]jZhRƲ!4MZF㝩JӧO4}Nȣ>J ȋ/qz^@k'EEE,4M;\rj]WW7`\,$xXV^b'>DbZϡ0tK~%%kFX禦&n~^^׊2}z}D[z ZKɓ{_`0ܷo_ TZk`#쓒dٲ l[ !h4 & qww O:;`ȆL!Rj~~DMO<Ի'O!Մc2m4r7={0v}\XEO|ҭ&PGX99MNBx^$$$+s^?AR w(}uʕS-|L& ~jznn <$''cƌxѿ!AAAYN5dPTXM&-஋`7FqZ@Ŧ&t:а*%%彊 > D|:dZ"˿Ǐǎ; "993g̙3!]rJ<{ ٳ'θmjj(`0`ǎسga0t̛7)))ͼZRR2;11:@K>A|Rj"** ~ٳÇD "0F7]_!&H o`BXF<bYֿUUU5hֿ<^w^ sMLL$EQ$33|{UVV6 i생 ={yfhYtqf^Jz!̤ǼdΜ9$>> d' W^u(lsmg1B}ݥfy !B^Jϟ/U8p r^_HZ; !$''G4-J(oNB`08֦[+ihh`<嵧NJ9O _jtݔY'!.cTYYI!CߟetpNSsXVE!!َE9OɢizbqF%z`<jow 80 =WJ#8sL~kرPT(++9::z7@tEQj#--y`(_!VWK0arB8Čӧ^ӧ{9,Zq^FW_}uժUx 4[+s2^233ڻw/-UQ$4?k`c]^^>?22?cʕ{Сؽ{7"##A+Wpu҈FOR\a6W(W;#F8 QQQ8|믿>]1!<:JڝRfmh[Jx۷0tQ A{#hd2~fлwKf޲AEO flWl6SV}蒢?BB?"B, !va[^BnZqeB!k׮ @beO")))-u1dڤIb K.jjjd22kFUUUC}Y D*jgnP&f{f}J4Ma*| zbZM&SnccW[&gÎ/_+kvA0B… [4gU8@smpѝ̾)b{h&BHcc#j-9>6vWEEӄrVgΜ!/ ` D#wBٰaCw{up/_^hZŶ/loϝ;T-w;l!F&F0[ر1 Y{Zd+Ly⒒5j9uԟ@ 4N o6pZm~n j>)V "o^ǎk`ILmm-,]& rHtA9z V; 9/++4S5kqCttr<F#Μ9ll6Z&NNN>xոBBjll doP… '|K,qyq!P0{wsSkӻlڴnܸ1@=ʶlٲ|VV\z:vH 0 Y[X7҃Cu1WHϟs-RHggg@'0\?TpQ%P;v q{b-\w5o\bE=DBr\%4r\-J=<<<>_bET*d2\.W٩Em ۔"? ajZ0vغu+:v(\H˗/ GZ6ۗZƀήC EDD(&'g|e)C&8y)@[O!/tuN;^e Jf lXVfƵYf tKbĉ{0;; ń pBHR֭[m۶mP%{FRRRpJP(*n/0qϞ=R[׮]z\}Gn;,cFщϒ XT*ucy?!"L<-ҫQjj*vލc>|8d2Y+VYf u?Ϟ=չ ~Z* [*Vh4|j4 @YB@RK| ?2M4 l~Ӛ0d@oÂaӂaق@3 9-A@)S;Ošݾ}{-j\zu7|uc7 ob̝m%7իWϳPBݸ߿˻σOV P~fM:5_,W_ơC Yobai]7qvvv[Rffٶv<ӧO-N:'-V 2A.XD'8S~^ƍaZzثYfd?HZv>>>~٭[Wq/C)s`xOCV'"ڸqc_~fڰBe#dT֍*, '"{[%mɒ%:%+((,,,Os4j(""zAxT @]6TiDc!|;.s C&5VTu떧w>-]t 69?O8El.rzU8FƹIyF;'Y={&JOO2qDͪZ4KT x»׉.\佡CrWr>+5¥_p4r|fza:שۮ\R@gƧ4^%$$FZpС.R8+"la֪ZADtΝ<3իxW(OVX>5kY ʕe5 ֌:j? 8qE_hڵpnW^_Ân޼yw.84zI& b_sVl2`0ˬzVwsֲ)X| //E~d1\Q@@N3ʧ̓޸O|'{Juh߾}ZcǎdZۯouܤl[ю;zNNN>2/\0tv!G+V?~L)h|<ڻwT*SݺudɒTtijԨML6ydڠw?SRR]t)Ԁ80 )555諯scbbցW <@- e};(ɓQb#**v=ѭٟ-yj/ŰMђە+W~k2Dt@׮];*5x2^ {u0jMb9qo!Kk~>} RyZhofgggW(ؽ{7|}}QbE,YDy@ׯ"##c˗8ϵP>tS?훷Dϟ? ݻwsVZaѢE/^~z6 řyos^xQ+ܹ״i R)vڅ;ZWZpx{{####9 `9*ړW;u#99$&&⯿BLL pez Qn ,x_'YfUT5lѻ|WXf ٳl=C1Η/Xgx?f'p~ a0Fqt*x[> +V$r`{Mi-Y- v.2sm`JKK;>>>pqqsnnnygfbt IDATٳ' .l`(Y$ .hC &'':thVl8B@Ch'Gt~ٳgcʕprr2!#pAd2D i\|222+d"3VZS899_tE I.c̙vUÇ/w7?r/ }R2ƍF]KIIy}t/),]4r۶m4MV_t<}vlݺvvv:t8ID]^ cdcV`(J2($"J$wwOiQУG8P_.b7m'adi|o[sKNC[͚5UG߿?ǣPBy~vaϞ=x%^sI&Kdggcǎh֬K_¿U%'Ɠ?kO7UTya 6 K,1nݺ_~#RSSSũaR)RTRy|rrr`DGG3j՚t޽ hFh;wK.Ő!CЮ];oZӧOuoܲe7gg OO9}ǁ}…퍤$4i*T@ݺu1|p,_W\Gзo_g^ڬ,Jef~}ttmNL!QH$R`i)07~wC*0WЂaӉa> %9ij}0䳲@Dмy> زe ڷo\BJOOիiӦ… HHH@HHz D|:u իWDzeˠh JKlMNN^9lذbJY2M> ۶mhoo_BCC1rHڿ?f̘(Tرck _bSͨTs@]3@I+W^;o޼QQQ$Iv1f)SǎѣGm۶!** иq ?7BB!ӥK7;;bssqq)e_PM usܹsx">| 5jQРAH$DGG?2dHoR4Z%O> [Ηtv!Rfj+$9)))inr妛￷7(+K>~###/"eS1L@k$c6v0lٲݺu0Sbb"6oޜ#ڵ Ŋ_~`dff ^wvvF.]oݻ jcرhܸ1ܹ $ݖ/_~lƍU؃B1 8e*ޘݸqFӦMI$bڵEgܹ3g0qƦV n Ζ\KHJJ:Gʕsթ3wظq 3f<*S>>>=0reh4زe 0eX,tnR^*p*2%yB#;4hǽKtt=zL.]u=̹s]hѢJ*q "?`L(+bziuK 96oތ`?̙R \^6(( ښZsyd0>5j8"H\p4sL,X_wرcG Xsh&࿮h.I$,Y$W3gD"EsD&squVfVVV ΅'LcՅB}44hPmߍ… [K$Ǚ[SN'555PB?~'ab HRDEEJ\-\}~ٲe333+WT*-!CdɒP~';wgΜ?oooxxxoEjj*)ق ,T }Wv@!.@>} R_N?p@"XXR7KV%Z>|lpFҥKM?=iN8P&u$"W^۷oׯ_c׮]|b !ڵk1}t,\6lie̙طo6mڄ:u85idÇPj*q ) +~g ~~" )&&^%3 pє)S 0qDv={6M4e ޞ9={dd$//m۶ef̘ٳg[I`` ƍZ;wZ ANx7#=BXX5k-, K(!э7PZ5TX\Zjuݻw 3vK}05w$m۶ >!C:%4w\!###gϞkY;j z k,%_[h!T*mGkxYǏǖ-[ЬY3J*_e1SnLOCJM0~xZԯ_?NTpR@hIG? _:IIIѪULX t xS'h D}mo/'2RSS}HCD4eʔ޿8޿G :zSNFѼĐht ;-TxSl"מa "cǎKݔ%KСCZ;̓͡_ gxS YL &''Oaٲe$MD"j5mڴi;v:C[-KDߛT*˗ ` zC[#Ws*{gdd<&">|賏7+ +hVɍOÆ 駟ƍg<C1@h$_~WM}ʔ)$HL':t+B3fl1wpkB[oj8R\2q4mbvs _,H$4qDݚޱch(;]z! /71!--BDDD3fzݻh ں@I9.E4l0|ttt\ ?NƍpaR ond5 ) ٳ[g}  ..΢zzz"44s΅T*t G|L3~r@K7dRC^,BktԩK:99!KcIV[Oݳ8=\"/.@ߚ(@uL4 AAAƍcҤIGN{ٽlٲ"jg.E_b|X"T3/_6-P4i6mdZ*t6mqŋ9r7뤈@yMk &OO$JM5k[_gΜyWBJOku=zPJJGc~:+WΔcf,6nTDDqqqfSe2׏M IJĉOR@@`;wQjjjtRhZ3JެE; !} nrRcӧOQ"Ǐ4777r gUUWTi/~#&佲Zqe׈' o>Ԯ]z7mڄ Ǧn#kd}VIɥRX?~ ī7VZ5K.HLL

$"K.b]&Ơ VTTn"ݻwga-xN?~ds!"\`"^e/w3Ure_I&}שSQر\ e`Q,߲Cbqb bJڣhR^Vedd ڹsg9䚓A+P(,YRSS-7o6իW˗/eu& vZEg4*Bq"...o߾E *"Vg䉈Eܹs4sLر#'M<R,ׯ_gL40݇]ٳXYz$+varDc̙\Vz޽kt [nEǎ7oތU~ٖ mil``aDkp0k׮ <1R&LO?R)P(r]#/^aÆ7$$ݻw7Z7nDPP4rŊߌ;;J^S4&&|%tR9\&- @׮]hѢسgZl x__y{p^44|-'5 0FRRR69;;TQǏM6HIIyY\)Yk5...F+W>ԩS1ov ǏST9vI*Vksj׮M?֪4ͦMJ+,0dXROh4֟"2gu Bё(33 .lӷ~XUΥEEEU3-[LRΟ?Y^tK8Rd|V s1{Z#JuY|7Y~h}j lDHƞI%Yl%v,66 Z+VH =Yڰfgc LCҥuY}VX1e54P`>j:]vfK.DDP(ҥRiWz+Wo6Ӊɓ'kXf'm޽{ҥK5j(""ՋS.;7eóf"edxiqZVҎ;hРAK$*S u֍VZ\IPyݺugevtt;:3FC۷oAѴiF?hMs<@[W^%--oܸAԲeKruuطk׮?>x( m3hY3>4pLD:uT[Xڊ)B۶mc}||gbW o_fAn*U38gTThʾ < AC35̥ k (\2k FV "ڳg3tP5:njsB[l1 2_zzzҋ/ .Z*к1#>R`矂(7 .4]>}Pzz:'$mݺu0>!pyv,sbϢ{A^:M߿Ĕ[ӢE l??A?.;M4JMM}HDvqb6/C`̚5+vĒ3[ٲeu{gϞCxK5DDW6)SٳgF7q L2\F/_K}lh]by,7io{M/uMņU-= ]YYY}7wܡݻ+  *>LAAA/M۶m=R|tԩ,(,ʂ 7˒b. 0͹ZֹsgHLL|Ѻuo͞OX';`QNjKҨQ> `@7om&ԨQc? VB[cdڬ!]X؀e\N}H2+F̍ڵKT8߾}1'$:˪TҶmkֳ Q٥>6Uvh4g$00ЪD͚5uYѨ=:`N=y يSz!0\X*@ʳVZ_vm)KpqWX@"fA޽u56lh_C_:u;Vo&&&њ5k,SL } Qdd5ggh/ɾLLLÎQ< : \xq n,dy W\vCq6\(vTаn̚5NRmɓ'4`Xh}-ZHowoiҤ`dff}z\|٨ɓ-i P=ݻ:ӳ 79a4 k.Y3l\Hh//2֨Q#]Mr!8o[]WZj/;hР bhܸ1 $C*bZ| IDAT{q=L>}gؿ?jԨ8tPD``_xO78*h+eرc\O:#GZ5i$bJؽ{77n۷o/44-w}ڵkտ[n}&1> DGGyzze~VVz?ê͛hڴ)N>eJڶmΝ;S/ CҰCcEsKL0I *!!9/_^Ӵ4L8;v@ ULr]|#a,R 99Yf/LL2e*_ҍ7вeKTZ+<_~w2d/^snnn`Ѻ:"T\9@LLsQ!^ϧ?7'Ot)H:]0`xHKKC\\EՖ#""0i$L6 ;vĀЮ];d2؍/_t2223x*PdI߯^һG.طo6l؀ki%rƈo>:t[nE@@dɒݻE +x 'WO?-zzC|2Zl/ͭѣGUTiLga֑hʕ>\Ÿ{.URE?,QfϞ-OɜjWl :B{Y/&@9Z/&j.@!+4鴜&o߾&-nAٔJ"ݻMHAL&/Qtth35iL.x?)&=..FejٲU2e|U*Uƌ3C?&Ô%ZSܤ\X(g(Ǯۚׯʹ0.n%PB\<@K l^FF3s ZZLOr@˖ZZaPӧ KS!R!<&&_ւѕ@5kvN"":xI vFF͞={$L&'kb;MKKld`("`0gyFM0UJ9s&EFYbcc鯿l%yTxq3g]xQ4GE1]GsM3f 9;;[*WLcǎ+VuT*=Aߧ0ڹs'd ł=|;;\%)%dQy" "7o~j߾}KXkܤ:`8Bqavq RҸ51ah麠=k$Сh:ŋ p6o6sZmw6 D{#G$L"֭[)1r/]pA+WNgz_~L1tW4rW¹%%%Ybistt7R||<Tf|DΥm j62̹Iqw)˾[>*kԨ?uQ7333w{ztn„ &HP$ꫯ(===Uu6ˍ7N%KZߘ1cpun ]q`Q-nWz}ƘY/X\.'In(99~7ӧـE]2L2|p{mftOB*4iB/Q!W4!!!ԩS'ksu_>_/].oΝaH) ًhbp&˖-CD"RJ RM m] ʊe-n޼y/Twܹ37ו+Wի_|1o*y 2Yȑ#9qޝ 6LѨf͚e&MpVthE۲ۉ}\W.ыwz!TOP(&SլYnܸ}zW\{ȰiW)"MDw^ΝYR<<<:6U$?8&4 :SPݸq#tғϟ?TQbEpixxx )))+ رcM L42ō;Fbq;IR?xGŋgϞ=oY (VZaĉhԨ./4sL}tm޼Yp0G9BBBpmR* <}<@RR ۷oG``;111J#G:bս-Y/A`ޥKBPyĉ!\].ѻ"e݆;В5 i-vߟ0a²"EyyyUU~ɊbbbUR)R}}}GDDøʫS3yd(@Xa<|805f>|߷n݂ZFзǏǼyt0[ls6lN8!zOΝѭ[78p@qijJ? ۺuy7d\ìSa={2X|9>|h/SbӦMhԨQMp XVuЯULgxF ,X 6`Ȑ![.3lذѳg}@(7K8v:u??.ASY)>/SX&O 6l h#|2"%RJk@emBBBAy@8cauyC`Awɓ'0LEB=z ==]y{ŋ|}x4>Y! ]dI?T*%\\۵k^zsbS \#J{O?/^vCTTX~PBB-ZZaÆ;"""tׯ_}" `ƍh۶w8qժU… -*hɺYv-z)2:wjժ] Řԯ_O=6KHm0;l΃+aA2`Д"Sӝ5krhk]ֺ6 ޤ#3%Z]_D "ѣӧLoÔʥ4Ebvm0v Wdj)Ϲq4?cdlXׯ_QA>ْšԮ0vWRbkWƮp9Nh4ǏR2(WkԨwQDDt޽\Ç\OOG5kr{ԹFչmvy KRF>} H0={ׯ|o휷3gg*}}}_p/^0dn[^{Ν.YwӴ vV#Vu\X\qI7;v`V^6޸Gat Z1lEJ!-E9J5Jce 9;;/ ߳gg+àvz8ׇ/bL>]0k… e˖ֽ{wtW‹k}N8)\n7jԨޜ<'Y1ẍ(eK2@f0Hܹ(+Wݻw7Ж-[Lf+eggcݻ``Mt.fm޼Yp>o޼itn&M27)) M4YٳG׫W/x{{]tRRR G]MA2ΈVOgG\6)1 !Ȱ]S~ PJl`!.b/눿`0 bD" 1fjժpuuջv]B)iTbEnZٴq}iB4m-R=ғ'O>}sSZ*&y+ШT'9j#G+VD"-I 0TF7R]RR㔔x) bl2 a@&cǎPvmAwЕ+WK'ݻzSPBذa}Jݺu˳RR2|.DT*]vC??/3Pp5L-16lY˖-#W@}֒?o E `Y1 k^V6--s\ W^D_/_Ν;o:d6o9/iR Y2 2@h]Ν;lB*!++˨={ f3ާx%E4PDL4PJecΝ;;?,VSeŊ9>8!`o1@HfY$r0<%7\|Y9wᄈm۶ u!55Uwjj*vܩwϢEPL[]asSK%Kb{kj- b985"ƒI"B7٣eҤIxuW"g9kX,h,;/.0LqN8D};_7JymgggTq|޽zJ(CbٳP;'v;w"$$f;lߙƉ+'F95k&q&Z 0Sq6]|bB\`𙆥n; `ۥKT^gϞ_k dHl<,Nbŧ40wS zHHH1|[@# yY#G"I(#޽Pbf4OR7k[R?Dz+ 5ĭ *αQ:02gw͛7KJ;WVCzjܼy3Wܣ3|daÆU8 @OB+aٳgo<<< &beKs;jS o>cǎ ݿ_WM=/tС<c<7 .ɈAS0@D bFԩ^gnjܸN?C/#TJ9sW~XF 4ƜoF%UG7o\ |ѣ۷G:u- nyX/}(p6d暵-&99T*]h35}wŋhӦ w[zŜ`jժ]OOOe4iݺuup!?k-sLViX$?iϞ=ORgʹ9|m_qNwqMl27hUժUk+VmmmmZg[j֭`k]ZWŽqR@dkr d%z.Krzx?Za[?/`@}§:J:P@AAW욚2-[(b*x "H[n 'O5yOfСCP(TӔ˓aٲeG8p W>:3[CS`=dbaa@ PJnH$?>;4IPblr04%UԩSoB<-Z@^Xw(%?| \UImjY(j U(`f*,,<T'h@ub)0wUx}֭Z{j#-Zk4֭[S9Pϯ!uܽ{믿sUM)gPD"ɗ_~y[Z[R`4ajtR`X`ŊK\4| 2S `eee;h g Cc/։'D|ϟgLK0a ??ڵkEZ, 2oTlYT̃V(7խIXCx-ڳgT(y&ܹ} o4jWCAOvwwg:n``C~/^Ν; d%P(:zh }6p.]D0ܺu0|pڵk@ʧjz44!QU,Yxɓ'XbEsR4Iuԉ^ee%~3v`0SՄfP/4tz<cƌǧQș룇 ҀޛFRRR-SRԨ͛7L(˗/gŋѡCF{{\.W% a[ϝ;h4HZJ,wƍI|=Z?@>c:%f͢B_r޼yLѤ`4Kek^i>}1*{7n@H\Դ[ H$90i$OBGvڕP#> 6nJi2uEҒs]yAP`nnΝ;←Jƍ 0d`.Jڵkrσ %''GR6oa5F Ա}Lnn\kߘ=bbbfk^D"!P.m@TYmF蜰pСFw`ٲeHHH@u iLڵZf@:6"_(o^իec_a˗/'GGGg1,B~er!\.XLd X,sN)@Svx<RiccJI!WprrՐ4Ƣ-ÇÇU֬Y*s/EVVV5u|OWT>3g2#"" \@0H̍>4f$''XuVCѣGXp!x<u⾪4a("ݻâ£B?~Xeeeݟذa:v숪*ԩS/1X .Y6,))D@sF]b)S mF])%dɹEEE믿Vb۹s'n޼a? ,_xtNVN^bc?T9޽{Wu7n >s&|}1l09\ؘr[cɒ%*#Ru˗S^GH$Ņ'G&`!M:j &Yt`ghkP$SSSL: 8rB+ywU~`` 3|9rsYz.-@CzONNtܙr/DEEaʔ);v|q TߔT[UmTӪB굨ڵk7H$RKKK|  8=b;Ο?ߠ^<ڄHՆbMdĉVɄtCyҥp8UV%B}^v***;gΜZG3f̀G$W\&M$@]f#4!Tæt"`4K@Wc$&&"55iiiӧOݬ~'deea˖- :tIBBB\|Yo˥" j۶4G1V2 srr_~&133BCCѧO=ӦM… f,Y_|ƍs;vM6߿9s{PX4 ` fQs~Qۥأ~/xo*o-SI]鉳gR)[b1iv傟 9r$vءrڷo{=%6m`ԨQu]ɩTUL&˸^"?X|r;ŲOOODŽ  6IMmE `Νa#pg͚>%%ep~ \DYj0Xڀ;w-Z8;;cѢE{ʕ+1h j-((I _z5_@uԭ[_~v ^@벢JY][j˗/-,,ݻX~VxXdI«$ ܹN:iuᅬ7/{q -fOX_?waffWWW6665ajjx<R{BB!D"(//WJKKkS\xN3LII,TԦoc]كH瑝Ν;СCu'|||gϞ ȿ|NNN FЕ{Yq۷O%Xz5͛B 111`Xry=+LsS>7D6[bٍZ!8z(N<%K`pss\oPe"uh,hRBPJ ={VZ533n-̙3ٳg[n}~gUUU"3gzqE"Q %>>DE\U\36H$*\ ]WHYLREExĉ_޽7 n?3F(y--Zufl[laIIIݻw?^\\\=U1:m9dR: S\\\кuZ}!˅7nnnpuu.(7x%2334œ'Ojfg`Ԕ/Vi0VܹxzdF7o'||7nB%88'OD>}PZZ xyy 1BL_`ԩ())Aqq1򐒒@ ѣGCf% fΜ+pQ //dȑ砜8,Ezi ,-)|>ϟCa׮] 4Xh0ۡC.//1@I4 R~Z6DK!׆@'+VBtR*_->0{h5-X0`jQyFk/B$_z… ܼ^#HFF[s̹f`lqF!?^MRRQ'we-u;S Q @g|pkxRCc5>moFF^s"'όbO@:fO]~tn2 4`: |qs!Cuů!dZcccҳgO2|C>|Hw'Ν#k׮%}zbffz$#ׯٳg)nnnӥ3@O8 - 0`L𾴃 B!@bķo>^m6;;;rIw|h۶m---Ӏzyym "B2dJ&~)mB~~H}h G6T([ANNwҥEBTn߾MBBBW=T1شioۓKD7np~Q?DnBFE<ɑS<}://o!@@6=cK`6暮!R/^`XfL}WTƖsҥKJ]]]-,,,8%%%04O=!,K}ƌl< 1::'11AX"j*@^ff&aŸt5)BQ6ڵk “'O/ӛ0aΝKX,QԖQQQW.^ аiwBuv.[lɌ3?*\f%桷E1l0 6 +6mڄ?\ox~! P"Fj&jmverrrKEe˖P(TsΡcǎ`7X[0H5DH=zG߿f AÇѻwoBaÆk3gΌjF"ܼC&w2'BI9s}իW#77۶m7慅}^"LseMiQRRiffvɫW𾇇tjmm|wy`II 4(v[],ڀeXj=9ɩӛٳ'> kkkTN2CrMΝեK?XjR.6666j3GiS[QJ 9r$ȑ#K3mBvܩpu/K.!KϷ@=Y]5 4FB}|[>z„ pqqÕ={ aaaسg^ϹL)W̙3񁥥%\Uu-ǎ|쌓'O"$$DdɒK} 0!j"u1)Dž={v޽_ƁpͥݺuRb]g˵1Jgxwxt'Nݻ~ڵ]v...+t$k2KX,_uѣB111jE^^&N~ <III Z4""OOO… Ç~7 &888X@1[]o `"mo6-# ~7@Y^^&ٺu+&O sssaÆ߿?L 20g5 :HӝΝ;-,,|-[kRUCb1D"Cq}V޳gܹpnڵrڵkW -sGJuT< won߾zb_zC Q-//ȑ#b` 11=Bnn.cD:6mySSS ts...]O?9s02kGB_S=|D8S4Œ3\qAh"ʕ+\]]D2JzZ>!uJXB^z!11Q`9s@mlvdy7nv ǏvuGau%2ҭ @J&?e !Z.;=))IbPƪ^X[[c N>DGGNosڵk .EDD>*R&rm#?Tɵlt`0 Gމ' pH"ڷox ,,,Tw.YYY˗/K塨b?mur)"&S.*1Iyy9|}}Ap1bI~;w.Gn\W-ܼ);5U" 6͐f 7Vy ȑ# f#** bCb޽033S=Bbb"(* D@@cz ϰm6w֬K2o IDATYXlx<***'OWjܠ*yi#B kDW>N0` )wot_vKZi]X!>,)#[Qׯu.֭[F~ǍGD"!'666_`8~Nl'qx 1 ɵyyy=e =l6VK6m]NN۷oO?~<@4ݨN N\ՉXt…1bN's[c?YXQ gQQ%Bi62eE ՉQM0tk0KnjY.)REm~oXd"HHJJ 9p?>2d'z P2j(dLqOg[x Ztt}TY` T'x Atq@5{[`gaDfΜIOkڒݻiӦ_~DDD0^BbccrBCC[WntdT3vQ X"dBȑ#xp*0MEGGEԂ>qqqԩNf߾}I ,jڢo dĉwG6$$lmmM rxr <l6BP徴x5 _~tdeejNh=zT ff&rTd:hk*2D /rrrZlQY%((_VV&3S_{+ tnze5Yr%&L///?\vw>Ԫ^ ֍ 0!Rp6 &|*noJYf-ٸqc_www#G ""B0 &ĉñcǰn:~w055EEEpw~`޽]F5>?OgZ(2*Mj9PO``WtYiUU8::~  ۪wJ5ZKSt@SNܹaFFFiDU+ǺꀡyiXM67ZjE51ODGZZRRRӧsV^LYt%QpRRa+0L^ ybXُZlޛ<==aaaA dr(//GYYʨcu+++CVV={T\xq{VUX [ w mPS*̘1ޙ0aB{hiˠ;D T\ggg#""B5HQ>۷+L" )ߺυvŴ$!Alٲ"**jz l߾Ǐ nݺӧ*96oٳ2)Nm۶ǏTE;Ϋ2 XXX]+Bwzp\*F^:Lnј9s&E%w…mNzdQiY"hNNNGXXѾ}{x<󆆆W" 99׮]õkpu<~Xi^)9ڶm]2ߜw؁˗cÆ x9cǎU lllyfEYtttY(ppBs~bׯ_ǠAPYY}h"TŋGX,{@&\.| Cϒ` dff5}FzzzCP"Ab:( 蠡c ٳG~wXr8:Ͻl4!X\LƦ"C I A;|GgΜlٲ}/ٻw/Ǝ2zhѢhW趥"##/^> ]\\`ddpn˖-Gvڻ,gR}n Dd4DcBIRǕ&cmb200dI_e9)iiiP.LJx}G맲)f,HJkR<~X%HIIyh ({/ԅ @]̔oر},--Fyՠn_4.4SWrڪNQ@>O]re>}iٲegXL****LMM-GRHLLWcbbn߿_6i*]bǎq\^qq1"##QTT$C 0%vk .;;ۇf]v)\TVVD PtСC_affflٲ'N< ^MWSb!# TPHOOχҗ#%%HMMU8 v}%ЪU+j/<< U n?i$L4 yyyqL%?>O> Ÿa `̃rZ ua 2h~'p >|'N@iii EDD HF~z8y^CG B,ﰳSX" 55}6MCfq=ܻwO=+++t;vDNЩS')Zh033321SUVKJ*AOƀ`s,--fiiic``0b=z4|>Μ9ÇҥKHKKk0cСx`iiI'ŎIAm(1#fTTԬE mllА7h 4PZZSHHHP p8߾|D@bPNTQ\\\~Ǐ'رqqqq  y/U9 ~M^U9E)>0x~pY/` ?kj"oIll,akhh>/T׀4RR"|lBHPmg ۷/UT7yU%YT{ӪU++({ԱY|.5[B%.CEELLL؃ _J_OtuZk`P@kD! I?@d>D2`_J0n:ɓ'7վƟ%y7`5,h*bXXYY)*;wJ'O\FrNۅ۷o?ȑ#g͚ճe˖x<ssst ݺuP]044D\\BBB0m4ǣ!!! W_}O?Tgee]t)СC)G͔H$B[My`c777#[[[P(,(*>uTΝ; zu^{oSVVZ9ǃ=`mmMeVVV044ǣDŽ*[>\vQTT"R{q~~~)Ϟ= Bx}:P C Ǎ{v6-\]]]LLLV155-LMMabbB5GAEEQQQQׯ_ all,ggg+0HR[&1]L7nhir vrCuJy㮼N!RV:ʟH$,^vܲ(X׸/r.744244UWMMM񱌌 !ä Xrg5 yO|S'gZp .&wQWC81V௿FFFp8clv$ M !VVV`Xvǎxqƕ 4>VVV B!G$qìKbcc1tP۷o_Bzٳ*2!_qbbb̜93 fY,ؘdiggJ IDATgcjjj 0|02&X,3nLLLЧODԢ_uݻ+5X}CrcIO9-2Z.Cg|@_R 0R@ZNu>}f`+{#++ /_1=z"BB|j;;;u {wwwlX,3Bo֭[C)iiiOƨQ˖-ݻwKی3p1lذ~~~0mŋDmYYY}lR5G%vAAAp8lmmرcO?eÆ ۖ.]ZAP6ܒw^k6ƒ%K0&7MLLХKt҅:~z+fB֭ݤJ*Ȥdʬ3ӠlݻwsC3T3)( __7;Ґ gggDDD(ӧOǣG9^&ǫW`oo &[@éXhb3qttX\0{0843.TUU?^ɬ3MQV\0iXrP(‹7hȺ4T10]' 4*< cƌT+65dYS@`k*WUoH$p:!8t݋ .Ԉ(??/_˗xmmm-^1cL thS߿W^1R{QztҥK: 'Nl?WLBk4F%j>277% oɁM###+شi>sܹs3f nݺ m3 d2h={zAAx59{,^A5P(9)9Pfx BC BPt 2?:AS@ P\7[ h$"8IB^6lPK x355Ŵip9wfԩSػw/\.un̘1WH 8uN:ՠ}Ç;w.͛1cᅦޔs⯪q( Ҳ?^IEvޚ5"$$666(((P׮]CDD #0T51RI< 3I~ޚЫW/gΜ1cЮ];o-ژ4 04 #,~z0E 0:D}* L ^3#0`@ƍp8|l߾ԲaC3+#0 p!8!WbС׹]^^>L5\.J2DuBСCشi>VZtpss(7Yr{ 8nHA/\n/.{*Vb}Ǝ'BLzC׭8^ŊӞ)zN"& 0 Qgꦼr ` !  Y`ggg`nn'Ol[WCc8Ǫ9DƘ Ũf͚Gj̕eέE+V"5R0ˏ&`웮dJSjjE\ܸqCBB衔Fvv6cl񁯯/бcG+ ܹsرc[KKØfix:022 .<L>>*) ` ul,]j|NNN͊!MUj^h~0dS`NТoȐ@JҖM,a/e\YYK.5&DJ]]TVVƘo׮O?ƍ=z [[[1?^PNǍ7GGGWM0c ڌ>\.{All,\D'g9RRRp"44ڵ+`kk"Hp91aaazC Kq8p/{p%ܻw)))^3 T-UF! hPp IΜ9O?Zj`WLE dxL2eYT  \^+wduܹ3Dv $y\hwҷ* ֑UXX;w .uRW -h}.0,33dHL^l<7f|rٳm6fep8>8%?< D( `s8qs8;;7y@("..qqqXn%66#F;fMRn̳B\xlr8߿/^ŋHAVVpy1p p*?b`ʔ)>˖-S,,={^,˻ك,-Z#b({*E0Q H$`BVX,6`aH*Xs+P.ڵkoE6[uaaa---[O7n^ܹs)"KKKرCILN:"6Bm2hc3ݻwgXVp֭流2 1NNN.G i꬘ׯ3֎JKKkowDÇغu늊pmt{[l- NaA2`(̃ŋ@ \MC2 xJvA?fR`6&666n @)5LtoŢk׮Eeee|JECF,֬YCy/n޼ٳgagg+VTY?nݺ*  ծT%W@uXLnݚ quuŏ?(///KNNV510Y=tAY?`NW&"Ք{wf`tm.Ҟ]Cԫ5C\ʁ &ppJ}=LUD5A fy#Px~W<4)FFF?1k,wI~O? eeeGu.4Zj9Ew/^^(ŋo߾h&]?Fdd$,XX48Ppe[6Zn]gM]dhB&P,uvBWsTLb꼜u" 0 lƐUfLLI߀*ӣF2*Do (++ѣG^VSk+ 7nܘݭ[^~~~Ƴgd޽{cժUh߾=رcw rbbb2D"ѡ]v 6y&>3:_"""0~x͛c2228'}W&7WFE٭oͻ =}N> }ܾ}{^rؼyxھ|/``v1W˲N+s۶m #=y}DOOO  xIӴΝ-[,x_`0 Dy,$ӗmD8؜s_BhѺuҥK /">|~[r`ccbEV60׶v6mW:u6I$^5x|>*V\Y|ښJb +aǡ`ݺuAn޼y?i6O<Ē<<ŐLӄW… `xx|>|>hmm@ D"F'BP4 EGGGѡ`ɿqƆkYCC2o ŋ'|dld|oӗ])X،2PFD:s=ZZZZdɪ&gKq 8C$zF!Li` @4x˻v̾M_}$1r O0t]. $`EH0XT4_O>dc;@o+VxXbɈXY8 H$Oٞ={>;qD 7-`6.f5WijjZt555UUUTٺ']g]9}(\XDQꫯz7lذa] ߆ac7orJʕ+ѱ$8C5Mo|-++B[ZZ:aбF.pa2`˴d-M_>ڴiS?bݺuMTUU|V nY=<<<100\z5r?J̖yScS;Et*F`Z/~Go޼@ poAH&0888ui_UÌ2hjj&hllzY><<;yǎD"N l!BR &=_W^=ڣ> _|Bww7<}aI >*j111/_^@}9ظq#I0x ub{|> Vl--- '1lafʑ`ٷo7|('Nx]p!Z)Umذaիkkk+B((=0R~য়~:H$XVZ)W;w6ر嚦y4Mx<O<7{{{Ǻ:;;Gϟ?M|Bs=gϞ}b޽{1 N!I (4 B0pRŽlZohhXlYy]]]Ymmmyuu/_UUy;1 #511OLLhTFH$a=cccȈ>22 :;;'''My$Ai&A\ pI$*iF2Ammg]y+WaEmmmx<DBѲ,|PZZ:=_x1455ŋ7$7o ߸q# C===SN 9sfa p&[ %S *-HUUu7|_}ﷵΝ;! ZZZ G8I_$n4P|ct' ?~z۶mz^}1000.L IhsBe`===b ^R5-  CfRthU%޿ 3&l ɐ!3~7mٲeݻOS@rro,49,4)/F$2{9$C?!MZ(G4 y<*FFFH$;XsIA2L4R96*A L=d)xJnݺ_jժ%U-WUUUVVVV N+Yx\uVdpp0 ݡPggg?Fo2)E'+**sa}:t_y o \d8A0pP<#䏦i*a(aDBx\v&]K7n299YK/L&R4KL,IRT*,Km[m[M_ dlZ_L 2B((.\zmpl%A" 3dREA*H`:7рhX$#I k +=C .K0! }:;mΣ͈nINd*!%"7ׅ z,L'SWSSSٚ5k+V\|yE}}}Emmԫi~TUUU(I=&ґ,}||< PHGFF"L IDAT[nŃ`, &$Ʌ JE6g\k/$K]\Ȝj+mF4h R "BMG(0( RA6P9‰AYڵM^]ͰVE2-Opw7YCb&3 p-yxFC%MAYL0x 5 DC.u>$ Lr S8V kX  2RYkVK`ٗl4&K)e\ӣxsj\!Q*(:&PG q[9VȦB-&͘wXAa6z] /dxfC ;&s`#;ZKkS림J`l"ddOtvȴ(6{dz"Z(:śl7ddSl -EEM#vK2"KgEHR]!s1'Mv'Z!K|+/^d&'""!>'"iPm&xA6mAP(k0ho@|a$YΘ.\Ir}aS ;ͶHrt IJdڊ:`D%*y[ AbA2XKfGKJu ٪31ć,,vቕ (d' |^yݢu|% stL.hl`;Ax󋚖EuYB@^zٰy' /V:ۜfEpȅP6-QzEF m/hd9g) h?/ &}H*E13S*S0ꯜ~/۵H ǶVd^c> tIIȫ]9x@0䀤W V);Y-!`3H^'[@^_ی@%|!nAe!kY_{a CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs  tIME#f~ IDATxy\W}?W[WUZZ-uK-Kز-/c`& 㐁C! @ GHgB$cl6M,cZު-W[wUo*9ukWw~z^nT)_?_ hGOJi<d7ޅX6:k[=kLW X?ȯսٽ'n]v ٱlk]x3kĒfmvJ/ Z{qn @J@AQUZB8phc?Z}:{IM|FdfKY՘`22D#-QJ-uƒk~Y<:}K[ -0kW( QyFu @Wku4Go!Ɵ!?wOG 7f:^YrRkVA!Z@ZKfD]{ݥ l'~=h܃X;@:/G i 1j@Dja0E =8@BUn7t[ O9 \;oVlA#@K̍V҄Vh+adkII"᣽B/(XehXWHv}/(Taaw|#A8 X٣!n+&ċxg63=21Bae DZ)ed"Cdj} l!|y!$N"jY!CєDpOA&{@{"FVk7y}Id "Xڬm5TNsp 0i,*ΙJchB`kGswA 3XK2bU *=5[ ׇXGy(ώU=t&цNt} WϞ~ ݵP3,ՔvL$D^\AX=;M9{^ϗK`kex8gG#@ƫ_*T5[@(8Q|_5 x~iA,i'D3IT-NU~uh!9CsQ;hܱ'mk@i($&c=W>KԱV}&N*r/HӾWY &Etm͂/nMl`W'V ,b`7EYsd G9%?HdLVup.a;uQ=ZW-Q+vЊ(.DVu iUNsj(@#6SO+Sp~\c-B\6PsD~,nW P0~Hxb!"SiZU!bXͦl0eB;if*Θ4It#Ph<2ՇHv8S^dz#"޹DƢ o[!xĶO&}Ci6 KVV*$עFBšsT^2 d%`@{yb)Wi!UA aHbPD仲jVWY}KtԌm>@#-3c}g"nsBRXʪ%՚nOh5[F7S"ցEA`@EjN&q>h!u5j4964j5r +1# *cV,!TeMouNt™mVȡW܃0T;Tfj bȠTX XIcci{H; SáX;%05U5IJδ1(˂x/6V4V|IY=3-bi/˯ m u{1kzKOmЦ@++ _zƑB[ _Ǒv*fd+*AaV լMj )`|KcObǎ8K&lf<ʝGk:ko~IXkVmt&NGDPJH{x4yt])ei&*XugPVtAo㦛Ze4ϖ0t{@HQΕR}kd |}d2hH:О{bѹ|AYO8G&_,SZj4;3H)&gK3QuFW&1=3?|~7kGk%9ڇ"J_\+1N>Mif0]43>E&)s~Dz,++_BՕ@FU5neaŎ[6266Z].,CE) p 8v ߾o?cgٸq#vz/SI[s3[>m3ض]!t+CAw-@Ҁ@M|G100ƍ/޽l:u\Т͹)&́ڝcn>϶mxÍ7ىeIկaYV1+3GOw)%gΌnݺJu~)dϾ=?|qعs'W^y%T }GyI>lfhDPlG$%X͞ }݌~DK3"A99*Fʙ'sO>v+m|u]|7V ;NvɝJ-+u]%.`rz!JY<*LYG8֚ݻws饗"}<|'} ˲+䒋QJ* X,>Gg庫/uW^G]a;v4KM@/Mճa EEJzr\2g'|#b1*.B<}b8(8x Gpw5?Vm ep}z JN;fº9t檜lX`XR}L+'Hݻ;.q\H)8E\u]z)fffgodKnlX`ꌒ&+.k]`#'H&n2'OdÆ dЉ#ק'}91Fww77x#CC8KP,'*x9u$L?.#Q\+WHT#60\M(UlW GO}òln;6>] #YNoLqFnf6Uq`llÇ377ǵٳЋ_rkqք^~P@7 1 #w 7`#ϼh%w~klٲwZpBl NbddbE;ʨ ܈_XhH!*G LZuf~`$n',O.m 7%+Ga}?kx᭛g~~)p[n\ץX,Ő)9rG233C"gϥ/'$vWav.\eqS+i#㤝\#\ d9lr -K'~pWæ+cpf|q1 Ϯ?¦-n` % a`!\eddW^yQl՗`e׳7v ۊ G"hX)2q#`mه <~gy澻@Cm>ͦM%NrXp >RJ.:MﺉڰMJRDhgK9fA ժU"QUA6C. ;o׾|nNrnӓx ;yǡ)`{?D:?;O_Kw1.=ͻ~sA,П8ʓcH;I,s^؏gM sk./$E/,N4~ḬG>@gT&14>8n6Q4\_mݸVN:W_tahLl13BFσ}1qjX6}V FDIfY Md<l2+հDk?; OitF^t#~%!n<|]:gv»?'= KL f'u"YӘ)*14ZWr 7k)L*67ґ>7_kT_t&tg`o,2uYc狮mB=ُ|SKf_GbiL/`W2]!V*/Wu\Qho\Sy¶ݷ0:eT pyZ>G!gx#H Lw/랻g!QLL]6ꕖ׀  fZ4lX`źcEhMi!-`qkvP(I{[qR'?qN. $< g;a| P ξh*LJ[UmeShN]5!`B*2,TfkVWS\ <}d(ޝޝHi : o_7 SGŒt~ek̂hUD&{о*T:gJ:\!xQDVhTX%-ĩWfyݫ`G?ls'c,s?gG(C@g%}[;f<5W np=/XuȘa.ߙ囟}?9|4O>3|^5`Spk|8<<I+L6aq@#6A1w8Wk`WqY2b #6 +J[d= ^9s^7\ /c_A GHK _COu(K}+ D B ah L؝dK[{VhT NFozOQfT %sӯ|-MȜcqH)Ap]78f}㢫d |g0Tb~W " /3,V, Ү`DHb2f%(-ʿR|. C{{KLRT4p t|ᅴMQ,:!jr{ZBP "ɅI_@g0E*U@hE;, "(!CF,H ݈D"e޳ $BX Y{kmhm\ ggY?BkdH˲PZٳqO?>or$mod =X,VXI <7>PR9|92iW=* ,/x,ID/]2ݿ!w.LO8XK~]$vh+h"IQAp;|@ _ gN$"e ^ twuyƩKKD|ͳ,lr'N4j |¯?p ٻ:D6v!c6aŶ"@ETڙF;ӨiX"]sDV–#bfѩ.&"3%kB "[}(, prgKw ܫF.ݚm01mum찈gdbqɢg dxc%PϿ׽vV!a&6 HJ5#$36\ c*j{~&aou"a`;Bn6D~h+4n`XiV{^sG~?00/^k_窒8ZQbJozJfR|RL^럨@DIENDB`chessx-1.0.0/src/guess/misc.h000644 001750 001750 00000027046 12223260306 016637 0ustar00niklasniklas000000 000000 ////////////////////////////////////////////////////////////////////// // // FILE: misc.h // Miscellaneous routines (File I/O, etc) // // Part of: Scid (Shane's Chess Information Database) // Version: 3.5 // // Notice: Copyright (c) 2001-2003 Shane Hudson. All rights reserved. // // Author: Shane Hudson (sgh@users.sourceforge.net) // ////////////////////////////////////////////////////////////////////// #ifndef SCID_MISC_H #define SCID_MISC_H #include "common.h" #include "error.h" #include // For isspace(), etc namespace Guess { // Scid initialisation routine: this MUST be called before such things as // computing chess moves are done, since it sets up piece movement tables. // void scid_Init(); // ECO string routines // void eco_ToString(ecoT ecoCode, char * ecoStr, bool extensions = true); inline void eco_ToBasicString(ecoT ecoCode, char * ecoStr) { eco_ToString(ecoCode, ecoStr, false); } inline void eco_ToExtendedString(ecoT ecoCode, char * ecoStr) { eco_ToString(ecoCode, ecoStr, true); } ecoT eco_FromString(const char * ecoStr); ecoT eco_LastSubCode(ecoT ecoCode); ecoT eco_BasicCode(ecoT ecoCode); // String routines. Some are identical to ANSI standard functions, but // I have included them: // (a) to keep nice consistent naming comventions, e.g. strCopy. // (b) so stats can easily be kept by modifying the functions. // (c) so some can be made inline for speed if necessary. // // Currently, strLength() and strPrefix() are inline. // strCompare_INLINE() is an inline equivalent of strCompare(). // charIsSpace: // Return true if the char is whitespace, including ASCII-160 (a // non-breaking space, = 240 octal or A0 hex). inline bool charIsSpace(unsigned char ch) { return (isspace(ch) || ch == 160); } char * strDuplicate(const char * str); int strCompare(const char * s1, const char * s2); int strCaseCompare(const char * s1, const char * s2); int strCompareRound(const char * sleft, const char * sright); inline bool strEqual(const char * s1, const char * s2) { return (strCompare(s1, s2) == 0); } inline bool strCaseEqual(const char * s1, const char * s2) { return (strCaseCompare(s1, s2) == 0); } void strCopy(char * target, const char * original); void strCopyExclude(char * target, const char * original, const char * excludeChars); char * strAppend(char * target, const char * extra); char * strAppend(char * target, unsigned int u); char * strAppend(char * target, int i); char * strAppend(char * target, const char * s1, const char * s2); char * strAppend(char * target, const char * s1, const char * s2); char * strAppend(char * target, const char * s1, const char * s2, const char * s3); char * strAppend(char * target, const char * s1, const char * s2, const char * s4); unsigned int strPrefix(const char * s1, const char * s2); unsigned int strPad(char * target, const char * orig, int length, char pad); const char * strFirstChar(const char * target, char matchChar); const char * strLastChar(const char * target, char matchChar); void strStrip(char * str, char ch); static const char WHITESPACE[6] = " \t\r\n"; const char * strTrimLeft(const char * target, const char * trimChars); inline const char * strTrimLeft(const char * target) { return strTrimLeft(target, WHITESPACE); } unsigned int strTrimRight(char * target, const char * trimChars); inline unsigned int strTrimRight(char * target) { return strTrimRight(target, WHITESPACE); } unsigned int strTrimSuffix(char * target, char suffixChar); void strTrimDate(char * str); void strTrimMarkCodes(char * str); void strTrimMarkup(char * str); void strTrimSurname(char * str, unsigned int initials); inline void strTrimSurname(char * str) { strTrimSurname(str, 0); } const char * strFirstWord(const char * str); const char * strNextWord(const char * str); // strPlural: // Returns the empty string if its parameter is 1, or "s" otherwise. inline const char * strPlural(unsigned int x) { return (x == 1 ? "" : "s"); } unsigned int strSingleSpace(char * str); bool strIsAllWhitespace(const char * str); bool strIsUnknownName(const char * str); // strIsPrefix: returns true if prefix is a prefix of longStr. bool strIsPrefix(const char * prefix, const char * longStr); // strIsCasePrefix: like strIsPrefix, but case-insensitive. bool strIsCasePrefix(const char * prefix, const char * longStr); // strIsAlphaPrefix: like strIsPrefix, but case-insensitive and space // characters are ignored. bool strIsAlphaPrefix(const char * prefix, const char * longStr); // strIsSurnameOnly: returns true if a string appears to only // contain a surname. bool strIsSurnameOnly(const char * name); // strAlphaContains: returns true if longStr contains keyStr, // case-insensitive and ignoring spaces. strContains is similar but // is case-sensitive and does not ignore spaces. bool strAlphaContains(const char * longStr, const char * keyStr); bool strContains(const char * longStr, const char * keyStr); int strContainsIndex(const char * longStr, const char * keyStr); bool strGetBoolean(const char * str); int strGetInteger(const char * str); unsigned int strGetUnsigned(const char * str); void strGetIntegers(const char * str, int * results, unsigned int nResults); void strGetUnsigneds(const char * str, unsigned int * results, unsigned int nResults); void strGetBooleans(const char * str, bool * results, unsigned int nResults); resultT strGetResult(const char * str); typedef unsigned int flagT; const flagT FLAG_EMPTY = 0; const flagT FLAG_YES = 1; const flagT FLAG_NO = 2; const flagT FLAG_BOTH = 3; inline bool flag_Yes(flagT t) { return ((t & FLAG_YES) != 0); } inline bool flag_No(flagT t) { return ((t & FLAG_NO) != 0); } flagT strGetFlag(const char * str); squareT strGetSquare(const char * str); inline unsigned int strTrimFileSuffix(char * target) { return strTrimSuffix(target, '.'); } inline const char * strFileSuffix(const char * target) { return strLastChar(target, '.'); } int strUniqueExactMatch(const char * keyStr, const char ** strTable, bool exact); inline int strUniqueMatch(const char * keyStr, const char ** strTable) { return strUniqueExactMatch(keyStr, strTable, false); } inline int strExactMatch(const char * keyStr, const char ** strTable) { return strUniqueExactMatch(keyStr, strTable, true); } inline bool strContainsChar(const char * str, char ch) { while(*str) { if(*str == ch) { return true; } str++; } return false; } inline int strCompare_INLINE(const char *s1, const char *s2) { while(1) { if(*s1 != *s2) { return ((int) * s1) - ((int) * s2); } if(*s1 == 0) { break; } s1++; s2++; } return 0; } inline unsigned int strLength(const char * str) { ASSERT(str != NULL); unsigned int len = 0; while(*str != 0) { len++; str++; } return len; } ////////////////////////////////////////////////////////////////////// // MATH functions //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // log2(): Returns logarithm (base 2) of the integer x. // log2(0 or 1) = 0, log2(2 or 3) = 1, // log2(4/5/6/7) = 2, etc. // inline unsigned int log2(unsigned int x) { unsigned int result = 0; x = x >> 1; while(x) { result++; x = x >> 1; } return result; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // isPowerOf2(): // Fast test for a power of two. Returns true (nonzero) only // if x is a power of two (0, 1, 2, 4, 8, 16, etc). // inline unsigned int isPowerOf2(unsigned int x) { return ((x & (x - 1)) == 0); } ////////////////////////////////////////////////////////////////////// // FILE I/O Routines. unsigned int fileSize(const char * name, const char * suffix); unsigned int rawFileSize(const char * name); unsigned int gzipFileSize(const char * name); bool fileExists(const char * fname, const char * suffix); errorT renameFile(const char * oldName, const char * newName, const char * suffix); errorT removeFile(const char * fname, const char * suffix); errorT createFile(const char * fname, const char * suffix); errorT writeString(FILE * fp, char * str, unsigned int length); errorT readString(FILE * fp, char * str, unsigned int length); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // writeOneByte(), readOneByte() inline errorT writeOneByte(FILE * fp, unsigned char value) { ASSERT(fp != NULL); return (putc(value, fp) == EOF) ? ERROR_FileWrite : OK; } inline unsigned char readOneByte(FILE * fp) { ASSERT(fp != NULL); return (unsigned char) getc(fp); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // writeTwoBytes(), readTwoBytes() inline errorT writeTwoBytes(FILE * fp, unsigned int value) { ASSERT(fp != NULL); int result; int v = (value >> 8) & 255; putc(v, fp); v = value & 255; result = putc(v, fp); return (result == EOF ? ERROR_FileWrite : OK); } inline unsigned int readTwoBytes(FILE *fp) { ASSERT(fp != NULL); unsigned int v = getc(fp); v = v << 8; v += getc(fp); return v; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!! // writeThreeBytes(), readThreeBytes() inline errorT writeThreeBytes(FILE * fp, unsigned int value) { ASSERT(fp != NULL); int result; int v = (value >> 16) & 255; putc(v, fp); v = (value >> 8) & 255; putc(v, fp); v = value & 255; result = putc(v, fp); return (result == EOF ? ERROR_FileWrite : OK); } inline unsigned int readThreeBytes(FILE * fp) { ASSERT(fp != NULL); unsigned int v = getc(fp); v = v << 8; v += (unsigned int) getc(fp); v = v << 8; v += (unsigned int) getc(fp); return v; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // writeFourBytes(), readFourBytes() inline errorT writeFourBytes(FILE * fp, unsigned int value) { ASSERT(fp != NULL); int result; unsigned int v = (value >> 24) & 255; putc(v, fp); v = (value >> 16) & 255; putc(v, fp); v = (value >> 8) & 255; putc(v, fp); v = value & 255; result = putc(v, fp); return (result == EOF ? ERROR_FileWrite : OK); } inline unsigned int readFourBytes(FILE * fp) { ASSERT(fp != NULL); unsigned int v = getc(fp); v = v << 8; v += (unsigned int) getc(fp); v = v << 8; v += (unsigned int) getc(fp); v = v << 8; v += (unsigned int) getc(fp); return v; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // readCompactUint, writeCompactUint: // Read/write an unsigned int using a variable number // of bytes: 1 for 0-127, 2 for 128-16383, etc. inline errorT writeCompactUint(FILE * fp, unsigned int value) { ASSERT(fp != NULL); int result; while(true) { if(value < 128) { result = putc(value, fp); break; } putc((value & 127) | 128, fp); value = value >> 7; } return (result == EOF ? ERROR_FileWrite : OK); } inline unsigned int readCompactUint(FILE * fp) { ASSERT(fp != NULL); unsigned int v = 0; unsigned int bitIndex = 0; while(true) { unsigned int b = (unsigned int) getc(fp); v = v | ((b & 127) << bitIndex); if(!(b & 128)) { break; } bitIndex += 7; } return v; } } // End namespace Guess #endif // #ifdef SCID_MISC_H ////////////////////////////////////////////////////////////////////// // EOF: misc.h ////////////////////////////////////////////////////////////////////// chessx-1.0.0/data/themes/shadow/berlin.png000644 001750 001750 00000230245 10633464147 021273 0ustar00niklasniklas000000 000000 PNG  IHDR4RsBIT|d pHYs66BtEXtSoftwarewww.inkscape.org< IDATx]y\.,7""} xk@QyߦeG24fhx摨(7._ϋegygy> C 2dȐ!C ey7@ 2dȐ!C 2!*# C 2dȐQ 322XRލP`yy7B 2dȨp*ȐQp0x"10 ^^+ǶȐ!C CFUwsU_sd8 j \2dȐ!Y!*C8ʚ00iiiHKKC`=7˱m2iʯ92dȐؐ5229GCd"&&QQQHHHο`iy5N`t,Ȑ!CFE`ȨpsҥKܱ 3Ua\$$$ȕ{ ]UGO;K+dȐ!@f0dTe )) L*e \p`2@U\ʭ52N: ٜ`Q_dpL 'jHIIATT.^ȝ yCYY޽{6a.8ܻw111pwh.(e2ڵk@ my6JF->.6HpL2 2!*#55&L-7 `.̴"pe9P(tH˗e3 70F"T 77׼|3 `z CF`Ȩ4g2 :n!77 l9T*i4wO!ɌFD{x^ӧOseGʋB }v̙3z?<==b…9`JF$SUMDD;w$d{<Pbb"qj !l,ydLHGDJ͛79jҤ J /sp> GrynT|:IDG_-󲰢r6jd[""tK 4x`.%^ƍ`A*Lv#Y!*bT{JvQQXZ)X4B 7qAΧ ::7Q#C!d:MB4lDPP6mj3ÇK[0DsAp;Za,$M*˪2 3gb„ RVqMt ۷o(ʧ;dᔌ*Q!0'l]\\ fR710fx4hDZc֘dDGGʕ+oow^Y,0Jjݻw]xdᔌ*QaU!}NVVdH_EzpAԩSGt$L߼0e2$ y^T(Dlܹ B RympLXtɓ'Ni@nn.qY#33[lAppILr: S-?-sCF%`ȨʰLכoC-d򁈹6BXc2޽h\z8/))-12Qq ]0T_)a䍤" @3gn޼irrʔ)8s bbbnr#GĥKmr_~_ pqqjժZ pJF`Ȩ(DJl>>>oϭV3䏅`4 /!\ԭ[BHHHd:u̻y`LP!hCfCp0`@Lגɐ0 XzɉڵkcٲeP*oݱfj˖-( u~CmNNɨYPi5m N @Wvةnaq7n09hٲ%|}}HOO!CnU@ BADdgat钨P:upA\1dDGG#%%ܝ;wCaÆ yڵkԠA0L@P@Lhkx"rssWWNB¦sK.=(]Ng:f̘OO>M4СCyf˗777xyy -`sF69"B@#u"~ zc \W/ d{l$W\M#(H:F&M())5j$f͚ty:rĉ^0J<e%5]>~ʔ)f3Ə/YB 65kcS@u^>FKFÉ*7իW#GHlaj`B/oo0c\JD'"ZvhC%ŋEu|͚5KKKCΝ/ cju/-nݺ r@no3fH\f ~`̙ظqBU0~x@NNN>ŋ0M'G*=Dn{VCRu4IF =s2?#>>^tq%LUR%;*{H?>ǮÜ9s N}:waݻTQZ5Zv%]%"K(>>z׀!P2Hy*'$^ӧO)22 EӤIat}j۶mU^f̘A/^$stsrr"屵;\Ϙ1x{q2 ^/ؼy`im[hQf.ɌЌNS_S5 cP%0ֵ 3dD{e#?"u Dw^* ,Y"&"'N#lm3cB8.8 +X_pڵkW쾠iӦt)4+,,={Vno^'?3هj&/2(IԛN/^ɓ'S@@@ǜ "̤\GTT}wTTT$F޿ae]T-ӭ1-uqי3ɉ 4/^`h17mKJ!!EDNvG/]t8w`cX&`0:0Kv,FDkH+_ڷoh/_N%رcEu$|H111%ߟfϞMׯ_VUj?~[jԀnsnXthme.n߾Pnq`o$JٔѳfC5GDj_a\X3P(X@XZ2|{ X}_Yh%I 33S"\r\\\LW; !̵4˗?b֬Yk4}jW&>QZliLQQN8a7zj/BoLj RlqΝ`/0X{JtJ:OH_^s￱pBxQ(_>ڶm+Jɓ'vZl۶ Vw.]e˖aXh*z=h>ܻw灍1o+c>d̞=* f`ŭ[۷o"55UQ06͉ IY6f`k)#gӧѫW/8;;];wy00DŽc\ %e~{Z=30Yؿ? jFW$OË/hr-rk1;#͛CsnY#^XsZ,Z-VX}'Sg϶ =[!lUPqHNN0ƍVq  sHi0k4i2::sZ ݶvO=>srl۶`pM L:]cF9kMBDDk֬yn׮;vLhBDDc .nߐ|LF-.8-&"h4>5k֤/RRRyA?5lPT>$$>|HDD[ /LřUXr`0B8M$t8X-pWH`;pU \[o%˯E >?`(` P4yyyVaKDTC"' M?XbWQ_9s/^ī Z0pH٢=uOO6K9;jL4WP,_ ۵p1MCXz5-Z @Y+n///|g7n:v숻wZn5q{yM(t~;wNt駟.N:< :6iҤ=+`Z ̓.oŘ v^J]QRz FIq5ׯ_ 6 &&[y|U%̵\_޾}:wlqܭ[7z'777zꩧ>Kj.겳_|ykAT ba"}||}  c?Q̙_߻wﮆ;@`73,E;BDD{|"l#>LĒ#66o:z(4tb-CV n:#>Z^J% eOӸ]8zxx0VPPvv6?hgMK^8,U( FeVu8Q{!&j5%_+7O`&M}vjXV/cԨQxwfIXQQ^y`ѢEP(CBBφ 3ҌJͨ`1XFv>ڕ+WO?!..GElyT4k K.EwƬYIۑ8`Qbbb0|pjZٽqݷnݺtƍ?SN? TVq}\._ƍBX((o1[U} (0aB_/\)[/"t+W\ S̯Xةb+Sl36k׮8wvލ3g௿ٳgBDGG#66QQQ%jOwruu)=<<4EnnnEnnnE...Z{޽Zn䵡<~GRբ+1+KD̄' T`sR f­A0-e0j5:tXuX.˟{x{{?:Na2c7 f8?P?Lk׮!::IIIG?;wxgˬ~) ѣG#99YŋQPP˗kppVZ S D%Wf:8r>#/( Ă 0qDT8޽{cX`Ő ==۷oQF 9ǏGDD ڵkj4\\\6. Yh󈋋SO=S> 8OkMxc0i!N:eSΜ9"B@ӦM[8 SK/ZsVGvv6֯_#!!{g$k`ڡj Ӑ牢իcܸq# N;w }5xyyՙl1zg":n|ZZ'TV:W^_Wt]pp0~ݺu+ Ph6fT IDAT,@DMܚfR*$SC!ʊfK#)UvލmJVh0rHhZQF@@ۇc…eVZB[Jүk׮;o{С` ]G3c0vŒ3pƍWZjVZ BZPZ5xyy ر#/=*Xr%O˗/CBB!##W\իWڵ+Dtŋ=[hqr('x"ͮy}!!!-[RJ=#z Ν;EO:Fǧ9k6w=,k9;;ODa-Ia<¹R5 0SXOB0D=zGşY@0J}IAD% 4D5ҥ unݺ^zhR7:99kcH8 o>:z ggʳ3f YТE"LckGE``Mqc0D]C=aa`QEjI<$ؕQL)ebb"HJ|||\RhӦM%G}dU=vXjDDh| aL#LXH(((_~f-3oߞfΜI;v0ItTʢ~}]VvO2Esֆt7nVQu֭P ^6yxxt„ 8<|patpL7'$mϞ=I`y晁b6Q`;"v4Fz?%,"^T,hj {.pԆ:>L/V#ˣm ܹsW ̬gEX7T*mW]^Xrʰa FaaṩS#@T6D'(xbN*K;w|M\h;?c \[g^|l+6}I~UՔ!{aX/ )xgLD5,^XrSܹ3?_}[`ܟ2lLᐎRTT:w}ddq|Zs $t7>Di~{.ksK6?,vhт>C^V_~~`+:vLJ"""SNTfM^~e`仁5˝TӰUH\f0 `y0&9Y XUKD7hNNNk׮bR>pe5k֐B(-\/ D<_FEb2y rww!mذ!-^޽[^ڰh4w׬Y lY}RyyyǷ#M$[ODqF[o񝖘Lnmxgy[Jn䈤mF!"SNm2ݽ(H'S5l0O^DDt϶c""t ,**!Gx""{ذaD@rr2ܹ#SN;J C54ӼyxZt9޽ 6lү_0(,s&G! i30I!ngFGѣ-%qԩ:vHxxx{9Z-"""PTTmAj'N}||pĉn¹s_~ANNŲoFll,6l؀["44*_LḺWiԨUeq4Lڸq#WvUZ SNEjO>ntRT܀>v^d D߹s'mذ1s4`:y [ᇶbcҥ=vX͛7ɈھvZةS':wz>Us;&?^z322s#K#ZN:M8RH^p-qtDԳIDTTTDV Jiii f]ޗM =DD?d.\ǻQF'O4h"Xg xL5p…gk^|EմiS+W32<_j`rfn@D9D$NDT捊r7j4|RTV"22-[F7nܠB.]DyTyDu۷TڙK| â#Pz>3558V|8_Onn55uᝯkB ߉@0)bpCADXKrͿYFŋr7MJJݻ[탡CҥK3g~/#չsgQ]h]v&LP,C+igC"d&DTu؊+ϦGRoc0߭W_}1ݶm0`<o Q.&Ryyyyfyܺ\ T1̥Kh8$04ݡx 6mB֭q})S ** jr2e{oDj9| Q>EMO>dŎ [͢7;vdp]ӧߩYf$àA,=&Nz oݻ>}cRGDt8w<==|f28hX7b4hJ'|2Yf b"=ztsN>-cǎ&sSNشiI -[lᔹyrӦM\\\z5k,dp%ͭ9L 'qf/z2/m`0k,DEEq[mH 0>A!##CpTT-[H5'%KL߿dggKf'mP~}|W3g,X[JYn?_jRyzz. vwwV;| 0c \R+w>}pcATB#==wÇg>||bpcŊr ~`Сo޼9w{!1.K+Ƙؑ{I`X!>tGJJ jJwh0* ,9^{/w$A0\¶(2eA?1Z-z]Hj.rrr2{```;wճ{n0~sX\A\7onb2DD/>F5J^xX. Baam`y(ZI ߗ9=|}}Eu͟?d%y8SHݽ{x? Ӿ'XZ.FÌMD,|?),,L43halu VF'o&UXXؐ Q\iT;hUDDt1ɼ&3%,%)u63+RkȞHLLN:Y?͚5{]:ƈc9Qԁ :&N(ُnnnSzzz4c G| ^۴iS+`8О  I޺u7n,wU "6md?xzzRFF$%6MƢ$*Id'EVSbb{`+sOo3"((hLRR\k.ɏTbJEo&"}0n 8{j)f,7 sqk={CDT+ +Yzy?!Co߾7ۀm𛁙Lիu۷dZO>'OR qƵD,rąN`96 73 !I9 :TEӨ >^apl!>!ѩS[Yʕ+Th׮F.0}tQ}O%hh޼y3)33<:s̓0&nQGVg/r'+\ZճgOsH~\ڵ+=|ҥKc `p>qrEg2adCDs~_>ɪ*ϗ {=ʕ+( !ξ`1ŵgϞx}[={zpl@@III \= JE~-nZtw./ZzumM0CTmqDDi&@j`":8|’ںE#k׮qcff nFVNDeQ=\=sDEEʎ3??r0:W1_͛L۳gd͞=FF&&&ni%9p۷oa͛MY1a{TXDDvZ쵯:j׮goӦW`K@ @rg8Vh(';k0իSs-~q٨[.ܿ} t>u?cСh4&uT*|75j ''kFVV_FPÇBvv޳Upkל};uy oߎ!Ciڑ?pdv=%|ׯ_X U*PXX(:ၤ$T^w=Vv`(]T7UHx!q…/Zh 0~?{Blݺ}{ ExNNZj[ILLD}B80 @"8YSjNOOG֭q]QS>R}????b˖-=z1dffٹTj+KtnСضm ##cC5f!wDǛ۷/~g|222жm[&ك>}wy'}mn('{%^a uVF$:th0h0, `XÞ+CMD3űcǨZjpJKhVYHILO?͗O'( T{~'Qf|j۶dj:<_?8 mRڵ_uWsΝ,زeRP;FDD{L`8n WY{=Bf???JIIN< &uPi]dYf4j(R%K^O8q,X.`fE]UHe_/%Ľ{$~""JII`rssoY@/9Α<99 h`Eigx… Z/_/yj}`\ c ӱ2'[K{:TᩥLW\iӵ?ڧz-.iiiԬY3~rAfK뇝אrжmDE 'OիW pڵMaLYuEȐ`,ݻ' O׬Y3;6t䄦Mz^l8 2 .0308pzÇE###ϯxxW":~I 5(x#$$puu!:WTT'|Ν;C]N<9#88 ܹÆ \lڴ #Gݺukѱgꀍ Ď ^^~i8ܿBxxxZn!%0駟 Bꫯ S&k8ԬY 4xxx8A֭ P0qDkNۻ!Lo!syϞ=GJ;v5kvʅ॔?DJb uݺu÷~ZݻV=Ӗ~~~طo|||DMK;u4Re7Pt:̛7OtrѢEk:taÆqv [nFy씰^2W6AU:n/ÇE+V<GXV=zH%Cڳg.h8x0Xn mmk0iT-0BE`xk׮]u)Re8))0KU0o`v!/jeʠJ??%$>ܔ{5[nx{4iiLú,Xx $<=}+Em'Lw >6lgO,tVwjYw4֜7nYAxLYTTtH:y=s3Ft͠A|^4il0AUP IDATwD,|S7ٳ9^[n_0_^`>ON4MAA)=wW%Tk6`|UDF @CJ]lYKȎ=ZF-/\s߿?_fƍ},=?=(hÆ ~iӦMNx(Wμk/K6L5^0Fs)WqBh/^ hժ:.\6+MsMgC𛷯PE/`||4htTTgwAECǎ%?rcQj˫ n_:^:$CLL WÇ\|1bIqoI}Yh1@˖-Qzu pqqyy˖-qj )Bh0Ͱ$aaa aŊJ74bĈ gg$'3vCXOTTT{ k֬V\)zP4kLn`( ň#B!P8qbڵkD@\\ "/i'`PAZT-F0@ ׯGzzo-' ) FVVdF!nnnh߾D1c$ڵ׌w%H1سg /PfI_6m*=~8RRRZ c@KMLrc0\ E\tItQa`F3:1XpNqN"'TL&A29W5jZ`Ϟ=gxxxq:t<νCjL7V"giL+:|||'Uc28Ɏ;,27o\؂FB\Xi(q?0Ν;NٳFREvxrrX6&LpU*ae(`7nnneΟ?8@ddd_???WXm Ro߾o 7o3/ҳ ذ~zurZq DDDԇ/رbJU`9nnnٟF9!G\X2e@hx&OzYe hҤ^'ucǎPեֶu$M-ZQF%K4mT_t?3eژ޽{]R=x`رCґYCPPDǹ n`_ V~7I/%%fͲ+sa@q̅G,Kp ՐEEE>}: ć_vsssm'Nϫ9x aMo>^ߣGg@||hJE&c0|}}ԬYS{Q**NXߤIRyq}cC(ܜc{=MTC˖-oY7>Dzbm9!e"|NE~ݻu|HfGq I& ``رc`r<\bMm[R0js^zʼ1c\(iBR:uj?sPT4i1) `4۠AK.`ƍȑ#-jJ8p&Nw bš-hL¤̇-ZQ rpz>օ򀋋 M&:O? jРAG ͣ@5DDa\$Ki"P(LUnG(ZliݻwyiF&MjA{i0~S&bk0D*aӦMT i&ɝ ːb05Zm<[Ǟooo۷Ϫ96o, EP(a/!(KQz t_~%%ͭ`[jnMe$''I4QyMiӦUд< ԩcr15Μ9nݺmM6nJ?c~~0e,c.lXύyxxO>Ŷ,)Md&%u}2)Sy^z`La$orTH_{CPt:4srg0*7k~!e" d"`5z=&Nh1;)S_:$Q\d-WWWg4(߅G_`4\V$m6g2-E/0!U3)!;5-Ę1ciZG e+!U.==ׯ_GZD$ˣF]<ǧ^ݻwǍ7ljwXX͛g ͤ P8Q0_D'۷o%)3))MEQQfQͣ8bx7Xxa2$dffyczH(FD 1!ƥvu l+rZ Z)α[P\L<*@F#GbÆ g̘իWWGAq*\d,4^[% 31C= 05x,M4N0|p$%%,1,yyyY_v-&>|(rlg0Q~}qsf⣏>XGhh(z%yNJKh߿?^yt[# E3k֬fdcM8!/*(] `Nj|-?.1**^M+5H=#7o}||gvYV&B& 4;.+aa#C4B))[eb0B4J5*6=21 I4=< 0h l۶Mٳi BM/8&фʠY_E.]䄭[ڍxCJSa)AYnl3Y eZZ;]Zb0,Iedd=Μ9#2)&ݚL0vmɓ'[#)-MNNoru >D`,o!3uGQj $J^BU ?)D1_P" A Ez A RRHreenvv.<䲻73;y?T1^~ e ˪R&DJoȐ!\Sɓ0nla%О୞$ȶ9s nI. M2eʸ" Β&bIkYdUhϝ{oJJ :v4YD1>14` &"E'wF=['tJ ge;ǪWn0fIԮ]݉ǂ LiR`u> `̟?_J!CD-]23YO0<[߬R7cucUC%]F&m3#88X`_ԫW"W^5̴lٲ .Rb)k=-fYk׮YRV?mZ6c߾}/`8;K(\J0t:@iQ2uz^.w r{Z7`$%%Lʕ-Nto=tŋhٲ%bbb'.X}3ۖ+ViaҒp`?֒[<y8 ?1KO>ifN E.k׮aҥvp73P͛͛7Nd\ ̫V6~Ś,ir=u(xicy {.^X$ XI8/^,;vL֭[3o͚ݮ/\E09#t )s&)0ݐX(c۵k d駟0~x5{Rɿ֌3g9fv2 `O|1V~ܹ$Xgc@,``cbb-0mM=b=*A*TVZI^[.3G+VHh5 hkE7hѢYn`XRD&MǀUL&c%ڃܤÐGE^rŪ 84oڴqy Z0rBZRޅ Q(P4Cj=+@I.cʕ ĥKХK4lGFttS~םVpq6xlݺUz?oGzc̴oU1;!!!,YF%gm=,H<{L;#F*b_t=-/_ "0-``PP!Svm4ɞ\ΓLK5Ha`2M>VXSN =3-բp(c~dR@ R{[/ 3R뙹7nO>Y&va7o: ,R<ła">>>fbcc4ɽ߂޽{8sˊ;w2 @jժXCV]xXߓL|||m%aaae Ŋ3ej q(1(jZrd6y{%d2Vk:Kb 0f[nw~{LEGV8q\Rip01ڂQH #HKߵhт ɅEkEǴðaM6 2yݻwiP*RV1WY.)Z8N2gnΝ;e˖5]~>ASPh48yM%[nKV $R޽UVzBF\\*Us DoΝ wA,!&Hyl% 9` TT/Cر'Oo߾v#N>pA5Z2mڴ#aZ4`T(0oy>E.u< CF|-ZěU<}ǏGŊ/@ςz% ̓"2 'g"2;qss(f@X*U Ǐ>-gϞ6)J0+̧/[Ojլr:u*VZ\|)hR.\r̃L<) alÐ7rr9or\2 +36::7[}_~͛7gR-_riӦ/^LNB3AnOuA Vk"QeʔSՊšX^|֭[f :u*ʕ+EYm\z5VXa6;()wA3!{֭[nܹsf~}y/?yN 4'5km97+; `s@o1`c2\pk?$%2u|2waÆ1ɓ'G:tq0E4 HoRAAA  0*!UavOErr2fϞebΜ9HII}7"<<5jM>`Μ9 QcƌYh'ͬi.d̂yH͟?… Y6 VW&@xx8v̠N:a׮]6]<-- Ghh(f̘̫NI&8tv-GYzI0`#~رc׬YG9Mnh=zTUV&ںuY-mڃc ˖-̙3Z* M TZhaV`a6_[`#22RE05jdzvBC֎hv< ֺIPR~~ƍܹs[.W^aܹhժ (cǎ4hF>}M6R ѯ_?l۶8R(>}:n \F6~E۶m'FKBkH\|r#44TP'2LC oWT.~0p}ɲe`]#ɅVdsr:-aBL~~~~̊LwylIaÆ%S!8% 8eرc(Q$F޽{cڵ̋z_+Wȑ#𡴛y*Uyf={:t0;H=zC< D=wj6|pe˖˗n`ѢEX;Ç#$ԄRE`UfU%KY%ݺu,{4T*ԩ#yNVk-˱n:f{\\S!/n'&&.gX`ԭ[.Cz(PZg VBO `&wR GeƐe#F VѸq2e˖%&Ʋ`)g "&(ERJ}uqGba\rqXT^.Q'N@J't: <?m۶z0`ŀ߲ebո|2zLvcΜ9z^Tbƍc֬Yٸ]Ev,N vLrriEs ޽tud&^'_#^pNŚEY q֭(Y IDATi_V ZFDDأ!eQFݰJ,iF&&O-[2eGT* THuKePT[9= 222!M}E j`ro>3}Ia+lقQFao>>>yvڵksߵvځZ/xRaxVnR& 555<=+ʕ+%K2IIz*pJ±cǘ=Ǿ}P^=~HH~GcРAP(j]z):u9u 7oMdxDFFO>Lq뉠g5= 'lٲ+WtBSaСHNNѣ=&..h\\$pWPPtKoXqbw(Z3](kU֭+&"k6i;vlЖ4RQ TN$eOri `)Ҁ݇~… }Xd@f^z5k֠k׮(\0w۷8nݺcllӧOСCAdZ.H!6\:F||`1oR-jQY4H"8t萨mҤIh߾=Μ9#y… c޼yy&>cWQsaÆS[n5>>>w?(GƂ ЦM<{,;VP*E: QQQUƍn˰tR sb&OCx}UV]TaPTXp79U"44T͛7ܹsmj`C =Ɯ9@[Z-_QNׯN8!)HܹsG4?7͍?onb\X$@ BT ,X͛L`+F} ۋ`t4e5kĢE$޽{0 /o!J,,45`?Sֳ4lj)Y]ݝhC/_` 1tXl[ܽ{צ ) hѢ(\0)"Eϟ?dzgS<{ ߷^1l0̘1ǏǸqhذa;wT9sf?aq6qq3f,.]r -jvoM65{%h/_ҥtCg:\ wƍ/[֥Kl {AUTt> @o:h*( (|0hrJr2yc{+V`>S:Az=׼ys7hЀh4q͛7/` 5IkdS tv^z7n畔Gi4.88l_G޽wl_͛7ٴie2at}kiOAV$Ɔ+k69q9wYvVrU'p;v~kM6տ[\9kt'O X@1骹9ӂQx \.p;ZjfELRk.f L&8Sw9qС.͚5]PYr% *y1V1rHL6 AAA7nܸ_n[~sI[LL̋3g~=w9 BW_!o޼ X\h СCgA s"55Y81'8r`˱|r}z}1hZ?^HLL|v̙7$d I5#MCb\\>l} X1BCb\Кaxپ 2>|eRtVpFrqFhB\.\ǣGl2 ŋGdd$ݻ7\r>y|/^ P(E;vuǎU`0(a7gVDo3ʀ!|SyH… ( nP;҈i?F~޽ܹs||/W\YuٱcǏGFF^Ī^Ik#I\ggҤI@S<~l[` =b={0Z8U맟~:*rƙ&b$UA )RY#}wxg{4Ȃ{X^t)> ݹsK,f@ժUQ|yqYqu;V[noqwW!E8ѯ_?,f~~~:u*nݺ &d;!CVRЧO\zˣ0vXL0z p7o\(DC#p8` gxw ?Z`T*6mj=h@(+W(]o*Wu`СC*UnhnR,"h%J@2eΝ X@)zA8v?+d2f˗/cҥVߛAJJ wά3a۷vݬD[3]a4ZƤIpM5Jb…ڵ+RRRP(v-zaH"&k3Ù!9>E-͛}dw˖-Kݻ1,7)=Л88xIӻ 2&+b͒5ZbmfA ի/6maÆt N RacqcL֩S'‚! O5/%2(a 0}MbŊfI0r9 ZqƨZCςm۶_HY/JL8[)FDD`ƌHL47sL#Sz"ѵkW\zUpM6&AZ!F6A6  @^N޽{cǎVgx#Qpa,YGFDD3Ɵ]⯿J ׯ_tJJJѣG߆A~""댸 g|0 0pIquScժUKPtʒܤ"EN@Z6ȣnEEE1:))~N fd̼7uEݺu]$AŊ$qa6zA˨w3ƍx)㑣1tP߿!nԨSt׻vz ȩFYVGɓG1gHHH@׮]o>Vx>/[@rr򫯾񐔥1 C*v|GbXtG0=zcƌ(e`3> $&") :Cj̊edd >>UVE2eJZK.<&e JYbiOFOKY.H$:M \.wgS_~;cƌ|2L&+bzLcR91rbǨ#os (G+v+tr%$f GqO6 v$BBB޽{;,$&&">>^`ܽ{E)M2m^B&9r$bbbvZsN8pرjږ{a%ݻv1,Z5kߪC"@ƈ1-9s&S?aÆ9mق~gԯ_cǎ2oذ!!!oRJ,YdfttI2CIDAC,лjժ.n%YÓ@ @H4@gMb$ <+x-`pݺu -eV̚55kt3`s23ba(Km>M R?OzhN,%J06mSF084-3 nϟueޤ.=sƍ+VlҥKqy3aػw/M6APry/,ڵkh׮` >pCQQQWaq7W0#/bVGreLy$5j{>oQD 7AAA=lٲG!-K:d8W2<{ ^2;ݣLRʗ/@o~i] 6dFGՀ5i|{\nrΞ^8 dHVײT'•=RЊ=~x0+GÙq9 ,&MٳaME)q\JSSSc(]-[c/X4kL\h?C -x L#gx> %Kɓ'=\_>PP':yd>Fֱcǯjժ2rd)frTnQBx!]t ^v-b{%E[2,Y/,,M.K$'?15kk+V0Tq)9q\-q8q2^/r~trrqL< ϝ;wn5klܾ}{ZvjOV߾}F!zBL3.N -X0bccq[͙3ÇwZ- xaÆ{`ͩ,Ws2##KJYlY;v mڴڴiΜ9 6~ot ))):t֭[ V1uԟs޽ ,f ,I9K,B@FFO?t?p lwf1L:JctO(j1ɉS۷o_\xqq }>6o믿<#FH΃N>f?5nܘ{Ⅻq믂5kt|ʔ)` n:hiO5sDIA=Y#O7!!a"qZ8FM:dDnݸ˗/; pyynݚui>|ȵo^ɓ[f#F6! a3Z 05a=au rd:h2Q.R*UrK?[{A*лhѢUhO̊8d˼K!K2F.^htN:.BOzǝ[twAؼyhMw`0]-f( ޽Yf!44[둚*q)hHyɓ'7oy4hK.5(-Tz^ ,XN:թUV* ڢN 0/={mb111]62!,ػ|+k*ɹQMb| (۷?8RDTTv-#m6ԨQM(߿jժ#G09pׯpf;GcӦMZ*<; ..$&&>fw`.bخN 1$*1c&9* SL_r)8<<'0Wڵڷ$0,4TAԜHÇ/P(tJܖ IDATRR2|||/^|Mxt= 1p7"X&=9R1cƌJ  STU EUL0hmi\+V;wzD7Ky&55[nŪUpaR(z2 bcc'k׮@6m ˑ7o 4^~5jt B7w@,ׇZ6r ?~zq=4k .ȑ#:! @\\\#KmSvltrwvZUTm߾=.\}2y^ 6`Æ hԨ^z@vjZ&nܸ VĈHa۶mؾ}; I&1e{!557nŋ%8x`,YĴ]v￿{ 6kk8[ 0}:q<{쪀xfc֭غu+H"hܸ1իE`--- >ģG#Ϸo߶z5jk׮_DkL/ė_~0aaaț7/ˇ|>8~HHH@bb"=zX|8"##[Ӿ'N(Y$j׮] d=ُtf;E =&V^»L׹sgL8qgl1$0 VmP(dpx%>gϚ/^d j۶mB<.kǎXjNg՗ ڷo!C>ZvH#k֬)N`Woч8f̚5a\f V^7oZ<8~8ƍݻ#""͛7L&+0'dp/!YQq/_ľ})߭[7oPT7n Ǝ+xג%K`ʔ)ٳ'=r"͛_Zi{ ˂]Bٿr) mVϟ?۱}\Fu3йsgd2L6 Vœ9sq|$^Hrϟ?O"Cd]ƈ畎AiKլY5jpbS Dݱ~zqqq(Y$J* XVVC, .=tJ>EH0xrAap م ,ZJeE8x .] X&a͚5hݺݯ`f*V 8!!!le=(QOӧXj6o,juᑒkbڵ8|07oHC3M4y:;v̦d ݻXܺu~!6l`a(P>c<^xO?~)-zJ*P(v,D`mjZ{[2HJ4݅Ν;.Q4h3f@ǎj9C ue՘bR jAAA8W䂎DqS`jv#U 9s ,V,rI[Yqr8rwK! 0w۷ocŊ8yZC޽;9 À|2d4iVy&6mMbѢE#GX|q^K캓E ;w~'Nė_~$}E&M0h Iڳgϰk.ڵˑ[_M.Xlk/Yf$ØdA6l@rcϞ=طo>}jA&Yf>}:ڵk'yJ!C0h lذsux6 *}h߾=Zlu։F`$@]i$KvbS ,3gd2nݺcbbZb40X6>eNޅ=Kk`)O<4z Zۿr /_u֙r 2  DPP 6'|bBw}/'OW7G_ad"O<8p ;w`Xf ? E(dZ4XbPT>=ʗ/H(hPlYDFFb֬Y8t $djL@ [}/_xo(_<5kۣQFĊw^Ĭ ` z ZJe˖-sŵ)['E&p{n{CbbdnHvI dZ@\@h C9n8 U~hРׯz!o޼h@ƍݞ\&1vL&CVPxqQ!zbWjh;wFΝQd,_+((_|M-[~S\n 3%A[i`|Yܲ@t]t1KHH[pMț7/BBBPxqXb#F`Ĉ 0?~lb#h4+W˗Ghhj0Y!9J0N\4WL0 *@A^zz:J%/^nI5Ky]Z0Ő-Sz~),X`q @:uLdA(QSEQ N!GL2p˥ݕSyEҥQL)S׷{:YJ>}O>HKK۷qMcsΉNG/b f_"%,(Puֵ" Ơp}YEXB.`:y*Tȩq7,XI0ɃbŊi Ʌ{[0z=O0KjA\_~?DOdx0vXoߞ׋'OŋJec2Z0*.RǏǜ9sܲL <<"`|v48  /,&tR:ւeb# #LJ˗/&FF^ ,KL3FlTn90TD߾}Es˗=zGԸ+An ܹVž={j]`8pC2atÆ Cǎa$~0'Z3=!T^xЛ?eJC9x WeD2XJY5/\ qr/ }ӗȲK0FXAWnnR Q\ԨQwFpp3態pEZ 6lKD{ 1ˠ?DHHC2Ġj$ c45ԋZsc_qX M0k5MK0lJf>4 `={0 ފA75̣Nd/_ħ~0c^E['hFeJ} ~ 5qu`^ɀ-Z`Ϟ=ⅇٳٳ'v sNǧ"83U/TW^O : -p&7)Wbxه1`Y4u9 θ9x7[c?ā',A TNqي>QX@aXz5󄐐\v I3 f=wo[{[ljժ}NIɃw;" `ӦMg9-IIIƓ'O${%.\(yv4 -X(ྮ^d" /r'XbuPXAIq}Ĝ?$,8`Dl ƃpuGA*$iY~r@Q &0mܸ7ntZp?*T}QNW6`Mʺ6mڠM6NmĢEw^^;vruh` TBq]W7mq[NgHbNPdKt8>|"I*<\C*y! *߹MJ>N:AԷz0 Js(D TWynz"hdLj\UP(СCt _ft?伛%i ]-0O[-=Sz]-$Az,f̘&D\x&Sz]D)&€ 3TV  BQX1c&OdzE&(~kuBQ`T*Eꉱ|^`l9fx.PnݺΝ;cg͚u+55OLfGKj}=B83 \߼yy wΝ4x} bg}VW^M*J*U`ܹ¾}zjl߾ݒN[BX X\ȝ$M-4LjK0"%,.R^jHG#{c!qĽ'NիW > ,*ERԂTtV)S- N)UԚzm۶mVxJ BGbb"6mڄիWӬ{SL­\/nJ /k-ZVEV#%%ŕm83q J*AAAnW˗\ݞ R*d żyX.PVyoSLٽn: Қs)@:W RV -I4d <h0߻wOqΝ;0a»kP$裏GXz5'ubt=@`T*ѼysW7#G)T`=ښ9~~~Ln}mweX Ӌ)r)-Cχ~HOծXj, i'" z>@D~cd':/]oĽHY , ;vxcǎ_ Ŧ3gӣG+VlT*}*W9sd^,sﺄ\fi%>BBB-'nînFh\@W_}x27x]t/'L q\z=8t:NiZqSu:zL9|>2A2]`nWKSyLd2O ^8Z Rltksdd4YLJK5&eV1  2w6t/_|q!44oMZh288 `Ybc僽rʮnB\.'KǂL&fM jjm19ڗaȯ Jv"0MFho߾U$''+SRR ꤤ$߷oZJ*¤, "&^~ ]4F@rfd ^|r5_ʸn2ر̏-,.0oT*iZ]xDS˖{$A:٤4$HNUg5ea0Rܾ};o߾{ٳgqZתUQ$Y+#|_^/tr^/jrFjJFh4J2B:_/s:a wt?iiiERR"99Y~͛77o:==GѨZRˍ?)CL&d2ѣGil[q@r1HL/Sc,lA4NXJ=JZ52 Iϸ JVD%`ׂ y& [FswRM0fMҜE{Ϳ#% H[& ҊA 8$,녭cE m\P(:uTlϑi3i>\nb$9_#H5c5VȒ7s8r\|ɯ bMǂ3]XJ@AGkHN!E0 9'7i FN ּ=b]+xh8KKJ"޽k<\{haܤ>6cE8;M\Xô&B:N}ԹwCh z8OJ1}9 bc0I~i,HY9ID*#<&Įi5⣼Ҋ+9URHyzmȖY5IZA~K/0< ;. bG Z2]L Z)w<6hXK0H,al+m`/E0X ۴`N R";.R]炌gt1E;%RZA[Yo׎1+}L<-wY.x",)yebYDri"\A0XI-5_]6jk=h Q0 uL"4V$i=iK:W8`e-ToǨ%rU([ )hϓeb ֚*Iׂ!*1)7H&i'ѹuX`葹X <)k䂎cK!ɏ12@wUL IDATKp_ 2`Ȝ=Y& +6#@&\Z'OA/er?R牑 RG R{*f֌cznIM0Ԓ]H NFi,֍0Ok1?]],b ?GcE2s8D0;i;68H+&_ߓ!6/6X+@y#I'1 (kcד">;RcCL]8Ǻ_ w <ʒ0!vESr^`nv@`R)œ^KcゆRnJX0(?QN wu%SZtqd 9@!7)A+%;=lK@;d݃7`]bu]1w)`Jz\ ^}-w kҚ!et5v;a #wgyB Y\;r8Gzl`0 REId>\R+raM1aƊp1#$ȚYc\XX#gjLXv@4 KBp+Xfi s%A0g? d*H7cAJѲDn\Рhu5;s+y ~0sv`iQ-"1 @xE F2=vD[J0Dslwd` K=Zxg8W+60za  +8 Wl`͛b?baCڣN0ogLa'JxzwbT¾k( `zzxH9x"`|"RJ*gw{qmXn;NPx<.!f vx&wzl8D;a+,J$9x,=ggNVd܀X}O;/<.'^x!B2 }VZ~+aV\A*S4h(t0X@ ;rOvxG*+PR]4hР EűF24 Ӵk׎-[ؒ9p*Au T 4x=4(`ɨB]47Μ9C۶mpN%sWT 99{ʟ5W:4h?`ŊXdQMJi(p={6 adh-5xZ8p]ы5QP ht!9GY) Pa`,\$#؂F2F@&8퐌tvP0UP#-,ٳgqqqTB1:>C$v)g( Ljj}+`ɒ% 4Ȗdd1 3Ν;Gv8wؒ N7/##e2,k}6Ǟ={#JjUJ8 ))Loߔ)SXC S(RZ5kݻ0`| 9Nӝt@-`$0mۖ3g\ϷXZ5bccX"HKKHq@ˎ[X R>};wPxqʓmZ9d$ٳ{o>=Jtt45aÆ4nܘ:u(tnJJwOh(BhIQ‚M B ,})--6Ε,(?a!xJ*Y^ʕ+׋ *Zj… rQaɷO7>Q8dBܼy~7g ! &ˡxh\Br޿_5Jt:cRbbb۷ ټ'>>BvL4EFO?e!FclBBCHBv/5x cIwExX:uDll,*Tv. `^RR`l,Zy46\H_j}9'h֬f͒Xz5u?@5R3g\X͌JCaF04E8$ !CȓJŋozdbHYI0 )Ĭ\>}:I*U"66*UPV-IFpp܄Adni$÷< F'O47aÆ8p Wf@5>|>&(7">PB#" O>DI2ʕ-[vә3gDJ)B;1),ڵ#>>>I+V$66,d/^|έ[dh #X)#RJ ɺh$mlVDbلq#999OL&FšCq…4̶6>h( H$cС!t+WX~,MBB] K.Ѯ];N:HbccZBrC2J,9(ydLs^K/@rr{߲eܩEq#-薲4EI v.\Ȟ={xٳ't%JغuҎݼys… WM2f@7+4@{`^l2L&+Wv ?ɱPgbٲe ?;uʮ]Ld7YrCLS9$$$=!..(Fc/AjgY>\D NˡG[j Xɢ,7!!HKg5x ,U ^x*)dV'qA} Bl1--ML0ADEE9\tY8qB(p_o/OIqT1!<11'l~8e;Byrq-j*K/ҥK{dYfbٲe޽{*ٜŋCڽR:iDóRGq]d8lӧ {pF.-[f=ڵkGk֬,VK2IF 2IFxB"_rUDz7_V.|ĈL۶m:"n*[#v2K!E+ ~.LB,x~AلOٳgfؐI7r:tHԫWϥ sfYyFFFFd$兙"] U=A0222^'Ljw/B%B|B%KG}T  {RdI1rHq1l[oUQD<"u7;l> K9#K.wʕ=.HyHult+#f&BӠ!97_If͚9/d2 !8w$BQig$gtYaK.yM!uebA/x.իvz)S| K)}-6&+6υO~)}'5k6d:m99=_"Ǹ 2yF22OJLLA kԮ7-$d8jAsvpƍ" d֬YY}v=Ŧ6 by4aeJ*M.a=^<fgC>Y ƽ{--M4ha{uwJj!?v 'L0cǎ Cq MzH95D1c)? !s|e3 Hsk!?h9P 'IBB5s|SB;w2|B!RRR YY!bZ.m\P_!:d"z^‚{k֬dY̧}zI tY&ms[&y8%ի3b9WŋՋ͛k.z}eˮMNNo˖-pRh8a< )7Np,hRJ _~Wb,GGGk۶zoO_>IMM]}ҥ;v=k֬˗.e6͕Q̙3L:dk)wj1f𶅜ϯ!CʓsZWBCZx0sLk64 ;`CYvG4-:(d~h L>}>@mk3 $Lge?~-8u=zݻr %RSS=׬kV́RbއP`T1+vM-ٳ'|oӳgkdmlBX=u;$i!ӹ{.ܽ{wr<]ĉٳ0J(AXXY_a??7oȑ) ^xq .X2ɅN Y#ꃴ}6K,aĈ B=TFe7-4\h (D+7nСC>|-Zp:a.]h0 9؜d^Oد`lڵn)0>>ҤIɺE'}Gn"UD6:w$2Ci9a9$H&BqTO7oO=m_)]t#&Çw@"SH;ʄLLm RJ!F !;HJJ6lsGݺu 6x0@ *Zj]ٳgf1a637={vѣ+`'dh{xZJ.-y1w\qQa ٜeBB3SL D#9IٵmW^-(þՅBr{ !}n$Z4BZ<qe8R[b͔Ç[W_|cQB8'2v%]%K_9[n: i`"DGK|PGv !ĩS:' 2Gƍ26@ZUqAk2*HII'yeYET rP06" ̙31cƐn܌ٳgm6V^M*U˗/~RRRWׯ_BT|gx)566saW͛|w|wԪU={ҳgOWN 2ݍFc'^0ajټخnͽAg޷oÙ3g /!=R]1]6aÆ>h4ӭ&oH﫳JtF9s#GXfAvqf])udFp<sMr>Sػw/(i5,޽4@l>l2>!]I!͛:wڰÇFZ5FvusJ_"U(*k0,< a&س/Lh r1j(>~ؠA~'F\bbbbŊE -;۵k׃L'Y[́H|&t"HP֧Ca?}͖ #==xo_{-0 =g]6ӁH  UVԩSЂA lL2ߙgn꧍ pBxqz(Ke˅JyHKKa+G sY$_ES`#G2gΜ\cn:tBRR9\vm۲qFׯO%;~e˾I(#2;$>B̈́)QD4h7nPběo_ϟ?!**m̔!^.Xv-TZ׀U7Cg`1rt G8~8Sj@\DZn ,\059BtuNR{esJ/RSSٳg۶mcܺuB O>s9g/t 6mJVhٲ%aaa ݺmڴl2Tm{msoFs5(_>;w㏳}18>>u9K+jԊH1vAݺuYd0x Olo=Yn݋_ Xj՗~~~t:WPPP\jjjSzsH&noy 4qd*tR.vҥGGQһ&; 7aaaՂf FFFf3g϶[94**a`8K窩d/$ݽ[Q8pl6W_ѹsg*Tټys632waӦM}\\nM&߿qQJ5kƼyHII@=|0##b|&ԗѣG4ՒK:t(%KNʶ@>U a2Kкuk~ѣЩдHNNٳ:d_۔u*텅 NEJ,˺uhԨ/G-\_ Hnqe^yjԨe0LtbŊ/##c-[@77,iFkB*VȆ  6P#Md`.O#*l6;"9IauK=yƍ!:oРASlIFN"o!_wɵ#/b̘1VrviɽGu x衇Blٲ,00I1ͬXCŔ/U111z:q$[.|yE;`,!rZ_r/BQpofy*5z@g4޹ %ܼy5j g)?4`Νر5> J厧]O۱@|$&&rE]~yG#0/r<]{`newE0k,t:]#ܧ C/rʕf… DEEqԩ\8h 5k?`5s|ᇛS|Z0/h4]|cyHlذ̼yozZjuVڷoܭ ?ӨQ#7oZΝ_~5:BBU322;vU?vk 4ѳ`\ö:wR2~*d #tD U"YQ>̉|#Gu=zTDFFz$ġ'z"11Q!ٳgB}'v" UZ6*qya ;9o<՟e|{/p]˖-ziy5kִ1'TjBb  >,W/ܯbǎ.?; Ī6RF*Hch9;S^X2A7.3X9f̘7g|S: mhGاsGRuԱm۶HaokY,F֌199yq՝9B3Zh0 k-Z;wXdӦM"(xihx*j,\#.ܯF0H[۷7СCGd㏇!0ے2d W\ʕ+,=)F夤k]v4y<˗]!oR͗:wAj,>Bg @ԯ__ɷ\lLr(sD8 !HII9m4!M" _=)WsWPk׮)2^ƷTMLL\'n.o4ɓ3-RD4% @o6_9d_~Eh6pc$_֭[^zd"7yqAKTT8oߞnlk_GwgGH4h@ܸq&?=NG#iT1`xrmW|؆2X 3sL-[^m}lޥݻaaaAdǰY[1:rܹs*U5jզ>))F^vm?"""$..nr .,X &:.|孱o~c5*RHJ*qyJu |Uik[ Z˔)@c*grz0N`…$''T~zz:-%k.QDM[*tA2Yx1-Zȗ_8j'm2߽{N:沈Cn0}ʓ8{,:tf _u\B܍b* cȑrӦMO?w|' ހ*H Z'Of̘1ȋnub HOOk[?MD}rU/K.о}^؏d(VXC'OkB׈d%{۷o?@ܹssU\=[. BCC?B8p B֭Khh|]e|px$}.%`HNN'z op\NF^+WVp$m+f`P7i$z9Bѣnݚ .u6rƌurOF0nQ !|B"U@3eukXx5cqvI* -YO-,D <^u+KLL٭[ׯ """ތy# L9hDjDZj@FF{Y o_ųj*~mU*qI:t{tVT,p˛Q QɉIra"UdI6myz lʚf ƢEԮO 99? &ѸK.?%2ɦmtHJ+1[}aÆ[>22׮]UXH$B.d۷t:]^{ٳlgYP|Xm௿bܸq̞=vZ~:qDϚ5k^'Di[7EqС7nXmkԨQL(TΟɹ޽{tɂùshӦ5nΝ]n]]v^b+Vo߾vU:;/_> ?5.t!Zl勑#GZ7t2elNLL?7oVCHɵgd2 Ǐ3 .| wɓTVM釡O:i/@OTTl?o}e?DFF˨l f<އDV駟_! tر#ΝcbŬ޹ ę3gXf /uyZq;tҏ9d7Q(̣ڴi#_kÆ y*[ѣGiܸ1˗АT~?CN:M2._L~2ۯ/vO;fRݐB2l0tjĉw|`ѯ_?ߏk֬ҲeN3lskB?~­66n[.=S?MTT !2bԨQ%"==]!_0~HQ!%^yxh G&R݅iBHɝZnz{tU>|$hG[6¾ ?7OKJ$ZbXgΜY&YLRg9њ*uB}vի{z^dddٹsg1-(6G!RSShj,jwӦM v@BLbȑk=#n3gδfo%K!HJJ7)}NtB7xnY}Bټiw4ɴ.H-!d5sd>BB}NG-[&رc1?vZ?CG !ޜ5?Onp՟ <ڷ_eʹ+M4ny & FZZ'NjժηL&]'##yPlheam V? IDAT4iINy̟?_T׮]{I&. 111ܽ{e~4[x:wܭvڵݻѣGr !:::z]@((J_ Dm޼9o߾o ԩSiٲ%NrZmN: Wwc%ꫯ6tŨdb˖-[!`,YY=v,ݬ5F2j뙽{PL(27l Wi1$A냏-dgܹs9j.Ld4$&\LiG8ᾄׯ ȅO%fُFE+6D29oA=E0f3~!KQv'@ҐJ*|[,]۷o˗/[5=\ Н;wm2~xrm#U~7bji;>82ڷo_{~gbǎExَ(#xի,YItmūk0Aݥ֭[aPj.Ґ&@Bd!k4lͤhǎu٢hpdFYL܍مh l 1jѢˉE㉉oK..Q22BzQInnݺl۶2d[4an !O<[5 /dܹsǪ)SL-kD)7 y^7 >'5& `={r-iL"lɅ,$R x$[6mXw%5rhM͞l 3 O/8祫.L&L ѻx<#.hǎ9o%ݻǂ |I!c͚5n`Ⱥy&]vNzHH 11q/s87?-֭[װeZ._P~dɒ5ȚdўbX52]͒On^zfI-Q)W3ȼBaÑcL0$) }j1 H7H v)}4x:N9K['MwC#@zz<#j,q]5[meļyO8r)))XY tݚU4oXݹvQ ʃgZHHHHMMױ{nFc_|1,56,܅DRJj)xflPj k¨Lu l#I9r #fRު(|<ҮOR:NZ6N ʝMVC0d8"RJ-ڋF,Z.] ]a_>3TVh)S)%S4 !---DB?G}ԣ!/1cAAA+?..?ccb^7r4h`B\4} g[ 3 Na>}(dвO,_ nMpp0ǎS {T&RgW\f͚"I)a8OI4l3x[ʦQs2`{QQBѢ F[A Ahh(Ұ_]1p(\NC0 /2/ՁSR~}V\mBBˮ&A5Qͣ=juz_~N~6xqq^ϩM.K.*VwѦMd.m6_I$4 7@n˱I8N %д[o%k̙3sXf/p4? 5|~Id%qnU`2dg޼,SP4i;w|bҥGTG„\ijo(O0LZ2'lc4#99zӋ<4 |駌3@+PX1Fӧy)Y$˗//0}ı$_zArTobŊ :7_Xp{]:#F9"݁Bzz}k'E|eqXwXp!?GZjc&Ol51߷oțFr%Ȱ#2q_ӧ @IM6Z|L65˜:u3fX.TP?Yo`QkX> 1~x w}U񕳨"9}VR1oK(/L{a/=h ##Û&%R3@UҫW/^,$$ɓ'gaÆ.^ԩS t2ɅR8u&SHp)RSSx衇9zǶ¡TCzIO7  @>}￙?>uaر3N:us^ۺC&R !V4lPx5TBpoW|[$Lr(F 0ԩCNءnoxk&Riiim>fkV;`4LlٲQFQzu|Af͚֋&%%ѣGʔ)CLL +W$!A䑑UrI ,h>H, յ(*&cǎP~RZ 2+Wb4RN#&&#Gl2+WN8qvJޟ1cƉ'x[n]6mZZz!t@hdժUZt!'0LW_}uMgt(IvQ(xhºn:%GNgQj!(q811U~ 3gUV]v|ᇜ:uʣHNNoᥗ^\rߺV,]tСC^r+V6 f2=k"7D0 #<<<'7ZBBB;,{w?K.}yx;Y[ЖPM(DY/ԺႸ\@PzҢTz,("j -mf~$'=9I6ˤ)Ν{c̘1MQ !bBrh͚5Ml%Wr'*|A1c ++ QQQ;?3ѧO@IIɕ>lU˖-ߛ={Q(YW>e 7|3~'kc(W "c'IHIIɓ}yz#>>9C=sRg>Z8߂$x_pd.HEqe5@-н{w'ktTJwy?>JJJ<+A@FFÇĉ6mܾ}'[lãdE.FWA &LheX\Hy0)YʥKNX,EdϞ=hٲ[2dvڅ]v[o_[zuj\\ˇ,>1;edd|;wFNN<~rJbAߐXyƍ`0j*m֟M  ֯_Hϛ7o}ii:ob4o jU?NΆйSU/c1|p/\Mn߽{EcPx֨{n=?VA~{d2AVMn&޽$`UF={~/p-U (**cU ň$k&< _kdX~=h.FRo'4hrȑ#yyy: Z Eҿ]֟m3?Cjuqƭ߻wa5D}N0IkN,p&h$>+++X=8b18p޽{0a„JTOxD $PQQQѹsyyy<++ wyoӼbwcR_~ؕA _K.Hd'4 =y)Ax ۷bUˑht5/ddd`ذa~K, O^z 5:t_u`ds>O5z1bhBy *RfQP'M.-,,, `2&Ia4&Ia0pŢ^ڰaӧOʦ  KY-"޽Ç_ׯ߫LhApi/#ЪHQ RX*KAE+-D Iر#PXX4l( {R'YK= M6 鞼 `/^]K@ʃ!0k/̙3& ,]'6mڄ>}|?ڻwl0z þX`h4naaaM{KظxwCW\\6ԶMc۴̾ ÕEWX00`ҥKsRRR_HHHVe$@qh۶-\ _!:::5'rg!n ?HGvn6l޼Ohѣ6m >qP,Td3%>JLLD׮]WH$''򎖗T2$46rꫯbɒ%m?`ذaFlllHϞ=ߦG848|9J62`wM0ȅT)dп%z'bgmU{uQ7wdm*/bA9w{/_^^XXt -<7 M6% Jv\b8ky>Ŵf͚WGɍ iśo \rcg-WP@7*o \{AEE8 իVX jTGQ > V" _~7]9f-Tkև ǸBW#$ $CKm=믿9R żNNAXq;&L3h"\T1c ={2W\'jz\ cQvZ̙3 :x۶mJdСg &dO FYYY-++Ѿ}{tY%)w 9FLybCNH rC@j rs5̝;{ڶX-Cψn"K IDAT^ X/&x03zBӦMQZZ渇>}}HKKwS` @=-}hݺJR4ɠXZ+ .!-vjd*X$:`*:@hڵkۓDAdU .T*:N5ZҘL&lV^ Aċ'֮]{2bĈ^zx2!gϞm9Z.XBz0ɾtBCݻ#++ HJJ&D@x>U7tTM6aϗG} ڵk ѭ[7l޼wy'^*zLll,n݊(<Ϝ9󋒒bv*|ΗK… x衇`6]a͚5֭^un:嫯裏t 6)h{T*9B:֝0փA gIjr!UEJ*]D~ Ο?˗/ZAbqq\WX=>Ç߿ǨQ|}~A'Oǧ'_GN5kֶ?sW< x{[k׮bfSՂhA222`= )I0]a]GHX 6} $JdMۮ3 @ fbh1߄ ˆY)v|6dF}7 W^=o'<`46y#Va$Y[2MA(9rDx饗|ޖ#G>`޽{A())[2DXbp pҤICt1" S9/k6lߟ#zj²eJjժTNWb4RSSUTT;!22X{Ҿ׽`$jghԜ#8O/Blƙ3g|p:d2D, kۤ*Bkemb9&)tf#F㸑cڵ޽ƍ(Sp*.(**޽{Q\\ǦZV jقԩSѲeK<#عs}Uo.9rmqqq'.s'#0L>8A¤Zj媒E6L$][w-\pUqqq&il~Y<jAv@|Wx}v͍ prX(0ؾ};кukkɞF1 ƍ1zhoo&N> 8Nyo~6^xw^~m k.ڵÚ5kk' O}ȑorfȱaaa3fxtٟΝ;СCزe n?]E5{Z\\\Nd^Qu%Xpގ;{lQF~s+妛n… q9cٲeHJJBTTTڥP(УGK.aСC/VC=]vڵkغu+O޽{׉pcXlΞ=lHyBBo/ZVVvg]q9pV4uz`B?9 C,d>r0rC A~111- ç"[hb,gx@CͻnJ q9 [;駟R E;XOЖHMMņ q"$$ |K.aX` d$J?KHH@BByX,׮]#<<EvڡiӦ4q`ĉ8q"GK__o4i͚5CLL}0`n6h4Zw۶mزe Zl J5OCܰ) A6w^ұ+VÇ1`$$$ `+1E=E0p T7hD'VB@JPc {޽{*^؈EQQJKKQVVr,J/Eޔ믿ڵkqa?6v 1B&!Ro>۷ӧOǤIObȑV3ǍP#rw[%p@`ܹ>;iXX#&qSN/n#ߌm˖-K/A`2gI&˗/dɒE xiӦMcRRRRr=z+nܸkCgNXK.fgOK7mX^^޿bbb( /vZyJ%:wΝ;ץnCoŘ1c\u!&&^hx嗱~z{cǎׯB3lx(?£F@^^VXիW#**=cǎP}GH]rEQ< Dywcƌ'դ<6 ʛt b6gϞΟ?J_]B6TTT'DZZjĻVk`TT`6l о}{xꩧCoq~_0Ɠ'OIMMݳq7oxm%r%KW_l6>Z1cƍJIIYݶmۯ^y;{9*<C̞=ƉVX~ 6l@N.]ܵgϞ!+ǎƍ ,薔4:::F W&\R) %f63}C>^?ϊ*PS1Z+MʋAh'Zk[bʕڵk}P'O?Œ%KPTVVO>+Oc֬Yh۶JJJ[oaĒ٢*RkJI_`~ԁgh֬ڴiּ ~1W+yQ;4DoCшb׮]صk<,O@Jfa,O@]YGc-[vtI{I@v˚JNӚLP"BdҘf bqHRDqQ#7o3gNﴴ'n*3gtwK,SO=Z9z3.\JOOٵkENT:.MD 5U,FJ`&E7$$D̓E:wѣGc̘1۝.& `ɒ%O .]HNNٳ^bعs'233/Z#D,\y-hlO_z/蔁#G஻Bttt, w l!]#H0 W!RdM9( A" 匠?ܻw/V\[BeA4jX, aV"g1@}Aݻ+, WUUTVVV*zJ׫+**ԕ*2Ljɤ0 ٬yda{RƆ7o<2&&iӦMFFFFj*AV;1ܺN~۶mÜ9sp뭷BVGuW^y^xd2髪******u:]N,--2blbxblkas#;+Cs=ɼf3=D2^ B*8F[||gj0f=={oHOOGZZki4j*^C ĉ1a儜;wعs'vU+="E0XM,T,`_V a4UT `k9mf*&0m4bddd?k@߾}K/Fhh(4MsF v=n+*y%yW$Tʢjku ݻ=c ٽCE֭.{q!-- w/?̙3ѥKL0'NnիWq!G9[kJj v̈݇ \8q ^Sf+Lc,P !H3 %'k U'N8_ؼy3ڸy@J @m6] zZ8Z2 :vx:.\ŋtOBLѣGSOaƌ8q"СCǣChѢGSKXi &PTzHMM`]\cǎѩS't&  6o{jWcsPPP3gΠ:Γp'rg , vXXXZVL&a4 GWl8 Ӄ?jh걘;w./_Y@hd0 ZZԐ!dܰ{61v:Ti,ϔbY6c…kv9`Jjڣ穪B^^<^ėrgA=9]Ј r bРA al1!`_ׯ&4ciHŁ0a/D! ŃQ\\3m$ɣj`04p>)͜&RaRb^R&iRb["%S{G"@B#8=z޷o_1J7M2`H .``h b @s ֏,B\ Sl'Pz'@1@$ŧ^7J0|0w}HNNBTނX(8QQQ>m1~x\~_5֭[#GL&VAv+J{; ps% 0rq BjSik &6ԋh |A:U\]nV0/,aHNNɓl6\pӧ HQ+Z:q/VΝ;JJeV&FcRT{ q bL&`0(M&h4*M&yJ QTZJQZVTjUeZTU*ZՆj4&͚5ôi0m4?~֭Æ pbŔG>DÁ@,{DC΄EЃQ 81։ A!_LbI<. @??Cx'0et;NWkVV-:uuZWd2ƚ1X` PXIDAT,8k*f@uyO)a- 5ׁ;ABF,wnZ͚5<0k׮T*GXh>dffbݺuHKKsb!"pJ%; \^h6ZWq`B g0 D} ?t2PVt .QPP ?6s< q F SKAȪڴ NRi9\BFz0jZLʸ^ٳO964{\ILOM2'Nw[4 GȅOȆVeѸԩS{UZإ;E&dk4M"4 H"GBŮخY,̟?s۶m2o޼F޺u KHHQu2 _uhǡT*P^ aOD] _~{ 1F˗C:.sfQT*}^1MCCCԂ8Q?HxsRd2?駟իK 5QAz"%3M2XA5+2bgRH]!x9999ƎW_1x7qb^g_77HHܨ# b5 @% :ksYAuEQp&9 @%lj#rV +R$cU)y8&䙧<뤯iEUԥ6OYc&t 59(UY>b1Ŗ@+Esc+d0Hʃ& Jfu. X]DsV{WsD*}cXkٱ.hX :e=6xdx?zptxBl|a"zFHz,e w q YL0\)Z ZX6 xaB`J1mymvm8evߙ6>빠 =㽨MU*2ʀ$sDO.]F]P_2oŞ5V-)r byhcM>jT߳cTƁC kn)%,8% $["4T!`@+,æe&bp6#S픲XM/wz0}1}87-)`ZNN*L]aL¹KX/f8aeGM/V`?q-XZ-~pG(yE0fTAmpp@2@6)KpCgʱ "%3l3CQ YCpFC0*f#C^iyRx܅+AOjNr]b 5Sˎ{t= A_/!v>pC/xd58ӳ\@"cz`PFj1I& V]A˔s}z1 iYFISIˆݸR]Gʓ-9s+Y_"Cʓ*\l\b|Osip`c3o`}* ylҤ|ϒL2=QbJhHC vn%q]^oK.8l1Tc1)``F9p^mlWG :`xba^ڐ DΓVw)R^{I򴷍?g$C*ٛ\ks,QjUW䢱 ,X"үrR2Y9`hÄT\c)C p" Y>#bh(r 60SXYtz] 6HH%EQ:Eˁ!>1!H0`H)PxZɅb!J$gRqb `Ɇ%fc-IbIyp{wy*E2h_9+ D> LXϒw^dˀLJY$ c{ ,l?mg͒B9ϝ.̒ O gܕrqt5ZtX wpxd2wm`I3o,ݕ& 1$at塆,G|V r&! ;SJIRɺ #jxm^1IENDB`chessx-1.0.0/src/gui/mainwindowactions.cpp000644 001750 001750 00000140171 12223260306 021425 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2009 by Michal Rudolf mrudolf@kdewebdev.org * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "analysiswidget.h" #include "board.h" #include "boardsetup.h" #include "boardview.h" #include "copydialog.h" #include "chessbrowser.h" #include "compileeco.h" #include "databaseinfo.h" #include "databaselist.h" #include "ecolistwidget.h" #include "editaction.h" #include "eventlistwidget.h" #include "filtermodel.h" #include "game.h" #include "gamelist.h" #include "mainwindow.h" #include "messagedialog.h" #include "memorydatabase.h" #include "openingtreewidget.h" #include "output.h" #include "pgndatabase.h" #include "playerlistwidget.h" #include "preferences.h" #include "renametagdialog.h" #include "savedialog.h" #include "settings.h" #include "tablebase.h" #include "tableview.h" #include "version.h" #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN #include #endif void MainWindow::slotFileNew() { QString file = QFileDialog::getSaveFileName(this, tr("New database"), AppSettings->value("/General/databasePath").toString(), tr("PGN database (*.pgn)")); if(file.isEmpty()) { return; } if(!file.endsWith(".pgn")) { file += ".pgn"; } QFile pgnfile(file); if(!pgnfile.open(QIODevice::WriteOnly)) { MessageDialog::warning(tr("Cannot create ChessX database."), tr("New database")); } else { pgnfile.close(); openDatabase(file); AppSettings->setValue("/General/databasePath", QFileInfo(file).absolutePath()); } } void MainWindow::slotFileOpen() { QStringList files = QFileDialog::getOpenFileNames(this, tr("Open database"), AppSettings->value("/General/databasePath").toString(), tr("PGN databases (*.pgn)")); foreach(QString file, files) { if(!file.isEmpty()) { AppSettings->setValue("/General/databasePath", QFileInfo(file).absolutePath()); openDatabaseUrl(file, false); } } } void MainWindow::slotFileOpenUtf8() { QStringList files = QFileDialog::getOpenFileNames(this, tr("Open database"), AppSettings->value("/General/databasePath").toString(), tr("PGN databases (*.pgn)")); foreach(QString file, files) { if(!file.isEmpty()) { AppSettings->setValue("/General/databasePath", QFileInfo(file).absolutePath()); openDatabaseUrl(file, true); } } } void MainWindow::slotFileOpenRecent() { QAction *action = qobject_cast(sender()); if(action) { openDatabase(action->data().toString()); } } void MainWindow::saveDatabase() { if(!database()->isReadOnly() && database()->isModified()) { Output output(Output::Pgn); output.output(database()->filename(), *database()); } emit databaseChanged(databaseInfo()); } bool MainWindow::QuerySaveDatabase() { if(QuerySaveGame()) { if(m_currentDatabase && qobject_cast(database())) { if(database()->isModified()) { int result = MessageDialog::yesNoCancel(tr("The current database is modified!") + '\n' + tr("Save it?")); if(MessageDialog::Yes == result) { startOperation(tr("Saving %1...").arg(database()->name())); Output output(Output::Pgn); connect(&output, SIGNAL(progress(int)), SLOT(slotOperationProgress(int))); output.output(database()->filename(), *database()); finishOperation(tr("%1 saved").arg(database()->name())); return true; } return result != MessageDialog::Cancel; } } return true; } return false; } void MainWindow::slotFileSave() { if(database()->isReadOnly()) MessageDialog::warning(tr("The database %1 is read-only and cannot be saved.") .arg(database()->name())); else if(m_currentDatabase && qobject_cast(database())) { startOperation(tr("Saving %1...").arg(database()->name())); Output output(Output::Pgn); connect(&output, SIGNAL(progress(int)), SLOT(slotOperationProgress(int))); output.output(database()->filename(), *database()); finishOperation(tr("%1 saved").arg(database()->name())); } } void MainWindow::slotFileClose() { if(m_currentDatabase) { // Don't remove Clipboard if(databaseInfo()->IsLoaded()) { if(QuerySaveDatabase()) { m_openingTreeWidget->cancel(false); m_databaseList->setFileClose(databaseInfo()->filePath(), databaseInfo()->currentIndex()); databaseInfo()->close(); delete databaseInfo(); m_databases.removeAt(m_currentDatabase); for(int i = 0; i < m_boardViews.count(); ++i) { if(m_boardViews.at(i)->dbIndex() == m_currentDatabase) { m_boardViews.at(i)->setDbIndex(0); } else if(m_boardViews.at(i)->dbIndex() > m_currentDatabase) { m_boardViews.at(i)->setDbIndex(m_boardViews.at(i)->dbIndex() - 1); } } m_currentDatabase = 0; // Switch to clipboard is always safe m_boardView->setDbIndex(m_currentDatabase); UpdateBoardInformation(); m_databaseList->setFileCurrent(QString()); updateMenuDatabases(); slotDatabaseChanged(); } } } } void MainWindow::slotFileCloseIndex(int n) { if(m_currentDatabase == n) { slotFileClose(); } else if(n) // Don't remove Clipboard { if(m_databases[n]->IsLoaded()) { m_databaseList->setFileClose(m_databases[n]->filePath(), m_databases[n]->currentIndex()); m_databases[n]->close(); delete m_databases[n]; m_databases.removeAt(n); for(int i = 0; i < m_boardViews.count(); ++i) { if(m_boardViews.at(i)->dbIndex() == n) { m_boardViews.at(i)->setDbIndex(0); } else if(m_boardViews.at(i)->dbIndex() > n) { m_boardViews.at(i)->setDbIndex(m_boardViews.at(i)->dbIndex() - 1); } } if(m_currentDatabase > n) { // hack as we have just moved the index by one m_currentDatabase--; } updateMenuDatabases(); } } } void MainWindow::slotFileCloseName(QString fname) { for(int i = 0; i < m_databases.count(); i++) { if(m_databases[i]->database()->filename() == fname) { slotFileCloseIndex(i); return; } } } void MainWindow::slotFileExportGame() { int format; QString filename = exportFileName(format); if(!filename.isEmpty()) { Output output((Output::OutputType)format); output.output(filename, databaseInfo()->currentGame()); } } void MainWindow::slotFileExportFilter() { int format; QString filename = exportFileName(format); if(!filename.isEmpty()) { Output output((Output::OutputType)format); output.output(filename, *(databaseInfo()->filter())); } } void MainWindow::slotFileExportAll() { int format; QString filename = exportFileName(format); if(!filename.isEmpty()) { Output output((Output::OutputType)format); output.output(filename, *database()); } } void MainWindow::slotFileQuit() { qApp->closeAllWindows(); } void MainWindow::slotConfigure() { PreferencesDialog dlg(this); connect(&dlg, SIGNAL(reconfigure()), SLOT(slotReconfigure())); dlg.exec(); } void MainWindow::slotReconfigure() { if(AppSettings->getValue("/MainWindow/VerticalTabs").toBool()) { setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks | QMainWindow::VerticalTabs); } else { setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowTabbedDocks | QMainWindow::AllowNestedDocks); } #ifdef Q_OS_WIN if(AppSettings->getValue("/MainWindow/StayOnTop").toBool()) { SetWindowPos((HWND)winId(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); } else { SetWindowPos((HWND)winId(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); } #endif m_recentFiles.restore(); updateMenuRecent(); emit reconfigure(); // Re-emit for children delete m_output; m_output = new Output(Output::NotationWidget); UpdateGameText(); } void MainWindow::UpdateGameText() { if(m_gameView) { m_gameView->setText(m_output->output(&game(), m_training->isChecked())); } } void MainWindow::slotToggleStayOnTop() { #ifdef Q_OS_WIN QAction* stayOnTop = (QAction*) sender(); if(stayOnTop) { AppSettings->setValue("/MainWindow/StayOnTop", stayOnTop->isChecked()); } if(AppSettings->getValue("/MainWindow/StayOnTop").toBool()) { SetWindowPos((HWND)winId(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); } else { SetWindowPos((HWND)winId(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); } show(); #endif } void MainWindow::slotConfigureFlip() { m_boardView->setFlipped(!m_boardView->isFlipped()); } void MainWindow::slotEditCopyFEN() { QApplication::clipboard()->setText(game().toFen()); } void MainWindow::slotEditCopyHumanFEN() { QApplication::clipboard()->setText(game().toHumanFen()); } void MainWindow::slotEditCopyPGN() { Output output(Output::Pgn); QString pgn = output.output(&game()); QApplication::clipboard()->setText(pgn); } void MainWindow::slotEditComment() { if(gameEditComment(Output::Comment)) { slotGameChanged(); } } void MainWindow::slotEditCommentBefore() { if(gameEditComment(Output::Precomment)) { slotGameChanged(); } } void MainWindow::slotEditVarPromote() { if(!game().isMainline()) { game().promoteVariation(game().currentMove()); slotGameChanged(); } } void MainWindow::slotEditVarRemove() { if(!game().isMainline()) { game().removeVariation(game().variationNumber()); slotGameChanged(); } } bool MainWindow::pasteFen(QString& msg, QString fen) { // Prepare Fen - clean up code like this: // [FEN "***"] to *** if(fen.contains("\"")) { int n1 = fen.indexOf('"'); int n2 = fen.lastIndexOf('"'); if(n2 > n1 + 1) { fen = fen.mid(n1 + 1, n2 - n1 - 1); } } // Another go at Fens copied from Wikis: [FEN]***[/FEN] is reduced to *** fen.remove(QRegExp("\\[[^\\]]*\\]")); Board board; if(!board.isValidFen(fen)) { msg = fen.length() ? tr("Text in clipboard does not represent valid FEN:
%1").arg(fen) : tr("There is no text in clipboard."); return false; } board.fromFen(fen); if(board.validate() != Valid) { msg = tr("The clipboard contains FEN, but with illegal position. " "You can only paste such positions in Setup position dialog."); return false ; } game().setStartingBoard(board); slotGameChanged(); return true; } void MainWindow::slotEditPasteFEN() { QString fen = QApplication::clipboard()->text().simplified(); QString msg; if(!pasteFen(msg, fen)) { MessageDialog::warning(msg); } } bool MainWindow::slotEditPastePGN() { QString pgn = QApplication::clipboard()->text().trimmed(); if(!pgn.isEmpty()) { MemoryDatabase pgnDatabase; if(pgnDatabase.openString(pgn)) { Game g; if(pgnDatabase.loadGame(0, g)) { slotGameNew(); game() = g; slotGameChanged(); return true; } } } return false; } void MainWindow::slotEditPaste() { QString fen = QApplication::clipboard()->text().simplified(); QString dummy; if(!pasteFen(dummy, fen)) { slotEditPastePGN(); } } void MainWindow::slotEditTruncateEnd() { game().truncateVariation(Game::AfterMove); slotGameChanged(); } void MainWindow::slotEditTruncateStart() { game().truncateVariation(Game::BeforeMove); slotGameChanged(); } void MainWindow::slotEditBoard() { BoardSetupDialog dlg(this); dlg.setBoard(game().board()); dlg.setFlipped(m_boardView->isFlipped()); if(dlg.exec() == QDialog::Accepted) { game().setStartingBoard(dlg.board()); slotGameChanged(); } } /** Set position's PGN to clipboard. */ void MainWindow::slotEditCopyImage() { QPixmap pixmap(m_boardView->size()); pixmap.fill(Qt::transparent); m_boardView->render(&pixmap); QImage image = pixmap.toImage(); QApplication::clipboard()->setImage(image); } void MainWindow::slotHelpBug() { QDesktopServices::openUrl(QUrl("http://sourceforge.net/tracker/?group_id=163833&atid=829300")); } void MainWindow::slotBoardMove(Square from, Square to, int button) { const Board& board = game().board(); Move m(board.prepareMove(from, to)); if(m.isLegal()) { PieceType promotionPiece = None; if(m.isPromotion()) { bool ok; QStringList moves; moves << tr("Queen") << tr("Rook") << tr("Bishop") << tr("Knight"); int index = moves.indexOf(QInputDialog::getItem(0, tr("Promotion"), tr("Promote to:"), moves, 0, false, &ok)); if(!ok) { return; } promotionPiece = PieceType(Queen + index); m.setPromotionPiece(promotionPiece); } // Use an existing move with the correct promotion piece type if it already exists if(game().findNextMove(from, to, promotionPiece)) { if((button & Qt::AltModifier) && (!(button & Qt::ControlModifier))) { // The move exists but adding a variation was requested anyhow // Take back the move and proceed as if the move does not yet exist game().backward(); } else { slotGameChanged(); return; } } if(!m_training->isChecked()) { if(game().atLineEnd()) { game().addMove(m); } else { if(button & Qt::ControlModifier) { if(button & Qt::AltModifier) { game().insertMove(m); } else { game().replaceMove(m); } } else { game().addVariation(m); } game().forward(); } } slotGameChanged(); } } void MainWindow::slotBoardClick(Square s, int button, QPoint pos, Square from) { if(button & Qt::RightButton) { if(button & Qt::ShiftModifier) { QMenu* menu = new QMenu(this); m_annotationSquare = s; m_annotationSquareFrom = from; bool twoSquares = (s != from && from != InvalidSquare); menu->addAction(QIcon(":/images/square_red.png"), tr("Red Square"), this, SLOT(slotRedSquare()))->setEnabled(!twoSquares); menu->addAction(QIcon(":/images/square_yellow.png"), tr("Yellow Square"), this, SLOT(slotYellowSquare()))->setEnabled(!twoSquares); menu->addAction(QIcon(":/images/square_green.png"), tr("Green Square"), this, SLOT(slotGreenSquare()))->setEnabled(!twoSquares); menu->addAction(QIcon(":/images/square_none.png"), tr("Remove Color"), this, SLOT(slotNoColorSquare()))->setEnabled(!twoSquares); menu->addSeparator(); menu->addAction(QIcon(":/images/arrow_red.png"), tr("Red Arrow to here"), this, SLOT(slotRedArrowHere()))->setEnabled(twoSquares); menu->addAction(QIcon(":/images/arrow_yellow.png"), tr("Yellow Arrow to here"), this, SLOT(slotYellowArrowHere()))->setEnabled(twoSquares); menu->addAction(QIcon(":/images/arrow_green.png"), tr("Green Arrow to here"), this, SLOT(slotGreenArrowHere()))->setEnabled(twoSquares); menu->addAction(QIcon(":/images/arrow_none.png"), tr("Remove Arrow to here"), this, SLOT(slotNoArrowHere()))->setEnabled(twoSquares); menu->exec(pos); } else { bool nextGuess = AppSettings->getValue("/Board/nextGuess").toBool(); if(button & Qt::ControlModifier) { nextGuess = !nextGuess; // CTRL selects the other mapping } if(!nextGuess) { bool remove = game().atLineEnd(); int var = game().variationNumber(); gameMoveBy(-1); if(remove) { if(var && game().isMainline()) { game().removeVariation(var); } else { game().truncateVariation(); } slotGameChanged(); } } else { m_boardView->nextGuess(s); } } } } void MainWindow::slotMoveChanged() { const Game& g = game(); MoveId m = g.currentMove(); // Set board first QString fen = m_boardView->board().toFen(); m_boardView->setBoard(g.board(), m_currentFrom, m_currentTo, game().atLineEnd()); m_currentFrom = InvalidSquare; m_currentTo = InvalidSquare; emit displayTime(g.timeAnnotation(), oppositeColor(g.board().toMove())); // Highlight current move m_gameView->showMove(m); slotSearchTree(); emit boardChange(g.board()); // Clear entries m_nagText.clear(); emit signalMoveHasNextMove(!game().atLineEnd()); emit signalMoveHasPreviousMove(!game().atGameStart()); emit signalMoveHasVariation(game().variationCount() > 0); emit signalMoveHasParent(!game().isMainline()); emit signalVariationHasSibling(game().variationHasSiblings(m)); emit signalGameIsEmpty(false); } void MainWindow::slotBoardMoveWheel(int wheel) { if(wheel & Qt::AltModifier) if(wheel & BoardView::WheelDown) { slotGameMoveLast(); } else { slotGameMoveFirst(); } else if(wheel & Qt::ControlModifier) if(wheel & BoardView::WheelDown) { slotGameMoveNextN(); } else { slotGameMovePreviousN(); } else if(wheel & BoardView::WheelDown) { slotGameMoveNext(); } else { slotGameMovePrevious(); } } void MainWindow::slotGameVarEnter() { if(game().variationCount(game().currentMove())) { game().moveToId(game().variations().first()); if(m_training->isChecked()) { slotGameChanged(); } else { slotMoveChanged(); } } else { slotGameMoveNext(); } } void MainWindow::slotGameVarUp() { if(!game().isMainline()) { while(!game().atLineStart()) { game().backward(); } MoveId currentVar = game().currentMove(); game().backward(); int n = game().variations().indexOf(currentVar) - 1; if(n >= 0) { game().moveToId(game().variations().at(n)); } } slotMoveChanged(); } void MainWindow::slotGameVarDown() { if(!game().isMainline()) { while(!game().atLineStart()) { game().backward(); } MoveId currentVar = game().currentMove(); game().backward(); int n = game().variations().indexOf(currentVar) + 1; if(n < game().variations().count()) { game().moveToId(game().variations().at(n)); } else { if(!m_training->isChecked()) { // Do not show next move in training mode game().forward(); } } } slotMoveChanged(); } void MainWindow::slotGameVarExit() { if(!game().isMainline()) { while(!game().atLineStart()) { game().backward(); } game().backward(); if(m_training->isChecked()) { slotGameChanged(); } else { slotMoveChanged(); } } else { slotGameMovePrevious(); } } void MainWindow::slotGameLoadFirst() { gameLoad(databaseInfo()->filter()->indexToGame(0)); m_gameList->setFocus(); } void MainWindow::slotGameLoadLast() { gameLoad(databaseInfo()->filter()->indexToGame(databaseInfo()->filter()->count() - 1)); m_gameList->setFocus(); } void MainWindow::slotGameLoadPrevious() { if(QuerySaveGame()) { int game = m_gameList->currentIndex().row(); game = databaseInfo()->filter()->indexToGame(game); game = databaseInfo()->filter()->previousGame(game); if(game != -1) { gameLoad(game); m_gameList->setFocus(); } } } void MainWindow::loadNextGame() { int game = m_gameList->currentIndex().row(); game = databaseInfo()->filter()->indexToGame(game); game = databaseInfo()->filter()->nextGame(game); if(game != -1) { gameLoad(game); m_gameList->setFocus(); } } void MainWindow::slotGameLoadNext() { loadNextGame(); } void MainWindow::slotGameLoadRandom() { if(databaseInfo()->filter()->count()) { int random = rand() % databaseInfo()->filter()->count(); gameLoad(databaseInfo()->filter()->indexToGame(random)); m_gameList->setFocus(); } } void MainWindow::slotGameLoadChosen() { int index = QInputDialog::getInt(this, tr("Load Game"), tr("Game number:"), gameIndex() + 1, 1, database()->count()); gameLoad(index - 1); m_gameList->setFocus(); } void MainWindow::slotGameNew() { if(database()->isReadOnly()) { MessageDialog::error(tr("This database is read only.")); } else { if(QuerySaveGame()) { databaseInfo()->newGame(); m_gameList->clearSelection(); slotGameChanged(); emit signalFirstGameLoaded(true); emit signalLastGameLoaded(true); emit signalGameIsEmpty(true); // repair effect of slotGameChanged } } } void MainWindow::saveGame() { if(!database()->isReadOnly()) { databaseInfo()->saveGame(); database()->index()->setTag("Length", QString::number((game().plyCount() + 1) / 2), gameIndex()); m_gameList->updateFilter(); slotFilterChanged(); slotGameChanged(); game().setModified(false); if(AppSettings->getValue("/General/autoCommitDB").toBool()) { saveDatabase(); } } } void MainWindow::slotDatabaseModified() { m_gameList->updateFilter(); slotFilterChanged(); emit signalCurrentDBisReadWrite((m_currentDatabase > 0) && !databaseInfo()->database()->isReadOnly()); emit signalCurrentDBcanBeClosed(m_currentDatabase > 0); emit signalCurrentDBhasGames(database()->index()->count() > 0); } bool MainWindow::slotGameSave() { if(database()->isReadOnly()) { MessageDialog::error(tr("This database is read only.")); game().setModified(false); // Do not notify more than once return true; } int n = saveDialog()->save(database(), game()); if(n == QDialog::Accepted) { saveGame(); } else if(n == SaveDialog::Discard) { game().setModified(false); // Do not notify more than once } emit databaseModified(); return (n != QDialog::Rejected); } void MainWindow::slotGameModify(const EditAction& action) { if((action.type() != EditAction::CopyHtml) && (action.type() != EditAction::CopyText)) { game().moveToId(action.move()); slotMoveChanged(); } switch(action.type()) { case EditAction::RemoveNextMoves: game().truncateVariation(); break; case EditAction::RemovePreviousMoves: game().truncateVariation(Game::BeforeMove); break; case EditAction::RemoveVariation: { game().removeVariation(game().variationNumber()); break; } case EditAction::PromoteVariation: { game().promoteVariation(action.move()); break; } case EditAction::EnumerateVariations1: { game().enumerateVariations(action.move(), 'A'); break; } case EditAction::EnumerateVariations2: { game().enumerateVariations(action.move(), 'a'); break; } case EditAction::VariationUp: { game().moveVariationUp(action.move()); break; } case EditAction::VariationDown: { game().moveVariationDown(action.move()); break; } case EditAction::EditPrecomment: if(!gameEditComment(Output::Precomment)) { return; } break; case EditAction::EditComment: if(!gameEditComment(Output::Comment)) { return; } break; case EditAction::AddNag: game().addNag(Nag(action.data().toInt()), action.move()); break; case EditAction::ClearNags: game().clearNags(action.move()); break; case EditAction::AddNullMove: game().addMove(m_boardView->board().nullMove()); break; case EditAction::CopyHtml: QApplication::clipboard()->setText(m_gameView->toHtml()); return; // game is not changed case EditAction::CopyText: QApplication::clipboard()->setText(m_gameView->toPlainText()); return; // game is not changed default: break; } slotGameChanged(); } void MainWindow::slotMergeActiveGame(int gameIndex) { Game g; if(gameIndex != databaseInfo()->currentIndex()) { if(database()->loadGame(gameIndex, g)) { game().mergeWithGame(g); slotGameChanged(); } } } void MainWindow::slotMergeAllGames() { Game g; for(int i = 0; i < database()->index()->count(); ++i) { if(i != databaseInfo()->currentIndex()) { if(database()->loadGame(i, g)) { game().mergeWithGame(g); } } } slotGameChanged(); } void MainWindow::slotMergeFilter() { Game g; for(int i = 0; i < database()->count(); ++i) { if(databaseInfo()->filter()->contains(i) && database()->loadGame(i, g)) { game().mergeWithGame(g); } } slotGameChanged(); } void MainWindow::slotGetActiveGame(const Game** g) { *g = &game(); } void MainWindow::slotGameChanged() { UpdateGameText(); UpdateGameTitle(); slotMoveChanged(); UpdateBoardInformation(); } void MainWindow::slotGameViewLink(const QUrl& url) { if(url.scheme() == "move") { if(url.path() == "prev") { game().backward(); } else if(url.path() == "next") { game().forward(); } else if(url.path() == "exit") { game().moveToId(game().parentMove()); } else { game().moveToId(url.path().toInt()); } if(m_training->isChecked()) { slotGameChanged(); } else { slotMoveChanged(); } } else if(url.scheme() == "precmt" || url.scheme() == "cmt") { game().moveToId(url.path().toInt()); if(m_training->isChecked()) { slotGameChanged(); } else { slotMoveChanged(); } Output::CommentType type = url.scheme() == "cmt" ? Output::Comment : Output::Precomment; if(gameEditComment(type)) { slotGameChanged(); } } else if(url.scheme() == "egtb") { if(!game().atGameEnd()) { game().addVariation(url.path()); } else { game().addMove(url.path()); } game().forward(); slotGameChanged(); } else if(url.scheme() == "tag") { m_playerList->setDatabase(databaseInfo()); if(url.path() == "white") { m_playerList->slotSelectPlayer(game().tag(TagNameWhite)); } else if(url.path() == "black") { m_playerList->slotSelectPlayer(game().tag(TagNameBlack)); } } } void MainWindow::slotGameViewLink(const QString& url) { slotGameViewLink(QUrl(url)); } void MainWindow::slotGameViewSource() { QString text = m_output->output(&game()); QApplication::clipboard()->setText(text); } void MainWindow::slotGameDumpMoveNodes() { game().dumpAllMoveNodes(); } void MainWindow::slotGameAddVariation(const Analysis& analysis) { game().addVariation(analysis.variation(), QString::number(analysis.score() / 100.0, 'f', 2)); slotGameChanged(); } void MainWindow::slotGameAddVariation(const QString& san) { QString s = san; s = s.remove(QRegExp("-.*")); s = s.remove(QRegExp("[0-9]*\\.")); if(game().atLineEnd()) { game().addMove(s); } else { game().addVariation(s); } slotGameChanged(); } void MainWindow::slotGameUncomment() { game().removeComments(); slotGameChanged(); } void MainWindow::slotGameRemoveVariations() { game().removeVariations(); slotGameChanged(); } void MainWindow::slotToggleTraining() { slotGameChanged(); } void MainWindow::slotToggleAutoAnalysis() { slotToggleAutoPlayer(); if(m_autoAnalysis->isChecked() && !m_mainAnalysis->isEngineRunning()) { MessageDialog::information(tr("Analysis Pane 1 is not running an engine for automatic analysis."), tr("Auto Analysis")); } } void MainWindow::slotToggleAutoPlayer() { QAction* autoPlayAction = (QAction*) sender(); if(autoPlayAction) { if(autoPlayAction->isChecked()) { QAction* otherAction = (autoPlayAction == m_autoPlay) ? m_autoAnalysis : m_autoPlay; otherAction->setChecked(false); int interval = AppSettings->getValue("/Board/AutoPlayerInterval").toInt(); if(m_autoPlayTimer->interval() != interval) { m_autoPlayTimer->setInterval(interval); } m_autoPlayTimer->start(); } else { m_autoPlayTimer->stop(); } } } void MainWindow::slotAutoPlayTimeout() { if(m_autoAnalysis->isChecked() && m_mainAnalysis->isEngineRunning() && (m_AutoInsertLastBoard != m_boardView->board())) { Analysis a = m_mainAnalysis->getMainLine(); if(!a.variation().isEmpty()) { Move m = a.variation().first(); if(!game().currentNodeHasMove(m.from(), m.to())) { if(!game().isEcoPosition()) { slotGameAddVariation(a); } } } m_AutoInsertLastBoard = m_boardView->board(); } if(game().atGameEnd() && AppSettings->getValue("/Board/AutoSaveAndContinue").toBool()) { saveGame(); loadNextGame(); } else { slotGameMoveNext(); } m_autoPlayTimer->start(); } void MainWindow::slotFilterChanged() { if(gameIndex() >= 0) { m_gameList->selectGame(gameIndex()); } int count = databaseInfo()->filter()->count(); QString f = count == database()->count() ? "all" : QString::number(count); m_statusFilter->setText(QString(" %1: %2/%3 ").arg(databaseName()) .arg(f).arg(database()->count())); } void MainWindow::slotFilterLoad(int index) { if(index != gameIndex()) { gameLoad(index); activateWindow(); } } void MainWindow::slotStatusMessage(const QString& msg) { statusBar()->showMessage(msg); } void MainWindow::slotOperationProgress(int progress) { m_progressBar->setValue(progress); } void MainWindow::slotDatabaseChange() { QAction* action = qobject_cast(sender()); if(action && m_currentDatabase != action->data().toInt()) { m_currentDatabase = action->data().toInt(); m_boardView->setDbIndex(m_currentDatabase); m_databaseList->setFileCurrent(databaseInfo()->filePath()); slotDatabaseChanged(); if(database()->isReadOnly()) { for(int i = 0; i < m_databases.count(); ++i) { if(i != m_currentDatabase) { if(m_databases[i]->isValid() && m_databases[i]->database()->isReadOnly()) { m_databases[i]->database()->index()->clearCache(); } } } } } } void MainWindow::copyGame(int target, int index) { if(m_databases[target]->isValid()) { Game g; if(database()->loadGame(index, g)) { QString fileName = m_databases[target]->filePath(); QString msg; msg = tr("Append game %1 to %2.").arg(index + 1).arg(fileName.isEmpty() ? tr("Clipboard") : fileName); statusBar()->showMessage(msg); // The database is open and accessible m_databases[target]->database()->appendGame(g); if(index == m_currentDatabase) { emit databaseModified(); } } } } void MainWindow::copyGame(QString fileName, int index) { for(int i = 0; i < m_databases.count(); ++i) { if(m_databases[i]->filePath() == fileName) { if(m_databases[i]->isValid()) { copyGame(i, index); m_databases[i]->filter()->resize(m_databases[i]->database()->count(), true); } return; } } // The database is closed Output writer(Output::Pgn); Game g; if(database()->loadGame(index, g)) { QString msg; msg = tr("Append game %1 to %2.").arg(index + 1).arg(fileName.isEmpty() ? "Clipboard" : fileName); statusBar()->showMessage(msg); writer.append(fileName, g); m_databaseList->update(fileName); } } void MainWindow::copyDatabase(QString target, QString src) { if(target != src) { Database* pSrcDB = getDatabaseByPath(src); Database* pDestDB = getDatabaseByPath(target); DatabaseInfo* pDestDBInfo = getDatabaseInfoByPath(target); if(pDestDBInfo && pSrcDB && pDestDB && (pSrcDB != pDestDB)) { QString msg; msg = tr("Append games from %1 to %2.").arg(src).arg(target.isEmpty() ? "Clipboard" : target); statusBar()->showMessage(msg); for(int i = 0; i < pSrcDB->count(); ++i) { Game g; if(pSrcDB->loadGame(i, g)) { pDestDB->appendGame(g); } } pDestDBInfo->filter()->resize(pDestDB->count(), true); } else if(!pSrcDB && !pDestDB) { QFile fSrc(src); QFile fDest(target); if(fSrc.open(QIODevice::ReadOnly) && fDest.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) { while(!fSrc.atEnd()) { QByteArray line = fSrc.readLine(); fDest.write(line); } } fDest.close(); m_databaseList->update(target); } if(databaseInfo() == pDestDBInfo) { emit databaseModified(); } } } void MainWindow::slotDatabaseCopy(int preselect) { if(m_databases.count() < 2) { MessageDialog::error(tr("You need at least two open databases to copy games")); return; } CopyDialog dlg(this); dlg.setMode((CopyDialog::SrcMode)preselect); QStringList db; for(int i = 0; i < m_databases.count(); ++i) if(i != m_currentDatabase) db.append(tr("%1. %2 (%3 games)").arg(i).arg(databaseName(i)) .arg(m_databases[i]->database()->count())); dlg.setDatabases(db); if(dlg.exec() != QDialog::Accepted) { return; } int target = dlg.getDatabase(); if(target >= m_currentDatabase) { target++; } Game g; switch(dlg.getMode()) { case CopyDialog::SingleGame: m_databases[target]->database()->appendGame(game()); break; case CopyDialog::Filter: for(int i = 0; i < database()->count(); ++i) if(databaseInfo()->filter()->contains(i) && database()->loadGame(i, g)) { m_databases[target]->database()->appendGame(g); } break; case CopyDialog::AllGames: for(int i = 0; i < database()->count(); ++i) if(database()->loadGame(i, g)) { m_databases[target]->database()->appendGame(g); } break; default: ; } m_databases[target]->filter()->resize(m_databases[target]->database()->count(), true); } void MainWindow::slotDatabaseCopySingle(int n) { slotDatabaseCopy(0); } void MainWindow::slotDatabaseChanged() { database()->index()->calculateCache(); setWindowTitle(tr("%1 - ChessX").arg(databaseName())); m_gameList->setFilter(databaseInfo()->filter()); slotFilterChanged(); QString fname = databaseInfo()->filePath(); int lastGameIndex = m_databaseList->getLastIndex(fname); gameLoad(gameIndex() >= 0 ? gameIndex() : lastGameIndex, true, true); emit databaseChanged(databaseInfo()); emit databaseModified(); } void MainWindow::slotSearchTag() { m_gameList->simpleSearch(1); } void MainWindow::slotSearchBoard() { PositionSearch ps(databaseInfo()->filter()->database(), m_boardView->board()); m_openingTreeWidget->cancel(false); slotBoardSearchStarted(); databaseInfo()->filter()->executeSearch(ps); slotBoardSearchUpdate(); } void MainWindow::slotBoardSearchUpdate() { m_gameList->updateFilter(); slotFilterChanged(); finishOperation(tr("Search ended")); } void MainWindow::slotBoardSearchStarted() { startOperation(tr("Updating tree...")); } void MainWindow::slotSearchReverse() { databaseInfo()->filter()->reverse(); m_gameList->updateFilter(); slotFilterChanged(); } void MainWindow::slotSearchReset() { databaseInfo()->filter()->setAll(1); m_gameList->updateFilter(); slotFilterChanged(); } void MainWindow::slotToggleFilter() { m_gameList->m_FilterActive = m_toggleFilter->isChecked(); m_gameList->updateFilter(); } void MainWindow::slotTreeUpdate() { if(m_gameList->m_FilterActive) { m_gameList->updateFilter(); slotFilterChanged(); } finishOperation(tr("Tree updated.")); if(m_bGameChange) { slotGameLoadFirst(); m_bGameChange = false; } } void MainWindow::slotTreeUpdateStarted() { startOperation(tr("Updating tree...")); } void MainWindow::slotSearchTree() { if(m_openingTreeWidget->isVisible()) { m_openingTreeWidget->updateFilter(*databaseInfo()->filter(), m_boardView->board(), m_gameList->m_FilterActive, false); } } void MainWindow::slotSearchTreeMove(const QModelIndex& index) { m_bGameChange = false; QString move = m_openingTreeWidget->move(index); bool bEnd = (move == "[end]"); Board b = m_openingTreeWidget->board(); if(!bEnd) { Move m = b.parseMove(move); b.doMove(m); } if(m_openingTreeWidget->isVisible()) { m_openingTreeWidget->updateFilter(*databaseInfo()->filter(), b, m_gameList->m_FilterActive, bEnd); } } void MainWindow::slotDatabaseDeleteGame(int n) { if(database()->deleted(n)) { database()->undelete(n); } else { database()->remove(n); } m_gameList->updateFilter(); } void MainWindow::slotRenameEvent(QString ts) { RenameTagDialog dlg(0, ts, TagNameEvent); connect(&dlg, SIGNAL(renameRequest(QString, QString, QString)), SLOT(slotRenameRequest(QString, QString, QString))); dlg.exec(); } void MainWindow::slotRenamePlayer(QString ts) { RenameTagDialog dlg(0, ts, TagNameWhite); connect(&dlg, SIGNAL(renameRequest(QString, QString, QString)), SLOT(slotRenameRequest(QString, QString, QString))); dlg.exec(); } void MainWindow::slotRenameRequest(QString tag, QString newValue, QString oldValue) { if(database()->index()->replaceTagValue(tag, newValue, oldValue)) { if(game().tag(tag) == oldValue) { game().setTag(tag, newValue); } database()->setModified(true); if(tag == TagNameWhite) { database()->index()->replaceTagValue(TagNameBlack, newValue, oldValue); if(game().tag(TagNameBlack) == oldValue) { game().setTag(TagNameBlack, newValue); } } m_eventList->setDatabase(databaseInfo()); m_playerList->setDatabase(databaseInfo()); slotGameChanged(); } } void MainWindow::slotDatabaseDeleteFilter() { database()->remove(*databaseInfo()->filter()); m_gameList->updateFilter(); } void MainWindow::slotGetGameData(Game& g) { g = game(); } bool MainWindow::slotGameMoveNext() { Move m = game().move(game().nextMove()); m_currentFrom = m.from(); m_currentTo = m.to(); return gameMoveBy(1); } void MainWindow::slotNoColorSquare() { game().appendSquareAnnotation(m_annotationSquare, 0); slotGameChanged(); } void MainWindow::slotGreenSquare() { game().appendSquareAnnotation(m_annotationSquare, 'G'); slotGameChanged(); } void MainWindow::slotYellowSquare() { game().appendSquareAnnotation(m_annotationSquare, 'Y'); slotGameChanged(); } void MainWindow::slotRedSquare() { game().appendSquareAnnotation(m_annotationSquare, 'R'); slotGameChanged(); } void MainWindow::slotNoArrowHere() { game().appendArrowAnnotation(m_annotationSquare, m_annotationSquareFrom, 0); slotGameChanged(); } void MainWindow::slotGreenArrowHere() { game().appendArrowAnnotation(m_annotationSquare, m_annotationSquareFrom, 'G'); slotGameChanged(); } void MainWindow::slotYellowArrowHere() { game().appendArrowAnnotation(m_annotationSquare, m_annotationSquareFrom, 'Y'); slotGameChanged(); } void MainWindow::slotRedArrowHere() { game().appendArrowAnnotation(m_annotationSquare, m_annotationSquareFrom, 'R'); slotGameChanged(); } BoardView* MainWindow::CreateBoardView() { BoardView* boardView = new BoardView(m_tabWidget); boardView->setMinimumSize(200, 200); boardView->configure(); boardView->setBoard(standardStartBoard); boardView->setDbIndex(m_currentDatabase); m_boardViews.push_back(boardView); m_tabWidget->addTab(boardView, QString("%1").arg(m_boardViews.count())); m_tabWidget->setCurrentIndex(m_boardViews.count() - 1); return boardView; } void MainWindow::slotCreateBoardView() { CreateBoardView(); } void MainWindow::activateBoardView(int n) { if(m_tabWidget->currentIndex() >= 0) { BoardView* lastView = m_boardViews.at(m_tabWidget->currentIndex()); disconnect(SIGNAL(reconfigure()), lastView); lastView->disconnect(SIGNAL(moveMade(Square, Square, int))); lastView->disconnect(SIGNAL(clicked(Square, int, QPoint, Square))); lastView->disconnect(SIGNAL(wheelScrolled(int))); } BoardView* boardView = m_boardViews.at(n); m_currentDatabase = boardView->dbIndex(); connect(this, SIGNAL(reconfigure()), boardView, SLOT(configure())); connect(boardView, SIGNAL(moveMade(Square, Square, int)), SLOT(slotBoardMove(Square, Square, int))); connect(boardView, SIGNAL(clicked(Square, int, QPoint, Square)), SLOT(slotBoardClick(Square, int, QPoint, Square))); connect(boardView, SIGNAL(wheelScrolled(int)), SLOT(slotBoardMoveWheel(int))); m_boardView = boardView; } void MainWindow::slotActivateBoardView(int n) { activateBoardView(n); slotGameChanged(); m_databaseList->setFileCurrent(databaseInfo()->filePath()); database()->index()->calculateCache(); setWindowTitle(tr("%1 - ChessX").arg(databaseName())); m_gameList->setFilter(databaseInfo()->filter()); slotFilterChanged(); emit databaseChanged(databaseInfo()); } void MainWindow::slotCloseBoardView(int n) { if(n < 0) { n = m_tabWidget->currentIndex(); } if(m_boardViews.count() > 1) { m_boardViews.removeAt(n); m_tabWidget->removeTab(n); } for(int i = 0; i < m_boardViews.count(); ++i) { m_tabWidget->setTabText(i, QString("%1").arg(i + 1)); } } void MainWindow::UpdateGameTitle() { QString white = game().tag(TagNameWhite); QString black = game().tag(TagNameBlack); QString eco = game().tag(TagNameECO).left(3); if(eco == "?") { eco.clear(); } if(eco.isEmpty()) { eco = game().ecoClassify().left(3); } QString whiteElo = game().tag(TagNameWhiteElo); QString blackElo = game().tag(TagNameBlackElo); if(whiteElo == "?") { whiteElo = QString(); } if(blackElo == "?") { blackElo = QString(); } QString players = QString("%1 %2 - %3 %4") .arg(white).arg(whiteElo).arg(black).arg(blackElo); QString result = QString("%1   %2").arg(game().tag("Result")).arg(eco); QString event = game().eventInfo(); QString header = QString("%1").arg(event); QString title; if(!white.isEmpty() || !black.isEmpty()) { title.append(players); } else { title.append(tr("New game")); } if(game().result() != ResultUnknown || !eco.isEmpty()) { title.append(QString(", ") + result); } if(header.length() > 8) { title.append(QString("
") + header); } m_gameTitle->setText(QString("%1").arg(title)); } void MainWindow::UpdateBoardInformation() { QString name = "

" + databaseName() + "

"; QString nameWhite = game().tag(TagNameWhite); QString nameBlack = game().tag(TagNameBlack); if(!(nameWhite.isEmpty() && nameBlack.isEmpty())) { name += "

" + nameWhite + "-" + nameBlack + "

"; } name += "
"; m_tabWidget->setTabToolTip(m_tabWidget->currentIndex(), name); } void MainWindow::slotScreenShot() { QPixmap pixmap = QPixmap::grabWindow(effectiveWinId()); QString dir = AppSettings->commonDataPath(); QString shotDir = dir + "/shots"; QDir().mkpath(shotDir); QString fileName = shotDir + "/shot-" + QDateTime::currentDateTime().toString() + ".png"; pixmap.save(fileName); } void MainWindow::slotCompileECO() { (void) compileAsciiEcoFile("chessx.eco.txt", "chessx.eco", "chessx.gtm"); } chessx-1.0.0/data/images/arrow_red.png000644 001750 001750 00000014262 12103305243 020457 0ustar00niklasniklas000000 000000 PNG  IHDR((miCCPICC ProfileX XuXUͷOrN:tsQ E))E)Q)A$ DABB{sw~kϞwfY/,0 !Q$#]'gNԊp++sR%?>D +䶗w$1/NDa'3"x= ~=cgT$@ވyb~H;`BBG&G"$$l!X?ߦ>g,ȓȋ"Ã=YG#p!5Edr#sK4}L8cҵLmlGAaf^-ډzl_ol#clqzz$7 6ox~?CŗdxE 04k'Ã?} EσOz{-|b:~ţz PȿHdjC_c<huE6~BѤC]0`\I :X; @G@mh  !H($z +| ϐУp8KQEIbRR҅2,e CʷTTRT&TT'JƨQQ RPQQPߡ^!ѣ9ASBsffV֒66vG'Dg@MLWAnEOGO?E_IK `ȐpaaQс14IɄ))9&3's:s=: ;6KMg,<AY[X߰جَ]be[dg`Wg'g798l8qTp qrrqqsq>\b jZȣSók{wwOϞ/&~ /7@@KA2AA }BBBiB-B,&qu¯E(ED"DE&D*AEbbb%b#ⰸxEQ DDĤ$ddTT7ii}ҿeee*e^ɚ&ɶ.ˉJ&) OʷPWQ0HhحDRWZPPP.UTaPRRyQU=z_ZZwuI Z|TԸ1ɣyYsZWS\659Q@:tetIMzjz:QFto uc͌OpMjLLMQٚ73'Y  =b ,M,s-X [EXݳZ[YX鳥u]ӵ˶{e/bm@P8$tiЙ9reC]]S]>{ߍ-;GǶg窗WQx[;{G'gW7wO/o_˿1@/8Gq`YzePUnc|GPРО0ذp%Z$y859 EDDhƔlq8r'664vsqqWu'9~tDI'?&%T'$$$iVnQi}mhX׸ g>>5:9==5"ŏ1/^%ƼxC-wnN+M?џzo,qˇ?Q~*㞫`ZLJȷ߇> ]Za]{jZzF/_}s[Gqۅ;;m~ $y9 ` Jg@9#sȩ2(&Fk_#!נ(Ch>ya$2Ͱxeh&.s (  뉨*sIJ%ץ_ v5W((&)+V1VUTRǪ;0ѩYUmckgoogvEӖ)VO$۞KOvHrLt:|%Pk7owgW41OoǁA/gCCQt$H(hGVm>6|u&-'_2O G*KitB:c's-3ٯM3;7?Z0rI@➒[/55^n^bv 5LuRUot_CR㑦c'Z[例˼쎜=n5=n7`}IpH{Mc'.ʃCO kh>370{ffnC\_q{{˴{Y4~}|i`ax!EP߾|Xqk|gjZzІ/M-m߬X Ǎ!;MLDcK^s%+ [5Ww^>wBwDĚě$$oJK_,_pA1G)CJ*IW倅>.>!1 )9A%lkmeimmiyۡ߹rx9{gߜ|BB|\\|5I%crPlc[hڟ0؟s^rCJUjiڹ)A,蜕>q!2,*;~-)X:}CW*+_}Rn?ieӻٖw-[jzzzFÍGk}W |:ɧّ駯GLJ'?~~iE˲Wߤ=.roɬŹ[K.F|uf]a2 O*aN "oᶱ;ߨ]hU7`䠗Y` TXQ` `I ߏ@A\H)41 iHFY `|b!=$C ҠP Zia9(4ӅPH.GHb1X ! sSdd!܈"b҇rʌZFV. =4C(osLLWXrXX_%q9+/\'#,d /𔔐ܐz,]$"/))Z-r"<\ .jTi6jhO,ꡑlhcjiRk:dÂ%ɪzҖ>㚳|7]#Ƴk['wП9/-6$8t \"l>9۽K'o1hws0ə0p.CQgP}hZŐcl09"6;½ dd2Rry,' GTTe%44崢tt#nN00V022XjY-XWJ W8pZqraM])fB BDċ%p']($#*S~TARr QUI逋VvNn^iYmh+9ka{).Cq[=T=OxzS Ƅ g$=>z1 '㧶RN`ˬ=qv\HYnMY¢beW*IV-ݐ߸Ӑݬ|wݨGj]ꆧF Zb'_,|=]ς͗ԯ7UƯ=ES?b@Q̀F,(i!bD Ma,[$WP(T!jA4 :&ӏǺco`wpVmYAp<|ŒQ> ȩ6cWhhht e  mfkYYXϰɳbOxřƥnj˯KŒH~_! &-&!!(%,)="sM6AM^SA@F `TӲIѭ՟33k1>Hanb]nҎ!3ˡC\߻{"]o;?]!|m+z1'Of&R%%sԦp\;s>[HNd[~υ"g/CW*RW1WmQuKNlݶ{7TuTw~;7?{0; W.o25LD9/Yg['?7օ~9me+/=DȏowwW}*ݩ@t9ci(E fY QZ!tIDATX U0;G# ty)#@oOII 9'#(۬yY3+t7LPEX­E<[.sBnߟQK9r:#ˁTIm1NqN #RB rޣR eB4lbN>_0׏Ȁht#%KT}dc%ވU1qpŨdZ &B`k@6H.Ǎ5!GkAN׀s#9\H/`705r0%r60rp. q's`;-`d`XȠHՇ=oc L@ uatEXtSoftwareAdobe ImageReadyqe<&IDATx}GvW1}}`f b%@J|-va;6ekiCl9_ kՂ+rD`́{tfU `0@v" ]]Gu/3J)ZVj-Z @j-Z @j-Z @}y;oRQ5)@G  sN dOg {d;biU t3짜aO1CZ ]?!!P|GLgY 6 Ysk\7^ʶߟ9dw i 0̀Sݚ"[ §[؅gc+ܼk>1=44n_ e)&W+[!o;Ͼ%sEVl`~IEG耨ۀezms:{qF1ZEe db@V|/khg8g }/gA`%]C]봡н;=m> Tn 0~_iDhGMֻ ׵:(_'욖[8?d?`E_@AuaRxo k{/~%AyGN a¹=xݎ@fL%, t#;6{q NoFm.@9a  lĈ9X)QG!)X}EV#Tݘ%Eg)'oyhlW |j }GU D,C<.pEi.QU嚬j RlSS.h`5kGPֹ$p岤6g`$+.?z{. _zTZF-AH[ڱqM$t Z_.y=@FU/~Y5jBg[K(0 ,!A]p?9uK534xeНQHt*j_bOXy~`ᇪ}b i{J1 ZG$fD#EPj S`/W\ 5BJCv/c_ 9۟'"PD_f Fсb%**:J@4YD2H8,Y67 <ZE}PkhW11Hfpp F:|ڽVcu#A:ISwDLNJ({V[eBxL뀕e\[`C L nm 1 ;;x0*:{]#|Z:O2TVֽ{1;xp\:90Ӎ >Lbm&[nشfx%{f.]fŸ¯3~"{̈́7N&rvT|Av}mHXGt η ᏽ„傮)N n#MZAJizG T.ajyׇA*IvgNvw'4,+yF#B2MP/?bR:bfF{;X8ؿИŸ9L>7[ :]}@GCMX=gj>+#w85Ro-5\;Esw7_E%q܋]w?|f,; ^"[ -bl0#H~q>"Yj_qs\ai ##7.$QuKP#=lr['P-DbmmAd`qMR Ҍ|p }gV~J*ūxu„y|vT!P.\>ӳwD#N0vyP+@P<2[`PCZ Vczp= i7ń.asQܸ }Q*a"b\^Zg+z+ wy>cf^W6Ե ?я>o]z-~YvrzoC_C[8bA\uvM0 Y<rj่a7\BݦL&\S xg0?C>hywIZ98[rִ t/1sb#{q^eQԭg8}ԩ*_xoe/vqyKݫT#Xq237RyD6(ǘDb萦>rHc!^6h0;ت&5 m<ߕ/9@~% -;H*!hȧO%A}qjM6}R*x0=ufo\Xlzj5N:=kΞʱ.3͹Y f eִ<=%&Ek' 1.O Y ׳W/ /'bh?nf:;;Lͣ܁=ŋ>afĹ}jP p q .xPl@|Dtun,}Vl0vF(}8\؃;|U4. J~koKI<-ߌ>.,#{KT*}vPX[:Ձh4"k2ɧdMF(9?u8jŖD*40wRě)p yM9#ܟF҇!p7n_pT,5zrGZFji|^ <8_q'yn^)2ի]C\k/ r `nȭ}@5z6 [Q\LM"_nl,$FP}F ,GQr}7~G"45פ:-:@r]^.+ `[gn>B(0 ˲BT pTك˸+tt"dM+p}=AI2(CE.-J#Sr _]@+rO|V1PI>Bט_f>'iձp;*Tz1XL,,gӈ+&y28s;f4s kTbMΠ Tr1oBȞmv\ZoPz"O-Uc3mk,ty.z$ҵơ/C }ؑA_:!jlQY\"Ӓ0ifY|:jyj)*a%ؚ Dg$IO׈1l9m dX[[zmE xHNy |}HW0j9T\Y`?׿( i hp _N#3 J]C OabO-yC;Vu3_#XϬk>00h#~[mqvRG oi*̓ Z1꟮2㲐C~roE{ NhLn ,n[Aoo6מQך}:# +Zx*Op*Kpx !|4uN"Ա > UG=4|;l԰&x ]\^íj}o @\ĭB/-0:X1҅U 3}%9^=Ծ:C}nH4|Fy i,T0x| ѧ䞺|.-NF3qTfSJDZٵV)ȅbbc֌ w>+3 +e!~cǡhd=Z)k7K%6pfX7RWY 2xg`TA8VGN-ƴt/`[1fo0j##zVzpoo;daL3GhCw ; `7Qf)ށn)k .! _#X^gcN>/03/~ȞֳnV-9tvDz+pq~9qDz/MՅEu(PxUfnhyeU>סvV )pj^b NmiYr(է6El|iekVۭ*|UA5ȁE:?kYg CR̿ZuB%eċG/9[IvIBW f?pcuLLO#pyDg/|cGOm*SDq¡0"~eyBeM4ӎ0 І:N?"v]TC>xGh[s^GDzl"A$b*#o`N/ |YxM{ De𱗧>n>r0֦CAFD[*ªL8K2*ΥU$`QS*z MċGNajԆ7}P;'+4N=Ǣ <ݫs+~L0ŦPj4ɈcD0vkO0bGmhFf̿wQg(&xհ6taB8@EOɗA!ヘFGiin{F/?̤MbK߇ p2S}f qVzg%W*ECEÞ!k.~߮0ȭ5֪Qiݦ+ :; WO*{ s*Z|9T'ݽ{ԶHfi,UKt,V~Wؽ$ C4Ӻ痯z1@V au.ϋAvO!:{ cC:AACȲeCm!+9ThZ^IG%1KV Y `'1&?<;7cUi]׎h6>_`B>p\UawDa@e8s;w 8=r(m0f x.` ߸Ƈe}F-ܓH+S"Y@DZ3Y)3`?bWZ K5:^U7QZN*Vn?`V~Fŕjv1| "i Bo*4<!@4l !`jHm#MΩQt{@"&F':FB2ұ!ۇ@a @? G~%t\b!Opw8H?C?_t#h}fQX{:Š7ۂmҪ⼏9w)쇧A$"`2%|= '.<"IlTXrVB9pir2q&]#P(h7ZljiN^\Z@ʜk]nJߋt HD)7ZN CԳ)rkPemC +Lj2{y/e`.70ZKw/ ,_jwSJpq;}RMݙ8ʴ`54aY༆ ɘJ"7xh̘aXKCWU]~>'FZȡxwVgpNw %uS#?>丟PDP5T;mh^f]q*ŠS?42g 4#Q'R5PI!g G%:xB'b9CJ5]s jfQȰa#})b{7nOB⺸TXgghLAgG'^[ǂmYLbz(Ln`% ۻ@3Tƃ4fxt6FD"$V=d.F +Zh-4ȨCpz2J WI +++mT%-pnaEJs솸% / Bt,=*V%ebD"|;AԒV8I lD#nb#Y,>]ƺ^'.Bͼ݂Q $?J؁:E`&.{)Mj3 jSsgbiv)rv,du#)/nf O]K[ZF-l5d6:B&|sHr_VHh瑄pj5>*0ƾja}dEQ5|c+z uHRccH*J .x-;WJ!O8b$b[/()sxtkgQLDvl싻/=1G^ k$f f./Z'ytX)otxm*Z?S.wEk6l^^*4SC+xvIXC.n9'w:m vĴ-atK`$ov~O:eSv٭CLxui!qܠQoID?FT!C |/ ;K;.[AB;>aJa)dÏ3@Tzh4~#' /`H9{An8Og3 Up;_M+t.Wsx'֌&?]K=ڍ\6HSXȯc8um`WQ{eH\Һ~ЁbU#M،Zq^}7Qz9вqkIW;/>BHnijsCoz)BavRŶuKsڣjegwvr$@\ۮ=ծ1š\:!kW諥 n7pZ,O2s$iOJ*+>gM\j:#zwE)%Lt P3uKJFP33ke\^KBwr^ڨ-~Zz4z#֋JuW)|>8vuw~Ή皂@\CTc@?o %X{Y/;; ۯ;Vgfw.6 (%7)ڿ?X='8q%,"HXS(50na14ʢ`]p>ǍQԢ]nAv|zk>GgpdPҸ"{O3lq0?ZMSN0sasmGlǸ b8"Tzy٤=G_KGJ/kb?PC,V@_8H*VtFҫfresA~n;wkUP!1Ic&ufvCwh!ᅴeyQ52ZL#:|3CHC~@AMrhCsk=WsEj{oa&r~H-s;3h 2\6Sh M`j}xrj `A*݀(xEjxg47Ztz竨,[k7BBQ 6@J^v-0|2h'޷[2{67XFĎkSvG{#y|' :_b:o mwҟ2߃v nD݋_oulωKcVj܌c6Q[ ͸PYP&`9 :,ҷ7Iս]>ޫ%Oߓ1i~F{7bG:nF'[|an{iz<"zf ?+Um;l߶dy[fgGC8)x p B qp|G]9čx@+dy}5IuW37`ıP3(}TsGs۬?n'\9O]FH5mZӞKSo/ |K@+ED71yKIۤXL HhN'yY@!$~WrD^;v)C9Lr&<タlwy$qtް R5g K 6Fcv~v_j8\9xeqza/LWpGd=npF8vMLN;ULq-L<3#'siڟ:ڗ.hZhZVkZhZVkZhZV/}OIENDB`chessx-1.0.0/data/sounds/move.wav000644 001750 001750 00000031400 12071615462 017524 0ustar00niklasniklas000000 000000 RIFF2WAVEfmt DdataL(bb __\\<>&&55ee==QQ 44 rr88((SSٳճvv''cc  d d e e yy  dd44oo))HHOO55\\II  AA~~++ԖttNNccԙܙ**EE ssͤؤا^^^ ^ u!u!\\nn VV22++@@LLNNEEH4H4::::ӶӶ >>pp]]ڝFF%%RR``YY. .  & &11k:k:??4A4A==66))==--00++ ~~{{bbxx MM 22UUjjEEɩhhV V ww22ԣȣȍÍ::қT*T*Q;Q;DDBB?7?7!!66ǴNjggݠݠղղ̏**-.-.''jj܌EEPPj&j&U>VV<<eeffh&h&*+*+m,m,I)I)!!  }}NN**5/5/..''00%% __ 0'0't(t(##88 eeMMݒܒ;;**UUqq[ [ 8 8 ++eeMM99LL22NNyyG G GGddy"y"J.J.a4a4k3k3a+a+c c vv99;;44##""ddm m ``vv##%%!![[66**!!/ / ((Z+Z+))$$ 11  f f ' ' ,,{ { CC!$!$@'@'''&&%%@#@#!!Y!Y!N!N!*!*!f f ,,X X ggzz  ZZ``::QQܖۖkk;;  ::  ??ii ++  ||%% iiNNjjuuII99]]   vv&&11wwVV-- ]]  \\VV,,QQ55::[[ffXX̺ɺ++֟͟jj//LLTT ==..NNߥۥll]]BBww}}BB߁VVTT 22(($$} } YY{{MMnn@@""))^^SSDDppHH''YY  llhhq q ]]ZZ"",,OO>>//BB>>AAKKԓד%%LLDD yy,,UUhh//tt..{{]]  BB[[3377$$\\``JJ||PP' ' g g 4 4 YYvv@@ BB++~~jjpp<>ssii %%uu ddAAYY  l l v v ]]vvjj__ll``hh..pp==LL]] II22GG6644^^ss@ @ nn' ' V V {{--ooee <<,,HH;;KKaaww}}JJ++55::;;IIjj!!}}&&$$..NN]]!!====77ss33  99++vv}}@@ hh>>GG%%EEmmdd))55''++__44vvKK ||####44mm bb77bb77V V  8866FF22**hhCCkk\ \ & &   + + D D __--%%^^++;;UUpp##//%%//33JJ[[ggnn11jjWWII..  tt77CCYYRRllHH}}RRuu$ $ 8 8 i i mmzzYY99q q n n   55oo[[oo~~aaVVYYDDZZ22yynn55KKss CC  / / m m ??44zzjj""66  33~~{{ZZ;;66QQ22nnbbBB111 1 0 0 ! ! GG[[00llwwCC" " \ \ 0 0 OO88qqhhee))uurr^^NN..JJ\\6677OO NN{{AAGGddoo,,jjFFNNMM((JJ55NNZZNN0011VV//00--UUsskknnHHUU44NNXX{{uu11**11\\UU''EEyyVVSSLLqq==++    DDPPGGYYTT....__ww5555 ``88 ||((OO  HH[[{{BB33< > 1 1 z z >>  CCkk  --<<##44TT55nnrrbbWW@@ff<<;;44PPhhUUEE3311uu[[FF22WWpp  ..11))  ||55ee^^HH  %%MM }}LLbbrruu  }}:://77##DDHHTT""11rr##99((NN,,  --mm\\;;HHUU44iiMM11mmOOggoo77**~~[[}}**22mmMMkk--UULL//33BB!!IIHH'' BB^^00;;AA88OOHHLLdd::!!PPEEww77 ::UU__LL\\CC ##IIff(($$LL33))@@--[[HHww::99^^zzKK>>  ((qqKKIItt++&&@@GG;;~~//KK44[[qq$$DD4455}}``&&//vvaa}} kkoo>>**KKOO}}11 ccgg 33LLLL44SSYY22??aaDDQQ//RR((""ii88 KK##MMvvRRzzll::99::00__@@mm""\\qqaa66<<KKBB%%((..^^HHDDiiZZ,,kkaa,,UUHH PP<<""ee||mmCC!!2244&&((..&&GGQQ||      ||MM ==||vv++ZZEEuuhh]]``NNppQQ BBdd1188vvrrpp== [[&& < RenameTagDialog true 0 0 509 249 Rename Tags in Database 0 0 Rename all Occurrences ... QLayout::SetDefaultConstraint from Qt::NoFocus true to Press 'Rename' to proceed. Qt::Vertical 20 40 Qt::Horizontal Qt::Horizontal 40 20 Rename Close editTo btRename btClose editFrom chessx-1.0.0/src/gui/dockwidgetex.cpp000644 001750 001750 00000001345 12223260306 020350 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "dockwidgetex.h" DockWidgetEx::DockWidgetEx(const QString &title, QWidget *parent, Qt::WindowFlags flags) : QDockWidget(title, parent, flags) { } DockWidgetEx::DockWidgetEx(QWidget *parent, Qt::WindowFlags flags) : QDockWidget(parent, flags) { connect(this, SIGNAL(visibilityChanged(bool)), this, SLOT(onVisibilityChanged(bool))); } void DockWidgetEx::showEvent(QShowEvent * event) { QDockWidget::showEvent(event); if(isVisible()) { raise(); } } chessx-1.0.0/src/database/search.h000644 001750 001750 00000020372 12223260306 017562 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 Marius Roets * * (C) 2005-2006 William Hoggarth * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __SEARCH_H__ #define __SEARCH_H__ class Database; class Filter; #include "board.h" #include "game.h" #include "partialdate.h" #include /** * @defgroup Search Search - different ways to lookup games **/ /** @ingroup Search The Search class is an abstract base class that represents a search on one criteria. @todo - Operators for joining may be obsolete. - Cloning may be obsolete - Type may be replaced by dynamic typecasting. - Or and And are the same, they probably should be joined. */ class Search { public: enum Type { NullSearch, PositionSearch, EloSearch, DateSearch, TagSearch, FilterSearch, NumberSearch}; /** Operator for joining filters */ enum Operator {NullOperator, Not, And, Or, Remove }; /** Standard constructor. */ Search(); /** Cloning search object - probably obsolete */ virtual Search* clone() const = 0; /** Standard destructor. */ virtual ~Search() = 0; virtual Type type() const = 0; virtual int matches(int index) = 0; virtual void setDatabase(Database* database); protected: Database *m_database; Game m_game; }; /** @ingroup Search The NullSearch class is empty search, doing nothing. */ class NullSearch : public Search { public : NullSearch(); virtual NullSearch* clone() const; virtual ~NullSearch(); virtual Type type() const; virtual int matches(int index); }; /** @ingroup Search The PositionSearch class is a search that checks for given position. @todo Performance is seriously bad */ class PositionSearch : public Search { public: /** Empty constructor. */ PositionSearch(); /** Standard constructor. */ PositionSearch(Database* db, const Board& position); /** Object cloning - probably obsolete. */ virtual PositionSearch *clone() const; /** Standard destructor. */ virtual ~PositionSearch(); /** Type - probably obsolete. */ virtual Search::Type type() const; /** @return sought position. */ Board position() const; /** Sets sought position. */ void setPosition(const Board & position); /** Return moveId the move of after which the game matches the search + 1. E.g. for standard game and chess start position 1 is returned. */ virtual int matches(int index); private: Board m_position; }; /** @ingroup Search The EloSearch class is used for searching both white and black player Elo. */ class EloSearch : public Search { public: /** Standard constructor. */ EloSearch(Database* database, int minWhiteElo = 0, int maxWhiteElo = 4000, int minBlackElo = 0, int maxBlackElo = 4000); /** Cloning - probably obsolete. */ virtual EloSearch *clone() const; /** Standard destructor. */ virtual ~EloSearch(); /** Type - probably obsolete. */ virtual Type type() const; /** @return minimum Elo of white player. */ int minWhiteElo() const; /** @return maximum Elo of white player. */ int maxWhiteElo() const; /** @return minimum Elo of black player. */ int minBlackElo() const; /** @return maximum Elo of black player. */ int maxBlackElo() const; /** Set acceptable rating ranges. */ void setEloSearch(int minWhiteElo = 0, int maxWhiteElo = 4000, int minBlackElo = 0, int maxBlackElo = 4000); void initialize(); /** Return true if the game at index matches the search */ virtual int matches(int index); private: int m_minWhiteElo; int m_maxWhiteElo; int m_minBlackElo; int m_maxBlackElo; QBitArray m_matches; }; /** @ingroup Search The DataSearch class defines a search based on a date range */ class DateSearch : public Search { public: /** Standard constructor. */ DateSearch(); /** Constructor for searching games in given time period. */ DateSearch(PartialDate minDate, PartialDate maxDate); /** Object cloning - probably obsolete. */ virtual DateSearch *clone() const; /** Standard destructor. */ ~DateSearch(); /** Type - probably obsolete. */ Type type() const; /** @return beginning of the acceptable period. */ PartialDate minDate() const; /** @return end of the acceptable period. */ PartialDate maxDate() const; /** Sets whole period. */ void setDateRange(PartialDate minDate, PartialDate maxDate); /** Return true if the game at index matches the search */ virtual int matches(int index); private: PartialDate m_minDate; PartialDate m_maxDate; QBitArray m_matches; }; /** @ingroup Search The TagSearch class is used for tag search. Only simple substring searches are supported for now. @todo Improved performance by creating a bit array of matching values */ class TagSearch : public Search { public: /** Simple constructor */ TagSearch(Database* database, const QString& tag, const QString& value, bool partial = true); /** Range constructor */ TagSearch(Database* database, const QString& tag, const QString& value, const QString& value2); /** Makes a deep copy of TagSearch object. Probably obsolete */ virtual TagSearch* clone() const; /** Standard destructor. */ ~TagSearch(); /** Type - probably obsolete. */ Search::Type type() const; /** @return tag to be searched */ QString tag() const; /** @return value to be matched. */ QString value() const; QString minValue() const; QString maxValue() const; /** Set tag to be searched */ void setTag(const QString& tag); /** Set value to be matched */ void setValue(const QString& value); /** Return true if the game at index matches the search */ virtual int matches(int index); /** initialize the search. Done automatically in constructor, or when values are changed */ void initialize(); /** initialize the search. Done automatically in constructor, or when values are changed */ void initializeRange(); private: QString m_tagName; QString m_value; QString m_value2; QBitArray m_matches; bool m_bPartial; }; /** @ingroup Search The NumberSearch class is used for game number search. */ class NumberSearch : public Search { public: /** Simple constructor */ NumberSearch(Database* database, int start, int end); /** Simple constructor. Supports "N1" or "N1-N2" format */ NumberSearch(Database* database, const QString& value); /** Type - probably obsolete. */ Search::Type type() const; /** Makes a deep copy of TagSearch object. Probably obsolete */ virtual NumberSearch* clone() const; /** Set range to be selected */ void setRange(int start, int end); /** Set range to be selected. Supports "N1" or "N1-N2" format. */ void setRange(const QString& value); /** Return true if the game at index matches the search */ virtual int matches(int index); private: int m_start, m_end; }; /** @ingroup Search * The FilterSearch class is not a real search class. It is used to * combine other searches with a filter, in order to solve the search * tree quicker if possible. For instance if a search is combined with a * filter using the AND operator, only games in the filter are searched. * If it is combined with the OR operator, only games not in the filter * are searched. */ class FilterSearch : public Search { public: FilterSearch(); FilterSearch(Filter* filter); virtual FilterSearch* clone() const; virtual ~FilterSearch(); Type type() const; bool contains(int game) const; Filter* filter() const; void setFilter(Filter* filter); virtual int matches(int game); private: Filter *m_filter; }; #endif // __SEARCH_H__ chessx-1.0.0/src/database/pgndatabase.cpp000644 001750 001750 00000051553 12223260306 021126 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 William Hoggarth * * (C) 2006 Ejner Borgbjerg * * (C) 2007 Marius Roets * * (C) 2006-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include #include #include #include #include "board.h" #include "nag.h" #include "pgndatabase.h" #include "settings.h" PgnDatabase::PgnDatabase(bool b64bit) : Database(), bUse64bit(b64bit) { initialise(); } PgnDatabase::~PgnDatabase() { close(); } bool PgnDatabase::open(const QString& filename, bool utf8) { if(m_isOpen) { return false; } m_break = false; m_filename = filename; if(openFile(filename)) { m_isOpen = true; m_utf8 = utf8; return true; } return false; } void PgnDatabase::parseGame() { skipMoves(); } bool PgnDatabase::readIndexFile(QDataStream &in, volatile bool* breakFlag) { return (index()->read(in, breakFlag)); } bool PgnDatabase::writeIndexFile(QDataStream& out) const { return (index()->write(out)); } QString PgnDatabase::offsetFilename(const QString& filename) const { QFileInfo fi = QFileInfo(filename); QString basefile = fi.completeBaseName(); basefile.append(".cxi"); #if QT_VERSION < 0x050000 QString dataPath = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation) + "/chessdata"; #else QString dataPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/chessdata"; #endif QString dir = AppSettings->value("/General/DefaultDataPath", dataPath).toString(); QString indexPath = dir + "/index"; return(indexPath + "/" + basefile); } bool PgnDatabase::readOffsetFile(const QString& filename, volatile bool *breakFlag) { if(!AppSettings->getValue("/General/useIndexFile").toBool()) { return false; } m_gameOffsets32 = 0; m_gameOffsets64 = 0; QFile file(offsetFilename(filename)); if(!file.open(QIODevice::ReadOnly)) { return false; } QDataStream in(&file); short version; unsigned short magic; in >> version; in >> magic; if(!((version <= 1) && (magic == 0xce55))) { return false; } int streamVersion = QDataStream::Qt_4_7; if(version > 0) { in >> streamVersion; } in.setVersion(streamVersion); QFileInfo fi = QFileInfo(filename); QString basefile; QDateTime lastModified; in >> basefile; in >> lastModified; if(basefile != fi.completeBaseName()) { return false; } QDateTime lastModifiedStored = fi.lastModified(); if(lastModified != lastModifiedStored) { return false; } in >> m_allocated; emit progress(1); if(bUse64bit) { m_gameOffsets64 = new qint64[m_allocated]; for(int i = 0; i < m_allocated; ++i) { in >> m_gameOffsets64[i]; } } else { m_gameOffsets32 = new qint32[m_allocated]; for(int i = 0; i < m_allocated; ++i) { in >> m_gameOffsets32[i]; } } emit progress(2); in >> magic; readIndexFile(in, breakFlag); unsigned short finalMagic; in >> finalMagic; if(*breakFlag || (finalMagic != 0x55ec)) { delete[] m_gameOffsets32; delete[] m_gameOffsets64; m_index.clear(); m_gameOffsets32 = 0; m_gameOffsets64 = 0; m_allocated = 0; return false; } return true; } bool PgnDatabase::writeOffsetFile(const QString& filename) const { if(!AppSettings->getValue("/General/useIndexFile").toBool()) { return false; } QFile file(offsetFilename(filename)); if(!file.open(QIODevice::WriteOnly)) { return false; } QDataStream out(&file); short version = 1; unsigned short magic = 0xce55; int streamVersion = out.version(); out << version; out << magic; out << streamVersion; QFileInfo fi = QFileInfo(filename); QString basefile = fi.completeBaseName(); out << basefile; out << fi.lastModified().toUTC(); out << m_count; if(bUse64bit) { for(int i = 0; i < m_count; ++i) { out << m_gameOffsets64[i]; } } else { for(int i = 0; i < m_count; ++i) { out << m_gameOffsets32[i]; } } out << magic; writeIndexFile(out); unsigned short finalMagic = 0x55ec; out << finalMagic; return true; } bool PgnDatabase::parseFile() { if(readOffsetFile(m_filename, &m_break)) { m_count = m_allocated; emit progress(100); return true; } if(m_break) { return false; } bool ok = parseFileIntern(); writeOffsetFile(m_filename); return ok; } bool PgnDatabase::parseFileIntern() { //indexing game positions in the file, game contents are ignored qint64 size = m_file->size(); int oldFp = -3; qint64 countDiff = size / 100; qint64 nextDiff = countDiff; int percentDone = 0; while(!m_file->atEnd()) { if(m_break) { return false; } IndexBaseType fp = skipJunk(); if(fp == oldFp) { skipLine(); fp = skipJunk(); } oldFp = fp; if(fp != -1) { if(!m_currentLine.isEmpty()) { addOffset(fp); parseTagsIntoIndex(); // This will parse the tags into memory parseGame(); if(!m_file->atEnd()) { if(fp > nextDiff) { nextDiff += countDiff; emit progress(++percentDone); } } else { emit progress(100); } } } } return true; } bool PgnDatabase::openFile(const QString& filename) { //open file QFile* file = new QFile(filename); if(!file->exists()) { delete file; return false; } file->open(QIODevice::ReadOnly); m_file = file; return true; } bool PgnDatabase::openString(const QString& content) { //open file initialise(); m_filename = "Internal.pgn"; m_isOpen = true; QByteArray byteArray; byteArray.append(content.toLatin1()); QBuffer* buffer = new QBuffer(&byteArray); buffer->open(QIODevice::ReadOnly | QIODevice::Text); m_file = buffer; m_utf8 = false; return parseFile(); } QString PgnDatabase::filename() const { return m_filename; } void PgnDatabase::close() { //close the file, and delete objects if(m_file) { m_file->close(); } delete m_file; m_file = 0; delete[] m_gameOffsets64; delete[] m_gameOffsets32; //reset member variables initialise(); } void PgnDatabase::loadGameMoves(int index, Game& game) { if(!m_isOpen || index >= m_count) { return; } game.clear(); seekGame(index); skipTags(); QString fen = m_index.tagValue(TagNameFEN, index); // was m_count -1 if(fen != "?") { game.setStartingBoard(fen); } parseMoves(&game); } bool PgnDatabase::loadGame(int index, Game& game) { if(!m_isOpen || index >= m_count) { return false; } lock(); //parse the game game.clear(); loadGameHeaders(index, game); seekGame(index); skipTags(); QString fen = m_index.tagValue(TagNameFEN, index); // was m_count - 1 if(fen != "?") { game.setStartingBoard(fen); } parseMoves(&game); unlock(); return m_variation != -1 || fen != "?"; // Not sure of all of the ramifications of this // but it seeems to fix the problem with FENs } void PgnDatabase::initialise() { m_file = 0; m_gameOffsets64 = 0; m_gameOffsets32 = 0; m_inComment = false; m_isOpen = false; m_filename = QString(); m_count = 0; m_allocated = 0; } void PgnDatabase::addOffset() { IndexBaseType fp = m_file->pos(); addOffset(fp); } void PgnDatabase::readLine() { if(m_file->atEnd()) { m_lineBuffer.clear(); m_currentLine.clear(); return; } m_lineBuffer = m_file->readLine(); if(m_utf8) { QTextStream textStream(m_lineBuffer); m_currentLine = textStream.readLine().simplified(); } else { QTextStream textStream(m_lineBuffer); QTextCodec* textCodec = QTextCodec::codecForName("ISO 8859-1"); if(textCodec) { textStream.setCodec(textCodec); } m_currentLine = textStream.readLine().simplified(); } if(m_inComment || !m_currentLine.startsWith("[")) { m_currentLine.replace("(", " ( "); m_currentLine.replace(")", " ) "); m_currentLine.replace("{", " { "); m_currentLine.replace("}", " } "); m_currentLine.replace("$", " $"); } } inline void PgnDatabase::skipLine() { m_lineBuffer = m_file->readLine(); } void PgnDatabase::seekGame(int index) { IndexBaseType n = offset(index); if(!m_file->seek(n)) { qDebug() << "Seeking offset " << n << " failed!"; } readLine(); } void PgnDatabase::parseTagsIntoIndex() { m_index.setTag("Length", "0", m_count - 1); m_index.setTag("Result", "*", m_count - 1); while(m_currentLine.startsWith(QString("[")) && !m_file->atEnd()) { int tagend = m_currentLine.indexOf(' '); QString tag = m_currentLine.mid(1, tagend - 1); int valuestart = m_currentLine.indexOf('\"', tagend + 1); QString value = m_currentLine.mid(valuestart + 1); bool hasNextTag = false; while(!value.endsWith("]") && !m_file->atEnd()) { readLine(); if(m_currentLine.isEmpty() || m_currentLine.startsWith("[")) { hasNextTag = true; break; } value += ' ' + m_currentLine; } int valueend = value.lastIndexOf('\"'); if(valueend != -1) { value.truncate(valueend); } if(value.contains("\\\"")) { value.replace("\\\"", "\""); } // quick fix for non-standard draw mark. if(tag == "Result" && value == "1/2") { value = "1/2-1/2"; } // update index m_index.setTag(tag, value, m_count - 1); if(!hasNextTag) { readLine(); } } // skip trailing whitespace while(m_currentLine.isEmpty() && !m_file->atEnd()) { readLine(); } } bool PgnDatabase::parseMoves(Game* game) { m_gameOver = false; m_inComment = false; m_comment.clear(); m_precomment.clear(); m_newVariation = false; m_variation = 0; do { if(m_inComment) { parseComment(game); } else { parseLine(game); if(m_variation == -1) { return false; } } } while(!m_gameOver && (!m_file->atEnd() || m_currentLine != "")); if(m_gameOver) { if(game->plyCount() == 0) { if(!m_precomment.isEmpty()) { game->setAnnotation(m_precomment); m_precomment.clear(); } } } return true; } void PgnDatabase::parseLine(Game* game) { QStringList list = m_currentLine.split(" "); m_pos = 0; for(QStringList::Iterator it = list.begin(); it != list.end() && !m_inComment; ++it) { if(*it != "") { parseToken(game, *it); if(m_variation == -1) { if(!(m_currentLine.startsWith("["))) { skipLine(); // illegal move in the buffer! } return; } } m_pos += (*it).length() + 1; } if(!m_inComment) { readLine(); } } inline void PgnDatabase::parseDefaultToken(Game* game, QString token) { //strip any move numbers if(token.contains("...")) { token = token.section("...", 1, 1); } else if(token.contains('.')) { token = token.section('.', 1, 1); } else if(token.indexOf(QRegExp("[1-9]")) == 0) { token.clear(); } //look for nags Nag nag = NullNag; if(token.endsWith("!")) { if(token.endsWith("!!")) { nag = VeryGoodMove; } else if(token.endsWith("!?")) { nag = SpeculativeMove; } else { nag = GoodMove; } } else if(token.endsWith("?")) { if(token.endsWith("??")) { nag = VeryPoorMove; } else if(token.endsWith("?!")) { nag = QuestionableMove; } else { nag = PoorMove; } } if(!token.isEmpty()) { if(m_newVariation) { game->backward(); m_variation = game->addVariation(token, QString(), nag); if(!m_precomment.isEmpty()) { game->setAnnotation(m_precomment, m_variation, Game::BeforeMove); m_precomment.clear(); } m_newVariation = false; } else // First move in the game { m_variation = game->addMove(token, QString(), nag); if(!m_precomment.isEmpty()) { game->setAnnotation(m_precomment, m_variation, Game::BeforeMove); m_precomment.clear(); } } } } void PgnDatabase::parseToken(Game* game, const QString& token) { switch(token.at(0).toLatin1()) { case '(': m_newVariation = true; break; case ')': game->moveToId(game->parentMove()); game->forward(); m_newVariation = false; m_variation = 0; break; case '{': m_comment.clear(); m_precomment.clear(); m_inComment = true; m_currentLine = m_currentLine.right((m_currentLine.length() - m_pos) - 1); break; case '$': game->addNag((Nag)token.mid(1).toInt()); break; case '!': if(token == "!") { game->addNag(GoodMove); } else if(token == "!!") { game->addNag(VeryGoodMove); } else if(token == "!?") { game->addNag(SpeculativeMove); } break; case '?': if(token == "?") { game->addNag(PoorMove); } else if(token == "??") { game->addNag(VeryPoorMove); } else if(token == "?!") { game->addNag(QuestionableMove); } break; case '+': if(token == "+=") { game->addNag(WhiteHasASlightAdvantage); } else if(token == "+/-") { game->addNag(WhiteHasAModerateAdvantage); } break; case '=': if(token == "=") { game->addNag(DrawishPosition); } else if(token == "=+") { game->addNag(BlackHasASlightAdvantage); } break; case '*': game->setResult(ResultUnknown); m_gameOver = true; break; // From here, cases may fall through into default!! case '1': if(token == "1-0") { game->setResult(WhiteWin); m_gameOver = true; break; } else if(token == "1/2-1/2" || token == "1/2") { game->setResult(Draw); m_gameOver = true; break; } case '0': if(token == "0-1") { game->setResult(BlackWin); m_gameOver = true; break; } case '-': if(token == "-/+") { game->addNag(BlackHasAModerateAdvantage); break; } else if(token == "--") { // parse a null move! parseDefaultToken(game, token); break; } default: parseDefaultToken(game, token); break; } } void PgnDatabase::parseComment(Game* game) { int end = m_currentLine.indexOf('}'); if(end >= 0) { m_comment.append(m_currentLine.left(end)); m_inComment = false; if(m_newVariation || game->plyCount() == 0) { m_precomment = m_comment.trimmed(); } else { game->setAnnotation(m_comment.trimmed()); } m_currentLine = m_currentLine.right((m_currentLine.length() - end) - 1); } else { m_comment.append(m_currentLine + ' '); readLine(); } } inline bool onlyWhite(const QByteArray& b) { for(int i = 0; i < b.length(); ++i) if(!isspace(b[i])) { return false; } return true; } IndexBaseType PgnDatabase::skipJunk() { IndexBaseType fp = -2; if(m_file->atEnd()) { fp = -1; } while((!m_lineBuffer.length() || (m_lineBuffer[0] != '[' && m_lineBuffer[0] != '1')) && !m_file->atEnd()) { fp = m_file->pos(); skipLine(); } if(fp == -2) { fp = m_file->pos() - m_lineBuffer.size(); } if(m_utf8) { QTextStream textStream(m_lineBuffer); m_currentLine = textStream.readLine().simplified(); } else { QTextStream textStream(m_lineBuffer); QTextCodec* textCodec = QTextCodec::codecForName("ISO 8859-1"); if(textCodec) { textStream.setCodec(textCodec); } m_currentLine = textStream.readLine().simplified(); } if(m_inComment || !m_currentLine.startsWith("[")) { m_currentLine.replace("(", " ( "); m_currentLine.replace(")", " ) "); m_currentLine.replace("{", " { "); m_currentLine.replace("}", " } "); m_currentLine.replace("$", " $"); } return fp; } void PgnDatabase::skipTags() { while(m_lineBuffer.length() && (m_lineBuffer[0] == '[') && !m_file->atEnd()) { skipLine(); } //swallow trailing whitespace while(onlyWhite(m_lineBuffer) && !m_file->atEnd()) { skipLine(); } if(m_utf8) { QTextStream textStream(m_lineBuffer); m_currentLine = textStream.readLine().simplified(); } else { QTextStream textStream(m_lineBuffer); QTextCodec* textCodec = QTextCodec::codecForName("ISO 8859-1"); if(textCodec) { textStream.setCodec(textCodec); } m_currentLine = textStream.readLine().simplified(); } if(m_inComment || !m_currentLine.startsWith("[")) { m_currentLine.replace("(", " ( "); m_currentLine.replace(")", " ) "); m_currentLine.replace("{", " { "); m_currentLine.replace("}", " } "); m_currentLine.replace("$", " $"); } } void PgnDatabase::skipMoves() { QString tag = m_index.tagValue(TagNamePlyCount, m_count - 1); if(tag == "?") { tag.clear(); } if(!tag.isEmpty()) { while(!onlyWhite(m_lineBuffer) && !m_file->atEnd()) { skipLine(); } tag = QString::number((tag.toInt() + 1) / 2); m_index.setTag("Length", tag, m_count - 1); } else { QRegExp gameNumber("\\s(\\d+)\\s*\\."); QString gameText = " "; while(!onlyWhite(m_lineBuffer) && !m_file->atEnd()) { gameText += QString(m_lineBuffer) + " "; skipLine(); } gameText = gameText.remove(QRegExp("\\([^\\(\\)]*\\)")); gameNumber.lastIndexIn(gameText); m_index.setTag("Length", gameNumber.cap(1), m_count - 1); } //swallow trailing whitespace while(onlyWhite(m_lineBuffer) && !m_file->atEnd()) { skipLine(); } if(m_utf8) { QTextStream textStream(m_lineBuffer); m_currentLine = textStream.readLine().simplified(); } else { QTextStream textStream(m_lineBuffer); QTextCodec* textCodec = QTextCodec::codecForName("ISO 8859-1"); if(textCodec) { textStream.setCodec(textCodec); } m_currentLine = textStream.readLine().simplified(); } } chessx-1.0.0/src/gui/tableview.cpp000644 001750 001750 00000006226 12223260306 017654 0ustar00niklasniklas000000 000000 /**************************************************************************** * QTableView with some adjustments like storing header layout * * (C) 2007 Michal Rudolf * * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "settings.h" #include "tableview.h" #include #include #include #include TableView::TableView(QWidget *parent) : QTableView(parent) { setShowGrid(false); setSelectionBehavior(QAbstractItemView::SelectRows); setSelectionMode(QAbstractItemView::SingleSelection); setTextElideMode(Qt::ElideRight); verticalHeader()->setDefaultSectionSize(fontMetrics().lineSpacing()); verticalHeader()->hide(); horizontalHeader()->setHighlightSections(false); horizontalHeader()->setStretchLastSection(true); #if QT_VERSION < 0x050000 horizontalHeader()->setMovable(true); #else horizontalHeader()->setSectionsMovable(true); #endif setTabKeyNavigation(false); setContextMenuPolicy(Qt::CustomContextMenu); horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu); connect(horizontalHeader(), SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(ShowContextMenu(const QPoint&))); } TableView::~TableView() { } void TableView::saveConfig() { AppSettings->setLayout(this); AppSettings->beginGroup(objectName()); QByteArray visualIndex = horizontalHeader()->saveState(); AppSettings->setByteArray("VisualIndex", visualIndex); AppSettings->endGroup(); } void TableView::slotReconfigure() { bool sortIndicator = horizontalHeader()->isSortIndicatorShown(); AppSettings->layout(this); QString objName = objectName(); AppSettings->beginGroup(objName); QList sections; if(AppSettings->list("Sections", sections, model()->columnCount())) for(int i = 0; i < sections.count(); ++i) { setColumnWidth(i, sections[i]); } QByteArray visualIndex = AppSettings->byteArray("VisualIndex"); horizontalHeader()->restoreState(visualIndex); AppSettings->endGroup(); int fontSize = AppSettings->getValue("/General/ListFontSize").toInt(); QFont f = font(); f.setPointSize(fontSize); setFont(f); horizontalHeader()->setSortIndicatorShown(sortIndicator); update(); } void TableView::ShowContextMenu(const QPoint& pos) { QMenu headerMenu; QAction* hide = headerMenu.addAction(tr("Hide Column")); headerMenu.addSeparator(); QAction* showAll = headerMenu.addAction(tr("Show all Columns")); QAction* selectedItem = headerMenu.exec(mapToGlobal(pos)); if(selectedItem == hide) { int column = columnAt(pos.x()); if(column > 0) { hideColumn(column); } } else if(selectedItem == showAll) { for(int i = 0; i < model()->columnCount(); ++i) { showColumn(i); if(columnWidth(i) < 50) { setColumnWidth(i, 50); // Fix a bugfeature in Qt } } } } chessx-1.0.0/src/gui/databaselistmodel.h000644 001750 001750 00000005506 12223260306 021020 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef DATABASELISTMODEL_H #define DATABASELISTMODEL_H #include #include #include enum DatabaseListEntryState { EDBL_OPEN, ///< Database is open EDBL_CLOSE ///< Database is closed }; class DatabaseListEntry { public: DatabaseListEntry() { m_isFavorite = false; m_isCurrent = false; m_utf8 = false; m_state = EDBL_CLOSE; m_lastGameIndex = 0; } QString m_name; QString m_path; bool m_isFavorite; bool m_isCurrent; bool m_utf8; int m_lastGameIndex; DatabaseListEntryState m_state; }; inline bool operator==(DatabaseListEntry const& lhs, DatabaseListEntry const& rhs) { return (lhs.m_path == rhs.m_path); } inline bool operator != (DatabaseListEntry const& lhs, DatabaseListEntry const& rhs) { return !(lhs == rhs); } enum DblvColumns { DBLV_FAVORITE, DBLV_NAME, DBLV_SIZE, DBLV_OPEN, DBLV_PATH, DBLV_UTF8, DBLV_DATE }; class DatabaseListModel : public QAbstractItemModel { Q_OBJECT public: explicit DatabaseListModel(QObject *parent = 0); int getLastIndex(const QString& s) const; signals: void OnSelectIndex(const QModelIndex&); public slots: void addFileOpen(const QString& s, bool utf8); void addFavoriteFile(const QString& s, bool bFavorite, int index); void setFileUtf8(const QString&, bool); void setFileClose(const QString& s, int lastIndex); void setFileCurrent(const QString& s); void update(const QString& s); public: void toStringList(QStringList&); void toAttrStringList(QStringList&) const; void toIndexList(QList& list) const; virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; virtual QModelIndex parent(const QModelIndex &child) const; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; Qt::ItemFlags flags(const QModelIndex &index) const; public: virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; protected: DatabaseListEntry* FindEntry(QString s); QStringList m_columnNames; QList m_databases; protected: void addEntry(DatabaseListEntry& d, const QString& s); }; #endif // DATABASELISTMODEL_H chessx-1.0.0/000755 001750 001750 00000000000 12234251403 013605 5ustar00niklasniklas000000 000000 chessx-1.0.0/data/images/circle_grey.svg000755 001750 001750 00000021513 12062314776 021014 0ustar00niklasniklas000000 000000 LED Circle (Grey) jean.victor.balin@gmail.com led shape Open Clip Art Library Jean-Victor Balin Jean-Victor Balin 2005-08-21 image/svg+xml en chessx-1.0.0/unix/000755 001750 001750 00000000000 12234251005 014566 5ustar00niklasniklas000000 000000 chessx-1.0.0/src/gui/qled.cpp000755 001750 001750 00000006637 12223260306 016630 0ustar00niklasniklas000000 000000 /*************************************************************************** * Copyright (C) 2010 by P. Sereno * * http://www.sereno-online.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License * * version 2.1 as published by the Free Software Foundation * * * * 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 Lesser General Public License for more details. * * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. * ***************************************************************************/ #include #include #include #include #include #include #include "qled.h" /*! \brief QLed: this is the QLed constructor. \param parent: The Parent Widget */ QLed::QLed(QWidget *parent) : QWidget(parent) { m_value = false; m_onColor = Red; m_offColor = Grey; m_shape = Circle; shapes << ":/images/circle_"; colors << "red.svg" << "green.svg" << "yellow.svg" << "grey.svg" << "orange.svg" << "blue.svg" << "black.svg"; renderer = new QSvgRenderer(); } QLed::~QLed() { delete renderer; } /*! \brief paintEvent: painting method \param QPaintEvent * \return void */ void QLed::paintEvent(QPaintEvent *) { QString ledShapeAndColor; QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); ledShapeAndColor = shapes[m_shape]; if(m_value) { ledShapeAndColor.append(colors[m_onColor]); } else { ledShapeAndColor.append(colors[m_offColor]); } renderer->load(ledShapeAndColor); renderer->render(&painter); } void QLed::resizeEvent(QResizeEvent*) { setMinimumWidth(height()); } /*! \brief setOnColor: this method allows to change the On color {Red,Green,Yellow,Grey,Orange,Purple,blue} \param ledColor newColor \return void */ void QLed::setOnColor(ledColor newColor) { m_onColor = newColor; update(); } /*! \brief setOffColor: this method allows to change the Off color {Red,Green,Yellow,Grey,Orange,Purple,blue} \param ledColor newColor \return void */ void QLed::setOffColor(ledColor newColor) { m_offColor = newColor; update(); } /*! \brief setShape: this method allows to change the led shape {Circle,Square,Triangle,Rounded rectangle} \param ledColor newColor \return void */ void QLed::setShape(ledShape newShape) { m_shape = newShape; update(); } /*! \brief setValue: this method allows to set the led value {true,false} \param ledColor newColor \return void */ void QLed::setValue(bool value) { m_value = value; update(); } /*! \brief toggleValue: this method toggles the led value \param ledColor newColor \return void */ void QLed::toggleValue() { m_value = !m_value; update(); return; } chessx-1.0.0/src/database/tags.cpp000644 001750 001750 00000032313 12223260306 017604 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005 Ejner Borgbjerg * * (C) 2006-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include static quint32 Magic = (quint32)0x00DDB0DE; // 'magic' number static quint32 Version = (quint32)100; // file format version static QString Tagfile_suffix = ".ctf"; static const char* knownTagNames[] = {"Event", "Site", "Date", "Round", "Name", "Result", "Title", "Elo", "USCF", "NA", "Type", "EventDate", "EventSponsor", "Section", "Stage", "Board", "Opening", "Variation", "Subvariation", "ECO", "NIC", "Time", "UTCTime", "UTCDate", "TimeControl", "SetUp", "FEN", "Termination", "Annotator", "Mode", "PlyCount", "Source" }; Tags::Tags(const QString& fname) { m_fname = fname; m_tags_file.setFileName(m_fname + Tagfile_suffix); clear(); } Tags::Tags() { clear(); } void Tags::writeFile() { // set which QDataset version format to use if(Version == (quint32)100) { m_tags_ds.setVersion(6); } else { m_tags_ds.setVersion(6);//default } if(!m_tags_file.open(QIODevice::WriteOnly)) { qDebug("Error could not open file"); } m_tags_ds.setDevice(&m_tags_file); m_tags_ds << Magic; m_tags_ds << Version; //store basic information for each tag type m_tags_ds << (quint32)(m_allTags.count()); for(int i = 0; i < (int)m_allTags.count(); i++) { m_tags_ds << (quint32)count(i); if(isCustom(i)) { m_tags_ds << tagName(i).toUtf8();//write custom tag name //used flag if(m_customTags_m.find(tagName(i)).value().second == true) { m_tags_ds << (quint8)1; } else { m_tags_ds << (quint8)0; } } } //write the tag value data QString currentValue; QString lastValue; QByteArray ba; bool first; quint32 id; quint32 freq; quint8 prefixCount; for(int i = 0; i < (int)m_allTags.count(); i++) { first = true; QMap > map = m_allTags[i].second; QMap >::iterator map_itr; for(map_itr = map.begin(); map_itr != map.end(); ++map_itr) { id = map_itr.value().first; freq = map_itr.value().second; m_tags_ds << id; m_tags_ds << freq; currentValue = map_itr.key(); if(first) { ba = currentValue.toUtf8(); m_tags_ds << ba; first = false; } else //use prefix coding, since values are sorted in the map { prefixCount = 0; while(lastValue.at(prefixCount) == currentValue.at(prefixCount)) { prefixCount++; } ba = currentValue.mid(prefixCount).toUtf8(); m_tags_ds << ba; m_tags_ds << prefixCount; } lastValue = currentValue; } } closeFile(); } bool Tags::readFile() { m_tags_file.setFileName(m_fname + Tagfile_suffix); if(!m_tags_file.open(QIODevice::ReadOnly)) { return false; } m_tags_ds.setDevice(&m_tags_file); quint32 tag_magic; quint32 tag_version; m_tags_ds >> tag_magic; m_tags_ds >> tag_version; if(tag_magic != Magic) { m_tags_ds.unsetDevice(); m_tags_file.close(); return false; } // set which QDataset version format to use if(tag_version == (quint32)100) { m_tags_ds.setVersion(6); } else //unknown version { m_tags_ds.unsetDevice(); m_tags_file.close(); return false; } clear(); //read the file quint32 tagCount; m_tags_ds >> tagCount; quint32 valueCount; quint8 prefixCount; QString currentValue; QString lastValue; QByteArray ba; bool first; quint32 id; quint32 freq; quint8 used; QVector valueCounts; for(uint i = 0; i < tagCount; i++) { m_tags_ds >> valueCount; valueCounts.push_back(valueCount); if(isCustom(i)) { m_tags_ds >> ba;//read custom tag name m_tags_ds >> used; currentValue = QString::fromUtf8(ba); bool b = (used != 0); QPair p(i, b); m_customTags_m.insert(currentValue, p); m_customTags_v.push_back(currentValue); //reserve an entry in values collections m_allTags QVector first; QMap > second; QPair , QMap > > elm = qMakePair(first, second); m_allTags.insert(i, elm); } } for(uint i = 0; i < tagCount; i++) { m_allTags[i].first.resize(valueCounts[i]); first = true; for(uint j = 0; j < valueCounts[i]; j++) { m_tags_ds >> id; m_tags_ds >> freq; m_tags_ds >> ba; if(first) { currentValue = QString::fromUtf8(ba); first = false; } else { m_tags_ds >> prefixCount; currentValue = lastValue.left(prefixCount).append(QString::fromUtf8(ba)); } lastValue = currentValue; m_allTags[i].first[id] = currentValue; QPair p(id, freq); m_allTags[i].second.insert(currentValue, p); } } closeFile(); return true; } bool Tags::removeFile() { return m_tags_file.remove(); } QString Tags::value(const uint tagId, const int valueId) const { if((valueId >= 0) && (valueId < m_allTags[tagId].first.count())) { return m_allTags[tagId].first[valueId]; } //else { // qDebug ("An invalid valueId has been received : %d. Valid values could be:", valueId); // for (int j=0; j Tags::find(const QString& pattern, QVector& vector, QMap > & map) { QVector result; QVector::iterator it; for(it = vector.begin(); it != vector.end(); ++it) { if(map.contains(*it) && (*it).startsWith(pattern)) { result.push_back(true); } else { result.push_back(false); } } return result; } QVector Tags::find(const QRegExp& pattern, QVector& vector, QMap > & map) { QVector result; QVector::iterator it; for(it = vector.begin(); it != vector.end(); ++it) { if(map.contains(*it) && pattern.indexIn(*it) >= 0) { result.push_back(true); } else { result.push_back(false); } } return result; } QVector Tags::find(const uint tagId, const QString& pattern) { return find(pattern, m_allTags[tagId].first, m_allTags[tagId].second); } QVector Tags::find(const uint tagId, const QRegExp& pattern) { return find(pattern, m_allTags[tagId].first, m_allTags[tagId].second); } int Tags::add(const uint tagId, const QString& value) { if(m_allTags[tagId].second.contains(value)) { (m_allTags[tagId].second.find(value).value().second)++; return m_allTags[tagId].second.find(value).value().first; } else { quint32 idx = m_allTags[tagId].first.count(); m_allTags[tagId].first.push_back(value); QPair p(idx, 1); m_allTags[tagId].second.insert(value, p); return idx; } } int Tags::count(const uint tagId) const { return m_allTags[tagId].first.count(); } void Tags::remove(const uint tagId, const int valueId) { QString value = m_allTags[tagId].first[valueId]; if(m_allTags[tagId].second.find(value).value().second > 0) { (m_allTags[tagId].second.find(value).value().second)--; } } void Tags::compact() { //remove values with frequency==0 // the index file has to be rewritten too. } bool Tags::isKnown(const uint tagId) const { return tagId <= maxKnownTagIndex(); } bool Tags::isKnownMandatory(const uint tagId) const { return tagId <= Result; } bool Tags::isKnownOptional(const uint tagId) const { return tagId <= maxKnownTagIndex() && tagId > Result; } bool Tags::isCustom(const uint tagId) const { return tagId > maxKnownTagIndex(); } int Tags::defineTag(const QString& tagName) { if(m_customTags_m.contains(tagName)) { return -1; } else { quint16 newTagId = m_customTags_v.count() + maxKnownTagIndex() + 1; QPair p(newTagId, true); m_customTags_m.insert(tagName, p); m_customTags_v.push_back(tagName); //reserve an entry in values collections m_allTags QVector first; QMap > second; QPair , QMap > > elm = qMakePair(first, second); m_allTags.insert(newTagId, elm); return newTagId; } } bool Tags::unDefineTag(const QString& tagName) { if(m_customTags_m.contains(tagName)) { m_customTags_m.find(tagName).value().second = false; return true; } else { return false; } } QStringList Tags::tagNames(const TagNameType type) { QStringList qsl; if(type == All || type == Known || type == KnownOptional || type == KnownMandatory) { for(uint i = 0; i <= maxKnownTagIndex(); i++) { if(type == All || type == Known || (type == KnownOptional && isKnownOptional(i)) || (type == KnownMandatory && isKnownMandatory(i))) { qsl.append(knownTagNames[i]); } } } if(type == All || type == Custom) { QMap >::iterator it; for(it = m_customTags_m.begin(); it != m_customTags_m.end(); ++it) { if(it.value().second) //is used { qsl.append(it.key()); } } } return qsl; } int Tags::tagId(const QString& tagName) const { if(m_customTags_m.contains(tagName)) { if(m_customTags_m.find(tagName).value().second) //is used { return m_customTags_m.find(tagName).value().first; } else { return -1; } } else { int i = knownTagIndex(tagName); if(i >= 0) { return i; } else { return -1; } } } QString Tags::tagName(const uint tagId) const { if(tagId >= minKnownTagIndex() && tagId <= maxKnownTagIndex()) { return knownTagNames[tagId]; } else { int ix = tagId - maxKnownTagIndex() - 1; if((int)m_customTags_v.count() > ix) { QString tagName = m_customTags_v[ix]; if(m_customTags_m.contains(tagName)) { return tagName; } else { return ""; } } else { return ""; } } } uint Tags::maxKnownTagIndex() { return Source; } uint Tags::minKnownTagIndex() { return Event; } int Tags::knownTagIndex(const QString& tagName) { for(uint i = 0; i <= maxKnownTagIndex(); i++) { if(knownTagNames[i] == tagName) { return i; } } return -1; } void Tags::clear() { m_allTags.clear(); for(uint i = 0; i <= maxKnownTagIndex(); i++) { QVector first; QMap > second; QPair , QMap > > elm = qMakePair(first, second); m_allTags.insert(i, elm); } m_customTags_m.clear(); m_customTags_v.clear(); } void Tags::closeFile() { m_tags_ds.unsetDevice(); m_tags_file.flush(); m_tags_file.close(); } chessx-1.0.0/data/themes/spatial.png000644 001750 001750 00000314277 10633464147 020200 0ustar00niklasniklas000000 000000 PNG  IHDR4RbKGD pHYs  tIME 6 IDATxw?wfKқb VvTl KLi45&T&1Fc{]DQ*җm3{̝;]=>yg[9"$H"$H"$H"$H"$H"$H"$H"$H"$H"$H"$H"$H"$H"$H"$H"DEMI$DJV]EDV$H"d{DDI$X#y^<`2ϣI$D(# D7<\PR*RӇ H"$H"$5A$mRS ,Qc!ٟLim~~$[XA{`RѼ17iH"$HG<l`n]GuK4ZY Dތ8xH%pPķBƍ;NR@loF4VuI֏6-H95A$ࢯ 1Ka8LQΡllX)AD6>"rRa}qYsQ]U^DJd/J)U*qJRF 69lk䷁.e0yˎ;dH=X*cXik僄ls3VrYhpFKfK4ZMWtnPφ d>s{؊D#Rd\.~ų EV]%Y9̀ `!0R?/n*ԝzl#bu\֭_6E"3] ( 4mJE㶥l:2Op*{D .;.gCg IT"f,ˤ5g`;h]WZp+ &"C t:C)_ |/ݬj*DI%BRIza=$=`4I"&I$Bg2A`Q ,ԃ]) Oc}oߋL6>F?ygc%"R`T_|!˗/㧷`"^Dh ®ض@|ȠqډeR0j7zx9j1{5lOb4NZ49ٽodW/I?Ql,e2fіK_d"2,a aI làօH"rxR:V%d9#?_[S4444= '#>DX,F<%KLJ8ki: 2+IqqT2 \(\z/L&;0 "J5|k۫y1ZgMmNM _4lQ,"t@Cy/RiIfs.uQU5R"6,} NBW@?MlO$h ;Dm꽖lzR>'٘tҙ^=lcHu_r~ي\}SO6E-)+-[F2~௙u<!0yxn+W?}FPdO Tn{Enw:mou pçN([ibq<}df~k5c"Sw&0%-; 4b-Xm0|!ШBp[eT{xH)2XAD[q F=b]GIi %CD}v0s7)*`&րe zuNw` O ψ-ouuu$$q8v+T~ @@~}I3t:uч~Ï^EJq}]:LBy5 ˥!qgӫgwR:zhR"B9ةrF(|VjWt SG^@GzG;ZI&,014f'v ܳښ5Wշd+K7-^'_u&k3{-#iö O s'0çB&\Yůz3(bKƖs֑yZmL))] mCJF=YD<2D>*\֥k9ę<| '"ObZa>lνmNx"[.c;43Hv :f8Vä Oڨ[ZE6@"2엣ړgLHZk[͹9[DE {|զǐ |CF6{LӼODfù5WJKn} p9Y]MJ=pRߞ `)nʖE1+ŝunzȢFY{D9IƃQdoZڊV-m;CE1𗗗nm'Oogn:? .LvԉG[W[o'JuNOR/;usFk\jD@S.?[%⤒,paS+ڕqGpT+Eo"R >T4H?#c5`lfPФ (+-e `ؔ(i:Bc]ߤ>W'6jD"w_>՜/hP2`>k $ QnF$Ia&`rZSJ}W=/Nv$!! #!V0EX|( $No[6jlk.p 063q,JCBW(*.]oo+eLSJ=,%6V*ɦeQ"%2=w'lLtoz~?/N={|\ ٞZm-#<#(rpa"Ryݿ&ym7辐0h `>MOP8-؈뎲VV"{|ڂqi 8СC9| E& 1SҚ#XRb~{seezHi#E*6VX|%zhoKqi$m` k_:x'kF ,V|AVV%+7zˀ wޢ/݌B Pl%QNm.$aWm ߊ1{Gn0k߾yowSOT*UJ3@J,&N#o0x4|Oo.cPjf@>Ӌxx3"qiGsշtSG4RTz\[uY|fTXoCӿ_TDk^dhK2\10z.\M%E&)0M_{&R*+EN<I̼g^2Xf逸s„ t-B?;KKst143;M?"o/ [IӋ}zC(9`v67|*9gn÷)̑CW~A}!i}9g֜ n>}TUo{Q<%Fjd.Sy)倩H~B0R1kg%V\e\Xqnle,H:d:r:JH5  KKY/Jcjl0[d^"_LCWnu,x!|ć >wculظw/ ˎPh:uAHZc_y0TGR;ZUPuTjd 27q a&) yMy.|^8ߵFolpz-h#H"ќɔЁPʐd8s[[֪' =(Q9.ѣMC\p̓5jTA1 9dN^eWюy@OB,j7U&TGnЄc5m @ݺq)\H+ yYY){&'7+>IRKDi @76lOvP@h\$̒)"SvejbX[cQ}TQbQMm{ъgTL'_`72J 1mtd;PdЁusF>\HҧwO06yy4 04SL$C*{V%SG̰""|m-aK$(luS<v<|ڋqMxB{}ڛ@v\#wQޚ\a”m}Az+G\rEt {w֕[~|='8.ƊNJ{hA/7cK)%9#ڥ^dK;48WR,v*8jߙc|y466{uw فV8zm;KJZ O*\QOs/b>H& .`766~ݺ Ka<)JK `hhvSn(TTO^ yDH$ +Ѵ?Z%ΚdgsBGoGRAV#ץ ҞjlyflEm*PVRR‰'hepA8ppaQ{ӏ?n~~d\H.MXl@FIv^ϠID"✖ܙc6tlmx1"!mЁQF3@79(E46^;u&r~g@M=R&cʜj}KF"F׿;tcGz'>^)u7O?Z7"fesr=VQRDhNecbe?us,頕 _Dl1k,cy" Y䦧0tڥl0]R\̷q!}F ڝ8f,[Eaҥpxӿous*gpygn g0̓HZ礓!1mZL^z9Gڛa3 (uOmDvLNąz0i ˚R<|c{E}OJx6\@uh tDȖ`H򌫸%~o/ $[,z~'L F=+ȑ%1 0RL:|Q(F.M*[]*Ӝų7%g 8d͚2M㲯cV m`x י-4("Ddf _e[\:D$BEXu>6HUCvzlD1^[>8c@(MȆhb}>T^L6 ( ?Yx0dQ[#o hEpu&aKEA[48eDjИ Q? IDAT 0|`4:УR3ߤD4-g]k@SYj; SiӦqM7T+Zi戮IbS|C{?Ν:ѩcuOeo>^) kNR18 `"SAR)>_6Y׵eso<0θy` VNJ4ѰZ0&A95h @&HCbEr|W7V*6]rٖhR}4:VkywKQ⣌m/t8Z\:؉Gs7O˧34x J`#h Kx̛sX1G>yǡLw }_ݕRKԾO,FKHlPFMΝYzva]ÎHkU6w޽1A:1³HtL0$UlB-=ʾ$N( ilK(>^t=sM^#0: .6Xo]te$l֝B3Ga(,ǭ:Jg˶P[t Co)ws h佁Rp@ dpa?_?pӱ"2L[MLad'p ޫg>b-ep5 4:h}gvdYG06n@qq1'N4J)&Ke^ן~Uea?])_Z_f8ؕ^=#& $yPq&<،߅zW[u(0%f1 R5J `dUNQQ*6)6WJ5J)ÎPśah5ex0 P&֥ T/J JDJ¯5\wK No'퀫cJ8V,ZAj} P 0lPz׳xgYX,Fn;У{wb1E;K_ DuÎgK'n&"P<-J5 VS7sN=,óJ>I/A}J'YLDڋ+@Qkbܣ: ߸g`z׿v'Sгz;/@jkhiYM.f;|4fE`׿V 7{jbf`Rjm^iaKvEwd(g/o̡H%=]1/m꓉q<-c{ X..[+o]%l}#E a)wò@Fꖒ;Zr-X1,`*emEj3m>FQPfɉaw]b(E| .zӾ p᡽UŃwaǟהiWNaj*]}ڵo_)'GXEddp,{iRTF|PKfHl=1t])@ag֭[~s„ PWWRX M) bJY{[b{0Y{BS#{ 5mYqqǍX 0nH9 ."wO/m*gD2E! =ba_d"`4)+M4XNo swFk;8byϮI&1c%O"ي<D0jFd6W@w2HLXys,ÕϋKH j霹RKQGBDCgr9ü g?U _4|" ԟoǞz6uu# 4.$D6pEtjړNN8ʂ6l乗^ွdǡ<~ ~HD)l:h`2k_| `:u`g FX:ݯ* \YMjB32ړ.:,cs:[W᾵fĎ2㱵@S:G;aWr:6h<u$[ßE*e ۋa{aF iiυKs˗8=958"V0S~*϶"v$Y([޾A,·Ǝ9=wݫ;2+R_hkb;P"H{1px1 04x*LNY"iQ:wdcR$bzT0vv`t5fF>F޽x s-忐x`>} Y~ik϶"[| ,Ǔ=9mjűa2V{-bxiS2Y>`={w|S&OI"2 G)<ٙ MG(io ]*SCĥH5ب՟t뫀 :$q~y< neQ{1tȠаu ~ue/9k ^3$RE,Ix-e{yDdtsΜhzwMM pK:v+Vg/1@[tۙ R@l̘146Mj@oZz0qi? `PT Rgv|(~8dc1:RjH$,Jo ǠT*"R=,^$ك\ r^x <Jx lUX,PS;}dY2X \Mg;s_VR\gܙR;{oɥ"CygÏswR\ ܪzMG/^Suz8H<6[ٺBDJ)u~^ t4ճGHCԨsS}YԨ|x綠^Wˁۀ޽[0h^,f @@) yWXDiѠj$KXZ&;@#";Ξ;XLx-ѣ,[-wʜj(I2Oxg9d~7d})D DvaP=x1b Юyk fn8mScW]J9ӦN憟 AgRI\hޗzFH+UmJMK 18|XEKo$k#H<"2_m'{MKUQ.P滉<&)꫸5ұi-DaC؟~ 75" /uP|Ad[M4/oIaw\DNՕGWNC=8Y{GR8|#w̜Ke+K3EV;W׳-4C6Zf`qSZEsKO9-Fj4p 9VQ 4YʙϾLBa9ٚOzB~ 9LΝ.h:ۅ ەzpܓMs z[饖ȳI''ZSٛ# %<̢kSjj6-vv][5" : sAƟ4` k=lK}`%{t(Ǔ)jK׾qm ~a:kŊ:fAsS)Md~#z&>4J^ A FX>' {@Wۧ]gAR,^\"vEow?@G0s0Y[m~=?9󌹹&MX<`/ gkX'>շ$?/G= ?ȏ-dz@n0\Omy"M$ϯfH_=G:X{L!{KLmoK065"QDc>ֈZxzMS-F5>%ͤO`Y₹c1 ۸[cɛ0̹|ИBZ\H lߞ}tUUv )@I[([B)VbvJtvfRRRB&x1ƚ_u@Rj /+o yh\L ݼ\aټAP)K,k.s+r{6>|x( yx,FUe׽{µU^Ç>qlJ,s ¼Xދh ֬eيtU%dO.#-zͺ_ |.|悋̍Z: c<%Za'K5%ԚXp߫7fp خl ?~ړ4՜RYg ^>\qdlW|uMuSm c~F W_yl3".=w6g^rT>DHRʗ^̯ojA1(ر'L8lJu?"ՓZ (톫Я';JHH4Mj `Fr喟%ҳO PفޟU I+WbڔI;`U=p 4 ũ@ǎԱC0sgn$ ¶(h`X,a &{,{+iY@q9C8%joc/[`(9 ƟPZR7 NhbͬÇ /GǢş3EN`R=41.1F)uV п;P䀿0pa^ $v:o. @r?FDuaH1Qw$_ `V8sYDl6Tnya>+B ,%-O{'`9 &j@'}h\ۀ().Bpaoe`zw>NZQ9|eۓA 13?;dy84Y)1>Z}+9g X.®sٶ`E;wsqwzBDVSHRJ0ρe˖ev5aS'щ1郋B6w_0(gn,^igxY#v1~}zY~S#iy R,e^ƃw1S)+-EKlW(v8mra-7ā>{MX\cUoeUe]"\W\W0@+NxgOsQm.uwؾpQi2}y^MPЮK.wV F?Ex61a/̱!?Lw! WHsь7c݋1eQ5BevOnt[TTl `l־ӁҎ*8IZ5֛T؋5J[͙=kyf}3{]G2h JKK <,"SDd'"g9MDN"(y80Iqcc@0Ԩ@D<-}z(0dm#Esf +,nhoc<x39y0rc0Tφy5 Yx!M*Yj0jӿY|D))~tn^u& IDATG0Y ckR"rARN:a'86\ i5eD+DVo˯ڲC+8Ѝc wǢϖAg)йS:g ~444;.6x?-iEׯgѳ;v˿AbHKZދTz%1L܇HҭMbKݫ %Mʞ<q'Mዿ1&';36^6>p@>)hۯ, SM+ J2BEhsU_7o0ssHpwwH5pDJRge@F)rq֬k =uPJkkT_?֭]a8cw4e|ɗK֎YŬ7^GrjTnDk/@, EhP*K78I{9|#,nJjT| .d9y>(.(%"J)cI/1,5X[[IÁXygJ[2Cݺ.[ͷݝvfX:@{/R 8{?ӯ7GN>qb1 GMF-Y6CcWLQ/\H9sOe"2Y)k}IK贏]02#D8tD0:깳ڀ > 8LMjo(mƒaOߞtj_C>4 0m"(7^ uh_S%SŦG]* \lʬ#v}wڵkGӱҊ$9 AXUm sNuc1bxx,N<Ϗ*ݠvߗ3؎Crܙ>Ӕ!aCAgI$Ҡ(8`dl=plq.|:́D+n$p xj/}2+MGi+YsjY*w;m4 \Nk!׀u=!.J;wϝkW! >[\H ۇO>ok)+toFmy#)(gtpzu?)6mC+*N>0ƹdTyࡿv"^&C7ixiS^m m=j/DK. /:Ҟ\RDtǤtrĔjH >_ۃݻ|JDRj=b{Ԭ)jHgȫ Te(R%M d5y{agtX0c:sGMcrxO{)`^ZPeÇXZdS]y/2??#܉20]2~{ /܋iZK b|(..1tǞТؓ|dw"J@/;L̻g_Ţe`oN ȍmq fњu0lZ_ܘ;`,SZ>%MM{ʗJ6$?ݬfv{m$7Yk]l*õzW4YݸˀRx6l.d pqY0=8 0lm4oyz|#9sN,yF^}-~ПˍdmHSf5<eWww>8rJ:chCXѫmX6iR~aּuL7>y05GJJJ.g h0i3NQJ-^̎Æ84`1u"wfޅ IlR؀ UVZJ­^=9{ ŐTL6=JD(C2a٣\LBPW զ{!r~;c)*JJ,AH&lذF۵(i<N},nV#k/"Ro2俽V::e%\r,/8Z~#}e+VR_@:;t锽?@cOHXhTA+. m31 @Pd &Rm$#p#x=lVIm-akm&}nHF>jT3Sb/?T>׃ih79ZN]zLX&L>@|#Z}BZ.xL֭+<0tP?v:*R+ OqfVvng&Svϊ<+fw}Áߕ*4OΕM.*{USC t7HRʦٱEbF~8qƛywUJ=("vMz`Xպ~ ʢҧw/JJ)ֱH>Iqw%40\p^Ɗ=8r(FͦZ>[5̪b{ ]ұC3%}>M6("e@j\l=57lhX7#k֮ D^={!n/#w {1>?AiS3ˀ7y&CsɦG3g4z y=3/‚+[)\|Tn»"G<]F[2RE Ҿ}}m**I׳fZ-_PWWAƲD|YԻѻima'bHqo,!96i?E&;›l}3K寲Ya(ev ۃQ_Ë7[o޻oԫdoBz}^~MwoV~pA3~ cxL{1ªֲIދy@ML7uQ7ZO-KII;sf˷.chpY? 0z-XxLqؔC_BRHDQ۸U^;_ zΧ "%:v$,{ ^oeuFEvT:/Oɷ[e[2`J潰iv(`ŴV!=>t3fͷ$ƢşOqnw/69kO; 'A̫zRh][[Ǣϖ=p.DdPV\\SeGß`UaQ R {)_~GM9ǞxU4:a"?|b6ZPDR`N.]0 Ǝͨ=w2X2\_W܋/ϧ?ϾH]}}^ƈJɭmfIHvd$Z}WiioCj/5*4T!) ٌyܸXY}nmHh? 2h BsxI. ?]칇4'߽ND`y1JZa9MSX zj:z}|3{aSZp3._YՃ?>0X{14b؊ŰA73|,˔Io}xיjz>t ȶ1u?^tu\+mO Yry}*t̡Wy0}جlWb+⃏ucK)){1(ҩ3OZ_gϦ-۠{Z^p| j^n, @b5S<3e5(̞ԪsPْwqmw=ڥ3X A7|Ïl.l d`hr&X|gru7ϺT/V7p{01,캛y@nrLX~j?x-ژt8)wf68H5J)I׮,c"%1|(; ¬e͚Vw KB\>(C ?pܟϚ_7.>n@C={6jjK`1.R~@,**+f(~ 䃏?1sr_&&Ͽn^4YE T.MCF?#=$)}S6ҪjTV R+ })[\<~G>z-6a<9"DbJ $Ғb8h_z_k>l>mMTf#x ENa A"qNj4j˧Ib0L');d. af`ԅUуaR^cPnY-ϾZ656p_s7oQ*@CX^tC(ԆNX1IS= <1+ִb\bN`ÔpG7Kf-z[N ';s<-EYnn.}c( |,xRo N;?lD}J:%/7{ays5X~ 3BFK.$;G"b9*x ~WA{޻D4?{GHC1doZӎ#wM4w,C--̞ 0\9s(#1g|=-1-fה5vCR[LN.(~tk78 v"R'"8~< PW-N0 8݆(QJ}ۅ.2aR'BH`jY ;kI־>< N 0dQ"KDg=eLb qnǁd=;CʊrQc2S'D}Dֶ&()y`X JVI}¥Q4JZ!j|!!0{)\"&Шu [*/f1gv2m0S%K+䚛_B2|dl3j͸Ac1,GceR6Ñ 'b_΅X~Lb\2z]k5yQwdeh8 ѿwO&dX`1<;ӤvEk3)x𰡫sQG_K)8GQJ-_~꒔+!c`>lzo; VVJ2DJ܋K/xݵ2oPً-X̒eLp!~PVlo0͎]5 BS_z9b^6y.E@\r,"fnY`=ppTu+:/^$PJM^PJDcnAz禪Բ }EGc#Io\%0e6D"LRyƁCLD;$KʓODD鿵 (DKF ³2ΠaaffLKNa2J"uZJP)RC>K$|*`8FR*p͛ DG5r*,hjjℳ.?>ZÇ\Hl3B}ˤSl]J"e^g><(p8 ^|^_^lO]qb6پLʶM)n_dۚQkHT+3Q+#ӎ㬓}V[XoGb{weC7z+|ɧRʸܳ³7X rœF8{1&l%L7\cΎh@ ۓ7|\~5{! /Xvr N$x/RiJe9A}@Dx'vζ~׬UU>QJ: yMuNCCC rJbeg͖R!{Aul{ Y(z8Mq$I+aHLL)k pwr18Y|cĬ e X1ADԕ睬;^ VD\M/et(4*3TU 2)ol4]wٙ,bIo7qΊ) .a2:+anY}?b1q<| I@sŻ$7cP- IDATga#Fڬ5|"dv݆J&+%( J);P)+|5MM_,6 qFE{ʣ{5/<׵`zƩ6;x љKb1a@,<È@;;T'g_߼l*]tP9 . F$비,*.s)nR1H{,Wwfx`2TbtjSN>Fe& 8KumpDd`RN?՘Whlj;3/s.r]^0㫸RLZlدBQÇD.Jb+؋Nq ͖mⴡc%lil13Ol`H*ΊЧgw4Y ,Fb5 , 2qMYuʥڶ /,>? nN@ș6}.u@z) # =D`d͓mi-6o/:P&l i{s"1H8Ea6l; bELp⇏F|j~ʿgzff`1"s>Jʔ|*3i $3#%23>@`ܺ+\|ͷLgW^{3?[OؗcO9w?_\H,̯koc[K9)*_6x`iK.@սnEpItYmN>a23i\iK ">@S\t)2pbC*%I"㘃,Fd10o>kܜ֎!XsDCCcl=b(< ʈ59D*]IcM()*HC0ߩI$+יr1@lpq"1d~ƵB_Xպ=+RJo{ĬϑY/A>}X}`}o 2\R <HĹ6UÝ)JFء. A6[n.c[Wߟ|Yk=A&ckVJ셞;qJST$GH s"l(RZ\čIVVTVxvLTjYsJ2[#H(iTbdx .jjj{p3/3/Lnel:Xs({ 77ƆFW0|LX^U)^h4gR4BX` 0"UJE"3$B'js nSŗ<8{!"@T)%ƉGMr4f-{ GT8hyS51G>ODRdhE.=;RJ})"uX,>wM=3 y&/**D;Q#YAv勯şKz Џb>$m5JhCJNvNS078د??)E(0R-)+J" l5˯˯.w Lq{v[d4X C&&"ic4Xc{aa~$>6r11.@v^nn6n}y ,^ߤe-mql"*")֛VV݋̅5$$Q1Z/̚-JGؑnU'4=GgsqhiiG\spٓd1i=cMX/# ů~ qJa8SK˩Y m̯ ȡHl=<P,Fpg1#C@~`R.Ќˠ=C41.}zuC &Ƒ'OOz_+WJ} Wɫ2Vu R_()~\毕&>y偋$k]ϵ#dd@agVrw+Ѓ'2٩׊F #'3Yd*e˦z(=ޫ)^|Zg[ۑ{1Go^"ù ɘQkZO]9YR8$r9h5u cFrhVĔIr"Jq~;:PX,3YpusO8Of;)؍[|edoI0:Db/EQ2o șT 9R>ۊ 8Y"w:KhiT=VT d5( }ί3Z|އ|7ogsSyIA)H)U7-~(RJW)R3NODdM ڳ{7eO$Q+Q-@rpd(҉0l /S;'çb jH$”#n mfď>`7 ,HbD;8`G} 2/T!;+BpcyAF_|!A958xx^+3:Cpaމv[n8Ky&1ׅ,ԫ:M6Y4n\w۽->lUB؋嚡 pVJM>R[Şw+ 70 Em7{ Wߧ~/Si1;*Q5wLϼpjXT 2:Dt:`„3zT0i1C T8(`p 6eS-=5h=> Ӳ6Ua]Z&iTSA(Ōo'&x* ࢩ /='{\3gqx׵-`R\)DX*"K}F"Vo&:@NQQ!WV/#{ üsBH:Dd/Jrs93b vCኃ/9c?v, mk\zv+=R}GVNbJo/Zjuhz{D\ƶ_3' oG]]3.fx֧g7~͞yyYkx7&hQ`NΜc2> #x=(9Y\rQ^<$[w>!_?EւwE6U2 ~no!o /Wp]Ǥލ"C}ztZh iq&Iq@DvQJqʑEJk߆F.a=g`!ma3aA-''79AfT>6x 0.R旟>џiu#s2)NW&.j|*{;qI.{aTnLs1ϘD~DQ# x#~}yn+ZG/Bm@aTB)7c߯JDEdf@^QaZJ؞=0֒6'TT)!$OW&7}I?⯗ч!` ܆6X\*QwuI\X6L}RnA {  IU7W74շ!9hQ#)>ڣe԰N9/O^wXqA{ƐIy~ֽ.hdA Ӥ<pw3g@pj d{cUx)9n%9AQ)zVoͦZw?eOj \ԧlqy7n챰}vaXpy sԚtl5~k^J ZUE׃!>HJ\ ~{ S,uETJ= ȧMgvcmsrXyzAɵS.Ͽ+6߁[GYLāRj~xs1c>GǭE~0AFg0Dd?`@$huh4W^ȑIduTH_:+ң{1X d$t$h:/oK .Dnj,ƒYio6cV*,={A}uǻFHZo^cP|Ss3fk_Du5tp?dc0ljo7"ܙ6p9~60C7(s.Eץ^/~!>3吜`c!sk чSg%ds8\ ,L9B:?\P  cwQ +9ElN&O2fq;l6@$* 3"ZMi4JR;KuQžHRb1 O>O?7? ;;s.oζ;_ӯWїWn R('caKTJU)CcV,h}oNNyyDg[!֙ pgMN;lkA3ϳ/" S.氃  WԑOȳ,FX&Fn*lGH~/mlJsS_%ɡLagOmn)bEP&әg|'*k:ykH9ܜҭg^yOw_0Q{LK"ծW1}?wk`wsyg2P>0+a}eSvclxF"ډn!ckfȮ!'ת =}lj9iiKLB \[0\Fg(LaN;́ESTiU>5uH7 rug DOX0R|ʮh.4JҼ `2Ouk1Rx` 0/ls=JF>-.ׯՀ՞ |?_jJ`)BXkju#w{0 VЯYRopjL ܽ=^s/tÙknhC7C>}q^V̤`/(J*Y G_Գ83XkĚXDz%/ܩ;S&e;K}=sn*-)f: LD`ˍ`7k|0T/?}wfܘ)d L}#/A&Wh uvRJ2vxSnN`Q!X?]_D==*enF1< T(lnq{q D&GyϿdzP-`Gъ_\/7Ŧl[jgʖHei]NQf6i@mvK]AU*9Qքo2FI+h'Tg.H)>QJ=܇:0E)$f3R?B@R-M Zh`Q,"gkowxz p!+\h!jj!AFHީ_78)y0[Ij ˙Zr~)n=X S{O'yy{z ퟗ%|7w~ Zw lq D-}ΞaM#R3fQ%^8 8,φb/<0px2*o+8ZNYnjk.r~ᨈShV@^4a %Zb ng [j[Jszrŧx=BWc[sny.|6Hb/:xPF :RWI28{J(2% Ӂb1F_\Z`–I=j irɬGR]`I-`T]X)1B , g, X9 qqe琛ݡ"q&`kkSO\; WJ'L h5o!>tF0 |lviې1эuxR7>9\ 0x99\uVz7V":̹()=!2){U(ZL9U7JBtlik{=z}zuw,e8!BȲ@xikG$Ӫ =}lWQ}ڛ̋FVvȠ \Θ f5eHjضIrl6yV-d#{+uJ2qr*iT}U?<ʘ8FJ ;Y; $,e L`aʤ*"r?>l/ 7xi%`pWg' 41nRi:)qMfx^bʌ>yG'3A{̫[Y mc!!+mfvaK+֧zCggF|'"&3L\IlL51o7Ĕ7ҨZIZ{Q ?60h2$qK#,kڴnRvsِh4Be(m__&Xa{4ñwU3OI2OI+S0:^mHm0Xu" VJq~+\H{ i4lX b;V[g R1ϢRv8_r^qGA*vbh"аǟ|p>jDw}}O6>\䩵a{ VdS[NKybK?Bq;l礤j=+1O,&Y9ϕҜŨSJ,o΢z2œc~?cӉF#%4@E }V?o"rhܳ\%ݽP48ffL5n'G[ޓpyb\teH;: \žHeq%Gpҽ{w)dHTp)tHfNQϗCW( w*:hXaa}\8IGB IDATl+T FE|'JoLTra,j..pύWpzmp+5f(:D/?޽<6f[ggԡ{HIXÚDU֪D0>?/[ZTuNN6uV_M_7eu|O6 /!;;7B.yѩjJf|;__@b̈\y(EH:1?^{38,qq&TV1j!p#2{\νxJ@ʒU+1{o"v x}%(GO3mN\y;)T@_zqqtKj#|ߏZ=Y,%2/:+{aJO ICJƹOִ8E Ӏ#/\ *\`|GB2JaOTKF 4e0lar2+2"2BDvԦkOoh\*"SY Vt8C),(Ș)eC۾ݤq*.*ݷ0ط"Ǧ3dyڛzv~}oGC30.^ @Dpp5?vD"x'P⮫&?/'%p/jӤf/lp` {!pJiy\IUgם'V +"Ed[hLDWԟ: q=%{+-*K`^OD.FDⴣ'rމt_~ d#_sߟV Paf{/\E7T =)8$},P)*l%Zw&K%^i7QI߱OmMϟhq,zLrA <RdS 2m dggq Gq1F\:ќ4B9HG`yPq`U]ZZZhhldie5+R^K*)7KXREyeUjU*Ed:xLjL6}M 6h O.=x~ݓt;`k546r޵jE}ѤCcϝ|ff0b̅q`.&WUAJL2ԍ"rKMmmO:מ}‚V.>;_g}KE>)3Q;;:S/\kؑøXc NNӞx)0pFuv(Wm)@EE9E s"ST`BqJe+*q>:NzJ$#iTkS?4QE#ɢҨT}6gQ-&#iv\w98p!+\AbT@0"??pʉld?T:ٔH&*XT^,._ W,aQW,U~#r-v=P `,lRJODfcvb_*`S8 ߏ?y_SϿ—n0?\ʗV!"(8뤣npd"ݲzq'q%72kOp0aKk|ݣXk!9L42q~=g>S^sk2{QX)j|2p3pwύuuՎB2ΊԿ/7_ugp$OO}>⊥Ճ7ېOA^^$#[l3\ ww>NSS3b.dEm s Pe|c)K^f<H KtG:_3 K$aNQݤҺ@Ild¢JSa!WDD FeO{ʧ #O-bSy "0Y dDDsss/'sA$tZ.X"8 ՛NWt& 8`N;0|5H$BvVe%E,,_x^%$5U&{Aomf}tjgi_ҫo3&2& 7q?~%5uˀ~}kEfa{1Mv3.lkbay%kjdgeq>9Ia "µw[b5)Q'7v*TD̿[ hXUJ}*"ϳ/u93(. ɇYHjuCҺ\}\{>5,\TNIQ!=\K#WקS3&[kpFz/V5?|{ LE]}BibiU5s506ДA'"$j|JK>T>0up& bk5__y 뭽s|BV)@:pU;8G|iҲe5,Z ?-*~..gr*,z#Ke^FٽJ?{t+gRSRTH$8[xR^3!._"d߳g1>676[zz6dM7`ޏ?QSSːAhwIfiyyj[Zkpg3YZUM=|Lk'VЧV~qq7u5K[ #,`oU]G6PJ[DF_4z]{4XG˱!AB"Ey ݏ:F)r 19sűOi'[coR|B E>*{ZNT4*RΰQJER]g"r70`g.?K%@8 RGqqx8X%Kk +E4=ӫGw4f,Cʊ)l苧Bt1߅N:?U!K))r9.A ]A0{0?zσx`2x CHZxRKR)i UOf ɤ {ϧv KI\/u#eʜ? -خf2J[DƆ^O=ן}O7N6 gR, @HߠMpAKq攻ihl/LÔF̅ \ta53ijjR|ne2M:F7)hM9[& ɶAFǔH%3LϵR$ŤRd[LY&aц68d=3jp*ֿU/%V˸eXhav>ݼ(+-!';UyjS^YM'pӞ5Pa6&#PJ&˒Np+7~{6.{"mZOqi*)ᒩ +'YT%(,s.)&y?uWr߭$ft' _C8!Az$Sv#CyU$&%7?/,%~:Nܲւ,kE"07bۭĖ!INQ>CGp 0"|0mYTH'R4F-|*d"&˦4z\c 8.,-(Szi[O8JD#y'yazBV *V  ha@oĨC `0IAI#O,64SϣNjn1f-UȾȔc>1CD{j 90Oy%K {yU'_|7>ߧYMpNҹG.0/reQ֘MFIISX-%鷅|;g}cԆ Vꣃ"o|ݥQdz|4K̆iJTcrIpW~,n"N8j pZXK:0M)XD;vL>6visy4cʊ<߬+RJT_eI0pU;q1Ft^=o>L(+*ɓd*yj4Vz<*VqM|ݽZ}݄j;@J׆ ?LꛘÏ)LoQI.$8  }7.(5j^^*p6ĺ̛#} ID+iΒ FB N2t o|ǘQ-`d\ i!y"}rﵪkj}("®RJ⠴5M)ًZ{#˗E=d~ YXTa1Z,.{CD6z~\.?%Qk}&'Qr_hnNtGnS{ID6tY}A!m+hIDF"0QyǓƘ,3ٯ~u`2n[kKO=2^" XKS"0=y̷n"(l j}v8)"s5{!lT0JN)U"uS퓙Sk&z]jxU0*0;Mu,|*Sim>3q-d\zޚוmڻvnTD x]7\\Y .6F*_y3 [GjWDd#`KvޑqYw:rr  .a4磳bt٪WJ$"T/)|fۣM%Onֻ$Oik i\̿^f\(l)1\&(Q} =V'aW2" =Է>qװs\ \]5q^xc!9s.ݤu@NQ}^|c,^jh!1F2=z{Y gܘLl[~^>B<#iJ\2)Fp%"*s)\d.D_)c7{- "f7m̽w@V4+%`hR}=o۴oyU+s,H1>| 8 u\5 T`ASSS!IP8iI%w U_]I2٧U)&r_ͨ La?⃇B2ޮJ`}'q‘. B_MDHjgp0R>簡sSVZJK)-)NQ9 *ߏ󫮡 dY eߝ5ìT@2[)'e8hSzfV<ҁS|YqukSf5(^&\ԒMߺi:~YzYMw=ժ|i$xlϼ>/0ًbREآ?c w༧}#;7d DDT\8@ &eVsOW,x~͙MRD:K]>O%VXYW 0#!K0.BDLa+:.XB"1a0Tp9YIwD!aOCz<5Ͻ(+-JeŔSVR@Iiq!E^r "SW) O9}>,r%Tf3 Pt HF:P`ܥ€}Vm<9F wϿsŷQ[^"|XЖv~JGԙ0{2~{驜v=|fDZ@&3 B,ÔI 5̖ƹE]YDdX,igy l)*(RI9Cɷ?~Q<;K)]^0X];@g?D Ad,JfARTٚϐ"Rb5v_Fgg/dR•3x`nr!*V".XXs±E*ΰk="RPxR|Yss3K)c3PJ RDiI3BJ (,#Azq{q}ءXl t #URg}^Dkhh,x9I o^Rgy?aVm+kWRw 뿑..\=| ϙuWpWnR`a$iM>kzSl0sTnC`Xgf.MդJ~XM.r wJa8 ;`ˮvz#8X+pRZRd d_0gFb (nBc+D*Jދzc䓓C멭2>HDD(.,!%%SX`.^z59;6SҐ4QtǗ(LJ[x+kzMߙL!w.i:CЇy\tTb],K6(͌b\zӃ̞+M`2Gԧ]F"e9@U\Bd # ]'zO+Jf0T`4J@ \ 8쀽du"cJ|g}\6t1<[`T#" JjQ*>(IrQ(-.^挋.ED("U˨ZƂ&#bTV:g-œJUh|`Xm*Fa:JE]6Rj\&"ݚ[ANN6;$}{@Dx'sZk'dsu̞M>Mǚ[B~fiIlY9epl1{sJDd ÞRwXRϟWԋ Ԉ'Ћz?^`ƫt!ߣyk.x4v+.xU"rsSSjG*}+;lɒ' {nMNQ>n)| {&@>RlV")p?лRLL+ ."Q\E XG:oܻd"C㌣'|*ȀI:l `4XoOz1WBDN|(e%+\ j|`h B!9>F-YYQ}g8h o`?oP-"~7g>5 b!wL-MJNO7oZIjYKޤQ [{XDrRض,)btTDJpJDX)p{倌MĬAdLA*͆Rjp&>"_"Y(Gŋ^3sjD+TFXDw1'sU0iD0(Sv2ݤr<7( $ɺ*} h,`[~i]لQkFR^F 0gF?6ȿǝѕ:ѭCs PbђJ~[XopdfGTbƤoq8CrEdC`/^ ߁O95 |gw= j bȚ{~AF~7_GfrO0}w,uOAJ75@ 4FU @H6o=DEd"M<ɵYg/6|pgu|fU,BS.8;y^2F3/x Ľc͝\y@xZ -GbyQSzw~UJ]$"765 Va@H$„S&3jVkf}=}E~_97c2MǍaFb7s4QB׬s`v5f^vAP"g=G7~fU.vǔEMgFs5f*PJ)eQ#]E L_;3g83nbƭ;֨saYi Ͼ/V-ӇLy0vz:X#| Zb/y{ʗTFÝ,JvNJU4ً`jv@/kl;.dŀ ͊Ky\6Z/?gx,PX(vv+9xƎ{~ 򁅖5M}oc!V, jubtxify\`^c|XW! 1rKnn.kICR +f(4u㭬ENd~+}rrr(((\,DkN$gn"S V'+dCS~aJc8|_u$`A$Is,Q)mYeWھݷ{}]]?%VMY&)QEIH'vfjj{ H>Sw9gBO)惍G VO=F&VWʫ@Wla?{;b f$_%Ge) 0H5DZ6RPY viEs)a(H I9 . `LL8E$Ek:ֶ38s6켑o>g7켑Ly]Vmxc,[#z5?+%"m"~7uk^<|.sFݹ{>\%x\C8B^&leÛoR֕hZe)v,G4K5=VTi)*Y"ﱍ,R_^uljuhic#w87! ?ciR\||>-C')c >b_ɀkW|W.^v`܋&F&@b48"c$BpÚ%fN7X}RJ !;9?65 E1+˜ Xw< 4M"1W,C_{ױ:z^6s^#qRnsuHy㴧9"ӁZBr`8nMF ^|u#^|u#R?t] 60cUstAl|yt&r"`}Np!6%KBJ:iS;J=~HMÜa>IhbxzH-Sc>:S$X|5;4?X"ͧ}>|::mC  >;|ۋ?ߏ32g0*cHQofUbJȿ>} 3r@~R |>3jq]GSk;v>`Ǯhm?+닢3#$1'Y5P3u2=}?%?Oh2Opv"HukVO+-dR>N4d0B^b Q+AC*O`wވ"|R*/򐬃 4S7qJ)} QBț fלQ3!Dt\32^ *4Yy/+囇kf X])4̕+Pe9`^$+sx I:Ab5^>+G/FM.S tCP֫(}\q9T^Õ1eND+ X*5*0q(,V_f*icR7~wDE4C$B-!׈G))9y)ru ׄ1u(َshn=6ͧڎήDbE/M(nBGҵNwAIQ+QSY2T 5(+AA}sSUܼn)nX|~۷p)`R^'@I~5nW]{:5@+ #-vBf%y;7E1 seRfG v`O${DL>"ѵ $ċq:3]8u,[v!խ1 224$sSy)^$jDc~2~ĩʇME-{-`1kZ>/[bIHgϝCss+[̣[N:u"]=pzR,:@~  h ;p kL"Kf8CYI!'$@Guy *ʊpX ~vroS.hz¶]ܘY7E1$k˯QJ[现 I*!Ώ_|9k?TNkBfRFbKB'-M]W| ;9ZFQ6-Z!/xfHr,J ꛐ2<]E2B]6J.5IQddzX!p!:Fa4GXF?9ǁLd+?q MKV a8'F+Ȁ$|DЊ64cL!G] 0tˆ4* D{0cD '_ӐxJ\D!@bW%Sa 0=M;@(YFIC2 uNƄҶF S+݂ZcdQ%qh0,.ʍ!i#L0R76zH/gI)\r!xXOh,Ԥ\Um8GGmE r:QS:K.)`mNmΦ2 X<p۸N x|4״ƹ]FE g•G4$c`XZ X"EʐxÂcWȑ  *b p)ۮS)>,%'Xsʰx B**~&u2 RNFא8& ~ͦmD0rpZ|ew&83cp Y> fٸ_%a7jk(+|`]BR!VƱ0+aK$*8:5E0.YIŵ=s.E*$@ἘvB+%!5* QɒM&< ɑ1ɂb78KJ4 2T `}t'<ibuG,d@ y$ްT`FxdkG8o6.ѰaO~`^,hc3DT,G$r`D%8 3T?W \ K@h.F h V9{Vd`sY:hʨť#c`))@zj e|lȪQ:(bq=ɴ!SW p!rR|2)8!)BA$r!$.TId#a<*E* p&gYNQH(]bک9X0rx8l:r#I%sǎ-ovd&0`(dJS^ ڍ!t]L`/.N%32 O5A!b\^Df8ʡ\`1RJCdJ ͵$^*q:9qN*0%1C2{f]23~Q| 6cPp @沛$Ndˌ\P2psĘSd0l,@l)PdR\HvPɭ]ߍ (nDrـ Ə@AuqCOlq=$lp<\`dYճpt1 6 CP3rW. o\. _@bgJ  \jgHTs¹s'Hx(3CQ`hWqmJQ{ <% fow.Kְ]i' Pdz؀3XNAR]NKP2Ucs5îX#-Qr_<Hr:7 bvl>fbdaF9F Ld9,x4qCbHYـLf<7 aMg@2;'qV>懢88L;3\i:+IW#l"kǶsQ-@CIXB3A1A xصuYg<\&X0,RUfLRsH/![CaN ++++++++++++++++2VC+2fL+W!pW\I6}W\qW\+A7shȀE;o\qW\F0\@:6sq1O$E쮸+CJZWbsNfdҋٍݕ>O`]s׷^s5O?gCn9qW\qe<pe,_ {3dt  `4ь\Kl6l+%Ka3g9bБp;cZwPw>2č`2V? 6 @%h<+VL۱cG TCZv\R\IQi`0#Ga:d<֭,U I rq<(=Btx{*W\q+bP}\bńG~/nN%B+_WB)!D+)) Ĉ'7NlA.06ﱹŝWFO[ς &> hx O:lgZ&g:Ʒz_BjzzQTLȑ#=FHIvJ"qn('kP_[~?:<ܭDaGu+9'nߔN;=ܓAgzVk3aDttnjQP̝;7Ԅ6Wtq1y2\/eL6WzΏ\Xq#[cC@ ~_NQ]00T6qcv{>CO.p\#*wiʑSC~bUU͙3ү? 9X,޴}XJxe__Amv 2r\q@@S)jسV^@ [oN !̀r@B6!MEQ!dnQQW{炫3׾& ,r&***NoڴV0d·N7Jn"tw.F2g9yg ӊ %ǔM6跌ښWo<@ak?<O.(/>@uka7i!o.5&@!s{BHi,'!:Ձܹs4H+Z';OF H`!d:(2rRo)qgІ^U vCp`͇RBGsz/Ϲ7JB%4d=ya{x>xP:::`IEQZeeeSOMя~K04~`Ý;?WCAA|+'?ߔҸ0i06kfk_[x={ap0 Uh{UW-|-o`PJuBH @8Ri.U2+\y ! k!8T;6ބџ8~X@Bby}An `Bu\ W.\+6,E.WVV^8p(`߄tv.TUbΜ9an~hOs] *vQ9섢(n1OK!6T\s0] a{1w=$#|RD*֮t)sMMF$HeeEg>tʕKmmΈy19CC6MӠ*~p=wcƌ+Oojj:a@׍wR?MaҤZp‡BywZ # ̵`D&&0ꌋ {NhF[.!&`֬YJJJ?RZϼl=)&|Q c=Ve/y&~bgCNUUgOL0a:Ӑ0$p8R\\>ߢPlE"x;I$ȮY+D">fB(R,AT]RٲRsuHf({G\J +[eRv ΰ-Փ ܆;Ga͛:X!?5'bn R̛7555&ܔ:~pRYrUUoBH&Z<1ϳȑtJ \2NEQ!8w%;mĉex<oqo- ңbȈ5.:w}555{/vbhbZًh*2?7v~/*LYnQ_җVh?x?|XUgP-0ԨԃH@bp!|>{{-]W#b]3 #'[K@Tl^5 CF]65VsfÈba40B̝;yyyGK/w7*++˗YZZZ/ O;ҍj\v@}'4^쳽 AU=iԇ$BA$GSSNDCC#01aIG1| eee1 1EI|3ٳg+2B&Z(1sy'@˻$M${"k*>4A(|#f|^js)\+`$<,ZEE/XL㪮뚮՘FCnmWK'Gr J+XCrBe\ć5c(R01DZpƘxWp_I>}7&޽w{u6h\>y@<-AMMP[[WSoe>c2F1.:B|z1CwBe .ӧO2^s]UU4*Q ?rX~[Z`eT߲MBHa` h( aϫ79B!)(۷o-[Dj!^_d_:s !SR4{4lF)/N8)=p/֭[E;|hݺux۶ma\n{]se20n'EI)Ň~T53 @)NČ2eJW\QsرVqJi26uu=WUU&f ~EpDeCb9 Ili9F)Qt(XGs=+!O8Jϝ6xmPePF#K1ˆn޲eK+R 0gb ]+90Xb:!dܐ7a„U>,@d~8&1/0 )%Kk`(cƏP=f\77Ο9l#{t;Zr֭]n7otwyQUa0uajaa]ٳy\%"~`c9ى={5a^V23زe;%{ !pϙuuu=hKT8Ĺ\W0Ѩ+H$tKgݺ50aOwQXyI$!s6lQ H,ZcpQG*M`.xn4 ?"N 梮^78cƌMvM{{[n<|I$8!,O1O*++ fX:u2Ӈ?((O8y fUf¼yj৔ !soL_9iub)cWZZz#='Eu 4m:tuGoo/ɓ'W=zGxIff)@z<81 " ~/Ċ;m=saRp!V#<>|JL?GEEE /ٞF.pe\ Ed?v"3tYt @u/P^O"g!طdg](Rr `$60x' dv]ǖE!I}ᇯSUu Ü9h<)UUU+|NڲqWB!d4hErUW=?iҤY@`z[@^yyB8q^z֭[{n!kS,\#^f͚)[l96$PĄkH{ELT(F<i(--p6SJu5w6y3.aH pP:!0u݇dNdND7aߕq0"ElXd*b%*<̿UWiCϪ_$DHO2KAEZ`8ԨTeQ%" y"QITUN)ŦMG1ڵ Xdk}ѕ~_;#I s,8uQ6o`7c 'x P[lGQQ! QTTb|^Saj AA_gXbm.+{)\ @8N[3gμv˖-/ =:`pE0DSV\YEgz{QZZ*&\SFFĉ `"%"Hx..D7S lK6<1#`d` PdO ;o`"yBFHxG} vރSY rAػ :`yzٳg?y57o;vDz'W>)!+/a &\7 'wee9ꊗkeeeZqqGUUK8+q)R6]`1r#Q(.. +%eIm i!}}}(--F^^^%k$ҫILqmUUjBEE^o7$ߝkN N7e6#5 \ui`KHJ Pd 'ړwΫo0(AZb|9ΝsbyB,]:)>H@OBaF60Iw i6E]]w |8{qQX3f\{ٛ_zW{,MJaJ8 4'T@n/(8p1EBplZ[O w]]2(@yyyƃ ֛ƍ^zpp0QѣXt)~SN 2CH/+:`JҦW@(F4j<@ P! C0u8l]QQ݀100 x<$b)^wboKBoRM2D!`?R1F؄/씽Ȇ$|u%Q͡|vʇ>O5v){\Q,k ZA `dx@+ %a-Ri=G /_ i6:t ֭@IIR__׿9ovhm =uPhƈ循;lm8Aj=s-uU(--,X[={6BY;zGc8q/^ EQ+W\K/} ^lEKlǟSp #e9u*+90 9{>$K"jK5RIj j IDAT&w)\\u#1=bႯ0p e_uݻ_R \O>W^و%Kcv۷Lƫ.yL\}#")v߬jaػ;w>Xvmݻ,}xpQ 0AHD"hmmE]]jjjVe]0=\665M Aj^DQU H"PBw[ne-!d@SS+keI޲2|bynVO--q|_^gx tt3\rBA&SfjhV |y0X3﵌7j4}W<0 aFQPJ`T%`D(\q,>fhnnF8NFnOv7E_Eϟ?XAAA%bE0 y"mW7ɓ-X^o{A@iihѢ<cXk4Z8|hl4m˼^[; U$J!(Lfw0EN0Lс䙶uZn$ i6vWb-C}OMMm>EIIѰtww#WƜHC,ÚjY( Yb!:uP+9q`6cf }x6(( ~UU~+ ٳڵ1yr->c/⿷!=z!`.}as p}]id<^;םbYp׮]=Vޅh&p .F(RJihll_Mӊ/_>k֭Ha9nc2XYYU}TUUM8sL3 5Wd] nΜ9ybSP^ 00%).d=2\ӟ'ׯ\h4FX,byxM#555_3ڽjkPRR-Z(Ν:Ԩ+pa’0i8{,Ο?L>ʭ[9 ؗs˖-"/1'u i&H!RJnq5 x'3JUw3s _~-e>LFBRdaF XC[,qĉٵi|(7e{$pŕQ/#Aм2+fyDℒ~HdW1 6^=>={ /^<t)FRbUҥ`Æ K<س@A]]=hi15k֔p%jKTx+%#Md"4 IOa4 &,!T%)HI)UUUS>b3QTTT*ٟ4'X w|KM|1<- `fuAPU5,aIQ8gs["YkT.`tel8.¦2b(#FCsA"(0h9|e+2΁xf8)pf\j~-TU}O>ه5†F2jkkiuA˽{ ŞK}ǽYLUr9mټN QRÇ|rӧOill`kKSdߞ70?n?#s0<˗5M['O~|ggg\hfMq7V _i.X UQpR'5KR\`G2 \8 2( #U2FҸ`g㝷sAg*6zc~ >T F&`ƩP,YTUu 0ZF%Fƛonƍ7E0馛h ~ dG@6l0hHŔ;FDmWW/Z[OcҤ*ZO?mvP.}AE)MhjjB8' ,X|t↓7+Q[0zT0J@~~~ P`_EJFTV\y!RPgܹsaйﳍ^ppZ0Z>fBP4M ak'D0x!FG~|.JW\՞.wz 9P!IY/@Yx0&3 CMك/g'`[&'y+MNrίI>mE_TU|̝;w&Q 9Wb9GVqEb?@đ#'l{6R"W^YY״F`iJD!2OekE0t]ѣG'N\ԊNvt)K|ӟoD@ P9]ɩDttG(! $ #۫CNR ^q6:"߆RZ^oW B!HR5=c BBs!z~"`yEPŽn\2|A?E~UUUpB)麞oFa<PJRs-2(+C|ịP5\ʂ@m zUPXgzC"=|` w7ݴmv?$V#x R̋R*u]U^~ط0tz;FϟCkLT+WNܱcGS<gU+da/qرcu/[o}Vb)YJaaJeFzy>Y .o0 Nu$8,D`F. Onhhh Ȝ%s]L` @Wl0?A.ѡeCL gC*$E߯q@Iځr#Ñ2WuqWFjS̟??8cƌ+`&Pְ%!! PJ 2eE5yvVZnwS)ךi%x^^z?x9kƍAPoƧ !a*E~~^iNVXXzucӦ\'NBii`̙ V\y>cur{o "X2e/| kB_߀#H}L,Gmm%`ڴI8p8˖-GF>>JIdG"hX,fϞǿ9t "4ȏ= JoiEM۶m08.K0CPZFz(...pBq87KӦM7ޙ^If3 hգ~ *a gZ 6p$HSNqEY .EQi4ϷuuuƵ^{OoֻgΜGj VfH_$wzoIғe06#,`(r.nT^/PVVcǎqƍGxT U.pD0(4u]GG'vhecٿ&q8TU0_P߽{JKK1w,x<R#Gam#\ aP|n_^w]w] JtcH{s2$ r6GyJQF￿;w~kiOn\ZZԅby]nݼ͛73>a2^7De/}KkEYwYOĶ{Xpȑ#ȓO>P__'N4kN}z^N;hkkihh0('NĔ)QPPp ~{NRD=|fj0 #0=u̙3iݭgHd~[KaD0T^J$CGGO Kv (~bմ~ UU6]]] !L91{y(+ gUUɌ޴Oz gqu'N4fA,[ ̅)_l3^x=" bҴ!]Q#m/ I@#*DRtO<◄z3ZՏSdҁs() b:d?<| xD\Bۍri#jcii3gF<q>Oua^vk0-\׉\#(</xGҌ3_䓝xMPTs.`0qb Xկ~uk[ fc`w)qӐx:_bV}*,,!8pihyvmqB]]f͚Sr7~d˖-,]wzI߮\Zg"uRZN׬;q>}}}1}).pyiOC/RrΛ7/gx- ٽr OcR|>-ܲ7͟)1BH}XjpVF̗ٚ`F/X @B̞= n,3J<| {zrAD&A I02mZ{ܻgsھ,_]+˖d)& q`099VꪞHbTSgfzzz}y]xѿ~LÊl OŹX,{V7iF1dllabix'y|ݺuoOg*M 0ffffbZ nl۶ŕE]ySz3<!$_d0 YIb)by9A_|MEUd{d0"H *M\З%Mb0^{u <#~vk ĵ>q_B_|h>O/kT,4)87f€ IDATbMعs,KK/~˓'Z$cB z}6QQÊkWĭMɟ7@!\|33yb @?'͛+a6{p8wW^m}~/˕}Ug@i0eJ,EQzu=-NjWiaQ:EKEHS/^.F?g)}[/$_Mz555eeei sMĬf6 ://~]])s޴ C# ONn])| 6m3L2#P 3y~v^mk^ǜaդY&HwwY֔ sgg >2*++s`O:H[uuuy 0O`,XVFf\,22a! D-qh)%?1Ίm<zR}o`#vzXKj_xGȑ#ݶm[Dt P8.Eee**cW16ˀCP3oN=k:bypjB((2:tť2y| b2Ji6Xƣ~f}QeOd_IzF}|hQ5Nl6 ŷ׎!BȡC6Bdè V2(XKX"SK/,{iyȂݻ\(//={6 + rҥ)r!fk"5jl:m ` | }@AL*(7$BXJweB(O$T E:p`sssef%*/ :#.e5ًoNx<)3}Ν{iXGe }WjrrgD85>/pׯw#( yj̓w+0j}HӴ5^|8jO /{ZnV ˀ |Ij< `TUV@KNoP8w\BƎQTTnݺ( QB̠|1rJ &0~)#kG͕enZB+WT kmm ̸]./߅8JJrظ̙37`ACCrTL|GaیGy:̡BK\-~"' ̮]j3fvև n#RTVz^Z[P ]o߾N*Bıd -!K !ABH'!阕}`ziQU߀9s8,(@EE>#y(+CYYn(-Q()ɆaQKCAjC٪j QtAAa?"D1)67OK}/'qhhb\ݻw"$gWaMs @[D"4Ej299~ԦYaACPPѓEl4L7YRˀy#k477WTT,\.̤r7 6M JvgYYY"+ `v/ 5T d8N 朶ip!errr"h {AQL&cjj*(ˣb׮]fM`]${v]_mJ[,? -*N4LW"{# eYW7nw R^XaЫ Po.Jq\={EQp8 n#jXj/vtl̋ /`˖-{  ]/WGec3Ji6 QBU" dRVi! ߻i U_y2܁9ƪ)@_4MS>ػŀs(}عs# r*++󻺺d#B(^;b}Y z۶m_%dr;wY gaiF@OOO!żsnܸ1|2aBt%XO y)9 H,Q}Vu' @ikn`֭X̆>Ϫ=CT׷vx<>i0f0{hll@Ve===x\X ˲%2H!XdddX4<LMMMlQjF5`Yq&&& kA;w6!qLZU?Bi0%K. ^+oݺd_z2_})}0,W^yG?Ob:{/f8vؖ 0 y4,BBy?}ܰ/2Ap]yTe99,;,cǎΝ--O>)Ytj_6uB- %$>*+" i uk@i˞V55TkbO=fWFv Al)b@ƪ !]0LmEkkj##S-ؽ{wMWW׸ Th uq£V&.6č~0~OQVfy|Dz`i^xᅍ b>p@QQF__Q1s?ϙ@(,,hb@$+W^!@OO?֣rOJ?ro$Q`߫Tv݄Gڵ0!q<_> Щfi.H%(Zޯ?O)ٹR-Dzeـ0\eO=U3 ,oUs<|^üY'N\''gy"i .Gg,?++,JeyTGL*qm= ! (RJbF]] khtt4?"4M^{ 555={a R-M>GFfudZUKlCt:͛Aa8p [.J\pXj%EQ3]P4y+Ԥ˲F  }Zp8L04 /q>iEh4x<`E0k$Ȟ={N1b&A`H׶$Xj C!-`|G.>lܸqkcc:D(Q*Mpx"(044Q }}BO G"⃒1]v wU+9/"kZ]A]"eD#C}Ғ{s9SZ5KԺsӗ `(N#X*,+FjP4w1ɠ,遌** Ru!$7׿Xs W|E:488h4Ν;u̗aCPfV+cZ ØN[Vڼ,  N#Ձ7Jt_*nzu!hٿ|)9Ӭu^ç߻woy\Gb|* ??K݋!Iq0Ւ0=S "hll,úކ<MӮ9#=c- fTŶm۪M&zGV/xC`Æ NE>D<."aY,(&''X#.],!SO=ujf*@Fctt.q7'q%>}g4f?.DGG_ö@Uwȑ}fPܸqc)+5/AhW_RR U:GPDf͞R,jT%ġ dcLVXEx"$(AYj[ DȠ"#a!B^0n\I !k4M?|rSS3_zpnc``ذaCч~x㸰'׍2X"1Q+J\[_Q$2w|YY(?>b*i:vɦBĭ[ Ř@IIN>  %@1F\U$q %2`0qEQ333۷`۶-ȠC8i#AyMa4a42R)Az{P[["B}A P^^^&_$:,If6YdBa=x c /`X@sJ1"{!noXdrkO%RD?p%}}+`yF9Dq ]mmmCO G(IHe(//رr3 dBx'^POOO͛7G#q^^|YMW Jq1`2Z+{Zxbee (T "9/ђ]-=꾋FwCkkP+ .Ħ}@"Z 6ݽ{7~KI"ưZqVs:) h =r۶zIr|r@hM9۷;ΡzBQQFy߾}u|-̕FFTk%6X,˲F;3i8.\ѣ[P239C&l@ؘ%FFF4w seRB2;R1s%ӭG*/ _X,0::V#ET/ׯ_vdBTɈbBA'YR!#P0XPx<RՉii#֯__[]]}#"I w>|8JQ!+˕8Zcq3 =o:th;˲6p^&,l6 f#hB4D$\ a٬YU2\kP1i_xᅪgM&d^G^^jjjpС`0xglls.{TBV^]&N+0*My!M(L&SH+!p=-5oE)C,+3Sz/\t:=11O?=}&<4#G˲s;xȰݻÊr!D-5iHS([V=M *?KKQǕaɓ"pOTfr N$}YW0A0B:,ua]n;%ikk[&{ΝA U(3>l8vz=Of2)b1JүG`<σ(dff 4!<M 8h_?3 IܢƂFF48puB1?gU \EkTD .RE :)`X Xx([Wu몐QgxWWאBH0n/qKFC>W3sXVw@O0BHeg;lvsJBi/̌ xQ45^ΣZ$|'s8ߤizzߌFzBDK4F,3l6+hMNn^uֻΝk Qh;ǐ,dDV,P*Fc$5c>ϲ> Y}+Jh\Z%kwAjjj~DɎFE!3.raddrǨ?IddXQVVͲ9ƫv(+Jל?@|~tw&u:nauk7Vf$p<<۝i9,ƽ{no+wS#Y`ו 3 Àu-Οǟ.ޱcǺ˗/wI9OQK 'Xp&@>'Auuu>EQRA4b)A}@V,BV3\.Qulp\Skxx8} %{uTd/&X,zӱʒqp8XX؍ =,w*mBVVb۶&Atu/SOAVVVݻϝ;wSB%NCw,4M'Ƽ+bٳeY3ho&a%%0 u+T A E100455U={Kh Q`1 cppAii)XtՃa`׮]_vm(G)(~FGYw8lRs{oj`YQlmL58Z4!49 {17n)Ƨbi ^^Fa8ѢzXL{(CX.Nh`@V{E\l6p8Fb1SSBnsjy5htPWWWOd&$۹k3#CL D^ r G~fCff&XXxYھ}8vqg? >x m!$V\\455֯_kXL9YVסC>)w4%%j$aymjll,lttd|ksi=CƍnJ4, 1d:1 Zb-??#Ik/{qeLNN% 0~.)]4ǃ}@QQᰑ}7.\={6fJp'TjFAָ/{B@\Q|ϫ"2P F#qٳ'#++`gffqQ!ee Z𱌏JKK3ͩ&U-05Ȱp 7Eڎh4$6B͛7*eirP0pR\uK=JB(ŌrSSSjMaBjZӑX, 9(:;۷o*(Ö$ Bo'SYYc4Mvc5D4h0`0m1A, 0$oJ#1+ ۷eB0884,$4זۊG͒<0r XրZѷܹs}kzAOwUqIa)&ͱȆH$e%.Z>o&`Y]7ov@v3X CfT G*)pc9f ;wĤr^5HXPq|E<`Yֹw/@q@UcꯤV@ Al<,F!"TBe\5(5 .T5?!<㣏~\ HeXp].(ꜗ7 /Āaζ)qV_(n&!qiӼ'ŬLTUJXN&j=t..70<< ())y7=d&CnQ0FԪ'Vuy=-5)J9T1U8˥ǢXGPF_SSӸ|! 4ݻ7%p1;!l@bSH`kDJy=/BAP_T^^ q,KN0$za@vvY.򜬬%M=>`$v4ΏD0 x'N:%QlȨEWԬk` %է d 'nXB͐Xikk "ULAViݻ6mEQlĤHwwNY\hRp,,'^8n jk7,0NWVN-. +!D8.Кc^9r_5VZ% rl(RP =@V N"G=_KeU`Ͳ>Ϛ?75Q~rb O>ϟ`ixx~Ł ``ddd,"Z{0,PNͻja,G}4 ɓ'3 pv;R,`CIY f1:LZf1n#HUg{>A!O>&HnvL̏-{IQ488.] )JEGP'^2UVV `]5+b12DrIM+SOmZy1~8P'mըC0?|>_/`fnrfXլdë:/1ABH@H 1Ŧӎ}Ob$@0 p#ם;wv{쩖Ţ00̌>; >Q8p6lؐ- 2`.0+g8rd! YR njll<ccx!ykgffffgg97vs J)&͛7ogZn]M-*E` DSҁ T :HLH?1 !I.0,qVZ`Id2\^ C! W^뀊8!D hı2r_tBz(yRcKkNH8ppF' Ä(ϙf< C{XU"vʞLGdX1::>o,5 wxCغUUe8~I۷9*#Կ' 337hl\g.\=1Ԕgc\gFk^^`hHX%RlԷ6{!lOҞ?>rI[ii)# m pg&wRf1ntt2˴lc=Vp82X!&)I4@ bfغuk 0rQXH`n2p\aXe09!B 4f4-g___H\cǎ=n0ld( çf0W }X+CK$IE.jCݔBp8kȿ2PT{n*U'!qxk- (GF<4}) DCRGf*8ܺ Afjm[=vhĶmFII~\+WqZ|Qɇ;w:*ݡը pcDV-p8:~򟖗 77[ fт ڵ[%:grJ̙3J,PcId2vi𼠫$6?nw&~M]]]Y!$<7;;;Ur9?x*A,k&QUSNegg;D1P_.23ؽ{t{ݛG`$@H\;w,+qN]?d;q`S~E[KlAݽ{l߾}KNNƒXa &]ve CmfahҲ}-EY{69HD,W5LF}+tWJ˞VЯRo$?WVPD"g}GP5S"d/{ !Yi%n G:6CbǰaC***rss[8 rL mf1zm4b{)"{tlfMH2Td,BAS>FmmEͶ{׮mܺuEqqmÆ 6cUUUyL6^K( hdp\a!kj5|G>Oh"p#*G?>" -[AF IHB(bA&&&@S֤߸MԸWZ\4*+`00c=%mʃUܿt=*f~#! @㩧'愦)ڵ=wǏ 8xqOөǣx3=ґP),,|Fj8C {KP[K%R b˖-_#88CKK.;wf*\ڢ`.${f@bK2222rH:XQ*)|̙x|**J1:!m455UBQ"0888 UZkJK8Y ^hCrE8懇#*&;vbXy^@{(dgۤz$6dnuȂdZ3/Bŋ?!f۱eK;>',e&#ZBi9 j%L!'' UiQ=Ƴ 4`s\79 EQr`||xb@X!*[5X2ַUOQ&~FZ@ Y ~4I<kjjˣ ,Lhom=-ax'''R " "''+fGԴ\,9[ZZcè(fiAd %PO> IDAT֭.jEp1=]BKL(ʤADj^jd2@Iݐ.\S˅7lkQK)38>b@[kYK`3~Yqm(WI~|>?({,Z$0f Ӟ׏7%q&(.ԉ9f/{ yڰ$䪫3kkkEk `uwwd,#W/UbdZ\ҥKMr9DW܄ ̴<䓥DUv3WwE걄B5PzLV#=@سgr'af&(#=eZRBt~q\T=:'Ivd&ʣnW Cԭ*k" H(M:/=<,CfTSSS3/y'ju^oQ qJ ^!///|zj>'_ /C^^N"p*(Bv;vl«>Ç0LOOG~8^8(5K1C!d\</AhFc8{&&'gkxK#l6VP5`Ww,q{!},6c8HBeݺuIo|B c0RSoyRʞ'y?htPl!] .GX0U:vXEQխ+FYYHM8R4Buaa4 _m_*RQiq_#wΙL;?&ɔq===oooWghso#<~PEzIrOK[ \׉'^sݒ,.]jQݮpd1Xdb, ﷿E- bnmH4t_p)r, fCb1PWWWr̙/^XRI, {O].+hn%*3ԩkQX+;vqpp { ].;h h{`k3Q%h[5(.ΆJ 8nSp۱OLLkjj26mT,x<DŽ{&DWQhUvzOr8=6 \Y|Ẃ#Gj^:AHϭL]]:ԔʰX,`0J$+WJ3227)祲 I/FpZsFEEfNі׸y(r Mh JJp\Vd !T`$YUQ>ˬb-=-aK0RLpO> Ml??PIӴqzz:r3+6RkH%ؽ{wݞ={m0=7U \B h` RXp](R q.^^R/b!RCCdaz߾}Wʴ_H֮@)`dd88>g}Vxĉh ݻ /KdŌT➟\"x< f1>l!twO `Y< ׮]Rj_=py5yTDxĉuFon'V ŋ7[o|:*S=Ф(Ey"VZ,{Zk$MjRiA|}wy3g z`Æ3\|P\\:rHP<$7+ˤR(YIl!l a~"`^H$ARM0(͢E{{{D>/Bn7a&{ou~ }dl6[siH([(ۊdŦK9vxwdμ9$o72$ysdΛ8"ZlIV[2EQ$Q^KP苋[&P8h}̌iiKal,yفIis={y)nXEBs]~?$[ȸXs3i(H؋dV0{m%IZ33%R(Dִ-,s gy`5;X`} 0 @%ʞ.F:b0%-2Kad9U-,1Y`|Gxodz0=_ܜìŊ e/}ѕ.!Óy ݞR躉LtӦM+#CEu`mؿ˔Ҕ(hk[S>H}j&\.I*咱tiFu @ӹs7(i$:wIS4lٲ%pLe4119s&&tV>ʃ ~5;i&{iڨ,'o(eeߝ8qǎk|~ΝPaۿNj5 # I;W -4}k ? .gMܺu g}v6A|, .QU`BHdr%ÊeM"@"b8 5ۦ5-0|>.\@1R|u`E.':9MgcY` 0DKK}okk$i {G p]i0<q΀nǼUUq9G Qpf;}Zommu?z^y*hh[x6lvx01YI{o(F4ƭX6;s >4M}?7.bE=uuu_0 }4Xf,Rtu 6o޼dժUupXbEW̰$'/ŋȯKeQ"ً $mtX<$O@: >qZr65*P"U}r;` Ö$?: 63>xB ##x)9/|Vnm+JT<*As=u< 'Nʝ8R*gR bh(f-VdUXskCUɓ'@0VlYVx]ɼkv$ (2c˱ECi2`^lbDJ{d=`pQXDDw޽[n B'qBo q\8x\$I䡇X__œ, p뭷җ}. .:E>\Y8sLl݅ A^lsj[t)QR(iy[\ɜ$WV.R({*5af;d6+b]El=W?&MĩS]8{c \=f( U9H;v|2 }t v: B2n[킢d(Jp2Y;s>Md@)sRx7Oرq۶v\_IJ:K{nC  AYK8u$VYSLO'0<<:,[M39/~^CR)Ǐ"2{|.,^q :tЄivu)BZ*Xq@Ph"gG?ѷ͡Ph-&'gl%BNL6n\MVvoOmٲ֡3DbqѢE !.MqiY`}ԍnZp8ݛ8pŋ}vڵvŊma8sfӘOnBGA[\^xaR&Xŀ%McQ삜0pnۏYtӠϮ#xFadTTȏFʞk[  d4^"&DEvy;v}ӟ+)Œ8t#M_1pp2xbӦM>p$`)թ $zxx<}.\Ҽ濦i*SJ BH1PRC4}ܹر%KܼCE Lqs<ooFOffTPJ+X>W 粝IpsX!ٳhl 咱jU]]1d+H2Qp. D{\::4%`l6\D}V"9G:=裏(u{܂^UμܦiN }-Vl(+VdX"СӘ͋Q}jϽ޻vo$qT?Ts$aÆEPT>ST"iT5;Gl iNɲ +3 (E[^eH$ ۩5*yTݚF)J&ctQfFbo߾mmm I ѣN.PgY#զ#{~RsX,^'{s^Ȁy^a4ND"'I#HhD"H$x݅+1 UMaxx. 0y1 s##38xږ1 I%)c``1TJ5k A)~#ǘyb}D!EQ I [@Tj=95:fv0d1l`brAV.K!ַ'B0L|l'\HeIiAU"/abbJ%*Bd דy@ $Iǘ(5iH"ā111}EA% +j @ |S$mfdn~~>ܽ;,0`O)aHHܑN{4[IJeСCt3$DAKSU c1 ~_ڰa@ p]?x8 P_%1>>-/TlnZ>88$Z[>Eq!01G_dZ񺏹](H$Vxq#+2PjPY=dyo" vmǧ˼&n(}àK0AƠ J3E`^XHuuup4xgۃrG0&"L:229f~} 0J< Ք=6NBA: g[I;Ⱦ;o۷oO)FF&ǑJqR++.XeRc8PA($ ~'ªU-hoߐ$^\-]IiT5UMCUYj90NkHL4,Sg??E"x<\O?t lf2; >X0KѫT:rSwu?F"!}N8_3bIjɬD9aD"3glrq]. ;y~j IDATԩ8 TfL c fM@ 3ݓO>7n{'>/VBR=x(]E~}#$`zz|gMӴ^u5 1N>}bŊT%lR XkͰwr"Ŋkd 㚁=ZpueOug1۩zl9.INB*d/Nl3ݘký۸{ɲ :;{qYPj^JJ~ȹxܰ |)}m$IwΝۋ/J)&J)zH$ "HZK~h&+TJÅ ش7n7l ={6|kV>TQcTS,^S~S[n}3۶mŋY Yrn ]/~Ip$$9!ג ׻/B[v`%^ be7JNߥ0fM=^ à?O8[gً*{7O~rim]˲-Eho~ MLt7^PjqVkp`:م,`Y+2t_WWW"Ng e/\0 @;}W#+J~饗]Q\oށ7|'g*Xpoޏ%K2f{ &Lm!{_b12w9r]ɕ+ah=o1N]fzofWE~[.IE9D֬[sLhreMִ,)967krPT)_NvzM)Vٛ$nTxp J(tPnU'(p>/moo$ILxq@dib<(ӊ#?я&)URJCBv%D},pq:u`MJq8{vwA4{Ws, %|ի<Ȳp?nذ777aݺVtt\Ւ3-p(\8e3̞ k73vc/ZvRzG~;Foع##cؗnK^)fz.\H.LqT!۝Y):ϣ7 &?Mmmmܹ.=QEuU;޽;p񩡡R:'dC5uNy_]Ph][Rue%8W^yڵpehFi0;%lX0+I8!)?sO7mxxunYSY&~YJ)VTw3/xCQ[nCc(AoErQ$ӧOL=6!sI,^S!U_=4ٓkVnDkkZZsU馛vմsΖ;vۺuk{{{ 6leӦMԧ>u_6c6C\k wcg/n!p7XͦI+\Pif̌EjͬMB|ݛ7o.^ÁG֍J ݣPU ,~ y& dEqAh'oF "si/5 cZQ\!˲mk/g?+Qj=Ɋ_ [MS"pA .cwhlWQ+cX;'}-]4M}xxnDG1:r!gC 0:{TZeOf`z:i33;fgS0x$) ޒN Ł^׵w.I-pɊWYb F~I) ع}```<\: u. }vX~gEA1VU@~L>%u…?oІ(vR+Q,3\yD)}5hnN<:|p d"y Vlr5__366lY[1Wݐ$ --Q@GGvĉ\%&Du\׿ a^x0aIpͻP=,J se --Iܹs:+sJ+caeOlS9ƭx΍hmٲi*Y`$vYZkWw~[.k:Ձ2p^oƁ' asJ4ӎ;~ӳؼy=i^Vв@ BFzX 144gϞgΜA\7Dk]M]Zy饗755t_Xv%b8w5-.t+{.`ݺ ?ϧLBHUJc䙕HspOޠ(kp2g7, au\ \w'&]8'c||<ԩfz]QB8 iq [zYQ@C`q*M _c9/Zֽ`Xڀa0D׿>o'Ov^>ȸ".ccc\V2t[[]zƍk?{aYZ#֠i}YYM )\l\0hڻw' JA6F[)Ks]oD";w܄DBE_eW8.D/OƍeY?D:F-hs֤NkYk0z\MFOOK]zV5njlVRٍ?=::vb<9I\h !O?n={ <3Q( pcĹ#8PJG@+2|I"T. 0}j mS b9< PJ  Bm̖~YBm` m_hSx.vpBnW, ɲҵ|awneA,aYC.+ ˲Oe I"xxfQafpHc ݛL'o]7a`K&zu#6nܸds΍/bq85S@=up~W>ommo+`5`؋{$I)8t4M.@+H0Q-,`MCu:t!6@ JT%@E|>_=O  +=LnEq9e:%pd|2̿fd0MRB޽{tuuujQJ5nP+k(0jD7l'gettt?_۷/n={vICki'?@,eQ|QD5m,`eRlb㓓644|jٲEӕ''f ɤ;^Nj^uvCtkvK.}bӦ62::3gr=rnRbkBAdM{%:-F ixUU-7E@dI9|7|y J=a 49דFZXX/򮅭6.y{هk.cE@ 0uUUZ,UM 1۾RJu]7u]דd*͝x;|>)W%(a,PFݻw8p֢qd^x|vבC7M3<3C<Ȩy&͍ܺ799(>kj i żxRa}V%y5n׷@ ;nB"wZ,PS#pnF,^iXGGGYv5i/lS)Ml (Vkj)s29Iyի=*Ɖ*5| !©]!p& xp@nO|b 7ܰ-ƧNuBUSmm-ӧ9jjj"۷oG;򺂇~[9s}}}RO}>#R'9i|9gHɚ'WΜ9;33gmmmu]ug4MopSJݔRRZ T.jSl'x>`3Z`srХkךPw˹k?;]+`Hx?g=܁7x}}eQw_^GUbE5ɓo=B0M@6pMBy??B)%PJii.BHz7oaLPUΈ^u5*3'itu@`-ZQY.=c-<gt#֯kpq^%0@^* n}wo޶m]>/ ).^ɓ%PK#R[G.w)l߾=  rSlv6>֬iB}}$aƍr(2z-ÚetvcP9L)uBoi͑5k!񣹹Yҗu[F TxRa@ 4=ӪStf@_l}]=ë0 ^4=aMd1JR*QJv]6g4!FGGhww 0ihy j-%x va^]]tZ4͝JtګiO4i>]eOlc7+X555 ! !+I_$I$ISǎ;aHnwmVg1,y rg}Oz?zwܱ8ř} qAE ׫}9"L̳gϪ>aN5V1\$Ppq#`@#%2vB6Cٲ,aɒXzsE~- aɒ{7 A"4͎[.]38K!U{b 'x~mtvv3 `@L`<\m۶_ ;1Y߷o+˙K0 cu䐕ͮcGyꩧ}kii[Wĉs$WQNE)# `ݺ&D~@*2_N?~|a#XbqE/t7OqBI)8 ѢRnnÕ"iTM ddvl3 Ћݡ$Sxvvːe P0M x\C2RE<^&@F\t7PCw߾},Y;.k!|iO9\[׋+92e+1ɳM$~o: x~! 0>d A\Y@?߿tϟ?ViparƮ^0y#+4g")K̑cįg^SJX*lblQdW U'OW^{O;א+mfyc.6oni(\e֍# ꨪ*˿nSv~ڵ-X^4211ŏ΀g8$IQ4.ɗ_~ylrrb!q]w2_3v.MW $@ VwvdId˵F\̧8@HďHćPߝ*zu*Ta0p!j0Xh4{GhhhCY7Xo caon] $IѣG'!SJKp_@9Q }y督gΜ)$=7`oYP& Ӥ &A߱pA6/1N29$ f$*eKfvJBZ*&^PW&?Kw'7lp^݌իlbdd4 4^CX(E"p푑[o5~5m `DTQuV `PzWɝ|^#b'D6+r=R:/|a!ʀ ~a(\HA}}ADEifb1=idR40Mʲ +A%x=rIhhM31<P<:>ꚁ=)iQ"܏?heY>8rb, ۭ`͚f~8*[$G s7N:u}ʤ+ߧK`bBECa -[/~3CCCȞ`tԴύ @]jFj6ͯ(HHs3ME)%nB}tNf,yAUU wu׭m"F IDATmm7P(@7l Zax7C.PX h(Ձ@rpp0999u]Caf/2ijj[.T(in),!H'p2L!z%1c=h4G$mbXv_zu3]̓r¢\?{t2|K: qF# X<EZ~>Ot !v8is&jN8v{Rpq×ZM/'xoo|]ֱa1b1K/I9޾}ٲe`$)!a###>hrttTEu. 0Nlͅ\8vuʔ=5o$FmX|\`C&ڮYMܼ^zŒ0MI.2 uueX ]TU5.]JtwwY0aWd-ltgG[oE/^Z7mԪ(%FfLY>]]](lœme)gEEyyߊFߓ$a,q؉"B˅@u2Ν;71===]=픚I}nݺ;,o鴁a e'3@Cd >,["-Z|n8t/=zӴ 9-cWiMhXߵF!:8)@gk"TcJ)4.ntVf-k:Ɋ u&Rj8q̉'zW\ٴxp8~EQ܄0 `?z^ۃVqTQ|\hZ ;vcܧXMvOOO'dnڬT`}Nc*TWLS+=dY^ d:#G"!IYvs=>dYF8G8G$@$"wޭk׮]+dӦzĠ:EAdI:d AĕpֵdϾ}D"ߓ$)Wc7c>(7 Y?Y    d=J)}w/f3CϺwX5>}uܸ 0M MӡTUG*i鴙S LLJދ&?|>444r-9{Dh@{6u'S2>n%IP[68 Q!u1,r`` :M)MMLL&&&&*Ú` $$!"{Ƽ`^WE1`H ~y{X$Iin񴘨;kM BHD!snx\E,D6s$S LL05΍%K|dRWW{w7tgljΩH_lp]U,9SP4߿$(+/Ej"C"Xə@*eA^2 4ԒyߋLqq8U4L$mhVʹ_PiEQ>y]4͘ݺt: .SK%ab,6:: .k !$$2dג< \RXmBx]_v{%I \. .aaAHMh@~ nD"'7x>_WG͌vfZ|^D47= ;X[-bsףD'/땭Px|\ÒP1wFNƔ^J[I2b FXPi.0QFn֟JR~Mra4Mi>J4Mo gwk9ȟʣ_ Z+ɓd(RVA!f:N9r ŋ{4 ??h4n޼is0\Z<](JP$"qIMӤdRb陙Tjtt49<<-,v>vl*EaWx &Ø0!.tyG>vmp"jUSpA~m۾(B/hhǭaN%ٙhbddD5MdMi<{3V>L$ | |H]]]]}}}]4 G"@8B!_(|>+2 - m|ǎϞ=_~4:DrvvL(u{`|QMMz@ #y6wK)E, Y ;a |?3qy ۉ$iˢ*%o8  ɗ=# oß=C9ڋ[Zg6* g8]emΎI*T 6c( H) e!!uaYC$MN443N иκ$R t9{Bꫯ^[[lQ2;^(0BD%??'I\l^u}4J '񉉉ٱ10 T)(%&C,b $RܵRqJ) 0kuXk. pXill644|H$ @ C.˓]Ooߞg6R +e1]ZnwC*il*$R&j脐i1~?xd\xkkkk{4M늮n0ֽan4݆a(i*R^J k.n$Hɷ~D2F~;IIJq A- 纸+~V݊ .9nH;$*ւz! 6XcYl"a6{v]0DnI`N`3(,YZ*juQJd2IɤU oT7VwL b.]#[(^{70], TJr~iiާ@,HR)+XkguEz@;,:մ˘lv^g\\l:&&&Ąh=K/-^8D"`0uAQ0)dbzjIQȑ#kSnUkd5EM)u^U}{Wz_y'{mL‰A1Pebζڜ _I Zun-ws"݊`F{>W b,4~y(Y#"=$PXR<;j"e xkعe81#[CqE:5q,Y-'߅Z86bSOow}9|pgrw6,ߴ#27DkS2@|a]MVƋe*-kCv=2HFRjLOO.\`\+ P(Dƙ\rRebp{IaqZWh _H2]ED7Q6Z͊1Am@*̚:1"¯:%6Lh1o ch  7V=_A.&2i ~o3d, v>\V׾&5`s`Cl 0$.k]p@c3Dkı|&vCTD.Z 8Ϊhj 6O6 0x`ЧE"]^)YZX u{Bla)PŔ+*d* 6ٱ=E/b&M@/ŕZctmEEv9J3{&L,Sc<P\=Pj$DE3~3ja-/wչy˱ k *A&h&>Mb:jW`hPa0$ H2D2$,b^d% mp\(jG t(M(Ւj5QyQ5&vRk*/ݱy%H d812,V@;HVKjhVͶNA- *HNlFl[B"xi1ͶA3 jn |`hj&% iAlJ0Jͤ]^pvVqndg( тJ.Wf '[ .vQ d(<חktEZ1y&`gkkT$Z+żTlrXUa:$J4A2W l ò/w5 0Fbٌ@)Wm,v,B,!xIN3R$5KsMQ"CQl`Y)SBv}7*LܼI,JN;67ƕdnEf:ďjJ68 LRCa1f(!U;I86z+7 Yv xK7ׂw;EE"(^D`gʒv9&jaWFq%-y|JavϕrmvEpĶU{7 2dZj`"+XW)ZagRb-j?U1~ij ?v`8vQ æ )!#6  K9(JSϕMAeXkZ]RƜ.#vIQYc5W0Y<8bc|0Zj8Ylnt%Ƿ`68Y] hRA*-U=匟J<(%@eb |@N58N\1WNIb Z *s(4جXE;o߮74kkIENDB`chessx-1.0.0/data/images/square_none.png000644 001750 001750 00000013505 12074576333 021032 0ustar00niklasniklas000000 000000 PNG  IHDRw=iCCPICC ProfileX XuXUͷOrݝ])R."RRJ)*RRH6 (*܍ߕ~=k֞=3^^XC`ZBâȶz.׀hZ/Rd?ڭ|"WFjoHR(_")J  f$#D{VOE؄ycHH;ħ`|C)VQG24.G{M//=X'FxןSFۙ#%X_k{x_e;?h8:A/>dꯝ?;>1dݞ=.@_ /]ƾ!{ gX||#oTv{>~Fd={xȟ5h۽y s؛C/xRoln!D"W4$-+/+'vЮ˶<-06ܐeM; =R49л7@ et!0Vw@ a@g@(Ԁk<C1x^)|`lB  ⁄ HR C\ O B%% ݆h zMC`J悅aXօa{ Gqp |.+p ) ("ŇBQV(W:D*P vT? j Ƣмh)&#t ݋~F/c0 :Ƥa 1W0͘>3G*eƊ`U&Xl6=Žag+8 'YpQ4\1*7[> AAp##Qє11"="#S,S)=)f0)sss#s .]_ q5VVV_LX7x قβaG۰fǾȡAhx ssrsVrspqssssZfa ī[˻gwoo_߁?:@@ ``K! !UsBBk"N­s"""q""EDE#D+DaTł΋=ŕKG%` e@cI50 )J)]ziifi dVo222gee~*ɆVɾ3Kk['ɗ?UR0R8ЦCQBWRRҶ2YAy^EPSLeBQZ5[FMO]_Q5454WoF_KE)m>m/ ::>:Wtfutt~ӓ#52@d:5777Z4V272502%֚.5543/1o!nAh-,,_ XZYc)d+g`o`aWgjgcA!ڡǑͱq)iY KK+>)=?(r0;{=/[O':-/+ oS2E>鋏Oϼoײַ_ߜ|v@aB~`I `Paaa O P(X$DB#ۢphtjtVLia÷bbb82gw9OIKHJ>{1SL4NI"$'=JMMyD{ WJbLqj}u9m"]#$dɑ ߙ>YYY[٤SrN;=s LؙgYg,((T,,?G8}nȢXLVI@ɳReeek}Ώ_йPUUq1%K-ʘOUUU/^aue:zƶV.v5km R 3_ϺnD|Fƞ[ʚ3[#-Sm.mcnk7ߑS}n={9θΕnW?3{~·TlRjVn~yDyeTe}cO _HӬ>lo9,9[xȼ|K<*B"bJܒtRh59r J*UMԔԹ5Mhviifeg囟8mU )v'SRĻt ;A &%-0h,eLBj8*,es#q# KPiٓxNr3 d3V;=gO G=*,~X[Uv|ۅ򦋭:*V>zB-s@Uk ;zt9XkR[;YwO;ݑәU]S~mw u w=||gy꓊e?O zq+*orz{}37?~LtheNo^3/}mv{b%el+ko*H r-üǿ4lBv4FqSzSu2,l~/8* 6 +/Ȓ<&!- k,!/H)-)O1yj ^v;)i3Bh?l\|/V _}tǍŸ+I1k랿66䶅~PcQh"`oKq0L)FD֎-fI*6VLE.j| o57K4K6J]n*[#W%QTRr 5>KM-E}]n=N}..C^#^c^nS.36sf ZK8+jzfvn~aq˒ns1kϴGـ๐ٰC_Wp$}`rGꎶ"t q(i ĝ괲3'S3b3f[=#r,c.UE>U *Z)^,Rl OG/_ھxg{+kk]k={<\1}GFfFdg=N4O6~YuΛGENO7Q 0;9;s间nߌ+. `YY&$V ku/ &n ځvG؍ Xe 9C3HzəA 5j0 6ELS; BdU`C dt"=`:Xv+SQ3H扮@Ha1]XJ5sSC# %јHEAJK5AmNMNL@DLw^~a17f!,,ˬll/989xyy DD,işHKzIIJK?) 3Pxx_rJjZzƹ}5{u&tV153236aɶl]i3aGmoxiE@۠;7B6.q+'z~lkt|QcUBI5'$R)0ɜ<;\h~D!ӹ{ŁeO/]tyAuYmL5,7v&[x5ӳG/5`9xoS/a|g;;˜纅?wV׻6E~`? @ 78 C|[ $  CTP?a~:GкdtŔafJTNw/oPxP< ʈb,#*5j!rNRZ. :1&zQwoǘh*՘XBX ullF˜vox2 nT!saFw"t %) ӕg0بtN9Q*IMYyVvNn^~1YyMVhky9 nnq<ռy z g$?>vA|B1IPGQ'Oeg՝FFIENDB`chessx-1.0.0/data/themes/boards/brazilwood.png000644 001750 001750 00000301042 12042321450 022134 0ustar00niklasniklas000000 000000 PNG  IHDR@;w AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~@IDATxDْ#ɒgLY{sDoW/yOv2oYD5"pjj|_^_\udzoH19$ShƼ]E_?^^7gt&_v5?vy ~_wڔo|[",q({q5x ?"`!`f3Ma}  n];X1Xƾh;GgtxN!ZpR{Rp }v}xd>a՛bs'.5.5|$ ߡx%;_??j :6xqF %Wb\p~ ~Ӈ0>Fn,^Ӆ{/IѦpJ|%[3 }\+3k:G[>w{Ħ}!{‡ CA(Ndg#Sys5A`0!ta1QuU7t1Z8])CkʃyK nt-Ej4EE4jO< Lo_b>)3FxGt؁?G+ڗ*+C=*4bm7KR8~1ž/=lڥ0Z5_ t:K §λη`< K+Pk4QD?/h,ԨWL:xwJQ#KtÞ{pv-&CܻWjq%:F:S@/ S0l DQRɬ[8d<@ݣ3N S^J>2ьPqw>YEUXAkw<V1QHٗR(hF9y}<+a^9BT*d/UAhśw<՞U LF=S$F!יD\*ɭ^Ʋ3"ԕ,QP\sC:kǠYƌc'apZ"VjM%O++N`@/3OJ<+ڟ_?Qx$$fCx[pYC53{{bMB)x/|u|dFNdBki`@dyۡ/<[+1r,gFFj_xuC4.`rm\)\ׅ чd3nwқK雫èN<klmLa}5(pL+wg",nCєVMoI1$8H</K6o#yt>֌qH@[^0""38&pE'B҉l8+5ϛWa/gSB< r nnyz!5X[$4]E$z:Ym9 q&ph,/8+ePYSDU~X}ҍjJϫΛ9_u=GcJ[zR]nÙPMJQԀ{fǣ^j K"fo1N)H{+,j{fΌڝM0 ރ#^[qܚS)'`x10fNU9ᇆvUY<\N[BJrF8lI5tZjrHQ+%H2.%+_d|C/E/7NYL4]z0l d}K㫎{t/uƻPsw0b1'aJ3piS*4/GSEl 'ֵy>m+rsa)Y$ћ菔BvuK3)qVTQvd o=7$Co7y,+p1QvH᪷+E;D,R>9β))x!R/mUYfԷØW-awk" p͸:r#TA|VX~6^C|P𨟗}aea[s{J wFpJ ~NCvL`#ᰈUW<ݻ Y1 f>~K7sW]{N);c`\B뿙s5MqBaKГ˱sLd:~Dv>+mFãt<܈7%-oɭ9dz4S”"2W^;JW o˄rH+89Hi 9E=m+<3$JXY6U{js.:w1;H̼\#n  |lL^USG;|ENA }bbF7)eѓeTg6#v VBKjA,~p{;^!nfl՛!- 0 J$鋥/}%hƟ706 hcOxx_W^Eh^Df۵!qP-CaCA^qKnZ`Dpjx3:ptȠ',jgP'MQ3Ke.YJLq2B`Pivu ;Lf> ߢݸ3 Un%܏&M+;۫?k()pоQCut *ٍYGy_ ٴn\ة2zex}k;kI!(ٚDqܧd͘OlB&YX {p'vZG(J ъG~Ä;bWC vK6er!iij$eY)}6>0CXn>֕LϟV%mf ^>t+ w8d쫣ևLM\ަy'u8mh ~2[r§q(5i)J6~rx&Sb"`R͕HCKGSPlCo]j5RǨObx] o+7G^2bx߼(" >G,`cz/DԬkfOv\lϰ2e1&Lzn̓R@>8.N› 5Aåp8xioLy.w'J5gSFv"sY{ j#S;tV=~qfN^:<>A$tk ޜ+C6ԬvHt值vB,*>6&lgu ^h$d{ƞ1n E8˾B_|FJ{ yd}CňPFċ;6e%^;dV &@G1܍2&._R`h7f7 p"'Cǫn茥 . ')bkO ?7y)TnRz] > ޯvLv!9?p{:9ӲÃ2ha>S3`WOV~kR\+IPtBTj`&'"LxQn% `R407}k6YW8)(55S,l}n1g7M7"6qBPcNsKңuB) i ,L1X ooWp}@ׯ H1bn($xޢ@YLQ`+s?){} &O.lS:&ͳӠnCw0 >+9}IY4ПjDMm'[etHȈaS:`1yYBEB[ħf!,wA\y2]@[N% ~sn< GO1k*{ ϐ9N71n,]@aD @2b --xe3v"Ӟ`?=zէc}j-ױQ,zK?ӛ 7Q2%ɕXfnz4a%5y(1jOȧz/,rLqSy>q7`(>ZuHؐF\-t{席VQ$` \Ma,e'O픁r]EN+vR"4z{ 2mJVmVhjF,<d5S#8\o H.e('ϩX*تRm ioge$CwSOD5p^k|w[ş8^M2Ys8O#P2Eըb`FeY1#V= \S+j4ʍѷ{Q(\hU!LJ̵ٵvPG!&@f4No2JM 2%6t^K0Zdx\vdDDCrlڤȏ>מ%Qa>7q3遙1R͉u`C-o|2l]:8wsL 6TpX*`MB3PV/xޚJHY/Ӛ&~q}13FBoO2>)qIF<M[c gdϠxDXBXQM"{tEb6- Dv}dxS_c~SO+wGPEp nͳ>GP/Zcޠu63EFT OR/Uνg `, !{@^囉I18ݹ)  'sEOqLrZ•jL9|e4 c)!Ϩ.{H )=.dl C 3t.[]C/C@!~s皱>+W1~EH8TFtFoqQ9I9AnGf."%"hd#35r_xjdDؽ %f 'j:T^ߎg|(|*1[0$`3a|ɒ0KPIկD3h!ֆKuo7ՅZC!u)ntؼg@^g+Rע%̘APv/Xl+1g!r@ ]f7C7& NxOt> oP*S[ *I'S5}/m_Qfg:ؔ-6j,fK\t3WG+^lǓo:>M,GEK<)o~QtV67>&[fJX38'q;D`+X䇵˭ncb{.Ԍ~(gzmWq\O)A0IpcVfBi z`tL1W8XhmDc(G#񴦈!n7OCSNH[7'e>48 V($:|wj\M*- @|o{WXu^w ΛݒM<Rular[P xNi]mJ±"/4Aac^D)CJBo cY>xα>T*RU ,W}йb0wUmwO)'+,O nУFyҙ\ yxZ*D'įxd :v s Gt##x8fWt8]3~fpէ, b2)A$" N1f*cj;(nCB=i-m IGB7[IC kN% RHvAnyipnL3mds[֮=Ʋu)Fv0* [z+VK ~?/IQ[WR漓xCOT]LRm=2lΣϗ'Mt Q/0M5j znf\$Xaxjn-+mxPր}BsLOW5y5:RKROx@Dt~I]Ê|e6|1&!ݱe,I# k^/#\^)Xo7xakK0&tƆVi0{hX)Eaq FXۅF gy_ tn1ngBcy5Bxܓ4~L-=Y2u _ +(QؑCmJ`nWfn|6z~ɫqO{U_]DyDJ^a$rMpܔ=ϹE1b|rdOIm]m-х1_B!p8q쌓,t_Bxj6列fwBJU&AC6gٍ̪GńraHy85U}l"bS8O`#I(uʳI (c̵O.ߡRr9!@S(۾m5Av~Sٱb=VxKYOkѵ)p.p~f4cO+ 0h>S&Jzhcɣq*+l&SB^n{9viGR0yͫR( eY?7uB?IG7!8{Jc<О% nH!{<lrNC K>-FY>j) N5A]_Қ5Bx vY:c I uFU8!'b ߘrp[>vo!k {莦`2VǠAfn\x5 >4>xS.md :a7&v&Seg7x1?sfީo}2M{yyh/ }!H"T~5qs\2g+(]z8H28 ,uw!=G0vIB}']/ѷuYEi?rxx ?eV-l&^:㲳1Ofp_D> GT?{QZ7P`QCrzB\Ƭ,pb7xyIc!8;KiA0;R%f`tn u 6A.)${3L ó=A! k;y  .83Gx&ЀǸގws`)O;Od |M)F=jbOhI#.{'F6O0({pyW.rMDגo/eD҃RS`-Ӕl##7Y+A?XM>}Sd<@'0W?zƓ)tڑnPR7IR(ƳYss3 m(eO,{౮-+sۨ{\Iz)?>k$S1_~}9 R}vӒf)mnb!oLudmY)g>"(lVQQ (y+]hل څ^1 )K`9!'K+.V$Qlgn q8.ZKo՛K9ZoFK3?$Zc9A/y[|6JP,R2>Gi otw#8}j@iS4 d!#,OQwQ,W-w A/ht%O>OMҭ.XUD9 |A$q' nq>U}.Edl7zM3jED^n)+6;Ze`=*k5ӅDf} TV'z|cZU(]J/L:/Mt+ExfkV1/Q7 /OH$d ՓFS(Obg bopҸp" 8|^"C#@F;K} QS܍v|b0qޑgqf\+40ɁV$0 yq)v8y"FKHoHx9ϊ cړ4<` IG5q;e^>r-op,T?*$KH K'(?tNQ=fӔ$1#dZP9,hHPJ]|ƃڳb#Z 7%j&Qf!i>KEPyAVAw -u3ބ2%2$㚢T-?A;g?XrEc?ɓvO#6qvQ$`v 7$g RI> Xy0*83蔁r+ ]FkuػY@InF])&gt+).yhy6qѵ)p=a0L#? G%AFx<0XO&`F祟Js[-1+Ma!L@\*}.Fm1:a l~qٝ-P +V¶"apj5cƔ'^yyB}d.Dx<,޾C깧K7QS8KQytyEA2%=ؒw).~1ޖ$'] ^4;x4q\yy7N73v7##Ґf0=ýĭbk:o:\5s )6d$1(AyǯwDc'NGV(`@]w)|[}s%rMܕa-]l{+ƴm~BԄE.ܔ{ XkX78ށA,aJJ&=r)A0 [%Lh8@Nb15pI9cn? _ʆ`IK +,C"+ŌH(W;̥iGՑZ^ }`lO:NtXEsmt\#Nr6WiD05N)1 a24HИn[% yQP#/ -y'XQu=(V CĬ^~p6/†; !?OqjyrcmgR~yW SB|8T0V N=->_wU 4(FMKS3\0O.ICTMZԎ&njv[9nb) B au˕bt%An:m/KApP$bFV㝳)y*K~A h̎jcnA}amXAy8ehz钐~M劔( vGl%f+R+W^)r!@S!^ UC;۵ f1Z4t~Fu F'B ^(fᖹ_ K+6]+\Zk,0zWvkjRgmk^?U'yn ~^⬬m#H Ldآ;ri(Ͷ/mR΋/{?]]%u^hMqF]= RguPfW˻f`"Ӛ犼23cXl ;WNbZ:$e}]HhD<)HJjyĄjOؾyQKL2]Ka>!4r@xtaw7r(SX 25pB#.iAmy GEJXx1m# B]V(/V[AŖ6OB@"1+k-%ȓ> Qd>yP}V_H=X[^ uBfB?8J_.y/NsEI52?05Ƨߪ'X\ nW)rڄBJ/d8s, >vuȺ4Jm쳜r3OΩ 42*c`8=3NE&mLУ[XM ]B:~IdS&[&OBA;ePx֪OnäfA[g 8ԥ*{pRmFDo֊c ݓ `O+`dThJI ;RƲ8W3Ç.4[Yl⵼p7'B\l {;>\tO@IDAT?NRĤ!dA +tyy¼I ?6Ol_?a=&;esݽ3nw }mMѰ߼0FX[9k3=*B7A&q_6ާ κ1G3k ={9!1ªn1J?mxӛV-q jr31(۟'BKnt"G5BҪdqN Xrx' @[!! {4BzʩNN))6jb %>Xvy3-KK:tw]h5acDޢߏoSxwS^Ow i[(EHWF'#soY<",\=.vnȔYFibp3^<"Ei5nn9MT3Sm8|Si &r% -ۉ( 1RBiR3x<R9bJ0g4^w+D9/rKjQApJ` UcWf]`1Ԯ 5swzbɝ%SH^^_ +ܦoo̻O/R[fC"ʧV)G9al5PP n((Mc($PaQ8AvOOEO]SrѪ&_|qrUpJA|6&\Lycd>Hcx"qG~ijC94b#.,($07 %#P 0"YIx'J#U~sw厎fĔC)rqs n#Ċ\魛-,) Buy 4b-z-I[#5/d^~$fW]hrep<=/]iRN(JCMѤ!J BqpEypk嶷rQ^D7k +*,Myt)R-3U{~yVj˰aa=]aW!+&жuQ5I=ƝޟV5bPgǪj\}G\x~ئD$wz*CJ`J<ʅjS(3SAfczrwSC{B$Y[f~.RZOA6_JGq* @shv8odCVbp='uk6l/9r3ͽ/<:7E>5L.' 9 ^Gh h"D]n܏dלmcn<ѭ18 P85N7d,A6+]-V(4Nji;+&0H]w )+ fW İmLD$pan5#(.$1C|}B'bHam7l$m$k+Ġ-' 10 Ôw~=X|F)A|! )[1\cݹwPH:y&e@'tk}K-wML&<4;:Zl .͌&7<ҪZ9E7ţ!6p4`H]" e a^w#~ʸR!s*ɥȎ#*Z{2GQjnԿ5mWADO,9ԇ'`95]>lby ʳ/K[ї9ZѶ%dp iq꜂!I_ۇv]i?w_{S?j2pw-DڳB^#&=bb^H)rj/Oj{Є]}n2@9 E4ޞ"1<™L#3+GeL+# Ea}If^7t=k<53xCgRS&۔i^Їq*E/M(M"/V]J=+#^isrX]Q݄H`:kڅUYt>ۜᆠln!<,Q4ԁx^N<óhLX~_7>H-x '>Ju qBxO?AJ h.}&7>rn@"^NĜyw»zy*,VP:#N䓘UPMkY1s ڎ ]y7@5I[2ERt?:&< (Tܗ+S0?㓛PqӲ`8e˾"ٸY:!+5A;k2mBcZTxo6a^yj8]RfPԄwo (ᅅEb{?X.L.8MNry{kƤh< CN*jz03 vq& {B<]53?|ȘfzyD6wb\iRYg _e˖ӭS#JFSǃ4vJf" RU@q-oiW+0)`|40¬ERk~gbY8*6ǴS5r^fӧBexSv9µ|~Te =fh .XlFn[m|e&g ccǫR| Gn_nw]Jy+`ˏ:S7fK;Gf(>Jvvn:%K\遞╒o_m@IvbYy {?9YPW^ǹy4oB  6<=R L/յX5H'5`1֍B{^f @r,lP$H~˶AjGdRU'ASxȷ#^tfeS],/ig{FW#LWnÔ0`SƢB|`0m<U^kk4у?[I8:x20To6FҁL21 RB* m6 DOq;q&arVi C0p|ZS=X{*Ss[fI.gu9I&Ę3etYR<};Qjm1 `kYm7L#_crGИ]1"Ζp\80bBtmM}~t8g208|*u(R 9!acTcpMgY&X'ϔ^2B)S4_7Va2$RSXRﮞq, PK>B?<'){8ƍi_W틜] ]{k7~YWSHٶBPH.<TH?'WʬF!)\mw֬% ^\ȋ5ȄQl\op\N;ʍdLXٱ≽TW {LRTV/_S<|LBjrVHOx w;P/#WAgSlY!lo>%l=3<%K4ZWPG+奬rה Xx2x _u<0Rr"6i&k"}.W+(!O5}ysQ\iLko)2] BXYaq;Dr.wygc ) 7hڿ,ۛ%}#`R'-h6L#+LKYKƴ^h~$y2(e>Xe9CCrF _ &3Wɂ[hgヌ*c|}Q1,+n(|1axFN5Ͷ]ҨFpzkGǠ6 VT<_l^~|ّ/G-ZBѫڌ 6HaRw dy]5O*܇uYx@  7,& K/Lѿ)E3cCXO2x2 tvc'c*_JZ)h#X'z?5Oj<٪1:#x36e jZǿ-/_3;sN'&ExXNj/8),f{2mr- xb5')0 2Qbٝ8y .oK gbohϓDgB@&Zb6&ymBsc3}zSN$rmh; OE&c +BRM`7OJQC 1J`-7 z_RGu*RNCFzĈPl CTB`rEl['XgXjKWEO]r0V4~ߝR ia=9tG/1C$=mBF"@Q”=ށykKRHܑotMG*[J݅9p_:J웣hBA5 }t⣹A-ώjnp7 V;gpɫ<I}Tz>e嫝?Vݬ \=Qa^zڹoP!OؖN_,BH.7a )rB'4t{NHX >hfb(BkP{{* +%)4`Ro olϵv/ӣ0(cz?la"<@ʻY~ᩑ?Ͷϐ Q`DdE:7= E}sE-Oq@0Œby >gGs'# 3S)xSJBx?D,<˶{v 9 ̰0pS, #g9YhW<l:32p:ko2@ה6+β6#'m 'N+@6fNNOvoead4uCV?ǢEPzя5q끔F >S6+IhRs']Rm\QF;ܗyᣆq_f)$9swm@ S2DuAhѻzlMGK&&"'uʞDlj ̥<&g&&?~ L;Xn ֚COP`X'^'ӟK~|;I{fTVw(I`¬DEeyW6;F[xSLCm=aTtZ"1p{أ2rTk0D_Ar(Ǜ>"U@RF\ZuԂO~RryBpnCgx|%o9f@zWw=*2)Ѹ䋝53h`X q"$d܏ķ5~ٮZB-"$sZq\܄%=#dK\P!K=;9mMu 3-hyfшZ˸#9[4 > &$ ֽԧ1tq7I@p[x3 ³n?s|y&4Z9#zq6v3PB?›Dtdʉ2V'by <6 E`yS;k㳜_S$6eѝN쳮BZ69e e{4p1ΤL1y/[q ylla{•eW5~-j愦V), - ڟ>xV4v?SZ5 Cw8`4c Q:.J22 ZoBIRxH޻>:YE)3vDGA_ nu΄#Y:Clh +g`4E5+qna˷+mJ!q5 Cf xկ[MJ9%)B}包vdoGͪ#' T+Κ_|(4vTة \Ϳ&{lEǽu@7OPǼO7`GM;uR TD~?f2e ] 0̕6F X«ǀx`˞hZwH J-3xU?z|x04DMrZ8ܣsiTty !F­68̂0t~&!Zgq "'cv.ВR;Y#Is":rӼK J_BKK:4dv4[ l,)$njn}Ͷayʢ?.e1""*n)AAN$8Nڵ4kj{E%l bڭ(7(Οf\MYm¦dofvОg E m2kԌ,I{t\IM \G;8=|#bƬ#)Y~ p'hWFL詌r?p͵z2wAvd儯qb '8#7'Ɋ|_;g1%3wwaapOFI>% 6}{0~HPjp$Kl 0|2DG 9hF1^NezH^23V;ʠu[mk 10УvvFżòX6N1&KZ" \BFp9QuI$ ?`l4ܹQDŽm9k\ybg){u" w#6.bo+_`*c8uĄk5{ve'ekӻE+1gW(~K%\ًjB'+K(g8^ um 5c_7:*)TBR z<9Ym#6&0iLz쳈 n~כȥjMLeOu[5nlx C\pU@bGDqܳ"&iŕc5dV+JlXѵß+'k1킟Ҳ8(6gEe`]5ئ43ƬΔlF_,XڗrM"~n)5^4k%q%qHɁzJܐ.uhsw:f6FSتAaQ2w"ɂ-lY$4\\_~n̩c0 bsRp; p U`PV/#<@o'Sڎ)$)"g炞o0 G߽ >3D3ŀlKIϪ(.q!e5wlbmF-Psm rRY(~Lr /ĄT:JƐFN1vS6`3:aE2r㠂,<͚M b F4 #@%@ bZ&s%빩L>Wu]8rϸ&Be4ѿy&5q<6Gz5}Pbv3+\>zuܩާzufZ|o]$| ZG~S1%%VQ!k?eMyǟh.zdI_4h43.W;%&%C>לQ-XM)Z`.&楶 F*Ku۝bIKmEeU\ vb~ y4 +A}R Q}XBtl# %HTV{D(g1bh(OSe] 9gV+E8\u5p}i115WS) Oi߸eu.q856ua ,OiB4R>V.wlP/b`Bԋv|:P1+F#L|R^h+ESuk9&(Rrǰ ǣy t[yv&}! hWLftj Se7,[f(aQqtC)v.ns(F1YNXS`.G\U`X4DD{lJY>{sVجEtp42% ,`y8FYx]GI|zPO-\,0Z&Icv[0D.}VDE4/;KiKw1h-S߹`ӏ&06Gޮ h1[,.+ 7ef3*}5ݜy|YH7׽}GNN\"2XKI#P uL ؃%D8¡̕(et%<`\1V_%h4ʏ:w:bFBY %B"`O7HeJLSq!fX:LJGOSؖ#-5aeЈ$,&՞U$ue} q%BD_胷%^ %|'(ƴ+fkaH*ݎ `9)IH'ّ,nJC}Zftqayøi9m * UӂUߙ :h"6Mױ1qS\iDědAތD"xs˞CF?LYon` 3gy >;bY"{d-)I5M^cpHG#7o_]$E3ٷMIyG;lbի QsS_(uT<\i#]t)aY6ѲP8u~b:^U'5+7,a;Olm 3,b1:PkI[HѾ}z%fM:}vF:Z-|IX5fL1d >Gi"H1 cVR\0k 1j(3*fk-6CCFhe ޝ eY& MBp,cNcdǃ֘Nh1c[! cCz b Su8쮰p j1v]c 9sr?fm2a H׳qQ:q1.)bfx3\F<VLj f oKJ};C-acsF9-M~JtևGet{kٶ`ТCqza; GkKCZV'{w7?p$Y AvuȀ<x<"NKC`XiaZwL!!R 4"5,ۘm4DZ[D.;SraiVOL$&fڵ s bij[&-)A8BBthm\}O(6B`#hV~نjFb5"r% 4J'@IDATe WUXތ{s h.[AsNC T$Yc {o i:jh7qt LNl] Bp`_F`]\ ];ά4\|qRA~4qɖ(Ų0$<=,.+ӵ}_9kjO.>ef&GkG| _aҿ}}S$NgVCY][Xp6x ˯$_n8jYkm-8BohG4SiML_E60i'ȥ0gBjl9![:6Gy^s,Ήf:VQ?\iSD.D7@Rj]r?,2* hw ֞CNfP ٬ klpEؾvYYTӼ6c!o34c8r \&}TwnpΊ;]ɂ&4˲})pt'wщ p?}?1K>1NH`'(,Be)w +\3<)Lm[.[z{\:'ݙ券SҐ1xo,іDTjG-pJ"qv|0{Lj ]ẻpŧVW? \S͒|p`M[Laa'(aY,{[ bL)FfR׆}`^A͂mE. %›uF`߽5"6N ڡsUY+٦sٜS{La|UCk?A`e㒉ગY2IƄYȻ,0"ZɊDCۆ|83yH63M_T\MYa-y Ţ@ ^PF,,b[v|ՆXyf.w1ꗧXx/ה5AckF,@bP4ګ,,MLQC=EfRmW0Zy85MiI~Cz) ûh*QLzWu.ZE󶪷xi )(BrhDot8w/fYV+L1@s_)3- ;BmʇPG]b]hiEW1 gGZ2p KǷ :7Qe1{t,']qRv0xx?j{nҶ60\B#<:ɂ.>K;&el`t4YpvGPÔ!2v[xYh-':qI-hMHFd&«]H;VdX22S}ت6f®>*(py $tu6 (c-Y p)G(U։WVԭ5|:Z9|+g:@ Vդ& q ,J )']G77xJ/~sDZ{1C|\3keύbjdQ8\%R`eCz0s>]t7zM )DžQҾ<6)%!`ڽkd&փgD뙿eW@]~a} o-8iK_[ngve^|b3ƹǃC4缦D/Kp]=w팰~t)4;UvDtBtG1e\]iJ] m.c9C:lƂx0Ƅ+uy,QuCӹg7IAxmpN٬z]jtLzv "ѣWWp zkB`b,E%\'@3UaJ@ :OaʪJ?k2.+4&hS=S2]hl\ܔָb?Lp[F{O\`]C)> e09e$IN&$,!lPԝZ+\"sR޶&o|IAqЗܲ|U&Nwcopח1˜[' ~;vryq|LkeEwS_ƮEЀ:L !ti#˝`άv~s)Zfwi۬^lIUnTpر4]m#nɢKi}VT6#(xQNpx̕ӓ:wj 1ӎۮI,L bCz9w_d&Ye8hW!j7cO_tTX*a:u,x\'ޘeK o>f xLh,U$'6KRĤä q0|1݊YCajzTʆQ7psgWѕl,&?G;|/SlSeɂ|Hsv.ws&h=V`7mr ]mquK&<b@>5ŴANe[tvԋvaLWmăTRgBDh7wgs1rCcxΕ f=qmve= ,g)Snf[c;f:l#7d$lq.ݬƔո2Δ7VVVU .)gpcꞀۭ~%hdSWhhk2!H,RWli1za}CZ%F%{JNlDzbV|*k( 6ѕ:ZeQ(9 V1gU+IeޟRqUNPٸm~I '1&cyBV!6]׃WH8u @N1OLjnZM Ջ J';@i$ds% gj\+5\MUr*:&X07%}'_qk28x {7{\:%R[lx1Kɋ(%m_]̮bo3cm}>9hLh" EƁM}o!?ZˮI4s'2Wݧ)ַ<ub~Oa6lv8n[ЦRfAG(1d_%'8H<%"l;y  ', K\𒂮AsDL9@x;+F?^Wo:5JPn/P䲧0Y($PbE:)ZpR>?M}~0ًpNHFEq!EoIro Nvpsj"4jmsK?${.C3ZrhYy7'#Ƥ3'5ݢ3c[›Piuh2z>ebL&>M ɉfD_]BE0KUbr^E֛z9f,h?=l{eS]{{H`O ]չm{SMsnH,܉τgDJ'&0sAu̲ۙo F[Eh:8 ƚ ,@ yl˪9xhVaqYw{\u10cE1W ld=-u36j-֮oj3=^IK \CЦ@s2?b%f8fդ[PK#TtZ-E\ɡ\Mcb%ﲟ, sr;ssC7jJ%K7Yo2ӯ24UOx~#,s%#j@#:av\jjٿb La[SÝ\qV f9T׆Ztxte '(*~xg@Qn.>l+S+e_|ȪhVn0M[r|d 5 pL/wہy #ϱ|[k.זn"eRXb~<`h Dı kK 8tbM;jgP!X\IÐiX\ɍy!d'#vo.0)ݬa_/Dqdx}W()$45 ga~ca;v]ѩAB$Ĭv#੢C.^tB;~I, ~"] %`W{#\13{TvZB7w\_9;}kjz/W"J')p~BctKdRuʧG~r܍@0{Ge' s1֔e1C+`ȬYT@ 5q:dGō7r2Sxׂ *d,+arS7YGDdk,$A)ªVh#}Ds nO7`3L,㬍z٘jVcM]n ì1)Bky^2nOɐ#+4>Ϩ)Z@qWͲFfZ:hha jDD6AiiVpdɸSWLr}`-4UحRl+w.}$,R2~_ ]XԧYƠt15@EƔ% 4׶WpCYD; DS^M}Ǿ7\–\Xj _CKvk {/t{(W bguSִíaZ嚦2R~asG78KX U`Fz)d/+˦ke/`XgiX ouZî3Pr}&M 0`5 $MBy|qtf(Ȟȭش_.~_$xbڜ 5A) \}.<.{GxmSY9‹A>."aH:7]}B%lׄX=cgd/ : DŽ0:V: # teL+RF15U0Q'~UpTWٮ "3V<2yEDAf@ h\LCɠ1@,XřUqލLU3aȹwrU-Ū!F&?٫URQV)(n*X0Q/Dwqp0c6hٿQk‡{liۧ0h B}OgM Moދ$G4aBR;Eb | NJj 8[FxAol9!ݔj7$7fT[Hw)dSW͉jDBp+#ܧ{lģ˷, |& Eʹ-cZUgwsK̳7\Þ="Ц6xJBD~> Sgz˶X^EJ5wL:70[`]j3R9B/GnDD#c m9K# 麶n`qo)J1vA!YDT`)Fn3+).Mmk=}e&p0MWuMʔ9vxޘ7Ÿ!Lqvqc_,z? /p1v,hK \~6EЊu?L4'=ϻ>0fFXpXhunJ0{rtM]ˊjs? D?BX{h/- @8n^c\Q QxK 81[ö6#6EMq1z:1!8{z'VY1u}`c*VpMs/T;w5Hb3+Յۯ'z/tml,'\e#o&A=K`u]G2DuM 'ڟ0=|Yma*/R.b: $[7|=`мk/֊-c_;k) B!A`U+TDqѴ^)XdR A[f/>6+ɮ^IșZJ ,\^BUq?Et~5i8aW? ig*sr3%]PYEe7q K>*5vDz 5c\OB $vSnuBēWEs/zGD̄0,cEV3mps"EH8=RC:3L-)( MBwSSG Y'F'LMXO9e>I4F~5dPi;:zmlfVOE= k,璬k[} Mi-g7`q}q Ŧ&ơ^}\c؄']=~iKǗnxa` Q) $8}=fI"Irp>uy.su,LhOVӯ0[H:.SByZ,s{RD163~a;4x-9$`RW?Zsb|.cP>MFc}7=$ ZLf,=$Sj qJ<#Vw,q-Qq 4fw)`(LȌȵjA$PW r ?Eǃ g b9&d4cb1R䕖TEײVd(BBjh^IS xٸn!FVO:TW"Y'OqўV DߒYJ=KC`1>b>L=(0⏉vt mCvdQFE/56Y ]n]fM"DmNq~iN Y(+q8_q=#E8 vؔϹ!c6 m585IVy oBஜ$l=Q#S|BovsT[Tm2!mѮK׵"tc&-a]O#[%O Θ-qa>s{n],%m`[}KGJ/0 ]X@mۏ>YBmɏs P"xF h~؍iʐ zDD\Y1!C@1Ap^.qj+\Ѹ[\B!}E8kpŤDJGFhYšnX|=2DVtINR.2mV2Gd A1lD)f~sd7՜b.CSfp= iIFΊs}YֱdO<r\)FhY erY%Q1 4cx01"HYPZ5',]*!@x`} n9>Y#˴%),Q_1FlmZY97bzD|_B\o1-VO3zaM9~̀Dn-'*LvSv}[),AD=2ǁ%繟$ բl`a…@};0mgEz J`ep1NϞdLuG#JTOȌ;~ꝍ6VA0oWpuQbո Ѡ~,0:;U@ilt۶>l5PJQ {^! :- g75#>7θcHvUвS#kwD&(hY [% =\F+$X=*_7]` @Y} Q ֣n:L bMuQb oՊ("k̚ Vn 7M;{la%idj40X0Op73V+ g؋#sQ5&"$Kf{)C#`YtaAm\ zP"unqeM9q((%*Gvqc&ůO6Bx+p6fQ|Sas1O1IEi!uJq- f67efj!Oc0+ UQnb%7nZfRXJqeyxqSpk,c()m?vq͗LXhJxCyQXsq6)&8 Հ7լLH:pꙉQxǔyJV(mN y|KL'm,iI3մ},s#r,;l_x2zۮyadטZ6Jg"Iz=v1CQhq Hyc~ƒͻqfn1Φbm;2Mߎta" aPyO3 iILae#j@):rxQ %$)h[̪k-)MN@x0

:Dn-wӜЙ8Q?~ OL^Ob ) Z»0+Y>+ܵ\v!Pz} RgQPO)ndhְ /0rMG@;d0_-BQDNddW \"ŞA|,dKySmq`3VNqfj' #ԵG(18 169 7_V粽w31k~o&AVgI&`aJ&8@y) v`1Ya]'sOB z>Y!Rd"xPIPMh`\ ڈ;(lOwWΒ'L|@pWh7Av.4mvW>5X϶w.%,W{˓n in>`5,HrK9]7 ^Pjԋ~ }…@ *L#p>Z0=QAN8-&`mB(0sF͛P`&gTcF$r*j5-2f2Ѵ3-g5 |Ĭ{fG˖ ,e}W}O:vKI%>{5.wp }Xb2)^G m"= I8nBThypcϳ 4,]q\\)DF#Z)SbJ1Z4+  (K^L`zE_EKG5|%6vqU~]ج<ѭeǫ `*YlXely\ }C#/M=4E%wAvn4F Iwti/Kw=MPm >5#!Pܸ!0O.-}pA]/aA 'a ƽmćrsq>&h瞋.wm$i=~,vLwn9W'Bz~V' _/38޵ڹqtInAogZD U|1*mXYb>!X5s!f4xBx%*0|mȬY5`M1ABBy!rpK} uP,! BMUBdg7\Ig}҄}Z%rc&z3,_}+l~,6.[>1x&6ލgOMЬj|+;L1nE삱a˽l&f޻? `]!Kي]#pgבb^hC\Wr ?F(NXkH׮![kd{Vbp:GzabAKe)Vqkׂ%{sb|wev.qW׆1 ަOBڌio%NM)a^0 zJxatuZ|D$g!D=kIlWq^g,9;z>sm8֯p@6\(yf,):gsB`΃tGf# 6A=ث[Ɲu5b\=mC3bwIb_~N $%*M: eX[8/=Oϣa}dÂOi#m-cxyT`bY,Sbl\,<1+cԦDkTBh>ExVGqMj]̊DY6'>Y˘qf=E"L|_mt>ʿ]+J&I ho'&w=꺋xC}؞NKU5hͧ\p|oYK%~cj5kHJc` x iS:).`,QT|&+^945w>o,nUqIӤfNh)Șk< dm.c+zZѲGS:BVz>!d/7˒ξ =Xվ,}K4e0powŒ+rhLi%Zp.)HbK?}0F<7yETO7ԧc]Spҽ6]-`OCKi UP*p U=NL6n?ѽᾝ,5>~XImSjֿO}ݛ oJy]P /_yfSAo?]y]ɡYs8rb~p"uhLUP [_O_պiUU[pS| }.IíM ys~jD鿾`e~kxQ|Ӌ7=N_b5 2fV<oxA+TjOTwUqu׋w3f=1Z~ߵ1U~/$w+g ˷/!>CB&@B?,rνcJ_XpX5/߼;I 񔟾c#^aϿjiַ`nI/o O]\Є_H{00y}b.~??V7{hY7ob˴.KGGw_iıW{M |oş:(*IgYe?oO)kGzWi!FŇ_x1X'H6"/xbL߷KFdm*oR, =Zw\,KM< E5̿_ 4x5c%.ް1W}x?.~GT4ǿ>]oަ\ ڑS|K(׫%)\( ooz 1cAwt0!ͺx<bX+o];_\_SW~xt_ k.#q _~C ,cTn# 1e%z_ pE.&P[Q׭𰳨_#WcVv ~J8F.&}6m2;bފbmAmDo`pMn3pX"Â֝}`%LLr%\_LK)%ʺcF?\2Ѿn߸J> &aψow?Zp4<Ʒ,ş[ mt+&+\v}i5\wW [m;/<*;0g =oOG˖K^}G㒋wEgc]6y8׋6H'窾}M+M 4=Wi}̘ YhqlEJݧq2Ғxc)vm h}c ,ywتnAEOC#2M$-No߾fn nx7)/U'ŇY?$hjD},ydG<7$7mO a4ӝa.&΀MVL8RY|)pBTl?4-VGeD~is{OATafAʨ> ƭpaFT*ob‰S6vB&@*`6W~Ϯ(`eCv_]'‹}6/ hL_2?gnS w} S]~M4~M޿{]2 B" 0` ͫBw 4#$w] Z"ňq1e}D)EM'EsqR`)){C(x'K1va5NYDIWծ۴N<"@$%Dx,GϋaVcs[b?˜D!b@ -t_lA98 IWd޹]s,e„MǕWX7{K?J3%RO!@ir섬st3S܇db4 ų11 0.Xe%QOmDO8e62 |UL*Y~6s0›{Ē- h##S0c_;#Lu /s M)Ѯ'bDq0IH0fc a`r7ജ~.p-@IDAT%"ӮB΢5yM+]Hfҩ+ Ո&he2 `=e=&2{,Ƣʺ қ䯏.8ފjżςq.nAL<Wew2ڗ1q=}ϊa̛Y|U?$(q$ꃕ􃗵m),gR2c75ۑ>jYS&5ktH"Tf8ˮn˜ 8 `xB,;j׭b?r#lhsD7YW,a  Jp  qa'ff7pW93#Y ,߉m><q>fAGigU ݫH uzDe4/8%-f9Y5]nM6&fE{m}>`cxDOVz6[(vX-5˿WvT/1˘/Լ)x3/osv" U•?PƗ)xBShd1GQuXg+:8+]u|D,ڢ`SK*ZrPЌTA⇶n)􈀙̨2(,F EGHbsyD 0,K Y5M0Uq86Z(pr{.뗻?\Y=Ƽ/T&ݦ% ݉|).D>qDvls !9؞uPFΙȄu? #go÷DžƴG% 1?Y𻍦,͗d}eUax(m_ }0D+ oϕ{ꃵxuqP}*+yNl#[o(nyn݇Yh>8_^"qǙ.ƜucFluWup,7bp,UuYs4tEsB[v;ma RH,KP`$X2.uc L! XV|o_FY KU2'f ~Lo)OoYWl\Yv,Ub!^zWA^[J6]qX:ϿLĸ7%&np\r[=$iTp#B›f|a Dႈ%~6M,xqL%}E)˜0'C`=rIu;o5 i$'"\x=RJAžӉX\+m8T銸1)XHJ 1nHuX>T̈j,0S}XY  Jъk*z5^"<(WA~x QY#[N!8) 0-V3eǕ" kZ7?8wZcn7ALBW@b!$+p 7ι6Ro5ri@YCƃym7!;Z(eV} E {?^\bk 8-ҌHX%l]a4Y`bpPi0SKFo6'aEB! ǻw݃ݵ+C w ]2 'K.֫q X/OIሼ@>Z;T t!;ElELk# c 'SڲT:ZL}Ǚ[ wܡ~)XH_!_Z +dn/`ojփ%4ʄy}t}?XDpdaU]#N YDYnee}L`2(BB6t*‘fr/\ Je,7 -B*PNnEq\Ӕ0!+(ADtQ2y|HM-;ݢ{BЋMc>EmQy&RwmB U :f)7+DZbG#7<+xO&{sxxs2(Z"g i%Zq0`\&VSO=,؏N^"KcmXMqUA ,,danlѢc:BJİ`1#ε;//3G;+߹-x!_NPaZxS‚ UQ=ӢTȬ{s%\Z(o5Nˬ]1!z\1}Jx,)Kn:A WdY)]v*,r`> V SGRVO-LTHNxVf~m{uxgFeQBl=2!bHmv23}rc,&hCY2u͂\mq%[di)do db6=/b~LY`z笒DcҲOAޛ /J).EKث7zH%c'<,Y؇;Uc i:X,cՍ0̊G15V03KCⷭA`ī71q(6bK}2UgG ů IJb1l,GLwvRyЦk)%^;1KyZ/Pw8*YP ve]K1ۄVҜ]QT6}>>}sz/OlmsS,k1yo)=|x=T$cVx]ҤقL82MWt"ewϐ Y`=- ۷![;ųJ֔qo}RI:N݈T=-4XHSpO؛JF,Fئ;cav6SeKx.j ŧn[p$\B`Dט 3@"4črVX2y@~Կ~KDD *&cۨ'-,/Yy7OW W4+cv'u!kIA-KKLkb !>j!{UmK`R^mwWp.J*Z% B"dk8[łlDL!vAq *K f̔9c"f:X-܊sEAP/ɦnbȭoQ)G |{QfO0/ \ТV3R! §^+r9ԩ]gcoCx^xQ ($BMe3x)z S{|JEnBt`M!b܂3XSeEOI[XHq#h[+xnR iӔ@ ]gpf@ԂfK($Cƒ­՞,:b#t3U̼r:5VHp ڱH^C2`Y;Ϻ`qef{sB7U=%{f>)~6]J(̋ŲL/ڂKqOKDf#Ͽ1a+IBjf7l\Q Y,Ұ?]_QCeO{Wrք=YkR VD}D Ej/4u|⺩B|4OV$4*ӫ~1a56+fiّU+:sW_!w'[+ϴI?#8t1`bIh@ARS0DmOgSE7`!A;/-.N:fkg ^1_HrRzVR$!m,aU38! g7׊!v LN~I|o,xc}?|Vtv#Xma+%RÉi)+yXY(80#Юnaq\@hY:<;04e BkxŧVr3ܛg?pB)8N_Ó|^VeZ2,+i043b6"(N}wUrv4|{#[a9%6z[@oZf,׹Kٵe5-efbB1CN2 ) V0(#j.?+t-a%<9b.fgSZAU=Oe BLFI7~N}H&1=4MSh(謯ӻ~ GX4Uҿ-OPc4g?'7[)S-!YX1#7"_$D8Rf=:%Lu4+%.bmISs2&\e3J@ϙzګǕRK6Uv,됦yf R%bίLRѝ">Y$BJdF;9piވ0E@`}n3eU b2 )aVeqTIlS8BzjxݰX ,nd|=Ĕr>Q Ka$@l C+;E!1caZ㽴[n^%yOR4UIwc`@6Xos]$ P yN8iwf4DxgefXhl7 f bķyD&!!0a~#8>[IY 'H "cEB oÄ $,J 5-bC {;(l>p[P߼yԻª(% a/(O`G֨(Rf2_gi@rCnZ+Ϡڍ5"P6{"섴Fw[ov5 HA-}犙3$Ÿl{Zgϋ ZMDLnf20n{f^BD:O i3`UR;}na<94"!P_߭mEڌ;M 00]UO IJ N{ gOx"#|ggrp}h\VjNf`P`\&_doJ޵?rq Wh| uI0ao prK`/-A* [)GV|R.>ϖ^ ::7:VEL6 <(PEcn;J[÷ՕpWu'L qs\ӵM.piMr:U!V0RM:))RPP.9Ki0i+YĪqcŮ@ ڒUav[ɽ!koOw-T%P${Oqw8U[pǽ[jgp!L c,Q:gYy j!EǼS;Q `gQ}]Qád}SYk@ XP{^" ~JyIJ/I)>XBE}K+R >h"7IB_G;Ӓn!?0% @jȗpYBTCvh5u?2#| ][ ǐyLBNqr{!Z9B"*@T9kP󋘚4(am6Aچvm{:(9Ka|gܦ(킀3 Lu.ߵ=s3B;g{bwT%)}8||  AJT{.R k3PYN3KhQ17?{ bH$ |.F/[ SpûU٠kl:C+KkB}AL8A.zMb˘&}K"):"@$} 02d8!\JS_c0G0ba6v7Uėb cDu݊VH$7V^,Q­m7,?ɣ~,P {o@eH6?;鑩8QԾlEMva K aelTB/f`BWJʬ }_GDsZJ)7N@"[UE0L1Lt!:ګAuGŊ,ڪaT k8յFJ +4 -M9n|G n%ZĞB״A/TgPGekL='fA -(μ鮍@%H)2?+JX.So°˘|$˝=Ϙ?~1T{+hheuwR)DG3j<JY]Ǘӎ4"0;{k %g]p5qW18[G^nmk)<Pmֈ(p[;=BV.B;K-Ag^GLXnX.-1 ^x>@fDiJzn'萗]~ @C.QC,aE y*W"6P g)cj}.Aꉉehsڏ~(yBcTL @^Ic)qC ƱP{g[JZ(OC H8%;/i jiG쯭BE~mDxY tTFC󱪄'ǝrUp|߈z\,: E"T@bߪ$Оx"u%%3Oc\!>. YɘYaKPǑU$ji It!ifϾJg l+3ɘWH +iZ.3c9/(r[ٝml9~o OZz'~n Ou2Y{W^n\J(oY Rk GTѱk!?Nk“uSx(ű`j48,%W}v{o9@Hr$f^_ I8C1554V9 @1}Oz@: vP̔9?3=LEgi}QbHe?Bn7.ٚ}- = yƒO1 N C(!kBnJvÓVCq QÄs/^KM2 V)*hȊ1{wiXA=*9Qr)7K0\ea[;|>󔫩|-hrwE)=w u뢢?%dG; 6~CofCs{OpƵG V,PM[|AD8)m_.927;= G-}hФL6ҜFEc1ܤJO}p^1W!"c䷪9Ԟ][0 Be3q\ԥ8'Q Né&&}.@wm;:B?T\CB#)'gХ!`Waݖfbpy bCٮ+i= }3B[U ~Arw8[Ȭ^ {`9#ϥb)R fHqKlr"3TȩДɦHhu]uz6 7.K7:<&^@x42 ]A~25&bӕ5Sv˶؆,9_jhdX?6g%d;FVC\)\zex#?rNx1%\|JM1/` \6@E4(;R%m"Y9%Ŝ4${'ST,C̮NyV}:zfjwCtZT\ >x]ʼn <^(xZ=u, bo+gt}||C#ӏVh$@:qE|̟.U-o9&zd{95M: rR|H@l'jD;'8Lא6!dA7C?tUe=_,'3ǭ"Փki!_T689Ebi[1@|%@} W-7 Ԧ XȒ6 Cϝ իW~{ `t;S?PC+s ]l8u@BwV0>KEi;9M@$(i }zRN:y[#iARJ*q2`.1tl>P^5]718i A5㠙^'4[%H9KDR"-]Gmix ݻqE i_ڞ(@j(A+':#bC Zu*NAP@-y #ǹ7AqiCR{֣d]ZELoi^nPh6rd%p֋t3o2$;hdʘ|OpPۊ '̆a@¡xTΎ]/YI$t` NM!5Ӡ8d.9A^3䪘vZCBj$Ck[iU1$ Se)PEP<݌cTCkǿ&DMhkߗh<ƱND ^M_}cMZ3)*Cuȑ'u/K9&|u΢'~lIց Dt@YgU|ra(JEu6zy:8dRW"9iAkAJ? E(Aņ *@Ȧ]%o:)sas$$WߠTú|tn5&'4.c:-ġ >Fvm]{ j \oD|}3"Oxr'2 d ((AD} #ښT`,K?YB nB z@SXLpyBkcWp,VE 2~j`t*kMA*rMDߎwoL0y%됆p ԋ$18(Mlu'Je,aiTiP<wT }Jg\0N69l 1\@qtg IjŌ@feVs>mEIJ7qOqüh5pl<8| k4w);E(.s%E5h0ba>yl-1% #t&L$cVQugMSSliPj>`ym?nROd~ *̕HJt3EWF@0FkҮv/ >sD r"fwA8D h|[qA3sPW ,ʔ+7kH|܎Iۼ4eM# i"SW*k:wMTqQltܮkp{&[ XE LĻ2,|4fIrs{I_@d&!Z@`HmhχVrA`[0۵=`A#F1!7pN;J!"a1{ AZXK [TD3MPp$[M}Nh]/% N0`E\mg(MNdpH =#O`F so@е{?vT f-2{$¿1wZ~bY>%"3eZ֤&|Ui۴Oas'~RYR2<@* HAՈK^2 ^C^\-yfnwHJ}vMme}?Qgi 3u@k}~1vۋ3"NԤ];S["8ZS6j#\-C}*hjJR$&$SU&0 t|Dch5"vE{[y]ȔZC`/ @`\Qb&I*Zr1Y $Fh)Bl} )ٴN९g(/"Ge#Cv9Z1`yUuS Sm .} >|zY,} 7F+-j,Mpk 9DP*$f37 _&p1̃lѭU%K`QR,QfKh s.MhJ{m%TH ; ɣ5V!58;*-Ҝ5Zl𻖭"1&[fXs&s""S}2_0s%`ڡܯ+Bhߢ}M;POwݘW3ݘ1i;aI{oN9~9kfݚUt~-] [FHvmOlXޜϜ@Mb=+s^-/9<bYL&Pdt“Z  -S;="0QM l}|,HRf-: cNUL)B/@I3&]J9H E yocDA84ڿ"1C)C '6.o `k-)pNͯhygVA$)4DaVV4l*{^qoT@Rs|漏 fP| 3Uj,xL|O]/.U+ ΉLH v<ݛ05 Y>LwK68`Rbtڄ%ZξcGW Q,s}L4ZTDlX9'x-a1M3e)m0&]UMԳ;f+nt6]up>T(B02q]O̍a|XU9G/E_ =3ѥs*]6 }|nk}}9 _ʢoA9sAv`eI ޗx U*g6޸_ok/d4 s m"ECT2w;`j50>}> 1&;Leٯ|/BaKWli0geI}_}uN Xߜ$rDFk4X0aKԽzsfʹ+C;(":EC `|Eh]|&c }Ug i dZcM UkKAxז ܃"AEVvXXQ.ÖQO*%֎ E+S\(xnQLUN 5"eJ31ÒX"Z֘5۴b~GVBO*2֖ܲ.ʋ lb!/0kAٜboNsZ{tcf q@-2OBhDeJș>#t{sfΞwb*DdƦ9nڌd3 0ޱ{-x.׆B RRfUx%hYd`0 U_4ik։UN/0P Jq">9aIBv>o)[o^GG|Bj6& A{18D\)BH{~2`R"[sl_p֩HCfc!?ffޤ(BÜ͔tJ i) EV3 <{ wkcaSݣ,#nV]Р?9 "kyE4pgJmR% t]%hc1gXH X `ק"W1x!E̞by(_ȋS`D_ hlj@IDATk`7hF 7Ρam, wVPdX)KK悽P[ВU|6CWRvɫժر 1:|e5JJI[/Ŵd'OQY߃rNm߯GV- 0>cx 4&/ўEt1&P#EO#CQ2U.]){בbm4wK0~F%-aRuT3S͍ik<#D-Lxsh$R |G]]qLq;|h)%XZNǹ6I(w,Blu× YC*g!vp:~ʊ[z!JYmBlP{x#j"\JATZ0"O|b0gf)B&<ѧt=)7F~eW TҶ*76AŽ- (f_0 0BuPփODЁdSHS?Ecq?$4Ipă1;D)Z5o)N7 r5 QR k&4V(B&]@g!5w)e?<ȔnΈArn :@ym|Z^LY 9̮ӏlDd1mͫG`1)ir|F /Sfuj/\n]q=l>XAl99Mp"54CDDM14C"AsE,wٜ/=C)?ybdңJYaM\;>4ѕ/jE$4(K*u Ό PwfGHEy P|BE^)zp eO:mh~hX{X% Cq2)_G%0 7c9EDzf#f ]U9 @x?Wu~QyiKHS@/Мtpkm\lcp $UksDxYB~ͣ:m(X!pX5 }O kF}q Խ4r Cir Kzik :/ӦuCS!=3‘wmKTYJ?߭lc@V[0huB*g!Qq-UǗ* OgbK co s?$tmuܙqPR1O)E/ (ЪحHaE&\$ER3GԎ C!$ q[I ʹ15 n3V#%9]?"y)Ћ@T r|0J$rE.2A&a6}fiC ~YwPk\d Ȳ 7Ɲza)lfKtg84N(1[m=(i^ [RY$}CPėl|4{̎1EvoSRH!ҩyP( @}xN[il?ڷWAN%!!zZq} (F Y,jԐ._"LOB D鵒xWH`H1 תң a!j7#XhACG0 )@Sh!gc)pVξjb{~G%twQ8*>JyHkZyw'@3 cl7.4FZ%'3hua{];ĔeE=le@ak YFDiJ30Fq~ 1U2eBd6 ^1(K_2˳q)8Рܕo{8LJa y}P=}>*W/) ;8d @Y6,@~"#ϕ4<{ ۗOn^aU, l?hmc(âٻ!C { ϱ`]}1Ǘ#%g#$`E8C4qfw#tjxB1Ln@"Plkc(^) tyu,M禄%fk{YL~|f){R9B7nt{Lx` H?_vzZ(/5?K𑢠3ɋU1%DrBPAR (ȩ5يoWr18F|(m-)~pb@m|9@OZ#Eyc 1p1R߭9sX փyr$W RiTςſ?)vOsXD"BC]%Y#ûsL蝒R[@0[D87|fw 7rĶV 9mM{dz3;QjC%s()[2ȾctۤR&Pt'7Uw\m N& hl&YGQ[_J0ߤbN9ô%9k¤0cDcV,%tE7?$_p l,[F D½+fӆ ,=\;ZkBw:JA>:r]4N߼)'B@EǶg#@?`_ظu4&9=`%Q6w7τ3Ri0 1IƱӝӿU,5d,uOh-p͍$8~E$Ju?ѼEgvל5ןSJg h}q)oSlcvLL~#Cqf3iX 1HV;E?jS@7?S%|zV=Kl6L7 d^lc|JƲ)Vk %u]{ =97׈"dN`XW\\4O{lF<sK_Aig8p BP\EPǩހ*[hUHE8Elh9L _ (uL3\5ʜH?aAPWHH}ɍ?3il.DR N;Fc hY9oX,C}JH(D+1:*g$SL43jkd3;a]:gkݧ%) n"،jeY5^Zj&KssFƓ$dBF w`cu'9*l\;WD3sE. )PQE=&%`J~G`t=o 0ZT$;" IFItߤ}.w$SZ 7ٙ@5N }% 󺟐c8C*%AETlGoEҐ ԁԋ.X{Ѐ/Cy?ٷ<󧢧NB$QM@3OO2HKz? \Ld˄`|恁`{,;U!C=" `7p5T_CR&U#jsÅ"vfs.߸VmAVbBdr X.ư"Zv5M}K'Iy$Lx {K;l,6}Pd78< FpnٽhyaI*n1@s%͓u橿4gE a n6nуe]U2^=Yg >3GF^NS*U0ڣ$qnGԵ=7,(8toHEqε$Vw"=C^;7 5&"]2?8NcE[IMl-6ɊPfr @ 뷞lYi#Yb1&sUzTFߝC`6M ' iCML),U{ݏX+ {o C |Z^M_"5Le,eiXffN6pcyY|MءL+5kPmE5u$"@*(DkXh'%|E`U/a*JN ~c J(_Vy2RrBQ4$^˪LR49]Hȍډ::+.|ÑQ$q.,:cfԀi e9[@&w! :"d  45*#Oꋘ<]JTf 1&ks%aMG \Rfb+DS%Yhz*ED@s{MBBai1a4+&܎;RpUs % uj9Dwo=&1cV9'UB%ocHd+‹ySz @I?WYHVU[2|O!,_~IT<-DJiEDG `۷aJ**{eg[eIi F&{&^1cNtH{i7 r .dԞkSM ~BER1dPҏ]1!K8^PvBe\0${ WD@ 73Zl59LzHڒP09 kfrROW2(р~StR@M_TPB 8Z 'DvƍȱjWsɉ}ԯb"(rzRP"k42fB܏\ڍ˻Ay@{hl[ poo"-@W'Cسz4)[h'ФNfWֽU޳^ ɉJMb5v*MO  *H ڻZc42zLZb;k @;$1ˇ |J&aO٩1ԄV!@YKd7ʬYv0VBp2Sؠ9ֹ7㔜2(QgwkE]3_A}9e`dmc+3HBIZ& (lJpFRdx[٦Br>e!0D.h[jju+mD_ "Ƹ''%>'oA=A'YqFh$]gq>X:KgZAcTxIIyളplSN4KW5NZ RK[zh>ܢ%E[}I^WZM:4?LIچiaH xiYЌaM8u`e@krqy"_QDYQeS{}fr? Ftϫ[z#ƕ T)Bņ4q4= ڄ/uZzb|ʿ$+ւW-I!g9`-k()tSP|FhhVO8|jHZ{P4K3AjK| ߊO9zz:@^i@3_'>m ϶&oHp b/'f{ /%FbQ>ߍy12MхEՃᝯWILZz7$ ZaܯUB7fi2̃ [<2ȾyKvmhKJ`}=S9uL̍E ܃*[~t w拠-m|GY}ݳRdT bV=A> xE"(R7!r-!Ν+?T$A`K|M§7m7-}n#: 6<*}(h,[Ù,["V НYCk>r2NOiqhu&6@E2 %"Y1h9iWG;\9P2 t 2ƈ|G  E9<Ӽ-{iHeiI咠KWZfGWtuO,Y^m,BGۑ|؇~L+!`ʹ'prr5!?:G㇠pW;g W窱Y;B:7sȨJq=^%? 38E8JQُFgS\9\#1]|&~C!bhT: gIN~pZ~|": jH$5!Y_ՇA4@>N@,cC{%#6eF\! "]L W!=].c冹\|&r:ՖoR#<") Q/ԇ uiJt4guOvV]/XnQr%$C_eS3`)Ǖ@hOt/mD+)$sh8>؂>k|7J2#?b}cY:Ϟur)~lʄarYfBpQQ}Bu[ʆ)2A!K˘c v713E~Ōn3!t=eaJI&7įh ?a]|Ɵp[D4TrdWZ0Z!=6-goY YrLOTЁLTi ]X}'ԟoV:ĞX |U&vg6Eg ,}p h Eʹ]UzN@ނ+ФU E+!t3)6_-V jqm"LH!hO9L 1@rH bY _{-VF_X=O<SkMH BϡaeEi44F#^֚(۵KDY}^m3}B K}(bR3C/vAa^yxB&QeKShyGHMfg4Nk"kcaI_ӾؖӾ+/ʥ) >+ jȹ!dQkuv?%LH?$"+LUq&A:B$ WH9Bh N iE&ŔKrͬf (o4Aa# 1Dtk@r|01!` YT{\ hIrh1Gʉ) P}K6F|oZ f|2| \Ohe̎^筜#;5{qt Ld.FD ) -__$~~IX@~o\BcMnP!\1" &'CW$JO>NXE!_3IgP; ј؟l6 s-͢rm4x<'N 7QgևU ^4DhtH9"*"1DIgQ"p%O[o_[I&f&{ f8T)ogN֟Y UjM#*fFl1y l}~kQC˿pEEjT >}F)~^@x쭐8AS=mZ8gC|jxKG_%2åz]Co15h̞u0&P x!v"ƾS;jHtD#y&e@w(41mABZu~"8%F!A>J 'iKPmzBՅ3 &#!95wJgz!* *t>rI<뤋s/O'55߯4_X E? 2@S\6#?ܓbN-cUҏі)4"Rp;[Il|Ms>>-cׄ*^?JCn˜SÛffm oE >g9vQV: Ml_r씛a#HI]dӞ& ;v\=<8ΰ%NE@wK0@#y8d΀NT"c1.8m.^K0J$5XN/fIo 1tR~*3(MR4B(s-R9)6Qn9Zr˄qY=43 2eBZ\Z@Kwd-o(r_(Ǘ"dA+ċ"ƬIyXkb7 5jab{gk k0gI Hs@IA{ŎDfM VEЖ@0R j(Aà&@؎6j`r;叙昑Jh1]t) V*/@i ]/hP`pkM{tLS`U7RgUΊф"d~>jo>k|1t)kZ|ߧ+hLҾq @Q!4w59yːli#-6Bo0Bi(blgH)lp2͛Ƹgv=_mq0@c=FK;q*";LVbc{ԙ/@b$i[ǼF B;7>$Ц|7AD #rYtWDRH3.0iLyЙK)r{ A)̂mڇ+^{4 8ݧ uzڱq8T*~\b][똀 l_i$$ ˭?'+˭st. x4|ZĒh(p7.~fti5Mb/qT"cK%%Pua&k iB5g?ND(`JO3bO%ڡUB/c Lo52d:EXZfs}G\AB%|Cg CV)RQa+M%Gi*z1<+xճ(\C=-E؟s(JG; 3}IUNHf:IJϞ7Ξ+k5(0l 5#<8DnC˷*J8%$P} -!&e嘇 MZ-CL+%PL5;5@XS6ѕ:!I~_$C}GTB-ԧk A,m4]PJ/ A[>ߥG/E%MY'aѯB 8ͅyVwF?%d!ݸ *Yx^mJeSg@@{0 s@D{|J[쐳DkCS$!-M(? Z,Js.;>$x\_~oH8n8C4`Ilnk3fP̆.HEh=;I ٪Fkjz uo6F1TPs]ic#\%b|wLm 0Ӄ~ bbLPj{)\85G{!⓲(S\h4\T{^;f^ֆ@ϛ_NɸԴM(9K:)T-Z,!g ˓~ES @$8O&4[/Qhņ@:0"'D}faaK*cpWO"0tzG!=5s ӽe>K=F(&N|BzAeLU.$` /O0+ xBcv7?B@k 0z3@n뭄q|Kڪc&@_-T`DLl4<5 DHv)ߟoO!T#("\ )3(.7S:%xTx'9 }Gܵ5FB6Ui E[8چj!#'!,~FA)1%o崎 (*$ _$/n;Ԃzhb;B|]!d 6f ^B&C [|"^l^:ZHi08äp?j[Uȣ*Fj~J={C1Bhċv~{qeu'VC ,V] :ne h`zP5!ͣߣIgZP&لui /EG_.Yd]sCXhvkG* ^`2ԠwUQ5rl}MY:b4h1:8CA;;~# G5zaM1NbAIc{dmR3 9L03ᆭR_1?_b$*fooD]]Ah*0G~9շ6D@`R-1?h!7ɲ8T;c e  QB9Au^̄ oedX㇪k&:dB[gc! =&t%I(UX6yE^93)|> 8Aݱ ɝM6i 2ȘPi)B˳*Tp&T-TGw7V.D6ؘño 4INeZff2b9%phh5w%I.IFUpX&؈MP X"E ) ߛAiG+FE(IUL7c 굉v@tߍWW?!YQ=aj/ D"r]m͓ IxO,|З\Z'?tG FcNEHfCA߆:5$„ Ghs,Z`/A$YچjJ3>  [[;U5'T?61AOsH3-QٻĽS";n,ЈIyo_3iץ9[kL4sAM~lf@pgm9Sm }5q)qQ<~Ԋ &7I{9|5Zʪ9za9q\߄NzycT$0] 4֕u?zk&]BqLΥ6E/kvס+EYY\j ÁF?0/޽^Lt",XEKLb%rI$EوwSA>'l˯;?s6'z`b5\Se^)S81d;ovhhǼ ,ڜcHќF'Pk(=2GL@CuE%h pk%ztAM<X gK̜>Ta'45-ݪg`-e!RTc Y׸J{ ў__RJ=o5eknCJ uB7. DtUrm,q1 AA|"iMH44|GK SױNƝ?<Re ^^t#.a%@e 2fY*d!s,^E2NhK >I|/϶iKL[ $/p鮱0K&V!: dyHG˜ocKT$Pt|Yjf\g{'P_stÁsxjvY Bs|A yʣmªRj߹ҪIp%w )*?ڿu)$H=)qL7 3OnHBZ-H&D Fd&hZig`ߦtR؅VLQfAtΡ Ad"CzA4&_ [Di1S8g^)s<&(82Ά3Y16`+e:p6̶ S& FBLJsQPtZ3 Gi xf$x[#O7pM 65Y1" 8@6^z ":PYm|wlX@+MTzeqޛ"< gØߺ1ad!UnDx :ރsAMh'v`Qף9By㝏ט-[Ҳ5@%!a{1*%C9-sI~Ƙ}O%WC=78ztCP&|Ÿ3rs?IZ6tB!}>Rwǃ"PlKj`H 4M=B@hbģru-wGPΑvHmi-oQVICP,$X@ N;!T8yך|ސlz \tHc"?i,=/llx2 k@(%)7@7K:99s\_&H՚PgQX)u9Anޫce*;$ j>2HYywFtk AO)2*!(bqԶ!2t1z^'_09)->.A5]x%poB𖂍?5D9g9d jCdȉ} h5ztKNcV=.CP "H%8dTZ ԰ !hz]ۗ%`(U/2ma #޲ 1-)K|'&IvͨZ̞I"惪KT NJpzz90"&R{h'F,rub1h N&@&Xb: fu!U?:Ⱦ ?eʸF/+`n_ %3p-WJ]8UݱD,+*;GYtŬ] o/9R5>|=A-BrɵJ;m 2L3Io @tQe$@s}ECLlSB69|=Mi DQM©葦/ػS$ j[ya~*3"#L ,7hSAruHßt0h@^N0:4;-3%qD\@j6Ph+4 !Ԋ)ݫnpi/a(- $d 6tug?yb>c+F&N5pWҿMHx$BP+F 01$Y$w2W1R`Bɜ[wpwH`(!DX B"7pBU3 g1'.Ft-eNÑP>g6BEvq h)R(w'S :=> ; uyYˉjfξ|H%3ɍ))0(l2RJfzmJGI% L<0,`i?YU0kܢ|g /)GcK9C #tmnSZd'!|ubEJV4'}̽ޗ hjܙ9:"[KDv333AY'̅AGTwS- 5kTL H#flJ = | KxyDEiHAB>i>ysx8ckCG2JU&6S~AkEm5Xm} ٙ[%Qh6Lpc?)';U"CT(24M~*kb <wG-gmYKȌvE^916‰/o-y1qp&|4Xhp&/\H* ;77hO L2qϞS9V..O;&6/&\j=!OzC>/l>|ms6eΡFw=z /SD>%M_Ր%kK}v! !ńJ)r*T#UD"zGd V܌`U9Ylt}mbKAqnkнoD1qDf/kMh9Qi|B2& MSoSٚc͹'> q5|:?/0X?ya~T{9$ADV(=T} x|gl?; ^j]}A)KsH!\T"&!01wYOJ)N'rƇh4#kT_9 16QxuRdK V28!hzҰG;6b(yA$y\ޣƩ4F7%NP?SbKТp+Y,I'eʋy͛UT$mV\bB$|*"&fJpZ?g%0P%&l (WA)))9e3̹{/}0a5'̳DXG0LF\5~ 7CWx@P▙ҝ=)ȣRB[fY0w7&z*cvɄX~"TP5w>D㯊\ %vv=NbJI81{!D1Vxz' zO`7=7]UlNX@RЁ^R]0Hdj'k>7:#&%b:Dy}@,̿ K!lUB$EPK<&ܓFs hh`@4ɬ`O6518&}/d|(aږ+t=K1]e'G!LfI1WB"Df̫I xbW" #WL^1WK9OP JLJXqh[Jm L*:/K[gju d~/Qm W)sbス\w={=4\خXik=)t 8QLhQC0hSWMa 5ҔhH& duE1YYwCqQ m3I>Y#|%N,LMq#b2-)t&?zvxkŶq(.f⊘ iUΨsS, 06`\*0dy(v(4B{c8>Ch5  \a zأ|AiEɘHW[ҳN*oO:cDLPR@zH~1qGk% oペ$p`HjS"|\?uӗ 8F׈BN~ &%dQ>@(>3h6p27NeOy"(nht1DDgBd'J7‡[ hkS_3>A1?1;AA0iqީZzK{tCmId)ĵ\)K&De%uB:?FQ|}5*4"XX)Sf"- ɼghٝ(&8KP"G0OKuh]pRBqG,ďȟa24ϣP $M!]T3IȲc&^#.9CsM؃Ph88R"JnPeMj(}qnfDo"L+0EhZ"s>I #4P~E`%+#$ 3eF 7^~08/!DV GlTԯL.jɌQГNiSGxi(JFWBǔ , t$ і>̾)uJk顋K 5aR{ |u-~F}:pV$e-̝rdQ)LN5G-ojȞ3ag5\er/)aXn X[S Gru# @5f#2Ca| Sei̴\ ֍M5ltZЙswP.'lWbsQ>+Q۔c>U,8|1E )E\ @[c{+D*Dם# DŽ;? Ze;2-؈Nc>p0['n<# jS4|Cwhגcy) %5zhJxl j:໑H5\~n3nh|f(4W  y1unef*aϣwi XA†2R%c [LeKn  AvGC0A?RedEK@19sMsz.#$\ ր&ؙ䮿 D_87QlA4Yht 1#ml2ރ)fo忻j%e Pi.G}t]{VVvE)`N{,vA6v%QF!B%X~,. ݌uIED<%vO3jaMz{63,0G8%Uɪol|{?04!L|ADfZEL J= Pq:s1*L{o]$H`rf$x亘3 -n"ڰu`O-gF81$ oi&0}zY 4W',MNH9,I%qӮG!2F c3<̉3'UwrCt r\^qDiP)vE^(4ݓm0hR%9w1ڀ@CR.zܲpOQ&? iN-[`ٙ<]Vܮo ~K}`kB쇩\+9/Z,W#LtjEC.=ј Ѐ5iU9;НA=4N4GBǷ%K<:Xy..9b%Kx~4kDX`hדBS\E 9fm]B =#bF{gŇr G>EaC !hŌ.P! i,c0vRO8SCA%\F OO#\1FS K/!O F.pzW0۸%FgY+iGĬlީP2#I L||G!j6im3h~貨5zfdE3Ʋw-Iar*\6x0T@j!C%ă}I;!JͮK8^s l5̟ce)T[ԑ(Ar S-*4&6׌G)G=7 ?C4/eݳiR< !d<' 4*gˇvdUߡeBgP>Hjf}iFB/BUrxLN31 T:!,ҝSG\!^i>ׇ,*kYa/ۻB` 'ʫ |H"Љ P[]0F08aPkyGa"Icjjj`Dn| TDR 1'"מ*n[EhukMrSc/ s{~1zEdc@5]:yod g6G2?!Tv5WU-јP|oeE|[44!y>dwrdkOE`N9*L[J#v4GJA޿OC˪4ԘűqCPD`j3#.$Jlϰd.vMVqVA=~„mv{'" b̃-A&7ZQ ? 0.Qo|-N %J]m,ẹ}~j("KӊKU`eGP%buQڿ̊+\F>' ꥴ,PbV<<=[s B `3Ջ[> 0-6I`fb;_XGQﺱQ-4iA#gV.vA<P&543uqHi룏jvb>@0P__&>c"\$q!4l--N3ڜXN JŤotGE Җ HdB j x `,8 j3ʪWGߏkھE/^8( ^ BwŘ6.:<bH= TDҟVR=\#iByW@ R6in;\= gZGDh1 TBp'?&cnB=qyr^g WGoSHe.|&ma:t!3q,P P@aޠB;s,!_%PpڜKUD G('ԝLA"+'d^CT}𴈲'L-"KH 520k4JTl%%h){,˥pL ?oi*Nf}d?W]Kp;ZXO,x4=P[tY$xD٤ƙ~VQM3&72toϥ.rBe>7O}uH7g[:jVpXUl = +$Nz;-7Z>MP95@xOLf4exY.,zEt AC2j2hJΪ&1F0 /b/Oh჻1EcjR# 8F>ڀJe/fTP(Gds~,T{ס+:z>95o4s@ASQGC(А̲ꔽK(B)2CJ8X.Pv2F2 !L~sB|ZByNԲ$+5O Tsd\6f.DV4i@Aob>%t -&4};&J!spE]qBB+p!hc0շ >MQ7"4"#]-Z9GAPɒ9$_hSr[JhX!RM|A HYC4h4a1D:Zl7A3mR/œ1hMlc03L3h멊|Uk欋%MIB A}P)6jCn$Vryƛ-Յ#Tfl؃yj`È,]0R>ɷs.03 W2MCrl0_ >(~}&wȩlC!|!'U_L xaԛ/~5~)*IHd& >)T`c ON5ԣ7m""9(ňƿYO~k()Qk`R L@3 Xm(HP% OhL} 10 |<Ο ߖnL#g&Vzj~!!X*mޜƞ|U ИtئJk6)\$cBɹhj._[{"M;[XL9QlH M^3ї OBYZ14[I0S9rSBpuN1:A?fT{SX0cZu4[KX5g-fG_l29gpP^NK$E"dQb}=EN }9!ޫ^#Wk@pIޫ+HQҎƒĒUtgE`Cobs&8'n Ɓ/ [} hs/†_4@yX"TԎ%N'OP|;)©_hA% K"3("jyP*9 uR##ȇ*l0.o;uy %X1۝$1 :6@p !SJFhJk⻍dNHl5E? No&dKC^t{ ef]r%s|!\!!';Ki̊p<)V엱dʄP^߉zXͭig %4GC&*E#ȣWC˘VwtVG8w]-*g YPC:#~x~ڒ-UQ`;@i ڄD&}#AI2GxA$r]c1 8b8~6R64qdLF'cCPB`!0d9=ǃ?Jwki9xfo1l*uWA@:R@A 4':|xư\TP4FQ1k_B8' ?Z֫ePJI̶>;`(^ƐR8 0^:ʄ |D;')xLO!/geJ; 7ImN /ߺWp/))iL6_JOY181𙇤d(~f1G014j$Ul˄& hej2ӶIJZbȚ_\{>N n1=VsCcvU\Dv _p61ڃiAXVy7#4~Ϙh< ja,D<ۼ[%c*M+pՏmqMKCQI s. R9Rƪ kB)z9g0$Bo9``+<& @:rXI_C_1 mAHΠg ҅A;914čyMVib"=<;YS,(ԈIj) L=p/[.+,@s@LE ? rq%}כjk:͗1Ʀ]QT~RX E :5~,$CIz5XY}p꡷y:E;!bW*w'Ae*hs+>3tŠg|,E8l' >^Q 1٭MOL M ̇]I1?@# LJ+8]VN{dgbhii!4{{WYU8Κ6)%`>SH?[>wbCcT9m7Rc;l~TcF7]{yhVH8=7V0,saK7緊"=͒0 S@+3\bcRovSBbNE[0gݗ}ue.E0f&RbOӽm3ZbSщb,rgk܍bt6M Tncd>yg#` $L%}aY bA|DG ^0 X06QgL88 cƈxy(5fF4=c4%P_{R,&ߔ9PQ.19=ıj&̖BB*NDa42"C`PSAO{'v Y2r*bhڐkV魄t^tk=D_ ~zBG]PYmasf)jHϭa,rv"2RC^T͠/j.f~=` o: &"6I"E~u6?*m"bi$%"A`\v pNO&AƜd܅̪OEh Fw49{L"V67Em"n A8^=C8d:¸Go~A5cٗLw'j *5}H@gѕ? [&ָ:AChW^#$K{jif.a߀!17 M(6!?My9n2&'g+M1Ҏ2o95/bSDU0~"XTgaAz>S}4'}ql2PCL,hAPDQX68я:ҵjE kXLJN7tRTBi('质)֝fcmP"c#(_:}SC~;|C-sRcK-_77nQx7&r`012]N,a&h))A"? tʹ_爤#5g ecX<&w~s'-emR}tDLG(#i,sY{Ս%iEDBr$Lh\w|Jno#@4H>+6vˡaK*p<+'PXk2iN`jFm[?))Ehb]|lٓerډ^ JV>?6f.0ga?xK)t/ңk3Ixo60pEnzT߂qL[a}NXR8v cu{Bl}Iiu cz ?r)UXq]_o9| AH"xh3d+a]$w N2 ):$=C UxǞIJV9TSK@ƥ! ."SDWxAGj|] %DWhĪٓ|mV5#9ΤS+ߙ@%6ru?ςCY`Kk{?xNˢ<:p, FG7 am%'SV_ YC_:fiF4mOj'iX !_nLP,w X&+o{S$ #֠ 4f=V :A@?  m:܋7ffϹȭ$_Dd$b< ;{B*d^݉bGbz&Q0{} ow|n1Ͼy;ެ&DٸQbt5R[mY\o'c sMԦ~KClC\Mys_@t\-" *HIsz(MW+hOeyكK8&M0L!g# >ʽ_~kMNͤMdf,|kR, C+{P  bFe%:Ynڞ4&/("RJ|ms ]M1("\s+ )TC EH) P;~8 plf NqZp h" XtX!Pt0(K ]O!s*ΒmB-E%T)#vt<'~x0=@K AO>w#~ᄇX5HbYD [ KA4 m,&e~@>  2@C6$' G 7JZ&UVO‰^;YSDgŧx*!A~X6BszE\EXbi\pl}0|!p.Fen3ђh뵣yk˲TB}딼pqss<ݘD *)~h_Z+ImL@CߙΫn$׊PK DۖZIGd k 92# |ū1s#rݱ0-QC5QQ T~6J6QR{%+L oi m~&s j0=׏iyJ" 7)0^L|# ?тprڵ rHB>uU &SA;OM۔1tHͳ(ӄED!sqY3^>9 %inHAQD7C &`iqs`s|o7yW[6+;l)߄Ph-T5M Ow-3xlK-}WNKE IENDB`chessx-1.0.0/src/database/enginelist.h000644 001750 001750 00000002605 12223260306 020455 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2010 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef ENGINELIST_H #define ENGINELIST_H #include #include "enginedata.h" /** The EngineList class contains configuration of all installed engines. */ class EngineList : public QList { public: /** Standard constructor. */ EngineList(); /** Restore configuration from INI file. */ void restore(); /** Store configuration in INI file. */ void save(); /** Retrieve list of engine names in current order. */ QStringList names() const; protected: /** Set the content of the default engine directories into the list of engines */ void restoreEmpty(); /** Set the content of the given directory into the list of engines */ void restoreEmptyFromPath(QString path, EngineData::EngineProtocol protocol); }; #endif // ENGINELIST_H chessx-1.0.0/data/images/flip-vertical.png000644 001750 001750 00000003344 12171025447 021245 0ustar00niklasniklas000000 000000 PNG  IHDR>asBIT|d pHYsD$D$@gTtEXtSoftwarewww.inkscape.org<aIDATxϫU?WfBhSZ()F -DM)\EZ*VQA- "kmFBmYmqfz_sfΙ|vW3ü̙)|f12g~0!";GTt͐e!"Kq`hM>V "Dd ͲF`#"CX_ggDa` ,f "2lFn$ہ-HEbDNW~"D?&@D~#0"HON ADJ\,nb&@J^5R$H>5 "qn=&@ H>d"їI>""fN>M|4ObN>sHS)&,et O'&4}0J[+N-k Nd-@wЂDCv99$zZ/@ O':Z+@އ s5\6"2N$IX\D_I "YucB@Dn%ǰD(D_`HO O';HۀD `>.j}@DX !܁3>jTK1Y@~,SD[pQ,ѧXK }+Rg@Dx X^˴8Ga^`;mBǴ@DoNF V#8Op|af/;8px_U'/hN-wy34k#bHاc3 sL12 s.% Y] NKv3L{3hKXNh'rpUu蛚&fV7lIX+Qգ(4_˼n۲@Sɂ{4,Y>tEPMN=remLYVCs8<"sxj5$pO4P1wcc'It~IGUx줈VWUn{^ޝ񶐌%5*x#搜~Yt!iJ9 J7tñnV PR'cZZ)@I :kZ-@5Bn7p)i PӱqTcWJxt!{Jj||ܚ 0"2D9J6`j`7A& ml&mj&͡8.5OC5Rn&@oVL@a 9pLj|k}ؚ "2L9, 8L)F\`\`6 "jjT}!"Ks) bDd=PapMM) !COL9̈ 54aD‰oe5"h7 5&@b{wH9.,6&@any{>E:t5Mi6xFU5Z,n~8ۘc scJvIENDB`chessx-1.0.0/Doxyfile000644 001750 001750 00000024117 10622575745 015341 0ustar00niklasniklas000000 000000 # Doxyfile 1.5.1-KDevelop #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = "Chess Database" PROJECT_NUMBER = 0.1 OUTPUT_DIRECTORY = CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = YES BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO BUILTIN_STL_SUPPORT = NO DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO HIDE_UNDOC_MEMBERS = YES HIDE_UNDOC_CLASSES = YES HIDE_FRIEND_COMPOUNDS = YES HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = NO INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = YES FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = src/ FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.mm \ *.dox \ *.C \ *.CC \ *.C++ \ *.II \ *.I++ \ *.H \ *.HH \ *.H++ \ *.CS \ *.PHP \ *.PHP3 \ *.M \ *.MM \ *.C \ *.H \ *.tlh \ *.diff \ *.patch \ *.moc \ *.xpm \ *.dox RECURSIVE = YES EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = */ui* \ */moc* EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES USE_HTAGS = NO VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = YES TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = chessx.tag ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO chessx-1.0.0/data/chessx.eco000644 001750 001750 00003523144 11216274615 016530 0ustar00niklasniklas000000 000000 \(wpBA41q Neo-Old Indian: Modern, 3.e4oYV.$A84 Dutch: 2.c4 d6.DUzC06r French: Tarrasch, Closed, 8...f6 9.exf6, 11...Qc7 12.Bg5Aٗ018E11e Bogo-Indian: 4.Nbd2 O-OԁPA09c Reti: Advance, Anglo-Polish, 3...g6)k@A70e Benoni: Classical, 8.Be2 a6Z6'-:A01 Nimzowitsch-Larsen AttackJHkkdC87b Spanish: Closed, Averbakh (Russian) VariationϘ.-#@*A80t Dutch: 2.Nf3 Nf6ΨR$B20 Sicilian: 2.g3*wXE14r Queen's Indian: 4.e3 Bb7 5.Bd3 c5 6.O-OLA26 English: Closed, 5.d3 d6 6.Nf3 Nf6} TA66 Benoni: Mikenas Attack, 8...Nfd7 9.Nf39DE10g Neo-Indian: Blumenfeld/Benoni8zvC09h French: Tarrasch, Open, Main Line, 9.c3 O-O 10.Nb3 Bd6I6]^C97b Spanish: Closed, Chigorin, 11.d4 Qc7 12.d5iBP|A45r Trompowsky: 2...c5 3.Bxf6 gxf6 4.d5 Qb6 5.Qc1 f5 6.e3 Bg7kcoRC16f French: Winawer, Petrosian VariationzcbA39k English: Symmetrical, Main Line 7.d4, 9...d6"16vnE14t Queen's Indian: 4.e3 Bb7 5.Bd3 c5 6.O-O Be7 7.Nbd2Yu7SXB51p Sicilian: 3.Bb5+ Nc6 4.O-O Bd7 5.Re1 a6 &$;=.D73 Neo-Grnfeld, 6.Qb3QF@VB06r Modern: Two Knights, Suttles VariationڐVE04j Catalan: Open, 5.Nf3 a6 6.O-O Nc6 7.e3}3Pq.ND02j Queen's Pawn: Krause, Reversed QGDz"0ZB42n Sicilian: Kan, 5.Bd3 Nf6 6.O-O Qc7 7.Qe2zL:jXB37g Sicilian: Maroczy Bind, 6.Nc2 Nf6 7.Nc3xHbǚXDD00u Blackmar-Diemer: Lamb DefencelHC82b Spanish: Open, Berlin Variationkx. 0E00t Catalan: 4.Nf3 dxc4Xi^NB04e Alekhine: Modern, Schmid VariationT*<6D11m Slav: Slav-Reti SystemP7ҋ3 VD31w Semi-Slav: Marshall Gambit, 5.Nxe4 Nf6PfYbNC40f Elephant Gambit: 3.Nxe5 dxe4 4.Bc4HkJD90 Grnfeld: Three Knights VariationE'1in>TE21 Nimzo-Indian: Three Knights, 4...Bxc3+E EFD35i QGD: Exchange, 5.Bg5 Nbd7 6.e3DFIND77g Neo-Grnfeld, 6.O-O dxc4 7.Na3 Na63&BRC83 Spanish: Open, Classical, 10.Nbd2 Nc5(ɦ~C09p French: Tarrasch, Open, Main Line, 9.Nb3 Bd6 10.Re1 O-O 11.Bg5#DtkB84 Sicilian: Scheveningen, Classical, 7.O-O Be7 8.f4 Qc7 9.Be3 Nc6[g2FE50 Nimzo-Indian: 4.e3 O-O 5.Nf3 b6?X0A45s Trompowsky: 2...Ne4e@mP6\E61o King's Indian: 4.Nf3 O-O 5.e3 d6 6.Be2 c5XkJE12y Queen's Indian: Botvinnik, 8.Qc2LG“gDC44l Ponziani: Leonhardt Variation¶nr 2C55d Two Knights: 4.d3 h6 " 8G6D11m Slav: Slav-Reti System,܂x@B30h Sicilian: 2...Nc6 3.Nc3 Nf6+F(kRB49m Sicilian: Taimanov, 6.Be3 a6 7.Be2 Nf6 8.O-O Bb4 9.Na4 Be7 10.Nxc6gdD36t QGD: Exchange, Main Line, 9.Nf3 Re8 10.O-O h6Zf E19i Queen's Indian: Old Main Line, 9.Qxc3 f5 10.b3 Bf6 11.Bb2 d6i@C01s French: Exchange, 4.Nc3 Nf6'ioZB97b Sicilian: Najdorf, Poisoned Pawn, 8.Bxf6ѩxh4A25 English: Closed, 5.Rb1َD8\B20 Sicilian: Wing Gambit, Marienbad Variation>oQQLHC78t Spanish: Archangelsk, 7.Re1 Bc5COøPE73h King's Indian: Semi-Averbakh System\B02q Alekhine: Smisch Attack, 3...Nxc3 4.dxc35LlR4C57e Two Knights: 4.Ng5 d5•ܬ0A55c Old Indian: 5.e4 c6VE61x King's Indian: Smyslov System, 6.e3 c6Q`MZA31 English: Symmetrical, Two Knights, 4...e5qiRbE05t Catalan: Open, Classical, 8.Qxc4, 10.Bd2 Be41"FD94 Grnfeld: Slav/Schlecter, 6.Be2ݻ>bC19n French: Winawer, 6...Ne7 7.Nf3 Nbc6 8.a4 Qa5ʧ qkbC95n Spanish: Closed, Breyer, Main Line, 15.a4 c5+·HE32c Nimzo-Indian: Classical, 4...d63׭4D31a QGD: Alapin Variation1@nPC65j Spanish: Berlin, Kaufmann Variationy)lQ@NA17 English: Anglo-Queen's Indian, 4.e4x8D23f QGA: Mannheim, 4...Nbd7q$M3TA16 English: Anglo-Grnfeld, 4.Nf3 g6 5.g3h ZpB01z Scandinavian: Marshall, 4.c4 Nb6 5.Nf3 g6 6.Be2 Bg7\;!bE45 Nimzo-Indian: Nimzowitsch, 5.Ne2 Ba6 6.a3 Be7UE)#bC69e Spanish: Exchange, Gligoric, 6.d4 Bg4 7.dxe5U+96A13n English: Wimpey SystemC w&K`B56q Sicilian: Open, 2...d6, 5.Nc3 Nc6 6.Be3 Ng4?dFNC61k Spanish: Bird's, 5.O-O Bc5 6.d3 c6?XdPB00u Nimzowitsch Defence: 2.d4 e5 3.dxe5>C4lTLA94 Dutch: Stonewall, Botvinnik, 8.Ba39sBD00n Queen's Pawn: Veresov Attack0g|E48 Nimzo-Indian: 4.e3 O-O 5.Bd3 d5 6.Ne2 c5 7.O-O cxd4 8.exd40{lzDB45b Sicilian: Taimanov, 5.Nc3 Bb4+qxPD46p Semi-Slav: Chigorin, 7.O-O O-O 8.e4!)r>E41 Nimzo-Indian: 4.e3 c5 5.Nf3 `ǪlB12h Caro-Kann: Gurgenidze/Modern: 3.Nd2 g6 4.Ngf3 Bg7JB41j Sicilian: Kan, 5.c4 Nf6 6.Nc3 d6,B03b Alekhine: 3.d4 d61,:A45s Trompowsky: 2...Ne4 3.h4 zzrQfE62g King's Indian: Fianchetto, Larsen System, 8.b3:hXB^E20 Nimzo-Indian: Romanishin, 4...c5 5.Nf3 cxd4%U4bA46o Indian: 1.d4 Nf6 2.Nf3 e6 3.g3 c5 4.Bg2 Qa5+ cFF<C10n French: Rubinstein, 7.Bd3:+<LD78j Neo-Grnfeld, 6.O-O c6 7.Qb3 dxc4Ȳg jC29h Vienna Gambit: Oxford, 5...Bb4 6.dxe4 Qh4+ 7.Ke2Y"-|XC14e French: Classical, Rubinstein Variation'1LE32a Nimzo-Indian: Classical Variation;fA67g Benoni: Four Pawns, Taimanov, 9.Bd3 O-O 10.Nf3ҽ:%Z^B20 Sicilian: Wing Gambit, Santasiere Variation} >(B08a Pirc: ClassicalgA/N$C29a Vienna GambitFb's`D07m QGD: Chigorin, 3.Nf3 Bg4 4.cxd5 Bxf3 5.gxf3Xpޯ8C78b Spanish: Mller Defence 7\9ND36o QGD: Exchange, Main Line, 9.Nf3 h6N[|VA56w Benoni: Czech, 5.e4 Be7 6.Nf3 O-O 7.h3@NNE18n Queen's Indian: 7.Nc3 Ne4 8.Bd2 d5)bLDC55u Two Knights: Max Lange Attack3nB09v Pirc: Austrian, 5...c5 6.Bb5+ Bd7 7.e5 Ng4 8.Bxd7+6D11o Slav: Slav-Reti System"6s6D01a Richter-Veresov AttackIULC49f Four Knights: Svenonius VariationlQ"B00d Owen Defence, rD91m Grnfeld: 5.Bg5 Ne4 6.cxd5 Nxg5 7.Nxg5 e6 8.Qd2 exd50O$D04g Colle: 3...c528_>JC96g Spanish: Closed, Chigorin, 11.d3\]SDD11f Slav: 3.Nf3 dxc4 4.e3 b5 5.a40hC48f Four Knights: Spanish, Classical Defence, 5.O-ORzhw4C37 KGA: 3.Nf3 g5 4.Bc4 g4ijMRD46i Semi-Slav: Chigorin, 7.Qc2 Main LinecUiDB41i Sicilian: Kan, 5.c4 Nf6 6.Nc3`m)8C26i Vienna: Smyslov, 3...d5^!sOs(B02n Alekhine: 3.Bc4]c;*bDA00p Polish (Sokolsky; Orang-Utan)\v"{TD31s Semi-Slav: Noteboom, Koomen VariationZx$PE94w King's Indian: 7.O-O Nbd7 8.Be3 Re8W=\E99 King's Indian: Mar del Plata, 10.f3 f5 11.Be3 f4 12.Bf2 g5 13.a4 Ng6WM?h`sE00g CatalanP+=g1hC24 Bishop's Opening: Urusov Gambit, Panov VariationItc#eHD06t QGD: 2...Bf5 3.cxd5 Bxb1 4.Qa4+@MZVC91f Spanish: Closed, Bogoljubow, 10.d5 Na5=T:A04 Reti: Lisitsin: 3.Ng5 Nf67B33q Sicilian: Pelikan, Chelyabinsk, 9.Nd5 Be7, 11.c3 O-O 12.Nc2 Bg55EE\B33m Sicilian: Pelikan, Chelyabinsk, 9.Nd5 Be7/Kp@B50m Sicilian: 2.Nf3 d6 3.c3 Nf6-ԙ&xZA86 Dutch: Leningrad, 4.Bg2 Bg7 5.Nc3 d6 6.d5+ےDzBE73d King's Indian: 5.Be2 e5 6.d5%.V.E20 Nimzo-Indian: 4.Bd2#zXA83h Dutch: Staunton Gambit, 4.Bg5 e6 5.Nxe4"(l.A57b Benko Gambit: 4.a44`C57f Two Knights: Lolli Attack, Pinkus Variation;l 2D05b Colle: 3...e6 4.Nbd2$? nA94 Dutch: Stonewall, Botvinnik, 8.Ba3 Bxa3 9.Nxa3 Nbd7TQlXA52g Budapest: Adler, 4...Bc5 5.e3 Nc6 6.Be2}VB53m Sicilian: Chekhover, Zaitsev Variationd7# 1TB46k Sicilian: Taimanov, 5...a6 6.Be3 Nge7sA88 Dutch: Leningrad, Main Line, 7.Nc3 c6 8.d5 e5 9.dxe6 Bxe6 10.b3tfE67k King's Indian: Fianchetto, Classical, 8.h3 Re8#LC49c Four Knights: 4.Bb5 Bb4 5.O-O O-Oh|j>C77i Spanish: Exchange Deferred܎Q͚uTB17f Caro-Kann: Steinitz, 5.Nf3 Ngf6 6.Ng3؀rCbA39j English: Symmetrical, Main Line 7.d4, 9.Qxd4f9oJC77o Spanish: Centre Attack, 5...exd4fմ(B07b Pirc: 2.Nf3 Nf6ŠrhE45 Nimzo-Indian: Nimzowitsch, 5.Ne2 Ba6 6.Ng3 Bxc3+e6̵RD85t Grnfeld: Modern Exchange, 8.Be3 Nc6;-0C55a Two Knights Defence'0/>C67e Spanish: Open Berlin, 5.d4ǫB5rVA94 Dutch: Stonewall, Botvinnik, 8.Ba3 Bxa3hJSQ:B24 Sicilian: Closed, 3.g3 g6!qb8D16j Slav: Smyslov, 6.e4 Bg4Fq.6C87a Spanish: Closed, 6.Re1')֎F`B70s Sicilian: Dragon, 6.Be2 Bg7 7.O-O O-O 8.Bg5o%L^C73 Spanish: Modern Steinitz, Richter Variation.^jE14o Queen's Indian: 4.e3 Bb7 5.Bd3 d5 6.O-O Bd6 7.b3F#A07 Reti: KIA0"J>C41m Philidor: Berger Variation(ajJpA14 English: Neo-Catalan Declined, 5...O-O 6.b3 c5 7.Bb2=+ZE29 Nimzo-Indian: Smisch, Capablanca, 10.O-O (X/HD33l QGD Tarrasch: 6.g3 Nf6 (Prague)~ebjA30v English: Symmetrical, Hedgehog, 9.b3 Nbd7 10.Nb5|ydC09c French: Tarrasch, Open, 5.Ngf3 Nc6 6.Bb5 cxd4s)a%C\E90s King's Indian: 5.Nf3 O-O 6.h3 e5 7.d5 Na6s:| ZA07 Reti: KIA, Yugoslav, Main Line, 6.Nbd2 e6mj˷zE29 Nimzo-Indian: Smisch, 5...O-O 6.e3 c5 7.Bd3 Nc6 8.Ne2 e5gLR9PQRA87 Dutch: Leningrad, Main Line, 7.Nc3 e6`]nW^E05h Catalan: Open, Classical, 7.Ne5 Nc6 8.Nxc6\0;.7E88d King's Indian: Smisch, Orthodox, 7.d5 c6 8.Qd2 cxd5 9.cxd5 a6XA?RE50 Nimzo-Indian: 4.e3 O-O 5.Nf3 c5 6.Be2@Q(HB20 Sicilian: English, 2...Nc6 3.Nc3=[)U\E87b King's Indian: Smisch, Orthodox, 7.d5 a54[>oUZD75 Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O c5 8.dxc53 fv>B47b Sicilian: Taimanov, 6.Nxc6W@tYݴ8A13c English: 1...e6 2.g3 d5HHB00g Owen Defence: Matinovsky GambitдZB42n Sicilian: Kan, 5.Bd3 Nf6 6.O-O Qc7 7.Qe2@z]^B37i Sicilian: Maroczy Bind, 6.Nc2 Nf6 7.Nc3 d6˔uNB57a Sicilian: Sozin, Magnus Smith Trapθį^0A10 English: Wade GambitM3`A58s Benko Gambit: Fianchetto, Main Line, 11.Qc2 k"ZtA45o Trompowsky: 2...e6 3.e4 h6 4.Bxf6 Qxf6 5.Nc3 d6 6.Qd2ʻ`[.f`E85c King's Indian: Smisch, Orthodox, QueenswapR^hw4C60p Spanish: Cozio, 4.Nc3Uy FB08h Pirc: Classical, 5.Be3 a6 6.a4IM <B08g Pirc: Classical, 5.Bc4 c6 XE96 King's Indian: 7.O-O Nbd7, Old Main Linesѥ+t`ZE13d Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.Nd2Wߟ8A44l Old Benoni: Czech, 3.e4o5R^B76b Sicilian: Dragon, Yugoslav, 7.f3 O-O 8.Qd2f&(A60a Benoni: 3.d5 e6#1LdC06e French: Tarrasch, Closed, Leningrad, 9.O-O a5n0q8A09m Reti: Accepted, 3.g3 e6"nOY<B02r Alekhine: Chase VariationS$&*6C70 Spanish: Cozio DeferredħBC36 KGA: Scandinavian, 4.exd5 Bd6r #\C48p Four Knights: Rubinstein, 5.Ba4 c6 6.Nxe5m#.C57a Two Knights: 4.Ng5iYKNLB30r Sicilian: Rossolimo, 3...e6 4.O-Ob#GF^D68 QGD: Orthodox, Classical, Maroczy Variation_"lӍ>C57a Two Knights: Traxler, 5.d4Ua40DC64p Spanish: Classical, 4.O-O Nd4PI:9RD96 Grnfeld: Russian, 5...c6 6.cxd5 cxd5F$S0E70a King's Indian: 4.e4B.J޶DLA45n Trompowsky: 2...e6 3.e4 h6 4.Bxf68PAK6B07h Pirc: 3.Bd3 e5 4.c3 d50WRaE59 Nimzo-Indian: Main Line, 9.bxc3 dxc4 10.Bxc4 Qc7 11.Bd3 e5 12.Qc2 Re8-$JE09h Catalan: Closed, Main Line, 9.e4'4'TFVB66b Sicilian: Richter-Rauzer, 7...a6 8.Be2%+\:D25d QGA: Smyslov, 5.Bxc4 Bg7!18ND86 Grnfeld: Classical Exchange, 8.Ne2!z0ZC87h Spanish: Closed, Averbakh, 7.c3 Bg4 8.d3帅`B39c Sicilian: Maroczy Bind, Breyer, 8.Qxg4 Nxd4,xuE13q Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.e3 g5 8.Bg3 Ne4 9.Qc2 Bxc3+ 10.bxc3 d6 11.Bd3 f5tXC72 Spanish: Modern Steinitz, 5.O-O Bg4 6.h3P)N@C54c Giuoco Piano: Bird's AttackY!tE15k Queen's Indian: Nimzowitsch, 5.Qa4 c5 6.Bg2 Bb7 7.O-O .'=~|E09p Catalan: Closed, Main Line, 9.e4 Bb7 10.b3 Rc8 11.Bb2 Qc7buArB90o Sicilian: Najdorf, 6.Be3 e5 7.Nb3 Be6 8.f3 Be7 9.Qd2Nr+a40A54 Old Indian: 5.g3 Be7B;b'0C12a French: MacCutcheon"S>C40s Latvian Gambit: 3.Nxe5 Nc6ݢSYDB83 Sicilian: Scheveningen, ModernڹćA^D44l Semi-Slav: Botvinnik, Lilienthal, 11...Qa5+@B23n Sicilian: Chameleon, 3...e5ט%SrD31v Semi-Slav: Noteboom, Abrahams, Main Line, 14.O-O O-Oiet˴bA70w Benoni: Classical, 8.h3 O-O 9.Bd3 b5 10.Nxb5@9^C75 Spanish: Modern Steinitz, Rubinstein, 7.Be3 @B21a Sicilian: Grand Prix Attackȼr3TB21y Sicilian: Smith-Morra, 5.Nf3 d6 6.Bc46**A55a Old Indian: 5.e4od_\E81c King's Indian: Smisch, 5...O-O 6.Nge2 e5q1/G8vB78k Sicilian: Dragon, Yugoslav, Main Line, 12.h4 h5 13.Kb1:ɭPVB55 Sicilian: Prins, Venice Attack, 6...Bd7·8D47h Semi-Slav: Meran, 8.Bd36XpE87j King's Indian: Smisch, Orthodox, 7.d5 Nh5 8.Qd2 f5 A vLC45v Scotch: 4.Nxd4 Bc5 5.Be3 Qf6 6.c3pZVr<A01 Nimzowitsch-Larsen: 1...d5oѺi&ZE30 Nimzo-Indian: Leningrad, 4...c5 5.d5 exd5n>ݙ2LD27m QGA: Classical, Spassky, 7...Qxd1cu$D35b QGD: ExchangeXi_7F^A32 English: Symmetrical, Two Knights, 5.g3 Qb6L c~LB00u Nimzowitsch Defence: 2.d4 e5 3.d53VA45y Trompowsky: 2...Ne4 3.Bf4 c5 4.f3 Qa5+2V@KbA41h Neo-Old Indian: Wade Defence, 3.c4 Nd7 4.Nc3(JT<A95 Dutch: Stonewall, 7.Nc3 c6 #!n@C40c Open Game: Gunderam Defence$TjE31m Nimzo-Indian: Leningrad, Main Line, 8...e5 9.Bd3jLA64 Benoni: Fianchetto, 11...Re8 12.h3]RA75 Benoni: Classical, 9.O-O a6 10.a4 Bg4 _A07 Reti: KIASt42pB56n Sicilian: Open, 2...d6, 5.Nc3 Nc6 6.f3 e5 7.Nb3 Be7 ꥛*B06j Modern: 3.Nf3 d6hFYHC86b Spanish: Worrall Attack, 6...b5TӫwzD99e Grnfeld: Russian, Smyslov, Main Line, 9...Nb6 10.Rd1 e6ۖ?ZB01q Scandinavian: 2...Qxd5, Main Line, 8.Qe2b4tB44z Sicilian: Taimanov, Szen, Hedgehog, 11.Be3 Bb7 12.Qb3U2A13b English: 1...e6 2.g3k8\ZC33 KGA: Bishop's Gambit, Bryan CountergambitjXB45h Sicilian: Taimanov, Four Knights, 6.Be2/wZ\D21u QGA: Alekhine, Borisenko-Furman Variation 6JA44q Old Benoni: Czech, 3.e4 d6 4.Nc3}LB29j Sicilian: Nimzowitsch, 4.Nc3 Nxc3vbC99a Spanish: Closed, Chigorin, 12...cxd4 13.cxd4}$B06i Modern: 3.Nf3w]-D8A85 Dutch: 2.c4 Nf6 3.Nc3 g6uX,bA20 English: King's, Nimzowitsch, Flohr VariationjWۡDD73 Neo-Grnfeld, 5.Nf3 dxc4 6.Na3Vj6б@A55l Old Indian: Main Line, 8.h3SBb ND12l Slav: 4.e3 Bf5 5.Nc3 e6 6.Bd3 Bxd3P̅(C15a French: WinawerOctA45r Trompowsky: 2...c5 3.Bxf6 gxf6 4.d5 Qb6 5.Qc1 f5 6.g3Klؗ66D15e Slav: Chameleon, 5.Bg5@ Ɨ#ZE11t Bogo-Indian: Nimzowitsch, 5.g3 Nc6 6.Bg2<:層DND41s QGD: Semi-Tarrasch, 6.e3 Nc6 7.Bc49ÍVE63l King's Indian: Fianchetto, Panno, 8.d57g;6thC97k Spanish: Closed, Chigorin, 12...Bd7 13.Nf1 Rfe8bWVfC86i Spanish: Worrall Attack, 7...O-O 8.c3 d6 9.Rd1X'Ld*B20 Sicilian: 2.d3 e6uN`E78 King's Indian: Four Pawns Attack, 7.Nf3 cxd4@ 'DA36c English: Symmetrical, 3.g3 e6N'~A77 Benoni: Classical, Main Line, 10.Nd2 Nbd7 11.a4 Ne5 12.Ndb1!<C40n Latvian Gambit: 3.exf5 e40:=QHC55e Two Knights: 4.d3 Be7 5.Bb3 O-Oz/9|6D70 Neo-Grnfeld: 4.Bg2 Bg7׵BB10j Caro-Kann: English, ExchangetdC46l Three Knights: Steinitz, 4.d4 exd4 5.Nxd4 Bg76SB58r Sicilian: Boleslavsky, 7.Nf3, 9.Re1 O-O 10.h3 Be6 11.Bf1 Nb8뢈d,(E00n Catalan: 3...d5N B39g Sicilian: Maroczy Bind, Breyer, 8.Qxg4 Nxd4 9.Qd1 e5 10.Bd3H RE18y Queen's Indian: Old Main Line, 8.Qc2 E12u Queen's Indian: Petrosian, Kasparov, 7...Nxc3 8.bxc3 Be7 9.e4_@%FC63l Spanish: Schliemann, 4.Nc3 Nf6kPE62b King's Indian: Fianchetto Variation. FWjxE12o Queen's Indian: Petrosian, 5.Nc3 d5 6.Bg5 Be7 7.Qa4+ c682BA14 English: Neo-Catalan Declinedۿ>@?M2A03 Bird: Williams Gambit׭lͯ`E31e Nimzo-Indian: Leningrad, Main Line, 7.e3 e54[vRD08 QGD: Albin, 4.Nf3 Nc6 5.a3 Bg4 6.Nbd2ŕ|ATB12w Caro-Kann: Advance, Main Line, 6.Nge20_X<C26c Vienna: Smyslov Variation);%"fE19k Queen's Indian: Old Main Line, 9.Qxc3 c5 10.b3zA32 English: Symmetrical, Two Knights, 5.g3 d5 6.Bg2 e5 7.Nf3),ș<A92 Dutch: Stonewall, 7.Qc2 c6?L@C15k French: Winawer, 4.a3 Bxc3+D "<D24p QGA: Bogoljubow, 7.a4 Nb4,"hpfC45q Scotch: 4.Nxd4 Bc5 5.Nb3 Bb6 6.a4 a6 7.Nc3 Qf6$XE15g Queen's Indian: Nimzowitsch, 5.Nbd2 Bb4bLC64f Spanish: Classical, Cordel Gambit6s~vB78n Sicilian: Dragon, Yugoslav, Main Line, 12.h4 h5 13.Bg5{)@ATE34 Nimzo-Indian: Classical, Noa Variationn,qICvC95g Spanish: Closed, Breyer, 10.d4 Nbd7 11.Nbd2 Bb7 12.Bc2e8\X6D00f Hodgson Attack: 2...g6^a`E30 Nimzo-Indian: Leningrad, 4...c5 5.d5 d6 6.e3Vl5As\A16 English: Anglo-Grnfeld, Smyslov VariationUa/tFB43m Sicilian: Kan, 5.Nc3 Qc7 6.Bd3RQP*D08 QGD: Albin, 4.Nf3MmH:]XB13h Caro-Kann: Exchange, 4.Bd3 Nc6 5.c3 Nf6IZ`E18p Queen's Indian: 7.Nc3 Ne4 8.Bd2 f5 9.d5 Bf6Fo8dDA56u Benoni: Czech, 5.e4 Be7 6.Bd3DIULt>A67s Benoni: Four Pawns, Taimanov, 9.a4 O-O 10.Nf3 Na6 11.O-O Nc7>owUHA42g Modern: Averbakh, Kotov, 5.Nge2:vHFA25 English: Closed, Trger Defence'LVZC55v Two Knights: Max Lange, Krause Variation'\R@C20 Open Game: Portuguese GambitԏkDA52j Budapest: Rubinstein, 4...Nc6DQ(FD28e QGA: Classical, 7.Qe2 b5 8.Bd3 HL?HE18m Queen's Indian: 7.Nc3 Ne4 8.Bd2 ޑ C44a Open GamekF(D11g Slav: 3.Nf3 Nf6e\E92k King's Indian: Gligoric-Taimanov, 7...Ng43VA45n Trompowsky: 2...e6 3.e4 h6 4.Bxf6 Qxf6 iH)LJA31 English: Symmetrical, Two Knights.Hv^D38d QGD: Ragozin, 5.Qa4+ Nc6 6.cxd5 exd5 7.Bg5AN=WBC02p French: Advance, Euwe, 6.Be22wPE83g King's Indian: Smisch, Panno, 8.a3*A 8D01c Richter-Veresov: 3...e6Dg%FA21 English: King's, 2.Nc3 d6 3.Nf3O6D11o Slav: Slav-Reti SystemS4D02u Queen's Pawn: 3.g3 g6ӵ.,A^D35s QGD: Exchange, 5.Bg5 c6 6.e3 Be7 7.Bd3 Ne4Eta*A^D90 Grnfeld: Three Knights Exchange, 6.Bd2 O-OȢ˭T0C45b Scotch: 4.Nxd4 Nxd4t"jD35v QGD: Exchange, 5.Bg5 c6 6.e3 Be7 7.Bd3 O-O 8.Nf3P I^C99c Spanish: Closed, Chigorin, 13...Bd7 14.Nf1]<D17h Slav: Central, 6.Ne5 Nbd7L$6o@B93e Sicilian: Najdorf, 6.f4 Qc7`?Z8D02d Queen's Pawn: 2.Nf3 Bf5 |fE84e King's Indian: Smisch, Panno Main Line, 9.Rb1ڧ;F4A03 Bird: Lasker Variation'R^E38h Nimzo-Indian: Classical, 4...c5 5.dxc5 Nc6RA03 Bird: 1...d5 2.Nf3 Nf6 3.g3 g6: 5.O-O=kFDC59a Two Knights: Morphy, 8.Be2 h6ӿTE19a Queen's Indian: Old Main Line, 9.Qxc3~+mt?rB63f Sicilian: Richter-Rauzer, 7.Qd2 Qb6 8.Nb3 a6 9.O-O-O}Te|C15i French: Winawer, Mller-Zhuravlev Gambit, Kunin Variation}r(`nD37q QGD: Classical, 5...O-O 6.e3 c5 7.dxc5 Bxc5 8.cxd5w[ՃJE92o King's Indian: Petrosian, 7...c5vlVTB93n Sicilian: Najdorf, 6.f4 e5 7.Nf3 Nbd7vJ<E00r Catalan: 4.Nf3 Bb4+ 5.Bd2v.Ek]@E11k Bogo-Indian: Vitolins, 6.g3oEw`B33s Sicilian: Pelikan, Chelyabinsk, 9.Bxf6 gxf6m 2C67a Spanish: Open Berlinlu,C55l Two Knights: 4.d4d=ھ|PC97f Spanish: Closed, Chigorin, 12...Re8c}z RB25j Sicilian: Closed, 6.f4 e5 7.Nf3 Nge7ag:jC43d Russian Game: Modern Attack, 3...exd4, Main Line[n~jE12f Queen's Indian: Petrosian, 4...c5 5.d5 Ba6 6.Qc2Vb;0PA43m Old Benoni: 2.d5 Nf6 3.Nf3 g6 4.Nc3R oHC80b Spanish: Open, Knorre VariationHSRC53 Giuoco Piano: LaBourdonnais VariationC@xKE66j King's Indian: Fianchetto, Yugoslav Panno, 9...a6 10.Qc2 Rb8 11.b3B MNB43k Sicilian: Kan, 5.Nc3 Qc7 6.Be2 Nf6A;@C81 Spanish: Open, Keres, 10.Rd1AbC56a Two Knights: Classical, Nakhmanson Variation2B\^C73 Spanish: Modern Steinitz, Richter Variation-͗$% 4pD18t Slav: Dutch, 8...O-O 9.Nh4 Nbd7 10.Nxf5 exf5 11.Qc2"s BA45u Trompowsky: 2...Ne4 3.Bf4 d5efA38p English: Symmetrical, Main Line, 7.d3 d6 8.Bd2Hȱ6A24 English: Bremen, 3...g6+HLC29t Vienna Gambit: Breyer, 6.Qe2 Nxc3_ūD37a QGD: 4.Nf38lC33 KGA: Bishop's Gambit, Lopez-Gianutio Countergambit3Ͷ3A43a Old Benoni uBD03i Torre Attack: 3...e6 4.e3 c5#b6XaNE08j Catalan: Closed, 7.Qc2 c6 8.Bf4 b63s;<A60c Benoni: 4.Nf3 exd5 5.cxd5k$x&$A84 Dutch: 2.c4 e6^aA07 Reti: KIA홥xZA31 English: Symmetrical, Two Knights, 4...b6W7MXD75 Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O c5 8.Nc3xadA14 English: Neo-Catalan Declined, 5...O-O 6.b3 b6dۮ"D25c QGA: 4.e3 a6!;hC30e King's Gambit: Norwald Variation, Schubert lineg:C37 KGA: Ghulam-Kassim GambitrvD76j Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O Nb6 8.Nc3 Nc6 9.d5 Na5G:MvE59 Nimzo-Indian: Main Line, 9.bxc3 dxc4 10.Bxc4 Qc7 11.Bb5/~;׭FXD51 QGD: Capablanca's Anti-Cambridge Springs}+.TB35q Sicilian: Accelerated Fianchetto, Modern, 7.Bc4 O-O 8.Bb3 d6 9.f3`FC05b French: Tarrasch, Closed, 4.e5>HC39 KGA: Allgaier, Blackburne GambittIZB17g Caro-Kann: Steinitz, 5.Nf3 Ngf6 6.Ng3 e6vfeXC78x Spanish: Archangelsk, Main Line, 10.Be39qJA82 Dutch: Staunton Gambit, 4.f3 exf3Gp^C15t French: Winawer, Alekhine Gambit, 5.a3 Be7:U"c GlA67i Benoni: Four Pawns, Taimanov, 9.Bd3 O-O 10.Nf3 a6VPSFB06t Modern: Pseudo-Austrian Attack);2E01 Catalan: 4...c6 5.Qc2rC)PB00b Reversed Grob (Borg/Basman Defence)fqT.D34d QGD Tarrasch: 9.b3ar;kCFC23 Bishop's Opening: 2...Bc5 3.Qe26JA85 Dutch: 2.c4 Nf6 3.Nc3 e6 4.e3 Bb4[W<;RB05c Alekhine: Modern, Alekhine Variation"44ջuLB02t Alekhine: Two Pawns Attack, 5.Nc3e<D07s QGD: Chigorin, 3.Nc3 dxc4[`6A65n Benoni: Smisch, 8.Bg5΂ʭ6VC78v Spanish: Archangelsk, Main Line, 10.a4Q%PA68i Benoni: Four Pawns, 9.Be2 Bg4 10.e5)hC67s Spanish: Open Berlin, 5.d4 Nd6 Queenswap, 9.Nc3ğYw:A45m Trompowsky: 2...e6 3.Nd24ύq>A00m Van Geet: 1...d5 2.e4 dxe4]]LD36b QGD: Exchange, 5.Bg5 c6 6.Qc2 Na63XA46j Indian: 1.d4 Nf6 2.Nf3 e6 3.c3 b6 4.Bg5I9^D23t QGA: Mannheim, Main Line, 10.e3 Ne4 11.Qe2\[[`BD41c QGD: Semi-Tarrasch, 6.g3 Nc6upC44w Scotch: Goring Gambit, 4...dxc3 5.Nxc3 Bb4 6.Bc4 d6aIjVD35o QGD: Exchange, 5.Bg5 c6 6.e3 Be7 7.Nf3)E18w Queen's Indian: 7.Nc3 Ne4 8.Nxe4 Bxe4 9.Ne1 Bxg2 10.Nxg2 d5 11.Qa4 Qd7O[pܢFD00e Queen's Pawn: Stonewall AttackH&)8A13d English: 1...e6 2.g3 d5XXB00u Nimzowitsch Defence: Bielefelder GambitVsSTNE17q Queen's Indian: 6.O-O O-O 7.Re1 d5B쑏ri:E10b Neo-Indian: Dry Defence V4E10c Neo-Indian: 3.Nf3 Be7vw mtPE12l Queen's Indian: Petrosian, 5.Nc3 g6_tU.A45p Trompowsky: 2...c5Z]M<C79 Spanish: Steinitz DeferredW \LE61q King's Indian: 4.Nf3 O-O 5.Bf4 d6R zAtXE72 King's Indian: 4.e4 d6 5.g3 O-O 6.Bg2 c5LU!Տ\&A25 English: ClosedKcbXxDD71 Neo-Grnfeld, 5.cxd5 Nxd5 6.e4I"k4C55t Two Knights: 5.O-O d6HDTg9dB73 Sicilian: Dragon, Classical, Richter VariationG<@C78t Spanish: Archangelsk, 7.Re1GKG vB44u Sicilian, Taimanov, Szen, 7.N1c3 a6 8.Na3 Be7 9.Be2 b6=2XD46r Semi-Slav: Chigorin, Main Line, 10...h6<6Y-ND47c Semi-Slav: Meran, Freymann, 8...b44E~PC91c Spanish: Closed, Bogoljubow, 10.Be3,Q\s0C37 KGA: Srensen Gambit'#)bDA41e Neo-Old Indian / Modern: 3.g3"[.@wzB22h Sicilian: Alapin, 2...d5 3.exd5 Qxd5 4.d4 Nc6 5.Nf3 cxd4yW\20E60e King's Indian: 3.g3Ys6hA68l Benoni: Four Pawns, 9.Be2 Bg4 10.O-O Nbd7 11.h3pY80D23b QGA: 3.Nf3 Nf6 4.g3 >i B39l Sicilian: Maroczy Bind, Breyer, 8.Qxg4 Nxd4 9.Qd1 Ne6 10.Rc1 Qa5 11.Qd2IK,C37 KGA: Salvio GambitgI*C38 KGA: Greco Gambit[*HD97n Grnfeld: Russian, Prins, 8.Bf4U+ZE19b Queen's Indian: Old Main Line, 9.Qxc3 d60mfD36u QGD: Exchange, Main Line, 9.Nf3 Re8 10.O-O Nf8賸k`@HA21 English: King's, Keres Variation6GQbE62p King's Indian: Fianchetto, Spassky VariationiFvC81 Spanish: Open, Keres, 10.Rd1 O-O 11.c4 bxc4 12.Bxc4 Bc5FnA59o Benko Gambit: 7.e4, Main Line, 11...Nbd7 12.h3 Ra6K6D17e Slav: Czech, 6.Nh4 Bc8=FTC57b Two Knights: Traxler, 5.Nxf7 & 6.Kxf2iD58o QGD: Tartakower, 8.Be2 Bb7 9.Bxf6 Bxf6 10.cxd5 exd5 11.b4 c6m+lvB00r Nimzowitsch Defence: 2.Nf3 d6 3.d4 Nf6 4.Nc3 Bg4 5.Be2RC89p Spanish: Marshall, Main Line, 15.Be3|#KJD81 Grnfeld: Early Russian Variationn@B01a Scandinavian: Bhnke GambitwxRrB93s Sicilian: Najdorf, 6.f4 e5 7.Nf3 Nbd7 8.a4 Be7 9.Bd3rd3_0TD55j QGD: Neo-Orthodox, Gligoric Variationm8gBE24 Nimzo-Indian: Smisch, 5...c5jȢy2C26b Vienna: 2...Nf6 3.d3j-3pB27q Sicilian: Accelerated Pterodactyl, 4.dxc5 Qa5+ 5.c3` TB47l Sicilian: Taimanov, 6.g3 a6 7.Bg2 Nf6`[sW4D14h Slav: Exchange, 8.Bd3VI(A53 Old Indian: 3.g3A۔'wpC47t Four Knights: Scotch, Main Line, 7...d5 8.exd5 cxd5?@ΨXC88l Spanish: Closed, Anti-Marshall 8.a4 Bb7+aیX\B52i Sicilian: 3.Bb5+, Sokolsky, 5...Nc6 6.O-O PqFC56d Two Knights: Classical, 7.Bxd5 7JB42k Sicilian: Kan, Gipslis Variationr@HD14k Slav: Exchange, 8.Bd3 Main Lineu3,4A53 Old Indian: 3.Nc3 Nbd7ʓzX"LA59b Benko Gambit: 7.e4 Bxf1 8.Kxf1 g6҉x>C60k Spanish: Fianchetto, 4.O-Oq1O:A61 Benoni: Uhlmann Variation lA67r Benoni: Four Pawns, Taimanov, 9.a4 O-O 10.Nf3 Na6ɸjB21x Sicilian: Smith-Morra, 4.Nxc3 Nc6 5.Nf3 e6 6.Bc4E)LC68n Spanish: Exchange, 5.O-O Bg4 6.h3fRdA03 Bird: 1...d5 2.Nf3 Nf6 3.g3 g6: 5.O-O O-O 6.d3Wh(V|A77 Benoni: Classical, Main Line, 10.Nd2 Nbd7 11.a4 Ne5 12.Re1 UVE92s King's Indian: Petrosian, Stein, 8.Bg51]\C85i Spanish: Closed, Exchange, 7.Qe1 Nd7 8.b3BpNC07g French: Tarrasch, Open, 4.Ngf3 Nc6yL*ZE95i King's Indian: 7.O-O Nbd7 8.Re1 c6 9.Rb12}4B08f Pirc: Classical, 5.a4^D9tHA30c English: Symmetrical, 2.Nf3 Nf6<&C44r Scotch OpeningL=jDC20 Open Game: Portuguese, 2...Nf6 zB39j Sicilian: Maroczy Bind, Breyer, 8.Qxg4 Nxd4 9.Qd1 Ne6 10.Rc1\ tD99d Grnfeld: Russian, Smyslov, Main Line, 9...Nb6 10.Rd1tʏiZD48f Semi-Slav: Meran, 8...a6 9.O-O Bb7 10.e4n,zddD36t QGD: Exchange, Main Line, 9.Nf3 Re8 10.O-O h6it0D26b QGA: 4.e3 e6 5.Bxc4gPPT:t$B20 Sicilian: 2.d3gcBD56 QGD: Lasker Defence, 9.Rc1 c6f@"JD36k QGD: Exchange, Main Line, 9.Nge2aX>]>A36a English: Symmetrical, 3.g3\ * :C26e Vienna: Smyslov, 3...Bc5V6xB78h Sicilian: Dragon, Yugoslav, Main Line, 12.h4 Nc4: 14.g4?v*A54 Old Indian: 4.Nf34ZԽՔZC00e French: Steiner (Anglo-French) Variation2x6`B47v Sicilian: Taimanov, 6.Be2 a6 7.O-O Nf6 8.a31EJ XC12e French: MacCutcheon, Chigorin Variation+'>BA46t Torre Attack: 3...c5 4.c3 h6)YN=tD67 QGD: Orthodox, Main Line, Capablanca Freeing Manoevure' \HB82 Sicilian: Scheveningen, 6.f4 Nc6 wDB27c Sicilian: Quinteros Variation `PE97e King's Indian: Mar del Plata, 9.Bd2 %=jC45y Scotch: 4.Nxd4 Bc5 5.Be3 Qf6 6.c3 Nge7 7.Bc4 Ne5 R;KVC44j Ponziani Countergambit, Schmidt Attack44 zD75 Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O c5 8.Nc3 Nxc3 9.bxc3 cxd4qWDD18b Slav: Dutch, Lasker Variation_ƦG]!BA56s Benoni: Czech, 5.e4 Be7 6.g3Z EHE73j King's Indian: Averbakh, 6...c6?ܶV^E49 Nimzo-Indian: Botvinnik, 7...c5 8.cxd5 exd5$,JD54a QGD: Anti-Neo-Orthodox VariationzMjDB43h Sicilian: Kan, 5.Nc3 Qc7 6.g3F@rufD34u QGD Tarrasch: 9.Bg5 cxd4 10.Nxd4 h6 11.Be3 Re8DFC65g Spanish: Berlin, Mortimer Trap߬xF~E99 King's Indian: Mar del Plata, Benko Attack, 11...Nf6 12.Nd3Ձ^SR2A46x Torre Attack: 3...h6EBA58h Benko Gambit: Accepted, 7.g3&bR%A07 Reti: KIA[A_B11n Caro-Kann: Two Knights, 3...Bg4 4.h3 Bxf3 5.Qxf3 e6 6.d3 Nf6 7.Bd26zB96v Sicilian: Najdorf, Polugaevsky, 10.Qe2 Nfd7 11.O-O-O Bb7< VC42q Russian Game: Classical, Marshall Trap"xZA31 English: Symmetrical, Two Knights, 3...g6&JfD58l QGD: Tartakower, 8.Be2 Bb7 9.Bxf6 Bxf6 10.cxd5Vy(A56i Benoni: 3.d5 d6{I,`B10v Caro-Kann: Two Knights, 3...dxe4 4.Nxe4 Nf6,z<A45u Trompowsky: 2...Ne4 3.Bf4iQXfC29l Vienna Gambit: Paulsen Attack, Heyde Variationhj>B51m Sicilian: 3.Bb5+ Nc6 4.O-Od TC01p French: Exchange, 4.Nf3 Bd6 5.Bd3 Nf6_Al^B54k Sicilian: Prins (Moscow), 5...Nc6 6.c4 Qb6Yؿ\,XA52l Budapest: Rubinstein, Main Line, 6.Nbd2V'PVA34 English: Symmetrical, Rubinstein SystemQy+"HA95 Dutch: Stonewall, 7.Nc3 c6 8.Ne5OZVB99m Sicilian: Najdorf, Main Line, 10.g4 h6LR!5dE69c King's Indian: Fianchetto, Classical, 9.h3 a6B]hA32 English: Symmetrical, Two Knights, 5.Nc3 a6 6.g3?ԫ>`D67 QGD: Orthodox, Main Line, Janowski Variation7TVGhB17u Caro-Kann: Steinitz, 5.Bc4 Ngf6 6.Ng5, 8.Bd3 h66>ͫjE15o Queen's Indian: Nimzowitsch, 5.b3 Bb4+ 6.Bd2 Be7,Tp.:/^E67g King's Indian: Fianchetto, Classical, 8.b3)7瘟WnD19e Slav: Dutch, 8...O-O 9.Qe2 Bg6 10.Ne5 Nbd7, 12.Rd1(cg4>D05c Colle: Zukertort Variation(<A60h Benoni: 4.Nc3 exd5 5.Nxd5'=`R*JD69 QGD: Orthodox, Classical, 13.dxe5Εq'PD00j Trompowsky: 2...d5 3.Bxf6 gxf6 4.e3@Ŏ5<C96a Spanish: Closed, Chigorin h!DBB33d Sicilian: Pelikan/Sveshnikov 4&{\:A45j Trompowsky 2...d6 3.Bxf6C+CX\C93 Spanish: Closed, Smyslov, 10.d4 Re8 11.Be3̻vI 2A09l Reti: Accepted, 3.g3a"A56f Benoni: 3.d5{Oj0DD48b Semi-Slav: Meran, 8...a6 9.a4&ZD43k Semi-Slav: Moscow, 6.Bh4 Gambit Accepted缥slfA37m English: Symmetrical, 5.Nf3 e6 6.O-O Nge7 7.e3 .A54 Old Indian: 5.g3 c6Þ^A88 Dutch: Leningrad, Main Line, 7.Nc3 c6 8.Qc29f1>A43s Old Benoni: Schmidt, 3.Nf3ΈAc46D25d QGA: Smyslov Variation=FƈhE12s Queen's Indian: Petrosian, 6.cxd5 Nxd5 7.e3 Be7f`B92m Sicilian: Najdorf, 6.Be2 e5 7.Nb3 Be7 8.O-O O-O 9.Be3 Be6 10.Nd5 (`B77h Sicilian: Dragon, Yugoslav, 9.Bc4 Bd7 10.g4h+k~C10w French: Rubinstein, 4...Bd7 5.Nf3 Bc6 6.Bd3 Nd7 7.O-O Ngf6R<E06 Catalan: Closed, 5.Nf3 O-OU<NE90l King's Indian: 5.Nf3 O-O 6.h3 Nbd7LktGZA57n Benko Gambit: 4.cxb5 a6 5.e3 g6 6.Nc3 d69>&A25 English: Closedaf_8A20 English: King's, 2.g3 d63ԾjC48e Four Knights: Spanish, Classical Defence, 5.Nxe5n跇$NB32m Sicilian: Lowenthal, 5...a6, 8.Qd1UoXA33q English: Symmetrical, Geller, 7.Nb3 Ne5"dB44e Sicilian: Taimanov, 5.c4 Nf6 6.Nc3 Bb4 7.Nxc6wF6]{LD13s Slav: Exchange, 6.Bf4 e6 7.e3 Bd6s:d3rB08u Pirc: Classical, 5.Be2 O-O 6.O-O Bg4 7.Be3 Nc6 8.Qd2rtCB34s Sicilian: Accelerated Fianchetto, Modern, 6.Be3 Nf6 7.Nxc6 bxc6 8.e5 Ng8o< zVD85c Grnfeld: Exchange, 5.Bd2 Bg7 6.e4 Nb6iNÍ^LA66 Benoni: Four Pawns, Mikenas AttackcYFD52b QGD: Cambridge Springs Defence_ 3t<D00t Blackmar-Diemer: 3...dxe4],XtcDC44x Scotch Gambit: London DefenceYMr\B44r Sicilian, Taimanov, Szen, 7.N1c3 a6 8.Na3Qx]Q.dE12n Queen's Indian: Petrosian, 5.Nc3 d5 6.Bg5 Be7QB1x ZC93 Spanish: Closed, Smyslov, 10.d4 Re8 11.a4P2nLA26 English: Botvinnik System, 6...Nf6N)uR>!8C70 Spanish: Alapin DeferredKr=$E01 Catalan: 4.Bg2K%eibC14h French: Classical, Steinitz, 7...a6 8.Nf3 c5HCΤ4D11e Slav: 3.Nf3 dxc4 4.e368JC92o Spanish: Closed, Zaitsev, 12.Bc26%d4D.D24b QGA: 4.Nc3 e6 5.e43EHLD32o QGD Tarrasch: 5.Nf3 Nc6 6.Bf4 Nf6-{ )tG&D06a Queen's Gambit(utKHA57s Benko Gambit: Zaitsev, 5...axb5LbA39f English: Symmetrical, Main Line 7.d4, 8...a6|C76 Spanish: Modern Steinitz, Bronstein, 7.O-O Bg7 8.dxe5 Nxe5ٳOtA00i Saragossa |SZHE05b Catalan: Open, Classical, 6.Nc3 ,IxB90u Sicilian: Najdorf, 6.Be3 e5 7.Nb3 Be6 8.f3 Be7 9.Qd2 b5I>uXE84a King's Indian: Smisch, Panno Main LineK>TPC44g Open Game: Inverted Philidor, 4.Be2{6B08h Pirc: Classical, 5.Be3v+õdC57a Two Knights: Traxler (Wilkes-Barre) Variationፆ ^C64u Spanish: Classical, 6.c3 Bb6 7.d4 c6 8.Ba4Q9/[8A20 English: King's, 2.g3 g6 8}dA79 Benoni: Classical, Main Line, 10.Nd2 Na6 11.f3ͥ%"aVA23 English: Bremen, Keres, 4.Bg2 d5 5.cxd5EjC79 Spanish: Steinitz Deferred, Boleslavsky Variation𻾟n^E14g Queen's Indian: 4.e3 Bb7 5.Bd3 Bb4+ 6.Nbd2 myxD21q QGA: 3.Nf3 c5 4.d5 e6 5.Nc3 exd5 6.Qxd5 Qxd5 7.Nxd5 Bd6_$OFE18g Queen's Indian: 7.Nc3 d5 8.Ne5mZB21y Sicilian: Smith-Morra, 5.Nf3 d6 6.Bc4 e6_n@<A11 English: Caro-Kann DefenceCsq6A16 English: Anglo-GrnfeldoKlOfHB58a Sicilian: Boleslavsky VariationPUA05 Reti: KIAz`A41s Neo-Old Indian: Modern, Rossolimo Variation_^&ܣ8A04 Reti: Lisitsin: 3.Ng5 d5QvB45l Sicilian: Taimanov, Four Knights, 6.Nxc6 bxc6 7.e5 Nd5HDE87n King's Indian: Smisch, Orthodox, 7.d5 Nh5 8.Qd2 f5 9.O-O-O Nd7 10.Bd3G>XTK=tE11v Bogo-Indian: Nimzowitsch, 5.g3 Nc6 Main Line, 8...O-O>SgC8A41m Neo-Old Indian: 2.c4 e5=-a!RC59c Two Knights: Morphy, Main Line 9.Nf3<_%HE17p Queen's Indian: 6.O-O O-O 7.Re1;OJD00q Queen's Pawn: Anti-King's Indian8N*`E59 Nimzo-Indian: Main Line, 9.bxc3 dxc4 10.Bxc41~M<A08 Reti: KIA, 2...c5 + 3...g6'xQr2`D36m QGD: Exchange, Main Line, 9.Nge2 Re8 10.O-O'l՘N\E22 Nimzo-Indian: Spielmann, 4...c5 5.dxc5 Na6#a=!\C32 KGD: Falkbeer, 5.dxe4 Nxe4 6.Nf3 Bc5 7.Qe2 -\=bC21 Centre Game: Maroczy Defence, Philidor Gambit~UNA87 Dutch: Leningrad, Main Line, 6...c6\K]rB31l Sicilian: Rossolimo, 3...g6 4.O-O Bg7 5.Re1 Nf6 6.c3d "dE84k King's Indian: Smisch, Panno Main Line, 9.h4ɟ_YJD06c QGD: Austrian, Rubinstein, 4.Nf3bdgZD61 QGD: Orthodox, Rubinstein, 7.Qc2 c6 8.Rd1)lBRA29 English: Four Knights, 4.g3 Bb4 5.Bg2 \Z>A08 Reti: KIA, French VariationkdC84n Spanish: Closed, Centre Attack, 7.Re1 b5 8.e5j״>D10t Slav: 3.Nc3 Nf6 4.Bg5 dxc4?$@A15 English: Anglo-Indian, 2.Nf3ZE95j King's Indian: 7.O-O Nbd7 8.Re1 c6 9.Bf10]+P`E14n Queen's Indian: 4.e3 Bb7 5.Bd3 d5 6.O-O Bd6>&JA57g Benko Gambit: 4.Nf3 g6 5.cxb5 a6SqE LC03o French: Tarrasch, Guimard, 4.Ngf3d{JLD74 Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O c6˻e@@B15f Caro-Kann: Gurgenidze: 4.e5@{5tx^C06d French: Tarrasch, Closed, Leningrad, 9.O-OrND97e Grnfeld: Russian, Alekhine, 8.Be2ĵiHC42p Russian Game: Classical, 5...d5|!@_<E91q King's Indian: 6.Be2 Nbd7RJFrC98h Spanish: Closed, Chigorin, 12...Nc6 13.d5 Nd8 14.Nf1\9'6A56c Benoni: 2...c5 3.e3 g6tTA82 Dutch: Staunton Gambit, Balogh DefenceovC19o French: Winawer, 6...Ne7 7.Nf3 Nbc6 8.a4 Qa5 9.Qd2 Bd7xPZ>A30a English: Symmetrical, 2.g3abA40c Queen's Pawn: Polish Defence, Spassky Gambit 7S,A05 Reti: KIA, Spassky'?HA12 English: Caro-Kann Defence, 3.b3fNC42d Russian-Three Knights Game, 4.Nxe5:w >D90 Grnfeld: Schlechter, 5.Qb3p#]zXC30j KGD: Classical, Senechaud Countergambito׺$/4A45a Indian: Gedult Attackid)0D31o Semi-Slav: 4.e3 Nf6iֆ \A28 English: Four Knights, Nenarokov Variationi#>6HD18r Slav: Dutch, 8...O-O 9.Nh4 Nbd7h0iUd4C25f Vienna: 2...Bc5 3.Nf3euHA90 Dutch: 2.c4 Nf6 3.g3 e6 4.Nf3 d5UaNA35g English: Symmetrical, Four KnightsR ^E92u King's Indian: Petrosian, Stein, Main LineN:F5<E08b Catalan: Closed, 7.Qc2 c5Mdb?~2A03 Bird: 1...d5 2.Nf3 g6L~MNQBC02c French: Advance, Wing GambitK+y9&iXE98h King's Indian: Mar del Plata, 9.Ne1 Nd7HLbVA83l Dutch: Staunton Gambit, 4.Bg5 Nc6 5.d5F-1\E56 Nimzo-Indian: Main Line, 7...Nc6 8.a3 cxd4%HD83 Grnfeld: Grnfeld Gambit, 6.Qb3U\C67m Spanish: Open Berlin, Showalter Variation<A52e Budapest: Adler VariationUJFB06s Modern: Pseudo-Austrian Attack/5C~]A05 Reti: KIA3NHC32 KGD: Falkbeer, 5.dxe4 Nxe4 6.Be3PㅔGTD66 QGD: Orthodox, Main Line, 8...h6 9.Bh4=b)}NC52 Evans Gambit: 5...Ba5 6.O-O d6 7.d4׬0{2D65 QGD: Orthodox, Rubinstein, 9.cxd5 exd5 10.Bd3 Re8 11.O-O Nf8V[*@E11g Bogo-Indian: 4.Bd2 Be7 5.g3Bg7<A90 Dutch: Dutch-Indian, 5.Nc3%VB56i Sicilian: Open, 2...d6, 5.Nc3 Nc6 6.h3"CN B07h Pirc: 3.Bd3p~5DC63a Spanish: Schliemann (Jnisch)sjB48s Sicilian: Taimanov, 6.Be3 a6 7.Bd3 Nf6 8.O-O Ne5Q!DC80k Spanish: Open, Harksen Gambit9IfqJE46 Nimzo-Indian: Reshevsky Variation HD46g Semi-Slav: Chigorin, 7.Qc2 dxc4 ]qjD77i Neo-Grnfeld, 6.O-O dxc4 7.Na3 c3 8.bxc3 c5 9.e3K|PD48o Semi-Slav: Meran, Reynolds, 10...c4=^VZD31u Semi-Slav: Noteboom, Abrahams, Main Line1_EHC80e Spanish: Open, 6.Re1 Nc5 7.Bxc6|%5S\C42x Russian Game: Classical, Krause Variation3/u?^B31h Sicilian: Rossolimo, 3...g6 4.O-O Bg7 5.c3aKNB03n Alekhine: Four Pawns Attack, 7.Be3C&u+<D31e QGD: Alatortsev, ExchangeuǾqR>eDE91p King's Indian: 6.Be2 Nc6 7.d5rm]mLE24 Nimzo-Indian: Smisch, 5...d5 6.f3q >D15k Slav: Chameleon, 5.c5 Nbd7p#xB90j Sicilian: Najdorf, 6.Be3 Ng4 7.Bg5 h6 8.Bh4 g5 9.Bg3 Bg7 10.Be2lQn]nA44k Old Benoni: Czech, 3.c4 d6 4.e4 g6 5.Nc3 Bg7 6.Bd3lH/LA64 Benoni: Fianchetto, 11...Re8 12.a5\)FD02i Queen's Pawn: 2.Nf3 e6 3.g3 c5W7|$'tC08e French: Tarrasch, Open, 4.exd5 exd5 5.Bb5+ Bd7 6.Qe2+QJ#XfC45t Scotch: 4.Nxd4 Bc5 5.Nxc6 Qf6 6.Qd2 dxc6 7.Nc3PۣVB48m Sicilian: Taimanov, 6.Be3 a6 7.Bd3 Nf62UARblA37v English: Symmetrical, 5.Nf3 e5 6.O-O d6 7.d3 Nge7(r *|C93 Spanish: Closed, Smyslov, 12.Nf1 Bb7 13.Ng3 Na5 14.Bc2 Nc4tGBXLB01w Scandinavian: Marshall, 4.Nf3 Bg4gMަ%ND32c QGD Tarrasch: 4.Nf3 cxd4 5.Nxd4 e5g,A48d Neo-King's Indian t8B93a Sicilian: Najdorf, 6.f4w^zE81p King's Indian: Smisch, 5...O-O 6.Be3 c5 7.Nge2 Nc6 8.d5B9A29 English: Four Knights, 4.g3 d5 5.cxd5 Nxd5 6.Bg2 Nb6 7.O-O Be7 8.d3C5eBB12p Caro-Kann: Advance, 4.Nf3 e6vpm2D16f Slav: Smyslov, 6.Ne5S58A45k Trompowsky 2...g6 3.Nc3>{~8B28f Sicilian: O'Kelly, 3.c4x6P>D45u Semi-Slav: 6.Qc2 Bd6 7.Bd2 e)B26D11m Slav: Slav-Reti SystemrXB94j Sicilian: Najdorf, 6.Bg5 Nbd7 7.Bc4 Qa5GAklB66g Sicilian: Richter-Rauzer, 7...a6 8.O-O-O h6 9.Bf4͘$B:D35i QGD: Exchange, 5.Bg5 Be7ת0A10 English: Anglo-DutchԸ hB76r Sicilian: Dragon, Yugoslav, 9.O-O-O d5: 12.Nxd5ٯRA52d Budapest: Alekhine, Abonyi Variation#nʞA14 English: Neo-Catalan Declined, 5...O-O 6.b3 b6 7.Bb2 Bb7 8.e3ɊźQSBB01b Scandinavian: 2...Qxd5 3.Nf3vZJA17 English: Nimzo-English, 4.Qc2 O-Oa<E20 Nimzo-Indian: 4.f3 (Kmoch)=gCXD50 QGD: Semi-Tarrasch, Pillsbury, 6.Nxd4 e5SU/|D25r QGA: Janowski-Larsen, 6.h3 Bh5 7.Nc3 Nbd7 8.O-O Bd6 9.Be2Q <A00o Grob Gambit: Hurst Attack>G-5hB31k Sicilian: Rossolimo, 3...g6 4.O-O Bg7 5.Re1 Nf6$m(vC16i French: Winawer, Petrosian, 5.a3 Bxc3+ 6.bxc3 b6 7.Qg4"BB15j Caro-Kann: Gurgenidze: 4.Nf3֢M.$A00c Kadas Opening\7vhE88b King's Indian: Smisch, Orthodox, 7.d5 c6 8.Qd2~C69g Spanish: Exchange, Gligoric, 6.d4 Bg4 Queenswap, 9.Rd3 Bd6{bx3.:C40h Elephant Gambit: MaroczyzY§f6C34 KGA: Fischer, Main Linen@8A20 English: King's, 2.g3 g6l nE܋&A25 English: Closedk%E:xC19q French: Winawer, 6...Ne7 7.Nf3 Nbc6 8.a4 Qa5+ 9.Bd2 Bd7i}Ϊ7PD53n QGD: 4.Bg5 Be7 5.Nf3 O-O 6.Qc2 Nbd7bR^B62c Sicilian: Richter-Rauzer, 6...e6 7.Be2 Be7`BZE62f King's Indian: Fianchetto, Larsen System\XĶTB42b Sicilian: Kan, Swiss Cheese VariationP~gX&A51b Budapest: 3.e3I 9lfA37y English: Symmetrical, 5.Nf3 e5 6.O-O Nge7 7.d3E_ BA57t Benko Gambit: Zaitsev, 8.Nf3APVDB15t Caro-Kann: 4.Nxe4 Nf6 5.Nxf6+=Z#1ATA13v English: Neo-Catalan Accepted, 5.Qa4+7b؈8RD39h QGD: Ragozin, Vienna, 6.e4 c5 7.Bxc42&73FA22 English: Bremen, Reverse Dragon/潆U<A45q Trompowsky: 2...c5 3.Bxf6"{"KdB78e Sicilian: Dragon, Yugoslav, Main Line, 12.Kb1cHA96 Dutch: Classical, 7.Nc3 a5 8.Re1]ےB97p Sicilian: Najdorf, Poisoned Pawn, 10.e5 dxe5 11.fxe5 Nfd7 12.Bc4 Bb4.+[9^C92i Spanish: Closed, Zaitsev (Flohr) Variation}*A03 Bird: 1...d5 2.g3V(<A90 Dutch: Dutch-Indian, 5.Bd2GW ZB08q Pirc: Classical, 5.Be2 O-O 6.O-O c6 7.h3k@HB36c Sicilian: Maroczy Bind, 5...Nf6sdTO^E71h King's Indian: Makagonov, 5...O-O 6.Bg5 c6+PE08h Catalan: Closed, 7.Qc2 c6 8.Bf4 Nh5UDA36e English: Symmetrical, 3.g3 g6b%zS>D95h Grnfeld: Botvinnik, 7.Bd2bExJC00c French: La Bourdonnais VariationߝzPC90l Spanish: Closed, Pilnik, 12.Nf1 Nc6X6LB13p Caro-Kann: Panov-Botvinnik, 5.Nc3zN@B94c Sicilian: Najdorf, 6.Bg5 e5cYFC52 Evans Gambit: 5...Ba5 6.d4 exd4ATJPA22 English: Bremen, Smyslov, 4.Bg2 Bxc3jv+ZB45k Sicilian: Taimanov, Four Knights, 6.Nxc6Dy&A00a Start position컷vTl&B07c Pirc: 2.f4 Nf69PLbD25o QGA: Janowski-Larsen, 6.h3 Bh5 7.Nc3 a6 8.g4Y |C06o French: Tarrasch, Closed, 8...f6 9.exf6 Nxf6 10.O-O Bd6 11.Nf3`硲NC27e Vienna: 3.Bc4 Nxe4 4.Qh5 Nd6 5.Bb3쓣ؿ#JZE83j King's Indian: Smisch, Panno, 8.Qd2 Re8순͏sxC18s French: Winawer, Poisoned Pawn, Euwe-Gligoric Variation7d5&D12a Slav: 4.e3 Bf5g<4f8D11n Slav: Slav-Reti with b3\i;q*D10o Slav: 3.Nc3 dxc4Yxi tCbD52i QGD: Cambridge Springs, Bogoljubow VariationX91VC33 KGA: Bishop's Gambit, Classical DefenceRbpD64 QGD: Orthodox, Rubinstein Attack, Carlsbad Variation?mLD78n Neo-Grnfeld, 6.O-O c6 7.Nbd2 Bf5=\,RA93 Dutch: Stonewall, Botvinnik Variation9'kn5jA42m Modern: Averbakh, Kotov, 5.Be3 e5 6.d5 Nce7 7.g46Bddr4A00p Polish: 1...Nf6 2.Bb2/HhMglD41m QGD: Semi-Tarrasch, 6.e4, San Sebastian Variation(H_ZB98h Sicilian: Najdorf, Browne, 10.O-O-O Nbd7!'$&A25 English: ClosedvEZE85b King's Indian: Smisch, Orthodox, 7.dxe5|M)RA86 Dutch: Leningrad, 4.Bg2 Bg7 5.Nc3 O-O!y lB04m Alekhine: Modern, Fianchetto, 5.Bc4 Nb6 6.Bb3 Bg7 B35n Sicilian: Accelerated Fianchetto, Modern, 7.Bc4 O-O 8.Bb3 a5 9.f3IlE39l Nimzo-Indian: Classical, Pirc, 6.a3 Bxc5 7.Nf3 b67J^6B70b Sicilian: Dragon, 6.g3{cgFB57g Sicilian: Sozin, Benko, 7.Nxc6iLA93 Dutch: Stonewall, Botvinnik, 8.Qc2$I&8A65l Benoni: Smisch, 8.Nge2OOL&A00r Polish: 1...e5Y٩jA39o English: Symmetrical, Main Line 7.d4, 10.Qd3 Rb8)XT )sVC41s Philidor: Improved Hanham, 6.dxe5 dxe5ᾕq'v2A40b Queen's Pawn: Jadoul룋'Ê8C26q Vienna: 3.Bc4 Bc5 4.Nf31A22cxB04o Alekhine: Modern, Fianchetto, 5.Bc4 Nb6 6.Bb3 Bg7 7.Ng5U'mJE80a King's Indian: Smisch Variation˨c B58t Sicilian: Boleslavsky, 7.Nf3, 9.Re1 O-O 10.h3 Be6 11.Bf1 Nb8 12.b3-e]DD63 QGD: Orthodox, Swiss Variation(93PA16 English: Anglo-Indian, 2.Nc3 g6 3.g3|إVC57m Two Knights: Fritz, Berliner VariationoE&FE11g Bogo-Indian: 4.Bd2 Be7 5.g3 d5m,pxjE18z Queen's Indian: Old Main Line, 8.Qc2 Nxc3 9.bxc3lNR|BE70c King's Indian: 4.e4 O-O 5.e5fm/2D02o Queen's Pawn: LondondnUۋ`vE54 Nimzo-Indian: Main Line, 7...dxc4 8.Bxc4 cxd4 9.exd4 a6c1n|lB99n Sicilian: Najdorf, Main Line, 10.g4 b5 11.Bd3 Bb7c%+@C42k Russian Game: French AttackW}{k<VA77 Benoni: Classical, Main Line, 10.Nd2 a6Ty \B04h Alekhine: Modern, Larsen, 5.Nxe5 g6 6.Bc4Jv,{nFA28 English: Four Knights, 4.e3 Bb4C2nbB78d Sicilian: Dragon, Yugoslav, Modern Main LineA>=a*^C07k French: Tarrasch, Open, 4.exd5 Qxd5 5.Ngf3ANB96i Sicilian: Najdorf, 7.f4 Nbd7 8.Qe2:#xvrB37j Sicilian: Maroczy Bind, 6.Nc2 Nf6 7.Nc3 d6 8.Be2 Nd78#s(3>B25f Sicilian: Closed, 6.f4 Rb8*giRB22t Sicilian: Alapin, 2...Nf6, 5.cxd4 d6(Bb| >C28e Vienna: 3.Bc4 Nc6 4.d3 Na5V@kbB65a Sicilian: Richter-Rauzer, 7...Be7, 9.f4 Nxd4G8B91a Sicilian: Najdorf, 6.g3 Rj.JE46 Nimzo-Indian: Reshevsky VariationoRgs<A08 Reti: KIA, 2...c5 + 3...g6A()4D28a QGA: Classical, 7.Qe2i^,A44a Old Benoni: CzechTk<D03e Torre Attack: 3...e6 4.e3!ǹ"6C54a Giuoco Piano: 4.c3 Nf6Ӵk;2B96w Sicilian: Najdorf, Polugaevsky, 10.Qe2 Nfd7 11.O-O-O Bb7 12.Qg4 Qxe56>uvE14x Queen's Indian: 4.e3 Bb7 5.Bd3 c5 6.O-O Be7 7.Nc3 cxd4ҁ-Ԣ:D30u QGD: Semmering Variation!k^B73 Sicilian: Dragon, Classical, Zollner Gambitk`'/JB01s Scandinavian: 2...Nf6 3.Bb5+ Bd7M:B20 Sicilian: English, 2...e6-;yBA90 Dutch: 2.c4 Nf6 3.g3 e6 4.Nf370@C26o Vienna: 3.Bc4 Bb4 4.Nf3 O-O귣dTC64q Spanish: Classical, Zaitsev VariationVA19 English: Mikenas, 6.d4 cxd4 7.Nxd4 Nxe5ꢱn/`E12r Queen's Indian: Petrosian, 6.cxd5 Nxd5 7.e4U$D50 QGD: 4.Bg5 Bb4ꛎw):C29q Vienna Gambit: 5.Nf3 Nc69ZB56e Sicilian: Open, 2...d6, 5.Nc3 Nbd7 6.Bc4ꌗLxx8D17m Slav: Central, 7.f3 Bb4ꃲ=44A25 English: Closed, 5.Rb1 6IbC48k Four Knights: Rubinstein, Exchange Variation}|w3NB03p Alekhine: Exchange, 5...exd6 6.Nc3w#xA29 English: Four Knights, 4.g3 d5 5.cxd5 Nxd5 6.Bg2 Nb6 7.O-O Be7t;XC16k French: Winawer, Advance, 4...Ne7 5.Bd2tJZA34 English: Symmetrical, 3 Knights, 5.e4 Nb4cafXA37u English: Symmetrical, 5.Nf3 e5 6.O-O d6]tWr A04 Reti: 1...c5U^YLbB78g Sicilian: Dragon, Yugoslav, Main Line, 12.h4T3-FYLA41r Neo-Old Indian: Modern, 3.Nf3 Bg7QwS `C13n French: Chatard-Alekhine, Maroczy Variation?@B8BD33h QGD Tarrasch: Swedish, 9.Bd2:RX0PJA98 Dutch: Ilyin-Zhenevsky, 8.Qc2 Qh5/{arD23n QGA: Mannheim, 4...c6, 5.Qxc4 Bf5 6.g3 e6 7.Bg2 Nbd7,`AU,PB12n Caro-Kann: Advance, Short Variation%*-@B15e Caro-Kann: Gurgenidze: 4.h3 vDLlD03t Torre Attack: 3...g6 4.e3 Bg7 5.Nbd2 O-O 6.Bd3 c5`ѐLQ:D36c QGD: Exchange, 6.Qc2 Be7X5r8dD36p QGD: Exchange, Main Line, 9.Nf3 Re8 10.h3 Nf8 Ņy.nD76d Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O Nb6 8.Nc3 Nc6 9.e3^7"LD31y Semi-Slav: Marshall Gambit, 8.Be235ʨ%ZC98b Spanish: Closed, Chigorin, Rauzer Attack9L+GtD85x Grnfeld: Modern Exchange, 8.Be3 O-O 9.Rc1 Qa5 10.Qd2Yv)HC44a Open Game: Paschman Wing GambitݏVHWB67o Sicilian: Richter-Rauzer, 7...a6, 9.f4 b5 10.Bxf6 gxf6 11.Nxc66dE05q Catalan: Open, Classical, 8.Qxc4 b5 9.Qc2 Bb7>Z8D33m QGD Tarrasch: 7.Bg2 Be68X\9pE96 King's Indian: 7.O-O Nbd7, Old Main Line, 10.Rb1 Re8БfB27o Sicilian: Accelerated Pterodactyl, 4.dxc5 Qa5+齩.8RC01f French: Exchange, 4.c4 Nf6 5.Nc3 Be7鱸Z 2A20 English: King's, 2.e3= DB57i Sicilian: Sozin, Benko, 7.Nb3FGZD60 QGD: Orthodox, Botvinnik, 8...c5 9.O-O a6ME38j Nimzo-Indian: Classical, 4...c5 5.dxc5 Na6 6.a3 Bxc3+ 7.Qxc3/UZA42j Modern: Averbakh, Kotov, 5.Be3 e5 6.Nge2~-X75VE16c Queen's Indian: Capablanca, 6.Nbd2 O-OhQ&vTC30k KGD: Classical, Soldatenkov Variation9b{xE15n Queen's Indian: Nimzowitsch, 5.b3 Bb7, 7...a5 8.O-O O-O|I|ZB51i Sicilian: 3.Bb5+ Nd7 4.d4 Nf6 5.Nc3 cxd4evI}d$A81 Dutch: 2.g3 e6WIJLE15u Queen's Indian: 4.g3 Bb7 5.Bg2 c5q|C{`D97f Grnfeld: Russian, Alekhine, 8.Be2 b5 9.Qb3m`#v<A11 English: Caro-Kann DefencefV_^C83 Spanish: Open, Classical, Breslau Variationb{Ӯ+=nB97g Sicilian: Najdorf, Poisoned Pawn, 8.Nb3 Nbd7 9.Qf3Uoy)DD32l QGD Tarrasch: Marshall GambitS&SFwB99y Sicilian: Najdorf, Modern Main Line 13.f5 Nc5 14.f6: Perenyi's 16.Rg1SYР-3/hC15i French: Winawer, Mller-Zhuravlev Gambit, 5.Qg4PWf<B47q Sicilian: Taimanov, 6.Be2N;otFA02 Bird: From Gambit, Lasker, 5.g3IMgE#:B24 Sicilian: Closed, 3.g3 e6EcؔYZC40q Latvian Gambit: Poisoned Pawn, Main LineD wFA95 Dutch: Stonewall, 7.Nc3 c6 8.b3=db2-lD48f Semi-Slav: Meran, 8...a6 9.O-O Bb7 10.e4 c5 11.d543]NLD00w Blackmar-Diemer: 4.f3 exf3 5.Nxf3/?+߇2A40w Queen's Pawn: Modern%6eg&DD20a Queen's Gambit Accepted (QGA)dװgLC80k Spanish: Open, Schlechter Defence^=n&A25 English: Closed$sRA37u English: Symmetrical, 5.Nf3 e5 6.O-OBPA11 English: Caro-Kann Defence, 3.g3 Bg4AޛbC19m French: Winawer, 6...Ne7 7.Nf3 Nbc6 8.a4 Bd7Ѷ<B27f Sicilian: Hungarian, 3.c4`HRB71 Sicilian: Dragon, Levenfish Variationk{fD42h QGD: Semi-Tarrasch, 7.Bd3 Main Line, 10.a3 Nf6C=LB72 Sicilian: Dragon, Classical Attack|PZ$&D31c QGD: 3.Nc3 Bb4nLC10s French: Rubinstein, 4...Bd7 5.Nf3Q{HC79 Spanish: Steinitz Deferred, 6.c3[U,^C42r Russian Game: Classical, Marshall, 8.c4 c6C50e Italian: Hungarian Defence֐pB22j Sicilian: Alapin, 2...d5 3.exd5 Qxd5 4.d4 Nf6 5.Nf3e]|dgBB53l Sicilian, Chekhover, 4...Nc6;7VGJE53 Nimzo-Indian: Main Line, 7...Nbd7 BB40j Sicilian: Marshall Variation /3FA06 Reti: Tennison/Zukertort Gambit葀?4A22 English: Bremen System艈s6EDD29f QGA: Classical, 8...Bb7 9.Rd1ze`x4A41b Neo-Old Indian: 2.Bg5$>C81 Spanish: Open, Keres Attackp[O!<A25 English: Closed, 5.d3 Nge7jֶH :B10c Caro-Kann: Breyer, 3.Nd2glaVE87a King's Indian: Smisch, Orthodox, 7.d5d b0FD17l Slav: Central, Hbner (7...c5)`/9#U6C30g King's Gambit: 2...Nc6^))2x2A45a Queen's Pawn: Indian\2LC19h French: Winawer, 6...Ne7 7.Nf3 b6Xet\C26h Vienna: Smyslov, 3...Bc5 4.Bg2 Nc6 5.Nge2X+ VzRA20 English: King's, Nimzowitsch, 2...Nc6Wb_}>TD41m QGD: Semi-Tarrasch, 6.e4, 8.cxd4 Bb4+R#TDC45j Scotch: Mieses, 6...Qe7 7.Qe2M25TC53 Giuoco Piano: Centre-Holding VariationH'q$VC83 Spanish: Open, Classical, Tarrasch TrapF9DZB36b Sicilian: Maroczy Bind, 5...d6 6.Nc3 Bg7F0>D47a Semi-Slav: Meran Variation4 U2LD85j Grnfeld: Modern Exchange, 7...c5+F9&_xB44v Sicilian, Taimanov, Szen, 7.N1c3 a6 8.Na3 Be7 9.Be2 O-Om2E20 Nimzo-Indian: 4.f3 d5Q8b2A46r Torre Attack: 3...b6w#0D91d Grnfeld: 5.Bg5 Ne4ofQ_tE69h King's Indian: Fianchetto, Classical, 9.h3 Qa5 10.Re1 |]yTC12j French: MacCutcheon, Lasker Variationkp~|C43k Russian Game: Modern Attack, 3...Nxe4 4.Bd3 d5 5.Nxe5 Nc6%ɃN)8E04e Catalan: Open, 5.Nf3 a6Y_ rB09x Pirc: Austrian, 5...c5 6.Bb5+ Bd7 7.e5 Ng4 8.e6 Bxb5OlE(NC18l French: Winawer, 6...Ne7 7.Qg4 Kf8LR^C42t Russian Game: Classical, Jnisch VariationƍXlJD32r QGD Tarrasch: 5.Nf3 Nc6 6.e3 Nf6%1NUhA91 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nf3 d6 6.Nc3OHNHD38f QGD: Ragozin, 5.cxd5 exd5 6.Bg5OU #DB42h Sicilian: Kan, 5.Bd3 Nf6 6.c4S$DB01j Scandinavian: 2...Qxd5, 5.Nf3NӁShC30e King's Gambit: Norwald Variation, Bcker Gambitn4B06h Modern: Geller System稳'RD85l Grnfeld: Modern Exchange, 8.Be2 O-O fE19c Queen's Indian: Old Main Line, 9.Qxc3 d6 10.b3p@tbB77g Sicilian: Dragon, Yugoslav, 9.Bc4 Bd7 10.Bb3琱Y!i9DC67f Spanish: Open Berlin, 5...Be7珲A GrD36q QGD: Exchange, Main Line, 9.Nf3 Re8 10.h3 Nf8 11.Bf4瀗XJB44p Sicilian, Taimanov, Szen, 7.N5c3xW5PPA81 Dutch: Leningrad, Carlsbad Variationt84D02s Queen's Pawn: 3.g3 c6p%_bC09d French: Tarrasch, Open, 5.Ngf3 Nc6 6.Bb5 Bd6lq0x*HB95c Sicilian: Najdorf, 6...e6 7.Be2iHhNB16e Caro-Kann: Bronstein-Larsen, 6.Nf3e{|E61z King's Indian: Smyslov System, 5...O-O 6.e3 Nbd7 7.Be2 c6ahL tE93 King's Indian: Petrosian, Main Line, 8.Bg5 h6 9.Bh4 a6^4aY8D11n Slav: Slav-Reti with b3W =LHE11f Bogo-Indian: Grnfeld VariationSi.^;Cc~B83 Sicilian: Scheveningen, Modern, 9.f4 e5 10.Nb3 exf4 11.Bxf4R>IA^C96n Spanish: Closed, Chigorin, Keres VariationRz~)-HC92j Spanish: Closed, Zaitsev, 10.d4Ij`B25v Sicilian: Closed, 6.f4 e6: 9.Be3 Nd4 10.Qd2I@=܊8D21s QGA: Seirawan VariationGc n(HE90h King's Indian: Larsen VariationFe%[HB19g Caro-Kann: Classical, 7.Nf3 Nd7?O>>lC47x Four Knights: Scotch, Main Line, 10.Bg5 c6 11.Qf3>SsLfA59n Benko Gambit: 7.e4, Main Line, 11...Nbd7 12.h3;intA45z Trompowsky: 2...Ne4 3.Bf4 c5 4.f3 Qa5+ 5.c3 Nf6 6.Nd2-YUFD19g Slav: Dutch, 8...O-O 9.Qe2 Ne4'w'T\HvD36v QGD: Exchange, Main Line, 9.Nf3 Re8 10.O-O Nf8 11.Rae1$dU_2B89 Sicilian: Velimirovic"ܸFC12p French: MacCutcheon, Main LineiCh :D41k QGD: Semi-Tarrasch, 6.e4yP BC29d Vienna Gambit: 3...d5 4.exd5xi,A40a Queen's Pawn GamedQvbD58i QGD: Tartakower, 8.Bd3 Bb7 9.O-O Nbd7 10.Qe2 ȃܛJE54 Nimzo-Indian: Main Line, 7...dxc4HZC16d French: Winawer, 4.e5 b6 5.Qg4 Bf8 6.Bg5]Ii|D87o Grnfeld: Classical Exchange, 10.Be3 Bg4 11.f3 Na5 12.Bd5wPgēJD00u Blackmar-Diemer: O'Kelly Defence PD30i QGD: Tarrasch without Nc3: 5.g3 Nc6ڔu TA90 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 d5 5.Nf3oNyunB32x Sicilian: Lowenthal, Kalashnikov, Main Line, 9.Nc2ʷ)ND28i QGA: Classical, 7.Qe2 b5 8.Bb3 Nc6/*g%`B12t Caro-Kann: Advance, 4.Nf3 e6 5.Be2 c5 6.O-Oem|JE03 Catalan: Open, 5.Qa4+ Nbd7 6.Qxc4y JE98p King's Indian: Mar del Plata, 9.Ne1 Nd7 10.Nd3 f5 11.Bd2 Kh8ED65 QGD: Orthodox, Rubinstein, 9.cxd5 exd5 10.Bd3 Re8 11.O-O Nf8 12.Ne5X0JC21 Danish Gambit: Schlechter Defence榒Wh1NC03n French: Tarrasch, Guimard, 4.c3 e5eW8VA33o English: Symmetrical, Geller VariationQQQBD85a Grnfeld: Exchange VariationPA,KNB14i Caro-Kann: Panov-Botvinnik, 5...e6ُl.D06l QGD: 2...Bf5 3.Qb3726A09e Reti: Advance, 3.e3 c5yQ;j0fE67i King's Indian: Fianchetto, Classical, 8.Qc2 c6|DC51 Evans Gambit: Normal Variation恠[eBA45t Trompowsky: 2...Ne4 3.Bh4 c5_ <8D16e Slav: Smyslov Variationj:)"&A10 English: 1...b6L5|Q,:A00p Polish: 1...Nf6 2.Bb2 e6>l7 2D30l QGD: 3.Nf3 c6 4.Nbd2>XV-yNA75 Benoni: Classical, 9.O-O a6 10.a4 Bg4 11.Bf4 Bxf3 12.Bxf3 Qe7 13.Re1=Pz9RA68n Benoni: Four Pawns, 9.Be2 Bg4 10.O-O Nbd7 11.h3 Bxf3 12.Bxf3 Re8 13.Re1C52 Evans Gambit: 5...Ba5 6.O-O6y$JE05p Catalan: Open, Classical, 8.Qxc459ȁ`kXC47m Four Knights: Belgrade Gambit, 5...Nxe45Z. pBB23o Sicilian: Closed, Grand Prix04,dA88 Dutch: Leningrad, Main Line, 7.Nc3 c6 8.b3 Qa5/='SPB03k Alekhine: Four Pawns Attack, 6...c5(6EjB49h Sicilian: Taimanov, 6.Be3 a6 7.Be2 Nf6 8.O-O Bb4 Q-0A10 English: 1...g5 2.d4dʜp]\E30 Nimzo-Indian: Leningrad, 4...c5 5.d5 Bxc3+ HHA30e English: Symmetrical, b6 System 6I^B62h Sicilian: Richter-Rauzer, Margate, 7...Bd7@A72 Benoni: Classical, 8.Be2 O-O 9.Bg5 h6 10.Bh4 g5 11.Bg3 Nh5 12.Nd2ERD85u Grnfeld: Modern Exchange, 8.Be3 Qa51VB21i Sicilian: Grand Prix, Toilet VariationX=\+8A09h Reti: Advance, 3.g3 Nc6J:C45q Scotch: Geller Variationn)tJB26c Sicilian: Closed, 6.Be3 Nf6 7.h3RѧHC47s Four Knights: Scotch, Main Linea?HA30e English: Symmetrical, b6 System5(B07c Pirc: 2.f4W+XE32i Nimzo-Indian: Classical, Adorjan GambitGrE31o Nimzo-Indian: Leningrad, Main Line, 8...e5 9.f3 Nbd7 ?JB01y Scandinavian: Marshall, 4.c4 Nb6)!\tBB53e Sicilian, Chekhover, 4...Bd7HHC51 Evans Gambit Declined, 5.b54-@C85q Spanish: Closed, Exchange, 7.d3 Nd7 8.Nbd2 O-O 9.Nc4 f6 10.Nh4 Nc534lD37r QGD: Classical, 5...O-O 6.e3 c5 7.dxc5 Bxc5 8.Qc2ԶǪZA35g English: Symmetrical, Four Knights, 4.d4.Y|B97o Sicilian: Najdorf, Poisoned Pawn, 10.Bxf6 gxf6 11.Be2 Bg7jyPE17k Queen's Indian: Opovcensky, 7...Bf65 #NB96f Sicilian: Najdorf, 7.f4 Qc7 8.Bxf6/|PdB76i Sicilian: Dragon, Yugoslav, 9.O-O-O Bd7 10.g4QDffXB19h Caro-Kann: Classical, Spassky VariationD RjB19l Caro-Kann: Classical, Spassky, 10.Qxd3 e6 11.Bf4ҍ0a\C15o French: Winawer, Alekhine Gambit, 4...Nf6@ߖqz2C45k Scotch: Mieses, 8.c4CD XA51e Budapest: Fajarowicz, Steiner VariationWᳶX`A46o Indian: 1.d4 Nf6 2.Nf3 e6 3.g3 c5 4.Bg2 Nc6nCHxB64e Sicilian: Richter-Rauzer, 7.Qd2 Be7, 9.f4 h6 10.Bh4 Bd7dfpC84k Spanish: Closed, Centre Attack, 7.e5 Ne4 8.Nxd4 O-O䵩2<C41j Philidor: 3...exd4 4.Nxd4䴲^C67p Spanish: Open Berlin, 5.d4 Nd6 6.Bxc6 dxc6ptHD27g QGA: Classical, 6...a6 7.Bb3 b5䒀iDD85e Grnfeld: Exchange, 7.Bb5+ c6䉬S*A02 Bird: From Gambit1Rh :A52f Budapest: Adler, 4...Bc5{| O,B07p Pirc: Czech, 4.f4hKۜ<B12p Caro-Kann: Advance, 4.Nf3_)R B07y Pirc: 4.Be2JtG1D:B50g Sicilian: 2.Nf3 d6 3.Bc4G+u5QfA44y Old Benoni: Czech, 3.e4 d6 4.Nc3 Be7 5.Nf3 Bg4E6tzA77 Benoni: Classical, Main Line, 10.Nd2 Nbd7 11.a4 a6 12.Ra3?$ h{nB14l Caro-Kann: Panov-Botvinnik, 5...e6 6.Nf3 Be7 7.Bd33Ÿ4%3D10a Slav: 3.g3/^l@JE66i King's Indian: Fianchetto, Yugoslav Panno, 9...a6 10.Qc2 Rb8}Z<D11e Slav: 3.Nf3 dxc4 4.e3 Be665r0`E92x King's Indian: Petrosian, Stein, Main Line, 10...Qe8 11.O-O Nh7ʧ\B63p Sicilian: Richter-Rauzer, 7.Qd2 Be7, 9.f3ʷJk,A47 Neo-Queen's Indiann|#A81 Dutch: 2.g3 p4B29a Sicilian: NimzowitschqNB38k Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 b6 9.O-O Bb7 10.f3 Qb8 bsND01p Richter-Veresov: 3...Nbd7 4.Nf3 g6XWfLA57q Benko Gambit: 4.cxb5 a6 5.f3 axb5xXAFB27k Sicilian: Hungarian, 3.d4 cxd4aDD13m Slav: Exchange, 6.Bf4 a6 7.e3|wL/PC81 Spanish: Open, Keres Attack, 9...Bc5CJ6D11p Slav: Slav-Reti System5pZJB57j Sicilian: Sozin, Benko, 7.Nb3 e6x :B20 Sicilian: English, 2...d6bT<JE61m King's Indian: 4.Nf3 O-O 5.e3 d6㼂78 pA67a Benoni: Four Pawns, Taimanov (Alatortsev) VariationvB12h Caro-Kann: Gurgenidze/Modern: 3.Nd2 g6 4.Ngf3 Bg7 5.c3㌻/IJ>E10e Neo-Indian: 3.Nf3 a6 4.Nc3㌠Q@RE80k King's Indian: Smisch, 5...a6 6.Be3x^p4dA88 Dutch: Leningrad, Main Line, 7.Nc3 c6 8.b3 Qe8ㆈaLV\E91n King's Indian: Kazakh Variation, 7.O-O c6͘Ɗ6<D24o QGA: Bogoljubow, 7.a4 Bb7ms\qHC41q Philidor: Nimzowitsch Variationg|jBE17s Queen's Indian: Euwe, 7...c5b'7i(A65b Benoni: 6.e4 g6Wu# VB01f Scandinavian: 2...Qxd5 3.Nc3 Qa5 4.Nf3WZk"\A34 English: Symmetrical, 3 Knights, 5.d4 Nxc3NDE{DD00x Blackmar-Diemer: Euwe DefenceHj"XB97d Sicilian: Najdorf, Poisoned Pawn, 8.Qd3@RrB34c Sicilian: Accelerated Fianchetto, Exchange Variation>f<E17a Queen's Indian: 5.Bg2 Be7=>A53 Old Indian: Dus-Khotimirsky71]R>E94j King's Indian: Glek, 8.Re13{4jtC08c French: Tarrasch, Open, 4.exd5 exd5 5.Bb5+ Nc6 6.Qe2+3EY4B24 Sicilian: Closed, 3.g3TÝ~E69m King's Indian: Fianchetto, Classical, 9.h3 Qb6 10.Re1 exd4ƧhXE55 Nimzo-Indian: Main Line, Bronstein, 9.a336;6D31d QGD: Alatortsev, 4.Nf3*ZE56 Nimzo-Indian: Main Line, 7...Nc6 8.a3 Ba5ez8A22 English: Bremen, 3...Bc5 G-^B32t Sicilian: Lowenthal, Kalashnikov, 6.c4 Be7 ʁ\C21 Danish Gambit: Accepted, 4.Bc4 cxb2 5.Bxb2G4C02g French: Advance, 4.c3]A(C02a French: AdvanceoۂXE36 Nimzo-Indian: Classical, Noa, 5.a3 Bxc3+:~:B13z Caro-Kann: Panov-Botvinnik, 5...Nc6, Normal Variaiton, 8.c5=jTBA41f Neo-Old Indian: Wade Defence)TA45v Trompowsky: 2...Ne4 3.Bf4 d5 4.f3 Nf6}UJD58g QGD: Tartakower, 8.Bd3 Bb7 9.O-OYzRE11g Bogo-Indian: 4.Bd2 Be7 5.g3 d5 6.Bg2gXHA42f Modern: Averbakh, 4...Nd7 5.Nf3YhC86j Spanish: Worrall Attack, 7...O-O 8.c3 d5 9.exd5r6DA43u Old Benoni: Schmidt, 3.e4 Nf6O-ogbC46k Three Knights: Steinitz, Rosenthal Variation`cŝ<D03m Torre Attack: 3...g6 4.e3,2A40u Queen's Pawn: ModernLf16E11c Bogo-Indian: 4.Nbd2 b6⫱#E18x Queen's Indian: 7.Nc3 Ne4 8.Nxe4 Bxe4 9.Ne1 Bxg2 10.Nxg2 d5 11.Qa4 dxc4⋆=ONA50l Indian: Queen's Indian AcceleratedSMI>A86 Dutch: Leningrad, 4.Nf3 Bg7} mD]HC87e Spanish: Closed, Averbakh, 7.c3w6Fus2A02 Bird: 1..Nf6 2.Nf3 c5qusa]LC26j Vienna: Smyslov, 3...d5, 5...Nxc3o&+f,A47 Neo-Queen's Indianl6'LC18h French: Winawer, 6...Ne7 7.h4 Qc7j)W8B07v Pirc: 4.Be3, 150 AttackaL!v?2A80u Dutch: Barcza SystemYotu2D45j Semi-Slav: 6.Qc2 Be7UDV>C51 Evans Gambit: Gring AttackUu>TE34 Nimzo-Indian: Classical, Noa, 5.e3 O-OT~)ZA69d Benoni: Four Pawns, Main Line, 10.Nd2 a6J#We.A07 Reti: KIA, Yugoslav8~LA72 Benoni: Classical, 8.Be2 O-O 9.Bf46*(RprE79c King's Indian: Four Pawns Attack, Main Line, 9...Ng460UvB05o Alekhine: Modern, Main Line, 8.h3 Bh5 9.Nc3 O-O 10.Be32wf8B58q Sicilian: Boleslavsky, 7.Nf3, 9.Re1 O-O 10.h3 Be6 11.Bf1 Qa5+lu^B22v Sicilian: Alapin, 2...Nf6, 5.cxd4 e6 6.Nf3HyBD35d QGD: Exchange, 5.Nf3 c6 6.e3dRҼrD46j Semi-Slav: Chigorin, 7.Qc2 Main Line, 9...Qe7 10.Bd2KpIrZC23 Bishop's Opening: Calabrese CountergambitЃMfB21j Sicilian: Grand Prix, Tal Defence, 3.exd5 Qxd56B`E26 Nimzo-Indian: Smisch, 5...c5 6.e3 Nc6 7.Bd3Z2LC29o Vienna Gambit: Kaufmann VariationvFpC40x Latvian Gambit: 3.Nxe5 Qf6 4.d4 d6 5.Nc4 fxe4 6.Nc3˅){VC41s Philidor: Improved Hanham, 6.dxe5 Nxe5sZD87n Grnfeld: Classical Exchange, 10.Be3 Bg4tFWdB99c Sicilian: Najdorf, Main Line, Keres VariationOs;oHD81 Grnfeld: Early Russian, 5...Be6=lFA46u Torre Attack: 3...c5 4.e3 cxd4$ =B69 Sicilian: Richter-Rauzer, 7...a6, 9.f4 Be7 10.Nf3 b5 11.Bxf6 gxf60[zQLB38d Sicilian: Maroczy Bind, 6.Be3 Nf6k*+D89e Grnfeld: Classical Exchange, 14.Rc1 Bxa2 15.Qa4 with 17.Qb4 b6 iD5@D95c Grnfeld: 5.e3 O-O 6.Qb3 c6A!zB17m Caro-Kann: Steinitz, 5.Ng5 Ngf6 6.Bd3, Main Line 10.Qxe4N A04 Reti: 1...c5QAE19o Queen's Indian: Old Main Line, 9.Qxc3 c5 10.Rd1 d6 11.b3 Bf6ᓻj==BhB70p Sicilian: Dragon, 6.Be2 Bg7 7.O-O O-O 8.Re1 Nc65xHC36 KGA: Scandinavian, Modern, 5.Nc3ᄳFA53 Old Indian: Ukrainian, 4.d5 Be7}ʁ~V\C77u Spanish: Wormald Attack, 5...b5 6.Bb3 Be7wQq$ٹB67r Sicilian: Richter-Rauzer, 7...a6, 9.f4 b5 10.Bxf6 gxf6 11.Kb1 Qb6sdB76p Sicilian: Dragon, Yugoslav, 9.O-O-O d5 10.Qe1m^؅}2&A25 English: ClosedkO棲bB80p Sicilian: Scheveningen, Fianchetto Variationi W;dA28 English: Four Knights, Bradley Beach Variationfg]'xE98f King's Indian: Mar del Plata, 9.Ne1 Ne8 10.Be3 f5 11.f3e|WnoTC43f Russian Game: Modern Attack, 3...Nxe4_ NC41v Philidor: Improved Hanham, 7.a4 c6]uj2.C54j Giuoco Piano: 5.d4V0/E%tD66 QGD: Orthodox, Main Line, 8...h6 9.Bh4 dxc4 10.Bxc4 b5PE˥P\C11g French: Steinitz, Brodsky-Jones VariationP09dB22w Sicilian: Alapin, 2...Nf6, 5.cxd4 e6 6.Nf3 d6N31xC24 Bishop's Opening: Urusov Gambit, Forintos/Haag VariationJ\~B79f Sicilian: Dragon, Yugoslav, Old Main Line, 12.h4 Ne5 13.h5GTKtNB49a Sicilian: Taimanov, 6.Be3 a6 7.Be2ADB09r Pirc: Austrian, 5...c5 6.Bb5+@)O[XD63 QGD: Orthodox, 7.Rc1 b6, Duras Variation7N\B01v Scandinavian: Portuguese, 4.f3 Bf5 5.Bb5+)c=@C55g Two Knights: 4.d3 Be7 5.O-O&TD57 QGD: Lasker Defence, Main Line, 11.Qb3$JhB35k Sicilian: Accelerated Fianchetto, Modern, 7.Bc4 O-O 8.Bb3 Qa5I?<TA90 Dutch: 2.c4 Nf6 3.g3 e6 5.Nf3 d5 6.Qc2Eae^B13q Caro-Kann: Panov-Botvinnik, 5...Nc6 6.cxd5^J:B28b Sicilian: O'Kelly, 3.Nc3o<C45v Scotch: Blumenfeld Attack eQOHZVE74b King's Indian: Averbakh, 6...c5 7.dxc5 Q{PE51 Nimzo-Indian: 4.e3 O-O 5.Nf3 d5 6.a3 3b^6E10p Blumenfeld: 5.Bg5 exd5 dӍ^D85m Grnfeld: Modern Exchange, 8.Rb1 O-O 9.Be2 \_JE|`B97q Sicilian: Najdorf, Poisoned Pawn, 10.f5 Nc6hRnB36n Sicilian: Maroczy Bind, 5...Nf6 6.Nc3 d6 7.Be2 Nxd4 8.Qxd4 Bg7 9.Be3 O-OP/)vB51s Sicilian: 3.Bb5+ Nc6 4.O-O Bd7 5.Re1 Nf6 6.c3 a6 7.Ba4*\E66c King's Indian: Fianchetto, Yugoslav Pannohp0C00m French: KIA 2.d3 d5 >B15r Caro-Kann: Alekhine GambitE%ƶB07a Pirc$*A02 Bird: 1..Nf6 2.g3ݍFFR4D10c Slav: Exchange, 4.Bf4Jq\B21n Sicilian: Smith-Morra, Andreaschek Gambit/\e!RC85h Spanish: Closed, Exchange, 7.Qe1 Nd7j/\ XE71e King's Indian: Makagonov, 5...O-O 6.Be3ǰƥn;,D20t QGA: 3.e4 c5 4.d5Zh7K>A08 Reti: KIA, 2...c5 3.Bg2 Nf6ɐmy8(DE61m King's Indian: 4.Nf3 O-O 5.e3h@ND30t QGD: 3.Nf3 Nf6 4.e3 c6 5.Nbd2 Nbd789]2D53c QGD: 4.Bg5 Be7 5.Nf3ວ, ^C66 Spanish: Closed Berlin, Showalter VariationAiND41r QGD: Semi-Tarrasch, 6.e3 Nc6 7.Bc4നj%HD16p Slav: Bronstein, 6.Ne5 Bh5 7.g3Tx܈LA46o Indian: 1.d4 Nf6 2.Nf3 e6 3.g3 c5]>#"9JD66 QGD: Orthodox, Main Line, 8...Re8|HD30i QGD: Tarrasch without Nc3: 5.g3zj>2`B66f Sicilian: Richter-Rauzer, 7...a6 8.O-O-O h6wɶsnB01z Scandinavian: Marshall, 4.c4 Nb6 5.Nf3 g6 6.h3 Bg7r5;@5^B60j Sicilian: Richter-Rauzer, Larsen, 7.Be2 a6j S;UVC40p Latvian Gambit: Svedenborg, 6.Nxg6 Nf6eh4B12g Caro-Kann: 3.Nd2 dxe4eFήXC47l Four Knights: Belgrade Gambit, 5...Nxd5^0PD33p QGD Tarrasch: 7.Bg2 cxd4 8.Nxd4 Be7[r> ^A32 English: Symmetrical, Two Knights, 5.g3 Qc7XےpD74 Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O c5 8.e4 Nf6 9.e5 Nd5IfXC47t Four Knights: Scotch, Main Line, 7...d59QQ@qjD26m QGA: Classical, Furman, 6...a6 7.dxc5 Bxc5 8.O-O5iND38m QGD: Ragozin, 5.Bg5 h6 6.Bxf6 Qxf6.eO|\E20 Nimzo-Indian: Romanishin, 6.Nxd4 O-O 7.Bg2ЖnyLD17r Slav: Central, Main Line, 15.Nxc42&̍\B21j Sicilian: Grand Prix, Tal Defence, 3.exd5,;`PB18q Caro-Kann: Classical, 6.h4 h6 7.Nh3=V>D31w Semi-Slav: Marshall GambitbDC78d Spanish: Mller Defence, 6.c3y !^B36e Sicilian: Maroczy Bind, 5...Nf6 6.Nc3 Nxd4 udXC78u Spanish: Archangelsk, 7.Re1 Bc5 8.c3 d6 PA87 Dutch: Leningrad, Main Line, 7.b3 c6z*F*C44k Ponziani: 3...d5Ƥ*C37 KGA: Muzio Gambit nTRE15m Queen's Indian: Nimzowitsch, 5.b3 d5@[PD16l Slav: Bronstein (Steiner) VariationGc6TB81c Sicilian: Scheveningen, Keres, 6...a6$T=JA86 Dutch: Leningrad, 4.Bg2 Bg7 5.Nh3ڽf:B14s Caro-Kann: Panov-Botvinnik, 5...e6 6.Nf3 Bb4 7.cxd5 Nxd5 8.Qc2?jB47x Sicilian: Taimanov, 6.Be2 a6 7.O-O Nf6 8.Kh1 Be7fOE92w King's Indian: Petrosian, Stein, Main Line, 10...Qe8 11.O-O Bd7A08 Reti: KIA, French Variationr^-bB80u Sicilian: Scheveningen, Fianchetto Variations/f C25a Vienna Game ;2dE60m King's Indian: Fianchetto without Nc3, 6...c6 zC@E11l Bogo-Indian: 4.Bd2 a5 5.Nc3 5;O2A65b Benoni: 6.e4 g6 7.h3 K FC37 KGA: Muzio Gambit, From Defence0ZC48d Four Knights: Spanish, Classical Defence֚36C77j Spanish: Centre Attack֠@C01n French: Exchange, 4.Nf3 Bd6 LrhD65 QGD: Orthodox, Rubinstein, 9.cxd5 exd5 10.Bd3 h67xtC69l Spanish: Exchange, Gligoric, 8.Nb3 Queenswap, 9...Bd7v DRRE83h King's Indian: Smisch, Panno, 8.Nc12L1ZHA96 Dutch: Classical, 7.b3 Qe8 8.Bb2)+6\C47r Four Knights: Scotch, 4...exd4 5.Nxd4 Bb4>dD83 Grnfeld: Grnfeld Gambit, Botvinnik Variation_8^vB67m Sicilian: Richter-Rauzer, 7...a6, 9.f4 b5 10.Bxf6 gxf6 =q@B03g Alekhine: Four Pawns Attack޼Zm>D94 Grnfeld: 5.e3 O-O 6.Bd3 c6޸\gHD68 QGD: Orthodox, Classical, 13.Bb3޷ߜONE09b Catalan: Closed, Main Line, 8...b5޷4ZHC41i Philidor: Morphy, 4...Nf6 5.Nc3ޫ\c#<D08 QGD: Albin, 4.Nf3 Nc6 5.a3ީt A04 Reti: 1...c5ޤ8A00p Polish: Schhler Gambitޤ"r,A47 Neo-Queen's Indianޡ hA70o Benoni: Classical, 8.h3 O-O 9.Bd3 Re8 10.O-O c4ޞQiJ:B12m Caro-Kann: Advance, 4.h4ޝgGVB80g Sicilian: Scheveningen, English Attackޝ [gț`B46q Sicilian: Taimanov, 5...a6 6.Be2 Nge7 7.Be3ޙ|D36z QGD: Exchange, Main Line, 9.Nf3 Re8 10.O-O Nf8 11.Rab1 a5ޗm4ctE59 Nimzo-Indian: Main Line, 9.bxc3 dxc4 10.Bxc4 Qc7 11.a4ސbZSE`B45o Sicilian: Taimanov, Four Knights, 6.Ndb5 d6ށ-9\jB67f Sicilian: Richter-Rauzer, 7...a6, 9.f3 Be7 10.h4|JӘ\A26 English: Botvinnik System, 6...Nge7 7.Nge2z #ۀ<C55b Two Knights: Deutz Gambittk (|FC07c French: Tarrasch, Open, 4.dxc5q>>o؟TjB37i Sicilian: Maroczy Bind, 6.Nc2 Nf6 7.Nc3 d6 8.Be2p0lPC88j Spanish: Closed, Anti-Marshall 8.a4e({DD44a Semi-Slav: Botvinnik AcceptedXP&FC05m French: Tarrasch, Closed, 5.c3WF->fC24 Bishop's Opening: Urusov Gambit, 7...c6 DefenceUx cSB22s Sicilian: Alapin, 2...Nf6 3.e5 Nd5 4.d4 cxd4 5.Nf3 Nc6 6.Bc4O +`B92g Sicilian: Najdorf, 6.Be2 e5 7.Nb3 Be7 8.Be3KmC:~FE48 Nimzo-Indian: 4.e3 O-O 5.Bd3 d5?SnBD78b Neo-Grnfeld, 6.O-O c6 7.Na3.kVB01z Scandinavian: Marshall, 4.c4 Nb6 5.Nf3.iԴlE34 Nimzo-Indian: Classical, Noa, 5.cxd5 Qxd5 6.Nf3 c5)?NB02p Alekhine: Smisch Attack, 3...Nxc3e++jC41b Philidor: Lopez Countergambit, Jnisch VariationBZ>C55f Two Knights: 4.d3 Be7 5.c3 QZ\E24 Nimzo-Indian: Smisch, Botvinnik Variation /[^E29 Nimzo-Indian: Smisch, Capablanca VariationwI DD91r Grnfeld: 5.Bg5 Ne4 6.cxd5 Nxg5 7.Nxg5 e6 8.Nf3 exd5 9.e3 O-O 10.Bd3h*@}HA57l Benko Gambit: 4.cxb5 a6 5.b6 e6 ڈZE92c King's Indian: 6.Be2 e5 Queenswap, 9.Bg5z:rD50 QGD: Dutch-Peruvian, Prins, 6.Qxd4 Be7 7.e4 Nc6 8.Qd2nZB45o Sicilian: Taimanov, Four Knights, 6.Ndb5妏ǿ,*B23b Sicilian: Closedۅ PrB93r Sicilian: Najdorf, 6.f4 e5 7.Nf3 Nbd7 8.a4 Be7 9.Bc4dXtq|DD31q Semi-Slav: Noteboom VariationF8>TA63 Benoni: Fianchetto, 9...Nbd7 10.Nd2 a63qPD53f QGD: 4.Bg5 Be7 5.Nf3 h6 6.Bxf6 Bxf6hE13l Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.e3 Bxc3+ 8.bxc3 d6 9.Nd2 Nbd7 10.f3 Qe7ݺ=JC90g Spanish: Closed, Pilnik, 9...Na5ݸnMoRA30v English: Symmetrical, Hedgehog, 9.b3ݲҐŘu\E05o Catalan: Open, Classical, 8.a4, 10.Bg5 a5ݮ1lE82c King's Indian: Smisch, Fianchetto, 7.Qd2 c5 8.d5ݣ4>D24q QGA: Bogoljubow, 7.a4 Nxc3ݣ/ |A59p Benko Gambit: 7.e4, Main Line, 11...Nbd7 12.h3 Qb6 13.Re1ݟOXD44g Semi-Slav: Botvinnik, Ekstrom VariationݕtȒLC92m Spanish: Closed, Zaitsev, 11.Nbd2ݕcR,DA21 English: Kramnik-Shirov, 3.Nd5ݎy}lC68p Spanish: Exchange, Alapin Gambit, 7.d3 Qf6 8.Nbd2݊EU2A10 English: 1...b6 2.Nf3݅4&2B52a Sicilian: 3.Bb5+ Bd7݄V{W@B01b Scandinavian: 2...Qxd5 3.d4 E68g King's Indian: Fianchetto, Classical, 8.e4 exd4 9.Nxd4 Re8 10.h3 Nc5y}@@׸JA10 English: 1...b6 2.Nc3 Bb7 3.e4 e6v`̂hB47n Sicilian: Taimanov, 6.g3 a6 7.Bg2 Nf6 8.O-O Bc5dq& 'fE48 Nimzo-Indian: 4.e3 O-O 5.Bd3 d5 6.Ne2 c5 7.cxd5dma:,BC45p Scotch: 4.Nxd4 Bc5 5.Nb3 Bb6aF_.JD54b QGD: Anti-Neo-Orthodox Variation\mfA30g English: Symmetrical, Mutual Double FianchettoWޫNC59k Two Knights: Main Line, 11.d4 exd3VA(>C12l French: MacCutcheon, 8.Qg4N1#@XA26 English: Closed, 5.d3 d6 6.Nf3 Nf6 7.O-ON A04 Reti: 1...c5J8\VB91k Sicilian: Najdorf, 6.g3 e5 7.Nde2 Nbd7DQ_ZB14j Caro-Kann: Panov-Botvinnik, 5...e6 6.Nf3@nHU6:E60h King's Indian: b3 System@^VC63a Spanish: Schliemann, 4.Qe2;Z0B66m Sicilian: Richter-Rauzer, 7...a6 8.O-O-O h6 9.Be3 Be7 10.f3 Nxd45KDD01i Richter-Veresov: 3...Bf5 4.f34 hD91o Grnfeld: 5.Bg5 Ne4 6.cxd5 Nxg5 7.Nxg5 e6 8.Nf31bMPVE34 Nimzo-Indian: Classical, Noa, Queenswap/J'B^E67j King's Indian: Fianchetto, Classical, 8.h3+Yp}pLE10l Blumenfeld: 5.dxe6 fxe6 6.cxb5 d5%ĬI3 A04 Reti: 1...e6#Dj"NC37 KGA: Muzio Gambit, Holloway Defence!j6J&RC86d Spanish: Worrall Attack, 7...d6 8.c3Q@C05o French: Tarrasch, Botvinnik,PC79 Spanish: Steinitz Deferred, ExchangeP XD63 QGD: Orthodox, Swiss, Karlsbad Variationr`B26q Sicilian: Closed, 6.Be3 e6 7.Qd2 Rb8 8.Nge2JJA31 English: Symmetrical, Two KnightsJʑ^D36k QGD: Exchange, Main Line, 9.Nge2 h6 10.Bh4_^SxA65y Benoni: Smisch, 8.Bg5 h6 9.Be3 O-O 10.Qd2 a6 11.a4 Re8'RJB57d Sicilian: Sozin, Benko Variation3/bB66d Sicilian: Richter-Rauzer, 7...a6 8.O-O-O Be7~^&B20 Sicilian: 2.Bc4ON%8D94 Grnfeld: Slav/SchlecterܶgG,C11a French: 3.Nc3 Nf6ܲӰq<A55c Old Indian: 5.e4 c6 6.Be2ܰ]lRA45w Trompowsky: 2...Ne4 3.Bf4 d5 4.e3 c5ܰ.AA|B70v Sicilian: Dragon, 6.Be2 Bg7 7.O-O O-O 8.Bg5 Nc6 9.Nb3 Be6ܭGμTD14i Slav: Exchange, 8.Bd3 Bxd3 9.Qxd3 Bd6ܒNS)HE94u King's Indian: 7.O-O Nbd7 8.Be3܉,@B16a Caro-Kann: Bronstein-Larsen܈OH2A00o Grob Gambit Accepted܅qDB40u Sicilian: Pin, Koch Variation~b!$|D91p Grnfeld: 5.Bg5 Ne4 6.cxd5 Nxg5 7.Nxg5 e6 8.Nf3 exd5 9.e3|[pUk^B01e Scandinavian: 2...Qxd5 3.Nc3 Qa5 4.Bc4 Nf6zh\B22f Sicilian: Alapin, 2...d5 3.exd5 Qxd5 4.d4x;+B97w Sicilian: Najdorf, Poisoned Pawn, Main Line, 13.e5 dxe5: 15.Ne4 Be7wrycjE63g King's Indian: Fianchetto, Panno, 8.b3 Rb8 9.Nd5qh>A51g Budapest: Fajarowicz, 4.a3o1<A01 Nimzowitsch-Larsen: 1...e5l$J&C25c Vienna: 2...d6h;`Y<`D00r Queen's Pawn: Anti-King's Indian, Main Line`~AgWtB47p Sicilian: Taimanov, 6.g3 a6 7.Bg2 Nf6 8.O-O Be7 9.Re1WP(`A61 Benoni: Nimzowitsch, 7...Bg7 8.Nc4 O-O 9.Bf4V S\B01i Scandinavian: 2...Qxd5 3.Nc3 Qa5 4.d4 Nf6Vͺ䳱DA07 Reti: KIA, Petrosian VariationV7YjLD58q QGD: Tartakower, 8.Rc1 Bb7 9.cxd5R]S'pBA40c Queen's Pawn: Polish DefenceHL~b"B06g Modern: 3.c3Ba>UhB91n Sicilian: Najdorf, 6.g3 e5 7.Nde2 Be7 8.Bg2 O-OA5T-NC48c Four Knights: Spanish, 4...d6 5.d4@n&jD37p QGD: Classical, 5...O-O 6.e3 c5 7.dxc5 Bxc5 8.a3;ҵH>fB13v Caro-Kann: Panov-Botvinnik, 5...Nc6 6.Bg5 dxc4'TIdB13s Caro-Kann: Panov-Botvinnik, 5...Nc6 6.Nf3 Bg4%V\B62f Sicilian: Richter-Rauzer, Keres Variation#PKs+8C50n Giuoco Pianissimo: 4.d3X.hdC18q French: Winawer, 6...Ne7 7.Qg4 O-O 8.Nf3 Nbc6U+VLC57e Two Knights: 4.Ng5 d5 5.exd5 Nxd5/nC92g Spanish: Closed, Karpov Variation, 10.d4 Bf6 11.a4z )D85y Grnfeld: Modern Exchange, 8.Be3 O-O 9.Rc1 Qa5 Queenswap, 12.Nxd2 ~1hPA01 Nimzowitsch-Larsen: 1...e5 2.Bb2 Nc6 D8D11n Slav: Slav-Reti with b3rrE33 Nimzo-Indian: Classical, Milner-Barry (Zurich), 6.Bd2ˣ0OK!@E47 Nimzo-Indian: 4.e3 O-O 5.Bd3jIG`E18s Queen's Indian: 7.Nc3 Ne4 8.Nxe4 Bxe4 9.Bf4dc$C26l Vienna: 3.Bc4D(UmHA23 English: Bremen, Keres, 4.Nf3 e4ЮXU"JB45d Sicilian: Taimanov, Four KnightsΟSɇB76q Sicilian: Dragon, Yugoslav, 9.O-O-O d5 10.exd5 Nxd5 11.Nxc62gWVC25p Vienna: Hamppe-Muzio, Dubois Variationۢ7^B00x Nimzowitsch Defence: 2.d4 d5 3.e5 Bf5 4.c3ۡ\`HD47j Semi-Slav: Meran, Lundin, 9.Ne4ۜTC55i Two Knights: 4.d3 Be7 5.O-O O-O 6.Bb3ۓ;;tE69q King's Indian: Fianchetto, Classical, 9.h3 Re8 10.Be3ۑ&CsF.pB35b Sicilian: Accelerated Fianchetto, Modern, 7.Bc4 Qa5ہLB60d Sicilian: Richter-Rauzer, 6...Qb6{ĸ4OBB15d Caro-Kann: Gurgenidze: 4.Be3oYwJB01i Scandinavian: 2...Qxd5, 5.Bd2 c6n HS8D00i Trompowsky: 2...d5 3.e3m ݬLB13n Caro-Kann: Panov-Botvinnik Attackh1|ND85g Grnfeld: Exchange, 7.Be3 c5 8.Qd2_ӄYHE12y Queen's Indian: Botvinnik, 8.e3\߭0A86 Dutch: 2.c4 Nf6 3.g3[k*&D53a QGD: 4.Bg5 Be7QUZA59j Benko Gambit: 7.e4, Main Line, 11...Nbd7D+v@C45g Scotch: Steinitz, 5.Nb5 Bc5A2IANC92r Spanish: Closed, Zaitsev, 12.a4 h67aYvNC33 KGA: Bishop's Gambit, Boden Defence3ޥ`A22 English: Bremen, Reverse Dragon, 4.cxd5 Nxd5!UgLB45c Sicilian: Taimanov, 5.Nc3 d6 6.g4n0mjA70x Benoni: Classical, 8.h3 O-O 9.Bd3 b5 10.Nxb5 Re8؄uQ<B06d Modern: Norwegian Defence8%mM<D30v QGD: 3.Nf3 Nf6 4.Bg5 dxc4:R{W4<D31f QGD: Alatortsev, 5.Bf4 c6sRo`D79i Neo-Grnfeld, 6.O-O c6 7.cxd5 cxd5 8.Ne5 e6 C[; E97j King's Indian: Mar del Plata, Bayonet Attack, 9...a5 10.Ba3˥Q\A16 English: Anglo-Grnfeld, Smyslov Variationw :C01u French: Exchange Winawerc#E59 Nimzo-Indian: Main Line, 9.bxc3 dxc4 10.Bxc4 Qc7 11.Bd3 e5 12.Qc2p~E11i Bogo-Indian: 4.Bd2 Be7 5.g3 d5 6.Bg2 O-O 7.O-O c6 8.Qc2 b6{)2NB82 Sicilian: Scheveningen, Tal, 8...e5` zXE63b King's Indian: Fianchetto, Panno, 8.Re1ei?G(B20 Sicilian Defence$05T4E00h Catalan: 3...c5 4.Nf3;;\A91 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nc3 d5(CJA99 Dutch: Ilyin-Zhenevsky, 8.b3 Nbd7pvRD81 Grnfeld: Early Russian, 5...Bg7 6.e4Սg7&bD65 QGD: Orthodox, Rubinstein Attack, 9.cxd5 exd5ԹOiϡFB57f Sicilian: Sozin, Benko, 7.Ndb5a|E87l King's Indian: Smisch, Orthodox, 7.d5 Nh5 8.Qd2 f5 9.O-O-O f4:ZE10j Neo-Indian: Blumenfeld/Benoni, 4.e3 cxd4kc<C60l Spanish: Fianchetto, 4.d4ڼo <;lZD95j Grnfeld: 5.e3 O-O 6.Qb3 dxc4 7.Bxc4 Nc6ڹKC*NB52t Sicilian: 3.Bb5+, Bronstein GambitڶMm XD31x Semi-Slav: Marshall Gambit, 5.Nxe4 Bb4+گ'zB34o Sicilian: Accelerated Fianchetto, Modern, 6.Be3 d6 7.Qd2ڧboeFD45m Semi-Slav: 6.Qc2 Bd6 7.g4 dxc4ڥU#~LA26 English: Botvinnik System, 6...Nf6ڙrD19n Slav: Dutch, 8...O-O 9.Qe2 Nbd7 10.e4 Bg6 11.Bd3 Bh5ژ?\D91k Grnfeld: 5.Bg5 Ne4 6.cxd5 Nxg5 7.Nxg5 e6ڗr&FC26u Vienna: 3.Bc4 Bc5 4.d3 d6 5.f4څ!4PE17i Queen's Indian: Opovcensky, 7...O-OzHz'DC44c Open Game: Inverted Hungarianv`(NC72 Spanish: Modern Steinitz, 5.O-O Ne7hNڍ9TE38b Nimzo-Indian: Classical, 4...c5 5.Nf3eLC29d Vienna Gambit: 3...d5 4.exd5 exf4bFp\B44r Sicilian: Taimanov, Szen, Kasparov Gambita,JWbD58h QGD: Tartakower, 8.Bd3 Bb7 9.O-O Nbd7 10.Rc1_3B97y Sicilian: Najdorf, Poisoned Pawn, Main Line, 13.e5 dxe5 with 18.Nxf6+_l;VD23l QGA: Mannheim, 4...c6, 5.Qxc4 Bf5 6.g3V)1h8BBA14 English: Neo-Catalan DeclinedU9{NC37 KGA: Muzio Gambit, Brentano DefenceM:Kb NE15l Queen's Indian: Nimzowitsch, 5.b3 M~:MNrB33o Sicilian: Pelikan, Chelyabinsk, 9.Nd5 Be7, 11.c3 O-OGlE98m King's Indian: Mar del Plata, 9.Ne1 Nd7 10.Nd3 f5CN֨^2A53 Old Indian: 3.Nf3 Bg4Bѓ40A10 English: Anglo-Dutch, DA40d Queen's Pawn: English Defence(WPZFA82 Dutch: Staunton Gambit, 4.f3 d5 #w DA36m English: Symmetrical, 5.e3 e6XdA14 English: Neo-Catalan Declined, 5...O-O 6.b3 c5 ,,.K0VB01s Scandinavian: 2...Nf6 3.Bb5+ Bd7 4.Be2%tHC45b Scotch: Ghulam Kassim Variation LABD63 QGD: Orthodox, Swiss, 8.c5 c66!KPE98a King's Indian: Mar del Plata, 9.Ne1aFFA42p Modern: Averbakh, 4...e5 5.Nf3Z9AFD13g Slav: Exchange, 5.Nc3 a6 6.Bf4[ZD03o Torre Attack: 3...g6 4.e3 Bg7 5.Nbd2 O-O͕ʚ@B30n Sicilian: Rossolimo, 3...e6ߺT;NC11x French: Burn, 6.Bxf6 gxf6 7.Nf3 f5̭;{]lA79 Benoni: Classical, Main Line, 10.Nd2 Na6 11.f3 Nc7|RB22v Sicilian: Alapin, 2...Nf6, 5.cxd4 e6xNu*A46j Indian: 2.Nf3 e6ٺq٦`gpD46j Semi-Slav: Chigorin, 7.Qc2 Main Line, 9...Qe7 10.a3ٸKAFD46q Semi-Slav: Chigorin, Main Line٬nS,,FD25e QGA: Smyslov, 5.Bxc4 Bg7 6.O-O٬2XB82 Sicilian: Scheveningen, 6.f4 a6 7.Be3 b5٦FNC95h Spanish: Closed, Breyer, Main Line٥# DB89 Sicilian: Velimirovic, 9.O-O-O٠,m(|B99r Sicilian: Najdorf, Main Line, 10.g4 b5 11.Bxf6 Nxf6 12.g5ٞE"C37 KGA: 3.Nf3 g5ٛ{>ҭNE14w Queen's Indian: Averbakh Variationٙ4hE15j Queen's Indian: Nimzowitsch, 5.Qa4 c5 6.Bg2 Bb7ّ˂/98E40 Nimzo-Indian: Rubinsteinِ "pB59n Sicilian: Boleslavsky, 7.Nb3 Be7 8.O-O O-O 9.Be3 a5َh6ۋhA41h Neo-Old Indian: Wade Defence, 3.c4 Nd7 4.Nc3 e5ٌiPLC18h French: Winawer, 6...Ne7 7.h4 Qc7ي%XE46 Nimzo-Indian: Reshevsky, 6.a3 Be7 7.cxd5يW`HE50 Nimzo-Indian: 4.e3 O-O 5.Nf3 Ne4و, zND85i Grnfeld: Modern Exchange, 7...O-Oك׉j0D21v QGA: Alekhine, 4.a4ـ{l'@B26b Sicilian: Closed, 6.Be3 Nf6y;T*HC39 KGA: Kieseritsky, Berlin DefencesO>TB00n Nimzowitsch Defence: Colorado Countero6'F-jC17r French: Winawer, Swiss, 6.b4 cxd4 7.Nb5 Bc7 8.f4mYHC63n Spanish: Schliemann, 4.Nc3 fxe4e$DB23n Sicilian: Chameleon VariationcfWۑDC41b Philidor: Lopez Countergambitc[_R|TA45x Trompowsky: 2...Ne4 3.Bf4 c5 4.d5 Qb6X|RDB21m Sicilian: Smith-Morra, 2...d5WJco,JB66a Sicilian: Richter-Rauzer, 7...a6Uš6A24 English: Bremen, 3...g6Ik[JC41d Philidor: Philidor CountergambitH#BC30f King's Gambit: Keene DefenceCk1|B48u Sicilian: Taimanov, 6.Be3 a6 7.Bd3 Nf6 8.O-O Ne5 9.h3 Bc5Cn4 FnE76p King's Indian: Four Pawns Attack, 6.Nf3 c5 7.d5 b50Ԑ<A42f Modern: Averbakh, 4...Nd7-hND79l Neo-Grnfeld, Main Line, 10.f4 Nc6-b)evE62h King's Indian: Fianchetto, Kavalek/Bronstein Variation$%78D02e Queen's Pawn: 2.Nf3 Nc6 BE00c Neo-Indian (Seirawan) Attack=PFC10j French: Rubinstein, 5.Nf3 Ngf6z1nC41e Philidor: Philidor Countergambit, Berger Variation?ʚND79a Neo-Grnfeld, 6.O-O c6 7.cxd5 cxd5::-VE00a Queen's Pawn: Neo-Indian, Devin Gambit(VE81b King's Indian: Smisch, 5...O-O 6.Nge2Ƽ]4D18f Slav: Dutch, 8...Nbd7xB47y Sicilian: Taimanov, 6.Be2 a6 7.O-O Nf6 8.Kh1 Nxd4, 10.Qd3 b5`QL^C97i Spanish: Closed, Chigorin, 12...Bd7 13.Nf1%:hE81n King's Indian: Smisch, 5...O-O 6.Be3 c5 7.dxc51k%VDA42h Modern: Averbakh, Kotov, 5.d5>#L<D31d QGD: Alatortsev Variation;SJB01r Scandinavian: 2...Nf6 3.Nf3 Nxd5XuUBD27d QGA: Classical, 6...a6 7.Bd3Z~G.D00d Queen's Pawn: 2.e3ؿUެ+$D21d QGA: 3.Nf3 e6ؽ yBE24 Nimzo-Indian: Smisch, 5...b6طjFB00m Nimzowitsch Defence: 2.Nc3 Nf6طgJB01e Scandinavian: 2...Qxd5 3.Nc3 Qa5؜IY Ă<rB59l Sicilian: Boleslavsky, 7.Nb3 Be7 8.O-O O-O 9.Be3 Be6ؕePA65q Benoni: Smisch, 8.Bg5 O-O 9.Qd2 a6ؕ"@bE14k Queen's Indian: 4.e3 Bb7 5.Bd3 Be7 6.O-O O-OؓQ ͵FE47 Nimzo-Indian: 4.e3 O-O 5.Bd3 d6؈Vr| /FE10k Blumenfeld: 5.dxe6 fxe6 6.cxb5؂<7},A70a Benoni: Classical؀~[F`A65s Benoni: Smisch, 8.Bg5 h6 9.Be3 O-O 10.Nge2| \;zE66h King's Indian: Fianchetto, Yugoslav Panno, 9...a6 10.Qc2c3 HA04 Reti: 1...c5, Nimzowitsch-LarsenU1cbA74 Benoni: Classical, 9.O-O a6 10.a4 Nbd7 11.Bf4Tfr6RE09e Catalan: Closed, Main Line, 9.b3 Bb7N{fBC80i Spanish: Open, Friess AttackG:RC01e French: Exchange, 4.c4 Nf6 5.Nc3 Bb4:2a0A46e Neo-Benoni: 3.c3 e692jC63s Spanish: Schliemann, 4.Nc3 fxe4 5.Nxe4 d5 6.Nxe560fB13o Caro-Kann: Panov-Botvinnik, Gunderam Variation'Y96A86 Dutch: 2.c4 Nf6 3.g3 d6%Y9YDE49 Nimzo-Indian: Botvinnik SystemS>D93 Grnfeld: 5.Bf4 O-O 6.e3 c5@* ^NE11n Bogo-Indian: Nimzowitsch Variation,kdD29l QGA: Classical, 8...Bb7 9.Rd1 Nbd7 10.Nc3 Qc7 ((xB23u Sicilian: Closed, Grand Prix, 3...g6 4.Nf3 Bg7 5.Bc4 e6:q`D10g Slav: Exchange, 4.Nc3 Nf6 5.Bf4 Nc6 6.e3 a6XŎ`B81p Sicilian: Scheveningen, Keres, 6...h6 7.Rg1F[XA00l Van Geet: Sicilian Variation, 2.Nf3 Nc6]1 LA87 Dutch: Leningrad, Main Line, 6.Nc33:7JtB19p Caro-Kann: Classical, Spassky, 10.Qxd3 Qc7 11.Bd2 e6 12.O-O-Oa{DC48b Four Knights: Spanish, 4...d6VEZC29t Vienna Gambit: Breyer, 6.Qe2 Nxc3 7.dxc38kVC44w Scotch: Goring Gambit, 4...dxc3 5.Nxc3פE8RB22f Sicilian: Alapin, 2...d5 3.exd5 Qxd5ez]ZE31b Nimzo-Indian: Leningrad, Main Line, 7.e3]3iT0D20n QGA: 3.e4 Nc6 4.Be3tqjB49g Sicilian: Taimanov, 6.Be3 a6 7.Be2 Nf6 8.O-O Be7Ƌ0@<2D03l Torre Attack: 3...g6<7|r2B01a Scandinavian: 2.exd5׼ly@A/6D11e Slav: 3.Nf3 dxc4 4.Nc3׻DeHE60a King's Indian: Mengarini Attack׸-J)bA39m English: Symmetrical, Main Line 7.d4, 10.Qd3׸BfB27h Sicilian: Hungarian, 3.c3 Bg7 4.d4 cxd4 5.cxd4׵n<C57f Two Knights: Lolli Attack׳M LC70 Spanish: Taimanov (Wing) Variationײ$@%JC85d Spanish: Closed, Exchange, 7.Nc3ײ:L|8D96 Grnfeld: Russian, 7.Bf4ק+~DD06h QGD: Marshall Defence, 3.cxd5ף1z4@A61 Benoni: Fianchetto VariationןЎڧ|NC87c Spanish: Closed, Averbakh, 7.Bxc6+מni6D16m Slav: Bronstein, 6.Ne5דH"B07d Pirc: 3.Nbd2׎I@pE76m King's Indian: Four Pawns Attack, 6.Nf3 c5 7.dxc5 Qa5 8.Bd3 Qxc5 9.Qe2 Nc6׌`b2u]BA57i Benko Gambit: 4.cxb5 a6 5.b6y4ZA32 English: Symmetrical, Two Knights, 4...e6u$y>D05l Colle: 5.c3 Nc6 6.Nbd2 Bd6u&BD30g QGD: 3.Nf3 Nbd7 (Westphalia)sݫ>D39c QGD: Ragozin, Vienna, 6.e4q`gHD60 QGD: Orthodox, Botvinnik, 8...a6l*NC39 KGA: Kieseritsky, Long Whip Defencea &B07i Pirc: 3.Bd3 g6_QmA04 RetiWcjHBD44j Semi-Slav: Botvinnik, 9.Nxg5CMPWJC49i Four Knights: Symmetrical, 7.Bg58v~|C44w Scotch: Goring Gambit, 4...dxc3 5.Nxc3 Bb4 6.Bc4 d6 7.O-O0Jw\FB21r Sicilian: Smith-Morra, 3.c3 d3-khlNB90h Sicilian: Najdorf, 6.Be3 Ng4 7.Bg5*@NE05l Catalan: Open, Classical, 8.a4 Bd7 YH@D06o QGD: 2...Bf5 3.Nf3 e6 4.Qb3FY2E01 Catalan: 4...c5 5.Nf3I?+VA67d Benoni: Four Pawns, Taimanov, 8...Nfd7 d8A57e Benko Gambit: 4.Nf3 Bb7 }eA79 Benoni: Classical, Main Line, 10.Nd2 Na6 11.f3 Nc7 12.a4 Nd7˺jB00r Nimzowitsch Defence: 2.Nf3 d6 3.d4 Nf6 4.Nc3 Bg4酟r `B47m Sicilian: Taimanov, 6.g3 a6 7.Bg2 Nf6 8.O-OJ~&>C45e Scotch: Steinitz VariationA|`A97 Dutch: Ilyin-Zhenevsky, Winter, 8...Qg6 9.e4s^E13m Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.e3 g5os_LB75 Sicilian: Dragon, Yugoslav, 7...a6ֿI\ŹNC42s Russian Game: Classical, 6.Bd3 Be7ֵbc8LC54g Giuoco Pianissimo: 5.d3 d6 6.Nbd2ֳ>3DE69f King's Indian: Fianchetto, Classical, 9.h3 exd4 10.Nxd4 Re8ֲI~\D38n QGD: Ragozin, 5.Bg5 h6 6.Bxf6 Qxf6 7.cxd5ְ9t'`B84 Sicilian: Scheveningen, Classical, 7.O-O Qc7֬acJC39 KGA: Allgaier, Schlechter Defence֬WTzڴbC97d Spanish: Closed, Chigorin, 11.d4 Qc7 12.Nbd2֧ԨBD73 Neo-Grnfeld, 5.Nf3 c6 6.cxd5֝&)>D02j Queen's Pawn: Krause, 3.c4֔܁PB52h Sicilian: 3.Bb5+, Sokolsky, 5...Nc6֒ h0xLC44a Open Game: Irish (Chicago) Gambit֌6})k<C00n French: KIA 2.d3 d5 3.Qe2}GNt8E61a King's Indian: 3.Nc3 d6xc(C68a Spanish: 3...a6vú $NXB97p Sicilian: Najdorf, Poisoned Pawn, 10.e5d%`B67s Sicilian: Richter-Rauzer, 7...a6, 9.f4 b5 10.Bxf6 gxf6 11.Kb1 Qb6 12.Nxc6b-LB>A08 Reti: KIA, French VariationYxuKFE06 Catalan: Closed, 6.O-O c6 7.Nc3TUAebB65a Sicilian: Richter-Rauzer, 7...Be7, 9.f4 Nxd4QW E^E15m Queen's Indian: Nimzowitsch, 5.b3 d5 6.Bg2N"QEYNC00x French: Alapin-Diemer Gambit (ADG)J}2/:BB15c Caro-Kann: Gurgenidze/Modern@,JP8A04 Reti: Lisitsin: 3.Ng5 e5='HB22f Sicilian: Alapin, 2...d5 3.exd5G6B01b Scandinavian: 2...Qxd5 d713D41j QGD: Semi-Tarrasch, 6.g3, Main Line, 9.Nxd5 exd5 10.dxc5 Bxc5 11.Bg5CD58o QGD: Tartakower, 8.Be2 Bb7 9.Bxf6 Bxf6 10.cxd5 exd5 11.b4 c6 12.O-O7*2c0A10 English: Anglo-Dutch[վ E75j King's Indian: Averbakh, 7.d5 e6 8.Qd2 exd5 9.exd5 Re8 10.Nf3 Bg40-{OaDC32 KGD: Falkbeer, Keres VariationpcFA82 Dutch: Staunton Gambit, 4.f3 e6^B25k Sicilian: Closed, 6.f4 e5 7.Nf3 Nge7 8.O-O6>)ZNC48o Four Knights: Rubinstein, 5.Ba4 c6f LE30 Nimzo-Indian: Leningrad, 6.d5 exd5m>rdHE11y Bogo-Indian: 4.Bd2 Bxd2+ 5.Qxd2Y}(8C50l Giuoco Piano: 4.O-O Nf65b|rZB43l Sicilian: Kan, 5.Nc3 Qc7 6.Be2 Nf6 7.O-Ox lC86l Spanish: Worrall Attack, 7...O-O 8.c3 d5 9.d3 Bb7ջ~RB96n Sicilian: Najdorf, Polugaevsky, 8.e5յKjZA07 Reti: KIA, Yugoslav, Main Line, 6.Nbd2 e5յ4jnDC29k Vienna Gambit: Paulsen Attackձ#9BC45o Scotch: Romanishin VariationեT5^C51 Evans Gambit Declined, Hirschbach VariationՠB H>tC50t Giuoco Pianissimo: Italian Four Knights, 5...d6 6.Be3՟2JC85f Spanish: Closed, Exchange, 7.Qe1՜\∭dA39h English: Symmetrical, Main Line 7.d4, 8...Ng4՘qRB26n Sicilian: Closed, 6.Be3 e6 7.Qd2 Nd4ՔؑLt0A54 Old Indian: 5.Bg5 c6Ւ~pD89b Grnfeld: Classical Exchange, Main Line, 13.Bd3 Be6ՒmK1bB80t Sicilian: Scheveningen, Fianchetto VariationՊĈnbE12t Queen's Indian: Petrosian, Kasparov, 7...Be7Պ"3J@E60i King's Indian: b3+g3 SystemՉ2>/XA41i Neo-Old Indian: Wade Defence, 3.c4 Bxf3ՈR vB19s Caro-Kann: Classical, Spassky, Main Line, 13.Ne4 O-O-OՄ? 4C02n French: Advance, EuwevX:[rE82g King's Indian: Smisch, Fianchetto, 7.Bd3 Bb7 8.Nge2u-Y-dC05t French: Tarrasch, Closed, 7.Ngf3 Be7 8.O-O g5P[wHD23r QGA: Mannheim, Main Line, 10.e3K(ŖR`A32 English: Symmetrical, Two Knights, 5.g3 Bb4+J^ nE70v King's Indian: Accelerated Averbakh, 5...O-O 6.Qd281P@B18d Caro-Kann: Classical, 5.Ng36TC33 KGA: Bishop's Gambit, Fraser Variation,ߦ@E00l Catalan: 3...Bb4+ 4.Bd2 Be7+cDA03 Bird: 1...d5 2.Nf3 Nf6 3.g3 g6!a*\A44g Old Benoni: Czech, 3.c4 d6 4.e4 Be7 5.Nc3zXD91n Grnfeld: 5.Bg5 Ne4 6.cxd5 Nxg5 7.Nxg5 e6 8.Qd2 exd5: 11.h4 h63;}PC18m French: Winawer, 6...Ne7 7.Qg4 cxd4KJwn2E61a King's Indian: 3.Nc3&)TE12j Queen's Indian: Petrosian, 5.Nc3 Bxf3\2,A52a Budapest: 3...Ng4\I TC67n Spanish: Open Berlin, 5.d4 Nd6 6.dxe5l 0ۓHA57k Benko Gambit: 4.cxb5 a6 5.b6 d6;G]$B07g Pirc: 3.f3 g6mN^FB06t Modern: Pseudo-Austrian Attack dB17o Caro-Kann: Steinitz, 5.Ng5 Ngf6 6.Bd3, Main Line 10.Qxe4 Nf6w>UxuFE06 Catalan: Closed, 6.O-O c6 7.Qc2#ں<D30v QGD: 3.Nf3 Nf6 4.Bg5 Nbd7%1KrE94d King's Indian: 7.O-O exd4 8.Nxd4 Re8 9.f3 Nc6 10.Be3ڭTC84l Spanish: Closed, Centre Attack, 7.Re1VS6hA75 Benoni: Classical, 9.O-O a6 10.a4 Bg4 11.Bf4 Qe7ЁMQ0tB70q Sicilian: Dragon, 6.Be2 Bg7 7.O-O O-O 8.Re1 Nc6 9.Nb3ԻVI6C55l Two Knights: 4.d4 exd4Ԩp 8C77a Spanish: Morphy Defenceԣ+K(NC23 Bishop's Opening: del Rio VariationԗmH>THC48a Four Knights: Spanish VariationԖ9 HA58m Benko Gambit: Fianchetto, 9.Bg2Ԕt[RA87 Dutch: Leningrad, Main Line, 6.Nc3 d6ԏ'ˤhHA19 English: Mikenas, Sicilian, 4.e5ԉ{&^(D45a Semi-Slav: 5.e3Ԉ (C25d Vienna: 2...Bc5Ԅ*+`jD48p Semi-Slav: Meran, Reynolds, 10...c4 11.dxe6 fxe6y\`NB33j Sicilian: Pelikan, 7.Bg5 a6 8.Bxf6t}tU|qXE74g King's Indian: Averbakh, 6...c5 7.d5 a6ruebE92e King's Indian: 6.Be2 e5 Queenswap, 9.Bg5 Re8S׉S,sJB34a Sicilian: Accelerated FianchettoDtcWyA29 English: Four Knights, 4.g3 d5 5.cxd5 Nxd5 6.Bg2 Nb6 7.O-O Be7 8.Rb1.A!M`C89b Spanish: Marshall, Herman Steiner Variation+3iTTB15k Caro-Kann: Gurgenidze: 4.Nf3 Bg7 5.e5$)h A04 Reti: 1...d6!D rfQHD02d Queen's Pawn: 2.Nf3 Bf5 3.e3 c6! JkfZ`D31w Semi-Slav: Marshall Gambit, Gunderam Gambit7S2A15 English: Anglo-Indian S"VNC96f Spanish: Closed, Chigorin, 10...c5kCMQWPC03l French: Tarrasch, Guimard VariationBŢLB00a King's Pawn: Hippopotamus DefenceބHD02t Queen's Pawn: 3.g3 c6 4.Bg2 Bg4F*HE17u Queen's Indian: Pomar Variation_l'mPA33p English: Symmetrical, Geller, 7.Nb3"kl:C60d Spanish: Pollock Defenceى PA76 Benoni: Classical, Main Line, 10.Qc2_JdA59f Benko Gambit: 7.e4 Line, 9.Nf3 Bg7 10.h3 Nbd7ʹ@^FE50 Nimzo-Indian: 4.e3 O-O 5.Nf3 c5=w{FA70b Benoni: Classical, 7...a6 8.a4%~uRB46l Sicilian: Taimanov, 5...a6 6.Be3 Nf6Ӿp9$A46a Indian: 2.Nf3ӱ LB22t Sicilian: Alapin, 2...Nf6, 5.cxd4ӯ'!.C37 KGA: Blachly GambitӢ=k;:D07h QGD: Chigorin, 3.Nf3 Bg4Ӛ0B30k Sicilian: Rossolimoӕmj3 pC09o French: Tarrasch, Open, Main Line, 9.Nb3 Bd6 10.Re1Ӕq)<A58c Benko Gambit: 5.bxa6 Bxa6Ӓ%5c,lD69 QGD: Orthodox, Classical, 13.dxe5: 15.f4 Qf6 16.f5ӌMb~:A60l Benoni: Snake, 6.Nf3 Bc7Ӈ!wVC52 Evans Gambit: Alapin-Steinitz Variation}:J@A46p Indian: London, 3...c5 4.e3wzmBC44e Open Game: Inverted PhilidormtE29 Nimzo-Indian: Smisch, 5...O-O 6.e3 c5 7.Bd3 Nc6 8.Ne2g\.:D94 Grnfeld: 5.e3 O-O 6.cxd5[ WNC65o Spanish: Berlin, Benelux VariationYEPB25s Sicilian: Closed, 6.f4 e6: 9.Be3 b6Xw'*ND02j Queen's Pawn: Krause, Reversed QGAWBݘ(fD98i Grnfeld: Russian, Smyslov, 8.Be3 Nfd7 9.O-O-OO過ۼpD49g Semi-Slav: Meran, Sozin, Stahlberg Attack, 13...Bb4O_xA67c Benoni: Four Pawns, Taimanov, 8...Nbd7 9.e5 dxe5 10.fxe5 Nh5 11.e6848e_5<C10q French: Rubinstein, 7.Bg56EdB22j Sicilian: Alapin, 2...d5 3.exd5 Qxd5 4.d4 Nf62Js@D25i QGA: Janowski-Larsen, 6.Qb3-A|ζӗ^D34t QGD Tarrasch: 9.Bg5 cxd4 10.Nxd4 h6 11.Be3&ƧHC78c Spanish: Mller Defence, 6.Nxe5 t!,dA94 Dutch: Stonewall, Botvinnik, 8.Ba3 Nbd7 9.Bxe7 xv4E06 Catalan: Closed, 6.O-O~= zDB58e Sicilian: Boleslavsky, 6...e532\ TB01g Scandinavian: 2...Qxd5 3.Nc3 Qa5 4.d4>@C10r French: Rubinstein, 4...Bd7ѤFC55n Two Knights: Perreux Variation&E12a Queen's Indian$ i0@B01r Scandinavian: 2...Nf6 3.Bc4U>2A57h Benko Gambit: 4.cxb5jf A06 Reti: 1...d5e"l:C89i Spanish: Marshall, 12.d3MCKUDtB48t Sicilian: Taimanov, 6.Be3 a6 7.Bd3 Nf6 8.O-O Ne5 9.h3EPD41n QGD: Semi-Tarrasch, 6.e4, Main Line+'(JB56h Sicilian: Open, 2...d6 5.Nc3 Nc6Ϸ;2A40u Queen's Pawn: ModernWL(/xB08v Pirc: Classical, 5.Be2 O-O 6.O-O Bg4 7.Be3 Nc6 8.Qd2 e5Ⱦ7dHB01b Scandinavian: 2...Qxd5 3.d4 Nf6žuMQD21a QGA: 3.Nf3ğ +RE16a Queen's Indian: Capablanca VariationҸ2!aD65 QGD: Orthodox, Rubinstein, 9.cxd5 exd5 10.Bd3 Re8 11.O-O Nf8 12.h3ҵ-jq8A20 English: King's, 2.g3 f5ҮGŬJ'RD36l QGD: Exchange, Main Line, 9.Nge2 Re8ҥ*=g*yBC68k Spanish: Exchange, 5.O-O Ne7ҋ>갣FD53e QGD: 4.Bg5 Be7 5.Nf3 h6 6.Bxf6ҀHE83a King's Indian: Smisch, 6...Nc6{j@D33g QGD Tarrasch: Swedish, 9.a3r3FD11d Slav: 3.Nf3 Bf5 4.Nc3 e6 5.Qb3p0rB23t Sicilian: Closed, Grand Prix, 3...g6 4.Nf3 Bg7 5.Bc4i:abD46i Semi-Slav: Chigorin, 7.Qc2 Main Line, 9...e5a^ui0A81 Dutch: 2.g3 e6 3.Nf3]!p,RC01f French: Exchange, 4.c4 Nf6 5.Nc3 Be7Z)`B84 Sicilian: Scheveningen, Classical, 7.O-O Be7W)A<E00g Catalan: Hungarian GambitR_?}$A56o Benoni: CzechK4T{'dE64e King's Indian: Fianchetto, Yugoslav, 7.d5 Na6F5ї"D32a QGD TarraschCl8C61a Spanish: Bird's DefenceA,8D82 Grnfeld: 4.Bf4 Bg7 5.e3@֩*?*A46d Neo-Benoni: 3.c3;[fB21y Sicilian: Smith-Morra, 5.Nf3 d6 6.Bc4 e6 7.O-O7_u^A28 English: Four Knights, Romanishin Variation0.r7 VC16m French: Winawer, Advance, 4...Ne7 5.a3/Jcv lB52p Sicilian: 3.Bb5+ Bd7 4.Bxd7+ Qxd7 5.O-O Nc6 6.Re1'+uB97v Sicilian: Najdorf, Poisoned Pawn, Main Line, 13.e5 dxe5: 15.Ne4 Qxa2%m!N+TC44w Scotch: Goring Gambit, 4...dxc3 5.Bc4#MVFA37b English: Symmetrical, 5.Nf3 a6-?ZC84d Spanish: Closed, 6.Nc3 b5 7.Bb3 d6 8.Nd5nQlB27i Sicilian: Hungarian, 3.c3 Bg7 4.d4 cxd4 5.cxd4 d5NuvD77l Neo-Grnfeld, 6.O-O dxc4 7.Na3 Nc6 8.Nxc4 Be6 9.b3 Bd5Pm@A45s Trompowsky: 2...Ne4 3.h4 d5 ?j/TC48n Four Knights: Rubinstein, 5.Ba4 Nxf3+xLD48i Semi-Slav: Meran, 8...a6 9.e4 Bb7pUX&FD36c QGD: Exchange, 6.Qc2 Be7 7.Nf3$HD00u Blackmar-Diemer: Vienna Defence+B$ 0D30r QGD: 3.Nf3 Nf6 4.e3ޏ'+INC09a French: Tarrasch, Open, 5.Ngf3 Nc6x2A10 English: 1...g6 2.Nc36<D50 QGD: Dutch-Peruvian GambitioqLC18e French: Winawer, 6...Qc7 7.Qg4 f5M!R_,C33 KGA: Breyer Gambitҕe=6D77c Neo-Grnfeld, 6.O-O c5&+JE13k Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.e3 Bxc3+ 8.bxc3 d6 9.Nd2 Nbd7Jd`C52 Evans Gambit: Tartakower Attack, 8.dxe5 dxe5ѿ(S|E76r King's Indian: Four Pawns Attack, 6.Nf3 c5 7.d5 e6 8.dxe6Ѷ=?6D08 QGD: Albin, Lasker Trapѯ:8D51 QGD: 4.Bg5 Nbd7 5.Nf3 c6ў\~FB57e Sicilian: Sozin, Benko, 7.Nde2ћUmXA22 English: Bremen, Smyslov, 4.Bg2 O-O 5.e4јdDRE08q Catalan: Closed, 7.Qc2 c6 8.b3 b6 9.Rd1 Bb7 10.Nc3 Rc8 11.e4ї4]\oBC22 Centre Game: Berger VariationьaL\C23 Bishop's Opening: MacDonnell Double Gambitш0 DB27d Sicilian: Katalimov Variationr}GhVB21h Sicilian: Grand Prix, 2...Nc6 3.Nf3 g6l9xDA46t Torre Attack: 3...c5 4.c3 Qb6k{J1ZD79i Neo-Grnfeld, 6.O-O c6 7.cxd5 cxd5 8.Ne5hFWsTC60j Spanish: Fianchetto (Smyslov) Defencee:RDuVE32e Nimzo-Indian: Classical, 4...O-O 5.Bg5aXFA16 English: Anglo-Indian, 2.Nc3 c6`u2 bC45x Scotch: 4.Nxd4 Bc5 5.Be3 Qf6 6.c3 Nge7 7.Bc4]BD40f QGD: Semi-Tarrasch, 5.e3 Nc6Y̥:jC44y Scotch Gambit: Anderssen (Paulsen) CounterattackU=FC52 Evans Gambit: Tartakower AttackOu+E14i Queen's Indian: 4.e3 Bb7 5.Bd3 Bb4+ 6.Nbd2 O-O 7.O-O d5 8.a3M)9ۡHD26s QGA: Classical, 6.O-O Nc6 7.Nc3K'FC07i French: Tarrasch, Open, 4.exd5Az!0D38h QGD: Ragozin, 5.Bg5;ƨU{xB49i Sicilian: Taimanov, 6.Be3 a6 7.Be2 Nf6 8.O-O Bb4 9.Nxc60;W(}zA37p English: Symmetrical, 5.Nf3 e6 6.O-O Nge7 7.d3 O-O 8.Bd2.UZ<B44g Sicilian: Taimanov, 5.Be3( e(A45i Indian: 2.g3 c5&6A90 Dutch: 2.c4 Nf6 3.g3 e6#cl\_<E15b Queen's Indian: 4.g3 Bb4+{} >D00i Trompowsky: 2...d5 3.e3 e6nrB52s Sicilian: 3.Bb5+ Bd7 4.Bxd7+ Qxd7 5.O-O Nc6 6.c3 Nf6 ףZ&D04b Colle: 3...Bg4 Q-fA75 Benoni: Classical, 9.O-O a6 10.a4 Bg4 11.Bg5 h6:4D10e Slav: Exchange, 4.Nc3۞&HC30c King's Gambit: 2...d6 3.Nf3 Nc6ăH2RPC33 KGA: Bishop's Gambit, Bledow, 4.Bxd5 /hE98o King's Indian: Mar del Plata, Fischer Variation"s.=BA13t English: Neo-Catalan, 4...c5Ht2B51k Sicilian: 3.Bb5+ Nc6xG8C45g Scotch: Steinitz, 5.Nb5؎$5QNE11q Bogo-Indian: Nimzowitsch, 5.g3 O-OKfA89 Dutch: Leningrad, Main Line, 7.Nc3 Nc6 8.d5 Na5|ק_(A00d Clemenz Opening)sRB22t Sicilian: Alapin, 2...Nf6, 5.cxd4 d6|˔'*A46g Indian: 2.Nf3 d6Х(D80 Grnfeld DefenceТqH7TC55k Two Knights: 4.d3 Be7 5.O-O O-O 6.Re1С ]PC07j French: Tarrasch, Open, 4.exd5 Qxd5ИQPB08p Pirc: Classical, 5.Be2 O-O 6.O-O c6А7fD42f QGD: Semi-Tarrasch, 7.Bd3 Main Line, 9.O-O O-OЎ0Q#B11k Caro-Kann: Two Knights, 3...Bg4 4.h3 Bxf3 5.Qxf3 e6 6.d3 Nd7Є_xFA29 English: Four Knights, 4.g3 Bc5p MJ*C44t Scotch: 3...exd4mg zPE08i Catalan: Closed, 7.Qc2 c6 8.Bf4 Ne4irgqVE12p Queen's Indian: Petrosian, 6.cxd5 exd5aTzRC78m Spanish: 5.O-O b5 6.Bb3 Bc5 7.a4 Rb8_7VhC49m Four Knights: Symmetrical, 7.Bg5 Bxc3 8.bxc3 h6ShY@2A04 Reti: 1...f5 2.d3 Nf6JA07 Reti: KIAC7G,C26p Vienna: 3.Bc4 Bc5?De^D\B71 Sicilian: Dragon, Levenfish, 6...Nc6 7.Bb5?0 CYRNE17e Queen's Indian: 6.Nc3 O-O 7.Qc2 c5*^C5$D24h QGA: 4.Nc3 a6%dLg\D23m QGA: Mannheim, 4...c6, 5.Qxc4 Bf5 6.g3 e6I-TB70l Sicilian: Dragon, 6.Be2 Bg7 7.O-O Nc6]ѧEvzE29 Nimzo-Indian: Smisch, 5...O-O 6.e3 c5 7.Bd3 Nc6 8.Ne2 d6/ʊD[dE65f King's Indian: Fianchetto, Yugoslav, Exchange)&C20 Open Game: 2.c4)@L\D76b Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O Nb6 8.Nc35ow;vC16n French: Winawer, Advance, 4...Ne7 5.a3 Bxc3+ 6.bxc3 b6ggnA35l English: Symmetrical, Four Knights, 4.g3 d5 5.cxd5c33{hB90s Sicilian: Najdorf, 6.Be3 e5 7.Nb3 Be6 8.f3 Nbd7ƱsObtB31f Sicilian: Rossolimo, 3...g6 4.Bxc6 dxc6 5.d3 Bg7 6.h32|PZA37t English: Symmetrical, 5.Nf3 e5 6.d3 Nge7Ϸ-r93JB32n Sicilian: Lowenthal, Kalashnikov϶/?H vpB38p Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 d6 9.O-O a6ϨRzBC68n Spanish: Exchange, 5.O-O Bg4Ϛ; ~PND31g QGD: Alatortsev, 5.Bf4 c6 6.e3 Bf5υGzq,A47 Neo-Queen's IndianςLKGDB04d Alekhine: Modern, 4...c6 5.c4|C=h@C01i French: Exchange, 4.Bd3 Nc6sd1hB29m Sicilian: Nimzowitsch, Rubinstein Countergambitr[T(C00x French: 2.d4 d5n]x~D62 QGD: Orthodox, Rubinstein, 7.Qc2 c5 8.cxd5 Nxd5 9.Bxe7 Qxe7n[GЍDC16e French: Winawer, 4.e5 b6 5.a3ifVC41p Philidor: Exchange, Sokolsky VariationgJ0yhBB10r Caro-Kann: Goldman/Spielmannf [~R:B94a Sicilian: Najdorf, 6.Bg5efC92t Spanish: Closed, Zaitsev, 12.a4 h6 13.Bc2 exd4a$Θ>VRC54i Giuoco Pianissimo: 5.d3 d6 6.O-O O-OY ydA38q English: Symmetrical, Main Line, 7.d3 d6 8.a3ENb4A21 English: King's, 2.Nc3EKeijE85j King's Indian: Smisch, Orthodox, 7.Nge2 Nc6 8.d5 Ne7 9.Qd2C%1j)\A34 English: Symmetrical, 3 Knights, 5.e4 Nxc39=jE63f King's Indian: Fianchetto, Panno, 8.b3 Rb8 9.Bb27̥C7LB50h Sicilian: 2.Nf3 d6 3.Bc4 Nf6 4.d322:_JJaDD53h QGD: 4.Bg5 Be7 5.Nf3 h6 6.Bh4,B}\B45t Sicilian: Taimanov, Four Knights, 6.Ndb5 Bb4 7.a3, 9.ed5 ed5*ZB50w Sicilian: 2.Nf3 d6 3.c3, Torre VariationFe8B70f Sicilian: Dragon, 6.Bc4@M<C52 Evans Gambit: 5...Ba5 6.d4ШE<E60j King's Indian: Fianchetto9/TC36 KGA: Scandinavian, Botvinnik VariationB?8B07b Pirc/Reti: Wade Defence=¹ A91 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nh3 O-O 6.O-O d6 7.Nc3 Qe8fŵvpD88 Grnfeld: Classical Exchange, Main Line, 11.cxd4 Bg4K |ND61 QGD: Orthodox, Rubinstein, 7.Qc2 c6&CFB51d Sicilian: 3.Bb5+ Nd7 4.O-O Nf6+|'r8LC18a French: Winawer, 5...Bxc3+ 6.bxc3:V)dD66 QGD: Orthodox, Main Line, Fianchetto Variationٓ}\A30u English: Symmetrical, Hedgehog, 8.Qxd4 d64Az.8B07v Pirc: 4.Be3, 150 AttackjHʭ`E55 Nimzo-Indian: Main Line, Bronstein, 9.Qe2 b6ξA$9bE95k King's Indian: 7.O-O Nbd7 8.Re1 c6 9.Bf1 Re88SEdqHD07u QGD: Chigorin, 3.Nc3 dxc4 4.Nf31wpD85q Grnfeld: Modern Exchange, 8.Rb1 O-O 9.Be2 cd 10.cd*9/PHB54d Sicilian: Open, 2...d6, 4...Nf6$'DD00c Queen's Pawn: Mason Variation o dE39g Nimzo-Indian: Classical, Pirc, 6.Nf3 Na6 7.a3IjA91 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nh3 O-O 6.O-O AApFD46o Semi-Slav: Chigorin, 7.O-O O-OkO4BD51 QGD: 4.Bg5 Nbd7 5.e3 c6 6.Qc2&3ihpE82i King's Indian: Smisch, Fianchetto, 7.Bd3 a6 8.Nge2p9hE12i Queen's Indian: Petrosian, 4...Ba6 5.Qc2 Bb7 6.Nc3 c5 7.e4 cd 8.Nxd4 Nc6 >D56 QGD: Lasker Defence, 9.Nxe4퀵&A00q Polish: 1...d5_@B40n Sicilian: Kveinys VariationNA5|}4C44t Scotch: Goring GambitzNIjB59k Sicilian: Boleslavsky, 7.Nb3 Be7 8.O-O O-O 9.Be3͹}RApA33g English: Symmetrical, Two Knights, 5.Nc3 Nc6 6.Ndb5͸˵"`C41z Philidor: Improved Hanham, 7.Re1 c6 8.a4 b6ͷZ\ (@A34 English: Symmetrical, 2...g6͵{ѡ6s)lD97d Grnfeld: Russian, Alekhine (Hungarian) VariationͰ*X=4D26p QGA: Classical, 6.O-Oͯ +ԉDC37 KGA: Lolli Gambit (Wild Muzio)ͯa86VA30r English: Symmetrical, Hedgehog, 8.Qxd4ͬBj8xC43e Russian Game: Modern Attack, 3...exd4, Main Line, 7.Nc3ͪKSpD87k Grnfeld: Classical Exchange, 10.Be3 Qc7 11.Rc1 Rd8͠HJYPD30h QGD: Tarrasch without Nc3: 4.e3 Nf6͝ǓXBC51 Evans Gambit: Anderssen, 6.d4͖tBbg8E91c King's Indian: 6.Be2 a6lޣ>B47c Sicilian: Taimanov, 6.Ndb5sDA54 Old Indian: 5.Bg5 Be7 6.e3 O-OVSYTA30h English: Symmetrical, Hedgehog System4b0A84 Dutch: 2.c4 e6 3.Nf3 [fȃR&B07h Pirc: 3.Bd3 e5 jBA55e Old Indian: 5.e4 Be7 6.g3 c6rUDC10i French: Rubinstein, 5.Nf3 Be7] 4C29f Vienna Gambit: 4.fxe5+0WzE09q Catalan: Closed, Main Line, 9.e4 Bb7 10.b3 Rc8 11.Bb2 c5dhTJ8E00i Catalan: 3...Bb4+ 4.Nd2lNWDB80f Sicilian: Scheveningen, 7.Qd2:פD.2A41c Neo-Old Indian: 2.g3 ">A02 Bird: From Gambit, 3...Bxd6wAxE60l King's Indian: Fianchetto, Yugoslav without Nc3, 7.dxc5גjx&D35a QGD: 3.Nc3 Nf6Y ˳fB14c Caro-Kann: Panov-Botvinnik, 5...g6 6.cxd5 Nxd52%t:D34r QGD Tarrasch: 9.Bg5 cxd4m|bB48n Sicilian: Taimanov, 6.Be3 a6 7.Bd3 Nf6 8.O-OF|JJD02g Queen's Pawn: 2.Nf3 Nc6 3.g3 Bg4K|>B32j Sicilian: Lowenthal, 5.Nb5$[E><C60n Spanish: Fianchetto, 4.c3̪,zvC05h French: Tarrasch, Closed, 5.f4 c5 6.c3 Nc6 7.Ndf3 cxd4oXB01w Scandinavian: Marshall, 4.Nf3 Bg4 5.Be2j5^C80s Spanish: Open, Bernstein, 9...Nc5 10.c3 d4bïŽ,A47 Neo-Queen's Indianb=qwNB12q Caro-Kann: Advance, 4.Nf3 e6 5.Be2^I|adA35e English: Symmetrical, 2.Nc3 Nc6 3.Nf3 g6 4.e3^0uQrD62 QGD: Orthodox, Rubinstein, 7.Qc2 c5 8.cxd5, Main LineV(S7s<D09 QGD: Albin, 5.g3 Be6 6.Bg2FR0R4A03 Bird: Lasker VariationA-Ri+DC32 KGD: Falkbeer, Keres, 5...exd3?DBA62 Benoni: Fianchetto, 9.O-O Na6>BTk:A21 English: King's, 2.Nc3 d69p{ˁVE30 Nimzo-Indian: Leningrad, 6.d5 b5 Gambit(X6n^D35v QGD: Exchange, 5.Bg5 c6 6.e3 Be7 7.Bd3 O-O& $,A48b Neo-King's Indiana cHD14q Slav: Exchange, 8.Bb5 Nd7 9.Qa4HݱzD85s Grnfeld: Modern Exchange, 8.Rb1, 10...Qa5+ 11.Bd2 Qxa2 12.O-O Bg4 13.Bg5w‰bE12h Queen's Indian: Petrosian, 4...Ba6 5.Qc2 Bb7X!ZB75 Sicilian: Dragon, Yugoslav, 7...Nc6 8.Bc4]m<^xzB90i Sicilian: Najdorf, 6.Be3 Ng4 7.Bg5 h6 8.Bh4 g5 9.Bg3 Bg7}`ZA17 English: Anglo-Queen's Indian, Romanishino){%fDD08 QGD: Albin, 4.Nf3 Nc6 5.a3 Be6Բ>8B50e Sicilian: 2.Nf3 d6 3.d3iLBVD71 Neo-Grnfeld, 5.cxd5 Nxd5 6.e4 Nb4 7.d5poK.PD06b QGD: Austrian, Rubinstein Variation򾴮`E23 Nimzo-Indian: Spielmann, Stahlberg VariationbE);HA12 English: Caro-Kann Defence, 3.b3+9"5&A25 English: Closedg@B10e Caro-Kann: Breyer, 3.Nd2 e5 ޝVB53x Sicilian, Chekhover, Main Line, 11.Qd2ƉOXC80t Spanish: Open, Bernstein, Karpov GambitjvD76g Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O Nb6 8.Nc3 Nc6 9.e3 Re8˫~ tC57c Two Knights: Traxler, 5.Nxf7 & 6.Kf1, Beyer's 8...Bg4˖ )JD26k QGA: Classical, Furman, 6...cxd4˖gB|C43s Russian Game: Modern Attack, 3...Nxe4, Main Line, 7...Qh4ˊ>sGMLB72 Sicilian: Dragon, Classical Attack˄`{&bA33a English: Symmetrical, Two Knights, 5.Nc3 Nc6} WzE4D14f Slav: Exchange, 8.Qb3k"$A00t Benko Openingko^hC42w Russian Game: Classical, Chigorin, 8...Bg4 9.c4`"̾rC89q Spanish: Marshall, Main Line, 15.Be3 Bg4 16.Qd3 Rae8@ bVB22p Sicilian: Alapin, Heidenfeld Variation-P|B92r Sicilian: Najdorf, 6.Be2 e5 7.Nb3 Be7 8.O-O O-O 9.Kh1 Qc7 E t(E86i King's Indian: Smisch, Orthodox, 7.Nge2 c6 8.Qd2 Nbd7 9.O-O-O a6 10.Kb1 )z"PXB47a Sicilian: Taimanov, Bastrikov VariationN(B07u Pirc: 4.Be3 Bg7r"\E93 King's Indian: Petrosian, Main Line, 8.Qc2+3 2hB92g Sicilian: Najdorf, 6.Be2 e5 7.Nb3 Be7 8.Be3 Be6 Y;JA83d Dutch: Staunton Gambit, 4.Bg5 g6 03_"`2>D05f Colle: Rubinstein's Attack HV.,C13a French: ClassicalQ%ZE81l King's Indian: Smisch, 5...O-O 6.Be3 c6NTN*B11m Caro-Kann: Two Knights, 3...Bg4 4.h3 Bxf3 5.Qxf3 e6 6.d3 Nf6 7.a3 !vD97k Grnfeld: Russian, Alekhine, 8.e5 b5 9.Qb3 Nfd7 10.Be3Dfee.YbE04o Catalan: Open, 5.Nf3 c5 6.O-O Nc6 7.Qa4 cxd4?fOBD08 QGD: Albin, 4.Nf3 Nc6 5.a3 a50y:@B18b Caro-Kann: Classical, 5.Nc53X´8A45p Trompowsky: 2...c5 3.d5t A04 Reti: 1...c5nUlE04n Catalan: Open, 5.Nf3 c5 6.O-O Nc6 7.Ne5 Bd7 8.Na3osZ}VA54 Old Indian: 5.Bg5 Be7 6.e3 O-O 7.Qc2 c6OinhD36r QGD: Exchange, Main Line, 9.Nf3 Re8 10.O-O-O h6؋AҐNC19d French: Winawer, 6...Ne7 7.Nf3 Qc7ZϡS60B41f Sicilian: Kan, 5.c4,O~bB30t Sicilian: Rossolimo, 3...e6 4.O-O Nge7 5.Re1чDB07j Pirc: 3.Bd3 g6 4.Nf3 Bg7 5.c3Ř8p$lJE46 Nimzo-Indian: Reshevsky VariationvD46k Semi-Slav: Chigorin, 7.Qc2 Main Line, 9...a6 10.Rd1 b5ópWvD36y QGD: Exchange, Main Line, 9.Nf3 Re8 10.O-O Nf8 11.Rab1ʺռ72A30a English: SymmetricalʱWyH:lE87h King's Indian: Smisch, Orthodox, Bronstein, 9.g3ʕ;v<C15f French: Winawer, 4.Bd3 c5ʔ?6A57f Benko Gambit: 4.Nf3 g6ʌ0$WJB30o Sicilian: Rossolimo, 3...e6 4.b3|-S,9bA64 Benoni: Fianchetto, 11...Re8 12.h3 Rb8 13.Nc4z{[sjA52m Budapest: Rubinstein, Main Line, 6.Nbd2 Qe7 7.e3v$f;y5\D19j Slav: Dutch, 8...O-O 9.Qe2 Nbd7 10.e4 Bg6r^~{@(D15b Slav: 4.Nc3 Bf5^K<D96 Grnfeld: Russian, 6...O-O]=|:FC42o Russian Game: 5.Qe2, QueenswapQ.Jq)fE96 King's Indian: 7.O-O Nbd7, Old Main Line, 10.h3I$eAD85r Grnfeld: Modern Exchange, 8.Rb1 O-O 9.Be2 cd 10.cd Qa5+ 11.Bd2@(NA64 Benoni: Fianchetto, 11...Re8 12.Nc4, lD38p QGD: Ragozin, 5.Bg5 h6 6.Bxf6 Qxf6 7.e3 O-O 8.Rc1vqA\A68k Benoni: Four Pawns, 9.Be2 Bg4 10.O-O Nbd7hcq`C77u Spanish: Wormald Attack, Grnfeld Variation^ ׉VA42k Modern: Averbakh, Kotov, 5.Be3 e5 6.d5\7XD85f Grnfeld: Exchange, 7.Bb5+ c6 8.Ba4 O-OUI@B01e Scandinavian, Mieses GambitRI+t^A71 Benoni: Classical, 8.Bg5 h6 9.Bh4 a6 10.Nd2KkW`o)FD15n Slav: Chameleon, 5.a4 e6 6.Bg5I|(*A43e Old Benoni: 2.d5@bC4C84e Spanish: Closed, 6.d3:W}|ZE94o King's Indian: Glek, Main Line, 11.h3 h68ϗTE61q King's Indian: 4.Nf3 d6 5.Bf4 d6 6.h3.FHE12w Queen's Indian: 4.Nc3 Bb7 5.Bg5)sGhB78c Sicilian: Dragon, Yugoslav, 10.O-O-O Rc8 11.Bb3$UNA58k Benko Gambit: Fianchetto Variation!sjE15d Queen's Indian: Nimzowitsch Variation (4.g3 Ba6) <2D60 QGD: Orthodox Defence/X\RB08o Pirc: Classical, 5.Be2 O-O 6.O-O Nc6kXD42d QGD: Semi-Tarrasch, 6.e3 Nc6 7.Bd3 cxd4pOIND63 QGD: Orthodox, 7.Rc1 dxc4 8.Bxc4 a6 |B05p Alekhine: Modern, Main Line, 8.h3 Bh5 9.Nc3 O-O 10.Be3 d5 :S|B63i Sicilian: Richter-Rauzer, 7.Qd2 h6 8.Bxf6 gxf6 9.O-O-O a64|)z{hB33c Sicilian: Open, 2...Nc6, 5...Qb6 6.Nb3 e6 7.Bd34Z+2A80s Dutch: 2.Nf3 e6 3.d50$w`E12g Queen's Indian: Petrosian, 4...Ba6 5.Qc2 c5<HA16 English: Anglo-Indian, 2.Nc3 Nc6_sZB20 Sicilian: Wing Gambit, Marshall VariationȿzOD85q Grnfeld: Modern Exchange, 8.Rb1 O-O 9.Be2 cd 10.cd Qa5+ 11.Qd2ȼh *RC14b French: Classical, Pollock VariationȮ_)HA82 Dutch: Staunton Gambit, 3.Nc3 g6ȭ@>B91f Sicilian: Najdorf, 6.g3 e5Ȭ"HC61h Spanish: Bird's, 5.O-O c6 6.Bc4ȫQyBA61 Benoni: Nimzowitsch VariationȪYH,C10e French: 3.Nc3 Be7Ȣ(EYZE85d King's Indian: Smisch, Orthodox, 7.Nge2ȟgo rD36w QGD: Exchange, Main Line, 9.Nf3 Re8 10.O-O Nf8 11.h3Ȟ 0lfE19h Queen's Indian: Old Main Line, 9.Qxc3 f5 10.b3ȚdC69i Spanish: Exchange, Gligoric, 6.d4 exd4 7.Nxd4șDA03 Bird: 1...d5 2.Nf3 Nf6 3.g3 g6ȋ0.65RB19d Caro-Kann: Classical, 7.Nf3 Nf6 8.h5ȉ|5`j"D20d QGA: 3.e3 e6Ȉ\}ZC56h Two Knights: Classical, Moller Variationȇ-B38s Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 d6 9.O-O Bd7 10.Nc2Ȇtڵ4C40l Latvian Gambit: 3.Nc3}&9 "DC44u Scotch: Goring Gambit, 4...d5yl>C54b Giuoco Piano: Albin Gambitvw&Ȗ8B70e Sicilian: Dragon, 6.Bg5slrB75 Sicilian: Dragon, Yugoslav, 7...Nc6 8.Qd2 Bd7 9.O-O-Op~"PqFD26l QGA: Classical, Furman, 6...a6U܋~A68g Benoni: Four Pawns, 9.Be2 b5 10.e5 dxe5 11.fxe5 Ng4 12.Bg5O L;rND38g QGD: Ragozin, 5.cxd5 exd5 6.Bg5 h6MUo,A47 Neo-Queen's IndianD BR\C95i Spanish: Closed, Breyer, Main Line, 13.b4?D;?\Z\E18y Queen's Indian: Old Main Line, 8.Qc2 Nxc34~'!^B15m Caro-Kann: Gurgenidze: 4.Nf3 Bg7 5.h3 dxe40aLFC32 KGD: Falkbeer, Alapin Variation,]?VC38 KGA: Philidor Gambit, Schultz Variation'!FE80e King's Indian: Smisch, 5...e5$DsO:A00q Polish: 1...d5 2.Bb2 Bf5x0vA33i English: Symmetrical, Two Knights, 5.Nc3 Nc6 6.Ndb5 d5RA91 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nh3 O-O 6.O-O d6 7.Nc3 c6X/,l~B49l Sicilian: Taimanov, 6.Be3 a6 7.Be2 Nf6 8.O-O Bb4 9.Na4 Be7#8t@A53 Old Indian: 3.Nc3 Nbd7 4.Nf3BԩUFA59d Benko Gambit: 7.e4 Line, 9.Nf3֋XB90f Sicilian: Najdorf, Fischer-Sozin Attack {hE96 King's Indian: 7.O-O Nbd7, Old Main Line, 10.Rb1 NJ|x(B07d Pirc: 3.Nbd2 g6\PQ*B12g Caro-Kann: 3.Nd2Pa7tB66j Sicilian: Richter-Rauzer, 7...a6 8.O-O-O h6 9.Be3 Qc7Z ,tD79h Neo-Grnfeld, 6.O-O c6 7.cxd5 cxd5 8.Nc3 Nc6 9.Ne5 e68%PA09f Reti: Advance, 3.e3 Nc6 4.exd4 Nxd4f.H0E60d King's Indian: 3.f3Qr BC29s Vienna Gambit: Breyer, 6.Qe2y;"MhC24 Bishop's Opening: Urusov Gambit, 7...Nc6 DefenceJ?G]TB05n Alekhine: Modern, Main Line, 8.h3 Bh5e.?BA68d Benoni: Four Pawns, 9.Be2 b5A08 Reti: KIA, French VariationǠ`B44m Sicilian, Taimanov, Szen, 6.Bf4 e5 7.Be3 a6Ǚ5fQE_FC30l KGD: Classical, 3.Nf3 d6 4.Nc3ǓyN{DA21 English: King's, 2.Nc3 d6 3.d4nj٠"A80d Dutch: 2.Bg5{ܺNC72 Spanish: Modern Steinitz, 5.O-O Bg4x^r+VE90t King's Indian: 5.Nf3 O-O 6.h3 c5 7.Be3w3¯l$A00v Benko Openingq.X,VD81 Grnfeld: Early Russian, Adorjan GambitfTQ>DA40n Queen's Pawn: 1...e6 2.Nf3 c5a>JA48j Neo-King's Indian: London System`V=rA13w English: Neo-Catalan Accepted, 5.Qa4+ Nbd7 6.Qxc4 c5`^$lHA30e English: Symmetrical, b6 System[pWdA65v Benoni: Smisch, 8.Bg5 h6 9.Be3 O-O 10.Qd2 a6U,O* &8B50f Sicilian: 2.Nf3 d6 3.g3N'LA65o Benoni: Smisch, 8.Bg5 O-O 9.Nge2A=DC44y Scotch Gambit: Vitzhum Attack=ňXE15f Queen's Indian: Nimzowitsch, 5.Nbd2 Bb79e7R"B07q Pirc: 3...g69!J`C82o Spanish: Open, Dilworth, 12.Rxf2 f6 13.exf65D܁Ŀ`E08p Catalan: Closed, 7.Qc2 c6 8.b3 b6 9.Rd1 Bb7+=־NB40o Sicilian: Open, 2...e6, 4.Nxd4 Nf6&2ٕTE81e King's Indian: Smisch, 5...O-O 6.Bg5$OcBC20 Open Game: Napoleon's Opening!d)BC80o Spanish: Open, 8...Be6 9.Be3rJzKXD00k Trompowsky: 2...d5 3.Bxf6 exf6 4.e3 Bd6 XA83i Dutch: Staunton Gambit, 4.Bg5 e6 5.Nxe4ب^C15l French: Winawer, Winkelmann-Reimer, 6...c5+6 7RD27p QGA: Classical, Rubinstein Variationp?(^fA76 Benoni: Classical, Main Line, 10.Qc2 Na6 11.Re1{b>\D62 QGD: Orthodox, Rubinstein, 7.Qc2 c5 8.cxd51YU^C19f French: Winawer, 6...Ne7 7.Nf3 Qc7 8.a4 b6t1~:D63 QGD: Orthodox, 7.Rc1 dxc4ƿdaN8B43b Sicilian: Kan, 5.Nc3 d6ƪ,Ţ\E46 Nimzo-Indian: Reshevsky, Simagin VariationƞrMBD06f QGD: Marshall Defence, 3.Nc3ƙŬ=`C42u Russian Game: Classical, Jnisch, Main LineƗp\VB44e Sicilian: Taimanov, 5.c4 Nf6 6.Nc3 Bb4Ƒ‘lfE60n King's Indian: Fianchetto without Nc3, 6...Nc6ƌ3'tA14 English: Neo-Catalan Declined, 5...O-O 6.b3 c5 7.Bb2 Nc6 8.e3ƄƃQK]HE43 Nimzo-Indian: Nimzowitsch, 5.Bd3w]{^A75 Benoni: Classical, 9.O-O a6 10.a4 Bg4 11.h3vɮhB@A64 Benoni: Fianchetto, 11...Re8thE@7XB99f Sicilian: Najdorf, Main Line, 10.Bd3 h6h#AEY#AHA48q Neo-King's Indian: Torre Attack];~DC30q KGD: Classical, 4.c3 Nf6 5.d4[gZZB02h Alekhine: Scandinavian, Exchange, 4.Nxd5S`cC92u Spanish: Closed, Zaitsev, 12.a4 h6 13.Bc2 exd4 14.cxd4 Nb4 15.Bb1 c5Oη*DD30x QGD: 3.Nf3 Nf6 4.Bg5 Be7 5.e3J)OETA64 Benoni: Fianchetto, 11...Re8 12.h3 Rb8E|3&0VB42j Sicilian: Kan, 5.Bd3 Nf6 6.O-O d6 7.c4E`&LA34 English: Symmetrical, 2...Nf6 3.g3>v,QPD59b QGD: Tartakower, 8.cxd5 Nxd5 9.Nxd5p`JC51 Evans Gambit: Anderssen Variation/m*p"B07q Pirc: 3...g6$EXC51 Evans Gambit Declined, Vasquez Variation"sTVB96j Sicilian: Najdorf, 7.f4 Nbd7 8.Qf3 Qc7Ko8B33g Sicilian: Pelikan, 7.a4fTBVB84 Sicilian: Scheveningen, Classical, 7.f4м,A47 Neo-Queen's Indian9 qJPC56d Two Knights: Classical, 7.Bxd5 Qxd56ވ^B01w Scandinavian: Marshall, 4.Nf3 Bg4 5.Be2 e6 zTB00x Nimzowitsch Defence: 2.d4 d5 3.e5 Bf5 pJD27i QGA: Classical, 6...a6 7.Bb3 Nc6ObD,A47 Neo-Queen's Indian"BA15 English: Anglo-Indian, Polish2]p/DC09d French: Tarrasch, Open, 7.O-O# PD87e Grnfeld: Classical Exchange, 9.O-OEbD79f Neo-Grnfeld, 6.O-O c6 7.cxd5 cxd5 8.Nc3 Nc6Ęd>B04a Alekhine: Modern Variation* E61z King's Indian: Smyslov System, 5...O-O 6.e3 Nbd7 7.Be2 c6 8.O-O &hzD42m QGD: Semi-Tarrasch, 7.Bd3 Main Line, 10.Re1 Nf6 11.a3 b6Q}\A34 English: Symmetrical, 3 Knights, 5.d4 cxd4a!rh<LD49e Semi-Slav: Meran, Sozin Variationv41VC56i Two Knights: Classical, Moller, 10.Bg5+`/DE27 Nimzo-Indian: Smisch, 5...O-Oik?k D05h Colle: 5.c3߀"jB59i Sicilian: Boleslavsky, 7.Nb3 Be7 8.O-O O-O 9.Kh1č8]$g2B43a Sicilian: Kan, 5.Nc3Ŵ!\=ٓ<B22o Sicilian: Alapin, 2...Nf6ŪɚVD32t QGD Tarrasch: 5.Nf3 Nc6 6.e3 Nf6 7.Be2ŦB32r Sicilian: Lowenthal, Kalashnikov, 6.N1c3 a6 7.Na3 b5 8.Nd5 Nge7ţ{ qNB22a Sicilian: Alapin, 2...g6 3.d4 cxd4Ř'hJB20 Sicilian: Keres Variation (2.Ne2)ŒZ,A47 Neo-Queen's Indianń@ -B90q Sicilian: Najdorf, 6.Be3 e5 7.Nb3 Be6 8.f3 Be7 9.Qd2 O-O 10.O-O-Ov]]6DE04f Catalan: Open, 5.Nf3 a6 6.O-OfljlbC55w Two Knights: Max Lange, Schlechter Variationc#oNC25p Vienna: 2...Nc6 3.f4 exf4 4.Nf3 g5ad2E24 Nimzo-Indian: Smischagg{<E04c Catalan: Open, 5.Nf3 Nbd7_}Ӯ RC90i Spanish: Closed, Pilnik, 11.Nbd2 Qc7SJ|pE94c King's Indian: 7.O-O exd4 8.Nxd4 Re8 9.f3 c6 10.Kh1N46C02f French: Advance, 4.Nf3ID>edC55j Two Knights: 4.d3 Be7 5.O-O O-O 6.Bb3 d6 7.c3<+ r\[`B97f Sicilian: Najdorf, Poisoned Pawn, 8.Nb3 Be79pbE05v Catalan: Open, Classical, 8.Qxc4, 10.Bf4 Nc69=w4A55k Old Indian: Main Line5ZY?f:D30t QGD: Spielmann Variation!4^D85l Grnfeld: Modern Exchange, 8.Be2 O-O 9.O-Otn (<B95a Sicilian: Najdorf, 6...e63yLPLC01s French: Exchange, 4.Nc3 Nf6 5.Nf3?8D22g QGA: Alekhine, 4.e3 Bg4aG4DE90i King's Indian: Larsen, 6...e5VD43v Semi-Slav: Moscow, 7.e3 Nd7 8.Bd3 dxc44 C85r Spanish: Closed, Exchange, 7.d3 Nd7 8.Nbd2 O-O 9.Nc4 f6 10.Nh4 Nc5 11.Nf5h{:A21 English: King's, 2.Nc3 f50˄FC55q Two Knights: Modern, Main Linegi+lE15r Queen's Indian: Nimzowitsch, 5.b3 Bb4+, Main Line؀rN6A86 Dutch: Leningrad, 4.Bg2!>X2A46s Torre Attack: 3...c5¼ah4XD18s Slav: Dutch, 8...O-O 9.Nh4 Nbd7 10.Nxf5¸UhXNA44h Old Benoni: Czech, 3.c4 d6 4.e4 g6Ľߘ{VB98l Sicilian: Najdorf, Gothenburg, 11.Nxe6ĽRYJLE14m Queen's Indian: 4.e3 Bb7 5.Bd3 d5Ķ&vE59 Nimzo-Indian: Main Line, 9.bxc3 dxc4 10.Bxc4 Qc7 11.Bb2ĵZ)cu2C52 Evans Gambit: 5...Ba5ĦR^gTC63m Spanish: Schliemann, 4.Nc3 Nf6 5.exf5Ğ$52=\C58f Two Knights: Morphy, Blackburne Variationą E11a Bogo-IndianpS\@C80n Spanish: Open, 8...Be6 9.a4lQVE08f Catalan: Closed, Zagoryansky Variationj?,74A46j Indian: 2.Nf3 e6 3.c3i6޿zE92l King's Indian: Gligoric-Taimanov, 7...Ng4 8.Bg5 f6 9.Bh4d⡈7<D15v Slav: Geller Gambit, 6.e5U7HC77n Spanish: Centre Attack, 5...Be7Nt A02 Bird: 1..d6K9\4dD03p Torre Attack: 3...g6 4.e3 Bg7 5.Nbd2 O-O 6.c3Jَ4^E76b King's Indian: Four Pawns Attack, ExchangeJsPGW*B02a Alekhine Defence7df-0D45i Semi-Slav: 6.Qc2 b60e|E84n King's Indian: Smisch, Panno Main Line, 9.h4 h5 10.O-O-O&VDmFD45o Semi-Slav: 6.Qc2 Bd6 7.g4 Nxg4"Sm=-|HA66 Benoni: Mikenas Attack, 8...Nfd7!KxE84i King's Indian: Smisch, Panno Main Line, 9.Nc1 e5 10.d5 F@jHA48u Neo-King's Indian: Torre AttackDO{:E17m Queen's Indian: 6.O-O d5O~ǦE74c King's Indian: Averbakh, 6...c5 7.dxc5 Qa5 8.Bd2 Qxc5 9.Nf3 Bg4(uvE62k King's Indian: Fianchetto, Kavalek/Bronstein, 8.e4 Bg42NC05d French: Tarrasch, Closed, 4...Nfd7vϟ TD98c Grnfeld: Russian, Smyslov, 8.Be2 Nc6^_&TC86b Spanish: Worrall Attack, 6...b5 7.Bb3=fD15s Slav: Accepted, Alekhine: 5...b5 6.a4 b4 7.Nb1~pN5LB86 Sicilian: Sozin-Najdorf, 7.Bb3 Be7dVE15e Queen's Indian: Nimzowitsch, 5.Nbd2 c5òBD2D08 QGD: Albin, 3.dxe5 d4ñ?WTC30i King's Gambit: Adelaide-Wahls, 4.exf5íuDlB35d Sicilian: Accelerated Fianchetto, Modern, 7.Bc4 Qa5 8.O-O O-O 9.Bb3í}̶*dB13i Caro-Kann: Exchange, 4.Bd3 Nc6 5.c3 Nf6 6.Nf3á ;cBB99a Sicilian: Najdorf, Main Lineà\Ng$4C55e Two Knights: 4.d3 Be7ÞZ8$@<E08c Catalan: Closed, 7.Qc2 b6ÚtbE16p Queen's Indian: Capablanca, 6...Bxd2+ 7.Qxd2Ùz6JD69 QGD: Orthodox, Classical, 13.dxe5ÕԓtXA68f Benoni: Four Pawns, 9.Be2 b5 10.e5 dxe5ÉWp0A10 English: Anglo-Dutchz ORD85m Grnfeld: Modern Exchange, 8.Rb1 O-OzǤj:A03 Bird: Lasker, 3...c5 4.b3tmc^E71f King's Indian: Makagonov, 5...O-O 6.Be3 e5lk[-C:D30t QGD: Stonewall FormationeՑ`YgZA42b Modern: Averbakh, Randspringer Variation]Ι':C00j French: 2.Nf3 d5 3.e5 c5R"̎ ZC30m KGD: Classical, 3.Nf3 d6 4.Nc3 Nf6 5.Bc4R0FND48e Semi-Slav: Meran, 8...a6 9.O-O Bb7L YD57 QGD: Lasker Defence, Main Line, Bernstein, 12.c4 dxc4 13.Bxc48 <C01c French: Exchange, 4.c4 c67BB48c Sicilian: Taimanov, 6.Be3 a66'%=ND43g Semi-Slav: Botvinnik, 5...Be7 6.e35b/ bB74 Sicilian: Dragon, Classical, Stockholm Attack3 0]0A43f Old Benoni: 2.d5 e6/ۆ`B23x Sicilian: Closed, Grand Prix, 3...g6 4.Nf3 Bg7 5.Bb5 Nd4 6.Bd3'PD50 QGD: Dutch-Peruvian, Prins Variation4A>C41f Philidor: Hanham Variation@::tB66m Sicilian: Richter-Rauzer, 7...a6 8.O-O-O h6 9.Be3 Be7JXj^C42x Russian Game: Classical, Maroczy Variation r>"wZD87j Grnfeld: Classical Exchange, 10.Be3 Qc7 r{pi@C25p Vienna: Hamppe-Muzio Gambitp^hE09g Catalan: Closed, Main Line, 9.b3 Bb7 10.Bb2 Rc8eJE61g King's Indian: 4.g3 O-O 5.Bg2 d6]8r$A80i Dutch: Alapin7Npy4B40f Sicilian: 2...e6 3.d3ućPPA36c English: Symmetrical, 3.g3 e6 4.Nf3ΏoHA48t Neo-King's Indian: Torre Attack̊]TD82 Grnfeld: 4.Bf4 Bg7 5.e3 c5 6.dxc5 Qa5Hj- .D73 Neo-Grnfeld, 5.Nf3"[FC94c Spanish: Closed, Breyer, 10.d3׃H7PD33p QGD Tarrasch: 7.Bg2 cxd4 8.Nxd4 Be7֬p9'fB80h Sicilian: Scheveningen, English, 7...Nc6 8.Qd2S ;E69n King's Indian: Fianchetto, Classical, 9.h3 Qb6 10.Re1 exd4 11.Nxd4 Re8Ku+B06b ModernK{uJD02d Queen's Pawn: 2.Nf3 Bf5 3.Bf4 c6iUͼxD40n QGD: Semi-Tarrasch, 5.e3 Nc6 6.a3 cxd4 7.exd4 Be7 8.Bd3½W+RD50 QGD: Semi-Tarrasch, Pillsbury, 6.Nxd4¼6:C30o KGD: Classical, 4.c3 Bb6¥[*VA36n English: Symmetrical, Botvinnik SystemWl B06f Modern›dy|D89i Grnfeld: Classical Exchange, Main Line, Sokolsky, 16.Bh6—+Ms3DA85 Dutch: 2.c4 Nf6 3.Nc3 g6 4.Nf3–ށTB A03 Bird: 1...d5”|-٩FC62 Spanish: Old Steinitz, 4.d4 Bd7O>C51 Evans Gambit Declined, 5.a4…e:A61 Benoni: 6.Nf3 g6 7.Bf4 a6DrTD70 Neo-Grnfeld: Alekhine's Anti-GrnfeldvD@\^B81o Sicilian: Scheveningen, Keres, 6...h6 7.g5tξ6B86 Sicilian: Sozin-Najdorfp8nBA46f Neo-Benoni: 3.g3 cxd4 4.Nxd4k:/ɎJB26e Sicilian: Closed, 6.Be3 e5 7.Qd2fhם&A25 English: Closedf/厍XA99 Dutch: Ilyin-Zhenevsky, 8.b3 a5 9.Bb2 c6WՑ {pB99j Sicilian: Najdorf, Main Line, 10.Bd3 b5 11.Rhe1 Bb7VLƸ5SVC32 KGD: Falkbeer, Main Line, 7...Bf5 8.Nc3UtLy|E99 King's Indian: Mar del Plata, 10.f3 f5 11.Be3 f4 12.Bf2 g5O]vB12h Caro-Kann: Gurgenidze/Modern: 3.Nd2 g6 4.Ngf3 Bg7 5.h3Ne;JA08 Reti: KIA, 2...c5 3.Bg2 Nf6 4.O-O7O3bbD35h QGD: Exchange, 5.Nf3 Be7 6.Bf4 c6 7.Qc2 Nbd7/X JJB72 Sicilian: Dragon, 6.Be3 Bg7 7.Bc4/8=n(A80d Dutch: 2.Bg5 d5&0:B12n Caro-Kann: Advance, 4.c3~H%"dC49j Four Knights: Symmetrical, Tarrasch Variation]I>C10b French: Marshall Variation u#l'dD29n QGA: Classical, 8...Bb7 9.Rd1 Nbd7 10.Nc3 Qb6 %R@A40i Englund Gambit: Zilbermints~N ?~D37s QGD: Classical, 5...O-O 6.e3 c5 7.dxc5 Bxc5 8.Qc2 Nc6 9.a3h َ\\A31 English: Symmetrical, Two Knights, 4...Nc66^ZD36i QGD: Exchange, 6.Qc2 Be7 7.e3 Nbd7 8.Bd3,ַfB81l Sicilian: Scheveningen, Keres, 6...h6 7.h4 Nc6mm=R\E56 Nimzo-Indian: Main Line, 7...Nc6 8.a3 dxc4 RBS:<C45w Scotch: Meitner VariationIHY.D32j QGD Tarrasch: 5.g3{Y8LA56w Benoni: Czech, 5.e4 Be7 6.Nf3 O-OSt?FA30b English: Symmetrical, 2.Nf3 b6Ѹg`A28 English: Four Knights, Nimzowitsch Variation8ؑ$D20o QGA: 3.e4 Nf6λ&8x|VE61n King's Indian: 4.Nf3 O-O 5.e3 d6 6.Be2)ZB78b Sicilian: Dragon, Yugoslav, 10.O-O-O Ne5LԢD^E54 Nimzo-Indian: Main Line, Karpov, 10.Bg5 Bb7ѯŒr.C31 KGD: Falkbeer, 4.d3w4E17l Queen's Indian: 6.O-OG}Ln`|B06b ModernֻhC89p Spanish: Marshall, Main Line, 15.Be3 Bg4 16.Qd3UbE|B70r Sicilian: Dragon, 6.Be2 Bg7 7.O-O O-O 8.Re1 Nc6 9.Nb3 Be6"e2D35d QGD: Exchange, 5.Nf3|jB32u Sicilian: Lowenthal, Kalashnikov, 6.c4 Be7 7.Be2s \bY[\E03 Catalan: Open, 5.Qa4+ Nbd7 6.Qxc4 c5 7.Nf3h)IYIHA51j Budapest: Fajarowicz, 4.Nf3 Nc6gZT5{8D66 QGD: Orthodox, Main LineY jz*VB57m Sicilian: Sozin, Benko, 7.Nb3 e6 8.O-OQ-ZD29h QGA: Classical, 8...Bb7 9.Rd1 Nbd7 10.a4FuT_MjE83c King's Indian: Smisch, 6...Nc6 7.Qd2 a6 8.O-O-OAgbPLD12p Slav: 4.e3 Bf5 5.Nc3 e6 6.Nh4 Be4@\m#JB50n Sicilian: 2.Nf3 d6 3.c3 Nf6 4.h3@ŀsVB96o Sicilian: Najdorf, Polugaevsky, 10.Nf3>>$l"D20f QGA: 3.e3 e5A00m Van Geet: 1...d5 2.Nf3 Nf6'kLB16i Caro-Kann: Bronstein-Larsen, 6.c3WFE14e Queen's Indian: 4.e3 Bb7 5.Bd37‰o`A41g Neo-Old Indian: Wade Defence, 3.c4 e5 4.Nc3;XC40p Latvian Gambit: Svedenborg, 6.Nxg6 hxg6ݡ&;>C42c Russian-Three Knights Game[5B,LD84 Grnfeld: Grnfeld Gambit AcceptedYpk\D64 QGD: Orthodox, Rubinstein Attack, 8...dxc4,,NpB36i Sicilian: Maroczy Bind, 5...Nf6 6.Nc3 d6 7.Be2 Nxd4;*zE92k King's Indian: Gligoric-Taimanov, 7...Ng4 8.Bg5 f6 9.Bc1 6E01 Catalan: 4...Bb4+ 5.Nd2S!hC99e Spanish: Closed, Chigorin, 13...Bb7 14.Nf1 Rac8 ofC48h Four Knights: Rubinstein, Bogoljubow Variation愵pB22n Sicilian: Alapin, 2...d5 3.exd5 Qxd5 4.d4 Nf6 5.Nf3 e6 6.Be20s~E68d King's Indian: Fianchetto, Classical, 8.e4 exd4 9.Nxd4 Nc5q6'B47z Sicilian: Taimanov, 6.Be2 a6 7.O-O Nf6 8.Kh1 Nxd4, 10.Qd3 b5 11.f4˽C0rB85 Sicilian: Scheveningen, Classical, Main Line, 9...Nc6<{;^A69e Benoni: Four Pawns, Main Line, 10.Nd2 Nbd7<FC16c French: Winawer, 4.e5 b6 5.Qg4k˲Λ,C70 Spanish: 4.Ba4 Be7@Ej`E18t Queen's Indian: 7.Nc3 Ne4 8.Nxe4 Bxe4 9.Ne1>C78p Spanish: Archangelsk, 7.d3;izE57 Nimzo-Indian: Main Line, 8...dxc4 9.Bxc4 cxd4 10.exd4 Be7n lB67l Sicilian: Richter-Rauzer, 7...a6, 9.f4 b5 10.Nxc6_TC50f Italian: Hungarian Defence, 4.d4 exd4٠YwBC90d Spanish: Closed, 8...d6 9.a42׺56D02b Queen's Pawn: 2.Nf3 c6*B_iZA46z Torre Attack: 3...h6 4.Bxf6 Qxf6 5.e4 d6,v*B63n Sicilian: Richter-Rauzer, 7.Qd2 Be7 8.O-O-O Nxd4 9.Qxd4 O-OqЂTE15i Queen's Indian: Nimzowitsch, 5.Qa4 c6f|HC86c Spanish: Worrall Attack, 7...d6d֑ HC52 Evans Gambit: Sokolsky Variation(C6E10o Blumenfeld: 5.Bg5 Qa5+^hVD32d QGD Tarrasch: von Hennig-Schara Gambit^A16 English: Anglo-Grnfeld, Korchnoi Variation~Z DE61g King's Indian: 4.g3 O-O 5.Bg2tNv}l$A60b Benoni: 4.Nf3]"~MZB18o Caro-Kann: Classical, 6.Nf3 Nd7 7.Bd3 e6\e"I{LC32 KGD: Falkbeer, Charousek VariationQ|b>D58f QGD: Tartakower, 8.Bd3 Bb7DXT~D49k Semi-Slav: Meran, Old Main Line, 11.Nxb5 axb5 12.exf6 gxf6DjCLC33 KGA: Bishop's Gambit, Grimm Attack"'9[`DC57d Two Knights: Traxler, 5.Bxf7+ e@>NC13l French: Chatard-Alekhine, 6...Bxg5aq9:D92 Grnfeld: 5.Bf4 O-O 6.Rc1 }~LB54i Sicilian: Prins (Moscow), 5...Nc6 $NC35 KGA: Cunningham, Three Pawns Gambit -g*>A53 Old Indian: 3.Nf3 Bg4 4.Nc3* upC25n Vienna: Steinitz Gambit, Fraser-Minckwitz VariationPS}C PC37 KGA: Salvio, Anderssen CounterattackݢjC`E15n Queen's Indian: Nimzowitsch, 5.b3 Bb7 6.Bg2w8^\B67h Sicilian: Richter-Rauzer, 7...a6, 9.f4 h6 LE90m King's Indian: 5.Nf3 O-O 6.h3 Na6ͬYZB60h Sicilian: Richter-Rauzer, Larsen, 7.Bxf6h TE60k King's Indian: Fianchetto without Nc3uxSN:D07p QGD: Chigorin, 3.Nc3 Nf6%C<LB24 Sicilian: Closed, 3.g3 g6, 5.d3 e6ɴoȿqd>C47f Four Knights: Glek, 4...d5G0E97n King's Indian: Mar del Plata, Bayonet Attack, 9...Nh5 10.g3E{lA46n Indian: 1.d4 Nf6 2.Nf3 e6 3.g3 b5 4.Bg2 Bb7 5.O-OꏂnB34n Sicilian: Accelerated Fianchetto, Modern, 6.Be3 d6* l?fE98d King's Indian: Mar del Plata, 9.Ne1 Ne8 10.Nd3댤HA11 English: Caro-Kann Defence, 3.e3+n6D34p QGD Tarrasch: 9.Bg5 c4@fiBB10h Caro-Kann: English VariationXbJ"hD91l Grnfeld: 5.Bg5 Ne4 6.cxd5 Nxg5 7.Nxg5 e6 8.Qd2Ly7OvB64f Sicilian: Richter-Rauzer, 7.Qd2 Be7, 9.f4 h6 10.Bh4 e5wC2C30n KGD: Classical, 4.c3RC54o Giuoco Piano: Mller, Bayonet AttackudC` 7fE65d King's Indian: Fianchetto, Yugoslav, 7.O-O Nc6uD\lE66e King's Indian: Fianchetto, Yugoslav Panno, 9...a6q;iTE33 Nimzo-Indian: Classical, 4...Nc6 5.Nf3R'cbA55e Old Indian: 5.e4 Be7 6.g3 c6 7.Bg2 O-O 8.O-OQlNLB88 Sicilian: Sozin, Fischer Variation@QUfBD27f QGA: Classical, 6...a6 7.Bb3<yC07s French: Tarrasch, Open, 4.exd5 Qxd5, Main Line, 10.Nxd4 a6 11.c34_IV,C33 KGA: Orsini Gambit*}.PvrB47k Sicilian: Taimanov, 6.g3 a6 7.Bg2 d6 8.O-O Bd7 9.Re1,lT.C27a Vienna: 3.Bc4 Nxe4>a<B25i Sicilian: Closed, 6.f4 e5!ULD00w Blackmar-Diemer: Gunderam Defences26B36a Sicilian: Maroczy BindTzfJB32e Sicilian: Open, 2...Nc6, 4...Qb6FnB17e Caro-Kann: Steinitz, 5.Nf3 Ngf6 6.Nxf6+ Nxf6 7.Bc4S1,6A24 English: Bremen, 3...g6رŤFB21s Sicilian: Smith-Morra AcceptedFXuC10x French: Rubinstein, 4...Bd7 5.Nf3 Bc6 6.Bd3 Nd7 7.O-O Ngf6 8.Ng3տkj~TA38b English: Symmetrical, Main Line, 6.d4e/D91r Grnfeld: 5.Bg5 Ne4 6.cxd5 Nxg5 7.Nxg5 e6 8.Nf3 exd5 9.e3 O-O 10.Bd30<6D63 QGD: Orthodox, 7.Rc1 b6F PC48q Four Knights: Rubinstein, 5.Ba4 Bc5 90D24b QGA: 4.Nc3 e6 5.Bg5yTDA43u Old Benoni: Schmidt, 3.e4 Nf64{8D79j Neo-Grnfeld, Main LineGoCrA13w English: Neo-Catalan Accepted, 5.Qa4+ Nbd7 6.Qxc4 a6b/$D55c QGD: 6.Nf3 b6 l4i#\E47 Nimzo-Indian: 4.e3 O-O 5.Bd3 c5 6.Ne2 cxd4A~ 2E73a King's Indian: 5.Be2.(TE61t King's Indian: Smyslov System, 5...c5A`o^B67d Sicilian: Richter-Rauzer, 7...a6, 9.f3 Rc8NZC55x Two Knights: Max Lange, Berger Variationqz$8D94 Grnfeld: 5.e3 O-O 6.Bd3oqM}\E81f King's Indian: Smisch, 5...O-O 6.Bg5 Nc6k DA68a Benoni: Four Pawns, 8.Nf3 O-Oj 5yFC54l Giuoco Piano: Krakow VariationhDHC24 Bishop's Opening: Berlin Defence] }|D40r QGD: Semi-Tarrasch, 5.e3 Nc6 6.a3 a6 7.dxc5 Bxc5 8.b4 Ba7MlZE54 Nimzo-Indian: Main Line, Karpov VariationF~|bD85h Grnfeld: Exchange, 7.Be3 c5 8.Qd2 Qa5 9.Rb16hTE32h Nimzo-Indian: Classical, 4...O-O 5.a36Dk 6xpB11g Caro-Kann: Two Knights, 3...Bg4 4.h3 Bxf3 5.Qxf3 e6)Z pRhB25x Sicilian: Closed, 6.f4 e6: 9.Be3 Nd4 10.e5 Nef5$kOnB11c Caro-Kann: Two Knights, 3...Bg4 4.h3 Bh5, 7.g4 Bg6 A6A24 English: Bremen, 3...g6#[YzE69u King's Indian: Fianchetto, Classical, 9.h3 Re8 10.Re1 a5ߚ}h`B01d Scandinavian: Schiller, Bronstein VariationjLB09l Pirc: Austrian, 5...O-O 6.Bd3 Na6q$A45g Indian: 2.Bf4f2nPdE67l King's Indian: Fianchetto, Classical, 8.h3 c6R6C08m French: Tarrasch, Open, 4.exd5 exd5 5.Ngf3 Nf6, Main Line, 10.Nb3 pV6B06n Modern: 3.Nc3 d6 4.Bc4>AmDA69a Benoni: Four Pawns, Main LinejC16i French: Winawer, Petrosian, 5.a3 Bxc3+ 6.bxc3 b6ɩa(E17y Queen's Indian: Pomar, Polugaevsky, 8...c6 9.cxd5 Nxd5 10.Nf5 Nc7ǠޅBD78g Neo-Grnfeld, 6.O-O c6 7.Qb3`k_TC82l Spanish: Open, St. Petersburg, 11.Bc2ɼYзB35o Sicilian: Accelerated Fianchetto, Modern, 7.Bc4 O-O 8.Bb3 d6 9.h3+d|TC17f French: Winawer, Bogoljubow, 5...cxd4W9bC87k Spanish: Closed, Averbakh, 7.c3 O-O 8.d4 Bd7F*HE11o Bogo-Indian: Nimzowitsch, 5.Nc3}IA02 Bird: 1..g6z߿@4D06b QGD: Austrian Defencez}(>RdE25 Nimzo-Indian: Smisch, Keres, Romanovsky, 9.e4k|s2XB02g Alekhine: Scandinavian, Exchange, 4.Nf3g 2=Z6B30d Sicilian: 2...Nc6 3.g3W0X@D76l Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O Nb6 8.Nc3 Nc6 9.d5 Na5 10.e4 c6 11.Bg5UVNC69j Spanish: Exchange, Gligoric, 8.Ne2MQ !dE32j Nimzo-Indian: Classical, 4...O-O 5.a3, 6...d6K\5"|A30g English: Symmetrical, Mutual Double Fianchetto with ...d5B!řdD31x Semi-Slav: Marshall Gambit, 5.Nxe4 Bb4+ 6.Bd29=.`E92d King's Indian: 6.Be2 e5 Queenswap, 9.Bg5 c66 sA05 Reti: KIA#i-d|9^E76k King's Indian: Four Pawns Attack, 6.Nf3 c5!e`ǮnE14l Queen's Indian: 4.e3 Bb7 5.Bd3 Be7 6.O-O O-O 7.Nc3 bՒW`E92m King's Indian: Gligoric-Taimanov, Main Lineu"avE66g King's Indian: Fianchetto, Yugoslav Panno, 9...a6 10.Rb1 Rb8HAԛ@`C42q Russian Game: Classical, Marshall Variation ~%/\C18u French: Winawer, Poisoned Pawn, Main Line8r@E11c Bogo-Indian: 4.Nbd2 b6 5.a3mP:B12c Caro-Kann: Mieses Gambit:ݽ}`C95f Spanish: Closed, Breyer, 10.d4 Nbd7 11.Nbd2/HA55s Old Indian: Main Line, 8.Re1 a6ςm!:C11a French: 3.Nc3 Nf6 4.exd5;;fC89w Spanish: Marshall, Main Line, Classical, 18.a4 >A86 Dutch: Leningrad, 4.Nc3 Bg73=@D43k Semi-Slav: Moscow Variation}IhB34m Sicilian: Accelerated Fianchetto, Modern, 6.Be3ȒPC65g Spanish: Berlin, Mortimer VariationuQXD87f Grnfeld: Classical Exchange, 9.O-O Nc6B6ŋ`E55 Nimzo-Indian: Main Line, Bronstein Variation>A45u Trompowsky: Borg VariationUpZD79b Neo-Grnfeld, 6.O-O c6 7.cxd5 cxd5 8.Nc3Y@<B04b Alekhine: Modern, 4...Nc6ɀ ։^C48a Four Knights: Spanish, Spielmann Variation>?7LB02f Alekhine: Scandinavian, 3.e5 Nfd7%ŜDhB92j Sicilian: Najdorf, 6.Be2 e5 7.Nb3 Be7 8.O-O O-O'|+2>B46a Sicilian: Taimanov, 5...a61JD(D05j Colle: 5.c3 Nc6|s4C60s Spanish: Cozio, 4.O-O}l"tE58 Nimzo-Indian: Main Line, 9.bxc3 Qc7 10.cxd5 exd5 11.a4x `B25u Sicilian: Closed, 6.f4 e6: 9.Be3 Nd4 10.Rb1uqJB01x Scandinavian: Marshall, 4.Nf3 g6pڙ~rZE05u Catalan: Open, Classical, 8.Qxc4, 10.Bf4mdUQH^A65g Benoni: 6.e4 g6 7.Bd3 Bg7 8.Nge2 O-O 9.O-Oh&.tLfD85l Grnfeld: Modern Exchange, 8.Be2 O-O 9.O-O Nc6e-ؗhC42x Russian Game: Classical, Chigorin, 8...Bg4 9.c3c) ZA83f Dutch: Staunton Gambit, Lasker Variation_bwﱼNE94x King's Indian: 7.O-O Nbd7 8.Be3 c6V2D03k Torre Attack: 3...g6TLB30p Sicilian: Rossolimo, 3...e6 4.Nc3MI<XB01t Scandinavian: Icelandic Gambit AcceptedK6wND42a QGD: Semi-Tarrasch, 6.e3 Nc6 7.Bd3JY<C89b Spanish: Marshall, 9.exd5A7xBB00v Nimzowitsch Defence: 2.d4 d5?|6LE04i Catalan: Open, 5.Nf3 a6 6.O-O Nc6/Q;$VC54o Giuoco Piano: Mller (Therkatz) Attack.YrNC80p Spanish: Open, Bernstein Variation+Eic*D46a Semi-Slav: 6.Bd3Pf9LC19b French: Winawer, Smyslov, 7...Qa5v.\C12c French: MacCutcheon, Bogoljubow VariationJ tFB24 Sicilian: Closed, 3.g3 g6, 5.f4>uĄ HC26t Vienna: 3.Bc4 Bc5 4.d3 d6 5.Na4S1{JC17a French: Winawer, Advance, 4...c5 zxE33 Nimzo-Indian: Classical, Milner-Barry (Zurich) Variationڐj7<$D94 Grnfeld: 5.e3k;<D35i QGD: Exchange, 5.Bg5 Nbd78|FDD78k Neo-Grnfeld, 6.O-O c6 7.Nbd2B8}[HE06 Catalan: Closed, 6.O-O c5 7.cxd55nhA36o English: Symmetrical, Botvinnik, 5...Nf6 6.Nge2 pD26o QGA: Classical, Furman, 6...a6 7.dxc5 Bxc5 8.O-O b5Yϼ@E00m Catalan: 3...Bb4+ 4.Bd2 Qe7exRC41u Philidor: Improved Hanham, Main Line%kh]lB45q Sicilian: Taimanov, Four Knights, American Attack֯~_6D31e QGD: Alatortsev, 5.Bf4x-]FA17 English: Anglo-Indian, 2.Nc3 e6vQTE36 Nimzo-Indian: Classical, Noa, 5.a3 Be7ЇFC65e Spanish: Berlin, Nyholm AttackSiDB37b Sicilian: Maroczy Bind, 6.Nb3uqL+pD30i QGD: Tarrasch without Nc3: 5.g3 Nc6 6.Bg2 Nf6 7.O-O'|NB18r Caro-Kann: Classical, 6.h4 h6 7.f4I\C49h Four Knights: Symmetrical, Maroczy System))}DB01i Scandinavian: 2...Qxd5, 5.Bd2_"D16a Slav: AlapinoWHA48w Neo-King's Indian: Torre Attack>XB33u Sicilian: Pelikan, Sveshnikov Variation|go\B58k Sicilian: Boleslavsky, 7.Nf3 h6 8.O-O Be7mtpw^B38h Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 b6f(DRB72 Sicilian: Dragon, 6.Be3 Bg7 7.Bc4 Nc6G4hPD11q Slav: 4.e3<NJA8A02 Bird: From Gambit, Lipke/?;bE35 Nimzo-Indian: Classical, Noa, Exchange, 6.Bg5+bDJ"bE57 Nimzo-Indian: Main Line, 8...dxc4 9.Bxc4 cxd4(=TjA36r English: Symmetrical, Botvinnik, 5...e6, 8.d3 d6!Jv.ElD72 Neo-Grnfeld, 5.cxd5 Nxd5 6.e4 Nb6 7.Ne2 O-O 8.O-O&"ܷVE30 Nimzo-Indian: Leningrad, 4...c5 5.d5 d6G`PC33 KGA: Bishop's Gambit, Bledow, 4.exd5mW?8C25n Vienna: Steinitz Gambit?VB19i Caro-Kann: Classical, Spassky, 10.Qxd3a2iRA08 Reti: KIA, 2...c5 3.Bg2 Nf6 4.O-O Nc6yJC39 KGA: Kieseritsky, Paulsen Defence_.<C41i Philidor: Morphy, 4...Nf6f}L:A43i Old Benoni: 2.d5 e6 3.c4UJA91 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be72N+ΦBD43v Semi-Slav: Moscow, Main Lineң5ZE33 Nimzo-Indian: Classical, 4...Nc6 5.Nf3 d5'h<<D63 QGD: Orthodox, Swiss, 8.c5|LD98b Grnfeld: Russian, Smyslov, 8.Be2kD+&XB31d Sicilian: Rossolimo, 3...g6 4.Bxc6 dxc6WXE62d King's Indian: Fianchetto, 6...c6 7.O-O#1RDC80g Spanish: Open, Riga Variation?ABB00t Nimzowitsch Defence: 2.d4 d6㆑\RB93g Sicilian: Najdorf, 6.f4 Qc7 7.Bd3 g6 $TB49b Sicilian: Taimanov, 6.Be3 a6 7.Be2 b5~ED4C65c Spanish: Berlin, 4.d4J\nD66 QGD: Orthodox, Main Line, 8...h6 9.Bh4 dxc4 10.Bxc4lZA31 English: Symmetrical, Two Knights, 4...g6ЊXXC57l Two Knights: Fritz, Radchenko VariationyVTfE98e King's Indian: Mar del Plata, 9.Ne1 Ne8 10.Be3ro|bC96l Spanish: Closed, Chigorin, 11.d4 Bb7 12.Nbd2o's<BC64e Spanish: Classical, 4.c3 Qf6nlJB22u Sicilian: Alapin, 2...Nf6, 5.cxd4 d6 6.Nf3 Nc6 7.Bc4 Nb6 8.Bb5j;BC47e Four Knights: Glek Variatione YpD46j Semi-Slav: Chigorin, 7.Qc2 Main Line, 9...Qe7 10.h3`PkB59m Sicilian: Boleslavsky, 7.Nb3 Be7 8.O-O O-O 9.Be3 Be6 10.Bf3R]td9nD19f Slav: Dutch, 8...O-O 9.Qe2 Bg6 10.Ne5 Nbd7, 12.Rd1<10<B12v Caro-Kann: Advance, 4.Nc30,]tC95k Spanish: Closed, Breyer, Main Line, 13.Nf1 Bf8 14.Ng3"~\1HD37l QGD: Classical, 5...O-O 6.e3 c6 ϿOjB57o Sicilian: Sozin, Benko, 7.Nb3 e6 8.O-O Be7 9.Be3m4aVDA16 English: Anglo-Grnfeld, 4.Nf32:bRA72 Benoni: Classical, 8.Be2 O-O 9.Bf4 b5w lRC05s French: Tarrasch, Closed, 7.Ngf3 Be7Se:9nE90w King's Indian: 5.Nf3 O-O 6.h3 c5 7.d5 e6 8.Bd3 Na6ҔY E<D45k Semi-Slav: 6.Qc2 Bd6 7.e4LD48p Semi-Slav: Meran, Reynolds, 10...c4 11.dxe6 fxe6 12.Bc2 Qc7 13.O-O $"B07q Pirc: 4.Nge2ǵe:D17g Slav: Central, 6.Ne5 Na6Dr$pB01z Scandinavian: Marshall, 4.c4 Nb6 5.Nf3 g6 6.Nc3 Bg7@HD30w QGD: Capablanca-Duras Variation,8dD29m QGA: Classical, 8...Bb7 9.Rd1 Nbd7 10.Nc3 Qb84_WND20y QGA: 3.e4 e5 4.Nf3 exd4 5.Bxc4 Nc6)-a†\bB48k Sicilian: Taimanov, 6.Be3 a6 7.Bd3 b5 8.Nxc6O@PhE69e King's Indian: Fianchetto, Classical, 9.h3 exd4Q/|D88 Grnfeld: Classical Exchange, Main Line, 11.cxd4 Bg4 12.f3ϕYfA78 Benoni: Classical, Main Line, 10.Nd2 Na6 11.Rb1|S`B85 Sicilian: Scheveningen, Classical, Main Line'jA83m Dutch: Staunton Gambit, 4.Bg5 Nc6 5.d5 Ne5 6.Qd4w:T,?BC82j Spanish: Open, Motzko AttackdWeC23 Bishop's Opening: Calabrese Countergambit, Jnisch Variationa%E57 Nimzo-Indian: Main Line, 8...dxc4 9.Bxc4 cxd4 10.exd4 Be7 11.Re1 a6^3PE07 Catalan: Closed, 6...Nbd7 7.Nc3 dxc4^6[tB96w Sicilian: Najdorf, Polugaevsky, 10.Qe2 Nfd7 11.O-O-O Bb7 12.Qg4\ C8A71 Benoni: Classical, 8.Bg5Z n*AJB01y Scandinavian: Marshall, 4.c4 Nf6XYB45m Sicilian: Taimanov, Four Knights, 6.Nxc6 bxc6 7.e5 Nd5 8.Ne4V%kDB09h Pirc: Austrian, 5...O-O 6.Be2O'UINC50u Giuoco Pianissimo: Canal VariationDS_3 NB54f Sicilian: Prins (Moscow) Variation7kZC15h French: Winawer, Mller-Zhuravlev Gambit)c)NA02 Bird: From Gambit, Lasker Variation K:TNE95b King's Indian: 7.O-O Nbd7 8.Re1 a5o7}\A86 Dutch: Leningrad, 4.Bg2 Bg7 5.Nc3 d6 6.Nh3x:dC14k French: Classical, Steinitz, 7...O-O 8.Nf3 c5SG?n*B10a Caro-Kann: 2.Ne2#+p\D44q Semi-Slav: Botvinnik, Main Line, 12.g3 c5R6_ sXE14q Queen's Indian: 4.e3 Bb7 5.Bd3 c5 6.Nc3bUhh\C99g Spanish: Closed, Chigorin, 13...Bb7 14.d5MSfA30g English: Symmetrical, Mutual Double Fianchetto0=qRA29 English: Four Knights, 4.g3 Bb4 5.Nd5pSVD85h Grnfeld: Exchange, 7.Be3 c5 8.Qd2 Qa5 ̜zB14r Caro-Kann: Panov-Botvinnik, 5...e6 6.Nf3 Bb4 7.cxd5 Nxd5{yDC46f Three Knights: 3...Bc5 4.Nxe5|2`A30k English: Symmetrical, Hedgehog, 6...d6 7.b3X{oWfD83 Grnfeld: Grnfeld Gambit, Capablanca VariationBhYHB95j Sicilian: Najdorf, 6...e6 7.Qf3N:=ގzE34 Nimzo-Indian: Classical, Noa, 5.cxd5 Qxd5 6.Nf3 Qf5 7.Qb3pnA36u English: Symmetrical, Botvinnik, 5...d6 6.Nge2 Nf6v |JTE09j Catalan: Closed, Main Line, 9.e4 dxe4sP{^C85m Spanish: Closed, Exchange, 7.d3 Nd7 8.Nbd2r%%_c(PB98g Sicilian: Najdorf, Browne Variationlܜg6B07h Pirc: 3.Bd3 e5 4.c3 d5l [VNA01 Nimzowitsch-Larsen: Spike Variationi|rp$D35b QGD: Exchangee:gZ#PE30 Nimzo-Indian: Leningrad, 4...c5 5.d5e`wHC93 Spanish: Closed, Smyslov DefenceXp>B\\D19i Slav: Dutch, 8...O-O 9.Qe2 Nbd7 10.e4 Bg4WNjhA41g Neo-Old Indian: Wade Defence, 3.c4 e5 4.Nc3 Nc6S1_mdA36q English: Symmetrical, Botvinnik, 5...e6, 8.d3PVƃfB01h Scandinavian: 2...Qxd5 3.Nc3 Qa5 4.d4 c6 5.Bc4F57z^D84 Grnfeld: Grnfeld Gambit Accepted, 8...Nc69{1nA30y English: Symmetrical, Hedgehog, Flexible Formation1H7˄^E09m Catalan: Closed, Main Line, 9.e4 Bb7 10.e5!4hP@A51h Budapest: Fajarowicz, 4.Nf3j6hB35a Sicilian: Accelerated Fianchetto, Modern, 7.Bc4ߴPBD45l Semi-Slav: 6.Qc2 Bd6 7.g4 h6 X+¿!RB50o Sicilian: 2.Nf3 d6 3.c3 Nf6 4.h3 Nc6R0lC69i Spanish: Exchange, Gligoric, 6.d4 exd4 7.Nxd4 Ne7/7T@D17e Slav: Czech, 6.Nh4 Bc8 7.e3&VC33 KGA: Bishop's Gambit, Classical DefenceY4C41h Philidor: Bird GambitsYc`E78 King's Indian: Four Pawns Attack, 7.Nf3 cxd4A!V`E70t King's Indian: Accelerated Averbakh, 5...h6+x v04C61d Spanish: Bird's, 5.d3ҍ:CJA06 Reti: Nimzowitsch-Larsen, 2...Nf6)2jlB03i Alekhine: Four Pawns Attack, Fianchetto VariationPA80a DutchI8C70 Spanish: Bird's DeferredmdB23p Sicilian: Closed, Grand Prix, 3...d6 4.Nf3 g6穤LC80q Spanish: Open, Bernstein, 9...Bc5sg 8D11n Slav: Slav-Reti with b3)/xE18u Queen's Indian: 7.Nc3 Ne4 8.Nxe4 Bxe4 9.Ne1 Bxg2 10.Nxg2 d5|O7(A50k Indian: 2.c4 a6E ߻\C29j Vienna Gambit: Oxford, 5...Nxc3 6.bxc3 d4ad vC15u French: Winawer, Alekhine Gambit, Alatortsev Variation@A72 Benoni: Classical, 8.Be2 O-OyfB22f Sicilian: Alapin, 2...d5 3.exd5 Qxd5 4.d4 cxd4n.D56 QGD: Lasker DefenceR0Vw|NA70b Benoni: Classical, 7...a6 8.a4 Bg4jm|TE83b King's Indian: Smisch, 6...Nc6 7.Qd26ۊ_>D96 Grnfeld: Russian, 7.Bf4 c6{2A40x Queen's Pawn: ModernzpE16m Queen's Indian: Capablanca, Riumin, 7.Nc3 O-O 8.O-Oz00rE56 Nimzo-Indian: Main Line, 7...Nc6 8.a3 dxc4 9.Bxc4 Ba5rHEOWB85 Sicilian: Scheveningen, Classical, Main Line, 9...Nc6 10.Kh1 Qc7nl[WT^A32 English: Symmetrical, Two Knights, 5.Nc3 d5myq4:BC41m Philidor: Antoshin Variationjz`RA4A03 Bird: Dudweiler GambitiORC90j Spanish: Closed, Pilnik, 11.Nbd2 Nc6dTD43q Semi-Slav: Moscow, Hastings VariationdIguzD39k QGD: Ragozin, Vienna, 6.e4 c5 7.Bxc4, 8...Bxc3+, 10.Bb5+^b_TA90 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 c6 5.Nh3IZ wLD29k QGA: Classical, Smyslov VariationDY6ПZE90j King's Indian: Larsen, 6...e5, Queenswap@ꋌ{MVD88 Grnfeld: Classical Exchange, Main Line3}tjC41e Philidor: Philidor Countergambit, del Rio Attack+1[s 4E11l Bogo-Indian: 4.Bd2 a5 n]X:QpE43 Nimzo-Indian: Nimzowitsch, 5.Nf3 Bb7 6.Bd3 Ne4 7.O-O৷TE27 Nimzo-Indian: Smisch, 5...O-O 6.f3 d5!YFC64l Spanish: Classical, 4.O-O Nge7=junC18v French: Winawer, Poisoned Pawn, Main Line, 13.Nxc3D vE15j Queen's Indian: Nimzowitsch, 5.Qa4 c5 6.Bg2 Bb7 7.dxc5b%U<E41 Nimzo-Indian: Hbner, 8.e4_4A00m Van Geet: 1...d5 2.e4Kd~x2D91b Grnfeld: 5.Bg5 dxc4h `D79c Neo-Grnfeld, 6.O-O c6 7.cxd5 cxd5 8.Nc3 e6ב<E15b Queen's Indian: 4.g3 Bb4+-qdD86 Grnfeld: Classical Exchange, Larsen Variation頹3FHB25a Sicilian: Closed, 3.g3, 5.d3 d6nBCTD46d Semi-Slav: Bogoljubow, 7.O-O O-O 8.b3X)ZH4A65c Benoni: 6.e4 g6 7.Bf4;'+nA37o English: Symmetrical, 5.Nf3 e6 6.O-O Nge7 7.d3 O-OQˉ0D31c QGD: 3.Nc3 Bb4 4.a3KNC65q Spanish: Berlin, Beverwijk, 5.Nxe5⣰ MVD80 Grnfeld: Stockholm, Taimanov Variation^D91g Grnfeld: 5.Bg5 Ne4 6.Bh4 Nxc3 7.bxc3 dxc4A4E12w Queen's Indian: 4.Nc3^ڐeA79 Benoni: Classical, Main Line, 10.Nd2 Na6 11.f3 Nc7 12.a4 b6 13.Kh1"pjB91m Sicilian: Najdorf, 6.g3 e5 7.Nde2 Be7 8.Bg2 Nbd7>IdB58n Sicilian: Boleslavsky, 7.Nf3, 9.Re1 O-O 10.h3 j>PC96e Spanish: Closed, Chigorin, 10...Bb7~;VE68f King's Indian: Fianchetto, Classical, 8.e4 exd4 9.Nxd4 Re8 10.h3y(}ͨVB57l Sicilian: Sozin, Benko, 7.Nb3 e6 8.Bf4yn>C12i French: MacCutcheon, 6.Bd2l6HE30 Nimzo-Indian: Leningrad, 4...O-Of]5]QpC95m Spanish: Closed, Breyer, Main Line, 14.Ng3 g6 15.a4Z0 LE11c Bogo-Indian: 4.Nbd2 b6 5.a3 Bxd2+5T8C01h French: Exchange, 4.Bd31Vk^HE05e Catalan: Open, Classical, 6.O-O/m"<C63d Spanish: Schliemann, 4.d3/-2JB60e Sicilian: Richter-Rauzer, 6...a6+DDD09 QGD: Albin, 5.g3 Bg4 6.Bg2 Qd7(߲.NA00o Grob Gambit Accepted: Fritz Gambit SXDA58e Benko Gambit: Accepted, 6.Nc3):~NTE61r King's Indian: 4.Nf3 d6 5.Bf4 d6 6.e3OFD07j QGD: Chigorin, 3.Nf3 Bg4 4.Nc3GLD53o QGD: 4.Bg5 Be7 5.Nf3 O-O 6.Qc2 c5 @nU|HD19h Slav: Dutch, 8...O-O 9.Qe2 Nbd7 ;&A25 English: ClosedNl7fB44x Sicilian: Taimanov, Szen, Hedgehog, 11.Be3 Ne5C!0DE86f King's Indian: Smisch, Orthodox, 7.Nge2 c6 8.Qd2 Nbd7 9.d5 zA45o Trompowsky: 2...e6 3.e4 h6 4.Bxf6 Qxf6 5.Nc3 d6 6.Qd2 g5 D1FA15 English: Anglo-Indian, 2.Nf3 g6]iRD47k Semi-Slav: Meran, Lundin, 9.Ne4 Nxe4fSv|8E61a King's Indian: 3.Nc3 c6"3GYA29 English: Four Knights, 4.g3 d5 5.cxd5 Nxd5 6.Bg2 Nb6 7.O-O Be7 8.a3_2Q;fPC50n Giuoco Pianissimo: Dubois Variationi34C24 Bishop's Opening: 3.d4:Ki"RE48 Nimzo-Indian: 4.e3 O-O 5.Bd3 d5 6.Ne2RvFFB24 Sicilian: Closed, 3.g3 g6, 5.d3",PD76a Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O Nb6Ȟ\E20 Nimzo-Indian: Romanishin, 4...c5 5.Nf3 O-O QmI JC01q French: Exchange, 4.Nf3 Bd6 5.c4}>^A58j Benko Gambit: Accepted, 7.Nf3 g6 8.Nd2 Qa5zhC79 Spanish: Steinitz Deferred, Rubinstein VariationiƬ&@zB11h Caro-Kann: Two Knights, 3...Bg4 4.h3 Bxf3 5.Qxf3 e6 6.d4CJ^D48s Semi-Slav: Meran, Old Main Line, 10...cxd4'L@M>D21m QGA: 3.Nf3 c5 4.d5 e6 5.e40dB63r Sicilian: Richter-Rauzer, 7.Qd2 Be7, 9.Nb3 a5xFoFHA38a English: Symmetrical, Main LinexG3vE25 Nimzo-Indian: Smisch, 5...c5 6.f3 d5 7.cxd5 Nxd5 8.Qd3sPAPE04w Catalan: Open, 5.Nf3 Nc6 6.Qa4 Bb4+r<`C57g Two Knights: Fegatello, Leonhardt Variation[_Ga`NJA58g Benko Gambit: Accepted, 6.Nc3 d6YM:^W*A54 Old Indian: 5.Bg5RDCԅ`B61d Sicilian: Richter-Rauzer, Larsen, 7.Qd2 Rc8HӭZ8A45i Indian: 2.g3 c5 3.d5 b5H}u&D10b Slav: ExchangeC~@ZB96n Sicilian: Najdorf, Polugaevsky Variation:C|A05 Reti: KIA2Jn@B97s Sicilian: Najdorf, Poisoned Pawn, Main Line, Timman's 13.Be20m|LE16e Queen's Indian: Capablanca, 6.Bd2'O;yHC48n Four Knights: Rubinstein, 5.Ba4C2ˣJblC89y Spanish: Marshall, Main Line, Classical, 18.a4 f5b>B00f Owen Defence: Smith Gambit U<D26r QGA: Classical, 6.O-O Nc6vD_"PB63c Sicilian: Richter-Rauzer, 7.Qd2 Qb6%oZC58c Two Knights: Morphy, Yankovich Variation=>4D30v QGD: Vienna Variation ̺SfB83 Sicilian: Scheveningen, Modern, 9.f4 Bd7 10.Kh1L.s^B81i Sicilian: Scheveningen, Keres, 6...h6 7.h3%VOtrBD02d Queen's Pawn: 2.Nf3 Bf5 3.e3^A30t English: Symmetrical, Hedgehog, 8.Qxd4 Nc6"#T@C70 Spanish: Fianchetto Deferred D`D28k QGA: Classical, 7.Qe2 b5 8.Bb3 Nc6 9.Rd1 c4O5D%bxE82d King's Indian: Smisch, Fianchetto, Bronstein Variation+>yl<8E91f King's Indian: 6.Be2 c5~2E61c King's Indian: 4.Bg5]x<@A76 Benoni: Classical, Main LineSTD19d Slav: Dutch, 8...O-O 9.Qe2 Bg6 10.Rd1WKqXJD81 Grnfeld: Early Russian VariationUQRB91h Sicilian: Najdorf, 6.g3 e5 7.Nb3 Be7a?" dE04x Catalan: Open, 5.Nf3 Nc6 6.Qa4 Bb4+ 7.Bd2 Nd5(NBA90 Dutch: 2.c4 Nf6 3.g3 e6 4.Nc3u8%BRB46g Sicilian: Taimanov, 5...a6 6.g3 Nge7t*JB66m Sicilian: Richter-Rauzer, 7...a6 8.O-O-O h6 9.Be3 Be7 10.f3iA EoXD22j QGA: Alekhine, 4.e3 Bg4 5.Bxc4 e6 6.Qb3U#:,<A11 English: Caro-Kann DefenceSm &A10 English: 1...g6L3s?hjB11d Caro-Kann: Two Knights, 3...Bg4 4.h3 Bxf3 5.Qxf3Lf} mlB84 Sicilian: Scheveningen, Classical, 7.O-O Qc7 8.Bf35|hC42f Russian Game: Boden-Kieseritsky Gambit Accepted&[ |<D63 QGD: Orthodox, Swiss, 8.a3&;sLD14c Slav: Exchange, 6.Bf4 Bf5 7.e3 a67,8B33a Sicilian: Open, 2...Nc6#}^C04b French: Tarrasch, Guimard, 4.Ngf3 Nf6 5.e5&QT"krA55h Old Indian: 5.e4 Be7 6.g3 c6 7.Bg2 O-O 8.O-O a6 9.a4;;x6A16 English: Anglo-Grnfeld !zLbA67n Benoni: Four Pawns, Taimanov, 9.a4 a6 10.Bd3CAJD93 Grnfeld: 5.Bf4 O-O 6.e3 c6 7.Qb3逦LA41t Neo-Old Indian: Modern, 3.Nc3 Bg7IP2A40t Queen's Pawn: Modern?\'d:E06 Catalan: Closed, 6.O-O c6 KH\pD79e Neo-Grnfeld, 6.O-O c6 7.cxd5 cxd5 8.Nc3 Ne4 9.Nxe4E66l King's Indian: Fianchetto, Yugoslav Panno, Main Line, 12.Bb257pD64 QGD: Orthodox, Rubinstein Attack, Grnfeld Variationim+x2D18n Slav: Dutch, 8...O-OЬJX|DC23 Bishop's Opening: Lopez Gambit&-HC30k KGD: Classical, Heath Variation1N)nDA10 English: 1...b6 2.Nc3 Bb7 3.e4[=OFC93 Spanish: Closed, Smyslov, 10.d4uBA23 English: Bremen, Keres, 4.Nf3gM\B15n Caro-Kann: Gurgenidze: 4.Nf3 Bg7 5.h3 Nf67tB13y Caro-Kann: Panov-Botvinnik, 5...Nc6, Normal Variation꣩HB17c Caro-Kann: Steinitz, 5.Nf3 Ngf6EBB01b Scandinavian: 2...Qxd5 3.Nc341:D47a Semi-Slav: Meran, 7...b5KfC04i French: Tarrasch, Guimard, Main Line, 6.Nb3 a5nDa6D58k QGD: Tartakower, 8.Be2h@V!tRB48f Sicilian: Taimanov, 6.Be3 a6 7.f4 b5[SV\e+B99r Sicilian: Najdorf, Main Line, 10.g4 b5 11.Bxf6 Nxf6 12.g5 Nd7 13.a3RƇE89h King's Indian: Smisch, Orthodox Main Line, 10.Qd2 a6 11.g4 h5R ^^R8C45f Scotch: Steinitz, 5.Nc3CϏhD39j QGD: Ragozin, Vienna, 6.e4 c5 7.Bxc4, 8...Bxc3+>[GsJB54g Sicilian: Prins (Moscow), 5...e6=jJPC33 KGA: Bishop's Gambit, Paulsen Attack*Ɛ@p_4B89 Sicilian: Sozin, 7.Be3 S,\B52k Sicilian: 3.Bb5+, Sokolsky, 5...Nc6 6.Nc3 Q,A00f Anderssen Openingc jE38k Nimzo-Indian: Classical, 4...c5 5.dxc5 Na6: 8.b4#NC78i Spanish: 5.O-O b5 6.Bb3 Bc5 7.Nxe5 !RdE97u King's Indian: Mar del Plata, 9.Nd2 Ne8 10.b4yײvE16n Queen's Indian: Capablanca, Riumin, 7.Nc3 O-O 8.O-O d5]D32v QGD Tarrasch: 5.Nf3 Nc6 6.e3 Nf6 7.Be2 cxd4 8.Nxd4 Bd6 9.O-O|t ̳FA16 English: Anglo-Indian, 2.Nc3 d6՟.ԗ>bB97p Sicilian: Najdorf, Poisoned Pawn, 10.e5 dxe5TA:D10v Slav: 3.Nc3 Nf6 4.e3 Bf5XXA32 English: Symmetrical, Two Knights, 5.Nc3~]bNE27 Nimzo-Indian: Smisch, 5...O-O 6.f3FA22 English: Bremen, Smyslov, 4.Bg2 t\A37l English: Symmetrical, 5.Nf3 e6 6.O-O Nge7C3)8NB88 Sicilian: Sozin-Scheveningen, 7.Bb3ytRB97x Sicilian: Najdorf, Poisoned Pawn, Main Line, 13.e5 dxe5 with 18.c4d~VE97w King's Indian: Mar del Plata, 9.Nd2 c5y>vNC78i Spanish: 5.O-O b5 6.Bb3 Bc5 7.Nxe5jy%qVC51 Evans Gambit Declined, Pavlov Variationh#wBVD55k QGD: Neo-Orthodox, Petrosian Variationg UK>A86 Dutch: Hort-Antoshin System[}]ûPA87 Dutch: Leningrad, Main Line, 5...O-OY'!pE90w King's Indian: 5.Nf3 O-O 6.h3 c5 7.d5 e6 8.Bd3 Na6 9.O-O Nc7Q-#ZFC51 Evans Gambit: Paulsen VariationIlqC63t Spanish: Schliemann, 4.Nc3 fxe4 5.Nxe4 d5 6.Nxe5 dxe4 7.Nxc6 Qd5E~,PD05g Colle: Rubinstein's Attack, 5...Nc6UC^E90r King's Indian: 5.Nf3 O-O 6.h3 e5 7.d5 Nbd7٘zE18u Queen's Indian: 7.Nc3 Ne4 8.Nxe4 Bxe4 9.Ne1 Bxg2 10.Nxg2 .0FD00s Blackmar-Diemer: Hubsch Gambit+Yi-r*D11e Slav: 3.Nf3 dxc4iQ<C85b Spanish: Closed, Exchangex $BD00s Blackmar-Diemer Gambit (BDG)Qf}\B71 Sicilian: Dragon, Levenfish, 6...Nc6 7.Nf3eN@C47g Four Knights: Glek, 4...Bc5ؙJbE85g King's Indian: Smisch, Orthodox, 7.Nge2 Nc6_?nB34f Sicilian: Accelerated Fianchetto, Modern Variationrb6B30c Sicilian: 2...Nc6 3.d3l{k&4DB13b Caro-Kann: Exchange, 3...cxd5$]_=^C95c Spanish: Closed, Breyer, Simagin Variation5xsL2D21e QGA: 3.Nf3 e6 4.Qa4+O-FE30 Nimzo-Indian: Leningrad, 4...h6kV1B34u Sicilian: Accelerated Fianchetto, Modern, 6.Be3 Nf6 7.Be2 O-Op5J'@A16 English: Anglo-Indian, 2.Nc3&~CVdB21y Sicilian: Smith-Morra Gambit, Chicago DefenceqͤPC23 Bishop's Opening: Lisitsin Variation}`0|pnB61i Sicilian: Richter-Rauzer, Larsen, Main Line, 10.f402RA01 Nimzowitsch-Larsen: Ringelbach GambitN@(bD85g Grnfeld: Exchange, 7.Be3 c5 8.Qd2 O-O 9.Rc1^bB01n Scandinavian: 2...Qxd5, Main Line, 6.Bc4 Bg42X7B39f Sicilian: Maroczy Bind, Breyer, 8.Qxg4 Nxd4 9.Qd1 e5 10.Nb5jlv2A13r English: Neo-Catalan CvA37w English: Symmetrical, 5.Nf3 e5 6.O-O d6 7.d3 Nge7 8.a3v0dE74g King's Indian: Averbakh, 6...c5 7.d5 a6 8.Qd2rsvxD93 Grnfeld: 5.Bf4 O-O 6.e3 c5 7.dxc5 Qa5 8.Rc1 dxc4 9.Bxc4r a\B19k Caro-Kann: Classical, Spassky, 10.Qxd3 e6bd(2D51 QGD: 4.Bg5 Nbd7 5.Nf3^ yFD00j Trompowsky: 2...d5 3.Bxf6 gxf6SUfB74 Sicilian: Dragon, Classical, Alekhine VariationIFapD43n Semi-Slav: Moscow, 6.Bh4 Gambit, Main Line, 9...Bb7?ݻuhB60b Sicilian: Richter-Rauzer, Bondarevsky Variation=bafZD87i Grnfeld: Classical Exchange, 10.Be3 Na5=<6*6D30s QGD: 3.Nf3 Nf6 4.e3 c61D!?HA90 Dutch: 2.c4 Nf6 3.g3 e6 4.Nc3 d5,K~G:D28d QGA: Classical, 7.Qe2 b5#*hR8C65a Spanish: Berlin Defenceŗ^C77h Spanish: Four Knights (Tarrasch) Variation~*C21 Centre GameY&HE20 Nimzo-Indian: Romanishin, 6.Nxd4KEyTE49 Nimzo-Indian: Botvinnik, 7...c5 8.cxd5D9 TLB07c Pirc: 2.f4 Nf6 3.Nc3 g6 4.Nf3 Bg7͇jC43e Russian Game: Modern Attack, Pillsbury VariationǑD0`HA23 English: Bremen, Keres, 4.Nf3 d6lh>B91b Sicilian: Najdorf, 6.g3 b5@nzRC27d Vienna: 3.Bc4 Nxe4 4.Qh5 Nd6 5.Qxe5+J zD03u Torre Attack: 3...g6 4.e3 Bg7 5.Nbd2 O-O 6.Bd3 c5 7.c3 Nbd7 j^ܡ$E60a King's IndianBVB16f Caro-Kann: Bronstein-Larsen, 6.Nf3 Bf5rbA44u Old Benoni: Czech, 3.e4 d6 4.Nc3 a6 5.a4 Be7R2C25m Vienna: 2...Nc6 3.f47Կ900D34f QGD Tarrasch: 9.Bf4fF7ZD59d QGD: Tartakower, 8.cxd5 Nxd5 9.Bxe7 Qxe7R#OpD58l QGD: Tartakower, 8.Be2 Bb7 9.Bxf6 Bxf6 10.cxd5 exd5EVF6D00h Hodgson Attack, 2...h6HPA44f Old Benoni: Czech, 3.c4 d6 4.e4 Be7*8A41e Neo-Old Indian / ModernH<XA82 Dutch: Staunton Gambit, 4.f3 exf3 5.Nxf3e,OAHPA40d Queen's Pawn: English Defence, 2.c4WCj:A21 English: Lukin, 5.Ng5 Nf6wPj%3LB01l Scandinavian: 2...Qxd5, 5.Nf3 Bf5n8Ž\"@A42v Modern: Averbakh, Queenswapf:OrB33p Sicilian: Pelikan, Chelyabinsk, 9.Nd5 Be7, 11.c3 Bg5c.<_\DC50m Giuoco Piano: 4.O-O Nf6 5.Nc3_4TB74 Sicilian: Dragon, Classical, 9.Nb3 Be6Vyc6HA48m Neo-King's Indian: Torre AttackU}9JB08n Pirc: Classical, 5.Be2 O-O 6.O-OR?h 6C44z Scotch Gambit: 5.c3 d3LƦ PA87 Dutch: Leningrad, Main Line, 7.d5 c5HnB:{bE70u King's Indian: Accelerated Averbakh, 5...O-OF)nfBB12v Caro-Kann: Advance, 4.Nc3 e6?$C LE08m Catalan: Closed, 7.Qc2 c6 8.b3 b65Q qZC33 KGA: Bishop's Gambit, Anderssen Variation/*,̆\D91j Grnfeld: 5.Bg5 Ne4 6.cxd5 Nxg5 7.Nxg5 c6/퉖bB10l Caro-Kann: English, Exchange, 4...Nf6 5.Bb5+$"änD32f QGD Tarrasch: von Hennig-Schara Gambit, 7.Qxd5 Nc6"IjC69j Spanish: Exchange, Gligoric, 6.d4 exd4 7.Nxd4 c5M9VrB76m Sicilian: Dragon, Yugoslav, 9.O-O-O Nxd4: 11.Kb1 Qc79W6A00k Van Kruijs{XBBD43k Semi-Slav: Moscow, 6.Bh4 Be7wysHA18 English: Mikenas, Flohr, 4...Ne4:WlE11z Bogo-Indian: 4.Bd2 Bxd2+ 5.Qxd2 O-O 6.Nc3 d5 7.e3ڥU RB86 Sicilian: Sozin-Scheveningen, 6...Qb6ԖR:C41j Philidor: Paulsen Attacks}qbLE24 Nimzo-Indian: Smisch, 5...b6 6.f3F.SJD35c QGD: Exchange, Smisch VariationFO^>D94 Grnfeld: 5.e3 O-O 6.Be2 c5+P*(A45h Indian: 2.g3 g6R^'PB98f Sicilian: Najdorf, 7...Be7 8.Qf3 h6D]On=`A75 Benoni: Classical, 9.O-O a6 10.a4 Bg4 11.Bf4\&rE13h Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.e3 Bxc3+ 8.bxc3TpȤ0B06d ModernebFB42h Sicilian: Kan, 5.Bd3 Nf6 6.O-O\`DA29 English: Four Knights, 4.g3 d51XNB96i Sicilian: Najdorf, 7.f4 Nbd7 8.Bc4 K5tdB63v Sicilian: Richter-Rauzer, Podebrad, 10.f3 Rd88J2>A43s Old Benoni: Schmidt, 3.Nc3ŭMJZB00w Nimzowitsch Defence: Bogoljubow, 3...Nf6|lyHA95 Dutch: Stonewall, 7.Nc3 c6 8.Bf4U>^E78 King's Indian: Four Pawns Attack, 7.Nf3 Bg4te\C82e Spanish: Open, Berlin, 10.Bc2 Bg4 11.Nbd2f}l!XD06k QGD: Marshall Defence, 3.cxd5 Nxd5 4.e4a 2A25 English: Closed, 5.e3Y)N^E12x Queen's Indian: 5.Bg5 h6 6.Bh4 Be7 7.e3 c5S(DD00v Blackmar-Diemer: Ryder Gambit@20hlE51 Nimzo-Indian: 4.e3 O-O 5.Nf3 d5 6.Bd3 Nc6 7.O-O a6/1bVDD10w Slav: 3.Nc3 Nf6 4.e3 a6 5.Bd3-GN$D20i QGA: 3.Nc3 e5"؝<D00v Blackmar-Diemer: AcceptedUs(4D10o Slav: 3.Nc3 dxc4 4.e3GFHTJB59c Sicilian: Boleslavsky, 7.Nb3 Be7 &mXC43c Russian Game: Modern Attack, Tal Gambit,YfC04g French: Tarrasch, Guimard, Main Line, 6.Be2 f6K!{JC05p French: Tarrasch, Closed, 7.Ndf3\E95e King's Indian: 7.O-O Nbd7 8.Re1 Re8 9.Bf1 PA00l Van Geet: Sicilian Variation, 2.Nf3>ؔdE84b King's Indian: Smisch, Panno Main Line, 9.a3*fB30w Sicilian: Rossolimo, 3...e6 4.O-O Nge7 5.c3 a6|lUDD35j QGD: Exchange, 5.Bg5 Be7 6.e3zjE73y King's Indian: Averbakh, 6...h6 7.Be3 e5 8.d5 c6)oǾ%JB10t Caro-Kann: Two Knights, 3...dxe4:HxA14 English: Neo-Catalan Declined, 5...O-O 6.b3 b6 7.Bb2 Bb7 qM<HD60 QGD: Orthodox, Botvinnik, 8...c5{o;tN.A07 Reti: KIA, Yugoslavwz.vMl\B13r Caro-Kann: Panov-Botvinnik, 5...Nc6 6.Nf3i~=FE70g King's Indian: Kramer, 5...O-ORO!DB22a Sicilian: Alapin, 2...g6 3.d4R6dE43 Nimzo-Indian: Nimzowitsch, 5.Nf3 Bb7 6.Bd3 O-OJhMweZE73y King's Indian: Averbakh, 6...h6 7.Be3 e5HNOLD60 QGD: Orthodox, Botvinnik, 7...dxc4:ZgvD34n QGD Tarrasch: 9.dxc5 Bxc5 10.Bg5 d4 11.Bxf6: Main Line5m\E72 King's Indian: 4.e4 d6 5.g3 O-O 6.Bg2 Nbd7.GLD20p QGA: 3.e4 Nf6 4.e5 Nd5 5.Bxc4 Nb6)tg"p_ND61 QGD: Orthodox, Rubinstein Variation(7NE15d Queen's Indian: Nimzowitsch, 5.Qc2RƋfbC41s Philidor: Improved Hanham, Larobok Variationmjh 8B07u Pirc: 4.Be3, 150 Attack>F+pC52 Evans Gambit: Compromised Defence, Paulsen VariationfFp`!"A04 Reti: 1...Nc6R>RA34 English: Symmetrical, 3 Knights, 5.d4twBA34 English: Symmetrical, 2...Nf6֙Mn NE91t King's Indian: 6.Be2 Nbd7 7.O-O c6g,C78e Spanish: 5.O-O b5ÑJs0C25g Vienna: Fyfe GambitsƵJFC24 Bishop's Opening: Urusov GambitXC17q French: Winawer, Swiss, 6.b4 cxd4 7.Nb5W\VbC52 Evans Gambit: Tartakower, Levenfish VariationRu2/~E69m King's Indian: Fianchetto, Classical, 9.h3 Qb6 10.Re1 exd4o lVC33 KGA: Bishop's Gambit, Jnisch Variation勇6WNC02y French: Advance, 5.Nf3 Qb6 6.a3 c4x5b!\B13j Caro-Kann: Exchange, Rubinstein Variation%@sBpE23 Nimzo-Indian: Spielmann, 4...c5 5.dxc5 Nc6 6.Nf3 Ne4` HE12b Queen's Indian: Miles, 5.e3 Be7'&N{<A55e Old Indian: 5.e4 Be7 6.g3ѶXBA46w Torre Attack: 3...c5 4.e3 h6UBzD85q Grnfeld: Modern Exchange, 8.Rb1 O-O 9.Be2 cd 10.cd Qa5+cY }8A45n Trompowsky: 2...e6 3.e40j4A53 Old Indian: 3.Nf3 Nbd7V.HC51 Evans Gambit: Stone-Ware Defenceoz xbD50 QGD: Dutch-Peruvian, Canal (Venice) VariationnUE5:C18b French: Winawer, 6...Qa5NӆP_BC33 KGA: Stamma (Leonardo) GambitKoHE95a King's Indian: 7.O-O Nbd7 8.Re1IFߋ8A00s Polish: 2...Bxb4 3.Bxe5C#9TtD90 Grnfeld: Three Knights Exchange, Romanishin VariationAl*C03a French: TarraschZA35h English: Symmetrical, Four Knights, 4.e3nZ8E32r Nimzo-Indian: Classical, 4...O-O 5.a3, 6...b6 7.Bg5 Bb7 8.f3 h6үNE93 King's Indian: Petrosian, Main Line-gw>C28m Vienna: 3.Bc4 Nc6 4.d3 Bb4 ՙ庨<A03 Bird: 1...d5 2.Nf3 g6 3.e3}|`B48l Sicilian: Taimanov, 6.Be3 a6 7.Bd3 b5 8.O-O%zrD49j Semi-Slav: Meran, Old Main Line, Botvinnik Variationfǎ@6D94 Grnfeld: Flohr DefencebmcrDA06 Reti: Tennison Gambit Acceptednv :B49n Sicilian: Taimanov, 6.Be3 a6 7.Be2 Nf6 8.O-O Bb4 9.Na4 Be7 10.Nxc6 bxc6 11.Nb6\jE92w King's Indian: Petrosian, Stein, Main Line, 10...Qe8 11.O-O𱇞RBA60p Benoni: 4.Nc3 exd5 5.cxd5 d6A4uZC30i King's Gambit: Adelaide-Wahls, 4.exf5 e4 pYVA30j English: Symmetrical, Hedgehog, 6...d6W}TE81j King's Indian: Smisch, 5...O-O 6.Be34}V,E00q Catalan: 4.Nf3 c5 8D31b QGD: Janowski Variation;VDE20 Nimzo-Indian: 4.f3 d5 5.a3 Be7K*A43r Old Benoni: Hawk~$DB56a Sicilian: Open, 2...d6, 5.Nc3D_dD43j Semi-Slav: Botvinnik, 5...Be7 6.e3 Nbd7 7.Bd3h ^vD42l QGD: Semi-Tarrasch, 7.Bd3 Main Line, 10.Re1 Nf6 11.Bg5-doC>D45v Semi-Slav: 6.Qc2 Bd6 7.Be2ObD82 Grnfeld: 4.Bf4 Bg7 5.e3 c5 6.dxc5 Qa5 7.Qa4+ze&lB39d Sicilian: Maroczy Bind, Breyer, 8.Qxg4 Nxd4 9.Qd1u[9qVD49a Semi-Slav: Meran, Blumenfeld VariationpB\}=QDB92b Sicilian: Najdorf, 6.Be2 Nbd7^ #?,A05 Reti: KIA, SpasskyZ4vTPC85k Spanish: Closed, Exchange, 7.d3 Bg4VmA07 Reti: KIA=1E76q King's Indian: Four Pawns Attack, 6.Nf3 c5 7.d5 b5 8.cxb5 a6 9.a46wNE11f Bogo-Indian: 4.Nbd2 O-O 5.a3 Bxd2+4K+"LD71 Neo-Grnfeld, 5.cxd5 Nxd5 6.e4 Nb6!**XD36f QGD: Exchange, 6.Qc2 Be7 7.e3 O-O 8.Bd3!Vu0D21i QGA: 3.Nf3 c5 4.Nc3 ɬ}>A00t Benko Opening: Symmetrical1tj`D47f Semi-Slav: Meran, Capablanca, 8...Bb7 9.O-OI3蛮"A45d Indian: 2.e3U%K^C95d Spanish: Closed, Breyer, 10.d4 Nbd7 11.Bg5}ӽ~D59h QGD: Tartakower, 8.cxd5 Nxd5 9.Bxe7 Qxe7 10.Rc1 Bb7 11.Be2u檲ljE63j King's Indian: Fianchetto, Panno, 8.h3 Rb8 9.Be3 h-smND01o Richter-Veresov: 3...Nbd7 4.Nf3 h6 3"vB51t Sicilian: 3.Bb5+ Nc6 4.O-O Bd7 5.Re1 Nf6 6.c3 a6 7.Bf1R](1TB19e Caro-Kann: Classical, 7.Nf3 Nf6 8.Ne51lE71l King's Indian: Makagonov, 5...O-O 6.Bg5 Na6 7.Bd31/bTB22t Sicilian: Alapin, 2...Nf6, 5.cxd4 Nc6$LܮhB49e Sicilian: Taimanov, 6.Be3 a6 7.Be2 Nf6 8.a3 Be7AC .C37 KGA: 3.Nf3 g5 4.Bc4Ҭz*&D92 Grnfeld: 5.Bf4܌virB90t Sicilian: Najdorf, 6.Be3 e5 7.Nb3 Be6 8.f3 Be7 9.Qd2 BnPB02s Alekhine: Two Pawns (Lasker) AttackAbC69k Spanish: Exchange, Gligoric, 8.Nb3 QueenswapmPJE90t King's Indian: 5.Nf3 O-O 6.h3 c5ʪjhA40q Queen's Pawn: Keres Defence, Kangaroo Variation:/v*A00l Van Geet: 1...e5Z|XvB78s Sicilian: Dragon, Yugoslav, Old Main Line, 11.Bb3 Rac8:0::D11f Slav: 3.Nf3 dxc4 4.e3 b5QxE77 King's Indian: Four Pawns Attack, 6.Be2 c5 7.d5 e6 8.Nf3!I2HD02t Queen's Pawn: 3.g3 c6 4.Bg2 Bg4 L6B09o Pirc: Austrian, 5...c5z|4C80l Spanish: Open, 8.Nxe5f#bB92l Sicilian: Najdorf, 6.Be2 e5 7.Nb3 Be7 8.O-O O-O 9.Be3 Be6 10.a4 O]B34r Sicilian: Accelerated Fianchetto, Modern, 6.Be3 Nf6 7.Nxc6 bxc6njtC15u French: Winawer, Alekhine Gambit, 5.a3 Be7 6.Nxe4 Nf6shx/X0A00n Grob: Alessi Gambitn~bB38w Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 d6 9.O-O Bd7 10.Qd2 Nxd4 11.Bxd4fNOQi2E01 Catalan: 4...c6 5.Nf3e%D20b QGA: 3.e3[!gz@:D01h Richter-Veresov: 3...Bf5VhΡQ*B23h Sicilian: ClosedS7ЧsxD34m QGD Tarrasch: 9.dxc5 Bxc5 10.Bg5 d4 11.Bxf6 Qxf6 12.Nd5N{|v)t2XD30b Diemer-Duhm Gambit (DDG): Keres DefenceJotE69s King's Indian: Fianchetto, Classical, 9.h3 Re8 10.Re1G?>,_tE85i King's Indian: Smisch, Orthodox, 7.Nge2 Nc6 8.d5 Ne7G ctVB96t Sicilian: Najdorf, Polugaevsky, 10.Qe2F6@5hD46p Semi-Slav: Chigorin, 7.O-O O-O 8.e4 dxc4 9.Bxc4BU/.C41h Philidor: 3...exd4BeVC68m Spanish: Exchange, 5.O-O Bd6 6.d4 exd4>!.C42b Russian Game: 3.d3;nT|%"A57a Benko Gambit;!FND80 Grnfeld: Stockholm, 4...Ne4 5.Nxe48P?>A29 English: Four Knights, 4.g36N 1ۓTJC74 Spanish: Modern Steinitz, 5.c3 g60RDaNA27 English: Three Knights, 3...f5 4.d4%+jC57d Two Knights: Traxler, Chigorin/Pithart Variation$xXND17j Slav: Central, Carlsbad, Main LineFXC82k Spanish: Open, St. Petersburg VariationH>hzE81s King's Indian: Smisch, 5...O-O 6.Be3 Nbd7 7.Qd2 c5 8.d5k$l6D02h Queen's Pawn: 2.Nf3 e6]CWoPA54 Old Indian: 5.Bg5 Be7 6.e3 O-O 7.Qc2TdMPB63k Sicilian: Richter-Rauzer, 7.Qd2 Be7$cqLD00f Hodgson Attack: Welling Variation;y>DD32l QGD Tarrasch: Marshall Gambit ˝X3NE17j Queen's Indian: Opovcensky, 7...f5 إW$$B78q Sicilian: Dragon, Yugoslav, Main Line, 12.h4 h5 13.Bg5 Rc5 14.Kb1 ol}PB28d Sicilian: O'Kelly, 3.d4 cxd4 4.Nxd4}n\E75c King's Indian: Averbakh, 7.d5 e6 8.Nf3 h6T [UzZB32p Sicilian: Lowenthal, Kalashnikov, 6.N1c3fD32f QGD Tarrasch: von Hennig-Schara Gambit, 5.Qa4+CYaLC40o Latvian Gambit: Morgado VariationuBD00n Queen's Pawn: Veresov Attack+^E53 Nimzo-Indian: Main Line, Keres, 8.cxd5 exd5!JB80e Sicilian: Scheveningen, 6.Be3 a6T~6NA22 English: King's, 2.Nc3 Nf6 3.e3 Bb4.W}RC33 KGA: Bishop's Gambit, Greco VariationA.VD37n QGD: Classical, 5...O-O 6.e3 c5 7.dxc5O=n$D24d QGA: 4.Nc3 c53gJb>LD27t QGA: Classical, Rubinstein, 8.Qe2ǧbB05d Alekhine: Modern, Alekhine Variation, 6.exd62fA88 Dutch: Leningrad, Main Line, 7.Nc3 c6 8.d5 cxd5q~+7 2D03d Torre Attack: 3...e6Fj^@C30c King's Gambit: 2...d6 3.Nf3̏vCZC41x Philidor: Improved Hanham, 7.Re1 c6 8.a4SՕ^*B51a Sicilian: 3.Bb5+_jD76e Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O Nb6 8.Nc3 Nc6 9.e3 e5 10.d5ڳ+Z=:B33i Sicilian: Pelikan, 7.Bg5\C17h French: Winawer, Bogoljubow, 5...Ne7 6.a3%s0:A43h Old Benoni: 2.d5 e6 3.c4zϙ9&FC00i French: Chigorin, 2...c5 3.Nf3v-64ohD89a Grnfeld: Classical Exchange, Main Line, 13.Bd3t TC40w Latvian Gambit: Nimzowitsch VariationqΝU8p@FB54c Sicilian: Open, 2...d6, 4...a6Xz=JbDD36f QGD: Exchange, 6.Qc2 Be7 7.e3QLB70l Sicilian: Dragon, 6.Be2 Bg7 7.O-OLC LA42j Modern: Averbakh, Kotov, 5.Be3 e5KtdD76c Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O Nb6 8.Nc3 Nc6B#6 :HA06 Reti: Nimzowitsch-Larsen, 2...c5?9i:B10t Caro-Kann: Hector Gambit9dlj,C21 Centre Game: 3.Nf34L>V 6C15c French: Winawer, 4.Qg42*u$TC66 Spanish: Closed Berlin, Wolf Variation0PexZB21l Sicilian: Grand Prix, Tal Gambit, 4.Bb5+$wJE90d King's Indian: 5.Nf3 c5 6.d5 O-O_5BA43b Old Benoni: Cormorant GambitT%nB04i Alekhine: Modern, Larsen, 5.Nxe5 g6 6.Bc4 c6 7.O-OȿFg6D51 QGD: 4.Bg5 Nbd7 5.e3 c6 @V\DJ4D17c Slav: Czech, 6.Nh4 e6TNB30q Sicilian: Rossolimo, 3...e6 4.Bxc6qJA82 Dutch: Staunton Gambit, 3.Nc3 Nf6%XdpA59m Benko Gambit: 7.e4, Main Line, 11...Nbd7 12.Re1 Ng4>&B >D58p QGD: Tartakower, 8.Rc1 Bb7׍?q|A91 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nh3 O-O 6.O-O d6 7.Nc3$U i).B00c St. George Defence ?mJC06k French: Tarrasch, Closed, 8...f6s35*TA30h English: Symmetrical, Hedgehog System&E~D87l Grnfeld: Classical Exchange, 10.Be3 Qc7 11.Rc1 Rd8 12.Qd2C9<A60i Benoni: 4.Nc3 exd5 5.cxd5tg^C08g French: Tarrasch, Open, 4.exd5 exd5 5.Ngf3@ y:C84f Spanish: Closed, 6.d3 b5Yb[;NC33 KGA: Bishop's Gambit, Cozio Defence$s&A00p Polish: 1...c6XBPE12y Queen's Indian: Botvinnik Variation͊LA21 English: Kramnik-Shirov, 3.Nd5 Bc57,JD02d Queen's Pawn: 2.Nf3 Bf5 3.Bf4 e6x HA01 Nimzowitsch-Larsen: 1...d5 2.Bb2q+=V3NB94e Sicilian: Najdorf, 6.Bg5 Nbd7 7.f4oioz`E86a King's Indian: Smisch, Orthodox, 7.Nge2 c6fNJhbA69g Benoni: Four Pawns, Main Line, 10.e5: 12.O-Oc&帛unE70p King's Indian: 4.e4 d6 5.Bd3 O-O 6.Nge2 c5 7.d5 e6aG L0[,\E05m Catalan: Open, Classical, 8.a4 Bd7 9.Qxc4YK mDE83f King's Indian: Smisch, PannoY J XE30 Nimzo-Indian: Leningrad, 4...h6 5.Bh4 c5YubzSLC23 Bishop's Opening: 2...Bc5 3.c3 Nf6NbNIjtjB10n Caro-Kann: English, Exchange, 4...Nf6 5.Nc3 Nxd5K^,<[fB36h Sicilian: Maroczy Bind, 5...Nf6 6.Nc3 d6 7.Be2>z@XC11i French: Steinitz, Boleslavsky Variation8``E76f King's Indian: Four Pawns Attack, 6.Nf3 Na65ϠAPE80g King's Indian: Smisch, 5...e5 6.d54=0RD^C62 Spanish: Old Steinitz, Semi-Duras Variation4PE62a King's Indian: Fianchetto Variation4aȒ7HD78q Neo-Grnfeld, 6.O-O c6 7.b3 Ne44x ~E48 Nimzo-Indian: 4.e3 O-O 5.Bd3 d5 6.Ne2 c5 7.cxd5 cxd4 8.exd42F4C29f Vienna Gambit: 4.fxe5.}|vE17x Queen's Indian: Pomar, Polugaevsky, 8...c6 9.cxd5 Nxd5+tlIr_RC67k Spanish: Open Berlin, Winawer Attack*p}DJB01u Scandinavian: Portuguese, 4.Bb5+NFs^D72 Neo-Grnfeld, 5.cxd5 Nxd5 6.e4 Nb6 7.Ne2 c5jC-:D40a QGD: Semi-Tarrasch, 5.e3%&u:B24 Sicilian: Closed, 3.g3 g6"iꕓDA18 English: Mikenas, Flohr, 7.Nf3e2C33 KGA: Villemson Gambit‚7Jr(B07x Pirc: 4.Bg5 Bg74˂rzE88h King's Indian: Smisch, Orthodox, Polugayevsky, 8...cxd5 摥'JC32 KGD: Falkbeer, Main Line, 7...Bf5LhE04h Catalan: Open, 5.Nf3 a6 6.O-O b5 7.Ne5 Nd5 8.a4ڧ}>>D09 QGD: Albin, 5.g3 Be6 6.Nbd2 A04 Reti: 1...c5``C04h French: Tarrasch, Guimard, Main Line, 6.Nb3C hB80h Sicilian: Scheveningen, English Attack, 7...Nc6!܀7B45w Sicilian: Taimanov, Four Knights, 6.Ndb5 Bb4 7.a3, 10.Bd3 O-O 11.O-O d4 12.Ne2t JA44n Old Benoni: Czech, 3.e4 d6 4.Nf3eTnB34i Sicilian: Accelerated Fianchetto, Modern, 5...Nf6 6.Nxc6 bxc6C,A48a Neo-King's Indianj4A09o Reti: Accepted, 3.Na3YhE75c King's Indian: Averbakh, 7.d5 e6 8.Nf3 h6 9.Bf4W3bBD58s QGD: Tartakower, 8.cxd5 exd57H?fE50 Nimzo-Indian: 4.e3 O-O 5.Nf3 c5 6.Bd3 Nc6 7.O-OfzM.A07 Reti: KIA, Yugoslavu@`@6*A03 Bird: 1...d5 2.b3L`ZA30o English: Symmetrical, Hedgehog, 7.Re1 d5}A78C88a Spanish: Closed, 6...b5|W4fB16n Caro-Kann: Bronstein-Larsen, 6.c3 Bf5 7.Nf3 e6yVʮW>D08 QGD: Albin, Alapin, 5...Bg4w@C68c Spanish: Exchange Variationj ~ RD48n Semi-Slav: Meran, Reynolds, 10...Qc7f`h|nB80l Sicilian: Scheveningen, English, 7...b5, 8.Qd2 Bb7R_+B85 Sicilian: Scheveningen, Classical, Main Line, 9...Nc6 10.Qe1A f(A80d Dutch: 2.Bg5 c6?v9EqNC91e Spanish: Closed, Bogoljubow, 10.d5=ҩ>D96 Grnfeld: Russian, 5...dxc4C54e Giuoco Pianissimo: 5.d3 a6֏|RB99b Sicilian: Najdorf, Main Line, 10.Qg3?ZLC45g Scotch: Steinitz, 5.Nb5 Bc5 6.Qf3[Ƶ\HA82 Dutch: Staunton Gambit, 4.f3 Nc6$YbD46l Semi-Slav: Chigorin, 7.Qc2 Main Line, 9...b5}VB29l Sicilian: Nimzowitsch, 4.Nc3 e6 5.Nxd5YVC51 Evans Gambit Declined, Hicken VariationҞbENC90n Spanish: Closed, Pilnik, 12.Nf1 h61FFC29h Vienna Gambit: Oxford, 5...Bb4P[E13k Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.e3 Bxc3+ 8.bxc3 d6 9.Nd2 Nbd7 10.f3%ې@B03a Alekhine: O'Sullivan Gambity2C40m Latvian Gambit: 3.d4R bB94i Sicilian: Najdorf, 6.Bg5 Nbd7 7.Bc4 e6 8.O-O|F?dA43z Old Benoni: Schmidt, 6.Be2 O-O 7.O-O Na6 8.h3@G]B14t Caro-Kann: Panov-Botvinnik, 5...e6 6.Nf3 Bb4 7.cxd5 Nxd5 8.Qc2 Nc6Z{`^A28 English: Four Knights, Capablanca VariationaI ,A07 Reti: KIA, PachmanPxjE34 Nimzo-Indian: Classical, Noa, 5.cxd5 Qxd5 6.e3 c5bvC57c Two Knights: Traxler, 5.Nxf7 & 6.Kf1, Palkin VariationGh|bC55b Two Knights: 4.O-O Gambit, Holzhausen Attack}fhyNA73 Benoni: Classical, 9.O-O Na6 10.Nd2whޜVRC12m French: MacCutcheon, 8.Qg4 Kf8 9.Bd3n@ ӚB14w Caro-Kann: Panov-Botvinnik, 5...e6 6.Nf3 Bb4 7.cxd5 Nxd5 8.Bd2 Nc6^TA36f English: Symmetrical, 5.d3yISjE61y King's Indian: Smyslov System, 5...O-O 6.e3 Nbd7zL6h0E60e King's Indian: 3.g3.B12b Caro-Kann: 2.d4 d5ԙ. XD53k QGD: 4.Bg5 Be7 5.Nf3 h6 6.Bh4 O-O 7.Rc1 "jD42c QGD: Semi-Tarrasch, 6.e3 Nc6 7.Bd3 Be7 8.O-O O-OcZA34 English: Symmetrical, 3 Knights, Exchange]W/VB56l Sicilian: Open, 2...d6, 5.Nc3 Nc6 6.f3a*ZE80i King's Indian: Smisch, 5...c5 Queenswap-9PHC93 Spanish: Closed, Smyslov, 12.Bc2ӉFfC33 KGA: Bishop's Gambit, Boren-Svenonius Variation ZC82d Spanish: Open, Berlin, 10.Bc2 Bg4 11.Re1 \VJD46c Semi-Slav: Bogoljubow, 7.O-O O-Oz\ `B95g Sicilian: Najdorf, 6...e6 7.Qd2 Be7 8.O-O-OpRB71 Sicilian: Dragon, Levenfish, 6...Nbd7[miElB48o Sicilian: Taimanov, 6.Be3 a6 7.Bd3 Nf6 8.O-O Nxd4kHC92q Spanish: Closed, Zaitsev, 12.a4/=HD00p Queen's Pawn: Veresov, 3.Nf3 g665hTD00u Blackmar-Diemer: Elbert CountergambiteTHA45a Indian: Gibbins Gambit Acceptedsm(-BD33e QGD Tarrasch: Swedish, 7.Bg2=VD45s Semi-Slav: 6.Qc2 Bd6 7.b3 O-O 8.Be2 b6~0K1fC69d Spanish: Exchange, Gligoric, 6.d4 Bg4 7.c3 Bd6z'cjB38f Sicilian: Maroczy Bind, 6.Be3 Nf6 7.Nc3 d6 8.Be2vuBD80 Grnfeld: Stockholm VariationmKR~C05j French: Tarrasch, Closed, 5.f4 c5 6.c3 Nc6 7.Ndf3 Qb6 8.h4l)FE90f King's Indian: 5.Nf3 O-O 6.Bd3ew<D14p Slav: Exchange, 8.Bb5 Nd7`ϱJD36g QGD: Exchange, 6.Qc2 Be7 7.e3 h6[dbBB58h Sicilian: Boleslavsky, 7.Nf3YI”]BD80 Grnfeld: Spike/Gibbon GambitTL$OZC18q French: Winawer, 6...Ne7 7.Qg4 O-O 8.Nf3Qz\dA45r Trompowsky: 2...c5 3.Bxf6 gxf6 4.d5 Qb6 5.Qc1Mx<C11t French: Burn, 6.Bxf6 Bxf6KCrWHA48s Neo-King's Indian: Torre AttackK]/A66 Benoni: Mikenas Attack, 9.Nb5 dxe5 10.Nd6+ Ke7 11.Nxc8+ Qxc8 12.Nf3B\_/}HA01 Nimzowitsch-Larsen: 1...e5 2.Bb2ByF<E04b Catalan: Open, 5.Nf3 Bb4+?Mu0D16g Slav: Smyslov, 6.e3?٘e8C60e Spanish: Lucena Defence)mk3tfA46z Torre Attack: 3...h6 4.Bxf6 Qxf6 5.e4 d6 6.Nc3"輢:B04c Alekhine: Modern, 4...c6acLB92e Sicilian: Najdorf, 6.Be2 e5 7.Nb3ZrS`E12x Queen's Indian: 5.Bg5 h6 6.Bh4 Be7 7.e3 Ne4ȖVB32s Sicilian: Lowenthal, Kalashnikov, 6.c4toXA36s English: Symmetrical, Botvinnik, 5...d6 f6LB74 Sicilian: Dragon, Classical, 9.Nb3sڬ~C89x Spanish: Marshall, Main Line, Classical, Spassky VariationfK{^<B32f Sicilian: Flohr VariationRȮQWXA67l Benoni: Four Pawns, Taimanov, 9.a4 Qh4+陷pB97l Sicilian: Najdorf, Poisoned Pawn, 9.Nb3 Qa3 10.Bxf60ɐJC90d Spanish: Closed, 8...d6 9.a4 Bg4Z="FPA40g Queen's Pawn: English Defence, 3.e4y`\E77 King's Indian: Four Pawns Attack, 6.Be2 c5S1v(`A44w Old Benoni: Czech, 3.e4 d6 4.Nc3 Be7 5.Bb5+TD99a Grnfeld: Russian, Smyslov, Main Line$HU3 PE09c Catalan: Closed, Main Line, 8...Re8sD˔PC06a French: Tarrasch, Closed, Main Line>TA90 Dutch: 2.c4 Nf6 3.g3 e6 5.Nf3 d5 6.O-OE41 Nimzo-Indian: Hbner, 8.O-ORLIxB22i Sicilian: Alapin, 2...d5 3.exd5 Qxd5 4.d4 Nc6 5.Nf3 Bg4\0YVD27j QGA: Classical, 6...a6 7.Bb3 Nc6 8.Nc3pǚXD64 QGD: Orthodox, Rubinstein Attack, 8...h6CMZfHE20 Nimzo-Indian: Romanishin, 4...c5NFD25g QGA: Janowski-Larsen Variationσ jA64 Benoni: Fianchetto, 11...Re8 12.h3 Rb8 13.Nc4 Nb6~*X>DC56d Two Knights: Classical, 8.Nc32-TE91h King's Indian: 6.Be2 c5 7.d5 e6 8.O-OSċ @D43t Semi-Slav: Moscow, 7.e3 Nd7uLJ488B00h Owen Defence: 3.Bd3 Nf6a2NC26g Vienna: Smyslov, 3...Bc5 4.Bg2 O-Of:B90g Sicilian: Najdorf, 6.Be3x:E61k King's Indian: 4.Nf3 O-OK B65g Sicilian: Richter-Rauzer, 7...Be7, 9.f4 Nxd4 10.Qxd4 Qa5 11.Bc4 Bd7 12.e5u؏}0XD38o QGD: Ragozin, 5.Bg5 h6 6.Bxf6 Qxf6 7.e3uM%n9S`D52m QGD: Cambridge Springs, Argentine VariationqR56U.E11g Bogo-Indian: 4.Bd2qH!Dq0.D17b Slav: Czech, 6.Nh4i0x$>D37d QGD: 4.Nf3 Be7 5.cxd5 Nxd5^e\-I#~E98g King's Indian: Mar del Plata, 9.Ne1 Ne8 10.Be3 f5 11.f3 f4WlK!!*B23c Sicilian: ClosedQi :C50b Italian: Rousseau GambitOf<RD31w Semi-Slav: Marshall Gambit, 4...dxe4IӟÕ9RC40p Latvian Gambit: Svedenborg VariationI83>hB87 Sicilian: Sozin-Najdorf, 7.Bb3 b5 8.O-O Be7 9.f4I01XA85 Dutch: 2.c4 Nf6 3.Nc3 g6 4.Nf3 Bg7 5.Bg5GfbC28k Vienna: 3.Bc4 Nc6 4.d3 Bc5 5.f4 d6 6.Nf3 Bg461hjA74 Benoni: Classical, 9.O-O a6 10.a4 Nbd7 11.Bf4 Qe7/W`C04f French: Tarrasch, Guimard, Main Line, 6.Be2*[!@4D06e QGD: Marshall Defence%rgZE62n King's Indian: Fianchetto, 6...Nc6 7.O-OO:x$B07d Pirc: 2.d4 c6z`A58q Benko Gambit: Fianchetto, Main Line, 11.Rb1fvtC05i French: Tarrasch, Closed, 5.f4 c5 6.c3 Nc6 7.Ndf3 Qb6ؑ5O6B32g Sicilian: Flohr, 5.Nb5wRE38c Nimzo-Indian: Classical, 4...c5 5.e3`{\E45 Nimzo-Indian: Nimzowitsch, 5.Ne2 Ba6 6.Ng3HRA99 Dutch: Ilyin-Zhenevsky, 8.b3 a5 9.Bb2 v<\D47t Semi-Slav: Meran, Wade, Main Line, 12.O-O5-uSA26 English: Closed, 5.d3 d6 6.Nf3 Nf6 7.O-O O-O 8.Rb1 a5 9.a3 h6z3'ZB40r Sicilian: Open, 2...e6, 4.Nxd4 Nf6 5.Nc3L3/.,C28a Vienna: 3.Bc4 Nc6]e1f~C07r French: Tarrasch, Open, 4.exd5 Qxd5, Main Line, 10.Nxd4 a6s @B06l Modern: Mittenberger Gambit'8BB93c Sicilian: Najdorf, 6.f4 Nbd7̡y B07a Pirc: 2.Nc3{B @B18l Caro-Kann: Classical, 6.Nf3H sHB19c Caro-Kann: Classical, 7.Nf3 Nf6FUPC97h Spanish: Closed, Chigorin, 12...Bd7 nE08p Catalan: Closed, 7.Qc2 c6 8.b3 b6 9.Rd1 Bb7 10.Nc37ޗ\C31 KGD: Falkbeer, Marshall/Nimzowitsch, 4.Qe2pb90^D35p QGD: Exchange, 5.Bg5 c6 6.e3 Be7 7.Nf3 Bf5dj+)`B05o Alekhine: Modern, Main Line, 8.h3 Bh5 9.Nc3ck JC41s Philidor: Improved Hanham, 5.Bc4Eড়RB93l Sicilian: Najdorf, 6.f4 e5 7.Nf3 Qc7DiGtJJC40t Latvian Gambit: 3.Nxe5 Qf6 4.Nc4DD6YRbD85c Grnfeld: Exchange, 5.Bd2 Bg7 6.e4 Nb6 7.Be3:OzA36x English: Symmetrical, Botvinnik System, 5...d6, 8.d3 Rb8*F'e?(4D73 Neo-Grnfeld, 5.Nf3 c6'&?TA30n English: Symmetrical, Hedgehog, 7.Re1&珱B99e Sicilian: Najdorf, Main Line, Keres, 13.Qg3 dxe5 14.fxe5 Nd7 15.Bxb5$qW{VA56s Benoni: Czech, 5.e4 Be7 6.g3 O-O 7.Bg2$xa7vB33s Sicilian: Pelikan, Chelyabinsk, 9.Bxf6 gxf6 10.Nd5 Bg7.thE70p King's Indian: 4.e4 d6 5.Bd3 O-O 6.Nge2 c5 7.d5uX\:B03c Alekhine: 3.d4 d6 4.exd67aFE52 Nimzo-Indian: Main Line, 6...b6St{bND70 Neo-Grnfeld: Alekhine's, 7.Be3 O-OGTH"JFA29 English: Four Knights, 4.g3 Bc5:CUn3NB21e Sicilian: Grand Prix, 2...Nc6 3.d3!z;NA41f Neo-Old Indian: Wade Defence, 3.e3("ԒlC44w Scotch: Goring Gambit, 4...dxc3 5.Bc4 cxb2 6.Bxb2WÛ*A80m Dutch: 2.Nc3 Nf6& 5S؎JE00f Queen's Pawn: Neo-Indian, 3...c5(|6PD02j Queen's Pawn: Krause, Reversed SlavgBM'D37t QGD: Classical, 5...O-O 6.e3 c5 7.dxc5 Bxc5 8.Qc2 Nc6 9.a3 Qa5,PE94k King's Indian: Glek, 8.Re1 c6 9.Bf1\HC48j Four Knights: Rubinstein, 5.Bc4|lE52 Nimzo-Indian: Main Line, 6...b6 7.O-O Bb7 8.a3 Bd6x??qx.E00s Catalan: 4.Nf3 Be7vu,ZA44h Old Benoni: Czech, 3.c4 d6 4.e4 g6 5.Nc3qL~tE14x Queen's Indian: 4.e3 Bb7 5.Bd3 c5 6.O-O Be7 7.Nc3 O-Oo WPB04k Alekhine: Modern, Fianchetto, 5.Bc4kӈFLE30 Nimzo-Indian: Leningrad, 6.d5 exd5jՉ`E16f Queen's Indian: Capablanca, Yates VariationdAD(A45d Indian: 2.e3 e6\kGFC18r French: Winawer, Poisoned PawnWgKND97m Grnfeld: Russian, Prins VariationVvx 4C30j KGD: Classical, 3.Nf3TIySHC86a Spanish: Worrall Attack, 6...d6N!8D35d QGD: Exchange, 5.Nf3 c6MOG}VA53 Old Indian: Ukrainian, Queenswap, 6.Nf3L]c(NB04f Alekhine: Modern, Larsen VariationC^O|D58n QGD: Tartakower, 8.Be2 Bb7 9.Bxf6 Bxf6 10.cxd5 exd5 11.b4@݉gj0DC30q KGD: Classical, 4.c3 Nf6 5.d48w(FDD12j Slav: 4.e3 Bf5 5.Nc3 e6 6.Be21y9>E21 Nimzo-Indian: Three Knights-T-LBD44f Semi-Slav: Botvinnik, 9.exf6%jB59h Sicilian: Boleslavsky, 7.Nb3 Be7 8.O-O O-O 9.Bg5%zbPFA96 Dutch: Classical, 7.b3 a5 8.Bb2X{HC28i Vienna: 3.Bc4 Nc6 4.d3 Bc5 5.f4hQHE71a King's Indian: Makagonov SystemT+ 2B07s Pirc: Holmov (4.Bc4)B̈3,A46c Neo-Benoni 3.dxc5!d:IDE06 Catalan: Closed, 6.O-O c6 7.b3|48A58b Benko Gambit: 5.bxa6 g6xIּa`A30l English: Symmetrical, Hedgehog, 6...d6 7.d4rq0!b0A10 English: Anglo-DutchptH8B41a Sicilian: Kan (Paulsen)mc0D02a Queen's Pawn: 2.Nf3hBE11f Bogo-Indian: 4.Nbd2 O-O 5.a3dٟR6A24 English: Bremen, 3...g6[ ={:C45o Scotch: 4.Nxd4 Bc5 5.Nb3Y0U¡NE15h Queen's Indian: Nimzowitsch, 5.Qa4EHQ<D34i QGD Tarrasch: 9.dxc5 Bxc5>rs'F'RC66 Spanish: Closed Berlin, Tarrasch Trap="D20d QGA: 3.e3 e6NHB95e Sicilian: Najdorf, 6...e6 7.Qd2 6JC16h French: Winawer, Petrosian, 5.a3/IʂxB29n Sicilian: Nimzowitsch, Rubinstein Countergambit, 7.dxc5BtDC51 Evans Gambit: Cordel Variation @~NurD33q QGD Tarrasch: 7.Bg2 cxd4 8.Nxd4 Be7 9.O-O O-O 10.Be3_\NC05w French: Tarrasch, Closed, 7.Ne2 a5do<7<E18l Queen's Indian: 7.Nc3 Ne4N&0hD64 QGD: Orthodox, Rubinstein Attack, Wolf Variation{2A00q Polish: 1...d5 2.Bb2n 1nfE69i King's Indian: Fianchetto, Classical, 9.h3 Qb6ٷW>D41a QGD: Semi-Tarrasch, 5.cxd5ڈ'>>C57j Two Knights: Fritz, 8.cxd5>D25g QGA: Janowski-Larsen, 5.h3\xfB02l Alekhine: Brooklyn Defence (Retreat Variation)Jy HD30i QGD: Tarrasch without Nc3: 5.g3,TcDB06r Modern: Two Knights VariationbrtA33f English: Symmetrical, Two Knights, 5.Nc3 Nc6 6.a3 Bc5;PC50c Italian: Blackburne-Shilling GambitMTQ6A12 English: London DefencedߪNC40d Open Game: Gunderam Defence, 3.Nc3rB23w Sicilian: Closed, Grand Prix, 3...g6 4.Nf3 Bg7 5.Bb5c@A34 English: Symmetrical, 2...b6WLD35n QGD: Exchange, 5.Bg5 c6 6.e3 Nbd7ƘC16o French: Winawer, Advance, 4...Ne7 5.a3 Bxc3+ 6.bxc3 b6 7.Qg4vivVA41h Neo-Old Indian: Wade Defence, 3.c4 Nd7?ZFD28h QGA: Classical, 7.Qe2 b5 8.Bb3}Nj!D37u QGD: Classical, 5...O-O 6.e3 c5 7.dxc5 Bxc5 8.Qc2 Nc6 9.a3 Qa5 10.Rd1vׁ7SbE62o King's Indian: Fianchetto, 6...Nc6 7.O-O Rb8p_|XE53 Nimzo-Indian: Main Line, Keres Variationn @,C34 KGA: Fischer, 4.d4g}jrC48f Four Knights: Spanish, Classical, Marshall VariationZ9TA69b Benoni: Four Pawns, Main Line, 10.O-OO=tN"nD57 QGD: Lasker Defence, Main Line, Bernstein VariationLbА>B30i Sicilian: 2...Nc6 3.Nc3 g6KےZA01 Nimzowitsch-Larsen: 1...e5 2.Bb2 Nc6 3.e3>.[ğ;\D41m QGD: Semi-Tarrasch, 6.e4, Kmoch Variation0_Y!8A45a Indian: Paleface Attack$tXD63 QGD: Orthodox, Swiss, Karlsbad Variation- Zw D11i Slav: 4.Qc2 U`^ZE90v King's Indian: 5.Nf3 O-O 6.h3 c5 7.d5 e6YJB46m Sicilian: Taimanov, 5...a6 6.Be2:H`TE32f Nimzo-Indian: Classical, 4...O-O 5.e4s8A00r Polish: 1...e5 2.Bb2 f6%THC61j Spanish: Bird's, 5.O-O Bc5 6.d3ծ ZB14f Caro-Kann: Panov-Botvinnik, 5...g6 6.Qb3ꍁ_ BB01s Scandinavian: 2...Nf6 3.Bb5+[)RA65g Benoni: 6.e4 g6 7.Bd3 Bg7 8.Nge2 O-O߀-ZD00h Hodgson Attack: 2...h6 3.Bh4 c6 4.e3 Qb6hRA51k Budapest: Fajarowicz, 4.Nf3 Nc6 5.a3k6[PD71 Neo-Grnfeld, 5.cxd5 Nxd5 6.Nc3 Nxc3￲hA45o Trompowsky: 2...e6 3.e4 h6 4.Bxf6 Qxf6 5.Nc3 d6yїkbC15s French: Winawer, Alekhine Gambit, Kan, 7.Bb5 %m4C46c Three Knights: 3...d68 VXA36p English: Symmetrical, Botvinnik, 5...e6z\AA08NC18n French: Winawer, 6...Ne7 7.Qg4 O-O>QbKZC15h French: Winawer, Mller-Zhuravlev Gambitp{XA40d Queen's Pawn: English Defence, 2.c4 Bb7Yw@JE04g Catalan: Open, 5.Nf3 a6 6.O-O b5kA` ^E13g Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.e3 c5 ijA55f Old Indian: 5.e4 Be7 6.g3 c6 7.Bg2 O-O 8.O-O Re8*o 'RB76a Sicilian: Dragon, Yugoslav, 7.f3 O-OGg(FD25d QGA: Smyslov, 5.Bxc4 Bg7 6.Nc3*9<JE70l King's Indian: 4.e4 d6 5.Bd3 O-OXC28d Vienna: 3.Bc4 Nc6 4.d3 Be78qޠRXC68h Spanish: Exchange, Romanovsky Variation&:B42d Sicilian: Kan, 5.Bd3 Qc7ݘB0A10 English: Anglo-DutchgKVA55e Old Indian: 5.e4 Be7 6.g3 c6 7.Bg2 O-O#+cPA16 English: Anglo-Indian, 2.Nc3 g6 3.e4/@8bE54 Nimzo-Indian: Main Line, 7...dxc4 8.Bxc4 cxd4`w.C46a Three Knights GamekVD|E58 Nimzo-Indian: Main Line, 9.bxc3 Qc7 10.cxd5 exd5 11.a4 Re8 D15a Slav: 4.Nc34bA45o Trompowsky: 2...e6 3.e4 h6 4.Bxf6 Qxf6 5.Nc3U6xC64t Spanish: Classical, 4.O-O Nd4 5.Nxd4 Bxd4 6.c3 Bb6 7.d4;s^E70o King's Indian: 4.e4 d6 5.Bd3 O-O 6.Nge2 c5z-h,!TC13g French: Classical, Tartakower, 6.Bxe73rP(E00g Catalan: 3...c6|UXA46o Indian: 1.d4 Nf6 2.Nf3 e6 3.g3 c5 4.Bg2~;yjC91h Spanish: Closed, Bogoljubow, 10.d5 Na5 11.Bc2 c6x-C63u Spanish: Schliemann, 4.Nc3 fxe4 5.Nxe4 d5 6.Nxe5 dxe4 7.Nxc6 Qg5U)o PB46r Sicilian: Taimanov, 5...a6 6.Be2 d6~e\PA37f English: Symmetrical, 5.Nf3 d6 6.d3zoYHD42q QGD: Semi-Tarrasch, 7.Bd3 Main Line, 10.Re1 Bf6 11.Be4 Nce7sdn*RhDC88a Spanish: Closed, 6...b5 7.Bb3W8P8D01f Richter-Veresov: 3...c6V 9SVC18r French: Winawer, Poisoned Pawn, 10.Qd3QmA70y Benoni: Classical, 8.h3 O-O 9.Bd3 b5 10.Nxb5 Re8 11.O-O Nxe4QW=TE60k King's Indian: Fianchetto without Nc3Pe$dB53j Sicilian, Chekhover, 4...a6 5.c4 Nc6 6.Qd2 g6>oٲZC19m French: Winawer, 6...Ne7 7.Nf3 Nbc6 8.a4A43x Old Benoni: Schmidt, 6.Be2;mRE51 Nimzo-Indian: 4.e3 O-O 5.Nf3 d5 6.Be2 \B78p Sicilian: Dragon, Yugoslav, Main Line, 12.h4 h5 13.Bg5 Rc5 14.g4X6PA58p Benko Gambit: Fianchetto, Main Line%@CzB13v Caro-Kann: Panov-Botvinnik, 5...Nc6, Spielmann Variation,K(A00b Fried fox0A09g Reti: Advance, 3.g3 BxD46m Semi-Slav: Chigorin, 7.Qc2 Main Line, 9...b5 10.Be2 Bb7%6dA39e English: Symmetrical, Main Line 7.d4, 8...Qb6E"«>B28j Sicilian: O'Kelly, 3.c3 d5wِg2A02 Bird: 1..Nf6 2.Nf3 g6;QLB48d Sicilian: Taimanov, 6.Be3 a6 7.a3 >D91h Grnfeld: 5.Bg5 Ne4 6.cxd5`]6C45w Scotch: Paulsen Attack~ݛjE74o King's Indian: Averbakh, 6...c5 7.d5 h6 8.Bf4 e6v@Q=]JC37 KGA: Salvio, Silberschmidt GambitkDND64 QGD: Orthodox, Rubinstein Attack, Grnfeld Variation, 9...h6 10.Bh4jP">A03 Bird: 1...d5 2.Nf3 Nf6 3.b3f"zVA34 English: Symmetrical, 3 Knights, 3...e6ez@C78h Spanish: 5.O-O b5 6.Bb3 Bc5^ E8B56c Sicilian: Venice AttackZ.b8A07 Reti: KIAIflFA18 English: Mikenas, Flohr, 4...d48s[SN^A89 Dutch: Leningrad, Main Line, 7.Nc3 Nc6 8.b36fJE12c Queen's Indian: Miles, 5.e3 Bb4+4tI2A81 Dutch: 2.g3 Nf6 3.Bg23+ۉHA12 English: New York/London Defence.L>A44m Old Benoni: Czech, 3.e4 d6*U-BD37f QGD: 4.Nf3 Be7 5.e3 O-O 6.b3Tˡ<A68c Benoni: Four Pawns, 9.Be2&Ƚ:LD29e QGA: Classical, 8...Bb7 9.a4 Nbd7䨨RE20 Nimzo-Indian: Romanishin, 4...c5 5.d55 *B23e Sicilian: Closed~uL(D08 QGD: Albin, 4.a3.D21g QGA: 3.Nf3 e6 4.e3䦚4fC06f French: Tarrasch, Closed, Leningrad, 9.O-O Bd7m`E55 Nimzo-Indian: Main Line, Bronstein, 9.Qe2 a6m5r,B00a King's Pawn: Fred:ӜXB04l Alekhine: Modern, Fianchetto, 5.Bc4 Nb6.۹&A00b Barnes Openingb)қNC80m Spanish: Open, Zukertort VariationO<8B21m Sicilian: Halasz GambitTYQѣFA46k Indian: 1.d4 Nf6 2.Nf3 e6 3.e3J4RC83 Spanish: Open, Classical, 10.Nbd2 O-O\8zxC07p French: Tarrasch, Open, 4.exd5 Qxd5, Main Line, 10.Qxd4plXC78w Spanish: Archangelsk, Main Line, 10.Bg5pͱ!%~E16i Queen's Indian: Capablanca, Nimzowitsch, 7.O-O Bxd2 8.Qxd2k^:C88g Spanish: Closed, 8.d3 d6hX .|D85p Grnfeld: Modern Exchange, 8.Rb1 O-O 9.Be2 Nc6, Main Lineem04ddB14e Caro-Kann: Panov-Botvinnik, 5...g6 6.cxd5 Bg7`Ł<A44b Old Benoni: Czech, 3.dxe6^Ep;BB00u Nimzowitsch Defence: 2.d4 e5Lcq2B18a Caro-Kann: ClassicalL-DC55m Two Knights: 4.d4 exd4 5.Nxd4IQ.u:C02k French: Advance, 4...Nc6$l}=BC47i Four Knights: Scotch, 4...d6BT XC56c Two Knights: Classical, Canal VariationLwkqPC90m Spanish: Closed, Pilnik, 12.Nf1 Bf8ɇg HE08e Catalan: Closed, 7.Qc2 c6 8.Rd1q_\<B20 Sicilian: English, 2...Nc6ΉB`E31c Nimzo-Indian: Leningrad, Main Line, 7.e3 g5ǪyVD49d Semi-Slav: Meran, Trifunovic Variationo[@ZHB58d Sicilian: Boleslavsky, 6...Nxd4jB38i Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 b6 9.O-OQhAB11i Caro-Kann: Two Knights, 3...Bg4 4.h3 Bxf3 5.Qxf3 e6 6.g3 Nf6ݜGTB26o Sicilian: Closed, 6.Be3 e6 7.Qd2 Nge7l96A16 English: Anglo-Grnfeld̻C2A02 Bird: 1..c5 2.Nf3 Nc6^ZpLA45y Trompowsky: 2...Ne4 3.Bf4 c5 4.f3Y:B44b Sicilian: Taimanov, 5.g3Z @8D37i QGD: Classical, 5...O-O5`D72 Neo-Grnfeld, 5.cxd5 Nxd5 6.e4 Nb6 7.Ne2 O-O7=9\A29 English: Four Knights, 4.g3 d5 5.cxd5 Nxd5|&RJA48i Neo-King's Indian: London System:yjLB53g Sicilian, Chekhover, 4...a6 5.Be3Ǐ&ؘBB10i Caro-Kann: English Variation}`JNE05j Catalan: Open, Classical Main LineyaΈ4A04 Reti: Herrstrm Gambitu;YHC47d Four Knights: Italian VariationparD26n QGA: Classical, Furman, 6...a6 7.dxc5 Bxc5 8.O-O Nc6ik"ZVB93i Sicilian: Najdorf, 6.f4 Qc7 7.Nf3 Nbd7eDO4B07b Pirc: 2.Nf3 Nf6 3.Nc3e. yV}HB18e Caro-Kann: Classical, 5.Ng3 Bg6_mf-fa|B01g Scandinavian: Anderssen Counterattack, Goteborg Variation\FrstE75h King's Indian: Averbakh, 7.d5 e6 8.Qd2 exd5 9.exd5 a6\UBB10i Caro-Kann: English VariationYO5i>C65d Spanish: Berlin, 4.d4 exd4Va(٭^D44k Semi-Slav: Botvinnik, Lilienthal VariationM}$NC40u Latvian Gambit: 3.Nxe5 Qf6 4.d4 d6M;@.2D35a QGD: Harrwitz AttackKR0C80f Spanish: Open, 6.d4FE =pC19p French: Winawer, 6...Ne7 7.Nf3 Nbc6 8.a4 Qa5+ 9.Bd2A8@`C17i French: Winawer, Bogoljubow, 5...Ne7 6.dxc5=g\ar6A65m Benoni: Smisch, 8.Be37wsrE86g King's Indian: Smisch, Orthodox, 7.Nge2 c6 8.Qd2 Nbd7 9.O-O-O5J4B[dD30i QGD: Tarrasch without Nc3: 5.g3 Nc6 6.Bg2 Nf64n:WdA83b Dutch: Staunton Gambit, Nimzowitsch Variation)=NfE84f King's Indian: Smisch, Panno Main Line, 9.Bh6RH֐4C88g Spanish: Closed, 8.d3^.8B28h Sicilian: O'Kelly, 3.c3 d@8C15b French: Winawer, 4.exd5{%*B23d Sicilian: ClosedzjSrA87 Dutch: Leningrad, Main Line, 7.Nc3 Qe8 8.d5 Na6 9.Rb1ꤺ &E87k King's Indian: Smisch, Orthodox, 7.d5 Nh5 8.Qd2 f5 9.O-O-OZL@BC15b French: Winawer, 4.exd5 Qxd5z9 #XD65 QGD: Orthodox, Rubinstein Attack, 9.cxd5ޤ`B70p Sicilian: Dragon, 6.Be2 Bg7 7.O-O O-O 8.Re1.IŐFC14a French: Classical, 6.Bxe7 Qxe7׹uT8B41h Sicilian: Kan, 5.c4 Nf62RICZB51q Sicilian: 3.Bb5+ Nc6 4.O-O Bd7 5.Re1 Nf6ͯ8~ORD98a Grnfeld: Russian, Smyslov VariationrS4C37 KGA: MacDonnell Gambit߭TBD06g QGD: Marshall Defence, 3.Nf3͢HC39 KGA: Allgaier, Thorold Variation{3 HVD97b Grnfeld: Russian, Levenfish VariationtfUJXLD48c Semi-Slav: Meran, 8...a6 9.O-O c5s`_>B18p Caro-Kann: Classical, 6.h4pG#TD27r QGA: Classical, Rubinstein, 8.Nc3 Be7iFC21 Danish Gambit: Chigorin Defencegk:A92 Dutch: Alekhine Variation^Ƃ8DC45m Scotch: Mieses, 8.c4 Ba6 9.b3Zl:E91u King's Indian: 6.Be2 Bg4Yd3XC59c Two Knights: Morphy, Main Line 9.Nf3 e4X 6A92 Dutch: Stonewall, 7.Qc2Tc$҅J>D24g QGA: 4.Nc3 c5 5.d5 e6 6.e4S>SJBD43v Semi-Slav: Moscow, Main LineR"lLC16g French: Winawer, Petrosian, 5.Bd2OT3BA18 English: Mikenas, Flohr, 7.d4C0fD85o Grnfeld: Modern Exchange, 8.Rb1 O-O 9.Be2 Nc6BLLBC17n French: Winawer, Swiss, 6.b4@ XB97q Sicilian: Najdorf, Poisoned Pawn, 10.f5?Ƃ_ }LB70d Sicilian: Dragon, 6.g3 Nc6 7.Nde25RC65m Spanish: Berlin, Beverwijk Variation*ʋ(uJC49c Four Knights: Gunsberg Variation).EIrE12o Queen's Indian: Petrosian, 5.Nc3 d5 6.Bg5 Be7 7.Qa4+(0/yLE62c King's Indian: Fianchetto, 6...c6%Am0dE98r King's Indian: Mar del Plata, 9.Ne1 Nd7 10.f32DtB81f Sicilian: Scheveningen, Keres, Perenyi Attack, 7...h6o;0D53p QGD: 4.Bg5 Be7 5.e3{PbJVB58g Sicilian: Boleslavsky, Louma Variation֮RA14 English: Neo-Catalan Declined, 5...c6 >p9N4D12c Slav: 4.e3 Bf5 5.cxd5ChVB13g Caro-Kann: Exchange, 4.Bd3 Nc6 5.c3 g6RX)<D55b QGD: Lasker without ...h6epQlE52 Nimzo-Indian: Main Line, 6...b6 7.O-O Bb7 8.cxd5 exd5 9.a3 Bd6/(>B98n Sicilian: Najdorf, 8...Qc7{ 8C78e Spanish: 5.O-O b5 6.Bb3l 6{<E02 Catalan: Open, 5.Qa4+ Nbd7P%CTE73k King's Indian: Averbakh, 6...c6 7.Qd2txh\A32 English: Symmetrical, Two Knights, 5.g3 a6G6VA38c English: Symmetrical, Main Line, 6.O-OYJC28n Vienna: 3.Bc4 Nc6 4.d3 Bb4 5.Nf3쮍BE30 Nimzo-Indian: Leningrad, 6.d5 uLC56f Two Knights: Classical, 8.Nc3 Qh55ZrD84 Grnfeld: Grnfeld Gambit Accepted, 8...Nc6 9.Ne2 Bg4ߙto@B96c Sicilian: Najdorf, 7.f4 Nc6RzXA70f Benoni: Classical, 8.Qa4+ Bd7 9.Qb3 Qc7ʮ2׈D43a Semi-Slav h,6A52b Budapest: 3...Ng4 4.e3L:C34 KGA: King's Knight GambitZB11b Caro-Kann: Two Knights, 3...Bg4 4.h3 Bh5%fC96o Spanish: Closed, Chigorin, Keres, 11.Nbd2 cxd4C˫pE89c King's Indian: Smisch, Orthodox Main Line, 9...Bd7vO^B44x Sicilian: Taimanov, Szen, Hedgehog, 11.Be3 FqhhE56 Nimzo-Indian: Main Line, 7...Nc6 8.a3 Ba5 9.cxd5sY:A70h Benoni: Classical, 8.Bd3y̛vE15o Queen's Indian: Nimzowitsch, 5.b3 Bb4+ 6.Bd2 Be7 7.Nc3l} #E14w Queen's Indian: 4.e3 Bb7 5.Bd3 c5 6.O-O Be7 7.b3 O-O 8.Bb2 cxd4a5!s:E11x Bogo-Indian: 4.Bd2 Bxd2+S,B=HA57n Benko Gambit: 4.cxb5 a6 5.e3 g6Eۺ5;^E92i King's Indian: Gligoric-Taimanov, 7...exd4Cm??>C11d French: Steinitz, 5.Nf3 c5B4t*]`B97r Sicilian: Najdorf, Poisoned Pawn, Main Line< G<B25l Sicilian: Closed, 6.f4 e69%2E97q King's Indian: Mar del Plata, Bayonet, 9...Nh5 10.Re1 Nf4 11.Bf1 a5 12.bxa55ڸu*A65a Benoni: 6.e4 Be7! ohD10k Slav: Winawer Countergambit, 4.cxd5 cxd5 5.dxe5 VNhB48q Sicilian: Taimanov, 6.Be3 a6 7.Bd3 Nf6 8.O-O b5 `Lp}^E89a King's Indian: Smisch, Orthodox Main Line^0\B97o Sicilian: Najdorf, Poisoned Pawn, 10.Bxf6O,8&lB62i Sicilian: Richter-Rauzer, Margate, 7...Bd7 8.Bxc6eQZA31 English: Symmetrical, Two Knights, 3...g6{dD4D15l Slav: Chameleon, 5.a4˺D,B35l Sicilian: Accelerated Fianchetto, Modern, 7.Bc4 O-O 8.Bb3 a5h0l#]9TB16j Caro-Kann: Bronstein-Larsen, 6.c3 Bf5効FH>:A84 Dutch: Rubinstein, 3...d5⿘`C10t French: Rubinstein, 4...Bd7 5.Nf3 Bc6 6.Bd3<A11 English: Caro-Kann Defence]p]aHE94f King's Indian: Donner VariationRnRA88 Dutch: Leningrad, Main Line, 7.Nc3 c6Μ-^D84 Grnfeld: Grnfeld Gambit Accepted, 8...Bf5T^D `E94r King's Indian: 7.O-O Nbd7 8.d5 Nc5 9.Qc2 a5DX}NB63h Sicilian: Richter-Rauzer, 7.Qd2 h6I)ZXC06i French: Tarrasch, Closed, 8...Qb6 9.Nf3NxPC89h Spanish: Marshall, Kevitz VariationGЉ@A46i Indian: 2.Nf3 d6 3.Bg5 Nbd7tKMjB42o Sicilian: Kan, 5.Bd3 Nf6 6.O-O Qc7 7.Qe2 d6 8.c4݆V&4E06 Catalan: Closed, 6.Qc2!sxg^>C44h Open Game: Inverted Hanham"xB34v Sicilian: Accelerated Fianchetto, Modern, 6.Be3 Nf6 7.Be2 O-O 8.O-O d5z a^D33d QGD Tarrasch: Swedish, Rey Ardid VariationwfNA17 English: Anglo-Queen's Indian, 4.g3u̱YnE34 Nimzo-Indian: Classical, Noa, 5.cxd5 Qxd5 6.Nf3 Qf5rBLidnB45l Sicilian: Taimanov, Four Knights, 6.Nxc6 bxc6 7.e5fe.D24e QGA: 4.Nc3 c5 5.d5_ϒ!W(VjD67 QGD: Orthodox, Main Line, Capablanca, 11.O-O Nxc3N|38A81 Dutch: 2.g3 Nf6 3.Bg2 e6J:XtynE55 Nimzo-Indian: Main Line, Bronstein, 9.a3 cd4 10.ed4IvO1u7xC46m Three Knights: Steinitz, 4.d4 exd4 5.Nxd4 Bg7 6.Be3 Nf68 tGA39r English: Symmetrical, Main Line 7.d4, 10.Qd3 a6 11.Bd2 Rb8 12.Rac11D?ZA38m English: Symmetrical, Main Line, 7.d3 d50 :D90 Grnfeld: Flohr Variation!9H6C46e Three Knights: 3...Bc5&nC64s Spanish: Classical, 4.O-O Nd4 5.Nxd4 Bxd4 6.c3 Bb6d:FA34 English: Symmetrical, 3 KnightsӪ4A45e Indian: 2.c3 g6 3.Bg5Tώ>E00u Catalan: 4.Nf3 dxc4 5.Qa4+[YLD23p QGA: Mannheim, Main Line, 9...O-O Ѧ׹VC30f King's Gambit: Keene Defence, 3.g3 Qe7 %;FE22 Nimzo-Indian: Spielmann, 4...c5P)Z\C51 Evans Gambit Declined, Showalter VariationŮ[dE74n King's Indian: Averbakh, 6...c5 7.d5 h6 8.Bf4tn9R.VC13e French: Classical, Frankfurt VariationƣGdE16l Queen's Indian: Capablanca, Riumin, 7.Nc3 O-O,A\ZA70c Benoni: Classical, 7...a6 8.a4 Bg4 9.Be2E#ZVC27h Vienna: 3.Bc4 Nxe4 4.Qh5 Nd6 5.Bb3 Nc6#a\C74 Spanish: Modern Steinitz, Siesta Variation;z jA16 English: Anglo-Grnfeld, Andersson-Bk VariationYPB13q Caro-Kann: Panov-Botvinnik, 5...Nc63l/qNA17 English: Anglo-Queen's Indian, 4.g3KZVB87 Sicilian: Sozin-Najdorf, 7.Bb3 b5 8.O-OK+rB84 Sicilian: Scheveningen, Classical, 7.O-O Qc7 8.a4 Nc6t>&PA93 Dutch: Stonewall, Botvinnik, 7...Nc6tZ, 8D30n QGD: 3.Nf3 c6 4.Qc2 Nf6s">$TE90u King's Indian: 5.Nf3 O-O 6.h3 c5 7.d5lN~DB09s Pirc: Austrian, 5...c5 6.Bb5+h!,U>C46d Three Knights: 3...d6 4.d4h:A21 English: King's, 2.Nc3 g6d] :A09t Reti: Accepted, 3.e3 Nf6c`E21 Nimzo-Indian: Nimzo-Queen's Hybrid, 5.Qb3 a5Y1*jBB15p Caro-Kann: von Hennig GambitKo| B11l Caro-Kann: Two Knights, 3...Bg4 4.h3 Bxf3 5.Qxf3 e6 6.d3 Nf6H)^Q>B70c Sicilian: Dragon, 6.g3 Nc6=@2`E38e Nimzo-Indian: Classical, 4...c5 5.dxc5 Bxc55pXC41k Philidor: 3...exd4 4.Nxd4 Nf6 5.Nc3 Be7M.C45n Scotch: 4.Nxd4 Bc57sW~8A73 Benoni: Classical, 9.O-O'\YNA45u Trompowsky: 2...Ne4 3.Bf4 d5 4.Nd2 e@9LD66 QGD: Orthodox, Main Line, 8...dxc4 m2D02c Queen's Pawn: LondonCZ<E57 Nimzo-Indian: Main Line, 8...dxc4 9.Bxc4 cxd4 10.exd4 Be7 11.Bf4=*B23g Sicilian: ClosedWlZVD17d Slav: Czech, 6.Nh4 e6 7.Nxf5 exf5 8.e3w1}D42r QGD: Semi-Tarrasch, 7.Bd3 Main Line, 10.Re1 Bf6 11.Be4 Nce7 12.Ne5l!DVE97d King's Indian: Mar del Plata, 8.d5 Ne7+:6D11m Slav: Slav-Reti System:^jVB09k Pirc: Austrian, 5...O-O 6.Bd3 Nc6 7.e5jua4 TD59n QGD: Tartakower, Main Line, 12.Qa4 c54`y0D09 QGD: Albin, 5.g3 Bg4ׯ*4B\C67e Spanish: Open Berlin, Rosenthal Variationқ `A40g Queen's Pawn: English Defence, Polli GambitŁVpn<C60h Spanish: Alapin Variation[\^E21 Nimzo-Indian: Three Knights, Euwe Variation ux0C34 KGA: Fischer DefenceH֜4A46b Indian: 2.Nf3 b5 3.g3`{Z{\D38n QGD: Ragozin, 5.Bg5 h6 6.Bxf6 Qxf6 7.cxd5;sR.:E05a Catalan: Open, ClassicaliwPE07 Catalan: Closed, Botvinnik Variation4@B94b Sicilian: Najdorf, 6.Bg5 b5pAG&B03e Alekhine: 4.c4͈tE35 Nimzo-Indian: Classical, Noa, Exchange, 6.Bg5 h6 7.Bh4i}C43p Russian Game: Modern Attack, 3...Nxe4 4.Bd3 d5 5.Nxe5 Nd7 6.Qe2QNE31a Nimzo-Indian: Leningrad, Main LineP90^C75 Spanish: Modern Steinitz, Rubinstein, 7.Bb3m,hhB63o Sicilian: Richter-Rauzer, 7.Qd2 Be7 8.O-O-O O-O R\A38e English: Symmetrical, Main Line, 6.O-O d6#.>C31 KGD: Falkbeer Countergambit4BIv>C78f Spanish: 5.O-O b5 6.Bb3 d6,HOPA37j English: Symmetrical, 5.Nf3 e6 6.d3}&S_HA18 English: Mikenas, French, 4.cxd5e5[.C00y French: Schlechterco.HB89 Sicilian: Velimirovic vs. 7...a6_N8FA41o Neo-Old Indian: 2.c4 e5 3.dxe5ZO/4@D46b Semi-Slav: Romih, 7.O-O O-ONՂ DA10 English: 1...g6 2.Nc3 Bg7 3.g3?hFE72 King's Indian: 4.e4 d6 5.g3 O-O:=pV:HC03g French: Tarrasch, 3...Be7 4.Bd39<%:lVA32 English: Symmetrical, Two Knights, 5.e34E*:lA33e English: Symmetrical, Two Knights, 5.Nc3 Nc6 6.a32ˀ DD22d QGA: Alekhine, 4.e3 e6 5.Bxc4*ۯJC63h Spanish: Schliemann, 4.Bxc6 dxc6!9;?>PA49 Neo-King's Indian: Fianchetto System!2"PA37r English: Symmetrical, 5.Nf3 e5 6.a3"DRvD58j QGD: Tartakower, 8.Bd3 Bb7 9.O-O Nbd7 10.Qe2 c5 11.Bg3 QGFA65k Benoni: Smisch (6.e4 g6 7.f3)mNC90b Spanish: Closed, Lutikov VariationR._`A53 Old Indian: Ukrainian, Queenswap, 6.Nf3 Nfd7ټ:1D32i QGD Tarrasch: von Hennig-Schara Gambit, Main Line (11.Be2 O-O-O) Ș\E18r Queen's Indian: 7.Nc3 Ne4 8.Bd2 Bf6 9.Rc1!JA31 English: Symmetrical, Two Knights̻@dND04d Colle: 3...Bf5, Alekhine Variation92&`D93 Grnfeld: 5.Bf4 O-O 6.e3 c5 7.dxc5 Qa5 8.Rc1j+FA30b English: Symmetrical, 2.Nf3 g6p !QItB11e Caro-Kann: Two Knights, 3...Bg4 4.h3 Bxf3 5.Qxf3 dxe4XؒBB21b Sicilian: Grand Prix, 2...g62Gu6E61f King's Indian: 4.g3 d6~>C21 Centre Game: Queenswap line$h2C29n Vienna Gambit: 5.Nf3ϚrE79d King's Indian: Four Pawns Attack, Main Line, 9...Bg4Ɍ)E38l Nimzo-Indian: Classical, 4...c5 5.dxc5 Na6: 8.b4 Nce4 9.Qd4 d5 10.c5βėFdD31x Semi-Slav: Marshall Gambit, 5.Nxe4 Bb4+ 6.Nc3ٍ_FA34 English: Symmetrical, 3 Knights+e<D28c QGA: Classical, 7.Qe2 Nc68<D56 QGD: Lasker Defence, 9.Rc17*6C65k Spanish: Berlin, 4.O-Oc`_NA87 Dutch: Leningrad, Main Line, 6...d6-P^C13p French: Chatard-Alekhine, Breyer Variation8HVC58c Two Knights: Morphy, Maroczy Variation9ZC41e Philidor: Philidor Countergambit, 4.dxe5QCLE15u Queen's Indian: Buerger Variation₡HTA38k English: Symmetrical, Main Line, 7.d3~e2DA15 English: Anglo-Indian, 2.g3 g6':`\C98c Spanish: Closed, Chigorin, Rauzer, 14.Nf1uV>B28i Sicilian: O'Kelly, 3.c3 e6tnqFA42d Modern: Averbakh, 4...c6 5.Be3eE涖`C94e Spanish: Closed, Breyer, 10.d3 Nbd7 11.Nbd2aG-sFD02i Queen's Pawn: 2.Nf3 e6 3.g3 c5\%pB99q Sicilian: Najdorf, Main Line, 10.g4 b5 11.Bxf6 gxf6LchA92 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nf3 O-O 6.d5F,QJ9a>A84 Dutch: Rubinstein VariationAsPC08a French: Tarrasch, Open, 4.exd5 exd522*A03 Bird: 1...d5 2.g31,. AB34v Sicilian: Accelerated Fianchetto, Modern, 6.Be3 Nf6 7.Be2 O-O 8.O-O+MZB06r Modern: Two Knights, Suttles, Tal Gambit| 6D24j QGA: 4.Nc3 a6 5.a4 Nc6 'Bg@VA03 Bird: 1...d5 2.Nf3 Nf6 3.g3 g6: 6.d3 c6! hLA21 English: Kramnik-Shirov, 3.g3 Bxc3l<A11 English: Caro-Kann DefenceE94l King's Indian: Glek, 8.Be3!i,RC50j Giuoco Piano: Four Knights VariationL$C80a Spanish: Open2u)RD47e Semi-Slav: Meran, Capablanca, 8...a6K J>A08 Reti: KIA, French VariationB*^A49 Neo-King's Indian: Double Fianchetto System⸴+BiXA97 Dutch: Ilyin-Zhenevsky, Winter VariationBqDA43m Old Benoni: 2.d5 Nf6 3.Nf3 g6bW2A00r Polish: 1...e5 2.Bb2ܺA>B08l Pirc: Classical, 5.Be2 O-O+tvC21 Centre GameߎRHE80c King's Indian: Smisch, 5...Nc6\1e ,A48c Neo-King's IndianÔ"E08r Catalan: Closed, 7.Qc2 c6 8.b3 b6 9.Rd1 Bb7 10.Nc3 Rc8 11.e4 dxe4 x8TA40j Queen's Pawn: Bogoljubow-Miles, 2.Bg5ǘ &D30q QGD: 3.Nf3 Nf6 z*C>C44a Open Game: Dresden Opening'mѧND47i Semi-Slav: Meran, Lundin Variation!zE97p King's Indian: Mar del Plata, Bayonet, 9...Nh5 10.Re1 a5L0A43e Old Benoni: 2.d5 b5¾E:C84f Spanish: Closed, 6.d3 b5e0XD31t Semi-Slav: Noteboom, Abrahams Variationc=t+fB22t Sicilian: Alapin, 2...Nf6, 5.cxd4 d6 6.Nf3 Nc6X d@B91d Sicilian: Najdorf, 6.g3 Nc6RV;g~)4C30c King's Gambit: 2...d6Rro6i\A38d English: Symmetrical, Main Line, 6.O-O d5QH@VB39b Sicilian: Maroczy Bind, Breyer, 8.Qxg4G]>TD15y Slav: Geller Gambit, 6.e5 Nd5 7.a4 e68*.~f8E73i King's Indian: Averbakh*ɻjD64 QGD: Orthodox, Rubinstein Attack, 8...Re8 9.a3 a6(mb?~D58m QGD: Tartakower, 8.Be2 Bb7 9.Bxf6 Bxf6 10.cxd5 exd5 11.O-O'T7L1vB62g Sicilian: Richter-Rauzer, Margate (Alekhine) VariationoBrRC36 KGA: Scandinavian (Abbazia) VariationPBDE73g King's Indian: 5.Be2 O-O 6.g4_PD45q Semi-Slav: 6.Qc2 Bd6 7.b3 O-O 8.Bb2;o0A10 English: Anglo-Dutch2?hHE17u Queen's Indian: Pomar, 7...exd5/yND59j QGD: Tartakower, Main Line, 11.Rc1VC18r French: Winawer, Poisoned Pawn, 8.Qxg7*o.D82 Grnfeld: 4.Bf4 Bg7֤/7 pD19l Slav: Dutch, 8...O-O 9.Qe2 Nbd7 10.e4 Bg6 11.Bd3 h6}8ZJZC13d French: Classical, Nimzowitsch VariationpZA38n English: Symmetrical, Main Line, 7.d3 d6墺!EDA85 Dutch: 2.c4 Nf6 3.Nc3 e6 4.Bg5J'KEDD07i QGD: Chigorin, 3.Nf3 Bg4 4.e3dGZE21 Nimzo-Indian: Nimzo-Queen's Hybrid, 5.Bg5޼T/}:C16b French: Winawer, 4.e5 b6g}|\E58 Nimzo-Indian: Main Line, 9.bxc3 Qc7 10.Bb2ڼ/)^A30s English: Symmetrical, Hedgehog, 8.Qxd4 O-OӞ>6C11f French: Steinitz, 5.f4ҌZ%GLA87 Dutch: Leningrad, Main Line, 6.O-Oo4C66 Spanish: Closed Berlinˑ}M1^C05f French: Tarrasch, Closed, 5.f4 c5 6.c3 Nc6( A04 Reti: 1...g6pEEqdTA28 English: Four Knights, Stean Variation>7~0sF0E61f King's Indian: 4.g3A>QXD39f QGD: Ragozin, Vienna, 6.e4 c5 7.e5 cxd4-o;mpB64d Sicilian: Richter-Rauzer, 7.Qd2 Be7, 9.f4 h6 10.Bh4}rpD25r QGA: Janowski-Larsen, 6.h3 Bh5 7.Nc3 Nbd7 8.O-O Bd69!δDC21 Danish Gambit: Accepted, 4.Bc4oDXA56m Benoni: 3.d5 d6 4.Nc3 g6 5.e4 Bg7 6.Bd3}Li70E00r Catalan: 4.Nf3 Bb4+zlLE18h Queen's Indian: 7.Nc3 d5 8.Ne5 c6z{bPC12o French: MacCutcheon, 8.Qg4 g6 9.Bd3g ʜNC11w French: Burn, 6.Bxf6 gxf6 7.Nf3 b6Z#sXC19k French: Winawer, 6...Ne7 7.Nf3 Bd7 8.a4Ve)E66m King's Indian: Fianchetto, Yugoslav Panno, Main Line, 12.Bb2 e5R1^E12e Queen's Indian: Petrosian, 4...c5 5.d5 Ba6QMw+a2E14a Queen's Indian: 4.e3Q) 'لvD32v QGD Tarrasch: 5.Nf3 Nc6 6.e3 Nf6 7.Be2 cxd4 8.Nxd4 Bd6JތkTB73 Sicilian: Dragon, Classical, 8.O-O O-OD24g QGA: 4.Nc3 c5 5.d5 e6 6.e4%-JpE32n Nimzo-Indian: Classical, 4...O-O 5.a3, 6...b6 7.Bg5t*gXA41u Neo-Old Indian: Modern, 3.Nc3 Bg7 4.Nf3jg`D10a Diemer-Duhm Gambit (DDG) vs. Slav/Caro-Kann $\J4A12 English: Torre Defence;W_YBB03o Alekhine: Exchange, 5...exd6VC HB17i Caro-Kann: Steinitz, 5.Ng5 Ngf6N2BD29c QGA: Classical, 8...Bb7 9.a4Et.z>A25 English: Closed, Hort, 7.d38&my{&A10 English: 1...g6 7vC48f Four Knights: Spanish, Classical, Bardeleben VariationvM̒LB01t Scandinavian: Scandinavian Gambit2T"`A35i English: Symmetrical, Four Knights, 4.e3 e5f 0D35a QGD: 3.Nc3 Nf6 4.e3LA43j Old Benoni: Clarendon Court, 3.c4NKXB27s Sicilian: Accelerated Pterodactyl, 4.c4!izA94 Dutch: Stonewall, Botvinnik, 8.Ba3 Bxa3 9.Nxa3 Qe7 10.Qc1m_`DA46u Torre Attack: 3...c5 4.e3 Qb6~>yB&hNA95 Dutch: Stonewall, 7.Nc3 c6 8.b3 Qe8z+FVA73 Benoni: Classical, 9.O-O Na6 10.Nd2 Nc7wlZ$"C21 Danish Gambitn0BC46h Three Knights: 3...Bb4 4.Nd5TmkBTA89 Dutch: Leningrad, Main Line, 7.Nc3 Nc6RbUBE97a King's Indian: Mar del PlataP.`mTA70m Benoni: Classical, 8.h3 O-O 9.Bd3 Na6NNpD44r Semi-Slav: Botvinnik, Main Line, 12.g3 c5 13.d5 Qb6KuLC41s Philidor: Improved Hanham, 6.dxe5F 8D37f QGD: 4.Nf3 Be7 5.e3 O-OB4 %ޞZB00c Basman's Creepy-Crawly System (as Black)Au^ UBC41b Philidor: Steinitz Variation5*<A11 English: Caro-Kann Defence'uE"D25b QGA: 4.e3 c5&0kRB23s Sicilian: Closed, Grand Prix, 3...g6 ڑFA^D42g QGD: Semi-Tarrasch, 7.Bd3 Main Line, 10.a34ץ3RZA35d English: Symmetrical, 2.Nc3 Nc6 3.Nf3 g6 M4X8B28c Sicilian: O'Kelly, 3.d4t'sZC84m Spanish: Closed, Centre Attack, 7.Re1 b5m|!4A03 Bird: 1...d5 2.Nf3 Nf6_YiFD74 Neo-Grnfeld, 6.cxd5 Nxd5 7.O-Op׮B>B70j Sicilian: Dragon, 6.Be2 a6|fB31q Sicilian: Rossolimo, 3...g6 4.O-O Bg7 5.Re1 e5`Dv6B00f Owen Defence: 2.d4 Bb7"m\ļ4D70 Neo-Grnfeld: 3.Nf3 d5~P"VE38d Nimzo-Indian: Classical, 4...c5 5.dxc5B6,LD40i QGD: Semi-Tarrasch, 5.e3 Nc6 6.a3bDC07p French: Tarrasch, Open, 4.exd5 Qxd5, Main Line, 10.Qxd4 Qxd4ɡ(M:ZB01p Scandinavian: 2...Qxd5, Main Line, 8.Nd5Ɋ'zPC10p French: Rubinstein, 7.Bd3 c5 8.dxc5Wt9DA58i Benko Gambit: Accepted, 7.Nf3b dD39i QGD: Ragozin, Vienna, 6.e4 c5 7.Bxc4, 8...Qa5FkCZA09j Reti: Advance, 3.g3 c5 4.Bg2 Nc6 5.d3 e5 h.A54 Old Indian: 5.g3 g6#pa4D10d Slav: Exchange, 4.Nf36xOIB85 Sicilian: Scheveningen, Classical, Main Line, 9...Nc6 10.a4 Bd72 }FE94q King's Indian: 7.O-O Nbd7 8.d5`F3iDA27 English: Three Knights, 3...d6뎼HB37a Sicilian: Maroczy Bind, 5...Bg7v^(4DB55 Sicilian: Prins, Venice Attack^ijD30c QGD: 3.g3yC7ThA75 Benoni: Classical, 9.O-O a6 10.a4 Bg4 11.Bf4 Re8i`G~B84 Sicilian: Scheveningen, Classical, 7.O-O Be7 8.f4 Qc7 9.Kh1h˩PB94g Sicilian: Najdorf, 6.Bg5 Nbd7 7.Bc4g?)w<B25p Sicilian: Closed, 6.f4 e6PK×\E20 Nimzo-Indian: Romanishin, 4...c5 5.Nf3 Ne45oDA15 English: Anglo-Indian, 2.g3 g6-9ZE05s Catalan: Open, Classical, 8.Qxc4, 10.Bd2(?:1XC33 KGA: Lesser Bishop's (Tartakower) Gambit&o\&8C61c Spanish: Bird's, 4.Nxd4"-d>C00g French: Chigorin Variation+-BA85 Dutch: 2.c4 Nf6 3.Nc3 g6 4.f3C85p Spanish: Closed, Exchange, 7.d3 Nd7 8.Nbd2 O-O 9.Nc4 f6 10.Nh4~E]zC57c Two Knights: Traxler, 5.Nxf7 & 6.Kf1, Menovsky Variation\ITA74 Benoni: Classical, 9.O-O a6 10.a4 Nbd7s;;yTE73w King's Indian: Averbakh, 6...h6 7.Be3l+4A27 English: Three Knights ^z $A45f Indian: 2.Nc3LdC49d Four Knights: Nimzowitsch (Paulsen) VariationmB7ylC39 KGA: Kieseritsky, Brentano Defence, Caro VariationByG\^C41w Philidor: Improved Hanham, Sozin Variation*t.D21j QGA: 3.Nf3 c5 4.e3: POHB23l Sicilian: Closed, 2...Nc6 3.Bb560a`D33f QGD Tarrasch: Swedish, 7.Bg2 Bb4 8.O-O Nge7v PC99c Spanish: Closed, Chigorin, 13...Bd7Ͱ rE65g King's Indian: Fianchetto, Yugoslav, Exchange, 9.Be3x{0бVB59f Sicilian: Boleslavsky, 7.Nb3 Be7 8.O-O2\RC@A46q Indian: London, 3...c5 4.c3^HBB10i Caro-Kann: English Variation^hC92n Spanish: Closed, Zaitsev, 11.Nbd2 Bf8 12.d5 Nb8}|jE74i King's Indian: Averbakh, 6...c5 7.d5 a6 8.a4 Qa5YS1*PA19 English: Mikenas, Sicilian Variation`+LC16j French: Winawer, Advance, 4...Ne7U^qbC42s Russian Game: Classical, 6.Bd3 Be7 7.O-O Nc6|e͎VA55j Old Indian: 5.e4 Be7 6.Be2 c6 7.O-O a6|7:<A02 Bird: Batavo Polish Attacky(VFE53 Nimzo-Indian: Main Line, 6...c5rd9 A04 Reti: 1...g6kk9/RL>C40a Open Game: Damiano Defenceb1,W~B49k Sicilian: Taimanov, 6.Be3 a6 7.Be2 Nf6 8.O-O Bb4 9.Na4 O-OQ{16D31d QGD: Alatortsev, 4.Bf4N[>XB19h Caro-Kann: Classical, Spassky VariationH-D^B09u Pirc: Austrian, 5...c5 6.Bb5+ Bd7 7.e5 Ng4G#^D28g QGA: Classical, 7.Qe2 b5 8.Bd3 cxd4 9.exd4Eɲ M޴JE00e Queen's Pawn: Neo-Indian, 3...b6%Ǫ4SU:A20 English: King's, 2.g3 Nf6"uB\E89i King's Indian: Smisch, Orthodox Main Line, 10.Qd2 a6 11.g4 h5 12.h3z:B42h Sicilian: Kan, 5.Bd3 Nf6HB85 Sicilian: Scheveningen, Classical, Main Line, 9...Nc6 10.a4 Qc7LlifD87c Grnfeld: Classical Exchange, 8...c5 9.Be3 Qa5ëfD85x Grnfeld: Modern Exchange, 8.Be3 O-O 9.Rc1 Qa5)'?8D11n Slav: Slav-Reti with b3PW z>.A07 Reti: KIA, YugoslavƜ,&:D41c QGD: Semi-Tarrasch, 6.g3NA93 Dutch: Stonewall, Botvinnik, 7...c60Xj13B06c ModernR^I^C55x Two Knights: Max Lange, Marshall Variation' N&tpE43 Nimzo-Indian: Nimzowitsch, 5.Nf3 Bb7 6.Bd3 O-O 7.O-OyxzDD41p QGD: Semi-Tarrasch, 6.e3 cxd4Ó}t=4B08b Pirc: Classical, 5.h31+1JC88c Spanish: Closed, Noah's Ark Trap ʵ'*A46c Neo-Benoni: 3.e312 rHB00k Owen Defence: 3.Bd3 e6 4.Nf3 c5VKo*A00m Van Geet: 1...d5C%<<E12d Queen's Indian: PetrosianV\B82 Sicilian: Scheveningen, 6.f4 Nc6 7.Be3 Qc7@9G)JC02f French: Advance, Ruisdonk Gambit˫$.uTB91l Sicilian: Najdorf, 6.g3 e5 7.Nde2 Be7qE )RD20i QGA: 3.Nc3d+ZZ A04 Reti: 1...c5%}H DD02f Queen's Pawn: 2.Nf3 Nc6 3.Bf40*&D13a Slav: Exchangel& A04 Reti: 1...b5XsݙZD61 QGD: Orthodox, Rubinstein, 7.Qc2 c5 8.Rd1>/s4A46f Neo-Benoni: 3.g3 cxd4hlbJPE95d King's Indian: 7.O-O Nbd7 8.Re1 Re80K>B17p Caro-Kann: Steinitz, 5.Bc4|7eް>A44d Old Benoni: Czech, 3.c4 d6zM6A24 English: Bremen, 3...g6p+rB27p Sicilian: Accelerated Pterodactyl, 4.dxc5 Qa5+ 5.Nc3mU8.RE41 Nimzo-Indian: 4.e3 c5 5.Bd3 Nc6 6.Ne2m1̇4A46p Indian: London SystemYwXHDD85d Grnfeld: Exchange, 5.e4 Nxc3K [ND00u Blackmar-Diemer: Weinspach DefenceGEpг:D13e Slav: Exchange, 5.Nc3 a6G=ހQ pB09n Pirc: Austrian, 5...O-O 6.Bd3 Na6 7.O-O c5 8.d5 Bg4CGt%WDE61j King's Indian: Smyslov SystemC<-HE18e Queen's Indian: 7.Nc3 d5 8.cxd5C>' rRA28 English: Four Knights, 4.e3 Bb4 5.Qc2= /_Y8C37 KGA: Double Muzio Gambit/SRhpRD95e Grnfeld: 5.e3 O-O 6.Qb3 c6 7.Bd2 e6'@]XE71g King's Indian: Makagonov, 5...O-O 6.Bg5%`C57g Two Knights: Fegatello (Fried Liver) Attack K)`B12t Caro-Kann: Advance, 4.Nf3 e6 5.Be2 c5 6.O-OSB36l Sicilian: Maroczy Bind, 5...Nf6 6.Nc3 d6 7.Be2 Nxd4 8.Qxd4 Bg7 9.Bg5 O-O# <D30h QGD: Tarrasch without Nc3VjƦ1VE10i Neo-Indian: Blumenfeld/Benoni, 4.e3 b6*KipB99r Sicilian: Najdorf, Main Line, 10.g4 b5 11.Bxf6 Nxf6<@B70k Sicilian: Dragon, 6.Be2 Bg7кu pE64b King's Indian: Fianchetto, Yugoslav, Early ExchangebdM_FHD90 Grnfeld: Three Knights ExchangeĪ `zD32h QGD Tarrasch: von Hennig-Schara Gambit, 7.Qxd5 Nc6 8.Nf3-A=`D10n Slav: Winawer Countergambit Accepted, 6.Bd2oA,A45k Trompowsky 2...g6n@B47h Sicilian: Taimanov, 6.g3 a69~ƶoNE90g King's Indian: Zinnowitz VariationHC05v French: Tarrasch, Closed, 7.Ne2~lkFA20 English: King's, 2.g3 Nc6 3.Bg2ON<A53 Old Indian: Ukranian, 4.e3a ULB46c Sicilian: Taimanov, 5...a6 6.Nxc6{K}FD46h Semi-Slav: Chigorin, 7.Qc2 O-Of`0A10 English: Anglo-DutchS6YBC57i Two Knights: Fritz VariationUݗXB84 Sicilian: Scheveningen, Classical, 7.Be3sbc5jC55b Two Knights: 4.O-O Gambit, Rosentreter Variationl`BE91g King's Indian: 6.Be2 c5 7.d5cDَCVC62 Spanish: Old Steinitz, 4.d4 exd4 5.Qxd4`G\dE48 Nimzo-Indian: 4.e3 O-O 5.Bd3 d5 6.Ne2 c5 7.O-O_dE`C70 Spanish: Schliemann Deferred, 5.d4 exd4 6.e5W5NFDD90 Grnfeld: Schlechter, ExchangeV ګ FE80l King's Indian: Smisch, 5...c6S:^B02l Alekhine: Mokele Mbembe (Bcker) VariationSDeDE41 Nimzo-Indian: Hbner, 8.O-O e5RzP2E60f King's Indian: 3.Nf3P0_#\D52j QGD: Cambridge Springs, Bogoljubow, 8.Qc2O\CRVC00t French: KIA, Reversed Philidor, 4...b6E$BD}pHC25p Vienna: 2...Nc6 3.f4 exf4 4.Nf3C#)q~C67v Spanish: Open Berlin, 5.d4 Nd6 Queenswap, 9.Nc3 Ke8 10.Rd1B,CY^rB79b Sicilian: Dragon, Yugoslav, Old Main Line, 12.h4 Ne596lB45o Sicilian: Taimanov, Four Knights, 6.Ndb5 d6 7.Bf48hwTR.@C70 Spanish: Schliemann Deferred7G)YtC07m French: Tarrasch, Open, 4.exd5 Qxd5 5.Ngf3 cxd4 6.Bc42G:C45l Scotch: Mieses, 8.c4 Ba6UyDD95g Grnfeld: Botvinnik VariationhRB09c Pirc: Austrian, Ljubojevic Variation22A10 English: Myers Gambit&k ^A90 Dutch: Dutch-Indian (Nimzo-Dutch) Variation vO+Ay,A47 Neo-Queen's Indian Y\|rA33l English: Symmetrical, Two Knights, 5.Nc3 Nc6 6.g3 a6K<rB51u Sicilian: 3.Bb5+ Nc6 4.O-O Bd7 5.Re1 Nf6 6.c3 a6 7.Bf1 Bg4 8.h3C03a French: Tarrasch, 3...dxe49.|D99f Grnfeld: Russian, Smyslov, Main Line, 9...Nb6 10.Rd1 Nc65)|E11w Bogo-Indian: Nimzowitsch, 5.g3 Nc6 Main Line, 8...a5 9.e4iXXE13o Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.e3 g5 8.Bg3 Ne4 9.Qc2 Bxc3+6BpE14s Queen's Indian: 4.e3 Bb7 5.Bd3 c5 6.O-O cxd4 7.exd4R 94D26h QGA: Classical, 6.Nc3⌃<A00l Van Geet: Tbingen Gambitk6A12 English: Bled VariationwZ<&D51 QGD: 4.Bg5 Nbd7v;2A54 Old Indian: 4.Nf3 Nc6oî2D34h QGD Tarrasch: 9.dxc5] 6fE62v King's Indian: Fianchetto, Uhlmann/Szabo, 9.e4Y3LX@B10b Caro-Kann: Breyer VariationVq ýTB18j Caro-Kann: Classical, 6.Bc4 e6 7.N1e2H%|\B27n Sicilian: Accelerated Pterodactyl, 4.dxc5H`lE76h King's Indian: Four Pawns Attack, 6.Nf3 Na6 7.Be2Aw} $lE14p Queen's Indian: 4.e3 Bb7 5.Bd3 d5 6.O-O Bd6 7.Nc3; hPƙ ZB36g Sicilian: Maroczy Bind, 5...Nf6 6.Nc3 d64*/R@C02o French: Advance, Euwe, 6.a3.uv,B20 Sicilian: 2.d3 Nc6-kE2C>B13c Caro-Kann: Exchange, 4.Nf3)A)VC47l Four Knights: Belgrade Gambit, 5...Nb4$XC58a Two Knights: Morphy Variation (5...Na5)fBA56d Benoni: 2...c5 3.e3 g6 4.Nc35,TA94 Dutch: Stonewall, Botvinnik, 8.Ba3 Bd7H]p~E68e King's Indian: Fianchetto, Classical, 8.e4 exd4 9.Nxd4 Re8 ÁVVX@A46s Torre Attack: Wagner Gambit9yJD00w Blackmar-Diemer: Ziegler Defenceni+52D45k Semi-Slav: 6.Qc2 Bd6`UXB09q Pirc: Austrian, 5...c5 6.dxc5 Qa5 7.Bd372D09 QGD: Albin, 5.g3 Nge7eE13p Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.e3 g5 8.Bg3 Ne4 9.Qc2 Bxc3+ 10.bxc3 d6SS"D20e QGA: 3.e3 e5ѮEBB02d Alekhine: Scandinavian, 3.e56ɮf=>C51 Evans Gambit: Mayet DefenceH?mVC12d French: MacCutcheon, Advance VariationuPp,8A10 English: 1...b6 2.Nc3 e6ӕbfE31h Nimzo-Indian: Leningrad, Main Line, 7.e3 Bxc3+M7HA18 English: Mikenas, Flohr, 7.d4 c5pcFJC17m French: Winawer, Swiss VariationcITD47f Semi-Slav: Meran, Capablanca, 8...Bb7i$ b&C41c Philidor: 3.d4(qءPA49 Neo-King's Indian: Fianchetto Systemv2|LB22q Sicilian: Alapin, 2...Nf6, 5.Qxd4kZXK4C60i Spanish: Alapin, 4.c3juڇPB13o Caro-Kann: Panov-Botvinnik, 4...Nf6h:%rE92v King's Indian: Petrosian, Stein, Main Line, 10...Qe8dшpD59e QGD: Tartakower, 8.cxd5 Nxd5 9.Bxe7 Qxe7 10.Rc1 Bb7_̔hB98i Sicilian: Najdorf, Browne, 10.O-O-O Nbd7 11.Qg3WŁs>mbC06n French: Tarrasch, Closed, 8...f6 9.exf6 Nxf6E8y}rE71l King's Indian: Makagonov, 5...O-O 6.Bg5 Na6 7.Bd3 e5@,iTB36d Sicilian: Maroczy Bind, 5...Nf6 6.Nc37ӃhTC49l Four Knights: Symmetrical, 7.Bg5 Bxc32pDYU2D12i Slav: 4.e3 Bf5 5.Nc3+<3\C98e Spanish: Closed, Chigorin, 12...Nc6 13.d5)zX,lqzB14n Caro-Kann: Panov-Botvinnik, 5...e6 6.Nf3 Be7 7.cxd5 Nxd5I>? _vE35 Nimzo-Indian: Classical, Noa, Exchange, 6.Bg5 h6 7.Bxf6e(ZC78k Spanish: 5.O-O b5 6.Bb3 Bc5 7.c3 d6 8.d4v8{PD41n QGD: Semi-Tarrasch, 6.e4, Main LineWLP,A02 Bird: Hobbs Gambit(6D21a QGA: Ericson VariationV82B07c Pirc: 2.f4 Nf6 3.Nc3ʫGzC06p French: Tarrasch, Closed, 8...f6 9.exf6, 11...Qb6 12.Nc3U!.pB^C93 Spanish: Closed, Smyslov, 10.d4 Re8 11.Nbd2 c:A00l Van Geet (Dunst) OpeningهnJB10s Caro-Kann: Two Knights Variation*>TE80f King's Indian: Smisch, 5...e5 6.Nge2;V:E15t Queen's Indian: 4.g3 Bb7P^nE76r King's Indian: Four Pawns Attack, 6.Nf3 c5 7.d5 e6+yкzB66e Sicilian: Richter-Rauzer, 7...a6 8.O-O-O Nxd4 9.Qxd4 Be7 ';BVB84 Sicilian: Scheveningen, Classical, 7.a4dSZ1E77 King's Indian: Four Pawns Attack, 6.Be2 c5 7.d5 e6 8.Nf3 exd5 9.exd5Ʊҷj>rB39e Sicilian: Maroczy Bind, Breyer, 8.Qxg4 Nxd4 9.Qd1 e5a-alA33d English: Symmetrical, Two Knights, 5.Nc3 Nc6 6.e3X֪s\E88a King's Indian: Smisch, Orthodox, 7.d5 c6;MbPA16 English: Anglo-Indian, 2.Nc3 g6 3.g36TA82 Dutch: Staunton Gambit, 4.f3 d5 5.fxe4",(zB65c Sicilian: Richter-Rauzer, 7...Be7, 9.f4 Nxd4 10.Qxd4 Qa56f:\B11d Caro-Kann: Two Knights, 3...Bg4 4.h3 Bxf3VlxRnC11m French: Steinitz, Boleslavsky, 7...cxd4 8.Nxd4 Qb6g\hE63k King's Indian: Fianchetto, Panno, 8.h3 Rb8 9.e4w ,|\B82 Sicilian: Scheveningen, 6.f4 Nc6 7.Be3 Be7u_^E85a King's Indian: Smisch, Orthodox VariationsPH0abB57h Sicilian: Sozin, Benko, 7.Nxc6 bxc6 8.O-O g6rΔ>C40p Latvian Gambit: 3.Bc4 fxe4r)DB43d Sicilian: Kan, 5.Nc3 b5 6.Bd3mrRRD25m QGA: Janowski-Larsen, 6.h3 Bh5 7.Nc3k{*A46b Indian: 2.Nf3 b5cR0A10 English: Anglo-Dutchb!y;bE21 Nimzo-Indian: Nimzo-Queen's Hybrid, 5.Qc2 Bb7b`XtB49e Sicilian: Taimanov, 6.Be3 a6 7.Be2 Nf6 8.a3 Be7 9.O-O\9BA23 English: Bremen, Keres SystemSzJD12d Slav: 4.e3 Bf5 5.cxd5 cxd5 6.Qb3IL BB12i Caro-Kann: Advance VariationDvuNA41g Neo-Old Indian: Wade Defence, 3.c4C9lVE63c King's Indian: Fianchetto, Panno, 8.e4>YCnDC64d Spanish: Classical, 4.c3 Nge7=tfE25 Nimzo-Indian: Smisch, Keres, Romanovsky, 9.Nh3:)ةhJC10f French: Rubinstein, Ellis Gambit856D63 QGD: Orthodox, 7.Rc1 b60Ug54TD46e Semi-Slav: Chigorin, 7.e4 dxe4 8.Nxe4)3w8E60f King's Indian: 3.Nf3 d6"gp8JB56b Sicilian: Open, 2...d6, 5.Nc3 e5!@ o8B41g Sicilian: Kan, 5.c4 Qc7=<B27j Sicilian: Hungarian, 3.d4R$1:A26 English: Botvinnik System=3FC09e French: Tarrasch, Open, 7.dxc5`]'2A40s Queen's Pawn: Modern1HD02t Queen's Pawn: 3.g3 c6 4.Bg2 Bg4Ľ4A82 Dutch: Staunton Gambit $x^<D55e QGD: 6.Nf3 b6 7.cxd5 exd5 grmhrC43g Russian Game: Modern Attack, 3...Nxe4 4.Bd3 Nc6 5.d5R#K,D80 Grnfeld: 4.e3 Bg7GLHD35i QGD: Exchange, 5.Bg5 Nbd7 6.Nf3r+4>:B42c Sicilian: Kan, 5.Bd3 Qb6p$.D20k QGA: 3.Nc3 a6 4.a4u~FE30 Nimzo-Indian: Leningrad, 4...c5i1LC90e Spanish: Closed, Pilnik VariationTC33 KGA: Bishop's Gambit, Steinitz Defence.D02r Queen's Pawn: 3.g3aP߾XA78 Benoni: Classical, Main Line, 10.Nd2 Na6ކVqNbB46d Sicilian: Taimanov, 5...a6 6.Nxc6 bxc6 7.Bd3qe5\E91x King's Indian: 6.Be2 Bg4 7.Be3 Nfd7 8.Rc1IfrFyXE26 Nimzo-Indian: Smisch, O'Kelly Variation=%ZXvE61y King's Indian: Smyslov System, 5...O-O 6.e3 Nbd7 7.Be2`̺fE84g King's Indian: Smisch, Panno Main Line, 9.Nc1+y NE15t Queen's Indian: 4.g3 Bb7 5.Bg2 Qc8}Y `FA55i Old Indian: 5.e4 Be7 6.Be2 O-O{LB01m Scandinavian: 2...Qxd5, Main Lines56tDA43u Old Benoni: Schmidt, 3.e4 Nf6n.4\A66 Benoni: Mikenas Attack, 9.Nb5 dxe5 10.Nd6+RyF@RD43x Semi-Slav: Moscow, Main Line, 11.Rc1L tE03 Catalan: Open, 5.Qa4+ Nbd7 6.Qxc4 c5 7.Nf3 a6 8.Qc2 b6B <bC55x Two Knights: Max Lange, Rubinstein Variation>^0z!JA86 Dutch: Leningrad, 4.Nf3 Bg7 5.Nc3)F1<C11f French: Steinitz, 5.f4 c5^ 6A13n English: Wimpey System>;:U6C00a French: Bird VariationL;p8B33g Sicilian: Pelikan, 7.a4c7Heq\E19d Queen's Indian: Old Main Line, 9.Qxc3 Be4fB58l Sicilian: Boleslavsky, 7.Nf3 h6 8.O-O Be7 9.h3 K'3^B38e Sicilian: Maroczy Bind, 6.Be3 Nf6 7.Nc3 d6wbE93 King's Indian: Petrosian, Main Line, 8.Bg5 h6E97o King's Indian: Mar del Plata, Bayonet Attack, 9...Nh5 10.Re1iwS/`E08n Catalan: Closed, 7.Qc2 c6 8.b3 b6 9.Rd1 Ba6*2'PD41t QGD: Semi-Tarrasch, 7.Bc4 Main Line^ NAjE37 Nimzo-Indian: Classical, Noa, Main Line, 7.Qc2 c5y2>w($D20j QGA: 3.Nc3 e6ژ}7VE41 Nimzo-Indian: 4.e3 c5, Hbner VariationفSuiHC41o Philidor: Nimzowitsch Variation&?dC98d Spanish: Closed, Chigorin, Rauzer, 14.Nf1 Be6ڋ6EHE12b Queen's Indian: Miles Variation+YlB32v Sicilian: Lowenthal, Kalashnikov, 6.c4 Be7 7.N1c3AWf2`E25 Nimzo-Indian: Smisch, 5...c5 6.f3 d5 7.cxd51UNE28 Nimzo-Indian: Smisch, 5...O-O 6.e3c| &JB02g Alekhine: Scandinavian, ExchangeFc4E17b Queen's Indian: 6.Nc3y[ DA15 English: Anglo-Indian, 2.g3 e6j8',~B84 Sicilian: Scheveningen, Classical, 7.O-O Be7 8.f4 Qc7 9.Be3f].VD80 Grnfeld: Stockholm, Taimanov, 5...Nxc3U$g6 LD95d Grnfeld: 5.e3 O-O 6.Qb3 c6 7.Bd2U94(B10a Caro-Kann: 2.f4Na4BB29c Sicilian: Nimzowitsch, 3.Nc3I}x`E67h King's Indian: Fianchetto, Classical, 8.Qc2E =k~!FB51n Sicilian: 3.Bb5+ Nc6 4.O-O Bd7;`RC02s French: Advance, Milner-Barry Gambit8(}2E10d Neo-Indian: 3.Nf3 a61|C$ְ4D00u Blackmar-Diemer: 4.f3+^VfTD19i Slav: Dutch, 8...O-O 9.Qe2 Nbd7 10.e4#ʞ!.D00b Queen's Pawn: 2.c3onxA10 English "FdD46j Semi-Slav: Chigorin, 7.Qc2 Main Line, 9...Qe7_R_fA40g Queen's Pawn: English Defence, Hartlaub Gambitj!\B56m Sicilian: Open, 2...d6, 5.Nc3 Nc6 6.f3 e5=*¢rB81m Sicilian: Scheveningen, Keres, 6...h6 7.h4 Nc6 8.Rg1s>C17l French: Winawer, 5.a3 cxd4h/FD52d QGD: Cambridge Springs, 7.cxd5&5®`B70s Sicilian: Dragon, 6.Be2 Bg7 7.O-O O-O 8.Bg5xSBpE99 King's Indian: Mar del Plata, Benko Attack, 11...Kh8\afE28 Nimzo-Indian: Smisch, 5...O-O 6.e3 c5 7.Bd3 b6̂KxA14 English: Neo-Catalan Declined, 5...O-O 6.b3 c5 7.Bb2 Nc6ҋI5JA06 Reti: Nimzowitsch-Larsen, 2...Bg4LVkB\A88 Dutch: Leningrad, Main Line, 7.Nc3 c6 8.b3=SfC05u French: Tarrasch, Closed, Nunn-Korchnoi Gambit]OBD33i QGD Tarrasch: Swedish, 9.Ne5Si\04A12 English: Torre Defence#qs8B07y Pirc: Chinese Variation@dJC65n Spanish: Berlin, Beverwijk, 5.c3V\jquXA17 English: Anglo-Indian, 2.Nc3 e6 3.Nf3 d5SeVeNfE12s Queen's Indian: Petrosian, 6.cxd5 Nxd5 7.e3 g6g,A47 Neo-Queen's Indian9Հ]JD85t Grnfeld: Modern Exchange, 8.Be3)T0HC42e Russian Game: Italian Variation$zJxbC94b Spanish: Closed, Breyer, Matulovic Variation1@C44p Ponziani: 3...Nf6 4.d4 Nxe4"t.KBD00b Queen's Pawn: 2.c3 Nf6 3.Bg5Q :D77e Neo-Grnfeld, 6.O-O dxc4~u0&dB51r Sicilian: 3.Bb5+ Nc6 4.O-O Bd7 5.Re1 Nf6 6.c3|>#0A57c Benko Gambit: 4.Nd2r M^C63o Spanish: Schliemann, 4.Nc3 fxe4 5.Nxe4 Nf6qQ{[brB14g Caro-Kann: Panov-Botvinnik, 5...g6, Main Line, 8.Be2b#")N>E09a Catalan: Closed, Main Linea%NC69k Spanish: Exchange, Gligoric, 8.Nb3]srAx>C89g Spanish: Marshall, 12.Bxd5Q#.8ElA32 English: Symmetrical, Two Knights, 5.Nc3 Bb4 6.Qb3H1N&D50 QGD: 4.Bg5 dxc4H_PDC64m Spanish: Classical, 4.O-O Qf6HIt(Y|fB80j Sicilian: Scheveningen, English Attack, 7...b5FnD46p Semi-Slav: Chigorin, 7.O-O O-O 8.e4 dxc4 9.Bxc4 e5> =JA43q Old Benoni: Neo-Benko, 4.Bg5 Ne4=BA13m English: Agincourt Variation8,} lA78 Benoni: Classical, Main Line, 10.Nd2 Na6 11.f4 Nc75C$BB50k Sicilian: 2.Nf3 d6 3.Nc3 Nf6*j RD09 QGD: Albin, 5.g3 Be6 6.Nbd2 Qd7 7.Bg2z݀FB40t Sicilian: Pin, Jaffe Variation<bE97f King's Indian: Mar del Plata, Bayonet AttackZE50 Nimzo-Indian: 4.e3 O-O 5.Nf3 c5 6.Bd3 Nc6U):D30x QGD: 3.Nf3 Nf6 4.Bg5 Be7QCt86A24 English: Bremen, 3...g60fD62 QGD: Orthodox, Rubinstein, 7.Qc2 c5 8.cxd5 exd5#VC42f Russian Game: Boden-Kieseritsky Gambit:(C40e Elephant GambitًIB13z Caro-Kann: Panov-Botvinnik, 5...Nc6, Normal Variation, 8.c5 O-O 9.Bb5fҀXB08d Pirc: Classical, Spassky System, 6...a6km8\A91 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nf3 d5z}TnA59q Benko Gambit: 7.e4, Main Line, 11...Nbd7 12.h3 Qa5|]A65y Benoni: Smisch, 8.Bg5 h6 9.Be3 O-O 10.Qd2 a6 11.a4 Re8 12.Nge2 Nbd78_`D41h QGD: Semi-Tarrasch, 6.g3, Main Line, 9.Nxd5(iPD34l QGD Tarrasch: 9.dxc5 Bxc5 10.Bg5 d4`@B28a Sicilian: O'Kelly Variationd}HE33 Nimzo-Indian: Classical, 4...Nc6LJ7CFB58b Sicilian: Boleslavsky, 6...Bd7,yrhB00q Nimzowitsch Defence: 2.Nf3 d6 3.d4 Nf6 4.Nc3 g6srB84 Sicilian: Scheveningen, Classical, 7.O-O Qc7 8.f4 Nc6qrb%XB38d Sicilian: Maroczy Bind, 6.Be3 Nf6 7.Nc3f7oVB45f Sicilian: Taimanov, Four Knights, 6.a3d^C56o Two Knights: Classical, Moller, 10.Bd2 Bb4_Md>D85e Grnfeld: Exchange, 7.Bb5+VQg<A00r Polish: Tartakower GambitU1dC40u Latvian Gambit: 3.Nxe5 Qf6 4.d4 d6 5.Nc4 fxe4PtZ \PB33d Sicilian: Pelikan/Sveshnikov, 6.Nf3JaX>A56j Benoni: Bronstein's GambitEn &DA13u English: Neo-Catalan Accepted?+a}HZD14m Slav: Exchange, 8.Bd3 Main Line, 12.Rfc1>H{}FD13f Slav: Exchange, 5.Nc3 a6 6.Ne57h"9FD07q QGD: Chigorin, 3.Nc3 Nf6 4.Nf36g`PZC56i Two Knights: Classical, Yurdansky Attack1r78NC36 KGA: Scandinavian, Modern Variation!JA48g Neo-King's Indian: London System s`B12u Caro-Kann: Advance, 4.Nf3 e6 5.Be2 c5 6.Be3Ӝ@VB94h Sicilian: Najdorf, 6.Bg5 Nbd7 7.Bc4 e64M;XC13f French: Classical, Tartakower Variation ($PC21 Centre Game: Maroczy Defence, 3.dxe5 m?,A02 Bird: Swiss GambitqDE94k King's Indian: Glek, 8.Re1 c6r(LQJA55o Old Indian: Main Line, 8.Qc2 Re8".BjC43r Russian Game: Modern Attack, 3...Nxe4, Main Linep;v@B05m Alekhine: Modern, Main Line{u(`D37o QGD: Classical, 5...O-O 6.e3 c5 7.dxc5 Bxc5 JmE[HB29d Sicilian: Nimzowitsch, 3.Nc3 d5߼ZB15g Caro-Kann: Gurgenidze: 4.e5 Bg7 5.f4 Nh6}'ELV2A10 English: 1...b6 2.Nc3 $6'2A51d Budapest: FajarowiczmvC84h Spanish: Closed, Centre Attack, Basque Gambit AcceptedNXהpB13v Caro-Kann: Panov-Botvinnik, 5...Nc6, Herzog Defence4'jA69k Benoni: Four Pawns, Main Line, 10.e5: 12.Bg5 Qb6ij_/DB27e Sicilian: Hungarian Variation} ' bD52h QGD: Cambridge Springs, Rubinstein VariationbN46C40r Latvian Gambit: 3.Nxe5/[h@C88d Spanish: Closed 7...d6 8.c3{L4C60r Spanish: Cozio, 4.O-OGϋdE12t Queen's Indian: Petrosian, Kasparov, 7...Nxc3r]BB83 Sicilian: Scheveningen, 6.Be278B07r Pirc: Sveshnikov (4.g3)upbB84 Sicilian: Scheveningen, Classical, 7.O-O Nbd7~ ưهZD28l QGA: Classical, 7.Qe2 b5 8.Bb3 Nc6 9.Nc3x%yFA22 English: King's, 2.Nc3 Nf6 3.e4spi\B68 Sicilian: Richter-Rauzer, 7...a6, 9.f4 Be7fUDn$D04e Colle: 3...g6]Vjw9xD86 Grnfeld: Classical Exchange, Simagin Improved, 9.O-O e5Xv-LA07 Reti: KIANx\D33a QGD Tarrasch: 6.g3 (Schlecter/Rubinstein)Ki\b^A87 Dutch: Leningrad, Main Line, 7.Nc3 Qe8 8.b3KEuVE91m King's Indian: Kazakh Variation, 7.O-OHD/JB24 Sicilian: Closed, 3.g3 g6, 5.Nge2Hx3l 8D12i Slav: 4.e3 Bf5 5.Nc3 e6A5u8XE80n King's Indian: Smisch, 5...c6 6.Be3 a66QU`>C51 Evans Gambit: Morphy Attack2 \C12i French: MacCutcheon, Tartakower Variation)<\o:E17b Queen's Indian: 6.Nc3 d5'GHD97o Grnfeld: Russian, Prins, 8.Be2!w9zE11s Bogo-Indian: Nimzowitsch, 5.g3 Nc6 6.Nc3 Bxc3 7.Bxc3 Ne4!(av/>A08 Reti: KIA, French Variation b NRE52 Nimzo-Indian: Main Line, 6...b6 7.O-O3b -dpE65e King's Indian: Fianchetto, Yugoslav, 7.O-O Nc6 8.h3 -BA57v Benko Gambit: Zaitsev, 8.Bf4QE:A57d Benko Gambit: 4.Nf3 bxc4^D85u Grnfeld: Modern Exchange, 8.Be3 Qa5 9.Qd2hN"A50a Indian: 2.c4S=DC47l Four Knights: Belgrade Gambito^TB76c Sicilian: Dragon, Yugoslav, 8.Qd2 Nc6KUT<C00p French: KIA 2.d3 d5 3.Nd2@o~|B47y Sicilian: Taimanov, 6.Be2 a6 7.O-O Nf6 8.Kh1 Nxd4, 10.Qd3Ě<A43v Old Benoni: Schmidt, 6.h3ʙW/8D43p Semi-Slav: Moscow, 7.g3{TE15c Queen's Indian: 4.g3 Bb4+ 5.Bd2 Bxd2+P XRC03j French: Tarrasch, 3...Be7 4.Ngf3 Nf6F;5\B31p Sicilian: Rossolimo, Gurgenidze Variation1#PC78j Spanish: 5.O-O b5 6.Bb3 Bc5 7.c3 d6bpp|B35i Sicilian: Accelerated Fianchetto, Modern, 7.Bc4 O-O 8.Bb3%HE07 Catalan: Closed, 6...Nbd7 7.Nbd2|-lE25 Nimzo-Indian: Smisch, Keres, Romanovsky VariationbehE76n King's Indian: Four Pawns Attack, 6.Nf3 c5 7.d5TdRC42n Russian Game: Milner-Barry Variation70O8CZE94r King's Indian: 7.O-O Nbd7 8.d5 Nc5 9.Qc2*,B35r Sicilian: Accelerated Fianchetto, Modern, 7.Bc4 O-O 8.Bb3 d6 9.f3 Bd7SBA43t Old Benoni: Schmidt, 3.e4 g6eMfD85m Grnfeld: Modern Exchange, 8.Rb1 O-O 9.Be2 Qa5x-@B^E74b King's Indian: Averbakh, 6...c5 7.dxc5 Qa5y懒9RB82 Sicilian: Scheveningen, 6.f4 a6 7.Be3wAntE93 King's Indian: Petrosian, Main Line, 8.Bg5 h6 9.Bh4 g5w{b(FC25k Vienna: 2...Nc6 3.Bc4 Bc5 4.d3nb"\A91 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nf3 d6i<\jE84l King's Indian: Smisch, Panno Main Line, 9.h4 b5hWC}dD86 Grnfeld: Classical Exchange, Simagin ImprovedWKj}6A42c Modern: c4 PterodactylWX馕\E91i King's Indian: 6.Be2 c5 7.d5 e6 8.O-O Re8Uc'=:A43h Old Benoni: 2.d5 e6 3.c4U!OVC15g French: Winawer, 4.Bd3 dxe4 5.Bxe4 Nf6P TE41 Nimzo-Indian: Hbner, 8.e4 e5 9.d5 Ne7K(WRB25t Sicilian: Closed, 6.f4 e6: 9.Be3 Nd4CЅ|@A63 Benoni: Fianchetto, 9...Nbd78=r*C41a Philidor Defence8JdbBC68l Spanish: Exchange, 5.O-O Bd6#U=B36j Sicilian: Maroczy Bind, 5...Nf6 6.Nc3 d6 7.Be2 Nxd4 8.Qxd4 Bg7 9.O-O"~>@[PB71 Sicilian: Dragon, Levenfish, 6...Bg7Ob3:D96 Grnfeld: Russian, 6...a6rKi8C80h Spanish: Open, 6.d4 Be7kb8#pE51 Nimzo-Indian: 4.e3 O-O 5.Nf3 d5 6.Bd3 Nc6 7.O-O dxc44+:D34r QGD Tarrasch: 9.Bg5 cxd4{c1ZhB46e Sicilian: Taimanov, 5...a6 6.Nxc6 bxc6 7.Bd3 d5 6^E42 Nimzo-Indian: 4.e3 c5 5.Ne2 cxd4 6.exd4 O-OK]g&ZD07w QGD: Chigorin, 3.Nc3 dxc4 4.Nf3 Nf6 5.e4ї@A17 English: Nimzo-English, 4.g3\ j2B41d Sicilian: Kan, 5.Be2|R؏FD21k QGA: 3.Nf3 c5 4.e3 cxd4 5.Bxc4oyq3PVC47j Four Knights: Scotch, Bogoljubow, 5.d5=MSܴ,JC32 KGD: Falkbeer, 4.d3 Nf6 5.Nc3 Bb4揢2yXE07 Catalan: Closed, 6...Nbd7 7.Nc3 c6 8.Qb3IWB66p Sicilian: Richter-Rauzer, 7...a6 8.O-O-O h6 9.Be3 Be7 10.f4 Nxd4ع9_nRE12k Queen's Indian: Petrosian, 5.Nc3 Ne4NJC28h Vienna: 3.Bc4 Nc6 4.d3 Bc5 5.Bg5Ӟ [B35o Sicilian: Accelerated Fianchetto, Modern, 7.Bc4 O-O 8.Bb3 d6=f&{JC78j Spanish: 5.O-O b5 6.Bb3 Bc5 7.c3/Q3QVB33e Sicilian: Pelikan, Haberditz Variation! zB58p Sicilian: Boleslavsky, 7.Nf3, 9.Re1 O-O 10.h3 Be6 11.Bf1lO5dD41f QGD: Semi-Tarrasch, 6.g3, Main Line, 9.e4 Nb6LS4p\B63d Sicilian: Richter-Rauzer, 7.Qd2 Qb6 8.Nb3%5 'NE62l King's Indian: Fianchetto, 6...Nc6M^BC32 KGD: Falkbeer, Reti Variationa¨elB83 Sicilian: Scheveningen, Modern, 9.f4 Bd7 10.Nb3 a6~ВRcZD61 QGD: Orthodox, Rubinstein, 7.Qc2 h6 8.Bh4i %_DC52 Evans Gambit: Lasker's DefenceQvB78t Sicilian: Dragon, Yugoslav, Old Main Line, 11.Bb3 Rfc8R@fE82e King's Indian: Smisch, Fianchetto, 7.Bd3 Nfd7?L:C26d Vienna: Smyslov, 3...Nc6w~8,A47 Neo-Queen's IndianukXiXC41o Philidor: Nimzowitsch, Locock VariationtD{hE23 Nimzo-Indian: Spielmann, 4...c5 5.dxc5 Nc6 6.Bg5r/D62 QGD: Orthodox, Rubinstein, 7.Qc2 c5 8.cxd5, Main Line, 11.Bd3 g6oY|i>C44r Scotch: Cochrane Variationl<pPB44q Sicilian, Taimanov, Szen, 7.N1c3 a6lnQ2"D20e QGA: 3.e3 e5lM':D95a Grnfeld: 5.e3 O-O 6.Qb3jiFI/jE81h King's Indian: Smisch, 5...O-O 6.Bg5 c5 7.d5 a6_;-RC04c French: Tarrasch, Guimard, Main LineUIFA52h Budapest: Rubinstein VariationP,rR_<D85b Grnfeld: Exchange, 5.Bd2Kx5F'NC77g Spanish: Anderssen, 5...d6 6.c3 g6FgzE66f King's Indian: Fianchetto, Yugoslav Panno, 9...a6 10.Rb1C1CeC40a Open Game9)HZE21 Nimzo-Indian: Nimzo-Queen's Hybrid, 5.Qb38 XE81l King's Indian: Smisch, Byrne Variation3xVB98d Sicilian: Najdorf, Danner, 9.O-O-O Bd7!GQRE12j Queen's Indian: Petrosian, 5.Nc3 Be7 uTE16o Queen's Indian: Capablanca, 6...Bxd2+v:A43i Old Benoni: 2.d5 e6 3.c4922D08 QGD: Albin, 4.Nf3 Nc6UHE91h King's Indian: 6.Be2 c5 7.d5 e6nE!ggVA91 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nf3 ;$D80 Grnfeld: 4.g3~K|INB93d Sicilian: Najdorf, 6.f4 Nbd7 7.Be2v]oTC86e Spanish: Worrall Attack, 7...O-O 8.a4q9DA05 Reti: KIAŞ[JA87 Dutch: Leningrad, Main Line, 7.b3ƚwRA30p English: Symmetrical, Hedgehog, 7.b3[_lC89r Spanish: Marshall, Main Line, Pawn Push Variation=|'&D10h Slav: 3.e3 Nf6/JC77q Spanish: Wormald Attack, 5...Be7NY<E18d Queen's Indian: 7.Nc3 Na6Q`>c{nE62t King's Indian: Fianchetto, Uhlmann/Szabo Variation),q]zZB27t Sicilian: Accelerated Pterodactyl, 4.Nc3㈠vC48m Four Knights: Rubinstein, Exchange Variation, 8...Qe5+K^-NA43j Old Benoni: Clarendon Court, 3.Nc3*jB79a Sicilian: Dragon, Yugoslav, Old Main Line, 12.h4gdE93 King's Indian: Petrosian, Main Line, 8.Be3 Ng4V !^D68 QGD: Orthodox, Classical, Vidmar, 13...exd4}>8A06 Reti: Santasiere's follyzS+ hVB01y Scandinavian: Marshall, 4.c4 Nb6 5.Nc3y.fۦjA39n English: Symmetrical, Main Line 7.d4, 10.Qd3 Bf5v~DD43f Semi-Slav: Botvinnik, 5...Be7s($ZX"LC45w Scotch: Paulsen, Gunsberg DefencepfZE94n King's Indian: Glek, 8.Be3 Ng4 9.Ng5 Qe8]A D20a QGA: 3.Qa4+]&xHA30e English: Symmetrical, b6 System\^)!HD26g QGA: Classical, Early QueenswapT5ܷWhB59j Sicilian: Boleslavsky, 7.Nb3 Be7 8.O-O O-O 9.f4E)|Q^^E61h King's Indian: Fianchetto, Flohr Variation6f*RA17 English: Anglo-Indian, 2.Nc3 e6 3.Nf35_ߪ@B90k Sicilian: Najdorf, 6.Be3 e5*옾x\B78r Sicilian: Dragon, Yugoslav, Old Main Line#63cLLD47r Semi-Slav: Meran, Wade, Main Line .R3t>C42n Russian Game: Cozio/Lasker FX6C26l Vienna: Horwitz Gambit LD78f Neo-Grnfeld, 6.O-O c6 7.Nc3 dxc4`XlC43n Russian Game: Modern Attack, Trifunovic VariationX {(qVB29e Sicilian: Nimzowitsch, 3.Nc3 d5 4.exd5>hU#L.A00g Amar/Paris Openingنô:D24m QGA: Bogoljubow, 7.a4 e6yID99g Grnfeld: Russian, Smyslov, Main Line, 9...Nb6 10.Rd1 Nc6 11.d5 Ne5^K)ZA29 English: Four Knights, Main Line 6.O-O e4i<.fD10l Slav: Winawer Countergambit, 4.cxd5 cxd5 5.Nf3^{g2A53 Old Indian: Ukrainiany:|TC52 Evans Gambit: Sanders-Alapin VariationZ8D80 Grnfeld: 4.e3 Bg7 5.Qb3dqٽ A04 Reti: 1...c5 dC75 Spanish: Modern Steinitz, Rubinstein Variation.5JD23q QGA: Mannheim, Main Line, 10.Bg5rfL(A45e Indian: 2.c3 g6rio[zB11j Caro-Kann: Two Knights, 3...Bg4 4.h3 Bxf3 5.Qxf3 e6 6.d3a|Hq@D08 QGD: Albin, Alapin Variation]q7O2A09r Reti: Accepted, 3.e3[}O fD46r Semi-Slav: Chigorin, Main Line, 10...h6 11.Bc2Q\6A24 English: Bremen, 3...g6M?#]0D30m QGD: 3.Nf3 c6 4.Qc2L)B^A86 Dutch: Leningrad, 4.Bg2 Bg7 5.Nc3 O-O 6.Nh3G$hC48i Four Knights: Rubinstein, Henneberger VariationCWYHC40u Latvian Gambit: 3.Nxe5 Qf6 4.d4:׹ B37o Sicilian: Maroczy Bind, 6.Nc2 Nf6 7.Nc3 d6 8.Be2 O-O 9.O-O Nd7 10.Bd2 a532Kt^D72 Neo-Grnfeld, 5.cxd5 Nxd5 6.e4 Nb6 7.Ne2 e5.vIu^E69a King's Indian: Fianchetto, Classical, 9.h3,ig^4C24 Bishop's Opening: 3.d3)VinE62j King's Indian: Fianchetto, Kavalek/Bronstein, 8.e4S20jE86b King's Indian: Smisch, Orthodox, 7.Nge2 c6 8.d5sV>B02f Alekhine: Spielmann Gambit Ȯ:E90b King's Indian: 5.Nf3 Bg4#B58s Sicilian: Boleslavsky, 7.Nf3, 9.Re1 O-O 10.h3 Be6 11.Bf1 Nb8 12.a4~҅ϜXD00l Blackmar-Diemer Gambit (BDG): 2.e4 dxe4~Zn[EslA77 Benoni: Classical, Main Line, 10.Nd2 Nbd7 11.a4 a6~ɠ%HC41t Philidor: Improved Hanham 6.O-O~ȢpA47 Neo-Queen's Indian: Marienbad System, Berg Variation~ŗQ&:D15q Slav: Accepted, Alekhine~t?=CvD32u QGD Tarrasch: 5.Nf3 Nc6 6.e3 Nf6 7.Be2 Be7 8.dxc5 Bxc5~ND38i QGD: Ragozin, Westphalia Variation~(}`.D21f QGA: 3.Nf3 e6 4.e4~Ň5HA96 Dutch: Classical, 7.Nc3 a5 8.Qc2~e>C27g Vienna: Alekhine Variation~ARA37g English: Symmetrical, 5.Nf3 d6 6.O-O~;PpB21x Sicilian: Smith-Morra, 4.Nxc3 Nc6 5.Nf3 e6 6.Bc4 a6~քVwPA71 Benoni: Classical, 8.Bg5 h6 9.Bh4 g5~7JuLB02u Alekhine: Two Pawns Attack, 5.Bc4~]rGgDE91j King's Indian: 6.Be2 c5 7.O-O~ߡlZC11w French: Burn, 6.Bxf6 gxf6 7.Nf3 b6 8.Bc4~uATD06d QGD: Austrian, Rubinstein, 4.Nf3 cxd4~z^;dC84h Spanish: Closed, Centre Attack, 7.e5 Ne4 8.b4~Tbbw8C77p Spanish: Wormald Attack~~k D6C21 Danish Gambit: Accepted~w)PA16 English: Anglo-Indian, 2.Nc3 g6 3.g3~YK=F`tE93 King's Indian: Petrosian, Main Line, 8.Bg5 h6 9.Bh4 a5~WJMx:tC55r Two Knights: Modern, Main Line, 8.Bxc6 bxc6 9.O-O Bc5~SG.1LD43f Semi-Slav: Botvinnik (Anti-Meran)~H74]PD59c QGD: Tartakower, 8.cxd5 Nxd5 9.Bxe7~Dcz cn,C20 Open Game: 2.d3 d5~?udA~6D00f Hodgson Attack: 2...f6~59nD76i Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O Nb6 8.Nc3 Nc6 9.d5~1 2E13j Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.e3 Bxc3+ 8.bxc3 d6 9.Nd2~'::i6B25e Sicilian: Closed, 6.f4~&7=@Jd,A05 Reti: 1...Nf6 2.e3~kg-RD00h Hodgson Attack: 2...h6 3.Bh4 c6 4.e3~@^B15m Caro-Kann: Gurgenidze: 4.Nf3 Bg7 5.h3 dxe4~ D&ZE45 Nimzo-Indian: Nimzowitsch, 5.Ne2 Ba6 6.a3~ I6-]6D26c QGA: 4.e3 e6 5.Bxc4 a6~g)"S^PD36c QGD: Exchange, 6.Qc2 Be7 7.Nf3 Nbd7}=*fD50 QGD: Dutch-Peruvian, Prins, 6.Qxd4 Be7 7.e4 Nc6}7@j@C39 KGA: Allgaier, Walker Attack}DɮocrE11s Bogo-Indian: Nimzowitsch, 5.g3 Nc6 6.Nc3 Bxc3 7.Bxc3}R7!*D31p Semi-Slav: 4.Nf3}~Z?NoJE90n King's Indian: 5.Nf3 O-O 6.h3 e5}DPD45r Semi-Slav: 6.Qc2 Bd6 7.b3 O-O 8.Be2}$RA35b English: Symmetrical, 2.Nc3 Nc6 3.e3}&DB58c Sicilian: Boleslavsky, 6...a6}ޱwFB05j Alekhine: Modern, Flohr, 6.O-O}ad@A51f Budapest: Fajarowicz, 4.Nd2}Lϒ>jB61e Sicilian: Richter-Rauzer, Larsen, 7.Qd2 Rc8 8.f4} $Ͼ7DE07 Catalan: Closed, 6...Nbd7 7.b3}k4BB83 Sicilian: Scheveningen, 6.Be2}&BA58g Benko Gambit: Accepted, 7.f4}$dLA21 English: King's, 2.Nc3 d6 3.Nf3 g6}ND46m Semi-Slav: Chigorin, 7.Qc2 Main Line, 9...b5 10.Be2 Bb7 11.Rd1}:FA54 Old Indian: 5.g3 Be7, Main Line}?FC63e Spanish: Schliemann, 4.d3 fxe4}Լ^#`0B32i Sicilian: Lowenthal}s|@bB64c Sicilian: Richter-Rauzer, 7.Qd2 Be7, 9.f4 h6} BA00l Van Geet: Sicilian Variation}K1UJC22 Centre Game: Kupreichik Variation}պDC51 Evans Gambit Declined: 4...Be7}$2C34 KGA: Schallop Defence}D ƂTB81b Sicilian: Scheveningen, Keres, 6...e5}C~v:D15c Slav: Schting Variation}rtrdB99n Sicilian: Najdorf, Main Line, 10.g4 b5 11.Bd3}r;ZX'pE68k King's Indian: Fianchetto, Classical, 8.e4 c6 9.Rb1}d=}rfE97d King's Indian: Mar del Plata, Odessa Variation}c5iVDA41e Neo-Old Indian / Modern: 3.g3}_d0E60e King's Indian: 3.g3}]J.bC49p Four Knights: Symmetrical, Metger, 10.d4 Ne6}[SDJaGbD28n QGA: Classical, 7.Qe2 b5 8.Bb3 Nc6 9.Nc3 Be7}J'xC85o Spanish: Closed, Exchange, 7.d3 Nd7 8.Nbd2 O-O 9.Nc4 f6}CKLB52f Sicilian: 3.Bb5+ Bd7 4.Bxd7+ Qxd7}B;7RB74 Sicilian: Dragon, Classical, 9.Nb3 b6};8HN$B07f Pirc: 3.f3 e5}:P$kpB35f Sicilian: Accelerated Fianchetto, Modern, 7.Bc4 O-O}9A,)&D21b QGA: 3.Nf3 Nd7}'QFS8D16h Slav: Smyslov, 6.e3 Bg4}<0xB99c Sicilian: Najdorf, Main Line, Keres 10...b5 11.Bxf6 Nxf6 12.e5 Bb7}G*A51d Budapest: 3.dxe5}SYudC69h Spanish: Exchange, Gligoric, 6.d4 exd4 7.Qxd4}+آi `A32 English: Symmetrical, Two Knights, 5.Nc3 Bb4}3~u`E18s Queen's Indian: 7.Nc3 Ne4 8.Nxe4 Bxe4 9.Nh4|ukL0$ FA37q English: Symmetrical, 5.Nf3 e5|ӢPC81 Spanish: Open, Keres, Adam Variation|0;DD30o QGD: 3.Nf3 c6 4.Qc2 Nf6 5.Bg5|VR%PA11 English: Caro-Kann Defence, 3.g3 Bg4|@;BPA43j Old Benoni: Clarendon Court Defence|۲C43u Russian Game: Modern Attack, 3...Nxe4, Main Line, 7...Bd6 8.c4|܍HD81 Grnfeld: Early Russian, 5...Bg7|U}:E07 Catalan: Closed, 6...Nbd7|kN9VC47n Four Knights: Belgrade Gambit, 5...Be7|ͦ+FޠTB33x Sicilian: Pelikan, Sveshnikov, 11.Bd3|aQ)>C57j Two Knights: Fritz, 8.Nxf7|ܮ9zM9<C63c Spanish: Schliemann, 4.d4|Wi|LA18 English: Mikenas, French Variation|{zOg[=DA41p Neo-Old Indian: 2.c4 e5 3.Nf3|9.O2D02q Queen's Pawn: London|o*@qrB22u Sicilian: Alapin, 2...Nf6, 5.cxd4 d6 6.Nf3 Nc6 7.Bc4|<@LA00s Polish: 2...Bxb4 3.Bxe5 Nf6 4.Nf3|sf!(A56g Benoni: 3.d5 a6|}EZ'RA39c English: Symmetrical, Main Line 7.d4|wMNFS D10a Slav: 3.Bf4|pL]P)VLD97h Grnfeld: Russian, Alekhine, 8.e5|pKKR6RA40i Englund Gambit: 2.dxe5 Nc6 3.Nf3 Qe7|p<̴RgpC46l Three Knights: Steinitz, 4.d4 exd4 5.Nxd4 Bg7 6.Be3|UEm~2A40x Queen's Pawn: Modern|T*FFB01v Scandinavian: Portuguese, 4.f3|Q D65dE76c King's Indian: Four Pawns Attack, 5...c5 6.d5|JuE97i King's Indian: Mar del Plata, Bayonet Attack, 9...a5 10.bxa5|=En,zC06t French: Tarrasch, Closed, 8...f6 9.exf6, 11...O-O 12.Bf4|7bD$:C77e Spanish: Duras Variation|*/@FC47i Four Knights: Scotch Variation|$<2ZA59e Benko Gambit: 7.e4 Line, 9.Nf3 Bg7 10.h3|*˃<LC05p French: Tarrasch, Closed, 6...Nc6|O`Z>A19 English: Mikenas, 5.Nf3 Nc6|LE58 Nimzo-Indian: Main Line, 9.bxc3 b6| 6'-\B13v Caro-Kann: Panov-Botvinnik, 5...Nc6 6.Bg5|䪥|E52 Nimzo-Indian: Main Line, 6...b6 7.O-O Bb7 8.cxd5 exd5 9.a3| 9]dB15t Caro-Kann: Tartakower (Nimzowitsch) Variation|0Ɉ=HC92p Spanish: Closed, Zaitsev, 12.a3{ባ<C65j Spanish: Berlin, 4.d3 Bc5{UުdC41l Philidor: 3...exd4 4.Nxd4 Nf6 5.Nc3 Be7 6.Bc4{i~NwbB31e Sicilian: Rossolimo, 3...g6 4.Bxc6 dxc6 5.d3{~1&C20 Open Game: 2.d3{㦑d`ZB02h Alekhine: Scandinavian, Exchange, 4.Nxd5{>BA43o Old Benoni: Neo-Benko, 4.Bg5{`&A25 English: Closed{mZS.`B54j Sicilian: Prins (Moscow), 5...Nc6 6.c4 Nxd4{ʱۢFE41 Nimzo-Indian: 4.e3 c5 5.Bd3 Nc6{ĨuEJC50v Giuoco Pianissimo: Canal, 6...h6{E\"D25a QGA: 4.e3{WeA4B15p Caro-Kann: 3.Nc3 dxe4{y ЗBC53 Giuoco Piano: Close Variation{pjopB22h Sicilian: Alapin, 2...d5 3.exd5 Qxd5 4.d4 Nc6 5.Nf3{<BB53k Sicilian, Chekhover, 4...Nf6{ hb_P:E73f King's Indian: 5.Be2 O-O{âR0n(A56h Benoni: 3.d5 g6{YFξrLD74 Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O c5{9¬rdA80p Dutch: 2.Nc3 Nf6 3.Bg5 d5 4.Bxf6 exf6 5.e3 c6{(8A61 Benoni: Uhlmann, 7...Bg7{&pB52m Sicilian: 3.Bb5+, Sokolsky, 5...Nc6 6.Nc3 Nf6 7.O-O{j>j|fC13l French: Chatard-Alekhine, 6...Bxg5 7.hxg5 Qxg5{{1NRA43x Old Benoni: Schmidt, 6.Be2 O-O 7.O-O{z (^E73o King's Indian: Averbakh, 6...Nbd7 7.Qd2 e5{u&2D45f Semi-Slav: 5.e3 Nbd7{r޿2zA36y English: Symmetrical, Botvinnik System, 5...d6, 8.d3 Ne8{ol\HE05g Catalan: Open, Classical, 7.Ne5{nr{5NC95a Spanish: Closed, Breyer, 10.d4 Bb7{jp(NA58m Benko Gambit: Fianchetto, 9...Nbd7{f#ZD.D06m QGD: 2...Bf5 3.Nc3{c*1RC88e Spanish: Closed, Leonhardt Variation{bD~PC30m KGD: Classical, Svenonius Variation{bz!l@B90j Sicilian: Najdorf, 6.Be3 Ng4 7.Bg5 h6 8.Bh4 g5 9.Bg3 Bg7 10.Be2 h5{aߟLB31g Sicilian: Rossolimo, 3...g6 4.O-O{_m4ZC28j Vienna: 3.Bc4 Nc6 4.d3 Bc5 5.f4 d6 6.Nf3{R9yHA48o Neo-King's Indian: Torre Attack{PA"2NA17 English: Anglo-Queen's Indian, 4.g3{Lm(V<A68a Benoni: Four Pawns, 8.Nf3{JKRB53s Sicilian, Chekhover, 7.Nc3 Nf6 8.Bg5{I,EpBC39 KGA: Allgaier, Cook Variation{=8OAbE62r King's Indian: Fianchetto, Simagin Variation{=o?~D39g QGD: Ragozin, Vienna, 6.e4 c5 7.e5 cxd4 8.Qa4+ Nc6 9.O-O-O{<ݬ$q^D44i Semi-Slav: Botvinnik, Alatortsev Variation{7N66>ZD81 Grnfeld: Early Russian, 5...Bg7 6.e4 O-O{5G#JB70g Sicilian: Dragon, 6.Bc4 Bg7 7.h3{/1'GlA32 English: Symmetrical, Two Knights, 5.Nc3 Bb4 6.Nb5{.HVA40j Queen's Pawn: Bogoljubow-Miles Defence{*J2D30v QGD: 3.Nf3 Nf6 4.Bg5{'Zݥ[6B32a Sicilian: 2...Nc6 3.d4{gxdHNB95n Sicilian: Najdorf, 6...e6 7.Qf3 h6z.n;A"~E90x King's Indian: 5.Nf3 O-O 6.h3 c5 7.d5 e6 8.Bd3 exd5 9.exd5z P[<D14a Slav: Exchange, 6.Bf4 Bf5zNHD4TC33 KGA: Bishop's Gambit, McDonnell Attacky" ~C91i Spanish: Closed, Bogoljubow, 10.d5 Na5 11.Bc2 c6 12.h3 Bc8yӻ8D11n Slav: Slav-Reti with b3yqRE51 Nimzo-Indian: 4.e3 O-O 5.Nf3 d5 6.Bd3yӄp`C42v Russian Game: Classical, Chigorin VariationyqF԰BC11g French: Steinitz, 6.dxc5 Nc6y͆`p .D32a QGD Tarrasch: 4.e3yGRB00k Owen Defence: 3.Bd3 e6 4.Nf3 c5 5.c3yj8L$PD41d QGD: Semi-Tarrasch, 6.g3, Main Liney4X!=0A10 English: 1...g6 2.g3yo_`B92h Sicilian: Najdorf, 6.Be2 e5 7.Nb3 Be7 8.O-OyVvC99d Spanish: Closed, Chigorin, 13...Bd7 14.Nf1 Rac8 15.Ne3yuLE07 Catalan: Closed, 6...Nbd7 7.Nc3 c6ymrhE35 Nimzo-Indian: Classical, Noa, Exchange, 6.Bg5 h6yJr,JA06 Reti: Nimzowitsch-Larsen, 2...Nf6yBYFVA97 Dutch: Ilyin-Zhenevsky, Winter, 8...Qh5ymjA97 Dutch: Ilyin-Zhenevsky, Winter, 8...Qg6 9.e4 fxe4y 2vB03m Alekhine: Four Pawns Attack, Ilyin-Zhenevsky VariationyfY18A85 Dutch: 2.c4 Nf6 3.Nc3 e6y~5BC20 Open Game: Portuguese, 2...c6yzLE21 Nimzo-Indian: Nimzo-Queen's Hybridyy;5PB76g Sicilian: Dragon, Yugoslav, 9.O-O-Oyy6jNhPC93 Spanish: Closed, Smyslov, 12.Nf1 Bd7yur:`B61g Sicilian: Richter-Rauzer, Larsen, Main Lineyr|fF|B68 Sicilian: Richter-Rauzer, 7...a6, 9.f4 Be7 10.Nf3 b5 11.e5yn[?x$&A51c Budapest: 3.d5ym"9bZE73x King's Indian: Averbakh, 6...h6 7.Be3 c5yaN`B46p Sicilian: Taimanov, 5...a6 6.Be2 Nge7 7.O-Oy^JC69n Spanish: Exchange, Gligoric, 8.Nb3 Queenswap, 9...Bg4 10.f3 Be6y]D XB17d Caro-Kann: Steinitz, 5.Nf3 Ngf6 6.Nxf6+y?3oZD25e QGA: Smyslov, 5.Bxc4 Bg7 6.O-O O-O 7.Nc3y<ț܋bB40p Sicilian: Open, 2...e6, 4.Nxd4 Nf6 5.Bd3 Nc6y:O'[zB94k Sicilian: Najdorf, 6.Bg5 Nbd7 7.Bc4 Qa5 8.Qd2 e6 9.O-O-Oy:8BC39 KGA: Kieseritsky, Rice Gambity8&Z<A11 English: Caro-Kann Defencey5~`N<A68b Benoni: Four Pawns, 9.Bd3y/+a,D94 Grnfeld: 5.e3 O-Oy-NA05 Reti: KIAy$9SwHLA45t Trompowsky: 2...Ne4 3.Bh4 c5 4.f3y!s=MTFC93 Spanish: Closed, Smyslov, 10.d3y8RDA36e English: Symmetrical, 3.g3 g6yzpB99w Sicilian: Najdorf, Modern Main Line 13.f5 Nc5 14.h4y ; ;|E97q King's Indian: Mar del Plata, Bayonet, 9...Nh5 10.Re1 Nf4y 㜟j,<B02r Alekhine: Chase Variationy mb!8*A03 Bird: 1...d5 2.g3yhE90s King's Indian: 5.Nf3 O-O 6.h3 e5 7.d5 Na6 8.Be3x.Y2D70 Neo-Grnfeld: 3.g3 d5x<6A46p Indian: London, 3...c5x68C40g Elephant Gambit: 3.exd5x=NC45g Scotch: Steinitz, 5.Nb5 Bb4+ 6.Bd2xB>B53r Sicilian, Chekhover, 7.Nc3x[G2B93t Sicilian: Najdorf, 6.f4 e5 7.Nf3 Nbd7 8.a4 Be7 9.Bd3 O-O 10.O-O Nc5xˎU^E49 Nimzo-Indian: Botvinnik, 7...dxc4 8.Bxc4 c5xkFz|TC50i Giuoco Piano: Three Knights Variationx}So\D57 QGD: Lasker Defence, Main Line, 11.Qb3 Rd8xN?Yz^E71m King's Indian: Makagonov, 5...O-O 6.Bg5 c5xFVAvS`D98h Grnfeld: Russian, Smyslov, Keres VariationxJJE03 Catalan: Open, Alekhine Variationxۗ[T0BA58h Benko Gambit: Accepted, 7.g3xq-Ei`B74 Sicilian: Dragon, Classical, 9.Nb3 Be6 10.f4x/<؁xD86 Grnfeld: Classical Exchange, Simagin Improved, 9.O-O b6x~B38j Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 b6 9.O-O Bb7 10.f3x_wVHA43p Old Benoni: Neo-Benko, 4.Bg5 d6x8A20 English: King's, 2.g3 g6xR^:-D30f QGD: 3.Nf3x_od=LA42w Modern: Averbakh, Queenswap, 7.f4x¹b}lpE08o Catalan: Closed, 7.Qc2 c6 8.b3 b6 9.Rd1 Ba6 10.Nbd2x5;pHC78s Spanish: Archangelsk, 7.c3 Nxe4xqB*ZE72 King's Indian: 4.e4 d6 5.g3 O-O 6.Bg2 Nc6xw^w`B77b Sicilian: Dragon, Yugoslav, Byrne Variationxuh108D02a Queen's Pawn: 2.Nf3 Bg4xlR<D13j Slav: Exchange, 5.Nc3 Nc6xi56FA50d Indian: Mexican Defence, 3.Nf3xatkQ>D44c Semi-Slav: Botvinnik, 6.e4xWK>򛞳\C58f Two Knights: Morphy, Bogoljubow VariationxVuș<E17g Queen's Indian: 6.Nc3 Ne4xV82rB01s Scandinavian: 2...Nf6 3.Bb5+ Bd7 4.Be2 Nxd5 5.d4 Bf5x=~lvDD57 QGD: Lasker Defence, Main Linex:I<LE12e Queen's Indian: Petrosian, 4...c5x5+UBB00j Owen Defence: 3.Bd3 e6 4.Nf3x/)&~^C66 Spanish: Closed Berlin, Bernstein Variationx)~jC50f Italian: Hungarian Defence, Tartakower Variationx 4j:A45p Trompowsky: 2...c5 3.Nc3x$}Ox^C17j French: Winawer, Bogoljubow, 5...Ne7 6.Nb5xZLA20 English: King's, 2.g3 Nf6 3.Bg2 c6x$LJA08 Reti: KIA, 2...c5, 3.Bg2 Nc6 4.d4xldB99v Sicilian: Najdorf, Modern Main Line 13.f5 Nc5x:5PcVC47k Four Knights: Scotch, Krause Variationx HE70k King's Indian: 4.e4 d6 5.Bd3 e5xGV(JE49 Nimzo-Indian: Botvinnik, 7...dxc4x/V6D11p Slav: Slav-Reti SystemxnQMBJA98 Dutch: Ilyin-Zhenevsky, 8.Qc2 Nc6x sD00m Blackmar-Diemer: Lemberger Countergambit, Rassmussen Attackx ٣I$D20i QGA: 3.Nc3 c5x ODE37 Nimzo-Indian: Classical, Noa, Main Line, 7.Qc2 c5 8.dxc5 Nc6x56D11m Slav: Slav-Reti Systemx`i¤vC69f Spanish: Exchange, Gligoric, 6.d4 Bg4 Queenswap, 9.Rd3w\ |D32w QGD Tarrasch: 5.Nf3 Nc6 6.e3 Nf6 7.Be2 cxd4 8.Nxd4 Bd6 9.O-O O-Owb **JA51i Budapest: Fajarowicz, 4.Nf3 Bb4+wqi4vC<B53p Sicilian, Chekhover, 7.c4w䈿}|8D01e Richter-Veresov: 3...g6wmHQ0A10 English: Anglo-DutchwJqtA45r Trompowsky: 2...c5 3.Bxf6 gxf6 4.d5 Qb6 5.Qc1 f5 6.e3w37vE59 Nimzo-Indian: Main Line, 9.bxc3 dxc4 10.Bxc4 Qc7 11.Be2wޠJXxA37y English: Symmetrical, 5.Nf3 e5 6.O-O Nge7 7.d3 O-O 8.a3wе/\n\E91m King's Indian: Kazakh Variation, 7.O-O c5w7WQ>A36j English: Symmetrical, 5.b3wB8B:D48a Semi-Slav: Meran, 8...a6wƄ>\bD30b Diemer-Duhm Gambit (DDG): Exchange Variationwù4h4W*A08 Reti: KIA, 2...c5wh+;@E20 Nimzo-Indian: Mikenas Attackwkէ:9.A00g Amar: Paris GambitwY1>RA37l English: Symmetrical, 5.Nf3 e6 6.O-OwQpbHA19 English: Mikenas, 5.Nf3 Nc6 6.d4w"ne@A97 Dutch: Ilyin-Zhenevsky, 8.b4wo2JTD51 QGD: Alekhine 4.Bg5 Nbd7 5.Nf3 c6 6.e4wgjZB21y Sicilian: Smith-Morra, 5.Nf3 d6 6.Bc4 a6ẁŦMbA41g Neo-Old Indian: Wade Defence, 3.c4 e5 4.dxe5wm P\C15p French: Winawer, Alekhine Gambit, 4...Nc6wو€NA22 English: Bremen, Smyslov, 4.Bg2 O-OwFdSrB38o Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 d6 9.O-O Nd7wWTvE08q Catalan: Closed, 7.Qc2 c6 8.b3 b6 9.Rd1 Bb7 10.Nc3 Rc8w^}~VE78 King's Indian: Four Pawns Attack, 7.Nf3w|.;=@B18i Caro-Kann: Classical, 6.Bc4wEsP,C47a Four Knights Gamewv9zHRD47d Semi-Slav: Meran, Capablanca, 8...b4wray->B25g Sicilian: Closed, 6.f4 Nf6w|ł>A87 Dutch: Leningrad, Main Linewud;NC93 Spanish: Closed, Smyslov, 10.d4 Re8wqQאdD77j Neo-Grnfeld, 6.O-O dxc4 7.Na3 Nc6 8.Nxc4 Be6we{ (OPA16 English: Anglo-Indian, 2.Nc3 c6 3.e4w^0`iPA43l Old Benoni: 2.d5 Nf6 3.Nf3 e6 4.Nc3wWRB05c Alekhine: Modern, Alekhine VariationwT+Pb|<>E11m Bogo-Indian: 4.Bd2 a5 5.g3wSiZD29g QGA: Classical, 8...Bb7 9.Rd1 Nbd7 10.e4wDvfKHC51 Evans Gambit: Ulvestad VariationwB3[ ŎhE75c King's Indian: Averbakh, 7.d5 e6 8.Nf3 h6 9.Be3w2s>^D50 QGD: Semi-Tarrasch, Old Pillsbury Variationw-4s۪E69y King's Indian: Fianchetto, Classical, 9.h3 Re8 10.Re1 exd4, 11...Nc5 12.Rb1w-߁7rtE60p King's Indian: Fianchetto without Nc3, 6...Nbd7 7.Qc2w,-5EB36q Sicilian: Maroczy Bind, 5...Nf6 6.Nc3 d6 7.Be2 Nxd4 8.Qxd4 Bg7 9.Be3 O-O 10.Qd2 Be6 11.O-Ow*l`~fC93 Spanish: Closed, Smyslov, 10.d4 Re8 11.Nbd2 Bf8w(KK-LD27e QGA: Classical, 6...a6 7.Bd3 Nbd7w&>9p؇VB24 Sicilian: Closed, 3.g3 g6, 5.d3 e6 6.f4w U4JJB02e Alekhine: Scandinavian, 3.e5 Ne4w 'TJD90 Grnfeld: Three Knights Variationw 7NRD41p QGD: Semi-Tarrasch, 6.e3 cxd4 7.exd4wwbX A00h Durkinv#,? %.D18e Slav: Dutch, 8.O-OvxfB13e Caro-Kann: Exchange, 4.Bd3vA]`B10m Caro-Kann: English, Exchange, 4...Nf6 5.Nc3vr? DC24 Bishop's Opening: Greco Gambitvw>?WtB13y Caro-Kann: Panov-Botvinnik, 5...Nc6, Normal VariationvuXY>!bRC14j French: Classical, Steinitz, 7...O-Ovoq2JdB13s Caro-Kann: Panov-Botvinnik, 5...Nc6 6.Nf3 Bg4vl{0N~*GTC58d Two Knights: Morphy, Polerio (6.Bb5+)vdG dB12h Caro-Kann: Gurgenidze/Modern: 3.Nd2 g6 4.Ngf3v^aeWJB53h Sicilian, Chekhover, 4...a6 5.c4vYzmlFB30e Sicilian: 2...Nc6 3.g3 e6 4.d3vWb0x) 6A04 Reti: Lisitsin DeferredvRU$JD07o QGD: Chigorin, Tartakower GambitvR!,TB82 Sicilian: Scheveningen, 6.f4 Nc6 7.Be3vKZ;ZC59j Two Knights: Main Line, Knorre VariationvF #OBC00q French: KIA 2.d3 d5 3.Nd2 c5v;!*DPA17 English: Anglo-Indian, 2.Nc3 e6 3.g3v5"~sTA16 English: Anglo-Grnfeld, 4.Nf3 g6 5.g3v4b ]hA70s Benoni: Classical, 8.h3 O-O 9.Bd3 a6 10.a4 Nbd7v25_'NB20 Sicilian: English, 2...Nc6 3.Nc3 g6v.!3~(D24k QGA: Bogoljubowv,/hB01z Scandinavian: Marshall, 4.c4 Nb6 5.Nf3 g6 6.Be2v+6c<B44c Sicilian: Taimanov, 5.Be2v+S,JD30b Diemer-Duhm Gambit (DDG): 4...f5v'xv@LNA50n Indian: Queen's Indian Acceleratedv%<@D21n QGA: 3.Nf3 c5 4.d5 e6 5.Nc3v:/.D91a Grnfeld: 5.Bg5 c6v4 :B02o Alekhine: Smisch Attackv TKrB19t Caro-Kann: Classical, Spassky, Main Line, 14.g3 Nxe4v ^-\QZD30b Diemer-Duhm Gambit (DDG): Duhm VariationvԕP:C40b Open Game: Greco Defencevv8uxNA42q Modern: Averbakh, 4...e5 5.Nf3 Nd7uNvB00r Nimzowitsch Defence: 2.Nf3 d6 3.d4 Nf6 4.Nc3 Bg4 5.Bb5usuZB13k Caro-Kann: Exchange, Rubinstein, 6...Bg4uKЖnQ D30d QGD: 3.cxd5uܾ?"\:A00q Polish: 1...d5 2.Bb2 Nf6uuvx{PE20 Nimzo-Indian: Romanishin, 6.Nxd4 O-OupaVD44p Semi-Slav: Botvinnik, Main Line, 12.g3uśvVD02c Queen's Pawn: London, Alapin VariationueW$B20 Sicilian: 2.g3u IWbC09k French: Tarrasch, Open, Main Line, 9.Nb3 Bb6ukŸtC67q Spanish: Open Berlin, 5.d4 Nd6 6.Bxc6 dxc6 7.dxe5 Nf5usxG{lC82j Spanish: Open, Motzko Attack, Nenarokov VariationuK S`E21 Nimzo-Indian: Nimzo-Queen's Hybrid, 5.Qb3 c5uۺ-KBD97a Grnfeld: Russian, 7.e4 Nfd7uq~jxC99m Spanish: Closed, Chigorin, 13...Nc6 14.Nb3 a5 15.Be3 a4u[s3(B08a Pirc: ClassicaluHD30i QGD: Tarrasch without Nc3: 5.g3uW~B78o Sicilian: Dragon, Yugoslav, Main Line, 12.h4 h5 13.Bg5 Rc5u|@刏RC96h Spanish: Closed, Chigorin, 11.d3 Nc6uu-Y)o~A70t Benoni: Classical, 8.h3 O-O 9.Bd3 a6 10.a4 Nbd7 11.O-O Re8uuc~<A90 Dutch: Dutch-Indian, 5.Nd2us+H+PE94v King's Indian: 7.O-O Nbd7 8.Be3 Ng4uoZ^E70s King's Indian: Accelerated Averbakh Systemui`X=tC39 KGA: Kieseritsky, Long Whip Defence, Jnisch Variationu^г fS*B10o Caro-Kann: 2.Nf3uH0kM\E11y Bogo-Indian: 4.Bd2 Bxd2+ 5.Qxd2 O-O 6.Nc3uEЂ:D10q Slav: 3.Nc3 dxc4 4.e4 b5u;6ux`D61 QGD: Orthodox, Rubinstein, 7.Qc2 h6 8.Bh4 c5u*LV*E99 King's Indian: Mar del Plata, 10.f3 f5 11.Nd3 Nf6 12.Bd2 f4 13.c5u"ڸ}@A99 Dutch: Ilyin-Zhenevsky, 8.b3uujLD37j QGD: Classical, 5...O-O 6.e3 Nbd7u L<:C03c French: Tarrasch, 3...b6t^fPA44t Old Benoni: Czech, 3.e4 d6 4.Nc3 a6ty2e:B24 Sicilian: Closed, 3.g3 g6t@9zjzB13u Caro-Kann: Panov-Botvinnik, 5...Nc6 6.Nf3 Bg4: Main Linet4+I>C40t Latvian Gambit: 3.Nxe5 Qf6t}f7`D69 QGD: Orthodox, Classical, 13.dxe5: 15.f4 Qe4t)Du2A40v Queen's Pawn: ModerntRB46n Sicilian: Taimanov, 5...a6 6.Be2 Nf6tE7@k.C45h Scotch: 4.Nxd4 Nf6th!^gDA59i Benko Gambit: 7.e4, Main LinetXB67b Sicilian: Richter-Rauzer, 7...a6, 9.Be2t*l|B34t Sicilian: Accelerated Fianchetto, Modern, 6.Be3 Nf6 7.Be2tgϠd\@A73 Benoni: Classical, 9.O-O Na6tq1\A90 Dutch: 2.c4 Nf6 3.g3 e6 5.Nf3 d5 6.Qc2 Bd6t~OCWk,A47 Neo-Queen's Indiant~l@LD16k Slav: Smyslov, 6.e4 Bg4 7.Bxc4 e6trFQdWtA22 English: Bremen, Reverse Dragon, 4.cxd5 Nxd5 5.Bg2 Nb6tqo"cFB22o Sicilian: Alapin, 2...Nf6 3.e5tj-` fD42i QGD: Semi-Tarrasch, 7.Bd3 Main Line, 10.a3 Bf6tf?mHB46b Sicilian: Taimanov, 5...a6 6.f4tdS5Vj`E75g King's Indian: Averbakh, 7.d5 e6 8.Qd2 exd5tN*!jE97y King's Indian: Mar del Plata, 9.Nd2 a5 10.a3 Bd7tL|BA80k Dutch: 2.Nc3 d5, Euwe GambittK{n1HB82 Sicilian: Scheveningen, 6.f4 Be7tD28s84C30j KGD: Classical, 3.Bc4t?U+#@B93b Sicilian: Najdorf, 6.f4 Nc6t">~*^E38g Nimzo-Indian: Classical, 4...c5 5.dxc5 Qc7tHyŪu^B56p Sicilian: Open, 2...d6, 5.Nc3 Nc6 6.Be3 e5tDs5@C32 KGD: Falkbeer, Morphy Gambitt Q#HD59f QGD: Tartakower, 8.cxd5 Nxd5 9.Bxe7 Qxe7 10.Rc1 Bb7 11.Nxd5tdrNA87 Dutch: Leningrad, Main Line, 5...d6sXda\LB30f Sicilian: 2...Nc6 3.g3 e6 4.d3 d5sVlnE03 Catalan: Open, 5.Qa4+ Nbd7 6.Qxc4 a6 7.Nf3 b5 8.Qc6s:XI>D46b Semi-Slav: Romih Variations |D89h Grnfeld: Classical Exchange, Main Line, Sokolsky, 16.Rb1sj[PC12k French: MacCutcheon, Lasker, 7.bxc3s>HC78u Spanish: Archangelsk, Main Lines䚫PA44s Old Benoni: Czech, 3.e4 d6 4.Nc3 g6sqf fA37n English: Symmetrical, 5.Nf3 e6 6.O-O Nge7 7.d3sBfjJA06 Reti: Nimzowitsch-Larsen, 2...Nf6sQfzB11i Caro-Kann: Two Knights, 3...Bg4 4.h3 Bxf3 5.Qxf3 e6 6.g3sBGX<C11u French: Burn, 6.Bxf6 gxf6s _rD19m Slav: Dutch, 8...O-O 9.Qe2 Nbd7 10.e4 Bg6 11.Bd3 Re8snbDJE73p King's Indian: Averbakh, 6...Na6s \@A08 Reti: KIA, 2...c5 3.Bg2 Nc6sEuIXC17o French: Winawer, Swiss, 6.b4 cxd4 7.Qg4s~s[fE94e King's Indian: 7.O-O exd4 8.Nxd4 Re8 9.f3 Nc6 10.Be3 Nh5 11.Qd2sMJB37d Sicilian: Maroczy Bind, 6.Nc2 d6s/qzfB03g Alekhine: Four Pawns Attack, Planinc Variations 'NE82a King's Indian: Smisch, Fianchettosz>C89d Spanish: Marshall, 11.Rxe5sosgRC63k Spanish: Schliemann, 4.Nc3 Nd4 5.Ba4sk)S>C54n Giuoco Piano: Greco Attacks`N8C44t Scotch: Relfsson GambitsZyG:TDB18p Caro-Kann: Classical, 6.h4 h6sV 82JC48h Four Knights: Rubinstein, 5.Nxe5sP IXE97v King's Indian: Mar del Plata, 9.Nd2 Nd7sOS#j.C54k Giuoco Piano: 6.e5sM 0D73 Neo-Grnfeld, 6.cxd5sK6E30 Nimzo-Indian: LeningradsJ.NNnE81n King's Indian: Smisch, 5...O-O 6.Be3 c5 QueenswapsIJ\XDD08 QGD: Albin, Janowski VariationsB)rHC85j Spanish: Closed, Exchange, 7.d3s43r`8D35l QGD: Exchange, 5.Bg5 c6s/%R(ZlPB71 Sicilian: Dragon, Levenfish, 6...Nc6s* )!@D18k Slav: Dutch, 8...Nbd7 9.Qe2sZ)rB:C65h Spanish: Berlin, 4.d3 d6sɾk 0D07b QGD: Chigorin, 3.e3sPXN5hE99 King's Indian: Mar del Plata, 10.f3 f5 11.Be3 f4s9:[_fA78 Benoni: Classical, Main Line, 10.Nd2 Na6 11.Re1sNPE05f Catalan: Open, Classical, 6.O-O O-Os maYBD45f Semi-Slav: Rubinstein Systems R'e \D30i QGD: Tarrasch without Nc3: 5.g3 Nc6 6.Bg2s $0A00o Grob Gambit: 2...c6snl@K2A85 Dutch: 2.c4 Nf6 3.Nc3rna"BA52c Budapest: Alekhine Variationr%Ţ/aZC09b French: Tarrasch, Open, 5.Ngf3 Nc6 6.Bb5r2r<A45p Trompowsky: 2...c5 3.dxc5rxnRB51o Sicilian: 3.Bb5+ Nc6 4.O-O Bd7 5.Re1r䃜+xdC99l Spanish: Closed, Chigorin, 13...Nc6 14.Nb3 a5r*N tE97g King's Indian: Mar del Plata, Bayonet Attack, 9...Kh8rFTtC69m Spanish: Exchange, Gligoric, 8.Nb3 Queenswap, 9...Bg4rTEdC84h Spanish: Closed, Centre Attack, Basque GambitrS:A70e Benoni: Classical, 8.Be2rhWLB91i Sicilian: Najdorf, 6.g3 e5 7.Nde2rf CfTE73q King's Indian: Averbakh, 6...Na6 7.h4rʩrNA40q Queen's Pawn: Keres Defence, 3.Bd2r\PD48m Semi-Slav: Meran, Reynolds, 10...e5rW]q7jB19r Caro-Kann: Classical, Spassky, Main Line, 13.Ne4re|D47p Semi-Slav: Meran, Wade, 9.O-O b4 10.Ne4 Be7 11.Nxf6+ Nxf6r*A02 Bird: SymmetricalrWy0RD12e Slav: 4.e3 Bf5 5.cxd5 cxd5 6.Qb3 Qc7rf [NA53 Old Indian: 3.Nc3 Nbd7 4.e4 e5 5.d5rبcf4D02s Queen's Pawn: 3.g3 c6r~ӷO6D11m Slav: Slav-Reti Systemrz8  pE99 King's Indian: Mar del Plata, Benko Attack, 11...Nf6rv!GiZdE37 Nimzo-Indian: Classical, Noa, Main Line, 7.Qc2ro|| RB33d Sicilian: Pelikan/Sveshnikov, 6.Nxc6rXIgU\E76d King's Indian: Four Pawns Attack, 5...O-OrWc&tE97l King's Indian: Mar del Plata, Bayonet Attack, 9...Nh5rNY:?`B90m Sicilian: Najdorf, 6.Be3 e5 7.Nb3 Be6 8.Qd2rHjɕP$C30a King's GambitrD87cF\A30v English: Symmetrical, Hedgehog, 9.b3 Nbd7r,MQ>C01d French: Exchange, 4.c4 Nf6r&4EtC95o Spanish: Closed, Breyer, Main Line, 15.a4 c5 16.d5 c4r"w/O hB49f Sicilian: Taimanov, 6.Be3 a6 7.Be2 Nf6 8.O-O b5rB4NB46h Sicilian: Taimanov, 5...a6 6.g3 d6r/ZWVD00f Hodgson Attack (Trompowsky vs. 1...d5)rBh~LA50e Indian: Mexican Defence, 3.Nf3 e6robB22q Sicilian: Alapin, 2...Nf6 3.e5 Nd5 4.d4 cxd4r S:ؠ<C64k Spanish: Classical, 4.O-Or eVC41p Philidor: Exchange, Rellstab Variationr וbNTE28 Nimzo-Indian: Smisch, 5...O-O 6.e3 c5rljpyXD23k QGA: Mannheim, 4...c6, 5.Qxc4 Bf5 6.Nc3r&h7:D33o QGD Tarrasch: 7.Bg2 cxd4q4؈3:E61d King's Indian: 4.Bg5 O-Oq`)XC89n Spanish: Marshall, Main Line, 14.g3 Qh3qΧc|>D24g QGA: 4.Nc3 c5 5.d5 e6 6.e4qq)zxLC60q Spanish: Cozio, Paulsen VariationqMD"D26a QGA: 4.e3 e6qƋ:^E63m King's Indian: Fianchetto, Panno, 8.d5 Na5q ק#JC52 Evans Gambit: Leonhardt VariationqX@dB01g Scandinavian: Anderssen Counterattack, 5.dxe5qSVs6D04i Colle: 3...c5 4.c3 Nc6q7V~E75e King's Indian: Averbakh, 7.d5 e6 8.Nf3 h6 9.Bh4 exd5 10.cxd5qw^4BC64n Spanish: Classical, 4.O-O d6qwNpCFD39a QGD: Ragozin, Vienna Variationqo Ֆ% LA73 Benoni: Classical, 9.O-O Bg4 10.h3qn\;\]PC99i Spanish: Closed, Chigorin, 13...Nc6qnO<VA63 Benoni: Fianchetto, 9...Nbd7 10.Nd2 Re8qk=*C01b French: Exchangeqi* D64 QGD: Orthodox, Rubinstein Attack, Grnfeld Variation, 9...h6qbrC85n Spanish: Closed, Exchange, 7.d3 Nd7 8.Nbd2 O-O 9.Nc4q`uF{HB46f Sicilian: Taimanov, 5...a6 6.g3qR.A43b Old Benoni: 2.dxc5qR9[A^B93p Sicilian: Najdorf, 6.f4 e5 7.Nf3 Nbd7 8.a4qG1 $"BB10i Caro-Kann: English VariationqC1״otH.D70 Neo-Grnfeld: 4.Bg2qC[-obE14s Queen's Indian: 4.e3 Bb7 5.Bd3 c5 6.O-O cxd4qA9U\C46l Three Knights: Steinitz, 4.d4 exd4 5.Nxd4q5ĬIsB45s Sicilian: Taimanov, Four Knights, 6.Ndb5 Bb4 7.a3 Bxc3+ 8.Nxc3 d5q0<ݳXB53t Sicilian, Chekhover, 7.Nc3 Nf6 8.Bg5 e6q+lD6HC54m Giuoco Piano: 6.cxd4 Bb4+ 7.Bd2q;>4D06m QGD: 2...Bf5 3.Nc3 e6q|e>D53b QGD: 4.Bg5 Be7 5.cxd5 Nxd5q y,A47 Neo-Queen's Indianq)4XA43x Old Benoni: Schmidt, 6.Be2 O-O 7.O-O e6pAT3NDB37c Sicilian: Maroczy Bind, 6.Nc2p 5#D42o QGD: Semi-Tarrasch, 7.Bd3 Main Line, 10.Re1 Nf6 11.a3 b6 12.Bc2pmS`JD27k QGA: Classical, Geller VariationptFA15 English: Anglo-Indian, 2.Nf3 g6pt܁bE11y Bogo-Indian: 4.Bd2 Bxd2+ 5.Qxd2 O-O 6.Nc3 d5pF͢xB78i Sicilian: Dragon, Yugoslav, Main Line, 12.h4 Nc4: 14.h5psfC64s Spanish: Classical, 4.O-O Nd4 5.Nxd4 Bxd4 6.c3pwlVA97 Dutch: Ilyin-Zhenevsky, Winter, 8...Qg6pGErB63w Sicilian: Richter-Rauzer, Podebrad, 10.f3 Rd8 11.Kb1p*6D11o Slav: Slav-Reti Systemp[ۃ"LC80u Spanish: Open, Bernstein, 11.Bxe6p#,7uvE74f King's Indian: Averbakh, 6...c5 7.d5 b5 8.cxb5 a6 9.a4paOD>C70 Spanish: Brentano VariationpanlA67h Benoni: Four Pawns, Taimanov, 9.Bd3 O-O 10.Nf3 a6p$VB50u Sicilian: 2.Nf3 d6 3.c3 Nf6 4.Be2 Nbd7puG<,D31j Semi-Slav: 4.cxd5p%ΣbB22d Sicilian: Alapin, 2...e6 3.d4 d5 4.exd5 exd5p[hZTE20 Nimzo-Indian: Romanishin, 4...c5 5.Nf3p,B30a Sicilian: 2...Nc6p~b})8A85 Dutch: 2.c4 Nf6 3.Nc3 d6pi㨐HopE73o King's Indian: Averbakh, 6...Nbd7 7.Qd2 e5 8.d5 Nc5pgVE7i4C65f Spanish: Berlin, 4.d3pE_mxxVD22l QGA: Alekhine, 4.e3 Bg4 5.Bxc4 e6 6.h3pAb|TC91b Spanish: Closed, Bogoljubow Variationp?|2?PB33d Sicilian: Pelikan/Sveshnikov, 6.Nb3p6fGNA70i Benoni: Classical, 8.Bd3 O-O 9.O-Op2czB96l Sicilian: Najdorf, 7.f4 Nbd7 8.Qf3 Qc7 9.O-O-O b5 10.Bd3p1A<&TD40j QGD: Semi-Tarrasch, 5.e3 Nc6 6.a3 Ne4p*O:eRE39c Nimzo-Indian: Classical, Pirc, 6.Nf3pAUHC62 Spanish: Old Steinitz, 4.d4 exd4pQ6'b.D20o QGA: 3.e4 Nf6 4.e5p&(vV.B38y Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 d6 9.O-O Bd7 10.Qd2 Nxd4, 12.f3 a5p =4D12c Slav: 4.e3 Bf5 5.cxd5p 9Sa3 bD46k Semi-Slav: Chigorin, 7.Qc2 Main Line, 9...a6p\DD12n Slav: 4.e3 Bf5 5.Nc3 e6 6.Nh4pU&A10 English: 1...g5p"mSED85x Grnfeld: Modern Exchange, 8.Be3 O-O 9.Rc1 Qa5 Queenswap, 12.Kxd2pܗ*E66n King's Indian: Fianchetto, Yugoslav Panno, Main Line, 12.Bb2 bxc4ok)fE98l King's Indian: Mar del Plata, 9.Ne1 Nd7 10.Nd3on%c&B07m Pirc: 3.Nc3 e5o}"EzA46z Torre Attack: 3...h6 4.Bxf6 Qxf6 5.e4 d6 6.Nc3 Nd7 7.Qd2oz@D10j Slav: Winawer Countergambito͘[ I0A10 English: Anglo-Dutchoͯ E.D92 Grnfeld: 5.Bf4 O-OoRNNE95c King's Indian: 7.O-O Nbd7 8.Re1 h6o.qNC92c Spanish: Closed, Kholmov Variationoٕ\\E44 Nimzo-Indian: Nimzowitsch, 5.Ne2 Ne4 6.Qc2oKb~#DE07 Catalan: Closed, 6...Nbd7 7.b3ohyA^A32 English: Symmetrical, Two Knights, 5.g3 Qb6o̥oNC41g Philidor: Hanham, Krause Variationo'bg6A56b Benoni: 2...c5 3.e3 e6oi DB00o Nimzowitsch Defence: 2.Nf3 d6oۼFD46q Semi-Slav: Chigorin, Main LineodD85q Grnfeld: Modern Exchange, 8.Rb1 O-O 9.Be2 cdoŸuy*D43d Semi-Slav: 5.Qb3o QPC99e Spanish: Closed, Chigorin, 13...Bb7o~y]ۏE97s King's Indian: Mar del Plata, Bayonet, 9...Nh5 10.Re1 f5 11.Ng5 Nf6o|[P`RD16r Slav: Bronstein, 6.Ne5 Bh5 7.f3 Nfd7o|CBA43t Old Benoni: Schmidt, 3.e4 g6om,[Cc^E38i Nimzo-Indian: Classical, 4...c5 5.dxc5 Na6olY9vHD10e Slav: Exchange, 4.Nc3 Nf6 5.Bf4olb݀V|C43l Russian Game: Modern Attack, 3...Nxe4 4.Bd3 d5 5.Nxe5 Be7ogs_ZC84h Spanish: Closed, Centre Attack, 7.e5 Ne4of?2HElE76i King's Indian: Four Pawns Attack, 6.Nf3 Na6 7.Bd3od4D21g QGA: 3.Nf3 e6 4.e3 c5od' (zTB44j Sicilian: Taimanov, 5.Nxc6 bxc6 6.Bd3o]"hA69j Benoni: Four Pawns, Main Line, 10.e5: 12.Bg5 f6oZ RA72 Benoni: Classical, 8.Be2 O-O 9.Bf4 a6oS E11w Bogo-Indian: Nimzowitsch, 5.g3 Nc6 Main Line, 8...a5 9.e4 e5 10.d5 Nb8oN_<A46u Torre Attack: 3...c5 4.e3oK$P+ND00l Blackmar-Diemer: Grosshans DefenceoIc\E44 Nimzo-Indian: Nimzowitsch, 5.Ne2 Ne4 6.Bd2oI)jD98k Grnfeld: Russian, Smyslov, 8.Be3 Nfd7 9.Rd1 Nc6o9YXD47o Semi-Slav: Meran, Wade, 9.O-O b4 10.Ne4o8 UXC82k Spanish: Open, St. Petersburg Variationo7١|THB95d Sicilian: Najdorf, 6...e6 7.Qe2o6pCTA69c Benoni: Four Pawns, Main Line, 10.Nd2o A\@D47h Semi-Slav: Meran, 8.Bd3 Bd6oFS"bC87o Spanish: Closed, Averbakh, 7.c3 O-O 8.h3 Bd7om~C05l French: Tarrasch, Closed, 5.f4 c5 6.c3 Nc6 7.Ndf3 Qb6 8.g3o 97:B50i Sicilian: 2.Nf3 d6 3.Nc3o E?ZunE18p Queen's Indian: 7.Nc3 Ne4 8.Bd2 f5 9.d5 Bf6 10.Rc1o b730A54 Old Indian: 5.g3 Be7o .9HE00b Queen's Pawn: Anti-Nimzo-Indiann>DB38z Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 d6 9.O-O Bd7 10.Qd2 Nxd4, 12.f3 a5 13.b3nvBDo2D25f QGA: Flohr VariationnUInE89b King's Indian: Smisch, Orthodox Main Line, 9...a6n%Dm7BB18h Caro-Kann: Classical, 6.N1e2n`%<A53 Old Indian: Ukranian, 4.e4n?ZpB27r Sicilian: Accelerated Pterodactyl, 4.dxc5 Qa5+ 5.c3nЏE0^LA70k Benoni: Classical, 8.h3 O-O 9.Bd3n't*bE70i King's Indian: Kramer, 5...O-O 6.Ng3 e5 7.d5ndv>C41n Philidor: Larsen VariationnwH=`B32w Sicilian: Lowenthal, Kalashnikov, Main Linent%52C25m Vienna: 2...Nc6 3.f4n{~HD60 QGD: Orthodox, Botvinnik, 7...c6n%DC65i Spanish: Berlin, 4.d3 d6 5.c3n\EIpC76 Spanish: Modern Steinitz, Bronstein, 7.O-O Bg7 8.Re1n?;eknE03 Catalan: Open, 5.Qa4+ Nbd7 6.Qxc4 c5 7.Nf3 a6 8.O-OnS4E32q Nimzo-Indian: Classical, 4...O-O 5.a3, 6...b6 7.Bg5 Bb7 8.f3nPEKND74 Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O Na6n[z<D35e QGD: Exchange, 5.Nf3 Nbd7nuXZ,NC45g Scotch: Steinitz, Berger VariationnqjMJnBC02j French: Advance, Wade, 6.Be2nnM\C42x Russian Game: Classical, Berger VariationnksomRE24 Nimzo-Indian: Smisch, 5...c5 6.f3 d5ni1~wJE18s Queen's Indian: 7.Nc3 Ne4 8.Nxe4nhZcFlDE61l King's Indian: 4.Nf3 O-O 5.g3nODHB20 Sicilian: English, 2...Nc6 3.Ne2nLh*A02 Bird: 1..Nf6 2.e3n=]o}PA49 Neo-King's Indian: Fianchetto Systemn5նd#?VC01t French: Exchange, Bogoljubow Variationn&ÏjE15t Queen's Indian: 4.g3 Bb7 5.Bg2 Qc8 6.O-O c5 7.d5na@LA46k Indian: 1.d4 Nf6 2.Nf3 e6 3.e3 c5n sC65l Spanish: Berlin, 4.O-O Be7mn љ`D67 QGD: Orthodox, Main Line, Alekhine VariationmzO':O`E28 Nimzo-Indian: Smisch, 5...O-O 6.e3 c5 7.Ne2mx] KE97k King's Indian: Mar del Plata, Bayonet Attack, 9...a5 10.Ba3 axb4 11.Bxb4 Nd7mwmRC31 KGD: Falkbeer, Milner-Barry VariationmwORB11b Caro-Kann: Two Knights, 3...Bg4 4.h3msP\*C11c French: Steinitzmc3SFA41e Neo-Old Indian / Modern: 3.Bf4m^}A EBA26 English: Closed, 5.d3 d6 6.e3mVrjmBC35 KGA: Cunningham, Euwe DefencemO4^E97s King's Indian: Mar del Plata, Bayonet, 9...Nh5 10.Re1 f5 11.Ng5 Nf6 12.Bf3 c6mFQRPA49 Neo-King's Indian: Fianchetto SystemmF4’yБ\C64s Spanish: Classical, 4.O-O Nd4 5.Nxd4 Bxd4mB=PWfB01h Scandinavian: 2...Qxd5 3.Nc3 Qa5 4.d4 c6 5.Nf3m@ e˰8B40s Sicilian: Pin Variationm?VB32l Sicilian: Lowenthal, 5...a6, Queenswapm7ųZC89m Spanish: Marshall, Main Line, 13.Re1 Qh4m4nR6JB98b Sicilian: Najdorf, 7...Be7 8.Qf3m2.#?A69l Benoni: Four Pawns, Main Line, 10.e5: 12.Bg5 Qb6 13.O-O Nxe5 14.Nxe5m,`T.`D82 Grnfeld: 4.Bf4 Bg7 5.e3 c5 6.dxc5 Qa5 7.Rc1m$IA\HB22b Sicilian: Alapin, 2...Nc6 3.Nf3mPPPC94d Spanish: Closed, Breyer, 10.d3 Nbd7m0wXD53j QGD: 4.Bg5 Be7 5.Nf3 h6 6.Bh4 O-O 7.Qc2ma-TC54o Giuoco Piano: Mller-Herzog Variationm+MJC77l Spanish: Centre Attack, 5...Nxd4m&PE62a King's Indian: Fianchetto VariationmǃuXB60i Sicilian: Richter-Rauzer, Larsen, 7.Be2m N33DB07z Pirc: Bayonet/Mariotti Attackm;^HC48g Four Knights: Rubinstein, 5.Be2lABB44d Sicilian: Taimanov, 5.c4 Nf6l1B06c ModernlHA2`D40q QGD: Semi-Tarrasch, 5.e3 Nc6 6.a3 a6 7.dxc5lԶW5v~E69v King's Indian: Fianchetto, Classical, 9.h3 Re8 10.Re1 exd4l\iQlhB92h Sicilian: Najdorf, 6.Be2 e5 7.Nb3 Be7 8.O-O Be6lɝ=QjVA38g English: Symmetrical, Main Line, 7.Rb1lLM95tC43i Russian Game: Modern Attack, 3...Nxe4 4.Bd3 d5 5.dxe5l,8>B00n Nimzowitsch Defence: 2.Nf3lhLC64o Spanish: Classical, 4.O-O d6 5.c3l-hzB34h Sicilian: Accelerated Fianchetto, Modern, 5...Nf6 6.Nxc6l6XD43i Semi-Slav: Botvinnik, 5...Be7 6.e3 Nbd7loZf(C41b Philidor: 3.Bc4lfH|HrD79n Neo-Grnfeld, Main Line, 10.f4 Nc6 11.Be3 Nb6 12.Bf2l[JD47m Semi-Slav: Meran, Wade VariationlvFB06s Modern: Pseudo-Austrian AttacklcL)LE14w Queen's Indian: 4.e3 Bb7 5.Bd3 c5 6.O-O Be7 7.b3 O-O 8.Bb2 cxd4 9.exd4lně <$NE11r Bogo-Indian: Nimzowitsch, 5.g3 Nc6lp^w!!RB42f Sicilian: Kan, Polugaevsky Variationl4VA90 Dutch: Dutch-Indian, Alekhine Variationl-8A70j Benoni: Classical, 8.h3lI5NND61 QGD: Orthodox, Rubinstein, 7.Qc2 h6l;9sV@C37 KGA: Salvio, Herzfeld GambitlgYNC41s Philidor: Improved Hanham, 6.Bxf7+lm<D12h Slav: 4.e3 Bf5 5.Bd3 Bxd3l|CLD36f QGD: Exchange, 6.Qc2 Be7 7.e3 O-Olxr/6>A28 English: Four Knights, 4.d4lvy2C40k Latvian Gambit: 3.d3lvId)$TB70o Sicilian: Dragon, 6.Be2 Bg7 7.O-O O-OlmVQ.jC24 Bishop's Opening: Urusov Gambit, Karpov VariationlU B|JA09j Reti: Advance, 3.g3 c5 4.Bg2 Nc6l> VA97 Dutch: Ilyin-Zhenevsky, Winter, 8...Ne4l6/ <A43s Old Benoni: Schmidt, 3.e4l1QlB05e Alekhine: Modern, Alekhine Variation, 6.exd6 exd6l-=CJLB77a Sicilian: Dragon, Yugoslav, 9.Bc4l,:#&B07d Pirc: 2.d4 Nd7l&F/IDD29b QGA: Classical, 8...Bb7 9.Nc3lx B07y Pirc: 4.Be2l6c26D00b Queen's Pawn: 2.c3 Nf6lAE:`DJD35j QGD: Exchange, 5.Bg5 Be7 6.e3 h6l vB21z Sicilian: Smith-Morra, 5.Nf3 d6 6.Bc4 e6 7.O-O Nf6 8.Qe2 Be7l $>bB80o Sicilian: Scheveningen, Fianchetto VariationlםXD52n QGD: Cambridge Springs, 8.Qc2 O-O 9.Be2kFSRB03m Alekhine: Four Pawns Attack, 6...Nc6k7-Q\E39d Nimzo-Indian: Classical, Pirc, 6.Nf3 Bxc5k:zy fA65u Benoni: Smisch, 8.Bg5 h6 9.Be3 O-O 10.Qd2 Re8k 8lE54 Nimzo-Indian: Main Line, Karpov, 10.Bg5 Bb7 11.Qe2k'gݡlD49c Semi-Slav: Meran, Old Main Line, Gligoric, 12.Qa4k^B09m Pirc: Austrian, 5...O-O 6.Bd3 Na6 7.O-O c5k ?ݤRE95f King's Indian: 7.O-O Nbd7 8.Re1 exd4kӜ(nJD36g QGD: Exchange, 6.Qc2 Be7 7.e3 h6kڵLE24 Nimzo-Indian: Smisch, 5...c5 6.f3kBƯA`B53w Sicilian, Chekhover, Main Line, 10.Rhe1 O-Ok.V$2A41l Neo-Old Indian: 2.c4k6!MLD35k QGD: Exchange, 5.Bg5 Be7 6.e3 O-OkDWi1+XD56 QGD: Lasker Defence, Teichmann, 9...Nxc3k9`2b?onD03q Torre Attack: 3...g6 4.e3 Bg7 5.Nbd2 O-O 6.c3 Nbd7ku 52A20 English: King's, 2.d3k>,3<C25h Vienna: Paulsen VariationkYxD^B87 Sicilian: Sozin-Najdorf, 7.Bb3 b5 8.O-O Be7kI@<PE03 Catalan: Open, 5.Qa4+ Nbd7 6.Qxc4 a6k<A89 Dutch: Leningrad, Main Line, 7.Nc3 Nc6 8.d5 Ne5 9.Nxe5 dxe5 10.Qb3kNI2D25f QGA: Flohr, 5.Nc3 c6kz{M5FC42a Russian Game (Petroff Defence)kuRY\E43 Nimzo-Indian: Nimzowitsch, 5.Nf3 Bb7 6.Bd3kt4})dE69d King's Indian: Fianchetto, Classical, 9.h3 a5kj4̞JB76d Sicilian: Dragon, Yugoslav, 9.g4k`~>B37o Sicilian: Maroczy Bind, 6.Nc2 Nf6 7.Nc3 d6 8.Be2 O-O 9.O-O Nd7 10.Bd2k^ڹ^fDC47h Four Knights: Glek, Main Linek^5Fo8A09f Reti: Advance, 3.e3 Nc6k\.G{~D19o Slav: Dutch, 8...O-O 9.Qe2 Nbd7 10.e4 Bg6 11.Bd3 Bh5 12.e5kX]vq/XB97i Sicilian: Najdorf, Poisoned Pawn, 8.Qd2kUOBb"D20g QGA: 3.e3 e5kQ' d>C54o Giuoco Piano: Greco AttackkN66)tE69k King's Indian: Fianchetto, Classical, 9.h3 Qb6 10.Re1kN4c4E70f King's Indian: KramerkN̡NC72 Spanish: Modern Steinitz, 5.O-O Bd7k@_FTrVB00p Nimzowitsch Defence: 2.Nf3 d6 3.d4 Nf6k8xqPC41k Philidor: 3...exd4 4.Nxd4 Nf6 5.Nc3k. >A13k English: Romanishin Gambitk% |FC01v French: Exchange, Canal Attackk!9XE94y King's Indian: 7.O-O Nbd7 8.Be3 c6 9.d5k>ͬbdC13j French: Chatard-Alekhine, Teichmann Variationk ;4rJA05 Reti: KIA, Reti-Smyslov Variationk&pE&VB99n Sicilian: Najdorf, Main Line, 10.g4 b5k}HD06s QGD: 2...Bf5 3.cxd5 Bxb1 4.Rxb1k;~.C33 KGA: Schurig GambitjɅ<D03m Torre Attack: 3...g6 4.e3jYUXPC02w French: Advance, 5.Nf3 Qb6 6.a3 Bd7j~XC64g Spanish: Classical, Cordel Gambit, 5.d4je(TTC59e Two Knights: Morphy, Gring Variationj JVE61w King's Indian: Smyslov System, 6.e3 c6j\C63r Spanish: Schliemann, 4.Nc3 fxe4 5.Nxe4 d5juX"Ed>B53c Sicilian: 2...d6 3.d4 cxd4j$H[MXA16 English: Anglo-Grnfeld, Czech Variationj` 6A86 Dutch: Leningrad, 4.Nf3jənEVE07 Catalan: Closed, 6...Nbd7 7.Nc3 c6 8.b3j P`S9HC36 KGA: Scandinavian, Modern, 5.Bc4j~8D08 QGD: Albin Countergambitj65XE00b Queen's Pawn: Anti-Nimzo-Indian, 3...d5jI|xHB82 Sicilian: Scheveningen, 6.f4 Qb6jn.[wD10h Slav: 3.e3jSNd@C26a Vienna: Mengarini Variationj>p2E04a Catalan: Open, 5.Nf3jjB&JA18 English: Mikenas, 3...d6 4.d4 Be7j"A00e Ware Openingj_oiFB57c Sicilian: Sozin, 6...Bd7 7.O-OjV34B34w Sicilian: Accelerated Fianchetto, Modern, 6.Be3 Nf6 7.Be2 O-O 8.O-O d5 9.exd5j~c7i6C28b Vienna: 3.Bc4 Nc6 4.f4j|ڞRC45q Scotch: 4.Nxd4 Bc5 5.Nb3 Bb6 6.a4 a6jxh&B90r Sicilian: Najdorf, 6.Be3 e5 7.Nb3 Be6 8.f3 Be7 9.Qd2 O-O 10.O-O-O Nbd7jxX<4D10o Slav: 3.Nc3 dxc4 4.a4jmlB03h Alekhine: Four Pawns Attack, Trifunovic Variationj_P)60D06r QGD: 2...Bf5 3.cxd5jXw==\pC67u Spanish: Open Berlin, 5.d4 Nd6 Queenswap, 9.Nc3 Ke8jO|DKYD8BB27b Sicilian: Mongoose Variationj>c^5fE98j King's Indian: Mar del Plata, 9.Ne1 Nd7 10.Be3j8X9GXE13f Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.e3j2*D05i Colle: 5.c3 Nbd7j*,xdB04n Alekhine: Modern, Fianchetto, Keres Variationj`E54 Nimzo-Indian: Main Line, 7...dxc4 8.Bxc4 Nc6jm&0FD35g QGD: Exchange, 5.Nf3 Be7 6.Bf4j ʠ:HA09s Reti: Accepted, Keres Variationj wIEwfB01u Scandinavian: Portuguese, 4.Nf3 Qxd5 5.Be2 Nc6j(STnE93 King's Indian: Petrosian, Main Line, 8.Bg5 h6 9.Bh4iD24r QGA: Bogoljubow, 7.a4 Nxc3hm[DA55e Old Indian: 5.e4 Be7 6.g3 O-OhREBD94 Grnfeld: Makogonov VariationhJEz@B15s Caro-Kann: 4.Nxe4 Nf6 5.Ng3h)5nLB43e Sicilian: Kan, 5.Nc3 b5 6.Bd3 Qb6ht2C31 KGD: Falkbeer, 3.exd5h^2KӁ<D00j Trompowsky: 2...d5 3.Bxf6hXE3-JD33k QGD Tarrasch: Swedish, 9.e4 dxe4h@NIbVE75b King's Indian: Averbakh, 7.d5 e6 8.Nf3hdC+JC03j French: Tarrasch, 3...Be7 4.Ngf3hy+MEXB02i Alekhine: Scandinavian, Exchange, 4.Bc4ht-FE08k Catalan: Closed, 7.Qc2 c6 8.b3hqF$=8D10w Slav: 3.Nc3 Nf6 4.e3 a6hlY3܃hRNC15g French: Winawer, 4.Bd3 dxe4 5.Bxe4hh]˯x#`A58r Benko Gambit: Fianchetto, Main Line, 11.Re1he\loN'JC30l KGD: Classical, Hanham VariationhaB/r LC18d French: Winawer, 6...Qc7 7.Qg4 f6hSRA34 English: Symmetrical, 3 Knights, 5.g3hNՇ=x>C28g Vienna: 3.Bc4 Nc6 4.d3 Bc5hMi@RB08t Pirc: Classical, 5.Be2 O-O 6.O-O Bg4h9MT:B41e Sicilian: Kan, 5.Be2 Nf6h5%\E54 Nimzo-Indian: Main Line, Smyslov Variationh3~>7fB01z Scandinavian: Marshall, 4.c4 Nb6 5.Nf3 g6 6.h3h3\{vA65w Benoni: Smisch, 8.Bg5 h6 9.Be3 O-O 10.Qd2 a6 11.a4 h5h+Ӹ"[ՙVC41o Philidor: Nimzowitsch, Klein Variationh!zȇ#pC64v Spanish: Classical, 6.c3 Bb6 7.d4 c6 8.Ba4 d6 9.Na3h!#(6A09j Reti: Advance, 3.g3 c5h:bE^E27 Nimzo-Indian: Smisch, 5...O-O 6.f3 d5 7.e3htq$B20 Sicilian: 2.g3h 2\E66a King's Indian: Fianchetto, Yugoslav Pannoh n>PDC82n Spanish: Open, Baguio, 12.Nb3g4@D02i Queen's Pawn: 2.Nf3 e6 3.g3gfA76 Benoni: Classical, Main Line, 10.Qc2 Na6 11.Bf4g+LgLC01m French: Exchange, 4.Nf3 Nf6 5.Bd3gG5flC91g Spanish: Closed, Bogoljubow, 10.d5 Na5 11.Bc2 Qc8gB22m Sicilian: Alapin, 2...d5 3.exd5 Qxd5 4.d4 Nf6 5.Nf3 e6 6.Be3g&ׂ2A28 English: Four Knightsg^ipB99x Sicilian: Najdorf, Modern Main Line 13.f5 Nc5 14.f6g;MhsHB58i Sicilian: Boleslavsky, 7.Nf3 h6g1)>0E60c King's Indian: 3.d5gA:8:D96 Grnfeld: Russian, 5...c6g=cvE15p Queen's Indian: Nimzowitsch, 5.b3 Bb4+ 6.Bd2 Be7 7.Bg2g6o1`B97m Sicilian: Najdorf, Poisoned Pawn, 9.Rb1 Qa3g~c2jE49 Nimzo-Indian: Botvinnik, 7...dxc4 8.Bxc4 c5 9.Ne2gJ% @B15f Caro-Kann: Gurgenidze: 4.e5ge6ND77j Neo-Grnfeld, 6.O-O dxc4 7.Na3 Nc6g+CPs&BE40 Nimzo-Indian: Taimanov, 5.Bd3gchE37 Nimzo-Indian: Classical, Noa, San Remo Variationg|N^RA40h Queen's Pawn: English Defence, 3.Nc3gpQRE15v Queen's Indian: Rubinstein VariationgosHdtC47y Four Knights: Scotch, Main Line, 10.Bg5 c6 11.Qf3 Be7gkɄFB00f Owen Defence: Naselwaus Gambitg^(!dE85f King's Indian: Smisch, Orthodox, 7.Nge2 Nbd7gWKrBA61 Benoni: Nimzowitsch, 7...Nbd7gO[ɽbTE32h Nimzo-Indian: Classical, 4...O-O 5.a3gKޘp3iA05 Reti: KIAgGBB01y Scandinavian: Marshall, 4.c4gCWthB05o Alekhine: Modern, Main Line, 8.h3 Bh5 9.Nc3 O-Og@N<֒`A46o Indian: 1.d4 Nf6 2.Nf3 e6 3.g3 c5 4.Bg2 Qc7g. 2B42a Sicilian: Kan, 5.Bd3gj`DC35 KGA: Cunningham, Bertin GambitgV@r2A20 English: King's, 2.g3g w8A45j Trompowsky 2...d6 3.Nc3gWNyVPB51h Sicilian: 3.Bb5+ Nd7 4.d4 Nf6 5.Nc3fyGFE80j King's Indian: Smisch, 5...a6fB17h Caro-Kann: Steinitz, 5.Ng5eYI߽IXE36 Nimzo-Indian: Classical, Noa, 5.a3 Bxc3+eݧTx6A10 English: Jnisch GambiteժDA30a English: Symmetrical, 2.g3 g6eJB15k Caro-Kann: Gurgenidze: 4.Nf3 Bg7eC9aEFA29 English: Four Knights, 4.g3 Bb4eɨ<:D17q Slav: Central, Main Linee:74B09b Pirc: Austrian Attacke>978E61i King's Indian: 4.Nf3 d6e/~LB70h Sicilian: Dragon, 6.Bc4 Bg7 7.O-Oe9BLC26f Vienna: Smyslov, 3...Bc5 4.Bg2 d6eБPz0A56b Benoni: 2...c5 3.e3eȣwI6A06 Reti: Old Indian AttackeQ2hC07l French: Tarrasch, Open, 4.exd5 Qxd5 5.Ngf3 cxd4e^?(A96 Dutch: ClassicaleHC56k Two Knights: Classical, Moller, 10.Neg5 O-O-O 11.Nxe6 fxe6 12.Rxe6 Bd6e"͎LE71d King's Indian: Makagonov, 5...O-Oe˧4(D08 QGD: Albin, 4.e4eP08͠lE11h Bogo-Indian: 4.Bd2 Be7 5.g3 d5 6.Bg2 O-O 7.O-O c6e3úBA34 English: Symmetrical, 2...Nf6e-BߦBC30b King's Gambit: Mafia Defenceeg'wtD34w QGD Tarrasch: 9.Bg5 cxd4 10.Nxd4 h6 11.Be3 Re8 12.Rc1e^A70r Benoni: Classical, 8.h3 O-O 9.Bd3 a6 10.a4eߵBB10i Caro-Kann: English Variatione!shLB52b Sicilian: 3.Bb5+ Bd7 4.Bxd7+ Nxd7erd~^+FA15 English: Anglo-Indian, 2.Nf3 g6e~&bI6DC55o Two Knights: Modern Variationez'~B33t Sicilian: Pelikan, Chelyabinsk, 9.Bxf6 gxf6 10.Nd5 Bg7 11.Bd3ev!˺@B50j Sicilian: 2.Nf3 d6 3.Nc3 e6etr ήLA72 Benoni: Classical, 8.Be2 O-O 9.Nd2eW͉PC46h Three Knights: Schlechter VariationePDlB99h Sicilian: Najdorf, Main Line, 10.Bd3 h6 11.Bh4 g5eDh 66C70 Spanish: Caro Variatione?Q!~[q,A03 Bird: 1...d5 2.Nf3e7+tՊ-<A43g Old Benoni: Franco-Benonie1xZ#ܲpD21p QGA: 3.Nf3 c5 4.d5 e6 5.Nc3 exd5 6.Qxd5 Qxd5 7.Nxd5e.=,jD35q QGD: Exchange, 5.Bg5 c6 6.e3 Be7 7.Nf3 Bf5 8.Bd3e#fPC01w French: Exchange Winawer, 5.Bd3 Nc6e `fAW<A11 English: Caro-Kann DefencedEDD13q Slav: Exchange, 6.Bf4 e6 7.e3dЬ ~RB76e Sicilian: Dragon, Yugoslav, 9.g4 Be6dXΏNB05r Alekhine: Modern, Main Line, 8.Nc3dXSŌA&B07i Pirc: 3.Bd3 g6d xeLD43u Semi-Slav: Moscow, 7.e3 Nd7 8.Bd3d#ZC12g French: MacCutcheon, Bernstein VariationdBɼA~@C02m French: Advance, 5.Nf3 Nge7d)aDA36e English: Symmetrical, 3.g3 g6dKMw4B07p Pirc: Czech, 4.f4 Qa5dB"dD32x QGD Tarrasch: 5.Nf3 Nc6 6.e3 Nf6 7.Be2 cxd4 8.Nxd4 Bd6 9.O-O O-O 10.b3dicF&D13b Slav: Exchanged/μ`A87 Dutch: Leningrad, Main Line, 7.Nc3 Qe8 8.Re1dI:E18e Queen's Indian: 7.Nc3 d5d}jo>D28b QGA: Classical, 7.Qe2 cxd4d}A#BC66 Spanish: Closed Berlin, 5.Re1dx/ LZcjC39 KGA: Kieseritsky, Salvio Defence, Cozio Variationdr@ʴVB21v Sicilian: Smith-Morra, 4.Nxc3 e6 5.Nf3dg8A20 English: King's, 2.g3 d6dfIUbA74 Benoni: Classical, 9.O-O a6 10.a4 Nbd7 11.Bg5deM)A&A25 English: CloseddV _lE14x Queen's Indian: 4.e3 Bb7 5.Bd3 c5 6.O-O Be7 7.Nc3dIEFbrB38x Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 d6 9.O-O Bd7 10.Qd2 Nxd4, 12.f3dIUⲭFC18d French: Winawer, 6...Qc7 7.Qg4dB44i Sicilian: Taimanov, 5.Nxc6cFaPD00y Blackmar-Diemer: Bogoljubow DefencecDT;ZD14l Slav: Exchange, 8.Bd3 Main Line, 12.Rac1c<pv6LE92b King's Indian: 6.Be2 e5 Queenswapc7)fD27v QGA: Classical, Rubinstein, 8.Qe2 cxd4, 11.Nc3c52C54l Giuoco Piano: 6.cxd4c2Ip,A00l Van Geet: 1...Nf6c*&XD45w Semi-Slav: 6.Qc2 Bd6 7.Be2 O-O 8.O-O e5c&)_VXB38g Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2c <A92 Dutch: Stonewall Variationc&1j~JC02t French: Advance, 5.Nf3 Qb6 6.Be2c ĤwvE16r Queen's Indian: Capablanca, 6...Bxd2+ 7.Qxd2 O-O 8.Nc3b~B79e Sicilian: Dragon, Yugoslav, Old Main Line, 12.h4 Ne5 13.g4blB A04 Reti: 1...f5bjaUO:A96 Dutch: Classical, 7.b3 a5bJZE58 Nimzo-Indian: Main Line, 9.bxc3 Qc7 10.h3bMX^~U6A24 English: Bremen, 3...g6bl^ZC13q French: Chatard-Alekhine, Breyer, 7.Bxe7bѬ6l8D73 Neo-Grnfeld, 5.Nf3 dxc4bUVc[dA39e English: Symmetrical, Main Line 7.d4, 8...Qb6b6&@B25c Sicilian: Closed, Botvinnikb*w7<A40o Queen's Pawn: 1...e6 2.c4bQml&DdE97v King's Indian: Mar del Plata, 9.Nd2 Nd7 10.b4bkڱ\D06u QGD: 2...Bf5 3.cxd5 Bxb1 4.Qa4+ c6 5.Rxb1bPz~bE17w Queen's Indian: Pomar, Polugaevsky Variationb' 2A40b Queen's Pawn: 1...c6bH VB83 Sicilian: Scheveningen, Modern, 9.f4 e5bnLF0>E72 King's Indian: Pomar Systembv[0A53 Old Indian: 3.Nf3 c6bgJE22 Nimzo-Indian: Spielmann VariationbV vE86e King's Indian: Smisch, Orthodox, 7.Nge2 c6 8.Qd2 Nbd7b^FDA57g Benko Gambit: 4.Nf3 g6 5.cxb5b]7~7FC89c Spanish: Marshall, 9.exd5 Nxd5bB"D(pA59l Benko Gambit: 7.e4, Main Line, 11...Nbd7 12.Re1 Qa5b|4B76u Sicilian: Dragon, Yugoslav, 9.O-O-O d5: 12.Bd4 e5 13.Bc5 Be6b| =:^A88 Dutch: Leningrad, Main Line, 7.Nc3 c6 8.Re1btE7k".D73 Neo-Grnfeld, 6.Nc3brhZ{b@C78g Spanish: 5.O-O b5 6.Bb3 Be7bqbt<DB17a Caro-Kann: Steinitz Variationbcx`oٷ|E15p Queen's Indian: Nimzowitsch, 5.b3 Bb4+ 6.Bd2 Be7 7.Bg2 d5ba(ܹ@B15e Caro-Kann: Gurgenidze: 4.h3b_]M\:E18c Queen's Indian: 7.Nc3 d6bT1 kNC68r Spanish: Exchange, Bronstein, 6.d3bL szXE12c Queen's Indian: Miles, 5.e3 Bb4+ 6.Nbd2bJ`DB58f Sicilian: Boleslavsky, 7.Ndb5b>VҴZC05c French: Tarrasch, Closed, 4...Ne4 5.Nxe4b=8V#fE98i King's Indian: Mar del Plata, 9.Ne1 Nd7 10.Kh1b2A50i Indian: Slav-Indian, 3.Nf3a NC18i French: Winawer, 6...Ne7 7.h4 Nbc6a|@cc>A92 Dutch: Stonewall, 7.Nbd2 c6ajlahdE97x King's Indian: Mar del Plata, 9.Nd2 a5 10.Rb1a=%*&D16b Slav: 5.a4 Nd5a{UA75 Benoni: Classical, 9.O-O a6 10.a4 Bg4 11.Bf4 Bxf3 12.Bxf3 Qe7 with 14.a5aHU⥗B14u Caro-Kann: Panov-Botvinnik, 5...e6 6.Nf3 Bb4 7.cxd5 Nxd5 8.Qc2 Nc6 9.Bd3aʻp<rA71 Benoni: Classical, 8.Bg5 h6 9.Bh4 a6 10.Nd2 b5 11.Be2a|ALB01w Scandinavian: Marshall, 4.Nf3 Bf5a‰RE56 Nimzo-Indian: Main Line, 7...Nc6 8.a3awmhE52 Nimzo-Indian: Main Line, 6...b6 7.O-O Bb7 8.cxd5ag[Q#-@B15v Caro-Kann: Tartakower, 6.c3aT1]FC77k Spanish: Centre Attack, 5...b5a٭znE73z King's Indian: Averbakh, 6...h6 7.Be3 e5 8.d5 Nbd7a';NA20 English: King's, 2.g3 Nf6 3.Bg2 Nc6aJxD48p Semi-Slav: Meran, Reynolds, 10...c4 11.dxe6 fxe6 12.Bc2at_>A08 Reti: KIA, French Variationa͊kDxJ2E10n Blumenfeld: 5.Bg5 h6ax8FA99 Dutch: Ilyin-Zhenevsky, 8.b3 a5al9Q7-DE00k Catalan: 3...Bb4+ 4.Bd2 Bxd2+acC>B91c Sicilian: Najdorf, 6.g3 g6a]cQs`B16k Caro-Kann: Bronstein-Larsen, 6.c3 Bf5 7.Ne2a]wn$TA42b Modern: Averbakh, Randspringer, 5.Nf3aQZLD66 QGD: Orthodox, Main Line, 8...dxc4aJ<A07 Reti: KIA, Keres VariationaIrDE70d King's Indian: 4.e4 O-O 5.Nf3a7G];jE81r King's Indian: Smisch, 5...O-O 6.Be3 Nbd7 7.Qd2a4]LvTB17r Caro-Kann: Steinitz, 5.Bc4 Ngf6 6.Ng5a0M6*HD64 QGD: Orthodox, Rubinstein Attacka)}-#?FC12l French: MacCutcheon, 8.Qg4 Kf8a$tj4E18a Queen's Indian: 7.Nc3a vq6A24 English: Bremen, 3...g6aS)GHA21 English: King's, Keres VariationaZ":C44l Ponziani: Caro Variationa*tΖ@A02 Bird: From Gambit, Schlectera5:fA27 English: Three Knights, 3...g6 4.d4 exd4 5.Nxd4ap*sB06c Modern`脐ͨDC20 Open Game: Portuguese, 2...Nc6`50E60e King's Indian: 3.g3`XkIdE81m King's Indian: Smisch, 5...O-O 6.Be3 c5 7.d5`I XC72 Spanish: Modern Steinitz, 5.O-O Bd7 6.d4`0DB21e Sicilian: Grand Prix, 2...Nc6`݀ߡEiBC55p Two Knights: Modern, 5.e5 d5`ڿzzC82h Spanish: Open, Berlin, 10.Bc2 Bg4 11.Nbd2 Be7 12.Re1 O-O`ؾ%RHA30b English: Symmetrical, 2.Nf3 Nc6`/Z VC43a Russian Game: Modern (Steinitz) Attack`nyeDA41e Neo-Old Indian / Modern: 3.g3`˘TD58n QGD: Tartakower, 8.Be2 Bb7 9.Bxf6 Bxf6 10.cxd5 exd5 11.b4 c5`PNC07f French: Tarrasch, Open, 4.Ngf3 Nf6`ǬOZ'ND58t QGD: Tartakower, 8.cxd5 exd5 9.Bd3`<A11 English: Caro-Kann Defence`-JD22e QGA: Alekhine, 4.e3 e6 5.Bxc4 c5`` q!NC03h French: Tarrasch, 3...Be7 4.Bd3 c5`Zeu*DB94d Sicilian: Najdorf, 6.Bg5 Nbd7`G!=BD46c Semi-Slav: Bogoljubow, 7.O-O`g0D34g QGD Tarrasch: 9.Be3`s}~PC99b Spanish: Closed, Chigorin, 13...Rd8`p@^!PE44 Nimzo-Indian: Nimzowitsch, 5.Ne2 Bb7`o5\B18k Caro-Kann: Classical, 6.Bc4 e6 7.N1e2 Nf6`klND59n QGD: Tartakower, Main Line, 12.Qa4`e^|A77 Benoni: Classical, Main Line, 10.Nd2 Nbd7 11.a4 Ne5 12.Qc2`d*Jxz`A61 Benoni: Nimzowitsch, 7...Bg7 8.Nc4 O-O 9.Bg5`]fF^B38l Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 d6`\7/vC49r Four Knights: Symmetrical, Metger, 10.d4 Ne6 11.Bc1 c5`[ KG~E69h King's Indian: Fianchetto, Classical, 9.h3 Qa5 10.Re1 exd4`U5APB00b Reversed Grob (Borg/Basman Defence)`H-mwIjA13v English: Neo-Catalan Accepted, 5.Qa4+ Nbd7 6.O-O`A5(<D45l Semi-Slav: 6.Qc2 Bd6 7.g4`=enRzE35 Nimzo-Indian: Classical, Noa, Exchange, 6.Bg5 h6 7.Bh4 c5`-Ti+^E23 Nimzo-Indian: Spielmann, Carlsbad Variation`,5mi:C25i Vienna: Paulsen, 3...Bc5`*tF2A55d Old Indian: 5.e4 Be7`'qwdC12f French: MacCutcheon, Olland (Dutch) Variation`$-lpRDD92 Grnfeld: 5.Bf4 O-O 6.Rc1 dxc4`"▙yB|A26 English: Closed, 5.d3 d6 6.Nf3 Nf6 7.O-O O-O 8.Rb1 a5 9.a3`" p^B90n Sicilian: Najdorf, 6.Be3 e5 7.Nb3 Be6 8.f3`[kpC29l Vienna Gambit: Paulsen Attack, Bardeleben Variation`VFB13d Caro-Kann: Exchange, 4.Nf3 Nf6`βLA34 English: Symmetrical, 2...Nf6 3.g3`(KvbE11d Bogo-Indian: 4.Nbd2 b6 5.a3 Bxd2+ 6.Bxd2 Bb7`)E15s Queen's Indian: Nimzowitsch, 5.b3 Bb4+, Main Line, 9.Ne5 Nfd7`jվpRB36b Sicilian: Maroczy Bind, 5...d6 6.Nc3_%FC47l Four Knights: Scotch, 4...exd4_@4>0C82a Spanish: Open, 9.c3_pxvxA79 Benoni: Classical, Main Line, 10.Nd2 Na6 11.f3 Nc7 12.a4_Z@JC92b Spanish: Closed, Keres Variation_FgXLE26 Nimzo-Indian: Smisch, 5...c5 6.e3_.Ν?bE27 Nimzo-Indian: Smisch, 5...O-O 6.f3 d5 7.cxd5_ykRC23 Bishop's Opening: Classical Variation_ʸmXB52n Sicilian: 3.Bb5+ Bd7 4.Bxd7+ Qxd7 5.O-O_14FVC75 Spanish: Modern Steinitz, 5.c3 Bd7 6.d4_:qUJyDD45p Semi-Slav: 6.Qc2 Bd6 7.b3 O-O_#nTB48j Sicilian: Taimanov, 6.Be3 a6 7.Bd3 b5_ܽ>C61i Spanish: Bird's, 5.O-O Bc5_`IDLD93 Grnfeld: 5.Bf4 O-O 6.e3 c5 7.dxc5_|B35h Sicilian: Accelerated Fianchetto, Modern, 7.Bc4 O-O 8.O-O_ő bA39l English: Symmetrical, Main Line 7.d4, 10.Qd2_g4D21t QGA: Alekhine Defence_JC83 Spanish: Open, Classical, 10.Nbd2_7󶈺d&D31a QGD: 3.Nc3 Nc6_ȑN8JB21u Sicilian: Smith-Morra, 4.Nxc3 e6_VF<E14a Queen's Indian: 4.e3 Bb4+_qƺTC14c French: Classical, Tarrasch Variation_z< 2D03l Torre Attack: 3...g6_rQ&\C95j Spanish: Closed, Breyer, Main Line, 13.a4_r2hC43g Russian Game: Modern Attack, 3...Nxe4 4.Bd3 Nc6_]rXZM&E00o Catalan: 4.Nf3_WW\8A06 Reti: Santasiere's folly_RZE81m King's Indian: Smisch, 5...O-O 6.Be3 c5_K}u?7PE18i Queen's Indian: 7.Nc3 d5 8.Ne5 Nbd7_J%td*LB05h Alekhine: Modern, Flohr Variation_A:|@A37a English: Symmetrical, 5.Nf3_@`\ LA21 English: Kramnik-Shirov, 3.Nd5 Ba5_:+M%|A36v English: Symmetrical, Botvinnik System, 5...d6, 7.O-O O-O_*&XB99j Sicilian: Najdorf, Main Line, 10.Bd3 b5_%gHI6&B07i Pirc: 3.Bd3 g6_]Ձ1bA74 Benoni: Classical, 9.O-O a6 10.a4 Nbd7 11.Nd2_K,7nE03 Catalan: Open, 5.Qa4+ Nbd7 6.Qxc4 c5 7.Nf3 a6 8.Qc2^/<*"D20c QGA: 3.e3 c5^fŀ{FD13i Slav: Exchange, 5.Nc3 e6 6.Bf4^vf <A11 English: Caro-Kann Defence^LdLzE12u Queen's Indian: Petrosian, Kasparov, 7...Nxc3 8.bxc3 Be7^i7fE69o King's Indian: Fianchetto, Classical, 9.h3 Re8^y@b{|A59q Benko Gambit: 7.e4, Main Line, 11...Nbd7 12.h3 Qa5 13.Re1^l|tNE28 Nimzo-Indian: Smisch, 5...O-O 6.e3^ӚoS)FD30b Diemer-Duhm Gambit (DDG): 5.f3^՛٫\S"&D04c Colle: 3...Bf5^w=LbD75 Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O c5 8.Nc3 Nxc3^XxhB74 Sicilian: Dragon, Classical, Spielmann Variation^)6dE39h Nimzo-Indian: Classical, Pirc, 6.Nf3 Na6 7.g3\FȌ3URC41s Philidor: Improved Hanham, 5.Bc4 Be7\E(|>B28g Sicilian: O'Kelly, 3.c4 e6\BlC24 Bishop's Opening: Urusov Gambit, 6.Bg5 Nc6 Defence\<0BA45t Trompowsky: 2...Ne4 3.Bh4 g5\:H9bFA37e English: Symmetrical, 5.Nf3 d6\8l{x*B15a Caro-Kann: 3.Nc3\/sND07r QGD: Chigorin, 3.Nc3 Nf6 4.Nf3 Bg4\j '{*A53 Old Indian: 3.Nc3\ ':C29p Vienna Gambit: 5.Nf3 Bb4\CǓ.XD45t Semi-Slav: 6.Qc2 Bd6 7.b3 O-O 8.Be2 Re8\8D77d Neo-Grnfeld, 6.O-O Nc6[8! E>B30c Sicilian: 2...Nc6 3.d3 Nf6[شJC41s Philidor: Improved Hanham, 6.Ng5[{nMirD47p Semi-Slav: Meran, Wade, 9.O-O b4 10.Ne4 Be7 11.Nxf6+[s/>TB46o Sicilian: Taimanov, 5...a6 6.Be2 Nge7[מHD29d QGA: Classical, 8...Bb7 9.a4 b4[4y6D91s Grnfeld: 5.Bg5 Ne4 6.cxd5 Nxg5 7.Nxg5 e6 8.Nf3 exd5 9.e3 O-O 10.Be2[4эXA57s Benko Gambit: Zaitsev, 5...axb5 6.e4 b4[J 2C33 KGA: Eisenberg Gambit[[yŊ<D31r Semi-Slav: Noteboom, 5.a4[̌`A63 Benoni: Fianchetto, 9...Nbd7 10.Nd2 a6 11.a4[ ],WlB34g Sicilian: Accelerated Fianchetto, Modern, 5...Nf6[Ղ~dNC59i Two Knights: Main Line, 11.f4 exf3[UHB29k Sicilian: Nimzowitsch, 4.Nc3 e6[)i`E90y King's Indian: 5.Nf3 O-O 6.h3 c5 7.d5 e6 8.Bd3 exd5 9.exd5 Re8[ΐ2C51 Evans Gambit Accepted[QBC99n Spanish: Closed, Chigorin, 13...Nc6 14.Nb3 a5 15.Be3 a4 16.Nbd2 Nb4[$'rB68 Sicilian: Richter-Rauzer, 7...a6, 9.f4 Be7 10.Be2 Qc7[G8bB30u Sicilian: Rossolimo, 3...e6 4.O-O Nge7 5.Nc3[5OH(lB84 Sicilian: Scheveningen, Classical, 7.O-O Qc7 8.Kh1[{JA65g Benoni: 6.e4 g6 7.Bd3 Bg7 8.Nge2[$QNHC88d Spanish: Closed 7...d6 8.c3 Bg4[ eBA13o English: Agincourt Variation[=JC28p Vienna: 3.Bc4 Nc6 4.d3 Bb4 5.Ne2[`.JB75 Sicilian: Dragon, Yugoslav Attack[`D}FBE70j King's Indian: 4.e4 d6 5.Bd3[%RzcTD32k QGD Tarrasch: 5.dxc5, Tarrasch Gambit[F`@D80 Grnfeld: Stockholm, 4...Ne4[eFLA65e Benoni: 6.e4 g6 7.Bf4 a6 8.Nf3 b5[ 1_/jE90r King's Indian: 5.Nf3 O-O 6.h3 e5 7.d5 Nbd7 8.Bg5[0!eFC18j French: Winawer, 6...Ne7 7.Qg4[XD85d Grnfeld: Exchange, 5.e4 Nxc3 6.bxc3 c5[U])LD36d QGD: Exchange, 6.Qc2 Be7 7.Nf3 g6[s}#XB32h Sicilian: 2..Nc6, Nimzowitsch Variation[=0E38l Nimzo-Indian: Classical, 4...c5 5.dxc5 Na6: 8.b4 Nce4 9.Qd4[|͒+uNE12g Queen's Indian: Petrosian, 4...Ba6[wsKMXD56 QGD: Lasker Defence, Teichmann Variation[p6bB80r Sicilian: Scheveningen, Fianchetto Variation[p9uJA44p Old Benoni: Czech, 3.e4 d6 4.Bd3[o0'PTDD57 QGD: Lasker Defence, Main Line[_G8D94 Grnfeld: 5.e3 O-O 6.Be2[TS*[p^E09i Catalan: Closed, Main Line, 9.e4 Ba6 10.b3[@47LC45p Scotch: 4.Nxd4 Bc5 5.Nb3 Bb6 6.a4[@}GjA07 Reti: KIA[:P,'AiTB92f Sicilian: Najdorf, 6.Be2 e5 7.Nb3 Be7[.Z9\4DC51 Evans Gambit: Normal Variation[+N|@A60f Benoni: 4.g3 exd5 5.cxd5 b5[+TНG^D52e QGD: Cambridge Springs, Yugoslav Variation[' P:E60h King's Indian: b3 System[`A0C60a Spanish (Ruy Lopez)[+]XD73 Neo-Grnfeld, 5.Nf3 c6 6.cxd5 cxd5 7.Nc3[vhz.D30k QGD: 3.Nf3 c6 4.e3[2>gPB21f Sicilian: Grand Prix, 2...Nc6 3.Nf3ZG X E79e King's Indian: Four Pawns Attack, Main Line, 9...Bd7 10.Qd2Z#rDB12v Caro-Kann: Advance, 4.Nc3 Qb6Z#%Q.>XA16 English: Anglo-Grnfeld, 4.Nf3 g6 5.Qa4+Z6ÖbfC96m Spanish: Closed, Chigorin, Borisenko VariationZ7GHD01k Richter-Veresov: 3...Bf5 4.Bxf6Zx7NB47f Sicilian: Taimanov, 6.f4 a6 7.Nxc6Zڐ2pThA39p English: Symmetrical, Main Line 7.d4, 10.Qd3 a6Zy:2A21 English: Lukin, 5.Ng5Z-/><:C11s French: Burn, 5.Nxe4 Be7Ze}nA91 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nf3 d5 6.O-O c6ZjE32s Nimzo-Indian: Classical, 4...O-O 5.a3, 6...b6 7.Bg5 Bb7 8.e3Z܁;>DND61 QGD: Orthodox, Rubinstein, 7.Qc2 c5Zycn8E70b King's Indian: 4.e4 O-OZHdB81d Sicilian: Scheveningen, Keres, Perenyi AttackZtgxԱ<<C45w Scotch: Blackburne AttackZ<+76D53t QGD: 4.Bg5 Be7 5.e3 h6Zrj"E69z King's Indian: Fianchetto, Classical, 9.h3 Re8 10.Re1 exd4, 11...Nc5 12.b3ZI32WDNjE31l Nimzo-Indian: Leningrad, Main Line, 8...e5 9.Qc2ZH{ .MZD87h Grnfeld: Classical Exchange, 10.Be3 Qa5Z7FRqgHD16q Slav: Bronstein, 6.Ne5 Bh5 7.f3Z7$z_VbC92f Spanish: Closed, Karpov Variation, 10.d4 Bf6Z2IT<C21 Centre Game: Halasz GambitZ*|(D37v QGD: Classical, 5...O-O 6.e3 c5 7.dxc5 Bxc5 8.Qc2 Nc6 9.a3 Qa5 10.O-O-OZ$N~(D43b Semi-Slav: 5.g3ZTc'ZD60 QGD: Orthodox, Botvinnik, 7...dxc4 8.Bxc4Z T9[|0A50h Indian: Slav-IndianZ p60ҚNC18i French: Winawer, 6...Ne7 7.h4 Nbc6Yl|DFC25q Vienna: Hamppe-Allgaier GambitYiGs!DB12w Caro-Kann: Advance, Main LineY@>FA43x Old Benoni: Schmidt, 6.Be2 O-OYn_.hC04j French: Tarrasch, Guimard, Main Line, 6.Nb3 Be7YJdP6A41q Neo-Old Indian: ModernYCdlD45e Semi-Slav: Accelerated Meran (Alekhine Variation)Y%IY}ZC18o French: Winawer, 6...Ne7 7.Qg4 O-O 8.Bd3Y8h[@B31a Sicilian: Rossolimo, 3...g6Y7i{D:<E94p King's Indian: 7.O-O Nbd7Yi8u:6C07a French: Tarrasch, OpenY_^DB13a Caro-Kann: Exchange VariationY0LD17i Slav: Central, Carlsbad VariationŸ́~S>E32t Nimzo-Indian: Classical, 4...O-O 5.a3, 6...b6 7.Bg5 Bb7 8.e3 d6Y̽n,A48a Neo-King's IndianY/`:}DC11a French: Henneberger VariationY)X!zD32g QGD Tarrasch: von Hennig-Schara Gambit, 7.Qxd5 Nc6 8.Bg5Yey&InB01p Scandinavian: 2...Qxd5, Main Line, 6.Bc4 Bf5 7.Bd2Y0)CoHC29i Vienna Gambit: Oxford, 5...Nxc3YtfPE41 Nimzo-Indian: Hbner, 8.O-O e5 9.Nd2YbK~B76n Sicilian: Dragon, Yugoslav, 9.O-O-O Nxd4: 11.Kb1 Qc7 12.g4Y(aNHBA40c Queen's Pawn: Polish DefenceYL:A10 English: 1...g6 2.Nc3 Bg7Y 80D09 QGD: Albin, 5.g3 Be6YXtC09j French: Tarrasch, Open, Main Line, 9.c3 O-O 10.Nb3 Bb6 11.Re1Yd>B17b Caro-Kann: Steinitz, 5.Nf3YB@@D63 QGD: Orthodox, 7.Rc1 c6 8.a3YS8^TB15l Caro-Kann: Gurgenidze: 4.Nf3 Bg7 5.h3Y{ʂnvSRA39a English: Symmetrical, Main Line 7.d4Yf 2hTB77d Sicilian: Dragon, Yugoslav, 9.Bc4 Nd7Yc}t:C44p Ponziani: Fraser DefenceYagVB00o Nimzowitsch Defence: 2.Nf3 d6 3.d4 Bg4Y` 46E01 Catalan: 4...Bb4+ 5.Bd2Y_KTC45g Scotch: Steinitz, Rosenthal VariationYZsRB01u Scandinavian: Portuguese, 4.Be2 Bxe2YS6rnE77 King's Indian: Four Pawns Attack, Florentine GambitYQT=KTjB48r Sicilian: Taimanov, 6.Be3 a6 7.Bd3 Nf6 8.O-O Bd6YPMHB01u Scandinavian: Richter VariationYK-NPC02x French: Advance, 5.Nf3 Qb6 6.a3 Nh6YJtk|>A40b Queen's Pawn: 1...c6 2.Nf3YD44b Semi-Slav: Botvinnik, 6.a4XB01t Scandinavian: 2...Nf6 3.c4WJTϑWZC71 Spanish: Modern Steinitz, Keres VariationWCDs*jC{zB75 Sicilian: Dragon, Yugoslav, 7...Nc6 8.Qd2 Bd7 9.O-O-O Rc8W<T5}}8E20 Nimzo-Indian: RomanishinW:g,0B00l Nimzowitsch DefenceW9ZC11w French: Burn, 6.Bxf6 gxf6 7.Nf3 b6 8.Bd3W7AMLKbD41o QGD: Semi-Tarrasch, 6.e4, Main Line, 12...b6W2ށD$D24b QGA: 4.Nc3 e6W2:o@C60c Spanish: Nrnberg VariationW(JxpScebB17s Caro-Kann: Steinitz, 5.Bc4 Ngf6 6.Ng5, 8.Bb3W$$'DC12n French: MacCutcheon, 8.Qg4 g6W`VE67a King's Indian: Fianchetto with 6...Nd7W /HE10q Blumenfeld: Spielmann VariationW8%BIJC68i Spanish: Exchange, 5.Nc3 f6 6.d4W| Ts4C80m Spanish: Open, 8.dxe5WC N@C21 Centre Game: Maroczy DefenceVfiFnpB34p Sicilian: Accelerated Fianchetto, Modern, 6.Be3 Nf6VzVPB33d Sicilian: Pelikan/Sveshnikov, 6.Nf5VRc@D78o Neo-Grnfeld, 6.O-O c6 7.b3V[{A<D13d Slav: Exchange, 5.Nc3 Bf5VvK]JbB67a Sicilian: Richter-Rauzer, 7...a6 8.O-O-O Bd7VT~BUXE62m King's Indian: Fianchetto, 6...Nc6 7.d5VJdFD34o QGD Tarrasch: Stoltz VariationVͲ+<B22b Sicilian: Alapin, 2...Nc6VaZB08r Pirc: Classical, 5.Be2 O-O 6.O-O c6 7.a4V<>\fD12m Slav: 4.e3 Bf5 5.Nc3 e6 6.Bd3 Bxd3 7.Qxd3 Nbd7V-G ZB01h Scandinavian: 2...Qxd5 3.Nc3 Qa5 4.d4 c6V=aBD85g Grnfeld: Exchange, 7.Be3 c5VoHJB21t Sicilian: Smith-Morra, 4.Nxc3 d6V> TA30m English: Symmetrical, Hedgehog SystemVm/x lE54 Nimzo-Indian: Main Line, Karpov, 10.Bg5 Bb7 11.Rc1V5r6B70a Sicilian: Dragon, 6.f3V"liJC47j Four Knights: Scotch, BogoljubowVh-lX3VA21 English: Kramnik-Shirov, 3.Nd5 Be7 4.d4V`ox].D00a Queen's Pawn: 2.g3VGxzXE90m King's Indian: 5.Nf3 O-O 6.h3 Na6 7.Bg5V@!y 6D58e QGD: Tartakower, 8.Bd3V>2TC07t French: Tarrasch, Open, 4.exd5 Qxd5, Main Line, 10.Nxd4 a6 11.Re1V7|C67w Spanish: Open Berlin, 5.d4 Nd6 Queenswap, 9.Nc3 Ke8 10.h3V3?2!9LD80 Grnfeld: Stockholm, 4...Ne4 5.Bf4V1'.aBD40b QGD: Semi-Tarrasch, 5.e3 Be7V,,$fE67d King's Indian: Fianchetto, Classical VariationV"&w lB45j Sicilian: Taimanov, Four Knights, 6.Be3 Bb4 7.Bd3V ].D24i QGA: 4.Nc3 a6 5.a4ULx\H>A53 Old Indian: 3.Nc3 Nbd7 4.e4UF)7RC47c Four Knights: Van der Wiel VariationUNIPJA65p Benoni: Smisch, 8.Bg5 O-O 9.Qd2U?2D07n QGD: Chigorin, 3.Nc3UV FB21s Sicilian: Smith-Morra AcceptedUWN <C31 KGD: Falkbeer, 3.exd5 exf4U%xuVA16 English: Anglo-Grnfeld, Smyslov, 7.Rb1U4$<A70b Benoni: Classical, 7...a6U< ?BC41p Philidor: Exchange VariationU鋾:C30p KGD: Classical, 4.c3 Nf6U"2RA42v Modern: Averbakh, 4...e5 5.dxe5 dxe5U!FD19c Slav: Dutch, 8...O-O 9.Qe2 Bg6UO'NE21 Nimzo-Indian: Three Knights, 4...c5U3MB36p Sicilian: Maroczy Bind, 5...Nf6 6.Nc3 d6 7.Be2 Nxd4 8.Qxd4 Bg7 9.Be3 O-O 10.Qd2 Be6UPA11 English: Caro-Kann Defence, 3.e3 Nf6UF 2A53 Old Indian: 3.Nf3 Bf5UpFtD85v Grnfeld: Modern Exchange, 8.Be3 Qa5 9.Qd2 Nc6 10.Rc1UtJ?R8E61g King's Indian: 4.g3 O-OU'^T<D85d Grnfeld: Exchange, 7.Ba3U|^ z8E00j Catalan: 3...Bb4+ 4.Bd2UsMUsHC83 Spanish: Open, Classical, 10.Re1Up|[:A42n Modern: Averbakh, 4...e5UmʹLB73 Sicilian: Dragon, Classical, 8.O-OUej 6A09n Reti: Accepted, 3.Qa4+UeHZD10f Slav: Exchange, 4.Nc3 Nf6 5.Bf4 Nc6 6.e3UYC05k French: Tarrasch, Closed, 5.f4 c5 6.c3 Nc6 7.Ndf3 Qb6 8.Ne2UQS%NB42l Sicilian: Kan, 5.Bd3 Nf6 6.O-O Qc7UIq0.zE15s Queen's Indian: Nimzowitsch, 5.b3 Bb4+, Main Line, 9.Ne5UC,:ZFD48c Semi-Slav: Meran, 8...a6 9.O-OU?dKr2DC44v Scotch: Goring Gambit, 4...d3U;"IlFA37i English: Symmetrical, 5.Nf3 e6U6 { ,`B84 Sicilian: Scheveningen, Classical, 7.O-O Nc6U36TC34 KGA: Becker Defence (Anti-Kieseritzky)U-FRB50v Sicilian: 2.Nf3 d6 3.c3 Nf6 4.Be2 g6U#'8A10 English: Adorjan DefenceUˊp.ΈRC89o Spanish: Marshall, Main Line, 15.Re4UfE73s King's Indian: Averbakh, 6...Na6 7.Qd2 e5 8.d5U,:E00d Queen's Pawn: Neo-IndianU_mtE97h King's Indian: Mar del Plata, Bayonet Attack, 9...Ne8U=o^>C18a French: Winawer, 5...Bxc3+UEHD90 Grnfeld: Three Knights ExchangeT/;|B90p Sicilian: Najdorf, 6.Be3 e5 7.Nb3 Be6 8.f3 Be7 9.Qd2 Nbd7T:XC12h French: MacCutcheon, Janowski VariationTP546LB33k Sicilian: Pelikan, 7.Bg5 a6 8.Na3T^ FD02j Queen's Pawn: Krause VariationTŜGA<D55h QGD: Neo-Orthodox, 7.Bxf6Tg*B23c Sicilian: ClosedT6C70 Spanish: Graz VariationTҺc36A84 Dutch: Bladel VariationTлoiP jA42l Modern: Averbakh, Kotov, 5.Be3 e5 6.d5 Nce7 7.c5Tin`B49d Sicilian: Taimanov, 6.Be3 a6 7.Be2 Nf6 8.a3Tu\D76k Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O Nb6 8.Nc3 Nc6 9.d5 Na5 10.e4 c6T3vD40m QGD: Semi-Tarrasch, 5.e3 Nc6 6.a3 cxd4 7.exd4 Be7 8.c5T˜[LTE15j Queen's Indian: Nimzowitsch, 5.Qa4 c5T,\E19p Queen's Indian: Old Main Line, 9.Qxc3 c5 10.Rd1 d6 11.b3 Bf6 12.Bb2 Qe7T x,|JD10y Slav: 3.Nc3 Nf6 4.e3 a6 5.Qc2 b5TkvXbC26k Vienna: Smyslov, 3...d5, 5...Nxc3 6.bxc3 Bd6T1ΐdhC36 KGA: Scandinavian, Modern, 5.Bb5+ c6 6.dxc6 bxc6T@k=jB22h Sicilian: Alapin, 2...d5 3.exd5 Qxd5 4.d4 Nc6 5.Nf3 cxd4 6.cxd4T PnzE60q King's Indian: Fianchetto without Nc3, 6...Nbd7 7.Qc2 e5TebC82q Spanish: Open, Dilworth, 14.Kxf2 Qxf6 15.Nf1Tx\CE48 Nimzo-Indian: 4.e3 O-O 5.Bd3 d5 6.Ne2 c5 7.cxd5 cxd4 8.exd4 Nxd5 9.O-OTt GUFD18d Slav: Dutch, 6...e6 7.Bxc4 Bb4Tp|{DC23 Bishop's Opening: Lewis GambitT_6W$,hB09m Pirc: Austrian, 5...O-O 6.Bd3 Na6 7.O-O c5 8.d5T\Q^d\B01z Scandinavian: Marshall, 4.c4 Nb6 5.Nf3 g6T[r'.B44a Sicilian: TaimanovTWg\axE12u Queen's Indian: Petrosian, Kasparov, 7...Nxc3 8.bxc3 c5TR0.S`B97k Sicilian: Najdorf, Poisoned Pawn, 9.Nb3 Qa3TQc(C23 Bishop's OpeningTLgBR:A13g English: 1...e6 2.Nc3 d5TKfC96d Spanish: Closed, Chigorin, Rossolimo VariationTJ7/PE10h Neo-Indian: Blumenfeld/Benoni, 4.e3TF0(3fC59l Two Knights: Main Line, 11.d4, Honfi VariationTDFXQk\DE04k Catalan: Open, 5.Nf3 c5 6.O-OT?(bB27t Sicilian: Accelerated Pterodactyl, 4.c4 Qa5+T9n6A16 English: Anglo-GrnfeldT7X AB79c Sicilian: Dragon, Yugoslav, Old Main Line, 12.h4 Ne5 13.Kb1T5lhB63a Sicilian: Richter-Rauzer, Rauzer Attack (7.Qd2)T5nQB48v Sicilian: Taimanov, 6.Be3 a6 7.Bd3 Nf6 8.O-O Ne5 9.h3 Bc5 10.Kh1T)h,kF6C61f Spanish: Bird's, 5.O-OT&K,A47 Neo-Queen's IndianT/JE76a King's Indian: Four Pawns AttackT{8E91b King's Indian: 6.Be2 a5TB8 8C11h French: Steinitz, 6.Nf3TƽJE71b King's Indian: Makagonov, 5...c5S$B38v Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 d6 9.O-O Bd7 10.Qd2SDxVXC67i Spanish: Open Berlin, 5...Be7 6.Qd2 Nd6S8K* >C62 Spanish: Old Steinitz, 4.d4S0ZE69r King's Indian: Fianchetto, Classical, 9.h3 Re8 10.Be3 exd4 11.Nxd4Sm>tB01p Scandinavian: 2...Qxd5, Main Line, 6.Bc4 Bf5 7.Bd2 e6SqSClB84 Sicilian: Scheveningen, Classical, 7.O-O Qc7 8.Be3S[_@D27b QGA: Classical, 6...a6 7.b3S40JA09h Reti: Advance, 3.g3 Nc6 4.Bg2 e5Sݿ%RvC88o Spanish: Closed, Anti-Marshall 8.a4 Bb7 9.d3 d6 10.Nc3S(g8B06l Modern: Nc3 PterodactylS] )XC50r Giuoco Pianissimo: Italian Four KnightsS #w\C02z French: Advance, 5.Nf3 Qb6 6.a3 c4 7.Nbd2S࣢r%NC19g French: Winawer, 6...Ne7 7.Nf3 Qa5S[cvB00s Nimzowitsch Defence: 2.Nf3 d6 3.d4 Nf6 4.Nc3 Bg4 5.Be3S4Qd4D15g Slav: Chameleon, 5.e3S8E90c King's Indian: 5.Nf3 c5S᰺IlC87d Spanish: Closed, Averbakh, 7.Bxc6+ bxc6 8.d4 exd4Sz iVC27i Vienna: Frankenstein-Dracula VariationSlvJE75a King's Indian: Averbakh, 7.d5 e6Sf823.D00a Queen's Pawn: 2.f4Sdb?<C03f French: Tarrasch, 3...Be7Sdw)VB58g Sicilian: Boleslavsky, Louma VariationSR'TB12k Caro-Kann: Advance, 3...c5 4.dxc5 Nc6SO Dr(3:D71 Neo-Grnfeld, 5.cxd5 Nxd5SD8'>^4C25r Vienna: Pierce GambitS@fDe\A16 English: Anglo-Grnfeld, Smyslov VariationS?5P{BB15d Caro-Kann: Gurgenidze: 4.Be3S=1M:A09q Reti: Accepted, 3.Na3 c5S7x^:D23o QGA: Mannheim, Main LineS$@B23n Sicilian: Chameleon, 3...g6S%hE23 Nimzo-Indian: Spielmann, 4...c5 5.dxc5 Nc6 6.Nf3STD27u QGA: Classical, Rubinstein, 8.Qe2 Qc7S7sFC00s French: KIA, Reversed PhilidorSW#1,dA87 Dutch: Leningrad, Main Line, 7.Nc3 Qe8 8.d5 a5RQ`B97j Sicilian: Najdorf, Poisoned Pawn, 9.Nb3 Nc6R4XdA94 Dutch: Stonewall, Botvinnik, 8.Ba3 Bxa3 9.Nxa3R@ $ojB67i Sicilian: Richter-Rauzer, 7...a6, 9.f4 h6 10.Bh4Rݧ@[zA65x Benoni: Smisch, 8.Bg5 h6 9.Be3 O-O 10.Qd2 a6 11.a4 Nbd7R֞Xfk^A38f English: Symmetrical, Main Line, 6.O-O O-OROtW`B02k Alekhine: Scandinavian, Exchange, 4.Bc4 Nb6RGndE15f Queen's Indian: Nimzowitsch, 5.Nbd2 Bb7 6.Bg2R)ZHE40 Nimzo-Indian: Taimanov, 5.Ne2 d5R}HTE35 Nimzo-Indian: Classical, Noa, ExchangeRIcXfA36t English: Symmetrical, Botvinnik, 5...d6 6.Nge2RR/JHC34 KGA: Bonsch-Osmolovsky VariationRȳ)$D20m QGA: 3.e4 Nc6R"PD00k Trompowsky: 2...d5 3.Bxf6 exf6 4.e3R񺟌 HB21m Sicilian: Smith-Morra, 2...cxd4Rp6;jD19k Slav: Dutch, 8...O-O 9.Qe2 Nbd7 10.e4 Bg6 11.Bd3Rm-jA45o Trompowsky: 2...e6 3.e4 h6 4.Bxf6 Qxf6 5.Nc3 Bb4Ri:~JB01i Scandinavian: 2...Qxd5, 5.Bc4 c6Rfo[ <D01l Richter-Veresov: 3...Nbd7RfctAikNB44k Sicilian, Taimanov, Szen VariationRa=Q6C46g Three Knights: 3...Bb4R^Ωv<D30h QGD: Tarrasch without Nc3RTOA|RA53 Old Indian: 3.Nc3 Nbd7 4.e4 e5 5.Nge2RP!q*bE74h King's Indian: Averbakh, 6...c5 7.d5 a6 8.a4RB"ڻ%7VB76o Sicilian: Dragon, Yugoslav, 9.O-O-O d5RAw ԬVE97x King's Indian: Mar del Plata, 9.Nd2 a5R?%A@B29f Sicilian: Nimzowitsch, 3.e5R=~8D17k Slav: Central, 6.Ne5 e6R:⢉aHA18 English: Mikenas, Flohr, 7.d4 e5R:֌xtA36d English: Symmetrical, Keres-Parma, Main Line ExchangeR&;{D|B59o Sicilian: Boleslavsky, 7.Nb3 Be7 8.O-O O-O 9.Be3 a5 10.a4RnadE34 Nimzo-Indian: Classical, Noa, 5.cxd5 Qxd5 6.e3R 4Z•^D54c QGD: Anti-Neo-Orthodox, 8.cxd5 Nxd5 9.Nxd5Q3⻧wpVB37e Sicilian: Maroczy Bind, 6.Nc2 d6 7.Be2Qd,A00n Grob: Double GrobQsND40e QGD: Semi-Tarrasch, 5.e3 a6 6.cxd5Q@C39 KGA: Allgaier, Urusov AttackQ}<`DA46x Torre Attack: 3...h6 4.Bh4 g5Q2 3 4A13e English: 1...e6 2.Nc3QU= }jVB97c Sicilian: Najdorf, Poisoned Pawn, 8.a3Q翃o,XE92g King's Indian: Gligoric-Taimanov SystemQ[]zHD43k Semi-Slav: Moscow, 6.Bh4 GambitQV]PA01 Nimzowitsch-Larsen: Indian VariationQ##iZTC33 KGA: bishop's Gambit, McDonnell AttackQ蓤榏B70w Sicilian: Dragon, 6.Be2 Bg7 7.O-O O-O 8.Bg5 Nc6 9.Nb3 Be6 10.Kh1QR_VA94 Dutch: Stonewall, Botvinnik, 8.Ba3 Nbd7QXD20q QGA: 3.e4 Nf6 4.e5 Nd5 5.Bxc4 Nb6 6.Bb3Q,s^D41v QGD: Semi-Tarrasch, 7.Bc4 Main Line, 13.h4QI`B63l Sicilian: Richter-Rauzer, 7.Qd2 Be7 8.O-O-OQ&|FD60 QGD: Orthodox, Rauzer VariationQqcwvD42p QGD: Semi-Tarrasch, 7.Bd3 Main Line, 10.Re1 Bf6 11.Be4Q]BB29i Sicilian: Nimzowitsch, 4.Nc3Q=Ɗ2D38b QGD: Ragozin, 5.Qa4+Qm_ydE94d King's Indian: 7.O-O exd4 8.Nxd4 Re8 9.f3 Nc6Q 7t`B89 Sicilian: Velimirovic, 9.O-O-O Qc7 10.Bb3 a6Q;eHC32 KGD: Falkbeer, 5.dxe4 Nxe4 6.Nf3Q7:=8B90d Sicilian: Najdorf, 6.f3QRB18f Caro-Kann: Classical, Maroczy AttackQw`A34 English: Symmetrical, 3 Knights, 3...e6 4.g3Qw%f8D23c QGA: Mannheim VariationQ}.Nd"E01 Catalan: OpenQ}R i8D46b Semi-Slav: Romih, 7.O-OQ|O|'6A42c Modern: c4 PterodactylQz۩VC67i Spanish: Open Berlin, Cordel VariationQz:p&VB21g Sicilian: Grand Prix, 2...Nc6 3.Nf3 e6QsP<A02 Bird: 1..Nf6 2.Nf3 g6 3.g3QpGmqLB92d Sicilian: Najdorf, 6.Be2 e5 7.Nf3Qm@kl=^HC53 Giuoco Piano: Eisinger VariationQXI*0C45c Scotch: 4.Nxd4 Bb4+QWVWZbD41o QGD: Semi-Tarrasch, 6.e4, Main Line, 12...b6QW.&Q8A09b Reti: Advance VariationQQL RGdC82e Spanish: Open, Berlin, 10.Bc2 Bg4 11.Nbd2 Be7QHB#nD35t QGD: Exchange, 5.Bg5 c6 6.e3 Be7 7.Bd3 Nbd7 8.Nge2QGCPB95i Sicilian: Najdorf, 6...e6 7.Qd3 Nc6Q>z؃LA08 Reti: KIA, 2...c5, 3.Bg2 Nc6 4.O-OQ:*~>C41i Philidor: Morphy VariationQ5DiJA18 English: Mikenas, Flohr VariationQ4 )vBB59a Sicilian: Boleslavsky, 7.Nb3Q1>`B19j Caro-Kann: Classical, Spassky, 10.Qxd3 Ngf6Q.`<A86 Dutch: Leningrad VariationQ&PXB34e Sicilian: Accelerated Fianchetto, 5.Be3Q%p bA67o Benoni: Four Pawns, Taimanov, 9.a4 a6 10.Be2Q$XiXE08n Catalan: Closed, 7.Qc2 c6 8.b3 b6 9.Rd1Q%) E14i Queen's Indian: 4.e3 Bb7 5.Bd3 Bb4+ 6.Nbd2 O-O 7.O-O d5 8.a3 Be7Qox,aJB44k Sicilian, Taimanov, Szen, 5...d6QgM[HHB11a Caro-Kann: Two Knights, 3...Bg4Q95>E72 King's Indian: 4.e4 d6 5.g3Q m:A21 English: King's, 2.Nc3 f5QDyLC82c Spanish: Open, Berlin, 10.Bc2 Bg4P%bB22p Sicilian: Alapin, 2...Nf6 3.e5 Nd5 4.Nf3 Nc6PS53?6D11m Slav: Slav-Reti SystemP[6^FA84 Dutch: Staunton Gambit DeferredPV59~B81g Sicilian: Scheveningen, Keres, Perenyi Attack, 7...h6 8.f4PڽLB15r Caro-Kann: 4.Nxe4 Nf6 5.f3 GambitPQe"IhC50s Giuoco Pianissimo: Italian Four Knights, 5...d6PԪ|f\E16k Queen's Indian: Capablanca, Riumin, 7.Nc3P ]qC13m French: Chatard-Alekhine, 6...Bxg5 7.hxg5 Qxg5 8.Nh3 Qe7 9.Nf4PӜRؤBA57e Benko Gambit: 4.Nf3 Bb7 5.a4P# rbA67k Benoni: Four Pawns, Taimanov, 9.a4 (Zaitsev)P`7\E17v Queen's Indian: Pomar, Taimanov VariationPv GƙUD76k Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O Nb6 8.Nc3 Nc6 9.d5 Na5 10.e4P͚_0>A70d Benoni: Classical, 7...Bg7PxwHE73v King's Indian: Averbakh, 6...h6P!5hE91i King's Indian: 6.Be2 c5 7.d5 e6 8.O-O Re8 9.Nd2P PD41t QGD: Semi-Tarrasch, 7.Bc4 Main LinePMa~NA63 Benoni: Fianchetto, 9...Nbd7 10.Nd2P!*NjB84 Sicilian: Scheveningen, Classical, 7.O-O Qc7 8.a4Po{XNC68g Spanish: Exchange, Keres VariationPSg NC41g Philidor: Hanham, Delmar VariationPA/@@D03c Torre Attack: 3...Ne4 4.Bf4P؏T^C75 Spanish: Modern Steinitz, 5.c3 Bd7 6.d4 Nf6P\>C64a Spanish: Classical DefenceP '|E69t King's Indian: Fianchetto, Classical, 9.h3 Re8 10.Re1 Qc7P{u'%FD17n Slav: Central, 7.f3 Bb4 8.Nxc4Pp5-bD79m Neo-Grnfeld, Main Line, 10.f4 Nc6 11.Be3 f6P[Ê<lD46r Semi-Slav: Chigorin, Main Line, 10...h6 11.Bc2 e5PY4Wg RC89l Spanish: Marshall, Main Line, 13.Re2PAPYn̨K\E03 Catalan: Open, 5.Qa4+ Nbd7 6.Qxc4 a6 7.Nf3P>N30D17a Slav: Czech DefencePGLjD84 Grnfeld: Grnfeld Gambit Accepted, 8...Nc6 9.Ne2O\c:$uyLA46m Indian: 1.d4 Nf6 2.Nf3 e6 3.g3 b5OpsnVE90n King's Indian: 5.Nf3 O-O 6.h3 e5 7.Be3O%fE88f King's Indian: Smisch, Orthodox, PolugayevskyOOkPo&fA31 English: Symmetrical, Two Knights, 4...e5 5.Nb5O타?SfA77 Benoni: Classical, Main Line, 10.Nd2 Nbd7 11.a4OWP4A17 English: Nimzo-EnglishOtZC40u Latvian Gambit: 3.Nxe5 Qf6 4.d4 d6 5.Nc4OY+jW4A61 Benoni: 6.Nf3 g6 7.Bf4OѶؓ0?@B21o Sicilian: Smith-Morra, 3.c3ONhB58m Sicilian: Boleslavsky, 7.Nf3 h6 8.O-O Be7 9.Re1OɎۗ{4D10s Slav: 3.Nc3 Nf6 4.Bg5OƇ&qkx`,C10c French: 3.Nc3 Nc6Oٔ tD36n QGD: Exchange, Main Line, 9.Nge2 Re8 10.O-O Nf8 11.f3OR<A02 Bird: 1..Nf6 2.Nf3 g6 3.g3OG6C37 KGA: Rosentreter GambitOo"!hE35 Nimzo-Indian: Classical, Noa, Exchange, 6.Bg5 c5O/DLC92e Spanish: Closed, Karpov VariationO%aVB04j Alekhine: Modern, Fianchetto VariationO",|JC42m Russian Game: Nimzowitsch AttackOLA45p Trompowsky: 2...c5 3.d5 Qb6 4.Nc3OB( YhD97j Grnfeld: Russian, Alekhine, 8.e5 b5 9.Qb3 Nfd7O*XjsBC13h French: Classical, 5.e5 Nfd7OPnC63q Spanish: Schliemann, 4.Nc3 fxe4 5.Nxe4 Nf6 6.Nxf6+OLRC45i Scotch: 4.Nxd4 Nf6 5.Nxc6 bxc6 6.Bd3OutC48l Four Knights: Rubinstein, Exchange Variation, 8...Bc5Ooᙌ5BBB03r Alekhine: Exchange, 5...cxd6Of _9ZD63 QGD: Orthodox, 7.Rc1 b6, Pillsbury AttackOaJ :gXD20p QGA: 3.e4 Nf6 4.e5 Nd5 5.Bxc4 Nb6 6.Bd3O`^B60f Sicilian: Richter-Rauzer, Larsen VariationO^3dA78 Benoni: Classical, Main Line, 10.Nd2 Na6 11.f4OXKjVA83k Dutch: Staunton Gambit, 4.Bg5 Nc6 5.f3OH$Ձ{PC97g Spanish: Closed, Chigorin, 12...Rd8OG~iDD30t QGD: 3.Nf3 Nf6 4.e3 c6 5.Nbd2ODJJC41x Philidor: Improved Hanham, 7.Re1O@(C60b Spanish: 3...a5O=d/qjE87f King's Indian: Smisch, Orthodox, 7.d5 Nh5 8.Qd2O&y GE97q King's Indian: Mar del Plata, Bayonet, 9...Nh5 10.Re1 Nf4 11.Bf1 a5O!,wmD20l QGA: 3.e4O42A92 Dutch: Alekhine, 7.d5O/STA70n Benoni: Classical, 8.h3 O-O 9.Bd3 Re8O$*I2@B86 Sicilian: Sozin-ScheveningenO >'9~E13n Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.e3 g5 8.Bg3 Ne4 9.Qc2N9Y׎DYFA25 English: Closed, Hort VariationNBbpB61f Sicilian: Richter-Rauzer, Larsen, 7.Qd2 Rc8 8.O-O-ON❶5VB12d Caro-Kann: Maroczy (Fantasy) VariationN% DC42j Russian Game: 3.Nxe5 d6 4.Nf3NشN^D66 QGD: Orthodox, Main Line, 8...h6 9.Bh4 dxc4NӧFwH :XE12c Queen's Indian: Miles, 5.e3 Bb4+ 6.Nfd2N;J;lB80l Sicilian: Scheveningen, English, 7...b5 8.Qd2 Bb7N/YEfB01v Scandinavian: Portuguese, 4.f3 Bf5 5.Bb5+ Nbd7N[DE61j King's Indian: Smyslov SystemNgphB74 Sicilian: Dragon, Classical, 9.Nb3 Be6 10.f4 Rc8NlA22 English: Bremen, Reverse Dragon, 4.cxd5 Nxd5 5.Bg2NŸ[A08 Reti: KIA, French VariationN3P`dH"D20f QGA: 3.e3 e5NۋVQ^E71i King's Indian: Makagonov, 5...O-O 6.Bg5 h6NTD dC95k Spanish: Closed, Breyer, Main Line, 14.Ng3 c5N1|\>D46f Semi-Slav: Chigorin, 7.Qc2NU\ZC00e French: Steiner (Anglo-French) VariationNLY|JE11x Bogo-Indian: 4.Bd2 Bxd2+ 5.Nbxd2N#DQ8D32n QGD Tarrasch: 5.Nf3 Nc6N1;QHC13i French: Chatard-Alekhine AttackN6LJ<C27b Vienna: 3.Bc4 Nxe4 4.Nxe4NzsHHA48n Neo-King's Indian: Torre AttackNQwrFA52i Budapest: Rubinstein, 4...Bb4+NXm HC82n Spanish: Open, Baguio VariationNf0ZC71 Spanish: Modern Steinitz, Noah's Ark TrapN{XOhAC19r French: Winawer, 6...Ne7 7.Nf3 Nbc6 8.a4 Qa5+ 9.Bd2 Bd7 10.Bb5NyI^5TA90 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 d5 5.Nh3Nwo4B14o Caro-Kann: Panov-Botvinnik, 5...e6 6.Nf3 Be7 7.cxd5 Nxd5 8.Bd3Nwz~~LD52l QGD: Cambridge Springs, 8.Qc2 O-ONtC77c Spanish: Anderssen, 5...b5N4sfVBC32 KGD: Falkbeer, 4.d3 Nf6 5.Nc3N0H"߅DD47n Semi-Slav: Meran, Wade, 9.O-ON/_ύpB40q Sicilian: Open, 2...e6, 4.Nxd4 Nf6 5.Bd3 Nc6 6.Nxc6N,C}\NC23 Bishop's Opening: MacDonnell GambitN# rC17s French: Winawer, Swiss, 6.b4 cxd4 7.Nb5 Bc7 8.f4 Bd7N'6hE95g King's Indian: 7.O-O Nbd7 8.Re1 exd4 9.Nxd4 Nc5N/M٨tE38f Nimzo-Indian: Classical, 4...c5 5.dxc5 Bxc5 6.Nf3 Qb6N=Π"jfE09e Catalan: Closed, Main Line, Sokolsky VariationN_ͧ(A80k Dutch: 2.Nc3 d5Nur%p2D32d QGD Tarrasch: 4.cxd5MSRZ(A80g Dutch: 2.Bg5 g6MAYo1BD78c Neo-Grnfeld, 6.O-O c6 7.Ne5M^-֋$D80 Grnfeld: 4.h4Ma_~+RA30p English: Symmetrical, Hedgehog, 7.b3MGLD35e QGD: Exchange, 5.Nf3 Nbd7 6.e3 c6MIvB78l Sicilian: Dragon, Yugoslav, Main Line, 12.h4 h5 13.Bh6MMש 8B66n Sicilian: Richter-Rauzer, 7...a6 8.O-O-O h6 9.Be3 Be7 10.f3 Nxd4 11.Bxd4M[D$ȠnC74 Spanish: Modern Steinitz, Siesta, Kopayev VariationMۨ~ZC12e French: MacCutcheon, Grigoriev VariationMᔜ)njD59i QGD: Tartakower, 8.cxd5 Nxd5 9.Bxe7 Qxe7 10.Nxd5M{<,5uB85 Sicilian: Scheveningen, Classical, Main Line, 9...Nc6 10.Kh1Mg{cPC67h Spanish: Open Berlin, 5...Be7 6.Qe2M=!LD77h Neo-Grnfeld, 6.O-O dxc4 7.Na3 c3M?S*A03 Bird: 1...d5 2.b3Ms&tBE89g King's Indian: Smisch, Orthodox Main Line, 10.Qd2 a6 11.g4Mt}NE18o Queen's Indian: 7.Nc3 Ne4 8.Bd2 f5M̧*<>D50 QGD: Dutch-Peruvian, 5.cxd5M5 <A80o Dutch: 2.Nc3 Nf6 3.Bg5 d5M_ tB13y Caro-Kann: Panov-Botvinnik, 5...Nc6, Normal VariationMI݂HE06 Catalan: Closed, 6.O-O c6 7.Nbd2M+ȱrE69p King's Indian: Fianchetto, Classical, 9.h3 Re8 10.b3MWVB12h Caro-Kann: Gurgenidze/Modern: 3.Nd2 g6MhWSlB45r Sicilian: Taimanov, Four Knights, 6.Ndb5 Bb4 7.a3MZz$A00v Benko OpeningMyNB6D23e QGA: Mannheim, 4...Nc6Ms)nE71o King's Indian: Makagonov, 5...O-O 6.Bg5 c5 7.d5 e6Mp~aWnC76 Spanish: Modern Steinitz, Bronstein, 7.O-O Bg7 8.d5MG@A02 Bird: 1..g6MD1s0A10 English: Anglo-DutchM@<0o^C12r French: MacCutcheon, Main Line, 11.Nf3 Nc6M@T,A02 Bird: Swiss GambitM>_6A24 English: Bremen, 3...g6M:xLpC74 Spanish: Modern Steinitz, Siesta, Kopayev, Main LineM,1ط 4C91a Spanish: Closed, 9.d4M+¥+jD:C64b Spanish: Classical, 4.c3M(D`A87 Dutch: Leningrad, Main Line, 7.Nc3 Qe8 8.Nd5M%@z=jtB33v Sicilian: Pelikan, Sveshnikov, 11.c3 Bg7 12.exf5 Bxf5M$ ,C^TD58h QGD: Tartakower, 8.Bd3 Bb7 9.O-O Nbd7M#1k>C41g Philidor: Hanham, 4.Bc4 c6M @X:C20 Open Game: Alapin OpeningMA-tXA30f English: Symmetrical, Double FianchettoMe̡}#<B89 Sicilian: Sozin, 7.Be3 Be7M!pB79a Sicilian: Dragon, Yugoslav, Old Main Line, 12.h4 h5Mzq#RnE39k Nimzo-Indian: Classical, Pirc, 6.a3 Bxc5 7.Nf3 Nc6MJ@C10g French: Rubinstein, 4...Nf6M;>X@A73 Benoni: Classical, 9.O-O Bg4LbhB81r Sicilian: Scheveningen, Keres, 6...Nc6 7.g5 Nd7L+>CRC40m Latvian Gambit: 3.d4 fxe4 5.Nxe5 Nf6L?rL(D09 QGD: Albin, 5.g3Lm6B07h Pirc: 3.Bd3 e5 4.c3 d5LN&A25 English: ClosedLp1E97k King's Indian: Mar del Plata, Bayonet Attack, 9...a5 10.Ba3 axb4LjLWRB13p Caro-Kann: Panov-Botvinnik, 5...dxc4L*D YrE76j King's Indian: Four Pawns Attack, 6.Nf3 Na6 7.Bd3 e5L?M6xC40p Latvian: Blackburne Variation (Corkscrew Countergambit)L ˆ nB32y Sicilian: Lowenthal, Kalashnikov, Main Line, 9.Be2LoF+<A02 Bird: 1..Nf6 2.Nf3 g6 3.g3Lص!PC01e French: Exchange, 4.c4 Nf6 5.Nc3 c6Lb0oPA49 Neo-King's Indian: Fianchetto SystemLqb' HD00l Blackmar-Diemer: Zeller DefenceL/̈́VE12r Queen's Indian: Petrosian, 6.cxd5 Nxd5L߀jE74l King's Indian: Averbakh, 6...c5 7.d5 h6 8.Be3 e6LmZJB25h Sicilian: Closed, 6.f4 Nf6 7.Nf3LqA>A86 Dutch: Leningrad, 4.Bg2 Bg7LzdC97c Spanish: Closed, Chigorin, 11.d4 Qc7 12.d5 c4L9*ze<C41r Philidor: Improved HanhamLEG*y:A04 Reti: Lisitsin: 3.Ng5 Nf6L hBD17o Slav: Central, 7.f3 Bb4 8.e4L{^ةrE89d King's Indian: Smisch, Orthodox Main Line, 9...Nbd7Lj5 D10i Slav: 3.Nc3LcB)<D43o Semi-Slav: Moscow, 6.Bxf6LbϛLB38b Sicilian: Maroczy Bind, 6.Be3 Nh6L]:W B07k Pirc: 3.Nc3L[*4A07 Reti: KIALVRgZ}2D38e QGD: Ragozin, 5.cxd5LTZA36o English: Symmetrical, Botvinnik, 5...Nf6LPV)XVA41s Neo-Old Indian: Modern, 3.Nf3 Bg7 4.e4LK%7>D93 Grnfeld: 5.Bf4 O-O 6.e3 c6L@}n'3qVA67b Benoni: Four Pawns, Taimanov, 8...Nbd7L7T&Zh4A45a Indian: Arafat GambitL.rbC02u French: Advance, 5.Nf3 Qb6 6.Be2 cxd4 7.cxd4L*eRnRD45v Semi-Slav: 6.Qc2 Bd6 7.Be2 O-O 8.O-OL*po^+LD22h QGA: Alekhine, 4.e3 Bg4 5.Bxc4 e6L)LfD83 Grnfeld: Grnfeld Gambit, Capablanca VariationL(u`:E02 Catalan: Open, 5.Qa4+ Bd7L `HzC47m Four Knights: Belgrade Gambit, 5...Nxe4 6.Qe2 (Old Line)L恞BVC89d Spanish: Marshall, 9.exd5 Nxd5 10.Nxe5LbE03 Catalan: Open, 5.Qa4+ Nbd7 6.Qxc4 c5 7.Nf3 a6LN%v8C58c Two Knights: Morphy, Kieseritsky Variation, 6...h6 7.Nf3 e4 8.Qe2L磲k;HD66 QGD: Orthodox, Main Line, 8...a6L &*L{4C02i French: Advance, WadeK[칩XA40y Queen's Pawn: Modern, Beefeater DefenceKב,P`E79a King's Indian: Four Pawns Attack, Main LineKnqXE39a Nimzo-Indian: Classical, Pirc VariationK/c5HN:C29o Vienna Gambit: 5.Nf3 Bg4K='dB66e Sicilian: Richter-Rauzer, 7...a6 8.O-O-O Nxd4K@̡KbVC56l Two Knights: Classical, Moller, 10.Bd2K'|>E12f Queen's Indian: Petrosian, 4...c5 5.d5 Ba6 6.Qc2 exd5 6.cxd5 g6K}м"A80j Dutch: 2.Nc3K0 JD11f Slav: 3.Nf3 dxc4 4.e3 b5 5.a4 e6KXܣ]kVA41f Neo-Old Indian: Wade Defence, 3.e3 Nf6K~K&:A10 English: 1...b6 2.Nf3 Bb7Ka >D18o Slav: Dutch, 8...O-O 9.Qb3KޚS\A31 English: Symmetrical, Two Knights, 4...Nc6K%poDfB47j Sicilian: Taimanov, 6.g3 a6 7.Bg2 d6 8.O-O Bd7K d+JA06 Reti: Nimzowitsch-Larsen, 2...Bg4K| |2A54 Old Indian: 5.Bg5 Be7KwWYqBD31k Semi-Slav: 4.cxd5 exd5 5.Nf3Ku5BvnB22d Sicilian: Alapin, 2...e6 3.d4 d5 4.exd5 exd5 5.Nf3Kt&ФZC41w Philidor: Improved Hanham, 7.Qe2 c6 8.a4KqF5^D95f Grnfeld: 5.e3 O-O 6.Qb3 c6 7.Bd2 e6 8.Bd3Kh%ClB84 Sicilian: Scheveningen, Classical, 7.O-O Nbd7 8.f4K`ly!^C58b Two Knights: Morphy, Kieseritsky VariationKVG:DbE16g Queen's Indian: Capablanca, Yates, 7.O-O O-OKOS|6A56q Benoni: Czech, 5.e4 g6KLe4ZC19i French: Winawer, 6...Ne7 7.Nf3 b6 8.Bb5+KCjhE60l King's Indian: Fianchetto, Yugoslav without Nc3KBu\C66 Spanish: Closed Berlin, Chigorin VariationK@BV<B25o Sicilian: Closed, 6.f4 e6K6uVC12d French: MacCutcheon, Advance VariationK.o`D32v QGD Tarrasch: 5.Nf3 Nc6 6.e3 Nf6 7.Be2 cxd4K+_@C63b Spanish: Schliemann, 4.exf5Kn[ΥjB33y Sicilian: Pelikan, Sveshnikov, 11.Bd3 Be6 12.O-OK 3\B25d Sicilian: Closed, 3.g3, 5.d3 d6 6.Nge2 e6K8D20w QGA: 3.e4 e5 4.Nf3 Bb4+KWD몡JA83g Dutch: Staunton Gambit, 4.Bg5 e6K`8/2PD31w Semi-Slav: Marshall Gambit, 4...Bb4JgM{VE56 Nimzo-Indian: Main Line, 7...Nc6 8.cxd5JcI@D06p QGD: 2...Bf5 3.Nf3 e6 4.Nc3J0qwRB01t Scandinavian: Icelandic Gambit, 5.d4Jܜ+nE75b King's Indian: Averbakh, 7.d5 e6 8.Nf3 exd5 9.exd5J@LA85 Dutch: 2.c4 Nf6 3.Nc3 g6 4.Nf3 Bg7Jn߸,jB76l Sicilian: Dragon, Yugoslav, 9.O-O-O Nxd4: 11.Kb1JY:D09 QGD: Albin, 5.g3 Be6 6.b3Jڴ0 B00a King's PawnJ o]b~*A00s Polish: 2...Bxb4J/8RYD48g Semi-Slav: Meran, 8...a6 9.O-O Bb7 10.e4 c5 11.d5 Qc7 12.dxe6J+6B06n Modern: 3.Nc3 d6 4.Bc4JE(QufB99p Sicilian: Najdorf, Main Line, 10.g4 b5 11.Bxf6JdH2D02p Queen's Pawn: LondonJ <LC41g Philidor: Hanham, Kmoch VariationJ wO^E70q King's Indian: 4.e4 d6 5.Bd3 O-O 6.Nge2 e5J>/)8C01k French: Exchange, 4.Nf3J1&]k|E69l King's Indian: Fianchetto, Classical, 9.h3 Qb6 10.Re1 Re8J rJB91g Sicilian: Najdorf, 6.g3 e5 7.Nb3JcdE52 Nimzo-Indian: Main Line, 6...b6 7.O-O Bb7 8.a3Jz NA01 Nimzowitsch-Larsen: Dutch VariationJu}kPC27j Vienna: Frankenstein-Dracula, 11.d3Jre$C01d French: Exchange, 4.c4 Nf6IZlHC55w Two Knights: Max Lange, 6.e5 d5IG$^&zD03r Torre Attack: 3...g6 4.e3 Bg7 5.Nbd2 O-O 6.c3 Nbd7 7.Be2I}"hE76e King's Indian: Four Pawns Attack, 5...O-O 6.Nf3I6xB92n Sicilian: Najdorf, 6.Be2 e5 7.Nb3 Be7 8.O-O O-O 9.Be3 Be6 10.Qd2I?'0B00g Owen Defence: 3.Bd3I]iTB06e ModernI"^PnC30i King's Gambit: Adelaide-Wahls, 4.exf5 e4 5.Ne5 Nf6Ix14VB32o Sicilian: Lowenthal, Kalashnikov, 6.a4I!NB6A40i Englund Gambit: SollerI}R!BD63 QGD: Orthodox, 7.Rc1 h6 8.Bh4IePW [fV`A69h Benoni: Four Pawns, Main Line, 10.e5: 12.e6IdE;hA34 English: Symmetrical, 3 Knights, 5.e4 Nb4 6.Bb5+Id:5v\TE61u King's Indian: Smyslov System, 5...d6I^XPC19l French: Winawer, 6...Ne7 7.Nf3 Nbc6IU]OE8D56 QGD: Neo-Orthodox, 7.Bh4I=TJC23 Bishop's Opening: Pratt VariationI0[yrB36k Sicilian: Maroczy Bind, 5...Nf6 6.Nc3 d6 7.Be2 Nxd4 8.Qxd4 Bg7 9.Bg5I#,jrcJE90g King's Indian: Zinnowitz, 6...h6ItR.E69x King's Indian: Fianchetto, Classical, 9.h3 Re8 10.Re1 exd4, 11...Nc5I&&;fC08b French: Tarrasch, Open, 4.exd5 exd5 5.Bb5+ Nc6ItB66k Sicilian: Richter-Rauzer, 7...a6 8.O-O-O h6 9.Be3 Bd7IdD71 Neo-Grnfeld, 5.cxd5 Nxd5 6.Nc3 Nxc3 7.bxc3 c5I-/`rC76 Spanish: Modern Steinitz, Bronstein, 7.O-O Bg7 8.dxe5HP#8A45m Trompowsky: 2...e6 3.e3H2æDD57 QGD: Lasker Defence, Main LineH55ԮrC84j Spanish: Closed, Centre Attack, 7.e5 Ne4 8.Nxd4 Nxd4Hs)fDD35l QGD: Exchange, 5.Bg5 c6 6.Nf3Hɓ̠"<D85a Grnfeld: Exchange, 5.Na4H2:^B59g Sicilian: Boleslavsky, 7.Nb3 Be7 8.O-O O-OH]6j) B07a Pirc: 2.Nc3HZG lB47y Sicilian: Taimanov, 6.Be2 a6 7.O-O Nf6 8.Kh1 Nxd4HW[.#@B19a Caro-Kann: Classical, 7.Nf3HrpmhE65b King's Indian: Fianchetto, Yugoslav, 7.O-O cxd4H~a,A47 Neo-Queen's IndianHk ~4C25j Vienna: 2...Nc6 3.Bc4HIX b|B92q Sicilian: Najdorf, 6.Be2 e5 7.Nb3 Be7 8.O-O O-O 9.Kh1 Nc6HrkHA82 Dutch: Staunton Gambit, 3.Nc3 e6HRF1rE69i King's Indian: Fianchetto, Classical, 9.h3 Qb6 10.d5H V?tTB17j Caro-Kann: Steinitz, 5.Ng5 Ngf6 6.Bd3H \NC16a French: Winawer, Advance VariationHMNB00v Nimzowitsch Defence: Aachen GambitHpQ8fD62 QGD: Orthodox, Rubinstein, 7.Qc2 c5 8.cxd5 cxd4HX3VE91l King's Indian: Kazakh Variation, 7.Bg5HQ-4lRB81a Sicilian: Scheveningen, Keres AttackHE{vKvB49j Sicilian: Taimanov, 6.Be3 a6 7.Be2 Nf6 8.O-O Bb4 9.Na4H<ƛmw`<^C67h Spanish: Open Berlin, Trifunovic VariationHX<DD37g QGD: 4.Nf3 Be7 5.e3 O-O 6.Bd3H`!q:B57b Sicilian: Sozin, 6...Bd7H~X|`C83 Spanish: Open, Classical, 10.Nbd2 O-O 11.Bc2H\ }6A80n Dutch: 2.Nc3 Nf6 3.Bg5Gz:O(JC05r French: Tarrasch, Closed, 7.Ngf3G>D24s QGA: Bogoljubow, 7.a4 Nxc3G%UZB75 Sicilian: Dragon, Yugoslav, 7...Nc6 8.Qd2G휳#<A43v Old Benoni: Schmidt, 6.h3Gr;CjDD48h Semi-Slav: Meran, 8...a6 9.e4Gݖ.PC36 KGA: Scandinavian, Modern, 5.Bb5+ c6GGy!VE04g Catalan: Open, 5.Nf3 a6 6.O-O b5 7.Ne5GDŽXD00k Trompowsky: 2...d5 3.Bxf6 exf6 4.e3 Be6GۈC'0A34 English: SymmetricalG4(,\RC23 Bishop's Opening: Lewis CountergambitG~O&6B20 Sicilian: 2.d3 Nc6 3.g3GԌ.C00w French: St. GeorgeGQ٤ B07a PircGH1 A04 Reti: 1...c5G2bRj`E87d King's Indian: Smisch, Orthodox, 7.d5 Nbd7GvʨC15v French: Winawer, Alekhine Gambit, 5.a3 Be7 6.Nxe4 Nf6 7.Qd3Gٲ9lVE12e Queen's Indian: Petrosian, 4...c5 5.d5G<|dC23 Bishop's Opening: Lewis Countergambit, JnischG| nXsc>D44c Semi-Slav: Botvinnik, 6.e4Gx" ::C05a French: Tarrasch, ClosedGuw*Ù=ND29g QGA: Classical, 8...Bb7 9.Rd1 Nbd7Gp~̬@A00s Polish: 2...Bxb4 3.Bxe5 Nf6GhC(A10 English: 1...Nc6G_5sORA29 English: Four Knights, 4.g3 d5 5.cxd5GZ"!(@B70f Sicilian: Dragon, 6.Bc4 Bg7GY9fp^A87 Dutch: Leningrad, Main Line, 7.Nc3 Qe8 8.d5GD:֭^E68a King's Indian: Fianchetto, Classical, 8.e4G>MIs `C89d Spanish: Marshall, 9.exd5 Nxd5 10.Nxe5 Nxe5G<lZY_8D63 QGD: Orthodox, 7.Rc1 Re8GD96 Grnfeld: Russian, 5...dxc4G;Ĩ]?RE53 Nimzo-Indian: Main Line, 6...c5 7.O-OG2e_YND22b QGA: Alekhine, Haberditz VariationG1A<XD17t Slav: Central, Main Line, 15.Nxc4 O-O-OG*;VE42 Nimzo-Indian: 4.e3 c5 5.Ne2 cxd4 6.exd4G*͢(vfC59k Two Knights: Main Line, 11.d4 exd3 12.Nxd3 Qc7G(oY;O^A56t Benoni: Czech, 5.e4 Be7 6.g3 O-O 7.Bg2 Ne8G#կNE04t Catalan: Open, 5.Nf3 Nc6 6.O-O Rb8G WNDD39d QGD: Ragozin, Vienna, 6.e4 c5G'z&HD34h QGD Tarrasch: Tarrasch's GambitG pehE71m King's Indian: Makagonov, 5...O-O 6.Bg5 c5 7.d5G ( 4TC33 KGA: Bishop's Gambit, Bledow VariationG^2YXB52c Sicilian: 3.Bb5+ Bd7 4.Bxd7+ Nxd7 5.O-OGJS:)hE75d King's Indian: Averbakh, 7.d5 e6 8.Nf3 h6 9.Bh4FΚNM~B85 Sicilian: Scheveningen, Classical, Main Line, 9...Nc6 10.a4FسǵdE74k King's Indian: Averbakh, 6...c5 7.d5 h6 8.Be3Fإ酋mPB00l Nimzowitsch Defence: Wheeler GambitF֫fLb|E96 King's Indian: 7.O-O Nbd7, Old Main Line, 10.Rb1 Re8 11.d5 Nc5 12.b3Fѩ#آWjC24 Bishop's Opening: Urusov Gambit, Larsen VariationFޔqAt@B05g Alekhine: Modern, 5.Be2 Nc6Fİ>A43k Old Benoni: 2.d5 Nf6 3.Nc3Fw d=:A40i Englund Gambit: HartlaubFXJPB95l Sicilian: Najdorf, 6...e6 7.Qf3 Be7FONB47t Sicilian: Taimanov, 6.Be2 a6 7.O-OF͖f@ZA40q Queen's Pawn: Keres Defence, 3.Bd2 Bxd2+FZupB61h Sicilian: Richter-Rauzer, Larsen, Main Line, 10.Bd2F|B17l Caro-Kann: Steinitz, 5.Ng5 Ngf6 6.Bd3 e6 7.N1f3 Bd6 8.Qe2F˱ bE45 Nimzo-Indian: Nimzowitsch, 5.Ne2 Ba6 6.Ng3 h5FMhfB81k Sicilian: Scheveningen, Keres, 6...h6 7.h4 Be7FG_T8C42g Russian Game: 3.Nxe5 d6F(TVB59d Sicilian: Boleslavsky, 7.Nb3 Be7 8.Bg5Fe 58C90a Spanish: Closed, 8...d6Fk c |E95n King's Indian: 7.O-O Nbd7 8.Re1 c6 9.Bf1 exd4 10.Nxd4 Re8F`쬴G>C51 Evans Gambit Accepted, 5.c3F`.d5dC13r French: Chatard-Alekhine, Breyer, 7.Bxe7 Kxe7F[˜nC17p French: Winawer, Swiss, 6.b4 cxd4 7.Qg4 Ne7 8.bxa5F4es0A03 Bird: Lasker, 3...g6F)nS7KfE15i Queen's Indian: Nimzowitsch, 5.Qa4 c6 6.Nc3 b5F&X_ZzB22u Sicilian: Alapin, 2...Nf6, 5.cxd4 d6 6.Nf3 Nc6 7.Bc4 Nb6F#2c\D68 QGD: Orthodox, Classical, Vidmar VariationFe}PE97t King's Indian: Mar del Plata, 9.Nd2F<rbD65 QGD: Orthodox, Rubinstein Attack, 9.cxd5 Nxd5FBD31i Semi-SlavF (iLC29e Vienna Gambit: Steinitz VariationF nTPPC85l Spanish: Closed, Exchange, 7.d3 Nd7Êd(D11c Slav: 3.Nf3 Bf5Ei#IE4C88q Spanish: Closed, 8.c3Er3D59f QGD: Tartakower, 8.cxd5 Nxd5 9.Bxe7 Qxe7 10.Rc1 Bb7 11.Nxd5 Bxd5EÇEVRA30p English: Symmetrical, Hedgehog, 7.b3Ejje^C03k French: Tarrasch, 3...Be7 4.Ngf3 Nf6 5.Bd3E$ޏp@C68c Spanish: Exchange, 4...bxc6E ~2C42g Russian Game: 3.Nxe5EVXkE57 Nimzo-Indian: Main Line, 8...dxc4 9.Bxc4 cxd4 10.exd4 Be7 11.Be3Eӄ\<hD23m QGA: Mannheim, 4...c6, 5.Qxc4 Bf5 6.g3 e6 7.Bg2E+! >C62 Spanish: Old Steinitz, 4.c3EWm̮@B26g Sicilian: Closed, 6.Be3 Rb8EÊrW\ZB97n Sicilian: Najdorf, Poisoned Pawn, 10.Be2E A05 Reti: KIAERŕmbFA43s Old Benoni: Schmidt, 3.Nc3 Nf6EQi^&\B00w Nimzowitsch Defence: Bogoljubow VariationE{z5!k8A40i Englund Gambit AcceptedEâ%"D50 QGD: 4.Bg5 c6E}.#B78m Sicilian: Dragon, Yugoslav, Main Line, 12.h4 h5 13.Bh6 Bxh6Ea⼵jA55e Old Indian: 5.e4 Be7 6.g3 c6 7.Bg2 O-O 8.O-O Qc7ERD30i QGD: Tarrasch without Nc3: Main LineE{AJC28o Vienna: 3.Bc4 Nc6 4.d3 Bb4 5.Bg5EWW\BxB78f Sicilian: Dragon, Yugoslav, Main Line, 12.Kb1: 14.g4 b5E"_\E93 King's Indian: Petrosian, Main Line, 8.Bg5Eš6D78a Neo-Grnfeld, 6.O-O c6E`˵bWZB20 Sicilian: Wing Gambit, Carlsbad VariationE~v#4>B12j Caro-Kann: Advance, 3...c5Eu7\C4RB03l Alekhine: Four Pawns Attack, 6...Bf5EY*TB58j Sicilian: Boleslavsky, 7.Nf3 h6 8.O-OEW:'FD03f Torre Attack: 3...e6 4.e3 Nbd7EN$O=HC90f Spanish: Closed, Pilnik, 9...h6E<5nC84p Spanish: Closed, Centre Attack, 7.Re1 O-O 8.e5 Ne8E7t"m:A21 English: King's, 2.Nc3 g6E.n4mNE11q Bogo-Indian: Nimzowitsch, 5.g3 O-OE"9RE22 Nimzo-Indian: Spielmann, 4...c5 5.Nf3E"ٽ*LD78m Neo-Grnfeld, 6.O-O c6 7.Nbd2 Ne4E7Dن 8dB08s Pirc: Classical, 5.Be2 O-O 6.O-O c6 7.a4 Nbd7E#f`D77h Neo-Grnfeld, 6.O-O dxc4 7.Na3 c3 8.bxc3 c5E #b(B12a Caro-Kann: 2.d4EՒ1JD26j QGA: Classical, Furman VariationE2FD03f Torre Attack: 3...e6 4.e3 Nbd7E/;,C39 KGA: 3.Nf3 g5 4.h4D8ۢXC15k French: Winawer, 4.a3 Bxc3+ 5.bxc3 dxe4D(z$NA41j Neo-Old Indian: Wade Defence, 3.e4DqJLN4D07c QGD: Chigorin, 3.cxd5Dn@?JA87 Dutch: Leningrad, Main Line, 7.d5DE):*BA90 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2DZE02 Catalan: Open, 5.Qa4+ Nbd7 6.Nf3 a6 7.Nc3D#C\DVD32s QGD Tarrasch: 5.Nf3 Nc6 6.e3 Nf6 7.Bb5DPNBA13s English: Neo-Catalan, 4...c6DfUA84 Dutch: 2.c4D}6A24 English: Bremen, 3...g6D^2C51 Evans Gambit DeclinedDHBD03j Torre Attack: 3...e6 4.e3 c5D-KRB12e Caro-Kann: Maroczy (Fantasy), 3...e6DޏntzB70u Sicilian: Dragon, 6.Be2 Bg7 7.O-O O-O 8.Bg5 Nc6 9.Nb3 a6D|6fC08d French: Tarrasch, Open, 4.exd5 exd5 5.Bb5+ Bd7DuoVUAXE04o Catalan: Open, 5.Nf3 c5 6.O-O Nc6 7.Qa4Dq!AtE99 King's Indian: Mar del Plata, 10.f3 f5 11.Be3 f4 12.Bf2 g5 13.a4Dg~nSJE80d King's Indian: Smisch, 5...Nbd7DbCX,A48b Neo-King's IndianDb1tJB59b Sicilian: Boleslavsky, 7.Nb3 Be6D_\fC89t Spanish: Marshall, Main Line, Classical, 18.c4DSH 4LC06g French: Tarrasch, Closed, 8...Qb6DC.;dtA89 Dutch: Leningrad, Main Line, 7.Nc3 Nc6 8.d5 Ne5 9.Nxe5D<"l$^B71 Sicilian: Dragon, Levenfish, 6...Nc6 7.Nxc6D< 7~>|B13t Caro-Kann: Panov-Botvinnik, 5...Nc6 6.Nf3 Bg4: 9.gxf3 Nb6D:kHNC19j French: Winawer, 6...Ne7 7.Nf3 Bd7D2$8`=:^A92 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nf3 O-OD&1~A69m Benoni: Four Pawns, Main Line, 10.e5: 12.Bg5 Qb6 13.O-O Nxe5 14.d6DjΆ9}dE80p King's Indian: Smisch, 5...c6 6.Be3 a6 7.Bd3D$eV*C00f French: 2.Nc3 d5Dt`z1UlA35f English: Symmetrical, 2.Nc3 Nc6 3.Nf3 g6 4.e3 Bg7D'&ybDD12k Slav: 4.e3 Bf5 5.Nc3 e6 6.Bd3D郕RC96k Spanish: Closed, Chigorin, 11.d4 Bb7D?DA68h Benoni: Four Pawns, 9.Be2 Bg4CJD36g QGD: Exchange, 6.Qc2 Be7 7.e3 h6C@/ZE76b King's Indian: Four Pawns Attack, 5...c5CXt#2A40x Queen's Pawn: ModernC/ zpC87l Spanish: Closed, Averbakh, 7.c3 O-O 8.d4 Bd7 9.Nbd2C7ǯA6B00i Owen Defence: 3.Bd3 e6Cu1dC86k Spanish: Worrall Attack, 7...O-O 8.c3 d5 9.d3Cg~14C40o Latvian Gambit: 3.Bc4C;<E17c Queen's Indian: 6.Nc3 O-OC0/p<C45h Scotch: 4.Nxd4 Nf6 5.Nxc6CJifE81k King's Indian: Smisch, 5...O-O 6.Be3 a6 7.Qd2C4rD62 QGD: Orthodox, Rubinstein, 7.Qc2 c5 8.cxd5 exd5 9.Bd3C;ҾZD49f Semi-Slav: Meran, Sozin, Rellstab AttackC^ϋB45n Sicilian: Taimanov, Four Knights, 6.Nxc6 bxc6 7.e5 Nd5 8.Ne4 Qc7C IštB22r Sicilian: Alapin, 2...Nf6 3.e5 Nd5 4.d4 cxd4 5.Nf3 e6Ck%<~"s`A50b Indian: Mexican Defence (Two Knights Tango)CU0FA80b Dutch: Krejcik Gambit AcceptedCiN9DD30a Queen's Gambit Declined (QGD)CZJ B07t Pirc: 4.Be3CMyqrB85 Sicilian: Scheveningen, Classical, Main Line, 9...Qc7CEm_k4A43n Old Benoni: Neo-BenkoCAo&dE68j King's Indian: Fianchetto, Classical, 8.e4 c6CA]RB33e Sicilian: Pelikan/Sveshnikov, 6.Nbd5C>m+yZFC54m Giuoco Piano: Krause VariationC8P3nTB50r Sicilian: 2.Nf3 d6 3.c3 Nf6 4.Bd3 Nc6C4M׆r%ND26q QGA: Classical, Steinitz VariationC3V <C25j Vienna: 2...Nc6 3.Bc4 Bc5C-vbB61c Sicilian: Richter-Rauzer, Larsen, 7.Qd2 Nxd4C+)&}TZA99 Dutch: Ilyin-Zhenevsky, 8.b3 a5 9.Bb2 Na6CA&^D52o QGD: Cambridge Springs, 8.Qc2 O-O 9.Be2 e5C$y]FD79k Neo-Grnfeld, Main Line, 10.f4C阑y!Q@C43b Russian Game: Modern AttackB_NtC83 Spanish: Open, Classical, 10.Nbd2 O-O 11.Bc2 f5 12.Nb3Bht_&6D05k Colle: 5.c3 Nc6 6.Nbd2Bs,KsxD36x QGD: Exchange, Main Line, 9.Nf3 Re8 10.O-O Nf8 11.h3 g6Bg},>A03 Bird: 1...d5 2.Nf3 Nf6 3.g3B! *ZB17k Caro-Kann: Steinitz, 5.Ng5 Ngf6 6.Bd3 e6Bэj5BA82 Dutch: Staunton Gambit, 3.Nc3Bۮ/A05 Reti: KIABU~D89c Grnfeld: Classical Exchange, Main Line, 13.Bd3 Be6 14.Rc1BԒOT6jB38n Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 d6 9.O-OBώ y,A47 Neo-Queen's IndianBQpE36 Nimzo-Indian: Classical, Noa, 5.a3 Bxc3+ 6.Qxc3 dxc4B9^A13v English: Neo-Catalan Accepted, 5.Qa4+ Nbd7B npYFB19b Caro-Kann: Classical, 7.Nf3 e6B Y xA77 Benoni: Classical, Main Line, 10.Nd2 Nbd7 11.a4 a6 12.h3BBDULA93 Dutch: Stonewall, Botvinnik, 8.Bb2B2=cXC89j Spanish: Marshall, 12.d3 Bd6 13.Re1 Qh4B|k0C33 KGA: Bishop's GambitBcjB72 Sicilian: Dragon, Classical, Nottingham VariationB( FDA85 Dutch: 2.c4 Nf6 3.Nc3 e6 4.Nf3BUE18v Queen's Indian: 7.Nc3 Ne4 8.Nxe4 Bxe4 9.Ne1 Bxg2 10.Nxg2 d5 11.Qa4B>@fC08j French: Tarrasch, Open, 4.exd5 exd5 5.Ngf3 Nf6B:$^<FD53m QGD: 4.Bg5 Be7 5.Nf3 O-O 6.Qc2BE[7f\E42 Nimzo-Indian: 4.e3 c5 5.Ne2 cxd4 6.exd4 d5BdU)hD47p Semi-Slav: Meran, Wade, 9.O-O b4 10.Ne4 Be7 11.Nxf6+ Nxf6 12.e4BWI>PC95b Spanish: Closed, Breyer, 10.d4 Nbd7Bқ9tPC41g Philidor: Hanham, Steiner VariationB`kpD67 QGD: Orthodox, Main Line, Alekhine, 11...e5 (Lasker)B{+#<A80n Dutch: 2.Nc3 Nf6 3.Bg5 e6B{'q,r8D20x QGA: 3.e4 e5 4.Nf3 exd4Bz, bD79d Neo-Grnfeld, 6.O-O c6 7.cxd5 cxd5 8.Nc3 Ne4ByiF8C45j Scotch: Mieses, 6...Qe7Bwjxt8A21 English: Lukin VariationBn/UVD42b QGD: Semi-Tarrasch, 6.e3 Nc6 7.Bd3 Be7Bm/SC67x Spanish: Open Berlin, 5.d4 Nd6 Queenswap, 9.Nc3 Ke8 10.h3 a5B`I]PC23 Bishop's Opening: Philidor VariationB_1xjB68 Sicilian: Richter-Rauzer, 7...a6, 9.f4 Be7 10.Nf3BZݲA>A55i Old Indian: 5.e4 Be7 6.Be2BTOL6C80n Spanish: Open, 8...Be6BHF\FNE08f Catalan: Closed, 7.Qc2 c6 8.Rd1 b6B;FjA38r English: Symmetrical, Main Line, 7.d3 d6 8.a3 a6B3=gFA27 English: Three Knights, 3...Bb4B.PlC05g French: Tarrasch, Closed, 5.f4 c5 6.c3 Nc6 7.Ndf3B*vۛ/ZE19f Queen's Indian: Old Main Line, 9.Qxc3 f5B'+JJNB01v Scandinavian: Portuguese, 4.f3 Bf5B$_5RxB97u Sicilian: Najdorf, Poisoned Pawn, Main Line, 13.e5 dxe5BOFhhD42l QGD: Semi-Tarrasch, 7.Bd3 Main Line, 10.Re1 Nf6BxɸHD46c Semi-Slav: Bogoljubow VariationA7K"<B06q Modern: 3.Nc3 d6 4.Be3 c6A rND97g Grnfeld: Russian, Alekhine, 8.Qb3AFB12a Caro-Kann: de Bruycker DefenceAMz:A43i Old Benoni: 2.d5 e6 3.c4AiɈ>ylE04n Catalan: Open, 5.Nf3 c5 6.O-O Nc6 7.Ne5 Bd7 8.Na3A;0D20c QGA: 3.e3 c5 4.Bxc4APE^B19m Caro-Kann: Classical, Spassky, 10.Qxd3 Qc7A $C00f French: 2.Nc3AR`i8TA38h English: Symmetrical, Main Line, 7.b3AB>|8C44r Scotch: Lolli VariationA^VZB00v Nimzowitsch Defence: 2.d4 d5 3.exd5 Qxd5AL%\A88 Dutch: Leningrad, Main Line, 7.Nc3 c6 8.d5A(@B32k Sicilian: Lowenthal, 5...a6A'e[ԉRE16e Queen's Indian: Capablanca, 6.Bd2 c5A ,lXgBD00o Queen's Pawn: Veresov, 3.Bf4AG/d@E94g King's Indian: Donner, 8.d5A\\dgA05 Reti: KIAAc,9CLB33k Sicilian: Pelikan, Bird VariationAɣJ~B38t Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 d6 9.O-O Bd7 10.f3A)0\jE96 King's Indian: 7.O-O Nbd7, Old Main Line, 10.dxe5APX4D15j Slav: Chameleon, 5.c5Ar4A12 English: Torre DefenceAw!?XA46l Indian: 1.d4 Nf6 2.Nf3 e6 3.e3 c5 4.Bd3AnvHE08p Catalan: Closed, Spassky GambitA+~!46A12 English: Bled VariationA_3^A83a Dutch: Staunton Gambit, Staunton VariationA<3pA65v Benoni: Smisch, 8.Bg5 h6 9.Be3 O-O 10.Qd2 a6 11.a4A{`iNTE30 Nimzo-Indian: Leningrad, 4...h6 5.Bxf6AwDVB25b Sicilian: Closed, 3.g3, 5.d3 d6 6.Nge2As㥞6[HA90 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 d5Ajڲ3BB96i Sicilian: Najdorf, 7.f4 Nbd7AeXu:x>C02r French: Advance, 5.Nf3 Qb6Ab nE04q Catalan: Open, 5.Nf3 c5 6.O-O Nc6 7.Qa4 Bd7 8.Qxc4A`o٦NA58k Benko Gambit: Fianchetto VariationAVm3xLB38g Sicilian: Maroczy Bind, 7.Nc3 O-OAP2P`A82 Dutch: Staunton Gambit, Tartakower VariationAO6OXB01t Scandinavian: Icelandic Gambit AcceptedAGfD¯2GzB01g Scandinavian: Anderssen Counterattack, Collijn VariationA5XF"`B12u Caro-Kann: Advance, 4.Nf3 e6 5.Be2 c5 6.Be3A"1R9XE48 Nimzo-Indian: 4.e3 O-O 5.Bd3 d5 6.Ne2 c5A5:.bB63t Sicilian: Richter-Rauzer, Podebrad VariationArx|HD41c QGD: Semi-Tarrasch, 5.cxd5 Nxd5AYWFE32r Nimzo-Indian: Classical, 4...O-O 5.a3, 6...b6 7.Bg5 Bb7 8.f3 h6 9.Bh4A #qNA45l Trompowsky 2...g6 3.Bxf6 exf6 4.e3Ahg"`0D45b Semi-Slav: 5.e3 Bd6@%3rE57 Nimzo-Indian: Main Line, 8...dxc4 9.Bxc4 cxd4 10.exd4@D~/$B20 Sicilian: 2.g3@7 qHE14i Queen's Indian: Dreev Variation@JWZD64 QGD: Orthodox, Rubinstein Attack, 8...Re8@!UB36o Sicilian: Maroczy Bind, 5...Nf6 6.Nc3 d6 7.Be2 Nxd4 8.Qxd4 Bg7 9.Be3 O-O 10.Qd2@Eb4@A61 Benoni: Nimzowitsch, 7...Bg7@xJfE32k Nimzo-Indian: Classical, 4...O-O 5.a3, 6...Ne4@PC97e Spanish: Closed, Chigorin, 12...Bb7@Z5NA09c Reti: Advance, Anglo-Polish Attack@D RD85w Grnfeld: Modern Exchange, 8.Be3 O-O@3,C25b Vienna: Zhuravlev@y}2D18p Slav: Dutch, 8...O-O 9.Nh4@DU-D42m QGD: Semi-Tarrasch, 7.Bd3 Main Line, 10.Re1 Nf6 11.a3 b6 12.Be3@D_DC42l Russian Game: Vienna/Kaufmann@zEAB35e Sicilian: Accelerated Fianchetto, Modern, 7.Bc4 Qa5 8.O-O O-O 9.Bb3 d6 10.h3 Bd7 11.f4@|&$ZA31 English: Symmetrical, Two Knights, 3...g6@{DL0D16i Slav: Smyslov, 6.e4@slMBD23i QGA: Mannheim, 4...c6 5.Qxc4@\̓خ$D20h QGA: 3.e3 Nf6@\:@nnNC96c Spanish: Closed, Chigorin, 10...c6@YϺE4HC89a Spanish: Marshall Counterattack@R`{RPB00v Nimzowitsch Defence: 2.d4 d5 3.exd5@LuP?GBA55m Old Indian: Main Line, 8.Be3@Fƙ}~dB22h Sicilian: Alapin, 2...d5 3.exd5 Qxd5 4.d4 Nc6@Bx'K'2E91a King's Indian: 6.Be2@:F*hB33f Sicilian: Pelikan/Sveshnikov, Pelikan Variation@6B_.RE41 Nimzo-Indian: 4.e3 c5 5.Bd3 Nc6 6.Nf3@4 ;h~C05l French: Tarrasch, Closed, 5.f4 c5 6.c3 Nc6 7.Ndf3 Qb6 8.g3@3nфXB28e Sicilian: O'Kelly, 3.d4 cxd4 4.Nxd4 Nf6@2֥)8B70e Sicilian: Dragon, 6.Bg5@"k!XhE81o King's Indian: Smisch, 5...O-O 6.Be3 c5 7.Nge2@ LI/`\D09 QGD: Albin, 5.g3 Be6 6.Nbd2 Qd7 7.Bg2 Nge7?wQrE79e King's Indian: Four Pawns Attack, Main Line, 9...Bd7?SqXB42m Sicilian: Kan, 5.Bd3 Nf6 6.O-O Qc7 7.c4?nx0C50k Giuoco Piano: 4.O-O?xjVB53n Sicilian, Chekhover, 4...Nc6 5.Bb5 Bd7?d@C33 KGA: Tumbleweed/Drunken King?>iHThB13q Caro-Kann: Panov-Botvinnik, 5...Nc6 6.cxd5 Nxd5?j'@i0A54 Old Indian: 5.g3 Be7?v&-ID41i QGD: Semi-Tarrasch, 6.g3, Main Line, 9.Nxd5 exd5 10.dxc5 Bxc5?7>A50j Indian: Slav-Indian, 3.Nc3?IJE58 Nimzo-Indian: Main Line, 8...Bxc3?Nx{@B29h Sicilian: Nimzowitsch, 4.d4?wgԂ^A32 English: Symmetrical, Two Knights, 5.Nc3 a6?Xd-LB01j Scandinavian: 2...Qxd5, 5.Nf3 Bg4?Ña^B47i Sicilian: Taimanov, 6.g3 a6 7.Bg2 d6 8.O-O? :D35g QGD: Exchange, 5.Nf3 Be7?q_AHA85 Dutch: 2.c4 Nf6 3.Nc3 e6 4.e3 d5?"IYVC45w Scotch: 4.Nxd4 Bc5 5.Be3 Qf6 6.c3 Nge7?A/.JC90h Spanish: Closed, Pilnik, 11.Nbd2? ^ٞHn,E00p Catalan: 4.Nf3 c6?t P8$8B05f Alekhine: Modern, 5.Be2?|nX^B57n Sicilian: Sozin, Benko, 7.Nb3 e6 8.O-O Be7?w+y /HD18l Slav: Dutch, 8...Nbd7 9.Qe2 Bg6?qLNVB16g Caro-Kann: Bronstein-Larsen, 6.Nf3 Bg4?ksq^C52 Evans Gambit: Tartakower Attack, 8.dxe5 Bb6?\aa6E11b Bogo-Indian: 4.Nbd2 d5?TIhpB06c Modern?OV\JC52 Evans Gambit: Compromised Defence?MS}RB26m Sicilian: Closed, 6.Be3 e6 7.Qd2 Qa5?>\uLA44o Old Benoni: Czech, 3.e4 d6 4.Bb5+?=[5HD36o QGD: Exchange, Main Line, 9.Nf3?;WqeNE14j Queen's Indian: 4.e3 Bb7 5.Bd3 Be7?:WL_>B90c Sicilian: Najdorf, 6.a4 e5?u$M72C33 KGA: Eisenberg Gambit? 8A56r Benoni: Czech, 5.e4 Be7?p"<A03 Bird: 1...d5 2.Nf3 g6 3.g3?dg:b8D01d Richter-Veresov: 3...h6? !!XE98c King's Indian: Mar del Plata, 9.Ne1 Ne8? >M:B43g Sicilian: Kan, 5.Nc3 Qc7>MiF:B44d Sicilian: Taimanov, 5.c4> [ <A11 English: Caro-Kann Defence>XHE94s King's Indian: 7.O-O Nbd7 8.Qc2>spz1VC62 Spanish: Old Steinitz, 4.d4 exd4 5.Nxd4>ى@݈WaPC49g Four Knights: Symmetrical Variation>"Zx6D58p QGD: Tartakower, 8.Rc1>m?)LD73 Neo-Grnfeld, 5.Nf3 c6 6.cxd5 cxd5>Oe|E96 King's Indian: 7.O-O Nbd7, Old Main Line, 10.Rb1 Re8 11.d5>m7Y{8PA19 English: Mikenas, Sicilian, 4.e5 Ng8>>o|C43o Russian Game: Modern Attack, 3...Nxe4 4.Bd3 d5 5.Nxe5 Nd7>xB69 Sicilian: Richter-Rauzer, 7...a6, 9.f4 Be7 10.Nf3 b5 11.Bxf6 gxf6 12.Kb1>01hMqbC87c Spanish: Closed, Averbakh, 7.Bxc6+ bxc6 8.d4>܌jA64 Benoni: Fianchetto, 11...Re8 12.h3 Rb8 13.Nc4 Ne5>z2ۛ)bC14l French: Classical, Steinitz, 8.Nf3 c5 9.dxc5>1ZSVA64 Benoni: Fianchetto, 11...Re8 12.Nc4 Ne5>bw+PC68e Spanish: Exchange, Lasker Variation> 28B31n Sicilian: Rossolimo, 3...g6 4.O-O Bg7 5.Re1 Nf6 6.c3 O-O 7.d4>L*7G*E01 Catalan: 4...Bb4+>$lB76t Sicilian: Dragon, Yugoslav, 9.O-O-O d5: 12.Bd4 e5>KGc[$C70 Spanish: 4.Ba4>qb2A35a English: Symmetrical>\M FC78q Spanish: Archangelsk, 7.d3 Be7>(`D10m Slav: Winawer Countergambit Accepted, 6.Nd2>[E!$C44x Scotch Gambit>|odnjO@B66l Sicilian: Richter-Rauzer, 7...a6 8.O-O-O h6 9.Be3 Bd7 10.f3>|Y(LVB30s Sicilian: Rossolimo, 3...e6 4.O-O Nge7>ufm ,dD13t Slav: Exchange, 6.Bf4 e6 7.e3 Bd6 8.Bxd6 Qxd6>s_X7ߑDC51 Evans Gambit: Anderssen, 6.Qb3>rn55HE56 Nimzo-Indian: Main Line, 7...Nc6>n(`D67 QGD: Orthodox, Main Line, Capablanca, 11.O-O>`,=&*A02 Bird: 1..Nf6 2.b3>J&4C00w French: Franco-Benoni>HVJEbB01o Scandinavian: 2...Qxd5, Main Line, 6.Bc4 Bf5>H{g:B89 Sicilian: Sozin, 7.Be3 a6>Eڔ).iRA30d English: Symmetrical, 2.Nf3 Nf6 3.g3>0rPC14g French: Classical, Steinitz, 7...a6>+p&sPD32l QGD Tarrasch: Marshall Gambit, 6.d5>)jMuXD52f QGD: Cambridge Springs, Yugoslav, 8.Qd2>"4zB90q Sicilian: Najdorf, 6.Be3 e5 7.Nb3 Be6 8.f3 Be7 9.Qd2 O-O>6C15e French: Winawer, 4.Bd3> nprE13e Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.Nd2 Bxc3 8.bxc3>EDDBD08 QGD: Albin, Krenosz Variation>NC@DA59h Benko Gambit: 7.e4 Line, 9.g3=v]["4B01r Scandinavian: 2...Nf6=\yϝoTA14 English: Neo-Catalan Declined, 5...O-O=Ĺ~&jHC71 Spanish: Modern Steinitz Defence=3DB86 Sicilian: Sozin-Najdorf, 7.Bb3=ق쓜ChC15r French: Winawer, Alekhine Gambit, Kan Variation=؛1zD00m Blackmar-Diemer: Lemberger Countergambit, Sneider Attack=yY$ZB19q Caro-Kann: Classical, Spassky, Main Line=0r"HC41v Philidor: Improved Hanham, 7.a4=HxnC52 Evans Gambit: Compromised Defence, Potter Variation=0s@LE73m King's Indian: Averbakh, 6...Nbd7=%T|rA89 Dutch: Leningrad, Main Line, 7.Nc3 Nc6 8.d5 Na5 9.Qd3=n^`D68 QGD: Orthodox, Classical, Maroczy, 13...exd4=@vKpE92t King's Indian: Petrosian, Stein, 8.Bg5 h6 9.Bh4 Na6=9n>qND34o QGD Tarrasch: Bogoljubow Variation=NC49e Four Knights: Double Bishops, 6.d3=`TlPD94 Grnfeld: 5.e3 O-O 6.cxd5 Nxd5 7.Bc4=j[jE84m King's Indian: Smisch, Panno Main Line, 9.h4 h5=;E68h King's Indian: Fianchetto, Classical, 8.e4 exd4 9.Nxd4 Re8 10.h3 Nc5 11.Re1 a5=uw*ND00l Blackmar-Diemer Gambit (BDG): 2.e4=¶,C55c Two Knights: 4.d3=&RV&D15o Slav: Accepted=7oPE22 Nimzo-Indian: Spielmann, 4...c5 5.e3=zZRB63b Sicilian: Richter-Rauzer, 7.Qd2 Nxd4=f'J"A05 Reti: 1...Nf6=_ª&D10h Slav: 3.e3 Bf5=Zq$&A10 English: 1...d6=Sq4HHD00h Hodgson Attack: 2...h6 3.Bh4 c6=D3)}ZD36h QGD: Exchange, 6.Qc2 Be7 7.e3 Nbd7 8.Nf3=@{6^E31j Nimzo-Indian: Leningrad, Main Line, 8...e5=?<lB66i Sicilian: Richter-Rauzer, 7...a6 8.O-O-O h6 9.Be3=/^T8A60j Benoni: Snake Variation=.bBsvA39q English: Symmetrical, Main Line 7.d4, 10.Qd3 a6 11.Bd2=+&T_VE63d King's Indian: Fianchetto, Panno, 8.b3=&r4PD86 Grnfeld: Classical Exchange, 7...c5=FsL'LB05n Alekhine: Modern, Main Line, 8.h3=|!HE02 Catalan: Open, 5.Qa4+ Bd7 6.Qxc4= @{'8D58d QGD: Tartakower, 8.Bxf6= mSLA26 English: Botvinnik System, 6...Nf6=lVpD58r QGD: Tartakower, 8.Rc1 Bb7 9.Bxf6 Bxf6 10.cxd5 exd5<_!rB84 Sicilian: Scheveningen, Classical, 7.O-O Be7 8.f4 O-OC52 Evans Gambit: 5...Ba5 6.Qb3<>A40i Englund Gambit: 2.dxe5 Nc6<=6&fB80i Sicilian: Scheveningen, English, 7...Nc6 8.Qd2< ESHD33o QGD Tarrasch: 7.Bg2 cxd4 8.Nxd4<r={NB96j Sicilian: Najdorf, 7.f4 Nbd7 8.Qf3C22 Centre Game: Paulsen Attack;刚:A65d Benoni: 6.e4 g6 7.Bf4 a6;Qr=JC17b French: Winawer, Advance, 5.dxc5;"B–$lD35v QGD: Exchange, 5.Bg5 c6 6.e3 Be7 7.Bd3 O-O 8.Nge2;{cGND94 Grnfeld: Slav/Schlecter, 6.Be2 O-O;&^D32u QGD Tarrasch: 5.Nf3 Nc6 6.e3 Nf6 7.Be2 Be7;+4$ <A11 English: Caro-Kann Defence;v>ZD63 QGD: Orthodox, Swiss, Karlsbad, 9.Bd3 Re8;V\&A10 English: Vector;\vLE36 Nimzo-Indian: Classical, Noa, 5.a3;xAA$D80 Grnfeld: 4.f3;rڕTC07i French: Tarrasch, Shaposhnikov Gambit;q%<A13p English: Kurajica Defence;kpnX0&D24a QGA: 4.Nc3 Nd5;bP`B48h Sicilian: Taimanov, 6.Be3 a6 7.Qd2 Nf6 8.f3;XV T<A11 English: Caro-Kann Defence;VBfuBD59a QGD: Tartakower, 8.cxd5 Nxd5;Mi4k:B60a Sicilian: Richter-Rauzer;GsD94D14e Slav: Exchange, 8.Ne5;-U㟵jB52r Sicilian: 3.Bb5+ Bd7 4.Bxd7+ Qxd7 5.O-O Nc6 6.c3;)V$-D91s Grnfeld: 5.Bg5 Ne4 6.cxd5 Nxg5 7.Nxg5 e6 8.Nf3 exd5 9.e3 O-O 10.Be2;hNyHD48q Semi-Slav: Meran, Old Main Line;D9~XB97e Sicilian: Najdorf, Poisoned Pawn, 8.Nb3;ߩ}DB44h Sicilian: Taimanov, 5.Be3 Nf6;k:a]@>A36g English: Symmetrical, 5.a3;u4#FE94m King's Indian: Glek, 8.Be3 Ng4;o. rE88e King's Indian: Smisch, Orthodox, 7.d5 c6 8.Qd2 cxd5 9.cxd5 a6 10.Bd3;oE29 Nimzo-Indian: Smisch, 5...O-O 6.e3 c5 7.Bd3 Nc6 8.Ne2 b6 9.e4: 0E11a Bogo-Indian: 4.Nbd2:67i4A41d Neo-Old Indian: 2.Nf3:oyonB44f Sicilian: Taimanov, 5.c4 Nf6 6.Nc3 Bb4 7.Nxc6 bxc6:^&6hE19g Queen's Indian: Old Main Line, 9.Qxc3 f5 10.Rd1:9n\BA73 Benoni: Classical, 9.O-O Nbd7:௝k%BZE83c King's Indian: Smisch, 6...Nc6 7.Qd2 a6:pYs<D10e Slav: Exchange, 4.Nc3 Nf6:;BxՏ%lC89s Spanish: Marshall, Main Line, Classical Variation:MrE33 Nimzo-Indian: Classical, Milner-Barry (Zurich), 6.a3 Bxc3+ 7.Qxc3:([TC33 KGA: Bishop's Gambit, Morphy Variation:ra\C65p Spanish: Berlin, Benelux Variation, 7.Bg5:`D00c Queen's Pawn, Mason, Steinitz Countergambit:) ~E09k Catalan: Closed, Main Line, 9.e4 dxe4 10.Nxe4 Nxe4 11.Qxe4:Jr`8C02b French: Advance, 3...b6:6$jB38w Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 d6 9.O-O Bd7 10.Qd2 Nxd4:J<ޟGXB34b Sicilian: Accelerated Fianchetto, 5.Bc4:hKf\r^D66 QGD: Orthodox, Main Line, Fianchetto, 11.e4:QNsvE82i King's Indian: Smisch, Fianchetto, 7.Bd3 a6 8.Nge2 c5:ZE74e King's Indian: Averbakh, 6...c5 7.d5 Qa5:klE76l King's Indian: Four Pawns Attack, 6.Nf3 c5 7.dxc5:w^B13m Caro-Kann: Exchange, Rubinstein, 7.Qb3 Qd7:,4E12v Queen's Indian: 4.Bg5:cpm#JPB46j Sicilian: Taimanov, 5...a6 6.Be3 d6:zI˺4C25e Vienna: 2...Bc5 3.Bc4:v^hA91 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nf3 d5 6.O-O:tCh0C00k French: Wing Gambit:rǚ(8A21 English: Lukin, 5.Ng5 c6:qK"5LB50q Sicilian: 2.Nf3 d6 3.c3 Nf6 4.Bd3:jX({~*A04 Reti: 1...f5 2.d3:fA>)|B99i Sicilian: Najdorf, Main Line, 10.Bd3 h6 11.Bh4 g5 12.fxg5:eU PC87f Spanish: Closed, Averbakh, 7.c3 Bg4:aĖ=<A08 Reti: KIA, 2...c5 + 3...g6:`1dB22x Sicilian: Alapin, 2...Nf6, 5.cxd4 e6 6.Nf3 b6:]{7`B37h Sicilian: Maroczy Bind, 6.Nc2 Nf6 7.Nc3 O-O:V5TA37d English: Symmetrical, 5.Nf3 Nh6 6.O-O:?@0BA85 Dutch: 2.c4 Nf6 3.Nc3 e6 4.e3::&*6oHE43 Nimzo-Indian: Nimzowitsch, 5.Nf3:5.6PDD53v QGD: 4.Bg5 Be7 5.e3 O-O 6.Qc2:/Fu<A03 Bird: 1...d5 2.Nf3 c5 3.e3:#!Ŧ?ZC42p Russian Game: Classical, Close Variation:*?>D24f QGA: 4.Nc3 c5 5.d5 e6 6.e4:?tnPE53 Nimzo-Indian: Main Line, 6...c5 7.a39BK D89d Grnfeld: Classical Exchange, 14.Rc1 Bxa2 15.Qa4 Be6 16.d5 Be7 17.Qb49oTf̗JB46i Sicilian: Taimanov, 5...a6 6.Be39Z0$GbE12q Queen's Indian: Petrosian, 6.cxd5 exd5 7.Bg59 $HE00v Catalan: 4.Nf3 dxc4 5.Qa4+ Nbd79m!tB92k Sicilian: Najdorf, 6.Be2 e5 7.Nb3 Be7 8.O-O O-O 9.Be39K:y~B37l Sicilian: Maroczy Bind, 6.Nc2 Nf6 7.Nc3 d6 8.Be2 O-O 9.O-O9ڕ~E!ZE55 Nimzo-Indian: Main Line, Bronstein, 9.Ne29RKUfD87g Grnfeld: Classical Exchange, 9.O-O Nc6 10.Be39é >B26k Sicilian: Closed, 6.Be3 e69\wDC49b Four Knights: 4.Bb5 Bb4 5.O-O9é"bE82h King's Indian: Smisch, Fianchetto, 7.Bd3 a69Nং$<A70f Benoni: Classical, 8.Qa4+9J$A53 Old Indian9bB41k Sicilian: Kan, 5.c4 Nf6, Bronstein Variation9 nIWBD00b Queen's Pawn: 2.c3 Nf6 3.Bf49fRbE64d King's Indian: Fianchetto, Yugoslav, 7.d5 e69څLA45x Trompowsky: 2...Ne4 3.Bf4 c5 4.d59FpBB30m Sicilian: Rossolimo, 3...Nf69Z3lB34j Sicilian: Accelerated Fianchetto, Modern, 5...Bg79lYfRD97l Grnfeld: Russian, Simagin Variation9+5\E58 Nimzo-Indian: Main Line, 9.bxc3 Qc7 10.Qc29;=MPB85 Sicilian: Scheveningen, Classical, Main Line, 9...Nc6 10.Kh1 Bd79xP4oBB21m Sicilian: Smith-Morra Gambit9_<XB83 Sicilian: Scheveningen, Modern, 9.f4 Bd79~BA25 English: Closed, Trger, 5.d39kpE81o King's Indian: Smisch, 5...O-O 6.Be3 c5 7.Nge2 Nc69_6A46i Indian: 2.Nf3 d6 3.Bg59QJHhZB39i Sicilian: Maroczy Bind, Breyer, 8.Qxg4 Nxd4 9.Qd1 Ne6 10.Qd29NhiJBC44d Open Game: Inverted Philidor9DR@$RE15l Queen's Indian: Nimzowitsch, 5.b3 b59D *FD14b Slav: Exchange, 6.Bf4 Bf5 7.e39A9Z>dD85n Grnfeld: Modern Exchange, 8.Rb1 O-O 9.Be2 b69;JI޺]TE32h Nimzo-Indian: Classical, 4...O-O 5.a39-Ǵ}ZA37h English: Symmetrical, 5.Nf3 d6 6.O-O Nh69ȼhC10u French: Rubinstein, 4...Bd7 5.Nf3 Bc6 6.Bd3 Nd79ոZV:C45j Scotch: Mieses Variation9ܮVC56h Two Knights: Classical, Moller, 9.Nxe49 ) :E91o King's Indian: 6.Be2 Nc68mxXCJE32d Nimzo-Indian: Classical, 4...O-O8&D23a QGA: 3.Nf3 Nf68#\6jB63m Sicilian: Richter-Rauzer, 7.Qd2 Be7 8.O-O-O Nxd48(E6DB00m Nimzowitsch Defence: 2.Nc3 e68Q) u0A03 Bird: Lasker, 3...c58۾"D38a QGD: Ragozin8'ZD00m Blackmar-Diemer: Lemberger Countergambit8͚WPC80c Spanish: Open, Tartakower Variation8Eh#PC68s Spanish: Exchange, Bronstein, 6.Na38Դ.hD36m QGD: Exchange, Main Line, 9.Nge2 Re8 10.O-O Nf88wZoLVA45a Indian: Gibbins Gambit, Oshima Defence8PuVB02g Alekhine: Scandinavian, Geschev Gambit8j™$DA36i English: Symmetrical, 5.a3 d68e?VA28 English: Four Knights, Marini Variation8aBD85a Grnfeld: Exchange Variation8XNC8A81 Dutch: 2.g3 e6 3.Nf3 Nf68WX#ubA57u Benko Gambit: Zaitsev, Nescafe Frappe Attack8ElwmDA27 English: Three Knights, 3...f586;=3LA83j Dutch: Staunton Gambit, 4.Bg5 Nc68$ptB52q Sicilian: 3.Bb5+ Bd7 4.Bxd7+ Qxd7 5.O-O Nc6 6.Re1 Nf68PHA48o Neo-King's Indian: Torre Attack8 pf>RB69 Sicilian: Richter-Rauzer, 7...a6, 9.f4 Be7 10.Nf3 b5 11.Bxf68 JH^E73l King's Indian: Averbakh, 6...c6 7.Qd2 Nbd78Tp2E02 Catalan: Open, 5.Qa4+8x_  6E20 Nimzo-Indian: 4.Bd2 O-O8mΤnB21z Sicilian: Smith-Morra, 5.Nf3 d6 6.Bc4 e6 7.O-O Nf67ꉉ0D32m QGD Tarrasch: 5.Nf37Q0:D53r QGD: 4.Bg5 Be7 5.e3 Nbd77ӠuT D30d QGD: 3.cxd57dMbC00v French: KIA, Reversed Philidor, 4...Nc6 5.c37j>FE94o King's Indian: Glek, Main Line72q,XA62 Benoni: Fianchetto, 9.O-O Na6 10.Nd2 Nc77۲#A79 Benoni: Classical, Main Line, 10.Nd2 Na6 11.f3 Nc7 12.a4 b6 13.Nc47ْ`hz|DE42 Nimzo-Indian: 4.e3 c5 5.Ne2 d57||JA56s Benoni: Czech, 5.e4 Be7 6.g3 O-O7# Y<4C00j French: 2.Nf3 d5 3.e57DzxBfB93q Sicilian: Najdorf, 6.f4 e5 7.Nf3 Nbd7 8.a4 Qc77iۤ^E62e King's Indian: Fianchetto, 6...c6 7.O-O a67Z)u^D74 Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O c5 8.e4 Nf67༞هFD46q Semi-Slav: Chigorin, Main Line7YR+[TD23h QGA: Mannheim, 4...Nbd7 5.Nc3 e6 6.e47%|B81t Sicilian: Scheveningen, Keres, 6...Nc6 7.g5 Nd7 8.Be3 Be77B`D41u QGD: Semi-Tarrasch, 7.Bc4 Main Line, 13.Qc27,ouBA12 English: Bogoljubow Variation7iD#VC39 KGA: Kieseritsky, Berlin Defence, 6.Bc47UjDTB98o Sicilian: Najdorf, 8...Qc7 9.O-O-O b57}bȏZA46y Torre Attack: 3...h6 4.Bxf6 Qxf6 5.e4 c57zrjE90r King's Indian: 5.Nf3 O-O 6.h3 e5 7.d5 Nbd7 8.Be37lla%JC96i Spanish: Closed, Chigorin, 11.d47e`NC00b French: Reti (Spielmann) Variation7\ĝX&D32e QGD Tarrasch: von Hennig-Schara Gambit, 5.Qxd4 Nc6 6.Qd1 exd5 7.e37[f90PE15e Queen's Indian: Nimzowitsch, 5.Nbd27YUl<A65r Benoni: Smisch, 8.Bg5 h67MɺA%nC67t Spanish: Open Berlin, 5.d4 Nd6 Queenswap, 9.Nc3 h67IwxԇeZD45x Semi-Slav: 6.Qc2 Bd6 7.Be2 O-O 8.O-O Qe77A(+`RB25r Sicilian: Closed, 6.f4 e6: 9.Be3 Rb87>BpIPD42e QGD: Semi-Tarrasch, 7.Bd3 Main Line79Yfx_8A44c Old Benoni: Czech, 3.c476evX<B08k Pirc: Classical, 5.Be2 c671A+lD|C07o French: Tarrasch, Open, 4.exd5 Qxd5 5.Ngf3 cxd4 6.Bc4 Qd67*A`E15m Queen's Indian: Nimzowitsch, 5.b3 d5 6.cxd57[l2-E87m King's Indian: Smisch, Orthodox, 7.d5 Nh5 8.Qd2 f5 9.O-O-O Nd77 @TE25 Nimzo-Indian: Smisch, Keres Variation6KB30j Sicilian: 2...Nc6 3.Nc3 e56|4 4D73 Neo-Grnfeld, 5.Nf3 c56{~-B79d Sicilian: Dragon, Yugoslav, Old Main Line, 12.h4 Ne5 13.Kb1 Nc46yB"A60e Benoni: 4.g36pE\B63u Sicilian: Richter-Rauzer, Podebrad, 10.f36n'~X VE75f King's Indian: Averbakh, 7.d5 e6 8.Qd26etxQ<C84c Spanish: Closed, 6.Nc3 b56_hѸF@B88 Sicilian: Sozin-Scheveningen6W"K>B01u Scandinavian: 2...Nf6 3.d46H7OPC64b Spanish: Classical, Boden Variation6GӀzDC71 Spanish: Modern Steinitz, 5.d46EE69w King's Indian: Fianchetto, Classical, 9.h3 Re8 10.Re1 exd4, 11...a56E5cr;VB01e Scandinavian: 2...Qxd5 3.Nc3 Qa5 4.Bc46>J?]H^E67e King's Indian: Fianchetto, Classical, 8.d56=>/TB12l Caro-Kann: Advance, Bayonet Variation62ZԥbB01q Scandinavian: 2...Qxd5, Main Line, 8.Qe2 Bb461ӈo8C40f Elephant Gambit: 3.Nxe56)\$_7XB56g Sicilian: Open, 2...d6, 5.Nc3 Bd7 6.Bg56(*++XD20p QGA: 3.e4 Nf6 4.e5 Nd5 5.Bxc4 Nb6 6.Bd36%=1$D11s Slav: 4.e3 a662`{@C50o Giuoco Pianissimo: 4.d3 Nf66G1fD41g QGD: Semi-Tarrasch, 6.g3, Main Line, 9.e4 Ndb46M~DB01w Scandinavian: Marshall, 4.Nf36 &hC88n Spanish: Closed, Anti-Marshall 8.a4 Bb7 9.d3 d65|~Hf^>B05k Alekhine: Modern, 5.Be2 e65sj+4D15p Slav: Accepted, 5.Ne55:{qvE75i King's Indian: Averbakh, 7.d5 e6 8.Qd2 exd5 9.exd5 Re85#jZB12x Caro-Kann: Advance, Main Line, 6.Nge2 c55qύџDB05i Alekhine: Modern, Flohr, 6.c45)6D11l Slav: Slav-Reti System5BC44b Open Game: Konstantinopolsky5َ.F4lE73t King's Indian: Averbakh, 6...Na6 7.Qd2 e5 8.d5 c65?y}zA89 Dutch: Leningrad, Main Line, 7.Nc3 Nc6 8.d5 Ne5 9.Nxe5 dxe5 10.e45W*nC24 Bishop's Opening: Urusov Gambit, Marshall Variation5{⒒FD91f Grnfeld: 5.Bg5 Ne4 6.Bh4 Nxc35Iwz/:jE56 Nimzo-Indian: Main Line, 7...Nc6 8.a3 dxc4 9.Bxc45F4A54 Old Indian: 4.Nf3 exd45렋3fE14h Queen's Indian: 4.e3 Bb7 5.Bd3 Bb4+ 6.Nbd2 O-O5/NfND51 QGD: 4.Bg5 Nbd7 5.e3 c6 6.cxd5 cxd55J'4A45c Indian: Lazard Gambit5AP#{dD79n Neo-Grnfeld, Main Line, 10.f4 Nc6 11.Be3 Nb65\#LLE14q Queen's Indian: 4.e3 Bb7 5.Bd3 c55[a4e0A10 English: Anglo-Dutch5Zf]dA88 Dutch: Leningrad, Main Line, 7.Nc3 c6 8.d5 Bd75~Y>j>C52 Evans Gambit: Waller Attack5{ {LD34b QGD Tarrasch: 7.Bg2 Be7 8.O-O Be65{m5ZbC88m Spanish: Closed, Anti-Marshall 8.a4 Bb7 9.d35jG;IIvlE54 Nimzo-Indian: Main Line, Karpov, 10.Bg5 Bb7 11.Re15b*"HDA42t Modern: Averbakh, 4...e5 5.d55`ܮbE16j Queen's Indian: Capablanca, Riumin Variation5`t%YbE11v Bogo-Indian: Nimzowitsch, 5.g3 Nc6 Main Line5[N"IRA63 Benoni: Fianchetto, 9...a6 10.a4 Nbd75Uh1ArVD74 Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O c5 8.e45U![ \E61o King's Indian: 4.Nf3 O-O 5.e3 d6 6.Be2 c55FD"MLC11g French: Steinitz, Bradford Attack59O;,@C68d Spanish: Exchange, 4...dxc651BC46e Three Knights: 3...Bc5 4.Bb550TU-@C37 KGA: Salvio, Cochrane Gambit5.6(C26a Vienna: 2...Nf65, 8C11o French: 3.Nc3 Nf6 4.Bg55(WLjE97z King's Indian: Mar del Plata, 9.Nd2 a5 10.a3 Nd75zxA@D24j QGA: 4.Nc3 a6 5.a4 Nc6 5.e45Al6C44y Scotch Gambit: 4...Bc559(@A19 English: Mikenas, Nei Gambit5B/,n,@C54c Giuoco Piano: Bird's Attack5-g6XjC89q Spanish: Marshall, Main Line, 16.Qd3 Rae8 17.Nd25ǂ>C58h Two Knights: Morphy, 8.Be25sFD18j Slav: Dutch, 8...Nbd7 9.Qb3 a55- .>C70 Spanish: Classical Deferred5 DQWFC29g Vienna Gambit: Wurzburger Trap5UT\E73s King's Indian: Averbakh, 6...Na6 7.Qd2 e55/,RA70u Benoni: Classical, 8.h3 O-O 9.Bd3 b54WzTC64j Spanish: Classical, 4.c3 Nf6 5.d4 Bb64= (bE99 King's Indian: Mar del Plata, 10.f3 f5 11.Nd34v44B20 Sicilian: 2.d3 e6 3.g346&C40j Latvian Gambit4T<C61g Spanish: Bird's, 5.O-O c64[:FA45q Trompowsky: 2...c5 3.Bxf6 gxf64ղZAlC47w Four Knights: Scotch, Main Line, 10.Bg5 c6 11.Na44'jB34k Sicilian: Accelerated Fianchetto, Modern, 6.Nde24}Pi^B23q Sicilian: Closed, Grand Prix, 3...e6 4.Nf341kᨩNC14m French: Classical, Steinitz, 9.Qd242˿GPA16 English: Anglo-Indian, 2.Nc3 g6 3.g34ޝ=3jA45r Trompowsky: 2...c5 3.Bxf6 gxf6 4.d5 Qb6 5.Qc1 f54\6D20u QGA: Linares Variation4 *IIRC67g Spanish: Berlin, Minckwitz Variation4~GiXC23 Bishop's Opening: Philidor Counterattack4ߛ[d0D20c QGA: 3.e3 c5 4.Bxc44'6A86 Dutch: Leningrad, 4.Nc34/Fӊ4E06 Catalan: Closed, 5.Nf34ɗĮ@D92 Grnfeld: 5.Bf4 O-O 6.Rc1 c54,A03 Bird: Sturm Gambit4vqTNA93 Dutch: Stonewall, Botvinnik, 7...b64t^QUB49m Sicilian: Taimanov, 6.Be3 a6 7.Be2 Nf6 8.O-O Bb4 9.Na4 Be7 10.Nxc6 bxc64eW օhFA42g Modern: Averbakh, Kotov, 5.Nf34[u-y(A13a English: 1...e64QDIMFA29 English: Four Knights, 4.g3 Bc54L.@)dE13h Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.e3 Bxc3+4JfE39j Nimzo-Indian: Classical, Pirc, 6.a3 Bxc5 7.Nf34BV~2;#6B23y Sicilian: Closed, Grand Prix, 3...g6 4.Nf3 Bg7 5.Bb5 Nd4 6.O-O49]ГPD56 QGD: Lasker Defence, 9.Rc1 c6 10.Bd346g]dB78e Sicilian: Dragon, Yugoslav, Main Line, 12.Kb14/`%2JD21o QGA: 3.Nf3 c5 4.d5 e6 5.Nc3 exd54-B:C18c French: Winawer, 6...Qc74+6.࠼PE05c Catalan: Open, Classical, 6.Nc3 O-O4&ؿIJB54h Sicilian: Prins (Moscow), 5...a64+kHB29f Sicilian: Nimzowitsch, 3.e5 Nd54 $#<VC12q French: MacCutcheon, Main Line, 11.Nf34FpE57 Nimzo-Indian: Main Line, 8...dxc4 9.Bxc4 cxd4 10.exd4 Be7 11.Re132H%>A40n Queen's Pawn: 1...e6 2.Nf33nlA13w English: Neo-Catalan Accepted, 5.Qa4+ Nbd7 6.Qxc43e^.\B54o Sicilian: Prins (Moscow), 5...e5 6.Nb3 d53IZB71 Sicilian: Dragon, Levenfish, 6...Bg7 7.e53y*VC69h Spanish: Exchange, Gligoric, 6.d4 exd43nTrbB75 Sicilian: Dragon, Yugoslav, 7...Nc6 8.Qd2 Bd73,Epi@C15d French: Winawer, 4.Qd3 dxe43g\E64c King's Indian: Fianchetto, Yugoslav, 7.d53s+9ZE81h King's Indian: Smisch, 5...O-O 6.Bg5 c53w8B26a Sicilian: Closed, 6.Be33EToHA46p Indian: London, 3...c5 4.e3 Qb63FTA02 Bird: 1..c53;꣬ZB96p Sicilian: Najdorf, Polugaevsky, 10.Bxb5+36g^LE08l Catalan: Closed, 7.Qc2 c6 8.b3 b53\N"XC09g French: Tarrasch, Open, Main Line, 9.c33_wYJA16 English: Anglo-Grnfeld, 4.Nf3 g63|JZC91d Spanish: Closed, Bogoljubow, 10.Be3 exd43l8HLg^B25w Sicilian: Closed, 6.f4 e6: 9.Be3 Nd4 10.e53pN6hC15l French: Winawer, Winkelmann-Reimer Gambit (WRG)3~% .\D09 QGD: Albin, 5.g3 Bg4 6.Bg2 Qd7 7.O-O O-O-O3JSpD89f Grnfeld: Classical Exchange, 14.Rc1 Bxa2 15.Qa4 with 17.Qb4 e63uZ,lbB22g Sicilian: Alapin, 2...d5 3.exd5 Qxd5 4.d4 e63a^*C01a French: Exchange3Vt!skBB30l Sicilian: Rossolimo, 3...Qb63R;zE97r King's Indian: Mar del Plata, Bayonet, 9...Nh5 10.Re1 f53FJE46 Nimzo-Indian: Reshevsky Variation3@qS9׃(C39 KGA: Kieseritsky3>f=tLD14d Slav: Exchange, 6.Bf4 Bf5 7.e3 e6385ǩ[<HC51 Evans Gambit: Steinitz Variation31/TdTC17e French: Winawer, Bogoljubow Variation3.[nE73u King's Indian: Averbakh, 6...Na6 7.Qd2 e5 8.d5 Qe83)mfB93r Sicilian: Najdorf, 6.f4 e5 7.Nf3 Nbd7 8.a4 Be73#TƒNC31 KGD: Falkbeer, Tartakower Variation3=yVC67d Spanish: Open Berlin, 5.Re1 Nd6 6.Nxe53"I%%HE53 Nimzo-Indian: Main Line, 7...Bd73H-A02 Bird: 1..g63 Ux#BD47m Semi-Slav: Meran, Wade, 9.a33 L@B91e Sicilian: Najdorf, 6.g3 Bg42mlE70n King's Indian: 4.e4 d6 5.Bd3 O-O 6.Nge2 Nc6 7.O-O2U85 VD90 Grnfeld: Three Knights Exchange, 6.Bd22NT6D00d Queen's Pawn: 2.e3 Nf62f6A42c Modern: c4 Pterodactyl2~.WdB55 Sicilian: Prins, Venice Attack, 6...Nbd7 7.Nf52I LC02q French: Advance, Euwe, 6.Be2 Nge72ۖbFC10m French: Rubinstein, Capablanca2]]XD42d QGD: Semi-Tarrasch, 6.e3 Nc6 7.Bd3 cxd42C,JZA31 English: Symmetrical, Two Knights, 4...g62a~XvE59 Nimzo-Indian: Main Line, 9.bxc3 dxc4 10.Bxc4 Qc7 11.Ba22k֩ILB41k Sicilian: Kan, 5.c4 Nf6 6.Nc3 Bb42y \2C44y Scotch Gambit: 5.Ng52ZIxBD90 Grnfeld: Three Knights, 5.g32Z^DB01i Scandinavian: 2...Qxd5, 5.Bc42d>WXB22d Sicilian: Alapin, 2...e6 3.d4 d5 4.exd52js2C25c Vienna: 2...d6 3.Bc42x2G,D31j Semi-Slav: 4.cxd52BB45c Sicilian: Taimanov, 5.Nc3 d62 2.>B00m Nimzowitsch Defence: 2.Nc32'N>C01a French: Exchange, 3...Qxd52Chj֧RA39b English: Symmetrical, Main Line 7.d42!}Y ,E00i Catalan: 3...Bb4+2ĠZA03 Bird: 1...d5 2.Nf3 Nf6 3.g3 g6: 5.O-O O-O2ܳEZD06j QGD: Marshall Defence, 3.cxd5 Nxd5 4.Nf32d,@A34 English: Symmetrical, 2...b62{~>NB16d Caro-Kann: Bronstein-Larsen, 6.Bc42z44d #>E42 Nimzo-Indian: 4.e3 c5 5.Ne22v)HB25j Sicilian: Closed, 6.f4 e5 7.Nf32o FD96 Grnfeld: Russian, 5...c6 6.Bf42f*fHC81 Spanish: Open, Keres, 10.Rd1 O-O2_Lb$ZD48d Semi-Slav: Meran, 8...a6 9.O-O c5 10.Qe22\" 3VD00k Trompowsky: 2...d5 3.Bxf6 exf6 4.e3 c62[ 1`D27s QGA: Classical, Rubinstein, 8.Nc3 Be7 9.Qe22Y(XA76 Benoni: Classical, Main Line, 10.Qc2 Na62VCׁ >C51 Evans Gambit: Fraser Attack2MڻʹbE67f King's Indian: Fianchetto, Classical, 8.dxe52LDXB45e Sicilian: Taimanov, Four Knights, 6.Bg52?fI^C16l French: Winawer, Advance, 4...Ne7 5.Bd2 b62<2>vB22d Sicilian: Alapin, 2...e6 3.d4 d5 4.exd5 exd5 5.Nf3 Nc62;J`C07n French: Tarrasch, Open, Eliskases Variation21oJ4D15b Slav: 4.Nc3 Bf5 5.Qb320YhA55g Old Indian: 5.e4 Be7 6.g3 c6 7.Bg2 O-O 8.O-O a62"92A81 Dutch: 2.g3 Nf6 3.Nf32{lfB76q Sicilian: Dragon, Yugoslav, 9.O-O-O d5 10.exd52\E66b King's Indian: Fianchetto, Yugoslav Panno2 ,"JRB96h Sicilian: Najdorf, 7.f4 Qc7 8.Qf3 b52Ŝ_vD65 QGD: Orthodox, Rubinstein, 9.cxd5 exd5 10.Bd3 h6 11.Bh42Vm9rA26 English: Closed, 5.d3 d6 6.Nf3 Nf6 7.O-O O-O 8.Rb1 a51 DJC51 Evans Gambit: Anderssen Variation1RKrr<B45a Sicilian: Taimanov, 5.Nc31}JPD36k QGD: Exchange, Main Line, 9.Nge2 h612hB01z Scandinavian: Marshall, 4.c4 Nb6 5.Nf3 g6 6.Nc31ytB92o Sicilian: Najdorf, 6.Be2 e5 7.Nb3 Be7 8.O-O O-O 9.Kh11ĚTb+~LD27h QGA: Classical, 6...a6 7.Bb3 cxd41ĉ0]LJE61e King's Indian: 4.Bg5 O-O 5.e3 d61hATdD49i Semi-Slav: Meran, Old Main Line, 11.Nxb5 axb51<A46t Torre Attack: 3...c5 4.c31+/(NkNB16b Caro-Kann: Bronstein-Larsen, 6.Qd31e:ivBA55q Old Indian: Main Line, 8.Re11:"B07q Pirc: 4.Nge21~VE12o Queen's Indian: Petrosian, 5.Nc3 d5 6.Bg5 Be7 7.Qa4+ c6 8.Bxf6 Bxf6 9.cxd5 exd51~{,pDXB21i Sicilian: Grand Prix, Tal Defence, 3.e51w|LdB80k Sicilian: Scheveningen, English, 7...b5 8.Qd21vwEs<JB01l Scandinavian: Grnfeld Variation1p{ǘD88 Grnfeld: Classical Exchange, Main Line, 11.cxd4 Bg4 12.f3 Na51mh6dB23r Sicilian: Closed, Grand Prix, 3...e6 4.Nf3 d51k"T:DA36h English: Symmetrical, 5.a3 e61d+{ӀPA47 Neo-Queen's Indian: Marienbad System1c4E4_FD60 QGD: Orthodox, Rauzer Variation1b7NE15d Queen's Indian: Nimzowitsch, 5.Qb31`Y6JB33b Sicilian: Open, 2...Nc6, 5...Qb61_Lca 6A61 Benoni: Uhlmann, 7...h61] 7YvFE04s Catalan: Open, 5.Nf3 Nc6 6.O-O1I߲E4D23i QGA: Mannheim, 4...c61If#0D46a Semi-Slav: 6.Bd3 a61H8ñp8E04d Catalan: Open, 5.Nf3 b51AnB51j Sicilian: 3.Bb5+ Nd7 4.d4 Nf6 5.Nc3 cxd4 6.Qxd4 e5175JB62a Sicilian: Richter-Rauzer, 6...e6151T_$D11r Slav: 4.e3 g615D\E92s King's Indian: Petrosian, Stein, 8.Bg5 h610hcoZC98b Spanish: Closed, Chigorin, Rauzer Attack10=5RB01u Scandinavian: Portuguese, 4.Nf3 Qxd51,̇PD00w Blackmar-Diemer: Tartakower Defence1**9>ZE92h King's Indian: Gligoric-Taimanov, 7...c61(+ BA43t Old Benoni: Schmidt, 3.e4 g61!?ő1bE99 King's Indian: Mar del Plata, 10.f3 f5 11.Be31URT>A30a English: Symmetrical, 2.b31$,lC43c Russian Game: Modern Attack, Bardeleben Variation1_;]\A90 Dutch: 2.c4 Nf6 3.g3 e6 5.Nf3 d5 6.O-O Bd61rHTrLB01s Scandinavian: 2...Nf6 3.Bb5+ Nbd71겴HA42v Modern: Averbakh, 4...e5 5.dxe51A65n Benoni: Smisch, 8.Bg5 O-O01ГLB93f Sicilian: Najdorf, 6.f4 Qc7 7.Bd30 םZB43o Sicilian: Kan, 5.Nc3 Qc7 6.Bd3 Nf6 7.O-O0ۿ͎RD05m Colle: 5.c3 Nc6 6.Nbd2 Bd6 7.O-O O-O0L|HB01u Scandinavian: Portuguese, 4.Nf30Λ>eUxB22k Sicilian: Alapin, 2...d5 3.exd5 Qxd5 4.d4 Nf6 5.Nf3 Bg40^1bC76 Spanish: Modern Steinitz, Bronstein Variation0=VbB17t Caro-Kann: Steinitz, 5.Bc4 Ngf6 6.Ng5, 8.Bd300:E00a Queen's Pawn: Neo-Indian0 6V<E94b King's Indian: 7.O-O exd40gű6D05e Colle: 3...e6 4.Bd3 c5030\C83 Spanish: Open, Classical, Malkin Variation0*4vB22r Sicilian: Alapin, 2...Nf6 3.e5 Nd5 4.d4 cxd4 5.Nf3 Nc60|ÐWJA06 Reti: Nimzowitsch-Larsen, 2...Nf60[LHC11q French: Burn, 5.Nxe4 Nbd7 6.Nf30~Y*HD33c QGD Tarrasch: Swedish Variation0zv!U(A00o Grob Gambit: e50ue.XC74 Spanish: Modern Steinitz, Siesta, 6.exf50tJA\BD35m QGD: Exchange, 5.Bg5 c6 6.e30^ 8C"A46r Torre Attack0Zx+j4D07a QGD: Chigorin Defence0X^W|d`E04p Catalan: Open, 5.Nf3 c5 6.O-O Nc6 7.Qa4 Bd70PdƱzC93 Spanish: Closed, Smyslov, 12.Nf1 Bd7 13.Ng3 Na5 14.Bc2 c50M0OPC45s Scotch: 4.Nxd4 Bc5 5.Nxc6 Qf6 6.Qd20B`QdC95l Spanish: Closed, Breyer, Main Line, 14.Ng3 g60#.@:B33f Sicilian: Pelikan, 7.Na30!C;RE47 Nimzo-Indian: 4.e3 O-O 5.Bd3 c5 6.Ne2/Ih&xC07q French: Tarrasch, Open, 4.exd5 Qxd5, Main Line, 10.Nxd4/P IdPC42h Russian Game: Cochrane Gambit, 5.d4/KJD48j Semi-Slav: Meran, Pirc Variation/3GXA27 English: Three Knights, 3...g6 4.d4 exd4/Jqm8C26n Vienna: 3.Bc4 Bb4 4.Nf3/ndn@2BD00p Queen's Pawn: Veresov, 3.Nf3/*htTC55x Two Knights: Max Lange, Loman Defence/ڸ@;E19o Queen's Indian: Old Main Line, 9.Qxc3 c5 10.Rd1 d6 11.b3 Bf6/qnE55 Nimzo-Indian: Main Line, Bronstein, 9.Qe2 b6 10.Rd1/P=pTA30w English: Symmetrical, Hedgehog, 9.Rd1/Ⱦ؞TC81 Spanish: Open, Keres, 10.Rd1 O-O 11.c3/ç+8A21 English: Smyslov Defence/ՕVC91f Spanish: Closed, Bogoljubow, 10.d5 Na5/;ܱ4D43e Semi-Slav: 5.Qb3 dxc4/LD27l QGA: Classical, Spassky Variation/3/ F,B07w Pirc: Byrne 4.Bg5/Փ.E"C00w French: 2.d4//`bgBA10 English: 1...b6 2.Nc3 e6 3.e4/k.*B22a Sicilian: Alapin/scE)l:FE47 Nimzo-Indian: 4.e3 O-O 5.Bd3 c5/]:bB80r Sicilian: Scheveningen, Fianchetto Variation/[#(ri{lA46z Torre Attack: 3...h6 4.Bxf6 Qxf6 5.e4 d6 6.Nc3 g6/YVݢjC63p Spanish: Schliemann, 4.Nc3 fxe4 5.Nxe4 Nf6 6.Qe2/RT`SHA55p Old Indian: Main Line, 8.Qc2 a6/HQٖ=4D06n QGD: 2...Bf5 3.Nf3 e6/<ð[f:B08f Pirc: Classical, 5.a4 c6/;ҚPA65r Benoni: Smisch, 8.Bg5 h6 9.Be3 O-O/3v/HD38j QGD: Ragozin, Westphalia, 7.Qc2/351\6D77b Neo-Grnfeld, 6.O-O e6/&4FA02 Bird: From Gambit, Lasker, 5.d4/Lt%|E15p Queen's Indian: Nimzowitsch, 5.b3 Bb4+ 6.Bd2 Be7 7.Bg2 d5/HUn0C38 KGA: Hanstein Gambit.LhD58h QGD: Tartakower, 8.Bd3 Bb7 9.O-O Nbd7 10.Rc1 c5.GN:C33 KGA: Bishop's Gambit, Lopez-Gianutio Countergambit, Hein Variation.K<B23k Sicilian: Closed, 2...Nc6.'\C99i Spanish: Closed, Chigorin, 13...Nc6 14.a3.ۦjC#@VD40k QGD: Semi-Tarrasch, 5.e3 Nc6 6.a3 dxc4.+gJ@>B93k Sicilian: Najdorf, 6.f4 e5.Z?HE81a King's Indian: Smisch, 5...O-O.d?@HE08g Catalan: Closed, 7.Qc2 c6 8.Bf4. H~E69h King's Indian: Fianchetto, Classical, 9.h3 Qa5 10.Re1 exd4.>0B10q Caro-Kann: 2.Nc3 d5.9B93u Sicilian: Najdorf, 6.f4 e5 7.Nf3 Nbd7 8.a4 Be7 9.Bd3 O-O 10.O-O exf4.bDPA16 English: Anglo-Indian, 2.Nc3 g6 3.g3.VB33s Sicilian: Pelikan, Chelyabinsk, 9.Bxf6.PVE98b King's Indian: Mar del Plata, 9.Ne1 c5.43hD87p Grnfeld: Classical Exchange, Seville Variation.B%Anâ^A14 English: Neo-Catalan Declined, 5...O-O 6.b3.Ti|A59o Benko Gambit: 7.e4, Main Line, 11...Nbd7 12.h3 Ra6 13.Re1.VFbBA40c Queen's Pawn: Polish Defence.{=,^E63i King's Indian: Fianchetto, Panno, 8.h3 Rb8.yOEZB33v Sicilian: Pelikan, Sveshnikov, 11.c3 Bg7.u6qkZE93 King's Indian: Petrosian, Keres Variation.tC HD37m QGD: Classical, 5...O-O 6.e3 c5.pp|42D02p Queen's Pawn: London.mB#RC33 KGA: Bishop's Gambit, Chigorin Attack.i{ʁwzLB40l Sicilian: Open, 2...e6, 4.Nxd4 d6.Z7EDB22d Sicilian: Alapin, 2...e6 3.d4.GۇZD68 QGD: Orthodox, Classical, Vidmar, 13...e4.G8Fl'^E63a King's Indian: Fianchetto, Panno Variation.fd@E00m Catalan: 3...Bb4+ 4.Bd2 Qe7.[!8A26 English: Closed, 5.d3 d6.|-Z7fC13c French: Classical, Anderssen-Richter Variation.A-^C42v Russian Game: Classical, Chigorin, 8...Bf5.S>2LC09f French: Tarrasch, Open, Main Line. У#6C61b Spanish: Bird's, 4.Bc4. ڔ1 ,A05 Reti: 1...Nf6 2.b3-Z]VXC68u Spanish: Exchange, Bronstein, 6.Na3 Be6-L^C56m Two Knights: Classical, Moller, 10.Bd2 Qf5-8,jA00j Mieses-fOv8C41f Philidor: Hanham, 4.Bc4-_r0M]DC82b Spanish: Open, Berlin, 10.Bc2-5WJC57j Two Knights: Fritz, Paoli's 8.h4-hӠFA42e Modern: Averbakh, 4...c6 5.Nf3-KdjD36r QGD: Exchange, Main Line, 9.Nf3 Re8 10.O-O-O Nf8-$%WzJA00s Polish: 2...Bxb4 3.Bxe5 Nf6 4.c4-Po:B03f Alekhine: 4.c4 Nb6 5.Nf3-žV4D13k Slav: Exchange, 6.Bf4-U@w:A62 Benoni: Fianchetto, 9.O-O-7E57 Nimzo-Indian: Main Line, 8...dxc4 9.Bxc4 cxd4 10.exd4 Be7 11.Qd3-}FU@C50h Giuoco Piano: Jerome Gambit-|$*A80e Dutch: 2.Bg5 Nf6-1D16n Slav: Bronstein, 6.Ne5 Bh5-X6TC69b Spanish: Exchange, Gligoric, 6.d4 Bg4-QH&A84 Dutch: 2.c4 Nf6-Nyv?<$A00v Benko Opening-DODRD39h QGD: Ragozin, Vienna, 6.e4 c5 7.Bxc4-?lFD35e QGD: Exchange, 5.Nf3 Nbd7 6.e3-4\i DB09p Pirc: Austrian, 5...c5 6.dxc5-y}PC11r French: Burn, 5.Nxe4 Nbd7 6.Nf3 Be7-wFB40l Sicilian: Open, 2...e6, 4.Nxd4-GBց`B30s Sicilian: Rossolimo, 3...e6 4.O-O Nge7 5.b3- p&LE04l Catalan: Open, 5.Nf3 c5 6.O-O Nc6- 2]F A02 Bird: 1..Nf6- DgpB44u Sicilian, Taimanov, Szen, 7.N1c3 a6 8.Na3 Be7 9.Be2- v-$"2E41 Nimzo-Indian: 4.e3 c5-}B07a Pirc,+՞bBD78d Neo-Grnfeld, 6.O-O c6 7.Qa4,=lZC87j Spanish: Closed, Averbakh, 7.c3 O-O 8.d4,gkxW:B22e Sicilian: Alapin, 2...d6,+/E11s Bogo-Indian: Nimzowitsch, 5.g3 Nc6 6.Nc3 Bxc3 7.Bxc3 Ne4 8.Rc1,\7uXC57i Two Knights: Fritz Variation, Main Line,AL(jD42k QGD: Semi-Tarrasch, 7.Bd3 Main Line, 10.Re1 Ncb4, ^k>B72 Sicilian: Dragon, 6.Be3 Bg7,ŊJC21 Danish Gambit: Copenhagen Defence,4PhNE16b Queen's Indian: Capablanca, 6.Nbd2, aBFE49 Nimzo-Indian: Botvinnik, 7...c5,^3|B92k Sicilian: Najdorf, 6.Be2 e5 7.Nb3 Be7 8.O-O O-O 9.Be3 Be6,C"udB63s Sicilian: Richter-Rauzer, 7.Qd2 Be7, 9.Nb3 a6,j{wLB21w Sicilian: Smith-Morra, 4.Nxc3 Nc6,\,B07n Pirc: Pytel/Czech,x B37m Sicilian: Maroczy Bind, 6.Nc2 Nf6 7.Nc3 d6 8.Be2 O-O 9.O-O Be6,|%8D93 Grnfeld: 5.Bf4 O-O 6.e3,DBE8A05 Reti: Santasiere's folly,AGC+ZC89p Spanish: Marshall, Main Line, 15.Be3 Bg4,+NXB84 Sicilian: Scheveningen, Classical, 7.O-O,~ȑ,^D42n QGD: Semi-Tarrasch, 7.Bd3 Main Line, 10.Re1 Nf6 11.a3 b6 12.Bg5,xsJC01e French: Exchange, 4.c4 Nf6 5.Nc3,oUb$B06f Modern: 3.Bc4,g 0UFhB72 Sicilian: Dragon, Classical, Grigoriev Variation,a'jK`D69 QGD: Orthodox, Classical, 13.dxe5: 15.f4 Qf6,Yt_&nE62u King's Indian: Fianchetto, Uhlmann/Szabo Variation,OvH^C56h Two Knights: Classical, Moller, 9.Nxe4 Be6,I{rB19o Caro-Kann: Classical, Spassky, 10.Qxd3 Qc7 11.Bd2 e6,ю4>B96b Sicilian: Najdorf, 7.f4 h6,kzTB36m Sicilian: Maroczy Bind, 5...Nf6 6.Nc3 d6 7.Be2 Nxd4 8.Qxd4 Bg7 9.Bg5 O-O 10.Qd2, qa&\A37x English: Symmetrical, 5.Nf3 e5 6.O-O Nge7+;VNA29 English: Four Knights, 4.g3 g6 5.d4+XqeDD41k QGD: Semi-Tarrasch, 6.e4 Nxc3+<&ŋ`B12u Caro-Kann: Advance, 4.Nf3 e6 5.Be2 c5 6.Be3+hqH2D12g Slav: 4.e3 Bf5 5.Bd3+k2OXDB01a Scandinavian (Centre Counter)+Z~E52 Nimzo-Indian: Main Line, 6...b6 7.O-O Bb7 8.cxd5 exd5 9.Ne5+Ϩq@D33j QGD Tarrasch: Swedish, 9.e4+sLjXD07e QGD: Chigorin, 3.cxd5 Main Line, 7.Bxc3+ۤHA48x Neo-King's Indian: Torre Attack+P: VB81q Sicilian: Scheveningen, Keres, 6...Nc6+̽-XC56j Two Knights: Classical, Moller, 10.Neg5+]>8C54d Giuoco Pianissimo: 5.d3+g:fdE12t Queen's Indian: Petrosian, Kasparov Variation+RtC88p Spanish: Closed, Anti-Marshall 8.a4 Bb7 9.d3 d6 10.c3+@A&,XB97j Sicilian: Najdorf, Poisoned Pawn, 9.Nb3+?OAtB38q Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 d6 9.O-O Nxd4+Xi!*PD23s QGA: Mannheim, Main Line, 10.e3 Ne4+g/:A66 Benoni: Four Pawns Attack+S8"6C32 KGD: Falkbeer, 4.d3 Nf6+{mS1ibC57k Two Knights: Fritz, Gruber Variation (8.Ne4)+v_fB99h Sicilian: Najdorf, Main Line, 10.Bd3 h6 11.Bh4+q{ ;HD25h QGA: Janowski-Larsen, 5.Bxc4 e6+fSއND52k QGD: Cambridge Springs, 8.Qc2 dxc4+ZNV:C60u Spanish: Cozio, 4.O-O g6+IPRB35j Sicilian: Accelerated Fianchetto, Modern, 7.Bc4 O-O 8.Bb3 Ng4+IZȑt:D85a Grnfeld: Exchange, 5.g3+AW]JE00e Queen's Pawn: Neo-Indian, 3...b6+5:8B20 Sicilian: Snyder, 2...e6+3_?_[A29 English: Four Knights, 4.g3 d5 5.cxd5 Nxd5 6.Bg2 Nb6 7.O-O Be7 8.d3+2'19UNB16c Caro-Kann: Bronstein-Larsen, 6.Ne2+(Q)ˍbD63 QGD: Orthodox, 7.Rc1 b6, Capablanca Variation+'cjLA05 Reti: KIA+'-6bA37v English: Symmetrical, 5.Nf3 e5 6.O-O d6 7.d3+۷tFjB01f Scandinavian: 2...Qxd5 3.Nc3 Qa5 4.Nf3 Nf6 5.Be2+ +P*B10p Caro-Kann: 2.Nc3+҆>S6A00m Van Geet: 1...d5 2.Nf3*&shC95f Spanish: Closed, Breyer, 10.d4 Nbd7 11.Nbd2 Bb7*ָ[BB09f Pirc: Austrian, 5...O-O 6.e5*ۦYsNB03s Alekhine: Exchange, 5...cxd6 6.Nc3* |3:A09p Reti: Accepted, 3.Na3 a6*2/`z8RB26p Sicilian: Closed, 6.Be3 e6 7.Qd2 Rb8*՘,@B02a Alekhine: Krejcik Variation* g(JLB80d Sicilian: Scheveningen, 6.Be3 Nc6*d CfE34 Nimzo-Indian: Classical, Noa, 5.cxd5 Qxd5 6.Nf3*߲ ^B38c Sicilian: Maroczy Bind, 6.Be3 d6 7.Nc3 Nh6*9۞0D45c Semi-Slav: 5.e3 Be7*Zd|JhE70r King's Indian: 4.e4 d6 5.Bd3 O-O 6.Nge2 e5 7.d5*6\aHE90a King's Indian: 5.Nf3 Nbd7 6.Be2*e|B14h Caro-Kann: Panov-Botvinnik, 5...g6, Main Line, 8.Be2 Nbd7*ΣeQtB84 Sicilian: Scheveningen, Classical, 7.O-O Qc7 8.Be3 Nc6*4G`E75b King's Indian: Averbakh, 7.d5 e6 8.Nf3 exd5*?.s\E92j King's Indian: Gligoric-Taimanov, 7...Qe7*NK4A22 English: Bellon Gambit*xbuHA44e Old Benoni: Czech, 3.c4 d6 4.e4*m4O96B06n Modern: 3.Nc3 d6 4.Bc4*dadVB59e Sicilian: Boleslavsky, 7.Nb3 Be7 8.Be3*bZ3XB61a Sicilian: Richter-Rauzer, Larsen, 7.Qd2*`=RwZnB33s Sicilian: Pelikan, Chelyabinsk, 9.Bxf6 gxf6 10.Nd5*Ux6C0D45d Semi-Slav: 5.e3 Ne4*S:Q'qPA86 Dutch: Leningrad, 4.Bg2 Bg7 5.Nc3 d6*NiI^@D18g Slav: Dutch, 8...Nbd7 9.Nh4*M#){XC00u French: KIA, Reversed Philidor, 4...Nc6*AP<A08 Reti: KIA, 2...c5 + 3...g6*?y겙^E87e King's Indian: Smisch, Orthodox, 7.d5 Nh5*1՛j:D11c Slav: 3.Nf3 Bf5 4.Nc3 e6*0]p 4C68b Spanish: 3...a6 4.Bc4*.͢":B22f Sicilian: Alapin, 2...d5*+B}TE15n Queen's Indian: Nimzowitsch, 5.b3 Bb7*&c=@A45p Trompowsky: 2...c5 3.d5 Qb6*jUPg6D02a Queen's Pawn: 2.Nf3 g6*=uXLB12j Caro-Kann: Advance, 3...c5 4.dxc5*΃h^E58 Nimzo-Indian: Main Line, 9.bxc3 Qc7 10.cxd5*co@VB06d Modern*Q$PB99m Sicilian: Najdorf, Main Line, 10.g4*Nw^u2A58a Benko Gambit: 5.bxa6)< ?bB49f Sicilian: Taimanov, 6.Be3 a6 7.Be2 Nf6 8.O-O)};* &B07d Pirc: 2.d4 Nf6)1JaD48g Semi-Slav: Meran, 8...a6 9.O-O Bb7 10.e4 c5 11.d5 Qc7 12.dxe6 fxe6)Gp߅~B99u Sicilian: Najdorf, Modern Main Line 13.f5 Bxg5+ 14.Kb1 Ne5)Gu"D10a Slav Defence) ?,?+HA80i Dutch: Alapin, Manhattan Gambit)w(sNA26 English: Botvinnik System, 6...Nge7) %_2D03k Torre Attack: 3...g6)RVA91 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nh3)]'b]0ZB22p Sicilian: Alapin, 2...Nf6 3.e5 Nd5 4.Nf3)]W0A10 English: Anglo-Dutch) VA67p Benoni: Four Pawns, Taimanov, 9.a4 O-O)y @]@D46e Semi-Slav: Chigorin Defence)T'9vE74m King's Indian: Averbakh, 6...c5 7.d5 h6 8.Be3 e6 9.Qd2)OPFn_XD22k QGA: Alekhine, 4.e3 Bg4 5.Bxc4 e6 6.Nc3)-쯼xB65b Sicilian: Richter-Rauzer, 7...Be7, 9.f4 Nxd4 10.Qxd4 h6)\q։WTD43k Semi-Slav: Moscow, 6.Bh4 Be7 7.e3 O-O)]lC06s French: Tarrasch, Closed, 8...f6 9.exf6, 11...O-O)u4SlA94 Dutch: Stonewall, Botvinnik, 8.Ba3 Bxa3 9.Nxa3 Qe7)yyq0EnE89e King's Indian: Smisch, Orthodox Main Line, 10.Qd2)xriNE13a Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4)x [=\C15q French: Winawer, Alekhine Gambit Accepted)n&#'UsDC62 Spanish: Old Steinitz, 4.Bxc6+)eE\E93 King's Indian: Petrosian, Main Line, 8.Be3)cQRB91j Sicilian: Najdorf, 6.g3 e5 7.Nde2 b5)TwV -dE95l King's Indian: 7.O-O Nbd7 8.Re1 c6 9.Bf1 exd4)JM&fHB01u Scandinavian: Portuguese, 4.Be2)<6\,NTD44n Semi-Slav: Botvinnik, Szabo Variation)5ڡE57 Nimzo-Indian: Main Line, 8...dxc4 9.Bxc4 cxd4 10.exd4 Be7 11.Bg5)2؝DbA44i Old Benoni: Czech, 3.c4 d6 4.e4 g6 5.Nc3 Bg7))LKGC4B08b Pirc: Classical, 5.h3)(60hb9JA86 Dutch: Leningrad, 4.Bg2 Bg7 5.Nc3)!QO+JA84 Dutch: Rubinstein, 3...d5 4.e3 c6)!,L&JC90g Spanish: Closed, Pilnik, 9...Na5)[)BC52 Evans Gambit: 5...Ba5 6.d4 d6)SbB44s Sicilian, Taimanov, Szen, 7.N1c3 a6 8.Na3 b6)Ø$0C38 KGA: Hanstein Gambit),M~'BA57o Benko Gambit: 4.cxb5 a6 5.f3(=@o`A75 Benoni: Classical, 9.O-O a6 10.a4 Bg4 11.Nd2(&IbXC48a Four Knights: Spanish, Ranken Variation(\4TXD20q QGA: 3.e4 Nf6 4.e5 Nd5 5.Bxc4 Nb6 6.Bb3(EZFhB48p Sicilian: Taimanov, 6.Be3 a6 7.Bd3 Nf6 8.O-O h5(T9VD98f Grnfeld: Russian, Smyslov, 8.Be3 Nfd7('8\E94c King's Indian: 7.O-O exd4 8.Nxd4 Re8 9.f3(r4NB31c Sicilian: Rossolimo, 3...g6 4.Bxc6(Y %ΡBA17 English: Nimzo-English, 4.Qc2(ݥA2B07s Pirc: Holmov (4.Bc4)( A<RC97a Spanish: Closed, Chigorin, 11.d4 Qc7(ѻLA43j Old Benoni: Clarendon Court, 3.g3(Q'V{>C54f Giuoco Pianissimo: 5.d3 d6(nƍ6D23d QGA: Mannheim, 4...Nc6(&+ehB47o Sicilian: Taimanov, 6.g3 a6 7.Bg2 Nf6 8.O-O Be7(?^9ZA36c English: Symmetrical, Keres-Parma System(E;tA05 Reti: KIA(DA26 English: Closed, 5.d3 d6 6.Rb1(jbC15q French: Winawer, Alekhine Gambit, 5.a3 Bxc3+(#/0C44z Scotch Gambit: 5.c3(L(hD39j QGD: Ragozin, Vienna, 6.e4 c5 7.Bxc4, 8...Bxc3+(FC42q Russian Game: Classical, 6.Bd3(&0_FC93 Spanish: Closed, Smyslov, 12.a3(B$VC41g Philidor: Hanham, Schlechter Variation('NXB01v Scandinavian: Portuguese, 4.f3 Bf5 5.c4(s <C41i Philidor: Morphy, 4...Nc6(o3ʟFA13j English: 1...e6 2.Nf3 Nf6 3.g3(nGD-nA37y English: Symmetrical, 5.Nf3 e5 6.O-O Nge7 7.d3 O-O(k,{2oRB74 Sicilian: Dragon, Classical, 9.Nb3 a6(dJUmPE91w King's Indian: 6.Be2 Bg4 7.Be3 Nfd7(_"*&A25 English: Closed(X[f&A00j Mieses: 1...d5(S&T#VC06l French: Tarrasch, Closed, 8...f6 9.Nf4(Jr4A80h Dutch: 2.Bg5 g6 3.Nc3(IC6g!^C80k Spanish: Open, Schlecter, Berger Variation(=w7E59 Nimzo-Indian: Main Line, 9.bxc3 dxc4 10.Bxc4 Qc7 11.Bd3 e5 12.Qc2 Re8 13.de5(7qJC47b Four Knights: Gunsberg Variation(3jNB21d Sicilian: Grand Prix, 2...e6 3.Nf3(.US:D43r Semi-Slav: Moscow, 7.Qc2(,s;fn^C97l Spanish: Closed, Chigorin, Yugoslav System(+=KyzwLA45w Trompowsky: 2...Ne4 3.Bf4 d5 4.e3(|«QiFC46b Three Knights: Winawer Defence(\HB95h Sicilian: Najdorf, 6...e6 7.Qd3($euBD07g QGD: Chigorin, Lazard Gambit(U%trE13m Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.e3 g5 8.Bg3 Ne4'0gjB23v Sicilian: Closed, Grand Prix, Schofman Variation'ʆ[ZE11h Bogo-Indian: 4.Bd2 Be7 5.g3 d5 6.Bg2 O-O'HD02t Queen's Pawn: 3.g3 c6 4.Bg2 Bg4'뾇%:C02a French: Advance, 3...Ne7'6K6C80i Spanish: Open, 6.d4 b5'g&[-@C44o Ponziani: 3...Nf6 4.d4 exd4'7yTZD30u QGD: 3.Nf3 Nf6 4.e3 c6 5.Nbd2 Nbd7 6.Bd3'ᘰR*޷>A36k English: Symmetrical, 5.e3'.nE36 Nimzo-Indian: Classical, Noa, 5.a3 Bxc3+ 6.Qxc3 O-O'ۮFRhB78j Sicilian: Dragon, Yugoslav, Main Line, 12.h4 h5',HjC24 Bishop's Opening: Urusov Gambit, Estrin Variation'p{ĎB13z Caro-Kann: Panov-Botvinnik, 5...Nc6, Normal Variation, 8.c5 O-O'c:D13p Slav: Exchange, 6.Bf4 e6' avQ:E06 Catalan: Closed, 6.O-O c5'  VA41r Neo-Old Indian: Modern, 3.Nf3 Bg7 4.g3'4B15r Caro-Kann: 4.Nxe4 Nf6'7fE18k Queen's Indian: 7.Nc3 d5 8.Ne5 Na6 9.cxd5 exd5'-wLD54d QGD: Anti-Neo-Orthodox, Main Line'] HD30h QGD: Tarrasch without Nc3: 4.e3'k' FA01 Nimzowitsch-Larsen: Symmetrical' 7SdA88 Dutch: Leningrad, Main Line, 7.Nc3 c6 8.d5 Qe8' l\D25p QGA: Janowski-Larsen, 6.h3 Bh5 7.Nc3 Nbd7'LJD41k QGD: Semi-Tarrasch, 6.e4, 8.cxd4'.4>D44e Semi-Slav: Botvinnik, 7.e5'uW FD19b Slav: Dutch, 8...O-O 9.Qe2 Bg4'rb41LE34 Nimzo-Indian: Classical, Noa, 5.e3'hCFA82 Dutch: Staunton Gambit Accepted'h,E@ZC89k Spanish: Marshall, Main Line (12.d4 Bd6)'ZG|PC87i Spanish: Closed, Averbakh, 7.c3 O-O'XZ3^D43m Semi-Slav: Moscow, 6.Bh4 Gambit, Main Line'VG|6@E50 Nimzo-Indian: 4.e3 O-O 5.Nf3'O)ZD85d Grnfeld: Exchange, 5.e4 Nxc3 6.bxc3 Bg7'Na_HFA22 English: Bremen, Smyslov System'NyH&VD27v QGA: Classical, Rubinstein, 8.Qe2 cxd4';t2͢ C99o Spanish: Closed, Chigorin, 13...Nc6 14.Nb3 a5 15.Be3 a4 16.Nbd2 Bd7':.FB12g Caro-Kann: Edinburgh Variation'95eĊ'bC09l French: Tarrasch, Open, Main Line, 9.Nb3 Bd6'0@rXC09q French: Tarrasch, Open, Main Line, 9.Nb3 Bd6 10.Re1 O-O 11.Bg5 Bg4'0iԛO@B92c Sicilian: Najdorf, 6.Be2 e5'+28A84 Dutch: 2.c4 e6 3.Nf3 Nf6'*j:A43h Old Benoni: 2.d5 e6 3.c4'%ߴ)A46c Neo-Benoni'"%c^E05n Catalan: Open, Classical, 8.a4, 10.Bg5 Bd5'!F'TA27 English: Three Knights, 3...f5 4.d4 e4'!Y<LC36 KGA: Scandinavian, Modern, 5.Bb5+ ' hLV.RB15g Caro-Kann: Gurgenidze: 4.e5 Bg7 5.f4'%`A35k English: Symmetrical, Four Knights, 4.g3 d5&AGd,B90a Sicilian: Najdorf&E84o King's Indian: Smisch, Panno Main Line, 9.h4 h5 10.O-O-O b5 11.Bh6&ݝnkD31a QGD: 3.Nc3&>ݻ7>D82 Grnfeld: 4.Bf4 Bg7 5.e3 c5&ρ9(ȳBA85 Dutch: 2.c4 Nf6 3.Nc3 e6 4.a3&!JXXC11l French: Steinitz, Boleslavsky, 7...cxd4&#g+TE26 Nimzo-Indian: Smisch, 5...c5 6.e3 Nc6&FZE81k King's Indian: Smisch, 5...O-O 6.Be3 a6&PB07d Pirc: 2.d4&BE61i King's Indian: 4.Nf3 d6 5.e3& L<E20 Nimzo-Indian: 4.f3 c5 5.d5&$i5DD40c QGD: Semi-Tarrasch, 5.e3 cxd4&^RDA21 English: Lukin, 5.Nd2 Nf6 6.e3&NB40m Sicilian: Open, 2...e6, 4.Nxd4 Bc5&thB03l Alekhine: Four Pawns Attack, Korchnoi Variation&n58"nB97t Sicilian: Najdorf, Poisoned Pawn, Main Line, 13.e5&{K՛tE38k Nimzo-Indian: Classical, 4...c5 5.dxc5 Na6: 8.b4 Nce4&A!s7\B67k Sicilian: Richter-Rauzer, 7...a6, 9.f4 b5&#`B52o Sicilian: 3.Bb5+ Bd7 4.Bxd7+ Qxd7 5.O-O Nc6&|:-*fD47g Semi-Slav: Meran, Capablanca, 8...Bb7 9.O-O a6&q>DB83 Sicilian: Scheveningen, Modern&^T|J$D21h QGA: 3.Nf3 c5&Z8 lA26 English: Closed, 5.d3 d6 6.Nf3 Nf6 7.O-O O-O 8.Rb1&K' 0TE92r King's Indian: Petrosian, Stein, 8.h3&? kz@C29b Vienna Gambit: 3...d6 4.Nf3&>6-hA30y English: Symmetrical, Hedgehog, Flexible Formation, 11.e4 Qc7&=,FA50c Indian: Mexican Defence, 3.Nc3&;'j"6A00l Van Geet: 1...e5 2.Nf3&;#B$Ѿ*`C43g Russian Game: Modern Attack, 3...Nxe4 4.Bd3&3FlB19n Caro-Kann: Classical, Spassky, 10.Qxd3 Qc7 11.Bd2&0ƉJD47n Semi-Slav: Meran, Wade, 9.O-O b4&/:cXD31h QGD: Alatortsev, 5.Bf4 c6 6.e3 Bf5 7.g4&!BBy2A61 Benoni: 6.Nf3 g6 7.h3&JB96c Sicilian: Najdorf, 7.f4 Nc6 8.e5%FtB11e Caro-Kann: Two Knights, 3...Bg4 4.h3 Bxf3 5.Qxf3 dxe4%ch:B22c Sicilian: Alapin, 2...e6%;|{Dž=DA43s Old Benoni: Schmidt, 3.Nc3 g6%ahyPC51 Evans Gambit: Fraser-Mortimer Attack%"s3B36n Sicilian: Maroczy Bind, 5...Nf6 6.Nc3 d6 7.Be2 Nxd4 8.Qxd4 Bg7 9.Be3%3y#XB41m Sicilian: Kan, 5.c4 Nf6 6.Nc3 Qc7 7.Be2%#Lι`B03t Alekhine: Exchange, 5...cxd6 6.Nc3 g6 7.Be3%̬sVA30i English: Symmetrical, Hedgehog, 6...a6%L2ǀ`D72 Neo-Grnfeld, 5.cxd5 Nxd5 6.e4 Nb6 7.Ne2 Nc6%偈>dC08h French: Tarrasch, Open, 4.exd5 exd5 5.Ngf3 a6%f\HA48o Neo-King's Indian: Torre Attack%|"A45h Indian: 2.g3%xhC36 KGA: Scandinavian, Modern, 5.Bb5+ c6 6.dxc6 Nxc6%r :D53l QGD: 4.Bg5 Be7 5.Nf3 O-O%`X?HE32b Nimzo-Indian: Classical, 4...b6%-H-PD47l Semi-Slav: Meran, Lundin, 9.Ne4 Be7%te>E15q Queen's Indian: Nimzowitsch, 5.b3 Bb4+ 6.Bd2 Be7 7.Bg2 c6 8.O-O%-z>D58k QGD: Tartakower, 8.Be2 Bb7%~d7D50 QGD: 4.Bg5%|Z'2<A22 English: King's, 2.Nc3 Nf6%ygVPD33p QGD Tarrasch: 7.Bg2 cxd4 8.Nxd4 Be7%vsm@D40d QGD: Semi-Tarrasch, 5.e3 a6%t3XE04m Catalan: Open, 5.Nf3 c5 6.O-O Nc6 7.Ne5%fCJV BD27c QGA: Classical, 6...a6 7.Nc3%\GTC11j French: Steinitz, Boleslavsky, 7...a6%[v@ NC31 KGD: Falkbeer, Rubinstein Variation%V 9HC77r Spanish: Wormald Attack, 5...b5%Vִ%#RC89m Spanish: Marshall, Main Line, 13.Re1%SvIBD17k Slav: Central, 6.Ne5 e6 7.f3%M:㌪_ND38g QGD: Ragozin, 5.cxd5 exd5 6.Bg5 h6%I=&0D77a Neo-Grnfeld, 6.O-O%Hhs.A43k Old Benoni: Woozle%>BD31m Semi-Slav: 4.cxd5 exd5 5.Bf4%<ϭO$TD17s Slav: Central, Main Line, 15.Nxc4 O-O%;j4VE83d King's Indian: Smisch, 6...Nc6 7.Nge2%3ĎId,jE96 King's Indian: 7.O-O Nbd7, Old Main Line, 10.dxe5%2Y:G.D06n QGD: 2...Bf5 3.Nf3%1qTgHA23 English: Bremen, Keres, 4.Nf3 d6%1 қolLB09j Pirc: Austrian, 5...O-O 6.Bd3 Nc6%%d!utC41d Philidor: Philidor Countergambit, Zukertort Variation%+TRFD01m Richter-Veresov: 3...Nbd7 4.f3%?\O 2B41c Sicilian: Kan, 5.Be3$fXX-$A00v Benko Opening$ݓPє>B51c Sicilian: 3.Bb5+ Nd7 4.O-O$ֱKxchE29 Nimzo-Indian: Smisch, 5...O-O 6.e3 c5 7.Bd3 Nc6$c,2G_(D45g Semi-Slav: 6.a3$gDd\@B33i Sicilian: Pelikan, 7.Bg5 a6$Z678C01g French: Exchange, 4.Bf4$Uaeu|B92p Sicilian: Najdorf, 6.Be2 e5 7.Nb3 Be7 8.O-O O-O 9.Kh1 Be6$D[HC83 Spanish: Open, Classical, 10.Be3$yVB09t Pirc: Austrian, 5...c5 6.Bb5+ Bd7 7.e5$ZIHE17d Queen's Indian: 6.Nc3 O-O 7.Qc2$1wbB05s Alekhine: Modern, Main Line, 8.Nc3 O-O 9.Be3$" FD33n QGD Tarrasch: Wagner Variation$nJ{>A28 English: Four Knights, 4.e3$>6_xDB80b Sicilian: Scheveningen, 6.Be3$vc:K~E99 King's Indian: Mar del Plata, 10.f3 f5 11.Nd3 Nf6 12.Bd2 f4$v])dD67 QGD: Orthodox, Main Line, Capablanca Variation$s|j2A13s English: Neo-Catalan$k2=TpB01v Scandinavian: Portuguese, 4.f3 Bf5 5.Bb5+ Nbd7 6.c4$k: ~4zE98n King's Indian: Mar del Plata, 9.Ne1 Nd7 10.Nd3 f5 11.Bd2$de/9rB13t Caro-Kann: Panov-Botvinnik, 5...Nc6 6.Nf3 Bg4: 8.Qb3$c3ND15x Slav: Geller Gambit, 6.e5 Nd5 7.a4$a\ e\B93m Sicilian: Najdorf, 6.f4 e5 7.Nf3 Qc7 8.a4$TQtv>}C00a French$KI@C47g Four Knights: Glek, 4...Bc5$UǓXHC24 Bishop's Opening: Paulsen, 4.Nf3$4wVPD07v QGD: Chigorin, 3.Nc3 dxc4 4.Nf3 Nf6#_2tPC92k Spanish: Closed, Zaitsev, 10.d4 Re8#1FC54n Giuoco Piano: Aitken Variation#ܴ̅"Q`B12t Caro-Kann: Advance, 4.Nf3 e6 5.Be2 c5 6.O-O#ЬVbE71j King's Indian: Makagonov, 5...O-O 6.Bg5 Nbd7#L38C29a Vienna Gambit: 3...exf4#$`B30v Sicilian: Rossolimo, 3...e6 4.O-O Nge7 5.c3#* 0A10 English: Anglo-Dutch#d=HJ A04 Reti: 1...c5#Co2B20 Sicilian: Wing Gambit#K𡓏@C01j French: Exchange, 4.Bd3 Bd6#k!c_rE52 Nimzo-Indian: Main Line, 6...b6 7.O-O Bb7 8.cxd5 exd5#"0C38 KGA: Philidor Gambit#hm0hZE62q King's Indian: Fianchetto, Spassky, 8.d5#ufC43i Russian Game: Modern Attack, 3...Nxe4 4.Bd3 d5#*fq&B07t Pirc: 4.Be3 c6#WHEDD52g QGD: Cambridge Springs, 7.Nd2#u4x ]HA57p Benko Gambit: 4.cxb5 a6 5.f3 e6#pռ$2A43k Old Benoni: 2.d5 Nf6#j)RD86 Grnfeld: Classical Exchange, Simagin#j.h/LB89 Sicilian: Velimirovic, 9.O-O-O Qc7#a{q}>bB14k Caro-Kann: Panov-Botvinnik, 5...e6 6.Nf3 Be7#M)[sJA48k Neo-King's Indian: London System#Kɐ@ND61 QGD: Orthodox, Rubinstein, 7.Qc2 a6#7B@A45s Trompowsky: 2...Ne4 3.h4 c5#.&zjpC95l Spanish: Closed, Breyer, Main Line, 14.Ng3 g6 15.b3#.%E60r King's Indian: Fianchetto without Nc3, 6...Nbd7 7.Qc2 e5 8.Rd1 Re8#!(ar6E11g Bogo-Indian: 4.Bd2 Be7#iүEjC25q Vienna: Hamppe-Allgaier Gambit, Alapin Variation#u2qF.A07 Reti: KIA, Yugoslav# ޕE97m King's Indian: Mar del Plata, Bayonet Attack, 9...Nh5 10.c5# j<hC89v Spanish: Marshall, Main Line, Classical, 18.Qf1"optpA92 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nf3 O-O 6.Nc3 d6"J NB75 Sicilian: Dragon, Yugoslav, 7...Nc6"pGLFE51 Nimzo-Indian: 4.e3 O-O 5.Nf3 d5"oWqB85 Sicilian: Scheveningen, Classical, Main Line, 9...Nc6 10.Qe1 Qc7 11.Qg3"񐪣2#ZB66c Sicilian: Richter-Rauzer, 7...a6 8.O-O-O"ɆtD12f Slav: 4.e3 Bf5 5.cxd5 cxd5 6.Nc3, Amsterdam Variation"?%--fC14n French: Classical, Steinitz, 9.Qd2 Nc6 10.dxc5"ܐ/!4A10 English: 1...Nc6 2.Nc3"ښ!}]PC18k French: Winawer, 6...Ne7 7.Qg4 Nbc6"\c˱B97p Sicilian: Najdorf, Poisoned Pawn, 10.e5 dxe5 11.fxe5 Nfd7 12.Bc4"1BA60o Benoni: 4.Nc3 exd5 5.cxd5 g6"S\YLdE82f King's Indian: Smisch, Fianchetto, 7.Bd3 Bb7"0 VI\D29j QGA: Classical, 8...Bb7 9.Rd1 Nbd7 10.Nc3"-h S@B29b Sicilian: Nimzowitsch, 3.d3"7)!zZA35j English: Symmetrical, Four Knights, 4.g3"FG"tC47s Four Knights: Scotch, 4...exd4 5.Nxd4 Bb4 6.Nxc6 bxc6"5\FD07t QGD: Chigorin, 3.Nc3 dxc4 4.d5"5>6C38 KGA: 3.Nf3 g5 4.Bc4 Bg7"SX<A03 Bird: 1...d5 2.Nf3 g6 3.g3"OXB45v Sicilian: Taimanov, Four Knights, 6.Ndb5 Bb4 7.a3, 10.Bd3 O-O 11.O-O d4"\D36p QGD: Exchange, Main Line, 9.Nf3 Re8 10.h3"<,@|tE79b King's Indian: Four Pawns Attack, Main Line, 9...Nxd4"_.oZE04u Catalan: Open, 5.Nf3 Nc6 6.O-O Rb8 7.Nc3"H<9SDA55j Old Indian: 5.e4 Be7 6.Be2 c6"Z0RJD85l Grnfeld: Modern Exchange, 8.Be2"UntB84 Sicilian: Scheveningen, Classical, 7.O-O Qc7 8.Kh1 Nc6"L6ɑXB08c Pirc: Classical, Spassky System, 6...d5"|([;^D86 Grnfeld: Classical Exchange, Simagin, 9.h4"z`gNfA90 Dutch: 2.c4 Nf6 3.g3 e6 5.Nf3 d5 6.O-O Bd6 7.b3"wlŨ(A00p Polish: 1...Nf6"u=esXE72 King's Indian: 4.e4 d6 5.g3 O-O 6.Bg2 e5"hx~bD58h QGD: Tartakower, 8.Bd3 Bb7 9.O-O Nbd7 10.Bg3"g(tnHVC33 KGA: Bishop's Gambit, Ruy Lopez Defence"]L B97u Sicilian: Najdorf, Poisoned Pawn, Main Line, 13.e5 dxe5: 15.Ne4"\|,D21r QGA: 3.Nf3 c5 4.d5 e6 5.Nc3 exd5 6.Qxd5 Qxd5 7.Nxd5 Bd6 8.Nd2"\CaDD10r Slav: 3.Nc3 dxc4 4.e4 b5 5.a4"SҧJMt<B12b Caro-Kann: Ulysses Gambit"Ox`C04e French: Tarrasch, Guimard, Main Line, 6.Bb5"I4C!VD22f QGA: Alekhine, 4.e3 e6 5.Bxc4 c5 6.Qe2"5ҖR N^D09 QGD: Albin, 5.g3 Be6 6.Nbd2 Qd7 7.Bg2 O-O-O"4>rv8B20 Sicilian: Snyder, 2...d6"3qd4D51 QGD: Rochlin Variation"0C L8D53d QGD: 4.Bg5 Be7 5.Nf3 h6"" 乇fE51 Nimzo-Indian: 4.e3 O-O 5.Nf3 d5 6.Bd3 Nc6 7.O-O""de{ҽdA88 Dutch: Leningrad, Main Line, 7.Nc3 c6 8.d5 Qa5"҄~E69v King's Indian: Fianchetto, Classical, 9.h3 Re8 10.Re1 exd4"9LqnA33c English: Symmetrical, Two Knights, 5.Nc3 Nc6 6.Bg5" i\ɠCrB14d Caro-Kann: Panov-Botvinnik, 5...g6 6.cxd5 Nxd5 7.Bc4"i_|>C34 KGA: Gianutio Countergambit"C.^B01t Scandinavian: Scandinavian Gambit Accepted"r^fB98q Sicilian: Najdorf, 8...Qc7 9.O-O-O Nc6 10.Nxc6"Fb>A53 Old Indian: 3.Nf3 Bg4 4.Qb3!*oHC30n KGD: Classical, Marshall Attack!YZW5TbB47w Sicilian: Taimanov, 6.Be2 a6 7.O-O Nf6 8.Kh1!^#T@xE82g King's Indian: Smisch, Fianchetto, 7.Bd3 Bb7 8.Nge2 c5!dE+*B70a Sicilian: Dragon!fmR4&A40i Englund Gambit!ӸK>ZB96b Sicilian: Najdorf, Delayed Poisoned Pawn!wPE45 Nimzo-Indian: Nimzowitsch, 5.Ne2 Ba6!>^A83c Dutch: Staunton Gambit, Chigorin Variation!=_VB67c Sicilian: Richter-Rauzer, 7...a6, 9.f3!.|UJC80i Spanish: Open, Richter Variation!Txbb,C37 KGA: Quaade Gambit!n'I8E61a King's Indian: 3.Nc3 c5!]>NLB05b Alekhine: Modern, Panov Variation!%;hC84i Spanish: Closed, Centre Attack, 7.e5 Ne4 8.Nxd4!^3BC64a Spanish: Classical, Exchange!֦ 08C42p Russian Game: Classical!cINjA92 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nf3 O-O 6.Nc3!6Y̟zB34q Sicilian: Accelerated Fianchetto, Modern, 6.Be3 Nf6 7.f3!{Y56NE02 Catalan: Open, 5.Qa4+ Nbd7 6.Nf3 a6!x#/X`#LXB55 Sicilian: Prins, Venice Attack, 6...Nbd7!wgC!{<A00o Grob Gambit: Spike Attack!lᆩT(A45d Indian: 2.e3 g6!\-\,GD76f Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O Nb6 8.Nc3 Nc6 9.e3 e5 10.d5 Na5!Z|"צ4DD95i Grnfeld: 5.e3 O-O 6.Qb3 dxc4!R)r$A00t Benko Opening!O23(B20 Sicilian: Snyder!BF0@D18i Slav: Dutch, 8...Nbd7 9.Qb3!=]f#B67n Sicilian: Richter-Rauzer, 7...a6, 9.f4 b5 10.Bxf6 gxf6 11.f5!:K(rE11w Bogo-Indian: Nimzowitsch, 5.g3 Nc6 Main Line, 8...a5!*zN|LD68 QGD: Orthodox, Classical Variation!'o䧱6B06o Modern: 3.Nc3 d6 4.Be3!%1|6RHC42g Russian Game: Damiano Variation!ehC24 Bishop's Opening: Urusov Gambit, Keres Variation! v|k6D11o Slav: Slav-Reti System!>RƒNE17f Queen's Indian: 6.Nc3 O-O 7.Qc2 d5 M.c.D20j QGA: 3.Nc3 e6 4.e4 b\B12f Caro-Kann: Maroczy (Fantasy), Gambit line ѯ:D15m Slav: Chameleon, 5.a4 e6  <A80i Dutch: Von Pretzel Gambit ŸE7U$BLB26h Sicilian: Closed, 6.Be3 Rb8 7.Qd2 ZVA56l Benoni: 3.d5 d6 4.Nc3 g6 5.e4 Bg7 6.f3 +6A45b Indian: Canard Opening ]˽<E12w Queen's Indian: 4.Nc3 Bb7 GZH:C44i Ponziani: Reti Variation B;ڂB67p Sicilian: Richter-Rauzer, 7...a6, 9.f4 b5 10.Bxf6 gxf6 11.Nxc6 Bxc6 12.Qe1 ԓdC18p French: Winawer, 6...Ne7 7.Qg4 O-O 8.Bd3 Nbc6 lJMLC96b Spanish: Closed, Chigorin, 10.Bc2 bH*!^C56n Two Knights: Classical, Moller, 10.Bd2 Qd5 >)q^D84 Grnfeld: Grnfeld Gambit Accepted, 8...Na6 T(Y8E91d King's Indian: 6.Be2 c6 XA65e Benoni: 6.e4 g6 7.Bf4 a6 8.Nf3 b5 9.Qe2 ~I4\FC84g Spanish: Closed, Centre Attack |AhB70n Sicilian: Dragon, 6.Be2 Bg7 7.O-O Nc6 8.Nb3 O-O yr(']iDC60f Spanish: Vinogradov Variation xpfE45 Nimzo-Indian: Nimzowitsch, 5.Ne2 Ba6 6.a3 Bxc3+ mqTXB15h Caro-Kann: Gurgenidze: 4.e5 Bg7 5.f4 h5 WNC26h Vienna: Smyslov, 3...Bc5 4.Bg2 Nc6HECLJC24 Bishop's Opening: Paulsen Defenceѵ(K3ZC49n Four Knights: Symmetrical, Metger, 10.d4׶R>A46x Torre Attack: 3...h6 4.Bh4Ųg:A04 Reti: Lisitsin: 3.Ng5 Nf6~>K^C06c French: Tarrasch, Closed, Leningrad, 9.Nf3k뚣RE17h Queen's Indian: Opovcensky Variationh˞>A53 Old Indian: Ukrainian, 4.d5ڥ9(A80r Dutch: 2.Nf3 e6 5,iVD47d Semi-Slav: Meran, Capablanca Variation8(A54 Old Indian: 5.e3E'5xB13w Caro-Kann: Panov-Botvinnik, 5...Nc6, Czerniak Variationz6j[XA85 Dutch: 2.c4 Nf6 3.Nc3 g6 4.Nf3 Bg7 5.Bf4uƨ &A25 English: ClosedudhD59e QGD: Tartakower, 8.cxd5 Nxd5 9.Bxe7 Qxe7 10.Rc1j4{ljB33n Sicilian: Pelikan, Chelyabinsk, 9.Nd5 Be7, 11.c3c-^FC72 Spanish: Modern Steinitz, 5.O-Obp竬\@D27a QGA: Classical, 6...a6 7.a3_ѡ HE17g Queen's Indian: 6.Nc3 Ne4 7.Qc2ZhKCDPE07 Catalan: Closed, 6...Nbd7 7.Nc3 dxc4Y#GDFE05k Catalan: Open, Classical, 8.a4XO~B99k Sicilian: Najdorf, Main Line, 10.Bd3 b5 11.Rhe1 Bb7 12.Nd5QQL|V:A00m Van Geet: 1...d5 2.e4 d4H><dD64 QGD: Orthodox, Rubinstein Attack, 8...Re8 9.a3Ex2lD03t Torre Attack: 3...g6 4.e3 Bg7 5.Nbd2 O-O 6.Bd3 c5DA9>B40h Sicilian: 2...e6 3.Nc3 Nc6? JEWBB10f Caro-Kann: Breyer, Main Line:P^VB56j Sicilian: Open, 2...d6, 5.Nc3 Nc6 6.g37D5w\A32 English: Symmetrical, Two Knights, 5.g3 d569[QwtE29 Nimzo-Indian: Smisch, 5...O-O 6.e3 c5 7.Bd3 Nc6 8.Nf35!DA36m English: Symmetrical, 5.e3 e6&x>PE94s King's Indian: 7.O-O Nbd7 8.Qc2 Re8"~x } JA48l Neo-King's Indian: London SystemFMBC45g Scotch: Steinitz, 5.Nb5 Bb4+9FE80h King's Indian: Smisch, 5...c5RmU%2E15a Queen's Indian: 4.g31\PD36p QGD: Exchange, Main Line, 9.Nf3 Re8_u&!ZA38l English: Symmetrical, Main Line, 7.d3 a6{c nA76 Benoni: Classical, Main Line, 10.Qc2 Na6 11.Re1 Bg4z^\B97i Sicilian: Najdorf, Poisoned Pawn Accepted.^:4HA48v Neo-King's Indian: Torre Attack?^hRBD85d Grnfeld: Exchange, 5.e4 Nb6AZC86j Spanish: Worrall Attack, 7...O-O 8.c3 d5b9[DD94 Grnfeld: Opovcensky Variationٱ3QzE33 Nimzo-Indian: Classical, Milner-Barry (Zurich), 6.Bd2 O-Oտ՗HC02v French: Advance, 5.Nf3 Qb6 6.a3Ѿ 0"D06l QGD: 2...Bf5VmG<HD26t QGA: Classical, 6.O-O Nc6 7.Qe2"cDzFD77f Neo-Grnfeld, 6.O-O dxc4 7.Na3N]_kfD03s Torre Attack: 3...g6 4.e3 Bg7 5.Nbd2 O-O 6.Bd3vy8tXC19e French: Winawer, 6...Ne7 7.Nf3 Qc7 8.a4~1:E04a Catalan: Open, 5.Nf3 Bd7JsEHA22 English: King's, 2.Nc3 Nf6 3.Nf3)߯=lNC44f Open Game: Inverted Philidor, 4.g3O .KiND41r QGD: Semi-Tarrasch, 6.e3 Nc6 7.Bc4yEK}y<BA58c Benko Gambit: Accepted, 6.g3v.,\+DA85 Dutch: 2.c4 Nf6 3.Nc3 e6 4.Qc2sH:HZE21 Nimzo-Indian: Nimzo-Queen's Hybrid, 5.Qc2of>BD03g Torre Attack: 3...e6 4.e3 c5g?:B42e Sicilian: Kan, 5.Bd3 Nc6c+[BRE39b Nimzo-Indian: Classical, Pirc, 6.Bf4[ ]jB84 Sicilian: Scheveningen, Classical, 7.O-O Qc7 8.f4YQLB47h Sicilian: Taimanov, 6.g3 a6 7.Bg2X+49lRC90k Spanish: Closed, Pilnik, 11.Nbd2 Re8U'>l:A20 English: King's, 2.g3 Nc6S}adDB09g Pirc: Austrian, 5...O-O 6.Be3Op]VD85g Grnfeld: Exchange, 7.Be3 c5 8.Qd2 O-OAb%RC10k French: Rubinstein, 5.Nf3 Ngf6 6.Bd3= n_ znA30x English: Symmetrical, Hedgehog, Flexible Formation9W~hjD05n Colle: 5.c3 Nc6 6.Nbd2 Bd6 7.O-O O-O 8.dxc5 Bxc56l;%).C33 KGA: Carrera Gambit68ۧ~\bC10f French: Rubinstein, Frere (Becker) Variation4&t6*B69 Sicilian: Richter-Rauzer, 7...a6, 9.f4 Be7 10.Nf3 b5 11.Bxf6 gxf6 12.f5.{ND39e QGD: Ragozin, Vienna, 6.e4 c5 7.e5)+̻NA46t Torre Attack: 3...c5 4.c3 h6 5.Bh4(D>(A56h Benoni: 3.d5 g6$kRA99 Dutch: Ilyin-Zhenevsky, 8.b3 a5 9.Ba3$a&dB52j Sicilian: 3.Bb5+, Sokolsky, 5...Nc6 6.O-O Nf6x=FB22c Sicilian: Alapin, 2...e6 3.Nf3&FA00f Creepy Crawly Opening (Basman)/NB53k Sicilian, Chekhover, 4...Nf6 5.Nc3 M<<B05a Alekhine: Modern, 4...Bg40 ,}aTE90p King's Indian: 5.Nf3 O-O 6.h3 e5 7.d5D±*PLD78i Neo-Grnfeld, 6.O-O c6 7.Qb3 dxc47@A34 English: Symmetrical, 2...g6瀸6XNA22 English: King's, 2.Nc3 Nf6 3.Nf3 d6.2C80j Spanish: Open, 7.Bb3pCOzB96u Sicilian: Najdorf, Polugaevsky, 10.Qe2 Nfd7 11.O-O-O Nc6߄ 4C29b Vienna Gambit: 3...d6d(A18 English: MikenasfW,4|E59 Nimzo-Indian: Main Line, 9.bxc3 dxc4 10.Bxc4 Qc7 11.Ba2 e5LD98e Grnfeld: Russian, Smyslov, 8.Be3z3G@A43w Old Benoni: Schmidt, 6.Bb5+swbD75 Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O c5 8.dxc5 Na6 2A40w Queen's Pawn: ModernubIPE48 Nimzo-Indian: 4.e3 O-O 5.Bd3 d5 6.a3h=8ZE14k Queen's Indian: 4.e3 Bb7 5.Bd3 Be7 6.O-O1NA09u Reti: Accepted, 3.e3 Nf6 4.Bxc4 e6K}ItD42m QGD: Semi-Tarrasch, 7.Bd3 Main Line, 10.Re1 Nf6 11.a3H?fB99g Sicilian: Najdorf, Main Line, 10.Bd3 h6 11.Qh36#BA23 English: Bremen, Keres, 4.Bg2i6D11p Slav: Slav-Reti System[I(a4A03 Bird: Lasker Variationb8A20 English: King's (1...e5)"1HA48v Neo-King's Indian: Torre Attack5rFsfC23 Bishop's Opening: MacDonnell, Four Pawns Gambit]`E12p Queen's Indian: Petrosian, 6.cxd5 exd5 7.g3{@ RFB43j Sicilian: Kan, 5.Nc3 Qc7 6.Be2sHYv4E79f King's Indian: Four Pawns Attack, Main Line, 9...Bd7 10.O-Oq@K-lC87d Spanish: Closed, Averbakh, 7.Bxc6+ bxc6 8.d4 exd4pLA20 English: King's, 2.g3 Nf6 3.Bg2 d5nuTTB47u Sicilian: Taimanov, 6.Be2 a6 7.O-O b5j!^dD85l Grnfeld: Modern Exchange, 8.Be2 O-O 9.O-O b6g,f63"C50h Giuoco Piano]VݍnB53o Sicilian, Chekhover, 4...Nc6 5.Bb5 Bd7 6.Bxc6 Bxc6SH{y:A56j Benoni: 3.d5 d6 4.Nc3 g6S;_0A54 Old Indian: 5.g3 Be7Df}B35m Sicilian: Accelerated Fianchetto, Modern, 7.Bc4 O-O 8.Bb3 a5 9.a4~E69r King's Indian: Fianchetto, Classical, 9.h3 Re8 10.Be3 exd4/֫FE91v King's Indian: 6.Be2 Bg4 7.Be3/, ]\8fB76s Sicilian: Dragon, Yugoslav, 9.O-O-O d5: 12.Bd4)n1.B07f Pirc: 3.f3 e5 4.d5(;w 4A46h Indian: 2.Nf3 d6 3.g3&X+eadC13o French: Chatard-Alekhine, Maroczy, 7.Qg4 Bxg5"h,RB47i Sicilian: Taimanov, 6.g3 a6 7.Bg2 d6!BA57m Benko Gambit: 4.cxb5 a6 5.e3k*CBD44h Semi-Slav: Botvinnik, 9.Nxg5~+N"Q:E15t Queen's Indian: 4.g3 Bb7r7 @B53f Sicilian, Chekhover, 4...a6eF\E87c King's Indian: Smisch, Orthodox, 7.d5 c5mpB67j Sicilian: Richter-Rauzer, 7...a6, 9.f4 h6 10.Bh4 g5>DC45g Scotch: Steinitz, 5.Nb5 Qxe4+l[`C44w Scotch: Goring Gambit, Bardeleben Variation粘&0D22a QGA: Alekhine, 4.e3I snE71n King's Indian: Makagonov, 5...O-O 6.Bg5 c5 7.d5 b5p\B96h Sicilian: Najdorf, 7.f4 Qc7 8.Qf3 b5 9.f5&?#RD03n Torre Attack: 3...g6 4.e3 Bg7 5.Nbd2,=D76h Neo-Grnfeld, 6.cxd5 Nxd5 7.O-O Nb6 8.Nc3 Nc6 9.e3 Re8 10.d5\ͦ LC80r Spanish: Open, Bernstein, 9...Nc54UJD31l Semi-Slav: 4.cxd5 exd5 5.Nf3 Bf5"d4E46 Nimzo-Indian: 4.e3 O-OfLϨ<D85i Grnfeld: Modern Exchange7_mfE69g King's Indian: Fianchetto, Classical, 9.h3 Qa5ILC28f Vienna: 3.Bc4 Nc6 4.d3 Na5 5.Nge2n\D49g Semi-Slav: Meran, Sozin, Stahlberg AttackF qND25e QGA: Smyslov, 5.Bxc4 Bg7 6.O-O O-O΋#nC15l French: Winawer, Winkelmann-Reimer, Hbner Defence;[{&LD71 Neo-Grnfeld, 5.cxd5 Nxd5 6.e4 Nb4`m|wZA31 English: Symmetrical, Two Knights, 4...g6ZsJA45s Trompowsky: 2...Ne4 3.h4 c5 4.d5|9F*D45h Semi-Slav: 6.Qc2nԶy9VA34 English: Symmetrical, 3 Knights, 3...g6eȖsPA49 Neo-King's Indian: Fianchetto SystemaEVDC46j Three Knights: Steinitz, 4.d4^֢j[:B07m Pirc: 3.Nc3 e5 Queenswap^OAIHC01v French: Exchange Winawer, 5.Bd3TZnA67j Benoni: Four Pawns, Taimanov, 9.Bd3 O-O 10.Nf3 Na6KDJDE14v Queen's Indian: 4.e3 Bb7 5.Bd3 c5 6.O-O Be7 7.b3 O-O 8.Bb2 d5H/tG:A65k Benoni: Smisch, 7...Bg7G%lD69 QGD: Orthodox, Classical, 13.dxe5: 15.f4 Qf6 16.e4E4}>C78r Spanish: Archangelsk, 7.c3ErRND59k QGD: Tartakower, Main Line, 11.Rc1?1KNA25 English: Closed, Taimanov Variation'p^VE36 Nimzo-Indian: Classical, Noa, Main Line!xq:A46j Indian: 2.Nf3 e6 3.c3 b6?*<>D47a Semi-Slav: Meran Variation 7,ߡLB21i Sicilian: Grand Prix, Tal Defence'97LA45v Trompowsky: 2...Ne4 3.Bf4 d5 4.f39[>D24t QGA: Bogoljubow, 7.a4 Nxc3 cp<B51b Sicilian: 3.Bb5+ Nd7 4.c3k+LD97l Grnfeld: Russian, Simagin, 8.Be2Imp >E72 King's Indian: Pomar SystemsbhuaFA43s Old Benoni: Schmidt, 3.Nf3 Nf68R^$z8C11b French: Swiss Variation})QPHE22 Nimzo-Indian: Spielmann, 4...Nc6Ka.6E08a Catalan: Closed, 7.Qc2%Z/VC27h Vienna: 3.Bc4 Nxe4 4.Qh5 Nd6 5.Bb3 Nc6C8BA53 Old Indian: Ukrainian, 4.dxe57؄XWE17z Queen's Indian: Pomar, Polugaevsky, 8...c6 9.cxd5 Nxd5 10.Nf5 Nc7 11.e4&J]6C01c French: Exchange, 4.c49oPHC03e French: Tarrasch, 3...a6 4.Ngf3:ijPA71 Benoni: Classical, 8.Bg5 h6 9.Bh4 a6MŊőLB22c Sicilian: Alapin, 2...e6 3.Nf3 d5?8PC02e French: Advance, Nimzowitsch Gambita~[εZA46y Torre Attack: 3...h6 4.Bxf6 Qxf6 5.e4 b6cLZFD94 Grnfeld: Slav/Schlecter, 6.Bd3uTC69a Spanish: Exchange, Gligoric Variation,QJC54o Giuoco Piano: Steinitz Variation"rֳLtC10v French: Rubinstein, 4...Bd7 5.Nf3 Bc6 6.Bd3 Nd7 7.O-O@fC49k Four Knights: Symmetrical, Pillsbury VariationxrfC11k French: Steinitz, Boleslavsky, 7...a6 8.Qd2 b5aFC44i Ponziani: Romanishin Variation}ATC86f Spanish: Worrall Attack, 7...O-O 8.c3o(B17n Caro-Kann: Steinitz, 5.Ng5 Ngf6 6.Bd3, Main Line 10.Qxe4 Qc7hE~MhE73o King's Indian: Averbakh, 6...Nbd7 7.Qd2 e5 8.d5fΣSJD00l Blackmar-Diemer: 2.e4 dxe4 3.Nc3\r'.A54 Old Indian: 5.g3 g6Zj7~6FB50b Sicilian: Wing Gambit deferredVtC. rB37k Sicilian: Maroczy Bind, 6.Nc2 Nf6 7.Nc3 d6 8.Be2 O-OTQ^A80p Dutch: 2.Nc3 Nf6 3.Bg5 d5 4.Bxf6 exf6 5.e3Ma32%fD87d Grnfeld: Classical Exchange, 8...c5 9.Be3 Nc6M Il(FB01b Scandinavian: 2...Qxd5 3.d4 e5LfAӁ8A00m Van Geet: Hector GambitKWm^D19d Slav: Dutch, 8...O-O 9.Qe2 Bg6 10.Rd1 Nbd7K>cB34r Sicilian: Accelerated Fianchetto, Modern, 6.Be3 Nf6 7.Nxc6 bxc6 8.e5Hv8C49a Four Knights: 4.Bb5 Bb47@]hA58t Benko Gambit: Fianchetto, Main Line, 11.Qc2 Qb6i1d&TA70l Benoni: Classical, 8.h3 O-O 9.Bd3 Bd7 J lA32 English: Symmetrical, Two Knights, 5.Nc3 Bb4 6.Bd2߬`zE19n Queen's Indian: Old Main Line, 9.Qxc3 c5 10.Rd1 d6 11.b3xVlBB21c Sicilian: Grand Prix, 2...d6MJ`HD46g Semi-Slav: Chigorin, 7.Qc2 dxc4 8tE04r Catalan: Open, 5.Nf3 c5 6.O-O Nc6 7.Qa4 Bd7 8.Qxc4 b51jB84 Sicilian: Scheveningen, Classical, 7.O-O Be7 8.f4*f@tNE12j Queen's Indian: Petrosian, 4...Bb7FLC56e Two Knights: Classical, 8.Nc3 Qd8T?6NA13t English: Neo-Catalan, 4...c5 5.O-O =_SXC06m French: Tarrasch, Closed, 8...f6 9.exf6'unC15l French: Winawer, Winkelmann-Reimer Gambit Accepted﯁/6^E09n Catalan: Closed, Main Line, 9.e4 Bb7 10.b3P E12u Queen's Indian: Petrosian, Kasparov, 7...Nxc3 8.bxc3 c5 9.e4c`TA54 Old Indian: 5.g3 Be7, Main Line, 8.Qc2D\C47q Four Knights: Scotch, 4...exd4 5.Nxd4 Bc5 D(VA32 English: Symmetrical, Two Knights, 5.g37HB90e Sicilian: Najdorf, Adams Attack %@,A48c Neo-King's Indianynga"A00o Grob: 1...d5fX9^A91 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nc3 O-O^>|]ZA90 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 c6 5.Nf3 d5]pE90x King's Indian: 5.Nf3 O-O 6.h3 c5 7.d5 e6 8.Bd3 exd5ZfʠeDA59g Benko Gambit: 7.e4 Line, 9.g4O<RD63 QGD: Orthodox, Swiss, Karlsbad, 9.Bd3Ns@Sd*(A61 Benoni: 6.Nf3 g6JU [U*C00j French: 2.Nf3 d5D8>xD58j QGD: Tartakower, 8.Bd3 Bb7 9.O-O Nbd7 10.Qe2 c5 11.Rfd1AפJC78l Spanish: 5.O-O b5 6.Bb3 Bc5 7.a4<wVB56k Sicilian: Open, 2...d6, 5.Nc3 Nc6 6.f4HYXB22p Sicilian: Alapin, 2...Nf6 3.e5 Nd5 4.d474nC39 KGA: Kieseritsky, Berlin Defence, Riviere VariationWb0jE76g King's Indian: Four Pawns Attack, 6.Nf3 Na6 7.e5.,A47 Neo-Queen's Indian9QxE32p Nimzo-Indian: Classical, 4...O-O 5.a3, 6...b6 7.Bg5 Bb7v&s>A15 English: Anglo-Indian, 2.g37>D19a Slav: Dutch, 8...O-O 9.Qe2ܱec.D21l QGA: 3.Nf3 c5 4.d5V5jE14u Queen's Indian: 4.e3 Bb7 5.Bd3 c5 6.O-O Be7 7.b3N0Go,dB03l Alekhine: Four Pawns Attack, Fahrni Variation7zA77 Benoni: Classical, Main Line, 10.Nd2 Nbd7 11.a4 a6 12.Qc2WC3A30y English: Symmetrical, Hedgehog, Flexible Formation, 11.e4 O-OMjB55 Sicilian: Prins, Venice Attack, 6...Nbd7 7.Nf5 d5Զb(y8B50c Sicilian: 2.Nf3 d6 3.b3,x8D34o QGD Tarrasch: 9.Bg5 Be6JC65h Spanish: Berlin, Duras VariationB.:BC20 Open Game: Portuguese Openingtg@C15g French: Winawer, 4.Bd3 dxe4?DD6dB15i Caro-Kann: Gurgenidze: 4.e5 Bg7 5.f4 h5 6.Nf3$@A30b English: Symmetrical, 2.Nf3Ǭ_XD13o Slav: Exchange, 6.Bf4 a6 7.e3 Bg4 8.Be2SpB68 Sicilian: Richter-Rauzer, 7...a6, 9.f4 Be7 10.Nf3 b5L<D46e Semi-Slav: Chigorin, 7.e4G''ZA02 Bird: From Gambit, Lasker, Queenswap Line*ݦZC33 KGA: Bishop's Gambit, Bryan Countergambit|ikѮA51a Budapestv\RE50 Nimzo-Indian: 4.e3 O-O 5.Nf3 c5 6.Bd3qG8ӨDC42h Russian Game: Cochrane Gambith4g/XE83e King's Indian: Smisch, Ruban VariationhFE07 Catalan: Closed, 6...Nbd7 7.Nc3eۂQDD57 QGD: Lasker Defence, Main LineY(\D91q Grnfeld: 5.Bg5 Ne4 6.cxd5 Nxg5 7.Nxg5 e6 8.Nf3 exd5 9.e3 O-OX9- FA36b English: Symmetrical, 3.g3 Nf6RO(!NB18s Caro-Kann: Classical, 6.h4 h6 7.h5MtqjXLC70 Spanish: Schliemann Deferred, 5.d4Eos[&D82 Grnfeld: 4.Bf4D{c \D84 Grnfeld: Grnfeld Gambit Accepted, 8...b6:ݳKpA29 English: Four Knights, 4.g3 d5 5.cxd5 Nxd5 6.Bg2 Be614nLC90c Spanish: Closed, Suetin Variation$A2E20 Nimzo-Indian: 4.f3 c5\BC44m Ponziani: Steinitz VariationD?BZD94 Grnfeld: Slav/Schlecter, 6.Be2 O-O 7.O-OI@M`B77i Sicilian: Dragon, Yugoslav, 9.Bc4 Bd7 10.h4Τi<A11 English: Caro-Kann DefenceD#E~0D18c Slav: Dutch, 6...e6N}cTB76f Sicilian: Dragon, Yugoslav, 9.g4 Nxd4a//TC03b French: Tarrasch, Haberditz Variationj:LB43i Sicilian: Kan, 5.Nc3 Qc7 6.g3 Nf6ߚSHA37c English: Symmetrical, 5.Nf3 Nh6*:WRC57c Two Knights: Traxler, 5.Nxf7 & 6.Kf1=ƕnVB54m Sicilian: Prins (Moscow), 5...e5 6.Nb3֜3-<B12o Caro-Kann: Advance, 4.Bd3֖[̂ `A23 English: Bremen, Keres, 4.Bg2 d5 5.cxd5 cxd5'FA20 English: King's, 2.g3 Nf6 3.Bg2VD36e QGD: Exchange, 6.Qc2 Be7 7.Nf3 g6 8.e3LHND00t Blackmar-Diemer: von Popiel Attack !B22l Sicilian: Alapin, 2...d5 3.exd5 Qxd5 4.d4 Nf6 5.Nf3 Bg4 6.Be2 e6hdE84d King's Indian: Smisch, Panno Main Line, 9.g4#n|XB10u Caro-Kann: Two Knights, 3...dxe4 4.Nxe4!0NA73 Benoni: Classical, 9.O-O Bg4 10.Bf4Э56C26p Vienna: 3.Bc4 Bc5 4.f4؂{|6D15f Slav: Chameleon, 5.Ne5p(-PC85g Spanish: Closed, Exchange, 7.Qe1 c5&\TB98m Sicilian: Najdorf, Gothenburg, 11.Qh5Q00>A43l Old Benoni: 2.d5 Nf6 3.Nf3,bB96h Sicilian: Najdorf, 7.f4 Qc7 8.Qf3 b5 9.O-O-OttB> A04 Reti: 1...g60szzNE12x Queen's Indian: 5.Bg5 h6 6.Bh4 Be7z{0>>A73 Benoni: Classical, 9.O-O a6jv_ח`B99e Sicilian: Najdorf, Main Line, Keres, 13.Qg3i{^:`A26 English: Closed, 5.d3 d6 6.Nf3 Nf6 7.O-O O-Og k:E60h King's Indian: b3 System^u<A02 Bird: From Gambit Accepted]%LC01o French: Exchange, 4.Nf3 Bd6 5.Bd3FtϭNXB97m Sicilian: Najdorf, Poisoned Pawn, 9.Rb1F>V8C80k Spanish: Open, 7.Bb3 d5DrM?$D30j QGD: 3.Nf3 c63BA45t Trompowsky: 2...Ne4 3.Bh4 d5z\E92q King's Indian: Petrosian, Stein VariationE LD23j QGA: Mannheim, 4...c6, 5.Qxc4 Bf5o\:C68j Spanish: Exchange, 5.O-O;waJB08m Pirc: Classical, 5.Be2 O-O 6.Be3b XA50g Indian: Mexican Defence, 3.Nf3 e6 4.Nc39I]jJVD81 Grnfeld: Early Russian, 5...Be6 6.Qb5+-uـ4jE15c Queen's Indian: 4.g3 Bb4+ 5.Bd2 Bxd2+ 6.Qxd2 Ba6f= TA87 Dutch: Leningrad, Main Line, 7.Nc3 Na6iW|`DE94i King's Indian: Glek Variation4E2C44y Scotch Gambit: 5.O-O|+E3TC01t French: Exchange, Svenonius Variation{dEhB16h Caro-Kann: Bronstein-Larsen, 6.Nf3 Bg4 7.Be2 e6tC.JB05l Alekhine: Modern, 5.Be2 e6 6.O-Op'j+.B07o Pirc: Czech, 4.Nf3gD|c!RB95k Sicilian: Najdorf, 6...e6 7.Qf3 Nbd7f1:D83 Grnfeld: Grnfeld GambitfbQSbp,A47 Neo-Queen's Indian\7qpTLC39 KGA: Kieseritsky, Brentano DefenceG؞"RvB97h Sicilian: Najdorf, Poisoned Pawn, 8.Nb3 Nbd7 9.Qf3 Be7AkbޚXB21w Sicilian: Smith-Morra, 4.Nxc3 Nc6 5.Nf33ǭ(rhB38m Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 d6 9.f30TcmbD85h Grnfeld: Exchange, 7.Be3 c5 8.Qd2 Qa5 9.Rc1%׍$^B13l Caro-Kann: Exchange, Rubinstein, 7.Qb3 Qc8"*+^B53i Sicilian, Chekhover, 4...a6 5.c4 Nc6 6.Qd25h>D25l QGA: Janowski-Larsen, 6.h36SDE10f Neo-Indian: 3.Nf3 a6 4.Nc3 c5l 8B50l Sicilian: 2.Nf3 d6 3.c3 GPhD88 Grnfeld: Classical Exchange, Main Line, 11.cxd4"&A25 English: ClosedqKCCLA26 English: Botvinnik System, 6...Nf65}"C50a Italian GameКRh,A02 Bird: 1..Nf6 2.Nf3Im B07b Pirc: 2.Nf3>OPC14d French: Classical, Alapin Variationn45'<C54l Giuoco Piano: 6.cxd4 Bb4+ү (D91a Grnfeld: 5.Bg5iCFzB23w Sicilian: Closed, Grand Prix, 3...g6 4.Nf3 Bg7 5.Bb5 Nd4xK#0JC50h Giuoco Piano: Rosentreter Gambitg_ 6A09i Reti: Advance, 3.g3 g66 D30e QGD: 3.Bf4bVE73r King's Indian: Averbakh, 6...Na6 7.Qd2)?&A84 Dutch: 2.c4 Nf6j8dRC58e Two Knights: Morphy, Polerio, 6...c6>۽6D22c QGA: Alekhine, 4.e3 e6XƤRD80 Grnfeld: Stockholm, Lundin VariationhzP>C77d Spanish: Anderssen, 5...d6jVB01s Scandinavian: 2...Nf6 3.Bb5+ Bd7 4.Bc4{#fhA32 English: Symmetrical, Two Knights, 5.g3 d5 6.Bg2-$ZE55 Nimzo-Indian: Main Line, Bronstein, 9.Qe2\E82b King's Indian: Smisch, Fianchetto, 7.Qd2E`[6||C43t Russian Game: Modern Attack, 3...Nxe4, Main Line, 7...Bd6|sIlC06q French: Tarrasch, Closed, 8...f6 9.exf6, 11...Qc7{ΓPA37k English: Symmetrical, 5.Nf3 e6 6.e3elf8C02c French: Advance, 3...c5b!\B37f Sicilian: Maroczy Bind, Simagin VariationZ:ihKPC81 Spanish: Open, Keres Attack, 9...Be7VPS PgPC37 KGA: Muzio Gambit, Paulsen VariationU\l?6A80v Dutch: 2.Nf3 Nf6 3.Bg5F,F`F8A81 Dutch: 2.g3 Nf6 3.Bg2 g6Av̀V^B01x Scandinavian: Marshall, 4.Nf3 g6 5.Be2 Bg7;T~<VB45g Sicilian: Taimanov, Four Knights, 6.g368HE6D20o QGA: 3.e4 Nf6 4.e5 Nd54b etB22f Sicilian: Alapin, 2...d5 3.exd5 Qxd5 4.d4 cxd4 5.cxd4&؂w2{.B03e Alekhine: 4.c4 Nb6%UY,05jB87 Sicilian: Sozin-Najdorf, 7.Bb3 b5 8.O-O Be7 9.Qf3%6xPD10f Slav: Exchange, 4.Nc3 Nf6 5.Bf4 Nc6$SlI!_8B30h Sicilian: 2...Nc6 3.Nc3<.C@C60g Spanish: Brentano Variation6Ѵ76C44l Ponziani: 3...d5 4.Qa42Z JfA39j English: Symmetrical, Main Line 7.d4, 8...Nxd41~nO=ZE52 Nimzo-Indian: Main Line, 6...b6 7.O-O Bb7%‘TA93 Dutch: Stonewall, Botvinnik, 8.Qc2 Ne4 }v.<A41o Neo-Old Indian: Queenswap}zA92 Dutch: 2.c4 Nf6 3.g3 e6 4.Bg2 Be7 5.Nf3 O-O 6.O-O c6 7.b3_VB98p Sicilian: Najdorf, 8...Qc7 9.O-O-O Nc6 kvN^E61t King's Indian: Smyslov System, 5...c5 6.e3Ԉ`D29i QGA: Classical, 8...Bb7 9.Rd1 Nbd7 10.a4 b4i6B06k Modern: 3.Nf3 d6 4.Bc4[wPA01 Nimzowitsch-Larsen: Paschmann Gambit58C01r French: Exchange, 4.Nc3 y{ND36c QGD: Exchange, 6.Qc2 Be7 7.Nf3 O-OHѡ><D55f QGD: 6.Nf3 b6 7.cxd5 Nxd5ֱ#<6NB88 Sicilian: Sozin-Scheveningen, 7.O-O֢GäJA41p Neo-Old Indian: 2.c4 e5 3.Nf3 e4M 2lBD02g Queen's Pawn: 2.Nf3 Nc6 3.g3Ǔ\C77s Spanish: Wormald Attack, 5...b5 6.Bb3 Bc5?Ur2D12b Slav: 4.e3 Bf5 5.Qb3jLrjA41w Neo-Old Indian: Modern, 3.Nc3 Bg7 4.Nf3 Bf4 5.e3i$2OE14z Queen's Indian: 4.e3 Bb7 5.Bd3 c5 6.O-O Be7 7.Nc3 cxd4 8.exd4 d5bBA58g Benko Gambit: Accepted, 7.f4%#b LC50p Giuoco Pianissimo: 4.d3 Nf6 5.O-O^Ϝ%jE56 Nimzo-Indian: Main Line, 7...Nc6 8.a3 cxd4 9.exd4GCvE11u Bogo-Indian: Nimzowitsch, 5.g3 Nc6 6.Bg2 Bxd2+ 7.Nbxd2=?`/vA66 Benoni: Mikenas Attack, 9.Nb5 dxe5 10.Nd6+ Ke7 11.Nxc8+-ɧ^D98d Grnfeld: Russian, Smyslov, 8.Be2 Nc6 9.d5 dC15m French: Winawer, 4.a3 Bxc3+ 5.bxc3 dxe4 6.Qg4}i+n0A55b Old Indian: 5.e4 g6|zmK:C26d Vienna: Smyslov, 3...Nc6z :^PE39i Nimzo-Indian: Classical, Pirc, 6.a3r m{j.D24c QGA: 4.Nc3 e6 5.e3o?PA03 Bird: 1...d5 2.Nf3 Nf6 3.g3 g6: 5.d3^Y>52A03 Bird: Lasker, 3...Bg4YFB@B96f Sicilian: Najdorf, 7.f4 Qc7X:^BVB03q Alekhine: Exchange, 5...exd6 6.Nc3 Be7UʄE86h King's Indian: Smisch, Orthodox, 7.Nge2 c6 8.Qd2 Nbd7 9.O-O-O a6R/9h#9^C49k Four Knights: Symmetrical, Blake VariationR_*sȸ|A29 English: Four Knights, 4.g3 d5 5.cxd5 Nxd5 6.Bg2 Nb6 7.O-OBw16C15d French: Winawer, 4.Qd3>PX3nE75g King's Indian: Averbakh, 7.d5 e6 8.Qd2 exd5 9.exd5=-]AnDD36a QGD: Exchange, 5.Bg5 c6 6.Qc2=iqT!VD00u Blackmar-Diemer: Langeheinecke Defence:'X^B21y Sicilian: Smith-Morra, 4.Nxc3 Nc6 5.Nf3 d6:ʽu+dB51e Sicilian: 3.Bb5+ Nd7 4.O-O Nf6 5.Re1 a6 6.Bf1.3<A96 Dutch: Classical, 7.Nc3 a5)KFA46m Indian: 1.d4 Nf6 2.Nf3 e6 3.g3"_fx#E82g King's Indian: Smisch, Fianchetto, 7.Bd3 Bb7 8.Nge2 c5 9.d5 e6!>zAvE88g King's Indian: Smisch, Orthodox, Polugayevsky, 8...b5NHE05i Catalan: Open, Classical, 7.Qc2Zᱼ,C26m Vienna: 3.Bc4 Bb4=w>ND78l Neo-Grnfeld, 6.O-O c6 7.Nbd2 Nbd7tFTEBD00n Queen's Pawn: Veresov Attackl@ՂpC98i Spanish: Closed, Chigorin, 12...Nc6 13.d5 Nd8 14.a4nՉ`C2D35i QGD: Exchange, 5.Bg5{W\dD36t QGD: Exchange, Main Line, 9.Nf3 Re8 10.O-O h6O=ͣ~E12i Queen's Indian: Petrosian, 4...Ba6 5.Qc2 Bb7 6.Nc3 c5 7.e4!HtD48g Semi-Slav: Meran, 8...a6 9.O-O Bb7 10.e4 c5 11.d5 Qc7Ϙ`MXD40e QGD: Semi-Tarrasch, 5.e3 a6 6.cxd5 exd5}&bZvC47u Four Knights: Scotch, Main Line, 8.exd5 cxd5 9.O-O O-O%}.A12 English: Capablanca8x@VC10l French: Rubinstein, 5.Nf3 Ngf6 6.Nxf6+8 LB50p Sicilian: 2.Nf3 d6 3.c3 Nf6 4.Bc4zI3DE90h King's Indian: Larsen, 6...c52%!<:E04s Catalan: Open, 5.Nf3 Nc6掂BB21d Sicilian: Grand Prix, 2...e6:TV;.E10k Blumenfeld: 5.dxe6G6D38l QGD: Ragozin, 5.Bg5 h6OTA41g Neo-Old Indian: Wade Defence, 3.c4 e5q)m A00o Grob Gambit DC89f Spanish: Marshall, 11.Rxe5 c6TxʬbHA95 Dutch: Stonewall, 7.Nc3 c6 8.Bg5ޛZmnD14j Slav: Exchange, 8.Bd3 Bxd3 9.Qxd3 Bd6 10.Bxd6 Qxd60Z>B50d Sicilian: 2.Nf3 d6 3.b3 e6s8$׃.B02m Alekhine: 2.e5 Nd5O{CdC86h Spanish: Worrall Attack, 7...O-O 8.c3 d6 9.d4p6A16 English: Anglo-GrnfeldP;4D16d Slav: Murey VariationA$RA44r Old Benoni: Czech, 3.e4 d6 4.Nc3 Nf6;ѺBE94h King's Indian: Donner, 8.Be3sQhD58j QGD: Tartakower, 8.Bd3 Bb7 9.O-O Nbd7 10.Qe2 c5P=4D21m QGA: 3.Nf3 c5 4.d5 e6>FDA15 English: Anglo-Indian, 2.g3 e6S`B96h Sicilian: Najdorf, 7.f4 Qc7 8.Qf3 b5 9.Bxf6UZ\E91y King's Indian: 6.Be2 Bg4 7.Be3 Nfd7 8.Ng1lG}`A75 Benoni: Classical, 9.O-O a6 10.a4 Bg4 11.Bg5uE,A47 Neo-Queen's Indian~LT]K4D18a Slav: Dutch Variationx2ZTJA41q Neo-Old Indian: Modern, 3.e4 Bg7_8.A59a Benko Gambit: 7.e4XzoGBA43t Old Benoni: Schmidt, 3.e4 g6Wc_$HC25l Vienna: 2...Nc6 3.Bc4 Bc5 4.Qg4VXE54 Nimzo-Indian: Main Line, 7...dxc4 8.Bxc4LRJNA20 English: King's, 2.g3 Nf6 3.Bg2 Bc5GfZE*VB62b Sicilian: Richter-Rauzer, 6...e6 7.Be2@Cꎪ ^B01u Scandinavian: Portuguese, 4.Nf3 Qxd5 5.Be2?hĒTB10k Caro-Kann: English, Exchange, 4...Nf6,_jdB74 Sicilian: Dragon, Classical, Maroczy VariationY7U>FxA36z English: Symmetrical, Botvinnik System, 5...d6, 8.d3 a6}w_\B99s Sicilian: Najdorf, Modern Main Line 13.f5Yʁ~xB81n Sicilian: Scheveningen, Keres, 6...h6 7.h4 Nc6 8.Rg1 h5 ֥ebA46o Indian: 1.d4 Nf6 2.Nf3 e6 3.g3 c5 4.Bg2 cxd4 hB51i Sicilian: 3.Bb5+ Nd7 4.d4 Nf6 5.Nc3 cxd4 6.Qxd4Y;TbE31g Nimzo-Indian: Leningrad, Main Line, 7.e3 O-OwInDA43l Old Benoni: 2.d5 Nf6 3.Nf3 e6>خbB44w Sicilian: Taimanov, Szen, Hedgehog Variation1IQhB72 Sicilian: Dragon, Classical, Amsterdam VariationgjB95m Sicilian: Najdorf, 6...e6 7.Qf3 Be7 8.O-O-O Nbd7ϣu>C63i Spanish: Schliemann, 4.Nc3ں;GHt6D00g Hodgson Attack: 2...c6ԛDGTC49l Four Knights: Symmetrical, 7.Bg5 Bxc3҆ȞonA44j Old Benoni: Czech, 3.c4 d6 4.e4 g6 5.Nc3 Bg7 6.Nf3ezC82g Spanish: Open, Berlin, 10.Bc2 Bg4 11.Nbd2 Be7 12.Re1 Qd72+FHD91i Grnfeld: 5.Bg5 Ne4 6.cxd5 Nxg5D?̥6C11o French: Burn VariationwY7FB18c Caro-Kann: Classical, 5.Nc5 b6m˂~xE14i Queen's Indian: 4.e3 Bb7 5.Bd3 Bb4+ 6.Nbd2 O-O 7.O-O d54HTB03j Alekhine: Four Pawns Attack, 5...dxe5jn?NA70g Benoni: Classical, 8.Bf4 O-O 9.Nd2Z*AVD15u Slav: Geller Gambit, Spassky Variation^ +PC20 Open Game: Lopez/Mcleod, Lasa Gambit9oUbB14p Caro-Kann: Panov-Botvinnik, 5...e6 6.Nf3 Bb4t2B00e Owen Defence: FrenchŴ|A75 Benoni: Classical, 9.O-O a6 10.a4 Bg4 11.Bf4 Bxf3 12.Bxf3 Qe7bA68m Benoni: Four Pawns, 9.Be2 Bg4 10.O-O Nbd7 11.h3 Bxf3 12.Bxf3 Re82mzjE14u Queen's Indian: 4.e3 Bb7 5.Bd3 c5 6.O-O Be7 7.b3ݼzvD68 QGD: Orthodox, Classical, Vidmar, 13...exd4 14.exd4 Nb6(DA53 Old Indian: 3.Nc3 Nbd7 4.e4 e5L-6rVC27f Vienna: 3.Bc4 Nxe4 4.Qh5 Nd6 5.Bb3 Be7bRA95 Dutch: Stonewall: Chekhover Variation|s&<C26s Vienna: 3.Bc4 Bc5 4.d3 d6z݃3UrC09m French: Tarrasch, Open, Main Line, 9.Nb3 Bd6 10.Nbd4y uVU6A80c Dutch: Korchnoi Attacktޑ)5 PB13f Caro-Kann: Exchange, 4.Bd3 Nc6 5.c3qPB=ZC47p Four Knights: Scotch, 4...exd4 5.Nxd4 d6l+CSNB43n Sicilian: Kan, 5.Nc3 Qc7 6.Bd3 Nf6_.BE17t Queen's Indian: Euwe, 7...d5XXt[gPE03 Catalan: Open, 5.Qa4+ Nbd7 6.Qxc4 c5W.GG0A10 English: 1...g6 2.e4RըIGNB22o Sicilian: Alapin, 2...Nf6 3.e5 Nd5J,k dA67q Benoni: Four Pawns, Taimanov, 9.a4 O-O 10.Nf3Jab~\C76 Spanish: Modern Steinitz, Bronstein, 7.O-OE|ut;B65f Sicilian: Richter-Rauzer, 7...Be7, 9.f4 Nxd4 10.Qxd4 Qa5 11.Bc4 Bd7BDJ8D11n Slav: Slav-Reti with b3@#MfE31h Nimzo-Indian: Leningrad, Main Line, 7.e3 Bxc3+>xa D11a Slav: 3.Nf34'QbB45p Sicilian: Taimanov, Four Knights, 6.Ndb5 Bb4)tZBikdB02u Alekhine: Two Pawns Attack, Mikenas Variation)~fE81d King's Indian: Smisch, 5...O-O 6.Nge2 c5 7.d5(onVtVE63h King's Indian: Fianchetto, Panno, 8.h3! yP\B14b Caro-Kann: Panov-Botvinnik, 5...g6 6.cxd52B<A45t Trompowsky: 2...Ne4 3.Bh4ʥ0A09d Reti: Advance, 3.e3 g>|2B07d Pirc: Roscher Gambitbe[*A42a Modern: AverbakhJlPD86 Grnfeld: Classical Exchange, 7...b6t>\C84o Spanish: Closed, Centre Attack, 7.Re1 O-O|oFA80c Dutch: Korchnoi, Janzen GambitꯈmdA58d Benko Gambit: Accepted, 6.g3 d6 7.Bg2 g6 8.b38/WFD00k Trompowsky: 2...d5 3.Bxf6 exf6k mJC41w Philidor: Improved Hanham, 7.Qe2rXFA29 English: Four Knights, 4.g3 Bc5N*LC59j Two Knights: Main Line, 11.d4 Qc7իZA87 Dutch: Leningrad, Main Line, 5...d6 6.Nc3ŕx,LA58o Benko Gambit: Fianchetto, 9...O-O}̎vD36r QGD: Exchange, Main Line, 9.Nf3 Re8 10.O-O-O Nf8 11.h3-R?lE66d King's Indian: Fianchetto, Yugoslav Panno, 9...e5͛i}"TE22 Nimzo-Indian: Spielmann, 4...c5 5.dxc5jaVB96i Sicilian: Najdorf, 7.f4 Nbd7 8.Qe2 Qc7fk4D70 Neo-Grnfeld: 4.Bg2 c6N+%XRA40k Queen's Pawn: Bogoljubow-Miles, 2.c43BB37q Sicilian: Maroczy Bind, 6.Nc2 Nf6 7.Nc3 d6 8.Be2 O-O 9.O-O Nd7 10.Bd2 Nc5 11.b4yLruu<E73e King's Indian: 5.Be2 Nbd7y0>E13o Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.e3 g5 8.Bg3 Ne4 9.Qc2 Bxc3+]GOXD41b QGD: Semi-Tarrasch, Keres CounterattackUItχuZE34 Nimzo-Indian: Classical, Noa, 5.cxd5 Qxd5K`\qrE70n King's Indian: 4.e4 d6 5.Bd3 O-O 6.Nge2 Nc6 7.O-O e5:GE88i King's Indian: Smisch, Orthodox, Polugayevsky, 8...cxd5 9.cxd5 Nh57YmNE18j Queen's Indian: 7.Nc3 d5 8.Ne5 Na66{ MHD16o Slav: Bronstein, 6.Ne5 Bh5 7.h3.ݬW\NA50m Indian: Queen's Indian Accelerated($@e\E05m Catalan: Open, Classical, 8.a4 Bd7 9.Qxc4 ގE98q King's Indian: Mar del Plata, 9.Ne1 Nd7 10.Nd3 f5 11.Bd2 Nf6ʁ֖ .C10f French: Rubinstein [rC41e Philidor: Philidor Countergambit, Steinitz Variation iTC47o Four Knights: Scotch, 4...exd4 5.Nxd4cq6C26r Vienna: 3.Bc4 Bc5 4.d3ԓCE14y Queen's Indian: 4.e3 Bb7 5.Bd3 c5 6.O-O Be7 7.Nc3 cxd4 8.exd4?K$/>B03d Alekhine: Balogh VariationBS9PE11y Bogo-Indian: 4.Bd2 Bxd2+ 5.Qxd2 O-Oo(C25b Vienna: 2...Bb4dPKTB94f Sicilian: Najdorf, 6.Bg5 Nbd7 7.f4 b5wPE34 Nimzo-Indian: Classical, Noa, 5.cxd5?<C00f French: Pelikan Variation+~\D36o QGD: Exchange, Main Line, 9.Nf3 h6 10.Bh4ήG>B98a Sicilian: Najdorf, 7...Be7 _|}{`D66 QGD: Orthodox, Main Line, Fianchetto, 11.O-Oe:p:C40i Elephant Gambit: PaulsenS<A96 Dutch: Classical, 7.b3 Qe8m zC84q Spanish: Closed, Centre Attack, 7.Re1 O-O 8.e5 Ne8 9.Bf4#gRC60m Spanish: Fianchetto, 4.d4 exd4 5.Bg5~@ `E70n King's Indian: 4.e4 d6 5.Bd3 O-O 6.Nge2 Nc6zk*ѱ:E60h King's Indian: b3 Systemyq7 4D02u Queen's Pawn: 3.g3 g6r1"g|C08f French: Tarrasch, Open, 4.exd5 exd5 5.Bb5+ Bd7 6.Qe2+ Be7me]:C45u Scotch: 4.Nxd4 Bc5 5.Be3eM : >D44d Semi-Slav: Botvinnik, 7.a4]bВJA55r Old Indian: Main Line, 8.Re1 Re8Zk% D30d QGD: 3.cxd5TBz&s<D30h QGD: Tarrasch without Nc3T>^w6>C22 Centre Game: Hall VariationFC\74A12 English: Torre Defence6; ZB76j Sicilian: Dragon, Yugoslav, 9.O-O-O Nxd45 MLC69b Spanish: Exchange, Gligoric, 6.d4$Us+hE60o King's Indian: Fianchetto without Nc3, 6...Nbd7 sW\fC97j Spanish: Closed, Chigorin, 12...Bd7 13.Nf1 Nc4 BD43v Semi-Slav: Moscow, Main LineuVak>B26d Sicilian: Closed, 6.Be3 e5ʼnt/rB38i Sicilian: Maroczy Bind, 7.Nc3 O-O 8.Be2 b6 9.O-O Bb7sYnE76o King's Indian: Four Pawns Attack, 6.Nf3 c5 7.d5 a6 &A`E12s Queen's Indian: Petrosian, 6.cxd5 Nxd5 7.e3CJC49f Four Knights: Janowski VariationڙFB13f Caro-Kann: Exchange, 4.Bd3 Nc6Ց՝@A43a Old Benoni: Nakamura Gambit+L!dA30b English: Symmetrical, 2.Nf3 b6 3.g3 Bb7 4.Bg2O>^C45q Scotch: 4.Nxd4 Bc5 5.Nb3 Bb6 6.a4 a6 7.Nc3=}4A13h English: 1...e6 2.Nf3Uh7#RD87a Grnfeld: Classical Exchange, 8...c5/TZŝ:&A25 English: Closed-n$D80 Grnfeld: 4.e3֭RC85e Spanish: Closed, Exchange, 7.Nc3 Bg4@`I,C44n Ponziani: 3...Nf6Ce@%FB01d Scandinavian: Schiller DefenceifD50 QGD: Semi-Tarrasch, Pillsbury, Krause Variation0R LA42g Modern: Averbakh, Kotov VariationKEQ|LC23 Bishop's Opening: Anderssen Gambit}N11DE07 Catalan: Closed, 6...Nbd7 7.b3|r PLdB44t Sicilian, Taimanov, Szen, 7.N1c3 a6 8.Na3 Be7xͯDD10x Slav: 3.Nc3 Nf6 4.e3 a6 5.Qc2t'5s\E12n Queen's Indian: Petrosian, 5.Nc3 d5 6.Bg5nW?c&E06 Catalan: ClosedfoNE71c King's Indian: Makagonov, 5...Nbd7QnzhTD18m Slav: Dutch, 8...Nbd7 9.Qe2 Bg6 10.e4G}A^D44m Semi-Slav: Botvinnik, Lilienthal, 11...Bb7?iCJC90g Spanish: Closed, Pilnik, 9...Na56jcBA62 Benoni: Fianchetto, 8.Bg2 O-O2"񸩞(A56n Benoni: Vulture.@i RB23q Sicilian: Closed, Grand Prix, 3...e6"ȁKZB33l Sicilian: Pelikan, Chelyabinsk Variationu$fB49d Sicilian: Taimanov, 6.Be3 a6 7.Be2 Nf6 8.a3 b5q L A04 Reti: 1...b6wYNC84c Spanish: Closed, 6.Nc3 b5 7.Bb3 d6r6JB84 Sicilian: Scheveningen, Classical2o8bB00q Nimzowitsch Defence: 2.Nf3 d6 3.d4 Nf6 4.Nc3Il $A00v Benko Openingg9&xA41g Neo-Old Indian: Wade Defence, 3.c4 e5 4.dxe5 Nc6 Gambita/#FJC15n French: Winawer, Alekhine GambitoLB44o Sicilian, Taimanov, Szen, 6.c4 a6i XE70i King's Indian: Kramer, 5...O-O 6.Ng3 e5C42c Russian-Three Knights GameG2N,D08 QGD: Albin, 3.dxe5w6D11p Slav: Slav-Reti System$(%l4B09a Pirc: Austrian AttackڿL-PE14f Queen's Indian: 4.e3 Bb7 5.Bd3 Bb4+D) .PB98c Sicilian: Najdorf, Danner VariationBz;y2C32 KGD: Falkbeer, 5.dxe4t2/fLB72 Sicilian: Dragon, Classical AttackPIm`B60k Sicilian: Richter-Rauzer, Larsen, 7.Be2 Qa5pHFD19g Slav: Dutch, Smisch VariationXXDC41k Philidor: 3...exd4 4.Nxd4 Nf6_68B07f Pirc: 3.f3 e5 Queenswap~c!lLD60 QGD: Orthodox, Botvinnik Variationhww7xPD34s QGD Tarrasch: 9.Bg5 cxd4 10.Nxd4 h6dq"b 0A10 English: Anglo-Dutch^F?i^E90o King's Indian: 5.Nf3 O-O 6.h3 e5 QueenswapZJB97a Sicilian: Najdorf, Poisoned PawnYkiN>\B33b Sicilian: Open, 2...Nc6, 5...Qb6 6.Nb3 e6Y}f,<B53b Sicilian: 2...d6 3.d4 Nf6XsqCVA41f Neo-Old Indian: Wade Defence, 3.e3 Nd7OQ A75 Benoni: Classical, 9.O-O a6 10.a4 Bg4 11.Bf4 Re8 12.Nd2 Bxe2 13.Qxe2 Nh5G7Z&K&A00j Mieses: 1...e5)vjTC58g Two Knights: Morphy, Colman Variation(x"BD34j QGD Tarrasch: Reti Variation#, xRE80m King's Indian: Smisch, 5...c6 6.Be3uMZA38j English: Symmetrical, Main Line, 7.a3 d6t*WE75i King's Indian: Averbakh, 7.d5 e6 8.Qd2 exd5 9.exd5 Re8 10.Nf3?UŠLE06 Catalan: Closed, 6.O-O c6 7.Nc3 b6pDC59j Two Knights: Main Line, 11.d4d+ BzB97n Sicilian: Najdorf, Poisoned Pawn, 10.Be2 Be7 11.O-O Nbd7L|edE85e King's Indian: Smisch, Orthodox, 7.Nge2 exd4 E<B51f Sicilian: 3.Bb5+ Nd7 4.d4 ]f8B96a Sicilian: Najdorf, 7.f4 R+6A24 English: Bremen, 3...g6  'tA33n English: Symmetrical, Two Knights, 5.Nc3 Nc6 6.g3 Bc5 $m*A06 Reti: 1...d5 2.e3 E]TI JB01w Scandinavian: Marshall Variation ;<BD32r QGD Tarrasch: 5.Nf3 Nc6 6.e3 nb"A65a Benoni: 6.e4 kqcbB80r Sicilian: Scheveningen, Fianchetto Variation ^PC20 Open Game `F4D02u Queen's Pawn: 3.g3 g6 ʌ޴+`8D33b QGD Tarrasch: 6.g3 cxd4 6A43r Old Benoni: Hawk, 4.e4 Z:D94 Grnfeld: 5.e3 O-O 6.cxd5  QDD16c Slav: Soultanbeieff Variation LE97s King's Indian: Mar del Plata, Bayonet, 9...Nh5 10.Re1 f5 11.Ng5 Nf6 12.Bf3 .U%L^B54n Sicilian: Prins (Moscow), 5...e5 6.Nb3 Be6 yY@mEIrHB18m Caro-Kann: Classical, 6.Nf3 Nd7 u:F:C27c Vienna: 3.Bc4 Nxe4 4.Qh5 fynYJTA38i English: Symmetrical, Main Line, 7.a3 TЋO3HC93 Spanish: Closed, Smyslov, 12.Nf1 TSMXB76h Sicilian: Dragon, Yugoslav, 9.O-O-O Bd7 QLTp!LD37c QGD: Westphalia: 4.Nf3 Nbd7 5.Bf4 IUš^HE20 Nimzo-Indian: Romanishin, 8.cxd5 6UVdC03i French: Tarrasch, 3...Be7 4.Bd3 c5 5.dxc5 Nf6 #^^xC49q Four Knights: Symmetrical, Metger, 10.d4 Ne6 11.Bc1 Rd8 2;`E35 Nimzo-Indian: Classical, Noa, Exchange, 6.a3 uDA43u Old Benoni: Schmidt, 3.e4 Nf6 ahd`C95g Spanish: Closed, Breyer, Gligoric Variation /,uA07 Reti: KIA AhB34l Sicilian: Accelerated Fianchetto, Modern, 6.Nb3 0bB63e Sicilian: Richter-Rauzer, 7.Qd2 Qb6 8.Nb3 a6 B;FD18p Slav: Dutch, 8...O-O 9.Nh4 Bg6 5/騬fB83 Sicilian: Scheveningen, Modern, 9.f4 Bd7 10.Nb3 =FB15p Caro-Kann: Rasa-Studier Gambit Pp:vC67l Spanish: Open Berlin, Main Line 9.Nc3 (Rio de Janerio) 0cYTLE06 Catalan: Closed, 6.O-O c6 7.Qc2 b6 ] jpB98k Sicilian: Najdorf, Gothenburg (Argentine) Variation j:rRD86 Grnfeld: Classical Exchange, 7...O-O VK=[B37n Sicilian: Maroczy Bind, 6.Nc2 Nf6 7.Nc3 d6 8.Be2 O-O 9.O-O Nd7 20D34o QGD Tarrasch: 9.Bg5 3 C51 Evans Gambit ~vӊrB32q Sicilian: Lowenthal, Kalashnikov, 6.N1c3 a6 7.Na3 b5 ^lC06o French: Tarrasch, Closed, 8...f6 9.exf6, 11...Qb6 ~^ ~L^E64a King's Indian: Fianchetto, Yugoslav System |LW@ pBA20 English: King's, 2.g3 c6 3.d4 { jPD85e Grnfeld: Exchange, 7.Bb5+ c6 8.Ba4 w jXLC92d Spanish: Closed, Kholmov, 11.Qxb3 wRBA62 Benoni: Fianchetto, 9.O-O Re8 l ~V>hA29 English: Four Knights, 4.g3 d5 5.cxd5 Nxd5 6.Bg2 k{ޱ.HC84c Spanish: Closed, 6.Nc3 b5 7.Bb3 kTG~HA99 Dutch: Ilyin-Zhenevsky, 8.b3 Nc6 g5X8D43s Semi-Slav: Moscow, 7.e3 eQE]JA48f Neo-King's Indian: London System Y5vC"D20s QGA: 3.e4 c5 UPrC33 KGA: Bishop's Gambit, Classical Defence, Cozio Attack L#2kND71 Neo-Grnfeld, 5.cxd5 Nxd5 6.Nc3 Nb6 DC!)RA14 English: Neo-Catalan Declined, 5...c5 75oPA30b English: Symmetrical, 2.Nf3 b6 3.g3 3ԑdjNA27 English: Three Knights, 3...g6 4.d4 1b>:B22a Sicilian: Alapin, 2...e5 #sIFHA52k Budapest: Rubinstein, Main Line 'p@C43c Russian Game: Modern Attack ^לRA69f Benoni: Four Pawns, Main Line, 10.e5 [˘ަJB44q Sicilian, Taimanov, Szen, 7.N1c3 r+ u<D32j QGD Tarrasch: 4.cxd5 exd5 Ա HodE81h King's Indian: Smisch, 5...O-O 6.Bg5 c5 7.d5 vΓ$FD53s QGD: 4.Bg5 Be7 5.e3 Nbd7 6.Nf3 /A@UFC52 Evans Gambit: 5...Ba5 6.O-O Nf6 ?LD70 Neo-Grnfeld: Alekhine's, 5.e4 Nb6 ̦]DB38a Sicilian: Maroczy Bind, 6.Be3 >A45n Trompowsky: 2...e6 3.e4 h6 D7J:C18f French: Winawer, 6...Ne7 7d7.,A47 Neo-Queen's Indian $ GB66o Sicilian: Richter-Rauzer, 7...a6 8.O-O-O h6 9.Be3 Be7 10.f4 KaYRA99 Dutch: Ilyin-Zhenevsky, 8.b3 a5 9.Qc2 ܻz<E60j King's Indian: Fianchetto t<LB48e Sicilian: Taimanov, 6.Be3 a6 7.f4 Ή00A53 Old Indian: Janowski sz8B07r Pirc: Sveshnikov (4.g3) XA76 Benoni: Classical, Main Line, 10.Qc2 Bg4 4 4.A45m Trompowsky: 2...e6 ]?2D07f QGD: Chigorin, 3.Nf3 ɚJRD10m Slav: Winawer Countergambit Accepted =@mTE94o King's Indian: Glek, Main Line, 11.h3 A04 Reti: 1...c5 *.@D95i Grnfeld: Pachman Variation ۣrbE03 Catalan: Open, 5.Qa4+ Nbd7 6.Qxc4 a6 7.Nf3 b5 Pd1mRDD73 Neo-Grnfeld, 6.cxd5 Nxd5 7.e4 ~DXSOVB49c Sicilian: Taimanov, 6.Be3 a6 7.Be2 Nf6 z8}_JB01d Scandinavian: Schiller, 4.d4 Nf6 zvqJA09i Reti: Advance, 3.g3 g6 4.Bg2 Bg7 zI3FD38k QGD: Ragozin, Westphalia, 7.e3 u:Y4C17k French: Winawer, 5.a3 rMXD69 QGD: Orthodox, Classical, 13.dxe5: 15.f4 eq<C11p French: Burn, 5.Nxe4 Nbd7 bxq-VZC88b Spanish: Closed, Trajkovic Counterattack _>:׉:D13h Slav: Exchange, 5.Nc3 e6 _]>2HC88e Spanish: Closed 7...d6 8.c3 Na5 ^1bmĠ,D25f QGA: Flohr, 5.Nc3 \Q2bD67 QGD: Orthodox, Main Line, Alekhine, 11...N5f6 ZA߁$$,E10a Neo-Indian: 3.Nf3 H96RA01 Nimzowitsch-Larsen: English Variation ?fy%lE37 Nimzo-Indian: Classical, Noa, Main Line, 7.Qc2 Nc6 ;EHA40i Englund Gambit: Soller Deferred :\ NB01u Scandinavian: Portuguese Variation 9 v(HC77f Spanish: Anderssen, 5...d6 6.c3 *F<՞->D46n Semi-Slav: Chigorin, 7.O-O &kzE29 Nimzo-Indian: Smisch, 5...O-O 6.e3 c5 7.Bd3 Nc6 8.Ne2 b6 r? FC05e French: Tarrasch, Closed, 5.f4 1xE97z King's Indian: Mar del Plata, 9.Nd2 a5 10.a3 Nd7 11.Rb1 Lj^JB25q Sicilian: Closed, 6.f4 e6: 9.Be3 Ļ-^C99j Spanish: Closed, Chigorin, 13...Nc6 14.Nf1 /d^B01s Scandinavian: 2...Nf6 3.Bb5+ Bd7 4.Bc4 Bg4 o`n8D62 QGD: Orthodox, Rubinstein, 7.Qc2 c5 8.cxd5, Main Line, 11.Bd3 0*A08 Reti: KIA, 2...c5 ,=4hE59 Nimzo-Indian: Main Line, 9.bxc3 dxc4 10.Bxc4 Qc7 "hhDC18g French: Winawer, 6...Ne7 7.h4 ݵiw&D21c QGA: 3.Nf3 Bg4 թK9 PA37s English: Symmetrical, 5.Nf3 e5 6.d3 Ւ nA46z Torre Attack: 3...h6 4.Bxf6 Qxf6 5.e4 d6 6.Nc3 Nd7 гOwFA96 Dutch: Classical, 7.Nc3 a5 8.b3 \nPC89i Spanish: Marshall, 12.d3 Bd6 13.Re1 ȾohE19l Queen's Indian: Old Main Line, 9.Qxc3 c5 10.Rd1 çpfA78 Benoni: Classical, Main Line, 10.Nd2 Na6 11.Kh1 ȑLD35h QGD: Exchange, 5.Nf3 Be7 6.Bf4 c6 [Z.B50a Sicilian: 2.Nf3 d6 ,vújE84c King's Indian: Smisch, Panno Main Line, 9.O-O-O oNpD46m Semi-Slav: Chigorin, 7.Qc2 Main Line, 9...b5 10.Be2 N'&5D$tD34v QGD Tarrasch: 9.Bg5 cxd4 10.Nxd4 h6 11.Be3 Re8 12.Qb3 @abB36f Sicilian: Maroczy Bind, Gurgenidze Variation òm?fA99 Dutch: Ilyin-Zhenevsky, 8.b3 a5 9.Bb2 Qh5 10.e3 }X+NJB01c Scandinavian: 2...Qxd5 3.Nc3 Qd8 D'RLC37 KGA: Lolli Gambit, Young Variation HdD66 QGD: Orthodox, Main Line, Fianchetto Variation P8}\bbD98g Grnfeld: Russian, Smyslov, 8.Be3 Nfd7 9.Be2 vt_OO>B06u Modern: Three Pawns Attack i ]o6A12 English: London Defence h`IBB90h Sicilian: Najdorf, 6.Be3 Ng4 Ta J2zB35g Sicilian: Accelerated Fianchetto, Modern, 7.Bc4 O-O 8.f3 Fׂ<>C78o Spanish: Archangelsk, 7.d4 Fn JC54h Giuoco Pianissimo: 5.d3 d6 6.O-O .]"VC88k Spanish: Closed, Anti-Marshall 8.a4 b4 *KP~/BC30r KGD: Classical Countergambit '*PE97c King's Indian: Mar del Plata, 8.Be3 &{ĭ TB18g Caro-Kann: Classical, Flohr Variation $  HC66 Spanish: Closed Berlin, 5.d4 Bd7 $ XPE61v King's Indian: Smyslov System, 6.e3 5JB21k Sicilian: Grand Prix, Tal Gambit Bq-HE80b King's Indian: Smisch, 5...Na6 [Q:A13l English: 1...e6 2.Nf3 d5 xGk<LD53i QGD: 4.Bg5 Be7 5.Nf3 h6 6.Bh4 O-O Z0A46d Neo-Benoni: 3.c3 b6 c=^BC57e Two Knights: Kloss Variation *9=lE98d King's Indian: Mar del Plata, 9.Ne1 Ne8 10.Nd3 f5 K@D25j QGA: Janowski-Larsen, 6.O-O R(qRE09l Catalan: Closed, Main Line, 9.e4 Bb7 &Gh(E00h Catalan: 3...c5 F\C92s Spanish: Closed, Zaitsev, 12.a4 h6 13.Bc2 (~z\E20 Nimzo-Indian: Romanishin, 4...c5 5.Nf3 Nc6 äm) (B27a Sicilian: 2.Nf3 ”oN&A81 Dutch: 2.g3 Nf6 [>FD00l Blackmar-Diemer: Gedult Gambit ^ b9ZD61 QGD: Orthodox, Rubinstein, 7.Qc2 c6 8.Bd3 =U HB08c Pirc: Classical, Spassky System IVnE19m Queen's Indian: Old Main Line, 9.Qxc3 c5 10.Rd1 d6 Sb8"=ZE90q King's Indian: 5.Nf3 O-O 6.h3 e5 7.d5 a5 k;VA85 Dutch: 2.c4 Nf6 3.Nc3 g6 4.Nf3 Bg7 5.e3 ݍCh8D29a QGA: Classical, 8...Bb7 ¨ NC41g Philidor: Hanham, Berger Variation }C"FpE92f King's Indian: 6.Be2 e5 Queenswap, 9.Bg5 Re8 10.Nd5 vʅMbD36j QGD: Exchange, 6.Qc2 Be7 7.e3 Nbd7 8.Bd3 Nf8 tfgTB54e Sicilian: Open, 2...d6, 4...Nf6 5.Bd3 n0*^B01f Scandinavian: 2...Qxd5 3.Nc3 Qa5 4.Nf3 Nf6 iԶ wfC77t Spanish: Wormald Attack, 5...b5 6.Bb3 Bc5 7.c3 g_Q]BC10o French: Rubinstein, 7.Bd3 c5 bT|QND06i QGD: Marshall Defence, 3.cxd5 Nxd5 b(3@5FC52 Evans Gambit: Richardson Attack [ iVzB63g Sicilian: Richter-Rauzer, 7.Qd2 Qb6 8.Nb3 a6 9.O-O-O Be7 VSB31m Sicilian: Rossolimo, 3...g6 4.O-O Bg7 5.Re1 Nf6 6.c3 O-O 7.h3 U=`B12u Caro-Kann: Advance, 4.Nf3 e6 5.Be2 c5 6.Be3 O& X(jD40q QGD: Semi-Tarrasch, 5.e3 Nc6 6.a3 a6 7.dxc5 Bxc5 H?2NB44e Sicilian: Taimanov, 5.c4 Nf6 6.Nc3 CHE38a Nimzo-Indian: Classical, 4...c5 Bb,D@UfC79 Spanish: Steinitz Deferred, Lipnitsky Variation @72A06 Reti: Ampel Variation 3YzHC21 Danish Gambit: Classical Defence *ܤnCA07 Reti: KIA %⍀CNE90a King's Indian: 5.Nf3 Nbd7 6.Be2 e5 !b%k&D37d QGD: 4.Nf3 Be7 !\='^D30v QGD: 3.Nf3 Nf6 4.Bg5, Capablanca Variation ^ء0D04a Queen's Pawn: Colle AdJ+uVD59l QGD: Tartakower, Main Line, 11.Rc1 Be6 >3VD35r QGD: Exchange, 5.Bg5 c6 6.e3 Be7 7.Bd3 )ePZE11r Bogo-Indian: Nimzowitsch, 5.g3 Nc6 6.Nc3 ih8D01g Richter-Veresov: 3...c5VnJ&2E61b King's Indian: 4.Bf4>΀?T.D04h Colle: 3...c5 4.c3HK<E90a King's Indian: 5.Nf3 Nbd7iZA21 English: Kramnik-Shirov, 3.g3 Bxc3 4.bxc3͔FJC20 Open Game: Patzer/Parnham OpeningkM C47m Four Knights: Belgrade Gambit, 5...Nxe4 6.Bc4 (Modern Line)/@C10h French: Rubinstein, 4...Nd7AԭPE44 Nimzo-Indian: Nimzowitsch, 5.Ne2 Ne4AD91t Grnfeld: 5.Bg5 Ne4 6.cxd5 Nxg5 7.Nxg5 e6 8.Nf3 exd5 9.e3 O-O 10.b4B$6D34e QGD Tarrasch: 9.b3 Ne4̺LA57j Benko Gambit: 4.cxb5 a6 5.b6 Qxb6<$'xnB22g Sicilian: Alapin, 2...d5 3.exd5 Qxd5 4.d4 e6 5.Nf3k^A30s English: Symmetrical, Hedgehog, 8.Qxd4 O-O>XەJB38c Sicilian: Maroczy Bind, 6.Be3 d6QZC09k French: Tarrasch, Open, Main Line, 9.Nb3TD31z Semi-Slav: Marshall Gambit, 8.Be2 Na6sqD5DA07 Reti: KIA, Yugoslav, Main LineapoLC05c French: Tarrasch, Closed, 4...Ne4\ALC11c French: Steinitz, Gledhill AttackUkLg?"D20v QGA: 3.e4 e5T0jC31 KGD: Falkbeer, Marshall/Nimzowitsch CountergambitRNk,$rD16s Slav: Bronstein, 6.Ne5 Bh5 7.f3 Nfd7 8.Nxc4 e5 9.Ne4Dn >$:D15h Slav: Chameleon, 5.e3 b5<_1RA<A54 Old Indian: 5.Bg5 Be7 6.e3R2A40m Queen's Pawn: 1...e676C55s Two Knights: 5.O-O Be7C\xnYZC82m Spanish: Open, St. Petersburg, 11.Bc2 f57b4B40i Sicilian: 2...e6 3.d4 ṶFC95a Spanish: Closed, Breyer, 10.d4 ]K{<A40b Queen's Pawn: 1...c6 2.c4nm6C84a Spanish: Closed System5-4O&A10 English: 1...g6\i\vFC67m Spanish: Open Berlin, 5.d4 Nd6\S:D26f QGA: Classical VariationA,t"nA59p Benko Gambit: 7.e4, Main Line, 11...Nbd7 12.h3 Qb69GBtJB01b Scandinavian: 2...Qxd5 3.Nf3 Nf6ה.Jy:D26i QGA: Classical, 6.Nc3 a6OPB15b Caro-Kann: Gurgenidze Counterattack(@6@E60i King's Indian: b3+g3 SystemVC81 Spanish: Open, Keres, Ekstrom Variationԩx`C61m Spanish: Bird's, 5.O-O Bc5 6.d3 c6 7.Bc4 d5S+LE91k King's Indian: 6.Be2 c5 7.O-O Nc6>TbZD28j QGA: Classical, 7.Qe2 b5 8.Bb3 Nc6 9.Rd1z`8A20 English: King's, 2.g3 c6hc-w,D00a Queen's Pawn GameB| V6D73 Neo-Grnfeld, 5.Nf3 O-O{U;RA44v Old Benoni: Czech, 3.e4 d6 4.Nc3 Be7OlwjE81t King's Indian: Smisch, 5...O-O 6.Be3 Nbd7 7.Qd2 c5 8.Nge2 a6KpC08i French: Tarrasch, Open, 4.exd5 exd5 5.Ngf3 a6 6.Be2FB54b Sicilian: Open, 2...d6, 4...e5MKLB41l Sicilian: Kan, 5.c4 Nf6 6.Nc3 Qc7r D RA66 Benoni: Mikenas Attack, 8...Nfd7 9.e6= PB)`D32l QGD Tarrasch: Marshall Gambit, Modern 6.Bc4JbdLE92b King's Indian: 6.Be2 e5 Queenswap`B31j Sicilian: Rossolimo, 3...g6 4.O-O Bg7 5.Re1ݗhExB83 Sicilian: Scheveningen, Modern, 9.f4 Bd7 10.Nb3 a6 11.a4~7j(TB26f Sicilian: Closed, 6.Be3 e5 7.Qd2 Nge7l^,dnA77 Benoni: Classical, Main Line, 10.Nd2 Nbd7 11.a4 Ne5\ёtE87g King's Indian: Smisch, Orthodox, Bronstein VariationZ06uVA03 Bird: 1...d5 2.Nf3 Nf6 3.g3 g6: 6.d3 c5Wl]sHD26e QGA: 4.e3 e6 5.Bxc4 a6 6.O-O b5T|TC54k Giuoco Piano: Ghulam Kassim Variation4urD86 Grnfeld: Classical Exchange, Simagin Improved, 9.Be3 d{PC64r Spanish: Classical, 4.O-O Nd4 5.Bc4KwgX4nB52e Sicilian: 3.Bb5+ Bd7 4.Bxd7+ Nxd7 5.O-O Ngf6 6.Qe2YNJA40i Englund Gambit: 2.dxe5 Nc6 3.Nf3 U4q^D47l Semi-Slav: Meran, Lundin, 9.Ne4 Be7 10.O-O K|E15q Queen's Indian: Nimzowitsch, 5.b3 Bb4+ 6.Bd2 Be7 7.Bg2 c6 3ޱFB82 Sicilian: Scheveningen, 6.f4 a6 c(>D96 Grnfeld: Russian VariationxHxRB72 Sicilian: Dragon, 6.Be3 Bg7 7.Bc4 O-O t g.lB67m Sicilian: Richter-Rauzer, 7...a6, 9.f4 b5 10.Bxf6x"bE21 Nimzo-Indian: Nimzo-Queen's Hybrid, 5.Bg5 Bb74l92JA92 Dutch: Stonewall, 7.Qc2 c6 8.Nbd2@(.A54 Old Indian: 5.g3 g6xJ_&D11t Slav: 4.e3 Bg4~$LA26 English: Botvinnik System, 6...Nf6U A04 Reti: 1...c5d]6D63 QGD: Orthodox, 7.Rc1 c66M^B01z Scandinavian: Marshall, 4.c4 Nb6 5.Nf3 Bg4/ŪRB23o Sicilian: Closed, Grand Prix, 3...d6$EK-ZB62e Sicilian: Richter-Rauzer, Richter Attack$c:̦iHE91q King's Indian: 6.Be2 Nbd7 7.Bg5"Ѻ^BE61f King's Indian: 4.g3 d6 5.Bg2ٱ>8D51 QGD: Manhattan VariationGJ!)C\A34 English: Symmetrical, 3 Knights, Queenswap)OU@B01r Scandinavian: 2...Nf6 3.Nf3}]BA45x Trompowsky: 2...Ne4 3.Bf4 c5VfVD43h Semi-Slav: Botvinnik, 5...Be7 6.e3 O-O QS/ZC87g Spanish: Closed, Averbakh, 7.c3 Bg4 8.h3Lh"~D88 Grnfeld: Classical Exchange, Main Line, 11.cxd4 Na5 12.Bd3EVA22 English: Bremen, Reverse Dragon, 4.cxd5Q->C54n Giuoco Piano: Greco AttackՄiE\D54e QGD: Anti-Neo-Orthodox, Main Line, 11.Be2ѩ4bbpTC04a French: Tarrasch, Guimard, 4.Ngf3 Nf6\&&E01 Catalan: 4...c5tY>E01 Catalan: 4...Bb4+ 5.Nd2 O-Of7jB63m Sicilian: Richter-Rauzer, 7.Qd2 Be7 8.O-O-O Nxd4-qFB36b Sicilian: Maroczy Bind, 5...d6JXܡXB15k Caro-Kann: Gurgenidze: 4.Nf3 Bg7 5.exd5"b8rE88c King's Indian: Smisch, Orthodox, 7.d5 c6 8.Qd2 cxd5ª_HHC59g Two Knights: Main Line 10...Bd6}?JlB84 Sicilian: Scheveningen, Classical, 7.O-O Nbd7 8.a4+X"PB04g Alekhine: Modern, Larsen, 5.Nxe5 g6S,UmxE39m Nimzo-Indian: Classical, Pirc, 6.a3 Bxc5 7.Nf3 b6 8.Bg5o<E01 Catalan: 4...c6 5.Nf3 Nbd76@>lD40l QGD: Semi-Tarrasch, 5.e3 Nc6 6.a3 cxd4 7.exd4 Be7(A`A42l Modern: Averbakh, Kotov, 5.Be3 e5 6.d5 Nce7~rzPC50g Italian: Hungarian Defence, 4.d4 d6tjhC94f Spanish: Closed, Breyer, 10.d3 Nbd7 11.Nbd2 Bb7o!ª :A70g Benoni: Classical, 8.Bf4lrTA35c English: Symmetrical, 2.Nc3 Nc6 3.Nf3e6bE80o King's Indian: Smisch, 5...c6 6.Be3 a6 7.a4bSVB77e Sicilian: Dragon, Yugoslav, 9.Bc4 Nxd4V',6A19 English: Mikenas, 5.Nf3UBE24 Nimzo-Indian: Smisch, 5...d5PX_wy(D31n Semi-Slav: 4.e3Pqb3XD00k Trompowsky: 2...d5 3.Bxf6 exf6 4.e3 Bf5I4J,jE49 Nimzo-Indian: Botvinnik, 7...c5 8.cxd5 exd5 9.Ne2HkZA31 English: Symmetrical, Two Knights, 4...b6+E82j King's Indian: Smisch, Fianchetto, 7.Bd3 a6 8.Nge2 c5 9.d5*f֊JD54c QGD: Anti-Neo-Orthodox, 7.Bh4 b6V2VC14m French: Classical, Stahlberg Variation-<shD25q QGA: Janowski-Larsen, 6.h3 Bh5 7.Nc3 Nbd7 8.O-O%ÌnD27w QGA: Classical, Rubinstein, 8.Qe2 cxd4, 11.Nc3 Nd5bޥXD25n QGA: Janowski-Larsen, 6.h3 Bh5 7.Nc3 a6^"5t@B02b Alekhine: Maroczy Variation )|ϫ>A81 Dutch: Blackburne Variation <D91e Grnfeld: 5.Bg5 Ne4 6.Bh4 >pdA00n Grobud(A80f Dutch: 2.Bg5 h6U@&RB99f Sicilian: Najdorf, Main Line, 10.Bd3S DA56v Benoni: Czech, 5.e4 Be7 6.Nf3/ۜTC51 Evans Gambit Declined, Lange VariationKK!:D36k QGD: Exchange, Main LineY6JA58i Benko Gambit: Accepted, 7.Nf3 g6=LD58r QGD: Tartakower, 8.Rc1 Bb7 9.Bxf6cA|C43m Russian Game: Modern Attack, 3...Nxe4 4.Bd3 d5 5.Nxe5 Bd6RޓHB44l Sicilian, Taimanov, Szen, 6.Bf4'm 8C05n French: Tarrasch, 5.Bd3iK|RD14g Slav: Exchange, Trifunovic Variation@,NC17c French: Winawer, Russian Variationg }RB05u Alekhine: Modern, Main Line, 8.Nc3 O-O 9.Be3 Nc6 10.exd6 cxd6r.)PB23m Sicilian: Closed, 2...Nc6 3.Bb5 Nd4]<E17n Queen's Indian: 6.O-O O-OZ:B92a Sicilian: Najdorf, 6.Be2^E23 Nimzo-Indian: Spielmann, San Remo VariationUefA34 English: Symmetrical, 3 Knights, 5.e4 Nb4 6.Bc4uPsPC07h French: Tarrasch, Open, 4.Ngf3 cxd4t"ԌdB62d Sicilian: Richter-Rauzer, Podebrady Variationi&NB48i Sicilian: Taimanov, 6.Be3 a6 7.Bd3g"".D00i Trompowsky: 2...d5ce\BPE59 Nimzo-Indian: Main Line, 9.bxc3 dxc4b\NB56d Sicilian: Open, 2...d6, 5.Nc3 Nbd7_pE97h King's Indian: Mar del Plata, Bayonet Attack, 9...Ne8 10.c5]La$fnA36l English: Symmetrical, 5.e3 e5 (Botvinnik Reversed)TwGhHA59c Benko Gambit: 7.e4 Line, 9.Nge2Mʮ~fE69b King's Indian: Fianchetto, Classical, 9.h3 Qe7@soSvC99f Spanish: Closed, Chigorin, 13...Bb7 14.Nf1 Rac8 15.Re27ePhB19f Caro-Kann: Classical, 7.Nf3 Nf6 8.Ne5 Bh7 9.Bd35$-~^E81q King's Indian: Smisch, 5...O-O 6.Be3 Nbd70mq,C44n Ponziani: 3...Nf6.}O&A25 English: Closed*95IhB56m Sicilian: Open, 2...d6, 5.Nc3 Nc6 6.f3 e5 7.Nb3#c{MDVB33b Sicilian: Open, 2...Nc6, 5...Qb6 6.Nb3 yudE14g Queen's Indian: 4.e3 Bb7 5.Bd3 Bb4+ 6.Nbd2 c5:W~h0A10 English: Anglo-Dutch=NA05 Reti: KIAT/z@D08 QGD: Albin, Balogh Variation68A56p Benoni: Czech, 4.Nc3 d6g#jHD66 QGD: Orthodox, Main Line, 8...h6BHE92n King's Indian: Petrosian System_hۅ|BE20 Nimzo-Indian: 4.Bd2 O-O 5.Nf3JBPD27p QGA: Classical, Rubinstein, 7...Nc6zU )<C02h French: Advance, 4.c3 Qb6ZN:B47d Sicilian: Taimanov, 6.f4% E84j King's Indian: Smisch, Panno Main Line, 9.Nc1 e5 10.d5 Nd4 11.Nb35ap%@C67c Spanish: Open Berlin, 5.Re1/4QFB01k Scandinavian: Lasker VariationZsMRA34 English: Symmetrical, 3 Knights, 5.e41+Z*B40a Sicilian: 2...e6<3dE15n Queen's Indian: Nimzowitsch, 5.b3 Bb7, 7...a5JCE}FC84g Spanish: Closed, Centre Attack9GHC94a Spanish: Closed, Breyer DefencepC15j French: Winawer, Mller-Zhuravlev Gambit, 5.Qg4 Nf6ixuDB47q Sicilian: Taimanov, 6.Be2 Nf6[MND12l Slav: 4.e3 Bf5 5.Nc3 e6 6.Bd3 Bxd3YoMC@6B06g Modern: c3 PterodactylVoZ,XA45r Trompowsky: 2...c5 3.Bxf6 gxf6 4.d5 Qb6QD^8D21j QGA: 3.Nf3 c5 4.e3 cxd4Oi<HA48r Neo-King's Indian: Torre AttackFiTPE18q Queen's Indian: 7.Nc3 Ne4 8.Bd2 Bf6F!U:D01b Richter-Veresov: 3...Ne4.gd6A00r Polish: Bugayev Attackh[4VE32g Nimzo-Indian: Classical, 4...O-O 5.Nf3rB84 Sicilian: Scheveningen, Classical, 7.O-O Be7 8.f4 Qc7F8UTDDD17p Slav: Central, Piece-Sac Line~|ZE19j Queen's Indian: Old Main Line, 9.Qxc3 c5u:E60g King's Indian: 3.Nf3 Bg7SdDD17m Slav: Central, 7.f3 Bb4 8.Bg5#PA67e Benoni: Four Pawns, Taimanov, 9.Bd3NTB33l Sicilian: Pelikan, Chelyabinsk, 9.Nd5XE18p Queen's Indian: 7.Nc3 Ne4 8.Bd2 f5 9.d5FmVE54 Nimzo-Indian: Main Line, 7...dxc4 8.Bxc4 cxd4 9.exd4 a6 10.Bg5􍋛v^B80n Sicilian: Scheveningen, Vitolins Variationʙn$A00u Benko Opening9[k_<D89g Grnfeld: Classical Exchange, Main Line, Sokolsky VariationxAkdB13s Caro-Kann: Panov-Botvinnik, 5...Nc6 6.Nf3 Bg4z29VD50 QGD: Semi-Tarrasch, Pillsbury Variationn26VA40e Queen's Pawn: English Defence, 2.c4 e6`~gXE74f King's Indian: Averbakh, 6...c5 7.d5 b50k,A45j Trompowsky 2...d6GJQxE11i Bogo-Indian: 4.Bd2 Be7 5.g3 d5 6.Bg2 O-O 7.O-O c6 8.Qc2n|DB51g Sicilian: 3.Bb5+ Nd7 4.d4 Nf6e 8D34a QGD Tarrasch: 7.Bg2 Be73HD37k QGD: Classical, 5...O-O 6.e3 b6`,A,>E41 Nimzo-Indian: 4.e3 c5 5.Bd3j uXA88 Dutch: Leningrad, Main Line, 7.Nc3 c6 8.d5 e5 9.dxe6 Bxe6 10.Qd3]ApD49b Semi-Slav: Meran, Old Main Line, Gligoric VariationaK F\E43 Nimzo-Indian: Nimzowitsch, Keene VariationuZA58d Benko Gambit: Accepted, 6.g3 d6 7.Bg2 g6}.HRUfB15o Caro-Kann: Gurgenidze: 4.Nf3 Bg7 5.h3 Nf6 6.e5w\ϣZC61l Spanish: Bird's, 5.O-O Bc5 6.d3 c6 7.Bc4tq[hB99t Sicilian: Najdorf, Modern Main Line 13.f5 Bxg5+nz=@A46y Torre Attack: 3...h6 4.Bxf6l<B12b Caro-Kann: Ulysses Gambitj-Nn8HD97c Grnfeld: Russian, Szabo, 8.Be2f?CēxA33h English: Symmetrical, Two Knights, 5.Nc3 Nc6 6.Ndb5 Bb4f|^l3^E17w Queen's Indian: Pomar, Polugaevsky, 8...c6\ JRb:D41p QGD: Semi-Tarrasch, 6.e3[EZTx*A53 Old Indian: 3.Nf3F[yZMJA48j Neo-King's Indian: London SystemD*5GfE68b King's Indian: Fianchetto, Classical, 8.e4 Re8BPaImHB95b Sicilian: Najdorf, 6...e6 7.Bd3AORbTC58d Two Knights: Morphy, Polerio, 6...Bd76R~rA89 Dutch: Leningrad, Main Line, 7.Nc3 Nc6 8.d5 Na5 9.Nd2+}/nBC80k Spanish: Open, 7.Bb3 d5 8.a4*  4A46c Neo-Benoni: 3.e3 cxd4FLB90l Sicilian: Najdorf, 6.Be3 e5 7.Nb3.'QRC65h Spanish: Berlin, Anderssen Variation)PtDE91e King's Indian: 6.Be2 c6 7.O-OY*A46f Neo-Benoni: 3.g3Tⷶo\A32 English: Symmetrical, Two Knights, 5.g3 a6BĺIJC79 Spanish: Steinitz Deferred, 6.Re1 M6`PD43w Semi-Slav: Moscow, Main Line, 11.b4̲gp$D20k QGA: 3.Nc3 a6DbE97y King's Indian: Mar del Plata, 9.Nd2 a5 10.a3aIogB37p Sicilian: Maroczy Bind, 6.Nc2 Nf6 7.Nc3 d6 8.Be2 O-O 9.O-O Nd7 10.Bd2 Nc5Z:Z@A34 English: Symmetrical, 2...g6Wn.`E13c Queen's Indian: 5.Bg5 h6 6.Bh4 Bb4 7.Qc2 g5S[(EARHA18 English: Mikenas, Kevitz DefenceN?LC21 Centre Game: Kieseritsky VariationDȝ,ww D11h Slav: 4.Qb3C;ZE05r Catalan: Open, Classical, 8.Qxc4, 10.Bg5)kTR.D30a QGD: 3.e3w A׿PA55j Old Indian: 5.e4 Be7 6.Be2 c6 7.O-O*Z6A12 English: London Defencechessx-1.0.0/src/database/settings.cpp000644 001750 001750 00000022256 12223260306 020513 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "boardtheme.h" #include "settings.h" #include #include #include #include Settings::Settings() : QSettings(IniFormat, UserScope, "chessx", "chessx") {} Settings::~Settings() {} bool Settings::layout(QWidget* w) { if(!w || w->objectName().isEmpty()) { return false; } beginGroup("Geometry"); QList values; bool valid = list(w->objectName(), values, 5); if(valid) // Enough values { w->resize(QSize(values[2], values[3])); w->move(QPoint(values[0], values[1])); if(qobject_cast(w)) { QByteArray docks = value("Docks", QByteArray()).toByteArray(); if(docks.count()) { qobject_cast(w)->restoreState(docks, 0); } } else if(values[4]) // restore non-main windows { w->show(); } } endGroup(); return valid; } void Settings::setLayout(const QWidget* w) { if(!w || w->objectName().isEmpty()) { return; } beginGroup("Geometry"); QList values; values << w->x() << w->y() << w->width() << w->height() << w->isVisible(); setList(w->objectName(), values); if(qobject_cast(w)) { setValue("Docks", qobject_cast(w)->saveState(0)); } endGroup(); } QString Settings::dataPath() { if(m_dataPath.isNull()) { #if QT_VERSION < 0x050000 m_dataPath = QDesktopServices::storageLocation(QDesktopServices::DataLocation); #else m_dataPath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); #endif m_dataPath.append("/data"); } return m_dataPath; } QString Settings::commonDataPath() { #if QT_VERSION < 0x050000 QString dataPath = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation) + "/chessdata"; #else QString dataPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/chessdata"; #endif QString dir = value("/General/DefaultDataPath", dataPath).toString(); return dir; } void Settings::setList(const QString& key, QList list) { QList varlist; int i; foreach(i, list) varlist.append(QVariant(i)); setValue(key, varlist); } bool Settings::list(const QString &key, QList& list, int items) { QList varlist = value(key).toList(); if(items >= 0 && varlist.count() + list.count() != items) { return false; } QVariant v; foreach(v, varlist) list.append(v.toInt()); return true; } void Settings::setByteArray(const QString& key, const QByteArray& arr) { setValue(key, arr); } QByteArray Settings::byteArray(const QString& key) { return value(key, QByteArray()).toByteArray(); } void Settings::setMap(const QString& key, const OptionValueList& map) { QByteArray data; QDataStream * stream = new QDataStream(&data, QIODevice::WriteOnly); (*stream) << map; delete stream; setByteArray(key, data); } void Settings::getMap(const QString& key, OptionValueList& map) { QByteArray data = byteArray(key); QDataStream * stream = new QDataStream(&data, QIODevice::ReadOnly); (*stream) >> map; delete stream; } QMap Settings::initDefaultValues() const { QMap map; map.insert("/General/EditLimit", 10); map.insert("/General/automaticECO", true); map.insert("/General/useIndexFile", true); map.insert("/General/ListFontSize", DEFAULT_LISTFONTSIZE); map.insert("/General/onlineTablebases", true); map.insert("/General/onlineVersionCheck", true); map.insert("/General/autoCommitDB", false); map.insert("/General/language", "Default"); map.insert("/General/BuiltinDbInstalled", false); map.insert("/GameText/FontSize", DEFAULT_FONTSIZE); map.insert("/GameText/ColumnStyle", false); map.insert("/GameText/SymbolicNag", true); map.insert("/GameText/TextWidth", 0); map.insert("/GameText/VariationIndentLevel", 1); map.insert("/GameText/VariationIndentSize", 3); map.insert("/GameText/CommentIndent", "OnlyMainline"); map.insert("/GameText/MainLineMoveColor", "black"); map.insert("/GameText/VariationColor", "blue"); map.insert("/GameText/CommentColor", "green"); map.insert("/GameText/NagColor", "red"); map.insert("/GameText/HeaderColor", "blue"); map.insert("/GameText/ShowHeader", false); map.insert("/GameText/ShowDiagrams", true); map.insert("/GameText/DiagramSize", 200); map.insert("/GameText/PieceString", " KQRBN"); map.insert("/MainWindow/GameToolBar", false); map.insert("/MainWindow/VerticalTabs", false); map.insert("/MainWindow/StayOnTop", false); map.insert("/MainWindow/FilterFollowsGame", false); map.insert("/History/MaxEntries", 4); map.insert("/Board/showFrame", true); map.insert("/Board/showCoordinates", true); map.insert("/Board/showCurrentMove", true); map.insert("/Board/guessMove", true); map.insert("/Board/nextGuess", false); map.insert("/Board/minWheelCount", MIN_WHEEL_COUNT); map.insert("/Board/pieceTheme", "merida"); map.insert("/Board/pieceEffect", BoardTheme::Shadow); map.insert("/Board/boardTheme", "brazilwood"); map.insert("/Board/lightColor", QColor(Qt::lightGray)); map.insert("/Board/darkColor", QColor(Qt::darkGray)); map.insert("/Board/highlightColor", QColor(Qt::yellow)); map.insert("/Board/frameColor", QColor(Qt::black)); map.insert("/Board/currentMoveColor", QColor(Qt::blue)); map.insert("/Board/AutoPlayerInterval", 3000); map.insert("/Board/AutoSaveAndContinue", false); return map; } QVariant Settings::getValue(const QString &key) const { static QMap defaultValues = initDefaultValues(); if(defaultValues.contains(key)) { return value(key, defaultValues.value(key)); } else { QString groupKey = QString("/") + group() + "/" + key; if(defaultValues.contains(groupKey)) { return value(key, defaultValues.value(groupKey)); } } Q_ASSERT(false); return QVariant(); } QString Settings::getThemaPath() const { QString themeDir(AppSettings->dataPath() + "/themes"); if(!QFile::exists(themeDir)) { themeDir = QString(":/themes"); } return themeDir; } QStringList Settings::getThemeList() const { QStringList themes = QDir(getThemaPath()).entryList(QStringList("*.png")); return themes; } QString Settings::getBoardPath() const { QString boardDir(AppSettings->dataPath() + "/themes/boards"); if(!QFile::exists(boardDir)) { boardDir = QString(":/themes/boards"); } return boardDir; } QStringList Settings::getBoardList() const { QStringList boards = QDir(getBoardPath()).entryList(QStringList("*.png")); return boards; } QString Settings::getImagePath() const { QString imgDir(AppSettings->dataPath() + "/images"); if(!QFile::exists(imgDir)) { imgDir = QString(":/data/images"); } return imgDir; } QStringList Settings::getTranslationPaths() const { QStringList list; list.append(":i18n"); QString langDir(AppSettings->dataPath() + "/lang"); if(QFile::exists(langDir)) { list.append(langDir); } return list; } QStringList Settings::getTranslations() const { QStringList total; QStringList langDirs = getTranslationPaths(); foreach(QString dir, langDirs) { QStringList translations = QDir(dir).entryList(QStringList("*.qm")); total.append(translations); } total.removeDuplicates(); return total; } QString Settings::getUserDataPath() const { #if QT_VERSION < 0x050000 QString dataPath = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation) + "/chessdata"; #else QString dataPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/chessdata"; #endif return dataPath; } QString Settings::getTempPath() const { #if QT_VERSION < 0x050000 QString path = QDesktopServices::storageLocation(QDesktopServices::TempLocation); #else QString path = QStandardPaths::writableLocation(QStandardPaths::TempLocation); #endif return path; } ////////////////////////////////////////////////////////////////////////////// // The singleton instance pointer of our AppSettings ////////////////////////////////////////////////////////////////////////////// Settings* AppSettings; ////////////////////////////////////////////////////////////////////////////// // EOF ////////////////////////////////////////////////////////////////////////////// chessx-1.0.0/src/gui/loadquery.ui000644 001750 001750 00000005306 12210044263 017526 0ustar00niklasniklas000000 000000 LoadQuery 0 0 345 149 Load Database Currently, there are no databases configured. Shall I download a database? Large Database (9M) true Small Database Qt::Vertical 20 40 Start Download! true Skip Loading false false StartLoad clicked() LoadQuery accept() 91 120 172 74 SkipLoad clicked() LoadQuery reject() 253 120 172 74 chessx-1.0.0/src/database/eventinfo.cpp000644 001750 001750 00000013633 12223260306 020647 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include #include #include "eventinfo.h" #include "database.h" static bool sortPlayersLt(const PlayerInfoListItem& a1, const PlayerInfoListItem& a2) { if(a1.second == a2.second) { return (a1.first < a2.first); } return a1.second > a2.second; } EventInfo::EventInfo() { m_database = 0; reset(); } EventInfo::~EventInfo() { } EventInfo::EventInfo(Database* db, const QString & event) { setDatabase(db); setName(event); reset(); update(); } QString EventInfo::name() const { return m_name; } void EventInfo::setDatabase(Database* db) { m_database = db; } void EventInfo::setName(const QString& event) { m_name = event; update(); } int EventInfo::toResult(const QString& res) const { if(res.startsWith("1/2")) { return Draw; } else if(res.startsWith('1')) { return WhiteWin; } else if(res.startsWith('0')) { return BlackWin; } else { return ResultUnknown; } } float EventInfo::toPoints(const QString& res) const { if(res.startsWith("1/2")) { return 0.5; } else if(res.startsWith('1')) { return 1.0; } else if(res.startsWith('0')) { return 0.0; } else if(res.startsWith("+-")) { return 1.0; } else if(res.startsWith("-+")) { return 0.0; } else if(res.startsWith("+--")) { return 1.0; } else if(res.startsWith("--+")) { return 0.0; } else { return ResultUnknown; } } void EventInfo::update() { QHash players; const Index* index = m_database->index(); // Determine matching tag values ValueIndex event = index->getValueIndex(m_name); // Clean previous statistics reset(); for(int i = 0; i < m_database->count(); ++i) { if(index->valueIndexFromTag(TagNameEvent, i) != event) { continue; } QString result = index->tagValue(TagNameResult, i); int res = toResult(result); QString whitePlayer = index->tagValue(TagNameWhite, i); QString blackPlayer = index->tagValue(TagNameBlack, i); // The following works as QHash initializes a default-constructed value to 0 players[whitePlayer] += toPoints(result); players[blackPlayer] += (1.0 - toPoints(result)); m_games[whitePlayer]++; m_games[blackPlayer]++; m_result[res]++; m_count++; PartialDate date(index->tagValue(TagNameDate, i)); if(date.year() > 1000) { m_date[0] = qMin(date, m_date[0]); m_date[1] = qMax(date, m_date[1]); } } foreach(QString s, players.keys()) { m_players.append(PlayerInfoListItem(s, players.value(s))); } qSort(m_players.begin(), m_players.end(), sortPlayersLt); } QString EventInfo::formattedScore(const int result[4], int count) const { if(!count) { return QCoreApplication::translate("EventInfo", "no games"); } QString score = ""; QChar scoresign[4] = {'*', '+', '=', '-'}; for(int i = WhiteWin; i <= BlackWin; ++i) { score += QString("  %1%2").arg(scoresign[i]).arg(result[i]); } if(result[ResultUnknown]) { score += QString("  *%1").arg(result[ResultUnknown]); } if(count - result[ResultUnknown]) score += QString("  (%1%)").arg((100.0 * result[WhiteWin] + 50.0 * result[Draw]) / (count - result[ResultUnknown]), 1, 'f', 1); score += ""; return score; } QString EventInfo::formattedScore() const { return QCoreApplication::translate("EventInfo", "Total: %1") .arg(formattedScore(m_result, m_count)); } void EventInfo::reset() { for(int c = White; c <= Black; ++c) { for(int r = 0; r < 4; ++r) { m_result[r] = 0; } } m_players.clear(); m_games.clear(); m_count = 0; m_rating[0] = 99999; m_rating[1] = 0; m_date[0] = PDMaxDate; m_date[1] = PDMinDate; } QString EventInfo::formattedGameCount() const { return QCoreApplication::translate("EventInfo", "Games in database %1: %2
") .arg(m_database->name()).arg(m_count); } QString EventInfo::formattedRating() const { if(!m_rating[1]) { return QString(); } else if(m_rating[0] == m_rating[1]) { return QCoreApplication::translate("EventInfo", "Rating: %1
").arg(m_rating[0]); } else return QCoreApplication::translate("EventInfo", "Rating: %1-%2
") .arg(m_rating[0]).arg(m_rating[1]); } QString EventInfo::formattedRange() const { if(m_date[0].year() == 9999) // No date { return QCoreApplication::translate("EventInfo", "Date: ????.??.\?\?
"); } else if(m_date[0].year() < 1000) { return QString(); } else { return QCoreApplication::translate("EventInfo", "Date: %1
").arg(m_date[0].range(m_date[1])); } } QString EventInfo::listOfPlayers() const { QString playersList; playersList.append(QCoreApplication::translate("EventInfo", "")); for(PlayerInfoList::const_iterator it = m_players.begin(); it != m_players.end(); ++it) { playersList += QString("") .arg((*it).first) .arg((*it).first) .arg((*it).second) .arg(m_games[(*it).first]); } playersList = playersList.append("
ParticipantsScore
%2%3/%4
"); return playersList; } chessx-1.0.0/data/images/arrow_down_double.png000644 001750 001750 00000012354 12144113023 022204 0ustar00niklasniklas000000 000000 PNG  IHDR>a CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs  tIME  .% *IDATxMlT܁ĉ] @0JU0(BQhU&.Z.AtW*uMUJ]`H]UxQbH$@Y0cjk{N17'={10ؚtic0&` a0L 0&` a0L 0&` a0L 0&` QJ!~'R41LUX@CEGuv)@ȝ+W=]ٶk3?-pmMG(^Qujێ~B-[؀׿-S9iC)f0?Bwk|BH=jY{J?bcBxU'Ie|  ?19!`y-(H\Q;7ީQW^KX)g8 L@E*PAA«E >H^V ̨@Ux0\t݈<$u٫pIz8 "PŁ D+ <^%/HYA"I9!ք`A>>N'Zj"Bq@GH޲ "`f ɸ 4z l60B\<d J$jU LBC&͉ U+g PbF:u_ɉd]X Oa*8>A$,Xp(@e'׵{QhxD$0 ܽVE aPZ_DE .@VA )dw^˪A༇z wu/FcYxP*&/!K,uife({ /D1/ލiB: V8 2 ~-߲rQ{KHGlڼٵ-;^bf"44.nnQϧL^ek+-?U: 3srȅ3mDϓO "i`s2[9ɩlyg O@0/~v10;1%ޚ@A@xoxƲz_^7nX1\gf\>uO_P׃5_}^ZX8||<ZN|z 1peN>1 @r zm8yjevz 4$M3S8<瞞 .!*Z;w؂{y~,ti[^ֱo{qIï?DjBQ!*whщs{, |@u2Q!@zfAl[)Tޚ:.+B?Tr<H*IDKn[,T%n47N(d`_ (QT`K:0Q0HU}H'•3\8X`+kFX1iF)By6 `vn4m4Ca(_zdՇ@秃b +{f0BֿvMÇaVq էJ\$2@ϣ$qo`<) 1~ `gW8'`l 3|>}DQ M~x_cC=Xep+5fO i;r_':cMÃ;P eĈ_+[a @eh)uhH ) ՉÝ|>x_-{3B<Ή=p哛?xfx0Vm8P]p,HW?'2<+7<e7V>A2~[۲z&lx4x" @O ܸMAv: <|Sw9LAߪޟ8Ɓoߒ»OQDdzc{'Rm}s~xt=ݼ@XCv?;7^[%HVEu\"^| QLyAr]ɐNT.<@{IZ^+i^7J^o'Nf:ȱ\<@{c~^h]E~^y3y~f._U- 4` a0 0 0 0 0 0 0 0 0 0 0uZ%IENDB`chessx-1.0.0/data/images/edit_paste.png000644 001750 001750 00000013526 12141255204 020621 0ustar00niklasniklas000000 000000 PNG  IHDR>atIME "RrWbKGDIDATx]iez~軧\5bIv AH%.RDkJ"e-d B @h`,c3\}wח곪瓾zy 볅BaA|M@UG{5ʲ?k\K@+C9 G\j_S~'ឨ~_ 'yMx>Vz7r&ʊGNӧOdljմ o} Hקo3 ?cH$+47C;M-fzkԮU#1tp]~g灿Gy$G8'N|>?b`YiʹN xY]]wd.;FsΩ+++w*B-}4ssJ`0XXpuI[[[Ǡ_qv ^{w[3FR >m i~'G ͠QhJT@{NOW&KuEE۸&**>m%VHwc᝞! )S>q:9kzA߻}q'!Ɣ#2: )"k|ee'uJ=9\xF;uO LDŽ?N[^6Om~ y wL,rij8wB@ۺ hI/ E#c(+'zFy䫯{.L1?r ȅbaA`( Gf~GvtRimȧ7܀@ތ 3S 8x`[z/ $Cd|Ahl3 ME(f6J\'[r(!H47 &:yXZZ`ccCW!(@!<>}sbNk9$ǪCx`㳳yP"hH> MnˠW~*"BQ@?U*0'"]T"mlsh'G l^<[}2e3}_^^tD>^HO#e9 AZQ!@X<(m!DIN\#D 0j :$2( =N\߾O>LL@P4nÿ4X b7.> PiD  M'p?+YWW'trP(J//۴\ǩNEs K;d@)QzƄ΅o} *Jm!ԯbcccm;,  JK?}EI.EM$U#S0xzd?lpu))dZI@*n6փ&we%*= ZIQdpz[CWBD%!m@Ri^|ʈ7~ ȡXU݌u J2EEWaS =4m7Ey #M(_l,X0lKp, 4 MZm9pLIl7VN=f`[WjxR{ (4ӵ 2Dap\WZ PٖW K7X1 0qV pLonU؂Q+* ̒MBm뤛l`TAnP؃ЃOC  T h|/s$A 4#|NkpXawRW 6!Y dyE+V:7Mw"V-7U9Dѯ[X'T![|5)v . 408e=HЬyAA` zҳ>u: EM fQ@6 w*XzCHס(SQ!+'JUq@ѲВ/,A:$p+Z&>-osr: `Wދ1}?/ES Y0F3|0/&wߍRj&Cp9p TSk90, #NG PE؟~F3-p̙~Ov$I mim}{|Fi+WEFT? Uw rJO$Eԑz 7a*L%߃Hq+@OϞ=(]q3O(K~={c,[ϧ>}:f||\~Rz_q{p5;0mZ"PzJsܘJ2[-K7KǸ!N.2zcl&H}$q$ M=$)CFu}Qr=_Cp~/  F8URݵjy@CnpGzzuI )@Hp\J&)14\mN _!qU+?H@W3Fûz d M=GmLK$ UrA~~w7zjJAA$4`2ORH%yV2ݼyuؔ Z;3ܹ*1;; ~ވ/mNr?P#'h]Qx]''Я])ONE1<}ωRJiWM)9Fev3(/v;D:]3i6ZdOy P⧿ѹ!JVSP 25AC&`D>'AB6˗/ρ#kZ*"nuP/D'S QށL .Ms*ylDԁN8]Jv" ' y˿]/'x@sA'KJ@h_D`Tvj$ܟzrk|D%#bQ  '@:U V"FV 3D6Du0ۻ~S P9&/~]܇7xOm@6bT$H4Hfa%@___O@\0BP rxa}ݗ7JJ"UW5zcxӜQTDoLmf"%Z"$OuC.h P|TT{ztMD->A-xm 99Rx 4qF]Ş~(X${`7wr[wtk [f(L^Ѹ~TNn]nkH@_@uہ!{KvۅLrN=x'NHmT9{[Q[Q (ȍ(]g:&v*PHrkJv5{wwrLS9 I'Vݲk շRJ'<$#Ƚ]BG}V ,) p_|= Z?Wãf޸vzChI[> Dv[<8\*C)J 3 rptqePM峢)ltcfNq _0G&@T<׼Z>hj.K Vk-nR3~͜[ hH*@;e *Y^O_sPŤ{^V4[Wro7q:\5 \4o#N(l; Y$ӧY?T`m&Mk)U@|$–{[jϚF^#%*Q M v`8w  7*/2(X+@v$^wKs|hqsPP4 X*'da-N垯eX %TƐ}[ ̺>m0*7$; B2  D(*NOT+goVe,Z>kQehI7 #)m;aFJoB( H$!'$(Cty~:|C._8??OM"=䕕3GQDH8Iَp@k@$mA ]U)NN/ A[OTZ6FG[N sޑrOe>DG p<mAhXɡwT!-dI3  ;A2{=۪j'SO 7Ee8-}ŖNugJLo>7)h#UdZ8սI)N3@L6W -@~e*x*f H X_ TcDcpq_6XDݪnt9-}Zd!@Eܽ$C> hf"dw08]&Bp}zZUCT (bp3[|_C_XaRsڑ0\n`sE%B$5:,Ú@5Ȣy)歝.;a 6=NRMlF|lxK˸ 悧N:0=== JFt 14eF& RprJ~'vCD6?{K< L!e6/Nj=H kfxh m~,9 #include "boardview.h" #include "openingtree.h" #include "settings.h" OpeningTreeWidget::OpeningTreeWidget(QWidget *parent) : QWidget(parent), ui(new Ui::OpeningTreeWidget) { ui->setupUi(this); m_openingTree = new OpeningTree; ui->OpeningTreeView->setObjectName("OpeningTree"); ui->OpeningTreeView->setSortingEnabled(true); ui->OpeningTreeView->setModel(m_openingTree); ui->OpeningTreeView->sortByColumn(1, Qt::DescendingOrder); connect(ui->OpeningTreeView, SIGNAL(clicked(const QModelIndex&)), parent, SLOT(slotSearchTreeMove(const QModelIndex&))); connect(m_openingTree, SIGNAL(progress(int)), parent, SLOT(slotOperationProgress(int))); connect(m_openingTree, SIGNAL(openingTreeUpdated()), parent, SLOT(slotTreeUpdate())); connect(m_openingTree, SIGNAL(openingTreeUpdateStarted()), parent, SLOT(slotTreeUpdateStarted())); connect(parent, SIGNAL(reconfigure()), SLOT(slotReconfigure())); m_openingBoardView = new BoardView(this, BoardView::IgnoreSideToMove | BoardView::SuppressGuessMove); m_openingBoardView->setObjectName("OpeningBoardView"); m_openingBoardView->setMinimumSize(200, 200); ui->OpeningBoardWidget->addWidget(m_openingBoardView, 1); m_openingBoardView->configure(); m_openingBoardView->setEnabled(false); } OpeningTreeWidget::~OpeningTreeWidget() { delete ui; } void OpeningTreeWidget::cancel(bool bVisible) { m_openingTree->cancel(bVisible); } QString OpeningTreeWidget::move(QModelIndex index) const { return m_openingTree->move(index); } Board OpeningTreeWidget::board() const { return m_openingTree->board(); } bool OpeningTreeWidget::updateFilter(Filter& f, const Board& b, bool updateFilter, bool bEnd) { m_openingBoardView->setBoard(b); return m_openingTree->updateFilter(f, b, updateFilter, bEnd); } void OpeningTreeWidget::saveConfig() { AppSettings->setLayout(this); ui->OpeningTreeView->saveConfig(); } void OpeningTreeWidget::slotReconfigure() { m_openingBoardView->configure(); AppSettings->layout(this); ui->OpeningTreeView->slotReconfigure(); } chessx-1.0.0/src/database/ecoinfo.cpp000644 001750 001750 00000014554 12223260306 020277 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include #include #include "ecoinfo.h" #include "database.h" static bool sortPlayersLt(const PlayerInfoListItem& a1, const PlayerInfoListItem& a2) { if(a1.second == a2.second) { return (a1.first < a2.first); } return a1.second > a2.second; } EcoInfo::EcoInfo() { m_database = 0; reset(); } EcoInfo::~EcoInfo() { } EcoInfo::EcoInfo(Database* db, const QString & eco) { setDatabase(db); setCode(eco); reset(); update(); } QString EcoInfo::name() const { return m_code; } void EcoInfo::setDatabase(Database* db) { m_database = db; } void EcoInfo::setCode(const QString& eco) { m_code = eco; update(); } int EcoInfo::toResult(const QString& res) const { if(res.startsWith("1/2")) { return Draw; } else if(res.startsWith('1')) { return WhiteWin; } else if(res.startsWith('0')) { return BlackWin; } else { return ResultUnknown; } } float EcoInfo::toPoints(const QString& res) const { if(res.startsWith("1/2")) { return 0.5; } else if(res.startsWith('1')) { return 1.0; } else if(res.startsWith('0')) { return 0.0; } else { return -1.0; } } void EcoInfo::update() { QHash playersWhite; QHash playersBlack; const Index* index = m_database->index(); // Determine matching tag values ValueIndex eco = index->getValueIndex(m_code); // Clean previous statistics reset(); for(int i = 0; i < m_database->count(); ++i) { if(index->valueIndexFromTag(TagNameECO, i) != eco) { continue; } QString result = index->tagValue(TagNameResult, i); int res = toResult(result); QString whitePlayer = index->tagValue(TagNameWhite, i); QString blackPlayer = index->tagValue(TagNameBlack, i); // The following works as QHash initializes a default-constructed value to 0 float fres = toPoints(result); if(fres >= 0) { playersWhite[whitePlayer] += fres; playersBlack[blackPlayer] += (1.0 - fres); m_gamesWhite[whitePlayer]++; m_gamesBlack[blackPlayer]++; } else { // This looks silly, but the []operator has a side effect! if(playersWhite[whitePlayer] == 0) { playersWhite[whitePlayer] = 0; } if(playersBlack[blackPlayer] == 0) { playersBlack[blackPlayer] = 0; } } m_result[res]++; m_count++; } foreach(QString s, playersWhite.keys()) { m_playersWhite.append(PlayerInfoListItem(s, playersWhite.value(s))); } qSort(m_playersWhite.begin(), m_playersWhite.end(), sortPlayersLt); foreach(QString s, playersBlack.keys()) { m_playersBlack.append(PlayerInfoListItem(s, playersBlack.value(s))); } qSort(m_playersBlack.begin(), m_playersBlack.end(), sortPlayersLt); } QString EcoInfo::formattedScore(const int result[4], int count) const { if(!count) { return QCoreApplication::translate("EcoInfo", "no games"); } QString score = ""; QChar scoresign[4] = {'*', '+', '=', '-'}; for(int i = WhiteWin; i <= BlackWin; ++i) { score += QString("  %1%2").arg(scoresign[i]).arg(result[i]); } if(result[ResultUnknown]) { score += QString("  *%1").arg(result[ResultUnknown]); } if(count - result[ResultUnknown]) score += QString("  (%1%)").arg((100.0 * result[WhiteWin] + 50.0 * result[Draw]) / (count - result[ResultUnknown]), 1, 'f', 1); score += ""; return score; } QString EcoInfo::formattedScore() const { return tr("Total: %1") .arg(formattedScore(m_result, m_count)); } void EcoInfo::reset() { for(int c = White; c <= Black; ++c) { for(int r = 0; r < 4; ++r) { m_result[r] = 0; } } m_playersWhite.clear(); m_playersBlack.clear(); m_gamesWhite.clear(); m_gamesBlack.clear(); m_count = 0; m_rating[0] = 99999; m_rating[1] = 0; } QString EcoInfo::formattedGameCount() const { return QCoreApplication::translate("EcoInfo", "Games in database %1: %2") .arg(m_database->name()).arg(m_count); } QString EcoInfo::formattedRating() const { if(!m_rating[1]) { return QString(); } else if(m_rating[0] == m_rating[1]) { return QCoreApplication::translate("EcoInfo", "Rating: %1").arg(m_rating[0]); } else return QCoreApplication::translate("EcoInfo", "Rating: %1-%2") .arg(m_rating[0]).arg(m_rating[1]); } QString EcoInfo::listOfPlayers() const { QString playersList; // Does not work due to bugs in Qt5 // if (m_playersWhite.count() > 10) // { // playersList.append(tr("Go to Black Players Score")); // } playersList.append(tr("")); for(PlayerInfoList::const_iterator it = m_playersWhite.begin(); it != m_playersWhite.end(); ++it) { playersList += QString("") .arg((*it).first) .arg((*it).first) .arg((*it).second) .arg(m_gamesWhite[(*it).first]); } playersList = playersList.append("
White PlayerScore
%2%3/%4
"); playersList.append(tr("")); for(PlayerInfoList::const_iterator it = m_playersBlack.begin(); it != m_playersBlack.end(); ++it) { playersList += QString("") .arg((*it).first) .arg((*it).first) .arg((*it).second) .arg(m_gamesBlack[(*it).first]); } playersList = playersList.append("
Black PlayerScore
%2%3/%4
"); return playersList; } chessx-1.0.0/src/quazip/quaziodevice.cpp000644 001750 001750 00000020113 12223260306 021076 0ustar00niklasniklas000000 000000 #include "quaziodevice.h" #define QUAZIO_INBUFSIZE 4096 #define QUAZIO_OUTBUFSIZE 4096 class QuaZIODevicePrivate { friend class QuaZIODevice; QuaZIODevicePrivate(QIODevice *io); ~QuaZIODevicePrivate(); QIODevice *io; z_stream zins; z_stream zouts; char *inBuf; int inBufPos; int inBufSize; char *outBuf; int outBufPos; int outBufSize; bool zBufError; int doFlush(QString &error); }; QuaZIODevicePrivate::QuaZIODevicePrivate(QIODevice *io): io(io), inBuf(NULL), inBufPos(0), inBufSize(0), outBuf(NULL), outBufPos(0), outBufSize(0), zBufError(false) { zins.zalloc = (alloc_func) NULL; zins.zfree = (free_func) NULL; zins.opaque = NULL; zouts.zalloc = (alloc_func) NULL; zouts.zfree = (free_func) NULL; zouts.opaque = NULL; inBuf = new char[QUAZIO_INBUFSIZE]; outBuf = new char[QUAZIO_OUTBUFSIZE]; #ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT debug.setFileName("debug.out"); debug.open(QIODevice::WriteOnly); #endif #ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT indebug.setFileName("debug.in"); indebug.open(QIODevice::WriteOnly); #endif } QuaZIODevicePrivate::~QuaZIODevicePrivate() { #ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT debug.close(); #endif #ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT indebug.close(); #endif if(inBuf != NULL) { delete[] inBuf; } if(outBuf != NULL) { delete[] outBuf; } } int QuaZIODevicePrivate::doFlush(QString &error) { int flushed = 0; while(outBufPos < outBufSize) { int more = io->write(outBuf + outBufPos, outBufSize - outBufPos); if(more == -1) { error = io->errorString(); return -1; } if(more == 0) { break; } outBufPos += more; flushed += more; } if(outBufPos == outBufSize) { outBufPos = outBufSize = 0; } return flushed; } // #define QUAZIP_ZIODEVICE_DEBUG_OUTPUT // #define QUAZIP_ZIODEVICE_DEBUG_INPUT #ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT #include static QFile debug; #endif #ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT #include static QFile indebug; #endif QuaZIODevice::QuaZIODevice(QIODevice *io, QObject *parent): QIODevice(parent), d(new QuaZIODevicePrivate(io)) { connect(io, SIGNAL(readyRead()), SIGNAL(readyRead())); } QuaZIODevice::~QuaZIODevice() { if(isOpen()) { close(); } delete d; } QIODevice *QuaZIODevice::getIoDevice() const { return d->io; } bool QuaZIODevice::open(QIODevice::OpenMode mode) { if((mode & QIODevice::ReadOnly) != 0) { if(inflateInit(&d->zins) != Z_OK) { setErrorString(d->zins.msg); return false; } } if((mode & QIODevice::WriteOnly) != 0) { if(deflateInit(&d->zouts, Z_DEFAULT_COMPRESSION) != Z_OK) { setErrorString(d->zouts.msg); return false; } } return QIODevice::open(mode); } void QuaZIODevice::close() { if((openMode() & QIODevice::ReadOnly) != 0) { if(inflateEnd(&d->zins) != Z_OK) { setErrorString(d->zins.msg); } } if((openMode() & QIODevice::WriteOnly) != 0) { flush(); if(deflateEnd(&d->zouts) != Z_OK) { setErrorString(d->zouts.msg); } } QIODevice::close(); } qint64 QuaZIODevice::readData(char *data, qint64 maxSize) { int read = 0; while(read < maxSize) { if(d->inBufPos == d->inBufSize) { d->inBufPos = 0; d->inBufSize = d->io->read(d->inBuf, QUAZIO_INBUFSIZE); if(d->inBufSize == -1) { d->inBufSize = 0; setErrorString(d->io->errorString()); return -1; } if(d->inBufSize == 0) { break; } } while(read < maxSize && d->inBufPos < d->inBufSize) { d->zins.next_in = (Bytef *)(d->inBuf + d->inBufPos); d->zins.avail_in = d->inBufSize - d->inBufPos; d->zins.next_out = (Bytef *)(data + read); d->zins.avail_out = (uInt)(maxSize - read); // hope it's less than 2GB int more = 0; switch(inflate(&d->zins, Z_SYNC_FLUSH)) { case Z_OK: read = (char *) d->zins.next_out - data; d->inBufPos = (char *) d->zins.next_in - d->inBuf; break; case Z_STREAM_END: read = (char *) d->zins.next_out - data; d->inBufPos = (char *) d->zins.next_in - d->inBuf; return read; case Z_BUF_ERROR: // this should never happen, but just in case if(!d->zBufError) { qWarning("Z_BUF_ERROR detected with %d/%d in/out, weird", d->zins.avail_in, d->zins.avail_out); d->zBufError = true; } memmove(d->inBuf, d->inBuf + d->inBufPos, d->inBufSize - d->inBufPos); d->inBufSize -= d->inBufPos; d->inBufPos = 0; more = d->io->read(d->inBuf + d->inBufSize, QUAZIO_INBUFSIZE - d->inBufSize); if(more == -1) { setErrorString(d->io->errorString()); return -1; } if(more == 0) { return read; } d->inBufSize += more; break; default: setErrorString(QString::fromLocal8Bit(d->zins.msg)); return -1; } } } #ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT indebug.write(data, read); #endif return read; } qint64 QuaZIODevice::writeData(const char *data, qint64 maxSize) { int written = 0; QString error; if(d->doFlush(error) == -1) { setErrorString(error); return -1; } while(written < maxSize) { // there is some data waiting in the output buffer if(d->outBufPos < d->outBufSize) { return written; } d->zouts.next_in = (Bytef *)(data + written); d->zouts.avail_in = (uInt)(maxSize - written); // hope it's less than 2GB d->zouts.next_out = (Bytef *) d->outBuf; d->zouts.avail_out = QUAZIO_OUTBUFSIZE; switch(deflate(&d->zouts, Z_NO_FLUSH)) { case Z_OK: written = (char *) d->zouts.next_in - data; d->outBufSize = (char *) d->zouts.next_out - d->outBuf; break; default: setErrorString(QString::fromLocal8Bit(d->zouts.msg)); return -1; } if(d->doFlush(error) == -1) { setErrorString(error); return -1; } } #ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT debug.write(data, written); #endif return written; } bool QuaZIODevice::flush() { QString error; if(d->doFlush(error) < 0) { setErrorString(error); return false; } // can't flush buffer, some data is still waiting if(d->outBufPos < d->outBufSize) { return true; } Bytef c = 0; d->zouts.next_in = &c; // fake input buffer d->zouts.avail_in = 0; // of zero size do { d->zouts.next_out = (Bytef *) d->outBuf; d->zouts.avail_out = QUAZIO_OUTBUFSIZE; switch(deflate(&d->zouts, Z_SYNC_FLUSH)) { case Z_OK: d->outBufSize = (char *) d->zouts.next_out - d->outBuf; if(d->doFlush(error) < 0) { setErrorString(error); return false; } if(d->outBufPos < d->outBufSize) { return true; } break; case Z_BUF_ERROR: // nothing to write? return true; default: setErrorString(QString::fromLocal8Bit(d->zouts.msg)); return false; } } while(d->zouts.avail_out == 0); return true; } bool QuaZIODevice::isSequential() const { return true; } chessx-1.0.0/src/gui/toolmainwindow.cpp000644 001750 001750 00000001154 12053745721 020751 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "settings.h" #include "toolmainwindow.h" #include ToolMainWindow::ToolMainWindow(QWidget *parent) : QMainWindow(parent) { setWindowFlags(Qt::Widget); } void ToolMainWindow::saveConfig() { // saving subwindows does not work anymore as of Qt 4.4 } void ToolMainWindow::slotReconfigure() { // restoring subwindows does not work anymore as of Qt 4.4 } chessx-1.0.0/src/quazip/quazipdir.h000644 001750 001750 00000014540 12223260306 020072 0ustar00niklasniklas000000 000000 #ifndef QUAZIP_QUAZIPDIR_H #define QUAZIP_QUAZIPDIR_H class QuaZipDirPrivate; #include "quazip.h" #include "quazipfileinfo.h" #include #include #include /// Provides ZIP archive navigation. /** * This class is modelled after QDir, and is designed to provide similar * features for ZIP archives. * * The only significant difference from QDir is that the root path is not * '/', but an empty string since that's how the file paths are stored in * the archive. However, QuaZipDir understands the paths starting with * '/'. It is important in a few places: * * - In the cd() function. * - In the constructor. * - In the exists() function. * * Note that since ZIP uses '/' on all platforms, the '\' separator is * not supported. */ class QUAZIP_EXPORT QuaZipDir { private: QSharedDataPointer d; public: /// The copy constructor. QuaZipDir(const QuaZipDir &that); /// Constructs a QuaZipDir instance pointing to the specified directory. /** If \a dir is not specified, points to the root of the archive. The same happens if the \a dir is "/". */ QuaZipDir(QuaZip *zip, const QString &dir = QString()); /// Destructor. ~QuaZipDir(); /// The assignment operator. bool operator==(const QuaZipDir &that); /// operator!= /** \return \c true if either this and \a that use different QuaZip instances or if they point to different directories. */ inline bool operator!=(const QuaZipDir &that) { return !operator==(that); } /// operator== /** \return \c true if both this and \a that use the same QuaZip instance and point to the same directory. */ QuaZipDir& operator=(const QuaZipDir &that); /// Returns the name of the entry at the specified position. QString operator[](int pos) const; /// Returns the current case sensitivity mode. QuaZip::CaseSensitivity caseSensitivity() const; /// Changes the 'current' directory. /** * If the path starts with '/', it is interpreted as an absolute * path from the root of the archive. Otherwise, it is interpreted * as a path relative to the current directory as was set by the * previous cd() or the constructor. * * Note that the subsequent path() call will not return a path * starting with '/' in all cases. */ bool cd(const QString &dirName); /// Goes up. bool cdUp(); /// Returns the number of entries in the directory. unsigned int count() const; /// Returns the current directory name. /** The name doesn't include the path. */ QString dirName() const; /// Returns the list of the entries in the directory. /** \param nameFilters The list of file patterns to list, uses the same syntax as QDir. \param filters The entry type filters, only Files and Dirs are accepted. \param sort Sorting mode (not supported yet). */ QList entryInfoList(const QStringList &nameFilters, QDir::Filters filters = QDir::NoFilter, QDir::SortFlags sort = QDir::NoSort) const; /// Returns the list of the entries in the directory. /** \overload The same as entryInfoList(QStringList(), filters, sort). */ QList entryInfoList(QDir::Filters filters = QDir::NoFilter, QDir::SortFlags sort = QDir::NoSort) const; /// Returns the list of the entry names in the directory. /** The same as entryInfoList(nameFilters, filters, sort), but only returns entry names. */ QStringList entryList(const QStringList &nameFilters, QDir::Filters filters = QDir::NoFilter, QDir::SortFlags sort = QDir::NoSort) const; /// Returns the list of the entry names in the directory. /** \overload The same as entryList(QStringList(), filters, sort). */ QStringList entryList(QDir::Filters filters = QDir::NoFilter, QDir::SortFlags sort = QDir::NoSort) const; /// Returns \c true if the entry with the specified name exists. /** The ".." is considered to exist if the current directory is not root. The "." and "/" are considered to always exist. Paths starting with "/" are relative to the archive root, other paths are relative to the current dir. */ bool exists(const QString &fileName) const; /// Return \c true if the directory pointed by this QuaZipDir exists. bool exists() const; /// Returns the full path to the specified file. /** Doesn't check if the file actually exists. */ QString filePath(const QString &fileName) const; /// Returns the default filter. QDir::Filters filter(); /// Returns if the QuaZipDir points to the root of the archive. /** Not that the root path is the empty string, not '/'. */ bool isRoot() const; /// Return the default name filter. QStringList nameFilters() const; /// Returns the path to the current dir. /** The path never starts with '/', and the root path is an empty string. */ QString path() const; /// Returns the path to the specified file relative to the current dir. QString relativeFilePath(const QString &fileName) const; /// Sets the default case sensitivity mode. void setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity); /// Sets the default filter. void setFilter(QDir::Filters filters); /// Sets the default name filter. void setNameFilters(const QStringList &nameFilters); /// Goes to the specified path. /** The difference from cd() is that this function never checks if the path actually exists and doesn't use relative paths, so it's possible to go to the root directory with setPath(""). Note that this function still chops the trailing and/or leading '/' and treats a single '/' as the root path (path() will still return an empty string). */ void setPath(const QString &path); /// Sets the default sorting mode. void setSorting(QDir::SortFlags sort); /// Returns the default sorting mode. QDir::SortFlags sorting() const; }; #endif // QUAZIP_QUAZIPDIR_H chessx-1.0.0/data/themes/boards/slate.png000644 001750 001750 00000061155 10633464147 021117 0ustar00niklasniklas000000 000000 PNG  IHDRA\bKGD pHYs66BtIME 7;!GtEXtCommentCreated with GIMPW IDATxڍkn#MrSTIDiaëNoq?ðaLC^E]Hj4[Ȫ̸8qN777[k-Zk-v}}E[,5777-ooo̟sss>??W55_4M4li~oy_}Ehm[.z?k榿7MSj___y6>??xlu &Yr9[,,=Dn\<7˯{{||lyM%.ɯl\.~9Z~?]]]ԮuT{<'>l?xXjզ\uC\TC=nHPko-Mem||ͭlxlk{~?=olz}G^=\O#?susUnkϾubB\(Z n.~^6{ O_[- ]J[;mZn2`NBsk6MobO4MNSNS?yi97鼽=[tj1[=}_|G;Nm\ٍ3O NS >+kkˡ`^[Rmv8fn/Aev9Ԙ,D,D.ր'{}6 tKf?թu;`NwYր#{{ۭ컻c~777c:I|}?չD?,@>2y,<_Gm FB 3S[n;ilJl=?0ೊ{vmz[?f84%O8'8]$ @x:xBfrۛ)$ǩ%4M}p#y1;:隳9\mqssul6A/n rj Ҝ!z} rMdܴ>4yxx0lA* O n׭#>[DZl뙕jooom^~?[0dl&?Q i5f RTł4*5e=ܴJ~||YAu\sI|1aX,rlooo.v<GKvZOc.K N,;nǙ-ĥ/z x1n.1Hl_~e~ ~N5am\TM\0$ME,؀3hf/\DF9$ K?MS _7MYQY>!8 ΃Ye)'6i6Cj[v}jngUރG fku\p:f>ij6'jW OI֔ Ѕzݞ,P}ـnf05Tv4/"\Q}Iy V i#H,ۙJ6Wjjժ,ۗҪdT.V DM5g c5u<<0KqqRXÛs@8 з^lbMrjה"=rt  (g9<$ oooit',@9F;!6Jz{{杨k֬6k6~L1miQgAeN#U^ U/V'-VuN1\H1 HƅKS `դ$1&XH6D ٳT=sf]XE?Ŭx<_ِt,LU0Y.:8 iU% b[ j3whNG=H6uUY:7`0I.^6K “k ʟ7Q3s5Y&?\f3U-QY4dO05[ xU~e{@>vMyY 6O'N |G$IUpIK jAF8ˆCdOf"0/&ӆ1wIGA_w?+UI9|v ~Z?aȌʩg.L#zX*2W.QVDm:E>==L{n)\6zHcwww_#aOj?ܴ_~uRt&nQ~6x''4B ׸qC+&|phժc${(84eg.q3\lT(aeH,idkDkKi+alnZn0s7gLZoɠ),\Z9)5P9(u,ђL߈aX_hZ!3> f++N_ {U7p\ahIrJUnlٮNCv(%ǕUb1xwԐyJ7 >V|N\1e@4Rmԓ #UA)j-\|VCW(zMiaKW@^-M'NpT27AE6Oްjg!&%2 ZT%u$~&~*K, ؝>"Vg6(go3K-䔰CvP$uNԶm\eMn$B.|0XٙŅ)f|EͫN$9ooo{/~MaX`c~|a'=c9< s8&?)K.d߷j5;{HGU|+Cbo^YrIș{)׿v؈@+{&,x< dQ١V'm%|}}uPc sibe,PU)9uY-͂^]]eSԸZT_)eLT{bI 98Ţ-kl6 %*$TēKf"J2Mn4p2SlVDfC|zz4?CPh HuY[';^bYr>R Tbq8*??P13RO-M^*+}BSr KR^%腸$qg _6;%-){7MWX&S1SK,9pj4"5hEiffVP6L)j-=iUbQ$P? **-u`D(6!݌5q>>El6zFQGtn>V%ɣD{H "Jd$52pvU,S-$:| H% ٸC$UEh&0>Y\]1*'{Zmߥ,h_WuqW8d\3J0MpF6csرww|^?veI%slkEE7.8~_jR1ˮ͈ؖCI QO ev*n0ʁYP#'2t2Fi38 d؀pu6~܊SA-b{%,(ƃ@$̏$["]FQ9)uRbiXu DPzXGpҹ_~MQ ,ayq#NyU6ϵu^,`Օ 236VnjahJ[/TV1#Q̪ [7ؗQ]6)7TXcIWiG06$MfE7Cϖ 30.Z{#+:9igLTTn8Ȫ& ybF1'9z..MեZ='3=b'JWw-~'Ak1Xi> CzTdXnNt<~%`kT2,'Ǐm۵Cmt1UF9,fIYGs4Gҳ8C,935YpsMۘUˌi)d*K@g3_5Ҹ٘I:vs1XJssowww3 &`? rI+dK!ןG`t2X\"ViPUKA7 <lj;D%K$?V3BJhͨ,`a+Ûn*nszyy鑵5ʩ2/VeiF+x<(g̺[cƹB񍲸z_:n..퀛\VM% }ߕ<5FbѦn[Ma7>1jAǬ<3ьMfv?V³Le*Ǐgր.h%.T]c(S]X筵6km{~~./BS3V -Y˵uYBitPknBn nYj܁V nV+{pi }4eT`;-|l`1ihSRԤ}dH(J9#@yvf+Mj8)~UɉB?"A]ՌF+%|6ӵ")O.dMhuF<@ы(:`JӴDۤV҈&f0 !᪝pĆʂV `B9Yp`"C+V*#D1`W%{baJ8O{?*"7ELF#* ?~\Eγj'M u4F'ӔIa(7^7 37W0Ŝ kz72VNn*$ @ }~Wm6Iײ`?<n_~u)qd [gPNkwܵD#T΍T#cg%ϭ//z|CA|shgpQw;7HXQd_'h|c,T4bҨ\Nޣ+ߚEqbi 7lNT]Ί:V1 Hxd$B>iTLHY 'vgag>!?-TХrV?&zaUXՃ \ѿQk5UgPLнCx-9S!.$]777uFQSgv|(i\GN#j ~OT M7=6?{R^}^lH\e%4 8G3PܐaQ A*W>'!ؘ6onTQF;'8C΢shM> 'C0b ѧNJUiZEKҽT2r3UJIx(h@wu1 %)>Ţj59͑!}cf7Dw<:UT&JMQZTl8+W7V!7" uٴyhu:c+~k!P:=A)9,\JB*v6O".V}O 7ZL &!ʳ:Kl:tn ˁ(A0`$XEγr1]I}Ujᆒ;e-! ݝj>X-0=nnxE4],SMǍH f#[C< @&,kbl$'=>>f7j84$ #Tˮ nQZvQ$)&PkjT%XQYr50# dկIđI\DG7T͵TQ="b|X\8S])q,.mDeefp4Ga "#G"$2x`TD@ĴgyG\5JqDaOk0*6vb",͞Šu'<N(3H>jDåOX_M:?ۛʳUfa>[mh 3i) V)Dp(:΂[XF'Vsx:ݚTK҅.XdV| 3|\ 9s`I]H69 OOO3r7CȠ EKr6c#PFVJ8S6&|6bkqE,(^lP瑞?==UUPonn~FͧARM )Dg{ֆ IDAT:Ns vF'2dpVS6!k*V:ؼfvWQ N.l6-.jJWyVuOPR e=>Mx<3[*xߖ㭮+Q.r0Ffoe=ĭ0KPqL@;aeqԕG-TLJBoZR"D7S*E[  d,KM>]c9㞊^L`c41syiG%wnڽG\ .u32uǑzhq\z/i@0A+U^!z#j |]b^,%`Ym4qKgUNgt&Asbў;#r,RIsHV܋PMI=U_%VoN{xx&Ws<2R!27s]|nn":n(jV7'uQammk\;-e?L+ត|Ln&TsȣM>WW/]K*dF+u{zzj*G;7 Pŋef};=x# C Ze x7,瑈|L]_J#' Y?P<MSK6F)*6ɡ]6Qfa2@EWs݄g8`@%qelU}jȥǣU7Mo ׯN A'G/n]m# f Єr$ELω~2qL cR$"jeŷggaNN3=|v^͏c{yy aG쎀}АH6Mq~AʵbG.te9xnǷr`a::֛fˈ^L`0In?u*~:0:LȦKQW98)oҧ[sSZrJLj* 7Š;#%sOAZYP9:o?0PuhVl<$?.4%KܚfIa?H!j,=TS5*&g .jP&"v!P9&;sDKnKq3&SgFQ땹xY͍plUSf\9b^ sϹV2 3)pc66#'ʖ]HuEt26ٮؠL;SDAJ%jcW2I}/]^KS&.`INf" lyVUYX/zv=>==D(_Xi_h t8:c.N8n7 NB?ĢԈ±EN/b |p!-$ذѧ8 Iv]&Xijڃ2]…QEwgra.O[]vkIi5U7Hh67XՃuu'լ>.Ҙ[Մ*J&}]2ec8ƻ" w6W8c/S5cvݙoDR^y 2U$Ju1ͦbܤ ੪5 0ȝȸ!͈~>U}"Qd(T"ͦ}}}ժf`KŠ;4߃Lju$skIhg澐5 gvA,zapu£UłUSOU{r8JXXaZGHe}")5O1Tߵ d2nVdς);a 0,mD%M@2PJ󾷨\hJ~ޮ'5X19T5:).SEH:egd.۾@ȭN)v@{sJ+ g~9nGy\H026[E*[zB9)n6  &Mf%u==("VrʒʉE*Q KJSo'.\)|X[N MD! fvE؅Bz#$~i![ (=G "BPcHmv/;ti <N s { :Wu|9< ~AIgP "|9M.JR'B0@e Y¯_NfK<n}0ƒe :bvfgƀ1fWŪ 2 TFr:ciŃXFF?6yyyyJ7sW. 27dpSE0j I+&7w5ЄRLwa8[m*%ky9$dc@5Vq|JH-KCLI3;~ZVdlPXuY!֔r@ު1VZ]H+c3 Zq_ȃNn]. UX%kFrCܐUPFUL.5b:l#'rE v$aQtU$?zrMoVه*X&><n7:⃳ug~~~> z!Cj>PE<Մ&3U$n#t:M|uu{ }ff<$rCVf#IJS"r|aZ*¸kߟu[03FT%V0$X{`IRfBt:L^H5~',' Wu| xh2Z=1QM2d6e-%w2 ~F)w㳶`v>؄]!8϶S[;fHH D5j4d_9޴QIٖS^ b *n0ͦC_4t[+1U$DLh ^=Hķe;Lr5#4F9nR㯬 V~6#gk~.ADȶa?19 i6UHL(!L^V, SK?MߏTb\U=$*kÙ+؝hQk8V"ϟV)P~S?NmZR$ xBlaL]+C51I0*cU6b@Hu;OSHޯ3kRWk zUC `Pě:/nnnf%ߤX0ѳ>?Bc}B\Bs'ȩT9jN}RuO=$#!dcUVgQL'11 ꮑSĖؽEBrj=42컘.:8Je38<<Ǵ,ciZ>2)fv)3WqoM..;<gk|qCgcܴ_~ͺڪT~1N1GLHAΠSL06~Sө?]y-\jxE,Vz_ s?<<ۮGY r=Rt5SWb\.;:;%t]*?le&UT۪ "a {T Ə{ȇ8HUSM}g0 |Ub\;A9/(qen} a&hG4O,I7p)-x^ \$[57%ؾ w#ʸ\ iYBym/_Tʌx9h=~s8Z XsұM[ ?4iZ헙RS$Twbq3&!p%1q8NVPfqnLuۘ \89ixNSVLnDA\ 8؍Iۜ_Z^B1GM2 28-F06j:g&' xF:5VUL'ؼo51MoxVb 拏&jJ͔t:?~gA.)7ZX.m6Ur/~  M "C<C(s`L똴@*OS蚳yJM`gX=8&vA|Gg=ɅyN;s &1qa}V9zr}1Ϯ2qG8) Zf{o}TIstS7gm,x9$`i}ԎtkYː/qi20aVbQ5#Wf衇jo;U)Fr]ҷSuliM 0<<6P sOIXj<,Uxb`qN*IngaR^Hbk':.,F>1 sIWĐ/=}]f3sdq6XB'֧Үf)릃}$hk!zPSH>'z۝aS^'Ve\4Ѻ 9QpacZh@~\*f nfґV1vg'&5?z[uM\X]%T':'0`TvT4786/UHXGN,)ooo;N3Mv[edxQZǥ|i)VE>S:ǐR(<B)81iJл&',Zї[cfKѯ}3ta5"vA2ar|G6 GjU0Ѭ(O0 Kӳ&004I.ϐ֍cbu6(lH/֊W 0G4 &=777m^ v?jBN-̎xJ\$r ^8B솝i%)XQNo2qɬVtA;7n׹V3I91C&Tp9h'Msx8V,nT">Up)G9ȉ'RYvYVYH<=7=ϬÜ |IebGs< JP0wUDei/|cbX*qBZ͕t}"]I%r=Ps<,Nx[C=I$_dSӪQ-nij$XGUfa|}}V#!ֽT8sLGAsz_NuQrG___ĜSNQ>߮ ) 2fJJӐcfvLa*NTiڨ@kC]\Ċt]mâ?Ǜ;3`|36[?<I~%˔ s6%|&z.UN tsrSuL9D IDAT\ <1c *WJ8ttV'EZ0)&↟x11Wd Y`:PRf[ϳhhL% ȟ{)_l[3*[x6wuqwx䎃J2XQ@s;P;`b7[pdT8rΊgVLhj+UT%iވ I#yxւc(. ^>wd- uv`3Ѽ8;sYlӓȖWOfj}f:jgQOo J{1fuB^UvbN'ٖfUs&ĺ%"PC]Ӝ(z>qSkD\˨bl!t;"RXvYlaVNfiͦLWPŖbG5"ॲbsTjc\{SHx{{#%NhrFJL[,7Vܙ pՠZFQ.xCeCY ^X\3 Yc 9ή~Ɓ/WzM&_4mϮ 3f#WCu)fB܎XȬVYMfVѨGMJbvT1553¸9I͠Tk`1(| [A+e:4 =8{OAn5%]+RkAR;;5H?weЃ\ͩ t Mr&h,* ȪP"cTCQE5cdMiyBy%Z1c p\rbZlܘS"kTq-A9 67͌S#w虙Ub,Y+v}];8%/);h83&#"ja[y〈T`cd:nUDx5ϧda⊪`?]bօell sͶ.<˳UP̺\>??lU`ϋDI4/S\i\ufymbO^^^f}Baݙ_K9EO3碂23L6n4M%pğM~p:5ȘK=k!TeD5,bZ f_F|~~Ǚk@ш>*R@AaluCT zm-/3 M EΩ<<4<-fxguNث(.Mf@{L 0ĩ񤯃31RPOwi2ҥ9s8":q!oP5{\.s0hO>5$zY C%as'+aVδD&:Wz^Ǐ3Sꤹ^qn$_O})HlQU{ĠL:5`-Va>JZT2WͤZ?߹/7}7kvv {Yċ+N4qLb~o3XI&M66ʑbF h%,T㐍1U!v,=3cCvŅgƋbsSsb.xĬ$R57 /.atwPMeV,P<8,Ci%;Vjʪ8iM &bh~(sHO( 2ŋoK4-:b||f Hzt궗@$Wv}Y rPX̨s|8vT^,#j1٫>EqekJM#j>>B:Nl]i;9U̺)%T|c4;%iLq% )ΡS"2UhVUd?h/F6%s^n"d藧ה9l.!z$#"S0maizOB뎱|Fo&% L7wjT m\+j8E's4$֮=jȿ9"̈e:q&.a\V ؑo&}$% =ƅ"Z2Qu۵)VqNbW;g:Ud>AROz~~@c'!cR ^rˬu{?}=E0rӦ^@̄E1g$V閪M]'T$G PmoelB*I ^^^Q8eg€f<*V9YO݈WI WH[TMȭN y8ڞO??71([SJ5d92MTrdCVt$j?7b2*+r>*qy2[d 5ڲU%6&] PI+Y+4&bCܟ8UT~ߚ߉V5 jg|A渎|n9/&M*n447M%R@_g?K+=c,P~ZO؂|IU+dBH 8(RQFc)p#P ?bǪϢK  ??.ȘKw2Ӭrv]FIqh&x Ɂl%+ՎM-QUGG߇])0E~Hfդ;J ?RcdUyUw%jb"fX,{5̧-7;4Y9g tTlȻ RB8#2 "{nbTڧ={v)?c4 &F=I:A%;21D@B9a!V#o d>^ﯘޗW/I}+ҘjՐ*ٹip2;}ؐwWiYa[,mb7BѨ8KTW} I5&*Lc,?g!TZ ~Y,b-,i|)u2t_8+2qn]rˣ[*erRw+H"{mX2k6cQsBX%蔎U J`e^kM2тcgzT#ֱCz||lwwwm^w_%X<͙kooo=x YwĂ& Nc\0{,hi8i)m02r+FhfP>l?tI~4OYB7$e㠨BnD~&D"js#neT#&8匫ш`hgsF.;:ߧZ{yy`\XY.}>fˢA$ '"oXPD,TXSԬrcQA- 7:YЕji> >uDh+"2{7b/RbTYbI8NFy)Mz0t샛-z^Ln}췍$a?XMK4%F/'.\.gTq37 =uRˊ+šgh٧fIkl/e>^JiH88)[éWm%TcT}U5K2,"E1؊힢Gw֑ Rˋ)?nnn~z9ivVcJ y|ӑn2y Ns)T'յ jY򳉵0c0tDJm8gK5kl G5ЌHMǝtҵQZU HG l~+1ҚUL̎_Xe`xnVq}+ cA#GSI(jMPPRS+3%0edP.1@F%Zpa.tŘ\YUX4~Vonood^ҌHiN摅~xx wt|(RMb-LwN$|`iVU]eA^EM|Z)3k_R\Uij]S\jHβo-a]^__#D[)фWDWJ!Yޯ6XV 9ʳGE1ټ$?}fky C,ƈ0 y`,\ yʜ[LblmI) 2\rUs(>W8?c+^,l6ѐiefZyGu$EM1Lc!T*>h/IUTY Ttf~_z?+YN?+nFKÂN0>pVY ښua3U`{ ׯnuH4M ~L21./lTcq @?1tٗ:f;q ֱDrdM; `GU$ٖo0bSWX9IHs4d*~cY fWeaJU.&^oY"oXifWo6% xC)s+L%|~6咹gJ-a֢r~06k0kЪB4U;A[ L TXSrShl,Ɗh iiM"FsØRzY:o-Dz=2Gϒf)(4_& b(&3 p mR}0M)e_u0nx^__w?,r}gD5Hʥ~$Y7-ld/}YVkxY1 ,M$LB'kktJ[^__{ v-tղezVAը"x6DŒ‒Q%IDATj(Az,=r8[򹩎c60)#D5`5 K" >|?fNJu;ݯ:3IV߇-0{YHu)K񷦧Wq%=zݞfn߷qN3,irG {݈ȨdZ4% > [p}G4 xamFӸ(nyشnYohE*.Deϧ5mt֞rg\c/q3SZYJlK 7ДM6i_wwwD~hNYP*⦊`jxc d u.Y.Z)Xfb&\p&Ǽ[ޮb=hHr|DszN8'VqݝdiTvY#[~ y " IENDB`chessx-1.0.0/src/gui/copydialog.cpp000644 001750 001750 00000003675 12223260306 020031 0ustar00niklasniklas000000 000000 /*************************************************************************** * CopyDialog - dialog to choose target database when copying games * * copyright : (C) 2007 Michal Rudolf * ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "copydialog.h" CopyDialog::CopyDialog(QWidget * parent, Qt::WindowFlags f) : QDialog(parent, f) { ui.setupUi(this); connect(ui.databaseList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), SLOT(accept())); } CopyDialog::~CopyDialog() { } void CopyDialog::setDatabases(const QStringList& databases) { ui.databaseList->clear(); ui.databaseList->addItems(databases); ui.databaseList->setCurrentRow(0); } int CopyDialog::getDatabase() const { return ui.databaseList->currentRow(); } void CopyDialog::setMode(SrcMode mode) { switch(mode) { case SingleGame: ui.singleButton->setChecked(true); break; case Filter: ui.filterButton->setChecked(true); break; case AllGames: ui.allButton->setChecked(true); break; } } int CopyDialog::getMode() const { if(ui.singleButton->isChecked()) { return SingleGame; } else if(ui.filterButton->isChecked()) { return Filter; } else { return AllGames; } } chessx-1.0.0/data/images/setup_board.png000644 001750 001750 00000033717 12144234760 021022 0ustar00niklasniklas000000 000000 PNG  IHDR>a IDATxYp\y& db+q1EK%z\#UVjG[mwc+Є예?ypyTSU]S\lH*@kgs.ys38y{9 l6m6m6m6m6m6m6m6m6m6m6m6m6m/'GoDQb&$ $\.\.s.\3K_׉(իWׯ+<>M9F<ϳ|>/nb$=، xw^{ǯ?O,R Ƙ.i45{zz_|1:rt6(c+/###~]/_Qgi4ϯ-LMM ?h2rlb1D޽{,foo/+JX,|>?_=(K:u wslr~իW._|ƍ7ndFiww)988haEc G}J${FGG{@}R-S?OG'''_p!늢(ݻwSEQAF)> ;RӧIP%__??͘j_R-N/R/^I&+c:MeY6MEQXWW+˼T*|>?~i۷իWm49gBa>JNLL{sss+WQJ5Xb1I 34y6lccc@Xܹs$'''/}7t?[o5<33s… t:Q`Ȳl@Ce!fdW*L?֠x }駑sΝw^|Gf90 :===qk׮]x Jishh&::X4Qd0|ƍ  > 原gң~Лo/.,/l@h<(.8ghj?:ܹsG}_/kM$aٟd+߫Ddp997)jT\[[[J%/-. RT>$IL"09WU'|Ia||۩@' L6>6Ɯwyd6Sښ\TB'R<xTr'9ǵkBX" +~Y[<{UDڎ8y uιAK7ƗGfggn2ƆFb>0C[nG&~WUB;'p8񨞥y ;fx5VZ뾍ck4z:eFFq7 ­J!78{,Y^^c??HqCw0ƼO 1M [8f-W{(jRwVEQ:t̤|.g@@={7_p4a&(_%Icc#`8 Z_X+E{;;Z8c4(iBpyannN&/w@a݌1PJ:TUZ.YQLVr` f!Ez)T*AeHQ!A I L ^mU\Famm-@ p(I8;;x} _xa^ƗeWgQY7}O8 8WY6eEV I@laLZͤkZd@ٙRT``PO ccc(m?PEa; @\Fv& ,,bv9$$XD@V/Oc%jG "+EA=-pR Ll;=mF}wB8g@@9G%It:o~SN}a;5MCTDzf@$ AADs93BuiR|: 6ʽmEђ"^g{Uv3aFS+*Rezz:cX'ABiB49'> "QC Q:LC!$0!K"B YEfDIvA#3h<ѾvDQ̭|> &?N߿ہ^3Ƹa(X|A!|A.~dVݻз(n*`KQ2D@,Dv}AXuEuODZ1hXL1X `HDH&??='ӵsN)%r7SЗA @ \򇈨 H;` DIukxrnRdr DA(@ kܖk5|s(! d29  <|3!lVRU5ӳA!t]G.Aq}H AG "a[s9C$WDA"&c09c"@f 99 EQ J"AMwDh>· t i׮]߿و_XaT*!;{Z]C "aHJֳ$ۦ8Ƙ &aIaPj `d YC$Qz^D"eOf M Jy;o%yDI`uPZ.@4:QKǠe^w&sLP_]7U7p:whd2ys صku]T*g/`'jPֱƵHxt$:![Z]7HC0NMAIbas[L]=g{ >9` >Ān@h|SU-A8ysV&YDo$rIT*o#]6`SAcX PdKeB(LGEd(@}ed[S^;c5g.(hPQkLӄ,K`Zq5]͍Ck&xtC8<7}&&RgB"`}$ɦiWQfm9oAdBq㺆MCvx]߆ZpC% 1,2`'T 0gV~;Fzߊb!?tSja&K P &v$@ #eA"_7(]4Xh`aԁxi |``ha5XF6X#A 8{d'|JKYR4\42޶&qcfffX,EMp|>px[Zw+&Pl&%yu1nD(Be~0vv `{*jg#~ X ]7j1e7;߇Ã5`]EieԼg[ͱX(,J9=Hb(ro<0jDU}i Mp$Y!c#$ fbgO;$QGs(T48q)Pd9{5/5ͮrԤnZؑOe y0V췊QL4kEw%>,(H/BD\l7P잏ͷWԌ~TDH.(۰J:gήf@W _$= \[[ V T%g^(-ݾjџ @\F*Jz?5%={ZHߎ\[Yɲq%F5, 8_wv[k F{f/$ ~#N*>g.\X eɩ7 ÁHĂ56pmbsKza ɐeH[ƇcٍZ sx &@.drm?peE^_mR0.Hd֏k|qZ#z"IyÕ@Jy$'Js%t. B~>B=q O.adjٕ޽OlY A K2|>Ӑ6ơ3`Y SDKDݯ-Ⱔ,:ng'~9CI?_>DQD$A$A?X\dr iG3 WWWCCj,Q)׎z-; v&R $K|_9٩8*vtkn22!`et BO#?$f!V( B$,,,NImp]淾nk"5Z(5jkUm 8M ,n_êw 88|*rg<']Lp[9g W7ɽEJv뷺(>(JK 766pUG,3{iS ӤRP~_޽?8YjQ_] |7L@+u> LNqi~$ tvܚא-TbP>f]ty &\q2O/>0Wj0N ''''؝Fi(8IDAT n-h緾#jBgIUӮ=<)BBWW$I(h'YI,"!!HPd$VHGkfvRSֱ+dEyml֞MGpba||[NSKݻY1/vwTes1e07mnm/P.`ua8y;mE$\u#>~ (X$wHzj!憃<2 2([A&dfyyy@0nݺooo淾-,v9h`T1 ԍk{D sNkΠt0Jw:F IRu^ZC "Y?‘I-~e4C_7}0nɨߊoPf {T i8rDQa(0֒`W5-,U` lb7a(u5.J1;s?/5$-_7^I3\#:J=DBѣAEp- iѾrL8,1!/P(UUq,P5`!!^S ;/^(2 I];ҽFc3z]Nn>Mam|0MZ8sp #ؽvĽRsT4W\B,RT\^Cm(iѣG}mm˖P /8wZ7:xGGtvvvRm6Nt (N!AQYCPj$ヲi'''PwR EI={3g@ERu]Z[m.1=& >ϸzF$khnq caPP̮T*6WN4#ǏY_z鷿SRdccКhLx@S{f W `vڴDM}  (e*04RhT*ŷV@EUO?쁡缌[Ui0cl9^78Tt]šC(ԮCLmEZF~B-@4d=C&_SԀV\#(0Q7  J0(UcҤ{ׁ5hWZ&m;qDB "\yqgntkֺ CG:R?`@UUR򕯾800p}G 7Ol&BhZIZ ib}#?ᔯ 7eRG[zŊd-D `ttԙ_ݒBA MLF <@5 ZIHǻ_*8v4ʺ㠂] nVh?wU5Ȓ9fW$ov^ܓA#O~Q*a3 έ8k빭6,nXmx״N*s6Xc9ጛpqA,< q+1. {m:MȻ?qwÜsOͭp%}>e{~Xׯ_O^9iښz…ᅅT$) JnT%mն;mp@XZ\*?K:::O 9?oMAAD"$ld0n}-[e #\ӽ~3r !ȉ}M+S YI|Q2k&hȲt6!d2I^& X{0Ƙ$I*tcuu[o[oH$<̙3GO8-Y!?8RlrgI;I]%Dݨ_hac@-Sd wnX}>PFG';QL{2>r% 2$IUXhr1.]tҥK)~gϞ=zĉk]|qXС*ndM*<%c.*9`9x@ɹUm$ Hέ0ˠaj3ރ(]눂j2\Ŭ=ukE@b'F| T*Uݿ&ຮVdu]L\Ro̙3OGv FTTaa5W}&/}H$D"M+1:::UM A$QCxvvvzvvꫯ?vء3g}~{B$>q[#WZXL B5:Z |># 2,ʪ K""ANF٥ ,I  vƱ sl輛vϑDzDp,7xt'"D,l\BYfP0!"ѐ ,Ut O.ar!ݰ@|m}ڹ===hoowKi9HRT}=~e^0PXȫC,0`! #/^L^xg~?~=O~رc@@e`pVڮ-{сb B 202;>Ha5)T+S.tBEIBG[s`c#_4f7YƵ@ s @OObEiXظ,z7t'CA5БªF'?T}```S>}zhݽ`PR>ź<,lyܪٯzWe2)J>Yb~C^;}yawBȭVrD$Q`w:,ȗ-@Wr(Iع <#ƍ^%b@ FU,j78" zdzzzrzzW^y%'O:v`8+Oj9l ٳa46s]; R.ahWu|T"W| O.A ~VqU "H':={{nCѨ"{dҴί~SJΫ ,Po7gGyX(8vЙ3g:th;OF V6( 4Y J>'sEQD @"pS0)B `8GXѫ/~SLj "б ]`]صkVc{dL&kkksu=_ i*JpX\tiҥKSN>}POOO{ Y&~e7n\.w7]]]n/" @rQ] g;lGw?z100tww ~4&&&&t]ϠV@^U,D[@@FիWo?GW\XYY)p`0&,K6r#^ ę)( /Jj'YkToz}qDH5{Ν;ݍX,@ Oȷ|.\W^y', 鸏xh;œ'Z[<>yӧOFCa-GQ+rsgц@ p8vFv}<: l=`@!(AH8B;сNo"@4E(,MžCJTh}yaK *Bi֢΍wy'H$z<'< /GQ1 6 "+ߏh4d2dvPȣ\Cae0?-+H $?0p8h4v HPNo真ؔa˙[zyDv",@8o:@ ?qľgy39j)K)]OK|IW^?X:ˑ`0Jf?<<_T*u忁mptvC@x~~~z~~~cp8q__;rp8,8vÝ,v;2Mөs~'UlF^׳pCdu]_{wG^+?ϧ*@3MSPk[ Q,83fQ]_#,O* M7o޼u…/k&m|(L_>22,n?˶x*i倡&i9Ϭ-^|9k}+\I&|(9m7:y >^}wVWWa%ɟz@krL Ljr7bztttß|L&CA2dƘJ}]7|Uug"s54l.Jk~O/^8XE1 IRPuD 0??7xc?|G?0<Ǚy 'i M`ܤ(={xg~s:qDo"Aᥗ^ѥKVgt^b >)BW{ϝ;wڻwoK//,,|`@y`ym MPC/|>L)]AW28,"'b1q}mzxԬ%h V׌Miյ|pr۴M۴M۴M۴M۴M۴M' -IENDB`chessx-1.0.0/src/guess/error.h000644 001750 001750 00000003572 12223260306 017033 0ustar00niklasniklas000000 000000 /////////////////////////////////////////////////////////////////////////// // // FILE: error.h // Error codes // // Part of: Scid (Shane's Chess Information Database) // Version: 1.6 // // Notice: Copyright (c) 1999 Shane Hudson. all rights reserved. // // Author: Shane Hudson (sgh@users.sourceforge.net) // /////////////////////////////////////////////////////////////////////////// #ifndef SCID_ERROR_H #define SCID_ERROR_H namespace Guess { typedef unsigned short errorT; const errorT OK = 0, // General Error ERROR_General = 1, // File I/O ERROR_FileOpen = 101, ERROR_FileWrite = 102, ERROR_FileRead = 103, ERROR_FileSeek = 104, ERROR_BadMagic = 105, ERROR_FileNotOpen = 106, ERROR_FileInUse = 107, ERROR_FileMode = 108, ERROR_FileVersion = 109, ERROR_OldScidVersion = 110, // Memory Allocation, corrupt data ERROR_MallocFailed = 151, ERROR_CorruptData = 152, ERROR_Corrupt = 152, // NameBase, Index errors ERROR_NameBaseFull = 201, ERROR_Full = 201, ERROR_NameNotFound = 202, ERROR_NotFound = 202, ERROR_NameExists = 203, ERROR_Exists = 203, ERROR_NameBaseEmpty = 204, ERROR_Empty = 204, ERROR_NoMatchFound = 205, ERROR_IndexFull = 251, // Position errors ERROR_InvalidFEN = 301, ERROR_InvalidMove = 302, ERROR_PieceCount = 303, // Game Errors ERROR_Game = 400, ERROR_EndOfMoveList = 401, ERROR_StartOfMoveList = 402, ERROR_NoVariation = 403, ERROR_EmptyVariation = 404, ERROR_VariationLimit = 405, ERROR_Decode = 406, ERROR_GameFull = 407, // Scan Errors ERROR_PGNTag = 501, // Buffer errors ERROR_BufferFull = 601, ERROR_BufferRead = 602; } // End namespace Guess #endif // #ifdef SCID_ERROR_H /////////////////////////////////////////////////////////////////////////// // EOF: error.h /////////////////////////////////////////////////////////////////////////// chessx-1.0.0/src/gui/boardtheme.cpp000644 001750 001750 00000020157 12223260306 020003 0ustar00niklasniklas000000 000000 /*************************************************************************** BoardTheme - graphics theme for BoardView ------------------- begin : nie sie 21 2005 copyright : (C) 2005 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "boardtheme.h" #include "settings.h" #include "messagedialog.h" #include BoardTheme::BoardTheme() {} BoardTheme::~BoardTheme() {} const QPixmap& BoardTheme::piece(Piece p) const { return m_piece[p]; } const QPixmap& BoardTheme::square(bool dark) const { return m_square[dark ? 1 : 0]; } const QPixmap& BoardTheme::originalPiece(Piece p) const { return m_originalPiece[p]; } const QPixmap& BoardTheme::originalSquare(bool dark) const { return m_originalSquare[dark ? 1 : 0]; } QString BoardTheme::pieceThemeName() const { int start = m_pieceFilename.lastIndexOf('/') + 1; return m_pieceFilename.mid(start + 1, m_pieceFilename.length() - start - 4); } QString BoardTheme::boardThemeName() const { int start = m_boardFilename.lastIndexOf('/') + 1; return m_boardFilename.mid(start + 1, m_pieceFilename.length() - start - 4); } bool BoardTheme::isValid() const { return !m_pieceFilename.isNull(); } bool BoardTheme::loadPieces(const QString& pieces, int effect) { QString effectPath; if(effect == Outline) { effectPath = "outline"; } else if(effect == Shadow) { effectPath = "shadow"; } QString themePath = QString("%1/%2/%3.png").arg(themeDirectory()).arg(effectPath).arg(pieces); QPixmap big; if(!big.load(themePath) || big.width() < 160) { return false; } int realsize = big.height() / 2; if(realsize != big.width() / 6) { return false; } /* Cut big theme bitmap into separate pieces */ m_originalPiece[WhiteRook] = big.copy(0 * realsize, 0, realsize, realsize); m_originalPiece[WhiteKnight] = big.copy(1 * realsize, 0, realsize, realsize); m_originalPiece[WhiteBishop] = big.copy(2 * realsize, 0, realsize, realsize); m_originalPiece[WhiteQueen] = big.copy(3 * realsize, 0, realsize, realsize); m_originalPiece[WhiteKing] = big.copy(4 * realsize, 0, realsize, realsize); m_originalPiece[WhitePawn] = big.copy(5 * realsize, 0, realsize, realsize); m_originalPiece[BlackRook] = big.copy(0 * realsize, realsize, realsize, realsize); m_originalPiece[BlackKnight] = big.copy(1 * realsize, realsize, realsize, realsize); m_originalPiece[BlackBishop] = big.copy(2 * realsize, realsize, realsize, realsize); m_originalPiece[BlackQueen] = big.copy(3 * realsize, realsize, realsize, realsize); m_originalPiece[BlackKing] = big.copy(4 * realsize, realsize, realsize, realsize); m_originalPiece[BlackPawn] = big.copy(5 * realsize, realsize, realsize, realsize); m_pieceFilename = themePath; if(size().isEmpty()) { setSize(QSize(realsize, realsize)); } else { setSize(size()); } return true; } bool BoardTheme::loadBoard(const QString& board) { if(board.isEmpty()) { m_boardFilename = board; updateSquares(); return true; } QString themePath = QString("%1/%2.png").arg(boardDirectory()).arg(board); QPixmap big; if(!big.load(themePath)) { return false; } int realsize = big.height() / 2; if(realsize != big.width()) { return false; } m_originalSquare[0] = big.copy(0, 0, realsize, realsize); m_originalSquare[1] = big.copy(0, realsize, realsize, realsize); m_boardFilename = themePath; updateSquares(); return true; } void BoardTheme::configure() { AppSettings->beginGroup("/Board/"); setColor(BoardTheme::LightSquare, AppSettings->getValue("lightColor").value()); setColor(BoardTheme::DarkSquare, AppSettings->getValue("darkColor").value()); setColor(BoardTheme::Highlight, AppSettings->getValue("highlightColor").value()); setColor(BoardTheme::Frame, AppSettings->getValue("frameColor").value()); setColor(BoardTheme::CurrentMove, AppSettings->getValue("currentMoveColor").value()); QString pieceTheme = AppSettings->getValue("pieceTheme").toString(); int pieceEffect = AppSettings->getValue("pieceEffect").toInt(); QString boardTheme = AppSettings->getValue("boardTheme").toString(); AppSettings->endGroup(); if(!loadPieces(pieceTheme, pieceEffect) && !loadPieces(pieceTheme, Plain) && !loadPieces("merida", Plain)) { MessageDialog::error(tr("Cannot find piece data.\nPlease check your installation.")); } loadBoard(boardTheme); } QSize BoardTheme::size() const { return m_size; } QPoint BoardTheme::pieceCenter() const { return QPoint(m_size.width() / 2, m_size.height() / 2); } QRect BoardTheme::rect() const { return QRect(QPoint(0, 0), m_size); } void BoardTheme::setSize(const QSize& value) { if(!isValid()) { return; } m_size = value; for(int i = 1; i < ConstPieceTypes; i++) { m_piece[i] = m_originalPiece[i].scaled(m_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } updateSquares(); } void BoardTheme::updateSquares() { if(!isValid()) { return; } bool scale = m_size.width() > m_originalPiece[WhiteRook].width() || m_size.height() > m_originalPiece[WhiteRook].height() || m_size.width() < 30 || m_size.height() < 30; if(isBoardPlain()) { m_square[0] = QPixmap(m_size); m_square[0].fill(color(LightSquare).rgb()); m_square[1] = QPixmap(m_size); m_square[1].fill(color(DarkSquare).rgb()); } else if(scale) { m_square[0] = m_originalSquare[0].scaled(size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); m_square[1] = m_originalSquare[1].scaled(size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } else { m_square[0] = m_originalSquare[0].copy(rect()); m_square[1] = m_originalSquare[1].copy(rect()); } } QString BoardTheme::themeDirectory() const { QString path = AppSettings->dataPath() + "/themes"; if(QFile::exists(path)) { return path; } else { return QString(":/themes"); } } QString BoardTheme::boardDirectory() const { QString path = AppSettings->dataPath() + "/themes/boards"; if(QFile::exists(path)) { return path; } else { return QString(":/themes/boards"); } } bool BoardTheme::isBoardPlain() const { return m_boardFilename.isEmpty(); } void BoardTheme::setColor(ColorRole role, const QColor& value) { m_colors[role] = value; if(role == LightSquare || role == DarkSquare) { updateSquares(); } } QColor BoardTheme::color(ColorRole role) const { return m_colors[role]; } void BoardTheme::setEnabled(bool enabled) { if(enabled) { AppSettings->beginGroup("/Board/"); setColor(BoardTheme::LightSquare, AppSettings->getValue("lightColor").value()); setColor(BoardTheme::DarkSquare, AppSettings->getValue("darkColor").value()); QString boardTheme = AppSettings->getValue("boardTheme").toString(); AppSettings->endGroup(); loadBoard(boardTheme); } else { setColor(BoardTheme::LightSquare, QColor(Qt::lightGray)); setColor(BoardTheme::DarkSquare, QColor(Qt::darkGray)); loadBoard(QString()); } } chessx-1.0.0/data/themes/boards/aluminium.png000644 001750 001750 00000225617 10633750627 022015 0ustar00niklasniklas000000 000000 PNG  IHDR/ pHYs  tIME %9! IDATxt}$ɍ-h {2)*gTf2ro\URsk ~n6;۟b&Ycq 僉ߤV .P,Ə' ,~J"U71>"ԋ x625i.XO QC%D*I&%dF|a8jX~܈v2!x"˟x=1I.?Ũwa p"x޵D|*) 10[`s<-"kY0.džV5?go$?3?[7m~~pqHMDkŁH"z?$$Ip &/ʱsAB]U_n@ >?k7}V'=:6B^{ ߐn[O{+oG7C3{?86\$zy6X {17w\lAYQX qVEuC_yh~ɛ7@L]yAGpaaf^btT .ұ&oUlGYCp3SB+DBmB6W<$]_{~@i 3Y>,~zެ,PFM$V].QTeYD̅?*SVS 8˘~USzw|FQԟ7xDq=84HHi-aQj^Yz] N<6-[Vib~ś*i,uKfZ/z~r%7r_+U-*DV*s!"z FlEeETiwI'72M[VߡR\]{"+GLD{=FֽB.cd#QbEeX 8?T_={Z?f;wl<蕰Vm(53zᕳDXX%hݪtͳ澙ͪ`7GQa]qk1Ԡٰ`koJJ[ &U9b6J0HEg7a.{d~.AUf +[o<ܺ:%6;W~>i}7l,Ĵ7e%D'%ok]o}qRLD&p^k (%j cF*ysY"D$ޑIob_J:R^ȳ/)HJczIUVYRMV .|0,{Jv|P7?;ڑ{U7D-ļH,wHT_ 孚;hPFmZʒ ˱ޏB,w|<$o5!=c4Cf1zi?PãN DRy6N' OJ %7Mġl$/ouDio$4?fÉHXZj/{6(^\,*NjrU(r %bL$:HB2#%UN͖P x/zZUv_~P(óZW2J<=Ͻ(.lH gG[8|0xeF7{,xf/BhWz}%kRq$XPTqN‘7YT;_ S3m5uE,@\ԛu3\/sNh{PZ6٢ ܴV7jqBw9We؀y:o1:qW[~|bqZǰ-d?swq%n PƉ` 661 m& c0f>Ve]/ނUlawϙ5Bk.[\y(52gqޤQY\vl|sgsA_H!|q Q&45ud-+f_5Sce0#!bgyQW\eC=ud&Z8Eo|1QRz_YO)tӒ+N ҧB0'᪒/w4`\xQfRQQ:A90kn\H 7`5sO@Jg Q=O Yqdc#I=C=}'3h~Xv;#Z`UO{|0xgt nV=8UufB=ShAw< w7e6w;q8)j^;P%5{QrIK,&T-!"HJ }*}{YVI C&gq3dS[?Lag']=$ <ƻI ZDHc`ٵSio¬QӀ/lz'GD̳'{ePʍgDV/ q15# j.ccU*8FތubE[їyװ[^\5ae<'tc }VBsTlfq{F׬$"l0:ilV#@e+}70-$}B=_ru;uW/ݴ$jܗI\%߄-E1\/r΅AO;k} Pm wMR뇈1}bZ6|69쓾~9y臘̖*?[-/;~=xrtQس4J1{ՠ;(AS 3INZ`EF*H)yo[/1S!}ڲ7F <`2Wc 1@(!)svamh_0=]1Uvяc] -<%VuwCͼ˪0x$%@f4sшzXoW6"0m;Zmc͹c3"Z%SV)wwL`B-p浂if-_ P$ј/yN-Fhph$㴚u`SX^TE?$U٦PE^^^}oFЈ~$XW>kXp:/{[(6X[Fc-NZо5ТE 5"z/Lݘ!ad_,$: cX 8E.Y !H_DVAY|~>Ě ަVqEKFvla2_ݪ1 :WNu OZr}b~>@&/ii@R-w}A6zK fC|`P*|&k9i ˫-ho}lKjXY@7u3!vmR74҅Xc,ҥJ)gKK.5jأqzԆo<7FP0˸jF}pBѫk]+~&e?Vײ0>}`Ox[[cőP uL7m3 gYtA)"gBߘDn^l9yw&`JlMdq$ܶ嵵F\>)2| {x~.Ҹ7f]ؾjAbE;i #5f5<6O$ڟ]wHm$Y'JmOv*QfAcXc(@JI UVHl*?,-CqC9U>vQvH=d颺-=x7|MI­? N:am!,`ꙿsD{.~:Ȋ$u)}rs]!7IهVYr?ahӦE>_J̗B[Nk6ڼU w0s&e#k1B*MWı[͆}ՙfCo2DZ"d۪<} Z5`Sv DX,k5├>tFJT7Ȓk4t& P`R%4}ѫ~R0"$u"3Ydhq;Ѐ+,"Fʱ|I®.{@2oUzS['cz:@~_trv:FV_[ M4"%7iRDO-@Cw=DBfDgzaMS'N(eZ670P`9׃&?IOd2b 6> zJhm)<0Ni>ԵD @ڙ%R $#{Hz@&CN3U a1Qm `@ ВMl J40i5"D̓ 7jFC7M6M VqTT9G(DItgfT$лÙXr~2בBF. * 2~ъ:8xi=`E%EO2FwEG싺䜪Pߵ9<l(a 0D6E@>z:#Rs>MݱY+ <4*k2rW0275'ypS.H|XfzYqϡДc-GIEܛ4iέ;;a&E!MZiL1Znj~[([;n&tC! 8Ɇc#aD-Oρ!gIDţ hEMwMh*q(fˑ-(#W`@ DGpOn* 40 S׊^yh`dnsc{jFCgF&jr* $M74$Pe2ɟ4hGdŦ/#5} xW0SoLGR}e"&L何`KFY;bCN\Nw{;[ˆQZ# }7lHOy&,:J12)7!@"hǟ[! ?I{GVp$oI "o4eCOdIMo74GVP "t)jZf^ xm+K6CF 2pV9e@hbʺ9ihLGvcIr|>LD5zT e0Q|q9zLd[񴅒OUĽtلLu^$rIOr%_)Dy)N?L éenI= -j{M w&dJ O=-'%-PEfo? jo c@ O~^}4ƚ]0C; ]R&Oo2"&s8KN%# qڪ%8M!C:y-þaaO@þ(ҩfrnI}'ug6( ď%Pc_s;SvA;3ʌ*]+yV<f(f-~a:ۅF6f9aF_BMIܫ%kS\;-E|Y'nF{>"u:}!b m}){4u)B% =5Nۦ@}zC={A,qbaǬg'dY6=~Gw[\o>QRnpAUrJyះ޸xvp's[lL%]^'|5%Xg`0$_L&>/ ME4S6{h kN*ͦ8Nj wreuT_d>E'4'PA* ,Rt%LnVјZ"=L,z%۲hJWǷAKЭ,rfy6УEՏ2%eϼۧ0~VHq uSB9"8ڡF 5(l(Wf c"RƐEWoVb3| =M 6!ò\ !Mk̢6\yRBs ތ=@RyisN06y!^!ius 6`u3XkV*iά_;M`&.\EvӮ$ye#tRuU&;g'liݡ&DmƫM3LrjR:Y~8RzqЀ{Q&Dap[wI}plOBp|M5Tn=F.<_j0hra&q2 d6~*"1Xt}='B VP2e7魏2a6#ʾǂ!J&}q8 NM+4wB梊QVGBOM}֑tAV2N.rgP0n"yk"cVBŃAơO}g4 *hsrdcBZ͵|5EȜp'32bPS}ٵǜ{ 7&\Uf?o 9QeR]sSU1#nrMa̝!ٽH۶=zyhE::ρԅ<@tZ*mj#]+~sUM>5@6<a7(Gb\´T}0Z:7t8' y%,BII<2Q3ZRXP,!`G#a*ffv9}!^M GNJJzS h@.}fGk8V:fri0SaҒfj0p /p@MѺr O:ufip'C дT\Yj%X#6" Jt.w&k_O%z}9d q^yC`>Ӷd T3 l IDAT{0u Ko˿=Pw$ !Н8yYԃSkX&02k>8 ot*6TN ~:}5M-Z˞F<D]43iypK+ ϝ[[1i$*WöLSpYznA$tėضf6#:ԑ!*7Շ#(!̙Γg x Ʈ`cho6MI!1{a*goRzigRip@2cJ%3CMy֣_ZˣaoŞM,Qȧ&ST#h[nDzh9v!Mi T.M*WC`B%SGL;T0औdϗD ehԣMM!l--D6LA+x:yYt3ЄϕhpQ9 u1*DX>bzDI{)u/h6fS/D .dj1M$M+cj2d]Z+~䩛NB,j\>,MFKֺH#1.(B% F0Y6iؙ̛Ucug܂M^\k+KU )XpBL[B#w?jwo0(,sY2 ߘ~4VJ:e鸪- ؘґ*}l%Q,Oӓڞ+Xp 8TqI?Ya;vR%nE)3ç*t)REfJWק.UoI0LC6ּ$36{M*KPC>XDfχ +A%Cm$r)+G fv͛Q"Jʫ][;Z$k.ϛ Lw<4KD҉in4UCleyX5NMwG.V-a0C&DD^ZynjHP=rCs2.{"%v}NvDahب{VQiuM$#{kLpVJ{cqwI!g4 mep0j ?=rמ'<&U6zK=d0J͵9RϽEPڢӈ˺9oڌQYjcJ) .ipiQLц7p7OW=uwY70sL:vX}yrÎuޘ7kئNVCToPkDws9onL7180 co%'P)j\6ˡ/kpoYƤ~DSc3lgMR!kDqU`{bL:~LRq?-@9aԶ A4*8g$Bf`5]Jx@ө V;eP4:<}q#ujUژ]+&3=}Pd!`UgSJ"B:/F]< n@3J&o7_#_T%Ѓ +;`)dU  S̄.shKd .ܛVM(N dբ̧ܼBp?#!0M{Ed~a͈DwU&v5$0=9p:2\l{ߡ 1Ӱc49,\wCܜA5%6itoՇ>9mZ65ۣc7J rNjY J?z!] g"aD&eK̰6h{,#G\ֻPE*魗Ɓ)64>oƳ|q8lRaD]k \] wfRVͽyd[,7xYh }R-{]\M/` 6y<^LbCLS2)Ң .#pMLCR",FTNJ똴;< E; /BdϪ~~?¡pܺǮ؜n1 h@eQ 6bԥH[Ǜ5dnDyHnip1~Axr,rاnr $s,pV'u!ׂR; ٜЂLqjg}Q%J7gߢ@"tASAM=u΀QZQntSIw= %FzG(|5@\ur9LO l_0)˿{SI:VJ8<N0eCs+1h q:'0[+5(@\flkA# n]nխ77r?^BX.[Q[HU7(2'3˟$ֹԡ3MFnN@W갯(Z8{e iXNT%WS;˳AĂM<9+,0Xc*+x2q !jFaǒ֜ϓكC<"C֓۴An\u6&#]<ɱIh?ًl|>#.CCdt3}H;2Bǔ0@/ü ibpi;CN WblPԞݘx(֤B@BUFû-]YR7ּ4s7T HMϖpD3*8ڔ;I}FNOP5spqaq6{h8q;4[wF60 dJۓɡ`>lެ1Ձ^ )xoŠfg쪣}/AHC,4gsc&ܙ΀)uIut$Ԗs O|n\LEٻs&Ώ*]"%`G|vxS?X3a;y|;Ȝ% p /y8h)9ʢ=\3kYpl&NK\';/3 uh5qEaME"7-ʣl[*R_'3yiKJTUQI;'Zv B0rߴJ(5B| V! }niy~|%lo6cVx%oxnv ~pK&7WPo0݈,Yw TYJ1đ؃%ooXM6ϛDd`Qn+}ۈ=zH}Q TwKKBC\,Cѹr ѝeҴO}r[aKӘEAA/婀^Jpڰ/EԬ?nu@{}'S[n36ɰ3tRrZt5EWǐ*N^L恶֦`Ҫ}V$n!Ģtd3p:D+c8Yp(A =*9gv /Wre| ذd bk@AfB uKEeIk&@+w@iDkܸ>U[8\G<:?խt%b^9\ \B;9ziJ_w[ȃvMu)0:Cz@ n;#ng}xNRTk??]2V/w'nϑC{ɨ݈pɌg<,nJ@;$eɺΟKI-1ZR=A(~հH@b_ҊG*^RI$`1QOqU7%2YibNPrٚKa'9?=wY2MK DDžM7xxuL~ yt?︸T{єfP͇*Hktg);*?do%M9fꈪ5?q C ge0b},~]($D=h\h[xk#@Ynp^'>Z>pPb $Ť1 g%pxCcaYv6F0i'ֲ:zer4KFS <' 0$:2qҡU[ F/ӝҴ!K);RAsWp4%\Y[4HY0N(nEjI6?J"Jwr~ʆ+L! مgWcS=n Zv (t | 8OnѲ^Y[&h7-\{ID.Aɦ7d"nF\+LɕF Yc'19;@w3QnBLA]B)>yj KU*/t*Q}+:Y6E, jp+# E;cKּ{kt0 Z!x,Ǡ J {D%<5zmhf6=\qIojQ^ bU=9*z>x'HۅfoT `A,w|Kfئ 0;I`\HfsF|](fz=IhW?R"P43xe4#r'Mo¸O`D!!tMoG.&z((ʇ%.] ;`R "Fuq+ʘ).[j2p՚ XC07O?DJ$] 93"q-fg]&*˭2kgtD>&Z xi̼<"᲎,%f7rS0p[Bt}=Io;nrRdɸ!&zc(f|R.n291/otL" uq@dRYV47?z8IUBgYC:?P4$6D0(y!k3yٷXqM +Lv1;>HuBjRM(<|ՐfmL`hes Cp Ll[=fV1F"T8p(AnO M 3 6vlUft8Ē΂Pibh>б}=v( fМ{0Ӡ4#il8m؁1Pzh/=ȉӾQ؅${H+!R ㈣SǐEӘ--s 8c9(٧MvmNcﶛV={|(5rPݛdq75Nnz=F}Z`JI}(14K3~oǙ1=BpGߒTt!!\\zVCwnn.{LsuKYRfcNs&P!m ѽ[9@旡h?O +MIY[֡6FBN(IP*/fDkf|IgR:*/7yDYcg%j@BǑ0~Φ<WF{) gxބ=J>2X>}7b> '!ԔGo$9քw90zfT4d>a@Yl ZAKV=DI9"؃*mH-!M%qCj[S5}nsyN{[!((lh %zr[{\2v*>cS硇#!1͗a֗z9rd&ȇ68t4O.8ǵc rl#4'78N *1ɓ f^ה?oԜCa\z:KOFę<6{,y:pڬ Fry=2dɆ wZl!w"=ޤH$`b!2m-=X1)Mמ @yfk_ױDT?z4ك=08n*m1o+>iգ_ 4(Q{fw ݶhzPa--Rzƃzd bk@+"Apmz[IQJ#OO.4f|Cg|B@ AoaŜC$D.9>+IE=24O|I$!"FMh0j87$$$Rt&Mhjf$hBVNe3Cӈ(2k.T DqV!,% _ Ѝb٧>}MO_yj5q"9>8ڄjLCacHN=dj'.S#ntEX欚L@Ètatg0][I țӹT?X8šͱocGTΓR,G ?ߍYрj\6aOkEͳuG"Ta}z&5e]$H J^(,t~l*#Np򾲗؞ۭ_!Ng 0Z+~Ef3MR6p{ **ާ?+0s5=ǵeZ#/*i>dR9D_MN=LdR^KcR/=u|;wDFziAګ8`z|;W]yFdhщ]7Ƣ Y4FiMZe d԰փET9x܄s \ݺ=(<Mb`Bpq3n"egfR7];2Vtz7Hv>؟~6ͩ,喞BMB lrٗ3+GrӾRlѩ0̢+E˩lNU N \m^ֱu60Q CˑiR35rgDK{ ~EP*Ld2.o'|StBJmjF=D2rBŲI;/c(N45(u]p?&1:xP$9*'.ũ懎}%'Wtj?ʡR7hⱽ`,ӞTJ. 1Cd_!"|T&8$uFCষM[qTij#g|FW+/E|eBSZNٿ#69d\Eψq/ԇ&׿\2 vS.R.[Bu9*wEEHQ:\(tb3bRWMNj'8/iw|~nFb '_k겭;lm_H|/qh8>_M_pw`'M88hy_]1wAIRNH1b r/fbHˆU鯿Ҟ3l "7Њ윷eL^ '>/SZ]m1DƶSf?B4Xm*ݷ>^KdsFy۳#Kteö'Z+8OOB͔2<-F ƙsI)e9i3.`DIpƼB[(T_/7뤇IJqо=1hi~c;IK 2moEX]3B[p]&yʙ0O?VMFlP:gYOrIO3y"ޗ0p fNXI.|#IWHkE< >d1Q.6nO_pɌ!.H7h -Ɋy;WN5Dw{vy$_djrTDR 0JA?"ekZ{b^Bi8Zq; w￧iqZNS!5zNbQ$֔s`SGpS,"VHW)>g=׵[*. ~=j* rlB*uTHXmff5ZY\-FcɪRЂ)y!Ԛ{8ɤ>A=()x~iMN`l+Y3LW͖8g00AnR &Y/å-;=x U&5#%E>\UZ\eN>51٫Оp5_MOqSvhdr蕆遅ciY&vI4;nPck M5J5[{iݓFa& =q&B)>[oDtGs_Nv&nn(=N\Ŧ0~_@ l]i=f`I5긕ϺO5m)Ԓ3k`C1WL[~ޅи7lsɞϦa &ѣzȿ mD`ͪeB5sރ_V뗫m( 1AB TˉvtuIO΍B@M`@D[U3yo"2 xP'=ǀ-i39y-6m658[QDfBϰ!J~W۫+:_xxwIIZ_ʲ3oƌjCSwtf{{ٚg7 |M뛩+w.zG>5W4 ms0ksSe*lBO}1եXI 5.SƉ[ZpmB(b,9 ~h&(2|ʷ0kx J`hX㛏!jF SaCt%q GYK$T~4_5ާG,W--{DJ#ĉC3hlp`&)^삘FM 왤C6@'.TT6sco DKZ(X`kG3$'_*0yg=N8B~үoogyf-&3 %x? yS]h iB$Ql\VZ4 &M3SϷ;AqsJX6,"Q|6ȯt64( " qjx'-OT *6Ѯb'Uh4bF/qnb=df)h qCSUa%g-ʕ&-!ZKo,$ޓ dQ;q 6.+/YA-z$'GL\; s4k.-&ka5|&LiơZ5Qxu\-$?,Wr#阒a] ^N5Dϲan_r)f)AC_t<:0NO( GLe1r攥t?ђ6Lýf Z} pf [ ϊ}$3'`s]t9-UnTE@~d2ub8 `uP)`c4#,S|rьLgiő߰EF+)6:@X&yìVrKv| hbCϥx B7G>Oﮐ-\~L\H4{-`zg}>ZW; +mՏ%Z8Uդ_WշէMg:QI `Dpsf2Bi6îmZ?̯5E_pXL$ւL Ug~U AEyj!&bg''aر#`=XGkۈFKw"QE1Ӆ]J4tc8`Z7Wei(} $Rv"dL!4zT(K.CTY:9l9l3 hiEtXdL?RtWFk3(5oOw SJ sa# u44itOM=mr`˃:~,^hl]T3NW^sWxV7!}jSؖ^} ]p`DicZNcĮWi 8Ru]JM4  \V#g\F&́At)tq=e7DtX\?Ms$aOh.`Ku=Ch3?m{.bx YViIe]9JTb:Hֲ0еuKinmVT%ϼhNcx^xJhVx=53O.y=i麎o:g[FBيHX >˃ѤjMg1QW"ӑ{!lp']|g7 L+$rfCIL[6fŗʠf:8YⵓA>i]-fzATpF}pGT({SͰ٩ö+#3a:Nt t[cm|iQW 'XpsN_.Jtߠ'@::b/pW 4,{g78xiSD5h/} 0gh ӪV. wZ If7-7xCBD*B>25hq2hm1ͮ=M]k='P;Jl'>gasqbzWs+p®aנmԬ!BR ))WcK`b[ݞ ²o7Vق̉YjWl IDAT@ߵ8yFgbG}yΎ?PDʂ",WR>bsЭ[U;̨u!')5bEfTC7h1X'{3O3g$T H:Es/FnO(Hi9[0p+%T`-H.@앹|%fCDIv )*|p K >&KG(x}>ឃ`ZoKnr S78snO{Kk&P7/i-~LqK-G]p>|:"IQg#̴?K9tPag)!5~:B\ 5&+\$~Z[&Ē2e|ȵn@)RYLOzwK0ыt^v 8J1jd:g:VAa5#' HHf1iDNm ^o%cֵem ag)B,J=euoREC:S"ҖBi~g! -MO:31 PX>tlaAkx((-q{ap0~.ͷZ@*gc0I9IЇZa}, y;Xz+Ct?+iH 0&RǁFy/NNtLKl>i^{M7|9̋..~k"Dx2*bJ5\;󠪨Y]boX'0bt&GYm3 %c˺dIQM^Cکu$Eo "(s?5UB~e/s$p-p %N=L35l ?+0t^TfxwFENvX-d=^IOMagI@qt&BFFdTӚ([$o?+n$ZtQaW(ׄt%u) WFy 6`>Uuܟxo2ҰVAC·ťVZo>]Mbh&F!T@B$sfSV&:N}~S.G½aS7ǒ-٭X!B&'U3Yꏧ`h6`'kh܏[lfh+k{i$҇&D?Dhףϵ el/YT Bsuqo6DϘ.㔣v7'62aB0(=t}0Dh񢵂V\iK0f2M]^b`Ձ^Kqd9m6(uݵe]K݃vn{,I;@E*k7`;uKVr(gPrƘ8f")В%\yoWæ>dKV-M~~~e &<,P^lTSSﯺC{nUr NFYDW5P@ܿW</tn%')7=nhXcaY*=(Y R0^"VJdT}>=WŚ9!`^؎V]h nOuRs$CDD>RP%otT9S԰c,2ZFZ4f]W!dZ[4DtZīP *(OZ4-h#;RHbUn74P%5LD4$4 wi ߦy̪rcc3K]zY")LCuG"P1v1vYh~S% Uě3mhC~1k-ე~kxSd1S}}dJAQ~-KdV'@Rܵ mU/B HID$A,cn]R|h yR,^T -=0}CX?`e].c3JWwD$l՞{0x'ӻT!egv -%hH${WNהg/S 3(Ϣf$,j!t&U~\sx|"LRyWzhkz`K+ݻNHcyƥ{2_ ]M?lmޔE6e pj mD O)֒FҌ ,* :eկjɅ;?IBNWvL_ LM^+QsBpwiI;[^?~*'_/"}9˰<3O U`7Sul$4l=*7f%aWP FxE! B᜙znE~Kykfh8S ? Qv^߇.<7kAPpA=K'5K W7pnV%&wOHRF#I⊅PL-JGC[~ >%'ʱuoDCTopDP EŶʉbqh KtD̗;vӂۻ4dRIw&y*\it qg}Pө拑SUg[:FV"Ajͧ~]1ѩ5{bwj(H!4̒'$aV^aq꠱t蓍).xl=bKn @ |peԵ6"2CtE<<qOc,|Z`92o f4.\qq 6| QH0`攡:.Sw&z[eVRFh[:e3UJQ$UxI`w-c{ Љ'vx/ȡYicz+Z \<傸ck]tփNA5#nCYM  >zMkzrkPƲM*_&,`oi%1z Zu6= <>{N OvqhܡԪlni [WY4C;3Z|98!N2Nڧ bȿ$r$HeaϥYEF ZcAB"ʡvG}ֱ {PT6$4 %J*9O6Z H7Ĥ=⍤Iu&4DdH84d8 t%FW7Dsc̰ KJw= ~1kzb6yKթ!Rw}D"L{56s6&厍RsH)]fj*]=j{[pEmK:g(Y9%>ʪDQЗW 1嗔=No+%}pHWS$_J_A) W||](#h>u'L`bܓ)g!ӸAR,m+&Dye'8_DQCڋPuG,v&]{-;&I1i}j*)Nҟd+F(Fhb"Z|S¡io+,H1"RN. ,Xq +!:Rf5[FhQ$yRv};(ҩmB_2դĕ#)8ҚtGڐ.^ꨂvnEas,_rzbG4!OrORh*E-s<ݙx] 5e?)O9v{}3AܮafƂvD{Ѧ%WHr%bf :S]pQ8-vfNK 7T#g& 3#XR0F\1r`?{Fb{a- uJv|B$%mP* ɹ50µ\)3f0/EDIˏe>@78Bό$-N2DE/JmsfnR! XHc)5aB<(KA##H!.aVE 혙.ҒzMغ^} ` 6EC*5HB Lc&m~Wm:ݨd{{.LѯL?5굢s|Q,)WԋN HyD?@h}3/S ; Via6]+wSUCnCIN߇Fb޻>CCP+*Bv:к)<\j c|pKDH7}B1 L 3!*RFtDV v*Hy5N R}EZy=hv>CMlY%Clx!)vnR!|`hHzgzW}Ʀ5Ix5*+nqgrP:ug_#[3]f㺃pn "$!dCvDk65Q,I ']5w#?r\MЊ_kѼM]U&͹bk\5grL0N3d%+T}l|7ofx`Co Ț=;e{)7H]3GK򊧤(E(plj$)<DoUE&eHn[1kߘ;LSo޵EQr+ L -0*C4 qBuUu1??N2t{CZ.{]* 4m,_Wtrކ3WqلXRPءkߓjVlZ9J!TzXw'0צL6z3mtm,ZwZs)I HЛ{Ȍ5dPk7>b CM(СE8ZGZ'ȑ0Б]n}bziX?I$yQγi7Q5݋j3-N"W7ѽWJnUۤ8ب3.SIͿo300| Ƙ/di~}F@L#'ȱ58pXĈooZx9w,-ʲLyiZ}o!>ck}}*w [o9E4w$Үu@۠*{0;O 8zÁ &,7_KU6~i-?sƴ_g=#^s8ZUրxC^XQDI4Zx2G'FY11ƚ*iBɻm51ky>>CE`NUfuPe«܉#z fi3@wb|F]T]P*?ʹ⻁угSUp?Q+otlCJi53Tͦ؀OzF-Y$(&wqMe;uZ9|pm\!K2-:ˌmaaGzFQΣ'nM exmF2`?>š=ND-h}K8Di%Nkh 꾙{9A7Hii9*{|qV\=MLhj<$NP""3 %tu>g*PkCju7in{{)hVA3fe-"Y3Ј*G+ڒ \k@M|B3O"RO]SؿݎX .;>l"/ӽϧk>}6|D? O#v6 sTgW4H\ e׼?{:?`J+ 4I1#Pdf[>NE?bԜBnH.[-?rje`x$.܀Adn=&A_˙wy-Qzv=V3-†I#-)<0&t#eḕPK% kPg,z5L꿘[N#DC3\O7BP~rV9B:d Μ~"v(&dn'"i[GjHJFJgYy/J}&Rsyb2}i x@^{1=QAaOp` PeNg7>h#RuzQXlQJ}СO/C霺ro})Xap>p#%6GCG1vRR`C} $sbL@#FbF? fV{i Ɓ$xOFq0!zF٪9z+ Wp$$nj yѰز0PK{>95_#PCԚzWj")ҤWR'4Vs`Դvp,~[Ž9ty fX4[( 1("tuJP7lbm^Ț,DT!@~͟4Z>H[~+(mh 2)9?NxmD{[rǽaڶDEoٴd wxagH}g ~@EW̩lur.j%_IsJyMmZ IDAT׷&3{7uȃMtS }dѣ7 'g~u^`Pr[F & ;(m5yX̗R>RhШ8+iwp,J{ʷlLJ/vxng}?,H9]UyLjAr!@1ܼrT" A㑁/@x!衎г Q`\Fĭ1!q%ڻSI2GR|VT 14w!cz1jfGZ7A҆,J*F :e`)Lvf*r9_m#EYYIG`˻3ٺB7;kb{׊7~cEGc>?P;Z4Qq۸hǀ>RpֲUIM- |yy}DiXotVz ңcHIAe1i iZ'kp D(ask`:UwР)a@-LX|*a6aa.AEҒJ N"Z>aʼ̊"QG&Ɖɡ%7C`FOJdHF+!y8-wZ-F["=E0ŗtm24N=fa`Kсl^PgH9ش(&&\7t4-2%t12i׀KC#HTqQ>j--Vk>^Sv8;U%G]0g.-e5 hIH9=th:eiyQ+| ʩѓ^N65c⯅(9)gD43*_o Uk۰Zvbug[J-y^Y?q+9F/zv& ]NJ+#b[7Kb#@&ǵ=i ]Q`RѿwK@MT @ZRsҟ[0 & |dsa!ޡ&0&B)h34NJ_ќslԠN.1,*ufwTYZGvs(;vQ∩ObF:iPV@" FOf *zn&gٶ|ss4}޵aIBS$k-&腰P{>?Bw "@[ci9\lPhAV?E׎a\Z|`.ap(0}$ev{4 (Y@AZP3Lv fҘ<S0!&bp|30Z7e> .# ]qEIO TكA^9p6!c>+-6%3gN<SxR 塨L2}8}y paGp?IN>8), Fqh'G|\535Z|JJc&U>u.τd}Boq2h$W<YÁ=ca@ G 3=uwi&b( (/'NEM]r0'xm"I77+juO aRuWFp:┮=F@G{1A@8.C.$9q]Wּ ,#cN$BuӢ!d4׎aeC e `Ɛ\\9S-!hD9(cF6)BC~[+ )5s"9"=жo,ʥ|s NK$Thrk2tbZԘj/cW j1$m${삑UۊOsQhqq&'LY%cTbc)+qs8qrV6?q̃Pl]t(b+S#Cw#S='_*#}֨V"U!9{MkHtCnPjJZDK\2$ 81}euh*/RBTF90țZmܺLA`ihGU`9a9 $А'iE\OU흣c!bۗqeuhn"FٍڤD>K*F{~ XSQ` g-P6@)V&_М ftO;I|?tH_ ks M^d D멲5!5Wiq0AN8MUZB /-sM&Bo9ƗkFL].iC=[rY@;?j&.遌I7쐟2 &ˇ[,Ps!X5r^Q$X\܃L[' V% ¦>0)D:)'7ՍH«h6) MCIZH̜oıZ"}ɰ )FU ; LBJp${Ĵ+kf^zns]^Eo`m0ttX40x䙠eZ |nDEZ}7~>r M$/i" |\+\2/-ӮJRO藪9’v@ +|J 'm%I>PDV9;VV25(#; 0-),kb`#:쎠 7I77j( } K1W0+9[QVTq?*~Y&gZZֈFz5P/^i1(oԝRT0g.vy#rjNG3j%%&O]2mX\sxf ?q{_&;qH 2Uwoms{-3Q 26MrYpe͘3o!tApmlIr6Hs! !7%nL1yfZ{Z3 :[4q0m p0nӲQrֶqnj+;rnNyr;E?L@F.Ao;9zb5DZn\ A/Zr9V W*TBn6e؈0y>,u[FUGxgQFdXQ)bDH/Ss nm\ 0au2i҃zBg*[i<,m89y\/u>` )j[=ck@`*[  1|!)*ۤ@kS(ԋy[lT/AiXOχR>瓰s KVa ϱμax\MB'zӨ]8Ud׉P_ xrvy0}rMUډa|6.xeVd3QXj ٨T6O~#ͻTy;%ȝ߶3>n|Zn. ݵ܃`H=c#] ݵf\m0,a~) I=fJF!k&kʯgi}hU6xPD$eWvv,&.M#4RK+< 7+ԾnZ`l )"/&#޿m(ۅpUAq}rеC^WP*oՙ٘"207.XfUn ] 2:Bf歷+{~ ^QFk,z-\k޾vjKlQ2v]_P3@ Q+wCc$8]s<Ċp<}hU `Y*DUf}J#b+^lg!_eٌ4ً|\^vhƈfz훱5s9-|{D.Y8nio 3 ߘaD@ew,[yA<ʈO:!pΚZdY)/Pnb o^o7D!HLBxf9znZ>\,Ivv*}tJȕ@<DyT&'a;0)Y% t9 ]V2)Y% W#qghQ!hBoH̗sPl$g45:ݿ|38 rנͮ6 hi)K@LiD6Gѫ0.>#*B^n gSymPT?ǡ {"FJ[too'|LTsƴqՔƛ)1J^ae3) MPy>e  ?c-T=<(As3uퟟUQ^ۋB:L lbT'@Tnc#MȀoT0ƠU3[- p*mEC^Z|A*pȣekM#sUK0h3,(rkEGՇ.f܉@D|<{PR_wב *&)$raY]e}ESj{s4Q>1| -"bm#^zu.Q=1,N(#׈T6u̡d3"FY\iDQT/sFd|+ϑQ?ҸSTQRMp&qMӦNzb&ܓAA90[3-&T+pstav$*Ohn-:'d!o @z 1f4lƥ鳹q6Zꃡ:E;OZ$17]7s'jc&dC(Ç6 $`,)sfrO=SQ0I/̍<}?ګ!%,jOzu#A>Irآi Ѣ htΉ^DjOQ@)t.Hґhp FH:L$(d1MfN?8ʓ_YHޙsqtK &2~*sK!;Sdh#RXdt96"h;m)Q6=cƇavySצ&]W( $tj 5yQ#G [5qLxʠߒP0xeEs|;|10Q#0w]MCʾ1V`SϷ>0lo0D{brdYp"sƀ$ Yg{ڵLok/ʘ;\FBQ&M,8H+B6+֑#/H+ZLp%gDEɐ{jZMh=YweGfd OB `XnQ-4c+@F͙ A$ TXDzTP@:EF s6ap20M Cz4d fS'?=*D!BC,,/5%aY!w4Q1l[L?bj)頞0}{\0ElJO/{3 Z8j?6Se֐/_=N>SUjzи8}M<(fpYz~@' IDATهi?FàCBo=O#(ў 8; ƶ:Y^sY/wkd} |F_0mn:kђ83_cا֧1?&uO9t.^1Z%#`rǤL#p~nP-o0;tMFLL!pLg:Wfg.,@E| u4Jhjcs}°;zޮܴppiוuC_{8`k-_StQ%# IqdxZ?Hud㍓,Y3KLB H~ߋTRZ>z_O^V45#SjmjzNf8 ?s1/%g;64y$B:?똩ǁ3czm$/ 㼥V'IA3Om*j1]è͛ZFҎS0a7264dz)߷M[ ͊o'yeNU#H/@FqHH4)c {'oO`(5*<)ةMWLZ}poyPlj.k޽yE գ'kj̙Ǒ3 jgYᩪ9環驩u2;D59 nso/įЧ o[d}1=FFҰ\W.ZD[zY"7Nfdz uNQ$Bz/QҎo֑/FukK+wp{ p=FMY6WA(9F~Z37kZmo0C g`~+<ɾ$%oukS`prh :ƭmmB?<)YuH/f%dž-AAxTx˩s=n4Y_4n ceA [70+jĸ냽۾iJKRP݆> 0Su~7Ksl|˲DWӭזfD6<=2Km2+|Y#PO}{4PGٹ2ta(IP='yAY"j[? üDpӍCFJO sQ.P~kWX8^W,Zܪaq_eW=u}Qsb7KƽtJY_?gg#C:!/^B;dZK0M6zJ% :?(KծY2f 0qhh!~MB~BA e㰱tm|$~f[1t {P5.3gIX.OBb8`B+> 6>kĪ} ^빭ũл18+)) _!N3p:7cx68߳`Lu? Hf? i|x 3Ϣ|+#r֫Q/:Aˎ?Gkq׼kh&!6#/Դa gаMu"3? hSڏSv#wzU^jlDj_}hUv6gUb6c"a^{M~kMafAk˖ A<\+~H^3 )%tA?)1!Xc b7X 4JJ~NLBpE:VjmǘetBd|Ih#C 됲Jԡ+R){,+?k[: L 1P4Yh4s/Y&4)%_3 $,ps)N(?بG v˵IhPF%V?z"9!u\GDUD$~*M(4g*LcdV2e>u"#7Icx"Ozm]jy: TIioMg8שeVK%jOܲk h }~"᨝ںQZ?Щ7Si(ܦl$1|r ʄ! D~RC`e&8v/Шh4bc`)^z%wQ#oT4oc@4E鳚UaZZ_P6fpg2i%BH)-B_C !jf{=rt]_/ u# Kcy"0 A&[аyK4 Nwaþㅧ  &A:^"$.E]+F*ƚsy XlLx=èK&˫n+A%*@Z4#X?P<<9q2M£3X)zi摙*v0x3ꈡ&WzwLs4 ='`Te+{>2߳kM / ,jh9WGMc^m^B3B'Dq @Ԯy2ɀ(Q$P K]~wz@00_[AK NuZ$X嵭 !JėJ8@_ Nn4>#r{/1Un1AxQ`RLv+ϸ'wt!AuĢոilMJjO-ݤTEo,r5M/EN6oHk~XXCpF&c6j!o/h6n& ]9>mo+ZIB@pcn? Gmzb:LBrn8w@ŕu(i"IrBkܼM&^~K|n|n?i( m0C畟:n@4B0n[sp+ AKt;rUأƍrWVAIcՓgAR Adܘ#'Ef=g^3WO[ MVW)ȵIQD8ߘҫ< O-evid` qRM.f0iX85iVZ֠Ws/o9~ z'mDkBۘGa@Hx a*J`?ڵ ߥ 5#JR`Џ|i[00//rS/BXLQ[+(VB_ny?* ϶cz!qJ7r!%p*ɈD9ɽNM+I.ayK) u%IS `6><eАBoы λcO"I`|f:&ޮzD^N<@kyhȯ@@q<,y+?9LMo:vR85-oˋ6xOwkXlҋk5^eb'Ԓ=GxZS =O]L!ਧV9Q=0bYIV)h} (O3aj{G  CM,GĩC[ro?u~&1`;i,/֮Mq18HY{ώݥ!`J 狋"Za;D L(0NLi@x6:W#yT_1-a2on!9k/Z̤OH5)Wcq8W\9=r`oq6TǠj53i?atZ)>0܊D}#QJ30 hwED)ܟ=)t "ȢŞRJD7S~cM=nY2 pSUW^m먽|i`-(KN&g}k: ,zpLJw, 6!4í@| $>MoX[`-4s6yb;BFtN4]ZE " DH3!Ϋ%_h/.{ )~BT`ʭM${Tʯm gSʇ pAT z&7B-\ο{.09z-GB{_SeH1E4’u"(i;ցw _†'zf3Nwq[ m1&r28`ҝ0h0]c%69d7tO~ +aPOTQfvR</3Mj6Gh ecMIn/&<:-kCu+)| ?HR. xr/\T9X bRzҘMnByRZ5jFv! DQ7I|J;2`x0c`/E=! hpg2?|=(&3oGGA3eS]B|҇f&YևMM*G^c2&Zo>:^[R7\u?Jf\tȷ:ݽ'+)pqЏa?Pi8d{] E=o4?Arġ[UǩѲtL#CY-׏p ~=1 DiRZ΁[!Ł'eW #Lñ;`v3i +ߥޣ܅3AmnuosjG<4U/lŸYta=ȗ /)ZCG;"49mozƠFU)d(ä{,7Hpbݥ$h ]UR!cwpw}[DhƆ#bopEG:Xq4$C}eqwvT{,KryY_&=y/{_ yklP>Z7yôf4X,-5 @-F9(@ar17A 2גf5*֨&NUq[Г&82ґeH{>sk}{NC~O-61*xË;\E0+h: LOF{+?Pqx`mͽglEգw+dC~?o YrC@9x# 5pnOpDDGd[dsZa/ߊGK ʴ@JGƬHY,ouޣAf~ M}u27BrOHSJfRj4n|Lok4UFԆd~l}48\hW PYtю0\AdD:(+Fh ;qs(:d,!MRe:苞LSڈvwt( [2Q>W}݈NBa ,Bh"3=s(hߐv1P\׉%+WIGW!A 9~A 4c+X.9K핗k\>8Wm0sK,l rbY >سr6Og>G *vZ>;2弡FYEh) d76d3X2C=TL3m3"J@׸(<ţV)B?'PFb P >JfiʲB+ыZc㡵@Lj s GJLcv Yzm\#:ŌTT)4R'S+k=R!Cf^V/dpo[F$QY _PL IDAT/{9{Aha>2 幈Kg} _ BR܂}e_qjO)-3hA7[_rE<*͆Q2oϺٸCY\%n44H)0ք@e|3BrPO,(Ȇ} Ph?`dA*ӺNYQd72čJz-5RhTĞ.e1Q=l }g7g'p{4#(hsT1}a*Rڻ|3<0,6"qH6ԧƓIE9:u W.ZIrxYQeV/Lڵ<57$p=\MT:҆uZB$l*vK;WFGKEhZ0>Y|}>}CCEsV,@A[{ʩꘃ4["%dfD28!E~vYq?Tq ! OY>뇖Ah't:\ca]mw2Yf?fj@'i:,t/d5<f"l]~@x@FGevd919D `4BbJ)⪝r-ψ C̊2+#nϽcx@B`QbNeON,F724_h4nn~PYn@VRpaׅȋ%ϖ^gmHh,ͤ8j!u)K*DE+Q\?D{T1XC‘vwWVn-ݘWh4m\%_n"ё%oGT[)xW gڜYM o4>AIhIcB! Myb#JoJ=~j{{/-A=& #xB;%Yn1EE%KA"j@n]I]U3( 2~YYI[ gRX `߹YzRF v b%;?J.nR?)"tVpYY_U< <˃ Ug0Y!Œ߱)h7Is?@21Q*|TG_H?"ʨ?v$Cxmy8PfSqgFࢷm6o>4Z@)Ks@lSiMiH'#{o&` L ]*[[ 5ue`3b C&lb¶*N۰z 8v𠖴@ lM1?FhgFOs$J'7!trUye PLVO^̋3gW$-`0laoX6|DtORZLRiA*QxPnY٨,wlkc-ל(ڠO..^cV14%p(7>LO3Tf4aZ1=^S0 7INЭ {Ydl<[FE#& 4eXpȠ'H7O~v%Ciyu_)ͺ7$O$sZ'giw,aX p ^/ `W4^`X Sy*J +8^Bk}"j\~%JR4?LIOE++J9uWTknm7NEN"ٟ{ hDUG57n(97?[؇7&҂tYN/f$Cm8+h~9'Q]rSңH3ӼkBOkAf.']"'D_jMZ8yj/IP_\,yOWWynt=JiKWnٜVD?:ۭaGaT%$2`+1/e SM-&ng"0v_h`@Vs0 0ބnJ\0OK`Rk!?|x2FVLThr$:ehk/9Ĉ$3cށx<ȇF直'#{~y/mمfHHsGysvY2 G4 3APM]sFb( 5F?PTdk93Q Mc 5JqD_y*`ws84`G$|k.>{wR-4Kz G6nT`s,1qyYrv B*ϐI'L*č+hB{fHNd]#(1<Mω^HT;+K(T\;iaT9jfN ?'&Rŵ>™ Tk0nk+i}࠯k(omjG2eͯ[:t5!zٌ\O %CN z+EbdR<;91^rLaFrzDsZK? &Jz p'N|"VUIyZا(ң:ʦڥ_>m>͸`JQu ۳vA&߼8m?{  ]iӴb'ЪaRCp.@61_@d*՜`Ompj6AB|J%i(.)M57XM: 쑔zPaVUr yQ9iX3 P"*Cy\||yks>Ha(mL/""NOct"="/ 7dKя1a`% Iۑ*ZFq7'vMk^H%n(AۭnH읋2~^]ȭDL\ I{&m @&zV93d=D>$ 4d8O iBh8R[`S߸ALIdQQ'@O׏w@(Ӽ")ʤ2G:H[]єFC{f Cdz3Hh=yG+#CH) h8׷"AG^.4N틫VOkJj² !/Doq0zlM ,j][|P/9*DrP~v ]oL7n8g#VO3FXd6`,sQ^ΏGVzÇ(%a4[In%n |\aaVeο!)>!)!y?ŷ&)y8~ƓLs͢CO[)re&FҶ# ,)lYTɒݟ|k(x:=9~[4uc.ee`LdP*cidGދC|LE(~=9C_Ҍn,"ĀSxQjcE.|3FY1iSY@KB &削T3<^+/Sih2"Sm7aEd9@.C]U}f.ϭx6Upɱ )'T>ֺa|tw=44>MJj EERo$QSK2ad3 nT㧢d!ACϻ[ c *Q"onp'D i*O9:N_*n?q8\/ƀP U{ d(.|W̥F"z>%MMB.ŨtrCU~[!8xoj↱c-YEKkk II NZu,f >ȣX=>&E# ĩPJ7^CҚ7jE.[ ai`}n @(EF~ʅkd޿rWimN/oXw 2`@Z4s~(B?Qsw9AǩieNMc|{N%e ΂?pm AOq4Ns-D4OS[% 2eyNޮ zABrM|tCKʝǖc_1Asw?9 C]z)lԷzUAz|j噔`9TAdnd׭LQU&{v* :u-, 9f/QnjT[F؀+ 7Y2.śTdљ^ zgV)^X f6"ز $ńdz ֜Gm/sv>B96j;D:ҐiQgh`Ƙ/2BY6r3Ue!fEԘȄXixoQ`)'׭zTN Xİ `}|iRbagZd4d3 gM'Bm)mt;bFrP(ScYg _A)N6=}Gy[ 9INhCᘴCp;y‰x ?CCT=DmL=I\#Ox}0$?trYI0ezFUzD$=NIQY0=Ho9Ҝb{ufk {vk,;Nu>K7yfRqܼbۦ Śu(ShvA*= ,>Ε}yR_HħdI9\to2ةx!mF}ͪA6ߨU9͒l4NQ+1~jђ=4+}{kY Xx!^FuCJǕ0rȜ #3ݶf uEF:D]'*׭9@v!GD_Qhq׍Y僶*RxM,mxIma:bѾ`ˮI.mbsc'+&/SeM޸P/\ݙW< Ўp4!CDI[v틋=5=U72BqIv(5 9X>J48 XWUu2yѷY="|5Lxi=Qx.2N"x_ |j#S+&V<;4Gּ0 s:ܗ:|- E.ַ к(Iѭ,Λ5pr`wfa^djeשּׂ`1ͼIjv֙"}VƠ)z;(xGQNx(d?AKRT?aFR}1AʹY)U6I6^='C/{܀7b+b IMX4jsV|PeL (K2ΠQ)V[ 9 oO~6eʖ@;!QlG('o<}t(+^Y)+hu |saJ ˼( d Ѫ&goY.e#^@Ӭajjf=lRJ5i\[wcA:/ fȓrRy5Zu'J[. \zog+BaJ[~?eTrrfq@Lj -$m4jo ;ǩi7_G>g >Nԣ; A+e,0hވ!us5o ZFyN%p_:>x2<|2 "(Ŋ>@SVbĭFᱥN}_кk&-kamcYN#Ѭ|5~Nx |2 URAi['kS#`eyڳeZMtQ\4?ɉRŊ|@ciIIg梷&ߝ Ky)fU7@Ə'Ѓ1L!ͮI'\!ɤ'[w2Q"}ӪWr{ ^?<_F):Mч ' ӧCKX?0vRDm,Lib9ډ k T?>Gv;.q`Wwm-rעh\[is9W 'F'ItJnl7hp!e>LГɺ+!!T6?]p)BmAiװL#<\Ӎ,fAȟ?lX%7 KVR7G@Y$)4 IDATAfZ!O7?,5j>s%x/K(%4#.k2Ou3C,9['wq< LDNIF#<8|):7/FHT㯍Ė42GyTQ42Doi?9c@@5$j!ï$xii7I[7Fg9Q)vxьHb: ~ Դ& T@<}?zE6!0le]78LseGHV~J$I=tJi#ːWug:s~tʷb"`$5Qw"F=Y~wJOF.=8`|\gf5yEҜX}w,`K3t>RFS`^NuZ$*'HLTemU~m'lwR@gQ/Yx^K]&6_6办"VrJpۮN5JN fx~!σFLߺ.:YGPNѻoA,45m՘s:[wj; -bMJR$1eځ^e?\Ja'j[`6bTa8X^EDF+^-~1+~sjm5W)$R󣊪7ZnT-Č HVK1ۊe$œ& 2ٛyP|/dhjd5IN*@d,ꦛG\x@y ey3<:Q*_ؤ<-GM tj ӝ/BQdD<}dªEOcWH̝r8@Ų]^֏ sE>lŒő={5f FnnfLȦ9^ڏIZ0䕷ؤRȀ y!S#>GD(G ꄌ-((J6۟-7\h߳IkNw y_}aCz&XB:Lsa磏po%%.2b4FvӏyfQR2 hmJkBJȋ]\ؔofiC /# lcL 2%2TT{0kMyVKH/$;WS;Slt=Dde~4 RK%\R,&=&2._^EiC(SX׽GVBTƣ5e A:ҭyhZpc5 5;C98 dY 4ėQ 3Jڝ}ARΔ4ڣd/@hsJ;\I3,4 Mq'H;&`e7,Ntٷ1o}ҪyHyB/i-,u5 7$Wb+B Ht`BQ"az0>YӽM*|RZ +ft ,+=ށˎ>]\~1PtՂ(u(%VRrr ˎ9aDa(#@  qÖ́AF;R+9KϷ2خ3m0y*LYk#noVs]p<z XJ >8Y$1_NjkNG5|p˚gc͖N{ؚ~]Ta/nZ>J+ vX @~-E1.Plጆ]u$J׷Mvյq 鯆om7\TU 7$Н\"K)NayQR ֬0H?rS-ߥjw@sje_$$&?gH B8jϾ v Ue . ;ɮXEg<`$T(J US΋G:'XY/M?WDd|%*WasQ pډ;q$IXiu^a jQ"֠+=u0ɮ^,xk^v4dXDN]H 4Po]C0^<*œЗa)wQᘢA[;nc-&Ex'~Ȅ_"-hrqM7Qus@ddfoT[/2Jq&]WEof L»8S"5ZzgejL6x1Bx%#NDJ!hQڏY}m<7*WWijՈL9TF NBFDf"'Le ;`vӎiA~'7P3J'l,?{#IS]hF7ƘİsC69S\\H?1$C# y4} %R;f) B9!B-N!֗V>v sJhtA e"7f9%3'l%;쏆Ӊ~4EWF4+sBbݻٟAKz|:yנp=ΧkR(LOy6~sFEX. nδ70Ks ]C٤b Iv6!M6tQF^֋hRMƴ0 @uCezS:&-o/㲟֐xIWıp:!9UsCn@,5F R} fmT__Յ6Dgw6, $Kq^Z!c.e\tQoߟ;%!i(BFY9,!1*E95D-`-껴y>PfN`rrQQ Oa6dyD7}í1kP(#"zKԕ9\B\A<o?CZ9{LO?:66V}a.D@Hɖ@Ȑ+aI ƶ'5{}$Fe*]6gQ@gVI^N(*4)R[؝^g^ByB.nԜLJ<} 4( /C!W05*6nqoyfFgs*{zvZtw4D][#I5^F[:O-z?٭rԧMA>~sZXyeM:+=M|lSe۴*_W H>:NUЁJ?*Az҂ɧ`\Kg&D7v[)叽Xmk*񋯗T'V0J6v xEkS!ZxfP;nFb5#欵br=#6e@q j%32^ @1ͣ`*tx4jB%߁21Kmn _[ $1Nzann\vy/d C3[W=kVIq-n[5y5v;cV!b@$B+p +LtӖfbhX$#b`8M~LRPȮwkc}10| ȵ@Ie Sѵ5afAdvyxE=Ƀ95ugs{\.Qoȕ%k!й N>5=Okfkٿg^ :o_XIByEGKc|bQ`\Qrу>LJ3v}VbWHIS|rrQM|.?LK@)&a},e]Q 0|P2Eۂ%)emU˰) }V,efW%\>ufL1aga;,Kd#)ο֘@#YV z*oˆOpgX@PQVݰj2iCr'k4otlhNB\+%_>t9tdʕ"Գ4AwQJ03[W,[T1L)*Rbym8Cz 7TN厒1]dzQ/h ػ:+'[1/lfU%ί{]:a LǬ`^CA&[g*'lr:dܜyس^L9UbÔ_ oqud7C@LBK-XlTY$ӑ }<9Ų ۽5R6$Ɯ|wvgVR`'I1@ D#=7v|mUҨS>!uUb+ ym: 4J4*ˀSЋRh@D؀|_}ꕱ-e;T?FCD4:i$+3B6{W:tDey4`0'oF"rjYhC˹vKJ;$a\M6|0񼓀 6HP.l`4^M`xWSJ]Fh g'w92+\z_t׈In!e})Tz6| U48)=2D%C>T^֕h51Y]upgy_nFBOףM(VظaSf뜿~nxۈM~/e\v0c1&gLt'YSCVäawa(1ʇgQ:P:jNy*L!f!$_4Lh?)+/%> 7gYGeM:˦>N3Gm%\5x:|q hm~9f`۬O^Zd^x_Hk(d +$DQ?h%XYi0@*iR< YT7#İ5ԳP^lDL{Rq]]M3_wT -ĩ }%&~ ^'KA'sz:[|Mwzi7|͛{1X8ߘCA}rPۏuKbiû?LGj0UJ8[{X)`",ח{~ +d1Y:[ĤͰ\fWT7%WfXWY8+wiQ\,Oς 2ML4tWRiK6$JElw(y˘Nw%LQ83w6UmѠO\R^O[M߳'vɜLq| f>sIAL ?Au:l5vk{ A%&h7斅o"&z.>=B$> m&psg$k*);Hyž@QyS:a}W lV2Q I\FJ!bOUB,4%gl* [G -vVbp h0KF-k݌71G#&oNdW QDHބ *A<9'J\ mQUnҜ˂QKȥg0{ي6OmR8hYSȓXI^K4,v (GO}L'/%ߗ :t4P91o+[\G IO'kl]]/W.fkP9t.Ks!)XgubHf3u^iZFoPVY.*(@@*2*vosiẗ́rڠI[CN (ϵX __ȥX9D謱덇Q-8B|:U G$LV"B؋a1Ңo*ޓRށ%Q^M4^\y&@Zϩ1C;bs6 ݷȖ9j)S zL;K>`*i0MV7Sbz]5Pɫ/V;|N|N?ЬC Ie uCQ؜-::Jz,vLҮWtְzlo@c6VyĽ[2ʪ_4^y/VYftiк6طҠܲ4kiӁ\U|wR`q/qI#ʥZб8}A>P/D`L iMۗC֓gE':3 |q)!-~P}n9Mԧ]QhJ517.0\hڬ80 }#A7Z^|%`FC6$/jhqy2hNtrvnJ/D^1SeƗ:K][eXp}է5|Z׽OzA07`*MRPGу7 p  WatJ/Y*S?Cu.F-5K*4A6Dg7eɄ/ZtcaV1̛7M2 Gva F û|:&F2JTS(xt$O+TiT;f36PT}uo݀)gqEvSW8;fbjSJh҉Xgt? 1~eOCw{K4K. ϟIqd` NuXo ,ňjcG:+R 5CJ FgJ@@ Ϻ7@*G[os(Wذ5$. Ė0K TAM=#Zf уԵdA7, .l&V=d-YPykCe#$cG!=}&mL#8Y&CΤ̀\QP&\(2hGIS]ҺawׁRc@3WMlĺŌ^ؘ=I X}~CXA?YYvj^ IooZBZ9-,ELߥ:]g6(,Jc&25@w1S塭޴oF.Y]&f->_='/٣0ٍ[{:(I0:h3;% */VFOC>Q)]kЈ,eWU]+-ag`}vy_Vr_H 芡KAo)/k*{yi7ᎶR^yC\{{821~s@'%3CуShij򉭏7AsМmA8]\i>D쮑Jfb0]tz%*jcT9Ï3I"hDl.ў͓: ː0 w_dg-3B@=qujrQ?amnM&rW S]G$;a' )@%mkd {Ou^(FZC*l3ooŌJ_*X|Nɼ&]N fBgFsQnѡH,NͿ8e`].N@A hP(&hCz*<슿s_%?!6b:cNҳAÿd8J9bͤ{&⧏uє?1YUi(y0, QgId +}kKP2D-\eV @mW -L/P,7uR{_2#uD'ԟ 5aP!U.-3!6ط_N !DfFH *Csö]Ҥ ˨aEEvw<2CgﴄsX-M3orqsfe5ˋl%X^8c@?yb(fp~ 7Ǜa*M4|݊nP0FaNF0vc8`Idv)Efp5'AL RlTF6<$^A UExoJ PwBThJ1;l\ȔѻZZ?߭~Hֺp2 hd28jj.WޚfWVsb$]&P'GPmdBκ$Ҩ% w0VN wV~JMI"VU`[Q_ChfhfJp,w Eئ4[Zﯧσ̾;4n,LA5Hd| ^0?cel6au<+|,`67G !9feh.=!ґ;b{E7{8sQ:9tFB .r9<*L3 ]u?)%LIejV'\g!|Ms]WnU|:JERrk_Ʈ@s߭"'ϸ S\| FsDA:Q7J(ry]1/!@6aH\i?y8H<}ʝlXK&ePya@e"buTUp0?c0."v]ڟ9d[8#O$028&F1a Nos x>Jx, p{hDw3&QS _Z< ^ G磜q OWb(9b߱=^Դ4bQxr-+˷z°;06F VϏuLV[ԝa8ɉZQ<d& lBFP/hRp+o^yxM9QuԼ } S aP,ͥxFbs{gٽ&sɰGe&OR!cǀb?wAB"m 4s԰ oØz]'dzZ v>I8[}d^¶{@V7YBt$3=yEנ")nYwBjӒ9>^%&lvBl |"VLkfey =px_cP[ʊޭ/ {l}5x0F~}Ŧ28!Wj9rVcWgT-{wMY"cH1MYen p`i1dЩć1k~0|sCp0M,,=f ޵D7,w h= GN)^!~ +$QDڨ8s_I־8?~f&O;*Ur%BrŌ J"au!ߐ5rS3]gF b *y4~}~uI켉MҗLGE Ӳuhu*#585 B[(_JP_j䝣6Cs|.1.xc8ݚN.}$~N)̌zr}(:`*6ņ3羀P&U1u_s{.W; Ah ׆Z{&u=2&r}'7彼}P&fbvyof4ƛ y1C+ս&-;AV&<1:2M0 <4eqrYkuf2!+I{È?B}t Nʮr7G%beh/l#Y}g41eĸ!ϻ7JJpnd25T[8.:b&#zqK_"xU6nq:T -ܼ_٧Qp'.ϲD4E5VZ4hڳ pzA8I k"E{κyJ!0/XQ5c;J=|,U!x @JD8dL!fPȮ2gQ`Yq y1&z7'џ i )3*_FFS5%ң1~ QQC?e,ȡYk[Iґ.]|޸? m2/™ecԼ3maAC^ґloܧ]104;2Qjs2ŷkMX}^3V9+DiƜ<mU)`v܀d0kAzr'`X3:"?%iҌ*{܅ݛ_\kWM=OYDQazlGMMYu[Ç!h*%+`w\" F櫲E;eolE'i =H,Po.D8bԞjQYQl-F]E$y$U鱆͆? p\mY$jJqLMg ? AG ӟ֭@'ڻ*Roa,+EL$Ẃ݈Юyv!k@hf8tZ5<0caQCPJFax>pEZsKR i 8};*2bxI2Y>4"%m,]6Ds7<}=֝UC_jEEcPxdfJoׯX9 J[{'7o yNT<;.[ Vup~>aiݮVeIƔ psE3셶qe+; NLr2mSF~zGXЩ'C 0}2=sAn(j͒5l@$BMɖ9kv* RK*A^cTZ-.]FU|#؇9LFwق6E aE{Be Mȗa}eAhvՌ,?vᑻ}niCBtqAlf#7f+&k6h٨;Ҫ0cBޒ5gmɚ$%8Af-Z_ux{«,&Laб-=i65ttϓ6Wtc@&q6іTWQطJUf-5}ԋ(Kxu 6h_@ Tu(} E5Op[l@ ΰc9ee>XC@*0aʗ@|~Uzar]Hml"In`eN]M{. ekgT-nqHBUj'E9A Lŵ)6ŰPʬ\MC|itQb9l+9zYp* K4DL} z.-NIQ\YQxZD5dotKmJM60,+U3Pq1B\i yuAY/57>֦^{95s5`}aOw&s;wĊ֏em(ID)ⶲ'Az@80A)-_ P G,LzKв%{&Nr>ld{}VL#n<ȁyU U@kx!zn~'CTx~Zo(yzM^K.LpztEj'͕sc)h]N"JG+4!pgAò[Zt 9x`bz=sjJ v31rgK({}] ZQ՟zH~WЮܷ1{(Dg&J6wKڝ1FQVvf..LD!{NeA vj- 94u!DoIcAL\E~^3O$g% 5ތVֽ/ 哪tKN LRb0R|7j$\'0fC3PT|v=n٩a@6Qi)}pјT8<)-qlo VԆ.2Cf/e䭶f6F9&AiO ƈ+3 {o7H|88lyX I]nx!sInPC27ƃod.8`?ODUXOW5ԉRix2Jb|b KHi PE {4D8ʛP)&gIuSacنݻj+:"XR8'fOpy;%޼2AS3spvFt'hD=Сo9AĊ{'hn*ɫlN♓/lES&׃eWd\H(H8Yrf3׬嶫J}SHYjKW#%NZဲ_$8NFۨ:u5yaIpk>wlBL9Ήpro mC+ouwtKwH= \u%"arҍ=4A#߮jM n-EoS'bS?ii'A(wcTA ryEFsL }Ɛ|i.[y㚥-S : u[Y)Bt0ӵQ@]J-|-u٭}X=T{X ƅNđ3ڴA'v9@0e*p[eڤ&}^1êp-;\+ꅢE!FCC6B9&.SJ|5(.i^J1 ȱC`x( MxҼ8iftXTaL+b\s+8mD?4vG]% n&!ftX?pz<~K }syb<:u97BW}VꄴXFF|]؃vv}VBq~5MF ܒqsjDp#٥p3 T9 Ϙ+$ y`FC7 (V $_$ط{SqJalpyk}Mw"} IDAT3f)l2F`m:NRQ; (8\1qμ92A ^NAL=!,[~ҔS;7Q+}wƑE J =g'Zlm'E(majFhZ% z~>tU@ p]a,#w_{nD Y!re9>uʁ]AltONd7 ␘+}bC쁯ʉM\J-R{e$]O{,Ps/ N2V ~o ,{SvâR(FH-g&ZURxw^Z" ҀX-{D,TEVbIosTh w4^c$H o|$gg_ӏލ_aHɧS-X#q8o>+ck<6GڹpDh[!nU.i3FJ,WNt1X'5v)x&ape<"<@ ?<OArP+7_=e:az6vb%F-J$.u_gti4ɞUy"f2HPʦ#9<9XG=+E@/F.އ|{d@pDƲ,q6tIײcYA~و6KV0,t>B k1ydu' o! A+Ꙇ[Yr# YsƔ#.pW)ha\#h(n⟺qvDml1~56懶 Mb3gy߷D2OQW1ϋsX} Ԑ@eXQ6?4Ru? /c4x{LuĖ_XY;jt:&~g*PD6UG8:I2@sdyͤ+;#M9^; Q=68n(մϯABL) aiB|Y͝y[޳uok?ӹol!TG]dzMK,Va$iCCPICC Profile8UoT>oR? XGůUS[IJ*$:7鶪O{7@Hkk?<kktq݋m6nƶد-mR;`zv x#=\% oYRڱ#&?>ҹЪn_;j;$}*}+(}'}/LtY"$].9⦅%{_a݊]hk5'SN{<_ t jM{-4%TńtY۟R6#v\喊x:'HO3^&0::m,L%3:qVE t]~Iv6Wٯ) |ʸ2]G4(6w‹$"AEv m[D;Vh[}چN|3HS:KtxU'D;77;_"e?Yqxl+diTXtXML:com.adobe.xmp Adobe ImageReady zIDATx] xU>τO!2"-H܇q;~8#u^v|ͮNwfEm\tVg+h-2РKHBIQ{έNwR}[u=sϽuJEJx%`+ުjN(qP@ E."~P(,@ E."~P(,@ E."~9b;*fkZAj"1o (6SHt?UL¹p;x *>>%5q !CC ~b@je6U]osHdcˇP=&Ǵ8ey6ߑ0FLI?z4D:zh; 'ZG%MX#Q޴ׇuro%ĄQfFN;E`G)_?.fGcǧᓝ_@@!8֛D!c;!3d tw$_p"m&\Øeӟ.v~ ZZOuG@7P6/aɞQPbBlb2zbaGvM/ v7КגnTiw br>3Nvh{:QBw N.eʸqp1Z {;#4OB'eh^#4 *GuyS KR[)hp>9|+~&^6Muy~Ĕ!! k(8,cNikD':vnJ-&boҿ&b"\ n;F7žW*]C'E+_ua % zܥrWYǻ+P|X`{x[aۿIiP|O?n?v 'dgQhEcR%y-PمVʝL oΚW;Ɩi^6q} |0tNa?HkDAp]WN&μ U RF-];aϦU;3%1o}N~ښ/n\$RıƢ3\ >5$TԔ?Mt]\Idձ3߼VrPQ /p]`"f?uOmZ]N!31@G`7ʜArs8;s4!׳JhIAc% 9 "AgJ'x0 [>}𿏾Wpcz ԝUs '1`t[?=MQ&t-T8/^v ޭO~ts\}I]~upl,[>:{:4D\@wXnY)7%%T vh2q +vSKH4Y6Eݙ׼ UN4÷pg:aƃ( Z iwXYerr,l+Dsޱp72/>0%&OQޞ( 㹽9A?bx O9[a.WAQN!1L! mכ+9']iLjni _᝼ga |B,>]^fzW`Xx:\  pXXuM8KJAxCa/7߻]] rn1ޝZ<›ہ`z 5#\D,R_9MοiZ!vwNzpc?ȯ́XMo ^ј6;xoi U}S &pUمK:!۰Gݫغ;{V.Uש);Sea4(Y .ԫw` 6P?OK^.N@_GK<'>,XROt2䲚x^EiCB-zpժa+ n/^p94 'F0"e V\ -Y -y7%/eN23}/.d}?d"H.܆7-Gٝ25c5=|%#m$c5ɜ3;\̯M$~QDc8 ?:& ~Pe/29LZ9WswYW  $sӾ` |Oss}6ޡ\Ռwa54xFbiW~zWd5tIδ͸QdsSK"dκf2|n4e?F\ q vKS"ug%ʞCol8Fl6sG] xILG@O߶MOIFCWgY-?=k9r$s=O%Sp_Oju®%(O,%Kr$@Byy `hB.gPON`f9/jg`*l ċs:(@@̾:Xnm yh#=nDI٥'7ULN Ɠ%~4#R]$IBn Z5qZvߎ/>I-3SjhPO|?=OeOLzq|Cr4[9п$ ,9z9aיR p c3RB )Pw`4E< C {BiZZG߈F׌z[~Q RF~=)U%YM9J$، @gXNfcEUs3 J? )M4KM4vpÊ6vk5, J`ⱮB"køyy5eL>,ٝAzq LOoKt+@\ȅ !{ؐ/2؟&e8َeC',O2hw8Moa!x_XN7O5|*VzRӑ:z$R6D-.iƷ\+^C8sdRF ~T+h Δ63VO/Śx-YsA-KfԄy+t${['-PƟ!IU,zjx8Y\ m;CZL9 E_ 5bVG:$8KiZXMOnt`8CS." G%,A' pP wj< 6ܥ?AO4züV^rvx3.˧ `3 uD5g^:Z$\*I^}"R Gq1W['a\]I$*RKƨĸ-s<`=PGFOu5-*]"8үa @$nӾ_@ߦXwA{?oNk |tduE4$@`@2g;LOF]/Z }ayN_+jz]Q4& H{iٯ0 L. 54oCAFtPU-3>| Uf4Ql~x =ȊCU|9tWGHo5SjqA5; ]jϻBmyLsbШ#B HL) -~c bۇ·#"GN9v+8R;orͰ%JxΫl@+9R(Yr$7}rsd}uHN+}UF2MK@ iB;铤*?F#TM>0FanIL|OZc` #ȏpS|7ʱpQs!"cuN$gݟ]uȽO43x'l&QSX|D@ؑ[[#|yyINˇiICYN1˷yɲX A~_0' VQ 'gsrc'Yj tMP+5⮟yj]5t +[Z3iy=,8pi{됹.QP[O[>>1OP Hkd;[! . ,s-p{hqek YK|j(xpp5JM`^h1>,[ߍV<ېg|Dc BBѥF: < 9 ,:cmMh]&;H cჩ>P=uh ^w<4T";$' NN'ƶZWyV |(a~bFiWsl)_ }*?K+%P.@Z%Rd+]J(@XR VJiPJv*b%K%X)U@*JJRHT,?ȥS`#%IENDB`chessx-1.0.0/chessx.pro000644 001750 001750 00000023644 12222770050 015636 0ustar00niklasniklas000000 000000 # Main application DEFINES += CONFIG += uic warn_on QT += xml network svg greaterThan(QT_MAJOR_VERSION, 4) { QT += printsupport QT += widgets } static { # Everything below takes effect with CONFIG += static DEFINES += STATIC message("Static build.") } DEFINES += QUAZIP_STATIC DEFINES += QT_NO_CAST_TO_ASCII DEFINES *= QT_USE_QSTRINGBUILDER macx { QMAKE_CXXFLAGS += -fvisibility=hidden QMAKE_LFLAGS_RELEASE -= -O2 QMAKE_LFLAGS_RELEASE += -m64 -O3 QMAKE_CXXFLAGS_RELEASE -= -O2 QMAKE_CXXFLAGS_RELEASE *= -m64 -O3 } FORMS += \ src/gui/preferences.ui \ src/gui/boardsetup.ui \ src/gui/quicksearch.ui \ src/gui/savedialog.ui \ src/gui/analysiswidget.ui \ src/gui/copydialog.ui \ src/gui/commentdialog.ui \ src/gui/engineoptiondialog.ui \ src/gui/tagdetailwidget.ui \ src/gui/renametagdialog.ui \ src/gui/openingtreewidget.ui \ src/gui/loadquery.ui \ src/gui/aboutdlg.ui HEADERS += src/database/board.h \ src/database/move.h \ src/database/common.h \ src/database/game.h \ src/database/partialdate.h \ src/database/playerdatabase.h \ src/database/playerdata.h \ src/database/databaseconversion.h \ src/database/engine.h \ src/database/wbengine.h \ src/database/uciengine.h \ src/database/search.h \ src/database/query.h \ src/database/database.h \ src/database/pgndatabase.h \ src/database/memorydatabase.h \ src/database/filter.h \ src/database/tristatetree.h \ src/database/nag.h \ src/database/settings.h \ src/database/spellchecker.h \ src/database/historylist.h \ src/database/output.h \ src/database/outputoptions.h \ src/database/databaseinfo.h \ src/database/indexitem.h \ src/database/index.h \ src/database/filtermodel.h \ src/database/tablebase.h \ src/database/bitboard.h \ src/database/openingtree.h \ src/database/version.h \ src/database/playerinfo.h \ src/database/enginelist.h \ src/database/enginedata.h \ src/database/analysis.h \ src/database/editaction.h \ src/guess/attacks.h \ src/guess/common.h \ src/guess/guessengine.h \ src/guess/error.h \ src/guess/guess.h \ src/guess/hash.h \ src/guess/misc.h \ src/guess/movelist.h \ src/guess/position.h \ src/guess/recog.h \ src/guess/sqlist.h \ src/guess/sqmove.h \ src/guess/sqset.h \ src/guess/tokens.h \ src/gui/mainwindow.h \ src/gui/preferences.h \ src/gui/boardview.h \ src/gui/boardtheme.h \ src/gui/boardsetup.h \ src/gui/colorlist.h \ src/gui/savedialog.h \ src/gui/gamelist.h \ src/gui/chessbrowser.h \ src/gui/ecothread.h \ src/gui/quicksearch.h \ src/gui/analysiswidget.h \ src/gui/tableview.h \ src/gui/copydialog.h \ src/gui/messagedialog.h \ src/gui/commentdialog.h \ src/gui/plaintextedit.h \ src/gui/databaselist.h \ src/gui/databaselistmodel.h \ src/gui/dockwidgetex.h \ src/gui/logstream.h \ src/gui/boardsetuptoolbutton.h \ src/gui/GameMimeData.h \ src/database/engineoptiondata.h \ src/gui/engineoptionmodel.h \ src/gui/engineoptiondialog.h \ src/gui/engineoptionlist.h \ src/gui/helpbrowser.h \ src/database/downloadmanager.h \ src/quazip/zip.h \ src/quazip/unzip.h \ src/quazip/quazipnewinfo.h \ src/quazip/quazipfileinfo.h \ src/quazip/quazipfile.h \ src/quazip/quazipdir.h \ src/quazip/quazip.h \ src/quazip/quazip_global.h \ src/quazip/quaziodevice.h \ src/quazip/quagzipfile.h \ src/quazip/quacrc32.h \ src/quazip/quachecksum32.h \ src/quazip/quaadler32.h \ src/quazip/JlCompress.h \ src/quazip/ioapi.h \ src/quazip/crypt.h \ src/gui/toolmainwindow.h \ src/gui/playerlistwidget.h \ src/gui/qled.h \ src/gui/eventlistwidget.h \ src/database/eventinfo.h \ src/gui/renametagdialog.h \ src/gui/openingtreewidget.h \ src/gui/ecolistwidget.h \ src/database/ecoinfo.h \ src/gui/TextBrowserEx.h \ src/gui/loadquery.h \ src/guess/compileeco.h \ src/database/pdbtest.h \ src/gui/aboutdlg.h SOURCES += src/database/board.cpp \ src/database/common.cpp \ src/database/game.cpp \ src/database/databaseconversion.cpp \ src/database/partialdate.cpp \ src/database/playerdatabase.cpp \ src/database/playerdata.cpp \ src/database/engine.cpp \ src/database/wbengine.cpp \ src/database/uciengine.cpp \ src/database/search.cpp \ src/database/query.cpp \ src/database/database.cpp \ src/database/pgndatabase.cpp \ src/database/memorydatabase.cpp \ src/database/filter.cpp \ src/database/tristatetree.cpp \ src/database/nag.cpp \ src/database/settings.cpp \ src/database/spellchecker.cpp \ src/database/historylist.cpp \ src/database/output.cpp \ src/database/outputoptions.cpp \ src/database/databaseinfo.cpp \ src/database/indexitem.cpp \ src/database/index.cpp \ src/database/filtermodel.cpp \ src/database/tablebase.cpp \ src/database/bitboard.cpp \ src/database/openingtree.cpp \ src/database/playerinfo.cpp \ src/database/enginelist.cpp \ src/database/enginedata.cpp \ src/database/analysis.cpp \ src/database/editaction.cpp \ src/guess/guessengine.cpp \ src/guess/guess.cpp \ src/guess/misc.cpp \ src/guess/movelist.cpp \ src/guess/position.cpp \ src/guess/recog.cpp \ src/gui/mainwindow.cpp \ src/gui/mainwindowactions.cpp \ src/gui/mainwindowabout.cpp \ src/gui/colorlist.cpp \ src/gui/preferences.cpp \ src/gui/boardview.cpp \ src/gui/boardtheme.cpp \ src/gui/boardsetup.cpp \ src/gui/savedialog.cpp \ src/gui/gamelist.cpp \ src/gui/quicksearch.cpp \ src/gui/chessbrowser.cpp \ src/gui/analysiswidget.cpp \ src/gui/main.cpp \ src/gui/tableview.cpp \ src/gui/copydialog.cpp \ src/gui/messagedialog.cpp \ src/gui/commentdialog.cpp \ src/gui/plaintextedit.cpp \ src/gui/databaselist.cpp \ src/gui/databaselistmodel.cpp \ src/gui/dockwidgetex.cpp \ src/gui/logstream.cpp \ src/gui/boardsetuptoolbutton.cpp \ src/database/engineoptiondata.cpp \ src/gui/engineoptionmodel.cpp \ src/gui/engineoptiondialog.cpp \ src/gui/engineoptionlist.cpp \ src/gui/helpbrowser.cpp \ src/database/downloadmanager.cpp \ src/quazip/quazipnewinfo.cpp \ src/quazip/quazipfile.cpp \ src/quazip/quazipdir.cpp \ src/quazip/quazip.cpp \ src/quazip/quaziodevice.cpp \ src/quazip/quagzipfile.cpp \ src/quazip/quacrc32.cpp \ src/quazip/quaadler32.cpp \ src/quazip/qioapi.cpp \ src/quazip/JlCompress.cpp \ src/quazip/zip.c \ src/quazip/unzip.c \ src/gui/toolmainwindow.cpp \ src/gui/playerlistwidget.cpp \ src/gui/qled.cpp \ src/gui/eventlistwidget.cpp \ src/database/eventinfo.cpp \ src/gui/renametagdialog.cpp \ src/gui/openingtreewidget.cpp \ src/gui/ecolistwidget.cpp \ src/database/ecoinfo.cpp \ src/gui/loadquery.cpp \ src/guess/compileeco.cpp \ src/database/pdbtest.cpp \ src/gui/aboutdlg.cpp TEMPLATE = app INCLUDEPATH += src/database INCLUDEPATH += src/guess INCLUDEPATH += src/gui INCLUDEPATH += src/quazip INCLUDEPATH += $$[QT_INSTALL_PREFIX]/src/3rdparty/zlib win32 { # Whereever zlib is installed on Windows # Strange enough, on Mac OS this is found automagically by Qt # DEFINES += ZLIB_WINAPI # LIBS += -lz INCLUDEPATH += /Qt/5.1.0/msvc2012_64/include/QtZlib } UI_DIR = src/generated MOC_DIR = src/generated RCC_DIR = src/generated CONFIG(debug, debug|release) { DESTDIR = "debug" OBJECTS_DIR = "obj_dbg" } CONFIG(release, debug|release) { DESTDIR = "release" OBJECTS_DIR = "obj_rel" DEFINES += QT_NO_DEBUG_OUTPUT NDEBUG } static { DESTDIR = "static" OBJECTS_DIR = "obj_static" DEFINES += QT_NO_DEBUG_OUTPUT NDEBUG } !win32 { CONFIG(debug, debug|release) { LIBS += -lz } CONFIG(release, debug|release) { LIBS += -lz } } TARGET = chessx ICON = data/images/chessx.icns RC_FILE = src/chessx.rc macx { INSTALLATION_DATA.files = mac_osx/qt_menu.nib INSTALLATION_DATA.path = Contents/Resources/ QMAKE_BUNDLE_DATA += INSTALLATION_DATA ENGINE_DATA.files = data/engines-mac/uci/stockfish-4-64 ENGINE_DATA.path = Contents/MacOS/data/engines-mac/uci QMAKE_BUNDLE_DATA += ENGINE_DATA QMAKE_INFO_PLIST = mac_osx/Info.plist } unix:!macx { target.path = /usr/local/bin/chessx pixmaps.path = /usr/share/pixmaps pixmaps.files = data/images/chessx.png desktop.path = /usr/share/applications desktop.files = chessx.desktop desktop.extra += xdg-mime install --mode system chessx-x-chess-pgn.xml && desktop.extra += xdg-mime default chessx.desktop application/x-chess-pgn && desktop.extra += xdg-icon-resource install --context mimetypes --size 32 ./data/images/chessx-32.png application-x-chess-pgn && desktop.extra += xdg-icon-resource install --context mimetypes --size 64 ./data/images/chessx-64.png application-x-chess-pgn && desktop.extra += xdg-icon-resource install --context mimetypes --size 128 ./data/images/chessx.png application-x-chess-pgn INSTALLS += target desktop pixmaps } RESOURCES = resources.qrc TRANSLATIONS = i18n/chessx_de.ts \ i18n/chessx_fr.ts # i18n/chessx_it.ts \ # i18n/chessx_pl.ts # i18n/chessx_nl.ts \ # i18n/chessx_pt_BR.ts \ # i18n/chessx_zh.ts isEmpty(QMAKE_LRELEASE) { win32:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]\\lrelease.exe else:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease } isEmpty(TS_DIR):TS_DIR = i18n TSQM.name = lrelease ${QMAKE_FILE_IN} TSQM.input = TRANSLATIONS TSQM.output = $$TS_DIR/${QMAKE_FILE_BASE}.qm TSQM.commands = $$QMAKE_LRELEASE ${QMAKE_FILE_IN} -qm ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.qm TSQM.CONFIG += no_link target_predeps QMAKE_EXTRA_COMPILERS += TSQM PRE_TARGETDEPS += compiler_TSQM_make_all OTHER_FILES += \ data/templates/pgn-default.template \ data/templates/notation-default.template \ data/templates/latex-default.template \ data/templates/html-default.template \ ChangeLog \ COPYING \ i18n/chessx_de.ts \ i18n/chessx_fr.ts \ ChangeLog.txt macx { OTHER_FILES += \ mac_osx/Info.plist \ mac_osx/qt_menu.nib \ data/engines-mac/uci/stockfish-23-64 } win32 { OTHER_FILES += \ src/chessx.rc \ src/chessx.ico } chessx-1.0.0/data/images/folder.png000644 001750 001750 00000005075 12141003207 017745 0ustar00niklasniklas000000 000000 PNG  IHDR>atEXtSoftwareAdobe ImageReadyqe< IDATxO{?01&ZDJJq>F *O܇FjT%!~DJU{҇*1bXM[p(ƪ( ,0ww3{+-pwst8x @AP@AP@AP@AP}!&._?/vM×|^QPDnpR;XFWS'1n}}<BǥR)9u*|4}߭^'LL_@_8uc@d@Z8AjOamn B_t,Wc]btS ȨBHepu( B93L*>O> #G`{kn-݆۷oApGO8Q@#(  `gk;ÿm(ߏ/< R 8ff\=/PɄiUQ@P-#]jLMP122X|.>WIHo߿7v㽷MGUxTyA![PZ^o)vL^X}}Y;xDO( H]1@>o`x跾g{P%55ۿشѰ;39ܷ|KV3ci#?O9'P_{cpùz_I sZ.TXZfx]_PHV;/=TO0{r6<v}}}滓+}]=~ycQ@5 @ehٯ,TC)O XX5hw xg6U=/4?Yr=Z>&KqXc\׹T؟D%nB\q r]“Db3=[g.؝x6eŋZ2;U-kh+4\9Y:ϻc;͡=Ҥݯ5qH3?'kxf{ewkXcbS \,}TS6V7r۹r]wÀ`w5- ^mdq8'HH9IC3 /rc !>53x[JKy $AַϴF'bmk u)lNz (U >ɧG@}*J#`Z6Jd[ZWu:5ۤ@Nt9>.)-~<$C@QNZYiT#nO\\Mycl|yO+2RǬ^< >UdD=u(2# PreferencesDialog 0 0 543 539 Preferences true false 5 &Board 0 0 Qt::Vertical QSizePolicy::Expanding 20 150 &Colors: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop boardColorsList 0 0 0 0 plain outline outline+shadow Highlight current move &Draw frame between squares &Chess set: pieceThemeCombo 0 0 Mouse Behaviour Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft QLayout::SetDefaultConstraint &Guess move on left-click Next guess on right click Wheel sensitivity Qt::Horizontal 40 20 Fast 960 104 120 Qt::Horizontal false QSlider::TicksBothSides 120 Slow Board &style: boardThemeCombo Draw Coordinates Game Autoplayer Auto-Play Interval Qt::Horizontal 40 20 Fast 1000 10000 1000 5000 3000 3000 Qt::Horizontal QSlider::TicksBothSides 3000 Slow Automatically save game and continue with next Qt::Vertical 20 40 &Engines 0 0 300 0 Path to executable 300 0 Path where engine is started - usually place of books Directory: 0 0 Protocol: Name: Options: 0 0 ... Command: Command Line Options WinBoard 0 0 Options 0 0 Qt::LeftToRight ... Qt::Horizontal 40 20 Arbitrary name to identify engine UCI Down QAbstractItemView::NoEditTriggers false QListView::Static false Remove Add... Qt::Vertical 20 40 Up Database Automatic classification with ECO Codes Build index file Commit Database after saving Game MB 0 150 10 &Edit PGN files smaller than: limitSpin Number of recent files: spinBoxRecentFiles 10 4 0 0 Default Database Path: defaultDataBasePath 0 0 Default path for storing files ... Qt::Vertical 20 329 Appearance Font Sizes Game Text: gameTextFontSizeSpin 5 30 14 Lists spinBoxListFontSize 5 30 14 Game Text Show Diagrams Column Style Keep variations inline from level 1 200 Diagram Size 500 Pieces Courier New 14 Put the initials of the pieces here, mind the initial space. KQRBN - Mind the initial space! ... :/images/FlagUK.png:/images/FlagUK.png ... :/images/FlagGermany.png:/images/FlagGermany.png ... :/images/FlagFrance.png:/images/FlagFrance.png ... :/images/FlagPoland.png:/images/FlagPoland.png :/images/new_board.png:/images/new_board.png Qt::ToolButtonIconOnly Colors: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop boardColorsList Qt::Vertical 20 40 App Internet Use online tablebase servers Check for updates (at startup) and language packs Localization Language Qt::Horizontal 40 20 false Changing the language requires restarting the application! Load language file from Server: Load! Qt::Horizontal 40 20 false Appearance Use vertical Tabs Qt::Vertical 20 40 4 4 4 4 Qt::Horizontal QSizePolicy::Expanding 121 29 &Ok true &Apply false &Reset &Cancel ColorList QListWidget

colorlist.h
tabWidget pieceThemeCombo boardThemeCombo engineList addEngineButton deleteEngineButton engineName engineCommand engineOptions engineDirectory engineProtocolUCI engineProtocolWinBoard okButton applyButton cancelButton chessx-1.0.0/src/database/playerinfo.h000644 001750 001750 00000004630 12223260306 020464 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef PLAYERINFO_H #define PLAYERINFO_H #include "common.h" #include "partialdate.h" #include #include #include class Database; typedef QPair EcoFrequencyItem; typedef QList EcoFrequency; class PlayerInfo { public: /** Standard constructor. Does nothing. */ PlayerInfo(); /** Set database and player. Automatically updates information. */ PlayerInfo(Database* db, const QString& player); /** Standard destructor. */ ~PlayerInfo(); /** Changes database. Does not automatically update statistics. */ void setDatabase(Database* db); /** Changes player. Update statistics automatically. */ void setName(const QString& player); /** @return current player name. */ QString name() const; /** Recalculates all statistics. */ void update(); /** @return string with formatted score statistics. */ QString formattedScore() const; /** @return string with formatted date range. */ QString formattedRange() const; /** @return string with formatted rating. */ QString formattedRating() const; /** @return string with formatted game count. */ QString formattedGameCount() const; /** @return string with list of openings played */ QString listOfOpenings() const; private: /** Clears all statistics. */ void reset(); /** Add statistics for game @p index when player has given color. */ void addGameStats(int index, Color color); /** Format score statistics for single color. */ QString formattedScore(const int results[4], int count) const; int toResult(const QString& res) const; QString m_name; Database* m_database; int m_result[2][4]; int m_count[2]; int m_rating[2]; EcoFrequency m_eco[2]; PartialDate m_date[2]; }; #endif chessx-1.0.0/src/database/databaseconversion.h000644 001750 001750 00000002543 12223260306 022167 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005 Ejner Borgbjerg * * (C) 2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ /** DatabaseConversion contains utility functions to convert from various formats into ChessX format. */ #ifndef __DATABASECONVERSION_H__ #define __DATABASECONVERSION_H__ #include "playerdatabase.h" #include class DatabaseConversion { public: /** convert Scid ratings.ssp to player database outFileName is filename without extension inFileName is full path for ratings.ssp pictureDir is directory where player pictures are - format can be jpg, gif, or any format that QImage(file) will understand */ static bool playerDatabaseFromScidRatings(const QString& inFileName, const QString& outFileName, const QString& pictureDir); }; #endif chessx-1.0.0/src/database/filtermodel.h000644 001750 001750 00000006200 12223260306 020615 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2007 Marius Roets * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __FILTERMODEL_H__ #define __FILTERMODEL_H__ #include #include #include #include "filter.h" #include "game.h" /** @ingroup Database The FilterModel class is an interface to Database used with Qt Model/View architecture */ class FilterModel: public QAbstractItemModel { Q_OBJECT public: /** Constructs a FilterModel object using a pointer to a Filter */ FilterModel(Filter* filter, QObject *parent = 0); ~FilterModel(); /** Returns the number of rows in the model */ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; /** Returns the number of columns in the model */ virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; /** Returns an item of data given the item 'index' */ virtual QVariant data(const QModelIndex &index, int role) const; /** Returns the header information for header 'section' */ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; /** Return flags for items (especially drag drop hints) */ Qt::ItemFlags flags(const QModelIndex &index) const; /** No tree - always return invalid parent */ virtual QModelIndex parent(const QModelIndex&) const { return QModelIndex(); } /** No tree - always return self */ virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const; /** No children */ virtual bool hasChildren(const QModelIndex& parent = QModelIndex()) const { return !parent.isValid(); } /** Associated filter */ virtual Filter* filter(); /** Changes current database. Resets any views. */ virtual void setFilter(Filter* filter); /** Get the column tags. */ const QStringList GetColumnTags() { return m_columnTags; } /** Get the column names. */ const QStringList GetColumnNames() { return m_columnNames; } private: /** A pointer to filter on which the model opperates */ Filter* m_filter; /** The column names of the model */ QStringList m_columnNames; /** Map of coulmuns and database tags */ QStringList m_columnTags; /** A pointer to a game object, to hold the retrieved information * about the game */ Game* m_game; /** Current game index - used for caching */ mutable int m_gameIndex; }; #endif // __FilterModelBase_H__ chessx-1.0.0/src/guess/guess.cpp000644 001750 001750 00000004225 12223260306 017357 0ustar00niklasniklas000000 000000 #include "guess.h" #include "position.h" #include "guessengine.h" namespace Guess { Result guessMove(const char* fen, int square, MoveList& mlist, int thinkTime) { Result r; r.error = -1; r.score = 0; squareT sq = square; Position pos; pos.ReadFromFEN(fen); pos.GenerateMoves(&mlist); mlist.SelectBySquare(sq); if(mlist.Size() == 0) { return r; } if(mlist.Size() > 1) { Engine * engine = new Engine(); engine->SetSearchTime(thinkTime); engine->SetPosition(&pos); r.score = engine->Think(&mlist); delete engine; } simpleMoveT * sm = mlist.Get(0); ASSERT(sq == sm->from || sq == sm->to); r.from = sm->from; r.to = sm->to; r.error = 0; return r; } Result evalPos(const char* fen, int thinkTime) { Result r; MoveList mlist; Position pos; pos.ReadFromFEN(fen); r.whiteMove = (pos.GetToMove() == WHITE); Engine * engine = new Engine(); engine->SetSearchTime(thinkTime); engine->SetPosition(&pos); r.score = engine->Think(&mlist); simpleMoveT * sm = mlist.Get(0); r.from = sm->from; r.to = sm->to; r.error = 0; delete engine; return r; } // Use chess engine to decide if (from1,to1) is better than (from2,to2) move // it will start from the position given in fen and think for ms milliseconds // 0 is returned if the first move is better or 1 if the second is better // -1 is returned on error int pickBest(const char* fen, int from1, int to1, int from2, int to2, int ms) { Position pos; pos.ReadFromFEN(fen); MoveList mlist; pos.GenerateMoves(&mlist); mlist.SelectBySquares(from1, to1, from2, to2); if(mlist.Size() == 2) { Engine * engine = new Engine(); engine->SetSearchTime(ms); // Do a "ms" millisecond search engine->SetPosition(&pos); engine->Think(&mlist); delete engine; simpleMoveT * sm = mlist.Get(0); if(sm->from == from1 && sm->to == to1) { return 0; } if(sm->from == from2 && sm->to == to2) { return 1; } } return -1; } } chessx-1.0.0/src/quazip/quagzipfile.cpp000644 001750 001750 00000006221 12223260306 020732 0ustar00niklasniklas000000 000000 #include #include "quagzipfile.h" class QuaGzipFilePrivate { friend class QuaGzipFile; QString fileName; gzFile gzd; inline QuaGzipFilePrivate(): gzd(NULL) {} inline QuaGzipFilePrivate(const QString &fileName): fileName(fileName), gzd(NULL) {} template bool open(FileId id, QIODevice::OpenMode mode, QString &error); gzFile open(int fd, const char *modeString); gzFile open(const QString &name, const char *modeString); }; gzFile QuaGzipFilePrivate::open(const QString &name, const char *modeString) { return gzopen(QFile::encodeName(name).constData(), modeString); } gzFile QuaGzipFilePrivate::open(int fd, const char *modeString) { return gzdopen(fd, modeString); } template bool QuaGzipFilePrivate::open(FileId id, QIODevice::OpenMode mode, QString &error) { char modeString[2]; modeString[0] = modeString[1] = '\0'; if((mode & QIODevice::ReadOnly) != 0 && (mode & QIODevice::WriteOnly) != 0) { error = "Opening zip for both reading and writing is not supported"; return false; } else if((mode & QIODevice::ReadOnly) != 0) { modeString[0] = 'r'; } else if((mode & QIODevice::WriteOnly) != 0) { modeString[0] = 'w'; } else { error = "Opening a file requires a mode"; return false; } gzd = open(id, modeString); if(gzd == NULL) { error = "Could not open file"; return false; } return true; } QuaGzipFile::QuaGzipFile(): d(new QuaGzipFilePrivate()) { } QuaGzipFile::QuaGzipFile(QObject *parent): QIODevice(parent), d(new QuaGzipFilePrivate()) { } QuaGzipFile::QuaGzipFile(const QString &fileName, QObject *parent): QIODevice(parent), d(new QuaGzipFilePrivate(fileName)) { } QuaGzipFile::~QuaGzipFile() { if(isOpen()) { close(); } delete d; } void QuaGzipFile::setFileName(const QString& fileName) { d->fileName = fileName; } QString QuaGzipFile::getFileName() const { return d->fileName; } bool QuaGzipFile::isSequential() const { return true; } bool QuaGzipFile::open(QIODevice::OpenMode mode) { QString error; if(!d->open(d->fileName, mode, error)) { setErrorString(error); return false; } return QIODevice::open(mode); } bool QuaGzipFile::open(int fd, QIODevice::OpenMode mode) { QString error; if(!d->open(fd, mode, error)) { setErrorString(error); return false; } return QIODevice::open(mode); } bool QuaGzipFile::flush() { return gzflush(d->gzd, Z_SYNC_FLUSH) == Z_OK; } void QuaGzipFile::close() { QIODevice::close(); gzclose(d->gzd); } qint64 QuaGzipFile::readData(char *data, qint64 maxSize) { return gzread(d->gzd, (voidp)data, (unsigned)maxSize); } qint64 QuaGzipFile::writeData(const char *data, qint64 maxSize) { if(maxSize == 0) { return 0; } int written = gzwrite(d->gzd, (voidp)data, (unsigned)maxSize); if(written == 0) { return -1; } else { return written; } } chessx-1.0.0/src/gui/plaintextedit.cpp000644 001750 001750 00000001456 12223260306 020550 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2010 by Michal Rudolf * ****************************************************************************/ #include "plaintextedit.h" PlainTextEdit::PlainTextEdit(QWidget *parent) : QPlainTextEdit(parent) { } void PlainTextEdit::keyPressEvent(QKeyEvent* event) { if(event->key() == Qt::Key_Return && event->modifiers() == Qt::NoModifier) { event->ignore(); return; } if(event->key() == Qt::Key_Return && event->modifiers() == Qt::ControlModifier) { event->ignore(); QKeyEvent event2(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier); QPlainTextEdit::keyPressEvent(&event2); } QPlainTextEdit::keyPressEvent(event); } chessx-1.0.0/src/database/bitboard.h000644 001750 001750 00000031415 12223260306 020103 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2003 Sune Fischer * * (C) 2005-2006 Marius Roets * * (C) 2005-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "movelist.h" #ifndef __BITBOARD_H__ #define __BITBOARD_H__ enum BoardStatus { Valid, NoWhiteKing, NoBlackKing, DoubleCheck, OppositeCheck, TooManyBlackPawns, TooManyWhitePawns, PawnsOn18, TooManyKings, TooManyWhite, TooManyBlack, BadCastlingRights, InvalidEnPassant, MultiCheck }; /** @ingroup Core * Keep track of the pieces on a chessboard, provide a Move() factory. */ class BitBoard { public: BitBoard(); // Play moves on board // /** Play given move, updating board state appropriately */ bool doMove(const Move&); /** Return board to state prior to given move */ void undoMove(const Move&); // Setup board // /** Remove all pieces and state from board */ void clear(); /** Set move number in game */ void setMoveNumber(unsigned int moveNumber); /** Set initial chess game position on the board */ void setStandardPosition(); /** Set the given piece on the board at the given square */ void setAt(const Square s, const Piece p); /** Remove any piece sitting on given square */ void removeAt(const Square s); /** Set side to move as that of given color */ void setToMove(const Color& c); /** Swap the side to move */ void swapToMove(); /** Parse given FEN, return true if loaded properly otherwise false */ bool fromFen(const QString& fen); /** Set En Passant Square */ void setEnPassantSquare(const Square s); /** Remove En Passant privilege */ void clearEnPassantSquare(); // Move factories // /** parse SAN or LAN representation of move, and return proper Move() object */ Move parseMove(const QString& algebraic) const; /** Return a proper Move() object given only a from-to move specification */ Move prepareMove(const Square& from, const Square& to) const; // Return a nullMove -- King to the same square Move nullMove() const; // Query // /** Is piece sitting on given square moveable ? */ bool isMovable(const Square s) const; /** @return piece sitting at given square on the board */ Piece pieceAt(Square s) const; /** @return number of ply since a pawn move or capture */ unsigned int halfMoveClock() const; /** Set number of ply since a pawn move or capture */ void setHalfMoveClock(unsigned int i); /** @return the current move number in the game */ unsigned int moveNumber() const; /** @return color of side next to move */ Color toMove() const; /** @return true if its possible for this position to follow target position */ bool canBeReachedFrom(const BitBoard& target) const; /** @return true if position is same, but don't consider Move # in determination */ bool positionIsSame(const BitBoard& target) const; // Query other formats // /** Return a FEN string based on current board position */ QString toFen() const; /** Return a FEN string in human readable format based on current board position */ QString toHumanFen() const; /** Return a SAN string representation of given move */ QString moveToSan(const Move& move, bool translate = false) const; /** @return a SAN string representing a given move with move number. */ QString moveToFullSan(const Move& move) const; // Validation // /** Check current position and return "Valid" or problem */ BoardStatus validate() const; /** Return true if given FEN can be parsed */ bool isValidFen(const QString& fen) const; /** Return true if fastbits option was compiled in */ static const bool fastbitsOption; /** Set castling rights. */ void setCastlingRights(CastlingRights cr); /** Return the internal castling rights data (used by hash function) */ CastlingRights castlingRights() const; /** Return square where En passant capture may occur, or "NoEPSquare" */ Square enPassantSquare() const; private: /** Return true if side to move is in check */ bool isCheck() const; /** Return true if the side to move is in checkmate */ bool isCheckmate() const; /** Return true if the side to move is stalemated */ bool isStalemate() const; /** Test to see if given color has the right to castle on kingside */ bool canCastleShort(const unsigned int color) const; /** Test to see if given color has the right to castle on queenside */ bool canCastleLong(const unsigned int color) const; /** Test to see if given color has any castling rights remaining */ bool canCastle(const unsigned int color) const; /** Return true if making move would put oneself into check */ bool isIntoCheck(const Move& move) const; /** Return true if the given square is attacked by the given color */ bool isAttackedBy(const unsigned int color, const unsigned int square) const; /** Return all squares attacked by a knight on given square */ quint64 knightAttacksFrom(const Square s) const; /** Return all squares attacked by a bishop on given square */ quint64 bishopAttacksFrom(const Square s) const; /** Return all squares attacked by a rook on given square */ quint64 rookAttacksFrom(const Square s) const; /** Return all squares attacked by a queen on given square */ quint64 queenAttacksFrom(const Square s) const; /** Return all squares attacked by a king on given square */ quint64 kingAttacksFrom(const Square s) const; /** Return all possible pawn moves from given square */ quint64 pawnMovesFrom(const Square s) const; /** Remove impossible moves from given bitboard to aid disambiguation */ void removeIllegal(const Move& move, quint64& b) const; /** Update move with castling details, return false if no castle is possible */ bool prepareCastle(Move& move) const; /** Generate all possible moves in a given position */ MoveList generateMoves() const; /** Grant castling rights on the kingside to the given color */ void setCastleShort(unsigned int color); /** Grant castling rights on the queenside to the given color */ void setCastleLong(unsigned int color); /** Revoke all castling rights from the given color */ void destroyCastle(unsigned int color); /** Update the epSquare value based on a new epFile value */ void epFile2Square(); /** Setup board according to FEN string */ bool fromGoodFen(const QString& fen); // Actual Bit-board data quint64 m_pawns, m_knights, m_bishops, m_rooks, m_queens, m_kings; quint64 m_occupied_co[2]; // Square mask of those occupied by each color quint64 m_occupied; // Square is empty or holds a piece quint64 m_occupied_l90; // rotated counter clockwise 90 deg quint64 m_occupied_l45; // an odd transformation, to straighten out diagonals quint64 m_occupied_r45; // the opposite odd transformation, just as messy // Extra state data uchar m_piece[64]; // type of piece on this square uchar m_stm; // side to move uchar m_ksq[2]; // square of the m_kings uchar m_epFile; // file of a possible ep capture uchar m_epSquare; // This is requested by hash routine enough that we keep it pre calculated uchar m_castle; // flags for castle legality (these can be merged) unsigned short m_halfMoves; // Number of moves since last pawn move or capture unsigned int m_moveNumber; // Move number in game (incremented after each black move) uchar m_pawnCount[2]; // Number of pawns for each side uchar m_pieceCount[2]; // Number of pieces INCLUDING pawns for each side }; extern quint64 bb_PawnAttacks[2][64]; extern quint64 bb_KnightAttacks[64]; extern quint64 bb_R45Attacks[64][64]; extern quint64 bb_L45Attacks[64][64]; extern quint64 bb_KingAttacks[64]; extern quint64 bb_RankAttacks[64][64]; extern quint64 bb_FileAttacks[64][64]; const unsigned int bb_ShiftR45[64] = { 1, 58, 51, 44, 37, 30, 23, 16, 9, 1, 58, 51, 44, 37, 30, 23, 17, 9, 1, 58, 51, 44, 37, 30, 25, 17, 9, 1, 58, 51, 44, 37, 33, 25, 17, 9, 1, 58, 51, 44, 41, 33, 25, 17, 9, 1, 58, 51, 49, 41, 33, 25, 17, 9, 1, 58, 57, 49, 41, 33, 25, 17, 9, 1 }; const unsigned int bb_ShiftL45[64] = { 9, 17, 25, 33, 41, 49, 57, 1, 17, 25, 33, 41, 49, 57, 1, 10, 25, 33, 41, 49, 57, 1, 10, 19, 33, 41, 49, 57, 1, 10, 19, 28, 41, 49, 57, 1, 10, 19, 28, 37, 49, 57, 1, 10, 19, 28, 37, 46, 57, 1, 10, 19, 28, 37, 46, 55, 1, 10, 19, 28, 37, 46, 55, 64 }; inline bool BitBoard::isAttackedBy(const unsigned int color, const unsigned int square) const { if(bb_PawnAttacks[color ^ 1][square] & (m_pawns | m_bishops) & m_occupied_co[color]) { return 1; } if(knightAttacksFrom(square) & m_knights & m_occupied_co[color]) { return 1; } if(bishopAttacksFrom(square) & (m_bishops | m_queens) & m_occupied_co[color]) { return 1; } if(rookAttacksFrom(square) & (m_rooks | m_queens) & m_occupied_co[color]) { return 1; } if(kingAttacksFrom(square) & (m_kings | m_queens) & m_occupied_co[color]) { return 1; } return 0; }; inline void BitBoard::setCastleShort(unsigned int color) { m_castle |= 1 << color; } inline void BitBoard::setCastleLong(unsigned int color) { m_castle |= 4 << color; } inline void BitBoard::destroyCastle(unsigned int color) { m_castle &= ~(5 << color); } inline quint64 BitBoard::knightAttacksFrom(const Square s) const { return bb_KnightAttacks[s]; } inline quint64 BitBoard::bishopAttacksFrom(const Square s) const { return bb_R45Attacks[s][(m_occupied_r45 >> bb_ShiftR45[s]) & 63] | bb_L45Attacks[s][(m_occupied_l45 >> bb_ShiftL45[s]) & 63]; } inline quint64 BitBoard::rookAttacksFrom(const Square s) const { return bb_RankAttacks[s][(m_occupied >> ((s & ~7) + 1)) & 63] | bb_FileAttacks[s][(m_occupied_l90 >> (((s & 7) << 3) + 1)) & 63]; } inline quint64 BitBoard::queenAttacksFrom(const Square s) const { return rookAttacksFrom(s) | bishopAttacksFrom(s); } inline quint64 BitBoard::kingAttacksFrom(const Square s) const { return bb_KingAttacks[s]; } inline void BitBoard::epFile2Square() { if(m_epFile) { m_epSquare = m_epFile + (m_stm == White ? a6 : a3) - 1; } else { m_epSquare = NoEPSquare; } } inline bool BitBoard::canCastle(const unsigned int color) const { return m_castle & (5 << color); } inline bool BitBoard::canCastleShort(const unsigned int color) const { return m_castle & (1 << color); } inline bool BitBoard::canCastleLong(const unsigned int color) const { return m_castle & (4 << color); } inline bool BitBoard::isCheck() const { return isAttackedBy(m_stm ^ 1, m_ksq[m_stm]); } inline unsigned int BitBoard::halfMoveClock() const { return m_halfMoves; } inline void BitBoard::setHalfMoveClock(unsigned int i) { m_halfMoves = i; } inline unsigned int BitBoard::moveNumber() const { return m_moveNumber; } inline Color BitBoard::toMove() const { return Color(m_stm); } inline Square BitBoard::enPassantSquare() const { return m_epSquare; } inline CastlingRights BitBoard::castlingRights() const { return m_castle; } inline void BitBoard::setCastlingRights(CastlingRights cr) { m_castle = cr; } /** Set the side to move to the given color */ inline void BitBoard::setToMove(const Color& c) { m_stm = c; } inline void BitBoard::swapToMove() { m_stm ^= 1; } inline void BitBoard::setMoveNumber(unsigned int moveNumber) { m_moveNumber = moveNumber; } inline bool BitBoard::positionIsSame(const BitBoard& target) const { if(m_occupied_co[White] != target.m_occupied_co[White] || m_occupied_co[Black] != target.m_occupied_co[Black] || m_pawns != target.m_pawns || m_knights != target.m_knights || m_bishops != target.m_bishops || m_rooks != target.m_rooks || m_queens != target.m_queens || m_kings != target.m_kings || m_stm != target.m_stm) { return false; } return true; } #endif // __BITBOARD_H__ chessx-1.0.0/src/gui/mainwindow.h000644 001750 001750 00000042647 12223260306 017522 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2009 by Michal Rudolf mrudolf@kdewebdev.org * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __MAINWINDOW_H__ #define __MAINWINDOW_H__ #include "common.h" #include "historylist.h" #include "move.h" #include "output.h" #include #include #include #include class Analysis; class AnalysisWidget; class Board; class BoardView; class ChessBrowser; class Database; class DatabaseInfo; class DatabaseList; class DownloadManager; class ECOListWidget; class EcoThread; class EditAction; class EventListWidget; class Game; class GameList; class OpeningTreeWidget; class PlayerListWidget; class QLabel; class QNetworkAccessManager; class QNetworkReply; class QProgressBar; class QSplitter; class QTimer; class QToolBar; class SaveDialog; class TableView; class ToolMainWindow; /** @defgroup GUI GUI - User interface components */ /** @ingroup GUI The MainWindow class represents main ChessX window. */ class MainWindow: public QMainWindow { Q_OBJECT public: MainWindow(); ~MainWindow(); static const int MaxRecentFiles = 10; protected: /** QObjects Eventfilter for QApplication events */ bool eventFilter(QObject *obj, QEvent *event); /** Overridden to ask for confirmation */ void closeEvent(QCloseEvent* e); /** Filter key events. */ void keyPressEvent(QKeyEvent *e); /** @return active database */ Database* database(); /** @return active database structure */ DatabaseInfo* databaseInfo(); /** @return database name of database @p index (or active, if no parameter). */ QString databaseName(int index = -1) const; /** @return active database structure */ const DatabaseInfo* databaseInfo() const; /** @return active game */ Game& game(); const Game& game() const; /** @return index of active game */ int gameIndex() const; /** Edit comment */ bool gameEditComment(Output::CommentType type); /** Get export filename*/ QString exportFileName(int& format); /** Load game @p index. If @p force is false, does nothing for incorrect @p index . With @p force set, creates empty game. */ void gameLoad(int index, bool force = false, bool reload = 0); /** Make given number of moves in current game */ bool gameMoveBy(int change); /** Update recent files menu */ void updateMenuRecent(); /** Update recent files menu */ void updateMenuDatabases(); /** Save Game dialog (created when used first) */ SaveDialog* saveDialog(); public slots: /** Open database */ void openDatabase(QString fname); /** Open database from URL*/ void openDatabaseUrl(QString fname, bool utf8); /** Open a list of databases from a ZIP archive */ void openDatabaseArchive(QString fname, bool utf8); /** Open database from a local File */ void openDatabaseFile(QString fname, bool utf8); /** Add favorite status to a database */ void setFavoriteDatabase(QString fname); /** Promote current variation. */ void slotEditVarPromote(); /** Remove current variation. */ void slotEditVarRemove(); /** Show Setup Position dialog and set current board. */ void slotEditBoard(); /** Edit current comment. */ void slotEditComment(); /** Edit current comment. */ void slotEditCommentBefore(); /** Set position's FEN to clipboard. */ void slotEditCopyFEN(); /** Set position's human readable FEN to clipboard. */ void slotEditCopyHumanFEN(); /** Set position using FEN from clipboard. */ void slotEditPasteFEN(); /** Set position's PGN to clipboard. */ void slotEditCopyPGN(); /** Set position using PGN from clipboard. */ bool slotEditPastePGN(); /** Set position using PGN from clipboard. */ void slotEditPaste(); /** Set game or position from clipboard */ void slotEditCopyImage(); /** Truncate moves to the end of the game. */ void slotEditTruncateEnd(); /** Truncate moves from the beginning of the game. */ void slotEditTruncateStart(); /** */ void slotReconfigure(); /** */ void slotConfigure(); /** About ChessX */ void slotHelpAbout(); /** Display Tracker at ChessX SourceForge */ void slotHelpBug(); void slotConfigureFlip(); /** Go to first move of the game */ void slotGameMoveFirst() { gameMoveBy(-999); } /** Go to next move of the game */ bool slotGameMoveNext(); /** Go to previous move of the game */ void slotGameMovePrevious() { gameMoveBy(-1); } /** Go to first move of the game */ void slotGameMoveLast() { gameMoveBy(999); } /** Go N moves forward in the game. For now fixed at @p 10 */ void slotGameMoveNextN() { gameMoveBy(10); } /** Go N moves backward in the game. For now fixed at @p 10 */ void slotGameMovePreviousN() { gameMoveBy(-10); } /** Load first game */ void slotGameLoadFirst(); /** Load next game */ void slotGameLoadNext(); /** Load previous game */ void slotGameLoadPrevious(); /** Load last game */ void slotGameLoadLast(); /** Load random game */ void slotGameLoadRandom(); /** Choose a game and load it */ void slotGameLoadChosen(); /** Enter variation. */ void slotGameVarEnter(); /** Enter previous variation. */ void slotGameVarUp(); /** Enter next variation. */ void slotGameVarDown(); /** Exit variation. */ void slotGameVarExit(); /** Modify game on user's request. */ void slotGameModify(const EditAction& action); /** Get a pointer or Null to the active game. */ void slotGetActiveGame(const Game** game); /** Merge the game with index @p gameIndex into the active game. */ void slotMergeActiveGame(int gameIndex); /** Merge all games from the database into the active game. */ void slotMergeAllGames(); /** Merge all games from the filter into the active game. */ void slotMergeFilter(); /** Update GameView content after game was change. Triggers also @ref slotMoveChanged. */ void slotGameChanged(); /** Handle link click in Game View panel */ void slotGameViewLink(const QUrl& link); /** Handle link click in Game View panel */ void slotGameViewLink(const QString& link); /** Get GameView source. */ void slotGameViewSource(); /** Dump all node information to the console */ void slotGameDumpMoveNodes(); /** Create new empty game (to be appended to the database. */ void slotGameNew(); /** Save game, replacing old one if it is edited, appending if it is new @return false if the saving was cancelled, true if changes are to be saved or discarded. */ bool slotGameSave(); /** Add variation to current position. */ void slotGameAddVariation(const Analysis& analysis); /** Add variation to current position. */ void slotGameAddVariation(const QString& san); /** Remove all comments. */ void slotGameUncomment(); /** Remove all variations */ void slotGameRemoveVariations(); /** Start / Stop AutoPlay feature */ void slotToggleAutoPlayer(); /** Auto Play Timeout - make next move! */ void slotToggleAutoAnalysis(); /** Auto Play Timeout - make next move! */ void slotAutoPlayTimeout(); /** Filter was changed - update status bar information */ void slotFilterChanged(); /** Load given game (triggered from Game List) */ void slotFilterLoad(int index); /** Creates an empty chessxdatabase*/ void slotFileNew(); /** Open File dialog, choose a database and open it */ void slotFileOpen(); /** Open File dialog, choose a database and open it in UTF8 format */ void slotFileOpenUtf8(); /** Save database to current file. */ void slotFileSave(); /** Open given database from Recent files list. */ void slotFileOpenRecent(); /** Exports game to selected file type. */ void slotFileExportGame(); /** Exports games in filter to selected file type. */ void slotFileExportFilter(); /** Exports all games to selected file type. */ void slotFileExportAll(); /** Close current database. Switches to next active (or clipboard if there is none). */ void slotFileClose(); /** Close selected database. */ void slotFileCloseIndex(int); /** Close selected database. */ void slotFileCloseName(QString fname); /** Quit ChessX. Ask for confirmation before */ void slotFileQuit(); /** Find games matching single tag. */ void slotSearchTag(); /** Find current position */ void slotSearchBoard(); /** Receives the signal of a search board operation started */ void slotBoardSearchStarted(); /** Receives the signal of a search board operation end */ void slotBoardSearchUpdate(); /** Reset current filter */ void slotSearchReset(); /** Training mode */ void slotToggleTraining(); /** Toggle filter */ void slotToggleFilter(); /** Reverse current filter */ void slotSearchReverse(); /** Make an Update of the game list after the opening tree was updated */ void slotTreeUpdate(); /** Indicate start of tree update */ void slotTreeUpdateStarted(); /** Show opening tree */ void slotSearchTree(); /** Move @p index was selected in Opening Tree. */ void slotSearchTreeMove(const QModelIndex& index); /** Made given move on the board */ void slotBoardMove(Square from, Square to, int button); /** Board square was clicked */ void slotBoardClick(Square square, int button, QPoint pos, Square from); /** Browse current game by mouse wheel */ void slotBoardMoveWheel(int wheel); /** Update GUI after current move was changed. Update BoardView to current board, updates GameInfo and highlight current move in GameView. */ void slotMoveChanged(); /** Show temporary message. */ void slotStatusMessage(const QString& msg); /** Show progress bar for open file. */ void slotOperationProgress(int progress); /** Change database. */ void slotDatabaseChange(); /** Copy games between databases. */ void slotDatabaseCopy(int preselect = 1); /** Copy games between databases. */ void slotDatabaseCopySingle(int n); /** Database was changed - change informations. */ void slotDatabaseChanged(); /** Delete current game. */ void slotDatabaseDeleteGame(int n); /** Delete all game in filter. */ void slotDatabaseDeleteFilter(); /** Slot that updates internal info upon loading a complete db */ void slotDataBaseLoaded(DatabaseInfo* db); /** Fill up the current game (drag request from game list) */ void slotGetGameData(Game& g); /** Copy game from other database by drag'n'drop */ void copyGame(QString fileName, int index); /** Copy all games from other database by drag'n'drop */ void copyDatabase(QString target, QString src); /** Request renaming a event in the current database */ void slotRenameEvent(QString ts); /** Request renaming a player in the current database */ void slotRenamePlayer(QString ts); /** Pass a tag changing request from rename dialog to database */ void slotRenameRequest(QString tag, QString newValue, QString oldValue); protected slots: /** Receiver for a failed loading of a database */ void loadError(QUrl url); /** Receiver for a successful loading of a database */ void loadReady(QUrl url, QString fileName); /** Remove Color of the square in m_annotationSquare */ void slotNoColorSquare(); /** Colorize the square in m_annotationSquare green */ void slotGreenSquare(); /** Colorize the square in m_annotationSquare yellow */ void slotYellowSquare(); /** Colorize the square in m_annotationSquare red */ void slotRedSquare(); /** Remove any arrow */ void slotNoArrowHere(); /** Draw a green arrow */ void slotGreenArrowHere(); /** Draw a yellow arrow */ void slotYellowArrowHere(); /** Draw a red arrow */ void slotRedArrowHere(); /** Set the Stay On Top Property */ void slotToggleStayOnTop(); /** Create a new, empty Board document */ void slotCreateBoardView(); /** Activate an existing board document */ void slotActivateBoardView(int); /** Activate an existing board document */ void slotCloseBoardView(int n = -1); /** Make a screenshot and save it to file */ void slotScreenShot(); /** Make a screenshot and save it to file */ void slotCompileECO(); protected: bool pasteFen(QString& errorText, QString fen); void copyGame(int target, int index); Database* getDatabaseByPath(QString path); DatabaseInfo* getDatabaseInfoByPath(QString path); void activateBoardView(int n); signals: /** Re-read configuration. */ void reconfigure(); /** Main game has been updated. */ void boardChange(const Board& board); /** Current database changed. */ void databaseChanged(DatabaseInfo* databaseInfo); /** Emitted upon finishing a file download */ void LoadFinished(DatabaseInfo*); /** Emitted upon a update for the elapsed / clock time */ void displayTime(const QString&, Color); void signalMoveHasVariation(bool); void signalVariationHasSibling(bool); void signalMoveHasPreviousMove(bool); void signalMoveHasNextMove(bool); void signalMoveHasParent(bool); void signalGameIsEmpty(bool); void signalCurrentDBisReadWrite(bool); void signalCurrentDBcanBeClosed(bool); void signalCurrentDBhasGames(bool); void signalFirstGameLoaded(bool); void signalLastGameLoaded(bool); void signalVersionFound(int, int, int); void databaseModified(); private slots: /** Cleanup after ECO file loaded. */ void ecoLoaded(QObject*, bool); void slotDatabaseModified(); void slotHttpDone(QNetworkReply *reply); void slotVersionFound(int major, int minor, int build); private: /** Create single menu action. */ QAction* createAction(const QString& name, const char* slot, const QKeySequence& key = QKeySequence(), QToolBar* pToolBar = 0, QString image = QString(), const QString& tip = QString(), QAction::MenuRole menuRole = QAction::NoRole); /** Create all the menus and actions */ void setupActions(); /** Confirm quitting and save modified databases. */ bool confirmQuit(); /** Start operation with progress reporting. Shows progress bar. */ void startOperation(const QString& msg); /** Finish operation with progress reporting. Hides progress bar. */ void finishOperation(const QString& msg); /** Cancel operation with progress reporting. Hides progress bar. */ void cancelOperation(const QString& msg); /** Restore the list of recent files */ void restoreRecentFiles(); /** Query User and save game if game was modified @return true if the next action shall be performed */ bool QuerySaveGame(); /** Save game without query */ void saveGame(); /** Load next game without query */ void loadNextGame(); /** Save Database without query or progress bar */ void saveDatabase(); /** Save Database with query */ bool QuerySaveDatabase(); /** Create a new unassociated boardview */ BoardView* CreateBoardView(); /** Update Board Information */ void UpdateBoardInformation(); /** Update Game Title */ void UpdateGameTitle(); /** Update Game Text */ void UpdateGameText(); /** Check if an update is available online */ void StartCheckUpdate(); /** Check if download of database is an option */ void StartCheckDatabase(); /* Dialogs */ GameList* m_gameList; PlayerListWidget* m_playerList; ECOListWidget* m_ecoList; EventListWidget* m_eventList; DatabaseList* m_databaseList; SaveDialog* m_saveDialog; /* Main gui parts */ BoardView* m_boardView; QSplitter* m_boardSplitter; ChessBrowser* m_gameView; OpeningTreeWidget* m_openingTreeWidget; QProgressBar* m_progressBar; ToolMainWindow* m_gameWindow; QToolBar* m_gameToolBar; QTabWidget* m_tabWidget; QList m_boardViews; /* Status */ QLabel* m_statusFilter; QLabel* m_gameTitle; /* Menus */ QMenu* m_menuDatabases; QMenu* m_menuView; /* Local variables */ HistoryList m_recentFiles; QStringList m_favoriteFiles; Output* m_output; QList m_databases; QList m_recentFileActions; QList m_databaseActions; int m_currentDatabase; QString m_eco; QActionGroup* m_actions; QTime m_operationTime; /** Currently updated tree. May be NULL if no update in progress. */ QString m_nagText; QTimer* m_autoPlayTimer; QAction* m_toggleFilter; bool m_bGameChange; int m_currentFrom; int m_currentTo; AnalysisWidget* m_mainAnalysis; Board m_AutoInsertLastBoard; Square m_annotationSquare; Square m_annotationSquareFrom; QAction* m_training; QAction* m_autoPlay; QAction* m_autoAnalysis; QUndoGroup m_undoGroup; QNetworkAccessManager* m_manager; DownloadManager* downloadManager; }; #endif chessx-1.0.0/src/database/partialdate.cpp000644 001750 001750 00000012277 12223260306 021147 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "partialdate.h" #include PartialDate::PartialDate(int y, int m, int d) : m_year(y), m_month(m), m_day(d) { m_bIsValid = !m_year || asDate().isValid(); } PartialDate::PartialDate(const QString& s) { m_year = 0; m_month = 0; m_day = 0; fromString(s); } PartialDate::PartialDate(const QDate& d) { m_bIsValid = true; m_year = d.year(); m_month = d.month(); m_day = d.day(); } PartialDate PartialDate::today() { return PartialDate(QDate::currentDate()); } int PartialDate::year() const { return m_year; } int PartialDate::month() const { return m_month; } int PartialDate::day() const { return m_day; } PartialDate& PartialDate::fromString(const QString& s) { QString test = s.trimmed(); QRegExp regExp("^[\\?0-9]{4}([\\./]([\\?0-9]){1,2}){,2}$"); if(regExp.exactMatch(test) || test.isEmpty()) { QRegExp sep("[\\./]"); m_year = test.section(sep, 0, 0).toInt(); m_month = test.section(sep, 1, 1).toInt(); m_day = test.section(sep, 2, 2).toInt(); m_bIsValid = !year() || asDate().isValid(); } else { QRegExp regExpContinental("^(([\\?0-9]){1,2}\\.){,2}[\\?0-9]{4}$"); if(regExpContinental.exactMatch(test)) { m_day = test.section('.', 0, 0).toInt(); m_month = test.section('.', 1, 1).toInt(); m_year = test.section('.', 2, 2).toInt(); m_bIsValid = !year() || asDate().isValid(); } else { QRegExp regExpAmerican("^(([\\?0-9]){1,2}/){,2}[\\?0-9]{4}$"); if(regExpAmerican.exactMatch(test)) { m_month = test.section('/', 0, 0).toInt(); m_day = test.section('/', 1, 1).toInt(); m_year = test.section('/', 2, 2).toInt(); m_bIsValid = !year() || asDate().isValid(); } } } return *this; } QDate PartialDate::asDate() const { return QDate(m_year, m_month ? m_month : 1, m_day ? m_day : 1); } bool PartialDate::isValid() const { return m_bIsValid; } QString PartialDate::asString() const { if(!m_year) { return "????.??.??"; } QString s = QString("%1.%2.%3") .arg(m_year, 4) .arg(m_month, 2) .arg(m_day, 2); return s; } QString PartialDate::asShortString(int part) const { if(!m_year) { return QString(); } QString s; if(part & Year) { s = numberToString(m_year, 4); } if(!m_month) { return s; } if(part & Month) { if(!s.isEmpty()) { s += '.'; } s += numberToString(m_month); } if(!m_day) { return s; } if(part & Day) { if(!s.isEmpty()) { s += '.'; } s += numberToString(m_day); } return s; } QString PartialDate::numberToString(int d, QChar fill) const { if(!d) { return QString(fill) + fill; } return d < 10 ? fill + QString::number(d) : QString::number(d); } bool operator==(const PartialDate& d1, const PartialDate& d2) { return d1.year() == d2.year() && d1.month() == d2.month() && d1.day() == d2.day(); } bool operator<(const PartialDate& d1, const PartialDate& d2) { return d2.year() > d1.year() || ((d2.year() == d1.year()) && (d2.month() > d1.month() || (d2.month() == d1.month() && d2.day() > d1.day()))); } bool operator>(const PartialDate& d1, const PartialDate& d2) { return d1.year() > d2.year() || ((d1.year() == d2.year()) && (d1.month() > d2.month() || (d1.month() == d2.month() && d1.day() > d2.day()))); } bool operator>=(const PartialDate& d1, const PartialDate& d2) { return d2 < d1 || d2 == d1; } bool operator<=(const PartialDate& d1, const PartialDate& d2) { return d2 > d1 || d2 == d1; } bool operator!=(const PartialDate& d1, const PartialDate& d2) { return d1.year() != d2.year() || d1.month() != d2.month() || d1.day() != d2.day(); } QString PartialDate::range(const PartialDate& d) const { if(year() != d.year()) { return asShortString() + "-" + d.asShortString(); } QString result = numberToString(year()); if(month() != d.month()) return QString("%1.%2-%3").arg(year()).arg(asShortString(Month | Day)) .arg(d.asShortString(Month | Day)); else if(day() != d.day()) return QString("%1.%2.%3-%4").arg(year()).arg(month()) .arg(asShortString(Day)).arg(d.asShortString(Day)); else { return asShortString(); } } chessx-1.0.0/src/guess/compileeco.h000644 001750 001750 00000000264 12210654515 020021 0ustar00niklasniklas000000 000000 #ifndef _COMPILEECO_H_ #define _COMPILEECO_H_ #include bool compileAsciiEcoFile(const QString& filenameIn, const QString& filenameOut, const QString& gtmFile); #endif chessx-1.0.0/data/help/about1.html000644 001750 001750 00000022130 12204662031 017525 0ustar00niklasniklas000000 000000 ChessX Manual

ChessX Manual

Opening a database

You can open a database either from the File menu or drag a file from Explorer / Finder into the Databases view.

You can make a database stay permanently in the database list by turning it into a "Favorite" (right-click the file). A database is reopened from there by clicking the asterisk or again by the context menu.

You can also drag files from yor Internet Browser into the ChessX Database List, they are downloaded into the configured default path (see the Preferences-Advanced-Default Data Path entry). If they are compressed (zip), the archive is stored at the Default Data Path and its content is extracted. Again, if there is something like PGN inside, the files are opened afterwards.

Making moves

A move is done by gabbing a piece and dragging it to another square.

Depending on your settings in the board preferences, you can either

  • Click on a piece and a target square (if move guesses are deactivated)
  • Click on a piece and accepting the move quess (in case of deactivated next guess on right click)
  • Right Click on a piece and then again until the correct target square is high-lighted, then press the left mouse button to make the move (in case right click is used for next guess).

Going back a move can be done by a right-click (in case the right click is not configured for backtracking a move) or by pressing CTRL-right click if backtracking is assigned to the right mouse key.

Usually, making a move will insert a new variation unless you are at the end of the game or a variation. If you do not want to create a new variation, press CTR while moving, which replaces the current move and all following moves by the new move.

If you want to exchange a move without deleting subsequent moves, you can press CTRL+ALT while moving, this will exchange the move played with the new move and check the remaining game for illegal positions. The game is then truncated at these illegal positions.

If you want ChessX to replay the game, select "Game->Auto Player". You can change the move rate in the Game Preferences.

Annotating moves

Move annotations can be done by activating the context menu in the games text browser or by simply pressing the corresponding key sequence, e.g. '!?','!!','??','!x','?x','=','+-','-+' and so on, where 'x' is used in case the first character is ambiguous, 'x' can be the Return/Enter-Key or literally the small letter 'x'.

You can make special annotations like drawing an arrow or coloring squares by pressing Shift+Right-Mouse-Clicking (either select a single square or make a drawing gesture for drawing an arrow).

Saving games

Saving games is slightly confusing! A game needs to be saved into the database (Press CTRL+S, Menu Game/Save). From there, the whole database needs to be saved to disk by pressing CTRL+Shift+S / Menu File/Save. This is somewhat inconvenient but on the other hand prevents you from mistakenly overwriting games or files.

If you want to commit a database to harddisk immediatelly and automatically when saving a game, you can select Option "Commit Database after Saving Game" from the Database Pane in the Preferences Dialog.

By default, a clipboard database is open, which does not have a backing file on disk. Anything that remains in the Clipboard is lost upon closing ChessX! So you need to open at least one other database for writing and transfer anything from the Clipboard into this database by either dragging the games to that database or using "Copy Games" from the Database menu.

Switching databases

Switching between open databases can be achieved by either the Database menu, pressing CTRL+Number 0 .. 9 or right-clicking into the database list. The currently selected database is highlighted there!

Analysing games

There are two analysis windows where two different engines can be configured to analyse the current board position.

Engines must be configured before in the Preferences Dialog. A default engine (Stockfish) comes with this installation and will be configured as first engine, if no other entries exist. Stockfish is an open source engine (see Homepage of Stockfish. The Mac OS version has been compiled less agressively than the original one so that users of pre-I5 Intel computers will have their fun, too. The source code for the Stockfish engine is completely unmodified so you can replace the pre-installed versions by the original or any other version. The source code for stockfish is also located on the homepage. Note that Sotckfish is licensed under GPLv3, see the license text on the Stockfish home.

You can fine-tune engines with the protocol options dialog (works for UCI only, Winboard is seldom used and due to the clumsy specification hard to implement for GUI developers.

Automatically annotating games

Start an engine in the Analysis 1 window and select menu "Game->Auto Analysis". ChessX will start to move through the current game, analysing each position for some time. After the alotted time is over, the best move will be inserted as variation into the game text. Then ChessX will continue with the next move.

There are a couple of options which have an influence on the behaviuor:

  • Preferences->Game->Auto-Play-Interval determines the time, ChessX will us for each position
  • Preferences->Game->Automatically save and continue with next game: This allows analysing a complete database, select this option, start Engine 1, open the first game from the database and select move 1.
  • Preferences->Database->Commit Database after saving Game: Recommended, commits your results to the harddisk after each game, especially if you analyse a complete database, a loss of power will otherwise lose all results so far.

Generating content

You can copy/paste positions(FEN and images) and complete games(PGN) from/into the clipboard, export games in LATEX, HTML or PGN again. See the Edit menu and the File/Export Dialog.

Merging games

By dragging a game from the game list into the current notation, the dragged game will be merged into the current game at the first position after the current position, where both games deviate. The game will be merged with all annotations and variations. If nothing is merged, no suitable point for merging was found. This can happen, if

  • no position could be found where both games where equal (after the current position!)
  • the remainder of the game to be merged in was already contained in the current game

Customizing Listviews

All views can have their font-size set in the Preferences Dialog. In addtion, all list header support resizing, moving and hiding of columns. Columns are hidden / shown by right-clicking the list header element. All changes are persistent.

Customizing Board and Notation

You can customize board and notation easily in the Preferences Dialog. Especially the notation can be changed to reflect your local standard. E.g., in Germany, the "Queen" is called "Dame" and thus represented by a "D" rather than a "Q". Change the piece latters in the Appearance tab of the Preferences. You can also change to a symblic representation of the pieces, provided you OS supplies the character sets used. That is the case with Mac OS X and Windows 7, untested with Linux. The PGN remains unchanged, it is defined with KQRBN.

Filtering Games

The list of games can be filtered either by the opening tree or by clicking the list header. Several searches can be combined or inverted. Further occurrences of the current board position in the current database can be found via the Find / Find Position menu.

Training Mode

Selecting Game/Training starts the training mode. Moves starting from the current move are hidden on the game sheet. You can't modify a game so you can make any move in a position. If the move is the right one (the one that was played or a existing variation) then the move is executed and the game is moved one step forward. The game notation is updated and variations on that move become visible. Ideal for use with a tactics database.

If you have no idea what to move, you can get hints by hovering with the mouse over your pieces. Perhaps, the right move pops up! See the chapter on Making Moves and the associated preferences to enable move guesses.

chessx-1.0.0/data/images/edit_copy.png000644 001750 001750 00000007752 12141255204 020463 0ustar00niklasniklas000000 000000 PNG  IHDRi7@tIME "%BbKGD̿IDATx[$Ysݳ;ӳ3kv.-1Aj[‚!lłDp7d>#>>eȘga q1MZn1md‘?څ.W"8j 5 #S04ܿvY#ȚZTqXt3 og.nȺtV`bbacccacabb`%/V'0ؑ&'8T L䖮0F 08b]vXTB|. @V N]FC&{L,R]A-S}wymt]b P"U/wMޢA:# OX| zT2T,v p5@f<8M<\ *]>;:UPD1ykZ!zi>< "@*S饔 ^"zviqdk)ݩ P(\:+lL %PnRDӵ1s9 GtNH^D&rwstQU"QcoՇ'/=;-wr[.0/!2c :WjwE9S'l, pRxHt}zz/?|pmsN; !M5Lpp01aA8J85NW:w^XmF .NTuYx? Z$[WO6"!UjT`acb f$FQ؜Ar. }?n? pyl,!In+$4_=o>I,Ȝy| /@dUBԘyg1x>\b2"'c{> A]iF rtE ЈGրϮ+;A/>\@;̽]n!6]"9?NjcQzn[YtMXt?@wjy -}e6#R kMS*^J Vp줉I5+1[```S8Uv`hhk/6}OupRe {v0ܖ/$ mxH j}ϙ-WbG˫>-o(  p0܀3#PC BL:C'Ïb9ZI `PgvuFW41Lz4uyD0(ޒ cha\FhhD)6ݰzфO~0 ZTuߑ[li@za 1KT?eIUY] !}.RChj L^ug\tWf ttaǭDj$C =*O_-qCUQP_OLx:HDU#*X7K]L t/b;0FԀMav-3n[b;Ԉ6kuor+!܏h \Pvy>?|Ub ?K]̪Pjэ G@Fx>!!'A)|? "'83,&FX bddC-@};P7S tM#R '*eg sK4mf$|Nh TCL7f ?K@ OٳƺDP+яZ3 ?1cgh~-@IOA}"[?|}:7!įjcqpΛr\c.(f;)壘 gʱ ##ӭS,䷾\mkʚa 4ifrVTd:/X%(T&Əlzlfm߾m~O-^uWsq0vI2 Ɖo.k$@ 7lG~\p}kʪj3"LAB71x~h:6/Heh{?.不\>cVVkjZlAD:71 x-3CnWAJAu1_s7i Lofpw֝30F:b8/7){5מ>{=yQ W¢<oomb #fJpy3(pF:IENDB`chessx-1.0.0/src/database/editaction.cpp000644 001750 001750 00000002062 12223260306 020767 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2010 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "editaction.h" EditAction::EditAction(Type type) : m_type(type), m_move(NO_MOVE) { } EditAction::EditAction(Type type, const QVariant& data) : m_type(type), m_data(data), m_move(NO_MOVE) { } EditAction::Type EditAction::type() const { return m_type; } MoveId EditAction::move() const { return m_move; } void EditAction::setMove(MoveId move) { m_move = move; } QVariant EditAction::data() const { return m_data; } chessx-1.0.0/data/themes/shadow/leipzig.png000644 001750 001750 00000231166 11172700607 021457 0ustar00niklasniklas000000 000000 PNG  IHDRv=]bKGD̿ pHYsuuÃtIME 65ئ IDATxyMǟs}e0}'{IJ-BRJEMߴ⫯kJ$RY-"`0˽{9wa}03?@Y+keVZY+keVZY+keVZY+kev6u\#zedNVƯ+Mwb^-e$^EFA&YYT>[GӁgqnF^/.wxk81/G#<rYs赔o?Nہ, $~U`3-p O7ɉ"0h&<\9Kyi-ŗNrqNjs'aoHaB)xq::*f[zJO#P̦sy%[;.FskOkY;,5Ձ7d&$/H:$s2Cd$9SD D$@1LIx]t"~#j"\c~++ lqΥ1\(!\'}""d[S>H߫D qғn%d!=%C42Ir,<l6ZsH)4Նb)'x#*łG*Ds&duV"NI'TRI!d""E^ EķtHN"xW"j9js˫lqQODdn""I׷9p?$[p23R#"UC;gԲWCbX_?iM2E74KMi"vWJZ9J /^[&]4u!]?l`.wXmщ5I4a!Y_7m'x#ƬsP } rݑ?k-W|^K"4*J&E``('&0lgcPA`C9- 3! =֕*JI֯jcc)g[s:X) 6}Ep#[=fN:<[h f05jSNm"]|ȝ'DyK5{Ab|`zS_ (x?Q74 c#\1~#Ҳ0BJ (H䃷. r?H4; 8Z4Uq p3Qskg+.HZХV~&qd!VAw<M~!B j`,7pFgGߩFĜ=Ƕ4czO'f rXpU|)G^ Ci`-`Wu(oM"PǗhY>۟P I8YwrVwSCY~j"?dmpo!؂""(TdH-%S"}2MeDs`ӄhv1aDj{ VJ iEw瓨w9~xʰE]zV=X)fqhC~O syQ@:Wn7p2iJvZ5X!S@瀅aCo*RN[$@nȵI@^@`F'!  %(Ċwլp$ +{_3U(4DQx`aQ%̰>Ÿg -.vP*Sq|5'l_^q=ȐmPqLKSZ'UGՕB+4vZYBJ!PEӘr}PP@]S`G&m+W_UT~OS``'(뷓Vdb;aG9K~:"m  ]]qP߶hYzeWh8}XnX8uÍþ><``NØŇ_9ĩiRC50l=O2z60K-*h_ܭz=Daf1P+/rjȗSnVIg &lI~ΐKxIE=5&*rkR1dIB<~Yt I:Z#M`{Q ,t=ӊ*uKPk%N:DF-x\P(gV 330}J~4kYjqOd'3~ gZL`>zp:(Cg_;: EiJGr H"8I"bꡏw}!|;5;>Ǔm(^ |5~7,緬? X0@Df>j=~q$^'XxxsO!߬m3.X2Cڔu:\2Ռ2!vo O!U;$2/&6Mpg0SƮi)|J`\!Eqo9R(ܡ>w:?gA`pҖUU**_:VcTlL9֑Qқ#!voX$klmxp_ֱ~;Cj=kV6XY`fѷ}R'?]hty|A^cI1ЀUo o4Mwh5mv]7gf] @Mw3j}z#b,RMG=d|@Y&խYk|ƽ%Q0Nu+,jXHHT׆ im IGP9B+| >|/>k.g83hMPHIr, VBB`7+MuPrB"xsIe1{9fCm #ɇr(AtJ2 {L,}]2K 87lNl4^ЛlxL9qKrgqݑ6o˿E y 9(""'9+mT Yd{gt#ȩ AU^"s@{ђf46UH&:?`֊"Ae&d|=AV@GДT$oDk[yf'o0ȴl4=g~jh#SE6GY2drU(OTU8Ѝ^@0b$Ѯ;VX@W @BǾG7[W{.G*i3V}(@҅Ca<)Sd$y_i\RoÍs9B^<wiE|w}[ը 'FA] ̠1/Z̮6B%(5m@lj7%&Txq4%1paV Q163gg~]|)4B[y%| W|߯N"b7 ydާ+uʯ9ǯ9JBUPCsf|/AǣtQVeo< 劊R0Gg?q* )DtuѢ F3 ոEwO5b lSa;3N!f|5VA7Re9NplPԨNhb|k*i^>M&ck};" "=U#q;]uWӻjϨG` Sx6;~s(VmN93{k!R˳O$8 CNUU\Ŵ21LrozUb?S`rBec9L4KU]o0@8%;'=T%d+ƓPhG$X@KZGxژ%D8A\uz;T',wLzc:Q_yGh`ӝ3,f [ri;)Pf$$B6 rש4oS-d/.Zso^goHA>UƏ3 VzwX0 ι)N/YRΖ^~8*\~F4?>jmfhx#Izb8Z|\1>0yUki:gx16̦cT%-?yT?#JGN n|*ТӅ5qC|J|GB}`NIp eM0RRy/i.F{1V[35RR͒E |)*T_m3>ZcPgi]GxUd_=V㜆j$T$i*~f}367K ESÁ-ɷ1w{-Q/'~m6r=HAՃ[臵j]BI$SIy2IZT82~rT`f¿e*> xZ| #Ь 4Jx~`09VȋtTz W{y:.e d:! u;Ȝô6/q1Y&A5gY;lyJ*8ӹ[BO0~e4BFА~X>f (ѮQUR RU &o|%ӂH`8ח;i5Y.)2NPOV r0xA@=|NX/wh> @̰SLa7NaFEjјdZq7}]Ukd%T!9T+yYP!Gu^N@6.B%SLʑI&$B3n8oN]BLN% W*B}$o*_qʼm%JITJ#qbYhA?c2V*Wx$^CC>5'Аaqq6杖#8 r^>%4<) ?k`/k&?F$Fy(`wOwtJ Tlh4dL.=:a,'KЍ5ѝhB<>{ ~-r QޣxާKfP(Ԩ7]T39|"r-k,{g^>id%?d4>Zu[K='!Dw9nJKKedby8&uu,eF41{!T<@6$tzUwx&1{.sЮhILP PM lZv\\ϒ!MZpu,ۙ. |vۑZ"aoB8GAخ@7s qx1~_3X%cvSHb }=gђnvJ AI`&x3m<tJ"`p*)Ӏ;XYT#%f/X$cxU5 qǮH#efIA 'p o1xNΖ(A6nsԺ(q#5rڃ4#^h0ZFW|yupDfmP4hÌmO+x1 Glhqn9-0;/  M9QΩXGL)0rT:5DRR^Z"a {NQ;d+Ml"IFWO~q~|P@yȣ|,!|hkA7"l3g ;.!<$qnuk} o MG0rFF n~p2$MکN㞰њ%\$Td,ǚ"|O & nCȨbc151nj:$3 D=a e0ޜCG,)""9v #Ѝ*fp RW>(T@9I%v?xTL6\kO*[-/""rr1shkaIeN1zR9pCfFE}Ѫj@#uS_Cb^dH9qUoS;ikÌvUvMmSzI*HI߃x&9vb<0l;k) X|\&oބC!.Xlfm%n:0ȈAWXoWqVX^C\Rfrz@ ʑ:%9=[/|}(+x[yLΈćBG=3lzA]V:1톎,vqu_zF]5,n8?x<c1-Ũܫ:mVx9ޏ9؁'@UkeԴƜNE4O|儌vT(W\X("ZCG@ti6 Ӥ\ey,4ڸ/ߐmPL ݒ `#zq_ ^+Rtjnbf ҏ ?<ɣNO1?dvgMʜeQc)@*:,# 4-[POu.X ^ ]3/IamhhI&3<x/|a{b,bd3̫ IDATxJr Lg~9muEF{h_)2&xa>\!/]yǡyfBP_yDž)#I]|%*$է/Y< ozjmq,%Yaх{1.}-^WpBUm;&%t`},jձ%6c\* hϬo.Pȼ!SMs|*,@֑!)AnE_tHAl3]c݌gkL^/he=.ͨrK(Grc;$2%saꑏxFyIViZсbD˹ ҏz8pȐnFy[gvSZ|+@|7$!8K4 kߦs9x%ja'^#_;~XX;͟'ot2ɔJZyDe*7K.<l^sn1w 9n!id{b!Qo>o,Wyhm+DlM`XikL^Wѱ#nԍ k\9kE, [.) ְplc J eC;V X^4樿kgJ1mݙBP`R;dHjD8.^s;,Ϟ`W^XIKP+nW*Gcwgױıh$ ۸CG4|iRrsbʸO~eYp8-@<ġ$J-jS^[GM gOoF*yٍ7WKޕgL r2I=frgLԩ#x?a׻ .|" !qpG1b)|ϗմz S˦3Bsf &.c JIZ|@`xj"A #1-΅fݚ[7;A02j³V-rטs 3 ąZ?&t [T[Pr>gjJ+Ye}FẀpj~E;Ɯ.,v'}5*x(O0l/8`,ppV^h]1<9V߼mP> {7[]RICjWcԹj ȓt^{C AQxL찎N5OGl@޾n\E3BoXdpGn>O9)?bմt#[!*o]IhsuzөޕC]K*)8*ƟCoe ܯq͝B2ohÑ[&dzU TC>N.ZhIsVٚd%9P=T* 3jzJf"hпNk)t\n͂Af|c-ȣLYyS?E,D5㮫L7ub!}2årZ43^j2Y҆NF'D9CA:ćs~cn"r\(gv~kc ]-QXrik<"COBu1i]@ &FsUk&[yƒz-ZE&EZr* IۀZݪ/mq]n-rnUEP=1J<􌈭jFdd /vEkרjd+3S 9c%RF0|\f9=ZYaT:jknj5@j9S>ݛx;{VcNa?wn媀ėeSBXW{[Ud$,h^BJs}aF}}~Qfpn] .Q>KdCJDdHwC!claٺ0];U~1Lk8vZpn\y\EFa+3lq2ی8?9)V3^5Ak!d$2 7Kvkj{Cq$Z\x{և 3鷷we9RE-0cMq|f/l>!0d;  oG a*VT"dTt)#KNI""V#ZpJyv,4ufsUO櫽9A֪* +w6NB¡1YqIHݽ_pYtWp3~jzNtkjST3D2oV?0u.mK'5]-/~_9{;аD)( -qa<>b>79^Jm_u#IxP$R(^>4d'2gkCozfY%쭶+Bz|^٨YRÍ15C͈A) Kjhk@%܈ t;B [4t!\w=)C986Z(k:6vn\OIܭf[ޠ\3\$+vTzi𶓷f [z]/#H1>*4LSN+ǟXe:amp51yK4UoZ=°(wiE(_Ц Qh}|'-;h/ۭ,0(%Z~Q<|5zZ"aSnݕU9"CoK `N ̊R1]!G+G l,@mNpb4Sc^r4?5Z@%.t4xw^lf xȪ9ͩ=3]~PNNIo8;͎C`T4$q  l&3Tn=qc!Rk4.x[e.(ۙ7]+oiR+4H&AB@YOUگډ0t:LrU'i] K UsNWg d"Aut=aatIBh;$/IVS;zsuI|^5S0M1@{=0-G _dSF}XjO>W*^!GDy ̦c9s~0O_.yYj.TGCǷ'(0Ypv噮j0N}z+P%`H=MC`l[n)@,@ [ugZOZQ9WmyyB#EDL cnQNo;.[gAdQ`oBi|#KʧrP%+dy>GBY hL)<Tc3ضd e?̇|i c]fASxlNjzjuKǸLCRT:%K3@ cE%3;>DZD0J0GJp7X+}"1!8ޢmX f \q.mxC7#DP_ D7 +i c\,YNSqt7jȥ#r7Ⲛ!c-X[< xdXih whm@jS5[,D^*Ge`GRf6ֆKK',ӔI,?hnzٔM!Nh~eGdZ4SFˁ uT̕X@5ғ,Wjі5zf3 .oga`i; ;ޫ@.(8B΀w¤j%TOtTd1EK {f;/f:EO'u/ydTiik#qm拦-R5phk15L&Ȳ,~>Pj0= OoYޣjr.g96I #-#ؓGZ%V-dô/zetjiT YLwSx^`mqb„q%K Fk_@Cؔ{Eo~lO UĥTc;pa҂ 1t1<&9jؽgI -h%pvrSxAmʶ, $%3is}Ǥ Lϩ2O%DTUl.Zd8B{Xz7z}dgzI,#M*~ݡ~iޔ On)7["5 C zg)>"UV*(8^{WuI Gxtt`C۳]QϋU"N|-Ś+OR0B zDݓg]dzLbaQp[}>GN?n~~ N s-jų1,P(o~:U<2K/lWjz2 *0{%baH/1Н^ݟwe:r Xo~_H\$f4ŴoЁJ1Zz%*7Ea.Q| LlӳCeRla[ۤ0G"ְ8rK(O&KF6{Ĺ8ghʟO@RV(x+w5 Wh`0 eJ.o'#%\00Wj}@ǞD]>Rh\ۛ!#EeM j/-[ՙҔ,c"ߺ14XVE|Wo:Gn_j(0+C%OђFY|jT]+p#gR X`ɺf%k+Һ#xfCEzv e>̓숝Zn0a.Uf3v3p""e\D4~5ŅϑUBoIC:B>l3'\KCГKL^}*Ps?Lc?¶/q|ӦFxZsBq/Z *+hQMzõ$X@>3GӮ_mrP'p7[.) Xi4< BCk] {gL-HIgq5nUpAȶq#Ƣ1[* 0& MLq;l|~Uyz$Z2eA#2˥,K_[yl~q$XLB\`is7r6[ F.Jx 7˕'?)H!,U0pGI6y9DiTՓoms=C8z&~˘̗*ꅡ*kЀwDFj7?s7t%#sY=ACXK ,1U˄pAm+6J6СXس*2Ǜ+E}ƜOk9 5Ө9xMQ4C\<"euT5lo|N]ne}k9\uYu;-qb8oa(o޺2[]F˩4!Sy$Omy jJ3G,ʼnP0EJU"^ .YaZ,`ӯlÍn4Jng^iksrS-3,ʣ܊vT҄vSێ>O(iTULj9BfigPom fŷ$@-zW\`5ڧv: 4K;+ 0'uT+YCc/@Q5Ti9۽ Sni^^Te mԸ.MG@ ώ[؈TZ;a̴(T.FsZTF]=#وHԌTۦ_oWpMGVTĬzӹ~νRME!\_=vEQzd[<%daer5`nR{ĆŹ&TD1M6>gJckS%i9 ƑRG F0?+s {oKȑ%}=DqnK}kDu宆 z+я`|OQ?Ꜵ)E|Ud9uJU>{$DaU.)wjv*C)FѰv2(T, &g iBVՙ}y+B yk1XB@7Q 7M9+$k_o`5OaBCO-Uʶ6v9TaFhwcCԚ$woB&DYW|c%'p/b >CA|OM5fD۫JF-rJ,u^TwzR?4WWD,&@ɂ7TzD*v]{ɶ?4#@D}qиF<.*楽zTZ-j Q`جѦbg Sj:DB%)d3ߴ_]gК/s'x#C{uQ3Mf]\u9k_ħ GX`{׀'繍vo,?ѲO6zbF^ ƑM0Q13A޽ɜ՚ ߒ^6s{i*  wDձV[3@r15@(y4QBZ:gܪTf̞=Tb|Nd ]=Y=ic(^!b+V >`g d\5E eq,e]~ DXRrJ{ `;sJ~۝a1lVy A%ba,k9h D=A[ZZn؟3 |&=ط#aۋ4sR*#2Pz LGrxz"G{(Hn{ş@MuVNQQ@ +D:EEc.Wwl55 U4rQ ijүE(-RC`#^gFn1 P?~zKk1YPBF>Yp{KO.*b;۳cXVh@&r\L(N,}|J/cDN =—<k?1;% 2v [0Xؙ\<E`-sj\^BK/~_y,IM'sZ)!)3d 6Ψ/YQROA)q*ɳlTpެ검SRk  9qQ@V;9g!)(lhF(ŽNj$R IDATKUɳ moz!NcpJڮMAa&S}-f$:kz|3(̀@f ZE*7'y]TB5"͹ͱcX` |[ KB~Ci@q2QLj# > E#Е@U}\nxo9³ɂGmک$3nw\o:XRazR-uTTq `nHUVHR# $j0LrR2(>zV5=U=ϱ.18t_||~?7Ns'k\!Rb͂r,4Wib7bIYaYPs8G\r0Tj9Fm++"MZoÂ[]T(dY|BM`00#U, |Sz6k.DFc5ERK)sIFCyJ9Sr @,UD5~^tTAD4x. ǥi=Nx?}ۊ;dF[`y :+-*3[B> PrA "QwrG)h%WM1EW-R~vn~&ε|/<,7]H1{$.$B (x=#n7+z`݋@@h[,ew:PT碶C`${- 񟭿y^T3$X~۬[a;*,x U!DCpAU !&#U-YC}Ӗi%4ΧJ;Y." X4s%T;>cɋA "BdJaT\}VQXUJrʳ0q+q^٦]c^r,z2̰e\wyDy -a"mcĸ`&sC·7 b)'L&s>sR&ޭ1/y@Z=v㬶'c0:m۪̚Fz9gw[n o/s wmjx).4a8xyQEyGQ}}f7!БދtjTQP~Q]lQDE *U 鄖s?fvvfwR6󻾄s9^iW8YyKXRJD"UW\t4Ve֭h0Q#j?2_\v-C(C>qd>VEWT)Sbӎ;Y ҵ pD&g;GZ85Ru.W~Lm,,aY7xBUR 0{v42lE[.`nosq_u^\v:H~ hҘh }~Ed 0T;JXl[)XlMz7]L ;疋L/?d_k9>Q!`Յ酭\i`!fE7mrC0Y_`؍%L4m  HQ֞Es6B嫎 Wg)R;p|bL0dyV"l{[(mQOn]Bcx̧_ B}*p2]`yFbs;8(,|1n˾# \|;7c-֮/4X0p9n8dAD9W.٠$=26۟p=(M'Ss>+Ad'~͚f9u:Z:bv1%lz tRtUq*xl8=+T"U ۑnpD13=m _2b\)je Pc]h9c0t 4m`1vHS#4z^N'˅,8`_3MyZ۫u)L X"ixj_>tZXwjpئ^8=}H(tSCU 56Њ:>w~f Pϝ2MRm,|kS[}Ü]؊+#Q};F0gO/<:0(CX^Sv>r}ùbwBK*˥,e>{y(ߠ!`54 f`9*@{Jj!Q<[ξFR7p`;fOeQq`e~lX_8ψGR\z*p(n^NٙADPQ]cEeXR4ܖv2[\C< f1^]WJF0Y5qDiMH1s,@kEm'6>a_;jڽ$gE9r瘶Pc՘ݫڥ b.A[EQzM`|{2rM|es[-?+d>9gUO,%du΍K(2kY*#˥24@=u[FR_lrKSXqiE9` Rmi!;=J=@_; eWh@7S|L5~rӉi0Mw]t\ >u5Žѐ9^ŏ<"31YZX8vP_hn@C6ڮ(B%m=&Dn#圫-REׯ/iۈiMA# 7.]iC Bųb!K:N7{YAr%$٨MQRo5l[7Jza]+D]t. zpmYџuuԏaڤxav{ |y`nvwY~-P5\Q > Դ*l갧? +y.z΅q p7@%ĝMFl2GRrZWՇJ0!p>{*iB4O]z*u8kSMplǮ#Jⰰ·.l 9{+KEY w촾{sN^ky >䞷"0wL¯cP#1=J𯐺E0bkhz0q;hvB]QX8{ձGRiXkҴ1͔)uӅ/4C#GҸSDB^R8"MӣOK}-qfiZZx LfuYSc8p <Vu}g)kVR/0tXAK>i+utڿr9"[maXa~ Qb>?@Eay }-@V33!m~^lc19W̨p|Y+ x|ψVP~v'P)e^1WtR' &3RQ0?4mXΡE,;Ka;ӓh +ֲ')&5@.K[8mKZs@Y@Fz"NfsUC84tyEWDӵ0JFُ(jd,Go ct:u8O :'G6[.B "l%U2;R*eVbd `%N~kQt seE`٢ũa+("d z.;&w㽯a)B If{xF"@mRE!N?t=# j*g,P|/]]47{:N^NNȈnmԇ VجgIc3PCe-Su`'%^o=E=|?DluŻa(c1V(ؓ?ev.oXksQ7U1)II YAސ{%Fwt}XU.u/B[nC@#4溾YKi:p$)A XnuXEVC`G *F%TFSU^s?EN,G4&k+\ ~2 )2V̇ҭ``ǣ\9i `KdoH@e_/q{2^@̍cIol::3 sjSω,[DI8=ong)4֓@U];'P6\`4Gr5Kl D=Oϒu^إkinUQK x5hD#р:npt$U¶n߬f59ru I S'~dO8=g4Sr c`(MtLh)vAwrB0Q^+%Ni%q{jY{G{[ŝ2p9勱 .~dW;Ֆ}揥t%}Ӛ5YErw3pp-ن%{_%urTU8iqG U%<4i=NNOSY9ԭIF1css(r~b*6j ͽJײ}rDjbf$KI-GeSipH~\B쑒ߢ#Dd@[J ,[Ƹ8JUjSv_,ai}PaX0eyyQJm6wxe\ɿvNyGzc&.hnm>R)Uz3H2ғ4L[](ЉώaQk g>tҥHqr1?tkfۅdyQe8^{>uG FCR!d6 &,\F*n@Ryկ8Ҳ`Z=VTA1'.蔒! s<=Եd$%=OSY+Ii/ή6#s lސsOFf+_cN^PQWn1QXe0yuE>{@XSerI-,k#k=ݥ=lcꑖ7˯nVQ MK*(s$9o r~X_0QV*chlzҹX+S,!l2N><,Ѐ=; MU9Ȧw^pjzx0W{fFQR4B[kV*ԧ$UܢU;ke(œ|3\ZԢ*)'IZLN lg;Q%25vbwG 1? !MZj&Q.p8:qwei2Y&&wV{n,%0\Zꭒʗ}S48J5*Q򔡌0bZ,#C,9;.G#rl&Gɨ7қ{ceF `~:NK36=GO??Bڣp1M<3f91RFNYn}E"Yw~A#7+~Kc"CI>˽^8*;@2fqg XsʼnGNVo)K*Q BTVQUY5()e|ptx~nBX2+zwEVϊRWPh{y5~ rlY9kԀwRJẃ_wB$_6<s60n)|n[[Z)l e%:XOj)6>/ dѠDD[E/kM;sʗZm@xQ r;B 2E &lΰ$ԧIO7뫣ʲ#Z" uf;d{G7>\_at_s?MI=Jw;OC}K-Aq q.;̏B_ :w7IkHG&+{_k[nydVߺ p:%HsvE$c,YiyjΎʇV?Ox+8J&w(t,fmp~Sݜ`Ea!LO폞/0}š0&8Za/h+Ufۮ#{@|R:NWUim=ͺ2 ȢqSˉL=#Zܼ IDATPԥr1EHHJ#/v!i@ЌYYm6ڼv[bͭ" , |7Χė^*@<.-ҁWo>qtfT9.Nt+S7o̷I&)x!7hVIV-~go# esD6q2~DA}/QsPyjInnx^ԍ0b6No~ӏ%awuTdkJ9.e;~@ll^yoe@B%Lf4L fp*eָà"]ק|nHrn;s>+[3m)pH!e W;طT B@ wF da` pvv5\C`Xi\ ] BIv"_REa{lFtP?vDϩ2C[_x^\6l^ݨlGJ,.#y6{s!Q̣Zl D>`=iEr:Bb׭=۠f^s{R髮o{BXүu5|0֦c-ɧPM-.%ű$TJs#LAoho4>susJ %H< IF --x3!zڄ0\qFe<#NlYD~2`y3@g @9&0J;:ba 2V %;60s ZWRn0EvDSCu8 i5)=x5K[y}4|-XQ+g (Kr 9bE\f=:reS-z6RVM#ϐ*|Ua[d~Ga,a.:@0pl+bur VC=UW.oX+FrmUiX@^c >]&^md#L-YEUS'1I[uk *x^H$~cu4pOt2CBa%`c%-Q0wcJo\j :UJ1!čA-;et3PlD"`L'7yNƏq]+1v3x&=VAc|=*--u3>u15KdU7Sl0 p϶1/Ť ,ࠀAwKg41su8_K&P\[ъI>~կRdש(qR+=Cn)27qpж^ :Ŭ`E6z%Nc=hk3D8`%wGqQBR5mQMD!+?Y IBeKvՒE9B”n.9v/ BUcF}*I@b$E^%9ԧ% ֊$\.0?=G3JEX=b0x:#F9fXsG]Y IsP1%^hw&F0T^"}3ɋ(O&y*yOKJ'QC:ؾ X/"Ei-&;`#FlS?r+au1=S͐) FO7kR2]Am&gD@  b1\:u5o>DYvۥ|D/.eǼ%s(5J [9ibf/jZ(fIe~p79VV,X=b0,wtd"2У?=VJv8ݫXl^BF}6fʹ>(AF*J5PJJR$P=ne^&ķ-nQI-a*<:֖Ɔ= ԵhڜbShƮ#),A!^'3XGU\FZ)b֏5{FXP"ߒ> AӰcުs$y oyJ8Ejh/^VrM~Ix]ߝV]6bՃ rm_ԳsݑT{7͎dq"j׽r %xǍHq/ɬWyڟ)n\Q:1lA9TDn(^{ !t6R,qC~-b\ THmq βJZn CaثvUps'k5?!:}%@ Dj7 .n zm`mN=%54/pa)CAx=,Zƅqs6>}P*{-ӗҌı7Ls^-wjx<]TlGy ;J'Ȭ@{:ЁL`3:DL٩{c1pӠ/v}O9Ի fֳq%WҩVz {ttfی9DC/=sф@=`fon\=rb4tbau]L$G٪}8Γ aaV3ϩzymO)S. -K MXl9]W N%3K\2pإo븁$wrǼ|yeVX_2EdrԊz;(|Fw'Sig0^.Q+u8k[7nxkᾤ0޳pO1W,%--BQ$TO kxx(I\w~V#fGXs3#qۊ3_(2~x π8!Q/Ka8^pǠbRdRE<Ӹ/9Xj!.כKM{4WՎ*75~(3/.'xDq1=B?qa+3VF3"e'%$x?[4A8SD2rqj0C*VV+f*VBEnf3>/+!nax㌹  v_ (.,f;l96=PCٞ/АT"夸!ѫB~ ٮt%.9Z 9!|q_sCg `yc]O{Ƒ7$RowzpilOe[adj}Ig>e>Su0Geq6 y19U&p-788.ѕu737H%QOfzSX%%Q8Tg }π8Mm΢"&Tb#2\41"zP@s=FڼMBڶcS.h 掜m`m\@`EoE'etv%1]i$nwP%k ;)ZRpi)gЕHtku@}UF~Fؔ,0[^{CBm a&D~:C,ŒڠaV7=OtϚ[h"~"{6]cD_CLa9JȔuA:R\ŝvNZF듣Ԫ5oT`!9mgMWwy⣘;E+Rس媉9_,ReI`Q6Q^EO:P4Fr#ҕ7ؠ_Ge3*%iFE-P8)w8'L1 L5Й_(Ir9C206PiZluzgeeC R޶@,)fcX~ ?i`Wکƥ8]HAD?m}A2U\H1g.=v}Fz3*he2%9E;#\̅ Ǝc'ȳU{֯vvq夂~GͺԢV<:(ȣItw!DoE&թFU*RRZJJR\tNpL5%b;;` {w s"=~wwIE` > #VKO&Quߥjdtyу)JK>t;Qa>am,v+Fi{N{mPebD}(_i\oekt 6X/=/$ PբS釿*I{鳬y;^+B.Lle Ӝ&Řp UI]PU4~rOšEE TsGԤ<|*8{KQ5-iN3zO_auSYlU,e)# mm"ݴ临,t(iدF8vZ&mMr5q;0!`hX]U@s7(~"YCgJʆ}ǹ+ 9qEYQ.γ4̳lP'\XLJq۲DX RH29퐷:`+nB|ki`W%QQ$Ql cErKY:c@8455v| x'eaX׺ARm75IMV ~.́G,#e8\H߻}ӖTS7ݓk"V!(AyjҐhח]rb;T~c,|j@b[ԗ\ (kg2 E9b'꽾.LpT5;gv%e#;:J.h@SΣ ,RZ_$36vF[Pܶgv:iPVJ3rHw`^z5E5(OUx2 p*%Z2HѢW).ʡ`a 'c^׶ |ʝ_kMPDyCò?H'́@<`ڀi|$f}M& `ÞͰ3[,xP[j\TJu뷇\XA"L: lOٰzmdE{2ٚm<vr=RhxBׇ)}Nu6}ؘ[]F _$`xEЉ.s @ IDAT j;ꨰXuDD>n"YȦ^FW{.z N&̨2ҢY?vΤU K~݀]V}ʦ CͿ٦B<Gq] ш,{و4Z.E7b j4EEtBo#v89 [GK&|N=9 c;E⳽w-wxx֩ENA+=>vLX%+BhNkA]Z?$$>} K:E䩵R5u3㒬)d 933j`/{*J~ʕz*9 g'd)ae,#HU h!M[& ׌6? .Si砆~ʥ]~wNnWa ľ}lQNG?X˟0&TW_iw[cNfeeaXptK[fD.@u4 X2˩`FAKA[pVF|?l|&ǀL"0˧!C?7w<W\i-*P2.]˟zjowzeq wVLWI3ikp\G~8]WfOKXB̘ZyqѦFr-2uvQ` ݑHa2 C^KqG%)h@y|~c,Lp\+ ?p8:3(C AE4EW~C!*tsT s\>ɕrMem iRHP/'ptp]_Mx<%/ugb7yVg`> %L4_sg"˙L<ɷxwZ*-NHTl˙vK*S$Jo=!e"ZcX ]:Jb_Jhn22?}={F[CA?_Ԫg09TUƸ/5F< m:*#WKʇ6Wog8J㝸y;YHukLqEWղNLŽțpr΀4 Lv!6!PL^6أ*veQD0&&~'+-A cl7`ݼ?}VAaGd氲{:tIheґ=ɣue8%aM6*&:i?SM َ|WѷwjsUHZ4bHsBf%HA|d9n!ō yFs g]׳. p@^tIߎH[I44sS/݃J*1 b؎xմW+ڪy凢-rՂS%wUKcrRD4[2I6K@Z+Ku.rj=&"h ۚV|d0OOn6iVNJ4P:SV*~H~M=̕A ]`Hozu]+*{>&) 0w]jB_;6aA"pN \]Fa_Hg^Joe񃢀iؔ+~@Ea26g󎋥1?f4.bK&QXjZ΅ھ,-=_D|:Y5Y:ʬw˳Y+:ZJG2$P"R27+fy$1/u1i1M'g|*>a"MśQJcg!`ܧ>qnU16~ٜCgVmhcK>ƙYNp^+9ǹEN˭m_BU>ן1 _oy魖̣J>mi|%-ǂݸwujMI7TS8*j)J{(yfK*I AE@AEĎڻxk{llׂ ED ^vw޿?vvvfvvIvC=snͥ4IU[6cH\KZ*/yҜeg,TZEhQ!ÒI+ \v[0YZ12`MJ\U}&(-pquٽ*e?X!`vZ!O&5l0eD-y@Eȉ.@EGhx;ə\Ľ=sh/:>t[MT/lL+/m |n&]׫V[t1cƞK+IћAt Q&0gK4SQau=*^(YlVG a壝j2yq&j@zЖ"2`3GfPBD?)*ݩX!VǠfb'2)k1c2'ѫ/5Ӝ4ROc(c` [zY  ˯62.k1Rq ̴c*'yj`?wϟWp1RTg!nQzP5As*8٤UN>^9Cx U;v;.,R(21 \P RjDk%:W| GH\5;#y<넀z,gqʏs! n5ICZۄsTy/LaŌ혦ȩ<|Ey Fi[DwB IϿ|eQ*@0dkPN%Kҳ|z!mw_1 Xevlϻ oo~s)٢?!t#)Jd,f-ǡ6bvlZ2= S@GK|vZF5Hڅ,uՊm nөkQ3ŅFK 3 Cҕe2؄)L@9ӢyW{Og8he9Sg,o seSXl\_"V]xL7(*KMQZ:Mz<Of\}ˁֲd-H`]f9|E<7~i$T>U%K%z@V}^6VҒ53-4)-bcS.0[4Cs dKhOK"ڐ;w ne~_ק`=oUX͕]MAPZ`x C?~zm5xvtѺRT?Y~i?6ke7[0u5@TxRh99iubWt&r'LUW!)#ڌ0a,b3Hu?Hy.ui$&2zn2Lf*wA&>LN5t{`ꫫ,2qӤ!#Ge'Ҹ!.ҐAs\J},:%a-7p7)-!Ȅ^/,/Ӽ.NHޢ=\Nc2J͹+(`1""bq /6K1ƙGVIޒUն3@MkVjF#2!!凧g \:˅bsR)AUttڄ++}Lh0Ĵ+~쬉klVA53; ;j6~xIDF[1r#XHRlLnn y E' -~g̔{}M;|X)p=*ʟxEhy܅ai 2r0M) Vhowunϒc7Ĥtbq1vaPnSHG9?TCzp`>dH_$I,!uYחangu8rBWreaKnm]8CC>សW! 5,H'*EHb3cO H $O4}-swj 6 0q?i|6vqdV E沀XZ^G}p#nۺ*n ~f=95ӌ@gzX枭g4]_Ḑ$=N1zr=Q+EBdhI$w6NOk:o28H,g Y ֲMlc'%1K>4 hIflٹoxnp&f_ȠB,`L_Қڢ?qv֡G^_ѪJY"5l0PB h@I4=;_c[Ǖ.6]dOC{MԞ eٕvyBI>C2s4;7@]4}ͻX0}aԧ7W {,@(xJʺQ-~zЉ!ŢTGnݟc{ͬe3:y?>́e? V=x() bBJv5_$(aumFNtA|=ߛ`tc S%3"nlhpoHwh*QֹmvhۺqQJt 2 q[/]i]nVmHfm!$J?FYӡmF `RJ9Attؼfy˦/AhgF10Z z{^:3h-1Uع9궔*0htm^S|m;U"F_h/[Sg!?^Nbȭ咍+ZiݦEq%k|M?l/i={6mt;t[7]`՗+&>ꍣN h]}M0)RfJFA |0}Ûvkܲa|/Г \dm6o[yіfosyNJI֦AK;1 0"t0%|*8f4nTS^%tEyҡC|Ku3v-KTƮZgĻ۷˿+_/Wޠ75QRJʟZda(L,I=R..n_/ TFT&*a㞗[,@-Yyi.}$,=GL %^CV,뼿VZi%:{q Q䏝?pEXͳ;G{Y1zQ pz-"#,.Va$S0~ſv*OJF q0{:G"a4MJ\Ñ^,*bŅoaa]v֌]3J32*27=G Y,tXdDlPbK* ۇO>C_HT֯v~*lZ Sӫ"2 ˨G7D{^9M3"Yѹe,%#̘c#1ܢvhmc)1sru{3 psLlZ,MNQ3dT`x-j\!L-l0QqQs;2#be,G MxET\D,"tPoV(BՈ~Q#;R#(g}H|+5U1E 9Twײ/k kGqOn8 !լᱤYj{mXl4WߚbJŲKܴ>nj@3laleX(B'"ٵVI/uoq% EuaeK'PE頰PStN;%JNz)\rEU b>m`D;,$-:U Y IC12QǺ",&hg*U`覸,42!e/ƿ-N#6 ` 3u0 B(pװ#uS6S 1N^|&[>0m()~H:SDVVT).ttĊYj~lJ=!ʿÊS[lBل+(C\kaD5F+sn:HX C7cU爾kP 1/B'h#˜݀)W5L^)6Y粂JVnȄ, :6TURb7B RV^jQ"Yw\qk23>gG]T.@N7 o暋Ny61 ,[kکuDW|(G=^+;6LZ^kN:5Gt-s0."!ڞPIʽun OZ9{Tu5Cdq2 Rer:Yj̲ YW8U NKAs]j,u K]F~"`4'fQ[OW|aS5 ׫ w}GWbZ(l©Zq7vƥ:_e;-e&ue$2*UB TV) Yq1&3{e~o,RLQ:,MKJTQ-%P+=~D`ئsN IND`2Ӆ^NݺoH k0~q7N L>'{^ˏV__RbvNmh. qCw ".nUmY:Ԫ8G݂S6v2s+نffv/m|җܜUJJ^JE|6yԣ%l*4 #8;l_Kx"gq^RZZ;|[#=G)Ցx~9V%=lJi""A,H/"}bTc# {K@Dd(0.Wd)IY.o:g٬Rf mSSY%"[|(i-7ʆ0!Oѽd[i}a8Cvy[*RyALõ̝_F]^Gqʨ^Z"W&d܇F}S@DD2sNN`~qlgGF_W?U\5ݎvf9.KHi""I}۷eE9l-ʽϵW|("L;P(wls޽6GYf6,>.\+HiXd,T&OT!ONDYrY iFEBJ@&{WLUԐB GwvLQ0fv)ǰS([U܂p:d㛭3?xm6=iAk%aluwv~AxxYr Opocv/tU^ђуJgTutT :}< `>]??KE̷xP-ce ?+V4>)Fɡ].g 3nd@Yn j}#@ Lˆ* I 2ݐD3,Bîs7>:r~6槮xl%3 Ǚ'>S\'2>Kںvf$+T4A++9l>ZK,*SP- #9ƭkfh >|x%YἫ{QX|Vf$ѝ+}kqo%Ro%z!MD>VD.".6/X1@fȌUzҩ雷xpPwm)C*Hχkģ{u yu_Hkrn3Ҝ[Yxt&d&`M7MYoK"CCc[:>~NVҎ?FӠ5B.dCBBQ)Yi:7Xԡw1EYl4 X>mdFvc`wT̠Lcle"Ƃ:3Cl^QYlMCWm|8aYnʬܑm 2 %`QMU#}U f7OBZ %y~;;ika̬H.Vwq'[l0ӌ5M2&nszJX`LGnUj HOfvw\sAa{þ3U:N ҘtwվD,H#HcHeSA;*;Arfou{G ҂CW%*SG)h#1|Iwt? %B{ \?tH$kpAȨLHgݩs8)hxosчtq;ĐgovY%ȴ5ƍkۓuKValkf(o2vʄqAkdXBjuKw-Pc@fDUY8F+ĬC/> 郖f7&HWm)E vۺ ┘ `_ 3N?*?YW?,T''=Zm߾$_ܲut \!|}܊؃{}%N ~(˪'`37HoLWi6, !5Cu 4K 0D921ck@ee YdfSc ީy9 jPEm2Cg)@;5K΂ %ϫd^m  ziXɄ YA9W;gTE:J@ϴ04GG::bFh /mGb,e8eߞ,ۖn?Û!^[PCy.[ Jw<؋.boYI5; rt ^חA`՞qW9(<\fy)fs:'N?Lʉ<7,s9^X9!˴1;e޾$d u!"qU)0ܝ|{}`"җ@8 ѩUOsS˾Ӌ8q;C3Jrt5WΙLqQ&.~T 41x!q2.=di3o؏3mg ~6G*uss Ⱥ&33n!x;*( Tt=yP'JmGꚥ >o.Oҹ|yi-񞂰ک{蜤Dr\GƷ',AJ/s'׸o~_|H1›atIn'&hqa{i]^ʕwfd«XA}e4&y=Wz︃e8W +ԅ#2>=ܘ 6?oM_*Qڨ\Uzx>c`?lcZUr'kf%j˓ 3~\e4`Թ;uyQ(cË-ur[Y9yzrvr:ۂ{3FNos ZsnU;}lp (+w{םAwvFv5R)VŵEUo^2GRsG'hDȅlrʒui(Lѕxb *9t<́\Uakmt!)r;'r'~%7WFmu=<8Fp [pÎg2rYQ}ޔxy TZھxEmuxt*vYG&VJQ !vZR*$脀r݃WPd%䪬 4[fU/B3Ybx3;¡=ă[ (CY婺.*ތS@ %xR0% -H:&߅WG@=?Vr\c:h-ʆG"6D6mUد !UnjKNw>dqr/x7-is~?RШ\dD5E>B[ Ѡ=LBt\ ͥzX ~ޮGʰTT6F)ER$ޛQ #R?*pm#K&| 6qE)b*08%:Z}.;ܨ>3Dh2a]r#- 3:f;N2-#3X_twO:7/504 ]@hйU3<7/G8UliJZ4/pkNEc2ޢ"kF~G$zme};-QF8 (/OLE~[1s|'J$RR_iw܄3 X@ nf5@fE'rJ[եsvBR0Zr%+ .h-]ڴ)խ"4-0b2:Ş3x7)*aBїsforzUo~9X߹#ǵNeH.x1q4| \V;2 uIOz-.A` pcN+|-H#G nu 2bȲȐ7Q&/0~Y-2տ|e18n lPA# ~йey'{[(fOYFdW5;?( 9Ӈ16R|3fC|sZusQ.$9 I1td@Q^uGVE cJ_d3Xm9l!r su?csoeYkAA>.iAc3XT2`otv^Se)Tx>[t_|y[.5OMVdC5/MաjUNT& l4e}f;"Jjm>E|ؔ\Ku6sdIEV~;׽ފ"œElk@Q+/L1[\|o[՚xNZXxAΆڈӀ][ ZWH[vذŽ7γvs|Ea6|75ԶêHs@_Ʃ(hg25A]Nd(WqjzPiU\)P(;6Q7qgx?ryX_mpuMZw4\UXy`Z@TސyϯXJ?eujC[pf U9L%uϖ7V\ԆQ9Svz@uJ/lzy޿&K9kC$%sVw w@fFP>ZwoZV:0~oCpt;nfk\ f“G [n~ogo y[.6/pAL[ݰ0WLkԃjGz7TC0*dH~jJGϷ5d4*]e2E0'x.Τ8 -N!ɭ8r*AKia'̃ #2ҽ{7j0ӮOiRѯYE8'5I6c|.o3YW%:m`8'孔_8TXnyr?c;kn[lgG2oǁ-j:sRD&`S8,(GoK}F)w=,ҳt)\nt GBXQ>fSzʰ' *D_R8D̿Xx<-+Q_yS9-aGѻ\ QfT9ќpْA|w\d~{&{pYև2{np!ST6Zޟγ^Z43<'Vt<%L%bZ9H ?‹+Ep{GTZD4FJ˕g5՝iNQ?˽\4;{M$B& 0X[ yn>\̊qL P: 5r,"!nv3-s0ŞՋQҜkR;rizҋ.2DeOͶ2 A١W^ Jkɑz4P xyJ69VN_{]MaI ,%y 5.' gYXS_|0kta#00 u(ֳLC'ȉ 2+*ppL@GKy-KEq `vj#O8wp~L!dr= ֓lS'3Fnx:*?<~ZTnEjah=' w9O1sGuc|{E?YHHNh*goy J65\'ȽԷ|;R cd.KwHhm({G2^xjpRkC[zU[X`6&KX,%4~/F\ uDu^O5uAݤƫ- -fōmi[ิRҍa:~vU~f|; Lg:Km ħjEB}wESfexÜJzClT f|Fn '^##@ae  h]`{.c sXEwsFˆVG S o2RK?UCTobr$Y5l[YHξQˮƐ|H.L^i-dz(#])5YçÊ7qI:pQO^ok)lDG?[cnrŗZ,K{K 3]b9n^m/粯bR4~anEk2_11vqb`mBe5'N@\ޤ7 ذҡBN0#`Ii#-tk_%A/UwIb{78Nk*6]ي5ZcRs"b%1O}~dJ]g=(,n鱽$Jʺ $jE%HjYE HshP붿}.(nUaԜ}h3:kd- Ye7@%=*.vVx)^ 'LRX}:O u@b]y"R3| 46lup5pԵ@Ş*LFk_?qs&ʒ$PweZ-NGÞU"6$y23rL :Fu9>$dJӟ{*)Y\~WB)Р뤑 UїBRQ> )h %|-eIm TZ i80c*vQ^G~APm)th97#׼lqa1ROpo衱:7ڳx\]Հ̟˓U2u{UmOJDX=>]~S͟jֶJiꑡS/p^Z׼E4mOƃe1l!<sڍB2qk-3zmj}8 3rfze]Ac>g1_q ے3_F^,GH*X'2ӥ]GI§?5qv_ U-r1-&Gج3jsNgȘǿy8ܟV[b%D!X9Pz^GϡE`KsEc՘~yYbRts@ᮗwVm O2k!s/7Sh ;8)/K],%ԅMXO%_:Ӈ& >c[%Za$j2hLz{=P-0xI&κ\c9mnQ`E/oٵ4o@gKqv4k  wukQsT#_VG-[ԏ ,5bKƵ?Fp暛hY 2SlvNġjOs=kUD+w8OݻP,l0,/c.Paf ftKk5B49._BuZ^,r\/=:f#%3?=1,/RKmç;;'MS8BՀo>JNxﳝd'$a$̌y^tnqmEeJ,m@;𠸠X~ Q~e1[>}r+O$;n! [f IZzC 2/t.Ɛ(Wo/':uU)z#VQIŀo620.wdsgKYPC71>w<}YlttA4\\Vv,:jP4:ů@OGKD0_):p[|Y;'./0%/:,ıUa"%|gP7 YkXGFe_Zo|#fx%I';diqcˡ>Cm<=ʎr/L %d߃6 -?!t~13P˽cn}xG׬onvpO CaaIbcHC2O8g,e4ĺ2OVY!Xh94:S>d9Gu /0Z]֨SuūwzW':0o7w$qib&!Glޒ$pzGlqmCiJeBOFÁ")#,tUIEI(1]Zķ?hr.b(SP%oft5LjGK?SL dlJagQLu`&n@m`ڬlpsjB?`/w;(;m(#a<%A3t~I[!<@+HW}d*Zϲg8ak5V@/A@|ui)ZsS_~N(Wj i%>tRl)"PEޥ!^HeIxcF$WjխNuB߷,3=o TK2S~|TJ,OZ#QcL%~끜f?vu^y=@ҳaiP6A$#YW滩B_zb,#JcÆ/\JmeCjs"Xxt,P\N;j*N-'VՑ9kVl ¸U0ouʋ}PFBRg-}S9ꟐZpqC|tR!UpF|Ǽ:\n!}s2\p+\P֟YHt'|_ IDATڣk«c8>6B߯,892HDkT1X1R_ܡ;s65(r0Eb6Ir]x Ѫ=Ce)#tς)yW+2[16Rg5YDW[~ɾEM`ꬸ#EP<8}# 3<_, SفB" "K˼cRMuSNK0$'x7bXvg^2CKd;4NN7L}.,HRXNwlD̺5Z]rO)U`"Ǻ52w%Ds:s |тE.FXkz[hqnYz95^@<)Z|nNhz1#Zte`kYԋ͟s()a=#H AYF>#}8*ok?z9;Pan6*1ۓ~6P[%lzb$i-,*죅[{Z,Ǖ_MSk‘vOH@[e9i#ޡ89T{ɀթUɭ9pB(C a渨[h/Jy`}3YK?8"`D"ZػlS/rᮕ=Wl*RMXq"+FpdOv0`̥{]pAL~bo++ {Te' 0u8@LLGC|:K߳R.i5s:@o) Oby#cҧJnuA)]qQ75кGj6dbp{2BRγf{垜__hj^e}C' :nJbەMeՉ)I;JS}̕~2]1/\ B}aE$XZ{"'\V4Afrw0JIb1n4fM8e` y91f5/Y3, 8{;|%@$^,e/p У"vavS _XS@}!"FlH?tm2;=5Wu-i'Mz>uk;f zMVqXrVFα`rN+p~ "%byevxtdVu MJWMjr3P֩bfz&|ݕ,ſY:=۵d+  Z AT@ J>Urs6S$vj Pk6W/#]O `' (m.[Kb6r fAHQ_QTiMLxbcs}YUkj65Zz}mWJ򅌐֌Өv򀌔ӥjuP/S]<{d*5 ͣ3Ѽl\s=O?.圛"Rx[z8oVF9Ӕ}M%a.:bdO#eB02E]tӖO4w]36~i +xca[?IQtSQjUןl)36kԨQj?ȌT2eĮG9)Ig$*{L0jJR#Y7GUac,`t8&p\!2[vgʏr?鹮|̈hn|/3uS92NfpPTj#?33~ڪ+-pL)+9Nn9;y)߁v:':$(,8'm(:{Lɒf\sOօ:ՓiNB[Kf` = 㾏Zpn&ܗ)*IJl?dgB$123%j'ѫ zvm\s`O =樰矙 z)n Mr^a1\G[*g7\:P^i[Xw|iDTyRϪ2%@ʐF.odAzI^Z= pwJt`:}HK+_zWN]ZI!a f f.9L1?XhS Iuqn.Be,G E = ) k+?\0@nfR ed/ eIN`lmCkSڒ`%Zt XR_i ]v Ty}bc]NW:H ePGyvdM̲X.0RP^Eˢ:E鱺 /_Ԕu}j9ןY 6 Se.hE:R-O}ⷚ:p9c"^Y[_U*.\d-f9H"`ĺrLz-UD[Br\#BgvNL"d=q=9tf)+f}* u*1kiB\wvvTi;WD NÐmtýNQ|m=WOX*K_ʛ.3(.MF,*{{ `~pҭR ~G?jm_t:40w.Z~51=Yy/Њ[}b/W3FG[G\*.e;]afj[xQ"/%vM[C{z̫]1ӛdn>Fd7ɣ rڱH'v0a6Y6d5~-PcOxCj-++|FaiTiC{'Ak_m `Y7C2X fQP-a[1Ȭ~x[cTxNQy5p/JnRKsa[ͩG6L Q3B'<`p97We GI! Lg&(&Q7O+sDk-MZ6IKQv Cv .RdDa=X= V|Q@裑\y506'͎ nIŸJCɿL$??KoF?o/8gɯKmz>7zU~_ :EkC\>G4JS|%wNk=},e5Fsgbd @/r+x60Zcrg, ?dn{1$^r%rg'\ژx@51՗սc7|)>1K2Q\KӒ4u՚F l#t'[w]6X*Y2\[8<=fRP wO,$so%ux={lU$={#<P8 M/Ume,[A=HN2E몘no>vL)E45miM3JY"/#s7ac ?Cu .vTtZlk m?HƩ{oxXaʹde04%X:fv)~msjW6[+.pXwYFsg<07kf .@YK)} @dkum>7igc{#j)E+,< LNQ!'75+lKnE"jMׂkEl0ښ^E?b:ɗ2٦9VrjhbgJHgJ# Õ6yKo<$‚8BcX*6` wvu <\#J)&O `(n^v ݯҾ]Wg+n٭4BQ @kuK=ЀFTcJ <@fT :F%aI]sCOrH0q @G-b}p1wŃ.Tj6v ξG#{8xʗcj3w9z {A1?s%7~Ճ3BқE{PG+L)a2O{R[dC E8`$M&2(xT_3z*V_=#;#1OA@Z1j\Ɂ hڱ0)kc}^f4>%GаWv N."x/TeFn'0'a_,d)KKuqAki[sёfB3n `M\"\ bAK>n7xN~35ֳyB U[$?.[IU &ՍM}O\ҧFۭݦtf\H\Mgcͨ%ӕ]Ֆ;cG/de:_F .lE~ylO7Jmd,_gorO 'Ur=i\}=t n~Ԍ ##"oPM e'u4 ݺGM i0mT͓\jIyv ~(B \1(dxs0R"u^sx2XuK7ƽ˩@qѵ/-]>U=eRlϑJ- >(õr}8*:L笠3~7]6nxݡ}?95n JjYܑ}b|ͅ$&UVi 1Y75r}#`ֹ6cSR}d3car=R_fc j,j9WЄu<$O ޝ~2L'sb ]3X+.%u@mDžž2JZmCZݼ1k]m;7! |ٶJXjڹ;v]Z%`C~,Щf c6X|i'0z;mR7C U>&{VjI\x5Ds,>էS7mp%K?np#p.%)}Ýzu]rLf%XGbb~zŀqCǘ=Ծy6y%l_{YpYz UoHP)]4#8C~'\i!B}׌֝ܢQSO ;hNȈʛ;#K^Tc,M9۷l|zfE#@gM/ԡS{+/vo늡`(0גHZ³6g*]R%&VEpew&#T0Z ;H$8k1sqsײHG(gK4■L1@F֕=.iU.Qt#z\ReOVp) yB,׻5lwkU[6:{=_CPi2Z29B4p*#}l1& )Dy`);yvT2hy☛C`$j["/ _ ?Gĝq8e&d^^Lc){\iZ{v }j6<}k̻A(b(x*iB "N%6!71mIY90 e!jR'u'P!]_gJWs}>2:,JstK/)e4(ǻ7i417d Rh%tS*OB_6sDC ;1Ve^g)_9ҽ /qeSR7z]OTR8л߇<\ad:`ud{Oq.{4F.+nPW:Gk:R'9bCDWjg>uVn TD;x⸳ Bwm-x^G6{)_&kXü:FʠNw_J z1t(*Yhi1cFԻLrZsE*w-Wu؟#þ n4ok>m37>jh2Z_g)iqc / n2=ι\`?_1T.2w_a>TV1A<5A(7RMhNz*KN9 ז@؟Z+h\~%w}FkMHN8} .G|}KET/r:c.4.vi[ =#]54l_M;77GNXJ^Id*ZZtUٜLj^kTֳ^q FSq5ZNbw.4vx |RTZ`h#Eyjk=҅.]Sw"z9z{ ك~ 50}ȟS!aKF3y_aW~:&/h$O3sݵ wdi$`a._$[Ov]z 6D?; DŽ; w=_z ;{gmk8tL:ѳq\v:J lM6bn{r'Q_X&UnV2Jߒ}qz.8PsEOo/yMǔ7Iɴ- K+*Skm{Tڨǭf13.20\׶၊(XHjv d9y*)^> 5d%нk\{#UQox˴dy'QK.XE)pi(rmr bV},Nt,kQBY#[<0{G3rX}w0J3RK=I^Lcq4!N}JH5O)dw`33 3w8C}B@>`"Ylqq)Sh}=Fj^V&6Ue໿ %[k+5u:FIuAc9^y繒G iNX齯lĪaX|9 ;IrGvk۲v} {<[j7[;ҳ@Z.|0(u`LpkY߆tNrHaci\Pz8dW <"Y _K?K#SShN\2G dN5?0OEpd<γz1(};fթ`-ynZ}Am\hs4iMaeWBvp ՍqaZ]9ԣ\ x2&El Pb;۽ܵ|M] $j1DgP\a8<9S"ϷF[zX^b PRξ\8gbS:0gO"^!8%VkYC4>u1#,DUr+U9n$p ^d87cdvcQ)('gVޭdD)EkYa7_NYj-1`c7%ywv>4ɧQ,C y1K-yz6#7l\S)C.0>_dlRlyGvgk9F ~|j DI -eE})S[x^jylnlSZ~J;ok%|/OKt W289cmA=;[Elm'U*?`DLyаf_<چ&QƳ*oXG7|+{bGxAћծKeR~F-1,as2MII0<ķ-WiHRZ$k(X :\ɥ)FM8&K=9h ,V~TyfQ̕dke9Cu"1203%CC%"-"|n'_v{evS}]aM4dx99d A^ٮWL˄8x쳽#z-UE';!37NI[; ãcZ3&mxk]4U{iڔԗZ+D6zRd}'E:'vM\J0/;R[ṳdmz`4I!4%unʓ/݁ht #Xz76yr8 S =:N7O̦AOXf\&1Jɛb`''N5%͞ Tyϗ叵>h\׸W <4e8ZçeE?cO?g4f]9 s]8$k],y/)e?4.>ҲlTFsYea^ Ƈ̰oij]yF;fя)ԡ_=z5[uJ@+z}p0 dK#:\vݿv. ]_VVsr JE'$f\Mz% v`.яCp4q%Zs.K^ _}S{t1`+-Su1E_8׬~ɳXEV`]Ɏ*ֆ*7>@D!vܔ\YtN(2*f`MYJĕis~=&(\ϻ1{eClMjzh)VT v~nsaj]Of;d*AP`9 RYCo2tă g\w5_?g[!6,OH2-:/M`_9l`=6Is0Hдq_|xv~)Bc}jW@RqAKCJ(dx~ W\]EןH\w( Tr;c^i)14qdXYDsBWaf/\֦Z~Y\ .#SU!#v]FXt>̺ w,r@b O6pLc Y&Qɣ!9ur}nw0!GspF=M{]x _]xIY#`.3g%9ԣF/!3plֱ-|g胖{٢1bA*N5衻dyǟ:J@=1@QQ(e-\qe]s[xOcOi[24>:òMS@.Z_ȨXU}MI" * JkQLɔLM3ɨ{' 6d "JZ!W̃S ظN݇b )U4YoA0l-Ħ+YmɨY.0o|j m`V0J`xs+*y[A iAzoFti갂}XW|K.Imn`l:qew}PGW%A1 6ќBG]hI?̗"ەGKo\0~^|_l "[,t:T H)h7bNO]KzȷLc]2aGAF?|ᆙ QPJN/uP} = Q@*Wl1˨bytIHQߌ5K.LMj;ly^_ճlVgb,!,#~Po!|Zd_M@G+OXpӗ0/ixʾrq)s:;eMbode̓`};8kYh| jk6Кwl]f|4yMh]!D>R+)2" =G #bKG%yC;HjpQI>p׏Tdd#ʾ~5p~\&Os Ty%ϧ񯓛:FajrP c4֧rBCՓZhl{1ݣM[\Sf4M4$,`CߔX|ǜA1AO)9@>Ȧ.'r312?qv59,)wvgf;}=.sGT%:i X…}nm0S8obvƇ ut_((`e6I%_83gM+byڥc4a2K-S3m @r"dZ2zn*qUly<߮LNY}$9a`rVn͈q./3@iBJp_hPM)r٪ilrgkZjϫDuU{VZ 8$WJP`n(d^_2-#'9YűNɳ?9 ɗW7G=9:_{ (I&df`\Ʋ,ȳlfgQ{*ݴGe5x/ǚR-Ѐ= X3y:6U״R%g迈Kw>w/џIi -9*TTxPV3nbj NHY SfKo0P~ў#FIe+LG$H&%vtw/ZNecEޅu-u\ʽwUwSk$"1Defh?Vխꡛ54L׷}}o(:il{fȏ)69{^W犩lE)?W|:6RԙkQɩcXE'OcJ=}F4sI=}#Nɹ R]C 2y(dK+ĥMx5]̥aJ*B< e!sAG44G 3vam.s;idv [nQC$>`w՞-: x(>uS@R)^:]G:FkHQG/-k/RHۻ`҂Ju a$<q>m1T2 z0:E&xBܦ٧N ;=!L`*3JJhͬ5냷:_|P z~ 1E^RTsc=s7:F9ɻ.͠b˴% πLf)8ĘtZwaydm-mA1s-:bݯg2rmh46qXl|r{ZacٍZ>?nG>I2f1u.RzpӸq=#_iIh9g"IѦo|9eƭ k];!Uy+P{[;$}{HZ|o7ٸ.:^}S:?ʛy;168št ղrɽ+9hŲ|Ȣv@1Ug4BenC}NGZĔM|ke#6&3cM K&uw`O N*^BFbF.~Qw1iyϢe\HhܻxqmP: έpd*{+ݣ܋rF##2X#Dʿ{X_s'[޹MJéIJ}˞lc7忘<c(К4~%'ru m?^q V܅K~("Ip\zhdx/*Ӎ>bXRV1~=8 dJ+Ěտzsqm`晧_m@ǂ KXW?N7jlvI}qT$WpXsqЪ]foz 3辖/u!ɴc rJ lWHaY^ԅ<:̍Ww-7Ν/.fXtĖ"@k7&C:aC1V>dbKtK뷯; ~CG_g6Gm 論[Vۧ Ty zb#ﱖ@Q>>f gr"0Nmٰlwמ̗޵՛\ɻW qC?7qJ6峱238v_mM~nl!YT48܅@RrbiH "7kŝߝ,Jm@oy,{%DDjʼ}h)eU:l:7k_س{?NUe߽oѢ>qSZg]?e cq[J̀\BiP ̂)_eܨ<-]g$#f [.zi02PJEoa =?y}܏ LbJTN9~!1Qf:3̻ odhFs -|Vph!~4]Џ`Go'.ajZ.wz;s;pj9D Mea y8u1u-G@UkoKKO7lc,8dd=f-Zۺ'{3/pj_- 2j×h\ʍlhҔxK|!t?߽qKkܤ,xn.S+q`‰Ucsi!hFٹa{[8%"ם8' R'ZMۦLJ¯Cwmlǿ>qԪ{RyҾAYxpOx ß6o=oW8O& zk7g(-RVLIW"]̛0`]dFK #uIc1'rd- 9u]v&ܛ?r2|UÞ {傪K߿{neaơ~A9g?a!cZ-Mu;wowB!Vgѳaiw};Q#hiL: Tk(#R@G?5U*zt+-x7>ܜjiM&6666__fD .",4PV*C'[p$qz#1D5+ϩ\USիqx8$өda[ݙ [Xg4)tCzd29HEMzh$"ѦXS<kĒ1HGL҅&ΦEhYo"͘ ar1ֶWTfjơHS)KZbX*i-\v{=6%HÉ0@GhSt`2gUgl:\5BO@C/L8}A㦄E?u|MObad31Vyt_;txqiPXzIM"iv{$ 2sWϚd$4R{䈃GA"NୁS i}qԣIo0GGMxK53b³m `Ut"52ێ! 3FQ"GE=%,߱jT`KRiaxC$0 UCSp T(y0L<%'/9) ])m-K(՜hBxO'O6z' O7r1 W%& G~S|R;>Rr3),9US\恉 -Hn#Jc;Z\Ha3/c!3j͌F7T UPT#_R|tOSpN[D⠵a>sTVCJ)[ DFDC(Bp&E9^e9.F׊0L+[ C(͛WduhTdAE$6o3ؑnK.e8Oɝyj(>|D]5&!Xt:]25D{UcJYS.56FivZ=AJʈ6ͤBjoPhv`I1*ooDH+8n`evHh0G6-6zbg#y=[V QY5%o,JӪ3,>pie|aI:0 77~F>RܘHra=pp'dM_**ZdzXYԻ=#s,.Uxͤ>kY8>!a*[(yNc:\^]{0r޶!h\}gEBT#PJ0uϳMKT,wtpks$JC'%7qV0ҊY _'HA`-܄{Y1tCgi0~ZRF:$i+횾4PNpꙖSy"P7FZtF{6  a8]7qȤ >h՘r]i-*`JjRw 3#bKJ&|t]gAtT>}/M'a+7+BF2TkF +v[! ˭8)iCWi%}4LoRUJWi۳eg7Y0MspݵTrRb̶p0iRt!2b}Њj-E{eVu(OKq|IENDB`chessx-1.0.0/data/themes/boards/lapis.png000644 001750 001750 00000164312 10633750627 021117 0ustar00niklasniklas000000 000000 PNG  IHDR/bKGD pHYs  tIME 3 IDATxڜ;,ˮ$$@Ry uOτ8j M!p#~뼻w}2##_"LFDD"LDDDJ׈Hַ.2SRwϋ\z#sCfJ%xy"EDdkWII;WM"L>g5 {Ž~/?7 ̿!?D9/M}ɐ?xL5>QIDȔ>{GM%*s#2׹sB$??G?bU9`sDbxnscT??n }U0,8&5~!)%IW2"퇆R,?.µch5͛Fo"b8|]4˯{|]eS]q_Z89nҾ5,m3u"*Jblm⾯ ~-blfM|Mt{tf4DD4d5"V٪=jR_ދznFUsyOj>/Oy1ZWY'/-nӖ "ţۡ 6k`-5m@?[Dw5@>;̞EA{CFHӠN%yR4Gsoo@Y ѯ^Wl]%;jfyI79)Z#n RD(`}!"dyA [ۍ7kx=QH!ֺ!z_RzO k2]*tl ؿqu]볬w}'{=?9q2:`"}7uH/Ccv/"0-i~9PRpN!zNr < 6~L !BD6E9 h ^%FbŻ`CT뛁Ȥq D񴊔X"9P9=[\>YV$yH6loFec&4H >D}^ a7Py&A!;YRU;Fc1g!uDGHt"F{~SǼXg\7i /1ֶqkxY1{;qb DڋxhŭԮE2+Hs%%*oD|R뉧^>~mo"p0c)ŌK贡RKC=X7&|\lojvO,vD+>cx0G1qݟHl? }6V _7EEF"XS L njsvmWh7zc,W8ڟ#YYaDV RB>=)VNK3BP/FzXL>ٚ .kC8Zibd,o!: wͲޤQ^4^C'?iDf9mIYЦX k9NMx|\WKʇ< kuަTnjqOsvgP%`N,61=37 ,8EQEZ4jkL2Gۀ"I JY+'CZM<ҭwZ iWv~}gh.T9m&+=9R5k,[9-Gf iI[ <B^5g$>#'CƱ*UBߊn$75~/u!YXXm;f+Gb\I)1K C9KcE?0(btO%ߗ$a$ݟ]g3eJgC~2YA$ ]͏/h,}Lm}#ʖL|zs~ھQY0TDl+{<܍rzj^R^2>yL9 ܫvq*mݼ\mG]vs%Z_$AaN%8fN}p hU{A\saItY zWFx,K>P.Dr?EKrR"E"3Oތ{ fGS5!5"G(g@G`}ꏽ1 $xt\C8ů7 d5FM eLݾ( O1@0mT.3%4ZaW=ڄNRA"DS1(6!p\Q/ y7J.e\Y> Q)e9<\^Oҝk??SMԢ}^̃ ̹h A4#*BĦp%hE6'Uo(TT%E4Fo2T73pu٥-2ZjWa۶ { >YžJ*"\Dx_I AvI3Ȁr|C$KB*L_#7L44^iO0d>rmYcۗz̧'yIkc 2Arilo&W!ZAvf v"I-'5MHUpii"UMK,v!;" F2l;ȘThF\WC?$/P)Ѕ ٹZ#75C['爤VUyzUlL B4I"Vo _p"!!Ct E0o 7_z4;yo.!]%G)EXܰ*")*]KZe8 YTɫ}kEu6L@&$&ݲ GJ*,Jݭwk. +-jPdjWV:4+&h9#s].6pVglҗId*F,KAYUq~b6'}&g7G"ȶ\EKE.t+S C4rDaRfx rKdAL9>B(mj?F'Zy[KΊ3/s&6dSm{NcGuZXMrC| j"g)C&sk_eE&t,ȍ6GG9Wɨ!дx'|Ȥr۠aL'nDlVzca h/a*wN+v!sqv>LKuBg h_j"# p\XSl40-!=,Ok ~D4۟f9AAK\Nݒ`YAX=A!䄟Z'w[|>QH:+PN4jCPzTh:[un`܈NbN};$:qhSQp%$=YB]7TKȆ,Bd| *L}aڇ]_uv,C\r:,34. Mں#POrO&釿64Bxzjȗ] .ߏD$E5,}QWm]R*Hw6K]61̈́Xl*Ziө l19R>!%6,uq!%WQjߋ-pm ;j11o\`J#[j6#}%.>uMg9 d-}SN AZ-Gy8˸1nX 擤%H`MҚyiSA[ƋuU:詁Ҏ*= 4scYRMӔ Jkj6Ozў.q.o{qko{PQDVDNzzMɀ}M] 7aj:AM;2Q#t[AZESϻ:7z a|7wYRvp .~/ZQCx_\ _ZÔ)#CyְukmFMy-FTA PL]Km09 \GE:B QEo=u-J7ε`NYj%Se]+ᤚ穙T=N'Ra} ˞Tk7ov=byJ.CNbFɵfNz-V)r"f٣Jm'Nֳxԟhaį5q/ki$Gyݷ.F\M|]a3O)s#:\7SJMgJTեHM~ӭKYPZI3L6:qZl^R*_:O-$x0tOOӼI W2ۣZ+ڴKv0HKN";8psxnP7!d=<&JK#3Ӊ9[x(fƋt6&;9Y1/!nDP7Ss*%I{=}v?taw>OGXsC#dM{6:SAw[/8'[OG4%|[ݤn$Ofad`@!8"ꮑFo>onQƂ^8Ilu>fӺb/"/sW:ҝ$ 8bB6K<د>`\6d<x|WgEY攼stOD9/Մ_Ð?dEL(sqˆyS3UT4Bʸ ~"gTW.AyfEE{8kiL'jTϗvm6ƤWI^)椣.:Nit ^Z tn#rY}ZڙNf5X,{d<؛x"sY MX4FSՂd=afZYs4WRb6g}&ϔ[{6:X}E0 d; c]&x(9wdmġ8X`fҊ>{xFʿgy!q0|-~F:Y\op5iwl$? R;|W$X 53ZϿ(PdS*"tۇcEo[Ƃ:Nm(ifc9^c&[Spײ9y6dK uk+ؼ?7M.xW{* {$(*!ن$]<Ll!UR rpR>.؏*Y,fIw1t"_vK@x ֪6x=9@49QӒS:*^]] IDATg߬6wu5+pGnE DL=(Oc)޲Wֳow5TS1ZE*c8^ScuK.إٛ!VI^ ٫`~M-}g8wl$bduGo@$UaPYb E(*=фU TO4v kg\|Q-[낟B: )9Hz۴a]\~z\H۸f_ϞC}wB+@s83w7E&!eRp-'Ts7:v"GXEWla4T#z`<4qH|:=gf I6V8 G49u)' V̠| }yDENV;~W ޣ^2BS_zMІjǽ5Zj wnzfʟs,듋!3_cxZ8=Z%#ij!H7Q=V֬vA$t)t6F%r_Ne_`HjRfHV_?P2NuNy<'4ye}s={{]iS),,OiAN+({,/G5>l D鎌1$GI֋KȤ':~Hv[ X.X_oQ 9j,Zd8<0ۗae gl lvW1ۿZ~xb=P@{ U"ix矼\2y'DtBv]ϟ&|=vd\J_Dv]=U6X7I C$ a)(Pnк@j)=Ng]+ԜM!#בylx9hѻKQq.Fnahi;JX|c'#huݛH.\GΜAl6n~9ވ iQ ^7gÈ=LеAQIKO$cMA΄һ0>=PL  R\Fx5s ydk1d'$k҄1x\ sө}aiB^ dü}ZkU8lzD~a7UE5# %U;>ſ꾧_8 OAzEq$M'% ( e `\0W0q—v0rF3m4#(+f ס|gH1)pf}:OOD`wE)VO.u ;LL> O \\:; y +-)GΦM9$KMܽ^5$&!+[0@6oh#j%MBOp8t5-<W+,ޏWS {]lMM{ ]ɪcQߟw֔i)pGc08߾N?l|xJt \BY{>li*Rs]o=K K-MðQU:eMK'̎R ׸͓a1˼1ЦϙiZd*ќl6y١[Nw}cSAdr TrI @ؗI.k6GՈ&aΊԤ.D .E$pulsiQxX6"$5ZujOXň m 2;9SN,2XU/%#~%cpC,"42U/K">Z}rqI޷oDh ؾ!!l*c#/&pMe ;>olri&$q],Ӟ&R>ubk.(q5Me$oxS$!a:TMFE BJ4z)b4"қpBh3BbI?gE#^iS0!0T[g_XhxJ帽A}o#PV=0de2tkAL|(iz1IQXbUfl>f s{ ꭶLS4Ѭ}kTU2J 9sġ;/waӤwҍq'-xͪ3 ^E{ٞbj,ܯo)Z[(ttN=S]P|+ gQ:ev9`{L8d`!yߪvŚDwD hŭ96lo.P0?9rY4'wi$,OdEZ2t$hІ(JG*G Wl9,~PT~р.qE(.4'%21x?"=67mPɩ֙pcp Ͻ2 Sg3ѨX /l$:9>΍+EveKo3!5iތY2OÝ ^ J}$7a ԅ?T~56y,> =e{iHA )j\Y߸~N#Ýyn}j+f[2DD?aF;VmZ`8MZȔ)"[=b&G?Gx"$iC+ȱ/1nibGSjGwmija Xhv RR\<;Bș֨0ƆXנwqś}ȳQ=m1!:PLd!w  IӦ$K,ⶥh +R1UwYbm}{o+N31{Aa͠CyP0U(չ'H٧?c ,q ;`Jm7#o$Jl7xъ%"-$Tn,Y"(fTWfI.%NFN[ΩH|2͋$9vkڑ̼Hvt, jxrotN9i~hje6 Tv\?o>ϲ&9GoKAs*{u©#Py\S Nj)kyFi4o)jZ}?sC5 4߱eDOY|7Uʄg.xs\tNx2َ6{WsD' 7"j嗽@W=Aޖy5*S%.I +o0{A2D AEX<:ȄZ}o(0}ґ{XE<}Tz=p5~nz ǰCMBahe(9'Hv4ui4s'`:׳#0p\/dit&يKG["`]usҋSkJ$5Ӕ†Új76[ g'2E߷A֑ߥ>Q~fU=wI 7)SЩ2"0$ԨAGלx4{+9=}3?k)vx~`peYq=슴`"q <^g&zjcNg uňVX\c4I:'"UկtrhF%(1Te/s||x=[\r* c"2ȫL3\\^[rc[+Gഀ0ʛ63\eu_iw2NlÎ@?i8ZIXeWtߧV{Kogs8ӿV}IUO\Yc( i&"5co[ yCH&RBDib#d@0m&kZ"Y]!_@B[שP&d 4 Y{߅}X9QMc&car'$rG g&<)a^]j&hlm}uKf/֮w4Z9x˓/Qc{9[~TV۔bi ӊRQHd]s܈/f~ٜtlW4iZwS:%{2>uL#acz:죗b\K-qvg`_8k|QˢE^szh˽ ;"ݷ?4Y^F>^_D"3 ,m3+wߚ;ǴB.eN_sXo-CR/پgq˨׾^c0 H=(!fGdA'r2k|5%vk+J6j H'$rqcQ_/΀,_Mjt:9xI^E%:ϛw9>IyBij^[Chu#|ggCO7] nC.{AFv:#AZW]2?joD"&˲{ N3 gỹ~NfzR_D$z"E3*Q_2"^%?g=$"g8K(5c&Ά Nu$B&1uV8֕y^6x2[ʪ;-`-3k()Ă׺mhq4,2 a˸΍ӦiF4Y)iո̓5s߳S?)#єkҞ5X ާ-"QR禚uIdZFt"T|QnY2VtǹGT\e$Est(d|T;\yϺ1?aQTFlV<礼$> }ͪ-ef/ ϵ7rGd5i!}K8->*763x37-'>2*'GLQ,~.Hp(Ɖ=ߔMyhL&ܦVE'\ĤĞBm${4,^ɨaU ߚ"X'l;qCN[A Q>c݃]؏:d4AH&^s?wd^ Z l[#;7>mCG۝#A_Nc'1йH}d8#R."&lj~4I # ?i:D<νx˜)g9@/NULBES} buNߣ,%jhQqQž1{N Esoc*#҉e6 0'~Ӆ]=7Hpq朼Jx&Ja֡hߙY,(6_ ]PS=DzN&ipR0 ZR.Y+]z+ʁ:a}Ko̍IV* vM :E9Pl<!Oę %GGZ i!YOzxYZہoHhlCX&ۘ`O(}v)6oji_.do'4og!j Ġ盪N7)e z!5dzU~RCڛ"v|¨VTDKX>E̋?%ЪOڨF .S?:qOhcGh̅$.F^a#¹'qd}ߢz뇊GJJiņNL!2S)Kga kyW5 h3ëjOz&q%o>SF4Pbhȟ4=e\z5ĩhTpDnS$GMck\;}F_yBM9k ܐ&;ʵmpMDn,> G4 \Cg&y抖q;[*>ǫ^{h#!]k_* Wc(@fV;S*e . l4p;n8aLysXRP$Vj^M]}SB;hhj\و IDATfPoB$N(ZNPG`g҉M2ݿ .$P6U=az>Bo#>l$BQ4|o'^ǟoGBڢEMRZ[\r%8ܚRDjבnmd&C}Lb D<Ƨs/hA:8;c'm(8C~5=r{=P@Cۤ ,iHVMWU%ɉ>MH ;ɣ&Cp2)ٴ 9THY QH2wfkr0d$#ݼ# -Q_ts2Կ}K_bHĉ׏d)ϝ \ЄU^T^䖂u˴&+_`1향u?$qzVPvر^_bui"~%YvJAՠ6~JCEl:xOh#Vb ju^{RnD'zP~2h.$վy1:vO|(l^>&Y'f vL96Gi.bWo 9z[ .oCN R*ć 8.".B`yaSQIGu<^-pov S۽jw΄ŇwNf[haNhQ!9Ej7L>Qxf죌cZ ɉC#~1=ѽ|k*z4l}-NDڭwH]f2+V@h10L=-#+Z<^/ =CKh֙X "zroVֈ8݆=poyEQ`oA/sbg*I@KFClKW(hP4TAC:Vag@!կw8m[?$͐1œ̷*v 4H@gpK6{zgGm\ǹt}dRdb$ Km`Zp,lY̎M_&[q4ըb5ҼId5 U=uY3H} s?:h?hNDNqNp!H/.x'>7ſ@Pq}+>Q),R ոYM/JXp(m,=9/*L'apoJI-] /!9>rYbx-I"hi5uKr[%$7TIt?i`Yig{ewȢt}h3{WɉPA1dA/~[WU\[\e,>Z=:UiF#Ե8}8!J3}AjYZ;МE,#a{< bJT:3 ))J ]ي0s)~f] E0sb 3Mc^|s Sg9 Rid{PZO-d{Z4^G+ JF,Jݺj〫)ն,GkVꞅH6Op2<8Zn>в 4! |FfJQPjq)x+ZwF6*ʊ7t6;uNLN`#h3EA<v9ʱh>;*k#f>ErF[?W{ wbO]=fAn7N6#}Ti_UA72" .)YŧY' [ Zp&]ƑCڞI]I(n@}=CӴfxZSE{2)ިK{K 4 >؋i~FO@Jli#Idp46 ir),0}ˣw@6&u!yYQ̋1 Mz Xqڠ7^SލXkD& Ұ] [JsP½֚E{(̽|Nfj 3:6\gٟZ4L3¤L̶!6{9% LO4RR)E~jR,{>J}%$#(a^&0fJ86;4?s 1F;_ S$(=ILܘAO3`١=pu^+?NFH? ?J;eJ7ZmmWuO*dNKsirt\CǧiFc  xS(2pUatame~d%W|z_+˂j 9y> YkdIN!up!G֌HC),C۟MI7QNk1jD7XQqmKGsOaȵ4XO a$MVz=XD^@3J P+鳃6ګnOͼa@f37#"=~ǥ'd&ty _aչSrƦIfdyC-%zMo+](ei$YGր F`DmuCd|ϣ)ij_̺upd$s|+@Ot8ѕ9F TMS fS&T'jMAɿ8}gykJ<ղJE*.v֥L^V!Xp!J0pȴ6=_N.fvLbu?~Zt'yӲ{(:6FiS!p=m4t>Krx,G1;Ƨ&7l+R <pG=:N&7#o>WLpkԲ9t sʰƒ P q@I_dR4\s"!߯V?%7(.`.jm.&S6/\Oyyyȇh~M_^J * pʣy*Ӗ R=YuQ%kǥ1C#ޒdaru{R|hvY䦡d) ڽ8%ac?WBpfwY 5c$̬84 _ ^m#4I2 Apmu~&v ѐ,4'ү;O p[S]v+0*JC}H羉D _?\a>r!ކ&פJah$v06Z"הF.V:ܫY{ di;TaH a'NUXqPX OxK CJ)YË}~=׬(~G5+*m^eUA"<١WMgUh5v)wgntJ)TϜK=k=,/ė`Å<w&Zmd%% ':'EVT\>?Gkì-jy x+O= PiDQ)z1$";ݦ2/\G"xjYSlgyV Z/ ȥj{]Pӹȯ'߃!<`w;\ ]WYSE6d;˨m}ٺDdi;>>Ѥ?t7DM#[;xhWM @³oy:/Wo3'8ggy MsO&U9IM4rT5 ,d8φ{ 垨js953mS ӓNO'_Hrj/A~0#% ̛HA}];l電z K<~oIMIG֑y[TuI[;dO|IWx3)Ҕ1CϻԚȠn)xM3&+ [dbBrR{{7ޒɼw `>Uhxl;-cKfN0`yH=`uIl}aweu8u֒|Cp+Lvj_=' +鑄^ f'5آ9~tԙa !?$ݛS{׭iچиו iY nCf,bݠFH=)D2@Sf.ӺTw3j6ʁ"X7fJfrsW|*L2sLO YxXs+El?%ѾN֓ u8bIX`K=ϥ|w(J!r[)^yQwi)Y`N1.-fZ`}H?cѻ@|5D20r\+3m`̷S+!JD|.뚋M~ ?NJpѫV54m C-7@g}N})ל"К*#i3˸YiIPOTjoc!j'mO˶A2J}QNە<2m$ yOY5 7 gޡk%`o ;rM~vpνSd'!!nAz-Jiu~HՂA0`ӳ1);ȽYSG ~rkM2fke.JNP~jE2"(F P)ql1Ȼy'_7d=uNd ha~<꾵D,yf!jǦ?"s.̣]^r|MfJ[,*ijQ Z(8뒌Lv?Y]- ҩ>Xʋ[C ЧWRDB=j8$q[7kn"}@عCYV~_ rAYD $xb{qBGfuvlIJ@MUI}G[bjlri Q\SEkP!m`׍s,-*8 u@\B0kK^Q*{P'urIudf=)gG{9l1_uRcpL 򭠫[V'kUW!W03U LZBG?J:QNry'm};2mfW8MrੁaѪ4%xyp-V?_TC$/KoZL\+ i[*8AÊ哬 |64XoMgC=(?&fr;<6:mam ќf)6a4){{JWPa{ VGżuf*Hj)DJԛaLHD%2L韢ӉwOf-WVWqHݝH0dLԬsͶ; =1>pM,$?,bڦ]͒o@XfC`hQd'h'G,^vDz|DubD x]⃲{RU,ymn],>\{6o6X'1rhr8:g}6=Ή]3u9XqӂpAdYsP`R w{ LTO}3ᖳEX9.!oGЌnIjM Ka6/S3M:_yUB59;Y,'㼑mOMXzH)}&RdtyQYO<"[-͜z4NAP(K+:_4#fq=לZFc'ڗp6',sTCQsUu]s\b(Äds 9{^jy}2iiҬ_ʧijr4Yl#j8ѳp$M` 8&H% ^ҵ|Hgx%ϯz\k5O/۲2TJA!7m RRʍr^{~F4׍5֞[CԆ '+3+ |B"J'dZuT 7L7Z2==Y±$+Ӽ"7h0p1Nf᳠¨x[zAQ|N]j58N,UoQ1Q ߩ"UR?74@QĆw+[g4P$e>u]u!4R*7x)@m4,i9Axd b[}ƈrh:"=2-0(낚FJC*n4& 03 GpA&ɦqU1>E,#LѾn ?0I%lͩ[[8V+ xNJTp Z\"'ӇTd!{F:Z:Au(. {lJHSߡ.Cש~[$J.Pzu.Zu6QH[(N H.n㺍(zh2K(~$0nZ/TC;#eG:/hhA|r~2$qQzmW)z#a^ P `Bk.>lE*/O< ȘF+".h(}.5da V:ޚ61ZY_+-Ro&#cil:&sd Tk"8VKu&+$F\CQON}AaILJCAvt$lY`I498SVF{(~GPA܀E٠/I)=ՍR{P$BJv?j1L'5 lmc'ttp_KՉECY\X`eAHF7S$n)C2s;J wmܝ4̒w4%5&9J|cΡy~"h*|2ay&RD' uب+<'bcv(׆(}&}i1N3iOWeHEI72y+: Bl04y\uL.˭QMyR=~I?Iۘi[!QX[c~ZԖPdTI–XI$'7VUөN5ünGpIrhbn Yu|nȑR3o'uWר<^-Wчƫ^SWgI\ R f t8U/n X:DXO_3ծHZӒlW7LҡŨےho9MICS~U2VjSLTA4z cZHܥ;b.@N R NJ nygY(K:̓9(E+YRX 7鹃3o֊3L yo0+qVgcz%ܸ ,^ ,Lgg~EaV1jk~/8GWaQPn#$CL4ȴm]'Ӫ.Ω}C\i]Xbu LX<b[63i ڛ̤-i뤰l3eiTL<)X~ |;`ãI;`KMF/'.0V\ hWdcr&G~ARadG Cj=hmV35,(ĚmH[៿G]o0'Fn@Ę䓠yEd,"^5_0;"9}㸕oGݶd<3OkU)#k˜ۈG93]*,f< q Ta%5c e=3pnEh<}N1DԾVfV(d)I㟅EB(fOoygؒqj*ͭ:/`3|%:;%CZᅡ{ziiGJISP۶'%)#롂~WJ#S7a+5Y$Y>еwm̷a[^iGGMņ譛D$w c=8'J<шP"e4udًhgBU7kn*YSU-hNf8$R6B-z&ӡ%u9uzS,&'4l Fdsʷ`s`+-F뽎 5"k=}<@ՠ/8bqe D{0 Wj=x#͙ >ra4c2eyX ``1&46vwW,3ysHp^v/$6qW{3j=M[F/d]H;?tR:jȣg{tJI)DtiLub [RV<Ƞ{"?= GWX8=,mGµ/Ys΢Ov౟\IR!wY !'s)`j|0Y` 4Dc0Qq:=HJƥҍ C\jNA S6n \G>srbᩣ1\XhSۇzdz UY-zC(7"tXr7Uth_ſ3NesҾ>w">wCY_sycHs5T"MU׬;zh|n( Dg=K'`p\'t1i{ K[Xk^Zū)J& 2`(,>B"r, ڮ"]k\7T|t_ɇ 2vMuf`=C5J`^tҠQX.q$R_ ?uu awl~]5؄JHx|[ MGxQ+%SwkMi$Fz>ڗQ]d. Eb;?v G fOwk 6~ @Zvg=(:iFb 3/E]k7A1pX^d!G'v(RH}e!'ƧyǤWl{LcpǠQ)z`q"!Wb{Ofj{ڟj,?Г?qŶg|dwںWB,tMfّP#L/ռm>A$5A6 8prrhsI^T裓B]iY,[5(#H4UMf{L[5/&됝22ĪQ,{k]b66ͭcz96631iL qRTVGL)_$3wtiԐ P _;IPlR"S@'WcTy6$DZ^^}4\Ƚ P J5O![ġC* s]$ZyoM3eLY )a>hQD@ PY|98ͅ^޼xdPk%A>zCqi ˛'}Nfjrz4ザZ~ɒ֯iE r6RXO޷_Pk4m*̺#LGwk~:bJ~v. !I[`ܺ0&gz(IB19T0cq ͟5%B۠;"D},\Gwl:q p5hM)4R"Q X]7:¤8^M* -ZOR4 M,nOF Lj(%qcaRs_G^9jWoJ`J^k.1 {~AAA YЦ)A8Oda;H{A49lHyt8Hű) x_<S2j8V{ ?^뺰ٽBBdXx?/%,eVp}w #"^64||v3% {{0X R ziTwo_Q~I,f_D~iJF Q_sRM4P46ʧ6eEO%oe٭n$A[(|ack×>2RY$ 8ϒ^`#E*([>Qzqj:(tX=]B&O|AIW4}%U4retХr<|N)Ns)z.ICy%3kCL65pB_OR@9G)GW$IvD, nY!(Rˣ}ԕ( Z!G͝.̌w7`^q.'-66tC8Ou:4KN;8t3Y׉c؇MP6Ġ5}bfS; Q"0Q\~z:<#lPƒ|_ #&Q\ɡ85𜍒M寅9nNF6a#]"y#yGhTK dQ.6yF)p@ʤhN11i֨QXލN}}WzNSy UlIڌu MdBգk^ҽ,6/ɻbYwٽQ V-X 8R?bTX~e&C秇 d~&-P9iܚH2f\Yb`Eoc=4a=L^g'8ޣbASy:Tݥ~>{7|0]׺ݥa)RylpPΦ p5K0nBPI}{,gEed-էaމ99q- ~tְ sG<} 81]pչ=y0jRϺ#dҗm{o}XxAc-"p@X:~?׬zXJ?4Qj n\e2ߥZli'ZeHZԵ[GSs.*Frm=Cd/Yy2dvMNcN;Kj?Nj ť[,͖ Y!p?gc :.=H׳v˟PC){mNjD}FhR@}V}Z0b:nz96fx\!A"GʆrAk=X`-l PK}lVy={膠"OHTU O[D~C|? nSݸ~ MZٖ17]KVDF6&։QP?CND{[c׭EM8p ?#a.zDܩ1zYj\7<ݬzlj}aS7H|,o}p'dqӱ1ژ+h6zK}[n+حgox IdLc<>>TW])\[49¾'?YQA}H-1EYnGn7ģ԰W \|˂H+yܹYqBz!g5T%[{PwYVHMf.3{/:ۥ>b {\C E+d6|H<=WF#t+|{D;"@ +|Φլ/tВ\gCت]1S¬ju?r,>@\]VN5 n? {mTNrH`Yt^*' RD6+Voh||xnr7zz iY.[h4@T6# Pu 8@0HRXe!w|c)z*>*j+#r-uiD=`H:3Jﶪ Df;Oofqh.n7/|[̋{;,R7GpYq}RUdlrtc\iXb;tK$a?FG3;\$=R-T`2[I`߇__c=xck yB^2Z[pz/'˜o@y% A As~UcbsW53t5P?,?')xj]v8gYt Eְ+ ECi?G<5gNÉ [ XzY *-> IDATJ8[fhIDˏCԴA6CoQ*J֮+ف$ fS'!?"SUV*!"sT[R }rqcI=F Şv;ˆzKEFO\퓦XĒGXh\˻M  N߲F>Կgf ҩGǵ\e+/, U*p;4몚MT*AoskbHZX߹d)Y5iԎL>VR齐ho-Oj&Q"ՌGSѺˉ 䭝4 IFMO ƊfS4Jp8VHRbLDjZEz" /uDe.;'Ɋk|W5יICL1"=Չ,N "g2vDP#?R o []91Oy_)>Y-o$?~orYT=ˊ:D ˄\"o#1kQ%Wds^GH"i>Sh)lPevyu% -kwP)%vk> ц)Ɇ=A1϶崟mBou?%0=b;g%-i@~_D YSku"&(=亶!_{Ea:O'E9Iҟ)[<2eg]uF 4Obl,&}꽡ǯi~Q$_tG?S QoSP*R*&;R)7wkLjܻŮ_1cz ]I8d:o:´T#!$ %8F-eH$q ~& ;nyl8GQ/'6dx@}a7 =E$iQ,GNUL1OR7y-Dr>CmAZLkɮԩ 6(vXi` ,,YZp!p$.BtjQbpmJaRK]urUʉ? 9k 8nLkC,UB63hѶ  1c5w"ER? / V I%y,,Ěùr}CQ-ZXz^R5k(k9&.E{{O34F#YwiKDs8Kl[WhDC× K^] r! cAȠ{ݼ4` yuEŇ):- a/&+SV(X?h5 kPڜV liw%(Xo=I/6 ǎ=mU'T2!|6\G&P(r%,XwTN{ 6>9PlZ%}rŌ5) CQh1YvnI-xU:wh<0$׏mlt_#zyops җ3׳w@EF7zEzuAVbNB5Kb(wHMЧ3o:g|`G %=٥DVdϓ NyrxT&]n3s|5NC4}u7<x ix/x zG8ts\fw8GOa yv73Oy |FM€&};ݽJ[9أ('5*k/=X-1 w wWWP.m@ux$d'ꄁ{ApD @ߗ7rrirAT#1  0'p5(LM 'BnagHL`BGS cӒ>{91DA./+76YhcR  ʰ+9 #*udC jzckkt,gJ AaI4{@}w-r2#03*/J[GJ )Ht\5#.3}v}޻Ps?ARinyxܺVhs )Aq̫,jhM9(4("J9w;_p_;?H߁pb} prB y0-N 5~^FQ2RA : ˹d0$ʲ3)^eZ%[ 4[۫gVҩt }sgbI?Lˮkd?@=M0)JWn01Jk$;ν ztrQӻ4?޷ksiKw+:}]liksMRdrYM4k6G(qXWص. =CHX ⮋!@&tz(@1ڙ'؅rlۃAߟv pkI}Dǣx<}Q(r7lM0bv"T#Z0ѣP#ۜ^?tROqegCNI@s#vl{7[#a屮s[05hټ79΋0,4Khrt~ "0fvʢ7{wT8V@K^ 'Kpt![I;e Cw5swRMjػ)"?dhpROӷ#.Fk<$6=neSi=߻KD%<3'.`IBד!쌀,I#.k(}ZoA(*=̃ KJ׈ROI$uzu2ijnbZJ3C42 ۶x<ž~VTf5Kb@!6m"d0 Xz(a%h>Q*n`f <.CCZpFf+$4/]`n6G# ~ p1%+(OxMcd` MF _I?CayLc`܄WZ ]75~AdYO!=GƓ@ {6gC6lD"^s\ϝKhln::M+5Vr"t_bY¦4Vn^ձR &S]"%r?\ʥTTޤ:?@dP" yfO yI5gmhk e]d]O&1|Ι-Q mRfFѳO8t]xAM0s,9blIc+pZb).y:)dGܾZdWpiW;^!uȸ`dJ&BF#pRΞ>$F>g)'%ƾ/}t)KC[Q{e}ϗ"!R fĝf$.p|06Y\㟚[wY L wNbXs1֥:?45 _|KGkVX%DS%@6"ղY 封zn:J;Kip휉4W櫮k[9~n)(7xEGX|;uȊxв95RN8]}&i8j]-(4fatif׵Vx=;p5vtz@^aI *"~XhDM{>Ma6$_=@4϶Bx'ՇO;x S1s@ל9pLJ ^V]/@] H`dlpS7֥ >'pCTk0Y+t*T ;iA /\+Yۆ3> ]ŖgL)sфaĒY!/U-i-@ x=+Aۓ̠ZK (#Q΍'ft8O{즡7oq>EMR"x}b΍Ę"%RBZ䖌 /\N >ͽWs,C.2ڿCF':Ϟfsi%3Ud.]nE&V=H %|'wۜDM#L6[U-[jC=Ÿ`hׄ` 6 :R$5JWN!ؘhZeP5# __e Ƶ,hXEZb"sݕmQ') ])% {;L8/ &vs;H;b%9E AP}j.?T\nmWُXTY$a 2_BFzռdg\_{}m ͹q&85V-dYY|]kهSPsVhӄ:<"z5\XJlO흇mj<\z8``P {4Dfl$TydhSdCSy)-K⍅'kFyۈLsVwA9s$5hU ܅7jRyi^k\L&./` ; / Q``NI4UosyuɟX|*AD~(#^.31[Wcb RĄإ E#:C*xˢ _4 J] D%`O&L`oiB}aD<{;+Q'v)#z!%–a/Bx jʬi͟ӜG*CBanT: ""Lwq}\9XJ4tO)kڰ4Jo3)%\H/փ  ;adϡ8RIύ2'f\4;LIȋ% {7e ((Mk4T!h,Ҏum{N#>38!G^aF1aۛQfR gL1EɎֶDQ\bCw$6Owq! U~G$l[-!:bҏ->k-CI*":QP8t$FY _O 1I`=YxRxm?q+UeZu co$M(bSbYt#;0ezAF;Cb(w_:QCQ ~!!nٍZ 8:nE{ OY;@eS4]!cd6mӦbZ8ljqFt﷒,TJ5YI(W15XJŌ&m˝ BADkS rܳJ̀K8W,":JNE?%RSX* .CWtث#B9?!s+ aHR$4[64/3WbE O=l.B&)#>Ʊ\*)(}'3ʨ\%T2ݛ1c@zge*+/>X b<1uyv  /Nf~Hl<qo3=|rgCIj`6 5W \^'QgC5~vB8.*zHM=]r6k-7oQ0e:[;(9{?ny"Zbr'?jir-ƟO+6f/0MNv͇>URmy0OxPM+n k~ZMzD+PBKFKuÏ'=di>ɥdRQU gGɍE7EZ(7Q{zThk1ZjnD !2ohQ#p(UwoI*5[PS˪ Ƃ%K}ݣ,EzȉA$ooCzڷ=Z:1%&m^D \giz;Mn^VM*b;t؄ /n6;<|azjʍM'G?[:QO7s׵5gmHsuR+dGA.!mWWLwWN!'x7%XZ,kL`tXW=ofs-xr@󔦛~I[l:C] IDATŠ BUR*ˋ-C" ,V`@~ts.GহG. q+4?@6q2 I:vmՠg=Y/ۧpvLyᎨwJf).f{.坠iQ x@+DEćؼ$X`]d9X6oh\AF w0S{Z4`TW`r-d)jMÕ~^dgu6 ݈k 퐮A x9=,# S}a/8f1.RAk|E;lJTZ*$& 6uofֺ0Yq:\d@̋XPaVDjU)][T,T?[*7zfL~I`Dzs6*qWJ< eߚe34tJG"DgX^wwyڒaϼ&=?𙒽G(+) 7l4aR6&$PQ!F[?z4W] @]b#$uhcӸPiH>l.p{akl'd4x~_4K[?9Jm.hҝs*V)|ȐMe/DLEcEz@I>2L:5.Kc'cn`JժPANM?8|ݸ Θp`-\JMI4 ԍIRrI >=w߮\4  V~(uy7Ե]>\MEN\`فmӖe3B\ʽjK}OƔ ]T421DzC/e]rsF3̾(ɋ,[j|Pӊ>xb{jxq -cbhg̥Z~b^IlN_\;MEl"UKM*t4:YL-oF6 88yx2s>kk7(Ɛ-D1]뜀d>CG>4_\] 9:V)nY>v@ %ApfS!u48wP6Bt `"EspWP#DavCyO`b#%~kZNbCXCFek%Arm(**!~,AH:qnc%T&2V4,GWu{4PS䍗٘5 1;KHBp6.l'Q$˟ǣ9[yH篼Eğ#>ilnj˼qr>-𸞢G6ai'^Cf B_,O,}; ӊڃZS+5dL~U~ơO؅d"] '?u[6%(H֢X\4y;epU͏_8$4 _]ln:$Ĩc"l v̒B!`҆ȫnTOUrRW|-Ya]3{sٜx LBEQϙ@dFK90HJcRVqlH br#ĵ2"k&55!0?SfyN*'!! Gu+xxy*}Eɡ1dz݅goEüxDl),)WZ4ߍ^!]5-(+}Gi,)|3Ltd%*̃7;b9A)kq[ډt2́/zr\" 6m{y{.vΒtt$~oAp!(wK;OH繐QLQƗK(na.2 ' ?8EaqُCi};~?^zIBWx&\_d!ͺٻpOWLp5XFXLlҨW |m'36}n4|+0,o}\MmFrB3z!qh98g} ޢ^% ܝCFC/T4PRtYQ^ꥩpC፠AuWpx=$B) O&|(p$?8H3 {nP\rgR0/,Nw@8>Vpp W>@a>,alH+ V<7CK.|wwx6uAQ q;GA5^St5Igϒ sQTQd6q.}'dKV'u[.ڨ{FOQ(<7o~VgYQ k3LRF$[``_'nRY777tAYF+̸es gCeϥXen}}W<^8luv/Y+Zhd> 'nj(`ĔcVqlhy_.vo~RqBj֛u>Pc N`OfӼ|N U.'c@' $8^}S#oX^X`F:z }SO7l=V:O+C %`+vn[A" 6Q4Airxxz\E?WDͥ}Uܱ+yfvY6P0nxl}. :P^y#MaAz0NҜ=I/Y {=MȆ'y)!ϓBxf 2k{ši=4Ν;#\x]<?ofAɟ@6!(jgb#DҠJfȎ24@wJ*3`l&Ί8~?gSO| L ̚ڧ>[S a(@hSrzTgLG=@%7`z9V˭ڼHj?]wh`l.tov޷FJ= c^|p$J ;솽.t ߌ,ޠy*agd@gl+FAlF㿯oU veaY]߇n֥Vs|y}@[ms/[Ws/@9LVYrڗrZ2[yሂx*Sq;L&4KYҭ?_. ?(KV DVl0Ò,:5QME:"vLp8Cf;TxCKƻcy' gw,t 0WP$1V9ͶCzVM0Wtg5D~jV!<@E (Iun#,7;O ( AITNk)q*njd᛬{E"hWDՠ/r. +$P!_#:4 :L#wK$o!_U4ǎ1 \eSߓv^lroz~>,ZwJvaڻ0h"qbnUMFK7ⶢp0׬!(Y2rT ̇nÅxc2_S֩ݲߒh7Jp.$`ش"!Dy>^Jڔ2 G³My gǯȗG :ZzGGIbIýPh6$//8"a9JCT~N?*\Ob=Ϫ &w)2PDC(cP9?楝Uv#%k^)[ķ_/-bl5pP%&˺=qHRaTXIY0{7YtJt6%C\ r3zt:-p+M+|Z#;UlDm~/cz:^4SW˃c sDגKo̠۟EBE:^C/&eV4̶7S`\ i 6t%VТ܈8b81 Fv42A^W@~``0AOEΆea'J\wTn'yޖXX$ڳZS^^AHiXq|N(ptbrSy7uaщ9wfV=|Z܊)/^b*w:%?=2DtA$g8e&Ի e>ϕA70;=K5SbzLϥ~,x?tnU !R?5ptk)x1j R?wydu|LOlw:?5dSN{&$DaJaF0s,^4'Z7, s14h^٢eF/YmݓDJ?_ջZ عFqE_PY̛[^Q4Z=r2p 4y(tdoBwe;5!scᱴx]tTkOMX m{ Ա^o>Fc 3ACpU`%P; YÇR0f׽TOS"o;2G?:"fkGD-ԁ|fҳ-l@JceXiko.-x^smOP>5cHt(upSyz1fܹK<^Ma>xEwL!#KIKqL&0BtBdZ=W:P._[DUbhǪ.13&A?d=vo9QPg؏_NTKHlֽlWRI܌ҢIE%:~YIb*m:t:-^PṾPk{}sDNMCKTzhACqỜb!Z+Ux)Hr`UFZHR.SNAԽ@I f5p\Rb9nͭ< ^G'?Eφ1hwc];zq9Cd=,TXdD&|UݮSQM ^;{Q&s?n8Q(hȋ9"ɺq]$$Gx_Z <woI 'ߥʋH'E%?. @ z ~qlTa0%AGG m@fi*C_L٣icM7f'Q$Of{SzNm5 IU]XBG.4m+ 2')viҕ=i% >*}R W-7ma(t8 2ȆDpdAiݲ ㍘(:v$*x?`I!x2és~|>v)Nۑr쭰j`CD 89ФDn(pb5Sʯunk{EZFdcz]y[QCHr4$Ho[_#rCxZfqoP]z2l;bϽ2{vw@dӢlU3{|M/}6X|ҤdcCy%q:ivSuiN9)K/W=cOpsl=q&UtV?dr&]ƈAB7/{y7͒  e&COd#3OQۑЯ5"J2_~[9 UCtܠ|4Ww+Wf ;G&ȗ{i3S9g6IkV럴[AxZ`.)sՒ$6'`+{JL nvh$Jl۪Zc4D!3&[+3ɈaUQ*TkOc ݻ\TE̡6_Hiw߻ohk{duLm4shYڛX8{ǥB();34kqD" }ytA3Ѯ@nm@ pTb]k~A}j:$q>K6oAUaoǭ՘=5a )&`ӳ;y(N˺Kq%) 8ny\/=a@fMrDvN#L'Y1V333xc +Ƴ\9_e;yFR6x7xx3i]=:A3z\k~ |Lu.>EQU3nJeJ=y/(gv[DqtODk[75y Ԭ eU@Ť;8ADPtT>sgNQw}q+_icOwSͩ`ɭV=@Vdc:Ҽ^?~S{Fp"z˄=y}*rS{,c뇩$;,nˁb%>oœ!`CA{J.KSHr`_Fs/訝N5&>< W u1TO3w-@G?=k>isNг Iˆ1RAUn(d8t(Lw9sa"}1X­̟aH:{2Fu=VSCwroB/88-v~F[g S"bILlv4F/Lݴ´z6(N))%gL|)D>x >>>΍kx ZOh=>+n6_>~·ط}۷yXžü{ì}4۾ۇ}|؇}oj}09g_ޟn㕾ua1,og۾\C`1aǾ?f92}ǭ*P͋Z>^ N8U2S]  {%9Y%i0.e D`xE Zsk>xo=T03wRh]lt\NDO8/dHKKl S9uU ,s/7@t*c:y֯q4NTg>ͳ+<8㾛BE!d 5+  v*^/f _ۦsAb Ǟw3: Q;E9|ʱX4G܁A&T]vvYF4R)<5! "גDN@\Tf`culI^[k#?@ n` kǀ[،p\pTֿ)$[ٱG9Ni)e 77~d2ֈ\(͏(p8~WB25y ^ @ٹrnIÙݦ_N9,ѣTXcwȘZ 8x~Zs9C!C8 ptRI} wׄ$J {|_H}6^ͣ2(57d! !&Iddlt?߿9Q֎3t3.h`G%\1u@E+EnT(!g]RT]<A .0iD$Ey С!^v2U5;fᝃEP@pֳ4Sݽ^ʊ4?O!Μh{@Z#=_E ?VhO(6[ gחr՚XNs9bHW-)l{?FYG6 <"f@,]W bٻ2vc rBp}B츥o2%XU6z9N)y#POO.al[eh;>[#AH Ќ6E"y[BCdHs0P(ƪCdDTKCױhb$u )s>&%qgju 54$:Kw,p,'"c#u/He'ˡu]j9 TQrk=KIPDʪN 4Etƿ)Q(cʹVwB99˙L^<ܫtxul])rөN*F%GdˢY7ȫV$|1uWJ f/&zAR&/{j) jiy\ Xshc;]VLXʐ RM@@yaK&'2*e/!3{$b!vl( !Sf\9N2_ܲ1uq$(~ mg8Y&ں *b-Ҍ OF Pʰ%Z͘$K8>ECLK| 2R`e~cG-\@;#AP`P&~DzwxRk^v&d>0/^j!oE},[GRvycSXNaWU3*u" #*su䅊 Հ"7|61RDzEhFXvgi=Eθirr+][1-Fm{.; 5ʚ` z+ͭHvX e?5y+O0/ _"CiZGg @AVB5S>|r^~]4꾇S:F * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __HISTORYLIST_H__ #define __HISTORYLIST_H__ #include /** @ingroup Core The HistoryList class provides a list of @p N recent string items that can be stored/restored. */ class HistoryList { private: QStringList m_data; int m_size; bool m_unique; public: HistoryList(int historySize = 10); ~HistoryList(); /** Restore the list from application settings. */ void restore(); /** Save the list with application settings. */ void save() const; /** @return current number of items. */ int count() const; /** @return current size. */ int size() const; /** Sets maximum size. */ void setSize(int newSize); /** Adds new item. If there are too many items, last ones will be dropped. */ void append(const QString& item); /** Removes the first occurence of given item. */ void remove(const QString& item); /** Removes all the first entries that are not existing files */ void removeMissingFiles(); /** Removes all items. */ void clear(); /** @return item at @p index - 0 is the newest one. */ QString item(int index) const; /** @return item at @p index */ QString operator[](int index) const; /** @return @p true if history contains given item. */ bool contains(const QString& s) const; /** @return all items. */ QStringList items() const; /** Sets all items. */ void setItems(const QStringList& list); /** @return if older repeated value is automatically removed */ bool isUnique() const; /** Sets whether older repeated value is automatically removed. Does not affect current list content. */ void setUnique(bool value); private: }; #endif chessx-1.0.0/src/database/spellchecker.h000644 001750 001750 00000010744 12223260306 020763 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 William Hoggarth * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include #include #include #include /** @ingroup Feature The Spellchecker class provides spellchecker functionality. The Spellchecker can import spellings from specially formatted text files, or load them from a native binary format. The class caters for a number of spelling types and rules for correcting spelling. */ class Spellchecker { public: /** The rule type indicates what kind of substitution a spelling rule performs Spellings are corrected with a number of different substitution rules. Each rule type indicates where in the string it will look for a substring. When a match is found, it is replaced with the corrected substring. The literal rule is preferred as it is often the most suitable and is the most efficient. It works as a straight match and replace on the whole string. If many similar spelling mistakes are made at the beginning or end of a string, the prefix and suffix rules may be more appropriate. This results in more corrections with less rules. Finally, if a common spelling error maybe found in any part of the string, the infix rule should be used. During correction relevant rules will be applied the following order: prefix, infix, suffix, then literal. You will need to be aware of this when more than one rule may be relevant to a particular spelling. */ enum RuleType { Literal, /**< Matches the whole string */ Prefix, /**< Matches at the beginning of the string */ Infix, /**< Matches anywhere in the string */ Suffix, /**< Matches at the end of the string */ RuleTypeCount }; /** The spelling type indicates what kind of spelling is to be corrected */ enum SpellingType { Player, /**< Player name */ Site, /**< Site name */ Event, /**< Event name */ Round, /**< Round */ SpellingTypeCount }; /** Default constructor, creates a Spellchecker with no spellings */ Spellchecker(); /** Loads spellings from a native format */ bool load(const QString& filename); /** Saves spellings to a native format */ bool save(const QString& filename); /** Imports spellings from a specically formatted text file */ bool import(const QString& filename); /** Corrects a spelling The string parameter has the various spelling rules applied to it, and the resultant corrected spelling is returned. */ QString correct(const QString& string, SpellingType spellingType) const; /** Finds the incorrect spellings associated with a given correct spelling */ QStringList findSpellings(const QString& correct, RuleType ruleType, SpellingType spellingType) const; /** Adds a spelling rule to the Spellchecker */ void addRule(const QString incorrect, const QString& correct, RuleType ruleType, SpellingType spellingType); /** Removes a spelling rule */ bool removeRule(const QString& incorrect, RuleType ruleType, SpellingType spellingType); /** Returns the number of spelling rules, of all types, in the Spellchecker */ int count() const; /** Removes all spelling rules from the Spellchecker */ void clear(); private: /** Imports a section from a specially formatted text file */ bool importSection(QTextStream& stream, const QString& section, SpellingType spellingType); /** Standardises the format of a string for matching purposes */ QString standardise(const QString& string, SpellingType spellingType) const; QMap m_maps[RuleTypeCount][SpellingTypeCount]; }; chessx-1.0.0/data/templates/html-default.template000644 001750 001750 00000005606 12204210231 022635 0ustar00niklasniklas000000 000000 [OPTIONSDEFINITIONS] #Name - Name of the option. Use @Name@ in header, footer and markup # tags to substitute the value. #Type - Can be one of String, Boolean, Integer, Color #Allow Values - The values that are allowed for this option. Ignored # for type Boolean(1|0|true|false) and Color. Values are # are a | seperated list of values. For Integer types a # range is allowed, specified as in 1:200 #Default - The default to be used. Must be in allowed values (duh) #Description - Short description, will be used in the GUI to change the # option. #Name , Type , Allow Values , Default , Description MainLineFontWeight,String,Bold|Normal,Bold,The weight of the font [OPTIONS] ColumnStyle=false SymbolicNag=true MainLineMoveColor=#000000 VariationColor=#00008b VariationIndentLevel=1 CommentColor=#006400 NagColor=#8b0000 HeaderColor=#00008b ShowDiagrams=true DiagramSize=200 [OUTPUTHEADER] ChessX HTML Output\n \n \n [OUTPUTFOOTER] \n [MARKUPTAGS] MarkupHeaderBlock=,
\n MarkupNotationBlock=, MarkupResult=,

\n MarkupDiagram=
,
MarkupMainLineMove=, MarkupVariationMove=, MarkupMainLine=
,
\n MarkupVariationInline=(,)\n MarkupVariationIndent=
(,)
\n MarkupNag=,\n MarkupColumnStyleMove=, MarkupColumnStyleRow=, MarkupColumnStyleMainline=,
MarkupAnnotationInline=,\n MarkupAnnotationIndent=
,
\n MarkupPreAnnotationInline=,\n MarkupPreAnnotationIndent=
,
\n MarkupHeaderLine=,
\n MarkupHeaderTagName=, MarkupHeaderTagValue="," chessx-1.0.0/src/gui/boardsetup.ui000644 001750 001750 00000041700 12171025447 017700 0ustar00niklasniklas000000 000000 BoardSetupDialog 0 0 638 507 0 0 0 0 Setup position 0 0 0 0 0 Board true 0 0 0 0 true QLayout::SetDefaultConstraint Tools QLayout::SetDefaultConstraint Side to move: Move: 1 999 1 Qt::Horizontal QSizePolicy::Expanding 61 27 Flip board ... :/images/new_board.png:/images/new_board.png Mirror left and right ... :/images/flip-horizontal.png:/images/flip-horizontal.png Mirror top and bottom ... :/images/flip-vertical.png:/images/flip-vertical.png Change colors for all pieces ... :/images/swap-color.png:/images/swap-color.png Qt::Horizontal 40 20 Clear &Reset 0 0 &Advanced Castling rights Black O-O White O-O-O White O-O Black O-O-O Qt::Vertical 20 40 En passant file: Qt::Horizontal 40 20 0 - a b c d e f g h Qt::Horizontal 40 20 Halfmove clock: Qt::Horizontal 40 20 0 0 0 99 0 Qt::Horizontal 40 20 FEN 400 0 QFrame::Panel QFrame::Sunken 0 0 400 60 QFrame::Panel QFrame::Sunken true Paste FEN Copy FEN Copy Text Qt::Horizontal QSizePolicy::Expanding 40 20 &Ok &Cancel BoardView QWidget
boardview.h
wkCastleCheck bkCastleCheck wqCastleCheck bqCastleCheck moveSpin okButton cancelButton
chessx-1.0.0/unix/chessx-x-chess-pgn.xml000644 001750 001750 00000000346 12117557125 020756 0ustar00niklasniklas000000 000000 PGN Database chessx-1.0.0/src/database/pdbtest.h000644 001750 001750 00000000137 12211425766 017771 0ustar00niklasniklas000000 000000 #ifndef PDBTEST_H #define PDBTEST_H void testPlayerDatabaseConversion(); #endif // PDBTEST_H chessx-1.0.0/data/images/bug_add.png000644 001750 001750 00000004412 12142367140 020063 0ustar00niklasniklas000000 000000 PNG  IHDR szztEXtSoftwareAdobe ImageReadyqe<IDATxڬWklfv/0`ZHдI( `7&6(iUb"(P- ?? `h 1 76kgޙchcy3|=sV]³ j- UXU g2H&⭲7uu]D~3~/kVASĢD11 G*.v]||dPƽ$E@TU:Ё}z׶o=U6A7O9^INğ,{XDϰ&U,]ߊ1@[  d__s^Wɾ%3L,k';T>^w4egM2{۷sjXl~~!^z[.xztݠ>R|UOBk%o[-k[`k,ֽ7wF%dD0U'` qu? Qo1Dw6aASJ,%:2{}oJOGq :#oV=|ߘdT6^!3ԋ)H½y˗/!kXM^_DG=1 R^ LhΤSiP JEjViZY,MfәXR"%YUH4QDJ ߍ3Dq(,缌cG`&R| ]e Ql#0uzzFMI-t߸3)B>ȟjpPUl? z9+ ]N4&S֤4-tf"Hz:0zR,.YH,D Y%cg$8=A8 $EMIT 8Dʓߙ\/l|x=ޥ=ʼn7jLux$RɋW܋q6p{ tuU2lo ")3[Y$8U.Qg&?h,Yb,/7pp:ɲ, `mgfѽ`fxZEI~}n}vIJ*U[53UώPm`e =XƩ(j9.FZkFF$ks5@'0I&;a16".b_Y g7lj2.8pã53ﵬƊ\YKȱ& xeuΔp4 ҽ́bamGWp*ל baMxy ae r֠,5V̢PN5Al[ ^ë5kvm#:z,n#tZo@S(X sHU5;x Ozo"NAТĐZ6n:߁L/O5ܙ{bED - ZN,%: #iCt&U0NKJ'/y*9^u@ AgϏaՂ:YVn~UhoKeVSt?QT,{!úaXfN5|CYs;kvǼOdd?ϛo9S$hIt7w՟;i!OQW$#K8xݔ2"Y#uu؜|^{>I'Na ΏͶWbŴb,cB:7b}Q(y0Rjۅ[ ޫs ڇ=hG6ޡ?2,ߡWη9a= l?a"۩YJeK)@/=d{ڵ;ϲ)Ƽcgfݵt|r"nwe󃄱5x[0尛;eXuRS +IENDB`chessx-1.0.0/src/database/nag.h000644 001750 001750 00000016765 12223260306 017075 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2006 William Hoggarth * * (C) 2006-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __NAG_H__ #define __NAG_H__ #include /* Don't forget to add string for each 'nag' in source file. */ typedef enum { NullNag, GoodMove, MoveNagStart = GoodMove, PoorMove, VeryGoodMove, VeryPoorMove, SpeculativeMove, QuestionableMove, ForcedMove, SingularMove, WorstMove, MoveNagEnd = WorstMove, DrawishPosition, EvaluationNagStart = DrawishPosition, EqualChancesQuietPosition, EqualChancesActivePosition, UnclearPosition, WhiteHasASlightAdvantage, BlackHasASlightAdvantage, WhiteHasAModerateAdvantage, BlackHasAModerateAdvantage, WhiteHasADecisiveAdvantage, BlackHasADecisiveAdvantage, WhiteHasACrushingAdvantage, BlackHasACrushingAdvantage, WhiteIsInZugzwang, BlackIsInZugzwang, WhiteHasASlightSpaceAdvantage, BlackHasASlightSpaceAdvantage, WhiteHasAModerateSpaceAdvantage, BlackHasAModerateSpaceAdvantage, WhiteHasADecisiveSpaceAdvantage, BlackHasADecisiveSpaceAdvantage, WhiteHasASlightTimeAdvantage, BlackHasASlightTimeAdvantage, WhiteHasAModerateTimeAdvantage, BlackHasAModerateTimeAdvantage, WhiteHasADecisiveTimeAdvantage, BlackHasADecisiveTimeAdvantage, WhiteHasTheInitiative, BlackHasTheInitiative, WhiteHasALastingInitiative, BlackHasALastingInitiative, WhiteHasTheAttack, BlackHasTheAttack, WhiteHasInsufficientCompensationForMaterialDeficit, BlackHasInsufficientCompensationForMaterialDeficit, WhiteHasSufficientCompensationForMaterialDeficit, BlackHasSufficientCompensationForMaterialDeficit, WhiteHasMoreThanAdequateCompensationForMaterialDeficit, BlackHasMoreThanAdequateCompensationForMaterialDeficit, WhiteHasASlightCenterControlAdvantage, BlackHasASlightCenterControlAdvantage, WhiteHasAModerateCenterControlAdvantage, BlackHasAModerateCenterControlAdvantage, WhiteHasADecisiveCenterControlAdvantage, BlackHasADecisiveCenterControlAdvantage, WhiteHasASlightKingsideControlAdvantage, BlackHasASlightKingsideControlAdvantage, WhiteHasAModerateKingsideControlAdvantage, BlackHasAModerateKingsideControlAdvantage, WhiteHasADecisiveKingsideControlAdvantage, BlackHasADecisiveKingsideControlAdvantage, WhiteHasASlightQueensideControlAdvantage, BlackHasASlightQueensideControlAdvantage, WhiteHasAModerateQueensideControlAdvantage, BlackHasAModerateQueensideControlAdvantage, WhiteHasADecisiveQueensideControlAdvantage, BlackHasADecisiveQueensideControlAdvantage, WhiteHasAVulnerableFirstRank, BlackHasAVulnerableFirstRank, WhiteHasAWellProtectedFirstRank, BlackHasAWellProtectedFirstRank, WhiteHasAPoorlyProtectedKing, BlackHasAPoorlyProtectedKing, WhiteHasAWellProtectedKing, BlackHasAWellProtectedKing, WhiteHasAPoorlyPlacedKing, BlackHasAPoorlyPlacedKing, WhiteHasAWellPlacedKing, BlackHasAWellPlacedKing, WhiteHasAVeryWeakPawnStructure, BlackHasAVeryWeakPawnStructure, WhiteHasAModeratelyWeakPawnStructure, BlackHasAModeratelyWeakPawnStructure, WhiteHasAModeratelyStrongPawnStructure, BlackHasAModeratelyStrongPawnStructure, WhiteHasAVeryStrongPawnStructure, BlackHasAVeryStrongPawnStructure, WhiteHasPoorKnightPlacement, BlackHasPoorKnightPlacement, WhiteHasGoodKnightPlacement, BlackHasGoodKnightPlacement, WhiteHasPoorBishopPlacement, BlackHasPoorBishopPlacement, WhiteHasGoodBishopPlacement, BlackHasGoodBishopPlacement, WhiteHasPoorRookPlacement, BlackHasPoorRookPlacement, WhiteHasGoodRookPlacement, BlackHasGoodRookPlacement, WhiteHasPoorQueenPlacement, BlackHasPoorQueenPlacement, WhiteHasGoodQueenPlacement, BlackHasGoodQueenPlacement, WhiteHasPoorPieceCoordination, BlackHasPoorPieceCoordination, WhiteHasGoodPieceCoordination, BlackHasGoodPieceCoordination, EvaluationNagEnd = BlackHasGoodPieceCoordination, WhiteHasPlayedTheOpeningVeryPoorly, OpeningNagStart = WhiteHasPlayedTheOpeningVeryPoorly, BlackHasPlayedTheOpeningVeryPoorly, WhiteHasPlayedTheOpeningPoorly, BlackHasPlayedTheOpeningPoorly, WhiteHasPlayedTheOpeningWell, BlackHasPlayedTheOpeningWell, WhiteHasPlayedTheOpeningVeryWell, BlackHasPlayedTheOpeningVeryWell, OpeningNagEnd = BlackHasPlayedTheOpeningVeryWell, WhiteHasPlayedTheMiddlegameVeryPoorly, MiddleGameNagStart = WhiteHasPlayedTheMiddlegameVeryPoorly, BlackHasPlayedTheMiddlegameVeryPoorly, WhiteHasPlayedTheMiddlegamePoorly, BlackHasPlayedTheMiddlegamePoorly, WhiteHasPlayedTheMiddlegameWell, BlackHasPlayedTheMiddlegameWell, WhiteHasPlayedTheMiddlegameVeryWell, BlackHasPlayedTheMiddlegameVeryWell, MiddleGameNagEnd = BlackHasPlayedTheMiddlegameVeryWell, WhiteHasPlayedTheEndingVeryPoorly, EndingNagStart = WhiteHasPlayedTheEndingVeryPoorly, BlackHasPlayedTheEndingVeryPoorly, WhiteHasPlayedTheEndingPoorly, BlackHasPlayedTheEndingPoorly, WhiteHasPlayedTheEndingWell, BlackHasPlayedTheEndingWell, WhiteHasPlayedTheEndingVeryWell, BlackHasPlayedTheEndingVeryWell, EndingNagEnd = BlackHasPlayedTheEndingVeryWell, WhiteHasSlightCounterplay, BlackHasSlightCounterplay, WhiteHasModerateCounterplay, BlackHasModerateCounterplay, WhiteHasDecisiveCounterplay, BlackHasDecisiveCounterplay, WhiteHasModerateTimeControlPressure, BlackHasModerateTimeControlPressure, WhiteHasSevereTimeControlPressure, BlackHasSevereTimeControlPressure, WithTheIdea, AimedAgainst, BetterMove, WorseMove, EquivalentMove, EditorsRemark, Novelty, WeakPoint, EndGame, Line, Diagonal, WhiteHasAPairOfBishops, BlackHasAPairOfBishops, BishopsOfOppositeColor, BishopNagStart = BishopsOfOppositeColor, BishopsOfSameColor, BishopNagEnd = BishopsOfSameColor, NagDiagram = 201, // SCID compatibility NagCount } Nag; /** @ingroup Database The NagSet class stores set of PGN NAGs. */ class NagSet : public QVector { Q_DECLARE_TR_FUNCTIONS(NagSet) public: enum { Simple, PGN, HTML }; /**< format of a string */ NagSet() {} NagSet(Nag nag) { addNag(nag); } void addNag(Nag nag); void removeNag(Nag nag); QString toString(unsigned format) const; static const QString& nagToString(Nag nag); static const QString& nagToStringHTML(Nag nag); static bool isMoveNag(Nag nag); static bool isEvalNag(Nag nag); static bool isOtherNag(Nag nag); static QString nagToMenuString(Nag nag); static int prefixCount(const QString& nag); static Nag fromString(const QString& nag); private: static void InitNagStringListLong(); static QStringList g_nagStringListLong; bool conditionalRemoveNagRange(Nag nag, Nag start, Nag end); void removeNagRange(Nag from, Nag to); }; #endif // __NAG_H__ chessx-1.0.0/src/gui/messagedialog.h000644 001750 001750 00000003735 12223260306 020145 0ustar00niklasniklas000000 000000 /*************************************************************************** MessageDialog - wrapper for QMessageBox (C) 2007 Michal Rudolf This file is a part of free ChessX (http://chessx.sourceforge.net 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef MESSAGEDIALOG_H #define MESSAGEDIALOG_H /** @ingroup GUI The MessageDialog class is a simple wrapper for QMessageBox, to make it easier to display system messages. */ #include class MessageDialog : public QObject { Q_OBJECT public: enum {Yes, No, Cancel}; /** Standard information dialog. */ static void error(const QString& text, const QString& title = tr("Error")); /** Standard warning dialog. */ static void warning(const QString& text, const QString& title = tr("Warning")); /** Standard information dialog. */ static void information(const QString& text, const QString& title = tr("Information")); /** Standard Yes-No dialog. Escape is disabled, 'No' is default. */ static bool yesNo(const QString& text, const QString& title = tr("Question"), const QString& yes = tr("&Yes"), const QString& no = tr("&No")); /** Standard Ok-Cancel dialog. Escape cancels, 'Ok' is default. */ static bool okCancel(const QString& text, const QString& title = tr("Question"), const QString& ok = tr("&OK"), const QString& cancel = tr("&Cancel")); static int yesNoCancel(const QString& text, const QString& title = tr("Question"), const QString& yes = tr("&Yes"), const QString& no = tr("&No"), const QString& cancel = tr("&Cancel")); }; #endif chessx-1.0.0/data/themes/outline/alpha.png000644 001750 001750 00000175163 10633464147 021306 0ustar00niklasniklas000000 000000 PNG  IHDR4RsBIT|d pHYs66BtEXtSoftwarewww.inkscape.org< IDATx]exW~$;@) PXP(Zx)'@)._q[`yάd >y{sϝ;#n$A 4hРA hРA 4hР!@[`hА4W[ 4hРAWРzXڂhРA 4*<@o4`ʲhp, ( (ܖ}`4hРAMs֠*p sIG @_5,0.KA 40h ,#Y$讎8hl\K$&&"cƌJcJA 4 h ,c5vp/^bTE4E ,rׯ1sL8q.\ݻw9sD2ePbE 0BWAv 48M f[#:P \C RXhf͚/eQK0 vAoy?@7c֬YhѢxZN4hА:VN0ԁh4FQ]x+VĻwgԫWvUSH 6T :`͚5I]vXj!g&jР RKNZZ `7oޠuxN4}t'+tSR$3gL֬YiӦsm/4hx"2dȠHjAK@[`hР)@^p5}]pU 狦0Ο?Cmh6lN:%~aqA 4|4BR,YV2($3fKT4udoVniӦqE|_ƥKqqq0`;jp<40 <RQ"_!5!ѠACCK'MH& ݻL2A/ o@H.̞z͚5h۶⍛6m:w|||xzz"k $ =4s\|>7_@0#q.jtmFCpu?DG+Ϟ=U":9((ժUƍ -[gΜ?]d" .jܼy 0( ӧOM$#Gx0˗,ssQ9hӦ njՍ^^^صkj׮-^`[~{n4n V+W>=/pNri0jl޼!!!vxY&l|@C;!ƊB Π1t,v)hЦFSfar8n8m߾W^b5Iz@4LSH2!!12e MaΜ92~OOOƊ,}\߼ys9J>=^*Vd;OI^|ҥK\;w]@  M6%y,(y\m社[$WI2 4rT ,fΟ?oJ (<<4ڊ,Y 88,OTT)SF njh`:t*Ϟ=]ٳ}EB bNCkӧFs IPkc+0`&NhP8tP<|}EJwlٲs8$@>$FͯJS> nj[3y)< 3fA|I.\(d-042$o޼YLǾ\r:u%ɧ$@BN54F_m!K@4|p̙3GR-[b֬Yȑ#lРAҥy!::?3S2N`?|رcݻ7/_nڵŋ&MP{"S(׮]Tj:Ipp0͋ׯ믅aȑ!\t.) *YQIK.TRFy4؀ܹsSNeϟ?Ƕmڴi# K!e?<6ŋ1zhDDD$ӧOӘ1cƎ;=3ua'dj˵"Eh'VR"EV{5(L üyy\uVCLL̔A@N2{EA2 E#C#ipLըQ#jժIIaw+ C"71$?hP5j(QBZ\+r+)XA7+Ӌ/d?~X|t!Dٳ&GYN0R ӧZׯϗ/_J$=\v#g`wߕիiӚԩSx])[,rmvsHFDGG?4f+z4B*|ҥKM~aر7}YׯbѢE>}:6lY M6K}Qj 22]v:+hР~WqW2' :Bج |^~-+> ,h|օ!zOI۴$ mkn?FuW^eM/:pԩܿ?)S]v,ZFYf[(A]=[aa ~6 Wr+PM%h'IBU;ɓ'/G0eJR\+..CEzCsn:lݺYd?yM4 ɖ8_cq|t1bb/^[nwj}n2d^z߿GcԨQQzudȤzOB=fykGy5^6ݟ?M˗-[ăpe\| j֬ZjaXz5^;w 2DDDI&eCH)pJ&4k߾pH "<,86$w&l#W$ۺ@S3"OOOiӆGIسgOr7oވUͳ\HիWgϞ4iG6mNT ?Uii WHRHZvm1Μ937&K.5yҰaCo.dֳgOb׭[gq`,,0L EغXn쾞={JYRȗQAѣٗlٲ41X3g?hذ!_x!5dV'C#?/_|9ۛ'O6vcΜ9L&iӦEoYF$QNI^x*E%Zf8V$?\tuqҥ6'5tS8bŊ&7C*[,lق0 wQ '|-[XbyW*ޤV@)@DXz5ʔ)c>}vh߾,{tt4wݻwcѢE9\s[GK, 6 $$qqqVW0vXmV8 ;uB^_}1n8oƦMPpaDs7,R0+iueEpp0֯_ҥK~h^^^\N\DC8yd> [ [ɚɓ'$~pM]\qL(`xc`Oy R4{) [lM-TB"#BrESaؿMw}gҁ/w<|:Kj#7D%.DMOOO)U6mdcSL[y$bŊmӦ yzz2::Zp"H8mcIfJ$Ο?πݝnnna@@?~,m*26YBX@!M{j ^0^^^| `pOOO\@/63;LlԩŁH N:8#v:Qw۶m&]D UvVZqԨQ1k/L]mƐ엄jPLi8^v[lIإK~>|8͛-[J)^QtKitT~G-UNɻЋ,'oRVcԫWnιESD |viB ytHQPi@cO?)2vsA4iLV?b 6СCزeiO|(QڶmhweTP6l@ڵ`#,uЙ?~M4fA#sضm>S ѱcG/^7FDDAٽ{PjUl߾*UOP`2n{bӦMغu+>}joooTR @ӦM c8gvO;!s=pQm^| 4@ `ɓ,f'/<@mB||<6n܈ٳgĉV/FѢE ԨQzh\Q,V H.>c\z?qX΀W3IòZڵKuP,q]OX@G[la.ۉlѢYƚ4U*_<>}j~{ٳ 4&M:tHz$?Ls%۷3mڴ-X _nXي[nhѢ2M۷o?&Y4HB;t I/_&_%E2c2Ȩ;w˗/$O.+С`mЫ3ɃY!""zb@@@, (YfIMQI{ R9Ic8q3fLr9s?#mOi. Ƥ`:?3gΜsL8|pc$rv% 3p@'MDGaԩ+ǫ 3Ν)\rITrr9x ]aq2U"yYT@dd,Ic4i/ E1k#s֬Yd\tibt8p>>>&e ӧtc⊔BKed"}Ɋ_TDFFZjxzzj>$YD5TZI#zhBV^V-xNJT"kGVhQdNJL9nܸd/,)]t1bi A!*2ɒ!((H[N}%}GXKlTD[e? wWODkN?#7bZj%e1^rfc3I2<<\B %i@R#*3(-d?5kVʼnۛA%M6qY,;aƍffΜY:NJ>ل LyRY!&&FѱX &HQ9W[)ƐBl in:uJq<$),'Uݽ|hܔ̖- 64իʖ.]:N8ݳ߄۷={d۸qci8TR8-K($L"-V(%|$l1%>}$)njwاO><==l}* 9L>=.]jV_9{lΜ9ӧOԩS9i$N0ǏO?Fȑ#9|p>8q}Kl'=d}?njQ $ݻ+Gei&nݺIYSpxU[߶PzI{I2$m+kݺLsΥW.5Nܫk֬ի+0w\Dduf[V blZ 6xJ;v,߾}nl޼96K,pIeG_@pj(l`w;upcƌ!I:t&`Ϟ=mAm > UԞCԠrP(m0[/b39/EeȐAa/QÞq(QBQ2d~IxXL~l]9ׯhԴiS>x ZwM,Yl=<<~1P ϼ˗/Wԕq&Ÿih<;Ԃ^/_ ئM,Xsf9fҾ&2yIoyը-=vޭH|n:!///^jT-͛7%9'H+:z(G?9sdBI&G;zC]2ڵZ۷>GlƟi7fΜX#GU#ҨO>ol۶Mݝ3f0u](<<\1H~A=ASI4xr-=ae|]@/63 5YC$___Κ5+)c"1k,E(T"eOQ-zGl vLzdաdn!qTEQML:1pvObO*׻Ԛ x7lͧmO%ɧO2LB {K)Kg+,2+UPd111#5Ly?o߲wf___Θ1Cj“@_I3]!8~8ϓ'u@C+ȍJWgS8(P@Μ9CLޤsnE {̚5tM 3!sb),5DwCرǏ3$$]PP7lؐ,4,ZȬN|}}y-Wg;%M=75j԰[L|&YS4M4$DI!b>K$AKd=̎Cbbb$={JZi_0ѭ[7Y=%K萬9I!E…<m۶m/;$۷#GŶ5kfERq)fA?6ѺcoGIjݺٜHŋwoDD˗/(Gɒ%]@+h*IFEE)&94 ,(ș34|GHF?"~ԩcƁ=vupf':uO0W)J$$RzjYQ۷o/CgMHH:cGS'OVI8cA/^`"Eۑ8dW?H{T|>g}+ 6LߤD3*%ԴiSYbn@k֬#Ϛi,)@*Yb쾦MJY%Aś ~W k׮oSy n:u[?0w܊ȑCI3'OL(_"##Հa"H :Ԟ_I%IƑB$K% 2Īf!C(mZ,Rᴔ$ILLĉPE*Sdj˗/L2&ʼn'?PБH2.%Y=z]xBw jJ)3 )Iè8;ҐOW\Qt )T2qwwf~NםVeҥS<ܾ}lȹ:)6z8Pr%4RhXؿyɊ8{lٲIY&AabƛZٳgWJ~z p /} .… W*T:cbLPJ0Y/TF|zi*L+vܔ_dVl:e{-[jXQ.dINB۶mq E4iҠI&pwww#11۷oǻw ,kע|I": !^Xr% /^K.:u*ҧO]:tիMw/?~ 3R;bժUؾ};4h`Fo߾|)]zEk{Cope˖ذa/vm>x }PNyW^7]ڵ3dt ș3A/i%K[npmdΜbtQ4Ϟ=cjL/ɭB~U>.sbbla.Ip]{r$ԖB(P@8.UN:qy jԖ+$/.֒%Kx{NFI?^񞸸8 ZeK"`|ܾ!Cf6jHZlܨ]jnhHFtDR9rU֬Y9kRLzIYq|#wfOLLg0:# ɷ$9bY2d`sjG۷8nnnR߷*Ki[LܸqC1/$C4]D3g(F;26V$bccٱcG:r3gHُRިd(Rr`<}2))>Hc\@-Yd eiN ClDFFÃ]k޼=.%2M ;/dɒGI?lﺑ3ͨ\HI2w ""B?p@)K+/2+EtE}C)|d̙s&͛7̔)ߖp.]Փ1cF)p+BFN4 ׮]qF8e47QbJӞ8riK֭l)rP)MϤ3`AחM,c*II8M6)f\wss3#mƌi'5N.de7#3-Z'Ov@w}K.\Dƌ]_S3g:4)RK.Eʕ&c$$$ ,, ZYi?6ol<,, ݻw&룒ݨk=<{ K,;{H*cǎ\[f ƎD,˜'PX1+0D^0aϞ=… 1h h&^_`*C &͡XbǛ7oמ?p(PYQM4JVT g$&&bȑפP?X8:b:p%\vMVضm[t? ~Z{ئM)ۗ#^Od͛*s5vٲeb?8Pwk2PPPf?~AAAmtYS8U[?6(_$m6KFυz۶mb_T_IոӧWtzd˖mֱ 66wAKYj&U\W_}%=B]qA odJ驳;?w|Fș$wR6n:xx`)9l/ImCCCm ޼yS&BԤ>zUpU(){K#@u$ub za=o^ʒ7$O I իWW%J֭[Qnݺ%J(Uzucy:YWm 2&RjȶJ2K:hH6 }bu=Ν; ??~5kT>'NK4 J2_qyc#""ШQ#[&9L"3^1γ7E4O>Ȟ=Drr LRJ}hҤڽ{æ>C0? *VC?3;v y[yűcgСCX"R/;N+.02ͫ1RCҷT僡0N@Heȕ+G֬YeK̙3+`7t 3Nbƌ%TRؾ}x)+]&2b^Μ9#R+KSz=e@#zGÆ ͟?J1P:F6lXԇ5]tx"3d`SHMRN>mbǎv8ǀJ*%emKR O>my0PȲꏓ1+ƍU͹zeB /Ob\khѢ,ZzRsn(!11Q1w$&YHn ٫W/tÝmQ㨨(Y{֕}b2OOOuW7?!0'R\ݻKYRCliQquoooN8c Ν2dtźcV$,X`ѣG"|<$6Ν;ꌸj/0޼yضdef. ue鮱 F]>T]r办'""BƓ%KKg eʔS;R7H z 4P~̙gϞ6gϚLנAhCՌ 7:쮥ϟ?#G"11RG 2do֤S(Y$M_~]0t)++s0j!M4k ]  0'?޿!CnݺxY:t(<<"}o`&vBʕq-}sFWKw @mv;c̘1}F9Q<0|2*VM6J*0pPH=[l㡷oZwBxT_ɥO(%Zz5 .,>pdWM̛7O7a7|pf͚5֣Drh$I޼ySK,B@m+V(-GXMJKĉ'NBBBذaCf>:uׯodbǑpEgu777^peɒEӧk?WL)uC2;5||| dǏ+>ׯ_gdٳg7ixꕬr咲sTCQ+VȞÔL>>>ƹUFaX'$Ǝ^^^T_%}ʕ+'K2bĈdW (9eʔQQQkS)`Hŋg+RP|t4^`tUϟ,8JNCG///ᅵ3gӤIcrϯxÆ 4 h֬-ݠѣoRiӦ… yya}#q.(6;wn<ѝ#QV-Y?̙ŋˮ_mq .a4՟?V%LLL49iRϷ$[A `DHUtpp0S*e8ꌢzO.;cM7n=sptfڃԡtl6&CĎTTIP{Q`AYŊ4:Fv/HW\aٲe49# lj'dm8q!m92I}._<]FRyq,K2 ?]Lk׮u M4QѣG7ɘ9szHD* .t۷oٲeK-[J-|u:P{\#j#cƌx4ٳg]cs,ì%1~~~0`]'.^_WǏe5·~PlEB x J_7oăѥ<|PSĞ=Δ-I@1/F)SȜh`O )*Tz_իWϮRXwww :G߯`oڴi 8:SYUM6ڵ N~hѢc߿_d+W.TT%{]Vcu!)dGΝ;Q`AY [|rߡ *vIc߾}~gYfEΝ- UVeGKq^Ryf͚LY5T_ɥ@3m۶5N>=ϟB )/uLL _}q3f þ}rРAh"y*>|&Mb޽-+V8tC3rH8Dri9I>x@cرvӫ<駟D}T|A;ITH"֫?"I8p@Ƙ>|HGv8v>|hyC$&&|2K ky$O:%+[lv ,YشkrE.Xr}e՟3LQ 8nf͚zf͚eP G|661&ll2YZVJGt;wwS}'<ΘUݻGRTJ UVYHر#F`Z5k$e .P gτW^e͚5TG*U^ |Dd=F>ٝsӥKHL Cy#;Ԑ$RgʰrJKf/nbȑV[*UJ*o'G&١C٦ڵkym&eLqRXDd;v옝xtԩS3رc哲ts&yd($O<)Ӎ$믿d>}Z,NpPtQ0ӤM=,Bqʕbiw{{̘ޜ8tQP ?h 8d՟/MA]l R!GrrkWR]#M*a,bذa̘1C,MnzIf-^8ϝ;gR/ΝS|q={d7nd%첨P`ɜ93vp;d/E{CJٚxq;h5pIEslؓ #Mb޽[Q_wa xm:L;֠o5jݻwy-[;;yE*zzzΝ;vҘsdm>[ÇܹsrJ\pO<ŋ?~a%S~,,~'YIb lve} ɓŏrXum۶(Raڴi7Ν?O@(o5 &L} 0uT4i"~c$PV-ټYf"(]4M'.T41]dѣRJ(^ %s%K\ǎ~gsŮW8pz.]jrEXt?F|KIar׮]&u͞={i߾љ3g={v;F9r`rg144}ȑ#9b~嗬U ,hu 1ظqcrGd{G{Qة%K({vЬ0e?od5GP0g)d'UOfbSkԝ"S+VL\QvtzdߌԙЎ7N&g``rʙ۶mxI•+W- $ M_PHխ[W/#ߋ!T|Gdg𫯾MA*&ɓ/I]2e7oDTQnʛϷYJT~7 ͡J&RzSHYaj32cj0zk$O+իr???6l޽{ѴiSyƀ3gģGl2TZոXf5qރqFDGG+cܸqSc}Ha=I@_/0w\N[_FÆ qmUK߿ ŋٳgS'СCeVӧOV ԃ>?{]1bot&h*WȖ-'+\|KÜ)^r(In:۷Ov}yGWQum !!HUz"U@RU H)x&4^,.EЛ B1|ܴ[&9Jf̙==uoz%cǎVX1kxm [8 i*7TjY#z~~TLҔT [lim ~:ɣ9ʡ0y$?"Y{(nąǎӌ:uJ͡yKC0oLk %-[6KM 2 EY~Oo DJ(iӦblI޽Uve\\_+{{ZRoܹsFz.4]!-ZT9r?;zHҐ7:(((fgPP*5k*ˆYĖ"y+8 񁝝(gϞEʕ1j( 2ڵCHH*ݢEЫW/y3@S ppF5(UV^ՓHE)G0r[\@O-Ν >}:Y7ow޷T`#$$Dopp0H ^^^ȓ'^^^(YB唼~:ttZPbE,]ix43+>C,Z(%K`ܸqr"3<|[lQׯeVU80I///øq㒍Xh… `F(\~'''ɓd'ǪӦM߱ĜA3q]paxyye:c///.\O;w ,fVN:q޼y7o@bڴi*+ޢ^CJTEQh6DGG}*Ub||l^w$9akG+̙3ïM뮀B&dDD𞞞*4[F+(b$oKH XsThgRmL|҅ 訙5s WWWvjժ2iv&tft`y!N>-Z0,wyӦM4oRCـ-IYիUK0#E'ԿG;v쐓DSZwyjY>}hGÆ cf___޵j[T eٲe5m_*6ω^r$>;###3i'""B/'`讀B֒?ҦZj0"9S\H2<<&MJWhѢOY5P>,pe*Th'NLOVR{=er=[ZH7h"JH؀e$9l2tƏTLoLј8SfHHx wbذa7rFӢE 2JBB\29>bL*F߿N~a&{G%T&-n eXyE$i"݌30h L8֭S-9sY;0γgϢUV vX9i0/_kHI4M6k1cgAcpΝ7nիgtݏ,5R,cv9NGQ`0(28N:,ݺuKN//HyOp9g6:u7ESaFS&E ądI*;,XЬn5ݛ $]&;Piz6l-Z$M"yIi;vB ʈڱ$K8ϞJ9ӧO9nܸTCboo˗Ud6ǥKR/_֒&L\kF]ƍǽ{2<<$gH8pSLQysttT:/" i2ު2jђɨQTx7IFSK!r6/D 0~t/VKE@@fEVvsnP@Dk*و#2n40`:}2IfK@``@6"׬g/ȕ Eƻヒ˗/+#jpGq+?ԯ_sӧOS;oߎ.@jQdXŕ0"§ٳge˖pw~ps7774k SNEꐱ9`oo6mڨVWHxZlӮ];$F"| =lق2eʨܹsݻwGttK0E*$$:uBppXZrJy:n⭨-aO<ݻU 9=JG}[nUjZ[Yȱk0feflof֭trrҴYʕSvR>GԩS٨Q4ْ8;;iӦ9s&O[B)_vyTo7o1cpƍ~rl\f GƍgzC^~m \V$7v!,\0}T&ŋ~EqϞ=}Y$667o]`ٓɉ;v4x{{_ycz']tI|7QQQ,QJggg^|YkU7)/RZ.j1{l+d U=p/_{^,S8\~~~ |7KRfNF SBBNӦMQ4o\ǨQh}uQ69"S\9\~=A cxyy]vԩZjewT*U>4k.l۶ wFxxxHhk2x8BلpH#2hڤIݻmڴQ>y;wLW*T@Fиqc4jfW>5FF1^޽#G#GWLL ov?~߿UTwƜLu[8GIen:8::ZM)_7NA-::ݻwDZcY0\pje[8$H' .d… rt-.[{I޽{Fu:9&M}ZlLZ5$I6ٹs'mJ9u䲻D17:Dm4*1qqqaNi&zٳg\v-۵kQB իvt婷 ޽ƍkoDӧkԸqc~ZNvY bAΝ;u[[vܩ|&Dr%wѴ]խ:7ժU3}ʤԿ,-]ZդZjc%Jk׮M-˔)ñcĉc+Q4JhɎ;ӗPr8S3_|ٙ7l0 իٶm4=a)R$B):/A9ٹsgM5i"%K||цOΝPꥷ]A2߶m[{&xyyq۶m+,6?:/pxycO?EP82ѻЩSt%[l+zٮz>}U Vi?SLa*U޷"7Կ,.˗Y`A=ʗ/ue()qȐ!ܹ3>|hkO,Y-2f1CXHHHA4'oooƼH/ߧ R~biñLɕu9|pÇ3::ZL#)-3֓XcH>n89Կ,-I1Quk.i۶ۀmE~ ɰ0<==yZӧOVZW/^h޾}[XIy/'KAѾ+`7 駟?kΝzGŔ9RCI&R}gϞ\rĉ( p ʕKSמ={/Φ j"JHu2d>c,Y$ǎÖ-[PT)nXWS]qtظq#ܹJРA3z I=%* GnSuV|޽׮]C } je<ܹs!O/^ b駟@PfM9SNU57%K}}}?ه8r?ݱ(pԩd1|p_˗/GժU-ֽX U¶ `-N:êNNNغu+֭keSn]lݺ۷W-B߸q#=zm۶ɿT@ƚ p_~ Py)R6n܈ƍEӵkW=RG5b |; `$JHHYTsʅ5kHxx8V(HY5v܉+f8+We˖kid 3 bbb4+;`رC8x :NmXSU'`0Xt)+'ݎw}_~-B~}@\U".DNh`p5AW-'b~O>z FԩS-L^Sؤf䡫m۶i;;;_-[iӲeK_>)ÇAصkY\ZXaăy'**7Yڵk=d@k.U 4H#lAl#59ZvL1}˗>/k׮>eh)!iTsqqI6g;>>>ͅIcbb'O$0xKMƐdxxr9կ__,9rUVM;,YΟ?z]^_N֐qiŽ(S Mr:e|L\)^8weV}HXbS|JKۍg+2Qeʕ_ooo)"!/70j11;I←~9o޼,#$$$pܹVdVmJ6x31p|GRt'qqq}wII}& gL,ǏӬ8x/9o<2#L^c;ÕItwwܹsMaÆ>‹@_N֐$yʕTˡk׮fYºufYPJn+ضmۤ| ZS1q):t2ɕ+WʊM 6 FJUs>u^a̫21R"I_>U,YgΜɼ(gΜZ~Je &CܹUXxڤqQPeFāRtYe7|Rfߺ$lL)v${RNl0VXQebŊ~O|) iI-T#\lԨ|===U={&ԂR+=` eTTRϒ\rݺuC)Rqn5֭݀[ I(_J .]VZѴ .\P+WT1c[~cG-[5jՊ.]J*fwH?.X lIrZh6߿{Ouf͚c!7& @st{ƍ)w9YZƓR~C4ib!!!4h s͹s26663ɓ'YvmEVZǦ nZ޽xy9i}(m6LJ6mZӧ &'O %e=)uT/^ע:u*؄^ R)_.y1/7KH^ImlE߾}sWO>DEQ:29L+%3O ,H(0°aTv[ v$|r}Ϟ=,6hKJQ̹A}rH@@6l{Eޞz7ڷo߾ׯtYf?`Ƹy&{h6l0wwާ%etD믿 Wzo8{e%4֪UK-_^$i&y\8cƌ1aaa7n\RB#crCԿ,!I2֭[rkgtmҬYIߧR11ɘ1cҺYfRm̘1XfXb֭fiVѣV"'OL^e í[hRb0:pƌܽ{w^v\|yRkjٶm[yxv١Ch|dDdppfrɓstH?^QYCRbDs&M|{ꥌu۷o95H9/;K9RZt5Ӯ]9:::-[T#O<ݻ$irre(Hy?|PuB>hHaKH6~bE,I1K2eX[z갷G||bڴifLٳg2R ԩ:uPB` <=='Oxzzc˖-Uk׮}&m K.U-޽;֬Ynݺi/_>imڴI0&ITTH[x'Oɓ'qEs={W -t/jyZSTQyָo}?66gϞEÆ 1:hiJp)Ybgmtt';QDyae,I%`ԩEظq#MWyf(QICBB0k,|TߪP%iVkzD  ۧ[Æ ISDwر꾳pwFRjGGGFDDII>zH5OXŋߢ6}h3^*'"DJz PwYxq2(PҽyZ7+điӦ/0l~|)ukA(dٲeU6u떉ͺ={Veڵk+4gNCAAAkӍ^0::ZNҟV(+;4ST$#CF\lQF!o޼~ݓ7k[CK50|GѣG6Z6z.uIϒrJMgNVZ?xoX:޽{Xz`ʕooo+&22&MBroiO1vXys 6 |駚o(_<&L`4nV:qFeXi HǎKvW散xUS >&ՕƍJV;'ŋ'˛٭Pu߸[]![#wСj+70={ 2@///U}ll,={&ofFáEF1|!ܹsU]=~']ĒڵkQlY|ךkC`a0 G.`?hk̚5 eʔU`I?Xz5/@'(AF&,,,.]e'o|[n7յAE@{EŊ٭qlUv3; S\Ձt IDAT5t""… [ُ… Ν;=|PNS609ݻrV48Ќ@jcV*ڦ#$U!Y/;Xeq%. '@aSWH$=a,9@qL,y7? Ç?i<'m^h ` ( >o]s"-,` -VN``rHdX)=&d5"##nI: [F ҉%`$ Z#06*$b&MFIj*;(E;;;ԬY-[D-P~}7XK@#gspvvƐ!C0`?~_gܴܳg$i9֬YcY5k֠GPpߦ~F)A\zUv!hݠB3m$Z ͚57ح:SH=e y۷ƍDqttDPP!*TŊGd ~0fV:ސMUǽ{3<}Ϟ=S/Ѕ%J[ngE/<A՛; *:ޔGo`DC$GRb @ @C=f@ @ @ 0!@ ̆h`@ !@ l@ @ 0!@ ̆h`@ !@ l@ @ 0!@ ̆h`@ !Ax@@ U $A *p<SUE`ax+r'oNz @`@>T|(h]5XhF @@L,H @"[G]N"E"$$AAA)ӿ `~@ d@6!T:3S҈D… q)\xjժSFF>Aw@`=Zδ' }Wh`SELQ yDC  VC7|k&cysIA֡4ܿ/_49\|YlhrS$ Iq@tN`=x:ZEp \Hg3;FgJ>ͨ@`8譀@`C̀T!?SxС x8d  ̖?j֬ ͖ #0I>>Փo\pժU$-|D2̕+e*H/ol۶ Cڟ̯Ǐǰa 5EaNСCe˖m۶4qҔ@3%HSNa֬Y"""7p@iy9s&*Ud5d-kZcҸ%ݲغukH|G2jf#$}I޽{7eR$$_~=Uf˗gPP|j:fԫ2H|˔).uV*8HSoܶmپ :tH.6pB+$kI r$l@/Zk0­t쌰<O>{Iw7oƓ'OͮREe`07ߔ7 #LFbB\\\N~::u$/з4\?pANp֭t>)1fI {mpLHN.BZəï\{ꢩNXkT$$$y j׮jŋ~3v튡C&Wb0paN0ltJ1bbbd̘1K "mVa00j(|7&e6l0˩|C ʕ+<Mԫ$Uv=q$6&SJ >7otK.ń jr*#M2;vK2QJ0gy2|'Z̜9^e?c֬Yȟ?? /zLeN=LK d;={={ ϟ?Nj/@ @PdIi $G!}C/]͢Xs6[#;w2b4PtRl޼NJsV֭={bpttT ;R b)RTi~BxKa6B^P=zA)XٳQ^=CHU 'SLM@hѢ8z(>3Z*]'+WT x;vL0S 7He2*TZU9U0 E IĠE19WLYx{v$|}}EUһ%2Tc>u$7ӆԫWׯ_7EΝ;z)W҉2QҪIXHBk2RJxJO!EX W^Egڻ)\p7F=CyweH~X]! 4?N/ѢE (ϟ]v9r$2R#hsׯorFM4iH\34jHwə CF$*DO'HѡC~:v숨(@X.hEK#7 *;'EL;í1n  `)\1cjԨSN鬚7̙3ej.~+,: nР̙cXp!֭7nȻkC2QgA@ZPtLg>@ӾOݻw}3X=p ?֪3 Kw޸z/xW,eZ/k$ik0ҏVqP$JF[s6lɓ'U&K.(XP+|WPL^ bX )7YիWǙ3gv .f͚r6P8sDcʔ)dȐ!([6 3b?әL:UAo4M6oެl cu<$'MdU^^^,X`f빹y=///]oҤIw`بt !iӦM^qvv+8|*TH3=,X@$gtf7)Fl萐vA׮],cJ^GvoHK\>}2\VSzs@󼇎$dXXk֬a |~؀?"51Y@,[*T`\\̴{$ּ}3g$s̑z?(6(#)Uɾ}^^J}k*8Bl]1q;ŋ[(Z(9,$ڀ]x|Fqqq8p`˨`Jұ$QIӥ`СC/~⻐8$>N*f.6`$$ʕ+u;ZJ~~I:ۀ]2-ּ5\d"K,z?(6&d\x,-!|E`4uG E sȧ$cH9m4[)SRz'Ie*Oh`kIaPHQ'Q$yt=/^^^|PYIڀ$52'OtM޽2ڌ 3}ӥK*^vo9PRoXa^LJ=o߾-cBfO6I޸qvvv͛.ۀ=”Z z*w+Vpԩ߿?{a@@rkp#8J;wdS]9t(zuHT<..ws8p OUVq޽SFJ`?ir$w+m&.KŚNн8p@~ȶ؀|J2\6ȗ_~iz{{'͍bV,^KI38xV\Ynذa&Yl;?9ooo?~ ,a.r$7lؐr80i$Aa?8ClذA>5lԠ{T8tP)R$]tvvff9LJ*:8&@Rj;.ǎ;\='򄸸8nٲ 4Hwzɒ%9zh;vL랷,dk]wX>KGzS 1[5ػ1F1X#[Fh쨈D,4x?fgl>3w{Νٹ圓͓wM^9+ .\xE.\;f;pWDvv6f̘_d|lycƌk߾=U@v3m8p%Jl@ X+t񅲉 1nKr( XYYJdz} jN*| f`+L4 =w+VĪU-I,䰀r5 oxzz2eʨ*(\ L2}p+}e`k9чWNa xqreiVڝc~޾}dk/p>z\r5ر# X~= Er={dO&YذaC?褠6lvxdϢV24hPh}n1r4hЀ j.3[,Y+ c'q8ӧ +Y$._5is]1t|ptt4j}}}vZ-cr`^)c^{RыGsxĚڏRw3485ܪ p R_ ==`]8l0A݋-2d[0 et:@KۅyX?!GjUNm%`(Qx?oɓ'Kfb j w^٫Y&;)S IDATxmbŊXt)6m Ο?6 tosPB?d^\ixS߅={6*@Yw/ SSUIQ!`V-oT^ =֪U /^.XfYl?:uܤI"d`\:a„ ?r„ ^'(bLc׮]SNzКxĉzq56'e`3S \8\Kp6vXtTT)bXb݋p1M4Aɒ% =|jaQaÆ ppp/̜9S 4???hcƌʕ+gcҤI֭N= SolXμ"[2n862Џ^4ge 77W? P(!n~Ypqp~]5j Dnn]D1NjVR\מּJ "j,zE܇9?f ;paC] O9|pײ24/>}A2 >\^JF<ٿFGGW>0uT6?@p= >\=UgjZ5sLE<...p$D4DDϞ=˗/˗);;j֬I5k֤ҥKQW"g>"ڵkӥKn=zNQ3/=LDөL2 !!!tE}h'ѣG*{SZf͚^Isga -#":z(uЁE ݛΝKeʔ1҄ĉK,IӧOѣG ÇY!""EٳwNyyy[XXPxx8M:D֭Y\]] :qܹs&NH=J'Oի`+.zXHD_xA>>>+@DDˉ{V&8Qaߵk$%ʕnnnصkz$jd*ŋZ77UY,]TPvlA2 qUΗEvvvr pR]Wjqԯ__c[VK.A ? 666a…\t_lll[KIEO9s+VXgӦMݏ 7v?i v .hJVD YfR^`6mw<|wP(Ē%Ku-^Xp8j*~S4wfM\rC'f=MFT 0@zћ\vbUƍ%3\ٸqcaT,nSj|ٿׯԑ%Onb P<ڊ `un[xN@+++|V;oaxy|||t@@ffNźɃtZ} }7o`ĉ:ewrrڵk*'#"!&&Fu pUOFҥE뷵okb1c u˗/csj&3g4nE ӧh`HN1'Pq-[LexcZ/z277g.qMM+++̞=[q$(F((cJ*^j* DEEAk׮QGh:Ν;&J؃!Xte(/ /xag͚U;U*=O+W+Wgv-uW2I1?L3Px5Žz*tj G\1\-#G`ڴiׯZn޽{cʔ) <99!!!Zb@Y[[̙3SNZx͛7WO'l8p_}BCCѺuk 0ӧOӧEaӧ\F [mQg8%:4Gzuz{{=(+JUqpDpNf7\s΁ARGw#1 qYYY2e{jP#''GtK.{55U ,0=`fϞV;FvDpNpU() ]8h/[,]KOӌ>8p k*ЇPصk^u;88޽{|rO֢z۠A?J>\AHNNTgffj秞Ϟ=]^=A?P`ڲeb4QZ5{`/d0غuY,n IY?4۷@N:E|W=2q-Q pFdWtvvf\ rÃA);P&uV;0?W !nf͚zח/Ѥ/l>;JGCXZ5+>\!m~lS #7ڸqh}5k,p͛~:uT`gϞRJ׫F|g3fopp0Eq=2MO L, d| (t*'|bgZ|/~ X#l۶Mk趂9A[rl۶-.rhJ pV-!UUDub H2w|C?sB "B׮]٪=x> m޽{)D ##J*[m֊ԽfdiiN$T}<_`?%bŊõFoooZcѝ8uTwu.W`5bΝֳgϴ??x@'J*ݏcN@NKLL|`ZmߝVJ.Gk 233EP~}ht A ֹϞ=ʕ+!-6lh?K>d`wS (feP(pu[/ 7o63f`U i6رc/O6'TmEڶmIf:D +(WT&OlpL4,蟅]kvsB![`3k(ꫯ4pb ʖ-+H:o|:@ (\NT1rrr{ymmmQ`kk 666aƍ!%?[4i{jo_oooѽ~wU7pf\D2 K?^0M N:mCPBBLJ)0FbP1.^5K_кuk2e v}8YC^ze@ 'OX,_\:u9޽^_^c999FdѪU+_ qrr˗/"!Ɯm盈pYהuK~PrDQ%k-2YYm ZEW5,::ZYf齬ͪm۶-[ yf5o7lٲ;E1bbbO., 46nܘU.'DKҕy neS7"""LVo^/PM}6rשSG_RQ -sŅ YYY& e?w\:nتU+5jQu_8xh]tX7|&iE1NPxE7͛& B> ;Fj=L" cnUA,y\||<z׷1 ksX|z]/( MΎ]#~`L6j(٪`ܹ&o߾lUud`6Pq7 *l;U1DMnݺ\?( p *A|\5hyK'I,9s C 1^ Geee\r=4kmmڸ`uׂZbtS>LXOÇ~b0ihE'QRRDNNEDD] C#8DDʶ8%&&RӦMݻR#)00ڶmK{E7kL׬,:~8oߞ}SxeDܳn:e۶m0*[," X$Dt֬YUR3"k¹s(227oND4?_х LV)%%\]]j.yBDOȻZj*eqnDDqqqte޽{^tZvѣG; %___Zb+ݻwӭ[T֖Νpa~~zgҥ4|}f̘Aݻw#ЧO;v%''2$L*hKD;H=|r?~<暼Tj߾=-]FMDT{2#F_T]2RVj~\/ V^-Z~ԨQl2 }tγ< Q,IxCAbb"ƿt,=zvf6״ޘdꨓG$<Pn?k(rU3@`3jD!VV֨7ndP)"&1X!Tepđ#Gr~W0 L"%JTxҥcz)%''ӂ B]ҥ /_\\\ }}||>HC&7>-tD5" ":~ĢDTIBQq{-ZMzE7 VDTŋz׫+?NgϞU?::N8az:)`0Xj=nQ쉈=*8٭[7ыM*"--9svAwxѣG"" 7oh<TӧYC|c+pttĺu3bJ-&Oikƌ*ɠ?ʭp)ƶmx1NNb e;{.-[Af͚ NmYG +Ҝ60{n&ye]|OsRS/// $$3KK+V{p ɞ-ggg*k֬ dχOJai"dɒw}Bjra^^L" I&-l\5&# \6,_Ԩ1ǼyP(ʕ+5^ <d6cʕe`'M, e$#1DEE꙯[^xm\-4.N1c7Z+uEݺuuB`b#5Jd&MD+>v오zf"Cff&<<<^*sL2dXSO Cm2B F~N:!##5<+`>-t*@trrrjm]K$<)SИ1cI35ڷoOAAAEGG}?M0J R]"oJ-DROD^'ׯOfΝ5jƍCņ"2O)юڸq#ըQΝ; DS? "$.N}"gDD)DDnnno޼S˗/= 9z"""9FMVV?ٴj*#H?U;gQ|);"(!!5jD{V*=o>jРmr2qmsN*-zFUrI>Z4˕+ǎ@;@R$#GS r?~~x}[U}Hl*~ T ->x^u놗/_泇[2˗zxxxo @mfPHOO/l%''K#G# z4zJ^[lo޼M9992/K+ Vd|\5~k,F'''c|!F|cbɓ M8ؽ{w=޽{Q +ic8?Y1(˪2>@.???DFF>|(;\|!n=iĶnWoee1Z^%$sD!ߺu /_1B}j׮-iE nG!TWv-y2&z'(,UlJOOZ!==PHppJ)PT)ZzมIz/Yk˷AHDDK&KKKEʕ+@B1 "hĈTFB !!ZhA&M(c'[DEEѤIEP֭K_|߃LhBPޙC/^\@DԠAJU=*8vQڷo{.޽{ٳoӤ'O1/nDt|ݻwLW!deeQ^I"*Tjzu2!M ee1-Z\F IDAT"E$t޽{ {'>a W$ FPP+gMI([-4S;pls:CmDDdu_ʖ;;|e;t;FɇP'bBUk~c2AVV+MPv[RRAv=7d!*+iecԡCpZx^^kRRR())w m"%"˞={ٳgGٳ'gPCLDsGq.ާ@uԨQj*"1L:s=puIpAvh„ fOׯYf ~uִo>ձ'N;sda! @w6Ѕ@vD8p@pI&q$ ["ZCD}'www7n7߶mU7}qWDq;RpԸ?.<~8?'J1%3g]Sm۶.\КDW2Dpo=vz/ C$$$=m۶ 4 u/_6Y%̽ @C0a#}Ss„ 5cF9舵kBrrr0c L{xx`x6Ę$!iD닏z3\t^z/ɉ8w bL*\[06V/Kh]}9uT!//M6Tl"=O> sqq۷o322$x֩S'p1bj@ To)afX=AF`"TWد_?S@!,^u{ 7yQBJ*axF ::&}̙u?Z>|8_4SX7jݺu?E.0D0[ 8q:/. ՚ uf:ý{aaM&e>9kJ!i\\\cQٞ<}T=ZP /_䋬Aqpۇ* cG  `XQN0+ʋЂW^gϞFѝ/jҨHOOoPu\` ;wzڪƢ?Tt$akcx[h+;Ma8 h(0Ƶk nZ2]~ǢrڵKPe${C={V}<2?fY^'O6OΚEFRrv[BI_` A7078y$ʔ)c --Mg`X.qaL&_ؘ?'{ѣ7o5jtgk/zbm o^7HS/^MؕM[ ANNĐ IP(DW+WYN///}|עe4ibvyK(K.ikDXrek T4Xdlf^o@Srf_g5G76kCmw~SYrtQ(]ddd͉D2d? mn޽Y*l=Y\T"޽[ AAAJڵkͮWM VX*!Z߬* ڵKD[XXԩS| e_ ^ 7~[@Sr[nI6oݺw2пzy۷*UYOg/_c<ljJr{ʛ7oB ڵz]2o1RB[6߭[EwAz=KV(1uTɟŢŋUmڞbTM+,[l5_~iVzzzW0*ʬjzp~7nĉT,qi4x2Ѓ\ӧ%IO;o2п)i ` In2<<)::,su9 BKr[]UVlqOTՇ=߿/K)3ʪE$d\O prއƢ>t]vDk(_| ___  @nnًg r&$$UF5  z]PP޼ySWV啰`?LrL2ЇA\'`޽Ž{ oʏ2i$lu}ܻ"8 W۷o1l0\XjQPt5k۔tʀ5fQ xΞ= 6`ѢE6mF={e˖Uʗ/rʡf͚hѢzÇo… ~zDEEFaiʆ=8ԅ*g-[J<~*0 uyAmR[ɇtf}7F=Dϝ?loߞM&9sDŋ(~幄WDavYkfM6F0  JȌVo@d9pTx O5ģE85?^4icc 6fhq䭍~PnA۶mEFFTT̙VZh+QZh0:u o߾Uի#nݺaGMCilݺUg022GMHmǂXM4[ı?ST={bرK.Z'8vޭq5pl039]N9f2B`HӜ7oߑe)X08{ʱ`"{/m۶s˝Jt6s?}hZZh|%K",, -Z0kh;;;4k 3gDٲe@ -4^,lt5@޽{O>Dmk^oߢSN&1'F᧟~2\zry{ԒD!ߋ3U bJ diEQrrr L[=CB'DԍQ`ݺu)**vMM6!j_DDD?Ҍ3(++, _|I^F)ƕJָBD?x9}wf,++?NǏ=lllDDQ播(Mrss ɓ'Zyxx(RSSEDO<1mڴ!++jV?QW"`eeU~׮]TNW(##:vHϟ'MlllhԧOڹsфsss*_<Ppph9///=Wvm4iũj4Hk׮% ԩS'zG}D7n$BADtzQф+Z ^xAwL[ܹsoDD2a \DdMD$(Vkt&4b7ND;"r֭{~%H" $"ipss=3/X@)"DɑZB!11y)eNQud OOOVUV>C755_N7nW$y~tЁ.3I%A}JDN;իWOO~):u7m۶=mڴI]]]?@@ThQFz^z|2߀K.\ e>|8\ J,ITD "d"H0" !"?\HOOEQXXQc"@D$Hdy~=O?|\TKV^v!7Q;_#6_HnGcRS3g ȑ#|?e`Gs2Imѣ.@r1+UQFa޽HLLcڵ Æ C``Qdii$US\@{.] j۷… q%c|صk?n}sE֭?^뽲5Fٲ3BzKR^'O4n'3' FQDI.* Hn\sA`P[v .Xg*@VVt" ͶmB +Z9l gN>7Jnm2ӿOWNA4TRݻ7֯_/ꈋ/=z[ 6do/'_5tԉ ǃPk۶-ϟ .h苓'OFw-H1uT׽~mڴ՝-8.5U F%oϯR` Th* ІU\ܹ#8AJ(&&o[":,8r;]#"<֭ݻWjӁ 6РA^#*S Z"bRDhnݺ|'i̘1R%)>>>߱>}Ж-['fKΨNDWKZdN/_BCCGq .]D;w;v&̟?k"GDT΄"?ў={(44޽{'(ԬY3ڷo999iѵkרJ*oIpmrss#ooo;?Pcj߾=EGG SDDjՊ?r͉S*U(;;[b8SLL j@Ee\v3w7n3;t1IP28p>ɓEBz}ʉ O 22RkرcqBEӧ1rH,YRko޼_Pk̑n# IIIZ8 EucEs?7\D9O(_PĶJۃ(//^|),f˗/)//F4E?OJcBhRP;;;aq5z=yD}sfH>3?~c?8  "IDH!LI}"ZG4tPj֬gx]z?N)))+JIIG"AՕ]T) VE 6lH 6e˖Qdd$^ٓ\%(((Y+Q'^cǎA;wDt5jԈ=JF"//KqqqLNP(ёI#yyyQ``>>>F_U-[R\\԰aC%"NDFa2U$"Zp!EE/߱chҥ4a"fD4K*T! FJJ 叒E׮]D(czQJJ 7Є"ZFDw^/%ǴSP)(&ό'JDH4#l2iD:uGemz_ +:`j޼79]|Yſ>|h=ǁTfMUլYj֬ɿ KKKjժeff +Vd \H"OO"ݦM:x uQ:&&4h@G+Uٳg(**Ξ=KoߦӃ۷7D @TjU_>կ__ADtujݺh(:|0խ[?EDEn|Kot~7ԪU+Z*4"V*!+Ν;%  wJHo@4<|NNN/Y}hܹ>Cx[pt]TRB,w4׫KĶrB?33߿?|+WÆ áCezK.ܯgOUn$) 4'OQT%Kd\hD^^_իW_~Fe( *W/ׯg "** nnntwwǥKd`WY @:Zjۿ ~HMM X %@i-PZ" =~4prtQh޼9إKѾӸqc5jԈ-^K3o&_UTRСCn޼/r El+fȑ}իWؼy3tbLؾ};&Lcƌ2)ejFpqqѨϓ'O [:tC )ПENѣ)q!S=Av2 ү+;;-ZκyCpQ5֧VJY ޼y (C_=7@x?صkWѾSjUשTLn|cWX֨QW.T@M*UBBVX-ZZrDiW֘C,,md`+S|C/^qGFFvڅ^zYrJwwwį_*U 7n`oe`GY 0зo_IDATZXݛuN RU RLL Eگ_?OaƀӑDBޟQ<5}0)SFug~5pymf,FF&j@ra"=zTڵU)yN:P(S_* ԫWݻwUU͟Iv2%mDrƈVVV3am s[_(*)S$ĉYf*,~E)("ZDDDD7o#GRFFha[[[zh[[[W^Zr%ۗ'D|DԈspJOOXAzu""y6DD/XaѢE'x"+Ds"\Dll,M6Ko6 VVV4n8ͥp5~ tY:{,Mt_p B_sR 3qYDDDgMK-|?#:wZMF&A,Z⾂ ͛7'-,, \nnn4g:t֜+mڴ7nٳiȍ 1IG"ADeq Uױ5RSS1n8vZ[[㫯BzzzJLLDϞ=M>?~Ĵi OlnGGG|7x!̥E{[*q@e˖e/,Z999R޽{ Y?{ > |cu&Ν;5.//?ҥKc޽Z08B?u D8|0¥)H=~؄U_x1aOjYLD\@aaa@}͑$Dt`aiD)ѦMhРA&"VI~)EDDP۶mFQM5 &*8?GGd0s`lgNG\B CwZ 惉q5iӦ0}XprVVVhݺ5]5j0>|zgϞ;v,ueeee K???۷OPW߾}ew?29"HCbUBHHI%J`޼yFVVL!nݺ8}iiij۩Gnbk(+`ĉۊ\,Z"P?b6C!uZX@}:c6cl5`U"Jlf"A[N)!嫜{//yyyy}Ͻx-Jf***z'1,++s\Ӈ@.XRJx]~rab jYrz=GFFg@Y%AJQ۷oh۷2x_%qqqBy\+((П>wVȇJ);8"uuu3qAi-'n<8_x*}Kn Rnذv5y饗;}њkÈ(DyPN2u]t!^MlL6MUUJ%4RJ9sf8ݦvֲP+3gtouRf@)KKKsE233τ-Vyr$^cX[FRlb􃎎'InҥKy衇СC^UWWҽ<QMa---^N7Px :.붒nNq7o^0Xu)S{ӧO9W[[{PJCA{!44V|7oCEy$uFG6]z7ov&+/񻖭zRO+7YY~~o7+QSrvشi1Kr߬J)-(<<#T#0[gTJk~֟=vU04׮]ǵkhooדsd6/_NMM %%%y9rD?K?ৠx7m,|6nȶm䟀o_ؼyCڙCii)zI'u'NrvfBNrnX;¢Eƈ*7܍7/A[0QUٳCRb`W_}EJJ MMMlٲk1 -x< PXXHwwMŚƍܿ.orصk999h}}}رCOTg$2jjjhjjrGxў neagϞ5l]){XޗG-^ve| oA mhF$+Wx~oGy`a>6  10Iww7n͛qѣ6\iZ-ywm*|u 0n $].dgg;9⍅ D/..n>>(@0 ; r `&o10,"@ Y"5A^~e|_Yn3_ZBΝ?ܹh,xK 8rn۳gIII |6il/^^|82G$YrTVVڮ/9+--ӧO`^7"u) ˡ1LAVU[zzz08ѱgME;.+T~~ZMM:z^);"ZJXiCRJ{:^JRRjll4ׇJq9AiĕRJ566$3QyW*.;w:F"EEEz_W6I-XvILLT?`DrM222볣& nCގxO?SYYI[[dC>32( 9~8Q,e8|?ۣ }6j4}ؽ{êeR oy,؋#L}}=J)=I?i[~($10Ц.g`P10&Ooo/ӓkYm9kFss3hm5uNWм  !77&vEllͰ>Å;vz>#8,hhho\pAO> _tF!{0_zx,(beLFb& 0{ ڈ \zբ"9AAA$$$Brr2˗/7|mě~-zɓTUUQUUE]]Ͻ `wvmfnatYlh@N `DR={VCNXui ^y7f.' h~>||y'sήr&Sb…zS6b[@"p ߦbGhh(gfΜ9̙3X"##g6oU-9bq_|\tV=̟?zJO1&:@ /C Arr&6xKUUpZ'L1(4'||jgĐ'Cx@ #1f. ~u#vi%Q -BVy3 .[\ Xcb-p@-D֡W7pi%&\eM,-< s DIH֯k=|!D1{O9ρh/װytvx럠&9 .Y8 nqv!x70V"@X]hD1}va8V`  0E!   b`  `b`  `b`  `b`  `b`  `b`  `b`  `b`  `C^IENDB`chessx-1.0.0/src/guess/guess.h000644 001750 001750 00000000616 12223260306 017024 0ustar00niklasniklas000000 000000 #ifndef GUESS_H #define GUESS_H #include "movelist.h" namespace Guess { typedef struct { int error; int from, to; int score; bool whiteMove; } Result; Result guessMove(const char* fen, int square, MoveList& mlist, int thinkTime = 25); Result evalPos(const char* fen, int thinkTime = 125); int pickBest(const char* fen, int from1, int to1, int from2, int to2, int ms); } #endif chessx-1.0.0/src/database/version.h000644 001750 001750 00000002074 12222770050 020002 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #define VERSION_MAJOR 1 #define VERSION_MINOR 0 #define REVISION 0 #define XGLUE2(a,b) #a "," #b #define GLUE2(a,b) XGLUE2(a,b) #define XGLUE4(a,b,c,d) #a "," #b "," #c "," #d #define GLUE4(a,b,c,d) XGLUE4(a,b,c,d) #define STR_VERSION GLUE2(VERSION_MAJOR,VERSION_MINOR) #define STR_REVISION GLUE4(VERSION_MAJOR,VERSION_MINOR,REVISION,0) #define COPYRIGHT_DATE "(C) 2013" #define COPYRIGHT "Copyright "##COPYRIGHT_DATE chessx-1.0.0/data/images/circle_orange.svg000755 001750 001750 00000021520 12062314776 021317 0ustar00niklasniklas000000 000000 LED Circle (Orange) jean.victor.balin@gmail.com led shape Open Clip Art Library Jean-Victor Balin Jean-Victor Balin 2005-08-21 image/svg+xml en chessx-1.0.0/src/database/search.cpp000644 001750 001750 00000016630 12223260306 020117 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 Marius Roets * * (C) 2005-2006 William Hoggarth * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "search.h" #include "database.h" #include "filter.h" #include /* Search abstract base clase * ********************************/ Search::Search() { } Search::~Search() { } void Search::setDatabase(Database* database) { m_database = database; } /* NullSearch Class * *********************/ NullSearch::NullSearch() { } NullSearch::~NullSearch() { } NullSearch* NullSearch::clone() const { return new NullSearch; } Search::Type NullSearch::type() const { return Search::NullSearch; } int NullSearch::matches(int) { return false; } /* PositionSearch Class * ******************************/ PositionSearch::PositionSearch() { } PositionSearch::PositionSearch(Database* db, const Board& position) { setPosition(position); m_database = db; } PositionSearch* PositionSearch::clone() const { return new PositionSearch(*this); } PositionSearch::~PositionSearch() { } Search::Type PositionSearch::type() const { return Search::PositionSearch; } Board PositionSearch::position() const { return m_position; } void PositionSearch::setPosition(const Board& position) { m_position = position; } int PositionSearch::matches(int index) { m_database->loadGameMoves(index, m_game); return m_game.findPosition(m_position) + 1; } /* EloSearch class * **********************/ EloSearch::EloSearch(Database* database, int minWhiteElo, int maxWhiteElo, int minBlackElo, int maxBlackElo) { m_database = database; setEloSearch(minWhiteElo, maxWhiteElo, minBlackElo, maxBlackElo); initialize(); } EloSearch* EloSearch::clone() const { return new EloSearch(*this); } EloSearch::~EloSearch() { } void EloSearch::initialize() { m_matches = m_database->index()->listInRange(TagNameWhiteElo, QString::number(m_minWhiteElo), QString::number(m_maxWhiteElo)); m_matches &= m_database->index()->listInRange(TagNameBlackElo, QString::number(m_minBlackElo), QString::number(m_maxBlackElo)); } void EloSearch::setEloSearch(int minWhiteElo, int maxWhiteElo, int minBlackElo, int maxBlackElo) { m_minWhiteElo = minWhiteElo; m_maxWhiteElo = maxWhiteElo; m_minBlackElo = minBlackElo; m_maxBlackElo = maxBlackElo; initialize(); } Search::Type EloSearch::type() const { return Search::EloSearch; } int EloSearch::maxWhiteElo() const { return m_maxWhiteElo; } int EloSearch::minWhiteElo() const { return m_minWhiteElo; } int EloSearch::maxBlackElo() const { return m_maxBlackElo; } int EloSearch::minBlackElo() const { return m_minBlackElo; } int EloSearch::matches(int index) { return m_matches[index]; } /* DateSearch class * **********************/ DateSearch::DateSearch() { m_minDate = m_maxDate = PartialDate(); } DateSearch::DateSearch(PartialDate minDate, PartialDate maxDate) { Q_ASSERT(minDate < maxDate); m_minDate = minDate; m_maxDate = maxDate; } DateSearch* DateSearch::clone() const { return new DateSearch(*this); } DateSearch::~DateSearch() {} Search::Type DateSearch::type() const { return Search::DateSearch; } PartialDate DateSearch::minDate() const { return m_minDate; } PartialDate DateSearch::maxDate() const { return m_maxDate; } void DateSearch::setDateRange(PartialDate minDate, PartialDate maxDate) { Q_ASSERT(minDate < maxDate); m_minDate = minDate; m_maxDate = maxDate; } int DateSearch::matches(int index) { m_database->lock(); m_database->loadGameHeaders(index, m_game); m_database->unlock(); PartialDate date(m_game.tag("Date")); return (date >= m_minDate && date <= m_maxDate); } /* TagSearch class * ***************/ TagSearch::TagSearch(Database* database, const QString& tag, const QString& value, bool partial) { m_database = database; m_tagName = tag; m_value = value; m_bPartial = partial; initialize(); } TagSearch::TagSearch(Database* database, const QString& tag, const QString& value, const QString& value2) { m_database = database; m_tagName = tag; m_value = value; m_value2 = value2; m_bPartial = false; initializeRange(); } void TagSearch::initialize() { if(m_bPartial) { m_matches = m_database->index()->listPartialValue(m_tagName, m_value); } else { m_matches = m_database->index()->listContainingValue(m_tagName, m_value); } } void TagSearch::initializeRange() { m_matches = m_database->index()->listInRange(m_tagName, m_value, m_value2); } TagSearch* TagSearch::clone() const { return new TagSearch(*this); } TagSearch::~TagSearch() { } Search::Type TagSearch::type() const { return Search::TagSearch; } QString TagSearch::tag() const { return m_tagName; } QString TagSearch::value() const { return m_value; } QString TagSearch::minValue() const { return m_value; } QString TagSearch::maxValue() const { return m_value2; } void TagSearch::setTag(const QString& tag) { m_tagName = tag; initialize(); } void TagSearch::setValue(const QString& value) { m_value = value; initialize(); } int TagSearch::matches(int index) { return m_matches[index]; } /* Number class * ***************/ NumberSearch::NumberSearch(Database* database, int start, int end) { m_database = database; setRange(start, end); } NumberSearch::NumberSearch(Database* database, const QString& range) { m_database = database; setRange(range); } NumberSearch* NumberSearch::clone() const { return new NumberSearch(*this); } Search::Type NumberSearch::type() const { return Search::NumberSearch; } void NumberSearch::setRange(int start, int end) { m_start = start - 1; m_end = end - 1; } void NumberSearch::setRange(const QString& range) { int sep = range.indexOf('-'); if(sep != -1) { m_start = range.left(sep).toInt() - 1; m_end = range.mid(sep + 1).toInt() - 1; } else { m_start = m_end = range.toInt() - 1; } if(m_end < 0) { m_end = m_database->count(); } } int NumberSearch::matches(int index) { return index >= m_start && index <= m_end; } /* FilterSearch class * **********************/ FilterSearch::FilterSearch() : m_filter(0) {} FilterSearch::FilterSearch(Filter* filter) : m_filter(filter) {} FilterSearch* FilterSearch::clone() const { return new FilterSearch(*this); } FilterSearch::~FilterSearch() {} Search::Type FilterSearch::type() const { return Search::FilterSearch; } bool FilterSearch::contains(int game) const { return m_filter->contains(game); } Filter* FilterSearch::filter() const { return m_filter; } void FilterSearch::setFilter(Filter* filter) { m_filter = filter; } int FilterSearch::matches(int index) { return m_filter->contains(index); } chessx-1.0.0/src/database/partialdate.h000644 001750 001750 00000006310 12223260306 020603 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __PARTIALDATE_H__ #define __PARTIALDATE_H__ #include #include /** @ingroup Database The PartialDate class represents a date, perhaps with missing month and day. All comparison operators should work. */ class PartialDate { public: enum {Year = 1, Month = 2, Day = 4, All = Year | Month | Day}; /** Constructor */ PartialDate(int y = 0, int m = 0, int d = 0); /** String constructor. Creates date from PGN date format (e.g. "1990.01.??"). */ PartialDate(const QString& s); /** QDate constructor. */ PartialDate(const QDate& d); /** Converts date to QDate. Undefined parts will be replaced with 0 for year, 1 for month and day */ QDate asDate() const; /** Converts date to string. Uses PGN date format (e.g. "1990.01.??"). */ QString asString() const; /** Converts date to string. Uses short format (e.g. "1990", "1990.01", "1990.01.15"). Optionally saves just a part of date. */ QString asShortString(int part = All) const; static PartialDate today(); /** @return year, @p 0 if undefined. */ int year() const; /** @return month, @p 0 if undefined. */ int month() const; /** @return day, @p 0 if undefined. */ int day() const; /** Sets date from string in PGN date format (e.g. "1990.01.??"). */ PartialDate& fromString(const QString& s); /** @return formatted date range (e. g. "1990.01.12-02.13", "1992-1997.11.12") */ QString range(const PartialDate& d) const; /** Test if PartialDate is valid */ bool isValid() const; PartialDate(const PartialDate& rhs) { *this = rhs; } PartialDate& operator= (const PartialDate& rhs) { if(this != &rhs) { m_bIsValid = rhs.m_bIsValid; m_year = rhs.m_year; m_month = rhs.m_month; m_day = rhs.m_day; } return *this; } friend bool operator==(const PartialDate& d1, const PartialDate& d2); friend bool operator>=(const PartialDate& d1, const PartialDate& d2); friend bool operator<=(const PartialDate& d1, const PartialDate& d2); friend bool operator<(const PartialDate& d1, const PartialDate& d2); friend bool operator>(const PartialDate& d1, const PartialDate& d2); friend bool operator!=(const PartialDate& d1, const PartialDate& d2); private: short int m_year; unsigned char m_month; unsigned char m_day; bool m_bIsValid; QString numberToString(int d, QChar fill = '0') const; }; const PartialDate PDMaxDate(9999); const PartialDate PDMinDate(1); const PartialDate PDInvalidDate(0, 0, 0); #endif chessx-1.0.0/data/help/about2.html000644 001750 001750 00000007443 12223461210 017535 0ustar00niklasniklas000000 000000 ChessX Reference

ChessX Reference

About PGN Databases

PGN is a portable format between different chess programs, a file format, that can be written and read sequentially, but not modified at random places.

ChessX is a viewer for these files, thus ChessX is somewhat limited in handling chess data as these files can not really be handled like a proper database.

To work around some of these issues, ChessX handles smaller and larger files differently. You can configure the limit where ChessX switches the algorithm according to your computers performance.

Smaller databases are read completely into memory and can be read and written.

Larger files are only indexed and as of version 0.9.4, the index is also saved to disk for a faster reopening of a PGN file. As the games are not in memory, this algorithm does not allow saving the files again, so the database is opened read-only

About Index Databases

The index files are saved in the index-subdirectory of the Default Data Path. If the index directory or one of its files is deleted, ChessX will recreate the Index file the next time you open the PGN file.

ChessX will open the index file instead of the PGN file if the filename fits (e.g. "chess.cxi" fits to any "chess.pgn") if the date of the last modification fits to the date stored in the index file. So ChessX won't care for the path where your PGN is located (you can relocate the file after indexing), but this limits the Index to only one file with the same basename.

ChessX versions 0.9.6 and lower have index format 0, later versions support index format 1 and 0. On occasion, ChessX versions > 0.9.6 will not be able to read a version 0 format and will thus recreate the index file with the latest version. These occasions depend on the timezone when the file was created and the time it was read (summer/winter) and the version of the Qt libraries ChessX was compiled with.

About themes and file system

ChessX reads and writes files at different locations

  • Intermediate files arer put into the temp folder offered by the OS (see About Dialog for the exact path)
  • Themes are put into the program data directory assigned by the OS (see About Dialog again)
  • PGN databases are stored in a user defined folder (see Preferences Dialog)

ChessX has builtin themes and languages, which can be extended by external themes. These themes need to be stored in defined subfolders of the program data directory. Starting from ProgramDataPath/data/

  • Translation files are stored in lang/
  • Theme files in themes/...
  • Output templates in templates/
  • Windows Engines in engines/uci/ and engines/winboard/
  • Mac OS Engines in engines-mac/uci/ and engines-mac/winboard/

Board themes are put into themes/boards while simple piece sets are put into themes/. Outlined and shadowed piece sets are put into themes/outline and themes/shadow respectively.

Whenever such a directory exists, the corresponding internal directory is not evaluated anymore.

chessx-1.0.0/src/quazip/quazipnewinfo.cpp000644 001750 001750 00000003114 12223260306 021307 0ustar00niklasniklas000000 000000 /* Copyright (C) 2005-2011 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. */ #include #include "quazipnewinfo.h" QuaZipNewInfo::QuaZipNewInfo(const QString& name): name(name), dateTime(QDateTime::currentDateTime()), internalAttr(0), externalAttr(0) { } QuaZipNewInfo::QuaZipNewInfo(const QString& name, const QString& file): name(name), internalAttr(0), externalAttr(0) { QFileInfo info(file); QDateTime lm = info.lastModified(); if(!info.exists()) { dateTime = QDateTime::currentDateTime(); } else { dateTime = lm; } } void QuaZipNewInfo::setFileDateTime(const QString& file) { QFileInfo info(file); QDateTime lm = info.lastModified(); if(info.exists()) { dateTime = lm; } } chessx-1.0.0/data/themes/boards/wood.png000644 001750 001750 00000106526 11217130264 020746 0ustar00niklasniklas000000 000000 PNG  IHDRnYsRGBbKGD pHYs  tIME| IDATxd}[$Ga:{2,z)npws< ?_ "_\ȄbUo|た0#P \ׅX7. 0_/D|\_5Xx(}߈HLA 0 @a"߈L@ % /9/UAdbHHPp/tEݡXka7 Q/~cCDPbsa3@Ă x/T/8 <q]QdTanPwqw?GWD/cf3Cd!!3-`03c TBU*T D䅪D.^P!2*P/c<73øa2jU"2!\wW@な<!3Xw@QD"P*P7@BRn0s,^ZV"3 nU7'yLbͱ2|>5 QsN !0SdkA)"VP_@BBA@-!4Zk"9Zׅuzb\ˡbXee hdA0Bb&څ2s V@aC^5;-.4vd+ŮDa.z߼JV|!|藁I':5ud۟L}Ty?@ juy;_XE!" *\L0&nšЮ7P Íp( b:t p?PLI29"QʷfPדY]:**,`Ԑ\59|C=TPkQBp(;$ /L+9qP>L` }}u}PpglD _+1&9|U,E>b3?x815_Uo`<|7ʀt λ|6 \L\@¯{]*0zСvHp(U| ?GUb?n'lOb+2 k-xk4>ot*aSH. ^eRg ?b*D2?c~_edku,T%3fD޽. pwgi7:$?"x<*bݐLhΈ`z(]`n(c4~.M1|44-D+~='{*xEa pk"ֻz BD}U Hw,'p7<"2'!TOꆖL?. _ 7QU֓b09~uY+0SQɆyD66. {1|p=T |Ap߿QPh]axMq] *A. ` H ]f*6,dXg N 37Z k-6*N,$&DoF!a|ʰ+SMkLMyFvSΜȜ$%u]%@7%}L⋫3(n2^0Eb8afXF9Varւ `3fDQbX4k Օymb;hȼ,9pR"5v^=%>|@E;èczubk+E@hC2WPLp0(؄٘x89~f¤)ZF(`~т@N139{,~,L$^R@ADF vlv6_q`rW^;oÆU DJz.W&ۙ`]x8h%3Ή]9vCQ) RHՙY ۀTUV Ll¼.>%WaCIL2UnhQ$@xA+Jz֓UW HBM6`D6z$Xk2 E &R9,>EoZ) R0Pe&V$*fj .W"G4a<|<.hj%L8??W8Wno 6Hc 6Zqn=d+)bKUU `#xŅ4qKNct9I7LH!.&>ahE )Wx7M#`v{2o'hh_KeG>dz`\h u ݎTx(0{;[g 0/S"(sV4W?,5Ŭ{p]}#k^Tx x*DcpP͠dfuAF~-ryE8(ۼYfjW&f "ȞC(ލpcu]]Ul38XUY)gbwwn0 9$+BCX`κdY%f=v%dfYeb7E"A)BYc LWC,bCjB Fq?:p\  ʞ_`*xݧD"jָD^Ps"diDx/@܊,U#֏{NI^ KX`iPNB!XL_|nO w{~KpRҮjj|p+ҘC?P3H% uD7R5%݄bW,>udaXH \=6RRz(59SȅE = 5 xYbw* bucˌu-f.X- eU1|黲0'qe@$b=N`Dgɷz=@) }==I6(p7*v8U5!"CPe\Sr5No4DcaHb/ YY, Խ/Fs~N n CBb_M"'ʶA UKWe), __pwDEjHTuj dO,J ċ+zBkaiACr0.+7R)j^ZP<}]}LpQjHpU I0}BbE6EϘWMԙ2) ӅkMFd s1ęĺCq}I&09&on 4QC0w $ =%¯2x#]=݄+lʇϭ tY$$.9o|a!0|1^AbĠ5|w.5.L U+ :0"pCƷ4@LٜCE7͖r7h 7>x@veenknbܬ5oHjNEJ0Zsk. \ o8n2Uy6=<Hi#5Q{͵109Bs/RvUQ䅂^+0PQR  *6t0TI9Ss- YƌϨcWpH\A:1v*Qh hXm}8ÄĜiMQ7!3a&D 7U'D8Jo(Q8' h> BqENnܨ-z{0F̯u B!IgN;ʐþ ;vXYbpAAgkr]6)}Nܻtz٭X;Ex ' d,H~ ~]9Q"p} $z5%{bA")Ck$~zLaQ}kC+)nUokzٸcNwL"FOyQ؄C tv} fbdoNJ7{}ȫ%5k3 Wo~P OoOBhr77sY8w>5[֍9硑ot'! (zq ll9b"batַ1Ydn{ 2D5}r7:=oZdɿ&\-( t V Ϩb=uQ)@"Jg {< HhMȢ(\c]i7e|7m=f܊ӈ~rR R ({Vq$&d RezƳsBH@|o$ -k2g 0@o{|_\ZH^W_9_$Y;n Q@g.Do.ĝxy5N{uGܮE5'לzA4X}*{jf@>dkm GM#dߦ͔q5b:3?Ѧ߿;*&}P`.!tGxmZKYdA; xJ٬8;"?sf̛4.ggj@4wDAE&MvW/ffG9 9bY ^O$[w[l\_v?CZ۸HIÿh"`zl4;(D8S݀n"{"x#f0<-F_@rˁ/~\=lv \S>06᧩z#TeO9թ vs4i B_=1 VSTU:T=&[9DPaѵjAiAQGhrJS*'ØX(PJXqC%Hu7U=rrNIP^_ BHO--Wn"˷*YJ<džV$4 ЄčZ ] H! @a#JV fʃhO?`0hoQ\}[ Ì4+wؠmmX&l8fU}D isa=zDHXf7՟GCm"19":X h8$he04uEeo =nca*Α#|KIf-dcx}8JO%e(jk2c:K$l:=x:(7;݄SFoL ̱"Ga=ܳ.s;=L ]iS|x cjprXG BϜ & p栛GG) jYh\74N? M8F?F8>IE(k%P1\ctgH)SҊVhC:l`sͽs>jipNȔzk@o"hl6(N">.*jl"iBLUig*.} ҔtG1I.iBv07Ĥr,س%Y}A OY̳bU/ia.X}=! ć[11z% N\=# HݛRPiJma u}[]FQ|~&INT˅ܯ|Rj1501Aз8,!WZ`PɱvC0x*:6eɂXDg#NeYP*L4AB2D+?e[cOk'/ĨZ2ȔE ˰ v5""Z Tԫ r0w/;tJC6.,c7`WMM039 }N1)֘sҷoéۃFwy/Y0X-KPB|"=ЭY bɷv=cve5'L摎ˌf")c RTotʕx`{HA(: m?7z@TR3Vz ֜FaVpjĄ?\~="*)z6 'c|T=+pY*i{Wctȱh2Z& FWyN̻lnG> k\MgIdS=(Bmbz<>S,#aMP3f 1t4{yT zBձVbzKZͭ2(ق!f꩚RɂJfrÚ1oD HbE} u't"V`5q#Ɇ ZB@4/=>o@#ő6뫏"K4X ;-g?ʵ*$fa9(rcaNB3f7_ؓ\ #u&-RmWը5.\X-9-}2h'닣& qmoeZ4e€88ds^~BD 椑sog$TVjn{P|ԩV}~}A[cTPU8;53z>>7[ ]-`vYojˉM􁐟 ~P|jbϤk6є Uu D[QU,s֦"c7 ge[]Y/\!=eN"f 6Q&,[*MP.Dj"42ۦc3߲ ( SuMOʂ[؈+?unԡ> DK>.2pkF3$C;7X{dSDZkߛԕ+M s hC|FJj IDATM0 {:x(n,fYdo> mylGHg+h7Iq/*zq% ůQ+7Rf7d%A]H((XZ +vۏ,8^L3RPEo-sx\GKqG5(U2TH6{~C4a k -Cfڼ~Rϡa ξzցމׯ7bU , bBh-H؂ (Ǽ xƻG_m7* A6x>VWaR=?BFVPZ C1 b j*=ސ|#:5^+Ղ<|TVY~Q*aV׊"$ DHQ=\5]o)&l4::H _ik'~&==1`cloܩ\IA6ap[T¦:qțwoϷWH`-Z)V(FS!տ3ѥB4{H >: GFTB/hLX-jB{ xTc3 韛,ԛn3EkLᆲ=\v*@my[D`K8Z̕U:s/ u.a= C53xy]}5zxjTkR_?l?IL~nK~=8Ν6#ZEm`&x ǏՎ|L\iXRLl:Olжc=Ň2b $Ơur!rb[k:`25Ru@p|y\b%P x\_<Mjŧ~P7sm1y㞓(zWa @ދD7TqŊɳ:}eU mE2D)/кol[qZ'*+&z>9R)/ ʂ9PF!Svy{&hTquJd!Ri*`1p+9)ǮnE>gǹqĚKyzc*Ne>v [6Dy~F F n 2*ž}Z7BNh_qa?0uZgJD {PVc?:C3xWԌ+ 6. 'bZ*4k[' p{½A(hQU}GUN, r5tw1?A[%Pa޲{?1lJ`\_=KjxWS͌u5c0g 37}aYlN:>~U8}k$yl}\ ?w7v[pŊVR` qPف5! ց?S}!: 09tNmet[o]۸lun5c-C{;憨]4VN,p/@*od]bk=gܴ4]4nlO[Ciת6X?ά{N;Mja^u䚴#(٠f:񢮶[k}'8zڮH)ڕ&0OVo@z$ݼ3挦:R.V&[Iْ膽)7#_%Hs qyϹOfn'16:{ȱm-[3y}6x T{m"-6~T10Ov4fqaEc Cհc{w>ltCIIn*8ohsRb>-N*B(F!EO$Q5X8heiaf{S{qLR7U2z<ԡ^(Yю~LŖuf7FӶMd;*(̤kێjSMve* B@+h{5qX1"d_[\э1r\ZnTz5'څLiBSk7x\=ݤ榚)亐k14MX6JDk-ExC-:L}7mFeJW>F7^!uٛ.nU鱪Pjޒuu5lRU T? .s 풬n,.Ҋ*Ƣ9hk%DBU/8#9I]j{,o_@{)ܴ1fV!U\=w XsLA\*mTHK@'\ay[WNpwmФ]_'/r*J/ZXshѷOF*x+2Y8ȉz=JBAP-}@zAnQ2V*aߓ6ַp'j\Mcۄ;,7aVVzC~%7 ZzA,8G2x+z*w͸Vi11D]Suh,MZPn>8klv%vn[}gh{<[|Xo[Տ%7Lgmo4ܑWm퐰1ή79g m(#[w6hi4۩ouwAw7ha},q`ѽj-av/ܮmi`ֱ?^ V38βrv;lOEPFun&\\5MQi<fVQWkՍ{ vo; ӷݤo4GmѫaS}njFACh+#e{!YyFF>:$۵E ґsy[+] ݲ+BbHjONjѼDFo]Yod0?؅jW2Bܛ&vl<ET(n5L_wirpUey -@0aD0J2;IQa*<չӶ$T%ے|3iC]MֳW'fNbضhg:wM]M†VuMYk㨇2 wrPaa Y\ NF}E-C1 -peRj5,WoRk^8B@ba=} *I*ig$[ޮ]%AЖ QQ|{/ݠ{M&׀źfA饴ẗ́͜eL,Γޑs&. ?5?"9YSݞ2z6mdΆJaFq>{8kS] .>1.)&Y΂5. ;mKM-k@EQ6ZոbCq;?p%K)2cBgq 7T oF7JsxJ43,Z{}F@sq<x~r~/=ڎH"X14֐\\ء_T:F߭H*GmR/̤UM蒮TZ.w1҈'| mF@AbJkUJw `VwܮvJf:Mic Fob-9q9LڍVQY"$"EC꼚^QX/\x~ZwY},"ͱ'hr;x+^tw=F8'|lI~G}{lWHʵ0DwA =ۥ䘋nIX{uY׋TD[NSWW\pI aiYYs Rmpz2T#ΥURhϛxȞhK|" .mlxY 佐@4{^} ~"8|ouL8S46Ǫ8d.HAx npbp$4)w4 \ooǝﹰzl 2"г{`եs.~};"Vsáa&wћmՄ9Jt +UYdmm5 Kw~fTG!`(oޟ3iUfIjtmwI*{e`\4YѮ2-W❗H[ؾeȭce M$SƂ c<>җL9N3@vVΟ^#XZ\a:$I%;֜\^E 셈=:$jƁcqҼuq9q ͞]:-lSQ&`"n t.x'=Nn=mtF.Z; 1z1^7KxqtYGTJJt# ([ +Bi@<,Jz/xӂٹgKc̦s̤gַjD.(<$ m6Vq^g , .!zG=9h[^DEq$JZQvŭF)sDv+0{F0}ګ$&&BҁYt'O(FmqʸxwU3E8JЌbU/2 *HD*"ԅl8n&.٥Z\?y` FĂ1GX31ކ1cg7ϣ8_,bt슆>XlgՏ}ӾwC&@YŒ^k%f hmMUts>o8vX06kI?tﭕ*uGpmD];ns_5>&+cR`*&}xC JȞu ֯Nwǰgn#\L)B]-nm)rvzU5!]|4f{,K EP$:zmf` A欈 dXm[#t҂ lW-qUQ~5AbZ܊fqDm : DΟvc(-skD6'dzg)1v~_Ȥ}Ū*=ҬMQb면_kXR, /J?B0WB+EA*|JdK^qVUo^+*H}λgWO!Zi5zR5pY/f:7:3k-&z&nOAzJ/"h{‡=c{vs}lBIod}_nAx!a{ EZwF%@ު\ou]Pk L`z[++0՛ W/|7'wHՏf?̅ AfIPj4%.. ҪpSkϯO ofv"uk}1=/;ơfr ]0+l|slMP0йS,E:xm\{qZ=8!mOYPÙ_4L y,`qgdh? d5?/ǃr%Y llCb0rs- 8h5c;mN %$դ^.T~h s*aA~8ˋE랹\$ZC;4rZ}ۘQx+2`|Qci {J񅭅k{?ם,AѴުHĀw ͐ZvFlAg='%KWՒ6_W^v JlF׆5&jp'2A \ym^T1w^vd-TsaRu޸;EZ;PF'0TG;o$Tl+Jm$LԗALyÜwS(۫!zx`_1"?lq3Lah7n8^v^{UMc$zki@{ |3=^,`wDZ$bdB <%'0~ +g.&sT{O|¨!X#0әfx Ǽ}TrݏYx]l;.ɊV 'eFZx' '$ylWb^%hh3CU `ِDS oaHVl3И@k/D6nf)!Lf3Ml5,CknC1JcJC~~; Æsaz+:Lfb9s٣TJsSZ1&D m$+=%w(`5vA_9In"$@L0M#g<&*a;9ew1TbuUkP*.።PrݤF27ߪ@ǘKmOcZ8CGl~mIOUR7bPd6`AP7sF22evKFć*{5PfMNj$Crݚ""Td7׶|1^5ߘj\*bq?`XC1]ֱXaX{Lo?T'u׭9e_c \cZCv,84h uwTJ4}pV?ɹE)HC4b(.G0PYrJvSܵ׹[FIwq;UoeK X['7iibûBjd9ll #3i\U%kd-&Cߢܳq}8OQlW<1JS a#Q[&u};h]Дݯ mn8σ\&1z,!3@zC`J*b~D-T\Bd }*tBlLf~qFHC͙BoaoT=]NjhJJd٭R^"rkŸ }=01d~Bb)|WW=-Eƚ.RK:AU<6uqo]q;qܪ,lo;YS8S"'I,^5!kr iC>u S&xC)Dښr\xuoXݵuvk+SVrdq:C3&%[$ hjz"cf$o9&\"]!g7Eɜ^ lX0\EH7Z.>Is aDsJ | Pq^IPwoB.w|qB5c)cE2k,ywbw"ZQ"U3|Ѽ+mЦՑq7a~kzUF8<ѣu\WqRkGiR%t 99o3G} _kЊF>\vL_zϟ7>@}L??{#xIN/\k»S9s 7d%f__ug %ND,"-%pǺu,|Л)z ZkL? Z;^/+Liy7oH';[f#6.Ϝ/+CWZ_Ѱf8 _=`pmOeI1Dž5'ĸ.'&xAoh H4D #vmPp|?Xc*=1%@hNL&<0KwGb" i)P|Dž(Wa*Md8tHO1CX%py](zW)5~~,ǭX6+9p}>HB JM=Hx$R%,L/h7r# lR9QaRGGSefvZ99X80Aӌ&Ja֝:ުGd[!aPAuMRpsH|hmrH ^kF\am as_ȊގPs|j-!g5 \XCgX8MIbpbu? Y C& K&}Sj3-pĘ[ݚFmdu$]-%c\2@(. -f`*m}(]z,q];a$M9mña}سoq7sQ[&1Z+9:߀xt!tM!.>@A$/&1V-(BR@EK қ>t?ػ1UJ}XaQoTg>,pHE{(J͈ n-pA:ZcIK96߯5s1^jƻ~hPd㏔&u|ugփf ޥ7!v8_Jr w,k{ d>k[.us5=7$[mTGYo5?vwcHS{nhsےb= 7v-OM7Zx/9C6ycMOl[mrvDjw"+Iƚ s(M{RĊ6OP5TH.JD$(5&XH q3ptmbe+hA~tfcKt>La r@م 3]műTV5/<[]/~^S)_\߅bݨe? \e'*d^*[})2|ЧX{Vzgpf4_<3U+}q0G)[z@Vdq-|3F4$NɡbXb7Yw!Mn;7 ڗ 5{sȽW;7$P ^7SB{`S)W] :;͵$du,0xok;q|8{;N/fKq*By ~tFh8XQyC^(_rDU5oL!v %,x(F1PΓۥ9uM\c8%[say`aK5RP<[k'.h*vp+q;`mQ"c{.7.c 悼η+fGX~5_xWi) ok6'b÷[?~zcZuWq m*2at x!UbeZмw-6sj9IyW/v c 4נ/N!E֮CLsΈ5dQ:5txϨ1,R@Vs}0Pzl1z6SDso-y >Γ9jvX pְ#74G8mZ0t;09?'zgU=h.aQcMըVKcQQq G{G;N,K-\8^Nj^WŽiswACe5{oB,ю}9|͋ |>X0#Ml;=+/4tŢc|Euݜ׉nuN4 =qg\Kx)"EX.b~4|b“ߕ@;NcD?/0C2k0)Xqa/+p h70ѯ> -ދ\+Y Z@o 1>Dٔ54iI֚hXl4d&>ϽBYk;N~~dLʗX8R>e200W㢻?l0{ !(oO Xzp'y)JS ?]șݱdYt}7y]+.QVqt10&>1Gq}N>C#'׾7zD܉kwGm~lqSyvM8<<7ŸzT<zcHm)ƄhCZcQ5'uiGWB"4i(Nz‒?Np_#[j9:3/%؃UtNqh֝$| J>axp;ndz]e,vZG>nQ-нs$ ׇeoHE- ݃nsE9])hTU)gA);v57ԇ:Lh 80*X /4iIdN{gfVꬄMOx(lNsiݩ*^f0# X3нSl:ϻ"0t֔*45^n^!ە7:9,;&bB: LiH\e*$uT O^JFvt O`$Cssɡ_l Tڕfg sae{Fgl>fA fG5/ A>Kv;e{+Qa&fURS(m4-58D>+1&]g7r@@8b:d1C޶iUth՟ zo;do_z̭-J8Έtup?\7;^MooN)gR)8/S OeTS 2+YO=ZM`Y^~h ~tttS[.{-/(0>rN|IV$_zm;tZ=b^pMMPYQ=l^.b$\)3 h6`α|sNDlހW6J x7 tځV2J?;"IQ@kaEWhdG&ff;+'׮jg,G_X:*vp#Ήvxl;K\8 nYLzL7@/u!{TB<> ].܅@;:=л) ޔ04f$H v ds1IZW6%]R@1n lމe*X vxB81Y֊$eca[ 쿢lY}o !r`K$*Z7$V%\umk]\S kBM\/Wcp6?Bו{݀ ^!~Cu fE)ޚMK]$;,E[M}Fp:ژc8P<TRk6j@T IDATC`.].6+sWUhoLTiNRWɉ tKa:jy U“S%[mR@&r.x&Yv?`L_2GՖpOnnybzN4i̵Lmzmۺl4R^\(3D"jqHu; ֙"OO*0z痶) hXX˩vUJ2}i^lS'D"o4aJ O,nvʵg^)9B }G*9ӍӨxeNN_ g&mr,zXe'Nz"0%`M `9f\Hӈ̀yBlؑ +ڝHxHq=1>SOur'v,M*-=]hqceȀAĬD-{l.b, d3PRK:bAF~[E%$c 1.m#n y5j`!וcǶV3\w7l 7*K( Z Ǜt9^Jr7T[ef /xۑϵJ\lDV*Ws|c%/%uÚ 5GuwsOiV8? N +B|k_ &pM>$KCqp>`5&9q6" 0ͩ+x-'k6WMx9~뚇6ۜ)2+3%o &^ _zwb*ֶIij٠%I8<7\i~~u<Ę4nAc\CemYTWR-5!s)*Tz(@i%YĦ=lcp~}/(6{TEVPzx\d~|BN+#ڀBV9*ޮ ,圓JZ2ذ8lf|$e $ȁy`MƚH : _c5<&M}k. X&aqah :{ <፾ B #(@O|)ۘ 1cu&-yNrO昏SXx+I5g3D?;jK+߻[&blMZ|[=ϣ&"PTgyu:s>Mѯjos=ٌYAJi U*jpK^y&!}ҿCNRX8LuNAtajN 2NF.\Rںz.w96P$ @5r~0ޒ4F|Y< ʟo3{-pMrw~-ctSȵ,)vi7O{w<@jxyJZQ}>|~~83kDqN6gG 䂵2Ϯ'6ԇsk0B=C/#V>T_؎;^,T2|Bז+ڔzKX_,Oހ{Z@# Xq]ۚT.sVM.p,4WKH~Y8BLk<̛`s"^0q$&6sjѰj_LJLX,,21̧_=p @وֹe5Eo}NR L^nJ 1YS"|U9r$blC:|KZ9U+2oq(zkz06^8WvO^sB}n>ZYp)QR=|UVP:o'{3gh5wCج);]fLm(+O\0Cer ;ʢ~prPᙶ^ Q=1Ȇ$||*}Wr \Do@ 4;8K8 4]Daw׎qs/q r5v X50ﭓ+=YAX K'kc88^_R=792@o'^YJ웡X=u:'m?curm㌎7yaM}c%U)^/f usmIb9bQ;yMT,e~톸VU=>7MsNXOsҴ"kvysc`\&D  D Ғ4tUX5дtIm QhɐVl/C}Pq|aS&<&2^7@r'GB-2rڸE+̥R ށaNm1y uM=B!ܵj#H؊I E+EyeqDMT!GߞkQZ8ʽq)Wy)*;ݰ$M7 Q{My7tgp8r;#-!JTYnP&^KqFkIJ FPkZXԾ"| T6g1B%6ƨ,#Uiʼ!feڳ-c`I6'8Kāv& 1@0\L H%Խ\ڙ"Vn`7`Bc[ѬfE}vX=+Rok}R}V۹yl"s/R= =Q^quv6+x%5ԏi-NH@C m s,*K?3хS)!4eTv㜀Z;RҦ>̹͐ [ rT3&BKF}dJ 27b~M}Z4ulx\d6Sd Q360o6DKB^X8- .IaDz lo,Aj3*9Z,Ln>J3ێF~W>|0sPI(ӄ<~t`tiP%e3i Z[T[Szvh~SQyܸ28=V\3ʺ0^jl[¼÷ƷO;FLXs5$u!ֹDcɺ6WLʽ[58DQ2۠:w,OQha)b?6mZ&Źt~R*a3rLEћu9Df<Ԃ=]K=m7ZoX6k\uHj#vB[q 16kfښe+eC7K(45XGrb帮KiUT$X(¤l;a{ 8եia%0|%ib #tzo4b +`GlpM`f5N.{5F= o6LpKl/RakF[T.=捩nm4 u|M)ڶ&e$رU]ۼ+/~ݱ.zф(c}܆ic$E)vڐ pfj&1e:4ܑ, s)~"f֍PK0. gv*kVqP_vG,)@XxI@HdTadx'vɘ;rU`Z*G n2*"0vd2I3vS%37O7ˍ4AlTEᅼDSg䘖 'V޿7V Ph)ш;PO̵.V&V4 5EM4rA9XdX5)_A 1YGz*6Ԕ4!V_ `&lrUVʳаY;sQKV9 ~(f DːMi1ǪCwqq$j#2+WT5{ B+ůQs@.&4ߏ_3thuuׄ$i&'-/Ly̻U\~&S#Mb`qpLaUa51Sqa~Rq\nn\=Tm~\{y-c/D?;cxi%sҶ$& ҚK̽ )k|P3cCl˕d!HߤdnDF^Lh1!b=dB?Xs;FhO qz~/L>[:2nd -a45lη>H~Yiuü6jڪ8BGMų;@HyHxaSR߲;ur9vh^l@7Frpk&*zE;/Kd.zȋrB>q9TTFCtDǀǂDg*ǹ`>E f䮌.Ч™l׵Wӷ#x/eP`qP;U_dJ;ha;8Y1P"cAJANNGN]36">7ŒsLVDE$V >i7N-޾ 4|Lq;oכv4#kZqi_JEjh!]X/2W%qDG[Y^ـ? \+`Ę_ZV`}'D1ŷ2Gt"B, LZ{#fGf\cU;OuP+k0OHNV0GO(+@ h䊍/b] aۚ84.|2h+lq{SJ=Z]6s9[}ϟ.۔9@ XcrH/:2R;VUe*-2ܞzqoŒ=Qii~xDχ.q6>ִ$(1&{؜c9Pv췷=xtm0Vٷfi;P޸\bS`\CRu3Ey\c,f|ہxO;Nw #5:a`fU, \q0Wƨ+NLV4#+dh?qm3k踒h[Z'2ݪXM:z{#WarFގX_#0J<~/ݨ IDATlkX*b nO Z4ι0MyZŸ?y[B}xrqa:#k]YuX&H vysb^MH44MF&E+~IJ0 ځJ /\katNk9wN|͈;@~ Xw R\߁bf4}GK@3e nm2b-Tp1}SXUg ['P,i&=Z21bï9Dy:ǟ.~iE>P̾M.D/ݴD7t7rsj=#r@#q žVcІ&C)F.,(H 6[7#ȸ't YA ĠaFuiu||KsGh -wdg.Ӗ.B_)^kg0fX-gcY`Y^ٔ^y.M9sݖ@jJ0RTgkC*ļLj6nAR#$h4*SwN?˜Y*/^JvJ$t^XOP nyՊ(s Ʀ>^&2؈$( SrSP 0僉68n Bw4uF]!.S-6!Y뻡.:w3𵖟5iJN.7 Iq3X cMgjyl^57m34d`ߨ.u܅EsoX#hn*ƺWtIɉМ4 1wV.sah_ D.`7ZK${t͠n)ԘW{`Tְ={LY`oZXshTܜXl JF |2jscw2&,C KS,|zlojZ ahMBw8Y1EUX^q]9)*DʥzpUQkۻM8Oe:( VS}:_5k9%S\K?v?LCTG%ngeqbo= 5b;0äXݶ4]|[oZT b1"F/ŝh{؉u27|?+5Ro.ڒ+B`Z0$Q>Bbޝ@7ڬ2ϿL6T[r锊w[o+8}N6(8^pKo8ad;>1yԢ\ժ&ށxy9QFi;0|hc&m =17.1Tģ8Y9юVTj)9U\D5DW m]M+8#8wc Z ;07>뗎?CjQ0hiOjn6̟{CzPUI%@54o佺Q g\:`} qI];ƭI0gU\, zMoAbOsJdƏ!>GKFy7E/P+"{Xsw-C=eseØh6/@fnxߘc/`Mt7 E)Z Mj^Tci4itU\ak"]0٣漸ZR"q yɱjz3XcYku3Ѓ^T ?D(^(P}h2I9IyY{;u%YݭbYK &ԹB,l}ΪcgiZR$XH[9 V@tTkKٯP gb!+>%:rXBڙJ.990WSz@ ެ\' 5](%00iaCM15T;}j_ys{T@Gyg 0Υ;V=y#V \D TJV]MԽno=B]Pޮ:fixQIi$PBwE)KUY,2/?nTMs:xlCujvTwznҶA8[z:ʰȭۊ)wʚA)Yp.'< ryFRҲE)M0y#Kw(yuZ>z\,Ԡ$SoȒ }WN&Z#7~#;NO{H=n{ZoNXߒһ\ is[e4 u44X:z#yccM$6@Jt Dl) o o 57L)8:Ƽp؉k3 `z9)RK"HsD v) JylCZ)aќw(c^c9dQbKݥ_:7;u]Tlzr^/E]A "ܡ}@Zh{g`? 1 3>72PQtk,$ʞK=/۾aجXM, x^9#1=-/EwIENDB`chessx-1.0.0/src/gui/engineoptionlist.h000644 001750 001750 00000002636 12223260306 020732 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef ENGINEOPTIONLIST_H #define ENGINEOPTIONLIST_H #include "engineoptionmodel.h" #include "engineoptiondata.h" #include "tableview.h" #include #include class EngineOptionListDelegate : public QStyledItemDelegate { Q_OBJECT public: EngineOptionListDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent), m_model(0) {} QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; void setModel(EngineOptionModel* model) { m_model = model; } private slots: void commitAndCloseEditor(); protected: EngineOptionModel* m_model; }; class EngineOptionList : public QTableView { Q_OBJECT public: explicit EngineOptionList(QWidget *parent = 0); void setDB(const QList& options, OptionValueList& mapOptionValues); void resetModel(); protected: EngineOptionModel* m_model; }; #endif // ENGINEOPTIONLIST_H chessx-1.0.0/src/database/engine.cpp000644 001750 001750 00000013057 12223260306 020117 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 William Hoggarth * * (C) 2008-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "settings.h" #include "engine.h" #include "wbengine.h" #include "uciengine.h" /*** Engine ***/ Engine::Engine(const QString& name, const QString& command, bool bTestMode, const QString& directory, QTextStream* logStream) { m_name = name; m_command = command; m_bTestMode = bTestMode; m_logStream = logStream; m_process = 0; m_active = false; m_analyzing = false; m_directory = directory; } Engine* Engine::newEngine(int index) { return newEngine(index, false); } Engine* Engine::newEngine(EngineList& engineList, int index, bool bTestMode) { Engine *engine = 0; QString name = engineList[index].name; QString command = engineList[index].command; QString options = engineList[index].options; QString directory = engineList[index].directory; EngineData::EngineProtocol protocol = engineList[index].protocol; if(command.contains(' ')) { command = QString("\"%1\"").arg(command); } QString exe = QString("%1 %2").arg(command).arg(options); if(protocol == EngineData::WinBoard) { engine = new WBEngine(name, exe, bTestMode, directory); } else { engine = new UCIEngine(name, exe, bTestMode, directory); } engine->m_mapOptionValues = engineList[index].m_optionValues; return engine; } Engine* Engine::newEngine(int index, bool bTestMode) { Engine *engine = 0; AppSettings->beginGroup("/Engines/"); QString key(QString::number(index)); QString name = AppSettings->value(key + "/Name").toString(); QString command = AppSettings->value(key + "/Command").toString(); QString options = AppSettings->value(key + "/Options").toString(); QString directory = AppSettings->value(key + "/Directory").toString(); QString protocol = AppSettings->value(key + "/Protocol").toString(); if(command.contains(' ')) { command = QString("\"%1\"").arg(command); } QString exe = QString("%1 %2").arg(command).arg(options); if(protocol == "WinBoard") { engine = new WBEngine(name, exe, bTestMode, directory); } else { engine = new UCIEngine(name, exe, bTestMode, directory); } AppSettings->getMap(key + "/OptionValues", engine->m_mapOptionValues); AppSettings->endGroup(); return engine; } Engine::~Engine() { if(m_process) { m_process = 0; } } void Engine::setLogStream(QTextStream* logStream) { m_logStream = logStream; } void Engine::activate() { if(m_process) { return; } m_process = new QProcess(this); if(m_process) { m_process->setReadChannel(QProcess::StandardOutput); if(!m_directory.isEmpty()) { m_process->setWorkingDirectory(m_directory); } connect(m_process, SIGNAL(started()), SLOT(protocolStart())); connect(m_process, SIGNAL(error(QProcess::ProcessError)), SLOT(processError(QProcess::ProcessError))); connect(m_process, SIGNAL(readyReadStandardOutput()), SLOT(pollProcess())); connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processExited())); m_process->start(m_command); } } void Engine::deactivate() { if(m_active) { protocolEnd(); if(m_process) { m_process->waitForFinished(200); } } } bool Engine::isActive() { return m_active; } bool Engine::isAnalyzing() { return m_analyzing; } void Engine::send(const QString& message) { // qDebug() << "<-- " << message << endl; QString out(message); out.append('\n'); if(m_process && !message.isEmpty()) { m_process->write(out.toLatin1()); } } void Engine::setActive(bool active) { if(active && !m_active) { m_active = true; emit activated(); } else { if(!active && m_active) { setAnalyzing(false); m_active = false; emit deactivated(); } } } void Engine::setAnalyzing(bool analyzing) { if(analyzing) { m_analyzing = true; emit analysisStarted(); } else { if(!analyzing && m_analyzing) { m_analyzing = false; emit analysisStopped(); } } } void Engine::sendAnalysis(const Analysis& analysis) { emit analysisUpdated(analysis); } void Engine::setMpv(int mpv) { m_mpv = mpv; } void Engine::pollProcess() { QString message; while(m_process && m_process->canReadLine()) { message = m_process->readLine().simplified(); // qDebug() << "--> " << message << endl; processMessage(message); } } void Engine::processError(QProcess::ProcessError errMsg) { setActive(false); m_process = 0; emit error(errMsg); } void Engine::processExited() { setActive(false); m_process = 0; emit deactivated(); } chessx-1.0.0/src/database/tristatetree.h000644 001750 001750 00000005520 12223260306 021032 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 William Hoggarth * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __TRISTATETREE_H__ #define __TRISTATETREE_H__ #include "search.h" #include "query.h" /** @ingroup Search The TriStateTree class helps facilitate the efficient evaluation of queries. The tree is built from a query with each leaf node representing a search, all other nodes representing the search operators (and, or etc). Each node can be one of three states: Unknown, False, or True. As the result of a search for the a game is discovered, the state for the corresponding leaf node is set to true or false. After each update the tree is re-evaluated, returning a value of Uknown, False, or True. In some cases the value of the tree can be determined before all search results are known. Eg. if the query is A or B, then if A is true then we know the result is true without having to evaluate B. */ class TriStateTree { public: typedef enum { Unknown, False, True } State; /** Default constructor, creates an empty tree */ TriStateTree(); /** Constructs a tree from the given query */ TriStateTree(const Query& query); /** Copy constructor */ TriStateTree(const TriStateTree& tree); /** Assignment operator */ TriStateTree& operator=(const TriStateTree& tree); /** Destructor */ ~TriStateTree(); /** Returns the state of the tree */ State state() const; /** Returns the state of a leaf node */ State state(int leaf) const; /** Returns the number of leaf nodes */ int leafCount() const; /** Sets the state of a leaf node to true or false, the updated state of the tree is returned */ State setState(int leaf, bool state); /** Sets the state of a leaf node to unknown, false, or true. The updated state of the tree is returned */ State setState(int leaf, State state); /** Resets the status of all nodes to unknown */ void clear(); private: typedef struct node { State m_state; Search::Operator m_operator; node* m_parent; node* m_leftChild; node* m_rightChild; } Node; State update(Node* node); State m_state; int m_nodeCount; Node* m_nodes; int m_leafCount; Node** m_leafs; }; #endif chessx-1.0.0/src/gui/dockwidgetex.h000644 001750 001750 00000001207 12223260306 020012 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef DOCKWIDGETEX_H #define DOCKWIDGETEX_H #include class DockWidgetEx : public QDockWidget { Q_OBJECT public: explicit DockWidgetEx(const QString &title, QWidget *parent = 0, Qt::WindowFlags flags = 0); explicit DockWidgetEx(QWidget *parent = 0, Qt::WindowFlags flags = 0); signals: public slots: protected: void showEvent(QShowEvent * event); }; #endif // DOCKWIDGETEX_H chessx-1.0.0/src/gui/tagdetailwidget.ui000644 001750 001750 00000004510 12203373343 020665 0ustar00niklasniklas000000 000000 TagDetailWidget 0 0 276 302 Form &Filter: filterEdit QAbstractItemView::NoEditTriggers true Selected Item Filter Rename TextBrowserEx QTextBrowser
textbrowserex.h
chessx-1.0.0/src/database/database.cpp000644 001750 001750 00000002156 12223260306 020414 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 William Hoggarth * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include #include #include #include "database.h" Database::Database() : m_break(false) { connect(&m_index, SIGNAL(progress(int)), this, SIGNAL(progress(int))); } Database::~Database() { } Index* Database::index() { return &m_index; } const Index* Database::index() const { return &m_index; } QString Database::name() const { QFileInfo fi(filename()); return fi.completeBaseName(); } chessx-1.0.0/src/gui/databaselistmodel.cpp000644 001750 001750 00000031672 12223260306 021356 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "databaselistmodel.h" #include #include #include #include DatabaseListModel::DatabaseListModel(QObject *parent) : QAbstractItemModel(parent) { m_columnNames << tr("Favorite") << tr("Name") << tr("Size") << tr("Open") << tr("Path") << tr("Format") << tr("Date"); } QModelIndex DatabaseListModel::index(int row, int column, const QModelIndex &parent) const { if(parent.isValid()) { return QModelIndex(); } return createIndex(row, column, (void*)0); } QModelIndex DatabaseListModel::parent(const QModelIndex &) const { return QModelIndex(); } int DatabaseListModel::rowCount(const QModelIndex &parent) const { if(parent.isValid()) { return 0; } return m_databases.count(); } int DatabaseListModel::columnCount(const QModelIndex &) const { return m_columnNames.count(); } bool DatabaseListModel::hasChildren(const QModelIndex &parent) const { return !parent.isValid(); } QVariant DatabaseListModel::data(const QModelIndex &index, int role) const { if(index.isValid()) { if(role == Qt::DecorationRole) { switch(index.column()) { case DBLV_FAVORITE: { bool bIsFavorite = m_databases.at(index.row()).m_isFavorite; return QPixmap(bIsFavorite ? ":/folder_favorite.png" : ":/folder_grey.png"); } case DBLV_OPEN: { bool bIsOpen = m_databases.at(index.row()).m_state == EDBL_OPEN; bool bIsCurrent = m_databases.at(index.row()).m_isCurrent; if(bIsOpen) { return QPixmap(bIsCurrent ? ":/folder_new.png" : ":/fileopen.png"); } else { return QVariant(); } } default: return QVariant(); } } else if(role == Qt::DisplayRole) { switch(index.column()) { case DBLV_FAVORITE: return QVariant(); case DBLV_NAME: { QString s = m_databases.at(index.row()).m_name; if(s.isEmpty()) { return tr("Clipboard"); } return s; } case DBLV_SIZE: { QStringList sizes; sizes << "" << "k" << "M" << "G" << "T" << "P"; QFileInfo f(m_databases.at(index.row()).m_path); int i = 0; qint64 size = f.size(); while((size >= 1024) && (i < sizes.count())) { size /= 1024; i++; } return QString("%1%2").arg(size).arg(sizes[i]); } case DBLV_DATE: { QFileInfo f(m_databases.at(index.row()).m_path); return f.lastModified().date(); } case DBLV_OPEN: return QVariant(); case DBLV_PATH: return m_databases.at(index.row()).m_path; case DBLV_UTF8: return m_databases.at(index.row()).m_utf8 ? "UTF8" : "ANSI"; default: break; } } else if(role == Qt::FontRole) { if(m_databases.at(index.row()).m_isCurrent) { if((index.column() == DBLV_NAME) || (index.column() == DBLV_PATH)) { QFont boldFont; boldFont.setBold(true); return boldFont; } } } else if(role == Qt::ToolTipRole) { switch(index.column()) { case DBLV_FAVORITE: { bool bIsFavorite = m_databases.at(index.row()).m_isFavorite; bool bIsClipBoard = m_databases.at(index.row()).m_name.isEmpty(); return QString(bIsFavorite ? tr("Favorite") : bIsClipBoard ? tr("Clipboard") : ""); } case DBLV_PATH: { QString s = m_databases.at(index.row()).m_name; return s; } case DBLV_OPEN: { bool bIsOpen = m_databases.at(index.row()).m_state == EDBL_OPEN; return QString(bIsOpen ? tr("Open") : tr("Closed")); } case DBLV_UTF8: { return m_databases.at(index.row()).m_utf8 ? "UTF8" : "ANSI"; } case DBLV_NAME: { QString s = m_databases.at(index.row()).m_name; if(s.isEmpty()) { return tr("Clipboard"); } s[0] = s[0].toUpper(); return s; } case DBLV_DATE: { QFileInfo f(m_databases.at(index.row()).m_path); return f.lastModified(); } case DBLV_SIZE: { QStringList sizes; sizes << "" << "k" << "M" << "G" << "T" << "P"; QFileInfo f(m_databases.at(index.row()).m_path); int i = 0; qint64 size = f.size(); while((size >= 1024) && (i < sizes.count())) { size /= 1024; i++; } return QString("%1%2").arg(size).arg(sizes[i]); } default: break; } } else if(role == Qt::UserRole) { switch(index.column()) { case DBLV_FAVORITE: { bool bIsFavorite = m_databases.at(index.row()).m_isFavorite; bool bIsClipBoard = m_databases.at(index.row()).m_name.isEmpty(); return QString(bIsFavorite ? "Favorite" : bIsClipBoard ? "Clipboard" : ""); } case DBLV_PATH: { QString s = m_databases.at(index.row()).m_name; return s; } case DBLV_OPEN: { bool bIsOpen = m_databases.at(index.row()).m_state == EDBL_OPEN; return QString(bIsOpen ? "Open" : "Closed"); } case DBLV_UTF8: { return m_databases.at(index.row()).m_utf8 ? "UTF8" : "ANSI"; } case DBLV_NAME: { QString s = m_databases.at(index.row()).m_name; if(s.isEmpty()) { return "Clipboard"; } s[0] = s[0].toUpper(); return s; } case DBLV_DATE: { QFileInfo f(m_databases.at(index.row()).m_path); return f.lastModified(); } case DBLV_SIZE: { QFileInfo f(m_databases.at(index.row()).m_path); qint64 size = f.size(); return size; } default: break; } } } return QVariant(); } QVariant DatabaseListModel::headerData(int section, Qt::Orientation orientation, int role) const { if(role != Qt::DisplayRole) { return QVariant(); } if(orientation == Qt::Horizontal) { return QString("%1").arg(m_columnNames.at(section)); } else { return QString("%1").arg(section); } } Qt::ItemFlags DatabaseListModel::flags(const QModelIndex &index) const { Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index); if(index.isValid()) { return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags | Qt::ItemIsSelectable; } else { return Qt::ItemIsDropEnabled | defaultFlags | Qt::ItemIsSelectable; } } DatabaseListEntry* DatabaseListModel::FindEntry(QString s) { QMutableListIterator i(m_databases); DatabaseListEntry d; d.m_path = s; if(i.findNext(d)) { return &(i.previous()); } return 0; } void DatabaseListModel::addEntry(DatabaseListEntry& d, const QString& s) { beginInsertRows(QModelIndex(), m_databases.count(), m_databases.count()); d.m_name = QFileInfo(s).fileName(); m_databases.push_back(d); endInsertRows(); } int DatabaseListModel::getLastIndex(const QString& s) const { QListIterator i(m_databases); DatabaseListEntry d; d.m_path = s; if(i.findNext(d)) { const DatabaseListEntry& e = i.previous(); return e.m_lastGameIndex; } return 0; } void DatabaseListModel::addFileOpen(const QString& s, bool utf8) { QMutableListIterator i(m_databases); DatabaseListEntry d; d.m_path = s; if(i.findNext(d)) { DatabaseListEntry& e = i.previous(); e.m_utf8 = utf8; if(e.m_state != EDBL_OPEN) { e.m_state = EDBL_OPEN; QModelIndex m = createIndex(m_databases.indexOf(e), DBLV_OPEN, (void*) 0); emit QAbstractItemModel::dataChanged(m, m); m = createIndex(m_databases.indexOf(e), DBLV_UTF8, (void*) 0); emit QAbstractItemModel::dataChanged(m, m); } return; } d.m_utf8 = utf8; d.m_state = EDBL_OPEN; addEntry(d, s); } void DatabaseListModel::addFavoriteFile(const QString& s, bool bFavorite, int index) { QMutableListIterator i(m_databases); DatabaseListEntry d; d.m_path = s; if(i.findNext(d)) { DatabaseListEntry& e = i.previous(); if(e.m_isFavorite != bFavorite) { e.m_isFavorite = bFavorite; e.m_lastGameIndex = index; QModelIndex m = createIndex(m_databases.indexOf(e), DBLV_FAVORITE, (void*) 0); emit QAbstractItemModel::dataChanged(m, m); } return; } d.m_isFavorite = bFavorite; d.m_lastGameIndex = index; addEntry(d, s); } void DatabaseListModel::setFileClose(const QString& s, int lastIndex) { if(DatabaseListEntry* e = FindEntry(s)) { if(e->m_state == EDBL_OPEN) { e->m_state = EDBL_CLOSE; e->m_lastGameIndex = lastIndex; QModelIndex m = createIndex(m_databases.indexOf(*e), DBLV_OPEN, (void*) 0); emit QAbstractItemModel::dataChanged(m, m); } } } void DatabaseListModel::setFileUtf8(const QString& s, bool utf8) { if(DatabaseListEntry* e = FindEntry(s)) { if(e->m_utf8 != utf8) { e->m_utf8 = utf8; QModelIndex m = createIndex(m_databases.indexOf(*e), DBLV_UTF8, (void*) 0); emit QAbstractItemModel::dataChanged(m, m); } } } void DatabaseListModel::setFileCurrent(const QString& s) { for(int i = 0; i < m_databases.count(); ++i) { if(m_databases[i].m_isCurrent) { m_databases[i].m_isCurrent = false; QModelIndex m = createIndex(i, DBLV_NAME, (void*) 0); QModelIndex n = createIndex(i, DBLV_UTF8, (void*) 0); emit QAbstractItemModel::dataChanged(m, n); } } if(DatabaseListEntry* e = FindEntry(s)) { e->m_isCurrent = true; int index = m_databases.indexOf(*e); QModelIndex m = createIndex(index, DBLV_NAME, (void*) 0); QModelIndex n = createIndex(index, DBLV_UTF8, (void*) 0); emit QAbstractItemModel::dataChanged(m, n); emit OnSelectIndex(createIndex(index, DBLV_FAVORITE, (void*) 0)); } } void DatabaseListModel::update(const QString& s) { if(DatabaseListEntry* e = FindEntry(s)) { QModelIndex m = createIndex(m_databases.indexOf(*e), DBLV_NAME, (void*) 0); QModelIndex n = createIndex(m_databases.indexOf(*e), DBLV_UTF8, (void*) 0); emit QAbstractItemModel::dataChanged(m, n); } } void DatabaseListModel::toStringList(QStringList& list) { for(int i = 1; i < m_databases.count(); ++i) { if(m_databases[i].m_isFavorite) { list.append(m_databases[i].m_path); } } } void DatabaseListModel::toAttrStringList(QStringList& list) const { for(int i = 1; i < m_databases.count(); ++i) { if(m_databases[i].m_isFavorite) { if(m_databases[i].m_utf8) { list.append("utf8"); } else { list.append("ansi"); } } } } void DatabaseListModel::toIndexList(QList& list) const { for(int i = 1; i < m_databases.count(); ++i) { if(m_databases[i].m_isFavorite) { list.append(QVariant(m_databases[i].m_lastGameIndex)); } } } chessx-1.0.0/src/database/outputoptions.h000644 001750 001750 00000005310 12223260306 021264 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2006-2007 Marius Roets * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __OUTPUTOPTIONS_H__ #define __OUTPUTOPTIONS_H__ #include #include #include #include /** @ingroup Core The OutputOptions class manages options for @ref Output class. */ class OutputOptions { Q_DECLARE_TR_FUNCTIONS(OutputOptions) public : enum OutputOptionType { Boolean, String, Integer, Color }; OutputOptions(); bool createDefaultOptions(QString path); bool createOption(const QString& optionName, OutputOptionType optionType, const QString& allowValues, const QString& defaultValue, const QString& description); bool createOption(const QString& optionName, const QString& optionType, const QString& allowValues, const QString& defaultValue, const QString& description); bool createOption(const QString& optionName, bool bValue, const QString& description); bool createOption(const QString& optionName, const QString& allowValues, int iValue, const QString& description); bool createOption(const QString& optionName, const QString& color, const QString& description); /* Setting values */ bool setOption(const QString& optionString); bool setOption(const QString& optionName, const QString& optionValue); bool setOption(const QString& optionName, bool optionValue); bool setOption(const QString& optionName, int optionValue); /* Retrieving values */ int getOptionAsInt(const QString& optionName) const; QString getOptionAsString(const QString& optionName) const; bool getOptionAsBool(const QString& optionName); QString getOptionDescription(const QString& optionName); QStringList getOptionList(); private : QMap m_list; QMap m_type; QMap m_default; QMap m_allow; QMap m_description; bool validateValue(const QString& optionName, const QString& value); OutputOptionType optionString2Type(const QString& optionTypeStr); }; #endif // __OUTPUTOPTIONS_H__ chessx-1.0.0/src/gui/engineoptiondialog.cpp000644 001750 001750 00000003700 12223260306 021542 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include #include "engineoptiondialog.h" #include "ui_engineoptiondialog.h" #include "engine.h" #include "settings.h" EngineOptionDialog::EngineOptionDialog(QWidget *parent, EngineList& engineList, int index, Qt::WindowFlags f) : QDialog(parent, f), ui(new Ui::EngineOptionDialog) { ui->setupUi(this); QString t = windowTitle(); QString t1 = QString("%1 %2 (%3)"). arg(t). arg(engineList[index].name). arg(QString(engineList[index].protocol == EngineData::UCI ? "UCI" : "WinBoard")); setWindowTitle(t1); if(engineList[index].protocol == EngineData::UCI) { ui->tableView->setEditTriggers(QAbstractItemView::AllEditTriggers); } else { ui->resetButton->setEnabled(false); } m_index = index; m_engine = Engine::newEngine(engineList, index, true); m_engine->activate(); connect(m_engine, SIGNAL(activated()), SLOT(engineActivated())); connect(ui->resetButton, SIGNAL(clicked()), SLOT(optionReset())); } EngineOptionDialog::~EngineOptionDialog() { m_engine->deactivate(); disconnect(); delete m_engine; delete ui; } void EngineOptionDialog::accept() { QDialog::accept(); } void EngineOptionDialog::engineActivated() { ui->tableView->setDB(m_engine->m_options, m_engine->m_mapOptionValues); } OptionValueList EngineOptionDialog::GetResults() const { return (m_engine ? m_engine->m_mapOptionValues : QMap()); } void EngineOptionDialog::optionReset() { m_engine->m_mapOptionValues.clear(); ui->tableView->resetModel(); } chessx-1.0.0/src/gui/analysiswidget.cpp000644 001750 001750 00000016766 12223260306 020733 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2008-2010 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "settings.h" #include "analysis.h" #include "board.h" #include "analysiswidget.h" #include "enginelist.h" #include "messagedialog.h" AnalysisWidget::AnalysisWidget() : m_engine(0) { ui.setupUi(this); connect(ui.engineList, SIGNAL(activated(int)), SLOT(toggleAnalysis())); connect(ui.analyzeButton, SIGNAL(clicked(bool)), SLOT(toggleAnalysis())); connect(ui.variationText, SIGNAL(anchorClicked(QUrl)), SLOT(slotLinkClicked(QUrl))); connect(ui.vpcount, SIGNAL(valueChanged(int)), SLOT(slotMpvChanged(int))); ui.analyzeButton->setFixedHeight(ui.engineList->sizeHint().height()); m_tablebase = new Shredder; connect(m_tablebase, SIGNAL(bestMove(Move, int)), this, SLOT(showTablebaseMove(Move, int))); } AnalysisWidget::~AnalysisWidget() { stopEngine(); delete m_tablebase; } void AnalysisWidget::startEngine() { int index = ui.engineList->currentIndex(); stopEngine(); if(index != -1) { if(parentWidget() && !parentWidget()->isVisible()) { parentWidget()->show(); } ui.variationText->clear(); m_engine = Engine::newEngine(index); ui.vpcount->setEnabled(m_engine->providesMvp()); ui.label->setEnabled(m_engine->providesMvp()); if(!m_engine->providesMvp()) { ui.vpcount->setValue(1); } connect(m_engine, SIGNAL(activated()), SLOT(engineActivated())); connect(m_engine, SIGNAL(error(QProcess::ProcessError)), SLOT(engineError(QProcess::ProcessError))); connect(m_engine, SIGNAL(deactivated()), SLOT(engineDeactivated())); connect(m_engine, SIGNAL(analysisUpdated(const Analysis&)), SLOT(showAnalysis(const Analysis&))); m_engine->activate(); QString key = QString("/") + objectName() + "/Engine"; AppSettings->setValue(key, ui.engineList->itemText(index)); } } void AnalysisWidget::stopEngine() { engineDeactivated(); if(m_engine) { m_engine->deactivate(); m_engine->deleteLater(); m_engine = 0; } } void AnalysisWidget::slotVisibilityChanged(bool visible) { if(isEngineRunning() && !visible && !parentWidget()->isVisible()) { stopEngine(); } } bool AnalysisWidget::isEngineRunning() const { return m_engine && ui.analyzeButton->isChecked(); } void AnalysisWidget::engineActivated() { ui.analyzeButton->setChecked(true); ui.analyzeButton->setText(tr("Stop")); m_analyses.clear(); m_engine->startAnalysis(m_board, ui.vpcount->value()); } void AnalysisWidget::engineError(QProcess::ProcessError e) { MessageDialog::warning(tr("There was an error (%1) running engine %2.") .arg(e) .arg(ui.engineList->currentText())); stopEngine(); } void AnalysisWidget::engineDeactivated() { ui.analyzeButton->setChecked(false); ui.analyzeButton->setText(tr("Analyze")); } void AnalysisWidget::toggleAnalysis() { if(!isAnalysisEnabled()) { stopEngine(); } else { startEngine(); } } void AnalysisWidget::slotReconfigure() { QString oldEngineName = ui.engineList->currentText(); if(oldEngineName.isEmpty()) { QString key = QString("/") + objectName() + "/Engine"; oldEngineName = AppSettings->value(key).toString(); } EngineList enginesList; enginesList.restore(); QStringList names = enginesList.names(); ui.engineList->clear(); ui.engineList->insertItems(0, names); int index = names.indexOf(oldEngineName); if(index != -1) { ui.engineList->setCurrentIndex(index); } else { ui.engineList->setCurrentIndex(0); stopEngine(); } int fontSize = AppSettings->getValue("/General/ListFontSize").toInt(); QFont f = ui.variationText->font(); f.setPointSize(fontSize); setFont(f); ui.variationText->setFont(f); } void AnalysisWidget::showAnalysis(const Analysis& analysis) { int mpv = analysis.mpv() - 1; if(mpv < 0 || mpv > m_analyses.count() || mpv >= ui.vpcount->value()) { return; } else if(mpv == m_analyses.count()) { m_analyses.append(analysis); } else { m_analyses[mpv] = analysis; } updateAnalysis(); } void AnalysisWidget::setPosition(const Board& board) { if(m_board != board) { m_board = board; m_analyses.clear(); m_tablebase->abortLookup(); m_tablebaseEvaluation.clear(); if(AppSettings->getValue("/General/onlineTablebases").toBool()) { if(objectName() == "Analysis") { m_tablebase->getBestMove(m_board.toFen()); } } updateAnalysis(); if(m_engine && m_engine->isActive()) { m_engine->startAnalysis(m_board, ui.vpcount->value()); } } } void AnalysisWidget::slotLinkClicked(const QUrl& url) { int mpv = url.toString().toInt() - 1; if(mpv >= 0 && mpv < m_analyses.count()) { emit addVariation(m_analyses[mpv]); } else if(mpv == -1) { emit addVariation(m_tablebaseEvaluation); } else { mpv = (-mpv) - 2; if(mpv < m_analyses.count()) { emit addVariation(m_analyses[mpv].variation().at(0).toAlgebraic()); } } } void AnalysisWidget::slotMpvChanged(int mpv) { if(isEngineRunning()) { while(m_analyses.count() > mpv) { m_analyses.removeLast(); } m_engine->setMpv(mpv); } } bool AnalysisWidget::isAnalysisEnabled() const { if(!parentWidget()) { return false; } if(!parentWidget()->isVisible() || !ui.analyzeButton->isChecked()) { return false; } return true; } void AnalysisWidget::showTablebaseMove(Move move, int score) { QString result; if(score == 0) { result = tr("Draw"); } else if((score < 0) == (m_board.toMove() == Black)) { result = tr("White wins in %n moves", "", qAbs(score)); } else { result = tr("Black wins in %n moves", "", qAbs(score)); } Move move1 = m_board.prepareMove(move.from(), move.to()); if(move.isPromotion()) { move1.setPromoted(pieceType(move.promotedPiece())); } m_tablebaseEvaluation = QString("%1 - %2") .arg(m_board.moveToFullSan(move1)).arg(result); updateAnalysis(); } void AnalysisWidget::updateAnalysis() { QString text; foreach(Analysis a, m_analyses) text.append(a.toString(m_board) + "
"); if(!m_tablebaseEvaluation.isEmpty()) { text.append(tr("[+] Tablebase: ") + m_tablebaseEvaluation); } ui.variationText->setText(text); } Analysis AnalysisWidget::getMainLine() const { Analysis a; if(!m_analyses.isEmpty()) { a = m_analyses.first(); } return a; } chessx-1.0.0/src/quazip/quazipfile.h000644 001750 001750 00000046276 12223260306 020246 0ustar00niklasniklas000000 000000 #ifndef QUA_ZIPFILE_H #define QUA_ZIPFILE_H /* Copyright (C) 2005-2011 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. **/ #include #include "quazip_global.h" #include "quazip.h" #include "quazipnewinfo.h" class QuaZipFilePrivate; /// A file inside ZIP archive. /** \class QuaZipFile quazipfile.h * This is the most interesting class. Not only it provides C++ * interface to the ZIP/UNZIP package, but also integrates it with Qt by * subclassing QIODevice. This makes possible to access files inside ZIP * archive using QTextStream or QDataStream, for example. Actually, this * is the main purpose of the whole QuaZIP library. * * You can either use existing QuaZip instance to create instance of * this class or pass ZIP archive file name to this class, in which case * it will create internal QuaZip object. See constructors' descriptions * for details. Writing is only possible with the existing instance. * * Note that due to the underlying library's limitation it is not * possible to use multiple QuaZipFile instances to open several files * in the same archive at the same time. If you need to write to * multiple files in parallel, then you should write to temporary files * first, then pack them all at once when you have finished writing. If * you need to read multiple files inside the same archive in parallel, * you should extract them all into a temporary directory first. * * \section quazipfile-sequential Sequential or random-access? * * At the first thought, QuaZipFile has fixed size, the start and the * end and should be therefore considered random-access device. But * there is one major obstacle to making it random-access: ZIP/UNZIP API * does not support seek() operation and the only way to implement it is * through reopening the file and re-reading to the required position, * but this is prohibitively slow. * * Therefore, QuaZipFile is considered to be a sequential device. This * has advantage of availability of the ungetChar() operation (QIODevice * does not implement it properly for non-sequential devices unless they * support seek()). Disadvantage is a somewhat strange behaviour of the * size() and pos() functions. This should be kept in mind while using * this class. * **/ class QUAZIP_EXPORT QuaZipFile: public QIODevice { friend class QuaZipFilePrivate; Q_OBJECT private: QuaZipFilePrivate *p; // these are not supported nor implemented QuaZipFile(const QuaZipFile& that); QuaZipFile& operator=(const QuaZipFile& that); protected: /// Implementation of the QIODevice::readData(). qint64 readData(char *data, qint64 maxSize); /// Implementation of the QIODevice::writeData(). qint64 writeData(const char *data, qint64 maxSize); public: /// Constructs a QuaZipFile instance. /** You should use setZipName() and setFileName() or setZip() before * trying to call open() on the constructed object. **/ QuaZipFile(); /// Constructs a QuaZipFile instance. /** \a parent argument specifies this object's parent object. * * You should use setZipName() and setFileName() or setZip() before * trying to call open() on the constructed object. **/ QuaZipFile(QObject *parent); /// Constructs a QuaZipFile instance. /** \a parent argument specifies this object's parent object and \a * zipName specifies ZIP archive file name. * * You should use setFileName() before trying to call open() on the * constructed object. * * QuaZipFile constructed by this constructor can be used for read * only access. Use QuaZipFile(QuaZip*,QObject*) for writing. **/ QuaZipFile(const QString& zipName, QObject *parent = NULL); /// Constructs a QuaZipFile instance. /** \a parent argument specifies this object's parent object, \a * zipName specifies ZIP archive file name and \a fileName and \a cs * specify a name of the file to open inside archive. * * QuaZipFile constructed by this constructor can be used for read * only access. Use QuaZipFile(QuaZip*,QObject*) for writing. * * \sa QuaZip::setCurrentFile() **/ QuaZipFile(const QString& zipName, const QString& fileName, QuaZip::CaseSensitivity cs = QuaZip::csDefault, QObject *parent = NULL); /// Constructs a QuaZipFile instance. /** \a parent argument specifies this object's parent object. * * \a zip is the pointer to the existing QuaZip object. This * QuaZipFile object then can be used to read current file in the * \a zip or to write to the file inside it. * * \warning Using this constructor for reading current file can be * tricky. Let's take the following example: * \code * QuaZip zip("archive.zip"); * zip.open(QuaZip::mdUnzip); * zip.setCurrentFile("file-in-archive"); * QuaZipFile file(&zip); * file.open(QIODevice::ReadOnly); * // ok, now we can read from the file * file.read(somewhere, some); * zip.setCurrentFile("another-file-in-archive"); // oops... * QuaZipFile anotherFile(&zip); * anotherFile.open(QIODevice::ReadOnly); * anotherFile.read(somewhere, some); // this is still ok... * file.read(somewhere, some); // and this is NOT * \endcode * So, what exactly happens here? When we change current file in the * \c zip archive, \c file that references it becomes invalid * (actually, as far as I understand ZIP/UNZIP sources, it becomes * closed, but QuaZipFile has no means to detect it). * * Summary: do not close \c zip object or change its current file as * long as QuaZipFile is open. Even better - use another constructors * which create internal QuaZip instances, one per object, and * therefore do not cause unnecessary trouble. This constructor may * be useful, though, if you already have a QuaZip instance and do * not want to access several files at once. Good example: * \code * QuaZip zip("archive.zip"); * zip.open(QuaZip::mdUnzip); * // first, we need some information about archive itself * QByteArray comment=zip.getComment(); * // and now we are going to access files inside it * QuaZipFile file(&zip); * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { * file.open(QIODevice::ReadOnly); * // do something cool with file here * file.close(); // do not forget to close! * } * zip.close(); * \endcode **/ QuaZipFile(QuaZip *zip, QObject *parent = NULL); /// Destroys a QuaZipFile instance. /** Closes file if open, destructs internal QuaZip object (if it * exists and \em is internal, of course). **/ virtual ~QuaZipFile(); /// Returns the ZIP archive file name. /** If this object was created by passing QuaZip pointer to the * constructor, this function will return that QuaZip's file name * (or null string if that object does not have file name yet). * * Otherwise, returns associated ZIP archive file name or null * string if there are no name set yet. * * \sa setZipName() getFileName() **/ QString getZipName()const; /// Returns a pointer to the associated QuaZip object. /** Returns \c NULL if there is no associated QuaZip or it is * internal (so you will not mess with it). **/ QuaZip* getZip()const; /// Returns file name. /** This function returns file name you passed to this object either * by using * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*) * or by calling setFileName(). Real name of the file may differ in * case if you used case-insensitivity. * * Returns null string if there is no file name set yet. This is the * case when this QuaZipFile operates on the existing QuaZip object * (constructor QuaZipFile(QuaZip*,QObject*) or setZip() was used). * * \sa getActualFileName **/ QString getFileName() const; /// Returns case sensitivity of the file name. /** This function returns case sensitivity argument you passed to * this object either by using * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*) * or by calling setFileName(). * * Returns unpredictable value if getFileName() returns null string * (this is the case when you did not used setFileName() or * constructor above). * * \sa getFileName **/ QuaZip::CaseSensitivity getCaseSensitivity() const; /// Returns the actual file name in the archive. /** This is \em not a ZIP archive file name, but a name of file inside * archive. It is not necessary the same name that you have passed * to the * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*), * setFileName() or QuaZip::setCurrentFile() - this is the real file * name inside archive, so it may differ in case if the file name * search was case-insensitive. * * Equivalent to calling getCurrentFileName() on the associated * QuaZip object. Returns null string if there is no associated * QuaZip object or if it does not have a current file yet. And this * is the case if you called setFileName() but did not open the * file yet. So this is perfectly fine: * \code * QuaZipFile file("somezip.zip"); * file.setFileName("somefile"); * QString name=file.getName(); // name=="somefile" * QString actual=file.getActualFileName(); // actual is null string * file.open(QIODevice::ReadOnly); * QString actual=file.getActualFileName(); // actual can be "SoMeFiLe" on Windows * \endcode * * \sa getZipName(), getFileName(), QuaZip::CaseSensitivity **/ QString getActualFileName()const; /// Sets the ZIP archive file name. /** Automatically creates internal QuaZip object and destroys * previously created internal QuaZip object, if any. * * Will do nothing if this file is already open. You must close() it * first. **/ void setZipName(const QString& zipName); /// Returns \c true if the file was opened in raw mode. /** If the file is not open, the returned value is undefined. * * \sa open(OpenMode,int*,int*,bool,const char*) **/ bool isRaw() const; /// Binds to the existing QuaZip instance. /** This function destroys internal QuaZip object, if any, and makes * this QuaZipFile to use current file in the \a zip object for any * further operations. See QuaZipFile(QuaZip*,QObject*) for the * possible pitfalls. * * Will do nothing if the file is currently open. You must close() * it first. **/ void setZip(QuaZip *zip); /// Sets the file name. /** Will do nothing if at least one of the following conditions is * met: * - ZIP name has not been set yet (getZipName() returns null * string). * - This QuaZipFile is associated with external QuaZip. In this * case you should call that QuaZip's setCurrentFile() function * instead! * - File is already open so setting the name is meaningless. * * \sa QuaZip::setCurrentFile **/ void setFileName(const QString& fileName, QuaZip::CaseSensitivity cs = QuaZip::csDefault); /// Opens a file for reading. /** Returns \c true on success, \c false otherwise. * Call getZipError() to get error code. * * \note Since ZIP/UNZIP API provides buffered reading only, * QuaZipFile does not support unbuffered reading. So do not pass * QIODevice::Unbuffered flag in \a mode, or open will fail. **/ virtual bool open(OpenMode mode); /// Opens a file for reading. /** \overload * Argument \a password specifies a password to decrypt the file. If * it is NULL then this function behaves just like open(OpenMode). **/ inline bool open(OpenMode mode, const char *password) { return open(mode, NULL, NULL, false, password); } /// Opens a file for reading. /** \overload * Argument \a password specifies a password to decrypt the file. * * An integers pointed by \a method and \a level will receive codes * of the compression method and level used. See unzip.h. * * If raw is \c true then no decompression is performed. * * \a method should not be \c NULL. \a level can be \c NULL if you * don't want to know the compression level. **/ bool open(OpenMode mode, int *method, int *level, bool raw, const char *password = NULL); /// Opens a file for writing. /** \a info argument specifies information about file. It should at * least specify a correct file name. Also, it is a good idea to * specify correct timestamp (by default, current time will be * used). See QuaZipNewInfo. * * The \a password argument specifies the password for crypting. Pass NULL * if you don't need any crypting. The \a crc argument was supposed * to be used for crypting too, but then it turned out that it's * false information, so you need to set it to 0 unless you want to * use the raw mode (see below). * * Arguments \a method and \a level specify compression method and * level. The only method supported is Z_DEFLATED, but you may also * specify 0 for no compression. If all of the files in the archive * use both method 0 and either level 0 is explicitly specified or * data descriptor writing is disabled with * QuaZip::setDataDescriptorWritingEnabled(), then the * resulting archive is supposed to be compatible with the 1.0 ZIP * format version, should you need that. Except for this, \a level * has no other effects with method 0. * * If \a raw is \c true, no compression is performed. In this case, * \a crc and uncompressedSize field of the \a info are required. * * Arguments \a windowBits, \a memLevel, \a strategy provide zlib * algorithms tuning. See deflateInit2() in zlib. **/ bool open(OpenMode mode, const QuaZipNewInfo& info, const char *password = NULL, quint32 crc = 0, int method = Z_DEFLATED, int level = Z_DEFAULT_COMPRESSION, bool raw = false, int windowBits = -MAX_WBITS, int memLevel = DEF_MEM_LEVEL, int strategy = Z_DEFAULT_STRATEGY); /// Returns \c true, but \ref quazipfile-sequential "beware"! virtual bool isSequential()const; /// Returns current position in the file. /** Implementation of the QIODevice::pos(). When reading, this * function is a wrapper to the ZIP/UNZIP unztell(), therefore it is * unable to keep track of the ungetChar() calls (which is * non-virtual and therefore is dangerous to reimplement). So if you * are using ungetChar() feature of the QIODevice, this function * reports incorrect value until you get back characters which you * ungot. * * When writing, pos() returns number of bytes already written * (uncompressed unless you use raw mode). * * \note Although * \ref quazipfile-sequential "QuaZipFile is a sequential device" * and therefore pos() should always return zero, it does not, * because it would be misguiding. Keep this in mind. * * This function returns -1 if the file or archive is not open. * * Error code returned by getZipError() is not affected by this * function call. **/ virtual qint64 pos()const; /// Returns \c true if the end of file was reached. /** This function returns \c false in the case of error. This means * that you called this function on either not open file, or a file * in the not open archive or even on a QuaZipFile instance that * does not even have QuaZip instance associated. Do not do that * because there is no means to determine whether \c false is * returned because of error or because end of file was reached. * Well, on the other side you may interpret \c false return value * as "there is no file open to check for end of file and there is * no end of file therefore". * * When writing, this function always returns \c true (because you * are always writing to the end of file). * * Error code returned by getZipError() is not affected by this * function call. **/ virtual bool atEnd()const; /// Returns file size. /** This function returns csize() if the file is open for reading in * raw mode, usize() if it is open for reading in normal mode and * pos() if it is open for writing. * * Returns -1 on error, call getZipError() to get error code. * * \note This function returns file size despite that * \ref quazipfile-sequential "QuaZipFile is considered to be sequential device", * for which size() should return bytesAvailable() instead. But its * name would be very misguiding otherwise, so just keep in mind * this inconsistence. **/ virtual qint64 size()const; /// Returns compressed file size. /** Equivalent to calling getFileInfo() and then getting * compressedSize field, but more convenient and faster. * * File must be open for reading before calling this function. * * Returns -1 on error, call getZipError() to get error code. **/ qint64 csize()const; /// Returns uncompressed file size. /** Equivalent to calling getFileInfo() and then getting * uncompressedSize field, but more convenient and faster. See * getFileInfo() for a warning. * * File must be open for reading before calling this function. * * Returns -1 on error, call getZipError() to get error code. **/ qint64 usize()const; /// Gets information about current file. /** This function does the same thing as calling * QuaZip::getCurrentFileInfo() on the associated QuaZip object, * but you can not call getCurrentFileInfo() if the associated * QuaZip is internal (because you do not have access to it), while * you still can call this function in that case. * * File must be open for reading before calling this function. * * Returns \c false in the case of an error. **/ bool getFileInfo(QuaZipFileInfo *info); /// Closes the file. /** Call getZipError() to determine if the close was successful. **/ virtual void close(); /// Returns the error code returned by the last ZIP/UNZIP API call. int getZipError() const; /// Returns the number of bytes available for reading. virtual qint64 bytesAvailable() const; }; #endif chessx-1.0.0/src/database/settings.h000644 001750 001750 00000006161 12223260306 020155 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __SETTINGS_H__ #define __SETTINGS_H__ #include #include "engineoptiondata.h" class QWidget; /** @ingroup Core The Settings class provides a wrapper to Qt QSettings class. It allows to easily save/restore application settings and get paths for various resources. */ #ifdef Q_OS_MAC #define MIN_WHEEL_COUNT 120 #define DEFAULT_FONTSIZE 12 #define DEFAULT_LISTFONTSIZE 12 #else #define MIN_WHEEL_COUNT 0 #define DEFAULT_FONTSIZE 11 #define DEFAULT_LISTFONTSIZE 11 #endif class Settings : public QSettings { Q_OBJECT public: enum {Show = 1} LayoutFlags; Settings(); ~Settings(); /** Restore widget's layout based on its name. Optionally show window if it is visible. @return @p true if the state was restored. */ bool layout(QWidget* w); /** Write widget's layout with its name. */ void setLayout(const QWidget* w); /** @return directory where data are stored. */ QString dataPath(); /** @return directory where common chess data are stored. */ QString commonDataPath(); /** Write integer list to configuration file. Does it by converting it to QString */ void setList(const QString& key, QList list); void setList(const QString& key, QList list); /** Appends values to the list. @return @p true if the list contains exact number of items. If @p items is @p -1 , always return @p true. */ bool list(const QString& key, QList& list, int items = -1); bool list(const QString& key, QList& list, int items = -1); /// set a QByteArray into the settings void setByteArray(const QString& key, const QByteArray& arr); /// Read a QByteArray from the Settings QByteArray byteArray(const QString& key); /// Overloading value from QSettings with a single place where defaults come from QVariant getValue(const QString &key) const; void setMap(const QString& key, const OptionValueList& map); void getMap(const QString& key, OptionValueList& map); QString getUserDataPath() const; QString getTempPath() const; QString getThemaPath() const; QStringList getThemeList() const; QString getImagePath() const; QString getBoardPath() const; QStringList getBoardList() const; QString getBuiltinDbPath() const; QStringList getBuiltinDatabases() const; QStringList getTranslationPaths() const; QStringList getTranslations() const; private: QMap initDefaultValues() const; QString m_dataPath; }; extern Settings* AppSettings; #endif chessx-1.0.0/src/gui/ecolistwidget.h000644 001750 001750 00000002372 12223260306 020203 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef ECOLISTWIDGET_H #define ECOLISTWIDGET_H #include #include #include "ecoinfo.h" namespace Ui { class TagDetailWidget; } class DatabaseInfo; class ECOListWidget : public QWidget { Q_OBJECT public: explicit ECOListWidget(QWidget *parent = 0); ~ECOListWidget(); signals: void filterRequest(QString ts); void filterEcoPlayerRequest(QString tag, QString eco); void filterEcoPlayerRequest(QString tag, QString eco, QString player); void raiseRequest(); public slots: void findECO(const QString& s); void slotSelectECO(const QString& eco); void setDatabase(DatabaseInfo* dbInfo); void filterSelectedECO(); void slotReconfigure(); void selectionChangedSlot(); void slotLinkClicked(const QUrl& url); protected slots: void selectECO(const QString& eco); void ecoSelected(const QString& eco); private: EcoInfo m_eco; QStringList m_list; Ui::TagDetailWidget *ui; QStringListModel* m_filterModel; }; #endif // ECOLISTWIDGET_H chessx-1.0.0/src/quazip/quazip.cpp000644 001750 001750 00000040210 12223260306 017717 0ustar00niklasniklas000000 000000 /* Copyright (C) 2005-2011 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. **/ #include #include #include "quazip.h" /// All the internal stuff for the QuaZip class. /** \internal This class keeps all the private stuff for the QuaZip class so it can be changed without breaking binary compatibility, according to the Pimpl idiom. */ class QuaZipPrivate { friend class QuaZip; private: /// The pointer to the corresponding QuaZip instance. QuaZip *q; /// The codec for file names. QTextCodec *fileNameCodec; /// The codec for comments. QTextCodec *commentCodec; /// The archive file name. QString zipName; /// The device to access the archive. QIODevice *ioDevice; /// The global comment. QString comment; /// The open mode. QuaZip::Mode mode; union { /// The internal handle for UNZIP modes. unzFile unzFile_f; /// The internal handle for ZIP modes. zipFile zipFile_f; }; /// Whether a current file is set. bool hasCurrentFile_f; /// The last error. int zipError; /// Whether \ref QuaZip::setDataDescriptorWritingEnabled() "the data descriptor writing mode" is enabled. bool dataDescriptorWritingEnabled; /// The constructor for the corresponding QuaZip constructor. inline QuaZipPrivate(QuaZip *q): q(q), fileNameCodec(QTextCodec::codecForLocale()), commentCodec(QTextCodec::codecForLocale()), ioDevice(NULL), mode(QuaZip::mdNotOpen), hasCurrentFile_f(false), zipError(UNZ_OK), dataDescriptorWritingEnabled(true) {} /// The constructor for the corresponding QuaZip constructor. inline QuaZipPrivate(QuaZip *q, const QString &zipName): q(q), fileNameCodec(QTextCodec::codecForLocale()), commentCodec(QTextCodec::codecForLocale()), zipName(zipName), ioDevice(NULL), mode(QuaZip::mdNotOpen), hasCurrentFile_f(false), zipError(UNZ_OK), dataDescriptorWritingEnabled(true) {} /// The constructor for the corresponding QuaZip constructor. inline QuaZipPrivate(QuaZip *q, QIODevice *ioDevice): q(q), fileNameCodec(QTextCodec::codecForLocale()), commentCodec(QTextCodec::codecForLocale()), ioDevice(ioDevice), mode(QuaZip::mdNotOpen), hasCurrentFile_f(false), zipError(UNZ_OK), dataDescriptorWritingEnabled(true) {} /// Returns either a list of file names or a list of QuaZipFileInfo. template bool getFileInfoList(QList *result) const; }; QuaZip::QuaZip(): p(new QuaZipPrivate(this)) { } QuaZip::QuaZip(const QString& zipName): p(new QuaZipPrivate(this, zipName)) { } QuaZip::QuaZip(QIODevice *ioDevice): p(new QuaZipPrivate(this, ioDevice)) { } QuaZip::~QuaZip() { if(isOpen()) { close(); } delete p; } bool QuaZip::open(Mode mode, zlib_filefunc_def* ioApi) { p->zipError = UNZ_OK; if(isOpen()) { qWarning("QuaZip::open(): ZIP already opened"); return false; } QIODevice *ioDevice = p->ioDevice; if(ioDevice == NULL) { if(p->zipName.isEmpty()) { qWarning("QuaZip::open(): set either ZIP file name or IO device first"); return false; } else { ioDevice = new QFile(p->zipName); } } switch(mode) { case mdUnzip: p->unzFile_f = unzOpen2(ioDevice, ioApi); if(p->unzFile_f != NULL) { p->mode = mode; p->ioDevice = ioDevice; return true; } else { p->zipError = UNZ_OPENERROR; if(!p->zipName.isEmpty()) { delete ioDevice; } return false; } case mdCreate: case mdAppend: case mdAdd: p->zipFile_f = zipOpen2(ioDevice, mode == mdCreate ? APPEND_STATUS_CREATE : mode == mdAppend ? APPEND_STATUS_CREATEAFTER : APPEND_STATUS_ADDINZIP, NULL, ioApi); if(p->zipFile_f != NULL) { p->mode = mode; p->ioDevice = ioDevice; return true; } else { p->zipError = UNZ_OPENERROR; if(!p->zipName.isEmpty()) { delete ioDevice; } return false; } default: qWarning("QuaZip::open(): unknown mode: %d", (int)mode); if(!p->zipName.isEmpty()) { delete ioDevice; } return false; break; } } void QuaZip::close() { p->zipError = UNZ_OK; switch(p->mode) { case mdNotOpen: qWarning("QuaZip::close(): ZIP is not open"); return; case mdUnzip: p->zipError = unzClose(p->unzFile_f); break; case mdCreate: case mdAppend: case mdAdd: p->zipError = zipClose(p->zipFile_f, p->comment.isNull() ? NULL : p->commentCodec->fromUnicode(p->comment).constData()); break; default: qWarning("QuaZip::close(): unknown mode: %d", (int)p->mode); return; } // opened by name, need to delete the internal IO device if(!p->zipName.isEmpty()) { delete p->ioDevice; p->ioDevice = NULL; } if(p->zipError == UNZ_OK) { p->mode = mdNotOpen; } } void QuaZip::setZipName(const QString& zipName) { if(isOpen()) { qWarning("QuaZip::setZipName(): ZIP is already open!"); return; } p->zipName = zipName; p->ioDevice = NULL; } void QuaZip::setIoDevice(QIODevice *ioDevice) { if(isOpen()) { qWarning("QuaZip::setIoDevice(): ZIP is already open!"); return; } p->ioDevice = ioDevice; p->zipName = QString(); } int QuaZip::getEntriesCount()const { QuaZip *fakeThis = (QuaZip*)this; // non-const fakeThis->p->zipError = UNZ_OK; if(p->mode != mdUnzip) { qWarning("QuaZip::getEntriesCount(): ZIP is not open in mdUnzip mode"); return -1; } unz_global_info globalInfo; if((fakeThis->p->zipError = unzGetGlobalInfo(p->unzFile_f, &globalInfo)) != UNZ_OK) { return p->zipError; } return (int)globalInfo.number_entry; } QString QuaZip::getComment()const { QuaZip *fakeThis = (QuaZip*)this; // non-const fakeThis->p->zipError = UNZ_OK; if(p->mode != mdUnzip) { qWarning("QuaZip::getComment(): ZIP is not open in mdUnzip mode"); return QString(); } unz_global_info globalInfo; QByteArray comment; if((fakeThis->p->zipError = unzGetGlobalInfo(p->unzFile_f, &globalInfo)) != UNZ_OK) { return QString(); } comment.resize(globalInfo.size_comment); if((fakeThis->p->zipError = unzGetGlobalComment(p->unzFile_f, comment.data(), comment.size())) < 0) { return QString(); } fakeThis->p->zipError = UNZ_OK; return p->commentCodec->toUnicode(comment); } bool QuaZip::setCurrentFile(const QString& fileName, CaseSensitivity cs) { p->zipError = UNZ_OK; if(p->mode != mdUnzip) { qWarning("QuaZip::setCurrentFile(): ZIP is not open in mdUnzip mode"); return false; } if(fileName.isEmpty()) { p->hasCurrentFile_f = false; return true; } // Unicode-aware reimplementation of the unzLocateFile function if(p->unzFile_f == NULL) { p->zipError = UNZ_PARAMERROR; return false; } if(fileName.length() > MAX_FILE_NAME_LENGTH) { p->zipError = UNZ_PARAMERROR; return false; } bool sens = convertCaseSensitivity(cs) == Qt::CaseSensitive; QString lower, current; if(!sens) { lower = fileName.toLower(); } p->hasCurrentFile_f = false; for(bool more = goToFirstFile(); more; more = goToNextFile()) { current = getCurrentFileName(); if(current.isEmpty()) { return false; } if(sens) { if(current == fileName) { break; } } else { if(current.toLower() == lower) { break; } } } return p->hasCurrentFile_f; } bool QuaZip::goToFirstFile() { p->zipError = UNZ_OK; if(p->mode != mdUnzip) { qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode"); return false; } p->zipError = unzGoToFirstFile(p->unzFile_f); p->hasCurrentFile_f = p->zipError == UNZ_OK; return p->hasCurrentFile_f; } bool QuaZip::goToNextFile() { p->zipError = UNZ_OK; if(p->mode != mdUnzip) { qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode"); return false; } p->zipError = unzGoToNextFile(p->unzFile_f); p->hasCurrentFile_f = p->zipError == UNZ_OK; if(p->zipError == UNZ_END_OF_LIST_OF_FILE) { p->zipError = UNZ_OK; } return p->hasCurrentFile_f; } bool QuaZip::getCurrentFileInfo(QuaZipFileInfo *info)const { QuaZip *fakeThis = (QuaZip*)this; // non-const fakeThis->p->zipError = UNZ_OK; if(p->mode != mdUnzip) { qWarning("QuaZip::getCurrentFileInfo(): ZIP is not open in mdUnzip mode"); return false; } unz_file_info info_z; QByteArray fileName; QByteArray extra; QByteArray comment; if(info == NULL) { return false; } if(!isOpen() || !hasCurrentFile()) { return false; } if((fakeThis->p->zipError = unzGetCurrentFileInfo(p->unzFile_f, &info_z, NULL, 0, NULL, 0, NULL, 0)) != UNZ_OK) { return false; } fileName.resize(info_z.size_filename); extra.resize(info_z.size_file_extra); comment.resize(info_z.size_file_comment); if((fakeThis->p->zipError = unzGetCurrentFileInfo(p->unzFile_f, NULL, fileName.data(), fileName.size(), extra.data(), extra.size(), comment.data(), comment.size())) != UNZ_OK) { return false; } info->versionCreated = info_z.version; info->versionNeeded = info_z.version_needed; info->flags = info_z.flag; info->method = info_z.compression_method; info->crc = info_z.crc; info->compressedSize = info_z.compressed_size; info->uncompressedSize = info_z.uncompressed_size; info->diskNumberStart = info_z.disk_num_start; info->internalAttr = info_z.internal_fa; info->externalAttr = info_z.external_fa; info->name = p->fileNameCodec->toUnicode(fileName); info->comment = p->commentCodec->toUnicode(comment); info->extra = extra; info->dateTime = QDateTime( QDate(info_z.tmu_date.tm_year, info_z.tmu_date.tm_mon + 1, info_z.tmu_date.tm_mday), QTime(info_z.tmu_date.tm_hour, info_z.tmu_date.tm_min, info_z.tmu_date.tm_sec)); return true; } QString QuaZip::getCurrentFileName()const { QuaZip *fakeThis = (QuaZip*)this; // non-const fakeThis->p->zipError = UNZ_OK; if(p->mode != mdUnzip) { qWarning("QuaZip::getCurrentFileName(): ZIP is not open in mdUnzip mode"); return QString(); } if(!isOpen() || !hasCurrentFile()) { return QString(); } QByteArray fileName(MAX_FILE_NAME_LENGTH, 0); if((fakeThis->p->zipError = unzGetCurrentFileInfo(p->unzFile_f, NULL, fileName.data(), fileName.size(), NULL, 0, NULL, 0)) != UNZ_OK) { return QString(); } return p->fileNameCodec->toUnicode(fileName.constData()); } void QuaZip::setFileNameCodec(QTextCodec *fileNameCodec) { p->fileNameCodec = fileNameCodec; } void QuaZip::setFileNameCodec(const char *fileNameCodecName) { p->fileNameCodec = QTextCodec::codecForName(fileNameCodecName); } QTextCodec *QuaZip::getFileNameCodec()const { return p->fileNameCodec; } void QuaZip::setCommentCodec(QTextCodec *commentCodec) { p->commentCodec = commentCodec; } void QuaZip::setCommentCodec(const char *commentCodecName) { p->commentCodec = QTextCodec::codecForName(commentCodecName); } QTextCodec *QuaZip::getCommentCodec()const { return p->commentCodec; } QString QuaZip::getZipName() const { return p->zipName; } QIODevice *QuaZip::getIoDevice() const { if(!p->zipName.isEmpty()) // opened by name, using an internal QIODevice { return NULL; } return p->ioDevice; } QuaZip::Mode QuaZip::getMode()const { return p->mode; } bool QuaZip::isOpen()const { return p->mode != mdNotOpen; } int QuaZip::getZipError() const { return p->zipError; } void QuaZip::setComment(const QString& comment) { p->comment = comment; } bool QuaZip::hasCurrentFile()const { return p->hasCurrentFile_f; } unzFile QuaZip::getUnzFile() { return p->unzFile_f; } zipFile QuaZip::getZipFile() { return p->zipFile_f; } void QuaZip::setDataDescriptorWritingEnabled(bool enabled) { p->dataDescriptorWritingEnabled = enabled; } bool QuaZip::isDataDescriptorWritingEnabled() const { return p->dataDescriptorWritingEnabled; } template TFileInfo QuaZip_getFileInfo(QuaZip *zip, bool *ok); template<> QuaZipFileInfo QuaZip_getFileInfo(QuaZip *zip, bool *ok) { QuaZipFileInfo info; *ok = zip->getCurrentFileInfo(&info); return info; } template<> QString QuaZip_getFileInfo(QuaZip *zip, bool *ok) { QString name = zip->getCurrentFileName(); *ok = !name.isEmpty(); return name; } template bool QuaZipPrivate::getFileInfoList(QList *result) const { QuaZipPrivate *fakeThis = const_cast(this); fakeThis->zipError = UNZ_OK; if(mode != QuaZip::mdUnzip) { qWarning("QuaZip::getFileNameList/getFileInfoList(): " "ZIP is not open in mdUnzip mode"); return false; } QString currentFile; if(q->hasCurrentFile()) { currentFile = q->getCurrentFileName(); } if(q->goToFirstFile()) { do { bool ok; result->append(QuaZip_getFileInfo(q, &ok)); if(!ok) { return false; } } while(q->goToNextFile()); } if(zipError != UNZ_OK) { return false; } if(currentFile.isEmpty()) { if(!q->goToFirstFile()) { return false; } } else { if(!q->setCurrentFile(currentFile)) { return false; } } return true; } QStringList QuaZip::getFileNameList() const { QStringList list; if(p->getFileInfoList(&list)) { return list; } else { return QStringList(); } } QList QuaZip::getFileInfoList() const { QList list; if(p->getFileInfoList(&list)) { return list; } else { return QList(); } } Qt::CaseSensitivity QuaZip::convertCaseSensitivity(QuaZip::CaseSensitivity cs) { if(cs == csDefault) { #ifdef Q_WS_WIN return Qt::CaseInsensitive; #else return Qt::CaseSensitive; #endif } else { return cs == csSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; } } chessx-1.0.0/data/images/go_up_black.png000644 001750 001750 00000012475 12155032667 020762 0ustar00niklasniklas000000 000000 PNG  IHDR88; CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs11(RtIMEl {IDATh{pU?{ν!A" FET@l\KP\mJt\AD5z5=9>[`ׇp( `iMp0͏ٌKj̹L~kFV,? Z|=Ow\O acdJ@*:PQl>\ FZ3M6wɴ\Z0ld=B`ד1{٠ BP 'Сe {ka8,~\LUzGTEɤy;v?A 4wA uP\% )d H8Oގ=PQGG^>=gN`dH jJvmSέiGJҰbC^poq7W0z8Vi=`1R6>ގK:(,_zrA&qO&lXP*8Kݔ /)6o*Ln6Fk7um)q4< ?-0SHt2^t{ɏMe͔&Y7z)/3&5$-ǜL(' F? MP4PJh:u> L PEBp%$ƖCPN$Q-Jd++'$#ݑvi2 hNZU E"P% |v&'V-&LxpH&36#vWS`@9s!3SM)yeq?(]g #-;`tzʇ 0*vEtW#:am!P6n\ˆPXlvRt:BލrIw.lVح,>}rE eDDup`+|Ns dxy7/$x4(zꤊu~,`YRl*0"(/cqp|I+IBΣBaLdU7 >Z51 %!qE j!~\pb2'v}dYԮ;JyWgOP:nʂ!.Ջ_؃Lw-Gc%œl '398 F.h!ݍfU9;B" 4^nDЉ! Ot ve],ۡ䨝Xtkt ڳt` z۸6Jp_]~u}F^;rFm8V2`AbfIQDΏDۦ%tmI!dIN"r n ұ* k^ ?l09kPWY VmP_1hm%zoZ/0kmr#abĒO6E2t+`X}ND`m02 kMYèk. >ߏ~ zjU̶,Au40W#,}ǣ{'H7V3c7to^`%2X` ~j&"(dBl'I=~yt6P̴'2oQ.Y0y򼢵; P\wD19mN6?Y-0(c řR9e}Fw'P6ʹ߷N\Jҩ}0i 0; i--) { Moves[i] = Moves[i - 1]; } Moves[0] = smTemp; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MoveList::SwapWithFirst // Swaps the specified move with the move at the start of the list. // All other moves remain in their original location. void MoveList::SwapWithFirst(unsigned int index) { ASSERT(index < ListSize); if(index == 0) { return; } simpleMoveT smTemp = Moves[index]; Moves[index] = Moves[0]; Moves[0] = smTemp; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MoveList::Find // Searches for a move in the list. // Returns the index of the move with the same from-square, // to-square and promotion-piece values as the specified // move, if it is in the list. If the move is not found, // the value -1 is returned. int MoveList::Find(simpleMoveT * sm) { for(unsigned int i = 0; i < ListSize; ++i) { simpleMoveT * lsm = &(Moves[i]); if(sm->from == lsm->from && sm->to == lsm->to && sm->promote == lsm->promote) { return (int) i; } } return -1; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MoveList::SelectBySquares // Restricts the list to only contain only the two // moves suggested by (from1,to1) and (from2,to2) // Returns the new size of the list. unsigned int MoveList::SelectBySquares(squareT f1, squareT t1, squareT f2, squareT t2) { unsigned int index = 0; for(unsigned int i = 0; i < ListSize; ++i) { simpleMoveT * sm = &(Moves[i]); if((sm->from == f1 && sm->to == t1) || (sm->from == f2 && sm->to == t2)) { if(i != index) { Moves[index] = *sm; } index++; } } ListSize = index; return ListSize; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MoveList::SelectBySquare // Restricts the list to only contain moves which // move a piece to or from the specified square. // Returns the new size of the list. unsigned int MoveList::SelectBySquare(squareT sq) { unsigned int index = 0; for(unsigned int i = 0; i < ListSize; i++) { simpleMoveT * sm = &(Moves[i]); if(sm->from != sq && sm->to != sq) { // Skip this move, it does not match. continue; } // Copy this move to an earlier index if necesary: if(i != index) { Moves[index] = *sm; } ++index; } ListSize = index; return ListSize; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MoveList::FindBest // Searches the move list from the specified index to the end of // the list to find the move in that range of the list with the // highest score, and swaps the best move found with the move at // the specified index if it is not already there. // The moves earlier in the list (at indices 0 to index-1) are // ignored and are not moved. void MoveList::FindBest(unsigned int index) { ASSERT(index < ListSize); unsigned int bestIndex = index; int bestScore = Moves[index].score; // Search the rest of the list for a better-scoring move: for(unsigned int i = index + 1; i < ListSize; ++i) { if(Moves[i].score > bestScore) { bestIndex = i; bestScore = Moves[i].score; } } // Swap if necessary: if(index != bestIndex) { simpleMoveT smTemp = Moves[index]; Moves[index] = Moves[bestIndex]; Moves[bestIndex] = smTemp; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MoveList::Sort // Sort the move list by the score field in descending order, // with highest scores first. void MoveList::Sort(void) { // Do a simple selection sort, which works fine for small list sizes. for(unsigned int i = 0; i < ListSize; ++i) { FindBest(i); } } bool MoveList::IsSorted(void) { if(ListSize < 2) { return true; } for(unsigned int i = 0; i < ListSize - 1; ++i) { if(Moves[i].score < Moves[i + 1].score) { return false; } } return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // writeSimpleMove, readSimpleMove: // I/O for simpleMoveT structs. // errorT writeSimpleMove(FILE * fp, simpleMoveT * sm) { errorT err; writeOneByte(fp, sm->pieceNum); writeOneByte(fp, sm->movingPiece); writeOneByte(fp, sm->from); writeOneByte(fp, sm->to); writeOneByte(fp, sm->capturedNum); writeOneByte(fp, sm->capturedPiece); writeOneByte(fp, sm->promote); writeOneByte(fp, 0); // Obsolete unused value writeOneByte(fp, sm->capturedSquare); writeOneByte(fp, sm->castleFlags); writeOneByte(fp, sm->epSquare); err = writeTwoBytes(fp, sm->oldHalfMoveClock); return err; } errorT readSimpleMove(FILE * fp, simpleMoveT * sm) { sm->pieceNum = readOneByte(fp); sm->movingPiece = readOneByte(fp); sm->from = readOneByte(fp); sm->to = readOneByte(fp); sm->capturedNum = readOneByte(fp); sm->capturedPiece = readOneByte(fp); sm->promote = readOneByte(fp); readOneByte(fp); // Obsolete unused value sm->capturedSquare = readOneByte(fp); sm->castleFlags = readOneByte(fp); sm->epSquare = readOneByte(fp); sm->oldHalfMoveClock = readTwoBytes(fp); return OK; } } // End namespace Guess ////////////////////////////////////////////////////////////////////// // EOF: movelist.cpp ////////////////////////////////////////////////////////////////////// chessx-1.0.0/src/gui/databaselist.h000644 001750 001750 00000004275 12223260306 020001 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef DATABASELIST_H #define DATABASELIST_H #include "tableview.h" #include "game.h" class QSortFilterProxyModel; class DatabaseListModel; class DatabaseList : public TableView { Q_OBJECT public: explicit DatabaseList(QWidget *parent = 0); ~DatabaseList(); void save() const; int getLastIndex(const QString& s) const; public slots: void addFileOpen(const QString& s, bool utf8); void setFileFavorite(const QString& s, bool bFavorite, int index); void setFileUtf8(const QString&, bool); void setFileClose(const QString& s, int lastIndex); void setFileCurrent(const QString& s); void update(const QString& s); void slotCurrentIndexChanged(const QModelIndex&); void slotDoubleClicked(const QModelIndex&); signals: void selected(int); void requestOpenDatabase(QString s, bool utf8); void requestCloseDatabase(QString s); void requestLinkDatabase(QString s); void requestAppendGame(QString path, int index); void requestAppendDatabase(QString dest, QString src); protected: //Drag'n'Drop Support void startToDrag(const QModelIndex&); protected: void startDrag(Qt::DropActions supportedActions); void dragEnterEvent(QDragEnterEvent *event); void dragMoveEvent(QDragMoveEvent *event); void dragLeaveEvent(QDragLeaveEvent *event); void dropEvent(QDropEvent *event); void appendGameToDataBase(QModelIndex index, int gameIndex); void appendDataBaseToDataBase(QPoint pos, QString src); private slots: void itemSelected(const QModelIndex& index); void slotContextMenu(const QPoint& pos); void dbAddToFavorites(); void dbRemoveFromFavorites(); void slotShowInFinder(); void dbOpen(); void dbToggleUTF8(); void dbClose(); void rowsChanged(const QModelIndex &, int start, int end); private: DatabaseListModel* m_model; QSortFilterProxyModel* m_filterModel; QModelIndex m_cell; Qt::KeyboardModifiers m_lastModifier; }; #endif // DATABASELIST_H chessx-1.0.0/data/images/button_first.png000644 001750 001750 00000017313 12141003207 021212 0ustar00niklasniklas000000 000000 PNG  IHDR>a$iCCPICC Profile8UoT>oR? XGůUS[IJ*$:7鶪O{7@Hkk?<kktq݋m6nƶد-mR;`zv x#=\% oYRڱ#&?>ҹЪn_;j;$}*}+(}'}/LtY"$].9⦅%{_a݊]hk5'SN{<_ t jM{-4%TńtY۟R6#v\喊x:'HO3^&0::m,L%3:qVE t]~Iv6Wٯ) |ʸ2]G4(6w‹$"AEv m[D;Vh[}چN|3HS:KtxU'D;77;_"e?Yqxl+diTXtXML:com.adobe.xmp Adobe ImageReady zIDATx] |T?w *BѢ"" *꺻mj]j]Z[_񷿺vϺ?`ժ8X>F |RH cfww3L;y7}sFQU ir5|^9s\ PPa΁a^((00~`s`W` 090̫_/XaC:gt5RUJTT*#*MW06+j#=ʻ0U~eRx1 )%51صqq B cu(BW jS QW<]h4zB M,' )Nx&MXIhmz=ٶ"-]s~jJ{7,ȣ Y%]Oaݯ I0`эjSen> 0aj9M;p:f:J/9g+}Iv6-o}A1(XwL]KU`2 3jԥGqO &Ӊ8f4B\7IhNoh?P7m-=9LjJi ,4B3h(:ں)ڥ+Bg4L?˒}+^j yZz3PL%ѩ ->_ܑ00᝭JRMV.\ʴi:Lug3Scx/uwFXFx|'!o@zZ4X:f`)S Oh'}sB3ۇ U鄒)ºV kE{7N^=g몇ezn.t:-ΥbmoпYO28GU8 :3V6b`;WW2o=eD7}KշΣo{+b3o_u-H@Ƚ"}I4mDzp {`QivGkW Erz VЭZ+ ,tSx{nzOsʴ8^¬sӚ'>Ԟ נwGu` r_{m"3i4]v:& q@ίh+xAl? atcaի}sGbY{S8\E2thƙGQ͢s}`C> S'ZC1  dwX{wेL]-_}M3q KwӦ\ "H"j־pn9QsS2JQmBP6CO<pZ>nYuOd_Tk.t|F}ej`Ou|5`Yf{( pU'A1t͝cw0uת!E%rG6ddM95*)AoZ~sMAVd3=߻yקOC BQPvAV;WΞ0IBT:?.MѾ ?]g (>P2g_5{V/+zG]z C]iHrV;m$Xk~ㅗ0 |a~ ^eH8 KN\:M׹ mgә'lDW}\-H1-BEue"e,j t ҲVl8@y;ۻISߘ (Q#cgJʋ{J6cYK_ a# [V:?wG㪷]? ט{IVpXKyDcv_tԡq 3*:z5ս K dCE0>R)Ɠט`. :~,^CjjkP@4{08$x $א+Py%::9;<Xoc 7d}_C}qI8臿GOc#Mq.[W$Jr} dOz@A`e3jb2+0Sqt@cUK>Z)BOԽ8Ѻ/ 9h?G (rQaXmLF}qJ4sahU`=`([+Sױ̻Oy)sߡ]`-$=,v13upRQaXÞ^jB?"ZUcQ*ר#1-]sD>WpJc>:/LXb2d"*p[ x_`c ʰఏ_l8 ˄dpp̽hFۭTbak5 5>D=t3wl*ϝJrdk G>k|g㵪M>}DY6__ٷw.|iW,%)n9<5ج\Vp)Z6'_8OO߹J2 I5uPX?i/L>}KEW_n}b[(j: pSs痄'oN'0d!'1mE?( ~#[=ۊl+*Z#qMekD|@-qi;.+jRD:_B!Oe*0>&N LvKZlCk!*AM~J?d"en\}?^}bց+"zћ藕g\Y4'?v!\<+n,PToLOV)8D@!ݴ"r|&?&V'1ne]$Q^H psIm[.W5{aBA`DEz`~A.8ӧ{Ju&T ɀ!^[{TRɄL{7KPb~lxkaH 7u` L~{=}#eS1 8Wge+JFwz?m[cdJ²\J@H#M!xұô0_]FO " i-?1aY\vT0_#yFo'gȄ(R _?ʙ?s?;ʜ99K0*ҁײ,=)Oۉ@K6`-"ÐJ|͋6xҿ.XGX~b k u,뤟- ޻ANVܺwCIV8!p>%6tz۱/WVo1gddM때ęA+*6`Of-abRbE+f?&7,P&2H&"aXTiU x`aэ(צԱNfL~2s7le 'j ~}YUzz3`z VreE;9L:{)yQe&0EX"Afּ{˼O,s2c4rH}nRU@á_.(Gx_ێvp!x|cXWJ !۩'}tނ艶[!Un=#K|il o+@KtRqr근~;nd0IJtHPҲgaHv`6S"m ֯._~ ?zf]B"~yð$d!o9[V6ˆBn+!,Um>|w{3yiyK]B~xeHGy-+ 4&V"E L{7\Oq2?y̸k aYXeBF5z+ލ4̸[y a2`YN²< 4!:ҬPх~l_˿,vi7%܂'n% ?Rkr ea1YVZ#i3o·xĵz1O[Fg\YA-L, i^XVBFU~@㹍4ovZ^0vŴLM| c1ɞR|:ب(h\s!r7~dܛhف *e%Vkϰ!g9S+#xK:[^Р/MzyOO R}Rh  *lq(נX o-'ROzb>?FweM|C ""p֣~YeY>̪0BV|i2ӸAY:=_I% a{K"NҺ} 7@"g%9Ay?, * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "analysis.h" #include "board.h" Analysis::Analysis() { clear(); } Analysis& Analysis::operator=(const Analysis& rhs) { if(this != &rhs) { m_score = rhs.m_score; m_msec = rhs.m_msec; m_depth = rhs.m_depth; m_mateIn = rhs.m_mateIn; m_nodes = rhs.m_nodes; m_numpv = rhs.m_numpv; m_variation = rhs.m_variation; } return *this; } void Analysis::clear() { m_score = m_msec = m_depth = m_mateIn = 0; m_nodes = 0; m_numpv = 1; m_variation.clear(); } bool Analysis::isValid() const { return !m_variation.isEmpty() && m_depth > 0 && m_msec > 0; } int Analysis::mpv() const { return m_numpv; } void Analysis::setNumpv(int n) { m_numpv = n; } int Analysis::time() const { return m_msec; } void Analysis::setTime(int msec) { m_msec = msec; } int Analysis::score() const { return m_score; } void Analysis::setScore(int score) { m_score = score; } int Analysis::depth() const { return m_depth; } void Analysis::setDepth(int depth) { m_depth = depth; } quint64 Analysis::nodes() const { return m_nodes; } void Analysis::setNodes(quint64 nodes) { m_nodes = nodes; } MoveList Analysis::variation() const { return m_variation; } void Analysis::setVariation(const MoveList& variation) { m_variation = variation; } bool Analysis::isMate() const { return m_mateIn != 0; } int Analysis::movesToMate() const { return m_mateIn; } void Analysis::setMovesToMate(int mate) { m_mateIn = mate; } QString Analysis::toString(const Board& board) const { Board testBoard = board; QString out; if(isMate()) { QString color = testBoard.toMove() == White ? "000080" : "800000"; QString text = "Mate in"; out = QString("%2 %3 ") .arg(color).arg(text).arg(movesToMate()); } else if(score() > 0) { out = QString("+%1 ").arg(score() / 100.0, 0, 'f', 2); } else { out = QString("%1 ").arg(score() / 100.0, 0, 'f', 2); } int moveNo = testBoard.moveNumber(); bool white = testBoard.toMove() == White; QString moveText; foreach(Move move, variation()) { if(white) { moveText += QString::number(moveNo++) + ". "; } else if(moveText.isEmpty()) { moveText += QString::number(moveNo++) + "... "; } moveText += testBoard.moveToSan(move); moveText += " "; testBoard.doMove(move); white = !white; } out += " [+] "; out += " [*] "; out += moveText; QTime t(0, 0, 0, 0); t = t.addMSecs(time()); QString elapsed = t.toString("h:mm:ss"); out += tr(" (depth %1, %2)").arg(depth()).arg(elapsed); return out; } chessx-1.0.0/data/images/print.png000644 001750 001750 00000003304 10622422464 017633 0ustar00niklasniklas000000 000000 PNG  IHDR szzgAMAܲ{IDATXíWiLTWv!b%R EIVMlihŲF,aQH$d"BYD@@}S6 $ b _Ϲ1/޼{s=yT.;/##.Hӫ%.VGFެMLj/6A+WJۍ|IiZhoGsL ӈ=뗉P 2ǑmXyc8dq[+F:`~!,шKKB%3 -IJ9"g(jGͨ(-1' N t;Tcu`gĎ:6 Hiꀄj lJhjꀯ+25D. pR1qPzahhx! PPPxxxLnڴivmcc+,,Lr\|իWFGG?IݍJ68p`u9r$O&Щ`C&}666s 0ykk(TY{Um VOU;aB*y`---ɓ'x1=z$Z gSىDsqJRwL ;`&H0n޼) [n߿ P8K?jΕK WLvv(d???899رci!&&HIIUEp01ϒCbpubqyxz 233 Bt]QdHOOXzLM yu21 4%+Wؼy+a7oj);c!"bsDy㜫 {KxMOO 5ǏG̹*9]pT[\3gЎi8;wJXwMEɹ~P߷hM }D4C idP?xaKs$N:jd}...s myS1DFНq}\WWc˖-rvE `mm=+97-᫩ 'O%|h6_|͚5fff#‰Rw=eس dQ|ޓ˗&55K֒TY~Ajžu֕ڵkw@vx- ŋմJ[vrI4Eoŕ*"u%<@[[qmVVV-۶m=ZYGG|aBOOOU@N(Ή+Y+h ,(D;ʕ+V^@Yp7" 5򵤘 ",Sre~TJGcIENDB`chessx-1.0.0/data/images/folder2.png000644 001750 001750 00000005053 12077036777 020055 0ustar00niklasniklas000000 000000 PNG  IHDRiCCPICC Profile(UoT?o\?US[IB*unS6mUo xB ISA$=t@hpS]Ƹ9w>5@WI`]5;V! A'@{N\..ƅG_!7suV$BlW=}i; F)A<.&Xax,38S(b׵*%31l #O-zQvaXOP5o6Zz&⻏^wkI/#&\%x/@{7S މjPh͔&mry>k7=ߪB#@fs_{덱п0-LZ~%Gpˈ{YXf^+_s-T>D@קƸ-9!r[2]3BcnCs?>*ԮeD|%4` :X2 pQSLPRaeyqĘ י5Fit )CdL$o$rpӶb>4+̹F_{Яki+x.+B.{L<۩ =UHcnf<>F ^e||pyv%b:iX'%8Iߔ? rw[vITVQN^dpYI"|#\cz[2M^S0[zIJ/HHȟ- Ic www.inkscape.org 4qIDAT8[Ue{gF6& QfNby ,@(Hʞ z"&R^RgZ֌fNs9s<ϾcZ}-PU/s7͢e^\Ue!37p{i SgT6cXe/GV)ꋤƎYZ1k>+@2ƲJ$]ջL:-F40IZlmPQ2ⱇ" &Q5ae%!mmԌO(h"2<'>[ ' 10$H 1z]d\ =A@L0eYm Gɺ:( 2v('z8f#G^%s&t6OUH DfVcƧ/FC* ߇t4 2e[c0+|D -ɑX7⬝u Wk]D+_nJx^ :Ib p ~U8 4BC Ts)'I ƆR-iҐp"^%/@6dr a4x| $AvD/c]nmV0 j.Bޅ փ<r1`G! $Ad-U  K>ݢx%QГL?ZQVUT L0W 'z0ح,!s( HCz{]\YPͱ%`QTǰE)bg13;'c;Fy^v {L&os@>?Oml9W\TDDDj`.‰rvg N6=f mUU%-Ζb %hq\ҾX3}n$lzT5@4fqT(SaU$.`]p':[!yLt :8}wLHTUﺔv/zE6zN9+:щOyYOV/  5LfZ'xWײŢ[/h}|/tWUW9s%t w7)[7sWiA[o>~s۵IENDB`chessx-1.0.0/src/database/query.h000644 001750 001750 00000007406 12223260306 017465 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005 William Hoggarth * * (C) 2005-2006 Marius Roets * * (C) 2006-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __QUERY_H__ #define __QUERY_H__ class Search; #include "search.h" #include /** @ingroup Search * Store and combine simple and complicated queries. * This is done by using reverse polish (postfix) notation. The Query class is a conceptual * list of operands (different kinds of searches) and operators (logical AND, OR, NOT), * and methods to manipulate this list. * Example (A && B) || (C && D) * where A,B,C,D are different searches and &&=And, ||=Or * would be stored as a list: * A B && C D && || */ class Query { public : Query(); ~Query(); /** @return the operator at index, or NullOperator otherwise */ Search::Operator searchOperator(int index) const; /** @return the search at index, or NULL pointer otherwise. Do not delete the result. */ Search* search(int index); /** @return the number of elements in the list */ int count() const; /** @return the number of operators in the list */ int countOperators() const; /** @return the number of operands (search definitions) in the list */ int countOperands() const; /** @returns true if the element at index is a operand (search definition), false otherwise */ bool isElementSearch(int index) const; /** @returns true if the element at index is a operator , false otherwise */ bool isElementOperator(int index) const; /** @return true if the current list is a valid expression, false otherwise * Question: What to do if there are too many operands */ bool isValid(); /** query modification methods */ /** Add a new operator to the list */ void append(Search::Operator op); /** Add a new operand (search definition) to the list */ void append(const Search& search); /** Change element at index to operator op, return true if successful, false otherwise */ bool set(int index, Search::Operator op); /** Change element at index to operand search, return true if successful, false otherwise */ bool set(int index, const Search& search); /** Remove element at index from list, return true if successful, false otherwise */ bool remove(int index); /** Clear the list of all elements */ void clear(); private : enum ElementType {SearchElement, OperatorElement}; typedef QList OperatorList; typedef QList SearchList; typedef QList IntList; typedef QList ElementTypeList; /** List of the operators */ OperatorList m_operator; /** List of the operands (search items) */ SearchList m_search; /** Holds the conceptual list index for each operator in m_operator */ IntList m_operatorMap; /** Holds the conceptual list index for each operand in m_search */ IntList m_searchMap; /** Defines whether each item in the conceptual list is a operator (OperatorElement) * or operand (SearchElement) */ ElementTypeList m_elementType; /** Test if index is valid */ bool isValidIndex(unsigned int index) const; bool internalCheck(); }; #endif // __QUERY_H__ chessx-1.0.0/resources.qrc000644 001750 001750 00000021005 12221621654 016331 0ustar00niklasniklas000000 000000 data/templates/html-default.template data/templates/latex-default.template data/templates/notation-default.template data/templates/pgn-default.template data/themes/boards/aluminium.png data/themes/boards/cherry.png data/themes/boards/lapis.png data/themes/boards/marble.png data/themes/boards/sand.png data/themes/boards/slate.png data/themes/boards/wood.png data/themes/alpha.png data/themes/berlin.png data/themes/fantasy.png data/themes/leipzig.png data/themes/merida.png data/themes/spatial.png data/themes/outline/alpha.png data/themes/outline/berlin.png data/themes/outline/leipzig.png data/themes/outline/merida.png data/themes/shadow/alpha.png data/themes/shadow/berlin.png data/themes/shadow/leipzig.png data/themes/shadow/merida.png data/themes/boards/mahogony.png data/themes/boards/sandlewood.png data/themes/boards/brazilwood.png data/themes/boards/maple.png data/help/about0.html data/help/about1.html data/help/about2.html data/help/about3.html data/help/about.css data/images/chessx.png data/images/back.png data/images/fileopen.png data/images/forward.png data/images/home.png data/images/print.png data/images/time_clear.png data/images/text_clear.png data/help/about4.html data/help/about5.html data/chessx.eco data/chessx.gtm data/images/circle_black.svg data/images/circle_blue.svg data/images/circle_green.svg data/images/circle_grey.svg data/images/circle_orange.svg data/images/circle_red.svg data/images/circle_yellow.svg data/images/square_green.png data/images/square_none.png data/images/square_red.png data/images/square_yellow.png data/images/folder_favorite.png data/images/folder_grey.png data/images/folder2.png data/images/folder_txt.png data/images/folder_locked.png data/images/folder_new.png data/images/arrow_none.png data/images/arrow_green.png data/images/arrow_yellow.png data/images/arrow_red.png i18n/chessx_de.qm data/images/folder.png data/images/folder_open.png data/images/save.png data/images/label_blue_new.png data/images/button_ffw.png data/images/button_rew.png data/images/button_first.png data/images/button_last.png data/images/help_blue.png data/images/edit_copy.png data/images/edit_paste.png data/images/format_indent_less.png data/images/accessories_text_editor.png data/images/edit_cut.png data/images/close_board.png data/images/new_board.png data/images/edit_find_tag.png data/images/edit_find.png data/images/filter_rev.png data/images/filter.png data/images/filter_reset.png data/images/internet.png data/images/bug_add.png data/images/camera.png data/images/replay.png data/images/edit_out.png data/images/go_jump.png data/images/arrow_up_double.png data/images/arrow_down_double.png data/images/setup_board.png data/images/new_game.png data/images/FlagFrance.png data/images/FlagGermany.png data/images/FlagPoland.png data/images/FlagUK.png data/images/go_up_black.png data/images/go_down_black.png i18n/chessx_fr.qm data/images/flip-vertical.png data/images/flip-horizontal.png data/images/swap-color.png data/images/replace_move.png data/images/insert_move.png data/images/plus.png chessx-1.0.0/src/database/common.h000644 001750 001750 00000011456 12223260306 017610 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005 William Hoggarth * * (C) 2006-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __COMMON_H__ #define __COMMON_H__ #include #include #include #include typedef unsigned char Square; typedef unsigned char Coord; enum Piece { Empty, WhiteKing, WhiteQueen, WhiteRook, WhiteBishop, WhiteKnight, WhitePawn, BlackKing, BlackQueen, BlackRook, BlackBishop, BlackKnight, BlackPawn, InvalidPiece = 255 }; // Pre-Increment Piece& operator++(Piece& w); // Post-Increment Piece operator++(Piece& w, int); const int ConstPieceTypes = BlackPawn + 1; enum PieceType { None, King, Queen, Rook, Bishop, Knight, Pawn }; enum Color {White, Black}; /** Return opposite color */ inline Color oppositeColor(const Color c) { return c == White ? Black : White; } /** Return true if given piece is White */ inline bool isWhite(const Piece p) { return p >= WhiteKing && p <= WhitePawn; } /** Return true if given piece is Black */ inline bool isBlack(const Piece p) { return p >= BlackKing && p <= BlackPawn; } /** Return PieceType of given Piece */ inline PieceType pieceType(const Piece p) { return PieceType(isWhite(p) ? p : (isBlack(p) ? p - 6 : 0)); } /** Return Color of given Piece */ inline Color pieceColor(const Piece p) { return isBlack(p) ? Black : White; } /** Verify that given Piece is within range */ inline bool isValidPiece(const Piece p) { return isWhite(p) || isBlack(p); } enum SquareNames { a1, b1, c1, d1, e1, f1, g1, h1, a2, b2, c2, d2, e2, f2, g2, h2, a3, b3, c3, d3, e3, f3, g3, h3, a4, b4, c4, d4, e4, f4, g4, h4, a5, b5, c5, d5, e5, f5, g5, h5, a6, b6, c6, d6, e6, f6, g6, h6, a7, b7, c7, d7, e7, f7, g7, h7, a8, b8, c8, d8, e8, f8, g8, h8 }; const char strSquareNames[64][3] = { "a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1", "a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2", "a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3", "a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4", "a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5", "a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6", "a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7", "a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8" }; const Square InvalidSquare = 255; const Square NoEPSquare = 255; enum MoveType { StandardMove, PromotionQueen = Queen, PromotionRook = Rook, PromotionBishop = Bishop, PromotionKnight = Knight, Castling = 128, EnPassant, DoubleAdvance, Promotion }; typedef uchar CastlingRights; enum { NoRights = 0, WhiteKingside = 1, BlackKingside = 2, WhiteQueenside = 4, BlackQueenside = 8, WhiteBothSides = 5, BlackBothSides = 10, AllRights = 15 }; enum Result { ResultUnknown, WhiteWin, Draw, BlackWin }; #define MIN(a,b) (ab) ? a : b /** Checkes whether piece has given color. Note that there is no pieceColor function due to Empty piece value. */ bool isPieceColor(Piece piece, Color color); /** Returns a string representation of a result */ QString resultString(Result result); const char* const TagNameFEN = "FEN"; const char* const TagNameECO = "ECO"; const char* const TagNameSetUp = "Setup"; const char* const TagNameSource = "Source"; const char* const TagNameResult = "Result"; const char* const TagNameWhite = "White"; const char* const TagNameBlack = "Black"; const char* const TagNameEvent = "Event"; const char* const TagNameSite = "Site"; const char* const TagNameRound = "Round"; const char* const TagNameDate = "Date"; const char* const TagNameEventDate = "EventDate"; const char* const TagNamePlyCount = "PlyCount"; const char* const TagNameWhiteClock = "WhiteClock"; const char* const TagNameBlackClock = "BlackClock"; const char* const TagNameWhiteElo = "WhiteElo"; const char* const TagNameBlackElo = "BlackElo"; const char* const TagNameWhiteTeam = "WhiteTeam"; const char* const TagNameBlackTeam = "BlackTeam"; const char* const TagNameTimeControl = "TimeControl"; const char* const StandardTags[7] = {"Event", "Site", "Date", "Round", "White", "Black", "Result"}; typedef quint32 TagIndex; typedef quint32 ValueIndex; typedef quint32 GameId; #define TagNoIndex 0xFFFFFFFF #endif chessx-1.0.0/data/themes/shadow/alpha.png000644 001750 001750 00000311731 10633464147 021105 0ustar00niklasniklas000000 000000 PNG  IHDR4RsBIT|d pHYs66BtEXtSoftwarewww.inkscape.org< IDATx]wxE%BB%@)R4I%H/* ҋLB %!+~ig\vfwf睝w(P@ (P ;(P@a,Wk(P@(*P0 x׍Pf$e~U@E !p @n0$+Weڧ@w/qZ7_,FD8p` 9r$Ν;j]rpVJvUh@AEzz: .,< LVWlP  ,@4|HII2WX!Ӹ|q J[H=d?_!:{Frr2o8C4r̅5!@lLۤpo a.e Z( X ΰG˗-2={-[T*Uߋ/T7N2Bc ɘ4i$lٲpmٳg8y$#){m,^̩ekz.Eg21 Wr"DzlBݘ`=-&#7+FI8p` [1%/5OS pwͫX0'?ަTL вd7nܐSD !?22kTP@%peۤxGAp 5&;bStt4eddȑh0Fm)mr'_*OLLhue/x&ndiii6ׂ{fv;,{f)X)g$%eKRT(XIOO| "0OHH k]|k|͂M".Vx?.\ ,Wݛ+T Q_x ?=˫2x5)kRP08 Oa׮]߿?+2e@ 7ިj-yZ Ti~J*@@2ePbE|Wx"Lϯu466i&m5OA8p[걊o%7 .R>ӛpɩ dNM`aVN(Y)f60j(,_"sX`͛) ԩSaM4 3 I|b9@}V5)Ν;㯿{C֭dԬY7:;;ÄmHd˵~zL:=ۮL87-+W|U\gfmS+;=z`YX=Pn]x{{=.FmFn}{wR ϑ[6_[FV>,":Vpqq 8~9ZR_`Y[9TX]hǠ/ar { +Epj N?=zRJ3aQ/o] s#G:2&MBRRkpPO .l>~DތZM4^طo_pYyݺu2[,khXC<&͂78%HE(/KX(a4C!?TDDt?'+Y ++7$U'|߾| $x{xxн{hݺu Ћ/(11T_ߔW@)MD۞>|XBGJE/^$[ܹv }`p@cp5L/ngG{RiTF 6SrB CDD''0цMk{)ajWe"2۷ju"lwx-7SxeZ׳Lʕ+4Fo+ -og !]DtRIψh'Qy" "}%H8=Ԭjժdo‡y]$&&fK}KF"EDH111xqԧjTXF"Dp*Zعs'F'Oްb +W4i>}*䥦bժU4i[~SN}K`Va˝bK)Vw͛7Gz)d,m"$$]t222p5L6 {x00ah4fl߾%%R ԳAeEe-)4]~AN| *W u~eܹ!C`ΝP;֦VZ`Oi3O7[qT `4 6{ge"..gϞƍ-͙3~)>x֭["`yH2L{'X<4- +`$1@7S~Z]T:T`o88%DX^'ݻwt:2+L͈*ߟϞ=^z}gϖ)Y$t:""JJJD#p)S P^N'ŧ(XٝQ"˗& ,H*fѣ1q]Ψ]p;M@QXJ7)N"λOɒ%-ӰaC'kQ:u,:;;SBB%&&']'a;m)ɸ ㏒q3qDbYVҮ3gHq\w KZxi)WK9.ȸ4^x:hol)H"ADz!666nH&MRUVҘ1chѢEtU˲G~7Z[}MDa0ӗ,vuV-9`\2 FT\̢U9wóIDߓ-ц H"v_x!WWWIM6ۭ[4F8&Wf/UNy"ٳ .orРANDDiiiUTcp<c2Sj NU8u TjRbCQr<&" ̙3d ǎ߶tmK(FPdH[^߈磏>W7r;vEyJLL$"7nL6_pjSyÂQtzR3ws]]DGǖ2yND@W͛;YB gϞiaۤ}pU)wwy`]JLLTHE&Y) "vrzQAg=pņT@(SI<|Æ ޽{mޠh0n8̘1 F~$A׆{a„ pqqaʕ+a"""{ۃx69(G(_,2'(F aaY0}}]DFFߗu]k Fŋ A7q%7nxpޢNlU4$Z׷ycƍV-T݋^zAє- UiZZ6lVkA͚5\_:qTTԩWW2Cx d$38 *FlڴI6/((%K`gDǤIp,=Ν;orJcpsssqvv^~_l۶Mo*.#@Wg u2 b(>>>GߋeYTx펫 ƕ+W2d8J`,0Ǘ_~$75hJ9;c855ӦM? GP.5wٳO> c.G9\0 C{)p I1 !NNNpÁ Ĵ3fXxsUVEc?(9cPޭxvzgϞ x=aԝ:u*f[vi2DT;>>ޢҥK}!___ɵN:pqq) K1S!ހe@H%n:r6ǣCv13e̦D^t: 26lx&''cƌشivލʕ+͛7o֬YѣG;58<-#>f777 f àk׮>ȑ#6u:f7dY-Z@…weܽ{W6thh& TRn}Ϟ=ӧ-Ga~G(W aSj@ F 0x`;vM;w.>sTcOVR;vP܆G6mիջgϞ_i潅 .;w5f.!d(ҌWhDR-ܹsӧO1)))={64 ޾}{b~~8z 7H*Ć uk“'OXYztGDD?a$Yn3O0srx,prr*jjNj5L "'d `UH֎z @ll,w;~m4j۷oG6mh 6 t$+1\`fN`on1ˡvqjp+ooШQ#} cYV%aY{̙3/gϞD ۷Dur' o;XF/ӑfݻcٲe6Er;v,è]6򂗗ٳڷo޶m-/uaRVa…2e t:C`Y!!!8|0n ???*U9mٲeBT8dl$C)]/N-Zѣ`YK`jDp NZ ^UnAD UZP:u )))pssmÇ%֭ x-Sɖz|'yOsssĤ0xUll[n<<}d.4hWݻؾ};L;qHaȑ^|[n|||eٜJ%=z$;ĩv?dJW](00nh„ d0[nX|0-C>7+ݖ{ŝeLDgNNKK#GڤIɒ%tMJJ\ǔ`m۶=-Tm)b^DoF4`>|X∸oϤ*$5 [.;ड`bnrk4C_fMx]d߿4 @}5V)ilӷuώqăWOg\[0..n*7آ޽{(::]j:D^]p8r1\DJs/i(ի.h+VHׯ_WErr2[v,M4I('(o{ü'vO-'6֐SrvBѢ˯Hv˜?mOEJӥt tS9Hzo^w ۨa8p ^x![@9s&Ǝϫsxw)SV`\t ?# .TTK.Ι3gbHHmXD`0I? W^E>}$y }d ,5k֠SN:t`xΝ;hڴ)fϞ/jکW^\z|֭=<O-m&z*v6R.]:`0ꙝ;wƒ%K0fWTظq#4<?9r$fWb[7ݰgVh4RT̛7ǶmnW"E~xxx(<<|7,uy^Pf\Fo(k y{x{̤$r83{g<&O,,jlڴ)S=5kŋW5j|}}ѠAANtyrc# \d \u"k׮L>9 ƫW`jrD駟J@`;JpMpѡˀ;]+ )Px IDATs+!x"t=zݾoݺCÇk׮vUB|pN;wnopSp'eae:K"2}F...N֭]?~LAAA6iڶm[򱱱7;u;ub(L:~'˲$-Zٹ/@=Bw ̑ؽ154QQQ(3JW6mJ7ouر)SpldE.x#|v!"7"*NDz3rDI0C\r%SWpq+a,Y/<`0 .EXX2?Llٲ%/T\y8((Q߇o`;Nm<OD˲,7 -ccca^ߖ5FzzzlѢ',%f[IAbbboY=HDw:tODIDt,e,ˎ}_VOٓ#(RNL>=*SfϞ-? :tmodyb021~`;55UyC{ۆ~MKKC.]l,YƴilzsΡaC5*99={ADh4cƌYf&Cl 1]|) /9bC`8v올#`cǎ?իKyfj^K8lV< ۷OشiSgeo\˲гgOkȜ@%p1O60{lt IIIPnÆ [?4yBqkxbO.bo>krDS9-[о}{3'NҥKcDDD`bŊ=bYN3gXcXa48T[n!**"CR Z J%{W擜;k7y28J0zip_|1ӓˍaN_Z }IFJ(P@T[Z\}6յp6m|>̟s[LӘ~.|\"" ~YżKLL ڵk *1Y8 Kۈ›֛6c0h޼yje]}7vٳgԠAY׏?z}i*شi]rѣGeY?8f׆5a6/N5@lhNX򞶯> 1ĉmgn(555gw&7776T\@\\\djjL %Φ>}çjNϞ={z4ݹs$O(111ͭ8.y4Xj8=yDD-ADD4l0I_-&M0@}m; ^ޤ%LӧOE:do++VfΜIϞ=#X^^VEt:B Y`t!pqqikGԺseE'%%;Vk 2322f6ZcfXoLf&鈈z= 8f?5FqDDDPbdK. a[ŋg*W3ac{*3b0&eddoeY 䋽]v%8h1΋K%H7/n'w`W_ uMȟ7o^(ä~qU^*W~"ʿhp*^kmVCR\\&iӧy7oޤҥKr}...o u]~}f RRRy:fΜI^^^nnn4sLJIIB>*]F#NZϟ/yQN!..NR_ŊO>y x,rD3 >"={H:K.I7A'NNNB~xx/F 'n@kM`${z3gjD}{!thRl-'0ydm m-UTGp` MK`&ޘZ3L{zg5&4"įSN}0 -X )޽Kcǎ ecbbN.] [ⷒɀFFH'0a;Yyٲe-yf (Gjl3;p QQQHODwI(P=\h%eJ,)۷7p v.Ժ84fxǼ,zZFjHDw=rըQ#[7r{p%''OKNN_qCԸqc?>ZuF*JFY(22r+WK-]PpIa;gL+U8h*JD`I?.Zr )))*U$d qpRE*rnV$/B-Z1r7DDD/_uڝ<˕+G׮ A]VϴODWA~춧m۶ ˗w;hTKmf2碑^xA73V+ď+x5k&>ڹsPNj/^f8j+Mc2|}"@DC CT_`,l%4,> "Zb{iA 2~xʕ+r>PqXECK_XChTm,!{Q qP"t۶m*="D&feY;w͍8y{{S޽iҤI|rڱcmݺ/^LǏڵkg ah̘1&nm(ʕ+%:tJ,){Oʕ+{/_N|4l0?>_~7ZjM>>ոh;Ǐy61|7dgEĩ1[ȑ#er劤-[ #FX `b:Ȑ/ԤrD'7k~= O'o3fX K`m0eyQ*M6D;{lR ~1b%%%iӦ9X?jD|$&&RٲegڴiBUV} nDwq?77UU$" +{HOO^zɶSVӪUO<9RP!^gKd4|BӾDtN6 O>*jf1͛%4H!!!ԓ(66bbb[lhZVyp;}ty2۰a΂]5UkRSS_|N5= GQTe$:B"˲dB =^ql*NLݻ۝<<֭;\$=I1Z[3J;7jRY2"(Igj4 U}X٨իW|C`\lpzm0RL#y&=/^ȸbŊj&rsѲe(44-ZD ,SHH͙3fϞMf͢ӧԩS髯3fݻw>;qRhDDԹsA6`Qac2xqk&zS0D())V*O˗wxA-,KǏI۷ e/^)XڴhELF~!?E M uٛY I>RSSZ9- *U8J… gRbP (<СCe_~ԨQvZh14Rr[`GQQQ%Jr||bk׮T%8QF 3YELL 6̮dDҞ={H^ #G&$$skKa!zMIF޽6{JNϧB |~"E`0/ZuJֆ/瘜Lk8~R+,YDRߤI(5558p6CpmMsSMHդ\c0q|l 6mȞ8x1 z0`@( dA< Մ`!"at4k,L*ƍ+rC -Z?~LDDO>^@n6?m`63RM O"S޽e7_\ L˲ƥK%{zQdRa#":y$͜9vJJJ*Q޽i֌`zJJ @H23O7**^?"Nڻ0&kJ)==y* mLsæMQ /"yF;wȶa:t.\` ) J*i C={ɓ]vTX1Q 0.]jqi\\\PVB&o/^+aҥ ݺuKϲ .P˖-mLK.p"N7n>x`68QUk^pa ˲e3{lk=iqALL 1¦BZM;vgdd~쉐(M8jͩ5FNǏ; 9OI5l[hUfel{(88خO?T(߹sy/R8X~(`}…LugVJNv:$$$d*{9zL~ddm2x]qLؐKw^llRddd6S${,{dCgjj&Md)pJ#G;ŋeY6CLL̻0ojTSTSth诿#6Fjj*H;wPf֬Y0{l{m7^III夯իBC~d-)O ^/!={㓗A2%EGG7]c`;6޽{J(!''' _m۶Q"Edh4{Yf GGG wW]~(طoi4*T<<}rG`a]*GW^b˗DDIJlǫީ&Dzr ShQaya$c,@Dw^i h Jcܽ{"@p\kR5}e) ˲Ov =1DӧTbEٺK,I'NKŵkdUNB. 0@/>>wpipEUpR͹%|իWKt:===ɓ9QQQ6C<<<ܹsBǏO͗;G:VR }ݻf5lzlQ4&!zfeZei1"" *UX|o:V^m3P9sF(6gΜ0s fWeF` #H}67[|Yf?n|vZj'c4 ~#T4& l}#-dcS#>a|]\Rk7tl2ݻ LFNTKDDdZ.DfI*--'pwX54Ա{?#ɳ3s-H ܷdWzn*gτlr^LD-$LacEXÇMCG ":GIiԩ#[gݺu]"B''''9s0`OGӥW^}8,]XٻTu@XwUmD $dd`0N:%$f aÆ}&CV,Mwi d7kUTN:Q֭mƮ_aϞ= M '̛[YӴ4AUR㄃H IDAT%s?)=O.dɒwipm۶l4c;&^gϞʹqI 򃂂FAjQ4Q||X"N%wޑ q}2F=zTv.]Fbb"iF]bŝ7)ܡ\48}(cܹϳwNIIGlr Z,D֫W9C`Yf͚%L???a]{3/1b5yW*R !70$99ySG`4hbcce-Z(ڴi{}Mc׮]`YV6qؼy3ʗ/xqm[n,#= R)eMM!=BW2t:fϞ Z-fΜ`\jfhDժUqme֭[ ===bŊ?~|Jˏ !q9 tǏ-2K,(Q"[+gI-[ֺ`ʔ);wzxx8 "A Y~='#OK9zJh p 6T:tEÇѺukkL6Ѽysddd\rqqg Ѹ_R8t,+W8"X`5???ܺu j7o>HNN>>R:9X0L`@`` ._lQg"Ep gG9 \ÇoSuvȪ7Xf&J&M@[''^!$&&e˖pB ֭[N`^r Gva+=z]$\\\н{w 8AAAPT6v]lذ6l{$^^^8~8`4znΝO K"AS&9#:ptR# -)((HóӘT*:uEBRf,b88VNԪ,*P*"C&DDTzu}ԨQ# 5kZj e׭[o U6L-ZZM^B 1 l?|pynJ0,h~~~¼p?`鎘g/GӜbekݣ%-{0LcV^@u ]׼y$f'O.JFgΜr(eYY[ ~NwEp~BSNټysgm?#ѣDDd0^( 6/]%Kҳ{jvZ('%kY@A)--Y*UxQ3ӷ &O>sPrew޽{w+K.ɪ)8P(sѰ9I?==枔OիW{ԩvZ"ڵk ` I0{΋&\\@y Zr,έYCLLL\%J1gḾ\{ .#G`h4X` l{Q:,OĜ\r2P t:LF蠪XbB_tYC.0[ImP&113f̐sad"DDD 00sεբE \t ƍ+V|Ӡ_s0qDel(SLƍ{[ @Y\ Z <46o,QKjo_NtI5VH|zzMGGQ^= 4Hr}Μ90PڐNOW5/94 /_HD7AY\sww~`ȹU+VLؕ1rv{/dqڵkرcZj[nyZ$̝;Sk $Zޮ]b(`jW^geF|, Kb}h!eܸqNNNNN9!!j+VWkg}mJ>}Z͚5{2<5jve,ܺu W<9YǬY$jDM6ܪ͞= ku, rfMhlbcx9:w,дiS9sUV0ggg[s̑'NįUj믡:u* یL{6;IժUd0ӤHf{mٲ_K,̅5fdd`hܸ1^*[`X|9=+BrGɓ'ѣ~'|___'Xz9!٤A^!aYV6aĈ:vUN ::Z+?7o\]]-ݾ}?I& *͔䉙 {>RHp-2ܹ47I5y)hL;n?|YNNNUV^L2?yDIlȊSW]ۺUQWYu-k]?;JQ,(6K2a̝$(3O̝s[O?pa[G_#}_u^L0]Ƽرc {0D<`{%={rCb١PJko>q P{SDذaٳi/tʔ)!6lN&9"\;ƚ5k`eeUP\c֬Y{aHsΝD1fZP75kXގ}3g`kkՁM]v,24kkk}kO0DCcL^EQ icƌQKKzRa>|`) ` 62)] "##AAAX~ZOyǡCǏUǒd8q"ƏO ܾ} 6_gR(U)kГ ʁk$"#G,&>͛7?>e˖ 2ED=ʗ}DEh%YYY?>̙EQ2e o}-޽ nۙ {/4h##b_Ӕ)SL_?~fh;o2ٰaCtܹ%ɹQXXT 77jb3ѣG?JHHDF-ZScxWƨQx),,ɘLLLgϞ]{A I PJh#}!\\\tR 6Le[pZjǏO@YYYaÆ(@{߿?:uꤓk(.0zhobrr2ТE TZ5M 0 ǔ85h0_8z(z ގ3g$4!,, ...ڵ+RRREaɸ>֬YL&[pzρtPzkе/+]wߦ(dKKKjݺu*IJJ uIjƍ%n,AcWfdeeĻpBf6m#CƮ -}Yύ+> t׀~3((D~O(zYΝ;W"mtO<(_LS_)JYrʼߟ:w^bp1%7g=s<0#rM}kccDߠP(ݙ:\qqq{Lwޙw ާС1mAAAZW TA\WI%(ْ%Kxe5ovY/ERR`???ݻw̾/^dbb2 tr\&Ke. [B KZRk6g[ :57((+Lwwwܽ{W*$Ѯ];k/^z֖nܸH5uj`Ǐ3jCٹӝ<[B#,4kv[͙3ljoLJ\9$R? ux۷lقVZkFHH\ۯUVzujժ ]B9Hh7iӦѸp9<<CRfMϫN&P ҭ[7rqssS9B_???8;;nݺ޽;/ J*Xd ÇǍw|3gX,(sѵkWH:Mh Hs߼y hh@ܺu20qơbŊDXXo%ڵkmi('21Pz. 0|pL0'+ٳgK WJDGG}mQQQh޼9-[s(WWW#{D<2!E/M2b KA_[Z`A5,  ] ur*֮]uh֬J Z+˥͸o===]yɞ{:KTZׯ_66nX 52#$AtoI({kllP(@pp0 EǙ5k,@:u߼ysդIjp}5j`~ ŅQBO Yfu|$=AZEQ]Y vrr*<@,wppZp8`E}&x_d%x_n ի1u/*n:xxx0V{sss yܹ @[d24h૮}i\r˖-Cvv6Ω.WkRoeeepQzl``(E6noǏ3ޤ7n_\=dvHGJ2q5yСeO f6m`R}-LMMU֥!77PR'KFBm`85Cxyy1^c6D.IH$X|9LOOGzjeo>޼yt'4#݃2 #uefɃA E"j+2\j<t'EɓTYBtK'_=b>$pppP=IYXXXsO"4 U͛7 vvvd%v͛7e…yDY$UXd)M-pOX؏?>bccymooo̟? bؠUV߼yީS'ٖdEFxf͛SN:+W'-.H;w0}[u윔N:D"855]t?#? H0p@ܾ}ڵ<~_ooP)O%߂7ԨQ5?7Wqvv&ZB? sJ"ҝeFBM X/={^^^HLL8|p?~1cpA/,,ȑ#1frd2)S=|p{32%I0@ammmCo/x0L^ k`Bs(] @ z0zObҤI;nݪ666jQ|bt֍Ng&\Є,;Gggg7l@38+++s7 N{Zvɏ?(,,7o"55Nŋ1|4o\ /UVxž}mݺau/ y1Ξ=˫!TX"d͛UV ޻wou֭( 6Ç:ϰa0sL[W^Eff&6mx/ͥ!&k,=SNۺu+ "ػw/o'~Q`b M eue vXpYFgqC;vDtt4q̋@N'biN&ݽ{wɨD,=ɰ 33#y0Jz L_rV&`oBJM 6%R\,\ϟ?ɓ'ye˖ B<))Ѯ{xxTj66Ж\VPf#ᔤ|8&( |زe/ $ 5kFp N3333\˗/J2 &-z^p!ex ^zUnD: 4ճg>uE)R1̛7okaa![x1;qebgϞUV2e fΜI^xxx|UXMF`nn1cƔH@FFd#DLL Aʊfgg ;g+y.Ç_K0e\FժU1-[DŊU$8<:v/J^})]۷P)ՕKP ~!99gÀsn[\]]':dD[ 4{0*WՀ 8^EC&4/_Đ!CxT Wr9 6 *ѬB\xxxncg(` MJ  H{<>}?`{ũSkJr̛7Ԡ%)J9*TKP(0g {{{9r>>ƍ5o|l2,Y#Gnݺ#G244Lo1[ Vj *4i={h yXz5>|H$ªUh2dɒPԓBn&u5EDU|}}`8q3g,QJ£GTݺuu$](ھ}c 1< MXu%`.ݎHcǎ*UW^:FBB;Y(nĕ+W' WRz2985$$dӧOL>*2331w\Xضm:uꄑ#GӰD͚5Kɓ'~~R9۶mC:u(3v-}ӧ>z܂ {!$**ߋ-bb(sF\z߿/WcX,//,6lذ%s:w|qB&C,&%{!@J@/1\#W SSSe˖lҤ!CYBPF0=SB [ 7Paaa!:$vvv8t/fN:HKKC۶mq]ee \\\ЫW/XW^՚\Nƍ3f j֬aÆCZ KKK,_ׯWK<CcccCh8ig`#3fmZ*%~Wu...8{,.\eIUv{@\ m#WZ 6H$2D&"L$D"+HTA$9b'X\M,ngUWq`ffƋ-Ppuu]$JgKYRtT*M**JJSRRtT*+JGIRtD"/HzJ$nD" žbT*mp8R`0[Lȃ{g}!DTpmtܙM JNPPTaQNZi?HCqQZ5L>III%R4y0"B !T Sƍ#fJ*c&m=ύ=~n݂o?C('{O>yr&$Y:r`gݻ J_7G^&D@_999YOYY!J` ۱% @`#&&FHܿjMB3HE;z@UO-J`oP`cʕ8z(1(,Z#G$]v*5PfM7XS2-Z`޼y믿k.$%%ɓ'3g V{$022bK\$3Ǡ@|ؚW}ׯyA2}#... ڥ& 4B4% d/Bˉ'1j(f]i{0iBǠl߾(š5kx{Lbv޽ŋrw_>$C4Je Pl׮}K.-/Rc`` E_իW5AŋWrrrHEWK`Q`M<|ѢER +W6pǏ5@6p^ yIdC:_K D0Y8ɃQ^HhjjJ8r`$/_DPP&Os7b,\6mb$vB۶mz,jԨ͛CׯƎYfaĉٳ'U xzz"111116mF=zJ*Z uA,֏@A^yJ2BX(H)"yS,LQbƌHZ Jy2P /<..n> ذaZ7 ccc8v4hP iBӦM燛7o-FqF^!۷O 䂔1J`p7kA֭)z|q1b}:Y 4z DihѢآդUj>PEi/^}b|ASR}ѩZ/ ɃallLK_x ` لݝ733?I&1ѻwobjHHHGGb˖-?0c ,^;wDtt4?<$''cݺuboo{D%`lYx͇r9-`QLZ4I4wR{sμx0jԨ(TPG0<==uؒǯSHR >3g}P9r#F୷g5feee}tHuuOЪ:VA (q@Šk:b *(Ocm Jc_~믿ށ*r$yS;|6I/$[_NW//)f k۶mEeB}Ky![YYQMulI޽2)8)P6`{"yKHrc:ԪU ^ JÍ7鉵k ~KE˸gb] KKK8q!!!J((((wC5kVZ-611eff6W*bkk;sΝ;XbXh1&;y,!\PZDN:++h\\zB޶ŋ3:ٳg}'%P܉鳺T`~0|psb:Hq LŋcrssIaBXȡXի(7V4iO⥯6zY(}:F67Om6TXWPPx~?~DZZ+}zz:d2aeekkk{zqssӘBPVpԩQcӧO-Z(eQ "i|?ڀϪA:/p4%%%ի#((NRپtRѣTZqeUPE-X dY`= I DX!t޼yJשmڴynaa[HHZh ]n|}}’ "(ŵk0~xz˅ ڵ%7th NqP}Im78|0|5lҤ ;n֭ڵ+{Yy۶mOA$+wn!A[-M4{0HVMyOD sD\p\. t nªU1II&L&Mlzm.rѣ]ePӧ9s&1A[QPPߨB(8 vFn-,,( @?cڵ8pƏMmڴٳqܹR#CDFF2:J*G@ll,.ԩ{ZU8lذ]iii KV(!}6)AM)2qеkWbQEq0(;wfI"%{"5vB ֮]K1bCH2mHDL!OxBCC SXYY!;;;kС'|&z2B0ݤRi@9W^_}={9r!3]t3pR.7)4>='Qo [[[R&Ȥ ZK>UXX8@T*ŏ?Gaԩjk:HÇ BGGGիW{z{{'0zh֭KLD0\h/RGVYϟB ('"$+EQL"e˖ڵk8]سgƌooob5p[[[=z~\ѣGSԹ I΢2X!~z@Q.]8wYJZ-[`).郠f]@Ufyɡ_3F@ZlѣG=jԨqJ,o߾-[,͛7GڵaeeKKKW%򐖖tOOOGJJ bcc'Mիuv I7i 'T@o oRRR9;;רQ8so???6ZCֳ ,xϑ6Eu1eBa۷ ˣ[b'ݻ7&O♽p^x'''>6mz \PP{C&ޗ 'z05p+{ΰ`W+UVիW$I]OOO;wƤI@Yʝ>}zWNNN~ѱD`0//bX( sڵ he}+WŖ4 ?vG=!ӢWzjjȑ#h֬^z%xcnnnAbXr 2Ւ +++ڵKo!hRG0s;B egg733sT\7n}N[{U|'NiSPfׯ֮]`Ϟ=ĴsM6>}D,QTYVoP\ A/>;vɤ>|'O꺹z<* fffT iDk;Ydi"B4hp͛7GQ ;]O>[nmkѢV^ x"e:iאrA6E"Q @ϏWkAl۶ J fΜLGv{{ɓ'7rR)FG1~!EΝ;[EEEͬXbM8}4Zh7jWV 111. H` xf[;-Z ФI2 G݉"ٵ|O~ɓ'9(.D24IMKK;xA73lmFAAN8[߹sgO-Ztdqd2IJOIƲDyHo߾Daaa_xAgd"Eőb```0 yfG޽;u-\v ХK@GGG#I&A v҆Hx.Ԥh`krg "<}$M$1 ~r5XbL,W@KڅI^z\[zzmBg. I(LB'L1f̘RiN:a̙*;>x߿1ÇL>zIMM-1rss}b1\]]F>>>_l񎉉w^fGbiHF29Rl߾==00pAZ[[>|^^^w܁N>]blܽ{ӧOq*T, 4(1Wvv6BBBxE*qF#\vh5-n1@h1  *(( &ر#уUӧ`=zqqqB۶m|||GGG*p =`d2#cccqNNo.dɠ5;w|@ TYxq*;;;ITT\KK:tR^f6ѷo_ѣz, UaiiɤMOOW/Έ=z"i')Z_b<~ϟJ*^:]MNȋ!~F}gΜ!ҀBÇCٳ23^ƍ x{{H9;;;+22)tID_iH{СCׯS֮][h׮>~rD̙3puuEq89sgΜ˗ˤFDlԫW DVh_FF:u;6$k֬a 8q'%6\JP+ҷ>G47ӧFUj'ҥ T<0}t>}R0"""s > )=ۣARMЗ f_$DBޤuzO.hc]D ԩS(dwޝicc ('NH}SN;֭Yf`Р TT cƌa~xpe6D[bm,Qs)d_cĉy3XEz#wwwCܹsgr^e:/`o!E-уgggv=D/H.ŖJ]w@ .4XH@* A^?wZ6QN"~={Ʈ(dI4O&idb+4ZlWy1v9-&&Ʌ ]4LP?~άYHR sUʕ+عs'[8 6ШQ#xxxaÆ5acckkkӧO#>||7n7p޽b[0sL̜95B^гgO\ro'OL0 =OlDH2rss 7n<ի6664h . _V9Gػw/6oތ .|H$pqqA͚5QV-ԨQ666033cSSSD"Aff&dee1S$&&"11?&[;DDD ""uŀЯ_?899͛7 Ľ{x300ۙn˫W40 YvsS"oXnuLvT'''cزe LMM?VZsiba7}oD"L}"{ oppp0+zMZ6"GH*$z"oopO>CD*Jc,TV" 2gw^Z؁M6 FQ{mݺNۦ ͛7JDܼyhժi(jG}*sRԯz000PҘZ[[RZbR q{^^ܹׯڵkZ?>>2e Vvm<.]߿S_~A֭3ԩSZ[?|[GJ3?"jKZ"F*ݻ5jL|bŊ]]]]^Ь,AժU|}}bUTA*UT~ŋrMY%YVadd32vmqF4=7T'r 4H%b3pwwGZЪU 'N^ x1Pc> +ٳg:uۤdff"//2 Ub%BM 5[nٛ'N@dd$X6m"VLN"E[8sLB^(JexWxcǎX`*Uɓ'{>}^ QH U^$Pׯ_?qttԭ[G04ݺuCnE,ʨkaȐ!2d233qq8pGU`<{RK4JʩۓA{1 322T2NNNݫUȥ4A"uѣ:tIppp@)ӧOpY޽X\ |v!&&1cƌŅǏ%0 P&Х mKT^-Zy#o߾.$~,1l01~eΞ=jkР FRRR*ȤM$HRÑ2Ymd Q~~~IIIUTx2HiiH$G ]I_N!!! ANN?ݻwȑ#j ȑ#$''lZB9߱p@c5k֬YŅ^Wҥ F+WOJJBpp0`aaa4nܸik^۱cL0h^^uJ2*$QD."""YO:2Y jժU?&&fɓ@@2pk)T~~~[X&M"ΪUbٲe:i>@U`s t]`P`XzZU^fdeeA"H/_Ng'(gMW(SX,,Y'O >>3f(5rmDqahhc͚5x.^ \dL tzIbh3)B"BªU}f@iսpJ`; \/_ę3g0bĈR%yyy3gJ4K Ν;[ٳM6gaa'O2ӧϼ#YEqR 8^S=&\b7/^@ӹe˖/.YR'c7oD׮]H$Сokfff%0g`Z]e- a8iii Ř1c_)[$%%K,EQ033Z`gdCZ#sZ(b"`>mذ*.ZP'>{0>~&B=}qȃ HjժnKǏ1l0ߗoI (Bx Fڵ+\t Ǐ@رc]6uV4b1Zl%K89n?~<_~%ϧrʖnݺ :x`kʧ~zҡElRFh.SBtԙO.M8vXv/`9sj,1 >GJ f͚}݇jUzxi'X-=*!3Zh~W\AZZڥK,hѢ > TBa4yYjs4*epw*:&MFdŏ@C`)S&NrڨDR.Bnʱ<[nt1"fϞ=^l6ENNߔ˗!}g&''hM6ѱcGԩk#l&xg:' qt THgOѷo߰"''iӦseee1n8}]^{5ڵk2KA}}S'VUlٲHۡ`~ߗ !عs/qQ`0\tX-SO^fp: [wwO}u5kN:y]_\(8P>}Hr冹juhn4 $9u&y"{!ODzVR%o" D-&g۾}hذi;H*ذaHII?>>^̚5Kkݯ'%%5s5m) \~zZh˥xb^}USK4h L'O>?~@iذ_I&E ʍcWJXpɛnIv! Pf>MII)2%우CQϦo{IX,S u)Sx SoVtԉ^zyfРA @PBw܂!K`!еZalh_ ^ҥKiڴ)ӦM3={pUW1`S]Y9^}U4i‡~X*k W^o%Qjղx[0 kTD:i,Owڵ\m\ IQ;ƭJN ]8ɠA߿?{ȿ?u#F[n>+'OdĈtؑ;vH]vpEU7q "#Ib}G4/:tb3k֬1ttЁ 6x;葟<^4j΃ֲeK}\qk"*b8]GmhL6'Jڶm… -g̙tޝo]pիiѢ ,k׮$%%?Svyɒ%'ysX@ ؾ};9G@т:e]F$ɾ(?aU:ܮO BrI,B8tlB;{EQiLlfkpfkS|wvm>СCСױ?{||W‰Ç#f"##ë?ۺu+wy'X^^^މ'N9rqbϞ='N>(PiZ]LHHݻRrr3%%őP#%%i۳Μ9矟ݲeS.L > ]$m<;̝;ݻ?N:8رc||,Z%;άYݻwQWyŸWYx嗅BZ"f&A5_h$sxڵbi!R!>⧟~5kd;Æ }>=txi{ 2D>|8.\ Fvy[62Pze9ߟ:#$EV?]i;UVMlݺPmT+s\̙U缻Ta"U 4f3UTaҥK}NR]H"UV->ۆs)x?10 5~(,iwؾ};&##C~ĉV1㲩}CO?- 2e 7f8q"l'6՚p[rr5jt:;wnP},_bv-II2c~!`V\R^_ͻrf+Ś5k&([wbŊz)0Q:$J28[hfλa&Go檫"//[_1bD[nܹ^xPY/~iڷo϶mۤH+ _  ݢV }JZ}!UJ_ѣkٺu+mڴde˖6mTov85__}kQf4]g T-0oڵ+|5jcJV+׿ڵ+Cѣ^~+V*(=p29MhY8$$$pWKIIIXVSEUL7j(ѣF_\܈nE]޽{Yf 'G)tx!NɓeNNr&11իWԝ5RX *2y5|͋ps 뮻3f`zM0ToÇ_:_fM^x\h7n̞=;uuӺu4`7nR`ܢGjgt][BBBSN塇x( >(={[nK{e2tP*T/|ZjwJ?W.ž( &B1|} Yd&҆cǎI]ΜQ#|Q[4g]g~Lyӓ%uX!֭[{Z.YXdn?(z=/m_|wBB;6oԨF!:ty^Aݰp3fDg%''<ƍB!ٳ 5K0Tr p%jV@STˡ1[p4}V7,@>.f͚"m yyyb"!!Aʼn~XdffYׯTe[sR]Q8 unsQ3}(Y[Wo'QΝ;NрlqJj}گjЄ.UQretm_hwH3j* UVN:>ǵLJJyAf/iHعsω*ⅉF˭`4o޼m_rU 2U(QV-֯_O۶m}mذ?XFhӦ rq!<=, .dE[q^{5YfvL f={v2,tFrq&MӞi&l6O<;wSNE^t[^}URRRh֭֬c jCO?y-&+:IKKB\xB'B)pϜ+W).rfJPbE̙Î;f񎏏gĉܹ~{ί^aаaC>SVXZ`v%d @ڬsQpp5pa:v͛Ȉx#e+Ha9N ɢվ}ZlY & ..-?K FQw̥:\rif"0, TmժUWǍ]vuJ1|x`)j V"==]j8HIIaҤIp[=N5 :nǍi…,^^^zUVIL$q!z͘1c<˗ѣMWP}L;v:gوM6l۶S5(s=ݻ;vеkװ= ^z^SR%E&99E]Tbs aٚ>jraZ{ٳgO\BAƍ#p>}x=aUÛɆpZ1Z֘w@[!111e+;~x~~>O<U{サ1@P~?\##ՑVU^D8+FSr(#5tyv;| M6<˔B`1aEu`G:NXV4i°aØ3g6lѣ<Ӧƍɫo<|\>{zbݻ 2n8tRx@/L˖-=3iiidHy>#1GaZ{|>55jgeӦM!^TR%HnV~sNoׯ_P,_tڕ۷+Pr刔8ǃ>Ȟ={뮻$Jrʕoڴi"B?ba$}ф2yd5bժUS6L4Iڒ%K<M6rM7d t(ʨBoByD#pc\ $)))fr#"_|W]u+Vؾ} 6m:e$(}55&?<3f̐^D6mh߾=mڴ\9($%%B HII )kb̘1?9#x3m4>3;rJY РAn&ϱ|Ξ=ٳg9s Ν : {eƍlڴ߸ٸq#+VT222UVe_PN) p~+r%ݣz͸qhBժUy7裏;v4FsYhΌXxMQF '?ӧO` ̛7зo_s:ӧO_~d& ^$H -XUF\Q_|u?|X,!C_hI㾬]zw\֯_џRp^iܤޙ 5h ⅉVhqKFW _|gn&Ȅi Tx>^ԧO>*U-Ë "]|)==I&u.))|ڵy|G3aXh׮>V6m2OuNn!o߾ΪJ FΝ#\AN|?oٲeu'OBM3@?d6̞=hݺu5Pgyk7|Ö-[h۶-OJ~nm!.RĉgttIK! ތA5K0.`wǎ_;tPOw*rh]@%C|Eaĉ,_<*ŗ_~IvfonN%\D|={3yܽh]u€pAgyX M߿4P ^zT(}FAY c\E0L3H^Ћ .R5J۟:!Ak,Ә7I\. ^q DC8֋{￟ɓ'{߿nnݺ?Z,XK/-Z|A733(,^-Z6//gyF{L_VXj4_. Œ8}n aP7}|dK.Zר,XF})%XX,:d$.b)W@F4"Vf͚n`:(rtB Ç}&222HOOB1"@JVR%u b4hD`ܣ?):uTF2O TYi!8 J*UdmEE2}Yueԩ~ndffӬY3TV+| `Ǎ̙|8۷gƍKAQFL2_Zh ykRrݻ(IFVVVjZ[]hHMMm۶͓ak׮- }6#QEQ2QlڴiX,0G0RSS _9{j9Y|,{5O.dM#\15!]ٳg"))J@”yzƢ|/@).]ٳX,vmnݺ G Ad\7o^ gϲyf6lkѣGMl;@Ç۷R%3f[ѣGRre?Gk{lٲ/n~Ѯ];4iqedɒ%>?zW~E͚5:0⹼1쉉Áxo P@ IDATujJ3{](馛|0͛+Bƍ[h"yǎyBYPG([lrܹS& zD #6}j-J(YG1 oؽ{7v[[`\L:mҤ 9VRO*5* _C/PIšCXn=zmGeN7#> wp֭)C͚5oo?dӦM/A)5lؐ㣺zVffI0f̘M*UoR 7ndܸq,T>#>#*T@۶miժ ~>Ck/՚w f Ǐ{s:J<>yʕ+7uԮW_}O"`=Z;5~߿ ]W}sN-6XVIA2?|W\wu/P49v1Ͼ(Z\8tEHPE8F]ؿ4b A#+WX&X0b>=zVZ\s… f @aڙq!i^hȑ#y=M6m޽0rr-k\.W7|sbbW__~1«Ö̙3^իW/_QV-:v،9pI"(u9 ^+.;w?;3N:]iZ?v:wZHFdK/mGH-~)~iU-j;)}CQq޽R })Cicp8HL6p8W+#1Z+Ș $f3ؑZ0b}.G`\(:'&8P%/ڶm˪Ux4r!/^Iȅq=m&>lذ5Ǐ7W_͏?Ș1cºtQCq/i 6 Vu5ST_T%Av97oU{`b1ADVP V##1ȑqW^ ̭VtoD$)bcweQw  N˗/o\8$#EL>ڶm۪F  ,Nōf\~\͛7ӫ'zy7xˌB3 u[̙3ٳ9s~|VYY̲Hi(>p3V2uV{ -b/b0FjԨe Oz0Ӽ_d˜ß%TpHy,'Ar*T9sF p L2ݻR*YyVwyx rw`:}qGbb"]tgϞ+2;;;sūFт+;aÆի3y督ʗ/ߨzL8/5kְvڨ4k) *-[GGLݤ ppˆƫ̟?-[Rzfs=_c>X0:} vO>dpmTI#Efo& p `+P0)P.k֬G9ޮ\RЯ_:.Af~ ˕~GFbb"ժUlu%>>ݞv/G҂}DKEËX>ƍ裏vСCjժ]QB믿ޓرc:tGrQNo 4 $wZt=?ZBt:*NpC۷^vp8~vvvի].=0  ƗXhCݱw^u] X۠Aӧ_Ѱa丸r-1..fKՇ)37:ok5ָ}Nrnq8|K~~577זgsvnۜNU\.6xXg}bEqYVjuZVfs9N>}ۆn7CKҦe8^ u7JJĽowKau:Vak%}nI3S;v,' Tf{6kfrׂ 6>ПWIo@0*HzH幷Ö}u"J-FG-H|<)[2\4ywoyM;U2Ӫ<' :`;Ux \ \'ٷ-fY 3hT*f||"_0/(L3zпZe)P2gmw[{vŻ=cCwO;׸M& fpJJ eA\ݧ~3ʃl2(/49C-[Y$LI%UVh2d7.i ?z!FWJ0 tI^ ƝE#@ji"W()ʎb/-edՓ`cYiʐp81mԁ _4ֿ~Q%LV4YBɵ@w^k(i'#2,kϒ 7'X@@4˄L>eL&GIG0I+)Ɏ^:L^BF@?;3Ql5AP* + %=J 4BoFތ";(䤰(gefD4s8nF2뚅6؀AAL)գE c#xq{oN&Ƃhd@EƂdFi ~ iBw8`g9/@Gx"!a#Ba0ykt׿(2w =Jh)yƎhG2B8+f ;gQbd1e`V/!zD?OY3WBg$J0tq4ѩ̽g.ז``F0Oo浤uicÏ$ì31Ses͈rWES_Fׁq?r4);2%X6./ ՃTRLꠈ,eՓ !ɵdYdhbWMY3d +d ,pf[rЬM4,^ f:.R) CڧbEjD~2{Y)ki&7Zs`QL4P]Åo˫sNfn8S<2 d#B%c%3}#i# >\$#XھX进ɜ:WQŒtdׇ`+SiKϵ66O0XkVi?)Dr6!虥]&BqPD`x+}CpREnf̈5!cɒ%e! o>Q  ~0chy{L`H{6[޸o`)|4qQ8p!Ho0cC$CF8!Q&L0w;4>F8 zdub!mrc> GAabw,s>p:/Y,v(==\(RRBH`qL(%]veYֆ@ww=4rH`$#(V 5;%ɨ A & JēCd:Qh@.E#$̐#`a"1h01)Rq:,GBqefQ?aX t?$i0!X6lHl׮ݽn !>əQ\_uǵ&ʬ*=$VQB2>ĈcI'Bt H0Qa,n(!jF 1}EINNN2e*ꫯvw% /|Q~Eyyy.6;r+VL2Sr8gΜ|Aɭ ? B_4@H%Xaҗk!5^s! bJp F0b(U( | \a85HQ%,V!B-> t:Z,޽s??piV+5yݛ[o\.~@6mNnl,m* s,r"6%TPh_U'--mp0 !_),Qa#F0bA3S=#G~ؔ.X!`1`gg%//M:vȼyh֬.kobt\)}u &1D 2%>> /?(Jp0{c""F0b˗s5p3k,|{EQH~'Њ4H4#B:. رctڕ_5|ɓ'͛7J0%>"dUPo5Ef}r>>w\=0b'MrBQիWn2`[MCOի5n+W[r^{m$O6V! Ptr7sq9ظq#7o]v$$$nذ{zX˽Yܟ,{P aA=mgǎEr#GpqVJŊ to&Rhm[~b(Zˀ:O-_?sΑFjh߾= .99}ff;BHYᒁk۶mcٲe=zcǎa۹꫹Q@ͶpfM6O[FDC ;;[?vi=c(-H# up=/33s_J2uϫ,y"7>>WXT0\uɓ'W_̙3Yp!~M:ueBF"4ES\#H",m\rEvD?~oW>d^JFL& A| p0j(yS7m2}tv P-))iǻVZ'+{FBk#  Ԙ &dKʕ+ѣ .rX֧v{r\\#g+F47x#s{ǦMw3g4K1\!66P]D@p>/??*\.׃|{4n"i-K6\Vk׮%6MB!6j5ܟP] RQq*D یU&fےv;wndj]vK1ǁΨn9QxMr$.&: !\B+ڠG~ԨQI(3ڽ,Y"l6[PeJOOG+++kLq3ƁohuPnVO;cB]k˒%!.BB4B4BTrԡ!DX}].d%YO4GY TeO?KKpK/>k:(> ~1" дi">+V8y Q!q,fO5|pGPe駟ܹ3G\r/mܸLRKΜ9#bJ{P6dƀmv.z  x 5`ҀHHyƏ϶mۊdW=QBEa˖-<#_:u`۵P {O^$6m۷G?>=cU/Du8y$?~J_'_~)$ۂ5JsYb~ŃyN:ѦMBC0~xv{%K΢ 'ފNTB;T0:ļyXfM75j 6[n$&&ۢE9;vp;퉟cǎѿC*oƓO>o߼y6QLD6%튵et0Ap!*5j#EQڽ$A$ǂo߾|ރA-_m:X͂qԩ"{^ƍ=999lp88"{@nn..+[<ݧt?)Qx-ZĘ1ctÙ3g?>GB WO>G}-[+TeoHa>0fyiݺu 3={uNSXimA}ෞde Bp?0eʔp0sLu놢(>裫4hoE7hlPcB8rH5|~a7nL2e7nxݻxrU8{zMF =bm=r~rPJ^Ǐs rssIMM%55ڵkӫW/4hbu\K'yQD!#999\ϐp!77N3,fZ}9P]-yzuLz50uw}!Oaw}X,?р1o&޺e$>NYt)C!o ///kȑC}7)M2*K;v7Zv-$&&Rr^Z+z++]pOh|'.dҤI,\EQ<#uFGe2+(¹s4 D?Ct5!-b[.ɪK.PBE:))G~~9KB$  #s 厑mlV2U+???_ҧEՎ)ɨ=[o1n8Μ9S$ػw/SL'f7lp~ƍ߸떞>}:o) 2/4 rZ)2o߾l۶n!Ե63gz2Ng fڵ++[>$ 1uF999]׀dh}Ij(.(:u\z/"}N]zXREjժU1%##4ƫ]v=8.Ƈq@s~ank.v/SO=}G\\\v='ݗkb$H J2H0)n.+YYYZ`D~~5O $rss8]Mp|u̎+4஻bڵEI&h"fϞ͕W^I\\\JΝ?㗆 ޳ܨ.*v8gf.?w&M|o߾Ν{Sm&RoD,,i rxơC }_U#uQu#04b`8CéS$99 *G ջ#ǍʩVXRh2hBJ0 c=999Z @M9t:;v,s- ox}]>j֬fguC| sE#Z"R+ygBX]p>[B\4dee럙WVVV.wz;Y* `=*rx饗HOO ?ӳgOzONr]4lذ?ҤI _lXtرc@r*x=5jz޽u֭ ~dmlF2@mqzljrVwIIIu'g1Dc42+n\nVٳg۷oɅ۷om۶#V_nݺ xˆ jC4Z; G0Zn]=naˣIt"GEQ<9s&_<'HW ˤV g>,è1o6bXt)+V`<$&&vҤIp ot?gϞ5` \HmF5r#&3f0a„].ӦM/?~ԬY+VL;w{ƍۊKE\<֬YSNfUV ???46˂Q(T\Pw͉'N˥I`Vј58rȻ*TX*yyyʹs甬,KF.OMM]}voq}+bqYVfs\2Cܨ,ъZ )++]J*>L.]i߾=qqqnpjj |͒;x=[|޻oΝ)6zXFFF/FaONN+_ED,':uʉ7ЈEՂKcfz L<ٓu+eʔ)̟?(K/y&Lܹs*e .{i9z(Ç/PZS-[ТE ^}Unz衻;wܬ9rĎy\b /P7Rgff[e3Z{|?(2YfT^P֕t*Vo u"8sL1-LaA5rןV >Bt bV )cdx0,`a!غu+kצJ*~W[t ߘ+[ QE2JTӦMG <nan^f&&&AnTZg4>}NKK'N8P+R+RfHG*Wܹv 㯿bȐ!t҅;wr֬YK֬Y MP,0_&}&233:t(Ç'3SMצMNvt_C219`7\uܙZjqo1wL]YΞ=vaÆ\C^,2rUhN8P,L6}:++S E`ɓYti`m׮ eʔ)%ިE)V-ȑ#. }YFisðȝ 0k,ڶm#^ z-=_ӪU+ƌC^^6W^9СCS۴iyl_!F2BYrss3f \sMAޣe˖lݺ+xןYxq/å!L?/JzQ{(̙3p:=vEc/A]rԩ{;xHHHxҥ0P6Ɉ"j+ͅ믿Njnc޽WZ"{;v̅z! 32Z(ٝS /䝠ݯ_?|/VXj*._~Ν;{ԨQc7|l޼yn_dDMlŽN®]h۶-/rXo>:vB`ZmwZLj@Qe߾}AMG]v3c Zj_~h޽.y z!77w<@Yh !L2,ZH-sJ>#&GW !Bѕ|-$&cp#n ,aCx5S2&c(IϞ=9|p1Gҭ[7^uEرM6 Dn4-jb9 eQBzIÇѬe%={_~O>_?]}Ջ,υ^Sl΢s>Guq T ƁޱNf=zt}Qfw\ !~BB D_5?..X73g`7hp\@+#,p@ IIM?ZzFc,w|gggH"R^p;w >˂z6mgJJO :yg_P@3}|`1X۳D4)333?)hkbGjIxgϞ*U:rȅ9\MfG6MPε1\`}aP`8PhQܸqft:b̙裏иqcgΜ[|9][" @Qv\VF_!E+[c4 @1ظq#Vk.;`Ÿ}6m777UF?}bƍ}ݠi|R涖Ś5kPpA,3кuk( լY:5nx,ד$ 4XGEXSN]KJJ2d9ץr*6^3`%M'?۷oٳgx)={T 44PwbJCD â .lSr=bbbjlb&=z'b-eee!++ ~- >38999wwVܹ⨨WwAhҤI~_~`oo -pm>Ƣx Bɒ%իs6?=7 k޽W KD>DTTC g4hŊVoĹul=' '''Mcǎ%""Nc30|֕ڻ`E55N* 096 ں )r}%>>\]] FDDw^R6os'VK'O&BatMRu7nX/-=ۓӿ F!h;{D anݺ _|y488&XOW\[ Ngg%R޽CrJN111ۦM<ɓ'Hf֨QS.l;h)XTnb} ^()),.G"EHӧ1}+v`c;WN(/eCD3(}6͞=իgw0 /_ΝKIIId':n(I2==eeeeѤIŢP?|f^n۶m]삶҈#ŭ6 B^| `q??6oL^2}F2 C:ADo>z]vx@Gk&ꀕh+rN08+uxo!"T0 d`U 9#`%xEYfw&ggg0{*UuEܹsU.bʂ4;px g${w_}ÿWs)44`dddLޭOڦcǎ|;-Xz0&!& gM>=ҥKDD} c*0 =ޡ`~UVÃƎk f?ד'OaiөCySTիVZsvjvXt:]λw֭[...ԳgOuQzϗ/_du'JDD֭sѢE 7,h Vz2%߿h!^u^V2exC3g%&&hxzvlכ`%ESN-kƌ$]vٜdj:vQ/_U]NO毹vR.eg pM Ϯ=kZ8pÿUKR%ʕ+|['$$Zj-2&BZd!h' VΝ;j/FI  bP n2Wp?Xjek F21JU^ TN~J>z! 5Rw!,"V դI9o<> o[X͛7SJZgJE}`0_TToA 8@KD^$>`aiW/Rv{O& lX,kKex"y|ңgK,Idԩ|2h4tHGٲech߾=iJ*/ #|S|f t k׮up,Ctt45kcǎ|||GDD,Q'r\N[7-)wc;s xw!_s{)b |2ʯRw^"pa\Zp 0޽{ҥ ZlHfeԬY6l)RdV]ڥH"8%''E8~*Tɓ'c0`\]]%/w+VҥKnRh}?͛7ZgN%K $$ś^0et?oݺ8xƗT( th, Ky({{L]5luH6l ">%X; N #x FC| T|/JEׯ'K.RYE*S EGG}m 0xt=""̌}w[gPe$hIFVmڱcOW^= ƪqŐոB6%9[yș4/_.ʽ?<_mP((**ӓ`#GI(-(ciNLDI%JW9~z_ZG]H'`VY^zd *%mZvѨQhܹyfڰa}ԵkWP)\ӳgO'){=233qU^]۷Ks!"W 0fϞM۶m_[-V#kٲ%ϟ/ X"'"ڰaf͚m'whxg J IDATJ]#pj8XM^m:^-Bn޼y bHq6FB=$"gh l-"##̖$Zmh]QK… it]͚5yc`5rxs-$%=~T ITʕ+cճ98;oq ɨLD9"Jɮ |^Ν;jH{UECp"---{M6wߟo۷;5;CTTT?2899 ӧOkX;S]9F‚ݫ= Z"zJDiĪ":3++rnma>6z=M:լRΝ;륌ExM:̾%K]` 6m$gFFuI^///{.mff&}7hЀoNz>:߸q[ 5RJѹs ÃւEzuHlj<9gϞ|}v7`*h֦  i5)S{eĽݻ;^↓Y¥KB`t `'7(( LD~hhZ 777:pJ.m=*J2tPCձ C]F0r'oǡDCD+\ÿMk[}Ņ` -1%[azw+WhD"-mRDD9]BA疕 *W\g`/ 삢%`7|yHOOoID-h ȨGjCD:"j߾wN׮]bѢE~2 CK.%"ӧO㏹旚Jjբ zYacǎ";>Ki( Y`0ߺu,@gl~'b [#7k9=&tQm;`^?~mӧO~8}tdÆ NҳSZvJGa-8 zDDRǀ;!22ĵk :~`O ӤP(#--e AAAy&܌ԩSmذ`Ț4iҧs̹ ͳӮ_]v o.]ԡwشiC dMxxxܹsX"H|!#Gi;smM(.]{΍1K.5:cl޼_|s֘4h==gȑx"N<)Y2e`ƍ44̝;gφFfΜ90a`0<>tP6mD#gL1qƖ`Nw ݋p"tYδ|r%^|)?#r\fMQк/[ƍE!ÇB www)B?MO+Jڹs'W!'sQDD惁m{-0 WhԤ>k"{LV_>c9ܺu~Ocǎԭ[75jY"#p"I&ɾ RI%KOݓD!!!=Zdž J}||8,ڵk4c 4hSϞ=/^ J"$Y qܥ!`"V"Y(I*^JDD>| ` rg+dn4 ׁxo "U1 HoJ*R-[{d0 a`b_ vvR9UH050D4̙3k'hDD+W]{:uP!Eʆp:}$b'D{ys4prr'ORv&L [a[ۛdS~RZ;dhڣ`.7 FDC}OTVkɓ'dɒ)06 xU +"v̚}[܇e#OrrrތrKS.h4riIiD?=sٳg%A!#kD%ZMH/|Jm۶4hټ9,B|ᇲuP9r$WrWWW0` Z9ȩ˗/(## ~v/vI>DGDts %ۆ1cs,r!20b˖-]vrrUzѢE0a1@/^^E-0.]d>5kƍQJ@JJJĉ,_r st1 |2ge?ȶ ]`'?h4L6 ̓^a~G|Ft:ʔ)hVͨ]ׯ'"Ih.e`6@cuԨQvTh+Çl2-[o߆>|x(88xWh䯃q[@ϣAօ/^l Fu Exdd$y睂և=z///]/VUg<}Ӓ%K~M6 Ư̑7_|zwpJJШ[Ȼ{-[\bغu0p|b 6 6mֻwo\{ߩ\P1>>HHH0OVcϞ=`͏Nj ͡tX~=7on#F`㡡xQ͛7W^ իWy>|Ȱ{A˖-e˕ɓ'c(V֮]p 2W6lVXqFUعDas0amt`%v400n݂bcc_.OIIB}0~yCv1`ٯ˗/; >Ε+W/:A. 04n8`=/^29lsM6b0X/=ݵDN`dOADcI 8}JکI&}ekxlDN/UerK8 "!9cLk'GK0j*""2 ޽{I2*dpq2 V6l;?~|ſ︸`%4`40A(+^4}tLf5f͚Diky6l2r6F*R׮]Ӯ]ߴiS>~CXOkС "##=( ꫯDB 8pÆ ]_~}kMNNNk.urJ0 CcƌBS=$#C>lڴi)%Dg6m&ENumo V:1T,o !ΩޱcGYFGȐ5ؓYXѬY3Q/ndȝhѢ&#\U8ۋ`.u;pQg=W 4~l-rI bbbD}eݒs14222؛ Q9 JQeI`+W'&uQ Gqu7:v naE4/@}\z;[Ϟ=;7ׯ _HH~`]~12~g=k @DD[?/G7c~BDωΝ;G ]Ϟ=[6.E^RXXd5rp?.fȐ!gZhl9~WU^l$ɾR~}>}:A?hL~)--ͦF1O~L`Hys\x[! _  ;v(jÇ넮] ٳڵ b,Xdk{,cmޜ'S .5?z#"އSRJ6 k}RC222$5lؐf…!O `\-.p"(Y"6`9H`kR{ȨSN;Xh{#t_koPǧuޱceffF5.]?nakl0))we+W_})ʕk]4۪QddaKō&$$%b=yY#7oQjj<YB'yOpR 4{W!*VZf2߿/9lzȹMn׮x͛%X~/EEEa~7"") 6,ۯ\L/yJa^x>$̬Z!sraqS}rFNt +^:;+ v*u U^^qqq/*V}^ TȂX[KJ?K "]Hff&Əƍ͛V@ѢE1z|ݻsN1iFtԩSr m۶Sԭ'7((v͂999AV H^V0y3f̀^Jr7o^W]l|خk?d`"Rب[=RVt@mżyxO?ڵk999l; ϟEΦdTmS HJJJ)))NyNP| ߗQ#… `ԅåKбcG |3:6{l8;;>Szh4L2E???YFvطo>#-,ABB#y_~6*\0dB16`ۛ#P痼@ 7alkRk`ĉطoZڱcǢ0^#K 2LuN0F";᣹Nj}^ rG8aJ.HRF"raEp N:Zja޼yV_t^)t"y*TUtiH 9?8 gΜiLߏLQZxeʔ>33͚5Iܹ͛74h) 1 ʼnu{Jիa˗ =FR/̑Dtt4֬Y(]t1cƔ[n?~:/ Νy{{;d9##!@R(oafeei OD; ɥa۶m}b;sX~&|?aTT { VE4(@N?`Ȑ!PT̬YfYfza1z) U^7!/PDGG_)Z(PbIu*W Ğ&a{c˖-<#j1j(O>غudVZ'OŋT,XӧO}7pwwGbcg=sx%eVb ={˖-g}&:WvmT\QQQ1^۷cذaiѰaCSN% n3]r/]`7S~foz=F(OPsRʞ 6w% G!gT"k||.+}%[E^W(u0@.θ9X[;r[yHaͅzgܿ ϮRx۷o_A5 Pz ῭='rׯMΚv\͛7iY>u{`8:`'Dԫ=lo.mܸ@ܲe7}^v־sbP|k}ݺuF~];(Y$ƍ+ONz1n8H޳d={6?/Hѣؑ#Gxʕ+Wķ7c4XɅ'Ihذ!ݻh֬YëW-Wƚ*¿4LHJ/VlYNMJNEJho!_d9k!Ocذa(8ܐ IDAT]4UԩSh׮E5|0{(JՀC4G2LUM 7E:pwwoժU1H Z 0YYYK$1 _~%꫓'Oƃvڵzʕ ӝ;wPy&ox)֭[g<5RJqiE_zt3(#555_y/,]WX`6w\a*\wQ2'On)))O%9;;cԩ .DzzEuwwǘ1c$ &OR 6m<^F wū & - r?PB87oDqQ@HHHs΍ԩ?cmi/8`&&&B=tATZl qVV5z]v-<=='OVZذa@V :tֵkƔ,Y&յ&DFFº{(VwteгgO\v-_Rʔz⤂LժU߸qcՄ 8r tVGqt֮]UV-O~ B٫W2nתU߿RǎT*>FKSjU9s_} &&vWA~L1Ս{$5KIlJ%)|BxBAP(0j(<>]vÍ7$,YRt899 ` C.nԫWO8ZƄ `0Vݿ)gkKe]X V-*`Na C\UxQ6"CԩSFzϞ=Cnݐa ''';666_ϒ#RH85RJuww<'HFabrb!YYYuooo K~6kUV}@R?`޽oѭ[7/_ժUBtyfԨQW 5k֚cǎ}@5uJ ø%-c =d5i$bʔ)UΞ=spppGuAڢE L<"P-[m۶ń  22|axx8%+999rRDeszgd'Æ =jq8z(޽ktlΝ"]ʎ51ţG$K N%Bf΀uףuօ^kfܹx B\xqJ"xڂaf1Lp!TbxUWdRAVlM. ȝ`hԨ1x`رݺut:O>FNitj5%ϝ>}R[9{nM9WH$M!d`v1bɩ_lllO 6mv؁;wի2dHn~Z_ V Bnڴĸ͛7烏E)x˗|*U?rH~k lܸ5kִGXX۷sA^VN8B _|9*|b oa.i 'pƢ񶿿?z-:n*ŐR2|l#G@NR,E0* :| 80i$ 0n*&MkZj}Y5k֔~ 'Ѣ` ~TyslrX(__~i )''`Y:uJxwTa~la0ɱ\;Q*\])baP&]x=|MYYY׈ȨAgΜ ???e00{l4lؐW)Zhʕ+X7 F7oލaErr2틾}Z죟a,[L$Ej.]:0lذM4ٜers i4~@*R[.=pIX.G[n/HHH2p CӦM%xbƐj~`0hal&`90ѣf͚"/_Fzp@```ӈC ) tt^;(H w-r骚I5G&}Vѱ'Ny)))ŋKw?1+Wu bt.JCRqqqɐogS5G)̜9󕏏4Z600ʏ?1~~~yΩX踽գzFDDf͚ظqc3x`ԯ_p֭,Y2y៕*UjpڵWZtCj.T#r*q-e''ɖX/^,yVZ"`_"رc%+I{B=?}Ttsc7Ctt45k{{-Z <<F'%K@T=0 B<۟࿵ǏsCTC4c!66V_k֬ C Aݺut|'ڵ+9 N)SEy222lQF]\rX .9\#ѧO"X#SZf 6mB\\9)cmn7(V>CYFc <---9)Lj%Du֕TND޽5E aVڡ$PEnn.KH?`i>}Hzqr%& (r)C̼,<PlYǖA>ܹyc>Kl6EiBKZdmիW?F\Z .֭[hԨf̘/՚Yfi ^r&T5u*"ghD66@BNѸq<͚h4XrΝ;8pɢ=zX "Y)RP^=sR /%7^ŹD.xY`hڴkojo{Fff& KVGEE}BB2 : [.tEjonny-f͚E` =ZI`UɁ#>>>N}WvWիJb.p .VݴiSOঞeYǓO<֭k)bbbСC߿E~}5k[bS^=5xbb╞={q`j3IZه wN>:9۷w9,_ZVt:t0:vYo"#ݻK>{"SFƍ@BF<<`J8¬oaÆP*}A$*`:WSN!66VP?8pce0 QFYeaqF; Ŋ|̙c~zjsx'+A&K0)RYqQ HT*-Za~ͭlݺU.?r sCH+;ģ09BN?V=3={mH Sز#==]sСŝ;w^iӦYe8p /Ax~=sp< b2%B!$jwj5J(r|p 4o\T~9`Z)ѱcG 33?fJu/ʅ~:_6PT={qPj֯_ySɴE `6l Z%ZPF?ݽe˶ 9r$'2Ua&)?HKK{UrRT(QB-8%_XF *ĉ8>>jw͑ 9/F& TBRR(9 yRjgϞ}!˚*qRaR6Z.]xe b&{?NNN2e @kƎ*E"K&I{HIImܵʍÆ sZqssCxx{ԣ o߾ BpBTj>1'|( lٌ^p@%i (999 6{6|u[#o0cr8Kw(4K0/^z(Q=ʕ+۵E5pԪUKtn۶m0aʏ=$\ %G.](Wdee 兩S=5kGj֬i/^rȑ7nH{!,69CF$c?w'ڵo K_ϟ? H%$CVEdɒw %hm?CR#G(䌱ƗhժxBB~7-?P(ڡCDhԨŋKMR["\,I ø0 SaWa`Ƌa_a)P(( vcZ R`0+WnRWTߩToU*TJ5ERMRT_T/T*XJJR+ʏJJRlT*[)&NNN-۷o 0S5[*Lx/:)S bEs?v܉+W/^Gy`* ƍ EgϞVCFr )\PCoD`}ȿnԚ;w.<==_1)k7Y۵)SoDZY{>t `7%bXNNN]tpvvт !Pl`qO%ӳ>`,e68ɈBP 06M.<~II0[ x+%%J0`spEp\zUr `c=!*Lh׮_DFFw"C"„ 0fG_r)&>gJعB.9: M6E~'OLjsI V@!`ܹs.Oa};w:%ȂHnBғٳg7TT0`s̑L)Z(̙SWP`z ǎB֭%1=ʑ%ϝ8q缼ݻwǹrsEwazJrnѢEJ/>r-p9e}˖- NI HBnM (L㭔`+VLN!_#J^^^Xx1+0w\4h7o޴YOǕ+W?NYYY۷/Ν[b0Kܾ` i2a!^j;n|dW(J,Y+.>O<gϞٙjժhРWkݻwcҤIrU` s. 777) )(dBѣσ?>كBi`u95j={rDDDO6dWljKaȑjjĉђC ^XO^`#  )״rLŊw}WIiѣhz; ÇVZkРӧ!V75I% ~` *R:jLёWzrb:thܠT*SNf~~~4+?Ǐ/\},`)R#/$)#+W.>##cƠ L2_es|ŋT///[@@ѼyI)"{Rf8/0#E٢z).9֮][n,oOOOrұL˗GBBd_kaܹ\]6m7ntTWN'DCd [;wnu6m>P>|B?X.]ҋÇGz%EzR s*x|6wwwR~}ؾ}Qg̘իWiqㆬ {n3RDf8KR;...عsEEEϙ3 &sч!=~pvr!inݺ ];v zJM4 pЕP!ԩ6Ua!܏A %S|Ƒ#G ٺuk,[ G@X#Ro -p%ǭ_ʖ-,((:t˄!88mڴ\v+WR"7cQKm.gz3ĉ_obɒ%VT 1~kΟ?Q2ΐBFڵkyz/ѣGhV UJ.%Jݿ'ɓ'O>t:,2 Ó1cD@z  ߦĢP)~º0~~~@DDbccRm۶UVpuuu޽{-[<1)Mh3[n&İ ?$777S WJEjڞqTvBX8R9a>1{l#UKPn]>؃nhǏkc,j;f@g۷͛7O>Vw)km##ZR9{B"%pqww_j;Tmڴ%K'HAe˖hڴw1]-.D"KDNKhTR{UjR**ZK"_ZkWN*b>3ǝ3sܙI2<ɽwnνs>gg@ݺuQn]7={͛o>lڴ r%%%%#FبT*ϳ3M! y brr_~#TZe̘1 F90f] B(HcN@QrA ZXXsc۶mV3gI&̬~мysɻ%P\\7n 22Ro˖-!H@uE,$%%ᣏ>=>afǣYfM6yf ceiS:KgΜ1?WZ۶n݊%K@*w/0+n[1Xkp g͂Ʒ`g^ /?uVZ3g˗1f[ ,D"AIIIqF>ؓJPh{=H0tP'80gSWY\j*,[lZ>pւI&1W_}ݻwtr!D"Att4|MWal߾>>>/;wރg6ƅmsss@BBsP(0|pŴe!c׿:-;w|RTJ\>T*/V[X7nեr#o߶jŚ5kD0XbH۷G`CڌJr. Rdd%&޽C:uԐFIH4[]lYJܓgEJK00%$ϱ ޓo^vJHII?4Do믿n=t}jLJݺukrv=))Y}QA Z!V0Cb8qb޽{h4[GB{epJѣ\nݺ~ggg\lٲwԩ'6یl Q{oe2fsO>J;v8 CK/r!P 2޽{g޿ MI=B=D֭[3ɉ5"@X AAA_E]Aoߎɓ'dXz5ܠh4ob5D0T ;h.sNZj@K{Jmۏ?VZC2N*%hS p¢}g/ >39碑BPQo;YyB֭[=ji_>~waÆ d27  tϟt҉!G.eKT`TJ%%駣 I?>>ٳgBR)~GfJ[WN رcV\O?F~cǎhذ!jԨڵke˖޽;  &`Μ9ꫯn:O<rgddׯn=X N,C." ]; pp%(Og4HV>#C4ƂBԲ!B٧O%%%W`ŨQ\}*jb~:s&M DӣWP<u4_1Ew\LDoݏ`<3U)Zvma{ 6 Mls!Ij]tc֬Yz_{5ԯ_qƟ i7ߴ:th?''']5̙3 .t3~~~/77o`V81 A&ݘ9ua!!!e۶mC &̜9}-?Ɵc߾}8qJ`` ڵk:}ҹ'̘1"1{l <pʕk]tʻOS _%,fE =o͛)ܹ+ ;jԨN:Nx`C&mvl͚5ҥA?Gի2e \]]ldbjժJ*̢Jq ž={<={ɓ'ǚ4i2dqcNR /#&G:uJoǏa1M6 K~z c(\1\}Z]53Sdaaabq`|0W'@.]VQF5/J1b\t ś;t\nnW6lh?jԨW(8qf̘u>s8r?[*r+Mhh莜UVHTbذa>~ 0Vd@=@de˖5M64!aH_Q\\[Pĉ3tc˖-|Ah֬Y^zUEL bD{PobVl*b/㙶`P ;!Qp&MtwҤIoo޼nݺޮZjӧ ''!CUuk. Μ9]VzЕP^_D!D*V5 Ovhh's B=iHRe@xx8ׯgZKRDDDAFtt44hH 8s N>pUcǎc0oQFСCHLLÇ+v*bKM4߿ !T3c WLL=j0% 6kY/\Xy0tpvvF\\tN:!&&nnnXFH$#<<=z/)) o>aͭץloOøijT,ݸqhTggП-Z˗.B]}<5k2QRRn݊~pZdhܸf۶mQ,']!233o>&65hiiia,|wO&MaÆ?>T YlRJ9sظ9\֯CUVHHH{ɓ(%2'$2uMB09b(JxxxJ*rb.Q ^{'{رczժUܹsJR,Y*\.9s:u;w"))IYiX}X0ZeuM62hWXX""" 1y1(dbtJ://% bbb.]m۶V!BPAhРRcHKKCFFF,ܻw]veCra*% VFܤڷvڜƍMNN}Ϟ=ر#2336m`׮] Bt۶mC޽QPPFC^^^-=H$&Y(dĈLZ|q-4i;wS2 l2uG$&&nrCH.̝wDq`Fzjk+̚5 wBp^lYb֭BX&쮰!<[.Rwvx cف6}E\4h$;;q?pE=:W^Sۢ, L,#++!4d+됏N? ~ӪU+P -QPP>`0>b=Jسx քuҭxkVZ߬uA*C4hzUZ\.G\\0{l(Jر6lۙx!$ bY/Lҋ tζkQ nW֩SgJBB²5jH8N:ջȝ;wЮ];hѢuN.5AYjBZt5a\U%I~[oKB" '''_\_XXr+hr*{!>|]{={xjժ՛oyxҥgt jPC_vY6ճd 7˂a,DbkMx   IoČ8\1_SY۷o$cc&~B(ne6m.py}ǐ!Cs0dKI!gMT]VG-ZAK/ZjXKGbHKK \nڴ)֭; CAOz!FL;O%/ N[޽{SN-nР`߿;wƹs.t[nE.] ep4jժ%z'f8q" @aaa+ի0>VXq_b_bvi=+0uT5jN:ooo'|2r޽={BP*l &ЩdE xxxXL]u@ Ϻv:dȐyDݻ, FAA gZ0T*UIVV}\Xܹsn2 Bڅo߾LA1~L2>;N'^iӦpn֬/[L$ 33.\Ç#'rssW{DDիW@qOOOxWM6ary4QIII֭[iq4S.R?&Y1bbbweZj ¾}ХK:uJJX~=*D&>|+W;w@Tɓ'P*ɓ'(..;<<< 퍚5kprrh[U*~y|ڴi"%%%oZw:|#f0ǂH_=4X1č75kg֭#իHV uJhŰ%î˂{nQKGĉqF}~=<<¦ӲҐ - ]ydƍjW^>OX{䉰ljdc\Jddd"wشiy]vIII.]? C 쁡,Ymgb;y&M:,۳|]]]1cƌrOF/ĉxqo[LL 7n&MqƈB(Tc?0 uܽ{7KR Ǐ#saM:eZW /ٹsJի7jժػw/qq 㥗^ʕ+uq eEaa!9 'O k%J EZPvmhqqq]vWPP^z ۶mc9s&>c@QQQqVZ:~9ɨ ;xFQ bڵի6m޷oTpI-o6b|,:S#mޯ`j(V {'|r@Ӹ>|Rk `!$`(r| ?;v08n/QM4A5 -իQzx,//$Xi DR#C~~~͛7Tddd //ʁddd ##C 5B^ЧO2\~`%7nܸ sȩ,4**꫓'O7lpك_|QZȑ#L2d[ݻK?~R]p5 _ׯ#==_5.m\\Zn֭[I&`bx1z0={6 ???Ĉoܸخ`nu ;k41B/=bر /^z֕c|J` X~~~u~}||xyyB|azBP囯ЛRSS"""ҥKmJEA=zD 0Sm?/06d2ܷo_}ׯǝ;wӦMkCK1G(t~tsަh $$N%t q9̝;͚5C50a[\9s&ׯڵkwCҚ .{l- OkBrA`(ؕ_ܜk.nݚySZΞ=?M4A`` pB>|n/`ڴihݺ5k2)CDżytBT* -\ED1]Gٳ{'ɓ'c֭mxu{A*J͛7uM ?@4΋%`K u`ժU EsU XRSSuGǎ]xqJ=a~= &A?uBSHHILL\.H0rH5SZܜ:C\\E IDATWcbǎLɓ'B jԨ8q"bǬ`<7S޲e5Ν;ѡC7o^uj>|j׮h̚5ʞ[bС@|| X$(JL?JjǎԩShԨRSSAAA[lrз^?Y %C7ѝ={6^.ww}i˂1999b1-<ϘK=!b x;RRRL&_xq'dBwO%%%:YԵkpd--- oBBBвeK|)NYYYXr%PjUظqNƲ^DFF[n)aH]4>H4Kj;tq׮] !;OII/Zj> .]mpq㐖XJݻwc E%HdL4 GߤtܢBH46IJ4n 7n4˭p1ŐH$)˝Q_hŰɨ8/b公Jl^Ç۷/`8;;;=zl\\\ݞ={.zjؕ$^_lxR.[&mX/XJJ>Խ{lE.H,(> -**mÇئÇ߹jժ`1BH}h¸{`o8tmۆGY}5jӱzjXK!777nƍN:!,,ZT .#3J58v:ڼ,EDDJE!ڵk 2>ھk9X(VM17H.]F}ڵ6#ggg2sLG!DV˗iɺ9#$$d:dt@KpkG]iǏ-;N\eڶ7_ӶGBȖ-[l_Mj5a͛$))&msuuյ믿 xTpk[ `W V$-9Gh"7nNGAh ZM&Md[ݺuIffn=zѣ_@廙K7]Y*Â.ȑ#yJ׎ǏqHIIA<:t sk =!& k׮aݺunV… gʂ女|w# ]9{aÆe@~~U]%(<==Uhݺ5~'13f}&D{N;~ w^x%D@@߿FcpRHHHW_}5o߾4i֯_oժUݻwX BsN1 us-Yt4nb"q BƂD"駟:"$$7oƶmېs[PPWVZ q`,m1cy5^P }fͲHfB)S… 0`d29''''m?aza, YhY6дgϞ5f1|?رE9{l;v qqqeϟ'NqnBipy$%%1cPsVZ ĭƬ R|~FA#lh0w\lْizZPTTSsθ}6H4h0֭[<`m2R˄\|$9996lonٳh֬,Y#F)K.}b{y)$)عs'Sxx"Fs=T*rTR]p5c &ū&FU\\TTT4cYhdFh'B!WPvrrS(1;v ʳ999+G#G0j(}ܹ}+Wd{H$jLvqq!@9` ///KM?%RV?!(JٱcG!$#@,FyD1c )) ӧOw}W>o۶-r?1n8ݻ:`ٲezX7gJ\._\k> B!TVx1Tzիt_'O6p/+ /_5k^+ . 7./_GLAh777(s|QbU% |=K1x`6nRa޽hҤ lق8t8vؒVZ%_tT? ?"H5_:&0j8pMHOv!B!^p&oˑұꫯjsvv&'|:un޼I!Q"686\@p3<=a} BH{BTB&BUBXgΜ!-[Vo{=RRRbGJ:VTTqYYYNQhI7bk4{<ӧ3Illlݝ,\Pt_={o߾;(([yM6߭[7;~eTw&YأA mA߁>B.^h<"""䭷"2Bsvٳg4vA"##+F'''/Gk %p.t :[h'5% @K;J 7MJYC$"""#nNNNdպWTTT#pIBݥlB}c-ƍVstqq 7 ;6S+ti$\of EEEHIIWn]h]D5ǧ,(SY9 }N XYJǏ/s*:uGvvI׷ Y&5vrr<00oZ}HTHHH`LbKk!*HB0ΜoժGgg؋MNF8x`䯷g,]SLѹ{( ԩSgΜ͝;w^^^p;n $<%˗7oݻv#>߿lU٥[.Tr_#33ÇZ*\\\*FT T^ܹ3 RiwwmvΝ;BCCOi'LNiM%<< 5;d 'N@˖-1~x|2zMo{{Zh/ 28r?5PvRa Ġ> p*H!F0ɓx뭷**p cÆ Xt)?ܹsMs}vxupwwGXX^*A&)~ua!=|VE( `ĉ()))S"==+F5aBgj!T*"mn2z~BFx{{wW1J3>ŒL66ezBTh"?S{LBRے%K!wAannW} ?[$Mt~>(J2qD"J-LWN6mDXI׮]-ڇݻw'7n?EEEkh*Ut\#_Ci n(#AE|m \hf)gn~Yڵk ޽{d-))I箺sNRvmLR׮] `JF Ԏps/?@i:ZcK1\^ <"sRa{$ݮ]fh 0eU,?iܼyG%;uT ` Mf%vqS_|ڵ3z>uqwwwtB|bРAxq)㿴3Ԯ]M6mݔ2ѣGHIIAtt4ngOOEO?6BlxgϞ8? `u]v7n\#͞&pGYgY^j(%t3V^Ԇ6hpI\RA*z>5K$/;d~U v܉hlذFͩ ׯ_ݘl۷o[nHNNֹjxxxE #*?K*8:Pzux{{f(֭Um۶ ǴiP~}|GuCTb„ hӦ%H>|.` },Ba¡DHӳ.efdgھ};1yd<~mV*سg]ƺT...M4񀸛TD#h2_G>|8T*^z J|%X^eJakU sa9e5hp#bŨpeń pQ7'zt߻vJYu`q\6L2/.N u III6nQ@ҥKѨQ#\rѣG;B)F2D+$I'@zaDEEa͚5Ҟ<,X8:t7Ɯ9sPvmSMC̒P(.IHjժk׮!!!=z%^yfԫW3Т!֞- 7nElDZj*@TT hTd ݻwuh&,){(UܽtDx`ȑ޹sGŋ o 2[Ƃ pB ]66mj֬{&|/C,j۶' k'BT͛.$`bРAw^e5&(..|sqvvvѣG(X$C&4h;vT^#mB̝;9-,66:x !p$r`\ҚY*,Y Jl}+%E.!EJ .p9 j5 ???p5Q a_[M;+̳ׯcؾ};ڷoZjBnݺ-@'٨U۶m+p)#::>@Tzxxx>믿n֕/^Dk.( 6L †~D[|ɪGjZ[t@| :BiG+xIC im6S=X!ƌ#H$u6 AhhgsgC DI,"V^m8N>#GYf]vp)Yr+v Ƈ.YD#_~eG?M͜r#x\Z4W0pVA~Q%[f 9J!Gmʔ)B;s 1nܸ("5dz W Hb[e!ԬYϭ"\.'G!RXXXйs珏?~B4 ԩXэfQOW|-B(@;.|e`Zm_'''%Y+c !dffCiM޷W@>J lUEia۬ ɓ'O"3xW AjjUo߾_%r֭QZ|1+k+p P].!d!ܾ}m/&}\VɎ-"7_q!\L5\t[0, ߿ PFȐg~Ys]%~gY0h cy'2.Aϛ7 ?/d2[ }N+WΝB{nش  I"e@283%h? ݻAUkd2bU+`JEŋzǜ%DEEٽM6*}DI; R>G@ NJRY۶mt0_ 3 Y0!M^A-RTX{Sʂ=qcذa1bQFX*U0$ e%iG\ K.Sv\5k`7ndWa̟?܊+~@T={84ɠc&00]hhapTլ#ɓ'X~///[_?|}} ,N¡C=zh(l DR2H ׍HXƌIIDAT- ``|xD"󿱌tM(ogew())]P!d111^'O; Ӝ$^!߱cU 6?tСq!L<_ |%͛nȐ!`FI!j97JA777;qʚVZvڍ|<w]L(0tH$(%J=$Xi&)T 8&Bxx._6H$8"b) AtI?%A0ٳ4::ɓcO2]ʈlsĉhԨZj 1Bal3Gpl1c`ѢEpww:tΝ;oҒ teZ6lX:!C vssX=zȑ#>ʃLܺu !!!hѢENɅi0N,JII18}ƍf= p5DDD <}O>DoFVVp}Vhذ!J cY~,EI@O Za>V $%% (P*tpyOo߾,as]N-dн{wlݺmq(xyyd28& s̜;,M0M7J"I7>s[@pp0KW^m~ eҤIei!///̙3gvqꫯrDj`߼KivGDD8ϛ7U;Q( 1T*\LX9%藀A{!!!ap͚5w^zj# ާ=: 7/^l8,4h L+pRHf͚YⰐ(%'&WJh7rsseJRcţG?~씛T* ] KJJT*\jLH !dD"!അD"| jwMSX .Zӯ -Bra" Y9X1K?ńys{"菑"q }KsLp/ ů>+,e,hۭHl#}Y=\[/-x&gW :yl S+It=2VX7F;ArBQ$ 8(nܠVF  ,AisX/#utyPP* X {K,.P? q"$O` X0 Py% ~_ʠ/O&Scm#bQ‰.nDjpe$C LYĞbc^1('< 8`Lo>~`duD``&\35Y-9} gA-|.B.Z`mA_d]s*Pc,mh,sWBMP QBeyalq^ㄞ"<^Ą 1ʹڄ'%@y15Gh/9/ Ֆְ (UbNٰ9ØРz#S{F;%& JP!!4` yƘ5˞oSʃrv6g.q2c|+ǃ)"%ژX Ce1k`)(EYؘayÈCĪHDh͙J7t< $bO~W ODEĄGd!4s\qAaKQ؇\>4ַƞ ,znsX_ǥG(",EnDY?\ YySdўlX,bY}mo (φ Z'a<7r2\1A8wݾ|B_iJ, B!`Šw*_cA16qYB-A@'wa[}?sҖO;# g79M E,!~b©%Xt1ê'g 8g{¾`ebn^#F?ޫ4B`"%,K[ q0u@+gI34f7C`[`˪{!Ls2 A((_0jEm#iFO|e,7O3 h] Ђ" %cS",k)5o~zO`;oL¤pR7G 8ORb8 ,)I?iIENDB`chessx-1.0.0/src/gui/eventlistwidget.h000644 001750 001750 00000002360 12223260306 020553 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef EVENTLISTWIDGET_H #define EVENTLISTWIDGET_H #include #include #include "eventinfo.h" class DatabaseInfo; namespace Ui { class TagDetailWidget; } class EventListWidget : public QWidget { Q_OBJECT public: explicit EventListWidget(QWidget *parent = 0); ~EventListWidget(); signals: void filterRequest(QString ts); void renameRequest(QString ts); void filterEventPlayerRequest(QString player, QString event); void raiseRequest(); public slots: void findEvent(const QString& s); void setDatabase(DatabaseInfo* dbInfo); void filterSelectedEvent(); void renameSelectedEvent(); void slotReconfigure(); void selectionChangedSlot(); void slotLinkClicked(const QUrl& url); protected slots: void selectEvent(const QString& player); void eventSelected(const QString& player); private: EventInfo m_event; QStringList m_list; Ui::TagDetailWidget *ui; QStringListModel* m_filterModel; }; #endif // EVENTLISTWIDGET_H chessx-1.0.0/ChangeLog000644 001750 001750 00000040673 12222731111 015365 0ustar00niklasniklas000000 000000 September 2013: Version 1.0.0 - New feature: Get translation files from server - New feature: Copy Text or HTML from Notation - New feature: Offer to load a default database for first time users - New feature: CR#10 Configurable Game View - customize appearance of notation - New feature: Inserting moves (in addition to adding moves as variation - New Feature: CR#86 Merge games with Drag&Drop - New Feature: CR#46 Games whose position is [end] selectable - New Feature: CR#43 Frequency and score ~0% instead of 0% when not exactly 0 - New feature: Setup Dialog has new functions to mirror board or colors. - New feature: Select Language from Preferences (requires restart) - New feature: Online check for updates - New Feature: Column date of last modification - New Feature: Localized Piece Initials (see CR#3592733 Output / Input PGN - New feature: Create a Diagram Nag (201 like in SCID) from GUI - New Feature: Draw Board Coordinates (see CR#1715710 Numbers and ...) - New Feature: HTML Output with readable basic tags instead of PGN look - New feature: Diagrams in HTML Export and Notation - New feature: HTML Output with symbolic nags in HTML/UTF8 - New features: Navigation within siblings of variations with keyboard - New feature: Enter or Exit Variation now moves within mainline - New feature: Toolbar for commonly used actions - New Feature: ECO based Opening Overview of the current database - New Feature: MDI-Interface - New feature: Opening tree has its own board view. - New Feature: CR#3607996 Always on top feature - Bugfix: ChessBrowser does not indicate '?'-tags - Bugfix: HTML-Output contained one HTML-Header for each game - Bugfix: Sorting by size was not ideal - Bugfix: CR#171 - Board Setup dialog: wrong board size - Bugfix: Removing last arrow annotation leaves ugly comment - Bugfix: Stay On Top accidentally active in OS which were Non-Windows-OS - Bugfix: Concurrent loading of games (fix from James Coons) - Bugfix: Game List was not updated after bulk copy of games - Bugfix: Black ELo was only saved if a white ELO was given - Bugfix: CR#3612157 tablebase - Bugfix: Performance Boost for filtering with result-cache - Bugfix: CR#3611434 Local vs global menu inconsistency - Bugfix: Update Widgets after saving a database - Bugfix: Created PGN was invalid due to invalid date format - Bugfix: Opening new game did not clear selection on game list March 2013 Version 0.9.6 - Bugfix / Feature removal: Filtering opening tree was somewhat active - Bugfix: (thx to James!) Promoting into different pieces cannot start - Bugfix: Before closing a database ask to save a new or modified game - Bugfix: CR#3596577 - Game modifications lost when changing a game - Bugfix: Ctrl+Drag in BoardSetup-Dialog loses a button - Bugfix: DatabaseList view shows Linked local files with annoying scheme - Bugfix: Drawing board when resizing off by 1 - Bugfix: Enable Escape-Key for Dialogs - Bugfix: Flickering with OpeningTree open - Bugfix: New Game did not clear the tags from the last game - Bugfix: Openening ECO files missed some checks - Bugfix: Opening ZIP or URL from Commandline or event loop was missing - Bugfix: Parsing half move count in FEN (Francis Monkman) - Bugfix: Removing a variation removed the wrong variation - Bugfix: Saving a database did not reset the modified flag resulting in - Bugfix: Selected wrong game when deleting games from Database - New Feature: Accept FENs which do not have a valid EnPassant Encoding - New Feature: AutoPlayer - New Feature: Continuous Blunder Checking - New Feature: Drag Drop complete db onto other db - New Feature: Player List with linked ECO filtering - New Feature: PlayerList gives hints on openings played - New Feature: Sorting the list of databases with header click - New Feature: Support Team Tags when saving games - New feature: Accept FEN with invalid movenumber (James Coons suggestion) - New feature: Reload last game at open of database - New feature: Mass changing tags in database (Events, Player Names) - New feature: Shift+Rightclick on Boardview allows editing of colored - New feature: Training mode - New feature: Numbering variations - New feature: Refactor complete game (uncomment / remove all variations) - New feature: Saving a game can now be either cancelled (the new option) - New feature: Edit square colors like in chessbase with Shift+Right- - New feature: Delete games from a database - New feature: Auto Analysis with Engine 1 of one or more games - New feature: Clear cache between database changes - New feature: Reorder variations - CR#3558001 - New feature: Force adding a move as variation by pressing ALT while - New feature: Copy Fen in human readable form - CR#3580030 - New feature: DatabaseList double click opens file - New feature: Highlight last move done when scrolling through a game December 2012 Version 0.9.4 - Bugfix: Writing of files automatically made use of UTF8 instead of ANSI - Bugfix: Crash at loading PolyGlot 1.4 - Bugfix: Comment at start of empty game - Bugfix: Databases larger than 4G - Bugfix: Databases with UNIX-LF - Bugfix: Some nags were not properly accessible from keyboard - Bugfix: No keyboard nags for first white move - New Feature: Time Editor for elapsed game time - New Feature: CR#3580029 Add only first move from engine analysis - New feature: Close database from the database list with context menu - New feature: Toggle UTF8 flag in database list - New feature: Open compressed archives (from HTTP or local file) - New feature: Open a database from a URL (HTTP) - New Feature: Clear Nags from keyboard with - New Feature: Create Index File thus accelerating re-loading of large PGN enormously - New Feature: Searching of ranges, e.g. ELO "2000-2300" - New Feature: Automatic classification with ECO of unclassified / new games November 2012 Version 0.9.2 - Bugfix: Support engines which send multiple spaces - Bugfix: Close Database while updateing opening tree - Bugfix: Filtering for number of moves fails if an empty game is in the database - Bugfix: Not well behaving Xboard engines crash ChessX - Bugfix: Search of Board crashes when started together with OpeninTree Update - Bugfix: Press CTRL+drag to irritate the guessMove implementation - New Feature: Move Indicator adjusts itself in size (James Coons) - New Feature: Common Font Size for all widgets except game view - New Feature: Separate handling of UTF8 files - New feature: List views can be customized (right click title line) - New feature: UCI Option Parser - New Feature: CTRL+drag, CTRL-Shift-Drag replaces or inserts a move - New Feature: F1 starts Help View and some help contents are already there - New Feature: Games with errors insided are marked red in game list - New feature: Added Stockfish as internal Engine in case no engine is configured - New board themes Brazilwood and Maple - New Icons - Usability: Filterflag only influences gamelist September 2012 Version 0.9 * New Features - Player List as Dock Window - New Database List - Drag and Drop of games - Drag and Drop of Databases - Second analysis window - Locate Databases on harddisk in Explorer/Finder - Multi-Threading Support for opening DB and updating Opening Tree - Copy / Paste of PGN - Create Images of Boards - New Board Styles - All Resources internal - Parsing PGN to draw arrows on board (cf. chessbase) - Parsing PGN to color Squares (cf. chessbase) - Parse / Insert Zero Moves to document / analyze threats - Drag'n'Drop Support setting up a board - Relaxed FEN handling for easier pasting of FENs - Version Resource in Windows - Icon Resource in Windows - UTF8 Support * bugfixes in Parser - Fixed some strange PGN parsing issues - especially issues like the one described in #3396532 * bugfixes in GUI - It is not possible to add a variation from Analysis to a game text if standing at end of a variation - Bugfixes starting up engines - Disabled MultiPV on XBoard engines - Added elapsed time for analysis lines * issues closed: - CR#2984375 Saving Clipboard fails silently - CR#3043278 Problem with LaTeX output - CR#3135871 No control performed on input date - CR#3135871 No control performed on input date - CR#2872974 Remove->Previous moves should be smarter - CR#3542101 Changing and saving a file does not update the game list view - CR#2881228 Crash on File->Close (or Quit) with OpeningTree updating - CR#3297478 Crash on move gxh2+ - CR#2823746 Crash when trying to analyze with non-existing New Engine - CR#2881228 Crash on File->Close (or Quit) with OpeningTree updating - CR#3170534 Crash if start of engine fails (0.8) - CR#3179203 Do not crash trying to show a special NAG; this should solve bug . - CR#2824024 Confusion between slash and backslash in file paths - CR#1773747 "Change guessed move on right click". The feature can be configured, as currently we have "take back a move" om mouse right click (if configured, CTRL+right-mouse will move back instead) - CR#1651405 "Comments in UTF-8 are broken" - CR#1715720 - CR#1984912 Names in GameList vs QuickTagSearch - CR#3043278 Problem with LaTeX output - CR#3396532 errors reading multi line pgn formats - CR#2955889. * Building - Separate Debug/Release/Static folders November 20120 Version 0.8 * bug fixes: engine stuff * feature:Add engine variation to the game * feature:Implement MultiPV analysis for UCI engines (based on patch by Juan Carlos Girardi) * feature:Add basic NAG editing * feature:Simplify adding moves: always add variation if move exists. * feature:Add menu command to remove/promote variation. * feature:Show TableBase result in Analysis window. Wed 10 Feb 2010, 01:40:00 CET Version 0.7 * bugfix: do not crash when removing engines * bugfix: no problems with more than 10 engines * bugfix: do not stop running engine on minimize/hide * usability: browse for executable when adding new engines * bugfix: correctly display NAGs below the board * bugfix: correctly truncate previous moves * feature: global shortcut F2 to start/stop engine * change: speedup by canceling previous OpeningTree search before the next * bugfix: ignore clicks on illegal OpeningTree moves like [end] * feature: make editable PGN size limit configurable * feature: show progress bar when opening/saving files * feature: show progress bar for OpeningTree * feature: promote variation Wed 1 Jul 2009, 00:50:22 CET Version 0.6 * feature: warn when quitting with unsaved databases * feature: improve Engine tab of Preferences dialog, add reordering * feature: remember current engine * bugfix: show correct score for Crafty * bugfix: correctly display variations leading to mate in UCI engines * bugfix: update ECO database for opening detection and move guesser * bugfix: improve focus handling in game list and game text * feature: timer-delayed game loading when pressing Ctrl+Down/Up * bugfix: remove bold column names in TableView * bugfix: support NAGs not preceeded with space in PGN parser * bugfix: make PGN parser more robust * bugfix: optimize PGN output * bugfix: enable leading comment in mainline and variations * bugfix: slightly improve PGN export formatting * feature: allow creating new PGN databases * change: drop CXD databases support * bugfix: guess move only with mouse over the board * feature: truncate from the beginning * bugfix: correct tag order for QuickSearch * feature: search games by number or number range * bugfix: do not read a game beyong the end of file * feature: allow editing pre-move comments * bugfix: PGN standard compliant ep square in FEN * bugfix: reparent some dialogs * bugfix: remove flickering at startup * feature: make comments editable * feature: correctly read PGNs with FEN * feature: new Leipzig theme * feature: allow removing variations * feature: enable HTML export * feature: allow setting small fonts in chess text widgets (useful for laptops). * bugfix: save all PGN tags * bugfix: display correct move number in starting position * feature: allow copying games between databases * feature: allow copying pieces in BoardSetup by using Ctrl * change: add Advanced setting to BoardSetup * feature: PlayerInfo dialog with player statistics * feature: display FEN in BoardSetup * feature: copy/paste position in BoardSetup * bugfix: correctly recognize promotions in UCI engines * bugfix: correctly handle promotion in tablebases * bugfix: support 1/2 as a draw symbol Wed 13 Jun 2007 19:47:32 CET Version 0.5 * feature: engine analysis * feature: Opening Tree * feature: Setup Position dialog enhancements * feature: use ECO information to guess moves * feature: option to combine searches * feature: enable translations * feature: make frame color configurable * feature: remove last move with right click * feature: remember matching position in position search * feature: improve layout of Game Info * feature: display game length in Game List * feature: remove last move with right-click * feature: shortcuts for Game List and Game Text * bugfix: fix move loading failure in large databases * bugfix: open PGN files from command line * bugfix: don't flood tablebase servers with too many requests * bugfix: sometimes online tablebase wasn't used even if enabled * bugfix: flip setup board if main board is flipped * bugfix: various small fixes to move guesser * bugfix: some errors in Game/tags handling * bugfix: do not crash when loading random game from empty filter * change: lower network usage for EGTB server * change: new, much faster Board implementation * change: much faster Tag search * change: do not highlight first move in starting position * change: redesign Board tab in Preferences dialog Wed 9 May 2007 18:59:47 CET Version 0.4 * feature: new, much improved themes * feature: move guesser * feature: support for online tablebases * feature: binary ECO file format (faster startup) * feature: simple tag search dialog for single tag searches * feature: improve look&feel and usability of Tip of the day * feature: Apply button for Preferences dialog * feature: configurable square highlight color * bugfix: update theme when pieces are changed * bugfix: fix some drag&drop problems * bugfix: segfault when truncating moves from empty game * bugfix: ask for promoted piece only for legal moves * bugfix: allow variations in starting position * bugfix: correctly redraw board frame * bugfix: correctly show side to move in Setup Position dialog * bugfix: fix rare bug when # symbol was displayed instead of + * bugfix: correctly calculate hash value for en passant * bugfix: re-enable FEN tag support * change: optimize PGN loading (loads 10-20% faster) Mon 23 Apr 2007 18:59:47 CET Version 0.3 * feature: display ECO information * feature: move pieces by drag&drop * feature: remove moves/variations and truncate moves * feature: display side to move * feature: position search * feature: internal support for editable PGN databases (no GUI yet!) * feature: export games in filter/all games to PGN * feature: small sample player database (look for Adams) * bugfix: fix incorrect SAN representation of en-passant moves * bugfix: correctly calculate game length displayed in GameInfo * bugfix: display empty game * bugfix: more robust PGN parsing * bugfix: Sun-Solaris compilation (patch by Atul) * bugfix: some improvements to Windows installer * bugfix: more usual PGN format (space after move number etc.) Thu 28 Feb 2007 00:59:47 CET Version 0.2 * feature: highlight and display current move * feature: add variations * feature: support promotion when entering moves * feature: redesign Setup Position to improve usability * feature: check board validity in Setup position dialog * bugfix: correctly display move numbers for non-standard games * bugfix: keep move number and side to move when setting position * bugfix: copy/paste move number to/from FEN * bugfix: accept non-standard castling (0-0 instead of O-O) * bugfix: correctly draw large boards in unscaled pixmap mode * bugfix: insert all pieces in given color in Setup Position * bugfix: fix segfault when removing piece from empty square * bugfix: correctly finding installed data path on Debian. * change: clean configuration file format chessx-1.0.0/data/themes/boards/sandlewood.png000644 001750 001750 00000322411 12042261464 022132 0ustar00niklasniklas000000 000000 PNG  IHDR@;w AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~@IDATx\ #Gi,AfO#LW w>™% `fb_yq\˯?.g~r\..<nu|~\+(/]{uV]Ǐ-x^x:y]n?~\n{}<~5yyFܿ>/Ͽ r }u?ݹrz}DןKs5\73zǯ>kqyw`5_$4 xW]k2ϮK.p|=kuppo^>˭h|y=>{->p?~>WѦZt~t`=yq or/[:uAl |] 5#}"dHI=tN+}#׳]|1gzn&\3{;_3|J^*_) ?Ovp"h'@/y=;Jp:wGS\/׌z焜/g|Ap/FS`2NjV΅5}OWzq~V|:9OއD3#9C>@.Iond ݓ\fQɜ}dx?'묅>?&P{SX^ mMѵՑkcPB@ᮉ8CWFs :~D0E[F&&:1aSWQX>Rq0^<"7AY-@PQ=>y"XЯq5D)2oሒtpp &"RO\Z$L(42s R:-$+5vO|ngbg8 \8kB}:_ i\rL2ItC)¦viiIR~%D[E{S lj%{ ^GIMg8oA&ɘӼD. `y׆]ɕ,$ VLL?B^zns0ZI`rcgK5_r3:ˏvY(.baP3$Kjc4}v 夣A R`wJ^5@3F4N}] S-]ܾ$8kNѠv ZB^$Ч(#&{I ͽ'0S6 Z$cMCz{֞fi3 HtFC\4g+1;J[x^;[26Y1}tXk/,򥫏JLE@)#2t1]]8\Ӏ };8۠Xl<ςEJ^9qqp)/D/;dygQU)QN c:X BӒNq'f8V7q(2͓̓p@iZ}EKi@D? Qh؉Fd:on9C#GQQB5ŲG[e wHʣOzvNr+峁ZB.1(zP\Kc z_ ٴ[!<jiǜMx FZNDI!\ǧ:%8Ct` l0EL(_omuh_0qx8YPx- I ]ΟBmRJb6g"9h1N !MfYX3xA;71to LdxuF4 oAc^2sQB9 giZVgZ=@˵hlIpXTz./P' BV0zY֕ X 3 N" E' 8"8!6|@h~߂gN"W#ٯX!aثh]JGk;E >8)R~)6O!#N]+ن*'ChD9dM1}xcI7@ahE~e0W_#MmcdUMpY?ѐs?W76c75JԱl"w4ъgƘ0nՖoXY߲\ ~Ψ>\PPZΟ2訏QmԲ=D lƉOF0Q@6<bvz fgTt3H Hp2&^xk ֎\ q/إ&SDز" `]+7My7tn`>}2c`@wXhsXXL;XGua2(nD 'Qho[L.kx f|TyADO"730 9g HJ.gqּsV.?'b@HKMA:/ѰyE8듰YI\1I1OlB_Ċ dȟyݺQc H)ttE.hxJ1E3g$Ւѷ{/>4>-՚W;Β7+s9!ZixQ*A aLT n[T\/^7 \m9;O EE@F?Qya~+'xElDrlxg) ޮFKJ5RYu3 1zQvt:hљ<9t67s pM+cU12=9¦j^20e*5V$kiaLg?[dlTOB#蜨`%lVB':[?7)#_e#i@uR/WLSFs߭8hlbŒP*7&N\;A0 K̬FRPPk&T)*,3B2YvfX[{Ei8l9BG eQ4zEdㆭ)Z\q㜥[-+9xҢ,Oi"Oɘ<Έ>8'Ad{gQSڤ`S0K 6p$NNwgsN8a:=o8UT08ְ1s q]m*ASDas:΂Mx>R(t&` @@ N= '@v}TL(*GcT;)IE 7WT]IӔ#ܢ .J[ o6p$,87O%hIK]x:z;\T<5^scm $P3EMmкWprng ȭs mO9g1 ./ ;X]~z}rh\OjT?A{?.g6@8[;dQ%zit 'Xq@eMFqH@!~\:p)s QUK4P}pC!65e9-ש'R\ՍYԔގ`);2L x!?!:dF[R ݩQd) (T@g&4.-oImkyu&46 wYe00€L[tN㨷[,R9,}_.iLq0m19LPo%eM8QppR[_E 9ӄbSEME@b &(6/WO& @$ayќ(OI5N-reOHȣiBPEIo<42:Om) QmM>>ngѹeڃkYd`mc+48jdq ںaǸjgSV ӳ@;#N )(L^Ro߂dZGg] 71e% PSW_Czjܛ|=nmX a}'h׽j2'ts}tx#k-KpH]dp:-O>900ZoҸ{D8Ò&]jIgC"BmA#njiʉ?UקyShkc.Lʤ6j tk .p;~"PVࣄ]mv87qq}*(`kQ&d?4m()&۾.z= LΪ~ҷF@xeɹc/_:(Sh;VO7m|㇣CW0?T30l?BSҔ-*mZX&w51 EHq(:m,bDad׳WLP$EO{ (8ckw±!Cћ2m<`W wV&0^jD9gkeE{sJ ?gXwT~:nn5hf*%͇&Wnd6WDgp\,gkӻmEIsg nlzFeFm2mR05+a/JA'el@ieS3E8nz&i!UT6ĄhÝZ/xr}$/@)n/TB}-&Y/! 0"Qzd` ";:0+'9*)_1h\]*bglxt-;Fa:_>RBكO}}J-6 zf"JmGQA֗fhYtfd$:3]J?}=6sjΑQp}p<xfĶMFE_ GGp٫Q:&aKCe/vb!~jY7\n=A> 5*ݫ]BO" H#(@MBO}GhE8P_P?pjGvicu~#o 3SqS+8R7R%0{FK#=W 20wF\8ZV0@r?}`2 ?>*JJ2fs7n)o Im9Qfl `Te6":foM;6G R[FDI}9O}5s8, >-eyCk>EES8&‚N1%~Gi[^UWD;t sDXveT[Aa8 Vp8x8u՗_vdN߯E Aop22fM/eׂ=^} xR"] /iotMm~Kɶj 2ZS(jj(|[e'PleLz77<][8mj2 OMq!Nc*xVD)sSs@zI" He6^ zFimΰជ`{ +E1FyϔIor. .YPBDCt;GN7cCǀ)'(AU]#6DLH@5ҐY*j,"%\AN 6ڑd@1ůM &G07J,=qä^;^B2sֵmTe|"1

t^ s A !!8^9ŞI$ܭNt-ZCJ8:&NW(HqލR-?+e׵^] WQmH !gkیy.iYjlW+C[;h՛ RA &:l7rk\1DH s n71,agF'Xn6oesM tNtnK7J0[~̐n?YL58r-: Jf<2T:-tePa\f:]1ӵGm-Odd AM#Hxσ(ǫb?) 5{)H&UPju㶀aUF(؛E@loYa_}rm| A,Nvf-/zz)p?!MxXPDG(עYxw ׌fAE e~&iɞlL蓛iRP!pI͇=)yN[hYJ.u`X&õM*}X&)k:"C GDDfF5DZJOr=E*t'v 0:x6K(6߽}c\a`)"g4Pe;bІ^!SHOjE W2HaEٕ6Qmʉ 2J? 'FȢ՝q+?z]dsSI}Ej]PhMKk9y3Mz8qVg__ v,=# )GGtU<F]ϱԶ[t2/kɥo"٠]3aMIMh}au*E`wցqYt# k ]eνa"%i]<-m^L4?2jO0RdDC2g%}&-YD{J"<,;;O{ǯF)Qظ۠p(Auذ}r1GIlєj<lE7\}Yt}mf8AؤN`9m0o[׶ɠhY@G?(EfQ\##S;[hЋcduy'VaZ- 2C6G!KEy)M9(!>)'6Ac)s;@Oq9֠gt<7_iYiu˝ụzQ=NVԵ$ 'g_dpp-0-y ?_l6 Dw씀By`{ _@&1E??'7!M{y 2Bݷ#HJ1KXT )ڥ4BЛдvb1"S"Җa 1H,?DU_箟_"BZV 1097sz` 2XMe68lX82R&]2L!Vs^zfaA >ϻUU9E}O댃 LjmtlɈ9(mmg=]#.ѿGOƘ}lSQa6bpx Rn>yuKFb:Cui995IFLIGZEա;H,NKq;w#-ң(йs2lSȼSj٢̢TLo) RC9V,6 XByQAsu\N6hJQ朊w%%\ׁYr,9eaM)ų7qJzUa{9^eqM! UO!+bJ=_{(S2׫AuLI-e6WH m`)%9m!9vXZ)|Qx\iί~H)q|0Rkzg~j#@*)@3".<-ZNoC[ ?֙iڮ{ƌCMPc\zҢb0nҴ5NBF'CE~:G-ơ> mV}1ikMlp"^DL#.hSPXE? eJjM>MyғT\k匹D/AlE&a3ZnQQu -7 3^H=cngz- Ց 4Z\?/R+b)Ɣo7uDʼ5 `(?fg_m$c{Ҽ?Ż/:hpzGx vQxdgd#*r'W24+^Dmexq9#v rR;fs.pCn ßrƵ.0Hnzw6A7̀{}s$6%7)7s+|J'4Gv@n-v`ɣԐ%.Ŭ}`F_Q Cp3)#VclMBe @yHWp7u yUs:b8ŵtTش<\`20vAO|I rp/ ElQ$;uҎj_',\O7"] \YKY)lms+':foS=DW{2ϓ)-P~O&h"v'f2K:I~6]Cx" yNՠQߑeTx&ǩ@YS#Th^-QYjt㏊ % Gp|E': ^lMt~WΓɵeiK19zz՚J]k?G9`XKuл{ -*2E` ^24JOSg({B[0qXʋKVސ 隍'fJ}o LL5bܻHcgɨRxRx [ a<0Bq)ۘ͞ajR_I{S D`7 S6,nz7s-0WD\;"F[-]Y 1as /`~fonǚZ}l)wN.*%dF#(jksj뮳=:UF,gklpc UMŨI̓pi} ̻kkW"{V0OU]FVjGY msJ9W=&K' 4$c%ⵎ<3Tx6ya3, j.pЬAԿJщDkB۵xyA{ΐK :%eHFi/EB1@f𒹆GF}}$[ηn'LuQRG[6ʬp;szSZP V|֫?+Cl4|lW>0(/Axk6pJA Nx^BFm5ڨtPs`E#_S},l. 'dAI>t=Z͙&4d[B햱ub[ؑkh 2o]UPxbBk "F0>Ï!$A4 Ԁaŋg20ݼ87bɝx3))pF l'!V b 7E25Rp}8]o4ƒx&\2{d^[:mO#e  +8VEɎ3k C~8` j!!0^.lfL8~i1D:<͑sk.r>hty/A.# J_tF 3®~Q̃0ŲÛsp$$޺iS,Emfc> p#^mSMֻn pH@pb(F 2xŎ)3|-e>ͥ \Yq`0݊"ѳWmd#^7\?ˎɴoCjF 4>\V܅r-)htI7t6yIŧa}O7myNpb3k?X AhuP3Jׅ߼NFM-NZ)K`Zcv2Lm{,6 ۈm2w?&ısaKʦ"G4͌6)f4Nn/,F{',}=Q]w(-d#vJλV}Ml=kлMqk4lɉ=ƹjtw 2@wLQG7]J~OtYr= p<*)'2 w趟@|}6٭($8f-8FIgs>8<)# =Fu.ή$xخ9)`}ob\a!8{k2K/R\o"˽ )k5))3N:<CƒHl$ 6f'"mW7"^y3 PRXB%Fxe/#y4w] +G3cvO&Vi\oGsܐyRUTR]0WTXGTӺJV[vtnShj@]|b.m>'XG,F-9"`X]g^-؆.<(S*u{Rv׌јpj,iwRguSfmG_]#&,zD}&&72bEz0+d߻1DqHі*'g}GxEm&DR.:pF@67&JJ кsilm̙eE 2|gt}` sctiU1z! D8N;h ?Q\B i)F:!K"i_[@w=m}T+u/]cb _<ѓA'Y7C7Șh럡tIS$) iٻeH1<#YѸTNFQk9GZQQC'2J7o齚1(3rzSp,D4GH~pv$0ޛg.v"i4\ "&;UWH°3ʭ&p vXKhQ t4GVV>h@-sy&?=%_P<&J ,6:U'h||N=%yr ELq#JVMcS1*]wBn<87!XCph6ǘ;_cfL oD'"֎W?7x)qxu5aLv*pLC ޻0'\U<8)gwNwѯ;GTٻX;7u7Z]+73+.rFw8}rެCuQksٸ}Cw՗(gjCDptUO8Y@q߯y)_ocS܃~RD03g@Q3aOj{fPQb c`%:fd%lTZxY66;pJcrmO GixvN݋RѱGqpo#tN#FAɌ`EADxpafKpɎWn@y2؜ % :fyuʶh }l!|UsJAsFѼI|Ql b2}Ut8&tw.j8g2D #N& l{9t<42Vf%@IDAT`03#]oZift/!jթo=?}Lh55]#X&7X$Dm x3l42Ԯg` E6Rn#J@)FOA3J?LjC;EKu?bnа#lugp˭DUmUJnVu3 ΈQB2iql1ٙ2"6&;!=>B`xҌǢ!1%7C18BivLK9p>yԦjZ"1U޼ΉsK6{0A_S;2Ce4mv:3xs7aZ}MYlE&3𲧍kAg98 9pj2A/z'#W'{2]M,$M+AfǠy V4L ٜE<,{X۰ ]BR]Bz-#Vڵdix5)D J:Rϯz'0nE[Ru$tls+WJB^ig< (:v_j2?gIZ#̛SQ͙~f$0Ək^hNi%Cg^3ܮOZK2x.jŌNŻ$a:dC=r)xh.oD@yaNq&OV!TƇT*~W0F OL11)u<$hLЫ2|ضא&3VwS1c~1o`28<}w {Oږx%6Ǹ~I $Jݭ !)nʪ+@UIDR.ebؖ֎/ mXH'J~Ϟ+3 3hߠ!c< #.rTHfZas[ ~д鞮(h𙻅o?R.pv t ™ ,/6j\AA#|Eg?m|?N(L܈ a;F_JNV3̘ _Ms"*eFICT3 BД07#**;2^RiOƭ0@](N0! ^ׂ2#Oxc˚_"TrD)&zP7E-a!U=__6;'1 jI}cLلէn3xFjo;q #d3bhCc)N> LQ-+yyXZ%F6`{B11ݐRf Ҕ /%ybTN_oS nw&( ?Ey`6Vgg2ƵLϞb:sJ I4z:ڙnSkɒ1muI GJ-8-\{;ŀe@)[HZQW(ߣ8~"ᄛ &}AgTsvْgXrE(09Ub''jWD%=>n{\pA὿ =pc8#hKӬFxhZ 9#-PsFr$nf"h$%#Z,c,Ntp8QIJ[+v|ΩX6PlEdlBCZd:쌜teY3N-:OڍhΉ > b|NܵYet1|3A 0i:rN @ }NΓM_ skm ЀqB~}F[SNe>=V8epxc!}&, ur(k r+f[ ) n(04"0PUi04W ŠDdt{<:qp'j3JћQ`@t[0Z5 mCװ'XK稃/Ѳ:=9o:[a!h"9IL?[8q%>JymΡ[06w[##tik̟yTJ4nA]-47.X0^ z(0w#SWZ l(xnL%1RZjOxBlYHԑDG2)xzD8c6 7`NG[!څtRtp !n=Pӟ(AxXɸ>)\f,;kCTJ)sf#S0] |l9uvΟF}4gOK^viX|U .!8SX~+*))L*  #.zFtKb1ޖR.񪛌j1"EHǸ!&˧ ;O aZ2F)0}nJ>^sh J1FkLL驵%#C$aMd*\R~t|ьrH!skK!ח:E;p)l8j;#ֱNxRxDq>GO'*kΦ6'  S0x91͛x_mLDe"kO돟Z;}hlr)7e1ݔrO>QbY+| JL>"uz8 f*\^kOyjFNu28PʙM}XlzljZF!X9>D mӥ%>45 K 5ф9/RlNR&ԆGd0}#rZpL<~3E-E.y{|d>7=9{_ 1##f5$ZIcYi} 1}}4 YĦm)ko:#|<#$¥Nz"dqEkcEKf*H}H乚,# bYG}!GPY\y,K[5",8Qw] Z ԍ?enXί&pFQl)t(fsA*Bt$ 7#zCSG[[ƆS71<:8UD'/Ӣ=hhE,:CgL\S0 pܵ['a9:?jEF!#oFZo}WkvmceZyd+~<_n\snizjoj*2qDrxxptr}ƀ2Ǯa,G3/FO !H }Cߙ~p%7p -D*NoY~X1R <'P Lq/Jk_tq/0r+K"+{EGȼk"=w$FQ[?C: qϵnJ(!)i%Bx r͐28Gxǔi :OwY]% 0w24;C~;QcK7"N0pʢύp_ !hW [jQM97sߥZ2(W:\vL;}F{A-'X?ڞIymRMpj1 1sP﮸hH9H7a;Gi%@ܫjkjj`o$2Fpi(\8Ԇ(j;f uG/EW^N1Wuި߽vfo.7sz9\_8 lv*9uv[􉀥\_ p9$ E=,>[ƒ}G[ 0Sy@!5܏Ύ"d*8D)1Ho )c'm^ni\zUy)0im n sfQ^"V]#BQznPmN}hBg%'ɱ6tE m0q&ջͣ1ߨc%'vCVz8h!йM$y:Ԙ~4Yo_̌3d/pX((/:֐L`!%Su`!XnJ3&\4SV3FfV)P JwG"_]?:LxiɞLuo<6{uF*լ[QOJ4n9rvc@p8{ $AqZt(,b:RF06i=ycS Y?ϖ^k6f=Y:x֗uԎi}˭ P&AU֡tl'zwa2<lptLٴ~Ȣ Rӕ=wNK_QDeS(FhGG7qpc3`+ocv1߷3j.3Pu Ulί/wU*ޙ8;cv@s3q[9 z󎓹[*fPmF@MC-5 ڳF AZK}Lmc y#%mnAׅ) *yALo 'JUɨ7x%FwMw0x~RM g0#!eJ~Em϶o̢T"6Dы-"[V QTi;(fC,ΘjLR򒻀AU=#C~ 8N(.D!<ڤ@4.w@TMhߛQ+t_rw#zQ)j X6 V}X'&#*yF h7ML{5GpOĘ):)TAL55ؠ{^5{fB Zwl lsnaŹ۽;y[NZr2R2J8Zcl+d1 S*}ԗ,ѭ6qMk9!3>E>9B1o3=fUcwv=:qMkq|JGa-^!3_?Gce?Vc5ZR4FtGd?ϕIS#/Cy:e0%sN`M(#W!E;y#aHߧtc~;}Dx#ȴK&ƬC<I7ÇJ=|hB+RѺT=AbB.mHj6t+l{0+"r7I,卣%KGp'ώӖ'ڒPwl^)mltM+" jB>}DL( \ %{[(GVAwd4`[Lt;wwR $M'X["}v_+Y?7^D RihL/3Կ[,d}񤉮oժ8TsCb`UM_+D[͈P z?|ikY2GU!<))v3!hL5$>"ą L3E0{ȂN1ͻFj. NZ ?{q{}Fn(#vOP"h'mqW0A7MEFMZGe\Q_H2rOh %P~N7S@Y'y}nG F F n{Zch38b[08!O1KJM5 &*nҶա$ ]Nd5a$:M} ?2@' I3>[h,-b;Og,j g+8fk1"ܞi $+/5ك'3)zr>]Iq&O1'Z]7qhmo 2v S;,囝+>1ݏ,Jb}Թ A.}3F/Ћr\C v$o~&0OƜ+"1Ou}HnP<)80cL ldw^9LZgs9 Jl&'DH a`sg;B K֟n)! k?Z#·)*D'$ɤ&}[ۚmF!;on0Es2&F܏4Eوg`L7tʆ6 ?6w!E3:ysVΪ 'aO8A"(K-Qh[/xղsobyՌGO/#F\O*(&@r]Cj;)2Ѫ~s(U6īhFy{HO \M-Fj΀gICEpwޤ?FyȺs`,VM LgK rB_דQ9Z=C}j Gncx `bRC8B<@)w^`0PF\hC)[  "VB>KXSѿO̠(̜|?B[LNam&k΢Gw,:nTOw^MEqmgbt(9zūӢhH#VDe2W%sq9'@2$]3'jۮS:FJdC 'q'/3U5GyK䏧qK)`c_?Q9wODywYVJZ6{~GQǣ,Lk{D/0HBHvO;i7|)!dw4O ވ-Z6jNRQ)ֶ֊ƥhgڶ);Kѵ%Qy$-M E,Mr]|W~Nض-(tS(czvloeYDC)"^~dGfdƾ0=P[;F hlp듌_2z9yptH+A&4C(,R1r`b)Pꈈ_R(4꫷Ik¦^j=sWY9L$DMfo-UK A ēR N: ^ܿJExjc9Ón*:ҹWܔUHα]f`"-@1ItUh!3_UbfDNPus_%KPS@:4ww< l/6`EKӉۋ'sK&+O"FτlCN'epΰR\B]zI lxW)P湅G< zԤxdu~+W&>Ir.ƒФJGcP^~ZmZ ;$;滁A9ԽV@smnӧ 1 җ3 lgϼ;wp'I} ̝@HsrJ6 NEJWAXғ7 R>ߺz@K_;GA RC :`Ԟ1aKk{cXPs3?F(Դ ыppXѬ-b'ZdG,[z&<"9U 8(Ԁ#N |{OfFdxk;Oj"YZ{-[QY6ABPE7骷dAZQ*0IQ.W1bv'o.qtmGιg*j/q\R ` w+q&-n:F:mr+JK3ET}Y}%}ٳ7ɇѬ`cK8ţv zQ1+00T EY=q4+oP9J%HzǑ,KCΏ4d31 J 5rfAheNiDwڪui8Dx"H@\HQa#kofd3':ԥ9X>׾g&by0R4~78b"hxL#~\goOu,j^ 2=,Y:kOc 37X}9|2fDx 5pr4SB>D<9R)-D!]sϦx;\ǿi } bJ$MӦeFյcS 1+.4Zc]'tXqaKaOl^S@ ECV0bSVpvwdorD|qsrdH+&۾/`g]<^|wJSa|#>E$Rg,]N"3aưbKs*#(yh$$XF[S ]KN:VQ0 Y \z E+|UpiZ{UuyvX#Oy* 9rጾ kpFSbFaK#y>^ lb ,Ytuw0wYTYѫ R}ɫ l0]UBaĄ>kN[ˡF88|m<:qhi..(tMթωlBt0"uqk;kj&9.Kf:,τ01ڍYؖn "Hl(SBݭŗ f*(iGxX[m+s?9@NS%#Td}#lޤj5lb}4Ik e{QMb_HS4C A<`O\@c D ]>!@-3ݫHx$woϴ 3aU=tFBT,oxGnaFl]rsHP&<'t⼴p5P&0vRpwiv 8OGhM& jcGkk( ¬ƲBk4D}{UsU?P];p%9" g7r `nR;^ AWxqzI #)w9񘜠C;R!:Lӌb*2A^f1͵幂b.x|`=$\mɧPmd;ai IBΧ`[k H'8#l}R>#CqTJoV$a}De"Mxk4s,ɚibZ?w#J uOK 'W"XsVX XDsǬ7jgb4GaOcr_ѡ;6Ruz/%U /1}.ƫWlf˧ߡK:kSo[#\(/7[ffJ WwW^Xr1eqt[ 6,!<#+x6$j>>fd fBsiu WdZm_cx~sX9AoDO#;]*#~u (k6I]⪂G[xm |&8[ځϾ+?49T^h+15DG93(se;v)r")V2*ypm.d<_}7ᄉD!Ө9pT4ϯP-` )/G=oR\({ֲoL ]nA?^]pTCD-qZFW((Sdݳ3QcYBAJ Di:WVgGB`wh h#$7K#3 "Ѕ<,@xGOXgBNs##1r_8W&Y/ǾG6D7eǬIS]c[48l 5HCS&ʸ3vLs' <~"3|ZܨZUu84+u][|Ux-*[ `rlG\Ud`Uo^%QPe[)Yf V[8Csln#As_kGʎ}W.J!/gP"?G/# g nڶzw|-cV 2+u9 Jǵs,Ir 6ae]K*{gޡ3n3EX g#dGben1Vo~m ?v)SJEs!C0L@ TL+g 0*D$HڵB!٬s''wD"_iM: :#H6?ja#-Q `kz.5پF3';],b/j,caQ?:44btanN`2(kq4 0n<*2om ,DYڮXk[>'Cn M0|Jd[!7:Xo[ mxĩ[]AByXdt4<W.=fP\&19A;Bܹ,Q GewǙPsG5w0K͟,c4 Vr¥^DI%Y,}!b C`ŐVgS όbf1&0c4mc`uSߕ\]vw$o:` ́h{ˣi:D+31ex1'<ʨls^ˈp+C-Ф4*/ɽDB#GI npΘAU!ߝWo$V}dX{|7~[^9_)q8_ 97KH4A3%Lz=.;QR8Sz8{8kuꌢ&K}`֮iO'K}?i|nD [>+e@fh CAbvZw+ҏRnz4㫻,>hdmK}M9-,9ynw_;))sK1 F-#TXf+^K`]G+EF3l{4It'-@? 94w+101w]joW=kr\Bu4L#-L6^jd1Y:aekeK:sWD,lֱX-E0 >aYlĤ%-%VaeOlgn9͆rXMkg4BCǔV-UO ?|rd'ȡp)ϒX$J0k5ʤx*dk?L;};y9ps!(ZG pkm:P]oߞfZ=ό@% }^(E1XX|&sP/kSD޳f6>KL3C|y-)8д-DmiBK ,Pt=`4PxH0::'!ᖐ6ю*.QORg1p8X“{+_Rh-FNOg,Qd}Ǔb5LjmtHhk~F4B;8*/ǫяMUh)\k+>XYK綹e+|d1ѧ6"R*T=FQ)q R8DCuHP|k\gMlUM*u-$ze/~B Hӟ6ޢht|I1X{"a^&-%[$pRߠ^1TWXtNK&hݵ:ȤQۮ!ּA۽uz'Y8sI_UalM#'k@+WluX򯭳||0VvT0AZ}!gaݻ]&J$1"$0 ퟔV(Nc÷FV7VCS&e{}P+j 4Yr#j7;PuYyJ).4c(J!N5ʫ^.5H;ݲd)RWml ld߫s͟ybc4Jxr--nU&S&" }ap5K_9[B9Z\f˷αbG)?>.6`&y6X^i43FTo 1@ 1ٶnPiӳiF?~UvA;C^GH#PѤ`A!S""HvV 3}Vy"Dԍآz-kA k~46`i}B86@:+2 T`,+3%ShTYbtjS A> j'l;;jF$Lt`,JH1UN0̏nYik}j5um F:L`bx nڢm&b"fK%d2TCO.^if70n ]S OzGt6 ѡ(x 1GH&a.)$Gtbeޝodt1 8"娴Fׯ_Jy<퍢158͊4ObM)N{x6?];~@'9o34vc&7Ip=Θ8v|iy k4ϲD(F)-KLb:KQt? U15N-P:bs,Ncz/綸a(@jg{!/Z?[y%.P FpbdѠun)#RzVI1.`] RA pT`c(^Y>T g6H5xr>k`$ E.moq$cdRYԎ(yw%B#cin-ܻF'=uEV6 =\fEM 2;j@#܍1ZGqj^vYHP3ؗftŝo97˺x2ISa, ^E/e沴tw;hH%`]X۵چ[ͬw>gi$GҬ9~Wc cWрC_K 3YYWN LFO< pfnwAN OD@< -xL(=Ou6TDYL#ĸ- # gi%HYτv|%$B+Ҥi(v#1K+Ҥqg5s 'u+{)Tscy̛Gh)h=~hvŇP>],+m”Ei̗1;Mx`K\n?6t+ttHD,k7<f9)Qyҡp .4j׈*Ĉ*=+NLU3P)k}V>Fg23T8`H扁 5/:̀rq|Y9!.'(!2!mhŠWe[u]_#PrF٫V $i&t$mN"^ɝLardA>M!./7N%,ٔ= _t?ۢBb픯,D6ԟhyR9? .xλ>BCF.奔׃BA`BiU[?N N+U0V4oO]+=\+NoKqbȳ, @GOH;4ـ|dDT =[ >c a?4h0'Ң<$-0MwzZoA;ZАui'Ɂʶ]d!~hZVpg0\&w|$ǏJ'"O'rA}vBhaaG܀"e] |{xBt; W6gB(eqtG02fT_Q%*1!#&n.3M*ƅ-*n.cu,Mr+RŹu팀w[@<8t֔\SL! Y0d`m*6I2])FV6Oecw|"7:7̐ONaAeQt[TΞ+PGnv58*B$}k3;Ag@0Y,xXIU=1Yb6Ӗ4fҼ-¹F&$!yYe"Zȩd + uÀBN3lh_#lċib2 +&~tNדN {pg~ BU2;{w)j[Njr18)e0$FCj {J\ZA߉W֭|gJ%~Ol*\'hwlY,FE,IJ,u:1xKsѼk6hOH訝CP3g-vΫ$mXܗö́DrgsCMJv.]ٓagC sB.&|`8Q}mCB37,1DŒ;] .at3|1baCGq7ĜIz9zGpxhJ9ѿw׷]}$ w)K,_X}$yT{n`S!%:HGdcO7ǞpxxxX V5GȜ,i+IK!>MCy;Nv]mn,vu pkGMFˑצBzTx@ u4)63KLk՚WU)_E5D*[\aS7ǔz/, '\*ĝ_? l5px!S[+1p[8B6Hʰ* -\ѦrcY[|G H8TnQa?:8IIY@@*7:_F_LͰq)2mJb%糠^ƕ -]vkk Hr7 G"n zlJ;j \.~p CH~4V!>o5=Q7,vpYY <)>&6iZDCv [b>ݯDԟ~R@L¾:Wrq?{gpכ `$yr2F.OSlL Y|z-o#~uf=R^hX;Kt`>W g9m*K?5ՕY}c%ӈӂghĩ]V%w)wYoA7Sa2o%4-tح`+5~!b3Vm4w pIHESeH+_0O#v0&``yKX‚.10VAAtdnt˪++v\r> PxUE3/WYb; @p4hZ5V w)B<5yIy$[O^ح}cmڶx/59YϟU= [od^6 >,6C$DȳzCVFԀr۪1z,obXu wҁ4wiSSš;Z׮8i&ފkcV]ŠrLdՂ/ɚNlu%Kap'dMlL$0]ĻglN+UlaLH{~ h,$ ވF5}!)ή4b)bHsͧ?ìm ̧Z y'xN@njޏ:`G ZHEgp42#@rc[\eLORH{Xܳ&xoz,dY/X̀İ"n!0؂)X,IYm :Ei׶2VYMi&y8`~FcTHCy[h66BBϪF)Ud'J}-t<ߋ-AN ɩߦ6r "LfݳXlέ@YrwPf c%,/(;ai no󕛿D^?L-z8w(\QQ]Ղ]0&Qy!!$cl hAX[?1.H R`(5#WITK1*ZT6EV>}ʃs~F-BHjO8k{لƯ{vřԊ{sw\W[V+O18~cZHR*0׻s W[Ka/$G+.%PC(J67VP; DNܗU@'} ~'Cb93 hXɡ}5}$ObP9m nA|rheV{Y!F" Z\˒\d OfU':R \FE_"auCYgֽ{"f[0y)Wq+LW !JcXyϹigl2T 1U>8y4Ap& T7 mΘl1޺$D<`'0p"mw^"؝ MU ºfn7pp / sl@^Tng#Q9M*p.Q)vHnI*i(g4WzKђv?"r% p%1;ڝ5Nc@u լkSGON T 4.+ rUҸU$ Z!-7jh՗^psm>71oT7V A+[" Fƻ|Vϋ-f7j)P0YD$ebTu"l)NEFql.uXVf }ugkWA@b՘#~n%͎ JrZyV%g4@F)~Yd.XSȔX0,Ylx&`&LltdJ&`!m6sB)v_zsS0FWRT?y[sQ^cTxo=>*ps}G ^5z`w.IS>Ru%wҝp\eumf•#Zґ1v=e==00F\㢸>g18g=.iu#8ubITbWJ흵NزNnE F8!8ÜKKR7GhQحcNZ]#Hԝ!_hTOIh\(F] j~͊ *~ܵ6.U\F/ =f&n[?Dkm5@l;.IIͻupH1`g,Hm">P':w%zf n{<\h08#j#q H=Alq sv}UD,c؍(%&Izw=*Y }5hQ7TG]в~U )tST1z_gBZko qaº'S#s#uGAC54ƪ˜,B ?vB8eT.z q|XՏjk}అ*{.DW >1 (w5ZL<則R C,pcqʹFh)e*l-msowJohv\a~oD.ԳaC0' bˆXL=X"k޹Y~|ɑ'PYzS>7Pێ:oqD0~A|) |o3焰xiťJQ-nrx4rR҈"11& t3hF &)Ѡ)*hLzpr=hEO~{bUpSRBextuN1YQxt-6x`0`U,~ ])En˄2 $$Nd#!^M:/J\0b>wrN]mug_3ITV$ߦHneJD1="@Tr %+t4FL0{ZfT(iC Dde^|V"/ͫnn: s1C7ہ)VQ_nW zqS׳d›f*gFFbS1fF&jO ZEO `?Ѻp tQ*$ V`RUH$!% 5tG4e 7W;ي@wnDCI Ǝl qpq-wqS3!Ov|rDY!|H mm,!զf)O2@$p'>&C+K1!F$/ 浯<[Q<tb77(q\cL-K2'Vҙ\?)s1b TDԄ"0vvAr $ #rQV%Ry|H,#Fq z$)<|p|-r 4Lx3u1Յ{BZRNzȶ€U ͒P@z )mKDE]tF 6KI<\ kv&gg62$,ٔY3ԮO4~'׶2 ,u$0 <.TCMnwBKy Jʲ(xTa wTS|Q<Γb\aQ5@@~*geM&7:kY` aRځH [ !̇]N"K?UkMPN.k 4 8 ` CHܓBߺm0۠#ZH_43ubRO)w4bZgi:u0"$D1Y n p1R빩o%bG۫:OZDw3xiD_hF|Kch'KplW=aNH"_F8ZX|6滶dIUP;"YrR0 c+YIbZņK 5:fPأFcn'{;UljK9p8KZ ߵ5! QaI5+s-*RVȺLfTHV S^92CçchAc@Yt#=ddTR66 cZB?lrTnFǼPoj@(k~~I|k;gds~(X,K?/c΄bw|ɽ%v``zWZ֝t"]ل8[)rN7DV̩Y͟f -l$܍Ds^ɻR<(FtaV{i1q8'@rub kX?ѐdbaq(' ʠ=8cXŠ_RV_[_w<=۽=j?Z1}=W'8RL.$|mY399@푋m(=V𹿲F?T_^D â[ c7-J.mcSk - J+k(|yЬr ڵiCdAD\]=yVn@j&oK~I\nAƷﵡ`!"?30_ Pԯy|x/Q3 .\=/>la(޼{x\}u5}TɠhD^GM "%,rKl@qtHU& +W=Pnܚ-z5K݈4rˬ(6.`W,c) }lګ5#w;őMbkOW3ncE0_16AKKS 4^cPcz~F%i}A }0x5$;.Bis淧K )sU,H1d$R; ۫Vw@΂jM[8ˌs%8.;qD?` Y/RMQ- xtUX匊)ɍd~B#<~֍+4{VЁ[)_dV|X5^_jՓ7ݣ[1E@WDlgPUnn^~C\Lrdw% &5=~,. 3p}!Ksi-+|I~ CH_<-t=lvHfF=9{6ے^h:͏~gQݞH|8<̐<9z.wt +SF4 KD#E wB|Ǭſ IBJ¨{~ᳶZU1˺#7|b7{d|IhūKgak}SUᶕ.=j7aJ[f cm)=^@4|M蔫(\ rH?=~<9cg/Kb(ڹW3?yC3I:GK0=c R?u76}#a1<ϕ&gxmb@/o8.aXp9^|w|_ Ƨ>~T+NB<.!e1А˷xSirykFi+51%TIxX4k+> .'(\@^ua{1/.XW7״%k +D͞g%hFŊzrKOy+1۴y$䮢ѥ &;cX=z$wh;"#s!tQ2j#[<>W`JUG7,`kgW˅$ /R[S̙E|9m Fiu>ݳ B r9_>oPOk*EX_`=JS'>=|m4v)}} ^5u!<:; hsmg Qu|/DI\jm%}!SCx'_>=oH%c$cvd!͘Ӎq'8a^Rʒl<,Aղk/ᗮHy$<$' jW yQ_!WFg Īb]Ury@ ]ZvZ߅9hj;!(M_wwNEĘ/O A}4\`iw7A~7]=OM7)sRM?7ʾ`y#n/%/ @񌗺iP"_^͘l䒲$19xۓ#Kx&9)s0^_6ԍV!{Q5-mzxSxZ ćO\4WSk kc#]o^i5܈3ĚBǔYۯ(G˽i- m`/=-;/O<\2,퇓w`)Ll`Ģg.^Yb\=$ȍE- JPcf%⨃//apC)Qk`}w ]:({#}gpBKFm\ȅ!!=ILC~"fupa陛WoXwO^rn |4$I%b*'%p O _ |?sӴW,?>@1Ņɑ_#A\X1&u$?ޯ Z_п*kA jy,\`.2EUacroC8u˫bpHU/YHB"dU+y/őEFY֟yڿ"z!Az0pjvfs.{d^|?Ph[2 L QX^Κ$6Ś"0tY"j֘<l% %H@u|/&)\=9?/1$'L;'[˟0~|e vk `5ڙV| "n;D=g U޳{)թ'nވlmd٢{ڗ1scR"1S#w?LC]kWIkoKl'õzOR+/nJ_F8uC¤>_?*$nM7Pk֣iTSNl O=?>YOnwb?d m󊐜AX΄t_Lh ^knYƒ/ xd3wD w]UNr ?J' ޭ}#Y\(xhC5Lۿ嚞OY*}kG)$o4VK rL*!y}\]e%F?Y_F.Gs[%8Bbf_ׯ!rW ڍ}$%ۨť-F. #kB=> џ^E4y/'oxWFtb0o) VWDy3Őn%P\bVm*<,yXP ;.N^ly}ExG(#VW @IDAT΅!? [ʀm@p{J&N>5o fפ q՛ :_z[Vw@7lUي/[=+RXD'D~G ->suY=v]y+An޳O^+#/'1%Oom$v~vwB] XL=AX;sioޔ[u!Cg*+:~$Ŗ-"[JmwɂqI\?vE3"},s>x|:%S!>W<(ۻ[=Ja]\kɈh$7'{ ,1")V;!͛?{>]_yoCn{O+z(D eigx.U/i4N+@ֿ>_J~Z~ɿ:-%[d7HP&a 3s]0%GKKc4,-M2߱fe578~f⋳%{ۓϘ_iVD_=x)?5|v)sňިDw?qXd7dk:g=?!fŐ\H/W躘NO7|Ldo ξTv-v}?殹f?Z2|Ex7od‰s/BžW\m'at5!58f%*xioڿH7@B_^M~F㜷zMx/^K {s'ܿhܯLSۜw ˳bpw_|3 hY,–+J4j,ەg/,\C u (X%&o!M 7->j !s,+nQ#, $'?+R#~FƊ<]e 3`'n (){ ʘxz.޹Q R zh7:گ7|G$A3@%~kĭNIl?iރkG"^S/-AyyZ(e =Dw²-ze2,/(Y~MɄPWt?ߟ'ngmmRи춏Ȓ;9nYKYR\]K{( "͍XoůbV>2z|,D+.? zFUgʰIeI a5 K.^9W7yEtX{&ᦱwr6jǾzcp]+b YR_ŘvZO7Qϟ<b,nU*.iτPƀv|K=!+~N)C`m{pan37)Ur#I7hrMQrUV-*Rd9߼#ǒ%$fK|%\ԅA _2FhJao[ ,Q[zܖ/T{Y{;˘us|.3(B+mO+xxDcrOM] _cnR_Ck1Yą(~B޼2]VJ48y02,#ogb+ʹ{D3,_ڗ{:RI?MKg'xߒSJ`09Vh=r/LKsMq}-ϗk|/?VϋIGk:~dG`Y(&:bHIP@Eb[g9[T:ֱnĮn  D)ퟹU< Яyg&\x/%nͻ o<,ƾ2w2e!IG>ߑ4kS ܳ-1k:X nQ;0= 'l NuVzMn%*pro뿘j$̆%'Ӏ+&;#bOf+|A"4#?hQ nUo@p ιǴf nSbk[ Dʾ_ɁrS%1__wÚdwB.;ByC~ig+u-h?wp#Hv/ cs1jw49 ]@S>+#UyYkʟ6?_ֿׂ*\J%ހA\8վmy\'hZ|wwXA֍!N3?I;NZm A'+/+9'v_Lyo\R㯂V ;"6ʕ3w 3bňoh+FZSKV=U, v/w^Ղ΂"!WvX p~KSr%Ș}ǂ| BA€,=m[.;@\̵M/|(˟E_Kd) QR'(m΅!o`D[q~tB+BEyE}]H(ͥx1PQm{L!VcFxɧ[KJbWAVţa5kR,=4/nPEWm3ìn/I㞬C42~Lھ)n7Vg2٧͸{bZunQU~A'D O,ٝ4BlAo&ʙ*/A*O?f haB`Y ӬfOrD!D[˟B>KhوP#F+a0Y@LJ  Db&~Ԅ%(fl oܑ5lJ1 k/\dm3W|Hޒb&Pm~%xY J`R{-_Z$VҴ.~/-.N/P>xOL؋TćYJy[ ~_i|dQn^SuXfM"V^"-e} %LhT70'c|eCs-cYLF Z͟5)vgw(UӶ\#뛫n+eCY+\lbT{i{-GبŽIO~j`6Ser-jz/놧 :n)~8M:Bo܋ElH]|MYA+kb'ɋwg13޳ d g I~<ޅAY4M_k|F+AqkpP]̒[o~UW'{B1 2z_Z+)roIO䯟_48jo7( mr#ٯcvn_߳ N9f_7z'ܾATqr|Fn>vg'WK~ _ ,M|,|( /,En( JUP﷗$A5/7Ǽ~!h@Wp76,KFg wz*w/A{8.ٌm!ٔjUNۯ0Tp\ ^PO]R'O-d(es6ό͟M?0bidyu+ތ`o=cY\4:lp(l G,]V-~I7)FYw[ȕ@˷iN_ ?\'?A[IkL56"9N. lܬ~(CSK=<6k@Tq9V2-\w+1^7؇3v&OQJ|k_ik@H%lV@Ǹ)߈cKNTrW8c,qFI4 [wXWh* }[\B|ws1)O\>P7u2-5Bo}%OR?4pk?+EAoV|!j~zCk#ejXYկz>‡A X%Lr _ޛ,nkWLx9S'{\'y%փy8 '|zXJ.[Lk0rK [)n`}+x+,25%c"I` Y)-В5%^.k󢼤!5x |7gAжAr:$?ˁ:^g=WxFȚ5/bKnv0VNpIx}ה=fq7{fesmyȭvnI6ѯ3/ 9#pABbt|>ڪxSO-xXOŀ }/(sϦ~6~MMqqB["70yO7( Z$xS,aWNV]eCqj)gRA%La~h|:_+oJwr?[cAU(4ZDY1J{* NϬ&s&=*fh-o*{u^kB6gWJFXX8:1\`'̡=Ⳏ|ྛƊ_`; 9X4-!hf%@C6k0w{$"Grm *(p ʂ@PȾs _70@ /13J)7o~ۓdfůSۧ?ԯDp}Ax˘\d~쾟h=4Y[رǘs8viKElo{@H\Eރk4NfFƴ#绢:O:{k=~ϸ;p~$' 4ӵ`}~۬8e,dPzaiumU+/|M.WJA٪Y a[yۜTa >+h )aGgO+ |Fxkv bJTc.4L051MSmX;Oo-U`<޺QPדrs8k*oFՎ`*yZ>"QEOdxOfavѡw$_⷗8g^vЎ0a$أ`~NdJ+SJ a0mes{ѐ?_ҺiAz2KATÇ" Nz_#B 1S6]bM6Ƭ )Ħ ݡ+)OȒS,(7M}4%sTWpJ{+Qn" J;LB7Qnn?; s<;jϮ\s- *|3.g6iV[_=baKÀ3wwy%:ԼrKaO1s f~w6~4X~gCE(Wy'iJ '0McVNvn {0su ? vV!( ml T<ڐM:9D4#ݩijam 5b1dwU?yhvIՈtgO\FAhX$~}E[ qW q^ȣB5o>da3ϊN Y905DTvG)sRUeIҹRJ+;xU#-31fcm 4gw0x4Š3#| yTZ z3ZaC)utG+$Qtpv2{.8VU,gDBU'^1϶s"/˄xf}BW\ xyRj!4yةSe8½ QÕ=M0}@5W4 OӶ/PQh{nS6 3\cRj#t}auiԹp s6|CB:` pStoJ[O++T5_f6T"UZ/W?0{޵_F"#' JqNq!Zہd$ܟE3U0h 8lSNm2wua5w@?|J+>ͲOeK脑 `uc +m:K*Y=0hL=h=f 3VpRnHZ 0brxnuР>`ID;pzcVz{ځ0ej0yg0oG(^{,lsQm?S8GEJȶ `q; R `ήedr|Ǐп"0h=fJk c"gA&aҏլ.`~b.܎!l#q;^^wTWOxf5}uo˕/ԚZS׸Yy Sn!PuPJǔlX  V--@))g!bȥw'Vl촀j&bCM@R$//ISÞ.i-.VTE拊ޱS1†|` N},l0fvP[U%8è, a1%ЛJ*]T wY(&S歶nyG :vk|`uikiC=(~k]:fxP o F%ܝ0G:Kf+ZG:r4W^kU@>9r`,k8-OӥG9@2\7ħ^TDW(SW OBr`r1!a`PY.n#i8+sD ϋĵw曔Oo8 j41m˒Ĩ {_ hhLVDbX.s8r#Ԝ_#MS\RZA@55&,F3g_`Kb7yt/`@-[Jb":r7s-E\%vܙ,GvkG ,@s҆boGs٩&}QEj:Z9w31w18-R}Zlģ f2(1&Ic ib9T^' 'Gx㤔wun9q^H [1ƀ$iلy&sJ98> +V5bmu3gpBXS BTPLEn <,OͲsw>4Ϥ[ ^cRsLc u[t 0{N-LX!fa { M[tM_ݿmh_u5,E55٬i N{,IVۄ.BޠuΒH˽2g넝 cRdɂ-+<aзYd 1`25I}a4XJshpcm&0Y#M\K5?ӳ%|'kZWTnB;Dڅŀ9;\[Sa䂅Xyv K&~kU5UiWjwNsP-o EcOX>s0/K(Xrf>. 2CQAJf̻m g.1݌M2v@k.O$Kيp{H}&@UY)[k[]""jDgMT&lAlDfyX\;-aٺ!i8OKA:dpib^$箤R‹lA06mjx0V^l,bLMѰƮ_Q]lc{C4į>Aw~df?Qɹ:ڦ_E&zMܪwfJh+q^cVNbWYwH }"2$1&ZtwVYUۺBcAod U"8SVU ːTk ñT;fq_մ"~!i Z $О)iZNT(ԁb]0i{zfڛyRuo .qC-/Ysa;2VBrqb<57(Cr&~MS`۪ 4M x1m.);&$<\LF`JrDhrՊI =yT鑩!.#n޾TAB7Òmbn8|v&'P(('kM(f$s4)\(W`x@3\V7o[JTPb 滤"uK4/gbX%Im])\?,PFlXb5luM5k79Z^:O[b{exlFjI XU{Tyeմ:΁9i49::veF `G4Nb4M_*UdN\$޹ 7$k>2av~^\|cS"NBDlky6kVhuF1ވ:֘ީPc =Y!c+gq} v0hXr!K._Ѵ#WRk#4j#z? {Ʊ yxEjKiã)+Ym/?? FKsV(v Hꁸ 玪f&t nb}aye !㠒Tz{@`:gȱ J1=No[UBuu' DPڬmI֡_aR!!m6BI-j3ҿsHvֵG p|b2|UwǤr$4-`>Jag g[@񠟨j4MNhK)<`iƢ7#c *"3KPb:$90Z| 8BZgn "3wa;l< 署 4eoUzDhXpX)MW=iHL`buOq_Z#V.ϚƬj;<i@Q7IV~Y5,s h:N5& Eo4$v4֛B* F6Onz{.4k=6f}+ι9\ !nJ]6FoT6H9G+;N9lJe Ci3ep@6[J-u>֏E骄K8j sdw}2e nU_Z5UmW="*%E0pHXoW6ΡmP߻4g?aßS 6=ոo7jN{ƏcB TҔ[ECLOX&ysA|+&&X9QxEkȣ_0ΈSSSOp'KePyP!0@. +UMfMqLaj%&qB79Ⱦ_rLL5  ]p6 e ixA*yQ:}iYV |Ęy`@*~':6$"sHqL pW7'eb VFP<ߏ4Q^4]&mS+-(ZUWu=jV{z)fcvEnt*ã{nNR-&S%J.I[>iJŃRrmc4KW787}A(X\ELosNM<+csHT(`[$T.̵ gRuRWnN9fq㕢`9I(0ˍy?w@׬kU}1X$Z6IJyhۦRe*s5QE"K_&mAq+3::@w#ఊ% ?~c{;ׇoH84rubK~JX%#TgTaa$r/v vf4Hmz`A\Y{3AL.9Sc0!l1a&6+B]a1]6 A?( 6{{>\| /Dᮇ*q32bhlF,2ӊMU Y m%Ql׸6 Y$5R>~/')T0x\W`ÖfL,W_`tP0GƴBN1TR{ oŠ}i K9SD=k/w#/n!)4LΪ~Vt돮O^%o į^l ^+)}}rDzofKodi0]+Jgi=U6B m5ǘ\ xM]uA'꤬ lLMSX.|vG^m+;z_z#M؉Up I{RL7)eEj›ˎitgJ_g3 ̐?i߉ XE{g1bãRnH~2FW@8=CFK]tR9oTb0aC5s:a0koͼϑ٫I#ދRUu]QYwվY4MvLz6ZE:']V ɯ:sƬinZ_FQwZttܾ-LBZ䘉d5b4SPN4yWid9bh{yK,Q:L'HC BQ\]#bD,80GSK&^b^uš6B!.70hh0FI==!ֵ֯ۗ:sfCTS6RAx yADp%3 #0kio>Aa겪ή Y2Hy>FfxCCdvЮ0hOakKäХ9 BWsIMܿx7, lg[i*Q|C(!\BC+wS0;^4S ǁ{j|^%|TEqCO%c)ça1C?,vЖ'-Aj3ZK-$ry{4=eY{fzЀS|`~tdY1J[ꔙod-PΨ#UY2 Ӯzf#.y\q*]1F+hGum YBX"~#Yzdn/x'~ {5+3KL{!S|˧ Zr; /PMr% UvRcزBӽԯ!`8ĕUKKY"@h ,虆l?= is8US=]v1M(۪Ui+0 O'U3u *  `cYJwٻn U8/+]tObaU 3Ǜw!s!YYqq2]8hުpyg֒ñrs+ٯfYԾ9,<9pVXG^w5oֈ b)Bz8dYX;tJ>87*Ҧ-C]ޗm$Z@~|׷Q@ D< nXk T9^Ki$M99abAk TMQY_jCQk ג;Zm#b]q ߥx^bE7\]M՗N8L6ҷ_qiCWM.ŧb[LbSj5(pA{eKD檪p5-E11[ YT*D8#FLބ Ұ]w+wh.@[I4g `J*eΚ kY;δ'N9G~`„}DE_j5ǭ"{K2B` r~/I }V4n XLYGA)NYg}sRhk1Vn VQ,RmU|e6Ӻ`V{<6.{ ᕏ Fi*\enSwY[k6FoP9 W 1vTJz/ox%٩y Qf@ 2fJ:fI~(6VHE%̉l*B 5f(.}#%:NV4z k7 q4!yuVXšɝ{gjj] 5SW=n$yUoFU;uN0. /XA~1 yA؛=E rhԀ!ڄBB*lqB<-39 M1C?+yյwZC6S)DYP WUF-ULyt{MHOE! t/[he׵W^vX=80]]?;Cb g5Me('ri#90oyh x;ZV4p_9z0L!IEPwI7Ε_%݋[%v V_ ;+8lBSi*B9G.RaAфs^ϘbnT?'R46^B& 꺃RX7@%1*𬿥m Ϭ!zgc\,R]*9>}:s.b=L~R;ر2aWEН+kb` *ڱ'0Gz@|RH30 :Z@:g)jMSܙU%~;WTJwBיd}y)@$d*멒$^i'BT1+nC@C4G 9WNS Ė5+|`菱4x[tҘY>u܀3v&G D9fZ`e; u)5̹tT ~'1SHv"W{0w7\[)^U&Luy㕉ܺ@fcM߾?miZO3^oO|k({@_%݉IJjb~h]\#P y(.Zzppvv6&irdf_9>e\UƜʊ^߳kt^Ъd#`4Z +ALy_x@0)~#+ϾWaL hu}yPBKΛE!0]q5W;5ԩGl7s$4 _^nI)!RecT"f'㪁zN?*`q6ؑyHW9BXؠfi:&lCVJ*\|_ >aNy``7Y?'8 rt9bJ,yzt9Iyh%HN5^Ѽ^XZᘙQsɚ4{8pC|9&\X:v#[{&GF\6{-7pD 8 c-Ϳ y kb ~ޠ`mEfwBymmCf8#-Il 9{a>3_+N*W(42/9vqkA"w!ed`l|o[l^i \29hDB< Az3< @LCLfQOyY?R5OL7*qڹ'S7T z*'`Gqr*_bV{ Io~FZ {VAXސfsz No^iNlD~4|O>Kp7ƊRʑ[  _G8*3BK[yiQPa5-R[|XZ SxWZJDr+HWSr%p8){r @nZȦ:Zq8,@yڤn$%,=y\%{c`GqԚ}-inzynǂÔ7\Bw*г>[.{g40V9.ݕ\yfkqվk mzFL+Ϋ/,S1Qrs8oXϸl.i͛ ۡ_U=4Jpّ)aKGg#cUYq#O_K~m H69Mg#-Lo}tI 9s NKϕw <A>¥+$diAA;_OZ1hGwYElRV̳$Vq9y%gZsUƥͶHWi<EZƼ ltyy;SZi㏁AO`J(œ:@2ھ-UտL :w5Wb0LWuK{yuZhb~uaY [mVF gBB5`(̯p)e OMH9EY%~R;WlYҒFޕU,?n1A~m X@cGr/:+ڠr9DEXn_Bo=Bf]cߥW= 1]~.YMe ED BE3*תأFt\α5qM&$ʉzN3(e.1ZN9ﺄ|&㳘Ks3&tt14a=,1:y[ ښgDXn\Eash`Lj:?91g` Ʒ#~tݴ\HDh<jx왪 ylt_1JʫL* \ü1Šu^C^{LQ>/LcT/vy%;2Ɩj>fmؓt]U}3w<УaZO] v//Kͻyx5IlCy4qiŹj wmQ!8-|TTD-f,=u7D_qLIM%,-< =z;vgZ9G$-3QT<ʇJM+XD(RnB{nti6<ÞUђ%stI= t@}+. `kE[:@l9 o1d6,ύs|Uю\XZ@Pb1- {Agn8'uo|tj%X+)[Wk&+\Z81sF 'MGһs28ݘ $z: ŴHUiS2I%>C)ջ"(PxGm_% dʧKS.m܉f\)ʰX8lR^7 \pBt$cIa{}Zk`O_xFbXׂ$}!,ွ|+ "\P@w _[zzW]/5wdòn*UNX.!̚Q+FvA+P@1PQ8 Ti{ %*'S*QuPEDk? փ1j4Ҫm+'R1h+!/Ѧ6u+S',L@ (R}e]-G>򙍨MprrPJmkA 76`4r0]Z)S< ^i0`Z/V#p^Ϻh{4[WUPHW. bo5Џv6U@W-t1zA0N{`)X/oTsZ8=MWO3ȋY,U˵O͙_ÎsFlӂ1C☯Tjz㰆h8ޝcVM;՞ &Dvo/#rw^}]GO.D#U=wUC^4oGf^rx%-s\:/yRr'WYCnhQHպ|.-ټj}Py1 năK.П|&p̩9i:ԩ1Y<n9,Fڄ?? sU㱉9Ƥ)=dġ°4F.[ Ǿ56ɕgLY  p)ǫ!c@&:87ԩ~@9pwTk :0hbSxBDALҺDKՖ,l{c |_̮b8Sbw86"xe‰I阘֨Ԯl[WS8g&KA='b24]NC.1p(o 9hjq`daaGy 1>#]O\Z" <_~)|$^.j^ڄEw&9#BT{ƺ2-B b2[Olܴ[VF=Y.}ye!M2{0K78Xah3wU{Msg{^}Dy b,~g\5:M\Q]XCGH6Ωq w4gf^NE ldT{WB2»voadF];F)tHwQFmCͶlDDR~fib.R}RVUu1@ Dš)x_2 GaD#1ZnUQ Yli+Ik*jV]z {;xYx=t{p3,L^#9S5k`{)O5MQD(k+嶡 N]ȄFOf%Gh{_B'(_abSيѮi<^um#Ik}2ߎF'kfMNv䷟1r9" 1F 1WڅT]0E1L9j3,,͙i QSf^*uEgiBKi#4`a, th7 j~J"VVgrIaZӆ1- ;poǃ< B1ʿl*4Uگޕa\o =9mԉX/}1wFE'!O`tWyPQU][x<2mf".p1SU)Xflm*}m1\s|*)ypE`e@y%_ YÔ*Nw ] _Y뜆)>W_|0@ߘ; ~g-5ͲD f<33iћx|w7) icRƭ-#*L;N$˨KlIgXS')5̈́mjY#=|8eWE`̈6dCBsfU9._6҃F}j?ۥ^_Ni# -XZl(@DԀf))>6&d%VS=IjlIJBWRTc3ɏk{~x ^s@Y c^ҤMlXڍg+f&>-mK.ˆp47r~91>Ceb>GW^0Lg>BC{S=DTmގ' bϚȈQ(U"ٳ5Q΀/'8][^i!l/B,pceZmiUx;;n{uM-;j…zXW/|6~s(-3ѯJҫ+9iڦ_ t1VevAnOF1qۤg&5ek\VBZ*•VvcLŴNw{쾹ȅ궛ɝ&doN&W@{`yϹAJWy|ZB%QFb*f ;o&/Xw9v:Sb\m`'Ie…h7{>Dyqd?UJ_RVG 36?xgVT!Ái.]Ù&`.9-q)P$!ċmcD$lh A_gUK _zSs3>-L\AMpŤ>RL(cCzPKsx7} a:n"t>`_7DҐX jsFWzӯSw%e;Q,RޥbK4&`'N 9?r>$tp"֤{D]k0:qxb }9ʚq@es> 8cA+cAEy`3yY0죤;74)2몺bM*]ҽl d3}̣quXCeX( h|N$čMkexh ~ Uslu O :aӳaR|YZ8s +?lξkqZF({ z.V'NWfJL0n-ŸK0XupR„ XrG(^4W #Ds=J$3 $ pp57+$=V'IHT5a]x.0f1%w5>wYWɣ=`>$BDM6 @a ,W#+JEU`~iTؑ*9[ֻt+̖w4pBޘؽ?j=vMNЁѣ3QK}*r_, }x9Qg6؋=3L;h&NpzZR{F^LXڷ_BW9<ţ֘R3fflާXptwwB7xTx_)%*W17MqB#Аx^SapySsyb7&ǿKJԓ4 (?8\]u#4w8ҧ~UЖRݺXq* ];g,&gq* h/O)\diHb]FBccbLIHƩy6)(yu Xg;R9xBNjnjRкP}ɩ 9;6m&d,Af4UO3~I:]2w}6-j9j@ `fyQ/VPiTr嫸Y-h[ϬZ ޔ<^+}aA=Ē,]pIOc|?j?[r.dwǘ Wfu?2j_("\h"]10/~>F`ZT#ta W]`]Al57d t])Oj󢽫;bj&~GУUMj*,:_jF[IW7YsI5w&у\yRY'5|+LT%^9_"nXҾ!ƊXajp]W=́OYNަ8\c}9-U .OW ck/])QM^}x0p9rFlTQ.p~n9T iZy\ d₃u5i+&>6Kl^ѫdHHbrkӅ5bLԊC0e7{b?ș*aNFꏽX˗SNYpn( iE[ҒU^#b~?zJJ(/y^g~I-: rCJ1ɺ(-ӈL*Ieř9Faw`9UOC[Cmy%݁_YWB L |0ayu|\U崐&yZٽK0?(hH}8qԟcrk~DŽ8vKi*L(o>fB /jJE8sxˬYHgf+]od boIp4o|3`Jߟ^Se2֢9."~*b_9p>wv4M Zg6k{T5tm\`Lh'ϧrpshc:z_,if [%WEVUTu~õ5c,u}YZA-bH5k*^ocO Y,Ϯ+EáJ2_UW9[G*Z7-KҜtIi@.ۚ,w x1+){}e7`bvJ iWx;gF1Y%K~}p-"tWx*."xou}/GD? 1Sq=1]j*껁jǍXB :&;vf{`/ 5yʛF]b a:%ʈzy}/!#B*s( C=1?dߍ)z%Z&/":ӓ5j&`j_"@{N]1VPAtL!-N9#_$ 0FYo Y9@B] anBLCzgJd*,g:^e2P;; iL<3 t045 +xS@sIv)g9}K(3㲇 8~NP3BgʈM,EN)d1-ٳrC PЦ/p)`L.-\1p,d7tΙUjvtCZC*-"FIĹulj4/hXۏNW -@Xe TtQD3Ɯ%L.a&5,49^]7fwzC]w͓+| }>{JjGaJY-JKXBa坨?XSp/k'6:>3x=e*dPهUYDfyo2Q=$;$L{ lfqri |sͲ&]7pۍh]W^b`B߆Px{[SDSmш+ȫiz@dGd~ 5B>knJ$/W,Bf1$F [a!`csdj25f"Dh]44[IAlcc6,TߘV@%FXw a)۲Rp^>:_?Υ6,R?)\^Kc'@03ZazA&AB4X<->TI3A%VB/:$39BI9) g{vaWvmDTo驴`Ja>:U2cϥ^v^רtdV^*(lQbi{-3U-:Ry} [M$`*.=v{ y{S< *+">dYMIs `oiGYZ@W7dcp\]Þh.,Ț Z 76&/G{:@9#)(חw^0s@u*/n\I IY  ̔[;wׂyDB+]`󫪁h&i *sjKi\c{ e(%Mu_+kVA#NhL;Pn5+>Wľؚ_(`%tAC+x{<(TjȦ:tVf C*(iC}Pzn2{W66p0q}E,R<$C[Shw 4Q]YWza#^oITkhƃ#<6Zdc:,fE}fIGNmR%͙Nf Ԇ d'=v:pR3lAQG]xf&#Cp3Qw㒝JK0 nZ3&|l3 +jMO]XGp[.,"6h%ܕ|5+A~F 5-hú ,MS /7Fg]i2]x82a uuks4zae #-QˉJ)lX|&҈AF/ &2"MWɄxisPŚ9 Fv=,Pyb#2*c~tܨ7l?瘼Qګ)&!ܬ'!'>{$A^hGZj">X%XcE4yŜz$? BHиwЯយ0@a:Z!wmJΚ$M3gGx{ǒYURo`f Cda>qa|DaՕ/H}{>s64 ~)j1w $U7b]OҴzq.gթ"q2w\]vx/5qÛoluIgyUvk@xn/W I6sfʖ/BˏSD&;5#(a7 Gj_CO 5~nql^nlMwb ա9txrw.eģvKq8Que s mKPY'W6 G\^]1}@JaƩho7^? %0 DoGvjjo:ο|Ybĕ|r^@J7[hw癵a}we~|s5B(uj/pӑW9UWȖQ|sv]P du >$ϔ TpaR5 R}A]p˹3d,娲(7L9%:iA$*[ć*w"Or'NKtmE+NKQ^G-a'RkG67DgRNeͷ 2uYND\}%i^3spu_>'ɜWLI S(X{ӎ2UބR\ #qQ!摣'l;o" Iˆuq-=5bL>!I5t\'5dYrƠ̩{  9bNu$N0U9e=M .Xǁo]DX;ۣ=*g1^\Q;r =Uo+ds!xĽō+11eX%=QfrbSU[O'%uƪ>agUw#K :v'=lRiF4*]}PN m!f-\FOWHvVOD"' k]T{SBs:H(dܲny f囆 TF^+߱Ի:L ofWe,?2BK("ґI2CO.qe[T\Sъ^F%ļjPjC!^)Z_=;3~>R|>g-HTK)#KO)ӡKf>qc/dUTp\ީPQS1.kL;D:ͬwpgSM&FvnRcvWOå+Zz'8v/Uem]ƙXRǃ;ް# *; s+}.\H)+[9pxw,;(_ea8gё2;5[kհ򠟀тJ17,ɛCVv$hx Mq&`]loH46s)tN"/rQ=Փ0&1$(r-+R(^x,@% 0& >WeԆ8Zunw OfvdpLmK9Q;QrqxL,#MydFI~N $3*i^q;6g A< FSV! gʢR 14H0fpzƜ8JIw6XwP$q[S$oV83PtuJ2.i$鋲́~dS"Mņsv$j0|߭` !*Cj&fTɿ">]6;`"WG05YPshQeHg+8eknYtH5t+wwY^6=<PGߕFglMESF~Ø OʚE/'fMm(-xiϜ,7nI5,q{ִl4sBbh50/viTI|wKBrs  lĹKk]XL0hX.nb9K1]63R!(ǯbn݈?ڠU AQS *#ѕq^k`@9OKBEJpDF`>&믕cֿ%ϥ0/Ud$36^Vތҍ"` ?Fq6/!EJz^Gjl=^ZsX#(NݚN#rPM_q9;EzCF=kT^*P~RԤ f` yTrzϥ~)",Z.Z⭵Ԁ. K^ k}k8bw^Cᗵxc>m &ڲ렟8erl]pݱL('<{w} gߜm߽_" NYa`3?LDJ^)AF/,j;τ,Ai̖1:(TW#5`1Xs6m@cؿw_/ɰRF5b ܎R]gT`RqyE?S+ d `njuX@&vE!3aGك?wYQ+M?:#.kKI_]GB3sJ*lZ "-(U0'^&z^s\7Ϯgϙپ LPh־!ܾ> 챭CrBy܊>y5 x9)BSieOeXlJ^[vwu*DI*Z/c {(Nag*^#0WԵc0O?Z~;''04cy t;G$8AW뇷~͜١w7CV]IwD6Nɣ/BK&lQQ^:xtp{CuB?A{.xu 1]p]7OH.5ɓ#s E"5MZzZ3Dt;9FK}jpCgcxl¼\{ Y.D]ʂ9 )霞WޗU߿f}1Rڨa v]9?7Y޵88ێIPxE!sdmhxxcL_]mφΐ[o\D(:4_$3q@zshuH̽3}RKg#!bH{}g<~I W|-JCoZ""5찚]/2E^>H;2J` 57T;tNMwrSq 'n*snq/onh{(;@ @~D͑^4=; 糫R0JqVqæ# pTg /'wj_U鞈5ʝ((0Zl.< en!PaOO6s TeӢ_>'}w\Ay裗'2p"XgcOm? i(diby" uf2x.IS] z,HshVHCM:NY_a[fs؊lńi*'Qe˜nnQefB'lEn`oA28o93jzQc,j<ۭrԒlB7$zQe;W8Zs`-B~|@.%X]I);:>)qyv˖v8RW#KT\F<\a&̷3Tu%e<]Mw\C^7"K1w=QSaKW!M*4\3{_ d\~6-Ef֜T}E$+v J!}ŢG=-á>_ IfI@!݁zUG| =1cgOe4,`ᡨAםCh`o8aluE+P~D-4PFM琫I0K~ɹlRS)U7Wա,vI!M6#3"6͠Z }='lS:}*0>o?/>b^1(Mqi6ȡw _\ꟜGD|D٣ )4U;B{ FIt遹ωA+2!.>RI*"6ݔ!#$@Zu]j&<̤Tks|,Zj93 Hß `].Xi8aO{N'[2u^y 9LS/ɹc6^Q²%Fdp&*Р"mqkr^%8\}1uoZ&͛U!uO L5vJB8&r:#|Րjs{s*j&Kٯ^aٷ{I4TN,ľT`+L? b],W$.EN]*N2҈%&Cd:fO3#8$zv2Cr*$ #Lx[{w٥ͬO<=d޲uGaVA>&dUv7ٞ9sNZ,M4W "Bls{KdGµ t]g)a >g#4< 7B~1ieG;q>1|%D`c_fOfm# #>&mGYA=="dR#֏9/칁48CjGs#g.}8=+45̤Ğߡ"cN[z!GnzVfWg7ɟmWpa>K>fS T! 1;zfn gKNIM)p&Avf ϩܺP};|vg30: 6S]ېNqtw1SuprgeY-GNFxXy1ۊc.|!OEcSGdI4]pOÛo`PsL2M9gzG?KhxN`$?@>UՇTᣄG1hKԕ m֙?hn˘a9&%2G~41XS%k6g4n`,L>=]|A2cg@]hRGt$0 t mZ1z [y.t3kȳÿPkeIr9LS?F +JylujxsB !V$8ǤD!Aaʙ/ lrKȫ.iu +5k+٭n8fI,;&ZgESdDq"g 74m8M/r47w_kv8@0 l6 A3z7vNݑjs}Fj)XrThQFNk%V)Q>H q5˾&2qk9)ɰWS1ض˘ۣ+e٥mM|}Z) S{RD* "QuISp&;qnq̠dim7M"  _ڻ\[7R\P}Itðl`0ˉ p~ǀD>W|Jίs6%3 0IEٴ@`bi*x 9ך…\-:f_9Ø6)ZUzjfY(rB;_GCm]~Z 5c\?4ƈȉRD ]BI{A{G\SOE(D,p B8ut#Or$fasV{F˯TR:b`n~bnEy@0c 9Y. ";&=֌}s\ \h*^RGk=~T_3vRvjMB#lSj pݵ]}a pbuP>{fDc;)ť*N&2]^ɏT8ҟ1REM veTW&s| sQ9T-\-"HHIT`&I)q3抈~>b'nejqpekg25ggeYy8* jvF>y͹SFhDB !u<5bD(pX* q0S 3<'bJ!aBy }{eɣC%7d5#2FT6KPUʑxM/Ba3W06/_<-*,9GNj*A_|<╄F4Vg`#r*we['zgÎƩX}yA83Qϳ3˸ߝBji.<>~HIHioe4%h.> b>DΦ+2T D YО=9,7_7jlWsR(Qzڳ>hmفKDSE8G;dB#4ة}Mr?4ʊ!=vywʦ;Y}EOCLukBiDUԪ|Fώ,QEMJ3<$CN.9?I-1I7_@RPRm$9I H9C"w>/ŋ+\^9D1^=e [j= Gͽk@lLEJ"(KN5Ϟ +U:3 ;%0A5.v g/ToJJ, {E.7.Q\Iڢ7-R;0+Xzbn#V,(!}\NǙ;fFGץ!]d 5{F)8bfs*F媄 i ז$ ;AZ4хĂ˶h)tf˔ :^d6wq7c9__7˓:CQ@pG\= <HcQ!{ʑ'#@o8YؑXLQ\Q[6Ry{NLS7yIykҳE"Tkh sBf)"PR>݆vk2TL3ذH ."kTQ^I6]ǻ_˴)Ǯ]|^aUjŵm˶鳅.h oEE-⨯0"{9w*Ʉ #q;W6;VˏMt'$~0&̈́1H",iT 4bܐf23TЎ)pnc\Q!A 3w4Ԛ}K~S0꒔Vk5b= ^9eQr qWC(}w \@^hd}ƙuexu_ﻤKgOIbt!Bb" Sh]V7;@I4-ҫd=iWvfRb=HcqJÿDG5U;,3ߙ5TfxerR|zˀn@`U4C +GwB':frY9َ#6X3-Syd2E=LgE8ܶKĒj.sxO+X۲CX|c- uw.~3yf,SĴ(٢^_^a՚ RNczvR>zju݃> r)I$cO/w(^+q $we._wը>и\S oHExL镣k:W7 eq`vgkιtɘjՅcJUaθ$$m6/~_(=?jžJJ2D('|qkf@ˉ;(Maオ0ܽyI?~|z |Z$&9ќ<Ɔhw{k(0 kyQUeUymPkw_k VvE\0!yt_mٌ]tIPp'[}dOΓNjɠeQ i32oqIۑ3YkaNyq,ؽQxب+"<`'L2HqR{;Ȋup`/NlH"{?c)6j(UViy++iv.D+w1]ҁlA ¨,\<="2'yjK,`&#IxXMJ]m$a5윐*[wvISkDwݢ2!'o pEh*`oLiީQldJޅ%vٕ~unvLFR|{э}Z::;# iN1t0ދ0;..M6=6j'-{,ԬLSG j |fS. qPɵ(h\9W!Ƥno2JC ]{v{~'I}1tVXCTmfυ. KFGKwE @8k8$QKCXzrٓ Ua6U5XM?B[i[{*(p9 -kAt?4Hl`SﺖN^{>%@faH̺2>z[`Wmyg̗.MޖqCSU{}s/JSy sI_'N;p$LE?nC-?1zS)1)C`zĐ m9*=i`cTr70yFvmsRq+`jhl6w0i<飯_ ja|-4` hsy#z8 ):hxiMX(}ΰ&D=. JRy/lu9"Mֵ6%쩄ޛ Ѵ Y0]\^Q%H{I﨎y`~ z0R}[@Tմ J}ߕ`PtsA`]ĪGk{H,Nr?Ep}3AZ` {Ww$eQ {ž ke:~N"TuXf6rZ,4i6s kQ`#R8Ex7 %!@g&2Lg; @6JzDk<&S]g2K~2#~,ĚqH闖?6Y.٦#WN2iL3Ck#T]XwsG69 ܼUAwz)H2IHYT\yG~(w' Pll]۵5sVdчPrPΫ33IAl3}pflH#6nb)RmJ3VnrƯڠ8L]pJ};{@ ɫ]{'IϭwIV #$rb)GqC;J7ZL G.}G&QQӠr $OQ>LC'`q(d\泾xiJ #v =msP$qz+K F*(IP. [W2%{qCjJt:Iֶs /p0 &R!ȅ|wV>fFuә LM0WFt%rzIII=:EZ1ȣڔ GgJV2fH.Mpz<Ҟ VNW1k}#vjT/L@ 9dLk](qc3mȈQT4Z躠\BGdnzFR}- t$eVOƎ誫8oNP"u_Uh&ٛ(1 j*TM2?̊Mn=׌ߩL+ҁS2?A( BDc0yo ƃyW6f޸B^'>iuBxj*BzI*B ZS.EC..(DXUfi$o% L9oC6I46/yMjjU=|c?*zfіePr$4jRcmx9"zU۰Co(gF؅XAlT]d/;}, CKfL}䕅E%%K @Noԑ1]'flsrTLN;IDATK>b4W[mɁ#eoYӔz"zz $&$PoP>7Ln̥v c&p+y#H{}\rNCr߲WB+'/5@phܺipbcka)hb"qǙLT4 !-ک'?}ʜ\Zcєsqp3ߢ)q($)K|BtK{ZY ku[:6JWGm=wB $ъ^y6(m~$ԽRöܘDj}u]>peVY)?B#fb!DjҡGV?Gh.8[ $aڋ4>/? lp}IP:*r02)SC{':fw.o )̍M[z,+˞rZX8Yb?`Y#៏u4`yt9\c8#Wq@P4C`|üYX} S  AP9~dG]?|&+ kgo5yepֶ,xk( [`俔>4-|$!$f]]V)6~4`f8&3Na?(+rcNy`<(YήH姟n rRj5VK8r@JuǺxi@gF毝u8ga˹~E*Di 00&t_Ռ@CQœa…sJ[ (ξJP-#+F3?b Ҵ^keT|IIE)mЉLAQ'5&m~0(Rgsn5Ge#KYHyN,[4%Z7^VG%45}TgTG+_Þ]~4XH |=¬ p&F2H0/*rJ<7\o#nK<'@^ րz/2dvO[<:zրUv|H~ ZNܒ"~2~..p5꿼fgdP8f-:`9xD(GܓN Y(14ja[Y5P&X͕+WUc…'ץWB֥g|t>oys3h/γsxUZ=ʧĢyg2/t'|G/3lܼ4|9,/"ʐbw{1 ZQC5?-TJm_k#zW~ !j Qf 'WN:[pW}B];~vN?nސef0K>ptS$e C&4)R%Oxs:37(D E#-1L| b(c$lSVB<;=fXBm\ӓya42OU%(jįn- z-SEbL/4pamh.=EB; 7>aҔZB;^^BD 8m0?sp +cƈ?˵?90nsLO\ %|Vg%{Jwch1vЋ`zԓt/~g"MwM RǯKD8'k suգU!H.C $0Ci]xrJ UPi`0l .QMR}J /p1&:aVW8k=fؤ6 .Kvٵ|:L>=J[Zj˃`漐u^N%]vl$p&RB3b{/r#I%Ns \5BwpcrhZ=-ֹGЏ=ťOșn`u"77 =Y[rJr2LaY9mf'vB&$^D ~$w8)oonhHeB-2I%s\,T,""p>Y"YGTH5 p>M Bx(.į5E3Vfq6kizMׯ fȁ Wlb*[yoTӧ[ S_s\@Ϡ;&#g{o<uݹ֯ZDDR0'oql8/Ku`\Fs*{JK{F؎-3E9+X|8TmDH}ol޹g'PzF"<&/yաL?یO6^L6Û7('6zFɞ7KMܨWQ4>s〪8"[HuGH8N`''ZnL@R77_}. \h E%I1׻{ŦvI*|cp`Xj}1C"h\hrC3Վ$TFsg SX^1?Zg֯#|/n(u>dN`?{$ |0.5gnw'}΅jv8,*M91}/E&UUT!/7NuqTn`wWثԛEj܅Sc4ԶD̠?Tgecc,1# قxcȥ;U׍, YR~@y"v]]Y[]Zc9G("/z᲏`{gΜ[k8mcۂ./|X(dcEp#Ú2uɄce&>uժ5gCMk[VKrFfnF]]M-G;NBA'˽,-ҹ5"~q|~,!)5|$ }v)W+{/nM]W~bfv(Wzm+#g=a*w2U;Q1`$^B2*JZ1#Smp&9*Eqƒ㰯߈R(!8C-$w2{?IZ˾Im8iy!0l4Uɭdk^sw=McPo'~-;i\VxXbʯ{ob5 }'i v7МԞyrs&D{|〔\<࿑/nHOi4Rw4pSѢF.DE;>&hTV> QbחLJFv7 :QtAA ז%xD4TF9G_DMz-DUaA*:F =>4bȁ{ėJ^T2eݧ>b1kcTSk?fɦuIMN\Pyݏ9ag{,Q+_VVhMyjYQW^}c|kA襐| Ryt*j߈ :͋t|~3#jT̹rn^^>z^Xs[~"(-QɝgMeDS ɴG^e 8Gɺޏ\J* bH-<8wuxaT|u^#k $qGR~]Ww ziD&<6O]~]n9 A2$r'9Y\-rjHAVmrLxѨsճŐwbGZ0'45Oר~֩y*׭c3Al}՜olkz^X嗩jOg(彝kuO%] O& /Q)_{$O}QQ6LҽBi SS~yd]c\(p%;q[^: GD )Wdsi\o0q/÷jʢDXhU,4 8UOw.YV/SxaL|_>sRμ QrO`E\(ɟxWK69A l8?f1G}r lԟ9Z5YoRI#4I3!ѕ/ZRwYI $FCM4tNx<`Fr%+^oee Ϡ&'`)IENDB`chessx-1.0.0/src/database/query.cpp000644 001750 001750 00000022470 12223260306 020016 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005 William Hoggarth * * (C) 2005-2006 Marius Roets * * (C) 2006-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "query.h" Query::Query() { clear(); } Query::~Query() { while(!m_search.isEmpty()) { delete m_search.takeFirst(); } clear(); } Search::Operator Query::searchOperator(int index) const { if(!isValidIndex(index)) { return Search::NullOperator; } int i = m_operatorMap.indexOf(index); if(i >= 0) { return m_operator.at(i); } else { return Search::NullOperator; } } Search* Query::search(int index) { if(!isValidIndex(index)) { return NULL; } int i = m_searchMap.indexOf(index); if(i >= 0) { return m_search.at(i); } else { return NULL; } } int Query::count() const { return m_elementType.count(); } int Query::countOperators() const { return m_operatorMap.count(); } int Query::countOperands() const { return m_searchMap.count(); } bool Query::isElementSearch(int index) const { if(!isValidIndex(index)) { return false; } if(m_elementType[index] == SearchElement) { return true; } else { return false; } } bool Query::isElementOperator(int index) const { if(!isValidIndex(index)) { return false; } if(m_elementType[index] == OperatorElement) { return true; } else { return false; } } bool Query::isValid() { int i; if(!internalCheck()) { return false; } // Check if there are enough operands for the operators int operandCount = 0; Search::Operator op; ElementTypeList::iterator elementIter; for(elementIter = m_elementType.begin(), i = 0; elementIter != m_elementType.end(); ++elementIter, ++i) { switch(*elementIter) { case SearchElement : ++operandCount; break; case OperatorElement : op = searchOperator(i); switch(op) { case Search::And : case Search::Or : case Search::Remove : // These operators need 2 operands, and leaves one answer on the stack if(operandCount < 2) { return false; } --operandCount; break; case Search::Not : //Not needs one operand, and it leaves one answer on the stack if(operandCount < 1) { return false; } break; case Search::NullOperator : // Not sure if this is valid or not break; default : // Undefined operator return false; } break; default : // Undefined element return false; } } if(operandCount != 1) { qDebug("Warning: Not enough operators to evaluate all operands"); } return true; } void Query::append(Search::Operator op) { m_operator.append(op); m_operatorMap.append(m_elementType.count()); m_elementType.append(OperatorElement); } void Query::append(const Search& search) { m_search.append(search.clone()); m_searchMap.append(m_elementType.count()); m_elementType.append(SearchElement); } bool Query::set(int index, Search::Operator op) { if(!isValidIndex(index)) { return false; } int subindex = m_operatorMap.indexOf(index); if(subindex >= 0) { // In this case the given index is already an operator, so we just replace it m_operator[subindex] = op; return true; } else { subindex = m_searchMap.indexOf(index); if(subindex >= 0) { // Here the given index is a search, so we have to remove the search, // and add a operator at that position. If autodelete is set, the memory // for the search will be deallocated. m_searchMap.removeAt(m_searchMap.at(subindex)); delete m_search.at(subindex); m_search.removeAt(subindex); m_operator.append(op); m_operatorMap.append(index); m_elementType[index] = OperatorElement; return true; } else { // The index could not be found in the search or operator lists. Strange!? return false; } } } bool Query::set(int index, const Search& search) { if(!isValidIndex(index)) { return false; } int subindex = m_searchMap.indexOf(index); if(subindex >= 0) { delete m_search.at(subindex); m_search.replace(subindex, search.clone()); return true; } else { subindex = m_operatorMap.indexOf(index); if(subindex >= 0) { // Here the given index is a operator, so we have to remove the operator, // and add a search at that position m_operatorMap.removeAt(m_operatorMap.at(subindex)); m_operator.removeAt(m_operator.at(subindex)); m_search.append(search.clone()); m_searchMap.append(index); m_elementType[index] = SearchElement; return true; } else { // The index could not be found in the operator or search lists return false; } } } bool Query::remove(int index) { int indexToRemove; IntList::iterator intIt; if(!isValidIndex(index)) { return false; } switch(m_elementType[index]) { case OperatorElement: indexToRemove = m_operatorMap.indexOf(index); if(indexToRemove >= 0) { m_operatorMap.removeAt(m_operatorMap.at(indexToRemove)); m_operator.removeAt(m_operator.at(indexToRemove)); } else { // Element type does not match actual element return false; } break; case SearchElement: indexToRemove = m_searchMap.indexOf(index); if(indexToRemove >= 0) { m_searchMap.removeAt(m_searchMap.at(indexToRemove)); delete m_search.at(indexToRemove); m_search.removeAt(indexToRemove); } else { // Element type does not match actual element return false; } break; default : // Undefined element return false; } m_elementType.removeAt(m_elementType.at(index)); // Reduces index for elements after the element being remove, moving them // up in the virtual list. for(intIt = m_operatorMap.begin(); intIt != m_operatorMap.end(); ++intIt) { if((*intIt) > index) { (*intIt)--; } } for(intIt = m_searchMap.begin(); intIt != m_searchMap.end(); ++intIt) { if((*intIt) > index) { (*intIt)--; } } return true; } void Query::clear() { while(!m_search.isEmpty()) { delete m_search.takeFirst(); } m_search.clear(); m_operator.clear(); m_searchMap.clear(); m_operatorMap.clear(); m_elementType.clear(); } bool Query::isValidIndex(unsigned int index) const { if((int)index > (int)(m_elementType.count() - 1)) { return false; } return true; } bool Query::internalCheck() { int i; Search::Operator op; Search *s = NULL; ElementTypeList::iterator elementIter; if(count() != (countOperands() + countOperators())) { return false; } for(elementIter = m_elementType.begin(), i = 0; elementIter != m_elementType.end(); ++elementIter, ++i) { switch(*elementIter) { case SearchElement : s = search(i); if(s == NULL) { return false; } switch(s->type()) { case Search::NullSearch : case Search::PositionSearch : case Search::EloSearch : break; default : // undefined search return false; } break; case OperatorElement : op = searchOperator(i); switch(op) { case Search::And : case Search::Or : case Search::Remove : case Search::Not : case Search::NullOperator : break; default : // Undefined operator return false; } break; default : // Undefined element return false; } } return true; } chessx-1.0.0/src/quazip/quazipdir.cpp000644 001750 001750 00000036241 12223260306 020427 0ustar00niklasniklas000000 000000 #include "quazipdir.h" #include #include class QuaZipDirPrivate: public QSharedData { friend class QuaZipDir; private: QuaZipDirPrivate(QuaZip *zip, const QString &dir = QString()): zip(zip), dir(dir), caseSensitivity(QuaZip::csDefault), filter(QDir::NoFilter), sorting(QDir::NoSort) {} QuaZip *zip; QString dir; QuaZip::CaseSensitivity caseSensitivity; QDir::Filters filter; QStringList nameFilters; QDir::SortFlags sorting; template bool entryInfoList(QStringList nameFilters, QDir::Filters filter, QDir::SortFlags sort, TFileInfoList &result) const; inline QString simplePath() const { return QDir::cleanPath(dir); } }; QuaZipDir::QuaZipDir(const QuaZipDir &that): d(that.d) { } QuaZipDir::QuaZipDir(QuaZip *zip, const QString &dir): d(new QuaZipDirPrivate(zip, dir)) { if(d->dir.startsWith('/')) { d->dir = d->dir.mid(1); } } QuaZipDir::~QuaZipDir() { } bool QuaZipDir::operator==(const QuaZipDir &that) { return d->zip == that.d->zip && d->dir == that.d->dir; } QuaZipDir& QuaZipDir::operator=(const QuaZipDir &that) { this->d = that.d; return *this; } QString QuaZipDir::operator[](int pos) const { return entryList().at(pos); } QuaZip::CaseSensitivity QuaZipDir::caseSensitivity() const { return d->caseSensitivity; } bool QuaZipDir::cd(const QString &directoryName) { if(directoryName == "/") { d->dir = ""; return true; } QString dirName = directoryName; if(dirName.endsWith('/')) { dirName.chop(1); } if(dirName.contains('/')) { QuaZipDir dir(*this); if(dirName.startsWith('/')) { #ifdef QUAZIP_QUAZIPDIR_DEBUG qDebug("QuaZipDir::cd(%s): going to /", dirName.toUtf8().constData()); #endif if(!dir.cd("/")) { return false; } } QStringList path = dirName.split('/', QString::SkipEmptyParts); for(QStringList::const_iterator i = path.constBegin(); i != path.end(); ++i) { const QString &step = *i; #ifdef QUAZIP_QUAZIPDIR_DEBUG qDebug("QuaZipDir::cd(%s): going to %s", dirName.toUtf8().constData(), step.toUtf8().constData()); #endif if(!dir.cd(step)) { return false; } } d->dir = dir.path(); return true; } else // no '/' { if(dirName == ".") { return true; } else if(dirName == "..") { if(isRoot()) { return false; } else { int slashPos = d->dir.lastIndexOf('/'); if(slashPos == -1) { d->dir = ""; } else { d->dir = d->dir.left(slashPos); } return true; } } else // a simple subdirectory { if(exists(dirName)) { if(isRoot()) { d->dir = dirName; } else { d->dir += "/" + dirName; } return true; } else { return false; } } } } bool QuaZipDir::cdUp() { return cd(".."); } unsigned int QuaZipDir::count() const { return entryList().count(); } QString QuaZipDir::dirName() const { return QDir(d->dir).dirName(); } QuaZipFileInfo QuaZipDir_getFileInfo(QuaZip *zip, bool *ok, const QString &relativeName, bool isReal) { QuaZipFileInfo info; if(isReal) { *ok = zip->getCurrentFileInfo(&info); } else { *ok = true; info.compressedSize = 0; info.crc = 0; info.diskNumberStart = 0; info.externalAttr = 0; info.flags = 0; info.internalAttr = 0; info.method = 0; info.uncompressedSize = 0; info.versionCreated = info.versionNeeded = 0; } info.name = relativeName; return info; } template void QuaZipDir_convertInfoList(const QList &from, TFileInfoList &to); template<> void QuaZipDir_convertInfoList(const QList &from, QList &to) { to = from; } template<> void QuaZipDir_convertInfoList(const QList &from, QStringList &to) { to.clear(); for(QList::const_iterator i = from.constBegin(); i != from.constEnd(); ++i) { to.append(i->name); } } // utility class to restore the current file class QuaZipDirRestoreCurrent { public: inline QuaZipDirRestoreCurrent(QuaZip *zip): zip(zip), currentFile(zip->getCurrentFileName()) {} inline ~QuaZipDirRestoreCurrent() { zip->setCurrentFile(currentFile); } private: QuaZip *zip; QString currentFile; }; class QuaZipDirComparator { private: QDir::SortFlags sort; static QString getExtension(const QString &name); int compareStrings(const QString &string1, const QString &string2); public: inline QuaZipDirComparator(QDir::SortFlags sort): sort(sort) {} bool operator()(const QuaZipFileInfo &info1, const QuaZipFileInfo &info2); }; QString QuaZipDirComparator::getExtension(const QString &name) { if(name.endsWith('.') || name.indexOf('.', 1) == -1) { return ""; } else { return name.mid(name.lastIndexOf('.') + 1); } } int QuaZipDirComparator::compareStrings(const QString &string1, const QString &string2) { if(sort & QDir::LocaleAware) { if(sort & QDir::IgnoreCase) { return string1.toLower().localeAwareCompare(string2.toLower()); } else { return string1.localeAwareCompare(string2); } } else { return string1.compare(string2, (sort & QDir::IgnoreCase) ? Qt::CaseInsensitive : Qt::CaseSensitive); } } bool QuaZipDirComparator::operator()(const QuaZipFileInfo &info1, const QuaZipFileInfo &info2) { QDir::SortFlags order = sort & (QDir::Name | QDir::Time | QDir::Size | QDir::Type); if((sort & QDir::DirsFirst) == QDir::DirsFirst || (sort & QDir::DirsLast) == QDir::DirsLast) { if(info1.name.endsWith('/') && !info2.name.endsWith('/')) { return (sort & QDir::DirsFirst) == QDir::DirsFirst; } else if(!info1.name.endsWith('/') && info2.name.endsWith('/')) { return (sort & QDir::DirsLast) == QDir::DirsLast; } } bool result; int extDiff; switch(order) { case QDir::Name: result = compareStrings(info1.name, info2.name) < 0; break; case QDir::Type: extDiff = compareStrings(getExtension(info1.name), getExtension(info2.name)); if(extDiff == 0) { result = compareStrings(info1.name, info2.name) < 0; } else { result = extDiff < 0; } break; case QDir::Size: if(info1.uncompressedSize == info2.uncompressedSize) { result = compareStrings(info1.name, info2.name) < 0; } else { result = info1.uncompressedSize < info2.uncompressedSize; } break; case QDir::Time: if(info1.dateTime == info2.dateTime) { result = compareStrings(info1.name, info2.name) < 0; } else { result = info1.dateTime < info2.dateTime; } break; default: qWarning("QuaZipDirComparator(): Invalid sort mode 0x%2X", static_cast(sort)); return false; } return (sort & QDir::Reversed) ? !result : result; } template bool QuaZipDirPrivate::entryInfoList(QStringList nameFilters, QDir::Filters filter, QDir::SortFlags sort, TFileInfoList &result) const { QString basePath = simplePath(); if(!basePath.isEmpty()) { basePath += "/"; } int baseLength = basePath.length(); result.clear(); QuaZipDirRestoreCurrent saveCurrent(zip); if(!zip->goToFirstFile()) { return zip->getZipError() == UNZ_OK; } QDir::Filters fltr = filter; if(fltr == QDir::NoFilter) { fltr = this->filter; } if(fltr == QDir::NoFilter) { fltr = QDir::AllEntries; } QStringList nmfltr = nameFilters; if(nmfltr.isEmpty()) { nmfltr = this->nameFilters; } QSet dirsFound; QList list; do { QString name = zip->getCurrentFileName(); if(!name.startsWith(basePath)) { continue; } QString relativeName = name.mid(baseLength); bool isDir = false; bool isReal = true; if(relativeName.contains('/')) { int indexOfSlash = relativeName.indexOf('/'); // something like "subdir/" isReal = indexOfSlash == relativeName.length() - 1; relativeName = relativeName.left(indexOfSlash + 1); if(dirsFound.contains(relativeName)) { continue; } isDir = true; } dirsFound.insert(relativeName); if((fltr & QDir::Dirs) == 0 && isDir) { continue; } if((fltr & QDir::Files) == 0 && !isDir) { continue; } if(!nmfltr.isEmpty() && QDir::match(nmfltr, relativeName)) { continue; } bool ok; QuaZipFileInfo info = QuaZipDir_getFileInfo(zip, &ok, relativeName, isReal); if(!ok) { return false; } list.append(info); } while(zip->goToNextFile()); QDir::SortFlags srt = sort; if(srt == QDir::NoSort) { srt = sorting; } #ifdef QUAZIP_QUAZIPDIR_DEBUG qDebug("QuaZipDirPrivate::entryInfoList(): before sort:"); foreach(QuaZipFileInfo info, list) { qDebug("%s\t%s", info.name.toUtf8().constData(), info.dateTime.toString(Qt::ISODate).toUtf8().constData()); } #endif if(srt != QDir::NoSort && (srt & QDir::Unsorted) != QDir::Unsorted) { if(QuaZip::convertCaseSensitivity(caseSensitivity) == Qt::CaseInsensitive) { srt |= QDir::IgnoreCase; } QuaZipDirComparator lessThan(srt); qSort(list.begin(), list.end(), lessThan); } QuaZipDir_convertInfoList(list, result); return true; } QList QuaZipDir::entryInfoList(const QStringList &nameFilters, QDir::Filters filters, QDir::SortFlags sort) const { QList result; if(d->entryInfoList(nameFilters, filters, sort, result)) { return result; } else { return QList(); } } QList QuaZipDir::entryInfoList(QDir::Filters filters, QDir::SortFlags sort) const { return entryInfoList(QStringList(), filters, sort); } QStringList QuaZipDir::entryList(const QStringList &nameFilters, QDir::Filters filters, QDir::SortFlags sort) const { QStringList result; if(d->entryInfoList(nameFilters, filters, sort, result)) { return result; } else { return QStringList(); } } QStringList QuaZipDir::entryList(QDir::Filters filters, QDir::SortFlags sort) const { return entryList(QStringList(), filters, sort); } bool QuaZipDir::exists(const QString &filePath) const { if(filePath == "/") { return true; } QString fileName = filePath; if(fileName.endsWith('/')) { fileName.chop(1); } if(fileName.contains('/')) { QFileInfo fileInfo(fileName); #ifdef QUAZIP_QUAZIPDIR_DEBUG qDebug("QuaZipDir::exists(): fileName=%s, fileInfo.fileName()=%s, " "fileInfo.path()=%s", fileName.toUtf8().constData(), fileInfo.fileName().toUtf8().constData(), fileInfo.path().toUtf8().constData()); #endif QuaZipDir dir(*this); return dir.cd(fileInfo.path()) && dir.exists(fileInfo.fileName()); } else { if(fileName == "..") { return !isRoot(); } else if(fileName == ".") { return true; } else { QStringList entries = entryList(QDir::AllEntries, QDir::NoSort); #ifdef QUAZIP_QUAZIPDIR_DEBUG qDebug("QuaZipDir::exists(): looking for %s", fileName.toUtf8().constData()); for(QStringList::const_iterator i = entries.constBegin(); i != entries.constEnd(); ++i) { qDebug("QuaZipDir::exists(): entry: %s", i->toUtf8().constData()); } #endif Qt::CaseSensitivity cs = QuaZip::convertCaseSensitivity( d->caseSensitivity); if(filePath.endsWith('/')) { return entries.contains(filePath, cs); } else { return entries.contains(fileName, cs) || entries.contains(fileName + "/", cs); } } } } bool QuaZipDir::exists() const { QDir thisDir(d->dir); return QuaZipDir(d->zip, thisDir.filePath("..")).exists(thisDir.dirName()); } QString QuaZipDir::filePath(const QString &fileName) const { return QDir(d->dir).filePath(fileName); } QDir::Filters QuaZipDir::filter() { return d->filter; } bool QuaZipDir::isRoot() const { return d->simplePath().isEmpty(); } QStringList QuaZipDir::nameFilters() const { return d->nameFilters; } QString QuaZipDir::path() const { return d->dir; } QString QuaZipDir::relativeFilePath(const QString &fileName) const { return QDir(d->dir).relativeFilePath(fileName); } void QuaZipDir::setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity) { d->caseSensitivity = caseSensitivity; } void QuaZipDir::setFilter(QDir::Filters filters) { d->filter = filters; } void QuaZipDir::setNameFilters(const QStringList &nameFilters) { d->nameFilters = nameFilters; } void QuaZipDir::setPath(const QString &path) { QString newDir = path; if(newDir == "/") { d->dir = ""; } else { if(newDir.endsWith('/')) { newDir.chop(1); } if(newDir.startsWith('/')) { newDir = newDir.mid(1); } d->dir = newDir; } } void QuaZipDir::setSorting(QDir::SortFlags sort) { d->sorting = sort; } QDir::SortFlags QuaZipDir::sorting() const { return d->sorting; } chessx-1.0.0/src/database/openingtree.cpp000644 001750 001750 00000023706 12223260306 021173 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "openingtree.h" #include "common.h" #include "database.h" #include const unsigned MinAveYear = 1; const unsigned MinAveRating = 5; MoveData::MoveData() { count = 0; for(int r = ResultUnknown; r <= BlackWin; ++r) { result[r] = 0; } year = rating = 0; dated = rated = 0; } void MoveData::addGame(Game& g, Color c, MoveType movetype) { if(!count) move = (movetype == StandardMove) ? g.moveToSan(Game::MoveOnly, Game::PreviousMove) : qApp->translate("MoveData", "[end]"); ++count; result[g.result()]++; unsigned elo = (c == White) ? g.tag("WhiteElo").toInt() : g.tag("BlackElo").toInt(); if(elo >= 1000) { rating += elo; ++rated; } unsigned y = g.tag("Date").section(".", 0, 0).toInt(); if(y > 1000) { year += y; ++dated; } } double MoveData::percentage() const { unsigned c = result[ResultUnknown] + 2 * result[WhiteWin] + result[Draw]; return c * 500 / count / 10.0; } int MoveData::averageRating() const { return rated ? rating / rated : 0; } int MoveData::averageYear() const { return dated ? year / dated : 0; } bool operator<(const MoveData& m1, const MoveData& m2) { return m1.count < m2.count || (m1.count == m2.count && m1.move < m2.move); } bool compareMove(const MoveData& m1, const MoveData& m2) { return m1.move < m2.move; } bool compareScore(const MoveData& m1, const MoveData& m2) { return m1.percentage() < m2.percentage() || (m1.percentage() == m2.percentage() && m1.move < m2.move); } bool compareRating(const MoveData& m1, const MoveData& m2) { return m1.averageRating() < m2.averageRating() || (m1.averageRating() == m2.averageRating() && m1.move < m2.move); } bool compareYear(const MoveData& m1, const MoveData& m2) { return m1.averageYear() < m2.averageYear() || (m1.averageYear() == m2.averageYear() && m1.move < m2.move); } OpeningTreeUpdater oupd; void OpeningTreeUpdater::run() { Game g; QMap moves; int games = 0; for(int i = 0; i < m_filter->size(); ++i) { m_filter->database()->lock(); m_filter->database()->loadGameMoves(i, g); m_filter->database()->unlock(); int id = g.findPosition(m_board); if((id != NO_MOVE) && (m_bEnd ? g.atGameEnd(id) : true)) { if(m_updateFilter) { m_filter->set(i, id + 1); // not zero means success, but id could be 0. } m_filter->database()->lock(); m_filter->database()->loadGameHeaders(i, g); m_filter->database()->unlock(); g.moveToId(id); if(g.atGameEnd()) { moves[Move()].addGame(g, m_board.toMove(), MoveData::GameEnd); } else { g.forward(); moves[g.move()].addGame(g, m_board.toMove()); } ++games; } else { if(m_updateFilter) { m_filter->set(i, 0); } } if(i * 100 / m_filter->size() > (i - 1) * 100 / m_filter->size()) { emit progress(i * 100 / m_filter->size()); } if(m_break) { break; } } *m_games = games; m_moves->clear(); if(!m_break) { for(QMap::iterator it = moves.begin(); it != moves.end(); ++it) { m_moves->append(it.value()); } qSort(m_moves->begin(), m_moves->end()); emit UpdateFinished(&m_board); } else { emit UpdateTerminated(&m_board); } } void OpeningTreeUpdater::cancel() { m_break = true; } bool OpeningTreeUpdater::updateFilter(Filter& f, const Board& b, QList& m, int& g, bool updateFilter, bool bEnd) { m_break = false; m_filter = &f; m_board = b; m_moves = &m; m_games = &g; m_bEnd = bEnd; m_updateFilter = updateFilter; // todo: if running wait for stop start(); return true; } bool OpeningTree::updateFilter(Filter& f, const Board& b, bool updateFilter, bool bEnd) { if(!oupd.isRunning()) { if(&f == m_filter && b == m_board && m_bEnd == bEnd) { return true; } m_bEnd = bEnd; m_board = b; m_filter = &f; m_updateFilter = updateFilter; emit openingTreeUpdateStarted(); m_bRequestPending = false; connect(&oupd, SIGNAL(UpdateFinished(Board*)), this, SLOT(updateFinished(Board*)), Qt::UniqueConnection); connect(&oupd, SIGNAL(UpdateTerminated(Board*)), this, SLOT(updateTerminated(Board*)), Qt::UniqueConnection); connect(&oupd, SIGNAL(progress(int)), SIGNAL(progress(int)), Qt::UniqueConnection); return oupd.updateFilter(f, b, m_moves, m_games, m_updateFilter, m_bEnd); } else { if(&f == m_filter && b == m_board && m_bEnd == bEnd) { return true; } m_bEnd = bEnd; m_board = b; m_filter = &f; m_updateFilter = updateFilter; m_bRequestPending = true; oupd.cancel(); return false; } } void OpeningTree::cancel(bool bVisible) { if(!bVisible && oupd.isRunning()) { m_bRequestPending = false; oupd.cancel(); oupd.wait(200); } } void OpeningTree::updateFinished(Board* b) { sort(); emit openingTreeUpdated(); if(m_bRequestPending) { updateTerminated(b); } } void OpeningTree::updateTerminated(Board*) { if(m_bRequestPending) { emit openingTreeUpdateStarted(); m_bRequestPending = false; connect(&oupd, SIGNAL(UpdateFinished(Board*)), this, SLOT(updateFinished(Board*)), Qt::UniqueConnection); connect(&oupd, SIGNAL(UpdateTerminated(Board*)), this, SLOT(updateTerminated(Board*)), Qt::UniqueConnection); connect(&oupd, SIGNAL(progress(int)), SIGNAL(progress(int)), Qt::UniqueConnection); oupd.updateFilter(*m_filter, m_board, m_moves, m_games, m_updateFilter, m_bEnd); } } QString OpeningTree::debug() { QString s; for(int i = 0; i < m_moves.count(); ++i) s.append(QString("%1. %2\t%3 games\t%4%\n") .arg(i + 1).arg(m_moves[i].move).arg(m_moves[i].count).arg(m_moves[i].percentage())); return s; } int OpeningTree::rowCount(const QModelIndex& parent) const { return parent.isValid() ? 0 : m_moves.count(); } int OpeningTree::columnCount(const QModelIndex&) const { return m_names.count(); } OpeningTree::OpeningTree() : m_sortcolumn(1), m_order(Qt::DescendingOrder), m_filter(0) { m_names << tr("Move") << tr("Count") << tr("Score") << tr("Rating") << tr("Year"); } OpeningTree::OpeningTree(Filter & f, const Board & b, bool updFilter) : m_sortcolumn(1), m_order(Qt::DescendingOrder), m_filter(0) { m_names << tr("Move") << tr("Count") << tr("Score") << tr("Rating") << tr("Year"); updateFilter(f, b, updFilter, false); } QVariant OpeningTree::headerData(int section, Qt::Orientation orientation, int role) const { if(role == Qt::DisplayRole && orientation == Qt::Horizontal) { return m_names[section]; } else { return QVariant(); } } QVariant OpeningTree::data(const QModelIndex& index, int role) const { if(role != Qt::DisplayRole || !index.isValid() || index.row() >= m_moves.count()) { return QVariant(); } switch(index.column()) { case 0: return QString("%1: %2").arg(index.row() + 1).arg(m_moves[index.row()].move); case 1: { if(m_games == 0) { return ""; } int percentage = m_moves[index.row()].count * 1000 / m_games / 10.0; QString approx; if(percentage == 0) { percentage = 1; approx = "<"; } return QString("%1: %2%3%") .arg(m_moves[index.row()].count) .arg(approx) .arg(percentage); } case 2: return QString("%1%").arg(m_moves[index.row()].percentage()); case 3: return m_moves[index.row()].rated >= MinAveRating ? m_moves[index.row()].averageRating() : QVariant(); case 4: return m_moves[index.row()].dated >= MinAveYear ? m_moves[index.row()].averageYear() : QVariant(); default: return QVariant(); } } void OpeningTree::sort(int column, Qt::SortOrder order) { m_sortcolumn = column; m_order = order; switch(column) { case 0: qSort(m_moves.begin(), m_moves.end(), compareMove); break; case 1: qSort(m_moves.begin(), m_moves.end()); break; case 2: qSort(m_moves.begin(), m_moves.end(), compareScore); break; case 3: qSort(m_moves.begin(), m_moves.end(), compareRating); break; case 4: qSort(m_moves.begin(), m_moves.end(), compareYear); break; }; if(order == Qt::DescendingOrder) for(int i = 0; i < m_moves.count() / 2; ++i) { qSwap(m_moves[i], m_moves[m_moves.count() - i - 1]); } beginResetModel(); endResetModel(); } void OpeningTree::sort() { sort(m_sortcolumn, m_order); } QString OpeningTree::move(const QModelIndex& index) const { return index.isValid() ? m_moves[index.row()].move : QString(); } Board OpeningTree::board() const { return m_board; } chessx-1.0.0/src/database/tablebase.h000644 001750 001750 00000004063 12223260306 020236 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2007 Sean Estabrooks * * (C) 2008-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __TABLEBASE_H__ #define __TABLEBASE_H__ #include #include "common.h" #include "move.h" class QNetworkReply; /** @ingroup Feature * Abstract base class for different types of tablebase access * * @todo * - Subclass to access lokasoft tablebases * - Method to return all tablebase info rather than just best move. * - Provide a configuration screen to enable and disable etc. * - Subclass to support local tablebases * - Add caching and/or prefetching of online queries to reduce lag */ class Tablebase : public QObject { Q_OBJECT signals: /** Emitted when best move has been gathered from tablebase */ void bestMove(Move move, int score); public slots: /** Request best move from table base given FEN position */ virtual void getBestMove(QString fen) = 0; /** Cancel the previous lookup */ virtual void abortLookup() = 0; }; /** @ingroup Feature * Implement Tablebase access to ShredderChess.com 6 piece tablebases. * */ class Shredder : public Tablebase { Q_OBJECT public: Shredder(); ~Shredder(); signals: void bestMove(Move move, int score); public slots: void getBestMove(QString fen); void abortLookup(); private slots: void httpDone(QNetworkReply *reply); void sendIt(); private: QNetworkAccessManager manager; QString m_requested; QString m_fen; }; #endif // __TABLEBASE_H__ chessx-1.0.0/src/quazip/crypt.h000644 001750 001750 00000011352 12223260306 017221 0ustar00niklasniklas000000 000000 /* crypt.h -- base code for crypt/uncrypt ZIPfile Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant This code is a modified version of crypting code in Infozip distribution The encryption/decryption parts of this source code (as opposed to the non-echoing password parts) were originally written in Europe. The whole source package can be freely distributed, including from the USA. (Prior to January 2000, re-export from the US was a violation of US law.) This encryption code is a direct transcription of the algorithm from Roger Schlafly, described by Phil Katz in the file appnote.txt. This file (appnote.txt) is distributed with the PKZIP program (even in the version without encryption capabilities). If you don't need crypting in your application, just define symbols NOCRYPT and NOUNCRYPT. This code support the "Traditional PKWARE Encryption". The new AES encryption added on Zip format by Winzip (see the page http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong Encryption is not supported. */ #include "quazip_global.h" #define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) /*********************************************************************** * Return the next byte in the pseudo-random sequence */ static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab UNUSED) { //(void) pcrc_32_tab; /* avoid "unused parameter" warning */ unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an * unpredictable manner on 16-bit systems; not a problem * with any known compiler so far, though */ temp = ((unsigned)(*(pkeys + 2)) & 0xffff) | 2; return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); } /*********************************************************************** * Update the encryption keys with the next byte of plain text */ static int update_keys(unsigned long* pkeys, const unsigned long* pcrc_32_tab, int c) { (*(pkeys + 0)) = CRC32((*(pkeys + 0)), c); (*(pkeys + 1)) += (*(pkeys + 0)) & 0xff; (*(pkeys + 1)) = (*(pkeys + 1)) * 134775813L + 1; { register int keyshift = (int)((*(pkeys + 1)) >> 24); (*(pkeys + 2)) = CRC32((*(pkeys + 2)), keyshift); } return c; } /*********************************************************************** * Initialize the encryption keys and the random header according to * the given password. */ static void init_keys(const char* passwd, unsigned long* pkeys, const unsigned long* pcrc_32_tab) { *(pkeys + 0) = 305419896L; *(pkeys + 1) = 591751049L; *(pkeys + 2) = 878082192L; while(*passwd != '\0') { update_keys(pkeys, pcrc_32_tab, (int)*passwd); passwd++; } } #define zdecode(pkeys,pcrc_32_tab,c) \ (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) #define zencode(pkeys,pcrc_32_tab,c,t) \ (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) #ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED #define RAND_HEAD_LEN 12 /* "last resort" source for second part of crypt seed pattern */ # ifndef ZCR_SEED2 # define ZCR_SEED2 3141592654UL /* use PI as default pattern */ # endif static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) const char *passwd; /* password string */ unsigned char *buf; /* where to write header */ int bufSize; unsigned long* pkeys; const unsigned long* pcrc_32_tab; unsigned long crcForCrypting; { int n; /* index in random header */ int t; /* temporary */ int c; /* random byte */ unsigned char header[RAND_HEAD_LEN - 2]; /* random header */ static unsigned calls = 0; /* ensure different random header each time */ if(bufSize < RAND_HEAD_LEN) { return 0; } /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the * output of rand() to get less predictability, since rand() is * often poorly implemented. */ if(++calls == 1) { srand((unsigned)(time(NULL) ^ ZCR_SEED2)); } init_keys(passwd, pkeys, pcrc_32_tab); for(n = 0; n < RAND_HEAD_LEN - 2; n++) { c = (rand() >> 7) & 0xff; header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); } /* Encrypt random header (last two bytes is high word of crc) */ init_keys(passwd, pkeys, pcrc_32_tab); for(n = 0; n < RAND_HEAD_LEN - 2; n++) { buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); } buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); return n; } #endif chessx-1.0.0/src/gui/aboutdlg.cpp000644 001750 001750 00000002227 12223463406 017476 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2013 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "aboutdlg.h" #include "settings.h" #include "version.h" #include "ui_aboutdlg.h" AboutDlg::AboutDlg(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDlg) { ui->setupUi(this); QString refPath = AppSettings->dataPath(); ui->labelDataPath->setText(refPath); refPath = AppSettings->getTempPath(); ui->labelTempPath->setText(refPath); ui->labelCopyRightDate->setText(COPYRIGHT_DATE); QString version = QString(STR_REVISION).replace(',', '.'); ui->labelVersion->setText(version); ui->labelTempPath->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); ui->labelDataPath->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); ui->labelHomepage->setTextInteractionFlags(Qt::TextBrowserInteraction); ui->labelMailingList->setTextInteractionFlags(Qt::TextBrowserInteraction); } AboutDlg::~AboutDlg() { delete ui; } chessx-1.0.0/src/gui/engineoptionlist.cpp000644 001750 001750 00000007054 12223260306 021264 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "engineoptionlist.h" #include #include ////////////////////////////////////////////////////////////////////////////////////// // List Delegate ////////////////////////////////////////////////////////////////////////////////////// QWidget *EngineOptionListDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { if(index.column() == 4) { QStringList varList = m_model->getSelections(index); if(!varList.size()) { return QStyledItemDelegate::createEditor(parent, option, index); } else { QComboBox *comboBox = new QComboBox(parent); comboBox->setEditable(false); comboBox->setInsertPolicy(QComboBox::NoInsert); comboBox->addItems(varList); return comboBox; } } return 0; } void EngineOptionListDelegate::commitAndCloseEditor() { emit commitData((QWidget*)sender()); emit closeEditor((QWidget*)sender()); } void EngineOptionListDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QComboBox *comboBox = qobject_cast(editor); if(comboBox && m_model->getSelections(index).size()) { int selectedItem = comboBox->findText(comboBox->currentText()); model->setData(index, comboBox->itemText(selectedItem), Qt::EditRole); } else { QStyledItemDelegate::setModelData(editor, model, index); } } void EngineOptionListDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QComboBox *comboBox = qobject_cast(editor); if(comboBox && m_model->getSelections(index).size()) { comboBox->clear(); QStringList varList = m_model->getSelections(index); comboBox->addItems(varList); QString currentText = index.model()->data(index, Qt::DisplayRole).toString(); int selectedItem = comboBox->findText(currentText); if(selectedItem == -1) { comboBox->setEditText(index.model()->data(index, Qt::DisplayRole).toString()); } else { comboBox->setCurrentIndex(selectedItem); } } else { QStyledItemDelegate::setEditorData(editor, index); } } ////////////////////////////////////////////////////////////////////////////////////// // List Widget ////////////////////////////////////////////////////////////////////////////////////// EngineOptionList::EngineOptionList(QWidget *parent) : QTableView(parent), m_model(0) { setObjectName("EngineOptionList"); setWindowTitle(tr("Engine Options")); setSelectionBehavior(QAbstractItemView::SelectItems); setEditTriggers(QAbstractItemView::NoEditTriggers); setSortingEnabled(false); } void EngineOptionList::setDB(const QList& options, OptionValueList& mapOptionValues) { m_model = new EngineOptionModel(this); m_model->m_pOptionDataList = &options; m_model->m_pValueMap = &mapOptionValues; setModel(m_model); EngineOptionListDelegate* delegate = new EngineOptionListDelegate(); delegate->setModel(m_model); setItemDelegate(delegate); } void EngineOptionList::resetModel() { m_model->resetModel(); } chessx-1.0.0/src/gui/renametagdialog.h000644 001750 001750 00000001441 12223260306 020454 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef RENAMETAGDIALOG_H #define RENAMETAGDIALOG_H #include namespace Ui { class RenameTagDialog; } class RenameTagDialog : public QDialog { Q_OBJECT public: explicit RenameTagDialog(QWidget *parent, QString ts, QString tagName, Qt::WindowFlags f = 0); ~RenameTagDialog(); signals: void renameRequest(QString tag, QString newName, QString oldName); protected slots: /** Start renaming a tag */ void slotRename(); private: Ui::RenameTagDialog *ui; QString m_ts; QString m_tagName; }; #endif // RENAMETAGDIALOG_H chessx-1.0.0/src/database/movelist.h000644 001750 001750 00000002025 12223260306 020152 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005 William Hoggarth * * (C) 2005-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ /** @ingroup Core Low level list of moves, used by bitboard */ #ifndef __MOVELIST_H__ #define __MOVELIST_H__ #include "move.h" #include class MoveList : public QVector { public: MoveList() : QVector() {} inline Move& add() { push_back(Move()); return back(); } }; #endif // __MOVELIST_H__ chessx-1.0.0/src/database/indexitem.cpp000644 001750 001750 00000002775 12223260306 020645 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 Marius Roets * * (C) 2007 Rico Zenklusen * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include #include "indexitem.h" #include "index.h" IndexItem::IndexItem() { } IndexItem::~IndexItem() { m_mapTagIndexToValueIndex.clear(); } void IndexItem::set(TagIndex tagIndex, ValueIndex valueIndex) { m_mapTagIndexToValueIndex[tagIndex] = valueIndex; } ValueIndex IndexItem::valueIndex(TagIndex tagIndex) const { if(m_mapTagIndexToValueIndex.contains(tagIndex)) { return m_mapTagIndexToValueIndex[tagIndex]; } return 0; } bool IndexItem::hasTagIndex(TagIndex tagIndex) const { return (m_mapTagIndexToValueIndex.contains(tagIndex)); } void IndexItem::write(QDataStream& out) const { out << m_mapTagIndexToValueIndex; } void IndexItem::read(QDataStream& in) { in >> m_mapTagIndexToValueIndex; } chessx-1.0.0/src/gui/openingtreewidget.ui000644 001750 001750 00000002401 12126051304 021235 0ustar00niklasniklas000000 000000 OpeningTreeWidget 0 0 912 469 Form Qt::Horizontal TableView QTableView

tableview.h
chessx-1.0.0/data/images/folder_favorite.png000644 001750 001750 00000004442 12077036777 021673 0ustar00niklasniklas000000 000000 PNG  IHDRiCCPICC Profile(UoT?o\?US[IB*unS6mUo xB ISA$=t@hpS]Ƹ9w>5@WI`]5;V! A'@{N\..ƅG_!7suV$BlW=}i; F)A<.&Xax,38S(b׵*%31l #O-zQvaXOP5o6Zz&⻏^wkI/#&\%x/@{7S މjPh͔&mry>k7=ߪB#@fs_{덱п0-LZ~%Gpˈ{YXf^+_s-T>D@קƸ-9!r[2]3BcnCs?>*ԮeD|%4` :X2 pQSLPRaeyqĘ י5Fit )CdL$o$rpӶb>4+̹F_{Яki+x.+B.{L<۩ =UHcnf<>F ^e||pyv%b:iX'%8Iߔ? rw[vITVQN^dpYI"|#\cz[2M^S0[zIJ/HHȟ- Ic Adobe ImageReady zhIDAT8T]h[e~fYeƶ%J` 7B7.t^"w*:l@0a8Aǒ]6s^dI- << j9AJ.]SSRWm'os|1M)$ab`3U_ٿ__ymş7V3jnH-J fBɩ@Ϭ7PE(yff.U*3ąwN'cnSww͌*4LS'#ʕZ>N9vcGerͿ٣COCQ6n:-Ɇ bfИ¤X\|ύugQғ۶-%Y<jAHQĆ )%U"ҍXFgDz 7#깾mCˈxˉ;F3gb}r}3AfjgֵƱ^>3-U*R>Fvs=7Tn/v D9,o~muןw'ԼW˅W>9oaGD̈aeo<}LlBgϯI/*uu}REkm|eR4NˁT^(U@*BBi6T[g^ޅrnz*d1=' qb (ɑH@?r|+6Wu;Y?ZGf^u"EqC`r?q8|ED ?wXD1V©0uX85WKg L(Xmu}A7]%qU;O 8IENDB`chessx-1.0.0/src/quazip/quaadler32.cpp000644 001750 001750 00000000734 12223260306 020360 0ustar00niklasniklas000000 000000 #include "quaadler32.h" #include "zlib.h" QuaAdler32::QuaAdler32() { reset(); } quint32 QuaAdler32::calculate(const QByteArray &data) { return adler32(adler32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size()); } void QuaAdler32::reset() { checksum = adler32(0L, Z_NULL, 0); } void QuaAdler32::update(const QByteArray &buf) { checksum = adler32(checksum, (const Bytef*)buf.data(), buf.size()); } quint32 QuaAdler32::value() { return checksum; } chessx-1.0.0/i18n/chessx_fr.ts000644 001750 001750 00000407620 12232005535 016732 0ustar00niklasniklas000000 000000 AboutDlg About ChessX À propos de ChessX <b>ChessX</b><br> Free Chess Database <b>ChessX</b><br> Gestionnaires de parties d'échecs open source Version Version Copyright Copyright License Licence Maintainer Mainteneur Further Maintainers Autres mainteneurs Testing Testeur Coders Codeurs Further Code Autres codeurs Translations Traductions Path Information Chemins Path for temporary files Fichiers temporaires Program data path Données du programme Contact Contacts Homepage Page principale Mailing List Liste de diffusion Analysis (depth %1, %2) (profondeur %1, %2) AnalysisWidget Analysis Analyse &Lines: &Lignes: Analyze Analyser Stop Stop There was an error (%1) running engine <b>%2</b>. Une erreur est survenue (%1)durant l'execution du moteur <b>%2</b>. Draw Nulle White wins in %n moves Les blancs gagnent en %n coup Les blancs gagnent en %n coups Black wins in %n moves Les noirs gagnent en %n coup Les noirs gagnent en %n coups <a href="0" title="Click to add move to game">[+]</a> <b>Tablebase:</b> <a href="0" title="Cliquez pour ajouter un coup">[+]</a> <b>Tablebase:</b> BitBoard w%1 b%2 %3 to move. b%1\nn%2\n%3 à jouer. White Blancs Black Noirs BoardSetupDialog Setup position Inspired from Fritz GUI Définir une position Board Échiquier Clear Effacer &Reset &Initialiser Side to move: Trait aux : Move: Coup : &Advanced &Avançé En passant file: Rangée en passant : Castling rights Droits au roque Tools Outils Flip board Inverser l'échiquier ... ... Mirror left and right Mirroir gauche et droite Mirror top and bottom Mirroir haut et bas Change colors for all pieces Changer la couleur pour toutes les pièces Black O-O Noirs O-O White O-O-O Blancs O-O-O White O-O Blancs O-O Black O-O-O Noirs O-O-O Halfmove clock: No equivalent in French Compteur demi-coups : FEN FEN Paste FEN Coller FEN Copy FEN Copier FEN Copy Text &Ok &Ok &Cancel &Annuler Current position is not valid. %1. La position n'est pas valide. %1. No white king Pas de roi blanc No black king Pas de roi noir Both kings are in check Les deux rois sont en echec Side to move has opponent in check already Le camp qui a le trait est en échec Black has too many pawns Les Noirs ont trop de pions White has too many pawns Les blancs ont trop de pions There are pawns on the first or eighth rank Des pions se trouvent sur la première ou sur la huitième rangée Too many kings Trop de rois Too many black pieces Trop de pièces noirs Too many white pieces Trop de pièces blanches Bad castling rights Roque non autorisé En passant square is not correct La case en passant n'est pas correcte Unknown reason Raison inconnue Illegal position: %1 Position illégale : %1 Text in clipboard does not represent valid FEN:<br><i>%1</i> Le texte dans le presse-papier n'est pas au format FEN : <br><i>%1</i> There is no text in clipboard. Pas de texte dans le presse-papier. BoardTheme Cannot find piece data. Please check your installation. Impossible de trouver les pièces. Merci de vérifier votre installation. ChessBrowser Add start comment... Ajouter un commentaire au début... Add comment... Ajouter un commentaire... Add move symbol Ajouter symbole de coup Add evaluation symbol Ajouter symbole d'évaluation Add other symbol Ajouter autre symbole Bishops Fous Remove symbols Supprimer les symboles Enumerate Variations A) B) C) Enumérer Variations A) B) C) Enumerate Variations a) b) c) Enumerer Variations a) b) c) Promote to main line Promouvoir vers la ligne principale Move variation up Remonter la variante Move variation down Descendre la variante Remove variation Supprimer la variante Remove previous moves Supprimer les coups précédents Remove next moves Supprimer les coups suivants Insert threat Insérer une menace Copy Html Copier Html Copy Text Copier Text CommentDialog Edit Comment Editer le commentaire Elapsed time Temps écoulé Clock time Heure de l'horloge H:mm:ss H:mm:ss CopyDialog Copy Games Copier des parties Copy: Copier : &Current game &Partie en cours Games in &filter Parties &filtrées &All games &Toutes les parties &To: &Vers: DatabaseList Databases Bases de données Activate Acitver Open Ouvrir Close Fermer Add to favorites Ajouter aux favoris Remove from Favorites Supprimer des favoris Show in Finder Montrer dans le Finder DatabaseListModel Favorite Favori Name Nom Size Taille Open Ouvrir Path Chemin Format Format Date Date Clipboard Presse-papiers Closed Fermé ECOListWidget <html><body><i>No ECO code chosen.</i></body></html> <html><body><i>Pas de code ECO choisi.</i></body></html> <html><i>No ECO code chosen.</i></html> <html><i>Pas de code ECO choisi.</i></html> EcoInfo <i>no games</i> <i>Pas de jeux</i> Total: %1 Total: %1 Games in database %1: %2 Parties dans la base %1: %2 Rating: <b>%1</b> Classement: <b>%1</b> Rating: <b>%1-%2</b> Classement: <b>%1-%2</b> <table><tr><th>White Player</th><th>Score</th></tr> <table><tr><th>Joueur Blancs</th><th>Score</th></tr> <a name='ListBlack'></a><table><tr><th>Black Player</th><th>Score</th></tr> <a name='ListBlack'></a><table><tr><th>Joueur Noirs</th><th>Score</th></tr> EngineOptionDialog Engine Options Options du moteur Reset Reset EngineOptionList Engine Options Options du moteur EngineOptionModel Name Nom Default Defaut Min Min Max Max Value Valeur EventInfo <i>no games</i> <i>Pas de parties</i> Total: %1 Total: %1 Games in database %1: %2<br> Parties dans la base %1: %2<br> Rating: <b>%1</b><br> Classement: <b>%1</b><br> Rating: <b>%1-%2</b><br> Classement: <b>%1-%2</b><br> Date: <b>????.??.??<b><br> Date: <b>????.??.??<b><br> Date: <b>%1</b><br> Date: <b>%1</b><br> <table><tr><th>Participants</th><th>Score</th></tr> <table><tr><th>Participants</th><th>Score</th></tr> EventListWidget <html><i>No event chosen.</i></html> <html><i>Pas d'évenement choisi.</i></html> FilterModel Nr White Blancs WhiteElo Elo Blancs Black Noirs BlackElo Elo Noirs Event Évènement Site Lieu Round Ronde Date Date Result Résultat ECO ECO Moves Coups GameList Game list Liste des parties Copy games... Copier parties... Merge into current game Fusionner dans la partie en cours All Games Toutes les parties Filter Filtrer Selected game Partie sélectionnée Delete game Supprimer la partie LoadQuery Load Database Charger la base Currently, there are no databases configured. Shall I download a database? Il n'y a actuellement pas de base configurée. Dois-je télécharger une base ? Large Database (9M) Grande base de parties (9M) Small Database Petite base de parties Start Download! Télécharger! Skip Loading Ignorer MainWindow Game Text Texte de la partie Game List Liste des parties Opening Tree Arbre d'ouvertures Loading ECO file... Chargement du fichier ECO... ECO Loaded. ECO chargé. [Clipboard] [Presse-papier] Opening %1... Ouverture de %1... Database %1 cannot be accessed at the moment (%2). La base %1 n'est pas accessible en ce moment (%2). Cannot open file Impossible d'ouvir le fichier %1 opened %1 ouvert Export games Exporter les parties PGN file (*.pgn) Fichier PGN (*.pgn) HTML page (*.html) Page HTML (*.html) LaTeX document (*.tex) Document LaTeX (*.tex) &File &Fichier File Fichier &New database... &Nouvelle base de données... &Open... &Ouvrir... Open in UTF8... Ouvrir en UTF8... Open &recent... Fichiers &récents... &Save &Enregistrer Commit Database to disk Ecrire la base sur le disque &Export... E&xporter... Current Game Partie en cours &Games in filter &Parties filtrées &All games &Toutes les parties &Close &Fermer &Quit &Quitter &Edit &Édition Edit Editer Comment Commentaire Comment Before Commenter avant Variation Variante Promote Promouvoir Promote Variation Promouvoir variante Remove Supprimer Remove Variation Supprimer variante &Remove &Supprimer Moves from the beginning Coups depuis le début Moves to the end Coups restants Setup &position... Définir une &position... Refactor (Ca devrait être REcontruire / refaire / réorganiser) Restructurer Uncomment Décommenter Remove Variations Supprimer variantes Start loading database... Début du chargement de la base... A new version is available at chessx.sourceforge.net Une nouvelle version est disponible sur chessx.sourceforge.net &Preferences... &Préférences... &View &Vue &Flip board &Retourner l'échiquier &Game &Partie &Load &Charger &Next &Suivante &Previous P&récédente &Go to game... &Aller à la partie n°... &Random A&léatoire &Go to Aller &vers &Start &Début &End &Fin &Next move Coup &suivant &Previous move Coup &précédent Game Time Temps de la partie Players Joueurs Events Evènements ECO ECO Databases Bases de données Analysis 1 Analyseur 1 Analysis 2 Analyseur 2 ECO Load Error. Erreur de chargement ECO. Database %1 cannot be accessed at the moment. La base %1 n'est pas accessible pour le moment. Copy PGN Copier PGN Copy FEN Copier FEN Copy Position Copier Position Copy Image Copier image &Paste &Coller View Vue Toolbars Barres d'outils Stay on Top Rester au dessus New board Nouvel échiquier Close current board Fermer l'échiquier en cours Game Partie Database Base Training Entrainement Auto Player Joueur automatique Auto Analysis Analyse automatique Go to first move Aller au 1er coup Go to last move Aller au dernier coup 5 moves &forward 5 coups en a&vant 5 moves &backward 5 coups en &arriere Enter Variation Entrer variante Previous Variation Variante précédente Next Variation Variante suivante Back to main line Retour sur la ligne principale &New &Nouvelle &Save.... &Enregistrer... Fi&nd &Rechercher Search Chercher Find &tag Rechercher un &critère Find &position Trouver la &position &Enable filter &Activer le filtre &Reset filter &Réinitialiser le filtre &Reverse filter &Inverser le filtre &Database &Base de données &Switch to &Basculer vers &Copy games... &Copier les parties... &Help &Aide Help Aide &Report a bug... &Signaler un bug... &About ChessX À &propos de ChessX &Debug &Déboguer Following databases are modified: Les bases de données suivantes ont été modifiées: Save them? Enregistrer les changements? (%1 s.) (%1 s.) New database Nouvelle base de données PGN database (*.pgn) Base de données PGN (*.pgn) Cannot create ChessX database. Impossible de créer une base de données ChessX. Open database Ouvrir base de données PGN databases (*.pgn) Base de données PGN (*.pgn) <html>The database <i>%1</i> is read-only and cannot be saved.</html> <html>La base de données <i>%1</i> est en lecture seule et ne pas être enregistrée.</html> Saving %1... Enregistrement %1... The current database is modified! La base en cours a été modifiée! Save it? Sauvegarder ? %1 saved %1 Enregistré Text in clipboard does not represent valid FEN:<br><i>%1</i> Le texte du presse-papier n'est pas au format FEN :<br><i>%1</i> Le texte dans le presse-papier n'est pas une FEN valide:<br><i>%1</i> There is no text in clipboard. Il n'y a pas de texte dans le presse-papier. The clipboard contains FEN, but with illegal position. You can only paste such positions in <b>Setup position</b> dialog. Le presse papier contient une chaîne FEN, mais avec une position non réglementaire. Vous ne pouvez coller ce genre de position que dans la boîte de dialogue <b>Définir position</b>. Queen Reine Rook Tour Bishop Fou Knight Cavalier Promotion Promotion Promote to: Promouvoir en : Red Square Case Rouge Yellow Square Case Jaune Green Square Case Verte Remove Color SUpprimer couleur Red Arrow to here Flêche verte ici Yellow Arrow to here Flêche jaune ici Green Arrow to here Flêche verte ici Remove Arrow to here Supprimer Flêche ici Load Game Charger une partie Game number: Partie n° : This database is read only. Cette base de données est en lecture seule. Analysis Pane 1 is not running an engine for automatic analysis. Le panneau d'analyse 1 n'a pas de moteur d'analyse actif. Append game %1 to %2. Ajouter partie %1 à %2. Clipboard Presse-papiers Append games from %1 to %2. Ajouter parties de %1 à %2. Tree updated. Arbre mis-à-jour. <b>New game</b> <b>Nouvelle partie</b> You need at least two open databases to copy games Vous avez besoin au moins d'ouvrir deux bases de données pour copier des parties %1. %2 (%3 games) %1. %2 (%3 parties) %1 - ChessX %1 - ChessX Search ended Recherche terminée Updating tree... Mise à jour de l'arbre... MessageDialog Error Erreur Warning Attention Information Information Question Question &Yes &Oui &No &Non &OK &Valider &Cancel &Annuler MoveData [end] [fin] NagSet Good Move Bon coup Poor Move Coup faible Very good Move Très bon coup Blunder Gaffe Speculative Move Hasardeux ? Coup spéculatif Dubious Move Coup douteux Only Move Seul coup Equal Egal Unclear Pas clair White has slight advantage Les blancs ont un léger avantage Black has slight advantage Les noirs ont un léger avantage White has moderate advantage Les blancs on un avantage modéré Black has moderate advantage Les noirs ont un avantage modéré White has decisive advantage Les blancs ont un avantage décisif Black has decisive advantage Les noirs ont un avantage décisif White has crushing advantage Les blancs ont un avantage écrasant Black has crushing advantage Les noirs ont un avantage écrasant Zugzwang Zugzwang With slight space advantage Avec un léger avantage d'espace With moderate space advantage Avec un avantage d'espace modéré With decisive space advantage Avec un avantage d'espace décisif With slight development advantage Avec un léger avantage de développement With moderate development advantage Avec un avantage de développement modéré With decisive development advantage Avec un avantage décisif de développement With initiative Avec l'initiative With lasting initiative Avec Initiave durable With attack Avec l'attaque With insufficient compensation for material deficit Avec compensation insuffisante pour le déficit matériel With compensation Avec compensation With more than adequate compensation for material deficit Avec plus qu'une compensation suffisante pour le déficit matériel With slight center control advantage Avec léger avantage au centre With moderate center control advantage Avec un contrôle modéré du centre With decisive center control advantage Avec un contrôle décisif du centre With slight kingside control advantage Avec un léger contrôle de l'aile roi With moderate kingside control advantage Avec un contrôle modéré de l'aile roi With decisive kingside control advantage Avec un contrôle décisif de l'aile roi With slight queenside control advantage Avec un léger contrôle de l'aile dame With moderate queenside control advantage Avec un contrôle modéré de l'aile dame With decisive queenside control advantage Avec un contrôle décisif de l'aile dame With vulnerable first rank Avec faiblesse de la 1ère rangée With well protected first rank Avec une 1ère rangée bien protégée With poorly protected king Avec un roi faiblement protégé With well protected king Avec un roi bien protégé With poorly placed king Avec un roi mal placé With well placed king Avec un roi bien placé With very weak pawn structure Avec une structure de pions très faible With moderately weak pawn structure Avec une structure de pions faible With moderately strong pawn structure Avec un structure de pions modérément forte With very strong pawn structure Avec une très solide structure de pions With poor knight placement Avec un faible placement du cavalier With good knight placement Avec un bon placement du cavalier With poor bishop placement Avec un faible placement du fou With good bishop placement Avec un bon placement du fou With poor rook placement Avec un faible placement de la tour With good rook placement Avec un bon placement de la tour With poor queen placement Avec un faible placement de la dame With good queen placement Avec un bon placement de la dame With poor piece coordination Avec une faible coordination des pièces With good piece coordination Avec une bonne coordination des pièces White played the opening very poorly Les blancs ont très mal joué l'ouverture Black played the opening very poorly Les noirs ont très mal joué l'ouverture White played the opening poorly Les blancs ont mal joué l'ouverture Black played the opening poorly Les noirs ont mal joué l'ouverture White played the opening well Les blancs ont bien joué l'ouverture Black played the opening well Les noirs ont bien joué l'ouverture White played the opening very well Les blancs ont très bien joué l'ouverture Black played the opening very well Les noirs ont très bien joué l'ouverture White played the middlegame very poorly Les blancs ont très mal joué le milieu de jeu Black played the middlegame very poorly Les nois ont très mal joué le milieu de jeu White played the middlegame poorly Les blancs ont mal joué le milieu de partie Black played the middlegame poorly Les noirs ont mal joué le milieu de partie White played the middlegame well Les blancs ont bien joué le milieu de partie Black played the middlegame well Les noirs ont bien joué le milieu de partie White played the middlegame very well Les blancs ont très bien joué le milieur de partie Black played the middlegame very well Les noirs ont très bien joué le milieur de partie White played the ending very poorly Les blancs ont très mal joué la finale Black played the ending very poorly Les noirs ont très mal joué la finale White played the ending poorly Les blancs ont mal joué la finale Black played the ending poorly Les noirs ont mal joué la finale White played the ending well Les blancs ont tbien joué la finale Black played the ending well Les noirs ont bien joué la finale White played the ending very well Les blancs ont très bien joué la finale Black played the ending very well Les noirs ont très bien joué la finale With counterplay Contre-jeu blanc Moderate time control pressure Contrôle de temps modéré Severe time control pressure Contrôle de temps sévère With the idea Avec l'idée Aimed against Dirigé contre Better was Meilleur était Worse was Pire était Equivalent was Equivalent était RR RR N N Weak point Point faible Endgame Finale Line Ligne Diagonal Diagonale Pair of bishops Paire de fous Bishops of opposite color Fous de couleur opposée Bishops of the same color Fous de la même couleur Diagram Diagramme OpeningTree Move Coup Count Compte Score Score Rating Classement Year Année OpeningTreeWidget Form Formulaire OutputOptions Notation in Column Style Notation en style Colonne Show symbolic Nags Montrer lesNags Text width Largeur du texte Indent variations from Level Pas certain. Indenter variantes depuis niveau Variation Indentation Indentation variante Comment indentation Indentation Commentaire Main Line Color Couleur ligne principale Variation Color Couleur variante Comment Color Couleur commentaire NAG Color Couleur NAG Header Color Couleur entête Show Header Montrer entête Show Diagrams Montrer Diagrammes Diagram Size Taille Diagramme Comment Indentation Indentation Commentaire PlayerInfo <i>no games</i> <i>Pas de jeux</i> Total: %1<br>White: %2<br>Black: %3<br> Total: %1<br>Blancs: %2<br>Noirs: %3<br> Games in database <i>%1</i>: <b>%2</b><br> Parties dans la base <i>%1</i>: <b>%2</b><br Rating: <b>%1</b><br> Classement: <b>%1</b><br> Rating: <b>%1-%2</b><br> Classement: <b>%1-%2</b><br> Date: <b>????.??.??<b><br> Date: <b>????.??.??<b><br> Date: <b>%1</b><br> Date: <b>%1</b><br> <p>White Openings:</p><ul> <p>Ouvertures blancs:</p><ul> </ul><p>Black Openings:</p><ul> </ul><p>Ouvertures noirs:</p><ul> PlayerListWidget <html><i>No player chosen.</i></html> <html><i>Aucun joueur sélectionné.</i></html> PreferencesDialog Preferences Préférences Database Base de parties Automatic classification with ECO Codes Classification automatique avec les codes ECO Build index file Construire le fichier d'index Commit Database after saving Game Ecrire la base après sauvegarde de la partie Number of recent files: Nombre de fichiers récents: Default Database Path: Chemin par defaut de la base : Default path for storing files Chemin par defaut de stockage des fichiers Appearance Apparence Font Sizes Tailles polices Game Text: Texte de la partie: Lists Listes Game Text Texte de la partie Show Diagrams Montrer Diagrammes Column Style Style Colonne Keep variations inline from level Limiter les variantes au niveau Diagram Size Taille du diagramme Pieces Pièces Put the initials of the pieces here, mind the initial space. Que peut vouloir dire l'expression "mind the initial space" ??? Mettre les initiales des pièces ici, garder l'espace initial. KQRBN - Mind the initial space! KQRBN - Garder l'espace initial! Colors: Couleurs: App App Internet Internet Language Langue Changing the language requires restarting the application! Changer la langue nécessite de relancer l'application! Load language file from Server: Télécharger la traduction Load! Télécharger! Use vertical Tabs Utiliser tabulations verticales &Ok &Valider &Apply &Appliquer &Reset &Initialiser &Cancel &Annuler &Board &Echiquier &Chess set: &Pièces : plain pas certain. Simple outline Bordure outline+shadow Bordure + ombre &Draw frame between squares &Bordure entre les cases &Guess move on left-click &Anticipation du coup au clic gauche Board &style: &Style du Plateau : &Colors: &Couleurs : &Engines &Moteurs ... ... Name: Nom : Command: Commande: Options: Options: Highlight current move Surbrillance du dernier coup Mouse Behaviour Comportement souris Next guess on right click Coup suggéré sur click droit Wheel sensitivity Sensibilité de la roulette Fast Rapide Slow Lent Draw Coordinates Dessiner Coordonnées Game Partie Autoplayer Joueur auto Auto-Play Interval Interval de jeu auto Automatically save game and continue with next Sauver automatiquement partie et continuer suivant Path to executable Chemin vers l'executable Path where engine is started - usually place of books Chemin lorsque le moteur est démarré - Place des books Directory: Dossier : Protocol: Protocole : Command Line Options Options ligne de commande Options Options Arbitrary name to identify engine Nom arbitraire pour identifier le moteur Down Vers le bas Remove Supprimer Add... Ajouter... Up Vers le haut Use online tablebase servers Utiliser table de finale en ligne Check for updates (at startup) and language packs Vérifier les mise-à-jour au démarrage Localization Localisation &Edit PGN files smaller than: &Modifier fichiers PGN inférieurs à : MB Mo XBoard Xboard For updating translations online version checking needs to be enabled. Une vérification de version en ligne est nécéessaire pour la MAJ des traductions Select databases folder Choisir le dossier des bases New Engine Nouveau moteur Could not load server language file dictionary Ne peut charger le dictionnaire de langue du serveur Could not load or install language pack Ne peut charger ou installer le pack de langue. No further translations online available! Aucune autre traduction disponible en ligne Translation file loaded - select added language above! Fichier de traduction chargé - Selectionez la langue ajoutée au dessus Clear all application settings? Effacer tous les réglagles de l'application? Warning Attention Light squares Cases claires Dark squares Cases foncées Highlighted squares Cases en surbrillance Frame Bordure Main Line Ligne principale Variations Variantes Comments Commentaires NAGs NAGs Select engine directory Choisir le dossier du moteur Select engine executable Choisir l'exécutable du moteur Current move Coup actuel [plain colors] [couleurs simples] QuickSearchDialog Quick Tag Search Recherche rapide de critères Game Number Numéro de partie White Blancs White Elo Elo des blancs Black Noirs Black Elo Elo des noirs Event Évènement Site Lieu Round Ronde Date Date Result Résultat ECO ECO Number of Moves Nombre de coups &Find &Rechercher &Cancel &Annuler Value or Range like 2000-2300 Valeur ou Rang comme 2000-2300 &Value: &Valeur : &Tag: &Critère : &Mode: &Mode : Find in current filter Rechercher dans le filtre en cours Search whole database Rechercher dans toute la base de données Add to current filter Ajouter au filtre en cours RenameTagDialog Rename Tags in Database Renommer les Tags dans la base Rename all Occurrences ... Renommer toutes les occurences... from De to à Press 'Rename' to proceed. Cliquez sur 'Renommer'. Rename Renommer Close Fermer SaveDialog Save Game Sauver la partie &OK &OK &Cancel &Annuler &Discard Changes &Annuler Changements Players Joueurs Elo: Elo: &White: &Blancs: &Black: &Noirs: Team Equipe White Team Equipe Blanche Black Team Equipe Noir Time Control Contrôle de temps White Start Time Temps débutt Blancs H:mm:ss H:mm:ss Black Start Time Temps début Noirs e.g. 40/7200:3600 for 2h/40 moves + 1h e.g. 40/7200:3600 pour 2h/40 coups + 1h Tournament Tournoi E&vent date: Date de l'é&vènement : &Site: &Site : &Event: &Evènement : Game Information Informations sur la partie &Round: &Ronde : &Date: &Date : Result: Résultat : Clipboard Presse-papiers Dates are not properly formatted! Invalid Data Les dates n'ont pas le bon format! TableView Hide Column Cacher colonne Show all Columns Montrer toutes les colonnes TagDetailWidget Form Formulaire &Filter: &Filtre: Selected Item Item sélectionné Filter Filtrer Rename Renommer chessx-1.0.0/src/gui/boardsetuptoolbutton.h000644 001750 001750 00000001603 12223260306 021633 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef BOARDSETUPTOOLBUTTON_H #define BOARDSETUPTOOLBUTTON_H #include "common.h" #include #include class BoardSetupToolButton : public QLabel { Q_OBJECT public: explicit BoardSetupToolButton(QWidget *parent = 0); QPixmap m_pixmap; Piece m_piece; signals: void signalDragStarted(QWidget*, QMouseEvent*); void signalClicked(Piece p); public slots: void slotClearBackground(Piece p); void slotSetSelected(); protected: virtual void mousePressEvent(QMouseEvent * e); virtual void mouseReleaseEvent(QMouseEvent * e); virtual void resizeEvent(QResizeEvent * e); }; #endif // BOARDSETUPTOOLBUTTON_H chessx-1.0.0/src/gui/savedialog.cpp000644 001750 001750 00000014415 12223260306 020007 0ustar00niklasniklas000000 000000 /*************************************************************************** Savedialog - dialog for saving game ------------------- begin : Mon 17 Apr 2006 copyright : (C) 2006 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "savedialog.h" #include "game.h" #include "database.h" #include "partialdate.h" #include "messagedialog.h" #include #include SaveDialog::SaveDialog(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f) { ui.setupUi(this); QButtonGroup* group = new QButtonGroup(this); group->addButton(ui.result1Button); group->addButton(ui.result5Button); group->addButton(ui.result0Button); group->addButton(ui.resultNoneButton); connect(ui.buttonDiscardChanges, SIGNAL(clicked()), SLOT(discardChanges())); } SaveDialog::~SaveDialog() {} QString formatTagValue(const QString& s) { return (s.trimmed().isEmpty()) ? "?" : s; } QString formatTagDate(const QString& s) { return (s.trimmed().isEmpty()) ? PDInvalidDate.asString() : PartialDate().fromString(s).asString(); } int SaveDialog::save(Database* database, Game& game) { QString gameTitle; QString baseName = database->name(); if(baseName.isEmpty()) { baseName = tr("Clipboard"); } if(game.tag(TagNameWhite).isEmpty() && game.tag(TagNameBlack).isEmpty()) { gameTitle = "Save game to "; } else { QString name1 = game.tag(TagNameWhite); if(name1.isEmpty()) { name1 = "?"; } QString name2 = game.tag(TagNameBlack); if(name2.isEmpty()) { name2 = "?"; } gameTitle = QString("Save game '%1 vs. %2' to ").arg(name1).arg(name2); } gameTitle.append(baseName); setWindowTitle(gameTitle); ui.whiteEdit->setText(game.tag(TagNameWhite)); ui.whiteEloEdit->setText(game.tag(TagNameWhiteElo)); ui.blackEdit->setText(game.tag(TagNameBlack)); ui.blackEloEdit->setText(game.tag(TagNameBlackElo)); ui.eventEdit->setText(game.tag(TagNameEvent)); ui.siteEdit->setText(game.tag(TagNameSite)); ui.roundEdit->setText(game.tag(TagNameRound)); ui.dateEdit->setText(game.tag(TagNameDate)); ui.eventDateEdit->setText(game.tag(TagNameEventDate)); ui.whiteTeamEdit->setText(game.tag(TagNameWhiteTeam)); ui.blackTeamEdit->setText(game.tag(TagNameBlackTeam)); QList buttons = ui.result1Button->group()->buttons(); for(int i = 0; i < buttons.count(); ++i) if(buttons[i]->text() == game.tag(TagNameResult)) { buttons[i]->setChecked(true); } // Completion setLineEdit(ui.whiteEdit, database, TagNameWhite); setLineEdit(ui.blackEdit, database, TagNameBlack); setLineEdit(ui.siteEdit, database, TagNameSite); setLineEdit(ui.eventEdit, database, TagNameEvent); int result = QDialog::exec(); if(result == Accepted) { game.setTag(TagNameWhite, formatTagValue(ui.whiteEdit->text())); game.setTag(TagNameBlack, formatTagValue(ui.blackEdit->text())); game.setTag(TagNameEvent, formatTagValue(ui.eventEdit->text())); game.setTag(TagNameSite, formatTagValue(ui.siteEdit->text())); game.setTag(TagNameRound, formatTagValue(ui.roundEdit->text())); game.setTag(TagNameDate, formatTagDate(ui.dateEdit->text())); game.setTag(TagNameEventDate, formatTagDate(ui.eventDateEdit->text())); game.setTag(TagNameResult, ui.result1Button->group()->checkedButton()->text()); // Optional tag if(ui.whiteEloEdit->text().toInt() || game.tag(TagNameWhiteElo).toInt()) { game.setTag(TagNameWhiteElo, ui.whiteEloEdit->text()); } if(ui.blackEloEdit->text().toInt() || game.tag(TagNameBlackElo).toInt()) { game.setTag(TagNameBlackElo, ui.blackEloEdit->text()); } QString t = ui.timeControl->text(); QString format = "H:mm:ss"; if(!t.isEmpty()) { game.setTag(TagNameTimeControl, t); } QTime tt = ui.whiteStartTime->time(); if(tt.secsTo(QTime(0, 0)) > 0) { t = tt.toString(format); game.setTag(TagNameWhiteClock, t); } tt = ui.blackStartTime->time(); if(tt.secsTo(QTime(0, 0)) > 0) { t = tt.toString(format); game.setTag(TagNameBlackClock, t); } t = ui.whiteTeamEdit->text(); if(!t.isEmpty()) { game.setTag(TagNameWhiteTeam, t); } t = ui.blackTeamEdit->text(); if(!t.isEmpty()) { game.setTag(TagNameBlackTeam, t); } } return result; } void SaveDialog::setLineEdit(QLineEdit* edit, Database* database, const QString &tagName) { QStringList words; if((tagName == TagNameWhite) || (tagName == TagNameBlack)) { words = database->index()->playerNames(); } else { words = database->index()->tagValues(tagName); } QCompleter* completer = new QCompleter(words, this); completer->setCaseSensitivity(Qt::CaseInsensitive); edit->setCompleter(completer); } void SaveDialog::accept() { if((PartialDate().fromString(ui.dateEdit->text()).isValid()) && (PartialDate().fromString(ui.eventDateEdit->text()).isValid())) { // dates are formatted properly QDialog::accept(); } else { MessageDialog::error(tr("Dates are not properly formatted!", "Invalid Data")); } } void SaveDialog::discardChanges() { done(Discard); } chessx-1.0.0/data/templates/latex-default.template000644 001750 001750 00000004173 12014511115 023010 0ustar00niklasniklas000000 000000 [OPTIONSDEFINITIONS] #Name - Name of the option. Use @Name@ in header, footer and markup # tags to substitute the value. #Type - Can be one of String, Boolean, Integer, Color #Allow Values - The values that are allowed for this option. Ignored # for type Boolean(1|0|true|false) and Color. Values are # are a | seperated list of values. For Integer types a # range is allowed, specified as in 1:200 #Default - The default to be used. Must be in allowed values (duh) #Description - Short description, will be used in the GUI to change the # option. #Name , Type , Allow Values , Default , Description MainLineFontWeight,String,Bold|Normal,Bold,The weight of the font [OPTIONS] ColumnStyle=false MainLineMoveColor=#000000 VariationColor=#0000ff CommentColor=#00ff00 NagColor=#ff0000 HeaderColor=#0000ff [OUTPUTHEADER] \documentclass[10pt,twocolumn]{article}\n % This is a LaTeX file generated by chessX.\n % You must have the \"chess12\" package installed to typeset this file.\n\n \usepackage{times}\n \usepackage{a4wide}\n \usepackage{chess}\n \usepackage[T1]{fontenc}\n\n \setlength{\columnsep}{7mm}\n \setlength{\parindent}{0pt}\n\n % Macros for variations and diagrams:\n \\newenvironment{variation}{\begin{quote}}{\end{quote}}\n \\newenvironment{diagram}{\begin{nochess}}{$$\showboard$$\end{nochess}}\n\n \begin{document}\n [OUTPUTFOOTER] \begin{center} \hrule \end{center}\n\n \end{document}\n [MARKUPTAGS] MarkupHeaderBlock={\bf\n,\\ \n} MarkupNotationBlock=\begin{chess}{\bf\n,}\end{chess} MarkupResult={\bf ,} MarkupMainLineMove=, MarkupVariationMove=, MarkupMainLine=, MarkupVariationInline=\begin{variation},\end{variation} MarkupVariationIndent=\begin{variation},\end{variation} MarkupNag=, MarkupColumnStyleMove=, MarkupColumnStyleRow=, MarkupColumnStyleMainline=, MarkupAnnotationInline=\begin{nochess}{\rm ,}\end{nochess} MarkupAnnotationIndent=\begin{nochess}{\rm ,}\end{nochess} MarkupPreAnnotationInline=\begin{nochess}{\rm ,}\end{nochess} MarkupPreAnnotationIndent=\begin{nochess}{\rm ,}\end{nochess} MarkupHeaderLine=, \\\\ MarkupHeaderTagName=, MarkupHeaderTagValue=\\,\\ MarkupMate=\, chessx-1.0.0/src/gui/boardsetuptoolbutton.cpp000644 001750 001750 00000002567 12223260306 022200 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "boardsetuptoolbutton.h" #include #include #include BoardSetupToolButton::BoardSetupToolButton(QWidget *parent) : QLabel(parent) { } void BoardSetupToolButton::mousePressEvent(QMouseEvent * e) { QLabel::mousePressEvent(e); emit signalClicked(m_piece); emit signalDragStarted(this, e); slotSetSelected(); } void BoardSetupToolButton::mouseReleaseEvent(QMouseEvent * e) { QLabel::mouseReleaseEvent(e); } void BoardSetupToolButton::resizeEvent(QResizeEvent * e) { int w = e->size().width() - 4; int h = e->size().height() - 4; QPixmap p1; if(m_pixmap.isNull()) { p1 = (style()->standardIcon(QStyle::SP_TrashIcon)).pixmap(w, h); } else { p1 = m_pixmap.scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation); } setPixmap(p1); } void BoardSetupToolButton::slotClearBackground(Piece p) { if(p == m_piece) { slotSetSelected(); } else { setStyleSheet("QLabel { background-color: lightgray }"); } } void BoardSetupToolButton::slotSetSelected() { setStyleSheet("QLabel { background-color: yellow }"); } chessx-1.0.0/src/gui/loadquery.h000644 001750 001750 00000000541 12223260306 017336 0ustar00niklasniklas000000 000000 #ifndef LOADQUERY_H #define LOADQUERY_H #include #include "ui_loadquery.h" class LoadQuery : public QDialog { Q_OBJECT public: explicit LoadQuery(QWidget *parent = 0); ~LoadQuery(); bool largeDB() const { return ui->btLargeDatabase->isChecked(); } private: Ui::LoadQuery *ui; }; #endif // LOADQUERY_H chessx-1.0.0/src/database/playerdata.cpp000644 001750 001750 00000013252 12223260306 020775 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2006 Ejner Borgbjerg * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "playerdata.h" PlayerData::PlayerData() { m_estimatedElo = 0; m_peakElo = 0; m_firstEloListIndex = 0; m_lastEloListIndex = 0; } PartialDate PlayerData::dateOfBirth() const { return m_dateOfBirth; } void PlayerData::setDateOfBirth(const PartialDate d) { m_dateOfBirth = d; } PartialDate PlayerData::dateOfDeath() const { return m_dateOfDeath; } void PlayerData::setDateOfDeath(const PartialDate d) { m_dateOfDeath = d; } QString PlayerData::country() const { return m_country; } void PlayerData::setCountry(const QString s) { m_country = s; } QString PlayerData::title() const { return m_title; } void PlayerData::setTitle(const QString s) { m_title = s; } int PlayerData::elo(const int eloListIndex) const { if(m_elo.contains(eloListIndex)) { QMap::const_iterator it = m_elo.find(eloListIndex); return it.value(); } else { return 0; } } int PlayerData::firstEloListIndex() { return m_firstEloListIndex; } void PlayerData::setFirstEloListIndex(const int ix) { m_firstEloListIndex = ix; } int PlayerData::lastEloListIndex() { return m_lastEloListIndex; } void PlayerData::setLastEloListIndex(const int ix) { m_lastEloListIndex = ix; } void PlayerData::setElo(const int eloListIndex, const int elo) { m_elo.insert(eloListIndex, elo); if(eloListIndex < m_firstEloListIndex || m_firstEloListIndex == 0) { m_firstEloListIndex = eloListIndex; } if(eloListIndex > m_lastEloListIndex || m_lastEloListIndex == 0) { m_lastEloListIndex = eloListIndex; } if(elo > m_peakElo) { m_peakElo = elo; } m_estimatedEloCache.clear(); } int PlayerData::peakElo() const { return m_peakElo; } void PlayerData::setPeakElo(const int elo) { m_peakElo = elo; } int PlayerData::estimatedElo() const { return m_estimatedElo; } void PlayerData::setEstimatedElo(const int elo) { m_estimatedElo = elo; m_estimatedEloCache.clear(); } int PlayerData::estimatedElo(const int eloListIndex) { QMap::const_iterator it; if(m_elo.contains(eloListIndex)) { it = m_elo.find(eloListIndex); return it.value(); } else { if(m_estimatedEloCache.contains(eloListIndex)) //use cached result { it = m_estimatedEloCache.find(eloListIndex); return it.value(); } else //search in previous elo lists { int result = m_estimatedElo;//default to overall estimate for(int i = eloListIndex - 1; i > 0; --i) { if(m_elo.contains(i)) { it = m_elo.find(i); result = it.value(); break; } } m_estimatedEloCache.insert(eloListIndex, result);//cache result return result; } } } int PlayerData::estimatedEloNoCache(const int eloListIndex) const { QMap::const_iterator it; if(m_elo.contains(eloListIndex)) { it = m_elo.find(eloListIndex); return it.value(); } else { if(m_estimatedEloCache.contains(eloListIndex)) //use cached result { it = m_estimatedEloCache.find(eloListIndex); return it.value(); } else //search in previous elo lists { int result = m_estimatedElo;//default to overall estimate for(int i = eloListIndex - 1; i > 0; --i) { if(m_elo.contains(i)) { it = m_elo.find(i); result = it.value(); break; } } return result; } } } QImage PlayerData::photo() const { return m_photo; } void PlayerData::setPhoto(const QImage img) { m_photo = img; } QString PlayerData::biography() const { return m_biography; } void PlayerData::setBiography(const QString str) { m_biography = str; } void PlayerData::appendToBiography(const QString str) { m_biography += str; } QList PlayerData::eloListData() const { QList list; QMap::const_iterator it; int nextListIx = 1; for(it = m_elo.begin(); it != m_elo.end(); ++it) { int listIx = it.key(); if(listIx > nextListIx) { list.push_back((qint32) - 9999); list.push_back((qint32)(listIx - nextListIx));//number of lists without the player } list.push_back((qint32)it.value());//elo nextListIx = listIx + 1; } return list; } void PlayerData::eloFromListData(QList eloListData) { int listIx = 1; qint32 elem; for(unsigned int i = 0; i < (unsigned int)eloListData.size();) { elem = eloListData[i++]; if(elem == -9999) { elem = eloListData[i++]; listIx += elem; } else { m_elo.insert(listIx, elem); listIx++; } } } chessx-1.0.0/src/database/openingtree.h000644 001750 001750 00000007642 12223260306 020641 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __OPENINGTREE_H__ #define __OPENINGTREE_H__ #include #include "filter.h" #include "game.h" class MoveData { public: enum MoveType {StandardMove, GameEnd}; MoveData(); void addGame(Game& g, Color c, MoveType movetype = StandardMove); double percentage() const; int averageRating() const; int averageYear() const; QString move; unsigned count; unsigned result[4]; long rating; unsigned rated; long year; unsigned dated; friend bool operator<(const MoveData& m1, const MoveData& m2); friend bool compareMove(const MoveData& m1, const MoveData& m2); friend bool compareScore(const MoveData& m1, const MoveData& m2); friend bool compareRating(const MoveData& m1, const MoveData& m2); friend bool compareYear(const MoveData& m1, const MoveData& m2); }; class OpeningTreeUpdater : public QThread { Q_OBJECT public: void run(); void cancel(); bool updateFilter(Filter& f, const Board& b, QList&, int&, bool updateFilter, bool bEnd); signals: void UpdateFinished(Board*); void UpdateTerminated(Board*); void progress(int); private: QList* m_moves; int* m_games; bool m_break; Board m_board; Filter* m_filter; bool m_updateFilter; bool m_bEnd; }; /** @ingroup Search The OpeningTree class is a class to calculate opening tree for given position. */ class OpeningTree : public QAbstractTableModel { Q_OBJECT public: /** Empty constructor. */ OpeningTree(); /** Initialized constructor, performing automatic ee */ OpeningTree(Filter& f, const Board& b, bool updateFilter); /** Calculate opening tree from given position, using given filter. It sets the filter to contain only game matching position @p b . @return true if the update was not cancelled.*/ bool updateFilter(Filter& f, const Board& b, bool updateFilter, bool bEnd); /** Debug string */ QString debug(); /** Returns the number of moves in the Opening Tree */ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; /** Returns the number of columns of the Opening Tree */ virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; /** Returns an item of data given the item 'index' */ virtual QVariant data(const QModelIndex &index, int role) const; /** Returns the header information for header 'section' */ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; /** Support sorting. */ virtual void sort(int column, Qt::SortOrder order); /** Support sorting. */ virtual void sort(); /** Move leading to given entry. */ QString move(const QModelIndex& index) const; /** Current Board */ Board board() const; public slots: /** Cancel a running update */ void cancel(bool); protected slots: void updateFinished(Board*); void updateTerminated(Board*); signals: void progress(int); void openingTreeUpdated(); void openingTreeUpdateStarted(); private: bool m_bRequestPending; QList m_moves; int m_games; QStringList m_names; int m_sortcolumn; Qt::SortOrder m_order; Board m_board; Filter* m_filter; bool m_updateFilter; bool m_bEnd; }; #endif chessx-1.0.0/src/gui/commentdialog.cpp000644 001750 001750 00000004521 12223260306 020510 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2010 by Michal Rudolf * * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "commentdialog.h" bool CommentDialog::lastTimeWasEgt = false; CommentDialog::CommentDialog(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f) { ui.setupUi(this); connect(ui.clearTime, SIGNAL(clicked()), this, SLOT(clearTimeSlot())); connect(ui.clearText, SIGNAL(clicked()), this, SLOT(clearTextSlot())); } QString CommentDialog::text() const { QString s; if(ui.timeEdit->time() != QTime(0, 0, 0)) { QString format = ui.egtTime->isChecked() ? "[%egt H:mm:ss]" : "[%clk H:mm:ss]"; s = ui.timeEdit->time().toString(format); if(!s.isEmpty()) { lastTimeWasEgt = ui.egtTime->isChecked(); } } QString s1 = ui.textEdit->toPlainText().trimmed(); if(!s1.isEmpty()) { s.append(" "); s.append(s1); } return s; } void CommentDialog::setText(QString text) { QRegExp egt("\\[%egt\\s*(\\d:\\d\\d:\\d\\d)\\]"); QRegExp clk("\\[%clk\\s*(\\d:\\d\\d:\\d\\d)\\]"); int pos = egt.indexIn(text); if(pos >= 0) { ui.egtTime->setChecked(true); QString segt = egt.cap(1); text = text.remove(egt); ui.timeEdit->setTime(QTime::fromString(segt, "H:mm:ss")); lastTimeWasEgt = true; } else { int pos = clk.indexIn(text); if(pos >= 0) { ui.clkTime->setChecked(true); QString sclk = clk.cap(1); text = text.remove(clk); ui.timeEdit->setTime(QTime::fromString(sclk, "H:mm:ss")); lastTimeWasEgt = false; } else { if(lastTimeWasEgt) { // Setup GUI with the last value we had in this dialog // That may be a bad guess, as this could come from a different game ui.egtTime->setChecked(true); } } } ui.textEdit->setPlainText(text); } void CommentDialog::clearTimeSlot() { ui.timeEdit->setTime(QTime(0, 0, 0)); } void CommentDialog::clearTextSlot() { ui.textEdit->setPlainText(""); } chessx-1.0.0/src/gui/aboutdlg.h000644 001750 001750 00000000766 12223260306 017143 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2013 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef ABOUTDLG_H #define ABOUTDLG_H #include namespace Ui { class AboutDlg; } class AboutDlg : public QDialog { Q_OBJECT public: explicit AboutDlg(QWidget *parent = 0); ~AboutDlg(); private: Ui::AboutDlg *ui; }; #endif // ABOUTDLG_H chessx-1.0.0/src/gui/main.cpp000644 001750 001750 00000005607 12232012570 016616 0ustar00niklasniklas000000 000000 /*************************************************************************** main.cpp - main application ------------------- begin : sob maj 7 2005 copyright : (C) 2005 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include "mainwindow.h" #include "settings.h" #include "logstream.h" int main(int argc, char** argv) { QApplication app(argc, argv); #if defined(Q_OS_MAC) QDir dir(QApplication::applicationDirPath()); dir.cdUp(); dir.cd("plugins"); QApplication::addLibraryPath(dir.absolutePath()); dir.cdUp(); dir.cd("Frameworks"); QApplication::addLibraryPath(dir.absolutePath()); #endif app.setWindowIcon(QIcon(":/images/chessx.png")); app.setApplicationName("chessx"); app.setOrganizationName("chessx"); AppSettings = new Settings; #ifdef Q_OS_MAC signal(SIGPIPE, SIG_IGN); #endif QString shortSystemLang = QString("chessx_%1.qm").arg(QLocale::system().name().left(2)); QString fullSystemLang = QString("chessx_%1.qm").arg(QLocale::system().name().left(5)); // Language may have two forms: "pt_BR" or "pl" QString lang = QString("chessx_%1.qm").arg(AppSettings->getValue("/General/language").toString()); QDir().mkpath(AppSettings->dataPath() + "/lang/"); QTranslator translator; if (lang != "chessx_en.qm") { if(translator.load(QString(":/i18n/") + lang) || translator.load(AppSettings->dataPath() + "/lang/" + lang) || translator.load(QString(":/i18n/") + fullSystemLang) || translator.load(AppSettings->dataPath() + "/lang/" + fullSystemLang) || translator.load(QString(":/i18n/") + shortSystemLang) || translator.load(AppSettings->dataPath() + "/lang/" + shortSystemLang)) { app.installTranslator(&translator); } } MainWindow* mainWindow = new MainWindow; mainWindow->show(); // Destroy main window and close application app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); startFileLog(); int result = app.exec(); stopFileLog(); delete AppSettings; return result; } chessx-1.0.0/INSTALL000644 001750 001750 00000001301 10622575745 014652 0ustar00niklasniklas000000 000000 1. Requirements To compile ChessX, you need Qt version 4.2.0 or above. 2. Compilation Compiling the source is simple. Execute: qmake and then make If the compilation is successful you should be able to run ChessX executable in bin subdirectory. It is called: chessx on Linux, chessx.app on Mac OS, chessx.exe on Windows 3. Problems If you have both Qt3 and Qt4 installed, verify that Qt4 is first on your path. You may check it, running: qmake -v If you erroneously tried to build with Qt3, be sure to recreate makefiles using: qmake -recursive 4. Debugging If you want to help debugging ChessX, rebuild with debug option enabled: qmake -recursive -after "CONFIG+=debug" make chessx-1.0.0/data/images/text_clear.png000644 001750 001750 00000005374 12053226453 020642 0ustar00niklasniklas000000 000000 PNG  IHDR00W IDAThKlǿ$-d[dȭA]IQ$hvp%M6hb׭Ӱ;4Pl:qPhlCnNݴNRmؖ?"$eR/ۍK-~>thi8:rSu"@OFF e2;s7V8ut/ ID?W*X֥o CDL4 {{uwT eyz'%qSNߏXv xɾlN! |+ׯC( ,# G"A^[Ua2Y$َuvmKU{wLfXRULI 848`Y(&~8ǍN cqL$ A5|;xmRUWgY$m[bߏʭ[Xz P&2lZ I6p_wNsCKKڅ=8;0>$0ĎX7OgCe~WY&_?eY.ptKuQ.uq޻ 8<8Ήssm* =*na5 y}hAPHqYwX,D6mTuU8dm95(g%Jy"nߞQqY|d}]b{Ym5-T6*l]G,s%j& 6p.!1tfz< @k:/˗T*x,&<'FxnpLs#Ri8ϟ| AV%D2fƇ/(ؾ8/GB"Xc= rgᰢN%w[u+WjG?puӠwڀ/|eYpK8KK0+^B+{P 6>X-ò\38w}('(eh0>tٕ I$h&fp(n ~3D j5X {`ѴPD[]dc$dꑿM4KдiԾZv*Fˆٽ(*PmY1 8 7N4CE޿#!!Iӯd!l} {Bd@"X>~Tp*ѦY4A}WLڢxL@yO8"{+=4ʭ[E4NdrT0MKCm *ۖ8Ϗ9vtzhk7nG&#N4W"C /YSv$,0cǎi[ 4 a 10$M lpA%% Xw4yȆ /\)Zֶ$T˲iqO !#u$Fx4 (Q ~rH&.i 5d,$LE76| ?;rȷz|$v7H03$!M󆱩DKqs#?Ƅgb#0QIud(7'PY˃jg+4=ݘ 5E <!Ͳs$BK@ȷB4{whmsI6B"KxL2A:Bbgm$ ?;a~UIὝlxU4)I/YSIrj!A$(r%>8FxVӚ$F<@ oFvK $MB /Ր44HPr_~/}_1~k~ -i! BARFRˉD7I Yߵ]i9N/EӨ޻3379ב-l---sca*=޶ >WE4 XAն>^ 4?V7&6Yf2`yȒ?Eq,FHr[N^:E >PÀ!jW_-mmU*OE%l{qY~e,׷!B ɀ,[^.a _(P jnfb{wuܳQuYKC5Ų}}󃃐% 7$,+8emH%IJQpܿw}~0jkbۗLs4e>XX#_e\^l;KW\쳅3?/=Z7D!aY1vgUt%`2n $zXVHDOwoI<(hOYbQ$4xT2p4Khw$UN7Kj&IA4snnbGxhX,6XFKkkN lUN\w4m -7/Z~TIP{]7ܳ#uL|׫:IENDB`chessx-1.0.0/src/database/tablebase.cpp000644 001750 001750 00000007133 12223260306 020572 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2007 Sean Estabrooks * * (C) 2008-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include #include #include "tablebase.h" #include #include #include #include Shredder::Shredder() { connect(&manager, SIGNAL(finished(QNetworkReply*)), SLOT(httpDone(QNetworkReply*))); } Shredder::~Shredder() { } void Shredder::abortLookup() { } void Shredder::getBestMove(QString fen) { abortLookup(); if(m_fen == fen) { return; } m_fen = fen; QTimer::singleShot(100, this, SLOT(sendIt())); } void Shredder::sendIt() { QString prep(m_fen.simplified()); QString count(prep.left(prep.indexOf(" "))); int white = count.count(QRegExp("[A-Z]")); int black = count.count(QRegExp("[a-z]")); if(white + black > 6 || black > 4 || white > 4 || black < 1 || white < 1) { return; } QChar toMove = (prep[prep.indexOf(QString(" ")) + 1].toLower()); QString requested = QString("/online/playshredder/fetch.php?action=egtb&hook=%1&fen=%2") .arg(toMove).arg(m_fen); QUrl url(requested); url.setScheme("http"); url.setHost("www.shredderchess.com"); m_requested = url.toString(); QNetworkRequest request(url); manager.get(request); } void Shredder::httpDone(QNetworkReply *reply) { QUrl url = reply->url(); if(!reply->error()) { if(url.toString() == m_requested) { m_requested.clear(); QString ret(reply->readAll()); if(ret.indexOf("Not found") >= 0) { return; } if(ret[5] == 'w') { ret.remove(QRegExp("NEXTCOLOR.*\\n")); } else { ret.remove(QRegExp(".*NEXTCOLOR\\n")); } ret.remove(0, ret.indexOf("\n") + 1); ret.remove(":"); ret.remove("Win in "); ret.replace(QRegExp("[-x]"), " "); ret.replace("Draw", "0"); ret.replace("Lose in ", "-"); QStringList fld(ret.left(ret.indexOf('\n')).split(' ')); if(fld.size() < 3) { return; } Move move(fld[0].toInt(), fld[1].toInt()); int score = fld[2].toInt(); if(fld.size() > 3) { switch(score) { case 8: move.setPromoted(Queen); break; case 9: move.setPromoted(Rook); break; case 10: move.setPromoted(Bishop); break; case 11: move.setPromoted(Knight); break; default: return; } score = fld[3].toInt(); } emit bestMove(move, score); } } reply->deleteLater(); } chessx-1.0.0/data/images/square_yellow.png000644 001750 001750 00000013505 12074576333 021406 0ustar00niklasniklas000000 000000 PNG  IHDRw=iCCPICC ProfileX XuXUͷOrݝ])R."RRJ)*RRH6 (*܍ߕ~=k֞=3^^XC`ZBâȶz.׀hZ/Rd?ڭ|"WFjoHR(_")J  f$#D{VOE؄ycHH;ħ`|C)VQG24.G{M//=X'FxןSFۙ#%X_k{x_e;?h8:A/>dꯝ?;>1dݞ=.@_ /]ƾ!{ gX||#oTv{>~Fd={xȟ5h۽y s؛C/xRoln!D"W4$-+/+'vЮ˶<-06ܐeM; =R49л7@ et!0Vw@ a@g@(Ԁk<C1x^)|`lB  ⁄ HR C\ O B%% ݆h zMC`J悅aXօa{ Gqp |.+p ) ("ŇBQV(W:D*P vT? j Ƣмh)&#t ݋~F/c0 :Ƥa 1W0͘>3G*eƊ`U&Xl6=Žag+8 'YpQ4\1*7[> AAp##Qє11"="#S,S)=)f0)sss#s .]_ q5VVV_LX7x قβaG۰fǾȡAhx ssrsVrspqssssZfa ī[˻gwoo_߁?:@@ ``K! !UsBBk"N­s"""q""EDE#D+DaTł΋=ŕKG%` e@cI50 )J)]ziifi dVo222gee~*ɆVɾ3Kk['ɗ?UR0R8ЦCQBWRRҶ2YAy^EPSLeBQZ5[FMO]_Q5454WoF_KE)m>m/ ::>:Wtfutt~ӓ#52@d:5777Z4V272502%֚.5543/1o!nAh-,,_ XZYc)d+g`o`aWgjgcA!ڡǑͱq)iY KK+>)=?(r0;{=/[O':-/+ oS2E>鋏Oϼoײַ_ߜ|v@aB~`I `Paaa O P(X$DB#ۢphtjtVLia÷bbb82gw9OIKHJ>{1SL4NI"$'=JMMyD{ WJbLqj}u9m"]#$dɑ ߙ>YYY[٤SrN;=s LؙgYg,((T,,?G8}nȢXLVI@ɳReeek}Ώ_йPUUq1%K-ʘOUUU/^aue:zƶV.v5km R 3_ϺnD|Fƞ[ʚ3[#-Sm.mcnk7ߑS}n={9θΕnW?3{~·TlRjVn~yDyeTe}cO _HӬ>lo9,9[xȼ|K<*B"bJܒtRh59r J*UMԔԹ5Mhviifeg囟8mU )v'SRĻt ;A &%-0h,eLBj8*,es#q# KPiٓxNr3 d3V;=gO G=*,~X[Uv|ۅ򦋭:*V>zB-s@Uk ;zt9XkR[;YwO;ݑәU]S~mw u w=||gy꓊e?O zq+*orz{}37?~LtheNo^3/}mv{b%el+ko*H r-üǿ4lBv4FqSzSu2,l~/8* 6 +/Ȓ<&!- k,!/H)-)O1yj ^v;)i3Bh?l\|/V _}tǍŸ+I1k랿66䶅~PcQh"`oKq0L)FD֎-fI*6VLE.j| o57K4K6J]n*[#W%QTRr 5>KM-E}]n=N}..C^#^c^nS.36sf ZK8+jzfvn~aq˒ns1kϴGـ๐ٰC_Wp$}`rGꎶ"t q(i ĝ괲3'S3b3f[=#r,c.UE>U *Z)^,Rl OG/_ھxg{+kk]k={<\1}GFfFdg=N4O6~YuΛGENO7Q 0;9;s间nߌ+. `YY&$V ku/ &n ځvG؍ Xe 9C3HzəA 5j0 6ELS; BdU`C dt"=`:Xv+SQ3H扮@Ha1]XJ5sSC# %јHEAJK5AmNMNL@DLw^~a17f!,,ˬll/989xyy DD,işHKzIIJK?) 3Pxx_rJjZzƹ}5{u&tV153236aɶl]i3aGmoxiE@۠;7B6.q+'z~lkt|QcUBI5'$R)0ɜ<;\h~D!ӹ{ŁeO/]tyAuYmL5,7v&[x5ӳG/5`9xoS/a|g;;˜纅?wV׻6E~`? @ 78 C|[ $  CTP?a~:GкdtŔafJTNw/oPxP< ʈb,#*5j!rNRZ. :1&zQwoǘh*՘XBX ullF˜vox2 nT!saFw"t %) ӕg0بtN9Q*IMYyVvNn^~1YyMVhky9 nnq<ռy z g$?>vA|B1IPGQ'Oeg՝F #include "engineoptiondata.h" #include "enginelist.h" class Engine; namespace Ui { class EngineOptionDialog; } class EngineOptionDialog : public QDialog { Q_OBJECT public: explicit EngineOptionDialog(QWidget *parent, EngineList& engineList, int index, Qt::WindowFlags f = 0); ~EngineOptionDialog(); OptionValueList GetResults() const; public slots: void accept(); protected slots: void engineActivated(); void optionReset(); private: Ui::EngineOptionDialog *ui; Engine* m_engine; int m_index; }; #endif // ENGINEOPTIONDIALOG_H chessx-1.0.0/src/guess/guessengine.cpp000644 001750 001750 00000271365 12223260306 020560 0ustar00niklasniklas000000 000000 ////////////////////////////////////////////////////////////////////// // // FILE: engine.cpp // Engine class methods // // Part of: Scid (Shane's Chess Information Database) // Version: 3.5 // // Notice: Copyright (c) 2002-2003 Shane Hudson. All rights reserved. // // Author: Shane Hudson (sgh@users.sourceforge.net) // ////////////////////////////////////////////////////////////////////// #include "attacks.h" #include "guessengine.h" #include "recog.h" namespace Guess { // The Engine class implements the Scid built-in chess engine. // See guessengine.h for details. // Evaluation constants: static const int Infinity = 32000; static const int KingValue = 10000; static const int QueenValue = 900; static const int RookValue = 500; static const int BishopValue = 300; static const int KnightValue = 300; static const int PawnValue = 100; // EndgameValue, MiddlegameValue: // If the combined material score of pieces on both sides (excluding // kings and pawns) is less than this value, we are in an endgame. // If it is greater than MiddlegameValue, we use middlegame scoring. // For anything in between, the score will be a weighted average of // the middlegame and endgame scores. // static const int EndgameValue = 2400; static const int MiddlegameValue = 4000; // Bonuses and penalties: // static const int RookHalfOpenFile = 8; static const int RookOpenFile = 20; static const int RookPasserFile = 25; // Rook on passed pawn file. static const int RookOnSeventh = 25; // Rook on its 7th rank. static const int DoubledRooks = 20; // Two rooks on same file. static const int RookEyesKing = 12; // Attacks squares near enemy king. static const int KingTrapsRook = 35; // E.g. King on f1, Rook on h1 static const int DoubledPawn = 8; static const int IsolatedPawn = 16; static const int BackwardPawn = 10; // Pawn at base of pawn chain. static const int DispersedPawn = 10; // Not in pawn chain/duo. (Unused) static const int BlockedHomePawn = 15; // Blocked pawn on d2/e2/d7/e7. static const int BishopPair = 25; // Pair of bishops. static const int BishopEyesKing = 12; // Bishop targets enemy king. static const int BishopTrapped = 120; // E.g. Bxa7? ...b6! static const int KnightOutpost = 15; // 4th/5th/6th rank outpost. static const int KnightBadEndgame = 30; // Enemy pawns on both wings. static const int BadPieceTrade = 80; // Bad trade, e.g. minor for pawns. static const int CanCastle = 10; // Bonus for castling rights. static const int Development = 8; // Moved minor pieces in opening. static const int CentralPawnPair = 15; // For d4/d5 + e4/e5 pawns. static const int CoverPawn = 12; // Pawn cover for king. static const int PassedPawnRank[8] = { // 1 2 3 4 5 6 7 8th rank 0, 10, 15, 25, 50, 80, 120, 0 }; // Bishops (and rooks in endings) need to be mobile to be useful: static const int BishopMobility[16] = { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -20, -15, -10, -6, -3, 0, 3, 6, 9, 12, 15, 15, 15, 15, 15, 15 }; static const int RookEndgameMobility[16] = { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -25, -20, -15, -10, -5, 2, 0, 2, 4, 6, 8, 8, 8, 8, 8, 8 }; // Piece distance to enemy king bonuses: 1 2 3 4 5 6 7 static const int KnightKingDist [8] = { 0, 10, 14, 10, 5, 2, 0, 0 }; static const int BishopKingDist [8] = { 0, 8, 6, 4, 2, 1, 0, 0 }; static const int RookKingDist [8] = { 0, 8, 6, 4, 2, 1, 0, 0 }; static const int QueenKingDist [8] = { 0, 15, 12, 9, 6, 3, 0, 0 }; // LazyEvalMargin // A score that is further than this margin outside the current // alpha-beta window after material evaluation is returned as-is. // A larger margin is used for endgames (especially pawn endings) // since positional bonuses can be much larger for them. static const int LazyEvalMargin = 250; static const int LazyEvalEndingMargin = 400; static const int LazyEvalPawnEndingMargin = 800; // NullMoveReduction: // The default reduced depth for a null move search. static const int NullMoveReduction = 2; // AspirationWindow: // The window around the score of the previous depth iteration // when searching at the root. static const int AspirationWindow = 35; // PawnSquare: // Gives bonuses to advanced pawns, especially in the centre. static const int PawnSquare [64] = { 0, 0, 0, 0, 0, 0, 0, 0, // A8 - H8 4, 8, 12, 16, 16, 12, 8, 4, 4, 8, 12, 16, 16, 12, 8, 4, 3, 6, 9, 12, 12, 9, 6, 3, 2, 4, 6, 8, 8, 6, 4, 2, 1, 2, 3, 4, 4, 3, 2, 1, 0, 0, 0, -4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // A1 - H1 }; // PawnStorm: // Bonus when side is castled queenside and opponent is // castled kingside. Gives a bonus for own sheltering pawns // and a penalty for pawns on the opposing wing to make them // disposable and encourage them to move forwards. static const int PawnStorm [64] = { 0, 0, 0, 0, 0, 0, 0, 0, // A8 - H8 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 4, 2, 2, 2, 0, 0, 0, 4, 6, 0, 0, 0, 4, 4, 4, 4, 4, -4, -4, -4, 8, 8, 8, 0, 0, -8, -8, -8, 12, 12, 12, 0, 0, -12, -12, -12, 0, 0, 0, 0, 0, 0, 0, 0 // A1 - H1 }; // KnightSquare: // Rewards well-placed knights. static const int KnightSquare [64] = { -24, -12, -6, -6, -6, -6, -12, -24, -8, 0, 0, 0, 0, 0, 0, -8, -6, 5, 10, 10, 10, 10, 5, -6, -6, 0, 10, 10, 10, 10, 0, -6, -6, 0, 5, 8, 8, 5, 0, -6, -6, 0, 5, 5, 5, 5, 0, -6, -6, 0, 0, 0, 0, 0, 0, -8, -10, -8, -5, -6, -6, -6, -6, -10 }; // BishopSquare: // Bonus array for bishops. static const int BishopSquare [64] = { -10, -5, 0, 0, 0, 0, -5, -10, -5, 8, 0, 5, 5, 0, 8, -5, 0, 0, 5, 5, 5, 5, 0, 0, 0, 5, 10, 5, 5, 10, 5, 0, 0, 5, 10, 5, 5, 10, 5, 0, 0, 0, 5, 5, 5, 5, 0, 0, -5, 8, 0, 5, 5, 0, 8, -5, -10, -5, -2, -2, -2, -2, -5, -10 }; // RookFile: // Bonus array for Rooks, by file. static const int /* a b c d e f g h */ RookFile [8] = { 0, 0, 4, 8, 8, 4, 0, 0 }; // QueenSquare: // Bonus array for Queens. static const int QueenSquare [64] = { -5, 0, 0, 0, 0, 0, 0, -5, // A8 - H8 -5, 0, 3, 3, 3, 3, 0, -5, 0, 3, 6, 9, 9, 6, 3, 0, 0, 3, 9, 12, 12, 9, 3, 0, -5, 3, 9, 12, 12, 9, 3, -5, -5, 3, 6, 9, 9, 6, 3, -5, -5, 0, 3, 3, 3, 3, 0, -5, -10, -5, 0, 0, 0, 0, -5, -10 // A1 - H1 }; // KingSquare: // Bonus array for kings in the opening and middlegame. static const int KingSquare [64] = { -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, -60, -60, -50, -50, -50, -40, -40, -40, -60, -60, -40, -40, -40, -15, -15, -15, -20, -20, -15, -15, -15, 5, 5, 0, 0, 0, 0, 5, 5, 20, 20, 15, 5, 5, 5, 20, 20 }; // EndgameKingSquare: // Rewards King centralisation in endgames. // TODO: Add separate king square tables for endgames where all // pawns are on one side of the board. static const int KingEndgameSquare [64] = { -10, -5, 0, 5, 5, 0, -5, -10, -5, 0, 5, 10, 10, 5, 0, -5, 0, 5, 10, 15, 15, 10, 5, 0, 5, 10, 15, 20, 20, 15, 10, 5, 5, 10, 15, 20, 20, 15, 10, 5, 0, 5, 10, 15, 15, 10, 5, 0, -5, 0, 5, 10, 10, 5, 0, -5, -10, -5, 0, 5, 5, 0, -5, -10 }; static const int pieceValues [8] = { 0, // Invalid KingValue, QueenValue, RookValue, BishopValue, KnightValue, PawnValue, 0 // Empty }; inline int Engine::PieceValue(pieceT piece) { return pieceValues[piece_Type(piece)]; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // isOutpost // Returns true if the square is on the 4th/5th/6th rank (3rd/4th/5th // for Black) and cannot be attacked by an enemy pawn. static bool isOutpost(const pieceT * board, squareT sq, colorT color) { pieceT enemyPawn = piece_Make(color_Flip(color), PAWN); rankT rank = square_Rank(sq); fyleT fyle = square_Fyle(sq); // Build the list of squares to check for enemy pawns: SquareList squares; if(color == WHITE) { if(rank < RANK_4 || rank > RANK_6) { return false; } if(fyle > A_FYLE) { squares.Add(square_Make(fyle - 1, RANK_7)); if(rank == RANK_5) { squares.Add(square_Make(fyle - 1, RANK_6)); } } if(fyle < H_FYLE) { squares.Add(square_Make(fyle + 1, RANK_7)); if(rank == RANK_5) { squares.Add(square_Make(fyle + 1, RANK_6)); } } } else { if(rank < RANK_3 || rank > RANK_5) { return false; } if(fyle > A_FYLE) { squares.Add(square_Make(fyle - 1, RANK_2)); if(rank == RANK_4) { squares.Add(square_Make(fyle - 1, RANK_3)); } } if(fyle < H_FYLE) { squares.Add(square_Make(fyle + 1, RANK_2)); if(rank == RANK_4) { squares.Add(square_Make(fyle + 1, RANK_3)); } } } // Now check each square for an enemy pawn: for(unsigned int i = 0; i < squares.Size(); i++) { if(board[squares.Get(i)] == enemyPawn) { return false; } } return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::Score // Returns a score in centipawns for the current engine position, // from the perspective of the side to move. int Engine::Score(void) { // Look for a recognized ending with an exact score: int recog = Recognizer::Recognize(&Pos); if(recogFlag(recog) == SCORE_EXACT) { return recogScore(recog); } return Score(-Infinity, Infinity); } static unsigned int nScoreCalls = 0; static unsigned int nScoreFull = 0; inline int Engine::ScoreWhiteMaterial(void) { unsigned char * pieceCount = Pos.GetMaterial(); return pieceCount[WQ] * QueenValue + pieceCount[WR] * RookValue + pieceCount[WB] * BishopValue + pieceCount[WN] * KnightValue + pieceCount[WP] * PawnValue; } inline int Engine::ScoreBlackMaterial(void) { unsigned char * pieceCount = Pos.GetMaterial(); return pieceCount[BQ] * QueenValue + pieceCount[BR] * RookValue + pieceCount[BB] * BishopValue + pieceCount[BN] * KnightValue + pieceCount[BP] * PawnValue; } int Engine::ScoreMaterial(void) { int score = ScoreWhiteMaterial() - ScoreBlackMaterial(); return (Pos.GetToMove() == WHITE) ? score : -score; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::Score // Returns a score in centipawns for the current engine position, // from the perspective of the side to move. // Alpha and beta cutoff scores are specified for performance. If // simple material counting produces a score much lower than alpha // or much greater than beta, the score is returned without // slower square-based evaluation. int Engine::Score(int alpha, int beta) { colorT toMove = Pos.GetToMove(); const unsigned char * pieceCount = Pos.GetMaterial(); const pieceT * board = Pos.GetBoard(); int materialScore[2] = {0, 0}; int allscore[2] = {0, 0}; // Scoring in all positions int endscore[2] = {0, 0}; // Scoring in endgames int midscore[2] = {0, 0}; // Scoring in middlegames int nNonPawns[2] = {0, 0}; // Non-pawns on each side, including kings nScoreCalls++; nNonPawns[WHITE] = Pos.NumNonPawns(WHITE); nNonPawns[BLACK] = Pos.NumNonPawns(BLACK); // First compute material scores: allscore[WHITE] = materialScore[WHITE] = ScoreWhiteMaterial(); allscore[BLACK] = materialScore[BLACK] = ScoreBlackMaterial(); int pieceMaterial = (materialScore[WHITE] - pieceCount[WP] * PawnValue) + (materialScore[BLACK] - pieceCount[BP] * PawnValue); bool inEndgame = false; bool inMiddlegame = false; if(pieceMaterial <= EndgameValue) { inEndgame = true; } if(pieceMaterial >= MiddlegameValue) { inMiddlegame = true; } bool inPawnEndgame = Pos.InPawnEnding(); // Look for a bad trade: minor piece for pawns; Q for R+Pawns; etc. // But only do this if both sides have pawns. if(pieceCount[WP] > 0 && pieceCount[BP] > 0) { unsigned int wminors = pieceCount[WB] + pieceCount[WN]; unsigned int bminors = pieceCount[BB] + pieceCount[BN]; unsigned int wmajors = pieceCount[WR] + (2 * pieceCount[WQ]); unsigned int bmajors = pieceCount[BR] + (2 * pieceCount[BQ]); if(wmajors == bmajors) { if(wminors < bminors) { allscore[WHITE] -= BadPieceTrade; } if(wminors > bminors) { allscore[BLACK] -= BadPieceTrade; } } else if(wminors == bminors) { if(wmajors < bmajors) { allscore[WHITE] -= BadPieceTrade; } if(wmajors > bmajors) { allscore[BLACK] -= BadPieceTrade; } } } // Add the Bishop-pair bonus now, because it is fast and easy: if(pieceCount[WB] >= 2) { allscore[WHITE] += BishopPair; } if(pieceCount[BB] >= 2) { allscore[BLACK] += BishopPair; } // If there are no pawns, a material advantage of only one minor // piece is worth very little so reduce the material score. if(pieceCount[WP] + pieceCount[BP] == 0) { int materialDiff = materialScore[WHITE] - materialScore[BLACK]; if(materialDiff < 0) { materialDiff = -materialDiff; } if(materialDiff == BishopValue || materialDiff == KnightValue) { allscore[WHITE] /= 4; allscore[BLACK] /= 4; } } // Look for a trapped bishop on a7/h7/a2/h2: if(Pos.RankCount(WB, RANK_7) > 0) { if(board[A7] == WB && board[B6] == BP) { allscore[WHITE] -= BishopTrapped; } if(board[H7] == WB && board[G6] == BP) { allscore[WHITE] -= BishopTrapped; } } if(Pos.RankCount(BB, RANK_2) > 0) { if(board[A2] == BB && board[B3] == WP) { allscore[BLACK] -= BishopTrapped; } if(board[H2] == BB && board[G6] == WP) { allscore[BLACK] -= BishopTrapped; } } // Check for a score much worse than alpha or better than beta // which can be returned immediately on the assumption that // a full evaluation could not get inside the alpha-beta range. // If we are in a pawn ending, a much larger margin is used since // huge bonuses can be added for passed pawns in such endgames. int lazyMargin = LazyEvalMargin; if(inEndgame) { lazyMargin = LazyEvalEndingMargin; } if(inPawnEndgame) { lazyMargin = LazyEvalPawnEndingMargin; } int fastScore = allscore[WHITE] - allscore[BLACK]; if(toMove == BLACK) { fastScore = -fastScore; } if(fastScore - lazyMargin > beta) { return fastScore; } if(fastScore + lazyMargin < alpha) { return fastScore; } // Get the pawn structure score next, because it is usually fast: pawnTableEntryT pawnEntry; ScorePawnStructure(&pawnEntry); // Penalise d-file and e-file pawns blocked on their home squares: if(board[D2] == WP && board[D3] != EMPTY) { allscore[WHITE] -= BlockedHomePawn; } if(board[E2] == WP && board[E3] != EMPTY) { allscore[WHITE] -= BlockedHomePawn; } if(board[D7] == BP && board[D6] != EMPTY) { allscore[BLACK] -= BlockedHomePawn; } if(board[E7] == BP && board[E6] != EMPTY) { allscore[BLACK] -= BlockedHomePawn; } // Incentive for side ahead in material to trade nonpawn pieces and // for side behind in material to avoid trades: if(materialScore[WHITE] > materialScore[BLACK]) { int bonus = (5 - nNonPawns[BLACK]) * 5; allscore[WHITE] += bonus; } else if(materialScore[BLACK] > materialScore[WHITE]) { int bonus = (5 - nNonPawns[WHITE]) * 5; allscore[BLACK] += bonus; } // Check again for a score outside the alpha-beta range, using a // smaller fixed margin of error since the pawn structure score // has been added: fastScore = (allscore[WHITE] - allscore[BLACK]) + pawnEntry.score; if(toMove == BLACK) { fastScore = -fastScore; } if(fastScore > beta + 200) { return fastScore; } if(fastScore < alpha - 200) { return fastScore; } nScoreFull++; // Now refine the score with piece-square bonuses: squareT wk = Pos.GetKingSquare(WHITE); squareT bk = Pos.GetKingSquare(BLACK); fyleT wkFyle = square_Fyle(wk); fyleT bkFyle = square_Fyle(bk); // Check if each side should be storming the enemy king: if(!inEndgame) { if(wkFyle <= C_FYLE && bkFyle >= F_FYLE) { midscore[WHITE] += pawnEntry.wLongbShortScore; } else if(wkFyle >= F_FYLE && bkFyle <= C_FYLE) { midscore[WHITE] += pawnEntry.wShortbLongScore; } } // Iterate over the piece for each color: for(colorT c = WHITE; c <= BLACK; c++) { colorT enemy = color_Flip(c); // squareT ownKing = Pos.GetKingSquare(c); squareT enemyKing = Pos.GetKingSquare(enemy); unsigned int npieces = Pos.GetCount(c); squareT * sqlist = Pos.GetList(c); int mscore = 0; // Middlegame score adjustments int escore = 0; // Endgame score adjustments int ascore = 0; // All-position adjustments (middle and endgame) for(unsigned int i = 0; i < npieces; i++) { squareT sq = sqlist[i]; pieceT p = board[sq]; pieceT ptype = piece_Type(p); ASSERT(p != EMPTY && piece_Color(p) == c); squareT bonusSq = (c == WHITE) ? square_FlipRank(sq) : sq; unsigned int rank = RANK_1 + RANK_8 - square_Rank(bonusSq); // Piece-specific bonuses. The use of if-else instead of // a switch statement was observed to be faster since // the most common piece types are handled first. if(ptype == PAWN) { // Most pawn-specific bonuses are in ScorePawnStructure(). // Kings should be close to pawns in endgames: // if (!inMiddlegame) { // escore += 3 * square_Distance (sq, enemyKing) // - 2 * square_Distance (sq, ownKing); // } } else if(ptype == ROOK) { ascore += RookFile[square_Fyle(sq)]; if(rank == RANK_7) { ascore += RookOnSeventh; // Even bigger bonus if rook traps king on 8th rank: bool kingOn8th = (p == WR) ? (bk >= A8) : (wk <= H1); if(kingOn8th) { ascore += RookOnSeventh; } } if(!inEndgame) { mscore += RookKingDist[square_Distance(sq, enemyKing)]; } if(!inMiddlegame) { unsigned int mobility = Pos.Mobility(ROOK, c, sq); escore += RookEndgameMobility [mobility]; } } else if(ptype == KING) { if(Pos.GetCount(c) == 1) { // Forcing a lone king to a corner: ascore += 5 * KingEndgameSquare[bonusSq] - 150; } else { mscore += KingSquare[bonusSq]; escore += KingEndgameSquare[bonusSq]; } } else if(ptype == BISHOP) { ascore += BishopSquare[bonusSq]; ascore += BishopMobility [Pos.Mobility(BISHOP, c, sq)]; // Middlegame bonus for diagonal close to enemy king: if(! inEndgame) { mscore += BishopKingDist[square_Distance(sq, enemyKing)]; // Reward a bishop attacking the enemy king vicinity: int leftdiff = (int)square_LeftDiag(sq) - (int)square_LeftDiag(enemyKing); int rightdiff = (int)square_RightDiag(sq) - (int)square_RightDiag(enemyKing); if((leftdiff >= -2 && leftdiff <= 2) || (rightdiff >= -2 && rightdiff <= 2)) { mscore += BishopEyesKing; } } } else if(ptype == KNIGHT) { ascore += KnightSquare[bonusSq]; if(!inEndgame) { mscore += KnightKingDist[square_Distance(sq, enemyKing)]; // Bonus for a useful outpost: if(rank >= RANK_4 && !square_IsEdgeSquare(sq) && isOutpost(board, sq, c)) { mscore += KnightOutpost; } } if(!inMiddlegame) { // Penalty for knight in an endgame with enemy // pawns on both wings. pieceT enemyPawn = piece_Make(enemy, PAWN); unsigned int qsidePawns = Pos.FyleCount(enemyPawn, A_FYLE) + Pos.FyleCount(enemyPawn, B_FYLE) + Pos.FyleCount(enemyPawn, C_FYLE); unsigned int ksidePawns = Pos.FyleCount(enemyPawn, F_FYLE) + Pos.FyleCount(enemyPawn, G_FYLE) + Pos.FyleCount(enemyPawn, H_FYLE); if(ksidePawns > 0 && qsidePawns > 0) { escore -= KnightBadEndgame; } } } else /* (ptype == QUEEN) */ { ASSERT(ptype == QUEEN); ascore += QueenSquare[bonusSq]; ascore += QueenKingDist[square_Distance(sq, enemyKing)]; } } allscore[c] += ascore; midscore[c] += mscore; endscore[c] += escore; } // Now reward rooks on open files or behind passed pawns: unsigned char passedPawnFyles = pawnEntry.fyleHasPassers[WHITE] | pawnEntry.fyleHasPassers[BLACK]; for(colorT color = WHITE; color <= BLACK; color++) { pieceT rook = piece_Make(color, ROOK); if(pieceCount[rook] == 0) { continue; } colorT enemy = color_Flip(color); pieceT ownPawn = piece_Make(color, PAWN); pieceT enemyPawn = piece_Make(enemy, PAWN); fyleT enemyKingFyle = square_Fyle(Pos.GetKingSquare(enemy)); int bonus = 0; for(fyleT fyle = A_FYLE; fyle <= H_FYLE; fyle++) { unsigned int nRooks = Pos.FyleCount(rook, fyle); if(nRooks == 0) { continue; } if(nRooks > 1) { bonus += DoubledRooks; } unsigned int passedPawnsOnFyle = passedPawnFyles & (1 << fyle); if(passedPawnsOnFyle != 0) { // Rook is on same file as a passed pawn. // TODO: make bonus bigger when rook is *behind* the pawn. bonus += RookPasserFile; } else if(Pos.FyleCount(ownPawn, fyle) == 0) { // Rook on open or half-open file: if(Pos.FyleCount(enemyPawn, fyle) == 0) { bonus += RookOpenFile; } else { bonus += RookHalfOpenFile; } // If this open/half-open file leads to a square adjacent // to the enemy king, give a further bonus: int fdiff = (int)fyle - (int)enemyKingFyle; if(fdiff >= -1 && fdiff < 1) { bonus += RookEyesKing; } } } allscore[color] += bonus; } // King safety: if(! inEndgame) { if(pieceCount[BQ] > 0) { if(Pos.GetCastling(WHITE, KSIDE)) { midscore[WHITE] += CanCastle; } if(Pos.GetCastling(WHITE, QSIDE)) { midscore[WHITE] += CanCastle; } } if(pieceCount[WQ] > 0) { if(Pos.GetCastling(BLACK, KSIDE)) { midscore[BLACK] += CanCastle; } if(Pos.GetCastling(BLACK, QSIDE)) { midscore[BLACK] += CanCastle; } } // Bonus for pawn cover in front of a castled king. Actually we // also include bishops because they are important for defence. if(square_Rank(wk) == RANK_1 && wk != D1 && wk != E1) { unsigned int nCoverPawns = 0; pieceT p = board[square_Move(wk, UP_LEFT)]; if(p == WP || p == WB) { nCoverPawns++; } p = board[square_Move(wk, UP)]; if(p == WP || p == WB) { nCoverPawns++; } p = board[square_Move(wk, UP_RIGHT)]; if(p == WP || p == WB) { nCoverPawns++; } midscore[WHITE] += CoverPawn * nCoverPawns; if((wk == F1 || wk == G1) && (board[G1] == WR || board[H1] == WR || board[H2] == WR)) { midscore[WHITE] -= KingTrapsRook; } if((wk == C1 || wk == B1) && (board[B1] == WR || board[A1] == WR || board[A2] == WR)) { midscore[WHITE] -= KingTrapsRook; } } if(square_Rank(bk) == RANK_8 && bk != D8 && bk != E8) { unsigned int nCoverPawns = 0; pieceT p = board[square_Move(bk, DOWN_LEFT)]; if(p == BP || p == BB) { nCoverPawns++; } p = board[square_Move(bk, DOWN)]; if(p == BP || p == BB) { nCoverPawns++; } p = board[square_Move(bk, DOWN_RIGHT)]; if(p == BP || p == BB) { nCoverPawns++; } midscore[BLACK] += CoverPawn * nCoverPawns; if((bk == F8 || bk == G8) && (board[G8] == BR || board[H8] == BR || board[H7] == BR)) { midscore[BLACK] -= KingTrapsRook; } if((bk == C8 || bk == B8) && (board[B8] == BR || board[A8] == BR || board[A7] == BR)) { midscore[BLACK] -= KingTrapsRook; } } // Pawn centre: if((board[D4] == WP || board[D5] == WP) && (board[E4] == WP || board[E5] == WP)) { midscore[WHITE] += CentralPawnPair; } if((board[D4] == BP || board[D5] == BP) && (board[E4] == BP || board[E5] == BP)) { midscore[BLACK] += CentralPawnPair; } // Minor pieces developed: if(board[B1] != WN) { midscore[WHITE] += Development; } if(board[C1] != WB) { midscore[WHITE] += Development; } if(board[F1] != WB) { midscore[WHITE] += Development; } if(board[G1] != WN) { midscore[WHITE] += Development; } if(board[B8] != BN) { midscore[BLACK] += Development; } if(board[C8] != BB) { midscore[BLACK] += Development; } if(board[F8] != BB) { midscore[BLACK] += Development; } if(board[G8] != BN) { midscore[BLACK] += Development; } } // Work out the middlegame and endgame scores including pawn structure // evaluation, with a larger pawn structure weight in endgames: int baseScore = allscore[WHITE] - allscore[BLACK]; int mgScore = baseScore + midscore[WHITE] - midscore[BLACK]; int egScore = baseScore + endscore[WHITE] - endscore[BLACK]; mgScore += pawnEntry.score; egScore += (pawnEntry.score * 5) / 4; // Scale down the endgame score for bishops of opposite colors, if both // sides have the same non-pawn material: if(pieceCount[WB] == 1 && pieceCount[BB] == 1) { if(Pos.SquareColorCount(WB, WHITE) != Pos.SquareColorCount(BB, WHITE)) { if(pieceCount[WQ] == pieceCount[BQ] && pieceCount[WR] == pieceCount[BR] && pieceCount[WN] == pieceCount[BN]) { egScore = egScore * 5 / 8; } } } // Negate scores for Black to move: if(toMove == BLACK) { mgScore = -mgScore; egScore = -egScore; } // Determine the final score from the middlegame and endgame scores: int finalScore = 0; if(inMiddlegame) { finalScore = mgScore; // Use the middlegame score only. } else if(inEndgame) { finalScore = egScore; // Use the endgame score only. } else { // The final score is a weighted mean of the two scores: int midpart = (pieceMaterial - EndgameValue) * mgScore; int endpart = (MiddlegameValue - pieceMaterial) * egScore; finalScore = (endpart + midpart) / (MiddlegameValue - EndgameValue); } return finalScore; } static unsigned int nPawnHashProbes = 0; static unsigned int nPawnHashHits = 0; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::ScorePawnStructure // Fill in the provided pawnTableEntryT structure with pawn structure // scoring information, using the pawn hash table wherever possible. void Engine::ScorePawnStructure(pawnTableEntryT * pawnEntry) { nPawnHashProbes++; unsigned int pawnhash = Pos.PawnHashValue(); // We only use 32-bit hash values, so without further safety checks // the rate of false hits in the pawn hash table could be high. // To reduce the chance of false hits, we compute an extra signature. unsigned int sig = (Pos.SquareColorCount(WP, WHITE) << 12) | (Pos.SquareColorCount(BP, BLACK) << 8) | (Pos.PieceCount(WP) << 4) | Pos.PieceCount(BP); pawnEntry->pawnhash = pawnhash; pawnEntry->sig = sig; pawnEntry->fyleHasPassers[WHITE] = 0; pawnEntry->fyleHasPassers[BLACK] = 0; bool inPawnEndgame = (Pos.NumNonPawns(WHITE) == 1 && Pos.NumNonPawns(BLACK) == 1); pawnTableEntryT * hashEntry = NULL; // Check for a pawn hash table hit, but not in pawn endings: if(!inPawnEndgame) { unsigned int hashSlot = pawnhash % PawnTableSize; hashEntry = &(PawnTable[hashSlot]); if(pawnhash == hashEntry->pawnhash && sig == hashEntry->sig) { nPawnHashHits++; *pawnEntry = *hashEntry; return; } } // The pawnFiles array contains the number of pawns of each color on // each file. Indexes 1-8 are used while 0 and 9 are empty dummy files // added so that even the a and h files have two adjacent files, making // isolated/passed pawn calculation easier. unsigned int pawnFiles[2][10] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; // firstRank stores the rank of the leading pawn on each file. unsigned int firstRank[2][10] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; // lastRank stores the rank of the rearmost pawn on each file. unsigned int lastRank[2][10] = { {7, 7, 7, 7, 7, 7, 7, 7, 7, 7}, {7, 7, 7, 7, 7, 7, 7, 7, 7, 7} }; int pawnScore[2] = {0, 0}; int longVsShortScore[2] = {0, 0}; // Pawn storm bonuses, O-O-O vs O-O int shortVsLongScore[2] = {0, 0}; // Pawn storm bonuses, O-O vs O-O-O rankT bestRacingPawn[2] = {RANK_1, RANK_1}; for(fyleT f = A_FYLE; f <= H_FYLE; f++) { pawnFiles[WHITE][f + 1] = Pos.FyleCount(WP, f); pawnFiles[BLACK][f + 1] = Pos.FyleCount(BP, f); } for(colorT c = WHITE; c <= BLACK; c++) { pieceT pawn = piece_Make(c, PAWN); unsigned int npawns = Pos.PieceCount(pawn); SquareList sqlist; Pos.GetSquares(pawn, &sqlist); for(unsigned int i = 0; i < npawns; i++) { squareT sq = sqlist.Get(i); squareT wsq = (c == WHITE) ? sq : square_FlipRank(sq); squareT bonusSq = square_FlipRank(wsq); pawnScore[c] += PawnSquare[bonusSq]; longVsShortScore[c] += PawnStorm[bonusSq]; shortVsLongScore[c] += PawnStorm[square_FlipFyle(bonusSq)]; unsigned int fyle = square_Fyle(wsq) + 1; unsigned int rank = square_Rank(wsq); if(rank > firstRank[c][fyle]) { firstRank[c][fyle] = rank; } if(rank < lastRank[c][fyle]) { lastRank[c][fyle] = rank; } } } unsigned char fyleHasPassers[2] = {0, 0}; for(colorT color = WHITE; color <= BLACK; color++) { if(Pos.PieceCount(piece_Make(color, PAWN)) == 0) { continue; } colorT enemy = color_Flip(color); for(unsigned int fyle = 1; fyle <= 8; fyle++) { unsigned int pawnCount = pawnFiles[color][fyle]; if(pawnCount == 0) { continue; } unsigned int pawnRank = firstRank[color][fyle]; // Doubled pawn penalty: if(pawnCount > 1) { pawnScore[color] -= DoubledPawn * pawnCount; } // Isolated pawn penalty: bool isolated = false; if(pawnFiles[color][fyle - 1] == 0 && pawnFiles[color][fyle + 1] == 0) { isolated = true; pawnScore[color] -= IsolatedPawn * pawnCount; // Extra penalty for isolated on half-open file: if(pawnFiles[enemy][fyle] == 0) { pawnScore[color] -= IsolatedPawn * pawnCount / 2; } } else if(lastRank[color][fyle - 1] > lastRank[color][fyle] && lastRank[color][fyle + 1] > lastRank[color][fyle]) { // Not isolated, but backward: pawnScore[color] -= BackwardPawn; // Extra penalty for backward on half-open file: if(pawnFiles[enemy][fyle] == 0) { pawnScore[color] -= BackwardPawn; } } // Passed pawn bonus: if(pawnRank >= 7 - lastRank[enemy][fyle] && pawnRank >= 7 - lastRank[enemy][fyle - 1] && pawnRank >= 7 - lastRank[enemy][fyle + 1]) { int bonus = PassedPawnRank[pawnRank]; // Smaller bonus for rook-file or isolated passed pawns: if(fyle == 1 || fyle == 8 || isolated) { bonus = bonus * 3 / 4; } // Bigger bonus for a passed pawn protected by another pawn: if(!isolated) { if(pawnRank == firstRank[color][fyle - 1] + 1 || pawnRank == firstRank[color][fyle + 1] + 1) { bonus = (bonus * 3) / 2; } } pawnScore[color] += bonus; // Update the passed-pawn-files bitmap: fyleHasPassers[color] |= (1 << (fyle - 1)); // Give a big bonus for a connected passed pawn on // the 6th or 7th rank. if(pawnRank >= RANK_6 && pawnFiles[color][fyle - 1] > 0 && firstRank[color][fyle - 1] >= RANK_6) { // pawnScore[color] += some_bonus...; } // Check for passed pawn races in pawn endgames: if(inPawnEndgame) { // Check if the enemy king is outside the square: squareT kingSq = Pos.GetKingSquare(color_Flip(color)); squareT pawnSq = square_Make(fyle - 1, pawnRank); squareT promoSq = square_Make(fyle - 1, RANK_8); if(color == BLACK) { pawnSq = square_FlipRank(pawnSq); promoSq = square_FlipRank(promoSq); } unsigned int kingDist = square_Distance(kingSq, promoSq); unsigned int pawnDist = square_Distance(pawnSq, promoSq); if(color != Pos.GetToMove()) { pawnDist++; } if(pawnDist < kingDist) { bestRacingPawn[color] = pawnRank; } } } } } int score = pawnScore[WHITE] - pawnScore[BLACK]; pawnEntry->score = score; pawnEntry->fyleHasPassers[WHITE] = fyleHasPassers[WHITE]; pawnEntry->fyleHasPassers[BLACK] = fyleHasPassers[BLACK]; pawnEntry->wLongbShortScore = longVsShortScore[WHITE] - shortVsLongScore[BLACK]; pawnEntry->wShortbLongScore = shortVsLongScore[WHITE] - longVsShortScore[BLACK]; // If not a pawn endgame, store the score in the pawn hash table: if(!inPawnEndgame) { *hashEntry = *pawnEntry; return; } // This is a pawn endgame, so we cannot store the score in the // pawn hash table since we include king positions as a factor. // If one side has a pawn that clearly queens before the best // enemy pawn in a race (where kings cannot catch the pawns), // give a huge bonus since it almost certainly wins: if(bestRacingPawn[WHITE] > bestRacingPawn[BLACK] + 1) { pawnEntry->score += RookValue; } else if(bestRacingPawn[BLACK] > bestRacingPawn[WHITE] + 1) { pawnEntry->score -= RookValue; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::IsMatingScore // Returns true if the score indicates the side to move will checkmate. inline bool Engine::IsMatingScore(int score) { return (score > (Infinity - (int)ENGINE_MAX_PLY)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::IsGettingMatedScore // Returns true if the score indicates the side to move will be checkmated. inline bool Engine::IsGettingMatedScore(int score) { return (score < (-Infinity + (int)ENGINE_MAX_PLY)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::PlayMove // Play the specified move, not in a search. void Engine::PlayMove(simpleMoveT * sm) { PushRepeat(&RootPos); RootPos.DoSimpleMove(sm); Pos.DoSimpleMove(sm); simpleMoveT * newMove = new simpleMoveT; *newMove = *sm; GameMoves[NumGameMoves] = newMove; NumGameMoves++; // Change the transposition table sequence number: TranTableSequence++; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::RetractMove // Take back a move played in the game. void Engine::RetractMove(void) { if(NumGameMoves == 0) { return; } PopRepeat(); NumGameMoves--; RootPos.UndoSimpleMove(GameMoves[NumGameMoves]); Pos.UndoSimpleMove(GameMoves[NumGameMoves]); delete GameMoves[NumGameMoves]; TranTableSequence--; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::DoMove // Make the specified move in a search. inline void Engine::DoMove(simpleMoveT * sm) { PushRepeat(&Pos); Pos.DoSimpleMove(sm); Ply++; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::UndoMove // Take back the specified move in a search. inline void Engine::UndoMove(simpleMoveT * sm) { PopRepeat(); Pos.UndoSimpleMove(sm); Ply--; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::PushRepeat // Remember the current position on the repetition stack. inline void Engine::PushRepeat(Position * pos) { repeatT * rep = &(RepStack[RepStackSize]); rep->hash = pos->HashValue(); rep->pawnhash = pos->PawnHashValue(); rep->npieces = pos->TotalMaterial(); rep->stm = pos->GetToMove(); RepStackSize++; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::PopRepeat // Pops the last entry off the repetition stack. inline void Engine::PopRepeat(void) { ASSERT(RepStackSize > 0); RepStackSize--; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::NoMatingMaterial // Returns true if the position is a certain draw through neither // side having mating material. bool Engine::NoMatingMaterial(void) { unsigned int npieces = Pos.TotalMaterial(); // Check for K vs K, K+N vs K, and K+B vs K: if(npieces <= 2) { return true; } if(npieces == 3) { unsigned char * material = Pos.GetMaterial(); if(material[WB] == 1 || material[WN] == 1) { return true; } if(material[BB] == 1 || material[BN] == 1) { return true; } } return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::FiftyMoveDraw // Returns true if a draw has been reached through fifty full // moves since the last capture or pawn move. bool Engine::FiftyMoveDraw(void) { if(RepStackSize < 100) { return false; } unsigned int pawnhash = Pos.PawnHashValue(); unsigned int npieces = Pos.TotalMaterial(); // Go back through the stack of hash values: unsigned int plycount = 0; for(unsigned int i = RepStackSize; i > 0; i--) { repeatT * rep = &(RepStack[i - 1]); // Stop at an irreversible move: if(npieces != rep->npieces) { break; } if(pawnhash != rep->pawnhash) { break; } plycount++; } if(plycount >= 100) { return true; } return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::RepeatedPosition // Returns the number if times the current position has been reached, // with the same side to move, castling and en passant settings. // The current occurrence is included in the returned count. unsigned int Engine::RepeatedPosition(void) { unsigned int hash = Pos.HashValue(); unsigned int pawnhash = Pos.PawnHashValue(); unsigned int npieces = Pos.TotalMaterial(); colorT stm = Pos.GetToMove(); // Go back through the stack of hash values detecting repetition: unsigned int ntimes = 1; for(unsigned int i = RepStackSize; i > 0; i--) { repeatT * rep = &(RepStack[i - 1]); // Stop at an irreversible move: if(npieces != rep->npieces) { break; } if(pawnhash != rep->pawnhash) { break; } // Look for repetition: if(hash == rep->hash && stm == rep->stm) { ntimes++; } } return ntimes; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::SetHashTableKilobytes // Set the transposition table size in kilobytes. void Engine::SetHashTableKilobytes(unsigned int size) { // Compute the number of entries, which must be even: unsigned int bytes = size * 1024; TranTableSize = bytes / sizeof(transTableEntryT); if((TranTableSize % 2) == 1) { TranTableSize--; } if(TranTable != NULL) { delete[] TranTable; } TranTable = new transTableEntryT [TranTableSize]; ClearHashTable(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::SetPawnTableKilobytes // Set the pawn structure hash table size in kilobytes. void Engine::SetPawnTableKilobytes(unsigned int size) { // Compute the number of entries: unsigned int bytes = size * 1024; PawnTableSize = bytes / sizeof(pawnTableEntryT); if(PawnTable != NULL) { delete[] PawnTable; } PawnTable = new pawnTableEntryT [PawnTableSize]; ClearPawnTable(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::ClearHashTable // Clear the transposition table. void Engine::ClearHashTable(void) { for(unsigned int i = 0; i < TranTableSize; i++) { TranTable[i].flags = SCORE_NONE; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::ClearPawnTable // Clear the pawn structure hash table. void Engine::ClearPawnTable(void) { for(unsigned int i = 0; i < PawnTableSize; i++) { PawnTable[i].pawnhash = 0; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // tte_Get/Set functions // Helpers for packing/extracting transposition table entry fields. inline void tte_SetFlags(transTableEntryT * tte, scoreFlagT sflag, colorT stm, unsigned char castling, bool isOnlyMove) { tte->flags = (castling << 4) | (stm << 3) | (isOnlyMove ? 4 : 0) | sflag; } inline scoreFlagT tte_ScoreFlag(transTableEntryT * tte) { return (tte->flags & 7); } inline colorT tte_SideToMove(transTableEntryT * tte) { return ((tte->flags >> 3) & 1); } inline unsigned char tte_Castling(transTableEntryT * tte) { return (tte->flags >> 4); } inline bool tte_IsOnlyMove(transTableEntryT * tte) { return (((tte->flags >> 2) & 1) == 1); } inline void tte_SetBestMove(transTableEntryT * tte, simpleMoveT * bestMove) { ASSERT(bestMove->from <= H8 && bestMove->to <= H8); unsigned short bm = bestMove->from; bm <<= 6; bm |= bestMove->to; bm <<= 4; bm |= bestMove->promote; tte->bestMove = bm; } inline void tte_GetBestMove(transTableEntryT * tte, simpleMoveT * bestMove) { unsigned short bm = tte->bestMove; bestMove->promote = bm & 15; bm >>= 4; bestMove->to = bm & 63; bm >>= 6; bestMove->from = bm & 63; } static unsigned int ProbeCounts[4] = {0}; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::StoreHash // Store the score for the current position in the transposition table. void Engine::StoreHash(int depth, scoreFlagT ttFlag, int score, simpleMoveT * bestMove, bool isOnlyMove) { if(TranTableSize == 0) { return; } ASSERT(ttFlag <= SCORE_UPPER); unsigned int hash = Pos.HashValue(); unsigned int pawnhash = Pos.PawnHashValue(); colorT stm = Pos.GetToMove(); if(stm == BLACK) { hash = ~hash; } // Find the least useful (lowest depth) of two entries to replace // but replace the previous entry for this position if it exists // and use an empty hash table entry if possible: unsigned int ttSlot = (hash % TranTableSize) & 0xFFFFFFFEU; ASSERT(ttSlot < TranTableSize - 1); transTableEntryT * ttEntry1 = &(TranTable[ttSlot]); transTableEntryT * ttEntry2 = &(TranTable[ttSlot + 1]); bool replacingSameEntry = false; transTableEntryT * ttEntry; if(ttEntry1->hash == hash && ttEntry1->pawnhash == pawnhash) { ttEntry = ttEntry1; // Replace this existing entry. replacingSameEntry = true; } else if(ttEntry2->hash == hash && ttEntry2->pawnhash == pawnhash) { ttEntry = ttEntry2; // Replace this existing entry. replacingSameEntry = true; } else if(tte_ScoreFlag(ttEntry1) == SCORE_NONE) { ttEntry = ttEntry1; // Use this empty entry. } else if(tte_ScoreFlag(ttEntry2) == SCORE_NONE) { ttEntry = ttEntry2; // Use this empty entry. } else { // Replace the entry with the shallower depth, unless the deeper // entry has an old sequence number: transTableEntryT * ttDeeper = ttEntry1; transTableEntryT * ttShallower = ttEntry2; if(ttEntry1->depth < ttEntry2->depth) { ttDeeper = ttEntry2; ttShallower = ttEntry1; } if(ttShallower->sequence != TranTableSequence) { ttEntry = ttShallower; // Replace this old entry } else if(ttDeeper->sequence != TranTableSequence) { ttEntry = ttDeeper; // Replace this old entry } else { ttEntry = ttShallower; // Replace this shallow entry } } if(replacingSameEntry) { if(depth < ttEntry->depth) { // Do not overwrite an existing better entry for the same // position; but if there was no move, add one: if(ttEntry->bestMove == 0 && bestMove != NULL) { tte_SetBestMove(ttEntry, bestMove); } return; } if(depth == ttEntry->depth) { // Do not replace an exact score entry of the same depth for // the same position with an inexact entry: if(tte_ScoreFlag(ttEntry) == SCORE_EXACT && ttFlag != SCORE_EXACT) { return; } } } // Convert mating scores to include the current Ply count: if(IsMatingScore(score)) { score += Ply; } if(IsGettingMatedScore(score)) { score -= Ply; } // Fill in the hash entry fields: ttEntry->hash = hash; ttEntry->pawnhash = pawnhash; ttEntry->depth = depth; ttEntry->score = score; tte_SetFlags(ttEntry, ttFlag, stm, Pos.GetCastlingFlags(), isOnlyMove); ttEntry->sequence = TranTableSequence; ttEntry->bestMove = 0; if(bestMove != NULL) { ASSERT(bestMove->movingPiece != EMPTY); ASSERT(piece_Color(bestMove->movingPiece) == stm); ASSERT(bestMove->from <= H8); tte_SetBestMove(ttEntry, bestMove); } ttEntry->enpassant = Pos.GetEPTarget(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::ProbeHash // Probe the transposition table for the current position. // scoreFlagT Engine::ProbeHash(int depth, int * score, simpleMoveT * bestMove, bool * isOnlyMove) { // Clear the best move: if(bestMove != NULL) { bestMove->from = bestMove->to = NULL_SQUARE; } if(TranTableSize == 0) { return SCORE_NONE; } unsigned int hash = Pos.HashValue(); colorT stm = Pos.GetToMove(); if(stm == BLACK) { hash = ~hash; } // Examine the corresponding pair of table entries: unsigned int ttSlot = (hash % TranTableSize) & 0xFFFFFFFEU; ASSERT(ttSlot + 1 < TranTableSize); transTableEntryT * ttEntry = &(TranTable[ttSlot]); if(ttEntry->hash != hash) { ttEntry++; } if(ttEntry->hash != hash) { return SCORE_NONE; } if(tte_ScoreFlag(ttEntry) == SCORE_NONE) { return SCORE_NONE; } unsigned int pawnhash = Pos.PawnHashValue(); if(ttEntry->pawnhash != pawnhash) { return SCORE_NONE; } if(tte_SideToMove(ttEntry) != stm) { return SCORE_NONE; } if(tte_Castling(ttEntry) != Pos.GetCastlingFlags()) { return SCORE_NONE; } if(ttEntry->enpassant != Pos.GetEPTarget()) { return SCORE_NONE; } // If a hash move is stored, we return it even if the depth is not // sufficient, because it will be useful for move ordering anyway. if(bestMove != NULL && ttEntry->bestMove != 0) { tte_GetBestMove(ttEntry, bestMove); pieceT * board = Pos.GetBoard(); bestMove->movingPiece = board[bestMove->from]; } if(isOnlyMove != NULL) { *isOnlyMove = tte_IsOnlyMove(ttEntry); } // Only return an exact or bounded score if the stored depth is at // least as large as the requested depth: if(ttEntry->depth < depth) { return SCORE_NONE; } if(score != NULL) { *score = ttEntry->score; // Convert mating scores to exclude the current Ply count: if(IsMatingScore(*score)) { *score -= Ply; } if(IsGettingMatedScore(*score)) { *score += Ply; } } return tte_ScoreFlag(ttEntry); } static unsigned int nFailHigh = 0; static unsigned int nFailHighFirstMove = 0; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::SetPosition // Set the current position. If the new position parameter // is NULL, the standard starting position is used. void Engine::SetPosition(Position * newpos) { // Delete old game moves: for(unsigned int i = 0; i < NumGameMoves; i++) { delete GameMoves[i]; } NumGameMoves = 0; // Set the position: if(newpos == NULL) { RootPos.StdStart(); Pos.StdStart(); } else { RootPos.CopyFrom(newpos); Pos.CopyFrom(newpos); } // Clear the repetition stack: RepStackSize = 0; // Clear the PV: PV[0].length = 0; // Change the tranposition table sequence number so existing // entries can be detected as old ones: TranTableSequence++; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::Think // Initiate a search from the current position. If the supplied // move list is NULL, generate and examine all legal moves at the // root position. However, if the move list is not NULL, it // contains a subset of the legal moves to be analyzed. // // Returns the score (in centipawns, for the side to move) and // reorders the move list (if supplied) so the best move is at // the start of the list. int Engine::Think(MoveList * mlist) { Elapsed.restart(); NodeCount = 0; QNodeCount = 0; Ply = 0; IsOutOfTime = false; EasyMove = false; HardMove = false; InNullMove = 0; SetPVLength(); ClearKillerMoves(); ClearHistoryValues(); // If no legal move list was specified, generate and search all moves: if(mlist == NULL || !mlist->Size()) { Pos.GenerateMoves(); mlist = Pos.GetLegalMoves(); } // No legal moves? Return 0 for stalemate, -Infinity for checkmate. if(mlist->Size() == 0) { return (Pos.IsKingInCheck() ? -Infinity : 0); } // Sort the root move list by quiescent evaluation to get a // reasonably good initial move order: for(unsigned int i = 0; i < mlist->Size(); i++) { simpleMoveT * sm = mlist->Get(i); DoMove(sm); sm->score = -Quiesce(-Infinity, Infinity); UndoMove(sm); } mlist->Sort(); // Check for an easy move, one that scores more than two pawns // better than any alternative: if(mlist->Size() > 1) { int margin = mlist->Get(0)->score - mlist->Get(1)->score; if(margin > (2 * PawnValue)) { // Output ("Easy move: margin = %d\n", margin); EasyMove = true; } } int bestScore = -Infinity; // Do iterative deepening starting at depth 1, until out of // time or the maximum depth is reached: for(unsigned int depth = 1; depth <= MaxDepth; depth++) { HardMove = false; // If we have searched at least a few ply, and there is less // than 30% of the recommended search time remaining, then // continuing the search is unlikely to be useful since it // will probably spend all remaining time on the first move: if(depth > 4) { double used = (double)Elapsed.elapsed() / (double)SearchTime; if(used > 0.7) { break; } } // Set up the alpha-beta range. For all but the first depth, // use a small aspiration window around the previous score // since we do not expect the score to change much: int alpha = -Infinity - 1; int beta = Infinity + 1; if(depth > 1) { alpha = bestScore - AspirationWindow; beta = bestScore + AspirationWindow; } int score = SearchRoot(depth, alpha, beta, mlist); if(OutOfTime()) { break; } if(score >= beta) { // Aspiration window fail-high: PrintPV(depth, score, "++"); alpha = score - 1; beta = Infinity + 1; score = SearchRoot(depth, alpha, beta, mlist); } else if(score <= alpha) { // Aspiration window fail-low: PrintPV(depth, score, "--"); EasyMove = false; HardMove = true; alpha = -Infinity - 1; beta = score + 1; score = SearchRoot(depth, alpha, beta, mlist); } if(OutOfTime()) { break; } // If the 2nd search failed, try again with an infinite window. // This is rare, but can happen with hashing/null-move effects. if(score < alpha || score > beta) { alpha = -Infinity; beta = Infinity; EasyMove = false; HardMove = true; score = SearchRoot(depth, alpha, beta, mlist); } if(OutOfTime()) { break; } bestScore = score; PrintPV(depth, bestScore, ">>>"); // Stop if checkmate has been found, but not too soon: if(depth >= 5 && IsMatingScore(bestScore)) { break; } // Make sure the first move in the list remains there by // giving it a huge node count for its move ordering score: mlist->Get(0)->score = 1 << 30; // Sort the move list based on node counts from this iteration: mlist->Sort(); } // Statistics for debugging: // Output ("Hash probes: Exact:%u Upper:%u Lower:%u None:%u\n", // ProbeCounts[SCORE_EXACT], ProbeCounts[SCORE_UPPER], // ProbeCounts[SCORE_LOWER], ProbeCounts[SCORE_NONE]); // Output ("Fail-High first move: %u / %u = %f\n", nFailHighFirstMove, nFailHigh, // (double)nFailHighFirstMove * 100.0 / (double)nFailHigh); // Output ("Pawn hash hits: %u / %u = %f\n", nPawnHashHits, nPawnHashProbes, // (double)nPawnHashHits * 100.0 / (double)nPawnHashProbes); // Output ("Full scores: %u / %u = %f\n", nScoreFull, nScoreCalls, // (double)nScoreFull * 100.0 / (double) nScoreCalls); return bestScore; } int Engine::SearchRoot(int depth, int alpha, int beta, MoveList * mlist) { ASSERT(depth >= 1); // If no legal move list was specified, generate and search all moves: if(mlist == NULL) { Pos.GenerateMoves(); mlist = Pos.GetLegalMoves(); } // No legal moves to search? Just return an equal score for // stalemate or -Infinity for checkmate. if(mlist->Size() == 0) { return (Pos.IsKingInCheck() ? -Infinity : 0); } bool isOnlyMove = (mlist->Size() == 1); int bestScore = -Infinity - 1; for(unsigned int movenum = 0; movenum < mlist->Size(); movenum++) { simpleMoveT * sm = mlist->Get(movenum); unsigned int oldNodeCount = NodeCount; // Make this move and search it: DoMove(sm); InCheck[Ply] = Pos.IsKingInCheck(sm); #define PVS_SEARCH #ifdef PVS_SEARCH int score = alpha; if(movenum == 0) { score = -Search(depth - 1, -beta, -alpha, true); } else { // Do a minimal window search first, to try and quickly // identify the common case of a move not being good // enough to improve alpha: score = -Search(depth - 1, -alpha - 1, -alpha, true); if(score > alpha && score < beta) { // This move is good enough to search with the proper // window; use the score it returned as the lower bound: score = -Search(depth - 1, -beta, -score, true); } } #else int score = -Search(depth - 1, -beta, -alpha, true); #endif UndoMove(sm); if(OutOfTime()) { break; } // Set the move ordering score of this move to be the number of // nodes spent on it, so interesting moves of this iteration are // searched first at the next iteration depth: sm->score = NodeCount - oldNodeCount; // If this is the first move searched at this depth or // a new best move, update the best score and promote // the move to be first in the list: if(movenum == 0 || score > bestScore) { bestScore = score; alpha = score; UpdatePV(sm); PrintPV(depth, bestScore); StoreHash(depth, SCORE_EXACT, score, sm, isOnlyMove); mlist->MoveToFront(movenum); if(movenum > 0) { EasyMove = false; } } } return bestScore; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::Search // Internal Search routine, used at every depth except // the root position. int Engine::Search(int depth, int alpha, int beta, bool tryNullMove) { SetPVLength(); // If there is no remaining depth, return a qiuescent evaluation: if(depth <= 0) { return Quiesce(alpha, beta); } // Check that the absolute depth limit is not exceeded: if(Ply >= ENGINE_MAX_PLY - 1) { return alpha; } // Check for a drawn position (no mating material, repetition, etc): if(NoMatingMaterial()) { return 0; } if(FiftyMoveDraw()) { return 0; } unsigned int repeats = RepeatedPosition(); if(repeats >= 3 || (repeats == 2 && Ply > 2)) { return 0; } colorT toMove = Pos.GetToMove(); NodeCount++; // Stop now if we ran out of time: if(OutOfTime()) { return alpha; } // Check for a recognized endgame score: if(Pos.TotalMaterial() <= Recognizer::MaxPieces()) { int recog = Recognizer::Recognize(&Pos); int rscore = recogScore(recog); scoreFlagT rflag = recogFlag(recog); if(rflag == SCORE_EXACT) { return rscore; } else if(rflag == SCORE_LOWER) { if(rscore >= beta) { return rscore; } if(rscore < alpha) { alpha = rscore; } } else if(rflag == SCORE_UPPER) { if(rscore <= alpha) { return rscore; } if(rscore > beta) { beta = rscore; } } } // Probe the hash table: int hashscore = alpha; simpleMoveT hashmove; bool isOnlyMove; scoreFlagT hashflag = ProbeHash(depth, &hashscore, &hashmove, &isOnlyMove); ProbeCounts[hashflag]++; switch(hashflag) { case SCORE_NONE: break; case SCORE_LOWER: if(hashscore >= beta) { return hashscore; } if(hashscore > alpha) { alpha = hashscore; } break; case SCORE_UPPER: if(hashscore <= alpha) { return hashscore; } if(hashscore < beta) { beta = hashscore; } break; case SCORE_EXACT: if(hashscore > alpha && hashscore < beta) { UpdatePV(&hashmove); } return hashscore; } int baseExtensions = 0; bool inCheck = InCheck[Ply]; // Null move pruning: // If the side to move has at least a few pieces (to reduce the risk // of zugzwang) and is not in check, and a null move was not made to // reach this point in the search, try making a null move now. The // idea is to pass on our move and see (with a shallow search) if // if the enemy has any move that can score better than the beta // cutoff. If they have no such move, it means our position is good // enough to cut off the search without even considering our own // possible moves. if(inCheck || depth < 2 || Pos.NumNonPawns(toMove) < 3) { tryNullMove = false; } if(tryNullMove) { Pos.SetToMove(color_Flip(toMove)); squareT oldEPTarget = Pos.GetEPTarget(); Pos.SetEPTarget(NULL_SQUARE); // We keep track of whether we are in a null move search or // not, to avoid updating the PV. InNullMove++; // Do an R=2 or R=3 nullmove search, depending on remaining depth: int nulldepth = depth - NullMoveReduction; if(depth > 6) { nulldepth--; // An R=3 null move search. } int nullscore = -Search(nulldepth - 1, -beta, -beta + 1, false); InNullMove--; Pos.SetEPTarget(oldEPTarget); Pos.SetToMove(toMove); // If the null-move score is better than beta, cut the search: if(nullscore >= beta) { return beta; } // If the null-move score indicates that making a null move // would lead to us getting mated, extend the search another // ply to try and avoid the mate threats: if(IsGettingMatedScore(nullscore)) { baseExtensions++; } } // In-check extension: search one ply deeper if we are in check. if(inCheck) { baseExtensions++; } // Now we want to generate all legal moves and order them. But if // we got a move from the hash table, it is worth trying that move // first, and only generating and scoring the rest of the moves if // the hash move does not cause a beta cutoff. // Note that we already know whether the side to move is in check, // so we pass this information to GenerateMoves to speed it up. MoveList mlist; bool gotHashMove; if(Pos.IsLegalMove(&hashmove)) { gotHashMove = true; // For now, we only add the hash move to the move list. mlist.Add(&hashmove); mlist.Get(0)->score = ENGINE_HASH_SCORE; } else { // No hash table move, so generate and score all the moves now. gotHashMove = false; Pos.GenerateMoves(&mlist, EMPTY, GEN_ALL_MOVES, InCheck[Ply]); ScoreMoves(&mlist); isOnlyMove = (mlist.Size() == 1); } // If there is only one legal move, extend the search: if(isOnlyMove) { baseExtensions++; } // Remember the original alpha score: int oldAlpha = alpha; int bestMoveIndex = -1; // Search each move: for(unsigned int movenum = 0; movenum < mlist.Size(); movenum++) { // Find the highest-scoring remaining move: mlist.FindBest(movenum); simpleMoveT * sm = mlist.Get(movenum); // Move-specific extensions: int extensions = baseExtensions; // If moving a pawn to the 7th or 8th rank, extend the search: if(piece_Type(sm->movingPiece) == PAWN) { rankT rank = square_Rank(sm->to); if(rank <= RANK_2 || rank >= RANK_7) { extensions++; } } // Reduce extensions if the search is deep: if(extensions > 0 && (int)Ply >= depth + depth) { extensions /= 2; } // Limit extensions to one ply (only if deep enough?): if(extensions > 1 /*&& (int)Ply >= depth*/) { extensions = 1; } // Make this move and remember if it gives check: DoMove(sm); InCheck[Ply] = Pos.IsKingInCheck(sm); // Simple futility pruning. Note that pruning with depth of two // remaining is risky, but seems to work well enough in practise. // We only prune when: // (1) there are no extensions, // (2) we are at ply 3 or deeper, // (3) the move made does not give check, // (4) the score does not indicate mate, // (5) the move is not the only legal move, and // (6) we are not in a pawn ending. if(Pruning && extensions == 0 && Ply > 2 && depth <= 2 && !InCheck[Ply] && !IsMatingScore(alpha) && !isOnlyMove && Pos.NumNonPawns(WHITE) > 1 && Pos.NumNonPawns(BLACK) > 1) { int mscore = -ScoreMaterial(); bool futile = false; if(depth == 1) { // Futility pruning, when 2 pawns below alpha: futile = ((mscore + (PawnValue * 2)) < alpha); } else if(depth == 2) { // Extended futility pruning, when a rook below alpha: futile = ((mscore + RookValue) < alpha); } // Skip this move if it is futile: if(futile) { UndoMove(sm); continue; } } #define PVS_SEARCH #ifdef PVS_SEARCH // We do a normal search for the first move, but for all other // moves we try a minimal window search first to save time: int score = alpha; if(movenum == 0) { score = -Search(depth + extensions - 1, -beta, -alpha, true); } else { score = -Search(depth + extensions - 1, -alpha - 1, -alpha, true); if(score > alpha && score < beta) { // This move is good enough to search with the proper // window; use the score it returned as the lower bound: score = -Search(depth + extensions - 1, -beta, -score, true); } } #else // No PVS, just do a regular search at every move: int score = -Search(depth + extensions - 1, -beta, -alpha, true); #endif UndoMove(sm); // If this move scored at least as good as beta, we have // "failed high" so there is no need to continue searching // for an even better move: if(score >= beta) { IncHistoryValue(sm, depth * depth); AddKillerMove(sm); StoreHash(depth, SCORE_LOWER, score, sm, isOnlyMove); // Fail-high-first-move stats: nFailHigh++; if(movenum == 0) { nFailHighFirstMove++; } return beta; } // If this move is better than the alpha score, it is a new // best move at this point in the search tree. Update the PV // (and boost the history value of the move a little? - no): if(score > alpha) { alpha = score; bestMoveIndex = movenum; UpdatePV(sm); // IncHistoryValue (sm, depth); } // All done with that move. If it was the first move in the list and // it was the move from the hashtable, then the remaining moves have // not been generated and scored for move ordering. We do that now, // ensuring that the hash table move we just examined is moved to // the start of the list so it does not get searched again. if(movenum == 0 && gotHashMove && !isOnlyMove) { mlist.Clear(); Pos.GenerateMoves(&mlist, EMPTY, GEN_ALL_MOVES, InCheck[Ply]); ScoreMoves(&mlist); int hashIndex = mlist.Find(&hashmove); if(hashIndex >= 0) { mlist.SwapWithFirst(hashIndex); } else { // The hash table move was legal, but not found in the // move list -- Bizzare! Output("# Yikes! Hash table move not in move list! Bug?\n"); } } } if(mlist.Size() == 0) { // No legal moves? Must be checkmate or stalemate: return (InCheck[Ply] ? (-Infinity + Ply) : 0); } // If alpha did not get improved, we "failed low"; every move // scored worse than our lower bound. // Store alpha in the transposition table as an upper bound on // the true score of this position, with no best move. if(alpha == oldAlpha) { ASSERT(bestMoveIndex < 0); StoreHash(depth, SCORE_UPPER, alpha, NULL, isOnlyMove); } else { // Update the transposition table with the best move: ASSERT(bestMoveIndex >= 0); simpleMoveT * bestMove = mlist.Get(bestMoveIndex); IncHistoryValue(bestMove, depth * depth); // Should we also add this as a killer move? Possibly not, // since it was not good enough to cause a beta cutoff. // It seems to make little difference. AddKillerMove(bestMove); StoreHash(depth, SCORE_EXACT, alpha, bestMove, isOnlyMove); } return alpha; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::Quiesce // Search only captures until a stable position is reached // that can be evaluated. int Engine::Quiesce(int alpha, int beta) { NodeCount++; QNodeCount++; // Check that the absolute depth limit is not exceeded: if(Ply >= ENGINE_MAX_PLY - 1) { return alpha; } SetPVLength(); // Stop now if we are out of time: if(OutOfTime()) { return alpha; } // Check for a recognized endgame score: if(Pos.TotalMaterial() <= Recognizer::MaxPieces()) { int recog = Recognizer::Recognize(&Pos); int rscore = recogScore(recog); scoreFlagT rflag = recogFlag(recog); if(rflag == SCORE_EXACT) { return rscore; } else if(rflag == SCORE_LOWER) { if(rscore >= beta) { return rscore; } if(rscore < alpha) { alpha = rscore; } } else if(rflag == SCORE_UPPER) { if(rscore <= alpha) { return rscore; } if(rscore > beta) { beta = rscore; } } } // Find the static evaluation of this position, to either cause // a beta cutoff or improve the alpha score: int staticScore = Score(alpha, beta); if(staticScore >= beta) { return beta; } if(staticScore > alpha) { alpha = staticScore; } // Check for a static score so far below alpha that no capture // is going to be good enough anyway: int margin = PawnValue; if(staticScore + QueenValue + margin < alpha) { return alpha; } // Generate and score the list of captures: MoveList mlist; Pos.GenerateMoves(&mlist, GEN_CAPTURES); for(unsigned int m = 0; m < mlist.Size(); m++) { simpleMoveT * sm = mlist.Get(m); sm->score = SEE(sm->from, sm->to); } // Iterate through each quiescent move to find a beta cutoff or // improve the alpha score: for(unsigned int i = 0; i < mlist.Size(); i++) { // Find the highest-scoring remaining move, make it and search: mlist.FindBest(i); simpleMoveT * sm = mlist.Get(i); pieceT promote = piece_Type(sm->promote); // Skip underpromotions: if(promote != EMPTY && promote != QUEEN) { continue; } // Stop if the capture gain is negative or is so small that it // will (very likely) not improve alpha: if(sm->score < 0) { break; } if((sm->score + staticScore + margin) < alpha) { break; } // Make the move and evaluate it: DoMove(sm); int score = -Quiesce(-beta, -alpha); UndoMove(sm); // Check for a score so good it causes a beta cutoff: if(score >= beta) { return score; } // See if we have a new best move: if(score > alpha) { alpha = score; UpdatePV(sm); } } return alpha; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::SEE // Static Exchange Evaluator. // Evaluates the approximate material result of moving the piece // from the from square (which must not be empty) to the target // square (which may be empty or may hold an enemy piece). int Engine::SEE(squareT from, squareT target) { const pieceT * board = Pos.GetBoard(); SquareList attackers[2]; pieceT mover = piece_Type(board[from]); ASSERT(mover != EMPTY); colorT stm = piece_Color_NotEmpty(board[from]); #define SEE_ADD(c,sq) attackers[(c)].Add(sq) // Currently the SEE method is only called for legal moves, so if // the moving piece is a king then it clearly cannot be captured. // If potentially illegal king moves are to be passed to this // method, the following optimisation should be removed. if(mover == KING) { return PieceValue(board[target]); } // Find the estimated result assuming one recapture: int fastResult = PieceValue(board[target]) - PieceValue(mover); // We can do quick estimation for a big gain, but have to be // careful since move ordering is very sensitive to positive SEE // scores. Only return a fast estimate for PxQ, NxQ, BxQ and PxR: if(fastResult > KnightValue && mover != ROOK) { return fastResult; } // Add attacking pawns to the attackers list: squareT pawnSq = square_Move(target, DOWN_LEFT); if(board[pawnSq] == WP && pawnSq != from) { SEE_ADD(WHITE, pawnSq); } pawnSq = square_Move(target, DOWN_RIGHT); if(board[pawnSq] == WP && pawnSq != from) { SEE_ADD(WHITE, pawnSq); } pawnSq = square_Move(target, UP_LEFT); if(board[pawnSq] == BP && pawnSq != from) { SEE_ADD(BLACK, pawnSq); } pawnSq = square_Move(target, UP_RIGHT); if(board[pawnSq] == BP && pawnSq != from) { SEE_ADD(BLACK, pawnSq); } // Quick estimation for a nonpawn capturing a lesser-valued piece (or // moving to an empty square) which is defended by an enemy pawn. if(fastResult < -PawnValue && attackers[color_Flip(stm)].Size() > 0) { return fastResult; } // Add attacking knights. Only bother searching for them if there // are any knights on the appropriate square color. colorT knightSquareColor = color_Flip(square_Color(target)); unsigned int nEligibleKnights = Pos.SquareColorCount(WN, knightSquareColor) + Pos.SquareColorCount(BN, knightSquareColor); if(nEligibleKnights > 0) { const squareT * nextKnightSq = knightAttacks[target]; while(true) { squareT dest = *nextKnightSq; if(dest == NULL_SQUARE) { break; } nextKnightSq++; pieceT p = board[dest]; if(piece_Type(p) != KNIGHT) { continue; } if(dest == from) { continue; } // Quick estimate when this recapture ensures a negative result: colorT knightColor = piece_Color_NotEmpty(p); if(fastResult < -KnightValue && knightColor != stm) { return fastResult + KnightValue / 2; } SEE_ADD(knightColor, dest); } } // Add the first sliding attackers in each direction. Others // may appear later as appropriate, when the piece in front // of them takes part in the capture sequence. // First make an array containing all the directions that contain // potential sliding attackers, to avoid searching useless directions. rankT rank = square_Rank(target); fyleT fyle = square_Fyle(target); leftDiagT ul = square_LeftDiag(target); rightDiagT ur = square_RightDiag(target); unsigned int rankCount = Pos.RankCount(WQ, rank) + Pos.RankCount(BQ, rank) + Pos.RankCount(WR, rank) + Pos.RankCount(BR, rank); unsigned int fyleCount = Pos.FyleCount(WQ, fyle) + Pos.FyleCount(BQ, fyle) + Pos.FyleCount(WR, fyle) + Pos.FyleCount(BR, fyle); unsigned int upLeftCount = Pos.LeftDiagCount(WQ, ul) + Pos.LeftDiagCount(BQ, ul) + Pos.LeftDiagCount(WB, ul) + Pos.LeftDiagCount(BB, ul); unsigned int upRightCount = Pos.RightDiagCount(WQ, ur) + Pos.RightDiagCount(BQ, ur) + Pos.RightDiagCount(WB, ur) + Pos.RightDiagCount(BB, ur); // If the moving piece is a slider, it is worth removing it from the // rank/file/diagonal counts because we will avoid searching two // directions if it is the only slider on its rank/file/diagonal. if(piece_IsSlider(mover)) { if(square_Rank(from) == square_Rank(target)) { rankCount--; } else if(square_Fyle(from) == square_Fyle(target)) { fyleCount--; } else if(square_LeftDiag(from) == square_LeftDiag(target)) { upLeftCount--; } else { ASSERT(square_RightDiag(from) == square_RightDiag(target)); upRightCount--; } } // Build the list of directions with potential sliding capturers: unsigned int nDirs = 0; directionT sliderDir[8]; if(rankCount > 0) { sliderDir[nDirs++] = LEFT; sliderDir[nDirs++] = RIGHT; } if(fyleCount > 0) { sliderDir[nDirs++] = UP; sliderDir[nDirs++] = DOWN; } if(upLeftCount > 0) { sliderDir[nDirs++] = UP_LEFT; sliderDir[nDirs++] = DOWN_RIGHT; } if(upRightCount > 0) { sliderDir[nDirs++] = UP_RIGHT; sliderDir[nDirs++] = DOWN_LEFT; } // Iterate over each direction, looking for an attacking slider: for(unsigned int dirIndex = 0; dirIndex < nDirs; dirIndex++) { directionT dir = sliderDir[dirIndex]; squareT dest = target; squareT last = square_Last(target, dir); int delta = direction_Delta(dir); unsigned int distance = 0; while(dest != last) { dest += delta; distance++; pieceT p = board[dest]; if(p == EMPTY) { continue; } if(dest == from) { continue; } pieceT ptype = piece_Type(p); if(ptype == PAWN) { // Look through this pawn if it was also a capturer. if(distance != 1) { break; } if(p == WP) { if(dir == DOWN_LEFT || dir == DOWN_RIGHT) { continue; } } else { if(dir == UP_LEFT || dir == UP_RIGHT) { continue; } } break; } if(! piece_IsSlider(ptype)) { break; } if(ptype == ROOK && direction_IsDiagonal(dir)) { break; } if(ptype == BISHOP && !direction_IsDiagonal(dir)) { break; } colorT c = piece_Color_NotEmpty(p); // Quick estimate when this recapture ensures a negative result: if(fastResult < -BishopValue && ptype == BISHOP) { if(c != stm) { return fastResult + BishopValue / 2; } } else if(fastResult < -RookValue && ptype == ROOK) { if(c != stm) { return fastResult + RookValue / 2; } } // OK, we have a sliding attacker. Add it: SEE_ADD(c, dest); break; } } // Add one capturing king if the other king cannot capture: squareT wk = Pos.GetKingSquare(WHITE); squareT bk = Pos.GetKingSquare(BLACK); if(wk != from && bk != from) { bool wkAttacks = square_Adjacent(target, wk); bool bkAttacks = square_Adjacent(target, bk); if(wkAttacks && !bkAttacks) { SEE_ADD(WHITE, wk); } else if(bkAttacks && !wkAttacks) { SEE_ADD(BLACK, bk); } } // Now go through the attack lists (which may get hidden sliders added // as sliding pieces make captures) finding the best capture sequence. bool targetIsPromoSquare = (target <= H1 || target >= A8); int swaplist[32]; unsigned int nswaps = 1; swaplist[0] = PieceValue(board[target]); int attackedVal = PieceValue(mover); // Adjust the swap value for a promotion: if(targetIsPromoSquare && attackedVal == PawnValue) { swaplist[0] += QueenValue - PawnValue; attackedVal = QueenValue; } // Add as many captures to the sequence as possible, using // lowest-valued pieces first: while(true) { // Switch to the other side: stm = color_Flip(stm); SquareList * attackList = &(attackers[stm]); unsigned int attackCount = attackList->Size(); // Has this side run out of pieces to capture with? if(attackCount == 0) { break; } // Find the best (lowest-valued) piece to capture with: unsigned int bestIndex = 0; squareT attackSquare = attackList->Get(0); int attackValue = PieceValue(board[attackSquare]); for(unsigned int i = 1; i < attackCount; i++) { if(attackValue == PawnValue) { break; } squareT newSquare = attackList->Get(i); int newValue = PieceValue(board[newSquare]); if(newValue < attackValue) { attackSquare = newSquare; attackValue = newValue; bestIndex = i; } } pieceT attackPiece = piece_Type(board[attackSquare]); // Update the swap list: swaplist[nswaps] = -swaplist[nswaps - 1] + attackedVal; nswaps++; attackedVal = attackValue; // Fudge the value for a promotion, turning the pawn into a queen: if(targetIsPromoSquare && attackValue == PawnValue) { swaplist[nswaps - 1] += QueenValue - PawnValue; attackedVal = QueenValue; } // Remove the chosen attacker from the list: attackList->Remove(bestIndex); // If the attacker is a slider, look for another slider behind it: if(piece_IsSlider(attackPiece)) { directionT dir = sqDir[target][attackSquare]; ASSERT(dir != NULL_DIR); squareT dest = attackSquare; squareT last = square_Last(dest, dir); int delta = direction_Delta(dir); while(dest != last) { dest += delta; pieceT p = board[dest]; if(p == EMPTY) { continue; } pieceT pt = piece_Type(p); if(! piece_IsSlider(pt)) { break; } if(pt == ROOK && direction_IsDiagonal(dir)) { break; } if(pt == BISHOP && !direction_IsDiagonal(dir)) { break; } // OK, we have another sliding attacker. Add it: SEE_ADD(piece_Color_NotEmpty(p), dest); break; } } } // Finally, go backwards through the swap list and determine when one // side would stop because further exchanges would be useless: nswaps--; while(nswaps > 0) { unsigned int prev = nswaps - 1; if(swaplist[nswaps] > -swaplist[prev]) { swaplist[prev] = -swaplist[nswaps]; } nswaps--; } return swaplist[0]; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::ScoreMoves // Gives each move in the specified move list a score for move // ordering. Captures are scored using static exchange evaluation // while non-capture scores are based on killer move and history // heuristic information. Promotions are treated as captures. // The ordering has four basic categories: // (1) Non-losing captures (ordered by SEE value, score >= EMH * 2); // (2) Non-capture killer moves (EMH <= score < 2 * EMH); // (3) Other non-captures (by history heuristic, 0 <= score < EMH); // (4) Losing captures (ordered by SEE value, score < 0). // where EMH = ENGINE_MAX_HISTORY is the history value threshold. void Engine::ScoreMoves(MoveList * mlist) { for(unsigned int i = 0; i < mlist->Size(); i++) { simpleMoveT * sm = mlist->Get(i); if(sm->capturedPiece != EMPTY || sm->promote != EMPTY) { int see = SEE(sm->from, sm->to); if(see >= 0) { sm->score = ENGINE_MAX_HISTORY * 2 + see; } else { sm->score = see; } } else { // Non-capture; just use the history/killer value for this move. sm->score = GetHistoryValue(sm); if(IsKillerMove(sm)) { sm->score += ENGINE_MAX_HISTORY; } } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::Output // Prints a formatted string (as passed to printf) to standard output // and the the log file if one is being used. void Engine::Output(const char * format, ...) { va_list ap; va_start(ap, format); vprintf(format, ap); if(LogFile != NULL) { vfprintf(LogFile, format, ap); } va_end(ap); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::PrintPV // Print the current depth, score and principal variation. void Engine::PrintPV(unsigned int depth, int score, const char * note) { if(! PostInfo) { return; } unsigned int ms = Elapsed.elapsed(); if(XBoardMode && ms < 50 && Ply < 6) { return; } if(XBoardMode) { Output(" %2u %6d %5u %9u ", depth, score, ms / 10, NodeCount); } else { Output(" %2u %-3s %+6d %5u %9u ", depth, note, score, ms, NodeCount); } principalVarT * pv = &(PV[0]); unsigned int i; if(Pos.GetToMove() == BLACK) { Output("%u...", Pos.GetFullMoveCount()); } // Make and print each PV move: for(i = 0; i < pv->length; i++) { simpleMoveT * sm = &(pv->move[i]); // Check for legality, to protect against hash table // false hits and bugs in PV updating: if(! Pos.IsLegalMove(sm)) { Output(" "); break; } if(i > 0) { Output(" "); } if(Pos.GetToMove() == WHITE) { Output("%u.", Pos.GetFullMoveCount()); } char s[10]; Pos.MakeSANString(sm, s, SAN_MATETEST); Output("%s", s); Pos.DoSimpleMove(sm); } Output("\n"); // Undo each PV move that was made: for(; i > 0; i--) { Pos.UndoSimpleMove(&(pv->move[i - 1])); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::OutOfTime // Returns true if the search time limit has been reached. // "Out Of Time" is also the name of a great R.E.M. album. :-) bool Engine::OutOfTime() { if(IsOutOfTime) { return true; } // Only check the time approximately every 1000 nodes for speed: if((NodeCount & 1023) != 0) { return false; } int ms = Elapsed.elapsed(); if(EasyMove) { IsOutOfTime = (ms > MinSearchTime); } else if(HardMove) { IsOutOfTime = (ms > MaxSearchTime); } else { IsOutOfTime = (ms > SearchTime); } if(!IsOutOfTime && CallbackFunction != NULL) { IsOutOfTime = CallbackFunction(this, CallbackData); } return IsOutOfTime; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::PerfTest // Returns the number of leaf node moves when generating, making and // unmaking every move to the specified depth from the current position. unsigned int Engine::PerfTest(unsigned int depth) { if(depth <= 0) { return 1; } MoveList mlist; Pos.GenerateMoves(&mlist); unsigned int nmoves = 0; for(unsigned int i = 0; i < mlist.Size(); i++) { simpleMoveT * sm = mlist.Get(i); Pos.DoSimpleMove(sm); nmoves += PerfTest(depth - 1); Pos.UndoSimpleMove(sm); } return nmoves; } } // End namespace Guess ////////////////////////////////////////////////////////////////////// // EOF: engine.cpp ////////////////////////////////////////////////////////////////////// chessx-1.0.0/src/guess/position.cpp000644 001750 001750 00000351416 12223260306 020104 0ustar00niklasniklas000000 000000 ////////////////////////////////////////////////////////////////////// // // FILE: position.cpp // Position class methods // // Part of: Scid (Shane's Chess Information Database) // Version: 3.5 // // Notice: Copyright (c) 1999-2003 Shane Hudson. All rights reserved. // // Author: Shane Hudson (sgh@users.sourceforge.net) // ////////////////////////////////////////////////////////////////////// #include "common.h" #include "position.h" #include "attacks.h" #include "misc.h" #include "sqlist.h" #include "sqset.h" #include "hash.h" #include #include static unsigned int hashVal [16][64]; static unsigned int stdStartHash = 0; static unsigned int stdStartPawnHash = 0; // HASH and UNHASH are identical: XOR the hash value for a (piece,square). #define HASH(h,p,sq) (h) ^= hashVal[(p)][(sq)] #define UNHASH(h,p,sq) (h) ^= hashVal[(p)][(sq)] using namespace Guess; inline void Position::AddHash(pieceT p, squareT sq) { HASH(Hash, p, sq); if(piece_Type(p) == PAWN) { HASH(PawnHash, p, sq); } } inline void Position::UnHash(pieceT p, squareT sq) { UNHASH(Hash, p, sq); if(piece_Type(p) == PAWN) { UNHASH(PawnHash, p, sq); } } inline void Position::AddToBoard(pieceT p, squareT sq) { ASSERT(Board[sq] == EMPTY); Board[sq] = p; NumOnRank[p][square_Rank(sq)]++; NumOnFyle[p][square_Fyle(sq)]++; NumOnLeftDiag[p][square_LeftDiag(sq)]++; NumOnRightDiag[p][square_RightDiag(sq)]++; NumOnSquareColor[p][square_Color(sq)]++; AddHash(p, sq); } inline void Position::RemoveFromBoard(pieceT p, squareT sq) { ASSERT(Board[sq] == p); Board[sq] = EMPTY; NumOnRank[p][square_Rank(sq)]--; NumOnFyle[p][square_Fyle(sq)]--; NumOnLeftDiag[p][square_LeftDiag(sq)]--; NumOnRightDiag[p][square_RightDiag(sq)]--; NumOnSquareColor[p][square_Color(sq)]--; UnHash(p, sq); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // initHashValues: // Initialises the table of Zobrist hash values. void initHashValues(void) { // Ensure we set up the hash values only once: static int firstCall = 1; if(! firstCall) { return; } firstCall = 0; // First, set all values to 0: unsigned int sq; for(unsigned int p = 0; p < 16; p++) { for(sq = A1; sq <= H8; sq++) { hashVal[p][sq] = 0; } } // Fill in the hash values for each valid [piece][square] index, // using a table of pre-generated good values: const unsigned int * hash = goodHashValues; for(sq = A1; sq <= H8; ++sq) { hashVal[WK][sq] = *hash; ++hash; } for(sq = A1; sq <= H8; ++sq) { hashVal[WQ][sq] = *hash; ++hash; } for(sq = A1; sq <= H8; ++sq) { hashVal[WR][sq] = *hash; ++hash; } for(sq = A1; sq <= H8; ++sq) { hashVal[WB][sq] = *hash; ++hash; } for(sq = A1; sq <= H8; ++sq) { hashVal[WN][sq] = *hash; ++hash; } for(sq = A1; sq <= H8; ++sq) { hashVal[WP][sq] = *hash; ++hash; } for(sq = A1; sq <= H8; ++sq) { hashVal[BK][sq] = *hash; ++hash; } for(sq = A1; sq <= H8; ++sq) { hashVal[BQ][sq] = *hash; ++hash; } for(sq = A1; sq <= H8; ++sq) { hashVal[BR][sq] = *hash; ++hash; } for(sq = A1; sq <= H8; ++sq) { hashVal[BB][sq] = *hash; ++hash; } for(sq = A1; sq <= H8; ++sq) { hashVal[BN][sq] = *hash; ++hash; } for(sq = A1; sq <= H8; ++sq) { hashVal[BP][sq] = *hash; ++hash; } // Compute the hash values for the standard starting position: unsigned int h = 0; // First the pawns: HASH(h, WP, A2); HASH(h, WP, B2); HASH(h, WP, C2); HASH(h, WP, D2); HASH(h, WP, E2); HASH(h, WP, F2); HASH(h, WP, G2); HASH(h, WP, H2); HASH(h, BP, A7); HASH(h, BP, B7); HASH(h, BP, C7); HASH(h, BP, D7); HASH(h, BP, E7); HASH(h, BP, F7); HASH(h, BP, G7); HASH(h, BP, H7); stdStartPawnHash = h; // Now the nonpawns: HASH(h, WR, A1); HASH(h, WN, B1); HASH(h, WB, C1); HASH(h, WQ, D1); HASH(h, WK, E1); HASH(h, WB, F1); HASH(h, WN, G1); HASH(h, WR, H1); HASH(h, BR, A8); HASH(h, BN, B8); HASH(h, BB, C8); HASH(h, BQ, D8); HASH(h, BK, E8); HASH(h, BB, F8); HASH(h, BN, G8); HASH(h, BR, H8); stdStartHash = h; } /////////////////////////////////////////////////////////////////////////// // PRIVATE FUNCTIONS -- small ones are inline for speed //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::AssertPos(): // Does a slow, thorough check of the integrity of the // data structures, ensuring everything is valid. // errorT Position::AssertPos() { unsigned char mat[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; for(colorT c = WHITE; c <= BLACK; ++c) { for(unsigned int i = 0; i < Count[c]; ++i) { if(ListPos[List[c][i]] != i || piece_Color(Board[List[c][i]]) != c) { DumpBoard(stderr); DumpLists(stderr); return ERROR_General; } mat[Board[List[c][i]]]++; } } for(unsigned int i = WK; i < BP; i++) { if(mat[i] != Material[i]) { DumpBoard(stderr); DumpLists(stderr); return ERROR_General; } } return OK; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::CalcPinsDir(): // Look for a pinned piece in the direction 'dir' relative to // the position of the king to move. // inline void Position::CalcPinsDir(directionT dir, pieceT attacker) { // Two pieces can pin along any path. A queen is always one, // the other is a bishop or rook. To save calculating it here, the // appropriate piece (BISHOP) or (ROOK) is passed along with the // direction. squareT king = GetKingSquare(ToMove); squareT friendly = NULL_SQUARE; squareT x = king; squareT last = square_Last(king, dir); int delta = direction_Delta(dir); while(x != last) { x += delta; pieceT p = Board[x]; if(p == EMPTY) { // Empty square, so keep searching. } else if(piece_Color_NotEmpty(p) == ToMove) { // Found a friendly piece. if(friendly == NULL_SQUARE) { // Found first friendly in this direction friendly = x; } else { // Found second friendly in this direction, so stop. return; } } else { // Found an enemy piece if(friendly != NULL_SQUARE) { // Potential pin: pieceT ptype = piece_Type(p); if(ptype == QUEEN || ptype == attacker) { Pinned[ListPos[friendly]] = dir; } } return; // found an enemy piece, so end search } } return; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::AddLegalMove(): // Add a legal move to the move list. // inline void Position::AddLegalMove(MoveList * mlist, squareT from, squareT to, pieceT promo) { ASSERT(mlist != NULL); simpleMoveT * sm = mlist->Add(); // We do NOT set the pre-move castling/ep flags, or the captured // piece info, here since that is ONLY needed if the move is // going to be executed with DoSimpleMove() and then undone. sm->from = from; sm->to = to; sm->promote = promo; sm->movingPiece = Board[from]; sm->capturedPiece = Board[to]; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::GenSliderMoves(): // Generate slider moves along a direction, for a sliding // piece of the specified color from the specified square. // If sqset != NULL, moves must be to a square in sqset. inline void Position::GenSliderMoves(MoveList * mlist, colorT color, squareT fromSq, directionT dir, SquareSet * sqset, bool capturesOnly) { squareT dest = fromSq; squareT last = square_Last(fromSq, dir); int delta = direction_Delta(dir); while(dest != last) { dest += delta; pieceT p = Board[dest]; if(p == EMPTY) { if(! capturesOnly) { if(sqset == NULL || sqset->Contains(dest)) { AddLegalMove(mlist, fromSq, dest, EMPTY); } } continue; } // We have reached a piece. Add the capture if it is an enemy. if(piece_Color_NotEmpty(p) != color) { if(sqset == NULL || sqset->Contains(dest)) { AddLegalMove(mlist, fromSq, dest, EMPTY); } } break; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::GenKnightMoves(): // Generate knight moves. // If sqset != NULL, moves must be to a square in sqset. inline void Position::GenKnightMoves(MoveList * mlist, colorT c, squareT fromSq, SquareSet * sqset, bool capturesOnly) { const squareT * destPtr = knightAttacks[fromSq]; while(true) { squareT dest = *destPtr; if(dest == NULL_SQUARE) { break; } destPtr++; pieceT p = Board[dest]; if(capturesOnly && p == EMPTY) { continue; } if(piece_Color(p) != c) { if(sqset == NULL || sqset->Contains(dest)) { AddLegalMove(mlist, fromSq, dest, EMPTY); } } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::GenCastling(): // Generate the legal castling moves. // Assumes the side to move is NOT in check, so the caller // should verify this first. // void Position::GenCastling(MoveList * mlist) { ASSERT(! IsKingInCheck()); squareT from = GetKingSquare(ToMove); if(from != (ToMove == WHITE ? E1 : E8)) { return; } squareT enemyKingSq = GetEnemyKingSquare(); squareT target, skip, rookSq; pieceT rookPiece; // Queenside Castling: if(!StrictCastling || GetCastling(ToMove, QSIDE)) { if(ToMove == WHITE) { target = C1; skip = D1; rookSq = A1; rookPiece = WR; } else { target = C8; skip = D8; rookSq = A8; rookPiece = BR; } if(Board[target] == EMPTY && Board[skip] == EMPTY && Board[rookSq] == rookPiece && Board[target - 1] == EMPTY // B1 or B8 must be empty too! && CalcNumChecks(target) == 0 && CalcNumChecks(skip) == 0 && ! square_Adjacent(target, enemyKingSq)) { AddLegalMove(mlist, from, target, EMPTY); } } // Kingside Castling: if(!StrictCastling || GetCastling(ToMove, KSIDE)) { if(ToMove == WHITE) { target = G1; skip = F1; rookSq = H1; rookPiece = WR; } else { target = G8; skip = F8; rookSq = H8; rookPiece = BR; } if(Board[target] == EMPTY && Board[skip] == EMPTY && Board[rookSq] == rookPiece && CalcNumChecks(target) == 0 && CalcNumChecks(skip) == 0 && ! square_Adjacent(target, enemyKingSq)) { AddLegalMove(mlist, from, target, EMPTY); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::GenKingMoves(): // Generate the legal King moves. Castling is generated as well, if // the specified flag is true. // void Position::GenKingMoves(MoveList * mlist, genMovesT genType, bool castling) { squareT kingSq = GetKingSquare(); squareT enemyKingSq = GetEnemyKingSquare(); colorT enemy = color_Flip(ToMove); const squareT * destPtr; pieceT king = piece_Make(ToMove, KING); bool genNonCaptures = ((genType & GEN_NON_CAPS) != 0); ASSERT(Board[kingSq] == king); destPtr = kingAttacks[kingSq]; while(*destPtr != NULL_SQUARE) { // Try this move and see if it legal: squareT destSq = *destPtr; bool addThisMove = false; // Only try this move if the target square has an enemy piece, // or if it is empty and noncaptures are to be generated: if((genNonCaptures && Board[destSq] == EMPTY) || piece_Color(Board[destSq]) == enemy) { // Empty or enemy piece there, so try the move: pieceT captured = Board[destSq]; Board[destSq] = king; Board[kingSq] = EMPTY; // It is legal if the two kings will not be adjacent and the // moving king will not be in check on its new square: if(! square_Adjacent(destSq, enemyKingSq)) { if(CalcNumChecks(destSq) == 0) { addThisMove = true; } } Board[kingSq] = king; Board[destSq] = captured; } if(addThisMove) { AddLegalMove(mlist, kingSq, destSq, EMPTY); } destPtr++; } // Now generate castling moves, if possible: if(genNonCaptures && castling) { GenCastling(mlist); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::AddPromotions(): // Add promotion moves. // Called by GenPawnMoves() when a pawn can be promoted. // inline void Position::AddPromotions(MoveList * mlist, squareT from, squareT dest) { ASSERT(piece_Type(Board[from]) == PAWN); ASSERT(square_Rank(dest) == RANK_1 || square_Rank(dest) == RANK_8); AddLegalMove(mlist, from, dest, QUEEN); AddLegalMove(mlist, from, dest, ROOK); AddLegalMove(mlist, from, dest, BISHOP); AddLegalMove(mlist, from, dest, KNIGHT); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::IsValidEnPassant // Used to verify that an en passant pawn capture is valid. // This is needed because illegal en passant captures can appear // legal according to calculations of pinned pieces. For example, // consider WK d5, WP e5, BP f5 (just moved there), BR h5 and // the en passant capture exf6 would be illegal. inline bool Position::IsValidEnPassant(squareT from, squareT to) { ASSERT(from <= H8 && to <= H8); ASSERT(to == EPTarget); // Check that this en passant capture is legal: pieceT ownPawn = piece_Make(ToMove, PAWN); pieceT enemyPawn = piece_Make(color_Flip(ToMove), PAWN); squareT enemyPawnSq = (ToMove == WHITE) ? to - 8 : to + 8; ASSERT(Board[from] == ownPawn); ASSERT(Board[enemyPawnSq] == enemyPawn); Board[from] = EMPTY; Board[enemyPawnSq] = EMPTY; Board[to] = ownPawn; bool isValid = ! IsKingInCheck(); Board[from] = ownPawn; Board[enemyPawnSq] = enemyPawn; Board[to] = EMPTY; return isValid; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::GenPawnMoves(): // Generate legal pawn moves. // If dir != NULL_DIR, pawn MUST move in direction dir or its opposite. // If sqset != NULL, pawn MUST move to a square in sqset. // The dir and sq parameters are for pinned pawns and check evasions. void Position::GenPawnMoves(MoveList * mlist, squareT from, directionT dir, SquareSet * sqset, genMovesT genType) { bool genNonCaptures = ((genType & GEN_NON_CAPS) != 0); directionT oppdir = direction_Opposite(dir); directionT forward; rankT promoRank; rankT secondRank; if(ToMove == WHITE) { forward = UP; promoRank = RANK_8; secondRank = RANK_2; } else { forward = DOWN; promoRank = RANK_1; secondRank = RANK_7; } squareT dest; ASSERT(Board[from] == piece_Make(ToMove, PAWN)); if(genNonCaptures && (dir == NULL_DIR || dir == forward || oppdir == forward)) { dest = square_Move(from, forward); if(Board[dest] == EMPTY && (sqset == NULL || sqset->Contains(dest))) { if(square_Rank(dest) == promoRank) { AddPromotions(mlist, from, dest); } else { AddLegalMove(mlist, from, dest, EMPTY); } } if(square_Rank(from) == secondRank && Board[dest] == EMPTY) { dest = square_Move(dest, forward); if(Board[dest] == EMPTY && (sqset == NULL || sqset->Contains(dest))) { AddLegalMove(mlist, from, dest, EMPTY); } } } // Now do captures: left, then right // To be a possible capture, dest square must be EPTarget or hold // an enemy piece. #define POSSIBLE_CAPTURE(d) ((d != NULL_SQUARE) \ && ((piece_Color (Board[d]) == (color_Flip(ToMove))) \ || (d == EPTarget && IsValidEnPassant(from,d)))) directionT capdir = forward | LEFT; if(dir == NULL_DIR || dir == capdir || oppdir == capdir) { dest = square_Move(from, capdir); if(POSSIBLE_CAPTURE(dest) && (sqset == NULL || sqset->Contains(dest))) { if(square_Rank(dest) == promoRank) { AddPromotions(mlist, from, dest); } else { AddLegalMove(mlist, from, dest, EMPTY); } } } capdir = forward | RIGHT; if(dir == NULL_DIR || dir == capdir || oppdir == capdir) { dest = square_Move(from, capdir); if(POSSIBLE_CAPTURE(dest) && (sqset == NULL || sqset->Contains(dest))) { if(square_Rank(dest) == promoRank) { AddPromotions(mlist, from, dest); } else { AddLegalMove(mlist, from, dest, EMPTY); } } } return; } ////////////////////////////////////////////////////////////////////// // PUBLIC FUNCTIONS //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::GetHPSig(): // Return the position's home pawn signature. // unsigned int Position::GetHPSig(void) { unsigned int hpSig = 0; pieceT * b = &(Board[A2]); if(*b == WP) { hpSig |= 0x8000; } b++; /* a2 */ if(*b == WP) { hpSig |= 0x4000; } b++; /* b2 */ if(*b == WP) { hpSig |= 0x2000; } b++; /* c2 */ if(*b == WP) { hpSig |= 0x1000; } b++; /* d2 */ if(*b == WP) { hpSig |= 0x0800; } b++; /* e2 */ if(*b == WP) { hpSig |= 0x0400; } b++; /* f2 */ if(*b == WP) { hpSig |= 0x0200; } b++; /* g2 */ if(*b == WP) { hpSig |= 0x0100; /* h2 */ } b = &(Board[A7]); if(*b == BP) { hpSig |= 0x0080; } b++; /* a7 */ if(*b == BP) { hpSig |= 0x0040; } b++; /* b7 */ if(*b == BP) { hpSig |= 0x0020; } b++; /* c7 */ if(*b == BP) { hpSig |= 0x0010; } b++; /* d7 */ if(*b == BP) { hpSig |= 0x0008; } b++; /* e7 */ if(*b == BP) { hpSig |= 0x0004; } b++; /* f7 */ if(*b == BP) { hpSig |= 0x0002; } b++; /* g7 */ if(*b == BP) { hpSig |= 0x0001; /* h7 */ } return hpSig; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::Init(): // Initialise the position after it is constructed. // void Position::Init(void) { // Setting up a valid board is left to StdStart() or Clear(). Board [COLOR_SQUARE] = EMPTY; Board [NULL_SQUARE] = END_OF_BOARD; LegalMoves = NULL; SANStrings = NULL; StrictCastling = true; // Make sure all tables used for move generation, hashing, // square tests, etc have been computed: scid_Init(); initHashValues(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::Clear(): // Clear the board and associated structures. // void Position::Clear(void) { int i; for(i = A1; i <= H8; ++i) { Board[i] = EMPTY; } for(i = WK; i <= BP; ++i) { Material[i] = 0; for(unsigned int j = 0; j < 8; ++j) { NumOnRank[i][j] = NumOnFyle[i][j] = 0; } for(unsigned int d = 0; d < 15; ++d) { NumOnLeftDiag[i][d] = NumOnRightDiag[i][d] = 0; } NumOnSquareColor[i][WHITE] = NumOnSquareColor[i][BLACK] = 0; } Count[WHITE] = Count[BLACK] = 0; EPTarget = NULL_SQUARE; Castling = 0; Board [NULL_SQUARE] = END_OF_BOARD; PlyCounter = 0; HalfMoveClock = 0; Hash = 0; PawnHash = 0; return; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::StdStart(): // Set up the standard chess starting position. // void Position::StdStart(void) { Clear(); Material[WK] = Material[BK] = 1; Material[WQ] = Material[BQ] = 1; Material[WR] = Material[BR] = 2; Material[WB] = Material[BB] = 2; Material[WN] = Material[BN] = 2; Material[WP] = Material[BP] = 8; Count[WHITE] = Count[BLACK] = 16; AddToBoard(WK, E1); List[WHITE][0] = E1; ListPos[E1] = 0; AddToBoard(BK, E8); List[BLACK][0] = E8; ListPos[E8] = 0; AddToBoard(WR, A1); List[WHITE][1] = A1; ListPos[A1] = 1; AddToBoard(BR, A8); List[BLACK][1] = A8; ListPos[A8] = 1; AddToBoard(WN, B1); List[WHITE][2] = B1; ListPos[B1] = 2; AddToBoard(BN, B8); List[BLACK][2] = B8; ListPos[B8] = 2; AddToBoard(WB, C1); List[WHITE][3] = C1; ListPos[C1] = 3; AddToBoard(BB, C8); List[BLACK][3] = C8; ListPos[C8] = 3; AddToBoard(WQ, D1); List[WHITE][4] = D1; ListPos[D1] = 4; AddToBoard(BQ, D8); List[BLACK][4] = D8; ListPos[D8] = 4; AddToBoard(WB, F1); List[WHITE][5] = F1; ListPos[F1] = 5; AddToBoard(BB, F8); List[BLACK][5] = F8; ListPos[F8] = 5; AddToBoard(WN, G1); List[WHITE][6] = G1; ListPos[G1] = 6; AddToBoard(BN, G8); List[BLACK][6] = G8; ListPos[G8] = 6; AddToBoard(WR, H1); List[WHITE][7] = H1; ListPos[H1] = 7; AddToBoard(BR, H8); List[BLACK][7] = H8; ListPos[H8] = 7; for(unsigned int i = 0; i < 8; i++) { AddToBoard(WP, A2 + i); List[WHITE][i + 8] = A2 + i; ListPos[A2 + i] = i + 8; AddToBoard(BP, A7 + i); List[BLACK][i + 8] = A7 + i; ListPos[A7 + i] = i + 8; } Castling = 0; SetCastling(WHITE, QSIDE, true); SetCastling(WHITE, KSIDE, true); SetCastling(BLACK, QSIDE, true); SetCastling(BLACK, KSIDE, true); EPTarget = NULL_SQUARE; ToMove = WHITE; PlyCounter = 0; HalfMoveClock = 0; Board [NULL_SQUARE] = END_OF_BOARD; Hash = stdStartHash; PawnHash = stdStartPawnHash; return; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::IsStdStart // Returns true if the position is the standard starting position. bool Position::IsStdStart() { if(ToMove != WHITE || Hash != stdStartHash || PawnHash != stdStartPawnHash || GetCount(WHITE) != 16 || GetCount(BLACK) != 16 || RankCount(WP, RANK_2) != 8 || RankCount(BP, RANK_7) != 8 || RankCount(WN, RANK_1) != 2 || RankCount(BN, RANK_8) != 2 || !GetCastling(WHITE, KSIDE) || !GetCastling(WHITE, QSIDE) || !GetCastling(BLACK, KSIDE) || !GetCastling(BLACK, QSIDE)) { return false; } return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::AddPiece(): // Add a piece to the board and piecelist. // Checks that a side cannot have more than 16 pieces or more // than one king. // errorT Position::AddPiece(pieceT p, squareT sq) { ASSERT(p != EMPTY); colorT c = piece_Color(p); if(Count[c] == 16) { return ERROR_PieceCount; } ASSERT(Count[c] <= 15); if(piece_Type(p) == KING) { // Check there is not already a King: if(Material[p] > 0) { return ERROR_PieceCount; } // King is always at the start of the piecelist, so move the piece // already at location 0 if there is one: if(Count[c] > 0) { squareT oldsq = List[c][0]; List[c][Count[c]] = oldsq; ListPos[oldsq] = Count[c]; } List[c][0] = sq; ListPos[sq] = 0; } else { ListPos[sq] = Count[c]; List[c][Count[c]] = sq; } Count[c]++; Material[p]++; AddToBoard(p, sq); return OK; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::CalcPins(): // Calculate the pieces for the side to move that are // pinned to their king. The array Pinned[] stores, for // each piece, the direction in which it is pinned. // // For example WK on e1, WQ on e2, BQ on e7 on the e-fyle // means the WQ is Pinned in the direction UP. // void Position::CalcPins(void) { Pinned[ 0] = Pinned[ 1] = Pinned[ 2] = Pinned[ 3] = Pinned[ 4] = Pinned[ 5] = Pinned[ 6] = Pinned[ 7] = Pinned[ 8] = Pinned[ 9] = Pinned[10] = Pinned[11] = Pinned[12] = Pinned[13] = Pinned[14] = Pinned[15] = NULL_DIR; squareT kingSq = GetKingSquare(ToMove); colorT enemy = color_Flip(ToMove); pieceT enemyQueen = piece_Make(enemy, QUEEN); pieceT enemyRook = piece_Make(enemy, ROOK); pieceT enemyBishop = piece_Make(enemy, BISHOP); // Pins and checks from Bishops/Queens/Rooks: fyleT fyle = square_Fyle(kingSq); if(FyleCount(enemyQueen, fyle) + FyleCount(enemyRook, fyle) > 0) { CalcPinsDir(UP, ROOK); CalcPinsDir(DOWN, ROOK); } rankT rank = square_Rank(kingSq); if(RankCount(enemyQueen, rank) + RankCount(enemyRook, rank) > 0) { CalcPinsDir(LEFT, ROOK); CalcPinsDir(RIGHT, ROOK); } leftDiagT ld = square_LeftDiag(kingSq); if(LeftDiagCount(enemyQueen, ld) + LeftDiagCount(enemyBishop, ld) > 0) { CalcPinsDir(UP_LEFT, BISHOP); CalcPinsDir(DOWN_RIGHT, BISHOP); } rightDiagT rd = square_RightDiag(kingSq); if(RightDiagCount(enemyQueen, rd) + RightDiagCount(enemyBishop, rd) > 0) { CalcPinsDir(UP_RIGHT, BISHOP); CalcPinsDir(DOWN_LEFT, BISHOP); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::GenPieceMoves(): // Generates moves for a nonpawn, nonking piece. // If sqset != NULL, moves must be to a square in sqset.< void Position::GenPieceMoves(MoveList * mlist, squareT fromSq, SquareSet * sqset, bool capturesOnly) { colorT c = ToMove; pieceT p = Board[fromSq]; pieceT ptype = piece_Type(p); ASSERT(p != EMPTY && ptype != KING && ptype != PAWN); if(ptype == KNIGHT) { GenKnightMoves(mlist, c, fromSq, sqset, capturesOnly); return; } if(ptype != BISHOP) { GenSliderMoves(mlist, c, fromSq, UP, sqset, capturesOnly); GenSliderMoves(mlist, c, fromSq, DOWN, sqset, capturesOnly); GenSliderMoves(mlist, c, fromSq, LEFT, sqset, capturesOnly); GenSliderMoves(mlist, c, fromSq, RIGHT, sqset, capturesOnly); } if(ptype != ROOK) { GenSliderMoves(mlist, c, fromSq, UP_LEFT, sqset, capturesOnly); GenSliderMoves(mlist, c, fromSq, DOWN_LEFT, sqset, capturesOnly); GenSliderMoves(mlist, c, fromSq, UP_RIGHT, sqset, capturesOnly); GenSliderMoves(mlist, c, fromSq, DOWN_RIGHT, sqset, capturesOnly); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::GenerateMoves // Generate the legal moves list. // If the specified pieceType is not EMPTY, then only legal // moves for that type of piece are generated. void Position::GenerateMoves(MoveList * mlist, pieceT pieceType, genMovesT genType, bool maybeInCheck) { bool genNonCaptures = ((genType & GEN_NON_CAPS) != 0); bool capturesOnly = !genNonCaptures; unsigned int mask = 0; if(pieceType != EMPTY) { mask = 1 << pieceType; } else { mask = (1 << KING) | (1 << QUEEN) | (1 << ROOK) | (1 << BISHOP) | (1 << KNIGHT) | (1 << PAWN); } // Use the objects own move list if none was provided: if(mlist == NULL) { ClearLegalMoves(); mlist = LegalMoves; } mlist->Clear(); // Compute which pieces of the side to move are pinned to the king: CalcPins(); // Determine if the side to move is in check and find where the // checking pieces are, unless the caller has passed maybeInCheck=false // indicating it is CERTAIN the side to move is not in check here. unsigned int numChecks = 0; if(maybeInCheck) { SquareList checkSquares; numChecks = CalcNumChecks(GetKingSquare(ToMove), &checkSquares); if(numChecks > 0) { // The side to move IS in check: GenCheckEvasions(mlist, pieceType, genType, &checkSquares); return; } } // The side to move is NOT in check. Iterate over each non-king // piece, and then generate King moves last of all: unsigned int npieces = Count[ToMove]; for(unsigned int x = 1; x < npieces; x++) { squareT sq = List[ToMove][x]; pieceT p = Board[sq]; pieceT ptype = piece_Type(p); if(!(mask & (1 << ptype))) { continue; } directionT pinned = Pinned[x]; // If Pinned[x] == dir (not NULL_DIR), x can ONLY move along // that direction or its opposite. if(pinned != NULL_DIR) // piece x is pinned to king { if(ptype == PAWN) { GenPawnMoves(mlist, sq, pinned, NULL, genType); } else if(ptype == KNIGHT) { // do nothing -- pinned knights cannot move } else { // Piece is a pinned Queen/Rook/Bishop. Only generate // moves along the pinned direction and its opposite: if(ptype == QUEEN || (ptype == ROOK && !direction_IsDiagonal(pinned)) || (ptype == BISHOP && direction_IsDiagonal(pinned))) { GenSliderMoves(mlist, ToMove, sq, pinned, NULL, capturesOnly); GenSliderMoves(mlist, ToMove, sq, dirOpposite[pinned], NULL, capturesOnly); } } } else { // This piece is free to move anywhere if(ptype == PAWN) { GenPawnMoves(mlist, sq, NULL_DIR, NULL, genType); } else { // Knight/Queen/Bishop/Rook: GenPieceMoves(mlist, sq, NULL, capturesOnly); } } } // Lastly, king moves... if(mask & (1 << KING)) { bool castling = !numChecks; GenKingMoves(mlist, genType, castling); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::IsLegalMove // Determines whether the specified move is legal in this position, // without requiring move generation (except for castling moves). bool Position::IsLegalMove(simpleMoveT * sm) { squareT from = sm->from; squareT to = sm->to; if(from > H8 || to > H8) { return false; } if(from == to) { return false; } pieceT mover = Board[from]; pieceT captured = Board[to]; if(piece_Color(mover) != ToMove) { return false; } if(piece_Color(captured) == ToMove) { return false; } if(sm->movingPiece != mover) { return false; } mover = piece_Type(mover); if(sm->promote != EMPTY && mover != PAWN) { return false; } if(mover == PAWN) { rankT rfrom = square_Rank(from); rankT rto = square_Rank(to); if(ToMove == BLACK) { rfrom = RANK_8 - rfrom; rto = RANK_8 - rto; } int rdiff = (int)rto - (int)rfrom; int fdiff = (int)square_Fyle(to) - (int)square_Fyle(from); if(rdiff < 1 || rdiff > 2) { return false; } if(fdiff < -1 || fdiff > 1) { return false; } if(fdiff == 0) // Pawn push: { if(captured != EMPTY) { return false; } if(rdiff == 2) // Two-square push: { if(rfrom != RANK_2) { return false; } // Make sure the square in between is empty: squareT midsquare = from + ((to - from) / 2); if(Board[midsquare] != EMPTY) { return false; } } } else // Pawn capture: { if(rdiff != 1) { return false; } if(captured == EMPTY) { // It must be en passant, or illegal if(to != EPTarget) { return false; } } } // Check the promotion piece: if(rto == RANK_8) { pieceT p = sm->promote; if(p != QUEEN && p != ROOK && p != BISHOP && p != KNIGHT) { return false; } } else { if(sm->promote != EMPTY) { return false; } } } else if(piece_IsSlider(mover)) { // Make sure the direction is valid: directionT dir = sqDir[from][to]; if(dir == NULL_DIR) { return false; } if(mover == ROOK && direction_IsDiagonal(dir)) { return false; } if(mover == BISHOP && !direction_IsDiagonal(dir)) { return false; } int delta = direction_Delta(dir); // Make sure all the in-between squares are empty: squareT dest = from + delta; while(dest != to) { if(Board[dest] != EMPTY) { return false; } dest += delta; } } else if(mover == KNIGHT) { if(! square_IsKnightHop(from, to)) { return false; } } else /* (mover == KING) */ { colorT enemy = color_Flip(ToMove); if(square_Adjacent(to, GetKingSquare(enemy))) { return false; } if(! square_Adjacent(from, to)) { // The move must be castling, or illegal. if(IsKingInCheck()) { return false; } MoveList mlist; GenCastling(&mlist); return (mlist.Find(sm) >= 0); } } // The move looks good, but does it leave the king in check? squareT kingSq = (mover == KING) ? to : GetKingSquare(ToMove); colorT enemy = color_Flip(ToMove); DoSimpleMove(sm); unsigned int nchecks = CalcAttacks(enemy, kingSq, NULL); UndoSimpleMove(sm); return (nchecks == 0); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::MatchLegalMove(): // Sets the LegalMoves list to contain all the moves of pieces // of type "mask" that move to the square "target". // The type must be QUEEN, ROOK, BISHOP, or KNIGHT. // Pawn and King moves are handled in separate functions, // MatchKingMove() and MatchPawnMove(). // void Position::MatchLegalMove(MoveList * mlist, pieceT mask, squareT target) { unsigned int x; // This function isn't for Pawn or King moves! ASSERT(mask != PAWN && mask != KING); if(mlist == NULL) { ClearLegalMoves(); mlist = LegalMoves; } mlist->Clear(); unsigned int count = 0; unsigned int total = Material[piece_Make(ToMove, mask)]; pieceT p, pt, captured; squareT kingSq = GetKingSquare(ToMove); directionT dir; unsigned int tryMove = 0; // First, verify that the target square is empty or contains // an enemy piece: p = Board[target]; if(p != EMPTY && piece_Color(p) == ToMove) { return; } // Loop through looking for pieces of type "mask". We start at 1 // since the King is always the piece at position 0 in the list. squareT * sqPtr = &(List[ToMove][1]); for(x = 1; x < Count[ToMove] && count < total; ++x, ++sqPtr) { p = Board[*sqPtr]; pt = piece_Type(p); if(pt == mask) { // Increment count so we stop when we've seen all the // Material[p] pieces of this type. tryMove = 0; ++count; squareT sq; switch(pt) { case KNIGHT: if(square_IsKnightHop(*sqPtr, target)) { tryMove = 1; } break; case ROOK: dir = sqDir[*sqPtr][target]; if(dir != NULL_DIR && !direction_IsDiagonal(dir)) { sq = square_Move(*sqPtr, dir); tryMove = 1; while(sq != target) { if(Board[sq] != EMPTY) // oops, piece in the way { tryMove = 0; break; } sq = square_Move(sq, dir); } } break; case BISHOP: dir = sqDir[*sqPtr][target]; if(direction_IsDiagonal(dir)) { sq = square_Move(*sqPtr, dir); tryMove = 1; while(sq != target) { if(Board[sq] != EMPTY) // oops, piece in the way { tryMove = 0; break; } sq = square_Move(sq, dir); } } break; case QUEEN: dir = sqDir[*sqPtr][target]; if(dir != NULL_DIR) // Try the move! { sq = square_Move(*sqPtr, dir); tryMove = 1; while(sq != target) { if(Board[sq] != EMPTY) // oops, piece in the way { tryMove = 0; break; } sq = square_Move(sq, dir); } } break; default: // Should never happen ASSERT(0); } // Now, if tryMove is 1, the piece can get to target. We need // to see if the move is legal or leaves the king in check. if(tryMove == 1) { captured = Board[target]; Board[target] = p; Board[*sqPtr] = EMPTY; if(CalcNumChecks(kingSq) > 0) { tryMove = 0; } Board[*sqPtr] = p; Board[target] = captured; if(tryMove == 1) { AddLegalMove(mlist, *sqPtr, target, EMPTY); } } } } // Ok, we've searched all the pieces. return; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::MatchPawnMove(): // Sets the LegalMoves list to contain the matching pawn move, // if there is one. // errorT Position::MatchPawnMove(MoveList * mlist, fyleT fromFyle, squareT to, pieceT promote) { mlist->Clear(); signed int diff = (int)square_Fyle(to) - (int)fromFyle; if(diff < -1 || diff > 1) { return ERROR_InvalidMove; } pieceT pawn; rankT toRank = square_Rank(to); fyleT toFyle = square_Fyle(to); rankT promoteRank = (ToMove == WHITE ? RANK_8 : RANK_1); // from is the from square; backup is the alternative from square // for a pawn move two squares forward. squareT from, backup = NS; if(ToMove == WHITE) { pawn = WP; promoteRank = RANK_8; if(toRank < RANK_3) { return ERROR_InvalidMove; } from = square_Make(fromFyle, toRank - 1); if(toRank == RANK_4 && fromFyle == toFyle) { backup = to - 16; } } else { pawn = BP; promoteRank = RANK_1; if(toRank > RANK_6) { return ERROR_InvalidMove; } from = square_Make(fromFyle, toRank + 1); if(toRank == RANK_5 && fromFyle == toFyle) { backup = to + 16; } } // See if the promotion piece is valid: if(toRank == promoteRank) { if(promote == EMPTY) { return ERROR_InvalidMove; } } else { if(promote != EMPTY) { return ERROR_InvalidMove; } } if(Board[from] != pawn) { // No match; but it could be a foward-two-squares move: if(backup == NS || Board[from] != EMPTY || Board[backup] != pawn) { // A forward-two-squares move is impossible. return ERROR_InvalidMove; } from = backup; } // OK, now 'from' is the only possible from-square. Is the move legal? // We make the move on the board and see if the King is in check. unsigned int legal = 0; if(fromFyle == toFyle) { // Not a capture: if(Board[to] != EMPTY) { return ERROR_InvalidMove; } Board[to] = pawn; Board[from] = EMPTY; if(CalcNumChecks(GetKingSquare()) == 0) { legal = 1; } Board[to] = EMPTY; Board[from] = pawn; } else { // It is a capture -- is it legal? pieceT captured = Board[to]; if(captured == EMPTY) { // Must be an en passant or illegal move. if(to != EPTarget) { return ERROR_InvalidMove; } squareT epSquare = square_Make(toFyle, square_Rank(from)); pieceT enemyPawn = piece_Make(color_Flip(ToMove), PAWN); // If following assert fails, eptarget was corrupt ASSERT(Board[epSquare] == enemyPawn); Board[to] = pawn; Board[from] = EMPTY; Board[epSquare] = EMPTY; Material[enemyPawn] --; if(CalcNumChecks(GetKingSquare()) == 0) { legal = 1; } Board[epSquare] = enemyPawn; Board[to] = EMPTY; Board[from] = pawn; Material[enemyPawn]++; } else { if(piece_Color(captured) == ToMove) { // Capturing a friendly! return ERROR_InvalidMove; } else { // A regular capture. See if it leaves King in check: Board[to] = pawn; Board[from] = EMPTY; Material[captured]--; if(CalcNumChecks(GetKingSquare()) == 0) { legal = 1; } Material[captured]++; Board[to] = captured; Board[from] = pawn; } } } if(legal == 1) { AddLegalMove(mlist, from, to, promote); return OK; } return ERROR_InvalidMove; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::MatchKingMove(): // Sets the LegalMoves list to contain the matching king move, // if there is one. // errorT Position::MatchKingMove(MoveList * mlist, squareT target) { mlist->Clear(); squareT kingSq = GetKingSquare(ToMove); signed int diff = (int)target - (int) kingSq; // Valid diffs are: -9, -8, -7, -2, -1, 1, 2, 7, 8, 9. (-2,2: Castling) if(diff < -9 || diff > 9) { return ERROR_InvalidMove; } if(diff > -7 && diff < -2) { return ERROR_InvalidMove; } if(diff > 2 && diff < 7) { return ERROR_InvalidMove; } if(diff == 0) { return ERROR_InvalidMove; } if(diff == 2) // KingSide Castling { if(kingSq != (ToMove == WHITE ? E1 : E8)) { return ERROR_InvalidMove; } if(StrictCastling && ! GetCastling(ToMove, KSIDE)) { return ERROR_InvalidMove; } // XXX We also need to verify that the target square does not // lie adjacent to the location of the enemy king! if(Board[kingSq + 1] != EMPTY || Board[kingSq + 2] != EMPTY || CalcNumChecks(kingSq) > 0 || CalcNumChecks(kingSq + 1) > 0 || CalcNumChecks(kingSq + 2) > 0) { return ERROR_InvalidMove; } AddLegalMove(mlist, kingSq, target, EMPTY); return OK; } if(diff == -2) // Queenside Castling { if(kingSq != (ToMove == WHITE ? E1 : E8)) { return ERROR_InvalidMove; } if(StrictCastling && ! GetCastling(ToMove, QSIDE)) { return ERROR_InvalidMove; } if(Board[kingSq - 1] != EMPTY || Board[kingSq - 2] != EMPTY || Board[kingSq - 3] != EMPTY || CalcNumChecks(kingSq) > 0 || CalcNumChecks(kingSq - 1) > 0 || CalcNumChecks(kingSq - 2) > 0) { return ERROR_InvalidMove; } AddLegalMove(mlist, kingSq, target, EMPTY); return OK; } pieceT captured = Board[target]; if(piece_Color(captured) == ToMove) { // Capturing a friendly piece! return ERROR_InvalidMove; } // Now make the move on the Board and Material lists, and see if it // leaves the King in check: // XXX We should also check for adjacency to enemy King!! Board[target] = piece_Make(ToMove, KING); Board[kingSq] = EMPTY; if(captured != EMPTY) { Material[captured]--; } unsigned int legal = 0; if(CalcNumChecks(target) == 0) { legal = 1; } if(captured != EMPTY) { Material[captured]++; } Board[target] = captured; Board[kingSq] = piece_Make(ToMove, KING); if(legal == 1) { AddLegalMove(mlist, kingSq, target, EMPTY); return OK; } return ERROR_InvalidMove; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::GenCheckEvasions(): // Generate legal moves for the side to move when the // King is in check. // void Position::GenCheckEvasions(MoveList * mlist, pieceT mask, genMovesT genType, SquareList * checkSquares) { unsigned int numChecks = checkSquares->Size(); // Assert that king IS actually in check: ASSERT(numChecks > 0); bool genNonCaptures = ((genType & GEN_NON_CAPS) != 0); bool capturesOnly = !genNonCaptures; mlist->Clear(); squareT king = GetKingSquare(ToMove); // if it's double check, we can ONLY move the king if(numChecks == 1) { // OK, it is NOT a double check // Try to block piece/capture piece. Remember en passant! // First, generate a list of targets: squares between the king // and attacker to block, and the attacker's square. squareT attackSq = checkSquares->Get(0); directionT dir = sqDir[king][attackSq]; SquareSet targets; // Set of blocking/capturing squares. targets.Add(attackSq); // Now add squares we can might be able to block on. if(dir != NULL_DIR) { squareT sq = square_Move(king, dir); while(sq != attackSq) { if(Board[sq] == EMPTY) { targets.Add(sq); } sq = square_Move(sq, dir); } } // Try each non-King piece in turn. If a piece is pinned to // the king, don't bother since it cannot possibly block or // capture the piece that is giving check! unsigned int numPieces = Count[ToMove]; for(unsigned int p2 = 1; p2 < numPieces; ++p2) { squareT from = List[ToMove][p2]; pieceT p2piece = Board[from]; if(Pinned[p2] != NULL_DIR) { continue; } if(mask == EMPTY || mask == piece_Type(p2piece)) { if(piece_Type(p2piece) == PAWN) { GenPawnMoves(mlist, from, NULL_DIR, &targets, genType); // Capturing a pawn en passant will only get out // of check if the pawn that moved two squares // is doing the checking. If it is not, that means // a discovered check with the last pawn move so // taking en passant cannot get out of check. if(EPTarget != NULL_SQUARE) { squareT pawnSq = (ToMove == WHITE ? EPTarget - 8 : EPTarget + 8); if(pawnSq == attackSq) { SquareSet epset; epset.Add(EPTarget); GenPawnMoves(mlist, from, NULL_DIR, &epset, genType); } } } else { GenPieceMoves(mlist, from, &targets, capturesOnly); } } } // end of search for captures/blocks } // Now king moves -- just compute them normally: if(mask == EMPTY || mask == KING) { GenKingMoves(mlist, genType, false); } return; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::CalcAttacks(): // Calculate the number of attacks by a side on a square. // This function also puts a list of the attacking piece squares // in the fromSqs parameter if it is non-NULL. // // It ONLY uses the Board[] and Material[] lists of the Position, and // ASSUMES they are correct with respect to each other, but it does // NOT use the List[] or ListPos[] information. // This allows us to move pieces quickly (altering only Board[] and // Material[]) and detect whether they leave the king in check, // without having to update other information. unsigned int Position::CalcAttacks(colorT side, squareT target, SquareList * fromSquares) { // If squares is NULL, caller doesn't want a list of the squares of // attacking pieces. To avoid comparing fromSquares with NULL every time // we find a check, we set up a local array to use instead if fromSquares // is NULL. SquareList fromSqs; if(fromSquares == NULL) { fromSquares = &fromSqs; } fromSquares->Clear(); squareT sq; // Bishop/Queen/Rook attacks: look at each of the 8 directions pieceT queen, rook, bishop, knight; if(side == WHITE) { queen = WQ; rook = WR; bishop = WB; knight = WN; } else { queen = BQ; rook = BR; bishop = BB; knight = BN; } unsigned int numQueensRooks = Material[queen] + Material[rook]; unsigned int numQueensBishops = Material[queen] + Material[bishop]; // We only bother if there are any sliding pieces of each type: if(numQueensRooks > 0) { fyleT fyle = square_Fyle(target); rankT rank = square_Rank(target); directionT dirs[4]; unsigned int ndirs = 0; if(FyleCount(queen, fyle) + FyleCount(rook, fyle) > 0) { dirs[ndirs++] = UP; dirs[ndirs++] = DOWN; } if(RankCount(queen, rank) + RankCount(rook, rank) > 0) { dirs[ndirs++] = LEFT; dirs[ndirs++] = RIGHT; } for(unsigned int i = 0; i < ndirs; ++i) { directionT dir = dirs[i]; int delta = direction_Delta(dir); squareT dest = target; squareT last = square_Last(target, dir); while(dest != last) { dest += delta; pieceT p = Board[dest]; if(p == EMPTY) { // empty square: keep searching } else if(p == queen || p == rook) { // Found an attacking piece fromSquares->Add(dest); break; } else { // Found a piece, but not a queen or rook break; } } } } // Now diagonal sliders: Queens/Bishops: if(numQueensBishops > 0) { leftDiagT left = square_LeftDiag(target); rightDiagT right = square_RightDiag(target); directionT dirs[4]; unsigned int ndirs = 0; if(LeftDiagCount(queen, left) + LeftDiagCount(bishop, left) > 0) { dirs[ndirs++] = UP_LEFT; dirs[ndirs++] = DOWN_RIGHT; } if(RightDiagCount(queen, right) + RightDiagCount(bishop, right) > 0) { dirs[ndirs++] = UP_RIGHT; dirs[ndirs++] = DOWN_LEFT; } for(unsigned int i = 0; i < ndirs; i++) { directionT dir = dirs[i]; int delta = direction_Delta(dir); squareT dest = target; squareT last = square_Last(target, dir); while(dest != last) { dest += delta; pieceT p = Board[dest]; if(p == EMPTY) { // empty square: keep searching } else if(p == queen || p == bishop) { // Found an attacking piece fromSquares->Add(dest); break; } else { // Found a piece, but not an enemy queen or bishop break; } } } } // Now knight checks: we only bother if there is a knight on the // opposite square color of the target square color. if(Material[knight] > 0 && SquareColorCount(knight, color_Flip(square_Color(target))) > 0) { const squareT * destPtr = knightAttacks[target]; while(true) { squareT dest = *destPtr; if(dest == NULL_SQUARE) { break; } if(Board[dest] == knight) { fromSquares->Add(dest); } destPtr++; } } // Now pawn attacks: if(side == WHITE) { if(square_Rank(target) != RANK_1) //if (Material[WP] > 0) { { sq = square_Move(target, DOWN_LEFT); if(Board[sq] == WP) { fromSquares->Add(sq); } sq = square_Move(target, DOWN_RIGHT); if(Board[sq] == WP) { fromSquares->Add(sq); } } } else { if(square_Rank(target) != RANK_8) //if (Material[BP] > 0) { { sq = square_Move(target, UP_LEFT); if(Board[sq] == BP) { fromSquares->Add(sq); } sq = square_Move(target, UP_RIGHT); if(Board[sq] == BP) { fromSquares->Add(sq); } } } return fromSquares->Size(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::IsKingInCheckDir // Returns true if the King of the side to move is attacked // by an enemy sliding piece (Queen/Rook/Bishop) from the // specified direction. bool Position::IsKingInCheckDir(directionT dir) { ASSERT(dir != NULL_DIR); squareT kingSq = GetKingSquare(ToMove); colorT enemy = color_Flip(ToMove); bool isDiagonal = direction_IsDiagonal(dir); pieceT queen = piece_Make(enemy, QUEEN); pieceT slider = piece_Make(enemy, (isDiagonal ? BISHOP : ROOK)); // First, make sure the enemy has sliding pieces that could give check: unsigned int nSliders = PieceCount(queen) + PieceCount(slider); if(nSliders == 0) { return false; } // Now make sure the enemy has a sliding piece on the appropriate // rank, file or diagonal: fyleT fyle = square_Fyle(kingSq); rankT rank = square_Rank(kingSq); leftDiagT ldiag = square_LeftDiag(kingSq); rightDiagT rdiag = square_RightDiag(kingSq); switch(dir) { case UP: case DOWN: nSliders = FyleCount(queen, fyle) + FyleCount(slider, fyle); break; case LEFT: case RIGHT: nSliders = RankCount(queen, rank) + RankCount(slider, rank); break; case UP_LEFT: case DOWN_RIGHT: nSliders = LeftDiagCount(queen, ldiag) + LeftDiagCount(slider, ldiag); break; case UP_RIGHT: case DOWN_LEFT: nSliders = RightDiagCount(queen, rdiag) + RightDiagCount(slider, rdiag); break; } if(nSliders == 0) { return false; } // Now move along the specified direction looking for a checking piece: squareT dest = kingSq; squareT last = square_Last(kingSq, dir); int delta = direction_Delta(dir); while(dest != last) { dest += delta; pieceT p = Board[dest]; if(p == EMPTY) { // empty square: keep searching } else if(p == queen || p == slider) { // Found an checking slider piece return true; } else { // Found a piece, but not an enemy queen or rook/bishop break; } } return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::IsKingInCheck // Returns true if the king of the side to move is in check. // If the specified move is not NULL, it must be the legal move // that the opponent played to reach this position. This will // be used as a speed optimization, by skipping cases where the // move could not have left the king in check. // bool Position::IsKingInCheck(simpleMoveT * sm) { if(sm == NULL) { return IsKingInCheck(); } squareT kingSq = GetKingSquare(ToMove); pieceT p = piece_Type(sm->movingPiece); if(sm->promote != EMPTY) { p = piece_Type(sm->promote); } // No optimization of the last move was castling: if(p == KING && square_Fyle(sm->from) == E_FYLE) { fyleT toFyle = square_Fyle(sm->to); if(toFyle == C_FYLE || toFyle == G_FYLE) { return IsKingInCheck(); } } // No optimization for en passant capture: if(p == PAWN && piece_Type(sm->capturedPiece) == PAWN) { rankT fromRank = square_Rank(sm->from); rankT capturedRank = square_Rank(sm->capturedSquare); if(fromRank == capturedRank) { return IsKingInCheck(); } } if(p == PAWN) { if(ToMove == WHITE) { if(Material[BP] > 0) { squareT sq = square_Move(kingSq, UP_LEFT); if(Board[sq] == BP) { return true; } sq = square_Move(kingSq, UP_RIGHT); if(Board[sq] == BP) { return true; } } } else { if(Material[WP] > 0) { squareT sq = square_Move(kingSq, DOWN_LEFT); if(Board[sq] == WP) { return true; } sq = square_Move(kingSq, DOWN_RIGHT); if(Board[sq] == WP) { return true; } } } } else if(p == KNIGHT) { if(square_IsKnightHop(kingSq, sm->to)) { return true; } } else if(p == KING) { // A king cannot directly check its adversary. } else { // A sliding piece: directionT toDir = sqDir[kingSq][sm->to]; if(toDir != NULL_DIR && IsKingInCheckDir(toDir)) { return true; } } // Now look for a discovered check from a sliding piece: directionT dir = sqDir[kingSq][sm->from]; if(dir != NULL_DIR && IsKingInCheckDir(dir)) { return true; } ASSERT(IsKingInCheck() == false); return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::Mobility // Returns the number of squares a rook or bishop of the specified // color would attack from the specified square. unsigned int Position::Mobility(pieceT p, colorT color, squareT from) { ASSERT(p == ROOK || p == BISHOP); unsigned int mobility = 0; directionT rookDirs[4] = { UP, DOWN, LEFT, RIGHT }; directionT bishopDirs[4] = { UP_LEFT, UP_RIGHT, DOWN_LEFT, DOWN_RIGHT }; directionT * dirPtr = (p == ROOK ? rookDirs : bishopDirs); for(unsigned int i = 0; i < 4; ++i) { directionT dir = dirPtr[i]; int delta = direction_Delta(dir); squareT dest = from; squareT last = square_Last(from, dir); while(dest != last) { dest += delta; pieceT p = Board[dest]; if(p == EMPTY) // Empty square { ++mobility; } else if(piece_Color(p) == color) // Friendly piece { break; // Finished with this direction. } else // Enemy piece { ++mobility; break; // Finished with this direction. } } } return mobility; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::SmallestDefender() // Returns the type of the lowest-valued piece of the specified // color that could capture to the specified square. Pins to the // king are ignored. Checks pieces in the order Pawn, Knight, // Bishop, Rook, Queen then King. If the specified square is // undefended, EMPTY is returned. // pieceT Position::SmallestDefender(colorT color, squareT target) { SquareList defenderSquares; pieceT defenders [16]; unsigned int numDefenders = CalcAttacks(color, target, &defenderSquares); // If the square is undefended, just return EMPTY: if(numDefenders == 0) { return EMPTY; } unsigned int i; for(i = 0; i < numDefenders; ++i) { defenders[i] = Board[defenderSquares.Get(i)]; } // Look for pawns first: for(i = 0; i < numDefenders; ++i) { if(piece_Type(defenders[i]) == PAWN) { return PAWN; } } // Look for knights then bishops: for(i = 0; i < numDefenders; ++i) { if(piece_Type(defenders[i]) == KNIGHT) { return KNIGHT; } } for(i = 0; i < numDefenders; ++i) { if(piece_Type(defenders[i]) == BISHOP) { return BISHOP; } } // Look for rooks then queens: for(i = 0; i < numDefenders; ++i) { if(piece_Type(defenders[i]) == ROOK) { return ROOK; } } for(i = 0; i < numDefenders; ++i) { if(piece_Type(defenders[i]) == QUEEN) { return QUEEN; } } // If we get here, it must be defended only by the king: ASSERT(numDefenders == 1 && piece_Type(defenders[i]) == KING); return KING; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::IsKingInMate(): // Quick check if king is in mate. // bool Position::IsKingInMate(void) { SquareList checkSquares; unsigned int numChecks = CalcNumChecks(GetKingSquare(ToMove), &checkSquares); if(numChecks == 0) { return false; } CalcPins(); MoveList mlist; GenCheckEvasions(&mlist, EMPTY, GEN_ALL_MOVES, &checkSquares); if(mlist.Size() == 0) { return true; } return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::IsLegal() // Verifies the position as being legal. // Returns false for any of the following: // - if the two kings are adjacent; // - if there are any pawns on the 1st/8th rank; // - if the side to move is already checking the enemy king. bool Position::IsLegal(void) { squareT stmKing = GetKingSquare(); squareT enemyKing = GetEnemyKingSquare(); if(square_Adjacent(stmKing, enemyKing)) { printf("Kings adjacent\n"); return false; } if(RankCount(WP, RANK_1) != 0) { return false; } if(RankCount(WP, RANK_8) != 0) { return false; } if(RankCount(BP, RANK_1) != 0) { return false; } if(RankCount(BP, RANK_8) != 0) { return false; } if(CalcAttacks(ToMove, enemyKing, NULL) > 0) { return false; } return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::IsPromoMove(): // Returns true if the move is a promotion move. // NOTE that the move may not actually be legal! // The arguments 'from' and 'to' can be in either order. bool Position::IsPromoMove(squareT from, squareT to) { rankT seventh, eighth; pieceT pawn; if(ToMove == WHITE) { seventh = RANK_7; eighth = RANK_8; pawn = WP; } else { seventh = RANK_2; eighth = RANK_1; pawn = BP; } rankT fromR, toR; fromR = square_Rank(from); toR = square_Rank(to); if((fromR == seventh && toR == eighth && Board[from] == pawn) || (toR == seventh && fromR == eighth && Board[to] == pawn)) { return 1; } return 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::DoSimpleMove(): // Make the move on the board and update all the necessary // fields in the simpleMove structure so it can be undone. // void Position::DoSimpleMove(simpleMoveT * sm) { ASSERT(sm != NULL); squareT from = sm->from; squareT to = sm->to; pieceT p = Board[from]; pieceT ptype = piece_Type(p); colorT enemy = color_Flip(ToMove); ASSERT(p != EMPTY); // update move fields that (maybe) have not yet been set: sm->pieceNum = ListPos[from]; sm->capturedPiece = Board[to]; sm->capturedSquare = to; sm->castleFlags = Castling; sm->epSquare = EPTarget; sm->oldHalfMoveClock = HalfMoveClock; HalfMoveClock++; PlyCounter++; // Check for a null (empty) move: if(isNullMove(sm)) { ToMove = enemy; EPTarget = NULL_SQUARE; return; } // Handle en passant capture: if(ptype == PAWN && sm->capturedPiece == EMPTY && square_Fyle(from) != square_Fyle(to)) { // This was an EP capture. We do not need to check it was a capture // since if a pawn lands on EPTarget it must capture to get there. pieceT enemyPawn = piece_Make(enemy, PAWN); sm->capturedSquare = (ToMove == WHITE ? (to - 8) : (to + 8)); ASSERT(Board[sm->capturedSquare] == enemyPawn); sm->capturedPiece = enemyPawn; } // handle captures: if(sm->capturedPiece != EMPTY) { ASSERT(piece_Type(sm->capturedPiece) != KING); sm->capturedNum = ListPos[sm->capturedSquare]; // update opponents List of pieces Count[enemy]--; ListPos[List[enemy][Count[enemy]]] = sm->capturedNum; List[enemy][sm->capturedNum] = List[enemy][Count[enemy]]; Material[sm->capturedPiece]--; HalfMoveClock = 0; RemoveFromBoard(sm->capturedPiece, sm->capturedSquare); } // handle promotion: if(sm->promote != EMPTY) { ASSERT(p == piece_Make(ToMove, PAWN)); Material[p]--; RemoveFromBoard(p, from); p = piece_Make(ToMove, sm->promote); Material[p]++; AddToBoard(p, from); } // now make the move: List[ToMove][sm->pieceNum] = to; ListPos[to] = sm->pieceNum; RemoveFromBoard(p, from); AddToBoard(p, to); // handle Castling: if(ptype == KING && square_Fyle(from) == E_FYLE && (square_Fyle(to) == C_FYLE || square_Fyle(to) == G_FYLE)) { squareT rookfrom, rookto; pieceT rook = piece_Make(ToMove, ROOK); if(square_Fyle(to) == C_FYLE) { rookfrom = to - 2; rookto = to + 1; } else { rookfrom = to + 1; rookto = to - 1; } ListPos[rookto] = ListPos[rookfrom]; List[ToMove][ListPos[rookto]] = rookto; RemoveFromBoard(rook, rookfrom); AddToBoard(rook, rookto); } // Handle clearing of castling flags: if(Castling) { if(ptype == KING) // The king moved. { SetCastling(ToMove, QSIDE, false); SetCastling(ToMove, KSIDE, false); } // See if a rook moved or was captured: if(ToMove == WHITE) { if(from == A1) { SetCastling(WHITE, QSIDE, false); } if(from == H1) { SetCastling(WHITE, KSIDE, false); } if(to == A8) { SetCastling(BLACK, QSIDE, false); } if(to == H8) { SetCastling(BLACK, KSIDE, false); } } else { if(from == A8) { SetCastling(BLACK, QSIDE, false); } if(from == H8) { SetCastling(BLACK, KSIDE, false); } if(to == A1) { SetCastling(WHITE, QSIDE, false); } if(to == H1) { SetCastling(WHITE, KSIDE, false); } } } // Set the EPTarget square, if a pawn advanced two squares and an // enemy pawn is on a square where en passant may be possible. EPTarget = NULL_SQUARE; if(ptype == PAWN) { rankT fromRank = square_Rank(from); rankT toRank = square_Rank(to); if(fromRank == RANK_2 && toRank == RANK_4 && (Board[square_Move(to, LEFT)] == BP || Board[square_Move(to, RIGHT)] == BP)) { EPTarget = square_Move(from, UP); } if(fromRank == RANK_7 && toRank == RANK_5 && (Board[square_Move(to, LEFT)] == WP || Board[square_Move(to, RIGHT)] == WP)) { EPTarget = square_Move(from, DOWN); } HalfMoveClock = 0; // 50-move clock resets on pawn moves. } ToMove = enemy; #ifdef ASSERTIONS // Do a SLOW, careful check for corruption: if(AssertPos() != OK) { abort(); } #endif return; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::UndoSimpleMove(): // Take back a simple move that has been made with DoSimpleMove(). // void Position::UndoSimpleMove(simpleMoveT * m) { ASSERT(m != NULL); squareT from = m->from; squareT to = m->to; pieceT p = Board[to]; EPTarget = m->epSquare; Castling = m->castleFlags; HalfMoveClock = m->oldHalfMoveClock; PlyCounter--; ToMove = color_Flip(ToMove); m->pieceNum = ListPos[to]; // Check for a null move: if(isNullMove(m)) { return; } // Handle a capture: insert piece back into piecelist. // This works for EP captures too, since the square of the captured // piece is in the "capturedSquare" field rather than assuming the // value of the "to" field. The only time these two fields are // different is for an en passant move. if(m->capturedPiece != EMPTY) { colorT c = color_Flip(ToMove); ListPos[List[c][m->capturedNum]] = Count[c]; ListPos[m->capturedSquare] = m->capturedNum; List[c][Count[c]] = List[c][m->capturedNum]; List[c][m->capturedNum] = m->capturedSquare; Material[m->capturedPiece]++; Count[c]++; } // handle promotion: if(m->promote != EMPTY) { Material[p]--; RemoveFromBoard(p, to); p = piece_Make(ToMove, PAWN); Material[p]++; AddToBoard(p, to); } // now make the move: List[ToMove][m->pieceNum] = from; ListPos[from] = m->pieceNum; RemoveFromBoard(p, to); AddToBoard(p, from); if(m->capturedPiece != EMPTY) { AddToBoard(m->capturedPiece, m->capturedSquare); } // handle Castling: if((piece_Type(p) == KING) && square_Fyle(from) == E_FYLE && (square_Fyle(to) == C_FYLE || square_Fyle(to) == G_FYLE)) { squareT rookfrom, rookto; pieceT rook = (ToMove == WHITE ? WR : BR); if(square_Fyle(to) == C_FYLE) { rookfrom = to - 2; rookto = to + 1; } else { rookfrom = to + 1; rookto = to - 1; } ListPos[rookfrom] = ListPos[rookto]; List[ToMove][ListPos[rookto]] = rookfrom; RemoveFromBoard(rook, rookto); AddToBoard(rook, rookfrom); } #ifdef ASSERTIONS if(AssertPos() != OK) { abort(); } #endif return; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::RelocatePiece(): // Given a from-square and to-square, modifies the position so // the piece on the from-square is relocated to the to-square. // Returns an error if the from square is empty, or the target // square is not empty, or the relocation would otherwise // produce an illegal position (e.g. pawn on the 1st or 8th rank // or a King in check). // errorT Position::RelocatePiece(squareT fromSq, squareT toSq) { // Must have on-board squares: if(fromSq == NS || toSq == NS) { return ERROR_General; } // If squares are identical, just return success: if(fromSq == toSq) { return OK; } pieceT piece = Board[fromSq]; pieceT ptype = piece_Type(piece); colorT pcolor = piece_Color(piece); // Must be relocating a nonempty piece to an empty square: if(piece == EMPTY || Board[toSq] != EMPTY) { return ERROR_General; } // Pawns cannot relocate to the first or last rank: if(ptype == PAWN) { rankT toRank = square_Rank(toSq); if(toRank == RANK_1 || toRank == RANK_8) { return ERROR_General; } } // Locate the piece index in the appropriate list of pieces: unsigned int index = ListPos[fromSq]; ASSERT(List[pcolor][index] == fromSq); // Relocate the piece: List[pcolor][index] = toSq; ListPos[toSq] = index; RemoveFromBoard(piece, fromSq); AddToBoard(piece, toSq); // Check for adjacent kings or side to move giving check: if(! IsLegal()) { // Undo the relocation and return error: List[pcolor][index] = fromSq; RemoveFromBoard(piece, toSq); AddToBoard(piece, fromSq); return ERROR_General; } // Relocation successful: return OK; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::MaterialValue(): // Returns the sum value of material for a particular side, // where piece values are: // King: 0 (since both sides always have one) // Queen: 9 // Rook: 5 // Bishop, Knight: 3 each // Pawn: 1 unsigned int Position::MaterialValue(colorT c) { ASSERT(c == WHITE || c == BLACK); unsigned int value = 0; if(c == WHITE) { value += 9 * PieceCount(WQ); value += 5 * PieceCount(WR); value += 3 * PieceCount(WB); value += 3 * PieceCount(WN); value += 1 * PieceCount(WP); } else { value += 9 * PieceCount(BQ); value += 5 * PieceCount(BR); value += 3 * PieceCount(BB); value += 3 * PieceCount(BN); value += 1 * PieceCount(BP); } return value; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::MakeSANString(): // Make the SAN string for a simpleMove. // The parameter 'sanFlag' indicates whether '+' and '#' symbols // should be added to checking or mating moves. // void Position::MakeSANString(simpleMoveT * m, char * s, sanFlagT flag) { ASSERT(m != NULL && s != NULL); // Make sure m->pieceNum is updated: m->pieceNum = ListPos[m->from]; pieceT p = piece_Type(Board[List[ToMove][m->pieceNum]]); squareT from = List[ToMove][m->pieceNum]; squareT to = m->to; char * c = s; if(p == PAWN) { if(square_Fyle(from) != square_Fyle(to)) // pawn capture { *c++ = square_FyleChar(from); *c++ = 'x'; } *c++ = square_FyleChar(to); *c++ = square_RankChar(to); if((square_Rank(to) == RANK_1) || (square_Rank(to) == RANK_8)) { *c++ = '='; *c++ = piece_Char(m->promote); } } else if(p == KING) { if(isNullMove(m)) { //*c++ = 'n'; *c++ = 'u'; *c++ = 'l'; *c++ = 'l'; *c++ = '-'; *c++ = '-'; } else if((square_Fyle(from) == E_FYLE) && (square_Fyle(to) == G_FYLE)) { *c++ = 'O'; *c++ = '-'; *c++ = 'O'; } else if((square_Fyle(from) == E_FYLE) && (square_Fyle(to) == C_FYLE)) { *c++ = 'O'; *c++ = '-'; *c++ = 'O'; *c++ = '-'; *c++ = 'O'; } else // regular King move { *c++ = 'K'; if(Board[to] != EMPTY) { *c++ = 'x'; } *c++ = square_FyleChar(to); *c++ = square_RankChar(to); } } else // Queen/Rook/Bishop/Knight { *c++ = piece_Char(p); // We only need to calculate legal moves to disambiguate if there // are more than one of this type of piece. if(Material[Board[m->from]] < 2) { if(Board[to] != EMPTY) { *c++ = 'x'; } *c++ = square_FyleChar(to); *c++ = square_RankChar(to); } else { // disambiguate moves here: // SHOULD handle 3-way ambiguity! Looks like it does ok. bool ambiguous_fyle = false; bool ambiguous_rank = false; char r, f, r2, f2; f = square_FyleChar(from); r = square_RankChar(from); MoveList mlist; MatchLegalMove(&mlist, p, to); for(unsigned int i = 0; i < mlist.Size(); i++) { simpleMoveT * m2 = mlist.Get(i); squareT from2 = m2->from; pieceT p2 = piece_Type(Board[from2]); if((to == m2->to) && (from != from2) && (p2 == p)) { /* we have an ambiguity */ f2 = square_FyleChar(from2); r2 = square_RankChar(from2); if(f == f2) // ambiguous fyle, so print rank { ambiguous_fyle = true; } else // ambiguous rank, so print fyle { ambiguous_rank = true; } } } if(ambiguous_rank) { *c++ = f; // print from-fyle } if(ambiguous_fyle) { *c++ = r; // print from-rank } if(Board[to] != EMPTY) { *c++ = 'x'; } *c++ = square_FyleChar(to); *c++ = square_RankChar(to); } } // Now do the check or mate symbol: if(flag != SAN_NO_CHECKTEST) { // Now we make the move to test for check: DoSimpleMove(m); if(CalcNumChecks(GetKingSquare()) > 0) { char ch = '+'; if(flag == SAN_MATETEST) { MoveList mlist; GenerateMoves(&mlist); if(mlist.Size() == 0) { ch = '#'; } } *c++ = ch; } UndoSimpleMove(m); } *c = 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::ReadCoordMove(): // Given a non-promotion move in coordinate notation, // e.g. "e2e4" or "g1f3", generates the legal move it represents. // Returns: OK or ERROR_InvalidMove. // If "reverse" is true, coordinates in reverse order are acceptable, // e.g. "f3g1" for 1.Nf3. // errorT Position::ReadCoordMove(simpleMoveT * m, const char * str, bool reverse) { ASSERT(m != NULL && str != NULL); fyleT fromFyle, toFyle; rankT fromRank, toRank; squareT from, to; pieceT promo = EMPTY; unsigned int slen = strLength(str); if(slen == 5) { promo = piece_FromChar(toupper(str[4])); } else if(slen != 4) { return ERROR_InvalidMove; } fromFyle = fyle_FromChar(str[0]); fromRank = rank_FromChar(str[1]); from = square_Make(fromFyle, fromRank); if(from == NS) { return ERROR_InvalidMove; } toFyle = fyle_FromChar(str[2]); toRank = rank_FromChar(str[3]); to = square_Make(toFyle, toRank); if(to == NS) { return ERROR_InvalidMove; } GenerateMoves(); for(unsigned int i = 0; i < LegalMoves->Size(); i++) { simpleMoveT * sm = LegalMoves->Get(i); if(sm->promote == promo) { if(sm->from == from && sm->to == to) { *m = *sm; return OK; } if(reverse && sm->to == from && sm->from == to) { *m = *sm; return OK; } } } return ERROR_InvalidMove; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::ReadMove(): // Given a move in (possibly sloppy) PGN notation, // generates the legal move it corresponds to. // Returns: OK or ERROR_InvalidMove. // errorT Position::ReadMove(simpleMoveT * m, const char * str, tokenT token) { ASSERT(m != NULL && str != NULL); const char * s = str; char mStr [255]; pieceT p; squareT from = NS; squareT to = NS; rankT frRank, toRank; fyleT frFyle, toFyle; MoveList mlist; mlist.Clear(); // Check for a null move: if(token == TOKEN_Move_Null) { m->pieceNum = 0; m->from = GetKingSquare(ToMove); m->to = m->from; m->movingPiece = Board[m->from]; m->promote = EMPTY; return OK; } // Strip out 'x', '-', etc leaving just pieces, files and ranks: char * s2 = mStr; unsigned int slen = 0; while(!isspace(*s) && *s != '\0') { if((isalpha(*s) && (*s != 'x')) || isdigit(*s) || *s == '=') { *s2 = *s; s2++; slen++; } s++; } *s2 = '\0'; s = mStr; // Pawn moves: if(token == TOKEN_Move_Pawn || token == TOKEN_Move_Promote) { pieceT promo = EMPTY; if(token == TOKEN_Move_Promote) { // Last char must be Q/R/B/N. // Accept the move even if it is of the form "a8Q" not "a8=Q": // if (s[slen-2] != '=') { return ERROR_InvalidMove; } promo = piece_FromChar(toupper(s[slen - 1])); if(promo != QUEEN && promo != ROOK && promo != KNIGHT && promo != BISHOP) { return ERROR_InvalidMove; } slen--; if(s[slen - 1] == '=') { slen--; } } else { // Check if it is a coordinates-style move, in which case it // could be any piece: if(slen >= 4 && islower(s[0]) && isdigit(s[1]) && islower(s[slen - 2]) && isdigit(s[slen - 1])) { return ReadCoordMove(m, str, false); } } // First char MUST be a fyle: if(*s < 'a' || *s > 'h') { return ERROR_InvalidMove; } frFyle = fyle_FromChar(s[0]); // Check for the compact form of capture with no rank, // e.g. "ed" or "de=Q": if(slen == 2 && (s[1] >= 'a' && s[1] <= 'h')) { toFyle = fyle_FromChar(s[1]); // Check each rank in turn, looking for the capture: for(rankT r = RANK_1; r <= RANK_8; ++r) { to = square_Make(toFyle, r); if(MatchPawnMove(&mlist, frFyle, to, promo) == OK) { *m = *(mlist.Get(0)); return OK; } } // It is NOT a valid capture with no rank: return ERROR_InvalidMove; } toFyle = fyle_FromChar(s[slen - 2]); toRank = rank_FromChar(s[slen - 1]); to = square_Make(toFyle, toRank); if(to == NS) { return ERROR_InvalidMove; } if(MatchPawnMove(&mlist, frFyle, to, promo) != OK) { return ERROR_InvalidMove; } else { *m = *(mlist.Get(0)); return OK; } } // Here we handle piece moves, including castling if(token != TOKEN_Move_Piece) // Must be castling move { ASSERT(token == TOKEN_Move_Castle_King || token == TOKEN_Move_Castle_Queen); from = (ToMove == WHITE ? E1 : E8); if(GetKingSquare(ToMove) != from) { return ERROR_InvalidMove; } to = (token == TOKEN_Move_Castle_King ? (from + 2) : (from - 2)); if(MatchKingMove(&mlist, to) != OK) { return ERROR_InvalidMove; } else { *m = *(mlist.Get(0)); return OK; } } // If we reach here, it is a (non-castling, non-pawn) piece move. ASSERT(token == TOKEN_Move_Piece); p = piece_FromChar(*s); if(p == EMPTY) { return ERROR_InvalidMove; } if(slen < 3 || slen > 5) { return ERROR_InvalidMove; } toRank = rank_FromChar(s[slen - 1]); toFyle = fyle_FromChar(s[slen - 2]); to = square_Make(toFyle, toRank); if(to == NS) { return ERROR_InvalidMove; } frRank = NO_RANK; frFyle = NO_FYLE; if(slen > 3) { // There is some ambiguity information in the input string. for(unsigned int i = 1; i < slen - 2; ++i) // For each extra char: { if(isdigit(s[i])) { frRank = rank_FromChar(s[i]); } else if(s[i] >= 'a' && s[i] <= 'h') { frFyle = fyle_FromChar(s[i]); } } } // Calculate the matching legal move(s): if(p == KING) { if(MatchKingMove(&mlist, to) != OK) { return ERROR_InvalidMove; } else { *m = *(mlist.Get(0)); return OK; } } else // A Queen/Rook/Bishop/Knight move { MatchLegalMove(&mlist, p, to); } unsigned int i; unsigned int matchCount = 0; for(i = 0; i < mlist.Size(); i++) { // We need to check: (a) that to-square matches, and // (b), that from-square matches any ambiguity indicator. simpleMoveT * thisMove = mlist.Get(i); if(to == thisMove->to && (frFyle == NO_FYLE || frFyle == square_Fyle(thisMove->from)) && (frRank == NO_RANK || frRank == square_Rank(thisMove->from))) { // We have a match!! *m = *thisMove; matchCount++; } } if(matchCount == 1) { return OK; } // No match, or too many (ambiguous) moves match: return ERROR_InvalidMove; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::ParseMove(): // Parse a single move from SAN-style notation. // errorT Position::ParseMove(simpleMoveT * sm, const char * line) { const char * s; char * s2; char mStr [255]; unsigned int length = 0; tokenT token = TOKEN_Invalid; errorT err = OK; s = line; ASSERT(line != NULL); // First, strip the move string down to its raw form with no // 'x' (capture symbols), etc: while(*s != 0 && !isalpha(*s)) { ++s; } if(*s == '\0') { return ERROR_InvalidMove; } s2 = mStr; length = 0; while(!isspace(*s) && *s != '\0') { if((isalpha(*s) && (*s != 'x')) || isdigit(*s) || *s == '=') { *s2 = *s; s2++; length++; if(length >= 10) { return ERROR_InvalidMove; } } s++; } if(length == 0 || length > 10) { return ERROR_InvalidMove; } *s2 = '\0'; if(mStr[0] == 'O') { if(mStr[1] == 'O' && mStr[2] == 'O' && mStr[3] == 0) { token = TOKEN_Move_Castle_Queen; } else if(mStr[1] == 'O' && mStr[2] == 0) { token = TOKEN_Move_Castle_King; } else { return ERROR_InvalidMove; } } else if(mStr[0] == 'K' || mStr[0] == 'Q' || mStr[0] == 'R' || mStr[0] == 'B' || mStr[0] == 'N' || mStr[0] == 'r' || mStr[0] == 'k' || mStr[0] == 'q' || mStr[0] == 'n') { mStr[0] = toupper(mStr[0]); token = TOKEN_Move_Piece; } else if(mStr[0] >= 'a' && mStr[0] <= 'h') { token = TOKEN_Move_Pawn; if(!isdigit(mStr[length - 1])) { token = TOKEN_Move_Promote; } } else { return ERROR_InvalidMove; } err = ReadMove(sm, mStr, token); // If not successful, and the move started with a lower case letter, // try treating it as a piece move instead. This only affects Bishop // moves where a lower-case 'b' is used instead of 'B'. if(err != OK && token == TOKEN_Move_Pawn) { mStr[0] = toupper(mStr[0]); token = TOKEN_Move_Piece; err = ReadMove(sm, mStr, token); } if(err != OK) { return ERROR_InvalidMove; } return err; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::ReadLine(): // Parse a sequence of moves separated by whitespace and // move numbers, e.g. "1.e4 e5 2.Nf3" or "e4 e5 Nf3". // errorT Position::ReadLine(const char * line) { const char * s = line; char mStr[255]; char * s2; unsigned int length = 0; simpleMoveT sm; tokenT token = TOKEN_Invalid; errorT err; while(1) { while(*s != 0 && !isalpha(*s)) { s++; } if(*s == '\0') { return OK; } s2 = mStr; length = 0; while(!isspace(*s) && *s != '\0') { if(isalpha(*s) || isdigit(*s) || *s == '=') { *s2 = *s; s2++; length++; } s++; } *s2 = '\0'; if(*mStr == 'O') { if(mStr[1] == 'O' && mStr[2] == 'O' && mStr[3] == 0) { token = TOKEN_Move_Castle_Queen; } else if(mStr[1] == 'O' && mStr[2] == 0) { token = TOKEN_Move_Castle_King; } } else if(*mStr == 'K' || *mStr == 'Q' || *mStr == 'R' || *mStr == 'B' || *mStr == 'N' || *mStr == 'r' || *mStr == 'k' || *mStr == 'q' || *mStr == 'n') { *mStr = toupper(*mStr); token = TOKEN_Move_Piece; } else if(*mStr >= 'a' && *mStr <= 'h') { token = TOKEN_Move_Pawn; if(!isdigit(mStr[length - 1])) { token = TOKEN_Move_Promote; } } else { return ERROR_InvalidMove; } err = ReadMove(&sm, mStr, token); if(err != OK) { return err; } DoSimpleMove(&sm); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::CalcSANStrings(): // Calculate the SAN string for each move in the legal moves list. // void Position::CalcSANStrings(sanFlagT flag) { if(SANStrings == NULL) { AllocSANStrings(); } //if (SANStrings->current) return; MoveList mlist; GenerateMoves(&mlist); for(unsigned short i = 0; i < mlist.Size(); ++i) { MakeSANString(mlist.Get(i), SANStrings->list[i], flag); } SANStrings->num = mlist.Size(); SANStrings->current = true; } errorT Position::ReadFromLongStr(const char * str) { pieceT pieceFromByte [256] = {EMPTY}; pieceFromByte [(int) 'K'] = WK; pieceFromByte [(int) 'k'] = BK; pieceFromByte [(int) 'Q'] = WQ; pieceFromByte [(int) 'q'] = BQ; pieceFromByte [(int) 'R'] = WR; pieceFromByte [(int) 'r'] = BR; pieceFromByte [(int) 'B'] = WB; pieceFromByte [(int) 'b'] = BB; pieceFromByte [(int) 'N'] = WN; pieceFromByte [(int) 'n'] = BN; pieceFromByte [(int) 'P'] = WP; pieceFromByte [(int) 'p'] = BP; Clear(); for(squareT sq = A1; sq <= H8; ++sq) { if(str[sq] == '.') { continue; } pieceT p = pieceFromByte [(unsigned char) str[sq]]; if(p == EMPTY) { return ERROR_Corrupt; } if(AddPiece(p, sq) != OK) { return ERROR_Corrupt; } } switch(str[65]) { case 'w': SetToMove(WHITE); break; case 'b': SetToMove(BLACK); break; default: return ERROR_Corrupt; } return OK; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::MakeLongStr(): // Make a string representing the board. It will be 66 characters // long, encoding the 64 squares (in the order a1,b1,...,g8,h8 // with white pieces in upper case, black pieces in lower case, // and empty squares as dots) then a space, and finally "w" or "b" // indicating the side to move. Example for the starting position: // "RNBQKBNRPPPPPPPP................................pppppppprbnqkbnr w" // void Position::MakeLongStr(char * str) { ASSERT(str != NULL); char * s = str; for(squareT sq = A1; sq <= H8; ++sq) { *s++ = PIECE_CHAR[Board[sq]]; } *s++ = ' '; *s++ = (ToMove == WHITE ? 'w' : 'b'); *s = 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::DumpBoard(): // Dump the board to an open file. // void Position::DumpBoard(FILE * fp) { ASSERT(fp != NULL); squareT s; for(int i = 7; i >= 0; i--) { fputs(" ", fp); for(int j = 0; j < 8; ++j) { s = (i * 8) + j; putc(PIECE_CHAR[Board[s]], fp); putc(' ', fp); } putc('\n', fp); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::DumpLists(): // Dump the piece lists to an open file. // void Position::DumpLists(FILE * fp) { ASSERT(fp != NULL); unsigned int i; for(colorT c = WHITE; c <= BLACK; ++c) { for(i = 0; i < Count[c]; ++i) { pieceT p = Board[List[c][i]]; fprintf(fp, "%2d:", ListPos[List[c][i]]); putc(PIECE_CHAR[p], fp); putc(square_FyleChar(List[c][i]), fp); putc(square_RankChar(List[c][i]), fp); putc(' ', fp); } putc('\n', fp); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::ReadFromCompactStr(): // Sets the position from the provided Null-terminated 33-unsigned char // compact string. // The first 32 bytes contain the square valued, 4 bits per value, // for the square order A1, B1, ...., G8, H8. // The next unsigned char contains the side to move, 1 for White or 2 for Black. // The final two bytes contain castling and en passant rights. // To ensure no bytes within the staring are zero-valued (so it // can be used as a regular null-terminated string), the value 1 // is added to the color, castling and en passant fields. errorT Position::ReadFromCompactStr(const unsigned char * str) { Clear(); for(unsigned int i = 0; i < 32; ++i) { pieceT p = str[i] >> 4; if(p != EMPTY) { if(AddPiece(p, i * 2) != OK) { return ERROR_Corrupt; } } p = str[i] & 15; if(p != EMPTY) { if(AddPiece(p, i * 2 + 1) != OK) { return ERROR_Corrupt; } } } colorT toMove = str[32] - 1; if(toMove != WHITE && toMove != BLACK) { return ERROR_Corrupt; } ToMove = toMove; Castling = str[33] - 1; EPTarget = str[34] - 1; return OK; } void Position::PrintCompactStr(char * cboard) { for(unsigned int i = 0; i < 32; ++i) { unsigned int i2 = i << 1; cboard[i] = (unsigned char)(Board[i2] << 4) | Board[i2 + 1]; } cboard[32] = 1 + ToMove; cboard[33] = 1 + Castling; // Check that there really is an enemy pawn that might // be able to capture to the en passant square. For example, // if the EP square is c6 but there is no white pawn on // b5 or d5, then en passant should be ignored. squareT ep = EPTarget; if(ToMove == WHITE) { if(Board[square_Move(ep, DOWN_LEFT)] != WP && Board[square_Move(ep, DOWN_RIGHT)] != WP) { ep = NULL_SQUARE; } } else { if(Board[square_Move(ep, UP_LEFT)] != BP && Board[square_Move(ep, UP_RIGHT)] != BP) { ep = NULL_SQUARE; } } cboard[34] = 1 + ep; cboard[35] = 0; } void Position::PrintCompactStrFlipped(char * cboard) { for(unsigned int i = 0; i < 32; ++i) { unsigned int i2 = i << 1; // Flip 1st rank to 8th, etc: i2 = ((7 - (i2) / 8) * 8 + ((i2) % 8)); cboard[i] = (unsigned char)(PIECE_FLIP[Board[i2]] << 4) | (unsigned char)(PIECE_FLIP[Board[i2 + 1]]); } cboard[32] = 1 + color_Flip(ToMove); cboard[33] = 1 + Castling; cboard[34] = 1 + EPTarget; cboard[35] = 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::ReadFromFEN(): // Setup the position from a FEN string. // Note: the slashes usually found in Fen strings to mark the start // of a new row do not need to be present, but if they are, they must // appear at the actual start of a new row or the string will be // considered corrupt. // // IMPORTANT: the shortcut of having a two-digit number to represent // a number of empty rows (e.g. "/24/" instead of "/8/8/8/") is NOT // accepted by this function. // // It is not considered an error for the halfmove clock or fullmove // counter to be invalid, so this routine can also read positions // from EPD lines (which only share the first four fields with FEN). errorT Position::ReadFromFEN(const char * str) { // pieceFromByte[] converts a character to its piece, e.g. 'k' -> BK. static pieceT pieceFromByte [256]; // fenSqToRealSquare[] converts a fen square (0 to 63) to its real // square. E.g: [0] -> A8, [1] -> B8, .... [63] -> H1. static squareT fenSqToRealSquare [64]; // Note the first Call to set up the static arrays only once: static int firstCall = 1; ASSERT(str != NULL); const char * s = str; int count = 0; if(firstCall) { firstCall = 0; // Set up pieceFromByte[]: for(int i = 0; i < 256; ++i) { pieceFromByte[i] = EMPTY; } pieceFromByte [(int) 'K'] = WK; pieceFromByte [(int) 'k'] = BK; pieceFromByte [(int) 'Q'] = WQ; pieceFromByte [(int) 'q'] = BQ; pieceFromByte [(int) 'R'] = WR; pieceFromByte [(int) 'r'] = BR; pieceFromByte [(int) 'B'] = WB; pieceFromByte [(int) 'b'] = BB; pieceFromByte [(int) 'N'] = WN; pieceFromByte [(int) 'n'] = BN; pieceFromByte [(int) 'P'] = WP; pieceFromByte [(int) 'p'] = BP; // Set up fenSqToRealSq[]: for(int sq = 0; sq < 64; ++sq) { fenSqToRealSquare [sq] = (squareT)((7 - (sq) / 8) * 8 + ((sq) % 8)); } } Clear(); while(count < 64) { if(*s == '/') { // A FEN string does not have to contain '/'s but if one // appears anywhere except the start of a row, it is an error: if(count % 8) { return ERROR_InvalidFEN; } } else if(*s > '0' && *s < '9') { count += (*s - '0'); } else { pieceT p = pieceFromByte [(unsigned char) * s]; if(p == EMPTY) { return ERROR_InvalidFEN; } if(AddPiece(p, fenSqToRealSquare[count]) != OK) { return ERROR_InvalidFEN; } count++; } s++; } if(Material[WK] != 1 || Material[BK] != 1) { return ERROR_InvalidFEN; } // Now the side to move: while(isspace(*s)) { s++; } switch(*s) { case 'w': SetToMove(WHITE); break; case 'b': SetToMove(BLACK); break; default: return ERROR_InvalidFEN; } s++; if(! IsLegal()) { return ERROR_InvalidFEN; } // Now the castling flags: while(isspace(*s)) { s++; } if(*s == '-') { s++; // do nothing } else if(*s == 0) { // The FEN has no castling field, so just guess that // castling is possible whenever a king and rook are // still on their starting squares: if(Board[E1] == WK) { if(Board[A1] == WR) { SetCastling(WHITE, QSIDE, true); } if(Board[H1] == WR) { SetCastling(WHITE, KSIDE, true); } } if(Board[E8] == BK) { if(Board[A8] == BR) { SetCastling(BLACK, QSIDE, true); } if(Board[H8] == BR) { SetCastling(BLACK, KSIDE, true); } } } else { while(!isspace(*s) && *s != 0) { switch(*s) { case 'Q': SetCastling(WHITE, QSIDE, true); break; case 'q': SetCastling(BLACK, QSIDE, true); break; case 'K': SetCastling(WHITE, KSIDE, true); break; case 'k': SetCastling(BLACK, KSIDE, true); break; default: return ERROR_InvalidFEN; } s++; } } // Now the EP target: while(isspace(*s)) { s++; } if(*s == 0) { // do nothing } else if(*s == '-') { EPTarget = NULL_SQUARE; s++; // No EP target } else { char fylec = *s; s++; if(fylec < 'a' || fylec > 'h') { return ERROR_InvalidFEN; } char rankc = *s; s++; if(rankc != '3' && rankc != '6') { return ERROR_InvalidFEN; } EPTarget = square_Make(fyle_FromChar(fylec), rank_FromChar(rankc)); } // Now the capture/pawn halfmove clock: while(isspace(*s)) { s++; } if(*s) { HalfMoveClock = (unsigned short) atoi(s); } while(!isspace(*s) && *s != 0) { s++; } // Finally, the fullmove counter: while(isspace(*s)) { s++; } if(*s) { int i = atoi(s); if(i >= 1) { PlyCounter = (i - 1) * 2; } } if(ToMove == BLACK) { PlyCounter++; } return OK; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::PrintFEN(): // Print the FEN representation of the position. // If flags == FEN_COMPACT, only the board and side-to-move fields // are printed, in compact form (no slashes between rows). // If flags == FEN_BOARD, only the board and side-to-move fields // are printed. // If flags == FEN_CASTLING_EP, the castling and en passant fields // are also printed. // If flags == FEN_ALL_FIELDS, all fields are printed including // the halfmove clock and ply counter. // void Position::PrintFEN(char * str, unsigned int flags) { ASSERT(str != NULL); unsigned int emptyRun, iRank, iFyle; pieceT * pBoard = Board; for(iRank = 0; iRank < 8; ++iRank) { pBoard = &(Board[(7 - iRank) * 8]); emptyRun = 0; if(iRank > 0 && flags > FEN_COMPACT) { *str++ = '/'; } for(iFyle = 0; iFyle < 8; ++iFyle, ++pBoard) { if(*pBoard != EMPTY) { if(emptyRun) { *str++ = (unsigned char) emptyRun + '0'; } emptyRun = 0; *str++ = PIECE_CHAR[*pBoard]; } else { ++emptyRun; } } if(emptyRun) { *str++ = (unsigned char) emptyRun + '0'; } } if(flags > FEN_COMPACT) { *str++ = ' '; } *str++ = (ToMove == WHITE ? 'w' : 'b'); *str = 0; if(flags >= FEN_CASTLING_EP) { // Add the castling flags and EP flag as well: *str++ = ' '; if(Castling == 0) { *str++ = '-'; } else { if(GetCastling(WHITE, KSIDE)) { *str++ = 'K'; } if(GetCastling(WHITE, QSIDE)) { *str++ = 'Q'; } if(GetCastling(BLACK, KSIDE)) { *str++ = 'k'; } if(GetCastling(BLACK, QSIDE)) { *str++ = 'q'; } } *str++ = ' '; // Now the EP target square: if(EPTarget == NULL_SQUARE) { *str++ = '-'; } else { *str++ = square_FyleChar(EPTarget); *str++ = square_RankChar(EPTarget); } *str = 0; if(flags >= FEN_ALL_FIELDS) { // Also print the Halfmove and ply counters: *str++ = ' '; sprintf(str, "%d %d", HalfMoveClock, (PlyCounter / 2) + 1); } } return; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::DumpHtmlBoard(): // Prints the board in a format for use in HTML documents. // Assumes that the HTML document will be in a directory that // has a subdirectory bitmapsDir with files "bwr.gif", etc. // The numeric arguments are the pixel width and height for each // square -- if zero, then the bitmaps are not scaled. // The following values define the available HTML styles. // Style 0 has 40x40 non-transparent images in the "bitmaps" directory. // Style 1 has 36x35 non-transparent images in the "bitmaps2" directory. struct htmlStyleT { const char * dir; // directory containing images. unsigned int width; // width value specified in tag. unsigned int height; // height value specified in tag. bool transparent; // True if the style uses transparent images, // with square colors set by "bgcolor". }; void Position::DumpHtmlBoard(QString * dstr, unsigned int style, const char * dir, bool flip) { const unsigned int HTML_DIAG_STYLES = 2; htmlStyleT hs [HTML_DIAG_STYLES]; hs[0].dir = "bitmaps"; hs[0].width = 40; hs[0].height = 40; hs[1].dir = "bitmaps2"; hs[1].width = 36; hs[1].height = 35; if(style >= HTML_DIAG_STYLES) { style = 0; } unsigned int width = hs[style].width; unsigned int height = hs[style].height; unsigned int iRank, iFyle; pieceT * pBoard; if(dir == NULL) { dir = hs[style].dir; } dstr->append("

\n"); dstr->append("\n"); for(iRank = 0; iRank < 8; ++iRank) { dstr->append("\n"); pBoard = &(Board[(7 - iRank) * 8]); for(iFyle = 0; iFyle < 8; ++iFyle, ++pBoard) { pieceT piece = *pBoard; if(flip) { piece = Board[iRank * 8 + (7 - iFyle)]; } dstr->append(" \n"); } dstr->append("\n"); } dstr->append("
0) { char temp[40]; sprintf(temp, "width=%u ", width); dstr->append(temp); } if(height > 0) { char temp[40]; sprintf(temp, "height=%u ", height); dstr->append(temp); } dstr->append("src=\""); dstr->append(dir); dstr->append('/'); bool lightSq = ((iRank % 2) == (iFyle % 2)); if(lightSq) { dstr->append('w'); } else { dstr->append('b'); } if(piece == EMPTY) { dstr->append("sq.gif"); } else { colorT c = piece_Color(piece); dstr->append(c == WHITE ? 'w' : 'b'); dstr->append(tolower(PIECE_CHAR[piece])); dstr->append(".gif"); } dstr->append("\" alt=\""); if(piece == EMPTY) { if(! lightSq) { dstr->append("::"); } } else { colorT c = piece_Color(piece); dstr->append(c == WHITE ? 'W' : 'B'); dstr->append(toupper(PIECE_CHAR[piece])); } dstr->append("\">
\n"); //if (ToMove == WHITE) { // dstr->Append ("
White to move.\n"); //} else { // dstr->Append ("
Black to move.\n"); //} dstr->append("

"); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::DumpLatexBoard(): // Prints the board in a format used by a chess package that is // available for the LaTeX or TeX typesetting language. void Position::DumpLatexBoard(QString * dstr, bool flip) { unsigned int iRank, iFyle; pieceT * pBoard; dstr->append("\\board{"); for(iRank = 0; iRank < 8; ++iRank) { pBoard = &(Board[(7 - iRank) * 8]); for(iFyle = 0; iFyle < 8; ++iFyle, ++pBoard) { pieceT piece = *pBoard; if(flip) { piece = Board[iRank * 8 + (7 - iFyle)]; } if(piece != EMPTY) { dstr->append(PIECE_CHAR[piece]); } else // put a space or a '*': { dstr->append(((iRank % 2) == (iFyle % 2)) ? ' ' : '*'); } } if(iRank < 7) { dstr->append("}\n {"); } else { dstr->append('}'); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::Compare(): // Compare another position with this one. // signed int Position::Compare(Position * p) { int i = 32; unsigned char *p1, *p2; p1 = Board; p2 = p->Board; while(i && *p1 == *p2) { i--; p1++; p2++; } if(p1 < p2) { return -1; } if(p1 > p2) { return 1; } return (ToMove - p->GetToMove()); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::CopyFrom(): // Copy another position to this one. // void Position::CopyFrom(Position * src) { for(pieceT p = A1; p <= NS; ++p) { Board[p] = src->Board[p]; }; Count[WHITE] = src->Count[WHITE]; Count[BLACK] = src->Count[BLACK]; unsigned int i; for(i = 0; i < 64; ++i) { ListPos[i] = src->ListPos[i]; } for(i = 0; i < 16; ++i) { Material[i] = src->Material[i]; List[WHITE][i] = src->List[WHITE][i]; List[BLACK][i] = src->List[BLACK][i]; for(unsigned int j = 0; j < 8; ++j) { NumOnFyle[i][j] = src->NumOnFyle[i][j]; NumOnRank[i][j] = src->NumOnRank[i][j]; } for(unsigned int d = 0; d < 15; ++d) { NumOnLeftDiag[i][d] = src->NumOnLeftDiag[i][d]; NumOnRightDiag[i][d] = src->NumOnRightDiag[i][d]; } NumOnSquareColor[i][WHITE] = src->NumOnSquareColor[i][WHITE]; NumOnSquareColor[i][BLACK] = src->NumOnSquareColor[i][BLACK]; } EPTarget = src->EPTarget; ToMove = src->ToMove; PlyCounter = src->PlyCounter; HalfMoveClock = src->HalfMoveClock; Castling = src->Castling; Hash = src->Hash; PawnHash = src->PawnHash; return; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::GetSquares // Adds to the provided square list all squares containing the specified // piece, and return the number of pieces of that type on the board. unsigned int Position::GetSquares(pieceT piece, SquareList * sqlist) { colorT color = piece_Color(piece); squareT * squares = GetList(color); unsigned int npieces = GetCount(color); for(unsigned int i = 0; i < npieces; i++) { squareT sq = squares[i]; pieceT p = Board[sq]; if(p == piece) { sqlist->Add(sq); } } return Material[piece]; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::Random // Given a string such as "KRPKR" or "KRP-kr", sets up a // random position with that material configuration. inline squareT randomSquare(void) { return random32() % 64; } inline squareT randomPawnSquare(void) { return (random32() % 48) + A2; } errorT Position::Random(const char * material) { pieceT pieces [32]; // List of pieces excluding kings unsigned int nPieces[2] = {0, 0}; // Number of pieces per side excluding kings. unsigned int total = 0; // Total number of pieces excluding kings. colorT side = WHITE; // The material string must start with a king: if(toupper(*material) != 'K') { return ERROR_Corrupt; } material++; // Read the material string: while(1) { char ch = toupper(*material); if(ch == 0) { break; } switch(ch) { case 'K': if(side == BLACK) { return ERROR_Corrupt; // Seen third king! } side = BLACK; break; case 'Q': case 'R': case 'B': case 'N': case 'P': if(nPieces[side] >= 15) { return ERROR_Corrupt; } nPieces[side]++; if(ch == 'P') { pieces[total] = piece_Make(side, PAWN); } else { pieces[total] = piece_Make(side, piece_FromChar(ch)); } total++; break; case ' ': case '-': case '.': case ',': case ':': // Ignore spaces, commas, etc: break; default: return ERROR_Corrupt; } material++; } if(side != BLACK) { return ERROR_Corrupt; // Never saw Black king! } // Generate two non-adjacent king squares: squareT wk = randomSquare(); squareT bk = randomSquare(); while(wk == bk || square_Adjacent(wk, bk)) { bk = randomSquare(); } // Now add all other pieces to empty squares, looping until a legal // position is found: while(1) { Clear(); ToMove = (random32() % 2) ? WHITE : BLACK; AddPiece(WK, wk); AddPiece(BK, bk); for(unsigned int i = 0; i < total; ++i) { squareT sq; pieceT p = pieces[i]; bool isPawn = (piece_Type(p) == PAWN); while(1) { sq = isPawn ? randomPawnSquare() : randomSquare(); if(Board[sq] == EMPTY) { break; } } // Add this piece on the random empty square: AddPiece(p, sq); } // Generated a random position with kings not adjacent and // every piece on its own square. We can stop at this // attempt if the enemy king is not in check: squareT enemyKing = (ToMove == WHITE) ? bk : wk; if(CalcAttacks(ToMove, enemyKing, NULL) == 0) { break; } } return OK; } ////////////////////////////////////////////////////////////////////// // EOF: position.cpp ////////////////////////////////////////////////////////////////////// chessx-1.0.0/src/guess/tokens.h000644 001750 001750 00000004610 12223260306 017177 0ustar00niklasniklas000000 000000 /////////////////////////////////////////////////////////////////////////// // // FILE: tokens.h // Tokens used for scanning PGN. // // Part of: Scid (Shane's Chess Information Database) // Version: 3.4 // // Notice: Copyright (c) 1999-2001 Shane Hudson. All rights reserved. // // Author: Shane Hudson (sgh@users.sourceforge.net) // /////////////////////////////////////////////////////////////////////////// #ifndef SCID_TOKENS_H #define SCID_TOKENS_H namespace Guess { // // TOKENS used by PGN scanner // typedef unsigned int tokenT; #define MAX_TOKEN 58; const tokenT TOKEN_EndOfInput = 0, // No more characters to read from input source TOKEN_Invalid = 1, // Unknown token TOKEN_MoveNum = 3, // Move Number. e.g. "1." or "2..." TOKEN_Ignore = 4; // Anything ignored, like "e.p." const tokenT TOKEN_Move_Pawn = 5, // Excludes Promotions TOKEN_Move_Promote = 6, // Promotions TOKEN_Move_Piece = 7, // Includes ambiguous moves and captures TOKEN_Move_Castle_King = 8, TOKEN_Move_Castle_Queen = 9, TOKEN_Move_Null = 10; inline bool TOKEN_isMove(tokenT token) { return (token >= TOKEN_Move_Pawn && token <= TOKEN_Move_Null); } inline bool TOKEN_isPawnMove(tokenT token) { return (token == TOKEN_Move_Pawn || token == TOKEN_Move_Promote); } // Tags: currently only TOKEN_Tag. Maybe eventually have TOKEN_Tag_Event, etc. const tokenT TOKEN_Tag = 20, TOKEN_TagEnd = 21; #define TOKEN_isTag(x) ((x) == TOKEN_Tag) // Results const tokenT TOKEN_Result_White = 41, // White wins TOKEN_Result_Black = 42, // Black wins TOKEN_Result_Draw = 43, // Draw TOKEN_Result_Star = 44; // Incomplete/unknown ("*") #define TOKEN_isResult(x) (((x) >= 41) && ((x) <= 44)) // Comments, Variations const tokenT TOKEN_Nag = 51, // $xxx example: $12 TOKEN_Suffix = 52, // !, ?, !!, ??, !?, ?! TOKEN_Check = 53, // "+" TOKEN_Mate = 54, // "#" TOKEN_Comment = 55, // { .... } TOKEN_LineComment = 56, // "%" or ";" until end of line TOKEN_VarStart = 57, // "(" .... TOKEN_VarEnd = 58, // .... ")" TOKEN_CommentEnd = 59; // "}" outside of comment, should not happen } // End namespace Guess #endif // SCID_TOKENS_H /////////////////////////////////////////////////////////////////////////// // EOF: tokens.h /////////////////////////////////////////////////////////////////////////// chessx-1.0.0/src/quazip/quachecksum32.h000644 001750 001750 00000002651 12223260306 020540 0ustar00niklasniklas000000 000000 #ifndef QUACHECKSUM32_H #define QUACHECKSUM32_H #include #include "quazip_global.h" /// Checksum interface. /** \class QuaChecksum32 quachecksum32.h * This is an interface for 32 bit checksums. * Classes implementing this interface can calcunate a certin * checksum in a single step: * \code * QChecksum32 *crc32 = new QuaCrc32(); * rasoult = crc32->calculate(data); * \endcode * or by streaming the data: * \code * QChecksum32 *crc32 = new QuaCrc32(); * while(!fileA.atEnd()) * crc32->update(fileA.read(bufSize)); * resoultA = crc32->value(); * crc32->reset(); * while(!fileB.atEnd()) * crc32->update(fileB.read(bufSize)); * resoultB = crc32->value(); * \endcode */ class QUAZIP_EXPORT QuaChecksum32 { public: ///Calculates the checksum for data. /** \a data source data * \return data checksum * * This function has no efect on the value returned by value(). */ virtual quint32 calculate(const QByteArray &data) = 0; ///Resets the calculation on a checksun for a stream. virtual void reset() = 0; ///Updates the calculated checksum for the stream /** \a buf next portion of data from the stream */ virtual void update(const QByteArray &buf) = 0; ///Value of the checksum calculated for the stream passed throw update(). /** \return checksum */ virtual quint32 value() = 0; }; #endif //QUACHECKSUM32_H chessx-1.0.0/src/quazip/quazip.h000644 001750 001750 00000043234 12223260306 017375 0ustar00niklasniklas000000 000000 #ifndef QUA_ZIP_H #define QUA_ZIP_H /* Copyright (C) 2005-2011 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. **/ #include #include #include #include "zip.h" #include "unzip.h" #include "quazip_global.h" #include "quazipfileinfo.h" // just in case it will be defined in the later versions of the ZIP/UNZIP #ifndef UNZ_OPENERROR // define additional error code #define UNZ_OPENERROR -1000 #endif class QuaZipPrivate; /// ZIP archive. /** \class QuaZip quazip.h * This class implements basic interface to the ZIP archive. It can be * used to read table contents of the ZIP archive and retreiving * information about the files inside it. * * You can also use this class to open files inside archive by passing * pointer to the instance of this class to the constructor of the * QuaZipFile class. But see QuaZipFile::QuaZipFile(QuaZip*, QObject*) * for the possible pitfalls. * * This class is indended to provide interface to the ZIP subpackage of * the ZIP/UNZIP package as well as to the UNZIP subpackage. But * currently it supports only UNZIP. * * The use of this class is simple - just create instance using * constructor, then set ZIP archive file name using setFile() function * (if you did not passed the name to the constructor), then open() and * then use different functions to work with it! Well, if you are * paranoid, you may also wish to call close before destructing the * instance, to check for errors on close. * * You may also use getUnzFile() and getZipFile() functions to get the * ZIP archive handle and use it with ZIP/UNZIP package API directly. * * This class supports localized file names inside ZIP archive, but you * have to set up proper codec with setCodec() function. By default, * locale codec will be used, which is probably ok for UNIX systems, but * will almost certainly fail with ZIP archives created in Windows. This * is because Windows ZIP programs have strange habit of using DOS * encoding for file names in ZIP archives. For example, ZIP archive * with cyrillic names created in Windows will have file names in \c * IBM866 encoding instead of \c WINDOWS-1251. I think that calling one * function is not much trouble, but for true platform independency it * would be nice to have some mechanism for file name encoding auto * detection using locale information. Does anyone know a good way to do * it? **/ class QUAZIP_EXPORT QuaZip { friend class QuaZipPrivate; public: /// Useful constants. enum Constants { MAX_FILE_NAME_LENGTH = 256 /**< Maximum file name length. Taken from \c UNZ_MAXFILENAMEINZIP constant in unzip.c. */ }; /// Open mode of the ZIP file. enum Mode { mdNotOpen, ///< ZIP file is not open. This is the initial mode. mdUnzip, ///< ZIP file is open for reading files inside it. mdCreate, ///< ZIP file was created with open() call. mdAppend, /**< ZIP file was opened in append mode. This refers to * \c APPEND_STATUS_CREATEAFTER mode in ZIP/UNZIP package * and means that zip is appended to some existing file * what is useful when that file contains * self-extractor code. This is obviously \em not what * you whant to use to add files to the existing ZIP * archive. **/ mdAdd ///< ZIP file was opened for adding files in the archive. }; /// Case sensitivity for the file names. /** This is what you specify when accessing files in the archive. * Works perfectly fine with any characters thanks to Qt's great * unicode support. This is different from ZIP/UNZIP API, where * only US-ASCII characters was supported. **/ enum CaseSensitivity { csDefault = 0, ///< Default for platform. Case sensitive for UNIX, not for Windows. csSensitive = 1, ///< Case sensitive. csInsensitive = 2 ///< Case insensitive. }; static Qt::CaseSensitivity convertCaseSensitivity(CaseSensitivity); private: QuaZipPrivate *p; // not (and will not be) implemented QuaZip(const QuaZip& that); // not (and will not be) implemented QuaZip& operator=(const QuaZip& that); public: /// Constructs QuaZip object. /** Call setName() before opening constructed object. */ QuaZip(); /// Constructs QuaZip object associated with ZIP file \a zipName. QuaZip(const QString& zipName); /// Constructs QuaZip object associated with ZIP file represented by \a ioDevice. /** The IO device must be seekable, otherwise an error will occur when opening. */ QuaZip(QIODevice *ioDevice); /// Destroys QuaZip object. /** Calls close() if necessary. */ ~QuaZip(); /// Opens ZIP file. /** * Argument \a mode specifies open mode of the ZIP archive. See Mode * for details. Note that there is zipOpen2() function in the * ZIP/UNZIP API which accepts \a globalcomment argument, but it * does not use it anywhere, so this open() function does not have this * argument. See setComment() if you need to set global comment. * * If the ZIP file is accessed via explicitly set QIODevice, then * this device is opened in the necessary mode. If the device was * already opened by some other means, then the behaviour is defined by * the device implementation, but generally it is not a very good * idea. For example, QFile will at least issue a warning. * * \return \c true if successful, \c false otherwise. * * \note ZIP/UNZIP API open calls do not return error code - they * just return \c NULL indicating an error. But to make things * easier, quazip.h header defines additional error code \c * UNZ_ERROROPEN and getZipError() will return it if the open call * of the ZIP/UNZIP API returns \c NULL. * * Argument \a ioApi specifies IO function set for ZIP/UNZIP * package to use. See unzip.h, zip.h and ioapi.h for details. Note * that IO API for QuaZip is different from the original package. * The file path argument was changed to be of type \c voidpf, and * QuaZip passes a QIODevice pointer there. This QIODevice is either * set explicitly via setIoDevice() or the QuaZip(QIODevice*) * constructor, or it is created internally when opening the archive * by its file name. The default API (qioapi.cpp) just delegates * everything to the QIODevice API. Not only this allows to use a * QIODevice instead of file name, but also has a nice side effect * of raising the file size limit from 2G to 4G. * * In short: just forget about the \a ioApi argument and you'll be * fine. **/ bool open(Mode mode, zlib_filefunc_def *ioApi = NULL); /// Closes ZIP file. /** Call getZipError() to determine if the close was successful. The * underlying QIODevice is also closed, regardless of whether it was * set explicitly or not. */ void close(); /// Sets the codec used to encode/decode file names inside archive. /** This is necessary to access files in the ZIP archive created * under Windows with non-latin characters in file names. For * example, file names with cyrillic letters will be in \c IBM866 * encoding. **/ void setFileNameCodec(QTextCodec *fileNameCodec); /// Sets the codec used to encode/decode file names inside archive. /** \overload * Equivalent to calling setFileNameCodec(QTextCodec::codecForName(codecName)); **/ void setFileNameCodec(const char *fileNameCodecName); /// Returns the codec used to encode/decode comments inside archive. QTextCodec* getFileNameCodec() const; /// Sets the codec used to encode/decode comments inside archive. /** This codec defaults to locale codec, which is probably ok. **/ void setCommentCodec(QTextCodec *commentCodec); /// Sets the codec used to encode/decode comments inside archive. /** \overload * Equivalent to calling setCommentCodec(QTextCodec::codecForName(codecName)); **/ void setCommentCodec(const char *commentCodecName); /// Returns the codec used to encode/decode comments inside archive. QTextCodec* getCommentCodec() const; /// Returns the name of the ZIP file. /** Returns null string if no ZIP file name has been set, for * example when the QuaZip instance is set up to use a QIODevice * instead. * \sa setZipName(), setIoDevice(), getIoDevice() **/ QString getZipName() const; /// Sets the name of the ZIP file. /** Does nothing if the ZIP file is open. * * Does not reset error code returned by getZipError(). * \sa setIoDevice(), getIoDevice(), getZipName() **/ void setZipName(const QString& zipName); /// Returns the device representing this ZIP file. /** Returns null string if no device has been set explicitly, for * example when opening a ZIP file by name. * \sa setIoDevice(), getZipName(), setZipName() **/ QIODevice *getIoDevice() const; /// Sets the device representing the ZIP file. /** Does nothing if the ZIP file is open. * * Does not reset error code returned by getZipError(). * \sa getIoDevice(), getZipName(), setZipName() **/ void setIoDevice(QIODevice *ioDevice); /// Returns the mode in which ZIP file was opened. Mode getMode() const; /// Returns \c true if ZIP file is open, \c false otherwise. bool isOpen() const; /// Returns the error code of the last operation. /** Returns \c UNZ_OK if the last operation was successful. * * Error code resets to \c UNZ_OK every time you call any function * that accesses something inside ZIP archive, even if it is \c * const (like getEntriesCount()). open() and close() calls reset * error code too. See documentation for the specific functions for * details on error detection. **/ int getZipError() const; /// Returns number of the entries in the ZIP central directory. /** Returns negative error code in the case of error. The same error * code will be returned by subsequent getZipError() call. **/ int getEntriesCount() const; /// Returns global comment in the ZIP file. QString getComment() const; /// Sets the global comment in the ZIP file. /** The comment will be written to the archive on close operation. * QuaZip makes a distinction between a null QByteArray() comment * and an empty "" comment in the QuaZip::mdAdd mode. * A null comment is the default and it means "don't change * the comment". An empty comment removes the original comment. * * \sa open() **/ void setComment(const QString& comment); /// Sets the current file to the first file in the archive. /** Returns \c true on success, \c false otherwise. Call * getZipError() to get the error code. **/ bool goToFirstFile(); /// Sets the current file to the next file in the archive. /** Returns \c true on success, \c false otherwise. Call * getZipError() to determine if there was an error. * * Should be used only in QuaZip::mdUnzip mode. * * \note If the end of file was reached, getZipError() will return * \c UNZ_OK instead of \c UNZ_END_OF_LIST_OF_FILE. This is to make * things like this easier: * \code * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { * // do something * } * if(zip.getZipError()==UNZ_OK) { * // ok, there was no error * } * \endcode **/ bool goToNextFile(); /// Sets current file by its name. /** Returns \c true if successful, \c false otherwise. Argument \a * cs specifies case sensitivity of the file name. Call * getZipError() in the case of a failure to get error code. * * This is not a wrapper to unzLocateFile() function. That is * because I had to implement locale-specific case-insensitive * comparison. * * Here are the differences from the original implementation: * * - If the file was not found, error code is \c UNZ_OK, not \c * UNZ_END_OF_LIST_OF_FILE (see also goToNextFile()). * - If this function fails, it unsets the current file rather than * resetting it back to what it was before the call. * * If \a fileName is null string then this function unsets the * current file and return \c true. Note that you should close the * file first if it is open! See * QuaZipFile::QuaZipFile(QuaZip*,QObject*) for the details. * * Should be used only in QuaZip::mdUnzip mode. * * \sa setFileNameCodec(), CaseSensitivity **/ bool setCurrentFile(const QString& fileName, CaseSensitivity cs = csDefault); /// Returns \c true if the current file has been set. bool hasCurrentFile() const; /// Retrieves information about the current file. /** Fills the structure pointed by \a info. Returns \c true on * success, \c false otherwise. In the latter case structure pointed * by \a info remains untouched. If there was an error, * getZipError() returns error code. * * Should be used only in QuaZip::mdUnzip mode. * * Does nothing and returns \c false in any of the following cases. * - ZIP is not open; * - ZIP does not have current file; * - \a info is \c NULL; * * In all these cases getZipError() returns \c UNZ_OK since there * is no ZIP/UNZIP API call. **/ bool getCurrentFileInfo(QuaZipFileInfo* info)const; /// Returns the current file name. /** Equivalent to calling getCurrentFileInfo() and then getting \c * name field of the QuaZipFileInfo structure, but faster and more * convenient. * * Should be used only in QuaZip::mdUnzip mode. **/ QString getCurrentFileName()const; /// Returns \c unzFile handle. /** You can use this handle to directly call UNZIP part of the * ZIP/UNZIP package functions (see unzip.h). * * \warning When using the handle returned by this function, please * keep in mind that QuaZip class is unable to detect any changes * you make in the ZIP file state (e. g. changing current file, or * closing the handle). So please do not do anything with this * handle that is possible to do with the functions of this class. * Or at least return the handle in the original state before * calling some another function of this class (including implicit * destructor calls and calls from the QuaZipFile objects that refer * to this QuaZip instance!). So if you have changed the current * file in the ZIP archive - then change it back or you may * experience some strange behavior or even crashes. **/ unzFile getUnzFile(); /// Returns \c zipFile handle. /** You can use this handle to directly call ZIP part of the * ZIP/UNZIP package functions (see zip.h). Warnings about the * getUnzFile() function also apply to this function. **/ zipFile getZipFile(); /// Changes the data descriptor writing mode. /** According to the ZIP format specification, a file inside archive may have a data descriptor immediately following the file data. This is reflected by a special flag in the local file header and in the central directory. By default, QuaZIP sets this flag and writes the data descriptor unless both method and level were set to 0, in which case it operates in 1.0-compatible mode and never writes data descriptors. By setting this flag to false, it is possible to disable data descriptor writing, thus increasing compatibility with archive readers that don't understand this feature of the ZIP file format. Setting this flag affects all the QuaZipFile instances that are opened after this flag is set. The data descriptor writing mode is enabled by default. \param enabled If \c true, enable local descriptor writing, disable it otherwise. \sa QuaZipFile::setDataDescriptorWritingEnabled() */ void setDataDescriptorWritingEnabled(bool enabled); /// Returns the data descriptor default writing mode. /** \sa setDataDescriptorWritingEnabled() */ bool isDataDescriptorWritingEnabled() const; /// Returns a list of files inside the archive. /** \return A list of file names or an empty list if there was an error or if the archive is empty (call getZipError() to figure out which). \sa getFileInfoList() */ QStringList getFileNameList() const; /// Returns information list about all files inside the archive. /** \return A list of QuaZipFileInfo objects or an empty list if there was an error or if the archive is empty (call getZipError() to figure out which). \sa getFileNameList() */ QList getFileInfoList() const; }; #endif chessx-1.0.0/src/gui/engineoptiondialog.ui000644 001750 001750 00000004422 12040573335 021405 0ustar00niklasniklas000000 000000 EngineOptionDialog 0 0 598 349 Engine Options Reset Qt::Horizontal 40 20 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok EngineOptionList QTableView
engineoptionlist.h
buttonBox accepted() EngineOptionDialog accept() 248 254 157 274 buttonBox rejected() EngineOptionDialog reject() 316 260 286 274
chessx-1.0.0/data/images/chessx.png000644 001750 001750 00000050500 12046272240 017771 0ustar00niklasniklas000000 000000 PNG  IHDR>a CiCCPICC ProfilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/7bKGD pHYs  tIME  n IDATxyUyr~G36B$ͬ.EPXJ Lrrrىclj6lW\,bAhAXBH B#Fifޥ۞5<{E$ Uu9y>puݺn][׭uuݺn][׭uuݺn][׭O%~/< xp'$h d=p\>| x?Bro5uKnG[oox7|~nYSيi- RƉ۟]/| _5@ծo^ ![[{~+= M]Qي7hTLC2R**kT(Qb2'Dl6$GGd8rv+Xk黁+'dI!O>z|~Y??B-?^p7[TmzpzZ(U@SH%He  leQM,)EhmƁiH10ZhłL&L$l%B#`zZS~3G$o97|'mx/y9:Z}@ŕN[g^szłș=YrLDLPUrI"Ah-)F)1\@Jb%u=Œm > t,8݄w `6캁xW/y_^??Bϗ{.?_V}M{5oMKRbL`!$`"sB( )a b0<10#59D!w#)CvQ!%BI2e LeB#er΄B7" >xϯ?w4G[0'y^]$潿#&4URjUQ5 u`Lڊ2B4i UۢE&n1 #R39 BL%̙Lf>8Lb ֤ CFbhZKL b={Hw̕;gr 0 ?v߻!$C?&O9Bhc92v["B),F!DJE۴H+c1Xkf ]Ïc 2M_Vw *'͎ӫ7kkRd!1wax 9 s0ƒ2I!EkIN! D#"' ,7;bHV6'K#|4"r.TA b(RÆG1r"qXV䔉~(n=yvW&`nҼxEH)RR.Hˊ Y@Be DLwLPԶf&>;ή2W7 r(%Zb$<'z97yBp@3CIԼDžH ) &bdZI*qDq˾mJ1উ#!!5W<8|}^BAj=6(ȈiMHBR gե#))F!S N7Src$ĄHÎmjB敒hm51xr.TbyrqkLhqDh941 9a  #ZHRX4Ѵ-g=Ȼ^qWrAwʏ};W{.)}$:Gq*\F,.xBL\0| ]mq63'#gl )Bi,M#)DR bF*Iݶ"DF+0V#FiԒ.0 PZ!XJJ`>^+|? ?|=RHB)%ZQ>BVhc!I)n;vM ())RتFjFۂJSW !zMKLir0CDKE@ !"4689F c-9eB v *t1D7v?0t_yW5~*%Js@BJX,JsnDshmp!SFI )A*= saF3dAt%d#" AմHU:)RyOSW(U:VShȂŢV2Wk~`GDMsxO8{ad|,]ɾXi)c?Tʤ秿x|o?`S _WrBj B.]J0@iLA)fp'v@ EY%Kd%H16 %(ݻR{S@IEdEusfǃ3UMCș "y)?y H E$0X3HAhoRI[~._)|='䄔bn%L#9J"f0&ϔ2Xt/*8ZE6w4ZcDi4(Y1OǐiK܋+?KLΕL>^?z0RP aY}iC++}1EHBɒXn;i=_ן?0ש/w():GkB(A$OUVs$%"E)IVeУ2uU!|` E1S)D#-~ dhBJj]x)B"[5 nNO)b~ѝ|?m3(A.+2_oǫ! ͆HdQ\ w1XJS@BVZ_]w(s{_o݈FkE]WxH$sTMEt"ǷODJ2=jQo|?m/n,h-} ]!̑q;epnB;;;Ck4Mʖ%D]Ǯ gR.I&9a'bJ\ߎX0k718YsmJL3Vu+4:nG֤y^W{`ySw)%Zk4 S)~(mS v'|ӮHC]`G\ŽjAHU]s.UHeTǘ9 Rl;*k8>Y@K072}ٷR-/9g3F8;[U7>] TMM+JReQV!DXhb9p4) cFb:79BU=MS Cd]OU %zw,%OM<%|@з|C I4Z*.3zBBD>xORe! 8FB4Ydind1He،n`׏γJ(;꺞nGؕ۞'1e'Gy̎Ʌ<s 2Γb`r!R[[zcH1\. )%rɹ>wO ?©Ǟ"UeQZ9ꦡ]TAC(4eJ]Miap/$[irty7:3"%1|?Gہ8Gv=~$ AXǢ+?s1)U M7Ɠ0Ŷ_!e\teկ{> p! PI|liN,-1IS Ѽ/!(C!JjćPZ>FU4}Gu,%9}s,,)`{r#h'}mwVi:G>nb,ؖeV$;!Es$YnUWPʺq33&K?:6bLM\p^{v};.C/еQPrqjrFR*c*[!na.%6Z75B(Fj͵eq]{`B/wxHafJPFH1aLi,@v>Bze[CLJUYJa"fтʘ2*5P̃dOVrڇKH Kbauo^}PEòZ FI4m@I+oݴsha )(2PBBR)n{mˏ7,iͲ!\*ZR0/ÄVeвn@39C  L;a)%Z-OΓ%^FOY|Ѽ4'9^l6{ g6ێu=O"j8O^|jڊe[aI}HIWm% v#EQR8SdwKy#3\_ذ3iR 6 rE%!r.+l)PZ"2t搥!$,}i+K]ҢFSUhkZ\pygy45{' IDAT?wNJMYI^^. p[Y*-Y4F“V4Q %zVbƩ4V""-!PR`J۳ O.6;vf%<p'we`RPLXjb9!eg1Hm늜 ->PFFș4lxG7JKs35XnH!ưXxiۆgGE(Ja hB Fҗ );.n Q H_wysE!$4Zrhjx'+V# 4AL]Y*kzRŲaQZ0d",ZϽp6wh0"&%bB+>zLޕ0Gi-B)ŒjysSoff H":`ܔ]M 7i4mmZ^T\Y-Ud]k32E(d,m=$ʄtP1vTmXkJYtI+I}.E<\ޗNغy2PJ \ǞnʘmdM\b XfD2>eōJJ~BH9{< nNS~_< mӌ(5~Ԭ m]椭,9Y/IaHn+U.QyaGPeHE.Dߏ̒ȗlB覢5yP!8ms%_hFg;x_f31K*])C$ڐs$[{|ts2+>]SYsACޣaUk4FJ4Cncɓ6 0I0 e~`liDfqF NƱHhAB eu-sM!!:^p#صka$3Db(%~9Y]Y%90ɑզ&>L}B._blcJ 9ƳCryb("ݶ##nXm\@)0p_D;V8{72v[ 3OU(m8>>&7y0m;kPsFK@gd ^W$P厂1 3iC|eFO41)gģ1nҥcmWR~b z,Z\Lα^܈2iB1Dn #0ZIiܩ [ׅ)B ?pP auh)BR/NRs ()"9}*Jy|JP,!)=L Pen޿/?Ηz@-<ܔKAgXhe̫~UjEL kۦ YCsiE|QAq&q tX/vb]<0RZH "(M3{9eTӷ7kٜmPZTĞ|| Y-.vO4GWf9T(\1GGPWe&^k8MAbIj=U)&'r,2ܹ\pM"^й<:8{8ZX%BzͳؓT"u0yG8[ȥqI[U3U\q5黎;nD99>BZcV'lx;*+SE]b!u{0KS nHf6-)dM!ʸ䘆8+m+ܑ`e&9n*oN$jB'hUٓ2$\ֆҋj>`h- 'lUM-%Z+5} 7e˕dhoGieON"ň?0F45䙃'TX〵-&)rSGIm/{9 /! e@"ֺ7!2JRghX/(YY#qX"&79v9$aWJ)v Qֲlx;Vw< Sf@)!Q*!NMJam[ݖ4Òݜ0u Ydw@;xˋ~GWn]0t0Cؗ($ĘBEET9 %* ,rﻃr*C=;g~p!+SH8ɝlx;|1 c,M[궚@)Yu*0r(YnRjV({\H\FsPof %E^yӧӥDɛERMr."Զ" Rqz:T8Kԋ5-.:b*'Qp,BTiue3zu]D><>A1V4hc15 1ZvlRb4%IY i)ep '? |u񇕌SL(fm Ԇx6&Ϛ1$ɡĬR7a,sB+)[b,m ͮ:z} ~)DԆ1!F{0̒'j_ugx3#914g`娘\XS _beF+ŏ]ǻ!|ږG6=V >z_t ˍmӈDkLvYJ.Q#%duY?iן`1 b%D#FYa{,F% sԫ#bt8PUF")#烗$y}1I 1EGxsx39zڡ7v{mSqtz۫E[a'BK)"z+Ifu|mUJr;mן¯}8:>b{zFz,Mw;L㈚˚cQT"ZjLNPך88 ~*C+]h>?Vc􋝁}75+ sWm3MeB7tcՂe#i4FpzpꚔ,nUē0"98܄agXr-XBB3Iw1>NJ PENXmv39g$ ' B+6$If ]\f*` )dE6jkׯ2[7%󗚪nJD29$vW7h8Haeɰa }|O{6>S;~A? /ZRXr[pP%Cn -Kr#IiӹtL#a!z|f0 1&:_b <?'~~C< *ziBUS[BGz`L4#w,VkO2#8OH(&49 [U87-%G5Os/d?-'/?Tfb!R63aG(-i`.tb@DR1aDA,0N{#_<(g/Kľ7icp!$Mm]G%2Get@[X[v7( Yh[d7;KJk x`lK>_nr6N 8?̂n)EPGBhLQD4نz>1e'31M%aaCso=2xxCBgnRMdf| 0$8"c,h6qz㌽Ҡ6J",ޔHjB(/lxg? s_4L3Gc9Z[1kQ>E3C9' 01g˖ۮxQ/9D?u~&})%އ`U|ć4Hqbhp #f{O_`uiu $ͬ?,;OUդfSRI|] a T1UZZ\`KgR+QXQHxʿ痿r;//y_@N H.ò| GGGhi56gtQklU mlF5eɧ7PRW5Wr\?~:ρ¿ Lh$Uղ[t}3Wnb-쐌e&Wq*8%-nw\v}>14}U>ʊ/GĤ ~"Ŝdg|U)lzh?}weusiޠtr)- RHk+TlTH@L@!~'#Ԙ(!ib0AH %i#\[za:smk~x>L!NˀIəֻل Cj|n_c#Yɰ\:# }LOM<ő ̧\uOϟv3uP9?+ yY,fs6$ۈ9ͦ:rcHF>);1ٮs'u@+p /fܝ W-mlof){ hk8~)67wH͂STuů^nRg$;L&| o|eCD/hBp,݂J\EeUj圐&vJˠKk h1[Rx~t 2UH53ߏoSkJ)Aw5CxUIGf$VJH h拖e0e`\ rhFci{&xMAE[[g{ԉ&3}x?p%׿G} 8yJQ\m?H;h29,{͛lҳٜ;QUJUԣzJ4BxCV'9;jhWK&1 0<*JT)RMeY`rѢ&cfFBYa4(kH ~@%V%[e/kn>=lԃ9퇾҆U,ڵ#((c0Fْ{ N|qFJV}]zFaD|,;ݝsfP(0iW8+#VL$xD-9f1)Ѷm4e:csd{c=܊ c4]XK([Rn7}bx7-R&7|ƹ+|7׿ %V%EXJ\+A}zo OS"X!"8̧sBXW`V(#lskz@BqB`0@vEۊ56 FakZ ERv&Sݓ'hd=M% ge4M67I+=ӟ}ru> KƃhkE`:>EUF(2-(yj@1 45eDIc9Qz#$PMڴVB(Zx;mEQ{fEj[;QGdu] aYaC]$lnY+&RJ$ށ6E:l6c5Wj}4z3A=# 0 |[c'~Uꊲ)Ԯ(>o|MCUd+ Y d X=8gW5mӣ 2iAѵ:rFC`>dX֊z$TKu ZX蒦 r G#2hT!"Ɩ<1`A# FC> %F)ƣ1&U]?L_$4?MPaшKQڐږ,EzH 8eVSFџiJ|np+88g@$Z]xPȀ*Fuu1RX˨,匠@$]B ip0Wu)ē,3ȻbUtJl(ˊ4(ɤs?~&z0/lnDlz]+y[G6W}1^^ff)62 J-Išjհl/p ,ጣ])alMe(e(Fb+q,76hbKӴt]jِO੧NQ ڶJPNv֏|<3CrZr-yBY ^xI"حt<;o)>Sud0TV(ɢ# ڔ$cXdW-XuB2]GY~ vi{ûB|!M@}xx~X^|˯w5&TȽ"^2V+,)'^>Givr2/k}@ʝ,th>% l}64ؤG,0T6Sw4hd?,z.G+I"Œv0k.QV^_{/.&m3\ >60ne@ ] µ[ZA0ְ>ha3F<㪍hhSϠZ2cFk66lnoCA"+&cjD\+Ͽj◪Nk=(ؼ$fVJ((#D!XPFƈ13Wd.!*QXGrO+R6܈)fIDAT_u9mL+P^A֥Uf㬣(͢!2lz^a7?^ WNv-EBYli[]h2}h$1@2jn։8)$$n[c,UFò9L:& "VYnL6a(K.rrpuůC}e냡R9Kn+n',QVʬRf"'|p^W?O|K{+y/=@kE;L`QM; ]k[$kMaQ'9%ѧ:y舑}^ SJ->HYF g#&zB=>}{/gI)β9(p+>o4uRz ؾJ./_lB7ifn`y?ϣ}|4U?.ưH"5%RDlmntx(}&'S Q54#e~dLsf(=ݪɓBv. /%/bt_)ĥɧ;hn~w1>ߚISq/vif'X-8CRZzU1>9aFEϣo !s|^^h_ qb<_o/}=$j^Bҵ*3]^6_ǜqIENDB`chessx-1.0.0/data/images/help_blue.png000644 001750 001750 00000014021 12141003207 020420 0ustar00niklasniklas000000 000000 PNG  IHDR>atEXtSoftwareAdobe ImageReadyqe<IDATx] pՙ>u˒m6Ƙ.  aEB ![-Dz-,E6eC-..pd.2mIe˒,H39[# 9z]4y_kF$%Vt@':IN:tt@':\Aa4;_}v0*i Qdԉ$ImkuS]eA =nl!?ְ,aTIBB>iT̯ K/;ISkjL&٧ JY X 9hu ;G㏉EX#wUNVŰi4c:2@-%MjVDyf#&(wT帯"Ñ(Gy@F4>Vs6iqhi6Ǎf }n|# pү8(AD¿3"?Xr6|3iJ 1 7׈EH0C#t6o_Of|%U2gPJn5&Q rP819H(||a!C!b%xE5J`4J2=&9Pb6ΰr?"x)cw2@yٺCjBA z6IУxpEyj̺1A!ϓ*BL( i_i۬.7 CL>;gմ8zDƚlG PWaE/*@,<"ǒ@c7\EwݎzvY9L`23>L|(@oT\!BA Ec4PW/ylp%w9P4C<'l?ɝ{ 6HM.d|dc!Ńb(DX%:]Ȑu^rӻFM.,)t+A!qR {lՂl +ko#- T*uxh0L"<|%(l"`Gǂ\R78fK<b3~Eca㫧f r< Vw>y`w8`E 3[@hrק0-+fx#J2`dʂ^ CI)g~OT|J<0!m|_~' l+ȸ%< mfc$ueytc~xPH =`8`nf{`~JA)b$=;0N _%8 K N%Xuy9H>niWOdF@: s]v΄"SK9Uòy0V+$GEqB8 ! p pAa傴[qM{?]9(lLZÚןthz3{CE﮾\8*g4Oj 2Ŭ+̃ځxgڶ 0EV,+ &yJ'ΫG/si7[o#M3f3 iw؎mPSj_[#Gёf:N?'#̪N[Ph`X.xPsڒ3.m+E15tQgDӖx}mᙻ&tՖI qiieJPMH>VQ TհkeyܙvӮ|պ tlt ]b,04'|k3-Pv@Lw|Nf>/HMgh_ͺ5C֔eԸpaXLd EbCj$ i* ?Ѹ0@ ܵ(ecў1%}~hq$w0+(tJ `lfgA_GAT,^Uӱ@İe 1+ \s߫tшKzXt!J^;~?UtT0>NBP/j,,ɇ吟O}db \}y\utC4$jQGM5Ȭd&Xo#~)愳$3ڠl9x 0|yv"l$,n-v <g?nnqaܺKguXh4 7-];iEWNX:eڕMiLe?Qбh|)-^kF3l?7X uA;>g K4AnV^Λ;F|NQ[o峒KU@΂$=q*eTYԲXCUvGif\/9J2)NRw`wqdƋo$(YTW DX4_=54Q &NTe.39ܚ_ a$,d*"&@  ?qK`9Ƕu&vh3p&E}>#ZL%y)V*=ǻNNrHдKm YZ8d9> ,~|3U%Kcy aѓ2| UQ Xi'V39mi_Vr9fW|yܓd}Lj0YXQ;]$n08-ozM|,|𐫄@Od$ b0A]u 73ըQw s^*9F^gP -=&GYƸH%+ QTd` H.g- ‹4NJb(3gQd S#_l3Aw0Q)6wmܯXNN lL@[&+1=/&☋NΧ~Jx w͔1[\##cFf^C3Ŕ(wǫ&0@32K_yjQFO/\6GMu7Ih24@7 Eg1D̞5GÚn(/KzAO 2e$WTq *m'(= [C`_սdP0#x@7 &(3 q(o@yI1(?^pGћukd <(8A < ۦ*^b`++7HK*{3,X⭖nP!0Bs/+<VƷ%~O b+ i"gj,vM˖iݞzrgJ -P\}mFgrN0:UZd>X Vy]l[,WSߟ鲇4ܳ&TFCP*%waďwn{{VQOaVǮd[>YBn5G7}oe.Q~ᬌ}{\@ךj7s0O[v3zHkR%/VzXŜ.9q>9<PHfڸ5-HI'$8nxez?ð_*("m*fڌ}@F}9>c>8*ArJDž i)Sc&Vo'qp8x$,uѢjv2HOY@G? XW4Y!nyi˖j@J>OWH_f5`[ Jb&` M@Iwf#lv@T8%! 0Sޔo kym `KaA4 8LVwRЈfF @Onޖq !ԝAZ[ JvZGxG. ^AV B }jC ]=tVc=_q @}ͅE6Ғ5Bx㨂Fht}P:"b֘ç᭶9ܚOKIEĢ-rȱh+uML'z+#q|S Bd >NP9ćiss[_||M>:`4k3P0 ГϚ-2icjYEr57j*֗Z^>2Jxʨ$) 0pVlHkr 3m䔰OљWGՀ+@> >+ e"V3:b`/_R-j^6$o 6nq |yrjfr{zw7o5UEa!/Wo!L1woLSOoC/oR1YE.]ߠ568p}Mgɵ_$ay:>R{x.bR +T Z9 ;_?|+E_.jg {db4c@ &}]puE O0iGFZF(VX WUMz}:Tُ#RG;D)[& 1š?S=)d̾ͷo"#YEet>^E&hNcxﷻ#fXPŋ8oN6m$(67o lD," $ )\;MTKXQv@P,K:jp{&ҼM&u 'hesHs~ִ8dK܋%һܗ{%%#4u\>߲%0&@}#s JPwo7Mϰ7q)c=T%Yא)%5ڗMpMwNrHJR3cy/%HI_J(J{X'YkBF m%e<أi4H#C={ПaT`m%L0;gn20Zd !p/ b]DM)-?=ݙ!Ph z} ݖ0T?l ]gJEP]Z7P60LAׄpT/(USy|6e3q ?;Z@,M5H3*Du`4ق6rI'_i|&_5c+_l@4`j6;h!w6>My\r?X5zD3{ ql$bPBȯ\?n,+# HZyG@6u۴<ތ@A.:IN:tt@':IN:t r H`IENDB`chessx-1.0.0/src/database/000755 001750 001750 00000000000 12234477214 016152 5ustar00niklasniklas000000 000000 chessx-1.0.0/data/themes/outline/merida.png000644 001750 001750 00000221522 10633464147 021451 0ustar00niklasniklas000000 000000 PNG  IHDR4RsBIT|d pHYs66BtEXtSoftwarewww.inkscape.org< IDATx]wx~7 PB^C"]PA1HRHPzh@OHҥ鄒~:mK&s#(HAИ~H9l(* aӦM8~8N:gϢxUj֬:dɒb4B2;vS!K?u vލUV!%%={D۶m2 pQC%>rPH < x;Ox:tX`&'h47OMt ]5 @"Aء>@=!>jͤ`9] pzꅿ2yGad}?CPͪcqN?Atd?蒐bŊӧyȟ??,0؉}ԑ})h"W&3x/H: qj%l6:Sfdطo_˗}ɓ'#9d;߇dI~Xb쯭!9³$9X%ܺuزe>\:9ʓMI'ٜ =[(ی/^gOHH:t`Sk׮?r^^^Xj'Mgݾ}UVY/D!,, 5ѩS'xzz@jS_C8,0\6? : uL AtO>x'N3gPLԩS˗[8wO;@Z=&&N©SP`AԪU 5j@B:+lٳCi͛1h ]Ga]FMĄT\pN¥KP\9ԬYիWG75kƨ(iT)gU|XBjՊkf4_vV#)NJJ1c'OM۷/|$ atC0,8nݺY:uC:E̘Z $O ϟOwww`HHEm)G'Ss y&۷ooo3((ǎ\`,'ѣGf7"åKJ'dvZGרQ#?^ʏIII6m===eeI mH" X^G#a4h޽ʩz#۽#&LӧOgɓq12^gϞ3=zX|> >\vIe%jn0O2$GIC^ ;o/ ᳗ cكVfz̙3fve4lN$,=-PdcʕV|zѬY3m^py=N_j/ŝ-[Ν;iAF֬YғTR``T_ # $ׯ_ *Yf|/^k\}"z.06gS)\ D ޺@]A777ٜsܳgcbbxnذj}V*UK?3&ɣG/\/;H;jy!޼yǏҥK /Cږ-z(<גjbObĈ BШQ#l~~~T'ڡB$?Եة܅@4ib([,kvcQ [tt4.\\z5 ڐЂ`?~G؄uٵm셭[m !5ݻg6SSS1tP+_:,"TV HMM5e(:q|4h*lڴ yHLLĨQdeܰvZ.]0tP\rE 1l0XA8@Õ @+/`N%J@LL)My0Vxvh ͂?ƾ}o>|'9sP|s5љ 8'Zu:@ƍe(|ǘ?> ( c;V%в藩5~T }yat;*** QQQزe Ю];@8 A@br~0@uaƍ8qQQQؽ{,nݺ MTJ[2-0G1WdYfHH:va:t@=dIbڴiX~=4Pw݅`,`d2cUm0,RkqJfԩSk1!!TvժU2}QLMMUmCt >陸|OzW$gz޽[k}MHKKS=nf.$qׯ_gҥ3\Zv@i丅$MjD:t!"EtIRc,$IeBT `N8bݛ״iӤm33wHrΝׯ8HUyI󃘸|r\Z &Hc&ɧAM-:$tLy ƹ0>| # o*R:r>LJkזe뚕jԨ#GHULصk:tDO Lȟ??&OoVox7пL< <0m40 oAaef:4]aK5qYZ8te\f3[5H 8P4Oly"0Pᅢ&Kqe(Z`TO(Y$fϞ*pϘ9s&VX#G4m#G^p£ ´$|Ijm!pE <iiiy+1ydi{u P<7a W$=ITHp½@sWwsUYFΝiƅ B׮]eiؿx*] ` H>!y`˖--..ڵӜ-[V?~E*UgϞ\l#GIeƢXB eʔgBx-udzz:[n$ve< ozjN>;vO)e_F7ݺuSՙ;w$&&E#hɍ[jd޽3Pja> )w3===yQ]~]=`0b_$m@ ϴ\~+VÇҥK1cưbŊr+V ȍT{_xu&M>?'"Ir֭5^|9~Awb.0~Ȳ@___QDD6{m6۵kgXM$y!L2ܥr/ ^ƊΞ=kw5rssc-h"eRR]8{Οw*'.Vŋ3,,QQQLMM;w{n8 M4q3[v:R .,///8pZصk=<R^p KrCL4 VސaW3fiӦ\2ʔ) ͛~-Zl)Km=9X@xXBe3ݱb B*%1QF+WFJ`~~~*W  :#R99ZN8eJ2s(tC+ hx뭷d*#mXf УG7lЦi}$u7nٳg6mڨÑ#Go#((v_ͭw xqK6Uw}Ia9<(& RhK3S ܏ ݋AwŤ'J[q )͛qԩS8r2D#_B-axq +6U|EbN+%EJ(HkPBBBxiys7 $O"`xAx h,?tPk9kSUnye,_\m"$$$CV+WlS:uhѢ41JPP ۷#66;wĈ#;fqn{Çz"ӑ} O`=z5X@8y$z!&0ءt-v)44 }ot @~Ԯ]ꃿK.8wBBBހpb"55ΝSP*XH dvo-7.\XYC_vƏ&M㈋Ñ#G7ߠcǎԩ5k#GH]>'܍f5]TpZ̚5 ʕCΝѩS'[nō7p]|ȓ'X7׍|ib"##eMpYuppȶH,i-WƏvڡM6/QثApG_Μ_eD uV?~(QBu U`#F_'OTsVZ5&UP=<<(oz$O(y^Z6[1#=1B@ B3N)ʕ+Um4mTk*S06izXM up²k sR 1aL:}U+ׯ_={`٢ڍ>~Pu E>ŋc x5kΝ;1i$,X@faժUpssk(55(PZ&^p͚5ìYPNxyyٳg8rF(vI"P@c Vݻwƍ^s76k)*oe.]BBBhYޝ2 IDAT?LN`# nB"o&MF7ob(U ݻUV᫯R1ԩo,QnB'e˖aĈSt.] 6`P1r)O.DŽ #S#Gзo_C^Æ Î;di۷xy?mu=8X1{uzN0'pҤIVcԩ"66Ǐgzz:!>>7o "k_?CA7o^cl۶2X:r\!Nu266ִC\=z0--M,vB8gO_tt4ϯ97nnn,Vٸ2=d@Mᚼ1t+fD?y*\kObl͞`Ө&Dq殳ԲeK^n:I" O'L\4s'ӧOXl&I&Irqۍ݀.`drVڵk-B  {cҥ_}U땬իlذqVRE1[d\-N9AFfzޛWHu:L_3N Ԏ$*ULϴ!ƿ&2Fs 4R20LIIaݺu3>e˖'OĶ L CVgLL8׌kqd*P;Ãǎ5\rުueJJX4sYwG7 Y\,`$C.]jo6۶mJ?y$ /_6ʓ'׭[g>|EB z4om@OqB 7~T0zh5ӧTȈ!YHK!9qDzzzlܹ&"Y ǓwH &1uk,E.mW\9MkזbŘ'1JUϜ9#m{@(-[ԜvqҤI\f ;Çsׯ+Ye˖N沏\H](A||<[nZ-Z}]ݻwƻJn@0@XXJ OZj͚5cbb"Ϝ92`v"99Ç{wʔ)è(itTEPK.7oxk7n85߿#6&.0vGR0o֩Ssqܶm߿/w2v:I.^l[{18oM,^z6{_FXy?> (`=///N}*:zP$'ss]T)ԯ_uAƍѤID_^`HE˗/388Ή`ĉU>S"uQ)Φ Hvep&x~gn޼٬˜k*SŋsU@+w٣G9~3v믿+͛Ңv='4U{ѥU/"IΛ74<<\K66و2~GVK~3$gH_|EiGgp6+"kU׍ma$ehD,ɭ$ ٔd>+w];wpӽ{wiFV$Qp $M='ZԐd8Yqqq\d k֬i`u-\2g͚%s*BA5LSv4EA$`U]cǎus*^5jg̘!H]F'$,YFT6l޼FѢEyih:ɷte!8aׯ_7kڡC&%%edd>}&%J=M ̍#=ɟH>՚+/,PL}ak[$ٳg[|4kL[cb+/_^o͚5|ei4 9k+(Xb<c!yf%"ɣ$P{ǝBnmO?q3gLe˖~k,$N} CU&7xOgJdU&-eD Ϟ=i&Κ5#Fq8}t.X\~=###Yc]@c)vI `J,iw)g}fnMK&qʕҪ8{~2EX%?e˖1O<wm.]dur "EoŹ~i(;&#}(^Rmd>38ٳǬ+[^xQ,d%:M]ʓ[5ܹ]NBCC5O<==pBiч$p9r4݀ɗcڵUs|rdd$9sL ٵ`2ݦm~"G{Y~ᇲ#FH_6mj oXl4{1/9#nP%oȌ{}̈́Ǐs֭1bԩcձիsРAܸq#?~L < P4$)l*mD3)SxSm  SC8uطo_VPK.:CaS gIBx!{=I&SMǫZVZI]B@w H!)*T۶mx XܴiSe-$7i?)|)}6eBB͛ҥKmzm۶K^Y&={&[&3Ԝ=q-Zdֳȑ#e?˧V^*Xp!*~irf/^~ٳg9~x6h@3jxfm۶[@ʕn+El͛lР$6CpMC~?om}KlH~ył'Oٳ'cbbT{Qk11^ *U|IDO+}_E イex3*UJ:/cŽhԨ3FtD(,,̢\G??SUl%>|ſ*+s/C{煣ɛFO5R ^ug"VX8uqIk9S$ț7 hi…=ƬYm6ܽ{WÇcݺuPV8 OtcUV-۷7۷M$#88 4鎻&TX/^4[pݻ7TAXӊbn?iiifyW6]>|Z*|s*³J^zutt4?~ ___ѝ^?᲌6mڠhѢcP]0@>2dk0@t]bE(3j@XXTʗ/={\rLѼys>|SL/bΊ+кu \g- t cǎE͚53?ٳ'ڴiVZܹs+WQFӧocG[>9s*sȓ'OJ777,Y/'ϊ;6KU!I2 @&Ž{V%@gA䭷ޒfDT@z)tIƷdɒYk֯__k ?&Ʈ 4mڴN ~&ge Fjj.gԨQRʘ͛78pl-۷O̾k yNF oooi4梵ef͚N4Vظ~Ynh-Ev8=ʪUZ|ɓ-;`:t:СCt[vG2TR}kYlڴd7RlYݻm9٠ i:AHrÆ {{{˼d: #>eR}Qu7jW///v𫯾N7^X< `Y:4&]xԨQrbo#Ęi}NVER}&͞!kI V]JUpar̙CJ9tR喵vڪ9uܹSU(N[k(ٓ #8OUj# T 1l^z%LoEr5ΟW`p4f0ƪ j֬vک*\ݻwGPPO>$Tٵz"`ܸq]Ixp7_ـ*5kTGFRK)FDD'Y>@ `0LɈѣ /*L6 ׮? nN0,yPblٲ</{ ˖- *O0Ο?dR@&ldo׬YDFF$*Rqx@4G UT;泆=z`ɪ͛7ҥKf:u [nUOo<j6w1AKU`E0[ 'rٲ̠,N(])RI=N1xb5J/!R! ;՛CE׮]UtyYٔrݻwGxx83ygϞ-[60C׆U\WrՆ k.=Ԋ(QZj%KS&FjT6Qhn,ݻww@%`XU͛gmph8rjFs5;VuߐČ3kѢK3f*͛8yx)[;d_` c)]Zpm0r6%J%؂T?f{ zI sȑ1K -wYqe *R].ˊeczF9vMuժUm.%^(ml0H2""BfNB>TUB|Uڵk.]8_̙3U;}uRob@MbX_@꓃PbbbTeʔ4Aa߾}|2q ܾ}Wyyy!22REgΜ9s2zTD?4 ~iPeDhѢlIԠuJ ){1(@>ƴ4 4HUf֬Y}|h-…>s6̺U~ ‡@۶meiOƒ%KL0AjjI7N0PU#_.`*/PYVX Fؽ{7FJ4itW|8stg8'I@s ^r_xqߜ2U&[N0r7Ç`0GqRJY姴øy&ݻR*S 5kX|,H"*W"#5,w$`Pmm޼Y%`|%Bkm sɓC Qe6Lzطou6lTB}d YA>+*ƍipatUR\9|'Nm-9x@N5X(X:PzɈן U4<(,*8n&L@Ѣraaa8vnjxUUTpHNN޽{1n8XBW-Ck?u !MMMUczsZ8*J;' ÇRҨV*wN FڵW/F?*ҙGRR}i=7jÆ /Xpv? Gv}"l޼yhkfJJJ&4q]3lѢEEHIIaB4(-څοo2CMmYcղ6>SA#A{zzJ-FϽi;IٳG;v0;OK.U_>7on5GTi۷,mРA$M6"`홞7n)J;Њ=zhUZZfO.]d;v(n.$$yUsN)SXgHMMjLG<$N?CJ%I>"hSw|䉝f<8f Ģi$8p^JN צ$H,Pl^^^￳>Fdd$֭ke!waQ\_]ztQlXa4D5ƚDc4؍ݟ&HKb lҤ4a6;KYyγ3ޙ9= 6bȐ! u[l;?v*BT2&MīٳUؒ СC4n8ڼy$8s .|HUM뉈yu_r¶***f͚1000RSSiʔ)ԨQ#鄿O>EDD6m7n ,/DD |Zl)Khh(͛7H-gRqq1 u@/^TVDDM4)_sh1zzz\ap?Pb+KkOWWW:v ZW/^-2Tvmų_&*%PB5v9R}r8ŴvZ266.u:$6˥B~ŝK ,`(K$nggW%WD˫ŋT"!]4'_~pB#(//mmm˔WPrJrttTZN>>eV+'''^ڹs_uϻy̹Su'puutwAܹsGBIRAbb"޷o_Ms5͗ A͛QQQ*{Ǐep5Eqr bK8JfC;i9{!heeE*i"66 *C}ݎ\r%ĉ yfX:?*J-h:p ڵJV8;0IV'ZJpҎ;<}\]]˴#ЩS'ɡBZnؔ{1m6ˡh4`?Z]SǎzR̛7O| /^PXQFqz㩢SZGČ6mxvpp"KFFF4j(Ul`eBzLJ[?*J (ԩSt4(u*? UwmMD,Pǎ)3S:ࡨpB2d7-ZDGvcٳ4n8jݺ59;;.ժUuF3f̠# O?-J~!iӆ\ِ5/|e^#6[e2ё^~^dl2AW\QSR9hϽ jA;J3j aDJY۶mym ưjժ 0rrr.9;;Ӓ%K(55UD4F1k`N[3iOqlE6l X_}}}o)''G5 [AdggŋyAXZv-m5A3`V+JvZ Bc^T,Y}#iK{UUIr ~* zzz]l"E/TE;"PY\z֭[}}}EX&%T#`hLD{-[&o߾ Ș)))Ŵ-[ͽHc 12 !/?;A⏧ʒtf|rԩCTXXXv,**,z%zJ~T{V^MjR&M^FDh7ml$ S-Q5r{*/ŤB?ת"d>|ǻ: ʄ }vn$BUHPfTy .ÇqFTȏ>}wbblb DjRI5A{?Ν;˜9s=Isssɓ'y*H <|Xt)lll"pS'pI޽֭ڵkgM@ 0@tw"|t9s&:uQF2bbbwwwL<HIIA\\ %''۷x-rrr=&&&011AZ!C w}xAkժ7o߾lR8lU>ڌ쁗yP jv0∈VX_x!&LɷV'NPG׮]/"blA!orZ r~PP54z^^}e& 0@^U}ڹ`ɔѣymzj"b Ϝ9Cw+VЂ htAvX:"556l@&M>}Hm<\]]uHf͢sQrr*^ZZ{5$nQ(C, bZ… n4pႴM64dddDOSүJǏJ?^nw ]UlqƂ700yqmODCvv6-ZH]6֐ (!ij$`TYD|Rv)3cƌ ([nT166~M~;4)7je"7n̥F8:: Ϗ[5?TA"ZH%DN___' \媪8KpR2ѡCxmeee%d/UR ׯ+rss1c lܸgaaCqUԗIAfd?ƛ7oDfrsB00U ?<"66 Ç111~ٳgѳgOn|ƍq1nCӧWOpYh,XPi5O?ǎK${0@uYY&8pWz`oo;;;cdgg#-- _\ >;wʨ2_0ߘBFFFy2Lܸq͛7WÉ_FFFӑ ??_z,t }}}200.¨<'bg Q 4HԲeKt'Oݻw5Ƥ.LMMaff&C4Dl}VzHxR<<<Э[7ܼyn,cnn}ᣏ>bRtf# W#;;[>n݊Ç_q :yyy2Ƹx"im*SիѣG.X E``\BBw2 | =!Μ9Y}awtt4Zl,=z 88񳵌VK''J.F]v XA4ԩSeI5k%Kyyy2֭[ev<==SH$P@;V?1ĉodv/^, IIIFtt4N*tWKO<:oѬ@ƝZ@DD+踣pppKKK $DyyyB k#&&111HIIi^^^طo5k&]0Uкuk000@pp0z- ř3gtggg\~l`h":Z*Z^|pݝ-hlyysRE3:t(Ԯ];^{1z4ڕ.cM!!!ڴ֧4( 궉S5DL+++oٲE-6?y$FCYUdJDψcf@wlb>m߾fϞM&MhoYIGGݩ[n4a_)$$DBA=uq ԂVDfQFFӧBmG-Z/~'ڿ?ݾ}JUz=zV^MSL>LLL*FÇ纊/&H ]b\S~~>uԉW###* .Foݺ5^ӆ uV̔6._[!}_U@}0zݻ79_FgϞǏJ#$7EGQeE;[3n޼)V}%$$p "OUIO֭[a׮]mbÇI"/pu!D /ŋٳ'N,V{СCK(#i z., 332;M^^^EnRFp=2;w cddPv<h Ny7p @"˜1cc^aÆ)QUgvI&aݺuI40m޽Md\zm۶U;ptt-^cOțfn9qzқNWWTw^V&++ IIIʠطo{z%ADŘ5kVX!Shʕ6mi/ߏȤM:V&m0 ⭡=}%ׯ 8alذAԅo?L c{'p!dCDX… djjʓ֭[ >v2h8 P Ϛ5W}rC+ŀd?Lcx-2|rLDD'N\pqq28y•@X>1b)URSr17n\v-ƌ#|wwwn_P~g' \ԠAٳ'}Wb :pݺuK+gT .]J_~%uڕO4222XDCkEȄv/PIW',\NOH:h$[#GڠM6ݻ4Vvʫo>}ŖH"Cuh[ YFF۷Be-ˆ?.hPٮ];W'NFWW>|(/,,Fɔ Z%3f9W*r6ڵk '!['Ǔ*i B+WP[T身WaS@NԄmH$CÇkRxx8啻 222($$.]J#777"ZO+K版rssym۶UIV' 87&8T@LtDD.] ʫU+|y1d'z$Bh:D$U;wp$3٬.ؿ1iQ#"zGDc?::|0 S?^EEEiDd]F^-*{ܹs533s)[n)4jԈ[ԗO"S"zMDyf:RZZ҉Bk׮'R߾}[nԶm[jԨt꒥%9;;QΝ)00FM˗/GRtt4׳5nX -h3m#&4Yڽ{wؑP7^|$HիWll/2*o XXX)4h Fvvv$~F1M6}36o\fz]xYE"#[۳g YsuuJ56e2:/2~gΜp2kggG=zٳg'|BFFF2*moߒLɓ'sqBy"ŋ heeEW^e'hU2-d+ղeKw?'???644ƍӀO&OWWY6hAiufS >Ce)/UA~l2]^{%ѩS'n$~6l͛sR5\.]$FP`Ջ,z5PСΝ;'#t] ʁhl2s>|\7ݻ7F>ӧOl22s΅-{: Le.֯_3g 9::̙3hРAxꨦF>6lݺ̓bE(p@GE&PPPɤZKIIAzzL\{͡9ѣG2߬IIIóg͛2{(Jt<ȏeiNNNpww;L>/QFa$w:A`.={:4h>1M6ŗ_~)3NNNÇѿAAA$:t7o7|Sf=A"&O,u[ ޘ2e {̟2#\lݺ'OrwwǙ3gU&>rssU3 ͛7سgOn`bbKKKXZZJzlnn>qqqHLL乌W򐗗333OOO4k -[ Bm̪V(ъZTZp ,֭[eƍYU ?5F *0vcǎEPP6n܈5k %%WWWԭ[/^~ waРAp % mƮ^OoƍǛzyyٳpssSA QPPFA7g ѬY34o͚5CӦMKKKsX\\,}bcc 6mbZ5` 7i.]f<|P !&&GQUjՒN&6m͛Eppp08p\+ 033-s}ƍ~:_7o4w'<<<вeK)ݸ7rgTݼCdGĄ>9rDvDGG`v1h! }Ex,*rmvFj ODx={=z$:==ׯ_j{|W-.FQOJJeFfG⏝22422QFѱcǸW… 4|rttKGGkR:O$uW+f֭4}tRﶦɉzExp)}JVm۶CU!GGG`)}ѣ1cFHkv0~' >\l64ٳgc׮]b* ,= йsg^A8qڵË/oōP``5#6ޤI>}j*{)rrr`ii b(wޕÎ;p }G-\rEJe|*gj"=R/4ʌ 998v/LJQi}4i0XGGG-Dy&U?J?WgTvc3dVAAAb3#G`Ŋ`)4&5j׮.e,J.Nڃ1$~ yzzɓ9s&Μ9"x4h/_333({j-Z51V,[h惩Aϱ~߿}pww=`oo{{{@WWW^^Bjj %&&"<<aaaxU߶m; sUꋷ^%$`TΨSE2CXWY˗/Tk&`$1֩xՅի'^zpqqiRRRc=}vArFrU۷}LFPPT{#F`ҥҴ'Oŋe[oF 6EѬY3 33)))044D:u"0"(y'<}<6mɓRA1=(..i&l EhX[[Kl"--'Pn]$&&`<-@7T@M"իoo2O%3B\\"M&+͘vv-k:ujl::::uI/**B\\o<~:.8ډ^{Gt" Cڄݻpe`uFaamm-u#o3l/_lݺ5BBB`nn*a`{k.lڴ /8G"33B7...Fzzz<ݻwG>}(X`vdH$4nXfE%6z;+μQAAbbb;7lؐ{Z>v. Sb ///xyygϞ2y999Xnfϖv-3 N|j`Jqe^fv4͏֡uӓ F(#`qG+(Etӧxeػwo(8FXF6=J{F޽QPPرcy&޽Q2hԨZh=zGB[oi1L<\&m۶r(Li_>ׯz>|})+C'8p{711yӧ1zh'6 c/`888S &&&hڴLYN[yb" ^`?غu+ QQު5<8{޽;Fӧ2dxAFFOu&cihh6mڠyR 6TdH @NpyȴHޝ;wN>}_5{. cBmjlAVk IXƒU: kh߾uOQu*3ɥYE{@YExf^XcƌaÆaС窊@ ]v`vp(z } &6K%:uEݺu1`DEER'5x)LMM?c֬Y"|W8p_`Ŝ2we&`K~u쀼.=.`Vq^.`XXXW^"??5h sAq >vU3 ]tj~%"## EcLp;:nNhժ( i#d :Sj*$`D' K4̋%d8t '֯_/_U"zZѝmfpB0ncK( 5`]T &@W׮]e${zzb۶|pWYǣaÆo*uZXX!COz IDATe1Y_Fp@X @|mڴQC  Ǻׇ{CCCݻ999r >C讖z\^~4AJOOGnn`˧Lˏ 6666-,U}v׮]e iEUj\n`N75*R5,[&CWWwƙJАQ0BEGTT@B (= fB^T{LZo߾ݻ#--MzݻW(33S^0$ v܉͛#!!1l0>CûD_L@=01#8ٽݟ`ӬC&)}xLFyWO˗҉/7B``` Dၺu N[nl )BBBX@cTXP/ ,`'O ::㘘K&aii:uި[XZ(Gu'֎; ,`9y!fL5@ݻ1wR y;w.oX!{6.]KLZq9\.djԩ5^$5yۂ)^z{!22R似HM$ =}j@t g>&'7\^:GD*{UQgɑ#GCEEEAV~QZDu4}tڷoQ^xFFF|/UAEFFڥk.;v,5lؐ$}%Ґ!ChݺuԳgO^s1qD S͛Tٹs'}4WQazO 1bInݨ \t̙3-K="޴oNڵ;CnnnԱcGj߾=5hЀj׮M::: /Xd.//H$kCBެnݺG]t듁Ã͛Giii\#IE*Z2*S  ѿby{{/DdY%T"_U6璾>-999+988%i3w\vLdkeѶmxu0(((Ϻu3AUB0駟xcǎ4?Z|ן0S8pfϞ͋K"kkkFFFRw!66IIIef Reݻ.l?VV^s"лwoDDD`РAv caee FFF044!11xHڸ8Xf fΜ9s@WW1+>c 0q=lj'T@[[[899FFFe"q !==III* *}HHL?*{*)x '''X[[PttJWqdH $$?8W&i;޼?YճBafuXV9BGyqXW,ѻwoQF{WflCppB,ZHD"Av0h tnnnBdK.!<<n;w*'bjjCcmd[xΝ;_NYs\t +Vu%C__7F-4jH>: 󑔔W"88'O䍃7o`x"aiiB ,tO[888qI#(oӣ6{7d)..wrv =P@וC-ТE l50??)))x!"""[!>n޼W^,z XoH2P_!G&Lu@E[! U8<5 ٣]'DD̙3+ GUm>{ls|$"ZjZnM+VJ׫诿yQPP5k֌LLL3ҪUիWJ&cccf͚QNN޽{?Tʛ.խ[zIӦM͛7Ӎ7ړ_>SAΝ;sK߽Yf PnU777ӧ}tQJJJtjiΜ9ԣGzʈߠJ*1!ٳg\w+++ sҁ(>>^e#6233̙3/g}Fnnnen_+K;bbbxܻwիd5bU"Ux9y$/GQˎL ev>I$ԫWàAD$<~QQQxJmݺL9ѭ[7=_\۷ocعs 2߼y#UaÆ ðaðtR/=,aJlt}[o0cɷBiD޽ݻХK7oāpKg.N>ͪ'{ AȳRh]$ 5f@Dly푘X~3\`MfBF\>|XpDDk.v5kȜ255k׮"+HDH؁KNNN4e!X4zhlAq/HkEZܜJVn_u~-Zۛ[t$߿lEe9o޼7d5ux&I}UR j=zmH$5<`W_iӦ23fL?Dy &&&`fCEP˗/ǘ1cPTT^+)S044Ć Rw/98hǿѣG3^JQ+m۶!!!ӦM9sDĞU U؈^fн{wo^c64Ғ2::kGօwqՂ[FxxƙVȷ[]TtD^L*Y wtuu 7K'9ϟ?ǜ9sZL_FGGݻwϗD"AݺuSn ""+Wğ%?www6mڄ] qoߎ{a֬YӧO"M޽Ctt4'5"eחȑ#8tLٳQ^=t*Շ.?Bqqq߿?:u@M j^~ǏСC8q℠Ã4ܾ}͛7Q`Ƃлy 8qh߾=ѻwox{{kQ1q:t۷=}4ƌM:pvvFtt4#,, eU&s=ՈTQK^7e-e(,m׮ƌ[J37mڄ#G?3;sC*gggidc///ԭ[Wz\᣸Gʕ+چbڵ0a@VZҥKOx_v  @:u0uT=B 'OH݈+uݺuôiФILBBBɓ'iӦ D[- {.޽Ҩp9V)fYG"\x/^̙3VZM44uUƻwܹsGJw-$Dۭe5oXtϟfdee޽{7@FF:uV~ ~LÇfA`8,!`?ɲepA`qq1>Sddd7LJJBRR̟ {{{pqq#%%Ez}bb\X333ݻ={dB|s4i" C^p-111:u*ϟ/u*^\ʨ[c޽ػw/\\\x;~6l`8R=:=/_رco>-vvvI%ۨQ#h#cek<==1||\w fgv?ɓ5JFUUz-RSSq=ܾ}[Ơ=zGGGx2{ 5`ŋ %HxJIJHpY FZ?C  @_IzjnU ="ZDDoW\\Lݣ 6IwI$HA_Ў;(::ZH'YDdJFDϧ+WЏ?Hdaa!zu4}tڷoNDZЇ"CNׯgD6hTuV|6V_DEEnއ wX|ؼTypv02Cq6ӑK sf@gK 7..Np5 -[D@@F)  V4B>={p)ܺu O> ߴ4ũ.EwwwɣJM1q AG5ZfL.*#t<{Lʐ*m# addccc...2B{RZTO>Ͳ{'\`hhQF}RR\0>c c{%T8hf>8C%q!77yyy Cqq1x.V|"ܔop@̷Cd> p @oRD7+ lwV+jZ0?"DV!UL_c0 !Gg:ë({ozPC Ԁ`# U"E@ED@WA4QH* =B$$y{~{woo >yݝ=3sfvSpn &=%_BȫqQ//Y+v Gi!t瀂 ƊY;/<)P^_##)]hqw# C28JP6YBPK|%,8"}d ` Zt9!|z5xA~`ߌ7^AIG ]k!(%TP *TAMNʆH^2k !6*Tx**TPB *Tp, B *TPB @U0TPB *TP0 *TPB *UPB *TPBà**TPB *TpTC *TPB `PB *TPaP *TPB *T8 B *TPB AU0TPB *TP0 *TPB *UPB *,@/w7D *<B *TC H@6 ڧB  IwA덵X ۢB "@a >0<)l AԀ07LpʝRS**܍k  =~x7I /F]k׮ɓBHHʗ/r!88XzMuiU5l`p> P]"*< ݸ JDg]";,0pym:* O3p޳VXA޽{F5 ׯ "kdcY!잔P+ .Wp.; `޽xի???@PwUp$`+8 _~N3HF k׮Exx8"""Rht@OϝTy6p 43e`t:>0_Ԁs FOAxQW^Ot0j88y$Ξ=|x7S6C8T2pxyy!W\ra|(ⓐ\d&1p@wm,'SSSqu"0Hx7V5RӧQl4n݊z>6G v ঎bDu4&LJẉz;ޮ uF8Γ uw ;G®0,,&LrH!d^; JFHZKRSS9k,"W^|%8I2#$~k֫WrҏM޼y٨Q#Ξ=)))9L2,o0`#???:uJZwe BzիW٧OFFF200jYD mۖ6mfx8.t$׮]k4$کs&wF#oz@]F.7o:d7ۋ+fw0\].\(?~<\bw]t d|0ХK,YĨ@@@ ÇKW'!dE;w.oߎ+V LX`o !7n[nŋFuZ@P8TGA.]p97UZ :2[E x۷5kDjjM .U= @7ŻϟC">bgn0}tWLT8n:4o<ͅywހ௕ mS|XaBW^޽{{.RRRܹs%u'w0ڴicӊ!M>]dyDIOvUSz%!u#@`L"\lSSScVWMLIIIJYJ>zH{G%RVH̞=UϧV͛)A7SFl$o3g-L2qƍhb!GV]VdORPg1I$ƍGxET=`^I8Tԃ~ۜ:u*kժ%nj\2'Lk׮QIz{@Fj= |0!&&;vDժUqo|Nl?99-Z̙3_T^111zY!deF^CnNMME=loǏcРAHNux9tXP 'NJ' +!$ɓqFꈎFΝP3;!D2< s-OBx[3,3=E!C{nwSjj*8#Gx8p; ʈP F<̙Ӣ@dd$zϟ@!$WʦQ3gΠjժ8xjrDEzBtQ^.] 6߿xX@K.#3HO t}=B>Kt ^)Y7)Ç޽x]hE˗JJ!"!8vٳ;vMr Zq;R\vMz(P]aÆ!1ђ W3f z9rBݥ&烐_9ŽH K+[rr2vڅ B7nQP!|ùΆ G?I7m6nqq?wEZxbmjB|l`> I.^&~O,JI$]vQZķ^zR+<@N*9撂Ϫ$ON2CKb͛=>#F֛]ˤZh!/BċJˬ!/3GҐM!KsJ@[~fy@?U2OEH cǎ飺9uVJPRMT7 )ѦM_4 `71$~۷ū۶mâEvVUd/˗v3mA~&PHHHҥK1p@ԨQ9s;#O>-T ?xvg0Lc"TJ ok̃.ƅ 0c t JB޼yѸqc3۷o|!^/ߎ"kJk+bbbpaP͑>0ݻwѬY3L!99[Fě%v8s#J"P>a$ӧO-ʕ+ÇRH.f̘a5`FGG,^PcݛB UP%?!jyJjN2QYX1 5@!~|C'44TZ_ ~ /hg mذAdM*I[!k޼B )))4i}}}MkѢauTc˗wŠDֳ=*&6d6 N: Cl ^9qb u9ΌPxq[.=z6=3fгgOBFy2> `+"zw@JfAuE!OcǢjժxɛbccѨQ#[u ,) rqF֬YrI&։ 8^^c P~}pB2!!iH c۷QV-|gHJJ2o͚5(St7Xo͑'~ A,YҐLfuV)S&#""ӧOoN+*'۷xbUsNܹS|9@\QG"7(k={ i>}:ԩ%[xMpM^'zML&r+T,VԩnݺqΜ9&ɗ/_dɒV3w\J0ӄ ,hw8 ;"cxr6[W?$枫hnB.ޤI^Lao*OA sw3>>^2ØI9U^$?P)S۷ow8f͚9r$9B<Z% QԩSw}W:}[3Bű@6o6fH2QLM6?wR^6m(Nl$~z}7̚5K;="` I;&^DrrCYk׮aҤIX"J,~ItBȴ{s.o )Hʜ936n܈lٲY;#N܁TxAŋ ( #[Frz _̝;צP*T_|!ކ-ZТE DGGcӦMhڴ) ,ˣ[nڵk$p B]s61%˜93,X`uW^RiPI<) ak3 xaVrѾ g#.P m?M6u(cF0^uAժUmylsΡ{ǤI Z5Q*Dq@(R/UL"gΜXv-:t `3.@#rTj}_E;#?CtQ\Xk׮qu8q??nxO~ׯ^12:t)S\#co u 3($ WT89849HrLh9`8 ͚5YHHu놭[Zb4lÇO?EbU}60̙3$ 4k k0,(QۇڵME`` >>@<%Wl!@'>^. @dS,J*ԩS2dC4iߏp<(GtRI+2 n6^'|(ԪUMyl2@ĢҨu90FcܾP 'OsI]]VԪȰdZ,[9sbvC\aFӦM-7n۱m6lٲϞ=S~~Ï?(*( ]aUӶ*lٳg6yCBB>c_!6}&S"Mry0 )SgϞqIx@,}&2Xtl5 >}*zШQ(R dw~&xS>|wȑ#)dN;gN<ڵcũj gƍ9zhY0?Y*+*yf͚N+Xt;f" zÃ~w7@dh栠 lٲ++Xћkx/cԩ_޲ѣx뭷0rH5 >>>~PW^B*o|30h mذmڴooLUj젶z*VY&HۦӥK߫#_~[&%%a߿? d-볬l+e''OFѕ>T,YA!3vJйsgYޖ ,,LvU?tݻ^zaݺucbb7*Ve˖x86*<!*gi߾=1@t,ڵk'KZ+d Fq#wTڵH} v0;ػwoʕ++O%K24lPZi?ΩS244deʔs礷F2*P ɵpa>[bu!Oҷo_) [نhܼy,)/m~˲vڊ}9sX,AɧO1)h xǏ7o^h˖- HA$/^jsa8gQ0 vwT2OHɓ'f@^zU<#gW*5T0>;gk &$$r9eеkW߿ߦq~ǹrڤv [Na$OBur!RvJF,Rgg[}߶J^EeLL(dլ InذA'}Rd ٲeS㣏2RlMz.e%ۍ|Ȗ*Hz_H!dN~7k=;=P) %&ܓ$#o+PT0e&}^{M `!wpVRQQQ7o8RR8c >|;w~g˖0_4msiBᣟ :uĔc =$}d~fgV.\nb]QJI2::d vJzYYyRXxj2QO7n`  rz/((vzʔ)a%ؤI鑊R0cٳgo4;v;w 6ȚiZ޽[ZW%TSW^}]sPrvfHeɒdd~g0*NELI1D\\۵k3sܳg5$=`y* ]2*Vh鸭j2qi) #LMMerr2sʥQ``TFH氲^}XzX-(4n8-1׊*U(Ξ=TcQ?I&yz{{s\!Xbb"?~,7ts ᗃ(DkO!L I'ٓd (DjkG=HcRJiPAPģGضm[,X 6j(x5!ك³7J?@?6>SPQH;%%&QCjڴf ?'gWW0VZ [ْ X֪UKQoϜ9#H JR4ʓ) ݻw- ,P|>ciqsA^ʲe˺t̙0.EflIn$! Wv[j%U"5TP^M"֗ 6m8XIdYqbT K/(<_u̥ Sw'@Ȝ~]7G x3gNivs9kɔ;QFؼyBqydʔɊW\Ars%KJ3 7t@62Xܺu  BL[2Vu(c>09!,`8ٳk׮ӧ .,~`0 J>}-Zp*'VW_}%uImɞJIa1<|uۏ$9ydz{{S(GܶmtRE3>J7nJ6ׯo޼)Or i ?#,,LC'%ԃ ر]Jeʔ1 jdv)\ee3m4\:YW,?}ɒ%ǚ᭡δhm,Y COٶm}9Ɋ"En Yqi';Ǝ;2wv=slРNj[U H%{(zZ*F᧟~jTN.˗( $K3g6mjR4 #""h"i8mR0঱% ֭[|w[Qti>}Z:F([VV+,O!9Iae%O0_Of-h+VSLh'䔾kצ)_){u2.bz$M> &ᝇd)+}W\YC7_nbvj] cǎܽ{#$9|TѣGyi&&&)L9 gvɢ9(?|}BקN~~~<~\oUdNcwDQǏW_4h42n&uS2%Q/Xp޼y|8-Z022PB?~>dIӂ oiʞ8q¨hx~w&!lٲL2lР۵kǺut̞=Ż@\nɗM7 (ݻ|7A2gϋc%guH%n:Esl޼9>}JOǹsL~<{!PYs;v'RŮ];>3d||IѢEz~1v5l߿*Q}}}`3%HLS {[Mn3g^bx[<]9ޛIaٚq7[KKrO5!jbÇ4yDXΝ;MF*UpF>xJHII۷aٓXղSN?4u<~X1x֭[Ӕ5k{m2h &pϞ=|TYERR8f,Y$///(2,*Εu:H*]Ԛ$Ӊӷ@Ilue+WNQŊGOիKm۶H0eiřl񏆧%ǏW!2^U۷3SLrҥK$sO?)s믿g [gP*T0)~A*f fΜi{=)x!WMQ| .Ņ -4M^>>>/,V*L!55QXLkSR9:PK.F,]v̙36l]t{A7|w3 ;&7@G>$gKHHG}(6mSdch7@+/{W>C󲿿acEHI/3gN9C#(e|Fۏ:;X =4eʔ4c (8dLH`VL"{HiW)8t)KDZV#7xђTt}2ۋGa_IX Շ/v$Vyfŏɓt.]޽{[ѣiFe ϭTL.Yp!a8uI^ZKhZN >H*j@Djj*sQԩS'}NHH`…eU`ogABd$-J,)]2v4;7|p0Q-/T8ydd-1J%Y؀>gǀGCq6o#-}aH͙2|sP̙3Y~111"_]4թu5f˖ͨMcǎ(ʞ#pm2b0WҌ/^̲e,ʕ+sFNW8a ___i52[H(,/to]vj\zޤ`bh%KJWHr,t]IO4I dllE268XjU)6vrعs+W-Q0;t;rQq`(@EΝ+ڑK]8NK>iZi4lWwY%"EH5jX=| vE[n'ODedPطo__`콩q|~KwÇ/d˖/_Ls  >Hxw{nWu7 .]*-Ptg=JB-w$ҳZ-]& I!oV|y ))I_Ç8xg^Js\hQȑC< uB}[ݻ7rΝܳgϐ9s4ЧO'4QÇǘ1cT̞=thz™3gXv֭~'kCEƍ)S |z8Ҙ1cо}{dɒFh&9I,\©۷/F`*֒"^Ҳػw/WrN/}`„ Lj#ҔtvءX7&LCJC'OĦMp ܼy111y&^zP"OQIeS)һ[掤u,T% '>HyzMoJvH |Ld|ޖzjԨ5<晨s?vjyF qqiƦU爈NͶƍoYT)#GvUT|,IRgvs:tSΤ͛K"&HU02m;w(-[=4+?Tɞ=;2>wu.lPB{IH𡛪A ;vr b||B:35k4~^^^R):?M|%?H]<|ryO:ǜmNט4h`Ԗ@޻To'NYfyZ-;vȻw*'bъ+1Q!I9rdsO>UT"##}6۴iP///vЁ.\P/99Y6~奿sw=_|y]EY#t' WEr{L`&y$o޼i2<hт6mҥKmZsmؠO<õd#w200PݻK69HZD ] i sGPcŊX As$ B>}zk{@%ڪ};֭[s"+u9={fU3fxImKFXvI,.X3u=d۷or/^0rfHXb&~N Ν;^x}X$sOf={vו$Yt1!(r{L`҇ݐ^h۶m4\GPHHE$ &{c$E#$wYq;y'B&ݺunܸau [LJ#GT͈g"E/e˓3d9rl6)5r;wȶᅲGb^扫h*)XB$Iu WEr{L`oC Nsl{9 ٳǩuf͚բ$KJj3gsTW쐹,Ŗ_a0 j)yyy1))Idd( ӧ[-UV2IѣGK/$!|"I.իgF#@+Vmˉ'(k:F!ܽ{/D֬YX=RRRXP!s, 3F-/^:uX䒃+i2)ZގcǎHno RK ڵ[W]-N… 5ĥK%f6O1b;*ɲe8L|PwJC![- HXpTK(00hQb˖-vDm#z㑐D$''=qqqx=z}۷6I,a90Dtt4[0OJJ͍܉'lz.^朽AIs/0h *THz?7/_>߻w/߿f)G8p쵉'"_|i͞=h͟??ͱVO?___#;wD߾}lmU%f0G" IJ)ȓ'4?c~pUPh,ɓ'PhQk.͹۷u>|QQQfS|ll,~SǵmBG̙3ԩrʅ̙3#SLZpٲebD*U(ə~oØz.F,ɓq4Q0Ns,Ig3<@VAAAF,6=x۷oOSu֨T .UVHNNvLm$$$$ _Y(Z **A5jҜ;w~-ZdL--[6kf- d.d;\͛1p4U0֬Y8# .ʕ+}(k0i$H>S\QfyⅩv;w" p=4k ^2֣G9_jUFѣGIHH@ƍݞI:66V<}T7*PX1_ǍM1 UP(0 2ioZx ,pY-[f:uv>}Z9JV?csZu"""m B۶mml%P T%`4jܹx7Ҝyv|reJ.r^{ 6㿶BCC3LҥK:u*WqyGۭ[$.>;[ЯĔ-[$A,Yy-qqq1bˣjժiέ^6lHa^\9>Ld]+WF\&N5<Hoϥ +Md_jFS}!dzDʕ}駈wy[veQM4==zT_q-s9b!*ω!hd8uo @:Hd IDAT0erGҥK+%%ӦMåKl(U\]!a/v^?,}wavZ]ݷw^邏ۡ$k9K9E.s?T 6ȟ?4F̽</{8a*.\ 6-FI䠤`i̤"pH\}0Tk׮4ΝsC0}o2`s :a ƒ%Kd?(mɓ6_nܸ.. Q HX`[FIP-ZH &&۶ZEjOq[nB ói0/// 2m}4wb; Ry>-;_]֎"///>+WW_}UGRSS*{XX4XG7/g}… s˖-LJJbTT[nzkԨ!i il ,n7Mz^]%cǎɶ'>>rS-FG8zh{WnT>::}R&MdeO˗7*ᅨHj]0wMI2995rxFIwnYDno R Ϧ}Y]rŔC=y۷O,[i-In߾ݥw;v8VIj<@/w{zR.ۨ=QQQիW9sfKM6?P,?n8K.u{?D fttI288K.O`޸Sx2>>*Ur(QJ<@~j"h!^z#p<ݻgQ$SfR<zl&-ǿ!d48$ 1 8ŋ7.&]mvJ*F6كiӦ)n޼9MN>uh .SLظqG .7"SL⩏rc` ޽{ܜK|@֭kJG2{f3JQPfMwʼny{zF CԊ 1o<\ ]tA˖-8K+XlYVHҌD н{wǏ7:WjUh4@Xp]"(Frʅ-[ Oo-O"b۶mmذA,݅ƕTd"I>zݺusXu҅>D UL*#vSNn(O<\|9Ir…nopd1i$9"V*I2$Ǐ1q$U^]?dLzLzH˗qGSy-*ɓ'Xw+WΨ\ʕmذZ*>}(gV} tq5 "wŢE| ,ȭ[HMH]!$i cڠz ,[o)^;xo~4gal#͋UVps Ua???U&Rf/_ė_~xs,Ym6g] 7,g&%g4bԮ]Eppb;v`߾}F  &6~xCUv܉ sƶmP^=r@kUPa t_eIǜ???t'OČ3Ҽ|=U0!xi P!rx닅  Xz4^? BOB[FjՌ ㏘9s"l߾KvZ#Ν;Fs0N3CsB i&жm[KF>}gM(/V!puŋGttɛwtѣ.^(WS-HyU;[oY,9s_~_ٸqcG>*lbPvmd˖ ٳgGl$=I9D^^^LHH0;Ek׮^"EPTTU;kC 1+Kkp Λ7a$=@jb7lz@ ) P/?UT /b䥊T6U_PHЛD @zϞYgk6dg6gwg̜{9m+++rrr"///ݻ?y{{+ڊbS,q1VFҩ 4ȠΝ;I=d2rtt$___ G}bcciݺuzlڴIc_ʕ+iСԯ_?ѣCͺSo("[ʍ8^2YN8!3wsO9&>4!BƍMCbbVG;v:vvv0{lRu:tuk) HJJg>?3g`ԨQߎħFH6#""pƢEPSSwg^qqq1ܤIvZnSFU!qcd{:u///R`ee:7I}}=QSSZVVwݻxw^'s`m22,bI#"ZjU׭m=B0Jh{rssn -;lGyD>O6mڤQg">ŗ|@DaϫWmKsssuVu\^^^~]ILRNČw!),,FMϧ;vٳg)??fSQrr2۷>SzW^dkk꺱bTomH! TSzz:xʳM46oLt7vءfS(K n:?~:uwuuնUə3ghӦMڪn6wwѢEF#%%6l@2zуrrrL>Ċԭ[7[+:u/r[b ]*"zDQxg)//OA'zm߿_o8q"aaaV}Àk0|poMI\\FjC[$-6J}oq UD|_{걹֒ʹ^yb DԵ D9t}^&Q޽i4#puZv-1u]@@7jY*UQQA>k0775kִA-NCŋ  ⢳~H<`Qd/ٳ.8_n|!bX`:D:P:uB&Q__ Z? M5זlժUm|pvvO|],$vl3suuպհo4 ef8f*>RÇGff&RTVVJlmmakk| t ɓtRP({1`$::{>|8 Gbb"QP $$op19UU+Wю* ۷fڵk5 644`̙r 6nܨ5zS[ЀjTUUVWWss(Gvv6'Ø|嗘>}:/џ8q"oF0'<40n8gIS qqqؾ};&N0mG^(8b40Vy@3ga ddd`РA8r-9݀࢞[(kaÆ SnfO?Mݻ@g~%vRNNNhhh{p͛8x /{001([z5Ux^z(bG.#--Møa:Lp{֭ vL&swyGmpu۷A~~N)**RM&+NNNprr{}ՇB9szje͛KN%pE'#,saѨX%ŋ/WWWO\)5Q΃:u5;_tVDDjY+S е`̝;~gںu+WT_tt4%&&W_}E666O.X[QP3mv۷ >ixxxgϞ l-"Sm!DTFDe 1CIIIM.,--8uww]Q_NL[nKEEH׌ &:u Æ CY ߏC ,\H$$$˥~j*|8?}]ح[7 /`M7zhK"rO;L[&''_~M -^v؁^z UAq0FxGpyaBfeeK.'$&<p*..F5ٳ&Lh JJJުVUU666;2_K;w.VXV8xY8`K:ge <W^Րb#n\,,,pGGHH0rH$'k6dرձg< H5`fDп:!!!8{,@$5!&z:q988hXhdfdd$7L-&۠9rhͼXޜoDD4q& 2v j bPii) >\)))imذA~)[S[E"?S|m^"'1lb6nܨQwzGnsssk.Zx1M2 Faaadgg'x7%ԧO7n͙3֭[G %''Syy KKKcsv$9 ?~mbl6l7g1ׂН?5"#}H. Z|||hĈۣ][">uun8lyߑQuNN/ *MUr9]M "dgPD[FFDo|m}yfRG&W | }#5S}X.\s޽{s!_H3TږxzzҀ_+W?%saa!\dTYYVe%2{Ab,E9jnffWڳ-ă1#B׹XdϞ=l7d1v `ѣ1bDJ~\._L ~X5}0 aÆaŊ5k;}Y o?"ҹܹsѹ2m u@<SN_mbE_=ZĬlo*$|ӦMDÇ[nݗ_~&'QNl x;{{{A^]t}䭾*RQQaжr###@n4VP\`DDD(GlVoU9BPus999%OO׮]aoo~l୷Z; ..2dlm`,Cq`ĈA0}v8pʶK.i32 !'V3g"%%_};_|^^^½{pme1w\% 8ɝ`ƌOHV ˇ͛UG.]0rH!tL&Ô)S0|m۶aѢEds 2FFF6kG{{{!((ݻwGPPR<<dу4-JoeOD$|Idы/H6lK.q3 Ж-[W_P؏>' ߎ| "jԨQ|r:y$UWWDݻw駟~w}7yȆoKe\'͍;d1vgO}zvvͿ/:prr1DԍDDO@un>D  #[~&>C&qAj8Q%ڵkUҒ޽d}UUUѽ{ƍt:r߿vI?>|Ν;Giiit޽f=<*z9MAId+&66V\ Faa!߳Emȧ!"zs=GGmm-}7ZfΝl$|;\!"__p@5ʋ{N.]gyFh5ҥKq5Z֒ 1[JJKKq 8qB۷oŋYC5s X Z@D{{{i.\vMs=`nn~eTeeQ *`kk&NPUZ9A}Uic_BPٴi_8%Z{d`HM:]}<CSO">>K,={rDFFbĉ1c;QMz"G38W_}p—шS7pvvFqqz۷o# `"#Ev\|D[n!##999(++k2|禖YXX y>t#___;wTeZvm`S\\f-+((@ff&f@UU㛙Fڶۣs D@@7lhkqYVEp":x!cW4Ƈ~5kQy*%`lk>>>X~=֯_JVxLY]DOs=z}#Jb?|Wذa9}a ;;;bшcgXL_91*$[N.\@JJJ׬,Դ(..nq+燀# xGRրɂ)!^Kcu.NMM00pE\|*R^^ަ *++57ۗS7ޒ=0ᝓE֭[e`"77Wh5$ڞ:8 f# z¢4[$egi6//#Gl Tl@ߓ刍Ell,6n܈'O_ŋqիCr,{~rZ}YYY(((s甒f3uuu@FFw۷RԓH`a}aTk]r 0F;Ξ=$l*((@AAΜQM VaRmyΝ;KBŽɓ'1~xxQ2pn%?h&O6PS|H3*X(=(]e2]8/O%Tbb"ܹr@XXX 77W` dff,@]Q:"hxCJJF5rQF᧟~<øxϟ֬YYf) ..o6B ;ffIWLMkW|D aP;ZXZZўi_!MC Ɨ@20'j6w Se9뚚|GBbTLt�` Q5 06e'0Gcޏ+W`*^;wƖ-[335lDDD`ƌ8p@!"L>ԍ/}x= rGmXYY5?p?dV*ޗ"55u`-'7ϟR"))*&d`#jpoD#=x7Evt$q_<1.&d`XEƱ̦0йQkCt:4xK.!&&F%'v77f%.]`GDD(FtN kPw8ɫ1.oV@hh(BBBT^;w 4;;ׯ_בׯ#--EN-D큡pYYbgg}Gj+UUUS kKUdzƣ*,,~cpve|ЀBF؂5A4B*c L/_\h] 8y- f@I~~>dSQ؇P!44T= GXj.\[`(?)=y$F Ynm6=ZhHD6mN8UVK Q \!#55Woii rڢGDdd$N``'?1;? 0Ѣ jHED"#ݺuKkO>~ n  GWkܨԇlmm@ũ|!==]oÇ d9p{Ԏ@QQk`5UDDj͚5JaƌVFc}ƍc|D
 hK <˗/GHHz4v ~lGVVn݊>LcGdq$%p8~ZDć\&"ڻw/4)fmRmF_~Yd2ABa>&~Td){{GA~&c…l< 5jjjhÆ Cn)22zI]t!'''.Uv'%dccs}~gҹ y{{SHH=CԩS'֋7͙3j_'"?|V1chh_^kOlT-yk/V%##Col$|{!N8a{h{γ)c?4DP(ן)n^ .04FKmr<oH,g 1s/?4 ѕ Һ5jv #Gw0d*$FеkWh|wavI'E ԙQ®֡PB˜ e˖ pa`cD_xL"K}]]RSS5DO: @sAA %,Xx1N;#'P3Oŋ$Chh(%S M:h nzG[nFTIJW0xj > |O ?h\&MBEEEӅMGb̘13+@rDoz1!. :P)Guu5jkkUFcL&VVwpp'<<<777"=SBiiiy&; `/'he` }Tf{Z#+dzFW09imq-F"PyX0Qfk'oDD7nK'"` ^#M\BM{nǘ7o[OOD@?uć۷HPc=&N|5MD"}[Qё#G۷iϞ=4uTѣuiLqpp~bڵF9R(l.A۶D 7nׯoF=dii)x;K,,,wo޽{͛4ee{IAF15"I]޽}h+$Fh`&"JMMj۷=}ܹs$U499׫'p/k~ BV]\\;1L&@}%:Om["ӉH]@Zwg}[# MEͩOVR) S7^:df!liӦPNBPQ !!!xwُ!Oeu]ڢJud Υ` ef\pAgup:Z0er72). S78I4?5|X ,Y<8СCxMGн{w:uJ#a6H@V˓ŋG@ULwww4%,877נ9vL "m8]tRB-d`HHp$PS(\\\|r!th18}47RaOy 8r&M$-^: H $̘1Cé[B7֘}:Z~gJIIjC/K=EII }4h '8I GҢE(&&Fkȑ#>Ǐ# Dt;"h?>ŇJ.**ٳpaK===iѴb :}4jiDO"->ŽۂeرɌDmڴ oǓhLh]Lyk58`=6@=+3 99^^^ TTT ]tѵ0OL7V555̄\.-lmm`Pf0S9Db_oYBRF%Fe\IU܋`/BD|͛Z_߿o, ~~~ڵ+Tk׮p~pXz ^5BYYN,nF &4cdKZJ8ۦ܊c 0k***͛7Q\\*UUU033 lll`mmo1`%_yyW_"0!W{W@YXXh u.]OM݁p q ZpcIDATo B#ZnݺF@Q@ͦZvH1&K%143Vx16|0kn(`f*+F]X7BmDd>@ ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "boardview.h" #include "settings.h" #include "guess.h" #include "movelist.h" #include #include using namespace Qt; const int CoordinateSize = 16; BoardView::BoardView(QWidget* parent, int flags) : QWidget(parent), m_flipped(false), m_showFrame(false), m_showCurrentMove(true), m_guessMove(false), m_selectedSquare(InvalidSquare), m_hoverSquare(InvalidSquare), m_hiFrom(InvalidSquare), m_hiTo(InvalidSquare), m_currentFrom(InvalidSquare), m_currentTo(InvalidSquare), m_atLineEnd(true), m_flags(flags), m_coordinates(false), m_dragged(Empty), m_clickUsed(false), m_wheelCurrentDelta(0), m_minDeltaWheel(0), m_moveListCurrent(0), m_showMoveIndicator(true), m_DbIndex(0) { QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Preferred); policy.setHeightForWidth(true); setSizePolicy(policy); setMouseTracking(true); installEventFilter(this); } BoardView::~BoardView() {} bool BoardView::eventFilter(QObject *obj, QEvent *ev) { if(ev->type() == QEvent::Leave || ev->type() == QEvent::WindowDeactivate) { removeGuess(); } return QWidget::eventFilter(obj, ev); } void BoardView::setFlags(int flags) { m_flags = flags; } void BoardView::setBoard(const Board& value, int from, int to, bool atLineEnd) { m_clickUsed = true; Board oldboard = m_board; m_board = value; m_currentFrom = from; m_currentTo = to; m_atLineEnd = atLineEnd; if(underMouse()) { updateGuess(m_hoverSquare); } update(); } Board BoardView::board() const { return m_board; } const BoardTheme& BoardView::theme() const { return m_theme; } void BoardView::showMoveIndicator(bool visible) { m_showMoveIndicator = visible; } void BoardView::drawSquares(QPaintEvent* event) { QPainter p(this); for(Square square = 0; square < 64; square++) { QRect rect = squareRect(square); if(!event->region().intersects(rect)) { continue; } int coord = m_coordinates ? CoordinateSize : 0; int x = isFlipped() ? 7 - square % 8 : square % 8; int y = isFlipped() ? square / 8 : 7 - square / 8; QPoint pos(coord + x * m_theme.size().width(), y * m_theme.size().height()); p.drawPixmap(pos, m_theme.square((x + y) % 2)); } } void BoardView::drawCoordinates(QPaintEvent* event) { if(m_coordinates) { QPainter p(this); p.save(); p.setPen(m_theme.color(BoardTheme::Frame)); for(Square square = 0; square < 8; square++) { QRect rect = coordinateRectVertical(square); if(!event->region().intersects(rect)) { continue; } p.drawText(rect, Qt::AlignCenter, QString("%1").arg(square + 1)); } for(Square square = 0; square < 8; square++) { QRect rect = coordinateRectHorizontal(square); if(!event->region().intersects(rect)) { continue; } p.drawText(rect, Qt::AlignCenter, QString("%1").arg(QChar('a' + square))); } p.restore(); } } void BoardView::drawDraggedPieces(QPaintEvent* /*event*/) { // Draw dragged piece if(m_dragged != Empty) { QPainter p(this); p.drawPixmap(m_dragPoint, m_theme.piece(m_dragged)); } } void BoardView::drawMoveIndicator(QPaintEvent* event) { if(m_showMoveIndicator) { QPainter p(this); // Draw side to move indicator int coord = m_coordinates ? CoordinateSize : 0; bool white = m_board.toMove() == White; int square = width() - coord - 8 * m_theme.size().width() - 4; int maxsquare = m_theme.size().width() / 2; if(square > maxsquare) { square = maxsquare; } if(square > 8) { int posy = (white == m_flipped) ? 1 : 8 * m_theme.size().width() - square; QRect rect(8 * m_theme.size().width() + 2 + coord, posy, square, square); if(!event->region().intersects(rect)) { return; } QColor color = white ? Qt::white : Qt::black; QColor border = white ? Qt::black : Qt::white; p.setPen(border); p.setBrush(QColor(color)); p.drawRect(rect); } } } void BoardView::drawPieces(QPaintEvent* event) { QPainter p(this); for(Square square = 0; square < 64; square++) { QRect rect = squareRect(square); if(!event->region().intersects(rect)) { continue; } int coord = m_coordinates ? CoordinateSize : 0; int x = isFlipped() ? 7 - square % 8 : square % 8; int y = isFlipped() ? square / 8 : 7 - square / 8; QPoint pos(coord + x * m_theme.size().width(), y * m_theme.size().height()); p.drawPixmap(pos, m_theme.piece(m_board.pieceAt(square))); if(m_showCurrentMove) { if(square == m_currentFrom || square == m_currentTo) { QPen pen; pen.setColor(m_theme.color(BoardTheme::CurrentMove)); pen.setWidth(2); pen.setJoinStyle(Qt::MiterJoin); p.setPen(pen); p.drawRect(pos.x() + 1 + m_showFrame, pos.y() + 1 + m_showFrame, m_theme.size().width() - 2 - m_showFrame, m_theme.size().height() - 2 - m_showFrame); } } if(square == m_selectedSquare || square == m_hiFrom || square == m_hiTo) { QPen pen; pen.setColor(m_theme.color(BoardTheme::Highlight)); pen.setWidth(2); pen.setJoinStyle(Qt::MiterJoin); p.setPen(pen); p.drawRect(pos.x() + 1 + m_showFrame, pos.y() + 1 + m_showFrame, m_theme.size().width() - 2 - m_showFrame, m_theme.size().height() - 2 - m_showFrame); } if(m_showFrame) { p.setPen(m_theme.color(BoardTheme::Frame)); p.drawRect(QRect(pos, m_theme.size())); } } } void BoardView::paintEvent(QPaintEvent* event) { drawSquares(event); drawCoordinates(event); drawSquareAnnotations(event); drawPieces(event); drawMoveIndicator(event); drawArrowAnnotations(event); drawDraggedPieces(event); } void BoardView::resizeBoard(QSize sz) { // subtract move indicator from width int coord = m_coordinates ? CoordinateSize : 0; int xsize = (sz.width() - 1 - coord) / 8; int ysize = (sz.height() - 1 - coord) / 8; int size = std::min(xsize, ysize); m_theme.setSize(QSize(size, size)); } void BoardView::resizeEvent(QResizeEvent* e) { resizeBoard(e->size()); } Square BoardView::squareAt(const QPoint& p) const { int x = p.x(), y = p.y(); int width = m_theme.size().width(); int height = m_theme.size().height(); x -= m_coordinates ? CoordinateSize : 0; if(x <= 0 || y <= 0 || x >= width * 8 || y >= height * 8) { return InvalidSquare; } x /= width; y /= height; return isFlipped() ? (8 * y + 7 - x) : (8 * (7 - y) + x); } void BoardView::mousePressEvent(QMouseEvent* event) { m_dragStart = event->pos(); } bool BoardView::showGuess(Square s) { // Don't want to constantly recalculate guess, so remember which square // the mouse is hovering over, and only show new guess when it changes if(m_guessMove && s != m_hoverSquare && !(m_flags & SuppressGuessMove)) { m_hoverSquare = s; removeGuess(); m_moveListCurrent = 0; m_moveList.Clear(); #ifdef USE_ECO_GUESS if(m_board.ecoMove(s, &m_hifrom, &m_hito)) { update(squareRect(m_hifrom)); update(squareRect(m_hito)); } else #endif { Guess::Result sm = Guess::guessMove(qPrintable(m_board.toFen()), (int) s, m_moveList); if(!sm.error) { m_hiFrom = sm.from; m_hiTo = sm.to; update(squareRect(m_hiFrom)); update(squareRect(m_hiTo)); } } return true; } return false; } void BoardView::updateGuess(Square s) { // Invalidate any currently displayed guess to allow new guess to show m_hoverSquare = InvalidSquare; showGuess(s); } void BoardView::removeGuess() { if(m_hiFrom != InvalidSquare) { update(squareRect(m_hiFrom)); update(squareRect(m_hiTo)); m_hiFrom = m_hiTo = InvalidSquare; } } void BoardView::nextGuess(Square s) { if(!showGuess(s)) { if(m_moveList.Size() && m_moveListCurrent < m_moveList.Size()) { Guess::simpleMoveT * sold = m_moveList.Get(m_moveListCurrent); update(squareRect(sold->from)); update(squareRect(sold->to)); if(m_moveListCurrent < m_moveList.Size() - 1) { ++m_moveListCurrent; } else { m_moveListCurrent = 0; } Guess::simpleMoveT * sm = m_moveList.Get(m_moveListCurrent); m_hiFrom = sm->from; m_hiTo = sm->to; update(squareRect(m_hiFrom)); update(squareRect(m_hiTo)); } } } void BoardView::mouseMoveEvent(QMouseEvent *event) { m_button = event->button() + event->modifiers(); if(!m_atLineEnd && (event->modifiers() & Qt::ControlModifier)) { if(event->modifiers() & Qt::AltModifier) { setCursor(QCursor(QPixmap(":/images/insert_move.png"))); } else { setCursor(QCursor(QPixmap(":/images/replace_move.png"))); } } else if(!m_atLineEnd && (event->modifiers() & Qt::AltModifier)) { setCursor(QCursor(QPixmap(":/images/plus.png"))); } else { setCursor(QCursor(Qt::ArrowCursor)); } if(!(event->buttons() & Qt::LeftButton)) { if(!(event->modifiers() & Qt::ShiftModifier)) { showGuess(squareAt(event->pos())); } else { removeGuess(); } return; } if(event->modifiers() & Qt::ShiftModifier) { return; } if(m_dragged != Empty) { QRect old = QRect(m_dragPoint, m_theme.size()); m_dragPoint = event->pos() - m_theme.pieceCenter(); update(old); update(QRect(m_dragPoint, m_theme.size())); return; } if((event->pos() - m_dragStart).manhattanLength() < QApplication::startDragDistance()) { // Click and move - start dragging return; } Square s = squareAt(m_dragStart); if(!canDrag(s)) { return; } removeGuess(); m_dragged = m_board.pieceAt(s); m_dragPoint = event->pos() - m_theme.pieceCenter(); m_board.removeFrom(s); update(squareRect(s)); update(QRect(m_dragPoint, m_theme.size())); unselectSquare(); } void BoardView::mouseReleaseEvent(QMouseEvent* event) { setCursor(QCursor(Qt::ArrowCursor)); int button = event->button() + event->modifiers(); Square s = squareAt(event->pos()); m_clickUsed = false; if(!(event->button() & Qt::LeftButton)) { Square from = squareAt(m_dragStart); if(s == from) { from = InvalidSquare; } if(s != InvalidSquare) { emit clicked(s, button, mapToGlobal(event->pos()), from); } else { Square from = squareAt(m_dragStart); emit invalidMove(from); } m_dragged = Empty; return; } else { if(event->modifiers() & Qt::ShiftModifier) { if(s != InvalidSquare) { emit clicked(s, button, mapToGlobal(event->pos()), InvalidSquare); } return; } } if(m_dragged != Empty) { Square from = squareAt(m_dragStart); m_board.setAt(from, m_dragged); QRect oldr = QRect(m_dragPoint, m_theme.size()); m_dragged = Empty; update(squareRect(from)); update(oldr); if(s != InvalidSquare) { if((m_flags & AllowCopyPiece) && (event->modifiers() & Qt::AltModifier)) { if(m_board.pieceAt(from) != Empty) { emit copyPiece(from, s); } } else { emit moveMade(from, s, button); updateGuess(s); } } else { emit invalidMove(from); } } else if(m_selectedSquare != InvalidSquare) { Square from = m_selectedSquare; unselectSquare(); if(s != InvalidSquare) { emit moveMade(from, s, button); } } else if(m_hiFrom != InvalidSquare) { if(s == m_hiFrom || s == m_hiTo) { emit moveMade(m_hiFrom, m_hiTo, button); } m_hoverSquare = InvalidSquare; // Only update guess if "emit moveMade()" did not pop up a window (eg. promotion) if(m_hiFrom != InvalidSquare) { updateGuess(s); } } else { if(s != InvalidSquare) { emit clicked(s, button, mapToGlobal(event->pos()), InvalidSquare); if(!m_clickUsed && m_board.isMovable(s)) { selectSquare(s); } } } } void BoardView::wheelEvent(QWheelEvent* e) { m_wheelCurrentDelta += e->delta(); if(abs(m_wheelCurrentDelta) > m_minDeltaWheel) { int change = m_wheelCurrentDelta < 0 ? WheelDown : WheelUp; emit wheelScrolled(change + e->modifiers()); m_wheelCurrentDelta = 0; } } void BoardView::setFlipped(bool flipped) { m_flipped = flipped; update(); } void BoardView::flip() { m_flipped = !m_flipped; update(); } bool BoardView::isFlipped() const { return m_flipped; } void BoardView::configure() { AppSettings->beginGroup("/Board/"); m_showFrame = AppSettings->getValue("showFrame").toBool(); m_coordinates = AppSettings->getValue("showCoordinates").toBool(); m_showCurrentMove = AppSettings->getValue("showCurrentMove").toBool(); m_guessMove = AppSettings->getValue("guessMove").toBool(); m_minDeltaWheel = AppSettings->getValue("minWheelCount").toInt(); AppSettings->endGroup(); m_theme.configure(); m_theme.setEnabled(isEnabled()); removeGuess(); unselectSquare(); if(size().height() >= minimumSize().height()) { resizeBoard(size()); } update(); } void BoardView::selectSquare(Square s) { // You can't select a square when guess move is enabled if(m_guessMove && !(m_flags & SuppressGuessMove)) { return; } if(m_selectedSquare == s) { return; } unselectSquare(); m_selectedSquare = s; update(squareRect(s)); } void BoardView::unselectSquare() { Square prev = m_selectedSquare; m_selectedSquare = InvalidSquare; if(prev != InvalidSquare) { update(squareRect(prev)); } } QRect BoardView::squareRect(Square square) { int coord = m_coordinates ? CoordinateSize : 0; int x = isFlipped() ? 7 - square % 8 : square % 8; int y = isFlipped() ? square / 8 : 7 - square / 8; return QRect(QPoint(x * m_theme.size().width() + coord, y * m_theme.size().height()), m_theme.size()); } QRect BoardView::coordinateRectVertical(Square square) { Q_ASSERT(m_coordinates); int x = isFlipped() ? square % 8 : 7 - square % 8; return QRect(0, x * m_theme.size().height() + (m_theme.size().height() - CoordinateSize) / 2, CoordinateSize, CoordinateSize); } QRect BoardView::coordinateRectHorizontal(Square square) { Q_ASSERT(m_coordinates); int y = isFlipped() ? 7 - square % 8 : square % 8; return QRect(CoordinateSize + (y * (m_theme.size().width())) + (m_theme.size().width() - CoordinateSize) / 2, 8 * m_theme.size().height(), CoordinateSize, CoordinateSize); } bool BoardView::canDrag(Square s) const { if(m_dragged != Empty) // already dragging { return false; } if(s == InvalidSquare) { return false; } else if(m_flags & IgnoreSideToMove) { return m_board.pieceAt(s) != Empty; } else { return m_board.isMovable(s); } } int BoardView::heightForWidth(int width) const { return width; } void BoardView::dragEnterEvent(QDragEnterEvent *event) { const BoardViewMimeData *mimeData = qobject_cast(event->mimeData()); if(mimeData) { event->acceptProposedAction(); } } void BoardView::dragMoveEvent(QDragMoveEvent *event) { event->acceptProposedAction(); } void BoardView::dragLeaveEvent(QDragLeaveEvent *event) { event->accept(); } void BoardView::dropEvent(QDropEvent *event) { const BoardViewMimeData *mimeData = qobject_cast(event->mimeData()); if(mimeData) { Square s = squareAt(event->pos()); emit pieceDropped(s, mimeData->m_piece); event->acceptProposedAction(); } } void BoardView::drawSquareAnnotations(QPaintEvent* event) { QString annotation = m_board.squareAnnotation(); if(!annotation.isEmpty() && !annotation.isNull()) { QStringList list = annotation.split(","); for(QStringList::Iterator it = list.begin(); it != list.end(); it++) { if(*it != "") { drawSquareAnnotation(event, *it); } } } } void BoardView::drawArrowAnnotations(QPaintEvent* event) { QString annotation = m_board.arrowAnnotation(); if(!annotation.isEmpty() && !annotation.isNull()) { QStringList list = annotation.split(","); for(QStringList::Iterator it = list.begin(); it != list.end(); it++) { if(*it != "") { drawArrowAnnotation(event, *it); } } } } void BoardView::drawSquareAnnotation(QPaintEvent* event, QString annotation) { QPainter p(this); QString trimmed = annotation.simplified(); QChar colorChar = trimmed[0]; QChar fileChar = trimmed[1]; QChar rankChar = trimmed[2]; QString files = "abcdefgh"; QString ranks = "12345678"; int file = files.indexOf(fileChar); int rank = ranks.indexOf(rankChar); int square = rank * 8 + file; QRect rect = squareRect(square); if(!event->region().intersects(rect)) { return; } int x = isFlipped() ? 7 - square % 8 : square % 8; int y = isFlipped() ? square / 8 : 7 - square / 8; QPoint pos(x * m_theme.size().width(), y * m_theme.size().height()); //p.drawPixmap(pos, m_theme.square((x + y) % 2)); QColor color = Qt::red; if(colorChar == 'Y') { color = Qt::yellow; } else if(colorChar == 'G') { color = Qt::green; } else if(colorChar == 'B') { color = Qt::blue; } p.save(); QPen pen(color); QBrush brush(color); p.setPen(pen); p.setBrush(brush); p.setOpacity(.20); int coord = m_coordinates ? CoordinateSize : 0; p.drawRect(coord + pos.x(), pos.y(), m_theme.size().width(), m_theme.size().height()); p.restore(); } void BoardView::drawArrowAnnotation(QPaintEvent* event, QString annotation) { QPainter p(this); static const QString letters = "abcdefgh"; static const QString numbers = "12345678"; QString trimmed = annotation.simplified(); QChar colorChar = trimmed[0]; QChar fileChar1 = trimmed[1]; QChar rankChar1 = trimmed[2]; QChar fileChar2 = trimmed[3]; QChar rankChar2 = trimmed[4]; int file1 = letters.indexOf(fileChar1); int rank1 = numbers.indexOf(rankChar1); int file2 = letters.indexOf(fileChar2); int rank2 = numbers.indexOf(rankChar2); if(file1 < 0 || file2 < 0 || rank1 < 0 || rank2 < 0) { return; } int square1 = rank1 * 8 + file1; int square2 = rank2 * 8 + file2; QRect rect1 = squareRect(square1); QRect rect2 = squareRect(square2); QRect u = rect1.united(rect2); if(!event->region().intersects(u)) { return; } int x1 = isFlipped() ? 7 - square1 % 8 : square1 % 8; int y1 = isFlipped() ? square1 / 8 : 7 - square1 / 8; int x2 = isFlipped() ? 7 - square2 % 8 : square2 % 8; int y2 = isFlipped() ? square2 / 8 : 7 - square2 / 8; int w = m_theme.size().width(); int h = m_theme.size().height(); int coord = m_coordinates ? CoordinateSize : 0; QPoint pos1(coord + (x1 * w) + (w / 2), (y1 * h) + (h / 2)); QPoint pos2(coord + (x2 * w) + (w / 2), (y2 * h) + (h / 2)); QColor color = Qt::red; if(colorChar == 'Y') { color = Qt::yellow; } else if(colorChar == 'G') { color = Qt::green; } else if(colorChar == 'B') { color = Qt::blue; } // Now to Draw Arrow Head qreal headWidth = m_theme.size().width() / 4; qreal headLength = headWidth; qreal headIndent = headWidth / 4; qreal netIndent = headLength - headIndent; qreal halfHead = headWidth / 2; int px1 = pos1.x(); int px2 = pos2.x(); int py1 = pos1.y(); int py2 = pos2.y(); int dX = px2 - px1; int dY = py2 - py1; qreal arrowLength = qSqrt(dX * dX + dY * dY); QPointF arrowPts[7]; // we will shorten the line somewhat to avoid arrows all colliding in the center of the square int adjust = (w + h) / 8; px1 = px1 + ((adjust * dX) / arrowLength); px2 = px2 - ((adjust * dX) / arrowLength); py1 = py1 + ((adjust * dY) / arrowLength); py2 = py2 - ((adjust * dY) / arrowLength); // calculate the points that form the arrow arrowPts[0].setX(px2 - ((netIndent * dX) / arrowLength)); arrowPts[0].setY(py2 - ((netIndent * dY) / arrowLength)); arrowPts[4].setX(px2 - ((headLength * dX) / arrowLength)); arrowPts[4].setY(py2 - ((headLength * dY) / arrowLength)); arrowPts[1].setX(arrowPts[4].x() - ((halfHead * (dY)) / arrowLength)); arrowPts[1].setY(arrowPts[4].y() - ((halfHead * (-dX)) / arrowLength)); arrowPts[3].setX(arrowPts[4].x() + ((halfHead * (dY)) / arrowLength)); arrowPts[3].setY(arrowPts[4].y() + ((halfHead * (-dX)) / arrowLength)); arrowPts[2].setX(px2); arrowPts[2].setY(py2); QPoint pos3(px1, py1); QPoint pos4(px2, py2); p.save(); QPen pen(color); int penWidth = std::max(1, (int)(headWidth / 8)); pen.setWidth(penWidth); p.setPen(pen); p.drawLine(pos3, pos4); // For now only draw part of the arrowhead //p.drawLine(arrowPts[2],arrowPts[1]); //p.drawLine(arrowPts[2],arrowPts[3]); QBrush brush(color); p.setBrush(brush); p.drawPolygon(arrowPts, 4); p.restore(); } void BoardView::setEnabled(bool enabled) { QWidget::setEnabled(enabled); } void BoardView::setDisabled(bool disabled) { QWidget::setDisabled(disabled); } void BoardView::setDbIndex(int dbIndex) { m_DbIndex = dbIndex; } int BoardView::dbIndex() const { return m_DbIndex; } chessx-1.0.0/src/quazip/quaadler32.h000644 001750 001750 00000001057 12223260306 020024 0ustar00niklasniklas000000 000000 #ifndef QUAADLER32_H #define QUAADLER32_H #include #include "quachecksum32.h" /// Adler32 checksum /** \class QuaAdler32 quaadler32.h * This class wrappers the adler32 function with the QuaChecksum32 interface. * See QuaChecksum32 for more info. */ class QUAZIP_EXPORT QuaAdler32 : public QuaChecksum32 { public: QuaAdler32(); quint32 calculate(const QByteArray &data); void reset(); void update(const QByteArray &buf); quint32 value(); private: quint32 checksum; }; #endif //QUAADLER32_H chessx-1.0.0/data/images/circle_yellow.svg000755 001750 001750 00000023130 12062314776 021356 0ustar00niklasniklas000000 000000 LED Circle (Yellow) jean.victor.balin@gmail.com led shape Open Clip Art Library Jean-Victor Balin Jean-Victor Balin 2005-08-21 image/svg+xml en chessx-1.0.0/data/images/chessx-64.png000644 001750 001750 00000020255 12117557125 020233 0ustar00niklasniklas000000 000000 PNG  IHDR@@iq CiCCPICC ProfilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/7bKGD pHYs  tIME %9=IDATx{egye33gfoׄ$JB@6)$QD[WIZ7DVU $@IH%4U)8 c;0̜/]4`;묳g>=ύsyF}C=K7ODVJ] \ v;EfMJ?tJ)DZfvt7n~k;O8j,w:Gk)=~HO.JwKOmݒI\ Di|9LvŞ_ιW!"ko~} xRC_r_RIui2]GV$eN;,a6e9q@=_8v}/J~oIMvWDvN w_w{*Y߱F=-eUC JdY ,M@ 9kkk(4.8̷g$IJ[/{x2I[n4ww?t65] i| m4$yk:mO^EwB!"oZkSq>з-i:Z\k\rA? ^<~]_=&{Hh{ʜ1I|MeHu|Af@ rI[|# x|5gUJq Z[nT>1.".Hp(D߃4Mc<$ FCIK@ Y# *G)E^[7ߠ>;DU8"BE"OЃJkB!}c$3@TcYl5m< V `E|ۣo(Rrcq] gVs{f8R_{> 1">b -B{J#>`!ƈ|⺎z$J'Hh@`>_""mp]w,K,X>n_WS`d#(H(%&֦!hP}KIBb-yR,sP PJ$lb(׷4%{bpƐC;p$Sw?t6UOC+5c9I,m&SɊ y,Cx(#B0w9!z`!A"! t]G|S~Ӧj_}ݭ^pcD|Q CBCZdPHh! F+h9kٱcwZbTC8"Qh]_c,TB_D>bA5QȋNh"YlQp@{O*=>8diچz@D~ FJ)e-āQՈno=861/>۳(ר $yb 1)%mײ6Vc>鏱8|?^ػ14q0Uct;f[,y5{ V}ɍ+'ا$U1P F1jQ!p1g~| Fm^˘@2e9O%9b}:H{llF bɡYͣDg "k(s!sKw(n< "t%T`"1$%$" 1$6A)00 "(r<ᡭ%x #/I&/y ٪#[uǡG@ukfCFmPXΖޱs EU[~9o~شc( 4Ibӄz16Căhd0t9& ?/Ϳ8`/#֋āgH$ s'h$g^Jr\K7Z\ ~n&k m#.:poG"Yֲ#¾3w^ĵVP5dO9"'z|_kN /[ }h Yb@ J\iZ5dz8d{0 Qέ袧Ovɨ^QDP B[tz1G)M,e A"6)Q8쿛3/j|wI55VU:$ I:Jq=o{}#3ou|4GDw 2tDr F19buX3Ly6gU2'IUa"hO\TJѩ怋=_&HXV(Ȋb6h0JW<ߦ *C'ӂg!vn>DHDª@۶cw^D=tڜ&;'kUNt J XB 8>!CVMC K˥8c%iC "eiB&r(#O l F%d2^"(QyAdy6O+FS)RC2 bUZ c(J-gk37*r kU1PҔ,>vh5z_`_7$yAmע&ƈ1,)tzV!(ue2͵QR0ϫ,X߽s'@r`p=y%}OZ'ƀjVC$Ʀ$E' z8Qà'jy(Z33Bײ6)!t{Ē勺gOG]OQN]O4kZ(HcJ c% /1*x}9A |1FY iӹA3t*cP(A#4mI Odz6uH{DF14GъUcp~E ZiH^xB<Uhێ"iB9cy-bE ]O}S`d$AB V(齣Y6,*KDP,AEkx '= '!V+&k]h4@[ ,n#q؟ }GYCҤOVC;99!a(U9hJkGmۢ&+Jf5^ ~Xy Nm (gdZͱ-,ƛ$cȪj:OT6rU8É+0eΏMxl_}Ǐ|leCZq |NYL)}tc{-LW\Mbe34C!]5P",h%$ƢED:CGחJ_(._ŏ_~+yؒ##G(e1\Y ]rvn^.9EW2X"5} )̢UVw$EFW՘/IfGou}=9pEjQB4m#5{@ZZܵ(cx,VζY+^ `eKcy__RD-g %CF$9ǭ<{A~ "c^_zՠԄqؒ|JvdE(zYd&M-EUqeRTJtDQDUeUC_Z")͢5k55$VaMb4(c cF+nT;7LG O-w]6-EMY4UeuD.|5JD͑'ŁE}/*M۞&)Guz`mQ\=\󋯧֬f|\KCd8{}7|}쓫e*K黎(Ьk;FB L&g}$YEEw~W{vcPz YV{";i e#>v"2t"v J! Di Xc1)R6#9cInpu6"F+seΫh\6Jp7uw'J p]F55Ĉ$\G[.k4H_WvIZhqde$4`n.,g4ze6\Ʉ4OI 6%IsQ.r?{c8"æ)mk& JAZO,YQ2[4`4Q!8& D ȏZ^~oR՜=Rk?>t/&{Ntb7Ut864>zD {LjWYرd} cf)ijx~-\x`v}O9)]0Z"h*Aփ}.K9rD=;|8n(ѳ1^(v?3b=~{ʷnLloMu=p>p -b9!-՘3w%g_xy%LdY??zn<7ύb[p IENDB`chessx-1.0.0/src/quazip/000755 001750 001750 00000000000 12234477214 015717 5ustar00niklasniklas000000 000000 chessx-1.0.0/data/themes/rudolph.png000644 001750 001750 00000161746 12057443252 020215 0ustar00niklasniklas000000 000000 PNG  IHDR4R CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs66BtIME  o| IDATx]u\TCw XH bbuUV]k]w]ZqM,$73oޛA&y޻q}sϹ%/Zw`?7Lzz0J „ -_ܟRB s}ЍJ` ]dd kffF"""L<E c …%% d`` ޽/_.j>+VNV٨w܉-jBPWA۶m{$55bQmʕ #effСCe:Zj+j֬)((O^HEc d)0&K7|RCaVB53zS'ng`̱nȦXqQU&ȡ$hҤc({uYiǁQG&&&D^zm՗QV\4pqq{)S qiڴʟB+K,Hp})0d*1J/E|e``@ʖ-K7nLUFo_œw.U<[LɢW60Y]9Ŗ T(\G ,_~B!@5k۞Kk8y̡_0iO Y|v~k&w%&s%FFF\B}!ʭ FLO0(JHVaM|TwDժU/)C?2dHHQkٲMv 6:sL%UFsԣnB QH>|@0vXrXf%k-|Miנw7{Pz>ʰ TasKKf߿GFF411Aҥ>7oӡge/^xuZ<ɪȸ8˫Wտ:V Uu`v) tV Cٳ'x_5jΝNJ?RN`53Bh6 %~J! `<ӵcIQT5666Dj`[Na:uR#,,Lak FF_zu;ժUK+RN +W.gʔ)g[[[h"@RRRȃΝ;Iʕ>I\((G^xAݻGCjժş{P,!opgSgiccC͛Gɛ7oHBB!\@H.->t% 9::ri^K>'qsvB{#9-[:sL2|ҹsGN*3ݑ|'$$Ç\LR= ٞSP;#GV*r*ڞ<%WJBE65kvC wGM *`鳇Mȥ[ZZ{ZbccN>*̘Ӯ&okС\ttSPΔB~"hT xr*L%ѐ!'=Ojj*cC(+'`d) g8))ϟ?s}KuxM-ƠyիWr:7aӦM??.2iUV+9sfC.RNkR4&!rluH_!c. m-ʇY`"`b[IƀT=s,0;'>Ӛ  *T>lgg媙yQիW)C&_YTP#ʗ/[H$ڵkG|l۶ ٳ'?~05k*UERǎ+ܾ}/FӦMafUݻwmG;6}@p@= /`v+sUf'xyy}\rJÂǯ`A*wVj9g(_]O1;B &J<⡿" W"gzEʢQlRiWE@fеkWRH)_SL9sap>{!C ټbŊk(170nW cǎaXb6@OiDDܻwaaaXhall,\xGƓ'Od>0 .!1XL|MPS9l*{1c͛7:t( {lܸӦMc7"#bqLTwe Qh&T~Kt钠ؼyj_N>͎Y FKIQX5R|GgcΜ92FMOO'떑?TPx 2mc5Hwp! !<>|86@`l9#A `KpOP{xBw2pCj{2_i=@v.G,RhSz bŊO{ԬYSQ;s,XP%'\r"=z4ց3 )8}y~i 51'Kj_U wu x"΋B{WCCCrÇ?dr(AK"*`PCѫWVVV2 mےf͚ڵkMxQA)c䛓CF%7h…M:u/_oر||[BL0%Ƿ`lՁrQGDOmQ䟠 栫* }:7GONmF\B.\@V\I @i2yBal_4hpίY%+0Q<|d;,,dff[nPu#''Ǐj{ޞyK.mEG'\ԯ_+ݤI-6yQc`"䔵F RОj(?h@~tg?iSbErqcIdd$mCVwZXX<}hw?8~۶m3x;v,Zntܹطo}//֭[X|q]A˖-8pd3ݻ;;;)S0}t@5p9ŋܹ3oWWW2vnÆ Fva$Ú&ۧtӧcʔ)\֊zJ_C0ng+lc0|p+S5-9OswJcFT8 m(D qyЫ ƋMuI>>}||p 4a\E28 x mB;!?痕Wsǡ$$?77WkDΠRÆ 9dԩ{ׯv7RvWÆ sЩS';kkk[ld/Lg͚ՙ Exa%CpRfp$d]z|BW-رc "o C5H L$/6p1xM4@v@/ AŊY<o|QcƌkܸCynӦ\hmųgϸIԩ~}۷a_8s-\ݻws:9ڪU+]h͛7~֗TI`'Jm6Rzuv]syie}V=O,$Ms!2vWV͛7/ؐNʗ/Ϧ]5` ^/TCNA)ȑ#ӧ+k nWgϞMLLx O>|3Ǔ'OGGG:99OzcYlYv׬YCHGF^*.$.vA-ŋirDQ F(-d6޾}Ӈ]Ƃ"՜[hx_|Ӯ<%iYn/U, zӧO/0sL͐0Rv: DZ| &G:)bRu֕re.OdUpum\mûxxx֖Zh\b܈AAAڵkfӠEJ2##,_xxxH߬Y3FobllW|||FmEG1<~Tۉ<7M2$Xc ˘^ȼIcllLrssŋkܹsy'x7@yd.>Wcm!qlcΜ9\uaLgISjUB!ǎcui\u/,848LƳu6մ|1 _SO5 9:WVŋ'Omx%?bhhȧJLSL2ŠSN x?;*>RS[RV-X[[E/$iQJ\`\-Zw56G9x"[Rș3goo޼ї\6c\yNd /^ IBV2ݻmPդA&]AǏ'|_',5 }!unq\)$g/\P\e`?K|a5Y;wd\ RZ<9sVKiiӦh2lذ1[l"Ӵc:tFFFZAج,dggsޫXbV۶m[Ν;}|"e/[n믿xWoӄ pY;vLޚ5k?>v٧}}Ja6Q `CժUQti.]...pvvFZZ^~-sݸqiiiS:@)7nFj܍7߈}BR WWWťkkkIIIם;wpq޵x 8Lơ`4;uꔯUss qF!ǜ+z0iҤꁁ[ IDATnWӦMϜ9Ay\j,IDGGJƍKω'gd^J*ٓy$H,dER=*4n:vP-syH c?IzKB !. FR!hb:Oр`w.PH6lHV\I e|12tPRLe`R.h'e@ƎKΞ=[(-OƍI˖-<:`1|A^,9Ŋˬq>Հ[n. _~[(wC111֭[ҵN::mNNl8Q%hԨQ%j>sNbnnſ<>h9y0|EUȷ ~^*!CyR!o+0 _lt`Q6;σ޺u̙3G"Q10իW,_$&&G73לѳgs%=/^#oŚ& QQ˭]_{Pqqq]S|`=G 7޽{sܜDy ȈY4!{%$g\!_zQu_wٴ9\!tڕw |NGQ=+Rrr2QEzUK:>jzYZZb{IҨQ#G\Ν;wT*#""|~zbggWz2xSJ|#˗OV4&Mtl~Zpڵk>}||{Ui„ x8q#TV+;edff*A?-ZRؽ{FBG X/B[nE qll,wϊ͛.z%(/ԩwIqy=w8Byd~gz쉭[J&r8_g%-iӦ(U20d!l#I2eWg~_>.\3gСCJT*g h׮&N€^ziӦhܸ1ܑ L5:<NܲeI;400@lll|Bۙ{`TRR;uꤱ;^^^la2jK.IDG1kߍ/_,Ѿ%dlsKYdڵEwvuuu-r7o9G,GTDŅ<%=)O?$cQoe8 *Т;ﰰ0}5p'/W\cbbBRRRTҀ:;;Ϗ\vK>j&dkܠA7 3o047 ۶hdw;OG<== ԟ>XXXp񱫞m8X.;tEJ淔O QFqŀPF+*!KvO?+tH,',%`/PHv D9u2HOO'=z+sHƶmշo_o۷-W9noI z|HMM+'z T`׮];H/^L6lHF*UXzo>vHpMnݺ%`BȪUxq%X^r={FLMM4(f<ƍ\Vtnɋeؼys 8~}Z*^`` ""d7׭[=z  K"H귽}gҤI04g1zҥd%;nnnZQy,]V7=]xɓ';v,e֎+;ٓK"Cd8XNOOԫWO"c̙ý{1@)oVѤI^… ?k,5k֠Aqq% DK0dUVX)իWJU@5ڏx}v hѢTKN|nk---G뾲 :VڶmG/=^Iy݄BlLVA͛7\N{$mٲ%']U 'NP~?Vk@I&\ .RG`\X+]ʕ+\nߣ(`юTrȲt9O=H>>3)"muO섗/_jux꟢aDDDYfF8ͤ 񟹑?Xު~~~o5 R[xeXl xEI baR ZaǏlj'"' m| Wr&]҈r":tAS*رcDŽI0(4F>S)ېUMŋuV4;;;L,k׮ F0fӧAc͞޽{FsCLfg_p6M`'`; #`,0ءAoW0|%===VX#,kGGGL6g'( Ձd6/#` 6LkÛk:8dQ 6,o%VǏȠۖZ>i$v5.\@Ν'Qktt_v'j$KA5 xݦLRdRyK.\z I!'''OĤIvZrp֭B) nYxiZũ6  6}_.5^{>Jn U8' ]teBΉ uz|1B*J-RZ5^3rssɤIP(QT)h-g3ugӧj֭[6lX#t.@6=K}I("'-Z$ ҆ B!d߾}\I-H~~>yW޳U쨆NjvZPPͧcǎ<+.HVVV̙39sֶK$###v8d5 }%_|)vggg@E:RPCj1y'!!!ŷŋߖ.]ֿUVMt˭`_U;=srr޽{ɟɹH-*N8ůsz2{۾d^Z@.zes ߿'Æ #qtt$mڴ!< 𻏉!W\.] .$^\ЖӧO';iӦ8/Of9sFnߪ\2;%gC@ S+WhB#G]j>lxx9!~rb3g6]o ,KA 0!vڶOEw^;WӦMP gQ+wD۶můz2ȒlԩS ^z,Rvmܹs$++KPd"cccrRN-]瓩SrTӇ RW.])//ߋ*A^_a!22Rk/_Mrrֶkĉ\m'Q||޽\aa0|p>%JT[cܹ;v44*##oפI4~r#144=M֡ng 7nԪ|fyhx2M]BEFFV{Iv*CCCҩS'RfMK(WWWرCsr /_KǏs۬<fRڠpᡵ#\fG`bdj4ՅCΏ*`譀quugݺuKk2~x w!cO+& p*ɓ:&Xz3mѣxuVφw^)LQ9SQ/ }v{J? >p׻JD:kNk\֭[km{~7>(7:'E5kޝ;w҆~1ytBEMA2޶w22K9G7rrx/=FNfV311}􁷷7fϞ- I4i焄III+dMcmިQ#4ɓ'P˛˗"?ktR[l(rY#;?'+oLZXXXٕ*U 'ODdd$= ___eWWW'OSL5Jay 2U~v={p \ZjZٖW^aر\xK`BKE| xoggg E P f!_i5isjd_9_2H.zU߯ő$;sӧ&CÔCD1:lc?3j(؅:|0o;EǺ4 r57ec^ :Ru %iiiZ?k,:ZJڑFjժggL3F&~~~j{&Mdhndd$]SCs}kXrzȗ;U2䪽'lF ])3/߹:L"~[O.9N:t@ʕ+GnZOII! s'u 1ޭ[g'NERRulh0KE#5jpoϏ1[$$$r5K~5jԐq3BRf͚cǎ 䞿A>}ȻwݻwCBB8<:tmVށ8 :թSG넌KʴcÆ Z'\qN\"7h9iε}`%0BZ-0n}w$J3'aG`K<@+E](Gv ?{[|sn۷.]Z$mjjJ6lxG͛69Gʖ-;mRm#ϟ(ze*PWOw?yzꑏ?=#{n2uTҥK2p@2m4yfٸ82p@?777" iܸ19r$Y~=>e˖J (~F\εZSs dZJ ۶m k=~ˣǷN_VX.FT 'x($1{d'@H<@.*4O޸3j&mHi3wDFFٳ5gϞNpZPT)ÈZ3qnݚwq塃C`ǓGzz:1cCxx7 x;::ZH$"s!!p G\ .w"@=899e>|X|'˗W JT9㠯N7[mn72# {r@$ _Qj6!Dn\Y'ұ7/[^1߾}KWa:881םig |޾}5ƴixѷo_ut^jĚKD"Jt#iii$99|~vv6Ylqrr7q#<^c-H͋%ĭ[TRIx>"d۷O; @=Z .\֭[jވw?H2e%Tmfw# IDATҹBfz~L3vێa!gX¼ >aCXHGt +++֭[hѢ^x!saaaWT~ɒ%ϔ.?_QtiWpp0t`7]oVZ۷x|_~EFF'#CCCXXXprr .`ʔ)xlm2A`;pCʼn'p%^LPzutpwwzbTT /^ľ}i&>|Jkcc###|}+QÚagϞEÆ {bgZZ;$%%!)) ߿GFF222)u>}$g^`kk ssskmm WWW+Vz ڵ˗*Cuq>M &d/{@ /|}}ѷo_`ƌ$990f[xO wFF1C`^,R?! \~,d;D H!rP6"ȑ#DZZ̽~uvsȅ촺u<^\^%ߞ?ѣGcх.@$32~fY:a~|NNNGjj*_wݻw3 777xzzYbdd:Cv؁;wx ^~ tExx8*V???,5#8ʾqecǎW^2OII;w /_IIIT{RRRx]+SSS)^^^ ܩSdޘ̧pĮhȐ!f̘Qڲ!CO>Ea̙p?8)t("Thp՟BY ]Ie\[ؒgp#lːLիWsF@655ի֎; ٳgA!\Cj"\\\8լdبnhg hͦ-y=P dR`bF@Vhx%aÆF)t $]t!ӦM# ,[L)z0keJʕ+y=߸qxx@Uhǭшf͚ JF… R;.Y䎶~Trݩȅ =]Sz➞ [ HsWzS_ ];wSN2f9!!!m;wanҤIǥjٳg Zųڵk2鎎>G #0['V 8d?J%qTZyyyb2"G@/I.0 pO/B>T -- ENNN\B!.ccc4066.6ȑ#%} Le hԨ97o~J BXXXRLHOO~Z?K+Vx{{qHHHkK1=[΃96*9~ rцF޽:uD"цL0npgӦMk]!cӧZ|Ͷ5E6X'9 F:ͅoFaW[ ۩\G!88XE5{yyɞ}w)fhhϟU[^qF{իW|]=Z.a@̚5KJ(ぬ,)cرc#O Nvԩ3gΨ,8~=£Gc$'')))HMMEjjw]X t8::*T@ P\9zȑ#g' -3vvvFrP\9x{{FFP"R~VVD>ϟ#11x-QD,\\1eL6&$B&d/8 0"aO $ώ3|%֭ټy35kгyϷo^b޼y 5j(m۶GÉ_jU{S:+Ȧݖ-[x;޹s]믤]vrL E7nLL/^L?U$~~`'2T!V0`7oٵk~E gy{.9pYl6l[.177/lJ#r|_YԩS8Xk 4΋ԠAoܸt)ͅ\8BΝ;'Cho߾#Fh&kn޳lC(@>!`y0c B+\_ @ + u8oiii ׯMQZY@SO*U>vԩH@VZlܸqCئQXt֎n@ -a8ҹsb-RJQ.^(<Q*C0^l|J3[P(˗q9={˔!??ϟ??7Y"((uEݺuQN8::"&&w($o - =Xtif͚ EHHuk ~~~2pm\x.]ŋq]yn?'rHx@up{mmTzeJn`5t*.XXXh.lllNܺu+#md̮Pv0y: `O5 #F(Iȿ0&9#7,>xU['[L)7N6>Mȶ...EmÇ탂8رCɬXw+""b +mׯwUQ^]{>[Lp@ ~~~֖~UiOHHH/Gʕ+_ ٓ 4 4hM6GEյw֭Vk2?ziޏ0) !r\BB|  V0.0Fi?xPTÆ CNNNoSSS{9sYe˖]v회J{СV4T*пRpΝ1bK̤2\ @ӧO=8::/ l]IKKׯ9(!㺵 U WR '9\߉ъܡzD'0/zA\umڴ1:tR[ZzNFdnn.#9::k׮iZ4ӭ~>΃l# vd;.8#FdwE_rɣȗdҡC)zL4Ieh6jԨ]hK:upp?j};rgHH]ݕ*U<ׯxnPn1#͛7'C !-"w&׮]#?ŋ䯿"g& 5"ުj62x`bTeԩSD#=;AV&;;[-H*U^s|B 80Kpvv&nҙsN2b+)0{:d2@f8er~dc G "A_Ç  ɽ{>gׯRZXXq1:uNK..B|}}S`hYK,)-sss ^||<Q_) \={hrETrq2{lҮ];)O‚R;r g=7je6dhhŋdbnnp}.~.\]]]v###2z/(7|$0d7DV $3CɌM?A2RRhN,X cO=h V^-_Ժ7iliiIN<3}ڵkg2@&&&Çy9~8&QQQm۶q$44///boo_OB!!nnnחT^4hЀjՊ̟ۗ?8p*;(XpkF{,*ڴi[`*X[[S???vxG])̟?}ƍscqP.yxS?It[Bّ*""(pEDED7!.\ ^Q勢hײSڲt߲i&mZd>s''sygΜygEdddxmCoB!wVmnKm#F%}#DZRhBX1|p1gq 7!Ο?_)RT뮻^#>۶mvLhժl;CG5m@@֭[D>}l7䠔?me?Qڶm5ԩS!X$6PqmhѢ)ߺu ;'.f\'|KYVVfoW_}O>xǎ okLش:[Yy7oVb ++)ױ~z{f+YpaдYYYzy]tM_Z&lذ^zL/5BJ2x-^j*9}4~icɗ{w^Glc8g펃rJ{U^^n֪;GJJG2 ՜F#TUСCL5f/.+W,T{x: ^bOx}qx#FO4b-[܊0zh=/\kO>T]o|l'&&qŽ[įhRf$n+ht 6а Q].d2qN8ӧ)**r9◭BQ}8ۗD֭iݺumjn+:Vѯ_CW_}u'.Ҙ_*(|Cx|y >oM舃"@R1c:֭[볳uM8˗aulܸv\] ꔩ<88"""Nʭb*[s8~D]N:UԩS{l FScFހ2..TZnMjj*Zr)Q 7mobp!/9‰'8y$'N 33ZDӡ).Zlnݚ6mЫW/.ʇS_Y1&c,[sJJel!i|w/m߾~isj5)))oߞgVvbܹ?^xuUR=z7|NNɓ'O~O>vخ];~'Zjud2 ۻ%]ի{W^ٓx"""s;X,˾}عsgvqg}RpyP9ۼB;Fzz:?_پ};w)))a߾}vW'RSSK+WDs˖-tҥu:u}СUv:>!{w:2]P/j?_~[233BB|:uU7|zeQܹ8s;|9sį:K]U300Pu]bڵ"33Q렠@/gu`Ʒ2֕wl~(~aqWy?$%%oQ<3>2aM\޲|x-ZtW?=vbT{>^y&MSo9s'T^W½_~ΤI^:wmժW^2a„u .|jpݻhsNz+W;v͠"!!п @ZZ!g֭Çjڡ/;~U5>=lہ*h4ekfK@@9ٜPeUFxS !((_eᯌ3fgFFƇ{M0% \rɖ&Lp瞻w54~GbbbPۺ999\+WV>{}nݚ8bcc#..h4ݲ 8|-33?WnhR11QTlْm/•AAAjÊ϶;wNMAN4 tرrԩ;v$99)ÇklG_/GB@^{Y!!!>gU gUQIC{|?)sIݻworvvvȑ#?s7xoֻ}eDFFJ[)))FC r~W~WDEEU*%%%? .؊: -3ʨȎ;ҡC,:Tm@y!N8a//&u߶m[ZmD4lĉ5Çt ڎcǍӧOO`T0$>+r8^bB8ۅ M;_~lذ0)*zmMBYŸRb!77^`C1[X.ȖX+E(aT*ݺu6#]UͧXYiٲ%\sMF#ǎT8*{GC펙3g{uhh׮ڵcĈվ+++fΜ95Whlw 4( gȐ!]Pr_IC"']vz߾}0|R7U(j\ ܈xИGEL[R" f;{WuVq:uDN9rdիWsM5rv0vǭ}|pp0z=c(ԗ6mDz<^PP2& u6q޽5^</&55U Ⱦ pF U@;^AAA !tj9qqqjjCǣEEEZŢQ&vX(FTLP.R`DDDpWCҦMRSS9qDC}7d\a3ȣJ_W^g7mTUHCtkwZVvĉt}1Ć@{ x|N+z1c8w999tܹFG%??7Wm`pR?ClwN>}lw_hǐ!1&v@ [yyAdK8 j4\4k~E .6ݦMy) F+%Fe裏* ɓtҥ×_~aĈk[0 FDD}mFt:F`ogF?Zo :l0mVuW0m*u]W!(,,… v\ֿ>!Dm&&&bcc+?Wlu =d.]jOf=,k.^v ;w'( G*I/M޽VݧhXlR@N0 < l#X_TFϷ ت`\V IDATRXlwޜ:u /$mQXѣG9w\ߒ߀VDKjj*۷6ʼy &}Jm5#GAFFFcǎqywt5mۖ:СCڷo_Ym*x\ #**'Brrr+;<`y睋6n8VZU4멧_`FדYň#.[d._~z'wY,`̙O.+k#膲t:E(QbQ!u;d; Jj&bj5{/ꪫjT('z\kuݩG͈-8n=5(>9|0/sFVVYYWEXXX`oǎݻwIW\qJP)/Vcǎ|زe 7oСC={daa!;v`ǎ5 cǎۗ2`RRR%%\t`9::BllIan ^nU{キ?@}PU&*J=zTH믿[ouC#VU;`UYoۯȪ0`88pYԐ߼yoqoZs.K F1 Fp/JH*x%zHs=;vLf.x 1fѢE _.~aW_l!7xg[Ctvرc'|"N*t"T*ORRRĄ o-FaMb{|[͵&ICnRkL*{+[nu~FkWp 3JҺ_-(QkVų>+fs5t:o*J:tWZ%][uOߏ֕ƒqMsJBu=hZq׋p۵k':t`1^?ԔP#DJJ"00);/xib{oh4k 4fI I:u!#ȍ^v`TT)))NCӡ9~8gΜqjusJ\\˖-cذf|gM+,ZFѣG?j}g###K "00dffٳgeikKVūHm֭bbbHJJ"""@6VYӑ˙3g<ѣF#'j$<:,$$[˖-IJJ"**Z]{i0춋bή4nn. >F{~sJQQK2k رc ]?ί*ae}Y'ѣpuC@Rѯ_?Əϰahժ!!Σ 0]RhΜ9ömXbׯQV2M D!t֭rXuKLL$11F{&mۉ'صkA; LKP'bccIKK#--K/]ҲeRY$l8@zzzv^ʥ(o^.jDCq FuJjpc2Y=+*DEE=kchZ)*/L{_[+]uִnݺ2 v޽{9|pVVVp~%0e&OLDrAAAeHOOgU#9Cc}νme(Şǥ1\=ϥFnӶeCʕ+5jsTM"PT{e@wM4k?XdX`Xz8p0 "_|^;>*ؖ'''~X… ^,geeoFL4IDFFbsuoDD4iXv>';wM,¡@}.^, k׮i-! Qlbb LPji3`TbT;˛V^-?Þ&oN!!!M&%%zHl޼YX,{ Ŕ)SDtt=nǰ01qDzjd/ؿxDZZ6qK&fϞ'[‚ l'iL(~q]w]]ݪT* |d"6P-?#33 z=rSToߞΝ; ,\˗cwF {c%l5ХKw^qn&2M^'##C*H+d:u5kְj*ۢ^ih8qcǎeРA5QF5;zOPXXϪUXn(wx-DuXn3j(FM|=ڵUVj*vYCLgwX,.EvolGVT0$ T#iBB ۬/J[ɓ'kڵk9}tlٲ2qvh߾}(5kְpBg ]QUV?[h۶-3gdʔ)ug49~8G222ĉ0tPf͚Eݙ1c!GQB6eR4 lذ 60c zɨQ8p =z~ԩS޽ݻwi&6mT5k3{q:0jiA5xС]v=z{M^ٵkW{nw& yDD:Nw^K=|Za:W^qER;BRTT+&`kb7ȑ#63Μ9Ù3gشiSHIIe˖lْaaadggW>333gpǖ|X+Pcǎ1sLyV^[[__Lff!Q7eKP2:bUAlll堲o׮] nkaa!T&v͞={bZhFpte=PL/SYw2W&ZjE||<5o!={rrrdϞ=ڵoڙTj{x~w.ޗƾivmY|$$ ν{|{ܸqVXqE}IIIG6*:t:~ԨQ[֬Y3/nf$#(!\ ] :Hk.\>-Z8ۢE @y)h… 䐝]9xQc7(Eq~Z)Gf-U*QQQ G6\i~X.l?WR%ӫ/))H={sι2rSD .TcL 3ʀhFCHI5^,YYY^Z Ԫd _4-hӿ1$z]P܊-kXֿ%!@ ^"`V3k?ZV*1`X*ٹ;PVXfFpsk{3ǁG'QVY?iJA^^yyy`)pX>( qO\HCz! R ͪ%ٓɪt|bjJbU6*U>Pe (h:}{&p/m}8oUn +3J 3BX[R3JC}2{Y:Xe&|ɺYPL½\F-UmkQ+.I=`dȸܔb6 &鼬f.V(3})ɇ=-DUo{[NYuP,rzo u((@eVy\Yh3%[@_/RZY 'vցʺ5{,SvꢂQKl^*ٽ[+-lFm,pJ{8eU,ejOǬ'UIKiii'%Q?j?#5@ Huy eE hD-C1sjl'!@J؋pMfI)k4ܳgtTn+n[rbJDL@ػ-ynQ!FrrrG}kXhf-:N[JKK-z^t:!WtIIH| JW6KAbU[\}Bc@'AmkY$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$Y"Hu,@Ԅ/4&LD K`,~dxBGL B5;Ɵs X3Q^R'kIaK$DIH$OLpwZ2Y4f&J &,Cb1(,.d4ހK GX#Zj0Y04j)hD"H$RH|0ڄ,* ?hUi4C^Eg$ߌFo&HGNMpi!A ()AEc1`¬QaJC"H$T0$PT,PBC"L@?aZƒ1M F Ȣh!h& zB5h  Y#-H$D*/rQQ6 F2tj´$FEY,D7A2LThKKʻ@t&ekThdw"H$D*o(~jGRa4(-ӡ3Q Kї̌Yg`!_UQ-8Y\L΄':923 j3B"H$T0$h LyEb(,G]lFA(Zbĵ۹c !4tA@&RD"H!!h5u 0)/)H?eyZhJiȘa޻dEI1 $T%HI6@/vER4D" OhRTo$/uXB(P@'8v p! %y.LT0$^mBp/)Esh+0G@/E"HC҄xx饗Iixsp0QD/LCSD~mE?=Z@0!(#D0-EVv'"x0<˷9hX$`Hn~viӦIx<1h;5z,0B(@3/.e'z"P̥­e:N+)@uxRQLbND#0ξR,I#+&M<;;O}رGKޱc=F1_Ǐ7nc~~~s[ }! sϜ9Ylِ}r˯\r;eʔ{5x^}|oy]92#ΓWR4(Pcv[ɀQnnUr/wcnÆ {΀ff8p={B{ޤ>+V0l)//端*111~>z:έ}ҥ=fsu뮻7{|u)9GuHF%rD/AJl#sӶ};1ͺMTX'߭(GDx|yJWUnFc=FWF-C6 䢽7&#}O[s/ G}4 L&SlG}4Gf͚Ts=쳁}٩իWؗ#gF@IGQ ZxnE,hi?D'UBQz j!M$% %;b!( n2sCU9H$GrPNݘ F_u<VD"4]PVG]E Y[`H$App`lذov桇֝?~:>33S믯={WE'4h4i0!(EL *(B!:Q 4h)ΣOZDt8'$rb"llCϪoG4 3/2 ދm85ߍʂÀgJ`ֵk'qm 'i\ ls%؄KDr q7G 裏O:%K:H:u~ڎSm޼y75*i $<$u|J).PN4ƀ# Ah(D0¢F#b[RFL^OPdl>z^+٧2uḣ(u5;:܈Eq~@?(ko>{onȴ*)fI Z8"eU6/k,W0$ME8Sߕ,Y2sԨQ{>0G=쳁?ŵ?2eʧ"߂R ADEHx~AɤRH űPujIXDB@6rsBOHY*QLp<`HQ@u%t=oܘ>:[Zw_'OQL6(!d|O^2pk$X!?KG Is>_fMSNe=쳽͛w'N|~_~yni-7  !40hLQqlGO G(ƂP"@ BDےxQ՜/%PNJ湂CtO1}Q;쏵~sݸhrUkG\3\? M 0%ЂT0$O= }3gNl.++cǎQ(G$&&wNsSϿ%mRi׺5 1-HI|l<1))LfJ:\8 U))Ba1E%F :^`l4\T[[wѣ*jt(єN:`0ϯXkZrqJVu=(zMR K% o/[tYYYs6Л=޺ukfŕW^Ȕ)S .l8' sT :uhG䶨5(5̠C59ù2%++$(71 fɄlbYf%τnD\(mH(|=q#POPa$x鹼\NFߓ2TT+kȐ!b&$$Ǎf„ -dod錒Օ:=2L 62qז? u=TGrThW1| Mx2LIѮ][FTTSL~`Μ9#FyfrssYz5<;vt999+V\vmwܱひOW0kK\OWuQ|({^9`QVG6r\@I#_G`x^zFAHIž+..v;l\\ .dܸq+7nuYY5Q'OdÆ ㏬_be>[>.]\N9(jB렿u`ç+JG}8 J^?G(A(3Z*^9BsyDJH̙3SLjܸq–Yfy>x Qyyybܹ"22ŬY?~\4 f&|\fA(}z.G Z<|\cS#kD@ cH@u1|IqKC* ?ܢ[nE(<<\|WcU ?/bbbj-W^w}!K4+b[C٨lSC씩b|lV.\-[|{K߻wo e1cNY<̚5wy_=vΝ~=Т)SL0aaÆ'ѕ:؍@ ja-Ns jQW{td ~ΡFɈveidvjPfqpdv!)fr`Ps)z`/$ !o>߯_?EDDfF! T_ Nѱcjc4c͙(z5rQ-a%#%;: otrO9a:9R3{s(5}UjxFYo 7#P=`DGG N'5 +k֬Iccp_޽[/oT]7xC]ߋ/;**2el|7'Jd-g22 yG;9"Rxb$e^ _ Xk6Ce7l{;w#G<={kDTT3ʈ͛ ?nZ*q`"--M9r畋oFq 7iӦf(|Aq}ǎCˍo 8O6pg+;LYeR~փ'.Σc4쥞;߃󤎞%dV/vyNDCzooV$%%9RI6[T*2'6A(@ތd?F9rF(W``9sӗ-EEEb„  /s(ٍ|K :KR2SukInU6;{__pAObݺuɓvy'mD[iݘ=Vf Zv?.sac'(& ĉIºXf̘/u]7 7}f̘!N>]tK.i%-[撒0GRRqΜ9meR+AMx<@6ף.~_bP7a.]h MCp;I>9e9Xg[ΫZ/Ehhh1*J<5[j⵴Gɣe•bUJƷs8# e5b+duԃYf͈7rѣG⧟~ѣ*nݺC9xͪo6a4kU2n*qWf))(YtbCI Lp BSpetn>YtP&>+xqGoj爌{uU;ĉ( هB!R+sǚػ_s<oܹsYvwo>yyQF8p`Wbјq~;>-K9rH˕`~)jcK~o2uo 'O?ĖKPb'5B z7ͭȾ8xejRzJd w8>tSgKpHX i"zQ̌>D UoWÇSPP`۶mc'&&R)hmW܂r8QLCI~@3 d}I¢EƌJi4/7(QEEEb̘1NPO6m_﫮*6s*-[Ν;7UiӦԎnvO>${T7vshbz+1Ȥ.3v.\B НU*N7y7{eׅjBmoST*ѢE ѣGqu׉;S̙3G̘1C3FW$'':^E1ݫ\#q%Kj0;*g??s%sPڻݏDGGݻÇ &CnݺhJxxåћoY6yN۷?|{ow*ߟ+LZRIIC?6m/^,s-(Gx=uYhچjZE8u~ yOp\J2ZJZuouݵ3M9\UTb…5|a6EVVoŽ+\;O^B-~v̙3篸e(o-ѷo_1|/#Grr0 bbܹK.j*AS/A ?<̰Ν;;tǎ޽{rrJ氡 2}SSS[ki2yi4trcǎ'{ ehSddd!(((<@C|",!7d;s!ԣ;ap;F܉B1yqVޝM)R<.+ΰX,?O=޽+qM]vQk6!!ALjyvڮ# @\YYYþ}c=&= yWxWc~đǏdxG/1yo|nwy900P:u%9y'.\P:'^z%_6f1l ,pYSp_0F\ r6zuX˞f~En;Zaݻعsg322Ĵiӄ^j|5={vcJKKEre޽ODqqq]ĥ^HWg5f:K C{⦅67#))cM5 GЬY\jѢD;j粲2Ѯ];G>%B?mRK^nZRRRwBGԜ8w7۶m+QO(5F (JOUoN"fˁ.3r"gҩe%,22LAAAEQgUޫft6n!''gϢhHIIUVЦMFI׮]]۷3~x?+Vp뭷V_PP@JJ %%%޽=##N:نϏ裏R>۹s'}'OdffriF# $$$H߾}:t(zrܗ_~'{/탆8w7G 6fj2p@/^aէOѳgOk?P̟?_iӦp͚5ծM׋DǕld&LC閆!|Z!WRfԟm ~J0RVllTiYqj8F t1~xmz̬w^~Ĉ5~3qDѥKy$''-[z='O/ڵ+&O,}x<111֗Vv>ҜRԝZV3% 3+gZ] 8)ԟJ2!:jYaaa+:ƞ;wa_c1zh<[jZ~ٳ<Ü\ǏvիœO>Ym_aaCeo߾Ǐw'Mш'C9 ~:ޙ;+H!_VKx<1fw߉O?T84u1oFẾJ=Ξ=+~РAO#DH z{rCRܼ:Y8uR:,3}(pƍf^*޵o`Lzqr\>E=o۶ͦYj'P 5NXx-g=P@pgnV<3iQþWȼD6 /`vAscT4D"|r$,,UV1ܸqśo&5HFnn.k^}=~N.! %`tS9wV jGeEL0!VuܳgOsNO***HUU!ƬDYY)))1I7n -e`,C [[Yc= _=#{[Fsxyyu=}Xܴ% XUQQA5Yݞ4iׯ>̙3fŖ.^Țٳg%Pc~~~~IxxIn;w${1{ >hEWw)`.U+Ztg]M͸ 5 M˕0[^^-^hy;+\]]{!D fŢ!h¾o!]MlXo!u4Bh(zv|\~~>N Fcrnܹpqq1:v?Q;<=JKK;>d=nmsH9pޓ%`PsYz^\駟6TضbTڵ 555H$xgXeddx/g 2T Œ:d[ ^/0Ӆڲx9TW2~ T tD Gk;w>39ٳg;x z=`Ϟ=FfΜ=Mv_)))^ .^y?O SbѢEϞ=# 7Yغu+o$]Rb4Cfs皷~y\/`MMMgy<'Ķ `ڋ U(X\1xNGV.dG~~ ǥK+WK/_,_.h !V G J`%NsyyyG.͛ѭ[uݻW^f=w5+cu㩧!۞vPXAI[;%Lb"ű건4P(ގ?n7~ΝvS777:a5$pݎ<: VF.Uմ2vZיۇ8T%Ўޤ:@:x7}PZZgu-֋CBBXv~w<Ð!CL]`?}tzĉ(//o|}P1;-c!oUT bժUyZlY+UUUŅ}qLs;zOvK;lWWWkV͘1.m&y+**2\fe8q>dРAlp]S#J0(0j':#G+W[zE>z+ٸq+@):z_G햢:Ɩŋed^orhZLJu999vdORSN1'GA{})pZ1~ t/H%z駷c$ׯ7{o,Dp%`.fe0{!:&...$''Ǭ>+-- KIII&y6n&=z?tPRVVfxGMsҏm`1{'N>^zuXssM 6z+**|O8ǏLf Q\\f͚vO_8 s0W] u.T^ kqwTLeYٳ5iJUgqU PFZ0ށȬRuP.`֬Y2dvލcǎuX#Fеk6lH5-@Aii)MRQQGav#mNZ4T˶***IVdm,!xg,ٳg# ## DbE$2d~ڵk:u* X=~&LE>U`<j6ݱ8=$XN&B@"@~uQB%Kb%ٯ |o&|rտR}7WB߿h{%@@}?䰪 ঵o[֭[itP{q{ҵkWNBBBH@@"R{)&,k^WXAz,55I=|F:wLzIL&L@>s|lٲ+W\qF2~x2h ңGD E68h[!|D"{I'|ܔ &C`PXı`iijGj0:AT"`,DynD-(:M~m[*G}xݟZzuo֭ۛ7o޴˶tCll,HOOaq `B^slk i e%Th}GNopqqOfܽ{vB0944gΜÛ@憈DDD@TnnnpwwQrww\.V+| %K`ɒ%ף(//GYY" 99CuuuSNq/6S"##7ws!Dد_on`X$ߍ"} :͙bݺuÈ#,E0YpD CTTQ 7杩P\\{ܻwHHH@||<TZAjt:] WbO?a8rJݻwǩS0j(O5 Æ CTT"##ߦm 0>www[?!''HHHKpy1!|}}q)3g_5Y`VUngyFƥ-EkAM:Bmn}#r r $>!;\\U\m 1Cȫ#'i]{yyiNRK˺f͚w]͛gNnX +u"!iD[i۷\M9X-w@&I&u֑ÇDhIZZ9~8ٰaygI׮]3bJ;n{-trisUemg^O6oL&))[о: Ƕ#JԩSe[>}mrHHenzk:,cA%UZz:ސa dOJ6TƵY>CBBT۷>_~yV]ץKdff/,,9U8ċ/&SӧOwx1s3øq0~x 2U.!$$!!!<[vp):u ϟGee%E" j'1qDlܸ/69666<`|{޽Ν̙3QRb"infn??mfdN:e~/fgg{/]4|Æ rƃ A*' L|0u!42BFz_УGūEVzvV]TʭƉM4IrTWW I,C&A*B*@HH/ݺu rupƀUV??[Y¶m۰`hfT[Wf"40 H Fs`^Gff觟~thG$ŕ*![>Ѓ+G {X@r ЗPkL矷%&N!ڣt TVV ݡ]\Lw0PA^^޳ ^Տ/1b 3DHNN6!AAAq999zl;v 11lcvv6233o6 ya >< ~wK|||ZRtRld[2CWe ̅eU 5xW_T(&{/$ 9~̮\f.""zҥ,DYdGIHa| ;@v{i؋;@| 9y½ kĐ ./Zmw[q' V%K>cҤI8*yN(Mu7`nKǧKk=*<0.7nXr)i&2w\2x`PvBDFFӧwyݻőZe///'>gxITJ%YP*F cǎFQ8|0Əo x'''=zV2baPA# rh7Ph@Oo>P * dИx~+_{i2_#G̛9s#oU6n;3QÂ,`BGx$tMiy)JgWWWכ2ܸq=f͚疕՛Tφ߭TTpuuT*et5nnnpuumqk ޟb+?߁1m1BNN  cƌ_eJK;VERRpJ={DϞ=ѣGŔ)SpY< f0 c_Obў -ZO\nr!ɯ0Jk׮ee+VpB,ss?\ȇ퐒p#ABA.@A.CACJ/$.@\?9(w &6Cٳd~i֖/V*G(++kR6oli〓~vvoRubq6;;\tڵY̛7L8tޝd2X0`9s&Yt)ѣGݻwIeeŠsbY 0ptD0vhxHRs|9*r3pWd2 pss#W\q 6 ATTÐ!^[ I*9/rn DD$9.d{4yܿ;\a„ FU]]Mr]Lim$D[.1⺓vv9 q}GzҥK?$ӦM#~~~4CϟOvM2223f/9&<%-K</vh>Xm/{!۷o)vTTjƌk֬{sK.Bsp.Ch DA @ -jP *i '((7o4ڬw7{xM$uDFF +bIٷnj2cY &؂ rc)Tn޼i(g#Ç'/2ٸq#9~8IMM%:]c+W۷z<$22 aРA3Jsyz-JLumakH.իW; .\߃ɗ<r?NADNH^4-ْLݻw 3[ORTtҘV#9Mxoݺe0gqaG!;ָBo#FloH$"ˋH$'`6rvBA|||,ȤDJ.Ӭn~ضmۆ*D\wgѫVksynPi^^AfFe@'^zO P+ 璒WnЀS̙3FNN̙B̻0a 6nEyÇvގ.3j_XFdt…&M:</?Oa.\8[<\@IDAT.72cK5jMRUUU*++QZZTۢ%%%*]x BBB׬o|\*5m9;^^^Ldgg*NO&ظ ϨF0*`,Y-[6`FnqN8at,>>aHS7f9J༛Z۫5snyRt+/GD۷h!''~~~:X{їϝ;ן 2ZQSS'y<W;#״)S;"#|>-,[f' so$hq͹X.{ Cxx8ꓯotB!<<<:MHMMEJJJgJJ C`D={",, J>!((<MwBBI dddCBBӛ?H_,Ff=NU~{ rP($vtP$NG^~e%hp8qUKfN-M3fhլɓ/CKǎk\.'U C|"h...0oGyyfr-j9_zO+ /(Kq\ȴiȿorRSS1ÇɡC[oE TpDUP(Tfey`+Ņ9ri09ѭ[75lG̠+W,>g~-Ë/q~[K0 33  /tt^3UXZ#??IIIFnnnӧJeBaVe83}N_)FFӥpZ0h6N "@ ~~9sJIIa=zϟ?۷7|6l±(((p"m|Ο?!)//˗qeoY.yZ&`j#@ lޥ 1<<|g\\RP($U/^7m5/ܴi [ ¹L0˹H0jmЂ jc'>( !>RSSiݜƿ2 f] :'777t!!!ܹ3Uyˍ%9lPʾ} >D]$ Q &PT`Q`l%(l[]1r#/̺bg\rSL`ǎx'FV u Uf1ѧoT`#~ǃX#iEeH$Rd%>1RO>&߿_O8~fgg}y<8B;V}㛪Ӑ#QG*`<RJJ'{`%kSո\5NI0>c]j6 Lr0+Zx֐rCuM?ѵkW{R}Ō3L!`Tr `\`̙޽SC׮]ϛ#yŧQv^g6%j/--ML۰e!.\W֭{֭[Nig,Zn|[s@7RA${w֬Yb0TTTO0L McVexэW"##\4DC8J0FLq9<#88d &#GPuWa/~WxO"8 BAA.^k׮ SSS;`7 ^_?MHH`  0###1`ݻ{> . V!L* W^ŕ+WP/v[jddd?Ν;CDD@* ޽{H'CP5)|r,_6?EqF3ߎW0&Ɓ3b{r4Ԁqkbܸqx.^ .ŋh5B@ll, !C`РA֭233t:;Jc8ydLܸqneKQ6;;gϞM(DLLL< 2G6G0y](Oʞ}=FSe˖qƷcѢEcISo,>܆47*W/CZi|{zzR |"͝qD`RFBAB!y.xH5ORP8 <==G8{xM;fp6GD '.[vG %%%T6^4[?#աGEEE~ 555N`(@;[¡RBh-i,UW`!Q(z{{[twL:9XlڬV=QAP(--`Vmt2tcmz(%F`z}5_>2 WlC'{F1l"03_{EVX&VD01yHf aEa05肴bŊ4o>[n=hJJJ?ӣSMB LD~j׳jXՙyY!&\ mi>+  :әp"ZCC 95Px f_*7 W02~C U jC`"sf+ۻӀI$hFRKKK vyxx|||*=== EkP(L}TTT%%%MQ !@GՐ\@&p@(R8%MSJ0( EEEG dרSnҵD >?+} ‡o>1+**_p7_W$ 9!Dez^\u:DJ4Dш4VX[[˯჉9H$zXH$:HH$ZXDX jXx</YXXǥK*--.---g;TRKۧ;@ f۬nrhU/v™!cnŐ\|ow*3UeBZt -dXLIENDB`chessx-1.0.0/data/themes/shadow/000755 001750 001750 00000000000 12234477214 017302 5ustar00niklasniklas000000 000000 chessx-1.0.0/src/quazip/ioapi.h000644 001750 001750 00000005013 12223260306 017156 0ustar00niklasniklas000000 000000 /* ioapi.h -- IO base function header for compress/uncompress .zip files using zlib + zip or unzip API Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant Modified by Sergey A. Tachenov to integrate with Qt. */ #ifndef _ZLIBIOAPI_H #define _ZLIBIOAPI_H #define ZLIB_FILEFUNC_SEEK_CUR (1) #define ZLIB_FILEFUNC_SEEK_END (2) #define ZLIB_FILEFUNC_SEEK_SET (0) #define ZLIB_FILEFUNC_MODE_READ (1) #define ZLIB_FILEFUNC_MODE_WRITE (2) #define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) #define ZLIB_FILEFUNC_MODE_EXISTING (4) #define ZLIB_FILEFUNC_MODE_CREATE (8) #ifndef ZCALLBACK #if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) #define ZCALLBACK CALLBACK #else #define ZCALLBACK #endif #endif #ifdef __cplusplus extern "C" { #endif typedef voidpf(ZCALLBACK *open_file_func) OF((voidpf opaque, voidpf file, int mode)); typedef uLong(ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); typedef uLong(ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); typedef uLong(ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); typedef int (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); typedef struct zlib_filefunc_def_s { open_file_func zopen_file; read_file_func zread_file; write_file_func zwrite_file; tell_file_func ztell_file; seek_file_func zseek_file; close_file_func zclose_file; testerror_file_func zerror_file; voidpf opaque; } zlib_filefunc_def; void fill_qiodevice_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); #define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) #define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) #define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) #define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) #define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) #define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) #ifdef __cplusplus } #endif #endif chessx-1.0.0/src/database/downloadmanager.cpp000644 001750 001750 00000011522 12223260306 022007 0ustar00niklasniklas000000 000000 /**************************************************************************** ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "downloadmanager.h" #include "settings.h" #include #include #include #include #include #include #include #include #include DownloadManager::DownloadManager(QObject *parent) : QObject(parent) { } void DownloadManager::doDownload(const QUrl &url) { QString filename = saveFileName(url); if(QFile::exists(filename)) { emit onDownloadFinished(url, filename); return; } doDownloadToPath(url, filename); } void DownloadManager::doDownloadToPath(const QUrl &url, const QString& filename) { if(url.isEmpty() || !url.isValid()) { qDebug() << "Error: Invalid/Empty Url"; emit downloadError(url); return; } QNetworkRequest request(url); QNetworkReply *reply = manager.get(request); connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); destinationPaths.insert(url, filename); currentDownloads.append(reply); } QString DownloadManager::saveFileName(const QUrl &url) { QString dir = AppSettings->commonDataPath(); QDir().mkpath(dir); QString path = url.path(); QString basename = QFileInfo(path).fileName(); if(basename.isEmpty()) { basename = "download.pgn"; } return dir + "/" + basename; } bool DownloadManager::saveToDisk(const QString &filename, QIODevice *data) { QFile file(filename); if(!file.open(QIODevice::WriteOnly)) { return false; } file.write(data->readAll()); file.close(); return true; } void DownloadManager::execute(QStringList args) { if(args.isEmpty()) { return; } foreach(QString arg, args) { QUrl url = QUrl::fromEncoded(arg.toLocal8Bit()); doDownload(url); } } void DownloadManager::downloadFinished() { QNetworkReply* reply = (QNetworkReply*) sender(); if(reply) { QUrl url = reply->url(); if(reply->error()) { qDebug() << "Network Error " << reply->errorString(); emit downloadError(url); } else { QString filename = destinationPaths.value(url); if(saveToDisk(filename, reply)) { emit onDownloadFinished(url, filename); } else { qDebug() << "Could not save file " << url.toString() << " to " << filename; emit downloadError(url); } } currentDownloads.removeAll(reply); destinationPaths.remove(url); reply->deleteLater(); } else { qDebug() << "Sender is not a QNetworkReply derived implementation"; } if(currentDownloads.isEmpty()) { emit downloadManagerIdle(); } } chessx-1.0.0/src/gui/databaselist.cpp000644 001750 001750 00000025033 12223260306 020327 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "databaselist.h" #include "databaselistmodel.h" #include "GameMimeData.h" #include "settings.h" #include #include #include #include DatabaseList::DatabaseList(QWidget *parent) : TableView(parent) { setObjectName("DatabaseList"); setWindowTitle(tr("Databases")); m_model = new DatabaseListModel(this); m_filterModel = new QSortFilterProxyModel(this); m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive); m_filterModel->setSourceModel(m_model); m_filterModel->setDynamicSortFilter(true); m_filterModel->sort(1); m_filterModel->setSortRole(Qt::UserRole); setModel(m_filterModel); connect(this, SIGNAL(clicked(const QModelIndex&)), SLOT(itemSelected(const QModelIndex&))); connect(this, SIGNAL(doubleClicked(const QModelIndex&)), SLOT(slotDoubleClicked(const QModelIndex&))); connect(this, SIGNAL(activated(const QModelIndex&)), SLOT(itemSelected(const QModelIndex&))); connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(slotContextMenu(const QPoint&))); connect(m_filterModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), SLOT(rowsChanged(const QModelIndex &, int, int))); connect(m_model, SIGNAL(OnSelectIndex(const QModelIndex &)), SLOT(slotCurrentIndexChanged(const QModelIndex &))); setAlternatingRowColors(true); setDragEnabled(true); setAcceptDrops(true); setColumnWidth(DBLV_FAVORITE, 50); setColumnWidth(DBLV_NAME, 200); setColumnWidth(DBLV_SIZE, 75); setColumnWidth(DBLV_OPEN, 50); setColumnWidth(DBLV_PATH, 200); setColumnWidth(DBLV_OPEN, 50); setColumnWidth(DBLV_DATE, 75); setSortingEnabled(true); Q_ASSERT(horizontalHeader()->isSortIndicatorShown()); } DatabaseList::~DatabaseList() { } void DatabaseList::slotCurrentIndexChanged(const QModelIndex& source) { QModelIndex i = m_filterModel->mapFromSource(source); selectRow(i.row()); } void DatabaseList::slotContextMenu(const QPoint& pos) { m_cell = indexAt(pos); // Make sure the right click occured on a cell! if(m_cell.isValid()) { QMenu menu(this); bool bIsFavorite = m_filterModel->data(m_filterModel->index(m_cell.row(), DBLV_FAVORITE), Qt::UserRole).toString() == "Favorite"; bool bIsNotFavorite = m_filterModel->data(m_filterModel->index(m_cell.row(), DBLV_FAVORITE), Qt::UserRole).toString().isEmpty(); bool bHasPath = !m_filterModel->data(m_filterModel->index(m_cell.row(), DBLV_PATH), Qt::UserRole).toString().isEmpty(); bool bIsOpen = m_filterModel->data(m_filterModel->index(m_cell.row(), DBLV_OPEN), Qt::UserRole).toString() == "Open"; menu.addAction(bIsOpen ? tr("Activate") : tr("Open"), this, SLOT(dbOpen())); menu.addAction(tr("Close"), this, SLOT(dbClose()))->setEnabled(bIsOpen && bHasPath); menu.addSeparator(); menu.addAction(tr("Add to favorites"), this, SLOT(dbAddToFavorites()))->setEnabled(bIsNotFavorite); menu.addAction(tr("Remove from Favorites"), this, SLOT(dbRemoveFromFavorites()))->setEnabled(bIsFavorite); #if defined(Q_OS_WIN) || defined(Q_OS_MAC) menu.addSeparator(); menu.addAction(tr("Show in Finder"), this, SLOT(slotShowInFinder()))->setEnabled(bHasPath); #endif menu.addSeparator(); QAction* action = menu.addAction("UTF8", this, SLOT(dbToggleUTF8())); action->setCheckable(true); QString utf8 = m_filterModel->data(m_filterModel->index(m_cell.row(), DBLV_UTF8)).toString(); bool bUtf8 = (utf8.compare("UTF8") == 0); action->setChecked(bUtf8); menu.exec(mapToGlobal(pos)); } } void DatabaseList::save() const { AppSettings->beginGroup("Favorites"); QStringList list; m_model->toStringList(list); AppSettings->setValue("Files", list); QStringList attrList; m_model->toAttrStringList(attrList); AppSettings->setValue("Attributes", attrList); AppSettings->endGroup(); QList indexList; m_model->toIndexList(indexList); AppSettings->setValue("Favorites/LastGameIndex", indexList); } void DatabaseList::slotDoubleClicked(const QModelIndex& index) { QString ts = m_filterModel->data(m_filterModel->index(index.row(), DBLV_PATH)).toString(); QString utf8 = m_filterModel->data(m_filterModel->index(index.row(), DBLV_UTF8)).toString(); bool bUtf8 = (utf8.compare("UTF8") == 0); emit requestOpenDatabase(ts, bUtf8); } void DatabaseList::itemSelected(const QModelIndex& index) { if(index.column() == 0) { slotDoubleClicked(index); } } void DatabaseList::dbOpen() { Q_ASSERT(m_cell.isValid()); QString ts = m_filterModel->data(m_filterModel->index(m_cell.row(), DBLV_PATH)).toString(); QString utf8 = m_filterModel->data(m_filterModel->index(m_cell.row(), DBLV_UTF8)).toString(); bool bUtf8 = (utf8.compare("UTF8") == 0); emit requestOpenDatabase(ts, bUtf8); } void DatabaseList::dbToggleUTF8() { QString ts = m_filterModel->data(m_filterModel->index(m_cell.row(), DBLV_PATH)).toString(); QString utf8 = m_filterModel->data(m_filterModel->index(m_cell.row(), DBLV_UTF8)).toString(); bool bUtf8 = (utf8.compare("UTF8") == 0); setFileUtf8(ts, !bUtf8); } void DatabaseList::dbClose() { Q_ASSERT(m_cell.isValid()); QString ts = m_filterModel->data(m_filterModel->index(m_cell.row(), DBLV_PATH)).toString(); emit requestCloseDatabase(ts); } void DatabaseList::dbAddToFavorites() { Q_ASSERT(m_cell.isValid()); QString ts = m_filterModel->data(m_filterModel->index(m_cell.row(), DBLV_PATH)).toString(); setFileFavorite(ts, true, 0); } void DatabaseList::dbRemoveFromFavorites() { Q_ASSERT(m_cell.isValid()); QString ts = m_filterModel->data(m_filterModel->index(m_cell.row(), DBLV_PATH)).toString(); setFileFavorite(ts, false, 0); } void DatabaseList::rowsChanged(const QModelIndex &, int start, int end) { for(int i = start; i <= end; ++i) { setRowHeight(i, 24); } } void DatabaseList::slotShowInFinder() { Q_ASSERT(m_cell.isValid()); QString pathIn = m_filterModel->data(m_filterModel->index(m_cell.row(), DBLV_PATH)).toString(); // Mac, Windows support folder or file. #if defined(Q_OS_WIN) QString param; if(!QFileInfo(pathIn).isDir()) { param = QLatin1String("/select,"); } param += QDir::toNativeSeparators(pathIn); QProcess::startDetached("explorer.exe", QStringList(param)); #elif defined(Q_OS_MAC) QStringList scriptArgs; scriptArgs << QLatin1String("-e") << QString::fromLatin1("tell application \"Finder\" to reveal POSIX file \"%1\"") .arg(pathIn); QProcess::execute(QLatin1String("/usr/bin/osascript"), scriptArgs); scriptArgs.clear(); scriptArgs << QLatin1String("-e") << QLatin1String("tell application \"Finder\" to activate"); QProcess::execute("/usr/bin/osascript", scriptArgs); #endif } int DatabaseList::getLastIndex(const QString& s) const { return m_model->getLastIndex(s); } void DatabaseList::addFileOpen(const QString& s, bool utf8) { m_model->addFileOpen(s, utf8); } void DatabaseList::setFileFavorite(const QString& s, bool bFavorite, int index) { m_model->addFavoriteFile(s, bFavorite, index); } void DatabaseList::setFileUtf8(const QString& s, bool utf8) { m_model->setFileUtf8(s, utf8); } void DatabaseList::setFileClose(const QString& s, int lastIndex) { m_model->setFileClose(s, lastIndex); } void DatabaseList::setFileCurrent(const QString& s) { m_model->setFileCurrent(s); } void DatabaseList::update(const QString& s) { m_model->update(s); } void DatabaseList::dragEnterEvent(QDragEnterEvent *event) { m_lastModifier = event->keyboardModifiers(); const QMimeData *mimeData = event->mimeData(); const GameMimeData* gameMimeData = qobject_cast(mimeData); const DbMimeData* dbMimeData = qobject_cast(mimeData); if(gameMimeData || dbMimeData || event->mimeData()->hasUrls()) { event->acceptProposedAction(); } } void DatabaseList::dragMoveEvent(QDragMoveEvent *event) { m_lastModifier = event->keyboardModifiers(); event->acceptProposedAction(); } void DatabaseList::dragLeaveEvent(QDragLeaveEvent *event) { event->accept(); } void DatabaseList::dropEvent(QDropEvent *event) { const QMimeData *mimeData = event->mimeData(); const GameMimeData* gameMimeData = qobject_cast(mimeData); const DbMimeData* dbMimeData = qobject_cast(mimeData); if(gameMimeData) { QModelIndex index = indexAt(event->pos()); appendGameToDataBase(index, gameMimeData->m_index); } else if(dbMimeData) { appendDataBaseToDataBase(event->pos(), dbMimeData->m_path); } else if(mimeData->hasUrls()) { QList urlList = mimeData->urls(); foreach(QUrl url, urlList) { QString ts = url.toString(); if(m_lastModifier == Qt::AltModifier) { emit requestLinkDatabase(ts); } else { emit requestOpenDatabase(ts, false); } } } event->acceptProposedAction(); } void DatabaseList::appendGameToDataBase(QModelIndex index, int gameIndex) { // Make sure the drop occured on a cell! if(index.isValid()) { QString path = m_filterModel->data(m_filterModel->index(index.row(), DBLV_PATH)).toString(); emit requestAppendGame(path, gameIndex); } } void DatabaseList::appendDataBaseToDataBase(QPoint pos, QString src) { QModelIndex index = indexAt(pos); // Make sure the drop occured on a cell! if(index.isValid()) { QString path = m_filterModel->data(m_filterModel->index(index.row(), DBLV_PATH)).toString(); emit requestAppendDatabase(path, src); } } void DatabaseList::startToDrag(const QModelIndex& index) { DbMimeData *mimeData = new DbMimeData; mimeData->m_path = m_filterModel->data(m_filterModel->index(index.row(), DBLV_PATH)).toString(); QPixmap pixmap = style()->standardPixmap(QStyle::SP_FileIcon); QDrag* pDrag = new QDrag(this); pDrag->setMimeData(mimeData); pDrag->setPixmap(pixmap); pDrag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction); } void DatabaseList::startDrag(Qt::DropActions supportedActions) { startToDrag(currentIndex()); } chessx-1.0.0/src/quazip/qioapi.cpp000644 001750 001750 00000006674 12223260306 017710 0ustar00niklasniklas000000 000000 /* ioapi.c -- IO base function header for compress/uncompress .zip files using zlib + zip or unzip API Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant Modified by Sergey A. Tachenov to integrate with Qt. */ #include #include #include #include "zlib.h" #include "ioapi.h" #include "quazip_global.h" #include /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ #ifndef SEEK_CUR #define SEEK_CUR 1 #endif #ifndef SEEK_END #define SEEK_END 2 #endif #ifndef SEEK_SET #define SEEK_SET 0 #endif voidpf ZCALLBACK qiodevice_open_file_func( voidpf opaque UNUSED, voidpf file, int mode) { QIODevice *iodevice = reinterpret_cast(file); if((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) { iodevice->open(QIODevice::ReadOnly); } else if(mode & ZLIB_FILEFUNC_MODE_EXISTING) { iodevice->open(QIODevice::ReadWrite); } else if(mode & ZLIB_FILEFUNC_MODE_CREATE) { iodevice->open(QIODevice::WriteOnly); } if(iodevice->isOpen()) { if(iodevice->isSequential()) { iodevice->close(); return NULL; } else { return iodevice; } } else { return NULL; } } uLong ZCALLBACK qiodevice_read_file_func( voidpf opaque UNUSED, voidpf stream, void* buf, uLong size) { uLong ret; ret = (uLong)((QIODevice*)stream)->read((char*)buf, size); return ret; } uLong ZCALLBACK qiodevice_write_file_func( voidpf opaque UNUSED, voidpf stream, const void* buf, uLong size) { uLong ret; ret = (uLong)((QIODevice*)stream)->write((char*)buf, size); return ret; } uLong ZCALLBACK qiodevice_tell_file_func( voidpf opaque UNUSED, voidpf stream) { uLong ret; ret = ((QIODevice*)stream)->pos(); return ret; } int ZCALLBACK qiodevice_seek_file_func( voidpf opaque UNUSED, voidpf stream, uLong offset, int origin) { uLong qiodevice_seek_result = 0; int ret; switch(origin) { case ZLIB_FILEFUNC_SEEK_CUR : qiodevice_seek_result = ((QIODevice*)stream)->pos() + offset; break; case ZLIB_FILEFUNC_SEEK_END : qiodevice_seek_result = ((QIODevice*)stream)->size() - offset; break; case ZLIB_FILEFUNC_SEEK_SET : qiodevice_seek_result = offset; break; default: return -1; } ret = !((QIODevice*)stream)->seek(qiodevice_seek_result); return ret; } int ZCALLBACK qiodevice_close_file_func( voidpf opaque UNUSED, voidpf stream) { ((QIODevice*)stream)->close(); return 0; } int ZCALLBACK qiodevice_error_file_func( voidpf opaque UNUSED, voidpf stream UNUSED) { // can't check for error due to the QIODevice API limitation return 0; } void fill_qiodevice_filefunc( zlib_filefunc_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen_file = qiodevice_open_file_func; pzlib_filefunc_def->zread_file = qiodevice_read_file_func; pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func; pzlib_filefunc_def->ztell_file = qiodevice_tell_file_func; pzlib_filefunc_def->zseek_file = qiodevice_seek_file_func; pzlib_filefunc_def->zclose_file = qiodevice_close_file_func; pzlib_filefunc_def->zerror_file = qiodevice_error_file_func; pzlib_filefunc_def->opaque = NULL; } chessx-1.0.0/data/images/insert_move.png000644 001750 001750 00000010035 12176205356 021035 0ustar00niklasniklas000000 000000 PNG  IHDR szz CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYsIIEtIME -29̃[IDATX͖kUU>3S\g&5ӒL ++L-zSQG({EB:H/҈G$V*&!ZRLh8ͽwqνѹя,>^kw -Ol_CS*ΰ\䔧,fhˮG/C[R Yi`D=]?v_=]<6 .j58J_ˢp8+<ґVc-1o]ƻ<}YYُIٲq;e&Hp0iA+bn]9}ƷpߤsİI+ ~;w"צ$A#& O |)"?24m/17ӵ^10 ƠF z^.!- (O-~ٽza:UkElX "QQPc#GկR #9p-z;=d#//Jˁ#)cm߭UHZ$ebR#L;UJEx{s賃3~|%NjV$I$Ԉ&s2i!)89ԥʋNl//:"*]O._TD%EHM\'>IIĈa)ry\@(8UD EmU~[+ #(&Q;_ݓR.?>cbIR5F;ςY؄BQaۯ<ጮpv}m޵vC;oO^@S-s4՝~[ص*+t-`g;^c15`%2iq'sڳḣ?GV}b#""$"D>s rz[#G\킺phjvwvϞxeޕhu^x0jh|[ΠeV`ߌʪRA@_T0d'JaQdٽA!34haJ+PS1j"e3|;%5R%=!-rkv+Kjj TJ7^V+0~A_u IENDB`chessx-1.0.0/data/images/plus.png000644 001750 001750 00000011556 12176205356 017477 0ustar00niklasniklas000000 000000 PNG  IHDR szz CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs11(RtIME 0xqIDATXÍ]T9gvgeW\.HR`u` m5`•؄W #zѴHIW~\QSC1)Q"Y(B(cvvgxŜYgIywwyy3M[_~իW˚5k`+WX1P(,} ps~hh-[*O>${ȑ#?)'8xtϞ=[.]sU>P(P(H(뮻xGO|WEd ,X-Ӯ]x8tPҥK:66JE0tjUUj5EKD0r믿&͛7~{_kTRdubbB'&&\RJjf`4 C|۷C`N-3I~\.Ν;r?lٲΝyOrECCC֯_pQU[opppӜ9sl.=ϛO=EDDPUDq * i,sy}|0*oy9v?'"dKU˷ozRb<)h2'٪40}}}>}<_|ݻwU~hѢtwwL؄\hjzZKGG[v`Yl|>O""dM49Ύ٧YBUZ+}|/>e7.ގҪN[9R؄$$&&Iy˗/ .] ŋvuu|׌Z9s p&&N#bMw]j__=ЯY3gkoo'/$`lI5}ݷ8dgcpΉH#3=cx'(DispY UKwPd% PP5xCy9rXٻ V/b#@bR젓GU2+WڦgΜgCR|>s,5Sk1ģeU/ ,aZ Zs299q`lddLRt^OT*4BH#guZ͆)\Uɓ'iJjsXk1L ?gSJd8gϞ_4ٶm0 Q/cmh(xk㌇׹^N:Fx7Mxi9\zUwp9;=gO>mŊ-ׇi nv7lwg[zk׮駟k'˾˓fZau,Ѫ*_ȢY3 p^'ub]TX,п_}տ0oɚpO>{޾#BU%N#҈(։Xf+b(N:K/mowS L9r`ce^Um 'Yk9LsN1ZմX,z>|xΝ;n>ƍZ[C:^i*a$rYŢ\p;ZWWqT-W z [{iJ^9wܡ~Ys3Lrrή""ry2M9\=~v[wt $@ilZ7iyoexdBly- Z~ftuF>bIENDB`chessx-1.0.0/data/images/swap-color.png000644 001750 001750 00000010717 12171025447 020574 0ustar00niklasniklas000000 000000 PNG  IHDR>a CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYsD$D$@gTtIME֭ IDATxɏUtqcLT QȆqb+T01FA?дҍ #ل!pp @iIUsϗ{ow>r\.p" [U)=%Epأ4,>U=/UX|8x$}9!<2xb_*܈, %Ty< ӓgz@D`X Ƶ;? 2ּDd03F p,XTpɸϴDYൢ-_Q Ed0ڨ6ݾfGo\n`_Ajib"r9U.ZJ{5_U4kdo9UJ :#*&CtBpSb8II`Y8W}A 0 >i:3Jmtu}*myu+ʼۼ+z٬׹OOևBJO] ']۳@O"eN9CȊ_U5@}? o+f}?2BrA*%4UjD }dmk@wdߝTZUQNT=B?ӏ>Ѫ"Чg>[TTD/ }YOGdݿ^UϚ5 WUDT>ʒYOlݿ]UO5@ܳvDf ϒzU@}Jigw}jLŬDd٠ϪȺV&Ct}խ@D& \Чl yป}V6} }ʔ}0S >#*~]N=kG#O '>賸_ 夏CK}6D-{5+fuc%K,gEdM>4Ct5 ϚVm%~> @7oQЧ >ij:i@f'@;08pȺ%ЧiHOǻvFfR=scc>UuY`¡K,Чˡ!8WzrL ܡ=d>"C >/_'}%CtRKf "O'M>L?铮 zƬDd8gC{ xY8XơOJ}jwc0ONSBS7>#RBz&Ct]Tc>ZVVS'}}UjS 8|C{ '}UzS U=Q+}&CtmCI,'}:">TuY8ѻV#l YC 0>ic#Əwd;U=WdM,ȺuORK74Ƶ,g,}<0:g'"2aɫ :Vp'0h|k;Ugh}|v6Z3+}B pĨ =PJv.t'+Ƚp5{>&eM+`n7=U!(n!nE  L>.';W?.&"Cq TʂBBZIENDB`chessx-1.0.0/src/database/output.h000644 001750 001750 00000023363 12223260306 017660 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2006-2007 Marius Roets * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __OUTPUT_H__ #define __OUTPUT_H__ #include "game.h" #include "outputoptions.h" #include "database.h" #include "filter.h" #include const QString TEMPLATE_DIR = "templates"; const QString DEFAULT_HTML_TEMPLATE = "html-default.template"; const QString DEFAULT_NOTATION_TEMPLATE = "notation-default.template"; const QString DEFAULT_LATEX_TEMPLATE = "latex-default.template"; const QString DEFAULT_PGN_TEMPLATE = "pgn-default.template"; /** @ingroup Core The Output class converts game to various formats. Usage: @code Game game; PgnDatabase db; db.loadGame(0,game); Output o(Output::Html,"/usr/local/data/template-file.template"); o.output(&game); @endcode @todo Should output all tags, not just the most important ones. */ class Output : public QObject { Q_OBJECT public: /** The different types of markup that can be used. * The settings for each is set in the template file. * @see setTemplateFile() */ enum MarkupType { MarkupHeaderBlock, MarkupNotationBlock, MarkupResult, MarkupDiagram, MarkupNoFormat, MarkupColumnStyleMainline, MarkupColumnStyleMove, MarkupColumnStyleRow, MarkupMainLineMove, MarkupMainLine, MarkupVariationMove, MarkupVariationInline, MarkupVariationIndent, MarkupNag, MarkupAnnotationInline, MarkupAnnotationIndent, MarkupPreAnnotationInline, MarkupPreAnnotationIndent, MarkupHeaderLine, MarkupHeaderTagName, MarkupHeaderTagValue, MarkupWhiteTag, MarkupBlackTag, MarkupEventTag, MarkupDateTag, MarkupSiteTag, MarkupResultTag, MarkupRoundTag, MarkupMate }; /** The supported output types */ enum OutputType { Html, /**< Exports the game in Html format */ Pgn, /**< Exports the game in PGN format */ Latex, /**< Exports the game in Latex format */ NotationWidget /**< Exports the game in format appropriate for the notation widget */ }; enum MoveToWrite { PreviousMove, NextMove }; enum CommentType { Precomment, Comment }; /* enum CommentIndentOption { * Always, * OnlyMainline, * Never * }; */ /** Constructor. * Creates an output object for the given output type. Output can then * be generated by calling one of the output() methods * @param output The format of the output to be generated * @param pathToTemplateFile The full path to the file that contains the * the template for the output to be generated * @see Output::OutputType */ Output(OutputType output, const QString& pathToTemplateFile = ""); /** Create the output for the given game * @return A string containing the game in the specified format * @param game A pointer to the game object being output */ QString output(Game* game, bool upToCurrentMove = false); /** Create the output for the given game * @param filename The filename that the output will be written to. * @param filter A Game object. Exported, using the output(Game* game) method */ void output(const QString& filename, Game& game); /** Create the output for the given filter * @param filename The filename that the output will be written to. * @param filter A Filter object. All games in the filter will be output, one * after the other, using the output(Game* game) method */ void output(const QString& filename, Filter& filter); /** Create the output for the given database * @param filename The filename that the output will be written to. * @param database A pointer to a database object. All games in the database will be output, one * after the other, using the output(Game* game) method */ void output(const QString& filename, Database& database); /** Append output to a closed file */ void append(const QString& filename, Game& game); /** User definable settings. * Sets the filename of the file that contains the template that will be used * when creating the output. See example template files for syntax. * @param filename The full path to the file containing the template for the output */ void setTemplateFile(QString filename = ""); /** Static list of objects. */ static QMap& getFormats(); signals: /** Operation progress. */ void progress(int); private: /* User definable settings */ OutputOptions m_options; /** The name of the current template file */ QString m_templateFilename; /* Internally used */ /** Text to be written at the top of the output */ QString m_header; /** Text to be written at the bottom of the output */ QString m_footer; /** The type of output that the object will generate */ OutputType m_outputType; /** Indicator whether or not to write the move number, when it is black to move */ bool m_dirtyBlack; /** Keep track of the current level of variation, for indent purposes */ int m_currentVariationLevel; /** Character/string used for newline */ QString m_newlineChar; /** Pointer to the game being exported */ Game * m_game; /** Map containing the different types of outputs available, and a description of each */ static QMap m_outputMap; /** Map containing the start markup tag for each markup type */ QMap m_startTagMap; /** Map containing the end markup tag for each markup type */ QMap m_endTagMap; QMap m_expandable; /* Setting and retrieving of option. Methods to inteface * with OutputOptions class. */ /* Setting values */ /** Set option optionName to value optionValue */ bool setOption(const QString& optionName, bool optionValue); /** Set option optionName to value optionValue */ bool setOption(const QString& optionName, int optionValue); /** Set option optionName to value optionValue */ bool setOption(const QString& optionName, const QString& optionValue); /* Retrieving values */ /** Return the value of option optionName as integer */ int getOptionAsInt(const QString& optionName); /** Return the value of option optionName as QString */ QString getOptionAsString(const QString& optionName); /** Return the value of option optionName as boolean */ bool getOptionAsBool(const QString& optionName); /** Return the description of option optionName */ QString getOptionDescription(const QString& optionName); /** Return a list of all options */ QStringList getOptionList(); /** Sets the start and end tag for a certain markup type */ void setMarkupTag(MarkupType type, const QString& startTag, const QString& endTag); /** Returns the start and end tag for a certain markup type in startTag and endTag */ void markupTag(MarkupType type, QString& startTag, QString& endTag); /** Read tag settings from user settings */ void readConfig(); /** Write tag settings to user settings */ void writeConfig(); /** Read the template file */ void readTemplateFile(const QString& path); /** Sets the default settings for the specific output format */ void initialize(); /** Reload default tag settings */ void reset(); /** Create the output for the given filter * @param out A textstream that will be used to write the results to * @param filter A Filter object. All games in the filter will be output, one * after the other, using the output(Game* game) method */ void output(QTextStream& out, Filter& filter); /** Create the output for the given database * @param out A textstream that will be used to write the results to * @param database A pointer to a database object. All games in the database will be output, one * after the other, using the output(Game* game) method */ void output(QTextStream& out, Database& database); /** Output of a single game - requires postProcessing */ QString outputGame(Game* game, bool upToCurrentMove); /** postProcessing of a game output or a dataBase output */ void postProcessOutput(QString& text) const; /* Writing Methods */ /** writes a comment associated with a game with no moves */ QString writeGameComment(QString comment); /** Writes a diagram */ QString writeDiagram(int n); /** Writes a single move including nag and annotation */ QString writeMove(MoveToWrite moveToWrite = NextMove); /** Writes a variation, including sub variations */ QString writeVariation(MoveId upToNode); /** Writes a game tag */ QString writeTag(const QString& tagName, const QString& tagValue); /** Writes all game tags */ QString writeAllTags(); /** Writes basic Tags for HTML */ QString writeBasicTagsHTML(); /** Writes comment. @p mvno keeps a string representing move number (used for indentation. */ QString writeComment(const QString& comment, const QString& mvno, CommentType type = Comment); }; #endif chessx-1.0.0/data/images/new_board.png000644 001750 001750 00000007075 12142244753 020452 0ustar00niklasniklas000000 000000 PNG  IHDR;< IDATx^[ͫ^W}{oҐTL:HGRH'JfA;:F͠(:HPf6NBK1` ohڂ/su\k、 "?s;EDpso[1ى2ztΝ"l6UQTe-V 4"F?&Od\t.*%0 PQDOYl1`vME¤ٙLj`}*f` m>g PyDKǜM~rZY^ ("#07&bq3X7@&<xZ@ Cid\I7o M]kM=Ҝ;ר3[[hf&V͇҇sĵ &E@4,Bf' `Z 'ǎDL0G7Mnfef .`#2a .~k>:lXVqP";8T'Mvo}CUE3(|2]A[[W0a7c 챠s>344YZZS1 E +L{Yl, ]{~6ROe.j\ApAu ` & 9vzQ A 잞撻J<6 k5giQ4>ј=-"۰ILPRU&mbNs]1,ܘ0|HEh*8`bre`:8X `nR9fK6fsQg$e |RT W4" *NTeFw)e, [@tצLzEL&;0a/mHj o6{+®H0UQƄ 2s3b N X Qm0f `D ŒǵYHȇ""9J,;M,JEĉ`6#n&L0=Q:`uPPH"V ]cBbhX} sgA.ʔ;!]TN`;&|w0t( w`zafc"עVqq/5> R89e^ [X00ܫ*rF`` y"z}m\ |B| -_qԘ 3-fcɽeI{SO%9x@a-YY)*(3K ᠈mΥ7K,lXf5lz0Z@Bw='^~ˁ0FՂd(4j׏)d(dl5ٗkҗ뵼]ɡӋS*㳳iԣ҈,-9?Kmz |2fs4xҪNђ ɹVź_%`,'4`!qZp/3zUAF&3|n-&0q֗D7}Mw#@` n<9C`7BAJ=a\#:k˦"@X,?g_c 2[;rb^ n֩lM6 _L(JMx Hm p@ "zV :mB@@Vlb۵D cS(A-F@wEI yK]"ø@%2@&،W = fe66~:T7 쉡c ]OkmA% 7_-d~/`4.C<;3`ow4Vb0/.WU_?7`^˹AY(3&`($cHec<"`:27\ȫ@To~PiVm7ٮO=n80J: XXb<3`aXos46wfعv*5H7PE0cƏWhw"bQ/w`-37%XeߐsBF29g>̙ @g}q95ȵ*2>qg hi62ҙ a™f>lX7d$^R_tE/5vYwfQ8Iݲe)Mivb8k]\wŇ)D8CƔD` A g2&e1^Y]WrƂCnt2b2zoy3v?9Rd$XoX#?:U?o.fg(6G#~!ziFm>q؛jL9"*%$6Y$&Kaw^+-s-?聭 q`w|%e{Kh mūȏô_(1AY*6e5޽{1Ty:ujk0[K0 Ѝiǩ`wx XnSNɬcͼzmΝ 4l>{g}K{3+@goI} bUN^.RE¢A :Gnov+ '7m߾=8p`\Qs>gW3*b`ƷXm!лF(T09LE]ϧr2bF5 m۶-ڵ+=#O?/ƭ?OǏr\|y+O<1G4}ܟ`;[IE{U6(دƶ." V۷?ےm$+TXÇ7| fNfeKV::8V11T1p?diҟ|<*?S+?-d~_rHdq o9zh:q};vtS={`v3-T3o!@}tk}K.Ck넦2~ꩧ?wI"ҧPIDpN j?rN>7e4`e-6~$*<`\ȧ4R!|իv6`7?h4{DA:\,+߬CK{EIENDB`chessx-1.0.0/data/themes/boards/sand.png000644 001750 001750 00000251337 10633750627 020740 0ustar00niklasniklas000000 000000 PNG  IHDR/ pHYs  tIME 6$ ` IDATxڄ-x$ٱ-FQp'̂YPu >S=@nvհnTJy=/߽3esDXk|(('<`|`"2|3 /v]oe:x eg<x|K?7?|w>$/(|oqY_1I<|,=}m3,_ߙ/(>E8gF9ϟQ?AcJςxͽ>[)}dN|˔ ?zFz.sA߷}>oy9_2_'@? @%Q}V?3 Q~>Wr#PW ]U~ {|}f)opЁu'1qM|{&[?<:(`]9}#Pr*ˢt(?X`|E?;VY+Ye0P {7T4!jz7|8ƭBDž#/{һ/rM/ :}H#P z +邬*@4~uiem3F5e!%F|xODV֓2osΗ,T1O~|:% .َ6e /Pbt3P3@ .!VsAo.=z:HwgK.8; dw#Ϡ" oW#P F`T'"dۃ &"=E{i }ȭ٤!ҹ=y`!-ewe[t:dPF=yHCTf:xi6fi(d%N7[(+E7Y.Vv3N),TvU6qyQe!оhd4ĩ8zp}xc9m7*" @c:HN_298D.!j˝ܠu;Ԅ̬WN>{1E)Svh&D8,e;\@sy#g]bk tyg9En0wPfZأZw~+̺k m!d!Eb’^Cƽ^K bwYz-kȃCAK$X]v=;-$ H^HvԪ^$6bzpTÍjK2U=QCb񀏧 X K/NYc'^#>4EO\gG^^c~ڃD/'ynHR43@#>j2FGGIRY\TAe[ *°VQEErUN|z&G E$a9/:iu $2FbOq꧛dj[SЫɈ.WgG95$* I&#E)ں =UmըR[Z)4NE2)ZZ[4dMNJ<ǤEޜt i%o=b;UgM n{@AGYeqsE@ ex.4J(G I/oG*5=En$dB^߾Khp 4 n xa)Q,xKIVJc  |'*x~ l0ۚLSɵnk4V[pONs8cWȀ-S\ X"lcyjq9h%~?%'S`\p8~Se귖7k I͜R$P)OO0h<%Q!BΘAQ\Vr \*Z-5%1_~KkLhPT[{lN@=uEC1~ S^|#۩{NUd PiCEuw?o,k[(zxƬ'5RzI)ʂ, aiʃ_A8JT%E"H/zbmżHx;z)yWBd+JZYh(!_2'fAoh'F֫#"*i( ; H=x+g9P?8{uJ3E!*-_&]WqAV %tnk Bi|AEEPg%jqDɡWBTWIQJ^xa#>՚階!Ɲ8Er).,A, Dz̊ ?fEh]-_r8^-|N7XiDR;xi|AsMwM͍ƒۢTJ܅f#BLsn8U)z1Cm 1̷/(MD"SK^H^R w6(9԰B02}iѺwØ UL>$𨵞\C|Z)#Q`ϡנaw=Ѕ9O!jy"ٹX-KF&,$$ Q{,qVI5dLOuPRC+%Q 55R%3c}e H <&^v}.b 4$qJ<̬ǺG&F*x8)tm4D]b<$Z;)&J;G|NEr|vDƔ<=@yϿ( Q9H ӹTiUjm{j`#6og t 4N>v߳G&NԏxB\ T)J^iᡟEZ]-Vѡ^Nhnr8 @a(2UqJⱩV?:F ;R%yWFC_#/28d B9am HS<"r>-m Ua;cAa4T$^b+˚yZ%T0 =Ih@w59Dw$0_m4d 5m=Ԋ66?2Td5Ru㴎70|N?5/eCㄵ8flT+jryaeFe[j\}шyE%iptԜ30kEMcGkN- U8XA+w Y5Dc<+j2%Jb3zŲlf=4 cW2?؜9Y1Q򮖵I/ !PrU!YZbH$!坴{Q(ƊF>+ J4_ŷ9mEٞBEBK?P1"b.Z?!%9!/ZHjRTu!)q Փ{ kRd$e?K%TA)|[()03 )6|W6vpeav{FN2﬈CTHżZpw* rB#9j y|0yD/*41{k0.-t0‰*U%MQܥcB.ߩ& D4k Z`Tx%)U?[Bɦi]@;-EeJ I R8i<$_z^Qelf 5~\`q¾C* /PME9VCh>u7{|oPvnَ?N ٽ߫Ȯ ei׫W-ɯ/*!fE jX*L %Ȑ2Y 'U+ H?:#e6E<!Eğ*LJ^;FhQk:u,)1D{XMQo0VK.:V>Ii*l_3@ʹ(;bƀlU ًgG\o-v#: q˅.L%fAaɷ /h-h+b2TR8 }f2V[ ]٤R=ojjBJcRSh.J7ȶ8݀hm(剶>) ȷnXtTK*}jmȦ!kLIީv7.5' aW7Kg<އ 'zM-OO^՞C/{gW] jԈm9F.ã:<*1' OZ$Ν)WJ~d"Fsbձu9 = )R.Q|L 7zqIJ"Jy &-iA 5#_gVdj)ѺdXHsG j_ԃ*"s^gna+ig+yԪD"'<>FavD'FJMeG65Nr IyyI2F.bi/ug$J8i {*iHAQxт_MŸ>EZ`-P/@q[CMO&Hgpv+4WKr ^T-5(eE aagVߔ_4݅ܒd҅<XNL=vd_B4⠢ P9utoJW'jC#7aQ5UЁAE}1+`|/Q~:o`*Ji41ie(SZI+uH1'HbId*9 Yc.@4TۇT0ғ:&N 0xLNN.[bF\,X^%E,&pj.'S&`cs窟mX^4t:i#;1C-aKc*=wh–!QǺzEkcܟ eClsIJv(RG=GC鞕C8VE>Rz+\f%iɛE?eWI8 9jrJn\g:) |S>,ibZWr KB]rFCLO?wG 8{@k&|kf{2-Wɋ9rt A}Ϡ9PGpBP7TZw;UIhg],Kw߿߾"=7DP&bhӥoޱbQ?5uvK$Z~2LqVUaOෳ0Y]+sk!Ai6oQJ(bu׆"¦ C'bVsUśEREzO=Ջzʅyh8*M t8 :ݺrj,cOO5ٲےod誫:!-krTWuYOVqϨozG/!9 qPkteRd%H"$R$oɪh!3h \IJE Vۢ,kэlI$ZM:x)XE+" IDATZ~C}+z (CǒvV8V":/e̿jovzuTHk]I I뛜ý H|gj G2>5,j|QcbZMNXpX-ˠ" Pg!(ƆBV&>)Fr Om=jJox\QE]1M}n&cArWx{jQ&VOlTA>9MX7Wsg]z&94H-{|4psO!S86딉r.7 iެ3QzKP mԙ+f.}pX1 \5O&?uVI #:d BxF>}Kupn*| ?=>Ngm \,L!!Y f*p2ђ_F  iR%aAv z ( f&^b }KOd`ź%aM\2JvՖ{?DyYSE '9//Q"wpM+0U;T"7\9:ܧ%=㗀1:/yѨB-rՂJN% FЖtuRp\(0o)B=9 .LdKaq .&4ebE{vjCjWU7HfU"a5}FRR{jC{$pPZ;Mc< 26曍$UOEC)-K>L$i" SqhIP,>?F_y6}eՕH3gw%P2N+j'+"k5ٚ-8:;=UC\Ltz"q14}|n'9I<#ݞ3?d\9" tIWrZKX,/~?4#T" 4n󣡏7uY32Xteͫ=z4Ns$uLsVDnдrl*:o|p簟2SehInKwPg4ޭ*/m!zb[8kJckf0}jqe{9dKgMWBFm `rN+kyڜ'W}^63B vuclTS ^aT(gibؿ=߭Vש:juz[Ҁykimv6L5kTԡ7=c(eV=?<]cyDo`gn}]tJ4Ս3&vML qԍTms0O@O3+[P6,kK#&CRQΉI}jsPדb5ihdƇ":UwyBHm=K*WS!!dVvs;;u)<{IJ06; ~\&fxm&Wqq1ZNHia)W;뱨 u Ӏ/HJ%5J7U?eu~.Uԧ>WxcjRJ5 1ug9g-v+7hcվ"侹2If"BlyzۦA4 }Fw0~°E@ڶ8˰ =ucȭ; C5%Q|l{%H~kWC>MOIuN=(3Yrjұ^+ӊXǧ, ř՜o-}mڌZӻwkx{\q995_(t)mSwK8QȪ{i |NyޯiXkV5>])V8Ί&`_t xs-Fv65盲}w53ю7}H{;Q-Rz@b8gְ/В}3Ҙ[m'\}Y/|"S4Wǀ]T}6cjS5V3۶3?K|q8}U?6cnu,F϶dg>o7! ?'ѳ.'kQ) %:5m餅kkeҧaZM7Z5zkmr|+0|t w>  _ af ^'0[t]+e 0*"Yzj \0|^K\P8;4=FQ}E}f4G@pJjIlxDFwWBAT'P%q7 Z/B)]6E{wOj Ɂ/䉴!aRrw 㧽O,tUk0&5tԝzT) PqȎ|{A_QG2m B$8G o0, %)S2JtKdϜX("J)kcZHIWɒh JJjp1RWmi`!ld5otU&}"N*9j͎ei x!Q ~ և/b٣NY"ilb#0T@M[:+C 3ǎO511)(g7;0XZ)ө $4մ9!YQG @[&&WEC>wA sW<암&{S41r `n5E[gowoZHW$j + F\ȹuA)BG9FYk@`G8z/tqtlfk 4&JWTΧt"B R$rˌ~IwQ!P.)#dWѷ6QprU{1j͋v%PoϨw` /jȒX[EL|T+j!B@WklpEW#,u)Qکk1 4 D0j823pR]5$f*j߾/gT5h@)P@?OJt[6;u4ϲ -E&>=&c4Eh-Fݪ3YedC|jPey+0ķO`}Xwd/дZcrQ4/4OdƓ^ńq=pC }z4 ڦ%/x( 3= [kRT/dNpwZ#!C(Yf|~oT3Y,CҾw)_m~֍Jz`B50#q¿[{N9Cjz[{StC3oQÓi^?lu&+I: *PY;ޏ;R[-.X,?8kOq2M4MkpI¯z\c.s2 ߟˆ(9{b3˳>g7zkncvj5=⇧E:Tbn-|qYM榐U B5>&u3ڧz4}tckEz<bPm6|gszd o=LJ71P-&uݪʿAc qzd4Frx}H>]=oW2SlR"5RX(Zr|DUڅ] n3釸WgGa;2Gcs8y6_$7 ҎA\ް aItw,ݏ!%d1 SeR;h/ >S;Pk{VsS}%b:`]1DpyCl q&%b%\#*uWqG0%tQN$sq- _JWD..+{N RVG1GRA^i&$u ĶA%2XCZD'0J;'ųr`+˒. d",7,siֻ . f u8TZ]j83wեuBN-)S;n:e _< u w~W`JA!r)s9Nl\R"atY4: YÕBN+ ZtN)59ө 4>[7]*x>[ `Jop$#"֌ 5ju{V4 vYэBWr#lGYܴ}NbǺb 5 Gɜ$Rb*Sd^P~R.$b!IR{+ 3ȾoA;tgՋnWW.OA;tSxtTG@E7|E6?EK_PwRHAJƭyIM~,W6ˆ,zK'߹m)B|IV, } z sq伭YUڞ~ZV<>J֖Am'! V+^c)왣u0Mjl/4$]a6bB>JF8=>M)3EYR`-TxbHEՔm49M ˳j˗0kxs*WI]aJ6GWڼGM]~:>9WwGbdRZhzٱw*LĈf7T-&D7;£ !ɬW]#0܁ ,3XѮ8I73IeJp:$_u^P0mU3ht]a߭OgU=G4 =Cmr\EƬMkeʰRmX&t$snySk^ZMB!L tm]nJCp- IDATWj xoQ82xz/wurጒF5 YS+"rxRs~79 yÅʽ~x lk iLŤ]ɔh!<'0N;iWQ:8 6CGXNY]tw jYu4蔚ΤgT"o6Q 삗EKFxKNmĹ\^RxW$H4F~$!v~gXA1VDXr.ןz|}8t)=?* H2w>IwY 7n.Q1Ǣ'WYRa8oN4+(<؆:n!ʫ bLZտ#ʽ9?s8V }^\G륛//(!7o^*`D;-V+m????=S\PVQ3**HO~RQ6h K<((W]$`'>͑H{dŜ i>ZGϳR,O )h3-PB;;N%˥z bu{g|(1Go*<_znQY!6r%IڭJjX A'k`&5t_@GCaZ8$$aK3ʼnjBg[*u>|~NMRd7MOgƮ &e_R",J4}r{}@qaI"6N4eӡd۠.iHFb~NM+}ΧvrHqsةF^Y9ֹ1ЊGL.*' TBXh=y;' vRsh[<3K&阮NxpZq,<]rcOu 7|qkԙs+n2cpddE Xhל3W)yQ 3ʧ'b;}>]ͩ|*&&= uOO3jl!y * g_YG^v$%h_C-qZ4rtą wk.PXxR[I;r q82fH%칵5HVUAuѪwQq^YE_cB8<t'Q>X1yGc35Q@pg+( EzWKLPsm~,#6?h߂W6PoϨtWVE5Hߒ?@/~&hcP}OテXe{ ]wZUS);ficAhw.b^qcm6`V; CZ2{k";]2+c; op5Bz 31F{MA';ܒ_(9F=7GJo1a~yUw%A2"ItYGę'%Rm!~CHrĤj2KSV6ʺyAK|1[[6oLJ?=<\$%h:32nP`]ڛΨ˶X]\ST},FpVYj/**4P{Qo+7 רѭp[wI R_HnMЭSlL%(kS M[5& ˲q[UgP|P۩Sd]zOUq X5BJ"I椚_h^x8BWMlƄކ</)8Wry HBo'N]Ecê~"nm>^4Lކ*R\%NtcPC~銊nV0-E TGa>hR=t~"r&TE ;:Vp.L΢5L B9sjǃfe|ZᕳKڜ7]xH"h߲ĸHjr;1^B:mQpO[}㻅-tq]=Zێׇh#KPM sV};'^3o(FXյ&h*l!6DyVϝ#fK 7hDZ7[a)L-s83#!ӎOf5+uo4y2?%/)'"F/;/6!U`K/sRm>s5Tzƫ'7\45βiĐXEQGl{WwӻA.֙5@hTNGi2 B6Rd(-UH)RQY~o ԠᘌzEҾy% 6kY]җkk\MD\rBo݆@ˌ}"{%.3W3LELWՃ#=g7G }K[BZ tcM"eQCrCG&|˵5qT*m3cFq3ik;iGi:ǕQBBwHE BVKeaHVa>Æzq$hЍfdH1 66;iJ.*(D%pCŸ?Y5)52p"n}9'o {A>;,XS=9Vzv*.=q*˰a" n‘=ņ^w7[ƫj0lk]WUjީhC_dž^ ږ}|Gj4r=D*̶swc;|Y-[hOvk+-C S7t/ȝy06ђ -̍6>o*|O4A2cG1$6BlY#Om'&\&Yl؋NOy3jIYΝ$.Jr}HgOs{FN,Dl0;Mm-[m|AiF !NoF7ڹؼ 8~/ Ryh5ޑBXVͽGwvlݴS]L[cw{;6T/$$(Ĵ$5<TqL5 FEmðS4i+9Ғﰓr:s㗦 :6ibs$I#ީ4h( h6[zVy(k y7? la5!u/RP<}=,/o(n:԰7ӥ 4z/;yfN!j>OpLV`KY;N Pd9c_%@=ebej˳6"rX9(P5(!g[Btbr(N+U)54AzH,jssjgL֚%(5Lյ̌B㝣x"=ϸ\M \8ٮ|O: /}Y{)ظ]P/zSҩ<HYi+9ɛ"Ĝpeq7S$E<&k&Z;JNv*Y%J0GBȼywŔ -3|Vh#9œg D7WI~ӰTgWśUµdo5H*IO\@vt}9ލFBsqjݷ$95)M[\H[\a'Ukrx+0=}~I@tw]^4VV&.jɡn>@^LdbǸ!ifN)Ijz$7wLA'䷴wtܯ$|u0AⓅYS~5Ga:)>^䧻ļrmMyf𵚞'5q (cK܍grIs n'P*[uԎpdxrDITBQid ml!Lh٩&ܡx%e[,4Bx ʭ*RgK}DЯU'+uFQAQN2,!leɑrm\)iT=lot&í0C[v`X-r+%3%ѴԮ8;$l ٫(8~wQ 7:Jۯ(mY% >?dgo>jO GRΑOлpCnWZa)8& Q)ui+pTZtm{ %(P.}K#)g拪(B|wRc]SlOWU"%btPyL*cH` I #Oӄ娒EIK F߯>5m2Kh?i0pW+9+vNw '`f"LI ]ADlϒ@ҙ*&9sE6 /ޔ f:mxvJy G:pcg5kP WZS6:nһ,R Rץ$Z;NX8?-eWš7&f'QMe#3tQFKl nLr&DIVz סL&r510k5.ޣ.Wu[q2:?nzG*lSa#Ins}>7fcBmgikdXf2+ө &Ón.ͣ,^ig,)KG0 &/zl7stF)ݖR"}%uH36LYjyOAB$%RuF"vK߄jYFVq6@~N8$pn]v.p)W;nS4<#p.IáUM3 zSwۉ.KW^oNsn MƜBv7eixuZ}ŔSWsȯs';U}ܫ%ĠnL碧; KCuOѹw[qxM7b{&S@.uu[MC9Ҡ\r`oQ%hnF{JCØ zyoiC*NMkzOEΧ ;Q٢ a#N:NNݢ62;o_fc3~NiC,t<JTSۥb9lWMBp3M՞=F.Sh$}wa"im\JPݿ[TtcNda?+Y hvBr7v[ysH<4<蟵 tc5C>*(J7,,OFq'2, Isj )-SޚNSD ؟CۦlP b#(kR!'At#?A"lu(`I4%[M榟C G'!fRWFi<~?қȟy͚ynEsNKFwEXwJ`'E%EPNfkE=(۬FjNSPgb [1t+MAA4 x?LxOٱjM(7!TuM˵S6mHà-L>lLVM\}8ߜC a\ /%1D)GKj v!yݍ9 ODt[r^mqDF7pgr%:&) /qJbz]&Hy*?E"xwu#wVfuwƠMx۪Xp%wep+cZ;5#)alBfh ! IDATiVD%9 ̳f-Yc΋ J$Kv;?Tc[S`U*=3_./Qڌ}H—ˎ|U##j359cZӡo_Aà~bcz71ɯƟ; wk<mt8iԠiE!XAisTjuUm(C&ZVˆCX؎?mUmnT'Dv,թC%`҆!G+Wtq /c %Id^DjP C33ʁǶi,{Ʌ5eJ0L6U5sTUf}UEO`g4)|՞rsz~hz N NJD?sˆkbMTw(@H;{}#Og۾L<!Lu rs~Lq\1AqpӇF ]<-c=o&uxN{9Vb<$i#{I nS;/:(߉~.BC~_<*h*|@:ep";C(N%vb%Z՝&KVIC]TMQKbfG^FL4 r16`rUVG_#.yݥ^K 25Q84*oa]h~Qg})V:Q72n\e$Û =Es4so$IrdτKorN#EqPX<EhmQo֐LI68Y=X"0xAmS nA:Is=mjYfmVH?+G>^:Ҧ A]nvqᙄ̉]K:ĝ"ijw-d ,eT+1;LU݋*&N\FLh_ՍqR9_aEv/ µ71ʮhB:Oqh~QK;3I{E?o؟Jw:7Qa|R9HQPwesSRв:t毠?}}}Y[.fFlҕH;Zs3C[K_O9iǶ_@Sst oZl ﵲhN)pI);1E)9X]F1*$;L̜=+^6d9lXY~z[;(EjBx\`AKVNP71Ve4ѝ*\U_[㕛s^)5,HeyѴB9׍XYo_ČFm+;ԌBmŶ~9]=^gt{2Sv+iKM'y{$!4+M7Vԡ}6NA}o.ޮ (2qL)KQ,J;{ w]fRO-[Y8C})UMvNKjn◡1èkZV1׭ W+ݝNeyo/ݶm |g!9 <ܣb4QC\ٖr4w{Ȅs(ݵY$Y_Z]FxX>Zt>Moq O/u:WVS>7qd` > ʹL9Y^&?׈JXQ1-p_1VR vDaWrV& 5tWᚢ6ܞ; B\UʥijCۤ:O>!1Zo0igiLX9&BzL|).ys'B hP|ߐ}U{ !96Rt,Hl(/08kglF˴!2֭ʐO@oV4;?n |>5ew~$v/O{wљ8'e*J\ +z$ ՞S`"oy rהq"qnz}JH'`O=Cw2ڸ04Ri{?ч:rǮ` ]]Owf)28dУX)n_e[\yҢmSR"S/RVULi Yjx Y9F :12 " |5<9h%d(pD75G8)P6S}RbX$zfSTDX@c7m\URx)h4빰+:/r$!Q7-+>[E<Ovly ];}T{M=Q`ޒM )JFnsܫ2 N0 r#eF3B)jI烞L9qz0 Xh/>Ǵ\%[7#u&EkcD 6qv^'h15 يeE!PZ(rծG ׁ(}FlѣngDm~ԏ5w< zy+P>S&i_V3'pAEK  9;"KNDUX'AglF>Ӏgo}sGyysIa֪~'>EпQbo*q,1 RvY<MTkmtl۽c@g$Q?vB}:!J-/k'sWvzKV( eg/ gkGZQSf& <:ƭvTRפ3: /M?t!V,Gfpk.ڨڂ 66&8(d :tfg|Sie<1ϪDI0LU]WzUa9vGiTAmާ>-TrVWK5՚1߱\ßhzL!kr=CkzW 1>%lʦJ'L攜9no! ߾H/VDNEM1s:AuRc$@=9.eFeF Fsl͸Xto(.to0 WuPD;D"Me%bb {PO o B'dJ@ MsQ[򑳥HQq;Uo lV)V#E%*bmMsZƑʃѭ72{7mV<ݩi*m#)hxYu[:֔+8w_e<M_HмXUk!z9urb ΰh윹͓?DnCt.B'§SUJ;[pfis{OS:[izB 3OLdvB@wYT1:mgf7') ^bsp֏d.נ ]E x}>k{b䝩:+]ܹ燎њtj/8=T/*&sno͝0os?]项kɋ{WҚSs67}pg39S_ˮA31Mam▟CIV҆^B-krbO‹hAii-wE Vum``^_p蚈HzzDv-q(³%*i%:޸"@f<|{J.*VVh<5sTnȓy_Mt#G؜#xxFpsͤߙ[s975TdYoc8':+L}Dp(jNy8aX[YE {PNH<4fܝ:XncD'J|ϙ%&'"{^\4]В:;MrBzh;+=J9;[ƞr4*[V%34޾H43s:-.{86u, 8wۊ`8d1֓)z'k ;WAl (8| @qY Z7ƭ4?!W~ j`|QwLtenKu{ TPBҮD8Zo Ns<;U%¤k}.tg.%42s/~Y=&%*l֭懞7)RG>[7s9#tOԕP=viLeDS1Opjr7m9窌xe\=!?6?\(q4-%T4nsq&TF''}WO_$ lS8:ר Hq9s]w3?w B۸5%ݳ!tbM| =&N)tPDB g3%,4^X36ىs8#'1Qxļ-Rze`] `%afvn5Ύؾ3~2T wO+ԎZbl-3R:q]SR8m%)9ވN-zMZE?*BWټE0{Ϋ:p0}AeKZhKXכa9Ԍj_ÃSҢ~CYEpzF$|A\U?2V|Ct,C\aĈJMYzDb*Js0Me>dm%ګShYr^^i36!&]rۆ#<^lahr2Mv12O\?^enݦ,g VHyv˨JfįQ숹+Ҟtݣ+E"Ξk0PiNYjb^\(ڥV 5SA$-ԼE&?chY`PqryLf^瞁8|.Dg2iRRSo.-!cdHi{XקY.)T|fufMDŽ)a9L=5Şk1&C65(zOm-cyb-*npRnMsSpY+xM1%9C^xva~n-׭htӝ)|&\d9).?tzȵhWM׵aѱ tYޭ6Q~'Q,yݫ{y0;6>jFS9rKkvT vqrnRwk>n5t;QFah wO&&CGc4T=l~VL B̆lPA,HRAo $a Uhuon& Uy֡nAjfk2P?(SyJO><-;YbdlUCUvҸɤU%59x %(`T[bW/cEhNp3`H&!hmM/TL'gKV6zR*7W]fAZrM>6Cf8h؛ |nFr\iKnӬ6Y/sׯM?swtz82r"oI_3u6 3XR☗fNdbr@+ql}mymLfgr ϕ,(V3vN Nc0JiV׸2 ;D,1$k9qw"x%(;)X_1Ip}mo<D& Fʆ|:"qH%%PH!0i >GqXg"^@@)RC k g%N/(9GmأG4wQmsp= | q<b ݢ$Εv4vwf}_8qVCO-gq^qH:aÞs*{5N2)""y H 4 cSmrvY󌁺Fߛm'z>s@P_Pٸ8؝Ci+=_ztJ9)"nm0NŁ]&2hBbsٱ;;*"18MV3bĸlPʧ`ݖ|<3*`LY˷(a9ƀQM`F34s5X?&[ʍR7aD#b{G* |ft)sZtTZm-zْqJ{\}յl V^8?7j]45SrszS 4=Uj˝FҹLbsObJKp}GKĔdT.M|2f$iwksȁC:'g5]4 bkbnD <. c^䞄ID]W=ӑ`=IS_6(!-CtQ>{Dm=@mЕ|SޑKxobs\p4<<2J |2DYuJϱЎ[o2j69+ɨ]t73Zs ^xipr}A\uYM(یhhK_K 2+@gnk1JHcVN4㉷P'%gs9͘}R֍8^.)1lrɣ|UAY6)hQT 3˜į&{M_\ IDATl.y:a'I.&,w}ۓIRmXS`f?@) Y9ް4v }Ef&(s0EzPjL[$VՆdȃpZQ<*}5a-b^:t*PY^25T)7 ԗhFUٔeAi \r PÍS|HQl\l*G~oiVqoMr R7`ٓבmg$ #N̾NdфOlXg zGKPZ)zƳ =#și.F1Q%M&DoA'%EW ޟA˟4[3kf5@hAQ2=oL|<"[:uEN*!Pndt@jߔյ\ʢ+:% L- M be?;ٵV"~jۋh;2 jc;4Ѱ@F%yXvC˲*&%-YnI#!ٻa%UM2^S᭥Ք #O%u Ԫ%!4zC%QB$m޾2 hkDMמN["٦(RN(5eba4.5rxk*:2`^P*(*aĒv)4)d9 z#10JQgGI ؋Mm U(yC&kق~C\c\unזָTzCG)x;vH`T-݂mVjc ׇ?Xn5rYkâ9}[5kEo>Ϩ1rI,5g9v]0g}ä'N-*E |ۋRhyMCZ&)<:N+ k@gNtQ/׊Ƅg-|71Hgͱ`9NFa܁fSP?>aG 뵛Q7 kAx׿= M1vDI/1(X/~QNB~Z퉓vϠE|wq{E9SFcEݕymie)n'mgvxaWBR'oh'ree s54S 18n0X's{ۣS]Ք85(-Hkwj*ckMg9lsƶ6F8SG o7S ;zj[FUH'!]9h#qGqnw]}< ;5'=^ׁ);(c@h*Ifc[>D_4dXA"Ѽ5Hpc6/Q<~rM֘;qFϺ~Ʊxrq1n'ԙw7>$7XN.C'2s:轫2Pg bFǂ(w2OO}Ov\Yz9& »׋a$n& J Qnxi{Xܓ7yc˶\ۯ2Jy4a@$Yfr:G\| K)j}GPN[|6]2}l.$Q3xkaצ63 e-c"ACc^}J2ⰵ-(We'ɶSۿĖ#Y)6 ǖt41XP6|:)KdF2rncЬ-ՁwO>/dN(gcj)+(˿0:8-bDnm*gerS>k\M\߿J큢UBj>)0 xHUUѸL7)2 ^kGC)9P-ts{Xnacxטj}\\JЃ[TyJ>ME#m̠GX4!wsBҒ!lx{m&g>Rx^{ɵ=vkf eP*):Z¨6Ť7,񲌰W#hrtʯ:}/AW MnO }ϩ-ϋnWdY6R Bôq !]>T~J1\6)]97f}sv}hw 9!rk?V)EzY@"+G3j}aҮ|13nXo4ɆeצDLyau7DNΐ L7A>HЛBΉVӴ2hWFx7 !mtWyȉtWS!0iH[*V 2.Diڜ9U'ukk̂B0_ bceJ5`RڲNBfwIpYZ<[9#4/Uv2%aRMšrU'jr} bF>C@;qxܸa=ISv+kڕ 6RϿRQ-ɯjYGڬ9{ɪi?칊8b۪z1凔DTm>-:V_auٹF y̫\ (aB[ d|ou,lF4lyYUrD91\M$M)/2*<4K>3pczpzȭ0 xTx^_ߥI}A=z<?GmvK߅NMԙa5/kxxߞLim79.+"Z7ӼÞ{SK: =Ԏf&g?vJ 1wrW-ڱFJ8#m7!F3 9q~I=~| _T ֌ʆ:8ZsxP5RvmIo2q(0Q韼\?P.L3$XDB@PEa^*;ki~ҾM$^]oҒJ'Ɓik # o Gm\c~`Y CHmRWt`}VhL<K]6٠ke1 Qc},C9xiWLJΚ[&rVJȜKDx2;K=@tM@-,ֲԆssLԝTnJ0}!U JXQhu`\0L g>~2L_ ʒ~mky|bd2#I JֲRU[Mʌ^ϱVn(Ɛч؋fP&ߣʨEzKspkl&REE8 mem:Nn$-|ZȊnb xk)z+h9.*vۿ_3Q)$pSwozըhgƅBCGk,3[q$ BaՋajǟn!j㲕C;FkP F#~ ɊU(lnLgN '! 7)O[#HBl)-ļK[zAp z`'` /-#`Ͼu oT|׷C|WӘ%;:3h'?Ɲ۩tt?`&ZszI^4"mO|R>@]!A"!c|tvr\w {52$t(gE_ՠ&] %vS՞g̛7 SٳޣCP<ηM5 PԴTPqPkHWGYJ7k޾i R\6@GCLUQ+c) U9xꫠ3Cr,mfe mu#H&S,{hJ(7ʄނvW05H%#;2Im?E%Fw̫~רC G9$a%R#Ut' 44*lRY x-[E( (eY;E#P hFnt*JszI5p:vHOKB2GfZs{5ةuE-Sp% M/ɵ2|Uz#GK0*dJ~ugHa!@JHi^թD)Rfv*/W0+4~97VuPuh(;QMx[A? BR̷[ l"l;gImϷ/3paұlj$]}͸, GugO_B0W+҉7O+| w/0GAzKנ$eͬM k̯=\[Mf9Ԝyv{Oags3ϫI(NR.[+C_ed͇eQ(%AV6e?7o_p{-~IOњXbxƺeT)@Ւ7T= zTv4R r)гt}vآ3ljw ͉)MrO"*KneSQ`te&C}ެ0.'?7\aYǾ>'Ϭ\Wv`P:LMA/F`F |f6=.Q9lաl_,ejBw/\[[\܅e:zPfΠzs>0X_pb~\H$ l|9\ٴ*vL_@ӗ}|bI1 `Yr4P(;d{zIjy UTlhsHHkeOM 2n^!BX IՌ̓:kԎe,Ek"|O 6DTyk)V YD:SPY]sKyMKE+Z3V1÷Fi \KU+_Q7fd~M,H?B)rU`cys77\mhYto깻ڔo 'glZrmJv_D|NQoۆr}u炂4v e%Xe1K~FA&i gԋ2rir0*^hYW7;Za3CCL2缳xPX$T})cG2lRón;nZfWi[OC'˺Y**t>,;[A|lhuw0eyDCǤ6^)q!7y)d-ڵMP~nUŲSOQV"jJd^S9"\CwA;>O2s^3$ A Ib$$/qlЁdv=> p`pBڽ8؃m=H1s}?Y:5VzPWcc6G9=sKRoO(XiԋY|uTY˷>ضP-QL)뚔aJ4 emȟl%%üɔ<3$O 5sP%pJ\o((BQP7%HM%޷4| 4i›侸a(.R-(sHY2J-ePr{Z.XrPJb~TwB^aIG c*/XPk/da\p;f;w<-dJN+A S@1[F25R[FqʁW_~Y3H>h6sdhp=|@xj{y{nb s+:0gM<@ޜOdR^.N`g7,jB(+wpC|H)I숙Su9+'&Xk-z&}mLEn𾠔IJ/R}fUZzj/JW+zYQ?x,)UJGaN>Q*af sd5H=PܛiO?QHr_@kL\ QczϷ^qJ `Hlܶ IDAT~{F5U#HK)JQZ6$9}k6ơy2A$d=!Kl;PK{'Y-}8d*8r&!?P2v-]^Z ͏as$ߐp;y(/UoA/6UeۭW[IV9_Bp EQCOA+ [@eE/+X8ЃA$gWem?ts>XNTV [?&2cU/<7-iN0stM)y\d&b9F_,q_Wa 6W!ɠbt\qƫ^_;#,T*K*CP%¿iƴh&d,"ax슺]0[\k6|];Q}+(%9j(Q_(cC>4~SuƘ9MiBE M>4Jt_t!QEijH7ʎN^0뾪d\26'V+?T2(oOU[:˲ M|dKe(/W & *)⼫(TϽ Zgzf]owOOnV"'L:eت,Ƣt%-4<3sGyU2io9$WqSO"*E#4mw 7"5]C]h |y ).z+m%}rm8Zͯp:U.#lFs@+?wpHɏʪӚҟ3~R!LjZˠfVq_zXhƊ^L% ,{ǧd*F2nTM^iԪuEdcg$zT /5Tcz4ɶLřJ?cN FG4a#LMPRS q7.ʸeWSN%;]C[ PC=ZWF@3;.?eswL4c(G1pc9uaSQ`9륔k"^#䚍``<74w7ԉ8~ kǎAg2]/g{|J떏e^p<+]àRh_~Ѿ֊;4`0B-YdG;iRQ+0XQ >Kr@A_pQ$`,W ϊg@+ et%l0":mu0@ϥ\/r~27\;*ƴyE.ƻOo(\CA;3j}8_EVk;Fmoo=6/86Zʠ= REI6r,H"b|sgfio z}x2]"?c!\QhUKȺ4s|N)b tٛ8<踯1we}XW@4 a7oQٮdn{Ϸ+߃йN"R|Vshm5c!~zjn}K2|)<9&`NF-Mbcѝ),%g;9c|L ]]N`;ߑbleK69Δ7 }.A1 :w=9嗟@T} c論l2ʛW `xhQhQ@c5\|Cџzy,+H銝<[}&TYPd娥J تT&[v*+;C'nƺRAӈR߽sJU\vۉ$e4jۛC=~*uku8^0:}ţ ]:NQ=JԺa9V1||%]cmcluGI%oZ]TsIo]ǀU[^7T0hLI`;R)Ra!#?23;ao cԢD j8VM5-Xv8AvWw&c\%yQkP #?ǻV@ug+ϱCGs(V9J6vzKu|v nn?jFN}f=B  `jw>R)?#eV'agY0DYf)4`Pj0@t6<r)Pr3\ΎDdy74u:y5ƷX)Ю,j@{{(O|B# in#JhMn(Hv<91SߛVfNa_vilWYJ^{ΝgaP:@9PEj$.GXw1o\;[o~?u]h{t{y1d{̼Go`%Ѩ'U-"͹XcP;tktǧ;XBJTJWXpCFȖ6-on= W4/j_mTQWf[Ylj0 PAtvI9!u65g)B$d`_S4VHu.aHf A7fzWL(Vٳyi8'EJ(ᕮudzzZ0#:WHςz 3mWPut lCG֊kނh@ݪuZq%^ۛe& P߽ {OERlweHۙm}2-A_ km,gԇH #+Pz z ":]}-+\hV>YɵCJEB6~0\ƅ' 5pTtM¶ , HY,KA VmZQcבMˍfKZ*7_+ٸ>#[p,KV1x95F2bT}`Ru??Xy \ה =j~UEnv0}MwQX9ڬYeo`Lc3T hFm k)%>CRڿ.4̓;:(>j5VVN'46e Wzs{ce X'/PxV-)Ү`1 `ki3jK%i.>+@ʹ%3Vf\ڍ'՟6bPƮHRԖ0n8Ȇis/E!<vGu&7Y۴{W4Fx̋PܦtB8gev,(C?1b p@ݴvu!N`w]Ho\J*Qۿ}Oji+3:vNN4֎EKXu;偢lx`Tl\X b2]^!Z/_I FXFARybq m'Lu0]qnlN yWmΌ ZIŕdڶ,7}LF sP*^ӤH#:;R_P@ddz ͘Wy]}2 ^Tis pCb8 hTs@~W}~(T,lchyW[sN5ߓ..@#:)ua8msUrxd434}yF,7+8[*7|!+rvx1&]s﹩ݍeG(t{juO{Xj4߳L2H_)Swunzkxd;ۑ٣|*JMwcw^Ҏ7|҃ݼ# -2K d>7Y=ȇ'yǵ5ҏَk4i@=.^hAL?]=:!Jv'9-qRm8#_Vq?KDlv[oiga *T{d}v5tm] ՗o KQ%hy?b6LJOVK<ш痛#-lHqY_nUfeZ:+v gׅXr-h ZjPoNg+ lЖ2]ũ(+5# ng55 VXSnLlZZ\F6*J}egT'ZզhSDoweLn@-ʝw6[EmUm1MyԮREͯ(u2|UV( d;y.bb l\Qq4h; xĹ= >1crJC]mW Pf(bI>oA.[p&*@QKUiŎQ܅id;93cTW{cW;T"-a%\[$,mUbC.4O [wmډ8dե34G^&eG[rю)Y<9s;GYa%"'Yh.{7㿩P ށxRHnh߭bpiA8% ZO᠁.6Xu?oe\dFuE!o 8@Б9}4?U\,+$o# sAh|eϢțKZ3,[]%D.Tl'EYc02Uc~R58ǎ'Ȥ 27œ.Q149cxy%Hw52 eϲcȐ2*0LEY~QNM4* +jjn;*De%b91De]!hB yQw?d,\I^Pba֋<0bpce^m9-8`CGx Famoq.+PZ$gn:t蚓{3 -:BݧeTQ*cFTV[f2yȱqiJYtr1}yv_34̜l5teP}HԳ1ik& 1Mwbt߲Mb% ₡;Z$ET&ئ6b[}s^nz>}r:gGJRDk֨;,,-s!OMg&p;*jCMKZ<UP)b*S4ŵcUA$)pjUФ4b'qjo'z+f]B " I!I.^6Z% ɵ9"0]Q+9a LZ+AJdU(.~jˋV.גt֟\U/q}Va?sɞ.T(Om6eXpTfPs@Ĥ_7QT~s#/I b%/뛛iegwQ`MKuwUzwȤ1*2(N7 - mr_<\iGI^R<Mڜ]pU~@g06gb&y IDAT-͂<tI֙ lو#$c*WFPPcXFJr='+DeR,6% %31'aؿT{r4qҦjI]jnۛ5`,nσ[xW:Nmꎺf&xü\;^{SnQR:v [U)EGTQw漢^QiN%f&`BB"U>iBR@a0'F,6ʼnzF1f5C9)%cKq7F9Qw<le^ucSnoE &*tI6Tt>ӇUF=ٛ,^v8euXB">"6Gӱ15n;r:3k~C(z|v(L5xۻr qS@s'S5 jVxEXg8n9lBFZhi (1^dX0ks&kF0 !6/?}|)y Kٓܘ1(-XHQRV9$F^PImm_uh>u40f'|4h۔lkjZb>W.a;xc^|]ġf Y?,}^z=ys/^U;mj\8PێiE&밞UK<HĐَ1™3 snL/*Ky4(aJW jbڐφm9 ZStc*i+_9SpȎpwU&\܅Ts#ɼ<Q/^OyBm4\=U$ grB\V#ˠF Aެ仭Jׁ144%6 sy^A6mqi(;4t~a՛b:x͆y`$ P?ل-dUK<С5sAؿEŀBE<7gcʝ*2^oxT fu?KDHj¦ `SqPSQ\Ni.s"  {iܩ6CÈ'4YY9ߓE)ͮl5ۙ%`7F?@QA9!(/b*ጴJ6 muy@,93[1!W)zc9@+"9{[Idײ y@w#6= _v$؂0S̶6,ͬi}T+3>Ѕmabݓ_w)Ջ]ڈaQ]#Xqa7I4['i጗7w|DJLpMK[c"Rb:l' Rkִe;-!Y 2ݥDeCjO? ^)w8,gG&âh7Hfw'L?x^l2~)2;7Rhmkū_73\|ݮ)#|6wX$MLDϤ m{EﺛE &wòUaB7.+ i}V#O,s_εƙ?=՚˒~*,g0K6 LϰZaL*}DoHѠb 5]}SuMFhwRS8C4e7bg6N|F4BhA ~X>%jEErйFF}N翥0nî+b{m>ݺX_rP8 PY  FHqL(!S= 7|(>P#BAb\Vc7z }huJV_>mr@0E@{!CeMGB;j/fQYRWғA9ätiPAbC{0玧+s2\Ë%:<4dV[3"2Ďn ź?|U @*y2t߀>9~7'Pe| :'&A9]2G}CԒǟU#|νPa^KnI1rqƞf3NX88 BDca5xxtNyȋuC};ZRvړ0>{r16HFӚUrȋxl*_@gkiq\84Ve!<c d9{,ٟ<.43tk+ŤOSV[xPsMj54A1UǺ,،AdO-Y6D|t`7O[\5|i @I8&!Y 螰$Xj> c5_lwYϕc]x4b L_UxܝZXqhV:sgG!3|_ѱqxp%1_0ET!ߏ'%S+pqpM\8gEc‘2aLK>~Z=y0wL108>ٕ$}'!l{MQI!7>:I|7?!pתM)0!b+smZr{Žr0ojqCP["}dH8"3?N\s5,gxQT1  +rt= ׺η? a.>TCxN"g+qR89ClTyHq54v  ^Lkݦ BB$^tX܁bu)vYԨRNI! 5#)A.ruF-9:IVBB0D]ۆ C$לcu+qN;䁡 Uits ciڟA@s)5gI1V+O+ԛqoI;VcǎtIE k f]5C2yj|܃.u2`.g]݇:AS<4a"Uz=C$bw%ȮASu=[Ev,u;xOQfh.ɏ hvH7{NCϺ[>59BEmB>3ؤNڇ$2S0xd,h>O'L:tQjͬ.aiBl-F6g:c 5O!zWCN߷y"/KfvTS2G1@T{D_>&sn wV~Ys)T:(uXfc/s[tW?5"x ]Jvo!8쓺k*[m!iM*p$:sYiO}l@t,UsVzO2hﺈb,oo^}}}(}-z ,O]ꃝjUDp9lmOpXRěD .Yfu8+/iRZzlY'K)nVÆeҲuĚLhR#wVb{Nu o%y,,A19Ϸр|.Ҿ&.` bDhYFx,}ыs{ﰁ(v%719N78Fy볨Pbp84LCQz>t9SPJ>g(fԈ"2%L #~̃KWA`?slwd*#VW R_7ԏ~p֐XϑXs+}XBaN01PRQ2{U.֢XϷgQdA$ŧ!'EAtCo hrGVf *l|Q`q2$20;$V .sQI%x9/3=d0BlS,4(6SjQԑ^|kM fZW,KY4%)fMhp`qzdx_)%ebEAF݂ :Kr^=vZIbw8,GJFFdt 5R.ﳫ>!筟ԏtLjW)旣[*Qғ~;08`iC~vŭeq>/ Mcۿ&z^wyf G!o6 ɟK`2iM>۶۷3I.*;"Mڸ8#|(YWDܧўemD{Ψ ?vn|Zwcx NS*[`ŵw\>du^R#X6FĩA n{6WSsP U=o-ji! S9qDi>Z6W|շρꗶMv琉`),<.6ӿ=Maޔr,8O֛47allP+G4t?Cؑo\ nݏ|d.c Gb[f6Knaˮh lbJCqmՒN?6I[;a5r6fMTTr%#9wׇ,+9 ѡ:`=y:'9 @a}.r^Rv jmm1/!U L)D{蒆SښM]\M)bvջa+탭/(>/e%xY\bUGUSm6$ ZXqv֋Խu^407۔xU)2ZK@lTd-kuUP|W1 ӟE-]"y9%HIKNyjEŐ<"U.ļ-;5YXJ47>CNoj^4쒯чd9mggR#Ss3dŬϚPŬgMË~P>adw$|*x;  łHVZ2 e'!¹Oq'C_fX]ȲpvTLiZ-,M1;V͹Z\q"tv]<EZ]^08J  o:UVa9(=HUƸVqŷ4ۚ mM7$ 1tDR񊟜3-~=^ӽu.sÊgTb!J$3$c v+ vy)`kq iJqMgIxS:C4GSF;e>܋4LD]; 2%"xAՏZVma.w;{.O/KPҭև txԐb5z#HU y+F5@=' ]|(R!ŢƐ>3vE]`॰WZC.Ď "ԻiXr pdh>E{0$5^!Jrę#b4ʂR9Yb].^-ev^~FHRG 4]|W0)1OPБER ^Y1x5KD)0( xsg9Ta%??W=qa$sJGR֦taZo)wo)ŭp̛׈:Ӆ &ƭ6Z!Lo,&n>hurME)Ktt>7[u6]*g?B2oGT@&>Կ3rAϞY^&w ǟ H@rW?8 :_H zP&W"$YJ.]E=c<"vVWWkuze("0o]3O]mC JGW(!Af g{@,~&r_p?4Jb@&b.0\7v!iP?kd[rZG' T8[|h}G:am ~^H :"x̐e+m5hMd"gGTlx O@Ŷ*>!+*Ժ'?E +gYg[!d]"~Z{(r#]JC J"=zn`Njw\в>CR ) O8gIk ە[B x`Z]m΃F+͞I]߾3pRPl^ X(83I#<+,[8'tՄ}8uZH9*Xj~s+?oB^D!qVyrT?&kV*î׮U;oSs4)܈'= f]\CK.=euC -2Z)7S1,.WkdJ A{m=ˆgScvw9rRDo֟C\hGs ?kBZ1qٰ9x! O:iqbN@LefM~.KK=O-Q~Et-R\ EU>BMJfM]R1]474Ȯt_icw| pnJh S5MYM IDATm7mc%&UmC2nul,AmNz /BR2usRXT&bp7&*nRkPŒ☍gl\Uz qJ+GN|3d\ $ YA|~G5tUWF*w,\<$Ju ?`(./go[1sz[xD1ɤ:t{'6XbEgQuwjw=Ǯ% CkBP]LI1P. -ĮJ;ܜGn~L;vI\ur`$]GҌu.$R$.O ]cP|3_Nzf-Ժx̰O=E:qsmԙk>X!{^RZ.ĭw.A߭&e. b}q[jzh"^A <{8il PvdOѾ5b4gwRR{js#յ}\DWN;:/^wcHMT""_uskĬB2UZH5;l~P-!k 'Y* )1Ԭz՞gB=s ~u\SbRZAAgjJht@0ܔw-W w$!Za>J䒠1 PZSp cd/d{tMbTpdFqZ#H(Ul=6snihbLuM9&/SدO9Ĉx( ᡞw"?\B +Oí eI(/l["YSpЊ B=\U2%:^V)e'BؑrA9x=rn#x]N_nB * ɴ\[r?y6juV} {Hhï s$'p•|ӻ $uӧ?{[GJS=dUdQh4PE$ƃX0qS[*!ZCQ$Qf ^S?W+NhK9LK>{]pe{s>A uC=qP#e"clqI-v-[Pve "uei2AT)CŔ45 $e}HJ>w9s|7[){Pp$e@+9L"e]KY L5'&R1 z܉K,"X:mW*ij ^̉C9iդ?zB䀢6'Xot悲3G`e5P)s'Eݕ;Mi9yZ3Y~?flۻ4 ȘBk$0S-٧nuz)w iDAMs,uJ>oIFw"󲞐"ط-,ү#)&oR"24![$?d82vx"Ep%Wj=[#ιL"i:u@DRgOSص >\M%mN4YY]vW[w!}QD91C "DP'Bwv>?6Ɛ*>A*RG+ bP:(׽k͡Ce-RLrpd*8+ANHp❧nEa D%$}^_XpQK8Ѯ9a! Q"pȓ7u꠮cx<G)y)H4<ݬп=j*+AIJ/t-yKrHUP=7k*2}ao#;cPa`9`x\h09"cZD-jڤQե[Jxep#.n{ä3<֧_!yu :FCPCa_K6"ڦqqeRGmC(*T¯o\i:,JA0+.i/OK]cfkV%s] []#m!a!}+7fM[p\=UH'ۋM<~]9R AQ`s6hafdŷ~^K3"2;kHLXF{! C̝ ܌t3yK=*@K]csEOHn%d/&gF_2Ŏ# 9@L; ]z\-lNje\JS<^:@9'=5GFaLCwH2)ĭxf ?amqJX nWdIUWZz><ߟj-"/9Tu;N:xI%HPNvMqa?tfs!Raͣf47q5 B@ox]SڪjƐ +4iyrxK4$P)Ł9N:9t}C[ܑD|a/8U2ĕCZE:ڱF8DFs<\dܲv؝gFpuҺ#|6܀ۡk&KqDRޔgLc"`AnS.&cY?\{jZU 28yarBsCCFgmJϝ.W?7ݽF _]RkO~ޥu@dA/۳-.+]m ZI%_zW&mR#i]׳NJLSz'C S"Z|CHD`לYc5OT'b_" '&E@6-gR]cn4_S\ Ikr12fqe,9NZ,_19kMĻu2,@;z86K1jWy&sw7/Bê7ٜBғ^j^pt1R+(5.y ,ƋɿOy"bAxw׼kh@OJ-i:ª[U#XB! (d &+b}&IJ꼔6 a4-E|dXf¬j~Q5ak3PoS.qf?)|9pUP+nҜMx*Hމ昈Fx)%c}߯q"y$~vkp}IEƧ?^G@h<_;Ϫ;mm p>Oƅt, ʓ@7n,e /[s|QmZL o/uvQ cA@f]׃Ӓt2=TAk1a3U}vtl_eGrHX{%qV:l:_c43 ru>6JVu':TA2Vz˰>Lg$)EڪFlYbkG 1#J$D}bq  / Aҁ" ;M}Oũ<RBW{_(SQSn:r}n P)'곅>M+:0$G6`iCm0WPrWҁ6;ntXPkjG:"Y=N۫G/YÇ]0\TKg*aL`9㝠]е6Q>_68OyMWXU+{qm1@dv5KKQ|s&r J 7Dzć/?}pf#nrIp=J[i!=xQ@yZյFvfR [:< LYL!JS9idqlZ$HCMm7̖L6חx%zԂpTANH!h)SBs6qZҎ?UZr ̭Ʊ[3HD^#$eZi`]]$-_Nz뾈 yw_8j.剬u6UP-$ l0 \#u󵠚-&<5iN[cNbs`KO9z%rXA/:>92j,暇ĸH$n7Ngm7wshf܇wjmQͻ=vwً\9ھ;#vt>d]wc: jQWv@\= PGL.8%~"ȳv_I4(ە.VA:~ɳ߰Nk^#4Y .[ 3*"ըQ 1vg ^lA,< EG0Rp6>,c/#^F>ܹ7x'*NGƈN\ Ѕ"p:#4UN̘OyKj8^>&i?q{z`/`OH"q9^+F%'ѰSW 9^ﻒ\,Ign@wMU8ht\h&Tᨈ _?O\5f!` vwRPսpTOtI;9_xTI ˕AIЧ:~˒K|l4ׇBN27I޷ƏroG=BH,#\q~8H[yLOt9&|/=D.)FsMq嗞;xP!Ϲ8#wM(uQ4LӘCY%|C`[wW> ۟/b+Sz6 k>54|/ZXջ۔)i(sfMRꡨm.6fVgZeX>H",]w='<]wTP%I7$`ս&TڅջZ3jqua׳U$Ɵy"mW2%ֵ܃z88KsVi*SOE{Qj"JfJ.Ǥ u?wxTohTR4GfVEk+=\6a& %9X," G3کAS$;C%d@HNQd#|/4' 95Fs +7XjEa"f.Dl>@fC>}g/r!3Nsw;u[߂S$`_k\5s[h箕j<]D~(|E ۚ\Y Mh}hE 􌳿mHh,SyΫ 偏ؕbk=n=@{b"T{ҁOknUv_==\v<$bF>EZd0LA@96ݼ+:8_{ZrMAmF>CU IDATPwTMU~#tKx) *=LjU7gq) >*4v a@ݐhh߳xγhCj滕rٟ)CSa_V4 t^n \vNBYzi/xR@^2?:L%ţ "yXl9F7X Sxuu5ˣyY։஄xg+ja}ûTLj+O"]'ze~]Z_19!1#&ő@\{Er|ZWG,G$Łv"#գtZ&o9~b&aM_d8.o?}OoOcgSA+\].oiwl[<$FA)2t\)>2a .?Z yt #3 No|>d͝w5螿XQnmȆN+ k+xG,Iࢹ*G?۶˟8[D4նcP^]@bv[4YS!GY eoKͨD ˀg0Dn f++x%?<.GM9ؔN)`2V|i]&>[G|m[} Z,)rqFz]rqe^zQl"} _/*9PQ cֱ]ª:r Qh a6>S+%虼s(ЊEfZ@-X79){엷A}K22З3‚ D `l߱n- /:]`Wod nk]ɚh0T YS=O/˅050ざIGʀ#I`C ~_fQ]l1 э[V-Ndz3jJ UOe?Qviծ^CmI@\,VDBthnQ Q. YUoߛY&KAKT}חi] n]g]mY*eQ;f](R:U:$_XL1bmT{t9޶Zj7nD$PkF{/c J5 wIY2-2s\Ҟ-4Sr,. àgxXx YeV"5$]EIVV-GG.!@.bJ2nT?9 b΍S&j$_4܁^rRf-Ȱy@a bKp ?G H붊0Av6k%_8$#Xal!3sdH\ |Q[TsD' k7MޥY^wV5l1 |{3ڻhjki=T Z7Kļs1oMK^&Wе{]5ij&w %$Y$y~/|ܽE'"$jam.6 q#@׫ M6C[+[-,]mۭKLHo4~2 ! )-2gimmDyau!iN2O# uUm-z $B$G`T= iEcKzwgC v>c[`m9"QȭeA*꯵Vl%)ba`!aiЙrN'b.ϡJb[ xV{ "3"6oP5R@ܓUQLw(FRr5.]z\*kL4Q7f{io.loʽ+i7ڋ{Ԫy͋UCsڶUZ4.NfoA 0xTMB5fهx0ꡬX.<=;Eê*/yjizA0ew/۟dXI +E*,@x҈AG"x"gc)B!R\JeEHM-e?jlo}|7%\4Ӎ_ߤ(g³6ouq?hBւ.t5,,dAdYyBȷB#mN[ʠBAJ) OI" ͻ&"$uD.RJ5 biBmlWS9`Ml{ i2M2xԷ&/fB1\QS/fY[e58/)C.OvJ^)yk_7ٳ ã;դ\-MOָ'󬄍NL.wO8/_f<Rm5A.yoDT!鄥bΏg iSZV&tw~;L=ǂ&Uͱ.)j^*@?clhY>ȐN^x~]6! Q܃{rgPBɂͅG4' ht+`yψt!KJO#;^nRCzt#|T]KOq@}H&ѻVMQT&_Ul2r;GIl}5s, K_]:~5эn.Fa.MWMI!];InyB( b\;EipĚ떮 ?S ]|\)3?ڪo۷01$F-֊~V*0s[ok ~G<󏣑SU-Wf\{ZH=n8z%5T4E~ -g uꢂ@l<Ϣ쁺g\RbP&z:Ns@4Cmn:=۠ s ߯QT_ .w3^KpIק; ^xOaПYy+Y}&"2JT#$HN& i5EpO%9tFaa'_вCW+KGԺHr($xaqx(rjמn>?A.Bɠq)7XSsTr߲< Qv%(R^nTO=<ۥV{䂈ReY:;:bmErvouׁ-{̄8n)v|>7۠_b 9#F6|'||&|p8ƌMQ4 IRƒ{DpV&5 }2,&$11~-ء6MS ņx\TmD,`_*@Ù;@VqZCI%0t|xv wT~)` Zln92L0P8߰b0 B>w^U WS`܌Xykv]UK)pbx^ aq E3^1+`y k]"u=tZm~CI9/||yOGz%za`jQF_A/q4f15bڪIR&Q>5tP:G$_,(FKa$TF#jq +)'p=];f2>B"v~'BVK{qbb؜'To?2y[v#y & 8S#Y84JѴF͟%ɘWGHl4zILo]fuk]e.g:B\&I}q>@nu]2=]"#e_}rp]F?Fr^v帳or6Ճҵ4!CU@CVnͻ4W {cNx f(L4d*=>H1'݂gjOaW*ק\+ْ3yT\%nE8,Fp53 A2s|*AwXQtu/^ʦ2QOeW;JWHr|ucKψ`Q3HQ;9-L5ːyM9ST_oRHp7Y7?f8'9eyٔ~w>#ldGvq-Xw~[,ǫ;olA(Kc_o~?tdw ڰ~I$ }"NpqVVdK]TSj"-݁s}!$,͑ *xHQC&ż6Y7iv峂[e'A5|Īn>L;=T7Uύ>yRӅjcIz)KP-K!1m[ұ24vo"9FԼ{j6T$j*һT#6AgosF<eμ<ڒ=~"/11ׁ3JNiԠ אI@} \I#0onxNҫwWBOY*6\62--u(4Sr,K&un·EL@'6 FD(c=4-Çd EMo|ײx:q{ ܌{-Ӌ ` ,  @yrKT "60bZ!^lp"/=ETq=1<7H !}CO1ECZ7SwgiyRTk=NJxBι*6N?[Eat_|p* ÌYaDԎia9ŷy;Jݗ.7~~MCݒV*63jc۰']DSrJ[sE\Z5IF VS+:5zбNIٻybf|[a\ j9Zzae1 >HrG5#LM .^jEΤ,݃$]2(xGK&{hYĮǔŲ-:fey)lUAxOI$Ssv/gG^:aWR % gO;i;^$VoX|ŅyP_A;&$NyY/WLO)CB*㨠"J|]\i4aj!kYvV.I_\]B͚%.0e_ FG[Qg-M,Bd>e5G n(pXbwbu$,+wa̭;Vtt(ճ+ EOgB2 _lG4cDst;9{GʸkDdII]&PV@4x. GqßjvLAOUl/A.9bhB9:: hZ3^yl[8+,tl)G?l~Sq" L/rɲoی@ ˇaN JǞo'Lf,#Iy 3@@I QStϘi(Ўd1!IEG/ H?|6"g',iUnyuM}%@a=G2,IΏAV&q[>w[Նo k1؝[R(&x?d6#`wvl.MXض~+b)hO8 I`f*ŷ :#G;d]̭"{jw٧ OHrw߲nR,G=8US2oy=Ҙh[Ewot{ y9jA HᐗT%z{(:ﮬm!VzgoV#K;ڤJ=+dbJZ~+g4/zHOs A^$Sh"iG vd-]hM>2X_~~|,17Tjç[r;86N̲ leac v!9TVa3帟FCZjǓƝIa<[ܺ[kAڦ'W=pY4,:X+ȴI&~L].jkY7MҐjP +WhYާ#T6L߶fG0^PlJ LMn$@z(,$癭 IDATs,=> Du wî BhktկNꪾ w'J줻$tKӦ6 Y?F^`I=Pn5P5&%fM7~I$NJy=qpk Ow?AG׼`V*ӜDX/iufߣJN?k )9$H9'g9 TUN4khfLzrl M{ )4"hobJc)9즧᝵h?^jJ 8FQCiP$=O^ .vUGJB.^2 W8Ij[H ֮j#d#9_A{\me7Yiw#V3!gyjx"6QV_:u1>h-# DrrW랺?PҩǀbR3P[4ۉ>hSĤŇ!^"Bb %w]aP68!ouAQ/9Ɵ˥9:-uTOU\LO {l.ˆe ja y:dcC5!)0:A*k93gW4;}ɛN؎ʏ"t+x]$9VN0 :aJQ_Ycrmk7;jpbiN*JŸHw)^ȽE&+<|=tG]}Pf󜩱Iڍ=KRt1B\'[Df*cw3`)NnwKzH٪4m|+ɦ Kt Mc|*an|;6YFbU}P|؊$ &d(Wam M|k5;ݐJSUh?ٟ1 mSJ8XIcܒҌ޸fOFpe3 2S;D |*Ri;LI[ zD;!8f@=`\uQ%>Z)p,tq>P"W رzGk:uuSu"Uz]voy.AL86 3+/u#ٶ*g7WiAo~> )V:Q&aVQāaSǻ3@gW>akgl&pnqt${Bm#y]'A\]~0"AޑN?u`GqgS:_pf9:rB+u<ՈsWK l)r,nzBYЃ4VumI)nOq!݊py:쟯.it&1vGM熽_%R81IbeHW9.]aKOtwTk1[ݚ4]V%${^Y cN.~r;{-;-NtgC?VZZRJ<۠C‹E}X>9:@{:OM՚< 8ZWcm_R*ofՌKR.:dj}؋5nsБi|vY([0EAeD=Utg 7;3᳜ |uxgzggINNϵ5f xyQ i@iw"JF5SlV|ugbɏ]fz/sHQZäQ0+$܍:6Wry8lM\i*v##]!JAb`-i<ʌc٘}1B,cYGto!񕩎PFHs>T6ѸQC6 !Cz`aB_]O߃-ί{b<Dht\X=3.aro|֞WnmDj),#Vֺء0Z:Dw KEbG5w=H_Ŏ6ҵHkk۵\?ܑ`4VGr,3ef)l1/e:GU[aɿGPE ϮXq^|1m?_]kP.u^Rj]knb1@ߢ+Lˣc f)xu%ugVڙS2}E"{F C? 5ScI\}3y "n/;6r!=mԔ|ܽ};$lUk_rv?ϕTWeLI?{b:Lz/?}Z|z~y.dуήJ9Ժ̂ϳ\L"[5<,wq@;^fC.J,Y^@1 X1">?f0 ׬!rL86 mhLv|Dv4:cnXYdV_ IFm A)Lf}jR1O4HKczY-9:1Z\!Kyr"aYUZy' ə,?ͫtMĻvKKS 0:?=yG^ImvH:߼~Z@cJ_#mNGz"NTPg1w#73lkم$UxuhIwf\)?+}|})3RDl '6<&O5$|aZAJMf$. &l>^t\e,Z1\-݇cY:ګtI : F? gIXVyN0]5XRe x9H!Ĕ>6^n ظl7a0XVkC{X_L` $' c܈!P,Ò'_3 +t!xu>Ex/|%>=?dեfEøF?=0.og-PxYpgV ]!k>LoNE<^G&?k4:j&1ViJZ>§vD|'O~Zp NBNB%I@-'eB5'=TˈŔڡ}N>C5b*X|[ qr !k {^I۩}oV&@a-L!5.,=S$\cM-]neju~Y*Mrq͏o7!w6z8Kb,I*z1N?a!ŀ#'bv=}/H- \{_ q,9Bx#"%ΕbJ+}헟|Jb _ /Fϫ<5S?8ʇM \FdI(9e/w$T-r4X!6 u߸ti!9HeTin5>Ӝ B8G҄m5V$GÔ>Ѝ" ńrZ!ذY'2WZ1psqT&Ph$"W̓׳;LD=0#u8n0>g@sV}H"'ylv6yαh zKSPLmnƫxXTcwZdFܦ}?e^Y=yQ9B,14X 8;Ҙu,vͻ^ _]?e! >cuGC/܆LhAڠϧ*4ۜ[ IoO'"xu^#DTd $Xk]4mܙ7Hpx#v Q?ȵN,n p%C~ ="[=gܖ pV/w -]5V>ӛ۵No I΢B|$ݖIvzs#ǶF-؂#86 4]t/g/GvXNթٛ%/."7;Jq>dq 0G?t1 c 14gk 6t\Tc&cC5JLI%K/ڙ6{n.Y,!#Q칤}c }yn]yhtJ %V=lSmq{+IUTಓU0Uk%2b9Tw l.ɤFq<{Ux $c)v@̤M^AV#E.AR@|zWDS>GW+*6{vcoeaMբ7Mڝ9 Heo180qy7$k7:EEMW;5]T-qC# :3:\~i_~3 q2 2ύg9喣,S]9Ըs8P =8R`d%}r){]# fį%Eǡ\CY Q3&zRuGc\}Mil*kꅆe98t$`ح'ꪭ `+ }&R yPˊ.c3=cc[(QYSSz!wYX<j;: ato*:J=ÚI2F%l57,z'X{j@`RPnxRZV/!E C/3"Mp!ru#-һjpneқSˣ!qPq99j{l1GS*0`8ti? bq";l4R.I}RBPqpO4#nxO7̑Hg:lku~)?n]Jha_mPPe-j܍C$Y@ɸJLV/HKJ`91~p+BM5UdҡhuEt s]<3^fvC(-wAzX$^k͓`ó4p88[&[ v_NS΁1̝Mj>Guz@%%As2hL9.\ `9rk*%@=+S:iQ.'#IqX&539 ]dF|@y.8A;6[Ӕ:&-/޴)CNܮF+Wˆ8Ζ[IhOemW/,!N, Ի/ɽR_4{"8*&Ѻٸ{'Dg{6Ij.''RL򼭓@h*wQ$ne))Ѭkͬ]TYQp>ěBp0\)Mx_')>h.q:Ô|!Ѹ*z9tnd:&ݨ:e.GAR9Z)BUӧ!'{/;Iђu-$Mu"Q@L;Lj}uu!=!ࠨs?͓h0To2 GJ@ܙe!L6uݿe9 Ԍ6k[Q<^o_?}uѩ ײHU8jHmbfBjnԚ%i`'p30hXRg=kz D`^a( ?Nl>6coa9 ^:+`>LnX L :}k$k8ȡZd{̇fIW)(X L)tϝdtdu]2,rFٹzjqkL,h5;ӼĽ]m-g}mvsfKP(s)YI!bB Oy<~xA^NFvY_Bϒ-ufC #3 .}Z'{wS2p6Ë;b#Z͜a&RL1}A2Ei7VZP RD;#E.~U‰yT2YJ-o-mE5,@ӣTXи4N@)7*^1}kĀ9P7(&`tF[%ro$8rI8R6Ym1h"b˳͂ӊ&l5lr\mT8g+"Щħ2 ˪RUw(E@zd?֩XAVHOCir;LG:Ar[Y\$nuqYгxO:\21w,S 'sњ{5IDAT9gI,XWBJ3ܷ0b@j i+g(PȨP&TeXhyȽnie #h eq1QM rƫ1r"q}#|cb { UӞt7ބfM oClg&?^ޣ6u:IdNڥ>) Lf'؃cF"Z`&<q.-\HثOL9xgJ]Ҟ32œ2yW}kGH'J"nm'1$Zծ<(KKHz㑌z鳀ĥe"ra媯f:s!3xbcrv*NTpTHV7wL{+*L``HoDBd<4dxáѸHm4P2H B/Q˪ "<'UIFA lF_H70d)EmM+{ؠB,ٱ߷Fjha4Nmnԗb' wKK4ܠ҃F{;w)7z}4å=Ne6 bp}ߴ }٪˽xN]YJ>Q_>E2&, őBIGZPW"P>4.oK1Qla,JlnNύ4Ӷ,^ӀCf-s+I_@$qs#nS~>~PVj=V7{_Hz1wJxf-Ey=QdB<8Y_%10i(r VM1٬8sɃ s>4tP$B ʼ0D@KZ89cMJdPCs2 Ϡ3rŦs5xJdٻhH=ɷ{Z_xnJ9ӽo҄cXM+mP,F?Ό1X=TVq\yH5XD;\HH>!CR<`:>AٽDi36*h>ieyA<(B3 "dACGӿC#P:--*C2ԘyE]DX=u*@{KZp0R,["c"75+wweD6P}Q|or|>ߛ,vO~Vs|&M/J +oGY.d@$X0Lv3ܼV,f?)n_= B0r#E٭H7{g}7$a#u;Qá)cPn(nsd7X?VYT2{\ȵN&#>mωRQ*i1ͻݔk *7cDY-H&F?=ײJ"(^0P}y CPtbݽ^^tA9"7)>7(NC'On~0@Iدu Qx82=G_j@ I$(cxm!>NgD]O ODX0- WK;} 'OkWNL$ٿ8k\M}^Ӑ9ClM>̺Rh93!l% &%FE6"MqexU`Iji ̎aԯy_FǬec H D3ϋ[=!>ã=45Qic7: 'lI>)d:nԢ2|R/c~dC|KaALZwqv/~i (j$`DXגeǾ*?ϧ-qž#L&i.,ٗ f7-0  9^vg:||] 1W緪ϠPJpnV N\:٣owA8FLA<%&CbCXL&:\ Nͣl9/uT㲳Yt(s\4YK/~{=V![w Ruo|G%Sӎ S2hni>2 j[WY}FhUJ t*,n7é Aߠsl0 S*Z3ANE2ܰ_/p1$K}3ȇQF.'/k]`cB&j^zM1\۳"BDݽS o`>3"ϟ@$殛]DW :jGn]U "bc:jYG VB q}'wIi"&>Qޯd^F?z8*נأ@<7'Pn>V7ʘ򪤴-~~l_ P~AZ"L*1>cÐPYEUm헯/뀯c8:4. Kh˓ﭟ2Akx]MRg{lEIH@4B%&<@1_a1p,vC @4H6dxcwRuoa(p0q]򡜣Վf4._7u6&bceO d$[!]#Qnqw`zU|>*[)៹Crq!>">ܡ:ϳ_B]>߾a;Bh2-#Rt ;Xf_Ih$D)y!tijCbN%K\,K9@(ZMf "J3% Eݍ"uzQ^lXP= a<2I2p%x<ۛ Md^bl\"Q]W.ѱ{ 0W٬L,:Zu-W6>[==z íЋ;?d=^4,wVZ%f('Qiݠ'FZWޙgmZlNM3}^ c7w0ީv&UY%m?5`)֚Vom)ugXӔez>GšoX3,CX%;gX;L;W5ӬEC.ޘl 87҉]و 0 t:IP cS%/}Ϸٚ"S38ӆ{=v\?FRԗM{M/@09=KCY Č&y^1 g1diͧVE >'fRtR D.**y ̂le pba$XmHErn14}6ˮX< 3J9>]ƚaR̉?]ȳ~9?`{!רXz.8xf1DEDRڹD%B- rTဪj9 j;mkdDjT0ȳe#0(jP/mZux2碳2R0c<)9)n;12dӵOG|^nt]ke iZY*y| *7q쇙-pFKdGb>OVjDHLd"ef$Tb  :!o6>~m[MbqYO EQ7pN5*$jgZʛw9DX .rO6мg Ceg@l~(- g#@xVͩ g]<Ի?dž:IENDB`chessx-1.0.0/data/images/new_game.png000644 001750 001750 00000026557 12155114763 020303 0ustar00niklasniklas000000 000000 PNG  IHDR>a CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs  tIME5j IDATx}wxTU&6@A)IX2e׵d흨,(ײD]X@E%%uXu%!$)$2'e{{>9G:/ HP J A $(%@HP $v1b|Ǔ :#HgL|Q_W\v~4E[*3(|\{ $Bh4|棹\kjL#>v9fF-. ]S??{x0Hr1_y~LH5O#$RQ&>)Y)1CGr2g,[Mu ElK}$WJVJE$R:c8ZG aj!1'9uԩyI.ԔW{OyܣcRu)=RovϓG 8ZJT@e "@P.Z<)s}FEgt9u⻯@DA@eTV ͓#_2ijr_љ RT@$ћQ"8'VV#`<2wƃw2j5B7j!{ˏM9>瑕g_zNuC!xoFl_ c #9RAj4~=~״8ClJ?eluX@!rn1N^u۟ }r]93QK}*SCa  @z@oopF+^8!s@1W3 ;ba5!ZNyq0Xv'% $^MRBhddD 96?Y)'$/-+=·n#6tC&.pCmUU(Juw_yKe ݳ{#q4&a؈yI(UfpHBrb{:@Pb9#1, )-:ފM?k7;n$(F)Vd[ٕvzA̾=,] @-ڄwp[qq "HMOުZo&aZy4 R0j ZSҡAC-e([ i MRaLWM'G )[~ +16ɁpCc^/e0 LPۘСa%*txHSC2d$rATwC3uMzaTDKx3cc N=̩qढ़9إXұQy|>:'O|ou#pwO̢.eN5jMjJKN6'B$y[ϥ ydgœ'g۪$ ڝ{s(=U`@t!]`}!Ŗm}5e` L1_M T z7 w ^vH' ҹj~*oįRڏzdu "x3;s!x1spCp8 ټsVX4TY]\6kcܔK8+y΀b?6me߮6?k]j=x/EY*0EH$k`;N_4q68y[g~DGn2._GE͞}vwe,[_B CUUI =BF\M p v݌~(z@g*6m5юu[g^WVqG;4  ^ `h_~>94drى^X !(ثk B\ks s9ضjS7 /:Ϗ9|<# h!u,t#g!f2a:E!˅55k xWpM5%a쏬fohyP[cf̨OP-ZۯE0-΢, MB>S >ahZϰfX+BmP6Lg1]U00py MG_ȾԚpa0h : ^0-`WQ%>Y0434ʦbZT3o{ } zz2ZSaq仑yRw6vG\, AI'!L0To 8v4.025#G7b fQ}'4ػ AǞLpK +z0 !_?bDC4P'44&k M<9cJ*4^Jxۼ9wn H-[\g w;M qĻqp \*l5&3ny.͜|Qw{*qUL@|*V6p@IOq`U ! 6^V@(HY;7%sm^:&%}uE|szVoسk>y-Tu[w8M >h󫘄+pF ϠvnAv'ZKg'E 3 ,|" 0]'D0U7C-˾P$2]C4PО wBj9 H +DѿBeF9+ 5C?ʲ$ θ405 LSqB9!Y\23d]ufןYN='B$qÕsłe_´$F%܉hsI *K?b~ ]{!Sp^{m6 ƾ{+ I n_ǩ"QAݺԤd3g]/{Q зB#Eo߻ @)ɣ?˺̾ k%weS]F0,+􇿠b6Ӳm gFz¨sCnܲq[ ;VU _Ȟ*ro^fፓƥP?L9}g ;ғӰ$GPHLÜ` #]`صT4KCf.Dn6NȄQ:s+F8YP咻,K-V=7✫~Vݎwġs,Y֌,5"!PTͽrW$oYrtӰA.._^6UU4af%n2ܭ@Hi0 FƜ`c1Ȟ4%yh p'GD 1nW}8 JKU}j "P>-? 07}򍧘(e*ZN$.ZI=3p1g6V%ض{2ƉU_>ؐK*q7cuBv) `,q3TK.]0FT X@y *T\WVf\6T^ "3́?s\oEK 5@mlƿWn^$c6vVd5y;f7*Js_ ȃL_]&~JLgM*<\%MdpݯWV7BE0K_So(kW?&^o~]RҶY޻o/y!zU\gatR$hުhu}0*V%5Y}pͪ, *K\*nݗHHֆ;  ͘pnFLMxs ~Qڇ v Ľ0]G#,*X!%%v<9UWI8 $GrL[0݈0b8 zK9c `fLk:I?okTaw '`"xGڹ](]pEu7B{S3:GlJn,3kaST[:$ &!YAʵk 4v툹A)) iFWφ8%o=o8@89eC)Pe+C~iucF4 o40pb`kK͙nT揗 'Tkd(ڸbWOb_AQ,De̖Z n'&`qW|T>V>5O~^PLuǣoŝNCto*KX%:F_=X Hk@e~ÈVT=oҲ{38!@LKø31vxI)-V`󑩺kza[xgm: }bm6iUI].xPx}04z0xe|=|,QySL7Qɍ=iQF8 # ^\{t` .{+5!g/! 1%{Ò0|QTxQ@t\3f7P@ uqo|*J v|yn^8_}]sGkW8Gj"p)~#.4 rC g7<`켩T$N/&~э阖~U 9a`wcyGWÓeX9Λt9XfLY@G"*׷mGEσ1 sf%_tiwAgOHqcHIqJibuxLe+0ӧ'3!υ<@$o^]d2X4_fži۱J&ᨵXmNhW 7v1)5D+ܸEd_d ƁGb?#ܘžGwAJMD5xp,qi;J7|V:GXJꪞNJۼzt%=w(WUO7݈D-].Vcoxk@0U}֡-c!f4 &nWؠ[o-B cp߅L??-Dskz04^8 |^~やߨ@o۶b2F恅TPLŭ>tt~i }pڄ"e &ᛙ&6Yx|?\q d_)>h_[58|mZ_0b3Xw?+f-}+Ϊ|^ai)N2F0*|yM~0Ѹ p߅7Ǯ38Ԛ[<)2DrL[ nD,|mN_4bI_RX1k3hk@[%e{,7b1'k.I zwٓ9 .RA$U*nkB_4bL@3r \<+bf<*ĩ*7]]}WJNGꍸ-8URcۄiL0g7CoD\3G&T̜tIB-**;'4=KEo/uBÄ*MVaHMH#*T> enLvΞƼ͞ e(Bx[Ĉ8QwVU_ג-X^QVU`r83CyLMN6uTah!(u oV; NIfw=bp~5D;l.X ~xPYƜ;BTñQq1̏7`.A;EᕁrZ ʲI>:E8W t z zR vDE~ alVM 4S)uy8gy\`ٔh*||.<ϣn'Taٻ2b20 Bh)c?PVݦO fiޓ(>Tk&ȢscƷU?&GƤ9d hl@XQ뵏\UUE@ VϴKXPX<Q j;N>FxaF~#C_3i惖LF̜tRSގe5 9nsj͔;oo m>o: xXˎ vFC=t8@ɽ9gI[tTB?z{ 夌\BDL<i3^ P"6z (Y]̧L*j>b ՊLF!b>`cxCR7d@!ٽ2(Oi9QxxSkM v|Nm^goBZV\=‰2#IDAT'pF|џ+%[dSڶ+yLXٯYvр\POML.3?ש-m,hSڞ,JxbWa ZrEB~" 5L݄ۧY1N05F}G^O}p})ٶ-I:)mBٸL9A?來"6`]R!G+3py$eb#P3zmiL"48\R[15_߱;γPzt&5e*Ȏ&P ~>My @K +@ .9vwOl_P/5yP҃$wBdO$$Q !3yeTDM{ !4Qb (35/36QQnоrm >5?t9PB9}V/T92*}'_{bi4}9R*F!Kx[[X: *dYM\BU@)rN}M{* 8 rKK4,*a!w+/8_W&:!`(P q;HP' J A $(%@HP J A $(%YU{ u6IENDB`chessx-1.0.0/data/images/arrow_none.png000644 001750 001750 00000014271 12103305243 020644 0ustar00niklasniklas000000 000000 PNG  IHDR((miCCPICC ProfileX XuXUͷOrN:tsQ E))E)Q)A$ DABB{sw~kϞwfY/,0 !Q$#]'gNԊp++sR%?>D +䶗w$1/NDa'3"x= ~=cgT$@ވyb~H;`BBG&G"$$l!X?ߦ>g,ȓȋ"Ã=YG#p!5Edr#sK4}L8cҵLmlGAaf^-ډzl_ol#clqzz$7 6ox~?CŗdxE 04k'Ã?} EσOz{-|b:~ţz PȿHdjC_c<huE6~BѤC]0`\I :X; @G@mh  !H($z +| ϐУp8KQEIbRR҅2,e CʷTTRT&TT'JƨQQ RPQQPߡ^!ѣ9ASBsffV֒66vG'Dg@MLWAnEOGO?E_IK `ȐpaaQс14IɄ))9&3's:s=: ;6KMg,<AY[X߰جَ]be[dg`Wg'g798l8qTp qrrqqsq>\b jZȣSók{wwOϞ/&~ /7@@KA2AA }BBBiB-B,&qu¯E(ED"DE&D*AEbbb%b#ⰸxEQ DDĤ$ddTT7ii}ҿeee*e^ɚ&ɶ.ˉJ&) OʷPWQ0HhحDRWZPPP.UTaPRRyQU=z_ZZwuI Z|TԸ1ɣyYsZWS\659Q@:tetIMzjz:QFto uc͌OpMjLLMQٚ73'Y  =b ,M,s-X [EXݳZ[YX鳥u]ӵ˶{e/bm@P8$tiЙ9reC]]S]>{ߍ-;GǶg窗WQx[;{G'gW7wO/o_˿1@/8Gq`YzePUnc|GPРО0ذp%Z$y859 EDDhƔlq8r'664vsqqWu'9~tDI'?&%T'$$$iVnQi}mhX׸ g>>5:9==5"ŏ1/^%ƼxC-wnN+M?џzo,qˇ?Q~*㞫`ZLJȷ߇> ]Za]{jZzF/_}s[Gqۅ;;m~ $y9 ` Jg@9#sȩ2(&Fk_#!נ(Ch>ya$2Ͱxeh&.s (  뉨*sIJ%ץ_ v5W((&)+V1VUTRǪ;0ѩYUmckgoogvEӖ)VO$۞KOvHrLt:|%Pk7owgW41OoǁA/gCCQt$H(hGVm>6|u&-'_2O G*KitB:c's-3ٯM3;7?Z0rI@➒[/55^n^bv 5LuRUot_CR㑦c'Z[例˼쎜=n5=n7`}IpH{Mc'.ʃCO kh>370{ffnC\_q{{˴{Y4~}|i`ax!EP߾|Xqk|gjZzІ/M-m߬X Ǎ!;MLDcK^s%+ [5Ww^>wBwDĚě$$oJK_,_pA1G)CJ*IW倅>.>!1 )9A%lkmeimmiyۡ߹rx9{gߜ|BB|\\|5I%crPlc[hڟ0؟s^rCJUjiڹ)A,蜕>q!2,*;~-)X:}CW*+_}Rn?ieӻٖw-[jzzzFÍGk}W |:ɧّ駯GLJ'?~~iE˲Wߤ=.roɬŹ[K.F|uf]a2 O*aN "oᶱ;ߨ]hU7`䠗Y` TXQ` `I ߏ@A\H)41 iHFY `|b!=$C ҠP Zia9(4ӅPH.GHb1X ! sSdd!܈"b҇rʌZFV. =4C(osLLWXrXX_%q9+/\'#,d /𔔐ܐz,]$"/))Z-r"<\ .jTi6jhO,ꡑlhcjiRk:dÂ%ɪzҖ>㚳|7]#Ƴk['wП9/-6$8t \"l>9۽K'o1hws0ə0p.CQgP}hZŐcl09"6;½ dd2Rry,' GTTe%44崢tt#nN00V022XjY-XWJ W8pZqraM])fB BDċ%p']($#*S~TARr QUI逋VvNn^iYmh+9ka{).Cq[=T=OxzS Ƅ g$=>z1 '㧶RN`ˬ=qv\HYnMY¢beW*IV-ݐ߸Ӑݬ|wݨGj]ꆧF Zb'_,|=]ς͗ԯ7UƯ=ES?b@Q̀F,(i!bD Ma,[$WP(T!jA4 :&ӏǺco`wpVmYAp<|ŒQ> ȩ6cWhhht e  mfkYYXϰɳbOxřƥnj˯KŒH~_! &-&!!(%,)="sM6AM^SA@F `TӲIѭ՟33k1>Hanb]nҎ!3ˡC\߻{"]o;?]!|m+z1'Of&R%%sԦp\;s>[HNd[~υ"g/CW*RW1WmQuKNlݶ{7TuTw~;7?{0; W.o25LD9/Yg['?7օ~9me+/=DȏowwW}*ݩ@t9ci(E fY QZ!tIDATX q0MAJop'v.!9r;H:%$ЃC4,VPt]Zr{Z2ZwPE Y֢ Ox&\4ͻ RUU7}T= gpߦ r@6Q +nN, 8# ؎bhHȆy~2~bI1].z<#2fH0:q.$b1+Kw"ɶq'ƶw6<D@$]7. !R Gi 0`HoԐSBNL9 p*$+r6RzgP)0 b@04t}'] (v v> 8~> EwpdW\' 0+mf\Ϯb⽸ůS @:7L΍~u)BzIENDB`chessx-1.0.0/data/images/FlagPoland.png000644 001750 001750 00000000230 12153133357 020502 0ustar00niklasniklas000000 000000 PNG  IHDR(ClebKGDMIDATH10P> Sx+D2!WAT?vX12222=v7|ug02222z.$AIENDB`chessx-1.0.0/src/resource.h000644 001750 001750 00000000623 12223260306 016375 0ustar00niklasniklas000000 000000 //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by chessx.rc // // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 101 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1000 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif chessx-1.0.0/data/images/folder_new.png000644 001750 001750 00000004642 12077036777 020647 0ustar00niklasniklas000000 000000 PNG  IHDR2iCCPICC Profile(UoT?o\?US[IB*unS6mUo xB ISA$=t@hpS]Ƹ9w>5@WI`]5;V! A'@{N\..ƅG_!7suV$BlW=}i; F)A<.&Xax,38S(b׵*%31l #O-zQvaXOP5o6Zz&⻏^wkI/#&\%x/@{7S މjPh͔&mry>k7=ߪB#@fs_{덱п0-LZ~%Gpˈ{YXf^+_s-T>D@קƸ-9!r[2]3BcnCs?>*ԮeD|%4` :X2 pQSLPRaeyqĘ י5Fit )CdL$o$rpӶb>4+̹F_{Яki+x.+B.{L<۩ =UHcnf<>F ^e||pyv%b:iX'%8Iߔ? rw[vITVQN^dpYI"|#\cz[2M^S0[zIJ/HHȟ- Ic www.inkscape.org 4IDAT8ohu?Ͻwݼkؘ7A AzEb.eaB 䊐LAa҈ᚦaj⬦w9vϟŦR|΋s8LJ~[I2dוD~>J >ҌÉGG+<ǔI&눪b%ˣ7ˏKiU"X$!8CY0~D"2SDEgb`}̅ ZnJgdjxkk`xySXrq{zNSP_{f))Zm8{WtK4gК**iC dEo-Vz:2ZK; {et~c Ff(C1t jوꢫOt^=i9OX[61+rNb ǑQd8N]l@}jh˪ꊈnnTGxHwONM-{<kTSR}hѱΑӧIM6lTK,)` RQHML A+qt?5pvG'7GιK_wRƢ1ffB$Q=w'_[?c" "T(*_S`^giP\Y6,Y ~; zm m*"I`ɀg BX m 0\u 78qmA^|`/w\#Q| zUu,kGc?|(!P;)؄D~{j5IxC5z3 PpceE-Ѳ"{k)QkHvDs. 8 cl<; e81b÷6tnQ_ buWQ*E}٥&P 2C44`P bS;oN.z3όIIENDB`chessx-1.0.0/src/gui/colorlist.cpp000644 001750 001750 00000006116 12223260306 017702 0ustar00niklasniklas000000 000000 /*************************************************************************** colorlisti - QListWidget item to edit colors ------------------- copyright : (C) 2007 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "colorlist.h" #include #include #include #include #include #include ColorList::ColorList(QWidget* parent) : QListWidget(parent) { } ColorList::~ColorList() {} void ColorList::addItem(const QString& text, const QColor& color) { QListWidgetItem* item = new QListWidgetItem(this); item->setText(text); if(count() == 1) { setIconSize(QSize(100, sizeHintForRow(0) - 4)); } setItemColor(item, color); } void ColorList::editItemColor(QListWidgetItem* item) { if(!item) { return; } QColor col = QColorDialog::getColor(color(item)); if(col.isValid()) { setItemColor(item, col); } } void ColorList::mousePressEvent(QMouseEvent* event) { QListWidgetItem* item = itemAt(event->pos()); if(event->button() != Qt::LeftButton || item == 0) { event->ignore(); } else if(item == currentItem()) { editItemColor(item); } else { setCurrentItem(item); } } void ColorList::keyPressEvent(QKeyEvent* event) { #ifdef Q_WS_MAC if(event->key() == Qt::Key_0 && event->modifiers() == Qt::Key_Control) #else if(event->key() == Qt::Key_Return) #endif editItemColor(currentItem()); else { QListWidget::keyPressEvent(event); } } void ColorList::setItemColor(QListWidgetItem* item, const QColor& color) { QPixmap pix(iconSize()); pix.fill(Qt::transparent); QPainter painter(&pix); painter.setBrush(palette().color(QPalette::Background)); painter.setPen(palette().color(QPalette::Text)); painter.setBrush(color); painter.drawRect(0, 0, 99, iconSize().height() - 1); QIcon icon; icon.addPixmap(pix, QIcon::Normal); icon.addPixmap(pix, QIcon::Selected); icon.addPixmap(pix, QIcon::Active); item->setIcon(icon); item->setData(Qt::UserRole, QVariant::fromValue(color)); } QColor ColorList::color(QListWidgetItem* item) const { return item->data(Qt::UserRole).value(); } QColor ColorList::color(int index) const { return item(index)->data(Qt::UserRole).value(); } chessx-1.0.0/src/database/engineoptiondata.cpp000644 001750 001750 00000001141 12223260306 022171 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "engineoptiondata.h" EngineOptionData::EngineOptionData() { } EngineOptionData* EngineOptionData::FindInList(QString name, QList& list) { QList::iterator it = list.begin(); while(it != list.end()) { if((*it).m_name == name) { return &(*it); } ++it; } return 0; } chessx-1.0.0/src/gui/quicksearch.cpp000644 001750 001750 00000004254 12223260306 020173 0ustar00niklasniklas000000 000000 /*************************************************************************** quicksearch.cpp - Quick Tag search dialog ------------------- begin : Sun 6 May 2007 copyright : (C) 2007 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "quicksearch.h" #include "search.h" #include #include QuickSearchDialog::QuickSearchDialog(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f) { ui.setupUi(this); connect(ui.okButton, SIGNAL(clicked()), SLOT(accept())); connect(ui.cancelButton, SIGNAL(clicked()), SLOT(reject())); ui.modeCombo->addItem(tr("Find in current filter"), Search::And); ui.modeCombo->addItem(tr("Search whole database"), Search::NullOperator); ui.modeCombo->addItem(tr("Add to current filter"), Search::Or); } QuickSearchDialog::~QuickSearchDialog() {} void QuickSearchDialog::setTag(int tag) { ui.tagCombo->setCurrentIndex(tag); } int QuickSearchDialog::tag() const { return ui.tagCombo->currentIndex(); } QString QuickSearchDialog::value() const { return ui.valueEdit->text(); } int QuickSearchDialog::exec() { ui.valueEdit->setFocus(); return QDialog::exec(); } int QuickSearchDialog::mode() const { if(ui.modeCombo->currentIndex() == -1) { return 0; } return ui.modeCombo->itemData(ui.modeCombo->currentIndex()).toInt(); } void QuickSearchDialog::setMode(int index) { ui.modeCombo->setCurrentIndex(index); } chessx-1.0.0/src/database/filter.h000644 001750 001750 00000010147 12223260306 017601 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005 Ejner Borgbjerg * * (C) 2006 William Hoggarth * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __FILTER_H__ #define __FILTER_H__ #include #include #include "common.h" #include "search.h" #include "query.h" #include "tristatetree.h" class Database; /** @ingroup Database The Filter class represents a set of games. It is always associated with some Database object. On creation it has the same size as database, but it is not automatically resized when database size changes. */ class Filter { public: /** Possible operations on filter. */ enum Operator {And, Or, Xor, Minus}; /** Construct filter of given size. Add all games to the filter. */ Filter(Database* database); /** Construct filter from another filter. */ Filter(const Filter& filter); /** Assignment operator. */ Filter& operator=(const Filter& filter); /** Destructor. */ ~Filter(); /** @return a pointer to the database on which the filter is. */ Database* database(); /** Add or remove game @p game . Does nothing if the game is not in filter. */ void set(int game, int value); /** Set all games in the filter to the same value. */ void setAll(int value); /** @return true if the game is in the filter. */ bool contains(int game) const; /** @return the ply at which the game in the filter is. Zero if game is not in filter */ int gamePosition(int game) const; /** @return number of games in the filter. */ int count() const; /** @return the size of the filter. */ int size() const; /** @return next game in the filter or @p -1 if there is none. */ int nextGame(int current) const; /** @return previous game in the filter or @p -1 if there is none. */ int previousGame(int current) const; /** @return @p index in filter of game with database index @p number. */ int gameToIndex(int number); /** @return database index of @p number game from filter or @p -1 if the game is not in filter. */ int indexToGame(int number); /** Resize the filter to the specified size, keeping current content. If the filter is increased, added game will be initialized to @p includeNew (by default - not in filter). */ void resize(int newsize, bool includeNew = 0); /** Reverse the filter (complement set). */ void reverse(); /** Join filter with another filter, using one of possible operators @p op . Does nothing if filters have different sizes. */ void join(const Filter& filter, Operator op); /** Executes search 'search' on database m_database, and sets this filter to contain the results. */ void executeSearch(Search& search); /** Executes search 'search' on database m_database, and modifies this filter with the results. */ void executeSearch(Search& search, Search::Operator searchOperator); /** Executes query 'query' on database m_database, and sets this filter to contain the results. */ void executeQuery(Query& query); /** Returns the number of games searched during the previous search */ int gamesSearched() const; /** Returns the time taken for the previous search in milliseconds */ int searchTime() const; protected: QVector intVector() const; int m_count; QVector* m_vector; QPair m_cache; Database* m_database; TriStateTree m_triStateTree; /* Search statistics variables */ int m_gamesSearched; int m_searchTime; }; #endif chessx-1.0.0/src/database/board.h000644 001750 001750 00000011163 12223260306 017402 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005 Kamil Przybyla * * (C) 2005-2006 William Hoggarth * * (C) 2005-2006 Marius Roets * * (C) 2005-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __BOARD_H__ #define __BOARD_H__ #include "move.h" #include "movelist.h" #include "common.h" #include "rand64.h" #include "bitboard.h" #include #include #define COMPILED_GUESS_FILE_ID ((quint32)0xCD5CBD03U) /** @ingroup Core Track a chess game, and calculate a hash for each position. This hash can be used by other parts of ChessX to do position searches etc. This class is actually only responsible for calculating a hash for each position; it derives from BitBoard to provide all other functionality. Only operations that affect the hash values are implemented here, for everything else the derived methods are used. */ class Board : public BitBoard { public: /** Empty constructor. Creates empty board with no pieces. */ Board(); Board(QString); /** Resets board, restoring startup position */ void setStandardPosition(); /** Sets position from FEN, returns true if FEN was loaded */ bool fromFen(const QString& fen); /** Clear board of all pieces and other state */ void clear(); /** Sets side to move - mostly useful when setting position */ void setToMove(Color c); /** Change side to move to opposite of current value */ void swapToMove() { setToMove(oppositeColor(toMove())); }; /** Sets a piece on the given square **/ void setAt(Square s, Piece p); /** Remove a piece from a given square **/ void removeFrom(Square s); /** Make standard move. */ inline bool doMove(const Move& m) { return doIt(m, false); } /** Undo standard move (no captures). */ inline void undoMove(const Move& m) { doIt(m, true); } /** Return a suggested move associated with given square based on ECO data */ bool ecoMove(const Square square, int* from = 0, int* to = 0) const; /** Load the guess-the-move ECO hash data which is used by ecoMove() method */ static bool loadEcoFile(const QString& ecoFile); /** Return a hash based on current and a given square number */ quint64 getHashPlusSquare(const Square square) const; /** Return hash value associated with current board position */ quint64 getHashValue() const; /** Compare one board to another for equality, based on hash values */ bool operator == (const Board& b) const { return m_hashValue == b.getHashValue(); } /** Compare one board to another for differences, based on hash values */ bool operator != (const Board& b) const { return m_hashValue != b.getHashValue(); } /** Sets the squareAnnotation*/ void setSquareAnnotation(QString squareAnnotation) { m_squareAnnotation = squareAnnotation; } /** Gets the square annotation*/ QString squareAnnotation() { return m_squareAnnotation; } /** Sets the arrowAnnotation*/ void setArrowAnnotation(QString arrowAnnotation) { m_arrowAnnotation = arrowAnnotation; } /** Gets the square annotation*/ QString arrowAnnotation() { return m_arrowAnnotation; } private: quint64 m_hashValue; QString m_squareAnnotation; QString m_arrowAnnotation; /** Play (or undo) move on board and calculate hash value for new position */ bool doIt(const Move& m, bool undo); /** recalculate hash completely */ void createHash(); /** Adjust hash value based on piece sitting on given square */ void hashPiece(Square s, Piece p); /** Adjust hash value based on which side is to move */ void hashToMove(); /** Adjust hash value based on the current en passant square */ void hashEpSquare(); /** Adjust hash value based on the castling rights each side has */ void hashCastlingRights(CastlingRights oldCastlingRights); }; extern const Board standardStartBoard; #endif chessx-1.0.0/src/quazip/.obj/000755 001750 001750 00000000000 12234251015 016534 5ustar00niklasniklas000000 000000 chessx-1.0.0/data/images/back.png000644 001750 001750 00000001617 10622422464 017404 0ustar00niklasniklas000000 000000 PNG  IHDR szzgAMAOX2tEXtSoftwareAdobe ImageReadyqe<!IDATX[HSq%>t.) QFDz L vv6 BzAԃՋ%t#PR&y)'2Sihyp>įѡS6O;4r68;3 S(/Er/].v'ֻ#!cQXR4<3lxv*A6xT`lLl 'é& Ko\}^CqE&+2? f~ =+0/*u YeAs˽o"X̏_O[:0RnmF֬J`^{ +pJ%&6pM`HeJg\> magicNumber; if(magicNumber != 0xCD5CBD01U) { if((magicNumber & 0xFFFFFF) != 0xCD5CBD00) { qWarning("Incorrect magic number for Spellchecker file."); } else { qWarning("Spellchecker file format newer than this program version"); } return false; } stream.setVersion(5); //QDataStream::Qt_3_1 //remove any existing rules clear(); //read in data for(int ruleType = 0; ruleType < RuleTypeCount; ruleType++) { for(int spellingType = 0; spellingType < SpellingTypeCount; spellingType++) { stream >> m_maps[ruleType][spellingType]; } } //check for errors file.close(); if(file.error() == QFile::NoError) { return true; } else { clear(); return false; } } bool Spellchecker::save(const QString& filename) { //rename the file as a back up QFile file(filename); bool newFile = !file.exists(); if(!newFile) { QDir dir; dir.rename(filename, filename + "~"); } //open new file and initialise stream file.open(QIODevice::WriteOnly); QDataStream stream(&file); stream.setVersion(5); //QDataStream::Qt_3_1 //write out data stream << (quint32)0xCD5CBD01U; for(int ruleType = 0; ruleType < RuleTypeCount; ruleType++) { for(int spellingType = 0; spellingType < SpellingTypeCount; spellingType++) { stream << m_maps[ruleType][spellingType]; } } //if successful remove backup, otherwise restore it file.close(); if(file.error() == QFile::NoError) { if(!newFile) { QDir dir; dir.remove(filename + "~"); } return true; } else { QDir dir; dir.remove(filename); if(!newFile) { dir.rename(filename + "~", filename); } return false; } } bool Spellchecker::import(const QString& filename) { //initialise stream QFile file(filename); if(!file.open(QIODevice::ReadOnly)) { return false; } QTextStream stream(&file); //import rules bool imported = true; imported &= importSection(stream, "PLAYER", Player); imported &= importSection(stream, "SITE", Site); imported &= importSection(stream, "EVENT", Event); imported &= importSection(stream, "ROUND", Round); file.close(); return imported; } QString Spellchecker::correct(const QString& string, SpellingType spellingType) const { QString corrected = string; //apply substitution rules first QMap::const_iterator iterator; //prefixes for(iterator = m_maps[Prefix][spellingType].constBegin(); iterator != m_maps[Prefix][spellingType].constEnd(); iterator++) { if(corrected.startsWith(iterator.key())) { corrected.replace(0, iterator.key().length(), iterator.value()); break; } } //infixes for(iterator = m_maps[Infix][spellingType].constBegin(); iterator != m_maps[Infix][spellingType].constEnd(); iterator++) { corrected.replace(iterator.key(), iterator.value()); } //suffixes for(iterator = m_maps[Suffix][spellingType].constBegin(); iterator != m_maps[Suffix][spellingType].constEnd(); iterator++) { if(corrected.endsWith(iterator.key())) { corrected.replace(corrected.lastIndexOf(iterator.key()), iterator.key().length(), iterator.value()); break; } } //look for literal match QString standardised = standardise(corrected, spellingType); QString literalMatch = m_maps[Literal][spellingType][standardised]; if(literalMatch != "") { //found, return return literalMatch; } else { //if player name, try rearranging the name if(spellingType == Player) { standardised = standardise(corrected.section(' ', -1) + corrected.section(' ', 0, -2), spellingType); literalMatch = m_maps[Literal][spellingType][standardised]; if(literalMatch != "") { //found, return return literalMatch; } } } return corrected; } QStringList Spellchecker::findSpellings(const QString& correct, RuleType ruleType, SpellingType spellingType) const { //iterate through map looking for matches QStringList spellingList; QMap::const_iterator iterator; for(iterator = m_maps[ruleType][spellingType].constBegin(); iterator != m_maps[ruleType][spellingType].constEnd(); iterator++) { if(iterator.value() == correct) { spellingList << iterator.key(); } } return spellingList; } void Spellchecker::addRule(const QString incorrect, const QString& correct, RuleType ruleType, SpellingType spellingType) { QString standardised = incorrect; if(ruleType == Literal) { standardised = standardise(standardised, spellingType); } m_maps[ruleType][spellingType].insert(standardised, correct); } bool Spellchecker::removeRule(const QString& incorrect, RuleType ruleType, SpellingType spellingType) { QString standardised = standardise(incorrect, spellingType); bool removed = m_maps[ruleType][spellingType].contains(standardised); m_maps[ruleType][spellingType].remove(standardised); return removed; } int Spellchecker::count() const { int count = 0; for(int ruleType = 0; ruleType < RuleTypeCount; ruleType++) { for(int spellingType = 0; spellingType < SpellingTypeCount; spellingType++) { count += m_maps[ruleType][spellingType].count(); } } return count; } void Spellchecker::clear() { for(int ruleType = 0; ruleType < RuleTypeCount; ruleType++) { for(int spellingType = 0; spellingType < SpellingTypeCount; spellingType++) { m_maps[ruleType][spellingType].clear(); } } } bool Spellchecker::importSection(QTextStream& stream, const QString& section, SpellingType spellingType) { //locate section QString line; while(true) { if(stream.atEnd()) { return false; } line = stream.readLine(); if(line.startsWith("@" + section)) { //section found, exit loop break; } } //add rules in section int lineNo = 0; QString incorrect = ""; QString correct = ""; while(!stream.atEnd()) { line = stream.readLine(); line = line.trimmed(); lineNo++; if(line.length() == 0) { //empty line, ignore continue; } if(line == "### END OF " + section + " SECTION") { //end of section, finish break; } if(line.at(0) == '#') { //comment, ignore line continue; } if(line.at(0) == '%') { if(line.startsWith("%Prefix")) { //prefix rule incorrect = line.section("\"", 1, 1); correct = line.section("\"", 3, 3); addRule(incorrect, correct, Prefix, spellingType); incorrect = ""; continue; } if(line.startsWith("%Infix")) { //infix rule incorrect = line.section("\"", 1, 1); correct = line.section("\"", 3, 3); addRule(incorrect, correct, Infix, spellingType); incorrect = ""; continue; } if(line.startsWith("%Suffix")) { //suffix rule incorrect = line.section("\"", 1, 1); correct = line.section("\"", 3, 3); addRule(incorrect, correct, Suffix, spellingType); incorrect = ""; continue; } //must be bio information, ignore line continue; } if(line.at(0) == '=') { //alternate spelling, add to map if(correct == "") { qWarning("Error at line %d whilst importing Spellcheck file", lineNo); return false; } line.remove(0, 1); // remove = line = line.trimmed(); addRule(line, correct, Literal, spellingType); continue; } //must be a correctly spelled name, remove comments and store int hashIndex = line.indexOf('#'); if(hashIndex != -1) { line.truncate(hashIndex - 1); } correct = line.trimmed(); } return true; } QString Spellchecker::standardise(const QString& string, SpellingType spellingType) const { //remove exterraneous characters QString standardised = string; standardised.remove(QRegExp("[.,\\s-_()]")); if(spellingType == Player) { //capitalise first letter standardised.replace(0, 1, string.at(0).toUpper()); //standardise captilisation of names beginning with "Van de" standardised.replace("van de", "Van de", Qt::CaseInsensitive); } return standardised; } chessx-1.0.0/data/000755 001750 001750 00000000000 12234477214 014530 5ustar00niklasniklas000000 000000 chessx-1.0.0/data/images/time_clear.png000644 001750 001750 00000061161 12053101561 020600 0ustar00niklasniklas000000 000000 PNG  IHDR>abKGDC pHYs   vpAg01aIDATxݽw$}'Ws]"HL`x"!Rђ,@Ig|'N|:K$DEJ`@ AA,ɳ;9uU= $j+?MuiZ366668?f;&M$Sz(ԩJEI $,Hi˪QU\nP(,acueunnnn1X_߽|?~f6MIUXooo__C9L:t"3b @P   @B @ aAXFCT+z!+r;ەRի犅¹女kkw KKK֏zLX,>|uz;zz&:xHUT""4u4uрe‚R ! "@"EQjUPT²Pd!X_]-_b>_իW_^[[[t N'9rC8q<ٙC!&DZEZA^i`D#HxR:HiDXBx"spEBC!B\k+˳k+n}iiKcUUH;n=qv=faV.V4`pE 0!s6aKQXñ(jF၌E"Dc P)ҕWVsgc ?xw~hСCT:$@RFZi"3ιmMrYw!MV* ƹT AQ a0 25EiM&(*HS8Q.[DR0 !""$͍•VVv[O?]Q)?t~{уF"ҨQa H!A08eYjܐrjB"pDzH" A\ =I$R8 $;8שV%,j C!ӈ'HgĉZ)bFˆ%tBZ]1qȸZz˲H8c0- bQnR*Rm"LHo~T޺Jz{>'NEqV)VBa_˥WWn>BGgHe:ףV]@Tl+lǍc11'F`F`D|'RY BBJ$8z+Q/d2ڻ{+moQ+*"r;;ԅSj}mNMM-?wGF*:|zߺ去n5j5Ԫr:!,vv2j2鷔pªZC Br7398gP8I вLţIn؂B H!a iZ,!`  0IʼW -K]ĹulQAQT$m,_]^<{W7_{,k J>_?t8@T-hA- [X^\$E2I )l@D)  *МG33g^c}y!mI B²-LӂaZaZR)$`Y+E%Ά)ckmBP8T&0+S.-/-> ;v~LGgԎ+$8W &$ЈHf{̲kTQ' 0F V8'MSk 4CS ppΈp};$9vK%ƪ.,fRHHxqI!%,K` ôdaa\DÍnT ȲGW//`gkKœt _?ʙ!='>uh,s=o7X"՜ }T3.bcyCb1TnMuBpƈk,( Q""!u iB <{aS}E2mIiD@hs@{጑p*'MN@RN1WcV$4KŢ\""P ԪETg;aiY7HaUUw7h.m@$}G>wɛn=6srY%Sѓ (W$$8g g!]h$DhX0ţ!u d.33.Lͳ;o<)Rҥ4S0w niMFD1mmNĈsh Ge,-̱DXDi]hpt,nJx<~9L^C o{g~~?;ô`v \ȱDv*V\#!#xC*#!$ar*4U1/ ^_X^fj9cD3 t~?eRXK/C5cP)1⚪PX(ёG(P2F4CT{;$@l-Ip}D3 W٥~ qiZ cbApr| #⌑)P9]d""O6fXQT[,Z.#٥ K pß~ N+vν:3#GOX>c=_:sΘ)TVug(#֡kʹ _!Oh; ;D_\K3 tɣti5- 1S=b}=ҥ$nl1pΈsN\Qe42!ZdR(B.4W+KZ\ _;~ا?Ӊ8ҡWawwW>'(#ǯ766eicqU7MOOx #dDK[(НsуPUa l r円u`@D4HSBJC`QŹYb#Mϡ[@$ѮzzmfW*J cǎ)%4U}#mPm&%7ޑrǞbp4_JH)r"l#ɤ*5u38Ē4 KE2\[^:Jw~dћ'?;wpnxȘ%:kd3i)" #P9wb.;swID{ewG;*>DD͹Ƶz/`]S*9!I[,Y{ARB n:~Tv93</^ZrSēIKءäBlZ)Gѡ+ X,6+|cǎ??>v 0 A EA\f3Y0Vs%iY)R"t"X4BzjGúc$zdOGy5MWmIn7/  :i{ iR 179nZ@P_L'~ hb\@@ qM*"Lf!ggGH b>F4+kDU@zH_wI˂FO? k<`°,pBGs<8`%·2H8dOiaQt/7dޠ4X@p-6}\9i| =9 pDH$Sfnk KWCGVT(Inm 3َ˗rP@UU}~Ͻ?!@^eٓ(ΞaZb#|Ģ!hm_K0pbCN['?%:[M܁᱀-`bW2ndsKpI LHɤcUkJmeqAH[nd"hGc;V:|}CO&#]o%xYN>anfngl' LQثE<eH Df>Azj ʏO/{uz@n |:@pH.)%R*CGW秧ͭM 15wv];czK=t:o<4Q-4 !P0},>f-ܭԈ1M,ѐ(ѡ 1;'B+I0?oVVF] E-[<0ڌ=ɜHH,Cz?E$$!%B*X #csgN[dٮF 9~]G$uOO-x{a4a6Bqd_w6sP. H#B5ϯJ>Oʖ!onvxdәaET{?|+_&v4kMr R+}Q "OT,B|H$pH ;~Mwx.<8kLZ){I˕ BиY)%S8PHDn5>I "`{e35PhB]; X9+5%F^a=m p G\ckc= ư>#R2::@UU{9prɞj/]^3sUˬ5lkNGUh@Pn%}wlGOPڟx1|3n.?Wn Ai |r$z[zY0H(᱉WXXmY4ju8~To*zcwsO#PUMijdoWY(1UU(֐(R*D͜ocˀ)kf3>y0Z/ #8$% <ɞD-WJ+F^RLG'jd0T]C1C<CG,uk6}@UU~tdD\;[10z٭ !S8R,B$CUƯS+|_M">ompWAMʻo6 p*T =ኴ$䱠^3=M-ND|xl~Y74Q,1qp&n{@cw} у<`D̨۽X##c*RogtMx4D4]SŸr}i߷3 /rr˰o&&ņ)x6q8Q ,q)W]G%b~^ɤ<Ɏ^]C!ECa8xMl [=PUU%I~3[ M崽MO>,̾bN#KAO)\@,ns>M@P}L @ ![TM$SsEhCH52vvpFà.ǾRR*CF1cK%d: n#cx"quo(ё;C3ְNCH+rxx*d5 8gU2pG_}qAZz0[4U@6CAShIS IavY@#h^Y04+s~gƟ(I)1e>cϿeiV  7P$۲tJXOX:NPFpm}ɟ354 0ƑP0v踱Y}), @<2>|HϿ*;7581d3iTՑ5>I[Adp 0 fROW;j)P}ID{Nx쟿(h^| sNw_o^mKI0@$5f~NJ8WD ssDts!0RT?sCJ TWd_oE[gEB%J"ՁSG#˯ЕE<JCDǢ\-?XWgh0-6d د;xtq>hH\| o:;$<6g*MIS,#{Ḣ+ IpRDcmy0MRJ 1HïK5Q}ckȶgt%ƈtMA8AbvMRJ)t*=p|\zk O>ƨMr[| |dܸ9]5188>I;o<[OF!6JߕHEc1+7VlW *zz{XD\fࡣ-sƛ "{_P}bڐ$UiU( ]e41'ko~P^%}3(nзgwd,<8w-Bpa)=!^pﶜHkkoQO z2#v:|蚍?#\̽ۦC]WޢP-n2`nA3b#L ȕh0np4C0lK$US=X]"әv1ڳY=Bd@,K?y.hQ+!TEAXSILq0 ]' ~+/?^)bfK 1~ x#~x`tͽzȞ[3:BH ehE$=Gh5_"J/nH!Y26)ݶ1"B{6vya~s%׷P`phTOo_gRrUKC2! Eᤩ 4M̕O k"`ZZ—MO϶Rn~DS0 PBٍ.%hp #lw Ar p?f nkYH4qcueU&(rl6(cMY^Z<AUSC@ jÔ1s͘8!v cZ 1 ųMU8 ]kв,i{.U _i΁4}pcv|Nd'5`Y$jڙJ" H$8q6` 4j5ēmN#k )l;8DB^L+[^m>"~p-oƕ).$@5mK 7ҝnZnݜ ־՝KJ/mJ.5LDڲYkMht֖@GGG,J9$4+U{ {q$jylAAó0$z&4SrݲzapH2d+_=r߳h,Ix7 w 8;z $)-ƙi: g' ӲuMOlFfR.!JK"筹˰9ޟ 7-Z^%4 F _9 H.2@b9k5Clis&LdB뺌FfTB(;L9罊3mm{haEUCh4Q+38vdݴ$OΘ܂?팁YHldog  E! ^SBiaګJ',?:y?>g*1F̣[R1x "h4jL&C Hht!B@molGG\7@)PHE 0#D{yQw<="mzdf/0 ȣj%0 Ӳ{p)%܈^JA!T1<ܧM@nh!I5QT:-wr2D#JZOTpȑ>"0'۬% rFv7oQ:PSz`;qA_JXRJӲ`vK5I@7ò!DV2A_"}u,|cYf{7']Ј'TB@t!=U.UmmmjԔt[fBLd0 j\դ0a/h/ Tk1lu|=|7]m#@p phB,lmtOw *E ^7{ƭ'CaYj9eAh,[,% =8 ,jY;١?=ZXrnBLc:}oðS7iY&RAStH8o\4AAX+'i^1& '(AƻgMܩͭѾ5'@_Zn2:%`Fwres)%٫4m1`Z,x4M|s 4AA7~obPSLѣ&\it]2 R1YBCz(˖TP!"`cP5McD Re9%a~-^ ӄa**|'s +)ekhh7i2T4IJS@܎{h~Pl \6Qn9TU 7pCQ.4M2 -//{#U z(,qIv~O0<>M9O8k}7p;ӄe iϯ7?B8&+I귃5Jrvx>8h%(^='=l.זvcTUpa&RJUJ[UM$Spj qF oueyZ!gwmso]om(BJh7y"vѫ9M8B|yrnkHgG2bhw]{ ;'6`PV$j<#XfGAw覜 Ը{%8邔=ϰ ǐ`&.n,9ax C+m{ i 0aX+J}kI Zi%Ux=cs }-Mo^a;w^0 E(ft/5p9U1+[45`fh) dgG;{9$]+~יH0֜oRm/|K%T&c`DB{yvOORmEv! 'Fݠ'ZXZeY]ddw,[BBShqmuˤ^|;/+82q o/j, 3f>8,'K(@N=|Kz y'.q姟}4݃x$n?HwfwYȇh4'w}˦XNaA gdG&My;-4XQ8!ad !;GS0rw]pB|)%) -74-i !kr䋻r6VUyt#}=2 #H8i#Nf:qӿ'>02^@#p/41%TMJ'6qn$6a4@J"ai+91n2-."ؗ A_Eh#-|HM,/v~TQ AN$5y׿{ӗ!An`y#_.>eI; "0H8($\>NT2apn) 7|BHٯ> `T.8:ڐLfW'3L?{b?}J_ ?b+XOo q s?n窳CC )/쒦*2 TL ʃ#CMO?g,OJ6XVo\*?0y8W%;eSW@aOhjDRnݝ$*l# [LqT5tY<9ȉLi A%0 Ԫu2m<+{:1ՉRVju Gd ),\wa(5~' XOMQ7~U m (d^<1!R8*OMb>Y6Zl=gnQ/a7tƚ,MPec @00 ") M2Z ] rBI=]c1~;1T!t@"X%$Bn tMY&?#Xwջ'vSJxns;旄$&<,>I(%$o< 7|gkb'32^J 4-"2He<4D!78 ˂3J4^ so(p80Tr'ޏgɧX?ź$O37H1AŴ ']`LO,̠h8yq?ƙ^H[czB^ĨADVV9TM#߇tge5K4u ;`s{fd=i7Ah8#Na2!o_fY0$Iy1RʛX7ј_%E]M|/Dk|0И /^ 9&`B0oba7/Fӏ>ӽ}{A!,T+#7 c{kIrpxT,J2" F`!]%UaMg<_iىa0-O̜q]~o7 f0b]8RJz$ t#! f?9&t_a= siNee k($XJ-NGŹ+؏b߲5Q̇> Tt/5;{`.@Tk*d>8'eaiTj5 ^w Ĺ^[5 Bs/>GuYsa gZpe/irkROMxҗ^&`>Ht0BVnk |3}B@DoƢ W!7ȫ+6`^;C>"gfE?Ǜ&Pd f>!^X\O:bIW`ʰvK%R \ >[Z8xK_“jjebTf55vafs%dz :Ta *$$'IAa-] vyI658#'\Fٽfc߂/7ݭ7x/>OHG/8ٖANþN8ۿѨc/t-~R{@๠ tqy)2h 7⯢ERBW'(L)v˻x_ĶaHCXeUUKsB>48=x{G4]G"AnsC] Ea]Np o]H)aYnoAW4Ѽ`)77q*siQ|L_gyeA/nKgP_]0LHo4 JPs>Ԯ^FiymTyKɤٌ:sF:y S? xj[_Co{ ހl+Dg7:؅s(^j^z*\Y\5 'O} NW%2XFWw%CጩvO5 }0''r7,hg݀ ~'b!|ȋew^H<(}_e_nTV L{@a:؀0]k|Q^G767)CRMkkkn.|'y~rD7>MހUolu;8ܖ#^AٲP(ڷ66 UUz{q;FʻR"neL1b‰5C2V𛷀hۨd~UAq-~7X4 tB+ѰP[߀aAQ.oBҕ+onRߠ;!t۵թ)yanPw¯0 f|ccX3D8Nހ?J-i>EUZ-`ڲT*uKY g̛GP=Ҳs3A@ "h&[>j>P^w-|F]EuyV4h[\[YE`wk uM=4RKSMR%乹9(n?B7SQ_[Cð' XEC4̺ߨg+NMMYhmmn3j(T, J b˅{A:yIn=io@ZkA*{G/xz~>O{(c݂rǿf[z 0% 2c>J3/k ;H_s`z4 =AJe4V fz [wvvBGzà ī/lnp&.^|vgkk3V%ww34)&M ɄފN~.0Mk^6/◁&x}}-eatb\K (TJ`*Ur 7=Bgq%Benɋ?nҗDד4^|TtDx?j e,&%l[pn|P<]JX .lome{]FY.S #N*|w+bh*xL 2|A!gM]{CFd*|w5JW9O<)G-,vفA@D鐗xο!~싏Za/Mb'ϋ)*cm Bu"";8x2ƧªׁnF"EU'V4 {)iwg[dMi @\{i$uInKȦ0k|}SCH)V5 ⵳gh~m }iteX0`&[ح4!MluGOb^V)wP΋Ow n2vڣK[3[fmvrbb<:vE=D==ST0I tpڳ?7@`Ē՚'V~?8G8䏢(E#Ha1<={ ;xfzX 2, aQ-/(U3}@3D8yӝi _N&v}%ma% U!h:3,MOjU|sz}GL;K,FI='˧CVEF2|^.k`43M1<< [PZiZgP8,`'vg5WwAQ Mq~vߪMuqJ 9n L! +.Udƶ W`u^~v2`X}o\N\~3[jҹi@Z˄b6AoCkW#J}`YϖgL`j~-);08T)`4F@qgGf;;Mg)LHo@jIw_D} 4 =4uەjaL} CfG'Z B{O/\8O]]ݦҞs'ݻZ`ZM_B}ykHd<!(e65h3;P =*H"1t*Kx'p4NF0kU--t>aO'Rx{%(R(LfSB/k|i) +wt3S)Ш݋\nꕲd;LK]ξ7_8A7<&y׭=k5z{Q?G+hM3`^$O@4RTt djx~y#p"Fmg ث.{jտ%e)PWix+qbR ]kԐv@cWXxi=6^gEU7FUA/^`]]݆RJ#83羨ll{C84.#!_~QMŞk~‡=5vi W$Rianl^HTᅕH DMoa92-GUm& X ދbaG"ϵtuukқaYծ3dTQo|*łlvұ;5z=w;nNqsOnFj?oəDDF5בooo5x|!,U+0Lc4s" iK$-m Pҿcx) |ślDSIEUIi:MGK^az*:GaTױ70 Gð}J ,@4{ރ0(gggѳH͍ͩ7 h>^)POfi9vuJHd*XL:a_w?ASX2u  7;fȚ#J!qt_ QV2G`8 m+s_'QgOŒ)MѶ6t? bHՕ# 3}oH_f9c4MS2*FFQ(Xa{ HR;ȷݱ<P#kwR*i2~N[⊂p"UC2ӆ2j;[~]M[[LTq @@@:Eg/OB3 v} !3qՊ.oG776fMu0?7g1Ǝ45T+@J9JsS+ E] rfqpŴ{?O6iS޿yM"Ί'PŬ+Dz$9",9rnE~Q@xUDxK!<1Y}WvB4wjt>F.h4!īOB+Z.X"eR [Ɠ}9ހf˦3G[˽oDC/D|ށayVd8c'o6;+ˋXhtﳖcpˆ XP/,UN}kueeٳo8{+.=T-P-Bt OY.,ӊzrp K+-8k5 5 l.ZMsK>ʊ/PVpMw@Y'3`M)% M(s঩eWWNM)l+\.?8t4)r ‘ [ׇ[>~oe\'Ahj*J%jK&$$j ZDrS҇?w'/Q垇 .T`oW`A+oy9Br*FGE#(moA Vw?|)BP1L^m88 ( HېasSFdF1m#w"j7Ew6}ɧYZǡ!( w@BMf}:<~幩)<,:Cap^.V7P}?9040P:$)wxkv `yyYfhIss}#`62q09jb~8@iE܊DccC4縢(x[D4vPBn [-<ږ܄ M(N *Lɇq20Ưsr\Z@hf@'lG'G>h e{c _Oo}Z l,`Y ]}|ڒRյ[,wEVT[ȣ^x4_Sj2(* xdžEg{R:gHnħ)(L x &mȝ?Ϟ?brv20F< {6x'= ?w8;;XRz-V pX_*nX*a0s*7܀08='X`r)Vk@n7u:@]"= Oc_\T|[rrrԑXKk犂JyTMEenQ<7混s.4]TU1't&k 1xstAq;>pzD:OAǫث#9OHtq-XQ. 1D>q FןY[TXMTIKo EA0A |6c<_e] gv._H;HԥF14:#<򨰳 "Bou0-/ixiwqiPUUpΥG{$9d!}bVgxy4Bag`k]>^myN~]`+RJ_;tkҫgvW&rߎqvR6ӚiNЍ PoX 7qTH qíXyX{r)mpU\g´fff&/<3<6vtpBMԪUڨx2ZKWhW敭 V9q* bLr$cL `D%Epo?ʓ(W|ۨV8reHL}Pȭ&?HφawarֿE5(YD?Q;;s? SS/2ñ J8 SbA6pDzeډD6'pۚt>Fes]KNSk4~hB>/jT*uR\p$cDPGw/FJD[{z[B*|NUԵIJiaY¹U "E(ᰀa %*W*r0 =憽JQ00NSO`Vz׻Zʥ+-,|,䳑HH4īg~q%'0jXVSkah[^Bqb\C tEyIK6UݽPh`ICcl6` M]]?u꺣םʤ2V)#JiiDTHxXn [RX&-$ Mץ3T167njraiDΜY s qHıxx\=otbt]LmueEYq'­v`WC!2*2 þU+swnT %$P܅5?1; W_F@[{O`aU{@݃SF5U1..ѩd̕5}>m^K` 8ŀ_$>syX/%)@j~8ۍS~(ak_SZi3@p;v:84D"]e9ڑd2y``xd ?8I$LUH!` 4 M:޼@`aѿt GO"K%OqtzQʷ0j0^^'S^N$_jvܹ7`upmw!xWQUń:{;|yj` tkhi-СC,N)US;%z  P(⽽=L& gY5P(dI̫+؛zn Y,xAJL&P:2d1(p<>0gVX1 AK93շLsdzNM?%2!лYXu5@ эX خ`B/5xwЏ5CxGGG(N%8cΕ62;ML]U^M;8Wd2i&bD8kq30ک%4-!MÐ rk|^$Dǩۀo?5a"fiTaτgeSc&޲mV`I gDBS4a.CzL솛3݅AkHL= 0nMIӑt:'UU[Ha%,KĥI!DDBhBJUJH)=ba -zoo p\W+$&-l:He܀M{zW3mBmmmCpX4MJ%$sg RzmnÊOXXCB/A!_%*ّ`Ԅ12 LF#irE40[GjCAߔ`Z Acö: dCm35K& i*koˆړj'HЫ?TˀReϣ-QR!RNTK$wRo2guSJ3t$-4b%5~j85Yȕ[y"@f { tFjLZo)F5'0Y"A .EFS("C)<7Eqk_lEkzW7&"Gj l/w-Q)eٌZp饗88N [n^CX+0~ӴLJ.bTK 86 {F{""\n=g+?*r~$}R ٍ$fXZOԒFI4JXy!@+;JOg*Ɩ4VWDDž/[sD*@$ ӣ<:՚8X b 3q@ok! -J@}*R-0Sp::Y/VKY%QDԊD'^-Fڵk{K/^{ڵkq "1Bð9l¼%E@DNnvb"pRjS# m6s;A "rRj]-E$W) ky7ĔRE- "'7hBnp>Cs`?^}|cck*MyRmK (//'77'3W1뇣2"UjX~Ï:F֎swv%u&na"Rzt@^oߞ#<qyӺKX.5~ TR SD\A_:& tF2JbD3 -#= x,Y]BD>VJ}2D d~6Y\xi[cלawҧ{b6m\uw9M\1v}$ћjͣ-$/8\1a$s*T%粲D#_|C6bKTK-<)ۻO|7!O[2,eTy~-PT(qhh%4=_O(θ(yȑ駟*(Rj "бcG/_δi8 xGNV"󀌈, ~}k_hL<#%8~D;lЮ5}Mw?Xz8{v5qHZ.8#y@m[b>Hzk)TF@ J da3"2vg5=RM' Rg'Yr!/+v1B}\s5K ̜9> '.Ô 2"j>D L%Nvy ,AUJplse@ߞµ DkMMO2g v1H,[P^ `dϗXDv&iiiy晌9mRQQ~ʔ)SXre8SD:*Axm|K ҍ֛0"cLX'aLyWD 1*۝!-gJH&fuܹ r0|*SJǍPP֭4#LN 0x&~J~#U\,@  ##4B(:9+B$%F#8c?9$ţ)FovSX;~.eeeзo_N8*++ EU(,,d}_GGᨣqnIkg E`v-Tǃ;&KԿuqmb 2bF>ӌ>0e@P7)[IK< ˯2欓h"`s`, MYq=K 67 8쳹+? pzuI?*梌47sXlJYp2s=EF\;~"(f`Vk?#az 07?e{/"^|ipH(kt5.JohHj Ɗys! x;̵ՖMJ=ޏ[ܶ+ܐ(9py㵴nՊ̌ BMA?u,% S[[Gyy6m_1JK P==E" "J/BR{3:^QUv_jUC=g}N8h4SD.ӖV`vi̜9~nٳg3fBDb@-PqdEPFԢ$#d3M/hLmT 컕鯾ANy朧q+="(+tR-"DΏO}6ZĀ-%?no<--/x N p|0Lxüf_Am50W6%Uʒ 0H^|߸aP`D`cNy0*Q/ҼLi~֭[GOLyp{adD?hbf$ÖCHQ0z +SRC^s$\J|ݻѳ{7^A2dfdвE]:wwDzVL*|ދ~hϑ5 7 0bMX$O6rE%8c[kk@ΝQJ1~xΝ93XdI7i O~9r$ݻwMded N2-^ORRZWDf(M:N!kD}@cVTi 1}[k DxGc-\B~ O0ؠCT|ъ n?gرb13߫`$ɺ{D"?YfaÆt`LՊmc*7 8^㵸5~+\x LydV4n E<1E?ٜ%R*Ǻc~/TCLwMT&̖~@ݷzpĺ#NܘBn .TB+Gm4ii\owH+PfT:t(#F0bRj]8h„ \xObܸqy{ 7qK$v޶26 F+IlpȻc:oYu ̩.K%2ǂ7D炋aEds)v5nFܜ1"Y| "Ԙ G"1?=rk@0ɔ#vlY3Dd@-B+y[VVzdn1`@Mԡ<=h~zhGOZ|-j-&!W2FXa^I\:K[ՉH^h=5pgbFJʙ>+>|.'<׻^jinKwEH|HMMZ`ÇOXx ի[f]ܲuuut֍ko'xc1rյX`#g-zzˌ{ڷkqG5W\̻31m֢P{{"!c]YjUk~q6ɲ@mqO^JOu)hۖ]PU]gX5ދbw3׷J{2pT 2aGDuytуm 6P]]8& "b{CMB _dgӧWwE=}vXH-ps:e[))3Rv3 3uG$rvn '{̞wdefs"ܪnL3"rt2c?*&)@qBvй40tY#ԃkuVTVKBioAÇr**b">;>ϲ?8Nߤ=',BciL@Z'"E@?8`[Toڴir!TTT0bp#Fg c1^ysriSSSA0~2x!n^F֯gOżyS\qcg<7u"H[`(0) \槁e7,7F:C]=&x еa_/[|l`a}OaJ$|̈́B!x s/jpag.pBj222袔Zo/H$Pjmb`/wr=J"5|w}HRGkߘ*%'';o駎&'{&=ѡuq ~ؒ.D6Ͱ~:O=T(6mbŊ,]Ehb6l؀8:{:v  ҫgwnۀڙPM wb8_Cv}6(Ґ` XnNQ@[Zz;,R (,,dg0pdffi/o+r+bn⑩v"rRj9DqW0-ڴg@P"jj(Z7[jds~8hP@i&>t̝ǟ/`sq)a&Իߓ 0{aR\I<8fܹ68̘1￟c9/3f0i$'E5W;O|?5kk~"2 7|e>nr i[m{?5]wx%#<\}+7n6s*z䕘76zl t4=f ".p6UJݯ=Y`=\* h+nLFͰa=zY+jA^M5jbBu1Zz:' ygs_/o΀k!SE >01Bs"G O?'qk.'#==N]DV2}:~"$z+"?7lVJ&{۫e{-;;:fGqB QXXHaa!Ç?oLv AwystzZMu3D]:.`Rx2wƪde& 'zG:{m1K8;zkrSQQIUUw{ $!P[SKEU%|xV]8-MT C<1=l8PҜ؈P^YŚuXJ^).&GQ.D]F{(=h4ʒ1q k15S Yb;8$z_tE uqsp??>V}Ouu5̐nqwsם䔧xyt`M, ϛ[q&=ɰ=wg|>Q v(nK !R6[|[.pÓHb=RJJX Bb _Y̙K/d.Ů l<`o.Uwd7~p8n8/鵲ooz~%G8#n'0a#Y6==pjEkW]]8s/~m +R8) {2J'56n⋿B=dwԉ<{p87))1X1鈯r(lߞѧBz9"g-֭[gnsRqG=&D[. pEEEXJ:-ռ9`D; }0'y3F 5ԟ"!L(Q |PX 2BA2fM2Q,ksEH\ hӺ7m.tbá.YiDhBD-<_ʸzKmYLvco ,RDR_F)U^,&%dh@#+L@ϯ}$Buuf5UW i P0^WYP*rXSf6KדQRZW\5ӌmi yjs& t=+V`IG}HW +l=6[.㢱g;U@o\&/ps.V)*q4B.= yE l!2ebn]Ν;17ݻ'v(~&?DjTY IDATe&SZJ\޽zsSп?xdƒ18JXDv m^:=L_QScǎviv =J<5DAE&0:k6.( k#s29魑Wv 5o,:DJiJF,iBn\,mji~q֚>h#]In}#фיGIɏo.)5|e<zWܭ9k&XDdsq eРAMdBm9N=G'?~'!`7Rj)VgZHXW# ^DSJ ri2`#a)KMYF- xck Do|lF| |77}=lLDpt@L{ߴiFP(N;d[nn=5 &R,dв| PZ,YG,h_2ԄPp؊Zsrr/ѿxL5"t҉ggYo[+KDъ{PaSg&7'G[&J azmp+o6Zvm G#sD4S]۶my8p #F WV_EֿZF{|KteNjRL6 k-%pkΧ}^'}uEZx-vx/\]1@L@o9s~F]8[@B3@bof<$J_`(++N;V'8v҉Gi'{q.lyR[fɲYݺ5 5k 5"YGKglʢ$ srrxiժUBl;[qn6mxxᔓ{_nJt:77:vHn] PZVƪVp\UDrR3u~4X<A2,KI3c{aڊ83?<4=_ z.¿\([KO P<߁[Snc O_ -0bLB,f…P s'c"Ӈ"0n(Gygv2]tb 2 ~E"h[| SY87+lb$25UCcGm?#ƍG^^]o RRR҈EEq/ޱerĒUA@9Yq3% 90 \cuÆ=!p[;0DR2?7.KDvUJejI P&L¢6.aj8`ʟqF‡!';,222 ==̌ 2͡e~>m۴Sލ~Юm[l:\[98+WfoX;V|Hцl..!s|KRA~=~PDu)uh@e"eJr~>V T&#W]h{pc=ƹAA.g'ssi^UYǟ|ʜUJsd|(DsA9 Knw7sPZljͯZQIK p s 7f FLy p ; d݋w|֭ZS*wh301RTnn.ƍcرL:K/x.7tkrjRf7/*TXVlB>]{ܡ⾻FqbwF3SN9B%QJX_NVF #eio3rۇA.\\**Z\ * Ú1{ 7]wSOo2wywu;?Zc^Cby} ӷ>A5¸bCN@=1wŢ7%%(V2by4PNLH)Xc ]iJKpHm);ej+qr=z4ȯjBH,ŗ_a?QJ=F}ZVl؅0_9Zc's9gl:q(@MOP8?@bTVVQYUM$&P`0@fF:9Ydf7p!9\̚ &Xd R 0JPU`XQ6`= O駟&IhHvMpe}y{ΆLU}-ƫӞaĢa^y λjzgr-@^ۉ- oG}_~`@5k>tX |~ysj ;E fz޽zja\hP_q5<ȣ:nOb 뼎=Δ)S`̘1vZ["b>WEՖbE%9І'4kQDA~S;3TgPa)ʀ-',%4W[o^H?KJϨbF ԼN=0o>ePVRPEg\Z7; #?i2]?2*VJge>?1x@{c:h.}S]SZҰy+a ([j$6A9F>/778bor?, ŎCqI ^}#3f=_u]rqPӈyqn$VXi9&x7ΨxD#!ȒxƎ'@p@ @\:KڅntsBڶnEVfF_$?re-SLP<<ȘDtA k׮sV|&2O>#-f%"gl[3GRCa{rri ˕R)?!yJ4ߚ \ Ϥ̴.k.`.YR*~] ^oF?PJY)uR\mйxI)9n>ș-݌#2\2!fy-:պ5HCER:]*j&dz?Nhl.ImҥK7\M~xBY)<k &frҦu<ٌo΅4mom!` ?31vG߫4˵l.DHiPlQ%rz1vN-`oOTHVѭk#7,e6mxk 4УWxtCa{4Rp\2CD0ǍtAmH,cjժ $7Xq!SS[Ceeeys1Kظi37nbæMlTLqI)e床x5uᰉnRK/:n#uESF/ԬA 4h\pꩧr7.|%%?a97?/=42f[i)$?u]甓FVL`w 333x3fpEteER< ;qMfn6vZϜLfTTVQ^^a֏7YgKFMn@R]/c<"v08oCDr4o>2wK ڹlk "".YT#{g^ńpCJD*EBovX].@ҵK'st*uT%9Bf6g~^6z_(gM}= Xǫa-/X@7׹}^z@#خe}hO^3]ƪUIfE)--ŔRVVFYieeTTTPYY9TVRYUEuu 55PSSKmm-u0pp8B$?Gu`0$=-DZZYdffAffYdMnv69%E^|ߺe>[Ӻe 2]`?>5]1M󁂌 nm+m}EBܴ-xx*+"EIiSy6-X%v =:'@=h~ɩI'RsXhKa6m̙@FF&h(BVX|94Lߠc;<ڷoرc XzVϛd8ŭ&(2:\Dg.DDz?0|/h`fN3Fm%3 ճ;g{raG3~ECݴqc4DCqi5XpZMv& \̯P!5}{NjՃY~Vc4njSLАc,׮ {ĥ毗\ H/ˤog:ykIo/di4\yǭ_x-r nO6lλ.# kc _6q&JKKblO q4Xֻrs)hӊmо ܡ;kkCZ([[ĭO6]ilo RL:]6ZyMoa5 n" 1G~X DplރweƇԬ! -6pj%H j @t&OLzZz"щ _Ly.Zĵ7nBF=e{sNv\K7[; Hꫯ'p-n_(ĩTs KՌ _d}O^{櫵fj 4l9:>p'GGY~Uz4Qk`ش^đ$$Wvb֮+2Ͻԕ佰ã6S/8D[ ,[y "ia?W\-`'ð$*m<^\gیQv')KdM홉[=w S:Qҩ6n7f Mp~Cρ~:fsl˱ jOMYCߠh=}uõ},9 O)ćQ ,R7oijƲtJpf{ZԦ&e;gcx{=[>gIZkmtL]U[C3F#$"oR6u}-Iإgm)suuu}m؄^[3.;P?#hX{[֭ТE &<8_}ŗѮѮ];uִnՊ6[Ѻu+\P`Iu &c ښ1'F4MKT\¦lظiF6q7SQUMw?BqIUZ1K,jv 09rONkԬݕО7jKAK,c.?n~*`VL@θ1bNyBSFgѩ(3 !2] Yދn;>}0/H iou$F_кUK>~5:KM>u2^ϫ}fٲeL>/x/^ rb: .lߜГ7~ fob  i*R5τQFCFeW G`6JH%a:=4x)tґ2ޙ!w<0kי2VU{.F`x5Qhµ#2LZހ ODqNN6yy*Wn}Sc/xkY؆9Km{ܡ7A\"gC+W,c>Գ6P&$BDcS`~%f͏lt:v+!"s<q|} k:zٞs7q;>Ÿs@`z: ҾU IDATMz k;_}jBю߬Q0Unz`ɋ)o8^o`g_aQ) #BlwrINNw{q0D)ſYY q)Xg=xP(^y=MRH<"!D  Kzz:p1cЪU+s?yn[ KAbFXmoB+{/ih:[/st!1ɧZVֵ/-Y$ "Y6 7){ʣqpON' \zbEG|Ƅ_.oM9>!y~ֻ&{;."7`_psv(xg݊&[853f_G?Ix)@f{ЩcG &w2a' [ߐO:b8zbHR]ۖ,Rvalϋwe[J*~۞)N}Cn0l^V>7)gԾH6%>lS گii Rq)il~2HF SJ("WCnfm jATo-IqP]SP8oWP@uM Z_ƂGOXN5s/m-(;nf[AM=QzRQQA'aF6mbJJJ(// **+ 4>z dee)s2&/'[Sf"/yln[SЦ%ydeeR\Ry Bg*Ea1@B%Nt#F#AѯƤɓ&mNÒDQ@AA%'EP" 欯39+*"& 9y'GWT}y`wz{sQ>t܉ LOf͚89̾9Gyn<]J)0u8a?!440b(2Y +꣤)O9؋SNkk{6@!*A(En0Y;0_}6.Km/f{#%%nӧ0#cF78I& z ؇۟K& e+) !WEPR}Kى}[ݻwg_ߴ}{m[+ SC9gw yݮ`}KDK52A #Lڴ⺫rǃOlSA-M*9Zx5Sw^3 êL2"X3> tt.6)VK ~f%T ;>o(]f==GéCYw^b3ê?@d#).3D8zԕvORb<~p%^|έ؋J7Aظ$F9Ɛ xQF֩-0g&S'3{q;lܸ1_> nh**Ar}w1hhX'~).ʤ3{;L:Ry#..:G  -pNـi3jԃuDv^@ӑy ga-" w)x NR,!ĂReN+a*ҤBGkp8HOOAԭSIMM%!!l_ϱcؿ[la ~] R~V3x`^x Z @F kr&OϿ\aA g9 ^/Izuh(ڵjB|\,N PTXDN^Gfsav/@,kN\ ;Ay&v"a@k ]#h'dmr)ĺC1 /H c 5a= ہ ҟ~4m҄ўJ$1!8{x<.;IMMeڴiL>,[8u}o $D=xh/aL3=z)dQ}Y mWi3=86ڵ%>.>d<BwvwH, q4kK8j!/n## eIЧ &ÝgxU,p9Exr0ЦUs|>6nqE6p=`u3mZ3k1JȒsgн{w:wD۶mV B8Blu桠_~/烏?a]h^lќ_LthZ2$% Or9ٺ}Eg*ҫU_sut:=UR-%8 ٹ{/\ϯǟWaV@,B!#''8 :3$Xᇥ|>GXSt1EWr)ݏ?VXLtc;-ѿ` op'!ć-Jdc$Ҩ\%6Mˣ #J'a/(GڵBm޽9s6t(WǼv֛y$%&Oh(*"ڶ8/Z=Rz浸KA`Ujd dx5aeB: }85kȑ#²G5q72EW^)W쇱wA^=xxIC;|d_-\ҥ"p'V1U)O @gՈC8SiQ-wvO =岌b 0y`h0͛~TvxҳX<3vfg q1:qYQ>iT%2OmZr%#3CWIGq zjYeR0br5йc{|:uÌb6muw(Q"̪1[Y$)u5flˀ9r$z"))14x,ЖXu=gv?ɗOJqax:_[-CR3(}Χ1az{.:>/WMiQ )w [g )4>^^'%FCuAA{cُ9!\;Z`~ $%Fܭ  t,YtXlBG1x g?ˏbb-A䲆 ,e߲ ǖ6A9>)Zn!؍!2 $*cH͔*BĨeaL͚5e_pqeԬYcǎqwg^bb<"DY.l(R a|Ǥxt$HUץUkLtI`Ĩ;s8i&. {d/n.HִF 3v76)RʥK`Ύ ZtQoV=öm:t[i_s\x!y6̃d~2ɝۣ{D+o{J>xe>{ueA0$ZpΩfjh?})WJZ9^I)Rџ#E|̞R_!XQϋgXݡFr0c^<\- Ie3)X*-?a`SF vACq\`%O}l kʣ@WWA@l+"BI[.*y^YbƌIiѼ9s^MfM9yyk&4-ᜳ4/Q uM\֬]OUyFOiRs'H]ӆ8Y=<p6hЀQ#G1 Byie {Ӯxfe3s2=xݏ:u*n;>t0 `̽&U> 0im]%57IŨ <&8Iذ ]g>_7 _5ғ*9ZV8n7k^H qqV#qh-Zye#hݢ)HXN%^cSy0QUh2"X% 4x3~ogُg? v//RvXH² 5Ճ)cGw,î YΈecDj^hY0r4j?h]TJ^8y8VОLuaK3-geiW Ed1?V[p8U}F{zIFYv>ߣ#@z^~Kٵ#F 94VJ]%QI@hg R%aM+d={g-t|Fz5_:f7aؑ<;U Z*SLaF{hq \˯fըWGٱsR$)aJo*h7q #`"sFΤs!SA-7%%%H"jQ\<׭ԉcCt?LP¸&jLb"tLQ,w~+#_D5:ʫ.q1<ظi+\+֚~RJivkTW!Z}QF̙33<Ӧ2 /4kh5W^FB|n{k⽷?;N;vAfQP5hw,'$8g6σ{GΧu c/u ]&z]RQBm*q4zZyԟwvjs$J)8!,b]NƏH{nj8 1L~_ T/*س*m `@B؁``-B ;,(7P_}w9B3\eQaM*#( k'UC!m4! E8Qoh(L3˯W;xDzoC}Hk|yv6 vhT'8)gŭissr4b)%GGKI6DWëyc V'O_ SeѯgP*p27%]ݡߢܫOjj*_/ˠ>=%:oc~ nl v0;zh`:{',π]*Nmg`Aa#81osY58֬́}oqRҙ4Pqb^:saܹTV.<%Bk0ر<:\va9IߍVM74܉,TawY{%ҏ0i`'I)3OMfTCb,y ^.l˥Jn恃GdDB2`X :8B M}51l:/17> >>>h?yV-q\|> T6a9,^ .w,3x,i[s2j-'c39:Kmܲg#HK=+2$ދfSiN ü4&\Ҫfl3vj{.Rˍ>:KaENOn[,Ig0tga-,Lz2 }vJ)[ioF)"<0ihQ7K/yE+.ᵷ>ȩl-1|R~ KKtu !`0g>*iCÆ ׮ִ~4JR Ù5kEEEhִD8nڵԱ?իWk ^\;aAV@"4oڈsUmakdPV(wϞ%:$mߦ)deÚ FHY19zh ^h,U1/#}U)-qa'7/¢B (zIFՉ[=̥ w?CǷأ5Œ.N qQ+pB+òٽxeLrW-SwT `_xq0( c)"0?0,osM{5e4lؐ--.&55il D lDe,v6PՆ֚٫5{aj/}^;(K`ҷ5jZ"|N79~L p96a Ò1ĩ̀0%;dYL(@ԬYִdgg\xJM431|%ԨQI&D A) qv&HTwPh#H=A ŰŭgZ4kR5;wqh9?1z.j í0yy ؾ}LꐖaE͕ 0SڴnYcS$'5ە~:n:Ld¢"+짤CL JYERc.BXa#=zn]ۻ9o󯼁tLp-YVk̊fo,-pxJl޼/gOp Rr9qܸn7drGm?7ܹdIt4ʨGt5WnWJ Wa8p8ӅaGZb5T* p/BT`҂䧟ΌWf3x@.؟gNrbbhs0L.mYQ?_OIi_ńsy5핵t4-`.PAt`\OhH1r)YKlh)1n+a'E|>;ZFרD!3.Dh(Z5@F 8iGߍԣWn,X=Rd!~)pWO<~%atKvatujˆKO*"aln"QFrlM(..q+]6.G 1!w9Ś}uNs`d^AkZ)DұN/0ܤ#On"Op&X2R / Pf դ@>9HQ#yF%BbŪs2AGS[ƨ7Q=] jޖDW] ؛Pudoe A+mK}`:۶}'&^"&6|=Qր6D (}Q_tЁ6mDa/*^"$dѷyYR*}#ƎQ.a7?ְ}Eq:8kDPdeælشo} c2qG^D^~ \1z>3 Z5Y)l"!~vn] =})})nѸa5W#!>˱vM[9%A4§0j K 0,zj36Ne-Kߌ㵡ew;Va2kr2GY M\.O?8!*ԇҀHd]hn2t'IIlX̪(c`PEAo3{3Zkk O5^\sXʶ@.9LִG23ƛ7yyyP^=7lHͩS&+WfFX\\ϿJzjdegw>v}9vM3fPbccŽs/zUW]u3fxn&_>Jua\JR5-ٸe (2H%nQ36mv1_xZ5҃|x>(鿰A ]wցO[_bymT+`AQ"Ibbb`0A6¦;L]7NƩ HY eL^XK9p!gFZ;x"h H|on"ؠvI/}ݱYGyց3[HѬ\su|ֱ*Zlȑ#zx(**b?/\15Imm7~̜98HLL$11nCzYLy))7t{cϿ-x4 L0ҵ<1cE.9RJpA] ,B(~ (fYEsF\sbe)MJmkvu!/[WR) 885dF>_oC[mzv ׂ֗f+sv_0+pj2j(yM*9؋.)M}ViQw"LBRR.^7V3e8r %&dV)˔N:ID'5f@Mj$5G8|+WvAѺukˣߒeym3!Ɩ/馛}/bccZ%U )thۊ[ ]XʤvDId<O7,aХ;vFF9ɢ~#g ![U&qx1J֡_^|>wbu2f`4um԰AD0Iص)e7F(N ꒲:{fPbe `:jѤM3}>b!Hb> ObbQ" ,I/д C N;R؋ Gn}PBxq:t܉߇>~YGih1,~)Ç]P.K%~225kFFJ[8V%;ܓt><23"t!`T |:o!II<| vcՐDS۰_ f)Rأ/'`xE$Wx)e4 mVc >!XY©JyZYQewZF4RĆ8о_]ȀvÃpPk,Emh]VeV*Xϧg tjQSZ -* ˩>fc b2`)`԰A< IΉQr֬-AH)+023H0o _`Ȑ! c5kгgOn˶mظq#֭2dF駟''''Qn]ԩCJJ [la|H)C"'vL83f~>sw ӏ>hݲ~<׼׮2N4ӄsTojAAA_G|L2̵a$\5 `T7&GR1Ǜԫ["խ͎]MCC5N'N8ݱkQJ$2D\m^k@SU ^2!pc& !J)"1-p &#c2t&Lϵ:6m\P!awnn..P*@ pҩ*߇[3^?'.z9ٹB~V];ԩoG@%FzUyz7* '5V=?nsNt v]:F AR%>8ah+k2%YiҸ1-7aFujפzz:)rCfQ<Ğ={ٶc'7oaf,;wOJ4PϚf.-C_tB˟]'R+T.o3zߏpqHNNbP>)Lme5+eR9I~" g~eKkO :HUPoԗ@"W?U <1*{0j> sɊ鉢u00n:5mΝXG;j֬⋩_>IIIz sW0fۇ%99jժr(..oaԩ4o8)ٴe~%7|3RJqcs8\8%kH BЬqyJbBlܤNx? U'9X*i&hڴ)6mh$Bl63Z 2#G(**"I$8ڶUuCsbL!1֢YS[B2@JvoQ e&DhY}zU@o ~YVfi)Im3.+Юm1<1sl^Y^aݵk֨[,%B NJYF  3?[ ԧgpо-7#.66&Mmt" 7/۶j:~c +W ),,B]@m)e{O!r59JK5NTUƂ9&u1q޳lS X}ǎ *KCQigg:&Tw` 8ohW> E$^ X ўuU~,G4#W-V/W3xz$bb06 Cv5݁r sܜFN(57\7 jj|M|QF ڵkǐ!CK3~?=+V`۶mdffCff&[nb:u0af̘}p]zسm5[wQAkZLTeRQ~ ,Y,WC:zS2`Xg2ߪ~.ԩCÆ ꫯNUavB|WX+վhQ? !6.*0;Ufݖ> _d| xnz|s!`]tp#|7wvݧ/IhUw.XK0`8%+\R IDATذeXKoK20O zd/4`a^?v[mc,t/S9AR:c?t\N=~?nCggQ:U$nݱ 0w UKz8)ϊ֮}eNBQwt|<}_>{N֩M aQ`R>&ӦUKZja烔j:_/Ukף,;J) !׫ 3#8!Z]W%C?5kQK\\.Ӊ |>bЮmȩb6ef~"F%/'+UqUCrv@bbn/kgYfɥe?F~^.4k 1烹-U"4 (;X3XX g}6N0A%օ7-5oϫ_磏?ի)((DJٿ? ,端pp饗[oE;/:uwHN 7m#eGy뭷CF079t$~.Eix:륙F Olj(fy7~ò[mgDz8X R AF}E3nudb¥ͥi'*h-/Ɖ]FE5kbٳva&z!ϝ… Ybmڴq NiՂIKM~:ھ 6[ǟ^z\q̜9{r:i1nd֛ELr4N#DH$-%ăNNm4ʣNtB$}YIBJ9{|t֍X<#֏0Uk5\.nqW^ FC}&|J D`dDe/@ҢYc}&hʥ؋v@BLF[w2˷!\2 0q.ӝEKf:ʌ՜k>f^VPڄ"B{0H [} bUTP} v͚{C '*sx0 HLHp;3S #/xGiȀb1ѬQ}1:LHN?A ׮8J)]`u26%<xCgB?ҿ__u #YdiG r9t&26i3_{C~AA0L%Kfc4Z 29+.7FgՓv #@2rel۾݆i,͆Vwz%p-7ѣ١*=vЕId[oݶ* W K6ϖyKk@F@f?AK 6!.sYowNf¨&:0V[=d}D 9Ԏ>ҚIԮ~t; ǎgQf V^d8{a̚γ?ă΍S ӸaFq7l's燰=Cd~l۹4q "lmi"b}<))Zp̙3u2gf/@OJ2tz`ΝDSriצuBƘCAuk"9)gv/<`SfD`"=`2blTkz_9 <A !(_Fx&BZ\u?i\5V9(PƀfP|!-@bUpKxH]EWOg(5g_dCPfyMIwY`$v_&@HM6L5b0i? `ؔEs*ɼb9ɥـi#;f=Uvo7WGY)#zn}mu #o hQ 7 Zu &x=D$};+Ȫ.!8n6r%n{yc9HO3MN/VY 󜚙CeK$g\8 T0abbbZY = /W^aϞ=\N۷mIUoD)I:!ePvօJB,04_5ox}4zhA&SFܹ+t 4`ܸq̚5ݻwr:va>"#("^"%e.rNQFڵw!z~{a42Ydn^#CZj*ԩUTSۙG0p7Ps8\=~4igfYjlaSJ9ht:xȨ[ )aƭ,-h|rNۯJLͅ">k.|6 Xti4mRxQzXPoe1233KʣTԊ_Vft+V`=5[j6l/ a/yЛ&2ιyF4ʨǖm;tjJI/5}E!BQYJw)Vѣ;.ޜC}_p!'\ƪص{^WH$Q5x{x4`ZjP{!.w0" W4i zW)9H|1]?TFӽKIG )#'Ё xիqӷŷKk!CN;v ("-0g3) m_{.֩Cbb"|=[\ Fpǎ;iܨaD)Æhy#%A{0J ^j $-%[rZBIG _`'R6@=1aSE,W̅Khy u6Lޝ[X5 !B Xۇ Ey޹|ptaR1}eǡC3wxLfDڵnEin^E:wb<6o #/U@Rvvo"UmAA3g_OQڊh]'Nv'{!++l \@860'#ЋO0RjCT_<&`nǛNgбC;[pQF{▻ 7&'-%*XUƤ&'u,)\!HYґ[Wu>Jj'Q@*i՚6*{aYcW;vM{l~#_o)%+~=iڤaxܳ`omvG:501V.(O 6 "e]I1_J98i֬WQ_|)޽{cKפ{U.AI i7(x“ϺcZ$UƟjU0ܳ{WVZ hߺ%:-@J~us؀Z0ѺycH>r1E^TD&c '0-셵Cm-q62-rwH)[6P/O㸋 {CR&*&s<ٷOi0zA>ct9E@mOithk׷`!G-as@z5DuAoߺ U\m?K{Uƈen뺜͡|N^=ϳLd!Mu`.fN ?2Th-ü {eہALۍrt/rt8qxL3PVv6!ZU>aÆ;ٳgsNNӮhNW۟BRb9y*ծa!՚t:Wiℋ-m@";d_C_rs0hj0/>>}px`,b2*㜲yu^D|yg㣨ٖ^IޛXPłbC^^_kv^*/JGEQQP-Jcf6%cHΜ9z]:<{ZU!6 Bۘ3Gjg2u.&c/$ EJ "eg#!>QBb?A]b{%l4 0\,W_}EII Y-ZДncAN\~x>(5s~G lh*;MFWss"II?tPPb#1kӚmZg~TcGc`(-hޣ*C):(Q9O?9j8g-*BaUͿ ;H;hGKHQ!IoNQ}Io0@Qh2fLij-y* J7A ?!_]z)[zԔdSINJ$kz<_ ޔn9!CMMR !B#!ECk^=\q9gqDž-,Y']7s7IVeR"#w^~zy=n@ZGe2.7VY,'E;xν& ~\I1[Jy[mmm|=LnRcwQ{L1ں:bz^]GqwZ:m8I &IOf>|Oˍ ΀CN +`MNJd9n%A\7E(ҤWGOihۦMЫD-i)JtE3P2Y=*742IYigc ` -?ʍ3|?YԿs |rZ 1E/CMo>84ڝ י#O?OC.8?|!jlJי_fsѽ+;v 33ݎ餤;ve@c<]b֓ X#C&PD7oMIJGcfYqQ9 ||II$%%Q]]þ}8iٲ%lٶ"^TًΝ;ً]vaXǤ;S:a~\;#}>P"U]Sb>"8j C" mq8{oR\t6p@f3sϿҲD`<@JYGM["k׹#+od](LYBxU2bd< IDAT_vX{NQpjrd iza'|0mXxԷ{$חQA̓Me(*R`.p7:&5vCsCK)[@A^ztFz=8lL.Qҋ1]|h `8xq~X[2u{?U'=5A/uCjk ^+"1 &TQԘ*ͽnU4V/>Aeyt8/z F9bhx172,5g b0XUCdRgtv)))!ZZ٤ܗ!B&ѤL8^"oVX hʧiGDu72jE,h748Yx-1{3a/zFŧS޽xƷԛq㜳E9{^MzrAZ$G.>,d~{ )!୔H,kV|ͥحWקwך&^"mnxa μ&?9't 8N, Ej W6_M$3p#v,_&;-(FGNסU0 p"|VK `3!OGi'#4h뜵>zCFskmЎAQ*(BBBC-ݸ(BBUBR,)eK@nɗSj#7ϋh}ڹ1q!P.—I {QPiZcپUsNF%WTӼ<*LŽ;C0*+O.6|>y`4zb Ohvv& ~J^/}B_|;onNF2.+/gQk"3?x$EF}K]?mZtE-͙xLb\pl,^R_7[P4J L y?4۬DHyAksJ.Js`ϾBEFj"q&Yݯ%;&aXn2PE]8Fu+dey-[wNocR^kQ?7>8<r%2^ߥ9O  46mpeJ63N;n{.Eaw˯?򤟵Po2jU _CAj!ru[#pH)PӜ4t0g|L=مC030"E JPIswfX],jo+Mk;w͊mΝkw Xv.{q#ս+fҴfCjr oݥ3Sh7+$=Z.3R>|T,8JI]~7u6h[o^ ۫z Id)U3\}tusUJ鍣|(nbԑ @@YXTċz鐍RSRg W+T FaU֍&i]L)0h@?ƍݤn3bP.>o.mPp *i2ho2=(%'<8Atkd/\wcy28A.m4Jѯo4hk@>f 73!Ju%EMۧքp\#yv  ?.AJJ qq቉ytx;4 )Mv99:mrgin C?5fh f%FƬ?/a1E~JfכQRJ)eJ*)evtJ);J){q9}&00!;4"^:k9da/j3mۆœ0ɤгr,h@#N\nw/5NrM67% _aa!s/ O_69,֬m{u] H ;V%r )j'ѻn LHqOKtEf-42ٟ^{۷rHZd9─5 ͻg v=ncz{ݳYeHvlg/\N'e~Ud)d ! x!sٽP^ :CX,fE=IU%^HNN[.`"/T * Dv,n6zӘGxh,2٘LyCamNPW_Oee%es&117v֮W57vFoĆM),:pP ܆mVJJJX,̜>-Vs뤛P\n.Ϧ$nr/qײovګMXZ#0dZJY#R:WGu T`-d~ BȠ}'-+}f#ޑŎQw߾Pi̒R]XX޽{i*~RJZg/<3}F8iS_\%ٵ^hQި) lBhocm,/f,U~|2eJ|oeHNJbʇcW{؋ xd:UU:T25Qgh>~[ŤO ӌi=K^ B PZW_{o,<8KOKcOK_PYYfHkog`>7v؛LgtT}wRz0jjkipj=tx񱻙tݥQH7?}FpNcDJH-€ `>`Ӻn5lEW#1:Qg*5EZ Br7{쥸%%QVVNEe%UUUTWl9vF:p9s=g.9',xDH[ϟ磜6{/3s7~&.xw<1m8&ތ-\bկqju}zt'ӻ{7v#h*uR(A 0Y^w(nf{XׄkFrJQ 9n@L >nՁ \#}/GF{s}E͈\ OD"1ɧSpx =ׯ)JW9ZILP._mmnzwҍuW]2HRr>;nV )w~OƣE>z-@i<+'Ф^ժkT&F! XRSx`:W5X02iӒ5NlLMOjZR&~ٲqɇE֘Iq딗sM7vO?4 ?A*"YN&hMOKiY*khӲR fWr㕡uF^@,7f:֭_O=NUً获oZ$Y5BUb9׬6ޥRʙ%M.bucw!r};^{Y&q +w19&}y1o{L9~Y W\)AU±6s~1Mwks{aXGM GĮ)L~1 &;Q8{޹C?XUxBܷf%Ρ;-VnQd޽!3=-jfAJ*XZm:B{UC JeH)H)ϘI^={! 6=0-:cv!RS\.W;1oVTD,ߡ}[ڷk<4; ƕ%P؃cm0^{M^*T^^7-i$i:T+.4"_o]wN:|R,՗KۄK wp^<[KP28](xPv\.wݽCd1@Xı ,'+%x_B644PYU 㞯A>(>PSϿS˯h7`]52l@RSW*,iR{5pqqԱ}!EX02h tnڨa2bu_,qҴf;&;h2Nx|b?{aZyꩧ82_il͊ͮu>s~~:=(f^b&ڸЅj~L|>߱^p]\YýNt&^n⨗D+ -@R>C.&O8Dmyա(W>X paT$rHmҸ 7! @ż1TT Kj~a6l6̎[>ֹi#jS*^bE)=64x^|R6121&6]2Уz!l')e' O|DfZH)&uvۺ^S~ h5riU^?1w'k'\x2+CjXoVÄçRJOi=g..O ܡi{?n ʉIuƄ ꫯXvm#{;4s-B{nERc@(} `dX߾c'+WfЀ v Xy<-B "J' ȈkMv!R_a820l>I䋹5-Y3 3ӒQ4b-P(䫯g&B6[$l>M;W9W+G*;uQ B2xꙐYC,?-x0hYz~CN4*G%QuN3G9Y(0z xtԑ.$y@E)Z9/ dDS(OaBB<1nD:$4](4ogf$dh#aio1X o"hW U0 PL)Xnc.yr3N:rHyF}Hfp f%QF5VǑxLXϬ^&=iHA拯^̙3+V[o \J M0ׇϧ$1|0}v*\ЈuMPA&!L'#W(7^pd \/r$s 0 {_>ŠU `Y7>ξ-&[Tdd0ݱr$J)G6w?pe4`"%gڵ* f*KsT"%"E P^QAeE%TTG{rt:q9]=ӫ)هIJD}X-l6 ݎnn1ԯWH"VK4߽9eQzBX^)!q&ҟ0bN:R"R^ \2块iA):;ЄP7%9 TFL=#ǑVSrcO<8TiPS֬cf'J $fl IDAT"~^`!F ˶mMѭIG_^|k.B_P'Y `TcLe`CpMfpz3,/fkZOb(`cЃ 1p&\:>,D#Okl٬<=\|MH)SyZ ^Jf?(W[3nڼ᧝Ae,eiLFaZDb7%bҭXم~!ji96&D2 \v<"IICq0mobBHP@#0[Ϙ "IӚO X`˖-SًA2+^SSק$8oA26c]tb0 Af/bLJ9g|z$(8{!{a]J(*_vԟ0:aGayɯ̙71>̍ݡu0/}"~#-y^Tpaa luBߧhR>tlZH QӢc6N 3/H.@i5#:ȈE!̂*jjjuIJJ"11≋paw(-6+6 o?=n. ۍ2~ܘ"ThO473C[,#([`*. 0TpbTr.y pYYA {A  od(nUM(P\KZrC6gm^//5E?^14Ks"r>q =Tpg.oC cy 0c4ksGq pI)]:g/S\vbf2Et v"sGHӘ'Da&%RFLT8vå m3kdl_}R{ ן'Y5hWW`9!CX`HwJ>˙\|7f4#I?dԩ8TiZ[Ff셦\4PSTJxq}#_z9SDBJ墨 )*>@IieTVUSSSK]]= N'.׋łj! >ARR")IJv Zfe2y(Nۄʀ1fCgw_cr)p/…UKc7x=^Rw/{E(-+*kj) GJO۬Vv;qqHJJ$-5T23jAVY6ġ4vW eGpޭ`47Cz&dfdd0OHLtnjyG}zƋ#o1B }̥}nk>!# clLuMu#@D*㾹&D8p靻h_K4cDROݺ["1>&P4ɳ(L5EA6~1ф-fǗ:Le3}^NzY-MAȄGpuDSCW LY 3]%( `50) 셔rmD-lڲm;vcgF⑞B6ؾ yѭSw%mkՕ::$ՀpCp CטKAp÷ 8ac&1wBƎ>ɍ>]f6o&n{;_nѺU:Kt܁]:- D6wv{|J(> HnՂO?SS9h(=5o0zes/J))**;ⳏа(Z>x'ݳg4nW+^8 "kEd a/x=5Qc=YߖWb #iB 3#4RSSHIJ$!!8v͟|x<. Njj먮*kqjo zù>ܷC -%)${QK4xKR)o"fFâKF5,j`zϊw\,_%-cYj eaCBB6Qj[fꏣ}b` &1R9ɟ#TPVahykppM16L w.h06 t@jFC,@nמCBPDCaZ ھZ45"bXKItXon[~%rTBR*5 TVVR]]ó/k׮L0_PiW6v N|ĄxHJL$nC_<tشu  \Dh"xK;JJKYz-8 "'~^ʪ`AB65Nt@v9iM-HKMQ=7_rr:2ϰX,mVhCJNJJWX̞E޳eGvPदWUխ3 ȓѷ{gՔUL+K 4fR9cu6лg2._~&%ݻ-;v C;&3#_FW\RBIITVVQS[Km\.i#}Xj爤DZegLFZ*-2i$%RX|{ ٵg/waoIiY;ߺ~N0A:e(CfMF?NҚ ciTU .,&LV+o*WL\- ލn~@_je˸rL{>QKϨN-ҭ3G7#URd)s8HHH^ *ę{dȐG5[4%Gf4Rʫ3vN2 0uP}inʾ@GX Ōx23s!Rʾ2 u$ur:olٲ;wQwEŔQWWa<v'|->2L {qqIMI&#=̴TZuY̢Ml"-5;m|!2Fc\a>-R"բ?3h`?2Y|l\P1x`?CHKIrsw;w`/-[bRZVNEBz#^RSIOM!+3nEN,b^nEe=ʪX6M[wX[yCsI ΂BqwN9G-%TGS3O Ŝy |t3.wHnv8t7Aңk6Z6mʦjvͮ=_DiY93.ZdȠMthCmұ=CqqmH$JYq+|FV˧Ɏر{1TƜ~2InuZ6^:ZVQrYeg/ %Qzpqp8[\qej>%Oލ < s0sʛGرk8IJ+ .b(.਱"FHwك, l2Uu u{ .W2DMVyٱ^|7J!؉:]!%@ŕZ* vv72.Ԥ9mvAiJ<{>zE5"9}#4~{}^}=.{hn瘎 ݸV:)7FMVҹ85“-SJ`:d -Z̟+VR_ga/_ΰaÐRe>RINL`"~5P)%4:kKݴr)AWwQ kZJ0Gno׆E?yO'3ҹ#EEŬX56>3`GB|t*}1Ep99d:uh>6oWnul߱_鑤6m'%&c| ;rhpSʣNWTm)1o؇m[) kYt9~wv@nd-nuWu]PNj~zL|p㥔w֌ MJUDH=wuU5t6$. xs_t󉾙;ED}iSa ANJo3P\%Bo5&eGdxJ4!O-n*B p ia6N;/?. vETJ+>6 +Äp@FdH˖شu7o`_Qz&Kv8~#OĀ^]XO۳FUE0ILicE ><͐ xHR~tUsj?i:u| ggffpܠ ؟}zҷW2M_i2I+cI?@E"9w7mc͆ͬ\uƜ~2;:!,mOk6@Hc"`h$.9{/)B:^~%;{"H/M.M5{/߮ӇhSQYɳԙLj!Ԅ>7J ; ,ԫn5v'=ueWϧ KAncWoIXX-VV-Si~A|Jcϧ%^<^V0^J PfWR !gC7b< 08o~3AZD͹aBt@b!ķRJpsUU5ÇHNjjy ]}G\\m/,$zmNk,V ;vfæYά^bnC'4!4z_ l4sܥiP1HU>3( x}rr'7ߧ' z Px7멭fqͥY78cZL-LD&&ѣKG2_QY[X&?Vo`-48]lQYdeq)CwQBe,80k+}&@I%>>0?f F0ٽkc4_0cv9hӒ3G( %Q젢Ͼ_cP gM N=O j2-B^:Juu-iśoE^\k1g>%C/!بmKq @f،ͱ6jA\4 WOښ  cç]X\p9!i_~^/:tk?d\eQx<98h*?*)I4~/.a]}wuhH[z +Wؽk>c$g6!ђs9i%l%ee^IEpXzٙtmGY R>t RR_t%?.]ɎW2QOje*h@ V5OY:OuhB eg"3JJBˬL.h,zup8vm6~= ڻoėkO!3gXpߩ[@lӯՁ =8fL;C$$RW4pqYg#'' TVVRYYit U :o^`Z!7G_| +CJ9Q*rf fJH] `ٛj2x۬:$@НN O}$ZH%ԘRb!vx2RٯW7:WK XZݱ15"u@@; IDATй_cDZ?a$+Ə;]:=G>dv|"IK4`2f[8FAqd֕}n]:Hs\U6r5ebIKM@)+>W!v}1؋Pf Ipߤ+غs}V* RGWcV,Hëz?%2v'}&u }{<`P1Z}USy|6}=0F 03PU]B0BW&M- ҹ s{ƈ_V-۾-=v's`ZxG8i2 EI$Jf-1j"6umKM_%(m b0J~p8N֫3'8{F v÷~b.ثF0*{wP)н[IM sgN9~ ]z@ )>6LBB;FG,&< Fa+p=p0}mܢ*Kلy'J _۔;IdŚ>O =Ld:U5vJM*!* r U6a?7k4gNzDNNml߅?ʝ?GrR"3-FSfJyloPj+Ơn]z'O&!!'|G,dZf!`>te99ج><:|#s!0iyP±^0L(SUVUvFmpn:{!ιǟOvt X~Si^U(f{_ˉ`4!\Rp/0t1l p¢ſpW'qcɚuxϳϕybp9gspDZ"Jc=ɓٶm]tvүWm5yKo_ ݝ'=D9߭ZE:R֩Qi0z|~PMkj'+aX`\roHG!`c`x}8;VKƩkMix#qmw[-sKa$'so8D2!p>A,Lv<;5}9* $<x=NE)$ y؋~ڄqեvOPP{ukdo]w[vg:u4|4l}a4k24n~} )*.nc>n&Nȟg/pbꗳU0BXpm$%%Hrri)ʖBfz*deD0kzɄۥ@Ɵ+VӿoCf/ ƞ[|]<қ?Ν?nj p`6laa/?;J)ީBꢺ8v۱r6f77M~I>{78Iر#%E\-Q;A~ a02%Ԝ p09署qx+$Ifu0= @itst) 2RkXǛ nlٶD|t.[tgC Duu5VZ-[>KW.ct"Eƻヒn /bB "~W>W__/6mM 4̨5Mg&#ވAI`4a =`^h6rxKo HP`j1!dhK0d"RUQ/\f?y[]{nSE6 B֥ݠA19Óc~?7~v?iCR:\F"@(A_XNa]>Ht*I̔KP=~_ضk}ÈDKoއ  K(Ņour1. J$Hqe06;H@a8x35ԟ\,A%mgE]_Wx衇2:}曨K^뗿xj*R\Fgw}xGi&\uUCxwIeR]zU(i)F%ؔQ#+Qf(j3M}zw`f?DMܔ6265)S4C`6 _~9{pW Ƅxw } @dȲl!<$ ,+el$!}F.TՁ|GIBR3# xp:O9pDix5Vc˰/a7G`۞U4uQU`0ϭc=L&;MQk+^U2xW!XuE{,~X+bJ+:Fq=EiaEpZ,kpO`36;F ?`@@I#p342Ii >) 5z_]YGJ}Ŗ[?@0B LF?—.^l#zP4vAhtdkZ }{1bCݾk-F׽"yn8|0`E髫tp*n: >`(pե?ia\K`<-^mZ/vI)2?S=TD>!J$}A8N`Lȏ z.BTfQ!h2و `@UZ 5pq-_*VZdz~D\)U='ˣƟ FNhE"92lR^>BHʡ 6fC#E77\} nꋐd]=}{/~aEn1S&VB5J39F| mUDcl kM#TbRA9Оng0&QaVǛOD@Ӎ\5PTU6,c`ЇdxD/@2[#S.!A}͉8oݴ߼CaߏL7]VLK ܅{oNve%EHIA*ȵ"ozϽ Gn׾e`tǓAT& }#ki0ىʱ 3@`OWZ g 8/@EE?5^ѣ0PSҁ{oAݴQTO=v? UP yF bȓ1q-Z7 >Ҫv9,/' QqJQ$ DcQBa! G0}Vj!NVvy Fm = @'7dUglnaC> п7yn$J{FmUZbEg 0 42xO!(#43wPBE>18( {̂RJv91ovCN1N ;?>$ЛJTCGOQPQBH[yuP5[)AYݏ7~LE(NWS&0A3J?>I4c@sL$8kiQ`,?JG/pIR!PӎpSoWRF_#9%mFӕgߣdT)!KUn%W IB"G<@"@<@,C,G,TML5*2^ބN'>J:Ֆʽm9نGG<R]׮wy'*KR qਜ਼ꦥX<қ"pPݔbJ0 :rڷ0#(%>37 Ja{ BGW75^PP8>ttv=}|~?AaQb1qrjb[app;ssBo> (-.@yI!*JPRa]p$`8F0L{}*_E1GsAQJH$p1,i\0ݡp a7aB0Z P5홇MM{v:s9sA׃‚|x\N 53HEm_Lһż1`oy=)[B?(WE7^sΫnqNL ɲ@$!b`p³n} Ho͉xFtuʑ)~2]s0F[W(,L<wZ9kE=A^tъSEQ^i, i8ʲg^{_''{6@l+_8uu3QZR B@ ! ThZ=Lf{~or"'.TVVo u(p~_W@|2X C?=ϿneYxSa٢x[wzn؈a͗,yyn' P<%}#8܆H4#(z0:'@oqnPB'u&ďCCGp1k>`琜2Cnw6D`FM%fNBj7ͨaF Q-Ԛv"8?PahȠcXp~.2zqx 7@6l@{Gzz1A,;-#E^T k*1 3j1.u `d4ŵ١jș2`-׿a` lvyx%󅭡VS (ϵG#TMzQ@+/,Cd$qQ0!8z&Jiߟ#N`g} ,L6ꂕ뿢we؈ZCS4ЈO)= `Kmė.\-` D$Y§ڌ5T6=m[Wf2@ΖR!… Xy ųz|awh@Ww70F4((//â3W@GgxC= 6?<[wD"FGCS1, G"zO?2V_s:,Z0axMYI!o߉Mp=}v'E^EA~6GR:p_}+59"2V ^6hF.S"4lӻ`߁ؾsd1Ps%E(*Ǔ(Bx<,d RBJ#BaC c0 I28:݇wGmecYXp6FAr3PrFQ-dQ(& kAvڃb8t9F< ӡ*p Is,p$p$#*P8l۝FTb,7EݴJp'Yi593BNRuud$!$#$Јe@;7w\lݺ5╨N"AO=b^Aڒҟʲl*%+NUӘd&-wTgGӠ$Iy]AWVR4tJkg^ß^|FjFbUgJI%X!vQJQaa܈׃/Ck]qe7SxJ.*}!;mJ !R^TT%c٘1}:*QVVBpf ΐu]^xK,!J^ZBG~(FPJ+Bi5UXxf7@yI1v8$ T&R9~K`% DQŠ2?ĐϏa 'ڻ3iHO juhqx驡ZmZ|'5Q ~TU8_ѳahC(A(AuAy"78(zъhBWOzDƅo!pmsPZ\bTU3j*1"ϣώbGNf|ާ1ZxCy<97!D!.Uؑ bd+wطzNh$@iف(FS `xX4 HT"Ts`Ud8ŘQ[ a RfhGttwv834k'9b:i\$99E[e$J2#YB{[;nK740!dX.Ftc0N)B}WC)v }˘hѢExب սgzf P rS'(ݯjq"[5Z{V5 lJ}$cR Ɛ R2P7cc]:6 yn' PX7?OiMm"DQL,'sq%&   a$?!}~}) r<\~;?8Lqzq0mMKp $~ ?;o#tN|}'v9#0llxσ#Zh7I )Θ Ϩ X8Kn݋/o498@:O.uf@tK1"p2rCnJyŀ ` ~52nɜ#FZ:`L9PAF߇f`haJJ2\s7'!DG=5dxJc wOE4ZP[BH `cSb&+x(R%?2\"@ .Œb~\`pF<=6SJ59&@Ra6G _~zщO(q@*PJ [;BʙRe!1!p"}&MSaR!;ȣQ2d "52uoZKCeEXpUpp()-v66Q QqըL$ǓЇ^;ю-md`1 @RAd~AS<ƀ/v2{kmhvÜ{Bj+PW*TU%Ņ(*&t Z %9bA"G\mE0<@[goLu0믋ZN%}JlLz'ڣKmd6ANMsxmtAy: BB&CKJr&xaj#lacJXǼ"Gqi$iIT,fdLt)!dՁjT#T3X ONSc u$8!FGjLĐi diaA5]_V 3aMbT՚nRaG$ :[]a/M)&=2LU%SPV@(0Ϊ$G+3I& 5Os)[ܝ!Fc{OVe1F1AӑA ݮw j?:wKBsdIJ}'  Dc1;DBBۅ5q]PƐ$I}v8hB _h 4h2)5TOz TQB'&cG'Q#: Yq q^L yJ)(L g\ x^U֢l*xYo<x!d4 Wa$8̋hN9cx ta8H*|FQFfinG`*wx!Df^Q12M*@èU~ fѨ͠5z )hhJf[9QQZLsH&LK1`4Uh^:ϡNDgq,AyAJ[i IUKzem0s|ZƗ#ƐuV6Γ0MOuL QcThd]r}@0ՒQj<Y#8VBȿg1BH1|94+\~Ȗ;O PE&ѿ OhAoh<[ b.X[fFf>0d08"Jp6lj|3p!(2 `H5%.ELfE&.xeJSxSA,1 0#x:#өʪ$( =X`?xS'8&R"9/nq`苼9@֣%AX!9v=ЧfQ}!!=!eUr@3kK(`\-G9s36hI O67.=$E=ɮwRCzM2LYu[Sc%<)groim#pT"RӬL@Uf3rbHghFһ KPԣƱ.0qR>Nyd1 & BdJ0&ȴFjMi+H8lOV7r*d0!d,(JL2 :\/6cg䇾8SEٲHEφ?]LE5fJ?Hq/#c#T0F(B6GƲMo!!Z_e|*dג80F]~YBCxč<:eM3 :,\0J`$LVdzx 830h+"FsLxɉZ3Iv*2^kYs$yJ Z=Q9G3dLSl%Og Ѧ }0>3v546QQ&yj]t1~T^fj} 4fzX.FaZyuVa;p]kc0Q0lcgfQ\<Թ|^o5``T48f`'͚*d: 8sl]d<"{נsv>J6Au<{~m\"^ik."2ȣ`ukMq![x,T4B&pQyxŃ \: :zB)dPƣD9ˑ `H3eMEA٢[t3)1  C1&vyR`@4@0ĝ}6LZfM5` 3SNRx,,e汞P`Q2 etv`gf(7 jp מ,Vc@)l9G1iͺ:JJ  |f|kȡd@:Y9?p@ y0k#8U6ACopy.21TgzmB{c:]iQY/,dE0,ꊝ|V.U ɰȢsZFO-y2#Ɂ|+WVWWv,B0uvv߿lj6,0:F?"&ƱȢɨsn7n|y#nk,Yt=ܦަ~on|>ߏ_=ef!5za,`\`C;y,#sbT$zM-Ť#<(l,O$~W(B;b8:MjR,8: N#D$,1E&s&@@ t(=f\"#VTd|m^{*Q/8n>!$OjժUoVi/zGa˖-\q8Eݏr̘QH$me.$ZMEY  l]};[ +|nڵ߱l,r|SIص  >,֮]|i˖-`GWZ;dg5'٢/߾tgvYUUuE]5Ƭ`5s= .$ TM-pBς =d@6EO-z?!: IReY07rdXk3ut"yn֭[!˔^h<;s[/ DU^`oWY.4F撕w| p>  RlyxX V"ZbyzHfX4 (󤪪 89xpKO>|8IO͜$-9 Sd,^ꭩv8<B<,sRAe"H$X, 60 VKFy~K:ׅ m҂m۶aŊꪫ ´/| ?{AK%E/Ǽy0sL5%+ +Od2h {*#pV[|0vxކYJ!dYoڴu_4`Ikt,:3 o%7oZlY+qkk+HV;wbtyOՄ#,L[Bu+ jd7 ׄzDeYgׯ_;)sDR5p(H5JJ)mۆ~vmlW_}/~OA(@ v̛7uuuX|96l؀ n{M7t˺u^c!$^WWW1o޼Sm+A(8.CqIzΏ?x;FdC`4byƉy-ť l.tuH!߇ݏPʲq\]YY!NAlB۠RjWe|~ ,x$ CSSBv;xbw]GD"0EfEFd~#{>+Ӽ 䲟 G*_@(xA 3gzu~_$ \LpKm&Hd^SSB^aٲFά-[t|C1 ̥dxz&vТs `D&g7JU2Rfi&r!fx7$B!%+ yfcihh&*`EL<{=@.++oR$I'hۿ;ve,j:Gᘪ)GA@yyyG{g/%%%_{xwJ Aqq1nFQVV]quvv>+WGSS|FGSDii-^p 6çT}DC0(7âUUU_z̙)MKznjjʄ^ϯ[fZjfϮB,Fa 7ojoJW*JUy,aݺuxUq7GUyyyʓ`pW__߮={=x c;R|$`^lN'z]0t (BY">#L6 wϟ5 $ (^|Ew}(,,e]{7p8ܷvן~W;;;[y%%%X|9:::م~!FKK;NW^|5k\ !l hh$L琲F7=#EQzDh˺u^@zY3 B=X\x\݇ߵkW/s>3 /y^~~; ]wA$ !< /7@}}=nK/OPr3 nC={V_{=,'X,vظq(QC2ehJG0(((/UUU].QAK)0"Hy-PqFypR31 )z A@Fd.;QPD^GxA^o뽹AF'|>߮[ll`` Ԏt ` {KJJ(mmm)|/cڵza CB|peaɒ%ضm[2*//p͚59rݻ7f̘QU^^^mQ__`'s~F,Z4ς( o|;߹ȑ#/kE0,(?VD"ݢ(^r@CP(b'ƙRJYb1eyi߅+V-ׇY#|ɣ[lis:nmMUUե>v؁;wK.Aeeǽ 2=#}TL@!_&<_Y#<ϻ<|B8TTӾ\TTTlB&{R .3gN]SSS cKt:_<Т^h V(766/nA.y~9!{DCCq7,v;'"@$)D"~?¡P(L)P=QS E\.Ww}3"B,GeYq8=m'ObжrHhjRxB` (*rčR7 8.] w555ؽ{wK< ==K:XoT4L lܸsUN6-`(< ^l68q$5k֠h4 *̙xp7p566.ljj:+|z;vs'.,\8exwatqfάf+Y` ٳgƍC،Y02|CN xUPPPpҥK_ڵkWɚp" (jwl6[u}}􁁁z<w1]eKtgGn͚5oBj^``` (¯^{l}(bs50G Nh7rQj*BfRJ144P(Y!J( p8c)H4zMMMQ*/Kcd$P(xx\}l<7MMM} =T"n+2Cf<GooՃ %=d:á4⨪; rT$,x~szgy7i5p8+r$ў6ͥy*R".xwm,fdPAY#G.F۷wKr˪ރ,hhh>|9\h-1r͕KG!H@TUU6) ʀ =8ڄLp5YpRO> Ëb\Y'^w%&PT !xj!"+˖Âu(**馛{TnuѼ" ['`4`,{!OhFrۇ^z)ar\. QRR2WnPJ7@ >_> `dDQϩ <uP6R dIk4pڊ6tttLY)/ϝ8qCŲ ڹsZj{oC\5I@D>E@`) x_\y$2zz SL'v(\u777?ѐbbʃgNڲ25\+x駟ɓ8y$k*++QPPQIoo`ڴiXh̙ Qņs[[[}ݝ'OJKKHx£߇z`7qgr#R h]hV$ ȇɞLy>D09ҲbŊۆ pȑdD5 tlE駇O*BqJ'Qpذx ّH$ R׮{h(Gt.(rp:9x<JJxHcϗ#68kDzeep8xbac'MM͍tyh-k[[[[o+UMRaj#geV<ن͛E|RsӧOo{;vڰaiӦ5\.W\WZR FBCa=*>j@R '`Ъड़n`ٿK^pw|7{߾}݌F !NtC_O<kfx?|';m}}llP[[y)noI nڴ0 NraI$^0(fH0o>_~>q+>KIS}}}Z:c @9@v|'!QMl&Á5566joo߯sobY@EZd` X"ڴi8[qٳg_'|wCCC ]BcP}i5yaÝI𠟃a|^mBJ=OLjx \qèSllsdG6u*qoVhmr9r4'^ؾa SFh:Ղh4*(T.ҳH<3i߄D"eHAAA=aWBj+;hNy>j.pN5@)s=B"$iQ*_|6`mرc'.\ /^;oƌ3wﶼ;V^"//ϙH$<`0 <DJ@ Qwb.Sy'Vrw(!522{ χ(gqq{ۏJj#IwqECCBX,͛G M7]Qq?ߏѷgϞ˗v{ޛGGqkϯn}EZXfX`6ll ;6Nr$2sg|;9fc' Ƙf7b {w-]ժ©sH*Uw(СCvZ.NS\\RmmmZPw``矍9 immWrrϳ1g,9a0Mkkt5SQ Kd]POQU:Py@Q4d``D$&&&*Z|9L`.xgׯ_Ȳ /voٷoq9ʾj~$I42('"_ y.f&fNWdZhQ>o!-ͬ7ׯjZ)F^[}% CXT15(^#!`dGk7o, .^G]];*+硸8 -z_mhh2'Y]444+++fyybj6""ms8B###NY_tɂ?З---OOOO8Qo}}𰠈%EG̙ 4L-VHa#9*=LvU)YQ/1 S}}3O{Ķ?9| J;QܷhBMMTQ h$%YХg줞Ѓp0CQp8xC?3Uvn4aLp##,]e7o$˲SᾝU$Tܸq#\}y5#p9L`5|M& (*f >sOG0n,KX|+TVVFiZ:,-(x$"|>~`ITQ<?_Wa2#͚3𺅯_III>? !Q4MKJJ];r~D}hM=Ͷ0 UQTPΠƆ.p t~ҾN􃄐tY}J32ĉ5`,kØCΌ IDATK aZ+֯_4Z#ϝ/JJUqĉ(FJJ s= YYJ\3qnhƑ#gAR,]Z Cl^QA$3|>o' Es|rʕ+5/RU8cp \ݾ1???8>>~ڵk;vVUЎI~ Ȑpcdd9>>NL&d2޷ ֬y###úgϞ{f"Uł`0~ahhgBFF-[$opF*@C۟aT t/Po&EL&fݺu?(j,ػ}tuu+JDE@>6mZ9(**ZsN78YdIҥKw }ػ0DQ!4{,vj?#G4@@^n݂ʧY)YM{ GZZdY9А3F+LLn e+CMob %%0۶m{w5#Օd}sPe8r,hda5:< .1'(|q?τY6|R$K\9xuY6SDT2>>~,%%e[nn.$Orr2R`A&pSnn&r].WeYl63f&f3 .\pM[_\c_|...GZO7ӅN`tt ' HAFF hbGժUϟرc/Դ!̯1$ML2#Jhjjϗ !$!!NkhGKK;3 DQ x~\91<<"k#`=:WAQv{HHn7b1#.ϳ "I2:;Gc8*hA$ j {Tc׾fGp5\|6E,vb2 8r8;~Zf駟}Ѯ_*}֬YvHbb"Q\\{?(GpF RS($It/$H0.8yo Z{b  H7 o.FMM"atԃ1ᇗyM~`uc> /7o_~eee&c=q a% .Wё~p.u….Zf2Gy!֮]s?AmmmE fnkqOuuEX%lRRdzvX, q,˲vvv?~AxFo 4zΝ9iz5q&\Eoo2w9NCChm!L& Q^^v|~iio$)O"A\>#0pձu֍B1ek;#H@YۧO߀Oq/}hk\E XVջ, J&zn.p!Ŕ5 .f<{;tff&3Elv{37044{ d^~F"222ϟ?j.,ѣMS8SK/Ȳ,|0И5/:LTo|clPx 'OF CC(ܹsΞ=8 -emm]|-W^yf,˂2!<쳏.E4*?_;)$@c-|)igMqF;PXKKssy_zy^B,:T1{ŸktJ(v2 O=7hc5`2>` `N &`qRRB8 ? Q@^^fTVVv5我=_,ԪU쩩`޽4 &\<xCaa>L&S? \Q=-рԩ=;G]rH,AB#TxQTT'x"\;j$Cx%u #V`{.V(jjj5*I,~onŅ(={/*o#F1|Gmɚ_f0 X oAǝ5`Og/E`6pࠤ 9e&A35@PW Fr`Ճc'tם싨}۷P`}> Ä$Ӄc..tvc}}'d&9{_OGBI{k𬑨N%|Qtu@LCH 9 Yf͚R%4Y,[EEp ݻxa2 Soo(" \uLWLR/3 Vժy&T89YBlf|Awggg[KK4 {b"tU!yz㡵uX ,x5sE Nb>eU~h ݓelLA,%z:c.} !Ze90rsϞ= `sx7pa@@WQ[HJJ*߽{W !)ϲyqU*wUa(t@||gcZ|tRԦXEl`6U}Yp Uĺ?a}1 K 06}_@r!$E=zt].}ȧ:澒$ȑ,,PRR}Bzey%%@VV*B]]{F~q,0h}K,˾OA{{.KA޽1::B6lX.@Ѷܸq lٲxիsg@QQ6mڤ([Ç)H1N_&~r 7~Nn.&ʘҚ1X.i:ڵb1ғJ ې(//B`xx$`Xe*Quf0E RUpV|5(ogz8^5X GB׬z1<RVeffx? }}Q B"7'Ѹ| ׯɔś7o^/˲]24opPd0w違H~? 0b9c6a6`2`2yuqXq8 ÀaB` {(4@ L8@eH4G ABQ B$T*#~J)S%jeYP FlJؙ0fddp<jjj0::\bn_ 8y,$IFE<$?۽^ol6+V,VRSC2ׯ_?'Y8+5zWPU)0w8QPz(poToo/N8>{O?dž + =HIɲ'1{v.xcy䑹~KvyfB066qz[:HՏ-1'OEQTeh>ϙ,IJ)$ 4qTE<2>ڿ\inAvv,Xի-^)2 ]O0ɶv; +p'ွyyX,8LFk+&<\}>!Lxe >꒘hܹ -~.kNfڬ-?c!4;BfǝMoqΜ9eP^^秺\.^JKKrJԠ<e0XdY 5 .D}扡WZ|BrEQ޽ I"K#(hfGqIl޼))X'O^Ҁ &oIp<2dr<A:u eY޷oߑq-H`hz.Qͤ&IE||pSii1Q_`$';pa}ttԋ=b8sGl6[47w-^dQ3kFZ2(u4M/+))FSSGR$,F{{Kp2A^ɂ/Zۨ<*dء&mHMM!!?|haFA=Zp¸ +c `8^(`Y#وhaO~![HIdb/}K}KQB6g%Nb{/|hkjj.t4nC(**ľ}ruԁ,Bl  k *lI I2$)H Y0 nk@*)iiZ*RMhZ'LԿ2h Cf w0(̙.8A|YQF2b1Z#Be_3gΠOSoNCOv\Tŋ硬]]hnɛ(&kkjn`޼IAAA^x|p -1F F9wÆ 4M熀K~W:h!BDDb{#11qYaaΝ7;"X BB:K"Ĭ:I œ9 ,A4@b0oKb͚7iW2ܹsuuuLdx4ˀGI@Ɲ-:##].4Fmr'o,~k:tldeeimmP-gX5ͼg]fXSS3zo޼m6ۣ99س8pΟtx<ݡ @,kDݭ$턚LkwYg,L&& ,B}!Blf`(/ODžXp!ЧM3͗*--51 (FlSC<# qw7CGO ..xGrqBHQ=w䤤$񈭭C`P\`APggg0$ Y,PHGY .990CCCaIZ=1}aٳWTU-Fn/"0bIIg/GW+{h"8Ȳ,;vNeNw LX3Ę7{k{~cͿy~qaa. sx\oA7"_hnnjoo#Ԥ-P<+MT9H` 46hkkkGSOm|R^N8M`c@&Y ѣ\ˈHր>m[@tQT@ڵkMәX^^BHQ%Itыׯ_м~$1@LL. Ũ.8׾ͶP_߂xOb˚`Yyyy?_'n 1W`u 1!G,Γ>ûj޼yk%Iիצ-"|*'4 BlrVTkqEg]C hrQ5 O=1cq{۩,tG.YDQƂ9 XCC[e?&4]Tpp),l3a nݺ@>}JNсlF|| IDAT^|INob|MF ߢ_hdpwC2q"!vc0: @CCCwWWSBB⪪hoDww=lksT$'N;v%IvW3QxuQr&TAAA<.f_EQ(((@yy9rss`X729z3Nƚ5ˑf͚cǎ?e˖<8N{0-=;sH nܸ+ל`t0@I 8|3y;QSܸьfz}S&y.\@ ʕ+ ݒrE͵ @ENT\ B{3 y˗/g;hWQ3ū>( <ּoPtȐMm. JuY #2`(Z@eee=n HKKGFF:aZ<(( pv4s̙uСICI$';d*CFxҞlQ5xƒNtJs~~BdPAfffJ__ߘ:˲kͽWy|0bɿ\.W^( W Ҁ/r|deʢ?;r[.|:PDMmNv3 L_q5.|}}=L g4`B=<###ݎycv5hll͛-UV%GFFW^yĉ,غ x<>޽ ())YW}0*G=}Ξ=1@~Ҵ|q'Z-\Xcqi,^6 $ǏFbD)BbhCP"q=kbܛd Z' 09l Ҩ;9@MVj0Q07ɞEe o$I- ɼ]|rǹsnty4}!ۣK@ :E Y51!R{_owb,ϪK B^fz 1-`G)q\>ř;s&^ ?? HOw +ˁx̝K|KtX,8B%2/в.;}?wTWY=]WJ5uPQ^6C/ &2|qp8gPn'էf0R:BbbrA$@'5'&l2EtWAĔKJSj,#F%Im4|ߩ0$C)8qƒj-PA1S { fm D ƢEjЈnȲ83V+ڧ-aqg\@ZZ v+ٲeK/˛`;vt6nX"v)FQ," Z`-ffddĨ_K95p #"4qҥI\a2hN"8!qNeYI #^{ddƕ+Wzŕ5(3df?(n"H, ŌD8,4MB8Y8Y93q efffl iQT,I< !766vڵnr*+`z )WV*QX*L1}"ǎeY=eY5M} 0 (/Y05??##cy6Ma08V1c"֯}~c HEQ2{1 5s8'|Q-eQڞ '!DK};sypZla@H=J<;v //W ̺qtwf Ԍq҇ݎy^7p'ظq-kצg8iz cx؇kK0m۶=+M.hֳA4EQ V%yyy.iDl9V#6oޜEQTttF1.btHh2 ޼ys1jhȍ,Zޞ/`DO DwT{/k&f>㘝;w|U###?O[.-+9 &ذaCVqqCqqqX]do+1LlHMMŜ9s 6t9rVV'^jkpf+F.Z6格qqf,lܸ߿>e˖.Z~i/ Dii)֭[M׻={rF%{B 4S!(@u 1y X,V2I{rC 8|>nt8Vx˗/l7,ô^4{۟E0 )HyK,T©f DD܈l ^3a'+Wn&$IBmq…˅,8{EC1y ` u9EK!Pn (^ dO5 ªF{zFhQVkKhz, ÀaB?' 2HK+@i"8:u188|npiqBȘ4\C{o$M:# hŲ; m֛Ҋr mV, }SǾ."7w8qͲ,KrS3 fIIIIYYY #qkgO׾aTB%l`4Yetw ggaѢBA{Qep9,Y(99Xp?$)"10\cd!ܟ D% a؇ ;8+]f͢#GP&uo޼s=G֭>@[T}9O q\IJJA)=Ќ >0)`1ٰ@R@'c0UV%l4M[cҊH)hKRwA,)“O.-~_joo?~X3AZRU_v '_WJi^/_ ʇ >88 Ղkר#?~r`P'\u+mY`A+Wqqqlrr"::pVrs3qcǎ/׿~r A8"%%凡Ғ!\V@M?3a\\^̙f/DQ 7ov99p8LAA͛v}V\_1dYC0!,ta(..pȑ6S@6)!@OHB022!$%%aΜ9ՍP' ˲40CI{GE`Sּd" ``Վ@ *.il=!k|P|TR6m'ɴT!(JZsKJJS_ŵkpb`b<[RR_nj~w0g1Ƒ@/YĶnݺg2F^466MMMrh)hĔW,dՋSΣ N\Dd( Y螞!յc@ICꙒ$c| ӏPW\xdg'"% YYYOڵkSoo9Jm1 o@|>U6R Ө==QJI@E;Uhw[8.^xŋn'=K%&&ΉK!2_a>rhjj򶵵,*BSW}aBedd2>>FÚzm>66^EUՃχÉ0<<϶A{bQUn.fwYYiXvmb46n=;xrKn'<߫Q)牞$Bfe/^x8ubDF>si@7nl6r ?@04^o{QSs NCCcHJr`…7oO1IUU t1 5WW̙ :;GQZU_W=~vܹ[@/56 =bY ֭f$%%!332NfG_>١@p yW=ut TSAXG<ʾ[[[{[?en(}[Ydm)))(H)q\.ݳiԐKt@,KuxI0zCw`)AzhnBs0,g'!??

Uo{GDQT.|ioT'3dtvv;wZ5+ ݘ4*voGVVZz4{~,X:>>N>|@ nO;wn#2 b4{tӿӰgdL+(.ϳ;755-P\}:_(: 1gNSpa .L@qq\QxdVcId.~~b?22_~~Y}|"(oO*'W$46&tw; {/--gP} (CLβˁ@@|)Dzzz\~'*Qcya̝"xcq/3X 04z(dBeiPw8{ΟR-Ok7蠔 zǽzDQlfVX&g?k>}Ȉ_+rq4Mǩ6(Yи'}RPP˟wǞ=g.dggN׮5CDp(,,c\~ŘP4r2#'ktt/9sxo^ǟ>yF̝;w>xGw)dll,ɸu+읝=o6 P Ͳb2CK^m=Eʣ:::m8 ,Y KF ,46n5 }(A\ǎL|;*?WM&?Z[[Z|ڬh P_a(AQ?߉+Wz!2xO~'_VVVvo! [o _ (+GQQՑkً6%Л`@~~~p졡q|ylXYlӧOH0B|Lyohaٲ[ZZIW#zfN|ƃh2t:aa6a0`0q,j1KgDRVr2q&d5w#[ SJK-:yş@,nH$ ՑGSSz=yf{vD}O!ʪ2 J鋑Bf{bAp^UVf"LŋhooGQE0W𒩎47צ#N8^\:PHGs|##hooh[\}ABob (vDdbs?v^\X3 pV/M #p^8 #`Г׷ V@iU1pw6RSS@2b0+ L)Mx?-c씕Ye@HC{!h01! >t&^KX,  K3Y&Vg}[wg<(Bee)TVTؽ"Dq,Zx_gXL}pR>W݇n\ԍ={ Ws[WR5/S k{fԗ`/(]4MC}-#Hfo߮f)--zzzB p\֝;w]_^(Y^|r3gq#TXV,K F}qX XL҈Ǐ@NA7ؘ4S[[ȓqj޿ݎ<^קAdMY.ץBk &SyJ|`43{gg$]rjdO4E'`0HjRGy  Xeϐ?^lڴBp8p88G}2[T;/ ~T*޻ FQ^FEbvsPTj|ȅCKpڵr+}}4˳Bbx0ZMp:()…"ԔE(-j5aZh79ܼUJ݋!?hɮ%m B^{޾?vkr)44cfRy_ggg%<ϾZ Pfcb0XR z}W4n*|ְ"A`khlS&4h/ m.pA[l13.,uC< Դ ~7ccw@S*ŦM/'^yt +V,G}}-f塇zbP: 0P0f-'*--} !ҴѨ(! R H (Cڵ i `_|Ey]](&IML̢fѨÌ2HJޔjq;0 vgg;"CEEEZkX8OMMEB@/B.ؤɤeY{1::͊iEҼɪE Ų*3H<=YV̌ vw޽d2ma$*mMSA@=#( |;O4 N;~!|%>%+VTcժjBzH6ʥ/ /f1MgϞZAg"te0`yR(I%%3]vWBH#?e4 CBb,öm'߼Ct#8z{PUU2{7oWLFRVV۷oi'[n~ĉx<vctR rt,>%g;2KR .s^.ymrOW.#ȰZMhl`/dߋA7(&dIMO ("˗/]ަCn%Znw$7 _۴CymZ#h__jt L&s ܽ/w;7v`8QUm)2 \d0\(l6iff&& 05k~x_}ضm#z1"VRN^\*}Oo&T v`0{w,C4C =`0"@,C(z eeňDb8fVf,˂y{ u.k6Din=b)lFTWW[/_ZeS>[`ӮtG}qD"4`64' ,rʮ߈$ 秣[lNq-,_AxB`ř7瘊Hx4fQ#[Bٳg^oI >!hlkJ.~.p z="H&MD"}e=PH`5HP < ~iX$^]}Ѩ LOO%\1.Bl6aٲd2 .,#L"7q@Bmm~&Vbի`W5Q!%RhMMv4ͬ[nÇR Ȃ qT4\헰[[>S]\lak|y-xB8C*Ńh& lƇMLLLs0SZl7c0(jW eY[w fjG)h*++ >ȑ H}3Mjsﻐ*ҫWGv 4779ϝ;ڴi`У^o.q|>HY8Nj_`(w8n(f{T^/H(.FFJK>SSS`YO+P-T)B4ٔHzںO?A&j TWWB. bA-#l6sYB[ZZ1/YsEQ&\b\⥗^`$BF<A]MM2NgwɫWѨ<%XrnbV/`T+P[l1SU/^AbO?"}tt4uرl&> '}]ncAQ: Fr%Fuu9z{ĠTTۍYQ:+)8p8{ڨz+>|Xxk֬jjH$R8{ZVbsn22PCqՇ$T0 /APk9G?~zzz:~`0  Zg Ogff4$[TK:cɒ oP|t @eYA^|X|'çf19DT/{S7Kz1ٛt5GkkX%W6={6SF.//E Kq1 W)y*\xDwR1N{PhuII̮X,p8p\(..dB4EWW.]A~<wŹ(L#tեYoݺFPA HfXѨt5ONbNMJw\Fߨfpߒ|_W?|0 mH$M92> I )kΟ@ccGի/]4d`Icv}9{sҸ`0" 23ݻwrW&.^ f,+ *Z^W^^]]H a[g~__y|| r.2{S `r W R3(Orv b/ UKbY_(*r"JO>8q"@~`. pAQ â%-3]^^!,DW>N$fffEf?2[S p/%܎UtknɆib&R}0XN'?UY ^A楾9LGO5tي )|_+`0w踌oqͦBP^^"eS d) F㘜t3gGFFbMMMƲb\:Y0͖{lӛoyT4Sjuم񶍛~z!^dz GUU ۋ|>qhͽgϞŋa6%Q0xMXlv d$l63-`/nݚ*;1<^"=GM&`0Hd1RO׿~w;,˖lFtyَ;<~\+CO%0 6kajʍlvҥiʤdAL&S=f/qDP^EA}h4677?(24n|mQWf/Dbll,x pR֭s]5B#qMMf(6oBYJY+(]R^$BKxDjS1=&D! Bw(..x7C]]]q|ee%]\\Lg$gneUs)*rh\b2ҽ.dF>,9G?knAF_(Wl6`ӦM|b>򔗗UUUܚ5UʐO^`PćAq)&QE!*E%hA- dTI 殻*[vf>6B8ߧR222=tP2Ԛ)UBR& mmgEg<EE.7 gRc(ӨAII1֬Y5k֤P( tww… is/P[[*v̓`h p:ՙ1'Ǚ3g 8~r` FsP(}>rFFFԲù~rtll]'??l6[,pwONNvvv+!b-{ RSSS}7^ӧ/bϞnhh(rʌؒ(P 8ƙ32T"}ݷeY | !H$"PK۽{Kt pr8ŋ B.(QfeWZ|D]"7a4m2sImֶF 8p `JB={Fen7r(͢U4'm 7Iڵ.++oߎR|tiQʕ1]ۀ+W}Q8G}4U ;FG} |ZRh 1TϊO9,YC 0,2/6]Nw"q.cdd 㓼 S{YVkNˆ"qs8,i fmnnhnnxv=zLDKU%$=C`@BPYY\L$Iqy!-d$=7ZRCͲ,cǎ(j%*Z~ IDATF4 X!j؞R)4UVwt:UU{z=2;W|wDTjm5PR. ,n3פBic^-Y+V4:J؈W xښ&'=c\3 -M;`b``ݣhi^Ϣڎi b.sE|VDeBInTV`ʕƓ'O"uuujxLQj`tt" 'a{P]]]rʊ d r䌺%ziv4::S\;veY$:d/Ydfff*6@wK/}jALQsZԩSyQdU擗wcc\Z zxTf fՌ<_T]8wvv&䘷@ӜDIk E9rdáj|:#e/Koc6ϗ|뭷>O]w/_; ԩY%Z@DJ٪CtwwVWW͠(AX\cz?78 $.| UI ~'*aGsg݋x)Q~L=7$4҂dj)Υ e<::qr7^^?w.<ۭyoza g)ejEpd;qAg(*'4)ı{Bp E[xNUUU``;VӊzXQF,&VCpg뮻6J&o^Dٛ, 1::n ]JJJҌ'|) Ɖpl3|lÂ9D @08(jL,Nc'-FQ~jPAaU[ 2<h`xx0Y>65+ 4{}DwbCYYY y BP(x<)}zիe"4MAA v޽/`z:+WBQǾG"93II!A~~Dvυ | @|>G~Ne/g;w3r>"QEoxx8oqDL:0,Ko:׋sCCCCMAYK}.B&"xZ f^8?|֯_ ˙ՏAH$!d"0A/ Fu5v+%r&D"`Kۿ;Ο$1e?g{gq(I ڞя~׍,-zF -Q}\fV/g?!빼~Ró>[t:;;; -ZhP}Y}!7?8X _zbb溏+Hfr@4ijj2?cw2Fqv[qD D/${6I猙Q8袢"Rt/Ff7sXny8wťKA Z 4e'^4u[" M2ѣG$BBc5ǁy{k`"[ ,9ǃ ǎs۶m˥ plho,̈_QQaVwqtue/8Iy<\(ehii)_~I$::b %-`HV$@X "k{zzpd mգ`0%"1O,@Fyy l6СC00)yΙ7!n' p=@ IQ֭k`/$$ݟ!v]F# cf4'dI`(瘥 .҉ ժi~Eqb1|G{W4׊ /9M<ĥK#Ëo|}׮]J| #)V`Ps* xpu,EaQ@-[!űX ofEza( e)=iڪPٟoUU9֯_݃fg9sPex< Glkll'?O<85s5TooՓ'O/Cu?j[*@lmD#<&64m3dM6 dRF #eGB 5}*+UrPH&y0*0AXo7 ef0"CCCcn ظq#(O̙^wMԒeGf0~xxC;S.-F&R H,&DyfƯ:ab|F 0s_atvv6l?ٜVƨᡇbɤoXWgǏJT(գ{V %XHE֫#JgLs Zc;i@@2)6P BTM^odpppVf BbU~C`#Ϟ= tR F*җe*idO855ˑo[JM ]UUG?q ~s>}FȞ8d{3D8q*X, [lyi hAX2# 5X<{0n/>Gvp= zByz|VVaǎ;@QP(=rBʽwrRh׳J9rdz߾}W^{ __tC%u(kK"骤`v"۠%`aW -ZCY_) ÐLJbt:*O1Wfv-ʾT. tҥ?@qq1jk)UlkkoΝ pD/ּӈ`YV㏯((d29 ف_fE۰aCh4e/@W $/&]a:(zc0jtɇHDߴX8Ν;wP`(KRDs!ZsAvERX+Ht@MMͼ ";Q]JGA F4M`ča8,АG4c#pT -o"FZ]+8NRWZV .W}(*)RXҖ!Ichxx8u~&8)^O?eYx"^{5i- +Kv uS,>cc^|I_yz` e00W5t d HTj*Z9ehPnݺb4V }]Au!~9LOπmP4ވ>F{V0 YarrRYz{o}%NfQu2L>\RD&R`U! -*d1, @r?W8DfJN ؋ދ) \|ԓ@LJNb R(R([W"ScG""b~ ͛77IJxnff+;3(d/PGYx` U"@XAPEmvӦMu0667ed2'\yꩧvmffcLgdZr`֫2Z DJ \h)FeסJ#/ X?ح|FENbRH$.4/DSv`lllV1^㥥`a~H\.ZMOO`JJ / U\RU`$N'-h-w8XtA@___X,KPNax%’ɋe)ԉ|Pj>'IѫEJKK׾+5L:dy֋[bИH Ѵ$?h(v TTBI{4F4ޓKz6 )ps 0^$TR)~р-[P[+_|E`cNfq}$XACC799DDh(v-pdA2 EQK.Q4BATYM r=v˽^7^l6Kr&#FGhn6Ānې텡DDy`>lOyyi9V+ 8{ p8l$yŋrPcccq`YA6k3 XQ7={vTכD+%xp,X|5H$N g/DX* 020ғᄏuŊ{`b"Pb`tuuyCvY *F)CU uH}\$Hhqq1zZxc q<>1dO4ţ%8嗾?0FqHB.Kv;ͲUҪ>SSS!l eY<B=%é:^9\˲2%^_גz_N?$g*>/3= S`YNs/g0磗 djT gis6X,fz=8Yž\.>XB{7`uz;ٕ ߊ<7?Xy^&8+W6b&eK=z4r̢-㐿GY555ǵߓd$ٹRc2d !f9ː0 8S K^tZQWW^u]!dv|܋rL L&$dᛂXH--|$/ BA> /4mik[#GICoX?D"]]]cg:v&?_To ^5?^|y FX40JKEq02SyRX; ÷VaÆ AZֶԩSR\R$ e|yZZVI{ psfJ TJQ=qxx5@6Oє Fv)TR^&s =x~YYYʕ?E2˒0zzu3np>Ç_t:m?DtX@?#㉋m$IZͪUD60[MMhnn68p@P$xYՊa)%'¢Jz.ޱcradȈXH|8r%2NxR7 !)ȩ6wҽm۶~ΝpoyW; _xv% T$ȸ=RJ.@Fqgc8y Ο@ww1>>g`X\b/ŚXȣ u㡻>M6B \4? IDATՒ d߾}{)$eMޢ9F3 %%%6*AQ700 q|˗ K> @U"%bP(Ηjjj쭭 q=PRdb ?B~ABS_cnRJ/"Eka"EQjbňƦIBLMڥ`1c'`~ŧ|a$Z`#/@EBS`nvmCCpZ Bkk36o^!Ν;ӟD" BHn)--eh4R4MT*ŇNLLD^7 6 '|jv~СSx|7ka<@ ̈́ ŋȕ1#R);S7LV9wp8 եK<fs`(eb/nilO eiYIjz= c#YI& &U rR^UNU6bŊ5px4{O=0F#c1'---p:F{w`6FLO{ f/c]:0 1kHR^lf=O(橧Z[SSS&f@) &7===} "bx)ʎnarAɨRG,mLz$ys.˖{ sy$(ŀH$ ցB Ţ|m۶5 ##S bP)?\. vYy+=@ӌ`02p 7h42?fH$>O4Y ~˖@\Mhe%sF)WN楟ٜng٠I(أ/fTd#b*\Sk A}U-_+R)wp; }$!1;;UgdF GsslX,LNqD"(Zo_/ ̈́RNAMZ8,dWAA"Pvbe `[`555ZYd>szM"Xtǡ(/Hzb>%<4z32jllt4ZͺvSS3xwj0{kppp\jfȂƢ8>dp&$H/eti\!셨`L <WXQ$}A 5/].@ԩSפHߩ|`٥QʠfPw'OڼyGv}֭wҥ˒|aZA ؿxbJKȃ>Xq 3`8hENl 555%p\hI7q5(++3ܹ(ĉLpf׋̥Y%=v&&%űeezX,"{qsɨNJJp)W*ťS s8FxzUq"d4|:j$$t\)p_K[U"EKJqX}y_:+`0.׮|y.<#hmmɱo!^UUz4g? `PJVSm~i O(7B\4imS. Rb9lE"{ Qya`:hȦrBEd)/je y<zu h ggo !B>pQ`Be*t DC{(VoF0(N^fYg||d\Ǒ:id&ٕ[ۛ@@.\5kp@ fsEjXDJA0>>Gn?Y3سXsν7Mhl\3@ط} dĵH,=|>#F{Ֆe˖E"._c4%2z===cRvQ n߂QSNܹs#oMp]/r &݃0aaV<9BY h /("{]qƒ"eatZ8wmeeeEp\\wc7 6v4x'|.bR2P?UIH9UlZaf#ϼRQQAC$KK#"r|0Y}&b@P]I 0{Y3?K 4(Y z9?d2 .N+N+F"XٍLիW<*"Fy6_PfM \.'J}V ݅HW_}s) aך4Ya8cǾHl g  tBtuۗ͢WdQ.\^ҴIh$os.UI_*rt:{,;_P%{ܹ4rQc 2bӧ0=]4k.KJ&S8t~4M|`0$N@Fkkkd2R<ΞC_^O^d/.\jhrKD*W2CU`HDzE(g-i 7` TVVs\%DeH2JR- @QaZ`2`4a0{ǂeuҝo޼l){,,Հ&?W$o6WZ=\3h<:F76bApEHQ.[l+,;ϻlyv{글wwwb*Ν;=x`\k y >&-Kر3XXXZqܪ}A$i 555ׯ%&YgT$|GMFHFceEz‚B8"… 3Kًr B ofҖ붜z.PnQUUMgg~155;{p2ѵa/716G0` lGM66 .dZjme 855822Þvww ãkTk&'gРG$BU8\6篭 b8No{>3>` PW')p4qa\]cww4M8m ;u+e/{DΡ~Ж""PYO   芊 Bðq Lh._F{wc=t?\]-KQ{EF{N<~z駿0Lݳ>7xccE6eEKbEի\`\Fݡ-[Jwy'Jɥ:mvc].^E3TP7edivrֹhnnHtwwbpn6bQ1blO:U,(ld0t-JCQd2Yd2YpET(CMө[UY4vXHL7["J'@Q8N<bسg߻ݮgy׮…ˈD! XEcc=|XXX ZCM? W@yf-IZjIE2Mg>󙧺#N]kjwf5QYYLTu2]Ynʕ+C]]]*AD]]-&'x7ח11qʼn'ae/.^;v^<8IgJ%qڿ]UE$իW Hm]:bĒ`0Ԏ8KVː˥ݲI[N-ܶE6'&DQ;vO*֢ H8q<._޽; $p5_٭wMbf&nE0)#0:%݈snw$۫)~ޯˣ"`BN$e@)>ajĉ*fN5 ^#1ү!U`uMc ]iMsf?i4_v˹u~&--uH&3߆Ha\aK5R*W_ BOOe0 m[cq=X IԣG.{qEQ7|&¨M45ruu糟WNX\HJNܾ}YFWH)PAKO?EQ͍ ^iZ{744{vyEObff&pѣ3Xf(SFl*Q;v ."Jéz9Ҳ+ٗXվ/I2hnŞ={'Jyv+he&eXɗ"wskM((KQ<0$IPervV8IPEQW.?[[[۫BQ/N[TJ,mH?C(^'?opG17]Ӧ;ћa0 C2 clz(4EwwwI:U՜{ϝ ߛۋ:b VJ4 SE!6'Fc0E7>SYD]] Jc 6{m0::;bR ^UyW8^YYCݏf9LYJk PsYkR[BMVo4B-IgV (3V BN$I"!F(k=(vhnECCC=866BUs`fm3}CW)(o˲lv5G]3 b |؈@îS3 ?O?~ŋ/>|W_~3Tj7Nr%QVA޵k׷`x]\!^~V=d3vSI}Zo9B6=vX~yW kً%D"1F d 8q"g 'sDDz 9#G.J4 h7ot Z.0L CSZ|eLܡC~(Jqf n1@cK$nǥgfPZd o/~nGf@ i~ΜPӚdC@Sc 3훱tl\GuE$8z}={7n̯m"%\4S@Q5b) {0WjlD5ӘRAXdb(0ܕ+W&'&&^m[sHGn7Y&ga_)#m|Mtmm@bq\:\˲…@[[[&\V dڽDCԲ_Mxp5nerexwo]0i46t/gg)s, ߋ-[f]!qk<9h4UF2R(hox7"W`D5KZrUUaX/i1a'~_MMM_@ܸ1w[8|k\ IDAT,­8d9W*v)\b/@cya襗^:|g/j^12LdOpf/"fg+('MQ9Cк: BEѣ)'`|bta0YׯUUUB CF㛀X96UQi(֛qez1x=6~_GXm| U˪hil$`/ u\o|4{piݗ,(sGFfsgB!?|ш,. p_wCJ{p8/|p;v. aڙCڭ|SX,HlZ @딍abjLՄ|+6y_ﹹ3xb_MD]ee ;Xϔ9V,?>>wݸzudRًN466khQ_|>8uT6qEƵf0 -,E8rݻw/Rl ^d\"M 0eGcIY@L&/^{ySS:;022qʒ cMom-:_؍65{aEee ݥ.33=߃?yСܪ pnNfyv} uv 2. eTU,+E$&{dYMl_+*(ȱhVcd (F :o"`aw/~mnn."%n^F!mV4j=H) ⋯;' d2ܪbb/☙Y,p^<6kSҒla/@[:ށny#zl*: ?ъ^q7w@@c/dY Ҿ(>J-Φ{NE̠t@A~ߋdl)o܈G?)XϋEt붛Jz{;@Q\+|كF(E)vC@_sh0\+s x~N95倎rNJS#VgjR$ oSO<o~["_9Ȱ^\xhii~ǓK(W^y%%$Z9,>]8;;n0xmm5^Y)GjRcKKK RbݖG-nH`(G}DOOF<뿒n(tp/H@wy111!]t)"6rKD4ַ˲ӧƍ9pQfkGN(x'z] z`i)]JuGAG")#x>Y {6ZU \,j (TM(hsʙٹs۶m'At,{.5oGoJ #}XqXP6s;v}[[۟nڅWG122jiZ[]]{!˲^DILOG2n|{ӽ ³Q/cǎIp5ʕUHzz=z]pY,X|m=ƞQT 2Ay٬{, k#󞄜E1u:qыw}`0x}ƵkumʒB 6Džƅi[Z%dY$ɐ$ Ceq28ND6+!,cCzc)n;!\\`0<;U0皕1Ƶ {x^>?яLRٻhs}\=;&kjV :M ; XE3ma-db<===K$,~ Rim 3?O^Kf{={؋V.^\B%51==-9r$R?XY '\Kfv~rr2qys_kk#GW, *+}zX}kQHHER"R) ɤlVY1iܜ(;(2u~ ֒@a7{}GWUU-J˒H@ Guu% B~^0EIHRITJ4m&I^055e*%Kkw7v+Dݖ(mmm?'"q_$I͕0h Ǐ#GN&N6a〲?$N/~|[{.2+ < ӛ6 pF?ހL[evCuaO~;MӭwO#n r-5lI`%Fa5EQ9ryꩧ?ofv5.xKK)LN.4+̯&'' 5\oB NR,;xknIu IՕزuuUD ]fJx^ϋ< mV5@$@hM` ,Ke)0 e^w R]y'I* XLD,&AԢEf‚PXb#8; =z{=vٳf)B]]jeK5jjBpK HlG6+qfbӈ1jh*ؠic|ph݌Άhc$ x ^>wTJ%V__-Ǎ*-}>mm hnGcck4X,D"D"tC:̓4Pa3εU`sgsqix,<> ߯=S&4 XXLy&aeX 0Az -r@ k׮{ݍu#n hkkDcc㘐eKK)bIbi$Rڸyɼ|ˤr2G)8R%Cdv Ccĥ .\"`8D"D K[^*,'K,QRLpa>-{y$ɻTU166n\ K5{@( =W_|.hخ]҈D }w~_*R,+$4Mݤ0(Zmʆ "o9Fpvj@=3UUUIe3ݪǑwDQlΪNFb<? Ï۷$̙CJTUU" "qۄަ'5 DQ 㴚k: ***\immF{i}Tk%{k("|>/[Ղpܟ]| q,.&!2(B CEuu!xnx<,n,ˀereFуa_plVF6+ai) WLvc PYɢE 4W0?/"HzI3y#_ԢDF*rFdb_;v1 ScG7}T7a۶47o)ZH&Ӹq#E%0-|<2X!"NkPh 3QvӨtҍp؍J(GAP0;afC2)!fisS6HHrS`/\bk[[HTU~.]k˅ \;: ؿ O}'_{c)W '9zQ6KftoƝc0ȲY V!2>@HdY d)J0qW.x 62pIeY8v֏!^9Cˢik̦xг??}k@ pE}}-fgڀjGQ챸/f@Pj>2EGLTJFE.6z=Z g2@ 𱞞vע>o$LME03x< ׃뫰cG;B! `UE(."鴈dRH$$\,` &)Z].\hjr!Q 1VdI`Bf6Z dlLkJYg-s%tƼCIZ&엋<p0L xbW΢1R**+쬅M$Fs^_OL RQ"?NKD,-I ,jkxiǵ(҉(eQ ,F^rܹsq_'AQ8Ʀ!XEksv47vF' O#R! P2g mlzY,gAZF0B0BkvN,"KYd̄f޽SQQ_ƍyLLܸ뵏a(KВ.hzd4F9o3<Զm۞cY6q{oQ=siц㏷{ ϟGcc#^ ߿a?ygxNR>Pȃ\ǥG&Q\=/c/JLܹsZZZ8 \ K ]0p D,bKKii$Yd2^^e& Ʋ4qYqkN|> " ^m]h&HeD$ vPIa077g5*`1!4|[U{lruSEQ?+O$I47oAooZZ L,a~>h4$8NJX4f5iZw(^/`P+ \2Z[E7nd1=E"!ad$3geA*tGG-Iz8{-\lJ!Τ>w ॗ~ (VT( 癷I ${w#n{cS.a/țo7Ƞoņ1 g^seN@PKba u*iR_-`\|`q={訹?l6k XUd3 f+a>| VEQ10Y=+q,mT*%ۂbۺENCŠt}8i߾}pLOG,N߅ py? NszLbVTxPYC([4-Ifɤ,~h'(Zlf2:3Νx<!(Ij{ggyxyE ]D$h4YҐ:ۓ UUottU(>LNƱ,H&E$30*+]d i$GAP1?/w_mmmp!8c1TU姦[Hī Y_?FE/hE19~k׮կ~08$w " /"I_y"gC;]h2b1۫ _vCK$.QELȳ ۅ"=ا hPU|0x--udx,.&8n-J&~Wm&h $q7^okee~־J?::ڔcǎA$",|qYD!̥e.˧%fp 8"gm0x≝zs}55x똘X* Fsdd&16F}}}A;% 'paOhҍ^A}S.FFF˯ JŔҥ+pzNup*+*0>u(,-qx)W7 z௒ɤU ȩC]še }zzȠ(<KƩgK33:XݵYbǎ=== y IDATW?~F· 5 ba76#0' 5C*Z6R74Tcޭ$[nws}ВlTda,'r9vIH$8{,uV=[}$cdz{GXM (fgceYJ6R` a fk.dH$ruA<* ]bCkkYeyߟ@OO-A7nAƇ 'b/9tZ&:jM,0PblRb~8sf``c=({|Xo  bi< Ҍ]wDhoߎIDQӌDnnTJD&#͠h\0oG~"b=]@~;M@?|]߇t]򼀓'uQl# ^ˉ Xkι|`rz鴄{﭅y駟|_!QljAEuϢP=\wGGWng `q<?3PeAjSpv.=KKBGGA0 ܹsH$2>44t̙3bU֯QL6t@~k_E]0<.%TR datqX]4ڴq{qqGyA & 0::04x^қ |.r1bٙ-5LOE|/t(^8Z² */;/^IpbSp 8yrA=L]fm"$k^h%xFe:Y9wb/$l2 cbX/69wO?(*X[[ݧӹ_|^h0?|tt.5 Un܈IM!͢ʃ#GܹsH9vD$UU4_a/&(ce]Jy,0+uKJݻMeU˝ (e}|pV3*^"X"Oµkאd?['kUzC HV\RU[U~[E*%ҥ8Aōfgy FE^@kk]gΜu&a%Szزe6FkHT(*#+`?<}C!ͭxrrE 6 w\0r{g;0Y+WoԴ-p)sRĆ5+X+c/֦t]A.`ؙ {6<(b{*e+~mmWU|y.Fd2$Ybpp( bdd~kZ)K/d6YZnalG!~}+*XN_'Tix@ʍYns3xPUpnU} `vvD um۶8 ߏfӵ;M !"DQșyj߽h P`Y,Kfr`Z/  vd.Yn ^6nܸФ\vbEQ}0==my=:t#'*Jˉ|65J v4v|*0K+-y[6+#.sVŭju\oh!|LJh(kWUM9㨮 fPX/lZ;r-3M ~UT 00裏8={lt``@O; r555z ^e M> \QdrԩS'E=#|ǀŘؽ{eYE1*bLŔ(r}4M F1::F۷(ɓhmmEGz5jzsg::I\kfl!m+y(hj rٷo_M6lV$$Ii0 C,iM$S}\UU_k%S!x_wD^ippp6!9u Iz)Y".wV7^X^RV<$diM(0|$h0 (j܉BIs}EQY\x KK1Ȳb)=(buvvhj#Җ[o5Bʟou^3(ʢ1_.˿q**r%I'tZl:paODgP[Z`xxXꦂuU**Zz0+,KMD###dږ2ֵ" 9 ݡŅТeocff+'4Mv#" ?|>bAQEA&a~~ CCctv6@Q;Rw¤~.]xhn{p}@eo@07dnųL|1#5cdd$_bX4rpN@{U$IJ---`Y#'*gB8Ww!Iouu?l\"$R42ƍ9LN0Õx ">ϘI$ɓ' QR2|ͅcǎ=[rjW#07D4A2)$=H-ߌ&x\@"!sENJ b=RbsM%r3d܉'ƑS*0TJQ%u8XxAP\y͚`s=l>T(J&5bIRul>pH||> @D]q?dAp2Y,U$b^(Yݹ}{vp ҌދT*TC:#͊y (CU4@$JmdnZˤ J>(x< < O{fx~? FcGOH(FżvfZ(nI|+b~~|* / EQN>}:r娪˚o$}#~ŷw:1@lP-{+׹{9qJkjSSSj~feM>vCw-=rTYxfVdULٸc ^–@r ĢК,zb aS2aGUUT3#37n/""{##QY!QYYq=|yΞ} nݺ fK@+GL2 RȘ XK9,߹sD4 ꫯ_8οkv\. ǏZ]FN);|QڥPGTKx'b}}7l sxՊ>?Μ9ӧ/,,;'N,É' D]?}Ʋa uG;m9!Uoܺ^NbAJN8̱FiRwq#]g0?G uү(AȊt9T6"$7SCEjܹS{/ h6`F*5J*P.5:aMZj>ܾ׍PPZPƠö58vA%w(*)qF_ö'O?kVe3!DYQn&k@3`' l-NR,sEgy<޽{2RmX1D)4Y G22X*8Lz=NuXIDATX^Z 1_}|D6$X>0p|ߥ_x]*BJ aokkkPBcxcgfYa.--UKRYu#41%ӴDчB?mιAnVmZv}߇lZ2ptIhT*ʧ-Z" ̓4ϾZ @ECmY&Ͷ5(㴨JE k?%.#G8e0 9eL.lAvT<lۆӧO_kkk ƑNTD@0 Guu=TĐitFývڟVVVΘy4æiu4-cRgo۶#XV"X&).k̃D!}_)6aqqOAfg (:SVHFu93iTZ5Z5|xw7677)(<;N: Qk/, ( Gkfj{be)Mb4jA%cBL uuJ#$egQgFܳ]* G2!$U*M"ZM(E_vF%K@tf>x n}9}O> d oTyn\JABHMP2Cţ,^sUH@5ăƼ;ˈdwgi~~~y~~~qr\m۱m{ζm˲,39u4u0t4u]5t2YcHH#( ( ((>cJeyaapRY[,J mW,*۶miZe'f:4"}.,<gN.Lv1,%Ԇ8cpc)X 3 q<9),{ YtRR=('Nrj$RcN޾ƏoZzVF<b8I}Zd v ,hjP4h:HwbDgC;g܎39(L6 VG2ɩYLg3q=Z` ]is#ۡ< } >cM!DCB(y >" L.@g X~ ڈDCc,/#Orcb9("ǩ-dhUTc18md ϫd(H\?e/d'.杤)"GRK6!b#V;7O?}V5!ӈ#&= $M*up$TDY:"ѐi(K CV;I9rO#8R !Z95UcoC9AǸOaCy T> dßqM L61`|)R*}!$Z5ӇZO8p*BXBDDP|ũ̵G CqBwy­QAIDѢ-256>ĘpAu 5ZzV+Q$'>9CS |j9Xg@C7WU1Mv)1jsJ`%k 0hOKx} =`sRdR]iÔ"P> 5w*9KGpұ|Td1;Hl\W[sX_8 Gq͗W9͠aX+) UL̒~)I`DDhT|`#@V geB@{)`H d9_AF`(5&u W#VҶ(]:L5)l6FeMf#/"|v"BɆ>%R9kTdu (WANzԤ#yn*y'oɔ yf?*T1t>eDQVbH U)` B/=Ir!z9Jgh0u!`Д3lE$p*p!KdCwFꁠ-˱G0`PrD0 a'E6f'鑏n*`#Ð u]k^f{ d#rB'*.2hOUJͤĎ#ca/j0dY8q?=5(bOʂI;}5rpdH:njP0\jlB^/8E_! `hH~3;]o&  M`ы~2S(ϐZ{c E!D0e "ZUVmIG7q>$tʓ PN@@ǐ(r C0sU!琰t`,Ao$ClCH~nTҙ0}Rn/vE tpѯ_tk/A,-62FhN4fm I$0I7M,^Gd9 ̙$4p'W9c?r,ɺ]!#wu33@rd,69S9)tZ6SDTE@sZ8Z= A! FSbmjw"E#h z o W=¬~Dnx6 A-PY9eDfgJaB &RVدrȵ MP&y Ѥau vHtGY}ֻ t15 AR"uyѡ,ae88&Y`fWmY[g3c\1 ;zwq /z/{Vp?&%D DdS)Z ("E(`9B1E?ҼRSIENDB`chessx-1.0.0/src/database/ecoinfo.h000644 001750 001750 00000003444 12150452502 017740 0ustar00niklasniklas000000 000000 #ifndef ECOINFO_H #define ECOINFO_H #include "common.h" #include #include #include #include class Database; typedef QPair PlayerInfoListItem; typedef QList PlayerInfoList; class EcoInfo { Q_DECLARE_TR_FUNCTIONS(EcoInfo) public: EcoInfo(); public: /** Set database and player. Automatically updates information. */ EcoInfo(Database* db, const QString& eco); /** Standard destructor. */ ~EcoInfo(); /** Changes database. Does not automatically update statistics. */ void setDatabase(Database* db); /** Changes player. Does not automatically update statistics. */ void setCode(const QString& eco); /** @return current player name. */ QString name() const; /** Recalculates all statistics. */ void update(); /** @return string with formatted score statistics. */ QString formattedScore() const; /** @return string with formatted rating. */ QString formattedRating() const; /** @return string with formatted game count. */ QString formattedGameCount() const; /** @return string with list of players in the event */ QString listOfPlayers() const; private: /** Clears all statistics. */ void reset(); /** Add statistics for game @p */ void addGameStats(int index); QString m_code; Database* m_database; /** Format score statistics for single color. */ QString formattedScore(const int results[4], int count) const; int toResult(const QString& res) const; float toPoints(const QString& res) const; int m_result[4]; int m_count; int m_rating[2]; PlayerInfoList m_playersWhite; PlayerInfoList m_playersBlack; QHash m_gamesWhite; QHash m_gamesBlack; }; #endif // ECOINFO_H chessx-1.0.0/data/images/folder_locked.png000644 001750 001750 00000005132 12077036777 021312 0ustar00niklasniklas000000 000000 PNG  IHDRiCCPICC Profile(UoT?o\?US[IB*unS6mUo xB ISA$=t@hpS]Ƹ9w>5@WI`]5;V! A'@{N\..ƅG_!7suV$BlW=}i; F)A<.&Xax,38S(b׵*%31l #O-zQvaXOP5o6Zz&⻏^wkI/#&\%x/@{7S މjPh͔&mry>k7=ߪB#@fs_{덱п0-LZ~%Gpˈ{YXf^+_s-T>D@קƸ-9!r[2]3BcnCs?>*ԮeD|%4` :X2 pQSLPRaeyqĘ י5Fit )CdL$o$rpӶb>4+̹F_{Яki+x.+B.{L<۩ =UHcnf<>F ^e||pyv%b:iX'%8Iߔ? rw[vITVQN^dpYI"|#\cz[2M^S0[zIJ/HHȟ- Ic www.inkscape.org 4IDAT8ukhe<Мn6O hvPtCARID)IRJfpmxHfۂ4uMݦ.޽>M_.şߍ_d[vc#Ο=+^LK,TU˱5ȓ|`ɪhZoTaƲy≈Ή+)$zØbET?(TT: n׋]^gdݲ%SB8yGuqP7oyꋌ '6mٺU](eʯaޝ@:n`B<(["KUoL,ڔ8l/@w9y?XnHRXa{L.єY7,eȨwv$u?jQ}mT`ZThcq:Sm LfI\큱c2ӽoXR)eLGx~dUv00ҍl5p\%zv )- ZIyxK\v ǜl$b`7w`uv`̀gAK?\q L@ʅU`lE 7CMY.] u+pL9%譁)w`j> %a(74w( ߥ*'ZVK'ba$̂~ z`~a1`^ ,(KC[wAχ\BAN=D.U#ُi|p0=H ̍Ȏ :")gg+E@AD@h(t:m>pV[拣ADn7cvmH{`0DžLDeaSXPCܱ 4v1zH2sxZ<FC҂ Q(m0/ÝZ.}ѹ鞔ޭ:UUB,AΆwUV3|߲p@F <L}pfpBQJDlU Y젆#\ rCC}-gi@].Dq] ;yQ3 _O=:AK-[rtTXw"Ok~l8P<){= 8I.FO) ,?蓐KUi:ɫ=Ō vOL<' )y;IENDB`chessx-1.0.0/src/gui/quicksearch.ui000644 001750 001750 00000007453 12056725773 020054 0ustar00niklasniklas000000 000000 QuickSearchDialog 0 0 392 148 Quick Tag Search Game Number White White Elo Black Black Elo Event Site Round Date Result ECO Number of Moves Qt::Horizontal 40 20 &Find true &Cancel Value or Range like 2000-2300 &Value: valueEdit &Tag: tagCombo &Mode: modeCombo tagCombo valueEdit modeCombo okButton cancelButton chessx-1.0.0/src/gui/preferences.h000644 001750 001750 00000007573 12223260306 017646 0ustar00niklasniklas000000 000000 /*************************************************************************** preferences - Preferences dialog ------------------- begin : Thu 18 Aug 2005 copyright : (C) 2005 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef __PREFERENCESDIALOG_H__ #define __PREFERENCESDIALOG_H__ #include "ui_preferences.h" #include "enginelist.h" class QListWidgetItem; class DownloadManager; /** @ingroup GUI The PreferencesDialog class is a dialog for configuring ChessX. After changes are done, reconfigure() signal is emitted. */ class PreferencesDialog : public QDialog { Q_OBJECT public: /** Create ChessX Preferences dialog */ PreferencesDialog(QWidget* parent = 0, Qt::WindowFlags f = 0); /** Destroy the dialog */ virtual ~PreferencesDialog(); public slots: /** Restore Default values */ void slotReset(); /** Execute dialog, save options on exit */ int exec(); void slotApply(); /** select given engine # for display */ void slotSelectEngine(QListWidgetItem* current, QListWidgetItem* previous); /** user asked for a new engine entry */ void slotAddEngine(); /** user asked to remove current engine entry */ void slotDeleteEngine(); /** user changed the name of an engine */ void slotEngineUp(); /** User asked to move current engine up in the list. */ void slotEngineDown(); /** User asked to move current engine down in the list. */ void slotEngineNameChange(const QString&); /** user wants to use file dialog to select engine command */ void slotSelectEngineCommand(); /** user wants file dialog to select directory in which engine will run */ void slotSelectEngineDirectory(); /** user wants file dialog to select directory in which DataBases will be stored */ void slotSelectDataBasePath(); /** user wants option dialog to select parameters which will be sent at startup of engine */ void slotShowOptionDialog(); /** User pressed a flag to change the piece string */ void slotChangePieceString(); /** Start loading the language file selected in the combo-box */ void slotLoadLanguageFile(); /** Download dictionary was loaded */ void slotFileLoaded(QUrl url, QString name); /** Download was not possible */ void loadFileError(QUrl); protected: /** Overridden to save size */ virtual void closeEvent(QCloseEvent* e); /** Overridden to save size */ virtual void done(int); private: DownloadManager* downloadManager; Ui::PreferencesDialog ui; void restoreSettings(); void saveSettings(); /** Select given item in combo. If not found, select last one. */ bool selectInCombo(QComboBox* combo, const QString& text); void restoreColorItem(ColorList* list, const QString& text, const QString& cfgname); void saveColorList(ColorList* list, const QStringList& cfgnames); EngineList engineList; /** Store any changes made to Engine fields in UI, into list */ void updateEngineData(int index); /** Select engine file. */ QString selectEngineFile(const QString& path = ""); static int s_lastIndex; signals: /** Signal emitted when changes are applied. */ void reconfigure(); }; #endif chessx-1.0.0/src/guess/position.h000644 001750 001750 00000034715 12223260306 017551 0ustar00niklasniklas000000 000000 ////////////////////////////////////////////////////////////////////// // // FILE: position.h // Position class // // Part of: Scid (Shane's Chess Information Database) // Version: 3.5 // // Notice: Copyright (c) 1999-2003 Shane Hudson. All rights reserved. // // Author: Shane Hudson (sgh@users.sourceforge.net) // ////////////////////////////////////////////////////////////////////// #ifndef SCID_POSITION_H #define SCID_POSITION_H #include "common.h" #include "misc.h" #include "movelist.h" #include "sqlist.h" #include "sqset.h" #include "tokens.h" #include namespace Guess { ////////////////////////////////////////////////////////////////////// // Position: Constants const unsigned char WQ_CASTLE = 1, WK_CASTLE = 2, BQ_CASTLE = 4, BK_CASTLE = 8; // SANFlag: since checking if a move is check (to add the "+" to its // SAN string) takes time, and checking for mate takes even // longer, we specify whether we want this done with a flag. typedef unsigned char sanFlagT; const sanFlagT SAN_NO_CHECKTEST = 0, SAN_CHECKTEST = 1, SAN_MATETEST = 2; // Flags that Position::PrintFEN() recognises: // const unsigned int FEN_COMPACT = 0, FEN_BOARD = 1, FEN_CASTLING_EP = 2, FEN_ALL_FIELDS = 3; // Flags that Position::GenerateMoves() recognises: // typedef unsigned int genMovesT; const genMovesT GEN_CAPTURES = 1, GEN_NON_CAPS = 2, GEN_ALL_MOVES = (GEN_CAPTURES | GEN_NON_CAPS); // SANList: list of legal move strings in SAN. // struct sanListT { bool current; unsigned short num; sanStringT list [MAX_LEGAL_MOVES]; }; /////////////////////////////////////////////////////////////////////////// // Position: Class definition class Position { private: //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position: Data structures pieceT Board[66]; // the actual board + a color square // and a NULL square. unsigned int Count[2]; // count of pieces & pawns each unsigned char Material[16]; // count of each type of piece unsigned char ListPos[64]; // ListPos stores the position in // List[][] for the piece on // square x. squareT List[2][16]; // list of piece squares for each side unsigned char NumOnRank[16][8]; unsigned char NumOnFyle[16][8]; unsigned char NumOnLeftDiag[16][16]; // Num Queens/Bishops unsigned char NumOnRightDiag[16][16]; unsigned char NumOnSquareColor[16][2]; directionT Pinned[16]; // For each List[ToMove][x], stores // whether piece is pinned to its // own king and dir from king. squareT EPTarget; // square pawns can EP capture to colorT ToMove; unsigned short HalfMoveClock; // Count of halfmoves since last capture // or pawn move. unsigned short PlyCounter; unsigned char Castling; // castling flags bool StrictCastling; // If false, allow castling after moving // the King or Rook. unsigned int Hash; // Hash value. unsigned int PawnHash; // Pawn structure hash value. // unsigned int NumChecks; // Number of checks. // SquareList CheckSquares; // Stores list of pieces checking the king. MoveList * LegalMoves; // list of legal moves sanListT * SANStrings; // SAN list of legal move strs //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position: Private Functions inline void AddHash(pieceT p, squareT sq); inline void UnHash(pieceT p, squareT sq); inline void AddToBoard(pieceT p, squareT sq); inline void RemoveFromBoard(pieceT p, squareT sq); void CalcPinsDir(directionT dir, pieceT attacker); void GenSliderMoves(MoveList * mlist, colorT c, squareT sq, directionT dir, SquareSet * sqset, bool capturesOnly); void GenKnightMoves(MoveList * mlist, colorT c, squareT sq, SquareSet * sqset, bool capturesOnly); void AddLegalMove(MoveList * mlist, squareT from, squareT to, pieceT promo); void GenCastling(MoveList * mlist); void GenKingMoves(MoveList * mlist, genMovesT genType, bool castling); void AddPromotions(MoveList * mlist, squareT from, squareT dest); bool IsValidEnPassant(squareT from, squareT to); void GenPawnMoves(MoveList * mlist, squareT from, directionT dir, SquareSet * sqset, genMovesT genType); errorT AssertPos(); // Checks for errors in board etc. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position: Public Functions public: Position() { Init(); } ~Position() { if(LegalMoves != NULL) { delete LegalMoves; } if(SANStrings != NULL) { delete SANStrings; } } void Init(); void Clear(); // No pieces on board void StdStart(); // Standard chess starting position bool IsStdStart(); errorT AddPiece(pieceT p, squareT sq); // Set and Get attributes -- one-liners unsigned char PieceCount(pieceT p) { return Material[p]; } unsigned char * GetMaterial() { return Material; } void SetEPTarget(squareT s) { EPTarget = s; } squareT GetEPTarget() { return EPTarget; } bool GetEPFlag() { return (EPTarget != NS); } void SetToMove(colorT c) { ToMove = c; } colorT GetToMove() { return ToMove; } void SetPlyCounter(unsigned short x) { PlyCounter = x; } unsigned short GetPlyCounter() { return PlyCounter; } unsigned short GetFullMoveCount() { return PlyCounter / 2 + 1; } sanListT * GetSANStrings() { return SANStrings; } MoveList * GetLegalMoves() { return LegalMoves; } // Methods to get the Board or piece lists -- used in game.cpp to // decode moves: squareT * GetList(colorT c) { return List[c]; } unsigned int GetCount(colorT c) { return Count[c]; } unsigned int TotalMaterial() { return Count[WHITE] + Count[BLACK]; } unsigned int NumNonPawns(colorT c) { return Count[c] - Material[piece_Make(c, PAWN)]; } bool InPawnEnding() { return (NumNonPawns(WHITE) == 1 && NumNonPawns(BLACK) == 1); } unsigned int MaterialValue(colorT c); inline unsigned int FyleCount(pieceT p, fyleT f) { return NumOnFyle[p][f]; } inline unsigned int RankCount(pieceT p, rankT r) { return NumOnRank[p][r]; } inline unsigned int LeftDiagCount(pieceT p, leftDiagT diag) { return NumOnLeftDiag[p][diag]; } inline unsigned int RightDiagCount(pieceT p, rightDiagT diag) { return NumOnRightDiag[p][diag]; } inline unsigned int SquareColorCount(pieceT p, colorT sqColor) { return NumOnSquareColor[p][sqColor]; } unsigned int GetSquares(pieceT p, SquareList * sqlist); pieceT * GetBoard() { Board[COLOR_SQUARE] = COLOR_CHAR[ToMove]; return Board; } // Other one-line methods squareT GetKingSquare(colorT c) { return List[c][0]; } squareT GetKingSquare() { return List[ToMove][0]; } squareT GetEnemyKingSquare() { return List[1 - ToMove][0]; } // Castling flags inline void SetCastling(colorT c, castleDirT dir, bool flag); bool GetCastling(colorT c, castleDirT dir); inline bool CastlingPossible() { return (Castling ? true : false); } unsigned char GetCastlingFlags() { return Castling; } void SetCastlingFlags(unsigned char b) { Castling = b; } void SetStrictCastling(bool b) { StrictCastling = b; } bool GetStrictCastling(void) { return StrictCastling; } // Allocating memory -- maybe these should be private?? void AllocLegalMoves(); void AllocSANStrings(); // Clearing data structures void ClearLegalMoves(); void ClearSANStrings(); // Hashing inline unsigned int HashValue(void) { return Hash; } inline unsigned int PawnHashValue(void) { return PawnHash; } unsigned int GetHPSig(); // Move generation and execution void CalcPins(); void GenPieceMoves(MoveList * mlist, squareT sq, SquareSet * sqset, bool capturesOnly); // Generate all legal moves: void GenerateMoves(MoveList * mlist, pieceT mask, genMovesT genType, bool maybeInCheck); void GenerateMoves() { GenerateMoves(NULL, EMPTY, GEN_ALL_MOVES, true); } void GenerateMoves(MoveList * mlist) { GenerateMoves(mlist, EMPTY, GEN_ALL_MOVES, true); } void GenerateMoves(MoveList * mlist, pieceT mask) { GenerateMoves(mlist, mask, GEN_ALL_MOVES, true); } void GenerateMoves(MoveList * mlist, genMovesT genType) { GenerateMoves(mlist, EMPTY, genType, true); } void GenerateCaptures(MoveList * mlist) { GenerateMoves(mlist, EMPTY, GEN_CAPTURES, true); } bool IsLegalMove(simpleMoveT * sm); void GenCheckEvasions(MoveList * mlist, pieceT mask, genMovesT genType, SquareList * checkSquares); void MatchLegalMove(MoveList * mlist, pieceT mask, squareT target); errorT MatchPawnMove(MoveList * mlist, fyleT fromFyle, squareT to, pieceT promote); errorT MatchKingMove(MoveList * mlist, squareT target); unsigned int CalcAttacks(colorT toMove, squareT kingSq, SquareList * squares); unsigned int CalcNumChecks() { return CalcAttacks(1 - ToMove, GetKingSquare(), NULL); } unsigned int CalcNumChecks(squareT kingSq) { return CalcAttacks(1 - ToMove, kingSq, NULL); } unsigned int CalcNumChecks(squareT kingSq, SquareList * checkSquares) { return CalcAttacks(1 - ToMove, kingSq, checkSquares); } unsigned int Mobility(pieceT p, colorT color, squareT from); pieceT SmallestDefender(colorT color, squareT target); bool IsKingInCheck() { return (CalcNumChecks() > 0); } bool IsKingInCheckDir(directionT dir); bool IsKingInCheck(simpleMoveT * sm); bool IsKingInMate(); bool IsLegal(); bool IsPromoMove(squareT from, squareT to); void DoSimpleMove(simpleMoveT * sm); // move execution ... void UndoSimpleMove(simpleMoveT * sm); // ... and taking back errorT RelocatePiece(squareT fromSq, squareT toSq); void MakeSANString(simpleMoveT * sm, char * s, sanFlagT flag); void CalcSANStrings(sanFlagT flag); errorT ReadCoordMove(simpleMoveT * m, const char * s, bool reverse); errorT ReadMove(simpleMoveT * m, const char * s, tokenT t); errorT ParseMove(simpleMoveT * sm, const char * s); errorT ReadLine(const char * s); // Board I/O void MakeLongStr(char * str); void DumpBoard(FILE * fp); void DumpLists(FILE * fp); errorT ReadFromLongStr(const char * str); errorT ReadFromCompactStr(const unsigned char * str); errorT ReadFromFEN(const char * s); void PrintCompactStr(char * cboard); void PrintCompactStrFlipped(char * cboard); unsigned char CompactStrFirstByte() { return (Board[0] << 4) | Board[1]; } void PrintFEN(char * str, unsigned int flags); void DumpLatexBoard(QString *dstr, bool flip = false); void DumpHtmlBoard(QString *dstr, unsigned int style, const char * dir, bool flip = false); // Copy, compare positions int Compare(Position * p); void CopyFrom(Position * src); // Set up a random position: errorT Random(const char * material); }; ////////////////////////////////////////////////////////////////////// // Position: Public Inline Functions //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::SetCastling(): // Set a castling flag. // inline void Position::SetCastling(colorT c, castleDirT dir, bool flag) { register unsigned char b = (c == WHITE ? 1 : 4); if(dir == KSIDE) { b += b; } // Now b = 1 or 2 (white flags), or 4 or 8 (black flags) if(flag) { Castling |= b; } else { Castling &= (255 - b); } return; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::GetCastling(): // Get a castling flag. // inline bool Position::GetCastling(colorT c, castleDirT dir) { register unsigned char b = (c == WHITE ? 1 : 4); if(dir == KSIDE) { b += b; } // Now b == 1 or 2 (white flags), or 4 or 8 (black flags) if(Castling & b) { return true; } else { return false; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::AllocLegalMoves(): // Allocate the legal moves list. // inline void Position::AllocLegalMoves() { ASSERT(LegalMoves == NULL); LegalMoves = new MoveList(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::AllocSANStrings(): // Allocate the SAN strings list. // inline void Position::AllocSANStrings() { ASSERT(SANStrings == NULL); SANStrings = new sanListT; SANStrings->current = false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::ClearLegalMoves(): // Reset the legal moves list. // inline void Position::ClearLegalMoves() { if(LegalMoves == NULL) { AllocLegalMoves(); } LegalMoves->Clear(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Position::ClearSANStrings(): // Reset the SAN moves list. // inline void Position::ClearSANStrings() { if(SANStrings) { SANStrings->current = false; } else { AllocSANStrings(); } } } // End namespace Guess #endif // SCID_POSITION_H ////////////////////////////////////////////////////////////////////// // EOF: position.h ////////////////////////////////////////////////////////////////////// chessx-1.0.0/unix/chessx.desktop000644 001750 001750 00000000304 12117557125 017467 0ustar00niklasniklas000000 000000 [Desktop Entry] Type=Application Name=ChessX Comment=Free chess database GenericName=Chess Game Icon=chessx Exec=chessx Terminal=false Categories=Game;BoardGame; MimeType=application/x-chess-pgn; chessx-1.0.0/src/guess/recog.cpp000644 001750 001750 00000151134 12223260306 017332 0ustar00niklasniklas000000 000000 ////////////////////////////////////////////////////////////////////// // // FILE: recog.cpp // Endgame knowledge recognition methods // // Part of: Scid (Shane's Chess Information Database) // Version: 3.5 // // Notice: Copyright (c) 2002-2003 Shane Hudson. All rights reserved. // // Author: Shane Hudson (sgh@users.sourceforge.net) // ////////////////////////////////////////////////////////////////////// #include "guessengine.h" #include "recog.h" namespace Guess { // The Recognizer class provides score bound information for chess // endgames. static const int DRAW = recogValue(SCORE_EXACT, 0); static const int UNKNOWN = recogValue(SCORE_NONE, 0); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Recognizer::Recognize // Checks the current position for a recognized endgame. // Returns a recognition value, which contains a regular score // for the position and a score flag indicating if the score // is exact, an upper bound, a lower bound, or useless. int Recognizer::Recognize(Position * pos) { unsigned int npieces = pos->TotalMaterial(); unsigned char * material = pos->GetMaterial(); if(npieces > 6) { return UNKNOWN; } // TODO: Speed up this code which selects the appropriate recognizer. // TODO: We should maintain a material signature (or hash code) in // TODO: the position and then we could use a small lookup table here // TODO: find the appropriate recognizer quickly. if(npieces == 3) { if(material[WB] == 1 || material[BB] == 1) { return DRAW; } if(material[WN] == 1 || material[BN] == 1) { return DRAW; } if(material[WP] == 1 || material[BP] == 1) { return KPK(pos); } return UNKNOWN; } if(npieces == 5) { // KRP-KR: if(material[WR] == 1 && material[WP] == 1 && material[BR] == 1) { return KRPKR(pos); } if(material[BR] == 1 && material[BP] == 1 && material[WR] == 1) { return KRPKR(pos); } // Bishop and 2 pawns on same rook file with bishop of wrong color: if(material[WB] == 1 && material[WP] == 2) { return KBPK(pos); } if(material[BB] == 1 && material[BP] == 2) { return KBPK(pos); } return UNKNOWN; } if(npieces == 6) { // Bishop and 3 pawns on same rook file with bishop of wrong color: if(material[WB] == 1 && material[WP] == 3) { return KBPK(pos); } if(material[BB] == 1 && material[BP] == 3) { return KBPK(pos); } return UNKNOWN; } if(npieces <= 2) { return DRAW; // Lone kings. } // If we get here, there are four pieces (including kings and pawns) ASSERT(npieces == 4); // Positions with pawns: if(material[WP] == 1) { if(material[BQ] == 1) { return KQKP(pos); } if(material[BR] == 1) { return KRKP(pos); } if(material[BB] == 1 || material[BN] == 1) { return KMKP(pos); } if(material[WB] == 1) { return KBPK(pos); } return UNKNOWN; } if(material[BP] == 1) { if(material[WQ] == 1) { return KQKP(pos); } if(material[WR] == 1) { return KRKP(pos); } if(material[WB] == 1 || material[WN] == 1) { return KMKP(pos); } if(material[BB] == 1) { return KBPK(pos); } return UNKNOWN; } if(material[WB] == 2 || material[BB] == 2) { return KBBK(pos); } if(material[WB] == 1 && material[WN] == 1) { return KBNK(pos); } if(material[BB] == 1 && material[BN] == 1) { return KBNK(pos); } if(material[WR] == 1 && material[BB] == 1) { return KRKB(pos); } if(material[BR] == 1 && material[WB] == 1) { return KRKB(pos); } if(material[WR] == 1 && material[BN] == 1) { return KRKN(pos); } if(material[BR] == 1 && material[WN] == 1) { return KRKN(pos); } // KBKB, KBKN, KNKN and KNNK are all draws, but may have a // trivial mate-in-one if the non-side-to-move king is in a corner: if(material[WN] == 2 || material[BN] == 2 || (material[WB] == 1 && material[BB] == 1) || (material[WB] == 1 && material[BN] == 1) || (material[WN] == 1 && material[BB] == 1) || (material[WN] == 1 && material[BN] == 1)) { squareT wk = pos->GetKingSquare(WHITE); squareT bk = pos->GetKingSquare(BLACK); colorT stm = pos->GetToMove(); if(stm == WHITE && square_IsCornerSquare(bk)) { return UNKNOWN; } if(stm == BLACK && square_IsCornerSquare(wk)) { return UNKNOWN; } return DRAW; } return UNKNOWN; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Recognizer::KPK // Returns a recognition score for King and one Pawn vs King. int Recognizer::KPK(Position * pos) { unsigned char * material = pos->GetMaterial(); squareT wk, bk, wp; colorT stm = pos->GetToMove(); // Find piece squares with White having the pawn: if(material[WP] == 1) { wk = pos->GetKingSquare(WHITE); bk = pos->GetKingSquare(BLACK); squareT * sqlist = pos->GetList(WHITE); wp = sqlist[1]; } else { ASSERT(material[BP] == 1); wk = square_FlipRank(pos->GetKingSquare(BLACK)); bk = square_FlipRank(pos->GetKingSquare(WHITE)); squareT * sqlist = pos->GetList(BLACK); wp = square_FlipRank(sqlist[1]); stm = color_Flip(stm); } // Find pawn, king and enemy king rank and file values: rankT wpRank = square_Rank(wp); fyleT wpFyle = square_Fyle(wp); rankT wkRank = square_Rank(wk); rankT wkFyle = square_Fyle(wk); rankT bkRank = square_Rank(bk); rankT bkFyle = square_Fyle(bk); // Find value to use if it is a win: int winScore = 500 + 5 * wpRank; int winValue = recogValue(SCORE_LOWER, winScore); int lossValue = recogValue(SCORE_UPPER, -winScore); // If the enemy king is behind or equal to the pawn rank: win or unknown if(bkRank <= wpRank) { if((stm == WHITE && wpRank > bkRank) || (stm == BLACK && wpRank > bkRank + 1)) { // Runaway pawn wins: return (stm == WHITE) ? winValue : lossValue; } // Cannot easily determine the result of this position: return UNKNOWN; } // Black king is clearly the closest king to the pawn: draw unsigned int wdist = square_Distance(wk, wp); unsigned int bdist = square_Distance(bk, wp); if(stm == WHITE) { bdist++; } // TODO: check if the "+ 2" below can safely be "+ 1". if(bdist + 2 < wdist) { return DRAW; } // Black king in front of a rook pawn: safe draw. if((wpFyle == A_FYLE || wpFyle == H_FYLE) && wpFyle == bkFyle) { return DRAW; } // King the two squares in front of any pawn before the 6th rank: draw if(wpRank < RANK_6 && wpFyle == bkFyle && (wpRank + 1 == bkRank || wpRank + 2 == bkRank)) { return DRAW; } // Pawn on 6th rank, enemy king blocking it on 7th: draw if(wpRank == RANK_6 && wpFyle == bkFyle && wpRank + 1 == bkRank) { return DRAW; } // White king two ranks in front of the pawn, on the same file or an // adjacent file: win if(wpRank + 2 == wkRank) { int fileDiff = (int)wpFyle - (int)wkFyle; if(fileDiff >= -1 && fileDiff < 1) { return (stm == WHITE) ? winValue : lossValue; } } // Pawn-King-space-EnemyKing formation, draw if pawn is before 5th rank // and side with the pawn is to move; otherwise a win. if(wpFyle == wkFyle && wpFyle == bkFyle && wpRank + 1 == wkRank && wpRank + 3 == bkRank) { if(wpRank < RANK_5 && stm == WHITE) { return DRAW; } return (stm == WHITE) ? winValue : lossValue; } // No key KPK position was found: return UNKNOWN; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Recognizer::KBBK // Returns a recognition score for King and two Bishops vs King. int Recognizer::KBBK(Position * pos) { unsigned char * material = pos->GetMaterial(); squareT wk, bk, wb1, wb2; colorT stm = pos->GetToMove(); // Set up piece squares so that White has the bishops: if(material[WB] == 2) { wk = pos->GetKingSquare(WHITE); bk = pos->GetKingSquare(BLACK); squareT * sqlist = pos->GetList(WHITE); wb1 = sqlist[1]; wb2 = sqlist[2]; } else { ASSERT(material[BB] == 2); wk = square_FlipRank(pos->GetKingSquare(BLACK)); bk = square_FlipRank(pos->GetKingSquare(WHITE)); squareT * sqlist = pos->GetList(BLACK); wb1 = square_FlipRank(sqlist[1]); wb2 = square_FlipRank(sqlist[2]); stm = color_Flip(stm); } // If the bishops are of the same square color, it is a draw: if(square_Color(wb1) == square_Color(wb2)) { return DRAW; } // If the lone king is to move and is next to a bishop, or on the // edge of the board with the enemy king nearby, it may be a draw // by capturing a bishop or by stalemate: if(stm == BLACK) { if(square_Adjacent(bk, wb1)) { return UNKNOWN; } if(square_Adjacent(bk, wb2)) { return UNKNOWN; } if(square_IsEdgeSquare(bk) && square_Distance(wk, bk) == 2) { return UNKNOWN; } } // Compute the lone king distances used for scoring: int bkCorner = square_Distance(bk, square_NearestCorner(bk)); int kingDist = square_Distance(bk, wk); // Return a suitable winning score: int score = 900 + (25 * bkCorner) - (10 * kingDist); int winValue = recogValue(SCORE_LOWER, score); int lossValue = recogValue(SCORE_UPPER, -score); return (stm == WHITE) ? winValue : lossValue; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Recognizer::KBNK // Returns a recognition score for King, Bishop and Knight vs King. int Recognizer::KBNK(Position * pos) { unsigned char * material = pos->GetMaterial(); pieceT * board = pos->GetBoard(); squareT wk, bk, wb, wn; colorT stm = pos->GetToMove(); // Set up piece squares so that White has the bishop and knight: if(material[WB] == 1) { wk = pos->GetKingSquare(WHITE); bk = pos->GetKingSquare(BLACK); squareT * sqlist = pos->GetList(WHITE); wb = sqlist[1]; wn = sqlist[2]; if(board[wb] != WB) { squareT temp = wb; wb = wn; wn = temp; } } else { ASSERT(material[BB] == 1 && material[BN] == 1); wk = square_FlipRank(pos->GetKingSquare(BLACK)); bk = square_FlipRank(pos->GetKingSquare(WHITE)); squareT * sqlist = pos->GetList(BLACK); wb = sqlist[1]; wn = sqlist[2]; if(board[wb] != BB) { squareT temp = wb; wb = wn; wn = temp; } wb = square_FlipRank(wb); wn = square_FlipRank(wn); stm = color_Flip(stm); } // If the lone king attacks a piece, the result is unclear: if(square_Adjacent(wb, bk) || square_Adjacent(wn, bk)) { return UNKNOWN; } // If the lone king is to move and possible stalemate, unclear result: if(stm == BLACK && square_IsEdgeSquare(bk) && square_Distance(wk, bk) == 2) { return UNKNOWN; } // Find lone king distance from the appropriate corner squareT corner1 = A1; squareT corner2 = H8; if(square_Color(wb) == WHITE) { corner1 = H1; corner2 = A8; } int cornerDist = square_Distance(bk, corner1); int cornerDist2 = square_Distance(bk, corner2); if(cornerDist2 < cornerDist) { cornerDist = cornerDist2; } int kingDist = square_Distance(wk, bk); // Return an appropriate winning or losing score: int winScore = 700 - 25 * cornerDist - 10 * kingDist; int winValue = recogValue(SCORE_LOWER, winScore); int lossValue = recogValue(SCORE_UPPER, -winScore); return (stm == WHITE) ? winValue : lossValue; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Recognizer::KBPK // Returns a recognition score for King, Bishop and Pawn(s) vs King. // Recognizes draws with wrong-color bishop for rook pawn(s). int Recognizer::KBPK(Position * pos) { unsigned char * material = pos->GetMaterial(); squareT wk, bk; fyleT wrongFile = A_FYLE; // Wrong-color bishop rook-pawn file. // Set up piece squares so that White has the bishop and pawn(s), // and make sure all pawns are on the wrong rook-pawn file: if(material[WB] == 1) { wk = pos->GetKingSquare(WHITE); bk = pos->GetKingSquare(BLACK); if(pos->SquareColorCount(WB, WHITE) == 1) { wrongFile = H_FYLE; } if(pos->FyleCount(WP, wrongFile) != material[WP]) { return UNKNOWN; } } else { ASSERT(material[BB] == 1); wk = square_FlipRank(pos->GetKingSquare(BLACK)); bk = square_FlipRank(pos->GetKingSquare(WHITE)); if(pos->SquareColorCount(BB, BLACK) == 1) { wrongFile = H_FYLE; } if(pos->FyleCount(BP, wrongFile) != material[BP]) { return UNKNOWN; } } // OK, we have it set up so white has the bishop and pawns, and we // know all pawns are on the wrong rook-pawn file. So recognise a // draw if the black king controls the queening square: squareT promoSq = square_Make(wrongFile, RANK_8); if(bk == promoSq || square_Adjacent(bk, promoSq)) { return DRAW; } // The black king does not control the queening square, so no draw yet: return UNKNOWN; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Recognizer::KRKB // Returns a recognition score for King and Rook vs King and Bishop. // Contains simple rules covering many drawn positions, which were // checked using tablebases. int Recognizer::KRKB(Position * pos) { unsigned char * material = pos->GetMaterial(); squareT wk, bk, wr, bb; colorT stm = pos->GetToMove(); // Find piece squares with White having the rook: wk = pos->GetKingSquare(WHITE); bk = pos->GetKingSquare(BLACK); squareT * sqlist = pos->GetList(WHITE); wr = sqlist[1]; sqlist = pos->GetList(BLACK); bb = sqlist[1]; if(material[WB] == 1) { squareT t = wk; wk = square_FlipRank(bk); bk = square_FlipRank(t); t = wr; wr = square_FlipRank(bb); bb = square_FlipRank(t); stm = color_Flip(stm); } // Flip board so the black king is in the 10-square a1-d1-d4 triangle: if(square_Rank(bk) >= RANK_5) { wk = square_FlipRank(wk); wr = square_FlipRank(wr); bk = square_FlipRank(bk); bb = square_FlipRank(bb); } if(square_Fyle(bk) >= E_FYLE) { wk = square_FlipFyle(wk); wr = square_FlipFyle(wr); bk = square_FlipFyle(bk); bb = square_FlipFyle(bb); } if(bk == A2 || bk == A3 || bk == A4 || bk == B3 || bk == B4 || bk == C4) { wk = square_FlipDiag(wk); wr = square_FlipDiag(wr); bk = square_FlipDiag(bk); bb = square_FlipDiag(bb); } int kingsDist = square_Distance(wk, bk); if(stm == WHITE) { // Black king on c2/c3/d3/d4, black bishop adjacent, // white king more than 2 squares away: draw. if(kingsDist > 2 && square_Adjacent(bk, bb) && (bk == C2 || bk == C3 || bk == D3 || bk == D4)) { return DRAW; } } else { // Black king anywhere but a1 or b1, black bishop adjacent, // white king more than 2 squares away: draw. if(kingsDist > 2 && square_Adjacent(bk, bb) && bk != A1 && bk != B1) { return DRAW; } // Black king not on edge or b2, not sharing a rank or file with // the white rook; white king more than 2 squares away: draw. if(kingsDist > 2 && !square_IsEdgeSquare(bk) && bk != B2 && square_Rank(bk) != square_Rank(wr) && square_Fyle(bk) != square_Fyle(wr)) { return DRAW; } } return UNKNOWN; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Recognizer::KRKN // Returns a recognition score for King and Rook vs King and Knight. // Contains simple rules covering many drawn positions, which were // checked using tablebases. int Recognizer::KRKN(Position * pos) { unsigned char * material = pos->GetMaterial(); squareT wk, bk, wr, bn; colorT stm = pos->GetToMove(); // Find piece squares with White having the rook: wk = pos->GetKingSquare(WHITE); bk = pos->GetKingSquare(BLACK); squareT * sqlist = pos->GetList(WHITE); wr = sqlist[1]; sqlist = pos->GetList(BLACK); bn = sqlist[1]; if(material[WN] == 1) { squareT t = wk; wk = square_FlipRank(bk); bk = square_FlipRank(t); t = wr; wr = square_FlipRank(bn); bn = square_FlipRank(t); stm = color_Flip(stm); } // Flip board so the black king is in the 10-square a1-d1-d4 triangle: if(square_Rank(bk) >= RANK_5) { wk = square_FlipRank(wk); wr = square_FlipRank(wr); bk = square_FlipRank(bk); bn = square_FlipRank(bn); } if(square_Fyle(bk) >= E_FYLE) { wk = square_FlipFyle(wk); wr = square_FlipFyle(wr); bk = square_FlipFyle(bk); bn = square_FlipFyle(bn); } if(bk == A2 || bk == A3 || bk == A4 || bk == B3 || bk == B4 || bk == C4) { wk = square_FlipDiag(wk); wr = square_FlipDiag(wr); bk = square_FlipDiag(bk); bn = square_FlipDiag(bn); } int kingsDist = square_Distance(wk, bk); if(stm == WHITE) { // Black king not on edge or b2, adjacent to black knight, // not sharing a rank or file with the white rook; white king // more than 2 squares away: draw. if(kingsDist > 2 && !square_IsEdgeSquare(bk) && bk != B2 && square_Adjacent(bk, bn) && square_Rank(bk) != square_Rank(wr) && square_Fyle(bk) != square_Fyle(wr)) { return DRAW; } } else { // Black king anywhere but a1 or b1, adjacent to the knight, // white king more than 2 squares away: draw. if(bk != A1 && bk != B1 && kingsDist > 2 && square_Adjacent(bk, bn)) { return DRAW; } // Black king not on edge or b2, adjacent to black knight, // not sharing a rank/file with the white rook: draw. if(!square_IsEdgeSquare(bk) && bk != B2 && square_Adjacent(bk, bn) && square_Rank(bk) != square_Rank(wr) && square_Fyle(bk) != square_Fyle(wr)) { return DRAW; } // Black king anywhere but a1/b1/c1/b2, adjacent to the black // knight, not sharing a rank/file with the rook; white king // not adjacent to the knight: draw. if(bk != A1 && bk != B1 && bk != C1 && bk != B2 && !square_Adjacent(wk, bn) && square_Adjacent(bk, bn) && square_Rank(bk) != square_Rank(wr) && square_Fyle(bk) != square_Fyle(wr)) { return DRAW; } } return UNKNOWN; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Recognizer::KMKP // Returns a recognition score for King and Minor Piece vs King and Pawn. int Recognizer::KMKP(Position * pos) { unsigned char * material = pos->GetMaterial(); squareT wk, bk, wm, bp; colorT stm = pos->GetToMove(); // Find piece squares with White having the minor piece: wk = pos->GetKingSquare(WHITE); bk = pos->GetKingSquare(BLACK); squareT * sqlist = pos->GetList(WHITE); wm = sqlist[1]; sqlist = pos->GetList(BLACK); bp = sqlist[1]; if(material[WP] == 1) { squareT t = wk; wk = square_FlipRank(bk); bk = square_FlipRank(t); t = wm; wm = square_FlipRank(bp); bp = square_FlipRank(t); stm = color_Flip(stm); } // Black (the side with the pawn) can only lose to trivial mates // in a corner trapped by the pawn: if(stm == WHITE && square_IsCornerSquare(bk) && square_Adjacent(bk, bp) && square_Distance(bk, wk) == 2) { return UNKNOWN; } // Black has at least a draw: return recogValue((stm == BLACK) ? SCORE_LOWER : SCORE_UPPER, 0); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Recognizer::KQKP // Returns a recognition score for King and Queen vs King and Pawn. // Contains rules for many draws with Queen vs a2 or c2 pawn, // checked using tablebases. int Recognizer::KQKP(Position * pos) { unsigned char * material = pos->GetMaterial(); squareT wk, bk, wq, bp; colorT stm = pos->GetToMove(); // Find piece squares with White having the queen: wk = pos->GetKingSquare(WHITE); bk = pos->GetKingSquare(BLACK); squareT * sqlist = pos->GetList(WHITE); wq = sqlist[1]; sqlist = pos->GetList(BLACK); bp = sqlist[1]; if(material[WQ] != 1) { squareT t = wk; wk = square_FlipRank(bk); bk = square_FlipRank(t); t = wq; wq = square_FlipRank(bp); bp = square_FlipRank(t); stm = color_Flip(stm); } // There are only recognizable draws with a pawn on its 7th rank, // defended by its king: if(square_Rank(bp) != RANK_2 || ! square_Adjacent(bk, bp)) { return UNKNOWN; } // Make sure the pawn is on the queenside: if(square_Fyle(bp) >= E_FYLE) { wk = square_FlipFyle(wk); wq = square_FlipFyle(wq); bk = square_FlipFyle(bk); bp = square_FlipFyle(bp); } // Lists of squares for each (black king, black pawn) pair listing // the white king squares for which white to move only draws // regardless of where the white queen is: static const squareT drawSquares_None [] = { NULL_SQUARE }; static const squareT drawSquares_BPa2_BKb1 [] = { G1, H1, F2, G2, H2, G3, H3, F4, G4, H4, E5, F5, G5, H5, A6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPa2_BKb2 [] = { F1, G1, H1, G2, H2, F3, G3, H3, F4, G4, H4, F5, G5, H5, A6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc2_BKc1 [] = { H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc2_BKd1 [] = { F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc2_BKd2 [] = { F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; const squareT * drawSquares = drawSquares_None; if(bp == A2) { if(bk == B1) { drawSquares = drawSquares_BPa2_BKb1; } if(bk == B2) { drawSquares = drawSquares_BPa2_BKb2; } } else if(bp == C2) { if(bk == C1) { drawSquares = drawSquares_BPc2_BKc1; } if(bk == D1) { drawSquares = drawSquares_BPc2_BKd1; } if(bk == D2) { drawSquares = drawSquares_BPc2_BKd2; } } // Scan the list of drawn squares for the white king square: while(*drawSquares != NULL_SQUARE) { if(wk == *drawSquares) { return DRAW; } drawSquares++; } return UNKNOWN; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Recognizer::KRKP // Returns a recognition score for King and Rook vs King and Pawn. // Contains rules for many draws, checked using tablebases. int Recognizer::KRKP(Position * pos) { unsigned char * material = pos->GetMaterial(); squareT wk, bk, wr, bp; colorT stm = pos->GetToMove(); // Find piece squares with White having the rook: wk = pos->GetKingSquare(WHITE); bk = pos->GetKingSquare(BLACK); squareT * sqlist = pos->GetList(WHITE); wr = sqlist[1]; sqlist = pos->GetList(BLACK); bp = sqlist[1]; if(material[WR] != 1) { squareT t = wk; wk = square_FlipRank(bk); bk = square_FlipRank(t); t = wr; wr = square_FlipRank(bp); bp = square_FlipRank(t); stm = color_Flip(stm); } // There are only recognized draws when the pawn is defended by its king: if(! square_Adjacent(bk, bp)) { return UNKNOWN; } // Make sure the pawn is on the queenside: if(square_Fyle(bp) >= E_FYLE) { wk = square_FlipFyle(wk); wr = square_FlipFyle(wr); bk = square_FlipFyle(bk); bp = square_FlipFyle(bp); } // Lists of squares for each (black king, black pawn) pair listing // the white king squares for which white to move only draws // regardless of where the white rook is: static const squareT drawSquares_None [] = { NULL_SQUARE }; static const squareT drawSquares_BPa2_BKb2 [] = { D1, D2, D3, C4, NULL_SQUARE }; static const squareT drawSquares_BPa2_BKb3 [] = { E1, F1, G1, H1, D4, E4, F4, G4, H4, A5, B5, C5, D5, E5, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, NULL_SQUARE }; static const squareT drawSquares_BPa3_BKb2 [] = { E1, F1, G1, H1, E2, F2, G2, H2, D3, E3, F3, G3, H3, D4, E4, F4, G4, H4, D5, E5, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPa3_BKb3 [] = { F1, G1, H1, F2, G2, H2, F3, G3, H3, D4, E4, F4, G4, H4, D5, E5, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPa3_BKb4 [] = { G1, H1, G2, H2, G3, H3, G4, H4, D5, E5, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPa4_BKa3 [] = { H1, H2, H3, H4, H5, H6, H7, H8, NULL_SQUARE }; static const squareT drawSquares_BPa4_BKa5 [] = { A7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPa4_BKb3 [] = { G1, H1, G2, H2, G3, H3, G4, H4, E5, F5, G5, H5, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPa4_BKb4 [] = { H1, H2, H3, H4, H5, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPa4_BKb5 [] = { A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPa5_BKb4 [] = { E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPa5_BKb5 [] = { A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb2_BKa2 [] = { E1, F1, G1, H1, E2, F2, G2, H2, E3, F3, G3, H3, D4, E4, F4, G4, H4, B5, C5, D5, E5, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb2_BKa3 [] = { F2, G2, H2, F3, G3, H3, F4, G4, H4, A5, E5, G5, H5, A6, B6, C6, D6, E6, F6, H6, A7, B7, C7, D7, E7, F7, G7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb2_BKb3 [] = { F2, G2, H2, F3, G3, H3, F4, G4, H4, A5, B5, C5, D5, E5, G5, H5, A6, B6, C6, D6, E6, F6, H6, A7, B7, C7, D7, E7, F7, G7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb2_BKc1 [] = { F1, G1, H1, F2, G2, H2, E3, F3, G3, H3, A4, D4, E4, F4, G4, H4, A5, C5, D5, E5, F5, G5, H5, A6, C6, D6, E6, F6, G6, H6, A7, C7, D7, E7, F7, G7, H7, A8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb2_BKc2 [] = { E1, E2, E3, C4, D4, NULL_SQUARE }; static const squareT drawSquares_BPb2_BKc3 [] = { E3, A5, B5, C5, D5, E5, A6, B6, C6, D6, A7, B7, C7, A8, B8, C8, NULL_SQUARE }; static const squareT drawSquares_BPb3_BKa2 [] = { F1, G1, H1, F2, G2, H2, F3, G3, H3, F4, G4, H4, E5, F5, G5, H5, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb3_BKa3 [] = { G1, H1, G2, H2, G3, H3, G4, H4, G5, H5, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb3_BKa4 [] = { H1, H2, H3, H4, H5, H6, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb3_BKb2 [] = { G1, H1, G2, H2, G3, H3, G4, H4, F5, G5, H5, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb3_BKb4 [] = { G1, H1, G2, H2, G3, H3, G4, H4, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb3_BKc2 [] = { F1, G1, H1, G2, H2, E3, F3, G3, H3, E4, F4, G4, H4, A5, B5, D5, E5, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb3_BKc3 [] = { G1, H1, G2, H2, G3, H3, E4, F4, G4, H4, C5, D5, E5, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb3_BKc4 [] = { H1, H2, H3, H4, E5, F5, G5, H5, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb4_BKa3 [] = { H1, H2, H3, H4, H5, H6, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb4_BKa4 [] = { G7, H7, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb4_BKa5 [] = { H8, NULL_SQUARE }; static const squareT drawSquares_BPb4_BKb3 [] = { H6, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb4_BKc3 [] = { H1, H2, H3, H4, E5, F5, G5, H5, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb4_BKc4 [] = { D6, E6, F6, G6, H6, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb4_BKc5 [] = { E7, F7, G7, H7, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb5_BKc4 [] = { E7, F7, G7, H7, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPb5_BKc5 [] = { F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc2_BKb2 [] = { A4, B4, B5, B6, B7, B8, NULL_SQUARE }; static const squareT drawSquares_BPc2_BKb3 [] = { A5, B5, C5, D5, A6, B6, C6, D6, B7, C7, D7, E7, B8, C8, D8, E8, NULL_SQUARE }; static const squareT drawSquares_BPc2_BKd1 [] = { G1, H1, G2, H2, F3, G3, H3, A4, B4, E4, F4, G4, H4, A5, B5, D5, E5, F5, G5, H5, A6, B6, D6, E6, F6, G6, H6, A7, B7, D7, E7, F7, G7, H7, A8, B8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc2_BKd3 [] = { F3, B5, C5, D5, E5, F5, A6, B6, C6, D6, E6, A7, B7, C7, D7, A8, B8, C8, D8, NULL_SQUARE }; static const squareT drawSquares_BPc3_BKb2 [] = { G1, H1, G2, H2, G3, H3, G4, H4, A5, C5, D5, E5, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc3_BKb3 [] = { H1, H2, H3, H4, A5, B5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc3_BKb4 [] = { A6, B6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc3_BKc2 [] = { H1, H2, H3, H4, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc3_BKc4 [] = { H1, H2, H3, H4, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc3_BKd2 [] = { G1, H1, H2, F3, G3, H3, F4, G4, H4, A5, B5, C5, E5, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc3_BKd3 [] = { H1, H2, H3, F4, G4, H4, D5, E5, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc3_BKd4 [] = { F5, G5, H5, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc4_BKb3 [] = { A6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc4_BKb4 [] = { A6, A7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc4_BKc3 [] = { F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc4_BKd3 [] = { F5, G5, H5, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc4_BKd4 [] = { E6, F6, G6, H6, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPc4_BKd5 [] = { F7, G7, H7, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd2_BKc1 [] = { G1, H1, G2, H2, A3, G3, H3, A4, B4, E4, F4, G4, H4, A5, B5, E5, F5, G5, H5, A6, B6, E6, F6, G6, H6, A7, B7, E7, F7, G7, H7, A8, B8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd2_BKc3 [] = { A3, A5, B5, C5, D5, E5, B6, C6, D6, E6, C7, D7, E7, F7, C8, D8, E8, F8, NULL_SQUARE }; static const squareT drawSquares_BPd2_BKd1 [] = { H1, H2, H3, A4, G4, H4, A5, B5, C5, D5, E5, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd2_BKd3 [] = { H2, H3, H4, A5, B5, C5, D5, E5, F5, G5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd2_BKe1 [] = { A1, H1, A2, H2, A3, G3, H3, A4, B4, C4, F4, G4, H4, A5, B5, C5, E5, F5, G5, H5, A6, B6, C6, E6, F6, G6, H6, A7, B7, C7, E7, F7, G7, H7, A8, B8, C8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd2_BKe3 [] = { G3, C5, D5, E5, F5, G5, C6, D6, E6, F6, B7, C7, D7, E7, B8, C8, D8, E8, NULL_SQUARE }; static const squareT drawSquares_BPd3_BKc2 [] = { H1, H2, A3, H3, A4, H4, A5, B5, D5, E5, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd3_BKc3 [] = { A4, A5, B5, C5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd3_BKc4 [] = { A5, A6, B6, C6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd3_BKd2 [] = { H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd3_BKd4 [] = { H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd3_BKe2 [] = { H1, H2, G3, H3, G4, H4, A5, B5, C5, D5, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd3_BKe3 [] = { G4, H4, E5, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd3_BKe4 [] = { G5, H5, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd4_BKc3 [] = { A5, A6, B6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd4_BKc4 [] = { A6, B6, A7, B7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd4_BKc5 [] = { A7, A8, NULL_SQUARE }; static const squareT drawSquares_BPd4_BKd3 [] = { A7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd4_BKd5 [] = { A8, B8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd4_BKe3 [] = { G5, H5, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd4_BKe4 [] = { F6, G6, H6, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, NULL_SQUARE }; static const squareT drawSquares_BPd4_BKe5 [] = { G7, H7, G8, H8, NULL_SQUARE }; const squareT * drawSquares = drawSquares_None; if(bp == A2) { if(bk == B2) { drawSquares = drawSquares_BPa2_BKb2; } else if(bk == B3) { drawSquares = drawSquares_BPa2_BKb3; } } else if(bp == A3) { if(bk == B2) { drawSquares = drawSquares_BPa3_BKb2; } else if(bk == B3) { drawSquares = drawSquares_BPa3_BKb3; } else if(bk == B4) { drawSquares = drawSquares_BPa3_BKb4; } } else if(bp == A4) { if(bk == A3) { drawSquares = drawSquares_BPa4_BKa3; } else if(bk == A5) { drawSquares = drawSquares_BPa4_BKa5; } else if(bk == B3) { drawSquares = drawSquares_BPa4_BKb3; } else if(bk == B4) { drawSquares = drawSquares_BPa4_BKb4; } else if(bk == B5) { drawSquares = drawSquares_BPa4_BKb5; } } else if(bp == A5) { if(bk == B4) { drawSquares = drawSquares_BPa5_BKb4; } else if(bk == B5) { drawSquares = drawSquares_BPa5_BKb5; } } else if(bp == B2) { if(bk == A2) { drawSquares = drawSquares_BPb2_BKa2; } else if(bk == A3) { drawSquares = drawSquares_BPb2_BKa3; } else if(bk == B3) { drawSquares = drawSquares_BPb2_BKb3; } else if(bk == C1) { drawSquares = drawSquares_BPb2_BKc1; } else if(bk == C2) { drawSquares = drawSquares_BPb2_BKc2; } else if(bk == C3) { drawSquares = drawSquares_BPb2_BKc3; } } else if(bp == B3) { if(bk == A2) { drawSquares = drawSquares_BPb3_BKa2; } else if(bk == A3) { drawSquares = drawSquares_BPb3_BKa3; } else if(bk == A4) { drawSquares = drawSquares_BPb3_BKa4; } else if(bk == B2) { drawSquares = drawSquares_BPb3_BKb2; } else if(bk == B4) { drawSquares = drawSquares_BPb3_BKb4; } else if(bk == C2) { drawSquares = drawSquares_BPb3_BKc2; } else if(bk == C3) { drawSquares = drawSquares_BPb3_BKc3; } else if(bk == C4) { drawSquares = drawSquares_BPb3_BKc4; } } else if(bp == B4) { if(bk == A3) { drawSquares = drawSquares_BPb4_BKa3; } else if(bk == A4) { drawSquares = drawSquares_BPb4_BKa4; } else if(bk == A5) { drawSquares = drawSquares_BPb4_BKa5; } else if(bk == B3) { drawSquares = drawSquares_BPb4_BKb3; } else if(bk == C3) { drawSquares = drawSquares_BPb4_BKc3; } else if(bk == C4) { drawSquares = drawSquares_BPb4_BKc4; } else if(bk == C5) { drawSquares = drawSquares_BPb4_BKc5; } } else if(bp == B5) { if(bk == C4) { drawSquares = drawSquares_BPb5_BKc4; } else if(bk == C5) { drawSquares = drawSquares_BPb5_BKc5; } } else if(bp == C2) { if(bk == B2) { drawSquares = drawSquares_BPc2_BKb2; } else if(bk == B3) { drawSquares = drawSquares_BPc2_BKb3; } else if(bk == D1) { drawSquares = drawSquares_BPc2_BKd1; } else if(bk == D3) { drawSquares = drawSquares_BPc2_BKd3; } } else if(bp == C3) { if(bk == B2) { drawSquares = drawSquares_BPc3_BKb2; } else if(bk == B3) { drawSquares = drawSquares_BPc3_BKb3; } else if(bk == B4) { drawSquares = drawSquares_BPc3_BKb4; } else if(bk == C2) { drawSquares = drawSquares_BPc3_BKc2; } else if(bk == C4) { drawSquares = drawSquares_BPc3_BKc4; } else if(bk == D2) { drawSquares = drawSquares_BPc3_BKd2; } else if(bk == D3) { drawSquares = drawSquares_BPc3_BKd3; } else if(bk == D4) { drawSquares = drawSquares_BPc3_BKd4; } } else if(bp == C4) { if(bk == B3) { drawSquares = drawSquares_BPc4_BKb3; } else if(bk == B4) { drawSquares = drawSquares_BPc4_BKb4; } else if(bk == C3) { drawSquares = drawSquares_BPc4_BKc3; } else if(bk == D3) { drawSquares = drawSquares_BPc4_BKd3; } else if(bk == D4) { drawSquares = drawSquares_BPc4_BKd4; } else if(bk == D5) { drawSquares = drawSquares_BPc4_BKd5; } } else if(bp == D2) { if(bk == C1) { drawSquares = drawSquares_BPd2_BKc1; } else if(bk == C3) { drawSquares = drawSquares_BPd2_BKc3; } else if(bk == D1) { drawSquares = drawSquares_BPd2_BKd1; } else if(bk == D3) { drawSquares = drawSquares_BPd2_BKd3; } else if(bk == E1) { drawSquares = drawSquares_BPd2_BKe1; } else if(bk == E3) { drawSquares = drawSquares_BPd2_BKe3; } } else if(bp == D3) { if(bk == C2) { drawSquares = drawSquares_BPd3_BKc2; } else if(bk == C3) { drawSquares = drawSquares_BPd3_BKc3; } else if(bk == C4) { drawSquares = drawSquares_BPd3_BKc4; } else if(bk == D2) { drawSquares = drawSquares_BPd3_BKd2; } else if(bk == D4) { drawSquares = drawSquares_BPd3_BKd4; } else if(bk == E2) { drawSquares = drawSquares_BPd3_BKe2; } else if(bk == E3) { drawSquares = drawSquares_BPd3_BKe3; } else if(bk == E4) { drawSquares = drawSquares_BPd3_BKe4; } } else if(bp == D4) { if(bk == C3) { drawSquares = drawSquares_BPd4_BKc3; } else if(bk == C4) { drawSquares = drawSquares_BPd4_BKc4; } else if(bk == C5) { drawSquares = drawSquares_BPd4_BKc5; } else if(bk == D3) { drawSquares = drawSquares_BPd4_BKd3; } else if(bk == D5) { drawSquares = drawSquares_BPd4_BKd5; } else if(bk == E3) { drawSquares = drawSquares_BPd4_BKe3; } else if(bk == E4) { drawSquares = drawSquares_BPd4_BKe4; } else if(bk == E5) { drawSquares = drawSquares_BPd4_BKe5; } } // Scan the list of drawn squares for the white king square: while(*drawSquares != NULL_SQUARE) { if(wk == *drawSquares) { return DRAW; } drawSquares++; } return UNKNOWN; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Recognizer::KRPKR // Returns a recognition score for King, Rook and Pawn vs King and Rook. // Contains rules for some draws, checked using tablebases. int Recognizer::KRPKR(Position * pos) { // XXX INCOMPLETE XXX return UNKNOWN; unsigned char * material = pos->GetMaterial(); pieceT * board = pos->GetBoard(); squareT wk, bk, wr, wp, br; colorT stm = pos->GetToMove(); // Set up piece squares so that White has the pawn: if(material[WP] == 1) { wk = pos->GetKingSquare(WHITE); bk = pos->GetKingSquare(BLACK); squareT * sqlist = pos->GetList(WHITE); wr = sqlist[1]; wp = sqlist[2]; if(board[wr] != WR) { squareT temp = wr; wr = wp; wp = temp; } sqlist = pos->GetList(BLACK); br = sqlist[1]; } else { wk = square_FlipRank(pos->GetKingSquare(BLACK)); bk = square_FlipRank(pos->GetKingSquare(WHITE)); squareT * sqlist = pos->GetList(BLACK); wr = sqlist[1]; wp = sqlist[2]; if(board[wr] != BR) { squareT temp = wr; wr = wp; wp = temp; } wr = square_FlipRank(wr); wp = square_FlipRank(wp); sqlist = pos->GetList(WHITE); br = square_FlipRank(sqlist[1]); stm = color_Flip(stm); } // Make sure the pawn is on the queenside: if(square_Fyle(wp) >= E_FYLE) { wk = square_FlipFyle(wk); wr = square_FlipFyle(wr); wp = square_FlipFyle(wp); bk = square_FlipFyle(bk); br = square_FlipFyle(br); } // Get ranks and files of piece squares: int wkRank = square_Rank(wk); int wkFyle = square_Fyle(wk); int wrRank = square_Rank(wr); int wrFyle = square_Fyle(wr); int wpRank = square_Rank(wp); int wpFyle = square_Fyle(wp); int bkRank = square_Rank(bk); int bkFyle = square_Fyle(bk); int brRank = square_Rank(br); int brFyle = square_Fyle(br); // No draws recognized if the black king is behind the pawn: if(bkRank < wpRank) { return UNKNOWN; } // We cannot recognize draws if the rooks share a rank or file: if(wrRank == brRank || wrFyle == brFyle) { return UNKNOWN; } // Designate side-to-move king,rook as sk and sr, enemy as ek and er squareT sk, sr, ek, er; int skRank, srRank, ekRank, erRank; int skFyle, srFyle, ekFyle, erFyle; if(stm == WHITE) { sk = wk; sr = wr; ek = bk; er = br; skRank = wkRank; skFyle = wkFyle; srRank = wrRank; srFyle = wrFyle; ekRank = bkRank; ekFyle = bkFyle; erRank = brRank; erFyle = brFyle; } else { sk = bk; sr = br; ek = wk; er = wr; skRank = bkRank; skFyle = bkFyle; srRank = brRank; srFyle = brFyle; ekRank = wkRank; ekFyle = wkFyle; erRank = wrRank; erFyle = wrFyle; } unsigned int kingDist = square_Distance(wk, bk); // No recognition if the king and rook of the side NOT to move share // a rank or file, since there may be a pin or skewer. if(ekRank == erRank || ekFyle == erFyle) { return UNKNOWN; } // No draws if the side NOT to move king and rook nearly share a // rank or file (that is, are on adjacent ranks or files) and the // king is on an edge, or the enemy king is only 2 squares away. // This can lead to loss of a rook, e.g. WK=d1 WR=a2 and ...Rh1+ // or BK=d6 BR=h7 WK=d4 and Ra6+ wins the rook. if(square_IsEdgeSquare(ek) || kingDist == 2) { int rankDiff = (int)ekRank - (int)erRank; if(rankDiff >= -1 && rankDiff <= 1) { return UNKNOWN; } int fyleDiff = (int)ekFyle - (int)erFyle; if(fyleDiff >= -1 && fyleDiff <= 1) { return UNKNOWN; } } // No recognition if either king attacks the enemy rook: if(square_Adjacent(wk, br)) { return UNKNOWN; } if(square_Adjacent(bk, wr)) { return UNKNOWN; } // No recognition if the white pawn attacks the black rook: if(square_Move(wp, UP_LEFT) == br) { return UNKNOWN; } if(square_Move(wp, UP_RIGHT) == br) { return UNKNOWN; } // Philidor draw: // white pawn and king are on 5th rank or lower, on any file; // black king is on the pawn file and on the 7th/8th rank; // black rook is anywhere on the 6th rank. // Drawn for white or black to move. if(wpRank <= RANK_5 && wkRank <= RANK_5 && bkFyle == wpFyle && bkRank >= RANK_7 && brRank == RANK_6) { // Only exception: WK=a1, WP=b2, WR=b1; White may be checkmated. if(wk == A1 && wp == B2 && wr == B1) { return UNKNOWN; } return DRAW; } // Sixth-rank pawn draws: // white pawn on 6th rank; black king on pawn file on 7th/8th rank; // black rook anywhere on 1st rank; white king on 6th rank or less; // white rook and black king are not on same rank. if(wpRank == RANK_6 && bkFyle == wpFyle && bkRank >= RANK_7 && brRank == RANK_1 && wkRank <= RANK_6 && wrRank != bkRank) { // Black to move: draw if(stm == BLACK) { return DRAW; } // White to move: draw if the kings are > 2 squares apart, and // the white king and black rook do not share a rank or file. if(wkRank != brRank && wkFyle != brFyle && square_Distance(wk, bk) > 2) { return DRAW; } } // TODO: Common a-pawn draws. if(wpFyle == A_FYLE) { // .... } return UNKNOWN; } } // End namespace Guess ////////////////////////////////////////////////////////////////////// // EOF: recog.cpp ////////////////////////////////////////////////////////////////////// chessx-1.0.0/data/themes/alpha.png000644 001750 001750 00000145053 10633464147 017622 0ustar00niklasniklas000000 000000 PNG  IHDR4RsBIT|d pHYs66BtEXtSoftwarewww.inkscape.org< IDATxyxUl$ "8(⠌㊀(( OA EQAQU@^GBt-ݝNuW%yUuܮ[w9011111111111 Tf 0;&&&&&&&&&&&av0LLLLLLLLLLL4`҈(Mo=LLLLLL* fĤQ}"譇I Ԥg6lSJJiJNN>M4ۀ:d01"|`3[q8s%;/))T^^@DfbbbbbRY0;&&QBD/x1sPgL4,6miQQQ\t:Ͽ5^z"HV9||6SLLn`ɟMQX,s#N&&&>HGLL 01_T&|"QGScܹsQk U211111Ԙ 0bC*h lI}v"77۷oĉrB㙛PMLLLLL $ D4 DËyD"1"VkA ʦ/] PfŸ[BDQ,|NsIՇSpKf5qژab SЈ%N+-)KٴcaU=*MbjhRQJp ֧,DP!sZy0;&&1H(@DMF&qRiBÆ #^ԬY3dsʜAb|t n{8;J:BD C|3K[#D>¢]58} Me8ed~ˋʳg*%@ BDBRR{gϞxcEEEJOO_&Hknf@ X^^^r^^HMM]LD#BDm6s@@(===VZ5]gr^'2SLL$31|}ZB3"@ȴ 9r5j@nnPsfMMiii+srrEsj ̼6zuX, ѤIoӝD" `^̫4ĐSLLJ D -Z`ܹ=zҥc&aXBggg7P`֬Y΅b)BqFq\E۹@ `ˉEt"h;gϞ5k ^:ě`-ma{YqB2x`KBq 6aR.`:f?m?Df &f8h(3~}4<{P^=ka̙C?,[i~r6BD]|U6r;_ ˅{b…?BEqOQQQxvoX6iӦ[Ѹqc͛?mxesĤ0s fX#EhX+Q[(6yo^ 4H鼯)1<v]}8mDqKrr/ec)^6Zj!ߟ^L}qfffȹիWߠ]/TY;)KP},{/zbq&?VTHUV(>}p0䲬_^z˔C3{y/ԇR߼ơCXE?Z/d2DQCo(K(?Fnߢfz(cx)M&!%6xJCdkO!5򪫮e]&F5Dt̿_I$%%wK8´I\p5ר\N4m:#jZ)>M6E:uTW9K[Lnt.6mtM޽O]$§(.j}y`Xq8^7|3,p:wM̬YѳgO\mٲko۶-ׯ`֭WNt!9Xf4`h]MSn]k߿ JxHߕ"t:\@ ^Zsrr3Dg%L](ehB}s(ho KD!JEr\Ixr$qv}uaaWrRPP599y']̿k0DcƌhժU؋ {OƏQF=g;4)ꫯƒ%KžsNdeFF!"*2[,7ӦMCRRRT ?pӆOḎ0+DtXRPP5999]\.D4e_L+촴zj޽{gO> ;Kٳ{Eƍ_zRD'  e;LjEѮ];mڵ3㧟~*ݻw#͛Ǎ5fןmSdmt:g|iVZ~!ᇜxqrrL;IdžR֭[YʩS[nJ+z'-[n|)^?3JV@mk׷[?S4s5QTAѣ_~xHѻZ!F0Μ9BF (:NӉ)ST A0zh~x1m4ݻW> u{MtZ$%%}rfJ{ VZ+FMedf9s澔^DԗP$~0>۽"??ӧOC4hPHK!;S^wQT S~u֡E8p`H?P_G+**+z,VCPz,##gƐ!CʫnݺXbϟxO.8w\1u㒞M@HzoK,4fEy1`,YD~s"(qe-KW^gϞ>)/>ϟύ74wmu!f["%8~Wd33A~UblBQG] QdYVEF!$EzE6 ;s J֭?~cСC|嗫z[K1FnnnLuDitۈEu0e)R r@DxBqիcƌ1bD\F°aSO^E|>*D8f.B&2(-99ݢ땎n-R]FD?=z`Ĉؾ=t `~jjM19< y X,Ak 0-^vEEEEj~̼;^z(CD Ӥիcɒ%^zyשS>Zn-{Rf\HtڤPI*#&f^PVOUQ0F'O-ٶm[/e=)vpP>ȅQj7\.W] Mtq݇7x4x`ێmc 2.[b…jgJ h/9D*wݘ?>.\j%\ 6`̙x7G"H.$J#=MD^oxݺu__f:_ݎ3f?/]Qe=M*f&// G"[XXX,['OF}Ycȳ_AD=ϗ,%)) ozcЯ_?lڴ c;VuW[MHOOիqcj=m^QͶH> ۷׼ѣGUVrEqd-nRMChҤ w}7XJJʳ(^ǥ9(NBl6 M4A{w:nvKelEqzK_T6, J<@D9tn3Z>x< P+ X,`0;ȱlW̬y*NiB61ڵî]UCT}E-ݻwfMLgq,@!彠{J}f,1p[DĢ(~asNnذ⪧z* OiO<ilW6X,EQ+ٵErsӦM}+@OTޑ}ƌ\|PYz^ZΝ;yƌ2=j֬\oId,Q"3JRRqO1pj=Y2m6IP^jff)))9j<`xIFFv|9^KJ2H ,5Ę۷1xPڷoڰQ@7A*?k֬ᔔ7ӧG.M;vlg0CKnTgΝ+P{vɅ(v}~mo(IJJZa6J8p`~LhB* (?Rg<ʲ6-x.p8z<IdIIIHjUVqXnOo;h!/h,5ffbrLUYfJ1-<^ {qZlZ@ jyFU\)QnRgeeһwo/kn_ͽ%++K]tێ:Nt:sO׭[o64iϙ3-[ .^z^n޼yu[ԟkԨ?xQ}4سgOVz)%<} |R7 bOǍ|l `cN/uٸq#Ϟ=gΜɯ /s=>,O6NO>$?GGιP] ǎeرcܧOH/qpHJJ9sP7Q꫑چ@6v7.!obgj $6c5Nh<k.-[&өdmoZ2$e˖ա]vJ魑M.NKK;?~vpQҡe˖k׮6(~VU:da|AP,^zV-[p wݧԏUI)OF4|ܤI%_ӻQ~N233yʕvQYr%gffЏ 0!8a׫W/޿V.0<`;w%6rTKϞ=i޵kz)**Rt:+-h_fϋ 41cƄC0Tr勢4Gƌd5=555ȰTVxul6bgφV\fMU;]&%%}n袋.Js.;;JNh8rVYd1}{;{Nf~GkfGj"e{z| S"_h{o*{4Sc2bZPG9''G3'\oܸZYl^0Z.5^zq^TkZ+=Ԇz+Ŏ$o-M6syܹ3좲:?{S [YVˇ'x"RcmHx6--wޭKHT,+dhK6A!%%?YWXjՒ7XlR;FXVi%Q%,M6UF,[nU*B}h)ԪUWX!+>ME1q 6ե^ʧOhxpnݺt΋etWHy8~8hB>w̤'v}}yyyy^^st]Ӳ~WlRخ]ТE M[j@ ӧjZX ){Q<>aX~O,pٳ!o&ΐ4A|~.3Pv z0ʦϛ7GXGRR^P]f>1e0lҥK1`̙.m,l,**V6qذa233*ܜ>}]v~w}ye,QˤmڴvcV:N:!NHAAAcf5 "Jw: HUV ÇǨQСClٲ ,ŋq)q۽///3N{wG*<3}&4#CI] ͵~ gƼwUGƖXOhe9qa>$DtT3g΄4(sc-M/_TTՓ@#mXKW^^~JXvCփ9sFVtJkFmx~z-Iİu(Z6M \EͶ(+VPMaWNgYW:?p>!T+ƩlqHD0 V0WfӦMرc"c:Rz[nLѠGٳiC%lD[ȈXgꤤm`v{oy\f#̮JRK\W({R{=\.ֲyeeeEA955XWSÇ/?"7V)x}tX,j-z NjσΝ;svvm#mInz+ơIji(([aÆ'g:t&y?>Rt +|[a|>.((/j_~E-vzXg?D9!ׯRjժk+,XP.+gXP+ddff{ʞ_j e_~,6kR0QZ$͂i/X߁Jyn:.A*6 poS-If#GraaaDȑ#۔f;*M]w8jGYTt}tQIZ" _y嗹ZjD?tlpm 6))))n߾&qQLo}ʔ)' reyQS%eTpȦ$%%\OQe1vQnly[Z&fv;vPz8=A5eX.(ߔڵfvvi׿mDyfgzg/!)K駟VX&N(%nA*z)Y8%e<Ҩy~KZh^xA]bƎ;+}Ϣxz"~;f̘X-[SNa͸+W:u0j(̝;WDa氫++DTj7DJq0n8od+Ҵɓ'W<G0 I;{X&&ʦnՅ{0}t䔦& %cBMKKS]-[lPTT!&̼x1k,'OSyUȒr-Zd9:t O"v.Dcm۶*#F3<מp Tf,ˣD4;,XCKyqEaԨQ!:~;D4A^ 7h0nBWlANQ:׭[W=}xjdggN>}&yݻ7]R qRRR4[{a U" fDMX<+u=xժUw^޻w/^'8FH~;wJdLv."@evLk.+[_~xեXjCV(Xb)[An:f;%|5Qn;((թS'1>ʋ԰/6=FW=רQC9"lzA[ꭀbB mÅnSjD}6xFZ>}pnnn]rrrzx OΣ7of76!IIII{=hfW#v02|NA7Ȉ9z4'Odǣ2ex<|ɘ?TKj"@X˕ +euzTYfϞf#9Q&zt?Eq%ޒ4 jՊO,rVۗn1Zf41r@ tYQѹU$z _~9CҦL'N駟{)evLP㪫 wz 2DD>O}zPڵk'KX,=˜yW ˵}4h;,Mرc,j(^iBD  {ժU]-J:.͇2AX0Ug?bV Pv 7h}ܸ뮻ШQ#YfQ{z`Tҹ"HD}A+o6 o^@ PS֠A- ('Hv `0((2m4X(!J/>F5I,DS^o]鱱c>}$Ղd|g;vXaaa]Q$(BQ(L3gNOaΜ9JC`ϰlp<@MN*Iaĉ}ݥ4sEڦ6L5عsUB8e M5lD#;b]23rZIMMMd1NO417dVN"}  q* i4O"QMEq;[r eCSxH- Ϙ1CKeƌAKt'ZDXn#!ΨYfbG;i5jԐ_ew.CBDY3tw垶htjfx= {<,[ l2Hxn8? V#w0do۪*:WR`H;@z {o]i6jL8eJ\qkۣ1҄d$%%)[VlzN 2f>1lf z:kXMD4!"LVQ_>F#G~jUX,|>_hg~m<'l֪UK̉Ô#M(((H`'%%Eq1.qm۶|)0`cbtT|#ae9^"7nĥ^tiBKqFőLpHD S*'#;wĝwމ~. VBβf"??_֙3fL\Eh `i‘#Gp*?Mj8uJ0SX`(c}>ljE ]PTTt(#;} "j68j5koK,Q<~7Yf{AAA "D4Dy>Oq8O͆n7.'҄cǎ%Xs7c!i6eSb Ʀ7*2BDl6g^7EٳgѧODZ'6l[f^`ʇދ@Hh\+)-;q<@;i}{SL-KNNM6iirY`,[khZ J|w5yϝ;Wlh!:J1q6#w7իWm6(Ym6+#$bү_?ӧb o'х~v'O=J$kԨQv=$===}>j /[hl VS.#k84SGJrRW葍`Y׿PTk3gpua۶m SN+rssѫW/|!wy'j׮r۴ipUۯ|R7|h=_vH&flZe_WXӧ7P6m'w Aы\r%ׯ,_~6_ :moU:ro`ԩXjf3oXըZ' qa=T)K#55nT`4hȓD>|XfUQDD(> U-FdF";*(.V:D#999ٳ'~x9GA=?{<Mb+!CBT<+ ̜OD?KӥRC,Wf~8`3f nݪa(**`4= 4I?M1M T0Pq{:`֭3f &L {It8^7u/Z~]VU*7,KKMMw^ف8=J'>;T"r #~ Kp_ڛQ;HZjJ_k2AxSǏGoиqxTa|r,X+W 1< ,P %aw j#`%BVڵ aUf݋C~:W$=K.ŦMpeaÆ x'1}tً`t={Ě5k={t1yYb OBE[+Wz3sT;wŃ@ 57UVaԨQ(#(|iWcǎ|A5\h*ȗBU sH;~;{w:]7o.joUT>>h^ZbFA|^{mԩS8p<8wA(p:+ѥǨ͛7cΝطo݋+WɓeN4  PFؠU=&03,XzH'H=țNsbAAA=KiӦw9r$?K,^/@|#^@tuhРyҍ2Y1^͕,yk֬A ϓ6m`˖-iEEE):ub "Ҷ-AuaK7 Bb9w_5kVHd&df De1,h4hWV Hz6!dQ1AS.{X].">zhTv k.~7yќn;ER(W_K,)*kժuD>lTjoN |1m[ݻwsJJ޽;n߿̷ g"^V6zު]vE]N:qN^NڵUy뭷rnnn/V; _ETkzcر ӦM[rvZY=l6I6AoAq|_~^]MoRx،3&J1c(5[8W͚5S-?dQelU{=zǏժU#I.R2dH[.5X|y$jڀr|Nmk :?uС/^̩2[/VG͊+xŊq/Gi'T^xܢ"nܸ N[RﯽL< WZoba?ױcǔ}z/nv[EcEBc)5lp|=.>wm|Ate 9ʔ)^~'x fx&oR#GpĉHg@T˗?g9WH'iBVbLZzuv0d`jF ~QFgVXzҵ^ҿaJ=+./&",\M7ąf Çw8ujDvv6:=zTvj렖%6-$`Ŝ9sRɰ̘1Crr|xm!7.$i׮걶m&P)((P`Zx%Ks~J׺\1gh`(wADD>~8WFĉJ3s"U'_[;I&xWqY >\锣f=Х;/=xꩧb:!]^{mSz2se"rOAW\qK\oػw/rrrӧOҐ47m͚5Xv^^wM6Ɏ9y˘9lʪ qe233*9R ǎC PXX.47Y'b_O6 'NCrqi҉>R|G /(h}lZZ_U(ڵkȑ#e@cfWs@O#"|lϧ\։ _Pz^,Rzeu5kƅ8a)+}c۳lp 7~l3fr5"1fA+?cip|>u:'Q5EUUd)٧*,׊{Nf" a8`EQjV{`P9jQ+nKKD kUhFZQq`ZtW@>%%%zf1|}QC{>KðdY(',O6 l6mR\l$U&KKMMA=z4v)KEq|7)FJ HnOAoR[Ԟݪ6"̼uDtcS\"9gb͟0AIФIXO8Qt08s35jh}ĉbM6h۶-ҐT@\>}:8u~'l߾`vu:ϟ^.9r-|cʦ/ZcƌQ@2_ub"C>?e];S/¢_|,>f.A-CBDvA?#FhVecz+= #v0 f֠x!S(BSty"L y_~yر,yy7:=Ɖ'nYfG^v Сt.]ꫯ9 4xӧwo7|҇TYNw|2M|78tֽ 6ᓱm6ڵK鐼Q `oEQ{ѦMtQRF0֭[ ѿ|; ~lBff&zY{FZZrrrJ@u"JHĕ~ȕ :T0sh_(zQW"Z tv.6lEUb`(GvEQ6?ydYO{7pC:ђ}?ӧOc͚54i\ZTPPpce`!jfVTw":;tPG~$4 dQ*K:t(GqQ? SuPIӆ fo׬1ba &T`]:2ԅd!uREN:uJ@jy |۲e 5`۶m_cdgg#77W&EE|T###cZvvv.(.vڵk|v0w%È s$j9;`ј4iRgP\zz$ݨ[.u`v0"b`C7oW_S_~T)Mkժzk]vErrrTym o*̼ 5SXg["j. 3ޝ,}]PETQDe6S*+.:#spQQ@VE$,!IH%I:s>֭{=Vuݪ{ϭcȐ!RzY駟bҥXt)֯_oV{n޽K.=&I틡CbС8Rڵk>l/],#hf44RڴiȎ;jM5 W^$2<aCU;ܔq |d͚5YlS碠jA_&ӽ{6l;;7v(/V/gX۝ mFO?;3O9e(^>3X4hgq{gq$۶m3Wr~u(JƿzkvOɓ'Hsav.P[liȖ-[.650)MI&~| lٲgK 5&+VGrmgg튊WZӦMmf졯EܢE=mۖMƫVնH$^v'S"YԩS~-vmܮ];VKvnoִ?w\]Ce?*bִiS>x𠩽_8n*Uu DTVҤ?!;Cͯ`̯XkD9dz_aa!㤓NʾbYvMe3°T N~xp(3fA 34;GP)$h 6lsU LTD#/-Z@QQ4i"E"q8pݻ_bꫯҊ8չsg7Ǐ3O>˲\sDZ4]ח-X6mtRt%%%?>ΝիWUر#v튮]s(,,1*GTTTyfl޼[nE(JKO>&LѴiSlڴ CX0aCpxYZ6bO6;}q 7dE| 3?%,Q "2UUHԎ\G4yCQw`ɒ%ܐ*B4-7&әѺ24VL;sxb42gذaXdIlTf~}r>cʹv1p@'x"nݺADi&[ׯb  _2aVYWVTh#Xq)K}8ѿt ]vE2b"য়~͛cժUXlmkkUUqbʕ_g0V!eY^Dj޽;6lU3e~[n.IR(9ύmR3vMY}ܖwءO.AD2 =zSNɾbYW1 )@ P83g7lZܶXx1.\ŋСC7'Z! ͱO?駟P۶mòe'`ٲevkO0|~03HFx_|1Ms#:|II }xrUVV.-CDa73fH4])w}뮻 kTD{HMp*rvwof?'E 4k׮/ a+ۢ]EDzزs__|:#29H$˖-iӦ1l߹l ^a.#xܹ\ZZjlΝ#F7abʩ@43yIEHl[.)6:AlW"hAm,>7if |ʦk*d=,NNd>}=ܓh4+/nݻw]}|]X{tڕ_z饬Daf>x O:G?s|饗k׮q0>r 5zjҤ o߾= Xöm۸I&|^^ ȑR+hw8n8Mof/?#M,\>ԑl,ˋpZ",/۞NXVZfunwQrlrwXazF/s-ԝǏ<pwGngƩ@u o^^šXL+nsyDeYɓѺu*!v܉Yf-8fN=b4?N:e[[go8 =u!vahtu׿9\&r4 $rV%%%1gΜ#;?tIq=ąN:Ak(`0;-FQj~ ={x_~%?>^QQӧW_s=_fmuVQA4M[o@1r z-\pqT}>E^3"̎ݷmADx&!G֯]2رcq饗bQ'XGDW3YVqckA#{gV8|M6)" "B "4Ms\a.] I䯾۬#Æ G$c$ @6mлwo03@ `0*ZcM( )$Ȇa 4in)h>,N߿ֱp8~o|Ir:afq!XᰳVg]O`t=c;&$>=O\I&=GxРA_,_ѣGm,/Ajk(d[H,bѩS'~w-a(ܼyO{l׮;rN̦YC!FQ^ϧ3{D?Wvc%ێ0RU}ќ*hyVU:J@1pM^K쟋̙34/;wNO\ xlRC3fn,.ȲSNM;jО={+sH<%KKKyԩ,u]αQF֭[3sYY~ 2f.++K[[QL\C:|du]O2;//-ZO:,<@edٗ(KdN:ի-qD.zj75 eΒM0솰o>k ;wNY.]8ԲG}ZA/_9~?u@o e2s-[W_}SMIIS~|We˖qe&`4˖$F" ?n(֭~v׿!.6WdX@w0M֭[u|ܶmۄ}MUua9K u7QĪNR7n\}7g&[XL:"&K, ei)-5t/Eڵ6mJ3{}Pdr]tm~~~aȐ!q8?Gyy9O6-nPs9w5ލ7!CpY-X[$W׮]o?jD rn1cF4$mm-Y;6Fp(ҧOGM;wI'ɲ|9_dEyD7g}2:>lQ1UtcmʏvcbMd @pL^^ޣnxڹ|ꩧr#5ƍgzaL}iZeGqh4}=֮[Nx=ٳM }sݶm[~7Rouҏ)k EQϕW^۷dرiljF|WYY5M)IR}jvSQQ\sM] ?l?1 _b{ h_qaƍf2i Ӛiݺuw}gF`֭[]Y`'U st @Iak$QÛElpYb4UU%37 F]:ho]t~AhѢVX /l֭۾^n7!oE޽&]׃ûCNf.7cIHUUEUUYBfh0 P( W[ `'c|{ IDATu*cщLx<(//;rH̚5 mڴIh4z wy'L󨪊n wuWjw؁ɓ'cѢEFp3KlF)} I&M3fyԿpBL2%.dOsα_~;^|EӨvfmx<ߗe.C!seY^D⢣Dž^hjcѢEꪫPRRwLUU(:?A*2=01={rEEEFOEEld: m6meUSߛY%},A/I~9}16m̌M7oiO`rVf͚#j,q0msTv8,ΎesN<MhժUm(Ζ?:uCGү_ R5I WeQ8\t?лwo;Tcƌ;%I VTT\rxp!$IZFcرxq'U,(**BQQ8Vرc}Z#{Dt3ﴴrJ\)qIA 0Np4 0ƾ kNf͚'=ظcD4c*DD"Lk۶-hJqge˖ɧ}lK>]vKFUUtڵVZh{:rHBȑ#u̦@+0 ˧4F`q*lژk,71 #iRgeCVIQ̙3V?FQ̙3]vC=@ `OGc13G#$M^3;^YY{ݺuüyZW._=3+ۣU j=@_tEhZ$ oka7qhuz%K:H`nF۶G,H`!ӯ4hժnnq\]I~~~}YUu}t-܂>}d]@ cʕ;w.֯__)u .Q"\eD"ٱc&L'|0`Ҝ0`O3gJwݿ,_`Մ7O>d4"6baB^o%xuUcf EQ:!C+pC%&˪do7x]r3fD@i,#{ɚUn:gȘӞQwD\F"ӑիzjU_gK.AZ|>_K"[H! M?SMr0@":7حK&4w5O?gI#gO?ťifb z_+mXxM9;cxx۱)9ƍA; ۽Um{˵ W}cק`\W%//oʤ:nMez ^e=ݦq_0)q uvΔ4m?|S1L4m_ fcbDeyz $M "zd "R*++;ڭGPYYفmH$? feb{4v5!~"W\(/ y"]9̏hR7?mD""$LDQ/b.h>0[Mm$h4ՇsvMhط!4vxn% *[\Veee٪.Y"D?$`p&+df?Y;3;*Q^^cO$)T6aD/ڭGN/VB `FbLh,4CJX,WTEZ gfvĨвZnHx~`۬@P/Dt:#'3/[L@D=Pu$nfڀ3 @ @pt5@ (B 0@ e@ @ 1@ !@ 2C @ X`@  @ @`b!@ ,C 0@ e@ @ 1@ !@ 2C @ X`@  @ @`b!@ ,C 0C \A 0DTXPP@vV`~~&M|DDn=@ p*v  D4 gݺv_*I3޺y<}>H$([ @+@$D_媪.cG`D$V(ՐTU 'fJ/@< X_6tX]w3eQY4 u]>{އv3(TEQyfy\.WIeeDf^ !F9G6m߮]ŝ,Yb:4 c$I镕Afg^{~C vDd? `UUJ'o,*;3oQY1 cB(z1n+++;dR'"*eye$V_^EQ͚5|ΝeR'Aogq2,.S p$b@P֭[YPP L$(?HMI~@AȲ|U0|)/((XBDZt""믿RXXxitLƆ@D(i<D9&5kvh޿QZZ3?UO}u],i/ p8|&3$"zVTT\6ܡPh4gmRO!9htJ:DљJ/A! ZPZZzi nrN$p8K3@ d09()>4*O 4I"O{Z ֧IiYQ,!1uhTGyp8dY('#?8tPdž[PP7ʐz$ , ^L*ί.;%%V*%RzJ5^D5>a\f+d}Q]A 0,h(φV &i,93o&vx̓9'??AiiģDҚ(ʅxQTTtف_e L)Ar\ BP8 Et]W[nݴSN'.]cv,"M̑HdWd0|>_˲O '8rJD71i `7I"le=D\M >n`7.\Yl׮݆۷+$IKKKKgK7AIYy*BvCG 4fcǏ `ٱH$r3oʤnCD^UU B|HV{ߗ_ؘg=E*!V1ADSH$26SuxωȪ?,@D Dѡ+"jnXmoA Y`AF u0 cM(nUg|ED##b(U{EQ1"jiڿ YW^^_/ ^$dl?;sJKKtݛL&fޑnpx$챠_,(C WUukd-JKKx< #p8|0uZE~~+岭Uq(Y!Y(:t JDi.X in "W (l>>zU gy%V(RgŦj,(C 4"rk8 g(/SuEPȲ[>}f}PH|M"vRYY骨x,//oi.zxޯ+++03oX yVbHuS(P㺮o$Qe^0|mV,=ϛ'1Eʲi?F@:JnNpBXD4QU VGu놑#GB/.#0 :UU*++jUi7]aU`5 xR'`Ey!b/$ шp8l?KDel@鼹KBiEYEEEP%*p!IE"H(:" 7n^++++`0D$IP(TȊFyn[;۷/fΜ^z G$?s[TCrpܼ>4DO\1axظq#.rr@idYiGDtޜq\L%Ox]}|Viibj@`aLn]ׯn g#lU?x8:.BSee%.b̘1]t/{-Z8o߾mQ$솈:h"YEQ 1vG1FѤЋfdZ>!R⭏2'j$I0 ?'V3+ `0xrc moQjhf~n% ]o_PP;믿6]'a%W^y%fϞ "¯I&aŵ}>o9^A ޚ- Mt]0fuiQWI-&"fc ҝm#CDǢj¶ɽ- ~X~ffKoD4iӦ/r6WVVNf[\ n5DC>)L":?mVfoYg`!IYOvj .KKKyʕ\PPqr-\'x èGURwK`M|ka>]\)]$IzRD i.ko2$ }`4);4Y?->:%cn,W=t|4 g`-mpp^vw' Zڔ]/2ul 2zZ~WܫWZy( v9W0&cleyvj"Ic I>@GI7o>n9IP~(ӹv@^ :(ʯ)\B}^7\YQ\;2$Om+$=\vw' (OS%M'Oh C$^paz}>2$6_vYhb?(to:zMKt]@۞A\4M (@|'!WmG,??e]viҤ _{tR\k֬qƱ,]ܦMfy۶m[lIX-[4GUOQ^w]]&L 6P(|_}\XXXg۴iU/1mDvn;X!T(t(ⷻs)%rk-P}c?>i??quoܸk$i1J W}Zxϲ۞AdY~6??@Dc6n-Tزe _vN?Efy^/ַvZ3`frz<}t޾}{Jm޿?x㍬j6A=Ď60VH֧Ha@H$Sh?dma@D=t]%nYСCADHOjf9yo{z땁@3)yUU R8ǒ._DP `-u̼7%;+f/)w}ÇD;/.}ԨQq{,?pCLD5 sAqq?nfc#iP(s"*${;06FcUU42Dcjی{>!9ݯ(&LX"YS@EJnZ䣮lGuP&IRV4tSWyTdES=O…Ӳ, V'hf:vܹsj(?(uqfSm~$%Iz(Yiٲ%{<Ӻu]633?S fx< Tmh} x>70v*ba+rSE1uyY?S孷2!"4c2%.'^휆H5MA_XrJRߥi% К7ot2u]qMIg0LmեK"ʕ+c1i zk3f̈;w79.r‡]u2˗-\yo^cov2;D.g:B$Iѝ8vşR NH$±|f'; wMUwt=rݶNU$Ij|Y* )?~+lRTTu5 SK˵ì>;H.]wy'O8Η\r r-dɒ'N>JSMv3lP)<}>V4M+E# b/vSD, OGq,|A\>Y‚H7($9{Eɹ7Yz2u+UU}*]uݲ/kM4yÂT=SDQO8p _xA{UVue˖pp e4m4nYf m޼9WVV:g߾} 7qׯ֩c$/ܴi:ܮ];9s˪X}?Dp/[Zn4݇ŖEfWӴg%uӧ ȖZi_֙GUBu\/.;Z:u*{챸3;Q"Z̔麺wM6ѣLIh8f6YIa|{r{CP7f>NJNoyN2*pہ:z>r~~~Cbh:$Ŧ1 i&\veXn]wyxТEy݋38~tMxGk3 .4-ꫯs=W+kK^z?s1O? &`ٲe rg`޼yh׮]<{kT+lA0<'u/}>__vC=15^j~~嗄#6^y@/0Hd]:vhڏx,p0wݦ#3!NEyn'+zZ1iԟW2@kȆaXt4a؞i{cԩ޽;5OJ͚5~w:u;xɒ%n޼t-E۶mFۦ:uԉwYNsaכR7߬۷su\a?Zy]~v+ Xmǹ3Lmu6BDwXݥ7|(t}>t,emN 0m$}t+IR{P8-C~EK2TiCUҭ_-#3YtimϞ=|yYb)SԹNaӦM{eiӆW+7w߭gΝӚn7oڴ)`ǎkI*HXŋ{{~nLޙu] ̈VʱszTݦ&  *SS%Q䮻2G;w+/GK_***ZM9eEkG ]?M.>C)U{' 8^27.vpʴilZLs&M >|iYu D"<~xK|9p0LXQΑey"M=c2 ۗ1٭@u:UVk$X&jqBQ~衇R:O>mYYK Ȳ̺I޽MܻwosdYHw~O_KߤZofUGοjכ-㢋y<Ӟ uYkZa}1YfM|_[bEcK.5-Ϋɓ'g͗]vY¯7[nM4쏩nakrp̈VuD^8H-;ƙ뺾!S;vt@>CDδ˔8[wߝ>PLOEEEO~۝HgCz].חJaj[?t][-3_ ? ޽{i#G k׮${.a4gyjsѥKc_~9fΜY+#V̼+9"ZgBNDdY9<#:FCQ2nfo`_D$޵k3JF/_f79 2\Q-Wz|u=aD0)}vmdz2^˵<8;EiJ*rۢ15?:F<`L۔m۶%ͦh]x fȐ!q55g0Ç'c5;DzX $UUφ/0Ѐw,AFDcn sN駟pꩧfC3p@lj(۷o7MsS(e9+1sۂ}pxr˲d52\s5 Ϙ1#.W_}e˖?O4":pfW_ ߟo1=vǥɲh_b!"a B7إv?&&v`N`$y&im/_Ν;UVh֬:t?'N̆~e̘1G޿Jel۶4O4M/((mJ9""YۭSeye|t/{<S9WQK\5\铗w_:FS9ƅ R9WӴy~*r:Ǧy[UmR_/lzl&df< {.Beٳ7@?ܵ#FKi}up\k~/r|>@u[JM wm -.RHlذY$}Ȳ?:efʔ)Y|i~Iv>}G}6}t޵kWݻ{5=gg=K~kvSPI&o5?\_xv6^IZahbepݥ$:v-?#S[cYbE\~MӸ$.}XQ+W4-{Ν\XXT{u\ N~ ~O4M+GO]:n,v7~4n%_|q6HQFڨh}t]t>1r~IwɲR꼼%YWlrrɲ[$iAnOEQ܄:H/niiJۮk65߯_O )[6a pCqq?]$Ijv./j/)M=J:HD 7- Bm+LӴR˵iӦ[ZnׇP\e!͙Ծ-[lߎ;,:y͛ͻ_ /ĥK:ui+@-!_Yё5],5TUkpرQ/ѨuI"֧A=I$a|3!a|h}3%%cBKyLcn"k>ȴNOSw܉9JJJ1Q P(!ʜnD[ta媪&(Dtq}e9cЛP`0xRe 3/Nz9PYYiiS{??ӈFq麮cѢEO<ƝDO[qǚI8*Dv^YYyaEeeY.ku[dp#6HKmH"Tco߾8ځ'VHoϱDj`D`b>WƼc`piI@  xjMD",WaBZ"*<<*mZ{fX"DvD`%(HDeDDf@_tpYfPe&*dED\Pvd@Nz~?]u;yʩ)復,{}>ߣq7j~@DC- %I^8{l~lYFiFugggcذa8qCqqqTOG^u$##.+x  (J)Ͳ(cKOdL ~ [cyRl`0P(mQB!'c,:ĠA`L2}t-}ljFѤI+SQ1fM2d_D~cl,W8r$I16Zv0p("{IL6n܈JܽulXzuFyFҽݻuZbQY~x$I3Vvi`,Zu$K60]$Y`z0:wgy& P\\\{˲~3sꕩ o;({)N;+["Ҽ^n$")`%a; =C5i>DD L  EmkA :^|E㹹p:+\n]LWzH$biZrl(_Ph&Ed,'%IZUJ?/%)F@$ -T RZZ@/(Jzgl1xaBb6"ږhd'kOp)y%%%iOm4}0Xիq=D]k… 1}tUv1h W o?%Kct-իWG+))IUXBBV/AiZ\W p^4mkA0Y8X_X`I0՗ ]jue+x^e/^Lz?>.y|'5kV4gPZEm;Ÿ$Iu|C&w+334M}zogֵ_6;CvڴiճgO]4Mmu*R0ޱ$"ŏd-c,Y>ζwl2K>z0eo-qo8uUU/Q8}ODcRlM0EDw1'IRѥΞ=۷^SObTUKC rjjj* u< bܹq.ۣ&x˲\@D'l0Ʈ)񾯦i2}_'oaV#YaÆ?@)**ow j-Zо}H͛7SJJJuLo6%cDE|TEMaQ}ƍ#=0uܙbD <8fO7ŋsu7n^yw 30.y(=H2:zn7ϟ+WVZ`ڵ1'Yc޼yؿ?:wu7APTTnԥe |$U"$Lљp8w$$ "MӢV]1UoÇLҥKbS}o EN8P˪cVC˨{sw 'Fkypn雠y(It7|C8x ՋwbW^bŊㄉy2u{駫KۖwFNw0[z4 N IDATbDE?o'dY.;tsʔ)[o5jYE1zM%%%QחZ[o5Lu(_/VQffGֱ/y(q7@O<D3[FIo W_됢>6,4l0bNTօcfӧu}ᇫKۑw5[n~7SϓE w<#`N4|R9BnmۦkߡC^fept]~X>ĻXAd#?|p.)EQx`4\ƜӦM]9r$ƌ!E ^\5p8Lx^eϞ=ύ1?0ᣏ>Baa!V\믏ׇ~>}瞫50r^ҸcJKK_LOO?{L~tI~`ިZiUQiG:׋3g^ܲeKݽDoVXX0gy-[=7sLxfEV[ׅB!ޫ9`»'˵[frg}jѢE\xv YGd":L`tmR?tm曫Kc&„2oJKK{]nOX3<=^A?&=4Mo/vkתU}u{.cIt]O"4:F$]NC|=9Ft: jNDs7 9p<jim69r!s-b)]Vz PgIԭ[7߿?1FAnݺQvv69NC/bo?VuhL 4*&HvJ@(**.]pѣGl:sLk$Iҝw^nvw%Ǫ@ >G*JII1wjjjRn$I*@%Iy,eee͍DQslJ%)Νŋ}k!CxbF͛7.}?6Z܊쫏;vH'N^{6nHwcǎ Kǎݻwӆ hѢE4aꪫUU!ITn}޿щ*dzw_?1vjܸ1Ι3GצW\{ӹܸq.?J+*Ԥax7bN 1@@ZjHm0Ɔk]{H@ p=vڴi+B!A:u ǎѣG+i’Ǐs:|DD 1B0ƚ]V۷o~UiӦwi{:pfSGNҮDvg1vHPfFTcLeH  ʲ?]tMoF 0΋ 6 +W:>f,\0yd Q6^,ؼys9!9zGa"@D<( 昔ݯ(i16/@& o[DY/WN jҥ zk~(8Xe9cƌEw}O39~8-Zƌ3ve,[ Jg1Ѥ(QáՅ7Ю];ǘ̔g_;uk˼y*Yt5٦ۛ?#kN/]JJKKiVn6卷e쇑vIjb&_A5 x-ju7ǎIkǝgϞG̞=[7nḓ,S:mUyǭ6R%O7t~GNj_c [t~űcǢ·B!2ԩScM7+틼냕0m.cLNɇ ~y떲,YiU @koؽ{wM7?RUU}RGϋcǎэ(O|i%hܟD!zȲ|B<>STi4tPS{9];RSSyv8qTZư>n:IpVI㉼OEoTF 0T((rz'0:zշkdtd̥Nj1qD?6 b׮]ؿ?Ν;SpeTǎѣGݽ_.2qDGw:oЀ!C,o xے F"*b`"]+SO=p`ɒ%2dlbGEFFFݻwGZZn Xd ͞}YEgQ0J 61p\JJu$< -VXpd`(v\x/AŧDQHMBii!6x^_ׯPW޽ѧƠ7/zAC(dAZƘFDoC c,rT5<)I[.=HD=z4ZhnӉUVaȑ7cǎoҤ <93z0N,]]0z8WBwo1Pe璷`; 0TADcyѾceʲ6^H3 "UgJ5M"-E-Ă jgjj*z쉶mV4$.6*bGҤI{W^իWcƁsNcb1\cС8uT9Q/ۈ6222~WPPd`PImF)UUׂ7SZNtrxjŊ_eyǃs];vuPo~t;t@'N|:uw}Go?ڶm:py<|mphzeg}HnOZRR҂fryޖHDcE;yo~m 2$^;wLv+..H۬(K=kҤ &LˤJ̝;gT^ETż`0'Afɵ[ȑ#1bt %ƨ9"ݻobҥ8z#~OD260Ɔ r_Xzuj㪫$EMˊ+ hժA|ҥKkΟ?!C?:' Ng, XPBP(@DxRgxp"%XhdY߉(Y.{3JW&=Rp8 O5Tn„ bt:|guE'O>pmF&M~3& U$ݥƻuFODaa!6N>MݺuFHAdZQXZZ~.,Ճs0BD cH$0o[Ƙ*..Xf rssW߈haYX#_rN ٰaw9PKUGqơ_~1'֖|g8s Ο??1==ݴiSt-kE4lٲǛoY\II1cfEQQ]ڵÆ {@D8q<СC8{,QTT 1S7jm۶Pfޫvr-8p@9EQBD4/ggd/#O F"ٸhܸ1˞ҵkW_^t@0۽2t_>P&K&v৑222Яu6ׯ222V)s0)a ByUZD|3gO?'|#G\0жm[\}ՕYA@  I۸",UU7|JnѩS:̙3ضmmۆ ÇꯪhӦ ڶmN:wݻ75ۢ_~%'NDS%ڝ0:8+cp81%=m5P"DDQǎ)Yر^7ؕd'FIw}7|5IK1T/DQG#oF7UUOnH͙3V/))+WҘ1cy?-[;竕sѻJq1KSUէLڱcG> _s:C=D }WUu;vPffE)E mSRR}uR >sYۀ`t_O_Wyz|oulZ~}T/kv8qGNJOcs"WZhu]r?B#Fŋ-?wbPUիOC7n[ u?\,Qf藿%mذAw7\VQ/eeq\.N oǼ $ت  #:dJ Uiˬb`UEn6lUwnZcCJQ{jW~I'NK/D IǷ:ɲLz+͝;N<[[/C¡(˓+B˗/'K˗/￟ӹǷȠѣGӊ+*ʦ(Jߒ w.UUxǵx<@@DAQ/PA@@,(4QiӦf͚mpn8tXYNN]믿3fе^K1ޱctu̙3iɱ E9?AtL?>͛7ϴ$Atϕ3X]y]2oT'y3F8zEӧ6E=;16la5q8 B[zkXq7kMxA NvX#8pO?4W_n(xGiGDؾ};oߎ'x:uwܡBq7  /c<yN4?c cǎŌ3*&yxGwUe C H`cBiixRW v…(۞*ղ$)jHTCWOܼ[Vcb~mdժU5I۔wLcaҖ_,áO߾}/|駱zL$I~)Q_ݻWƍME5qnZ^k ͥ1EQ|ߖGV& V7cN"=s<쳘1c~!UQd0ƚWXX4KHKKGq aUq[<wC/|뭷L#IRwA_~f177 M&Pt=]py䑘*I׿uvi>us=qC #ac%v_0wl9qo? ʲw0M>K]Q8(0Q馛(7x4# {/ԕ(ҬXЎwER#}v"{޽{%v4Զm۸лwoڳgOŽUUջ;.BH_m۶WK.>'6o\zɢEb.)[5oޜ.]Zqu XA,/0$IZ +@_(qHTޕky4iB|5I;nVtMu<A/?&ȠK ô`jԨQxhɒ%TJKK駟&YdCFhQ]:th%c=ɡO>s;e(cE :T[ZZ4%Iװ<>SpgW2EQ^9sts5IX#PփQkU;c,7 jȕc~cp8j+..ŋqر:4p`ؿ?~E&'I^2gݬLx~;uT=f͚={O>uh׮]ٳ'y8] ѩS'\{Yx*,s95zY$+~$}fEM DQ1V OLhIFuk۪̗P}I&Q$5;nVm7I|ŵ^K=z,knNjjj+$nV~mٲ%U̙3/M=U1'_|jѢE9sf eV)QGb…Uo޼yYfoVѺu+W^17o^,\0*(yLJ%B>~O 0w++k- TU}"_ޭjM"HPӦMF,] `zd^xᅊɓt]w13fL:ADԺukuEkU,ЈKlLy;8{jܸV @ awt]vY®Ѹq.%++NPYAM4P %\ׯ'"W^yMa m\tzWAy^孼7eXLDe=JӧO˒Vӧ#"]7wc1Nr.Ϫ sH/~PJJJ|m 9Zf ]'y ,.>{DQLM5<=u,%uK %eڼy3׏oV~hӦMQ}ҠH?L:VXAmڴ+ԦMZbM:Uoxɤ0wHכ3p:,ؤx?&`l5eddСCo1, $ܐKt:?%c.svG S@7sUEY񎏙$iI233LJ.Iq2C|O -5;>"kit X 6VÇǶmЮ];^`yQ0ZP($>8@ii}DTiQ 4-! dA0ƺIԂ^z\pcڵعsg^>`dY +ҥKԞ( ߏ-[T:&rү$` mGK'3W4kC1ܒB$b`4gjȑ uJ\(;yp,8XcWyדHŅex뭷[oEŒ1GBPeb `0k|zQu# ]/1 n#hHA7cS tR 2999x衇t4ju1֞F?0kD4ބ1P".z˥rpm2v\ʝdhViKC˚+EO4r IMOn`Tup 7`ʔ)hڴiy"hee0ƦQnt(D4?ADP(Kʹ-1vXKFp\Q|>_6c7'̦sԁQ16Lv4m@r #}j70a޽رcu+m\,w;j\\>>A^70#p\w&ɑdžKͶvC>Hvȼ H4DQL75? }j70j'(,,<}cl2̴1@c3(B DTaOT6~6Q jY,X":ۖX02DQ++n:&qFc`/p04$I9Ø7o'ÇIԕ)! KxRRR2n`$SQCtT6 )=hclo|.q4 lz e˖Ų /HVC^^,L$iZ=6|H%SA!V,`YEkw dY>[oͣ5oBUImHcI=L1&|>KW+Z3r9P61jb`:$m 8@D3RSeE;@ "CsQ_(HDl$I:{(v؍>-o;" 4.UK}Վ6֡& ㉡k0nj. cwc?/fg.Q"ҟb2=J-d r,916#wya~#XED6c]{}ěDdGacccccccccc7vC,a70lllllllllllv&n a70lllllllllllv&n a70lllllllllll&pBIENDB`chessx-1.0.0/src/gui/copydialog.ui000644 001750 001750 00000006123 10712472536 017666 0ustar00niklasniklas000000 000000 CopyDialog 0 0 400 342 Copy Games 9 6 Copy: 9 6 &Current game Games in &filter true &All games &To: databaseList Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok singleButton filterButton allButton databaseList buttonBox buttonBox accepted() CopyDialog accept() 248 254 157 274 buttonBox rejected() CopyDialog reject() 316 260 286 274 chessx-1.0.0/data/images/camera.png000644 001750 001750 00000047645 12142367140 017745 0ustar00niklasniklas000000 000000 PNG  IHDR>a$iCCPICC Profile8UoT>oR? XGůUS[IJ*$:7鶪O{7@Hkk?<kktq݋m6nƶد-mR;`zv x#=\% oYRڱ#&?>ҹЪn_;j;$}*}+(}'}/LtY"$].9⦅%{_a݊]hk5'SN{<_ t jM{-4%TńtY۟R6#v\喊x:'HO3^&0::m,L%3:qVE t]~Iv6Wٯ) |ʸ2]G4(6w‹$"AEv m[D;Vh[}چN|3HS:KtxU'D;77;_"e?Yqxl+@IDATx eyw޷3f+n)+4 ˖%@-eW K,GLlNJ+eZ8bXIdI%d @;`0̛o>}} 1O1QfO[sS]Սˁֻ7z.n(\n( xs]9. pCxwr˻]?'n]ݼIozo:zRp ?3zWKغZH-ZWɩ`w[{X:͘}ZǟiSd|V{Vʉ '<ˑj,W" B6dH"gtx-;XN,Qn8޵ب}҂90m~MwFCaMxX_—Z_(i˗t#j:嚦[5|m#x(C!Sb|5Ge*S+Ᏺ2_h?( ^hmd؛Vj4ˍ}5)g}!kIs;- |fۍvZ,гukI0XfgƲ6psg4_WgS͛hy@b:Ws0,OCԫ6=4ײ]ZN_ PACDت oo~ qM^:v2Ja۴c/2ڧ ~o|6->N<H{!da(uۀM閼oBS4m'ힴ,@Rrp샇V$ yOҵfC+x*azuu5n끾oU@hR ̧Szn%]tHg7} {Ű׃//on *vP6?DJ(I4L/C(<-8i $ah .Q%Q^2+.4fy%UcD~Lj%W+Ӆ`R58@},%!WOB϶=-W)xiy/xQbۉ?\#M7ʰC?ddq497myMc]-y͆`1 7%do(>ӳ]KUXW#CUu`FG Pr2kjn(ƛgiNT } ׊m7z-†Hs_9mSŲS\PYtઞ_Xl챸bIr~U?4}e[Hjbd, ns/V'O>1(L-&CGx dG&xŗmOM'5 -^ԻEFݫ,EL!yJGWvJ RGY%%c?u7iY1aBOu1ԗ^{3=+?g<zue-ݗw4g;c<^9s:}dvZ”`vϰ J!=N×tSN؂F ob? \g `|(y'}Xr~|!\rfŗ \B/:'t14fVpp׍Ū_d/}Q(T-ĘSǿV}Z '́j'z.W?N|DFǪ}{'"&Q"@|,t/⥧R]psFN6I-W傗ï}䢡}}iaL^>_WXq߮z]/ӔLR/z`X`i5n=]z~wgS~'asB/G{;aN*V㥰 F~L[WY qXPBU)[Xi&_Zc-/tG<.5`_;-/T?h:ƉjxxPα~ Oe'<%ȧ&`#,^|#@\膚iکgwo aX,įK^XQU?ٱ=QiaaK{୬TkXbl0JvP(W5v@2Du*]d@gvg!wc[,/V_sM3)GW"V %p^C_Ɣ(ɏ~zgh,Z,cv%r|{kx-.GRx\WX\{|nrO: 6?14}tJMرpǭ71"Q֖嵕ԿȺPzYWPS zvfٞtXvZocaB: Npfg0](H~vQ^՛CqÆbWS?v,C"oBuk\*G/PaT_,%AtIthNXx{bz> UOgdXH}𺓖CZYƒ,,+WÉjt:y4N(Q'ڳh Յ _π|#S_bOe /؁*2Z7%hډƥIS.VXszw=ѽ+uehv0W6+,z:3*|U&',Z=+tKbZ151@1@Jxv?F kU$jci~~ڛnJ??j2Z7zbZX_ē,鹙Sm79±=$'TxZB ~#ɠ ASb CQXۀ7m'Onyu+־ {{4-+m,cZ۩D<{j7;̚gGGǬQ(27;?<. VnNK/[FX\O!V}gKgQ~zbW}4T4w|WD ƆIqXn T7"cp4ϊb Qn?%#ÝTW7kzIoE}hȹ265vϲini_W̻"ă-gq쟪(pQϝXx9  y_LsgM4_○Ϟ;DcN<sO^~Tp_=21IZZ(/l!\_x_S?<]DQz:ivvzS>W=|(>t.[+߯=sL;YPg [DB'$a"psxC9Q<@?ub e Bݛ¯c#y:y*CNLD[kkt b¸5xyGD =_3U|HпĢkyᥴ0X|HȡiH>, ,.vsM($PX95ΗB6&0 ٚ"F(2/|v"Օ(z&R1}=%s-yL |c]/!X #V;,Ц jY#^Mcc#?Xg&d* ֯&SQ,bߞ4巇ϕ,~#)绖->{,T=H '- P|\ywk 1zU4Lf"loY~]cmOǒg07{?%,~&3:S\PqGZ+L}<37OUǿUM;[~uyN ?6X,<(?W0G L$:X4ْ@OP|jn#q_RІ©4س 7X'o8ce}ݬp>҉0m,7:1wiR\Y](O4"r$_gU>JF}>ĺAf8T|uȡڡAtJóW;?,|.|EN;"0,[ú_ (Hs+NJ|{azS~T:\o3y[:a_4_()[4c ݪ/x)N_, Xv=SճϽ^=q:^̽`W;i~R5'%F)|z Qfwhuݿ! 3HeWяp~Nwuʌ/B_DZc@7/&z`=ϳ[1ʥ:kA9꘧WX_L}{%+~ͳQ|j~y'͜<[3kBI/Vگvz빙yUnsu5._P?3 ӷߙp^ l,-/CXB@{Fidt;s/}MgaeOKG(RT(PBB >//|6[j]#L-]ҞD$=t4icW$%eNy:F`E/:7sMVXO&?UKl)tn 7|\jq+2uYVҿLV_] 9Ì FuZ C6[~h4fdEԬ@]'"J rTx` ϤO~:BpߍcRn x45m<;^;u ,O=hòtl"7pu)k$PsxTv/|sa?1"@ Љh,w8P1D5Cu)@RBVXUrf" ʈt+_yM>^x#>,H=|YAi{'o9gWr֙n }iz'vu@[;L "t1aq#{"9,J=;ĭ[˜lV<K/ގ?de45}!qXn`)vEX|tQY*wQE$߶D12e몌U +qE-iKO^ɜؽkq[L۰z,\IV?}zOwJ=Dw>,0u0OCяpﺽ4=ff,Ckvgqf'" "/| 2i;Xr#uW1+EZ=k_Xlcx&`"cRQ.Eg,PQ^ᢙ#87 _ϝ@1VXms#ZV 4<ZxʇL2`(至~ qf̠ |y&䔤:ppo=}eВ`s#oO Z^PK/Pc, @P+1@|cZ>bKzM\Dn`hEZ,eca9ucXg^xz+1S-17 OKgG1M3,>O=)ut-_}#ZXzC8 ~_ˬ7P4@~tU@|5lje7Ekr5 BZv>M,s_ADTPH;a|yfn(Hct)(׸«fm '8<'B!J=Ǥ_ 1`0\8F 0K~<xYA ڵ}qgN~~ A_(ܮُf9W/pDl~n^vg _h-,3u%P`R>M6D⒍y:ffȄHJE.&msm< MPk6Gg%,4ʳ:tk5p1}U_LR4\. |˝GZ>ϡšC@+{ؙTx8ȫ _ byPN7(e頋C%zFSC-oG3R ]":d.=~<4Wn1=Te݁.݄ԹآQm$& %#4/kkzVl1OW 7|zmF* 'q;vNa|(B41e)?|uAxny~ ,bbof" YըJaؘ ,-+|zee%jeu-\4_5 1|P,^ A[`ZRkG҂i]Ztϕ^"Gg娶a6z{hz=\Dy.rQO ƀ1B=f z= Q_A' Q1:_ EG9+!Җi9 JFyER|Л X4˭aIy@Dy2GAN<SCd'm*KO=?QxJk9pkAUh( vP3N4sO4^xL@9-o7=@7*c}X471 -*PK\q>eW[nOzsP˯a)cz I9D: c(Q?hpQ=@5͇Gi/*db0ix ѿ^|d~aqؗɀe쨃Ϸ &>i&CB 4n*i/0Sud2Çv"7vvyZd{%-cJigTNwXg-(VX.YYȄ=a<./i텋e0 <ͥcw rD>蚍\X׋xe4-/eA D](AL'i8;"zU jJc<jY2zFz-?,sO߉nvJ6ooj2F5s՚o㒱Mys@/{cG1^˯9;!8G"*& g_1WG̨ @:t~)#=Ҳ.Ay D,K5Fm Dm1` ~Fb2 d% MP|YSBʩBP205=@E %fY:|{c`6o(iT}v:K1k@1`ix%U^)wi*ވ= ~#RpK{x >S*]r_I>z`q!"ѤhF!@u ޵|^㺉^o{%*Ahh+Ԗ*9ÞP,}?JZw֖d~g }D4/俛Ngh^庳}h=wV=ױ7T`ғACC=]x g(H= ,A# 7| r;c^6p+\"%OE/囟- #4lPw1=͈!h>[0;KljYl#s]3Y1>Q8wogr\bc==iX3-mc`SYSk,= V晳3b@oygهj₈>K$l?IA/TF\E6kFQԏ#y.%*Pp(V; W2:2]==IAoo %ăR-~uumiaị+W"/u\B8w1,~uqƣhiݎSrW,_OV~DSỵHD@xoDN:K<+8GTr0V^GeΈ+7e$Dx9 bʑ:u]LAu{WrO"4\'˺|@9p<1P3}1`02G<_uO_ axv*Y!lxN^P&zY}#镗_RUAPҿ>я0 WQЁps~|{;ۍ9X/~gCrTTT]s,ncM>l71^L<'OJ3՞{?GPidb#66P6Y61#i T%7Voxc~^AFjiePg><ޢSWCS}jdp R`: >6xg_KUG8̞06~57^?x_MkUf ^tfzo%7<^C%(k542 .?C#I"lv4uHHCуnc; 0oד hCC|> ^mەO; ٸB Yv5`I7@sy4t{'_H~>-Qnު~{ t;n~oԏ|+[I#'f-c3 thg כ!tX0`>@_~cept8Mt3G-}G <0QV_UZtp(tH[i. W\{3uaB YM Pv$֕CC <]8&G]g:016B='r=h11K/|( Wo )9ؑ75_$>|H`i0GBpXzcwjfZ? ׌!|uXH=s{Qg_L};,cm1|셗8u8c{ 3,O^6L|9cW<dc.)3)'M@uۿ*o^x&@ᩴo|2V2uAc·'bw+u-t|Rmgu?)%^Ut6F-4>{Bz깗iA߳w>|d?/}K݇},=+Xt۱#1:J0'[4U 7 }M1;-1烰 wM՜&cz"A,K0'V(Xc_;uCWh\yӾR\ljג,46>̋y7p563.^~}ONMAΩT?_tpn0;QSOIi=nei`\^1]ěJo:z: ; =w+73CL/TSţJ ␦l%Ә4(8lxpHژ聹vHkiU<5zQᦸ/>W tyէ^H?}<{19 a㾜ve=X8(qaNr`a.į励ޗK?๶o߭_:o }_ tB$?iyO*|=fw֒=nw@ J A@{^O'˔n[~$]5{+|v{@}oq)igï SߨODQtSj,)A0")ўi#ݹJg>ـi/1v:b8}5o45<"ާz"^0`D}eI$NqctD\l^M7>?q~aַaCݏ [%㉠Q~'poyf' b$ΖV-y|5};*gOM|wyڄ/ _~P LO }k>4ZJEn @59 {f  n8XlV":]  Eiii3>zGL}+6fEXy- w=ƥf"T@K}_`{{=v7);{ODf:e[W 6a$cEx,v jvR aj(i%ghraZ|Y1FáS \AMl'8\OI<{~9af8^@ƪCD5IN#PG14~3VCgU:r9/t+4QX,>7c!:|vœSS/4P=(Eo=`<`C`Z\jXL+:r*7 mx_ ^΢ F`x9f1L4p( u~l[->ibMܧ#`M(-5]NыZߟ7,o?[js-^.HU4ީ8EXxoKO8L_c=i ZP-ps~Iw-~S9y\d)C< ԏb 1%$-EDy- ^z_s~S@9_'>ng|rJ}-v2 rӢ2 % Wh4;FbV`㟯id4%E@' Tokyo[gn.7V,D]` QxX^,j@ a/@d)NzXNVlK;x`/rߔ j9VPc]3 #f16䀷haHkYѽ*cyGtZX~& =6[|rPQLXlߺ#;+ŇD2ry[1hCxY0{eX)@Dcws?4Vw-^.X8]+kc|?gucVѽ%B|^C\z \mȞ6׳^X0f'( eeqזuS/8ʯx;}jGǡ}(谔5`Å ya 7 G" (5]HTN-on?2/g^ͽ\/*^Rrsn,ic-JэMc_[Y)<P͟?K[5  e5Y~rks]!7_Yo>gf^Xl WGLco\ߜ`%GWF3m륗^OnCWa⸱+Zn I݀ߜ|(2=~yuo n ^WMx'XvFwnD<*7`WCvCy2Uo(dP]e; xlW)w ΓٮR|Cv Gruchacz, RobertHeinatz, Thomas"Jedynak, Radoslawz,Jegorovas, AleksandrasDJelen, Igor Karalkin, Maksim&Karanda, Konstantin~Kolev, AtanasLapicki, Raul&Lapienis, Donatas P&Manaenkov, Vladimir$Managadze, NikolozManakov, Ilya&Paschall, William M,Pascual Arevalo, Ruben.Pascual Paredes, Javier> Pashikian, Arman Pasko, AlexanderPasman, Michael *Passerotti, PierluigiPolgar, Judit$Polugaevsky, Lev A*Poluljahov, AleksandrRosito, JorgeRoskar, Robert Rosmuller, Anton"Saverymuttu, Seth9Savic, Marijana Tetenkina, IrinaTeterev, VitalyaTeufel, JuergenThal, Olaf&Van Houtte, ThierryVan Hul, Chrisg$Van Kemenade, Rudy/Wen YangWenaas, Eric?Wendel, StefanZude, ErikZudov, OlegyZueger, BeatAZwaig, Arne$Zwanzger, Johannese"Zygouris, HristosZyla, JanuszZysk, Robert chessx-1.0.0/data/themes/outline/berlin.png000644 001750 001750 00000142456 10633464147 021473 0ustar00niklasniklas000000 000000 PNG  IHDR4RsBIT|d pHYs66BtEXtSoftwarewww.inkscape.org< IDATxwxǿN H z/A!NBA"*"("?ME:"Ҕt =HIHLfٝٚ&'ٙ;ιs4$b \]` UPQQQQQQQQQQ"+┸B7TTTTTTFU0TTzwBEWzo+$ 8.Y{CEEEEE 9Q`9F~G_{c{#?SQwp]TTTTREE@ %}p1(s,Q40\'SZEE}iRQ ӑd "~_&.ȷڕ }D%ȑ#AAU2:%_ qu#`< C`It (sRQ/L**:3No>@/y@P.SJѣGC,zoe?~'N? Fsf&˗qIJCP>.#kBE%***2СTPg90OILLDXX;&z ț4$\xǏ*cD GŨQЬY3FhР|||РA :7on!mS* UPQP&* d4V.#G *ڵC*UdѶm[.PHC8u233_Aҩ7> !!!5kOEjj*N< k׮x,# ixtTT`tl@P^ĕ r\t6mBttA%#,,L:=PFCq(^8J*v-_[ЬY3|0+V^z8yxoRS'DU0TT._'%%C?CXE2\oׯʔ)cPHHH@۶m/C+TF8wAllx^&;w^z8tř\zM4rfTQqbTCEEdɤ$o^dD@w@P HLL% dž =f!1}oh(#Q"yE|`Сx,еkW 4@"EdRSS1p@CXRQӨ YQ u}@A",,LQ æM).mLx ڴi#U20vMPq ѣGq`Yh V¶mtN,XSNE||<.\7bժU믿Z KֹҥK2eTR* y$-[F&`?)a>IChH.ȑ#,\⸶iӆϟ?)n߾*U('NHu>Pz9@;vmJ8 ꩊmW|uÃ.\)YBk]]]υ+$]b7QW0TTZW28  a+-4Vcǎ\hݺ56o //ӻY8uxCsoq)Jjҕ*@]+ x1c ((d&>>>;wα \RX@mWEiʆ@Y6,B`Zv*<"xV3ZNy0tf͚(X ={#22!!!;¥ڱ*@4m**-[Ė-[P@3-Zڵk:Ѻukٳf2GX} [-xc\~+WcjR@!kܹs|u ˗ǭ[$N^Jn, .f/ͻ8JAx {0@;q aOJh%-3pعs'ڵk#G{ڵk? 8 ̒+X]Zb oVT.jժ)"ŊCҥe  APzhqA*J4`FW0aUC` VJUGgF``EUVMG8}4HBшe-NeU lIA98tTFF^xmIKKS>Ǣffffڤ/^@fffNU;Q@WF!`("E]D%BgϞyh۶-6l؀tT5/@wY)Q9I8#G.XÆY6N:Ih)ZtWE@U.lI]\FC@pK';)Q:¾9z1 }bŊgVjUO>իWee:J@X =ÇRր0_JP?bHr֬YfԚ0JUBM$..N,cFVH222&իWeuN_L}LFRR[liTC6dv,$InذAqCBB\ǎؓUFi',#H233>>>:c]|yZJeW%=q߿)SSN,Svخ];N4wޥ$8A;.*8$o޼iX QN JSH>qqq\t)wnГ1$?p׹}ܲe ө-oQ$SGƔ>Ht0\_䳝yUnfr;E2$'N8P;?NyQ|Hv#^h$WWW7n4$;lKu)H5\~=K(a]hѢ_)!d_'h]QǐvW0~&`$Uɤ0$Ŏ5kLFc+$Ν;Gٲew 0' Ij}LS2F)sb'hs^~N!h2[<{g;gI[8A5iCR.'ԩS s)RDMJdK' U k$Swݻ3!A)ɪN.I^vS6s y@ MOONJ+PV- ǎIM}6>3/_ݺuΝ;S@˹žrQ?0a6f˜1ct6QQQNZљ؊:=` aɓ9^ ޒ/١LQ(qcpN8g̘yfQ f8*رczj3X~={=c!^Q^EϞؖ-[T^H}QlYe,^| #PԪeK={puiT̢2LMM?3fD޵ҥK^zW5k-ԩSxb,Z|322i&lڴ !!!={6ׯ!x&[`"VU\A@ &P~qo₯,aÆi&٧*Y+C!{ hW^œ'O &:~8 NAbh+`lKy ""BHcΝ5kF!zR$** 3gΔ_rNd… ⫨8%U{ł zpssÕ+WCZ ;wuBk;-Đ-RիW9/;mAiTdd2<==mAiMѳgOuTKb]vuֵhٲH"ԩMH&N nݺ۷Yek40ݓf¾\Gm^7H'LSѣGcǎI0+k}]W[IxJc,) !.o KKKË/j YP1F]FbU+wadQU!xvt9s0j(0zFewz8qݺu6Ӡ6lؠwfq`(9wO-"ƲPBVCCC-) JW|d!]n$Irڴiݻo_Q- 4ib8r䈘|waAٳgYL{QةV0>C6j烿A FG}$m۶.\]ץKi'h%O`+ BwgϞ8tbbFN:aر j gϞٳ'Ν;1c`8pu?@'' ;35.P0LKKí[p ܼy7n@LL =zD$&&"!!O<_hѢoҥѬY3TPA$~ꆺZe㯿¶m0sLѮn4tW! >}dǏ *Jd~sY\Fh.PRc梮`lر]vEJJbΝ;c(ZhV<:wp̝;}]9s&߿ŋJ+sNPA<5k`˖-ҙ!z´iPbE1rHO3pu\~ .FAݺuѳgO"3)KAXXvdyzw-Zɓ'p€F6hKl@S7o.\WaUW)嬿phI-[իWqI-,xajdy.NǣSNcJ isqT1` IC wwwV 5j(ivmp߾t{ؿ);z̬ /LIIaV URvZuɦrQU;аaC&$$(:z Aa^7$fڬY3w}WZ )FS (zKKKI2iHڵktqq1خ JԆc7r0s/dRF FDDpѢE\omU^iiix"׭[#F0  IDATi޼9ܹ#UH[:3Y׮]cDDmŅ={s<ɆN^ !UCU0LYRp7x%ٳիz1'aäQ w֭3kd؀*S7jL@&7n,&MHrq?^:S?)Dl7eaAIAWԩSASRr¤bfZfEwk<2TQJ08ǏrFbŊ8q"Ϟ=K[,{yh4F=VZzҸeFϏ[l^/sF_cig]p}v7Fî]N 'hQǐ*&E1b Wdd$M ^tɤHL8ݻw7xJ#DǏ%RYFG58d[v]ɦrQR]IEҗͩtJe-I2dPۜ)SgwҎ;b k֬.] <<M4,MZZ:۷cƍ:`˖-hѢv @N&lf9i61|CuC"$;ԩS9+y}ܟ??~ܻwbj/\(O^߱cǚҥ4t8XΝ;^z@`˳7"\f?O,X k-˔)#K!g~ՌvH $.es[nJx!VWEѣرCVA  ˧o߾v3g(xI&Rt)$GKwCw*Tʕ+-^AKOOO?h;SfMil 9Z$*8T ?NYÇ_I d\vl%e +B*U*\'yS K-!dx}֩SGloNLLTX\Qǐ$B$Nػw j/HMMU'J֣Ҕ#VV%3lo$Ef=IEbx)+s$ q)$yԘbV9fͱS֭[Ų,`F)O6J"?=DLdlY_[K5tV^2_sœ{ァҥK!mAXb ve6lݺUqvAx{g}tuu9s1 dddpذarFwi[w9**8T % /bl۶`0i4|t <:~פ$o+7HHyJ͛7Ϡ~[x$HFǏ1'cHb85lݺZpa9rD|9jz"-W.Hrԩ^h f۹sN=-=X^!!!ծ];[nD+3I^~]'O*poȐ!$m;W<`I4o%6 ,ɯE`-n(+ uN/7{lם8qBm/] U&z<䄬#kɅ{fB; 3>6n0 H֭[>|XY%>vFL ؾ;*4M%$*:~ X#Fڰl2vINNf6m *&׺1\LqF5~x_:~lA!"7RJ{J9Nh^"x.dx ϐѣGKԏ`|$׬Y#['>Jի'M fI޽{נBhxU+[bb,*1k$g$Χ~*a7$)իۥn(vu3f̐]WD9Rq K1c—Z ŃYܦM&֭[g޽{I5jHka..pNj?#;[e/he , 8qbaÆa…pqq1d헖! (*c9ZϟNzyyheCe%&&",, y=w}'K(Gb9YpW^96mŋ⡆Na Fp<{L1WȐ!+h"i?PM~=}?^j' W@ K)٘@VPJ|.\~4p=u`ڵ4hH$ = 1@11c줷7Lb-1Kߏ ݻ׬ɴiPzuYf2;H#NhyS(UZlskcV.]$;Qf5d Q0*!+bl>!}HbĈ6mb±cb޼yh49Y\!ƍ⿅s2{43¦MĨ:<}ZoԨQ5k,]Wd)10  q4h狇 >5zA7f/*1-[DժU$&&b"m75~ "x+)Χ̙3G1 "/X`C͛7$~TaB0 @T|۷U{E0oߎg1JS֡$&&&ʎ7k̦u. edw<… ŏǞz4| 777o>G+-+89Ψ`( @+VLD:9 (̙3G1᧟~*G+hذ:L! 0QPQ^zSqm)ϟ?ᅬnݺɓ'AN_@ؤDPZ5w}`̙tp0*l  o~L@DNN+ gѿsQFDTY\61 VW0|}}Qd,H @y)ѷo_,YD1_~?%ȑ#Fhhn]֜7VP"'딃w˔(MW;#`dYܮ`:I wIIIرbp2FcĈ~˨!Ctke| 'yWE^)SFvP^ãG7oތ>̬HƅZtU(%MکXۡMJIP:kp3tJ%U#ʕ+';&'[LϱgS0TQparw>2lX4kL%֭C^rgV0 dt%KDttWcNVE{333ѻwoܺu aR+VTC@Hx:{tk!;%/0]EH$""_YSv.][o%oa %-{XNM8wNn?^pa[yN+J ƩSd+EJ!!!"Mr^"u PV0$qzr g8-zgc'J.E*UrD8:Cs[n^Sxyyaƍ:*6پR2dLGpssÚ5kpќLjG{xACi{/zi+Jc“f͚%T#ۘnݺӧfU$/mJ FpppxV┙cr=ŭ͛7clRQysU@Yv,6LR? _pb훭_RE{gA_HJJBk <[hh4oool۶-C;.%߬b8 0DN<]ajM׋/?ȞwA\\?~˗SNNg⭷޲E( @RiO > wl |ԩ:u"J+z;. kˀZ3hkH?x೗ il/5E.eۣD' Pܾ}[;v@Vr~g&/0lZe!k.L)FxM cϟd6Jy/_[n"za/Y^͔oNgAIٳgqY\~]vu͉ez63{s75!3p@ɹsŋ9RիWW,YRdI իWe?̓ C 8dm֭[+IbVfZCJJ ̙]:qbT*R2pPn]~4EJ*ƃ+Y򫤔8pk*Vmۚ[IQ2gcdy^N:kp=%Y 1hWlT\H xݻUN{O>Dv<""BZvq# Hyg>; 3JѣGq}Tʙe?vhekhr@#==K,A˖--Ԑ{Z}|||ЧO"2[=u"> 4Ȭ-U05k3g(ΠHWmGQ0jժ/yLȋ+j >\v2!!;vq mK{̛7OvK.Rev)8QY>E܄իW"0 IDATY$޼y3ԩ}*Gx]d8Q`A٪VffbEƍAޜq#Y/0DFFwfgj(S6X`˲{ڵ~ -Xc޽(QJƍYatTnBXQ`A @^(m~:ڵkwڴ *WX1̘1Cx/6-8p&à2e8,l-W02224yIH0t")) :tm^={]*˒r-bgV0> 7lؐqv233zjqs %qƲ*@p_G6+CKfի ZբrهS\9E{%}k̘1t钢ZJR 3+eۤ4i+=_!`6 Sɻ_z!:::ۅbȐ!2dׯzz!3)5U[G#ORZCAW/^@׮]~zvahmڴ7o;v?Ir'Ih׮Ν;57l2\"ŕ(78뾲Zih4owߙ4:tː\ZjR0Uٳgc̘1ǎSL'YI:AɰVcۣ!TYFAѺukǪߦL\AAAXpbQj@9 $EK[m27sMYƌ# Y[HqOI,Z+VXݟOf֗ 0 @vŅ;v찺+"k[pp4II:0&Ŋ֩SG֖~f}y)K,)럂 255UL6OCE2$G-kSRRtڼfzxx(~ 0))E1 (_}lbֳo8Ço޼yC swwgrrKwrdddpf]]H"${KoV|yΝ;˗ kJJ 'zFK/D jqx$$w)233Ӧ0it|J:}R(}||XR%e˖|WXtiwwuI&ۤ8$̙#(v^}U6JOߖ2]l؍7Xre_dݼy /+ ĘiMqyϐ 6Xc<۷U8qBWJ(KD777Yz" + ƌ3LC-Zpt5- c )A+Wik׎ݓKAYgP[10aܻwO(/a,AŊq!{GS*ŰaPzu,_hcF^zŋXd?~ nӦ:RSs 98wKa',ĉ] ?.JYa@dWgȎ_~;v1K<*I]66mj4-Kðĸ[JPPY777Y>uA%`1Dc/@- Q\:}XbWYɓ}v*UJz8AĜq%Eխy4\˼yd}ӻ1KaO&?s6ho?޽eKIϟ?gbW^V+ԩS[sV޽{&y7deתUKM̘'AZ28|h1f(燭"ɅRIٳg;w.lPjժqڴiJ$[8AY$@L%owtÇ$q!$د_l} CBB~.I@S}_~+UijgϚOg ?VRG7n,kO:esny{Ot ?vZRRjۮ]ٳYdI+zS#G*?gΜlM,X,oooJ9̘1&(y)Ŝ$ٿY}oߞp k3pBܹ#kKեIro)@r)4qĉ zI1c6v",g8Y;I9rD3f\GW_}Uz%?`H1wAֻ$ߧ-"f3C+...4(<83 :~͕ $yu5@0OJJ]:);v0=X~,tY"#ʗ.]Z6c[~H]ϕU?}Zodd$׮]k4M\\b~15ܘE-G-W#AO?ճ %n4k"Ø b;}Rp:a%1)WtˆN4s5ki&.\_|^zAf9o~d['G d\l7mļB۶meZd_Gt8[(|9HJڵ<ܧ˂}uf{ixs3Xq%Az?zy'OL2m{AAǏ9{)k_NLOzzyi}KS$L8Q־Gf;ߴ4i6oެxܼySL97I˲J۪ϟ|!ݳgg&Let#GR;;CK.U\hHʗ/Ϸ~˖-7,㄄nݺFbݺubVEO?$dRgO3ıwP.]$;ۣxKy饗k.O֭[P׀?A,5kW^u:B $$$0~xmڴ~rNv/ (ȑ#yWK 7f۶m:tCRpa+M׮]ټy3ǎcǎiCFСC:7>2 fWڠ;w.7(gN:FW Q&:p}zɔl^sr~.\_Bع[ p ʊyKMT4Mٳixxxz}qÊ'Oru'xB%X/bݻwy뭷Bgر6?sxpǙ:ىtbjEjXd w6Pb:uYn]!f͢cǎܹs̺Q̙3V(P@-y#`0|,i8-Ey]KEg<;$ vfvz{n)RjUz)*Vhn7tcvo;-l)Rĸ ʔ)C^vΟ?+Yz5|  V>K.ѤI֯_o%J0c ?NnݜdztЁÇgQhQlذf͚q%J̓Mjx <˗[s1ڷoODDŊ+6_;oj\u h"IHHɓԫW +q-G0[0h\JTb.'۠].Jpp0)|ccciԨSԩlw}Qx  J]wgc`*^zL2%CѧO.\hLa ,XPolfR `ll,;wV˗FCʥ dٲe|'V>'OslڴB%31(+j`ȑ#p=c4-P -fv[Vw޶}}}iԨ{ݻf`x{{;5ˋݻ;m[ƦvR_¼ئ0Iؽ{ռ/]???fϞ/ӧOgȑ6W.ʗ/vlrCRIII*0@ٲeYd ͛7w9e4jԈ={H A>}Xt)Y@Nd " FsB&LRbšhOBEE8 [ÝTnVO}}} _woooŋӠARGŋ)^8h@0o~Zn͢E(U*:'nݚЭ[7~~|M}u7Z\)Z zNJ W/@TP@ P:)RPXO?| KsOדqf;a=*((___h"G+W5khu4h111-IJJbi7fu{^ s]Mo>+; f͚\m\-[-[,9uTvH ͥ60j\|{Rc7hIiCLRDAG$ ֭[(X/Rk@ˠߩAnTr R_,9n6${7onsY'ۮ@BB߿lUlb+!!17h,4jԈ;v5{l5jÇ[Gk gŊFWk3 (+b?`p77)Yd"bQf~ʘ(DD6l`U/BEhhFGG?Ge> 'NYES/_:LTn)kV "`qlED$ID~#b\T&'裏Z]ǫV׸مDٳ(6[%+Tb5Ww*Ϲ."عsjժ6s}}}e_ZڣGJ;wҭ'[l1e󯏬H]I&Ylܸ.l߾]{رÞ%b0JZ-jV䏥K2vXM6.]8SB#')*8p͛7[=r$z2~z<4]+F.](^"j,$wfJ:8y׮]?~O{ƌ朚E._D`~L:Uի7G*[tM^O`Vܶmi ҿR\9ٿ*?l_z(Ϲ-+Cy7#BN,-~Osi߾xzzf)/8նmۤ[n6}u)Sر(i/{vSDn,^|˖-+v#3iѢ/ ݻw3ۅqqbYֹu|lM--. ޽{ƍm='"߉Hsd}- IDATdVoI}.'**JIzR9$)Z>'"-wFRND""pL}2qDٶmܻw/';w1cHݺu-[ >\mۖ㕹ˎ;dəs&~783ɤdܸdϻ< 40O8GfyoG}m۶%ҥKTP<\b@' "•+W8M|2IIIjժY- >:@r$6oLXX+V 66s$=<}[nw5rGn$t111 6a@^^=y)VŊ# [nqdr W^sbŊ1b*Tĉ9}t^r??RJѱcGʕ+G…  KL0S:C-Ӱm~˗j{flVts]~pR\111DDDeLB1o?/70g.]7W\PBCC/GhѢa/>|ȪU cݺuX\x?ӲeK @^˜V vtϖ-[>}:wǾ̚5 x 6mDHH׳~z^xCPP+Vty*HunbjdHMbb"tHƷ%J0j( _~,Zst5;r߿?s-[L2(e& K.ؾw^73qŵk2u;wrI-=7$-khݽ{7[la֭ٳӽ76 bT73g2yL[@vʀhӦU]vk׮_̛7p?D۷}v7nLZ8q!!!iի;v,SOS\ڵ>}YxoŊX%KRn]rʙ3g2:$7R`Aڶm֭[ :ҥKo2d ,b}W^,Ys1/_>6m˗9wS6`e6Ob+m}֭@Y~H) բx (o$)U}eԩSlur駟rJظqndgԨQ.0i/_>&LO?/8JM6iӆI&_%mܸ7ndmoooZhs=GΝRJ[nt֍7n?rJ6l@LL=???ڴilTѕ?NGԺ:?Za-%KhѢ9sS d:h`&MrNŊ VZ) ] *dGsf`ѣ8q"GNɟ??=zGDFFҸqc"##Ʃ*T]f9fE}/M6q9 <3g[Zj|ᇹƸp&o˗[nHP(@`d e`(+$͘1Gf*KF!""AQLBCCپ}a,[:PjUƏ2G)C) E fī*C,fͲy9h >cX|95k'`ܽ{lr-.\ޣRJt9K "k O}=S1 g?H6@Hm+g"K.lڴ)S(P^xm Nz5O&MKtt4 .YHbb"VrV\zjp'50V^U&OdѢEfuƺq\n4=+WdʕNSH4oޜPwN…V'M6iӦNsȑ8qpϟϕ+N)f+8l4[ BwpP(.h#C>L] BP8 e`( BP( BP( mQBP( BP( BP(vC BP( n(CP( BP e`( BP( BP( Ba7P( BP(20 BP( PBP( BP( BP(vC B>f+P( EnA F3l%.G0 5Ykc B(C |xehf\%-(## 2WBp]PhQFxAyb" Pc: B(CݣzPFF^q4H|| HY* M@xwO?sܹxzzFF9j*L@BBޠx# Ph6H^>G;{ORRo%S4UAc+W:iP(.ZP(4֭[O<@_QO)ݝЌb ٓ+VX4|̙gI4#IJSzjX"hnRGTLt<@ <D7hqiPP(4֭k֬E] 2pW Ջ~!̓ϟF# p9*L Hg߾}ݻW70ߘ™ d?-n+OߝB(B 11{3ϰsN}_(0yqGEqQ}XtAxxxXm7o PFF `$%% h7 Z-j*ƎK(^8e˖ߟ&M0|pù>h#@NA0 QDȏ""aaa%*THo. $g\IHH={w]eɒ%2{lyL~$11Q>:.p~J+7ED>8]@?%">ׯ_gyw@jQ8p@ DHm8'%J&jCаt}yvءo,HxEZDDˢEbt֍\ɘ;w.W2JYڮSP8K^{.N+7)-͛7cf͚L?I&L6MT-ΫtU(\e`(i }v}Sw`1ZoE_~,\ ݸѣG9s62 w!Xe_s?Ӿ}{^>|ȿ/o*fkP!P(4ҍ>;v4]S؍h7 eVyyy1w\zi/##_VFpMΝ;q޽Q7D #HFEXX1uG`P5T(rP(42tyad<,|.@/zM #ӻw4JWF)W/R.v})܃QX :;wCrMۨd!<20 LTR۶m7= w^SFLRR `޼yVyzzK/a JQ+0/q60~w>|TnRA ZY-ZĪUkxUV F F(бcGp^QMJJ_fܹVyzzwѯ_L7f42J8Ȱ/%p|G`m`qa3+9 XǧOn׆,X}ڸB႘ s+9Ģ/>nQh.pAm+gA72~gڴi50h[|Bse)*xf߾}4jo`xm{u$%%/}A:t܏=bMU0)?q,}Lw`,}>v 1CrHĺFFR`Aٲe .p^y]Hȕ+WF6O"""RcܹSl/J||~" ;G"}t90`> "@=Hx9qD~2+'N]|LEd$"E$2IYADFHi.R*J5We4ó>˦Ma3TC"eʔa֭TV{®]2/O?ͽ{,\ooo[@;@6AahGv/  LXJRjb^?)@'2&v-L_Z,lL:54mV;ޠWes̡TRVwȑ#i׮]RH^4׊2j8&&z-[2dv튏@uflٲ[nu֜={6Aw%$$ӤI ʸp Xgco򣹴t8q4У "8> l7!(M`Ppm<9~8UTdɒ}{XgTիٳ')Rf/~eh7Ҏ"@L&66}qqN8'rwcvA%0`jժFﻙ˗g֭jՊϧ8Ν;tЁ7l!e\-ZmZI;QK1ʹ $8@˖-q~oVSa_JU̷%j"Z<% !*c,+]gϞW_e֭7ԫWٳgs @[poLͺ "2uT5vA 1""ϟ>m""k׮[ .P19"2ED/?SfΜ);v 8Vi߾F_|s"xX%O r6. @ݛzT̅өkO$ Hs:\sUDޝCDߒLLL˗ ˖-<o\`,/YHRRL>] *ywyG/DiPq g8E(t`RD͛GTW"eWD 6ХK*W|˗UP82}QR%nJŊnoߦ}oʅK hOI0ӧ}vV7J8'#HOXu#)P=tI2?uYЭ[7^u߿7'$$GѲeKv'=r)E$K_=rTT ;[z@ B`H[ !ŗ/_"Ehνd׮]G6 "otդI̅ LU,#"""hܸ1}ҥKg@[4_ ]?H臖Y … [l\˗O_G>0vYj cqEڷoSLѷ@W{KɌV0Rc|h)_oPE/K6QFxDBCCqUwSHً_~ZjoLpm۶%_|V3뇧+h7`GBCCv5D|rz-yWXLI IDATB{򡰍Z,ac.\@tt4w޽{ܻwSNek)B@@EI!h7MЮۇ/h~\>͛7s!ׯZ73 C2>>DDDd iU9u/^Zō&-\;rʔx@oaC7nG5sW"2DDN eʕ;H^I&RT)ϧtA&L C[ƉJa9/e>p˗@^z%x>k>dug59}xzz 6ms.2/yY_^J.Ͼ/cƌyE*Bm)b_w{@~G}Ϲ9:DbC,u#22=zӡ={РAfϞM.]~uccc`l޼h:weA iӦjՊ@`"| h4믿q/^̤I(Whu#~a IU;=/FPԩSIJҼx=J۶mA`ؓLHoߞÇʚ5k2}:'O!Z,Sv(V7׍.AW 7oȑ a?J>h7nC (QիWm68{,^^^*U{AѹsԱYQvp(yJ UۓTe<20bZ,ѫWk׮eƧ~k:X=gq ̙WA`!JUs6t,AIIIZS}vS)gΜ?hذ!{楗^}[ҥD1W_}Żヒ?h7齳Gje"]g&Zerf͚ELLLG ~4B]hSTu-I֭iݺu{Q@~SW&{EKnr͐ދ XwŋknqKIva1.V\I.]2e\| 0q9=z Sh+6a||<3f̠F<޸H Cߔ"Z٢.c ۷o3{le7, ǎ Hu__G\\yǎCDyMZ-h3.lg"+hYvlRNaW"YsB _OmqADym%EŒZDdҥ/_,իW%))IlfW}YՇឈ4uqt+ ?~\q裏)ċȋ.0& J*IBB~'cHDDDM6bm6-."1""}>Ν;? yRDVH&))I~wϥgϞR|yʹ˃$D1#G49KJJ3fHLGJz22.Z1늈L-se|!"rܹ4rѢE8ㆈȴiӲ4 $ﷳ{y}\R?$cZ1$v#FHٲe4d  ( ݺu˗2.HO.OkySq]+Ĭ/(Ö(#tc޼y啭1 QF>ٕ-[ݻwS&"5\`%"2W?+WHLsGK&ꉭl.0ghDGDdigPPqFe<~YWjβv4裏o;hNHh8>F"E$Tȭ[ߗJ*9󙪊zٳgSP9y*sVs[KD΋={.~'}nbD CĬ/(Ö(#Y|yr.HjCD6}+M41._2.0W9 Ojڵ6]`M2a\&ˍ)w3F~D'"""GNw\wءdmիgy>̙beڵK={翢WDHJڱϷȝ;w?"E83`2}Sȅ jċ2j*eOF駟h~R}9L20l20S,n2i)ʬ20DD{=;2tP,qʩ$oٲEo;Z{1q~ڶb\9sFʗ//޲b /pC,1fأzZJwl;wlԡWDD{J9>|RY""{׭[3vbMG;!"J)zȰa䯿2󧸧k%UfkN:wl01 "%H@8M[DiJuܘݻWM[GK&${}||dڵƹP""ܻwOS;=TD$111`K9uoYcƍ5ylE K|$H,aGD :wY$""rQ[~ACLL{6uOD7ans^ VZ%ŊB+Z95W;c0HLLd޼yL8?# 矼k?ѣG3d (,9,ǝ &Y6D2&+2eݪ8'NM63W_}Lّ=G\`޲"""7otz𦳥~\ KٳgB 9c G g%]K d]?Z5ʬ̜9So&*{hѢjرz9ODi3g DÜx|wz)eʪ\|YJFL;*THV^mTsh.fwL\\\5L%M48]` "fu|ADD)$$}駟LrvEӧOôSQ.3/Z:S>}H_ܼyS#[0ɢqHڵ;.0%oV80]D?l@ӦM3=%K4Ȩ8ݗ"{WNzNeD$.Nx%kTdd)RDJ(al3}ݛ! aQCGJe˖eE~HHLLo)Q^oXX20l20GD#֭[2(ri+b:J4hq3+ƅ.7o~2[ɓ'u4&V40mъ,X0K_}H˿\2G*Sz~TjL_J̶|7 /q+=I!}|ruNOd׮]F]YRG,Fܹ#-[t|T^]O| r1ɑe`e`+3_Ȯ,ƀ.0""w۴0.F;ϝ; ݻ.0%J@ʔ)ct,"Ylsȑ#G<>k6V~?}ŒT")(u4fo""K.Rb $7JrO? H+]~]j׮mg5#)[d^{t3"EȡCtEWDh+OG Dfd["󚞜k9B^|E/ ]}cvݢR˪U&W""?hzcFDDNJƁ7k,c~b:GDx֞wt%[U$JT{)k׮Q.;2eѬs%.aaaUի!7h{m;㸈… 2kVD1Y|Ice|zJ &MJkK,G5uv$ @$#^z%u͎|)DHa^ ">")wR֯Tl,YHtdHTTlO9x~,[.|/'H51jw^@c@H䶈ȀL7GJ*#CDk\@.0HS]mZ[hQYfqHDli" 6\xQo–eԨQv(YZJ,iiAIx`Zp JxM;iժr)St=#cx-tO.*ƀu.0VYHC~ٹslO;w~J:I""$Æ 3}AN8_gYȩx%LM3GȰqV.9.0Ē>HSaÆILLQm"R.U[EDs>^zE0Wܹs;dV,[GyN&M흶s13g8!= ;w/{層K>qDoQx?|3f}-.<'!!!fjkѢo<Yzp 0@ ,mu^L?3@[ňwTnۡf\z5V0VZgTpEGdXI#˰,Br $t|Rս{=i׮~-`r.?a@/q!Gvvuyyylܸ͊ҥKoJq%Kzyyy֜7p- ['N;o:V/_L޽oTk:M;;:}} EbKd޼yDEE(;xx6NKNa&0;:6M2e :u*履;w6w]8a{+Wt!Kq۷o'##jO\\9.*)nϿ0{J-.a (`an]H 0*38[}o`Ftt47oVk<\yWĪN7(Hٳ `ܹ 6ggg?:pbqlnL;V?{"eVFnsXfڵP85PIWfn8ktx\m ;YޫH ̽?55(`x҃S-w5k֤yk+>;{!'M:c޽_ީovXmٲÇ- ӄ]*x}???"eeeyUَ; @R\9s#22RiذPFm/L[9/M`y衇8pbI>v0|ۍ`@adggӧٽ{Ӆ^#Q`8Ff^Xٻw/ 0\ X; N3scϞ=.:G+V>|LsäR C8?T(vs0R`XBäo:tz#G(s a3@"=L ݺusI>;{)/Hjj*K,qܹkUzY\`45.8NiϷ jC~~~4h8nF27 99l4`X}ѭ[7N>Vo N:a)T.\ȤI\6󒘘%| IDATr*#رcpXSaVW͑WǞ={xJ^g39v`W#<< sb `se޽`T #gϞUT~`سJXb ݸqc"""8yj=\zw}ץ76l`Ŋ.bq*^tewRoJr tɺ8Qc`xR#(p.ڵv.ck~-=.h׮yM,/O\bmygyF k#&xUN- oKx6vV͝d`lk/8×C+ã@;ނߜ's̡sʄ̙3z|w9iiir,]xO~s;PCs;;"""߿j-G-hܸJ- zj~_[wag M%C&,[bE-[$رc4h{vNN]P4U(řPMDDb9PZ5[MR8+(y7,hcp5n;"J:y0@ѱcGߟ1c0yd@ F(N>DCvZo IHH;T"$88QFʕ+}? 9<5lْ'|]9=fUkY,#H.>=c3 LhԨ TຟH2eXYpeuvq0*MwF0;ƥK]oq0,ry9rӦMFw}n`3`̤`-r=Qzz-RsTj)%(XiNIa&7R;ށQxgoqFL 4qy!Lvq0A;or0^S7nw4h|G*111.`S<O<5R,w}9+} ,)UVlҥfsS}ѣGlompp09+o.Tխ[7oŁ"U]M?ruڀ:٠\e]`!77W{*(IHHDĿ N2VzSR^JoOZ}hLVV7Nsi_^~exN։H]m\2K'P^6K| )"?'=k,SԮ]kݺ,^qЌER79c,00Py;p98mmPe m@޽jkڴdffE/`#iРOb?^%b.m7s~XZlذA4i|csNhMMy,{GyۦOn~ ]VK,$SD&HDDDdժU-86 }zjׯOڵXj՜p8/IؔkF"n@|VZ4kuG=+[46uJ-oo :ÇZm3qD|I^ P #wG7n$@ ǏSX 0*n2@,1}|mRh ~1 //C14EZΝ;XF0e {QreE24ޣRJ rJ}`%P);;}Rի/^c<(GuT0 `۷όw: -0x:~[7U\0<^(}_w{Yjj=^KժUi۶jo_jՊO>gyFMq'N8zdOΎ;&ZF<,Xvڙa47ФI/_Npp0e`0D{U?P5|k׎ѣGۮLbgٳg{~*Yfb!VVOD\vMt颼}ռd~HDNZ>TODH  {<(ͭ/R!ҬY3neqqq٠clyꩧվ{nɑ &H@@Z``1BdK SN-юZli$'"O۠EG .HxxWi+W4_Dw}RTuՆlpv" mmPX28V2EdI<-j=+o8 ?O77~i۶rY``\|ٔ ܴ"rYD$//pݻ/$m6i޼2wrAk,:uq5h@6o\DKZZ<bQV{<^yziiFu-"2{lva6mp7+V&k`"RDr³/G}T*U$+VtY`=ڭZ"""dѲ~ ii,YvfVn]IHH61:ƦH`s)Z{Էo s.ȕ+WdڴiRn]%پ}{YnDzz=s\a+W^{Mo`t]22 ?OD٠ME䤈ȦM-ZȬi~T6 ?)2Tܹsp/f,ZHy{;w_~Yi~~ɔs1be:t f͒;Ddؠ~Kk+DD222_c=zٳg;O zE$EDc4IDDIpprV=zU ڋiSի%,,Pa-~[BBBB䥗^]vTKq\|YΝleĈrԩbL0+W\PBywI<ʯ7;Yxx\v,Uԏʆi>2TۨQ6p}ŪHapƍ%((Hy{QUD~/ %E8s̘1CڴiiOڵk &Y"XDёK1{WyRzu:uH1f h]"-0""wN:)?Ӗ/_nJb.‡ @yxgoKխo /%nNg  &&uֹu]DGG3fիg}{0hѳgOy^xs@/~`&P ??%K`o΅ uZlٲN:$S?/; :5ʗʕ+={48w+W&,,P #00IPvN8AJJ 'N(SNQR%BCC uҶm[4hPgƌ 8u/ H\LdffKT%f"x ڝV`ٳ{ו<4n<c@?p)HKK#33\]vR۰Qxs9<}sε&`T\3d+L>N 7n$55mS۷jժoF`d <9s]ox̙1@,0xKݻk׮ҽ{w7 S6g$0{%55?~)u#Ga֬Yн{wrn 2GҰaC=Ν;ؖ1c0e0zn -i//ܘ+*$$e˖K9rMVZ1qDlCCo=Tه2339z(III$%%>vYYYn19s&cǎ%;ۓ;<+Wh"-ZDdd$7n$2ҖؿiQQQ*uct]$!ȑ#9<Ǐ߿6 0 < <iӦ4mZd0ϝ\VurP̙3ߟz/Oɥ$&&2i$,YB^^>?Ǐ'&&F2aWlڴ6m0k,z)0zW?p`ċDC'p) D ر#111ٓn۶Slٲ[l߾{qѧO8v֭cݺuőcو6/_槟~R\zs=w籵 o/nܸO>Zk4GM %Wa, )[(2 #33{ӧsr"222xYp!#GGUX.FsM"G];]Jxf>+xyyyl޼͛73~x֭111у\6mY|9)))e]vѿ~_裏ҷo_zEjnK[ff&6l(t*n6Tعsgο`Qn`hTSZ?s?>gϾiȘF0VSʥKXnVo!==\߳vZ֮]Kfx饗2dWFX K"ÑsαtR.] @֭ٳ'=͚5q>}m۶|rΟ?m|g|gѵkWKtt4#88'%%C}v֯_ONNSy0=zQJ,N ѧ0n8.]G+#xOvB YYYLrr2۶mcÆ N]fĈtЁFp^.#<<+8vc޽ݻiӦrđ4mڔ&Mɓ' ̙3nY*ڵkY5k/JDDԭ[jժq1:DRR-9pK)z[FJJ c*>6Iu5fڴiL>^-y0||=ѣGY~j9EHOO'==pcMh竔X)cNĕ)w0NcZ4-TcIDATw˪;&%% ukV/:mLF|pHB鶲]T:|'h< 2h LƍU)d?meݺư7UVS4(5r_и( `ŊSJ !Cҥ[G-J@@{wޤ3oQ"оc| Xm` bbb… ,]yuVr5ed>5zCx\/ByӥK*UXp*VkJk11h / /@bb"g…*Ӽys2J+ (-^?ɻf͚\p]*BCCUKpAua.$,,L";,ܭɋH&XHa0 Tm޼9'Ofĉ)X:̙Zf<#4lP rʪ%8lիSvmZlOHHum~.N11S<?Q"V5~@U,ñj|*.5m~vj>R`j Z0Rd.y[+%839O0&l(s#lc?cdN!ZZFD^:-U @fFoy<9֬=0F=?^ZC=aLV)ʃ@j!M c<;h\E ]'WFh4F!"Fh4ihCh4F8 `h4Fh4 Fh4F4h4Fhv04Fh4Fh4Fqh4Fh4NC;Fh4ihCh4F8TX$GIENDB`chessx-1.0.0/data/images/flip-horizontal.png000644 001750 001750 00000004117 12171025447 021624 0ustar00niklasniklas000000 000000 PNG  IHDR>asBIT|d pHYsD$D$@gTtEXtSoftwarewww.inkscape.org<IDATxˏECbw6z(JbP㎗dAQ#b+5*K!QWj< cbÝ:}T[_B&Twnt: . RPIK S0 8"z _KDid@D`g|BDm(l:AD(c"ZCUW U$ŞLzo$kȍY1n_ERruk_EPdhuw8 t"@q ;lQ(.O!r.@D7ءxPTLXEPL"j;VOX8KݱٻygV1' G<ް;fd'j&zI 5# ;$Q H9EpP>RDY6@ 5&Б>RZ$@OHZe'dvc;sDY8tEhjʎDu`( $* $QV@|#%;IMJ)YIl (H)#hj͂Ӕk6f"h:͓E5,j6'Z[sD;GJt J)%b^ a#Ŵ$2/},R4bpB|XNYD&`Q(a4dsJ ^W,'$&%Ј՞c_c5 jD;5 Q;f= D'ه?[T0" $3Y"[ݹL >G4 QƔ$2"Z`O3z"˝srL2?I<Do|XNLܹ'%y [<3[?L$J]rR\3[>RKd !Ȥd]$J)I%Q,}$N"z9J)5N{M=$}$D):H)I$Q>kc(v4#%$9r(f)IH(JZHɁh(V`$ >\#%$$xGJI#UG]@(}#E]iw6'{Z2g$'ߢĨJI"0`j(PDDǻQ e$,;G2(H >QC#tHU .JhD!;#x-y6k\ D xA$p8asx>!$ O.wVT铂mEPW!J@D7_'8=hM@"}%QXS}$J ,xoG񶒨m+}lZB)=F$QPMZI6.aQh#wv*}#paIv$t'D+n}a/| Wv*}{vdJ;{7'>@H>fZI4gZysl%$*}1UcsI:vTSk0\ 3yiSU%J:DتJlzӫPOD { HDm_e118 0%v\#hL뒨,3@"bw+ד?,g^-.y؜X_ffH|467pB0ۦDpBb/vc;0O|Xgfym+ԓkfpDp(==LǑlf fv'|'lv̙chm]!lXY]\@  AboutDlg 0 0 517 810 About ChessX :/images/chessx.png:/images/chessx.png :/images/chessx.png false <b>ChessX</b><br> Free Chess Database -1 5 5 Version Copyright License QFrame::Panel QFrame::Sunken vvv QFrame::Panel QFrame::Sunken ccc QFrame::Box QFrame::Sunken GNU Public License 2 - GPLv2 Maintainer QFrame::Panel QFrame::Sunken Jens Nissen Further Maintainers QFrame::Panel QFrame::Sunken Michal Rudolf, Ejner Borgbjerg Testing QFrame::Panel QFrame::Sunken Bruno Rizzuti Coders QFrame::Panel QFrame::Sunken Jens Nissen Further Code QFrame::Panel QFrame::Sunken James Coons Marius Roets Sean Estabrooks Rico Zenklusen Heinz Hopfgartner William Hoggarth Translations QFrame::Panel QFrame::Sunken Jens Nissen Joachim Katzer Olivier Roset Bruno Rizzuti Path Information QFormLayout::FieldsStayAtSizeHint Path for temporary files QFrame::Panel QFrame::Sunken ttt false Program data path QFrame::Panel QFrame::Sunken ddd false Contact Homepage QFrame::Panel QFrame::Sunken <a href="http://chessx.sourceforge.net">http://chessx.sourceforge.net</a> true Mailing List QFrame::Panel QFrame::Sunken <a href="mailto:chessx-users@lists.sourceforge.net">chessx-users@lists.sourceforge.net</a> true Qt::Horizontal Qt::Horizontal 40 20 Qt::Horizontal QDialogButtonBox::Close buttonBox accepted() AboutDlg accept() 248 254 157 274 buttonBox rejected() AboutDlg reject() 316 260 286 274 chessx-1.0.0/data/images/format_indent_less.png000644 001750 001750 00000031013 12142244753 022356 0ustar00niklasniklas000000 000000 PNG  IHDR>a CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs  tIME30BW IDATx}y$UUU]U]Kw"OQaTy2O:(9.€B64MWWuwumY[fFqoD܈ȥ: sdUfdfD|-o w?ҥ{\n-`9{~Ũ? UMveHko~0@`y/Xz;hjL >3P~-C8~N>3,aŵw %TjBг)P "9@v  gB.'}] m~ ?ɟɧ@ܪmJVBe9ZKTvk 2t΁R9$%p%T" 97 wX,o[rx,g-XR= UuCցyPF V?`^wr'駔s% H - v_ 8n qR1lR5N%tʀRJmtc HGtYgYVv|S ,$`p>~u$̟[9ZN9ut@EZ+U^%_,@wq̃VqÀE "ZDr,^"'L#v#=x6DPUZOU rܖ3/IZ"|p;H|8\>'Y=_nٿEjs(%p-d«~TKx$=Of@=hp=aF2僸 B@ ªDQ-ac ^{@6",_QKg|&y \X^A"ih" ,N  PDa8s(=t7 w\~wOTS\: \*ܪrJVF=D*pJ+oknQ9[+>#J> >}.݁K!ZzCz=m;.?q`_T@ث: UE "(*!lZwXVsVFz_@i6%4 *L< Dk/_YnUaXekV =i K8-Vd2G\4H\?s[GV8 g64͆~ٰsf_zGeUa<|/IfXՋv.3]{+ w\~rSg}X4,#^ 9eqpPzvzk(< eksw}x\.N#we\0 9pT0hѺAe1b" 2e9r$Ra-^v eykap''4D~Vf\w)σ, l ^2Y@i+<ٹ&D\ Jw$ rݰRz]? #Zym^S!'0piJ ]=g.LHdaunַ4Pj@kr'{igNs eI%G=(=}+8Tv~E:X[ONl0WP*rkjP# H}R6uV}/{S̫L_c(=u3.(sf]-M ֤ [iAVjc\emU @4պ|h15COcHXXM-3\ O mV[ >"tT+Dk't2jjINiZ:- !Z)SR8 A;WW\8AV:=kV"hʷ^B~lr CdZB~+<#ͪLfK Z{5ODQ3v+YҗenyT]~$D ʃR9jGla3u@wJ 旵ꡫ~ s~6.ysH>#:kJf D7ʹ#AD*2`we\Tmv5f@#Uުy#"UgO|Qfw{JF|-@z_R= Y  v4+l$h-nڂlJpDDa@#^\QiobzAo G&2JJ4 eIbɇVؚ&oOjIi`JoW\ottV+| \+!f|gItJY}o=Ԡ2f kF|8eVt=zOU"O~t cP;n ǘ,]㡉BHc{Ȟ[)c{8H{\5cfy070ƅMXĪzЪV^Vu`xXagη"?~b٭[ز}U' {_:kio1mT`uܺUzUMJ@9K5 I>Lbźu%c~PX mx~DVe92ƘMk/XELb6\#yȦ^[`vc_0 ǦCIBJ\'4(^;4Mj+ w0#}'n̞'yQ0@bMu'g k[߇ϝWi6<ߣc"٪35BA>iM@֊:oUWrIV1}пf OO97]Ul6rLdjA)5R=Y^eU' k6dCkߑǁ8@ O? v7+ܩQH9g@C(onPc^5""=m#_U2 o${VPqFJ 8ȝZmڂ^n\-!#ωUj $1{"@"FxV ;@M _jbAsc{Րڭcr ShYUmٱ$x>lk߷.F2G'9.'T?bo]}& ŮzlbqT+@IR٘Gg#xl7תϞU4LZ<PJ^l:I ^O&vWu|UxT~!Տp-J'lJS3Pn׈w7^_ϿJ<@X^YPFCdU8sNKS 4ZAP#N%`ǃ20`i-n5'7 0Pxډuo@%*"H!! gh;:41a;6 JXBv16EufAqNkcz?ʅm?m 1xuzoOh[HTV욌ЯP`'q'W`ѽ a 瞏5/~5p餐nRevYFīzG>aJ%R~-B_tcfO-[4@}mǚ~v`"lcpXtʯ@аuTFr(ŎFffkP' f5VlC7sfL'(Q\-T%MExb3@5Eگ+Ջ)$U1 zq&b_@G@d?+?$?c؃g`_{:(JUg ;Vӟ,$j4WD͞Ͼ -=m |OYFQOR=b4107 2R][L{ cݲ1ܨP͚*~VPaP:`CT;1Ƣ/JZMJ굊:A)}>p,#yP?$vލ3O>eΟ<-jSf;X]G>S Խ7Ғ ᝴TcˬƵ7n=O1iSM(Y(ޖzR13ѯ[#ۻ>͠-Ɓ~~BD5  Z{u?1u0cC7W:i U~u&KV 7O4[F~> a.截 X`Ke=/|OߟF;DXkl |OmC*퇟B[q م_}g_S_ 6MSF<*P ED$o!!wCB%ž:sQR 7V?鰭3o# ~Xۉń_GM>Kj&HQ#cPQEH5b|n_RX8f`ul pMZ谴p6v݇޿.Rk6!(*M'/_ > jf7.R8њsDg&hjg>b~+:%F~sآ#~TOR3HkQb[; Δaǭ$[@nHE$Kc|X5A~əM0q]Rjd,V)Б;z?fw]7܇` )7%,N_W?˅f@ Q>i2C8Ï</z=I{_8 *h:1݇T^RPЦ,l& c8~sG+ gY Hcw?kNs&[[^8:(=}?_h ,c, Yd|So*$X>_ˆGcftRev 8p;Pwq4?F<7ލc^Zu7GHC]NỉKl7NVҁs p 8Xx{xoB>E[b&'R*M}|vmdىZhOxMD_} 9ڍW^ L grX}3T$CdЈvpFܲʢ^L6@ZCj y"vxD(85t@G (<>Sm.DyxG@Nj+;R^" Վòb0L7H@a]? _E~ŔaGqQ[P>9 /z9h~3;tgo^D)W b߬4B?N- nr`'ldfȼؖvpݓ(G\F*Na ?|Ztc[^6>;䝡X@ 3som@q^O}%6^X-"ckEh?\W7u0űlVAkޏ)0d]ǚ$QXQŹYU8Ng*mb{ЉM৮W} Gm'ۏ,3ލ/FߦH "JQ@a۸篷T7*Z 2&5n4`}B:Bj\x[邍GN TB[/0}w0}wLLy}J(Zwv7`4t1<܅ޅ{cq]}h; ѫVU_L72-g`MsuKAol@HEF7GT \*j ,l6w-Xq#{`#s.(0܅89&P|僿Ey|0#OE> GLN, {^Vl4AUl{aTAulb`e6#OܐL6]zH-?? ,HCj{A =u[ vQeUA:&Z Ph%nkp$|3f6V7N#_7gdR도 VJCl;l"!RI4Tbc(lf*^M h*8 !k5@0>&{Dx"8$;@sfO3UAH"U|3C.k^ @V&I/4 |'"e!İ8gKL`=tt\:`m T>y_m\6r)FƆ2|V3UC mX0Q$챦Y)9H^t,ҙ5zF ƛlmx :S5}ߞ7}T1V&ܹ} $ `eRy>UqC*C}`1]m AŎsY( h+h$/k:&ѡA8SX#hbLF,zuHő?˵Z& @دe" 7>?=IDAT0w 04@6׳8WdKSH^=ndN+qyE}@$D ;J(= 9h d76)Y2X60tQ7&(;f%`XR\|%WC"QCOe@& ELK5hN \F3 ܒҢK|9t2+؄ZDFUHԈ iK+`2Ps΅Y: JK@T vltzGuR߾EМäVwrzwa4Tq;GFЈvX"wh҄ģp& Pv2]Lz;B`vJqʱwC=)j+|(gjw/K< nQs XN]Vo8 j_'f׵NU8Tju $vNi߻ŌN@YYPvPku1 +҅.Xjy !ti@&ZM$Ҡt:>3X,<  ];{/aS˖JXqLJ 7{/xAf|ΐh0({ڣAVD 'YE{^ Xx:ű{Ck~/1؃`~ + 8Q1sl:sEmCVf91-u_XڐۏΟ(_`Ͼۮq vY (djS&p>¦:^[,9[?60 swR}ȭt~#Y!jY9μ=du 2st> |F )= X/|)y1B^ `zuO"9ǦTE486i\ɾ"9g9[dCCnu j|˃%g%c~4_|Կ8ih۰2Cd6bYM 1`hM= r&c]{+2~RUz#_ T^Wl)13¿ztO#4n`Xn/4f{gTuڷa;\7G#ꞖxN{\x9C?,_SK8ZF)IENDB`chessx-1.0.0/data/images/filter_rev.png000644 001750 001750 00000040746 12142254551 020652 0ustar00niklasniklas000000 000000 PNG  IHDR>a CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs  tIME!g4 IDATxi]u&x[(@hlNǀQ4At8v,&Fct;Ct1$4ĠJU֝Ͻ9[ j?Tttz׻^[sknͭ5qѻ񦻺bBTU:vڅ.T*޽{βUظq#=NԦMu(J4]=sV}76l@[ng׭[7 7† ؂N}y|B۶+%ua'mn:5!`Æ 4>'?ɫ;;nKSH)rPszƛwB]con?p?\/Nϛ7O7 v]ֶ` CԜEyf^?V\:,ķ[6}UWm ҥ]q#L#U0yѪ'N]2 (mܸo&>x [KnJtvK.ϛT*Zje!O ^nJ_oδuat:M.{M7(|Ѣ^x]tg/_/]x 3]יa2"]L&WL[GR~X>=:K9VqxG! _z*(D01JÈFW457-3,s`{`bbeq;jZԸ@J%tpz6X( ǑH$755s,tK/2T*:H 럟Z (/V,X`Nm@-=+ 8p]JuS`] N5)c8bإ馦9ix62jr2 0 ]@6g:OBr8gl_nN=!?d&D\8徊@CEG]`i8,} a9ixv:@_e%)ugI~6Pd,G<0N`wgM\fO?Q8o޼,ZeZn5 TΔYMQ#-H)%+KS.,wĉ00FR!x=R) Q@W NgD"D2y@9 f'_(O}n05,d Tza{GU׮H͛ifϒ_uSv8V*PRzJ<@F2跋w鴙L$?rKW>>9l e nTu'h@ B-S3 H$T-[f]tG9?p>˗ciJQ8/~(MK-Zc6 D#P=3I@]i0-aH)oVJ-]lYСCݻW8p۶n+WҾ}jݍmB˗^ꫯڤe[+-Nް멎ӹ~( )˲.%ׯ΅ǎ=:ۋ~xl {`ڵaȇ"˲Vz"3!h:@ ih,Je XkVXwvv}𡇝}sx^{/RoO?ZhJbKј`WJÌ = +OJPhiަeˮ>|cӦMڊ+3@JfٳXr+_>zjժbo OuאДlnPRL iٖ#6i_iǯ…G_~¾}d>ç>):zܹsNzW8=s.`&!kW/vs|A9ނm6pЃbڵڞ={䥗^wyH] t@T`B5=$RsMX4]נpTX/Xů:>A]t9nZjg  <ؼy3_+W-FRmfCScJ44\/!A! @*g ugib/,˺e>:<쳸[5\vHg]X,"LH0Mfy4H%TP[#BcHwjPC~;")%%R b뿦͛7o~2੧zaǎaٖ98i&躎{nۿ'>a|9/4B\ ܥ0!@}jJj+04+097"qʕe/mݲE|>ݻw/ #pRtmGjX6 !R)d*?OitOJ?" M+pš>AR )7oީq mۨ꺪罉5JAe+8_5Wm&3J3`Ŧ@l `B*s o(nh @k  N ԠJk3pI2e@L*(6%Pj=y_3tO]wǠRzHgB;i&F4ycWPcܹSzظq#O6mh4*4/Qè N% o4̦ iݏ?ku'LG f]W.W iU*/_\>1I֭[af ov95x2ǯWV ^,5*9ѿi4C 0M}줰v @F%WV],0h"mje'/ݿߴ2xN}DžP>FF/7 ,|X4K*R $%Jì& 4^@ŘxCiXP-do+'鷓7^*HSzU!qH&tIu ֓ʻwE$|S"6AoR c򭓆!j)y<0"$q47`޼ttt Ax.xW-58tя_M?}G*شi,YR~{]-|'iSC8wiIix!To4 .y>t hkoGS:F@>W_Ɖ~ d "M#iGcgSv-Eo߮?qF4M@jv]idH[flt !Υk'Ӻe}Y VFgyb :ZZڊ6479" 'pj<$ldx'񤒚I%AE[:7l,ζݍ;vkpr>~O>q܊LCa fUTJM!k}>P+ {B3t֊֖X ZNB G'1X0!LLV8\3  DSZ!+|Vq>NhvU*Skl;A~WnM&dToyîF]@@4ϐٹw 3EI=_ T*f4 @ B.㯣o`}C:s5!@7鹊5u5io?,oDoߎ7 ( GǗq ny<ES`iaA6In4lpZ㊧<σ>2M--H;> 9 %"2 )%t]m۰"eB\iANp*ÑcixM"!a8'()! D.90bGΠ)%9K{J3WZ'zvVї;[qIDATnQo|dC΅:sZ $g 3Hӕs3Zv{Og!@7  X{ Ia`d 'G8)c0YZIX8l4?L?2%}EH D*x Ŋ JA1ҴXSL tHfeUʇ$Ka.@PTO}rvno$ P$ sệ#˶q Cc Bp%Ld2lj џ004X*=GS2xԂi`@%jO?0| 0_It%*JUA-1,I[4-y a{#) tR 6/,Rgo4 xɂDޒ@G*d<˲?^(*  J ;1Wq@Pu%Uy1 Q\:՗F̬Z/@l#{;x}{F(P'}Cm5h4< z pn9 CG$bòl\T%d&I:ɬ 5ShM%J04?+JOd"p\!TFSWI]s0Ei -OR##{|TJʈ?!`ӦMf۶nTUC{:`T:BzҰbh)e hqXX=7''L *p:wixJ'`Ġ:($R$lg<39 %J85d*&2۶L&܌fRI(e'09dE ]  #3BjASho A*_q/R7ȅ߃$+*߇`2B{LGGTǂ,T=urLGGՑsQ.9T KROҋ0?_9OtDy/=#/Lh>w S\*0 x--hmmAss3l˂BC F'&1)` Wi028zzZar 000#1R&LFNk7AKaH$bHDMDle NFGPS -K7pE9!u )$8IWz ֟)XYx~ /T,VNR?ϛܹ_W~]&uk,r*[7rMڰn۩8\#40zz'N@03:$"uh$;۶ o K6Fj/A<}A< @Dgh29:l 6G$]Ը+hTe9'rȫdR6"s}Ykt[wg,8oqj(K6&y3hD$aa6&w3Aol9S{PZQ Y|UHH0,h՘{r.?/c0SH&LlJ<=Z؃a*ǡڸ~^sJ## ,9!n<^RT[!"iT4 n0t]a[z0 YmA`JP !ejձ c~TG UR2鰁|L1>"M@x όBI05tDǢ S6L4ۚO̔؉Ld ,"[(!/rXȕTA䪯~ggDors(`\AL(vkˠ BCՌ~uNH::&.jqAWzyH&D"r%Z,9}n}![J(z/?t,W Ÿm"Ӿki5`h !]¯M .nqqE) Qɒ+PBOى"Ng ,Q.;Tr=}sŁG0&qJᏈ< Ÿ@ ֏ &.j%"HZr zNj<2Ed %KʸpW' Q-ﻸ>{|k ef$Y^䇤1&t`•qX #--Q T#CYXM0;RwL \TTpM>kB/n? |qɴ5PmY5;Xâ 3)dDGGX"JeVݪGRPvܽNU<+\2~;_22 %+#k)J \{A+nY,Tze4G/ k MQ(;<dJDJȗ{:Wwp;/#~٪hZ4EΕ^Gr+9\&4Rp`z9~t\\]?!T^ #include #include ChessBrowser::ChessBrowser(QWidget *p, bool showGameMenu) : QTextBrowser(p), toolBar(0), m_gameMenu(NULL) { setObjectName("ChessBrowser"); setContextMenuPolicy(Qt::CustomContextMenu); setupMenu(showGameMenu); int fontsize = AppSettings->getValue("/GameText/FontSize").toInt(); setFontSize(fontsize); setAcceptDrops(true); } void ChessBrowser::setSource(const QUrl&) { } void ChessBrowser::showMove(int id) { if(id) { selectAnchor(QString("move:%1").arg(id)); } else // First move { QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::Start); setTextCursor(cursor); } } void ChessBrowser::selectAnchor(const QString& href) { for(QTextBlock block = document()->begin(); block != document()->end(); block = block.next()) { QTextBlock::iterator it; for(it = block.begin(); !it.atEnd(); ++it) { QTextFragment fragment = it.fragment(); if(!fragment.isValid()) { continue; } QTextCharFormat format = fragment.charFormat(); if(format.isAnchor() && format.anchorHref() == href) { QTextCursor cursor(document()); cursor.setPosition(fragment.position()); cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor); setTextCursor(cursor); ensureCursorVisible(); return; } } } } void ChessBrowser::saveConfig() { AppSettings->setLayout(this); } void ChessBrowser::slotReconfigure() { AppSettings->layout(this); int fontSizeSettingValue = AppSettings->getValue("/GameText/FontSize").toInt(); if(fontSizeSettingValue != m_fontSize) { setFontSize(fontSizeSettingValue); } } void ChessBrowser::setupMenu(bool setupGameMenu) { if(setupGameMenu) { m_gameMenu = new QMenu(this); m_browserMenu = new QMenu(this); connect(m_gameMenu, SIGNAL(triggered(QAction*)), SLOT(slotAction(QAction*))); connect(m_browserMenu, SIGNAL(triggered(QAction*)), SLOT(slotAction(QAction*))); m_gameMenu->addAction((m_startComment = createAction(tr("Add start comment..."), EditAction::EditPrecomment))); m_gameMenu->addAction((m_addComment = createAction(tr("Add comment..."), EditAction::EditComment))); // Nag menus QMenu* nagMoveMenu = m_gameMenu->addMenu(tr("Add move symbol")); for(int n = MoveNagStart; n <= MoveNagEnd; ++n) if(n != SingularMove) { nagMoveMenu->addAction(createNagAction(Nag(n))); } QMenu* nagPositionMenu = m_gameMenu->addMenu(tr("Add evaluation symbol")); nagPositionMenu->addAction(createNagAction(DrawishPosition)); for(int n = UnclearPosition; n <= BlackHasADecisiveAdvantage; ++n) { nagPositionMenu->addAction(createNagAction(Nag(n))); } nagPositionMenu->addAction(createNagAction(Nag(WhiteHasSufficientCompensationForMaterialDeficit))); QMenu* nagSpecialMenu = m_gameMenu->addMenu(tr("Add other symbol")); QMenu* subMenu; nagSpecialMenu->addAction(createNagAction(NagDiagram)); nagSpecialMenu->addAction(createNagAction(WhiteHasTheInitiative)); nagSpecialMenu->addAction(createNagAction(WhiteHasTheAttack)); nagSpecialMenu->addAction(createNagAction(WhiteHasModerateCounterplay)); nagSpecialMenu->addAction(createNagAction(WithTheIdea)); nagSpecialMenu->addAction(createNagAction(BetterMove)); nagSpecialMenu->addAction(createNagAction(Novelty)); nagSpecialMenu->addAction(createNagAction(WhiteIsInZugzwang)); nagSpecialMenu->addAction(createNagAction(WeakPoint)); nagSpecialMenu->addAction(createNagAction(EndGame)); nagSpecialMenu->addAction(createNagAction(WhiteHasSevereTimeControlPressure)); subMenu = nagSpecialMenu->addMenu(tr("Bishops")); subMenu->addAction(createNagAction(WhiteHasAPairOfBishops)); subMenu->addAction(createNagAction(BishopsOfOppositeColor)); subMenu->addAction(createNagAction(BishopsOfSameColor)); m_gameMenu->addAction(m_removeNags = createAction(tr("Remove symbols"), EditAction::ClearNags)); m_gameMenu->addSeparator(); m_gameMenu->addAction((m_enumerateVariations1 = createAction(tr("Enumerate Variations A) B) C)"), EditAction::EnumerateVariations1))); m_gameMenu->addAction((m_enumerateVariations2 = createAction(tr("Enumerate Variations a) b) c)"), EditAction::EnumerateVariations2))); m_gameMenu->addSeparator(); m_gameMenu->addAction((m_promoteVariation = createAction(tr("Promote to main line"), EditAction::PromoteVariation))); m_gameMenu->addAction((m_VariationUp = createAction(tr("Move variation up"), EditAction::VariationUp))); m_gameMenu->addAction((m_VariationDown = createAction(tr("Move variation down"), EditAction::VariationDown))); m_gameMenu->addSeparator(); m_gameMenu->addAction((m_removeVariation = createAction(tr("Remove variation"), EditAction::RemoveVariation))); m_gameMenu->addAction((m_removePrevious = createAction(tr("Remove previous moves"), EditAction::RemovePreviousMoves))); m_gameMenu->addAction((m_removeNext = createAction(tr("Remove next moves"), EditAction::RemoveNextMoves))); m_gameMenu->addSeparator(); m_gameMenu->addAction((m_addNullMove = createAction(tr("Insert threat"), EditAction::AddNullMove))); // Non-move oriented actions m_browserMenu->addAction((m_copyHtml = createAction(tr("Copy Html"), EditAction::CopyHtml))); m_browserMenu->addAction((m_copyHtml = createAction(tr("Copy Text"), EditAction::CopyText))); } connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(slotContextMenu(const QPoint&))); } void ChessBrowser::slotContextMenu(const QPoint& pos) { // Handle non-game browser if(!m_gameMenu) { m_mainMenu->exec(mapToGlobal(pos)); return; } const Game* game = 0; emit queryActiveGame(&game); // Handle game browser if(!game) { return; } QString link = anchorAt(pos); if(!link.isEmpty()) { m_currentMove = link.section(':', 1).toInt(); bool isVariation = !game->isMainline(m_currentMove); bool atLineStart = game->atLineStart(m_currentMove); bool atGameStart = m_currentMove == 0 || game->atGameStart(m_currentMove - 1); bool hasComment = !game->annotation(m_currentMove).isEmpty(); bool hasPrecomment = !game->annotation(m_currentMove, Game::BeforeMove).isEmpty(); bool hasNags = !game->nags().isEmpty(); bool atLineEnd = game->atLineEnd(m_currentMove); m_startComment->setVisible(atLineStart && !hasPrecomment); m_addComment->setVisible(!hasComment); m_enumerateVariations1->setVisible(isVariation); m_enumerateVariations2->setVisible(isVariation); m_promoteVariation->setVisible(isVariation); m_removeVariation->setVisible(isVariation); m_VariationUp->setVisible(isVariation && game->canMoveVariationUp(m_currentMove)); m_VariationDown->setVisible(isVariation && game->canMoveVariationDown(m_currentMove)); m_removeNext->setVisible(!atLineEnd); m_removePrevious->setVisible(!atGameStart); m_removeNags->setVisible(hasNags); m_addNullMove->setVisible(atLineEnd); m_gameMenu->exec(mapToGlobal(pos)); } else { m_browserMenu->exec(mapToGlobal(pos)); } } void ChessBrowser::setFontSize(int size) { QFont f = qApp->font(); qreal r = size; f.setPointSize(r); setFont(f); m_fontSize = size; } void ChessBrowser::slotAction(QAction* action) { if(m_actions.contains(action)) { EditAction editAction = m_actions[action]; editAction.setMove(m_currentMove); emit actionRequested(editAction); } } QAction* ChessBrowser::createAction(const QString& name, EditAction::Type type) { QAction* action = new QAction(name, this); m_actions[action] = EditAction(type); return action; } QAction* ChessBrowser::createNagAction(const Nag& nag) { QAction* action = new QAction(NagSet::nagToMenuString(nag), this); m_actions[action] = EditAction(EditAction::AddNag, nag); return action; } void ChessBrowser::slotDisplayTime(const QString& text, Color color) { if(toolBar) { QString objectName = QString("Clock") + QString::number(color); QLCDNumber* clock = toolBar->findChild(objectName); if(clock) { clock->display(text); } objectName = QString("Clock") + QString::number(1 - (int)color); clock = toolBar->findChild(objectName); if(clock) { clock->display(""); } } } void ChessBrowser::dragEnterEvent(QDragEnterEvent *event) { const QMimeData *mimeData = event->mimeData(); const GameMimeData* gameMimeData = qobject_cast(mimeData); if(gameMimeData) { event->acceptProposedAction(); } } void ChessBrowser::dragMoveEvent(QDragMoveEvent *event) { event->acceptProposedAction(); } void ChessBrowser::dragLeaveEvent(QDragLeaveEvent *event) { event->accept(); } void ChessBrowser::dropEvent(QDropEvent *event) { const QMimeData *mimeData = event->mimeData(); const GameMimeData* gameMimeData = qobject_cast(mimeData); if(gameMimeData) { mergeGame(gameMimeData->m_index); } event->acceptProposedAction(); } void ChessBrowser::mergeGame(int gameIndex) { emit signalMergeGame(gameIndex); } chessx-1.0.0/src/database/index.cpp000644 001750 001750 00000023171 12223260306 017757 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 Marius Roets * * (C) 2007 Rico Zenklusen * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include #include #include #include #include #include "index.h" Index::Index() { // Dummy Values in case a index is miscalculated m_tagNames[0] = "?"; m_tagValues[0] = "?"; } Index::~Index() { } GameId Index::add() { int gameId = m_indexItems.count(); m_indexItems.append(new IndexItem); m_deletedGames.append(false); m_validFlags.append(true); return gameId; } TagIndex Index::AddTagName(QString name) { if(m_tagNameIndex.contains(name)) { return m_tagNameIndex.value(name); } int n = m_tagNameIndex.size(); m_tagNameIndex[name] = n; m_tagNames[n] = name; return n; } ValueIndex Index::AddTagValue(QString name) { if(m_tagValueIndex.contains(name)) { return m_tagValueIndex[name]; } int n = m_tagValueIndex.size(); m_tagValueIndex[name] = n; m_tagValues[n] = name; return n; } void Index::setTag(const QString& tagName, const QString& value, int gameId) { TagIndex tagIndex = AddTagName(tagName); ValueIndex valueIndex = AddTagValue(value); if(m_indexItems.count() <= gameId) { add(); } m_indexItems[gameId]->set(tagIndex, valueIndex); m_mapTagToIndexItems.insertMulti(tagIndex, gameId); } void Index::setValidFlag(const int& gameId, bool value) { m_validFlags[gameId] = value; } bool Index::replaceTagValue(const QString& tagName, const QString& newValue, const QString& oldValue) { if(!m_tagNameIndex.contains(tagName)) { return false; } if(!m_tagValueIndex.contains(oldValue)) { return false; } ValueIndex valueIndex = m_tagValueIndex[oldValue]; m_tagValues[valueIndex] = newValue; clearCache(); calculateCache(); return true; } bool Index::isValidFlag(const int& gameId) const { return m_validFlags[gameId]; } bool Index::write(QDataStream &out) const { out << m_tagNames; out << m_tagValues; out << m_indexItems.count(); for(int i = 0; i < m_indexItems.count(); ++i) { m_indexItems[i]->write(out); } out << m_validFlags; bool extension = false; out << extension; return true; } bool Index::read(QDataStream &in, volatile bool *breakFlag) { in >> m_tagNames; in >> m_tagValues; int itemCount; in >> itemCount; int countDiff = itemCount / 100; int nextDiff = countDiff; int percentDone = 0; for(int i = 0; i < itemCount; ++i) { if(*breakFlag) { return false; } add(); m_indexItems[i]->read(in); if(i >= nextDiff) { nextDiff += countDiff; emit progress(++percentDone); } } in >> m_validFlags; bool extension; in >> extension; calculateCache(breakFlag); return !(*breakFlag); } void Index::clearCache() { m_tagNameIndex.clear(); m_tagValueIndex.clear(); m_mapTagToIndexItems.clear(); } void Index::calculateCache(volatile bool* breakFlag) { calculateReverseMaps(breakFlag); calculateTagMap(breakFlag); } void Index::calculateReverseMaps(volatile bool* breakFlag) { if(m_tagNameIndex.isEmpty()) { foreach(TagIndex tagIndex, m_tagNames.keys()) { if(breakFlag && *breakFlag) { return; } m_tagNameIndex.insert(m_tagNames.value(tagIndex), tagIndex); } } if(m_tagValueIndex.isEmpty()) { foreach(ValueIndex valueIndex, m_tagValues.keys()) { if(breakFlag && *breakFlag) { return; } m_tagValueIndex.insert(m_tagValues.value(valueIndex), valueIndex); } } } void Index::calculateTagMap(volatile bool *breakFlag) { if(m_mapTagToIndexItems.isEmpty()) { foreach(TagIndex tagIndex, m_tagNames.keys()) { for(GameId gameId = 0; gameId < (GameId)m_indexItems.size(); ++gameId) { if(breakFlag && *breakFlag) { return; } if(indexItemHasTag(tagIndex, gameId)) { m_mapTagToIndexItems.insertMulti(tagIndex, gameId); } } } } } void Index::clear() { for(int i = 0 ; i < m_indexItems.count() ; ++i) { delete m_indexItems[i]; } m_indexItems.clear(); m_tagNames.clear(); m_tagNameIndex.clear(); m_tagValues.clear(); m_tagValueIndex.clear(); m_deletedGames.clear(); m_validFlags.clear(); m_mapTagToIndexItems.clear(); } int Index::count() const { return m_indexItems.count(); } QBitArray Index::listContainingValue(const QString& tagName, const QString& value) const { TagIndex tagIndex = m_tagNameIndex.value(tagName); ValueIndex valueIndex = m_tagValueIndex.value(value); QBitArray list(count(), false); for(int i = 0; i < count(); ++i) { list.setBit(i, m_indexItems[i]->valueIndex(tagIndex) == valueIndex); } return list; } QBitArray Index::listInRange(const QString& tagName, const QString& minValue, const QString& maxValue) const { TagIndex tagIndex = m_tagNameIndex.value(tagName); QBitArray list(count(), false); for(int i = 0; i < count(); ++i) { QString value = tagValue(tagIndex, i); list.setBit(i, (minValue < value) && (value < maxValue)); } return list; } QBitArray Index::listPartialValue(const QString& tagName, const QString& value) const { TagIndex tagIndex = m_tagNameIndex.value(tagName); QBitArray list(count(), false); for(int i = 0; i < count(); ++i) { QString gameValue = tagValue(tagIndex, i); list.setBit(i, gameValue.contains(value, Qt::CaseInsensitive)); } return list; } QString Index::tagValue(TagIndex tagIndex, int gameId) const { ValueIndex valueIndex = m_indexItems[gameId]->valueIndex(tagIndex); return m_tagValues.value(valueIndex); } QString Index::tagName(TagIndex tagIndex) const { return m_tagNames.value(tagIndex); } QString Index::tagValueName(ValueIndex valueIndex) const { return m_tagValues.value(valueIndex); } QString Index::tagValue(const QString& tagName, GameId gameId) const { TagIndex tagIndex = m_tagNameIndex.value(tagName); return tagValue(tagIndex, gameId); } ValueIndex Index::valueIndexFromTag(const QString& tagName, GameId gameId) const { TagIndex tagIndex = m_tagNameIndex.value(tagName); return m_indexItems[gameId]->valueIndex(tagIndex); } bool Index::indexItemHasTag(TagIndex tagIndex, GameId gameId) const { return m_indexItems[gameId]->hasTagIndex(tagIndex); } inline ValueIndex Index::valueIndexFromIndex(TagIndex tagIndex, GameId gameId) const { return m_indexItems[gameId]->valueIndex(tagIndex); } TagIndex Index::getTagIndex(const QString& value) const { if(m_tagNameIndex.contains(value)) { return m_tagNameIndex.value(value); } return TagNoIndex; } ValueIndex Index::getValueIndex(const QString& value) const { return m_tagValueIndex.value(value); } IndexItem* Index::item(int gameId) { return m_indexItems[gameId]; } void Index::loadGameHeaders(GameId id, Game& game) { game.clearTags(); foreach(TagIndex tagIndex, m_indexItems[id]->getTagMapping().keys()) { // qDebug() << "lGH>" << &game << " " << id << " " << tagName(tagIndex) << " " << tagValue(tagIndex, id); game.setTag(tagName(tagIndex), tagValue(tagIndex, id)); } } QStringList Index::playerNames() const { QStringList allPlayerNames; QSet playerNameIndex; TagIndex tagIndex = getTagIndex(TagNameWhite); if(tagIndex != TagNoIndex) { foreach(int gameId, m_mapTagToIndexItems.values(tagIndex)) { playerNameIndex.insert(m_indexItems[gameId]->valueIndex(tagIndex)); } } tagIndex = getTagIndex(TagNameBlack); if(tagIndex != TagNoIndex) { foreach(int gameId, m_mapTagToIndexItems.values(tagIndex)) { playerNameIndex.insert(m_indexItems[gameId]->valueIndex(tagIndex)); } } foreach(ValueIndex valueIndex, playerNameIndex) { allPlayerNames.append(tagValueName(valueIndex)); } return allPlayerNames; } QStringList Index::tagValues(const QString& tagName) const { QStringList allTagNames; QSet tagNameIndex; TagIndex tagIndex = getTagIndex(tagName); if(tagIndex != TagNoIndex) { foreach(int gameId, m_mapTagToIndexItems.values(tagIndex)) { tagNameIndex.insert(m_indexItems[gameId]->valueIndex(tagIndex)); } foreach(ValueIndex valueIndex, tagNameIndex) { allTagNames.append(tagValueName(valueIndex)); } } return allTagNames; } bool Index::deleted(const int& gameId) const { return m_deletedGames[gameId]; } void Index::setDeleted(int gameId, bool df) { m_deletedGames[gameId] = df; } chessx-1.0.0/src/gui/loadquery.cpp000644 001750 001750 00000000320 12207414403 017665 0ustar00niklasniklas000000 000000 #include "loadquery.h" #include "ui_loadquery.h" LoadQuery::LoadQuery(QWidget *parent) : QDialog(parent), ui(new Ui::LoadQuery) { ui->setupUi(this); } LoadQuery::~LoadQuery() { delete ui; } chessx-1.0.0/data/players.cpd000644 001750 001750 00000205265 10622423665 016711 0ustar00niklasniklas000000 000000 Рd1972.01.17????.??.??SWE-(    + E T T h h d d d d O O)I h1971.11.17????.??.??ENGgm4 8  ( 7  2 F F d P _ d d } i x n O PNG  IHDRMdL* IDATxty$y{GUyTUs.^]%`@4HA&M %;¦d-[MEی$AR$. k̬33ٯ2~{rU. = hU0:ULCAe!q @76ʠ34 3V+^T\ڡXTS'uߡv}q(-8&cG8I{D~BcQe%唋@tVj6]cIQ4Y+D%L1$#8-`S+pnrRzV&[APcL*B<}p,V--:T窮q)GFdb=**-dsUTB%Ƭs5C봚2s$ѲT~qVH1BxGkT+T,hnʂͦM-K+aEV؄WE!WH4xJ!"+a9ˆ\X&HIOUr:#)ZR 5qt.G4ʨ>ڊ*S1R%,PMS*M@UVJJp7m{e\ dr)dZY⬨X1KcX}T|^TEVI e+Iy2M@cwI&J)JFN^,=O2F]x8QE82+6 YqVHPD4e/Ƽ4W\S4KD`$Ia{QRF6h.t1lK)]ĀPzKPb6<`QLle~aS͎s5zRQ`>l D[IHMc ,NyC)ѕχq+y y&I^Ǫ/SuQZQcW+j20y ;UE V!$M5{ ]X6"I2&(peHJkv;ӎ4fX, u@6(k Q.hM5jyЦYr%!֞ZWk ?x)4yc-nEoO>zs6.ǡ?d2XGVg=LT?2[>5lJk-3Qf-51:JjV~U,x5BP|gf ʰ;ʸO骀q@CADP4B8ʃWn/Ο~OfE=+@R.kb"-)=c0䲧9P;e&F`X.W,ܠ PWXY'e3"mR),IWf2/`` 咆f"R(\7[o|l@0R)0$<%bFS5;U" 5#dBՙ2"13O:dR4 fSz|S!RIlTL"ոMB%Eʬ\ie=a}X(8L >F-Eiݽ:6ݶyjӌIa[j:lt^Okkr9.JRڼxJL, hW~ڞԏg79ـlԠ@jOv{Dip9'E#5@)+!nۤQrZ+7x>Q,o "GۼRiia"2z6Ѹ|{Z h)'Yk n9yp8PQHpj l*x'y` 9LӲBU&!/̋9 C'1nYyG^}+Z^6Jʬ:畼az^)d*i:쓏e&@)=]3{ 3t\8Ja3w~R폾Rm>wvH2G89LM)UebU::2(J*e)vvX+56=x??\x6-d(/F0=,ʦLl6%7hgHcg;Y@MIYT.%-J*JTU%%j:.謔R.biZ\ eQp0zKwT6 ]A)due^nf{u65 p57N* n> w/f3w^#BVi9LO+Yu(n/YUДG) YG2n.[\_si\3d*Zch$zQ)>Bwܾo}oW߾OPxץsIC9Tg2&f.bSTz` =z=vJD&!Ղ4{ " >׍U0͑co @:Ρs+B"}OܻutQQoT$s30U*P\10Z@1j)u S-1~ d6j\gV"[cnLk>ǂv_22T' 9vɍ4 WVZ_a HB@1Q%kSa]9(Vbܾ,G֦{Ϻ--9|@Mz-kTeԪkJ dTUR2ja U =+ۮGt @1-uHVax [$H0˝;TAXݩP=MVA87BbV¿!«2O&jw}FXg[aV.70]кpT& qaŢÈXp ktTUcbY\ndkovkOfު*]gջ۝ݜO攢z^ꯗTU]KAGeA7ZpW#|~?t_|Y@Fqrj4ST1wF#؀ TP,Ua'{ h5*ʨI뚯i*rt[im{\j'N=TLn1A|K_7m=pOi;&iuK\tD2 T it?`KlI*_ھq0uF)[iUVש qFLM4B4I^3f0t%; 2Mb,\M4)Lڄ&Fɳ=?pܹmgŷqK\w˱7]j JYۃ)RPRUH&eB lK`SF7Ksi#j?#Ɨ_xVsڝtlȓ2 s cO?ISS\)RF"EP,-P(]eD!RyQWYl|wJ'K_km]]AcN3<寿o~s{wC;yp 钾]Z&(<*sf)oTʒr^vgpFC+7.s#/ Ԡ֓H:u0D2R .т*tm>.%_s(@c#wa֍:LW2qW zpMŸ # sC6eXaRTo6Cݳ'߭{$tB2>\@_(f\e,MVԭX4 IpʲTsD[N^ts3Ez&lؐD/a@$3h0K$L#hdT@$+d"K"6^OC2G!5H4 H; Dt2EN&;Eo\w~Y?; @L#w*Ӥ jQVU:|֥!u^穏?uzs U?jd.׋fR6VIPƁ(hUb$ȣ?0Z͹D74 L)2mw^wbB٬/05ꌴ.sYbߙvG8Q{Td\7 L`7IDAT믿jPK ʳx 0]5uu.LKu펺?w~޻;? cg[>-9* }g LPgO1NnA2e) мWb=WY/$n+c9'}4XU8,SeD-gj25'Br9ͶAoG}P; 0ޭw XA'Y_ͷ[(XEvOƩGnCRWLJȞ9'orǏK8sצ14^n<CI^Si4\k ga~sn 3[d\YoN,/$Mbnh(w3j$,n V婶z(_^yewZ,; !":B*j,s9MdQpR5d1$3"~(%O^l;38u/}f $U E,1)8 )'UɗUh YUrAC~oRR$v\Zmm\gAy<`§a*Tļ򈘎hbʽu}jHbN*kx =ISk{ׄ u'=MïZXپ1)0!=j+/G.3a].(9T[\YxK|z[ן{3(_8~-n[Xg|$+1?RxJb*$nxleH$m= Vk#9ދ_?ꙿgZk;r8]Ub>0eM&MJ2#TӜv*1gUy/WB/6Ȇ.WĪ` >y?l+fcGnS)Ϊ!ӏB*#e"< :F:sD77~7 ^޹,yM#`v Qx`4 .tL, W1=M|%Ch<"VCF'T9u:m{jw[kTcL{H&qLj vfdajHETTT@t>u?k}šg}a^X??Kl%^'n/$Q i<i[gw44 A^C5:hG=Th'>\<ԧ/d BU:ezNU: :6ْu)B[,;ʧ)[9__TA|k/ڽ=s_=Td-&ly:OO͕v';ro%cr<)T#[-NF: Cg~ۆ w`$ӅH+9J3}ۯ#n1$)nJ]! wG&u?Oz{DRfQzx#N{pcAll5aP *-5:NZ+vR(gI$a:h?~Un 4yS{zߓ1gv pdO܆t 1!}$ԕB.m/>K?}I/߈d_--T!:IiPҝ:e *mYRhaOu@Cc@H~goḮOx@s4 M &R{);S+yj~!<,6jhcתͺW'X'HZ$",P`p%hiv\{o~S <}'yOɀntgaM*eF,i=&fɒ-=H I6F*%ni UxZWW'l\K$%G[_-R0c1#KȌog?9Tb: =Lŏ>᯽ί_rs 5̆0{3[Tݡ\C2U\SRJ z$ɜzNsbPQ1)* &™y9.ޮ_+/ _~^l e*+6<ዒjڽݦ X_7Vo6j1e4|bZwR|%JJZt4$18mLcDJd>*7S :-I:Z+Y"IϞ;>.ڳOLJ;/se?SNolwGx8n02## mTpҠhd8*B5(D}'B$UACӗ'jD7e*h_jUõgCO]LD&R.T}=8: FS;M2g_!(\S;8rY<2bCI,a~4HyH҂]XБrH'78_ſ?w?6^ùu)_Zُu<i{k]O)ǁ\Ω}c 'J=IQ "%B؂NѧG.]:yrŁ5N4 bL,Ӧvd6,Xg:N.!ǀ)< 4&d 9|7Yw:-S?_Bɘ4DwZntYB8H^~Ƶ?B {k{r9ṫkY- 1Iw{g>~CkٜU/^VU9Y$U:"=OU #O8y| WE"6:2} +{v6ow~ٽOw\Ž{CkW#yM_HyS+]yp8iv/ m A'>ă?PKgidFTl )AjQHU5 GkPQOwY;] n$} db}o~_?\eK v[6м'73hdr07u/d>i0=MY?v>]փr5UD3ed2KaHˑz^ۥ i3=ȉ˖1& I%#zDEÝxK>{+__ދ#IKo-K EYw??ޯ}'=}_/~oyjN#eLDE12:7PT )to8,ï~&puqTE.DKvUyaA4J)WٓO_9%zl(3)d&oFsԙۯ=r*xb{/_/}]_KδTFX6O>v'YL$$-3Ru#E:W4iZ:U.%% W)y0 .*$0eJH%˕*F;7 Fْ[9f{㏟ ǷJL7/k"\o<)' d\G.Ȅ"U n T't&]:%v'Q s/-lWi⚪4pգ\P.(Ctم Lʢ &x~IFӃaO, h2+g (%Ƀ8)p/%uF;XF8qjf<_9~vuQ-gB,M*rqRy> ?"2#JP(a-0ILviAӘW_+(U0jrH;YRKVg>r42ե;1w~TaH%̹5jxu0pn?tf–yXK.g{c]Li8? 5[o`B[Rk_W#ɕb{dTeVUWWuuncd0f8́.\X,H > `5,!3 1`xlv]jWefeFfb{ˮ2T"cyH+Gza}%dZ_y_)MڎՠYlǣ}u|,x*? @r"9!Eytr `C[f- G|gbC[k mY͍εx Q^Kye C'?$@X@{šW~ERNj:ɳBԣ @okm}?޽wg3# $wI@tLg6a5U%D-DX̛ow\f8tVN#̙`e*hZϸdlzmsݕ"=-"i~ʛ "1۶ҳd)|iRMXeFi3:<TLJh.aR>)Sfi.+!\&!e"*d\sò{tMiZ2% QwZ򋺯jJ'H^B'h Lss?c/omhzQJzG[z@4FA|BωE:!='U.j}fm.9Yk01RsU  ٜpEӣHmr(#$aqN ~ŗi]zxUpk+Nr>{끯5)X%'ۆMlM'tMݰRlG̴>PQՈp @F$.[9.9QGfSSɫoүkݓHrQ/YGWY#;!^DH!r1[Ɛ݈%\Pzo0ڑS3p{}|/7^PZ-] hc=-* 4\ b7pʰXUKZ.ѵ{R8ꖳU(&.띓2zׂٌyUUR!}^D[d{G A~O@ h_u4ַk_W/kl6N+ &>X[QSHBi2K̕ƫoAgh{T%w^ҍ2"w Z[ٟy{~ꇑ ;W/4!(X,اay(lf}JYaʲlib^uu$!:0L,^gY(a$ _eYV+$mۘiF|V+wX7qO_զ)S 4UUUU4M˲h1H "8ʲı,b)ZZF9PEZgW///ɋi.K\FUf8au]_IFyN-I4(0$I*ZiL*MSVoYzfÜEՉZiyaX%ƼD*%I}(3x&z4M,K^Q pzXFeYƅ![ gF,Xˊ("x U]u])Lc8,SUV,VuzsaEɲmH "Q8ɓ$bP)˲nKnjf32(z6aIK``j qV4M)+,uE&IR$ɄuTU],r麮(l۶,ZjvwwIif3PDQgvb2cP(r{x'L=p(e$/ 85( m|7@"(<\zn.<$IUVh4Zyzayw޽{_!G,8^2ƺ1>4Mg^yT$O>l6a`dUUC;"M;!x.:G$I'! znMӜL&(u=۶60N$I-X({$i8Q,BVnTU5Zfp,x^$JDFJz8>N^$!z N]ף(جk .A$ag7$I=>>&$%FQcXdD+Q?cEQaa۶iԌuXN$-R1/xGneQ'LӔ$i4y>V$IeQށeN*s>Y;GiYpC<6 g ÀFnmmQ vE SZFk q<qΣϟ/Kd8mpbyt$@ ܀ @ e_zFXJnۅjPu]7 %=J1߇9,˦d2 #'CI3HRA;IPmGz?cS!D|>o6[[[k`m'/PJȡuH~yD=Iǹr~HP<k @NqZM=99U咚`[Vp@xTp6%Bu#j|>GyABaW(͆w"T5nh)@6Z.TZX") lb|4QdK#S+i4M۶o޼A"e u]g1p8Iii&pn1_-˚f`۶=⫀d8$ xG@R&l\rpm0^|ɪ8)i6j! ^PAgϞ5MIdfJ4yf3jF0kBض-ֽl.G Kk\( Z-EQ&I `8qⅣE bhD7޻\. # ai P43Ba+.EqDz,Nx6: 0 vݷoFQHEubWVKiH%@n2l6k!eEHwQ {5_9((( q7*|̡c4M9ّpSU'P88m<c4aHD,(_~e\zSL 1vp('r,t o40;Hl6(0[8 ,@űmQU, ~?D,|MٴZ$ICQMS~omQN>GNmfzng&HZ}PD8`FwZEqDQAiu6sa!znAQə(  -C-xO nZ'ئ)lrg\≤LQTBgVE+˲PЄJv)q8OӴlTh>/ɜH#S8*z\$(jaDdm23[PZ! uX0 t(JfyuF b sRly: Hr_,nmm]]]!m>XN.W\Q$IvwwWB 08Ieœi )t Y)j^ӹsŏM`CP+u\}AmڤKH\] Irx/)gYAvQQ1,8,EÇ7oPІ1@1($3)>AZJh8m4[Ge9cO%l<Ҳ, y~4D1C$q $u߾}B0@(-\EՖ%rsѰm; C@6N=ϣʏzNU|e7>_g98˚L& ZFD`lmminQjnvG &n6O eYѡIm۞A.{ZV pBe{2*RX,`0(1i7@uV4@Qfʲ nqz.A @Y/..X+iZAL {{[l6`7 $s5py@YSI X,޾}8N$X-MS공% y`@ʥRr}ߗ$9F@x D\Q^z,ĕ86> db۶8 C21 4VI Xhv:,OOO_xdj@TfģFzi4DTt tPI$.ד/cof$i6xp7v(h)0]iS qTgjA\]]iHi7i jFڶt:ꫯpH2\dža;h@ c[,gggZ'K;,׳g \Uq@瘔HCe5Z)Śʪ<GP҇`0:??((b{{[QlX,XfA0MPUv͛Ǐs⺮x 3k tTo> 䄺-6Ɔ!]& BFb,A@2N<# dYF;?LQ<id>e2|锱HԈ0;PB$$I G%Dajz'>}DUeh$InQHJq>G11%h 73Oj*gzʲQb $Wf3ӟ~ < H$t$I,}b97Rc%GGG˗,}8CvvDt ,~޽{?3k3 ILӔ}XR }dd#,߿l6:ψwx]^^FQ9~xxKԼbA,:)^z/F# xa(.Āa| gYl6HM=T+Š0/KjRM[T,XQϟ?  "Y8xX~ժ^ӗVg; exE;d1\Ep8Fw6E`0rq< -WŅeYi: ذcI(8૯ft=(ps D3f@0 rnrUin63YQ}`00 c{{& DQw8&iK)UUʏh>|PȨ`@:0T|j@ָA3$MӆfKt#8 K  c8+̚z=j O7 C=99I!z3XfADb!<} Ð[ iVAX8`gggJ5ވ0lQwڶ<8j%2my)R^amu-Ujz0>`vz0Fg CX,7ĕ [5)Tiu4+}4a.1?/~-Yeq1f&0fk@Y}AbipS ^|jmooF#~ S5j\ "3)p/..- mm=~VM%4 ZX,vkZ^i"<!C޽{4͝~ t<Gv_kP(:@rvvE/9GQ jc. :v2!u~1UT:–t]vcfT(EQ\^^^__O&UU).isF#Z?3 렀ݻwO\ZJߌϧhݩ4q*XF g6 @E}`#.z+jZ|IբEIF?ю )DTQijM0 i@0IGż@Ac:(YGB.u 0ψ7b~ˆx^w:N3P%EQHi|,>P8jj"EZׯ9Q~YM xnZ29K O((r1u`w^w} Ȝ\.'l6F#qGFQ sGTE9==˻U7,i VM"xH{SDc\(,...$><<|1y`r hO4r7i#(2)LGHA/Ac[[[ggg/^`xzyh 07o(!L|*NtKA@,X(oB.p=~fYFfs8GrGO(X< $I08! PSazju h6'.`Fc,T\hy>@C0d< NSf32m["$Dkrz >C^ݘ:o7!hꦉp H@qu߽{>駟ґc X$I=/# 5'f5X77^nL* ˥6N8u0 r0,n@! ť 8?k-(iqNef\BϬCh\# h[i)sTEQt:V3ݹsVh" "*I7 NNN ##|>'B`e׭Uo99y_~ el%I Gnn]NX%U[{*ՍL֊>;??g:rоE Q.ʻpFe/":1rTJuq3t-85~BVݼf=h6E)9ZA*x:"qe`ID2doi]{R]J"%ن`dcoh?s GTs\be͛7̈HO"ի;aZ)b*O,r6}嗘AjZ LEí "2p+^]y<BOj,n.jTZبXʔ`3yG\]<==}W_}P%1%yZQ!D]%89(!WScvM.w\ !3K!3A^R$y_j&ǔx<Eb2j7oǁ0? Ce+gJBQ)c$VL&ZU?Y.իW7`u{{;.҂䃟PI}"0PDBC e%[V]͆[YAh;Рrz* OUju)Ϸ~'u ΅QtZ+fͪ T*4Sjbr6-KY46łL:i`/q^]wU!UI;TIENDB`1968.12.09????.??.??SCGgm#  Q G L $I 1924.02.16????.??.??NEDim $    $1956.08.15????.??.??NED-6mmm7I1911.08.171995.05.05URSgm F F FPNG  IHDRPd IDATx}Iu̬̚4h4lEӳ\8Zh7i__\xCʖ  hbwP]\YUY-U2`U{*x& \7|~FBD" \`0O&B!AF#!NL&0MeAuf3$ >?GXD<G:p8yN8::tn1Fݮ@yBp]XL~·!|X4Ń|`0`0iZMBE1  ZlۆeYp]PhfnHe0 Cd"Ðq`&(>d2A^G @<GP@8&`8:|ߗBNbP(Z4a"" a8Jum8#/y* Bh4EVē'O4 JH`0(D<~0}aD")F qrrdl6B]eaX1,h4(>1B Àp#H@4Ϟ=C:azXXXp8D:,,˂iT*8:: )W͖xT NNBtZ2{Dl6i(J0  yM y,BT:ͦ% N3:h4N#ɒIg<c8""6Zx<.1iɤk"JZNg nh4dveUL `p.F"uNyn0D׃b pDV -B&AٔBϿ|1R"V%fH$"E/jGZyh4Nj8;;t:E$h4пr , fRzy4ôlb:lx<zb6(4 LT1k8;5&(5;өá,,369ax'!1Nj'''H$(bjv|4VVVy!&c.q9$A.$I + 0Nū-BZ7N+_0,d2,dyB@A G 0$ 0t NL&jp=TUt]DQҟrIjUVu]$I2.00NZq]W~v@R iPt u1$1*z8l6&>j&PF:}_\LqKVu]?&2BfFqh4d1˲XJAyp8 0k&ԇ܎! v*:prrP(D"!1(L"!HqYP($0dE1"T x,@K}駨j}pLDj ut:Rs ۶ ulx\²,eONN0%A;MӐfa$u1`Ydg: ߏnŚ 4 \@\BoţG$4Ms.0/$EocG2T1;q5Ix\p` O<.d2m^8rbL/˲ \ׅam+++p]v HRxwl6%RH(8c@ܽ^a  "JIRqX0d0heTUCQi=4 }8n++J&4M tBl+++, NG#J4M1f)2d2IbzB$oܸE8`0$˲8bn$^H$f+f3LS5@H$.x O InۨT*p3ԸnWLr82VVVprrp(h4izl6Dİ*h40MT +++z\c)Nò,l'+ T<*w!^OOb޽{0ժԷtZ=|4Mc˗J`۶euxZ ~_?TPXU?0Mq\zU2,* RŸ#k1H+^a,\zUvplV(н,B4E2 }_-K"d2AD9ɈB Y-B5T&GCGU#v E$ xW%[}|/U ,iJc^Br?L&Fj8NSK AY `E,X,&Y4<{ JEރgxj6z(TJZ8p9DW8f쯪W11y8" H$zs!@zMӤPPKeYD_t:B[F\GGG\ș((OSB!R)QxI 'uU@ I2 W\A:>LlAO7̍=PVITm躎H$"8i34Kj*_.8BdkkkBwyzѨ$0*6DYi}y(sjHW^v'`%=oJ1 lė]s^… ShF mt* l@h0ET?Džѓh4Ic8 .溮"aܼysϷ%KX@QܝcXFrLDw P勨RO11Q;.y'Rd;<<<¯T*EIT1\ɼC\/v[^' A8J$dL&2|U̯4mՋ˯xt$u+++X__(]>=1H$ڌZh_&]988υ&l6F8gQ'蹗 YN;h4F,~3J%XQ=9@蛮]T*8??oue)Te)/{=1B>slB3<}kkk(R0P.cg=df4 t:x>=<|PR:9@NvͦLϰVް*VT žn0D9j^u-Bۓ.B˜r 2dd2)~xE1ɰ Yױ&+&. aհ*T{ T9Z<Ϟ=(2.i=Tk4M|8Q.śaC#\A]*!x._}z!Z޽\.'eH&pΦ__ڑMtmQ):,RժPu^D~\.{UyI-+yOjѣG888G}$CB/{lG?%ˌT*\n2Dun2X_)!ä07C'5Qiz F`|z>/.yj/kaii VK?N ( s)09/ Bc/j9`Y# 0ģ|Z i _djқ9y6.7Uujh4½{`6޽+*-rʕ+(HӰm[fmBL͛7%2Xiݮ7Md0bLf1T7qtt^7g{W_@OD@jtD"7>vww1 ufÇj/mdlQ6höm|GxP$ϱ8GCH$"XJEZuslضerqUJJp/Dѽ=F#7 #i᫯r 4G>ljG8vBM-|w b `·`/JHӒU僠IRq^}U s!8&Re8hwwo_ţG ׮]C6TR loes8??He yj`plE/h toibI<GXĵkװ72-Ed27obaaAsxx \zKKKr ={F!\Sx?OQGɈ1fJEIzw`jf){DqTF$ڠR{4Z ׯ_~](lqN)Y1ömidYJ%ju:I* #NT*ͩV ի"///dIx1Sqa=۝fOv[F:Q9$E%3'? }苋\۶^~Z&{+f%09>SRV [[[*^uEp2wJ,h4B0`0>:nW<0KACj{ʪɲ,ܽ{8±}(ϫ{9HE! jowA"@^$-T*G ~mLy{ 1G3.>>}ƕ+Wdl9%Z0Vk#%TU h4Bד\MӐ籰eypT*Ç~W^yEc"`uubQR.+zҒ_!g&nܸ!B9:0DO<'X]]l&ա# RIA4h4B,BaEH$d3G\zU#ۥxpzzTUd Ǣl1Rh,fFs}8b4G$n߾??ښ;8ĦS8~Νݮ ܼLHpZ[[C"hwyrrFbZM%x<.G"@.óg${ߝN^O$NFB'FB) *6gn( xgɾjf)| $LJ=sHS>|;;;hrYPMve0 ﺮ()tȱ 0ϻ8!!N  bb.U)&ulll`sss&JdA=+xO}hJoF(?.W+|zz-|h4rc,x5 Z-e7},y = O]$~_i?-ldz2{ P,e97;CWWW+޽{rX]] j'''s]swa#[ߺuK:?NfzK۳ ^z] .j4eYakk tZz7BQHy&a08:n޼ f™ '/fcyd\qdh4dmܿ|\ !J͕UTՇdPd\0 dY|ra8,g!(d,i)~z?ǭV "1Z-T*̀/*mc0D, fJTs6IKQNOBzpolۆ(8??GZ>uԆ򕺚IDATFm9Ȉ履~* L&# xmB"ыR|Sq8`6e=wp' \w=sQzxGs d2??q^ |?e{jabd2mM2bK6Oa%E5t䍧ө$f. L"˞:r1C=Ŗ9q/!(J"C(<`p,.ÌLtm쓐Pqw8 {x3T*4Mضz.&,n޼\.'V^Gە 1tKKK"a9}+ti7g Nh6sMu6nHo4!J$gX2\ЬeTw^S(`۶vIZ'`&|1j@r労kլF<)Yd;O#>2_: jjdĖF!K&{jwɄ@%hx9n߾7n J s f9tdG%uJ"18GXHRxEQTi(3q&Nh!^{c#r14:jb̭ܝI<kynʊML6~8w]TPDSuiEQQɄw4u8Jݏ:0`f39nLc8BՅfŵI!hT '''o-i>P0#x߃y280cuuU<`jbb hq+-F(K:a=`&u:AӴI{JEL8hT^<ȊSAfdtCIR W_bɰ5ʺ<<}x54%BXL#-[>3KE4zшc;í|(K Epzz?\pin.:5@2qcܽ{W~`#&,s^I&7O$7ȟ^f@*+<J,TN$S'꘮w~O>_5ɎJg= Z |^j\bT#ULT}'RB!,Π:'F)}%(N3\Yf#$ˆ64WɈB__"Lbss| ݻ|>/}ZAH};R q}_x(+CCp^i(HRF3S(u@nF&ozuqٻヒ ժLkfS+L\o6_^)r$}^"QHPK28x'RU5 QjpjePSs'0Mp_}z-|{C.j<7g}F!nΝ;R5~HQ eRbΥt ͓ף~RԤ4 Ő #X/P_$ xWOOx7dO-jagaUFrPqްZlS,%Oϕ((,h4^"t}uoh<:MRۋQeL,|.`cc?NWM2<ϓFpQbݹsRiQo}ɕsB0ka4ɋT*l ݕ8>0B`C*pfYqkk ryn;֭[i̘ )r0DRL.. 4a~)3*1+s \"^RvX =|Y.ᓤľn+FH$X\\DNͺTZ(O m4&{.\A4MdUq"_B &r2YL!wͦ< C+J48#bɥXW&F?a 0*;uGדikf?UºE^GRA4SZOg [U~El8r99OF} CUȏeb.7'2EVzŰ(=b5'W;:)z3UCUn\$%*Wiz&p8,h<`jB$Fsj#i;s qMӤDdM#]@wYwY qX 6IEVjs`P)!$TgKȝT*X,&F!䃩a" (Ez}Df\."ƶmdY4Mh+Ýz<LseuVeB%4%\.7'[;.#J8v_~)lyEcz1Øf]# ޻ 9"|V5q.1S8 BxՀxC,aq,˂ms\u_|$fV$im7Јx<1X0/$ P,D2z87Û懚9M0`-L&HIYkM{ 1o䗿%NOOej^OSECfc.p88|uiBrم'Qdl]aȀ:?`ϡ!UV"S!+{{{ꫯd;J=kn 𲜥S:TR jYyՂ/>쏨 Q Rfr%Ȭ d".>$Ho[ .ԐlLUT-gw:- ժF 4w4:1K3)[yF gl5MIsKNGlַm&QMP.z+w믿O0KKKRqZiJ7O Z)IENDB`rgm:1950<br>World Champion, 1948-57, 1958-60, 1961-63.<br>1962.11.03????.??.??POLfm&  G G     = = I I T > ? ? ? 6 ; : : : + + + " 'I T1971.12.12????.??.??NEDfm0    . . . . 1 . . . . . . . . . . . . . .1I 11975.07.10????.??.??ARGfm/  . Q L 8 ) 3 B B B B B B B B B B V V0E V1923.04.211987.02.02RUS gm+cgm  ` t  cgm:1966 gm:1984<br>Winner, 7. World Correspondence Ch (1972-78)<br>1947.03.03????.??.??USAfm7 L P J a 8 J Z G J > \ L 4 8 8 .  8I a1952.12.18????.??.??NZLfm   8 8 8 D 8 8 @ @ 7 7 7 7 7     I D1960.06.09????.??.??HUNgm? G        I 1964.06.04????.??.??NORfm%  )   I )1970.01.08????.??.??GER-()I1976.05.04????.??.??DEN-<zxyy=I1953.11.30????.??.??USAim ` =                   I `1965.05.11????.??.??GERfm0 8 ) = L L     - "       1I L1982.06.09????.??.??POLim0C\\a\ + + + V c p s { |1I ????.??.??????.??.??LTU-9~:I1972.07.13????.??.??SLOim!+ 3 Q 8 ` ` o e ~ ) U [ { w \ ^ ^ ^ F = = : D D D F A,I 1977.03.01????.??.??RUS-6|7I1985.04.16????.??.??UKR- >{{ww?I1967.07.15????.??.??BULgm" .      I 1951.11.01????.??.??ARG-0  1E 1936.04.08????.??.??LTU fm+cgm0 ) $  . . $         1I .1960.07.31????.??.??RUS-<=I1969.06.07????.??.??GEOim0   ) . . .  q q t s m m | 1I 1968.06.29????.??.??RUS-0                1I 1972.12.19????.??.??USAim. B  G =   I N G B V Y v | } k g a/I 1966.06.14????.??.??ESP-3 $ yyyxxx4I $1979.08.09????.??.??ESP-67I1987.07.28????.??.??ARM-8  > ` 9I 1988.10.24????.??.??UKR-F GI 1960.08.05????.??.??ISRfm              ) ) " . ? ? ?I ?1954.06.09????.??.??ITAfm-   )        I )1976.07.23????.??.??HUN gm+wgm0 3  # F F F F K s i U n s i u o b ` t w ~ ~ u u y } O PNG  IHDRPd IDATxIH@PU,|-̬f 77U<2"af822\"#27[(`QőQñz_Ua8R`Z5=''\>k.4J>ok<~o:>]㨜zw0 ߎuqM @Jjzjz@a4}Ty`|xcp#%#;@-kLH$ר:n{B#h({êH@B$6DnG4P9 aA]`c;XA@9~'_u_a1]st IC>ģ껖Xt= 3C 0~Be-GrqBlG[J!?#蝿^z~q#FJsǟ@Mo"cP$pyA^dNfW,–gϸ\.pv8b&&|)gSAMglMϙyݡm=AZؚjW1p^s6w5\VcA@7HFI#D^LS9/=^xAt:ET+eI5% %ϙ>u`7?V1+햛NQu;LDhw9~et`JꠣmJ9c5~^4O~!}b7qw-RxеLa"IDILPm!21Ȉ0Lxq#h[H_6IچԵe)ik-N8*f!=1,誂:h5uPt/h_4km1`x@wN>2#P{,M b\h4b-#}Lsr:conv\ |5%+sxIn  ||:h>7tAjs҆$\piD7% -XQ365 F5`֔>h1UǙJZoC?[@"bBJ˙*kՎI(0<<PKqsWW8I% Z%U 񢀵|d~laD.b=ϖ1nWTeA,/>S!g&H1d)!= 4/|A?w"4?\4 ]3=Rqb|2[^0 LgP-nr5{LgKTx=dU>,9@gvLB5r1KHm@@ TrlWmP;ˉi]uE3: [`@ A|k!O'` Uu>zqJ77' "33{ZofƗ3 >kDEv (!<wxC<9z*7LQӗ 󐾏h_RVUg6D I<@ӊ}a)M[6cy2g~~&:É޶他g}3*װh{hJbsGtv\/^|x-6GLdALcbzݶ *$",(wdzJMԷ:?PuAZ}4<-7FmڞPJL |ibA¤O/{:GH~W_,3RQ6 싆ٓW֚|ÈIYs}َksKI>%epYviY0mTMs/?u!; GȧACHF&y)[lrLg)j&lznר0k2rsuݱYE\7@IqR!YY}1L`G$!-(7+_߱Jvi(Mlہ)σ OU-%@Tә;r2hi8оG$$3֛ Z$z&>˛[=֛[N,Lȅ)cK\=39"Ec^pk獌6#o=|,y`xLFF<)Ԁf0O3w Ds J[V0^I?b;m`I &ni6?m TLc6=Rqy1C!?VBRToH-T5^]Ikk ~(J]$ C?c- 1̌!04(5紑8z321ֲ}P--Ih_p2mt6  蘨Yv !LW pԕÊG>BP nVM Y04 WvO8īc02H'2CA(Yll$4ε,fY @Dɐ U`FW!P" مαr(jnGlgj8nm}m@뵔4caPė* zApy/y@yIu;ء(Sb1>Uqdz9ZēK"jӋA}5ס '3+Fc^a톲ރ0b nٚd'^ 4OR 5-w*~ӛ,;?e54ɫ 6לRʼng$QI%N/'-~A KxǔnjqUM4­Iؤc- 2Ѭ\BW`3f=l+ߓ?*έ7LU/@22P] -*UO qHxBGm sϢ޲ۂ3|yeNcI9BJaTKlO$ѓU}-ӢAaT%¬xg"6]I`tJض:J=\۶rdA]U kdl0*jzh?ī7(Zm:QA t~] #]fA@`g[ ]Kص&Gy-J Q [្p.'<я*XU-Eu|}l bB m-T-uyMFn' GJ!{4*31hMOr'TGC΁kKrTIQmYaKffKho 9۴8HfcRfjFѮ}41X;xţm'6wO'ʄ`FP,|th ["lq(ʚhB}Ҏ3yY~kܘ/vnGk*L0d{ֵ#,*x{u۫#hURuOO>"6¾lg L}O ;^'u_O9JnqhZ}14~dysa[꒹QII\59eiY8'nٷ~OH@ck>D0e]]"i`EuKO)ŔᅆeGTU/au=OǦ{  NCM Oz=t;"1z揇Th1]3)E!7d%~fQ7}SG#NNQjP ) JAX☪qvxP F;8W=փCъ^OZOW#k!k1=؍թ $uFb]j4VC*'ݖn<c"h+k"1d$"6)M@glˇn|Wn޳- j񧖨{0pt A[E]Cd M9CCaLd@c3 ^ cۖPJ1+ Z%cfd9Sj5$p/HT qL1*D3Bo }J7t]<`a˂LO,܂@*"qGb97Us8ᶈh@#fJj#X <7AATyPa\>} jCԖ1){4T"T |l"Et}I]EAT K,髒Psl%4(<%|:L8ε@Q;G-$Hu>OӰ HFRx׆ۆ,T@˜,Ioٗ u( OG^ IU9\s2'YbdzUբT>u}'2lv$NA0QG]Y"0} X_brK=wA֝GS? Ȕ]YOmmX!d<߃۳ҖB1}pcٷ|wb3s,| J3S>k Oʌ| Qn1aDyK K&jk1v3|#h3;s0&ܹs@gIB<;J l-(`\7^ݓΞ1Y\rNg)aV 'B֛"*D=l~a[rw͎tp^@'8t<%Q3=R2CJPڰ?6Jct`j{D>Y*ӐPk@^fM_cb:~N :qw(m QB]::3!aא@u5zꝥ2Q|8ƵHHoONOٳ o9i0S=r%mUӏ%lQ˫O_1}]\6d]G_Qg$1z,Ξsz>W`]!+c|ڏ|e:n74) =mœ}S 7(RR9#/}6uDžWTDAk< IDATNcY/ 1ڟ=w7EI??G 'I~?@d%f38}z2A OK.Ӕta &'cwUբR]"A}+˗/ON/޲ɱkx>~ѹr5}uxyѺp2RuK D)_?dJns6g)/ps_:9 rj4`y fKO8ъ}oHzAFD#<·}\\Pq :`pGb}5q A߲}S=m5GXY'%JJ>SC9s.;%7kalϿdq+lmI 77$~Mo$ i죣x*0j0v:P$K\Q7,f3N kH^asߎ4e\`86ص&aBakzRPDo{OѼ F? |?՟ϗ\I=gX3|d`L+ï1GQA`,/s68]ӱ>vWa K y^gHrB٭JN88' ެ2~7=p$ u/R=l$1m;6#Quݑ:wuMV0hm+ggӄO mr6DQۚlBu)_j%LNʧ5F-c=jGUŠ=w `E S+jGukZpՕCC At)-{HW!~\&6duF]4+a~.Y͆!fE9>!/Jrs_1 E &&'(4-anQbx;ŸL->$p+v@JϘem[nnGx\cZ;|丨܎Ҩ00<# 7{ݸFKHE[C2uL4u[=ڹY;%t4Vj:l:0!H=}KUmF>$͞uY[$vf Iȅ|X ]m z7XL 6uwv jzȀM糩Z>]&t AvUItxMnza'ov}Pv|]ے ;N8a1wے3=8ԑV ):xm̌(3d"@*p͓2x[T{YvܸČ` 7ăe?ϾĦ3摡lʦ!]UZX @;|e 6̰xNWw 0gdvT@1h麘Vjv%zf7W;>tQvOy F]yOXAU9YVj\pkKdZI~( YQa+UUb (n8.҄6?XN.Lgs6Q*wg30`Frb{tD}ĵ{PwL8-!%m`oR2 k>)^(C)$ȎuTŞm<qn=B'_ Lxxmm_0],(lՏ(g MG5fXރ]՞vt<4%%k2F\ Vɂ01cxxkyJI%6JH3yd&kUx-)x=! I2aZɄ6Sn7tĦl<Ϲ`hQ-x3@}ϮزkRЪTg3jKQ&@T֢GV#jNaX6SHHn7%YQ[28ehl_C#ain;j-G>ilMݶ`k G-&YAKz&@ =x0=X}cUBRPHxʀ6+ZPy<GX;wxc 2ljR""M`2bOVZv[+#x,ci~=wló6xeېo2~g_ )Ʉz~Leo ðoi𩃎nqxܲᔪR4~S?r؆*تPtF#A5sb:SC(xRWg^(^0H`mX"YIckaHB^H Js[% uBvHT& Bd6Ķm~]!}B1t2CзL|`|kTV =HIM ci*lI„rPO/ JO9w]V69~H$'>͉Mfv3C)ۖUG'Ǎ,zj$8$](vPonXqƽ{?|r+-߭{KOM@9IX+@]UH#GDDlr =u>+yq'ɫ?C?>[ %6(\mvGqv Ec9BK5:a,@"!5&6ܢ-{W7=~|H%۵ú#6ҧc.|ɤ{G#W6I!2۰dd-"+Y_aW\c$ y4;*JZ~}G'|^` Cl^E&5m]0?yF:nd삻߰)57__/S~O|-kI?]wJ$zla|A'J\\._3~:%Bqr6 AAu~WU@(D'C44i<9]e$񰃦Q O-pH5mPA weo>a:_|_gEo߳+J,*q2힬z<|>Jv1t5B4uKu&=ER{OOjHΐDDZ ,ZO> _  Y$A˂44E4gzZs "@ YYٝ|[xx56iVZ)6q<[آE=;@7!bNSd=o\ X_g:PLNp Fkܻ}WcwoW+~L .$mԭ6Nɔ$Ay[wm~sч?cZ$"bYTG,$Y+;‚ԇaж6˅ѱmӠeR!,h=49ѨrGjtSг4'8N[^@ K_ݗɄQHe1^kWy;PO?淇Ovжm!rllX" kslMKj}یu-Hm\FF M8o5qP3N 6">I}ds4ƏGDQ+_d I.wEAnny/&}Ocӆ>< %> d8-`%cPXqG ADIbЕx@fNF^H+)Z|&l J4mGQxE`_+`!D@Z:AΙRQMOr%,rby޸ʋ7wS/?flx n`{{^y>^᛻[ٻqo~;/\aӷȄ Кd>z:no>6.U6:`!>&-$(d"7YEJ( sqvzFkl^FdxE[临&C=>;I,`zj3!H3Eyτ gLLPIǗy7A~>94KQw^Cc)4eQ?jzFU)Y+dU׫Tg3?|ݜ)L''FVB&ńV"a1@sk|.?!3!&)"˛RU E|+Ⱥ8M4ucY;^aHiE"oMѢ닆\8Q'˖8RqLXrjZcQw헍#AwR~מӈn>޷شu,V]Ӌヘg0Vg1XR2!gNH۷<"Ox+L}SzMrmp9MXy &S)(#um,;|2[dR646_ 5xf25"U ),%c1 C/Esʍ?_gϫp6dsM4j*AU=# F/w;^@& `y3\lnp"i\67=Z{dE Z0O$j"Qd OtWP X]tgږ.<.sخ] h]z'-}ɡ2(TvIIjW6uB;$vlz/+t3T6Yk+SNKCNLŠL+:gs ^@t,B9dTzU DX/w\P%t0M=A$p/?! !0fG b# b'$E5Ca,j IV-yhjL)MzyN }2$Aô3"Kq.E໔^4Ȯ! E^J^] qaFƞU}U%VwD׃xh@_jp i>:OsgAgE *la7عT=T\'dEЋIFXd@ }FaLi=d!}]_FF#C3 Ihid6^"V'~^/ʗwD3צyVgrD؎Xxnz6tAY$ (=-W-EvQ/ k@ҧV%(lqUxe5+uXԟ1c,|s Yׂ"3:^vUyVT$.Ddc%7yv>csw}_ѣ1M^R#ꖬnijEӤcTf]i:?>b|0lwEܿ&^tO>qJV5ݢ[Jti>yG3*?0_千%pJ5+ Jz\ eX S9;_cf\o\} 3O5XKhSrA euKV. pJh,iɳ4]xiZEE_-r"g~jf'O͹b8\(ZId.V7˒Ttڮll-NRm B>8Cv3_~c: o>6 " z1YݒXFHR3T-ׯƝl]A$&,fDAGg36n-z՘BW K /sX~_p9 kmbF;?zS8Y G-1J, t!@{@$:|?g8΀-ݼ g`'[cdθ3p>{^yOE: 2!{{wVIDAT(0E+[fs g~zL]Op<*_൯l~ʇ9?Ck0 C4mQ`{!mfhMVİ: ZcloD ;H(+faka[qZyh!/s24PݻN>>\p > > > 4 4 4 4 4 4 4 41I >1961.06.03????.??.??SUIim8 8 Q y e   ~  [ y t y x t p r r w w ~ s d [I ????.??.??????.??.??NORim"  y y ~ (  I 1982.03.05????.??.??GER-5 ' ' '6I '1974.10.06????.??.??GRE-./I1956.03.09????.??.??POLfm!&      'I 1966.05.04????.??.??GERim!  V ~ ~ ~ ~ I chessx-1.0.0/data/sounds/000755 001750 001750 00000000000 12234477214 016043 5ustar00niklasniklas000000 000000 chessx-1.0.0/src/database/wbengine.h000644 001750 001750 00000004071 12223260306 020111 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 William Hoggarth * * (C) 2005-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __WBENGINE_H__ #define __WBENGINE_H__ #include #include #include #include "engine.h" /** @ingroup Feature The WBEngine class provides an interface to a Winboard chess engine. */ class WBEngine : public Engine { Q_OBJECT public: /** Constucts an engine with a given path/command, and log stream */ WBEngine(const QString& name, const QString& command, bool bTestMode, const QString& directory, QTextStream* logStream = NULL); /** Analyses the the given position */ bool startAnalysis(const Board& board, int nv); /** Stops any analysis */ void stopAnalysis(); protected: /** Initialises the winboard protocol */ void protocolStart(); /** Tells the winboard engine to exit */ void protocolEnd(); /** Processes messages from the chess engine */ void processMessage(const QString& message); protected slots: void featureTimeout(); private: /** Processes the feature command */ void feature(const QString& command); /** Processes the "done" feature */ void featureDone(bool done); /** Parses analysis */ void parseAnalysis(const QString& message); /** Instruct version 1 engine to stop pondering */ void v1TurnOffPondering(); Board m_board; bool m_analyze; bool m_setboard; }; #endif // __WBENGINE_H__ chessx-1.0.0/src/database/playerdata.h000644 001750 001750 00000006500 12223260306 020440 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2006 Ejner Borgbjerg * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __PLAYERDATA_H__ #define __PLAYERDATA_H__ #include #include #include #include #include "partialdate.h" /** @ingroup Database The PlayerData class holds information about single player. */ class PlayerData { public: PlayerData(); /** Players date of birth, if it is known. */ PartialDate dateOfBirth() const; void setDateOfBirth(const PartialDate d); PartialDate dateOfDeath() const; void setDateOfDeath(const PartialDate d); QString country() const; void setCountry(const QString s); QString title() const; void setTitle(const QString s); int firstEloListIndex(); void setFirstEloListIndex(const int ix); int lastEloListIndex(); void setLastEloListIndex(const int ix); /** players elo from the given elo list. */ int elo(const int eloList) const; void setElo(const int eloList, const int elo); /** the estimated elo for the player at the elo list with the given index: if the player is not in the list, the closest previous elo list is used if available; else the overall estimate is used. Non-const due to caching. */ int estimatedElo(const int eloListIndex); /** Like estimatedElo(int), but no caching is used. */ int estimatedEloNoCache(const int eloListIndex) const; int peakElo() const; void setPeakElo(const int elo); /** the overall estimated elo for the player */ int estimatedElo() const; void setEstimatedElo(const int elo); QImage photo() const; void setPhoto(const QImage img); QString biography() const; void setBiography(const QString str); void appendToBiography(const QString str); /** returns the elo list data as a QList. Useful for writing the data out to a QDataStream. */ QList eloListData() const; /** sets the elo list data from a QList. Useful for reading in the data from a QDataStream. */ void eloFromListData(const QList eloListData); private: PartialDate m_dateOfBirth; PartialDate m_dateOfDeath; QString m_country; QString m_title; QMap m_elo; // key is elo list index, value is rating for player from the list QMap m_estimatedEloCache; // key is elo list index, value is latest previous rating for player int m_estimatedElo; // for historic players int m_peakElo; // highest elo int m_firstEloListIndex; // index of first elo list where player is represented int m_lastEloListIndex; // index of first elo list where player is represented QImage m_photo; QString m_biography; // html string }; #endif chessx-1.0.0/data/images/000755 001750 001750 00000000000 12234477214 015775 5ustar00niklasniklas000000 000000 chessx-1.0.0/src/database/tags.h000644 001750 001750 00000015044 12223260306 017253 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005 Ejner Borgbjerg * * (C) 2006-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __TAGS_H__ #define __TAGS_H__ #include #include #include #include #include #include #include #include /** @ingroup Core Tags class maps string tags to integers. One instance holds all the tag values used in a game database. Documentation for managing QDataset format version, see http://doc.trolltech.com/4.0/qdatastream.html Some ideas for the file format are borrowed from Scid (see namebase.cpp and tkscid.cpp). @todo - compact(): - Needs access to index file for the games, but for now just create index mapping. - May also clean up unused custom tag id's. - maybe some functions can be optimized with const_iterators or just loops - file may be even smaller by having id/frequency use smaller types when possible. - QByteArray (in Qt4) can perhaps be used for read/write with compression ? */ class Tags { public: /** Construct with given filename. */ Tags(const QString& fname); Tags(); /** Write the tags file. */ void writeFile(); /** Read in tags file. @return true iff succesful. */ bool readFile(); /** Remove the tags file. @return true iff succesful. */ bool removeFile(); /** Remove unused values, saving space. Not implemented yet, it involves also writing to index file. */ void compact(); /** The different kinds of tags cf. http://www.tim-mann.org/Standard or http://www.very-best.de/pgn-spec.htm#8.1 */ enum KnownTagTypes { // mandatory tags Event, Site, Date, Round, PlayerName, Result, // the rest is optional tags // player PlayerTitle, PlayerElo, PlayerUSCF, PlayerNA, PlayerType, //event EventDate, EventSponsor, Section, Stage, Board, //opening Opening, Variation, Subvariation, ECO, NIC, //time/date Time, UTCTime, UTCDate, //time control TimeControl, //starting position SetUp, FEN, //game conclusion Termination, //misc Annotator, Mode, PlyCount, Source }; /** Return the value for the given valueId and tagId. Returns value even if frequency is 0. */ QString value(const uint tagId, const int valueId) const; /** Return the valueId for the given value and tagId. */ int valueId(const uint tagId, const QString& value) const; /** Return the frequency for the given valueId and tagId. */ uint valueFrequency(const uint tagId, const int valueId) const; /** Return a bitvector indicating which valueId's for the given tagId has the given string as a prefix. */ QVector find(const uint tagId, const QString& pattern); /** Return a bitvector indicating which valueId's for the given tagId matches the given regex. */ QVector find(const uint tagId, const QRegExp& pattern); /** Add the value to the value collection for the given tagId. @return new index if it is not there. @return existing index if tag value is already there. In both cases, the frequency for the value is incremented. */ int add(const uint tagId, const QString& value); /** Decrement the frequency of the given value in the value collection for the given tagId. Actual removal of a value can only happen in compact(), and then only if the values frequency is 0. */ void remove(const uint tagId, const int valueId); /** @return Number of different values of the given tagId. Values with 0 frequency are counted as well. */ int count(const uint tagId) const; /** @return true iff tag is known. */ bool isKnown(const uint tagId) const; /** @return true iff tag is known and mandatory. */ bool isKnownMandatory(const uint tagId) const; /** @return true iff tag is known and optional. */ bool isKnownOptional(const uint tagId) const; /** @return true iff tag is custom (user defined). */ bool isCustom(const uint tagId) const; /** Add a custom tag name, and @return its index in tag name collection. If the tag name exists, -1 is returned. */ int defineTag(const QString& tagName); /** Remove a custom tag name. All values for the tag are also deleted. Known tag names can't be removed. @return true iff removal succeeded. */ bool unDefineTag(const QString& tagName); /** The different kinds of tag names. */ enum TagNameType {All, Known, KnownOptional, KnownMandatory, Custom}; /** @return list of tag names. Default is to return all (both known and custom) tag names. */ QStringList tagNames(const TagNameType type = All); /** @return tagId for the given tag name. @return -1 if tagId is undefined. Works both with known and custom tags. */ int tagId(const QString& tagName) const; /** @return tag name for the given tagId. Works both with known and custom tags. */ QString tagName(const uint tagId) const; private: QString m_fname;//filename QDataStream m_tags_ds;//datastream QFile m_tags_file; //file //tag value collections (known as well as custom) QMap , QMap > > > m_allTags; //for maintaining custom tag name definitions QVector m_customTags_v; QMap > m_customTags_m;// is tagId and used flag void clear(); void closeFile(); QVector find(const QString& pattern, QVector& vector, QMap > & map); QVector find(const QRegExp& pattern, QVector& vector, QMap > & map); static int knownTagIndex(const QString& tagName); static uint maxKnownTagIndex(); static uint minKnownTagIndex(); }; #endif chessx-1.0.0/src/database/nag.cpp000644 001750 001750 00000062271 12223260306 017421 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2006 William Hoggarth * * (C) 2006-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "nag.h" QStringList NagSet::g_nagStringListLong; void NagSet::addNag(Nag nag) { if(contains(nag) || nag == NullNag || nag >= NagCount) { return; } if(nag >= MoveNagStart && nag <= MoveNagEnd && nag != ForcedMove && nag != SingularMove) { removeNagRange(MoveNagStart, MoveNagEnd); } if(conditionalRemoveNagRange(nag, EvaluationNagStart, EvaluationNagEnd)) { removeNag(WhiteHasModerateCounterplay); } if(conditionalRemoveNagRange(nag, WhiteHasModerateCounterplay, BlackHasModerateCounterplay)) { removeNagRange(EvaluationNagStart, EvaluationNagEnd); } conditionalRemoveNagRange(nag, BishopNagStart, BishopNagEnd); conditionalRemoveNagRange(nag, OpeningNagStart, OpeningNagEnd); conditionalRemoveNagRange(nag, MiddleGameNagStart, MiddleGameNagEnd); conditionalRemoveNagRange(nag, EndingNagStart, EndingNagEnd); append(nag); } bool NagSet::conditionalRemoveNagRange(Nag nag, Nag start, Nag end) { if(nag >= start && nag <= end) { removeNagRange(start, end); return true; } return false; } void NagSet::removeNag(Nag nag) { if(nag == NullNag) { return; } int index = indexOf(nag); if(index != -1) { remove(index); } } bool NagSet::isMoveNag(Nag nag) { return (nag >= MoveNagStart && nag <= MoveNagEnd); } bool NagSet::isEvalNag(Nag nag) { return (nag >= EvaluationNagStart && nag <= EvaluationNagEnd); } bool NagSet::isOtherNag(Nag nag) { return ((nag < NagCount) && !isEvalNag(nag) && !isMoveNag(nag)); } QString NagSet::toString(unsigned format) const { QString moveNags; QString evaluationNags; QString otherNags; for(int i = 0; i < count(); ++i) { QString strNag; if(at(i) < NagCount) { switch(format) { case Simple: strNag = nagToString(at(i)); break; case PGN: strNag = " $" + QString::number(at(i)); break; case HTML: strNag = nagToStringHTML(at(i)); break; } } if(isMoveNag(at(i))) { moveNags.append(strNag); } else if(isEvalNag(at(i))) { evaluationNags.append(strNag); } else { otherNags.append(strNag); } } return moveNags + evaluationNags + otherNags; } static const QString g_nagStringList[NagCount] = { "", "!", "?", "!!", "??", "!?", "?!", QString::fromUtf8("□"), QString::fromUtf8("□"), "??", "=", "=", "=", QString::fromUtf8("∞"), "+=", "=+", QString::fromUtf8("±"), QString::fromUtf8("∓"), "+-", "-+", "++--", "--++", QString::fromUtf8("⨀"), // Zugzwang QString::fromUtf8("⨀"), // Zugzwang "With slight space advantage", "With slight space advantage", "With moderate space advantage", "With moderate space advantage", "With decisive space advantage", "With decisive space advantage", "With slight development advantage", "With slight development advantage", QString::fromUtf8("⟳"), // "With moderate development advantage" QString::fromUtf8("⟳"), // "With moderate development advantage" "With decisive development advantage", "With decisive development advantage", QString::fromUtf8("→"), // "With initiative" QString::fromUtf8("→"), // "With initiative" "With lasting initiative", "With lasting initiative", QString::fromUtf8("↑"), // "With attack" QString::fromUtf8("↑"), // "With attack" "With insufficient compensation for material deficit", "With insufficient compensation for material deficit", QString::fromUtf8("∞="), QString::fromUtf8("∞="), "With more than adequate compensation for material deficit", "With more than adequate compensation for material deficit", "With slight center control advantage", "With slight center control advantage", "With moderate center control advantage", "With moderate center control advantage", "With decisive center control advantage", "With decisive center control advantage", "With slight kingside control advantage", "With slight kingside control advantage", "With moderate kingside control advantage", "With moderate kingside control advantage", "With decisive kingside control advantage", "With decisive kingside control advantage", "With slight queenside control advantage", "With slight queenside control advantage", "With moderate queenside control advantage", "With moderate queenside control advantage", "With decisive queenside control advantage", "With decisive queenside control advantage", "With vulnerable first rank", "With vulnerable first rank", "With well protected first rank", "With well protected first rank", "With poorly protected king", "With poorly protected king", "With well protected king", "With well protected king", "With poorly placed king", "With poorly placed king", "With well placed king", "With well placed king", "With very weak pawn structure", "With very weak pawn structure", "With moderately weak pawn structure", "With moderately weak pawn structure", "With moderately strong pawn structure", "With moderately strong pawn structure", "With very strong pawn structure", "With very strong pawn structure", "With poor knight placement", "With poor knight placement", "With good knight placement", "With good knight placement", "With poor bishop placement", "With poor bishop placement", "With good bishop placement", "With good bishop placement", "With poor rook placement", "With poor rook placement", "With good rook placement", "With good rook placement", "With poor queen placement", "With poor queen placement", "With good queen placement", "With good queen placement", "With poor piece coordination", "With poor piece coordination", "With good piece coordination", "With good piece coordination", "White played the opening very poorly", "Black played the opening very poorly", "White played the opening poorly", "Black played the opening poorly", "White played the opening well", "Black played the opening well", "White played the opening very well", "Black played the opening very well", "White played the middlegame very poorly", "Black played the middlegame very poorly", "White played the middlegame poorly", "Black played the middlegame poorly", "White played the middlegame well", "Black played the middlegame well", "White played the middlegame very well", "Black played the middlegame very well", "White played the ending very poorly", "Black played the ending very poorly", "White played the ending poorly", "Black played the ending poorly", "White played the ending well", "Black played the ending well", "White played the ending very well", "Black played the ending very well", QString::fromUtf8("⇄"), QString::fromUtf8("⇄"), QString::fromUtf8("⇄"), QString::fromUtf8("⇄"), QString::fromUtf8("⇄"), QString::fromUtf8("⇄"), "Moderate time control pressure", "Moderate time control pressure", QString::fromUtf8("⊕"), // "Severe time control pressure" QString::fromUtf8("⊕"), // "Severe time control pressure" QString::fromUtf8("△"), "Aimed against", QString::fromUtf8("⌓"), // "Better was" "<", // "Worse was" "Equivalent was", "RR", "N", QString::fromUtf8("✕"), // "weak point" QString::fromUtf8("⊥"), // "endgame" QString::fromUtf8("⇔"), // "line" QString::fromUtf8("⇗"), // "diagonal", QString::fromUtf8("☍"), // "pair of bishops" QString::fromUtf8("☍"), // "pair of bishops" QString::fromUtf8("❐"), // "bishops of opposite color" QString::fromUtf8("▞"), // "bishops of the same color" 0, 0, 0, 0, 0, 0, // 160 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200 "#" }; void NagSet::InitNagStringListLong() { g_nagStringListLong << "" << tr("Good Move") << tr("Poor Move") << tr("Very good Move") << tr("Blunder") << tr("Speculative Move") << tr("Dubious Move") << tr("Only Move") << tr("Only Move") << tr("Blunder") << tr("Equal") << tr("Equal") << tr("Equal") << tr("Unclear") << tr("White has slight advantage") << tr("Black has slight advantage") << tr("White has moderate advantage") << tr("Black has moderate advantage") << tr("White has decisive advantage") << tr("Black has decisive advantage") << tr("White has crushing advantage") << tr("Black has crushing advantage") << tr("Zugzwang") << tr("Zugzwang") << tr("With slight space advantage") << tr("With slight space advantage") << tr("With moderate space advantage") << tr("With moderate space advantage") << tr("With decisive space advantage") << tr("With decisive space advantage") << tr("With slight development advantage") << tr("With slight development advantage") << tr("With moderate development advantage") << tr("With moderate development advantage") << tr("With decisive development advantage") << tr("With decisive development advantage") << tr("With initiative") << tr("With initiative") << tr("With lasting initiative") << tr("With lasting initiative") << tr("With attack") << tr("With attack") << tr("With insufficient compensation for material deficit") << tr("With insufficient compensation for material deficit") << tr("With compensation") << tr("With compensation") << tr("With more than adequate compensation for material deficit") << tr("With more than adequate compensation for material deficit") << tr("With slight center control advantage") << tr("With slight center control advantage") << tr("With moderate center control advantage") << tr("With moderate center control advantage") << tr("With decisive center control advantage") << tr("With decisive center control advantage") << tr("With slight kingside control advantage") << tr("With slight kingside control advantage") << tr("With moderate kingside control advantage") << tr("With moderate kingside control advantage") << tr("With decisive kingside control advantage") << tr("With decisive kingside control advantage") << tr("With slight queenside control advantage") << tr("With slight queenside control advantage") << tr("With moderate queenside control advantage") << tr("With moderate queenside control advantage") << tr("With decisive queenside control advantage") << tr("With decisive queenside control advantage") << tr("With vulnerable first rank") << tr("With vulnerable first rank") << tr("With well protected first rank") << tr("With well protected first rank") << tr("With poorly protected king") << tr("With poorly protected king") << tr("With well protected king") << tr("With well protected king") << tr("With poorly placed king") << tr("With poorly placed king") << tr("With well placed king") << tr("With well placed king") << tr("With very weak pawn structure") << tr("With very weak pawn structure") << tr("With moderately weak pawn structure") << tr("With moderately weak pawn structure") << tr("With moderately strong pawn structure") << tr("With moderately strong pawn structure") << tr("With very strong pawn structure") << tr("With very strong pawn structure") << tr("With poor knight placement") << tr("With poor knight placement") << tr("With good knight placement") << tr("With good knight placement") << tr("With poor bishop placement") << tr("With poor bishop placement") << tr("With good bishop placement") << tr("With good bishop placement") << tr("With poor rook placement") << tr("With poor rook placement") << tr("With good rook placement") << tr("With good rook placement") << tr("With poor queen placement") << tr("With poor queen placement") << tr("With good queen placement") << tr("With good queen placement") << tr("With poor piece coordination") << tr("With poor piece coordination") << tr("With good piece coordination") << tr("With good piece coordination") << tr("White played the opening very poorly") << tr("Black played the opening very poorly") << tr("White played the opening poorly") << tr("Black played the opening poorly") << tr("White played the opening well") << tr("Black played the opening well") << tr("White played the opening very well") << tr("Black played the opening very well") << tr("White played the middlegame very poorly") << tr("Black played the middlegame very poorly") << tr("White played the middlegame poorly") << tr("Black played the middlegame poorly") << tr("White played the middlegame well") << tr("Black played the middlegame well") << tr("White played the middlegame very well") << tr("Black played the middlegame very well") << tr("White played the ending very poorly") << tr("Black played the ending very poorly") << tr("White played the ending poorly") << tr("Black played the ending poorly") << tr("White played the ending well") << tr("Black played the ending well") << tr("White played the ending very well") << tr("Black played the ending very well") << tr("With counterplay") << tr("With counterplay") << tr("With counterplay") << tr("With counterplay") << tr("With counterplay") << tr("With counterplay") << tr("Moderate time control pressure") << tr("Moderate time control pressure") << tr("Severe time control pressure") << tr("Severe time control pressure") << tr("With the idea") << tr("Aimed against") << tr("Better was") << tr("Worse was") << tr("Equivalent was") << tr("RR") << tr("N") << tr("Weak point") << tr("Endgame") << tr("Line") << tr("Diagonal") << tr("Pair of bishops") << tr("Pair of bishops") << tr("Bishops of opposite color") << tr("Bishops of the same color") << "" << "" << "" << "" << "" << "" << // 160 "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << //180 "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << "" << //200 tr("Diagram"); } static const QString g_nagStringListHTML[NagCount] = { "", "!", "?", "!!", "??", "!?", "?!", QString::fromUtf8("□"), QString::fromUtf8("□"), "??", "=", "=", "=", "∝", "+=", "=+", "±", QString::fromUtf8("∓"), "+-", "-+", "++--", "--++", "Θ", // Zugzwang "Θ", // Zugzwang "With slight space advantage", "With slight space advantage", "With moderate space advantage", "With moderate space advantage", "With decisive space advantage", "With decisive space advantage", "With slight development advantage", "With slight development advantage", QString::fromUtf8("⟳"), // "With moderate development advantage" QString::fromUtf8("⟳"), // "With moderate development advantage" "With decisive development advantage", "With decisive development advantage", "→", // "With initiative" "→", // "With initiative" "With lasting initiative", "With lasting initiative", "↑", // "With attack" "↑", // "With attack" "With insufficient compensation for material deficit", "With insufficient compensation for material deficit", "∝=", "∝=", "With more than adequate compensation for material deficit", "With more than adequate compensation for material deficit", "With slight center control advantage", "With slight center control advantage", "With moderate center control advantage", "With moderate center control advantage", "With decisive center control advantage", "With decisive center control advantage", "With slight kingside control advantage", "With slight kingside control advantage", "With moderate kingside control advantage", "With moderate kingside control advantage", "With decisive kingside control advantage", "With decisive kingside control advantage", "With slight queenside control advantage", "With slight queenside control advantage", "With moderate queenside control advantage", "With moderate queenside control advantage", "With decisive queenside control advantage", "With decisive queenside control advantage", "With vulnerable first rank", "With vulnerable first rank", "With well protected first rank", "With well protected first rank", "With poorly protected king", "With poorly protected king", "With well protected king", "With well protected king", "With poorly placed king", "With poorly placed king", "With well placed king", "With well placed king", "With very weak pawn structure", "With very weak pawn structure", "With moderately weak pawn structure", "With moderately weak pawn structure", "With moderately strong pawn structure", "With moderately strong pawn structure", "With very strong pawn structure", "With very strong pawn structure", "With poor knight placement", "With poor knight placement", "With good knight placement", "With good knight placement", "With poor bishop placement", "With poor bishop placement", "With good bishop placement", "With good bishop placement", "With poor rook placement", "With poor rook placement", "With good rook placement", "With good rook placement", "With poor queen placement", "With poor queen placement", "With good queen placement", "With good queen placement", "With poor piece coordination", "With poor piece coordination", "With good piece coordination", "With good piece coordination", "White played the opening very poorly", "Black played the opening very poorly", "White played the opening poorly", "Black played the opening poorly", "White played the opening well", "Black played the opening well", "White played the opening very well", "Black played the opening very well", "White played the middlegame very poorly", "Black played the middlegame very poorly", "White played the middlegame poorly", "Black played the middlegame poorly", "White played the middlegame well", "Black played the middlegame well", "White played the middlegame very well", "Black played the middlegame very well", "White played the ending very poorly", "Black played the ending very poorly", "White played the ending poorly", "Black played the ending poorly", "White played the ending well", "Black played the ending well", "White played the ending very well", "Black played the ending very well", QString::fromUtf8("⇄"), QString::fromUtf8("⇄"), QString::fromUtf8("⇄"), QString::fromUtf8("⇄"), QString::fromUtf8("⇄"), QString::fromUtf8("⇄"), "Moderate time control pressure", "Moderate time control pressure", "⊕", // "Severe time control pressure" "⊕", // "Severe time control pressure" "Δ", "Aimed against", ">", // "Better was" "<", // "Worse was" "Equivalent was", "RR", "N", "x", // "weak point" QString::fromUtf8("⊥"), // "endgame" "⇔", // "line" QString::fromUtf8("⇗"), // "diagonal", QString::fromUtf8("☍"), // "pair of bishops" QString::fromUtf8("☍"), // "pair of bishops" QString::fromUtf8("❐"), // "bishops of opposite color" QString::fromUtf8("▞"), // "bishops of the same color" 0, 0, 0, 0, 0, 0, // 160 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200 "" // Diagram is displayed graphically in HTML }; const QString& NagSet::nagToString(Nag nag) { return g_nagStringList[nag]; } const QString& NagSet::nagToStringHTML(Nag nag) { return g_nagStringListHTML[nag]; } QString NagSet::nagToMenuString(Nag nag) { if(NagSet::g_nagStringListLong.count() == 0) { InitNagStringListLong(); } if(g_nagStringList[nag].length() <= 2) { return QString("%1 (%2)").arg(g_nagStringList[nag]).arg(g_nagStringListLong[nag]); } else { return NagSet::nagToString(nag); } } Nag NagSet::fromString(const QString &nag) { for(int i = 1; i < NagCount; ++i) if(g_nagStringList[i] == nag) { return Nag(i); } return NullNag; } int NagSet::prefixCount(const QString &nag) { QSet matches; for(int i = 1; i < NagCount; ++i) if(g_nagStringList[i].startsWith(nag)) { matches.insert(g_nagStringList[i]); } return matches.count(); } void NagSet::removeNagRange(Nag from, Nag to) { for(int i = count() - 1; i >= 0; i--) if(at(i) >= from && at(i) <= to) { remove(i); } } chessx-1.0.0/data/images/close_board.png000644 001750 001750 00000021016 12142244753 020755 0ustar00niklasniklas000000 000000 PNG  IHDR;< CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs  tIME1aјLIDAThyV}?]wٙf@%ʢ,FkQsbIL$$xќ朶AcS4fkM9Dd@ I!UAdf}}~2phP駟Ν;:t}(% DIEH JD $2ߤDJ#g 5Zk֠9mcvw6 BhZ nݺu/~?*a`DJiHW!W* % @*2ϕHٻwCˀB-Byʕ]+VАfQJy@RdS8*fRF)R#G=Apg6!t _eur9P("OuB ƬS9F)sa5e ,(Z+V(Z58:hbqP>cl6\ qÆdǡ^EGΞ=[ ҊBŢjYTŇhCMEDTU!Pe,\5oA"QVxFF+iTh@ =X,~\,pȑ^chhbh=U|mC i3mJksh#s1ULêX"D#`s1{h_Ebj'\( /ְaQc'uBY"d *juĪ A+"X1EA6ICw`y^qQ,/0Z7^pȒJʐE06N:↪ـ su( 0J 1%C:لơF;4X]΢EdQ鄊!BKOe7ha)+Br(Δ"hYgOw0m"e&t@iZۀemڴPKR*NSTdJlOvuq)ܚ2u+n 7UTo-7^?iW\݇,AEl>lZ˾RJn*"C5xC)AIczy9wϙÜ'qn<, a搓\ɫ3f0kXVTpwSܷW\LP,Wt"݈LOA,1v, ˙ ]0:ԡ{?e㗾ļqh Q}eGGwuQw8= -|3ϝ+aD )a@^8RqypuU^Ƽ"Rd,XǍn.>ʜrffDVC8J)p`*^ڣ=RgT؍p B>O;mmT67+G'sRܓx)eVUIRvٳe r`'?5 )ӃUUETw64lhMgӢE91ϹLG28>?srH?SNnܘ(9DC&TS2ft"F6 P0)wXĪ'9}T#0mc>o(_XŋYQA[@O]?f62=- }ձmMCcBt>Ŏ^b_g'vs3ޟ w\?woBWuGr{6ܜFΫ_27.EzhzaV1sEf/lS۞z[&)+ rH%Up=u6UӦ1k_Cض1CDQpjhhx®X"+TX5'/zi|& 8^(++P,"믧w#w.ζ|hև"bÂOa*nzYR}L} L&h8E%R)b Vid=8@ۂ:кuW]e{JtxV6KՇ?̙ݻ);z˄`"ޞP4}Z P}5LX/ )MhM1^Hx(m1a7n$eLE(leT_}5 j|3+ 1f ֩Sxdz_L{;X*!̆1\B6QG(?N۬Y>жmdM3*2j8{7}͸ŋ)kk8EF{kbN_m'Oһ};IX/d 0Jpv' ߼ٳ 4F "f('p]e3a'7=^ɽ{㣤I0FH쳼sIh!8babWTmJ!=ϣrΝ?O}E7_wow(Z[Ud+F$IvWD `7ꯘ7y2ݻcS|Ȱ~G2l;FXN6oFKo[Z:fKRI:%YWLOK0za5/=3'L` ;w^K۲2,Av5~ϲ9qƛowec%00N2SSJ7؈eS1֢|y6?3McѳmJmUX)og:~<1{bW˦.Ji-ދSRM̝9)Z2a !ރir]3Yǎ%YtKPhM_ 2,{ט7o߼=quKfAbΧ?<מ:U[5aRʪ$vV`m1kü%m ui qؿ:/0O'g&H.+|UI>WŻg+W ^*`D&CuE8, 庌t]%pmAJf?`ٳ.INjI=(SEv/_K1cctaR7ͼymaa/gX۔⦞DQ%i/RzZ",Y ԡ!/IF5PW]B…t-[ƶ+Φ~,8~ Z**,tf$UTꋹ1Fg$k F45y*ʕFkmml>}>! uvu瘞χ ijVt%lѨ绻1dmogcw7 o`e\rѝ--z;8ԍQ~qUFKqc|NRY Д.\_wɓ?hU}=l|]?: Dƍ7Fȑl޷0)8S{rX+) %EkQJY&ﻏܸ~zﺋI} T65aM#GW]ŕKbn*գ Աl޹mSdrR64Leضc/ʑRtcX_:)"2Ne7TOŠ.\Hل RthNCLR>lA 4jFԱiVzSC#FtvOm|SaI4 ]2+Pvb[ke2\Y_2x-UcPd]TΝ˕-IwKnȰq嵆z֏^㜔ԌtTLOgOWWsNX9鰽/jlI|H&G1lƔě2Vguϓ?;)SX};spn7MIYG@:^f5_Ng$go*k6(dRM.&!PJQ__3fLsGg30ee |.IWZKcKϳvwu!<۷Su \c-Iwe Kڃ7OTSի3f= ;~kj8&cJɤ\zKJ$EZgׯ_+;sq~"Lɤ}xc=ݯК/~hؠ'7tSUZC EH*PLʓS gBj]<[8O}}=3g{:ڹ뮻N,[Q2&.u)c%, (I|&=̙|E)2S1d[[ҧ% 8֚Jd2vu%{7yGEimƸ+56Q.K_ٰ>eosRAR3 MYI[aD *:;;EKkmll|곟̠: J -Cچ7E]j2 ;wI8:۱q1qDk'>v-gnylj͈9ScEΘ1#n^)=~7q>TדhooWGm{!DϚ5ϷlˏqGO?0aBYH+}.ʥyJ3FhS+|8`>c6L&L6۴i`.׿~0 p껻(yG˫tpyci!]SE$Gʊt_1okժUۄ1O}u֭Q(( :Z u:8娪zgܹ>SDž4?À3f̘/ǩB>JJy:,;|oV9TSp8aP~^tIENDB`chessx-1.0.0/src/database/filtermodel.cpp000644 001750 001750 00000011323 12223260306 021152 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2007 Marius Roets * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "database.h" #include "filtermodel.h" #include FilterModel::FilterModel(Filter* filter, QObject* parent) : QAbstractItemModel(parent), m_filter(filter), m_gameIndex(-1) { m_columnNames << tr("Nr") << tr("White") << tr("WhiteElo") << tr("Black") << tr("BlackElo") << tr("Event") << tr("Site") << tr("Round") << tr("Date") << tr("Result") << tr("ECO") << tr("Moves"); m_columnTags << "Nr" << TagNameWhite << TagNameWhiteElo << TagNameBlack << TagNameBlackElo << TagNameEvent << TagNameSite << TagNameRound << TagNameDate << TagNameResult << TagNameECO << "Length"; m_game = new Game; } FilterModel::~FilterModel() { delete m_game; } int FilterModel::rowCount(const QModelIndex& index) const { if(index.isValid()) { return 0; } return m_filter->count(); } int FilterModel::columnCount(const QModelIndex&) const { return m_columnNames.count(); } QVariant FilterModel::data(const QModelIndex &index, int role) const { if(index.isValid() && index.row() < m_filter->count()) { int i = m_filter->indexToGame(index.row()); if(i != -1) { if(i != m_gameIndex) { // rico: it would perhaps be better to read here only header information that is // currently used and not the whole header information. m_filter->database()->lock(); m_filter->database()->loadGameHeaders(i, *m_game); m_filter->database()->unlock(); m_gameIndex = i; } if(role == Qt::DisplayRole) { if(index.column() == 0) { return i + 1; } else { QString tag = m_game->tag(m_columnTags.at(index.column())); if(tag == "?") { tag.clear(); } return tag; } } else if(role == Qt::FontRole) { if(m_filter->database()->deleted(i)) { QFont font; font.setStrikeOut(true); return font; } } else if(role == Qt::ForegroundRole) { if(!m_filter->database()->getValidFlag(i)) { QVariant v = QColor(Qt::red); return v; } QVariant v = QColor(Qt::black); return v; } } } return QVariant(); } QVariant FilterModel::headerData(int section, Qt::Orientation orientation, int role) const { if(role != Qt::DisplayRole) { return QVariant(); } if(orientation == Qt::Horizontal) { return QString("%1").arg(m_columnNames.at(section)); } else { return QString("%1").arg(section); } } Qt::ItemFlags FilterModel::flags(const QModelIndex &index) const { Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index); if(index.isValid()) { return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags | Qt::ItemIsSelectable; } else { return Qt::ItemIsDropEnabled | defaultFlags | Qt::ItemIsSelectable; } } QModelIndex FilterModel::index(int row, int column, const QModelIndex& parent) const { if(parent.isValid()) { return QModelIndex(); } return createIndex(row, column, (void*) 0); } void FilterModel::setFilter(Filter* filter) { beginResetModel(); m_filter = filter; m_gameIndex = -1; endResetModel(); } Filter* FilterModel::filter() { return m_filter; } chessx-1.0.0/data/help/about3.html000644 001750 001750 00000042015 12053740347 017544 0ustar00niklasniklas000000 000000 ChessX Copyright Info

ChessX License


GNU GENERAL PUBLIC LICENSE

Version 2, June 1991

Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA

Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

Preamble

The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.

For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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.

We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.

Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.

Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.

The precise terms and conditions for copying, distribution and modification follow.

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.

1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.

You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:

a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.

In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:

a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.

4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.

6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.

7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.

9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.

10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.

NO WARRANTY

11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.

12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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.

END OF TERMS AND CONDITIONS

chessx-1.0.0/src/database/move.h000644 001750 001750 00000036267 12224733130 017276 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005 William Hoggarth * * (C) 2005-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __MOVE_H__ #define __MOVE_H__ #include "common.h" class BitBoard; /** @ingroup Core Moves are dependent on current position, (remembers piece, check, capture etc) and don't make much sense when considered without a Board. However, you can create a move with only a source and destination square, Such moves are considered "illegal", but can be convenient when dealing with move entry. @todo Clean or merge setPromotionPiece() and setPromoted() functions. When setting move from scratch (e. g. in @ref Shredder class), setPromotionPiece() fails probably because isPromotion() returns @p false . */ class Move { public: /** Default constructor, creates an empty (illegal) move */ Move(); /** Move entry constructor, untested (illegal) move with only from, and to squares set */ Move(const Square from, const Square to); /** Set promotion piece. Default promotion is to Queen, use this to change piece afterward */ void setPromotionPiece(PieceType type); /** Set type of piece (Queen, Rook, Bishop, Knight, Pawn) pawn promoted to */ void setPromoted(const uchar p); // Query /** return Square piece sits on after move */ Square to() const; /** return Square piece sat on before move */ Square from() const; /** return Square where rook is placed after castling */ Square castlingRookTo() const; /** return Square when en-passant is captured. Undefined if there is no en-passant. */ Square enPassantSquare() const; /** return Square where rook was placed before castling */ Square castlingRookFrom() const; /** Convert to algebraic notation (e2e4, g8f6 etc.) */ QString toAlgebraic() const; /** Get the piece type moving -- note, returns Pawn, QUEEN, etc.. not colorized */ Piece pieceMoved() const; /** Piece captured from the opponent by this move */ Piece capturedPiece() const; /** If move is promotion, get promotion piece. Result is undefined if there is no promotion */ Piece promotedPiece() const; /** Check whether a given move is a null move ( an illegal move by the king to its own square ) often used as a placeholder in ebooks */ bool isNullMove() const; /** Check whether move is special (promotion, castling, en passant */ bool isSpecial() const; /** Check whether move is a promotion */ bool isPromotion() const; /** Check whether move is a castling */ bool isCastling() const; /** Check whether the move is a pawn double advance */ bool isDoubleAdvance() const; /** Check whether move is an en passant */ bool isEnPassant() const; /** Check if move is completely legal in the context it was created */ bool isLegal() const; /** Return true if this move was made by given color */ bool operator==(const Color& color) const; /** Return true if this move was NOT made by given color */ bool operator!=(const Color& color) const; /** Return true if this move was made by given piece */ bool operator==(const Piece& p) const; /** Return true if this move was NOT made by given piece */ bool operator!=(const Piece& p) const; /** Moves are considered the same, only if they match exactly */ friend bool operator==(const Move& m1, const Move& m2); /** Required for keeping moves in some map-like structures */ friend bool operator<(const Move& m1, const Move& m2); friend class BitBoard; private: static const quint64 CASTLE = 9; static const quint64 TWOFORWARD = 22; static const quint64 PROMOTE = 38; static const quint64 ENPASSANT = 14; static const quint64 CASTLINGBIT = 1 << 15; static const quint64 TWOFORWARDBIT = 1 << 16; static const quint64 PROMOTEBIT = 1 << 17; static const quint64 ENPASSANTBIT = 1 << 21; static const quint64 LEGALITYBIT = 1 << 31; static const quint64 SPECIALBITS = CASTLINGBIT | TWOFORWARDBIT | PROMOTEBIT | ENPASSANTBIT; static const quint64 PTCLEAR = ~(7 << 12); static const quint64 CAPCLEAR = ~(7 << 18); static const quint64 PROCLEAR = ~((7 << 22) | PROMOTEBIT); static const quint64 BLACKTM = 1 << 26; /** Set Pawn move of one forward */ void genOneForward(unsigned int from, unsigned int to); /** Set two-squares forward move of Pawn */ void genTwoForward(unsigned int from, unsigned int to); /** Set pawn promotion move to given Piecetype */ void genPromote(unsigned int from, unsigned int to, unsigned int type); /** Set pawn capture and promotion, promote to piece type, capturing type */ void genCapturePromote(unsigned int from, unsigned int to, unsigned int type, unsigned int captured); /** Set pawn en passant capture of opponent pawn */ void genEnPassant(unsigned int from, unsigned int to); /** Set simple pawn move with capture of piece type */ void genPawnMove(unsigned int from, unsigned int to, unsigned int captured); /** Set knight move, capturing piece type */ void genKnightMove(unsigned int from, unsigned int to, unsigned int captured); /** Set bishop move, capturing piece type */ void genBishopMove(unsigned int from, unsigned int to, unsigned int captured); /** Set rook move, capturing piece type */ void genRookMove(unsigned int from, unsigned int to, unsigned int captured); /** Set queen move, capturing piece type */ void genQueenMove(unsigned int from, unsigned int to, unsigned int captured); /** Set king move, capturing piece type */ void genKingMove(unsigned int from, unsigned int to, unsigned int captured); /** Set castling short move for White with king and rook */ void genWhiteOO(); /** Set castling long move for White with king and rook */ void genWhiteOOO(); /** Set castling short move for Black with king and rook */ void genBlackOO(); /** Set castling long move for Black with king and rook */ void genBlackOOO(); /** Mark this move as validated and fully legal in position */ void setLegalMove(); /** Set source square for this move */ void setFrom(Square from); /** Set destination square for this move */ void setTo(Square to); /** Mark this move as being made by the Black side */ void setBlack(); /** Return piece type of promoted piece (or 0 if none) */ unsigned int promoted() const; /** Set type of piece (Queen, Rook, Bishop, Knight, Pawn) making move */ void setPieceType(const uchar p); /** Set type of piece (Queen, Rook, Bishop, Knight, Pawn) captured */ void setCaptureType(const uchar p); /** Mark this move as an initial pawn move of 2 squares */ void setTwoForward(); /** Mark this move capturing a pawn en passant */ void setEnPassant(); /** Mark this move as giving check */ void setCheck(); /** Mark this move as giving checkmate */ void setMate(); /** Return pawn2forward, castle or piece type for doMove() and undoMove() */ unsigned int action() const; /** Return captured piece or En passant for doMove() and undoMove() */ unsigned int removal() const; /** Return piece type of captured piece (or 0 if none) */ unsigned int capturedType() const; // The move definition 'm' bitfield layout: // 00000000 00000000 00000000 00111111 = from square = bits 1-6 // 00000000 00000000 00001111 11000000 = to square = bits 7-12 // 00000000 00000000 01110000 00000000 = piece type = bits 13-15 // 00000000 00000000 10000000 00000000 = castle = bit 16 // 00000000 00000001 00000000 00000000 = pawn 2 forward = bit 17 // 00000000 00000010 00000000 00000000 = promotion = bit 18 // 00000000 00011100 00000000 00000000 = capture piece = bits 19-21 // 00000000 00100000 00000000 00000000 = en passant = bit 22 // 00000001 11000000 00000000 00000000 = promotion piece = bits 23-25 // 00000010 00000000 00000000 00000000 = Extra data set = bits 26 // NOT YET IMPLEMENTED // 00000100 00000000 00000000 00000000 = White=0,Black=1 = bit 27 // 00001000 00000000 00000000 00000000 = SAN needs file = bit 28 // NOT YET IMPLEMENTED // 00010000 00000000 00000000 00000000 = SAN needs rank = bit 29 // NOT YET IMPLEMENTED // 00100000 00000000 00000000 00000000 = gives mate? = bit 30 // NOT YET IMPLEMENTED // 01000000 00000000 00000000 00000000 = gives check? = bit 31 // NOT YET IMPLEMENTED // 10000000 00000000 00000000 00000000 = legality status = bit 32 unsigned int m; // The undo definition 'u' bitfield layout: // 00000000 11111111 = half move clock = bits 1-8 // 00001111 00000000 = castling rights = bits 8-12 // 11110000 00000000 = previous ep file = bits 13-16 unsigned short u; }; // return true if a null move // that is moving a king to its same square // while it is not legal it is often used // to annotate ideas inline bool Move::isNullMove() const { if(from() == to()) { Piece p = pieceMoved(); PieceType pt = pieceType(p); if(pt == King) { return true; } } return false; } inline void Move::setPromotionPiece(PieceType type) { m &= ~(7 << 22); m |= ((unsigned int) type & 7) << 22; } inline Square Move::from() const { return m & 63; } inline Square Move::to() const { return (m >> 6) & 63; } inline Move::Move() : m(0), u(0) {} inline Move::Move(const Square from, const Square to) : m(from | (to << 6)), u(0) {} inline Square Move::castlingRookFrom() const { return (to() % 8 == 2) ? to() - 2 : to() + 1; } inline Square Move::castlingRookTo() const { return (from() + to()) / 2; } inline QString Move::toAlgebraic() const { if(!isLegal()) { return QString("?"); } QString alg; alg += QChar('a' + from() % 8); alg += QChar('1' + from() / 8); alg += QChar('a' + to() % 8); alg += QChar('1' + to() / 8); if (isPromotion()) { alg += QChar('='); alg += "XKQRBNPKQRBNP"[promotedPiece()]; } return alg; } inline Square Move::enPassantSquare() const { return from() > 31 ? to() - 8 : to() + 8; } inline Piece Move::pieceMoved() const { return Piece((7 & (m >> 12)) + (m & BLACKTM ? 6 : 0)); } inline Piece Move::capturedPiece() const { uchar p = (m >> 18) & 7; if(p == 0) { return Piece(0); } return Piece(p + (m & BLACKTM ? 0 : 6)); } inline Piece Move::promotedPiece() const { return Piece((7 & (m >> 22)) + (m & BLACKTM ? 6 : 0)); } inline bool Move::isSpecial() const { return m & SPECIALBITS; } inline bool Move::isPromotion() const { return m & PROMOTEBIT; } inline bool Move::isCastling() const { return m & CASTLINGBIT; } inline bool Move::isDoubleAdvance() const { return m & TWOFORWARDBIT; } inline bool Move::isEnPassant() const { return m & ENPASSANTBIT; } inline bool Move::isLegal() const { return m & LEGALITYBIT; } inline void Move::genOneForward(unsigned int from, unsigned int to) { m = from | (to << 6) | (Pawn << 12); } inline void Move::genTwoForward(unsigned int from, unsigned int to) { m = from | (to << 6) | (Pawn << 12) | (1 << 16); } inline void Move::genPromote(unsigned int from, unsigned int to, unsigned int type) { m = from | (to << 6) | (Pawn << 12) | (type << 22) | (1 << 17); } inline void Move::genCapturePromote(unsigned int from, unsigned int to, unsigned int type, unsigned int captured) { m = from | (to << 6) | (Pawn << 12) | (captured << 18) | (type << 22) | (1 << 17); } inline void Move::genEnPassant(unsigned int from, unsigned int to) { m = from | (to << 6) | (Pawn << 12) | (Pawn << 18) | (1 << 21); } inline void Move::genPawnMove(unsigned int from, unsigned int to, unsigned int captured) { m = from | (to << 6) | (Pawn << 12) | (captured << 18); } inline void Move::genKnightMove(unsigned int from, unsigned int to, unsigned int captured) { m = from | (to << 6) | (Knight << 12) | (captured << 18); } inline void Move::genBishopMove(unsigned int from, unsigned int to, unsigned int captured) { m = from | (to << 6) | (Bishop << 12) | (captured << 18); } inline void Move::genRookMove(unsigned int from, unsigned int to, unsigned int captured) { m = from | (to << 6) | (Rook << 12) | (captured << 18); } inline void Move::genQueenMove(unsigned int from, unsigned int to, unsigned int captured) { m = from | (to << 6) | (Queen << 12) | (captured << 18); } inline void Move::genKingMove(unsigned int from, unsigned int to, unsigned int captured) { m = from | (to << 6) | (King << 12) | (captured << 18); } inline void Move::genWhiteOO() { m = 4 | (6 << 6) | (King << 12) | (1 << 15); } inline void Move::genWhiteOOO() { m = 4 | (2 << 6) | (King << 12) | (1 << 15); } inline void Move::genBlackOO() { m = 60 | (62 << 6) | (King << 12) | (1 << 15); } inline void Move::genBlackOOO() { m = 60 | (58 << 6) | (King << 12) | (1 << 15); } inline void Move::setLegalMove() { m |= LEGALITYBIT; } inline void Move::setFrom(Square from) { m = (m & (~63)) | from; m &= ~LEGALITYBIT; } inline void Move::setTo(Square to) { m = (m & (~(63 << 6))) | (to << 6); m &= ~LEGALITYBIT; } inline unsigned int Move::action() const { return (m >> 12) & 63; } inline unsigned int Move::removal() const { return (m >> 18) & 15; } inline void Move::setBlack() { m |= BLACKTM; } inline unsigned int Move::promoted() const { return 7 & (m >> 22); } inline unsigned int Move::capturedType() const { return (m >> 18) & 7; } inline void Move::setPieceType(const uchar p) { m &= PTCLEAR ; m |= (7 & p) << 12; } inline void Move::setCaptureType(const uchar p) { m &= CAPCLEAR ; m |= (7 & p) << 18; } inline void Move::setTwoForward() { m |= TWOFORWARDBIT; } inline void Move::setEnPassant() { m |= ENPASSANTBIT; setCaptureType(Pawn); } inline void Move::setPromoted(const uchar p) { m &= PROCLEAR ; m |= PROMOTEBIT | ((7 & p) << 22); } inline void Move::setCheck() { m |= (1 << 30); } inline void Move::setMate() { m |= (1 << 29); } inline bool operator==(const Move& m1, const Move& m2) { return m1.m == m2.m; } inline bool operator<(const Move& m1, const Move& m2) { return m1.m < m2.m; } inline bool Move::operator==(const Color& color) const { return color == ((m & BLACKTM) ? Black : White); } inline bool Move::operator!=(const Color& color) const { return !(*this == color); } inline bool Move::operator==(const Piece& p) const { return (unsigned int) p == (((m & BLACKTM) && ((m >> 12) & 7)) ? ((m >> 12) & 7) + 6 : ((m >> 12) & 7)); } inline bool Move::operator!=(const Piece& p) const { return !(*this == p); } #endif // __MOVE_H__ chessx-1.0.0/src/gui/savedialog.h000644 001750 001750 00000003210 12223260306 017443 0ustar00niklasniklas000000 000000 /*************************************************************************** Savedialog - dialog for saving game ------------------- begin : Mon 17 Apr 2006 copyright : (C) 2006 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef __SAVEDIALOG_H__ #define __SAVEDIALOG_H__ #include "ui_savedialog.h" #include "common.h" class Database; class Game; class QLineEdit; /** @ingroup GUI The SaveDialog class is a simple dialog to edit and save game header. */ class SaveDialog : public QDialog { Q_OBJECT public: static const int Discard = 2; SaveDialog(QWidget* parent = 0, Qt::WindowFlags f = 0); virtual ~SaveDialog(); virtual int save(Database* database, Game& game); virtual void accept(); protected slots: void discardChanges(); private: void setLineEdit(QLineEdit* edit, Database* database, const QString& tagName); Ui::SaveDialog ui; }; #endif chessx-1.0.0/src/gui/mainwindowabout.cpp000644 001750 001750 00000001341 12222770050 021073 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2010 by Michal Rudolf mrudolf@kdewebdev.org * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "aboutdlg.h" #include "mainwindow.h" void MainWindow::slotHelpAbout() { AboutDlg dlg; dlg.exec(); } chessx-1.0.0/data/images/circle_black.svg000755 001750 001750 00000023125 12062314776 021123 0ustar00niklasniklas000000 000000 LED Circle (Black) jean.victor.balin@gmail.com led shape Open Clip Art Library Jean-Victor Balin Jean-Victor Balin 2005-08-21 image/svg+xml en chessx-1.0.0/src/guess/movelist.h000644 001750 001750 00000006405 12223260306 017542 0ustar00niklasniklas000000 000000 ////////////////////////////////////////////////////////////////////// // // FILE: movelist.h // MoveList class // // Part of: Scid (Shane's Chess Information Database) // Version: 3.4 // // Notice: Copyright (c) 1999-2002 Shane Hudson. All rights reserved. // // Author: Shane Hudson (sgh@users.sourceforge.net) // ////////////////////////////////////////////////////////////////////// #ifndef SCID_MOVELIST_H #define SCID_MOVELIST_H #include "common.h" namespace Guess { ////////////////////////////////////////////////////////////////////// // MoveList: Constants const unsigned int MAX_LEGAL_MOVES = 256; // max. length of the moves list /////////////////////////////////////////////////////////////////////////// // MoveList: Data Structures // *** SimpleMove: less expensive to store than a full move as defined // in game.h, but still fully undoable. // struct simpleMoveT { unsigned char pieceNum; pieceT movingPiece; squareT from; squareT to; unsigned char capturedNum; pieceT capturedPiece; pieceT promote; squareT capturedSquare; // ONLY different to "to" field if this capture // is an en passant capture. unsigned char castleFlags; // pre-move information squareT epSquare; // pre-move information unsigned short oldHalfMoveClock; int score; // used for alpha/beta ordering. }; inline bool isNullMove(simpleMoveT * sm) { return (sm->from == sm->to && sm->from != NULL_SQUARE && piece_Type(sm->movingPiece) == KING); } errorT writeSimpleMove(FILE * fp, simpleMoveT * sm); errorT readSimpleMove(FILE * fp, simpleMoveT * sm); class MoveList { private: unsigned int ListSize; simpleMoveT Moves [MAX_LEGAL_MOVES]; public: MoveList() { ListSize = 0; } ~MoveList() {} inline unsigned int Size() { return ListSize; } inline void Clear() { ListSize = 0; } inline void Add(simpleMoveT * sm); inline simpleMoveT * Add(); inline simpleMoveT * Get(unsigned int index); inline void Remove(unsigned int index); void MoveToFront(unsigned int index); void SwapWithFirst(unsigned int index); int Find(simpleMoveT * sm); void FindBest(unsigned int index); void Sort(void); bool IsSorted(void); unsigned int SelectBySquare(squareT sq); unsigned int SelectBySquares(squareT f1, squareT t1, squareT f2, squareT t2); }; inline void MoveList::Add(simpleMoveT * sm) { ASSERT(sm != NULL); ASSERT(ListSize < MAX_LEGAL_MOVES); Moves[ListSize++] = *sm; } inline simpleMoveT * MoveList::Add(void) { ASSERT(ListSize < MAX_LEGAL_MOVES); simpleMoveT * sm = &(Moves[ListSize]); ListSize++; return sm; } inline simpleMoveT * MoveList::Get(unsigned int index) { ASSERT(index < ListSize); return &(Moves[index]); } inline void MoveList::Remove(unsigned int index) { ASSERT(index < ListSize); ListSize--; if(index != ListSize) { Moves[index] = Moves[ListSize]; } } } // End namespace Guess #endif // SCID_MOVELIST_H ////////////////////////////////////////////////////////////////////// // EOF: movelist.h ////////////////////////////////////////////////////////////////////// chessx-1.0.0/src/guess/recog.h000644 001750 001750 00000003503 12223260306 016773 0ustar00niklasniklas000000 000000 ////////////////////////////////////////////////////////////////////// // // FILE: recog.h // Endgame knowledge recognition class // // Part of: Scid (Shane's Chess Information Database) // Version: 3.4 // // Notice: Copyright (c) 2002 Shane Hudson. All rights reserved. // // Author: Shane Hudson (sgh@users.sourceforge.net) // ////////////////////////////////////////////////////////////////////// #include "guessengine.h" #include "position.h" namespace Guess { // The Recognizer class provides score bound information for chess // endgames. // Only positions with a total of 6 or fewer pieces (including kings // and pawns) are potentially recognizable. static const unsigned int MAX_RECOGNIZED_PIECES = 6; // Recognition value conversion: a recognition score contains a // regular score shifted left 4 bits to make room for a score flag. inline int recogValue(scoreFlagT flag, int score) { return ((score * 16) | flag); } inline int recogScore(int value) { return value / 16; } inline scoreFlagT recogFlag(int value) { return value & 15; } class Recognizer { private: static int KPK(Position * pos); static int KBBK(Position * pos); static int KBNK(Position * pos); static int KBPK(Position * pos); static int KRKB(Position * pos); static int KRKN(Position * pos); static int KMKP(Position * pos); static int KQKP(Position * pos); static int KRKP(Position * pos); static int KRPKR(Position * pos); public: static unsigned int MaxPieces(void) { return MAX_RECOGNIZED_PIECES; } static int Recognize(Position * pos); }; } // End namespace Guess ////////////////////////////////////////////////////////////////////// // EOF: recog.h ////////////////////////////////////////////////////////////////////// chessx-1.0.0/src/database/game.h000644 001750 001750 00000044165 12223260306 017234 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 Marius Roets * * (C) 2005-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __GAME_H__ #define __GAME_H__ #include #include "board.h" #include "movelist.h" #include "nag.h" #define NO_MOVE -1 #define CURRENT_MOVE -2 #define CURRENT_VARIATION -3 #define COMPILED_ECO_FILE_ID ((quint32)0xCD5CBD02U) typedef int MoveId; class SaveRestoreMove; class SaveRestoreMoveCompact; /** @ingroup Core The Game class represents a chess game. This is a complete rewrite, with simpler API. Moves and variations can be added and removed. Moves can have associated comments and nag values. Each variation can have a comment before the variation. The game can also have a pre-comment. Each node has a unique id that identifies it. Each variation is identified by the first node of the variation. Representation of a game tree 0 1 2 3 4 5 6 *---*---*---*---*---*---* \ \ 7 8 9 10 11 *---*---*---*---* 0 is the parent node of the game. It does not represent a move 1 represents the first move in the mainline. 2 is the parent node of the first variation 7 is the variation number. */ class Game : public QObject { Q_OBJECT public : /** Flags indicating how a move string should be constructed These flags may be or-ed together to specify what should be included in a move string. */ enum MoveStringFlags { MoveOnly = 0, /**< Only the algebraic notation should be included */ WhiteNumbers = 1, /**< White moves should be preceded by a move number */ BlackNumbers = 2, /**< Black moves should be preceded by a move number */ Nags = 4, /**< Nags/symbolic annotation should be included */ FullDetail = 7, /**< Specifies all move numbers and nags should be included */ TranslatePiece = 8 /**< Translate using the user-defined translation */ }; enum Position { BeforeMove, AfterMove }; enum NextPreviousMove { NextMove, PreviousMove }; Game(); Game(const Game& game); Game& operator=(const Game& game); virtual ~Game(); // **** Querying game information **** /** @return current position */ const Board& board() const; /** @return current position in FEN */ QString toFen() const; /** @return current position in human readable FEN */ QString toHumanFen() const; /** @return whether the current position is in the mainline */ bool isMainline(MoveId moveId = CURRENT_MOVE) const; /** @return start position of game */ Board startingBoard() const; /** @return game result */ Result result() const; /** @return the move at node @p moveId. */ Move move(MoveId moveId = CURRENT_MOVE) const; /** @return current move id. */ MoveId currentMove() const; /** @return comment at move at node @p moveId including visual hits for diagrams. */ QString annotation(MoveId moveId = CURRENT_MOVE, Position position = AfterMove) const; /** @return comment at move at node @p moveId. */ QString textAnnotation(MoveId moveId = CURRENT_MOVE, Position position = AfterMove) const; /** Show annotations on the board for the Nose @p moveId. */ void indicateAnnotationsOnBoard(MoveId moveId); /** @return squareAnnotation at move at node @p moveId. */ QString squareAnnotation(MoveId moveId = CURRENT_MOVE) const; /** @return arrowAnnotation at move at node @p moveId. */ QString arrowAnnotation(MoveId moveId = CURRENT_MOVE) const; /** @return annotation at move at node @p moveId. */ QString egtAnnotation(MoveId moveId = CURRENT_MOVE) const; /** @return annotation at move at node @p moveId. */ QString clkAnnotation(MoveId moveId = CURRENT_MOVE) const; /** @return time annotation (either egt or clock) at move at node @p moveId. */ QString timeAnnotation(MoveId moveId = CURRENT_MOVE) const; /** @return @p true if a move can have annotation before the move. */ bool canHaveStartAnnotation(MoveId moveId = CURRENT_MOVE) const; /** @return nags for move at node @p moveId */ NagSet nags(MoveId moveId = CURRENT_MOVE) const; /** @return next move in short algebraic notation, returns empty string if no such move */ QString moveToSan(MoveStringFlags flags = MoveOnly, NextPreviousMove nextPrevious = NextMove, MoveId moveId = CURRENT_MOVE, QString* annotations = 0, NagSet* nagSet = 0); /** return comment associated with game */ QString gameComment() const; /** Query event info and date information for display in game browser etc. */ QString eventInfo() const; // **** node modification methods **** /** Sets the comment associated with move at node @p moveId */ bool setAnnotation(QString annotation, MoveId moveId = CURRENT_MOVE, Position position = AfterMove); /** Sets the squareAnnotation associated with move at node @p moveId */ bool setSquareAnnotation(QString squareAnnotation, MoveId moveId = CURRENT_MOVE); /** Append a square to the existing lists of square annotations, if there is none, create one */ bool appendSquareAnnotation(Square s, QChar colorCode); /** Append an arrow to the existing lists of arrows, if there is none, create one */ bool appendArrowAnnotation(Square dest, Square src, QChar colorCode); /** Sets the arrowAnnotation associated with move at node @p moveId */ bool setArrowAnnotation(QString arrowAnnotation, MoveId moveId = CURRENT_MOVE); /** Sets the annotation associated with move at node @p moveId */ bool setEgtAnnotation(QString annotation, MoveId moveId = CURRENT_MOVE); /** Sets the annotation associated with move at node @p moveId */ bool setClkAnnotation(QString annotation, MoveId moveId = CURRENT_MOVE); /** Adds a nag to move at node @p moveId */ bool addNag(Nag nag, MoveId moveId = CURRENT_MOVE); /** Sets nags for move at node @p moveId */ bool setNags(NagSet nags, MoveId moveId = CURRENT_MOVE); /** Clear the nags from the node @p moveId */ bool clearNags(MoveId moveId = CURRENT_MOVE); // **** tree information methods ***** /** @return number of siblings of current node */ int numberOfSiblings(MoveId moveId = CURRENT_MOVE) const; /** @return whether the game is currently at the start position */ bool atLineStart(MoveId moveId = CURRENT_MOVE) const; bool atGameStart(MoveId moveId = CURRENT_MOVE) const; /** @return whether the game is at the end of the current variation */ bool atLineEnd(MoveId moveId = CURRENT_MOVE) const; bool atGameEnd(MoveId moveId = CURRENT_MOVE) const; /** Counts the number of moves, comments and nags, in mainline, to the end of the game */ void moveCount(int* moves, int* comments, int* nags) const; /** @return number of half moves made since the beginning of the game */ int ply(MoveId moveId = CURRENT_MOVE) const; /** @return current move. Equals to (ply-1)/2+1 for standard games, but may be different */ int moveNumber(MoveId moveId = CURRENT_MOVE) const; /** @return number of ply for the whole game (mainline only) */ int plyCount() const; /** @return number of current variation */ MoveId variationNumber(MoveId moveId = CURRENT_MOVE) const; /** @return number of variations at the current position */ int variationCount(MoveId moveId = CURRENT_MOVE) const; /** @return true if the referenced variation has siblings */ bool variationHasSiblings(MoveId variation) const; /** @return true if the game has been modified */ bool isModified() const; /** Clear/set game's @p modified flag. */ void setModified(bool set); /** @return moveId of the top main line */ MoveId mainLineMove() const; /** @return moveId of the previous move */ MoveId previousMove() const; /** @return moveId of the next move */ MoveId nextMove() const; /** @return moveId of the parent node */ MoveId parentMove() const; /** @return list of variation at the current move */ const QList& variations() const; // ***** Moving through game ***** /** Moves to the beginning of the game */ void moveToStart(); /** Moves to the end of the game */ void moveToEnd(); /** Moves by given ply, returns actual ply reached */ int moveByPly(int diff); /** Moves to the position corresponding to the given move id */ void moveToId(MoveId moveId); /** Moves to the given ply */ int moveToPly(int ply); /** Move forward the given number of moves, returns actual number of moves made */ int forward(int count = 1); /** Move back the given number of moves, returns actual number of moves undone */ int backward(int count = 1); /** Moves forward if the next move matches (from,to,promotionPiece) */ bool findNextMove(Square from, Square to, PieceType promotionPiece = None); /** Enters the variation that corresponds to moveId. moveId must be a MoveId that corresponds to a subvariation of the current position. Compared to moveToId this function runs in constant time. */ void enterVariation(const MoveId& moveId); // ***** game modification methods ***** /** Adds a move at the current position, returns the move id of the added move */ MoveId addMove(const Move& move, const QString& annotation = QString(), NagSet nags = NagSet()); /** Adds a move at the current position, returns the move id of the added move */ MoveId addMove(const QString& sanMove, const QString& annotation = QString(), NagSet nags = NagSet()); /** Replace the move after the current position */ bool replaceMove(const Move& move, const QString& annotation = QString(), NagSet nags = NagSet(), bool bReplace = true); /** Replace the move after the current position */ bool replaceMove(const QString& sanMove); /** Insert the move after the current position */ bool insertMove(Move m); /** Adds a move at the current position as a variation, * returns the move id of the added move */ MoveId addVariation(const Move& move, const QString& annotation = QString(), NagSet nags = NagSet()); /** Adds a move at the current position as a variation, * returns the move id of the added move */ MoveId addVariation(const MoveList& moveList, const QString& annotation = QString()); /** Adds a move at the current position as a variation, * returns the move id of the added move */ MoveId addVariation(const QString& sanMove, const QString& annotation = QString(), NagSet nags = NagSet()); /** Merge current node of @p otherGame into this game */ bool mergeNode(Game &otherGame); /** Merge @p otherGame starting from otherGames current position into this game as a new mainline */ bool mergeAsMainline(Game &otherGame); /** Merge @p otherGame starting from otherGames current position into this game as a new variation */ bool mergeAsVariation(Game &otherGame); /** Merge @p otherGame variations starting from otherGames current position into this game as new variations */ bool mergeVariations(Game &otherGame); /** Find the point in the this game where @p otherGame fits in the next time. @retval Node from where the merging shall start in other game */ MoveId findMergePoint(const Game &otherGame); /** Merge Game @p g into this game */ void mergeWithGame(const Game& g); /** Promotes the given variation to the main line, returns true if successful */ bool promoteVariation(MoveId variation); /** Removes the given variation, returns true if successful */ bool removeVariation(MoveId variation); /** Removes all variations and mainline moves after the current position, * or before the current position if @p position == BeforeMove */ void truncateVariation(Position position = AfterMove); /** Find the next illegal position in all variations and mainline moves after the current position, and cut the game from there */ void truncateVariationAfterNextIllegalPosition(); /** Removes all tags and moves */ void clear(); /** Set the game start position */ void setStartingBoard(const Board& startingBoard); /** Set the game start position from FEN. */ void setStartingBoard(const QString& fen); /** set comment associated with game */ void setGameComment(const QString& gameComment); /** Remove all variations */ void removeVariations(); /** Remove all Comments */ void removeComments(); /* Manipulating and querying tags */ /** Removes all tags */ void clearTags(); /** @return value of the given tag */ QString tag(const QString& tag) const; /** @return a map of all tags in the game */ const QMap &tags() const; /** Sets the value of the given tag */ void setTag(const QString& tag, const QString& value); /** Removes a tag */ void removeTag(const QString& tag); /** Set the game result */ void setResult(Result result); // Searching /** Search game to see if given position exists, if it does return move id */ MoveId findPosition(const Board& position) const; /** @return true if the move @p from @p to is already main move or variation */ bool currentNodeHasMove(Square from, Square to) const; /** @return true if the move @p from @p to is already in a variation */ bool currentNodeHasVariation(Square from, Square to) const; /** @return ECO code for the game */ QString ecoClassify(); /** @return true if current pos is in the ECO list */ bool isEcoPosition() const; /** Method that loads a file containing ECO classifications for use by the ecoClassify method. Returns true if successful */ static bool loadEcoFile(const QString& ecoFile); /* Debug */ /** Dump a move node using qDebug() */ void dumpMoveNode(MoveId moveId = CURRENT_MOVE); /** Dump annotatios for move @p moveId using qDebug() */ void dumpAnnotations(MoveId moveId); /** Repeatedly call dumpMoveNode for all nodes */ void dumpAllMoveNodes(); /** Decide if moveVariationUp() can be executed */ bool canMoveVariationUp(MoveId moveId) const; /** Decide if moveVariationDown() can be executed */ bool canMoveVariationDown(MoveId moveId) const; /** Start all variations with an initial character comment */ void enumerateVariations(MoveId moveId, char a); /** Move the variation @p moveId of the curent node up in the list of variations */ void moveVariationUp(MoveId moveId); /** Move the variation @p moveId of the curent node down in the list of variations */ void moveVariationDown(MoveId moveId); signals: void signalGameModified(); private: QString specialAnnotation(QString& annotation, QString specialMark) const; // [%csl [%cal QString composeAnnotation(QString freeText, MoveId node) const; struct MoveNode { Move move; NagSet nags; MoveId previousNode; MoveId nextNode; MoveId parentNode; bool removed; int ply; QList variations; void remove() { parentNode = previousNode = nextNode = NO_MOVE; removed = true; } MoveNode() { parentNode = nextNode = previousNode = NO_MOVE; removed = false; ply = 0; } }; /** List of nodes */ QList m_moveNodes; /** Keeps the current node in the game */ MoveId m_currentNode; /** Keeps the start position of the game */ Board m_startingBoard; /** Keeps the current position of the game */ Board m_currentBoard; /** Keeps the start ply of the game, 0 for standard starting position */ int m_startPly; /** Flag indicating if the game has been modified */ bool m_isModified; /** Start annotations for each variation */ QMap m_variationStartAnnotations; /** Annotations for move nodes */ QMap m_annotations; /** SquareAnnotations for move nodes */ QMap m_squareAnnotations; /** ArrowAnnotations for move nodes */ QMap m_arrowAnnotations; /** Map keeping pgn tags of the game */ QMap m_tags; /** Remaining Time Annotations for move nodes */ QMap m_clkAnnotations; /** Elapsed Time Annotations for move nodes */ QMap m_egtAnnotations; // **** memory management methods **** /** Remove all removed nodes */ void compact(); /** Removes the node at @p moveId */ void removeNode(MoveId moveId = CURRENT_MOVE); /** Checks if a moveId is valid, returns the moveId if it is, 0 if not */ MoveId nodeValid(MoveId moveId = CURRENT_MOVE) const; /** Change parent of each move of a variation. */ void reparentVariation(MoveId variation, MoveId parent); //eco data static QMap m_ecoPositions; friend class SaveRestoreMove; friend class SaveRestoreMoveCompact; }; class SaveRestoreMove { public: SaveRestoreMove(Game& game) { m_saveGame = &game; m_saveMoveValue = game.currentMove(); } ~SaveRestoreMove() { m_saveGame->moveToId(m_saveMoveValue); } private: Game* m_saveGame; MoveId m_saveMoveValue; }; class SaveRestoreMoveCompact { public: SaveRestoreMoveCompact(Game& game) { m_saveGame = &game; m_saveMoveValue = game.currentMove(); } ~SaveRestoreMoveCompact() { m_saveGame->moveToId(m_saveMoveValue); m_saveGame->compact(); } private: Game* m_saveGame; MoveId m_saveMoveValue; }; #endif // __GAME_H__ chessx-1.0.0/src/database/engineoptiondata.h000644 001750 001750 00000001475 12042741732 021656 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef ENGINEOPTIONDATA_H #define ENGINEOPTIONDATA_H #include #include #include enum OptionType { OPT_TYPE_CHECK, OPT_TYPE_SPIN, OPT_TYPE_COMBO, OPT_TYPE_BUTTON, OPT_TYPE_STRING }; typedef QMap OptionValueList; class EngineOptionData { public: EngineOptionData(); QString m_name; QString m_defVal; QString m_minVal; QString m_maxVal; QStringList m_varVals; OptionType m_type; static EngineOptionData* FindInList(QString name, QList& list); }; #endif // ENGINEOPTIONDATA_H chessx-1.0.0/data/themes/leipzig.png000644 001750 001750 00000113561 11172700607 020170 0ustar00niklasniklas000000 000000 PNG  IHDRv=]bKGD̿ pHYsuuÃtIME ;P^ IDATx]yMs={9gkH@$ 8Ԓ8H@ $  H0$  H@a$  H@ # H@` H@H@ِ=v`q &GP3dm p ,2- c< #HG{P_{UdEWF=G<{1BaVk+mh c#-OY|lq1LÞ7w|'AaE2m& SlgW瞑x^4',a;.j%F>rg_ϯSיer5A g!܋|;7Pa$ .\`-<8Ҵ[.R*l?}0CwbR@UL "9>uM~B36S4A!?5e !vq7΄WцU;b*<2.y = [R S;.EtnsJjL)x%-[c `f(KC˜n[aCtKHEF5I|NUOWU5g{}U`0&Dg$4zqz Cʸ<F @1 )DW ˮˣOKFS}M u)kf`.0 諸),h9c!J 7ڜ_FAmyŵ|mCU٣FZr`m^z"W٥|+"Ysdȩᖥ5|0 `>O uqpu l` 08MdF>Ӡ#]v_E] /%hjF8f;A ^VmnmY ǣ[ uC!y=`:I 8! H6^P38g7^sd]ӊ.|ŒAېg[ ;ؠѩ0YQ9*NxctB>Fd|BxӐ)2R&JSyO*'er3זnw1c !c<R9"փt$$MÃ:<yc,%$UF`pFi(Iޫ*cZ*@E#ๆYD5, {,!Zi^;+* dTLNtgwA.z4r:rI*x cΈ 6XE~\0$ai2#`K܍$dqb?u~Eac>ts re(2DAYE%Al&tN.@Jc9H _ct>Ϧ+j"8888jǸ-Sğo6Β 7?yH+^mIXH-iYnO.Aؖwv戺 RksK@o_xM#Dlɥ * [bOL=e=ơ!Oa\HͅfBZ ІQ>#aOVx}/;&vωyjֶ>AI_YA]&g}il!7*Wz]֭>㹲E"r9n|6skz]}2d^$7V4Gq8u`p3q2(cCˀwV-A"dM +ij,%҉<7}A/;e6Sd80É Σ+.uq#+ OT6+a)9]K"9D3Zy~@& A 4\)Zn U)j*5™a0/{`#O?1aM^;/D|gC]F *V?e;!sd0GW<W}̠S>kasOhUm u Tl8͛bx. $R\N{)5zM2O'j;QA{blF0zaLPc̯ :n'c綠sO0]u VH;Bk R@+@gAر;\|G\0Ne^?F:/.O }!`8Lr4E"0^2e3T|P1IU܌x c.  ¯>3!=?گŀ. 1BoW04L8_iixZJ A0th"}OqI -t!F଎ELS:Ȧ fM_W)TtRzp I!ޖ^3ObڦJKX+-\f͑Q-%t455xx<!eECET3r&1b-aK NHåXYu2Q 'qu⢴(͇"0L;iD?u>0[dll0`ޫ_@ W{U3?L| :3y8Eq]z`&|GT ? ҳ6}{C~WN"f^a0 HAtRR-BhijJs*:=uR. ))tf/҅ kF_ %6{8@)~st|_0}pWJ4{xL\L3e_Q0Yt7`3n3c 7ztȚm(WM"Y){hZB ~;uC||USRW [@^&pM|8sՙ.>Kh[Gms%13T'Év ! 0wЀ@(qrGrGm-kҗa"[l|!-Ѥ1w*IBzr ӑ$6 2Z޻q0'ɌxSLEjDs+xH\O,cLܱ,gxf'o.-u PS(d\[* l|6e 5AKkh؇'˸9$^b-QNyRZ$_ Ujb (;QzUx'?tͣ9+|5FEQvM#f%dpb=B _E9f "| (Yef6/j;Vx(`?xaмmBWIU-g-WyN-um\@2G)%R(1`\AgM("1&6ʭTL7!|3 #|3 >{7ZBLwk$̒(ǓDaO $<+o%jjt˗}6ϨO:~^yK븭>Uj}u6ab-wnB˅2"Ru&e~PgO]X#q :hM=(icWѬa]+1|'@Y B*yJEAcfcO3G3GTHGhh'QE"]O*R)>uh,7+*z/ sT33TP Hׁsսjʞl Gz\M*E2OP1? ?ugjsB(yqv}JtkVO;(8Os QUfQbCQafG IO!c |[LA ݀^IMڨδuJWq26I~5c69KUjZBc[#YP,{F1Om[GwOOٯ>#bfFȇ.uAaAdDDYKGox}he;\duP)HAf}*J|UIM.*`jOE+q.*b>3,4}q^@E8.GJu"7+Z̏0xIAgmdbnǃ  KŴ 03i 0*))S'CG鎰}nDaӔ KB4Txq| js7{Jo(q0ZiWG`p:b+QhmD\UK}nWZ==oܽf|8fE`0R<38fa膁ʖ/K͝ypV7g;EawO}AMsxC1’-T٦R^h9Mo E嫹0v?ceǐbgaUf ;ҕ$J#-sK "*jw]bY|4h'?;{{gvq1U~627[0X` patl6x1CqPPhw f {'Rt%fΛme0@D?kH/D)'|CTÈlb!֡9)o. MԂ|[lù.iR9>^J])dq"_+M\/MY Cq.Jc]ӈ3#_NA{%ݷØ?]Np(Ej6j S0V6@ '@|^QJC'Fj@H֪88~b|!ՌC?mDڡseWy*!TLt,*ZI4f\KI+tP-72ܜ,MQ~W\N`pJ ]oj?^JʨITWWFW;ۥѽE]!W+-3TS [;Mʼnw눙8Sm>^e>PH\1!q~n(%'7Jj%O(jO%5åuCG|hb++VZ}<0wd4FpDi (La+.̷V &4]H;$KR>A=LJif(3t?UA!1[k+Am*43o"y\_z{<= sCo7=F6wӄZn\Vڿ;KQHs`|z<ʯ117~_įx9?-"PoǫwrOn.#8ϓ]v͏8sꩡ[th.?1OQDYcЕ$IMB46 RSHj .mwp P_+3V[kJ,Y G?"tc|c~p3MX4uQU^e[5:9rTgS#aHz"%8lKh7R z~,7w: ~FqC r& ;>D KhUi=C54- x@yOyP=,7; Hʸ/ԢVH!i I N;3U}z:q=-k)4\I;t[/)dh*i9`'a,cs|:dlP+zF7Z"qÎGIͤu[E*`' 6-&f܌TWo)$r͒N~, K,4tt8I>6d!Bq'7/sI!QmDm9G`>'r2dlsk;[IO{5]c wr߾ΊZBlWW~p!+Z۷hHj2S`#t 3w 5t=ZƸYkMQMŲܭ{/9ov> u.9J̑rp@uԋޫ~}-f~&\*t]2ÿch\\ϩ>˩aJjNS$-=|Y\8(VR(+K-GZ%qaFnn%]zPFy}xm pH(.0FMY_+R'WWkS9FqT+5[x]#Op\%h[aNMXVHmK>@ƕ7Qp-Q'jMz^+u*P=~W;Υ홝ꨟ.{~*h)/3/ymw(6nץv>֐Oύk[#-w>wgvpW+?#s\]Y!?j8#UEa4U;1?s,YfatjJ ./ &X/Y^~kދ?ð^s uH%Vzk >eyZ5Cw{q_W4j/VF<џQ]cZ #´kiS"bR995ZL~A{I+Ou#N6jIrOOE>=:ŝ].P x%"%q=UZMIG03L`"*jkv»dI~2-C{3*'ܠvfvE[`~S`bf> 4<IdRʽi8\).hd2Pjd:dp0J[M@pM ii3՟1 niQS_E7+bYi+ϗʞz^[_^̃\ڨq w4R衠kOs7}>swe"%)øPn51AW :|F ?..^O.F3TM?-Ė$Cw)kjfKbFH r^ɮm/}s;|_hxH ޵,_\ݒcO1gdzc&ʚdC{Z :ai(E)E}&^-Lq),5mگ(Cb*F 3VmM4zF=>[q_+4c$}>EEavӉ}|KӅ^Ao  U]ꬔĵʹE yw#|=N>.QӶA-&צz]5/P4Y\:OM/y; 0 - Z[GY%0 G87M.2U[ hy č,ZerH}zO-H]ȾÈz*|5wry) =KoA6MsP3%aϗIL7)5r1A[I 5`P$JzSL|;\76#)gхo'}u(z}+'b6z ki_p:+ P>%lKĉ%.x{ƙ{,,j񨸎:<{ek\pOQy[؞P+:^ʘ}$F ^03Vˁj 3idM@13o5E!=.&dI6ԓݢ2b'kmuC`\LU9r#w )lgf~]OgyÙ;a (S {8nN) c(X t$$7 G8v@`VxL&nJlnQE q$0_Ѓ-xQ t:]NZ=q%aWT)L7P\06Ar~:gp).%9_0Qڊ;i<J ]Mk¶*10)CA V 9;hv&ø׵_eM̭;;Q5i^[Eax AU|IB'qFr(!N,տSel9ǭ%{Et7y4Tt)tyYYUȅZO pCjI -(*U823nN,IYq7&b K8}K $o'0x6ğIr̬0&j{S^7T;3Wš'o<w" aX<[ixF@ ~ SzJ 5o֦ ?K}+գ@gPYtTvN2Ǹ]b۪U֓,?|CgK mKTOd@.5IR*\y41}/Iif^F`pm߬vע5:N6Sr7Rg6:y<-EoL&fv Zo&'(ezY^3NQ`Ljp f׉.LS'!U;B,ҢFBQN6n9_WyolXW\#ϯb&=E7JQӄV-ZIh/`$N1 8JT& F `} =>WӨ; KŊĬpe.! vK%=e6.$01L`BĜeޛODaimFa|dI"hP+?8[RD҃¡sˣ/X#S{J Y/Q#D yfxKUFzXV񞸝αcv_Ա%b|Km&B͖ẙ1ӊ.z)>)j:J}h0`pSh[B24zfp ȹ.vwpa|!-=cj5==pVInɴ/>= -9./W]A΃.Z^Nb&#=2bs.u'QT.|SԢ]jujob uޗ11&kEQ[Q xN 'EZ.X'mRLN/4Ipcy| /!Uƍ6Y:l}KyˬȊiOab0YwCaG<Ê"K4"8hku(E7OI,r1D4pJj+ gFaDqn6t-RԗK^"xq/n'D$pHc |ߑI*_ W*i9w곂ħ`->c}_V;C5`U *_BqUƹ!/ڌ=(sٹ$OICIQN*zhto4:ĸJ8X1:e+Oxͪp/_%W[ :ɝ0>͔vY߼j^E{\i*lE_F$PbO <ܘCt |8sXEftRYW+f>4Q=ζ3Nct)?ltrڏy׌]:/:Ъ4Ot])5J?ac Z1p)N&?V搥 QeD%ΨHjCj?RiͽT^ָSy= i%t/)&zJ!+y̡J᱖ԗ6  ̈4yع./f;C2ϑNzы6ad<1/hIĿC>ȖE|ZG"HH<*r1J2 *-qJZ!{3PtI$-pIY 'GCn$IIr (3<)Lėخ<wb<)h~X /|0U]xE Fn0MZ&FſZHCK;pۨbnz)~"dhC! @p-Ϊaff Aob`lh}I%*,>BKu"-stP|- $ 5BOBnqbtGD i.=&QHF9SM\tK R18&nf=_bv(XMT_p#|-Xe;j #a3/Ea~/..j'z/"pg;%rbXPW!1hZ22Z[XGHodY!-n.+}SzP,&Q*{b~*2oVH#pπ` 18ŶfuK^2vd8^3]fV܈0 ~/ciP#("&ǵ jX 8h)G}|o{鈺ڕI-W u U_)rZ~dR1[M(Gaf$NS]徛{#*t? g:)%H8guC1cb1Yep D "c8m䛘o(.L_wb2ȝ'tS;f`n]Y{FʏZXӷm\ZH ']ZD?hrr]+|1!\۸]1A7֜A; N @*tͫ%UNov {Q.-[E˹KvF׊l"->>;+ *c|1 ~K"@O+e%Ө%Q(Qj gm=6fƨ/t:TuŚLGyBMM|?KߝEQ; Xaȩ-$S+Iwѯ7׊]ֈ琢5tY~-:+Zaоex)El{ziˌX0n+J #OhRp}!n[@$~!܂W;^bw!䪵tz-N~5AQ+rf*+ ;;&al ^ cP'YRVz.ᡱهG]jPZuW:`N9^tZV8f IDATϚt0* THUrӹ$L.]\Kp@^XL:XJQf?›Џz\royQx&Yt?Nj^i- U>^+>< 0݉"5佢?v%T%J[v4aJEVUӤ3Hc8h| b"O_jeC,ab8!|~کlBYJh2GGVq%rL"4nխ먳 ÍX U-{$Ɩn95J!40=A51O#H#H )śi<BmŁ{1t#mnVPApRK}޿NFFJ4[G55|уj[Nu - J)õDK.1F q҇{E~D8.j-]L/pmjșQ8)xv'0uܤ8$Xi,aggu xiF+46GEeqfZǩ̶eQZ/A4ږkynR&'8#ZXʱ+;FȠfe` ϘPpA2E]TJ r1$A!bvc+vWܪ an\#_~_,u@k(852Yhgn4z/@Bo p 7W \#aLyٚKްF߉~L1S'\[v'# T$2,W\+p.R~b|*$ܯtXB"L#*6C-f !B{Dܮ{]OJ":S2XcþܿU- AC7t@: k `%`1n$pM@5* Kqq9]J=i&$q1qHޏ}؍Cځ`RwwyH=g4v>+苩u}#U aAOOkE#{J@rS=+žv~ Vb%5Pu­Z[eiM3è@Hq>7K6_u4(Z{l X__X`|neh(aʒOR5Es2Xq,#R)*+UB$HHD60SZT-{0xċ0 Er݄0h 2Z-7i^HִXv'Y4\G'Zj%Nz͇MePkYx"z+|<|OC[qli^g~'jögPg #bԟ>!goGMꕋ$4p+4U!Q׵-xȧnF3bU!}F}OIs%LWPuv!}s%qa ;w]6ètEā8aNcquSRMc<4!zV}i@Ex:sn{;2t/rb4SI4s*x˚z6Z{!m^ۈ"k7 *m\07SK M&rK=j=зJo$#V 7 kib z1DO\NaΊMgIJ~(*IZ40hj(*hk1FaD3W aPL<@clZFvf!+hX#T)nTKK(xW-BwkWU0ЧH@G}\2aaØb$@k1Gd.s|K a&_&fd?Eoy&VdLxf֘o;;+ʖ%zOLFy.)JOX6/H3|ЅNk`v|A_6:Vgh'P(/SA䎗wpG~SDu.~IXŚ )"3 @I35-N KZKͻU_۰%`a2.< 6Ei tIRI胁hT+ȥΩXR2$M{xZKQqsBN9xfW;v#scvEH@"+;_ TU^TjQEʩS+z~11NϽbT#_Hu>Us!l'* H7+./!^f/pk]#f.?0"(χqWƁ0;q.@0LwΉ!4`,élI||(31epY% ".-'3I 3) CH~O:-,qzz JƫaFGRq!(+k0$U(8>04Ux78C8ZHo"*?8M=,)d4B 4FAdږ1G~ mmJQ6lF^fa^v6sP]gT~3l^;"" XE,`X?QQ^ADPQ. (wXڲ˶|?&3dLf$yjƒBlKރhc;B)/rTNd!(G)J(`iB%,롊n'9@Yr%_`VR.κ4 6G3('PNrTqn N@c#Wn#1wU# 𺅹\쌥m`_V ܫXsoP69f=O ǎ+0Hx(xZbz 0=Tc!:5qt'T,9F \@)[LV#k4<,BWc6F,#=䮮G! I8&DuJ=+`|~ԟ&=֖[t=kS:ؤgRLtb/8롙cgn|lpI\: F(,J3hq~kGևa ޿= 5ǻAE|,"0e W!'ƐRb"`V,xH>FwPG8t[Sm\ktAƤ@,,߯E\4\"~'}g6*.#f ~Q$+0*0yU&(1B-M%{ nRo!d`]Mq 3y.g-VR(4 &'9_M㰱/H!ℎ`@s/ L>̲I5OY"&'OlpaAf!mc'@vWQ>.,9W荒g N K'RH`Ƥ-)l핦Y}>Qś#yTE9\O/ǓɢJ"39s"hyһgmh/}Fb0 20-{q%~>`SwΈp4}ͱ9VN>N4`E33#OX: UDr4uG:=%?EhǍx.޷gqSI0y{p;fc|Jp*D67Oi=EekCc'$UOt`Y7n9Ɇk#_*xZo%ʷr'<(01眡zb fJ f8J9=E&;A1馱<|IUs:MFkR4.7DXqT 5/y6Q\Uut~3K*ea9?a7Jx&U xЈ 0J bau'Z %'0t܋p#ދѕ0?#rIE1USN\tz_V3SPxd9 v#<3$t8GޭW!<QxMy,&?Z*AS:٫aveɣ~ʔ1R X#"#/kn {U'tI\RQ=^`H#dϴSM`Hxb#jbEEKTPƣFBkG.UN^ $x |wDO›8#XX;G|fj}p/`&#Lĭc}"Q ʘfB~1t-`fGJzilc:QڨE5=5PUPY9 dPR:(%{1";ml*My T_%8܌S@\őfRÔ')C@MVRZU EaXDkU~E'ԗ%P]DO|`ܲ'P7!\E)MXyţSwz"Ts-' @!Z39];7tBJ5Kpٗ+ڈ+i(B3i D6C>MEޙ2ީOZK]Hu~篬 ~WBIw~Jq, ]BiiEiDxb*u7<Rɠ2Ŀ+5Fԗ&YO:VV-qL~qxj8~w)XVG5GܖJ*kvt(!44IiTM9EA@:="522cOVhF.dCxN sj<7C IDAT׌ڷ?!_-S6@A >@4+VYC"p4D~j-[^#EwV4}'w9t[3if?)G N`G2r'vڝFJCj 6,P$,ң#<>쉷 RG `0|Ej%uzP'- CWEo?ތ&Q 8CreQiKOA\qQpo37Ro13ˈJ /3Za,vTÎ:]qeSENp1 ꀷpqUؐyaS{Y?2ݴ#lT^;RcUyF[oGUR2tɉ-S>JT\Ͱѫ?~P+9GiM螸F $X;,0e!9x('Jםj9!‚Fo<\P`sW[͂o^ٶjZr%#-t]NazXnn;]9q_}^D|>&G seN%R`V^ϩJ=V7%;T4~Ehziު~n)C0A++\;qN@ _4^Dy-9jNT!Ǧ&r>NBk5l'-̰N#r E@Q*PXАGmkzI_M$qeQ:yXƩ:1Yg ZŬΠI]BUJU>#(hEc1ꚤ+P6b Bz&_@1|-T,iEj-[/$FIP-'/㰃fG:^+̇ }Y@2<ޗhbË5VFnzKᮧ ʸ!,e 3G0]טJ}^ߕcfBS"`>5(2<ԅ<ӥ T,VBЫ xۅq(kvxG=Z UKjLj*VZHe+&peZc;\;/0K̖ ;>ǩVuԺFZ_N\Ф*2$YL$#%L-⨠9v]N4NrC,^ק8MLrA̧?iaͧr:l"0'Z.K fN"Z~"+&{JQfSaM1¹ϓk8 4[Sgc1=8A;7pY 6ss]\WMozY6`'E9SS}$JGEsm9D?A1rLȓfV@_Uq-f8v`_nN7i›hXTyEg#=s贞*Y3huzb|(t-}fI?7>sA޺MׄVUHFouۋGEÀTE?CB.j8/捤f FX9v1:IþuTMZu$qTt¬ \zjv{^7aQC 22db9YL]hCI_èf.ter8BnS\gDL5,R3$ =z>Ice]+㬰TOZt ˧5u8fġķY( /3TrA4n'" Oo^ĭD 9Vf [q3q\$fd>Զ!qC(.A老wRY1]21KF1P&i>6,ˆU$Akf f/uFyro:/϶x Ar =*tE)P"q ktQYს5f!isY6M ܫ~CS(WQ[k1uzɘI6 *a$ v4W:{ ;( ,.jIA⯅?^ɭipq0P*/8,tԭ9+\&N\I} 0|;I;qW{qC"Cq/ ״ )#a/JmIpo?P/, jtS`tS)>/?4 V(QʱJ7UUGhrA 'Dũ' ՊgOKUdJ9|鵬 XE mRfV c4ތ '\U`\k)IdnzC03O2وܕ:!TrTQW039#2s5!nOS%}ߋm9[cb?ycBA50xT̘H:+/&"ci"D?%L4<~ wj4qˡyh"Ogs'` SVTR|YX@kj#+E'$MIneŀ^풻&i9F|WZ`VFkۗK/m^Pu:0ͅĸHTq,q tafHI3\YT̫K\-f{ T%rZdKYTLpS\6}\!̥,y8UG %qRd (nd.V~U{1UR١ԗ6^mD< ]}YtIվ)z+H70#w8't{=13(!bT|DvDԍ,T|0x`A 6!_c\+хB})uӄ.ͣTH!Oŭ);4>,Ev/\F~_Až/%uo}hdZ)6DI dʚjAp$Tzai)_ApuO1TF1Ĺ̗Ejunehԧ~4cOxM̼3b. OQ]:T~F[!0Ny2?*hFu=?TEQ FlRE,()JT#|3ψ``fO'4w>'$0 m h1A-=/Qev~zYZ->^>EnNQ%8+&|[n ‹Q`g&@S`\0/drGT̓3ȆmiJ׉oŏ_$1TU.bOp]һP!JKKC}C} NC&4qZwE4J\ (!k;w"1;̿/13`r~Pv?=טlX&O ?G!fii}:Am=3TRuu Tr آ~S<yz9k}4EG%Om9!ɭ, 4oPUite&`l V.r8sR ]13?%5.'f_=aii9TR\G^G!O/]χc}Gc&H`LNXԖa;X('Qk"lY.ҨveǴl{5¢^6: +>8 5.t< $fob%o &&CKxoxFԕ O gڿHMي 'HMbflf>{Bo5 iu56$ʬvD*Vw u=YJ$[Bw/.aWaT(G4n4>t%CZϥ uNO6G ȹWshCTa䖋4. .zٗdrg]bfnjV~CCa@e**#`Y=l=毄pe(O `KɱO<) ΢4"E`_'$V q[QJ}(#"0V?:&ڋ;Qm7b]%1! ,drǙN`'yE.Cm+Ft^:BjsR eEGL^Mh cl̋# [Z'I_V~:Q,wZ| 62Yh*ٚ-ƮN;Ρ67 ~R ?)So:MT 9\-ZG1XC _2y?8|q|U+cWl&fq G~GwG#S TS;> f_ >E|&V{ cnkŵ$'fC1㻬bY'OY<~vl#[Y^c>dh^+>k8 o.Sm8Y2ݙD14] s[f$+Z8fbt@=?h~E\z&5@ vB$])R +)Mϝ+\نWJVe؋UI(4.?R1tȊR8&0n a䙐('CuLȧ;?'~tZK[(M PN/GIyM=>tvHy;Ǧ–HyRFS_?$AQ~aQʳIETBsl^+{ ¦9n p.uNA|p*^Tڍ -L"ɝzV:i0OL3ho ;}Uw5b1}FyL8QBu dx{(%2LnT|+y׳ kc5 $H=Ou! :Ep-Oc@+n.5F=3QzN &AœB E='tO[*MW _,4zI0OjNBDlQ-:G}Ot=pcF| "Xpe\IIq[-(Vc=*KeV޶`̌8Jgj0 [{p ~^/TS&Hd/Cؘ<ߊ\?ѣT "~2vd&=y)]LYb/5!0v2f۾X_L c*xD%qc֣%,PLa iI0ȗGEjF@3_koX;tIuw47U.e0 lnuє8JRDŽm]?RyJNzj6 cP/wҽ% @)B-74+}@.5:Wf4l %/jq <ʥ~d˨fRqY |`ybD4|cmu'K J{QY>nZAR Nos)~ބ؊/>.B^^dPz r-E=O#n"Dz6,$^ez ąRf)b+xR=&AsE@R}QGgjIgE/$S&5!ۿVޘvks׃z;VS,y=7aq2,\=lGv1\<'&bxHc{JM1@9ziptw>^)t FcqcLF/FTq8_kҌe;-Cęy1$QU%][ALB1j#r ĀɸSҚㆺ#8 VPFx .Ea?B< . b4?mS=+6XOj ";!}]h&6+jsaKm\7(yQ4F,TVd~_IVGZg8:rm }W$!qOv#c/2YXZ-A5L/ ՗S{+M/IDATRذj6 /C 'DR㴾W"OhtMz3$\P~39.Us" t/Ң\jNgkC4~d&)1mY8D6 O01zS'|}L|HΌ6ڝDG3.B[pw^cd:+ =e3d$}+B MPë=be~)IōO󣃇 4φ:2Wߢ臛h]FDK܈n|!;=p:DYèU`/L!3o5{Vɇzw>OrSަ&( [Hh)MXꬳzP?lD0s&:af^O}wK ܊:~ClC  %~H#y4VҸ J+jM '$겾cV˕1sg4|-E'<IoJ4˨V\4HZBg`{lǨsV,,q*sT 9rֿ~Vlmw*͕1аcyPks"33.s G]#4<;vy:^7Yrlde4Fk, AOS:"[stI`1ǽ j~^;r{}wѿnA3T<_B|"JOf&FJzDȗ<:hb( Gxc[QTtVؑpq'/cP"`6yag-OҨ %6 a}*Dq0AF9;m|p]+2{<>+h_ۥd e;siC\zMpnd_Yآa J+PhKx_SDh$Ub/l9tVxʂ"m M_PȮ  1\CRI` 8 wn!F-2.Chm!u[lKWx!` b*G}qx6,JbD=MT(dF^oV S(KV'.U䞓YLR m9`NQYBI[]CƁWyME:_LD"j,4v8z> }@nR޷V W*Z+6o|"Fx.Vȱ 8TSkC[P4g^$*l3Gro/IXtu?,$Qì& I[i`f5ܫT, ]} e"ӖzPi*6 9MJO;Mw`/=F݄–(סBxb˺~NRV>;.ZC i6)CFssQ+"]TtuL;b&G |4_MeW+Ęw'B'_ |E=ݷ 0 vd; 䳁Xvyr 8)lH AȠBo=WwYʾf?_T·[Z2T "p]*;B_+8rqެk-ş3 uC3/WD۪4.5OʻC&b)ZRB+}i( EDhG.) [NKQ 0H|C|alɮ }Q/0x^:JF%,Ғp4^d$[a~ mZnM eʢ)+=kÓ41>'|(/|q|~݁~7c c|6ZÆ1';t?X2գjcaS-HXOIBMd<$Ư :!GTQUOUKU978ד,㭄LQSIJG@H=@\J%Rba!P:(E!:9 |iW*ߓj,dž؁vfV܍<΍PuTٓI.yrO簴vK;ygs~7̦Z`ƻlLLz.&dI+Tvd mRa͙a, Xډx4EmBB`ab{W P8 -PUF!vcV`~CQR$\I5x-sYثSNrwK@JCMTB;C>> XFRc1ғxY0f r.|RF,?y&7Fl.B.b1%|mNq݅A.':%- o(-:ݳp_[WgE;-˕pݼdsٖ=hN s3m5+ ڊEd匲K |)Djo+zrD4@s-=t# m-0'Gqҿy'a[|Fvad"´ v+GQ[o5g"{,$l)^OVm t\E'N?+Z΅6=RUЬ4I\E EGL&!wfd% +0⎋u8ZTe:?V8ߢqS71CG&Wk+*fS?ʊ낢=J!fץ6YgXF!Bĭ&jÊZtt..Xl\p+0(0wVJ qV`1r^yoCĔeQ}Po$!!51x9fo0JN7!Ϫa{jmgw K@umV@;8> x0n,cb; rmzRZB$#7uZE\jB|ɩBT[O忮׼O$.8ssmeКd|Smmﱚz"^NGZDT# / 9@tT(mkڕY*/q"_+po}rXޱP{C_*5N<k~OhM,bEg5fG;}+">cS(ŖRwtF/R䟿HgӷR# Kљ8I"|kE樅q|;h~/ ě\Rzal<*N ==V~ zl|F}w .* aG9pw/ Ë  ukHDF._?Х(TFN%b!\/V]ԓ K׆9]da%Ŀ6ׁMh䀶)1=_9εҟ8k e4DҐGsͨ_oc} . Y's2Ã膦EA|67M[qu$bS=b4Pm2XW` okCx0zsCI4yi'"™7t tGtQiCv&}/$ar4A Wai CCY]'lK1>uV=;5"Yt+Z|_]a #+Hs13I"Z8T *;$cF33uA H8œ-='*]o6} QZ""=>R`A͔0W9Bb?h~S3=lq FƆ(jx0`4T6਴cO~ĞR)z^1z=6Pzġ8t11:h? F,xY7M]0"h xgc8#> /CtGD,@Ap;35nkC؊/$zAc?QR: uQb副 =iOD𝁕^xNJ8:qCvigbw'W%… .F\R.\pυ .\p .\p .\p .\p .\p .\8亦C*IENDB`chessx-1.0.0/src/gui/analysiswidget.ui000644 001750 001750 00000005017 11400467355 020562 0ustar00niklasniklas000000 000000 AnalysisWidget 0 0 446 268 150 80 Analysis 3 3 6 0 &Lines: vpcount 1 7 0 0 0 0 Analyze true false vpcount engineList analyzeButton variationText chessx-1.0.0/src/database/historylist.cpp000644 001750 001750 00000005205 12223260306 021243 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2006-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include #include "historylist.h" #include "settings.h" HistoryList::HistoryList(int historySize) : m_unique(true) { setSize(historySize); } HistoryList::~HistoryList() {} void HistoryList::restore() { AppSettings->beginGroup("/History/"); setSize(AppSettings->getValue("MaxEntries").toInt()); QStringList list = AppSettings->value("RecentFiles").toStringList(); AppSettings->endGroup(); setItems(list); } void HistoryList::save() const { AppSettings->beginGroup("/History/"); AppSettings->setValue("RecentFiles", items()); AppSettings->endGroup(); } void HistoryList::append(const QString& item) { if(size()) { if(m_unique) { remove(item); } if(count() == size()) { m_data.pop_back(); } m_data.prepend(item); } } void HistoryList::remove(const QString& item) { m_data.removeAll(item); } void HistoryList::removeMissingFiles() { int i = 0; while(i < count()) { QFileInfo file(item(i)); if(file.exists()) { i++; } else { m_data.removeAt(i); } } } void HistoryList::setSize(int newSize) { m_size = newSize; } int HistoryList::size() const { return m_size; } int HistoryList::count() const { return m_data.count(); } void HistoryList::clear() { m_data.clear(); } QString HistoryList::item(int index) const { return (index >= 0 && index < count()) ? m_data[index] : QString(); } QString HistoryList::operator[](int index) const { return item(index); } bool HistoryList::contains(const QString& s) const { return m_data.contains(s); } QStringList HistoryList::items() const { return m_data; } void HistoryList::setItems(const QStringList& list) { clear(); for(int i = 0; i < size() && i < list.count(); ++i) { m_data.append(list[i]); } } bool HistoryList::isUnique() const { return m_unique; } void HistoryList::setUnique(bool value) { m_unique = value; } chessx-1.0.0/data/templates/pgn-default.template000644 001750 001750 00000000702 11214744737 022474 0ustar00niklasniklas000000 000000 [OPTIONS] TextWidth=80 [OUTPUTHEADER] [OUTPUTFOOTER] [MARKUPTAGS] MarkupHeaderBlock=,\n MarkupNotationBlock=, MarkupResult=, MarkupMainLineMove=, MarkupVariationMove=, MarkupMainLine=, MarkupVariationInline=( ,) MarkupVariationIndent=( ,) MarkupNag=, MarkupAnnotationInline= { ,} MarkupAnnotationIndent= { ,} MarkupPreAnnotationInline={ , } MarkupPreAnnotationIndent={ , } MarkupHeaderLine=[,]\n MarkupHeaderTagName=, MarkupHeaderTagValue="," chessx-1.0.0/data/images/circle_green.svg000755 001750 001750 00000021517 12062314776 021152 0ustar00niklasniklas000000 000000 LED Circle (Green) jean.victor.balin@gmail.com led shape Open Clip Art Library Jean-Victor Balin Jean-Victor Balin 2005-08-21 image/svg+xml en chessx-1.0.0/COPYING000644 001750 001750 00000043131 10622575745 014663 0ustar00niklasniklas000000 000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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 Library General Public License instead of this License. chessx-1.0.0/data/templates/000755 001750 001750 00000000000 12234477214 016526 5ustar00niklasniklas000000 000000 chessx-1.0.0/src/gui/helpbrowser.h000644 001750 001750 00000000725 12223260306 017671 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef HELPBROWSER_H #define HELPBROWSER_H #include class HelpBrowser : public QTextBrowser { Q_OBJECT public: explicit HelpBrowser(QWidget *parent = 0); signals: public slots: }; #endif // HELPBROWSER_H chessx-1.0.0/data/images/square_red.png000644 001750 001750 00000013475 12074576333 020653 0ustar00niklasniklas000000 000000 PNG  IHDRw=iCCPICC ProfileX XuXUͷOrݝ])R."RRJ)*RRH6 (*܍ߕ~=k֞=3^^XC`ZBâȶz.׀hZ/Rd?ڭ|"WFjoHR(_")J  f$#D{VOE؄ycHH;ħ`|C)VQG24.G{M//=X'FxןSFۙ#%X_k{x_e;?h8:A/>dꯝ?;>1dݞ=.@_ /]ƾ!{ gX||#oTv{>~Fd={xȟ5h۽y s؛C/xRoln!D"W4$-+/+'vЮ˶<-06ܐeM; =R49л7@ et!0Vw@ a@g@(Ԁk<C1x^)|`lB  ⁄ HR C\ O B%% ݆h zMC`J悅aXօa{ Gqp |.+p ) ("ŇBQV(W:D*P vT? j Ƣмh)&#t ݋~F/c0 :Ƥa 1W0͘>3G*eƊ`U&Xl6=Žag+8 'YpQ4\1*7[> AAp##Qє11"="#S,S)=)f0)sss#s .]_ q5VVV_LX7x قβaG۰fǾȡAhx ssrsVrspqssssZfa ī[˻gwoo_߁?:@@ ``K! !UsBBk"N­s"""q""EDE#D+DaTł΋=ŕKG%` e@cI50 )J)]ziifi dVo222gee~*ɆVɾ3Kk['ɗ?UR0R8ЦCQBWRRҶ2YAy^EPSLeBQZ5[FMO]_Q5454WoF_KE)m>m/ ::>:Wtfutt~ӓ#52@d:5777Z4V272502%֚.5543/1o!nAh-,,_ XZYc)d+g`o`aWgjgcA!ڡǑͱq)iY KK+>)=?(r0;{=/[O':-/+ oS2E>鋏Oϼoײַ_ߜ|v@aB~`I `Paaa O P(X$DB#ۢphtjtVLia÷bbb82gw9OIKHJ>{1SL4NI"$'=JMMyD{ WJbLqj}u9m"]#$dɑ ߙ>YYY[٤SrN;=s LؙgYg,((T,,?G8}nȢXLVI@ɳReeek}Ώ_йPUUq1%K-ʘOUUU/^aue:zƶV.v5km R 3_ϺnD|Fƞ[ʚ3[#-Sm.mcnk7ߑS}n={9θΕnW?3{~·TlRjVn~yDyeTe}cO _HӬ>lo9,9[xȼ|K<*B"bJܒtRh59r J*UMԔԹ5Mhviifeg囟8mU )v'SRĻt ;A &%-0h,eLBj8*,es#q# KPiٓxNr3 d3V;=gO G=*,~X[Uv|ۅ򦋭:*V>zB-s@Uk ;zt9XkR[;YwO;ݑәU]S~mw u w=||gy꓊e?O zq+*orz{}37?~LtheNo^3/}mv{b%el+ko*H r-üǿ4lBv4FqSzSu2,l~/8* 6 +/Ȓ<&!- k,!/H)-)O1yj ^v;)i3Bh?l\|/V _}tǍŸ+I1k랿66䶅~PcQh"`oKq0L)FD֎-fI*6VLE.j| o57K4K6J]n*[#W%QTRr 5>KM-E}]n=N}..C^#^c^nS.36sf ZK8+jzfvn~aq˒ns1kϴGـ๐ٰC_Wp$}`rGꎶ"t q(i ĝ괲3'S3b3f[=#r,c.UE>U *Z)^,Rl OG/_ھxg{+kk]k={<\1}GFfFdg=N4O6~YuΛGENO7Q 0;9;s间nߌ+. `YY&$V ku/ &n ځvG؍ Xe 9C3HzəA 5j0 6ELS; BdU`C dt"=`:Xv+SQ3H扮@Ha1]XJ5sSC# %јHEAJK5AmNMNL@DLw^~a17f!,,ˬll/989xyy DD,işHKzIIJK?) 3Pxx_rJjZzƹ}5{u&tV153236aɶl]i3aGmoxiE@۠;7B6.q+'z~lkt|QcUBI5'$R)0ɜ<;\h~D!ӹ{ŁeO/]tyAuYmL5,7v&[x5ӳG/5`9xoS/a|g;;˜纅?wV׻6E~`? @ 78 C|[ $  CTP?a~:GкdtŔafJTNw/oPxP< ʈb,#*5j!rNRZ. :1&zQwoǘh*՘XBX ullF˜vox2 nT!saFw"t %) ӕg0بtN9Q*IMYyVvNn^~1YyMVhky9 nnq<ռy z g$?>vA|B1IPGQ'Oeg՝F`K6\/}0j * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __DATABASE_H__ #define __DATABASE_H__ #include #include #include "filter.h" #include "game.h" #include "search.h" #include "query.h" #include "index.h" #include "QMutex" /** @defgroup Database Database - classes to manipulate chess game files*/ /** @ingroup Database The Database class is abstract, providing a common interface for all database types. There are methods for the loading and saving of games, and for performing searches and queries. @todo Add name() to get just the database name Add isReadOnly() */ class Database : public QObject { Q_OBJECT public: /** Standard constructor. */ Database(); volatile bool m_break; /** Virtual destructor */ virtual ~Database(); /** Query file format */ bool isUtf8() const { return m_utf8; } /** Set file format */ void setUtf8(bool utf8) { m_utf8 = utf8; } //Mutex operations void lock() { mutex.lock(); } void unlock() { mutex.unlock(); } //database operations /** Creates a database with the given filename */ virtual bool create(const QString&) { return false; } /** Opens the given database */ virtual bool open(const QString& filename, bool utf8) = 0; /** Opens the given database */ virtual bool parseFile() = 0; /** File-based database name */ virtual QString filename() const = 0; /** File-based database name for displayng (no path and extension. */ virtual QString name() const; /** Closes the database */ virtual void close() = 0; /** Returns whether the database is read-only or not */ virtual bool isReadOnly() const { return true; } /** Removes all games from the database, return true if successful */ virtual bool clear() { return false; } //game retrieval & storage /** Loads a game from the given position, returns true if successful */ virtual bool loadGame(int index, Game& game) = 0; /** Load all tags for GameId from index into game object */ virtual void loadGameHeaders(GameId id, Game& game) { m_index.loadGameHeaders(id, game); } /** Loads only moves into a game from the given position */ virtual void loadGameMoves(int index, Game& game) = 0; /** Saves a game at the given position, returns true if successful */ virtual bool replace(int , Game&) { return false; } /** Adds a game to the database */ virtual bool appendGame(const Game&) { return false; } /** Removes a game from the database */ virtual bool remove(int) { return false; }; /** Undelete a game from the database */ virtual bool undelete(int) { return false; }; /** Removes multiple games from the database as specified by the filter */ virtual bool remove(const Filter&) { return false; } /** @return pointer to the index of the database */ Index *index(); /** @return const pointer to the index of the database */ const Index *index() const; /** Returns the number of games in the database */ virtual int count() { return 0; } /** @return true if the database has been modified. By default database is read-only. */ virtual bool isModified() const { return false; } /** Set / Reset the modification flag. */ virtual void setModified(bool) { } /** Get the Valid Flag for a given game id from the index */ virtual bool getValidFlag(GameId id) const { return m_index.isValidFlag(id); } /** Get the Valid Flag for a given game id from the index */ virtual bool deleted(GameId id) const { return m_index.deleted(id); } signals: /** Signal emitted when some progress is done. */ void progress(int); protected: Index m_index; bool m_utf8; QMutex mutex; }; #endif chessx-1.0.0/src/gui/renametagdialog.cpp000644 001750 001750 00000001561 12202152776 021022 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "renametagdialog.h" #include "ui_renametagdialog.h" RenameTagDialog::RenameTagDialog(QWidget *parent, QString ts, QString tagName, Qt::WindowFlags f) : QDialog(parent, f), ui(new Ui::RenameTagDialog), m_ts(ts), m_tagName(tagName) { ui->setupUi(this); ui->editFrom->setText(m_ts); ui->editTo->setText(m_ts); connect(ui->btClose, SIGNAL(clicked()), SLOT(accept())); connect(ui->btRename, SIGNAL(clicked()), SLOT(slotRename())); } RenameTagDialog::~RenameTagDialog() { delete ui; } void RenameTagDialog::slotRename() { emit renameRequest(m_tagName, ui->editTo->text(), m_ts); close(); } chessx-1.0.0/data/themes/merida.png000644 001750 001750 00000161456 10633464147 020003 0ustar00niklasniklas000000 000000 PNG  IHDR4RsBIT|d pHYs66BtEXtSoftwarewww.inkscape.org< IDATxwXǿ. ]AcЈ55h[k{(1b,&ޢ{Q,(" )Xvvq>sΝ3;;w2"12PPPPPPPPPPP0CAAAAAAAAAAh(  02PPPPPPPPPPP0CAAAAAAAAAAh( a# c@{a3JDY fXED;d6IAl`N ĉ:t%mQPPPX0U5T{`1U c@2 ^DJ>%DJ,8q_~e|6mnN2%Zn{ncPh\ccEo .!LAA&ٳo bŊ/^0&3v @'1("R^((Hތe;m^yC{1 %H)9b>^reߍ7>1+X1_؟VBdpN1LdƘ+cl? 1#9g^j wT ׯ/͛ؽ{7N:'O`Μ9埿1 &X5'^ p1Xk(((Ƙcl[ OOfe9V9Q fAVVV.]r4iСCkzڵ;lٲv99ܸfǎÆ v᪅խ`y0ƼPGc*|G,fNˣ^^^زe *UV_~%F?m]c: 1$T7߀{9PzK@41-ݻwz]OOO8;k^c(]:YYYHL|{3:88<ץށ;v"!!-['"Út?|_o>C ׷oSUh+cՈeؤT3Iy!K'uvQm$OOOsF9sk[kXY S,e^.../^ nUw1:f6pqq;wspp7 u7ozꥱN׮]~z]3<<Xʕ+7doΏekƉ'u_~-[Y4Xxu]ӿ7n(ٳvgώKHH:u]*X.OtV-sssäIиqcɓ'pM .V-`Mh[EޏX2kkk 0:uB +\r~-9ZjX "rU]|w$rxyy5tV>cʺbhԨC޽{Drc-reBhO,(YdlŸpƎ$a>};11񲕕?Rm5jT~mi7o޴=z^-Tpvvƙ3gTP`oM6šCTOHDOLc[0y׭[ΝƄ AM6ײhY!Уa899̙3(W\A/j֬nݺjժsQDTk*bf ''O~$TЀ1gDc.@dpQF͛7{9Y(Guw1V8e Y_v9DEEի6l=zzҥtw-`_VZX~=? ;w,?bĈD OQ ;vBĈnt,Q1֚1V1o|f5j$\\ ,ЪC}[sfⴴ4 tcF6Pdɒ5k!?Ƙ#cc)cXIpc. ƺu>nܸqرcŦ/1hРϞ=[R7oFdd$ϟ/8gÆ ͛'KP\^{x5j{cOHL1։1) \S~X+=t9Z3yөT-۸q#/&TYjXa4''SNz`911^ps1 cKW}ŕ4VԝDoD} &1V`~ڵk}W޺7aaԨQN7o+tsB._޺uka`^2lzMxC4*UcccI0Z*^C ?x`=ztA@%K|~uapa#F7?yվ}3`^ ʔ)kkk޽{m_DW4f` i˦ދ0??(GTyQp*7o?Gll,JT{G;wbĉ3e]>>>b hNcX ޠMw-c/mEo13[޵{Up@.`c[P/AWvVv?P]$v*fD7o~3 WWW{{{R=b ҥQ/_Tc~I={ʔ)#/;bĈ:}ΦZj M0!l"p#={H999bKn~,ns}/pע@y#F?DD^^^kmc=C;v1cP>}N:RRk5矿i&mr5p|_ S德U}grۥj|8_ׯ-9S %~yRR6oތya8vLt/iv` %ԣJ^X…lIIA7N`}nT˚5ka𳳛ÏrAhB/,ܹsaL|p!t۶Ź0ƮZYYsѣ+qhݺ@ӧOSyR @we?psss޽YG)#wy/ؔgΜ9ݻ_9PD=>mNCΝQvm#!!qqqA"n?hKP9'O"66Æ Tt {i$=!njPٙ<66ݺuCZ°c5а/HC󣿖L1s@B j/~? `% \&'Cw%'55(fn5rۥQx<\쳼@[5 fCVԮ]jَ;``XdkHG ʪUv]rC6>6lؼ7PQ <8!Dt(ZҜVbFR>ODtހ $" n}up!u2|AD{ ?\(Z|r!.&|B$RXfePf0ӧOZ)?CԵ,e`VTPaX|h\[ Pn]{Hܹ3߿/"&&-Z@%Dr%ƍ{9h ~ KYYY锧1J{@';:QeZm6R ot+^z ] U >סo%-ua9hی2(^wZDb(D`(˗AmM6.]*x-[{zU-ɌF}WTPzǏBCC1rHرصkƌUj{-~in۶mﵵ`2|nnnX*URTM#DI 3o隞?*ӧ:CDh(l+ ~DVN][(*rho  Q1$"]PK/yPŋ[W{G/=*ve( ͛Yeoݻ9RPJxx ;t۠1r`͛oŹsptVV?ZWAlPRceS'>>^"0Ɣp7/_x… t#"0pPx `^S> v|ءCF[ \h y"Iրo\_d/ŋ%V-8K"0)Y-R0*DަGعs'Q)ClܹӧܻwϖB,-zcǎ!..N-Qj''kOUJ[/_Ftt4ll=zGM66lhq F16(777V+ /di̙YfhAD8t,K/ R H \y]"FDRP`2e2KXcypi'h \a]eaiP }Ld7Av^|҉wGzkKA4رc\7;/vwz'A֭[@tt4֭[ׯEǎpBxepݻ^b3Rcʕ2e fϞUV!33Smۜv:t؞z`jyձk.L>"y˻eE] 4p;Rf0"""0|8vƌg 1X1G"wD ;AرcC1<~+M&cXc3yƙΓ/,Rf,u(xtq֯_?oz)8pDžW`i4GLV6ٳ!m={6JN\˗uVi>|֑Ͻ{hȐ!࠱uI0`@A-` iU#m+!& bS.%tO0bj܆CqF=Y~GGGrssX{LN7{E z7|ChѢg$Wd~3Յ 0Fe@˗806/V~ӦM Ν;Tn]moMqH .ٳg3fTn~b\#\Fl_6|nkLmշ()%J ۣHjccC'O$m\vkVd>3Յ6 0,YRסCjٲ'gΜ!Sq iƍFћIGָ[```yQqH .4h@/^qIR p!Sm@+ÌtSMԖBm hiU侷du4}tZn_nWTRKq`~owDD~.\@j֬YC$338@O>5[d)S&g $7/_jI&I!ܞ '| k-3vZshAY#O#pM/4\ (oVu`o*VHw&M<~"##|;Xv)R{\>urr;?Qݞ-.W%KLKKcRuƍۛ$Y3gl"y<000u M29m۶]TR&LuA.]Lj-"""Dw۶mqtUt[͝;++C]W$F0F[]ԼyslٲEOL236ωH>>fJfo,VUVkn֬YRfs<xzj>zaoV7n8rrr_r!;Cz<7X=w _k.җ>L?}t8ϧbŊ<]vՇرcݛ5kvM?c1Жʝ;wZj.]l%31Z>7ohDn*B3W^% 2Xڮ];z!]FDD|g:X_QȐ2#x([֭[Gk_{!b#], N[=nV `8 4^\RG}DKP`==~ nӿB|f=Z>F>>}V=y 7pTTJ{{{IGW\],d{sg/_^|)I˖-СCE3X"LeݪUdgI!$1v(3c111R3Psp;}Է:G P@ݮ|{/^H{_BPʆN|r:dH IDAT:$S%y.z^ tN> e̙|r8i;pS_ko+wOW6lP-/_VZ_`7AjcY/>bĈnYRNvss[k;-"ɛFO nSH}ЦM|N .[lMvvvJpppژ1cڴ ܢ aTD rCnA7 shT HUeeeQLL@K60g[|{~ {ï5+:|Po.fS][xBv5gsK*UИ1ch֭z~ܹƏOaaa]X L0\zD. +++k›7oo߾o?ؐ!C nSIVp1OԏvEyfA-{*A?hŊ&NIIIb6jK܀(} M2=?Wze͛7 $$$?@~!HH%?UnSLҥn+++DΝuJi.<|ի'܁!3𿩥M6T}QjUo5m9)nsȑ?9 _po~+U:t0ݢDQM\.k_T5PDU]t==if:>S"EڠWHwTu?zR^^S@u-#u=Jk]}KdAqr^IpquunpȽ{f͚R~,M&N 5kNIIٸq#m[[[,ԟ yFXŊ3:tv{LlY maaausssѣGӨQ#_VVƢ0a>]v -[l`%6̚5 - UR'___1`(JU,,.F<RdIɭE@@_ϻ rp2iҤիW7(dҢE3g4S*ժUPIll,IW_iĉ%-$''KUR%-**ꭏp bjݺ,O.;h% jaFDDb t豹[pP]?IOR֪UHl#8i?O1{UMO?DIII/o޼]vСC\rF?7V>p@X*k[[jJƍÇ4K3_m۶)to A"~0`"bѢEY1ƹ\DvdܹN۷?Ewܾ5 P[ԸxbcڵZڠAs{l.]dF-kܦMQr֥}EXΓ9SUGŋb~LUݿ_ z. =0|ySl} 6W1p͞=[Sb5jD .[nӖtzoFTTԿFs<7Hf#I dɒ,Mʖ-_n.o>7[SׯkS lrSիhiŭ V.P֖-[f333?В%K TL>̅A\kmx DDݻwCoj}?u ܚsmll(99DO;RjX*f3f>@;w}xѺuk+rJrwwc9DQ /m|a4?JNNUP!Yo,jY~+&&W^UV2Z&>DGGW?~ 2ۙ 7e~Z>OOOf̟?7ӱy_?3/p_@o1Oۯkkk]:u2X 駟}yF8p4hGb~f'kYPQ񑌱DtMG}kvZբpX]A cstRE(UT]}`|n#cUH)rc}mFro߾"_#7FƍqQ̜9۶mzu+WjCǎ1qDT^]k}c-ZYf`/_f 6l(KDK2ƦcٌG8HRVwEa 84h" L?~\͇/^#*cƌ1 "!!dCSg|_0hwǎZE!wP5=:M|wy>31#t<}Df0^6|{AׄHZr ʼn'($$Do=333|||4T9s[e*NnU67i$ј5DbaW͛Uvwwd>>b3M-cu'ݻwd2+PM+ :Zo:`0,P;#Gg>cgFp/ ǖ-[PIVZ8y$z)Y͛70$'O4٬eʔ;&p1fi;% &&WC4?02A` 0Lƈ#߿EI&ngPtww͛7M"""#F?"{Ϟ=wݻ6mZ_S ZqUo$9=z`2X`ء9Gs.]y扅J~O ;/iX wղU ꉄIi|ZdܛFΝEDUwz ّA$\Q\ƲeРAQ +-[%?˗/Yߏ?(Z5k`ٲeptt4Vc͛7 H([1VVV9r"K*hesD)]D *ҲeM_vYΏ?w?=nnn%:J ;::e),4FӝC5jbtm,4i?&sTCZ*_&-:۫g9;v,_Y-z?j:EBrtAYRyzzRjj*͛7;$]lY]V{V:E^߷o Z?}͉(YMdeo.Q4TPA-*;w1fA`xq"/Z:???1&5BUtxh(ܛ.]GGG|7%|EFv<ӘA**U0۹j٧~*L\62>z3nyҕ+Y& ʳ]O>ĔETTf̘!(ߺu+]NpvY_3fH~o 4@Æ  cܤ7}TZUrs[Jem߾=\,44P)DMY'd?f1^|ܹ &Ծt?ɸiM>|#F@׮]r%YYYz쉕+W˗z_?::Zފ,: ԫW_c]ZhLK): 0*U$&JjF$x mcXA m3:1c ߙ'N7DsJ#vI&0a36Ǐ+iq!K<GGlLbrh" i>ajdggZ?^nO>q^^^5kִMC\~ݫnܸ!?CeҤIzېNNNN|]:hT\ݻw/ɓ'T_`+kj]5DDk֬j"TIoPCjժ%O"~_4h~ݮ]JNN`oU<--Mҧ۷tAZ]GGGq Onn.988 7%^sΧJ1| MӨQUoYCt!>>^f~2YΠAD˟>>4iѥ@Zd ·jJ*i`@eƘ4V-ZN6FX}j ܃fmH>Ě-1 :T˗رcG߿VgСf΄d1UUHII [ +8q? fe CHHȟwU[غuktY.f޼yHKKS+ׯLֈӽ{w͚߿oYit,x@ʖ-k!C~:n߾ѣGx W\ȅ `8ϲGɈ~ذaxwz0:04i"6?LJmZPSx :)Mݷ1ofrA)[ 0|Ӧ6]n1WWW$fDX7[f̜9fVZ*77z,2P0:=zܷoeΒ;#Of0a/V(߉SD ?o޼AVV`'''Sh|}ŢhF7ZiӦO>!5k ^q"rcCt9..n?4jƌzlj.XݫW/9 ;;Mh)x/HHH!a٦M4" iݺ5Zl/sZk$2{`*ˢm3VVVT:0\SNT.+S666'޽{b0%T~yrr)0 RKK ޽{EJY+++ 2D MbbXkI&6 \jP;uD&tTJJ 7O$  0Jff۷oתUKj`ڵje P~׮]Oɩk0 %'00m۪oSi&lݺUu7oFѝ'"~6#Kg5'ZjU֭[kX,= 0Ƅ >ݾ}Zຝ/_.Yg;VP>}txzz`n|ٳ-gvoU["?2ru2 v?;C~eXמKdcxQe˖EDD5c, ZM&z?_Sf@l֭ưa-9cj;߰ar֯_/EwNݻwe_ ~GDrd(C(;o۶~I&8z(v튜5AAA8pLV醦3g 6)E eP[y_T3,?zfe#--M2mʔ)(UJ/c ֭Xf^ 0Tؿ?&M˗*;ܮ&xm5kdV;3IQ Ń Tخ iSa"jAvvun4^TYZr%"¼.H3gQXlsΩFլYƍ$ɓѠA8|^ze30 6|8q&6Q NJJ*Y:hX;v_cC)5ꊙ3geSOyߥJ[ F[M6̙3ѷo_-[m۶ID/00< PhFڙ|3xbB$ (G&ĸH} [MD/ѷo_A&ɢ 33&L@Ϟ=ظ ]2P(4WҥKRGaʕmfJ^ubƌ|?~l mllvܹsǡ}MlRQ_?":u`ɒ%>}ѯo>7-i!_!КV~zu:Dw| *U JBp5@TT<)éSн{wz%[/`O jcA*\ae.^(9*"{,ׯ#++_ 昄v-!Rg ŶmۊFj_}<2F˃^J*K.d 4xHf"֭[Vm39sZRll,(Q!ZYv-ZW"ZEviӡCNfp/2T޿:xjtt4eddPE{zzҿKQw}Gю;A-Xrssiԩݻ7P\\6vMrrrSHǛ IDATޞ $ `$$$HMrrĉt\bR駟RNN|MD4bqع-e|{ctym N6`rrrL2bL2 S 1I}/^l,wӶm4}w"MNXJn?ŗr( .]pHMݟ={:uD]p@JJ }dkk:44QddP~zq_wĉEjHJJlo-;p;$,N:bog(BMJ*ȑ#iŊt)JII3gІ UVZ?uԡ/^`РAZClmme˖k.}j*/T1F{Gիskժ%ݻm6С^!f_ ,n`A;VZ%Yz)9B2{T|p3>1#4}.'_ S EI*U?<ҥKuW^-%زe .]Z㏴5m4]vͥG%3XH,ԣg;{ӦVwww:rq[H߿Ob} !?M-*`n4jԈ>}*999tuڼy3M:uF iӦollNN۷ @>5y{{SfhԨQrJrYYYԶm[(ԸqcS,YRW,0_mXnf錖E"2{5/h'5fR^, tr m. 0K6mS.Ž{D,XPH/NQQQ?~~~QQQNmXR7l`TK> 4(2(^[[[?~<zK1cJݟC6`ˆʾ_gggٳή(\ >sKd߼yf鄖EpI8흱}v?8P.s/+20/8p9s+ |P! ÇTvmgȑ#<{.m+[l1=>4Eʹi$ѧO/ !c / /_6l@z1''(99={Fz["}'"1裏zqT ] :_R[l_mV .@o2{(ܬ{x勳y=pP%77._L?3+WNSd 0m̒/^˚4i޽{;ɖ-[;v@ɒ%bDž ЦMܻwOp VILL]uV\y$__ PtBk*S@JJJ3ߘ@D2z֭[D`` vÇs玚$&&իWxE3 ptt7$00GŔ)Spddr@?\\\0tPݻǏOڵѵkWDFFL2ZUTcǰe^۷o]YWWWɓ'Cnh! y>MbEڟiiiHJJ£G$<~HOOׯՄ_3h%J ???ݽ p٢:v'NHUJD+a@c/'L_x"{$c !!! A>}xb̘1-)Z1"7( !r o߮+9ذcDFF"--Mp,44g՛Ԇ_ְaCM &4ŤqXMp{dݻ3f ƌc5s<pMfD$x |K "/^qqqHMMٳg# /"#>>ժUCNNjq^d2K'cm)E`ӇbΝعs'v]Y‗6m>͚5C_ƀzm>UFcZJذaC,Zy5FY ~f=}4o޼,X'O{}||,cKue&Hbw}o޼|=d[O(0Яx}Y-R&Lx>//Ok׷\83c߾}zOȜeTnnرz 蹥5\4jW^;222UO?ŬYZ;мy]v=|\,^Y~yx ɓ'=&~ѭ] Ǻu޶H@D/쳯/233Qm۵kjfg恕zR'Wvm$''ƾ}w^Zl{ =:v숐,\'Jd{a%!W|X5k]vCv#vB*HII N<СC8x N>][;jC10^'/^z^w8N:=(**]^[#Jk8i/UVMo" o +V0V2E,Yfiq9'NЋl[VW^yװu֠-[ zjŞo>zꩧV![$4}رr5qm"hGJ:111aqFzꆎwQ/ea$ҲѣGD-ᄏ*W[+0gA0Q &[lwzmڴQJ46l\\\0b gɨWd??4Pc gϞ6;9 z1fQs4leSbڴi+rMpPw% BHHz_}پ{KP//UT&77W^5DŽR;a-۩WsaD+ʉPe1;qwwp(ՀŰa2ǏHB&M_0(6Ci 1~>>>zXHH'&&Z V2W2zL &ˠA;h߲e^͘1cwqn8""o߾mL||'<%S Bnڴ\kcǎmT.qΖ )&?Fq޽W_yu811srr,C[_?c~饗[nzLHD @Kk}'74&u &&&@VyW zPZqƽbH 㤤$;^Xf)3glwqqqVn{lݺU;|bnҤVΝ;g1N:m3gŝ:t$aÆl2$W9=|ڲȢ8pPU8rА _" ?_5E:ۆn_|ٲp e{Ǎ7ѐr5t֮]Nd3f? ޸q^zZ/^:7 ~;[+o=kH^___޹si$&&ԭ[ة%k7o'==m_5+<`޽;k׎4iQQQk r6mK.ܷo_3f gyfNIIby6mnGIV˗;ĊDes ߿*vwc/g:5Yl}g)ޮ>\k?a<OVO:q&R."##9%%EFG֯_tJƈ#2RHHٓgΜO={yy ବ,uݻwõ<䓇w]V^8`])u)f;7ѽ\e˖8y$N|͛7 hgς!=&M|񨨨,kȑ^jsQQQؾ};bcc-ay Ev:0Kダz~~~ǝ;wNwAnnn9D `%rV2(3G˗4\|oߖmYzO M(CCC(DGGN:&3z8j6JXZZd9rϟGjj*Ґt෕E~~> )&V6-ZuzʇSge=TZxӸ5˗7,R^xC Xb_~ÇޱcG7n "##Qn]\~]}3LNN{gC⣏>֭[u7cE=z7ˋXرuTpz###ZxSGB ePh-[D-#,, ps3vXZZ\ܺu N±cҥK)  SHбnfŋ={VP( U IDAT廤ŷQz2e˖hժށjDpKe:u .]‘#Gpa>|G푼<:uDtt4ZnNG1T+DT ڵkoܸq]DR HNNnݍ1sR㥗^zhdӓ4ȑ;xg~駃1sKfpʕ 4= p֊16P իN(yݻwwb;#r'5ˋG[lt9Bܹ';\V->(Aki]x1O6;w߷m駟wyǐw7@)CјxG,XP|'fٲeI}Ws*ɕ \=U4v{###زegY!CN\0nl4~6Y[NzWWcǎ 6Q `e5k֬M'۱cc)))O<ғsF{gp9Zj?\sm?e;p5]kJ[QѦMoQQQ EHHBCC Ν;J8x /ܹsTy!˶"BڵCϨ])スQTT59,{Z^ލ76gUhԯ__4h#""Bmgdffܹsz… 9ADh|'2UVGңGx u]" c붔n Acڵ|7O<yO>RKڵIIIm۶-Qzu9v Qpp`޽w6\ F^^pM U@  M &z^z&OfFFF&HMM5vN?Tat<ԬY`?C𰥌SV-ԪU :u/))Ajj89w˶ RPXXh콫+~|OOOxy B=p,쪔zO>ŕ13rrrpM֭[xcfey^^^ Bpp0~_,uݭ[7ގNXHd9666PHÆ E kA(GuΝ/kebw0RXXXeQ HۦXr3۷ FV) ",_ܣe˖|raW? 3 qr(2O򐒒 .ƍꉣ׼M(ϝ;ӧOܹsHIIQfffVQXXW~~~dkѲeKIڵR[^}]Cl첳o>ݻqMBNNwG۶mѱcGt$5™3g48y:z Ο횐CmaKVzzzEufggrW0٩ۚۧh~&"L8Q)q슊"V Q,o[|.%K.hK" a2Ek(~ &LPn׮͛ɓ'k63Q"r .$T_iP!X`{(--qL݋7n(!Xe˖С:լY;wQ 3߶6׬Y3,[ {޽{qc wȑ#8rzpddZوU0y뜡 %Km50f- >|)$"Urz饗wFOMw;~뷛+ = ` % `|...rIIVsXXs''' 800<ٲ8,$SjKVn+eC5Ã{N\^=C*o4)ݝ}}}9889228 Q#}tUҘ{))),(**24& H`g{ "̕A )|"22B~~>QPPK.ի@U*P,_=zm?ltk3czN뇄 :2@X<]zu4j򂧧'HOOx  ms0s\ BD ),,֭[e?Wpp0///8-{5>??nիWe xczlêUpTvm#00KŷB"77To|֭~ǖo[3d7WU{lnV3۔K.aJa7=: 4BCCѯ_?D; ,2S"z{F!..CE=PNTVܴ4ݻDbb"?n՟Hj0b{;~=̝FDD-.]3fࡇ*{b޼yoUpwwGӦMѪU+i:t@&M 0Laa!^`ժU74!d[jehLc;K9cƌlYՁ/nꌁb.l3fLLqKD (Њ2}tV`Ŋxg +r >3;BJ2ydܻwO3@DoVtt46oތ+W`СC(Ί;z%K˘:u!n$CDZw=z@mfCcQ#(%dIٳT)A;vddf"%p(BBB+m{o \BD %vf͚ jMOOGJJ PXXNDuaÆfHCBBϟ+V}mfNS]W)bV:~ɓ'ofE6 99j#Ҳ |`ӦMذanUs\)zxgЩS'}ur~ 6l֭[9<~6ǣ lyٺu+n WWWo}E~P^=DTǏcÆ ذa;VQ@,[rO8WZZj/gúvK{`b=ק5kTB/-ZFBhh(>slٲW\ڵk#Ƣnݺ(شiϟ_mH Iu!  ACaʔ)3fE󊊊p%?^l7RSS+\) F1uT4k &M-r'f f[ eb۶mضm&M~}EǎѼys\|'N'k.ڵK3j|yts(&F ,))={gWy4o͚5Cv,a8~:8qI yйC~~ɓ'K7o^5ldeeErT1wr*F'2gݻ!y8% oURVW^իWk.cDڵQvmDDD!33Stxc e d$"j` $[-.^)SwQGՕM4e+{ov[naʕXr%"""[fVfyt: M QO*^4i)JNNN>V&N8$KX_Ki{5r(*0-Su^յD:u073֭[~:]k׮!==III8~8Ξ=k}S ^f2l/sYD66 @ B@t1b+Vame),O-jCsL eH+fR$_7n2e* 85l؏?j> fi,EJPddd`ƍJ#(gX1@<< R$p[,O]^w3 &TqtAʯ @SH{ E/ ` d f `70RǠZ3Ru0;s " IJn@u/lu>{/ND4:[LFvv3i<%hwg~v\AvZ!p0Y1HP'8 )S1$LQ5HFQW}$[O$W=>dD{ޗ ZC$A3]p+pMDBN2 ~3M*櫞X64,K?\&r0{++2R%;G )CbWaMxz[ (@~P %)..RZ0q"@9pB "1V:^!r³O*:2^0>0 3B_bH+6ZC{kBBgh [kX{J"4liP=al<@k~ʫ" @ @ UO@ @ `@  @ @ `@  @ @ `@  @ @ `@  @ @ `@  @ @ `@  @ @ `@  @ @ `@  @ @ 7!-4p@"|WQ!fVZ@ "`>36L8D 1~`EEJ`L4ٳgPZ@ " !5ðr'$"A;lpĮ@XO>?qVr~h֬qWZ.AՅ!mi Җ3\Xf!c>gW1?e@4k,v5pB'IfC y{ChԮ]={jҤYfVZ>AՀ4P~3R6yqH ` U~$%0Bf.4|>%̬;4Zh@),c,_ b^x6S~%|nC; IDAT'9sf[{NWW[64СC߾};6lۯj8۷O %%%Osu 6MJ D43o<eDi['_3O*Ol.c_P o_;ugE֢п7A̩PY.(...w_{ff%K^i޼yδiӞ\?|Lӧ|~-pXt V*Q+Hy(V R"iZY^:^EuGAD~D! &q\&?E(;۔r'N[`'xԘ1c,9סCٳGoq7|s<Ȓz = %JFq:l.pq._u-8.&+D$D 8!G)NQʐFd0̌m۶5[)S[`^;}ٵMOOOw7oު_|aS84SH"z"@I62sy[ .6w f>kjaf!TX h'Bo.~V SG_Ucfzp yY1ȴ_Af^u YpEw0>>>oﯲMGK[H,e'3'%* o`bዙ o0+7gȷSRKr("w'uTDQS68$w[lp.! pY|9s}ʔ)LHLL ܾ}{/<<~.]us d߰sP2P4*oJaVYQǖ(|GxJ!lBނ$Xʋ*W)5U`8ijqs`?pyxx7b93L]v믿vDGG33xIu,#QnS+5%$au\" M"aYT-"@yBYa6 `8&:ùlP0Di֭AFmnݺCps3}UZZZqٳo :teq< f>S,yyI³zTw<7duE P I10=lE0$^3# Mm#ù3=&C`Wbm3f ~w̜i#{ŭ[qFL8WSڵk.Ve˖k?T9 dDe (3o|_[̇!jC|oV\ y!\ɖG>Fͥe˖ >w\3f5x`k3 @ V*pܖ0ѿ4oibwR;2l="r!v07H1#\d} SfTp:Yˍ&C`W\t)ϯ477,C ~B9btI)DEE_ċ/۷ocX`1C?5eʔі/M0=#\Pb;I&7ˍ,3'CeODBUQ$ +eҤ!$O/ȶDT6#2+MDfgm.X ie '3J$FZ aS)0}۷o?adk֬ʕ+ ((ogiiill~~>60`_eT`6f*eڄhNjEUX71r}|TaVֹUS@Dk_Ay @7Ӊ"Z80|n*<6E'z펛7ob߾{_hϾ}N>qqqFȹaN]x1uT|7o =vɓ>|x̰aúu\2 *B墌>Vf2`*?aSiVbz )~WVԫ1TǬ\>oUC|cnSG&UzZT :U9=K&K.iovɚ_xlQ80W⌶_ů Ugywޜcv23߻w͛5k,0zv'U"A1>VpUzlǯ-lp^FNs e:Gw#PwuHvѓJ/vY}_$>ls t@YIl(΄ V_!shmڴ -Z@vpB&oZjaؿYӑ-w9͛7o׍Ȃ+ EpTpkD$vyuQFS| \VIE܊ FDJ'̜ySxvg7(`ɺ?)33qā?Eyyy޽; m۶E~p\m>~'tM6ł mz|6Z .7o,Yd'|\r Y(cU[]|WYG)/111uђ|U=11իgހ?R-]cgJ_Җ?!EGg@ftE+SAp/S GoTN(T2-8R:hn93337opCX%?g6;!lfoat:ѧO5;\)SݻwyذaFs+gHWx8 Rkik Az]FǗ]WN7e5,0AĞ$84ÃwŦ>OqVlv_~ ooo >yd.((µk׸sF#""^v0H*#5*f[&ooo>}:_~߳߇O:u} @ $w 7tQ)Ax u6[Y:z׫2Q8$ z+=5Afbs(..*}}"5\!yNHnoWS*j@k ZvT~~ah!k`Te۶m0x,...k׮q}FN߿ڍ7s/qL*={^^^߿_~EnAZ3.xTvNv7faE!m1F1YEH jy|S,,#AD?Cr۫f`MJBD>bbWT.gϢZjfs<øwfif6" )VJ>J nۜfEϙ[Xw@3Q^lnjL`ML#,AR6߃"謴Kl7o;x֭fٳu,mLkWDHMM1$HOR/%AD-VtKR#FݤI&Rz@"=i///4i_r5F)w@^|9BBBE3g|H>=2]'t(/oiiV9ʄ?eaݝL;#{Pwm [)=ʑ{=[Lsg.Wf___u"'۰a!ښ(K]!/O0%BRJƢ 쩠찲HI*V':uꤰ;LESs~mn8ΐwԶiڴ)'''1~iϜ4|p.**2z=e߿ ce*݇D8t_Iz)F 0#u5)fي?[dE{jJ#6d2~f.G=oݻwzϱuVʍ/&raɐ;k]677eS]InP-[v=z4X9///R4HKK+x߾}:v+QTTT˔r#GĢEc۷qyYelVXXl\\KW_}_֏gϞG^?: %Q#$ 2OJ  )wd4hQ` H H[W*¢*D C#j7Ҥ2WDbY5Tgoܹss8p={TUڧ@qH[sAZLD4V"zi`g)㡴X`AMՕ?Sv$޽4a;h[__5J 9B( kԨ͛7'|_x9s&O4m۶刈`H["U-߳&7Z;CU611Q չj % n֬ٓ ݻwMrpp0OHSz(8B[6Jw4P,j[L\K wΜ9SnݺfvJ-Zk=rrwΝJeIoFc)//ϨILLL… Ef@"}2aÆQYbGMnnnyQf9GfFDThjDL!Y{A9ی<==?VzZ}<|=s޷rƍh+ PgmuFW\!"1ckBס=뢑fflF]1洣M3ʎ3 ꠆'j_;-Zd*N8AuՔѩK.:2Dg֭[S}}FzJ') 2FEk׮7nX]/^y摻5 {h[υ/WhdŊ#GW&L G%,,Lߟ=?ԯo񲧧']zդzٳ;/Bn2z"[T)jE{=6гX/)t]KRHbRA &Fiީ%IJ,d0mBgGt9W\^x zir6oެW^SYYiڵ+r{1tr5|ͳ($]ofձ Snzu6M6kqÏ\w͞=ۤ:VT*Λ۷o78pͣG䖵%0pcǎ3g}rjUUUa8{mmdxyyARO>ٳy=Fdd$.^f IDAT%o#=֭[AyѣyÚazqM?ѷo_H@G"*PMdO1)Gp5A*T*_Cy8DDu<s";Fʽ% ;wښy|^`{ӦMg}ftR3g`8un޼7oRڵCѮ];DEE!)) ]t1ISNa„ ֛ã>ڵCEERRRеkצmW\A||: 9s M0Aop;Cҽ{wZr%]v1ޡ =z>?8uY'}Μ9zi۶-;v̨>|rҥLO?4=AAvQ3V אC=n8k֬e֭M޽y?NVLXɓ'!ں202[;D"&?#-1%I%oe>bI1Ɣ0 4 E:ljYx.r uFΞ=KcƌڒH$OPAA5xb2R)eggkݶm-\P#T1hԱǍ7h„ IJ+RqJKK{z}}7/J#t\B+`˫ˈ{<;v,ڵ6l@|ئ 0)ܹs9V&$$ƣ$QQ3lK0ۂz,klQ^+kO*(S3g90}<$.]Ξ=y -Xk,Y`.DDY @%%%:yJ%EGG딿xbϞ=dN] #sgl)PO){,=GSD]h=,o߾J5>nB$8qbPT8~8EI &c0Ƹ8[?&HaQ7K"v;XQ92:xyy =,avc :uXSS/.J5gظq#A_H+))wǎH뮻h"β׮]UVY]uuu:鞞!+e'`0 -SDpNy_ 66qs\. ¹ppp-}o:P/uܥKڰaRyy9UVVRuu52QZZJwёSNы/g0ڙ@g -,\i IVUs |zYzmۖڻw/אY"?ԫ"""4򇄄n5J#D"'Oro>M#Gp5i$57cVV zZSD40OFj+JG;OdM6@~W ELm܎^ ;cZ&`zm٨UoR,}\hh+hm=^k믿)éu۷i{QQÄ 8JMM(eN^{5}wl%J ]8EJ&TTT+,,tZkxtG^v9)SƎ miiiSh%v"Dhl )n[#1d4exzzjmݺŋuʩC=577ork6SdⰤ }Oh) |vaƍ6G&'ܖ3wܱM@(Z[cI20T* D`y$ts`570 (((ZHV^:hqwۚoh ݺq;9q=;Pwukc,BDP/x#ce@}}}c,^j7t]SCR93vʘBYY,XޣG 0@#~;4̻uuҫ N]LNnT!yCDJ0%K,ٽ{wG~͘1v&7))3=77mOpntBHFߛW#m:clc-xhid`4Ћ1Oʒ{ aNvH>}l_OI駟}vɓ'wQ|*iZ6UFm:&|- "pɨM6 8{V^_`ǎRSS{̗ͧȳA\|7n%^-Z40H=d`H$c(yDSYpS0=ܣ35U(׿tǎ6mڵkسgOoƘZ 3gmLw[*$ #  Z0 X"Z6c _*RϟO7od(gyRu֜`OxXd~jkk)%%}Q{Ӹ!L>$V_CCC= . &t]7 cn߾ŋիKsIJJ{"=zp}}S `a ̮_0EDñeǎzxx^׮*T*SL[Ƅ & OY%Bױͭ\뫥H@@ZWH)))EVV ^_k.nݪ7ҥKuoذAh???z*gq+D߱SpRv1 'x ]O8EJ*jjjb}ݹ5rLĉF&U^^>O(MJ-|̫N]v~i'Acv*<}t6g޽8~8צ6Sʁ ]ZEՠ""w}skVǚ5k<8)''ghmY ęP(pƍK(jBQ ;tIDccڵz=_E^lA***8=+qM I;sF`޽ ԛ7JB '"z鱂DdwD40D,b޼yq "J1iҤ]v~blqsskctG8wx{G[nYYN =TD6L-ix={p'\F4[nB%:t(v9Ⱦ}smԱZDt0Wx9%v :;2 CM6mC6mѣǯ$ _yE;>={}ua_ }OϹ0ZBp=mDx{{;B<~裏{⮻nם5V\\lLaȑصkIIIĉ6 `tsTcCo8;fE?AS󆄄`̙ؼy3z![e0c=vp̙駟Γ!n0@tt4t": ufHlzID[cIJr sB_;c߾}20<1jJ'M(cضm^p% >KG"k1v7cfb͢\fm9qZcҤIm׮<ĉ1}tYc#ݻwW 0=zycI쩛b`iR\r^| ,0>ʉ oc>>mqqq:t(ЪU+5I ":R\\۷o#++˒*1@'ByyN4m! JǓO> x1baaaؿ?[!tu҄00o'N1cPT{ qΙr5c^ y.08BDz[1k߾=\RީҡC 4Pӈhv~Lgwww"!!ACЪU+[~}6nܸ+WҥK|2.]4ƐJJU )cIcjׯm9bةS'ٳC Ai:NDD { GXX }H$ߤ "\~|2=C@"$${A6Kn߾qhgyxX8_tZ `cl$ vdO ]|ˬY3t۷zfĉ6렠1cL-[DbLMS\tЁs v=9RiREɖ-[Gn~~~y^4j(Z|9ϔJuuuVR(++vE=SԾ}{ڙKs=ݫ~?N}Ri&}|Mq%Zz5_z󤥥Qǎ ړ [ 8_n!t}3f >L'0Cpw[421`HRGb˖-6)**J8pG5f-vIڵk\[nWb Xo{lJ{رVݺuyY[ zOO.HгgO1?op+CTT0z4ٳ{CPQQ@@@qIIF'`~m9>f]htDVp`hكN:SNz8pǏfիsݾk]W&dɒ=^hč1ID|h#00P9j(iVV$77eeeBee%ސMȦSJ/_cjLzW֭Oh<-vtْG||)h c M,tJ xNRaܹCkX@ s\xMDVFh铗^z9___2vEʢE8U͝;#9@!mڴ:Oyiݺuhp>aLcǹ,\S)̙QF=)t$ IDAT@HvCp vݛT*pSRRBu&JU:`n9:u:~:ٳ>C2e ׏%nnnOcǎŋ͛)%%jjj {YY=.N})P_r! N/wy'ZcccepC0[=RiРA'?kn+-Mzqt /Ю>GһK?0 ݮ6TJݻwӧ7|C999ȸqt'$$, yьB c,8}}f.-t7L5k֌/Jh:9 qu{v3wD oϳ䘍08q"Қr}0bm={_unc깷Fd2>>>:ިAEEQQQΝ;&/l<[pQ ر#Ν;g[W#""=zΝ}deey,cz8):. @FDt/Rg~/RhUFjj׏?x^*v_t;' ,,l^iiپ^uO _}Fq!ׯ?3ҚrĀ?&n2-ts8ЦM###v'Y\\4j|fffj|Z19Dt9rȷ[uDII N:%Zqu}RECvE1r poÄVD!Yfv9N:UN;]W_MJf3crss9.\ Ƙ}rjܹݭd)B믿1Ξ=wj/^p^,DGG#00>>>SD6 oMSҤ 33|c۷s:-DQ'jVk/U*US[ʐ<ww1&z83vQP f`+֮]B=(c 3fpȭN/v%62֬Y3322b" 2 ]tAll,bbb$66`VZ˗/#;;ۜZ xM0 6?~pmܸ\RI?^`?!vc|2m&*駟߭[O>.\'JѮ];DGG#::YYY8pѲ<<<̥K,2y=?KudnRp%ΝhL;v2,,Lڵk8|\p(++L&?ݻ[n֭a_wHDN7%ҞTVV ;,,fSVZ雟7|tGLa4r Mj)SxY墼`v9Έ?_Ͽ UXR,ΖPZZ:1!''*L(,,DZZ ???}݈) ͭW}}}PPCsyUY^y%55UT*S*c1v@b (pnp%cP{?cn"2kM8!Q~?<;y}sηO%|W[eo8|EEE~0)[$44CP̙38w4¶UUUvo!!!MFLL 㑘XMO*J5q; 1_Nt`%k<yyyZ  "cι?+ K B0AfPO `O +Dj(**ɓ'$==kCꐙLm111HLLlst])"\Ɖ'$%%EEE8~FzVB߾}πä@`Пc`XCLL̞LA>jjj 6D64eh۶mg^^x@VVƴwwwe]]o5Lr'^µcccRY\h4<6mڤ7۷][r%N6b/:{9 s;$$V;-孇 ӽ{Ew 3Q[[-B@DD h ?癚O:TXB#NED2Dq%ISk /X%B+`DtS3}tׯ. "e*nh,-̙3M:'']vŬY/`޽M1"Zc[[54.m\lԴzTVV :ߍ{MH]]~Zs0ed2CĪP(l1c,.؁-N݌1=S#J7ܺu]h= Duuu-rc=,֮]{u]h`0_k׮(..n*7!!!HHH@||g6meW\49Ajj*RSST[y8\"w~~~C||DFFd^P(4\zb `p2Q)`u@qZrrr~ז> Z9 c,jw7|p^@u@F9ԁҠ 2T"e&mԩ닝q1$%%ñ~z<##+3! u A3joT-S%riZ8mwwwGLL !hGMG*6bu_vhgƪ FR)4 F"<\gC\.GLL bbb0zWrNʕ+qx4***XLLI&Nuٲe-%>;vxTh%*cmm`4,8}]I+,cȁځ?S*6m>L;w5:tCmJ?~cM/8 h߾uqr9zqD$0ς(gCcP$aԩ5r ch߾=y}?smtrQc: rWv@R#"O[,_|ٳg]LyKW[[klͮSdQ .qС>ޢ F8q"t_yyyI B0t؇6 qHcPѺk\4uL΅#Fpl("### "j۶m{Fhx_+gwٶii&1"qDt[hГŇI5 Y+J Spb8cǎСuqHuqm-;cZ'D kӱrʻO<ث8m '1.1~~ :֭[MrmTWWVCjjjt$ d2xzz6}Ehh(BBBVZhȐ!:kJe,c=] gT*ܹQUUe4J<<< ɚk oo~n+C g`cyQ%/r,r±kQPP;DZ606xB ]xD`]ƑnnnQVVfE- 999O1m68{\?oر#\Up,* ec`,\ .Z 'ԩS8 {RG*UNH5.{\N,F7nȑ#8|09K. Mk ___$&&߿?: 77W#T*1Ɯ9F޽!J{>q)5.-m^^ߔݻ7cС W\Tu$a$:-sCDf͚5žhB1"^K "bMp2"Z p裏oYǡþ}[qV*A8g_ 1&8/^D``QܮJ}}=N>ӧO?xzu.yc6J-aB$(6솳?0 Ш5ƐU[CD|.Si"Z#C2Qԁ6C)&,eeeFDDa:2 pzذah`7ֲV_\!T蝏#ÔyƘ;gpG ]j'tn*; `iX u u}(1Q#v7.H_HD[fBD$'''GTUU=<===>%%<MզM^^^_z'Bqƍ.pb} (C5P_GDǦXIi>h`8*JhDL.2>{Gk:WD3kx4~jȥrf"8x1X# Wͩ -A& c0Zk ^GH~mٳg{0##PUURmڴIsww?pO?ȍ"`W1}P뎖嶴fW=% VGDv "NEMMM>.E"oePGVwI&LP0a„hcZjݻw2[]]]B,++kSRRҪȧ̡ž^^^nnnUUUWyyyAjjY S5cPԃӾAvljc*~p٣_h`ӣq2WifT*5w5iq2}~QNA㻒7a]>ֆ1ݽ[8JVTrRT*e:Y]]{]][MM[MMZ<==U2LᡒdJwwzLVQ^QVQe}֭3GxqDG M0Bt:M9r|^pM0kGEoƳs`""""""""C=gx5[ =UBm<4] 艗""dC40DDDDDDDDDDDxC!""""""""""!""""""""""!""""""""""!""""""""""!""""""""""!""""""""""!""""""""""oNDdtIENDB`chessx-1.0.0/src/database/memorydatabase.h000644 001750 001750 00000004733 12223260306 021315 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2007 Marius Roets * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __MEMORYDATABASE_H__ #define __MEMORYDATABASE_H__ #include #include "pgndatabase.h" /** @ingroup Database The MemoryDatabase class provides database access to PGN files. Games are stored in memory, and are editable. The class is derived from the PgnDatabase class, providing methods for the loading and saving of games, and for performing searches and queries. */ /** @todo Removing from database is not implemented. */ class MemoryDatabase : public PgnDatabase { Q_OBJECT public: /** Default constructor */ MemoryDatabase(); /** Destructor */ ~MemoryDatabase(); /** Returns whether the database is read-only or not */ virtual bool isReadOnly() const { return false; } /** @return whether the database was modified. */ virtual bool isModified() const { return m_isModified; } /** @return whether the database was modified. */ void setModified(bool b) { m_isModified = b; } /** Adds a game to the database */ bool appendGame(const Game& game); /** Removes a game from the database */ bool remove(int gameId); /** Undo the deletion of a game */ bool undelete(int gameId); /** Saves a game at the given position, returns true if successful */ bool replace(int index, Game& game); /** Removes all games from the database, return true if succesful */ virtual bool clear(); /** Loads a game from the given position, returns true if successful */ bool loadGame(int index, Game& game); /** Loads only moves into a game from the given position */ void loadGameMoves(int index, Game& game); protected: virtual void parseGame(); private: QVector m_games; bool parseFile(); bool m_isModified; }; #endif // __MEMORYDATABASE_H__ chessx-1.0.0/src/database/bitboard.cpp000644 001750 001750 00000174527 12223260306 020452 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2003 Sune Fischer * * (C) 2005-2006 Marius Roets * * (C) 2005-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "bitboard.h" #include "settings.h" #ifdef _MSC_VER #include #endif #include // Global data that is initialized early on and only read afterward quint64 bb_PawnAttacks[2][64]; quint64 bb_PawnF1[2][64]; quint64 bb_PawnF2[2][64]; quint64 bb_PawnALL[2][64]; quint64 bb_PromotionRank[2]; quint64 bb_KnightAttacks[64]; quint64 bb_R45Attacks[64][64]; quint64 bb_L45Attacks[64][64]; quint64 bb_KingAttacks[64]; quint64 bb_RankAttacks[64][64]; quint64 bb_FileAttacks[64][64]; quint64 bb_fileMask[8]; quint64 bb_rankMask[8]; quint64 bb_Mask[64]; quint64 bb_MaskL90[64]; quint64 bb_MaskL45[64]; quint64 bb_MaskR45[64]; BitBoard getStandardPosition(); // Calling the function getStandardPosition for initialization avoids // initialization side effects when using BitBoards in other translation // units. BitBoard standardPosition = getStandardPosition(); BitBoard clearedPosition; bool bitBoardInitRun; void bitBoardInit(); const quint64 A1 = 1, B1 = A1 << 1, C1 = B1 << 1, D1 = C1 << 1, E1 = D1 << 1, F1 = E1 << 1, G1 = F1 << 1, H1 = G1 << 1; const quint64 A2 = H1 << 1, B2 = A2 << 1, C2 = B2 << 1, D2 = C2 << 1, E2 = D2 << 1, F2 = E2 << 1, G2 = F2 << 1, H2 = G2 << 1; const quint64 A3 = H2 << 1, B3 = A3 << 1, C3 = B3 << 1, D3 = C3 << 1, E3 = D3 << 1, F3 = E3 << 1, G3 = F3 << 1, H3 = G3 << 1; const quint64 A4 = H3 << 1, B4 = A4 << 1, C4 = B4 << 1, D4 = C4 << 1, E4 = D4 << 1, F4 = E4 << 1, G4 = F4 << 1, H4 = G4 << 1; const quint64 A5 = H4 << 1, B5 = A5 << 1, C5 = B5 << 1, D5 = C5 << 1, E5 = D5 << 1, F5 = E5 << 1, G5 = F5 << 1, H5 = G5 << 1; const quint64 A6 = H5 << 1, B6 = A6 << 1, C6 = B6 << 1, D6 = C6 << 1, E6 = D6 << 1, F6 = E6 << 1, G6 = F6 << 1, H6 = G6 << 1; const quint64 A7 = H6 << 1, B7 = A7 << 1, C7 = B7 << 1, D7 = C7 << 1, E7 = D7 << 1, F7 = E7 << 1, G7 = F7 << 1, H7 = G7 << 1; const quint64 A8 = H7 << 1, B8 = A8 << 1, C8 = B8 << 1, D8 = C8 << 1, E8 = D8 << 1, F8 = E8 << 1, G8 = F8 << 1, H8 = G8 << 1; const unsigned int RotateL90[64] = { h1, h2, h3, h4, h5, h6, h7, h8, g1, g2, g3, g4, g5, g6, g7, g8, f1, f2, f3, f4, f5, f6, f7, f8, e1, e2, e3, e4, e5, e6, e7, e8, d1, d2, d3, d4, d5, d6, d7, d8, c1, c2, c3, c4, c5, c6, c7, c8, b1, b2, b3, b4, b5, b6, b7, b8, a1, a2, a3, a4, a5, a6, a7, a8, }; const unsigned int RotateR45[64] = { a1, b8, c7, d6, e5, f4, g3, h2, a2, b1, c8, d7, e6, f5, g4, h3, a3, b2, c1, d8, e7, f6, g5, h4, a4, b3, c2, d1, e8, f7, g6, h5, a5, b4, c3, d2, e1, f8, g7, h6, a6, b5, c4, d3, e2, f1, g8, h7, a7, b6, c5, d4, e3, f2, g1, h8, a8, b7, c6, d5, e4, f3, g2, h1 }; const unsigned int RotateL45[64] = { a2, b3, c4, d5, e6, f7, g8, h1, a3, b4, c5, d6, e7, f8, g1, h2, a4, b5, c6, d7, e8, f1, g2, h3, a5, b6, c7, d8, e1, f2, g3, h4, a6, b7, c8, d1, e2, f3, g4, h5, a7, b8, c1, d2, e3, f4, g5, h6, a8, b1, c2, d3, e4, f5, g6, h7, a1, b2, c3, d4, e5, f6, g7, h8 }; const uchar Castle[64] = { ~4, 255, 255, 255, ~5, 255, 255, ~1, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, ~8, 255, 255, 255, ~10, 255, 255, ~2 }; const quint64 fileA = A1 | A2 | A3 | A4 | A5 | A6 | A7 | A8; const quint64 fileB = B1 | B2 | B3 | B4 | B5 | B6 | B7 | B8; const quint64 fileG = G1 | G2 | G3 | G4 | G5 | G6 | G7 | G8; const quint64 fileH = H1 | H2 | H3 | H4 | H5 | H6 | H7 | H8; const quint64 rank4 = A4 | B4 | C4 | D4 | E4 | F4 | G4 | H4; const quint64 rank5 = A5 | B5 | C5 | D5 | E5 | F5 | G5 | H5; const quint64 fileNotA = ~ fileA; const quint64 fileNotH = ~ fileH; const quint64 fileNotAB = ~(fileA | fileB); const quint64 fileNotGH = ~(fileG | fileH); #define SetBitL90(s) (bb_MaskL90[s]) #define SetBitL45(s) (bb_MaskL45[s]) #define SetBitR45(s) (bb_MaskR45[s]) #define ShiftDown(b) ((b)>>8) #define Shift2Down(b) ((b)>>16) #define ShiftUp(b) ((b)<<8) #define Shift2Up(b) ((b)<<16) #define ShiftRight(b) (((b)<<1)&fileNotA) #define Shift2Right(b) (((b)<<2)&fileNotAB) #define ShiftLeft(b) (((b)>>1)&fileNotH) #define Shift2Left(b) (((b)>>2)&fileNotGH) #define ShiftUpLeft(b) (((b)<<7)&fileNotH) #define ShiftUpRight(b) (((b)<<9)&fileNotA) #define ShiftDownLeft(b) (((b)>>9)&fileNotH) #define ShiftDownRight(b) (((b)>>7)&fileNotA) #define SetBit(s) (bb_Mask[s]) #define File(s) ((s)&7) #define Rank(s) ((s)>>3) // This C++ version is as fast as the assembly inline unsigned int getFirstBitAndClear64(quint64& bb) { register quint64 x = bb & -(qint64)bb; bb ^= x; #ifdef __GNUG__ return x ? (63 - __builtin_clzll(x)) : 0; #elif _MSC_VER #ifdef __x86_64__ if(x) { register unsigned long r; _BitScanReverse64(&r, x); return r; } return 0; #else if(x) { register unsigned long r; unsigned long y = (x >> 32); if(y) { _BitScanReverse(&r, y); return 32 + r; } _BitScanReverse(&r, x); return r; } return 0; #endif #else // SBE - After a fair bit of testing, this is the fastest portable version // i could come up with, it's about twice as fast as shift-testing 64 times. register unsigned int r = 0; if(!(x & 0xffffffff)) { x >>= 32; r |= 32; } if(!(x & 0xffff)) { x >>= 16; r |= 16; } if(!(x & 0xff)) { x >>= 8; r |= 8; } if(!(x & 0xf)) { x >>= 4; r |= 4; } if(!(x & 0x3)) { x >>= 2; r |= 2; } if(!(x & 0x1)) { r |= 1; } return r; #endif } /** Initialize a new bitboard, and ensure global data has been initialized */ BitBoard::BitBoard() { memset(this, 0, sizeof(BitBoard)); if(!bitBoardInitRun) { bitBoardInit(); } m_epSquare = NoEPSquare; } bool BitBoard::isCheckmate() const { MoveList moves(generateMoves()); for(int i = 0; i < moves.size(); ++i) if(!isIntoCheck(moves[i])) { return false; } return isCheck(); } bool BitBoard::isStalemate() const { MoveList moves(generateMoves()); for(int i = 0; i < moves.size(); ++i) if(!isIntoCheck(moves[i])) { return false; } return !isCheck(); } void BitBoard::removeIllegal(const Move& move, quint64& b) const { quint64 mask = 1; Move m = move; for(int sq = 0; sq < 64; ++sq) { if(b & mask) { m.setFrom(sq); if(isIntoCheck(m)) { b &= ~mask; } } mask <<= 1; } } inline QString sanPiece(int piece, bool translate = false) { if(!translate) { return QString(" KQRBN"[piece]); } QString pieceString = AppSettings->getValue("/GameText/PieceString").toString(); if(pieceString.length() == 6) { return QString(pieceString.at(piece)); } switch(piece) { case 0: return " "; case 1: return "♔"; case 2: return "♕"; case 3: return "♖"; case 4: return "♗"; case 5: return "♘"; } return " "; } QString BitBoard::moveToSan(const Move& move, bool translate) const { QString san; int from = move.from(); int to = move.to(); bool isPawn = m_piece[from] == Pawn; if(move.isNullMove()) { san = "--"; return san; } if(move.isCastling()) { if(from < to) { san = "O-O"; } else { san = "O-O-O"; } } else { if(!isPawn) { san = sanPiece(m_piece[from], translate); // We may need disambiguation quint64 others = 0; switch(m_piece[from]) { case Knight: others = m_knights & knightAttacksFrom(to); break; case Bishop: others = m_bishops & bishopAttacksFrom(to); break; case Rook: others = m_rooks & rookAttacksFrom(to); break; case Queen: others = m_queens & queenAttacksFrom(to); break; case King: others = m_kings & kingAttacksFrom(to); break; default: break; // Something really wrong } others ^= SetBit(from); others &= m_occupied_co[m_stm]; // Do not disambiguate with moves that put oneself in check. // This is an expensive operation of dubious value, but people seem to want it if(others) { removeIllegal(move, others); } if(others) { bool row = false, column = false; if(others & bb_rankMask[Rank(from)]) { column = true; } if(others & bb_fileMask[File(from)]) { row = true; } else { column = true; } if(column) { san += 'a' + File(from); } if(row) { san += '1' + Rank(from); } } } //capture x if(m_piece[to] || (move.isEnPassant())) { if(isPawn) { san += 'a' + File(from); } san += 'x'; } //destination square san += 'a' + File(to); san += '1' + Rank(to); } if(move.isPromotion()) { san += '='; san += sanPiece(move.promoted(), translate); } BitBoard check(*this); check.doMove(move); if(check.isCheck()) { if(check.isCheckmate()) { san += '#'; } else { san += '+'; } } return san; } void BitBoard::clear() { *this = clearedPosition; } void BitBoard::setStandardPosition() { *this = standardPosition; } void BitBoard::clearEnPassantSquare() { m_epFile = 0; m_epSquare = NoEPSquare; } void BitBoard::setEnPassantSquare(const Square s) { m_epSquare = s; m_epFile = File(s); } bool BitBoard::isMovable(const Square from) const { Q_ASSERT(from < 64); if(m_occupied_co[m_stm] & SetBit(from)) { quint64 squares = 0; switch(m_piece[from]) { case Pawn: squares = pawnMovesFrom(from); break; case Knight: squares = knightAttacksFrom(from); break; case Bishop: squares = bishopAttacksFrom(from); break; case Rook: squares = rookAttacksFrom(from); break; case Queen: squares = queenAttacksFrom(from); break; case King: squares = kingAttacksFrom(m_ksq[m_stm]); break; default: break; } squares &= ~m_occupied_co[m_stm]; while(squares) { Square to = getFirstBitAndClear64(squares); if(prepareMove(from, to).isLegal()) { return true; } } } return false; } void BitBoard::setAt(const Square s, const Piece p) { Q_ASSERT(s < 64); Q_ASSERT(isValidPiece(p) || p == Empty); quint64 bit = SetBit(s); if(m_occupied & bit) { removeAt(s); } PieceType pt = pieceType(p); if(pt == None) { return; } Color _color = pieceColor(p); ++m_pieceCount[_color]; switch(pt) { case Pawn: m_pawns |= bit; ++m_pawnCount[_color]; break; case Knight: m_knights |= bit; break; case Bishop: m_bishops |= bit; break; case Rook: m_rooks |= bit; break; case Queen: m_queens |= bit; break; case King: if(m_kings & m_occupied_co[_color]) { removeAt(m_ksq[_color]); } m_kings |= bit; m_ksq[_color] = s; break; default: break; // ERROR } m_piece[s] = pt; m_occupied ^= bit; m_occupied_co[_color] ^= bit; m_occupied_l90 ^= SetBitL90(s); m_occupied_l45 ^= SetBitL45(s); m_occupied_r45 ^= SetBitR45(s); } void BitBoard::removeAt(const Square s) { Q_ASSERT(s < 64); quint64 bit = SetBit(s); if(!(m_occupied & bit)) { return; } Color _color = m_occupied_co[White] & bit ? White : Black; --m_pieceCount[_color]; switch(m_piece[s]) { case Pawn: m_pawns ^= bit; --m_pawnCount[_color]; break; case Knight: m_knights ^= bit; break; case Bishop: m_bishops ^= bit; break; case Rook: m_rooks ^= bit; m_castle &= Castle[s]; break; case Queen: m_queens ^= bit; break; case King: m_kings ^= bit; m_ksq[_color] = InvalidSquare; destroyCastle(_color); break; default: break; // ERROR } m_piece[s] = Empty; m_occupied ^= bit; m_occupied_co[_color] ^= bit; m_occupied_l90 ^= SetBitL90(s); m_occupied_l45 ^= SetBitL45(s); m_occupied_r45 ^= SetBitR45(s); } bool BitBoard::isValidFen(const QString& fen) const { return BitBoard().fromGoodFen(fen); } bool BitBoard::fromFen(const QString& fen) { if(isValidFen(fen)) { return fromGoodFen(fen); } return false; } BoardStatus BitBoard::validate() const { unsigned int wk = 0, bk = 0, wp = 0, bp = 0, bo = 0, wo = 0; for(unsigned int i = 0; i < 64; ++i) { Piece p = pieceAt(i); if(p == WhiteKing) { ++wk; } else if(p == BlackKing) { ++bk; } else if(p == WhitePawn) { if(i <= h1 || i >= a8) // Pawns on 1st or 8th { return PawnsOn18; } else { ++wp; } } else if(p == BlackPawn) { if(i <= h1 || i >= a8) // Pawns on 1st or 8th { return PawnsOn18; } else { ++bp; } } else if(isWhite(p)) { ++wo; } else if(isBlack(p)) { ++bo; } } Q_ASSERT(wp == m_pawnCount[White]); Q_ASSERT(bp == m_pawnCount[Black]); Q_ASSERT(wp + wk + wo == m_pieceCount[White]); Q_ASSERT(bp + bk + bo == m_pieceCount[Black]); // Exactly one king per side if(wk == 0) { return NoWhiteKing; } if(bk == 0) { return NoBlackKing; } if(wk != 1 || bk != 1) { return TooManyKings; } // No more than 8 pawns per side if(wp > 8) { return TooManyWhitePawns; } if(bp > 8) { return TooManyBlackPawns; } // Maximum 16 pieces per side if((wk + wp + wo) > 16) { return TooManyWhite; } if((bk + bp + bo) > 16) { return TooManyBlack; } // Bad checks bool check = isAttackedBy(m_stm ^ 1, m_ksq[m_stm]); bool check2 = isAttackedBy(m_stm, m_ksq[m_stm ^ 1]); if(check && check2) { return DoubleCheck; } if(check2) { return OppositeCheck; } // Can't castle with missing rook if(canCastleLong(White) && pieceAt(a1) != WhiteRook) { return BadCastlingRights; } if(canCastleShort(White) && pieceAt(h1) != WhiteRook) { return BadCastlingRights; } if(canCastleLong(Black) && pieceAt(a8) != BlackRook) { return BadCastlingRights; } if(canCastleShort(Black) && pieceAt(h8) != BlackRook) { return BadCastlingRights; } // Can't castle if king has moved if(canCastle(White) && pieceAt(e1) != WhiteKing) { return BadCastlingRights; } if(canCastle(Black) && pieceAt(e8) != BlackKing) { return BadCastlingRights; } // Detect unreasonable ep square if(m_epSquare != NoEPSquare) { if(m_stm == White && (m_epSquare < a6 || m_epSquare > h6)) { return InvalidEnPassant; } if(m_stm == Black && (m_epSquare < a3 || m_epSquare > h3)) { return InvalidEnPassant; } // According to PGN standard, ep should be set even if no capture is possible /* if (m_occupied & SetBit(m_epSquare)) return InvalidEnPassant; if (m_occupied & bb_PawnF1[m_stm][m_epSquare]) return InvalidEnPassant; if (!(bb_PawnAttacks[m_stm^1][m_epSquare] & m_pawns & m_occupied_co[m_stm])) return InvalidEnPassant; if (!(bb_PawnF1[m_stm^1][m_epSquare] & m_pawns & m_occupied_co[m_stm^1])) return InvalidEnPassant; */ } // Don't allow triple(or more) checks. // FIXME -- need code here to return MultiCheck return Valid; } // Why QString throws asserts for access past end of string and // refuses to return a real c++ char type is beyond me... class SaneString : public QString { public: SaneString(const QString& q) : QString(q) {}; char operator[](const int index) const { if(index < this->length()) { return QString::operator[](index).toLatin1(); } return 0; } }; bool BitBoard::fromGoodFen(const QString& qfen) { SaneString fen(qfen); int i; unsigned int s; char c = fen[0]; memset(this, 0, sizeof(BitBoard)); m_moveNumber = 1; m_epSquare = NoEPSquare; // Piece position i = 0; s = 56; while(c && c != ' ' && s <= 64) { switch(c) { case '/': s -= 16; break; case '1': s += 1; break; case '2': s += 2; break; case '3': s += 3; break; case '4': s += 4; break; case '5': s += 5; break; case '6': s += 6; break; case '7': s += 7; break; case '8': s += 8; break; case 'p': m_piece[s] = Pawn; m_pawns |= SetBit(s); m_occupied_co[Black] |= SetBit(s); ++m_pawnCount[Black]; ++m_pieceCount[Black]; s++; break; case 'n': m_piece[s] = Knight; m_knights |= SetBit(s); m_occupied_co[Black] |= SetBit(s); ++m_pieceCount[Black]; s++; break; case 'b': m_piece[s] = Bishop; m_bishops |= SetBit(s); m_occupied_co[Black] |= SetBit(s); ++m_pieceCount[Black]; s++; break; case 'r': m_piece[s] = Rook; m_rooks |= SetBit(s); m_occupied_co[Black] |= SetBit(s); ++m_pieceCount[Black]; s++; break; case 'q': m_piece[s] = Queen; m_queens |= SetBit(s); m_occupied_co[Black] |= SetBit(s); ++m_pieceCount[Black]; s++; break; case 'k': m_piece[s] = King; m_kings |= SetBit(s); m_occupied_co[Black] |= SetBit(s); m_ksq[Black] = s; ++m_pieceCount[Black]; s++; break; case 'P': m_piece[s] = Pawn; m_pawns |= SetBit(s); m_occupied_co[White] |= SetBit(s); ++m_pawnCount[White]; ++m_pieceCount[White]; s++; break; case 'N': m_piece[s] = Knight; m_knights |= SetBit(s); m_occupied_co[White] |= SetBit(s); ++m_pieceCount[White]; s++; break; case 'B': m_piece[s] = Bishop; m_bishops |= SetBit(s); m_occupied_co[White] |= SetBit(s); ++m_pieceCount[White]; s++; break; case 'R': m_piece[s] = Rook; m_rooks |= SetBit(s); m_occupied_co[White] |= SetBit(s); ++m_pieceCount[White]; s++; break; case 'Q': m_piece[s] = Queen; m_queens |= SetBit(s); m_occupied_co[White] |= SetBit(s); ++m_pieceCount[White]; s++; break; case 'K': m_piece[s] = King; m_kings |= SetBit(s); m_occupied_co[White] |= SetBit(s); m_ksq[White] = s; ++m_pieceCount[White]; s++; break; default: return false; } c = fen[++i]; } if(s != 8) { return false; } // Set remainder of bitboard data appropriately m_occupied = m_occupied_co[White] + m_occupied_co[Black]; for(int i = 0; i < 64; ++i) { if(SetBit(i)&m_occupied) { m_occupied_l90 |= SetBitL90(i); m_occupied_l45 |= SetBitL45(i); m_occupied_r45 |= SetBitR45(i); } } // Side to move c = fen[++i]; if(c == 'w') { m_stm = White; } else if(c == 'b') { m_stm = Black; } else if(c == 0) { return true; } else { return false; } c = fen[++i]; // Castling Rights c = fen[++i]; if(c == 0) { return true; } if(c != '-') { while(c != ' ') { switch(c) { case 'K': setCastleShort(White); break; case 'Q': setCastleLong(White); break; case 'k': setCastleShort(Black); break; case 'q': setCastleLong(Black); break; default: return false; } c = fen[++i]; } } else { ++i; // Bypass space } // EnPassant Square c = fen[++i]; if(c == 0) { return true; } if(c != '-') { bool epgood = true; if(c >= 'a' && c <= 'h') { m_epFile = c - 'a' + 1; } else if(c >= 'A' && c <= 'H') { m_epFile = c - 'A' + 1; } else if(c < '0' || c > '9') { return false; } else { epgood = false; } if(epgood) { c = fen[++i]; if(m_stm == White && c != '6') { return false; } else if(m_stm == Black && c != '3') { return false; } } } epFile2Square(); c = fen[++i]; // Half move clock c = fen[++i]; if(c == 0) { return true; } if(c < '0' || c > '9') { return false; } int j = i; while(c >= '0' && c <= '9') { c = fen[++i]; } m_halfMoves = fen.mid(j, i - j).toInt(); // Move number c = fen[++i]; if(c == 0) { return true; } if(c < '0' || c > '9') { return false; } m_moveNumber = fen.mid(i).toInt(); while(c >= '0' && c <= '9') { c = fen[++i]; } if(m_moveNumber <= 0) { // Silently fix illegal movenumber m_moveNumber = 1; } return true; } MoveList BitBoard::generateMoves() const { register unsigned int from, to; quint64 moves, movers; MoveList p; if(m_stm == White) { // castle moves if(canCastle(White)) { if(canCastleShort(White) && !((F1 | G1)&m_occupied)) if(!isAttackedBy(Black, e1) && !isAttackedBy(Black, f1) && !isAttackedBy(Black, g1)) { p.add().genWhiteOO(); } if(canCastleLong(White) && !((B1 | C1 | D1)&m_occupied)) if(!isAttackedBy(Black, c1) && !isAttackedBy(Black, d1) && !isAttackedBy(Black, e1)) { p.add().genWhiteOOO(); } } // pawn en passant moves movers = m_pawns & m_occupied_co[White]; if(m_epSquare != NoEPSquare) { moves = bb_PawnAttacks[Black][m_epSquare] & movers; while(moves) { from = getFirstBitAndClear64(moves); p.add().genEnPassant(from, m_epSquare); } } // pawn captures moves = ShiftUpRight(movers) & m_occupied_co[Black]; while(moves) { to = getFirstBitAndClear64(moves); if(Rank(to) != 7) { p.add().genPawnMove(to - 9, to, m_piece[to]); } else { p.add().genCapturePromote(to - 9, to, Queen, m_piece[to]); p.add().genCapturePromote(to - 9, to, Knight, m_piece[to]); p.add().genCapturePromote(to - 9, to, Rook, m_piece[to]); p.add().genCapturePromote(to - 9, to, Bishop, m_piece[to]); } } moves = ShiftUpLeft(movers) & m_occupied_co[Black]; while(moves) { to = getFirstBitAndClear64(moves); if(Rank(to) != 7) { p.add().genPawnMove(to - 7, to, m_piece[to]); } else { p.add().genCapturePromote(to - 7, to, Queen, m_piece[to]); p.add().genCapturePromote(to - 7, to, Knight, m_piece[to]); p.add().genCapturePromote(to - 7, to, Rook, m_piece[to]); p.add().genCapturePromote(to - 7, to, Bishop, m_piece[to]); } } // pawns 1 forward moves = ShiftUp(movers) & ~m_occupied; movers = moves; while(moves) { to = getFirstBitAndClear64(moves); if(Rank(to) != 7) { p.add().genOneForward(to - 8, to); } else { p.add().genPromote(to - 8, to, Queen); p.add().genPromote(to - 8, to, Knight); p.add().genPromote(to - 8, to, Rook); p.add().genPromote(to - 8, to, Bishop); } } // pawns 2 forward moves = ShiftUp(movers) & rank4 & ~m_occupied; while(moves) { to = getFirstBitAndClear64(moves); p.add().genTwoForward(to - 16, to); } } else { // castle moves if(canCastle(Black)) { if(canCastleShort(Black) && !((F8 | G8)&m_occupied)) if(!isAttackedBy(White, e8) && !isAttackedBy(White, f8) && !isAttackedBy(White, g8)) { p.add().genBlackOO(); } if(canCastleLong(Black) && !((B8 | C8 | D8)&m_occupied)) if(!isAttackedBy(White, e8) && !isAttackedBy(White, d8) && !isAttackedBy(White, c8)) { p.add().genBlackOOO(); } } // pawn en passant moves movers = m_pawns & m_occupied_co[Black]; if(m_epSquare != NoEPSquare) { moves = bb_PawnAttacks[White][m_epSquare] & movers; while(moves) { from = getFirstBitAndClear64(moves); p.add().genEnPassant(from, m_epSquare); } } // pawn captures moves = ShiftDownLeft(movers) & m_occupied_co[White]; while(moves) { to = getFirstBitAndClear64(moves); if(Rank(to) != 0) { p.add().genPawnMove(to + 9, to, m_piece[to]); } else { p.add().genCapturePromote(to + 9, to, Queen, m_piece[to]); p.add().genCapturePromote(to + 9, to, Knight, m_piece[to]); p.add().genCapturePromote(to + 9, to, Rook, m_piece[to]); p.add().genCapturePromote(to + 9, to, Bishop, m_piece[to]); } } moves = ShiftDownRight(movers) & m_occupied_co[White]; while(moves) { to = getFirstBitAndClear64(moves); if(Rank(to) != 0) { p.add().genPawnMove(to + 7, to, m_piece[to]); } else { p.add().genCapturePromote(to + 7, to, Queen, m_piece[to]); p.add().genCapturePromote(to + 7, to, Knight, m_piece[to]); p.add().genCapturePromote(to + 7, to, Rook, m_piece[to]); p.add().genCapturePromote(to + 7, to, Bishop, m_piece[to]); } } // pawns 1 forward moves = ShiftDown(movers) & ~m_occupied; movers = moves; while(moves) { to = getFirstBitAndClear64(moves); if(Rank(to) != 0) { p.add().genOneForward(to + 8, to); } else { p.add().genPromote(to + 8, to, Queen); p.add().genPromote(to + 8, to, Knight); p.add().genPromote(to + 8, to, Rook); p.add().genPromote(to + 8, to, Bishop); } } // pawns 2 forward moves = ShiftDown(movers) & rank5 & ~m_occupied; while(moves) { to = getFirstBitAndClear64(moves); p.add().genTwoForward(to + 16, to); } } // knight moves movers = m_knights & m_occupied_co[m_stm]; while(movers) { from = getFirstBitAndClear64(movers); moves = knightAttacksFrom(from) & ~m_occupied_co[m_stm]; while(moves) { to = getFirstBitAndClear64(moves); p.add().genKnightMove(from, to, m_piece[to]); } } // bishop moves movers = m_bishops & m_occupied_co[m_stm]; while(movers) { from = getFirstBitAndClear64(movers); moves = bishopAttacksFrom(from) & ~m_occupied_co[m_stm]; while(moves) { to = getFirstBitAndClear64(moves); p.add().genBishopMove(from, to, m_piece[to]); } } // rook moves movers = m_rooks & m_occupied_co[m_stm]; while(movers) { from = getFirstBitAndClear64(movers); moves = rookAttacksFrom(from) & ~m_occupied_co[m_stm]; while(moves) { to = getFirstBitAndClear64(moves); p.add().genRookMove(from, to, m_piece[to]); } } // queen moves movers = m_queens & m_occupied_co[m_stm]; while(movers) { from = getFirstBitAndClear64(movers); moves = queenAttacksFrom(from) & ~m_occupied_co[m_stm]; while(moves) { to = getFirstBitAndClear64(moves); p.add().genQueenMove(from, to, m_piece[to]); } } // king moves moves = kingAttacksFrom(m_ksq[m_stm]) & ~m_occupied_co[m_stm]; while(moves) { to = getFirstBitAndClear64(moves); if(!isAttackedBy(m_stm ^ 1, to)) { p.add().genKingMove(m_ksq[m_stm], to, m_piece[to]); } } return p; } bool BitBoard::isIntoCheck(const Move& move) const { BitBoard peek(*this); peek.doMove(move); peek.swapToMove(); return peek.isCheck(); } inline bool isFile(const char c) { return c >= 'a' && c <= 'h'; } inline bool isRank(const char c) { return c >= '1' && c <= '8'; } // Create a null move // A Null Move is a move by a king to its own square // and is represented in pgn by a "--" although illegal // it is often used in ebooks to annotate ideas Move BitBoard::nullMove() const { Square kingSquare = m_ksq[m_stm]; Move m = prepareMove(kingSquare, kingSquare); if(m_stm == Black) { m.setBlack(); } return m; } Move BitBoard::parseMove(const QString& algebraic) const { const QByteArray& bs(algebraic.toLatin1()); const char *san = bs.constData(); const char* s = san; register char c = *(s++); quint64 match; int fromSquare = -1; int toSquare = -1; int fromFile = -1; int fromRank = -1; uchar promotePiece = Empty; Move move; unsigned int type; // Castling if(c == 'o' || c == 'O' || c == '0') { if(strncmp(san, "o-o-o", 5) == 0 || strncmp(san, "O-O-O", 5) == 0 || strncmp(san, "0-0-0", 5) == 0) { if(m_stm == White) { return prepareMove(e1, c1); } else { return prepareMove(e8, c8); } } else if(strncmp(san, "o-o", 3) == 0 || strncmp(san, "O-O", 3) == 0 || strncmp(san, "0-0", 3) == 0) { if(m_stm == White) { return prepareMove(e1, g1); } else { return prepareMove(e8, g8); } } return move; } // Null Move if(c == '-') { if(strncmp(san, "--", 2) == 0) { return nullMove(); } } // Piece switch(c) { case 'Q': type = Queen; c = *(s++); break; case 'R': type = Rook; c = *(s++); break; case 'B': type = Bishop; c = *(s++); break; case 'N': type = Knight; c = *(s++); break; case 'K': type = King; c = *(s++); break; case 'P': c = *(s++); // Fall through default: type = Pawn; break; } // Check for disambiguation if(isFile(c)) { fromFile = c - 'a'; c = *(s++); if(isRank(c)) { fromSquare = (c - '1') * 8 + fromFile; fromFile = -1; c = *(s++); } } else if(isRank(c)) { fromRank = c - '1'; c = *(s++); } // Capture indicator (or dash in the case of a LAN move) if(c == 'x' || c == '-') { c = *(s++); } // Destination square if(isFile(c)) { int f = c - 'a'; c = *(s++); if(!isRank(c)) { return move; } toSquare = (c - '1') * 8 + f; c = *(s++); } else { toSquare = fromSquare; fromSquare = -1; } if(toSquare < 0) { return move; } if(type == Pawn) { // Promotion as in bxc8=Q or bxc8(Q) if(c == '=' || c == '(') { c = *(s++); } switch(toupper(c)) { case 'Q': promotePiece = Queen; break; case 'R': promotePiece = Rook; break; case 'B': promotePiece = Bishop; break; case 'N': promotePiece = Knight; break; default: ;//return move; } if(fromSquare < 0) { int base = (m_stm == White ? -8 : 8); if(fromFile < 0) { fromSquare = toSquare + base; quint64 bit = SetBit(fromSquare); if(!(m_occupied_co[m_stm] & bit)) { fromSquare += base; } } else if(fromFile <= (int) File(toSquare)) { fromSquare = toSquare + base - 1; } else { fromSquare = toSquare + base + 1; } } // This isn't a hugely efficient way to go from here move = prepareMove(fromSquare, toSquare); if(move.isPromotion() && promotePiece) { move.setPromoted(promotePiece); } return move; } if(fromSquare < 0) { switch(type) { case Queen: match = queenAttacksFrom(toSquare) & m_queens; break; case Rook: match = rookAttacksFrom(toSquare) & m_rooks; break; case Bishop: match = bishopAttacksFrom(toSquare) & m_bishops; break; case Knight: match = knightAttacksFrom(toSquare) & m_knights; break; case King: match = kingAttacksFrom(toSquare) & m_kings; break; default: return move; } match &= m_occupied_co[m_stm]; if(fromRank >= 0) { match &= bb_rankMask[fromRank]; } else if(fromFile >= 0) { match &= bb_fileMask[fromFile]; } if(match) { fromSquare = getFirstBitAndClear64(match); } else { return move; } // If not yet fully disambiguated, all but one move must be illegal // Cycle through them, and pick the first legal move. while(match) { if(prepareMove(fromSquare, toSquare).isLegal()) { break; } fromSquare = getFirstBitAndClear64(match); } } if(type != m_piece[fromSquare]) { return move; } return prepareMove(fromSquare, toSquare); } bool BitBoard::doMove(const Move& m) { register unsigned int from = m.from(); register unsigned int to = m.to(); register unsigned int sntm = m_stm ^ 1; // side not to move register quint64 bb_from = SetBit(from); register quint64 bb_to = SetBit(to); unsigned int rook_from = 0, rook_to = 0; m_epFile = 0; m_halfMoves++; // Number of moves since last capture or pawn move unsigned int action = m.action(); switch(action) { case Pawn: m_halfMoves = 0; m_pawns ^= bb_from ^ bb_to; m_piece[to] = Pawn; break; case Knight: m_knights ^= bb_from ^ bb_to; m_piece[to] = Knight; break; case Bishop: m_bishops ^= bb_from ^ bb_to; m_piece[to] = Bishop; break; case Rook: m_rooks ^= bb_from ^ bb_to; m_piece[to] = Rook; if(canCastle(m_stm)) // a rook is moving, destroy castle flags if needed { m_castle &= Castle[from]; // question is if always doing the table is just faster? } break; case Queen: m_queens ^= bb_from ^ bb_to; m_piece[to] = Queen; break; case King: if(! m.isNullMove()) { m_kings ^= bb_from ^ bb_to; m_ksq[m_stm] = to; m_piece[to] = King; destroyCastle(m_stm); // king is moving so definitely destroy castle stuff! } break; case Move::CASTLE: m_kings ^= bb_from ^ bb_to; m_ksq[m_stm] = to; m_piece[to] = King; destroyCastle(m_stm); switch(to) { case c1: rook_from = a1; rook_to = d1; break; case g1: rook_from = h1; rook_to = f1; break; case c8: rook_from = a8; rook_to = d8; break; case g8: rook_from = h8; rook_to = f8; break; } m_piece[rook_from] = Empty; m_piece[rook_to] = Rook; m_rooks ^= SetBit(rook_from) ^ SetBit(rook_to); m_occupied_co[m_stm] ^= SetBit(rook_from) ^ SetBit(rook_to); m_occupied_l90 ^= SetBitL90(rook_from) ^ SetBitL90(rook_to); m_occupied_l45 ^= SetBitL45(rook_from) ^ SetBitL45(rook_to); m_occupied_r45 ^= SetBitR45(rook_from) ^ SetBitR45(rook_to); break; case Move::TWOFORWARD: m_halfMoves = 0; m_pawns ^= bb_from ^ bb_to; m_piece[to] = Pawn; // According to PGN standard, ep square should be always set. m_epFile = File(to) + 1; break; case Move::PROMOTE: m_halfMoves = 0; m_pawns ^= bb_from; --m_pawnCount[m_stm]; switch(m.promoted()) { case Knight: m_knights ^= bb_to; m_piece[to] = Knight; break; case Bishop: m_bishops ^= bb_to; m_piece[to] = Bishop; break; case Rook: m_rooks ^= bb_to; m_piece[to] = Rook; break; case Queen: m_queens ^= bb_to; m_piece[to] = Queen; break; default: // can't promote to other piece types; break; } break; } switch(m.removal()) { case Empty: m_occupied_l90 ^= SetBitL90(to); // extra cleanup needed for non-captures m_occupied_l45 ^= SetBitL45(to); m_occupied_r45 ^= SetBitR45(to); break; case Pawn: --m_pawnCount[sntm]; --m_pieceCount[sntm]; m_halfMoves = 0; m_pawns ^= bb_to; m_occupied_co[sntm] ^= bb_to; break; case Knight: --m_pieceCount[sntm]; m_halfMoves = 0; m_knights ^= bb_to; m_occupied_co[sntm] ^= bb_to; break; case Bishop: --m_pieceCount[sntm]; m_halfMoves = 0; m_bishops ^= bb_to; m_occupied_co[sntm] ^= bb_to; break; case Rook: --m_pieceCount[sntm]; m_halfMoves = 0; m_rooks ^= bb_to; m_occupied_co[sntm] ^= bb_to; if(canCastle(sntm)) { m_castle &= Castle[to]; } break; case Queen: --m_pieceCount[sntm]; m_halfMoves = 0; m_queens ^= bb_to; m_occupied_co[sntm] ^= bb_to; break; case Move::ENPASSANT: --m_pawnCount[sntm]; --m_pieceCount[sntm]; m_halfMoves = 0; unsigned int epsq = to + (m_stm == White ? -8 : 8); // annoying move, the capture is not on the 'to' square m_piece[epsq] = Empty; m_pawns ^= SetBit(epsq); m_occupied_co[sntm] ^= SetBit(epsq); m_occupied_l90 ^= SetBitL90(to) ^ SetBitL90(epsq); m_occupied_l45 ^= SetBitL45(to) ^ SetBitL45(epsq); m_occupied_r45 ^= SetBitR45(to) ^ SetBitR45(epsq); break; } // ...no I did not forget the king :) if(!m.isNullMove()) { m_piece[from] = Empty; m_occupied_co[m_stm] ^= bb_from ^ bb_to; m_occupied_l90 ^= SetBitL90(from); m_occupied_l45 ^= SetBitL45(from); m_occupied_r45 ^= SetBitR45(from); m_occupied = m_occupied_co[White] + m_occupied_co[Black]; } if(m_stm == Black) { ++m_moveNumber; } m_stm ^= 1; // toggle side to move epFile2Square(); return true; } void BitBoard::undoMove(const Move& m) { register unsigned int from = m.from(); register unsigned int to = m.to(); register unsigned int sntm = m_stm ^ 1; // side not to move register quint64 bb_from = SetBit(from); register quint64 bb_to = SetBit(to); unsigned int rook_from = 0, rook_to = 0; // =0 just to quiet compiler warnings unsigned int action = m.action(); switch(action) { case Pawn: case Move::TWOFORWARD: m_pawns ^= bb_from ^ bb_to; m_piece[from] = Pawn; break; case Knight: m_knights ^= bb_from ^ bb_to; m_piece[from] = Knight; break; case Bishop: m_bishops ^= bb_from ^ bb_to; m_piece[from] = Bishop; break; case Rook: m_rooks ^= bb_from ^ bb_to; m_piece[from] = Rook; break; case Queen: m_queens ^= bb_from ^ bb_to; m_piece[from] = Queen; break; case King: if(!m.isNullMove()) { m_kings ^= bb_from ^ bb_to; m_ksq[sntm] = from; m_piece[from] = King; } break; case Move::CASTLE: m_kings ^= bb_from ^ bb_to; m_ksq[sntm] = from; m_piece[from] = King; switch(to) { case c1: rook_from = a1; rook_to = d1; break; case g1: rook_from = h1; rook_to = f1; break; case c8: rook_from = a8; rook_to = d8; break; case g8: rook_from = h8; rook_to = f8; break; } m_piece[rook_to] = Empty; m_piece[rook_from] = Rook; m_rooks ^= SetBit(rook_from) ^ SetBit(rook_to); m_occupied_co[sntm] ^= SetBit(rook_from) ^ SetBit(rook_to); m_occupied_l90 ^= SetBitL90(rook_from) ^ SetBitL90(rook_to); m_occupied_l45 ^= SetBitL45(rook_from) ^ SetBitL45(rook_to); m_occupied_r45 ^= SetBitR45(rook_from) ^ SetBitR45(rook_to); break; case Move::PROMOTE: m_pawns ^= bb_from; m_piece[from] = Pawn; ++m_pawnCount[sntm]; switch(m.promoted()) { case Knight: m_knights ^= bb_to; break; case Bishop: m_bishops ^= bb_to; break; case Rook: m_rooks ^= bb_to; break; case Queen: m_queens ^= bb_to; break; default: // can't promote to other piece types; break; } break; } unsigned int replace = m.capturedType(); switch(m.removal()) // Reverse captures { case Empty: m_occupied_l90 ^= SetBitL90(to); // extra cleanup needed for non-captures m_occupied_l45 ^= SetBitL45(to); m_occupied_r45 ^= SetBitR45(to); break; case Pawn: ++m_pawnCount[m_stm]; ++m_pieceCount[m_stm]; m_pawns ^= bb_to; m_occupied_co[m_stm] ^= bb_to; break; case Knight: ++m_pieceCount[m_stm]; m_knights ^= bb_to; m_occupied_co[m_stm] ^= bb_to; break; case Bishop: ++m_pieceCount[m_stm]; m_bishops ^= bb_to; m_occupied_co[m_stm] ^= bb_to; break; case Rook: ++m_pieceCount[m_stm]; m_rooks ^= bb_to; m_occupied_co[m_stm] ^= bb_to; break; case Queen: ++m_pieceCount[m_stm]; m_queens ^= bb_to; m_occupied_co[m_stm] ^= bb_to; break; case Move::ENPASSANT: ++m_pawnCount[m_stm]; ++m_pieceCount[m_stm]; replace = Empty; unsigned int epsq = to + (sntm == White ? -8 : 8); // annoying move, the capture is not on the 'to' square m_piece[epsq] = Pawn; m_pawns ^= SetBit(epsq); m_occupied_co[m_stm] ^= SetBit(epsq); m_occupied_l90 ^= SetBitL90(to) ^ SetBitL90(epsq); m_occupied_l45 ^= SetBitL45(to) ^ SetBitL45(epsq); m_occupied_r45 ^= SetBitR45(to) ^ SetBitR45(epsq); break; } // ...no I did not forget the king :) if(!m.isNullMove()) { m_piece[to] = replace; m_occupied_co[sntm] ^= bb_from ^ bb_to; m_occupied_l90 ^= SetBitL90(from); m_occupied_l45 ^= SetBitL45(from); m_occupied_r45 ^= SetBitR45(from); m_occupied = m_occupied_co[White] + m_occupied_co[Black]; } m_stm ^= 1; // toggle side to move if(m_stm == Black) { --m_moveNumber; } m_halfMoves = m.u & 0xFF; m_castle = (m.u >> 8) & 0xF; m_epFile = (m.u >> 12) & 0xF; epFile2Square(); } quint64 BitBoard::pawnMovesFrom(const Square s) const { quint64 targets = bb_PawnF1[m_stm][s] & ~m_occupied; if(targets) { targets |= bb_PawnF2[m_stm][s] & ~m_occupied; } if(m_epSquare == NoEPSquare) { targets |= bb_PawnAttacks[m_stm][s] & m_occupied_co[m_stm ^ 1]; } else { targets |= bb_PawnAttacks[m_stm][s] & (m_occupied_co[m_stm ^ 1] | SetBit(m_epSquare)); } return targets; } Move BitBoard::prepareMove(const Square& from, const Square& to) const { Q_ASSERT(from < 64); Q_ASSERT(to < 64); quint64 src = SetBit(from); quint64 dest = SetBit(to); Move move(from, to); uchar p = m_piece[from]; // Check for Illegal Move // first the source square must not be vacant if(!(m_occupied_co[m_stm] & src)) { return move; } // Check for Illegal Move // If the destination square is a piece of the moving color if(m_occupied_co[m_stm] & dest) { // If Not a null move if((src != dest) || p != King) { // move is neither legal nor a null move return move; } } move.setPieceType(p); uchar pCaptured = m_piece[to]; move.setCaptureType(pCaptured); if(pCaptured == King) { // This test became necessary with Null-Moves if(m_stm == Black) { move.setBlack(); } move.u = m_halfMoves; move.u |= (((unsigned short) m_castle & 0xF) << 8); move.u |= (((unsigned short) m_epFile & 0xF) << 12); return move; } if(p == King) { // if not a null Move if(src != dest) { if(!(kingAttacksFrom(to) & src) && !prepareCastle(move)) { return move; } } } else if(p == Pawn) { if(!(pawnMovesFrom(from) & dest)) { return move; } else if(to == m_epSquare) { move.setEnPassant(); } else if(dest & bb_PawnF2[m_stm][from]) { move.setTwoForward(); } else if(dest & bb_PromotionRank[m_stm]) { move.setPromoted(Queen); } } else { quint64 reach = 0; if(p == Queen) { reach = queenAttacksFrom(to); } else if(p == Rook) { reach = rookAttacksFrom(to); } else if(p == Bishop) { reach = bishopAttacksFrom(to); } else if(p == Knight) { reach = knightAttacksFrom(to); } if(!(reach & src)) { return move; } } BitBoard peek(*this); peek.doMove(move); peek.swapToMove(); if(peek.isCheck()) // Don't allow move into check even if its a null move { return move; } if(m_stm == Black) { move.setBlack(); } move.u = m_halfMoves; move.u |= (((unsigned short) m_castle & 0xF) << 8); move.u |= (((unsigned short) m_epFile & 0xF) << 12); if(src != dest) { move.setLegalMove(); } return move; } bool BitBoard::prepareCastle(Move& move) const { if(!canCastle(m_stm)) { return false; } Square to = move.to(); if(m_stm == White) { if(to == g1 && canCastleShort(White) && !((F1 | G1)&m_occupied)) if(!isAttackedBy(Black, e1) && !isAttackedBy(Black, f1)) { move.genWhiteOO(); return true; } if(to == c1 && canCastleLong(White) && !((B1 | C1 | D1)&m_occupied)) if(!isAttackedBy(Black, e1) && !isAttackedBy(Black, d1)) { move.genWhiteOOO(); return true; } } else { if(to == g8 && canCastleShort(Black) && !((F8 | G8)&m_occupied)) if(!isAttackedBy(White, e8) && !isAttackedBy(White, f8)) { move.genBlackOO(); return true; } if(to == c8 && canCastleLong(Black) && !((B8 | C8 | D8)&m_occupied)) if(!isAttackedBy(White, e8) && !isAttackedBy(White, d8)) { move.genBlackOOO(); return true; } } return false; } bool BitBoard::canBeReachedFrom(const BitBoard& target) const { if(m_pieceCount[White] > target.m_pieceCount[White] || m_pieceCount[Black] > target.m_pieceCount[Black] || m_pawnCount[White] > target.m_pawnCount[White] || m_pawnCount[Black] > target.m_pawnCount[Black]) { return false; } return true; } Piece BitBoard::pieceAt(Square s) const { Q_ASSERT(s < 64); quint64 bit = SetBit(s); if(m_occupied & bit) { if(m_occupied_co[White] & bit) { return Piece(m_piece[s]); } else { return Piece(m_piece[s] + 6); } } return Empty; } /** Return ASCII character for given piece to be used in FEN */ inline QChar pieceToChar(const Piece piece) { return piece > BlackPawn ? '?' : " KQRBNPkqrbnp"[piece]; }; /** Return ASCII character for given piece to be used in human FEN */ inline QChar pieceToHumanChar(const Piece piece) { return piece > BlackPawn ? '?' : " KQRBNPKQRBNP"[piece]; }; QString BitBoard::toFen() const { QString fen = ""; Piece piece; int empty = 0; //piece placement for(int row = 7; row >= 0; row--) { for(int col = 0; col < 8; ++col) { piece = pieceAt(8 * row + col); if(piece != Empty) { if(empty != 0) { fen += QString::number(empty); empty = 0; } fen += pieceToChar(piece); } else { empty++; } } if(empty != 0) { fen += QString::number(empty); empty = 0; } if(row != 0) { fen += '/'; } } //side to move fen += m_stm == White ? " w " : " b "; //castling rights if(castlingRights() == NoRights) { fen += "- "; } else { if(castlingRights() & WhiteKingside) { fen += 'K'; } if(castlingRights() & WhiteQueenside) { fen += 'Q'; } if(castlingRights() & BlackKingside) { fen += 'k'; } if(castlingRights() & BlackQueenside) { fen += 'q'; } fen += ' '; } //en passant square if(m_epSquare == NoEPSquare) { fen += "- "; } else { fen += 'a' + (m_epSquare & 7); fen += '1' + ((m_epSquare & 56) >> 3); fen += ' '; } // half move clock fen += QString::number(halfMoveClock()); fen += " "; // move number fen += QString::number(m_moveNumber <= 0 ? 1 : m_moveNumber); return fen; } QString BitBoard::toHumanFen() const { QString fenFormat = QCoreApplication::translate("BitBoard", "w%1\nb%2\n%3 to move."); QMap charLists; //piece placement for(int row = 7; row >= 0; row--) { for(int col = 0; col < 8; ++col) { Piece piece = pieceAt(8 * row + col); if(piece != Empty) { charLists[piece].append(QString("%1%2").arg(QChar('a' + col)).arg(row + 1)); } } } //side to move QString toMove = (m_stm == White) ? QCoreApplication::translate("BitBoard", "White") : QCoreApplication::translate("BitBoard", "Black"); QString w, b; for(Piece p = WhiteKing; p <= WhitePawn; ++p) { if(charLists.keys().contains(p)) { if(!w.isEmpty()) { w += ","; } w.append(pieceToHumanChar(p)); w.append(charLists[p].join(",")); } } for(Piece p = BlackKing; p != Empty; ++p) { if(charLists.keys().contains(p)) { if(!b.isEmpty()) { b += ","; } b.append(pieceToHumanChar(p)); b.append(charLists[p].join(",")); } } QString fen = fenFormat.arg(w).arg(b).arg(toMove); return fen; } /** Calculate global bit board values before starting */ void bitBoardInit() { bitBoardInitRun = true; int i, q; quint64 mask; // Square masks mask = 1; for(i = 0; i < 64; ++i) { bb_Mask[i] = mask << i; } for(i = 0; i < 64; ++i) { bb_MaskL90[i] = SetBit(RotateL90[i]); bb_MaskL45[i] = SetBit(RotateL45[i]); bb_MaskR45[i] = SetBit(RotateR45[i]); } // Pawn moves and attacks for(i = 0; i < 64; ++i) { mask = SetBit(i); bb_PawnAttacks[White][i] = ShiftUpLeft(mask); bb_PawnAttacks[White][i] |= ShiftUpRight(mask); bb_PawnAttacks[Black][i] = ShiftDownLeft(mask); bb_PawnAttacks[Black][i] |= ShiftDownRight(mask); bb_PawnF1[White][i] = ShiftUp(mask); bb_PawnF2[White][i] = Shift2Up(mask) & rank4; bb_PawnF1[Black][i] = ShiftDown(mask); bb_PawnF2[Black][i] = Shift2Down(mask) & rank5; bb_PawnALL[White][i] = bb_PawnAttacks[White][i] | bb_PawnF1[White][i] | bb_PawnF2[White][i]; bb_PawnALL[Black][i] = bb_PawnAttacks[Black][i] | bb_PawnF1[Black][i] | bb_PawnF2[Black][i]; } // Knight attacks for(i = 0; i < 64; ++i) { mask = SetBit(i); bb_KnightAttacks[i] = ShiftLeft(Shift2Up(mask)); bb_KnightAttacks[i] |= ShiftRight(Shift2Up(mask)); bb_KnightAttacks[i] |= ShiftLeft(Shift2Down(mask)); bb_KnightAttacks[i] |= ShiftRight(Shift2Down(mask)); bb_KnightAttacks[i] |= Shift2Left(ShiftUp(mask)); bb_KnightAttacks[i] |= Shift2Right(ShiftUp(mask)); bb_KnightAttacks[i] |= Shift2Left(ShiftDown(mask)); bb_KnightAttacks[i] |= Shift2Right(ShiftDown(mask)); } // Diagonal attacks for(int s = 0; s < 64; ++s) { for(int b = 0; b < 64; ++b) { mask = 0; q = s; while(File(q) > 0 && Rank(q) < 7) { q += 7; mask |= SetBit(q); if(b & (SetBit(RotateL45[q]) >> bb_ShiftL45[s])) { break; } } q = s; while(File(q) < 7 && Rank(q) > 0) { q -= 7; mask |= SetBit(q); if(b & (SetBit(RotateL45[q]) >> bb_ShiftL45[s])) { break; } } bb_L45Attacks[s][b] = mask; mask = 0; q = s; while(File(q) < 7 && Rank(q) < 7) { q += 9; mask |= SetBit(q); if(b & (SetBit(RotateR45[q]) >> bb_ShiftR45[s])) { break; } } q = s; while(File(q) > 0 && Rank(q) > 0) { q -= 9; mask |= SetBit(q); if(b & (SetBit(RotateR45[q]) >> bb_ShiftR45[s])) { break; } } bb_R45Attacks[s][b] = mask; } } // Rank and File attacks memset(bb_RankAttacks, 0, sizeof(bb_RankAttacks)); memset(bb_FileAttacks, 0, sizeof(bb_FileAttacks)); int file, rank; for(int sq = 0; sq < 64; ++sq) { for(int bitrow = 0; bitrow < 64; ++bitrow) { file = File(sq); q = sq + 1; while(++file < 8) { bb_RankAttacks[sq][bitrow] |= SetBit(q); if((1 << file) & (bitrow << 1)) { break; } ++q; } file = File(sq); q = sq - 1; while(--file >= 0) { bb_RankAttacks[sq][bitrow] |= SetBit(q); if((1 << file) & (bitrow << 1)) { break; } --q; } rank = Rank(sq); q = sq + 8; while(++rank < 8) { bb_FileAttacks[sq][bitrow] |= SetBit(q); if((1 << (7 - rank)) & (bitrow << 1)) { break; } q += 8; } rank = Rank(sq); q = sq - 8; while(--rank >= 0) { bb_FileAttacks[sq][bitrow] |= SetBit(q); if((1 << (7 - rank)) & (bitrow << 1)) { break; } q -= 8; } } } // King: for(i = 0; i < 64; ++i) { mask = SetBit(i); bb_KingAttacks[i] = ShiftLeft(mask); bb_KingAttacks[i] |= ShiftRight(mask); bb_KingAttacks[i] |= ShiftUp(mask); bb_KingAttacks[i] |= ShiftDown(mask); bb_KingAttacks[i] |= ShiftUpLeft(mask); bb_KingAttacks[i] |= ShiftUpRight(mask); bb_KingAttacks[i] |= ShiftDownLeft(mask); bb_KingAttacks[i] |= ShiftDownRight(mask); } // File and rank masks quint64 rseed = 0xFF00000000000000ULL; quint64 fseed = 0x8080808080808080ULL; for(i = 7; i >= 0; --i) { bb_rankMask[i] = rseed; rseed >>= 8; bb_fileMask[i] = fseed; fseed >>= 1; } // Pawn promotion ranks bb_PromotionRank[White] = bb_rankMask[7]; bb_PromotionRank[Black] = bb_rankMask[0]; // Now that global data has been calculated, we can create a start position standardPosition.fromFen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); } BitBoard getStandardPosition() { BitBoard b; b.fromFen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); return b; } QString BitBoard::moveToFullSan(const Move &move) const { QString dots = toMove() == White ? "." : "..."; return QString("%1%2%3").arg(m_moveNumber).arg(dots).arg(moveToSan(move)); } chessx-1.0.0/data/images/go_jump.png000644 001750 001750 00000015450 12144113023 020131 0ustar00niklasniklas000000 000000 PNG  IHDR>a CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs  tIME  OÎfIDATx]}pTuV+!`1bl!FM~I $vҙLqǙmgNh􏶢5]$ۍ;vLjƘ1aBxDS w9㽷]h?$cy{}q@QMlhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhT5&k0 ^A_s@jA?68f8bM V̘y3ʿ~:zs\1DŽ@?DU5hAچ63Daf0 S1mv̂0Ϙu.ա4=S™K`&2Щh{0^Whe@"_;l40p9}l^A`Q'{!uņĤm?ٺE`<g:je!5‹gcWbшIν1}|WϠy ]C MAh|Y}m/f(wācK^ڰ}&#u/F0B%G#,n&48>8v@r`‹ga0{4. ;zSW(Up^Z'"O'W1 C9=oG:7Vs9wEbъϡ݃8} NZ&h}oo%|gkTV[_z,4|lXOmt1oH]ITO;{HNVF{ewf&ƻ?o}A } yk)Ӽц@JG^%X }Oh~AVS޻fJLB ly$.~@A.G%Xmx' PBC ;b}ӗ'^ԍs-o%mGYo%%𝟬\[WS*lrX13J'i5>c 6^*pI~1,xtތ.X=g)N,^ڸ+vvZGQc@(=ՉXVNvXoMBjFCzNZVĘ?Ꝿ@ѶcW|@M}Jѧxw ʐ7-  -ɪ*p+y/֠x}N: "WOIP6TxOW4֥.@U.:cʈJtoh:=037aF[l`d'ͽ` D.P0*3q˚6h aݳ+O-$Am=w”tc8gN7מ鱦g YZaIPm`C6O [;}i慓5G(0be!bޔ2BB +9 Q}2C7yniˎ_XFS}1 :?yPb Ihzk~Bdž5-mȺf# Zx<4`"TIQ'4lA ^݄_'Qgy:k`lG_F[!2P'D `nwaw"){ 7= (HGN;RWH]MG[owcFy%m٩T?R``M7sxɪ8#Tܕ9Ӡ%)E K& s>]SA9IIHGFc/wmm/ W-ӫl eu 7 %R;#DŪ  @mx0E$$.]_O* `-oΚV/?Rd5Ruܕi&m QpU}f 5`}F"6k*NX>B'[{ct[ "A P"a0pEwD*WHȑ(R2 :CNV bW<_\08+X,/@1U?ND9f3:]]y*`0 p`{KʈYܿWضnjy{ II.\oO0-H!2˴"s7F )'F551X#;߂y!Є#lak؛=Nyɗ"Xrff3"F >Ta sCD͇vpg[Ջ3Trq^o>cW s{ȫ'~mV7zG]r}`Wص9a!UNC03fޔ3UU믷k>w*6'uLoϷ879T lA6!s_k|TXO/ml1 ^6њ:/&;5TڻGjXtcW?!#G ?=],yy O`uB2 `umPwg3Qbtf_C)@g!Bg=W73Cz$wy4O<ˠ،wH( P (Yx޿Ch.^wDnB1C [rI{!%;zF-9A$ cItg 7k~Y.=0 X89\7⶜WT&Q)QŔd\̒_S rЬR*G\= cJR_ ,+]N.dp4[>^Ɋi<9xa!K l Ȥe+UsHvL3=뻨vN> CE8Qf3S6a l%;H qFQ( $$CJ*WEF!r7HjS@($.Y=ݫ C YDH9 r%Q-eYƯ x&HE8Nn]&b9zY:k/S[)IstD2 T|\`obʰRjTNEaժx?/:!DHAU4 )C@Gmmm#IP[T|ܠ^_&@`snF2qK5x!v544444444444444444444444444444444444444444444444444444444444444*p#IENDB`chessx-1.0.0/src/quazip/quazipfile.cpp000644 001750 001750 00000037154 12223260306 020574 0ustar00niklasniklas000000 000000 /* Copyright (C) 2005-2011 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. **/ #include "quazipfile.h" using namespace std; /// The implementation class for QuaZip. /** \internal This class contains all the private stuff for the QuaZipFile class, thus allowing to preserve binary compatibility between releases, the technique known as the Pimpl (private implementation) idiom. */ class QuaZipFilePrivate { friend class QuaZipFile; private: /// The pointer to the associated QuaZipFile instance. QuaZipFile *q; /// The QuaZip object to work with. QuaZip *zip; /// The file name. QString fileName; /// Case sensitivity mode. QuaZip::CaseSensitivity caseSensitivity; /// Whether this file is opened in the raw mode. bool raw; /// Write position to keep track of. /** QIODevice::pos() is broken for non-seekable devices, so we need our own position. */ qint64 writePos; /// Uncompressed size to write along with a raw file. ulong uncompressedSize; /// CRC to write along with a raw file. quint32 crc; /// Whether \ref zip points to an internal QuaZip instance. /** This is true if the archive was opened by name, rather than by supplying an existing QuaZip instance. */ bool internal; /// The last error. int zipError; /// Resets \ref zipError. inline void resetZipError() const { setZipError(UNZ_OK); } /// Sets the zip error. /** This function is marked as const although it changes one field. This allows to call it from const functions that don't change anything by themselves. */ void setZipError(int zipError) const; /// The constructor for the corresponding QuaZipFile constructor. inline QuaZipFilePrivate(QuaZipFile *q): q(q), zip(NULL), internal(true), zipError(UNZ_OK) {} /// The constructor for the corresponding QuaZipFile constructor. inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName): q(q), internal(true), zipError(UNZ_OK) { zip = new QuaZip(zipName); } /// The constructor for the corresponding QuaZipFile constructor. inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName, const QString &fileName, QuaZip::CaseSensitivity cs): q(q), internal(true), zipError(UNZ_OK) { zip = new QuaZip(zipName); this->fileName = fileName; if(this->fileName.startsWith('/')) { this->fileName = this->fileName.mid(1); } this->caseSensitivity = cs; } /// The constructor for the QuaZipFile constructor accepting a file name. inline QuaZipFilePrivate(QuaZipFile *q, QuaZip *zip): q(q), zip(zip), internal(false), zipError(UNZ_OK) {} /// The destructor. inline ~QuaZipFilePrivate() { if(internal) { delete zip; } } }; QuaZipFile::QuaZipFile(): p(new QuaZipFilePrivate(this)) { } QuaZipFile::QuaZipFile(QObject *parent): QIODevice(parent), p(new QuaZipFilePrivate(this)) { } QuaZipFile::QuaZipFile(const QString& zipName, QObject *parent): QIODevice(parent), p(new QuaZipFilePrivate(this, zipName)) { } QuaZipFile::QuaZipFile(const QString& zipName, const QString& fileName, QuaZip::CaseSensitivity cs, QObject *parent): QIODevice(parent), p(new QuaZipFilePrivate(this, zipName, fileName, cs)) { } QuaZipFile::QuaZipFile(QuaZip *zip, QObject *parent): QIODevice(parent), p(new QuaZipFilePrivate(this, zip)) { } QuaZipFile::~QuaZipFile() { if(isOpen()) { close(); } delete p; } QString QuaZipFile::getZipName() const { return p->zip == NULL ? QString() : p->zip->getZipName(); } QuaZip *QuaZipFile::getZip() const { return p->internal ? NULL : p->zip; } QString QuaZipFile::getActualFileName()const { p->setZipError(UNZ_OK); if(p->zip == NULL || (openMode() & WriteOnly)) { return QString(); } QString name = p->zip->getCurrentFileName(); if(name.isNull()) { p->setZipError(p->zip->getZipError()); } return name; } void QuaZipFile::setZipName(const QString& zipName) { if(isOpen()) { qWarning("QuaZipFile::setZipName(): file is already open - can not set ZIP name"); return; } if(p->zip != NULL && p->internal) { delete p->zip; } p->zip = new QuaZip(zipName); p->internal = true; } void QuaZipFile::setZip(QuaZip *zip) { if(isOpen()) { qWarning("QuaZipFile::setZip(): file is already open - can not set ZIP"); return; } if(p->zip != NULL && p->internal) { delete p->zip; } p->zip = zip; p->fileName = QString(); p->internal = false; } void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs) { if(p->zip == NULL) { qWarning("QuaZipFile::setFileName(): call setZipName() first"); return; } if(!p->internal) { qWarning("QuaZipFile::setFileName(): should not be used when not using internal QuaZip"); return; } if(isOpen()) { qWarning("QuaZipFile::setFileName(): can not set file name for already opened file"); return; } p->fileName = fileName; if(p->fileName.startsWith('/')) { p->fileName = p->fileName.mid(1); } p->caseSensitivity = cs; } void QuaZipFilePrivate::setZipError(int zipError) const { QuaZipFilePrivate *fakeThis = const_cast(this); // non-const fakeThis->zipError = zipError; if(zipError == UNZ_OK) { q->setErrorString(QString()); } else { q->setErrorString(QString("ZIP/UNZIP API error %1").arg(zipError)); } } bool QuaZipFile::open(OpenMode mode) { return open(mode, NULL); } bool QuaZipFile::open(OpenMode mode, int *method, int *level, bool raw, const char *password) { p->resetZipError(); if(isOpen()) { qWarning("QuaZipFile::open(): already opened"); return false; } if(mode & Unbuffered) { qWarning("QuaZipFile::open(): Unbuffered mode is not supported"); return false; } if((mode & ReadOnly) && !(mode & WriteOnly)) { if(p->internal) { if(!p->zip->open(QuaZip::mdUnzip)) { p->setZipError(p->zip->getZipError()); return false; } if(!p->zip->setCurrentFile(p->fileName, p->caseSensitivity)) { p->setZipError(p->zip->getZipError()); p->zip->close(); return false; } } else { if(p->zip == NULL) { qWarning("QuaZipFile::open(): zip is NULL"); return false; } if(p->zip->getMode() != QuaZip::mdUnzip) { qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d", (int)mode, (int)p->zip->getMode()); return false; } if(!p->zip->hasCurrentFile()) { qWarning("QuaZipFile::open(): zip does not have current file"); return false; } } p->setZipError(unzOpenCurrentFile3(p->zip->getUnzFile(), method, level, (int)raw, password)); if(p->zipError == UNZ_OK) { setOpenMode(mode); p->raw = raw; return true; } else { return false; } } qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode); return false; } bool QuaZipFile::open(OpenMode mode, const QuaZipNewInfo& info, const char *password, quint32 crc, int method, int level, bool raw, int windowBits, int memLevel, int strategy) { zip_fileinfo info_z; p->resetZipError(); if(isOpen()) { qWarning("QuaZipFile::open(): already opened"); return false; } if((mode & WriteOnly) && !(mode & ReadOnly)) { if(p->internal) { qWarning("QuaZipFile::open(): write mode is incompatible with internal QuaZip approach"); return false; } if(p->zip == NULL) { qWarning("QuaZipFile::open(): zip is NULL"); return false; } if(p->zip->getMode() != QuaZip::mdCreate && p->zip->getMode() != QuaZip::mdAppend && p->zip->getMode() != QuaZip::mdAdd) { qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d", (int)mode, (int)p->zip->getMode()); return false; } info_z.tmz_date.tm_year = info.dateTime.date().year(); info_z.tmz_date.tm_mon = info.dateTime.date().month() - 1; info_z.tmz_date.tm_mday = info.dateTime.date().day(); info_z.tmz_date.tm_hour = info.dateTime.time().hour(); info_z.tmz_date.tm_min = info.dateTime.time().minute(); info_z.tmz_date.tm_sec = info.dateTime.time().second(); info_z.dosDate = 0; info_z.internal_fa = (uLong)info.internalAttr; info_z.external_fa = (uLong)info.externalAttr; if(!p->zip->isDataDescriptorWritingEnabled()) { zipClearFlags(p->zip->getZipFile(), ZIP_WRITE_DATA_DESCRIPTOR); } p->setZipError(zipOpenNewFileInZip3(p->zip->getZipFile(), p->zip->getFileNameCodec()->fromUnicode(info.name).constData(), &info_z, info.extraLocal.constData(), info.extraLocal.length(), info.extraGlobal.constData(), info.extraGlobal.length(), p->zip->getCommentCodec()->fromUnicode(info.comment).constData(), method, level, (int)raw, windowBits, memLevel, strategy, password, (uLong)crc)); if(p->zipError == UNZ_OK) { p->writePos = 0; setOpenMode(mode); p->raw = raw; if(raw) { p->crc = crc; p->uncompressedSize = info.uncompressedSize; } return true; } else { return false; } } qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode); return false; } bool QuaZipFile::isSequential()const { return true; } qint64 QuaZipFile::pos()const { if(p->zip == NULL) { qWarning("QuaZipFile::pos(): call setZipName() or setZip() first"); return -1; } if(!isOpen()) { qWarning("QuaZipFile::pos(): file is not open"); return -1; } if(openMode()&ReadOnly) // QIODevice::pos() is broken for sequential devices, // but thankfully bytesAvailable() returns the number of // bytes buffered, so we know how far ahead we are. { return unztell(p->zip->getUnzFile()) - QIODevice::bytesAvailable(); } else { return p->writePos; } } bool QuaZipFile::atEnd()const { if(p->zip == NULL) { qWarning("QuaZipFile::atEnd(): call setZipName() or setZip() first"); return false; } if(!isOpen()) { qWarning("QuaZipFile::atEnd(): file is not open"); return false; } if(openMode()&ReadOnly) // the same problem as with pos() return QIODevice::bytesAvailable() == 0 && unzeof(p->zip->getUnzFile()) == 1; else { return true; } } qint64 QuaZipFile::size()const { if(!isOpen()) { qWarning("QuaZipFile::atEnd(): file is not open"); return -1; } if(openMode()&ReadOnly) { return p->raw ? csize() : usize(); } else { return p->writePos; } } qint64 QuaZipFile::csize()const { unz_file_info info_z; p->setZipError(UNZ_OK); if(p->zip == NULL || p->zip->getMode() != QuaZip::mdUnzip) { return -1; } p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0)); if(p->zipError != UNZ_OK) { return -1; } return info_z.compressed_size; } qint64 QuaZipFile::usize()const { unz_file_info info_z; p->setZipError(UNZ_OK); if(p->zip == NULL || p->zip->getMode() != QuaZip::mdUnzip) { return -1; } p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0)); if(p->zipError != UNZ_OK) { return -1; } return info_z.uncompressed_size; } bool QuaZipFile::getFileInfo(QuaZipFileInfo *info) { if(p->zip == NULL || p->zip->getMode() != QuaZip::mdUnzip) { return false; } p->zip->getCurrentFileInfo(info); p->setZipError(p->zip->getZipError()); return p->zipError == UNZ_OK; } void QuaZipFile::close() { p->resetZipError(); if(p->zip == NULL || !p->zip->isOpen()) { return; } if(!isOpen()) { qWarning("QuaZipFile::close(): file isn't open"); return; } if(openMode()&ReadOnly) { p->setZipError(unzCloseCurrentFile(p->zip->getUnzFile())); } else if(openMode()&WriteOnly) if(isRaw()) { p->setZipError(zipCloseFileInZipRaw(p->zip->getZipFile(), p->uncompressedSize, p->crc)); } else { p->setZipError(zipCloseFileInZip(p->zip->getZipFile())); } else { qWarning("Wrong open mode: %d", (int)openMode()); return; } if(p->zipError == UNZ_OK) { setOpenMode(QIODevice::NotOpen); } else { return; } if(p->internal) { p->zip->close(); p->setZipError(p->zip->getZipError()); } } qint64 QuaZipFile::readData(char *data, qint64 maxSize) { p->setZipError(UNZ_OK); qint64 bytesRead = unzReadCurrentFile(p->zip->getUnzFile(), data, (unsigned)maxSize); if(bytesRead < 0) { p->setZipError((int) bytesRead); return -1; } return bytesRead; } qint64 QuaZipFile::writeData(const char* data, qint64 maxSize) { p->setZipError(ZIP_OK); p->setZipError(zipWriteInFileInZip(p->zip->getZipFile(), data, (unsigned int)maxSize)); if(p->zipError != ZIP_OK) { return -1; } else { p->writePos += maxSize; return maxSize; } } QString QuaZipFile::getFileName() const { return p->fileName; } QuaZip::CaseSensitivity QuaZipFile::getCaseSensitivity() const { return p->caseSensitivity; } bool QuaZipFile::isRaw() const { return p->raw; } int QuaZipFile::getZipError() const { return p->zipError; } qint64 QuaZipFile::bytesAvailable() const { return size() - pos(); } chessx-1.0.0/src/database/game.cpp000644 001750 001750 00000131112 12223260306 017554 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 Marius Roets * * (C) 2005-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include #include #include "game.h" QMap Game::m_ecoPositions; Game::Game() : QObject() { clearTags(); clear(); setModified(false); } Game::Game(const Game& game) : QObject() { *this = game; setModified(false); } Game& Game::operator=(const Game & game) { if(this != &game) { clearTags(); clear(); //assign non pointer variables m_tags = game.m_tags; m_startingBoard = game.m_startingBoard; m_variationStartAnnotations = game.m_variationStartAnnotations; m_annotations = game.m_annotations; m_squareAnnotations = game.m_squareAnnotations; m_arrowAnnotations = game.m_arrowAnnotations; m_clkAnnotations = game.m_clkAnnotations; m_egtAnnotations = game.m_egtAnnotations; m_currentNode = game.m_currentNode; m_startPly = game.m_startPly; m_currentBoard = game.m_currentBoard; m_moveNodes = game.m_moveNodes; setModified(true); } return *this; } Game::~Game() { } MoveId Game::addMove(const Move& move, const QString& annotation, NagSet nags) { MoveNode node; MoveId previousNode = m_currentNode; node.nextNode = NO_MOVE; node.previousNode = m_currentNode; node.parentNode = m_moveNodes[m_currentNode].parentNode; node.move = move; node.nags = nags; node.ply = ply() + 1; m_moveNodes.append(node); m_currentNode = m_moveNodes.size() - 1; if(!annotation.isEmpty()) { setAnnotation(annotation); } m_moveNodes[previousNode].nextNode = m_currentNode; m_currentBoard.doMove(move); setModified(true); return m_currentNode; } MoveId Game::addMove(const QString& sanMove, const QString& annotation, NagSet nags) { Move move = m_currentBoard.parseMove(sanMove); if(move.isLegal() || move.isNullMove()) { return addMove(move, annotation, nags); } return NO_MOVE; } bool Game::mergeNode(Game& otherGame) { SaveRestoreMove saveThis(*this); SaveRestoreMove saveOther(otherGame); QString ann; NagSet nags; otherGame.forward(); QString san = otherGame.moveToSan(MoveOnly, PreviousMove, CURRENT_MOVE, &ann, &nags); bool retVal = (NO_MOVE != addMove(san, ann, nags)); return retVal; } bool Game::mergeVariations(Game& otherGame) { QList variationList = otherGame.variations(); bool ok = true; if(variationList.size()) { int otherCurrent = otherGame.currentMove(); for(QList::iterator iter = variationList.begin(); iter != variationList.end(); ++iter) { otherGame.enterVariation(*iter); if(!mergeAsVariation(otherGame)) { ok = false; } otherGame.moveToId(otherCurrent); if(!ok) { break; } } } return ok; } bool Game::mergeAsMainline(Game& otherGame) { SaveRestoreMove saveNode(*this); QString ann; NagSet nags; QString san = otherGame.moveToSan(MoveOnly, PreviousMove, CURRENT_MOVE, &ann, &nags); if(NO_MOVE != addMove(san, ann, nags)) { while(!otherGame.atLineEnd()) { forward(); if(!mergeNode(otherGame)) { return false; } mergeVariations(otherGame); otherGame.forward(); } } else { return false; } return true; } bool Game::mergeAsVariation(Game& otherGame) { SaveRestoreMove saveNode(*this); QString ann; NagSet nags; QString san = otherGame.moveToSan(MoveOnly, PreviousMove, CURRENT_MOVE, &ann, &nags); if(NO_MOVE != addVariation(san, ann, nags)) { while(!otherGame.atLineEnd()) { forward(); if(!mergeNode(otherGame)) { return false; } mergeVariations(otherGame); otherGame.forward(); } } else { return false; } return true; } MoveId Game::findMergePoint(const Game& otherGame) { MoveId prevNode = NO_MOVE; MoveId trailNode = NO_MOVE; MoveId otherMergeNode = NO_MOVE; bool found = false; do { if(NO_MOVE == (otherMergeNode = otherGame.findPosition(board()))) { if(trailNode != NO_MOVE) { found = true; otherMergeNode = trailNode; break; } } else { prevNode = trailNode; trailNode = otherMergeNode; } } while(forward()); if(!found && atLineEnd()) { // Both games are identical up to the end of this game // Need to go one move back in the game to merge otherMergeNode = prevNode; } if(otherMergeNode == NO_MOVE) { if(otherGame.m_moveNodes.size() > 0) { otherMergeNode = 0; } } // otherMergeNode points to the move before the game diverges // If the complete games needs to be merged, it points to node 0 return otherMergeNode; } void Game::mergeWithGame(const Game& g) { MoveId saveNode = m_currentNode; Game otherGame = g; otherGame.moveToEnd(); // Set the game information on the last move so that it is merged into this game QString white = otherGame.tag(TagNameWhite); QString black = otherGame.tag(TagNameBlack); QString event = otherGame.eventInfo(); QString shortDescription = QString("%1-%2 %3").arg(white).arg(black).arg(event); otherGame.setAnnotation(shortDescription); MoveId otherMergeNode = findMergePoint(otherGame); // todo if(otherMergeNode != NO_MOVE) { backward(); // merge othergame starting with otherMergeNode into variation starting from m_currentNode otherGame.moveToId(otherMergeNode); otherGame.forward(); if(atLineEnd()) { mergeAsMainline(otherGame); } else { mergeAsVariation(otherGame); } otherGame.moveToId(otherMergeNode); mergeVariations(otherGame); } // undo changes if(saveNode != m_currentNode) { moveToId(saveNode); } compact(); } QString Game::eventInfo() const { QString result; QString site = tag(TagNameSite).left(30).remove("?"); QString event = tag(TagNameEvent).left(30).remove("?"); if(!site.isEmpty()) { result.append(site); if(tag("Round") != "?") { result.append(QString(" (%1)").arg(tag("Round"))); } if(!event.isEmpty()) { result.append(", "); } } result.append(event); if(!tag("Date").startsWith("?")) { if(result.length() > 4) { result.append(", "); } result.append(tag(TagNameDate).remove(".??")); } return result; } bool Game::currentNodeHasVariation(Square from, Square to) const { if(m_currentNode == NO_MOVE) { return false; } QList vs = m_moveNodes[m_currentNode].variations; QList::iterator i; for(i = vs.begin(); i != vs.end(); ++i) { Move m = move(*i); if(m.from() == from && m.to() == to) { return true; } } return false; } bool Game::currentNodeHasMove(Square from, Square to) const { if(currentNodeHasVariation(from, to)) { return true; } int node = m_moveNodes[m_currentNode].nextNode; if(node == NO_MOVE) { return true; } Move m = m_moveNodes[node].move; if(m.from() == from && m.to() == to) { return (m_moveNodes[node].nextNode != NO_MOVE); } return false; } // does the next main move or one of the variations go from square from to square to // if so make it on the board bool Game::findNextMove(Square from, Square to, PieceType promotionPiece) { int node; node = m_moveNodes[m_currentNode].nextNode; if(node != NO_MOVE) { Move m = m_moveNodes[node].move ; if(m.from() == from && m.to() == to && ((promotionPiece == None) || ((m.isPromotion() && (pieceType(m.promotedPiece()) == promotionPiece))))) { forward(); return true; } else { QList vs = m_moveNodes[m_currentNode].variations; QList::iterator i; for(i = vs.begin(); i != vs.end(); ++i) { Move m = move(*i); if(m.from() == from && m.to() == to && ((promotionPiece == None) || ((m.isPromotion() && (pieceType(m.promotedPiece()) == promotionPiece))))) { moveToId(*i); return true; } } } } return false; } bool Game::replaceMove(const Move& move, const QString& annotation, NagSet nags, bool bReplace) { int node; node = m_moveNodes[m_currentNode].nextNode; setModified(true); if(node == NO_MOVE) { addMove(move, annotation, nags); return true; } //replace node data with new move m_moveNodes[node].move = move; m_moveNodes[node].nags = nags; setAnnotation(annotation, node); //remove any following nodes after replaced move by disconnecting them from the tree forward(); if(bReplace) { truncateVariation(); } else { truncateVariationAfterNextIllegalPosition(); } backward(); return true; } bool Game::replaceMove(const QString& sanMove) { return replaceMove(m_currentBoard.parseMove(sanMove), QString(), NagSet(), true); } bool Game::insertMove(Move m) { return replaceMove(m, annotation(), nags(), false); } MoveId Game::addVariation(const Move& move, const QString& annotation, NagSet nags) { MoveId previousNode = m_currentNode; MoveId saveNextNode = m_moveNodes[m_currentNode].nextNode; MoveId node = addMove(move, annotation, nags); m_moveNodes[m_currentNode].parentNode = previousNode; m_moveNodes[previousNode].variations.append(node); m_moveNodes[previousNode].nextNode = saveNextNode; return (m_moveNodes.size() - 1); } MoveId Game::addVariation(const MoveList& moveList, const QString& annotation) { if(moveList.isEmpty()) { return NO_MOVE; } MoveId currentPosition = currentMove(); MoveId varStart; int start = 1; if(!atLineEnd()) { varStart = addVariation(moveList.first()); } else if(!atGameStart()) { Move oldMove = move(); backward(); varStart = addVariation(oldMove); start = 0; } else { varStart = addMove(moveList.first()); } moveToId(varStart); for(int i = start; i < moveList.count(); ++i) { addMove(moveList[i]); forward(); } if(!annotation.isEmpty()) { setAnnotation(annotation); } moveToId(currentPosition); return varStart; } MoveId Game::addVariation(const QString& sanMove, const QString& annotation, NagSet nags) { MoveId previousNode = m_currentNode; MoveId saveNextNode = m_moveNodes[m_currentNode].nextNode; MoveId node = addMove(sanMove, annotation, nags); if(node == NO_MOVE) { return node; } m_moveNodes[m_currentNode].parentNode = previousNode; m_moveNodes[previousNode].variations.append(node); m_moveNodes[previousNode].nextNode = saveNextNode; return (m_moveNodes.size() - 1); } bool Game::promoteVariation(MoveId variation) { if(isMainline(variation)) { return false; } MoveId currentNode = m_currentNode; // Save current move // Find first move of the variation while(!atLineStart(variation)) { variation = m_moveNodes[variation].previousNode; } MoveId parent = m_moveNodes[variation].parentNode; // Link old main line to parent reparentVariation(m_moveNodes[parent].nextNode, parent); // Link new main line to parent's parent reparentVariation(variation, m_moveNodes[parent].parentNode); // Swap main line and the variation int index = m_moveNodes[parent].variations.indexOf(variation); qSwap(m_moveNodes[parent].nextNode, m_moveNodes[parent].variations[index]); moveToId(currentNode); // Restore current move return true; } bool Game::removeVariation(MoveId variation) { // don't remove whole game if(!variation) { return false; } MoveId parentNode = m_moveNodes[variation].parentNode; removeNode(variation); moveToId(parentNode); QList &vars = m_moveNodes[m_currentNode].variations; vars.removeAt(vars.indexOf(variation)); compact(); return true; } void Game::truncateVariationAfterNextIllegalPosition() { SaveRestoreMove saveNode(*this); QList variationList = variations(); for(QList::iterator iter = variationList.begin(); iter != variationList.end(); ++iter) { SaveRestoreMove saveNodeLoop(*this); enterVariation(*iter); truncateVariationAfterNextIllegalPosition(); } QString san = moveToSan(); Game g = *this; if(NO_MOVE == g.addMove(san)) { int node = m_moveNodes[m_currentNode].nextNode; removeNode(node); } else { if(forward()) { truncateVariationAfterNextIllegalPosition(); } } } void Game::truncateVariation(Position position) { if(position == AfterMove) { int node = m_moveNodes[m_currentNode].nextNode; removeNode(node); } else if(position == BeforeMove && m_currentNode != 0) { if(atLineStart()) { backward(); forward(); } MoveId current = m_currentNode; MoveNode firstNode; firstNode.nextNode = m_currentNode; firstNode.ply = m_moveNodes[m_currentNode].ply - 1; // Keep variation if truncating main line if(m_moveNodes[m_moveNodes[m_currentNode].previousNode].nextNode == m_currentNode) { firstNode.variations = m_moveNodes[m_moveNodes[m_currentNode].previousNode].variations; foreach(MoveId var, firstNode.variations) { reparentVariation(var, 0); m_moveNodes[var].previousNode = 0; } } m_moveNodes[0] = firstNode; m_moveNodes[m_currentNode].previousNode = 0; backward(); m_startingBoard = m_currentBoard; if(m_startingBoard != standardStartBoard) { m_tags[TagNameFEN] = m_startingBoard.toFen(); m_tags[TagNameSetUp] = "1"; } moveToId(current); } compact(); } const Board& Game::board() const { return m_currentBoard; } Board Game::startingBoard() const { return m_startingBoard; } QString Game::toFen() const { return m_currentBoard.toFen(); } QString Game::toHumanFen() const { return m_currentBoard.toHumanFen(); } QString Game::gameComment() const { return m_annotations.value(0, ""); } void Game::setGameComment(const QString& gameComment) { setAnnotation(gameComment, 0); } void Game::removeVariations() { for(int i = 0; i < m_moveNodes.size(); ++i) { m_moveNodes[i].variations.clear(); } compact(); setModified(true); } void Game::removeComments() { m_variationStartAnnotations.clear(); m_annotations.clear(); m_squareAnnotations.clear(); m_arrowAnnotations.clear(); m_clkAnnotations.clear(); m_egtAnnotations.clear(); for(int i = 0; i < m_moveNodes.size(); ++i) { m_moveNodes[i].nags.clear(); } compact(); setModified(true); } bool Game::isMainline(MoveId moveId) const { if(moveId == 0) { return true; } MoveId node = nodeValid(moveId); if(node == NO_MOVE) { return false; } else { return m_moveNodes[node].parentNode == NO_MOVE; } } Result Game::result() const { if(m_tags["Result"] == "1-0") { return WhiteWin; } else if(m_tags["Result"] == "1/2-1/2") { return Draw; } else if(m_tags["Result"] == "0-1") { return BlackWin; } else { return ResultUnknown; } } int Game::numberOfSiblings(MoveId moveId) const { MoveId node = nodeValid(moveId); if(node == NO_MOVE) { return 0; } MoveId parentNode = m_moveNodes[node].parentNode; if(parentNode == NO_MOVE) { return 0; } return m_moveNodes[parentNode].variations.size(); } bool Game::atLineStart(MoveId moveId) const { MoveId node = nodeValid(moveId); if(node == NO_MOVE) { return false; } return (m_moveNodes[node].previousNode == m_moveNodes[node].parentNode) || m_moveNodes[node].previousNode == 0; } bool Game::atGameStart(MoveId moveId) const { return (nodeValid(moveId) == 0); } bool Game::atGameEnd(MoveId moveId) const { return (atLineEnd(moveId) && isMainline(moveId)); } bool Game::atLineEnd(MoveId moveId) const { MoveId node = nodeValid(moveId); if(node != NO_MOVE) { if(m_moveNodes[node].nextNode == NO_MOVE) { return true; } } return false; } bool Game::setAnnotation(QString annotation, MoveId moveId, Position position) { MoveId node = nodeValid(moveId); if(node == NO_MOVE) { return false; } setModified(true); QString specAnnot = specialAnnotation(annotation, "[%csl"); if(position == Game::AfterMove || node == 0) { setSquareAnnotation(specAnnot, node); } else { setSquareAnnotation(specAnnot, m_moveNodes[node].previousNode); } specAnnot = specialAnnotation(annotation, "[%cal"); if(position == Game::AfterMove || node == 0) { setArrowAnnotation(specAnnot, node); } else { setArrowAnnotation(specAnnot, m_moveNodes[node].previousNode); } specAnnot = specialAnnotation(annotation, "[%egt"); if(position == Game::AfterMove || node == 0) { setEgtAnnotation(specAnnot, node); } else { setEgtAnnotation(specAnnot, m_moveNodes[node].previousNode); } specAnnot = specialAnnotation(annotation, "[%clk"); if(position == Game::AfterMove || node == 0) { setClkAnnotation(specAnnot, node); } else { setClkAnnotation(specAnnot, m_moveNodes[node].previousNode); } annotation.remove(QRegExp("\\[%csl[^\\]]*\\]")); annotation.remove(QRegExp("\\[%cal[^\\]]*\\]")); annotation.remove(QRegExp("\\[%clk[^\\]]*\\]")); annotation.remove(QRegExp("\\[%egt[^\\]]*\\]")); int moves; int comments; int nags; moveCount(&moves, &comments, &nags); if(position == AfterMove) { if(annotation.isEmpty()) { m_annotations.remove(node); } else { m_annotations[node] = annotation; } } else if(canHaveStartAnnotation(node)) // Pre-move comment { if(annotation.isEmpty()) { m_variationStartAnnotations.remove(node); } else { m_variationStartAnnotations[node] = annotation; } } return true; } bool Game::setSquareAnnotation(QString squareAnnotation, MoveId moveId) { MoveId node = nodeValid(moveId); if(node == NO_MOVE) { return false; } if(squareAnnotation.isEmpty()) { m_squareAnnotations.remove(node); } else { m_squareAnnotations[node] = squareAnnotation; } return true; } bool Game::appendSquareAnnotation(Square s, QChar colorCode) { setModified(true); QString newAnnot; QString annot = squareAnnotation(); QString oldAnnot = annot; QString sq = strSquareNames[s]; if(annot.isEmpty()) { if(colorCode != QChar(0)) { newAnnot = QString("%1%2").arg(colorCode).arg(sq); } } else { annot.replace(QRegExp(QString(",.") + sq), ""); // if not first annotation remove annotation with preceding comma annot.replace(QRegExp(QString(".") + sq + ","), ""); // if first annotation remove annotation with trailing comma annot.replace(QRegExp(QString(".") + sq), ""); // if only annotation remove annotation if(colorCode != QChar(0)) { if(annot.isEmpty()) { newAnnot = QString("%1%2").arg(colorCode).arg(sq); // If only annotation don't add comma } else { newAnnot = QString("%1,%2%3").arg(annot).arg(colorCode).arg(sq); // if not only annotation add comma } } else { if(!annot.isEmpty()) { newAnnot = annot; } } newAnnot.replace(" ,", " "); newAnnot.replace(",,", ","); if(newAnnot.endsWith("'")) { newAnnot.truncate(newAnnot.length() - 1); } } setSquareAnnotation(newAnnot); return true; } bool Game::appendArrowAnnotation(Square dest, Square src, QChar colorCode) { if((src == InvalidSquare) || (dest == InvalidSquare)) { return false; } setModified(true); QString newAnnot; QString annot = arrowAnnotation(); QString sqSrc = strSquareNames[src]; QString sqDest = strSquareNames[dest]; if(annot.isEmpty()) { if(colorCode != QChar(0)) { newAnnot = QString("%1%2%3").arg(colorCode).arg(sqSrc).arg(sqDest); } } else { annot.replace(QRegExp(QString(",.") + sqSrc + sqDest), ""); // if not first annotation remove annotation with preceding comma annot.replace(QRegExp(QString(".") + sqSrc + sqDest + ","), ""); // if first annotation remove annotation with trailing comma annot.replace(QRegExp(QString(".") + sqSrc + sqDest), ""); // if only annotation remove annotation if(colorCode != QChar(0)) { newAnnot = QString("%1,%2%3%4").arg(annot).arg(colorCode).arg(sqSrc).arg(sqDest); } else { if(!annot.isEmpty()) { newAnnot = annot; } } newAnnot.replace(" ,", " "); newAnnot.replace(",,", ","); if(newAnnot.endsWith("'")) { newAnnot.truncate(newAnnot.length() - 1); } } setArrowAnnotation(newAnnot); return true; } QString Game::squareAnnotation(MoveId moveId) const { MoveId node = nodeValid(moveId); if(node == NO_MOVE) { return ""; } QString annotation = m_squareAnnotations[node]; if(annotation.isNull()) { return ""; } return m_squareAnnotations[node].simplified(); } bool Game::setArrowAnnotation(QString arrowAnnotation, MoveId moveId) { MoveId node = nodeValid(moveId); if(node == NO_MOVE) { return false; } if(arrowAnnotation.isEmpty()) { m_arrowAnnotations.remove(node); } else { m_arrowAnnotations[node] = arrowAnnotation; } return true; } QString Game::arrowAnnotation(MoveId moveId) const { MoveId node = nodeValid(moveId); if(node == NO_MOVE) { return ""; } QString annotation = m_arrowAnnotations[node]; if(annotation.isNull()) { return ""; } return m_arrowAnnotations[node].simplified(); } bool Game::setEgtAnnotation(QString annotation, MoveId moveId) { MoveId node = nodeValid(moveId); if(node == NO_MOVE) { return false; } if(annotation.isEmpty()) { m_egtAnnotations.remove(node); } else { m_egtAnnotations[node] = annotation; } return true; } QString Game::egtAnnotation(MoveId moveId) const { MoveId node = nodeValid(moveId); if(node == NO_MOVE) { return ""; } QString annotation = m_egtAnnotations[node]; if(annotation.isNull()) { return ""; } return m_egtAnnotations[node]; } QString Game::timeAnnotation(MoveId moveId) const { QString s = clkAnnotation(moveId); if(s.isEmpty()) { return egtAnnotation(moveId); } return s; } bool Game::setClkAnnotation(QString annotation, MoveId moveId) { MoveId node = nodeValid(moveId); if(node == NO_MOVE) { return false; } if(annotation.isEmpty()) { m_clkAnnotations.remove(node); } else { m_clkAnnotations[node] = annotation; } return true; } QString Game::clkAnnotation(MoveId moveId) const { MoveId node = nodeValid(moveId); if(node == NO_MOVE) { return ""; } QString annotation = m_clkAnnotations[node]; if(annotation.isNull()) { return ""; } return m_clkAnnotations[node]; } QString Game::composeAnnotation(QString freeText, MoveId node) const { if(!m_squareAnnotations[node].isEmpty()) { freeText.append(QString("[%csl %1]").arg(m_squareAnnotations[node])); } if(!m_arrowAnnotations[node].isEmpty()) { freeText.append(QString("[%cal %1]").arg(m_arrowAnnotations[node])); } if(!m_clkAnnotations[node].isEmpty()) { freeText.append(QString("[%clk %1]").arg(m_clkAnnotations[node])); } if(!m_egtAnnotations[node].isEmpty()) { freeText.append(QString("[%egt %1]").arg(m_egtAnnotations[node])); } return freeText; } QString Game::annotation(MoveId moveId, Position position) const { MoveId node = nodeValid(moveId); if(position == AfterMove) { return composeAnnotation(m_annotations.value(node, ""), node); } else { if(node == 0) { return composeAnnotation(m_annotations.value(0, ""), 0); } else { return m_variationStartAnnotations.value(node, ""); } } } QString Game::textAnnotation(MoveId moveId, Position position) const { MoveId node = nodeValid(moveId); if(position == AfterMove) { return m_annotations.value(node, ""); } else { if(node == 0) { return m_annotations.value(0, ""); } else { return m_variationStartAnnotations.value(node, ""); } } } bool Game::canHaveStartAnnotation(MoveId moveId) const { MoveId node = nodeValid(moveId); return atLineStart(moveId) || atGameStart(m_moveNodes[node].previousNode); } bool Game::addNag(Nag nag, MoveId moveId) { MoveId node = nodeValid(moveId); if(node != NO_MOVE) { m_moveNodes[node].nags.addNag(nag); setModified(true); return true; } return false; } bool Game::setNags(NagSet nags, MoveId moveId) { MoveId node = nodeValid(moveId); if(node != NO_MOVE) { m_moveNodes[node].nags = nags; setModified(true); return true; } return false; } bool Game::clearNags(MoveId moveId) { return setNags(NagSet(), moveId); } NagSet Game::nags(MoveId moveId) const { MoveId node = nodeValid(moveId); if(node != NO_MOVE) { return m_moveNodes[node].nags; } return NagSet(); } MoveId Game::nodeValid(MoveId moveId) const { if(moveId == CURRENT_MOVE) { moveId = m_currentNode; } if((moveId >= 0) && (moveId < m_moveNodes.size())) { if(m_moveNodes[moveId].removed) { return NO_MOVE; } return moveId; } return NO_MOVE; } void Game::moveCount(int* moves, int* comments, int* nags) const { *moves = *comments = *nags = 0; int node = 1; while(nodeValid(node) != NO_MOVE) { *moves += 1; if(m_moveNodes[node].nags.count() != 0) { *nags += 1; } node = m_moveNodes[node].nextNode; } // Count comments for(int i = 0; i < m_annotations.size(); ++i) { *comments += 1; } for(int i = 0; i < m_variationStartAnnotations.size(); ++i) { *comments += 1; } } int Game::ply(MoveId moveId) const { MoveId node = nodeValid(moveId); if(node != NO_MOVE) { return m_moveNodes[node].ply; } return 0; } int Game::moveNumber(MoveId moveId) const { MoveId node = nodeValid(moveId); if(node != NO_MOVE) { if(int plyNum = ply(node)) { return (m_startPly + plyNum - 1) / 2 + 1; } return 0; } return -1; } int Game::plyCount() const { int count = 0; int node = 0; while(node != NO_MOVE) { ++count; node = m_moveNodes[node].nextNode; } // Counted one too much, because we have to start at zero // (an empty game has no node 1) return count - 1; } bool Game::canMoveVariationUp(MoveId moveId) const { if(isMainline()) { return false; } MoveId variation = variationNumber(moveId); MoveId parentNode = m_moveNodes[moveId].parentNode; const QList & v = m_moveNodes[parentNode].variations; int i = v.indexOf(variation); return (i > 0); } void Game::moveVariationUp(MoveId moveId) { if(isMainline()) { return; } MoveId variation = variationNumber(moveId); MoveId parentNode = m_moveNodes[moveId].parentNode; QList & v = m_moveNodes[parentNode].variations; int i = v.indexOf(variation); if(i > 0) { v.swap(i, i - 1); setModified(true); } } bool Game::canMoveVariationDown(MoveId moveId) const { if(isMainline()) { return false; } MoveId variation = variationNumber(moveId); MoveId parentNode = m_moveNodes[moveId].parentNode; const QList & v = m_moveNodes[parentNode].variations; int i = v.indexOf(variation); return (i >= 0 && (i + 1) < v.count()); } void Game::moveVariationDown(MoveId moveId) { if(isMainline()) { return; } MoveId variation = variationNumber(moveId); MoveId parentNode = m_moveNodes[moveId].parentNode; QList & v = m_moveNodes[parentNode].variations; int i = v.indexOf(variation); if(i >= 0 && (i + 1) < v.count()) { v.swap(i, i + 1); setModified(true); } } void Game::enumerateVariations(MoveId moveId, char a) { if(isMainline()) { return; } MoveId node = nodeValid(moveId); if(node != NO_MOVE) { MoveId parentNode = m_moveNodes[node].parentNode; QList & v = m_moveNodes[parentNode].variations; for(int i = 0; i < v.size(); ++i) { QString oldAnnotation = annotation(v[i], Game::BeforeMove); oldAnnotation.remove(QRegExp("^.\\)")); QString s = QString("%1) %2").arg(QChar(a + i)).arg(oldAnnotation).trimmed(); setAnnotation(s, v[i], Game::BeforeMove); } } } MoveId Game::variationNumber(MoveId moveId) const { if(isMainline()) { return 0; } MoveId node = nodeValid(moveId); if(node != NO_MOVE) { MoveId parentNode = m_moveNodes[node].parentNode; while(m_moveNodes[node].previousNode != parentNode) { node = m_moveNodes[node].previousNode; } } return node; } MoveId Game::mainLineMove() const { MoveId node = nodeValid(m_currentNode); if(node != NO_MOVE) { bool dive = false; while(m_moveNodes[node].parentNode != NO_MOVE) { dive = true; node = m_moveNodes[node].parentNode; } if(dive) { node = m_moveNodes[node].nextNode; } } return node; } MoveId Game::previousMove() const { return m_moveNodes[m_currentNode].previousNode; } MoveId Game::nextMove() const { return m_moveNodes[m_currentNode].nextNode; } MoveId Game::parentMove() const { return m_moveNodes[m_currentNode].parentNode; } MoveId Game::currentMove() const { return m_currentNode; } const QList& Game::variations() const { return m_moveNodes[m_currentNode].variations; } int Game::variationCount(MoveId moveId) const { MoveId node = nodeValid(moveId); if(node != NO_MOVE) { return m_moveNodes[node].variations.size(); } return 0; } bool Game::variationHasSiblings(MoveId variation) const { if(isMainline(variation)) { return false; } while(!atLineStart(variation)) { variation = m_moveNodes[variation].previousNode; } MoveId parent = m_moveNodes[m_currentNode].parentNode; return (variationCount(parent) > 1); } bool Game::isModified() const { return m_isModified; } void Game::setModified(bool set) { m_isModified = set; } void Game::indicateAnnotationsOnBoard(MoveId moveId) { QString annotation = squareAnnotation(moveId); m_currentBoard.setSquareAnnotation(annotation); annotation = arrowAnnotation(moveId); m_currentBoard.setArrowAnnotation(annotation); } void Game::moveToStart() { m_currentNode = 0; m_currentBoard = m_startingBoard; indicateAnnotationsOnBoard(m_currentNode); } int Game::moveByPly(int diff) { if(diff > 0) { return forward(diff); } else { return backward(-diff); } } void Game::moveToId(MoveId moveId) { if(nodeValid(moveId) == NO_MOVE) { return; } //jump to node, travelling back to start adding the moves to the stack int node = moveId; QStack < Move > moveStack; while(node) { moveStack.push(m_moveNodes[node].move); node = m_moveNodes[node].previousNode; } //reset the board, then make the moves on the stack to create the correct position m_currentNode = moveId; m_currentBoard = m_startingBoard; while(!moveStack.isEmpty()) { m_currentBoard.doMove(moveStack.pop()); } indicateAnnotationsOnBoard(moveId); } int Game::moveToPly(int ply) { if(ply == 0) { moveToStart(); return 0; } int currentPly = this->ply(); int diff = ply - currentPly; if(diff > 0) { return currentPly + forward(diff); } else { return currentPly - backward(-diff); } } Move Game::move(MoveId moveId) const { MoveId node = nodeValid(moveId); if(node != NO_MOVE) { return m_moveNodes[node].move; } return Move(); } void Game::moveToEnd() { // Move out of variations to mainline while(m_moveNodes[m_currentNode].parentNode != NO_MOVE) { moveToId(m_moveNodes[m_currentNode].parentNode); } // Now move forward to the end of the game while(m_moveNodes[m_currentNode].nextNode != NO_MOVE) { forward(1); } } int Game::forward(int count) { int moved = 0; while((m_moveNodes[m_currentNode].nextNode != NO_MOVE) && (moved < count)) { m_currentNode = m_moveNodes[m_currentNode].nextNode; ++moved; m_currentBoard.doMove(m_moveNodes[m_currentNode].move); } if(moved) { indicateAnnotationsOnBoard(m_currentNode); } return moved; } int Game::backward(int count) { int moved = 0; while((m_moveNodes[m_currentNode].previousNode >= 0) && (moved < count)) { m_currentBoard.undoMove(m_moveNodes[m_currentNode].move); m_currentNode = m_moveNodes[m_currentNode].previousNode; ++moved; } if(moved) { indicateAnnotationsOnBoard(m_currentNode); } return moved; } void Game::enterVariation(const MoveId& moveId) { Q_ASSERT(variations().contains(moveId)); m_currentBoard.doMove(m_moveNodes[moveId].move); m_currentNode = moveId; indicateAnnotationsOnBoard(m_currentNode); } void Game::removeNode(MoveId moveId) { MoveId node = nodeValid(moveId); if(node != NO_MOVE) { setModified(true); if(variationCount(node)) { for(int i = 0; i < m_moveNodes[node].variations.size(); ++i) { removeNode(m_moveNodes[node].variations[i]); } } removeNode(m_moveNodes[node].nextNode); if(!atLineStart(node)) { m_moveNodes[m_moveNodes[node].previousNode].nextNode = NO_MOVE; } m_moveNodes[node].remove(); } } void Game::clear() { m_moveNodes.clear(); m_variationStartAnnotations.clear(); m_annotations.clear(); m_squareAnnotations.clear(); m_arrowAnnotations.clear(); m_clkAnnotations.clear(); m_egtAnnotations.clear(); m_startPly = 0; m_currentNode = 0; m_startingBoard.setStandardPosition(); m_currentBoard = m_startingBoard; m_moveNodes.append(MoveNode()); setModified(true); } void Game::clearTags() { m_tags.clear(); setModified(true); } QString Game::tag(const QString& tag) const { return m_tags[tag]; } const QMap& Game::tags() const { return m_tags; } void Game::setTag(const QString& tag, const QString& value) { m_tags[tag] = value; } void Game::removeTag(const QString& tag) { m_tags.remove(tag); } void Game::setStartingBoard(const Board& startingBoard) { setStartingBoard(startingBoard.toFen()); } void Game::setStartingBoard(const QString& fen) { clear(); m_startingBoard.fromFen(fen); if(m_startingBoard != standardStartBoard) { m_tags[TagNameFEN] = fen; m_tags[TagNameSetUp] = "1"; } m_currentBoard = m_startingBoard; m_startPly = (m_startingBoard.moveNumber() - 1) * 2 + (m_startingBoard.toMove() == Black); } void Game::setResult(Result result) { m_tags["Result"] = resultString(result); setModified(true); } QString Game::moveToSan(MoveStringFlags flags, NextPreviousMove nextPrevious, MoveId moveId, QString* annots, NagSet* nagSet) { MoveId node = nodeValid(moveId); if(node != NO_MOVE && nextPrevious == NextMove) { node = m_moveNodes[node].nextNode; } if(node == NO_MOVE) { return QString(); } MoveNode move; move = m_moveNodes[node]; if(!(move.move.isLegal() || move.move.isNullMove())) { return QString(); } // Save current node MoveId saveNode = NO_MOVE; MoveId boardNode = m_moveNodes[node].previousNode; if(boardNode != m_currentNode) { saveNode = m_currentNode; moveToId(boardNode); } // Move number QString san; if(m_currentBoard.toMove() == Black && flags & BlackNumbers) { san += QString::number(moveNumber(node)) + "... "; } else if(m_currentBoard.toMove() == White && flags & WhiteNumbers) { san += QString::number(moveNumber(node)) + ". "; } // Move and SAN san += m_currentBoard.moveToSan(move.move, flags & TranslatePiece); if(flags & Nags) { san += nags(node).toString(NagSet::Simple); } if(nagSet) { *nagSet = nags(node); } if(annots) { *annots = annotation(node); } // Restore previous position if(saveNode != NO_MOVE) { moveToId(saveNode); } return san; } void Game::dumpMoveNode(MoveId moveId) { if(moveId == CURRENT_MOVE) { moveId = m_currentNode; } if(moveId != NO_MOVE) { qDebug() << "Move Id : " << moveId; qDebug() << " Next node : " << m_moveNodes[moveId].nextNode; qDebug() << " Prev node : " << m_moveNodes[moveId].previousNode; qDebug() << " Parent node : " << m_moveNodes[moveId].parentNode; qDebug() << " Nags : " << m_moveNodes[moveId].nags.toString(NagSet::Simple); qDebug() << " Deleted : " << m_moveNodes[moveId].removed; qDebug() << " # Variations: " << m_moveNodes[moveId].variations.size(); qDebug() << " Variations : " << m_moveNodes[moveId].variations; qDebug() << " Move : " << moveToSan(FullDetail, PreviousMove, moveId); } } void Game::dumpAnnotations(MoveId moveId) { if(moveId == CURRENT_MOVE) { moveId = m_currentNode; } if(moveId != NO_MOVE) { qDebug() << " Annotations : "; qDebug() << " Text : " << m_annotations[moveId]; qDebug() << " Square : " << m_squareAnnotations[moveId]; qDebug() << " Arrow : " << m_arrowAnnotations[moveId]; qDebug() << " CLK : " << m_clkAnnotations[moveId]; qDebug() << " EGT : " << m_egtAnnotations[moveId]; qDebug() << " Start : " << m_variationStartAnnotations[moveId]; } } void Game::dumpAllMoveNodes() { qDebug() << endl; qDebug() << "Current Node: " << m_currentNode; for(int i = 0; i < m_moveNodes.size(); ++i) { dumpMoveNode(i); dumpAnnotations(i); } int moves, comments, nags; moveCount(&moves, &comments, &nags); qDebug() << "Moves: " << moves << " Comments: " << comments << " Nags: " << nags; } int Game::findPosition(const Board& position) const { MoveId current = 0; Board currentBoard(m_startingBoard); for(;;) { if(currentBoard == position && currentBoard.positionIsSame(position)) { return current; } current = m_moveNodes[current].nextNode; if(current == NO_MOVE || !position.canBeReachedFrom(currentBoard)) { return NO_MOVE; } currentBoard.doMove(m_moveNodes[current].move); } return NO_MOVE; } bool Game::loadEcoFile(const QString& ecoFile) { QFile file(ecoFile); if(file.open(QIODevice::ReadOnly)) { QDataStream sin(&file); quint32 id; sin >> id; if(id == COMPILED_ECO_FILE_ID) { sin >> m_ecoPositions; return true; } return false; } return false; } void Game::compact() { int oldSize = m_moveNodes.size(); QList moveNodes; QVector oldIdNewIdMapping(oldSize, NO_MOVE); for(int i = 0; i < oldSize; ++i) { if(!m_moveNodes[i].removed) { oldIdNewIdMapping[i] = moveNodes.size(); moveNodes.append(m_moveNodes[i]); } } // update nodes links to other nodes in shrinked list (prev, next, variations) for(int i = 0, newSize = moveNodes.size(); i < newSize; ++i) { MoveNode& node = moveNodes[i]; #define GAME_UPDATE_MOVEID(aMoveId) if (aMoveId != NO_MOVE) aMoveId = oldIdNewIdMapping[aMoveId] GAME_UPDATE_MOVEID(node.nextNode); GAME_UPDATE_MOVEID(node.previousNode); GAME_UPDATE_MOVEID(node.parentNode); QList& vars = node.variations; for(int j = 0; j < vars.size(); ++j) { GAME_UPDATE_MOVEID(vars[j]); } vars.removeAll(NO_MOVE); #undef GAME_UPDATE_LINK } m_moveNodes.clear(); m_moveNodes = moveNodes; m_currentNode = oldIdNewIdMapping[m_currentNode]; } QString Game::ecoClassify() { //move to end of main line MoveId currentNode = m_currentNode; moveToEnd(); //search backwards for the first eco position while(backward()) { quint64 key = m_currentBoard.getHashValue(); if(m_ecoPositions.contains(key)) { moveToId(currentNode); return m_ecoPositions[key]; } } moveToId(currentNode); return QString(); } bool Game::isEcoPosition() const { quint64 key = m_currentBoard.getHashValue(); return (m_ecoPositions.contains(key)); } void Game::reparentVariation(MoveId variation, MoveId parent) { if(variation != NO_MOVE) { setModified(true); } for(MoveId node = variation; node != NO_MOVE; node = m_moveNodes[node].nextNode) { m_moveNodes[node].parentNode = parent; } } QString Game::specialAnnotation(QString& annotation, QString specialMark) const // [%csl [%cal { QString result = ""; int specialAnnotationStart = annotation.indexOf(specialMark); // If we found a chessbase special annotation if(specialAnnotationStart >= 0) { int specialAnnotationDataStart = specialAnnotationStart + specialMark.length() + 1; //+ 1 for space after specialMark int specialAnnotationEnd = annotation.indexOf(']', specialAnnotationDataStart); if(specialAnnotationEnd > specialAnnotationDataStart) { result = annotation.mid(specialAnnotationDataStart, specialAnnotationEnd - specialAnnotationDataStart); annotation.remove(QRegExp(QString("\\") + specialMark + "[\\]]*\\]")); }; } return result; } chessx-1.0.0/README.developers000644 001750 001750 00000003017 10622575745 016656 0ustar00niklasniklas000000 000000 If you start working with code, please read though the following rules: 1. Use Qt naming scheme. You may have a look at Qt API to learn it. Here are some examples: * classes: BoardView, Filter * classes with acronyms: PgnDatabase * class variables: m_list, m_darkSquareColor * reading class variable: QString title() const * setting class variable: void setTitle(const QString& s) const * checks: isReadOnly() * functions with acronyms: moveToSan(), fromSan() 2. Use Doxygen format to comment your code * start class documentation with Doxygen header /** @ingroup Database The Board class represents a chess position. Pieces are kept directly on the board which is internally represented as simple array[0..63]. You can easily and quickly make and undo moves, although undoing moves requires keeping track of captured pieces. */ @ingroup should contain Database (for non-GUI classes) or GUI Next sentence should have 'The XXX class represents' or '... is' syntax * document each function /** Sets widget color. */ void setColor(const QColor& color); /** @return widget color. */ QColor color() const; * rebuild documentation with 'doxygen Doxyfile' and verify that your class is documented correctly. 3. Format your code with TABs. We advocate using astyle (http://astyle.sourceforge.net) to indent your code. To use astyle, put suffix=none style=linux mode=c force-indent=tab=8 one-line=keep-blocks unpad=paren pad=oper in ~/.astylerc. Then you can indent your code using: astyle ... chessx-1.0.0/src/gui/copydialog.h000644 001750 001750 00000003256 12223260306 017471 0ustar00niklasniklas000000 000000 /*************************************************************************** * CopyDialog - dialog to choose target database when copying games * * copyright : (C) 2007 Michal Rudolf * ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef __COPYDIALOG_H__ #define __COPYDIALOG_H__ #include "ui_copydialog.h" /** @ingroup GUI The CopyDialog class represents a dialog for choosing target database for copied games. */ class CopyDialog : public QDialog { Q_OBJECT public: enum SrcMode {SingleGame, Filter, AllGames}; /** Create ChessX Preferences dialog */ CopyDialog(QWidget* parent = 0, Qt::WindowFlags f = 0); /** Destroy the dialog */ virtual ~CopyDialog(); /** Set current board */ void setDatabases(const QStringList& databases); /** Get target database */ int getDatabase() const; /** Get selected mode. */ int getMode() const; /** Set the preferred mode. */ void setMode(SrcMode mode); private: Ui::CopyDialog ui; }; #endif chessx-1.0.0/src/guess/sqlist.h000644 001750 001750 00000003524 12223260306 017216 0ustar00niklasniklas000000 000000 ////////////////////////////////////////////////////////////////////// // // FILE: sqlist.h // SquareList class // // Part of: Scid (Shane's Chess Information Database) // Version: 3.4 // // Notice: Copyright (c) 2002 Shane Hudson. All rights reserved. // // Author: Shane Hudson (sgh@users.sourceforge.net) // ////////////////////////////////////////////////////////////////////// #ifndef SCID_SQLIST_H #define SCID_SQLIST_H #include "common.h" namespace Guess { const unsigned int MAX_SQUARELIST = 65; // 64 squares plus null square class SquareList { private: unsigned int ListSize; squareT Squares [MAX_SQUARELIST]; public: SquareList() { ListSize = 0; } ~SquareList() {} inline void Init() { ListSize = 0; } inline void Clear() { ListSize = 0; } inline void Add(squareT sq) { Squares[ListSize] = sq; ListSize++; } inline unsigned int Size() { return ListSize; } inline squareT Get(unsigned int index); inline bool Contains(squareT sq); inline void Remove(unsigned int index); }; inline squareT SquareList::Get(unsigned int index) { ASSERT(index < ListSize); return Squares[index]; } inline bool SquareList::Contains(squareT sq) { for(unsigned int i = 0; i < ListSize; i++) { if(Squares[i] == sq) { return true; } } return false; } inline void SquareList::Remove(unsigned int index) { ASSERT(index < ListSize); ListSize--; if(index != ListSize) { Squares[index] = Squares[ListSize]; } } } // End namespace Guess #endif // SCID_SQLIST_H ////////////////////////////////////////////////////////////////////// // EOF: sqlist.h ////////////////////////////////////////////////////////////////////// chessx-1.0.0/src/database/taglist.cpp000644 001750 001750 00000014500 12223260306 020313 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2007 Marius Roets * * (C) 2008-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include #include "taglist.h" #include "common.h" void TagList::createBasicTagMap() { BasicTagMap.clear(); // Choose some sufficiently large value, there should not be more // tags created than this value. for(int i = 0; i < (int)TagLastTag; ++i) { BasicTagMap[(Tag)i] = (Tag)i; } BasicTagMap[TagWhite] = TagPlayerName; BasicTagMap[TagBlack] = TagPlayerName; BasicTagMap[TagWhiteTitle] = TagPlayerTitle; BasicTagMap[TagBlackTitle] = TagPlayerTitle; BasicTagMap[TagWhiteElo] = TagPlayerElo; BasicTagMap[TagBlackElo] = TagPlayerElo; BasicTagMap[TagWhiteUSCF] = TagPlayerUSCF; BasicTagMap[TagBlackUSCF] = TagPlayerUSCF; BasicTagMap[TagWhiteNA] = TagPlayerNA; BasicTagMap[TagBlackNA] = TagPlayerNA; BasicTagMap[TagWhiteType] = TagPlayerType; BasicTagMap[TagBlackType] = TagPlayerType; } TagList::TagList() { createBasicTagMap(); Init(); clear(); Init(); clear(); Init(); } void TagList::Init() { for(int i = 0 ; i < TagLastTag; ++i) { m_tagNameToInt.insert(TagNames[i], i); /* Here is something that could be worked on later. It is * strictly speaking not necessary to create a value list * for every possible tag. However the Black/White -> PlayerName * conversion is much simpler this way. The downside is that * between 12 and ? empty and unused objects are created * per database. Currently this seems like a small price to pay. */ // rico: I do not think this is a big issue. Furthermore it makes // access to the tags a bit easier. m_list.append(NULL); } // I comment these out, because I am not sure how to handle the integers currently. // It just means that everything is handled as strings. /* m_list[TagPlayerElo] = new TagValues; m_list[TagPlayerUSCF] = new TagValues; m_list[TagPlyCount] = new TagValues; */ for(int i = 0; i < TagWhite ; ++i) { if(!m_list.at(i)) { m_list[i] = static_cast(new StringTagValues); } } m_cacheEnabled = false; } TagList::~TagList() { clear(); } void TagList::setCacheEnabled(bool enabled) { m_cacheEnabled = enabled; for(int i = 0; i < m_list.count() ; ++i) { if(m_list[i]) { m_list[i]->setCacheEnabled(m_cacheEnabled); } } } int TagList::add(Tag tag, const QString& value) { // To add a value to a list using Tag, the list needs to exist. // Otherwise the value must be added using a tag name if(tag >= TagLastTag) { return -1; } return m_list[BasicTagMap.value(tag, tag)]->add(value); } int TagList::add(const QString& tagName, const QString& value) { Tag tag; if(!m_tagNameToInt.contains(tagName)) { // Create a new StringTagValues item m_tagNameToInt.insert(tagName, m_list.count()); m_list.append(static_cast(new StringTagValues)); tag = (Tag) m_tagNameToInt[tagName]; m_list[BasicTagMap.value(tag, tag)]->setCacheEnabled(m_cacheEnabled); } else { tag = (Tag) m_tagNameToInt[tagName]; } return m_list[BasicTagMap.value(tag, tag)]->add(value); } QString TagList::tagValue(const QString& tagName, int index) { if(!m_tagNameToInt.contains(tagName)) { // If we don't know the tag name, return a empty string. return QString(); } Tag tag = (Tag)m_tagNameToInt[tagName]; return m_list[BasicTagMap.value(tag, tag)]->value(index); } QString TagList::tagValue(Tag tag, int index) { // Only predefined tags can be returned using Tag // Custom tags must be retrieved using the tag name if(tag >= TagLastTag) { return QString(); } return m_list[BasicTagMap.value(tag, tag)]->value(index); } TagValues* TagList::tagValueList(int index) { Tag tag = (Tag)index; return m_list[BasicTagMap.value(tag, tag)]; } TagValues* TagList::operator[](int index) { Tag tag = (Tag)index; return m_list[BasicTagMap.value(tag, tag)]; } const TagValues* TagList::operator[](int index) const { Tag tag = (Tag)index; return m_list[BasicTagMap.value(tag, tag)]; } int TagList::tagFromString(const QString& tagName) { return m_tagNameToInt.value(tagName); } QString TagList::stringFromTag(Tag tag) { return m_tagNameToInt.key(tag); } int TagList::count() { return m_list.count(); } void TagList::clear() { for(int i = 0; i < m_list.size(); ++i) { if(m_list.at(i)) { delete(m_list.at(i)); m_list[i] = NULL; } } for(int i = TagLastTag; i < m_list.size(); ++i) { m_list.removeLast(); } } void TagList::write(QDataStream& out) { int n = 0; for(int i = 0; i < m_list.size(); ++i) { if(m_list[i]) { ++n; } } out << n; out << count(); for(int i = 0; i < m_list.size(); ++i) { if(m_list[i]) { out << i; m_list[i]->write(out); } } out << m_tagNameToInt; } void TagList::read(QDataStream& in) { int n, listCount; in >> n; in >> listCount; // clear(); // Init(); for(int i = 0; i < listCount ; ++i) { m_list.append(NULL); } for(int i = 0; i < n ; ++i) { int index; in >> index; m_list[index] = static_cast(new StringTagValues); m_list[index]->read(in); } in >> m_tagNameToInt; } void TagList::addTagValues(const Tag& tag, TagValues* tagvalues) { if(m_list[tag]) // tagvaluelist already there { return; } m_list[tag] = tagvalues; } chessx-1.0.0/src/gui/eventlistwidget.cpp000644 001750 001750 00000011446 12223260306 021113 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "eventlistwidget.h" #include "ui_tagdetailwidget.h" #include "database.h" #include "databaseinfo.h" EventListWidget::EventListWidget(QWidget *parent) : QWidget(parent), ui(new Ui::TagDetailWidget) { setObjectName("EventListWidget"); ui->setupUi(this); m_filterModel = new QStringListModel(this); ui->tagList->setModel(m_filterModel); setObjectName("EventListWidget"); connect(ui->filterEdit, SIGNAL(textChanged(const QString&)), SLOT(findEvent(const QString&))); connect(ui->filterDatabase, SIGNAL(clicked()), SLOT(filterSelectedEvent())); connect(ui->renameItem, SIGNAL(clicked()), SLOT(renameSelectedEvent())); connect(ui->tagList, SIGNAL(doubleClicked(const QModelIndex&)), SLOT(filterSelectedEvent())); selectEvent(QString()); QItemSelectionModel* selectionModel = ui->tagList->selectionModel(); connect(selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(selectionChangedSlot())); ui->detailText->setOpenLinks(false); connect(ui->detailText, SIGNAL(anchorClicked(QUrl)), SLOT(slotLinkClicked(QUrl))); slotReconfigure(); } EventListWidget::~EventListWidget() { delete ui; } void EventListWidget::slotReconfigure() { } void EventListWidget::selectionChangedSlot() { const QModelIndexList& selection = ui->tagList->selectionModel()->selectedIndexes(); if(selection.count()) { QString ts = selection[0].data().toString(); eventSelected(ts); } else { eventSelected(QString()); } } void EventListWidget::findEvent(const QString& s) { if(s.isEmpty()) { m_filterModel->setStringList(m_list); } else { QStringList newList = m_list.filter(s, Qt::CaseInsensitive); m_filterModel->setStringList(newList); } } void EventListWidget::eventSelected(const QString& event) { if(!event.isEmpty()) { m_event.setName(event); ui->filterDatabase->setEnabled(true); ui->renameItem->setEnabled(true); QString head = "Event List"; QString text = QString("%1

%2

%3%4%5%6%7") .arg(head) .arg(m_event.name()).arg(m_event.formattedGameCount()) .arg(m_event.formattedRange()) .arg(m_event.formattedRating()) .arg(m_event.formattedScore()) .arg(m_event.listOfPlayers()); ui->detailText->setHtml(text); } else { ui->filterDatabase->setEnabled(false); ui->renameItem->setEnabled(false); ui->detailText->setText(tr("No event chosen.")); } } void EventListWidget::selectEvent(const QString& event) { eventSelected(event); if(!event.isEmpty()) { const QStringList& list = m_filterModel->stringList(); int row = list.indexOf(event); if(row >= 0) { QModelIndex index = m_filterModel->index(row, 0); if(index.isValid()) { ui->tagList->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect); ui->tagList->scrollTo(index); } } } } void EventListWidget::filterSelectedEvent() { const QModelIndexList& selection = ui->tagList->selectionModel()->selectedIndexes(); if(selection.count()) { QString ts = selection[0].data().toString(); emit filterRequest(ts); } } void EventListWidget::renameSelectedEvent() { const QModelIndexList& selection = ui->tagList->selectionModel()->selectedIndexes(); if(selection.count()) { QString ts = selection[0].data().toString(); emit renameRequest(ts); } } void EventListWidget::setDatabase(DatabaseInfo* dbInfo) { Database* db = dbInfo->database(); ui->detailText->setText(tr("No event chosen.")); m_event.setDatabase(db); m_list.clear(); if(db && db->index()) { m_list = db->index()->tagValues(TagNameEvent); } m_list.sort(); m_filterModel->setStringList(m_list); m_filterModel->sort(0); } void EventListWidget::slotLinkClicked(const QUrl& url) { if(url.scheme() == "player") { QString event = ui->tagList->currentIndex().data().toString(); emit filterEventPlayerRequest(url.path(), event); } } chessx-1.0.0/data/images/chessx.icns000644 001750 001750 00000361550 12045216060 020150 0ustar00niklasniklas000000 000000 icnshis32 .ll.»ŋ0æǏz1krmDjlek=0Ħl1wtmmwÏĬƌ .lm.0ezzf1pnusrnljlwuslb3lm{`_zQo3epnLxgwqxU/iy{xryrԛDsmyfpyl՚Drre=3nwq~Wcv3lnURLKScqovytl0exxg1 2aqpb2,{d]]lzcHGOMJDa~^EEFNLPN:52:>d}fHFMSLC_{dZ^jz 2anob2s8mkRyyRvvxxPPxxxxPPxxvvRyyRil32 FMNG)|Ի|)ؿڎ<۬=D޿D ?ഡ ?оڛyԏ,תzmd+}ϤEnì^iJ{1RaN˵spovq|}{xmt?Gҏmt~rvvxrr~xueGA~i}uuorswwusxusukBˍiqwwxqqswwmm{vrgtm`urzllfow|ywn_eUdqwf.tqpwqk{TebZmha?sprr.m|qxj/YDU^.xurp~pwsxk&AZJ0>\.uzsp!vrotrr^Vu̲U1zzqv Kjxvrqvo@k-NrzwzqJPit{qry~f~^erz||oPQpxwvsycy'nlivvwrPKjptsxscw!dlillrmK!xnyrwt{dy"lmpvsrr!q|urug](]mn{~i|uuzzW|1ftvyp.r}qr];cr{}|. utlzmP<7 44#50=gm}lɎiuyvjaabba\dmaaqwjBтj{uvwuvsr{ppscAG׍nzzyppzvp}srbG?ȷuntotwr{pu>Ͷsjntnx̐+ĶǸ~+"JRRJ" $LSSM$ --ęfLFNHFQrĒ@ȜLFGOLVWURWDN@IlCNXKNPYRKLWSO=oICYBWPOHJLPQNLSPNOD\CjAMPQRJILPQGGSNKBNDp8OLSED?IPSQPIFO0NMJPK^r9B@:HC|V&NKLK/EVKQDJ23SRNNGcJQMQD5TF')|QOSNIp#PMJNLMMNq˺zKUSMPZ"MBSPLKPK"` 4LRRUJMSBPVLMSXAżq @BLRWXGRSIRRPNSY?¹kJGDOOQIRMCKONRMZ?ľiAGDFFKDM#RISLQOV@iHGKOMKJ#jKWPNP\A¼P?HHU]WmCWOPTVA    0ed0 kk  sۻs  DɬC i笠hyy!yy j j ' FǢF %ࢢ) tcq^ct '"ʡhssp^uIk"+l򢬯xrcwjrl[u>Kl+ ךrDYOp7C +0跟pBKKD$+h^7C0-j򤧧m_r~tms|Z8Ci騧xO-BĀ3Eܤnr<'0e؞w` FfܸУ|]'vٸϩ|]0ٸբ|]+tҸ|\*w߸+z\.z-iy['{j+0굧>4N0+ ڟfzAl۸ +ldu8Qk'"ɟm16-B# tmQ9/00/..).;22ct %تpekgigbddi|yom' EŞF % kj !yyyʟyh߬h DϩD  r߹r  kk 0ed/    0gg0 mվm  u캈pljruogjjyu  Dwinwuo~~|wqpC  htc}uwwmp}zyzu}wkih {syo{quxs}txplz~rvtqj{!{d{tzvpptq{}{vupz{{wxu|m{% jkp|xqyqppsrstuvvpvysqrpowoj ' EiwkrzsxrkrqpwvyskjxwyvnhlvylE %flzoq}ryvtops|ywuphuwumrehrtxk) uwpmuoyyorxoksstvutuzWO[KFblusttrv '"ԦivntqzvLa_[Eamqwkmt}T;G`rorwa"+nlxxkuq}mpo>QV\XFTqT42^}pnvr}n+ brtnnvo*A2jM/,]zzmszvº +1i{zqwnnyn )@B?BB.+Zs{vtsx1-lnprnrup{od]nskfkqzQ/,`|{qrrx}k+qqwooxnrvR8>Ҽ,/[~{ssw}wێkq}vovprur`IjҺ6 "F`x~wuzylȻdlu|osso|wsdjW0FWgrtx}{unkqsotso~{tgmSSghjvt}qprwxztvtt{~vjoSVqnel~wzytvhxttvvwpyuhlRLiofgohptqrfqjwrmorvklQMhmglonlrrk+jqlxvoqv{tkkPQjlitumsrmgՏ-kx|n~vouny{vjjƿPTrrhr~tyxsl+1qv{yswpwyooʓ6*6ailoy~1+ fy}wvxr{oTXk1H]mqxuy}k +nqp|spwr}tOx~{~h,9`rxwuv}tm'"֣gtovrfa*/$+[ko}~u" vn{onmxI<*"$"#!",%!Dajl{}pv %ɼs{lsnzye`KAHEGG@CBEUSNITmpptuj' Eexwn{grngqmonomgdstjdeqtwwmF % j|synqxvozwouwpswxonptinqj !|rp|qyzmsrmyuujwrjqqpg{{atz~qqrr}zj}zptxpd{ hxjx~{rqpx|vm~vjvh  Drowqssz||tvx}vpD  tklakjrpkmzu  mռm 0gg0   0ih0  nħo  whIBAILG?ABRrv  DP>FPOJXXYUZPZVGKD  hM<[UNPPILVTSSN\]WREDh }{IQIYSINPNWYOQHGUVLQPLB}!|a=ZSNTOJILJVWTPMJSTTRQOWEb|% jcCLVRLUKIKKJMMOQOIPTNLMIIREej ' F@QFLSLQLEJJIONSNDDRQRPHCFOSDF %ʳ>GSIKTLSPNHILVQPOICNONGK?CLLRC) wSKGOJRSIJPGELLNONOOR9AJ>1AHNMMOPw '"ՋCSINLSQ9SPN5?HINDFMT<ϼ0,?LJLQ;"+pGSRFOKVEkl$7GKH55K;ͻ,?VIJPKVo+ ;[YMOHXHok1H5ɸ(?SSHNTN +2hCUULPIXFql9<: (,Ŵ';LSQNMQq1-nJLMJLOJUH^Ziwjc_chnHƵ(BVSKMKSYm+JMRKKRIMQ9';%HQWJMOJUSO?_N /9EKMRWVQHFLN^KPOIWUOAa¾J ;ECEOWNW^LJLQQTNPOOVYQFcÿI;LGAGUPTRNMBQNQOPRJS[OB`H 3DIBBIBJNLH@LFRLKZJL[PE`¾F 3CHCFIHEKLA+DLHSPJYKPWNF_ÿE5EGDNNGMJG>đ-mSVIYPJPITWOE]E 9MLDLXOYRRLn+1hKQVTNSLQ]SIa."%@EGIQ[`cVo1+ ?UWQQSNT`K2LIJ]&/=GMROUXD +oLMWMJQLWNAso|xvsqmo[qr#'@MRQOQVMo'!։@aNJPK^DX$(tv wvwvwwvu> =n o= z= GruttuuvrG =zz=Gq||qGyHv uHy>7x<HuuHо>vEj#vɭv$jGBH ǩ HBKdB޻BdIj'ϸ'jKl((lKʮM44/K淣"KUl<㲤<lWi'㸩'iYe&ද'e[A泧A[F  FjEŬ,Djr% խ %r_=߸=akw뼰wj1BƮ.B6D߯(Deu>òt99@;:412+F>ue=ͰL%etijimp;o=gu=籪}JS#]vz=u#;Ȧ_$-20/-,-@ /zPY"Mio{~;!=B鰤>>CoeOR=\bnuB=!v|̥HmC,U}icid`[Z\YS`NR0MYlw|v!HIeA&Dkw` 6H@A@??F4YLR%BUk{Hkww׫Gc"5ZkO50C{~IR!=Qhxww3;󽦢Hc 'J_vJI4B6fq}EQ!UjT&)3*$!-KYfrJQ:New;-F謩Jb#4A?9) 1)5@H^k/Q:PeuF$={ؤKpF-(),574/,)&%%&&$%())0-Q =Oe{=1vsɢCKi€Á3óKN!>Nfsv/n}񽦮Y-2,+)'$':I%iK!=Mc{ }n1u]PE;0".8\W=Pcz1F߮~qf^J_1S2z$BShF={ժ ~vrp^&Q0v",())+,4M]q{=.vrѯu1R6؟( .GYk|rv2t vΰ;R0^#,3Wituw/vtKR$W %7Ge}uv,wtMR3V )BTquwwtMR1V *D[tuw-wtMQ@U *B[rzvw3wtﺩNQ1U )AYpzuw9wtLP4U (@Um}tw=wvǭKP/U (?Retuw8t vͬMP4V (?Pcsv t8vsձOP5U '?Sisv#={ݸNP2U 'AWn{= F缭#MP߀,U '?WpF,𿫦LP=U '?Xkz,n}īLO0T &BYi{|n2wsϭKO܀T 'DYk svo=|೨LOZ ,FZq{=0FMOހ-M(;JfwF+<󾣡OO8ςP 0`|<2vwѨPO7"#UQOXBGvwvH沧MN܁.&&9juH5;ªQZ23)0Zm;,wwڲ~20ï3/$#Nf|ww'Hォ= 13/$"36322321.05#(/#D[rH+v|Ω'`0x2"X͑*!6HauB=g;ͩ5A$%0C]r;u=篦'c8. öɡ3G_r=u$=Υ8/.)&$"! ! ,# /&'$#& 'AUl{=%u>𳝮ne_PA0&' %'&%&$$&&$$%**4;<5/-..&)CVev>u6DעyhTKMKMNMMLIMLIKJKLKHHJ)IINSX]\ZYOFLXcnzD Bpa[<_`__]Z^_]^\XZ[YXX[]\Zfmlpnjic^dghtB%jw筮upstw upsxyvmiprmp)rpn{|wxwt~wk$=ڴ7~~=_r% ի %r(jDĤ1Dj[F 𷜢 F[A篠AYf'ᬥ'fWi'஥'iUl<߱<lUKĶKM4Ͳ4KӱKl(۵(lIj'ò'jKdB޿BdGBH ϶ HBEj#w˸v#jCv>Ӹ>v? h4ý4h =CH 3Խ3 HC9w@ AA @w7x<HuuHyHu uHy>z=Gq}|qGtv wvwvwwvu>>tv wvwvwwvu> =n o= z= Gqt uqG =zz=Gp{|oGyHt uHy>7x<HtӿtHٱtnskrzttutxtrx}|w{kn{siuzuqqu>vEj#vڧ{x~tsxqtzvuvxwplt}}zuu}tvzz~uksv#jGBH wpmv{swoqzxuttrjhp}yw~|r{xptxu HBKdAǎmhuuz}txpntwvssrkglvzqr~|}v|zkx|suyutsBdIj'᫄xrots|~w{xssyvuyzskgmrrvyqy}uytmw~{yyxuuokp'jKl(œ~shlpyvvwrv|ut{{wpjpx|~|nos}tpnq|qju}vsrplcn(l{{ythkqytuuotzuvyu+pz~riuty~ojkp|x{xkhr{ulmukety5ksvvxrprxuxvopw0xvvts}{qp{vtwtoiiszwyvmttzylkurv{yyz5UK׊imsy{|smmvttwkkttuvwuss||u{zursrico{{z}vr|sv~tqwv~}rqusKl<тhqppuwwmmu~nqzlfrsr y}xy~yqrq!js|xxyvsq|ysnz~vtxzq<lWi'шpprmoss~{ttwwjs~rgqtusqrpsz}~}|~zvrpxxtvtw||xvzysp{|xmkw{|y|rl'iYe&Άxvrpjoyxzxus{ujqzqkqqvtpsptyppy~}rnty}yqptux}}yrx}vorutstpnvvyznu|&e[Aׄqwprrgl~xxtuqkxuinwnirpsvqpouzpjrzumt}yv{xlisql{rlvuxolquyvmjqprtpy}tA[G rsrnqrfj|sxutnfwvinwnitqsyonruxvpqxsr||omqrljwvnzqmuqnmpqpqmjltrnuzxwwo G]jDu{vrtuqgk}zt{{yrhwumnrjhppuwkkustytwztv|womklljv|{|}tqyulrtmljdeirsnxupvwvDjr% xtysrxwneftIy|}wmuxplqlepuwsjlssvxrvxuwwstphjigpx{ytsyytyumnlhjlmns~rlw}z %rR=ʆvqpkqxuoihpnr|}wsns}niusgpwwphqvsxzvux}tpsqlogblrxvpu~~ysuwnghmojlpu|zsry =Mjwzunggw|xslotnt}qqpr~ljzvfmuwmftvqx~wu}ttuvqogbmx}wv|tu|lkyqfaefbkqnsxyqsw~wjcB{zqibl}|zrhoypv|qsqq~mnyekrsnlxtnyuqxwtwwusnihnuyvq}mm{wof``akolrtpsxqs{tiBcD~xvoidovvxohs{sy}tsmkrq{ilppor|xnywqswsoxxnrrprpmfctujphU]edkndaimnrzzsswvttvsuDeu>}vorqhinv|qkr{z{vusohi}wo}zggnsqryvowzrqpvwntyrqszxnlK&)/+)$!#/]h\dpqtzxuuttwurt}w>uQ=|~qmvtmknvyqjn|}{sostpuu~{jlsqnquqlnqwxpuxqmuzuv}xvs5#_mbccgg7JYUglnxvqopwyprzsm=gu<ڃuujqxtqootvslo|}{ztk`Z_fe_W]YOT^dgmqojimz~vqrslkwz}|u}z4L~=MRb]_mqmnsojrztqrkj<ug;swtmwzrnqoozwnox{|u?&*('&%&&%Qffijkpxyoptpkpy{spzz9Q3GLSQ[muikwqkmuxrjfpv;!=Bnxurzymfppnzxomt}l)?DpBa]bfky}rnpmkmhfjjn|}9K}(?CIJ_{~omqotvpwzj^qzB=!v|omvwx~vidptqyxqmsn0lC&6TV^YEDJEB=<>;7AT[bik|9Kۀ!5=IMc~xrnmtwq|qft|v0Hjkuv{{lfsvpuvrntr0e!*GR]?4B:399@1;[]bcqw6K/LW^_qy{qxskz|yxzuurvqt uzrpsrlo{nw|rjqxtomoqutpv|qed_ep_'OV%*4=EOZ`bruoz|rxvnz~vs}xpyu tqwuxspmqmi~}qwyuljv|unqmovt}pnqhnyh,NQ+01>LOS^`gsihwvoryzu~yspywnxuwqwtvqmjkhhw|{}{tkgs}ytqjo|zstzqt|l/NO$5<>IVXY^`loluxolw|zyuju}twtw wtuplnkMnz~njkqywrlju{vw{qt}n/NO(NW`tzuqpnkeizzs|{urxwxw|{=+Fnu}tiv{t|vlqogqxtonu{|zrq}z4I׀<ϽE(2GQWpuomolnmmz~|w~}|zF1;kls{kuzwylvyuxzrnqv~}{qk{5Hр8ʷrF !?Pcihilotnoxuy|}y;1vwsko|{pu|y{|nz{{ypltuyxwuly6HЀ8ÿԤJGDL:.NV\dbbmrhkuqty~{|wvHׁqkpyxzzyz~zqvywpnyxy|xtlwy4HӀɀ0՗!wȼ͟$GMX]X_mgamvstxvw~|}}yrHk;tlpwuy{~|srrpv{urnr|x|rs}7Rҕ,ܭ"dxvinsmkoojrvvs[FCD:.<#''$,;EQ\`dljknmw~v{}|xl>ucDnnufnunknnjsxwsk^[aXI714146442056343453004422147;@@??6-3;==;;<>@=:ELIMLIIEAFECM[gmrqnhes{|ympyo{Bajw{|vjkuxrsqmsyzuwvi[\fe\OHKLPOQSPINTUSIDKLIJJKMHES_^[VX[WRSMHPelipwywtvuplmt}vmwj_=Ņ{wttgevtmnpx|ywyqf`akng[RU\_^_c]V^cc_WSZ^Z\]XSPS]fljcjnb]_ZTWioirtqw{uplkswvr|=_r% vpruij|tjkq~{~ujbetwrkbcjmnomhfmrnomjlnkgii`[cilrxvuqhdeebafkryrkv{ppzvvzuv %r]jDmorqyunln{~ypgiw}}ulosrw{xrqvyssy{||ukpvminryywyqkmhcltmemx|rlz{qw|vywDj[G gmp|zqonnzwtplu}}ukouuy|xutuslkz|suqnsvsuxutnlmjhmsmlutsnjlqurvt G[Aفgozyqolovtqnzytklrt|}tsvrifnxywjkvvppwzvvuonlppirunmif]cunpAYf&zlxwqhk~vtsqx~xsnnmmz|rqtrijvvpttkmqknx{y}~ytmkstlqttsljdfyxw}&fWi'{ozrhi~{truttz~xorlixxrpqrnox~upquvshdr{{xyskjoqjqvstlknnyy'iUl<ͅ~|sij~sltwv|}qrmjxwpoqrnrw}}xszwcfvuvzxlgklklvsimlptpu{<lUKٙ}yuml}tnpty|uvliuuqprpnvz{trahzvp{zujepqlwzpihpxypoK5xtol~|zxtoy|{yjits,qpt{~|yq_i|{xzpskkxwrxuusep}uq4Kyjl|}~{|yo|yz}wjlvqstlqxz~~v~tajz{yqvsuzxyqo|{imwzKl(Ájyzyvt||q~sqyxmoxqppkryy~|}qobmy~{tw{ln~jk(lIj'ޟ~wvno}|o~vqzyknwqnpns~~|{|yug_r}~~ywowzopyt'jKdAȓurqs{ym{{u}xhkwqmtvxyx}vyyady}x{v|sny{qp~AdGBH 籅srzyny}u{ylkwtkoz|qxvxuckzyvzw|so|zn HBEj#vܪ|umwsuwnlxuijwwrz}rwqmpv{zxvpi|v#jCv>ߴqtyqpsoqzuljrwosyu~nz|ntyy{|ws>v? h4⺜zkimru{xmgpxruxs{|w|{su}|xx|4h =CG 3ݷyssrvxngq}{wutxyz~}qmvx~3 GC9w@ Aڽ{oqywoiloouuqwurA @w7x<HttHyHt tHy>z=Go{|oGtv wvwvwwvu>>tv wvwvwwvu> =n o= z= Gptts ttpG =zz=Go{{nGyHs tHy>7x<HsƮxvuqty{sHМoNGLEMSMLNOPMKQWZ[ZVPXSDHUWLCNSP\_]WJIPd>v/j#vА\RTLLPINSNMPRQIGNW\YXVQWWLOZ[ULNSTZ[YVNFNev#jGBI VIGP]RINGJSQNMMLDDNXZRQXYXYVXZYYSIT^\\YX]ZQLPQPe IBKdAoHAOOTaTKQIGMPOLLKDCISULLZ_WTXXRV]REQ^`^ZY\[UOQUONMfAdIj'ؑ]QKIOOWcYPTQLMRPMQRLECJNLO[`SKSVORXNHQ\a]Z]\VRSURPPIEM'jKl(rXWXMBHLTc]ONOLNTONSSQLELSUU]WJJMWXMIHKV]ZXYZXLEPXQPNKH>Gn(lKW__SROCEKQd^KKMILQOQQNOOJT\VW]MEQNQXIDEJW[RSYVRFDNUOIJPG@NR`M5݀ELb\MNRKIKPa\MNOIJPOPPNOOMW\TZ[JKWOLPLHDDOVRRXVOHOQTRGGPNQVTTU5/KlBFMZXRSUMFGOa\MLOEENLKNQMMNU^[ZVMS[UNK"D>IUUSVXPLVNOVMKRQXWMNOKuKUlGMRQINWVRMNOHBBGHEIKNURJIRUT\`=jwpSOICBPVSMEIOIMXUKEL[WEDTQ@DLNHAMPLSYZPMVVONNMGGA>IRVNMUNOUGDQLBGLKKGIORLO^P^vjcBVWKC=FUTTOCISJOZTKNLKZWFH[R@EJLHEOOJT[ZPJOQORQOLIDCIOQMY\KU[HHTQJA;;>GIGKMILPKNVPDB9DYTSIC>IONQKDLTMRZVOOHFZ\KK[TDGJJIJRPISYQKKOMJSSJMMJ&GB@QSHNG7>FCIJA=EHHMRQMLONLMQPRDeu>zVSMLICCHOTKDKSRSPPOLCDX\QJUSBBIMJJPNGOTMJHNQIOSLKLRQGF1"=FuQ=VXNKPNIEIPRLDGUVTMJNOHM\_YNWUDFMLGKNJEGKQOHNRJGPTMNWROO$!Zf[\[^_40:8FIIROKIJPRKOYQI=uBBGLKGDGSUPLKLFFQRUVOUU$Gt'17C==HLIJOJDKRMLOHFe<ug;KRQJSUNHKHHTSJIQTU[Q* $#"! ! 4BDFGFKRYZQGJNKEIORLJTU(L{ /373:HPDGQLFFNPKEBLR;i=B]GRPMVUH@JKHSRIGNUXYHAn*A>@BES\\WMHMJHHC?CDHVY'Fӿs*,/.>TUHFKJOPJPRC:LUiB=!v|IGQRSYQC>JNKRPKGMXYWI kC!"89>9,,2-*'&)&#+79=EHW\(F¿t#(01BXXQKIHORLVXJ?N^\|vHfDFOQU]TGANQJOOKHMYN!d08?)0=524:-'==ABLS&Et(26CQUUNJGHGKVQNNP_[iHkwwPFJTPQ]\L@NSGMOIIOZXXMb)2=!0þӬ):9>>AF!EҾt&05CPUWNJLG>DPKQTPY]\wwk;wGGJYUV_^NCRVGJQIGOZ[XM!b!+8>604:?DBEѾs#-2BQSUPPRKBDNRUQMXbZ;iHYJICTZ\_ZQIRYKHOJFMZ][N"b )48/).38HK!Dмr"-4?LOPUZVKILQRSPKWi_gHmvwMMJAMWZ^YPFKVPHMJDM]]WK!a '0"'+-1GS$Dϼr!,5@KLLT\XMPSQONPOTc`Xwvm;vMSIBPTRVVQGFTTJOLFN^\RI"b *1%# &+.0FT&Dλq ",2=IKKRSNRXQLMIISTVYK|;6GYLUHDTSMMPSKCQWJNPKLWZTM$a1 )5D͹q $-1>HJOXQFOTLKLGHTTOUQjF$={MGOJFPSPIJNJEPVFIRKKWZXR$n&!!#')'$#! /#! D˸o %.;JLOW[VKFNNLOLLPOQYZf{=2vqILQOGFNUHEKLLMTLILIN[VSQ MýdӶ6@A˷o$-?NOX_WVODNQJKNKNMS_\[rvon|vLVXQGAHVIAHNQLOMJKHJVPMR,%(%%#"!%7CX?ȵm#+7DKY_SRPFPVMIKKRTW`^W|nmgS]XPFFQZMDHINTRLKKFHSNKRJ6&  *ÿ̻NHy&,6=BV_TQOFPYOJQQUYX\\Xt7G[S\SHEO][NKKFCRZSKHHLPNLOTO@;950" Wπ2ĿξE*b  '/;K\[UZVFQ]MHYWTSKQRRk{=qvqUNOSHCQ^VIRZKAOTKHNKINMLOVO?=:?F7L! "+4:>>LWQS\YLQXMFU[VRRWRPdqvqt tVNKMKEI]XJRUKEKQNJHILOMJPWPDD@EN@L¿N $).6<@ANNHRZVMRYPIUYRMWVMT_t tqwuTOKHLGDYYMQSNGEOUQIJIJOMV\NKMEKSDKǺI ! (357>@HOBAPOILT\UPYTOKTSJS[twqwtQMIGGDESWVWUNFBMXVQLDJWSZ`POTKNUFJƷG $)*1:;;=>JIEMQIGQWZUU`ZOFPXPSZtw\wsvOKHJGGHKV]_ZJEEKUSOJDNZUZ^QRTKMVII¿ŶF *46<=:=?CMJQ[TRRQUYegR>R]UV\swqvsqONQTPNFI[^_[LHJMTOIFFNVSVYQRPCHXNIĵE2@?BB?AAGLKNUUZYMLLV]ciQ:O]UR\tvqwsmKS[VPNAJ^YVXQJLQWVOJEIVSRZTMODDWS!I´E&8FDHMMJBDEFJMTZYOGFV^^`QALVPM[twqwskHV^RNJAQZRSUPHIRTSRMGLZSQ]XPUJEWU"HF +9>CPPIHEB?DIOSSWUMKVZXURKJUUS]}swqwsmJTYVSJKYWRVROJHSQJPOIP\SR[^XVLJ\W"HE+64?TMABEA?ADNSTXRPUTQPPQJIY]_]xtwqwstKRWXWMNUTSQNUPJVSHQTJNYTSY^YRIIZY#HD)55?OJFHBAFA?HTXOENVOORROFLX\aYvswws}PfUUNJMPQJMXPGTVJQUKKTTV[[SPHCVV GD$16?GELMCFI?>EMK>>HIJNRRHDNPTYNvswqwuQKHQPLHJRRLNUPEQXPRQGCJSU[\RPKCTRG¿D#*/>DJQPAANOTQAzuwqt tRHGOLJGEQYQNQPGMXUVTG>DQSWaYNKFQR!FC!).;DGHGFC<9EIFIJGA>ENQNLFLVVODt tqvqXJKQOLH@HWTQPLAEX[WXRFDOUZ_WLJJTW$FB"+8?AFJF?@DGFFLHDNIAIMIKVOHNQRTqvq={aQMMOLH@EOPTVM?AT_XSWNBKW\YQMMNYZ$FB&.9?DEHMGBHLJGHGKPKIGDEGLMHEKS^{=mGlSMIGGIDGNLQYODFM[YOSN=HY]TNOLLZX#EB'138EFBJOIADNMHNOHGMGEJF@?GHJP`GmsPIMMEHJLPOVYKDKOWXQSL?K^]RRPGIWU!EB(/2;HJB=JO=M]ZRUNHMIDNRJDDN]`SMONOXU"DF )5;>NSMJJIG?BS\]UMWXWZUNLSRQPW{=kFjJQXZODP\UOWQGLIDMTNIINY^XVTLLWT!D<!168MPIGIHJFGSVXUQ\_]][XUYXURfFm;{GGM[UGQ[TQ\UHPSQTUNJMPW_\XUKFUY"Cc< +4CGEEGJOHHQNQTX`c`^aca]^ZP};mvwPGJVTJSYTT^UKUXVVSLHPOSb`SQNFS[$B?<:A1 48;B@>IMADNKMRW^_Z^hhe^[VVwviH`LHKSQWVTSVSMQSTSSMISRRbeWSPHSV"Bf.3;>8=HB=HPMORPTZWX`__WSMbHk;PHKRPUWXUNMNLPUROJMZUP^f_VLMZY%K'y&2?62CNEEPTSUTIIWWSOPTJQOz;kww]QPOKX[WYPLOKPXRLFN_TM[aXH55B<)#j #1>94DNPRQPTXSLIMPQLPLATcww-HpPMILZYUTRPLFMZRIDL[SLW\I"$!,.+,++**)('&-(k#k !-9??IMQURNNSQUMDKRUYJCPwH*v|PLEGSUWNLOEBNYRIFLZWLS\DY}z/vcYʔ$i '3=>EGMUSSOHNWQNRV^_QLU|vi=BdKEEPW^SMPE>NYRLJP\YSTVAɤ/Bmk"/57?BFKIQTMVZTXY^e]WWiB=g;KIIR\aZQNJALZTGEN\[[VP@ǭ1 *2g?Ugda`QEJOHFIIDK\[QRO<,,.'8 (/9??>FHGHGP]UNVWVZRDf>ucDLK^_``NBJQKFHIEL]^SSOG<;C>2&!$ #%"#"$%##"#$#! ##!! "%(--*+%").49BGIFA=>HQXXIJXXPKWDQBEZa`^OAIPNHLJENYXSVTF45C?4+('%*+*+*&*.,-*&())''*+(%.415501-+0/+3>GLMJHBAPUKL[SHSBajv`Xa[VNCGQTNMJELSROSSH:4/014458603:<:/)1402114.+8BA>9:=:883,4FKGLQRPMQQJHKQWOGswj_=cVROLABQ\PFHJQURQVND??JLE;47=?>>A?9?DE@75@:525AOSNG@@FGIIHFCINKJHGJKGDGG=8?DHNRPOMDBCC?>AEJQMIRUHHTOPUOO %r]jDGJNLT_[QIFFS`[UYTLBDQVUNGGKKMQOKKPRMMRSUXREJOFBFKRSQSJFHCAIOI@EOTMHUUIOYUQTQCj[GpAGJW`ULJHHS_]ZYQNKHQUTODFLNNQPNOOMGDRYZ_YNOJGLPMNPONGFGEDIOJHONKGEGLOKNXXNsG[AaAJT[SLJGHX][_\PMMJUXRNEEKNSUMLOKCAHZc_[TSRDEPQJIPSOONHIIKKFNOIEBC:@QGI[VhAYf&YEQZYSMDEX]Y]ZPNMKSWQNIGHHSTKHLKCDP^b[QKONEFKFGPTRUXSLHHPPHKNNLFF@CTQPUe&fWh&YG\_UOEDZc\YWPLPMMTVSJKGDQOHHKLHIPX^YPLMNNKC?KTTRZZRJEGMNFLQOOIGHHSWOd&hUl֝eLLYSKLMHIRNFCININTOWc[IRTHORPSYTP\ab\P_>v? h4۩kUECHKNURHBIPLPSNT\XPSUNPVTR[YPTbo4h =CG 2ҢuXPNKORH@JUUROPRS\ZSWVKHOQXai2 GC9w@ AѮveaVGIPNGBGIIOPJRXPPg~A @w7x<Hsůvhbdcekr|sHyHs tHy>z=Gn{{oGtv wvwvvwvu>t8mk@"$&&$" 8YwǸwY8 !H{Ψ{H! #XΛX# HђH``hh__BB~~AA mm ""11999911## nnBB~~BB__hh``HH $$XX!!HHzz!!88YYww""$$&&&&$$""wwYY88!!zzHH!!XX$$ HH``hh__BB~~BBnn ##11999911"" mm AA~~BB__hh``HђH #XΛX# !H{Ψ{H! 8YwǸwY8 "$&&$"ic08 jP ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cOQ2d#Creator: JasPer Version 1.900.1R \@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP ߂8ҥyf4p Ddk~NshKvlncPQSBj#A@;0^yR9>X]F 51ޠ6Am?~ $1fEթD+Eyt?Erť]`BU]z(q&\&W]Ax+բ%>Q2=T xstXm k Ԩ|/erL{pһ5Q8KW~L) ;(cMMޛp>hMt@6j~A$LJHR:S"*۫ 6")u W뼷 9abܶ$ĊAa@YAK-s{)n\QYos,|,dT:d.w?,1'K[]3Kl^P:>""ǣw0;Ԯ&zMŴv^[$–oߙp_ l{*I,"0^8dg m (J7SSz RUl{i \s]-Q4H-j?r5W*|>8mO;"%ePgS{aѥ+jPy7A/2`6&MYJ*şu?;(k?rs \m_-q?=W񭸎ܹ!Mvڪp.3r:{}M#0RvF #7!@OYЗ 8R\wwȏE"vno2&h`7vijPc iO/mWYnŒ+lVI^qŎ7u_RA[lktteuOOQU =2{-֓W}2N|0;~8)h h7xh1ȤҭK( tJb G)RdoǚOWK& ~9Bb9dv $:F?!HUkk4KՋ4_5=hH:Uَ;|/G\Z{|2ez1$Q6rTǬk2<mC }nHYHֳNhuҭ=;ch>>;I>c3o]-?!]2v^R4_>S*,p#  CZ =_LSTBO@{qdzF93v*v`0{qj`Xŋ}xfV!w0A!Ɵu?;,kROA򵫩_@`ƳgȾ"ocG @σ|ÆiЧ]#l$&K N1xjcu{ܭ<5ltzsˑ-L?ZrwNM_~%`fkvG(yR{]^qBJ?\67+ѻxHTj͆s+%-$[*;RLԢᩑ-D#o E;kI^o0ZKg2*%3di_=H ^33JX2O︽(Ve=0I* Tn]% aFH~]`]`.ݟ+%`?ĉvM09 Ԫ>sP"̥w[ ĴԔFOl.Lc $Q(?Ǐ xz2JEl2ð絃:[!ZCa/3kj4H:KKXHE@2HX<FEZvH巳JFk,5 `OLJ䍪(2@~x? =CtJ:{ͤ LU+97m"-`(j/(Z $_e8N?Un;5PF]B+]VF?eoEUf^<^mkeNxC>5N"FҖ> ;#xYCk6ƹmRĞj~\qI6RpLh//qׄUQf6.N~`P 2Yhw8=8/%'_~rj,jq]M53d2&P >ɓՠP/mD9W6sYA5c)b@VӦ|^uhtHV=CljH BI4;/8''<6BP3'6/rI$Ԍh?Edyf 4S)ޭc}%'?*QLx08P" ѯ4Uv:t Q.5K50 aw$_$,4-ZD0^,Kt!%M+oce뗟<6SH96ƃF~>PCɓ"ZjE}һb^p8b:Sæ)tJn5anS?0^$k<ub=½P?#`X,0@׬:! ZX۫-Lڑ72H_z z}^$U\1$/ȇ/|טl2R%vдU߅AF?sz"#UtȼY9<TGh'ۤʹ ӐTb) acTÖ,9B0AK j}C1PBll׉y4ԫm#9<eΟ!BdMa/B w-ko&i0e*ѱ~v7F~`87Xuԅ&8`$#<ٗ1>'UɪEx7L N&{J"w|11]NڐOkws (pxb>Y֨ z^ӭ~1}(\)JB:"zNG|7<#S/E44C]r@z홳 Bm|jct * 鹃e?A-n;$Qq~!֔d"OnD7%|B襂o}Pæ9t?>no# ߏ27ɉq+\Jhү ]vO0bg6݊:B+Ɵ!I * qMu[fm(${UCX:d9W0RE76Ug&jתYպ3HÞ F+ZOs>&%tds4v~.+?r?|85=7}U\~+uKj.{P<%Гe9AB&w|68'ǠocyF>N}Kd@O$h|`S~\gFҒ08䮿(B6X1|:9U!8uxW7Ah~#F?_]>t :x ^5ŵC!6/Q(Όd zp>faxg_qրQzhX?l blvr;"Xۑl_Q*,e39q4w$Π"Dxyb'ޑ Q~;F8:-::E3r MͿ.fMm/= -GG*! 9hyU0 u-4kRfI•1sģY<*2O *}L8(""MYoOFO/3(5txqtqM.nϰ M_]*;Y?{q_f(DybNZȸg!.vWnt3qbBxT//~ϛ::씴*^uW%$Im5"|F?&[oۛhIW|]Wy(an?WA]HocN"Bi Չk,c3H æ[~}1 =yhb 'skjTpQTJdgQԂ,V>^Cp"`DSR%0v@]Ԟ6DΣC8z?KerC uf{^D4VY?V5NR|WUDSݱiV b*~C~>ώ)G#BP ] AhzC2ޅ]Lz4+ucd)_"!/3qxvi5U)b#cN[ˀȵGӹ}# -{UVWce6EYLtH*!RbeM^:jSA*(quiS٨ J'F' [ wx:Q2%~aQ+W̞cCI/]MT&z"~Myzpq}<]hT~e$?j1, [zW\YSYL}gKl:@${䧴ҜCzjHn6Ar |-jXZ7 ѪK%ra 6qϯf@`XJtJp7~x5X77YUY`/{B=7ӤGjp&F FZ 0Y ? n)BL;?#+` um_Ҋ-L6WdC(Lb&z̸f]@K4KRZ }$7?x?X7)RE0h:o).UZ}[~V](&k@Yxf7u$`F 5Nte摐̥Z+.Ʋ;Mƈ-}*:-{{VHkeXBdPQdRDz A$tĮ>וRbx\e=~"|.[З0ec . {`AT,ؔRNEU?4N0"q{0iQo6Pz V&̤ᤓ|X,R*퐼WͤbD8a$?/eūآ.e)6e~{H νnZp}ynX7,rqp2Zw≑-rl^zv77q*%̠DFC3@p'u)ܾ+,ݏm9=)F5|J=m@2FQ-Y\M*rg^ou~V4-Ps֧Y•(.K3LQwW5%s`wW^7^vYy٥t1bꪄ=gEWXt8y1gm| 6u]LaUq~"WMvFB쐑 X#늙DQ/1~SB m xƹ{&SP4ڏ^mn\sFLB}=/eb\o+)fv_Q[D/ք2\Y7\|S" 5yyPZH.aI+_JFtZgh6V/֒bj1a(~~*gXTh^b`0㭣(U\mwϴ[о([q5w>/2{ZUdGQA{x.OSjLn0'C\dβٵ~>8 ,R<~~_zcg{E\O7SYrs.Q~yOw ,p|2֩}Æїzʢn1˔rGg/v==K,fA;c݀ iEךt 韅AWt;緵WnukA'n ѳ:2zU,n0}5 {\Kj,R$FR-Ѽ̙-U59ߍ1V|-d{:.^M7%@WAI@v굁&Uب^vpuJjS(J9٤jE+h̥XEF@ f>N:׎,]A޽!S&<=ŲN )vWY6y2Dq{K -qۈx=_xx) GAFV9g[zۯ٭`IKT$%l _W9v"\C9\tʼ҉!4avٶn)ER[P[zE9$3bE<6u!QbU񮨂 2{E)w1Nx8ppH 5Qf,DU~^qA~:,vnΫ~RjȐVBUAu홃5[*?TJ,zaɋ0 Ɠx'NzZ㒖ȡ]ꙍ)A#c3FGvѹ28C5W9fY*5|i?J 8!Xx\ciw`Z܀ DMB{giHe⧘~5ߟKEszA\ ɣONʈ].d'_@n^)Ӕ^f DZctϟ64! B.W$ǫy{cZF3iIwvV^jąw/$;z/ alگ>,. }zxjvlt5=Tq c4 H5х%5@3m)U[Gt64ʕl9OXa/dorP"R&dl#C4ipU:U0ҫ ^1ZcKur\UoßB/C4Kk֛N$AkR'(^*ޞ/iesLFFmuFאj˺>Trv!mJc.D`zߒw< 8o`M id%r^C{Rw^`Vo`8`&`mLjY 3)_'DJ{ɶVXE.Ɨl]l90HCS=:!en}ɭUۙ@xd'VRvW$+(env[xSZ L/.(>GQ6d^P_KNK^IȨcZ qmX 8E%;W,x)QB?r1^Y֯2xG^>@KxNEuti +>RWo >u'#76P=#2%?f=S, /uAEA!. .rg' Kۡk'vǮ|Πa/ǂ+g"*kB;*;wI 6Q4 'uٴ=3cZPF0k]N¦|š5mVn$hEL됲r?ߏͦ=$ |ǬXn\!Nz8]šlr1Q ɤ/t:JEN|Tmˑ5Ӛ;/#Xܻí }hlz̊Ưz2TVFog˜dg<ɖI&!n{5{%}%r"~d ɍ.ͮ ׉a9Q<^poe7&:vM9. ,}M(OS]b^aHdyߙW+bR͇SmY fR4χqAiVh٩ L dǡrgu ?zV O+Nؑiia?`l?Ի+X.͑-lnkɥzKda$Ũ+9h 2_Z ^rzJ: eMo-e[% y+Kث&qEˎlKَ_ A&mVO+L}5<ᒤo}5z\!"n^!KRD D ) ȯ3{ǿz@hSHu9zwP&S"p>/P9F!%yhʭZ+oE;_b5ԍbsQ@{Y|òW}5s[u(#0Edsxy&B.CӨ}@-wp*@ӣ y O^2wcA(I߾hpM8q|6)'`pK/ۡw)V׽/Szjfb.[k_ָ\rfTs#0m*1*])S>G3[~ reSu9%v]zvFC}< A:vT 49 n aX@FQ_eNi]ٜG]J#(V}I˻O"꾰m8)>,f@6{Nt7W<ɯAI͸UhB 5q|H۔(: #=-hQ sIt|;e{3+/4M05kX"[Z5 Uѹ@[7[)?~ӓrXH(3!ۊ٤ZB7qVdQlj+s2?}xMmTC<u5FȔ iړT \dC5rV>B\5RC }pcg<v`,HhgMY Ij̍]9?e*/:,{dvYZpyVi[Z'ͪRzt!. J='w%p0T'Mo$aE"}k=)>v^kR8 L{j>0}qj53cUR8g_?2 i^Wd1N7'R b:"ĕn gBT hFͭٲIT& Vԅx!:ӉcoDр rЖc@%A]2kjz20Ƭ4=-vdK2tJ&M*'#Y+0u苻$B^c.vDT5MӦU]{a.Ypc` |uS!#ھ߄G!۟=ٷO!kU$cnrtFAS,hb{"#$._jN('Υv=7ZWh8e*]Tm_6jpr~N~Urs! tEz[pm%{S7$vݕbkwմH?i4p_6H-LMO ک^=ka -•/XGs Χ9Eb=!cUv3qҐb JΊ])X8Ahfb{*(c &f >8ęo./h}Vuwxۣz_"!qrvL eE@y?Шw M'egwwTeg(Wr/i |O{M#1!(IuF~J5rsASXwNRǺPWNmGI$|+cA"vRA?t]G"tNOc^2;>5_5BVb|~8ir2UqCVKSjRN9M?f7'Zdtn^>;@NUV*G9څ 2 1 K]vy} 55ot{KF/ hϗ3N+GH&dsX^?LJʿx*@!&9M/X\!䛙|y-SuCUy:C~(S 95ydCh'4]8& |BܬbkBYz[zyC#d\% @_fޘSCTq[!^MoY6GNhfn }%k;DF<ݝM)K~lJ!d\>SAֲEk°#.%QDpj]r9-tRFvf0<G_ ЪmV2hhT^N[X6-8fև&z4!Ѧŵ(AגHavpP4019 `Mw߶Cݪv,-Iyjf*BL4'WkHKU2i/o}nxoCS" Σ˩f;j5dY侅l,օ rk^s+:3ov'ms`@%@4k9J/W~ҵ̹|ID ο`JEoOZw5뮿:V*1mm>7ɳЕƑe'7J5v:qq;K.iחϤR,OĉKԮ!9vT/ ڂ`ޥי>P{2{JM!x2δڮK_W-* `<iө'*C>c)/U`5iSN䛀K*̤a9ǽm*HȿP2,i9#^w <g--QЭE7x?ߧ(dS͇ u1FZ] mM !J+1ghjUFʈL? j1ǜ(k/oVۨ]JxlOOIKA|2+GW7ΡV^'Nŧ7ITr0r@'"=2@10bUYk_{8 "9 a8-jj '%aՆ-2aZL>@ ޅd<*ʰY&nŵO X=J84*(nk)^~eVqWt"d .XJߟ]^8EszA\ ɣONʈ].d'_@n^)Ӕ^f'+w@,9Ф^nzvޚE{])MJtGr3pUwgoZ?K_+,@ҘMHKfkK{bCa2"ڒB O(ƻ,I;N_OcW8 ? cl ㍯=݉pg o))9/A~myNN6@Kfseb%ù@E6, &Sf J}B\#yjonml6W0@3ܣ Pd{(4EىN&)ER$?#ވYfeY>YO{P!l&U> /i$*[vb߾;8 zJx; A3ay0 [n+1L2 pS%6`w7cȥ5B&,kHdIvwe)9A4?,<$)&e5׺!B ` z #l5rɮ'=D O_" y4@Z)uy!FjwuP"JޭD!.F}_=rt}cc_/@}哣YBJ Y%lYWׁ2Xέ1Jցa T'BblƱ[ū pY  xJT9AK +%5R&x^ՇH>6J0w!&m67R$_ P1W,-x@H%` X(Yn!5 מ{-nrv.4zc*B2C(l399!cVtSh\蜠B[lDF/!ӴO!fY%x=FLuIF%$F8+Ulg%dtXAj1Iy1&[Bx'vvm*=ٗ6Ew ŤR9O_6Ics:\60抸"7VaȏHC{ /u?fh8|Ju D}y?!; $hDn(ِ?[XvmzX$OJ)]amd+KRD D ) ȯ3{ǿz@hSH hnH;pF%Fau/;#ڿג;Wckoy+ᘯ,x( YBkOh3{@-`B>mux~,]Ğe*y"s)[S̓RhM-@ 0)=EV[;{{LN= b8'+Ϲāmȹ-<5t$3L^0iFfPGښR' D#s\N40{hI௫.+\x-=s?&* QX"/\/((?-^|ғ5CDc-\6|Ŀt8Djh~ ;%eZ=kD墭sR;|uHS>-YnC3^Eq}^pBdhH8_~nB=ħsq{X'>k؀S| BP^QPPOaącχ 4DŽ:$#kbm)U2@e?HnhpTw9{ƈ1{MHnah [plh|+CJ`eoWA( @MA\wo49*FX0Ev~EelU}ieI$`|ʙW[b,H x#s:lfb:=w2h3PyPe/*H^]@)$xz[2f74"0/N3׎-!zv邱\UL~.*AG2QV!PbWzԊ};fɑ-Ž3!Vo).C9}wtU{ .l$J^DQ*[^huwxۣz_"!qrvL eE@y?Шw M'egwwTeg(Wr/i |O{M"TP%}- )z)N;);Cbj XC >5h9X3$/E~R}i죊<> w3vXc^A:]A&pBA%?̡wb<&{ejh51hQcKA^bga:6xص-. Az֢;'Sd]BZVb0Pa>T؜pdfDr"!h5=_no5ޱ)SӸ($@v:7&)z*`]pPy0j,ϓE!Q`:mXMNĺzyJi5fbE:omwJ_`%n*шr9c8IBТ<%ZsEDAuu>(ZA*ApGWM_Մ%i,2I2jN妝/lH.N䎄>@>Zѿ 7zdh" ДY#`75|)sF,|[3N:toibJgz rW\^lP,6Y'A+W \͎6yKF]>qXxݥNؒKHtLAAVP|7 -@L\po+%餮~TňJD˷ǧFiN߼D_vH*et*8nװV۵p墪1 JJU !LSŪ.;Pd gDLҽ@=* p܍?+1Iևv?= ;! '1׳fm[ bM7F!><ݘ$D|Z/dmQ" w)[ߗ_`9a^:hv ybh%ƀ']^_Оch;TFgI\C,L/@21~@bkD쿶4%Y[+IQ3Zs:njuj~#Y! *#c7-3' اW $\uRFa7IJ_@fC;MSUUB љ.Fy`6=nv xSCۛO:oe>GG q$h_sk5QVK?-2>q /+\ [:(3 }Z'!1-X2%C}p#6I ?-34R.IXQ^(UJ.`tiG":!(ּ%+%OkN)v_K; Ԭ6p9xY4-0S$q̅ / {-EUvɯ "r%~ӢILSKzƘt&}ln #pj,oDS{RHU HaE8dgb|-̈́+@E*o^0%]*C-5f!D:$PK{3/   :*}t2{ϸ$.<)G~.KP˧d).i@_%Lտ?v^7<pmQ5Qǵ6[s;4$CxMc.w6Y/?taeOipBK\ETťԣ`O_KqyQ$"bu Q@6@?廀yʗzRTQٔ]Yz*$ѩ.߽F!1FA;i?VSNl)/1 pL\WVԫ^z҇Y"MnHV@H{걊(柋1>ޤ}{\/j^bҤ1&hv2vi=+82Vo^WkѫR[@^+c1ج9{2oRai+ۉ Vm-VNvI.rhso g֒2D&Er/J&P(R%T?PJs^9J̹aUQ'Q[חCF-`ᰔ,0 +{ oM,FL_C?Lm {רɈy̡96%:Doop9W}wL6ims+]/δmg-/4WNT(˯W\IY9$Wװ CZ($9 T jÆ͡Xe6=h]\~sʠacM{^@t *%Tx9UD[ ;:htݲ?!?_4A.)uADnVȠSH}:NVpyYK# W[Gl@d7/S`u\6Id0N0@ GYP5{TľwϽ}eIx-=SgRX,N؄ӬU7'GAF<:*̱I#^F$8!ƀ8}'@q&?Ā-I엁ƀ=ua F#IqS!"u3IpTuFˏ뚭BQ.V$8UzXM`ke=h& e]{?]HiH %'q\9tt/t>4&Zn]{eo[[RUO$mJ[a) }еm=-)KRD D ) ȯ3{ǿU`u[kW z+r$sei ޯܾ`YؓAuBSN~"*qz.`YV̡ʫ/}hm1P8GLx¼ ;%/hXM;KZ{SÔ{Hʓht$UO}&oI{a>wvw%@pHso.)-Y*W6K:aʌ 5ARya5k#$5DD~\IDJ@> §Hh<`[IO4GUUI~&ÃLtucB"4UWrH!͘U$vkILkX0U%A^D[:猛~\~hY1Zɽ'F ӫSM E;ҿ.b߾}x3G~qzLz؟*̱wճNMWA}Ft@Sy$PY9cc}ڟ'b,dGU6aYM҃ FӔBNt:cp#<`]K+AQ|JCu[a4 0d#,87N;dj6\0Hc Nc![2quUX.*lyHŬ.&%12ɞAx"~2AjbիGn1|r>-O44RS»z8 *tCRtLv~~x]g3L(lvN4ލpuQ(cq|7PŢy!(D0 ƨd !;ď n4һ[{mx+!rÉDaxT}2IΦۯRɤ*,ED"{5J7,1N .W9x8-'`zb]kȏĹynpd[j$϶"6l|lC8*daUk6bP\[x`n\ڜ~p^S{a,֨AE1CU=r;zzeG}hnYA(cNF'3v Uy[m?m/X+:RE[*RiӸg1mPwq<@~/ϳOjo"UK1y5[b_ V|@Bd5v5 CeQA@3s"cAT.zəX80aAӦژ+ccޮ}L~riU"%n+|H !"4ߓiy' Sd $d[&{&*N}6xq{~ڲ^ " ͬ}_ V[HIq5:6-G8ٵ87z3!^ PuzJm#ڗvMDɠ_GD g)3K0oT0_Ng,[ %YS.]5/AuzCntz9qJT:mNPSYɐȂ?q F8訙Kc5 rɱQjStmџtqslUKҨ9)͗}IK2!BxQAQ6QҹNE0{s?UX,=zz?T5^:۩md Jv0)Cj氯.ȶ>^:S5@ݘ*"Q,/Ӣ/X-TR, f?4=+|tUX3FPō*`o''F k=eVM,{a-bQhMN|7HQQC{ g]focy*-\UEo%+2)B8D/1&1H鳇z5}7_Np_d3WCʢE*.0@o5.Kڥ}!ذ E~a}7|bZAE&@.Ki ^ &f FDpYؤ2XQkq H1 W4هmuEYOba"Mɴv`֚Uԟ_Z@g(-l>>dűJ% QV!fSZ:S4UC:2B宎ːjf;Ec m5EJ8wepW/۶>݉Ah#ZRSTmZ}FCAm^l{کq$%Jj&t4jau]-"Zƒc > &ke0|1]^M&Y{E&-c*<ʒ(+Ayuۜ BtH[>n;O_xdoV6f@M4sS} n~GӉ+GNKdlٖ|]C&[IˍۛG93G{|Fbː)S)0)d}efW0MJ̞BkY#wf?1?i9^~_8r:?ƻ]&Jhy1^_Cz <;;e!mPK4E)7n 3ALOQGYPio6.JUO .NWDTm~⨈P/ t |B%FM9u 7L.\*m0(:MIM"~leF.#go 툆G[E0=v`v5 4 eN^6qi5N y~І=#_te'u:cz&(K5Ie|8Mc梃֛?UEv9y}24'o@@QZM8u7Mmڤp LyRYP+N_ !J\49Ro,<5 = pdڤXՑ0}^i d:+creQ!H0m@27ռJO9D8B#{xrIؖ ښf^{u?[RP>fNz9[/#f _|^ʬK15y0?,b~߉ YKw9 MuE2p$؞i..k-zLh{9^iM+ʍ?%߱q{==?n=DZ63&ʱ $ޕ_N½3iȩȼ~ə aE֥ː@ETÏTSvgVL|U[.d-Dǰ@vi",tY0MX*ڴ>5b14!r a5I%/dҋViGtyKg/"-PH/f_ O}[KnDh '>LS>4N.E<㧋,[6vRkbN$LcT&<'*H1K:H)@O LhCBmtꍜVrRTwut"fݣ+Ǔ即i7*wiw(nꤶT#X+9G;ZE ($kS/£aqqS2 &vp7G3䧱T^N̉hclLo]@wڼ6s,MWw} <7Bx@怎BG8Q_sXU? b@9/e|xTbaM7ICh{WI=fYcRZ^K2[[h8i[hGC)ص]`W3X{+Zr zHϨIs9m ~?뀆f8 b@0ynwsp-C7 CXݦ %JVtUد?qՇ*Ԟ 9*#K#6b?B˿5Ұ]1yYWf̤ߏddmͧv)FVmMˮ@N;!˃8V2VDMd󌫢&Q,{6u`w`{ !sx{R l:Yo-MX2ei}p L _h%-(l#Vi9lYZHgX,>]<̚ R[G>>bʣ'ڼL-$K2l>}5!@one.:dl4\-rTmͱZ/V)n yz& h>}d7afIgoz0VD9G#jͣ_xλ^!5=F#d8e%kL1ZJnO0YۭOn*cL/Ar8EVIPZB屴\L ”e8Io(Nd90E,zac E/d>>՜=?0y䶠̯_s~37pMqineZIi %::_H aQ{XqZ|J}MSN\;RD4^oA4`hG4|ڊ`/!cÀtș6-mC~11WBK\юrn~C.*;_?~`3jPˆ N;VWO;̘BjL#ǭ0d. !j|{!kqxn.6D+9URׯ?TaK d?w)} *_)?nTYT^&Meu)΋L.|jwe[a ){*X3BR>{oėUz3F@V ۆw0` {xD&]+q89HT%4ey킠2/-)1s؃ FӣP'co*bp:T$%uMtOereA#ǣcKKhM/X6a]dJ >CpVِi78-¶--\NJ2/m :N'(y~1£ӑ6Gt_" {I^Sc/@c)CR]+|%FE?2>F,ЊӋH6aiOSBV\ Dq=FMO"Zʺ&Ph]R1]|(`2@Fr.{ eoD.A~>8X1p7vs%tlߵhN 'q%04uYs'R4yEc.֤;OVM4 \UB(h(ݗ@÷O 71 R^JDezuycj圧յPMKM#\)ؕ ;!#0%1 X2& G48">y77J(맨=Lj$|_s t (?dH*AWj}N 6X+ `pױd7<knӊfDH"2Pys8%YuoA}]yA%_"Yr#od {ښap]*f#}Pfg KSe@0T:XoM|<榀f03_i u@ 2a, 8)Hd'R4sX3}&lclTa^p 6E?iiZ,Z`yxx$>:$:\FSFlv|ܵuK vv Uh #wme@o?skn6zPv{[5C,J WsKl#b+VKعj⁛66rm ,Vwvb?pE(p{>A д[KarʙK^ЕtE 㧐XJN}瓴3`.hgE۝GSuIg>' 6&%P\'Q:cqFǐDV)9 w3TBM34Pԛo&1qj^^x EIb.2"Ҕ{sɌt58s8 '.E'$dC`3!%u2u wJء8ztXl.>lFsRdv[6S(Y؈p>5oI$iE W/Vk~0 [is?I5̦Wb99Vvf.9m>OQSQvfʳ1CEœ:T6]A ' p:wYU\SDHe/JI\QhAr|( be=^Kt-Yb!J-y0iG|wpjH/ʬObre13B c9_Y Vb҈itajj2{XN%Ir' UaB^dIl>;q ӛ%D uE cM}5.qL?AP ;*P]V@DQTd5vX8&ʒw庫|w԰푣4z!B/MðtE;?7!ʢ',B|i0RmYd9h(^߹A#ՙWnI:puY~u>L:"* e.c>ОGx6VUIe{siV68sjُqm_vG{Mػ )r|܃ kz_ǦSpTr|B'U KƲy&Ԑ2"]оLs)miw)o d )X͔O&8QL#eu=nM.I4Y[bwyǠ3J~[]"/@`a, 4h V pǡԝ8; mhX6Rx2rmP 6G3Js2(Գ^;9}D$OBڛ)dK$pߧ0mkVAB Afh>sS@Yld\|w*e(ΆyߜX'/1AD jqu?3s_E;<٪ rT+p vnZnkoy]UY%*ra)ekŚق8;wl/wuO{445Vψmj,9lؒy31*J[[3𚝤,0lm T 3 gLԸ(TyJnreԑ|7r鵆$+mg^$XQF vXmZR~AzM>E^8]} HϘtj6,.aOb[ 2MO$&upynnzU26~ډj~b!OX[(O{Pi-*u]~Q>χvn{L4A$)3íAr*^#){YVq+__Lvxz8QܢIZ۳  wST098 3&i4JrՂQCK d#mн<`?1I~9O5ˣn}z ᨁRҎGng=Sf[SQa} 'h Ҙ|yፇ;ukT )XwsB]G \tzyo_4#L6 ZVHKPCt]Cműc+^>Q0)q^V~j%]OkP e% /cbܴ##Tnk$f0ʣNkb@po}͇x3>cKG$MS ε] ⠝*ie'HpffEk KӋ.J9K/(KnbNw+DmAk\1t)R9o/*Sdм, R왈nݶfeaˠHU[Q+Xsp-s̵e6#~1`ܕK]#)Ix0Oi{yԁέ͙7+JN9K4nb[*,v&fÑvSO=v|+\% B}o,9zwL[r*~/[ ۑ"ϭD*(aV,إ %Lo0?L\h =kwݮ@# ?=>L2P6h;jt6#[&8FrAt``JM73Fwss@_$aCci80xJ91ˮlZ fx˫ְvTy.uu{#j XP`/p0KELO>"}N r' :rhsn y75WqpOJ.7|^-4j6X-ۖ a{~zQշV$\Sz2KduX}({9S >eQTc*(  xLO`uMPRdGnBc4Td%*>*Xf(CƑQ俫)/alw곐 jn^)8{ذnѸͧd(F W#~=ڀZ\fl/X{LnO\Z[DHi̤>,OŶǘl`MҢZ^\JM[MtJ:&BcvA8?EzzJD\fM:*pſ鍸?bwQѮP,dZؐ28=,X''t+ݯMrD[CɢAqڵS} 9-+XkFȼK3ٖ;PFYFLChxV?ӰP YvҒ;Jbeٝc rR$E7SsQ~_0SYzj? J52*"֩DiJj)Ut0O^nS]k e5h_7B {W~OcdXd Ҧj49?tdsz3_2u l:O+ON򧒵K 1>f nT Gv! SߘFAǠ q_tJM7M\pr\-d]kW*q O .u<w IG~XR N,Հka~qPPa7|i~ O!ͭ&P )aG58+Y;Uس@C4YWۃG:&LRc s.~<LfEݣ `%^9#88k3 _u7r3jtq6!ncE:r5 iҀkr^*G~Ur]=ګq`Rju|m2[ֻ4 ?Vr*PܖҐayt26/ڞC$$rRLi(\޵J?]&:-pvZɢsQ4!1~?DULQ]~nPb2 nW3a{k؎#+ۂ]73AY@wi*Idi dUI뫉d~Q$1kcAA@"9O6R{~!`E|<\3 _Ua2~ք BM7!ZO QwwαaQ (\sH[=_Cj35F~[gΪ=ԫ2\; zC1.bn#FylS>*]n?3ΡHڌ,X zkA64D&wmɆX|eFk]xf,4Ud#MtGLz/5 ;6VQ %G9I-ovԿHR. t 5|6]ߋEDh O$΅:1 Qԓ3OFP=!#U5CwFm\lk|^c ޓ`Ou|u }5+%dQP\>lgec 觤)`sф]1t c%-_YF܂z&(gx!wżܟsEHwJٌ6 |Ef(btW_vׯhsyi6y!̋I#[naTЫ|N P6ѧ7d7'8+I`Ώ3tm-x D4ND;VRLS%[9%$\aY940,t~FB04* `M@n?8.CН} h!`%{wsE|<=EҒOа"ip q_(CHxe[@'L 䣑ѽ8Sg`ڤ _ -;ZJm£$VsWnhXG6Gq]n*.㯽ܘ\IGqpBa6}^.w1ƜlԶ@dv"zs,B2l>SWAssAzVP>ɵz!@zԉS۟F~Nм]?܀/g+˱JT;_ wFJao;U,1#9q24NTOyWcDAtDJl e^GqcJg&t`!ۀ7" 53_g}b;5NG}Mc}* EvGj|+W9{/MƑu|i3w;QU/~gc?m\35DP8́+X<Ǥg\b* ނwjz}{-qER9!*8.}ǹveā/@t:!gKaiʸ)b [x$˾AXT W_ȅj\Sv|ߺ0Y&:[,nLDE$J"qҳ h[[+v%)[ /eSƟh0bkpɊexSJZ^?jK3tW*"M/B|39{dߏ*%%w̵cv2/d:m]#lI~(47gz*xG04qU-Hs!ϯ*%xz~'|#c+xb:\foH}}ĊBЅ,mиlx$df(biƤ7N'.b 7=␱QaA){2=GţWZsw :h^,wb"5ވmL8C|>>,g9-fʠAjZ, }JuDAOڑF-ssĶ)rķu簚9!+wl3DfA<) r$Kao`l=TBU-n5i^dSn2~gU2唋ryYS! DQzGU WmXb'r1LFcIk\f9ɣݵ?˗cQ*kl zwޤnA ڵ[ȸ)忦cq>+kZ9YbʣZ>3kpIjw-rT.“p({⡒q~do妺pئwߧhaHfʝFv5S &lLMEX=#n3p\F~cc )f}H>s+wK4!M ^$TV`'4ђBk_n>e)ŊyZI:V)~|^ݻ$A|`R9ܯdUTl{Nd\%8 ZBeexuEQR{VAlbLf-[Ȳc{(VKl% ڨ4'p ?R~h0y䶠̯_s~37pMqineZIi %::_H aQ{XqZ|J}MSN\;RD4^oA4`i++.A /p*K很Fe9X7D*ofphy ~M +׈Vz_PLMQΪ/3hOAa+p;)_4tv̍O ʭ7> 4nx"GΎ.NЙ F*C!|M5їF^o\h~vCwJe~o$eZ#=AQ|%).>ӿ>t\QZ)tt&K3 x5ky) ?eUD5|R2wHB'BACs-}z_'.dӫW" KQz'ELч) v^,ѳ)k/lߛNy< to{57q~ū0'+"Փ!AL<4mtתŠzwzlctrdhòMqVEr nӤnBI}E>/e+b ^>wj‘!ɂ;hB@+z65"*]Z&IH?#7s4m<:zZ[>@U )oK< xh\Ԧ{j~v BQQJLE af1@8{rK0c"G. &)$3JDDM62{s.L|.&|ԏy,6`K IJ;˝_-1.Fzqo(67.Mk,A TMz-5ik7ޜnm. 5Gml#Ծsds5Y+_TC={?hxT<xYw)i7g&٩zkug`u}v3r-D6gT_Б߽51]Fu}~>+ e$Aq|he8;7HOXQ_Ƨ,'+w[I7<knӊfDH"2Pys8%YuoA}]yA%_"Yr#od {ښap]*f#YvYҦ1+xTg0T:XoM~@0B*Tޑ\L=!5I)q q Kg/;SR,4_l+'˙TIӆb=B1r5cU=3\ A4{A=T[$m5"b6`_iр|" %=쾝QwVx*H-[i/NTKc%2x;jVGMۄExH+{p.DfEa#ò{kNW@1(IU62Jpet\C9xU)N/LWxjMkݲzY4}wʰ6rD^ۋOTf9Ŭ8uy@I4q$qp׮𘶎0|ӭ@]33(+8?{rG*u'PRUm:WxJ!Fgs=4X!'sJoW/cўHB|걗(EF6HU *UI!TW3< '0]s(2 ؏Sc0A;gyBbLBӐjhj %R=n66kԪ"\spD)!T3Vc_IZN RT6qGzIEEF8;f,&82>hhW[EI^YWKO~vt3ݶ+i"hgİDyJ;qt!C8*&HQ+I^liGg^^ 5쮬6Hsj{PXgx_6$ >f 4$O^eO`! lb"PڔI,&z u7i$QJFM+PzE ctVc&OΣxA8S#H!E)ˏZ^;|Kwޒ(2`3Ց>J:P2¶.{\V|`55R29 es!촟)l/F$j헤(|ݶ ˳F]+n@ڥeӗH]XG$i|FkAm$K$Z ʶFm{BFw֛|׶Y]Se_Mm|365+ q.L'x\`^z%ׯ,$1՗VʌL5ÊD2쏼jG|g`ݥW wph,~8gH?< C jȓVH2 il b9aY1|h@N1g\6~nGB0@PS^ib-NGRx_]r^‘(ÐuS_no/9ɐo9K` pb7gUtx^ PG^Pjv?BwB`EAxf)BeZ_>( T7+}4mio![cx2t =fgC4 9&)JE,8Y(DV *:Rw@ӌ^ݜG~@g64?i*L@k:BV{eG m(A= ŜRGTrK$>_PĄ: sH;K6ҢE2 xa@u*6 Uhr̃ -A>rzߒk%ELI[ۀE㊭y c Ώ"5Au__SG:vP6Ida q5c7%sZSXW ˙Zh(?ݴ /* pf9R :%f=Mb[GiQ|3H.оLs)miw)o d )X͔O&8QL#eu=nM.I4Y[bwyǠ3J~[]"/@`a~߈3=4o?CA'plO}hϙV$sPR׬2cchR Og}2_Sqq,㒾ްeɺRw-󕨁LeH&I1H}.ey9mbVp:f 6)%9hAV-}bbJ-&ɔǺ}xMR"qLɋq-&2$KϪz8*]BV{>{lX6~*r[ [7 0J4L!R_QWCs񸴤?XvV[Ydg2Q>2pA]ح܉z%1r$N.3l(o7{c+aۊ |i vn_uى{Meݯc6K[tk韻RBpdi2}[魝յ5a*s3GKh9.eUn! (ik2{`bdws퓑 @i άbX6g4m12RjșmWFG5gH)N/kͧӟMI⦺@#{g>|8+9ۣOnwyF? h Dd+5txNsEW.NՅJׇSՒW܆.\ Jkhuص9f,CQ;Ҙ8:Ub衟#?*uu\##2m.T־--^{ɐVxqXڛsL |R8BNJA_N'3W6MYr|owE!Hگ.uey+^f~J%-U0Έ/?;ݞRYU5Ujo쯈a<ǠE|{ZpmU)0sDܨ1XJD}L;Hq; T}A jiNSWG}ߌ4JW64\/pKFw7Xε-DԪ)vK.xI(O D.m)LF$|IaU}==K-PBs&PFej_ZA82\r&swdFЯi' l !PUm 5cX(Vub")>["a"l|t)6LT=g||{4YZu´B]m:UHh'vՋRl=B;tAh1ɚd )bҁ!cp9լdQi̕ ,dTl%^ 7G@ZR-Z,t<7{)$F˄taH}E6[<)[ xl28̫CZ ;8`2(aiJ5+BT ,SfgT3Sm/'eISM;8GpőRܨ9 (E F4U:NK0ҩwёD Ia`j<(N(c&>'0 =~kp^JfDk՞9{E'Reں;bCwF{*Xᒼ,Q!tQX<POLyBLQDaON陮x U;UvZ/-G*J/S Kϕ ڴڥvSki7?8,j|5*i' ǣc3ThW3nqlB\۠ZkT5MQIMbQV*~..4JJB-PpWI"%qm!_w6;uE~*(uE?L gi01rܖy6E<o6Y^mR֣=A.ٓc>i5krZY9>LcOLff^uذ^l rU[X3AcjG;?XB<685e¨ ʜ@\O|uYIN}ȳ ,M"&֪a0AjuhFU /yJ}w )-FwE^&OXb4WEi6qSF{d 4IsC.G%:knvӆJqc%/ 9K?qfh~S[#J#G ظQ0їŰhԢd$ sh(H}@\\%+/19_E^+F_rQ(Ct{C:Bq{Xᘒ[2F֐H;gi T%SѰ@E_pD3 B}1y~b'yC+R=@oV9ҍ}(4#V&2eDOv͎7ۧnyA '`[a_''y&= ? /DT?wq¾!c4YcKEC=Y-* :ݙ]\H\O NX+Z5LI,'HY`G|.Ǔh6&KxwefݧD| g/VA?k8n2*nkH(m Ng?@Ǘwm%{-BtA$ R:+d8FrAt``JM73Fwss@_$aCci >}X7snݓkiqႂ9jhp%;ET;8boBesu$1)K鸹,/v:@Slz.8@y}/•Fs&߁ 8D~ RqAyfhJ&d&HF:}YE3lRVt}tsRKkQ+tU^GU~!Y%,7-AٻFb'#*M6,Jq`sA.f<şK1_NT8F#z8)NQMYRi\dѺ\ߣ0c0LF^ e NpA&2 V{x$TІŁs W 0L.bQ& W#u"U 5)O[+z˰6(PB]4'DR_źomTf;b\`CI]rY\{>%/?ӈBė±*u -$ʘMԝнQ1>wP@Z -׸uyŎLֽV/C)'!bgɥCE3^W#v."C~H_avL۬@^yų}~J=8A6хDqR9OSWEsTcޤD F5|9 |8 Eb-6B3=7G/hM^ne.~a,F3Y K'j[zU?8Rb1jZ*} ud_t<t0'y,+‡-ndk Ez襯+#鼃ٱRJne.!d2[E#FSמ0.َ~ Q# U;YOI8PcҊŖqR46dzc;{Av*Yϊ:B{,;NmFծ3}I *H#DRbF M맫fjH\8'uYFEu^'M j-`l [H`Zi31ԮO:bKUa whUR61찯ҠgTwxϐi3 _4 4:'6#Ttqi  ElzjgPF0uѣ֦-ɌK_?Wڊh%9d^o4-׽6E z4B3qN\"W%~N:Gdǟ3opAIUpO蛯³``W+( /Ng֣Ni EW",HΜR"UJ7e7kzobVKw au 5ooÃ%?hvt{4~B=&߇~7臏GOv;cz&(K5Ie|8Mc梃֛?UEv9y}24'o@@QZM8u7NHe=yx%EU"#nƀlE=b~SO  ZbB@<. BBk %!H?~5ɎUַnIB\|]瘜U( qcC DF#P/izn3$ K[ -LByY4- &KP:-l=3nWyixI7 = <>LGv|o"Ip']<Đi#<^$Q92M 0;sfTwx~2 T{oF  jDxGv4I̮o.uCerħ3S 5yD5%=By6p!FäOpIS4P=SodŶ̕H$7MHl<txdr\2{|I|TIo&afΏS"9e27p`:2icwy_~ObӉdc&z4,vGm"۱L6*[R 26Gfs"Pidx#=3`[ynRЉ8W}0y8D%xj~t& L0(z)do9|Pn Z;z9 1>D+uR;{F6{ǀy"wLEv*Q zFA~T&<'*H1K:H)@O LhCBmtꍜVrRTwut"fݣ+v|Oiu3[ke`[ew5z)4 _%!x+Ӎs vhC2.L[o+ HuljykY$e6K"tr$+Y\ +M# ]%}4Pj}2wRۚK(v[NEש04DP2mO\FD `Py;/`@La("NWs(V_S#>_F%R ƌsJۍ(ܭ%R)<%aarXbmnKk!քT8ێ111B8HyOMcoz($QESBm,Vg3"H>%WOswxN!|Gt ]$S\gţ$_s{Q cɘwLK-¥[=<|r_JIp܉pSL9j"_rTyjȓc~)?;a'@V;q&xK D![*6爲F X;,ܺH剂;@gqIWcʧ9`8*^0'9bL;>^T _%1%e.k IXz(}qUuFcÇHgp?=](˜UlYgP*5`1 i^r&_'-2C7%v q7[DxF Ay__!37_Z c~_ hW\*Eⱞl '"Z!ϓo؟_?.S4 ]c1å)[>ҿ-W8,eSa`{Bfsc+(2k3{44Acw(a܉Amus8u4"]Rr][. +]@c4P99R)WD}Fq㣚rN/s-rsJG͍O ;UׯLOQDcHyp69تq0e 91<`'%7(EԖT?0y䶠̯_s~37pM\$b)y[>YnXF]!F)KˎG=UcF%75aW3SNSu?E \TT@Il'_I}*Y"ECR.`ބh'q͂(͸֒ލK-CgD,W JBb "cNwcxJAS_Wo^.&#녻9{jeV$ѹnD/DƷ,GœrRlfy>I",T<3洡]R^{ :{4kx2.2 ݅II'W`\"Rcf25;44T$pw׹z4ŸH@5*z=DԒdAeLH&h^Qz 5"PFetir=o*KJLw˿J.;"b_XPl|ĩIu(bFI͔5!gjJ4b=Rq-!N"afIVͪgg'xy%ӝ A <2j7<knӊfDH"2Pys8%YuoA}]yA%_"Yr#od {ښap]*f#YvYҦ1+xTg0T:XoM-Ң@Q;ͪ%Wޫ/SMvh: q5c$Yi`!.6f4CraE"g5 >&ab; K9mIK `?^`gX0?h=+N?;黅HX{.z̳m/my(7)a/[rQFژ.!rOb ݤ%GI.Em~;K{n3hB Sz1^C/5駉0^yBr6Jl]c<a .? n0)=.tEUʲ:o䕕}Շ-G}_MN%i|ECiB<1P-s*`@|tfT v#oR(Yw0y3;OVgXz]IN+%tN fG5oq63=88t ?Xp]fLXچ;/Ho+:?ڥeӗH]XG$i|FkAm$K$Z ʶFm{BFw֛|׶Y]Se_Mm|365+ q&: d lvN]Dz~]Y_ +PG!l[rϒ(8xfwKrF]7(XǼEkIߔvDRK֑d; L.'D/E&@{QPR)m߫UPD**Ss3xڔxGǵP\©d*OcB*Iba<<%̠pT>RiK+~]_y-ؤ4WIK1j*5 lmG-=0mWAk^(̧D^9i@A<`ֱm+=9\VcCֻSK1 H5|opH 5&VG<aL ~t9!$Ku/ ԮRa\̋g0!'ro>eUZ9ZrN0'I;y59]W-MoZLϧhŸ1W`},ʄ6] }Bh w_%X u'|vfDzˢ9߻Vzł`M ` r9>!E<3zh7ib޴X SaScd-@$-zj=pdWά.;XvM`ljj3ceǸhe4즈LiGؼB!oqQR*(Lf&D_W|[ZFz%Cڢ$^oI՛'E*rW R!.gN95Y&5rιI `'3dMx}Oě%, N3*]VHlXYm +оLs)miw)o d )X͔O&8QL#eu=nM.I4Y[bwyǠ3J~[]"/@`a~߈3=4o?D^s8SA^ |~. m&]P.[BK<|e )8ʧn3^vݳnjO|g TRh48{ chASn4r$Pi &O+QL@66V9PDLuM`G=oJ5e=O&PYjN"opxc}z=}@pI~!뮊R Vh ޿z7a׌j/J4f+;Cw5#՛ &u 1*Vjr,6'/-Y~Pv+lwIjo ̬93`UR7(<䗊E J?j.T'=١퓯V/:U }C|T}aH6},:p|I*P?ݭ*ZE@9DQQ!XNi>BDzc^+#INX\>}.0 Z,y߼^-;!Q4d.d*WLSRS5U Lx,@ ̿➴USĖ2W + 6,7 6Dxb*^iCu?(f&ƒv{ ϘpuٞHU[\/#L{>p bޙ/0"n<^wSo2bkv*z crT!tDjb8%SrPo[8fbKN[4JK!}&jAR|_Lvxz8QܢIZ۳  wST098 3&i4JrՂQCK d#|ptw,̉==u`a1V0s]|#w( (2mߦXF%.2럎mC`h7-k2S$`p^QY*a騶H&aC:p/5¿w8ymx93oǡ5ڪTh` C|dii THTM:<2݉)KvcSL`H:]ϊS yCz.2BDFK 1۔LLQju]яVT'38Oo8iy{vD4T4|9zGt} X{KGGgH,oݯf`/~wgb!+jՏŻ["FK49 )?(P;Ǚq++k˾w"UU)jpHT4y^꡵ڸhp C5ǧn|STf{G$F,ѧk2ô.OgYɱa&veH%F沲lU@C02 g%UփUw]'_vzI mf۶?Cf}j Sy1ɷPŤ%۹iA/mHt|&i.8utcRS6s nDHd.0^x&3&vXH#ŏ(Fp}ZAlSIgcYx>>8S VRI~?ٕNkeOG|!L+r+ 5Zg& !VIh4[H&u: O$[&_23v'i3JfDk՞9{E'Reں;bCwF{*Xᒼ,Q!tQX<POLyBLQDaON~ q<{;ŽBX)ˀ{lJv67Wѧ$p+!Ja/Z#H1U,a! Õ \QĞ):"K`ӝ9WT7_5i2gf7q@S0ktdxg[\JtбZR>o;6Hsĵ`@zwHa>:CPeW[{%;trIs5ޒjʑmsBw7:23J6'tߒ,xSYrp~#o7BUY3>JcLV5* c0i#XOvFeAiӪN⠍Q){\-];o>Vɬ**FƷ<ϓqv4oL!%&) &aZmpSe}^ 0E*__U9͒<&1޲R~:noe}h luoy`0HEcL&؀u.D&ǣ n_u7jzQaq>dsƅBn{:Đ9β!Ĺ 0Zɗ\G,_K=gn`js{z\rtCY ~ױY3yN. ; !.Ne cnh#4 . uYY_)t|}+[$fHY, K϶"myT|~zI1 7i {T7#vO8dϥ<ׇ]s;)`X1j<` &_[0zRK>"+)%PwqWDX48aeh&Sf$%eF")}Q$/j\o([f]|'w!F*71y`bA9/I7l7Ě g٤slDpAsUF|czKN $7\pwc:@LHUnbl ]}%x167|;nxs%Bcǡk^== ||EVC2B4"lU;E8zn\C I:g,QO`Wߋ][!% ;ؠ5< W+q@QA 3<πK""#)2R߄Xuy>΃ Tk0MkH!W#"}HOuQawa6*eS] Qj}ufRز 41a< ,艣Cy?UMЭ-إ|^gb O.D1 fאD q +m#Zy #!.5W/VMʩ1ӓ"fJ5+ǒaM+J3 _VnKerG!~@_ŒFK#hzn.9mN`ڨIcg9KFnUCNb2Yo;ҴoeP\sJ%R&%P'x ߸m8?qKW,#Kt0ghP٥ X^moDp#D:R;2ee g辡Z$'9':ĂlR&o+xFTIhA)003HOA@mHS'>N@[D8~ '?Z)?aJuP*!DPcHƙ *,A~ȫ.XZݯZPaf<2mv8]*Y}Z !zc+ԌY? ə`~MfN}PCRŚ avs"v/Qc>&lj~ 'JDJC{id>jAL~n~l'۶,|q 8ɷ'gO2 7_^}W2ʉn#3t hdHk X x"bbC? 6:k,_O={q^@j-UĻpdf6`(/"җ_ ~/EKO( 8zƸBF߶_LU(㜫}9app~ĤO#ySLm jH0.\Cj!2^5(ԶyT.\iTTkU)aA홬!7t #Y<ôxaYgXt ϙPgc/.jb⥷!V8fxK>a/(.v#^zOͽG۟ѝKC1qre:hRoV vusanIqV,!jDg8 -["e0~1Vuە:Y駜t`M{ HH c4O ?Ά^KP^{ ;LY3,k ]U<`u=M槬Z~tn?yWXTzkW_{<`a1^/5 Ń ?m ASrGN~=fD!.;wKU74 k سRȞp"|-^Eº.+CWj4cFMR QJG1<8e5>how{E}ܬh@{X S^GsjC1abt:B926zeަii T+Ljݪ9bXm4fFE,p]o>$+.L"!TЍۊ*76C&KhUL2`L\_SLR֥~ U^Qٯ{r-X0Y pLA 0O7WК18ƿ ʍo|]8X AvUw6lr a>P61'61HB-̨L)Y"=EKX']續d++ a|n1u?x@,]v>ףEQ.ٚQo]DTFXrw  *>δN\;:ɀgF^R$J]#Sؿw #0`%3F2:>o\+' p޻`7.5m' F~̣ZFKRk^P%/w#Z"jxi̺j &e?fho01 p"0/auU\jiATUQ6n-"mSel3KgfN8H[ [6 a8m@A͛鿇8SC>VY vq6޾PW+91ëP~ê}-&) ̤;Nl[G0"M<e&F?K4SfF!~W29OUVgHXQ͜)lJ͍ipj7aqXH] uXMSά1jlKR\e{43hpV'I^)LޟEkd?bv-B ҅m^)ݸ>Or| ZJYV yG/q ቌa CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs  tIME& IDATx}wtյwަnfrqc№1c+B` LJisA ptt$,&x>B(PMMMz?]Ϛ?֭["<>X:&ѱnZv>(4 ۪j <σRz(˗// ??/'K$Scv;v;$IZuV2|>Cp.Y,m??VX5Ƙ1cDCk|>@+辎!Xaq?[lW20=>>ӧOֆC F#!qȲe"kCTUO ALȑOII!|pi7nݺ+Vl"`Etww7<<\ȑ̄A)#_AYsu׵gV`+ vy~x8qTU}aR0?JbCc v;ޘ?cX2ʕ+=Mn߃AVmw烢( UUj80,PUu OU!7Ytvvqeш,!yȲ 硪*!21*DQrݨE]]n8111wr3111pk$XAgg'^/TUfSXI>DCCjL!2l504R*:u gΜA]]wDZZRSS<;/٤p&[ĄDGG1S={Ν=l`\.x<:tGII ;(--EiiOebHNN6{LDBB€2 1v4ePJK 'N`8|0a r̒0n89p8E6 ^L権1xpQ=zaȑ:u*&Ngh8,wI є?FEEEg̘9s`HJJiZ:u ( 4MCyy9˱}v,\˖-5x_͚o(Iu(?~Ofm馛0a7<ӑŋOgPJ܌7z+ϟ?h&Z%^& o&8'o~D{k$aڴi6m:::PPPz hkkÆ }vu]9r̀U8 @)mb۶mxކ dɒ!6˅իWΝ;?]]](//O?%K[րL3& W2_ ttt`Æ 8|oɒ%#wwwըAcc#:;;xf ==iii=ztN,XlΝz 6m8u|A cV6lfP djO?>-//Ǯ]PTT !ĤI0{lL4)9{Xl{9;wUUUXv-n̝;ߎ 3;%_jD$͛7G 'OFRT\zkEEEXn_8c <#Fպel۶ ϟdTBq)EgT Q P/n;܈ noFGS5_O~cBB.\o #6l؀|ofZ٨$If hii˗v|t@{{Gك 6Zf\a ?oDفđ3#Ft&K% (#@A?K@<ֆJ4;d^{-n={7cٲe;dHQa芋Q[[ ˗/ nѦ1&x{1̘1#uVĥ) 8BLsƅ߬nokCCc#W(Ε@Sܯ}kvVѣCgD9s/"#2s1vHJ # h0{;Qz(ÙpKh#FYB^ee%x ,\v[q٥=wJJJء˗W_*Dѹ`Db`cq^|E / ;;;߁_hjj=:SށI V#95 <.lxN @G ,bAt H !* ]hn]ގɓ'bbb0w\ر^eTp փg^{q@)Z ^03yӗ6χwسg #o., Q(8BuB5qDpOA@ 3@BsF((R8b3Qtp7`8q~cĈ~?kG;#\uU)R0ߦ( ?ASO=={@0c]$ CC>NǶ,!/p!l(y'DFcɊ0i @UUp0S֯_ovq{,J;\fo{qYUtҐ^?b؜{O0z8A 'x 'y]p@t10]X9P( qD<-^3؈{ Oׄ:u*RqBUU @2@$&1 11{oȾO<3g?"+E6p [`Iׯ"=|06mB8X='A8<х.r Z6isIY k7z `G(DÜkf"oRȎh8q"H0{lL8p!?~܏XR O8eODXn(;F$g(y&Mz7]Ե\QYg"n9V , 7w6&x{(..:w͚5oܸ1>Mӆ'hh5χBiӦ}+1fY!pE#hC ʗqӅsLXČ rdXqrbyH9 W^ 233l2!dz ùG[ ٳ~f  Kn3hșT/< `O׽v<Ǚv~M0rbDHo8|2~E ׈`!~+!1!G($A@ޤɨ(FSS:Yf}wٲex7QUU3FzOz@mm-Ν;曃:tnccj :::PSn=ְ qyrq`o:Zk.9s${ASF`áC 2r&† 2-D^ΏaΨ8bxpȑ19}tZaaKݚ>}z}Inĥ(x}8&L/f$ #= 6ޝ/7uT3\'>B[2P (bK dƒf+lF@PÈgzOG} `Goe-ffK^>(QR؜6hfeMӢ8VM@AQ3ֶ^uFN`^Xyj/c hl,Jʞqۀ({$b?Q6AvÔ)K7p%3 I"8N  t l65&aP٣!Ov o!'%oݥ'=lb]ir家:d> FOe 0i]z {$ q7!&LO-DFQ@↕Xqʋ}!L93$X FPRJM`.ki$Hӭ\E \.<Pnp@A7E zFzVvJfk]]]P,ZEXy/ ڻdx:[x R)F)TB5k ֱpfQLorA4 `O6g ",:.j-Ħ:[ |t4A5i:2k2Azng"LzOzK8mkmj 99?Y9s\f?9FeT*++"-uPU<B(TBQiTnGՠjZLՃK*#,cH{zxKlª"z@g5Y1PC'ê5SS |+Ţw S(fjg>IF.RdQMݩ_ Rѻ54jlX:=gF&3C$\8 PU@(՘z >KdR!nJ4JM6G$ ]z*YxeQ ZArE|>_lYQ1i$;\{| >^ |*hPT Tj4Sjgڸ(+0]}Aiiip:H0am)zd Η!tkM_&AW? l|STu@Ls9Ż3Oe%y0zh?GbW΂&a))fimgφfCC @ 1@U5x]>Eg /* :K``>ݻߢ꽏eehj^5Gʘ'oExpx>#( Ø@MWӌm,PT͔˅>OVK5M?ǎCgKA0ڶmfǬy%0+B]^ukW!glCWWA=oBiZ̀j0>ǛO|$`]^FU3{#Pu*NBS̟?/8FAKK ;6mPxg8l,ZӑJŢE\uU8tΕpdCt2@k(AEG{}1 :ۑl=ΰm}ȯyvy|U%[z))a2ώUF rG8zZoEEE2&>S{?DI%'Us(4 O@ x} {eP^v*Q; ?zEu/o*xJE'PYZ Ub1p?@O p4Q;חZpK/}oܸqXt)<8}0m,91@Lf|3;h=cƜR)*>_fÝwcرc9tҠr< 6 ,kjj@v]wr8cA!=UQ̞]Q)>pg((-^3:\s5A@+1HՖ.]j&BՈcȈCH%k-3;nj' gZUt9}8p0ʊ@nnnWUo99XfU 1چ6olhG~keB>SnG?} )ehFP`w_r=@ Wt{ {񓧰gho?X gΜ͛-/"Ν;6i%FVJ+V]P[[W_} }[IDAT.D\\w N—;n7,f8(ns @)6W48N' .> nFww/4KS#ZZ5rXz?8S¹S?яf./1;5U)сxͮ|>z_'|E)=½l30#+..o~X?ԕlkkÓO>g"m,LZu$'%By;gguށH貐}5Q s{jˎR =_GUUn|Gx7ވBs?,={,>MZ 44െ}yyyXh(«hhކAbbG( 4mɓ'+ X`9 4-c"acBE3 *H6D%#*! +X8]1$I#T񠣽m- t]6θqj*̞=;䠍ipطo֯_o>\<#2c]]]Bgg͖:FA=Rx/xy̙3GHcEEEX~RRRO"%%%(`mݻQTTc HvpA5 ⃦xz)9999s&ϟ2We9kfرcy|֬Yx`󼹄AMM }]3k*wI"T=~ R=(b8'lhll+bL#[o-bΝ PUUU())Q[[:x<h$IeHMMEjj*rrr0~ ᄿk.kfֳ(q 7?ׯ7A;! 7}Ěs d/]n6,}xظq#}N> fΜi:_͝l]yy9?9ddd@oMM76Õ|5({3?A*p־.(tbJ_ٳfW}P :߃-\7p$I2O/T{/cC1C  p]w= tQQ^1117oPQQǃ>@[[kXByu;!(((ucyyyA#Ēzcx~.\Qg/0V&P)Şڳ*}}R@RJJ ƍg[GRTU_|;wkEnn.vȲln7^/ZZZP[[*TTT"0h"_x~Ap-0!\m4= @}(?vq@)222Q.p7668x |Bnĉ1c ́z?9|B\=?%bx &شepS0f} >jZCC(n7ުǙ~u$!jUUiny8B`ףB՗8WSח̅$ QCЈ.=sTۑ9v4P>Rlh3I(2H߼w}wz2F,DWV@Xב:W۱TYLM:(:x GCL [6CMY盵e/}4@BSF<Ϗy>eB"BA$I&8?aͰj' \ {/   bn? %B7#ߣ_mm$@;wmY)))#eYΑe9K<Ϗy>qt064-, k}5+TUICA}5Y!q*{4e$kBD}fu*A;*jЌ/;3~ڴi#㳝Ng$IY d<-B",Vaedmk#R6 i^v8Nx:[S7Vpr`쫐 hh()ġy/Wzo ZsnJJx75*;666reɲ%b&Y<=)cIL4koBi}(6}{'^sݎ(sD"s+޶ǏWZiٲ,Eq =XWiulV'^{_Ռve:fp#ç^DaKJJNGqSLLLLr\,g̑| dzckڭ'띰tҍf? XᒋH?7m%H|ƍ,IFźb-l68CMM9[K/4_Թ ✡v$y?}Y&v̙QQQ9v=KǍ8n$!$ żoڴ$cjq,G z~4ә#IE G=м'O~џ0p@1 ),*7I%pbR w.V2uT@D!z !H$FF*ld"L&(J#Jb0!"/"LDOoy$#! D HBE66Qs "*%CR!GhpMDh.uWJD!XGL&OBC] Q*P~7-ĵ7 G/x y~` }ND"3KP  6ރ1fΝ;c͚5ؾ}5%c3A:+V&O7nȑ#Xz5-[͛Xl͛ --bfeH  ؎SScΕH5֔6m`ݺuƅ ТE :uJt&|P y%ƀA&%ĹQI̮Crr2Wn۷oVZ8w\L ), $0niE֭vZ`NF݂+1rʳ\?ަrAAA5ky7I'`H$6Uj׮-:$ÔyJ@hٲ%֭[۳d<`T2< sDTAI$yѣK.(Sy|H RHlCa۶m__`dH *VrMEDs!{.yV-(TyDDK"q tU0Lk5(:߇FODR3 ŋǖ-[#B="n"HD]83":ga̘1w=t;v#aA%bDIGo%Q\9XyUеJ]QѹgԠڋAP بQ,ר-J5ӿ 11:u®]{AyHD ,` N^/yic~)Dd+۶m T.< 5EB*gKΝ;rEBD<%{]ѦP0&NrPD"6" D?XE(A냂i&lipQG3e]};vT.dBM+w,=Vk]w;Ή'̫@I = ]`R.LD%Q"zx<&^D%( œJRѢEwߡ}{Yn<;gUuj }Gx٩\LPQP( eSy A#G}qq옖"1DHDf%%|ED c!"S^P.?֬Y.K2%Z!?<3gP.nh+ d.S)L3q4i$/6mnݺeM[svGy bXtMGDc#44zyŋUY,:vX},X0hڴ)Uf-[սY`"*`O[.֭͛S=ҥKX`ϟ rf>%@Dox[tl„ xU.J"~|y8"i*?3fرca-ԶmЩS'ܿ(;٤0DFnPdIT\^^^8q\QuxW:MH̺cpv\2CHH;Jes 7nh"Euʪ9sW^>z SP oqU-ܵkW:u*o޼]fsDddd5k}eo{ s$qq˖-z_X `o82x=֞^|4ޮ_>^O<霕.\m۶qϞ=pSšg$_بQ#NNNfs=ʭZ5zߏQ4!222BUkiO1 " `lVI&hٲ%Zl~^^F׮]ѵkW={âEpUkyM0 ,QTr?k[,Zѿ\z[&P5ȟ-5y3ؾ8'x???ܻwOg$.'kΝ;mZjزe 7onμ$DYu#|0.\PJyQJj؇AȏfX+Eƍfظq#&Lzi\S\9L:/_͛ۺ$t(ٟ#5Hi_(@SE0 sAPYQ(a0%:ϢaCu+ Eɒ%1uTg&q=+>rO>DTSCRx!vBɩb|Iٳ?#v __eC^}v>|[n0upxIHDmh$V"GDbAv! ":ID{h}ND+D4 &ўzu|BD>Cv'NCB˖-{nL4Ũ~ȑ#$X,$<6/Q-ij$a)IᄈX%ʕÊ+Р1ԪU ?֬Yq̙3j`?%1#%e[8???DDD?~PBj*qV; `+-3?M@Q0|qn~kVSاhrrEFFhQ *СC(ok';X'@rrat ǎԩSjOP`-I1R'oĉ \ڴisΟ?ߌݻF&M U0A"z fdږjq֋y(tEّH˖-qIܹ3gDBBTŋf͚ԩ.\K.giJ^?E3\ PUti 6ᬝ^]^rD G{=<9uѿJi"E`ĉСz)`D43\(!ѬY3_~kǮ]rJKv쁠l0~_9 "r U*Q3[$>/D垲UےShQ4mM6}Ӹ uBBB^̢ߋ;Z/ !Saj<%4ؕ-[g1{a///^`#2n߾}p%_6YmpZ*_ޮ9KKKӧ[֠ d;8d>G*!@+o־j8vYW @eh^WZ>3D⠌Z?8L}g>˖-9[l-w0$"zJFnMbݺu G+°a5ɒ:F`` 4nGFV0JVQwfNsCD~AٱÌ0TZшAtt4bŊیƏ#FAVVVNqĉ~?ޞf3<̪Y<.WZ4ND% .TgF}@ys#w0@D4, sᜐiC3`swh]on!q:殘0a:tq]=ZtH&s6(w0Jwڵk͛7UyϞ=y裏 Xt){{{[[@Q6@IleLʕ+yѢE| f`矼xbP;@`ݥ@1H4W֭ˋp}QyNJ=F*P†NpI&\P^{5f*5dBFg?o.Axx8/Z/\3/_/cccEs Jqxݎ҇}||g`9Tҥ_ӧOk6ZƏ?T.{.Yyi^ ~[s^wtߝўS|}}Ν;\yi*x@5rppyzFpEhvؼy3"" 0aa~-Ny BDAD(F)R{Fbb"Ξ=C]*=*TRJž!Qs/ț<]ozz:vܙSRRˢ x"zYNf^+$ܹkM2"R%ظq#TW^oTѵkW^Z۱DΕ2 " KvNqq,[ mڴqJ6v-X`)Vaǚщ#[\K{2J? "z Q( ._Eغ55IIIP(e4εǵnh>.@6mx:򡓸Eڵk$ص[oW_}UcǎX~=y"*bə{5T'GFFbŊظq#ʕ+Z Pl7;);aM /q" PѼ>[UZ *:Y9P`6v,TaÆa_/۷[]Ct%[zz:;cǎExx#| `+E:Yb"; Kp1ٖM`H {0Uԩ&ʕ+sʕ9" 2~xżyɾ 0GZDID3Xu7Z\mʇmT GkQ9sܬY3Q xoٸ[Nz?;di(WO4>Zq=x\v-_UVBEi"kzz:[|I;.lu%r(C @=˩cIC*WXp;.]`Ν!C >Pugw)AA:>>>իWFq9<>T(NDt>|U.jpPvtÔcH=DEE7!C̅4k w[gϞm6(S ,X'⭷W_}S9QLd=ƢUVEnСCwur~C#3| Hw D[ܧO={… L}3h-]s BdF`E!VTl'& ~k0|x{{;U2j(ܿǷW3t3uTTbz),[ .ܺu KV:Z@D]Wn]߿G}f^N] riv֔APn]s`<ݡX i^z%l9tl~tiȽ{e˖jp=/\-Y0Ϟ=E2:dhTf***}]k?3E7ξ\dI>}`nj.4vƷrbbp]ׅA5~7fffC=dq9s\ u5'}{ l*D1 >Z‡?EDz>|8bQy,Q0lbQf&M*%aaE(rܹ35j_{5 .Ikb]v0T> ɘlfp IDAT7n>(ZlVU~3XnڪkWf@\aj@hh:!]3߆17|*.p=bk3%βŖy=sTk9@UVChh"`U1?E[ob1#R0v؁LCғwy+WzbXLЀD9ҥKI&uL n u(+PY} 0W@_Q豢`Tp)m۶9ʅTXXmۆի;WX#x-ry'-[bŊjC7a +g֎Šv|ȑ9}ofw䖈|h /a8#NK 츍;.DJAJJ ߯zMZZ~7yTnxbU@qXy6=<ږio^T- ]p(/^ܼZ*0<S&OZ+> kע]vJrpl߾ @&l"ZmP@Jϴ p>k^oK(U*T̤HE䖈jU8wiK#^z]wÅ̤~'ZMg[$LB`9aÆvp˖-Ec J"Zzs0GD_85۷X9P>%q"z JbWah3tj^ѪU+k;N#2mRu8`WFBe0)e+,"(;Q{G a w62T^![ ュKbРA̍Q"E`ժUԩű($%%EqDY%e:UoQM29}[4٫`ԬYŊYXWy*F^"|Q`kv[ L6\4 v*`jJR +W\{v\/FYp[l?( @?Xbzv2JFΝs겕lBS(wCAD"lDD9?(DTw ׯ/:d+{#TFU3H"Q$+m WGAҸjۛCTj0<Z8g^qe ԜwZ! ',r*t )._Xz5|C"rJtHJJJ#a:p7rŀ*ʕS5e߿. 3€> maQE]?l0x{<0eG-lJPHdl"&MEXk=ʗ/,F./X1WѢE~zU;S÷~={:"b)(p%U%=eW/al aa+9vD \ooo 2DmkL~BvW_X(n-2qBRRRο/]Ǐ[׼ys'J*¢`XBVV֯_/:d+a1aʑ#̣)a;D ?BH$ꈜH݄ӵ`:" {#$6E ]24oO |2>Ç WƠa3|n^1sL//Z8aH@EvRbGJW(Q[nE||KHKKG}cUZIyşn;Di;Z6hD*/?*JISSBʕ+mUuT%_{eJ(!FM'"?;M4Q1r[9ޜ?gvziiix7D2ۮ(Up{lT__߀ `Xr#)) uuz?>*Vc⣏>¼yޯ$_$W]V1܃oFTr8ryO}CCCʶ`+췰lٲpX&c Ɔ fB~"[)vەQ=ώGIf3o6~w=aѢ ڱ190ź/ Fc²ePjU >Wα{N_/vH]w^\HСѣGE?vpE 9322h"lҡӚ>}X;"ԔQ6S eն Ff/C rU%J8tT0܎+nݺΝ;NO>[t 0[UخpTչ&BÝ;wps9YkFBBNJKKSO=eZP/&seeeaݺu:Id\Tv/ظqCp1Ɩ9U0jժ%JJnn׹/[",,LYO̜ewCŊS-!1(̼\ӧOcǎt钦}gjWig: FLL[g,(x2)))h׮0NxAILLDÆ Oȑ#V={,f\IPj*=0,YYYꫯD,{0ۭ_~%ƍSEGV֭ ,UɯP?6CPtiԭ[vO'-- C ȑ#EA;,3gϞe{0 0*}}}yŊσrDc**wl7m۶[Pre=e<(ye6|}˗LJ߿޽{CBBl34iP[ήwp=j{#F{@vo2eϞ=dffrpp]k.u7n&G/'xΝ'OT״4޶mO4+Vhy[t @0m}٪deeqPP 0,Pǹxbѣܽ{w&"{^| @c焇 Fϟwعs)`)m68z1c|wL0!_mgsU})R^p~ ϯS]ϼܱcGiiizR>ڎ  *p|||/^Dz˙9!r`FCW̧(ťѣG~@^xFB*U_ +jГ,_Yi_oGȰ$΂S,4_p(iaҤIHMMچ5qj~T}ń 9Q)75j@ƍEvi[J#ݹ^z>>>/dqnrr{M{= ,y P;kܙ!QQHdьB 0}=@K/᭷k0n8aܹP2iD5Έ5̆Y6T 8PObb".]*:t;G*`d3m4o>q¶QLM~o)իWG&MծoB$}ԯ_EzT0<"HD( 7h/M$"f$Bo-eMgO`"1l1wUPq` /kƁ,2zʏE{?8ߺu r<#,ӧ;a˭[866VٟˋSRRTŋ9lw555/.ק~:&99Y5k֬ݻwoM6Lz!o=UV[HNMM[D>9iPvYѪzP;D "wͦ0`dJʮϜ9SL;VM`'ǘ=3tPPI`n:4hǎsI %_B^}U:dc7n\L%;c0ydDDD؝N?  F͛-b̍r޽pxLE4o{c|M^n;k׮mo} ;X1smSLL*11{2"0D``*8ikB" 8r!q>̼:蓻~޼y8}4||҆K. h3w8d^+"I&w0r<; ճs(VuA|||۵W1::FcDt@}ۥK?ks*ѰaCc^3___\IVV/_.:bQ\UYV BBBFuلK.ҥ %y0|Uk,4Y`fӈN`-rimvָ K,i]c_ Rs#w0`(yTekA!--r?~'ܛ;w[u֢gs-4^+cܨQ#ׯ=/ z֭[?3}c-b n֬=F=C9ylbŊJ)HB? tu%wlfNYo9 \fyvc~ pZA[URJ!..>}ظBYm' ,d;w&~5&66֮:)Smw,΄|SBƍk.$"}0<;jժ~H06f.Kff0Db6S +fJ޽ĜAXg:ô%̈́a20#$qoK/8W^yE-g0ڣ;bP=gΩ\2V^1yjVZشi֯_J*Y;ykP>1 @ZOS0rVr! DRXXvQ|yiKFTTg+֒i5feB̗|e^tR-/x}"xDDΝ#G[n ;wƑ#G $D5_g?// 0G;xgSfM8q"wUe"cjH$X:8 aFשּׁ,9dȑXbS~GѰaCg`^9f۷OSG{:6mBϞ=8"zJʢ}Ŝ9s\b|}}/_~2d֯_/:6DԔ H M͚5rU>PW}$H 3-<HP$Ν;8rjժt邌 ]fM7)mat%_~ ꫯ4&l2 8É("@5c~~~9s&yFbP*U k׮Żヒ7xYYA5k@1ji:(H&R`]-D""×+ͤ|||УG퍞={:mo&:dL`a7`ذaj 5k\\N JL_pŮ]FȆꫯbӦM(Y,5aFLLa $%H$yݳgr=ɢǻ *̜%5c/رc]/T!^?eX,g0mڴArr26lHЦMVǏaÆ]/pmtm۲^^^ܷo_޹s'gffj._6IIIܣG&%Msu`~vYYY'a׼qʇ]0`ml7on`zr^T #IpB;ʕ+*TD#33۷o T$,af<Ğ={0xE07p-L>}ܹ#,b_1DY5j85{pAlݺfͲ>|p̝;J^X%D^O !! 4@ҥ5?/R}"zWzaNR/b (8˗/ǔ)S,Ϙ9/)!]תU+lٲE'O>+?̼ղrp{NLII)RBbT⡘ 3~~~޽;w_|,Ycǎٺ|7Ԑ_=8vB^|GKa3f f͚ylذ!ك{Wի(ɾjԨvO:yFhѢhժo߮,"""0a9Es ݻ7kL2Gu|xGq9֛м|zaTfrÕ6rC;ew-Iz])hNk???޲e C[ϟ}߼y#fI2eD291g?Q844Ԟg@w !>*U/_y75mXbEll,J.G*V?yE:u Oŋ55e۲e vޭY{Jɒ%QłuufqW߰=@sPHCR80/ qbСC1j(y,lݺXXpB6>}YfNè[zP`111A5oRH$pJMkHC &GPQ.jժcǢw2YgΜ%K?](_8ppjCJ0tP 0aaaNO"H$˿j,h EcРAR($ܽ{97o8Lɞ ށ?SS%%%y睜svJq.VdFG`?AL$~p{] SL쏟1"#y~wwa;&L`ܸqY7xy1a„t |/FM\ N5&U(Ц1d1"#YnM7ܹsnpr-~I8 !CV`}v!{HmKV`"hALT3fԨQ 7{lFMuuuu5n(I0RV`t=9$^PՔHOr0NU?O@PLTէjD#0KDfǙL \Dl؆ 5j3f`С-cEIw i#Mc=v]K$?f ^}Ue6\8,vֵX{`dhl+s@xliw ȣɯJKiEƳ@ߦ_#GCM}qڊhw𽜰v"7p;pT Y|WUF,&)*"PDkd߂7c`v@Dȉ&&Tu^1cׯgĈ̟?[xu*< 0BB&bXH Ņo\OP40ODDYwBypnXUU#F嗿hEhq]`Tu(( uos6x>SLEFH`݄=5pڸKtڥc֭cĈrmp SpDppq>NYHMU?xE6֮]˱˖-[k¥cDd quGD:3E7V3>MDpCRD 2řu2ED  ^"0En}֮]bŅSCEz@ȱao_| K#DdqE$HD7C'YP"{z;a T o>96Y!"Ǜɮͦ/ `Wշn\Dʁ2]HU i&nݺq'3ydT56 B۶m3gNL;XDvTՕKR`t loRΒo"rn7dNDGuoo:ھ?}'rluzokj Bh] ey`g޽;wqgqƍcŊoii)W^y%W_}5'N# ؋;R`"!qp`Ác SwwFD^+6P5jݠEC"iT6+01bǏk} H>kd2+0'LEx\+\ |B_ATɒ9#ђ>Awy&_:0Mzә5kW^_>={rssI'QVfWf;b~L")}d}a< E@7ą'uJ/~ظE亀s`z1Юɿ3 bB6l0 մoߞ805!Zp{n/vl)8`pwرc[b< QDxx7?Ѥŧyoݛ@Hg_X7)2 }`Pǎ(noYŎ0""gSɢ}ii)SNM6L2%l!:h+"RZa\=xV pU-+[bKDV8oy=~VHoU,2;zdD/~G|嗔rԓ\VD~ES_E[12Au-`w0L8nr[RRwD38x\4c x +.gt}. ~tI.l*"7g.m}|yT__ϬYR>Pe.53j_DN- Q|$[V`D-N{VD\hO< -H{8 __7V-J~鼾W^*K'_5)/ 626b {"m *"tM\|sq폂%" l qq!"{ȩdJN &2"T  $" ݢoSO=PVu)">ğݹXb^2"cT䘈*"tkgTkmѫo *B!ߙZ޵?F#"rdXm_|>p=.8456mrw[ao QhDD s~kE4K]{\sMw<`d3SJ BkqѨ-/J`|6d!R)뛟\ A~AVVK7$bADW\8k]9sys]o ޵6L"RbڬY~l(i3,b?M5\I':Ff̘W\:FR] 2gΜ.^uUmۖ+Lܸ^dA![aq^]R<oV>_9MDTn>ӓEWK\ @"2!@o]!gi؊LF/2q1pȠ IDATY 3ſc:3&-Bj8F>}0nl:o0믿NN-_5j/殻}7D'WA!"/\Y,Z8oj8w U`3|^GXCɲ.w3|xc-88?vsxpgꭷ>wY},Tzu8>wnѪ.}8Ø&Mآ:*q3IDDEd q$"d]\4<'";GHXabODNMa/H>W]:GH^IqoE'Y?%X^&$6Y~ϥY>?,pAq6Qkq?DOd[`İ{TsT:u8ޏ-M}L )++ tx3*I'QҖFv,rEj8 ~h6QH6W"-0ٜe[ᝌIרF=7,'ڲex2~~xxV$Y03}G e)c0ޢɬeee%]tХK;vСC.SLI٦>5~7lܸqkTխ"}2gWn LXD&<6 u[ "[U?<0B^.x][O1> ցx磱kZ<ˊ/Z_$6~i޻| ロvfȀBh soO; oaDoO2IU=-]nalZ\4?ߑrṇWr|}3h 9]eRqHgiHBrEID+`ĺ8sw_fM3fV [ $ri8uts D) Ep @ff_ i&) U};Wf…>/_Dpw"b}^ZZīiUVV$Lp%vJR?MBqJxKŀ|Ҵ~s*0Z!";ɣ>|JFEd"04"_Q/h%T75Y+);[&#򿂿&OVvyfƕ+p {Rw:@(*='֭+'w5lkOLJSq0ob:WD$ p J_<`NyAIDaH xhkXdݣDd?Q/ ?<뱄LOےCD,iCryH.0V^ AZrelW)uy8uuV]D/[0MDnD/D%t5Q;+!"Cy̤K/N'^ܳVSSË/z}و "u@U.0/_/ZjU"@ įc!M'NE@+NN揵_ᒀD3vPLB󩪪8M(g3Ƨ$m!"}Yfh?rFf K&c݅hÆ H,_{cb{'t%+&!z4? InUU3 Ptӂg\HtBU\0vØw'å/1Z8GbY`\rG"Pwixs~%ɭ[B!Nx V`?]Ѯ]3DaÆ Du0xE[^kTu01 &wv#sW3p%aɐnQ+ce!v`qĮشiӾ3DAUuQ@؃@?Uh$੐3,q"1+MǍW>Ƙ H7`W퀛o +0֭[uLR @(޴ryQ |XB..me־H 7Α1Ed<7t*0"쌷2/"E.:ǪիWwr#*:u:CTT`NNVS"+9bQU}u|Q\v6`2u J"r@i \ )"OX>~סP^^~ QNו)UUj>wU}[DWBgݤq?Y-0+T5q""szV8Ns⍳{ED9Q =zêP|fׁ1z2P[UoGϙ<'Z(W?;r]Y,\TuxӢuEO"ulĪ/խS)ީo+R5^Mpo@6P፵)v$8,Y,\tV`$, "oedś"2uLŪX~}_VQQQTšS՛UJœ_UN k&o\iu^L\ocI2u% xh71Iĺ^)0Ddʕ\Zݏrةx3\-]B<3&.2UeZ$RL^Ww] p%"m]iInV[[ڢ"' ,"r1pCLWՋE\^ƱoHuH%O`(A;]DN;〕+ er̭Yf) 1I׹aB:RbQ`"2HL?"Axp%$GsE8.;둮3P[[[:1D͟9@]ԸaҺLU7/it)#CxkMK}ݗ^x:v'mڴᢋ.bŊL:>}Щ2&Mģ>Jn+Sy84A._]pw"W^E4宏mnd]vٖ17 x-m5@[Ƿc_ܒ*͛쳏S7/֦6mڤ&Mvy>}ܹsWVV,s\|/c8va>}{"׭ -p0D~-CY>c>97d kmc{xc\oZ`Gy睝3fhK֬Y&LΝ;GB/2]fvJKKO]?G6MuUeС`8oK]ۼ w{p0K@W)cޝ< Tf3\Wt}p<1͛o~vU RfIgƍ:yd=#BX^^]tX"mJ\ 7`n ~-Jo Ux/6x\i6~?%zb)-0M#)7ŀ3 vghF>9̅Fz}SNѮ]uQGuӦM-fŋu„ ڷo@oΝ /O> "8?0 kqNtz\\1T={V@8Pނ5.%ʀnMMOB$l,ǯFrw(g&T\\?;e…:}kգ>Z+**2~zvx/k]]]ҥKuz9讻1.ә3gjmm/18Aow-tE㌈ljhhpõ/W^ub%"݁=]g ٶtؖjmEh"&M@ii)}af˗oV\ISoZee%;;;3:ubҥ{|l޼9\ f=`2dƲe˸+\Lj/u'D[Bd:a7f̕xZ}}=K,aɒ%<䓮lc͚5Y7xu$nәq:9/0/__:qĿjBc1ƘLD/qr0KDfQa1cdu3"x+.1cb)*qc19Jf]LDdp&1m۶+jkk y Djkk;?c1))Røp&S6o,[ꯁ_G?)F s"6s1ƘYaR)ƺ`bk#O` 0KUX+ TLJLbV5'HBbi=LS < Rq:ӊUYU&2oDf0o3h p S)Z:TR[z9jԣ/ݦ2Ƙ89qN 'uJ S@=gw)"8 P1&du$0 d ,U4MSumm"0TxucwL!#3_`|tpN?2%Uo6IDAT6_۸qQfծ4sډNT"2(u5z &vf&gW:@crS c1Ƙ oc1cL`0c1 c1cL`0c1 c1cL`0c1 c1cL`0c1 c1cL`0c1 c1cL`0c1 c1cL`?+($;IENDB`chessx-1.0.0/src/quazip/quagzipfile.h000644 001750 001750 00000001746 12223260306 020406 0ustar00niklasniklas000000 000000 #ifndef QUAZIP_QUAGZIPFILE_H #define QUAZIP_QUAGZIPFILE_H #include #include "quazip_global.h" #include class QuaGzipFilePrivate; class QUAZIP_EXPORT QuaGzipFile: public QIODevice { Q_OBJECT public: QuaGzipFile(); QuaGzipFile(QObject *parent); QuaGzipFile(const QString &fileName, QObject *parent = NULL); virtual ~QuaGzipFile(); void setFileName(const QString& fileName); QString getFileName() const; virtual bool isSequential() const; virtual bool open(QIODevice::OpenMode mode); virtual bool open(int fd, QIODevice::OpenMode mode); virtual bool flush(); virtual void close(); protected: virtual qint64 readData(char *data, qint64 maxSize); virtual qint64 writeData(const char *data, qint64 maxSize); private: // not implemented by design to disable copy QuaGzipFile(const QuaGzipFile &that); QuaGzipFile& operator=(const QuaGzipFile &that); QuaGzipFilePrivate *d; }; #endif // QUAZIP_QUAGZIPFILE_H chessx-1.0.0/src/database/filter.cpp000644 001750 001750 00000022341 12223260306 020133 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005 Ejner Borgbjerg * * (C) 2006 William Hoggarth * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "database.h" #include "filter.h" #include Filter::Filter(Database* database) { m_database = database; m_count = m_database->count(); m_vector = new QVector(m_count, 1); m_cache.first = m_cache.second = -1; m_gamesSearched = 0; m_searchTime = 0; } Filter::Filter(const Filter& filter) { m_vector = new QVector(filter.intVector()); m_count = filter.m_count; m_cache.first = m_cache.second = 0; m_gamesSearched = 0; m_searchTime = 0; } Filter& Filter::operator=(const Filter & filter) { if(this != &filter) { delete m_vector; m_vector = new QVector(filter.intVector()); m_count = filter.count(); m_cache = filter.m_cache; m_gamesSearched = 0; m_searchTime = 0; } return *this; } Filter::~Filter() { delete m_vector; } Database* Filter::database() { return m_database; } void Filter::set(int game, int value) { if((game >= size()) || (gamePosition(game) == value)) { return; } if(value && !contains(game)) { m_count++; } else if(!value && contains(game)) { m_count--; } (*m_vector)[game] = value; } void Filter::setAll(int value) { m_vector->fill(value); m_count = value ? size() : 0; m_cache.first = m_cache.second = -1; } bool Filter::contains(int game) const { if(game < m_vector->count()) { return (m_vector->at(game) != 0); } return false; } int Filter::gamePosition(int game) const { return m_vector->at(game); } int Filter::count() const { return m_count; } int Filter::size() const { return m_vector->size(); } int Filter::gameToIndex(int index) { if(index > size() || index < 0 || !contains(index)) { return -1; } if(index < size() / 2) { int count = 0; for(int i = 0; i < index; ++i) if(contains(i)) { ++count; } return count; } else { int count = m_count - 1; for(int i = size() - 1 ; i > index; i--) if(contains(i)) { count--; } return count; } } int Filter::indexToGame(int index) { if(m_cache.first == index) { return m_cache.second; } m_cache.first = index; if(index < m_count) { if(index < m_count / 2) for(int i = 0; i < size(); ++i) { index -= contains(i); if(index < 0) { m_cache.second = i; return i; } } else for(int i = size() - 1 ; i >= 0; i--) { index += contains(i); if(index >= m_count) { m_cache.second = i; return i; } } } m_cache.second = -1; return -1; } int Filter::previousGame(int current) const { if(!m_count) { return -1; } for(int i = qBound(-1, current, size()) - 1; i >= 0; i--) if(contains(i)) { return i; } return -1; } int Filter::nextGame(int current) const { if(!m_count) { return -1; } for(int i = qBound(-1, current, size()) + 1; i < size(); ++i) if(contains(i)) { return i; } return -1; } void Filter::resize(int newsize, bool includeNew) { for(int i = newsize; i < size(); ++i) // Decrease count by number of removed games if(contains(i)) { m_count--; } int oldsize = size(); m_vector->resize(newsize); // Set new (uninitialized games) to 'includeNew' value. for(int i = oldsize; i < newsize; ++i) { (*m_vector)[i] = includeNew; } if(includeNew) { m_count += newsize - oldsize; } } void Filter::reverse() { m_count = size() - m_count; for(int i = 0; i < size(); ++i) { if(m_vector->at(i)) { (*m_vector)[i] = 0; } else { (*m_vector)[i] = 1; } } } const bool ops[4][2][2] = { { {0, 0}, {0, 1}} /* And */, {{0, 1}, {1, 1}} /* Or */, {{0, 1}, {1, 0}} /* Xor */, {{0, 0}, {1, 0}} /* Minus */ }; void Filter::join(const Filter& filter, Operator op) { if(filter.size() != size()) { return; } m_count = 0; for(int i = 0; i < size(); ++i) { (*m_vector)[i] = ops[op][contains(i)][filter.contains(i)]; m_count += contains(i); } } QVector Filter::intVector() const { return *m_vector; } void Filter::executeSearch(Search& search) { for(int searchIndex = 0; searchIndex < size(); ++searchIndex) { set(searchIndex, search.matches(searchIndex)); } } void Filter::executeSearch(Search& search, Search::Operator searchOperator) { for(int searchIndex = 0; searchIndex < size(); ++searchIndex) { if((searchOperator == Search::And) && contains(searchIndex)) { set(searchIndex, search.matches(searchIndex)); } if((searchOperator == Search::Or) && !contains(searchIndex)) { set(searchIndex, search.matches(searchIndex)); } } } void Filter::executeQuery(Query& query) { QVector > filterSearches; QVector > searches; int filterSearchCount = 0; int searchCount = 0; QTime t; t.start(); m_gamesSearched = 0; m_triStateTree = TriStateTree(query); /* Make a list of all searches, filter searches separately */ int leafNode = 0; for(int element = 0; element < query.count(); ++element) { if(query.isElementSearch(element)) { if(query.search(element)->type() == Search::FilterSearch) { filterSearches.append(QPair < FilterSearch, int > (*static_cast < const FilterSearch * >(query.search(element)), leafNode)); } else { searches.append(QPair < Search*, int >(query.search(element), leafNode)); } ++leafNode; } } filterSearchCount = (int) filterSearches.size(); searchCount = (int) searches.size(); /* Iterates through all games in the database. * Don't worry, a search won't be performed unless necessary */ for(int searchIndex = 0; searchIndex < size(); ++searchIndex) { m_triStateTree.clear(); /* Add filter searches to tree. This could solve the tree in certain cases * making it unecessary to call searchGame() */ if(filterSearchCount) { for(int search = 0; search < filterSearchCount; ++search) { if(m_triStateTree.setState(filterSearches.at(search).second, filterSearches.at(search).first.contains(searchIndex))) { /* This means the tree evaluated to true */ break; } } /* So if the filter(s) wasn't enough to solve the tree, * lets see what we can find in the game */ if(m_triStateTree.state() == TriStateTree::Unknown) { for(int search = 0; search < searchCount; ++search) { if(m_triStateTree.setState(searches.at(search).second, searches.at(search).first->matches(searchIndex))) { break; } } ++m_gamesSearched; } } else { /* If the query is not combined with this or any other filter * there is no way the tree could have been solved, so just check the game */ for(int search = 0; search < searchCount; ++search) { if(m_triStateTree.setState(searches.at(search).second, searches.at(search).first->matches(searchIndex))) { break; } } ++m_gamesSearched; } /* Update the filter with the result of the tree */ set(searchIndex, m_triStateTree.state() == TriStateTree::True); } m_searchTime = t.elapsed(); } int Filter::gamesSearched() const { return m_gamesSearched; } int Filter::searchTime() const { return m_searchTime; } chessx-1.0.0/src/quazip/quacrc32.h000644 001750 001750 00000001000 12223260306 017470 0ustar00niklasniklas000000 000000 #ifndef QUACRC32_H #define QUACRC32_H #include "quachecksum32.h" ///CRC32 checksum /** \class QuaCrc32 quacrc32.h * This class wrappers the crc32 function with the QuaChecksum32 interface. * See QuaChecksum32 for more info. */ class QUAZIP_EXPORT QuaCrc32 : public QuaChecksum32 { public: QuaCrc32(); quint32 calculate(const QByteArray &data); void reset(); void update(const QByteArray &buf); quint32 value(); private: quint32 checksum; }; #endif //QUACRC32_H chessx-1.0.0/data/images/home.png000644 001750 001750 00000003517 10622422464 017435 0ustar00niklasniklas000000 000000 PNG  IHDR szzgAMAOX2tEXtSoftwareAdobe ImageReadyqe<IDATXõWyPUU>-daQSY543RhMJAn؂l*OIKPɃC@T>Ѐ'=ɴYws}g+[FDEw(`HB -Bbe'ˁh5Jɛg!`GO2J8sX;5@ֈ#"s<)9 x;rv.DNtFhxp;"h\ HO-e8'c\p@ߍ$X (=_TR /``Xͧ"ޅ6I&."BbtJ`O OmDQ %qCwC_۳>3kGm]zd5^Bd,N"@MD@s,N&rvK#Dx>1Qӷ<1Y<\ₖ#h9쁦cpɄh *Yt_=Mw $P=bddow5I0dzJ\5tV3 : \݃rJlAܿt1Vݤ7=(Ǣ`g1\lŋI@ӝC]M#NWRun8q/FB:ry;i4jUgjhWoC*m J(o8 i?xIENDB`chessx-1.0.0/src/database/tristatetree.cpp000644 001750 001750 00000021130 12223260306 021360 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 William Hoggarth * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "tristatetree.h" TriStateTree::TriStateTree() { m_state = Unknown; m_nodeCount = 0; m_nodes = 0; m_leafCount = 0; m_leafs = 0; } TriStateTree::TriStateTree(const Query& query) { m_state = Unknown; m_nodeCount = query.count(); m_nodes = new Node[m_nodeCount]; m_leafCount = 0; m_leafs = new Node*[m_nodeCount]; Node** nodeStack = new Node*[m_nodeCount]; int stackTop = -1; for(int element = 0; element < m_nodeCount; element++) { if(query.isElementSearch(element)) { /* search == leaf node, add to stack & add to list of leaf nodes */ m_nodes[element].m_state = Unknown; m_nodes[element].m_operator = Search::NullOperator; m_nodes[element].m_parent = 0; m_nodes[element].m_leftChild = m_nodes[element].m_rightChild = 0; nodeStack[++stackTop] = &m_nodes[element]; m_leafs[m_leafCount++] = &m_nodes[element]; } else { /* operator == branch node, pop children off stack & add to stack */ m_nodes[element].m_state = Unknown; m_nodes[element].m_operator = query.searchOperator(element); m_nodes[element].m_parent = 0; if(m_nodes[element].m_operator == Search::Not) { m_nodes[element].m_rightChild = 0; } else { m_nodes[element].m_rightChild = nodeStack[stackTop--]; m_nodes[element].m_rightChild->m_parent = &m_nodes[element]; } m_nodes[element].m_leftChild = nodeStack[stackTop--]; m_nodes[element].m_leftChild->m_parent = &m_nodes[element]; nodeStack[++stackTop] = &m_nodes[element]; } } delete[] nodeStack; //stack should now be empty Q_ASSERT(stackTop == 0); } TriStateTree::TriStateTree(const TriStateTree& tree) { //assign data members m_state = tree.m_state; m_nodeCount = tree.m_nodeCount; m_leafCount = tree.m_leafCount; //copy nodes m_nodes = new Node[m_nodeCount]; m_leafs = new Node*[m_nodeCount]; for(int node = 0; node < m_nodeCount; node++) { m_nodes[node].m_state = tree.m_nodes[node].m_state; m_nodes[node].m_operator = tree.m_nodes[node].m_operator; if(tree.m_nodes[node].m_parent) { m_nodes[node].m_parent = m_nodes + (tree.m_nodes[node].m_parent - tree.m_nodes); } else { m_nodes[node].m_parent = 0; } if(tree.m_nodes[node].m_leftChild) { m_nodes[node].m_leftChild = m_nodes + (tree.m_nodes[node].m_leftChild - tree.m_nodes); } else { m_nodes[node].m_leftChild = 0; } if(tree.m_nodes[node].m_rightChild) { m_nodes[node].m_rightChild = m_nodes + (tree.m_nodes[node].m_rightChild - tree.m_nodes); } else { m_nodes[node].m_rightChild = 0; } } for(int node = 0; node < m_leafCount; node++) { m_leafs[node] = m_nodes + (tree.m_leafs[node] - tree.m_nodes); } } TriStateTree& TriStateTree::operator=(const TriStateTree & tree) { if(this != &tree) { //assign data members m_state = tree.m_state; m_nodeCount = tree.m_nodeCount; m_leafCount = tree.m_leafCount; //copy nodes Node* nodes = new Node[m_nodeCount]; Node** leafs = new Node*[m_nodeCount]; for(int node = 0; node < m_nodeCount; node++) { nodes[node].m_state = tree.m_nodes[node].m_state; nodes[node].m_operator = tree.m_nodes[node].m_operator; if(tree.m_nodes[node].m_parent) { nodes[node].m_parent = nodes + (tree.m_nodes[node].m_parent - tree.m_nodes); } else { nodes[node].m_parent = 0; } if(tree.m_nodes[node].m_leftChild) { nodes[node].m_leftChild = nodes + (tree.m_nodes[node].m_leftChild - tree.m_nodes); } else { nodes[node].m_leftChild = 0; } if(tree.m_nodes[node].m_rightChild) { nodes[node].m_rightChild = nodes + (tree.m_nodes[node].m_rightChild - tree.m_nodes); } else { nodes[node].m_rightChild = 0; } } for(int node = 0; node < m_leafCount; node++) { leafs[node] = nodes + (tree.m_leafs[node] - tree.m_nodes); } delete[]m_nodes; m_nodes = nodes; delete[]m_leafs; m_leafs = leafs; } return *this; } TriStateTree::~TriStateTree() { delete[] m_nodes; delete[] m_leafs; } TriStateTree::State TriStateTree::state() const { return m_state; } TriStateTree::State TriStateTree::state(int leaf) const { if(leaf < m_leafCount) { return m_leafs[leaf]->m_state; } else { return Unknown; } } int TriStateTree::leafCount() const { return m_leafCount; } TriStateTree::State TriStateTree::setState(int leaf, bool state) { if(leaf < m_leafCount) { m_leafs[leaf]->m_state = State(1 + state); if(m_leafs[leaf]->m_parent) { m_state = update(m_leafs[leaf]->m_parent); } else { m_state = m_leafs[leaf]->m_state; } } return m_state; } TriStateTree::State TriStateTree::setState(int leaf, State state) { if(leaf < m_leafCount) { m_leafs[leaf]->m_state = state; if(m_leafs[leaf]->m_parent) { m_state = update(m_leafs[leaf]->m_parent); } else { m_state = m_leafs[leaf]->m_state; } } return m_state; } void TriStateTree::clear() { m_state = Unknown; for(int node = 0; node < m_nodeCount; node++) { m_nodes[node].m_state = Unknown; } } TriStateTree::State TriStateTree::update(Node* node) { State oldState = node->m_state; State leftState, rightState; leftState = node->m_leftChild->m_state; if(node->m_rightChild) { rightState = node->m_rightChild->m_state; } else { rightState = Unknown; } switch(node->m_operator) { case Search::Not: switch(leftState) { case Unknown: node->m_state = Unknown; break; case False: node->m_state = True; break; case True: node->m_state = False; break; } break; case Search::And: if(leftState == False || rightState == False) { node->m_state = False; } else if(leftState == Unknown || rightState == Unknown) { node->m_state = Unknown; } else { node->m_state = True; } break; case Search::Or: if(leftState == True || rightState == True) { node->m_state = True; } else if(leftState == Unknown || rightState == Unknown) { node->m_state = Unknown; } else { node->m_state = False; } break; case Search::Remove: if(leftState == False || rightState == True) { node->m_state = False; } else if(leftState == Unknown || rightState == Unknown) { node->m_state = Unknown; } else { node->m_state = True; } break; default: break; } //only update parent node, if this node's state has changed if(oldState != node->m_state) { if(node->m_parent) { return update(node->m_parent); } else { return node->m_state; } } else { return m_state; } } chessx-1.0.0/src/gui/helpbrowser.cpp000644 001750 001750 00000000773 12223260306 020227 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "helpbrowser.h" #include HelpBrowser::HelpBrowser(QWidget *parent) : QTextBrowser(parent) { setOpenExternalLinks(true); loadResource(QTextDocument::StyleSheetResource, QUrl(":/help/about.css")); setSource(QUrl("qrc:/help/about0.html")); } chessx-1.0.0/data/images/go_down_black.png000644 001750 001750 00000012517 12155032667 021302 0ustar00niklasniklas000000 000000 PNG  IHDR88; CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs11(RtIME< IDATh{?NC ""`!ńhXPCR+"ZFʨ@*/V$B$AS@ȃRjT*C 0 Q^}lٙۃb7s׹닼$Ak Hr!/;_zY Cs*p:4uXT,GtPL@Y2Esa1՛--P:EXb S~_ mB'>cͰs/H2[o[P2Q,^A*t>Wªm>عZWb&֓'e>wKzyX@7`x?,;od$of lu ӬXf~ib"^EFwc炀Tap sWn\gE7zBq@Q.L^}Nb +PIwli|!hSpP<%K =~V΄zOT]+nk#erQӀ(ԖtaUUF.R/^2a60nh) J@ƀ(8vVr=J Fr(Q&^Oäe z6-Ts¡+p H'e:āVM~0-6gMClt6/Ṧ<~_<6,fk{rWa#قzV=GwG L{Q&>㥠x}ܲ`5!0=X ꎚqRк7e˯(` #9gfk5yݷh{/쭁/ba$dF {})~QKo' lcVlxQajHr׷p0麡w=?PK:)?WN)V\|IIй/I>ħ`*(M蕵fn GCnZrC#+edmX̔+c`tcNxHnN߄l9^שM)q&ʤC+`^:~ө髆e '|I@$lXFiтi:7j7C+!( T V`;bN Z4mC[\܏gߥ]xywwx8p)z;iw0W_Z$~"U_⵮E؆(݁]hJNz{;P쨁qfQp'=v5sX_l۠U֠àD#RIt(_US,_=uɣ`p0WDSEyi`qŰ0`.5qxa9l_K|$BL.>zr)&>\ ^n.ۊ*TPmn V}_dšW?ضԛH=zZc?p9틠eS9Xˮ.S! .3v_3(Ö,oA1!( 6KZ uPD׿잾3'.T`m;•q_uX7nشz=rI"ꐮ}gs~sZ+[[-{c%? l#N}bWM<ˑST|ݶl=UbY,3ZWۥ+C@F|x(|[6Tg߸̚€ #vAd6m/>_[w!,+f".Ȣ=AϦ6n>\vk' -SXPY6ݴsdpE(19[ER=lT?86>O r@6oj5LnO%[<Fe0QʕUp0Ofv32C?O[6/:Q,ڌAHxBZ6+7{M,)~6/tySUq:#7@5=|@"|ul!T@Ʒ}ڃ[2x*ZAҽ32KJ K oفwrS:cIiajK:5Jh ؊m3=]|H43XfkԔ$9 ):R2W^hf {K' fn 42u] *P)+nn)T SMϞ]/I &@IENDB`chessx-1.0.0/src/gui/preferences.cpp000644 001750 001750 00000051726 12232012570 020176 0ustar00niklasniklas000000 000000 /*************************************************************************** preferences - Preferences dialog ------------------- begin : Thu 18 Aug 2005 copyright : (C) 2005 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "colorlist.h" #include "preferences.h" #include "settings.h" #include "messagedialog.h" #include "engineoptiondialog.h" #include "downloadmanager.h" #include #include #include #include #include #include #include #include #include #include #include int PreferencesDialog::s_lastIndex = 0; PreferencesDialog::PreferencesDialog(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f) { ui.setupUi(this); #ifndef Q_WS_WIN ui.engineProtocolWinBoard->setText(tr("XBoard")); #endif connect(ui.okButton, SIGNAL(clicked()), SLOT(accept())); connect(ui.resetButton, SIGNAL(clicked()), SLOT(slotReset())); connect(ui.cancelButton, SIGNAL(clicked()), SLOT(reject())); connect(ui.applyButton, SIGNAL(clicked()), SLOT(slotApply())); connect(ui.engineList, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), SLOT(slotSelectEngine(QListWidgetItem*, QListWidgetItem*))); connect(ui.engineName, SIGNAL(textChanged(const QString&)), SLOT(slotEngineNameChange(const QString&))); connect(ui.addEngineButton, SIGNAL(clicked(bool)), SLOT(slotAddEngine())); connect(ui.deleteEngineButton, SIGNAL(clicked(bool)), SLOT(slotDeleteEngine())); connect(ui.engineUpButton, SIGNAL(clicked(bool)), SLOT(slotEngineUp())); connect(ui.engineDownButton, SIGNAL(clicked(bool)), SLOT(slotEngineDown())); connect(ui.directoryButton, SIGNAL(clicked(bool)), SLOT(slotSelectEngineDirectory())); connect(ui.commandButton, SIGNAL(clicked(bool)), SLOT(slotSelectEngineCommand())); connect(ui.browsePathButton, SIGNAL(clicked(bool)), SLOT(slotSelectDataBasePath())); connect(ui.engineOptionMore, SIGNAL(clicked(bool)), SLOT(slotShowOptionDialog())); connect(ui.tbUK, SIGNAL(clicked()), SLOT(slotChangePieceString())); connect(ui.tbGermany, SIGNAL(clicked()), SLOT(slotChangePieceString())); connect(ui.tbFrance, SIGNAL(clicked()), SLOT(slotChangePieceString())); connect(ui.tbPoland, SIGNAL(clicked()), SLOT(slotChangePieceString())); connect(ui.tbSymbolic, SIGNAL(clicked()), SLOT(slotChangePieceString())); connect(ui.btLoadLang, SIGNAL(clicked()), SLOT(slotLoadLanguageFile())); restoreSettings(); // Start off with no Engine selected ui.engineEditWidget->setEnabled(false); ui.tabWidget->setCurrentIndex(s_lastIndex); ui.btLoadLang->setEnabled(false); ui.cbLangServer->setEnabled(false); if(AppSettings->getValue("/General/onlineVersionCheck").toBool()) { QUrl url = QUrl(QString("http://chessx.sourceforge.net/translations/dict.txt")); downloadManager = new DownloadManager(this); connect(downloadManager, SIGNAL(downloadError(QUrl)), this, SLOT(loadFileError(QUrl))); connect(downloadManager, SIGNAL(onDownloadFinished(QUrl, QString)), this, SLOT(slotFileLoaded(QUrl, QString))); QString path = AppSettings->getTempPath(); downloadManager->doDownloadToPath(url, path + "dict.txt"); } else { ui.labelLoadStatus->setText(tr("For updating translations online version checking needs to be enabled.")); } } PreferencesDialog::~PreferencesDialog() { } void PreferencesDialog::done(int r) { QDialog::done(r); close(); } void PreferencesDialog::closeEvent(QCloseEvent*) { AppSettings->setLayout(this); } void PreferencesDialog::slotSelectEngineDirectory() { QString dir = QFileDialog::getExistingDirectory(this, tr("Select engine directory"), ui.engineDirectory->text(), QFileDialog::ShowDirsOnly); if(QDir(dir).exists()) { ui.engineDirectory->setText(dir); } } void PreferencesDialog::slotSelectDataBasePath() { QString dir = QFileDialog::getExistingDirectory(this, tr("Select databases folder"), ui.defaultDataBasePath->text(), QFileDialog::ShowDirsOnly); if(QDir(dir).exists()) { ui.defaultDataBasePath->setText(dir); } } void PreferencesDialog::slotAddEngine() { QString command = selectEngineFile(); if(command.isEmpty()) { return; } QString name = EngineData::commandToName(command); if(name.isEmpty()) { name = tr("New Engine"); } EngineData data(name); data.command = command; engineList.append(data); ui.engineList->addItem(name); ui.engineList->setCurrentRow(engineList.count() - 1); } void PreferencesDialog::slotSelectEngineCommand() { QString command = selectEngineFile(ui.engineCommand->text()); if(!command.isEmpty()) { ui.engineCommand->setText(command); ui.engineName->setText(EngineData::commandToName(command)); } } void PreferencesDialog::slotDeleteEngine() { int row = ui.engineList->currentRow(); if(row >= 0) { // Looks like it should crash, but it first removes // the item, then it updates it by slotSelectEngine (which is obsolete) // and only then it deletes it and removes the data QListWidgetItem *del = ui.engineList->takeItem(row); delete del; engineList.removeAt(row); } } void PreferencesDialog::slotEngineNameChange(const QString& name) { if(ui.engineList->currentItem()) { ui.engineList->currentItem()->setText(name); engineList[ui.engineList->currentIndex().row()].name = name; } } void PreferencesDialog::slotEngineUp() { int index = ui.engineList->currentIndex().row(); if(index > 0) { engineList.swap(index, index - 1); QListWidgetItem* item = ui.engineList->takeItem(index - 1); ui.engineList->insertItem(index, item); } } void PreferencesDialog::slotEngineDown() { int index = ui.engineList->currentIndex().row(); if(index < ui.engineList->count() - 1) { engineList.swap(index, index + 1); QListWidgetItem* item = ui.engineList->takeItem(index + 1); ui.engineList->insertItem(index, item); } } void PreferencesDialog::updateEngineData(int index) { if(index < 0 || index >= engineList.count()) { return; } engineList[index].name = ui.engineName->text(); engineList[index].command = ui.engineCommand->text(); engineList[index].options = ui.engineOptions->text(); engineList[index].directory = ui.engineDirectory->text(); engineList[index].protocol = ui.engineProtocolWinBoard->isChecked() ? EngineData::WinBoard : EngineData::UCI; } void PreferencesDialog::slotSelectEngine(QListWidgetItem* currentItem, QListWidgetItem* previousItem) { int previous = ui.engineList->row(previousItem); int current = ui.engineList->row(currentItem); if(previous != -1) { updateEngineData(previous); } if(current != -1) { ui.engineEditWidget->setEnabled(true); // Fill edit fields with data for selected engine ui.engineName->setText(engineList[current].name); ui.engineCommand->setText(engineList[current].command); ui.engineOptions->setText(engineList[current].options); ui.engineDirectory->setText(engineList[current].directory); ui.engineOptionMore->setEnabled(true); if(engineList[current].protocol == EngineData::WinBoard) { ui.engineProtocolWinBoard->setChecked(true); } else { ui.engineProtocolUCI->setChecked(true); } } else { ui.engineName->clear(); ui.engineCommand->clear(); ui.engineOptions->clear(); ui.engineDirectory->clear(); ui.engineProtocolUCI->setChecked(true); ui.engineEditWidget->setEnabled(false); ui.engineOptionMore->setEnabled(false); } } QString PreferencesDialog::selectEngineFile(const QString& oldpath) { return QFileDialog::getOpenFileName(this, tr("Select engine executable"), oldpath); } void PreferencesDialog::slotShowOptionDialog() { int index = ui.engineList->currentIndex().row(); updateEngineData(index); EngineOptionDialog dlg(0, engineList, index); if(dlg.exec() == QDialog::Accepted) { engineList[index].m_optionValues = dlg.GetResults(); } } void PreferencesDialog::slotChangePieceString() { QString pieceString; if((QToolButton*)sender() == ui.tbUK) { pieceString = " KQRBN"; } else if((QToolButton*)sender() == ui.tbGermany) { pieceString = " KDTLS"; } else if((QToolButton*)sender() == ui.tbFrance) { pieceString = " RDTFC"; } else if((QToolButton*)sender() == ui.tbPoland) { pieceString = " KHWGS"; } else if((QToolButton*)sender() == ui.tbSymbolic) { pieceString.clear(); } else { pieceString = " KQRBN"; } ui.pieceString->setText(pieceString); } void PreferencesDialog::slotLoadLanguageFile() { if(!ui.cbLangServer->currentText().isEmpty()) { QUrl url = QUrl(QString("http://chessx.sourceforge.net/translations/chessx_") + ui.cbLangServer->currentText() + ".qm"); downloadManager->doDownloadToPath(url, AppSettings->dataPath() + "/lang/chessx_" + ui.cbLangServer->currentText() + ".qm"); } } void PreferencesDialog::loadFileError(QUrl url) { if(url.toString().endsWith(".txt")) { ui.labelLoadStatus->setText(tr("Could not load server language file dictionary")); } else if(url.toString().endsWith(".qm")) { ui.labelLoadStatus->setText(tr("Could not load or install language pack")); } } void PreferencesDialog::slotFileLoaded(QUrl, QString name) { if(name.endsWith(".qm")) { name.remove(QRegExp("[^_]*_")); name.remove(".qm"); ui.cbLanguage->addItem(name); ui.labelLoadStatus->setText(tr("Translation file loaded - select added language above!")); } else if(name.endsWith(".txt")) { QFile dictFile(name); if(dictFile.open(QIODevice::ReadOnly)) { QTextStream textStream(&dictFile); while(true) { QString line = textStream.readLine(); if(line.isNull()) { break; } else { bool notFound = true; for(int i = 0; i < ui.cbLanguage->count(); ++i) { if(ui.cbLanguage->itemText(i) == line) { notFound = false; break; } } if(notFound) { ui.cbLangServer->addItem(line); } else { ui.labelLoadStatus->setText(tr("No further translations online available!")); } } } ui.btLoadLang->setEnabled(ui.cbLangServer->count() > 0); ui.cbLangServer->setEnabled(ui.cbLangServer->count() > 0); } } } int PreferencesDialog::exec() { int result = QDialog::exec(); s_lastIndex = ui.tabWidget->currentIndex(); if(result == QDialog::Accepted) { saveSettings(); emit reconfigure(); } return result; } void PreferencesDialog::slotReset() { if(MessageDialog::yesNo(tr("Clear all application settings?"), tr("Warning"))) { AppSettings->clear(); restoreSettings(); emit reconfigure(); } } void PreferencesDialog::slotApply() { saveSettings(); emit reconfigure(); } void PreferencesDialog::restoreSettings() { // Restore size AppSettings->layout(this); // Read Board settings AppSettings->beginGroup("/General/"); ui.tablebaseCheck->setChecked(AppSettings->getValue("onlineTablebases").toBool()); ui.versionCheck->setChecked(AppSettings->getValue("onlineVersionCheck").toBool()); ui.automaticECO->setChecked(AppSettings->getValue("automaticECO").toBool()); ui.useIndexFile->setChecked(AppSettings->getValue("useIndexFile").toBool()); ui.cbAutoCommitDB->setChecked(AppSettings->getValue("autoCommitDB").toBool()); QString lang = AppSettings->getValue("language").toString(); AppSettings->endGroup(); AppSettings->beginGroup("/Board/"); ui.boardFrameCheck->setChecked(AppSettings->getValue("showFrame").toBool()); ui.boardShowCoordinates->setChecked(AppSettings->getValue("showCoordinates").toBool()); ui.hilightCurrentMove->setChecked(AppSettings->getValue("showCurrentMove").toBool()); ui.guessMoveCheck->setChecked(AppSettings->getValue("guessMove").toBool()); ui.guessNextMove->setChecked(AppSettings->getValue("nextGuess").toBool()); ui.minWheelCount->setValue(AppSettings->getValue("minWheelCount").toInt()); ui.autoPlayInterval->setValue(AppSettings->getValue("AutoPlayerInterval").toInt()); ui.cbSaveAndContinue->setChecked(AppSettings->getValue("AutoSaveAndContinue").toBool()); QString pieceTheme = AppSettings->getValue("pieceTheme").toString(); ui.pieceEffect->setCurrentIndex(AppSettings->getValue("pieceEffect").toInt()); QString boardTheme = AppSettings->getValue("boardTheme").toString(); ui.boardColorsList->clear(); restoreColorItem(ui.boardColorsList, tr("Light squares"), "lightColor"); restoreColorItem(ui.boardColorsList, tr("Dark squares"), "darkColor"); restoreColorItem(ui.boardColorsList, tr("Highlighted squares"), "highlightColor"); restoreColorItem(ui.boardColorsList, tr("Frame"), "frameColor"); restoreColorItem(ui.boardColorsList, tr("Current move"), "currentMoveColor"); AppSettings->endGroup(); QStringList themes = AppSettings->getThemeList(); for(QStringList::Iterator it = themes.begin(); it != themes.end(); ++it) { (*it).truncate((*it).length() - 4); ui.pieceThemeCombo->addItem(*it); } QStringList translations = AppSettings->getTranslations(); ui.cbLanguage->addItem("Default"); ui.cbLanguage->addItem("en"); QStringListIterator it1(translations); while(it1.hasNext()) { QString trim(it1.next()); trim.remove(QRegExp("[^_]*_")); trim.remove(".qm"); ui.cbLanguage->addItem(trim); } QStringList boards = AppSettings->getBoardList(); QStringListIterator it(boards); while(it.hasNext()) { QString trim(it.next()); ui.boardThemeCombo->addItem(trim.left(trim.length() - 4)); } ui.boardThemeCombo->addItem(tr("[plain colors]")); selectInCombo(ui.cbLanguage, lang); selectInCombo(ui.pieceThemeCombo, pieceTheme); selectInCombo(ui.boardThemeCombo, boardTheme); // Read Engine settings engineList.restore(); ui.engineList->clear(); ui.engineList->insertItems(0, engineList.names()); // Read Advanced settings ui.limitSpin->setValue(AppSettings->getValue("/General/EditLimit").toInt()); ui.spinBoxRecentFiles->setValue(AppSettings->getValue("/History/MaxEntries").toInt()); QString dataPath = AppSettings->getUserDataPath(); ui.defaultDataBasePath->setText(AppSettings->value("/General/DefaultDataPath", dataPath).toString()); ui.spinBoxListFontSize->setValue(AppSettings->getValue("/General/ListFontSize").toInt()); ui.verticalTabs->setChecked(AppSettings->getValue("/MainWindow/VerticalTabs").toBool()); // Read Game List settings AppSettings->beginGroup("GameText"); ui.notationColors->clear(); restoreColorItem(ui.notationColors, tr("Main Line"), "MainLineMoveColor"); restoreColorItem(ui.notationColors, tr("Variations"), "VariationColor"); restoreColorItem(ui.notationColors, tr("Comments"), "CommentColor"); restoreColorItem(ui.notationColors, tr("NAGs"), "NagColor"); ui.gameTextFontSizeSpin->setValue(AppSettings->getValue("FontSize").toInt()); ui.cbShowDiagrams->setChecked(AppSettings->getValue("ShowDiagrams").toBool()); ui.cbColumnStyle->setChecked(AppSettings->getValue("ColumnStyle").toBool()); ui.variationIndentLevel->setValue(AppSettings->getValue("VariationIndentLevel").toInt()); ui.diagramSize->setValue(AppSettings->getValue("DiagramSize").toInt()); ui.pieceString->setText(AppSettings->getValue("PieceString").toString()); AppSettings->endGroup(); } void PreferencesDialog::saveSettings() { AppSettings->beginGroup("/General/"); AppSettings->setValue("onlineTablebases", QVariant(ui.tablebaseCheck->isChecked())); AppSettings->setValue("onlineVersionCheck", QVariant(ui.versionCheck->isChecked())); AppSettings->setValue("automaticECO", QVariant(ui.automaticECO->isChecked())); AppSettings->setValue("useIndexFile", QVariant(ui.useIndexFile->isChecked())); AppSettings->setValue("autoCommitDB", QVariant(ui.cbAutoCommitDB->isChecked())); AppSettings->setValue("language", QVariant(ui.cbLanguage->currentText())); AppSettings->endGroup(); AppSettings->beginGroup("/Board/"); AppSettings->setValue("showFrame", QVariant(ui.boardFrameCheck->isChecked())); AppSettings->setValue("showCoordinates", QVariant(ui.boardShowCoordinates->isChecked())); AppSettings->setValue("showCurrentMove", QVariant(ui.hilightCurrentMove->isChecked())); AppSettings->setValue("guessMove", QVariant(ui.guessMoveCheck->isChecked())); AppSettings->setValue("nextGuess", QVariant(ui.guessNextMove->isChecked())); AppSettings->setValue("minWheelCount", ui.minWheelCount->value()); AppSettings->setValue("AutoPlayerInterval", ui.autoPlayInterval->value()); AppSettings->setValue("pieceTheme", ui.pieceThemeCombo->currentText()); AppSettings->setValue("pieceEffect", ui.pieceEffect->currentIndex()); AppSettings->setValue("AutoSaveAndContinue", QVariant(ui.cbSaveAndContinue->isChecked())); if(ui.boardThemeCombo->currentIndex() != ui.boardThemeCombo->count() - 1) { AppSettings->setValue("boardTheme", ui.boardThemeCombo->currentText()); } else { AppSettings->setValue("boardTheme", QString()); } QStringList colorNames; colorNames << "lightColor" << "darkColor" << "highlightColor" << "frameColor" << "currentMoveColor"; saveColorList(ui.boardColorsList, colorNames); AppSettings->endGroup(); // Save engine settings updateEngineData(ui.engineList->currentIndex().row()); // Make sure current edits are saved engineList.save(); AppSettings->setValue("/General/EditLimit", ui.limitSpin->value()); AppSettings->setValue("/History/MaxEntries", ui.spinBoxRecentFiles->value()); AppSettings->setValue("/General/DefaultDataPath", ui.defaultDataBasePath->text()); AppSettings->setValue("/General/ListFontSize", ui.spinBoxListFontSize->value()); AppSettings->setValue("/MainWindow/VerticalTabs", ui.verticalTabs->isChecked()); AppSettings->beginGroup("GameText"); AppSettings->setValue("FontSize", ui.gameTextFontSizeSpin->value()); AppSettings->setValue("ShowDiagrams", ui.cbShowDiagrams->isChecked()); AppSettings->setValue("ColumnStyle", ui.cbColumnStyle->isChecked()); AppSettings->setValue("VariationIndentLevel", ui.variationIndentLevel->value()); AppSettings->setValue("DiagramSize", ui.diagramSize->value()); AppSettings->setValue("PieceString", ui.pieceString->text()); QStringList colorNamesNotation; colorNamesNotation << "MainLineMoveColor" << "VariationColor" << "CommentColor" << "NagColor"; saveColorList(ui.notationColors, colorNamesNotation); AppSettings->endGroup(); QDir().mkpath(ui.defaultDataBasePath->text()); } bool PreferencesDialog::selectInCombo(QComboBox* combo, const QString& text) { for(int i = 0; i < combo->count(); ++i) if(combo->itemText(i) == text) { combo->setCurrentIndex(i); return true; } combo->setCurrentIndex(combo->count() - 1); return false; } void PreferencesDialog::restoreColorItem(ColorList* list, const QString& text, const QString& cfgname) { QColor color = AppSettings->getValue(cfgname).value(); list->addItem(text, color); } void PreferencesDialog::saveColorList(ColorList* list, const QStringList& cfgnames) { for(int i = 0; i < list->count(); ++i) { AppSettings->setValue(cfgnames[i], list->color(i)); } } chessx-1.0.0/src/gui/boardview.h000644 001750 001750 00000014713 12223260306 017321 0ustar00niklasniklas000000 000000 /*************************************************************************** BoardView - view of the current board ------------------- begin : Sun 21 Aug 2005 copyright : (C) 2005 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef __BOARDVIEW_H__ #define __BOARDVIEW_H__ #include "common.h" #include "board.h" #include "boardtheme.h" #include "guess.h" #include class BoardTheme; /** @ingroup GUI The BoardView class represents a widget for displaying current position on the screen. */ class BoardView : public QWidget { Q_OBJECT public: enum {WheelUp = Qt::LeftButton, WheelDown = Qt::RightButton}; enum {IgnoreSideToMove = 1, SuppressGuessMove = 2, AllowCopyPiece = 4}; /** Create board widget. */ BoardView(QWidget* parent = 0, int flags = 0); /** Destroy widget. */ ~BoardView(); /** Set flags for board. Flags include: * @p IgnoreSideToMove - allow dragging all pieces (useful for setting up a position) */ void setFlags(int flags); /** Update and shows current position. */ void setBoard(const Board& value, int from = InvalidSquare, int to = InvalidSquare, bool atLineEnd = true); /** @return displayed position. */ Board board() const; /** @return current theme */ const BoardTheme& theme() const; /** @return @p true if board is displayed upside down. */ bool isFlipped() const; /** Make it almost square. */ virtual int heightForWidth(int width) const; /** Switch to next guess */ void nextGuess(Square s); /** Set Move Indicator property */ void showMoveIndicator(bool visible); /** Set a reference to the database to which the current view is associated */ void setDbIndex(int); /** Get a reference to the database to which the current view is associated */ int dbIndex() const; public slots: /** Flips/unflips board. */ void setFlipped(bool flipped); /** Flips/unflips board. */ void flip(); /** Reconfigure current theme. */ void configure(); /** Enable / Disable Board for move entry. */ void setEnabled(bool enabled); /** Disable / Enable Board for move entry. */ void setDisabled(bool disabled); signals: /** User clicked source and destination squares */ void moveMade(Square from, Square to, int button); /** User dragged and dropped a piece holding Control */ void copyPiece(Square from, Square to); /** User dragged and dropped a piece holding Control */ void invalidMove(Square from); /** User clicked square */ void clicked(Square square, int button, QPoint pos, Square from); /** User moved mouse wheel. */ void wheelScrolled(int dir); /** Indicate that a piece was dropped to the board */ void pieceDropped(Square to, Piece p); protected: /** Redraws whole board if necessary. */ virtual void paintEvent(QPaintEvent*); /** Automatically resizes pieces and redisplays board. */ virtual void resizeEvent(QResizeEvent*); /** Handle mouse events */ virtual void mousePressEvent(QMouseEvent* e); /** Handle mouse events */ virtual void mouseMoveEvent(QMouseEvent* e); /** Handle mouse events */ virtual void mouseReleaseEvent(QMouseEvent* e); /** Handle mouse wheel events */ virtual void wheelEvent(QWheelEvent* e); protected: //Drag'n'Drop Support void dragEnterEvent(QDragEnterEvent *event); void dragMoveEvent(QDragMoveEvent *event); void dragLeaveEvent(QDragLeaveEvent *event); void dropEvent(QDropEvent *event); private: /** Resizes pieces for new board size. */ void resizeBoard(QSize size); /** Calculate size and position of square */ QRect squareRect(Square s); /** Calculate size and position of a coordinate indicator in vertical direction */ QRect coordinateRectVertical(Square square); /** Calculate size and position of a coordinate indicator in horizontal direction */ QRect coordinateRectHorizontal(Square square); /** @return square at given position */ Square squareAt(const QPoint& p) const; /** Selects given square. Previously selected square is unselected automatically. */ void selectSquare(Square s); /** Unselects given square. */ void unselectSquare(); /** Check if piece at square @p square can be dragged */ bool canDrag(Square s) const; /** Highlights the from and to squares of a guessed move. */ bool showGuess(Square s); /** Recalculate guess when board is changed */ void updateGuess(Square s); /** Remove the guessed move highlight from the board. */ void removeGuess(); /** Catch mouse events */ bool eventFilter(QObject *obj, QEvent *ev); void drawSquares(QPaintEvent* event); void drawPieces(QPaintEvent* event); void drawMoveIndicator(QPaintEvent* event); void drawDraggedPieces(QPaintEvent* event); void drawCoordinates(QPaintEvent* event); void drawSquareAnnotations(QPaintEvent* event); void drawSquareAnnotation(QPaintEvent* event, QString annotation); void drawArrowAnnotations(QPaintEvent* event); void drawArrowAnnotation(QPaintEvent* event, QString annotation); Board m_board; BoardTheme m_theme; bool m_flipped; bool m_showFrame; bool m_showCurrentMove; bool m_guessMove; int m_selectedSquare; int m_hoverSquare; int m_hiFrom; int m_hiTo; int m_currentFrom; int m_currentTo; bool m_atLineEnd; int m_flags; bool m_coordinates; Piece m_dragged; QPoint m_dragStart; QPoint m_dragPoint; int m_button; bool m_clickUsed; int m_wheelCurrentDelta; int m_minDeltaWheel; Guess::MoveList m_moveList; unsigned int m_moveListCurrent; bool m_showMoveIndicator; int m_DbIndex; }; class BoardViewMimeData : public QMimeData { Q_OBJECT public: Piece m_piece; }; #endif chessx-1.0.0/data/images/circle_blue.svg000755 001750 001750 00000017467 12062314776 021012 0ustar00niklasniklas000000 000000 LED Circle (Blue) jean.victor.balin@gmail.com led shape Open Clip Art Library Jean-Victor Balin Jean-Victor Balin 2005-08-21 image/svg+xml en chessx-1.0.0/src/guess/sqmove.h000644 001750 001750 00000023010 12223260306 017201 0ustar00niklasniklas000000 000000 ////////////////////////////////////////////////////////////////////// // // FILE: sqmove.h // Square movement lookup table // // Part of: Scid (Shane's Chess Information Database) // Version: 3.4 // // Notice: Copyright (c) 1999-2002 Shane Hudson. All rights reserved. // // Author: Shane Hudson (sgh@users.sourceforge.net) // ////////////////////////////////////////////////////////////////////// #ifndef SCID_SQMOVE_H #define SCID_SQMOVE_H //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // sqMove // Array indexed by square value and direction, giving the square // obtained by moving from the square in that direction. const squareT sqMove[66][11] = { /* UP DOWN LEFT UL DL RIGHT UR DR */ { /* A1 */ NS, A2, NS, NS, NS, NS, NS, NS, B1, B2, NS }, { /* B1 */ NS, B2, NS, NS, A1, A2, NS, NS, C1, C2, NS }, { /* C1 */ NS, C2, NS, NS, B1, B2, NS, NS, D1, D2, NS }, { /* D1 */ NS, D2, NS, NS, C1, C2, NS, NS, E1, E2, NS }, { /* E1 */ NS, E2, NS, NS, D1, D2, NS, NS, F1, F2, NS }, { /* F1 */ NS, F2, NS, NS, E1, E2, NS, NS, G1, G2, NS }, { /* G1 */ NS, G2, NS, NS, F1, F2, NS, NS, H1, H2, NS }, { /* H1 */ NS, H2, NS, NS, G1, G2, NS, NS, NS, NS, NS }, { /* A2 */ NS, A3, A1, NS, NS, NS, NS, NS, B2, B3, B1 }, { /* B2 */ NS, B3, B1, NS, A2, A3, A1, NS, C2, C3, C1 }, { /* C2 */ NS, C3, C1, NS, B2, B3, B1, NS, D2, D3, D1 }, { /* D2 */ NS, D3, D1, NS, C2, C3, C1, NS, E2, E3, E1 }, { /* E2 */ NS, E3, E1, NS, D2, D3, D1, NS, F2, F3, F1 }, { /* F2 */ NS, F3, F1, NS, E2, E3, E1, NS, G2, G3, G1 }, { /* G2 */ NS, G3, G1, NS, F2, F3, F1, NS, H2, H3, H1 }, { /* H2 */ NS, H3, H1, NS, G2, G3, G1, NS, NS, NS, NS }, { /* A3 */ NS, A4, A2, NS, NS, NS, NS, NS, B3, B4, B2 }, { /* B3 */ NS, B4, B2, NS, A3, A4, A2, NS, C3, C4, C2 }, { /* C3 */ NS, C4, C2, NS, B3, B4, B2, NS, D3, D4, D2 }, { /* D3 */ NS, D4, D2, NS, C3, C4, C2, NS, E3, E4, E2 }, { /* E3 */ NS, E4, E2, NS, D3, D4, D2, NS, F3, F4, F2 }, { /* F3 */ NS, F4, F2, NS, E3, E4, E2, NS, G3, G4, G2 }, { /* G3 */ NS, G4, G2, NS, F3, F4, F2, NS, H3, H4, H2 }, { /* H3 */ NS, H4, H2, NS, G3, G4, G2, NS, NS, NS, NS }, { /* A4 */ NS, A5, A3, NS, NS, NS, NS, NS, B4, B5, B3 }, { /* B4 */ NS, B5, B3, NS, A4, A5, A3, NS, C4, C5, C3 }, { /* C4 */ NS, C5, C3, NS, B4, B5, B3, NS, D4, D5, D3 }, { /* D4 */ NS, D5, D3, NS, C4, C5, C3, NS, E4, E5, E3 }, { /* E4 */ NS, E5, E3, NS, D4, D5, D3, NS, F4, F5, F3 }, { /* F4 */ NS, F5, F3, NS, E4, E5, E3, NS, G4, G5, G3 }, { /* G4 */ NS, G5, G3, NS, F4, F5, F3, NS, H4, H5, H3 }, { /* H4 */ NS, H5, H3, NS, G4, G5, G3, NS, NS, NS, NS }, { /* A5 */ NS, A6, A4, NS, NS, NS, NS, NS, B5, B6, B4 }, { /* B5 */ NS, B6, B4, NS, A5, A6, A4, NS, C5, C6, C4 }, { /* C5 */ NS, C6, C4, NS, B5, B6, B4, NS, D5, D6, D4 }, { /* D5 */ NS, D6, D4, NS, C5, C6, C4, NS, E5, E6, E4 }, { /* E5 */ NS, E6, E4, NS, D5, D6, D4, NS, F5, F6, F4 }, { /* F5 */ NS, F6, F4, NS, E5, E6, E4, NS, G5, G6, G4 }, { /* G5 */ NS, G6, G4, NS, F5, F6, F4, NS, H5, H6, H4 }, { /* H5 */ NS, H6, H4, NS, G5, G6, G4, NS, NS, NS, NS }, { /* A6 */ NS, A7, A5, NS, NS, NS, NS, NS, B6, B7, B5 }, { /* B6 */ NS, B7, B5, NS, A6, A7, A5, NS, C6, C7, C5 }, { /* C6 */ NS, C7, C5, NS, B6, B7, B5, NS, D6, D7, D5 }, { /* D6 */ NS, D7, D5, NS, C6, C7, C5, NS, E6, E7, E5 }, { /* E6 */ NS, E7, E5, NS, D6, D7, D5, NS, F6, F7, F5 }, { /* F6 */ NS, F7, F5, NS, E6, E7, E5, NS, G6, G7, G5 }, { /* G6 */ NS, G7, G5, NS, F6, F7, F5, NS, H6, H7, H5 }, { /* H6 */ NS, H7, H5, NS, G6, G7, G5, NS, NS, NS, NS }, { /* A7 */ NS, A8, A6, NS, NS, NS, NS, NS, B7, B8, B6 }, { /* B7 */ NS, B8, B6, NS, A7, A8, A6, NS, C7, C8, C6 }, { /* C7 */ NS, C8, C6, NS, B7, B8, B6, NS, D7, D8, D6 }, { /* D7 */ NS, D8, D6, NS, C7, C8, C6, NS, E7, E8, E6 }, { /* E7 */ NS, E8, E6, NS, D7, D8, D6, NS, F7, F8, F6 }, { /* F7 */ NS, F8, F6, NS, E7, E8, E6, NS, G7, G8, G6 }, { /* G7 */ NS, G8, G6, NS, F7, F8, F6, NS, H7, H8, H6 }, { /* H7 */ NS, H8, H6, NS, G7, G8, G6, NS, NS, NS, NS }, { /* A8 */ NS, NS, A7, NS, NS, NS, NS, NS, B8, NS, B7 }, { /* B8 */ NS, NS, B7, NS, A8, NS, A7, NS, C8, NS, C7 }, { /* C8 */ NS, NS, C7, NS, B8, NS, B7, NS, D8, NS, D7 }, { /* D8 */ NS, NS, D7, NS, C8, NS, C7, NS, E8, NS, E7 }, { /* E8 */ NS, NS, E7, NS, D8, NS, D7, NS, F8, NS, F7 }, { /* F8 */ NS, NS, F7, NS, E8, NS, E7, NS, G8, NS, G7 }, { /* G8 */ NS, NS, G7, NS, F8, NS, F7, NS, H8, NS, H7 }, { /* H8 */ NS, NS, H7, NS, G8, NS, G7, NS, NS, NS, NS }, { /* NS */ NS, NS, NS, NS, NS, NS, NS, NS, NS, NS, NS }, { /* NS */ NS, NS, NS, NS, NS, NS, NS, NS, NS, NS, NS } }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // sqLast // Array indexed by square value and direction, giving the last // square reached by moving from the square in that direction. // The last square is the same as the original square if moving // in the specified direction would move off the board. const squareT sqLast[66][11] = { /* UP DOWN LEFT UL DL RIGHT UR DR */ { /* A1 */ NS, A8, A1, NS, A1, A1, A1, NS, H1, H8, A1 }, { /* B1 */ NS, B8, B1, NS, A1, A2, B1, NS, H1, H7, B1 }, { /* C1 */ NS, C8, C1, NS, A1, A3, C1, NS, H1, H6, C1 }, { /* D1 */ NS, D8, D1, NS, A1, A4, D1, NS, H1, H5, D1 }, { /* E1 */ NS, E8, E1, NS, A1, A5, E1, NS, H1, H4, E1 }, { /* F1 */ NS, F8, F1, NS, A1, A6, F1, NS, H1, H3, F1 }, { /* G1 */ NS, G8, G1, NS, A1, A7, G1, NS, H1, H2, G1 }, { /* H1 */ NS, H8, H1, NS, A1, A8, H1, NS, H1, H1, H1 }, { /* A2 */ NS, A8, A1, NS, A2, A2, A2, NS, H2, G8, B1 }, { /* B2 */ NS, B8, B1, NS, A2, A3, A1, NS, H2, H8, C1 }, { /* C2 */ NS, C8, C1, NS, A2, A4, B1, NS, H2, H7, D1 }, { /* D2 */ NS, D8, D1, NS, A2, A5, C1, NS, H2, H6, E1 }, { /* E2 */ NS, E8, E1, NS, A2, A6, D1, NS, H2, H5, F1 }, { /* F2 */ NS, F8, F1, NS, A2, A7, E1, NS, H2, H4, G1 }, { /* G2 */ NS, G8, G1, NS, A2, A8, F1, NS, H2, H3, H1 }, { /* H2 */ NS, H8, H1, NS, A2, B8, G1, NS, H2, H2, H2 }, { /* A3 */ NS, A8, A1, NS, A3, A3, A3, NS, H3, F8, C1 }, { /* B3 */ NS, B8, B1, NS, A3, A4, A2, NS, H3, G8, D1 }, { /* C3 */ NS, C8, C1, NS, A3, A5, A1, NS, H3, H8, E1 }, { /* D3 */ NS, D8, D1, NS, A3, A6, B1, NS, H3, H7, F1 }, { /* E3 */ NS, E8, E1, NS, A3, A7, C1, NS, H3, H6, G1 }, { /* F3 */ NS, F8, F1, NS, A3, A8, D1, NS, H3, H5, H1 }, { /* G3 */ NS, G8, G1, NS, A3, B8, E1, NS, H3, H4, H2 }, { /* H3 */ NS, H8, H1, NS, A3, C8, F1, NS, H3, H3, H3 }, { /* A4 */ NS, A8, A1, NS, A4, A4, A4, NS, H4, E8, D1 }, { /* B4 */ NS, B8, B1, NS, A4, A5, A3, NS, H4, F8, E1 }, { /* C4 */ NS, C8, C1, NS, A4, A6, A2, NS, H4, G8, F1 }, { /* D4 */ NS, D8, D1, NS, A4, A7, A1, NS, H4, H8, G1 }, { /* E4 */ NS, E8, E1, NS, A4, A8, B1, NS, H4, H7, H1 }, { /* F4 */ NS, F8, F1, NS, A4, B8, C1, NS, H4, H6, H2 }, { /* G4 */ NS, G8, G1, NS, A4, C8, D1, NS, H4, H5, H3 }, { /* H4 */ NS, H8, H1, NS, A4, D8, E1, NS, H4, H4, H4 }, { /* A5 */ NS, A8, A1, NS, A5, A5, A5, NS, H5, D8, E1 }, { /* B5 */ NS, B8, B1, NS, A5, A6, A4, NS, H5, E8, F1 }, { /* C5 */ NS, C8, C1, NS, A5, A7, A3, NS, H5, F8, G1 }, { /* D5 */ NS, D8, D1, NS, A5, A8, A2, NS, H5, G8, H1 }, { /* E5 */ NS, E8, E1, NS, A5, B8, A1, NS, H5, H8, H2 }, { /* F5 */ NS, F8, F1, NS, A5, C8, B1, NS, H5, H7, H3 }, { /* G5 */ NS, G8, G1, NS, A5, D8, C1, NS, H5, H6, H4 }, { /* H5 */ NS, H8, H1, NS, A5, E8, D1, NS, H5, H5, H5 }, { /* A6 */ NS, A8, A1, NS, A6, A6, A6, NS, H6, C8, F1 }, { /* B6 */ NS, B8, B1, NS, A6, A7, A5, NS, H6, D8, G1 }, { /* C6 */ NS, C8, C1, NS, A6, A8, A4, NS, H6, E8, H1 }, { /* D6 */ NS, D8, D1, NS, A6, B8, A3, NS, H6, F8, H2 }, { /* E6 */ NS, E8, E1, NS, A6, C8, A2, NS, H6, G8, H3 }, { /* F6 */ NS, F8, F1, NS, A6, D8, A1, NS, H6, H8, H4 }, { /* G6 */ NS, G8, G1, NS, A6, E8, B1, NS, H6, H7, H5 }, { /* H6 */ NS, H8, H1, NS, A6, F8, C1, NS, H6, H6, H6 }, { /* A7 */ NS, A8, A1, NS, A7, A7, A7, NS, H7, B8, G1 }, { /* B7 */ NS, B8, B1, NS, A7, A8, A6, NS, H7, C8, H1 }, { /* C7 */ NS, C8, C1, NS, A7, B8, A5, NS, H7, D8, H2 }, { /* D7 */ NS, D8, D1, NS, A7, C8, A4, NS, H7, E8, H3 }, { /* E7 */ NS, E8, E1, NS, A7, D8, A3, NS, H7, F8, H4 }, { /* F7 */ NS, F8, F1, NS, A7, E8, A2, NS, H7, G8, H5 }, { /* G7 */ NS, G8, G1, NS, A7, F8, A1, NS, H7, H8, H6 }, { /* H7 */ NS, H8, H1, NS, A7, G8, B1, NS, H7, H7, H7 }, { /* A8 */ NS, A8, A1, NS, A8, A8, A8, NS, H8, A8, H1 }, { /* B8 */ NS, B8, B1, NS, A8, B8, A7, NS, H8, B8, H2 }, { /* C8 */ NS, C8, C1, NS, A8, C8, A6, NS, H8, C8, H3 }, { /* D8 */ NS, D8, D1, NS, A8, D8, A5, NS, H8, D8, H4 }, { /* E8 */ NS, E8, E1, NS, A8, E8, A4, NS, H8, E8, H5 }, { /* F8 */ NS, F8, F1, NS, A8, F8, A3, NS, H8, F8, H6 }, { /* G8 */ NS, G8, G1, NS, A8, G8, A2, NS, H8, G8, H7 }, { /* H8 */ NS, H8, H1, NS, A8, H8, A1, NS, H8, H8, H8 }, { /* NS */ NS, NS, NS, NS, NS, NS, NS, NS, NS, NS, NS }, { /* NS */ NS, NS, NS, NS, NS, NS, NS, NS, NS, NS, NS } }; #endif ////////////////////////////////////////////////////////////////////// // EOF: sqmove.h ////////////////////////////////////////////////////////////////////// chessx-1.0.0/src/database/editaction.h000644 001750 001750 00000003062 12223260306 020435 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2010 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef EDITACTION_H #define EDITACTION_H #include "game.h" #include /** The EditAction is a ChessBrowser action. */ class EditAction { public: enum Type {None, RemovePreviousMoves, RemoveNextMoves, RemoveVariation, PromoteVariation, EnumerateVariations1, EnumerateVariations2, VariationUp, VariationDown, EditPrecomment, EditComment, AddNag, ClearNags, AddNullMove, CopyHtml, CopyText }; /** Standard constructor. */ EditAction(Type type = None); /** Standard constructor with additional data. */ EditAction(Type type, const QVariant& data); /** @return action type. */ Type type() const; /** @return move associated with the action. */ MoveId move() const; /** Set associated move. */ void setMove(MoveId move); /** @return additonal data. */ QVariant data() const; private: Type m_type; QVariant m_data; MoveId m_move; }; #endif // EDITACTION_H chessx-1.0.0/src/gui/logstream.h000644 001750 001750 00000000521 12020176251 017324 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef LOGSTRAM_H #define LOGSTRAM_H void startFileLog(); void stopFileLog(); #endif // LOGSTRAM_H chessx-1.0.0/src/chessx.ico000644 001750 001750 00001261536 12045216060 016403 0ustar00niklasniklas000000 000000  ( V (~ 00 %(  NN h^(  ',26bCgJnRwV|V|SxPuRwTzT{QxOvQxX^`a_\V~PvJpInMqTxX}X~SyLrHnJpSypP3d{dOtQuQuOsMqMqQuTyV|SzOvHoGmNtZa_WPwOtRwW|W}T{OtGlBgCiHoNvQxOuKpHmHnKrNvPwPwQxT{X~Y~TyPtOuT{\bc`\ZYW}RxNtPvX}abZ~Lp@d<`@cHlRvX}X~UzQwSxU{U{QwOuRxZ_aa^ZU}OvJpInLpSwW|W}RxLrIoKqPvU|i{d3!OkW|QvOtPuQtNqKnLoNtRyU|U|QwJpGmNuZb_W~PvOtSwW|X}U{NtGkAfChHoNvQwNtJoGmHoKrNuMtMsMtRyX~\Y~TzRwU{\bc_[Y}X}W|SyOuQvX|`b\PtCg;_<_CgNrW|YV|TzU{V|U{QwPvUy]bb`]ZT~OwJqInLpQuTzT{QxLrJoKpPvU|XV}b}O!Sx$eu_\X}QwOtQuTuPpKlJmNsSzV~V}RxJpHnOv[b_V|OsMqPtUzW|U{OuGmBhCjIpOvPwMsIoFmFoIqJrJpJoKrQwW~[ZW}TzV|[`a]Y~V{W|W}U{QwPuTy\a^TyGk=a:^?dJoSyW}W}V|X~X~V|SxSwX|`dca^[WQzKrJoLpQuTyT{QxLsInJoOtV}YWQyRxne$Dj:tzW{OvY]YRyPvRwSvPqKlKmNsSzWW~RyKqHoOw[a]SyLqJoMrRwU{U{PvIoDjElJqOvOwMsHoFnFoGpHoGlGmJpOvT{X~X~W}V|X~\``\W}TyU{Y~X~RxMsNuX`aX}KoAd;_>cFlOuTzV|W}ZZY~V{V{[`ca_]\XS|NuKqLqPuTyU{QxJqEkFkMsW}\XPyHpElVy~t: ;fMrHoNuX~]ZU{RxSxUxSuOqNpPtTzXX~SyKrIpPx[a[QvJoInLrQwTzTzPwJpEkFlJrOwOwLsHoFoGpHpGnEkFkJoOvRyT{SzT{V}Y]_^[V}SzV|ZYRxKqKrU|_bZOsEh>b>cDjKsQxT{V|Y[ZY~Y~[]]\[\[YU}QxNtMrPuTyV|RxJpCiDjMsY^YPxGnCjFlSvo; P|WyGmElGnNuX~][V}SzTzV{VzTwRvRwUzX}X}RyKrIqPx[`ZQvLqLrPuSySzSyOvIoDjFlKqOvPvLsHoGoIrJrHoEkEkIoOuQxQxQxSzV}Y\]][WV|X~[ZTyLrLrT{]a\RwHlAd?cChJpPwSzT{W~Y[[[[X~U{TzU|W~WT|S{RzPwNuPuSxV{SyKqDjEkMsX}\YPwFmBhFjMqSxaPSxSvIoFlDjFmPvY^\XU|U|W}X}W|V{UzVzX|W|QwJqHpPwZ_[SyOuQwTzV|T{RyNuGmChEjJpOvPvLsIpIqLtLuIqElElIoNuQwRxQyS{V~XZ\\[YX~Y[[V{QuPuU{\`\TyJnAd>aBfJpQxT{S{U|W~Z\\Y~SxOtNtQwRyQxNuNvQySzQxQwSxUzSyMsGmGmMrU{ZXQxImCgFiMqSxTzW|uS$gkPuMsIoEjCiGnPwZ^^ZXW~W}X~Y~X}V{V{V{TyOuIpHoOuY^\V}T{U{V|W}U|RzMuFmAfChIoNuOvLsIqIrLuMuJrGnFmHoLsOvQxRzU}V~XY[\\[ZZ[ZW|TySxW|\`^VzJn?c;_@dJoSyV|T{T{V}Y\\X|PtKoJoMsNuKrGnIoOuTzTzRxRwRxQwNtKqJpLrRwV|V|OuFjBeFiNqTyUzPwKscg$,jlQwOvNtJpEkEjIpRy[_^[ZYX~X}X}X|V{TzRyOwLsHpIoOuW~\\YV~V|U{U|T|S{NvGmAfBfGmLsNuLsIrIrKtLuKrIpHpIpKqMsPwSzU}V~XZ]^_^][[Y~V|TzTzX~^a^TxHl>b:^@dJoTyX~V|TzSzV|Y[X}QuKpJoMsMsIoEjEkKqRxT{SyPvNtOuPvPwNuMrOtSxSxLrDhAeHkRtVzV{QxLtIpbj,3}`TzQwOuNtJqElDjIpSz\_^[[ZY~X}W{VzSxPvMtJsIrIqJqOvV|ZZYWV}TzSyRzR{OwIoBgAfElKrMuKtIsGrHsJsJrJqJrJqIpJpMtQxT{U|V~Y]acc`^[W}SyQwRxX~^`[RvGk>b:_?dInTyY~V|RxOuQwV|YY~SxNsLrMsMrInDhCgGlMtRyQxNtJpLqQwU{TzPuNrOtNsHmBgBfHlQuVzV{SyOuKrJpUz}38{~bX~U{PwNuMsKqFlDjIpSz\_]ZZ[ZY~W{TxOtKqHoHpIrJsLtPwT|WXXXW}TyQwOvPxOvJpChBgElJsMvKuHsFrGrHqIqJqLrKqIoHnKqOuSySzT|V~\bggd`\X~RyNuOvW}^`ZQvHl?c;_?dHmSxX}UzOuKqLsRyX~ZV|QxOvOvMsInDhAfChIoNuNuKqGmIoPuV|W|RwNrLpInEjBgChInPuTyV{SyQwLsIpIpUzw{8 :t[\YV|QxNuLrInEjCiIoSz]_]YY[[[W|RwLqHmFlGoKsMuNvOwR{U~WXZYUzPvMsMtMuIpDiBgFlKsNxLwHtEqFqGpHpKqMrLrJoGmInMrQwQxQyT|Zaghd`\X~RyNtNtUz[^ZSxJoAe<`>cGlQvUzRwMsIpLrQwV}YXU}RzQxNtHmBg?dAfFlJpJqHnFkGlMqSxV{SyNsInEiChChEjInMqPtRwRxPvLrHoHoLtRzs: :gW~\^[W}SyOuMrHmDhChInTz^a^ZYZ[[W|RwKpGmFlJpNuOvNvMvPyS|VY[[V{PtKqKrLsIpDiCgGmMuOyMxHtFqFpGpHoJpMrMrJpGmHnLqPvQwPxR{X_dea]Z~W|RxNtMsSxY~][U{LqBf;`=bFkOuRxPuMsLsOvRxV|YZXU|RzNuHnBh?eAgEkGmGmGlGkGkImMqQvSxOuInEiDhEjGlHmImLpOtPvOuLrHoIpNvT|Xm:8\~OuW~]_\X}SxPuMqHlChCgInUz_ca]ZZZZ~W{RwLqInInMrPvPwMuKtNvRzV~Y[ZUyNrIoJqLsJpDjCgGmNuQzOyJuGrGqHpIoJpLrLrKqHnHnJpNtOvPxR{X]aa]Y|VzSxPvMsMsQvU{XW~SzMrDh=a=bDjMsQwPvPvPwRySyU{Y[ZV}SzOvIqCkAhCiFjFjGkHlIlHkFjGkLqQwQwLqHlGlJnJoImGjHlKpMrLrIoIoLrQxU}WU}e83{VxHoNuV~^a^X}SxPtMqHlCgBfImUy`db^[YX~X}VzRvMsKqKqNtPvOvLtKsNuRyU|W~XW}RwMqIoKqMsJpDiBgGmNuRzPzKvHrHqHpIoJpLqLrKrIoHnIoLrOvQyU}Y]^\X}TyQuNsMrMrMsOuQwRyQyOvKqEj>c=bBhJqPvRxSzT{T{RyTzY\\W}SzPwLtGoDlEjGjGjIlLoMpKnGjEiJoPuRwOsMpMqNsMrJnGjFjInJoIoHnJpOuT{V~V~T}S|`{3,}UwHnIpOvW~^_\W|SwPsLpGkBgBfHmTx^ba\ZZYX}UyRvNtMsMsOtOuNtLrLsPvSzU{T{TzSyPuKpHnIpKqJoEjChGmOuS{R{NwJsIrHqHoJpLrLsKrHnGlGlJpNuRzW\_^ZV{QwMrKpKoLqMrNsMsKsJqIqIpGmCh?dAgGmNuRyU}U}T{QxRyW~\\W}SzPxMvIrGnFjGjHkLnPrQtNqHlFjInNsQvPuPtPuPvOtKpGkFjGlHmFkFkJoPvU|U}S|R{T|U|`},$jUvHnIpKsPxX]\YUzRvOsLoGkBfBgHnSy\_]ZZ\\[V{RwOtNtNsNtMsLrLrOuSyV|U|SyQwPvNsKpGmGnIoInFjEiInOvT|T|PyKtIqHqIqKrLtLsJpFlDiDiHnMtTz[`b`\W}RxMrKoJoMrOtOuLrHoElEmHoJpHmDiChElKrPxT|U|T{QxQyU|YZW~T{QxMvJrHnGkGjIlNqRuSvNrImGkInMsNtNsOtOuOuLrHoFkFkFkEiBfBfIlQuV|U|RyOwS{W~W~aj$gVxGlHnJqNuSzXZYU{RwPtNrKoGkChCiJpTz\][XZ]_]X}SxOuNtNtMsLqKpLqQvW|YW}SyPvOuMrJoFlElGmInHmHmKqPwV}W~S{NuJrIqJrLuMuLtHoDjAgAgEkKqSy[bdb^ZV{QvNrMqOuRwQwMrGlBiCjHoLrMrJoGmFmIpLsPwSzT{SzRyRzT{V|V|TzPwLtJqIoIlHkIlMqQuQvMqHlGkJoMsNtLrKqLrKrGoElDiEiEiAd<_=`FiPtUzQwKrJqQwW~YXbgS\|GkFkGmJpRxW}ZZV|RwNtMrLqJoHlEjEkKqT{\][Y[^`^Y~RxNtMtNtNsLpJoLqRwX}ZW~S{QxPvMrInDjDkGmJpKqLqNtQyV~WT{OvKrJrLtNvOvMtHoCjAgAfChGmOuX}`cca^[W{SwPuRwSyTyOtGlBhCiHoNtQvPuMrJpIoIpKrOvSzT{SzQxPwQwRxQxNuJqHoInJnImHlJoNsNsJnFjGjKpPuPvLrIoHnGnDlCjBhDhCf=`8[:]DgOsRxLsFmGmPvW}[ZWeS PaHlFkFkFlJoQvX}\[V{PuLqJoJoInHnGmGmKrSz[^][\^_]XRyNtMtNtNsKpImKoQuV|XV}S{RyPvLrGlCiDkGoKrMtNtOwQzT}T~S{OwMtLtNuOvOuNtJqFmDjChBgDiJpSy\``_^^\Y|TxRxSySyOuHnCiCjHoNtQwSxQwMsJpHoJqMuQxRyRyPvMtLsMsMtKrHoGmHmJnImHlHmJpKpJnFiFiKnPuRxOtKpIoGnEmCkCiCgBe>a:]=`FjOsPuIpDkElNuV}[[XT{gP ;iGlEkEjFlInJpQvZ_]W|QvLqJoInInInHnGmJpQwY^_]\[\[WRzNuNtOtNsJoHlInOsTyV|U|T|S{QxLqFlCiDlHpKtMuNuOvOyQ{Q|QzOxNvNuNtOuOuOuLsJqIoFkChBhGmOvX[[[\^_\UyQvOuPwOuKqFmFmHoLsOvQxQwNtLrKrMtOvOwPvPvOuLsIqHoHnHnGmFlFkGkFjFiGkJoMqMqJmGjIlMrQvPvNsKqJqHpGnEkDiDhCgCgEjKpOtOuKqHoIpOwV}[ZW~TzQwm;\:uIoFkEkFlHnJpLrSx[`_Y~SxOtLqJoInHnGnFmHoNuW~]_^[XYYWTzPuNtMrKpGlEjHmMrRxT|U}T}T|QxLrGlDjEmHqKtLuLtMuMwNyO{P{PyOwNvNtNsOtOuOvOvNtKpGlEkHoNvT|VWWY\^[~TwMrJpLsNuMtJqHoGoHpJrMtNuMsMtOvRzRzPwNuNtOuMtIpElDkFlGmFlEjChBfCfGjKpPuQuMqHkEiGlLqNuOuNuNvNuKrGmFkHlKpNsOuPuOuOuMtNuPxS{V~XV}T{SxRwRwy:Ry$tVxIoGlHmKpLqLqMsSxZ__\W|SwNsKoHnGmFmElHoNuW~]`^ZVWYXU{QvNsKpGlChChHmNsRyU|V~V~U}QyMsHnFlFnIrKtLuKsKtLvNyQ|Q|PzOwMuLsMsMsOuQxRyQxNtKqJpMtQxT|U}U}V}X~Z~[~X{QtInFlIpMtPwMtIqFmDlFnHpJqKrNtQxU|T|QxOvPvRxQwLsFmEkFkHnHmEkBf@cBeGkLpPuQvNrHlBgBgFlJqNvPyRzSzOuIoGkJnPuV{V{RxMsLsMuRzV~XW~T{RxRxRwSxTy]t$!eY{LqJoIoLqPtOsLpKpNsUz[^][UyNrInGlFlFlFmIqPxX^`]XU}V}YY~V{RuMqImCg?d@eGlNsTzU|U|T{RzOvKqGlEjEkGnJqJrJqJrKtNwPyPyNwLtKqJpIoJoLrPvRxRxOtMrMsOvQwQwPwQxSyTyTyTxRuLoFjChGlKqNtLrGmBh?e@fCjFmHoKrNuRxRxRxQxSzT{RyNuIoGlGkHlGkEjBf@cBdFiImKpJoHlDi@e?dBhGnLtQyT|U|PvKoGkJoRwX}W}RxJqGoJrQyXZV}RxOuRwSxTyTyTy]e!OiOsLqJoKpNsQuOtJnFjGlMrU{[_]VyMqGkEjEkEkGmLsS{Z^^[W~U|V|ZY}VyPsJnFjBe>b?dFjMrSyTzSyQwOtLqHmDhBfBfEhGlHnIoIpJqLsMtLtKrIoHmGkEjEjHnMrPuPtMrLqLrMsMsLqKpLpNrOrOsOrLpIlEiEhFjImKnHlCh>b;_<`?eCiFkHmInLqNsQvSxTzTzRxPvNuMqJnGkDhCgBeBeBeEhEhDgBfBeAe@eAgBiFmJqNvQySzPuKoHkJmPtVzV|RxJqEmFnMuU|W~TzPvOuRwTyTxRwPvPviO3rTyPvNsLpMrNsPuMsFkAe@dFkPuY}_^UyKpEjDjEkFlHnMtT{Y[[XU{TzV{Y}X|TwLoHjDgAc=`>aDgKoQtRuOsLoImFiAc>_;\<]?aCdDgEiFiFiFjFjEjEjFiDgBc@a@aCfIkKnKmIkHjHjFjDhBeAcCcDfFhGiGiEgCfCeCeEfEfDfAb<^8Y6W7Y;\>`@dBfEhGjKoNrPtPtMrLqNrOtOtKnEhAcAbAcBdCcAc?a<_;]:]<_@dEiFlGmGmJqNtPwOtLoIlKmOrSxU{SyMtGoFnJrPvQwNtLsNtRxTyTyOuMsMtPvl3d\W|SyPvNsMrMsNuKrDj?c?bDhMrVz]\UxKpFkEkGmGmIoLsQxV}W~W~U|RyRxTyW{WzQtJmFhCeAb=`>aBdIkMoOqLnIlEhAb<\8W6T7W]BaBbBa?`>_@`BbCcBa>^;[7W5T4S4S6V:Z=]@bDfGiJlMoLoIlFhEhIkMpOrJmDg?a>_?_AbAa>_<\9Y6W6W:\AdImLpImFjFlJpNuOuNqLoMpOsRxU{T{PwKrIoIoJoInGmHnLrQwTxSwOuMsMsOuQw|dPa][X}UzRxQvOuNuJrDk@eAeFjMqTxY}Y|SwLqIoIoIoHnHnJqMtQxSzT{SzQxPvQvTxUxQtKnGiBe@`<^=_@aFgJjKlIjEfAa^?_>\;W7S7S~9W>\A_B_B_B_@^^DcHgIhIjGgBc?_>^AbGgIjGgBb=]_:[;\?_FeIhIjFfCb>]8U~4Ox1Lu1Kv2Nx3Oz5P{6S|7T}8U~7T~6S}7T}8V~:X~;X~:V}7Rz4Nw3Mv5Px8T|Y}:Uz4Ou.Jq,Hn-Ip2Nu7Qx8Sz6Px3Nt2Ms5Nv6Px6Px4Ow4Ov4Pv5Pv5Ow1Mu.It-Hs/Kv6R|>[DaFdEdDcC`?^Z8Tz4Nt/Hm-Fj-Ej.Gl-Gl-Fl.Hm0Jo2Lq1Lq1Kq1Lp3Mp4Np5No3Mo1Jm.Fj-Ej/Gl3Ko5Nq6Oq7Oq8Pq7Pq5Mo0Hk+Cf(Ad(Ad,Eh/Gj1Hl0Fj/Eh.Eh/Eh.Ei.Eh-Eh.Fi0Hk2Jm2Jm/Gl+Dj(Ag*Cj1Jq9Tz>Y>Y^'>^)@_+Aa,Bb,@a,@`,@`+@_*?_)?^*?_+Ba-Cb/Ed/Ee-Cd)?a&=`(?b.Fh5Mq8Qu7Qu5Ot6Ot8Qw9Rw8Rv5Os4Nq3Np4Np4No3Lm0Ii/Hg0Gg3Ji4Kl1Il.Fk*Ci,Em0Js7R|=YCaGfJkKkKoLpMtLsLrKrKrIpDkChFkMqSwUzTzSzTzTxRtMoJlKnQuX}[V|NsFlJqT|dT1UuFiLpUy]a_```\T{IpBhAfFkLqOtPtNrLoHlGlInLqKqHnEkFlKqRyY\[X~TzSxUyVzUyPsIk@a8X1Q2Q7U~?\A]@[~:Tv5Mo0Fg+?`&9X%7U%8U&9V%8U#7T#7T%9W([.B`.Cb,Bc*Ac-Eh1Jn6Pv:T|?[DbHhJkKoLqLrJpGmEkDjAg=b\,@_.Ba0Db/Ca-B_,A^+A^,B^+@\(a;_;`@dGkNsQwSzU|YZV|NsGlFlMsV|ZYTyNtLsLtOwS{y]DzLnEiIlRv]ba__ab]U{JpDiCgHlMqQuPtLpIlGkFlHmHnInHmFjEjGnOvY``ZTyQvRvQvPtLqImDh?a:[9Z=\A`A\>Xy8Po3Ig-A^'8T /I-E-D!/F /F.E-D.E!1G"2G!0F/F.E/E/F.E-D,C,C/E!1F!1F /D.B.C.C/D.C.C.C /D!0E!/E .E-C,B+A+@,A.C /D /C-C-B-C.C.C.C.D/F 0I 1J"3M$5O&7R(9T):U):T'9S&9R&9R'9R&8P#3J-C(>'>)@ /H$5O(;V+@[/Ec1Hh4Lo6Ot;V~?\CbDfEiGlGmGmEjCfAc?b?b?dAgDjInMsRxW~ZZU}MuHoIpOuU{X~X~W|TyRwMtLsMtUz~DpYzDhEiLoX{bfda`ab^U{LqFkDhHlMpPtOsKoHlFkGlHnIoInHmEjDjFmNuX^^YSyPuQuRuQuLpGj@a;Z6T6S~9UzZA`AbAdAfBhFlGlGjEgDgFiFkFlEkGmKqSyY\XR{MuLsOvTzV|V|V|W}X~W}QwMsKqJpZ~pNrFkBhEjNr\fjgcaaa\UzLqGkEiHlLpOsMrJoGlFkGlHnIoIoHnEkEkIoQxY][W~SxQtRuTxTyIk;X-Fj'<]$8U&:V':S);R'8L$4F .>*9$3,%!   !                                #) 0#4%8$8"3+'$$%%&%%$!    %!4,C"2K':U*>[1Fg6Lo:Sy\=]=_;_=cCiHmJmIlIlJnJoJpIoJqOvV~\]WQzOwQyW}[ZV|TzV|[[V|OuIpGnGnpN'x\~FlBhEjQt]gkhc`_^YRxJpGlGkKnNqOsMrJoHmFlFkGmJpJpGnDlFnMuW~]]YU|QwPtSvVyX|Ed,B`$6$ $#$!                                                   $.!20&              %#7*A 1L%7S-Ba2Ik8Qt9Ty;Y;Z;\9]<`BfInLpMqLoKoJnKpMsPwU|Z][U|PxPwU{[_]W}RyTzZ]Y~QvHnFmHo\x'QhJpGnDjFlOt[eigb^\ZU{NuHnGlJnNrOtOtNtMsLrJoGlGlIoHoFnDmIqS{]a]X~TzQvNrRuVyX|@[-B (+.58<9=B8<@6;?59=59=59=59=59=49=48=48=48=38=38=38<37<27<27<27<27<27<27<17<17<16<16<06<06;06;06;06;05;05;/5;/5;/5;.5;.5;.4:.4:.4:-4:-3:-3:-3:-3:-3:,29+29.5=18@/6>#). $*%   &*2:0:C0:C.7@.7@-6?-6>0:D2bCgInMrNrLoHlFjHnNuU|Y[ZW~SyPwRxV|\_^XSzTzZ^Y~NtEkElKsOxmQ&zOsJpJpGmHmNrY}bfda]ZW~QyLsHnHmKoNrOsNtOuQwRxOtJnFkFlEmDlDmKtWab]X~U{SwOrPsSuVy=X~'948;Zagx~z{{||{{{zzyyxxwwvvvuuttssrrqqq~p~o}o}n}n}n|m{m{lzlzkzkyjyjyixgvntpUbp/7>       %ALXbuooi}i~h|fznsjHXg&- &0#9*B#6R)>[.Gg0Kn5Ry9X>`AcCgFkIoLrMqHlCf@cDiMsU}YZXW}TzSySyU|Z]]XU|V|\_Y~LrCjElNuU}\z&WeJoJpJpJoJoOsW{_bb`]YU|OvLrJpKoKoKnInKqPvV|X~UzMrFkDjCjCkFnNvYa`\Y~X}VzPsOqOqQs:T}': "$QV\IU`   (/6`rk.8B  !+ 4&< 2L&:V,Dc.Ik4Rx:YAcEgGlHnJpKqJoEi>b<`BfKqS{WWW~XW~W}V|V|X[[XV}X}^b]PwFmInQwZ\rW-XzKpJoInJnJoOsVz\_a`]XTzOvMtLrLpIlEhChHmPvX[W|OtHlEjDjEkIoQwZ_]ZZ[Y|RtNpLnMo8Q|*@(,2`fmQ_l,4;i}u3>H  * 3&< 1J&9V,Cc/Il4Qx9XAbFhHmHnHoHnGlBg=a;_?eHnQxU}V~V~Y[[YW}W}YZXW~Y~_ebXMuMrRw[`h-RhOtLpHmFkGkJnOsUyY}]``\V|RxOvOvOtLpFi@c?dFlQwXZV{PuJoHmGmHnLqSxZ][X~Y}Z~Z}TwPsLoKn7P{)?&+1^djKXe .5=4=F'-4 )08`sq1;F +"4(cAgHoQxU}U}T{V}Z]\X~U|W~YYX~Y~_ee_V~RySyZ_^oR!uV{PuLqGkChChImOsSwV{[_^YRyOvOvPwOuJoCf>a?dHnRyXX~TzPuLrKqJpJpMrSxY\[X}VzVzV{TySxOtMp7Q{)@'+1^djFP[!&%+1FQ^n|izAKV %$+2Scqi~-7@  -&8,@$5N*=X1Gg3Mo5Rx6S}9Z=_AfCgBgChGkHnGmEkFlKrRzU}S{OvPwU|[\X~TzV|X~ZY~Y~]bed^W~U{W}[\]u!MmQwPuLqHkBfBgHmOsRvTyX}\\U{NtLsNuPwMuHmBf>bBfJpRzXX~TzPvMsKrIpIpLsRxY]\W}QwPuRxU{W~TzPt8S}+A(,2_ekCMW$)/6:=48;48<58<58=48<36:148/37/37/37/37/37/37/37.27.27.27.26.26.27-27-27-16-16,16,16,16,16,16+16+16+16+06+05+05*05*05*/5*/5*/5*/5)/5)/5)/5).4(-3+28/6=$*/ "EP\zfx,3;$*1P^lk.8A ('9#2G(:P.C^2Jg;Uu>Y|@]?^BcGjLpMrLrNtRxU{U{SyRyPwNtMrNsPvPwOwQxT|V|QvJmEhFiInNsRwSxV{Y[YPzGqBlFnOvX}da2|Y~W|QvOsLqLqJoJnOqWx]}\}WzUzU|V|U{TyRwQwOvNuMsIoHmKpRwX~YU{OuKpInGkEjIoRyZ\V}OuLrOuV|Z]YT{Cc/Eg(>+%*+"0"0 .&  ,03:>C;@E8=A49=59=59=48=48=48=48=38=38<38<37<37<27<27<27<27<27<27<17<17<16<16;06;06;05;05;05;/5;/5;/5;/5;.5;.4;.4:.4:.4;-3:.4;'-3&+1+18EPZgxfx-4<$+1P^lk/8A ,*>%6M+>W2He7Po>Yz?[>\;Z?`DhKoMrMrOtSxU{TzRyPxOvMsNsQvU{U|RzQyS{SzOuImEiEiImMrQvRwRxSzV~VOxEn?gDjNtZ~`2QqY}VzQvPuOtOtLqJoMpUw]}]~Y}V|W~YX}TyPtNsNtOuOtLqJoMqSxX~XTzOuLpKnHlFkJpSz]_W~OvLsPwW~]_\XPsDa7Py.Fk)Ad+Ef/Hi6Pq7Qr5Mn*?Z,@ 48;`ho~t~t~t~t}s}s}r|r|q|q{p{p{p{ozoznznznznzlxlxkxkwjwjvjvivivhvhvhvgvfuetetetdrdrao}crj{{ev-4<$+1P^lj.8A 0,B%8Q,A[4Lj:St?[~=Z9W6T9[AdInMsNsOsRvTxSyQxQxPwOvQvUzX~W~T|QyPxNvKrJoJnKoMqOtQwQwOuNuPxS{OwFn?fChNs[`vQ*y`UyQvMrNtQvRwOtKpMqSvZ{[~Y}W~XYW}RwMqKpMqOtNtLqLpNsSyW}W}TyPtMpLoImGkJpSy\_XPxMtQxX_ca]ZUzOsGjAeChHnRxU{RwCa.Db!0!'Z`gdu-5<$*0O]ki~.7@ !$70H&:V-Ca6OpaGlNtNtJoGkGkKoPtSxTyTyTyTzV|V|U|RxLsFmFlLqSxW|V|TzSzSyOvKrLsQwSyOuHnGmMsUzW{Swk;Y\TyPtIlDhGkNrRwRwQvRwUyW{WzVzV|W~U}RzOvOuOuOtNrMqMpMrOtRxTzTzSwQuPsPrMpJnJoNuU|YV}RyPwT{[cgea\X}SxOsJnInLqQwW|Y~Op5Nq%6+29kszct.5<*18]l|v4>H *-F%9W)@a.Fi6Pv=W?[:W5S2Q5U>_FjLqLqEj@e@cEhLoQuSxSxQwQwRxTzU{RyMsHnHmNrVzZ~Y~V{TzU{T{QxQxU{X}U{OuLrNtRwRvOsVxYr~QwRwOrIlDgFjNrSxRxQwSyVzX{WzUyUzU{T{RzS{T{TzQvNsNqOsPuQwRxTyTyTxRwRvRuOrKnImLrRxV}T{QxPwU|]dgd]W}TzSxQuLpImImOtVzZ~Ll3Km#4(.6ckrbr)/6#(/Ucqt3=G , 1K(>^,Dh/Hn6Px:U>[=[:Y6V7W;\BeHmIoDi>c=`AdGkMrPvQwOuNtOuRwSxRxOuMsNsSvW{ZX~V{UzY~\[Z[][V|QxQwRwPtNsPtrBkNsNrLpKmGkKoQvTzRyOvPvUyX{XzVyTxTySzT|WZW~QwMqNqQvTzT{TzTyUyUzTyTySwPsKnHlJoPuTyRxPvPwU|^ef`X}SxRyTySxNsJoInNsVz\Oo5Mp%6)/6dlsev(/5bDjHnGlBg>b>cChJpNuOvMsLrMrPuRwRxQxSyVzY}[\Y~W|W|]cdbbca\W}U{UzQvPtRwpB^aLpJnIlImKpPvV|V}QxLsLqQuWyX{WzUyTySyV}[]YQvKoMqRwV}WV}V{V{V{U{TzSwOsJmGkJnOsRwQvOuPvV|_dd]U{PvQwRxQwMsHoHnMsW|^Rr6Nq%6)/7dlsj{*17 "=GSXgw[l|Ziy[kzYhxWfv]m~arWgw;FQ$ !3&8V/Fk4Ow5Q{7U8W<\@aCd?a<_:^>bDiJpLqInBg?eAhHoMtNuKrJqLrOuQwRyT{W~[]^]ZX}Z~`fhgffc^ZYYV{SxSxh^.ySvKnGjEjHmMsU{ZXPwIoHmNqUwY{Y}V{TySyV}\_ZPuJnKoQvV}XW~V{V{V{U{TzRwNsJnHlImMqPtPuOvQxX}_cb\V{RwRwQxOvKrGmGmMtX~`Su6Or%7)/6elsx>HQ#'-4$*0"(-"(.!(.!(/$+1&-5"(.  )>)>_1Ip7S}:W<\<\>aAdCfCeAe?dBfFkLqOtMsGlAgAhHoMuNuKrJqLsPwRyS{U}Z^```]\\afhggfd`]]]Y~UzSzY~.   $#*%5&5L-B`/Ho0Lv9XCbIkJmIlGjFiFiGkHmInImInLqNtKqGmFlKrQwRyPwPwQyT|U}T|U{Y}]acba_^^^`aa`^]]^]ZW}U|T|[ReTvOrKoLpOtSxW|YZU{MrFkFkMrV{[[W}RxNtPvV{Y~V{NsHmHlKpMsLrInGkHkLpRuUyTyQvMrJpJoJoKpMsQxV}[^]Z}X|X|X}W}SyNtJpIoLqRxX~ZLo2Ln#5*/6flt~P]i!%  ( .$6'9.D'8P2Fd4Ln3Mu2Oy;[GgOqOrLqInGmFkGlInInHmHkJnLqJpFlFlKqQwT{T{T{U|WV~T{RxUzZ~`a`^^^\\\\[YXY[[XV}V}U|U}U}e.|VxPsMqQuUzY~ZYW}QwInChDiKqTz[]YTyPuPvUzW|SxLqGlGlKpMrKpFjBfDgIlOsSwRwOtLrIoHmGmInLqQxW~]_]Y|UyTyTzTzQxNtLrLqPtUyY~YKn2Lm$5*/6fmtbq%+0 !#1(:/D!3K(!3J%8Q+A^1Hi9Rw;U|:X:Z@cJoRwRyPwMtLsJqHoIoIoInHlHlGlCh?e@fFmOuV~Z\\\X~RxMsNtU|[[X}W|Z\ZW~U|RyOuMsNuSyU{TzQwPvRyRyRyQxkD^iTxQuSx[_`\W~RxJpBg=b?dGmRwZ^\W}SySyU|U|QxKqHmImLqNsLrHmFiGkMpRvTxPuKpGmDjChBgFkLqTz[`a]VzOsLqLrNuOvNvNuNtPuUyY~ZLn4Ll$4)/6gntcr'.4 !#3+?$4K':S,Ba1Hi7Pv;U~cAfInSwZ][W|SySzV}U}QyLrInImLqNtNtLqJoMqRwW|W|QwKpFlDiBhChGlNtV}]a`[RvLoJoLqOuOvOvNuMsOsSwX}ZKm3Kk#4*/6gnt^l{%+1  !0)<#3J'9R,@^/Ee5Lr8Sz^CfInPvSxRxQvNsJpHmHnIoKpKoHlBf=b=cBhJpRxY]^[X}SxNsKqLsRzW~V}TzTzW}YW~T{QyPwOuNuOuQwRxSxSxSxRxPwMtKrTxyp(5uVzPuMrPvYac]U{MsGlChBgEjLpTxY}[X}U{TzU|V~U~QyKrHnInLqOuOvNuOtRwW|ZYSyLrHnEkDiEiImPuX~_b_X|OrJmKnNrQvPvNuMsLrNrRvV{XJl2Jk#4*/6gnt_m|&,2   /(<#4J(:T-A_/Ef4Kq7Qy;Y>_DhInOuQvRwPuLqFkChDiHmLpLpFj?c;_>cGlOuV|[]\V|PtKoHmGmJqOvSySyRxRyU{W}V}T|RzQxQxPwPwPxQxSySxSxRwOvLsIqIpf5?jTyNsJoLqTz]a\RxJoFkEjGlJnOsUxX{X|U{TzU{W~XU~PxJqGmInLrPwQyQxRxU{YZYTzOuLrIoGlFkIoPvX_b_WzOqKmMpQtSwPvLrJpJpLrQvU{W~Jl2Jl#4*/6hnt_n|&,2   .';#3I':S-A_.De2Io4Nv9W?_DhInMsPuPuNsHmAf>bAeHlMrMqEi<`8]?dJoTyZ]^ZRxHmBgBfEjHnKrNtOuQwRxSzT{U|T|S{RzRyQxOwNvOwQxQwPuOtMtLsJqIp\?N^UyMrGmHmOtW|[V|MrFkDiGlJoLpOrRuTxTySxSyV|YZV}OvHnFkGmLqOvQySzT|W~YXV}SzRxPvMsHnEkFlLsV}^b_XzQrNpPsSvSxOuJpGnHnKrQxV}XJl2Kl#5*/7hnt`n|&,2   -&9!1H'9R,A_-Ce/Gm1Lt8U=^DgInMrNsMrJoDi=b:_@eInPtMqCg:^7\?eLqV|[]\YPwEk?d?dCiGlHmInKqOuQwQwPwQxRzRzQyPwMuJrIqIqLsLrKqJpJqKrKrLsQxNZ]WyNsInGmLqQvSxNtGmDiEjInKpKoLpOsQuQvQvQwU{YZV}OuGmDjFkKpNsOuQxT{XYV~SzQxRxRxOuHnBhAgHnRz\a_Z|TuQrRtSwSwOtIoFlGmLrSyX~YJl3Kl$5*/7hnt`n|&,2   .%8/F%7Q,A_-Df/Hn0Kt5S:ZAdGlLqLrJpFlAgcDjOvZ__[~UwQsPsQuQvNtJpGmGnLsTzZ[Lm4Lm$5*/7hnt`o}'-2  .$8.D$6O+@_.Eg0Jq0Kv3Q6V=_DhIoJpGmCi@f?eBgHmNsPuKpAg;`:`BhLsS{U}T{QyQyPxMuJqFmElEkEkFkJoMsNtKrIpJqMtMuKtHpDl?f=c>dCiGnHoGoGnLrNuPxPxwm({^Y|RvOsKqJpInHlFjEjGlInInGkEhFjKoNsNtLsLsOvT{XX~RxJoEjEhFjHkJnOtV{[[V|QxOvQxSyQwIn?d=aChMtW]^\VyPtNrNsOtOtLrJpJpNtUz[\Mn5Mm%5*/7hntao}'-2  .%8.D#6O+@_/Fi2Lu2Ny3Q4U:]BfHmInEkBiBiEkInMqOsMrHnBh?e?eEkLsQxQxNuKrKsNvPxOwLsHoElFlHnLqMsKqGnFlHnKrKrHqEmAi>e=c?dCiHnIoGnGnLrOvRyRyt{( :y\W{RvOtKqJpInImHlHlInIoHmDhBeDhJnMsNtLtMuPwT{X~W}RxKpDiBfCfFiKoRvY}^\V{QwOvRyU{RxIn@d>bDiMtU}Z]\X|RwOtNsOtOtNsLrMsPvVz[]Op6Oo%5*07iotao}'-2   .&9/F#6P*@_.Fi2Mv3P|5T7W<_BfGlGlDiCiElKpOsOsLpHmEkDiCiEkHoLsNuLsIpFmGnJqNuPwOvKrHoGnIoLrLsHoDjCiFlIpHqFoDmCjBiBhDiFlInHnFmGmLsPwSzT{p: FsY~UyQtNsLqLqLqMqMpKpJoIoFlBf@cCfImNrOuNvPwRzU|W}UzPvJoCg?b@cEiNrW{]_[~VzRxRyU|V}SyJoBfAeGlOuU|Y\\ZU{RwOuNtNsNsNsNtQwV{[^Pr7Oo%6+07iouao}&-2   .': 1G$7P)?^,Dg2Lv5R~9X;\?bBgFkFkDiEjInMrOsLpGlDhDhEjHlJoLqLrKrIpGnFnGnHnIoLrOuOuMsJpJpKqKrHpDkCiDkFmFoFoFoHoIpJpJpInHmFkEkGmMtQyU|V}mFUkV{RvNqMqLqNsPtPuOtMrKpIoFkAf?bBdIlOsRvQwRxSzU{T{RxOtInBe=`>aFiQu[~_^Z}VzTzU{W~V}QwInCgDgInPvU|X~Z]\YU{QvNsLqLrMsMtOvTzZ]Pr7Pp%6+07iouao}&-2   .': 1G#6P'=]*Bf1Kt6R~^@dBfDiDjEkHmKpLqKoFkBf@dBfFiImLpLqJpHnFmGnHoIpHnFkGlKqPuPvMrInGmGoHpGoFmElDlEmGoJrNuQwPwMsIoFlEjFlIpNvRzV}V}hU_fTxOrKnKoMqPuQvQvOtMrKqIoFlBg?cCeKmSuVxTxRwRxRxRxPvNtInBf>`@bHkSw[^\X}W|W}W}V}RyLrFkCgEiKpQwT{V}Y\^]X~RxNsKqKqKrKrMtRxW}\Pr7Pp%6+07jouao}&,2   .&9/F!3N%:[(?c0Iq5P|]@b@dBhDkGmJpKoImEiAe?c?cAdEgGjImJnHnFlElGnJqLsJpEjCiGmMsPuMrGkChDkHpKsKsJqGnFnHpMtSzV|SyMsHnGmIoKqMtPyRzT|T{a_'m`RuLoHlHmLqPuQvOtLrKqKpIoGlChBfFiOqWxYzUwQuOuOvOwOwOuKpEhAcDfLoTyZZX~W|W|X}V|RxLrEkBgBfGjMqRwSzT{V}[__[TzNtLrKqJpIpJpOuU{YNq6Op%6+07joubp}',2   .&9-C1K#8X(=a.Fn3Mv9U;Z?a@cBhElHoJqIoGjCf@d?c@dAeBeBfCgDiEkEkElFmIpLsKqGmDjEkJoMrJnDh@eAhFnKtNvOvMsJqJqNuT{U|PvJoGmKqPvRySzRzRzQyOvW|{m',v~[}QsKmFjFkJpOtOuMsKqJpJpHoFlDiEiKnSuYzYzTwPtNtNuOwPxPwMrHjEgHjOsV{X~W}V|V{W|W|SxMsFl@f>dAeGkNrSxSySzT|Z_a\U{OvMtLsIpGmHnMsSzW~Km4Mo$6+07joubp~',3   /&9,C0J#7W'<_,Cj.Gq3O{8V?`BeDjFlHoIpHnFkEhDgCgCgBf?dcChGlGmGmGmIoJqIpHoGnHnHmEjAe>c@fDkIqMtQwPwNuLsNuPwOuJpFlHnOuT{V}V}T|QxMtIpNsqv,2uWzQsKnFjEjInNsPuNtLrJqJpHoFmFlInOrUwXzVyRuOsNtOvQyRzRxNrHkFiKnSwX}X~U{SyTyUzUzPuJoCi?e>dBhInOtSySySzU|Z_`[TzPwOvNtIoEkFkMsT{V~Hk1Jm#5+07jpucp~'-3    /':-C1J#8V'=^*Ag+Dl/Kw6T@aDhFlFlGmHnIoJoInHlFjEjCh?d9_6[9^@fHmJoHnEkEkGnIqKsJqGnDjAf>c=b?eCiFmJpNtQxQxOvMtJqGmDjEjJpPwT{U|V}V}RxKqEkEje26qVzRuLpGkEjImNsQvPvNtLsJqHoFnHoKqPtTwUwSvNrLqMsPwS{U|SxMrGkFjLqTzYW}SxQvRwTySyOtIoDjAhAhEkKqPvTyTzU|W~\^\W}QwOvPvOtInDiEkNsV|WGj/Hk"4+07jpucp~(-2    /':.D1K%9W(>_+Ch+Em/Lx6U@bEiFlDjDkGnKrMtLrJoGlFlFkBh;a6[7\?dGmKpInDjCiCjFmHoGnEkBh?d=b=b?dBhEkHmKqOvRyQxMsFl@f?eDkKrPwPxPxSzU}RyKqDjCh_6dEkLsOvNuNuQyU}T{NuHoGm[~<?eVzTxPtMqLpNsSwUzU{SyOvLrJqJqLsMtNtPtQtPsLoImKpPvU|W~SzLrFlGnOvW~YSxLqKpOtTyV{RxLrHnHnLrPwSzSzTzU{X~[\]YT{PvOuOuLqFkBhFlPwY[Jl0Im#4+17kpudq~(-2   /':.E!3M'=[-Cd2Kq4Ow7T:ZBeFkFmDkDkIpNtOuKqFlCiEjHmInEj?dd?fBiFmMsQwQwLrDi>c=bAfGmMrNsMqKpLrNvQyRyRySyRxNtHnDjFlLrQwRxRyS{WZZWU|[CF[}RvOuPuRxUzVzW{X}X}U{OvKrLsOwRzSzSxRvRvRuPtMrMrPvT{W~T{MuIpLrSyYW~PvIoInNsTyUzSxMsIoJpQvW}XU{SxSxUzW}Z]]ZU|RxOuKpGlFlKqT{[]Np5Mo%6,18lqvdq~(-2   !0';/F#6P,A`2Hj6Nu5Oy6R:XCeKnMrJpGmHnJpKpHmDiAdAdDgHkGjCg?d>c@fCjIpPvU{W}TzMtGmChCiJpQwT{SyOuMtNwQzRzRxRxRyPwLsGnFlJpQvU{W}X[^_]Z\FIUyPuNtOuSyW|W}X}X}W}TzNuJrLtQyV~XW|TxSvSwTxRwPuOvRyT|QyLsIoLqSyXV}OvIoInNsSxSxQvLqIoKqRxYZV{QwQvTxW|Z^^[V}TzQwMrHmHmNsW|]^Op5No%6,28lqveq~(-2  !1(;0G%7Q.Cb4Jl6Nu4Mv4P}:WDeNqQvMsHmEkEkFlFkDiAe@cBeDgEgBe?c>cBhGmMtRyV|XYV}QxKrHoKrRyW~V~RzOwOwPxQyPwQwRxQxNuIpFmInOtV{Z\^`a`^^IJRuPtNsQvTyX}X}W|V|U{RyMtIpJrPxW[Y~TxRuSwV{U{RxOvPwQxNuIoGlJoQwV}U|NuIoJoOtRwQvOsKpIoLsSzZ[V{QvPuTyX}\^^ZW~V|TzOuInHmOsX}^^Mo5Mo%6,27lqveq~(-2 !!1)< 1H&9R/Ec4Km6Ov3Mv3O|9WEfQuTzPuImChAfChDiEiDhBeAc@cAdAc@c@dDiJpPwSzS{T|WXW~QyMuMuQyU}V~T|RzPxPxPwOvPvPwQxOwKsGnGmMrUz\^^^a``^JLQtNsNrQvVzZ~Z~W{SyRxPwLsGnFmKsT{ZZUyQuRwU{V|T{QxPvNuKpGkFjJnPvU{SzNuKqLrPvQwOuMrJoIoLrSz[\V|QwPvUzZ]^[W}V|W~V}PvImGkMqW{\\Ln4Mn%6,27lqveq~)-2 !"1*a?bBdDfDhGkLqRyS{R{QzT|WXU}RzPxPxRyS{U|U}T|SzRxQwQwQxRyQyMuIoGmLpTx[\[Z]`bbLMPtMqMqSvX{]\VzPuOuOvLtFnBiElNuW~ZVzRuQvSyT|U|SzQwNsJnFjFjJoPuTzTzQwOuPvRxQwNtLqInGlJoQwY[V|QwPwU{[]\W{SxRxU|V}PuGkEhKoTyZZKm4Mm%6,18lqvfr~).2 !"1*=#4J(;T0Ec5Lm:Tz:U~;Y>^FhOsTzRxLrGmFlFlFkEkEkDiAd>a?bBfFjGkHmLrQyS|R{PzR{U~WV~S{PwNuMtOvSzW~XX}V{UzSzRzRzQyNuJqInLpRvX~YV~S{W~]ceMMPuMqLpRtX{^]VzOsMsOuNuGn@g@fHoT{[Z~UyRwSyT{V}U|SxOsJmGjHlLpQuTyUzUzUzUzSyPvMsKqHmEjGkNsW}ZV}PxOwT|Z\Z~SwNsOtSyTzNsEiBfInSxXXJm4Mm%6,18mqvfr).3 !#2+>#4J'9S.Db4Lm=V{@[B`AbFiJoPvQxNuLsLsKrHoEkCiChBf@d@dCgHlInJoLrPxS|S}T}VWWU|RxNtJpHnKqRyY[[[ZXV~T|PwKrIoJoMrRwV{U{QxMtSw[dhMMRvOsMpQsVx\]X|QvOtPvOvJpBh?eEkRx\^Y}UzTzU|W~V|TyOsKnIlJnMqPuSxVzW|W|UzSwOtLqJpHmDiEiLqT{YU}PxOwT{Y[X}RvMrMsQwPvJoBfAeImSyXXJm4Mm%6,18mqwfs(.3  #2+="2I%7P+A^3Kk>W{C_GdDdEgHlMrPvOvNvNvLtIpDkBhCiDiChCgDiHmIoJpKrOxS{U~XZZW~RxNsJoGkEjIoQxZ]]]]][V}MsElDjInOtTyU{SyNtJoOsY}djMMUxSvPrPqRtWz[Y~TyQvQuPuLrFkAgDjPu[`]Y}W}YZW}SwNrJnJnKpLqNsQvUyW{VzSwOsKpInHmFlEjGkLrSzW~T|QxQxU|YYV{QvNsOtPvMsFk@dAeJoTzXVHk2Km%6,18mrwfs(.3  "0(:.D 2J'-D#7R-C`:Qr@Z|D_A^AaBdEhFiDhCgCgChDhBhBhDjHoKpKpInJoKpNuQxS|T~VY]]W}OuKqJoInHmKqRxZ]]_cgeZHm;`<`HlTxZZV{RwNsQvZdjLJWzUyRvNqKnMpPuRwQvOsMqMqLqInFkEjLpUx\^^_a_W|NsHlFkHnJpIoJoNsSxTyQvMrJnIlGjEiEjGnLsRyV|W}TzSxU{Y[X~SyOvQwSySyNtGmCiFlNtU|W~RzCe.Hk#5,18nrwgs).3   ) 0$8(> 2L*>Y5Kj;Qs>W{`<^<_?aAdAeBfDiInMrMsLqKpMsRyV}WVU~W[[U|OvMsNtOtNsOtSyX[]afjg[Im;`<`ImV{][W|TyQwU{\chJIY}UzQvLqImImKoLqKpJnImImJnImGkGkLpSwZ~]_`a^V{NrGkEjFlGmGmHnNsSxUzSwOtMqMoJlGjEjFmKrSyX~YV{TyV}\^ZSyOuPvTzU{QwKqGmIoOvU|U|Ow@c,Fj#5,18nrwgt).3   &,!4&:/H'9T1Ec5Kj8Ps7Qv:U}=Y?^?^=];[;[<]?a@b@cBfGlLrNsLpKpNsU{ZZVS}S|V}V|SyPwPwRySySxSxTzV|Y~]cgifZJo>b>bKoX|^\W|UzTyW}]chIF]U{QvLqHmGlGkHlGkFjEiEiFjGjHkKnOsTxX}[]^][UzNsHlEjDiDjEkHnOtUyW{UzSwQtPsMpImEkEkIoQwX}[W|TzW~^a\TxNsOtSyU|SyNtKqLsQxU|SzMt>a,Ei#5-18nswht).3  !'/"5,B$5M+>Y/C_2Hg2Ij5Mr7Qw;W^=_>aDhJnMrJoHnKqSyXXU}RzOwOvOuOuPvSyU{V|V|W|V{TzUz[bffaW}KpAfAeLpX|]ZUzSxTyW}]aiFCbW|QvMqJnHmGkGkFiFiEiDiDgDgHkNrSxV{W|X}Y~ZYW}TyPuKpGlDiBgCiIoPvV{X}W{UyRvPtNrJoFkCiFlOtW|Y~V|SzW~^b]TxNqNsRxU|SzOuKrMsQxT{RyLs=_,Eh#5-28oswht*.3   %,!2+?"2H(:S+>X.B_-Ba/Eg2Jn7Qw;V}_=_@aGgLoMqHnDkCjFmLsPwPwKrFlDjGmMsRyU{W|Y~\X}RwQvV{^^ZTzQwMsInGlMrTzW|TyOsMqOsUz[_n?f?gFnNuQxNuJpFlHnKqPuSxV{Y~\Y~RwOtTyZ[V{RwPuNsKpJoOuU{VzQuLoKoOsU{\_p<6uZ~TxPtMqLqJoInInKpLsJpDjChInUz^]TwMpLpOtSxTzRxOuLrHnEjEjHnMtQyS{SzQvLqHmGmIoKqKpJnKoMsNuNuLsMsQxV~ZY}RtKmHkJlKnIlEhCeFiMnRvPuHl:X+@^ /-16ptwkw+/4     !% .$3):+=-A-C 1I$6P*?[/Ec2Ji2Jm3Mq5Pu8T};Z?_@`A`DbJiOqPtIpAh?fElNuSzS{QxMtKqKpMrQvV{Z\X}QvMrPuV{X}V{SwPuNsLqLrRxW|VzPsKmKoPtW|]aw62x[UyPtLpKpJpKqKqKrKrHoDkDjKqW|_]TwLoKoOtSyU{RyNuJpFlEjGmKrOwQxPwOvMrJoGlGlHnJpLqLqMrOuNuLsKqLqOuTzX~X|SuKmGhFgGiFfBcAaDeJkPrNqGi9U|*>Y,-16quxp|,16   "(,#2%5(:*=.D#4L(^@`A`AaFgLoQvNuGnDkHoOwU}WXU|QwMrLrPvU{YZV|OuJoLqSxX}X}V{SwOsLqMtT{Y~WzRtMoMpQuW}^c}2,v~]UyPtLpKpLrNtNtLsIpElDjGmOuY_\SvKoKoPuUzW}U{OuHnDjDjJpOvRyQxNtLqJoInInIoIoJpKqMrOtPvNuLsJpKpNsRwU{WzTvLlDdAaAbBa?^>\A`FeLlKkCc4Or&9R*-05rvxmy,15       #(* ."2'9-@#4J%7O';U*>[/Gf4Lm8Rv:V|>\?_?`>_AcHlQvSzNvJqLsPxU~Y\ZU{OtLrPvT{XW~SyLrGlInQvX}ZY}VzRvNtOvT{X}X{UwPsNrPuV{^iv,'m]SwPtMqLrNuQxQwLrGmCiEkKqSz[^Z~RvKoJoPvV|ZW}PuGmBhDjKqQxS{QxMrInHmJoLrMsKrJpJpKqNtOvNuLsKpLpNsQvUyVzTuKkCb>^?^?]=[;X?\DaIgGe?]1Jk#5M',04rvyQZc         !#+#3,?"1H&7P(^?_>_@bGjPvU}S{OwOwRyU}Y]\W|OtLrOvT|WV~QxJpEkHmQvY~[Z~W|UzRxPwRyUzWzWzSvOsNsTy]lm'_^PsOsOsQwRyT{RxKqDiBgFkOuW~\^ZSwKoInNtU|ZX}PuFk@fBhJqRyU|SyNsInGlIoMsOvMuJqIoJpLsNuNuMsLpMqOtQvTyUxRsIiA__>^?bGkQxXXT|SzSzU}Y]\U{LrIoNtU{YX~QwJoEjInRwY~ZW}V|W}U|RyPvQvTxWzTxPuNsTy^s_U]}LoOrQvT{U|T|PwHnBgAfGlPwY^`[TyLpHnLsRyV}U{NsEj?c@eHoQxV~V|QwLqHnHoLsNvNuKrIoIoKqMtNuMsMqOrPuQvTyUwQsGh@^;Y;Y;W9U~7Rx:Sx;Uw=Wy:Su3Lm';W*> ,.2txz\fp8>E"     "0 .B$5K)^>^@cFkQxZ[YV~U|U|Y\ZRyIoFlMrUz[ZRwJoFjKpUy[YU{TzV}U|QxMtLrPuTySxQvOuVz_wUFaKnOsSyXW~T{OuGmAgAfGlPvX^`]U{MsJoKrNvQxPvLpEh?c@eHoRyXYU{OvJpHnIpKsLsKqJpKqLrMtNuNtNrOsPtQuSwSuOpFe=[8U9U}8Sy7Pu4Mo5Nn6Mk6Mk1He+A] 2J#5 *.1twzs48>*/3>EKHOWEMTAHOAHO@GO@GO?GN>FN@HPAIQCKS=EM07<"  %): 0D%7M':S,B_/Fg5Ot:V~>\=]?bDiPvZ^^[W~U|W~ZYPwGmDiLoVy\[~RvInFjMpW{[X~SzRyT|T{OvKrJqNsRxSyRyRxX}`}F :gLpQuV{[YTzOuHnDjChFlNtU|\`]W}PuLqLrMsMtLrImDh@eBhKrU|ZYV}QxLrIoHnIoIoIoJpLrNuOvOvNtMrMrOtPvSyTxQtHi@_;X:U9Sz8Qu5Mm5Lj3Jf2Id.B]';U-C 0 -04|ht~+/305:doyer9BH  $3,>#3I&8O*?\-Cb3Lp8S{=[<\>_AeLqW~^`]XT{T|W~V}OuFlEiLoVy[~Y}QuImGjMpW{[X~S{RzT{SzOwLsLsOuSyT{T|T{Y`: ({qOtSxX}]ZV{QwLrHnEjFkJoQvW~\]X~QvLqKpJpJpJoHlEjDiHnPwW~YW~S{PwLrJoInInHmGlInMsQwRyPwMtKrMrNtPuRxRwPsIhA`;W9T}8Qu7Np4Jg3Hc0D].AZ);Q 1G%7' 026gr|/38&)-T]fR^h"% ,(9!0D%6L)=X,B`1Jl7QwbGlRx\a_XRzQyS{S{MsGlFjMqUzZ~W|PtJmHjMoUxX~V}S{S{V}U}SzQxQwSyV|W~WWZ_{(myRxUyY}][X~UzQvKqGkEiGkKpQwW}[Y}RuJnGlGlHmInImHmIoNsSyV}U}RzOwMsKqKoKoJnGlEjGlLqRwTzQwLsJpLrPuQvRuMoHg?\8S}1Jr/Fl-Cd-B_+>W*fpzYeo $( *'7 /B$5K)=W+A^0Hj4Ot:WbEkPv[`^XQyPxRzRyMrGlFkMrUzY~W|QuLoIkLnRuTzT{SzT|WXW~V|W|Y}[ZZY\_mZSxTxVzZ~ZZX}TyMrHlEiDiEkJpQwX|X{PsGjBfDhFkHmJoLrNsPuRwRxQxOwLtJqJoJnKoKoHmEjFjKoRvUzRxLsJpMtSyQtJj@B457235CEGu[DdJlKnOsUz^a^WRzRzT{SyMsGmGlLqRxU{SyNtJoHlJnKpKqJqKrNvRzRyQwRvY{_a^ZZ]p?5kLoKnLpOsQvRxRwNrImFjEjEkIoOuUyTxMqDiBfFjJnKoLqNsNtMrKqNsRxTzPvKqInJpKrKsJrIpJpQuX|[X~QxOvQyV}Ij0Fc*(()WXXbei*+, 8;=lu8beh#$% !"X[^~|luDJP&)-,05^hrQ[e!% ,'8.B"2I';U*A^2Ln:V{FdLlQrOqOsRwX~]\ZVVV~SzKsElEkKpQvRxOuKqJpKqNtNtMsKqLrMuOvNuMsPtWy\~^\Z[gp(^WwEhGkJnMqNrMqJnFjGmLrPwRxSwSwQuKpGkGlJoLrLsKrJqHoHnLrTzXSzJpDjFlLrPvPvLsJqJqOuV|[[XV~WXIj2Hg"+:GJM8:< 68:JLOEGJ?AD@BD?AD?AD?BD@BE@CGAEIAEI@DH@DH?CH?BF?BF>BF>AF>AE=AE=AD=AD=@D<@D<@D<@C<@D<@E;@E;?C:>C:>B9=B9=B9=B9=B8=A8=A8C%6-(#           ! -&5-> /B#4K%7P';W'=[)Aa0Ko;XEc@Z|-@W(*/5enxS\f!% )#4)> 1H(X/Db.Ee)>^"3L%8'%(+(#            $'6!/@%6K'9O*>Y+@^-Df-Fi1Lr:XHiPrIg4Jd%2+17dmvS\f!% )#4)>0H';V+A`.Gk/Iq3O}9V@aFiJpKrKqJqMtQyT|S{OxLsKrOtUyY|W{RvMsKrLrMsLrIpGmFlJpQvV|V}S{RzU|W|TyQtOsY{RZ/Ff-Eh';[)> !#%/2648>15:-16,05,04+/2+.2+.1*-1),0),/(+.+/1-15*-/ " '7"2F'9P(;T+@]+Aa-Ei.Gn2Ox>]LoUyMl6Mi'4,28dmvS\f!% *$5*?/G%9U*@_.Hk1Kr6R;YCdHlLsLsKqJpKrOwS{U}U}SzQwPuSvVyWzTyPvNuNuOuMsKqIoIoLrQwT{T|U|W~[\X|RvOtj<.uRvLqMrNsMqGkAfBhIpRyV|V|W}Z\\ZW}SxMrHmEkGmLrRyV}T{NtHoHnKqNsMrIoElEmJqRyZ`_[VS{QyBc-Ce(7@BF456 '#4+?#4L*>Y.Ed,De$8U"5*,-OSVosxx}rw|insjotkptjptjpujpujoujouiougmsov|u|mtzNSW(*,  &7#3G':R(;U+?]*@a,Eh.Gn3Oy>^MoTxKj5Kg&4,28dmvS\f!% *%6+@/G$8T)?^/Il2Mt7U=[DfJnMsLsLrKqMsPxU}Y[YTzOtNsQuTxTyRxQwPwPvNtMsMrMrOtPwQyRzV}\ba[UyX||.^]~InKoMqMpFjAeBhJpSzW~XY]_][X~TzOtIoFmJqPwV}V~RyLsHoIoLrNsLqHnEkFlJpQxY^_\YV}SzCd-Ce(7@BF456 )$6,B$6O,@]1Hh.Fg%:W$6GJLBFJ (:$5L)=W*?[-Cb.Ef0Io1Mu6TAbOrUyJj4Ki&4,19dmvS\f!% +&7+@/G%8T*@^0Jl3Nt7U<\DfInMtMtMsLsOvRzW[][U{NtKpMqOsQuQvQwQxPwOuOtOtPuPvNuNvQxY~agd^X|h^BfImKnMpMnEhAeDjMsV}YY[^_][X~U{OuJpIoMtT{YW~PxJqGoJqNtNtKqHmEjFlJpQxX]^]ZXU|De-Ce(7@CF456 )$7,B$6O-A^1Hi/Gh&:X%8'X\_PUZ!(;$5M)=Y+@].Ee/Gi2Mr5Qx9WBcMpQuFe1Gf%3,17dmvS]f!% +&7+@/G%8T*@^0Il2Ms7T;[DfInMuMuNvNuPxS{WZ\YSzMsJpJoKpMqNsPuQxQxQwQwQwPvNuLsLsQx[die^Y~qBryInKoLpKnEhCfHmRwYZXY^`^\YTzMsInHoOvW~[V|MsGmGnKrOvOuKqHmFkGlKpQxX\]\[XU}Df.De(7ACF456 -':.E%7R-Ba3Kl1Jl'=Z&: (]`dUZ`%+@&8R+@^.Dc1Jk3Lo6Rx9V~=\DeJnKoA`/Dd#2+17emvT]f"% ,&7*?/F&9T+@^0Hk1Kq5R}<[EgKpOwOxQyQxRySzT|W~XW~RyMtIpHnGlHlKoNsRwSySyTzTzQxMuJrMsSx]eic^YrYRuKpLpIlEhEhMpVzZXV|V}[^_^ZSyJpEjFkNsW|YTzKpEkGmLsPwOuKqHnGlHmKqQwX~\]ZYW~T}Df.Dd(6ACF457 !1*? 0I&8U.Cc4Ln3Lo*@^(< )adhX^c* 0G)\,Bb"1+17envT]f"% ,%7*?/F&9T*@^/Gi0Io4Pz=ZGiMrQyQzS|T{SzRyQxRyT{T{QxMtIoFkDhDhHlMrQvRwSxTzU|RyNuKrNtUz\bda]`Y;gJpKpHmEjGjOrW{YU|RxRxW}\__[RyHnAgBgKpTyW|QwInEkHnNtQwNtJpHoHnIoLqRwX~\[XWV}T{Ce,Bc'6ACF567 $': 0H$6Q)=[0Fh6Pt7Pu-Dd+@",fik]cf""1&8R.De2Jn4Lq8Ry:V|>]?_@`AdBgCh>]-Cd"1+18fnvT^f"% -&7+? 0F':U+@_/Gj0Io5Pz>[IjPtSzS|U}V}U{QxMtMtOvRxPvLrGmCh@c@dFjLqPuOuPuSxV|T|PwMtPvU{[_`^\u;*y}UyKqHnEkGlMrUzW}SyOvPvU{[^^ZRyGmAfAfJnSwU{PvIoGlJoOtPvMsJpIoHoIpLrRxX~[[WWV~S{Bc+Ab'6ACF567 )+@$5O(;X-Aa3Jm8Rx9Sz/Fg*?$[]^SX[#2+>Y4Km7Pw6Pw9U~`>bAfEi?_/Ff#2+18fnwU^f"% +'7-A!2I(a@dDjJpDd2Ji%4+28fowU]f"%  -(8/B$5K+?Z/Ec4Lo4Nt8T>]GiMqQwSzV|W}U{QwLsJqJpJqJpHnEkAf>bAdJmQvQwLrJoMsSzU|R{PxQyV}]^\X~lQ2rMrJpFkEjGmMsRxQwOuQwW}\\YS{LsEkBgChKoRwTyOuJpJoMrOuOvMtKrJqIoHnKqQwW[ZXYXU|Dd+Ac'7BDH678 "5"4P)?_/Fh4Kn9Sy=ZAB !" )=0Fg:T}=Z;Y<]>^@a@b@bDiKqPwJj6Ll&5,28fnwU]f"% !.*: 0D$6L,@[0Fd4Mp5Ov9V>]GiMrRwTzV|V|TzQwMsKqIpHoGnGnGmEjCgFiMqTyU{PvMsMsQxRyPxOwRzY`a\U{t2aUxKpFlCiFlLrRwRwPvRxX~\[V|OuHnCh@fBgIoPvRwNtJpKpOtQxPxNvLsKrIoGmJpQwW~ZZXXWT|De,Ad(8CEI78: '=&;[.Fj3Lq6Pu:V~>\=\5Py%:X#5 !"* '1%/#,",","+","*!*!)!*!*"+$-% /$6Q3Ms:X<]<]?aAcDfDfEgLpRyXOp9On'5,28fnwU]f"%  %4-?!2H%7O+A]/Ge3Mq4Ov7U>]IkPuU{U|V|U{RyOvMsKqIoHmGlHnKpKoImJnOtV|XU}QxNuMtLsKrMtSz[aa[[aEiKpGmDjGmNtSxSxQvRwV|ZY~TzMsGlAf>d@fGmOtPvMrJpMrPwRyQyNvLsJqHnGmJpQwW~YYXXU~RyBc+Ac)8FHK:;< +C*Ac3Ls5Px7Ry;X=\=]9X0Kr&<[ 2K!3J&7O);T':Q%7O#5L"4K"3J!2I 1G 0F 1G!2H"2I!1H 0G,B+?-B%9T.Fi6T8X:[;^?cCfFiFiHkQuX~]Su:Qo'5,28fnwU^f"% $(90D"4L%7Q+A^.Ff2Lp1Lt5R~=\JmTyXWW~T{QwNtKrJpIoHmHmKpPuPuNrLpNsTzYYU}OvIpDkDkJpTz\`_[pE&rY|HnGmIoPuSxRxPuOtSxW|W|TyNsHmAg>d?eFlMsOtLqJoMsQxSzRyOuLrIoGmGmKpRwV}XYYYT|Ov@`*@`(7CFI89;$ 1K0Io8T~;V:V[cGlTyZ]\ir&MgIpIpJqPvRxRwOsMrPuUzW|VzQuJoDi?e@fFmMsMsIoGmKrQxT{SyOuKqHnGmHmLqQwU|VXYZU|Nu>_(=\ -777tstilm-.. "4N4Ow\]>^@bAcAeAeChJoRvVzV{UzSwPtMqHkCgAeCfGhGhEfBbAbAcCeDfBe?cdAhCiEjFlJpSyX~]Rt:Rp(6-29gnwU]f"' / 0G&9S(=X(>Z,Dd.Gj/Ip-Hr0My8WGiRwXXT|NuHoGnHoJpIoInJnNrSxSyOuKpJpNuSzU}RzJq@f:_<`EjSwX}ZY~tM!uMsJqKrNuRwRwOsLpMrSwW{W{RwMqGlChCiHnMsLrGmElIqQxU{UzPuKpHnGmInMrQwT{U}VXZW}QwAa*?_)!!!GGGkkk|||}}}}}}}}}}}}|}}|}}{|}{|}z|}|}~{|~|}egi@AB"%8U7U@aBb@^AbAbCdCfCiDjHoOvV|Z[\\ZW~RyKsHpIpKrMrLqJoInJoJoHnGmEkCkEmFnFnElEkFmKqRxV|ZPr9Po(7-29fnvT\e#' $6#6P*?\,B`,Cb/Ij0Jo/Ks.It1N{8WCeMrT{V~QyIoCiDjInLrLrKpKoLqNsNtLrKqKrNuQxQxNuGm?e;_=aFjOtUzV{Y}u!RbKrLsNuRwTwOrKnLoQuV{W{SxOsJoGlFlJpLsKqFmElJqQxV|UzQtKpInHnJpNtRyT{T|U}W~ZY~UzFg0Hj#5...888:::787444445445445444444344344344334344344556345*++ /(>^9X@cCeBbCeDfEhEiDiDhFkKpOuSyV}Y[ZWS{MuHpGnIoLqMrMrLpIoGlFkGmHoJsMvOwNvJqGnGoKrQwU{X~Np8Po)8/5;ls|X`i!%) (<':W,Bb-Ef.Fg3Mq4Ou3Ow1Mx3P8W?aFkOtRxOuGlAfChJoOuOvMrKoImHmGmHnKrNuPxPwMtJqFlAf?cBfHlOsSwTxiR-Y}NuPvSwUwNqIlIlNrSxUzRwPtMrKpJoJpKqJpGnHnLsQxUzTxPsKoHmHnLrPwT{T|S{T{W|Z~Y~V{Lnow[cl#'-#.E*Aa.Gj/Hl1Kn7Sx:V}9W6T6U8X<_CfJnNsMrGlChEiKpQvQwNsJoFkDiDkGoMtQyQyNuKrJpHnFjDhFiHlNrRv_-WjOuPvRwTwNqIkHjLoQuSxQwOtNsMrKpJpJoIoIoKqMtQwRwQuNrJnGlGmLrRyV}V}T{T{V|X}W{TxNrGi>\9T~5Nu4Ms2Mr3Ot7Rv;UxaChInLqLqInGkHlKpOtPuMrImEjDjFmKrPxRzPwLsKqLqMqKoGkFiGkMqRunW&zUyQvSxSxOtJmHjJlOsRwQwOuNsMrKpJoInInKpMsOuPvPuNsLpImEkElKrSzX~W~T|T{U|UzQvNsMrMrMrNrMrJpHoIqPwW}X~W}V{SyOsHlFkLpQuPrGi@b?aBfEiGkGkGjDhChDjGmJpLrLsLrJoGlFkEiEjEkIoOvU|U}R{OwNuNsMsMsMsLsJrGnDkFlLqQwTzRyPxQyU}X~U{QwOvRxW}XKm5Lj$2)-3_fmLT[ "'$7R1Ls2Oy1Mw3Nv=ZDbFgBc>`=`BfHmLqLrKpJoJnJoKpLqMrJpHmFkFmJqOwSzRyNtJpKpOsQuPsJnEiFjKoUxz&QkRxU{V}SyOrJlJlMqPvPwOuMrKpInGmGlHmKpNsQwRxPvNsKpGlDjDkKqSzXW~U|T{T{QwLqJoKpLqMqMqLqHoEmGnOvW}ZZZYTzMsKqQxW}U{LqDiAgCiGlKpMrKoHmFlFmIoKrMsMtKrIoFlEkEkGmHnKqOuSzS{OxKsJrMtPvQwOvLsIpFmFmKqQvTzT{PwMuMuQyV}W}TzPvPvSyU{Ik2Ih ."BGLjqy}}}}|{~y]en5:?'&:W5R{8V5R~4PyEIOHMSEIO@EJ@EK@EK@EK@EJ?EI@FKAGMCHO=CI/38 "3*Ab_:Y6T;YAaHkJnKnJnMsQwSzRyNuLsLrLrLrLrKrKqJqJqKrNuQxRyPvLrJpLqRuWy[|WyQsKo\}x'N]\X~SxOqMnKnMrMtLtIpFkChBhDiFlIoMsRyU}S{NtInEkEkGnMtRzT|T|S{S{RyOvMrMsOtOsMpLnJnEk@fAfInTyZ[YUzPtJoInPwW}V}MsDh@d@dCgGlJoLrMsKrIqHpLtOwPxNvKsHoGoKsPwSyQvNsMsLsKsHpGoKrPxRyPwKrIoJpOuSxRxOuMrKrKrLsMuRyV|U|OvIpGnIoEh6S~"4O .&%.!)3'0%/$.$.#,!+ ))!)!)(%.F0JnAbEfAa;Y;[?`EhKnNqMpMrNuQxSzQyPwNuMtMtMtMtMsMsLsLtNuOwOwNuLsKqNrSuXz\}Z|UxOssNpmZV|TxQtPrLoKpKqIpFmCiAgBhFkHnJpLsQxS|RzMsHmEjElIpOvS{S{QxPxRzT{SzRxRxSxRvOrMqLqHmChBgInU{]_[TzNtKpLrT|ZYOvGlChDiFkInKpLqLrJpIpIpKtOxR{QyMuIpHpNuT{W~TyNtKqJpJqJqJqMtPxQxNtJoInMrSyU{QwLqInKpMrMsMsOvRyRyMuHpFmFlDi<\.Hq%:[#4N&7P*`CgImMpLpKpKqMtQxSzSzQyOwNvNuNuOuNuMuMvNvNvMuLtKsMsOtTwWyY{XzUxbpD\TyTxSwTvMrKpIoFmBi@f@fEjJpMsLsLtOwQzQxMrHmEjEkIpOwT{SzOuMtQxV}XW~V}U{RwOrNqNrJoEjCgInUz^^YQwKqIoNtW~\YOuFlDiFjHmJoJpJpKpIoIoIpLtPyS}R{NvIpIoOuV}YW}QwMsKqKqKsLtNvPwOuLrIoJoOtU{V|PvJoImLpNsNsLqLrMtMuKsJqHnGmEjAd:[8W:YC`IgJiFdB`A^B`C`@[7Rz0Ir.Gp2Ls8Ry;T{:U|9U}=[CcIlKnIlCe?a=`@dEiIlImHnHnJpMsPwRzR{QzOxNuMtMtNuNvNwNwNvLtKsLsMsPuTwTwSvQtVw~D]uRxUzWzVzPtLqHnDj@f=c?eEkMsQxQxOwOxQyQwNsImEiChGmNuT{SyNsKqNuU}ZZXT{PvMrNrOsLqGlEjKpU{]]V}MtGnGnNtX^YNtEjCgFjHnJpJpJpJqIoHnHoKsOyS}RzMtInJoPuV}ZYV}RxNtKqKrLtNvOwOuMrKpLqPvUzUzPuLpKoMqNsMrKoInHnHoHpJpJpIoHnGlEkFlKqU|^^X~QwOuT{ZX~NrCf?`CeKnPsOsKpJmJnKnKoGkBf>b<`>bAeEgGkInHnInInLrOvRzR{PxMtKqKqLtNwOxNvMtLsNtOvOuOtQuOsMpJmm]1`W|Y}W{RvMsHnEj@f=b=bBiLsSzU}S{RzRzSxPtKoEiBgFlMtTzSyMrIoLsT{ZZW~RyMtKqMrOtNrJnHmMsV}\[T{KrElFmMsX~]YMsChAeDiHnJqJqJrKrJpHmFlHpNwR{QxLrImKpPvV}Z[ZW~QxLrJqKsMvPxPwOuNsOtQvSxRxPuNsMsMsLrKpInGkDjDjFlInKpKpNtNtMtKrMuT}]^V|MsJpQxY\T{IoCgEiLqRxSyQwNsKpImGjAf>b;`;`<`>aAdEiHnJoHnGlHmKqNvOwNvKrIpJpLsOwPwMtKqLrPvSySxOtMrJoHlUu1T_Z~X|SwOtIoGlCh?d=b@fIoRyW~V~T|T{TyQvLpFkChFlMsRxQwLqHoKrRzXYV~QyLsIpLqOtNsKoIoNuW~\ZSyJqDkDkKqU{[W}LqBg?dBhGnJrJsLtMtKpGkChElKtPyPwLqImLqQwV|Y[[YTzMsJqKsNwRzRzQwPuPuQvQwPvOvOvNuLtIqHoGmEjBg@eChGlKpOtSyT|S{OxMvR{Y[V|LrHmLsV~[V~LrDhChIoPwSyQwNsKpFkBgbDgInJpHnFlHmJoKqKrJrJqJqKrNuQxPwLrInKoRvX|Y}RwLrHmLowT*tuZX}SyOuKqIoFlCg?d?dEkNuU|W~U|TzSyPvLqGmDjGmMrPvOtJpHnKrQyVXVRzLsIoJpMrMrJoIoNuW~\ZSyIpDkCjHoRxX~V{LqBg?eBiGoKsLtMvNuKqEjAfCiIqPxQwMsJoMqQwU{X~Z[ZTzNtLrMuR{V~V}SyPuOtPuOuOuOvOwMvJsGpFoFnDj@e>cBeGjLpPuT{V~U}PyLuMwR{W~U|OuIoKrQyW~T{KqBhAgGnOwRyPuJoFjBg>c:`;a=c?d>c<`>bCgInKqJpIoJpKpIoGnGnHqKtNvPxRyQwMrJnKoRvZ~\V|NtHnbt*3fXU|QxMsKqInGlChAgCjJqQxU{TzRxPvMtJqGnDkFlJpNsNrJnHmJqPxU~XXT{NuJpJpLrKqInIoOvX]ZRyIpCjBiFlOuU{TyKpBh@gCkHqLuMvNwNvKqEjAfBhHpOwQxOuLqMrPvTzW}Y~Y~W|RxNuNuQyVYXTzPuNsNsMrMsMtMuJsGqEoFoGoDj?d=`@dFjLpOuRxT{V}RzMuKsMvRzV}T{QwPvRzU}SzLrEkDkJrQyRyOtHlBf?c=bgDmJsNuOvPvPwNuIpEkCiDkHoKsMtMsLsNuQxRyPwLsKrMtOwOxOwNvOwQxSySxQuNsMqMsNtLrGnBi@hBjElFkBg@eAhEmJqMtOvRxSzSyQvNtLrKrLtQxU}XXU|QxOuQvSySyPwKsGoEmEmFmGmFlEjDjElFmFmGmGlHmHmIoLrPwU}YYU}MuHoElGnNtU{X~W}SyU|Z^u3OjOvOuPwRyQzNwKsJqKsNvOwPxNuKqImEhAdAeGkNtRyQwMtLsNvQxSzT|U|U}U|RyMtGnDlIqSzZYSyNtLqJoHnGmJoLqHnAg=d?gEmIqLsMsOuPwNvJrEmAiBiFmJrMuLtKrLsOwQyOwKsJrNuRyRzPwMtLsNuRxTySxPuNsMsMsLrHnDjAgBiEkFlDiBgCjHoNuRyT{U|U|SzRyRwQvNtLsMuQyV}W~U{PvMsOtRxSyPwKrGnElFmGnGmEjBg@fAgBiDjEkFmHoHnIoKqOuS{WXT}OvJpGmHnMsTzV|U{RyT{YtO!eY~PvRxS{RzOxKsJrKsLtNuOvOtMrKnFjCfCgJnRxW}T{OvLsOvRzT|T|S{SzSzPwKqEkCjJqT|[YRyLsIpHnInInKpLqGmAg?eBiGnIqJqJqMtOwOwKtEmAiBiFnKsNvLtJrJrNvPyOxLuKtNvRyT{RxNuMsNuRxV{V{RxMtKqJpJoHmFkCiCjFlFlEjChEkKrRyV|W}V}U|T{T{U{UzQwLsKrNtSzV|SyMsInJoNsQvPvMrIoFlFlFlFlCh?e>c?d@fBgDjGnJrKrJqIoLrPwT|VU}PwLrJoKpNsRxRxRxRwUzae!$tX|RxSzQyOwKsKrLrKrKrLsNsMrKoFjBfCgKpV{[X~QwLsNuRzS{S{QxPwOvLsGnChChKqV}][RyJrFmElGmJoMsMsHnChAgEkJpKrJqIpKsOwOyLuFoBjCjGnLtNvMuLsLsNvPxOxLuKsLtPwSzSyPvNtNuRxV|W}TzNuIpGmGlHlHmGlGmHnHnEkCiGlNtU{V|UzRxRySzV}YX}RwKqIoKqQwSyQvKpFkFkJnMrOtNsKpHmGlGlFlCiAf@eAeBfChEkJqNvNuKrHnIoMtS{V~U}QxNtLrNsOuPvOuPuRw^t$W~:uPvQwOvLsKrMsLrKpIoJpMrMrKpFjAeBfLpX|^ZQwLrNuQyRyQxOuNuNtJqFkBgBhKpW}_]SzJqDlCjElIpNuOvKqDjBgFlLrMtKrIpJrOwPyMwHqElDlGoJsLuMuOuPvQwPwMvJsHpIpLtQwSyPvMsMsPvU{X~W}PxIqFlFkImJoJoJpKqHnDjBhGlOtUzUyPuLqLrPwW~\ZRvInGlKpQvQvNsIoGlGlHmJnLqNrMqKoJnIoIoGmEjDiDhDiEjGmLrPvOuKqHmHnKsPxT|T|RyOuOtQvPvOuMsNtRw|:W~;mPuNtLrLrOtMrJoHmJoLrMsKpEjAdBfLpY}_[SxMsOuQxQwOuMsNtNtKqGlChDiLqX|`^UzJqDkBiDlHqNwPxLsEjBgGlMrNuLsIpKqOvQxNwJsGoEnGoHpJrMsQvTySyOvKsGoFmGnKrPwRxOuKqIoLrQwW}XT{MtIoInKpMsNtNtLsHnCiBhFlNsSxRvMqGkGlNtX~^[QuGlFjKoQuPuLrJpKpLpJnHlImLpNqNqMrNsMtLsJqHnGlFkFlInLrOuNsKpHnIpLsNvNwOxPxQxQwTxQwOuMsNso; PeNrMsNtOuNsLqInKqMsMsKpEjBeDgMqY}_[TzPvRxSyQwOtMsNtNuMrInFjFkMrY}b`WzLpEkBiDlGpMvPxLrEjBgFlLrNtLrJpKqOuPwNvJsHpGoGoHoIoMrQwTzSyNtHoDkDkGnLsQxRyOvJqGnHnMsSyW~W}RxNtMsNtQwQxQxNuHnCiAhDkKqQuPtKoFjGkOtY~^[PvGlFjLoQuPuMsMsPvQvMqHlGkJnMpNqOsPvQxQxOvLsHnEkEjGlKpNrMqJoJoLrNtLtJrJsNvS{SzSyRwPvNteP S_OtQwRxPvOtLqLrMsLrJpGkDgFiOsZ~_\U|RyTzUzRxPuNuOuOuNtLqInInOtZ~bbYzNqFkCjDmHqMvPwLrFjChGlLqLrKqJoLqOuOvLtIrHqHqHqIpJoMrQvSyQxLrGlDjFlJpOvSzT|QyMtHoGnIoNtTyV|U{SyRxRyT|T}S{OvHpCjBiDlJqOtOsLpInLqRxY]ZRxJoHlKoPuPwPwQxSySxNrImGlJnMpNqOsPvQyQyQxNuIpDkCiFkKpNsMrLqMrQvQwMsHoGoLuT|U}U|RyPvaSg_SyTzRxOuMsLsLrKqJoGlEiGkOsZ~_]V~SzSzTzRxQxQxQxQwPvPtNrMqPvY~a`XzMpGkDkFnIrOwQxNsHlEiGlKpLqKpKqMsOvNvKsHpGqHrIrJqKpMrQvRyQwKqGmGlJoNtQxU|V~T|QyLsHoHnJpOtSxUzU{U{U}V~V~S|OwIrFnEmGoKrNuOtNsNtRxV|YYX~UzOuKpKqOuRyS{TzSyQvMqJnJoLqOsOsOtOuOuNvNvMuJqElDjGmLrPvOuMsPuUyVzQvJpFmIqPyU~V~S{_g$jaV|TzQvNsNsLqJpJoHmFjGkOtZ`^WQyPwPvQwSzT|T{RxQvQvQuPtQwW}]]VzLqFkEkGoLtRzU{QvInEjFlJpLrLrLsNuOwMuJrHqHqIrJsJqKpMrQvTySxOtMrMrPvSyT{U}V~WT}PxLrJoJoLqNsPuRxT{V~WU}RzNwKtIrJrKsMtPvQwQwRxU|V}U|UzV{W|UzPvMtOvT{W~W}SxOrKoKpNsPvRwRwQvOtKqIpIqKsLsJqJpMsQwSyQxOvRxX}Z~VzNsHnGoNvT|V~`j$,}cTzPvMrJpJoKpLqJoGkFkMsYa_WOwLsLsNvT{WV}RxPuQuRuPuPvTzYZTzKqEkDkHpNvU}X~RxInChDjHoLrMtMtNuNvLuJrIqIrIrIrIqIpLrPvTyV{UzTyTyU|V}V|U|V}WV~T{QvOsNsNrLqKpMsQwU|U|RyNvMvMvMvMuMuOuRxTzTzT{U|T{QxPvSxW}Y~T{OvOwU|ZZ~TwMpJnLqQwSzT{T{RyOuJoEkDkHoMtOvQwSyU{V|SzQxSzX~[W|OtGmGmLsQy`},3{aNtJpInInLqNtLqHmFkMsX`_WOvJqJqNuT|XV~QwMrNrOsNsNtRyX[V|MsElCkGoNvV}W~QvGl@fAhGnLsMtMtLtLuKtKrJrJrIrHqHqIqJrNuSxW|Z~ZZZYW}U{T{U|V}V}UzUyTyRvMrInJoNtQxQxMtKrKsLuMvLtLrNtSyW}W~V}T{QyOvNtQwW}ZV~OwNvT{\]VxMoJnNtS{U}U}T|S{QwKqEjCiGnNuS{V}W}V|V{SyRxSzV}YV|OtInHmKp^{38^InHmHmJoMrLrInGlLsW~^]W~PvMsMtPwU}XU|NuJoJoJoJoKrRxZ^ZPwHoDlFoLuT{U{NsCi>eAhHoLsLtKsJsJsKsLsLsLsIrHqHqIrJrLsPvW|\^^\YV|TyRxRyT{W}X~ZY~V{PuKpIoKrMtMtJqHpJrKsJqHnGmKpRxX~YV}T{QxPvOvRyW~ZV~NvLtSz\]VxMoJnOuT}V~U}S|SzRyOtJnGlIoOvU}XW}TyRwQvPvQxSzT{RyOuLqJo]~8:`HmGlHmJpKpJoHnMtV~\[V}RxQwQxSzV~V~RyLrGmFlGlGmKqSy]b^U{LrFnGoLtQxQwJoAg?eCjJqLsLsJsIsIsKsMtNuNtKsIrIrKsKrLsPvW}]`_\YW|TyQwPwRyV|Y\[X}RxNsKqKrKrJqHpHpIqIpFlBgBgGmQwW}YW}U|SzRyRyT{XZU}MtKrQxZ[SwKoJoPwV~WT|QxPwQxQwOtLqMrQxV}XU{QvNsNrNsQvPwPwPxPwOud: :gGlFkGmHnGmHoNuV~\ZV}SzSyS{T|V~U|QwJqFmFlFlGmKqT{^c_W}OuJqJrLuPwNuHnBgAfFlLrNtLtKtJtJuLuNuPvOvMtKsKsMsMsNtQxX~]_^[YX~V|RxOvOvSzX~[[X}SyOvLsKrJqJrJrJrJqGmCh>c?dEkNtT{W}V|U{TzSzU{V}XYT{LsJpPvW}X}QvKoKqQxV~V}RyMtLrOuRxRwQvQvU{YYTzOtLpLpMqOtOuOuPwQxo: 8{pNrElElFmIoPwZ][W~SzQyQyRzT|SzOvJqGnHnHnHoLrT{]b_W~PwLtLuNwPxNuIoDjDjIoNtOuNuLuLvMvNvOwQxPwNvMtMsNsNsOtSyY]]ZX~Y[ZU{OvKsNuT{ZYU{QwNuMtLsLsLtKsKsIpFkBf?c@eFkMsSxV{UzTzRyTzV}WXWSzMsJoMsSyUzQuMqNtSzV~T{OuIoHmLqQvRwQvRwW{[ZUzPuOsNqOsPuOuOuW}x{83}xOtEkElIpRy\a^WQyMvNvPxRzRyNuJqHoJqJqJqLtT{]b_W~OwLuMwOxPxNuJpGmGmKqNuPvOvNvNwOxOxOwOwOvNvOuOtOsNrOtSzZ\[W|U{X\\W~NuHoJpPvW|X}SyNuLsMtNuNuMuKsJrHoEkBgAfDiInOtSxVzTyRwPwSzW~XWV}RyMsInJoOuRwQuOsQwT|U|QxKqFkEjJoOuQvPtPtSxX}X}UzRwRvRwSxSxRwZ~}3,j^FlJqTz_daYPyLuMuOvQxPvKrGnGnJqKrKrMuT|^daWNwKuMwOyOxMtJpHoIpLsOwPxOwOvPwQxQxOwNvMuNuOuPuOtLqMsRxZ]ZU|SzV~[]XOvGmFkLqTxV{RxMtKsOvRyPwMtIqGoFmEkCiDjInNsSxW{W{TyPvPwT|XXVU}RyMsHmGlKpOrPsQtSyU|SzNuInEiEiJnOtQvMrJnKoOtSyUySxUzW|X~W}lj,$gbKqU{`daYRzNwOwQxRxMsGmCiDkIoKqLrNuU}_fcXNwIsKuMwNwLsJpIoJqMuPyQyPwOuPvQxQyPxNvMtMtPuPvNtKqLqQwY][W~T|V~Y]ZQwGlDhImQuTxQvLsMtRzV}SzLsFmDkEkEkEkGmLrRxX}[Y~TyPvPwU}YXVU}SzNtHmDiFjImMpQtTyU{RxMsInGjGkJoPtQvLpDiAfEkLrQwTyV|Y[sg$Sv[_b`ZV~U|U|TzQwKpCi@eChHmKpLqOuV}`fcYNxIsJtLuMvLsJpIoKrOwR{R{PwOtOtQwRzQzPxNuOtPuPuMrIoJoOuW|[[XV~V~X\\UzJoEiGkMqPuOtLsPwW~ZV|NtFlDjEkFlFmHnMsTz[][U{RySzV~YXWVU}QwJoDiBfDhInPuVzV{QwMrKoKnKnKoNsOtJoCg>b@fGnOvTzW}^SPh_]ZXW~W~U|QwIoChAfDiImKoMqPuW}`ebYPxKtKuMvNwMuKrKqLsPxS|S{PwNsNsPwRzS|S{QxQvPvOtKpGlGlLpQvUzW}W~WV~W\^Y~PtImHlKoMqMrMsRyY[W}OuIoFlGmGnGmHoMsSzZ\\XV}V}XYYYYXT{MsFkCgDiJoRwW|V{RwOsNrOrOrLpLpLqInCg>b?eFmOvU{dP ;vaYYXX~U{RwJoDjEjHmKpLpNqRvY~`c`X~QxOvPxQyQyOvNtLsMtPxT{T{QwMsMsOvRzT|T|SzQxOuLrHmDiEiHlLpOsQwSyS{S{U~Z_]VzOsKoJoJpMrPvU{XW~TzPwNuMtLsJqIoIoLsRxW~[]]\ZYYY[[[X~RxLqHnIoNtTyX|W|SxPtPtQuPtLqJoKoHmFjCgBfFlTyq; :tfXXV}SzOuIoGmHnKqNsNrOsSw[ac^V|QwQxT{T{RzPwNuLsMsOvRySzQwNtMtNvQySzT{RzPwLsHnEjCgDgGjKnMpNsNsNuOvR{Y^`\TyNtKpKpOtSyV}U|RxOvPwSzU|S{OvJpHnJpOuU|Y^``][YZ\]]ZV}RyPwPwRyUzV{VzTyQvPuPuPtLrIoHmInImGkEiVw~t:Gm$ez]U|RxMtIoGmKqOtPwOtOtSx[bc\SzOvQxT{T{QxMtLrKqKrMtPwRyPwNuMtNuOvPwQxOwLsHoEkChCgEhIlNqPsOsLqJpKrPwW~^a_Y~RxNtNtRxV}W~TzOuMsPwV~[ZT{LrGlHnMtT{Z^`a_\ZZ\]]\ZXV~T|SzRwSwTxTyQwPvQuRvNtKqHnHnJoPsme$W~!OdPvLrGmEkGnLsPvOuNtQwYab[PyLtNvRzQxMtIpHoIoKqMtOvPxPwNuMtLtLtMtMuKsGoDkChDhEiIlNqSvTxRvMqIoJpOvV}]`^YU{RySyV|XXUzQuPtSxW\\V~MtFlFlLsU}\^_`_][ZZ[\\\ZWT{QwOtPtRwTyQwNuNtPvQvNtJpHnZ}zO!3dv\}DiBhEkJqOuNtNsOuV~^`YNwIsKtOxOvJqFmElIpMsOvPwPwOvNuMtKsKsKsKrIpElCiBgEhHkMpSvW{W|UzOuLqLqPvV}\^\YW~V~W~XYYX}VzUyV|X[[WNvFmFmMtW]_^_^][YXY[\\YU}QxNtMqOsTwVzRxOvOuRwSxPv^qd3P`FiDiIoMsLrJpLrS{[]WMwHrJtNwMvIqElFmKrPwRyQxPwOvNuMtKsKsLsLsIpElCiCgEiJmPsUyY~YW}SyOuNtQxV}Z[YXXYYXXYYZ~Y~Y~XYZVOxIqHpOvX^_]]]][XWY\]\WRzOuLqKoNrRwTzSyQvQvRwY}nP3t}bUyKqJoJoLrSzY[V~MvIqKtNwMvIrFnHpNvSzT{RyPwNuNuMuMuNuNuNtKqGmDjDhFjKnQuV{Z[ZV}SzRySzV~XWWXYYXUT|U|X~Z[ZYYXU~PxLtLtQxW~[\\[[[[YXZ\][V~SzPuMqJnMqQvTzTzRw]mt3*TbMpJnNsU{YWQzKsJqMtOxMvJsHpKrPwSzSzQxNvMuNvOvOvQwQwQwNtJpFlEkGlKpPvU{Y[[YV~U}V}W~V}T|T|VYYUPzNwPwT{Y[[ZXU}QyMuLuOwRyU{V|X~Y[[[Z[[ZZZXU}QyMsJoJnMqPvSzW}iT*1]f^V|YU~NvIpIoMtQxOvIrIpKqPvSyQyNvLuLtMvOvPvQwRxRxPvLsIoHnIoMsQwU{Y[\[YYYX~T{PxPxU}YYR|KuHpIpOuV}Z\ZV}PwKrIpLsPxSzRxQwTyW}[\[[\]YW}T{S{RzOwKqJnKnMq_n]1DpraU}MtGnIoNtPwLtGnFlIoOuRxPxMuKsKtMuNuOuPuPvQwPwNuLrJpKrNuRyU{XZ[[ZZZXSzOvPwU}YWPxHpDkFlLrTzXZXRyKqFlEkJqQxS{RxOtRwW}]^\[][V}PvMtNvOwMtJpJnSujpDNxxePuIpOuPwLsFlDjHnOuTzSyNuLtKsLtMtMsMtNuOwPxOvMtKrLsOwSzU|W}XZZYYZXT{RxRyW~YU|NtFlCiEkKqQxT{U}S{NuHnDiDiKqSzV|SyPuRwY^`^\\ZSzNtKrKsLsUycpxN'QzzhW}PwLrFkDiInPvSzRyNtKrKrLsLsLsMtMuOwPyNwLsJpLrOvSyTzU{W~YYXWWW~V|V|W}XW}RwLpGkEjHmLrPwQxPxPwMtInEjFkMsU|YV}RxSyW}[]\\ZXSzOvMsTyh}zQ'&W~gZzLoJoPvSzQxMtKrKqLrLsLsNvQyR{Q{OxKsIpKqOuRxRyTzV|YYXU~T|T{U|XYXTyOsKoImHmJpMtOvNvNvPwPvMrImJnQvY\YTzRxSzW}Y[[Y]gn~W&-RureW{RxPwLsKqKqKrKrLsOwR{T}S}NxJrHoKpNtQwRxSyU{X~XXU~R{QyS{V~WV|RwOsNqMqKqLrNuPwOvOvQwRwPtKoJoPwY\ZT{QwQwSzV}XapuR-!Mrpg\UyKrJqKsOwT}VUPzLtJqLrPvRxSyTyUzV|W~WWT|SzT{V}V}T{SxRvSwQvNtMsOvQwPwPwRxSyQvMqKqPwWZXT{Z`ltrM!&Ea{i[~OuOwT}WVQzNuLsNtPwRyT{U{V{W|W}XXV~U}T|S|S{SzUzW|X}UzPvNuPvRxRwQwSyTyRwNrMrPwU}ZeoaE&2Qy{yqja\X|V{SzS{V}X~X~X}Y~YZYXV~U}V|X~[[W|RxPvRwTyWzZ}`ekmrxyQ2*;Yr{vnkggc_\[\\[XW~XZ_`_adkpw}rY;*B^^B.>>yyyHHHstu!H{{H!ttuHHHyyy>>>xxx<<<stu #Xvhbdcekr|X#stu <<<xxxwww@@@ AAAHveaV{GoIqPyNwGoBiGlIoIoOuPuJqRwXPuPrg~HAAA @@@wwwCCCGGH 233`uXyPsNsKrOvRxHn@gJqU}U{RwOuPtRxSy\ZSzW~V}KqHmOvQxX~ai`233 GGHCCChhhhkUzEkCiHmKrNuU{RxHmBgIpPxLrPuSxNsT{\X|PwS|U{NsPuV}T|Rx[YPxT|bohhhh>>>_eLqLtYSyKqLpMsHoIqRzNuFlCjIrNwIoNsTyOuW~c[InRzT|HnOtRyPyS{YT|Pw\ab\Ps__>>>jjj###vvwBeU|LuEmPw`WKsNuQwHnElOxNuBiBjNwVOwLrTzV}X_]MrQwXKqImIpMvT{TzQxNvZafcLpCiV|kBvvv###jjjIHH ~cNsMrUzQyFnRyaT}NuU{RyGlEkNwNtEkHoRzWV|LqQx__ZYOvRx_Pu@cGkSzSyQvTzPwU|_a[NsLoW|TzHn]~ IHHAABAuPuMrNqNsT{RyGmT{aS{PuX}QxChEkPwMqHmMtOvQxZUyQx_b[X}PvTycUy=aAdUyX}SxU{PvW|b_WLsJnTyU{KqKpW~pAAAB''' m[W~QwSvNnKoU}U|IoU~aPvLqUzRyEkFnPwJqFnIpHnMsX~X~V|^_V{W|SyOu^\Cg;_MrW}X~X~Ty]c_ZOwKoRwSzIoLpYQyNtm '''lll(((aBjRy^TzTySvPtW|V|IqV~^MsLqSyRxGmHoPxJqGpHpEkLrRyRyW~]\U|YW}JqY`Lo?bFmRyW~[Z[XYXS{NtRwU{FlHn\V~CjEkk(((lll"UyCjFlV|^XV}X~V{W|SyHoU|^SyTzV}PwCjGlPvJqKsLtElJqQxSzW[\Y~ZY~RvY~_Ot=aEjTzT{X]TyKqPvLsNuTzRxSyKqJoW|T{EiKmQwTz"1SxMtIoFlW~_[YX|VzQxKtHoSy\XU|T{QyDjCiLtJsIsKsIqIpMtT{V~[a`\V|Ry[_Mq;_DiW|U{RxYVzKpMsFkFkRxQwLrRxOuPuNsAeMpX}NuJq19zW}SyNuGmElX^Y[Y}PtGnHpMtQyWYV|OuNvGlCiLuJuEqGpLrJpHnPvRzXef^U{MtZ]MrbAeOtSwNrGk@b@cFjGmInIoHmFhCfImNrKnJoHmGjJlKnGkDgGiGi=`8[?cDiHlNrRxPvOuMqDhBdCeCe?b>aAfEkJrQyMrIkRvU{HpHpTzOvPvUzOuOvB%%%===cV{RwOtLtAgBeQv\PtFmHnJpQxU|RyQwVyNqDf?`?aJkLnEg;[4R7U=\?_>^>_Ac?]9V?^DcEc@_7W5S\@]:X5S~2P~5S<]FfKlHjAcHjKn@b=]?_;Z4T6WGiKoDiLrPtNqQwT{OuJpGlEkMsSwPvKrX|===jjjvww~`X{a[V|NvCjGkQuTxNrMsJqEmLsSyRzOuSwSvHi:[<\GfGe>\4Ou/Hp0Ks1Lt4Pw4Ow5Qw8Sw6Pu0Ip3Ns:Tx[9V:X=[:W|8Rw8Sx3Mw,Ht4P~FeKlGiLpQwRyPwMtQvQuJpHlKmQtW}OvGms~wwwjjkBBBBEhZ}a`^OvAgInPuNqHmLqJpEkNtYX~SxVzTxFh4U5TC`?[4Mp+@a(<['<[%;[*?_+A`*@_+A_*?]&:Z*?^.C_,A]-B^*>\&;X(=Z)=[);Y';X'[+@](=\%:Z.Ef4Lm1Il5Mp5Ln0Ij1Ii-Ec+A^0Fd/Eg+Ch3Mt>[GgLmMrJqHnBhAePsU{U|UyKmLp[SyHoS{BBBBDDDLnKn^_``NuBfJnQuKnFkHnInEjLs]^SxSwOsGk<^;[Ca>Xy2Ih&7T!1K$4M 1K#4M%6N"4M#4M"2L0I$5M%6L#3I#4K"3J#4K$5L#3K!0H 0H#4J#4J!2J!2I 1I"4N%7S(;X-@]-@\*?Z+?Y%6O-F"3L)cHmQwXXIpJpX~X}PvKsW|DDDuuu_g?dUxgda`QvEiJnOsHmFkIoIoDjKr\[QvRvOs<[,Fn,Ce.D_':P.A0&'''''''%'&%&$$&&$$%%%*#4';'<$5/-..& ),C(;V/Ee9Qv?\?`>dFlHjGkHnGmPw]U~NvV{W}V|ZRxDlf_uuu===HnDiVzif^ZLrGlNrNtJpGlIoHoEmU}_V}OtVzNo'8"'/"'.$)"&$"""!!!!!!  !!!      # /&  '$# & ')A&9U3Jl8T{:[;_FjNrKnImPwZ[RxSy^ZSy\TzElKs===uuuh\}GnJoSwcb[SzJpJoLqNtU{OtEkCkIq]`X}QtRvFd'Z_c#).  h{r 3.G*A_2Nr=]EhHoLqCg@cPwYWU{U{[ZV|`TzElQxkhuuu;;;KpInInRv\aZQwNtJmAeLqZTyGlEkNt\[[VyPr@]'518A$ %  0,C*?]2Mr<\FjGmFl@d=bMsU~V~\YW~YX~b`OvX|^;;;===`dKqEiEjPtW}^SyMtPwEj>bNtYRxLrJpPu\YSwTyV|A`'5/6>BMXm$*k! &6"2H/Da5Qu7V?bBgFkKqIpQxT{MrV|ZTzX}Y~^e]W}Wi`===vvv|||PuLqEjGlSwUyW|NtLtOwEkBfNuYRyIoFlLsZW~LrSy\Dd'Y]`}zzzzvcsYgx$+2i|" +<'9P3Jg=X|>]EgGmMsU{SzSzOuHnNtW}QtNqRxV|^_QzLvU||||vvvHpPvMrInLoZzY{UzTzRxPwLrFlMsZRyInDiLs[SzLsW}\Il)= "(1$+3!'/$",/3.26+/3,/3+.3+.2*.2*.3)-2)-2).2(.2(-2(-1',1',1',1&,1&+1&+0(.5##(k|#)/k~# !/D-A[9Rr?\?_ImMrQvU{RyNtNsSyQxU|MrDgKpRvU{YJtCjPwwHwwwwww ]QvPuOtKoXy[~W~YPuLqOuKpPuXRwLoFkNu_T{Mt[aX~Hg5R5T~BbY|9V4UDiNtPsRvQxPwTzXS{LtIoMqPuQxLsPwLsAgTxcwww www;;;$PtHlKpRwPuUyW{X~U|NsMrNrLpPvU{RuOrJnMrZU|Px^f_V|LrMsZY}%7QKRZ',3y")0&]8X=_HmBg=aHmPvMsOtRxPvTwZ~W|X}`__W}SyMrbXvvvwwwPsGkJoV|T{JpSuY|TyT{^U|KnUzXV{V{SyLpHlPtOuSyb`SxQwNuFlSy[$6PBHO"#?JUbImMrAhDkNuKqMtRyW~^_Z^hhe^[V{V|wwwvvv;;<!{GkGlMs[U{GkQu[TzQw\UyHlPvSyQuTxUzNrJnMqPvW~_\X}U{KqFkU{Y"5OCHOcrcMr]ZRxU|NtHlMrInDgNqRvJpDjDiNu]`SwMsOvNuOtX}Uz"4LDJOFPZ , 1F)>Z5Nq;W>`NtSzMuJqJpInGk?eBiSz\]UzMsWXW|ZU{NuLrSxRwQxPwW|z{{{===vvwrrsSwPu_aRyEjAfOt\X}SzV~OvImNsNtNrW|U{IoCiFjSza]MqKoPvNuMrVzTy!2KEJO@IT '/D*=Y2Hk:UAcLrSxOtGlGmLqDhdDiQvSzW~aYNvKqFkQxRx!3MFKPCLV (*?!4P)?c.Is;[DiGmHoGlFjChcElNtQxNuLrFlLrV}V}OvDjtuvtttwwwuuvQuKoHlQvPwLrHoJqRvRvLpNtU}PuEjQwX~PuRxQwGmCjJqSyU|[\RxPvKpChTzRx0KGKPDLU (+?#6R*Be/Jt<]FlCjIpMtHmGlAf6\BgJoDjCjEkBh>d>cDiJoQxPwAgAgNuOvT{QwAgzuuuwwwwwwstt}PuPuPtUzU{NtJqMuPuQsJnMsX~PwGnT|V{JoQvU{KqKqT{T{V|[[SzPuHmCiV~V{ 2LGLPDMU (+@$9U1Im6R}?`GmElLrMrCiFjIm?d>dEkMsKq>c>cHmInJnNvRxRxHnDjNuPvT|YNwvsttwwwwwwstt"tKqRxW|X}W|MtNvU}TySvQuNtU|PwJpV}SzHnQuTyJpNtYTySwY~^YRxInInZY}#5NHLQDMU )+A)ZCdPuPvIpHnEkBg?bDiImOvS|S|WU|MtKqV|ZX|U|RzKrJoUyU|Sy]}stu&wwwwwwstt&mKoSu[V{PvNtAfJp^Y}V|X~QuJmLpQvW{VzOsJpEjImV}SzRyZTyMrOuDhDhW~Sy!4MIMRENV )-B&9T8PqFbDeHlMtMtJpBiDjEjFkJoMuT~ZYOtGkFkV}^^`QwAgLqV|PvMq[ttu&wwwvvvstt$qOtNpQuTyPtNsFlIm[~^_[LpHmJpMrTyOtImFiFkNuV}SyV|YQwRxPvChHmXNu2KIMRENW %%7/G2Ge@Y}?]BcBe?bAeAgGmLrKpNtU}UZYMsLqLqV|]ciQv:^Os]UzRw\ttu$vvvwwwstt"vOuKpHlJnGkGkHkKnVz]_Z~JnEjEkKqUySwOrJlDjNuZU{Z^QvRwT{KqMtV}In/JINRFOW -(>*bRu]UzV{\stu"wwwwwwttuQvMqImGjGkDhEhSwW|V{W}U{NtFkBgMsX}VyQtLqDjJoW|SzZ`PsOtTzKqNtU|Fl/HJNRGOW '$6$5I)]1Im:V|;X;Y=^>`JlIoElMuQxIoGlQwW|ZUzUy`ZOuFjPuX}PtSwZttuwwwwwwuuuTxOsKpHmLqGmDiY~Y}MqQwSyNuGlEjOvU|QuInJqImJoOvMtV}\NpKnMqEhKnSyDh,CKNRIQY  ,+;!0E 1J(>Z3Ll5Os7S|>^@`HgOsBiAhPwOvIoLrTy\UzPuY~TyOsKpTySwJnSx[tuuwwwttttuvVzNrKpMsKrElIo]X{JnRwU|KrEjKqQxNtJoHmIoLqOuMtJpPvW|PqDeDd@_EeNp@_';LORNV^  #,%3*<$4L)=W.Ed6OtY4Lk:W|>^>_LqWQyS{\YLqQxXMsFkUz[V|RyRxWzRuPudqrrvvv==={{{wRsOtW~RyDiChU|`YJoNuT{Im?cLtXQvHoLsLsJpLsNuNrPvTxKk;Y9V~7Pv7Pr8Pp+@^&LOQbkv"$(,!%(!%) %)!&+!&, %4%7M+A]4Nq`Kq\[U|ZV}FkQt]MrHlY~W}TzSyKqQvRxRwkw{{{===Y[{Sx\SxHnEiOu][NsKqKqFjCiRyZSzKpHnHmLqPwNuLrOuTzOp@^;V~9Pq5Kf0D^"3J W[_ELS*-2bnz $ /B':S/Gh;V<\DhZ`U}T|RxEjQtZ~LpJmX}U}T{SzNuRxV}V}oY8gSx]X~PuFjFkQwZ~MpDiHmIoNsTzRyLsKoKnFkHmSxNuKqRwJj6Ou&;] 2P0E*;!0 "*,.NU\HOWy+=&8P,Dc6Rz=\BgV|_T|QyOuFkPvY~OsJlQvQyU}YX}\\Xt8nnn||}!vLqVzX}QwGkAgHoVzIlAdHlNsQtLqOvMtJnKpHnJnVzPvMtRv,?Y%(-(-2%(,%(+#&)"%'!"$%&'78:CFIX`i?EKm{!+=#6M+Cc7T{DeKoY_S{RzPvFkPuV|MrIlKqKrRzT{W{`^W||}!nnnvvvqrsIlLpQvOsGkFlNtUyHmEiKpLrLrMsTzLrIoLtIqNs[V|S{Qv /CMLKdgi@EKAHNo}!,>$6N-Ff?]NoOrX}_WV~OwDkNsQwJpKpNsKrNvMtSv_\[rrsvvv==={{{zMoGkOrJnFlPwSyPtImJoNtJqElPwV~FmIoRwKrKrW~ZXRw$4Knop&)-!$(!%)#','-5)/7',4$(/#&,!%) #&"%"%"&!& $!%"(#)#)#)0!&- DKQo}  *=%6O.Ee;XJjLqOvW[VKtFmNrNsLrOvLsLrPwOwQvY|Zfz{{{===HYzLqUxHmDjT|SyMqMpPvSxKpChQwW~JpNsPtKpLsW~ZTMs$3Jaab#"4+A*A*A+?&9)   )$5+@/H)@^5Lk!/DJQq} ':$6P-De1Lu>]HmJqOvXQzFnOtTwLqKpLsGnHnTyT{OvUyQvjH;;;!vMsSxIoBhPwT{RwV{V|QvGlFlTyTyJoOtLqFlNu^\R|Io"2Jbbb ,>*;U1Ij%8T&")#*3#*$! !-&7K+?Y.Ef0KrFgTw&7JDKQq~ ':"5N,De2Mw=\IoKrKqRzS{NuRvX{QvLsMsIoIoSzT}V}Y}Kq|ή!;;;vvvwwwMrMqJnAfMtW~Z^YPvFlKqV}PwHnMrJpDkMt]]WKp!1Iabc (<':T0Hj*B"$'!#''9Q+?\-Dg1MuGjSu$4IDKRr~ *=!3M,Ee5Rz@aKqLsLsT{\X~MrPtSwQxOvNsPuOvT{c`X|wwwvvvXYzJmIkCgTzZ\_ZQwInRyYKrHoOuJoFjMtZ][Ns"1Ibbc *?)CI6]>`AfFj!2IEKRt!+=&9Q0Gh5OxCbPvU|W}NuJqLsGm>bDgPuKqQwT|PxY]\www wwwHfDjFkOuQvU{]T{GlAfNsQvJpOuOvKrHnMtYYYNr!0Idee!&*D0Gk8Rw?])?` 046=BH5:@5:A5:@59?49?:@F-14';Y=[=]AbBcLqSw&6LEKRt%/B(dJpNtKqRyPxKqGmMsXYWIn 0Hklm!&,"6U8T}9V>^9Y,Ei,Dc2Ji-Ed*B`'=[&\&;Y#7S+A`7T9[=bEiHkW|\(9NFKRt!0#5M(=Y0Il1MwBcX~XQxKrInHmOtRwLqV|XJq?fNt^\|||vvv===`]GnRxPuMrVzUyHm@fJpKpHnSzRxIoGmNtU}XYHl)>A?>npo*BeAa>]@bBfEkSy\\W}MrHnMpJmHkHmCh?fCjDjHnV|Y}'9OFKRs}(=*?\,Cb/In.Ju>_T{U~HoFmKqJoOtPvJpPwRzCj:^LqUzi`===;;;KsRwQtJmSwUzNrHnKqHoHoTzSwJnIoQxT{U|[Qu*?_$ &-$*2#(0"'/!&-%, &-!&- %- /4QzBfDfFiGjFkKpRxYZQyGoJpNtKpEkIpOyR{LsJpTzUz(9PLQY{" 3M/Gi3Lo7S{3Q~:[HmPuDiGkQwLqFkFmNuPxKrEjBfLpRv;;;uuuhaOuRuHjMqRxOtLqJoJoMtQvOsGlIoU|U}U{VzOtHkA`:Z=_GfEe@_8W?]^BdBgGmLqKoGjDiGmSzU~PvLqKrLsFlFkQwRzU}V|OuU}Uz$4JGLSt~#'=]1Mv7RzCb=]=_HmLqImJnOsJoDjKrRzMtLqOrHkFjehuuu===V|X~NqKmPvNtImEkInPvRyLqDjGnU|V}T{MsJoNsOtHpMu\_YNuW~U{DjFlMsLqGnKqNuJqElGnKqQwOxHpNuRxJqGmPuTzMuNvW}RxOvOs$5L!#%Z_efmt[bi\cj[ci^gm_gp47;0Jo:Y8UFgIlInRxOvKqKqKqIoJpPwRyKpOrYzQsIm===uuu_zV}SvMoLrIqChCiHnOvT|KqDkKrS{RzS{PvPuOsLoChDiX}\QwJoU}SzBgBgInMsJqJrPyNvGoOwTzMrJqHpNvQwInOtSyLrKqLsRzQxGnFl1Kt&9)9"/@+;):$4!1#2+/F=]Fh<\AdLpMqNtRzQxMuNuNtMtOwNuKrQt[}Twl_uuuDDDY~TxSvIoCi>dIoOvNvQxKoDhLsT{MsRyZV}OtOsHmFkZ\KrKq[T{DiGlJpJpIoJrR|PxInSyYQwKqKsOwMsJoSxSxJnMrMrJpJrJpGmBf@cQtSuHjNpGh7U>]FeCdIkJnAd=aEiHmHnMrRzQzMsLsOwNvLtMtQvPsRuDDDBBBBV{WzKqCi=bFlU}T|TzOrChIoSyJpOvZT|KqNsLqKqZW~FmHn[Ry@eEkJrLsHnElOxOtJnTy[ZPuJqOxQwOtRwQwOuLsInDiChInOuQyMvY\KqU}[HmHmT{QwJoAf;`;`>aGkIoGlKrMtIpLsPxKqNsV{PtDiBBBBjjkwww~pSzOuInCgBgPwV|SxMsElIoOtInMtXU}KqKqKpLr[W~ElDjTzQv@fDmLuNwHmAfMtPvLqSxY~ZPwMuVV}OtNtNuMvGqGoAg>bImRxV}NwMvU|NtOuU|GlDkQyLqBfbGkLqKqKqGnIsOxRyLqOs^Pw^~~vwwjjj===^OvLqKpEkJqRxNuHoCiChLpJnLrU|W}QwMsHnLs[W}HnBiOuMs?gGpPwPwIpChJqOvNsRxUzQvMuOxVV}OtLpMsHqClGoCg>bGlMrRxQvIpNuW~V~RyMsNuOwHnBgBhGmHoEjIlKpNuU|RzJsIrRyUyTy\`===%%%BQxNtQyKsJrPxOwInBeBfNtNtLtRyU|U}PwFmMuZRxKpFlLqFl=eFpNuPwLsCjElLsLsNvPxJrOvPxMuQwSwNsNtJpAhDjEiAgIpQxT{SyOtLsQyXSyOtSyNuFmFnGlChCjElGmHnMsW~WKrFlQwW}Sz\B%%%jjjDDEnNuT{MvKrLtNuMqCgGkW}SzMtS{S{RyLrChPw\NuFmInLrDjAhIpJpNuMwCkDkMuLsMtPyKtOwTzNtPvW|PwIoHmFkFlFlDjQvV|T{T|W}OtKqSyOuGlNrOtHmFlDj?d@eCiJrLsInQxVOuKpPvRwPvnDDDjjjGGF rKrNsMrInKqMrBfGj]W|MsQxOuNtHnAfRw`OvBiFnPwHnDiNtJqLsOyGoFnJrOuRxNvHpIqQxNsLrV|U|IoHmLqLrFlDjRwQvHnTz]LqHmQuKqInImLpNqLpJqGmEjGlNtMrHnMuRzPxQwQwHov GGFeKqRwKpLrLrDgIl]X~RxSxNtNuLqFkTxcSuCiEnOwInEiMrKpMsOvIqGpHoOuTzJpDjKrSzNuFmNtW}SyPvS{QxElBiMsMqGlU{]LrIlPvOuRxKoHlNqOuRyOvFmEjMqLpMrNtHpPyW}Mte&&&#dQxQvLrJpFjKo^ZQyRxRzSxQuOsU{`RuEjIqRzLqFkKqLqOvLtHpIsJpOtSyKpKpRyV~U}LrHnOtTyV}WQyIqHpNtOuRxW}W}TyMrQxV}RvKoMrPuPtLsLtIpHnQvOvTyWzInMuR|c#&&'&''1fIpKpMrImIo^\LsLsV~T{PtPtQwZQwCjJsX~MrAgIqMtMuKsIqIrHpMsVzX}W~W}U|V~TzRvNrJpQxRxLtMvMtQwV|U|QxPvYRzQy\QsKpS{U|RxGmEkOwU{V|RyU|YMrElcɺ1&''lll9aBhLqKpIpZZOuPwWPwHmHmNu^X~FnIqTzGl?fKrLsIsLsMsIrIrKrTy_^X}RxRyX~[TyKqKrJqIqIqDjMsYV|QxQxYQyNv\PsLqVT|RyNsInSzW~QvOtRxSzJqc9lll9lBiFmMsZXRyS{U|MsFmGmOva\MtLtOwEkEkNtLtKuNvQwMuMsNsU|^[ZV|MuS{[UzNuKrKsKrDi>cIoU{U{SzV}XPvLrV|NsOvV~MtKqRwQvX~W}MrNqOuKsu91EkLsb\MvNvRxKrIpKrPxa\MuNxOvIoJpPwOwPwPxNvOvOtMsW}\T{Z[JqKpW{OvLtPwLtHoDiDiOsVzRwRyXVOvHmOtQtTzRyGlGkPuNrQvV{TyTyUz1"W{__S{RyOtChEkKqQyd^KtKuMuIoLtQzOuQvQyNuOuOuJpTz\V~W]MrEiQuNtQyX~IoDjEkJpW|[RxS{YVRxFkDhNrU{OuIlJmPuGk@eNtRy`"lll(((rXWX~MsBhHlLpTyc]OvNvOwLrNvT|OuNtS{S{QwLpEjLpSxU|U~]W|JnJoMsW}XMtIpHnKqV|]ZXYZXLqEjPuX}QvPsNrKpHl>cGnn(((lll''' m]QxKrIoOtOsW|cY~PwT{QxLsMsRyPvMuQyRzLsEkCgJmNrLrOv[`SyKqSyV}OuRyXNtHmQw\a]Z]\V~R{SyUyRxPuPuIoEkMpm '''AABAoHmAhOuOuTzaT}KtQxIpGnMtPwOvLsLsKrDkCgIlSvUzLqLrZ_W~T|XX}RvV|]RzEkQx^`^ZY\[U|OsQuUyOuNtMsfAABBIHH ~VwIpGmPv]R{IsNwGoJqSzQxNuMtMtLrDjDhNpX}ZRyQwXYXYVX~ZYYS|IrT{^\\YX]ZQxLpPtQxPue~ IHHjjj###vvvB\{RxT~LtLsPxIqNtSzNvMuPvRxQwIpGlNtW}\YXV}QzWWLuOuZ[U}LtNvSzTzZ[[[YV~NuFkNseBvvv##$jjj>>>_oNtGnLsEkMrSzMtLtNuOtPxMtKrQxW}Z[ZV|PwXS{DkHnU{WLsCiNuSzPu\_]WJqIqPud_>>>hhhhz^HlHoPxKrLrMtOwQzMuKqQxTzW~YU}U|XW}NrGkKqOwPwMrHlTz[SyV|YWX_yhhhhCCCGGH 334`ycTyJqFnNwS~LuIpQvTzW|YU}S{XUzQuOsOuPwPwQuInPyVRyY~h`233 GGHCCCwww@@@ AAAHpfdX}PvOwQxSyS{T|R{PyQxV{PvLsPvUz[\~gyHAAA @@@wwwxxx<<<stu #Xxvuqty{X#stu <<<xxx>>>yyyHHHstv!H{{H!tuuHHHyyy>>>zzz===opq{{| 8YwwY8{|| noq<<<zzzzzz===pqrttuttustustu"stu$stu&stu&stt$stt"stuttutuvpqr===zzznnnoootttvvvvvvvvvwwwvvvwwwvvvwwwwwwvvvuuu????????????(0` $ige6ZttZ6hgd omkccomk  utrڊgEkCl9aAkBjKrGpBkDmSztڊvur  DDDm쏩KrEoOwKqLsLsSzV|_V|OtPvRxU}NvJpmDDD hhhRxEjRxW~U{MrJqIpQxZYV|QvHmY~\ZQvBjOvhhh}{y*ق8aZ[NtSzW~JqIqIrKrW_W}UzEjV}TzJpNtRxKp=d}{y*}|y+fJrLp^W|JqRyTzGmKsJrHmRy]OuOuDjPwXKrFjMqLqLp?gg|{y+jjk\|KsUyHn\YLqSxOvHoRzOwHoOu_RwIpLsOwQxIoJnLpMtDiKnHqijjj =eTxSwHnXV{DgMrJnCgJqHmLoInKoKmCg@dNsNtGjBdAeJqPtPwPwFm oMsU{GlOsHnSzUyBeA`2Kp)Ae/Hk,Eg0Gi/Gg)@b,Cd+Bd-Ei:U|8Sy4No0Im8TKmKpJpOtQuAjoxvtJneU{JoInGmXTx2Im,"*4%6N@aEiGlIoQy[`cV~omkiSxV|InY~PvJoPuInTyW{OvEj]jyEP[ '9T{MrLrDhLrX~OtYRyRxLsnlj5DjLqHlSxPvJoYKqPvW{NtFk_kzEP\.5QzEjGlDiNtNuGmMsJrGm>g5Z@fLqFjRwLrKmZJoLr[PvEk`l|FQ\ *3MwChHmCgFlIoHnElKrLrAkZtBhQxNtQtOvPvRwJpSy[OuBh`l|HR] +3LtDiIoBfBgIoBhJpNtLqHrtLrQwQxTzNtPvOtOtV{Y~QvFjco|IS]0;VLqGnAeGlU~PwTzRyNtMvFkLqNs^KoPtOsIoW~U{OtAgam|JS] ';SvEgChEjOvWNtW}^LqJpt>dHlQuW|JoMsOsJoU|SwOs?d_jwNW` 0F/Ff9WEgKrMtRxW}V{QuHntZCkKqW}QvIoOvJpLrOuOrA`.Indjr16< '"00Fe@`QxV~RwPuUzTyFlZ5JqMqRwKoKoRxInMrQv9Rx'8O-;>B%,3/E<[X~T{MsPsQwW}Nw5nljJnLpMrJnLrOuJpU{Ho^dmZ]_inrwjs~ckt_fmckshq|nzHQZ(/8,CB`V|S{KqMrKrSxY}mkihCiU{UzLqPwInXFnqylnp )B9@Kc7QwGVjK\rHXl5F[5TKq;Tu,4>2K?^V}IpJnPvKrV}onlӊCiSvInNtLqSzQv9LhSasP_sN[p5E^?aHmIqNwDkFmMtT}K^1FcAbHlNuMsMtOtPrwvto>fGlSzIoKqT}LrSyPvNtHoIpLsV|QyPwOuIpChNuOwNuGmKr?eChLrLtRxCko @iQwFkLrSzLsQxLrEkJrJqIpOwNvSyNsDkDjRxQwRyPvHnChFlOvSyDl jjjcCkLpV|RxLqUyKqIpKpKsJrMsMtOuQvOvIpPvTyNsLqMrIpIoRwEoejjj|{y+a=dZS{NtTzOvJpIpLtJqV{W}T{PvMuJpSzT{T{RwQxOuW|Emb|{y+}{y*{IsQyIoYS{IqNuPxNsW}YOtQxHpGlUzV~LrQvPtLqBj}{y*hhiMtiFnPwOuJoX~X~YU|ZPwZVGqKpmDCC  wusي餺hIpBlAjIrLuGo?gAjBjRyrيvus  nmkccomk ige6ZttZ6hgd????????( @ MJFTRNTRNLJG-+)|6ֽݣ뤶ݽս~|6-+)CÝgKsAjEnLtFnPxsÒC@?= ΚPuEnMtIoMtZ\RwMrU{GpMuΚ@>< IGDjDnUzSzSyHpHpSz\QvJpW}MsNr;biIGCDB@ ]DjZU{OuOvNwMuOv\LsKrT{JpKpNs=c_BA? ΙmCiQuQyQvFj?a>aAbAbAa<\BdJm@a@aLqRwCjlϙGMuPtGlSzLm9Pn.Z|Q\h.KOuSzNsIpp}7EmV|KqQxDj/EJYn2D^3US^i.JRxNuNrGp~{7׾NtMqJpPwKq^kr{9TzBe@b:ZHmCh|Vam&?dNsKpLrKrپG8`OuLrSzElDl?fIoPwS|QyPwInF_OefGЙjAiMqPwQwRxJqIqLsPwQwGmGmS{NvKrBgNtDmpΙCA? Y~BiW}PuOuHoJrLsPwQwNuLsSxPuNsOuDk\CB? IGDlCmNtX~KrNvPvYRxKrLrW~SxOu=eoIGD@>< КLsFpGoOvLqV|W}U{RxWDmNtϚ@?= CÙfLuFoNxHrFoQyrÒC-+)|6սݪ멻ݽԽ|6-+)LJFSQMSQNMJG??(  20.aelRnxyoxybgmR21.{vdZ^jzvfHqFoMvSyLtCl_~xcElPn>Uw:Rt5Lm2Km:Sw>cd}x430GnQwXqm~EWlAcMv531bflPgKpSyGl.DeLrLrh`ekPoxxYMrSyNr+DjKsGmXpyxowxZLqRx3U /DFiRy`r{xaekPeIpIn~~}2LrPxjcgmP430DlImm{I`G_az4QzFo531~x^ElEjFlNwLuPsNl #include namespace Ui { class OpeningTreeWidget; } class BoardView; class OpeningTree; class OpeningTreeWidget : public QWidget { Q_OBJECT public: explicit OpeningTreeWidget(QWidget *parent = 0); ~OpeningTreeWidget(); OpeningTree* m_openingTree; QString move(QModelIndex index) const; Board board() const; bool updateFilter(Filter& f, const Board& b, bool updateFilter, bool bEnd); public slots: void cancel(bool bVisible); /** Store current configuration. */ void saveConfig(); /** Restore current configuration. */ void slotReconfigure(); private: Ui::OpeningTreeWidget *ui; BoardView* m_openingBoardView; }; #endif // OPENINGTREEWIDGET_H chessx-1.0.0/src/quazip/quaziodevice.h000644 001750 001750 00000001254 12223260306 020550 0ustar00niklasniklas000000 000000 #ifndef QUAZIP_QUAZIODEVICE_H #define QUAZIP_QUAZIODEVICE_H #include #include "quazip_global.h" #include class QuaZIODevicePrivate; class QUAZIP_EXPORT QuaZIODevice: public QIODevice { Q_OBJECT public: QuaZIODevice(QIODevice *io, QObject *parent = NULL); ~QuaZIODevice(); virtual bool flush(); virtual bool open(QIODevice::OpenMode); virtual void close(); QIODevice *getIoDevice() const; virtual bool isSequential() const; protected: virtual qint64 readData(char *data, qint64 maxSize); virtual qint64 writeData(const char *data, qint64 maxSize); private: QuaZIODevicePrivate *d; }; #endif // QUAZIP_QUAZIODEVICE_H chessx-1.0.0/src/database/board.cpp000644 001750 001750 00000012612 12223260306 017735 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005 Kamil Przybyla * * (C) 2005-2006 William Hoggarth * * (C) 2005-2006 Marius Roets * * (C) 2005-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include #include "board.h" QMap > ecoGuessPositions; Board::Board() : m_hashValue(0) { } Board::Board(QString fen) { if(!fromFen(fen)) { clear(); } } void Board::clear() { BitBoard::clear(); createHash(); m_squareAnnotation = ""; } void Board::setStandardPosition() { BitBoard::setStandardPosition(); // Just use precalculated hash values which is _much_ faster // createHash(); m_hashValue = 17059429555746339296ULL; m_squareAnnotation = ""; } bool Board::fromFen(const QString& fen) { if(BitBoard::fromFen(fen)) { createHash(); m_squareAnnotation = ""; return true; } return false; } void Board::setAt(Square s, Piece p) { hashPiece(s, pieceAt(s)); BitBoard::setAt(s, p); hashPiece(s, p); } void Board::removeFrom(Square s) { hashPiece(s, pieceAt(s)); removeAt(s); } void Board::setToMove(Color c) { if(toMove() != c) { hashToMove(); } BitBoard::setToMove(c); } bool Board::doIt(const Move& m, bool undo) { if(m.isNullMove()) { if(undo) { BitBoard::undoMove(m); } else { BitBoard::doMove(m); } return true; } if(!m.isLegal()) { return false; } CastlingRights oldCastlingRights = castlingRights(); hashEpSquare(); hashPiece(m.from(), m.pieceMoved()); if(m.isPromotion()) { hashPiece(m.to(), m.promotedPiece()); } else { hashPiece(m.to(), m.pieceMoved()); } if(m.isCastling()) { Piece p = (m == White ? WhiteRook : BlackRook); hashPiece(m.castlingRookFrom(), p); hashPiece(m.castlingRookTo(), p); } else if(m.isEnPassant()) { if(m == White) { hashPiece(m.to() - 8, m.capturedPiece()); } else { hashPiece(m.to() + 8, m.capturedPiece()); } } else if(m.capturedPiece()) { hashPiece(m.to(), m.capturedPiece()); } if(undo) { BitBoard::undoMove(m); } else { BitBoard::doMove(m); } hashToMove(); hashEpSquare(); hashCastlingRights(oldCastlingRights); return true; } void Board::hashPiece(Square s, Piece p) { if((p > Empty) && (p < InvalidPiece)) { m_hashValue ^= RAND_VALUES[p - 1][s]; } } void Board::hashToMove() { m_hashValue = m_hashValue ^ RAND_TO_MOVE; } void Board::hashCastlingRights(CastlingRights oldCastlingRights) { oldCastlingRights ^= castlingRights(); if(oldCastlingRights & WhiteKingside) { m_hashValue ^= RAND_WHITE_CASTLING_KS; } if(oldCastlingRights & WhiteQueenside) { m_hashValue ^= RAND_WHITE_CASTLING_QS; } if(oldCastlingRights & BlackKingside) { m_hashValue ^= RAND_BLACK_CASTLING_KS; } if(oldCastlingRights & BlackQueenside) { m_hashValue ^= RAND_BLACK_CASTLING_QS; } } void Board::hashEpSquare() { int epSquareIndex; Square sq = enPassantSquare(); if(sq >= 16 && sq <= 23) { epSquareIndex = sq - 16; } else if(sq >= 40 && sq <= 47) { epSquareIndex = sq - 32; } else { return; } m_hashValue ^= RAND_EN_PASSANT[epSquareIndex]; } void Board::createHash() { m_hashValue = 0; for(int i = 0; i < MAX_SQUARES; ++i) { hashPiece(i, pieceAt(i)); } if(toMove() == Black) { hashToMove(); } hashCastlingRights(CastlingRights(0)); hashEpSquare(); } bool Board::ecoMove(const Square square, int* from, int* to) const { quint64 key = getHashPlusSquare(square); if(ecoGuessPositions.contains(key)) { if(from && to) { QList data = ecoGuessPositions[key]; *from = data[0]; *to = data[1]; } return true; } return false; } bool Board::loadEcoFile(const QString& ecoFile) { QFile file(ecoFile); if(file.open(QIODevice::ReadOnly)) { QDataStream sin(&file); quint32 id; sin >> id; if(id == COMPILED_GUESS_FILE_ID) { sin >> ecoGuessPositions; } return true; } return false; } quint64 Board::getHashPlusSquare(const Square square) const { return m_hashValue ^ RAND_ECO_SQUARE[square]; } quint64 Board::getHashValue() const { return m_hashValue; } Board getStandardStartBoard() { Board b; b.setStandardPosition(); return b; } const Board standardStartBoard = getStandardStartBoard(); chessx-1.0.0/data/images/chessx-32.png000644 001750 001750 00000010726 12117557125 020230 0ustar00niklasniklas000000 000000 PNG  IHDR szz CiCCPICC ProfilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/7bKGD pHYs  tIME %)pIDATX[^U{}.e:0褷 BűPl|0#nIc $ԪP.(ʵQ 0o^>̀tHE^X/kg眬uxCC!ֈ}Oor`ʄ $sëzخx Y;m/e󀘗~NjT/0.ˊCStmzs~BQ;:Ul&bԁmdOoXSoI.",]-[>MiV|zWi5cp%0^}5^;Ҧ۶q<28twn(&-;;|8W҈qa|d8xGCB@$zd,OnAN[K|mŋŻnYPCZSJEDI&_|v=p1t'y%2[D;T7'^z2y0W\:yOW\nESop.SerDa{fIqpb14G +l[I+$14{4Uf^Sk60FS,06 *w!xNhl4Әn;G|@!h_#(k\>3#yC+ALp3 +?t5xqJ"t4=4]Zs*-?+֯cqZ J3=R">x @)51Ҿ=Wg.ZDU"MdR 7D{9* U=-)> u^9H@E4ʜs7y 7.[{ѓa#m%3_}3)s*0lniLe+jM򁅣Ԃ+mNzywǽߺꓶWHDtKז|@% p#4t*Nlw$y7$/#I"$>v4Zk,(IE_oHB0|ˮ>' L4g.xZF$}X[Ⴠhґ36|O]Bh !Zte߸WQgD'Yt0IBY$IS,#k6, tZ2l?߶_j5Lg'JE%g].:yo{1ΫN۠iCKx_)ٚC2IENDB`chessx-1.0.0/src/gui/ecothread.h000644 001750 001750 00000001353 12223260306 017271 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef __ECOTHREAD_H__ #define __ECOTHREAD_H__ #include #include "game.h" /** @ingroup GUI A small little class to handle loading of the ECO file for the mainwindow */ class EcoThread : public QThread { Q_OBJECT public: EcoThread() {}; void run() { bool ok = true; ok |= Game::loadEcoFile(":chessx.eco"); ok |= Board::loadEcoFile(":chessx.gtm"); emit loaded(this, ok); }; signals: void loaded(QObject*, bool); }; #endif // __ECOTHREAD_H__ chessx-1.0.0/src/gui/analysiswidget.h000644 001750 001750 00000005355 12223260306 020370 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2008-2010 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __ANALYSIS_WIDGET_H__ #define __ANALYSIS_WIDGET_H__ #include "engine.h" #include "ui_analysiswidget.h" #include "tablebase.h" #include /** @ingroup GUI The Analysis widget which shows engine output */ class Analysis; class Board; class AnalysisWidget : public QWidget { Q_OBJECT public: AnalysisWidget(); ~AnalysisWidget(); /** Get the main line */ Analysis getMainLine() const; public slots: /** Sets new position. If analysis is active, the current content will be cleared and new analysis will be performed. */ void setPosition(const Board& board); /** Called when configuration was changed (either on startup or from Preferences dialog. */ void slotReconfigure(); /** Start currently selected engine. */ void startEngine(); /** Stop any running engine. */ void stopEngine(); /** Stop game analysis when analysis dock is hidden. */ void slotVisibilityChanged(bool); /** Is any engine running. */ bool isEngineRunning() const; private slots: /** Stop if analysis is no longer visible. */ void toggleAnalysis(); /** Displays given analysis received from an engine. */ void showAnalysis(const Analysis& analysis); /** The engine is now ready, as requested */ void engineActivated(); /** The engine is now deactivated */ void engineDeactivated(); /** There was an error while running engine. */ void engineError(QProcess::ProcessError); /** Add variation. */ void slotLinkClicked(const QUrl& link); /** Number of visible lines was changed. */ void slotMpvChanged(int mpv); /** Show tablebase move information. */ void showTablebaseMove(Move move, int score); signals: void addVariation(const Analysis& analysis); void addVariation(const QString& san); private: /** Should analysis be running. */ bool isAnalysisEnabled() const; /** Update analysis. */ void updateAnalysis(); QList m_analyses; Ui::AnalysisWidget ui; Engine* m_engine; bool m_active; Board m_board; QString m_tablebaseEvaluation; Tablebase* m_tablebase; }; #endif // __ANALYSIS_WIDGET_H__ chessx-1.0.0/src/gui/colorlist.h000644 001750 001750 00000003555 12223260306 017353 0ustar00niklasniklas000000 000000 /*************************************************************************** colorlist - QListWidget item to edit colors ------------------- copyright : (C) 2007 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef COLORLIST_H #define COLORLIST_H #include /** @ingroup GUI The ColorList class is a list of editable colors. */ class ColorList : public QListWidget { Q_OBJECT public: /** Standard constructor. */ ColorList(QWidget* parent); /** Standard constructor. */ virtual ~ColorList(); /** @return color of given item. */ QColor color(QListWidgetItem*) const; /** @return color of given item. */ QColor color(int index) const; /** Create new item. */ virtual void addItem(const QString& text, const QColor& color); protected: /** Edit color on left click. */ virtual void mousePressEvent(QMouseEvent* event); /** Edit color on Enter. */ virtual void keyPressEvent(QKeyEvent* event); /** Set item color. */ void setItemColor(QListWidgetItem* item, const QColor& color); /** Edit item color. */ void editItemColor(QListWidgetItem*); }; #endif chessx-1.0.0/src/guess/hash.h000644 001750 001750 00000026615 12223260306 016630 0ustar00niklasniklas000000 000000 ////////////////////////////////////////////////////////////////////// // // FILE: hash.h // Pre-generated random hash values // // Part of: Scid (Shane's Chess Information Database) // Version: 3.4 // // Notice: Copyright (c) 2002 Shane Hudson. All rights reserved. // // Author: Shane Hudson (sgh@users.sourceforge.net) // ////////////////////////////////////////////////////////////////////// #ifndef SCID_HASH_H #define SCID_HASH_H namespace Guess { // goodHashValues // This is a table of 12 (pieces) * 64 (squares) = 768 pre-generated // "good" 32-bit hash values, to be used for Zobrist hashing. // The values were generated using a threshold of 10, meaning that // (a) every value has at least 10 and at most 32-10=22 bits set; // (b) every value differs from every other value by at least 10 // bits and at most 32-10=22 bits. // const unsigned int goodHashValues [12 * 64] = { 0x039B11BFu, 0x4890D6A4u, 0x37539B8Au, 0xA7E3A104u, 0x8B263019u, 0xEB71AE0Bu, 0x87099341u, 0x32EF9CD4u, 0x698B8BC1u, 0x823FEACEu, 0x8E607A5Au, 0x7241E921u, 0x8E94A4B6u, 0x2670B742u, 0xD721044Cu, 0xD1FC122Du, 0xBD0CE70Eu, 0xA4159629u, 0xAE24AD63u, 0xAB5DA9E9u, 0x83D1C843u, 0x32E60A29u, 0xABF131AAu, 0x3C3CF99Du, 0x5553E1FDu, 0xD8328308u, 0x9B2FC0D4u, 0x4EDC83D2u, 0x852D84B3u, 0x068D4A5Fu, 0x35CE432Fu, 0xE4843746u, 0x2B67AF9Eu, 0xABCCC099u, 0x217F1CAAu, 0x7BF4C414u, 0x7C24E036u, 0x29E3C6EAu, 0x1053B4CCu, 0x8D96DDA0u, 0x4505DA02u, 0x47EFD3ECu, 0x32B9D1EDu, 0x4F688C67u, 0x1FFD9115u, 0xBC0156DBu, 0x28BD842Eu, 0xECE11B80u, 0x2088BE1Fu, 0x3384DFE4u, 0x05AAE96Eu, 0xE697A8F5u, 0x02E84551u, 0x6E0B75ABu, 0xC8EE1CA1u, 0x5387CC68u, 0xB0991EB4u, 0x332AD23Eu, 0x7063DDB8u, 0x844141B4u, 0x3D49AAA0u, 0xB73790D3u, 0x2009A159u, 0x43BCD4B9u, 0x3E47B851u, 0x992161E6u, 0x5C73DE21u, 0xA7185F26u, 0xEAF78BCFu, 0x9F46F244u, 0x90E2E582u, 0x2752602Au, 0x8D75AA38u, 0x4429875Eu, 0xDAB54C3Bu, 0x15F07D87u, 0x24936E7Du, 0xD26AF16Au, 0xF0C1BAA7u, 0x3A34F2E0u, 0x0A86593Eu, 0xBB870177u, 0xF1BCB046u, 0x91B63283u, 0x881BA73Au, 0x7FB62D0Cu, 0x9F06ED35u, 0x4CF4B1ACu, 0x24A21F70u, 0x509421A2u, 0xE492FD51u, 0x9DE1F22Fu, 0xFCEADB75u, 0x1244A7B5u, 0x9ACABF60u, 0xA32479B2u, 0x0396C362u, 0x0CEF72D2u, 0x9B9D27A1u, 0x3306A989u, 0x516008FCu, 0xE544EA8Du, 0xC33DBE2Cu, 0xE80D5B56u, 0xDC6FC86Fu, 0x4A3F3D4Du, 0xAE160A34u, 0x00512AA9u, 0xE6B8170Du, 0x419DE2C5u, 0x6B2E2517u, 0x89D27208u, 0x92847C09u, 0x38E38217u, 0x2821286Fu, 0x8AE2AAD5u, 0x30FDAE11u, 0x543C234Bu, 0xE3A2FF38u, 0x10194DDEu, 0x657AACB5u, 0x9B7A5005u, 0xE4F5DD9Eu, 0x43C4B54Cu, 0x7FB1E299u, 0xBA0FBFADu, 0x6650C485u, 0xA93F6201u, 0x0D27DBDFu, 0x03415B76u, 0x6BB1E5F7u, 0xFD2A98F8u, 0x3DB93342u, 0xE14B1091u, 0xBF290710u, 0xF23142FCu, 0xAB80B2CBu, 0xFB60F74Du, 0x21F3BB77u, 0x3888CAADu, 0x8A9ADBEFu, 0x789090FFu, 0x9D730E8Du, 0x49B24A39u, 0xD7910113u, 0xD106D4B2u, 0xD2EE43B5u, 0x6D341063u, 0xB61EDC4Eu, 0x9550B69Bu, 0xB31BF6E6u, 0xA77E70C6u, 0xD5A2839Fu, 0x36B5397Fu, 0xB9ECCD6Au, 0x5748A700u, 0xE55FD773u, 0x05B1D3B3u, 0x02C832FCu, 0x44475068u, 0x5A3FA331u, 0x7E98673Fu, 0x019BD400u, 0x2B500871u, 0x1B11BBD3u, 0xD9A16849u, 0x3D28C47Du, 0x5B5A17F8u, 0x11A56BBFu, 0x7A49A7EAu, 0x827A948Bu, 0x9CFCA8F3u, 0xD0139857u, 0x66934246u, 0x010B6D83u, 0x640E91CBu, 0x14F7F949u, 0x22E1DBDBu, 0xFE39F428u, 0xC1EFF01Du, 0xB7FBAA70u, 0x24D621C8u, 0x3E8CB46Cu, 0x799C9A30u, 0x9101AA6Au, 0x50057267u, 0x4ABB8084u, 0x96A69B26u, 0x64430CE7u, 0x29104757u, 0xF895CE65u, 0xACE8C5A7u, 0x8C311979u, 0xC50D43F9u, 0x74E82B12u, 0x7DD3F51Au, 0x024CB893u, 0x1082235Au, 0x267DE6F9u, 0xF07D4A07u, 0x2269E0C4u, 0x58CD4E12u, 0xA5BECEC3u, 0x548B6301u, 0x1DAD51A9u, 0xEDD5C126u, 0x82F2633Bu, 0xC03AA07Cu, 0xEF54151Fu, 0xAA6B4422u, 0x065BC9E0u, 0xC35692CEu, 0xA1D7DB4Cu, 0xD8633DF3u, 0x7298EB8Au, 0xFF0A0ACFu, 0x0DA1A674u, 0x6DE7B4C7u, 0xE761833Au, 0xF9FF6F50u, 0x84BC2B8Cu, 0xE799B3BCu, 0x16161665u, 0xF8F95501u, 0x576662B2u, 0x16C9842Au, 0xB200D414u, 0xF0B5A23Au, 0xDE336B9Eu, 0x6E2C4FCEu, 0x0DD75B71u, 0xDA5F5B65u, 0x10305BF5u, 0x25459D34u, 0x9024995Au, 0x9A35CB81u, 0xB04481ECu, 0x852EADD4u, 0x3979197Eu, 0x758912F3u, 0xC73CDAF6u, 0xDF52A76Eu, 0xC7340794u, 0x6C5684BBu, 0x9FA057F2u, 0xD740B832u, 0xB7AF5E98u, 0x0BB2995Du, 0xB58AB9B7u, 0xFE0BD190u, 0xB992ECC8u, 0x9FD77CDCu, 0xCD786AFDu, 0x9D06944Bu, 0x94DB6416u, 0xF7086164u, 0x06BA82F7u, 0x897BFB24u, 0xA3F57351u, 0x73087E2Bu, 0x05857541u, 0xA0BE3365u, 0x4FB89F40u, 0xCC8BF6FDu, 0xB6F359A4u, 0x7FFAF82Du, 0xFF05C5DDu, 0x41C88B7Au, 0xD94586E9u, 0x8ECBE977u, 0xC02DB501u, 0x085DD109u, 0xE167E374u, 0xE22877E1u, 0xFC504828u, 0x5A593E86u, 0xB82D503Cu, 0x0E23B9A4u, 0x1DA667E5u, 0xD6E88E31u, 0x87B13CBDu, 0x73A7CB92u, 0x1176EFD8u, 0x805EC39Fu, 0x0FAA9AAAu, 0xB2F707B2u, 0xB67AE203u, 0x8BCC0DAFu, 0xE1D2659Cu, 0x481CC9B6u, 0x4EA7AE2Du, 0x3F0E1BB1u, 0xA0EFE34Bu, 0xFB8D54E2u, 0xEEE20096u, 0x20F49785u, 0xA059722Eu, 0xF54885FBu, 0xBB655656u, 0xD674D353u, 0x1C2249E8u, 0xA4718FF5u, 0x61A84E05u, 0xA3126E85u, 0x61D9AD54u, 0x07198C19u, 0xB972FB1Bu, 0x5238CA6Fu, 0xA1BFB910u, 0x8645AEC8u, 0xE6C48940u, 0xAB771F63u, 0x17E50DB8u, 0x2D864432u, 0x1D832682u, 0x90B555C4u, 0xF57533F8u, 0xD7CD623Cu, 0x30F276B1u, 0x968A4BC2u, 0x43D75E3Fu, 0x232BD8E3u, 0x09D8EEF6u, 0xE43898C5u, 0x590FF714u, 0x578FB433u, 0x7CA18ACEu, 0x5E8BBA1Eu, 0x9377431Cu, 0x352D8B78u, 0x5D64CBE6u, 0xAC0E4DFBu, 0x8CC6D71Au, 0x357E5A72u, 0xE52B7EC4u, 0x8BA3C715u, 0x637A16E7u, 0xE53DE860u, 0x5D8D3992u, 0x69FA014Cu, 0xA741FD99u, 0x1D446311u, 0xD1B7AD7Du, 0xB09D684Au, 0x2AB52F38u, 0x115A6A4Eu, 0x70FA8C72u, 0x280593A6u, 0x90E51413u, 0x40D69014u, 0xFE54E992u, 0x80B0DF0Bu, 0xADCEAA5Cu, 0x2CE5D77Du, 0xC848DD13u, 0x1816469Cu, 0xF29F0F0Eu, 0x5267A846u, 0x9519EB95u, 0x36A0F7ABu, 0x47286387u, 0x1FDDB6CAu, 0xBCDB9881u, 0xC2D197BBu, 0x6EAEE818u, 0x283E0B1Bu, 0xF2E87D37u, 0x210662D0u, 0x093BAE47u, 0x7A2307D6u, 0x79876ECFu, 0x19DD55B6u, 0xC8903A3Eu, 0x00A6B10Fu, 0xF9C00FD4u, 0x494BB0A6u, 0x97FF861Bu, 0x70BD145Du, 0x7F46D4ACu, 0xE6F63ECCu, 0x707613DFu, 0x89A9805Fu, 0x98035A70u, 0xE941DB3Du, 0x84E3C899u, 0x4E8CFB84u, 0xB51B01EEu, 0xBFF2D163u, 0xC3A8202Bu, 0x18BB798Au, 0x12DF54DBu, 0xD10B9FFEu, 0xCEB08E5Fu, 0xA2250D9Du, 0x0E5C8F05u, 0x3BCB935Cu, 0x1BD051C9u, 0x46214EF2u, 0xDDF5D4D1u, 0x37A19E57u, 0x16DE6F73u, 0x25AFB2B9u, 0xDD2E7E69u, 0x082894FAu, 0x1535FCF4u, 0x7EECD60Fu, 0x6E9FCEAAu, 0x96D6D08Du, 0x79C709AAu, 0x1CA5070Fu, 0xB8A7AED2u, 0x80684E96u, 0xC7D6497Cu, 0xB93DD3FBu, 0xFA20C05Bu, 0xF55A0330u, 0x6D226F9Bu, 0x66A532A2u, 0x73FD3ABBu, 0xC77B9A07u, 0xCDC921ECu, 0xB68E327Bu, 0xB7F9555Cu, 0x30BA9B4Eu, 0x4C879967u, 0xC9A75320u, 0xFC83700Cu, 0x4027063Bu, 0x1B630D64u, 0x587C3550u, 0x1CFC5B44u, 0xA5AD192Eu, 0xFBE9177Bu, 0x1EABD059u, 0xAA4468C7u, 0x76AA58BBu, 0xB4B08556u, 0x71EE9F17u, 0xB3F5AC8Cu, 0xE6D8DBA1u, 0x8B0AF89Eu, 0xD36C2B70u, 0x128D3DEAu, 0x3D460CD8u, 0x16215910u, 0xCC0F0785u, 0x68CC3BCFu, 0xDEB2B9C7u, 0x6B633805u, 0x780E1005u, 0x09E49837u, 0x39E80ADBu, 0x012CEA31u, 0x3478872Cu, 0x413C1D1Eu, 0x233D57C2u, 0x4DED8698u, 0x2812F838u, 0xF3A213C0u, 0xDB90565Cu, 0x7B5BCA04u, 0x085A189Du, 0xD3B15A8Au, 0xCE88155Au, 0xC6583EF3u, 0x68BAE790u, 0x2B1EB054u, 0x71910CC2u, 0xD0D88984u, 0x210634A7u, 0x6A8140B0u, 0xD61986A7u, 0x777843EAu, 0x6D565FEFu, 0x243864EEu, 0xA5EB42F5u, 0xF06EFA92u, 0x37214225u, 0x7FD632D3u, 0x5270689Bu, 0x17D003A4u, 0xBFA3F882u, 0x3ABF601Fu, 0x9462B2F6u, 0x95506548u, 0xDFE5AA96u, 0x6014EF4Cu, 0x95AA0C22u, 0x5AA2452Du, 0x537E00C9u, 0xF1DA7E65u, 0xB35E0497u, 0xC000C9C9u, 0xC9041E45u, 0x43327CAEu, 0x5E1EC5E3u, 0x34618D4Bu, 0x19EAD6D5u, 0x2EFD99E6u, 0x670EBE60u, 0x9308BC47u, 0x8C167E0Fu, 0xE79510C8u, 0x7B6872B5u, 0x3E26A6CFu, 0x15C2DC3Bu, 0x2D58DB58u, 0xF146A05Au, 0x6FED31D9u, 0xB72E86A4u, 0x4C41B38Bu, 0xDBD4DBFAu, 0x1EC10AD0u, 0x4E58E234u, 0xAB4167FCu, 0x6B7E733Au, 0x097C2AC0u, 0x8B071EBAu, 0x776CFD58u, 0x6C9B3130u, 0x775F8863u, 0x30ACC2D6u, 0xF2E16ED1u, 0x7E7B4DDBu, 0xE3BE881Fu, 0xD50608E1u, 0x5BEEA67Cu, 0x2A6FDB10u, 0x532ACD1Bu, 0xEF979FD2u, 0xA7076C1Eu, 0xE5ED7E0Bu, 0xE0C08618u, 0x0A419EE5u, 0xE8A39152u, 0xF8049773u, 0x60E262CDu, 0xB64DCB36u, 0x5BC10B4Fu, 0x79ED7826u, 0xBDB0D600u, 0xA73B4945u, 0x15D99DF1u, 0x2EB2322Fu, 0x905CB323u, 0x8E9D7BBAu, 0xF589DA5Cu, 0x3239EC36u, 0xBD1A727Cu, 0x9A2B964Eu, 0x2738E521u, 0x3D32ADFEu, 0x7CCB6CC0u, 0x9408173Fu, 0x314D2743u, 0xE07F1718u, 0x07A67FCAu, 0x9A96EA79u, 0x2C83A39Cu, 0x553EFFB3u, 0xC45666F4u, 0xE870F6FBu, 0x60578B32u, 0x773C8652u, 0x05210BC4u, 0xF8D963F3u, 0xD93511B5u, 0xF1719F52u, 0x2B20CE90u, 0x9995F672u, 0x6C198588u, 0x38759A4Du, 0xDFBB53D5u, 0xD7685FBCu, 0x77513427u, 0x6180D195u, 0xAEC6B98Eu, 0x92BD89BEu, 0x9225B0FDu, 0x5739B0FAu, 0xA9033F59u, 0x141F2599u, 0xC36254D4u, 0x604A7F95u, 0x9E6C065Du, 0x31FBCC0Fu, 0x5B9ADD8Cu, 0xDFFA3B0Au, 0x0DFBFC78u, 0xF9CA5EBAu, 0x2ADB0F37u, 0xDDCCB685u, 0x8A5B515Eu, 0x41C144ADu, 0x34657B2Cu, 0x0D450F6Au, 0x826FAC71u, 0x9EC05C75u, 0x74DDC8D9u, 0x64C7389Bu, 0x09331092u, 0x3EFEA384u, 0x704FB6F1u, 0x6B4FEF67u, 0xCE61D945u, 0x9EE52925u, 0xE5A82DC9u, 0x0B78A412u, 0xDFCBC5A9u, 0x30DEC518u, 0x1F783F75u, 0x4E77188Eu, 0x40A76D52u, 0x38B18960u, 0x09891862u, 0x459A5AA7u, 0x42001B9Au, 0x0831CA1Eu, 0xF49286E0u, 0x877982DCu, 0x3B5CC623u, 0x807D7FFFu, 0x55540A37u, 0x6227F496u, 0x8A2A89B3u, 0x795F2B97u, 0xF63D1ECBu, 0x1124A560u, 0x4580D76Fu, 0xD6D5BC5Bu, 0xB116155Cu, 0x52AD63D8u, 0x9845DC86u, 0x6689C793u, 0x7EE16506u, 0xDC0190E2u, 0xC37420F7u, 0xE598CC3Au, 0x8DC81014u, 0xB6812BB9u, 0xE9F50AF2u, 0x0F41261Fu, 0x0466D7E3u, 0xDD946A80u, 0x4E326865u, 0x6E005C19u, 0x4146B339u, 0xC60EDF2Bu, 0xE0307009u, 0x0E646DF4u, 0x2654FA27u, 0xF81D24FEu, 0xC44C94DCu, 0x339B61D1u, 0x7D771304u, 0x61FF6433u, 0x7CDCFC56u, 0x76702E78u, 0x4E461F5Cu, 0x4F5E4893u, 0x41521503u, 0x7D997DEDu, 0x2F39368Cu, 0xC2A0ABE2u, 0xD8ABC763u, 0x0B196104u, 0x209549ACu, 0x34D15315u, 0x0357D995u, 0x40138F8Fu, 0xDC525599u, 0xF629FB1Bu, 0x6A62B298u, 0x3C1A805Au, 0xEE1674DAu, 0xBA19460Du, 0x3C72676Bu, 0xC34DD53Eu, 0x8DD03D72u, 0xADAA7B0Du, 0xFA0949AEu, 0x98DD7A1Du, 0x3A545F3Du, 0xF4AB0851u, 0xAA1C51A5u, 0xC4FEEB56u, 0x7E15A604u, 0x61459EDFu, 0xA64B7A31u, 0xDC4DBA74u, 0x57277D9Du, 0x0D694801u, 0xBB4B34DAu, 0xECBF05E2u, 0x5C192BF8u, 0xDF88AED8u, 0x10D59F2Eu, 0x1F4CD1FFu, 0x13C17092u, 0x34E8D820u, 0x8D0F4AE6u, 0xC22A9F84u, 0x4F757B90u, 0xF647C64Bu, 0xB8D5F5EFu, 0x4EF2ED32u, 0x08CFE621u, 0x6282A765u, 0xBB3B1A28u, 0x7A00FEDEu, 0x7EE74E77u, 0x0E72CEC6u, 0x7096E317u, 0xC53A15F1u, 0xA36CBB05u, 0x752139ABu, 0x2B28AD4Cu, 0x1AA3F3FEu, 0xA67D4188u, 0x9CB3B791u, 0x5130A6B6u, 0xF38FF94Fu, 0x4B18839Du, 0x92741FE8u, 0xA53A3E3Bu, 0x5AA03303u, 0x88E42368u, 0x7A62DB87u, 0xCB918AECu, 0x3FE0BBBCu, 0x5ED7B7A7u, 0x56148AA8u, 0x5B33902Fu, 0x8EF7172Cu, 0x5D756F5Fu, 0x67D49CA2u, 0xE5F2F3CAu, 0x45B9AA3Fu, 0x35B6D0AAu, 0xB086D241u, 0xF561EC77u, 0x817289AEu, 0x4ABC59C3u, 0x7171D0E6u, 0xAD03F121u, 0x4FB6B316u, 0x2F94FD3Bu, 0xAB9B2D42u, 0x9C39B806u, 0x139BDA75u, 0xBCFDFFA0u, 0xDE2D7D42u, 0xC314E010u, 0x91F7D7A9u, 0x961D52D0u, 0x4EEBB554u, 0x8E833C6Eu, 0xEC7FD2C9u, 0xACD9AE8Eu, 0xD31873FFu, 0x7E1551F6u, 0x809C8D31u, 0x8873E4B5u, 0x3221744Au, 0xEB3B4FBDu, 0xB17E5F84u, 0xEFD0E469u, 0xD08C2EC3u }; } // End namespace Guess #endif // SCID_HASH_H ////////////////////////////////////////////////////////////////////// // EOF: hash.h ////////////////////////////////////////////////////////////////////// chessx-1.0.0/src/database/pdbtest.cpp000644 001750 001750 00000024312 12223260306 020313 0ustar00niklasniklas000000 000000 // main() to convert a scid ratings.ssp to our player db format, // and test the content of the resulting player database. // // To use it, change the db_name, source and picture directory to fit // your filenames. The picture filenames should be = player name + extension // fe. "Larsen, Bent.gif" (any format that QImage(file) can handle will work). // // Code to query the small test database - see querySmall(). // Code to query the newest full database - see queryNewest(). #include #include #include "databaseconversion.h" static QTextStream out(stdout, QIODevice::WriteOnly); static QString db_name = "players"; static QString source = "ratings.ssp"; static QString picture_dir = "playerphotos"; void queryNewest() { //query newest full base as of 25/7/2005 (70207 players) // available from http://members.aon.at/schachverein.steyr/ratings.ssp.zip PlayerDatabase pdb; if(pdb.open(db_name)) { out << "opened " << db_name << "\n"; } else { out << "failure opening " << db_name << "\n"; return; } out << "number of players = " << pdb.count() << "\n"; QStringList sl = pdb.findPlayers("Hu", 3); for(QStringList::Iterator it = sl.begin(); it != sl.end(); ++it) { out << *it << "\n"; } pdb.setCurrent("Aaberg, Anton"); out << pdb.current() << " birthdate= " << pdb.dateOfBirth().asString() << "\n"; QString s = pdb.country(); out << pdb.current() << " country= " << s << "\n"; s = pdb.title(); out << pdb.current() << " title= " << s << "\n"; pdb.setCurrent("Aaron, Manuel"); out << pdb.current() << " birthdate= " << pdb.dateOfBirth().asString() << "\n"; out << pdb.current() << " country= " << pdb.country() << "\n"; out << pdb.current() << " title= " << pdb.title() << "\n"; pdb.setCurrent("Aaberg, Anton"); out << pdb.current() << " elo on 2000/5/5= " << pdb.elo(PartialDate(2000, 5, 5)) << "\n"; pdb.setCurrent("Aaron, Manuel"); out << pdb.current() << " elo on 2000/5/5= " << pdb.elo(PartialDate(2000, 5, 5)) << "\n"; pdb.setCurrent("Aaberg, Anton"); QString bio = pdb.biography(); if(bio.isNull()) { out << pdb.current() << " bio= null " << "\n"; } else { out << pdb.current() << " bio= " << bio << "\n"; } bool bl = pdb.exists("BYE"); if(bl) { out << "player BYE exists \n"; } else { out << "player BYE does not exist \n"; } pdb.setCurrent("Azmaiparashvili, Zurab"); out << pdb.current() << " birthdate= " << pdb.dateOfBirth().asString() << "\n"; pdb.setCurrent("Babaev, Rashad"); out << pdb.current() << " birthdate= " << pdb.dateOfBirth().asString() << "\n"; pdb.setCurrent("Zysk, Robert"); out << pdb.current() << " birthdate= " << pdb.dateOfBirth().asString() << "\n"; out << pdb.current() << " country= " << pdb.country() << "\n"; out << pdb.current() << " estimated overall elo= " << pdb.estimatedElo() << "\n"; out << pdb.current() << " elo on 2000/10/5= " << pdb.elo(PartialDate(2000, 10, 5)) << "\n"; out << pdb.current() << " estimated elo on 2000/10/5= " << pdb.estimatedElo(PartialDate(2000, 10, 5)) << "\n"; out << pdb.current() << " estimated elo on 2000/10/5= " << pdb.estimatedEloNoCache(PartialDate(2000, 10, 5)) << "\n"; pdb.setCurrent("Rudolf, Michal"); out << pdb.current() << " birthdate= " << pdb.dateOfBirth().asString() << "\n"; out << pdb.current() << " estimated overall elo= " << pdb.estimatedElo() << "\n"; out << pdb.current() << " elo on 2000/10/5= " << pdb.elo(PartialDate(2000, 10, 5)) << "\n"; out << pdb.current() << " elo on 2001/5/5= " << pdb.elo(PartialDate(2001, 5, 5)) << "\n"; out << pdb.current() << " elo on 2001/10/5= " << pdb.elo(PartialDate(2001, 10, 5)) << "\n"; out << pdb.current() << " elo on 2005/10/5= " << pdb.elo(PartialDate(2005, 10, 5)) << "\n"; out << pdb.current() << " elo on 1995/10/5= " << pdb.elo(PartialDate(1995, 10, 5)) << "\n"; out << pdb.current() << " elo on 1990/10/5= " << pdb.elo(PartialDate(1990, 10, 5)) << "\n"; out << pdb.current() << " estimated elo on 1990/10/5= " << pdb.estimatedElo(PartialDate(1990, 10, 5)) << "\n"; out << pdb.current() << " elo on 1997/1/1= " << pdb.elo(PartialDate(1997, 1, 1)) << "\n"; out << pdb.current() << " estimated elo on 1997/1/1= " << pdb.estimatedElo(PartialDate(1997, 1, 1)) << "\n"; pdb.setCurrent("'t Jong, Ewoud"); QImage img = pdb.photo(); if(img.isNull()) { out << pdb.current() << " photo == null \n"; } else { out << pdb.current() << " photo != null \n"; } // tests for partial birth/death dates pdb.setCurrent("Abbott, Hedley"); out << pdb.current() << " birthdate= " << pdb.dateOfBirth().asString() << "\n"; out << pdb.current() << " deathdate= " << pdb.dateOfDeath().asString() << "\n"; pdb.setCurrent("Baay, JG"); // out << pdb.current() << " birthdate= " << pdb.dateOfBirth() << "\n"; out << pdb.current() << " deathdate= " << pdb.dateOfDeath().asString() << "\n"; pdb.setCurrent("Barcza, Gideon"); out << pdb.current() << " birthdate= " << pdb.dateOfBirth().asString() << "\n"; out << pdb.current() << " deathdate= " << pdb.dateOfDeath().asString() << "\n"; pdb.setCurrent("Barden, Leonard"); out << pdb.current() << " birthdate= " << pdb.dateOfBirth().asString() << "\n"; pdb.close(); out << "closed " << db_name << "\n"; } void querySmall() { //query the small test database PlayerDatabase pdb; if(pdb.open(db_name)) { out << "opened " << db_name << "\n"; } else { out << "failure opening " << db_name << "\n"; return; } out << "number of players = " << pdb.count() << "\n"; out << "max. 3 players starting with G: \n"; QStringList sl = pdb.findPlayers("G", 3); for(QStringList::Iterator it = sl.begin(); it != sl.end(); ++it) { out << *it << "\n"; } out << "all players starting with G: \n"; sl = pdb.findPlayers("G"); for(QStringList::Iterator it = sl.begin(); it != sl.end(); ++it) { out << *it << "\n"; } pdb.setCurrent("Aaberg, Anton"); out << pdb.current() << " birthdate= " << pdb.dateOfBirth().asString() << "\n"; out << pdb.current() << " country= " << pdb.country() << "\n"; out << pdb.current() << " title= " << pdb.title() << "\n"; int start = pdb.firstEloListIndex(); int end = pdb.lastEloListIndex(); for(int i = start; i <= end; i++) { out << pdb.current() << " elo on list " << i << "pr. " << pdb.eloListToDate(i).asString() << "= " << pdb.elo(i) << "\n"; } for(int i = start; i <= end; i++) { out << pdb.current() << " elo on list - or estimate " << i << "pr. " << pdb.eloListToDate(i).asString() << "= " << pdb.estimatedElo(pdb.eloListToDate(i)) << "\n"; } out << pdb.current() << " elo on 1991/1/1= " << pdb.elo(PartialDate(1991, 1, 1)) << "\n"; out << pdb.current() << " elo on 2000/5/5= " << pdb.elo(PartialDate(2000, 5, 5)) << "\n"; out << pdb.current() << " estimated elo on 2000/5/5= " << pdb.estimatedElo(PartialDate(2000, 5, 5)) << "\n"; out << pdb.current() << " estimated elo on 1975/5/5= " << pdb.estimatedElo(PartialDate(1975, 5, 5)) << "\n"; out << pdb.current() << " estimated elo on 1993/5/5= " << pdb.estimatedElo(PartialDate(1993, 5, 5)) << "\n"; out << pdb.current() << " overall estimated elo= " << pdb.estimatedElo() << "\n"; QString bio = pdb.biography(); if(bio.isNull()) { out << pdb.current() << " bio= null " << "\n"; } else { out << pdb.current() << " bio= " << bio << "\n"; } pdb.setCurrent("Zysk, Robert"); out << pdb.current() << " birthdate= " << pdb.dateOfBirth().asString() << "\n"; out << pdb.current() << " country= " << pdb.country() << "\n"; out << pdb.current() << " estimated overall elo= " << pdb.estimatedElo() << "\n"; out << pdb.current() << " elo on 2000/10/5= " << pdb.elo(PartialDate(2000, 10, 5)) << "\n"; out << pdb.current() << " estimated elo on 2000/10/5= " << pdb.estimatedElo(PartialDate(2000, 10, 5)) << "\n"; if(pdb.hasPhoto()) { out << pdb.current() << " has photo \n"; } else { out << pdb.current() << " has no photo \n"; } if(pdb.hasBiography()) { out << pdb.current() << " has biography \n"; } else { out << pdb.current() << " has no biography \n"; } pdb.setCurrent("Aaberg, Anton"); if(pdb.hasPhoto()) { out << pdb.current() << " has photo \n"; } else { out << pdb.current() << " has no photo \n"; } QImage img = pdb.photo(); if(img.isNull()) { out << pdb.current() << " has no photo \n"; } else { out << pdb.current() << " has photo \n"; } if(pdb.hasBiography()) { out << pdb.current() << " has bio \n"; } else { out << pdb.current() << " has no bio\n"; } bio = pdb.biography(); if(bio.isNull()) { out << pdb.current() << " has no bio \n"; } else { out << pdb.current() << " has bio \n"; } pdb.setCurrent("Adams, Michael"); if(pdb.hasPhoto()) { out << pdb.current() << " has a photo\n"; } pdb.setCurrent("Polgar, Judit"); if(pdb.hasPhoto()) { out << pdb.current() << " has a photo\n"; } pdb.setCurrent("Anderssen, Adolf"); if(pdb.hasPhoto()) { out << pdb.current() << " has a photo\n"; } // checking overall estimated elo for a historic player out << pdb.current() << " estimated elo= " << pdb.estimatedElo() << "\n"; pdb.setCurrent("Botvinnik, Mikhail URS"); if(pdb.hasPhoto()) { out << pdb.current() << " has a photo\n"; } pdb.close(); out << "closed " << db_name << "\n"; } void testPlayerDatabaseConversion() { bool b = DatabaseConversion::playerDatabaseFromScidRatings(source, db_name, picture_dir); // the jpg is attached as photo to the first player in ratings.ssp if(!b) { out << "conversion failed\n"; return; } // query the converted database queryNewest(); // use this to test the small one // querySmall(); out << "end of testPlayerDatabaseConversion\n"; } chessx-1.0.0/src/gui/quicksearch.h000644 001750 001750 00000003321 12223260306 017632 0ustar00niklasniklas000000 000000 /*************************************************************************** quicksearch.h - Quick Tag search dialog ------------------- begin : Sun 6 May 2007 copyright : (C) 2007 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef QUICKSEARCH_H #define QUICKSEARCH_H #include "ui_quicksearch.h" class QuickSearchDialog : public QDialog { Q_OBJECT public: /** Create Quick search dialog */ QuickSearchDialog(QWidget* parent = 0, Qt::WindowFlags f = 0); /** Destroy the dialog */ virtual ~QuickSearchDialog(); /** Set default tag */ void setTag(int tag); /** @return current tag */ int tag() const; /** Set default mode */ void setMode(int index); /** @return current mode for combining searches. */ int mode() const; /** @return current value. */ QString value() const; public slots: /** Execute dialog, save options on exit */ int exec(); private: Ui::QuickSearchDialog ui; }; #endif chessx-1.0.0/data/templates/notation-default.template000644 001750 001750 00000004711 12204210231 023520 0ustar00niklasniklas000000 000000 [OPTIONSDEFINITIONS] #Name - Name of the option. Use @Name@ in header, footer and markup # tags to substitute the value. #Type - Can be one of String, Boolean, Integer, Color #Allow Values - The values that are allowed for this option. Ignored # for type Boolean(1|0|true|false) and Color. Values are # are a | seperated list of values. For Integer types a # range is allowed, specified as in 1:200 #Default - The default to be used. Must be in allowed values (duh) #Description - Short description, will be used in the GUI to change the # option. #Name , Type , Allow Values , Default , Description MainLineFontWeight,String,Bold|Normal,Bold,The weight of the font [OPTIONS] [OUTPUTHEADER] ChessX Output \n \n [OUTPUTFOOTER] [MARKUPTAGS] MarkupHeaderBlock=,
\n MarkupNotationBlock=, MarkupResult=, MarkupDiagram=

,
MarkupMainLineMove=
, MarkupVariationMove=, MarkupMainLine=, MarkupVariationInline=(,) MarkupVariationIndent=

(,)

\n MarkupNag=, MarkupColumnStyleMove=,\n MarkupColumnStyleRow=,\n MarkupColumnStyleMainline=,
\n MarkupAnnotationInline= ,\n MarkupAnnotationIndent=

,

MarkupPreAnnotationInline= ,\n MarkupPreAnnotationIndent=

,

MarkupHeaderLine=,
\n MarkupHeaderTagName=[, MarkupHeaderTagValue=","] chessx-1.0.0/src/gui/000755 001750 001750 00000000000 12234477214 015172 5ustar00niklasniklas000000 000000 chessx-1.0.0/src/gui/commentdialog.h000644 001750 001750 00000001226 12223260306 020154 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2010 by Michal Rudolf * ****************************************************************************/ #ifndef COMMENTDIALOG_H #define COMMENTDIALOG_H #include "ui_commentdialog.h" class CommentDialog : public QDialog { Q_OBJECT public: CommentDialog(QWidget *parent = 0, Qt::WindowFlags f = 0); void setText(QString text); QString text() const; protected slots: void clearTimeSlot(); void clearTextSlot(); private: Ui::CommentDialog ui; static bool lastTimeWasEgt; }; #endif // COMMENTDIALOG_H chessx-1.0.0/src/gui/savedialog.ui000644 001750 001750 00000036433 12127766505 017665 0ustar00niklasniklas000000 000000 SaveDialog 0 0 518 567 Save Game true Qt::Horizontal QSizePolicy::Expanding 20 20 &Discard Changes &Cancel true &OK true true Players Elo: Elo: 0 0 80 32767 &White: whiteEdit 0 0 0 0 &Black: blackEdit 0 0 80 32767 Team Team White Team Black Team Qt::Vertical 20 40 Time Control 6 White Start Time Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter H:mm:ss Qt::Horizontal 40 20 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter H:mm:ss Black Start Time Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Time Control e.g. 40/7200:3600 for 2h/40 moves + 1h Tournament 0 0 160 32767 0 0 E&vent date: eventDateEdit 0 0 &Site: siteEdit &Event: eventEdit Game Information 0 0 80 32767 &Round: roundEdit &Date: dateEdit 0 0 160 32767 Qt::Horizontal 40 20 Result: 1-0 1/2-1/2 0-1 * true Qt::Horizontal 40 20 Qt::Horizontal whiteEdit whiteEloEdit blackEdit blackEloEdit eventEdit siteEdit eventDateEdit roundEdit dateEdit result1Button result5Button result0Button resultNoneButton buttonCancel buttonOk clicked() SaveDialog accept() 20 20 20 20 buttonCancel clicked() SaveDialog reject() 20 20 20 20 chessx-1.0.0/src/quazip/quazipnewinfo.h000644 001750 001750 00000007353 12223260306 020765 0ustar00niklasniklas000000 000000 #ifndef QUA_ZIPNEWINFO_H #define QUA_ZIPNEWINFO_H /* Copyright (C) 2005-2011 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. **/ #include #include #include "quazip_global.h" /// Information about a file to be created. /** This structure holds information about a file to be created inside * ZIP archive. At least name should be set to something correct before * passing this structure to * QuaZipFile::open(OpenMode,const QuaZipNewInfo&,int,int,bool). **/ struct QUAZIP_EXPORT QuaZipNewInfo { /// File name. /** This field holds file name inside archive, including path relative * to archive root. **/ QString name; /// File timestamp. /** This is the last file modification date and time. Will be stored * in the archive central directory. It is a good practice to set it * to the source file timestamp instead of archive creating time. Use * setFileDateTime() or QuaZipNewInfo(const QString&, const QString&). **/ QDateTime dateTime; /// File internal attributes. quint16 internalAttr; /// File external attributes. quint32 externalAttr; /// File comment. /** Will be encoded using QuaZip::getCommentCodec(). **/ QString comment; /// File local extra field. QByteArray extraLocal; /// File global extra field. QByteArray extraGlobal; /// Uncompressed file size. /** This is only needed if you are using raw file zipping mode, i. e. * adding precompressed file in the zip archive. **/ ulong uncompressedSize; /// Constructs QuaZipNewInfo instance. /** Initializes name with \a name, dateTime with current date and * time. Attributes are initialized with zeros, comment and extra * field with null values. **/ QuaZipNewInfo(const QString& name); /// Constructs QuaZipNewInfo instance. /** Initializes name with \a name and dateTime with timestamp of the * file named \a file. If the \a file does not exists or its timestamp * is inaccessible (e. g. you do not have read permission for the * directory file in), uses current date and time. Attributes are * initialized with zeros, comment and extra field with null values. * * \sa setFileDateTime() **/ QuaZipNewInfo(const QString& name, const QString& file); /// Sets the file timestamp from the existing file. /** Use this function to set the file timestamp from the existing * file. Use it like this: * \code * QuaZipFile zipFile(&zip); * QFile file("file-to-add"); * file.open(QIODevice::ReadOnly); * QuaZipNewInfo info("file-name-in-archive"); * info.setFileDateTime("file-to-add"); // take the timestamp from file * zipFile.open(QIODevice::WriteOnly, info); * \endcode * * This function does not change dateTime if some error occured (e. g. * file is inaccessible). **/ void setFileDateTime(const QString& file); }; #endif chessx-1.0.0/data/chessx.gtm000644 001750 001750 00001031352 11216274543 016542 0ustar00niklasniklas000000 000000 \LUK* !}OV jH #lJO M٣i֢&e@ I9{J j"e$)0م#E.%9#vh^<>[B>/l(; [%B<>5{C 4,ϙceL*!2"L^  1^6vPN>ͥVHڧ2:\-N fH,T99 gmW32"c*ZeH% sWz2*V$~x# }#䓢 u: 6&l2"k3Kl81#cL Zi-;#c k\ׇ3"2"SKş*S$8="S>6 S`*$>$}Hp;2=n[-7=@ө93<5k7Sr$7cA7.91*40BH /2D2*%HN3#!156. P"=r9*t@* g#4֤g -1)bU,0 ĥa1!#mbHm'IЈj&Hhp#)K 썏=<[\QpD Ep cAG4,\-紩zzѫ0(/[2gQ3*WA-j?|#:-mXA,4$L-_:̐wu,>+#x>-ꡗA>-9P=4s~93" ۝3+TJܾ5M\̴Z<.M$x#Nti^1#2]dU=6ZW՟x\P J.&-Hw[Y^6.}1{C|CS zSk2z>x=xqD w#Ov_h4$obȭ eZH D_ <Ԗ=4ZBdTS;\E$L5c&}#+KFVIJDW@4$JllHeJ = X936m]Ad<<>6V2*.&X;f7/(h[c"& >ܪ0[0(%,}Z "]Tԑ93,%&R@9 mHN@$i 3+9ko" [g\ Oɀ2" . #sSM L 3_w_?W3I .UŁ LA[1!|3";h@X9*F+y=/-掘(Q7ML dߍ2"Uw ha1)XLOtʺ!G#=-=r3#/ԨrCڅ,#Zwzz}P>-}ު {2*xys4,v B*'$nkU &kׁ$-e{;C<>dc =`w5#\_ -1)X0`b V<@*Q>z Q0uE"Mc`*4,Kqr:HVtO3#D zA6.4$=  :%H ZUd#1܄2*AK SFZ*"90 Z<>K K|'i x9*\2(93狺-' W1oMg#` g5B"]v<;4ٿ:k!2*Qdu սQ(*0(:ò4$ΠT5҈1)̿܆`1!ĵr X*і, %S^5%4Bj6.n: 6&?q3Fn*"po _8;)Ϙ%7s9*}4 _E_;=n 6fE -fuʯ\Tz \$+86.ZҞG>-Z(PXY 4$Su93Q͔ #Nʞ>Vw{2*DUZ]$$>/Ӕi4,66?^.:3 T0GU7!'R '`.5,룮;4Nr0m?Q Mc0(,%++;4ۡ4$ tH~b-# UYc;6.GGs&^e#5$hd9(5g-ZM$AP- 2"W7v44쾕l!&콕eV^ `R&\e $6-՝A C&0 &vI2*퟈>ѥ7/ʸLi&4$ȴ%c;4XR |AɊʸ&},9*Dq-|JTkX fP#p@4$';"$?C3i- @%@. ⎫a$9*,gJ.&b/*rt4=PA3"bk$Lv;;)v-#*";O %<93͉T |w &-|hy wwwvq',v&m=OagP>4gIG1BF f,f6.cF~a'`6.`1`=ي\Z:Uk*@2 SP͑P\4 M4M?W$K28 E(- 9Xa-9*6 *P09*47|33.Η0(0w2fy /7;z0>-,4C:,9߃>-*: (R?u(<>`3# OX3#*< zV"ceyң%a>/hD؉'-8$ +G+1!>:,L?5z犼!u# #lן 3dْ[e.>/F{Qc ׋3bspdw;)ʂ-J xtEá_xS2&V-3P$:1R l&w7f͠ I뮀&ؽZ193r^ #;لJ>-F* F8d7/Ak_>-crX4"hzn; & [h93@")I*R!%V*2*֣j J SK ~;L0b4,} a44y`c332*^SG:3[U<>J3D$[BweB*"8YuD 1K6&4//ACw9*.-3J1+ET}b5'E9*t[vYe Zwݝ5: [ɑ:," 4FF 6wF8Éݍ>4H]#C<>p7[8 ;)Lgp#6j $Q:C }O$E> !𮋢,5Cӟ4<>ܱRO| ,!ψτ($)?8=6|/*|xTc'OYZg\0('v%/..7 FRГ4$A ,@*8N9*-ybStaR3nߞ93n@߽&h!dEb^>4diʟ7 cciW(//$Sr(:%Mp7%DHgሰ B] ; >;r&>ȧQ;2>,L>4=lЮ3qx 0T-LS0(-q!|&*бIvS1!$F=|x*_;$0a $ hL#g# d[!9`2*OtU2*iZ${yhEGc]5-܌xγTKr19*#:1zy0(\iQ@тyؾ70b غF ySt (K$ԥ%y> m.+4$l=4$>S%;#̺Ն\E6; ,;>-ʩ!%_V0(&SZl#3+&WmxKf=: Qvg9*y;3#.-_u "ClN'I:.tT2"l>)4$|/ Kuc r\#qW3+pP7 u>-l f(2jP?0 g,U\ [:˚ZZ*yZsV* UJ UaA-T% kr&S3O1)Q.Y\~$P&<>OI]=Nkk:NpT -Nkο4"Hv-s F8h AfTr">1W=<<6&9p=p+%7k즷6 5RG0(4RL4,.N0 +9?Т]=6*naY5%yWJ&ʪADyф 0e9Š R;m9*T7`93J-yRI p7+o ͪ0  >1?h-}9 Ή?`IA& fb2*[)VCf  ܜT1-6ۼذB>>-.]/7/' B Dvֈ9*HWe>F 9:%'n;-Ǻ,z?6&IEz B"<{P$GDc:1<#d9* Gtr>- 9(SU!2I PV U81S 蘲%!+;-. oxefuZ93|Ҕ<4vZjrLwXѤ l"xs2"h% g2w3#eFDe" a)Śz`2-^{DY[`knY82"Ok$Z9*Mwm!F4,L $92"KyF_@f3*:/5%6yd 5d-/, Lh4,,(_`0($X2@<>#KT] W+8 4i f;)$ !_tjo3-sl+,# H~ yH  U  O˜K1)Fprg^h.6$:3+ *[9*R & BF-űX4@S R>+1&i']2""|%^:ulvI,aԩL=]e ;2q :2"S Cp0 ?br 6O 6|^@; |\4ؓ9*'1)o}x=#!y ]( HZo0(A'k[ |[i3+r2  T1)] 1 f)YD0-<$^-3?7/F5s-!=A9*Fd93(R*uu1xN>-txn q=U9*nMh7lV~Nu2"l:LSnc93jΆG&eVd4$b To:1G+YP!Cِl>-;>43R)-#*iMk *;px05d,#':% @{9*iH] \{2# Hk_u dr0(1aۀF T)9*In". ѳ h#UK\9(>I,?P-<]T9W  Daϡ J93Ԫtyl*I "P3€4C$ŵU *3k3+±kA3+6wo3#$9*Ҙ E|c>-5h*#3U#S#9|$ ֧b4,Y]xE#7%=+%T\wC6.y8:Ljzy<v쑶4 qjk ?"p_>-nr n%`Dj<>mpU[>-m3rK$i} e"y=6^ѧ e^S|% I剤ܶ4,Hњ7$H-yF#E1 EDj ó 0 A?k=䥷  =yEs;7 9Jk 6χf-9*3>?:3/3i5%.VO4=.D̰?s+R:'+*WE4$$ġ:j n֊ ֭5@1!hX4, bsGJQG-3W i;y~WvQfLN f3+hRͼ՜#\2*%no#kqץ >-Qfʜ"n=6X˱<>SV?m.rPg:r33++_'$H0(%9*C"v$?0 Ɩ6.xwF  b37󠢲L6=ܑJؖ@(o .Gg2*2p& [W/ Ag:UF? ~]P1)w0 ,$s3(s.B?p9:g|Fa*$fV0|G>-f7R #d崻޳<>bLx Pb9ٞ75%b ~#a i\5$3#W(G)@WB"Z93Wfl #Ps *S~ӾM5HE_ 4$̘,I1!=W9=q7=3#xM{o m C}z ֞)33=*e/$T .|2*& 7Ap9** 89ֈ[r ?E=6Q0:;23s5-[X^ 2"K&=c6.MQQ؁ ~ TË<>#Ib&_B  ^\b4F<>E4VYt<>Rt?SCQ{xG`>E ?93+9kx80>-6%X0>-0A*7&/6b#.m=Z#,+ ,D~w^;-AEu @ȋj}|:19'na41uY4m 㔣m3#@#ν#$  `(S S|S7ٙf%+fk`L4-qH{? Þ=B ZS4HH Gҽe4V03#Wש*89.ь#ڼ%e cGuN:,}b$@6.l <%FQI;4$??+"-$C4,d<> =ڒ c-%eunM3+Oq* .!N?f@VQn>?ՄB)2k<><63+=s I>4w;N 9*vgHu@"{o A)"3+m]0 e dPU=4ak<>`D=6_y@A5%_Q]!U @\5I4,T-Mx_K^V~EyJMD#@-|2*>z)iu4&;i&$:':m23  3Hp 1%+:,.&u;+4%*!9**H$}:%'*$r8C $VvZ "uǺ  f2"#]u% xPo x``T2":%m i%C<>udq=:S+;+Ѓh?&NS0 ]z6.1z<BrB0(<1g2"T1?"'gQ4%u1ۣM^ c=+𪺈AK380WY5:T,Y=6؀R63#D2"@y3sU𒩹ׁIֲ&-F-'W_ Qy=<~%{=v. _=+uIzK>-r:1p?X[҈!:(dn92d1%ݙaa}apF˼l=+_@jUH IսB6.F~ DBq93CtA5-B:Q +#5z& -#4  4m .o]r*#+Z &(kXѽv>-&ؔVF0(&RHZ #~jFwy T*&( xݭ$06 31q5 EJ bތ  ˝4$Gbv=Z֗k=4WO 9[5%a ";2UKt}4,J!%$#T~!%-1>0<݀9*8684@3#!t>-5L g|͆5-͗Ei Qv'h ʴtĘhJĔ2*.b`3#ﯱ[g3$Seigh_ eOL%9*_ k]s0([sۛ2"U7S09*QP93O&N;EL処ѝ2*K=j~ 2 H%2"GY0Yw2"EOneA9*D'$?g9*Ags]%@j~ =1)@:X9e7;/&1>f#* /f6_;93.(Bh o&%5@6."hEl3- pb !&1)?ck,$a|3#($'A`4$gC+: HZ Hz$3+ 䝦O =4:d<>~2 o*ʇ59*ؐ Vky=4[ xr $^L7`93t*,h *O=:%93֫89ܱR+f1!؎1 d,$+ʚW#G#&m3+|p9*(:%5Ft<>2*@=4CaL `ܴ9*yMm5)#,];Gau<>@!::P2G1; \! ͆B#bpl#Y?kqP^"VRY T4C/ JM="B;i#-::,?`;pP )!+:/Ɵ :(wc 9G 6;:1,ơe(]A=$@3=#\:#XX_:3#74,"n>-" "b !b=kӒ  ~1#K6 I՟  g7 Z2"`ki)<'93{3#iE,OR py#)bD  ݹ6'H9*nqW3+ԖTz /-,#2O$ߴ ێ ݉1w#E/ȅ(!^MZ+l-&їד#"BQjW<>8/ϳWGǑ;%]0v$ !ť$Q2"i-,$:=4ܣYޔ oC4$rj\ 6 vS$,0hG]',$yTN$^y[,-=6(Ϊ3+膮Ϩ;)EZ9*퇑:1dw /%$}ڭX;|73#z>Oc9="q_>::;4m ^w0(lx5|\$-ky3hew3+ b)M ^2hiZ7l3(QW-lfM6.PR9PZfȡ1!GpU#F>-E)^=,@{G9 =;h@ /Qhq3+q$MiUZ.ֈ(?g$[+2.3#r*  /SJYYu|?*#ҭP{I. ͚҄@/q;)e=PD V~=4dz22*Ǔ b-%tPFK1,v3#Ti 칥͂=6쵵{I-#oH93:R\>-|ckB:졪`{&܍윱.N ljA"ku1)8=g >j9*~BL!쏓tQ[nq *$b2"$7z  쁦vv|jt {}!q*1!h:5w=4h(:ށ1)_tF#] ևܘD9*S]BFX`"&EX撼6.BgV^ AtWV @{/J1)?h7];0 >A,4ް2 =,aT=4;i.B&9敪<>7S<!5a90(3pO#)/b3+$Dk\U"-"מ9^ <>dv; ;1&ǔ:=4 ^{  rW  菿 ʞ'͇ gi,+k<>%FQNh2*8ް8OȴJC ob$d5% DŽ$sVD@9*9Bw lfD$8iU4,$(*#Ρ9N;)J|!+lu;|=6D:Tݑ m6.鼩rR6&fJ 3eb9* { h2"Eg 5 $=6#yNj6&R`8 #mҧ 뤹Jo9*ji;ɤ[$v <>AW5%>#67 #>[" {ABp9p&zp>-mr#m{g.$lH3+`׫11*_ph>-]ŽMX?6.T\}1)SU2"N JlAl<>Kf)t ?|)M >B5ᐃ0 =4,:/9`4"֋3+0mu++\7*w>-(g'93&.H %?V4,{ ?p}1)g3+WG0(u  W( U;'<6. {O S|#+:^beWEJ;)%al,3!8 4$…p5-|Zq9*Y-y{>0( $N3#]M]E-;kRc >-㿖t yF[3#5!FT ߱?rJz=4dz*=4\^ :j63d3+MN]c$W P(l'0(# D9 7/s"8K 귘5? ꮈK 9*Oc$>4Y@1;)Ꞃ.>#2C=4gMR &x4,Yȣ[. 'fꑧlYq $ؽV&)#;ꅍaI"#ώp9*{Jp@=z0-;y~%y>-x]IJ&t|1K#qsuc3#qAmlcn 3#jN0(i駃hψgy̩<>e9'6.bu,6.`=9ƅ :1]8LQ. W*֌ +3#Vi%.JbHϮ~^&F a@#5dƤ2?L`g$/t>-.P;Љ93";Es-#!gfZ3+"/}4,QY W$I"l Ag9(D"88_A&Lp#7L!{``ol/>4M_P ᦦd<>2k@JK0(\brs߹{'0(јUe(m ˶YpnM *eW܊}3#~wN1)D{;2m_]="魌( 3#ꙻHC2*Ighb3+k*ҶA1#ο($:[g93,6 [M2"VZw#%鑱j$ֽ8; P7R%Bo93邬;2. <>y:J2"w+vK  utrs-K&q^Zrw-#pOki2*nQ%.bՎe?:3bBAP`60(TIK+ OFE#M%c9*J5-^0(GRs8!BI*;2@ n!-%=\)ob6m.@"-*"t=+-S  n[O&֯= c֞x ^Aaz#Ps%&Ca9* 2"# E3]pBu]=6p?(` #nž^c3#gP3#g6'NW^t-R<;Xx1),=6W"|MWR\U|~MSvj R^O354,RNR00 Hgvb93@X$ H:")=fUj==X09DU<>6`M,#(QLC9*%Dni_K؎ Bt]5FA=+=f >4c^> M. zS>- $c 4D6X&-KI2"=*A8ǀ>-u:MR<kh1W=6Y:%筪@$窎ȱ3+t. s *B )="砌TՈj$]皌o=6瓰7q3=瓨 px $/&un 8z4q`3#Hkվ :[$~6" vY#t˟}-t+%ۏ5%o6&jI>fB cmDF* bK~;>-[>}y~~@2"[(2"SoQ>=;Nn1::,IS&?!ICInD{Ido-?4,IO<>=w+K6=-OaJ#=(&2#:S2"/F/q;), S1!*Ơ&6&'zij &ͤ 93%ޚ.nk"!7~5j9 tC]u9* &c8b Bt:3Sy   ]RFk#UӸ9*AXB/ԡ93Ek#By:d@X%2*,^|Xth446Q{4,P:26rs2 [怇3#݆3-3 n ڵG$< K{-ҴDt0(\FOZ93O4$Ɖw #M '1!LIR SXī 歋ԩ+<>樆CWI槾5Y 桃QB:1gD]/h0 -vza&掔daP=-惕#MD<>怳} }Ѝ@O |fB&{z<5kbui T- aw#_\bl Zw=ď3+Xs0(W p<@e;Q}Jf1*Oʳ Gd漶D"35E:'?>-1/H S Rl=4 Џk#|9^?cr+$\ v "24܍$<㞠"5cgq7/-ƒ YS hF}9* @KV `&,t xD%ޅOƕ:31!A| _pbIU@ =#'+LM4,!㫰S93Ø }V޾lL +>-峻[C?|+$`h֠ V(uqB<>%S!2*厇&I  E?H:,偹V&|Zl+A3#r>,Ngo,#h".!B8d@W c=a2S!_7?_I>BJXMj. $WJ Sj*=3+O1)?`&->' =t$, =^h4$;r^;? ;4Hk7r>-; _J}45J1A3#1zx5,$'aKp%4;# >Eq1X &l/ |h$+Ƨy&-Qj *n ޗ;2̶>-Oʥ:0= d  5K0(!@ h\On2Ր 93z2";_ iRlC a6 15<>ݢjM:,VD9*6d 3+Q1!ѤFF2*SY q侞T̈́]"伫f:伥~%&䷕3c.!g?4,rcD˦?p7v4,ͨ4,䧝_Rf4,䢧:%#ov&eTQj 䋾k693!꼍>4\C-٦y_4,>6.4;q#'t R)V1!Stl }C!0 wS.8`, vlA9*pp,soHq oY l͕dƴ="jD4=4c cY֠%h2*Wu T^2"PWa~DLL7ѵ.1!JқD̬b=6C gAV▂L>ӣI<>0cޟ:(/+rkv .DX4,.5=4,ݲ)!*ǢaN+*u]h=6(=q  !KRv4a Y93,ZT ̄[3+=ߺ  jI7/']N1)l3k.="  -$D06#mc$߮tS gk="ܢ]>4Lݢ`#Ԫ1Of;:Ԝl3#+ Y )t Lc TODÇ-5;:Ȼ=[O˨O=aq| Ʈ"09*<><('2#)OdX="K~7/$g &Жצ;)ܺ胴&tO#GbD6.T2GN + T)#"i<>㘦MBj:& x#N)!\aN÷_!0 [<}B,#tARun`}8];2k}E2*hOF? fDF$d}-5%^o;)XD;2V׊j$=6RJ\;OփuMhSb)*K%)KH&I `Ggy? FCOEdIDrn0(B4H+H1!=zzŇ 75pTc6 JT2G.{3>=<.m8s2".i׵%B '(2\FX!xZ^mH=4!z7$ y H14,Ih41)*b3+Do . \1!>Tnm6&ߓڴ9=+ի`]B2*ȝNy:v?'6.⾁w2*~( _|Ԏ=4lO ⵨L&GG#Q RY!>-l3#V0G:3⨱+⧞O 6: -3⥙ Z|,;)AJNU7. Z-⠝O4,a (o|O %@'⋸۪I&bZk=4#&*#⁉7N;,~iEIA=4}C{}P |^@ e=6|O@)> s7-<>j;gi#k&gvoHn`LB`!V [G5%Xyǘ%W0) ~7.Rh3>-Q|T \0(H0u3#Gfn{ƷD+$#C]K ?!AO]T =+@k>e1 > txU+#2EE̼/7<>+M"'#G&]m8<> 91ta:yӃb \`su BՖ9*U I 0 BpTE93K H")$1)"s)#UV{QA 4$R  P sgD@ f#&VU2*MN93+ϱM ]`G6.<"2"#G|#&T11!E=4#4,᷋qBQD4$Vt933+$M9*ᦰvW`7/MLtᜉ [Y75%>-ᙟ'{0(\[73+uE&t3+haD6.y ?<>3+ᆺ < ~CaG3+zo50(wpW t`r^<>pĢ h6F>/^P_J9(W@I4bT#S7 Q,1|AK I1n?=?h`l&7b3o *3$ȁxm.7/f&4$/_n*Tx..#Z8H#y =$"*yNI2" L9*Jm*&:,#BX4,ni!G #5L3#O. }P`+# tȐ<~-3 <oS:3kSOީ3+v-UH#%&-<-nb$p*;}3S+lmrܳn%Ni'mvf3Y4$d[Q& #^2.q#\-f4,\AcW ő1="V#MT 6.IW2*IL(}lH1GSU;)DvtF=C2q) C7ֵ @Q)! > =#-ո\ 9BF SJ{=4AP iQr1![lᰈ $2qD-3%{KFQ! 1 ả/4 C*2*jD" 1!:9*l.a9*ߔ{*:1ssu$g ?Vcwm:3߿3cH-߾dw˚߽aY=߽%S ߺeb߸*߷E~6.ߵaw6P߳,a$߲gY7/߮Pjj4$ߪBFlX ߧzttn94$ߣ9 ߟq ߚ-I;4ߓI* ߒ6 1)ߐc{_}ߌE~񉁋2*ߋǛDz2*߇Θ ߇^}R_%:߅Q [߅"k߅a ߃8Ћ ߂Ty89*xS wEE"tjnf˯2*n&9*mz!rp lFS; j;H4&-c1_*"aT8 Tsi[_Sr鹨sS-Ch=OiQaaL3B}a/=4B/J%Ƙ")84,7Rqel7^0(6`9(5f3#/X#)ChZ '4TG$%QZ$wj dG4,"K^(|ġBd93{&o:k>&Ҳ-  c n3-##H÷93}(;2;{9 B5 m@0(u؁8<3+[ {w 1nZ@94=I.! >-l6>-8da4,7Dfk2_:d+,#=E =&=S~1!RW )V y}"ƥ!lۘ' y $޾SB ޼2+ 2"޻Z@:޹.c(3+޷f(޳t%G ެ!IxZ ޫ!җ ިpSr4$ޤBIr2*ޝP(oV9*ޗ2GޏˉHޏ\C  ލKox ފgB`=N ފv>-ކ#?ށ@{SyZ"|‘HXL=6yY{-6uA_|!rX  mPXR>-l` q$kbՑ1!i*ѐ kFe읭y*9c*aQ 0o3+\1 1)TӏvSI< R>!1!PW!4,PID;4MFh(0(Lc3=6H0(D2">Oғ9>CHu5-:OHk'4PRV2McV3#1gp -;u>-'EDlP'❧6.!ؑΉ w1\'9* g* ^7:a;$xy3+Gh 6&E<#-~ Tv4$~4 ̩rE 8l!4$C鬤2)3$+~B"=:K=4Yk1)u{{cMٞh7b>-ԇ˂2"=6.D}ML 53)fܥq1!68b>*$;4$ݾYN'ݹW٧ݳU+> qݯybId93ݯr@"ݪ5yݪ4a;:(ݥWH#ݢ8< ݝK &>4ݛzPDݖ^>; ݖ TݏFn?!݄c"<>݀0 ݀$ ~If|Ch[9(yR%hx8ϰ=4uʏ|t4$s9adZ!pJZV:,n;C$mO, h a^-#e[ c-P;)a]֢0(aA@a,W}:,a#9E$-\>y VvJM VciqVؔ`;#R?F3+Pey΋L74,K4:1I]金4IX>-G3h>-?B=4I].aͱ띚4mxvt0(PvkI9#e>-ܶ#9*ܰL]b9*ܰ70 hܧ#D3b2"ܦ˰#ܤv3#ܢ^NL(q%!ܡ8"ܟr5-6ܝOd3 ܝM=6ܔ6=-܌ *܈"Pߊ>4܄1Y&܂S~w5%܁!$*|b&" zΣA~* y*>BN2"yx]k-%olez5#a#級:]BG[ QY;bGG Vg4,U?Ot!MR^r<>?n A5:?]*#:.]>-:#-̉=68N29*6NSr3T}o!2o-!c3F'?'X=<"&O 5W9 };#*$m9[C󑿨6.}+ljay#j;O4, s h!k&  V;22  e(`7'Y'@ɦ3+y4-;v1)<܋4,nga-#R]o9*Iy9*{Dؙ"G*Ii&6/H2*_L!93՗V:d˷sH  l+v}?c$ `:"RuӮ ۸>~9P:1۲\>-ۮ> ^<>۩LۥL : $+ۥҬ.ۥBo ۚ>>^ ۖݴ ۖҢv-#ۑY#!ېRs ې3%hiۆ]쎟j69*ۄD_ ۂv졬;4ۂ]9lu=4x׹Rt3+x/F+02*wUgn:U#uZ?F t3 n(o<>n?m;'4,l̰F} iⲿ"i)Zë&-fCcWq; e(+$#bx2"YSxd5%XP X7 ,#T4=b LG8_ Da7'='&9uu=8C ]=460ô"3qwR; 2p<>1[=+-e>-&Sƍ6<>$7J[P|3#CKFKXL?*ԄS d)"C:{*#11AD %5# F>sVS:1Y‘;=5=4[`Q#*b,jAt"1!ٚ69x93ZI-81ч%.1Lýp[ s<>ڽP$T 3$ڼ V4,ں"ڸ% ڶ_ƍr1!ڴWإ>ڱ",;)ڱEF+uY$گՔgl=<ګ,zP ڡ,1;)ڜoo$ڕ>٨ ڒWD ڏy޻ڌ™;o! ڃք涥!ځUU3$}pg-0}F~ #Z#yf@ t΍Wt'r؏2"knQߌjG3#i0(gY\I9(dUP]3c6.ZEQٖI2"WZc+5-Tv> S]Y/ Qh7MFE_ϑ E\@L2*E5\A D\*=6=`2*<-(d9UK,-939)X2 77"6]>-49_r2+ 1)1v-*S١9=i#)'~v!4"&uS! !-ٮT]8="ٮdᤅ٬Q2*٬/w83+٤lGĆe7/ٝցٜOe٘tSD2"٘1V 1)ٗԵZt2*ٖzٔPF<9*ُ ٌO#Qa6.و PD!4$ـU< zJK x qt1#qn&p$=6n@zbA<>j g43"gQV9t 0,$Yp !Y8cY$MX}Oi VN-#SGT3RM6@f!*PE2"PM6.O  MJPM=6KmgpKK",;4IE>ňKo4,9X:6+`gKW2*5Pz; 1O=*80,a>-(%uh(zD&9*&>k%D|c;2m<4,>7  ; `Vp#9aO& vcXs1! __-# m. uK%ג`#2׃93Yay yW-#*֌3+HV0(IG-0=64W3+ަw` ۳!:ᇶ։Ԕ,K=4LV!'  euE93*i; 6- /nˆ3*ظ7/جb>n3+تh\1"ة)"Ӭx ب4 (أ&} ء ؝P  ؚ?C^1!ؚ2Y4+ؘsؘE᭚"4$؂5a ؁XBR/3+{=L ydtE|:u%'qZ#tsYypS_-oFa4,f %7cD7ccXu-cU2$_[,%>>-Z+7/Z1e XqWb>+#Os=-LۚH Lr X H ^G=kFPm:%Ee9*Cp% @g0(A ; >un=47S/D-6x53Ň=45M23#4eC2"2*` -7/0Pg-$d"My3"#x'-##>w?# j"~/p# e8x4,)9/"}}$' >N"#ó5  d%W<>s2Xc4fQL]#h0{^ ^K֚6.U 4$3, s$8[\-׏H'")׊hׄIEׄB^3 ׄzqū9>-ׄp~%ׁۏ0 ׀4~z28A >9(vkv A;-s9l9*o$&*gip h6.fT#)d} 2:d5,9*U!@ PP2"Eky#D|ߛ4$:S;6.94r7/8"\6T 5 aj{2$pWD1l930Όe =++eLO *rI&D4-w?^)!*A&! IJ'*J_ uj7wIcS2*ܛ*=4Cߠ=6VV$ Ų˭, 0l&lܰ=+ݒg+; 1)?u>yD:%%$hJ;)󄡘9*Mڼ #*/(}xF<>x9+m54$gqC@";2[Xq>-ͱ:ha+:ЌOg; ֿ 54$ּtַ}%ֱíb ְ:d#֬bU1*֪< 3#֨ȳD2 ֦լ8 $+֤YYM1!֣֝p*֢8@w#=6֠jF0֠A ֟}~՚9(֟aBѴ=6֞o=RC;#֛>2*֚ N0.N3#։2jU=4ֆ$1wyօ*$譩ց,=4~66-xbʈ-3+t-m$";4lŇA 83+c=3bp=4\IL9[;4$[ R&!! X+-WlЖ#V࿡,.Sx#S#!Q, QqE[;^ OҾ>&O)>1 Np)NP;T3=M$ϟ9*Mx6.AD]Ձ6.@Gi>#??Ζ4,;Yp  7pK934lu7/.i[-#.9*,8AĹ'<>"2* Ɉ1!F ѱ2*r۵ Al[3%] oUy AW&e#ǑG-#*Y3#T~vz@[3+ |!>-e;2ьb!/Qm1; qP2**b@T)#* L175%ԇN}82*{}bpj}4H:b+Y DQ0(ƯgH2 ë^%ƒUt0(3F#սCH73Q յ_ۇ`*յ~+p7|#հiZbG>-ծ-\A2"ի\·_=6ե:""բ9V`I ա`.+ ՟ZDX >-՜9; ՛ +5 1)ՓP26.Տ'=4ՍtՋpũ}'6Մ%}\&Ձ7&&#Ձӈ#(=Ձ?ш7/Ձin$b&ՀO?$|"nS#{h(2zF1)u\$`$t v1)rFToKzl͘bx3+i^͖Eg^ Q:;4dȯT&71)W,0 `C93V9\qBD V?·*Kn"J.e Gٖ2G#CP=@3`?$A;"6 Ln 5sN<=4320(3?&2"3\NǬ*.|Q[+$.p^k$, k8:%x* G~`Z2*.&h C%h<>?@e#λ3+ 9t$Q.u'>/ V+9*7~?4"<M` R%p>-~)7B r Hp Ek*4,鯚<D3d2"\+U 4+Y=1#f= .EƏ$,y 'i׸#[[.x6.!Njc=Eԯ0=4Ԯomr0Ԧ]#Ԣ7C$Ԟ _IUwzԕ&y$93Ԓ(b<ԑꑹԋe$ԉϚ0EԆ$Gc-ԃkԃ/A2*Ԃ F93H2"x~@7/wuD1;q*\d#)pl)Y0(lè0(d#ykbg`ē0Q_@y[@" )F2"Y~,9*Uq賓Sn#L;RM RY *#RI)14,L4; L3x.Kd F9*C2=4@"83+;$\ 8xR{{~./} )F 0 )<>q`6-<>$"o ! Zt79[3+-Ӯ xӭX'ӫ"z8:Ө"mӧV 1!Ӧ#:>"ӤHY2"ӤyjBu0 ӝ@֓9(ӑm"a<>ӐM32"ӏx%t. ӎj")ӍGK ӊx3 1!ӊJX':3ӈ=4Ӈ89ӆ{VksӀ/( rdG@,$r?U=6pH!$pKmb:. lHۂ`K3+g~@2"Z}%p=4U+z RBؼ]QlQ I8 PpRX9*Ex8OCo54T;!ADk;+{2aO̓; 1P 1t2p82"/ޓG .a #,Hq&(N ,%$(f2*$2"#F=ø<> m<=<eS W@ko  \u8U! ֟[ i!3u-vv; vu^>-7Da}9* CkOk0(l {&?S`2"_&Kl=6ԭN9 3/R4,Η]#4¢,2"lgK1)Ȃ14+<>Ʊ`>>-Ķ3<*MQ-;ÿhV >-’H M ҾcAy2"ҽ"V ҷ_[ Ҵ - !+Ҵ-o҂\ ҁGN=ҁU^ p|*STB,$zʛ393ys:i3#x}>ݮk u7*MtQ0(sF²G-#r=~?,,#pE^ \43+p.r:l*#h}7uk9*c.̖2*bОB:1VA7-Uh=4T=c+'S}؁<>Q͢LwQYAb3#O3N6XF09*KΨc [$@D"?U^>H( 4<>68\*4093,N,m5)J~p|-'o}%*#ʼn*8:™   v%a>4(D;4A靗L<>9~a'=4)2~즯|#)Wh[#="x;T <)Q 2^zߤ#•$,$ױv0>-ځYfMԿq ґup&կ3+Р^$U.32"Ğ8O@#jP-'Ѹ0̝$ѱz2Ѱ09+ѮҪi93Ѯa!-Ѫp͎ ѧ@Ѧ'==<Ѥd ѣkH|ѣ<=6ѝM b, ћWv]ћ(;: њRј(.Q<>єV߼Z;<є }:%ѓHmJ=6ъnDK9*ъ}@ K3+шn|193чMei*3+фu#>-уC9z"у8*="~W  }/* rCn]&pЃR#n/ڿ&c "_Fy"uq5%P}MOP8a$U<>Mv( L'DL:3C2ozF-#16{s2*1;@ɀ (v>f& 2 ZQ$Z0:5%#EF޸ !4"Ya:%VB7@:%o q>-H]O', ; ZyD>4 b$kh)G [H  (`/=*QU=1!1ڋ$&Qq.?es6. ff=$ 8 0(gZ!灁!0(6i<>x~eǫ L= 2*=A*7/<x-#7`Q}K&I=;he&a#$Ѯ.й镸2"зɾ1{,жV.еI!;)в789Я@] Э6aP-ЧKNh4Р>cy  О?K" 0(МjxS#И7r*4,Џ%Cx ЎtЍIb̧#Ќ?^.!ЌAn2"Ћ:r=J<>Ї(2 0 ЅAZ,%ЂQ:Ёl&o zSh #yDR v;/~"u؄x mcq2"hzf8#3#cJ#9*`:b8=4Zar=X dlgR]A&"PY~ﳨ1)Nw#4=M,Ȥ?+%MAL9;2Lk3,s9*K0^ s JpNW#I| ׍b<>F t1#EAJU C5"!#0 8V)T3#4V 1)D32"0+#rN4$-kS~93,bs+K'D_4,"AB*y3#盌a 0(8C`1)hԥ<:zc 2D1 t% aE6=<""^; dp5#.} >J(=*w2"lH$īo$P -[W1i+P,#P)9|"NaNoLz?p- E;3En%:pA^tIU@] =0(?&5<R73#:Ԃ~75f{ &7T$%qUF:$R_h7'!#6nkw62*Up2dؗP  c4cW*DR;  9y>-Ew<>aqu9*TSٝ =':16>-3RP4S1U <8;_ٖ G:"+4,磃J ~Ph':3(%J,$VGFJw4$n߇ ζ:YÊ#έ" )6&Ϋс6ΥTl"_ Υ!Τki*Ο5[&Ζn1i"ΖGf#4,Ε00!Ώgg ΏYp,<>Ώ0fY!΍s Ό^  ΌX)>Ό-VsW~:Ή%Q3#·蒪_#΃wD#z_Bdr ,\9*k+@Z!gpu<>eeѢ2"dt˼Z7m#UZ2\d7/Uv:"O#:;2M#AJ ҭ9V-#HAh4{93F($5E3#Bk:V@=Z@4$? eJ<>>y<7Ѵ,#640T:%3#v:31|.*#1QGm4<>0N:\=.<Š2*'Xh'Q#6. Ս8"ir -0(ԕY vo4z+$ =,VR=4 42{# ^O1:?z&YR e\L3#XK؇t#4"9}4s>89*ܴ8} Si_*#T9*9S3+v_t0(M@ڛ}[  P_]6.єfv)f Ʃ4 34$2Pi( %k!3$͹6BD9*ʹ-3ͭgE4,ͫVV$ͧ|F|1)ͦlÓ  ͢*5-͞i"͞E=6͘G:1͗[9:%͕Q']>1!͑ȔU ͋  ͋nz1)̈́+"(͂^4<>͂C 4z-sz?_=x2"p'I- pQ%b:1lܔ3#e =6d脵p|j abeM2*^?2*[#93Ycߢ?1)V*9 Ur> M;\Mȯ.;:ILE+N74$<#9E#4N7g6e6'&82*3duK2/gp<>"!_ &2K̆F7/?r>*^ZB*/<> k `ؿ2"hs ou MhF~3+eWC3+-%`.d$ܚbШ۫NU3]&ѢX;2jo;-'@2*u=-[,#W ̿?:,̿@$#̽Bx"̵pO1D: ̵yE-̰3֪LL9*̭0-$1)̪퀒v-̦ ụ|y9*̡K7 ̠m6GF ̞I̚":%̕mġ̍:G64,̌.:,̉mVc!̈"~P:' ")~02I! }7|C i x&5xx? xcIb*w0ծT+$w 7X=-`'}Q ^G-\ap3#Y&RV3#W̧Sf QV!PZLMͰ#L2x< FTWWxES ?3%>uw<>=.1K=y:P[ j*8F`ab:6Ԫ2*5-jQ 0jHV^0] /Yc=6+ ŖL(L9$;2'm6V1!%FO2"!z?* P bZ7/%nf=J;319*6.{$S_ ; vӛj#͂"1mV-#81!U0(c"6 {*ft!3dG1)+fޮߢ#guBFzy\n#8Ҝ53#9> ˿>H[9˽۹gN;˻1_9*˸}dq ˷g3~=˶]A&˶ ~#˳,"8*˲:S"}>-ˮB2˩nyxb&˨uT0(˧"KT˧i:QJi˦Ιdˡb89*˝,z$/˜c{93˖iX ;)˕gtr~ˑmvf%ˎpJ׷#ˉY]Ĩb#ˆ ; ˅<^0(ˀj7sѢ |}Q3+u=NEu9*t\;AsC o!~ _V>-k8W-#gp < fkejR*4e2#  b,uZ{EXh9*RLCOa$OGP2"FP B敞< LYd#97>-7S ; 3$,,#3 Ml0Ia.0h*Hpr<>$N/S3##Pv- &U3& ٸO:(Ņ!N r<;/ Q1*^w=4 $[&n ܙF"-#Ve1*`:()ıN5%vu9t+/[q=6|Ka&|U.'uqOq0(q37/&'i$ZQT"ݳ<>C  U4 K9,ɭiӟ *<>Ifc0 6ȇ^ ä埳+3#ҮI1p1!ʽU3#ʼq\=2*ʻpDtʻZ2"ʹr,#ʶ tXʵ6p<3$ʴ(.ɰ+#ʰ_ʮkC;ʥ k p:1ʢ:ks-<ʢymQʛ)ʙV: ʘ.('B ʒw9*ʑ[%a!9 ʏmʋX(oOOʆ/ƈ#}*ʆ͝ʃqpc0(ʂ<%s ʁ~1# z:1nLTn iv" i}Š<>c!Az#"_e8?3+[dU,,>-ZmFYsQd6.X-C$W[w&U7*P,S2\Hc43+GN< :ɖ#-9_F1pײ<:6 cI 5L[)&4XED:%3p  3mrn-.7>K9*-*-V=66Z%DsT!2=>-bP}\9*K, -w5%'“0( v93a& 2(6 @6=""'#8dLE;^)@?)Dk S=HE 2Ry0DfJ2"cxn aT*ߍMB'ܶu:AY9*tF׀%;H$), vnFH56.G!2"\93i4$X-3kO@5p& ɻɸ^#ɸCɫg}9*ɫx| ;-ɫOO06ɨab[ɧsG%<>ɤSಬr4$ɤQ\#&ɝz43 ɚRG:1ɗ'="ɏ]3Ɏ6[PLɌEMԂ ɋa"9  ɉ!ҐihɈ9Ɉ#f6.ɈI8_ ɈZ${KG mle4,ek.3+c J<bP4>-`6d,#_GZwM>4\KǤ \3膜_1!T̲6.Q{xOzFLW:1D^@9*C:p3+=6-#8;26j+#2i 0au Θ ,OBi93(+D2*#*[;)pUy(O`'~!--o0(493 9Ahf 1ؒTz6$sp A1 i|3#s!c Y*##}493OG  ]3ulR$]=4R%Mc Vl2*4 5|2"̽m+5̧z͕<>ʺrg1>ߴC,#ÉA1!=?=6ȽzB5a*9Ȼް>](ȫJ Ȫ(D#;4ȧ/׹9*ȦnRn> ȣ6!3+Ȣx,dȟv~#Ț W,:#Ț;̓E93șꮀ|*ȗ( =ȖzPW4,ȓͿ#ȓdɕ? ȏȌ1SI:"ȉȁ1aHȀ+H9*|Qsx|SF=4w !m 2"u"2*tsxB93qVgܘ(3#przim$ɒHl6 c|\7'cO&&Y2"a*/Hz_e#*Zd1|8:XKЊi X]H* Qi> P0n9*NBIH{J,GuFJ%<,Bį+LBWT>3#A"I?9axZ3#>5> 6S~]1!.#R,t *'ϔ$=4$+y)w2#Dd#n:6 <>mf>-};4 !YS _@"+R0I3#tY"+Nm --fL!G_->Ζwf>-#55v"]<>櫯*| Y+V9;&`>@)6.|MJ߿n=4>-б{<4z2"%w:>r_!#I%ϾUݼB`2*| @>!Ǻef O ǺdEe ǹm'Ƿ:w!#6&ǭY'<>ǤPmM Ǟl<>ǖ˺ڢ93Ǖ9H:ǔAǏ=0 Nj)bv&Lj#Y2*ǀ'}2*{+)#voy1)v~~-tY5s t{GK< sTosl^c= mi"0(l;z<|dTQL$cp 6.V,eKcQ90 E<2q ? +y6&>f >16.<{7/6R9*.-{=6,d1),] :&ۘ^ "M594+$W= 4,@o""Hnc n,$!2*54&A@؃;4$ծdv Me`2",z!9* n 933K8;xj9 㖓BF<>`6;3Fpt#B#TKN;&Pm="ب=?~cRhy=4͞4wh&2"ǁAx#iXB ħՃĄ;2(DHe oƿ*[-#ƹ}`#ƹQJйƷ9c+$Ƶר3#ƳKƲƱ' W="ưiK:3ƯmƮF;)Ʈ$o( ƭq.t<>ƪTءsv9*Ƨ7K^ƥ|w1)Ƥ .®<>Ɲ j:=4ƗX(>#Ɩzg69*ƒft8CƐ(p?g0(ƌ2?1 ƋEW-$Ƅg@ƀaly4,u~,8<9*tP9*p(w!h pʯ<lݙ :1dЯh&bC ]}!(9([~zWDV6Bg S=4SFS OS+YOTҭ+2Lд f4,LP2c93Ir$,1QI 6.EDb6.DjϹ^2">ӳ-=jϟG;2:jLd83?և <;2J5_O-2/`.u`,:R#,;#O +*'/s5%)[~24,#yEt#H;3w|:1S-o)br,ûH$H4, i  ɀ }9*Tec5-uX\ X3 ,E0:,DT  N2*]:VOz>-žJ{q h^,#Hf) 翓ƙL)&!]t"BܘŌ#Bc_ :-=}ź.deH=4Ÿ~g ŷdJO<>Ŷ1Ŷ=$yŵ[n5K ŴbJ}#Ų5}J1)Ű5K]#Ű Ů=Ũ2-ŧsW ťև݇^ť+Ts_"ţ tb=+Ţ3ŢdŸ$ŝl& ŝZ)E];2ś^@ śm~2"Ř`z(=+ŗM2v6.Ő+7/ŃNh3"vZY#vźuͬ!t`A5%r2*qvɿ93lE62*h7;C1!g--d{1AA0(]n-[#f| Y Y=+X•  C @ǵ>-?Vw 2Ѡi.3;<+KFn$'+g$]KPg=6X:36[ rA o q:#)+$-364& `3hz2*i~N )GW  Z≐Q@' ڥ#hs 8&]d9j6.Л>:1r 3+4F2*@wKd)T<>RUh%tu1!-iE;#o;$-* 2*SvT&0A (xɗĽ]$Ľf1(Aļ\SD̸>-ļ6;93ļ5Y:]~:,ĨsWy <>ĤH [tĤ$ܸ ģZ>9;2Ģt,4,Ě]܈mqĖpdz:ĕ_a@f:,ĔbMI93Ĕ1H ēr1DĒgrѓĐS^>-ĆKX02"ăOHăG0D^JĂ@Ăl~G_:,zlcA$xp2?r9(xBҧ 1!xe]!39*2j2`Tӓ/*(o'-&o+o(j_+0(bO |q]>-`43  T2tW4,YȦx3#j _]3+τȬmd3+`|~I NsE'Z :Wd6. <2"dtH qP42*0R00 L;v:ɯ>^0(ܕ4݀0 NE$-Æa 7/Ã]@ ÃZb >-uJd9*qЏ q͟q/2&n.j)K]hRWRe= dי>-bq^ ^'><߳{'.Tx wH9(=°93;TX&80R9*5E2%x 3*00()u,9*'"_X[*$$84"#.0oo3+"G86y93"/$x)g "Gf| _K# !eu  z\#$#DK]t*#Eۨ<:HŢr0(,E4,>0(7HHΧjfULv93=do ůg 5bDPM @¾[zU ·9|I&²,U3#°r=!1)®q ®)K=-#­y׿ «F#©tc  ¢6 HS b<;œ)!$!œAl-&›W>61)šؑE_7/šN ”X%qpŠ0:U=6‡x<>…B7"$xǛ%jJ7/w>3#r(%; 9(qJC2"q EW)=6pZ o.eoLp;2o n j"J/5-ed((:3b3TQ9(\\aV5{Q1ti>-IPy- EY%D}; <`!R7L6O3#4 t7>-1L|2*0Ƿ /{1Ss+k(-3)>)Ϗd:1"93]URS g>v>'a',7/ KF+  C^}1)m':%+\nT93ΦZ$+z4/ pD|-'^*$keT=+15P$MU1#8 fB;47bm-#͹o ̷s  HEz33#ö>:1¿Q,mץ0(`B>-aql99*C֏ 6~ oO4$* lw~'2O-q u*$J ?;)|,$:B$\ |SnUO0(QI9aztu .NXa4, J9*dA ||PT80{}M:%sKh$mfXL4$j8bz=4j?e v0(cXध  ]Fv\ [0=WKFSpP*[&>-N3!L2+M^\}2"ERER:,DvTY>>-DC<$3+?o| 0(>޼ޠs<>3k 2wwr(20sY319*)@y %1/N Xk:%>7>-h1TZ:3b3'= 圷u5% DOr=4L6.u2" DsY"FL9**N{[H G&&7uBx 0ʏP5D4 Q Vy3#.ޠB$*>-{KS ⍊+n%D9*^f1)ݲs!U"{O~ ډ _θs(Kd0(=<ʤ]X"F   :&Aj1!Q@qk 2+$åi=4Nx;1! Đ:3US3&6*J0ga +6 Ì" b_  ˷EG0}V]* Y%JNYzfoZ t"e#t _3sUx< rGi6;n eSVq9>-cX "9*bmy`eв%_r5493^ na=<\y [<;]7!3+TS8A]yRgVl9*O65LT"M`0 I0C$8[f3+8w+6y/^0(3Qˊ .+c:%(TS{ 'b=(71)#:j;@ x +J"E# $ ѵ3# Wok  UP3+ `<&&5 ^+#-sV>ɇ#9B8W@*=4 *Ï&Ll WAF:G5w-GT:1ߵK TWRY6.a2uu_ީ U0>-Տo`3*Ս)9mW,- 6 ] };)fxWd מJO=6zw\6.íв6/ìN]]3+B C2"$;E4Wz9(9>4 ={*"+uPׯ_@W Bs"5?P g;2d_})<2*'Y#Liƍ;4,}`;2io{6H4,x?S w8j/=KtٌׄA%qnT@D&g~3#eƥH*)2"c9\U:%E/-#[Я*1*UqdG; T/d: ShڿBO>J=+NbUNly M۞: MWr-M,ha Jm# ğ>4FN C5 N]#@̴W&$7:  5*:ɟ?%=i-#Cw%$ GS ,W60(#3+4p`(4%N(3+ވ2n߲2* zZ 7t,t@  qs^ .ۄ 4o&'D !=6idYi93 THmW* c*U 0 U9*/3#h`&1)Ԡ5y*&= B}Ӝ d#?.#㖁[ Zua X )+A_cʈð 㴛8IGBcc<>!=~mMbzW0(7kW Ѵ_Kw NsL<!KcN c5 I> tp#,ulwb?41)Ί:3~m&}#]~&{ F;2y#ά#v) t# b r5L8pHv2*hf?_fjT_M܆W xiS/%P &:Ma É"HhH >Au>-=w1lr6.= Q#Y ; kT: KAi9(6ᩉ+0(6"-;x>-66I)-#4rxis"2H2"20`1~KXx/.w= O'':<>e8er:3m٧I4| 2 C vp,$ i- Uh#1)aIX޵qR-@f899"! 2"C:1F*#D -Z<2" ܟ<>y4Q,څWql0<>J'2"րl1)!(؇9384$g>w=6ǠՇ(1 :¾5,##\l#O0(X5ώ;:O(G4,v c-; yY@(:,M'&:4"Q&΢37"Ji6.h om hlp<>d@;4/nE.2"%γ32"2HyZ>-=+wzA>;3=43Um]jaH~3#<2>-fJ$HO<6. 93 6.~'Ix'Z;:3v>sY-* t(n r_V<>kd1(i ^= hRB & dOdc7"\lnf93Z5쎊U6/P7" H1 Du;2D_N-pGV 0( Ƣ=:Ҧx= Iݎ7~p(sBy 4$4V>-?L=B;'A{|åKX ȽRuUN2*=ɗJ 3$:d 8-'ݴ;A93.SFN2j1)pR-g#`:(x33+]Lp 2"\ߎ9*;zC=4<:Y2w0(QZ".S=6~+jApj  }g=93{o3#xXw;=4sG,&pϴe&oL&$nv&mf#3"m6mS'h4{H҉ e`4]Oa((Iu7U: %:3N2fM;Mkn#)K_? 93Ke J"`ybd#DCT?XF=4;+{0 ;Lˆ 5 9*5Dof3yA<:1O܎7//h /pe&* ՛4,*:3*_i&*oHȃ '~ <>'@?#$֋xP9*4'>!ב`<>< 6.w,#6.ڞp#VMm:1iY93%u-3=6v+k>-e:ܩxx0(֥HiF#6,1!£F="x0(n%t 4$v9*sA9*,A63$*g<'y9usf-ã#?93Yեb#qrSU=<̟#; |ƵmFX6.aI4,}u,h{F#zbbTsnU5xfi E,bi03+bL`75%_~4$]õ![g#Z3,!%R闉-RhQL!w Kڱ Qo<>CWdM0A-rN ?P:} 5%=O=6=\$9HMݭ4,9(3Y%-7 l@9*7"7<`Ey*#4T!%U>-%',:t "ma>.6._i~g}6.3%O&k>Ήc;2 XK}w4,* &4$ސ٥0(Zzo>=+٤ mUw _*`/{:%f*$Q>=(I% iO:zH߹o,$n;7u5#,c d]`W3&*9WЕc9U93T%rqf@$[ٵ81)rE0 g&&~#$-;pz#y݊=6}~e % E2*\-3[* Zx]4$ #|K' 5@,%]2=4"-u ($̀Jr;!ˡ1);ri&#K7,$hQ]jҏ&BC?3#C&Pz *}HK |1  wV7/u㊢`t\T6=t-:7/hF3<3#g֡JL1!gT%z&bǺ{qS `7W /_W X0 T2`C4,T~$j=QWOt7 $LdC Kc !*AJ4,@Om^+2"<\pðy6.;*ZT'M<>pL:1Ԅn=4= #=lD  W3<> M5l9*ogT1!21wPۋv)ۋ`@!ѥ|ln+#V_9t0(C'KCn6-nbW<>쀻ya)24,s81rnvE JHJ.v$BPS0^O";-#hľo; .Ճq;2,v* !OO9*]rU2"2|88X1"5-1Ɵ綁<>ոǍ4-7`B !}6.-q 2L(0 q 70(gr7!lX#2*a|wo `&g<>`#:Q.c ^ɕh#Z =OA R;F*4)Q\Yd,N*䉻 20 MB<56 !IFZ Er !%.?OA #>gZ;d(7,h2"6W5_7} .Kɗ)%nK (W939@m0?Ox:>-R>-zcEyq$bF.a 7/ׯ޹q_ V| :.JV;2$,Q"+' Rak*! f,F0(^'s(=bcmT3+5@ ֣e2"U<ё0\ ޴qb4,x,8:O&WS ÊLyh#r4 XM5%ht!/u} GH9*aq;)ά=6Op.!I84m7ʉ9(.!`s] P=4/<cjh&{c=+@坛;)v~G*N$-s@=+mcm;2m *l [z<>^ WS<2*R ; )MZ~QL^i4B#J eUD,:%B=Ed ='g-L;<5q  3 *] 2i}*4,⯠21)+" wP*(TY%3+'FI2*:c3+я5{^Ǣ83+5B~ Y,#}3! 9* ,К" >%VULvٻ+0(̀ ]SD0 W3+w܎5,w}GĚi,$|`cJ&C%,+$'4`" &xW3#ct4,ѓw1!㕕쒺DᏃߍ;#dkE0(߹<;֕o>-Iū:?j|6.Ҋ}O#< 2"˒+|Ќ_ %<;4Th  'l; 敹; e L{Eo;;-YsBl7/F~m$ 9`];2 ).9*ժ g> x WJ |;u 9(aɺA<;؋+Pi @ zK7 >9*T>6.w>-:pl- zdi1!umk mYagQ7Q `0_|-3_.Qo> ̬3+O~N&=6H% \CT#F1!A v<y0 7dB0(6?-:|2"2}V 8:12%N:1!1 1i׽.|93, '(k>-$ۜ59*"A|O>F<>! <}"6. O>a#Z  Ȗ?1!݊ZABne$Wkv d-&4,=+V9*t-3*6  chR:ɗňR,> \0g;& *5Ww<>{2*sBYNs݁3 Z^$`:tj0(͘n6*ψ&c擨ƐB1.-#QwC 4,=+k"Ԕ>-l"|¬3#Դ+#'%l Ov$c-ݰ~)3+F=T>-"=3#1)쁭p :x*"K^,0(  }O|ur0T3-yi+x*/hf4$x:wxZ$twt;> n#tG>Fs+G% o׏ud?;2nUW bYh;2]y=6\烣4,\ q86Eb\2*DCԟ/ A]`@<1n Uy93(;Tiw9*' c-1W"XvB,$! WAđ;)G; X:lB+9*kgBe86.1*h-<:g  u5?,$ o"=uw̒@$c*u֗93B؈g 9[b4,ώS=5%NTT4,)fi G⊊=6.(B!2"b Hz1) uY89B H%P!Ҕn4=6 g6;+Ŋ5r>-b;;ylv ?,srσ~r%! ě4,}kq@=4]- x:s2*=$t-# uWхp; 4}=<% 3# ,$k &;)6ʗ:,,*4~y-x^N ~a,[!/7/j%'<>hF҉4,_ٝ_ ]rKD$ZNm;#YhW Ydq!#Y7j2"Vx:1K\E`mP>-DbW;)Aar93?~oz=>D2 < 1Z <(fGh< <#;(' &:Е\::4̀%9*:f =47תPB&-2#T=:-KK7:( 9-&o t Dӈ-sdG0h##iJ1J)ry <>ƓG4$Q1 3=Z(1;I+;{ s>-^Ǡ:1PUv{>-#_Z T5>4 h4,X!,w֛qC'E=,O#L- 0vi:\Ys ̃#5tMYc2*T?QJ5,ju9(B #0xnJ$#u`RGī5|of3+WO] ~1)|3JkC%xؒs {#)sӱRq:1o*t*j"H3#hGZ gre=6c1)a9B? `SX^jis=<]-YYV,#\20(YG%./'U2oZ:S׷0~;2QY@H824$Gp;)-"E :?%I3+IiEo ez7ת="2"Up>-ߴi^#ܞՖ-# B>-ֹn 7>4i05OΠ 7RX&A[_XL=4NZ3+P=` lT; :0("ú: ei5%h8=+=𵗫4[ n6.'g 393^81?9*mܡֺ2X93Sw7zR ؜u3#yEIq7/3+}SYE _*$huF ܨy=za Pc;2F3#}B榉<>{8 { {BR$x9(3+xZyt1=+uA S92*s(P9-q75e9*lSe63=ji%1gJ11*dst{#_s*^I^f{[:a S=Xa6.O^g>N Nzym4$N$*NNjR<>MUt" IS F"I=`;3G}sC4$B܇}N$AZ[ g93>8'sn';ץq=7ܤI1!6 3H2".հxh ->ǟ 'tS&%%-#.VR=6!I A펤֛6&3Lyd9*?`0(Fi2"pe ,=4IZam9*@N;)6 d:1Gz t;2~ k-&oHR}; 1c^NmGY#s|>Un4*1!bT0@M։2*" 3+#Fcӭ0(0E6^9*X"YswG:oy3(*=<&e}N)n vN#gRS1:,|Ί 4,m!  \i  OZl&:wu 5f'`/^EC0(ؗ<! f~;X !n%-w #w=u/H,$s,V!p( hO“D g ʑ_4,gi{.7/`q!)`lB_[ ^D@߈3#XkI}}L O -#NC<%4,MCLE=Ks:å}@#_Q=4@oa^3}>/?yVat]>-<,vd ;؂,6-:6&3Ђ?8<-I;!+HU6.'!qd*# [3# A;m<>2"q2*5=ZX)~7/yɭ=6ss#{CW!1` lEHeJ zS_?! )=23+ؔr3q,Soy#B:,ۘMuh<3#3n>- ZGwQ$jna_*C̀&ɰ-Q_mI3*:IM p[G&mȸG4,h7 c /Xi3#lc+}1e :1aY)vR)=7'[>93 bָE .n3+N< C ~h3+^l0(w2  QǨȿ3#t:3'r81![m!!ep K ѳ&2*~$:N+5-{<>z+xrސ#w>5h3+no ,x;3j=i£M>-c7131)b[ u-#bg-dZ2"_3J _ ^SR^[%Lz<>\W:w=UTwFR+;) JAN{:GÉg0(F89\3EP (?r7EI6.;T932Y,R5/A4}+%HL:('ik=6%Z2E&#"#" dS4$cka4$ N 2K %.KpLxKX$פ5L5%DX\ppW5%{nW:%93+ "=`2*Eɷ@4,h0^6.K*#ުPX{q j/  wOܰ˭93ؾӑ l\Ia3+S7 :,XqWPzH>6.^cpJ=&"y& 2%7=J/ ; G4-,\>-qaKq8.d" ܑ6A<>cQ =>u1> :1R"XyI ="")xk8>* |γ y>wG<>n6g1, b5#C$a-24,_HRvd0\2+rhJ3#Y ®MX "ځS}q Q;4,P꯳ M5.ʏ LB~RK0_L\2*J GƯa9*Ab0 **a#*# E'j;%6P'#!H>9*.YJ ^Op`j o 9(TU#) Ҋi=ǃv| ! \I[x0|E2# 8*40<=G 0 "85&3+w4,MOt=|+ y;$vX* <>qXhK"d-k c'mO•F!\l`Ug]L7/V3$Sc&U?JS-1>:Rv`Q !nr P=WGwC`J2"Dh_<(#Tz/';Ȏ/4$9S(u6.7<7c* 4 -7v&+. Gg19**WG&3P0(é[[iEƌ<> b- 3( -F!qO<> v# ldj3 Rfg#ڴ;3# ;2*ۢ }a>-ڜh-ʤ^1)_Wk:1V? D#,4,  a:%qs*&q1!B.6U#]5}!*ܥU-#=ȐASAwr Ĉ?  CLo g H#Kun6.+/=~!JZ_qn =6T?L47/Hg!>-fݡ3#`{2*N'*1< `{v168 Ol6.3O6.<; ~ 2)(1~G,ٞ:1g-'>/\tL V)3qJ:=-IvO*_ I*d$F`11>-Dћ4%bCst*?Mcx%4GV*3LL-H:3/&& ~q9WImt*$h3}#sf  L~)ey0ڡ+t_ns u>-^$ A4,#_Vb9* ﴴ="xjK+W'>ۉ0<e~>-ٝz#r!^Uѷ[9*uO4-·_ُ5%Z{v{pE5&`ONW/ E 9*[o13#ţ=4B)*&-KRE<> 9*2*N ;2PP?&(k*K,#!f.-N Ĝ9*=4<#f/#eKI4$݉'$yf Ǧ>-{vfF gH="Jɷ$}\%f{KԐ vm!4r*s3Kg$nv Ӂ:4kҟ#j+N!j;3+j;Y1!i ':,`f]oxĖ(#)[I \$,ZUX&c3+X~YJ}UR|& T$`1!SJE St Jˌ]G93Ju<4,J@W#Y DN<4B8xaA%9vI1);#Qs )S )"Aa Svf׏ #5)eK $ʼnd @W:,h(# c9*LqDw.^ *d!  B.0 akP5%?B6.>89A6.٪9*0&aq;)'S<"H2"mPM22"'4K nW ^P<> "@ـvp0(~#=49z[!hIB=4;0=Z!%W=6 ^3{]:3ƹ 5  n4oATt|0(ډ@A13& 6&p)) Ɗ_6.ˠ}%<>~Z:jxIR0rl]9*u?\— uwMGsFK  rejRSrmHG qnl:3l܋hU*"i2]sb=b.Krx3+`EM=:Te~-;4M«Fu2<>Ed،=\\7/=k *;-9e95*77\;7|F<2*0ψ[7/0)xJL/C+&옴z)6.% /c2*#G -!Lg؎z6.7)  K2*9ndVwK=6'aO2*11X>- n[W") 3{ g/VX# WKp]2"js-@a ـL;44c^Z RAx0(0(ǏS`>-NjZqc4$f6ދd[-ʹ߲3 z4,Ȭ2"+%<>3u%ŧiL! f0(% <'dJ0)#{nߎz 4,܅#SP4,Xdx935 Ҡ* \#:%vy poV}2 2~oÈ=ѹ ~7g`4,zߨzm2vƱd#sYͨ(2*sPul->p2"g*0d$*'d-8 UO"bF*4_$~:,Yw1!X[(Jd*1)UTh4&U;R(=6O2<>$:3:J, 8pL~6.8Զ2"4ҟT($b5Mhu"G8o2*8*\d/*mF8 ꧘`<> ;4$:1 s*l o"کp3P7>9*{*9ŚZ9(~h_a{#Xxu:1;So0(Vx6 ~)i %=/.'4$n[3+d~ >-k 0y^=6~4"l |?6( |n2QXv(Wt#qnE=$-nGÆ =k>)"#*0  .ۙY%.(xS[c&_?H&$E` [j%5%I'.37M?0 !@2":mnʢ BY/,(> [X D29*ajV9*;:p;2"o-v$3=ur}#lj93hMz1 epB=73!=44y9*33R<>2##&0(0Lq1!$PI5|0(!Ekr="Z:@T!*8VЕ2" xz';-^R;Иﮜ ~9{l:18rr+ [hбlNj&N58Ư{~1!cG"@ K W[lJ=(7 Uq22-~*DYCl һ?U{6.G'M>ΈcjFoW%:5,$g%So'mc>°j (>-bsҳ0(g۶V\ ;D=&z['&7u(<>|P-N #Kp%>J)3+dq*,$O#)/B6!jUoz:1z1)G︧z6.g\d A9*EIP -~4,}$@=6xpMS< we;)q5[m|b;3j25="i I55%c-_f!bp]&Qk#Inc+#H`fx0(E$p9*Cٷ-%Euo-(;)Afu `->4?%Vb=R3Ax :, T2"(o\gyj#(J:1nx*!$-#됐>b 2A  SG +1)x-n8;™y%i3+‚#A4j miX@<>VACx1!X=6{3$pY` 9ypP9(Mxw2"{c $c |2*eXY26>ڟ=4}V]Ҽ4,u;Q?;93b5i{*"ajV'ë]Zf>Y ]jA4,Z&;S9*YvBW93PBF5((1O/n^4,Lc*н4,G #R2"C3%A}מ@;9;de3+:"H :}ٙ>-8,Ϸ1;#2⋩-r,#.&D2*-s% *JKgH3+"R"Mvl3+ʮ5$2O[-q3#Y* e7/ ?c Y|'&-~ޑk!1ǎIG@HbN=#E  >-|>lx<>zm :Uܨ q!<>^:v= Ss2"X}&-G?s3#IR=6%+R+-3^ =+x*+$5u7'9*Iٸ~1/ u$ vB.#)̗?="yv 3#uf0w}=4tK1H`27*G_N!C̲ ?jN; =Ɂ:=<4j QG 2 G+-0Zsn+.5*jbT! )('ʔ#*@ŭ$hiQ93g}?6.L+4,B%;)  - ;Y43# zt=,# ?ef%m8t!z&Å N%F` tVjs=6ב. mUA.7QpA: :6.=¨44, hx2"؋5 ؀rn}#JR+[^#Ψ s:+#Q ~E3J ÍCJ$]7+$N5}$CfV4,:"X6E<:߲jAu $ N! BׅH?.8#2" 'iNY1!̐0 z%Vc"$(Y'2" CS$r ck1W5X#xӳ=+|o8Z4<yzY$y$' qq07qja`E=g.L0(W{v)TZCJ.Pv=6K8\U4,I* HB FXZ}9*D1b4$@c@ .d?޺-hac1)*^Ɣ[()*' y!&x4$$bfK;)#@=ր K  %:1P=g_ y M5# S  rL>1)UM[3+ Ny"+~,ß$} \#F Ro~: Huy>/v+eqEj:v$Q)k  ڠ@F ǡ@ -&εď0?%WphgzU6~}ܵ(w#$|1O Ҧar#^Oԩ*"_% 9 ? MBN\n~ 3+$1#DfKS"άFVE5S-35؀ 4$@{;3[{:V dm\ >Q z# T.m6je:,vA]RY]\2*l[<>}@$zh#J;ydxm$uVm u kok{1!hVC=`:1hS -3eE-m7c"j(1baea֚5(!0(X:  SXz\A2*M+q=L68z0(E+DXN#>lM~[>O|O93;.86.2l 7/- sD&-(+̼4$&h0d6.&*NfuM3#&a="%}t^"M2G2*_W#bk c XP#`}*"93o )4,$\-t4 t?`#noqG,W0(h93/&SE}zVL-6@7'jv HT~2*YH !1)%rti0DI&@9:r 4+G鰆(*{`y^dz^6;4d% ַ6/s  k "չ&934 [/q3#uwhV'-vEۀz-b3#Uڛi93nD +[3*6.j!>- 1|S "If!Dv(,d~u<> p4,V] , ?S>- !8}{U"Z{%kn_3!Ӿu/hqnV=6oG &mi§#aשFT-3_9w#Z5>E WX^6.S(3tLRAOm3 <;O.:w#Iԙ B0?t!5 Y/#.ᦱP"->g *u^:3)ܪ9 $-&"=4"8'ۑ "X~o04,=]3#wy>-zX2*DZ y͊l[ek);2 Km"iH X .Nj=4:#`%#)-4pX3+'3#R-PO(!O~R\_l5%֛in;ϐ $u/m$t{.@-3]m23"ȥŨ2"3S<>E:%tnй1!%\h"M-6 2"?#*#Hm v ><>/, 13+RZ M&*z&5-%U0(Ө43+8x"Ly:3G&[)>-46_G#q{֮Z2*z/ k#sG[!U &-z4]~6.wB`н !poXc#h iV0([ 04,Wv<3V9դ$TC\]P\. J~#cj="H[18MPi2"3Sq{/ɐx6./$AX3.Be,~)e̫ͫ (f{('OLcSc,$!i=" ΄>--.:+~-#  ֲ3-/+=<0=4x+M8Z' !*Di]Z4$ѕ-:3S4qvd c[6.cb* (–&1!k)B`K |7D1yctH&r(i:q]*e3 =e#R=4a2̅ __3)_3j?>-_!> ]e-F \ Ҡ:1ZĨW9*ZL+gVaNH7/U[R7/R"N LeaDuLp*D &C_:2"A=C -]-{ nx\P=4e|93!>-+K66<>'Ii 䛉{ H%k{,#Ȝ^{|,#ǤߦrL>4[5\N0 |939*xkOD[&-ԜjRѤE">V ̏wXrzm Wzp : P`$Ą]DnmsMà}6 vF3+T9l tCF!@-.N U%`r4ܗ!Fؚ  $H93 A8)3+qutlR$ڲ`DY$,(+# ik +$E&j<>{ƺj ,#z;Af:,sTh؋{=6q0 pF͢71!fq<3+e :<>dVfba==R5%]:>[wƔZ?aeV?24QLJMg_s!*JeSz] 6.D:ж =A٧ >N+":1Y21*8"6o0!6 13珗=4/Rï:%':v<>T܊6.B˷ $Lg>/s!?7/ i*#R7\3#n\ )a  plS^t+*$Z3+tf gV`{<>$"$h/  /;9*Ύ4$*g1렶%Z.4, =6laN ^A~X.-#̹:3 #ˍ Mz3#ų/ԚHi4*Dni{1!wa Ӎz xt<>R,3+ ORq7>-I0b&_e=W 9*zYlƚ:zO y;z; vk{rs q9ȍk- q$o1~ jF8Zhdf?7Vefĵ'-3dFwϻ E8<>BR2"B :p<>Bo =c3#-4Ḙ-qUm ,+>. =2*hK-Д?.#$yÆ Q4$[ %Y:TI$彜r8T+S 9*מvy`t2"A/ 82Ge/KL=4O(>  Odm*TZ ;ʳAt+*4EmF~k2*FEeb # |Z;#8B<>Vr8v9*`[r uǟ&Xd=4{ק>-Zދ2*oR;6.C<>3S+< 0(iGG_Pqo$,:Z?{J<hC!q|ڧ1!qE̱Hp}F`&o#[ ; k[s7/hsB7/[2bKZ$5T'vQϮVi P.4"E&_;&@JgE:"@$$mR$>PR[ ;?.w1)7CY4$/Q.>c{3++q[+-o&)Gn+#'#k4׺$jd ÿ ^V<> KHTr$ȨA#B*p<&O_kqX'2*U\yLI6.VN UoE#w;Zn0(L*~ 3+s`HH6t2B=-PH Rݣ=":j+!d8@$ ?j |QB {$ }#*{KLWj2"{b0 v<.q2"thqUk*#s>ˤ*n\fR؞n;=#l&q%iXBhV2"fYCmy>4`O"=n4$L LArlTbL> F0(KS$3O"IS%  A*QC :Z._,8DE 3,\s=61.X1)-ݸ#(sP$' :J"$JB k1)m<'Lhq g3+/: h8}>- 9* +"M# rɨ(>4=Vژ4+7 T>bdC'g_1U<>[V&[B eӮv#&V:3w="ᷗԹM*ثLj&-eY{| s ėkz6@|7BtbV\˜o5%}s&T ,(} qm? 芶#)k,86.I-q.4u7/ 2"K3+%29>-mЧ]DnJ:3.fq93;`F[,1Ug=&mI1=)T= K(8#h =4=U@@ 5? H; >-8ϭ0>-%޳}R6&ݮOu/b }%d#D32"ю ?nh"ϫE2"[5& Fy}r 3<1;a :&?] }:A_=+: ;sS17/  :xW S;`/Ό0S+,#ڳ>/Fݔ<2~=6OC<>Xi&n$ AIS/jZP yw552*uwE ȑuc1)tcё^>-pª0>2*ls:'f.@4fN-c94$bq<aꡨ+<'aAZXF&KYcz =6YBXM3+Q N L26.E `D 2"D-3!;|0(7p/`9*6۱W3+4|ZT 3Zd4,1`wI4$. mJ`$,,ju>Km ,˟tr=<&Dg XR$a3/4dx#"w$jd: Y1 [7/rgeq , Pk;3 } ; `K0(fi $:u h 9hvKw+1aPP9= Ѡ,LG0(v>e .$7[=4粻*"-~Vg4$ڽ,R-0(`)%3#x=6܄"%3"u%LbR1!DY*pm׳j:3_EK@o :&=-lU6.6+|.$|5GX $-zr| m:2;MkqKjPJ<>bwb_59*b.IxAaŠe>3+^7=6\(5t X+T:џs3$T:Ou5%T\9%:$R·>-Q*VE>-Oi s|m KE'糡*"Igf&4,@aM%X,#5bg08p:3/RK-TF~3")&fsw>-'@ a:&$є1 $ӟ~ǯ;) iLը W%wFr CX+$"f xN;+ VI(2" `Jh2"C9"_fl9*֡3$2Wr2A Q!T,#z~!3Pil$m D )̉@^%O6.5-'O#äpt 3#KjW12*/#$3"obk* A,.n ۙj_$ݔA#̔Ǵ=.DБ )6 f-(GX} #-'Q?i &jd=6$"9="S[.1p$} VDrw<2*z_8& m Îqh3+u>` p93%$ ͝T.644Kv ! gg` Q~_C S.&r #v]72*ۛz[ ID6ؾ;4K驆az:=66.ƾrhg đ';4wkgn r^Z#\3Y93_I |CWV3`*$<Z j/g8(q{d *#Q_-!o($ }{_ ENJ”,3#8YH;3#z;2/ wJA"q4\(=4V&P!}N©4$Kh#52*I, sl+9*HyiQ!ED1ג(!Cu }2*Bf 3#7#}TVl:35P5 "3_1)*>9_#4$%Fih !t_q  `! t^f&H#&:٧ _\s3+,# t_<>&GYF2*F%@ϋ3+(ygv"ާcr9**]'0<>S9*5ȭPn/q ;C4$; hTԪ0(tnK1)ީŋ4$ݓk[!y;9*Н.g"*, 5֒0(!Z3 b$ Brec9(>p&L<3=!;4$>2*4ԛ6.K4$pv11)?o>-A.?&^CU6.bE{=6,.3P3+&ځ JX(;)@ #I'3#ٶ nY1!$ + + }5N6&wH3+G;W0(~ד}|{ ǟ[1!yҳT_>-oܧYp3m|n<>cx >?`c>4_ޭO \ 3=6X|=Wx7T0\7/UPUoCT֙> ;4Lcڢū!*G~觳CMU0V$;bO(:u* :3d߅>47l?:,2xظ7=40-A4$/ḣ .q .Y-:J0(+V7I#+@ 0((gT;0 ',G%>-%ff70M9r!Cemx9**:1uy6.! 4MG9*I|ѣepz_5,#϶ڙ#)Ȏz :%I%{68 e/Yw)2",+6!s*=6rX N/cl-˩˙q<> f0:w|&U!a-2*w+#|/mѝ 6_K +)5ӯ GK&~@9_.=6y[StK!sND 49*qIw=+U&hU3+e-Z>-c2HK ` C2>-`Dհ^b=4\`w;_\̮:?>-X%P T(h!R?Xs<>MpY6.K< L#K- RE4$Jbu3+Jw ( ?q3v#>Kw~2":N.<>8,Q+/U2*6ػ2Nv:1m=.klz .6yI"!*-W )51v$(D $30c4,$zTz#9c%m"N\z<>-P#ܥz-#ZK3+7 :1%NT꫻n1!Y3x ޾Q:,|[&:<>}4}_D}7/D=Ru߯;2`&3#(v=2"{'"l2"P۠%:1! c!6.8;2"uR;2ܜ`Q Xnq怾l7/г 7X (U=#r&8; pO km=6G:m"؊)=me#t`o"ƻVԭ14, o)) Dy|#?{0w*Fx*dz6.v ;;#pOIp)7?pJ/+&4p%M n/D  mKH2 ;4h$[K01!c7}{:1`:zOt:1V侗2SH-MyCII9+5%CoT 0=4?:K;#9N b>43.N_v3#1*j9*.gEVS93$ά1)#;~s\2*!$!% >۬V] v^,`9*gc;)>Բ,P$&#Wh4,M&_6.2r1T:X=>- ^ˬG#= /2*R70(IB:H+$_^PDYB u؁9* .Ҩ eZ>~R#ތ0(8;1M6.G( q-MTm!L7ȏ| @NM ?2t/2*>37#6gR4$0Q;+.;Y 7/."r_3+)gYs)1_KQ9*( (:'e{pT &#Q|1)"E>!G_=4 r]s4,Nm_cd6+R7/y&$# :-# ?1) ڍV28: 7dUX2*\e=6E-N7h""Ȓj D 7/#c03+I8C$%*_*"}F= ΍T6.˃z13 J;v#| fv řɋu݌93Rʎ$E2"kRIy E"<!Jc C}v =;JkM *$3+`gϔf +JBh'1!Ls &-NI4p KS ` W- H=8:r Q(9*Ub$(=+)>"NH1!|ѧE wd*z0(v2Rz"j! <>gN [7/frے$5bC_&aX3_ 1)^Y t QK4,I2jE˩ Fw"i@ۣ| ? 4$-9d 8ez 0(Tzy0%ZsE93-f3,a ,u2(|j-#ȿGTp7<>՝'I$>S/<>\dM3+ >-u=+z3٦# ǰi1!1 K7/a;%,q?4,-Mc2")\ a O3#VIG1!vC$ 4:u6.dp%ڭN4ؚ& #aN6=6↙ 7tP<>#'  2Ԟ1)[tU:%U=e9* ȹ3#" /;-B J \ .:3+>-N &XGWY2"pS%\pCQ3#vQE=40xf9*85>-T&:0(wIC9 aq[ Z\?Y,$Vc2B&6-VGzV#3U% Q93S)9*#R#iH JZ7I@1)FKgk=4Bn>R M 3#;  8F6-4._K<>&U^‡ %#ᐑ=6݀6 [9MpN VuB4, T' 鈦 0Yo9(^.m9#z@72"=F4&5QU#CZKҫZ#̢ٜ6.ܦ䊲\ t+2"G\!gK ށUlã5%.\nK4$GkD(2&^ xunM6.rEoeY`1=Dh0=6b=#t]m<>`=<&#$ 8pRx2I u  tM\ qH)2"gb-a#`@T#:%`)np4-]>B Z9_OJ!Pq~2u K(G!Klmp*$IrdH;O H(GH: A)݊P!@h3*=YKPÑ6.:ȃ:#.( =9=zӖ9&v*;)1Ǡv>-/w /)TzsK=(Ms 'q >-%Q,]*4"Ճᬿ,$o?")X  I*9* 4 iN vxJ3#"Хf;Ԭb& 9*(M3g=4l* FP/5.e Z(_P $qȒvX=<&1!郼PO9*'>1!sި(=4ͅ K*$Yc*ډY݃*Okt:%Ч`|Z BQ1)F~%u^3#;#üD2>+#_BЉ2*v dAf|`#%Q8t >-wA93Qr(ϕ=6Y␩<>;21^q;%/"2"%2"R_] nɑ2+6,9*r,aX5`/b}{NK؋93 !>}7g,F-|t"x)¿wׅ2/ ojlma* gdjcix&Ԩ5%b9:;_F+҅#^l "F93] >FZ<ɖ&VtX=4NSE?H6.Gk2*@R5.1)@i`\2*?WJR;)?;<4w%z#*19*!Dq!:;I=6/'VZC'9*!|ɐ$Ն6._{c0=40eWph 83#"h*ZmlC*4 Xl  $B ?ЭY^Oc_-Pgns#omV6& IT3qG=;Rǒl1!o;:37/X,_v Y*ϒ 28:] >-<ص1Q47/v:wܹ:/ ʆՑS P9s.}j,#9*3>-LV]=.82?R3#2"4XM@.&3+|̻;I4,tiI }uɑE2"`O?m=6^zўjj 32"ώw-1yͦHy RAr;D]f 6ﳀy;Rm\:r2iT o[i2*l骇\jՁzK g9E)2"e_+q c@ݺ1!bאl0$ao.(~%;2a#*x\`VyZY-.)=6X64:=m4,J4~#JZ P;G'] F7e4,FpC Cwj@yL4,:Ŝ^0(5fg`5$3)%9*2(1393.$p;-|@{0(&dU  %l<2"")-!*@T#,GAA#!ێ"Z0(i&|l=9(W΢֏ Bʯ ȣ  |C<> 25% qw/1! t.>ih1)Ӗ}K2"_1u3+wiB:tYoHG>-^'2"$2@<ca&G2UD=9*n9vܨ[=6/ S:%WSPHu; υ4^?IY7]rbv"â5A1*V>1-Sb«V5u="卦"93a 2#V .}?$Ls  [SkXJ0(Z^T-] :3>9^b* J="%Ǹ9*/s$Ey-`PS5%63|ׇ % [b R6.&U935bD Rl1!tx3,*fQӱJBw4$9=qYR>--ĺu2"4N?Ok"|C|EI{essD qt͠Xp`Anz7P}*e@4 e'Jrbݹ9*\@y \744*SOѢDM&i#H[KD)F=l0 Dn%=-vz<>Mָ 3OmȅES:3L# %-Y[ɧ0(¨H`L`T:,34M }E10 -_E*_Ο,P?b[0(W$9k>-K9>/CQ"&Sv KҢktw ~1)|S 8=x*}3=4uu{ZVB7/swaTr-A kߕ2%!j=,=4d~`c_ d5#qbHF5=6[adr*4Ud"RxxB"4$QxMuY=4E#A8p3+@j[:,<~-::wZ)":+g,9kغy!8/Ocq7q&2*6`J2*/ + 3#.2"-Eq $'U)D $€BA"_HS7/"\3"<;!nR$jN65%8"%*$1F>- RJ4, uxO~ 1F:3g=!snr5%%0&^]-# OHL"!u=-ʡA;[fP;C Ǚm{w&{2"(RW0 k6io 豏+2*h7V:h?6.D?c3&7  E"6d#:ك&2"c/. UU9(y}iEB} k4 |CÁM :"z cod0x0@,#v./6&v<>sex#oK:a6.n7m օ#)l -1=6f?da㪝6<>bx> bnT~ az@>-W I Un93Ub ?n="SQsw&Ol Jv9*J[U:%H'(;-FrU3#D1ak]BkA?f.d >ê(g=">C% =[/ <<*:4,;*x?&8f::U*"7X 3F6&1ۧ 0XbuQ2-qP& (&Og4$'W>KH-#ߣrJ5#"Pʫ'2" y"1MRK2"~g(=484n2*:h=X D[W93y   i-%YߚF.Bj=4R(q(M*B4,(r$GR{)2*L=eWH. x% %V .^< yuӌMd9*=.1!EW ߫4|T/ܐOr5Z- 61!պ=h0F>4' O .i!HIa4`fqp $ξK)*By*$Ǭ~i3+G@m#EX9*A5E [YT4+ Z89@ N B1EL F5]9j&U9K!-3vZ:%C5&~Hw FHS HE~U  h=ß׵3+8@$/rx u{ +n`廨*mí#[~-*> 5%+0dj2*)P:32Ǐ=;2~ڠ~i {s =w|1 Ug:,tlű1!s4 pAKBjB1)fXZ#bLU1!_хy.=4\@!M]f Jǩ=6H^6.>x)=;R3+3p @2h 1N+;93/*s/fD,06r8,m'+ՖaJ l3#%>Ⱥ=4 Ye<=4 +k$ AC%r=+ HNL3+!u&y3+ocn iL+¹=;dQ JCPq2*G&93x<>r\-3ӝ$,Q|63#?=<˝k31!ɅK{{4I}uhZG"8<>na # $p,1!mh+<>H *4@[9(=+) 7' 3+v 59*o5%٧ QL89kc$$Qe*'"$R6.VR;+$yy[M xc} :w3cp;)p.r۾#)ot#t' h29#gGgWf2*fXi c7Z3#bGܲ<>b^vp4ZK9*^E(d:3\\~NAR2*[&vI9(Xy=!X={/>-QE ^=4Iv3+AP#-A;6=<>Z=+<'4 4;N%-7/2@ۉ  0Ƿ9*/_ʒ; )^aR $3##t(=XM3#,`~ O$<CLL&#M fI wW7/ wp>#_}#;L''^>->t="U3#A`8:ؿɸ$s yܥU,E \e\.=6KT,EGPŶB_'ߊ4${2"8M3[: Ґ*8Q9*Қ[$%bԕ VfiܦIܖo7/-`#Gb+2x %KK$|Ȳ0(`)t="#K/,$+з<;:l}-<@*xћ""v2=t,E%o_WVz9(n@ j%6hi\Tfj"֠B f` WC:%P#NI}w-HkZž *ECG)L7/A)1!8#|6J6 . 42Y#4Jz&.Zo93.ROwI +^W=4(7.b*&!h1)&Mx7/"UDZŦ@e0 x 1>?ʇM1) .[U {(E&# d c R # J~ t#f9(] : *Q!?q#OiٌG 2H%V #<- >0p9*Gg>4,[4,<;=4y'xu2*Zi6&W@9(ӇR&тƩiG& K{04t93sYJ  FDdsw<>hܮ1?:1T/u}#%X5]݆>-œ6.VTIΫ-'2@=+&"/V%2%3#jؘ@:,*(PMQ6&)57;2㼑 &*g>4/<>$Hٓ7J^K1-3I;.I "S:1!\[S*ӽ#I Ů$|Q« xJ}2*u?<>uhj8s JqQuR*#msMtlaeO6.kdTG1!iz ؙfD |%3+cXb>Euz-`9!@x#]-k8`8 ] :*$\Tm=X|Җ S0#R*˽RE:3)R|U[ !*OҹC]&O$!*M9*J?L'7/I)7/Fe@>-Eᚗ8N AY6&ʆ}%5F1d /.w#.!& -xC,+@ؙ )ŀ E&:K0:3"@i{3$QH3+gP OjG꺱F4$xD#"ՒH?.ƍ}=6Ylw'z x93+3;i  vo#+X?!dU>-hd2*=>-(^:,ਠ7+D0$0l lOPk 1!ް2* c7U[v<>Ү#щoD="Mp+fa$ɑRaW !1O@ V1 !*>#Z5 7 ߔ6.5rf>-(S<7o="6l *}昉v.&aG#rU:,ߤ!R6.y-'#bdA5:1gxO"{\3&j˭mԇ1 nH&=4%;5j7/J :,XP P~1)/* *4P$p ;*4G"#;%'b4,9Ӆ"(9M\w-RL (a:3&oh4,$3 t9* $X]P r&$>-4,&&˜S?8}p /8FA %1 EZ$ l۹RM&c{**RҎ>-gMp WD^ 䶧,~1!+uPD|2*ݏ˕="_`. ~NLn* p`yU="~5s3 2$F Wb"g#>_X'Z5%kש6=6+P&|)F="Uo[.0(\Y Aa$P ;3S>-^ks!#d+2b F:35 B  -lů LP93ɂV<:1[}; }̒|#zPC3+yA#4*wGTwEL" sT.$mwGB0(k8bK@!)k{y3+jl&e -ea S=+b^ʂ3+aSSG9*[u =v Y }4,Tua?>RbA R=LhOO,#O2/>*N$LHNsȌ4I p^6.GD,@LF,  DhQ;2Bl7aY ?:<9H<#  ;C0;):f!:-+;3+6Gb6u{2"46K"4,49*2&K;2*0}S7/-j24--QQ+5tB;)"|X*~V< ")zjf2*HH&r2(9* Aʦf ÒZ^;4c ? ." B`/R[(2P4,hf߼wO^2"i&;4cz2<>G@W 7S#?:,.Uԓ=<َ.$M80f1)!6.y>B=4Mw1)?;xE9(P5AD͸M($ܞ4B_ XPW:(l:1X\pǩa&>-Ų{ +Vց :z#=4I6N|=;  e=<%I#<7&ͨM^h c. =4<>Z=;2r + _f_{ oJE23#e,8x -Ȇ=6R~%zPH 2"|**[>6.qU5byPlHW9*doKd7 .#a3T$anU6_`i#_,{LS+&[J̕_P RR->i+!J}[<>I&+;4H5d_ g2*GJ!jEGwC/ 7ZbNA93614_D3+5l23[Et -Z"+@&*Q3+$='>- Qfn>-ݚ$k3+vR2*wrD6.{  LT'|9* 5ܻ 1)d:oE_&.U4%c( 9*,)qUDt:Ud&*#󇚚OH93KO^٧@2*Tp 3;S x6.ۀK1!كSz  KY64,Չ l<>Ѫrņ^SSÌ<>aq129&4hMq ü.zԺ mTD 3+rҏ{6.+ٯ%*Z3=RАt !@5% QkX=+3v~;2`8*p;4Xg=6PnB6.ܹ׹>-{,x7 -#{ie  zb|}O4,wlFXCvd2"jsЯDC iK޻1!gj>c'-:1ao7 _Y_*&_:<1)\1^Y<4,V$ȓ#Sʶk:%FMjX12":vJX#92*8<ߋ9*3X=z>-1`/pK'u23#JY4W0H>-ٯ'B~'G9*~A*$~T E h# y.ՙJ6` u52sS9*T)"yo*<4$/¼3#0<),*vE;) 3)>R;f=4㯤puwE>-g6m O9*ݻTގ*ݦ! s=X:3#:X!*ӍP=ҁ`ЈM2"10Z&σb}D=4iMbqKi ʃf6.P[}-ĘZ ).n9*W9KKiM1=<|З,"~2"!Vr] qz&Ql93-d]&װ2* p"5>%ZH fܻ ^l$} 3$!g SO?1*tuØ*:1 ,Z1!36O)蟽!UBrJ+8!ڰcr}#,=+x  IS oo &kIx2qR f5**V$9gK RѝUa R-Oo9DF yiOBˎG:pt6tjh4_6B'/ELQQ**O): (J{9*r}ݱ []&#!36 bY\ RJn9*̨u=6%^i/,$6-.cJi:,ud4,0W2*ye! bFDDhq* W0OH;g 2"u.~6.K>=4ګE /8%B 6b;N Ď&9q$ʗ#` 1)W=#7ى tA16ۮ _>)=6@& 4,rs"߃$X%{ 5ϐ}:1ʬ3#32D`93|~>=4T VlitJS գ:,KO&1)0_-Ņ:%+5%"v3# #r7/|&\2"zNl t:Aq\b۠-q_?F=6p̜m7/m?19*hh |3+c3!bq09*asQˡ _eD9"],h&[EWk Ut1=4TIJ T*h*93S0J\PnR :,NA, $JXX=4CYsR4v-3B(f* ATZ9*@ݕђ1!?T5XV 9*-5 i! V?73+;1Hy#VZ*&  X\ WH <;`2i<8W:3&zO\dzb a8dEφ2淃=27 à~ d휮ي1ؿb4,Ħ-TNv 9%CQJ\4,ӝF0(F PB4,uQFJ6."ג%; C2"tZ 6?]wcs7/ \3#F g:1~ TPx>-|} s4$npK lr+k,l/-j&i߫r;2f5߬ cع;XŏB:Xf_:*3+U()O: Uμ-+-SZ+|,$SLL<->S>?&; R-Mg)9*Kٯ1JH- Hg\;4E9|3+D ҷC} xG93B#b('2=69t26.5Mo:11T})^7/1Wq-R{ &(!ʡ:3!(ؑ wA od)8XEM  4 !w< *]{0(W⧖2* G~ 83# 0(O M<>L *"k-#l"!-k=6z23+k%x:Ww{׏B.U wVѝ!k k(:cN?=6znHy4-w1XI>-- #6.˖}4,[ ;-d5%$_7/du#ۃ=!ʸ^-L}0 3)BJ}4$0634,\;) O+-il E'KP"}9 x;*>"uA֑f m;w@"lrCkq6 kO0 df^[-_46J1)W&ΪT#UC/}sS-CQ3_{$MQé~;)IQG IOE>-Iμ6 D، <>C9*AOH_2*;#;-RM3 6!Xl0('6i02*&&P4$=:$ 2 IGg ~WI2j2*~%ZO~TLxs:(~`q9*~!gx~6{2"~2 WD#~pܚh1~k`c*2*~׊,TA2"~ր;c~\[{~XpC3#~R X9*~4-:%~m ~VM9=~6 %~:#-%~'(^\=6~V)'s= ~? (2~ٷ3+~3 ~go ~y'$#~4F",%~O*5~ i,#~P{2*~ <~%f91p4,~|3a5-~x6.~tb$~s$鰌3+~s9 c ~pf;=~n ,y<>~i8}Q[~ei]$7/~aP5P=4~_@ ~_΍_#~Wd7,7n~T:ť;2~N<7=4~L4a~LzƤ+>/~HY:saT:1~A&~=}Oi$~1C$*w~1C3h=4~.s~,D$~*7)!~'(o ~#[0;2~"4-~an~ of6.~,SB1!~ژ*"~ln[00 ~ TZ5h"~u1)~N].7/}i.}!3Ry}$k }萸;4}(  }ƙ&51!}A]ڷ}COkt%!}>B}mp}$##}+ qc*}̇'}W, }ɖ): }ŋ| },(2*}uj,$}(AD6.}ņZ0-}fh,}˛W:,}Xb~:3}l2"}; } <'}G4}9*}CgWt>4}x!d5} 6E}:<}$#}/"7/}㔭c }zC$}z_/}xVck(!}wX#S>-}olh}lvZ 僥>-}_yV}_4N5j-}YuC=<}Xń*o=}T}RvMZ=6}Ri|ЇO9*}P~v})8 }dq8(}W }7H=;} }_m}dd#}742"|*%~:1|\~r|QV:|h42"|@n;*$|z |Pk~4$|50(|^^_4,|Ôr-#|䝅-^6&|ufaE=4|b= |DS% |g-|rZy2"|pXo=4|]:|X7j |Weؚ |V*`3+|Uh]# |S5_ |PrJI=4|L`߮= |I8]kz<>|H$|@zS|<͘#|< *3BC|:~8XQ=6|8vO&|6TP||6A;#|4 hbD>-|1gZ4,|0u|* p |*+)\H |)`[D<>|(]0$*|$r1)|Ţ=R0(| 93|`vށ0&|o9~'"#| $Go2*| )4,{~ }${Mbܲ {I>-{^Ԅ9*{/55%{+n1){==+93{ n6 "{Mp%{ C K9*{B={ڲXC:3{̠*#{זZ{SӤd{"d81!{}Pp'>/{κ*h{y;${Ƚ:3{if7S1){#75:"{ۡ}>{5ɔ${!섿89{K {7c8{t%b{芅g{3K+;2{Ӥ-3{ڋչ#{39*{?/1K  {KЬq${Հ {MkW( {}S.4${|+7̐6-{z,:%{yCE"){w͡! {t~*"!{rvF11!{qbX2P&-{n.>r{n'dsv3+{lX4,{f$<®{_ idy]6.{^4]3+{WYKC!{UF={T8? {S,9 {R- q:1{Q°6"){QIz*>-{P;@ {L'=6{K%@1!{HLa=4{Dִ<>{B^4,{Ajz  {@|t@{@S;#{?K c{=ݙ|{/Q19*{-uPR${)3)1!{!x4{bWq&{`1*{I\9*{9Wqؘ>-{ Ib3#{K,4,{FNu_zAX9'z% zkc:$2"zFg z޻lן=zX-#zؽSf2F;)z)kzB9*z|0(zǍZ:lz=3#z@ ;#z|u"zelͪ' zqz8u(A z_fL$zU\",#z`zU~@4$zU2;)z6.z{pl"zf?岷#z@36.z3α,&z7JzZEzȹ"r!zw= 1!zx  93zzU-G zzZzxzB6-zu]3lY zqnv$zqhn"w;#zn{Km$zm8-'ze{s"i#)zcAh@o.&z_k"$z\@93zXS6&zXL?`kzPzLd;C# zIPa[i><>zE*zD3Wz?Nc9*z<=@7/z-z4^yJtT#z+q6yqyR)ZG5%yQy\y64$y.h7T y8R2"yPR[ y1{ y&oB yy|;4yBj9uy/ܽ"yؤyJM99*y㳈$;2yEJ ykC>-y]^y18Gh0y+>2"yMA#Ii y%>-y3X/yʋs;:y1sAw$#ys?N:yy y-kxyJ!9*yD^:yߗ9+nyF%W4$y԰pyf8 y)}0(yZ5y* yqxI>-yB7/y@ &)!yv;y 9Fb3+yNx:%y| }y{70MQ ywUAP ys?}s6&ynW%m09*yhkh.F2*ygFUBydG#e\:3ycT ycFљ ya5By^Er`F yZ9 yYzBH> yR$=) yQ:LVyL79=yK'8yCs 6.y@^y@'45^ y?4y!y>w:@y3;&"1y0Ǖ y `S+yY<=yX(NTw yWO'D yF6.yUλ#y o=4y AFyaCW| y\` y8]@U4,x@`3#xA Cx0:69#xZD!4,xmms3+x;L!:%x Nz# xPԿMxNN3+xѸ1x xdL=xī<x xxѐ. xhq.3#x[_. xv?xp8-xf ֲx#H%:1x\W x*s"2"xw)xosפ x*#-<>xV,,e#x?F6 t]Hxx0 w 0(x.()&x+䂊i4$x+] | x*xҷMx!'>ܻ!x m1xp~!xpCP0(xM( x ~} x} x'nk> x 23<>wJ<>wz0 w9*w4wÝ o wuVm7 w_ Xa wyMȜ:1w+֖w"4ywԞ}Y!YE w$4&-w9X="w#w ʋwj! =4wSVVm\=6wTO{Ka="wGU")w)N$,w7zIwt 3#wF w1!wqȮwTS#Kd93w$*s#w7bY$-wR:(wMzg3#w~93wyO#/<6.ws׹:=>-wrA&$wnWXwkwhI)  wg8̏"waǃw`yHu!w_ȇw^5hq|y wY聣#t wH8I4,wDR1)wD;8 w@Il6.w6s:3w4=6Sp9*w0d mTt3#w) R <>w&4E"w&agw T>w䚕9*wߵ̬wtיwTcw?W9*w Ŗ_w .! w UN&w fJNp:1w@k!wDlH; w|Lw g* w d  v%vCvV 'vvmU3v A*vnث9&-v4!v"v:3vΊyvSqbKž&vQ  vӁK9*vΓ(vP?3*vYrcvUv3"nVv㤀Q v4=+v9*v";W2"v F7k v(En<>v_ 93vuE v,۽3+viNC7v {2 4$v&s. vyw^3#vt*$v'ɄQ&3#vM~|E=+vЮi<>v$€2"v䗸U v< %v|am>-v-ov0vϟ v{N8J#v{c{)=4vwP'4vsl>-vrY<vqg'-vj`t:.89vfk װ<>veŵ̸C"vd+vVd1!vU evSڄ#vP.W<_4,vO`4=+vMB-3+#vM=zGv vKXՊ1)vG1d.lvAy3;v@5 >-v<_GpRv<<>v4 1!v3 P _7/v1jU4,v-6E 2"v, 1 v$r:9*v#/R]v*j vȯ&vhw4ݙ vfsAh vwuv j9*vhb2"vFZvPu`Z=4u="ud.uWb[U uBJ0P3#u%}" u,uuu4M6.uyG6D+$u=6ubOB7/uesD&uxuR펇i<>u &,&u>ֻE;)uUx7<>uѫfuU+wOudg&"uYpDu.̞˞6.uh|> u}&!9 u&uou,##,uIJuL3[ uIs]1*u^ \="uK{-u ͖!u>-u8Upu z)$4-utP%.u5x6.u=3#u6 uxUo}uw K=uwAqz0(ut4^&un(9*umX.6.umd7`n uh͕b#uf8uai+59*u][tx$uX4IuXji&#uX-uWAb" uVNE-uOa 1)uMe2"uMjIg uM(^J9*uJ,Z8M u? u> u9\19*u7[|3+u0]&u/yén$u&>z]`u sTN u 8=:!u~q u@|T uQ"( >-u2K%uq+u64 t>Բ t4t8 $ta-2IJ,#tk9(t0?bU tӋcL6.tdƅIt@ŚtR"LY=t/|t_814,tƑa8tw{"tQ  tϚ 9;2t/P3tA  t͘ԭut) t1QHHt4?q$t^Xg;2tP%! tK&2*t#h#2*t|~0 t6=6tKm tiOm<3+t>#MLt R!+to]i tHQ4t~J"Jo)s$ty+8gC'StxL:3to(%(4,tm!➠:1tc2N>-t\<#"tX$Hi3tUM>' tQiq!>-tPVLf tF4e\d$tF+8u2*tCjVON tA69*t@$I3#t;6.yt5c4,t/P t- jt,rٙj"t+sHY:t+,j t*#l st${7/'t# a1:t"(1z0tѫ#)t^{-U2*ts0 tgt` tZ3Ȳ"t 36*tҰ4{| tsrMY2*s'e#s9~;=sp42*s0ls] sm4pt9*sкs:1sڄס +9(sՃn8Vy=6sF:$sϓgsο`os# syW sA2"s?"se {Zs*=M!sH×6.so s=]s9a<>sLm)*s-ra0 sca<>s+bZ2s';2"s sw(f-s`[sg`E  sW"~$s8lsK%O s|?~ sx)]C swN?msum[V0(smt8:1 si[ shKqsX꺯_sFumB+: sEi|>-sE(D-4,sAt9*s@aG=s?*)$s>l;~"skrͥ{u=6r=#)rC I rğ3#rP8r:"! r-46:r5&nzrޛ:%r '1)r5Әrᙑ rtKh&r[2f;r·X+#r݉} r}WE0(r8q^6.rV&ϊ3#r|fTryWZ">-rsV븖&<>rpR|5%rn],rj9R/ri h#r_F'\B&-r[himaW-#rU܉~~=4rU<~ rR.&rO1A <>rO)pk rO@i6,rN @K$rMJrJ^_crIg!rG?Gp r?7!r&r#rj  rEBri?">-qy"q5> qNH< qM[Dj"qqp墎0(qOyKw3#qA?qRx:3qғ^ qϺy@q)nwTt4,qˮw/#qa"qt0e&q 7P4=j&q)Bϫz3+qti q } qr93q~{*q~5Ըj"q}nVqz&ʮqu=X qppGd=P@;2qm9*ql,J#qji=#qh 5893qe1 q\kj6.qZ4#qY{2_<>qW-p=* pX# púز-3phO81)p p e2*pAt p=*]A3-p ck pE09nIj3+pFcp6hi pD40(p_ ۍ pwhRFp؍>2*pE`;#pVh.>-p|D p,&-=4pCp~ԫ'I:%p~QGx#p|WP?$' p{VY,#pyf#pwʻ7/pv+:pu-ptM3#pr:qi@ pr 4Y`"pohZJ pmkpfD2H-pe-t` pbux~2"p`tQS9*pV+`䑠 pOeK:pO1- pI5e p4^:1p.n.\ p-0@Hdgpw\Q:7/p CD)&-p1x9*pq!JL=6ppkSnppRo$puO8$,pop8R<>p *i,2"pDbPp I3#p ș=6pRKxSUp3>-p+q-o5n, oU!o`a&V;4o> a>-o$oj=4oTM"o[=gXf&o߁og6.oӉ: o+SH 3+o{Y!Fol#-oJ4,oZ%t#o8 ,$o]QUE; ok:oIY‘<>oyo^ŗ$Lo}4v# o|o$ * oz"YoxV7-93ovKV4$ov  osT*#or2!J>-or#͠$oo)  oa޿oa%+Œ>-oa>K9\;4o_p o^Ԡ*&EoZMn^1!oRT2"oO&oNݠbM oM?4$#lc oFa:o@BD_|o>"LsKR,#o>_"D o=8ʥa93o4/o/j H}V3+o,+'`3+o*/#o&m0Fo%*J4$o >o293+o]ʖ9*o\F>-oP:o l)к9*oZ)X=o Jn n4_,$n)69*ni^n犕K4$n޼e2"nGM`5G4$n,c#n M[|nؕismR=4nMiF:,nо0n׹żUY nӇ+[n-$$nЖ,0(nZHv n}]([:3n\"mC nǒJMn䱮܀'n\Z#npZn3/e>-n8 R>-n^9*n-4nf$c;=4nc(MU"6&nax3k5%nak]* )nah$rn_m4,nZ CT nXIGn=6nT̙qnQ(8*:1nP>n;d9*n9MyQR4&n4`EG~ n/{:A2"n,TrHfn&(] n%~n /XDnZz<;4n!M=n$)#nIB#nQß n I'-3mP  m}U]u mr_I; mٴ(9(mH+ۓm(h&mϵj#m; {FEmfYP m߯iP$mFiG#m29>mmLYO2"m|m܎K$-m;=p/mԨm;:m2m5?"m %b;m*%mϪbFK,$m))V;4mV8>/mS3Oym=½n mŵZ,ƒ mI;m:Ot mѽ mܶ).mS5%mT mX"ԫV<>m=>-mƝn%mH=p9*mHD1)m*m|ئC[ mxgV-3msta^( mp.ԕ-3moA͉#mnh9*mmV'; mj~c =mbʽPfmbVo)m[Hv2*mZ$ވ-3mXZ^5>-mWb|P=mF-r2"mA*m:y͡-m8l<\)/ m-$m(LApN#"m&gЗm%U  m$2>-m!־'m=lr+p  lXb$lsKlb'M3)lP;&l/E78la֬6-l$j="l=)PlR:Ĉ 0(l+:A3#lζl l@p tb)lp7p-#lH7B  le1E1!lo,$-3lZ2(lZ4w-lY lV X4,3+lUL4>lS =()3#lNclMΞo.= lDp6 lDH:(l>M9(l<ޜl:Sd<'l811 9(l7B=4l3=l2͓>-l14+&l/Pi l+&VXl"퇅>-ldѸ#l@_lF7/l t>-llO:%l63'2"kW52*kdGM; kOw jk2:yE>-kcD)Vks6#kP: k߫6\y  kXiU1!k2wꈂE kgJk$kPw'Kk+-kjGʇk:dХk)0[:,k "2L>-kb4,k~r/k I{3+kV j kz92o4$k4=r:k3$1)k,?93kUKD.-#kzF2=kpfdkl>'Ekx:kr@˲2*kxk[i[6.kYOK&4,kU_kP{<"0kO^f)&kN1ZjE&kM%rkEuG="kAAߴ&4,k=:XSk:Qɦk8#2k2x:c >-k.OP'eg="k,%& k&vs93k HkQ(.kN%0(kLV0$k[ pek^*4$k 5 jT[K(2j($jɚ:jW3#jhts=6j1 j@ܔ23#j'R"̾4,j 2Nj c=rj饘f9*j89j<"jӬj5K&j O j̤jZ/i0(jO jᄍj6!hl9,#jCtG4$j+3#jSۅ1!j,~?3#j:p6.j  j]1JȒ;2jQE6.j<9(jJgIM>4jvm#jP6kj9*jp0QM0(j3]$jsrjr9bR]jl9 j`ͱFi|j` DӋ4,j_gE-'j[*(jUV7/jR\P$jOFdjML78.>-jM#djK}J@2*jG(ljAQ۞Oj>m?93j=zH7/j7d E j,)N j)Yj'&с>-j%w?>Fjt{ j9 d-j +"ji)j qbRjrp"j|b i$iwJ]/. ih:i19*ib|Ǧ0(i8],#icYBig5*2*i٭" i]T=ik iknX;ix̒9*i8 iiH: iF-! iU=iӜYihy| ii)L#iK93i}R̕4iS<>i i 493i~$52*i}'>Jiwx is{Uũ=4iqb2"iq"& ^h$ic zd2"ib֥;Mi^w&i\="/iX#iX@i+iL.y"v0(iGt^H4+iGiH6.iBջiAF:G/'i@;0i98n i-+c$i,qoi+_ 2"i)V*8$i(`7  *i$:$i"g]8ZiO &iHgc=4iX <&i^Mv=6iHi).N& iXF<6.i 65N i[Er=hvyb]3+hKq G:1h+EBKh'ThpG@h -] hsWˬZ/hCm.7Y h<L*4hާ1ZY#hA巼Rh)n*j4,h8Vh>JN h!j h8y hɛ|n  h+bA93hY6h2 h+;mW1)h #=5%hױX=4"hrl3#hQ2"h-pJ0 hf\`1!h=A>-he3#hsx3"hR#)hEJK9*h+a7'hRGgh +%hvо@t˔hs[R-!hrZ$hlq8YSheKhds00 hb@i`1)hWcǎ`^ hO{JT~!hIv>-hEop hDny/6.hAE`1x h>>93h;Ȧ1Q$h9yQUPh6-S@Ch5Ueh3 옜<>h3Ij;)h2p5 h2N/$h.;C4,h.n$?q3+h-2+ph(2"h'eb=+h"pqh![5 7hl۷R4$hujhxm h!+hABv hC0ih!?ht%.h ~0(hKp h $B h}_՛ ^ hyK[h58YQ9*hqng!gWCF4-g:y[qVg2tLgѠg8>-gfȚag|]9(g1U5nE=;-gg+. gk gp4$g]vg;C0 g C<\9*gಡ{<>gkwg  gsg:1gW*Pgk}4S2"gӞ#R83+gӗp8̙ gFH#*4gɏϙ<>g =4gĆlgĆVg-Vs<>g/.:gqD@:gc +$gGEWgNOLh3+g~)X=4g( 0(g? 3+gwn=-gt g*zgJ{Sg1}l  gx;4gM/gZ ;)g}#0k;6.gqngn!aczglB捾 giR=gg2͌gg'#ggDi$-#gg'ߒ1)gf<r6 geʀyu>-gag^lK!g^l1d2"g]6A gYoR>-gXwe8 2*gV  gQ ;2gO/A,#gL^/jh0(gK-\gIЧğ=gFu=FZ$gDe2H:gDIڑ6.gC23+gC o(4j2"g5]4,g4/fų,g/*Jjjg.{0 g.<^* g)L>Ng&L0-; g%䯌9*gҧ;)gkdg_):,g @c g A gpU=-g f"t=fΛqM2*f0F#,fg1f_mȰ93f,Wh=6fЛM->f^flSfD. fO>:%fjz 0(fԓ B f5ӒfΜ fG%>Q?&-fn .f{lz fk)@N3+fhzqpf!N<;)fbB f L#fd8:fގ; fQ|<>fA=f{!R1)f`f)Yz f1 xL4,fP+- f J#fW f/t9*f{RA& fuU "fq{%E:-%fqmhfm@4"fm:3#fkE fi7fihP fh"!e#1!fUpFfT0!-fRK5Ƙ7>-fMc܆x:1fG9J4^4$fF_E.;f i}?*$f tGT2"fO1^Gh f(fzF4ee~G3#e|4ʏF&e}ݷYeacxF2"e1e~\0"e|w/eztu}exlu#!eqC@2*eo8+.enf#S="ekЏC0(ejϺ\#ei9:)6.egtmֆ0(eZ]x58:eZHƮ#eX&WPPeTfveRf;eQ"4$eNn@:1eL=Otz1)eL  _3+eJPH?.7eI5>eHa"-=-e-.K(n;2e ܅O~e SKl;2exМ=6eյ5JW&e~eシ,$eI%hj2"e ea&!2*e:4{H="eXl!93egO5d纰kdL5 Q93#dsv:,d.O`ٜ-3dM h4,d[j d_Ӵ'K6.dA7dܰyVdJ8X< d>+4,d {ĕd֜w֟GA4,dHU4,d=Î>4d?  dͷ#!kdAlx&ddҶ#dJ`KCn4,d&\_zd1,R dN-/dío| d1"d`\%Qd 1"dDB{3+d|@e#d8d)doė da:Cn0dYd e<>-dX2"d ;#d`/12"d4]c&dCJ.dhA7,W<>do{FYdJ+")d#ydx!NK7$,duZooq8 dp>G<>dpeUc` dmt.2*dmbYMS dg^ $d` Ad]joyv d]XR 5%dRf:dR|+dRC,R4,dO4"0(dNkHdK@m:1dGgV7/dBtG$d=:ud;a[,>4d9F!d5C+^J*d/CSx$d.^΁%;d-Ɨg2R5%d*Ad&r=+d#S\}7/dAʾ=+d d-Fd`uߖdT$/dsL.9*dLl[B"dq ddpR,<>d] Gd^U1!dWSd'dE`2"cLYQ7c&Tcvq<>c)Q#c* +c,~2y c cqN~¯Gc$ ˆcʆ cA>p?W=-c8ae c}LIc{acycV}CcU _8 cM[IL:%cE/9*cAh3}rc<>}c,a&c,ۧ0K"c+њDvsc&n"-bkդ( b6HSx93b.O+0bIWo-#bi^2ȕ89bqY6.beZ$b m bq͗4-bQ=4b{r7 bzCIgby;@Q=4bp텤sboֺ=!b\qa%bSF>-bQhhF"#2*bF| x,#bC@<e bBZx>4b>~w6eb:۠]b8'^ .b7f b11a*bb0^DѼ::b-.kCϘb-X(b*O`*b u+0(bkj>4bGZYbZIb׷93b% b\kb#bm~/ by9*b!7E b3Iac i2"a{Wba_t(md auRJ aAγw)0=a6#CW3#al8'32"aHZ(2"agM9*atnb!aZI' a޾ո9*awwX aسVP:3a֗rW3+aԴO' *a{`oikaӺB<>aI$ܛ4,aT.%=a9\aiv aYO~=6a9 %aύl6.apó a|a aʑ$ aAHLaLN#a!oc a{>-a'H1)aW2nY:1ajbaZj1!ao̕#-aӨ7Ca09*azJPas7hj>4ald"{ral] ai,Eo4,adm7!ac}a^1S#a]7=4a[+aXU6.aQ^$LaP*p  aNc#d3*aLzW^ aI193aI. {2"a@-Sa@ Eʽg$a9dzk<:,a8Ma7 c>-a6m+";)a1KOa){X::(a(F<a jHʕb=-`g@3#`$`?w `4`KS<>`c`t>*0(`7ppI#)93`|#k=X`{$_52;2`v ֱ. `s`>-`s&|; <>`rQ};+`r `o`1`-V3-`$d?c|3"`#f1 ` %` *zw4,`3o7/`* `FT `ۭ&5`T2 `T$d9*`ס{Q)4$` RF{{ <>` ?`kG:%_))F3#_!:_<9*_Ы8,=_줋݇S$_ص&=4_~ j; _䝩9*_!o=_mTBў4$_ݓ;Y _O}H:_-"5,#_kY?2=4_0DC$_X_23 _46Q[2*_ęZ <4"_׬h1s#_=RpW _I;_T lZ9s#_[:Fp3#_•8$-_vg->_@g _r +?0_ݓ^5x _Dsv7/_i2*_X["_G  _{_:Y9*__j>4_*ip-_=zh _yLUZ6?&_} g=>4_|H=4_|1E˳B _{@ľ'2"_{  X; _zR>-_vޟU_mm7/_ca_`1"tf_] ns|_[moH_XSp4,_MF-#_Dvs)4,_CMwCq9 _2*Dc_0+| _0OT_//$Qi(2_,G3$_,kGs_*L_&Ӏ` _% ̷&-_!3ogc;3_ NIt>-_A.*9_`Qj >-_h_91u93_ &]_4`|_ߚoZ&-^Op@>4^A 0z-^)J0(^jt"&^#``4&^jZ="^5%^&Rn#^f:^ߩ2^޳z ^3э-^ݬr2D:3^9!F^̓%U ^_ذ>-^{ #^ Eo&^1"^zéW^:&7= ^~1!^$=yO3+^-^ێ!s2*^&_ ^4  ^%="^⻕ ^}&ˉ3+^xiMwY1)^xF.$W^vrQ^j$s ^h`Zp1)^g$ >-^b2 GoY2*^aMt"&^[o`M^[cI },#^[(9Qж^V~ 8%^Tڎ>-^Saj9^RM_u ^Pβ^OgZ ^NlL>q1!^Kv^>쵈<>^=G1!^<*0(^;ǫ<>^7I ^.I\R ^-o*H*$^, 4,^+|KJ^+,w^)4_^)A=<^"{صn>-^ ul_/^%|J"^Sqj&^ޢ )nA^9a6&^#//^N]*s93^,86 ]19*]3* ]]-|h ]O 83+]U:L<>] ]#Y 2*]f5$]ێk]Qff<>]ݼF-]D}+J2"]я(_v]ޱgu]SLϠmO ]82]tL 1)]}3]NYVp ]l#*#]t&3+]C ]2e]O]s>yk1)]'593]{|Xǚ"]cj,3+]:{ ]:]s]5KްO!]5'9;)]3on?9*]2D o3+]0;m04,]+X O>6.]*q_?>-](0wW<>]%na@;2]##N"3-]#`A ]!o]jJU>-]_X@]P]-F1)]12E3#]tLna ] A9*] `.9*] _vT] @vR5`:] l]]uU}&]I90(]bG* \5qN5 \G4[\[~Sc\,$\c%MP \֛w1*$\P'.;4\բ8E=4\m׈R6.\NG8":\͕"r$ \Ҥ5o{ \eҟu:%\il1)\R|.\v= \\7/\ d5\\ c,!$\ּ>-\8_<\}Bӭ&4$\12"\ c \Acq't\GȲb4$\r26.\(N=4\E \70 \F\sM\~؝ \zһ^ \w-5:\t1<} \sp6<'\s;$c4$\r,j[@f\q}|X{W\qVq :3\q @4-\n-\YgԾ+9*\Yb ak2"\V'93\UdO22*\P<B{#\O ݷ>^-\H y2\GJYi\A. \=K6.\=,Z\8?b9*\6=B-B#\0X(:1\.STTs \-BT2"\* sP4,\$}#N+#\#a|bh=6\ 7c:3\*B(^=4\Qw#\eq\}\Մ3#\?jV7/[i&-[[fmM=4[;#[kƈ [.-[mTG>4[Xx`|C [:yޑ93[ax& L7/[D [ *#[L0([ݨ-[43#[ξW2"[юS%[1|8 J[gFb[ʜ|%[ő3/>-[9->-[u_U [W`a[o[)~>4[2#[>`χ[D8?_[2[?@p [9!=<[gp[3M H4,[뀉L#[~ 27/[{Ȕh6:%[xWM=6[w7hry[v.;4[u* (3+[j 2*[g:M<{>-[gi :,[^sЄ![V[0([T/?' [Q+\p5-[K;w=6[K!:2e9*[BNچ0([[9UV$[0ѯ;"[0)=6[-cp9*[*E! @9([*'7Z[%0[[!σ+[&[l2"[ml; [$_;-[8K4,[;|'[ÿ  [ i! [ B|=+[ |3 [OU( [y2`5%[Mq#OcZ#op+Z\Qk/<2*Z B]$Zf0Zk.6&ZE;FUZ,{ Zo ZETZ_Ԛկ>-ZR^Zc Ӧ4,Z;>8:ZI‚&Zm Z_' Z Zý Z<>Z4" Z_Zv7/Zշ,Ё:%ZFg:3Z֒_U Zf&-ZLgOT Zi H9(Z{E"ZzH*NX4$Zzl 'E6.Zxm@Zs]%W $ZmOw@^,\Zm^]V$Zk -Zj7XM#+ZgXͱ,$ZfZI1)Ze֥6 ZaoH=ZXkbJ{:(ZOΏvj<>ZJ( 0<1!ZH0魀 ZF)ݝZB|]Z7fw>-Z7ve)EZ5 z#Z4Y{c=+Z4V&Z3UJe4<:Z.U.Z**6.Z'9*Z"!ZßS * ZS\5%ZH$9Z+ Z+K#ZyU*3#Z b Z :3ZU YrhY<Ynl=6Y^ݙx>-Y+ m1)Y ~1)Y07=4Yji YOL Yޗ~yg2*YuF;4 Y*Cqp"0Yל-YRٮ Y{ZS#YPW+'X*$YҊ Y;nwjda>-YK2 Ye/^ YPo=YyrY^fY.Y|D Y)̵Vw&Y3<>Yǃ$_ YewO:Y^`YOam#Y- F3+Y,`.7j*Y3:Yv>-Y~a-#Y{tՊYw{ YvA 3!YvW;#Yul2J4$Yt+䞟;YS ף3*YRӣ;DYRq=4YK^ΧYH22"YBf?4,Y? ʫI>-Y?3CJ4$Y>~8 Y>kιY5n3+Y5 +7 Y3רz2"Y2($4$Y+v6!Y%@ڑ>-Y"nL1)Y4-2"Y- yw<>Y~/2*Y:u 3#Y4va4-YHjY=Y,9Ua2*Y:a,$Y ] Y6Z` YzowRXezeXY'X5_YX_P93X@2*XL)2f9*X߼0d,mXaGi&X}P" 2>-X=qD9*XnW1)XP֢qXѸ,̩ XB$9*XCkXuHiIXL*^XfXZXcm7X}L,$Xxrr9*XPeX3ϊX 6(XY#X/jX⇆/Xl#XN_+&{9*XPCY,$X/$@X13#X`vxXic,eNXh?f"74,Xfı<j Xe~c3#Xb<ĎuX_lB:=4XYKϭh3$XY"1!XW[-qa XTrK:,XR02"XKkZpX?&l<>X95׮H=4X6[STd#X2InϸX-(6.X+ZPnq X*_[й7 X"]H*#X5s/=6XwgOXNz93X80FX 8|޽XtV4,WV W0> $W2"W#\L;)WUħ}1)WKp93W*U[q0(WzZzUWGs 8=6W끼d]Sq WrU=> Wpu*W/,=4W(#Wwb L$W?7&Ws 34-WgO"Wf_$Wh% Wɪ§8>-Wo);2WAUݸWޚW~m4$W3&WWkdrWU8}$Wߑ#; W )l4$W6*3#Wlw7/Wd2"WlʕWål>-W=0#k\1)WJFW{J WV2"WZ0(W'ͺ\ W D#Wy62"Wt(WPb* W{"WXqTQ15%WGժSZ$WÂF WM= ~/&W}}{zk7/Wz3+Wx(=#Wx'oVsWuGe Wt Wqf3+WltJO3+Wk t2"Wiݢ48 Wi@GFWY(S=4WYkui2"WK3LWF=WCI,$W:9DXtXW: >[W8ī4,W8X3+W0*p8C6.W)2{^:w W!h.93WnlI6,$Wg;)W @:1WJ)FW~zBIWJ66N$Wxkq Ww6&W7@ WٽWŞ"U=Vd V;(Vl*"VaZS$-VT0A60(V|IVA =V l]V=t3"VO~$Vl;ho VI8$Vϊa V\yVA>z%V0 V93V$!=V@&j4V5D>-V& 4,Vh<>VxρVvn2"VL1j*"V,Vs_?SVٴA$V| V̧ <>Vyh93Vv$DVyw=4V%Oi V/C<>V%߬^2"V.D0 Vt Sr6.VyV)~NVwn4^6.Vt/hVnfVm JYkVll>-VgGubE#Ve,7E:3Vc[u?&-VaH~#V_qD< V_,^Eo V^/(y V\X{3+VX?$VTM:VR/'t VP30>[#VN I~^2"VKƋB%&VJa54JVIB2"VCK4,VBILJəVB1HV>۩?n-#V90=93V8_V2+xa V'=OZ,Vt*L:3V~MK=6V;C V˿p V:r_3+Vlk3VZ*3#V J43#Va">4VB7E6.V N-#Un]z Uh>QMU тUꎢ>Uަx~&U1E-Uʼn593U),;3UDkWs Uԁof3#UkфƓ UϙV6ޚ,*#U>&Uh=>"U5sn3=U46;#U!ĕ UɗU>-UƯ(\eUĵb`>-Uod3#U`2=4UG  UA.. UiA-UUAJUgU b"U= E89Un1!UJUzt~+!US Uyx UNb%&+1)UzN*3 Ud2"U!%7'Ut3sLU}&ka4$U|:gDQ0(UzL]z#UypP̍ Uqx2z3#UkXt0(Ug8UfSQ Uc7=+UbL0A U`Z)Ho:3U^Z UXz8UU蕽 %UTa+0 UK=r=UJJ`0(UH o3#UE$U96m@ U7d|J-U6|̰2U5 J U1l U0PVDHU,S;)U+z}zU)_];3U$Ln+ U"N U!B93U nem82"UboG3#U:}vJUWlLz;-U &{ZD UH|>#U8 C TR@*TQM Tbz<<Teo-fP3+T8j7 Tߎ T3}2$T*g_:1T< 3? T&TsieTqNz3 T TE"T=6Tܘ _$T=@ T2 ;T+*F"Tmr5 T,`.=4TԗT+MTG Tyr T8c3#T5:nTk>T³G2t$Teȸ&K-3Tnu>-T1/LtTV}K6( Tv#$-TSǭ2"T/NQ:1T.hޤT;ZV>=6TCN T;ù Tè2Tz}-T>ː93T!+TY85%TG=6T28UT93TZ4,TT'<>Tڿ-89Tߴc02*T`kбT3qüSTz:G>-Ttᨖ Tn "0 Tleʦ2"Te?~ * TdC2T`7cX93T]F9 TWW> TVLQS9*TUɧ:<>TNiTCe{ۢ<>TC5>-T5tg T0{լJ9*T..ks64,T-4ڍ#T,u,iT+u2H,T+IT -$T%V\ T \^T$ڒ=ThD)*"T-B$ T>-T!ǽ-#T /H T p=q2"T cW#)T ^P{<>TuLTUC!TeUj%:TQ0 e~1!SBwV!=SK\D}6.S˜KYSgSƒ1YSz Ӿ#SpSJ7<>SƃS`s3[6-Sס JSְ7:2"S1' S2x75-Sl=6S=_;=SčSL"SLj">50(S;f>-S٦{?:3SfkuSfK-Sl+P'S4SZSN''W6.Sc?2*ST.f0SGJ,$S/SPYE;#SKFS%,49*S.k!S|V) # SxGff;)Ssd 3#Ssږ#Sq13Sl\2"SjuhJ#Si`<_(*Sh|$%, Se Sd~>3#Sb|! SZ.#SX(Y;SW^k;4SV?AD#SURj>-STb SSUJpSLE5~W-SI<.U\9*SC&+5%SCZ \2*SCq걈j?;#SCDg<{SAdU%I1!S@`B&S3Yb| S30LNS2zU S1KS1\ viS+(*7/S*j D3+S%&S3eceS~fSwZ Sz3+S fc "1)S -#KKJ;)S S=䇎T;&S{3+RK Hr2*R$ Re1 RmUp|89Rַ( R!f6;4R[4:%Ri6.R*l2$R wʉR1)J5 Rȭ^ R㸊]&R6XRA) R80"17'R5%#R1eg R05 f;9R0^k "+R- ,*#R,ED=;R*80:,R$Nn7q=4R"t`@93RpaRb ?RE1)RF%R3+R MBð RC%?R`mI;&Rj^C QS* Q_ԕ QxV|G Qc#Q!qU_y3"Q QӮ'QTSQs`@̡>-QЬ4\9(Q?=4Qɾފ[=+QLjNN Q3k4$Qؖw>6.Q8uQ&I>-Qǽ -3Q)W&Q]CVi9*QG#w>-QU;7nlQ潩 Qp% QM/, QE=/ QU:Q_# >-Q 15Qo&93Q6dQ~dQ}40o_ Q}3O")Q{FQtsmj1)Qo;abQ4$QkFe%QgF =4Qa~B]Q_Ki8Q^qZh=4Q]dQp Q[ɨj`:3QZCpVQYyDU=4QWbYj`g=+QVU QU(wF-QKkHO7/QKieQIQA0|=Q@tIOa$Q@^3VBZ1!Q>ͨcZ Q8I3^MQ,Y$^Q*xH0-#Q)Jol"Q(ov^Y ,#Q&s7= Q%5 &<>Q%&q}F Q OR7/Q)7>-Q/=NQR^4"Q Q8:Q"?.9B QvQb)#*Q 򜃯3=Q 7i,Q0ްQyK P-I PJKK^ P,>?Pb7 PtA/c:1P@7DY--PE0p4,P P_҆ _P3DP]q P9z g PZL4$Pm@(1PW M&"P6UB&PJL>-Pvd&-P-SQ P%gr3#P >-P#}P%P)WOۀ P P5 a3#PRiPb? &=+Pb~OV!$PLD$Pua|i7/P+Z,3#PGKP Wf:3P4ȑP-3-PaRP_ 4$P|P|W, PvRa W4Pu B*PsS1)PoŚ-4$Pm J{$Pl9)4 PkC od/2*Pg3pPfxs'!Pe¾J:Pa Y[7/P\=I:P[f4h4,PZ7ϯ&PX<;'PWBb~PR/3+PL饯 :3PLPr4 PJ!㾠9*PHv(PEF莂4$PEOȩ*9PD;$B'>4PC RPBö-}MP>P P4O7bP/A`:(3+P*/^\ 3#P&(u,P$(&P$RG) P OS3#PT P,Pt>/P(6ZP-=P i?PzzP<* O~g#Odr? OpemdS<>Oޖm93O#;<>ONS ONy2*OmcM^j]9*O덬f 7O.L!3=O B1!O꜈nO?x6:Ows#Oxg`#OdVx#O6s8'Omu Ob]SOIBz` O֤Km>-OOh|4$O_V =6O ?S+$OH'KcOp9\O :1OhL7O%0.gOg C&O&ȧ+>4O4յ!1)O39*OɆO-|kƪ9*ONa8:O>Oێ4,OZXy#)O5] ObS2"OyO іO^( OUdV3->OJO2(#)OP[RZ OWWO-82*Ok[02"OqM7-3O|I#O@8<>OW OBI4$Ov^ZhOuz-Os l LOr{u2"Oq[?0#Onh sp^Ol3İq:Of|Ҧ #Odw9Odr#}=4Ocʄҗ: Oaq-O\Q5OX5oFF1!OW'>4OWMu0(OS:OP⺼:,OP,P ON3~^ OKZYc'+#OIIu>瘹>-OBwJlO>SF!93O=S93O<޹5~"O;c*A7D9*O9QL==6O9MPB O7tU!3+O6!84$O2ꛫo O, 'FY O(DP O%(V  O$+ :O$6J/OMO(>-OXQۀA OAv!*O Sh O l)g Oc)%N!dN{X}1)NA4,Nƫܙ*Nr'4$N9LN_e 1>-NT Q)5%NU?&P=N$!N/^]=6NRU!NnAv4%N?]0(NS=4Nqew~ N-]>1!N?l>-NPK&7Ns<NeP>?N17-4$NZ;kf4,NUH4,N?P N" Nbb-N,N~U5[2"N| 3-Nw73#NvHy/p"Nu F*2*Nr{B6!Np`=4Nj؟#Nj~I;)Nf͙*{#Nbmz&=#l NaSڒ;4N_Pz NYXf3NWC~q3)NU63+NU-NPaޟE{;2NF6nb: NFjϡ4$ND~D0< N9 N7@P#N-eZ&6o*N$!NhPNӜ_ N'0 =4NxȎNru>4N U߯Nw?Neτ=4N֖ NdzQ4c4-NYJ;)N*Kh9*N%ONgmVM~:Mݧh M`e2"MtOF7'MQ =6MLMMtM Mxэ(V<'M\( M==54,M3M:p_M M髺dM'Mn_K9*MW*0(M3M:'O۳M >1M RM߃,#MlWMA<M=j=4M|pR M =MC& MnSMjw+0(M9]!M64=6M*7/Mdrg 89M d; 89M $9*MX- M_\+-3M="M09:1MG±R=4M~C%iV<>M||q_0(Mz\'! 0(Mx-nn=-Ml;w="Ml|3+Mi_ p#MhP 5MgǂMd-,$Md(;;#M_p7-MVTՓ&-MV{cpMU_Q=4MSUi3#MMQ>-MH."#MFQ{ԥMD=m,,M?-EM>ZM;1.ڃM8oM,1t M/aX5-z6.M.\0(M-0-q-M& :#M"X7Q&MɰȊqMZIa>1)M8 M A-7=MEos<;MǶu4$MbK  M ;Z$[>2*M u="M@ꚥ3+MZL`͢"LR*L(=74,L^xŠ*&Lt@7A&-L~LjQH.#'L`%! L`w<>L$C\ L&QfL6.Lu`4$L]@+ L.5 L UV:,Lj0*i,$LQs=>-LJo-Lz q L=LoK3+L~=-L}* Lw #93Lt\GLrbg Ll3O eLk,xw Li$n >-Lh\?/Lg2uGS-#L]@v3-L[ Ry?<>LZ+i!LVNH3{$4$LUkvLN ̛4$LAإ3`; L>T>/L=M·L9"x6.L3c[L3NL0F0%L-@*L+P* L+1~ͽ%L(7jT>-L&Lp'&L#ͩL#|h8 L" :1L!שF6893L l<+/L /Vgl&Lس}" L]BWX L&HLU`L2 k!L!HLKYtLʘ=b#L.>9*LQeC4:,KߠZ#K3=K E*K n=K~cN4-K}<u-#KzIO 6&Kj3s4$Ki:%Ki-:7/Kf52((2KeO45=Kdm`=;*KbF?z!KZF|m1!KRN*V<:KQ;T KPgy KN ;2( KK˜| KKz;"0 KA./ K7Ԇl+K4\z˙;K3kt4K2%K.v/J K-b.; x_pK cC"KR1K}P{<>K ߝN=6K'tKJ!5ѐK̓vHBKԾu7/J3\x>-Jd< J YJ:B>>-J!1!J]2 JZn:1J|| JNz<>JTˊb  JgVwJ׏6vl Jq_%59*J4qGJV_; JIVJāHtJ[J) Jx-:P7/JQ:{5%Jv7'JGft!JfW; J% J^Y J%2"JwzJp,$#JtQ 5,J JPC=6J>~JE]E93J~>-JQ/J~5E6.J}.0bnJ|ġ JxEi0JsC"Jo^U3#JhV\$Je%Ye^0#Jbf6L.; Jajr-V, Ja93J\xjy}B2"J\Ն{*J\LK%JY>M JWr`,$JU:C=3-JO|{Z[ JC߭)*7/JA\J:`0 J9aܚ=[0(J.\6.J-l:#J- ֮ $J'8ژ* J'6dY J&Wd'J%fB/J!ܾיS J.3+J [Jk@SS J\s Jt0zI+UIL>FISv7a9(Iv8%IC,-3I5&쾪I녹f/5%Ib,093Im2W I<֦tj IH$Iᠢzz I_~W2*Iާ~2 zY:%IILj IՔb۟O1!I>AIݺS6.Iť$IͽL#Iŋ ICO-Iy2"Inja_t$ Iul_-#I}S>-ISͲD3+I9+*ILN:,Iu I,6yI!IWz&I=IT I|U I+X] '>-Iߝߴ= I3 I#IT#JIc:<ؒ3#I&l4IFoIk˂z Iˌ# I${bIx5Ä*IwU^' Iv81 ItEC:3It~?IfBM-3I\/" $IU]eIODM+$IL3z(6 IK IJ\2x2"IC\|>-I<{I6&I;=*$I0N I*ӜUI&h0(I$%@0.#I y #"M IS#K,cI$I8JL ;IR)ѡ#IψC$4,I=uOI &7/Hƅ5J HiR3+Hjރ\#Hٖ/  HN?o-#HPE-l<>Hd<*$H7A&H `4,HV<-H Ā@ H㛻grO"H(mh=6Hd60(Hj`>/H{;Hٍ c"-Hf3#H Pe(<>HE|>4H'hHгIɃ^ HЉ`:HvrL H )<>HƆt6rf H@,&>-Hsl0(HOZ{ HֶHq]K<>HJ0 Y$HRo;:H:nHa#0(H<Hr;S9*HJHA&H}H8|EHDHJ H 6 ΣQ Hܘ-Hb3#H_ HjX3+HR"HQH=4Hg-H&_:1H8XhH3Ha ߋ HxJ76're%HrHjHkGcU=6Hgd1m He9 o>-HcW #,H_] HS#=QHRض\3+HP:!HLXH@ H?mKH9AY19*H0p%!3#H)T #2H)6l6.H(6$H$d0V HHdd&H}!u#H Xڡ=4H VI=H fv+ H H4xk9*H4$HD}$H,,a` G%Օ~GӢc:G)5 GXl l GSi GB6vQGAZGшS[2"GϠ{hGͮ G̃+G롉G>t=ʽ$G(O3#GD0(G*h*Gi2*Gk G2*G)E>~G~M-#G}p.:G?u)Gyo/jGΛ`Gx#,Gٌ-G5̋=6G~q7Gy; Gt`X[4Gc{w-4$GaPM:4,Ga8J<>G`UQ-93GVH! GVk>4GSK BGR P&GKYY(^GC5Ņ93GAS|nG=M29 G=ȹG8AfG40*O|D6.G2X"gGG.N];(>-G'ң:,G'nxG sc($G唋GfD820(G KG?OE@gGh4v>4G u(=6G C'GB5#<>F{92*F 듭%-#Fkp#4,F/&/Fӻ9*F5NE Fwi) FyTc$FF#,"FC$"#FZ(ܦ_9*FtF 1!F,>-FlK!0(FKљ~[`#F!8 F  F=1!F>2*F=635F9>$FMݜ!FdߘtFV=F_-;)FP F(S#EFD0+@'6FEi<;Fr F`lɅ*#F]}x>-FJ,{*Fbg4F9*F|F8(3+F7kSF F Ym7/F\R|  F_OT>-FwĒi F22*F lWFthu6.FC+j,#F31r; F}Ta9*Fwx4Fs4Y6.Fq"LFpy~FpVb\Q3#FnGS!:FlPf4,Fk:/2>Fhol5Fc= - FaX ۡ:3F^V٬U5 F\`/.&F[k 3#FXzFR FVԗ FUyB4,FS!GA1!FR0"FP7*0!FK+EFJیFJ@/9~ FIع3YFEg΍"IHFEN:]L1!FAU~Y.$F:t^=F8ss=4F8AF3D%.F0f 93F05GPQ4,F-ܩPF-1N7/F& F&cWF%z  F!$!5FP?9*Fq*n FW(FW9(FFA+`9*FFFB<>F>p FB6.FUF>-Fu$ FYOh! E4|SETy_1!EI; 3#Ev,Tr#E(GEGƺ=;Epu2*EۣV^D5%E+AEҫGP3+E#E;ȯEǺ҃9*Eyh|<>EܸJ5|7/EZE }$Eq)Etbe;)Eb]93EO'n-דEvE ES/b1!EĐH(Ew"|=6Ese=A\#ErN3<2"EqzG3En!Em5ܴEm\xB$Eaf EY(493ERP&gI(EO!A7/EBG  EBq5=a!E?1f5%E=\  E8',#E6;4$E4/V,#E/Bֈ4$E$-E",MkE"hJ c|*E!O3+E=E&)0K E=2d:%ES EӴE q%.EGNbd E}),ZsD=W4DW D*viD%Wޘ$$DGhu3+D҅D*]p&D I( Du=6D޹s4,DDٔ>@>4DҾasDJуQ=Dvp5DnI;2DӇwlDؤ:EA"D4n`F#D"^zzD._&D&ϡDw12"D4 DZ<JG:3D㰄#DQّ|>-D!4 !DF&"Dmv D*k0?DlS<>D D{|s}9(Dz5$-DzeDx-p:3DxGAA:DuP%xEA6-DpKن1!Dh\T<=Dg*e`DeF.'4,Dch݇d D^wQ|D[ʐA$ D[." DZGzHDT\7^ DT/؊= DR:uxg#DO7MdPa DNJ-DM6 ۮDF$DB2*D;%2"D;,iB|[;4D6N bD2kR:&-D(!O#D! D"3+D [O/4,Dj{ CZDR4WD -C\C_/m=4CKbT+$C钀΂CN"m=+Cy)C}ß3#CBHX C3EJ>4CC';<>Cʘ <>C&*9*CO,2"C> 0 C)ݿC'6.CmiCLjC=y:9*CJ-4 Cӣ8#CpϳC[F} Ce>iC}b$o! C}0y+ C{RItV-3Cw]B޶=+Cv ,CvTD( CvXAG;)Cl;k)5-Ck`@#CaEj"C`eNQ C`3צ!=+C_L C]PC[w/2*CZ^ CP xm:1COőQi:CL-~3<>CKݪ CK*2*CJyjk+C;t.$#C9LXw C8ى 4C5 HƷC(QZ\{9*C!@~Ǒ1)C89CUػ'CV#CҾ$5=4C@?' C/g$Co]a‹ C ECbg{!CQuBB-3BZp2"B霏` B~K"B6&B햱30(B䕋  Bި@bB*o\{&BBABj X+"Bti<>Bߵl<ٍB_.,#B0f1!Bdnm0(Bi 6&BiHܣBx~*Bt31;<:BQ.BnfG;oXBd[:XB"a0(B554,B7 K#B2 0 B~oB!n:B8Bū5MWV<>BMaBSUǺ>/B~D4Z>=6B~I3+By#D\=Bu8FT*$BpPiu Bg\<>BewqFZ'-Bc 5%Ba'K`B`AB\#3+B[O" ^-&BRυVEG1!BPYr?A4BEujl>-BEo@Q2BBi)` B:T1!B4"js&>-B3eB+Ć B*f󶜹2"B)C}⌕ B)?حmB$B(+ 3+B%M 3*;B$2.>-B/29*B R]$ѡ:Br Bjo^!ǭ BK BSj*B+-BF|B7@=A =89A' AT#A:(V4,AdRMA } A]m\RAm`B5-A"ŋ>-A A}gAB=4Aǜd>-A.VI?A5Cf$,A|ib Al4(Ov7/ANk53+A-?-AԶs*$AY96.A/>-AzLP3#A%ix#A/)#A03+A[͆AmG73+AӐ AnY#AbP$Al}}m Aj7URAjp]>(90(AekAdWLNAc{UÈ=-A&eZkd$A&%Sk A$^09*A"/Ll>-AhƤ2*Ar/9*A2C Ha!AXN@g:,A I:aW A BOx1)AdbZ܉93AW,0 @9ɤ$@Sl$@#,%@;(V@UF<>@O_@wa_@X&@׷nxu3#@#LQ=6@~l *#@j&@]B=<@l"@24@D=4@̗8W3#@Bn,@B @4Y@m#V;@RW(7/@W86v")@xwy&@%l+=4@zh;@k;4$@$|&@X8 =4@OR @8Y;2@K&-@~= ]$@|m4}<>@y2#@wY*e2"@l1)@j>ȗ @ibx2"@hw0_(1@hvL @`WA'.@\6ȱ @U]U9פ<2*@QHpvu0(@O׀#@Mh)G@L(3p@H75Ȕ<>@H>8 @H3> d~2"@G_.* @E:@>W1)@=-Vfؚ=6@<\ih- @-@G#C2"?*184,??uVk3+?3Ӏ:3+??n՜ 4,?pTW?K*$?&}wŸ??s ?hYm2"?bn,$?Ր{ӧ ? m+)r*?Mw&-?ç1l ?rO<>?NMQ ? ŘC?i?T44禢<>?D³2*?7d@=?@ ա?K%^?eqz>4?);2?yD{q9*?x@yQ&?ug/d}$ %?o!=?k{M?frN#?`a?\^Xn ?[t[:?[@23.7?T]9*?S0C3*?Ob*?]} :%?Pu2*? '^5>8d >Ѭ'*!>$3=>;-6:>mX5->x'E> 4vc>+73#>az&,$>什FS >ߴ.J\ >/$  >6H+&&>& ׺ >1P")>I+EV #>][y01!>IƋ7/>Ķ;!6&>Ão|->ic>6 &Q;)>V:%>$n4.* >>I=?!>ΏQ"6.>yd$>\~ 9*>8R>VL 3+>C^9(>G>-; 6.>$+>3wxc >1&S8> #>}E$ >wf<}>uǀ >sY">sl Jr",<>>m6A$>->h#Hs2">c +g>^9U">Z"Ҷ0 >W&ɹ >Ln5>3#>K~>&>EMD5$">Bz>->@b:1>@?66>;4w|3#>99KY2*>2LbH>1N>->/")c>,ܒ*4>*[8Q1<>>"4-9*>!i; >bD!>Wa:>>4>P;f>X9*> JYh.'>d@'T >Tr%%$ >Xpge >^7=4= QA=%f"=Ve:3=/=nk z=<=3mC=oVT =O93+=eB>4=?+u =K=-=# f4$= Px==&-=kA6h$=lR 2*=G4$=i\h^0(=ap i5-=}.ʀ=53#=y+Q1:==y5%=pG=lKsg2"=f[%6=cxF64$=]rq =ZRB#=Y3 U:1=XXREjN3+=M0ni =JBԱ6=H1 9*=EB%3+=@$=<~-< $r<ɍy+<)WS93<߰q_ <[ 2"<2==XY-<ߑ9*< }L <:Nl&5-"<9i_:1<7B׍6.<6|)\"m=6<4|r;)m <Z@ <S`b1)<K!X"<gf <1WH+$<S  <)" <3+;8t;Hf=4,;$^ 0(;WZ{;ȡ$Da#;&p 8;w}`=#:;^T6.;@Z%v ;܇{=| ;|?;խ~B.2";j.rِ;2;ЄcA>-;B`*93;ƽQ%;[z3+;JY!;7E~;pi ;˦ҙ6.; ;ϓ; A:;s1&;)O;'H w#;,Fa#;Bo,#;&; ;1I.;9o6~k<>;,l)b ;&pٷ;+xX>-;2vMf; ;'3y ;w) ;q @4,;nȄk;mt]T<>;mU\;h92";aT3#;\Y2";W,;<;Q𙛓=";NQ ;KܜdД2*;Hk>`$;E94,;C[XW:3;Czkޛ<>;A,KV4;:TVH>P=";:El:1;6f*J;5y2*;0Fn!;.r\۫#;,&KUZ5%;)! #;(֋?;(eGP=;$!ŝy ;#yVMz ;(3+;r.`:3;B֖ ;$;}E@ ;v_6&;pY#1 ;EzV$;|_-#; {oP9*;sO;::;P :}t :NeD:tVRny :,;'u::I:ށ)%=4:ڈ ":c{93:ؑQ?:S@"S>-:.J3+:}9C>-:Cx :MQA:B^]Q0(:j?3#:De[E=+:"{ݬ:K%FM :2y :X Z8*<>:Hts:3+:31C}:1:[{&:F߅#:o`0 :g"-`,#: Z&: 4 :?!{I3#:ܣ:ad2*:w!#:~aX9*:~+: :sA]7#:s]C1":i/oȧ:dSk :b1'+:[QFz,@ :XK+:&4$:WVTE/<>:U_ :QVĹD :OD-3#:H׫ռ3+:E2>P 2":EO $:BYv\:A^e.&:@@kC :=4,:5.u :+j_wH0(:*{I:(d=+:(F:t4,:$Qpcu[5%:",L :~7 :Ѽ\:dS^|q:}o:&:]t,!Q#:{ci :1: :͓1#: (: O2: LH93:b ::!1)9F3+9"yu<939)#9w0ֽ1)9H_:19'=49hr 97og"9#䓋o3#9qR$9*Z9e )A$P9*9꣹"r=<9qե#)9>IG|T9O=k|2"9j*9(9@7}8#)9НApd<>9M+  9|WR 9(3l9ũK|,#9Qb19o9!' 9 d9*95x 92=9oC48a=<9i#-9"Uu49n,%9C*) 91s4,9 ֳQZ$,9v%Ҭ&9qi 9mq  9e2;29ealk 9b\%n 9a[9Z+X 9Yʱ9SC9RH5.M939PAge4.9LC~:9GCϻ;)9GƏM9F)A¤2"9E %27/9B/^(-9;x{ 993fr93BLz<>93(`~ 9)Om4-9'T%IG9#>9"2ydA 9!s(1)9!tގg!9+UZ9l}G=+9E}*f:9_?i2"9$:޺ 9Jm#9[<ǿ=4912*9jSj9 )&9 k/H9bI9_:O0(8ax[= 8V-8;ed#8::38vi 8Ph'8j 9(8~+G'8G 8֌8&xb #8C8% ՟6.8c8vA8VL 40868883ќT"8mNH9*8SrZ8Dv]ߔ9*8_*F!*8-98v84,8N' 8$Ia88tx+ 4$8[PRA&78-8xi=48x>-8wSUf+-#8ryP8nyIw8XI$>48U܄ 8Pnbw$5N8L?[r5<>8IBxz 8Eq~;48Bt944*8BiаH8?m`d"8=|=68 7#B~;27vPf7ޫx 7c[r\-#7 D,1J7dw,K7ܭFf.3+7q1$7 H͈7n[0 7#΄);#7l%b=67@b &79C+7!u7TʲFE&7 ;)7 .=I&7M 73o>A 7P{n74:17_Wz5-7Q|p$7hŽO7I#T=47|a^>-7G-7[9*7!94,70 7?Fq?#+7eTNR7t7AA#,2*73ۓ 77?<>7J"7p`N 7[j 3+7}D^6.7|. }^="7z^]4,7z'!E 7ynoI9*7vwC!$7sY#7oe,#7nGo&.7l_<47lF>-7h]A1 7gΣ6.7dU#0(7aG}L1*7^.Ѫ7Ywl&7X싖;9(7R`G 7JE"lC]6-7I C7G'V},#7FKR=7;UxI3$7;S 79A77?^1)74XVP9*746߰^D;272rdp2$7+5YΏ>-7*.I7/7*cA2"7*gA3L$7'}.M- 7%39*7#V;D#7 *D4$7 +Sщ7߲uHX4+7(#;7rt 7{="7^!9>?7 p~7 ^vy7n7c|]7S3+7l[5%6̸=<6et3+6i^#dA9*6Ŵsi01)60 `go"6br6-6fO#6qvhӮ 6}3#6Szۜ&-6,t 6l?3D 2"6'S#,6#>16ڪZ%M:,6x 66 6))6Vyv-=4686 Vky6C7C%6áJ$6՟6.6acr2*6BB/69:6H 6<a(6Mĕ6Q-$i3+6p~\3+6!6U 6t+3+6V6B6<>6S&6Y:%6S6H@ 6m_-6=`<6 "6w626s{6sL$1=+6pEGe+ 6h$s/ 6e\:16`!qW 6UU<;26T)6RN&r6N8aGm<>6J'J'3+6F~+$6<>m]0(66,`0jk2*64>EW-62~ɠ3+6'b)!6 <!6:N6: 6#8'6P6x#6#Q5Vs6>45-5 Ăi=5|#+$5RD)2"5p-($5cfjg5^>}935&~%-5jO۾ZQ*5琏RP2"5exH5~ֶ. )5 ڰ9t1!5q>3+54RFa>-5XF 5 \3e<>5գ'F5Jθ8a8 5A55%A!5m=2*5 n 58¨SN5:ٺ[2*5y4,5{8=9*52ï 5Q>45%?BV#!*5.|)5W#3"57/55 5 FF>-50\7\-#5-&5PK5 }#24,5_5 75A<>5}›ˣ4,5; 9*5+NfS5ot5fm‰n5a} 5D !5~d%] 5|\eS35vV1*#5t]F 5rad 5iL* 5dw;25d#p{Z45dl$L5^$L6`$+5Z>&5Vc q#5VSoy5U+@3 5EXS :35C{E%2"5@n5-4Wa$V_4ߵpYO4$4j4ސ8%4ƞR1)4hH"=<4n4$4{Z4,4ȸFCy$4-cJ~; 4EJ:,4qY 4{ YK934|! L4"˯_>=+4)1)46c52*4R:P<:4˴3 !4(0^}4&}g 4A7k5%4NV~p&-4^E-4& x4$4d4S$4,4 M4,4\-4}24wp;#4u%2"4rȄ3#4oW&9*4l`}k<>4i(ig=44h|u ؿ934_a>/4^\'9*4^k)4\۱uE2"4Y-ll8;34Xԁne 4Vc0 4FGq0=<4:s >  48ն:45n!44C/+6&4(nVg:Kd4&Hќk 4(]TY 4t1!4wK$4Nk4Ǧ~4,4S*"4o9&4 K<>4 ˉyS#4 YM0(4 Dx-4 y` 4237<A@2"3 o>-3HPY| 32530̧33_73#3m\P3-3ܗu90 3aD4#39\T=63t23 [ 933dnc8z"3o$ 3'43GG7  3 oϷ 3f ϥ4,3´Sd 0(3Q!>-3pUГ2"3T-g6.3ͪnq%3xD;3S <>3 , 3]|3C@4&3{x+-33aIBR3#3Uh35*43yhi@f=63cM0(3-#-3H\;!3M`&3j1;23,v]38Pg?0(3hW5-3ok<-32J3xn  3w~YVg$3v:oC 3p}F 3o1GJD&-3lV/WY3k]iZ 3Z723Zb.933Y舆$3YnyB6x#3RU<>3Qesҳ3Q礈S 3O]3I A<>3Fnv 3A!(r7/3?U-#3?s\ 3>6.3;6^5-3:2XI39*3/d"3/5S$p 3/3Hv$3.Wc% 3-byF3'3+3#`}1!3#mPN33{a=3d9*3#3Ӗ=3Pɧ3#3Mf 38k*#3 ~5]30b8A:%22"n2v:At2IM6.23:32 H9*2CVC 20V0 2ޠq<>2nֵ=<21LW 2/n2%K7,2۶J 932[vZ]-#2o 2Nb$2`˫# 2ZAˎܴ>-2OM 2ŗ? T.3"2^cEr9*2~(-#29Xd#2a`Y2Ao} *299*23e,H#2H(a0(2_ z2cב452}9e 0(2 O12b#2z}oG*2yܗ89*2xZw9*2tÕqEQ"2gpVm?-2g?[$3+2fD9,#2f?%e@X2f6Uik2e2d12*2\tF6.2\$2"2[p#2Z7V 2Vfw:2Tl/-2R}r2P,U&-2LN; 2E5L2;_'t4,25xj Y5 24J' 21A0(207U3#2-=>-2'`S&2%vz9 2 sG0(2`2ﶗ -2 Cvm-:%2b6&2-0+94 2hڣ-2SQ|4$2CQy9*14K+1A1><>1fӱ3=1.ڪ0(1bL\ 5<>19༏$11+$1Rc1V*>-1i%:1ٮ\)+#1U'TA>41נ/?<>1c%"1 ap">-1Vzr>-1n9I(Y1!1=}È0(1\He2*1 m;41%hyU&1@:æw 1'b1 (J6/1_ 1s5[B&1ln4$1mD1$3#1v"&1[1~ѽ 1)1|0qn4$1z?5>$1nF:13+1k:'N=+1hѬ/E2"1b)b1X5PwrX*$1Q 1PBsH(!1OOim 1M3t931KQ4$1E!I 1Ag i91>$0;21;v v0(1;J $$176!H,12;4,10478/%1* SC!1)r1(:%1#&SS1#QC>41#w>-1 jJ- 1 ~Oʋ1 /4,1sX$1|/ 1]6BE931 x_;41z0EOH2*0)HB#0 o<890uQd2"0R 3#0)4w'_ 0tِ5&0蟢a0@ >O#0zA>-0 1#0h!(Β$0D=60@p4,0B¾)j0>Li,$02 0&?3&=+0M2Ay1=40Q&01<{.9*0YOKYk0hXn0NTm;30bT6{")0ԨS>409 3+0m6^ 0"32ko:,0sR y5-0 'g#0W/Z\h 0*BL0p|d 0n-sbIy:30lAL݋ 0f|=T;0`J?iĢ#0Z0W[ށ 0N bk 0Mu'9*0J@d0(0J-t)B0GYe"l 0Es30E+h6.0D\ǂn#0CG?T=<0AD.0?/Ti9*0;'{ 0,<=0$<<>0$/6.0"7z 0(h}1!0^Q2*0XS"0lB!*0 #{!0 @Qq 0 HF0 9 gU;40 ]01)/!Z=/z}9*/~WM]9*/Lk/X $ /I9c /Lt /s/椃7B:%/X2*/}j>-/s1 /'ER /݄OwH*4/܁wct&/ U /_4]&/(&Mi/YՊ /o` / j$:/i /qW/u<9I;4/ˌ,%/?eXH"/r`=/Ol0 /M[<>/[2VK:3/op4//"_-#/40(/TH/×w4,/eD   /::3/qI&uC-/)1;1)/Yrƃ//%1-5-/7y/3u -#/ /\b:1/5{29*/[ʞX7//` /{E  /x<F:1/u!Wk /sMuZ1!/r'j2"/oY.;2/nؕeI:3/kـ'/d݉<>/cNpF/a/]ӅlRu2"/T$Ta⍲:3/Pi]][/Ps{VK/M#Q<>/F3B~#/FVG=6/BߖaE/Als/?Rѡ!Q2"/>9N%-/= )%m>-/6//o 2*/.C9$/-Ca4,/*`=/#t/1*/#oYP/"l Q/B4,/y!/Vܹ"/ ڬ] / M3/}#./Gq@3#.?0(.K~=6.\ zq2".::1."c#.Y6&.:(.&u{  .Be .8Й.ݏiZ' .8  .K4,.pC93.(#)4,. 1!.؜ ^a:3.UC.ϒޅH<>.%諈.Qo9a .RyH;2.(z1).ȼޗ=4.ǭ4,.Z.꘽8.E .R C&.b"s.qZ=tz.@\k/2".o0,#.)B*&.MC1/dr#.ø>l.`H+6&.Dt5T .r@.pΰ3f6..Fa2".x=.S .>.~x':1.~w  .tCZ$3.pf[k .kQ-3.jer .j >^*#.gMI] $.d  .Y<>e n$.Yj td]2*.Xl .XBl '".Pb\ .LHy3+.JF.n .B"0(.A^F#).@x f$.:63#.55)L2".4xt&.2YE1-3.0f,$.-$ 4;).+4"05%.*I}<>.)AvT.'Jw93.& #.%V.%b߿.$x%2".!7S.g$.46t;-3.$wԾ.2*.\õ$-.2Lé. [fA* .Ϛ .W:C2*.@Q0 .Wc*-A (2"-A3=-jIB-/j\>--/|̫;1*-NSc")-Bxh - ax-٫T}^4-O`yW-Wk`-Ȧ>5ui-ѣ漮#-$G56-ۈsn-ʶk -Hʿ9*-6F|-$v4,-9BcR-Od1)-!{둷"-P~0(-*B0-Y~4j2"-LC9*-MHu-Xi%-v@3f1!-&5B- 3#-zUFf=<-bc>--D--  -}sj -}ܛA0J0(-xj&v&--p&2-hk35-3-f,\, d1:,` ,U.,}Bn%.,CF>==+,^tR4,ܸe=",we[,s<h#,̳B,!0lc=,Mfj6.,ǼGGct82*,D?I!;4,u ,{%-,8KS0(,t.;*,[=",52!=6, n|?d",ċV$, Of3+,o2",K6.,E?#,LZi&G ,sŜ>-,,F4,, \kP, Ez*4,T<>,x~gܬ ,xQ4:,w ~,lZ\=",jU.",j$^y<>,i#2*,hМ ,huQ 3#,dx.0(,c@C^89,\A;2,Yk:K*,Xn+ ",WF<;<,V4;* ,Vfח2",U9Y>-,Qw;, ,Nhz,Nwn ,M ,M&= ,L_rhE,IGy9*,I<j6.,IrW'%,HQ :,,Ds'e ,CU,CR +",C^U͓ ,AQ܁<>,>s3#,8y,6#rL4,,36.,0ɏ1!,gOGv:,p,~ ,~׆ѭ ,R,#,ӿ{=4,Qk#,A.( >-, [c,fJ=",?v$+;AB9$*+S_p 5%+u;$+SvU3#+=SZ=#+[p_82 +b+Ka~6.+Ee9*+󻽏h0(+Y:#a +藺G%9*+ xo-+֦ q +ԠXvO#+LqqZM-#+ʽE <>+]+ɶؙ+AW̓+3; ,L3=+V| |`+}r`+{{.5-+z˙6.+kl+nz;.>-+_ [1)+|+*rP+q 3++-+N:3+ީP<9*+vHK:>-+Aqik1)+䍶9r$+x:+w/Pl0 +vBv&_} +ua4+usu~+tR +s\as +kNO:%+dxKmN+b7 K9*+b_Hо3#+^gF +]<+[xH#+Y%h&+HOg +AqJ[3#+9-+83Eq:3+50 M+3`W{3#+1 qxp;4+/UN5+.$1f+%Ҡo +%)1&?!+!zOXX+t;2+ׅ1!+Wvitv +>|p;4+{,\&85-+(!u-#+t *Q=T>-*&7*o55'z1!*j[&*=;*<*DZ49**G:*[d] *ѠkX"T$*8ټ !4,*`M13#*|E|4,*ƃAx| *,a!l; *Vdѭ&*Uk-t 2"*-=-. *ӆqA<>*~ 24,*; *Z3T *zxU *<{ *EHн#*! Q *V2 **{ *|q m*+E$*"Բ;9**+FŮ:3*K{,#*D#*y|]>-*9w"*ggx4$*.40*}<1)*{j4,*z&u76; *zAآ#*rL=*nWxd*i&Iy}*9*cL$*aOO^-*_, $*^ ɻ/*]0U0;)*[ cNh$*[o`U *[HPv*X;y*Sx1)*RC*Rv? b*>X牘5*9kO6 ;2*1Ed>-*0W/*,;R9***\ *)h7*'͇2"*#n *#$~*4*q:,*=&=*M3+*Rd0 *W73:%*:{(X*OX"0* ** S~3^b$*`4,*ec&X):=4)Pbd2")筛P]w2)'?~1!)[ ) );3)ZP8:)8$#))NL0)˵6|{4")ʠT87)ʇ}2")ɧ5 )Łg )Sz. ))-* )ã/D? )Tdr=<);xdp $-)cɓ-)P>l,!=+)h5`2*)@đ)@Ck)^!չE#)?Q)-.#3+)A}; )YJv )|*)Y1Rd)iÔ,:,)8å)_;2)ke<>)3#)y^C=2")p&A-#)c,&م7/)`#$)RvV)QV>4)Q,K&)P)fQ)Nu5;)N128)JG|T)G?zW93)F01!)Et+-m2")B\mm2")>!+;2)=g1 )-) (}=4);M]O0() 5u ) 3n\d6_>-) v8$)}MK>4)t|b\ ) )1A$3(<,b/ (N %$(I9*(,(](86J (cѷ93(meb0((a'="(\'A (sSl41!(,s;<(><c:,(mv͕׺ (QY4$(͍)(ѩQ>-(Zv`y (8T4$(k%5ۭ6.(r+Im(;Z+4,(ŸF73>-('v  (d9*(mT&(kV9*(~c-V!(pd[1!(XDS(W$>-(xi5-(!w(  (\:O2"(.]rs-(Dj&(0(XX$-#(rŧ~(4\ * (2)="(|ղO (~yZh"(~p!(}&1!({&c0((z&4-(vऺ=<(n%"(]Ҭ7f(]I\;4(S:o (R5mL>-(N36X(M'(D\ (CLgKB(C1Di (?rdb,2"(?1u_ (<@[Ѡ (5Ǻ""(4F]9*(.ab($a("hn(!h($( F:3(cXs(RXC(2( ba4.(br'K<=(6%(z|']D}'BӢ#'Kʴc@<>';4'팇"jZ'݃ '.L:3'ˣ\2 '>qa2"'y<<#1)'h>=;'ՠ_;<'ԛ4="'ks~>-'%I2"'ǹǽ="'gX93':p="'cF4:'i!['!'G-w1 '9"'MV="')2+'Խ#-'o#'#̧;2'p;sa,$'0:3' B=4'd嶉'WD_7=4'.x6-3'z3F* 'Ed'ėJ'ͮ  'o23+'t]g!'־b; ']0('yD<6.'ro(-0('ft[n2 'eo>' 'd>o'c<~ 'c@6&'^-'\K\9*'Y{yR 'X]:%@=4'S2}A 'PUY1T'B`x! 'AAS0('=H9'7  '3'AJ '0<y}z *'+x`r=<'#| u '"3Is#;';;'N'>D4"'*5'k'I 'Y5Y#'!dzZn'  7 ' 8="'p>-'4񺒹4,'jʅhL&FZ/t"&A&N^9*&7ɯ&}d!2"&WOj:&Z _ "&0w &{= &j/y:&㓺?RZT &rH&ٯD5%&Fu텣 &daL 1)&Tһ ;-&4qV &̊}ݗ93&DՎ"5-&{Z6.&>o\ &ôg\w93&T9n1&#*"&ftU3+&U2*&Tki9-#&m $V 3+&8~B^;2&v &&&ܼɬɻ=&f&X &}r;-&X5>4&b &;C9* &`4$&©j5%&#h&xO$L2*&tJ420&pSHSw:&my.SJ&h!&e*X&dӨo9*&b9%`NQ**"&`{&\3+:&[R4 eI3+&R}w&RVb&L&W%~&Jս#;&H.lJ0(&BR49*&>xU?3&;(g=4&5ݺf>-&3uHW:%&34.4,&34 A &2 &GM&~oU&g8:& V*#&4/&s>T0(&zLQ&)4,%2"z % =8:%V %Y~$g; %pv?%M}zB>-%y>>@ %$EW4$% N1 %=l@-. %?kͿ%ۄ %Ra%J03#%p$y:%x}5-%z<,0(%MX %p˦ %$C>%(.H`T"%ۼ%c9832*%w\x%Ge]>4,%lyq=<%&G%Oӷ%%fb#,%cc=%K=>B%Qd9*%he;2%}S;&%{ce %y5r%wxq0(%wJ0%m ]%jQm %f[4,%f%Xķ$ %R;)%>Db%=B`0 %;%t?:3%:U>-%2i %1i)?9*%.91^%)׻Ǒ;)%&J %%HśJ6&%#ƚ$% ]{%{T<>%kܬ2% wJG,7*4% M3+% 4A-% {l<>%Ji$e#%Bį $|)+ $Z< $5Ym3#$  $mR.c $=w $ؕ 1$ٶ $.s`$KY$$Duj7/$唄* $݀}27'$gj@3+$%q/$e1)$x,#$ʗ $շq2*$Y,d $ɩVs-#$&4,$MH#$m0$GN $ī]{$nMO?:$2"$b'`$u6$Y'<>$ :$G!\}#$'€ #2$O5$ܕD4,$NO$AvՊ=<$27#&_$kK%:%$#~<<>$*Q2*$O|2ڟ$2gVT93$*u@@$ ) !$~iѷ2*$}#$vU3#$rc`;+$q $psi8$oS ~'9*$e&o  $`j982*$WED$P</-$P)$m $MPθ $Jx $Ici:%$Iy%-$(n$& ;2$ᮐ-h#$HD>$>0 $$Enza&$ @CK$ ;#2"$ :$[)$h$$\^u#y3$#*'%.2*#2;b#Z!j3+#C_5:,#J6 ##g2*#A<3+#,F6F#GBU2*#0(#ܲ S3d #ց # ##/<>#jgK2"#X:֤;2#RBp:#4 h|#O,=E:#T;O#6.#ZYd!#M.;##4G7#7)e#bP892*#UiC4$#[l:93#`@&V #qV5u'#B#S7'#P;%0 #$4ܞxr7# ##ϝ$#tг#9*#~U:M#} ]4,#|Q7$4$#zɟn#z6"3##x4$#sa6 #jdn;2#iZ)! #h9*#gi<7/#ak$0(#\G 2ɏ=6#Z<(;3#TJY-'#L&7l#K 9",$#GcCq=#E:3-#>8j^#=B2*#:66.#8)#8jX>-#1tؗa1)#0,$%WP=<#0O!##-5R2"#'[dT/2*#"Y$ *#!?nGy #^ѓM4#@:,#fIw#%~fi5%#98$#.04m4$"#9*"7v/6."* X1"𚴥 ) "퓗t 1!" "1O"&S[%"ʫ$9W>4"<"|5 w "//=4"׵W 9 "֩i*͒4,"ք+y4$"'L93"Fk#*"^ Ņa\3+""&)  "ck:%"g_@+#"'^"j'q$"_";W3+"iVu "X@/=4"3 y93"$ͦ$"6ֹ¸>-"|m];"ּx3#"hK5,$"|g~W\=4"|8yo#)"|#߸ut "y`^5#="u8<1z93"mIyx"l+p "k0&-"j8+;&"d9=ށ "`ZZ4,"`Ds S"]p}#-"[Lp "Ykw,n<>"XF/6."W-#"W ժ=$"N[  "LV5L=4"FLDa%"A|+.oV#"AUu!*"A.'^9*"7p}-#"7=p"6ɣ۞4$"4H_b:%"3D :%"3$烢"2U["0pZ,o2*"/c?#".8Ӎ<>")M~#"#J^;4""vA9*""wP`<>"gB` "Y^i"$@[" &l3#"7"EG$!v$#!E'U*#!ԄH!!"&;2!V$-! ?B !@V>SQ>-! 22"!湥f^ 3=4!v}D!uG+$!ûğv1 !äU;S;!T9&!5\L<>!@[b 9(!4V--#!}o;3!}OE !}KŮh:!|4m&K_!tTd*!o3*6#!k[(!j-h="!gV8x=v R,#!6;2"!3V3f !0/X7"!.q*j4$!,e<:!'Ӛj&4,!"AKS"!!\~j93!!!j֣_=6!m3- ! oŜ,#! I4,z>4!qᝦ=+! =" d1b>- j-# jx~*`# %/9* ts؃t *4;4 k  xS ?{/ ^$d& ՜O-3 ]2 o˫;2 ҳ E   96( ;) `>- nR CxVo# Lf knG  }hEv-# gFfU=6 ;[X  ń Bh a֌ M wp%j  (w\%l  # F%.7 '~uE93 bqHC3+ t} `j0( = p)NA2* ky.y  iHcd4, e d ^ _}74, [Z&,# Z& Y[r_>- XMo' U6t =9* Tͅ RTIWmB NK5G>4 J{E9* HjL}8 F*p" EǶscx3+ E@#[2* DJXUI0( Aoo6. @4!1! ?7gI>- ;ƒ  ;ܢ#: ;u3:5% 84: /+$ +Dy5% +k1) + )P|^< 6. U+;) 5B. >t~ac& ՜bU0 6OM d@&Ф<4faa6-hVz &^\S9*[hV  !1Aʱ~93AgP/1·m6^3#x$ ."dςX93Z1!9ކ09*li0pg?ۀd03+\8 n3#3@G:9*-ֱ*0Ql3#a-V@i9($t63+"26+1!qf]z ӣ$a~v啄h>-~XOO|="zn !z yF y;q#xn6.rF3#jֺl!93iǙy<>`|F^1)_^cVi ^p93^" $]p[2T7'XJ-Q!*WPz%.V.6MT|ł_P'%?PGC~:3E!*Bt_-&-B9k2*9t9-.Mc'7!p %}C=6$mjb2*#u} .uIO VQU G]|=" X^i X +- P"h6D RÞT|&r2` ֐t<>hj%5%+M49v-5Zc/9 C? hp=4$UK. },$BBg9#) &+u9*1#+@r8>/ޥih[:B-"$;4P!*f3<2"&2*~Ω,93ZK1yi"fӮv:d y ǔX^84,? D&*'>4A9*jl>-4px!+F R v9 L?3=N&Ņ|>-uDN:1Kl R%~n rZwl 03+vuLO] s2(+St9*nf4,lDN4"k Ρjc 6.i7=6gK>-cMl ^r#[$j9Z㲓!R WUp{>-Q!@ r3+MtO f!+$L)b;2KB3-JF6q% E#*g <꫙T&:Dl&-5w0(1 k:/ +5\A1))#;#"F "Έ }W7<>-0 >-!x=4|s,`CY/   4 ! ]D &e,l&9h=6Iw$$[яa5PK * g4g P%kcO 3٥:%레ӥ dzVp #=l)m֝eea7/,; <>Zx#} ȝ4}:%ƣ@2*‚3(l7/}20(o\3(=<21]; H6( ( Ϝ{= j/o)=+ji FX#/ r>- F)cd93(I+ P#|)ƒ;#Z-$Qu_,#2  F |vHT,3+wl  sT_s˭>-s"tv6TʈĝYPX>-/o>-& |>2"'q"-μ=4ްXN ha  h t)x:3  %nw"K|#nӎ$&?9*z7'9729*p P"<3۠ל1)}Gq{JHU=6t߸ ].lSid5-iś~0 iIhy&gvifŎ=fPV>-c{_c%@:1`Z>>-^r8Wz%V Xo VXA/'TnUR2"J3u|HPV3f3+CF^OR$A@t )2*@2*?xk=uK#>)|793r*9!;'ւЯ $ [cG9*G@w* j){Y E̠Z'r/t  2^\T.ӕ ¶=4#B>-j;=6+\89ۭ. 0Br Qݍ ߳.&3+_{Q(|ʄ3+Z a93ۅ@="_@_qMd˶93ѶA9]9*4g'q7/V9o4 %ڕP:Û>{7'tǗ,=8$CǪ&-V '̷7/?3 *4﯑$$="T+# \&:F`T-=6nO0(I p:bW74; G&- y#} WFv֟&1!-WT5% Y(9*r$~Ym)Qb }'9#{{hx4$zCrt(ftY.1Ԉ'=4iFw09*hEq3+hJRpV4,gZ0(f7:e,e:6.eMט!c,"ы!b\b6t1O7/`*z _9*WNbwU6.PgvR LJ'`|&J񩑻;<>IdE9*H.k^c9*DiBiDfr%C?<><}/{0 1&(d3#*+bw1v%)`/ %})M;&#- 3 <> .Rf3)r !.Z19*D  ]zi: <& K%=+M:3ڢNlqy932W_gұ,w3+r2tkd9.t9*ϬU :1&md 2"(A2"gUe0(rjKhJ-jgP9*]!&"%$wg?%$8I.A Q$̴4r }#2"j Z=4*rzK1!b/*0(+V#u$-  ;>-ܱeFCp ~%T-|܉:1pu<>p\y Do:p8:ngY>C#0 gA*>g犝Yɕb%{aЁ/#^7M2"VN9V •[2"Q,#OH]4,Nsk$M6Ӝ($5-EeK C?.<>CEs]}:34ez` 4EH\0(/L1!#yo1UF})zm;)6 5rf&o00 ,<>BF;%>3#,1)mJ:([$b-/63.Dė :11>-+r3#onWL9*B>qږ4&Ȇs]T=4ս똇3+ѽ`1 n0v ǩ>0廒ܢ2"ٰ᭔->-")Ȍ; ed  _X0({sL:KAĀ/&>46.OPC#FgZLs~ Zu93!A Tnt03Ws|)0(L{w.)^9*p>-7hOy$x sߑvr #oTuž>-k}vjÝ,=6gն"fBq:d$g# `kyZ2"`9O9(\|VjXe2=6FL6.F=B<>E:m]?zM > #kg9b<>8:2V 7n5%6$5`|94,3G:39;)3&ѻ{#1^U T}#0k]7/,&2>-+2jůeq2**1Hy @F cg6y89NNk;  mF=pD4=`6=΃ 7̵$HfؤWCX  71j쀰 4,  \VC^ڭox`$_# *"۲LL0(-P6>-ٞV*ّ[z/ dM=<NO{ ҳuuyd3%U%A,#vJe!(2T k2Cn>-г F- T#Xt0(D5q?j5%+=4"+PE=>/Ećp/dWjGV3"p6b4]O9*z?@% M[rgpʋKM+gj"0s,{"Y>/'Q`f4=$~0/"Q5|@ {Յ*bNm0(` _FRle^w ]GS ZD[LJ&Y8XX<>Xh XNˆ XUYiU&Xlt<>Q<8E@9*N#="K'qB CC#,Aw.LJ ==!=<9.> 5Ԅ;X$5*Dv 3=S=60lɬp*/Ps%mD2="kOZmj=61!u7'MU 5[73#-2w  ezFn -9->tf?[) -z:K*;g+i\^-5-zy*4z)>=6u˄a  Os:1!Ԭ2߳63+܂r=6ƭ:3 $49* 6.Іn6.ˊ#c}=4H%)^b4==w"1П#,=z8&}9)#QC.-6.7@ ,#J 0 CrH0b*$C( *L"f4S ¶&3b5<>D"^"89[%89yRMsvD!sB 0o v;W3+nL"lFQE)Skz:2*iUѰk=4fI#ԥ6.ey2*^7%+$UyT:1N/b>> J\THIw5>-Hӵ Uj4$C 0 B003#>V-U >5*q3+=Ѫs<>-Y-::;  5W3+*:(E cf<>2UWメ-0 E+$vҏ0x*1! -|ߚ :#  _d# Si-#cbp? m;ΫRvq]|L 90<>Z2""wv>-k=6Z15~Λ6+0(6 WhD ܧ*! Z] o;3G,& hSZ* ƞ=+Ҡ¼,#'(R!Q/ ?54$  sM5%,r}\!=\FGD}z=1!,=6;^::(}^}ي]93} ̷|;vxw>-p Th3#o r*]; nN*)=<gON f)ພ _1[Z$2c R4JO"{| Li FA !"E3F2*AYP6&Ag&65OY4=4>A%`2*0--+fPV6$(U!*' 3e]#z12"#:"ݢ KJ_ċ=4KL%.+̛p aˀ-r>-a= &  r4_&HPC-39*-u<:̺6.dXngA<>jo\j#o9 j6,+5p"6&iOkhQC{gm7b>3=<_Uؕ^9R"^a{ȼ [#X]4@T4,Uש@eQ" L0aN DƗc AYW"0(@Ek:3> /{:1m 9Qf\,#&Ba/=.2*LN,#LW%$ 6@  gK  ũ b\=  K98y "ͼ"?f /:De"4,Φ̢S>- w0$~q_?6-kC%z:N2"$>&ް0q QB/#K[ fuLZ_="ao}&!f;4e^$ >4i24,i;T|=<bwC>-^@;X [n Xљv93Mr6=4$J&=v)=6I=g0<>C\K5bωg=<.^E=4'DG8 ;M;=6ҴxJc%43+a%Y4$rC3:K+30(RIUr )d! =+H6&-_=J2"Ui b93ͅ 3蘲3+ ޢ8~G];2ᗩ3-/鑈6Ɠe>-I,&C<>ټY #m>-=48#נ0M1!WxŒ ԻShk?  ªi<>%>4G1:1X2` }w<=W5{$cSآ=<& `XV>-FeF=4PlX cM L{ !<*$I~7 *9 ^0AKC1M2"8H^=6CDap#_u42*N‹&>2 Q<>4HZ'-#2Wd2*~1r/ { ȶyI(6.xa@*:1x`rjB u wǖp]o%?$ kW& h74=J:p$e2_s;<anϳgu<>`,:D\х4,Qanv_3+:-* 8uc-a 935of#1l\Ʈ3+%L4"3YCJ1'u kIR>-~9*y7e9*90ݧP  :3q*u21!O)gf ;$-7­e#Gg!L+<<>IxFUR Rlw,#pW$*6_(zZ _&-Z|2"֞).2"[zn>#Ϳ0Vyʴ[ &2"ՔҎ bR-<ƠG`4$ő~*"UU"X_I3#`.'1)mș=4Eiz]!x]193B=<Ʊ/CArT7/m]3!Ԑ,_1=~ZԌ*|4E:qɐoiC%oX=4j֐F>-gÿ>-cG1!^803pg Zʧ"(W1!R+I/ Hk oE0(GGnT4$@S>J5 ?z'B"9q$4B ? /vLbA-4,+&[!}k@dȄ$]t` !=4 2+!ziU YW  ){( ̸U3#sF7H#k ;hQX=<sJu,1)DR11!!,WLd( ɣ9\0=6L9*7O0 10 pDkU;)hE⿎2*ٱ8Qv5H#Ҭ~20(Џ<;<> |j 3*gGwi>--EuL6.k?' riNR-ʥyi W%?lc8:̆ F$+9J*:+1)$3 t[0(_ֹ[[eH]d "$W S;)'n" =6eh4,q6TWa!|59&vnS3)o 2"k4,ff}uo5-`V o>-_a/?$_Vc_#SsWwFRWDGW|0(CB%> -<#7Qe-#6鐥6Ge|}d +xU=*g *ޫ4$'I5:]-& W?"#RQٍ# Z?*b ^;2"`Y1!IRv9H.. 13#6wkIl!4$J7BKW 2*U:7.e6&w31$0( \)]d <>9*y $> 8N r~40(& 4-m?}-#}=6|v[Nh6"'ﵾ;-<>i#m V5-~Ơ `$-`>6=4\'h0(&ˆ)!R 15^M^W0 TD5%fF1)2*:1a$č i0C1@Wh"+\mI 4:%#|ߖE; z\9*lCH<>ja\a>-i) 7 d,vZ_޲c]`#^BJF#ViT% Oz6.M'EQQIc0?׭:3Gb>#=G) mG ?hy=;<.>-7b!65-$2 4ʠ#1Բ9:,,!F="%6!F2" ITi:,?ea /QZ aë&82H& 7ʫ  +) !a  Ӫ qN@5uȳ1!=<տ:~l,#tb$=<󮲲d GRN4SK1)H[3+0(p%c;9*$-6cc#50@%93o4|]!ЀpDfaWb<>J(2"ei*$ h>-123+q \v7/n)ʖ B͓<>| v=Yֆz7/;kS LF6& H#;sy U3+n/;  ?[)9#:3Xd9*詃zAj7"qSJ3+ZRZ=4,k89&}9~SQ }zUg |NQW6.sHkZi>8 k/N<>jiA8gR=3#g݊ eܛR5wdCL)X+apBgQ `K1B>-] ʏZ#%@3#X\NwO WvSW#WR7M2*U*¥2"GoIyL$GElVT4G.LT2 DE:B|E$=U0(:Zgz9[{5ԓ:3-3yjZ-Aձ>4)PfJS (Bp ػ &6<>!f*s0(n~c-' ͪ HQ 8:=6  x.   x-&{~vY '  /sg|18<˩}2*  HHme x'JZ9 -fx=6HTe"-˺%-3A`*"⁝4C L?Zp ?d>-߷~:A# =+4,ڌ9;2ڊkf#DbQk?n vB93Y-<>t(=6hXj; f:1épz:X4 n 9*\u:%L8ct2*h/7r5O 9*7qڲ _M0(\3+^Ֆ^0(-?O* N]#L32dv<(d89ӱ *U*[<>{+"{9H$,#w  w)ebJp?]AnM6.g YcvV->-b#M (0(_hiG™2*]=F$\ =q3#Yy=<WQ}|#VCRϼ)x QtYPd L}d K~5%Js/ Hþra GD FU!*EwQ5893EudU2*C#H<~B{4,;г :U49*:ڋGR4,5Vތ5k%9*/k$*,O(Fđ ;(:Ou^$3NJMZ4, =b   L r& 6Zn&  o>- pS F   Qjqh4$ ]]ڭ14 H2|o; ֜@  cأK qR 3y\ \F=4 % G"0 ÁX XB  @82* T!/* 3<B  .У {* K8 sw/ qg1%*; ЯYe]>/ 9`,v ն 2<> yZR:1 7* Hh.* _Qm 3LK  o`&p   YE e{ PcL& 46OF2 QC; ,dl2* ;Q! 7yq_/& | \h fj] =  f=!C* eĚJy<> _h9M  ]8?r >- Wמ$  U# S;L<1) McZ>- Fd*4 A;bqc*$ @2&p$ ?"R-   /6)2f3+ ')á2" &|SO>- $Q(=4$ #Ks9* ! !`Lt4 p3# ؒ?٨   A9* 1 Y=4 Goqh$3- ܒ!dm ]^A<>  :Z ϧIV-" 4&/ n\ 7[1! ?;) _0( \6Snm=4 +7-3 lnZ Rְc=4 |ֽm}S  Ŧ*i<> ܍qأ3" ܇ ~ ٧| ٖ;$M HD_;2 >hW:3 @TT$ /'3# 6c: Rl{<; v"4<> 㜅 HB)  %x[=< OJ ooG4, ~2" aM5 n K y4-4, ?$ ش# Q-in YD=4 \ 2" Z윝@#-# :9* $& }&Ny  #;9;) <"č l8ģ1) c \3# ai:3 U v0C9* vf&T<> s4}P=4 p*.~ p#:4, kж$ iÖS]x ev 5% afc) [}\ Y:'=+ U]H1) Rr#ѷ93 R&PV  Rӓn: Nuv L`v3+ H<1v  AXɼ!v>4 AQcE& 7Tx; 5xа!# 4u[N ݘ= 15YDu: .;M=: ,q ,om[K   (x2Am:3 (/R& I^u>4 o5 _?  :, TV<> Wͪ6(#) Kd93 fm1) 13Hw  I^ H8Ii3# X o X Lr*2" >1  I"* ϖC4  1) p3# <&׊4 l`$+ `2ػU9* UI>f "P`2" ݃Ǝk=4 dҵ[4 y`-0( ʃGR޶>- L"%a2" Sd&5$ 6L ßO v{lF<> Eѥh K&#0( KЙ \+-0( ij8ty  !* -D h J4$ k+2* 3l\ ʽ(0c>- jg n=6 .P/ ~t% 3# 2E=+ < N0)>- [z  xgI  C&  ~l=G:% v7 uqҰ" udPC`=6 t0;2" sS0!=4 oi, kΏ%m gMTf~ er>=+ a,!=6. `@C$ Tj!?P4, S4N]R6. P2gV: Me@ M:H#0( L0( I/$ EAslS @ps 4, @3 :3 >f` 8* *" 0fA -Ix  $"-3 #ݜ>`+2; "ml6 "+>- Z63>- a  eY9*  =6 uX;  ") tǟ G<> q@& "F7 >- ]J"] O^4$ =\ܸ*  +M=: t>- /  lڗ; yD  yB > 4 "}T>- mb_( LhNה  sV  ;H &У HHD!1) _ᦜf;) b( d [J-3 m3 >4 KJ  "u$ *n   u24, y |#R; xV|ݚ]$5 nr-  mFo;2 iw5% f.8_3# ew@Z>4 dQDxB[ aIJ/rx Xڼ-.$ Uqp=6 TX63# QPH.3# PT:,FJ  I8FX GjS-93 GF;# Di/%^4$ 72>d:1 3!O42* 01J* .ap& .[f0b* (oL64 ' &( "Ƴ: ;2" =_j3# 9r =6 Zj Kߟn<> Kv_  .];* MZ-3 $=y:c4$ OѺG  I>q?l  (d$ `1M\9* D{!g * ?ZO<> ck 8k3+ QdL$ NZ:, ^@=+ ANDc&- 8-v$ |JD- LA*4 H^':1 ڥ  {Nf  Ι i% ֐mc ՙW492* hoڱ:, ΚU+^Tu<> VI\# 8\ =: +X3+ $6:, Ĵyqz2* ht$ P:1 чq + 8 ڐ0( Q & 0t6. [Oj93 ]y;& #͹ 3# خq-# |=) =< R1H73+ md  0 zPt  w,"Ξ93 wTXUe>- u޵u7J! g  f m d1_ cG awry:3 ^eS; ]܄  [>5- Y!- YQ3%1! Y;K VB# U8f3+ OyA O?َA N}-Z`# M"Wu M-iU K$mF$ KeLvՍ J/1) E,!噧 CZX# Bp gm:1 B6. ?6P{R5;3 =3- :O= -\MV +j (# (D,S]3+ &Ƞ %*}0( c# 5>3& Qi C2* WX:, xCp; Q'&- \f>-cJA u 2";k{\n Ӳe  <>MR89*93ϊi=:3BA>-\f1!Jr!߷[2q.!*ޜ6GY 5 ک(WD"3KPpQ:3 =\:%ҩ|XW}yR fk:ӯ *EXNV7/(u =[0#Fuv>-3Ru611)+ɠ4$_|;+,$p,u{ S 35:,4f!Iv  w v:1h`&-s+i2"o+83!j(D{;9g))T1)gu%"gj4 bso|1)ars]8=]2*] ]J3#[#J"Y(3 U6X&-T%CۼL K$,IBy^j3#I`P2N1!Af`c2"6>sǠN(3#4^WJ->-)1)]̂'V1v&N_A0 %9>֓2*##y !Pe|:3!: 9' UC9(wuc8: "  G؂  Hu* * v5`G!D1!6:3D u'1OxBlO*#zJY%*)#7/4P ѣ >q,%Z7/i@_S|A&҄$-[1!ʃ.!{ ƍ.SwZ93eйi6.IJ9_c; o6.ǻCD ]v#QT/!9*wQm#ڶ #2lTb M ) =B{>-މ @$O6.u?Y1:R:^0(N4,\4, 7ev ~Dbn|eVLc ~p# ~7B6r! 9*4 , `Kp<>+sew*ҰLD*/?p y;-* g^ $ف:-'sPZi9(=k ~MQ 6|W&vg<;Ak!@(eO 2Y[1!G5.| _ݯI'ړ!<9$+ 73H-&΋3+.D4$X5BFz-#F;c<>؀A=:Ԭ 9*pD?&8~:or]<01y"y}f<>q)+G3+|NMJ~3+Ѳcx3#(;q3$U, /4,_$$=<cvbK!/Ւ1>-$/N_.>-=<>~5"S.&}2ڹA {%[4${#txV1 q7->-k<1)kdq4,dZJA^cJX="Zqhˑ_4,Z@3 #5%Z^:U&`- (KDuv!If#>-H+VU0(Gm"WU4,G25#Ej8D B_t<AC= A) cv>-@-q@<>@5,?1~Q@;2>fI >af6=e45\~#=Y :1=TQF:w6b**"5OA7="1| @+ 1z40B6H$0=/0(-0 *YT&($sf=; &9YD~ $(g ^>C ($&̯j>-X&4G- O '\=4 `:% 7.1)$@!4YO4$~Vr&<6.iDKrH=6 xCQM-":%~ ¹ >-'ܙe6._7"gt7)*sscqڹĕ=4|(;-}qr=6r-Q2c>-/thf: NT sk &}X&&#{$k>:1{Jߓ 9*r/J "q|DW*o~Cn+$m-qP1!j*5T=4fba&^Ej`Z!i;Oհ${"N7-8P5%Io-Nr-#HB;4,Do.<3+@]at>v m; ;Ԅ;--;`- &xёݕ&M 9*% $4,$l;#8xY0(ǼP0( 7'tYY#8u$ m'c"9N_  h  4̞3LY ˷"9Q#) *jcT40 |B'ѥ15#~YdA3"B$ tPb=6 z0UZIҔom=t2FX> 8 ؊!T 97% 4,M)<>yK#~z/d' zLO t+=6t!pw r)mHk0 m5=r&3"i1>-f- 0(eh`l"`fJ@&_3[ [3 [[>K0(XD3+UȗZ Qh/ -5-My[93LY* J69n HG+2*>\<> <;9V &-6A,>n;26.<|#1*#"fdu:;ϝ1)zXD L7a3#62V> ^ K CZBQ XA 1!t* 0 `V[")HZ'$__="32>3M:(t 59*=s:@Īg  *0s5%׼Y"  ͞y%ʺevNʊ~W=<_5T 2h5%T%yb Lۯ)4,)[ 9*Df=4"s:a 0(b="72"\Y(k:8ųck+b4:+L*60_V(z2*-_4ݞW xL(ї1)1&~ ݾ-}I/6.zO zse Er!x&K*4&t šv3+rP<=4qqZ"n/v9nb4A#lMIlk.i7i{;4b#$ "Sx2*>`ni<>7kA#627>-0 -#.ާF/- %4'E6Y3+%4,%mhS*#$ւ<: n, w ${Xp9*;$|g O!#OM0(fSU7/ .1 '$ ^xXu4$& x4,} Ef ¿2"uyǚE^  ob}uȨ ͊)j#vHY*\99*9ej2==6cQBf=6C{2"4$Bj+3"o=4ç>*? );)B^ Jw;4R_ pC-#$.nWKړ9*^~遢&M}1)<S?Z4$ &|6$ :3T*,$}uAz!V6&qdsp.Ep"5-oQ mgrS_#)k5@ ftgw#b3:^8V5%Z9-8=4XLUR=4X6;3+W0^7 QX `X7'NU(*MCUKҝƹr2"CǟW^9*@n`;4+255,?#T>X &(:gDd;4V}K SK_:%ivHr!R'j2"1{r"{93x2֠߻wy9* 77/<;Jj|:,R+a6zvQL,1)E/8p8="U$ :,ն|< w:"lU&$ !_=4,X"r4h5%ɬ%'1K6.<>zp +*ǐB">-Ruyr Wu[E a\7/vd-3lccb Ե!2" Up;|GKAX;= BY ָ߱S4,7o9*~[ }7zp9*{zG_(2z_I:1r nwGO=+mšrr2*h!\Ifv( [|.)Xrji3+WP0:Qrݣc LS63+G5)!G~,) E-ӧED7Aa+>-As- !@;8?7/<7GUT;<;ل38r4@0(60(58*d;,3+4NNe37+Q/'2TF0k>-,U<4,,]Y@9*("&=6% "f :Ma=4x _v=6 f\09* ۅ>- ; K,#QJW s3Qz:0P"hX r*L3+cF=6/f*U * Lt3+ceȆD%,84,zEU4,d] "^)v zǷL XfRPm2"Qz̭}4N[ѸV<#7&J/9*Wـ"'PM ^6Ӟ ˶ 25%43#d)ۣK 2*\Ŏ @WKV ]\#S/0 خ&&-_>-<:1ʒo!)9tT7nQ:y;2-c#|NK3$zhȭg#s =0o jAUS<>ix$D*i+12gtT]J$-]&Pz\$E`:3WdqW{? OyezD N'iO2"K.6.J'eH~'3#Eng <J(!#:EHs)9*841'>/*pH< &c49{8:2a:3b ud OuY1!/Q,3c33-3"7Y :p:Y-A$ vR zť  U,$TDS/ֵ$,tochessx-1.0.0/data/help/about4.html000644 001750 001750 00000063533 12076544175 017563 0ustar00niklasniklas000000 000000 ChessX Copyright Info

QuaZIP License


GNU LESSER GENERAL PUBLIC LICENSE

Version 2.1, February 1999

Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

[This is the first released version of the Lesser GPL.  It also counts
 as the successor of the GNU Library Public License, version 2, hence
 the version number 2.1.]

Preamble

The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users.

This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below.

When we speak of free software, we are referring to freedom of use, 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 this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things.

To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it.

For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights.

We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library.

To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others.

Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license.

Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs.

When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library.

We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances.

For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License.

In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system.

Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library.

The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run.

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you".

A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables.

The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".)

"Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library.

Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does.

1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library.

You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:

  • a) The modified work must itself be a software library.
  • b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change.
  • c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License.
  • d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful.

    (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.)

These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library.

In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices.

Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy.

This option is useful when you wish to copy part of the code of the Library into a program that is not a library.

4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange.

If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code.

5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License.

However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables.

When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law.

If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.)

Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself.

6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications.

You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things:

  • a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.)
  • b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with.
  • c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution.
  • d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place.
  • e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy.

For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute.

7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things:

  • a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above.
  • b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.

8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it.

10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License.

11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library.

If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.

13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation.

14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.

NO WARRANTY

15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

END OF TERMS AND CONDITIONS

chessx-1.0.0/src/guess/guessengine.h000644 001750 001750 00000035401 12223260306 020212 0ustar00niklasniklas000000 000000 ////////////////////////////////////////////////////////////////////// // // FILE: guessengine.h // Engine class // // Part of: Scid (Shane's Chess Information Database) // Version: 3.5 // // Notice: Copyright (c) 2002-2003 Shane Hudson. All rights reserved. // // Author: Shane Hudson (sgh@users.sourceforge.net) // ////////////////////////////////////////////////////////////////////// // The Engine class provides a simple chess position evaluator // based on negamax with quiescent search and alpha/beta pruning. // It is used in Scid for doing small quick searches to determine // which of the possible legal moves to or from a particular square // to suggest as the best move for faster mouse input. #ifndef SCID_GUESSENGINE_H #define SCID_GUESSENGINE_H #include #include "position.h" #if (QT_VERSION < QT_VERSION_CHECK(4, 7, 0)) #include typedef QTime QElapsedTimer; #else #include #endif namespace Guess { const unsigned int ENGINE_MAX_PLY = 40; // Maximum search ply. const int ENGINE_MAX_HISTORY = 100000; // Max accumulated history value. const int ENGINE_HASH_SCORE = 100000000; // To order hash moves first. const unsigned int ENGINE_HASH_KB = 32; // Default hash table size in KB. const unsigned int ENGINE_PAWN_KB = 1; // Default pawn table size in KB. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // principalVarT // Stores the principal variation at one search Ply depth. // struct principalVarT { unsigned int length; simpleMoveT move [ENGINE_MAX_PLY]; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // scoreFlagT // Types of transposition table score and endgame recognition score. // typedef unsigned char scoreFlagT; const scoreFlagT SCORE_NONE = 0, // Not a useful score. SCORE_EXACT = 1, // Exact score. SCORE_LOWER = 2, // Lower bound, real score could be higher. SCORE_UPPER = 3; // Upper bound, real score could be lower. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // transTableEntryT // Transposition table entry. // Apart from the type flag, depth and score, it also stores the // hash codes and other position values for safety checks to avoid // a false hit. // The best move is also stored, in a compact format to save space. // struct transTableEntryT { unsigned int hash; // Hash value. unsigned int pawnhash; // Pawn hash value, for extra safety check. short score; // Evaluation score. unsigned short bestMove; // Best move from/to/promote values. unsigned char depth; // Depth of evaulation. unsigned char flags; // Score type, side to move and castling flags. unsigned char sequence; // Sequence number, for detecting old entries. squareT enpassant; // En passant target square. }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // pawnTableEntryT // Pawn structure score hash table entry. // struct pawnTableEntryT { unsigned int pawnhash; // Pawn hash value for this pawn structure. unsigned int sig; // Safety check value, to avoid false hits. short score; // Positional score for pawn structure. short wLongbShortScore; // Pawn storm score for wk on abc, bk on abc. short wShortbLongScore; // Pawn storm score for wk on fgh, bk on fgh. unsigned char fyleHasPassers[2]; // One bit per file, indicating passed pawns. }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // repeatT // Repetition-detection stack entry. // An entry is pushed onto the stack when a move is made, and // popped off when the move is unmade. // struct repeatT { unsigned int hash; // Position hash code. unsigned int pawnhash; // Position pawn-structure hash code. unsigned int npieces; // Total number of pieces in position. colorT stm; // Side to move. }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine // Class representing a chess engine. // class Engine { private: Position RootPos; // Position at start of search. Position Pos; // Current position in search. unsigned int MaxDepth; // Search depth limit. int SearchTime; // Search time limit in milliseconds. int MinSearchTime; // Minimum search time in milliseconds. int MaxSearchTime; // Maximum search time in milliseconds. bool Debug; // If true, print debug info to stdout. bool PostInfo; // If true, print post info to stdout. bool XBoardMode; // If true, print info in xboard format. bool Pruning; // If true, do futility pruning. FILE * LogFile; // Output is to stdout and to this file. unsigned int QNodeCount; // Nodes examined in quiescent search. unsigned int NodeCount; // Nodes examined in total. QElapsedTimer Elapsed; // Timer for interrupting search. bool IsOutOfTime; // Becomes true when search is out of time. unsigned int Ply; // Current ply being examined. bool EasyMove; // True if the search indicates one move is // far better than the others. bool HardMove; // True if failed low at root on current depth. unsigned int InNullMove; // If > 0, in null move search so no PV updates. unsigned int RepStackSize; // Repetition stack size. repeatT RepStack [1024]; // Repetition stack. bool InCheck [ENGINE_MAX_PLY]; // In-check at each ply. principalVarT PV [ENGINE_MAX_PLY]; // Principal variation at each ply. simpleMoveT KillerMove [ENGINE_MAX_PLY][2]; // Two killer moves per ply. int History[16][64]; // Success history of piece-to-square moves. unsigned char TranTableSequence; // Transposition table sequence number. unsigned int TranTableSize; // Number of Transposition table entries. transTableEntryT * TranTable; // Transposition table. unsigned int PawnTableSize; // Number of Pawn structure table entries. pawnTableEntryT * PawnTable; // Pawn structure score hash table. bool (*CallbackFunction)(Engine *, void *); // Periodic callback. void * CallbackData; simpleMoveT * GameMoves [1024]; unsigned int NumGameMoves; private: int PieceValue(pieceT piece); int SearchRoot(int depth, int alpha, int beta, MoveList * mlist); int Search(int depth, int alpha, int beta, bool tryNullMove); int Quiesce(int alpha, int beta); int SEE(squareT from, squareT to); void ScoreMoves(MoveList * mlist); inline void DoMove(simpleMoveT * sm); inline void UndoMove(simpleMoveT * sm); inline void SetPVLength(void); inline void UpdatePV(simpleMoveT * sm); void Output(const char * format, ...); void PrintPV(unsigned int depth, int score) { PrintPV(depth, score, ""); } void PrintPV(unsigned int depth, int score, const char * annotation); inline void PushRepeat(Position * pos); inline void PopRepeat(void); void StoreHash(int depth, scoreFlagT flag, int score, simpleMoveT * bestmove, bool isOnlyMove); scoreFlagT ProbeHash(int depth, int * score, simpleMoveT * bestMove, bool * isOnlyMove); inline void ClearKillerMoves(void); inline void AddKillerMove(simpleMoveT * sm); inline bool IsKillerMove(simpleMoveT * sm); inline void ClearHistoryValues(void); inline void HalveHistoryValues(void); inline void IncHistoryValue(simpleMoveT * sm, int increment); inline int GetHistoryValue(simpleMoveT * sm); int Score(int alpha, int beta); inline int ScoreWhiteMaterial(void); inline int ScoreBlackMaterial(void); void ScorePawnStructure(pawnTableEntryT * pawnEntry); bool IsMatingScore(int score); bool IsGettingMatedScore(int score); bool OutOfTime(void); void AdjustTime(bool easyMove); public: Engine() { MaxDepth = ENGINE_MAX_PLY; // A large default search depth SearchTime = 1000; // Default search time: 1000 ms = one second. MinSearchTime = MaxSearchTime = SearchTime; LogFile = NULL; Debug = false; PostInfo = false; XBoardMode = false; Pruning = false; RepStackSize = 0; TranTable = NULL; TranTableSize = 0; TranTableSequence = 0; PawnTable = NULL; PawnTableSize = 0; SetHashTableKilobytes(ENGINE_HASH_KB); SetPawnTableKilobytes(ENGINE_PAWN_KB); CallbackFunction = NULL; NumGameMoves = 0; RootPos.StdStart(); Pos.StdStart(); PV[0].length = 0; } ~Engine() { delete[] TranTable; delete[] PawnTable; } void SetSearchDepth(unsigned int ply) { if(ply < 1) { ply = 1; } if(ply > ENGINE_MAX_PLY) { ply = ENGINE_MAX_PLY; } MaxDepth = ply; } void SetSearchTime(unsigned int ms) { MinSearchTime = SearchTime = MaxSearchTime = ms; } void SetSearchTime(unsigned int min, unsigned int ms, unsigned int max) { MinSearchTime = min; SearchTime = ms; MaxSearchTime = max; } void SetDebug(bool b) { Debug = b; } void SetPostMode(bool b) { PostInfo = b; } bool InPostMode(void) { return PostInfo; } void SetXBoardMode(bool b) { XBoardMode = b; } bool InXBoardMode(void) { return XBoardMode; } void SetPruning(bool b) { Pruning = b; } void SetLogFile(FILE * fp) { LogFile = fp; } void SetHashTableKilobytes(unsigned int sizeKB); void SetPawnTableKilobytes(unsigned int sizeKB); unsigned int NumHashTableEntries(void) { return TranTableSize; } unsigned int NumPawnTableEntries(void) { return PawnTableSize; } void ClearHashTable(void); void ClearPawnTable(void); void ClearHashTables(void) { ClearHashTable(); ClearPawnTable(); } void SetCallbackFunction(bool (*fn)(Engine *, void *), void * data) { CallbackFunction = fn; CallbackData = data; } unsigned int GetNodeCount(void) { return NodeCount; } bool NoMatingMaterial(void); bool FiftyMoveDraw(void); unsigned int RepeatedPosition(void); void SetPosition(Position * pos); Position * GetPosition(void) { return &RootPos; } void PlayMove(simpleMoveT * move); void RetractMove(void); int Score(void); int ScoreMaterial(void); principalVarT * GetPV(void) { return &(PV[0]); } unsigned int PerfTest(unsigned int depth); int Think(MoveList * mlist); }; inline void Engine::SetPVLength(void) { if(Ply < ENGINE_MAX_PLY - 1) { PV[Ply].length = Ply; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Engine::UpdatePV // Updates the principal variation at the current Ply to // include the specified move. inline void Engine::UpdatePV(simpleMoveT * sm) { if(Ply >= ENGINE_MAX_PLY - 1) { return; } if(InNullMove > 0) { return; } // if (! Pos.IsLegalMove (sm)) { return; } PV[Ply].move[Ply] = *sm; for(unsigned int j = Ply + 1; j < PV[Ply + 1].length; j++) { PV[Ply].move[j] = PV[Ply + 1].move[j]; } PV[Ply].length = PV[Ply + 1].length; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Killer moves: // We keep track of two "killer" moves at each ply, moves which // are not captures or promotions (as they get ordered first) but // were good enough to cause a beta cutoff. Killer moves get // ordered after good captures but before non-killer noncaptures, // which are ordered using the history table (see below). // // Only noncaptures and non-promotion moves can be killer moves, but // we make an exception for those that have a negative score (meaning // they lose material according to the static exchange evaluator), // since they would otherwise be searched last after all noncaptures. inline void Engine::ClearKillerMoves(void) { for(unsigned int i = 0; i < ENGINE_MAX_PLY; i++) { KillerMove[i][0].from = NULL_SQUARE; KillerMove[i][1].from = NULL_SQUARE; } } inline void Engine::AddKillerMove(simpleMoveT * sm) { if(sm->capturedPiece != EMPTY && sm->score >= 0) { return; } if(sm->promote != EMPTY && sm->score >= 0) { return; } simpleMoveT * killer0 = &(KillerMove[Ply][0]); simpleMoveT * killer1 = &(KillerMove[Ply][1]); if(killer0->from == sm->from && killer0->to == sm->to && killer0->movingPiece == sm->movingPiece) { return; } *killer1 = *killer0; *killer0 = *sm; } inline bool Engine::IsKillerMove(simpleMoveT * sm) { simpleMoveT * killer0 = &(KillerMove[Ply][0]); if(killer0->from == sm->from && killer0->to == sm->to && killer0->movingPiece == sm->movingPiece) { return true; } simpleMoveT * killer1 = &(KillerMove[Ply][1]); if(killer1->from == sm->from && killer1->to == sm->to && killer1->movingPiece == sm->movingPiece) { return true; } return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // History table: // This is a table of values indexed by moving piece and // target square, indicating the historical success of each move // as measured by the frequency of "good" (better than alpha) // scores. It is used to order non-capture moves after killers. inline void Engine::ClearHistoryValues(void) { for(pieceT p = WK; p <= BP; p++) { for(squareT to = A1; to <= H8; to++) { History[p][to] = 0; } } } inline void Engine::HalveHistoryValues(void) { // Output("# Halving history values\n"); for(pieceT p = WK; p <= BP; p++) { for(squareT to = A1; to <= H8; to++) { History[p][to] /= 2; } } } inline void Engine::IncHistoryValue(simpleMoveT * sm, int increment) { if(sm->capturedPiece != EMPTY && sm->score >= 0) { return; } if(sm->promote != EMPTY && sm->score >= 0) { return; } pieceT p = sm->movingPiece; squareT to = sm->to; ASSERT(p <= BP && to <= H8); History[p][to] += increment; // Halve all history values if this one gets too large, to avoid // non-capture moves getting searched before captures: if(History[p][to] >= ENGINE_MAX_HISTORY) { HalveHistoryValues(); } } inline int Engine::GetHistoryValue(simpleMoveT * sm) { pieceT p = sm->movingPiece; squareT to = sm->to; ASSERT(p <= BP && to <= H8); return History[p][to]; } } // End namespace Guess #endif // SCID_ENGINE_H ////////////////////////////////////////////////////////////////////// // EOF: guessengine.h ////////////////////////////////////////////////////////////////////// chessx-1.0.0/src/guess/misc.cpp000644 001750 001750 00000111132 12223260306 017160 0ustar00niklasniklas000000 000000 ////////////////////////////////////////////////////////////////////// // // FILE: misc.cpp // Miscellaneous routines (File I/O, etc) // // Part of: Scid (Shane's Chess Information Database) // Version: 3.5 // // Notice: Copyright (c) 2001-2003 Shane Hudson. All rights reserved. // // Author: Shane Hudson (sgh@users.sourceforge.net) // ////////////////////////////////////////////////////////////////////// #include "common.h" #include "error.h" #include "misc.h" #include #include #include // For isspace() function. #include // Needed for fileSize() function. namespace Guess { // Table of direction between any two chessboard squares, initialised // in scid_Init(): directionT sqDir[66][66]; ////////////////////////////////////////////////////////////////////// // Scid Initialisation Routine //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // scid_Init(): // Must be called before move generation etc is done. Sets up // any uninitialised piece/square/move tables. // void scid_Init() { // Check that we only call this once: static int numCalls = 0; if(numCalls > 0) { return; } numCalls++; // Initialise the sqDir[][] array of directions between every pair // of squares. squareT i, j; directionT dirArray[] = { UP, DOWN, LEFT, RIGHT, UP_LEFT, UP_RIGHT, DOWN_LEFT, DOWN_RIGHT, NULL_DIR }; // First, set everything to NULL_DIR: for(i = A1; i <= NS; i++) { for(j = A1; j <= NS; j++) { sqDir[i][j] = NULL_DIR; } } // Now fill in the valid directions: for(i = A1; i <= H8; i++) { directionT * dirptr = dirArray; while(*dirptr != NULL_DIR) { j = square_Move(i, *dirptr); while(j != NS) { sqDir[i][j] = *dirptr; j = square_Move(j, *dirptr); } dirptr++; } } } ////////////////////////////////////////////////////////////////////// // ECO Code Routines //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // eco_FromString(): // Extract an ECO code from a string. // // Eco code numbering: no eco = 0, A00 = 1, A01 = 132, etc. // That is, each basic ECO code = previous + 131. // The extra 130 subcodes are the extended code: // a, a1, a2, a3, a4, b, b1, .... z, z1, z2, z3, z4. (130 in total). // // Improvement, March 2000: now case-insensitive for first letter, // for example, a41 == A41. ecoT eco_FromString(const char * ecoStr) { ecoT eco = ECO_None; // Get the basic Eco code from the first 3 characters: they MUST be in // the range "A00" to "E99" or the eco code will be considered empty. // Changed, June 1999: now accepts partial ECO codes, e.g. "C1" -> C10 if(*ecoStr >= 'A' && *ecoStr <= 'E') { eco = (*ecoStr - 'A') * 13100; } else if(*ecoStr >= 'a' && *ecoStr <= 'e') { eco = (*ecoStr - 'a') * 13100; } else { return 0; } ecoStr++; if(! *ecoStr) { return eco + 1; } if(*ecoStr < '0' || *ecoStr > '9') { return 0; } eco += (*ecoStr - '0') * 1310; ecoStr++; if(! *ecoStr) { return eco + 1; } if(*ecoStr < '0' || *ecoStr > '9') { return 0; } eco += (*ecoStr - '0') * 131; ecoStr++; // Now check for the optional extended code: a, a1, ... z2, z3, z4. if(*ecoStr >= 'a' && *ecoStr <= 'z') { eco++; eco += (*ecoStr - 'a') * 5; ecoStr++; if(*ecoStr >= '1' && *ecoStr <= '4') { eco += *ecoStr - '0'; } } return eco + 1; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // eco_ToString(): // Convert an ECO code to its string representation. void eco_ToString(ecoT ecoCode, char * ecoStr, bool extensions) { char * s = ecoStr; if(ecoCode == ECO_None) { *s = 0; return; } ecoCode--; // First the base code value: ecoT basicCode = ecoCode / 131; // 131 = 26 * 5 + 1 subcodes. *s++ = basicCode / 100 + 'A'; *s++ = (basicCode % 100) / 10 + '0'; *s++ = (basicCode % 10) + '0'; // Now the optional extensions: if(extensions) { ecoCode = ecoCode % 131; if(ecoCode > 0) { ecoCode--; *s++ = (ecoCode / 5) + 'a'; ecoCode = ecoCode % 5; if(ecoCode > 0) { *s++ = (ecoCode + '0'); } } *s = 0; } return; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // eco_BasicCode(): // Converts an ECO code to its basic form, without any // Scid-specific extensions. ecoT eco_BasicCode(ecoT eco) { if(eco == ECO_None) { return ECO_None; } eco--; eco /= 131; eco *= 131; return eco + 1; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // eco_LastSubCode(): // Converts an ECO code to the deepest subcode it could contain. // Examples: B91a -> B91a4 and B91 -> B91z4. ecoT eco_LastSubCode(ecoT eco) { if(eco == ECO_None) { return ECO_None; } // if just a basic ECO code (1 letter, 2 digits), add the "z": eco--; if((eco % 131) == 0) { eco += 126; // 126 = 5 * 25 + 1. } // Now if no final digit, add the "4": if(((eco % 131) % 5) == 1) { eco += 4; } return eco + 1; } ////////////////////////////////////////////////////////////////////// // String Routines //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strCopy(): same as strcpy(). // void strCopy(char * target, const char * original) { ASSERT(target != NULL && original != NULL); while(*original != 0) { *target = *original; target++; original++; } *target = 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strCopyExclude(): copies original to target, filtering out any // characters in excludeChars. void strCopyExclude(char * target, const char * original, const char * excludeChars) { while(*original != 0) { int exclude = 0; for(char * s = (char *) excludeChars; *s; s++) { if(*original == *s) { exclude = 1; break; } } if(!exclude) { *target = *original; target++; } original++; } *target = 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strAppend(): // Appends extra to the end of target, and returns a pointer // to the new END of the string target. // char * strAppend(char * target, const char * extra) { ASSERT(target != NULL && extra != NULL); while(*target != 0) { target++; // get to end of target string } while(*extra != 0) { *target = *extra; target++; extra++; } *target = 0; return target; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Extra versions of strAppend() for appending an int, a unsigned int, or // up to four strings: char * strAppend(char * target, int i) { char temp [20]; sprintf(temp, "%d", i); return strAppend(target, temp); } char * strAppend(char * target, unsigned int u) { char temp [20]; sprintf(temp, "%u", u); return strAppend(target, temp); } char * strAppend(char * target, const char * s1, const char * s2) { target = strAppend(target, s1); target = strAppend(target, s2); return target; } char * strAppend(char * target, const char * s1, const char * s2, const char * s3) { target = strAppend(target, s1); target = strAppend(target, s2); target = strAppend(target, s3); return target; } char * strAppend(char * target, const char * s1, const char * s2, const char * s3, const char * s4) { target = strAppend(target, s1); target = strAppend(target, s2); target = strAppend(target, s3); target = strAppend(target, s4); return target; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strCompare(): same as strcmp. // strCompare_INLINE() is an inline version, see misc.h. // int strCompare(const char * s1, const char * s2) { ASSERT(s1 != NULL && s2 != NULL); while(1) { if(*s1 != *s2) { return (int) * s1 - (int) * s2; } if(*s1 == 0) { break; } s1++; s2++; } return 0; } int strCaseCompare(const char * s1, const char * s2) { ASSERT(s1 != NULL && s2 != NULL); while(1) { if(tolower(*s1) != tolower(*s2)) { return (int) * s1 - (int) * s2; } if(*s1 == 0) { break; } s1++; s2++; } return 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strCompareRound(): // String comparison function for round names. Sorts by the integer // number at the start of each string first. int strCompareRound(const char * sleft, const char * sright) { int ileft = strGetInteger(sleft); int iright = strGetInteger(sright); int diff = ileft - iright; if(diff != 0) { return diff; } // Now check if both strings are equal up to the first dot. // If so, do an integer comparison after the ".": bool equalUpToDot = false; const char * templeft = sleft; const char * tempright = sright; while(true) { char leftc = *templeft; char rightc = *tempright; if(leftc == 0 || rightc == 0) { break; } if(leftc != rightc) { break; } if(leftc == '.' && rightc == '.') { equalUpToDot = true; break; } templeft++; tempright++; } if(equalUpToDot) { templeft++; tempright++; // Now templeft and tempright point to the first character // after each dot. ileft = strGetInteger(templeft); iright = strGetInteger(tempright); diff = ileft - iright; if(diff != 0) { return diff; } } // Give up on integer comparisons and do a regular string comparison: return strCompare(sleft, sright); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strDuplicate(): Duplicates a string using new[] operator. // char * strDuplicate(const char * original) { ASSERT(original != NULL); char * newStr = new char [strLength(original) + 1]; if(newStr == NULL) { return NULL; } char *s = newStr; while(*original != 0) { *s = *original; s++; original++; } *s = 0; // Add trailing '\0'. //printf ("Dup: %p: %s\n", newStr, newStr); return newStr; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strPrefix(): // Returns the length of the common prefix of two strings. // unsigned int strPrefix(const char * s1, const char * s2) { ASSERT(s1 != NULL && s2 != NULL); unsigned int count = 0; while(*s1 == *s2) { if(*s1 == 0) // seen end of string, strings are identical { return count; } count++; s1++; s2++; } return count; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strPad(): // Copies original string to target, but copies *exactly* 'width' // bytes. If the original is longer than specified width, not all of // original will be copied to target. If original is shorter, then // target will be padded out to 'width' bytes with the padding char. // // If the width is negative, no trimming or padding is done and // the result is just a regular string copy. // // The return value is the length copied: always 'width' if // width is >= 0, or the length of original if 'width' is negative. // unsigned int strPad(char * target, const char * original, int width, char padding) { ASSERT(target != NULL && original != NULL); if(width < 0) { strCopy(target, original); return strLength(original); } int len = width; while(len > 0) { if(*original == 0) { break; } *target = *original; target++; original++; len--; } while(len--) { *target++ = padding; } *target = 0; return width; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strFirstChar(): // Returns the pointer into the provided string where the // FIRST occurrence of matchChar is, or NULL if the string // does not contain matchChar at all. // Equivalent to strchr(). const char * strFirstChar(const char * target, char matchChar) { const char * s = target; while(*s != 0) { if(*s == matchChar) { return s; } s++; } return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strLastChar(): // Returns the pointer into the provided string where the // LAST occurrence of matchChar is, or NULL if the string // does not contain matchChar at all. // Equivalent to strrchr(). const char * strLastChar(const char * target, char matchChar) { const char * s = target; const char * last = NULL; while(*s != 0) { if(*s == matchChar) { last = s; } s++; } return last; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strStrip(): // Removes all occurances of the specified char from the string. void strStrip(char * str, char ch) { char * s = str; while(*str != 0) { if(*str != ch) { if(s != str) { *s = *str; } s++; } str++; } *s = 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strTrimLeft(): // Returns the pointer into the provided string where the first // character that does NOT equal a trimChar occurs. const char * strTrimLeft(const char * target, const char * trimChars) { const char * s = target; while(*s != 0) { if(! strContainsChar(trimChars, *s)) { break; } s++; } return s; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strTrimRight(): // Trims the provided string in-place, removing the // end characters that match the trimChars. // Returns the number of characters trimmed. // E.g., strTrimRight("abcyzyz", "yz") would leave the string // as "abc" and return 4. unsigned int strTrimRight(char * target, const char * trimChars) { unsigned int trimCount = 0; char * s = target; char * lastNonTrim = NULL; while(*s) { if(strContainsChar(trimChars, *s)) { trimCount++; } else { lastNonTrim = s; trimCount = 0; } s++; } if(lastNonTrim != NULL) { // End the string after the last nontrimmable char: lastNonTrim++; *lastNonTrim = 0; } else { // The string only contained trimmable characters: *target = 0; } return trimCount; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strTrimSuffix(): // Trims the provided string in-place, at the last // occurance of the provided suffix character. // Returns the number of characters trimmed. // E.g., strTrimSuffix ("file.txt", '.') would leave the // string as "file" and return 4. unsigned int strTrimSuffix(char * target, char suffixChar) { unsigned int trimCount = 0; char * lastSuffixPtr = NULL; char * s = target; while(*s) { if(*s == suffixChar) { lastSuffixPtr = s; trimCount = 0; } trimCount++; s++; } if(lastSuffixPtr == NULL) { return 0; } *lastSuffixPtr = 0; return trimCount; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strTrimDate(): // Takes a date string ("xxxx.xx.xx" format) and trims // the day part if it is ".??", and also the month part // if it too is ".??". void strTrimDate(char * str) { if(str[7] == '.' && str[8] == '?' && str[9] == '?') { str[7] = 0; if(str[4] == '.' && str[5] == '?' && str[6] == '?') { str[4] = 0; } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strTrimMarkCodes(): // Trims in-place all Scid-recognised board mark codes // in a comment string, such as "[%mark ...]" and "[%arrow ...]" void strTrimMarkCodes(char * str) { char * in = str; char * out = str; bool inCode = false; char * startLocation = NULL; while(1) { char ch = *in; if(inCode) { // If we see end-of-string or code-starting '[', there is some // error so go back to the start of this code and treat it // normally. if(ch == 0 || ch == '[') { *out++ = *startLocation; inCode = false; in = startLocation; } else if(ch == ']') { // See a code-ending ']', so end the code. inCode = false; } // For all other characters in a code, just ignore it. } else { // Stop at end-of-string: if(ch == 0) { break; } // Look for the start of a code that is to be stripped: if(ch == '[' && in[1] == '%') { inCode = true; startLocation = in; } else { *out++ = ch; } } in++; } // Terminate the modified string: *out = 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strTrimMarkup(): // Trims in-place all HTML-like markup codes (, , etc) // from the provided string. void strTrimMarkup(char * str) { char * in = str; char * out = str; bool inTag = false; while(*in != 0) { char ch = *in; if(inTag) { if(ch == '>') { inTag = false; } } else { if(ch == '<') { inTag = true; } else { *out++ = ch; } } in++; } *out = 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strTrimSurname(): // Trims a person name string to contain only the // surname, or only the surname and a maximum number // of initials. void strTrimSurname(char * str, unsigned int initials) { char * in = str; char * out = str; bool seenComma = false; while(*in != 0) { char ch = *in; if(seenComma) { if(isupper(ch)) { *out++ = ch; initials--; if(initials == 0) { break; } } } else { if(ch == ',') { seenComma = true; if(initials == 0) { break; } } *out++ = ch; } in++; } *out = 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strFirstWord: // Skips over all whitespace at the start of the // string to reach the first word. const char * strFirstWord(const char * str) { ASSERT(str != NULL); while(*str != 0 && isspace(*str)) { str++; } return str; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strNextWord: // Skips over all successive non-whitespace characters // in the string, then all successive whitespace chars, // to reach the next word in the string. const char * strNextWord(const char * str) { ASSERT(str != NULL); while(*str != 0 && !isspace(*str)) { str++; } while(*str != 0 && isspace(*str)) { str++; } return str; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strSingleSpace(): // Modifies the parameter string in-place, trimming all // whitespace at the start and end of the string, and reducing // all other sequences of whitespace to a single space. // // Example: "\t\n A \t\n B C " (where \t and \n are tabs // and newlines) becomes "A B C". // // Returns the new string length, to save time if the caller // wants to find the length of the modified string. // unsigned int strSingleSpace(char * str) { ASSERT(str); bool spaceSeen = true; // Initially true so whitespace at the start // of the string is removed. char * forward = str; char * back = str; unsigned int length = 0; // Loop through the string compacting out unwanted whitespace: while(*forward) { if(isspace(*forward)) { if(spaceSeen) { // Already seen whitespace, so skip over this char. } else { spaceSeen = true; *back++ = ' '; length++; } } else { spaceSeen = false; *back++ = *forward; length++; } forward++; } // Now, if the last char kept was a space, remove it: if(length > 0 && spaceSeen) { ASSERT(back != str); back--; length--; ASSERT(*back == ' '); } *back = 0; return length; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strIsAllWhitespace(): // Returns true if the string contains only whitespace charaters. bool strIsAllWhitespace(const char * str) { while(*str != 0) { if(! isspace(*str)) { return false; } str++; } return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strIsUnknownName(): // Returns true if the string is an "unknown" name: the empty // string, "?" or "-". Used primarily to test if an event, site // or round name string contains information worth printing. bool strIsUnknownName(const char * str) { if(str[0] == 0) { return true; } if(str[0] == '-' && str[1] == 0) { return true; } if(str[0] == '?' && str[1] == 0) { return true; } return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strIsPrefix(): // Returns true if the prefix string is a prefix of longStr. bool strIsPrefix(const char * prefix, const char * longStr) { while(*prefix) { if(*longStr == 0) { return false; } if(*prefix != *longStr) { return false; } prefix++; longStr++; } return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strIsCasePrefix(): // Returns true if the prefix string is a case-insensitive // prefix of longStr. bool strIsCasePrefix(const char * prefix, const char * longStr) { while(*prefix) { if(*longStr == 0) { return false; } if(tolower(*prefix) != tolower(*longStr)) { return false; } prefix++; longStr++; } return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strIsAlphaPrefix(): // Returns true if the prefix string is a prefix of longStr. // Unlike strIsPrexix(), this version is case-insensitive and // spaces are ignored. // Example: strIsAlphaPrefix ("smith,j", "Smith, John") == true. bool strIsAlphaPrefix(const char * prefix, const char * longStr) { while(*prefix) { while(*prefix == ' ') { prefix++; } while(*longStr == ' ') { longStr++; } if(*longStr == 0) { return false; } if(tolower(*prefix) != tolower(*longStr)) { return false; } prefix++; longStr++; } return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strIsSurnameOnly(): // Returns true if the name appears to be a surname only. bool strIsSurnameOnly(const char * name) { unsigned int capcount = 0; const char * s = name; while(*s != 0) { char c = *s; if(! isalpha(c)) { return false; } if(isupper(c)) { capcount++; if(capcount > 1) { return false; } } s++; } return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strContains(): // Returns true if longStr contains an occurence of keyStr, // case-sensitive and NOT ignoring any characters such as spaces. bool strContains(const char * longStr, const char * keyStr) { while(*longStr) { if(strIsPrefix(keyStr, longStr)) { return true; } longStr++; } return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strContainsIndex(): // Returns the first index if longStr contains an occurence of keyStr, // case-sensitive and NOT ignoring any characters such as spaces. // Returns -1 if longStr does not contain keyStr int strContainsIndex(const char * longStr, const char * keyStr) { int index = 0; while(*longStr) { if(strIsPrefix(keyStr, longStr)) { return index; } longStr++; index++; } return -1; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strAlphaContains(): // Returns true if longStr contains an occurence of keyStr, // case-insensitive and ignoring spaces. // Example: strAlphaContains ("Smith, John", "th,j") == true. // bool strAlphaContains(const char * longStr, const char * keyStr) { while(*longStr) { if(strIsAlphaPrefix(keyStr, longStr)) { return true; } longStr++; } return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strGetBoolean(): // Extracts a boolean value from a string. // True strings start with one of "TtYy1", false strings with // one of "FfNn0". // Returns false if the string does not contain a boolean value. bool strGetBoolean(const char * str) { static const char * sTrue[] = { "true", "yes", "on", "1", "ja", "si", "oui", NULL }; static const char * sFalse[] = { "false", "no", "off", "0", NULL }; if(str[0] == 0) { return false; } bool matchedTrue = false; bool matchedFalse = false; const char ** next = sTrue; while(*next != NULL) { if(strIsCasePrefix(str, *next) || strIsCasePrefix(*next, str)) { matchedTrue = true; } next++; } next = sFalse; while(*next != NULL) { if(strIsCasePrefix(str, *next) || strIsCasePrefix(*next, str)) { matchedFalse = true; } next++; } if(matchedTrue && !matchedFalse) { return true; } if(matchedFalse && !matchedTrue) { return false; } // default: return false. return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strGetInteger(): // Extracts a signed base-10 value from a string. // Defaults to zero (as strtol does) for non-numeric strings. int strGetInteger(const char * str) { return strtol(str, NULL, 10); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strGetUnsigned(): // Extracts an unsigned base-10 value from a string. // Defaults to zero (as strtoul does) for non-numeric strings. // unsigned int strGetUnsigned(const char * str) { unsigned long ulvalue = strtoul(str, NULL, 10); return (unsigned int) ulvalue; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strGetIntegers: // Extracts the specified number of signed integers in a // whitespace-separated string to an array. void strGetIntegers(const char * str, int * results, unsigned int nResults) { for(unsigned int i = 0; i < nResults; i++) { while(*str != 0 && isspace(*str)) { str++; } results[i] = strGetInteger(str); while(*str != 0 && !isspace(*str)) { str++; } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strGetUnsigneds: // Extracts the specified number of unsigned integers in a // whitespace-separated string to an array. void strGetUnsigneds(const char * str, unsigned int * results, unsigned int nResults) { for(unsigned int i = 0; i < nResults; i++) { while(*str != 0 && isspace(*str)) { str++; } results[i] = strGetUnsigned(str); while(*str != 0 && !isspace(*str)) { str++; } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strGetBooleans: // Extracts the specified number of boolean values // from a whitespace-separated string. void strGetBooleans(const char * str, bool * results, unsigned int nResults) { for(unsigned int i = 0; i < nResults; i++) { while(*str != 0 && isspace(*str)) { str++; } results[i] = strGetBoolean(str); while(*str != 0 && !isspace(*str)) { str++; } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strGetResult: // Extracts a game result value from a string. resultT strGetResult(const char * str) { switch(*str) { case '1': // Check for "1/2"-style draw result: if(str[1] == '/' && str[2] == '2') { return RESULT_Draw; } return RESULT_White; case '=': return RESULT_Draw; case '0': return RESULT_Black; case '*': return RESULT_None; } return RESULT_None; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strGetFlag(): // Extracts a flag (FLAG_YES, FLAG_NO or FLAG_BOTH) value from // a string. Defaults to FLAG_EMPTY. flagT strGetFlag(const char * str) { char c = *str; switch(c) { case 'T': case 't': case 'Y': case 'y': case 'J': case 'j': case 'O': case 'o': case 'S': case 's': case '1': return FLAG_YES; case 'F': case 'f': case 'N': case 'n': case '0': return FLAG_NO; case 'B': case 'b': case '2': return FLAG_BOTH; } // default: return empty. return FLAG_EMPTY; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strGetSquare(): // Extracts a square value from a string, such as "a2". squareT strGetSquare(const char * str) { char chFyle = str[0]; if(chFyle < 'a' || chFyle > 'h') { return NULL_SQUARE; } char chRank = str[1]; if(chRank < '1' || chRank > '8') { return NULL_SQUARE; } return square_Make(fyle_FromChar(chFyle), rank_FromChar(chRank)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // strUniqueExactMatch(): // Given a string and a null-terminated array of strings // , returns the index of the unique match of the key // string in the string table. If no match was found, or there was // more than one match, -1 is returned. // // If the flag is true, only complete matches are considered. // Otherwise, unique abbreviations are accepted. // Example: looking up "repl" in {"repeat", "replace", NULL} would // return 1 (matching "replace") but looking up "rep" would // return -1 because its match is ambiguous. // // The array "strTable" does NOT need to be in any order, but the last // entry must be NULL. int strUniqueExactMatch(const char * keyStr, const char ** strTable, bool exact) { int index = -1; int abbrevMatches = 0; const char * s1; const char * s2; const char ** entryPtr = strTable; // If keyStr or strTable are null, return no match: if(keyStr == NULL || strTable == NULL) { return -1; } // Check each entry in turn: for(int i = 0; *entryPtr != NULL; entryPtr++, i++) { // Check the key against this entry, character by character: for(s1 = keyStr, s2 = *entryPtr; *s1 == *s2; s1++, s2++) { // If *s1 is 0, we found an EXACT match, so return it now: if(*s1 == 0) { return i; } } // If *s1 == 0 now, key is an abbreviation of this entry: if(*s1 == 0) { index = i; abbrevMatches++; } } // If we reach here, there is no exact match. If an exact match was // required, or there is not exactly one abbreviation, return no match: if(exact || abbrevMatches != 1) { return -1; } // Otherwise, return the match found: return index; } ////////////////////////////////////////////////////////////////////// // FILE I/O Routines //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // fileSize(): // Computes the plain (uncompressed) size of the named file, // using one of the other FileSize functions here. unsigned int fileSize(const char * name, const char * suffix) { fileNameT fname; strCopy(fname, name); strAppend(fname, suffix); const char * lastSuffix = strFileSuffix(fname); if(lastSuffix != NULL && strEqual(lastSuffix, GZIP_SUFFIX)) { return gzipFileSize(fname); } return rawFileSize(fname); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // rawFileSize(): // Uses the stat() system call to get the size of the file. // Returns 0 if any error occurs. unsigned int rawFileSize(const char * name) { struct stat statBuf; // Defined in if(stat(name, &statBuf) != 0) { return 0; } return (unsigned int) statBuf.st_size; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // gzipFileSize(): // Returns the UNCOMPRESSED size of a .gz file. // This is stored the final 4 bytes, in little endian format. // Returns 0 if any error occurs. unsigned int gzipFileSize(const char * name) { FILE * fp; fp = fopen(name, "rb"); if(fp == NULL) { return 0; } // Seek to 4 bytes from the end: if(fseek(fp, -4L, SEEK_END) != 0) { fclose(fp); return 0; } // Read the 4-unsigned char number in little-endian format: unsigned int size = 0; unsigned int b0 = (unsigned int) getc(fp); unsigned int b1 = (unsigned int) getc(fp); unsigned int b2 = (unsigned int) getc(fp); unsigned int b3 = (unsigned int) getc(fp); size = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); fclose(fp); return size; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // renameFile(): // Renames the file from oldName to newName with the same suffix. // Returns OK if successfull, ERROR_FileMode otherwise. errorT renameFile(const char * oldName, const char * newName, const char * suffix) { fileNameT fnameOld, fnameNew; strCopy(fnameOld, oldName); strAppend(fnameOld, suffix); strCopy(fnameNew, newName); strAppend(fnameNew, suffix); if(rename(fnameOld, fnameNew) != 0) { return ERROR_FileMode; } return OK; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // removeFile(): // Removes the file given the filename and suffix. // Returns OK if successfull, ERROR_FileMode otherwise. errorT removeFile(const char * name, const char * suffix) { fileNameT fname; strCopy(fname, name); strAppend(fname, suffix); if(remove(fname) != 0) { return ERROR_FileMode; } return OK; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // createFile(): // Creates (and immediately closes) an empty file. // Returns OK if successfull, ERROR_FileOpen otherwise. errorT createFile(const char * name, const char * suffix) { fileNameT fname; strCopy(fname, name); strAppend(fname, suffix); FILE * fp = fopen(fname, "w"); if(!fp) { return ERROR_FileOpen; } fclose(fp); return OK; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // fileExists(): // Returns true if the file exists, false otherwise. bool fileExists(const char * name, const char * suffix) { struct stat statBuf; // Defined in fileNameT fname; strCopy(fname, name); strAppend(fname, suffix); if(stat(fname, &statBuf) != 0) { return false; } return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // writeString(), readString(): // Read/write fixed-length strings. // Lengths of zero bytes ARE allowed. errorT writeString(FILE * fp, char * str, unsigned int length) { ASSERT(fp != NULL && str != NULL); int result = 0; while(length > 0) { result = putc(*str, fp); str++; length--; } return (result == EOF ? ERROR_FileWrite : OK); } errorT readString(FILE * fp, char * str, unsigned int length) { ASSERT(fp != NULL && str != NULL); while(length > 0) { *str = getc(fp); str++; length--; } return OK; } } // End namespace Guess ////////////////////////////////////////////////////////////////////// // EOF: misc.cpp ////////////////////////////////////////////////////////////////////// chessx-1.0.0/data/themes/boards/maple.png000644 001750 001750 00000305452 12042321504 021067 0ustar00niklasniklas000000 000000 PNG  IHDR@;w AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~@IDATxDْ#ɒgLY{sDoW/yOv2oYD5"pjj|_^_\udzoH19$ShƼ]E_?^^7gt&_v5?vy ~_wڔo|[",q({q5x ?"`!`f3Ma}  n];X1Xƾh;GgtxN!ZpR{Rp }v}xd>a՛bs'.5.5|$ ߡx%;_??j :6xqF %Wb\p~ ~Ӈ0>Fn,^Ӆ{/IѦpJ|%[3 }\+3k:G[>w{Ħ}!{‡ CA(Ndg#Sys5A`0!ta1QuU7t1Z8])CkʃyK nt-Ej4EE4jO< Lo_b>)3FxGt؁?G+ڗ*+C=*4bm7KR8~1ž/=lڥ0Z5_ t:K §λη`< K+Pk4QD?/h,ԨWL:xwJQ#KtÞ{pv-&CܻWjq%:F:S@/ S0l DQRɬ[8d<@ݣ3N S^J>2ьPqw>YEUXAkw<V1QHٗR(hF9y}<+a^9BT*d/UAhśw<՞U LF=S$F!יD\*ɭ^Ʋ3"ԕ,QP\sC:kǠYƌc'apZ"VjM%O++N`@/3OJ<+ڟ_?Qx$$fCx[pYC53{{bMB)x/|u|dFNdBki`@dyۡ/<[+1r,gFFj_xuC4.`rm\)\ׅ чd3nwқK雫èN<klmLa}5(pL+wg",nCєVMoI1$8H</K6o#yt>֌qH@[^0""38&pE'B҉l8+5ϛWa/gSB< r nnyz!5X[$4]E$z:Ym9 q&ph,/8+ePYSDU~X}ҍjJϫΛ9_u=GcJ[zR]nÙPMJQԀ{fǣ^j K"fo1N)H{+,j{fΌڝM0 ރ#^[qܚS)'`x10fNU9ᇆvUY<\N[BJrF8lI5tZjrHQ+%H2.%+_d|C/E/7NYL4]z0l d}K㫎{t/uƻPsw0b1'aJ3piS*4/GSEl 'ֵy>m+rsa)Y$ћ菔BvuK3)qVTQvd o=7$Co7y,+p1QvH᪷+E;D,R>9β))x!R/mUYfԷØW-awk" p͸:r#TA|VX~6^C|P𨟗}aea[s{J wFpJ ~NCvL`#ᰈUW<ݻ Y1 f>~K7sW]{N);c`\B뿙s5MqBaKГ˱sLd:~Dv>+mFãt<܈7%-oɭ9dz4S”"2W^;JW o˄rH+89Hi 9E=m+<3$JXY6U{js.:w1;H̼\#n  |lL^USG;|ENA }bbF7)eѓeTg6#v VBKjA,~p{;^!nfl՛!- 0 J$鋥/}%hƟ706 hcOxx_W^Eh^Df۵!qP-CaCA^qKnZ`Dpjx3:ptȠ',jgP'MQ3Ke.YJLq2B`Pivu ;Lf> ߢݸ3 Un%܏&M+;۫?k()pоQCut *ٍYGy_ ٴn\ة2zex}k;kI!(ٚDqܧd͘OlB&YX {p'vZG(J ъG~Ä;bWC vK6er!iij$eY)}6>0CXn>֕LϟV%mf ^>t+ w8d쫣ևLM\ަy'u8mh ~2[r§q(5i)J6~rx&Sb"`R͕HCKGSPlCo]j5RǨObx] o+7G^2bx߼(" >G,`cz/DԬkfOv\lϰ2e1&Lzn̓R@>8.N› 5Aåp8xioLy.w'J5gSFv"sY{ j#S;tV=~qfN^:<>A$tk ޜ+C6ԬvHt值vB,*>6&lgu ^h$d{ƞ1n E8˾B_|FJ{ yd}CňPFċ;6e%^;dV &@G1܍2&._R`h7f7 p"'Cǫn茥 . ')bkO ?7y)TnRz] > ޯvLv!9?p{:9ӲÃ2ha>S3`WOV~kR\+IPtBTj`&'"LxQn% `R407}k6YW8)(55S,l}n1g7M7"6qBPcNsKңuB) i ,L1X ooWp}@ׯ H1bn($xޢ@YLQ`+s?){} &O.lS:&ͳӠnCw0 >+9}IY4ПjDMm'[etHȈaS:`1yYBEB[ħf!,wA\y2]@[N% ~sn< GO1k*{ ϐ9N71n,]@aD @2b --xe3v"Ӟ`?=zէc}j-ױQ,zK?ӛ 7Q2%ɕXfnz4a%5y(1jOȧz/,rLqSy>q7`(>ZuHؐF\-t{席VQ$` \Ma,e'O픁r]EN+vR"4z{ 2mJVmVhjF,<d5S#8\o H.e('ϩX*تRm ioge$CwSOD5p^k|w[ş8^M2Ys8O#P2Eըb`FeY1#V= \S+j4ʍѷ{Q(\hU!LJ̵ٵvPG!&@f4No2JM 2%6t^K0Zdx\vdDDCrlڤȏ>מ%Qa>7q3遙1R͉u`C-o|2l]:8wsL 6TpX*`MB3PV/xޚJHY/Ӛ&~q}13FBoO2>)qIF<M[c gdϠxDXBXQM"{tEb6- Dv}dxS_c~SO+wGPEp nͳ>GP/Zcޠu63EFT OR/Uνg `, !{@^囉I18ݹ)  'sEOqLrZ•jL9|e4 c)!Ϩ.{H )=.dl C 3t.[]C/C@!~s皱>+W1~EH8TFtFoqQ9I9AnGf."%"hd#35r_xjdDؽ %f 'j:T^ߎg|(|*1[0$`3a|ɒ0KPIկD3h!ֆKuo7ՅZC!u)ntؼg@^g+Rע%̘APv/Xl+1g!r@ ]f7C7& NxOt> oP*S[ *I'S5}/m_Qfg:ؔ-6j,fK\t3WG+^lǓo:>M,GEK<)o~QtV67>&[fJX38'q;D`+X䇵˭ncb{.Ԍ~(gzmWq\O)A0IpcVfBi z`tL1W8XhmDc(G#񴦈!n7OCSNH[7'e>48 V($:|wj\M*- @|o{WXu^w ΛݒM<Rular[P xNi]mJ±"/4Aac^D)CJBo cY>xα>T*RU ,W}йb0wUmwO)'+,O nУFyҙ\ yxZ*D'įxd :v s Gt##x8fWt8]3~fpէ, b2)A$" N1f*cj;(nCB=i-m IGB7[IC kN% RHvAnyipnL3mds[֮=Ʋu)Fv0* [z+VK ~?/IQ[WR漓xCOT]LRm=2lΣϗ'Mt Q/0M5j znf\$Xaxjn-+mxPր}BsLOW5y5:RKROx@Dt~I]Ê|e6|1&!ݱe,I# k^/#\^)Xo7xakK0&tƆVi0{hX)Eaq FXۅF gy_ tn1ngBcy5Bxܓ4~L-=Y2u _ +(QؑCmJ`nWfn|6z~ɫqO{U_]DyDJ^a$rMpܔ=ϹE1b|rdOIm]m-х1_B!p8q쌓,t_Bxj6列fwBJU&AC6gٍ̪GńraHy85U}l"bS8O`#I(uʳI (c̵O.ߡRr9!@S(۾m5Av~Sٱb=VxKYOkѵ)p.p~f4cO+ 0h>S&Jzhcɣq*+l&SB^n{9viGR0yͫR( eY?7uB?IG7!8{Jc<О% nH!{<lrNC K>-FY>j) N5A]_Қ5Bx vY:c I uFU8!'b ߘrp[>vo!k {莦`2VǠAfn\x5 >4>xS.md :a7&v&Seg7x1?sfީo}2M{yyh/ }!H"T~5qs\2g+(]z8H28 ,uw!=G0vIB}']/ѷuYEi?rxx ?eV-l&^:㲳1Ofp_D> GT?{QZ7P`QCrzB\Ƭ,pb7xyIc!8;KiA0;R%f`tn u 6A.)${3L ó=A! k;y  .83Gx&ЀǸގws`)O;Od |M)F=jbOhI#.{'F6O0({pyW.rMDגo/eD҃RS`-Ӕl##7Y+A?XM>}Sd<@'0W?zƓ)tڑnPR7IR(ƳYss3 m(eO,{౮-+sۨ{\Iz)?>k$S1_~}9 R}vӒf)mnb!oLudmY)g>"(lVQQ (y+]hل څ^1 )K`9!'K+.V$Qlgn q8.ZKo՛K9ZoFK3?$Zc9A/y[|6JP,R2>Gi otw#8}j@iS4 d!#,OQwQ,W-w A/ht%O>OMҭ.XUD9 |A$q' nq>U}.Edl7zM3jED^n)+6;Ze`=*k5ӅDf} TV'z|cZU(]J/L:/Mt+ExfkV1/Q7 /OH$d ՓFS(Obg bopҸp" 8|^"C#@F;K} QS܍v|b0qޑgqf\+40ɁV$0 yq)v8y"FKHoHx9ϊ cړ4<` IG5q;e^>r-op,T?*$KH K'(?tNQ=fӔ$1#dZP9,hHPJ]|ƃڳb#Z 7%j&Qf!i>KEPyAVAw -u3ބ2%2$㚢T-?A;g?XrEc?ɓvO#6qvQ$`v 7$g RI> Xy0*83蔁r+ ]FkuػY@InF])&gt+).yhy6qѵ)p=a0L#? G%AFx<0XO&`F祟Js[-1+Ma!L@\*}.Fm1:a l~qٝ-P +V¶"apj5cƔ'^yyB}d.Dx<,޾C깧K7QS8KQytyEA2%=ؒw).~1ޖ$'] ^4;x4q\yy7N73v7##Ґf0=ýĭbk:o:\5s )6d$1(AyǯwDc'NGV(`@]w)|[}s%rMܕa-]l{+ƴm~BԄE.ܔ{ XkX78ށA,aJJ&=r)A0 [%Lh8@Nb15pI9cn? _ʆ`IK +,C"+ŌH(W;̥iGՑZ^ }`lO:NtXEsmt\#Nr6WiD05N)1 a24HИn[% yQP#/ -y'XQu=(V CĬ^~p6/†; !?OqjyrcmgR~yW SB|8T0V N=->_wU 4(FMKS3\0O.ICTMZԎ&njv[9nb) B au˕bt%An:m/KApP$bFV㝳)y*K~A h̎jcnA}amXAy8ehz钐~M劔( vGl%f+R+W^)r!@S!^ UC;۵ f1Z4t~Fu F'B ^(fᖹ_ K+6]+\Zk,0zWvkjRgmk^?U'yn ~^⬬m#H Ldآ;ri(Ͷ/mR΋/{?]]%u^hMqF]= RguPfW˻f`"Ӛ犼23cXl ;WNbZ:$e}]HhD<)HJjyĄjOؾyQKL2]Ka>!4r@xtaw7r(SX 25pB#.iAmy GEJXx1m# B]V(/V[AŖ6OB@"1+k-%ȓ> Qd>yP}V_H=X[^ uBfB?8J_.y/NsEI52?05Ƨߪ'X\ nW)rڄBJ/d8s, >vuȺ4Jm쳜r3OΩ 42*c`8=3NE&mLУ[XM ]B:~IdS&[&OBA;ePx֪OnäfA[g 8ԥ*{pRmFDo֊c ݓ `O+`dThJI ;RƲ8W3Ç.4[Yl⵼p7'B\l {;>\tO@IDAT?NRĤ!dA +tyy¼I ?6Ol_?a=&;esݽ3nw }mMѰ߼0FX[9k3=*B7A&q_6ާ κ1G3k ={9!1ªn1J?mxӛV-q jr31(۟'BKnt"G5BҪdqN Xrx' @[!! {4BzʩNN))6jb %>Xvy3-KK:tw]h5acDޢߏoSxwS^Ow i[(EHWF'#soY<",\=.vnȔYFibp3^<"Ei5nn9MT3Sm8|Si &r% -ۉ( 1RBiR3x<R9bJ0g4^w+D9/rKjQApJ` UcWf]`1Ԯ 5swzbɝ%SH^^_ +ܦoo̻O/R[fC"ʧV)G9al5PP n((Mc($PaQ8AvOOEO]SrѪ&_|qrUpJA|6&\Lycd>Hcx"qG~ijC94b#.,($07 %#P 0"YIx'J#U~sw厎fĔC)rqs n#Ċ\魛-,) Buy 4b-z-I[#5/d^~$fW]hrep<=/]iRN(JCMѤ!J BqpEypk嶷rQ^D7k +*,Myt)R-3U{~yVj˰aa=]aW!+&жuQ5I=ƝޟV5bPgǪj\}G\x~ئD$wz*CJ`J<ʅjS(3SAfczrwSC{B$Y[f~.RZOA6_JGq* @shv8odCVbp='uk6l/9r3ͽ/<:7E>5L.' 9 ^Gh h"D]n܏dלmcn<ѭ18 P85N7d,A6+]-V(4Nji;+&0H]w )+ fW İmLD$pan5#(.$1C|}B'bHam7l$m$k+Ġ-' 10 Ôw~=X|F)A|! )[1\cݹwPH:y&e@'tk}K-wML&<4;:Zl .͌&7<ҪZ9E7ţ!6p4`H]" e a^w#~ʸR!s*ɥȎ#*Z{2GQjnԿ5mWADO,9ԇ'`95]>lby ʳ/K[ї9ZѶ%dp iq꜂!I_ۇv]i?w_{S?j2pw-DڳB^#&=bb^H)rj/Oj{Є]}n2@9 E4ޞ"1<™L#3+GeL+# Ea}If^7t=k<53xCgRS&۔i^Їq*E/M(M"/V]J=+#^isrX]Q݄H`:kڅUYt>ۜᆠln!<,Q4ԁx^N<óhLX~_7>H-x '>Ju qBxO?AJ h.}&7>rn@"^NĜyw»zy*,VP:#N䓘UPMkY1s ڎ ]y7@5I[2ERt?:&< (Tܗ+S0?㓛PqӲ`8e˾"ٸY:!+5A;k2mBcZTxo6a^yj8]RfPԄwo (ᅅEb{?X.L.8MNry{kƤh< CN*jz03 vq& {B<]53?|ȘfzyD6wb\iRYg _e˖ӭS#JFSǃ4vJf" RU@q-oiW+0)`|40¬ERk~gbY8*6ǴS5r^fӧBexSv9µ|~Te =fh .XlFn[m|e&g ccǫR| Gn_nw]Jy+`ˏ:S7fK;Gf(>Jvvn:%K\遞╒o_m@IvbYy {?9YPW^ǹy4oB  6<=R L/յX5H'5`1֍B{^f @r,lP$H~˶AjGdRU'ASxȷ#^tfeS],/ig{FW#LWnÔ0`SƢB|`0m<U^kk4у?[I8:x20To6FҁL21 RB* m6 DOq;q&arVi C0p|ZS=X{*Ss[fI.gu9I&Ę3etYR<};Qjm1 `kYm7L#_crGИ]1"Ζp\80bBtmM}~t8g208|*u(R 9!acTcpMgY&X'ϔ^2B)S4_7Va2$RSXRﮞq, PK>B?<'){8ƍi_W틜] ]{k7~YWSHٶBPH.<TH?'WʬF!)\mw֬% ^\ȋ5ȄQl\op\N;ʍdLXٱ≽TW {LRTV/_S<|LBjrVHOx w;P/#WAgSlY!lo>%l=3<%K4ZWPG+奬rה Xx2x _u<0Rr"6i&k"}.W+(!O5}ysQ\iLko)2] BXYaq;Dr.wygc ) 7hڿ,ۛ%}#`R'-h6L#+LKYKƴ^h~$y2(e>Xe9CCrF _ &3Wɂ[hgヌ*c|}Q1,+n(|1axFN5Ͷ]ҨFpzkGǠ6 VT<_l^~|ّ/G-ZBѫڌ 6HaRw dy]5O*܇uYx@  7,& K/Lѿ)E3cCXO2x2 tvc'c*_JZ)h#X'z?5Oj<٪1:#x36e jZǿ-/_3;sN'&ExXNj/8),f{2mr- xb5')0 2Qbٝ8y .oK gbohϓDgB@&Zb6&ymBsc3}zSN$rmh; OE&c +BRM`7OJQC 1J`-7 z_RGu*RNCFzĈPl CTB`rEl['XgXjKWEO]r0V4~ߝR ia=9tG/1C$=mBF"@Q”=ށykKRHܑotMG*[J݅9p_:J웣hBA5 }t⣹A-ώjnp7 V;gpɫ<I}Tz>e嫝?Vݬ \=Qa^zڹoP!OؖN_,BH.7a )rB'4t{NHX >hfb(BkP{{* +%)4`Ro olϵv/ӣ0(cz?la"<@ʻY~ᩑ?Ͷϐ Q`DdE:7= E}sE-Oq@0Œby >gGs'# 3S)xSJBx?D,<˶{v 9 ̰0pS, #g9YhW<l:32p:ko2@ה6+β6#'m 'N+@6fNNOvoead4uCV?ǢEPzя5q끔F >S6+IhRs']Rm\QF;ܗyᣆq_f)$9swm@ S2DuAhѻzlMGK&&"'uʞDlj ̥<&g&&?~ L;Xn ֚COP`X'^'ӟK~|;I{fTVw(I`¬DEeyW6;F[xSLCm=aTtZ"1p{أ2rTk0D_Ar(Ǜ>"U@RF\ZuԂO~RryBpnCgx|%o9f@zWw=*2)Ѹ䋝53h`X q"$d܏ķ5~ٮZB-"$sZq\܄%=#dK\P!K=;9mMu 3-hyfшZ˸#9[4 > &$ ֽԧ1tq7I@p[x3 ³n?s|y&4Z9#zq6v3PB?›Dtdʉ2V'by <6 E`yS;k㳜_S$6eѝN쳮BZ69e e{4p1ΤL1y/[q ylla{•eW5~-j愦V), - ڟ>xV4v?SZ5 Cw8`4c Q:.J22 ZoBIRxH޻>:YE)3vDGA_ nu΄#Y:Clh +g`4E5+qna˷+mJ!q5 Cf xկ[MJ9%)B}包vdoGͪ#' T+Κ_|(4vTة \Ϳ&{lEǽu@7OPǼO7`GM;uR TD~?f2e ] 0̕6F X«ǀx`˞hZwH J-3xU?z|x04DMrZ8ܣsiTty !F­68̂0t~&!Zgq "'cv.ВR;K+I&-4IJi<ҩLX;o2x6"GC}h4aj83čI7S[[2XnkgEޘ }Up!B⦖֗l,RJ()"rODZtKw{W]֚px+݊rsEؔݱh!lZLF [mJMjw 3@!Abm{5@?K^-%W2{S+)}B w2yR`)gMi \WMP8̮-%D^qxSMI`KuD}'zBs@pc+m>s N0LZoE ln:U[2Nw4 uuN Ch2Xq3+q؍tOiad1V+Ƃ%"ɖFPƊt٦X($k{t>63E,}` YW0O)`7=6<\ڭ|uSl0V^a= ĂpGg 9'2vS]ě#Uc-e2Z8uVB…X6Wa3 6Now|ؐayAHu`McӑcLrc[V#KYF9g=Mof}YF9kh dXΔcJf:l,?C}IA}Jl7{0>$(5B%6 CuB"Ί΄f4G1'^NezH^23Vye 5\ψ ۬]Q"a,V}v̄ɒc{\}Nu]e)* i~"1wn1aj1g͂17o[lb=fg^=`&e_LXmKX f9 nXGBj1f:bBɵ 22]"fgr{3vO%ŒXYE쇠jB'+K(g8^ ue 5c-/H&WIUO*Z ģؘ1Pg4ݰ}7).!/  N:qBjv90+CН\p[ z xu{uYLsbv.;1אACX(Qc#DL\=ư{v ~Jȧ)▁uׄkҌN:S^ukz c'k_4+Rjn(i(J86K&.Z!%]LVv:f6FSتAaQ2w"ɂ:-lY$4\\.O?/sjjkX7 (XlPNBBnv>\d+dU&U,G%Pۗ)Um3sAƒַaoK^Wb@foҳ*(Kl;FM9[ֈ\_q؛7㮲6][{ߓoZ/^ڪS|- s1'FOSڲҥb(='A8XUڧ\Aict ?V4vdH|'c}-qҔ;\Rk5J-У/ 7ad] z;ڒ9zZsSDY'cfX 'znGpW mg bڡK0&uta}3흓QL*mY?Ʒ7Sf,'[~B !p,P+W"R׳J7Əya4=1_et,Ӧ0 [P`0tAYע7yj3| {xGWL12|L3{D{q5;g@2gA[P4H~UbFap F% jҸ d닰$)]cXn`6<dzMi3oV%1MR-Obc,bi.l1vOtZ]Fx\,qfkpV Axk%4ś8T{U$0]<xh(4gA\1 >3BxRd] m ooeƕAӏzz=IY=!Fs|}[ ̳12-^g3h~eƆ6xfZ MnƬZ=Df}l :35jܭk)5樍Uv'!aB;8iC#a囯կ&(l݋ 9S%8 {g6j}SʲxjJğJ;)Zލ 1s$o<)X"A n |v;'\J 2){Ӎ&, FLަIhOAR?g1[i-!m8̈Zwc%maY>ĵGspbЉ!#V(&˫Pq>cv5. dX{qѰYϪZ$>Psm ]rRY(~Lr u.ĄT]JƐFN1vS6]2x |F%6U֘ggP P&\z;=zĽI0Ժ1EiD_S]} g` X}<ԟUQYH$.r#:@HnmbE@-O YÆ7:ƫoM,\2rlfI4q|כ<i.Ϥ{>oWڄƫb`e0k&17-X6|UK3"*,"< =I*Pm/qXӻVڳr9}l nQgs-6 !% L8w$%\2%Nxa.&T}!-VY,=,[ɠnWAYr+CYФ(_*s9Jm]Bې.f!_?;Xw؍#'[k"d\FA뛙g[׳~js/Z탇 YAO}oq)9/5wE̗~~hL79fĐd**d)/s%Uo,  }⑐bFC ཇĵd35 )E+ļbvC4HTu8xr}S,iMYʀД+A Q,@!&!c"Tg'oBFi"b]9$ H+bE p> &n?ڳ14' \2Zv3":as>YҘÈ>+يm7n[KeM-kȠKOd!+D#["g'ɦi-&DԮU*R`Yh3}:8v4hG|s#cXwo;b΃ t[yq&}! hWLftj Se7qn [:͊!toFI;@7ik9Jˬ`_XS`.G\U`X4DDglĴRXY`cf ww%6KG0' TC? w'shAP>'!Bil XhZҼKW%wVڣb[M?cV_{*yTX}ɨ ts|d!Qjt^y^trqސA(=*cn$'0>j@{(Hx1+`nC2Wv G)c,㊱zC~/iFæQ>1$5"%ڝ̲uYP/b o 7CgAϿQ?[4RPn?Jq;rĴ%7&,Drscڳ@!7A=NW }+r$02ИNrBvM= YѸ;`!,'E< i$;M@VB2SbhZ.#1,b7pPu?-X)hPP uS?Ǹ7}ou^rȿFD\1Oa(A$779dajxwv5ca<{# ^Cif |oDb $4=z w!l$߹IfTw囒wR?a8ĖW{3~O}VSzU݉TѥDEdG˖C)H*RxVVnXF1v2@fX'ctTI[H/Ѿ Jt͚圌t[r'$p]3nkͬc| 9EH$b  a Vc6PhgU4H[l 28e'4 YSja+ 1m]%cH׶BU:8]aa j1v]c 9sr6FѰs[xc8u(o (xc tnK_GlwO[^sZ@և˛~^c.֓5ZlߔZt(~V/lzgQy6Hԭ1%isBMԦ =Zd1,Vy,!x8- a=k}b2xo2o paDnه-'"LvLKðzb"013UH8,(lKS2mHCshN{~Bq}זF. ,heE}RE;Sȕ0ď0?[Vr@IDATcw{7U7@_|i5G:K9.E4qn<'S}&zkX{iMQsF縹Cnns3sb+L(MX2:bq< Lcmi}'7Gx.GlF)!L~ 0eD}` 2b+s43Qe1W4\j~ KBMTX8eY eϺǂX8X~' @uP;}ͪw}^k'h᎗Dn;eD4SiMLoE60i'ȥ0gBjl9!߭Em \VD</\9`D`3ѴMfQ"B[ҿ䦢h(4ŃdwNu/KABZ%]?sge $fY4&f9b6k*dv]~p4-+6 X@A /0\)$m{j}1sV.G߾_oB6Y؄`Yv."}DVOԎpV9x_H`'(,Bm)6MY]񘋫Öl+QGp}ܺ;wJr{>9%JS]I$.I+\wqOX|jujlhb#ht?Arf1L+* OcM1R߄7 6LR n7 s$V{+oF9/5&6n['AOKV qtk=0SsCk?A`e㒉ગY2IMLsI a-&1,wMOo4T+OY]ta~dLCQZ&ԐbYwg[%?N<3*D"w:M%ـ+R+NNƼ>[Gx\AɌ{­s[T1iHӸ&+),2v2.tެCVb51tg{퉏1a+* k"0 8k33ȋXDF)#,3s$[0X(Kj=шE bˮ+څt.W42My\4Pil4D,/E#瀫 -QܔδJ8#^;af*,Av_3mʟG? 7/aܜِ1m}J.h*fƤvѼ-^l`  ]<Ν˨Y S ܛ-yʌouKŽP!Q@Xr7ZeaEDL96A#\vUYd&`{]2CweԄ ^='k.j!}ɂn>K;&el`t4YpvGP)7qC6#e~rRѴ[<$/]!Opu⻂'њpLVw :d&0&e+6Ul̄]}΅U|e-PZH| eqlP˭Z SPo++[cktr2Vh#b5BuIM @VXL =FASO(!:on p'=_v-&96ec-¹g4:ԮޣpJ/˿`Í/>t7zoEѦKLҊuu Rƿ(ioR?Mt{r~I+ubMcyz{= RHQ{/o!'m5qun;#+ L߳V\ $B}+Ѡҫux sCr8>cMoTx ?E?+9qQݣt?.;j%&3E5E+kE'Y}`WIpw0sbZR>Ae.==vSkB` 9)˒5\ğA@qݯ"0d'#A:`] Nr›Nߑ<bU#MIkAev!gHXFܘp] Y_γd[ B Mgn"$1fƝ Yv99LF}5:q=ۃȵyUf%vxnĚ4>B0JQ W ,LUꆾsOaʪJMyIe\('FxӘMVLXlwI ŵ{RũhmEM:Tq\M3+tk"]rp]\/M"EQ3[b~$}'#4hŔ͊Mvp#.MY%7!*D:3@˦AMhhk{#e)Gٛ|PV.R2xL_,ɹ-#Ibp2!ago[@R;V(O#DgE߱J=x;L!%EY+k[Cor2NV4{{H|MkXЏ۞1폄(+ǎ ?eZ k)jxKvSm?b>y t| [n^0ETK2mk-ʍ*; 0`-Ys8݊{;G(W< ,e}0Vp)7.밿43=QcW.z .3lfZ.v]=+kIk\. rՔEVw/Ǡ$+˾@xŞca$W: `ᛠ L xmdqa|q z^ش)ٺ;>l0ЯzFpK l%R4V5A'/ Çz,U$'6KRĤä q0|1݊YCajzTʆQ3֌J6ģ}{^sSז" Il #ؘX7;3ՐS_ h~97qkCi<*b.r׳\E#n://B8堏 Jw=P}Dk5>e9^&)p9dAF>$hwg;EmLGacd`u Q`?뺥Zx{6F$=?fƠt-d ꇱqaLۈ4> KgBDh7wgs1rCcxΕ f=qve= ,g)Snf[c;f:#3d$lq.ݬƔո2Δ7VVVU nw(gpcꞀ;~%hdSWhhk2!H,RWli1za}CZ%F%{J7Nl1$`c[-UȯhR³0`WW-*c6BIX?ZI*ɔۂtBƕl3# Hb =!A74e@[`u"uwpy">Fh5-T/>$(}1-͜J !3WWm|nmDD/;sS/^jZ(ȯSщ0!)}ɊPwB?ǭ&#`Wpsu%7.ڒG(yK@ЃSU,\mfx8-wZ㠯?' z`[$kHjKc\?kF ,-"BSv |niixwA#v/ `H$y  ', K%݃@r|2ӭw+F?^Wo:5JPn/P䲧0Y($56Ċ荻uxS|0>M}LD!zt:c}8(-)An48b|j77\}+}}QFMxn='<¹ehWcF @n'-0o{2bL:s^ӱ-:3% FXw( ,$,/c2imHN4##v `^r r,U]%vEA7.ެ׳"瘱|f;cMuo5=t1V jsCbN'x&=-8#RZ<6 c|k0:Z-B ֵؘ Ĺl(5֬^8`MÍe[V sÉYuf[SbB1d%`&\-p5Χب9Xѫ x%- rAW칙X_KNepͪI[PK#?*:FM"Dy|覱Lʻ'K#\dG ܐ`n_/qcu&3}*MSܵ3r;=Bƚ 4 ALEA!gr>]*n~Ůcξ>m߽~jz/W"J')vXRp\3Rcr TC9LNGf,ق! DPu5mYLEc !2+ds!Pd%ؠ&QCv}{qc׍5¾SHӇkA20~u)O BGwGDd};)b|Z: I8\{RU; hKDs nO7`3_M,㬍zu9jVcM]n ì1)Bky~dݙ!GV$i%0hh} ,ȩ#Q17VS@3ͯ$ReOi̴ub%jDD6AiiVpdɸSWLr}`-4UحRl;w.}$,R2_ nY_@'gٍAbjp&)K@:h/1(mMBwwDݧ}7\–\Xj _C[S>ՂX"Yݔ5p{0-rOS)?W^ﺎnp>#SV_V8M^=-3^z16fK&@=ڵg)D4WZ4z? T;lV,@sgp6ɵBWq̬Q=[ id]<.~[^'xbڜ=A)p \}.<.{GxmSY.‹ Ptjk0$Ϯ> _uLkB``3LA} DŽ0:~W: # teL+RF15U0Q_J56 Vk`\V[(,SD74Lgf x`e 󊈂 .ͮՅ=Ѹ1vՇAc.HY*&3i:﵍LU3aȹwrUbm=FOAjTU 5ƜyC1ED$(frշQ$`;ү|se&p0MWuMʔwJ 7;1o?CƟY"-A{Lr_;n$Psй<C+0!Ӡƫ`Pl`Hx>.1 m<73PFƪ@]癒f|1rmn6e  s,kX(:xBd1~ bj؇qeM }~rGe% ޷j8Mxkl3w-'[M/ mx~qXiKYGl$Eb麓9ȲaEP^' v}}x\\}sz* )ƞH_`'`臹4,wG P~MGJܺ3EUƳ"9 A ŐOސ`͒t+]M1da 1T3,akPLbRЮn^algj׊5*7~F-4ǴnAI(?h1qA[AnwO]ؤޭ+m7p@#tgf""0`5\qeُuNC\90/g)bm˴я/1&Gx@o|mz"+o՞x}>t]EJk{?i20]x߹轮IDXYny={!M}k#p$ec9*&x0 :&F@wl\=!kH8ԇYl KmbK$oܴSA!X+1C\[ݦu/KІU ;SED{8St+Ȥ ~k̛騷 ر>6+ɮ~33X$b?Ety5i8aW? i4Tߵ͔tCBV;! c7"Z!3vM(s.:1TVͪ)OX|h0C@xrD3 Y**0dd,x.^<:R'Ԍq!? 5.d2M IFOV_1+̭x+1_(:Ƴڲ4oYXD׷UΉ!H Ud M%\DØm`GˮMih8)- YhSd0h!jwfRg`[ }eG۾,,",PyM*%?:Lv)ܨ(o\RsnI0˶/sd6S،!G|!\Xr++~ܜemZfRXJqeuxxqSpk,c()m?vq7_LXhJQXsq6)&8 jjV h&Q$]8(c<%+I6]<å& X6j|ZRiŌF5-CrHr\KD!AN<׵'wڞƟ*OvZpIecоt,̓kC<֟3'ܿYd1'<ؼ,,MjaJY,֎>},$J&B;pȎ7?@Ĵ d,QJ^BBaɍŬ8IiBtb>'ƒ)!r ׄIAcxg^.Ү/?hLh% u;] ϟyheOm{qc``DA=qO_qc'C '}|m<&!jI"r' Gϓ]Ib|$piZ{F,mYL!ȈM)aX9O AF ©{Pcpkzmr\{m8LGMgYo31kݾ7c O\̳j$tR%FZM ϼKx9ϓ9VB'ځhFa=?-Ґe2EawS"TO4 f0rxm=z(.j6̧]i2YRP$6M&V΅-ՙlly1#\l qRi`B|7l(^Ec(XS0}A( d5Bq?lqE᮷sEYgUXprYfc!W!L P IX;;8EONz׭﫾[Bwx )X}ds_b欖89#{W6XR~1-leYΘm-ڬ EӝhiA~b (lDS>-ܤ{&]S8d{+]9$;U]"  RTSp :uQ{3ӀIl4Om@6cYb$~֍7<5pojfpl\wu{?Ybcs/9qU [85DLI{q%ZCx8$ b.'4^ۄ=<:ggL!h:?X(uW1{k LRr GRĔ,c04+  (K^L`zE_EKW5|36vu[~ج<ѭeǫ `U*?xD`r .jF_^f$b%`aa,aL Y!s=<)}ĊvWş'+n^UF=θ7Y"qOpnܚDIRs_ \ٍ͈˼Bz۷.F9}㈎)paV}BdtA{jjdtX ~_kވ}hSU6."po :,Bq/6ʠ1Nu}^ ?s&\_"^5;у_S*C>lXel}WR!#iS / G^=4f{^]d_#zivti/Kw &((n OW:>X𪮗0턂Ʉ~;ڈ]=pI˿15an5\}A8oluu2LݫMT}PXtuBUD:\] GZ$j; ezK|'G''mTP:KQcLZ63 I+sCLDkU5ylJgb>!X5s!f4xBx%*0|mȬY5`M1ABBy!rp.Ks uP,! BMUBdi/jE[!Vp jxj\ÛYLVwbbh c*38d 3{Ln,t_ouU,e+{fw+}/c5 D[s| אEjԉzX \J&g!GȬy,$[{VV_$n^[相+<(Npэ6,iڅaLs~S.qjM bG4aFY XO;d,袰r;j5w!@Ή^,⹶?=\,c.Ȇ %^"}/K s8T!Ux0xAu:OAˇYaHC&{Pg--jKոFC9{FX._$/F1H!C@"^ºp+[%PC< ƍߟlX)meo^:Ug5X:=[13̮Q$U!tUDahQ܆yyZ3?Q{VG:OEc&_=5vpkOarH0S_EԊ ,gm/95yd\]I]7٨$jJ\W| *{.Kj/}/W庣ǶJ! hzkM |X& 7!tBS\4:bF핓C#Xs ZNWĬ4Dn̓f5S# |&}<dEY2dje'yտ[3AGC:-,8"÷𲲍ٯK!G! ~rU}Β4L}_P!%}잗_OWрks^` w)MP^Vv֕CGk ՖHxd Y>٤H-y9%÷Vwek:Cj~[BwA{f&L"']M+xf]RL1yۏl 4\}##~S|@Cgl~럫_YO "scҖxkݏيiqW/>Β+3Ta:|p}m$o {  [{X:IK{s9+Lf,lAR$#WtW{p7=+dD܍L> $=gQo뷾nci̫k/#Ct:AGWOC\36=rx`a [F_yEƑ}ms׊Vb`܉_̦aa?5pϵxb&ȏ%@WHMP2C/_C5 ..΂16 hX&!Mu,yƲ)N?k YϾ(3$Ԝ`>W,䘐 3X,F(@{A`y$/Y'n|}!E} : {䯅7{.Q2Rn?K>?u,;X.u: IW|%[.ƬL[ 4L5ojK}iqm@fI.v(kUx\|MK1)(t7ѿ 4U%b3i a Y]B@IDAT) DWfP뇻3wNqlIC!gY/Gg5JY&EBt_%yJ͝v=W\6< ^[T2{B㾬1o\*

1{<)pAgai}qܬD@sI2ɹ`mcQēl(啴Q`b.|J ˄:{QQ[ҍYpږP{~)@|c]J3ULja9x]ʦĮFUr6l3'/f*O)^KrnBxheU~o]:,_] V`.{. R2ֳf UE^R2^N3} =G{\O8howa(0k }e $f0DGd=''-f5*%d -jY|FJao& ~{}Ř{qN#uhiqBExt+@䋐Kc3xER뗒*tbHR6&41أEc!@ p0wHBʳBډcաefaV1 )VxAU4Ja͂n?XMta])KFk2^`-%SԀ4Qpde3崰F,LS Z''#k P n^ {Bi5'bLKfv`aD%8EjG\8ƾE_yyRM}AƜunSL*HD"l"oSŃexjs7SFH}%u qp>pN YEyC% JRK$q}BSuYv/BuM4,N>Ny1zS jo*'YܵCτ8owRr-C)I&@W[\;Er)0IXOyCu`!B0G)MěǂM|?L~ݠVc@Rۥe;w('5iJifB`;ƒ}( 9leHVcÒ0B$p"R۾fqX[s SEx/=%SA%ߛ{g[[6`Q)>aV ( *C CbxF)__]%k[um '%#pm0$  t_4Up)S"sEò: O+kYcBnSf$ڃRY~OXLVFzW]Jב s޸?ewJ?)"p78a@CȒ}nFyR; #i*$hLCZ$e)cd@'bD(2{|k #3_ `~v8%KXkYL!!D=eGDSK_#xW+PIY,SX._s~+D nyYxY׭f_V/jnӦJ*2q)cxPIM[ %(d0f sˢ\ņ0Ŕ×9)u}MNxX[.Ei-pS:mNo=2 983AX]Pr1LA79d3 '+AP1[KE#-IB;3aelR[w1% ` /i|Y#Iۻ}_BH0ڃGhds [KnzǷݠ1X̻粲Q)ȢX/[л bG%A,2te PRx+~"Ŭ T3Gڻ~-+U>̄L/.] 6?%`꺮?$Almt8~ٴ^4{ _ &}?ͰPΤ0+2ZLgZLNbb8ā"hbq@>RDDf{#F r`q.Y2, C"grm.dӘtT`On V`e@:12=8{x-K1;d OZb#G(Zei'yFOlf,EC+q(H$GE/։PA@o6Ef;xsG@X8%j/hy3@jiPuxc~{pLP e`7뒱0ymӏMTEm _7lj"dNe!*@jֳ nYR~2]s.uos`?ŌMX.lUK!f!<,`&zb/#"e%X`O@>ݮ,Rh R^R󣦵hd/\llBneoYǔMTقBY( sDD0Oxtwʜ'|JouK ͸%Z|`/\x])Lxf!,HE[2O4DV0 w{pa|Lm1_̕S$m[/+$|cnqh#@9ŐLeQ޴sˇ21Zug=!SWK, Ҵ]v P,"fAjDn%1W9+#+5JhN3K"X`% 6K8U`D`QI ]_ vVB&FE}fO+J&>0d} +F}lq[1V Gs⋨;91p xm6RrܲnB I|iyP's7MDZe:nf FY8A {u +.S H ND04+fD0MCXCTUC Abm7\w1+iV~ƥHa?Mf_,_i 8kf=חBԇo1S5P!( _L/%FxV0b'ܫNg[k;5& ZQO}￴9ULzR^qZW9D=R|or驆bLoILCsoRS(11^};d;U"khd.Lz{XG4eĘdQúݜlW ed{&ِ9[.2Aw.\PR`|2~-LI!y4.Wn[ (ʱR+i'a V 䦫X$E6`߅Oq} ޟsr-ΉZ})ZmP> D=% )S-@Y7df^K@>X%|kfrYė,j3H`o<)^Aj}ajx&sb7Qܪ'. _q0n+ư40j;T~|U#ln&4}^k M4Yv^=/&PefXg7"Qp,3袯E%!4qi:e¤XLYI= *Uzd0W@ *1UKޟ}~ŭ^K~JZt%\y4r6[g ݦ.,1x* $GYVQeu9"-+DL9c!nY"i-[\PПd{A`AN,ۀ2-Ɍ Ksi) )FD˴ՙ1Cŗ2@-)BY>B7Yp~kf,TYŕMϢQsG& Dm.+K's]u>+i>t7N!cj:+CLϗ v&L),N, kea辚((0ۦ YD;>x8pw6AǿV=-ިPoʠ*[J˟I8 P0V.&X`m wBSѭ D7WS_sٴBU! }$bψ T| 89T#4zK_&SD`z.T؉S~ -SsF+* [|w,YL9%43|Y[bB|GQH6?=JK'Z}or)6TĴ{D_~%=?"Mxu=K}X"cxj935u>$e7BTYHO=NJ]W-/T $gm$aj0CbJ%{Izd!c!(.9/r,()f=<nSMlVwE /d/ÓAX+tr"pVB/S3"ZՊP̐Xa( SVf:jb|I$HKSNS1-OZ cWLI`C$J3S0 g1#A|QHWWw97xUNQ[L+f*p@!-l)-U!ȭr~vcT3l sM͝g8"26a 8_5Nw>Sq2(m+D94I!gHt[&S;'FgIkŗKG6`L +.jo@!B3I%=h۸S!q1Gݬ8%"jiRkj"i Hdy3-oŴ&C0ԿOU@ha'zpREYMO}H_T7R!/@UضJN ۙRC#á L7Ob$2bJe!& qzo c `ˠ"unK YFTIf =g]S @N$MU@<)vFID*\}/˾ĸL#A0)y]N5;ˇ7Wϲ#~g4Zf|mAƽ(ZE| P*͎627sX03A,QKxjD1SB>WD$x Z{QG5k oJL԰I Lt:n'I9FՂy\yňb\ #i*8D*8VOGҴ<2$6A.u@p=59L"LZC5O7ept/l (ީvz,S s,.ڛqče7~i!lG8sBb4l˷!^땾Ì'&h2LN Zgϲ\lUu!X( 7Zg.IMt]ا_CnO!McЊ-1DM`ֱ P ie^q!D_jTV!>E (l}`#ĩ5dQbqCDn7]CFي[d 4o |A}j $U^UCtY̲{Ì>,iɦ8PD=#[b'Z7LH;alRa):>\Z#rB4Zq7Au37;8~[>n{VdCz_›jIzMw/lm`+!|U^cI_ o)T/ؐ %ML{ѳm!y7E!Ns$t/ /u pPO%IE0sJV<:؏@uldD0(ᰟdSHca pF0Lr+2qh3 yŅ1WB8zc)0;ReOj SÁ/&MZ@&bjmx4&A]_;{p Wd #6=[cGV$1G"2~]vz= F|cq) );AٷppTDﭩvktȭ*hƋ*U Nu+7fts¹J6zo{G1-zh7\pAdRG(t1ő_GF:gk@Iju6W:0JQFo{M6}$F+3Hm>?0Tm8#"^9X-AVai㤱#,oqO]WiV#$FX$t(49Ve_^5{TjxL<`204P-Ӷ9[\i}6=1GA0XB6^j1|K>^$8ECIσG8=@%IՍz !_Agkp^|DIZ|PCS&*]Ϟ8)Dz#թۜ j܀ނޯ9 aJ9([ym, D:9u6䪛C'VXQ]pdGk!L̅쾻4GqeD:4hL #rRHfwb }yc*JTBn'bSddޅh>,nc<^3 ql1&x|ŶB AeKJ{`do9v!成}g4E2G &Zw{zqHR? LSj>G &c^0gϹg{ h)M8hY1/M!ҒFG%L᩻! በ ""F\)QoQ+4M(i߳qX(#!ylO@ӽ|dp/#:M&{ԫy*uS8Y Y#Σ11Ag\%\U% \B*A;ϱ!6!WxQ0b}H~ϿWDC`܂̖Fbǿs$Y{/`__ȳRG+apI(<&IKFp>Clry(R|-.gF aLقcP _ -cq 0Nj9qQ?;[dJ6XEL9Mؔ+h_ waY` r62އ;٬kG$L*9{xzd c{M\kq&-IyM:n?B/XXK9!zuhwZD Hy M ZA/݅ Wă1\OR!vgO$Zga»%}ؿ\UWDyψ$GÜ={4tzS`]w{o8 ovmϲ |`M8BE`E?Hf>s&DaK>棎`6;/Ϋ`T+<]Ys>qFIlL`S愵})cSĽ`},+"t"FnA^e`P"4P"v# P3Av p`"yICgqI yFD y/9$dVljB*TuFCcEU% `LFR^,)$OUꟼPDϺrAx5u`Jd]J- Бq-㔪+ LAkF~cG ͅVDpaM21WVQK]vXuB`2H6XbdS8&GZS;n?z"ܜwڃ5(+jv(90N. 9?-=I5y#1}||ɬ?.9ˣlHq782S^T7C\1ĜÎڥ5OJ: eFmA’W%JI?!vPr1TqRY"TtB-GLmc =j&RLj?Xjށ .evR`> 9̎ݔn"c9.o'"ƾk`![C/->Qc՘+A]T5آۯEWlefgOr|C FK 7B![0D!xp%7f=BEeo}hGH_,`dy>` rE0<#;-I8m(my'WQbO(v+d'QuG"@}ѳ&nmcW'Q(Q uF+5g'8:U`%(&%G_.e[;#Wpx.%ܵx} "vbwc,%݂veITτh~\?j> Ls1! ѕo X"cl<>sOà"{=IYzo6/9p$@Z}Q'`_&ahnZϿ@_~&G .w>?}ӞٕS0~÷h!UT+  . ńճ r2xiѦǽ P0 +$xS;_xI+$.P)`gUTl= h7d ; +!u\DzEAw`)I"@?}sdx1GˏPdv'͍0Y<=Gɠu7Sw{hG&9طECp!I Cƴ\Ǔ.]@{7& 33)KG@$MCA AW 4ט? 8sBH$GNr]՘ײ8s .D#Qj.)=B!8"YEoؗS[0R77m.vTn7WٷuB"-EDrc Bn*65տL~lݍ+uEmT6[aBbH_S6T !x9;i׽D2/ {w5:3,r'-Rʽ({B^;Xu!= t1d]"Z;ڧ?8#_擉@P[G+"8NLCLwF[dS;ZFr]Fm㘿*LaN0a_' 55u-fǸD\ z3~ZL;kY@{fug"ʦ_"spdsܶ&k)qS @+nx]-#"v q%';\ lM&Qb1 2zިI'$JoKYF!8jY v/CI#<$;2W`riȲ2$ {$ʘC$aB9F\q-! R<ǀuhswM*5_vp qxD#;Uv'xc7kWe8qy>|1æ Sy0B16M7ZߑRISq֒\>sՖQB bUBL-j@{BNg.ym/irH0N}*QnT].vkbjP6KIGǸH-cBYW5҆_\Ɯ S y't\#iߚ;;z9- >/pHYui2.ĒbhKH3þH 8(u%U IǨ`6Gl&5bn{#Їfer. :'XWxNZA`f dA*2ZMuR+Xp\ɏc5^-0mΘ9 LT]"k߷ewkKTdžĮ iIR19 ugeGsHB &T;⤟0@L٥ uO]z)۲HU;^ڱ5ƈ3~8qn_*pTR**9/Zݜ}N r6,u\>(u2)l_Ds4|جa Nr0TwlNպiE\&f]!f %V!v$ i`k(HVJ, =pxy$_kas1^?Ղ ix8b^ߘ1GIiL^FjéEw$Z`G-;n %m֯9ayiNO/:=q̙K؉s*Gt.-,E])"Is(H'ja~Y$G!xɾr Xyb"H5grYjN>1Hl ]L@: 3d VkmZ=bK|r luŲ&^ 65dg1h[`y E`wg0֥ŜHQKl)Q`&.͘@S $. ^lz1p[[DV!̌hnDȖkQJVDLyWiWؤ*rLF]o~IȸO]PX M,aU)l8} SX+{^gv&֨2 ӬWp"J.4VȖ#=MsZXXrKh.HK YBzR13 <ӆ"2r<$rbq-zPsZF#)yڢX|yA#RNj0Ki) kaRKCMߗiA~XSnvb{]hiD|/A+5-``cPR IʬNSQ I8q[׉<^E5YhDR'Sg4bLT.zݤQ7ݑ2w"b!Lxz\Kճf0[s vDH yIJ l"|AߓT #AhP%F2&" bR0Gc oAS-({ C85S0 ɭ/9 &qI;E)B1-6.q fZTb#1`IuoT'9P7:bqYaY! 0l ZW-g0]qK-"Zqr!k(8Pג DC۬SFKCSB3HA)1W s< ǣ&j⫼ze  vܸ-`/ [5(=7F9;ACf%#$34k֜ 0 lZtk@3bz@IDAT5 95 'f"=jDv~dF(R գcB ZWNJ! {M+/@HU[\zJBx.whR'h I-5Ga @28A͋OC(l33f$P8+v6 WGA@ XhFmGD~HD%C FKwǾ]*t"DyLZH b1!D ec+?"mR!kX꣈aDs2ւsS y8.o∣LI;ic[ J"𛀹JaH@R<X_?*EdAh0TĆ-# ZBteB# owp"x|G|jAMy@ }{|J#D&1 )!>VK Li&: hlp" 㔥0V+WIDm܍:}bX (EI$Ƚn#2bT_-,$\'w[?blNB# %ZB2T$vv*bGY JP*GB몿{wfMi[K=Q(Dsu8ṳq[@t OgD=%jΦji>wQe][sflM #uN@?[xI-L=ÜZ'cJ'-yF9#rök18e%>maԑJewF\4@RRR%]5+m#XJp7.sdҕ3$)IeK#"T#el!)٠{EYy荁x"#elQ ʳLhDn(Rs7 DI\Yòw-Ě26놸Ա 7"ދʻ:XH㎽ Vay]sS[v^ɜO;>Brmٳ;{:iD8 B!;8M#~Yf䬲'wT3ꐓ[RBUՑFmU0k]JeG[AsdS|9u[!6" B*dh@)tvQO5g?*LMrT'DRpSg,Iˈ1gAߝ̣Hҋ$־&\16]\,G#*SHM 8`k3p~` j,h?wԞ$ 6Ez/%:Ϯ"2 $!GRN&iO9!AIkNk$ẋjˤQ`nOM :Bޢ _BqJ!^cBQaǠMdFt;ȶd\Ӧz%CꎕӇI;c]uQ=-Rr-|ޖB9 "BIp/ `:WavRQb$Ns|O2X[3#ٌyDsR?S!ͅ0D,tӧ.\ŐPNt zJLif0{Nϴ ^ZݴŽG4"UMyauq>q}}IlNjNV@q1;Bఏ'Z+ruId ؕI1B NCcFyk(+sw 4|;9< { E*'-dnWC8& *B/& "*T6MzA~ Ix{=A%s:z1T.20 u~"&!"vœ+K7I 9 A$x"0*N 6K҅ˉ~BMMr@*ժ4_qEjik8ng6U2*k8;Q(%6G*Xgdk9)j;WdGBJΎ2G0F=D;8Wgκ%:'M0XcRSѝBR3"|TJ 9 v%G#N_^3bt߼G4TϤ_o€8dQ*m)<<s+ioظ9e$ !&CM=Ry}nqg3snkKhES0zz [H MJf`q=Nm~9ݸ78=׊O^3_mT.{Ibhsz`!\#w?Cr(T2y{O|?K[/Rq3 sj#4XNpP셝ռ]Ƙ2;3 ^!ez}f'TXk%]倡 oX U%|ʚH^oc 7J#~wgG:hodnmlXx!cJU$Y$Ё 0ˬYڱy85i=1SЏ!/T8Dz<;ɸ62]R#pRCm6wW;}&^TQ^leE`Q@jaԒ| T ;FqW?S*KXQZenTŜC1Ŧ6%-4DrlKc$) 8( 5OOhyr F/l- S}JstEåjI5I4` ֝LoԾvwr3g!л,sٖ[$cDQCRP2BqdECww1YF> ^y\5wBVP5#sC(PHVۅ m_ Hmz=\(\s畮? jcDp}|%nO3ͱ`! $'ƛe7@09I]G9+HQ?yaČD,8E\=M5Ӑb;77&N)_- Eov߽_$QvBqnp/О/..#( 8jpHbҰ5gƠ?j[!OlS xzJ{[c:oE <&2`Νa2NOa***O8KcQK&#G/E!FyOx}ᰈcC{y|1QTg >RoCMS>C#K$&Y"Du ږS'(E"PiB7`c=- ID@Wm,:$Bm4R!D3)p oLSZ[N/C4FKJxA*`d{2^l$}WI+<@I-DK<"] hbX<{A7t"E!"o Zp|rę lIڤ Bg86 9Rx >%b}x:1Lշ̶ mRLF?I"(4<p.b 5;[qU*;2d5L<͝L ;WwG)!:kL6LD}c*[bֽr*S@ԕg٪`CAdJ_QNⅭ?vnb8""~LMC%Uޛv6 7w 0Uh`Zq3_V0({ժW^_$R șhKayҨ'zܜ!/4CBR( w;5xQX{.i=S13yHRrxjB.?>PjbP@rXx]K)] q+!uIG{3kĶJPMBTk fLkmA'Q1=|*.u갡e1~!&_%\"Qy?;}ND; #~0*Iksj5 CgD 4:ƛ3N;Y8dv'~hT1}N\Rajp(~Z#&]Rr-`MC3II$yϺ+rؼUFb qWp=Ԣgdǰ/7 )"'QCkﰣQ/`Ep]U<=!xk+f!m5&;hTkv6%>4'D YgSI&!C(Nɑm &24]0ߣƢ?2GjI nV !84wQK)QP xPW߷&=%<ɬUf) Zp:U4n[3GH@ً|;{tHJ$d|R]+şy@yd$BD*C%ŭQF#yݥ.K̈́h!L2UW@-ػ!k^ Fߎ0pHR쫗kT?]y}Rzxh5=G`dJN7 Cc9FK~Fis]~3揠D1%QJf/n1CϝfQq#NeJ]eeUx7L-uT=u׿_ݾR߅)ssMϽy±RWC1º~ԑ"H%^TB>$,}g1M@xg&:4v➷0ZP,E N%xt<3 uRɜ?EP'Z\>Z ,J"3Tp+B?yTN&\FYX1;M}v2' ;޹Z{"wkT`}M]Gp>DLϒnȈlA UZ}I(fQ麣@G\'GoWllQ*=lN fVh/j2{x0S\*NKDv#h~׺uTbʠ#':%=oUFU;BzB]ZYȋ֞+ K8J-@T?Jhq2g"b14Q-/[_Cl&,J|31ٓGОёKf sžBxw YNQŠG[Oc/.'K)z9ZߚiH-9evQ0)pvjI4qb`0~!lYlpzX7S CTlB;Rs 3b2[MH Ӎ)I$"HojIy0Zf0qmb[ZTy)Gp1KܧqLuɀm,H%aٖfa'sڋ' ÀxSvMU&/,VvȦ}+wj#m=HD楰 Qbi՚G-L-|Q T0`g.!{pxI" ܃Y ٫)̓fj~mBmPOlL]ZJkk\[NbZ z4gL U;s@u 3l2C vƕv@-nKFdZIt  񿣓=H:H-O! n"bgQc\XkDd > Fe4G=pz{-eF z!BeW*cʰY9H=(K&lq`Jɬ!/.-)bIԢ7b`DMG=p0L/1ux{x}&nj]L-LI;@@`drG р*k>8L*9b1aCTy -uӃczA<2QFAp<<!!97s[ -Щ#C܌s6 .@ $"&beWR#}Arx*S탤;҅G4'Þ,l/#"[(9B#0B 9~TF cC 8@‰u&3 _/p Bh91BM*cr}.#<ʞK)tgpmA[x#+:v׈{^s kHVw3&< Tޮ+}'ėq_kɑ$܂mƈ"SH)bqm.\pa ْl9!Uwpj6%ђ,UNTB܊cKxoL"nXt8oLYqyb=iH‡mF0x[/-&^^y|12kn"bhr;9( \nLsN6Z͵]k.Xyv$h)^Do;qad|uH{Ā` pG tX"5Cc>bF3uT \gDahI4 ! hVM6=2.. hzW0g&AOb4$" eGI zjn_GHƱG$P6/xXa1[sxb_#C.sZHy1`L~zDi&d`t=y"v!:~/*eiK"!ٔiłO&(g>jؗ`C]$$62vCljG:L&dY"z)HKŭL1 X&Zߓ@zgũ% s4D բ~a;䴀hyRD\E ϑl;l(%bDwRel3ߞ Q @v3:I^<`G0BOUA'3to<<B%uReW9Gl!;'sTSڰn p4sm];TO9\Oi=~9MrG%.h=' nbsʖY8 S7|)t_Bxn[*>Mdwwa@C 3QoN95gud9ic^XMT10i+}\Gm|:1I9Ļ#FkHT]^8!8s@=)I\]T‹3S4Ս "qeb#:!bxtG]I7D[$Lǰ4BU8jϬˆIψ9܋:Oh$e*4X\v̤ll&BzaLE=-4]u1q|+oBW(`QM5SA"NTTQ{ s{xprsB@k`2^F#V $gwg[D) 9%s*ֆ 2^\,Dz`vӎ64!j^Hr?T+-^!nI4 ME!Z y᭝#-u%=1$0#xIaD]H~>340)jWX]t!u=f H#i0!OP;KMa:ŶgH}b0$@2gN@3Gw#JN5xŊQq2z6a(?tF(8O[,@iA+`$#QEр+BI3#w<>`kS*5D^u;`](כ xFpm@OG5^iqY̩1ZEZ$a7rBC;4& ĺsuC=A>ɘiݍФH8靾H3;GongOd]Jd1¢~ulKΚ2T9'go5A & 4$nY 'M͞ 9…R̛:k/}#u$:s9E) }w٘t;1 _Qi±4E09u=5tNΖ;*0cM ǚ[je{_JjH[5 x!g.{{gE7w}@ŊS$;„.6$D}-l>mC|zS9?!"ҸV FEOu M FX l!i.TJt7%]K1fBЊRsN >!TSD„S5=Rk<W ƹ &iUOeahf9L)$vZG[cۿGXҸ[ ݝ7(XS0900X {[tb1֨Q1Ș4<8/Ó#Ǽdu\\aۛ m/)K:{S8N"c"M`a#v&skQwBb@cXpInN94?Lp >x^Bvw$Ɗ'OI |.}.c6uG,>RX8o-c .\&cT ` iS55TtF,6'"`mdg#R|eM@g6kvd@#IyKQKke_;li8S}wT5˾(C{ NjM<3oZh릐4TFuWQC$\]7HVJX!8D飅CKZ})X0`TT]XnG'H>1 T[\H>\ߙ'd$ 83ΝҨxWeP*L4925(r`>#" /SZdϫ4 Nlc.rG1Q8¢-3<$+i¦!qi݇-/IlJe$(1! 2u7Dc9w90E>cn2:o'zV}yͰ 즥Dϝ1z?%Dc–Gk_U$q hcc0WAI} Zl l5ۣVX f6K0b>mFn}Xsgu̓ǘ[r!!^i޹`}:A51Gd`1!)%QQNj \NoC=1P(0l78Qx; _-5bv< 32/•ۓŒɓLi~F1ج0qy%O%ъ{~~rgLWqpeZ⌮l~YZ0!RhoEd$K"#1ۥEf~mmSa9MYb_Si^<#ةؘ85o[1&*M]!Ӣ[oe|qIeVPk텴dH32 j *Dd6NơFyCdiD;L␾oZ:f7{ܨ=.3NO⋷nLK+m* a[ԝ^/ Ӈ;0`jAajޑ@g,>\z^1͗r,FXIV~A.BVEJ|jBaaB.aBku "$j`s$"r4r %z8- ZC֘LRryh-l88v"RqJ,k @h=|߈K1%EH umN%K{{^;cK2dG0?D4ÿu_Ih$sN' p#4Q$a("5C1.d&l_jOVAWMǙt9z"u gT+E%G9,`wD&8uFdq&E51i ie W`ro#d\E&Rgs64SyGŦ !W-Pu6ytt/[ޒ3!JDHA?T`,YyR?dD4"y ST8"Xe^lbK<!7~niA 'SHG͔Ԩ1ֵtXHWmJF$ҍeTcךsZ)$s8ў|̇4u/քF*RϋeZ4ICGXObij}=.mk' -{RՅk ¦d g,1¯S11)O:)<aqԞaChqU'N[*ՀҺdvԴq1FA[Ҫ7#ZQrZ*.!0xGqp0MqE*L@lI-} Aqs L;>%r/6c{zc ;yߜoIm܏RC gI,ċ:Q1K" h؝ &9ULRy6usW#3dR(-|"w< ̽Q UUu*g4:|M ـ}bSz1lI$DuTFoH's̮6dKB~ صMiAlt뗔o` @,!itS#`IL-k^]go*`YWǢƏE@n#+K FICR!5&*d$D ZHVEďPviKݵfӜ Xy=BhZ5!"GNٖG .*y^y $=1bff]W ƀx.X{T2>WZdZӥ"6LRdO5\F9.8pBOZj݄ S5cK5dD/vtT㊀ƦQHڞ!T]2靅-wvDH eQxmؿsrl!21B $1¤JVA|#ILQ}ĩsN\?03T.9p8bI7*T( Sz+1 $&ZSIwr5 pz Thc(!DUN;3gJ 3| %o?\?Ե}E a1w} %`# m% 5 |ˆ9C۴K}~?` ;CUņLV'HET38uf=p3'<Jf͛W"QQ}mQB .3zγoUMƇ1Cs#|mFyP٦4ó#0 ~|^im.LEs!"gpAb~deϾLܜ*TKY$BD 7\4&h6ۤWnLzuwEsz>l6ς.&զem2cɷ cnxL&1pcIay"ipEV2,:aTۋB5]N< "O -Ll-Bwaĸ?0J'I8cjZ̎F1 I}6Yy{r8;aoo Χ(E=2>~Jz2kk<)G+#m1I#D ;ߔ48!L3E<f*Wk rV-#aRܳiVfgl݀p.Dx& ;ԾlEKkL9;xRF"Mi/8fBoҁ*u=ed*Uh!`F$tpY:>ph]7+_].Ƽ5z.Lz>]l1D!^[aJsMj0ԥ]o2LCF u ڮE1I()`%?M,EsI+7@0g=7}M" 8u>uUQAaKtX,"xEhҀt/It$Zyɣ-EUehrW9ҬYea hCg'w9"wN"OrK8b aSb`2Mo0}WǽLK LU†nI#VH1ZX0b }$K T<؍cJ'\M`4zPsڝ+xf'K!"n p]ҵ$DA7zPOHa=bqnm~Yinʂ}K5>`K=}>`u\톎[nN l@eWt1.x=>f"Ti~o 1Ww{:F4C $lNF-{l< )|'05s PF-E|bqZ:(dnpN zTb^sD]3B+3U7|;:#ơ%gI`ܞ'هM2h%¹%dWUFls:)LX}r !u)h? z,U@SQp'm" l"\B$'F>:.-#&b% q?r@k-N:bC(#vT{k]I}IbblL b^6E6OMk &|s7ǔdyVhZKsۚ}x: ^Aʱf"΂s>Z> &6[\ؚ1eĦ Og!`dFTS$UB L$ۢmy~1@nQmzّ+ }NrX,8QG-tS,%gޝ6j֘hgK?b?4>$8(y̛BWk4JE,c#AH{fPDF궎&H4 V" eB1I#5b<+3BETmhK{Viԉ8{c_ yHj &'5 `G-'08*]tvtPlxv0 .Iɣ9l{{ 5 {o!NX7gSl]uU l Q|zHuLb}"ԈXi n<ˈ*T .,EXSՅ0UzXnffMSsԲ c qpU -fMBn;bHyz\C![=O_J1HRQBz?DHL<85|?n|0_mri NOPVK¨1L %ibh_:4?iDEX JR/D+l?L:B92fΜ`&Ɇ+ϺbZs[V׵X~/]mNB 48UJ.bN`2FҐ&%M!d:ߡ72 s[f`hV0H,VHᢐ`S6>C>C8`#Wum@@(ujB 7"$ۛ*ҲoݭVf_gGRofeSdd N#h2wYk/>cF1UFVOGglҍD1Tج P6BZ`7y(g4L򻣥`CkH t㚶g9li_xD#KpC[?U)32[4uJ MDMb{Ƞ0pvEX5MŅn !iM`u$HR%7z\j'm"{.hϞ!_́&4Z5I?bHM=ǤBRfV$ H9n!?u 0ږvkd9wxOݳ%. =CX@=k՜[c>dߍiHz|7:sH*T{[h}S9qv &88@` Ο~1\Êu2rѤGE[is,"ET!%aB'I&ٍw a=^ojz9DDl%9$+9.}P[wHm^:&dxm"lAWO1 Y:2#Oݤ bfݏNB6ឝdϽIRT5xNc[_H!Hu.;8AjtڛI3!SXd >5#l|[CThĂICZ7!;>L.jh?Bf˜H9L/xRp4qPfm{hģ"LW-hE w~c9wF pF-[n>HQ{ G psbp-A]c Qk p)Fe(PCpQ ;&qnFʓ3WRuV[I [s'z}_/"8+$1?药kisDIv]H}Ac-<9ok$ d(pka-2$8uMD:s.-.l^Q=\BH9G:Ywmĺ& tij;5lk9qsٓ5> qR&:&Q6 JkM5| JcdK#0Z>ţ:ZGuV|$VdaЙ =bt6?mJ]ZB=w<jy2X ihɬwΝbiۤ-DE,b㌪R5T ή*}ѩ ZzJ9'u@Ds\*!8ҼTnNg$$xHgs덢Y{PKa?B=56Q]-LN*2-ymm I&P[s/?^^1L*(Ty- M[)P^| 90 5SK7V1@+G<V 663DsX6ē]ycy PvA$1˼=sK9N@aR{Eo5P6ٙ C" tr2?&`2؟ < @5!6y0`pcWT3ʹg}yqSj(-[Z^*VͲ-O²I١̆=ż(o/D5%ɶWx%l58Ahkh9s@ɝYQMsIgti-eF`ଭTTA"ˀAI);O &lCTvcHtB!6UI/'qH:4v`[\CNyko%,ܱ?QvT^궕%B5M؇k f)=kg,LfR; r/1BK,;`C`Rlᇝ)LY@Ҡ9#0% %GfwC혆o}Nt O;?Ʉ0ǜ>riǵnYg$HaSc*z0rA\&ק_l `1jN`ٛzc@DOc\mʞkpRq:)8$X0'qټB MJ݈i=ZFx!y( `ή?M= ]V6"ns<'ZRHhq>`EԟwlXs"l S[jRH+yG)/pyX4U_5lܚRaA8OAWNTU\4Ӽb*LÕ4' ` [ǂD #dӹ %M*sJ)5wW,R.n7([˗sOArB*/z\PA| q%mf[#7!^R/ SQ3v@`"jp#0R ^b-7kZT.6yd<"hlr!ن.P;8ּh$ gg.}:0B$-u7$D%WxLN_:i!"ZWD(6wScqނ[|Z JRkO$:9r2#I6.{vXԬn2 4B>&<"ā;6a+vABca:]88L˝`[em "ըx3 pqS(4qnNJ<TV*i[{b[ !ƞC^wuSvV}gXCRLf9bFmqFIZ^䩮Qђ=_F1_fSڜI )$D.}ŮA 0,!VZ2z]{$#RbIN!.gGlEڝ%o%S{mb$I X1 E- /XɱZ9P{n8ζe]ں-9ʵAIMỎ#1mA{ho#2eHHWI91 w9|*/ХJQ;ՅzG~+Pݕ8vRy^'MV)̋i3ώ[/mq/7{ }ƀ*NfD3E to}+8@ =cS HCZY49mq#&{Ftq `uQoiZ*>AŸ6@0N2C*9vo_~kyOM I+Bu3q~k׿7\40 bp#fDq@HjŮT|#8K-L6F,8y,R[PEAv'en .+ $[if 1뛟?S#=&Hw)3a@ :g{|7&O;ٓ戜ĝiI|.J%!(¡s^R 6(Ĕ^BqϾ'dPfҮ;%=ڀ/W{aa. NrDs/ r; wG榅9|"}kTZ* 2Pg/vb9GXA2I*gguqLj̑ Er:L (+|OeaޥɨU 7e?z1I/ ޚhjC  d*ɥ9a ^WLxl jUa#H7BhcЄJgq09Z67̛aOb fg~ EƁS-LtYj+N>5jH@lOptZXH±HҀx^%t]![>u^EᄒerF'*'Y T&ECku6 "NM*C]5Ik$EM:19I==gia1BLV=M*Sg/7"ye_e3nD6&N vק` Fi=[􈰟~ yI9-IcƾU1BJ" )nHoR jryq>)nӵ7셐F4| 8c=.*T%a "0nR R!!pb3$q{57H*ٍ%a}"EC6vcPIPM΅ ؆9bS«cG)֜P=w #i$> M!01j0;Mb>8"\PʞSJ49֏qL"u?雄iZԪJpB2xOƀ8qC &ھj1?'I#0,aFhTcr*[gmRi pR&lgT M>@#E`GL_CVҩKc3]6gƵl#«UsHӊV;"Fm`qL/N63u7aeI[j䵪>H{Ņ\%<LmпyDk*BR_8FxWQm$i d6MrdWZwd):{^a$hDtM+MVЗL # GQsC ,I!cfsW6/͉=/oלar`^]=5$]@ n=g>=ޒ!>C p>.YK^xdBھlv*5٬UUP:=yɅ^2"N9GH<8?m. O5LUl8yN\aPt\@QxyJmdZa0{ PVC*7xˎE}P{RrE R_]g>GQё#!vdgk6lrټs?Aa, )U`cES7)HEB XF}FSe,*qbj(g@9xKa}I!;"` `` $(n*(uzN95u<3MI9.<~A`T1m/QGPuAh$[Cew^2;QPpPi܀6Qp xZq ٱvLEofqXD@ݞ)@;LL9UH#s<"PEm)1n\*Ďʹk1F@`%Q%f霨(`2WXZ?Ɖpb2N)y[-vձk|'[[s:b"JxbQۆIHsJ E RbPGcˬ&L%"aHԢ%~iḺK-LGl[܋kr?} ,!-MWh$zC1=o/.9>Nqo7 B$'SXf[<&U#Sڙe+7yw8{؂b !~ {*}=P5B=W3,&z&hĮH-ZyƉJN -NUE{ !2"|K/=Rdk]iBBZA.R\et\NzXf(-K&5T%#lv$[HA$g *=d9MEG"&B: ߑH-B:BlK&L q!_ߓbwkjhr#\.P ,Z_km2ypvs]D/EIydhR`cĥr' w* I9PcG;qiv3FALILIkA%6~`-!j'd&a2v4nH230>Mm 8%5OzY&ĸV=5RG2 ) A1WMFT,kY&$,ؚ mє%jO0=ś +h}f72kquPy`$sRo+`pۺq7WMaѡ^WmSخ*tř}lQDŽLKri!48@? 056&x+I%/2؇4~E@_< !~-@z#)#63 H!_ d!^"j=!'~sB qfI'M,I b5hmbok!Iz ;C$oNO`h&jWXl# ?a]gV@'E BLVc/ %86 /@/STRLkϟ}q>&5"R[ 1W䡊r t}w=Ȥ3{zM="ZcEY[ ]! z^"XR8#`3Q+Sab&"Qu9EqI*A!P13P^`%CΤi܈ ;O`j^rlH/V'\Ϧ*[㘨uc4NvAZ3)9IȉB${ "8Fͼ_gc``.u9IӦӽќOm+ r;>%|K<,pRї)cl[$D_ Y%m BZfzΌ9p~̗̐m bBǦД8k ˠ% &eG@QX{i~-k%U 5}D+- Զe:zޱg4['gNRed$-xݘ8 ͵ ˃bPB؎@&*RG8U/۳0VpL]O=~pFIgqT)Tg4qLhVrIm1FFIuR+TaO\?7dzأ^j #jlh jTF<,}g{^ʽxkIq̃Cҩmnõ郙2 T&x57ۨrVћ7zHsy Czh$p8~1Lk9ap٠:l]TKؼ\TS|7SŽnC I(Tu] 졳l,Z[n!0끸WœIE>W!)[qiGk#ຍb1;o. Ї!_G/pt65% wq%xN7  5d^w8xYPG(# >V꽸ciKe,Pׂ5{n'[ׅusu;,2+!u1xd9"U#mZ!sgcfRTm SW8AN+ESv_'pUM9AX 7ĭ&Oe,§K;. )MWmkyA}'q*Tlv{[#o(R"v"P})F`yiAa%xmwsF~/ ʟРlA8"&=@_ocY()¦x s8p"!0v)&>BTLB 67#2P4Ġڤ jΞWK{jI8?}4km%O9W@![]u@޵͆y{)._@"ضU~O5&EU ĞwTaFB"i5Iۏ`Fⷐvr'e;1y[SdI EX+5өFx`q9O4 7_`הܫYi//zضQx̎U4uي]NoKt _\kQU5Vf<"HbdxU"@Y|IS{cӅPt.B]tN@RK0$]|p 8D1 BΟ;YgD//B(M &MlWjmίGhns ?;66L]NrZO ku& u<{k-פDŽwW$[zIz^l5ǫiL$elDƘUO;dd2TSU3vo^zb/,c i lϦ녌9u-i$W08g^j+DAt ,lRQ錠{xluCLu˦I=Qo E)Gȳ3#-#bvڊBq1DkhS{/?*;` ULUjPI4 U4ٰB!cCc.bTiғV#á"Qw$2368 {  YrN#[N: BA<~ ?X.ʮݘ;)~xLxyRxm<[ls$҉s6Z#)l Y19Z&q$@eAKSOҟz}]CMXx7]Ѥ5ۉ'' EOuio H(:9BT!]z7q1ZF}jD[&s,yb!n )l.iW[KQˎ-b7Ӏ1͇w.dFRƤ{ `ݳ,S Ec'guOݤZyahx4GXGb k 8~GMS2!2Ƌ"[@ 2>7| pŊw3o/ÒtbțʗHOfN:D aբpb"S5BDDqʕƍʥܞ˳By|moãH+E8VPHlj҅$0^!aĚ{"Ľ[pNXX&c_Ձ7Hq[MمDXJt7`sj5nUɕCcѕGk( Td6erXe8<~Sq!90/`iY;Ts}q%&x| x\0n v?FIk/9YQ3 sǧ0SSU5^ 8cU%>-'k);H0bY \VezhTVtJfP8R W4>*)pvq{|aO8b1fj`Bu +*Rv}:ns{WKH j=О_-cs4RWVBSjSjo(ȍZO YT?YIENDB`chessx-1.0.0/src/quazip/quazip_global.h000644 001750 001750 00000003216 12223260306 020711 0ustar00niklasniklas000000 000000 /** Copyright (C) 2005-2011 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. */ #ifndef QUAZIP_GLOBAL_H #define QUAZIP_GLOBAL_H #include /** This is automatically defined when building a static library, but when including QuaZip sources directly into a project, QUAZIP_STATIC should be defined explicitly to avoid possible troubles with unnecessary importing/exporting. */ #ifdef QUAZIP_STATIC #define QUAZIP_EXPORT #else /** * When building a DLL with MSVC, QUAZIP_BUILD must be defined. * qglobal.h takes care of defining Q_DECL_* correctly for msvc/gcc. */ #if defined(QUAZIP_BUILD) #define QUAZIP_EXPORT Q_DECL_EXPORT #else #define QUAZIP_EXPORT Q_DECL_IMPORT #endif #endif // QUAZIP_STATIC #ifdef __GNUC__ #define UNUSED __attribute__((__unused__)) #else #define UNUSED #endif #endif // QUAZIP_GLOBAL_H chessx-1.0.0/src/gui/engineoptionmodel.cpp000644 001750 001750 00000012011 12223260306 021376 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "engineoptionmodel.h" #include "engineoptiondata.h" EngineOptionModel::EngineOptionModel(QObject *parent) : QStandardItemModel(parent) { m_columnNames << tr("Name") << tr("Default") << tr("Min") << tr("Max") << tr("Value"); } QModelIndex EngineOptionModel::index(int row, int column, const QModelIndex &parent) const { if(parent.isValid()) { return QModelIndex(); } return createIndex(row, column, (void*) 0); } QModelIndex EngineOptionModel::parent(const QModelIndex &) const { return QModelIndex(); } int EngineOptionModel::rowCount(const QModelIndex &parent) const { if(parent.isValid()) { return 0; } return m_pOptionDataList ? m_pOptionDataList->size() : 0; } int EngineOptionModel::columnCount(const QModelIndex &) const { return m_columnNames.count(); } bool EngineOptionModel::hasChildren(const QModelIndex &parent) const { return !parent.isValid(); } QVariant EngineOptionModel::data(const QModelIndex &index, int role) const { if(!m_pOptionDataList || !m_pValueMap) { return QVariant(); } if(index.isValid()) { const EngineOptionData* pOptionData = &m_pOptionDataList->at(index.row()); Q_ASSERT(pOptionData); if((role == Qt::DisplayRole) || (role == Qt::EditRole)) { switch(index.column()) { case 0: return pOptionData->m_name; case 1: return pOptionData->m_defVal; case 2: return pOptionData->m_minVal; case 3: return pOptionData->m_maxVal; case 4: switch(pOptionData->m_type) { case OPT_TYPE_BUTTON: if(m_pValueMap->contains(pOptionData->m_name)) { return (*m_pValueMap)[pOptionData->m_name].toBool(); } return false; break; case OPT_TYPE_CHECK: if(m_pValueMap->contains(pOptionData->m_name)) { return (*m_pValueMap)[pOptionData->m_name].toBool(); } return QVariant(pOptionData->m_defVal).toBool(); break; case OPT_TYPE_SPIN: if(m_pValueMap->contains(pOptionData->m_name)) { return (*m_pValueMap)[pOptionData->m_name].toInt(); } return pOptionData->m_defVal.toInt(); break; case OPT_TYPE_STRING: case OPT_TYPE_COMBO: if(m_pValueMap->contains(pOptionData->m_name)) { return (*m_pValueMap)[pOptionData->m_name]; } return pOptionData->m_defVal; break; } break; } } else if(role == Qt::BackgroundRole) { if(index.column() != 4) { return QColor(Qt::lightGray); } else { return QColor(Qt::white); } } else if(role == Qt::ForegroundRole) { if(index.column() == 4) { if((!m_pValueMap->contains(pOptionData->m_name) || (*m_pValueMap)[pOptionData->m_name] == pOptionData->m_defVal)) { return QColor(Qt::darkGray); } else { return QColor(Qt::black); } } } } return QVariant(); } bool EngineOptionModel::setData(const QModelIndex & index, const QVariant & value, int role) { if(m_pOptionDataList && m_pValueMap && (role == Qt::EditRole) && index.isValid() && (index.column() == 4)) { const EngineOptionData* pOptionData = &m_pOptionDataList->at(index.row()); (*m_pValueMap)[pOptionData->m_name] = value; return true; } return false; } QVariant EngineOptionModel::headerData(int section, Qt::Orientation orientation, int role) const { if(role != Qt::DisplayRole) { return QVariant(); } if(orientation == Qt::Horizontal) { return QString("%1").arg(m_columnNames.at(section)); } else { return QString("%1").arg(section); } } void EngineOptionModel::resetModel() { beginResetModel(); endResetModel(); } QStringList EngineOptionModel::getSelections(const QModelIndex& index) { QStringList list; if(index.isValid()) { const EngineOptionData* pOptionData = &m_pOptionDataList->at(index.row()); return pOptionData->m_varVals; } return list; } chessx-1.0.0/data/themes/000755 001750 001750 00000000000 12234251061 016003 5ustar00niklasniklas000000 000000 chessx-1.0.0/data/images/square_green.png000644 001750 001750 00000013475 12074576333 021201 0ustar00niklasniklas000000 000000 PNG  IHDRw=iCCPICC ProfileX XuXUͷOrݝ])R."RRJ)*RRH6 (*܍ߕ~=k֞=3^^XC`ZBâȶz.׀hZ/Rd?ڭ|"WFjoHR(_")J  f$#D{VOE؄ycHH;ħ`|C)VQG24.G{M//=X'FxןSFۙ#%X_k{x_e;?h8:A/>dꯝ?;>1dݞ=.@_ /]ƾ!{ gX||#oTv{>~Fd={xȟ5h۽y s؛C/xRoln!D"W4$-+/+'vЮ˶<-06ܐeM; =R49л7@ et!0Vw@ a@g@(Ԁk<C1x^)|`lB  ⁄ HR C\ O B%% ݆h zMC`J悅aXօa{ Gqp |.+p ) ("ŇBQV(W:D*P vT? j Ƣмh)&#t ݋~F/c0 :Ƥa 1W0͘>3G*eƊ`U&Xl6=Žag+8 'YpQ4\1*7[> AAp##Qє11"="#S,S)=)f0)sss#s .]_ q5VVV_LX7x قβaG۰fǾȡAhx ssrsVrspqssssZfa ī[˻gwoo_߁?:@@ ``K! !UsBBk"N­s"""q""EDE#D+DaTł΋=ŕKG%` e@cI50 )J)]ziifi dVo222gee~*ɆVɾ3Kk['ɗ?UR0R8ЦCQBWRRҶ2YAy^EPSLeBQZ5[FMO]_Q5454WoF_KE)m>m/ ::>:Wtfutt~ӓ#52@d:5777Z4V272502%֚.5543/1o!nAh-,,_ XZYc)d+g`o`aWgjgcA!ڡǑͱq)iY KK+>)=?(r0;{=/[O':-/+ oS2E>鋏Oϼoײַ_ߜ|v@aB~`I `Paaa O P(X$DB#ۢphtjtVLia÷bbb82gw9OIKHJ>{1SL4NI"$'=JMMyD{ WJbLqj}u9m"]#$dɑ ߙ>YYY[٤SrN;=s LؙgYg,((T,,?G8}nȢXLVI@ɳReeek}Ώ_йPUUq1%K-ʘOUUU/^aue:zƶV.v5km R 3_ϺnD|Fƞ[ʚ3[#-Sm.mcnk7ߑS}n={9θΕnW?3{~·TlRjVn~yDyeTe}cO _HӬ>lo9,9[xȼ|K<*B"bJܒtRh59r J*UMԔԹ5Mhviifeg囟8mU )v'SRĻt ;A &%-0h,eLBj8*,es#q# KPiٓxNr3 d3V;=gO G=*,~X[Uv|ۅ򦋭:*V>zB-s@Uk ;zt9XkR[;YwO;ݑәU]S~mw u w=||gy꓊e?O zq+*orz{}37?~LtheNo^3/}mv{b%el+ko*H r-üǿ4lBv4FqSzSu2,l~/8* 6 +/Ȓ<&!- k,!/H)-)O1yj ^v;)i3Bh?l\|/V _}tǍŸ+I1k랿66䶅~PcQh"`oKq0L)FD֎-fI*6VLE.j| o57K4K6J]n*[#W%QTRr 5>KM-E}]n=N}..C^#^c^nS.36sf ZK8+jzfvn~aq˒ns1kϴGـ๐ٰC_Wp$}`rGꎶ"t q(i ĝ괲3'S3b3f[=#r,c.UE>U *Z)^,Rl OG/_ھxg{+kk]k={<\1}GFfFdg=N4O6~YuΛGENO7Q 0;9;s间nߌ+. `YY&$V ku/ &n ځvG؍ Xe 9C3HzəA 5j0 6ELS; BdU`C dt"=`:Xv+SQ3H扮@Ha1]XJ5sSC# %јHEAJK5AmNMNL@DLw^~a17f!,,ˬll/989xyy DD,işHKzIIJK?) 3Pxx_rJjZzƹ}5{u&tV153236aɶl]i3aGmoxiE@۠;7B6.q+'z~lkt|QcUBI5'$R)0ɜ<;\h~D!ӹ{ŁeO/]tyAuYmL5,7v&[x5ӳG/5`9xoS/a|g;;˜纅?wV׻6E~`? @ 78 C|[ $  CTP?a~:GкdtŔafJTNw/oPxP< ʈb,#*5j!rNRZ. :1&zQwoǘh*՘XBX ullF˜vox2 nT!saFw"t %) ӕg0بtN9Q*IMYyVvNn^~1YyMVhky9 nnq<ռy z g$?>vA|B1IPGQ'Oeg՝F~K66\/}0j ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef __GAMELIST_H__ #define __GAMELIST_H__ #include "tableview.h" #include "game.h" class Filter; class FilterModel; /** @ingroup GUI The GameList class displays list of the games in current filter. It allows user to click on list header and perform simple tag searches. */ class GameList : public TableView { Q_OBJECT public: GameList(Filter* filter, QWidget* parent = 0); ~GameList(); bool m_FilterActive; /** Set current database */ public slots: /** Change current filter/database */ void setFilter(Filter* filter); /** Update filter (called after changing filter outside) */ void updateFilter(); /** Perform simple search */ void simpleSearch(int tag); /** Select and show current game in the list */ void selectGame(int index); /** Select and show current game in the list */ void slotFilterListByPlayer(QString ns); /** Select and show current event in the list */ void slotFilterListByEvent(QString ns); /** Select and show current ECO in the list */ void slotFilterListByEco(QString ns); /** Select and show current event and player in the list */ void slotFilterListByEventPlayer(QString player, QString event); /** Select and show current player and ECO in the list */ void slotFilterListByEcoPlayer(QString tag, QString eco, QString player); private slots: /** Re-emit the request to the receivers to perform some action */ void itemSelected(const QModelIndex& index); /** Request a context menu for the list members */ void slotContextMenu(const QPoint& pos); /** Request to merge all games from the database into the current game */ void slotMergeAllGames(); /** Request to merge the complete filter into the current game */ void slotMergeFilter(); /** Request to merge a game into the current game */ void slotMergeGame(); /** Request a copy dialog for the game identified by m_cell */ void slotCopyGame(); /** Delete or undelete a game */ void slotDeleteGame(); /** React to a change in selected item */ void slotItemSelected(const QModelIndex&); signals: void selected(int); void searchDone(); void raiseRequest(); void requestMergeGame(int); void requestMergeAllGames(); void requestMergeFilter(); void requestCopyGame(int); void requestDeleteGame(int); void requestGameData(Game&); protected: //Drag'n'Drop Support void startDrag(Qt::DropActions supportedActions); void startToDrag(const QModelIndex&); private: FilterModel* m_model; QModelIndex m_index; }; #endif chessx-1.0.0/src/database/uciengine.cpp000644 001750 001750 00000030604 12223260306 020615 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2006-2007 Sean Estabrooks * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "uciengine.h" #include "enginedata.h" UCIEngine::UCIEngine(const QString& name, const QString& command, bool bTestMode, const QString& directory, QTextStream* logStream) : Engine(name, command, bTestMode, directory, logStream) { m_quitAfterAnalysis = false; m_invertBlack = true; } bool UCIEngine::startAnalysis(const Board& board, int nv) { m_mpv = nv; if(!isActive()) { return false; } if(m_board == board) { return true; } m_board = board; m_position = board.toFen(); m_waitingOn = "ucinewgame"; send("stop"); send("ucinewgame"); send("isready"); setAnalyzing(true); return true; } void UCIEngine::stopAnalysis() { if(isAnalyzing()) { send("stop"); } } void UCIEngine::setMpv(int mpv) { m_mpv = mpv; if(isAnalyzing()) { send("stop"); send(QString("setoption name MultiPV value %1").arg(m_mpv)); send("go infinite"); } } void UCIEngine::protocolStart() { //tell the engine we are using the uci protocol send("uci"); } void UCIEngine::protocolEnd() { send("quit"); setActive(false); m_board.clear(); } void UCIEngine::processMessage(const QString& message) { if(message == "uciok") { //once the engine is running wait for it to initialise m_waitingOn = "uciok"; send("isready"); } if(message == "readyok") { if(m_waitingOn == "uciok") { //engine is now initialised and ready to go m_waitingOn = ""; setActive(true); if(!m_bTestMode) { OptionValueList::const_iterator i = m_mapOptionValues.constBegin(); while(i != m_mapOptionValues.constEnd()) { QString key = i.key(); QVariant value = i.value(); if(EngineOptionData* dataSpec = EngineOptionData::FindInList(key, m_options)) { switch(dataSpec->m_type) { case OPT_TYPE_BUTTON: if(value.toBool()) { send(QString("setoption name %1 value %2").arg(key)); } break; case OPT_TYPE_CHECK: case OPT_TYPE_SPIN: case OPT_TYPE_STRING: case OPT_TYPE_COMBO: if(dataSpec->m_defVal != value.toString() && !value.toString().isEmpty()) { send(QString("setoption name %1 value %2").arg(key).arg(value.toString())); } break; } } ++i; } } send("setoption name UCI_AnalyseMode value true"); } if(m_waitingOn == "ucinewgame") { //engine is now ready to analyse a new position m_waitingOn = ""; send(QString("setoption name MultiPV value %1").arg(m_mpv)); send("position fen " + m_position); send("go infinite"); } } QString command = message.section(' ', 0, 0); if(command == "info" && isAnalyzing()) { parseAnalysis(message); } else if(command == "option" && !isAnalyzing()) { parseOptions(message); } } void UCIEngine::parseAnalysis(const QString& message) { // Sample: info score cp 20 depth 3 nodes 423 time 15 pv f1c4 g8f6 b1c3 Analysis analysis; bool multiPVFound, timeFound, nodesFound, depthFound, scoreFound, variationFound; multiPVFound = timeFound = nodesFound = depthFound = scoreFound = variationFound = false; QString info = message.section(' ', 1, -1, QString::SectionSkipEmpty); int section = 0; QString name; bool ok; //loop around the name value tuples while(!info.section(' ', section, section + 1, QString::SectionSkipEmpty).isEmpty()) { name = info.section(' ', section, section, QString::SectionSkipEmpty); if(name == "multipv") { analysis.setNumpv(info.section(' ', section + 1, section + 1, QString::SectionSkipEmpty).toInt(&ok)); section += 2; if(ok) { multiPVFound = true; continue; } } if(name == "time") { analysis.setTime(info.section(' ', section + 1, section + 1, QString::SectionSkipEmpty).toInt(&ok)); section += 2; if(ok) { timeFound = true; continue; } } if(name == "nodes") { analysis.setNodes(info.section(' ', section + 1, section + 1, QString::SectionSkipEmpty).toLongLong(&ok)); section += 2; if(ok) { nodesFound = true; continue; } } if(name == "depth") { analysis.setDepth(info.section(' ', section + 1, section + 1, QString::SectionSkipEmpty).toInt(&ok)); section += 2; if(ok) { depthFound = true; continue; } } if(name == "score") { QString type = info.section(' ', section + 1, section + 1, QString::SectionSkipEmpty); if(type == "cp" || type == "mate") { int score = info.section(' ', section + 2, section + 2).toInt(&ok); if(type == "mate") { analysis.setMovesToMate(abs(score)); } else if(m_invertBlack && m_board.toMove() == Black) { analysis.setScore(-score); } else { analysis.setScore(score); } section += 3; if(ok) { scoreFound = true; continue; } } else { section += 3; } } if(name == "pv") { Board board = m_board; MoveList moves; QString moveText; section++; while((moveText = info.section(' ', section, section, QString::SectionSkipEmpty)) != "") { Move move = board.parseMove(moveText); if(!move.isLegal()) { break; } board.doMove(move); moves.append(move); section++; } analysis.setVariation(moves); } //not understood, skip section += 2; } if(timeFound && nodesFound && scoreFound && analysis.isValid()) { if(!multiPVFound) { analysis.setNumpv(1); } sendAnalysis(analysis); } } void UCIEngine::parseOptions(const QString& message) { enum ScanPhase { EXPECT_OPTION, EXPECT_NAME, EXPECT_TYPE_TOKEN, EXPECT_TYPE, EXPECT_DEFAULT_VALUE, EXPECT_MIN_MAX_DEFAULT, EXPECT_MIN_VALUE, EXPECT_MAX_VALUE, EXPECT_VAR_TOKEN, EXPECT_VAR } phase; phase = EXPECT_OPTION; QStringList list = message.split(QRegExp("\\W+"), QString::SkipEmptyParts); QStringList nameVals; QString defVal; QString minVal; QString maxVal; QStringList varVals; OptionType optionType = OPT_TYPE_STRING; QString error; bool done = false; foreach(QString token, list) { switch(phase) { case EXPECT_OPTION: if(token == "option") { phase = EXPECT_NAME; } else { error = token; } break; case EXPECT_NAME: if(token == "name") { phase = EXPECT_TYPE; } else { error = token; } break; case EXPECT_TYPE: if(token == "type") { phase = EXPECT_TYPE_TOKEN; } else { nameVals << token; } break; case EXPECT_TYPE_TOKEN: if(token == "check") { optionType = OPT_TYPE_CHECK; } else if(token == "spin") { optionType = OPT_TYPE_SPIN; } else if(token == "combo") { optionType = OPT_TYPE_COMBO; } else if(token == "button") { optionType = OPT_TYPE_BUTTON; done = true; } else if(token == "string") { optionType = OPT_TYPE_STRING; } else { error = token; } phase = EXPECT_MIN_MAX_DEFAULT; break; case EXPECT_DEFAULT_VALUE: defVal = token; switch(optionType) { case OPT_TYPE_SPIN: phase = EXPECT_MIN_MAX_DEFAULT; break; case OPT_TYPE_COMBO: phase = EXPECT_VAR_TOKEN; break; case OPT_TYPE_CHECK: case OPT_TYPE_STRING: default: done = true; break; } break; case EXPECT_MIN_MAX_DEFAULT: if(token == "default") { phase = EXPECT_DEFAULT_VALUE; } else if(token == "min") { phase = EXPECT_MIN_VALUE; } else if(token == "max") { phase = EXPECT_MAX_VALUE; } else { done = true; } break; case EXPECT_MIN_VALUE: minVal = token; phase = EXPECT_MIN_MAX_DEFAULT; break; case EXPECT_MAX_VALUE: maxVal = token; phase = EXPECT_MIN_MAX_DEFAULT; break; case EXPECT_VAR_TOKEN: if(token == "var") { phase = EXPECT_VAR; } else { done = true; } break; case EXPECT_VAR: varVals << token; phase = EXPECT_VAR_TOKEN; break; default: error = token; return; } if(done || !error.isEmpty()) { break; } } if(!error.isEmpty()) { qDebug() << "Cannot parse Option string: '" << message << "' looking at token '" << error << "'!"; return; } if(done || (phase > EXPECT_DEFAULT_VALUE)) { QString name = nameVals.join(" "); EngineOptionData option; option.m_name = name; option.m_minVal = minVal; option.m_maxVal = maxVal; option.m_defVal = defVal; option.m_varVals = varVals; option.m_type = optionType; m_options.append(option); } else { qDebug() << "Incomplete syntax parsing Option string: '" << message << "'!"; return; } } chessx-1.0.0/data/help/about.css000644 001750 001750 00000005477 12045534760 017321 0ustar00niklasniklas000000 000000 body { background-color: #ddd; /* Background color */ color: #222; /* Foreground color used for text */ font-family: Helvetica; font-size: medium; margin: 0; /* Amount of negative space around the outside of the body */ padding: 0; /* Amount of negative space around the inside of the body */ } #header h1 { margin: 0; padding: 0; } #header h1 a { background-color: #ccc; border-bottom: 1px solid #666; color: #222; display: block; font-size: large; font-weight: bold; padding: 10px 0; text-align: center; text-decoration: none; } #header ul { list-style: none; margin: 10px; padding: 0; } #header ul li a { background-color: #FFFFFF; border: 1px solid #999999; color: #222222; display: block; font-size: medium; font-weight: bold; margin-bottom: -1px; padding: 8px 6px; text-decoration: none; } #header ul li b { background-color: #CCCCCC; border: 1px solid #999999; color: #222222; display: block; font-size: medium; font-weight: bold; margin-bottom: -1px; padding: 8px 6px; text-decoration: none; } #content, #sidebar { padding: 10px; } #footer { display: none; } #header h1 a { text-shadow: 0px 1px 0px #fff; background-image: -webkit-radial-gradient(white, black); } #header ul li:first-child a { -webkit-border-top-left-radius: 8px; -webkit-border-top-right-radius: 8px; } #header ul li:last-child a { -webkit-border-bottom-left-radius: 8px; -webkit-border-bottom-right-radius: 8px; } #header h1 b { text-shadow: 0px 1px 0px #fff; background-image: -webkit-radial-gradient(white, black); } #header ul li:first-child b { -webkit-border-top-left-radius: 8px; -webkit-border-top-right-radius: 8px; } #header ul li:last-child b { -webkit-border-bottom-left-radius: 8px; -webkit-border-bottom-right-radius: 8px; } #header ul.hide { display: none; } chessx-1.0.0/src/quazip/quacrc32.cpp000644 001750 001750 00000000706 12223260306 020037 0ustar00niklasniklas000000 000000 #include "quacrc32.h" #include "zlib.h" QuaCrc32::QuaCrc32() { reset(); } quint32 QuaCrc32::calculate(const QByteArray &data) { return crc32(crc32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size()); } void QuaCrc32::reset() { checksum = crc32(0L, Z_NULL, 0); } void QuaCrc32::update(const QByteArray &buf) { checksum = crc32(checksum, (const Bytef*)buf.data(), buf.size()); } quint32 QuaCrc32::value() { return checksum; } chessx-1.0.0/data/images/folder_open.png000644 001750 001750 00000006451 12141003207 020765 0ustar00niklasniklas000000 000000 PNG  IHDR>atEXtSoftwareAdobe ImageReadyqe< IDATx]lWϝEuJ@*h Nh w@)oϜ>ifW_ZRN"vxOHgXWWҋyϵgGF>۶nc[pu"HN818|!W dU90>YS͖uxGahfr*̸PHwGʿ&8n#RcfOȯi xc~k?"\ yM qccc{\6c9O}N:ٹAࡷ:_.#p]ʲ.iv3_XJhǎOYc2`X!=5y@*Ą%Ap=A7Ol+LeP)L(hK(*\7\K[>58uD[nL&[iV(,vzr m7p4+Z;1v 8/8iw`hi.r!eF>9ƫat Ơゖd?ж,e๰ONsSwoPfg#I\]( iXe, cf{L9mGa%o0s Q)H  /~hV|+pttcL|W T4EWӟj|Xm^8eΞ %^]NNPhroZh7^ G&p6o$: ?HŢm2z~%kY7 ]X&L*Z~_>cga(+0":z:B+`A`(FL6ffo/: ttpՁ3$XAs-+Л?0uuX;~7a/([Ey)y`@t7O Z~r,&8΢ˈbj2:^"zs dpL` Yg;Dz]56 46 P%(,nE` V@mdxb-@O%xB:d2 @ |F01ZX,6wo ;.(;0;; $fZdBgR)A(v}l|E]}_P~Q$}=L Nɶ‘(ĵb8v$fgp($D s!L@4Ax߹z7f_kkqwW[$ 0`V֓C[cuēYM d%A)z/> @p_ܾ G E3K-& 0eUMB.  8&Jx/I@Eqn5"j nPPVL!&`5Jo/Gw@D`n, ?K8P %J "&uv ̈́7ٺ -"$bU9m -* re6Jf Du[~CP"SY5a1Jr>H`JWݮȕ/Oڅˑ]P"0VwĤ^jtX;Gy2@f"Z_vr9՚ ƨk4^giXFa`ElrwM(f; t.^̉B8?| G /;#UO`Ev"a\F`  qbxFIfoR2H.gNJWide`F0`JzVv@z1s7]C: 7`-'[ C0jzb7~7ɒCnE^ T?o`u[ieP\:ʇP($J=(ъJ-SybG [ Tp+wDljhԠQ`%W:k"Hp`:kFUu~AbGa|iL  bl\@͏q^րok'EQ=~ǚ|tlY2 4ZU30¸t&BDJ,0 4bh4ANqZ0xo ƣ晱Zd ހN$Zl`P_g۝( Ss-9g hK¬]@͉ [D෈\3(02!{ۤa$iCCPICC Profile8UoT>oR? XGůUS[IJ*$:7鶪O{7@Hkk?<kktq݋m6nƶد-mR;`zv x#=\% oYRڱ#&?>ҹЪn_;j;$}*}+(}'}/LtY"$].9⦅%{_a݊]hk5'SN{<_ t jM{-4%TńtY۟R6#v\喊x:'HO3^&0::m,L%3:qVE t]~Iv6Wٯ) |ʸ2]G4(6w‹$"AEv m[D;Vh[}چN|3HS:KtxU'D;77;_"e?Yqxl+diTXtXML:com.adobe.xmp Adobe ImageReady z3IDATx] tu/IlI/ǖmL06X6aV51M"А$IliBBqz1k T|1kc/N, X=vg_i%;]IfQ4M|pݪk` <Ƹx 1.1^`K`W?o[<Ƹx`3枥Q׸JM*]R[ҨLqm)aUxQ;›~%ߏ0 /B&?_85~ B 1 a?Ћ#V^Xyj'iEW8Z>N-i%4g4ŹΎkSI4ާOʏHk7;H'&%h: ԨʐW~O^aoR5Senސ:^t63>GT Y}LO;MbXOLljХ)ܹC#{Y S~++fB i6 M?tPgHY8{`#uO}4}DQ\>&RL#ޣn(uP[BW4L=k7s+X/„ G$SȞt&G?cpjTP⣩s˅K;m̓iNڧ75OQOWTeh[9 0.-Y)\c)SrK!:F!B NydZP57P)p ѐ(~!궥n&)pV[/s\*6]h|_xhڜ2Z9$>¡kułu݋VW2w,[+*c_P{VJyhFNOGAK(箘AsO]k8Js'Z7ջJݪu"__H-ZPs?M-{в>ȪІ"!V${ Ep:vZo綠[sWAD kgeݒ*W ;k}@ˇZ@/SZ#1% dwXGN5ݻ Z YAWOq>N}Д-B7G9tPc] uio;(XHU0CCަ7ǣ:mmwot[>iZM~a\O3iP|;Fݼ9']( )JG[ AEt}aw*҇0}E%2r{~iFJ[_owB3~]9ק@/MA :"& g܁#Ky|.LL*o4SCHs p w`;u,ŭ1_V8-G`]mޑCKWc$96c{ZB MzWS\`x՚q2ytIoܾ-$2dE+ÒkƧ;5X뉏]s|hϖCb 3_R9$;̎d ըT=WTNncľD|mWG)*U>[&lR c gˊˋ*PDz_{~82(#Q34iuWdT-.S5o[~XЧ{ޭ$+8!Wa]:d ]]n׸=Vk` >ןz~ G2w#sd 8;xkWkWX MŪه%QW_TIm'/C9[?NRQ*mݶf@bJ }eXqOy)sߢmpUVZ8m G66vU0J *e=jӻ2븕@'鵧(~hUL4B+מO?mV XϛkA!;U/7ίkszAP3Ş+8n9Nw>%-D!w Ugp}(E/#,R%|3weZiqc­=:JYLGz*}wk/q?^Wؙt_vNt一+,fMG[z[aFμ̧4kd(=#A\8i70ƫ eѭ),]5}jB,*9uk9?5=iz Y1p!{ց,25b>_/A۞؛_~|#}AD0p^r-Czphxx87i&=@=1jkP`-PH?6u6׿"W)ws5{4z&_ϸB 7?)<0vNDwPZ-`-3l( y˧"pe$:Z:i27=|/^n^ xV}ׇtҮ`s¶2  @U\A>dz^(C6ҿ}v.m?:C%RC9MoZ0?I @Xr=;#<ýK#Dc+Ll}f.em{d AJ C4td',B- ]-`0>JDiX!I}* >x-ݳ째9H?]CN޳}L( BEiӡa0E'̖K7wѿUZ [|J"9MOMg+,yַP5~.qI+ܺ7qT&kx->+5(wtZX@l=qhԅ@M]J=7C[&Ys,νTfmǘB'M{پqPHԤWJY34O$.3 c‡279ej.GtђϡІ_Djrizf壛8r96ywɗSTawWѓw?K"[쥢#NI)rE\fDAYQ)Q  IxVIzlr[d q$4Co K&衆4^Cح @җ4k$.t#$^E8{]\rh Gԃ_[A W"h+ܠnFU&' 0Y"s)п @H`yh貵kmD0c\FdT@0@lysڿ£'<cqb-izkFV1*0eO$ƾ[/@pH ]v]xIP!{K}yw)YA̻.A&[iZ3?0EXِ> C ’4=2e:`]d[(l{D1#lȐu tW4p/a IOmE7_?t /0T<;M/}rXtێHܴN! ǣGv!Zi$3aP @f}Nn˾SL_)bƱdeʜ '7&`[5c]#wMo ʛ/nȄDbP%"A2kօ'Qx˃DmPvcP!܄/Z^(r)x;C`'{g~wowCȜ_ASʓ Gogppc .O% @<0*`=,iʄ ճiiL^YX&g SǓA_N}p'l5[!>Y,qd*@A$ZԚsP P_?~*[DOB@C82Ƀ#_QA}7jDT S2Q<:^n 6!h;=] 9(h0m& 2"9C,-/d_NP,'R|Kd+=)WBZ߱m=k/xd!pJ<)d7~ q]sb65..j+c_)nd%=vOJqb UlcN/&Yb2>λB~kbʦcMGS_m`g,R4%,ؕ>Rh 2~4'lǬmMkP~vI @P| 򦀥ЛY6o1p [t>`S>tLAM9P}qiǀ· SJ0i en?fkϜr@gm9Ay<,T static bool copyData(QIODevice &inFile, QIODevice &outFile) { while(!inFile.atEnd()) { char buf[4096]; qint64 readLen = inFile.read(buf, 4096); if(readLen <= 0) { return false; } if(outFile.write(buf, readLen) != readLen) { return false; } } return true; } /**OK * Comprime il file fileName, nell'oggetto zip, con il nome fileDest. * * La funzione fallisce se: * * zip==NULL; * * l'oggetto zip e stato aperto in una modalita non compatibile con l'aggiunta di file; * * non e possibile aprire il file d'origine; * * non e possibile creare il file all'interno dell'oggetto zip; * * si e rilevato un errore nella copia dei dati; * * non e stato possibile chiudere il file all'interno dell'oggetto zip; */ bool JlCompress::compressFile(QuaZip* zip, QString fileName, QString fileDest) { // zip: oggetto dove aggiungere il file // fileName: nome del file reale // fileDest: nome del file all'interno del file compresso // Controllo l'apertura dello zip if(!zip) { return false; } if(zip->getMode() != QuaZip::mdCreate && zip->getMode() != QuaZip::mdAppend && zip->getMode() != QuaZip::mdAdd) { return false; } // Apro il file originale QFile inFile; inFile.setFileName(fileName); if(!inFile.open(QIODevice::ReadOnly)) { return false; } // Apro il file risulato QuaZipFile outFile(zip); if(!outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileDest, inFile.fileName()))) { return false; } // Copio i dati if(!copyData(inFile, outFile) || outFile.getZipError() != UNZ_OK) { return false; } // Chiudo i file outFile.close(); if(outFile.getZipError() != UNZ_OK) { return false; } inFile.close(); return true; } /**OK * Comprime la cartella dir nel file fileCompressed, se recursive e true allora * comprime anche le sotto cartelle. I nomi dei file preceduti dal path creato * togliendo il pat della cartella origDir al path della cartella dir. * Se la funzione fallisce restituisce false e cancella il file che si e tentato * di creare. * * La funzione fallisce se: * * zip==NULL; * * l'oggetto zip e stato aperto in una modalita non compatibile con l'aggiunta di file; * * la cartella dir non esiste; * * la compressione di una sotto cartella fallisce (1); * * la compressione di un file fallisce; * (1) La funzione si richiama in maniera ricorsiva per comprimere le sotto cartelle * dunque gli errori di compressione di una sotto cartella sono gli stessi di questa * funzione. */ bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool recursive) { // zip: oggetto dove aggiungere il file // dir: cartella reale corrente // origDir: cartella reale originale // (path(dir)-path(origDir)) = path interno all'oggetto zip // Controllo l'apertura dello zip if(!zip) { return false; } if(zip->getMode() != QuaZip::mdCreate && zip->getMode() != QuaZip::mdAppend && zip->getMode() != QuaZip::mdAdd) { return false; } // Controllo la cartella QDir directory(dir); if(!directory.exists()) { return false; } // Se comprimo anche le sotto cartelle if(recursive) { // Per ogni sotto cartella QFileInfoList files = directory.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot); Q_FOREACH(QFileInfo file, files) { // Comprimo la sotto cartella if(!compressSubDir(zip, file.absoluteFilePath(), origDir, recursive)) { return false; } } } // Per ogni file nella cartella QFileInfoList files = directory.entryInfoList(QDir::Files); QDir origDirectory(origDir); Q_FOREACH(QFileInfo file, files) { // Se non e un file o e il file compresso che sto creando if(!file.isFile() || file.absoluteFilePath() == zip->getZipName()) { continue; } // Creo il nome relativo da usare all'interno del file compresso QString filename = origDirectory.relativeFilePath(file.absoluteFilePath()); // Comprimo il file if(!compressFile(zip, file.absoluteFilePath(), filename)) { return false; } } return true; } /**OK * Estrae il file fileName, contenuto nell'oggetto zip, con il nome fileDest. * Se la funzione fallisce restituisce false e cancella il file che si e tentato di estrarre. * * La funzione fallisce se: * * zip==NULL; * * l'oggetto zip e stato aperto in una modalita non compatibile con l'estrazione di file; * * non e possibile aprire il file all'interno dell'oggetto zip; * * non e possibile creare il file estratto; * * si e rilevato un errore nella copia dei dati (1); * * non e stato possibile chiudere il file all'interno dell'oggetto zip (1); * * (1): prima di uscire dalla funzione cancella il file estratto. */ bool JlCompress::extractFile(QuaZip* zip, QString fileName, QString fileDest) { // zip: oggetto dove aggiungere il file // filename: nome del file reale // fileincompress: nome del file all'interno del file compresso // Controllo l'apertura dello zip if(!zip) { return false; } if(zip->getMode() != QuaZip::mdUnzip) { return false; } // Apro il file compresso if(!fileName.isEmpty()) { zip->setCurrentFile(fileName); } QuaZipFile inFile(zip); if(!inFile.open(QIODevice::ReadOnly) || inFile.getZipError() != UNZ_OK) { return false; } // Controllo esistenza cartella file risultato QDir curDir; if(!curDir.mkpath(QFileInfo(fileDest).absolutePath())) { return false; } if(QFileInfo(fileDest).isDir()) { return true; } // Apro il file risultato QFile outFile; outFile.setFileName(fileDest); if(!outFile.open(QIODevice::WriteOnly)) { return false; } // Copio i dati if(!copyData(inFile, outFile) || inFile.getZipError() != UNZ_OK) { outFile.close(); removeFile(QStringList(fileDest)); return false; } outFile.close(); // Chiudo i file inFile.close(); if(inFile.getZipError() != UNZ_OK) { removeFile(QStringList(fileDest)); return false; } return true; } /** * Rimuove i file il cui nome e specificato all'interno di listFile. * Restituisce true se tutti i file sono stati cancellati correttamente, attenzione * perche puo restituire false anche se alcuni file non esistevano e si e tentato * di cancellarli. */ bool JlCompress::removeFile(QStringList listFile) { bool ret = true; // Per ogni file for(int i = 0; i < listFile.count(); i++) { // Lo elimino ret = ret && QFile::remove(listFile.at(i)); } return ret; } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /**OK * Comprime il file fileName nel file fileCompressed. * Se la funzione fallisce restituisce false e cancella il file che si e tentato * di creare. * * La funzione fallisce se: * * non si riesce ad aprire l'oggetto zip; * * la compressione del file fallisce; * * non si riesce a chiudere l'oggetto zip; */ bool JlCompress::compressFile(QString fileCompressed, QString file) { // Creo lo zip QuaZip zip(fileCompressed); QDir().mkpath(QFileInfo(fileCompressed).absolutePath()); if(!zip.open(QuaZip::mdCreate)) { QFile::remove(fileCompressed); return false; } // Aggiungo il file if(!compressFile(&zip, file, QFileInfo(file).fileName())) { QFile::remove(fileCompressed); return false; } // Chiudo il file zip zip.close(); if(zip.getZipError() != 0) { QFile::remove(fileCompressed); return false; } return true; } /**OK * Comprime i file specificati in files nel file fileCompressed. * Se la funzione fallisce restituisce false e cancella il file che si e tentato * di creare. * * La funzione fallisce se: * * non si riesce ad aprire l'oggetto zip; * * la compressione di un file fallisce; * * non si riesce a chiudere l'oggetto zip; */ bool JlCompress::compressFiles(QString fileCompressed, QStringList files) { // Creo lo zip QuaZip zip(fileCompressed); QDir().mkpath(QFileInfo(fileCompressed).absolutePath()); if(!zip.open(QuaZip::mdCreate)) { QFile::remove(fileCompressed); return false; } // Comprimo i file QFileInfo info; Q_FOREACH(QString file, files) { info.setFile(file); if(!info.exists() || !compressFile(&zip, file, info.fileName())) { QFile::remove(fileCompressed); return false; } } // Chiudo il file zip zip.close(); if(zip.getZipError() != 0) { QFile::remove(fileCompressed); return false; } return true; } /**OK * Comprime la cartella dir nel file fileCompressed, se recursive e true allora * comprime anche le sotto cartelle. * Se la funzione fallisce restituisce false e cancella il file che si e tentato * di creare. * * La funzione fallisce se: * * non si riesce ad aprire l'oggetto zip; * * la compressione di un file fallisce; * * non si riesce a chiudere l'oggetto zip; */ bool JlCompress::compressDir(QString fileCompressed, QString dir, bool recursive) { // Creo lo zip QuaZip zip(fileCompressed); QDir().mkpath(QFileInfo(fileCompressed).absolutePath()); if(!zip.open(QuaZip::mdCreate)) { QFile::remove(fileCompressed); return false; } // Aggiungo i file e le sotto cartelle if(!compressSubDir(&zip, dir, dir, recursive)) { QFile::remove(fileCompressed); return false; } // Chiudo il file zip zip.close(); if(zip.getZipError() != 0) { QFile::remove(fileCompressed); return false; } return true; } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /**OK * Estrae il file fileName, contenuto nel file fileCompressed, con il nome fileDest. * Se fileDest = "" allora il file viene estratto con lo stesso nome con cui e * stato compresso. * Se la funzione fallisce cancella il file che si e tentato di estrarre. * Restituisce il nome assoluto del file estratto. * * La funzione fallisce se: * * non si riesce ad aprire l'oggetto zip; * * l'estrazione del file fallisce; * * non si riesce a chiudere l'oggetto zip; */ QString JlCompress::extractFile(QString fileCompressed, QString fileName, QString fileDest) { // Apro lo zip QuaZip zip(fileCompressed); if(!zip.open(QuaZip::mdUnzip)) { return QString(); } // Estraggo il file if(fileDest.isEmpty()) { fileDest = fileName; } if(!extractFile(&zip, fileName, fileDest)) { return QString(); } // Chiudo il file zip zip.close(); if(zip.getZipError() != 0) { removeFile(QStringList(fileDest)); return QString(); } return QFileInfo(fileDest).absoluteFilePath(); } /**OK * Estrae i file specificati in files, contenuti nel file fileCompressed, nella * cartella dir. La struttura a cartelle del file compresso viene rispettata. * Se dir = "" allora il file viene estratto nella cartella corrente. * Se la funzione fallisce cancella i file che si e tentato di estrarre. * Restituisce i nomi assoluti dei file estratti. * * La funzione fallisce se: * * non si riesce ad aprire l'oggetto zip; * * l'estrazione di un file fallisce; * * non si riesce a chiudere l'oggetto zip; */ QStringList JlCompress::extractFiles(QString fileCompressed, QStringList files, QString dir) { // Creo lo zip QuaZip zip(fileCompressed); if(!zip.open(QuaZip::mdUnzip)) { return QStringList(); } // Estraggo i file QStringList extracted; for(int i = 0; i < files.count(); i++) { QString absPath = QDir(dir).absoluteFilePath(files.at(i)); if(!extractFile(&zip, files.at(i), absPath)) { removeFile(extracted); return QStringList(); } extracted.append(absPath); } // Chiudo il file zip zip.close(); if(zip.getZipError() != 0) { removeFile(extracted); return QStringList(); } return extracted; } /**OK * Estrae il file fileCompressed nella cartella dir. * Se dir = "" allora il file viene estratto nella cartella corrente. * Se la funzione fallisce cancella i file che si e tentato di estrarre. * Restituisce i nomi assoluti dei file estratti. * * La funzione fallisce se: * * non si riesce ad aprire l'oggetto zip; * * la compressione di un file fallisce; * * non si riesce a chiudere l'oggetto zip; */ QStringList JlCompress::extractDir(QString fileCompressed, QString dir) { // Apro lo zip QuaZip zip(fileCompressed); if(!zip.open(QuaZip::mdUnzip)) { return QStringList(); } QDir directory(dir); QStringList extracted; if(!zip.goToFirstFile()) { return QStringList(); } do { QString name = zip.getCurrentFileName(); QString absFilePath = directory.absoluteFilePath(name); if(!extractFile(&zip, "", absFilePath)) { removeFile(extracted); return QStringList(); } extracted.append(absFilePath); } while(zip.goToNextFile()); // Chiudo il file zip zip.close(); if(zip.getZipError() != 0) { removeFile(extracted); return QStringList(); } return extracted; } /**OK * Restituisce la lista dei file resenti nel file compresso fileCompressed. * Se la funzione fallisce, restituisce un elenco vuoto. * * La funzione fallisce se: * * non si riesce ad aprire l'oggetto zip; * * la richiesta di informazioni di un file fallisce; * * non si riesce a chiudere l'oggetto zip; */ QStringList JlCompress::getFileList(QString fileCompressed) { // Apro lo zip QuaZip* zip = new QuaZip(QFileInfo(fileCompressed).absoluteFilePath()); if(!zip->open(QuaZip::mdUnzip)) { delete zip; return QStringList(); } // Estraggo i nomi dei file QStringList lst; QuaZipFileInfo info; for(bool more = zip->goToFirstFile(); more; more = zip->goToNextFile()) { if(!zip->getCurrentFileInfo(&info)) { delete zip; return QStringList(); } lst << info.name; //info.name.toLocal8Bit().constData() } // Chiudo il file zip zip->close(); if(zip->getZipError() != 0) { delete zip; return QStringList(); } delete zip; return lst; } chessx-1.0.0/src/gui/messagedialog.cpp000644 001750 001750 00000005474 12223260306 020502 0ustar00niklasniklas000000 000000 /*************************************************************************** MessageDialog - wrapper for QMessageDialog (C) 2007 Michal Rudolf This file is a part of Chessx (http:/chess.sourceforge.net). ChessX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. ***************************************************************************/ #include "messagedialog.h" #include #include #include void MessageDialog::error(const QString& text, const QString& title) { QMessageBox::critical(QApplication::activeWindow(), title, text); } void MessageDialog::warning(const QString& text, const QString& title) { QMessageBox::warning(QApplication::activeWindow(), title, text); } void MessageDialog::information(const QString& text, const QString& title) { QMessageBox::information(QApplication::activeWindow(), title, text); } bool MessageDialog::yesNo(const QString& text, const QString& title, const QString& yes, const QString& no) { QMessageBox mb(QApplication::activeWindow()); mb.setWindowTitle(title); mb.setText(text); mb.setIcon(QMessageBox::Question); QPushButton* y = mb.addButton(yes, QMessageBox::YesRole); mb.setDefaultButton(y); mb.addButton(no, QMessageBox::NoRole); mb.exec(); return mb.clickedButton() == (QAbstractButton*) y; } bool MessageDialog::okCancel(const QString& text, const QString& title, const QString& ok, const QString& cancel) { QMessageBox mb(QApplication::activeWindow()); mb.setWindowTitle(title); mb.setText(text); mb.setIcon(QMessageBox::Question); QPushButton* o = mb.addButton(ok, QMessageBox::ActionRole); mb.setDefaultButton(o); QPushButton* c = mb.addButton(cancel, QMessageBox::RejectRole); mb.setEscapeButton((QAbstractButton*)c); mb.exec(); return mb.clickedButton() == (QAbstractButton*) o; } int MessageDialog::yesNoCancel(const QString& text, const QString& title, const QString& yes, const QString& no, const QString& cancel) { QMessageBox mb(QApplication::activeWindow()); mb.setWindowTitle(title); mb.setText(text); mb.setIcon(QMessageBox::Question); QPushButton* y = mb.addButton(yes, QMessageBox::ActionRole); mb.setDefaultButton(y); QPushButton* n = mb.addButton(no, QMessageBox::NoRole); QPushButton* c = mb.addButton(cancel, QMessageBox::RejectRole); mb.setEscapeButton((QAbstractButton*)c); mb.exec(); if(mb.clickedButton() == (QAbstractButton*) y) { return Yes; } else if(mb.clickedButton() == (QAbstractButton*) n) { return No; } else { return Cancel; } } chessx-1.0.0/data/images/replay.png000644 001750 001750 00000016755 12144113023 017776 0ustar00niklasniklas000000 000000 PNG  IHDR>a$iCCPICC Profile8UoT>oR? XGůUS[IJ*$:7鶪O{7@Hkk?<kktq݋m6nƶد-mR;`zv x#=\% oYRڱ#&?>ҹЪn_;j;$}*}+(}'}/LtY"$].9⦅%{_a݊]hk5'SN{<_ t jM{-4%TńtY۟R6#v\喊x:'HO3^&0::m,L%3:qVE t]~Iv6Wٯ) |ʸ2]G4(6w‹$"AEv m[D;Vh[}چN|3HS:KtxU'D;77;_"e?Yqxl+diTXtXML:com.adobe.xmp Adobe ImageReady zIDATx] |Tՙ<HT,> PE[2*?m?MKuuVw;U֭]v*+J@@HUE"a򘙻930d{|9ޫJw%軬g8g dq@}\}Kq q3 >.>~d%X>Wo{TE-r(J!oI|R()~UµuTETȱŏlOtg@)NAE`EbT *JW^ g8<4DOyCs(X.P.Ka)Ӡv-]F(ZBUDJ[cv<=?(5^ôw`\G$CLxKc[J\ [ Æ2ML[#_%Su!jk `kzC[ޡpKS_X4+G?XԾѧkv{Rg9Y#鬜Qº_IXTƣl9ݎr2VY88GtTOVҿSs 4lL>tk0z+myXn Bm9^pd{温䞩t{hx;hKvS 9J㦎 Kvk8uP[l_O%zS#v Ll|p1#TO?ڌUZvU d08j_kPۂApR] )#ۦљ4B[>;ZіU ? U*9K~.nK٩қ&O$y>;P=Wޝ_E-zb 7bucmqxK]-_~S!)~b}U.XRo8 Ij.gM)sX9?&;|a(z#|n8m"]ylm iAM9哪gxV4Nohݳ,Z)Ov BuxIQR=pR\8kR'` ̦Cv?5oYrl-))2T%%Bum\I9 n7`}i )O>NMw\'<LΦ~ CZ(o\>:ϚdVf?mz 0QWoK Z1>PɷzUfj膛/"^< 0)=Y3gcӿx{cFO5)۶3H:ySzRK9 p7vgbc\$Q1A>ϚD멹aqv"XM~|)nV2jzgD]"j -D˄^ d BzYwT,4R@H|RXw! ݧL.uxB rއT3D5<r#-+Qj(f܏QT2,dB$ҝLP:[q'Q55>1_8Gw$UG:m D md|"i-(dݎ}༫/NR65,|-HFtl$b \L/?rL`QtQT(6L [F/6 y29xDz\9}^y`f;ʋH9d@o^L/MQ Ed̯l9͘(2 JdNd }y1ċO2BƋNZ%I4o`&ձdK`b᠂Ӳ'7 Zd`ISbkV?R@T#1tC> Ie 0woZ<[ ˡoa rZ_wʔrFӡӅ/ CιFI\?(|9dt aW#ﯤVJl9Ŷa8n w ˍ0( 1=C{}?E5R-LFv]˩~D|ADKL@3Qe}2thޚ2 V =1qʒH_@l y[P5 Նq'`t)kWx0q1nX{ <jH9(&)2.[A/^ c<S`'+Wpt@K'vbJ˞i!DM^]B˹joweC&nhRylJU/[koV@͘Xd+z˃0GDbYuXV9dϲ'ad<χ[V&)[ngPmbC`k+` YD wV%ja&fꠅMR&̢Q׬JY_.v߭הoT+I{,p6w$AIЮ-V<ͺI1:3+UL`cr76,@XjU2ȣd<+#~.Ws"mh=k*dVvӲ8㈙@a  J&pŁ.t%jyG q.:N|~ą'+|wh_YPwh< . :X ]]xo 'M^`no޿ݳRG8IAFCCL"j6|Vj[zf^~X.n&u/4cP#"V@MR%ӝ1z&ڽ-7uXw իn FI^U4|jQ99\F, LY@%ϯkeoQiVpKwot"6b$v+Œ.^ɮ3mu7;wԏ0b+_ 34rڻG)#\1YP$B L #B[KKHe| lG*^ҊeSE3  U31@zfvKi/y_1N}?Z%~ :軌%!1C>zw}JA]*ʐ`?Qt\H$82޷{s'MЮ|d >I I H`" "ŻQrhVҴ~ޡG. $S<~jߎ#  r<@dEC޾禷 ;M'%I{; :͢4  [5^U2 |Jwj ѷ8h,ӞOz3M71NhXv֎6 Sm#8QZ.2?voctx#y0F&)օ2+J|MB9M$9 ҏVВ#Q d&Wډ)9H̱UBGoe͖%\ʊ/ lK ͡RN_j)|| c~&u@BPEjwuʼ3I-;W /`AĒ'>,+ȱ)%` N-0OdLK!d'|> [ѺY |)M)B6םBiҠ*_ȿQ: [  X}9'Y2|;%f?Q)rVq_Ru \y܉UbW^&*dO]ĩZs] *(r8* ">gDq>P动%]tlM][=-* RYOvG [ ҭ|S-@Hڏw =|(6#U0 VPdN,ݷV5e|,SOwHFvAv1cuV*ɛRRc.svPgۮ)тܙ̙TJ TJۆue`C R)m֕ J2HmXW6TJ*I Ҷa]P)$)TJۆue`C R)m֕ JxplIENDB`chessx-1.0.0/src/quazip/JlCompress.h000644 001750 001750 00000010335 12223260306 020141 0ustar00niklasniklas000000 000000 #ifndef JLCOMPRESSFOLDER_H_ #define JLCOMPRESSFOLDER_H_ #include "quazip.h" #include "quazipfile.h" #include "quazipfileinfo.h" #include #include #include #include /// Utility class for typical operations. /** This class contains a number of useful static functions to perform simple operations, such as mass ZIP packing or extraction. */ class QUAZIP_EXPORT JlCompress { private: /// Compress a single file. /** \param zip Opened zip to compress the file to. \param fileName The full path to the source file. \param fileDest The full name of the file inside the archive. \return true if success, false otherwise. */ static bool compressFile(QuaZip* zip, QString fileName, QString fileDest); /// Compress a subdirectory. /** \param parentZip Opened zip containing the parent directory. \param dir The full path to the directory to pack. \param parentDir The full path to the directory corresponding to the root of the ZIP. \param recursive Whether to pack sub-directories as well or only files. \return true if success, false otherwise. */ static bool compressSubDir(QuaZip* parentZip, QString dir, QString parentDir, bool recursive = true); /// Extract a single file. /** \param zip The opened zip archive to extract from. \param fileName The full name of the file to extract. \param fileDest The full path to the destination file. \return true if success, false otherwise. */ static bool extractFile(QuaZip* zip, QString fileName, QString fileDest); /// Remove some files. /** \param listFile The list of files to remove. \return true if success, false otherwise. */ static bool removeFile(QStringList listFile); public: /// Compress a single file. /** \param fileCompressed The name of the archive. \param file The file to compress. \return true if success, false otherwise. */ static bool compressFile(QString fileCompressed, QString file); /// Compress a list of files. /** \param fileCompressed The name of the archive. \param files The file list to compress. \return true if success, false otherwise. */ static bool compressFiles(QString fileCompressed, QStringList files); /// Compress a whole directory. /** \param fileCompressed The name of the archive. \param dir The directory to compress. \param recursive Whether to pack the subdirectories as well, or just regular files. \return true if success, false otherwise. */ static bool compressDir(QString fileCompressed, QString dir = QString(), bool recursive = true); public: /// Extract a single file. /** \param fileCompressed The name of the archive. \param fileName The file to extract. \param fileDest The destination file, assumed to be identical to \a file if left empty. \return The list of the full paths of the files extracted, empty on failure. */ static QString extractFile(QString fileCompressed, QString fileName, QString fileDest = QString()); /// Extract a list of files. /** \param fileCompressed The name of the archive. \param files The file list to extract. \param dir The directory to put the files to, the current directory if left empty. \return The list of the full paths of the files extracted, empty on failure. */ static QStringList extractFiles(QString fileCompressed, QStringList files, QString dir = QString()); /// Extract a whole archive. /** \param fileCompressed The name of the archive. \param dir The directory to extract to, the current directory if left empty. \return The list of the full paths of the files extracted, empty on failure. */ static QStringList extractDir(QString fileCompressed, QString dir = QString()); /// Get the file list. /** \return The list of the files in the archive, or, more precisely, the list of the entries, including both files and directories if they are present separately. */ static QStringList getFileList(QString fileCompressed); }; #endif /* JLCOMPRESSFOLDER_H_ */ chessx-1.0.0/src/gui/ecolistwidget.cpp000644 001750 001750 00000011363 12223260306 020536 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "ecolistwidget.h" #include "ui_tagdetailwidget.h" #include "database.h" #include "databaseinfo.h" ECOListWidget::ECOListWidget(QWidget *parent) : QWidget(parent), ui(new Ui::TagDetailWidget) { setObjectName("ECOListWidget"); ui->setupUi(this); m_filterModel = new QStringListModel(this); ui->tagList->setModel(m_filterModel); ui->renameItem->setVisible(false); setObjectName("ECOListWidget"); connect(ui->filterEdit, SIGNAL(textChanged(const QString&)), SLOT(findECO(const QString&))); connect(ui->filterDatabase, SIGNAL(clicked()), SLOT(filterSelectedECO())); connect(ui->tagList, SIGNAL(doubleClicked(const QModelIndex&)), SLOT(filterSelectedECO())); selectECO(QString()); QItemSelectionModel* selectionModel = ui->tagList->selectionModel(); connect(selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(selectionChangedSlot())); ui->detailText->setOpenLinks(true); ui->detailText->setOpenExternalLinks(false); connect(ui->detailText, SIGNAL(anchorClicked(QUrl)), SLOT(slotLinkClicked(QUrl))); slotReconfigure(); } ECOListWidget::~ECOListWidget() { delete ui; } void ECOListWidget::slotReconfigure() { } void ECOListWidget::selectionChangedSlot() { const QModelIndexList& selection = ui->tagList->selectionModel()->selectedIndexes(); if(selection.count()) { QString ts = selection[0].data().toString(); ecoSelected(ts); } else { ecoSelected(QString()); } } void ECOListWidget::findECO(const QString& s) { if(s.isEmpty()) { m_filterModel->setStringList(m_list); } else { QStringList newList = m_list.filter(s, Qt::CaseInsensitive); m_filterModel->setStringList(newList); } } void ECOListWidget::slotSelectECO(const QString& eco) { m_filterModel->setStringList(m_list); ui->filterEdit->clear(); selectECO(eco); } void ECOListWidget::ecoSelected(const QString& eco) { if(!eco.isEmpty()) { m_eco.setCode(eco); ui->filterDatabase->setEnabled(true); ui->renameItem->setEnabled(true); QString head = "ECO List"; QString text = QString("%1

%2

%3

%4%5

%6") .arg(head) .arg(m_eco.name()).arg(m_eco.formattedGameCount()) .arg(m_eco.formattedRating()) .arg(m_eco.formattedScore()) .arg(m_eco.listOfPlayers()); ui->detailText->setHtml(text); } else { ui->filterDatabase->setEnabled(false); ui->renameItem->setEnabled(false); ui->detailText->setText(tr("No ECO code chosen.")); } } void ECOListWidget::selectECO(const QString& eco) { ecoSelected(eco); if(!eco.isEmpty()) { const QStringList& list = m_filterModel->stringList(); int row = list.indexOf(eco); if(row >= 0) { QModelIndex index = m_filterModel->index(row, 0); if(index.isValid()) { ui->tagList->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect); ui->tagList->scrollTo(index); } } } } void ECOListWidget::filterSelectedECO() { const QModelIndexList& selection = ui->tagList->selectionModel()->selectedIndexes(); if(selection.count()) { QString ts = selection[0].data().toString(); emit filterRequest(ts); } } void ECOListWidget::setDatabase(DatabaseInfo* dbInfo) { Database* db = dbInfo->database(); ui->detailText->setText(tr("No ECO code chosen.")); m_eco.setDatabase(db); m_list.clear(); if(db && db->index()) { m_list = db->index()->tagValues(TagNameECO); } m_list.sort(); m_filterModel->setStringList(m_list); m_filterModel->sort(0); } void ECOListWidget::slotLinkClicked(const QUrl& url) { if(url.scheme().startsWith("player")) { QString eco = ui->tagList->currentIndex().data().toString(); emit filterEcoPlayerRequest(url.scheme().contains("white") ? TagNameWhite : TagNameBlack, eco, url.path()); emit filterEcoPlayerRequest(url.path(), eco); } } chessx-1.0.0/src/database/databaseconversion.cpp000644 001750 001750 00000020142 12223260306 022515 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005 Ejner Borgbjerg * * (C) 2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include #include #include #include "databaseconversion.h" bool DatabaseConversion::playerDatabaseFromScidRatings(const QString& inFileName, const QString& outFileName, const QString& pictureDir) { // was tested and works with ratings.ssp from january 2004 // and the latest from http://members.aon.at/schachverein.steyr/ratings.ssp.zip PlayerDatabase pdb; QDir dir = QDir(pictureDir); QStringList pictures = dir.entryList(); if(pdb.removeDatabase(outFileName)) { // std::cout << "removed " << (char*)outFileName.toLatin1().constData() << "\n"; } else { std::cout << "failure removing " << outFileName.toLatin1().constData() << "\n"; } if(pdb.create(outFileName)) { // std::cout << "created " << outFileName.toLatin1().constData() << "\n"; } else { std::cout << "failure creating " << outFileName.toLatin1().constData() << "\n"; return false; } // now read from ratings.ssp QFile inFile(inFileName); if(!(inFile.open(QIODevice::ReadOnly))) { std::cout << "failure opening output file \n"; return false; } QTextStream stream(&inFile); QString line; QString lineStripped; while(!line.startsWith("@PLAYER") && !stream.atEnd()) { line = stream.readLine(); } QString name; int numberOfPlayers = 0; int numberOfPictures = 0; while(!line.startsWith("### END OF PLAYER SECTION") && !stream.atEnd()) { line = stream.readLine(); lineStripped = line.trimmed(); //std::cout << line << "\n"; if(lineStripped.startsWith("#")) //comment line { } else if(lineStripped.length() == 0) //empty line { } // else if(lineStripped.startsWith("=") ) {//name correction line // } else if(lineStripped.startsWith("%Bio")) //Biography note { pdb.appendToBiography(lineStripped.mid(5, 9999) + "
"); } else if(lineStripped.startsWith("%Title")) //title award note - add to biography { pdb.appendToBiography(lineStripped.mid(7, 9999) + "
"); } else if(lineStripped.startsWith("%Render")) //name with special characters fe. Huebner { } else if(lineStripped.startsWith("%Elo")) //elo data { QStringList sl = lineStripped.split(" "); QStringList::Iterator it = sl.begin(); it++; for(; it != sl.end(); it++) { QString s = *it; //std::cout << s << ":"; QStringList sl2 = s.split(":"); QString year = sl2[0]; QString ratings = sl2[1];//ratings for one year, separated by commas QStringList sl3 = ratings.split(","); for(unsigned int i = 0; i < (unsigned int)sl3.size(); i++) { if(sl3[i] != "?") { // std::cout << "rating for " << name << ": " << year << ": " << i+1 << ": " << sl3[i] << "\n"; pdb.setElo(year.toInt(), i + 1, sl3[i].toInt()); } } } } else if(lineStripped.startsWith("%")) //unknown code { //std::cout << "unknown code in ratings.ssp \n"; //std::cout << line << "\n"; //ignore, as all kinds of tournament names are there now. //return false; } else if(lineStripped.startsWith("= ")) //name alias { //std::cout << "name alias line: " << lineStripped << "\n"; QString nameAlias = lineStripped.mid(2); if(!pdb.hasPhoto()) { //look for players picture //std::cout << "nameAlias= " << nameAlias << "\n"; for(int i = 0; i < pictures.size(); i++) { QStringList sl4 = pictures.at(i).split("."); if(sl4[0].compare(nameAlias) == 0) { QImage* img = new QImage(dir.path() + "/" + (pictures.at(i))); pdb.setPhoto(*img); numberOfPictures++; pictures.removeAt(i); break; } } } } else //name line { if(numberOfPlayers % 1000 == 0 && numberOfPlayers > 0) { std::cout << "processed: " << numberOfPlayers << "\n"; pdb.commit();//seems binary content changed when doing this ?! } QStringList sl0 = line.split("#"); name = sl0[0].trimmed(); int index = sl0[1].indexOf(QChar(' ')); QString title = sl0[1].left(index); QString rest = sl0[1].mid(index, 9999); // std::cout << "name= " << name << "\n"; // std::cout << "title= " << title << "\n"; // std::cout << "rest= " << rest << "\n"; if(!pdb.add(name)) { std::cout << "failed adding player: " << name.toLatin1().constData() << "\n"; } //look for players picture for(int i = 0; i < pictures.size(); i++) { QStringList sl4 = pictures.at(i).split("."); if(sl4[0].compare(name) == 0) { QImage* img = new QImage(dir.path() + "/" + pictures.at(i)); pdb.setPhoto(*img); numberOfPictures++; pictures.removeAt(i); break; } } numberOfPlayers++; pdb.setTitle(title); QStringList sl = rest.split(" "); for(QStringList::Iterator it = sl.begin(); it != sl.end(); ++it) { QString s = *it; //std::cout << s << ":"; if(s.startsWith("[")) //rating, peak or estimated { s = s.mid(1, s.length() - 2); //std::cout << "rating= " << s; if(s.endsWith("*")) { pdb.setEstimatedElo(s.left(s.length() - 1).toInt()); } // peak elo is dealt with by setElo() } else if(s.contains(".")) //birth date and/or death date { if(s.startsWith("--")) //only death date(!) Baay is an example { pdb.setDateOfDeath(s.mid(2, 10)); } else { pdb.setDateOfBirth(s.left(10)); if(s.length() >= 22) { pdb.setDateOfDeath(s.mid(12, 10)); } } } else //country code(s) { pdb.setCountry(s); } } // std::cout << "\n"; }//name line } inFile.close(); // std::cout << numberOfPlayers << " players read in from ratings.ssp\n"; // std::cout << numberOfPictures << " players had a picture\n"; // for (QStringList::Iterator it = pictures.begin(); it != pictures.end(); ++it) { // std::cout << "player picture that was not converted: " << (*it).toLatin1().constData() << "\n"; // } pdb.commit(); pdb.close(); return true; } chessx-1.0.0/src/database/playerinfo.cpp000644 001750 001750 00000015070 12223260306 021017 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include #include #include "playerinfo.h" #include "database.h" static bool sortEcoFrequencyLt(const EcoFrequencyItem& a1, const EcoFrequencyItem& a2) { if(a1.second == a2.second) { return (a1.first < a2.first); } return a1.second > a2.second; } PlayerInfo::PlayerInfo() { m_database = 0; reset(); } PlayerInfo::~PlayerInfo() { } PlayerInfo::PlayerInfo(Database* db, const QString & player) { setDatabase(db); setName(player); reset(); update(); } QString PlayerInfo::name() const { return m_name; } void PlayerInfo::setDatabase(Database* db) { m_database = db; } void PlayerInfo::setName(const QString& player) { m_name = player; update(); } int PlayerInfo::toResult(const QString& res) const { if(res.startsWith("1/2")) { return Draw; } else if(res.startsWith('1')) { return WhiteWin; } else if(res.startsWith('0')) { return BlackWin; } else { return ResultUnknown; } } void PlayerInfo::update() { QHash openings[2]; const Index* index = m_database->index(); // Determine matching tag values ValueIndex player = index->getValueIndex(m_name); // Clean previous statistics reset(); for(int i = 0; i < m_database->count(); ++i) { Color c; if(index->valueIndexFromTag(TagNameWhite, i) == player) { c = White; } else if(index->valueIndexFromTag(TagNameBlack, i) == player) { c = Black; } else { continue; } int res = toResult(index->tagValue(TagNameResult, i)); m_result[c][res]++; m_count[c]++; int elo = index->tagValue(c == White ? TagNameWhiteElo : TagNameBlackElo, i).toInt(); if(elo) { m_rating[0] = qMin(elo, m_rating[0]); m_rating[1] = qMax(elo, m_rating[1]); } PartialDate date(index->tagValue(TagNameDate, i)); if(date.year() > 1000) { m_date[0] = qMin(date, m_date[0]); m_date[1] = qMax(date, m_date[1]); } QString eco = index->tagValue(TagNameECO, i).left(3); if(eco.length() == 3) { openings[c][eco]++; } } for(int i = 0; i < 2; ++i) { foreach(QString s, openings[i].keys()) { m_eco[i].append(EcoFrequencyItem(s, openings[i].value(s))); qSort(m_eco[i].begin(), m_eco[i].end(), sortEcoFrequencyLt); } } qSwap(m_result[Black][WhiteWin], m_result[Black][BlackWin]); } QString PlayerInfo::formattedScore(const int result[4], int count) const { if(!count) { return QCoreApplication::translate("PlayerInfo", "no games"); } QString score = ""; QChar scoresign[4] = {'*', '+', '=', '-'}; for(int i = WhiteWin; i <= BlackWin; ++i) { score += QString("  %1%2").arg(scoresign[i]).arg(result[i]); } if(result[ResultUnknown]) { score += QString("  *%1").arg(result[ResultUnknown]); } if(count - result[ResultUnknown]) score += QString("  (%1%)"). arg((100.0 * result[WhiteWin] + 50.0 * result[Draw]) / (count - result[ResultUnknown]), 1, 'f', 1); score += ""; return score; } QString PlayerInfo::formattedScore() const { int total[4]; for(int i = 0; i < 4; ++i) { total[i] = m_result[White][i] + m_result[Black][i]; } int count = m_count[White] + m_count[Black]; return QCoreApplication::translate("PlayerInfo", "Total: %1
White: %2
Black: %3
") .arg(formattedScore(total, count)) .arg(formattedScore(m_result[White], m_count[White])) .arg(formattedScore(m_result[Black], m_count[Black])); } void PlayerInfo::reset() { for(int c = White; c <= Black; ++c) { for(int r = 0; r < 4; ++r) { m_result[c][r] = 0; } m_count[c] = 0; m_eco[c].clear(); } m_rating[0] = 99999; m_rating[1] = 0; m_date[0] = PDMaxDate; m_date[1] = PDMinDate; } QString PlayerInfo::formattedGameCount() const { return QCoreApplication::translate("PlayerInfo", "Games in database %1: %2
") .arg(m_database->name()).arg(m_count[White] + m_count[Black]); } QString PlayerInfo::formattedRating() const { if(!m_rating[1]) { return QString(); } else if(m_rating[0] == m_rating[1]) { return QCoreApplication::translate("PlayerInfo", "Rating: %1
").arg(m_rating[0]); } else return QCoreApplication::translate("PlayerInfo", "Rating: %1-%2
") .arg(m_rating[0]).arg(m_rating[1]); } QString PlayerInfo::formattedRange() const { if(m_date[0].year() == 9999) // No date { return QCoreApplication::translate("PlayerInfo", "Date: ????.??.\?\?
"); } else if(m_date[0].year() < 1000) { return QString(); } else { return QCoreApplication::translate("PlayerInfo", "Date: %1
").arg(m_date[0].range(m_date[1])); } } QString PlayerInfo::listOfOpenings() const { QStringList openingsList; openingsList.append(QCoreApplication::translate("PlayerInfo", "

White Openings:

    ")); openingsList.append(QCoreApplication::translate("PlayerInfo", "

Black Openings:

    ")); for(int i = 0; i < 2; ++i) { for(EcoFrequency::const_iterator it = m_eco[i].begin(); it != m_eco[i].end(); ++it) { openingsList[i] += QString("
  • %3: %4") .arg(i == 0 ? "white" : "black") .arg((*it).first) .arg((*it).first) .arg((*it).second); } } QString s = openingsList.at(0); s = s.append(openingsList.at(1)); s = s.append("
"); return s; } chessx-1.0.0/data/lang/000755 001750 001750 00000000000 12234251045 015441 5ustar00niklasniklas000000 000000 chessx-1.0.0/src/database/rand64.h000644 001750 001750 00000202540 12223260306 017412 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005 Marius Roets * * (C) 2006-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __RAND64_H__ #define __RAND64_H__ #define MAX_PIECES 12 #define MAX_SQUARES 64 #define MAX_EN_PASSANT_SQUARES 16 const quint64 RAND_VALUES[MAX_PIECES][MAX_SQUARES] = { { Q_UINT64_C(0x1ec62f17201666a9), Q_UINT64_C(0xbbfacfa8b9cedc99), Q_UINT64_C(0xd52582ca4006e48d), Q_UINT64_C(0xbe5cc29389b0a011), Q_UINT64_C(0x70b7b299fa084b79), Q_UINT64_C(0x31fc91d4b888aac6), Q_UINT64_C(0x953d8d65f16a27f5), Q_UINT64_C(0xa9e1894a083988a6), Q_UINT64_C(0x21454de44a9c3b61), Q_UINT64_C(0x5f8b1149ed761b1d), Q_UINT64_C(0x175d8e3320bc756e), Q_UINT64_C(0xdf290612a1c03992), Q_UINT64_C(0xe8eb7e4dd25319a8), Q_UINT64_C(0xaf4b12ca66fd9c4), Q_UINT64_C(0xbc7a46849f1ecb92), Q_UINT64_C(0x3176f59e6d590325), Q_UINT64_C(0xba1dd7cef5e19864), Q_UINT64_C(0x66354050f7debe97), Q_UINT64_C(0xa9bf0a169bacd362), Q_UINT64_C(0x6fbcab3c9569da6c), Q_UINT64_C(0xf776879f9737354a), Q_UINT64_C(0x1bb627864a4de101), Q_UINT64_C(0x7e0e89ff7ed651a4), Q_UINT64_C(0xd60fbbffa2bc218e), Q_UINT64_C(0x9fae83ea899cdc65), Q_UINT64_C(0xe968a74b29e28a00), Q_UINT64_C(0x7441d6653deb9005), Q_UINT64_C(0x114e67f4d201286), Q_UINT64_C(0xb570a88f1bb4a04f), Q_UINT64_C(0x979a9ed22e05d8f5), Q_UINT64_C(0x5c07b95482adfa30), Q_UINT64_C(0x895a9ebc0f0425f9), Q_UINT64_C(0xeb9c39059e157744), Q_UINT64_C(0x56eaba15345d2d3f), Q_UINT64_C(0xe16e06e1d7ecc810), Q_UINT64_C(0x36e6163492b22bd2), Q_UINT64_C(0xb16091b81a2e4d3f), Q_UINT64_C(0x457ccde451eb1bc7), Q_UINT64_C(0x84d57d447975de25), Q_UINT64_C(0x9f9e74faa2ad3bd3), Q_UINT64_C(0x24c7ae8acd3ad30d), Q_UINT64_C(0xa3cbda8eb6cd6d17), Q_UINT64_C(0x92d9ee42cbfa4f52), Q_UINT64_C(0x438f893e666ffa6b), Q_UINT64_C(0x3ccc5d24464f62b1), Q_UINT64_C(0xcfa9275812d9e5db), Q_UINT64_C(0xbbf17284897c0f48), Q_UINT64_C(0xa077f2f8f190127b), Q_UINT64_C(0x5fdeec8850464c2b), Q_UINT64_C(0x9429d7f4c15885f4), Q_UINT64_C(0x4dcac2831e23e842), Q_UINT64_C(0x4e109f15c27a18bf), Q_UINT64_C(0x8999f31dcc6fe7a9), Q_UINT64_C(0x38d5a8a6044dd9ee), Q_UINT64_C(0xa744dd883d5c7225), Q_UINT64_C(0xeeb12aaf9f92ef25), Q_UINT64_C(0xb1b218b1bb67cf61), Q_UINT64_C(0xe83e436e7362d9de), Q_UINT64_C(0x537512d7cdb2153b), Q_UINT64_C(0xd6483b5692e687aa), Q_UINT64_C(0x6b0a45a3318c51d5), Q_UINT64_C(0x226771aa9189c198), Q_UINT64_C(0x53235ce529bfd016), Q_UINT64_C(0x5ca80b4f2d5e1eb6) } , { Q_UINT64_C(0x53245edcd60cf397), Q_UINT64_C(0x7f6a708b5e8c84a4), Q_UINT64_C(0x325e8b4fb9a1aa4), Q_UINT64_C(0x14887c78f2a09203), Q_UINT64_C(0xc2bb16d21c0bc8cc), Q_UINT64_C(0xe055caaa118766fc), Q_UINT64_C(0x359748cb791ec67d), Q_UINT64_C(0x3b61d875ea2b7561), Q_UINT64_C(0x2a1b6c8960df15e0), Q_UINT64_C(0x9bf0d7a44740e32f), Q_UINT64_C(0xc22bf6c21eee246f), Q_UINT64_C(0xc020519cb401d072), Q_UINT64_C(0xf0968c3468e10e2), Q_UINT64_C(0xac96e408328061cb), Q_UINT64_C(0x7f7777aa95130c9b), Q_UINT64_C(0x6ce2af6150e0495a), Q_UINT64_C(0xabf54956d8e7b2ae), Q_UINT64_C(0x5d61b62788db096f), Q_UINT64_C(0x1dd0995e3a3833f6), Q_UINT64_C(0x4830b9ec0a52efea), Q_UINT64_C(0x4b6deac9ba54aed7), Q_UINT64_C(0xd8a5b2d82eb070ef), Q_UINT64_C(0xc78f51efd50a99d), Q_UINT64_C(0xb2d750e4cc381595), Q_UINT64_C(0xcc5a3d6cc8412cf9), Q_UINT64_C(0x716449e782e7c15e), Q_UINT64_C(0x60971d4c2dd8a2de), Q_UINT64_C(0xd181dae3d9e17d00), Q_UINT64_C(0xa51553f160a644a), Q_UINT64_C(0x33c2e7d569cfe4ff), Q_UINT64_C(0xf5463eadaa35d7b1), Q_UINT64_C(0x8597d849d5df0697), Q_UINT64_C(0x54673596ef45e29f), Q_UINT64_C(0x2753a9185702bdec), Q_UINT64_C(0x68edde16eb851e87), Q_UINT64_C(0xe63abaa5324431d8), Q_UINT64_C(0x238e3822a5480bbf), Q_UINT64_C(0x569dfbff9e7a3228), Q_UINT64_C(0x583d319124ecc023), Q_UINT64_C(0x174c93c203e706ca), Q_UINT64_C(0x75515b06b221631f), Q_UINT64_C(0xa3c0046d21d3937a), Q_UINT64_C(0x786176c17d7255e2), Q_UINT64_C(0x7fe7b6e3fee8447b), Q_UINT64_C(0x36b33d94116aa3d6), Q_UINT64_C(0xa540f2adc881ad04), Q_UINT64_C(0xc8e77cabc847bb78), Q_UINT64_C(0x3bb391ff43276713), Q_UINT64_C(0x9195bbff45b7f7e2), Q_UINT64_C(0x79019d67f09cbcc8), Q_UINT64_C(0xa8f17ad8e5ff080e), Q_UINT64_C(0x345b6fbbb3a98cd3), Q_UINT64_C(0x280ec7eb3f29a129), Q_UINT64_C(0x8cf0d5580efabe5e), Q_UINT64_C(0xd74514789ff96be4), Q_UINT64_C(0xaf51af61e09dcf72), Q_UINT64_C(0x2d886dba5494feb9), Q_UINT64_C(0x47847fb8831e9742), Q_UINT64_C(0x9c4645caf979f848), Q_UINT64_C(0xbdcb1b461cbac0bb), Q_UINT64_C(0xe0f76bfdabb9f044), Q_UINT64_C(0x452df2be09d5455a), Q_UINT64_C(0x6360e134cb41175a), Q_UINT64_C(0xedf28a4ba7818d3b) } , { Q_UINT64_C(0xcadac8d042c2659d), Q_UINT64_C(0x454389d89b0bf801), Q_UINT64_C(0xec352b4584ab0ba2), Q_UINT64_C(0x7d109cb245e59d87), Q_UINT64_C(0x68a74d8f67ac0998), Q_UINT64_C(0x2da1d772e2672337), Q_UINT64_C(0x95c65d9f325a81a9), Q_UINT64_C(0x35c69e246ea2a2a), Q_UINT64_C(0x7b2584588863292a), Q_UINT64_C(0x3e7d05d5e89afde4), Q_UINT64_C(0x58171422cfdfec83), Q_UINT64_C(0xd9a2075d95f868da), Q_UINT64_C(0x1da8afd77bdee29b), Q_UINT64_C(0x8d25e865fa5d1f41), Q_UINT64_C(0x5cad8f0581b90560), Q_UINT64_C(0xb8723d6f3e47b827), Q_UINT64_C(0xe1e4abe6712a85f9), Q_UINT64_C(0x8f0c5a1f19477a43), Q_UINT64_C(0x9407dd91b7023406), Q_UINT64_C(0x570a67babc5dffa8), Q_UINT64_C(0x965a6a2c6308a099), Q_UINT64_C(0x7e873487004f9484), Q_UINT64_C(0xac9ef8359380d43a), Q_UINT64_C(0xaff31969a6d0e11f), Q_UINT64_C(0xe4b3607a61f4ebf2), Q_UINT64_C(0xd30d436ce815daa6), Q_UINT64_C(0xf2ec127dd9b24bc0), Q_UINT64_C(0x29d24cc261e39f76), Q_UINT64_C(0xfdf4d684c0def5a4), Q_UINT64_C(0x3a91401a9f01288d), Q_UINT64_C(0x3d8f6a35d8bc4aaf), Q_UINT64_C(0x125dd19b7b757b2c), Q_UINT64_C(0xbe494ce02ed6499d), Q_UINT64_C(0x1880774dacc00e63), Q_UINT64_C(0x440f9561070c655), Q_UINT64_C(0xac5d0be114b6a229), Q_UINT64_C(0xdb3375c59bf08566), Q_UINT64_C(0xa10ced9c93388160), Q_UINT64_C(0x54a4dad59cc2c007), Q_UINT64_C(0x559408bc146bbebd), Q_UINT64_C(0xb8bad0664b209c79), Q_UINT64_C(0xbf586f0e24fefe87), Q_UINT64_C(0xec6d94b7a39286d1), Q_UINT64_C(0xed7c1459a5dc2519), Q_UINT64_C(0x4978282330d42273), Q_UINT64_C(0xff3fd26a98417ca), Q_UINT64_C(0xf26c9f7ae2b230b5), Q_UINT64_C(0x8c94dbd31f38dfbf), Q_UINT64_C(0xd5a3e7288ebf4c96), Q_UINT64_C(0x6e3944a9cd85a4c5), Q_UINT64_C(0xba9c4bc7e7b5c9d9), Q_UINT64_C(0x33e8ebb8ab9dca03), Q_UINT64_C(0xaa2c2de0783569d0), Q_UINT64_C(0x2b85abd021bf9d89), Q_UINT64_C(0xa439c8d9600cd247), Q_UINT64_C(0x622af17e71ccf035), Q_UINT64_C(0x2d5461656222a132), Q_UINT64_C(0x757de25d90c312b2), Q_UINT64_C(0x5bf4142296887e24), Q_UINT64_C(0x1f57f40b682dfae4), Q_UINT64_C(0x5900905f7327b2fa), Q_UINT64_C(0x55d3cee7500a070a), Q_UINT64_C(0x28431e31c56377f6), Q_UINT64_C(0xf2bac6ac56be5bd0) } , { Q_UINT64_C(0xdf46c89083b67e29), Q_UINT64_C(0xa79e77d5e82473b), Q_UINT64_C(0x1acf90d006f2a77f), Q_UINT64_C(0x161a43fe951ed4e), Q_UINT64_C(0x684fe4624c50d017), Q_UINT64_C(0x9d56130f929b7b28), Q_UINT64_C(0x5612e8d14194e557), Q_UINT64_C(0x8317bf19e7c0ec61), Q_UINT64_C(0x4bed0c56e8ae7c16), Q_UINT64_C(0x6524d908ba6fd75a), Q_UINT64_C(0xef1a4afc64d2dec2), Q_UINT64_C(0xcc91a06a6aed0e5b), Q_UINT64_C(0xe8caf25e2e3131f), Q_UINT64_C(0xc682ff6ccc7fbce9), Q_UINT64_C(0xb90a317118687ab2), Q_UINT64_C(0x483fdd9d5943b01b), Q_UINT64_C(0xd9ab9bfdcab982e4), Q_UINT64_C(0x8c36670af77644c3), Q_UINT64_C(0xbeec4e0f0681b526), Q_UINT64_C(0xeba28e747d18b8f0), Q_UINT64_C(0x2e101a99326fea47), Q_UINT64_C(0xddda32425f702ea0), Q_UINT64_C(0xc0b14cad105e3672), Q_UINT64_C(0x359cd242522f1563), Q_UINT64_C(0xd6affd6dc37876be), Q_UINT64_C(0x35bda8df5ead1224), Q_UINT64_C(0xc20e838ad96bba45), Q_UINT64_C(0x92291e135d8e98f1), Q_UINT64_C(0xd4d628339ae65ffc), Q_UINT64_C(0xfeccbee630743e10), Q_UINT64_C(0x58e92ff7f6be6df2), Q_UINT64_C(0x1e57637797590664), Q_UINT64_C(0x7203145c2f63a685), Q_UINT64_C(0x8fec2a2b0bead59d), Q_UINT64_C(0xdd56487be5b8c600), Q_UINT64_C(0x8b11513f987dc92c), Q_UINT64_C(0x1594970f9cab8f30), Q_UINT64_C(0x1bb5f0ea58bfeff2), Q_UINT64_C(0x42ff96fc97d2ebd4), Q_UINT64_C(0x7cb5664988b73c3f), Q_UINT64_C(0xf27eb6647cd62c13), Q_UINT64_C(0x30a27ac7b6107567), Q_UINT64_C(0xeaf3b797f5e00eba), Q_UINT64_C(0xd35e513359631e1f), Q_UINT64_C(0xc9f7f89c795c345c), Q_UINT64_C(0xf400f0cb9df71b18), Q_UINT64_C(0xc82d0a7de2b8c037), Q_UINT64_C(0xf79bf08329ee7b74), Q_UINT64_C(0xcf53f738e1b27b1f), Q_UINT64_C(0x949207eb00202221), Q_UINT64_C(0xb0aac2d90efef7a7), Q_UINT64_C(0x67144a43ef08d0ab), Q_UINT64_C(0xb58a58edfc076d67), Q_UINT64_C(0xc18306361a8ae880), Q_UINT64_C(0x900136708271a8d7), Q_UINT64_C(0x4c62781522d048eb), Q_UINT64_C(0x62f096438e887dee), Q_UINT64_C(0xf35dd72cab848b30), Q_UINT64_C(0x94e3a6cdb64a1d46), Q_UINT64_C(0x38a2d0bfa0bbcb49), Q_UINT64_C(0x1e2e21c184b7a78d), Q_UINT64_C(0xcaabdc94b883b7c4), Q_UINT64_C(0xe730d8e63586e008), Q_UINT64_C(0x9b46fc7effbf9fac) } , { Q_UINT64_C(0xf3c9da6687146357), Q_UINT64_C(0xbc0fc65dbeb389bc), Q_UINT64_C(0x9be6bbd61f09bf49), Q_UINT64_C(0x2140339ed7c11b99), Q_UINT64_C(0x6fc48df6290562cd), Q_UINT64_C(0x380b4bff46db1f22), Q_UINT64_C(0x1ada26b72231ccb5), Q_UINT64_C(0x705a1f7bdedaa01e), Q_UINT64_C(0xa2d620ab9407e5d0), Q_UINT64_C(0x67ab1673e4980aea), Q_UINT64_C(0xafc2252962d550a4), Q_UINT64_C(0xf3dfaf76b775c562), Q_UINT64_C(0x5ccbef3d0397c662), Q_UINT64_C(0x1b3b57a62eeae95), Q_UINT64_C(0xaec1518190e067c5), Q_UINT64_C(0x37488a3d36314db2), Q_UINT64_C(0x961eff8f15d8504a), Q_UINT64_C(0x64ff8e2e721a603c), Q_UINT64_C(0x681143138be3ec55), Q_UINT64_C(0x5ecbdb18d4c08510), Q_UINT64_C(0xd2c8dd0b141f60b8), Q_UINT64_C(0x90906cc9ba81725f), Q_UINT64_C(0x6e6ceecf99b39cda), Q_UINT64_C(0x3833b12c83573c84), Q_UINT64_C(0x77d6cce0c53d35c6), Q_UINT64_C(0xeaec84bd94c7a906), Q_UINT64_C(0x4e438c6201dfe450), Q_UINT64_C(0xe01676f81ef373d3), Q_UINT64_C(0x90b2023a3ee105ae), Q_UINT64_C(0x6d8598e2dc2a22cb), Q_UINT64_C(0x7aec68a3a3616522), Q_UINT64_C(0xd2751bc8535dcec1), Q_UINT64_C(0x5220c84bb8c51285), Q_UINT64_C(0x57810a9091810fbd), Q_UINT64_C(0x71a46e32f4e57778), Q_UINT64_C(0x4b44d5b5d146bfc), Q_UINT64_C(0x2943475171c4730c), Q_UINT64_C(0x422be94e746cea55), Q_UINT64_C(0x2696be9f46720f2f), Q_UINT64_C(0x34588bcf5b61c2bc), Q_UINT64_C(0xdcd4a8018a685369), Q_UINT64_C(0x59e93e1485a41634), Q_UINT64_C(0xc31571199e9eb91b), Q_UINT64_C(0x4ffe620332c7095b), Q_UINT64_C(0x4bac0fa0a2cf284d), Q_UINT64_C(0x1c035a2a33cefe8f), Q_UINT64_C(0xd6ae8360e511267), Q_UINT64_C(0xc9cc8849a2a35773), Q_UINT64_C(0xc880c44800e4b171), Q_UINT64_C(0x4657625b07c46cba), Q_UINT64_C(0x9e9cae5ad99cf4bd), Q_UINT64_C(0xbcda94886adc4193), Q_UINT64_C(0x969c91aed057979e), Q_UINT64_C(0x45f618b5564b7b33), Q_UINT64_C(0x8e7c8c99777ef253), Q_UINT64_C(0x8e9e9771832e577d), Q_UINT64_C(0x91dde22a9480b4bd), Q_UINT64_C(0x70ddf3148befa451), Q_UINT64_C(0x10b84400fa414520), Q_UINT64_C(0xbc5a066b606baf65), Q_UINT64_C(0x514dd10b07527017), Q_UINT64_C(0xcbab54a0ff2c2a98), Q_UINT64_C(0xfd7421297472cf1b), Q_UINT64_C(0x59f1839342ef0fb7) } , { Q_UINT64_C(0xc75866298a6e4bac), Q_UINT64_C(0xc8ee38b2898619e0), Q_UINT64_C(0x7f979c89244eb074), Q_UINT64_C(0x6dfe79552a503ae7), Q_UINT64_C(0x84e2657e2ef4ea59), Q_UINT64_C(0x5212c47457504706), Q_UINT64_C(0xc2d6c23f1ff0fbd8), Q_UINT64_C(0xead331b5f2fbe7cc), Q_UINT64_C(0x196b78ae8fab6cec), Q_UINT64_C(0x82e9b89e64e183d4), Q_UINT64_C(0xedf8a811a8525983), Q_UINT64_C(0x81401e0a707f4a2a), Q_UINT64_C(0xe97db9ef64670a17), Q_UINT64_C(0xdca4e599aa2b2046), Q_UINT64_C(0x55997b5728384a93), Q_UINT64_C(0xefea3f38b47dc02), Q_UINT64_C(0xf7715d0117066b50), Q_UINT64_C(0x202f640d407c7784), Q_UINT64_C(0x41fc2d1db8d2c58a), Q_UINT64_C(0xf1aea04995261294), Q_UINT64_C(0x1b97ca9b94818e5c), Q_UINT64_C(0x1a604d81c6832882), Q_UINT64_C(0x29de3de90ec4b09c), Q_UINT64_C(0x833b362a95d350cc), Q_UINT64_C(0x92bb628c33d0c1a6), Q_UINT64_C(0x17b218339404dff9), Q_UINT64_C(0x8ecc53ee80c128fd), Q_UINT64_C(0xde322a7a6d6d0b7f), Q_UINT64_C(0x9a1bf2c58b17b96d), Q_UINT64_C(0x46841b0080569274), Q_UINT64_C(0x175635b631158926), Q_UINT64_C(0x97e00b81c49f16a7), Q_UINT64_C(0xb0b7c04c7b91bbf), Q_UINT64_C(0x7b6f44fe486244c), Q_UINT64_C(0x6e3abe3d9168fa01), Q_UINT64_C(0xb8e6064f060e9848), Q_UINT64_C(0x9a7407276634a98f), Q_UINT64_C(0x8dddb9a33d0af4c), Q_UINT64_C(0xf48074674a428565), Q_UINT64_C(0x4c42426a115ca77c), Q_UINT64_C(0x2e476b77c7666bad), Q_UINT64_C(0x3ff12da796160fa8), Q_UINT64_C(0xb6b1986a2ecba623), Q_UINT64_C(0x1e5bf26bac6a2cc8), Q_UINT64_C(0xe854e404456189d7), Q_UINT64_C(0xa6bc5714b0e06a85), Q_UINT64_C(0xd94634b1c5575759), Q_UINT64_C(0x22edb1d386f7a76b), Q_UINT64_C(0x5425da975aa39f5), Q_UINT64_C(0x6ad785b5f1cb9ba3), Q_UINT64_C(0x92f67a06e954aa6c), Q_UINT64_C(0x808537a95a748260), Q_UINT64_C(0x6cf997acd7762b1c), Q_UINT64_C(0x61bb904dbec76cc7), Q_UINT64_C(0xd3646f8af70ef000), Q_UINT64_C(0xdcff1f6ef367b6ea), Q_UINT64_C(0xf66e9417cc7b0cae), Q_UINT64_C(0x8399ddcbbcc6a55c), Q_UINT64_C(0xb3f777be95923c1c), Q_UINT64_C(0x6386d01553c46e6d), Q_UINT64_C(0x1d342f505e226825), Q_UINT64_C(0x8c484323c0c0c008), Q_UINT64_C(0x7a7acbc76ac93bdc), Q_UINT64_C(0x5c61d0590ea1a132) } , { Q_UINT64_C(0x2f64bef8708ccc76), Q_UINT64_C(0x8f69cb123b86b473), Q_UINT64_C(0x14629d43439b0b9a), Q_UINT64_C(0xb51615b61addd932), Q_UINT64_C(0x56083fb3f25972d2), Q_UINT64_C(0x5824911f1514af24), Q_UINT64_C(0xcc31f9a300cd86fb), Q_UINT64_C(0x106f10489953b0f0), Q_UINT64_C(0x4e0da08ed53e3f42), Q_UINT64_C(0x861454c96e778a89), Q_UINT64_C(0x85fa8e9cb37aebe4), Q_UINT64_C(0x185f7b31ecc2b80f), Q_UINT64_C(0x77b4840c225dba24), Q_UINT64_C(0x21f3044fd95b9644), Q_UINT64_C(0xb10b52c194b80c12), Q_UINT64_C(0xd3511042b3dc6e17), Q_UINT64_C(0x127c6a623e7a8096), Q_UINT64_C(0xac40b42d23979b50), Q_UINT64_C(0x24eaf6e4d79f81dd), Q_UINT64_C(0xc188cff8736251b9), Q_UINT64_C(0x12392eb101fe558e), Q_UINT64_C(0x2e402c80d947c34), Q_UINT64_C(0x8b9d039619325a97), Q_UINT64_C(0x5d9b0636b0704c83), Q_UINT64_C(0x8a94b7d08b8d601d), Q_UINT64_C(0x5733a1895681c0aa), Q_UINT64_C(0xdd5a40d653d15e74), Q_UINT64_C(0xbb054e3cf7ccbacd), Q_UINT64_C(0x6e4b27ff19f158fb), Q_UINT64_C(0x41e3901659df0572), Q_UINT64_C(0xf6e26bfacb2b1d27), Q_UINT64_C(0x4fefc0f2472ecd13), Q_UINT64_C(0x3e27d9ba892b921e), Q_UINT64_C(0x948f060bc89c832a), Q_UINT64_C(0x8baa3f0efc1c2af2), Q_UINT64_C(0x2381a923ba396109), Q_UINT64_C(0xd3b06958774253f0), Q_UINT64_C(0xb445b670f7c832e), Q_UINT64_C(0xa2be518eb068da7c), Q_UINT64_C(0x3bbb38d5b2cdd554), Q_UINT64_C(0x1da3d990a138c7b6), Q_UINT64_C(0xc8e233f9accae801), Q_UINT64_C(0xa05e74f15d3eeef5), Q_UINT64_C(0xfea7f74d1c9bcaff), Q_UINT64_C(0xae0b4bfcf6a32afa), Q_UINT64_C(0x6be0332e6af8a0cf), Q_UINT64_C(0x943177446ddd6775), Q_UINT64_C(0xba0da641f019b36e), Q_UINT64_C(0x384025f9ab18fbba), Q_UINT64_C(0x1939888bb6674ce0), Q_UINT64_C(0x59e11e6d2f07fa4b), Q_UINT64_C(0xa596f492bd8f9bca), Q_UINT64_C(0xe939068dd320fec1), Q_UINT64_C(0xdcc4c3618c975c), Q_UINT64_C(0x486fcb60f496caa), Q_UINT64_C(0xcd6e638cc3106b1a), Q_UINT64_C(0x28b8c5a56fc98845), Q_UINT64_C(0x349ddc52f07e66d6), Q_UINT64_C(0xdc5b17f35598ab96), Q_UINT64_C(0x536c255baf56d4ec), Q_UINT64_C(0x7d58b9aa06d26aa3), Q_UINT64_C(0xc479e0c6ddbc2a4e), Q_UINT64_C(0x668cbed0f5dcbea), Q_UINT64_C(0x751054ba6613a289) } , { Q_UINT64_C(0x3c7280b077d6d7a), Q_UINT64_C(0xe12382c91253cda1), Q_UINT64_C(0xbefda033140e3cb7), Q_UINT64_C(0x1b6f806491b094b5), Q_UINT64_C(0x1e98babfcc965316), Q_UINT64_C(0x57d2ade56704a531), Q_UINT64_C(0xd54fc0a170ffd7aa), Q_UINT64_C(0x354ead717998c00d), Q_UINT64_C(0xeae96f6e4b1508c1), Q_UINT64_C(0x7c0dc22bf8632b40), Q_UINT64_C(0x83bc6818b369f89a), Q_UINT64_C(0x4efc4febd26e4b42), Q_UINT64_C(0xf8ceefc9feb1874f), Q_UINT64_C(0xf845bec6c1ccf8a0), Q_UINT64_C(0x3e2b5a324714c3bb), Q_UINT64_C(0x1d9eab2892b42859), Q_UINT64_C(0xb25280c92f83b2a2), Q_UINT64_C(0xeff78ea70b1c5e36), Q_UINT64_C(0x6d4de2bb930efe72), Q_UINT64_C(0x64b95da4f88ca989), Q_UINT64_C(0xfac373fc552add76), Q_UINT64_C(0x3c841f46705e8b18), Q_UINT64_C(0xc32fb541343401f9), Q_UINT64_C(0xf2c11cce7a469839), Q_UINT64_C(0xb817729006c14c65), Q_UINT64_C(0x1071ec724569f6af), Q_UINT64_C(0x621edfa9de9439e7), Q_UINT64_C(0x1a22c4d5150f2baa), Q_UINT64_C(0x75cca15a55258a3d), Q_UINT64_C(0x24f570d7d46087f1), Q_UINT64_C(0x73a8a9518592ea87), Q_UINT64_C(0x925f5b9e52691f97), Q_UINT64_C(0xb9b2c60211b8ee24), Q_UINT64_C(0x4308bc03f750dbc6), Q_UINT64_C(0xfc913f36d178361f), Q_UINT64_C(0x63322686eb9ad5fa), Q_UINT64_C(0x58a258ad8bfe49ce), Q_UINT64_C(0x6e58e93d4969b576), Q_UINT64_C(0x4cfdeb892f7103d9), Q_UINT64_C(0xe6d396b7019b60fa), Q_UINT64_C(0x891d9d8a680b0fe9), Q_UINT64_C(0x3af29f54df3c8952), Q_UINT64_C(0x4e4ab77a442734fe), Q_UINT64_C(0x6e9ee2c78557d228), Q_UINT64_C(0x39205e41d0b4f1bd), Q_UINT64_C(0x2d7afbfd5b402083), Q_UINT64_C(0xefaaa35cfcb13cd3), Q_UINT64_C(0xd5eb1dcb6c10d071), Q_UINT64_C(0xec6670a35fef81f5), Q_UINT64_C(0xec28f44e30a9996c), Q_UINT64_C(0x20f1adb9f2960c1e), Q_UINT64_C(0x6d0d8e411f5845a6), Q_UINT64_C(0xa15d0c9740e3a337), Q_UINT64_C(0x7e2d2c54bff916f2), Q_UINT64_C(0x2af10716e9691641), Q_UINT64_C(0x1dadd22c12ff5b22), Q_UINT64_C(0x6ba5819a9948d2c1), Q_UINT64_C(0x415fc03a15510c4d), Q_UINT64_C(0x40a4b22bdc58b560), Q_UINT64_C(0x6b94dc456fc3dca1), Q_UINT64_C(0xbc04ae725dca44cd), Q_UINT64_C(0x851229741d509353), Q_UINT64_C(0xdfa93ba511ed67a5), Q_UINT64_C(0x9930157fc5022cce) } , { Q_UINT64_C(0xa14f64e7e2a08adf), Q_UINT64_C(0x6b642680b3befe04), Q_UINT64_C(0xa5cec9da49db1e5b), Q_UINT64_C(0xc8a4791b8796b72b), Q_UINT64_C(0x96dcda1732dac346), Q_UINT64_C(0xdd6a468b90154135), Q_UINT64_C(0xc92cf06b2f7cec8b), Q_UINT64_C(0x49fdd61b76fb21c1), Q_UINT64_C(0x952d68a7d37cbdd1), Q_UINT64_C(0x1d02dca5ecce6696), Q_UINT64_C(0x7947464767cc4eb1), Q_UINT64_C(0xbc5690e29707fd78), Q_UINT64_C(0x1b77de938eb37a92), Q_UINT64_C(0x82a0316874d3f3b4), Q_UINT64_C(0x438b0002bc65e99), Q_UINT64_C(0xf7165ab04168fe6d), Q_UINT64_C(0x333d75259eefcd14), Q_UINT64_C(0x8906c3ac02d0bea4), Q_UINT64_C(0xffd91e4fe65f12e9), Q_UINT64_C(0xc14b1bf2982e4aed), Q_UINT64_C(0x35d83daf48cfe68f), Q_UINT64_C(0x9ec31949cd275677), Q_UINT64_C(0x2c3ee7e34b57d352), Q_UINT64_C(0x94660b0b00324807), Q_UINT64_C(0x3f7e45098859afce), Q_UINT64_C(0x69a26300773711d6), Q_UINT64_C(0xfcf669991e52df6b), Q_UINT64_C(0xe9fe0aec1acf55b5), Q_UINT64_C(0x6a22ade2d0520453), Q_UINT64_C(0x79b4957bf7ad0aaa), Q_UINT64_C(0x10bd4cdb980db736), Q_UINT64_C(0xf851ceac6b23657f), Q_UINT64_C(0xad9451efea678535), Q_UINT64_C(0x5646fc2f7a3ccca8), Q_UINT64_C(0x12501485c46afe0b), Q_UINT64_C(0xe44bf524b8fe2551), Q_UINT64_C(0xc7b072886b0fd978), Q_UINT64_C(0x2c29835d87188eeb), Q_UINT64_C(0xebd902fb34841eca), Q_UINT64_C(0xbc8da25aafd4c949), Q_UINT64_C(0xe8e2f478103c805c), Q_UINT64_C(0xf4bfa9cbd7ed9c07), Q_UINT64_C(0xac7f6a4adad8b297), Q_UINT64_C(0xbd209ad1b5f145ba), Q_UINT64_C(0x4f9d4c0a69871173), Q_UINT64_C(0xf6e28f3f8b89aebc), Q_UINT64_C(0x4b13bc67fe616132), Q_UINT64_C(0xcfe6c79ca07bb7bc), Q_UINT64_C(0x80a3f66f2c6a0eff), Q_UINT64_C(0xe3afb253772a75fc), Q_UINT64_C(0xf40c5da6637f1c4d), Q_UINT64_C(0x29002c86cc15c154), Q_UINT64_C(0x4dfe86a1b23ee0d9), Q_UINT64_C(0x65622cdf439dec74), Q_UINT64_C(0x30fda6a5933ffba0), Q_UINT64_C(0x960092fd4722f32b), Q_UINT64_C(0x4ab30ab6a72584cb), Q_UINT64_C(0xc74a9ae8575cdeeb), Q_UINT64_C(0x2e04317419a09c84), Q_UINT64_C(0x49c487bc3b339189), Q_UINT64_C(0xf1e89841c5586c04), Q_UINT64_C(0x618a5d4557a060db), Q_UINT64_C(0x67b1f2b29381993c), Q_UINT64_C(0xdac343bda84599fd) } , { Q_UINT64_C(0xebff8b8df3c83a0a), Q_UINT64_C(0xf9942b8463438981), Q_UINT64_C(0x6c2f8a36722bbac5), Q_UINT64_C(0xa7cae83f1120ef53), Q_UINT64_C(0x6be91f12cdd0ca04), Q_UINT64_C(0xc441e4b94cecfb40), Q_UINT64_C(0xcadae4afd1198c20), Q_UINT64_C(0x47d6c333e59f0d9b), Q_UINT64_C(0x1c7fe4e60648c3bd), Q_UINT64_C(0xf61d326de86eab61), Q_UINT64_C(0x71ea832569a032f7), Q_UINT64_C(0x27b805c6b65ae940), Q_UINT64_C(0x4ab0f7d8436b08dc), Q_UINT64_C(0xd7709084e3c83ba6), Q_UINT64_C(0xeda91d50da13848d), Q_UINT64_C(0x8540270732c408e0), Q_UINT64_C(0x35efdcdef2789841), Q_UINT64_C(0xf937151d7d7be252), Q_UINT64_C(0xe95c415b888c8aec), Q_UINT64_C(0x171a6366a0e1271b), Q_UINT64_C(0x9149c05e04f7036c), Q_UINT64_C(0x414f8230851b4649), Q_UINT64_C(0xfb51808713dc84ba), Q_UINT64_C(0xf933e08fb5dfaebc), Q_UINT64_C(0x28254a305cc7753f), Q_UINT64_C(0x6e9300d69c44cb1b), Q_UINT64_C(0x1fed087462b8e3c9), Q_UINT64_C(0x311931c6cc9d371f), Q_UINT64_C(0xab3c7d461118dc9), Q_UINT64_C(0x9f67ffd0d3815586), Q_UINT64_C(0x8586a78a5a5d0daa), Q_UINT64_C(0xc35e56c16ad732e8), Q_UINT64_C(0x5dec4f660f327eb4), Q_UINT64_C(0xbeca79c300886406), Q_UINT64_C(0xaad304bb2ea3f914), Q_UINT64_C(0x4f6aec0ed980ff6f), Q_UINT64_C(0x1ddf22d9fbb4a2f0), Q_UINT64_C(0xa5faf84525bab3e), Q_UINT64_C(0xb2f339ac1074ead), Q_UINT64_C(0xceeb55e80a6a92c2), Q_UINT64_C(0x8a439d961671da6f), Q_UINT64_C(0x66467b94b6de5d2f), Q_UINT64_C(0x21505ba132d4907d), Q_UINT64_C(0x34c443b890fac25f), Q_UINT64_C(0x48c89fd2e655cdf9), Q_UINT64_C(0x15897d714819c7e6), Q_UINT64_C(0xf7a8f3d223780746), Q_UINT64_C(0x6778549c3bbb486b), Q_UINT64_C(0x889aeb3bf2632b9a), Q_UINT64_C(0xcb8fb06abda385ff), Q_UINT64_C(0x502d1ab72f606c48), Q_UINT64_C(0x29b34ae2ff2c21a9), Q_UINT64_C(0x5f6942a552a43ba1), Q_UINT64_C(0xd9b44265023be3d7), Q_UINT64_C(0x29081045ed355455), Q_UINT64_C(0x2f915936359af5a0), Q_UINT64_C(0x6c3889068abe571c), Q_UINT64_C(0x97b66c46539aa106), Q_UINT64_C(0xec346e6de2e3f311), Q_UINT64_C(0x6aadba9193ad40f6), Q_UINT64_C(0xd835cf0ef3a71198), Q_UINT64_C(0x10e62386c249b3fc), Q_UINT64_C(0x1cd290d68761f8e2), Q_UINT64_C(0xb8337434d4e694e1) } , { Q_UINT64_C(0xbd77a59f1d361ebb), Q_UINT64_C(0x3fd63cdae63a60cf), Q_UINT64_C(0xabbde3878f5d3ddc), Q_UINT64_C(0x7bd30af727464ee0), Q_UINT64_C(0xc54b2e6fd776f8ec), Q_UINT64_C(0x87536cc23efddac8), Q_UINT64_C(0xa673f8fea0989c7a), Q_UINT64_C(0x7079efe6a0393e1), Q_UINT64_C(0xd59ef63e8c0a3f87), Q_UINT64_C(0x275f3761c2b39d86), Q_UINT64_C(0xabb109a58d81d722), Q_UINT64_C(0x6fa8223d3df3b5a3), Q_UINT64_C(0xc21d3f51d871af26), Q_UINT64_C(0x9d5c9fc29803819), Q_UINT64_C(0x866d72e99c8219c0), Q_UINT64_C(0xf903690329ec9854), Q_UINT64_C(0x463c5862fd725e53), Q_UINT64_C(0xfaa2e3b9009c23ff), Q_UINT64_C(0x51ed3fa38b3e32e1), Q_UINT64_C(0x3fdd054ae621b7a9), Q_UINT64_C(0x63422f3c0fcdb872), Q_UINT64_C(0xdb599cddb7ba5bb7), Q_UINT64_C(0x29d821145131732f), Q_UINT64_C(0xa768e7bd756f318c), Q_UINT64_C(0x6c499d80db10e3f2), Q_UINT64_C(0x1ccb5e0f3dfd948e), Q_UINT64_C(0xe59cdfdfde9ae15f), Q_UINT64_C(0x9d490cddfef6d223), Q_UINT64_C(0xb8985e20b3c308b5), Q_UINT64_C(0xca4145a21a50a82a), Q_UINT64_C(0xefa50915dbc7e668), Q_UINT64_C(0x66c706d2ddde9849), Q_UINT64_C(0x9ce9a5932d0364d2), Q_UINT64_C(0x9686b7e5e8901ff7), Q_UINT64_C(0xa9a42437501eaad7), Q_UINT64_C(0x20679ed4ada474e1), Q_UINT64_C(0x367a3bbc6c11bba2), Q_UINT64_C(0xe4cfc9c30e06a14d), Q_UINT64_C(0xc589b195c383ecfd), Q_UINT64_C(0x841ce907bbb6a61c), Q_UINT64_C(0x3d731ef371ea6132), Q_UINT64_C(0xab7a347deeedc48a), Q_UINT64_C(0xa5ba154bec151ef8), Q_UINT64_C(0x17726f865e2ee581), Q_UINT64_C(0xdbca0e729ac306f2), Q_UINT64_C(0xf7ee9f7dbf54f4d7), Q_UINT64_C(0x6c10670c9169452e), Q_UINT64_C(0x5a49ee9a2bc1486f), Q_UINT64_C(0x23630d9bff542959), Q_UINT64_C(0xdcb2d15124939ab9), Q_UINT64_C(0xa5de1bef76950515), Q_UINT64_C(0x730f408f5dc85968), Q_UINT64_C(0xd8c24e6721021521), Q_UINT64_C(0xe61242e7661ab160), Q_UINT64_C(0xceb3901956105e41), Q_UINT64_C(0x9a56e7a2a9b7040), Q_UINT64_C(0x6dddfaced358af91), Q_UINT64_C(0x6d597db8d1caf88d), Q_UINT64_C(0x7dfa62e1b1760d84), Q_UINT64_C(0x8e19fa60dfeb1bf), Q_UINT64_C(0xa34875d78b045e7e), Q_UINT64_C(0xa294952e7727e87), Q_UINT64_C(0xac7d17ef5e7b791a), Q_UINT64_C(0x51d95a618d846d91) } , { Q_UINT64_C(0xc58896c783248e00), Q_UINT64_C(0xb28c400d0e64ade8), Q_UINT64_C(0xc41ecb9b99a69765), Q_UINT64_C(0xa1bcd8aae00885c1), Q_UINT64_C(0xd66f8316f2155659), Q_UINT64_C(0x8eeb7bcc71816ad0), Q_UINT64_C(0xc0fd3c6163d7ca66), Q_UINT64_C(0x3483cad9e03c498e), Q_UINT64_C(0x797e845514e40aec), Q_UINT64_C(0x9213f80bf739746d), Q_UINT64_C(0x6effa9a6b1ea0966), Q_UINT64_C(0xecf7c1c9d0e33dba), Q_UINT64_C(0x244b3a0a6a1914d3), Q_UINT64_C(0x6ff19fb917323431), Q_UINT64_C(0x1fed9c34d7fa3bfe), Q_UINT64_C(0xc374c9f28e32936a), Q_UINT64_C(0x82e29126f964e26e), Q_UINT64_C(0x5e19b04bcae033ab), Q_UINT64_C(0x8e843603dbe6f7c4), Q_UINT64_C(0xa69036d38dc44fa7), Q_UINT64_C(0xdc8900d3ffe9bb33), Q_UINT64_C(0x7df691fb44c14455), Q_UINT64_C(0x8db41acc4e059813), Q_UINT64_C(0x9b2d3d0de5b20868), Q_UINT64_C(0x4b39506de2dc33e8), Q_UINT64_C(0x497fa4ddbb3b07ce), Q_UINT64_C(0x6c5debfda2c4ba40), Q_UINT64_C(0x8fdbde6d48bf1975), Q_UINT64_C(0xff2f49b04059933f), Q_UINT64_C(0xecbe4f65b27376f4), Q_UINT64_C(0x2721d3581a8b968c), Q_UINT64_C(0x1a24f47aac88d68b), Q_UINT64_C(0x789e285d63687859), Q_UINT64_C(0x90d51721750bfb72), Q_UINT64_C(0x6ec71da00ade928f), Q_UINT64_C(0xf30d9e21516cb984), Q_UINT64_C(0x26e15240e445a13b), Q_UINT64_C(0x1f2c3c30333f106d), Q_UINT64_C(0xc112f0277a1d8d9e), Q_UINT64_C(0xb8ded447d7ac9df4), Q_UINT64_C(0xec3468c53d70f8e2), Q_UINT64_C(0xc2762a9062b4fd52), Q_UINT64_C(0x125a697ea5c928fc), Q_UINT64_C(0x699ccbae2e951159), Q_UINT64_C(0xb84b2eebee507f54), Q_UINT64_C(0x3f758e5dc86257e0), Q_UINT64_C(0x98cce7a224a0ec87), Q_UINT64_C(0x9c664fde6084eb02), Q_UINT64_C(0xd0fc175ca6c00b3f), Q_UINT64_C(0xab97afa35e0176ee), Q_UINT64_C(0xc33d3e3c9d339042), Q_UINT64_C(0xdb4d05320bec3d50), Q_UINT64_C(0x39be4f2ea598bb3), Q_UINT64_C(0x82f71649af9e5b54), Q_UINT64_C(0xa314e81e7bdd8915), Q_UINT64_C(0xef47b0e2d07c4d8e), Q_UINT64_C(0xc95b40effdb0f22f), Q_UINT64_C(0xc388499302f30a22), Q_UINT64_C(0xff906154a95d03a7), Q_UINT64_C(0x9d33ff38637e7a05), Q_UINT64_C(0x2552ea8ad2b403cd), Q_UINT64_C(0x5e613aa2d28e5a87), Q_UINT64_C(0x4ec1298ccbd07a), Q_UINT64_C(0x8315aeb53c3d81ce) } }; const quint64 RAND_WHITE_CASTLING_KS = Q_UINT64_C(0x60c5f1b38762756d); const quint64 RAND_WHITE_CASTLING_QS = Q_UINT64_C(0x38918d25eac93e11); const quint64 RAND_BLACK_CASTLING_KS = Q_UINT64_C(0xfed940d4bb964ecb); const quint64 RAND_BLACK_CASTLING_QS = Q_UINT64_C(0x4a2da478101f9d64); const quint64 RAND_EN_PASSANT[MAX_EN_PASSANT_SQUARES] = { Q_UINT64_C(0xbc5e6419e34ab321), Q_UINT64_C(0x3513a06b02fc5132), Q_UINT64_C(0xb83ea9358f46207b), Q_UINT64_C(0xe575a233ac88fbf0), Q_UINT64_C(0x64c8173b165c69ac), Q_UINT64_C(0xe361ef6d97725e14), Q_UINT64_C(0x1ad0d77aa083746f), Q_UINT64_C(0x29a2f875cbc5f61a), Q_UINT64_C(0xd929e0170d1eda7), Q_UINT64_C(0xd13dda118259fd9f), Q_UINT64_C(0xe8cb491492468f4b), Q_UINT64_C(0x9c49ffc0f1b05f16), Q_UINT64_C(0xb76ca00d646c4009), Q_UINT64_C(0x99d8482b93ac2334), Q_UINT64_C(0x9d8a11eda9fe0d09), Q_UINT64_C(0x21f507b5b6d8771) }; const quint64 RAND_TO_MOVE = Q_UINT64_C(0xb1aac26e1c3caa9d); const quint64 RAND_VALUES2[MAX_PIECES][MAX_SQUARES] = { { Q_UINT64_C(0x2a5417a98307b2da), Q_UINT64_C(0x5ac95aaf5b5a0a8c), Q_UINT64_C(0x4242b999ccb11fd), Q_UINT64_C(0xa37501fe898e0e78), Q_UINT64_C(0x9a94bcea9e2da76b), Q_UINT64_C(0xc7ce19cc5e802f83), Q_UINT64_C(0x45eeced5b680b2cb), Q_UINT64_C(0xadb6adad23017434), Q_UINT64_C(0x80800ecc4d2b87a9), Q_UINT64_C(0x642f6c3b25f7815), Q_UINT64_C(0x36bee3949859adc4), Q_UINT64_C(0xbf7edddd305cd3e4), Q_UINT64_C(0xdc832abd4ffa5cb6), Q_UINT64_C(0x93633b3bfd69c313), Q_UINT64_C(0xace24bbc5c3b597), Q_UINT64_C(0x15b724f37500f32b), Q_UINT64_C(0xf8757ae36e0f7ad7), Q_UINT64_C(0x61ad06851f14a2d2), Q_UINT64_C(0x71305111983c5848), Q_UINT64_C(0x2312fe7b04ecc10e), Q_UINT64_C(0xa83a7e4426b47c5c), Q_UINT64_C(0x57273697f8db1fe1), Q_UINT64_C(0x1ba0df2ee5b42a5f), Q_UINT64_C(0xad7c2a49bc87d869), Q_UINT64_C(0xa0c2390e8cb1f3b), Q_UINT64_C(0xc88205c839aa498d), Q_UINT64_C(0xb0d939c06b5cb858), Q_UINT64_C(0xe07cec7f3264f226), Q_UINT64_C(0x6e33f7d923c0732b), Q_UINT64_C(0xe8203d23af991c54), Q_UINT64_C(0x1c99f6b4cf6f670c), Q_UINT64_C(0x44e4ec3c02e0a04b), Q_UINT64_C(0xc6ae9553cc99e7c0), Q_UINT64_C(0x449b73fe112a976a), Q_UINT64_C(0x5c3102046f66a5da), Q_UINT64_C(0xce6ab6643d315942), Q_UINT64_C(0x2522da9df2455649), Q_UINT64_C(0xa353599c1a2e0548), Q_UINT64_C(0x47a81c545e59e8a9), Q_UINT64_C(0xd20c18c91d0c7da0), Q_UINT64_C(0xa7947c53ce8dd184), Q_UINT64_C(0x524a385ac5da3912), Q_UINT64_C(0x877c13873f329da6), Q_UINT64_C(0x16f6860b1bfacd8f), Q_UINT64_C(0xe4c71662637278c3), Q_UINT64_C(0xaf4505840b228ab5), Q_UINT64_C(0x7cf5f4dd43e540e4), Q_UINT64_C(0x19d1b3bfcbd55a13), Q_UINT64_C(0x5f0e500c0e9d63db), Q_UINT64_C(0xdc76fab4b7b3ba9d), Q_UINT64_C(0x759ffa59e9523a66), Q_UINT64_C(0x9d7cc9cf7b2e1f05), Q_UINT64_C(0xf5614ae6f8970008), Q_UINT64_C(0x7987f955c2371b60), Q_UINT64_C(0x6ca454ef2c36b0b8), Q_UINT64_C(0xbf2d843f0342bc09), Q_UINT64_C(0x35ea28b097912aeb), Q_UINT64_C(0x41e7fb83df8e4c64), Q_UINT64_C(0x77db59b0f6e384ca), Q_UINT64_C(0xd6e3c5690790b6b8), Q_UINT64_C(0x776de83e838ab515), Q_UINT64_C(0x6118c9ee6248fe51), Q_UINT64_C(0x43111ed3b71e7d0f), Q_UINT64_C(0xf10630451923e6ab) } , { Q_UINT64_C(0x565ab14f492f71b4), Q_UINT64_C(0x3a76f59247731e03), Q_UINT64_C(0xa358e41c85134db), Q_UINT64_C(0x2aa4cf9149d3eeee), Q_UINT64_C(0x4b1a708bcd67571c), Q_UINT64_C(0x960b91658e4256a5), Q_UINT64_C(0xe92d20cc7b215cd1), Q_UINT64_C(0x6a17c2b1ff6d49a4), Q_UINT64_C(0xc280f23c9628ed6b), Q_UINT64_C(0xf5f3babb8223baf5), Q_UINT64_C(0xc00174f43aad425c), Q_UINT64_C(0x212624c4251f7393), Q_UINT64_C(0x209de09fd3e84346), Q_UINT64_C(0xa1adb8f309027c7), Q_UINT64_C(0xf5bdfed74bbbe2b5), Q_UINT64_C(0xb4a5c1446224e203), Q_UINT64_C(0x189b35d7180fefb5), Q_UINT64_C(0x8b2c72f8150e4587), Q_UINT64_C(0x1196c5cb9e797a9b), Q_UINT64_C(0x27b584dae8b2e940), Q_UINT64_C(0x79364f768b360ae0), Q_UINT64_C(0x171cc6787742c0ad), Q_UINT64_C(0xab538219f3d49a73), Q_UINT64_C(0xcc82e6842ac5486b), Q_UINT64_C(0x8eb33ec2c84c5894), Q_UINT64_C(0xc90f46cacfc0229b), Q_UINT64_C(0x80ed6a306da6b300), Q_UINT64_C(0x566ea1f3681bc906), Q_UINT64_C(0xa1dd6add546b62fd), Q_UINT64_C(0x4b4e3e160e17a039), Q_UINT64_C(0xf5fec0afe974790e), Q_UINT64_C(0x6206b04ec9a5be39), Q_UINT64_C(0xd1686b1c476e8ee1), Q_UINT64_C(0x3e05d0a857bb0b79), Q_UINT64_C(0xf861f0b941963817), Q_UINT64_C(0xa3bd04a8ae26f2ea), Q_UINT64_C(0xb9ef8e89213e0019), Q_UINT64_C(0x80496d52af615a37), Q_UINT64_C(0xb1bc75fdc72f0dd4), Q_UINT64_C(0x6aaf5289dbe9e7a), Q_UINT64_C(0x2034b6428849acf8), Q_UINT64_C(0x214b79e32484ffd1), Q_UINT64_C(0xed8b807ba1d0ba7f), Q_UINT64_C(0xb146c7ef65dc112b), Q_UINT64_C(0x29273be71456bbf), Q_UINT64_C(0xb0c321a881b2978b), Q_UINT64_C(0x97e80e566ba19dcf), Q_UINT64_C(0xdb8130cd436270bf), Q_UINT64_C(0x8390455b1d03ebd4), Q_UINT64_C(0x67d87a40f489f971), Q_UINT64_C(0x11371562ed0cd5ad), Q_UINT64_C(0xc78fc67ea384d066), Q_UINT64_C(0xa2c0b78e4160c607), Q_UINT64_C(0xec157db9f45f65b8), Q_UINT64_C(0x11a23a808020842d), Q_UINT64_C(0xf4870065c7cb9058), Q_UINT64_C(0xb688f87f37be9f10), Q_UINT64_C(0x523904f08e3a1db5), Q_UINT64_C(0x6d5547d362630207), Q_UINT64_C(0xbe377a2ee9614959), Q_UINT64_C(0xa74767500f61e91a), Q_UINT64_C(0x59f4428131dfe82b), Q_UINT64_C(0xbee2763074345495), Q_UINT64_C(0x924a98bc2c03faa3) } , { Q_UINT64_C(0xa3f278a8ea3800d6), Q_UINT64_C(0x8f95861dc9e88f9c), Q_UINT64_C(0xb016c7a699f29eec), Q_UINT64_C(0x4f871a0da97bd86d), Q_UINT64_C(0x6d70153d9c3926e9), Q_UINT64_C(0xf626a9275c8edca7), Q_UINT64_C(0xa37b001c2aa636af), Q_UINT64_C(0x50552a8f13bf4b67), Q_UINT64_C(0x7f506ef8d7583d2d), Q_UINT64_C(0x2e1f50f49c4fcb4c), Q_UINT64_C(0xfc174306518aadaf), Q_UINT64_C(0xa96e138bbaf3b99c), Q_UINT64_C(0x26d2537610a1428a), Q_UINT64_C(0x5d34b24783e87351), Q_UINT64_C(0xbdae7bbc576baf7d), Q_UINT64_C(0xa7386b52075119e), Q_UINT64_C(0x902f3d3f11b71bea), Q_UINT64_C(0xd6551d6cbd316ebb), Q_UINT64_C(0xe22c47438ea26697), Q_UINT64_C(0x812ad25de614fc1e), Q_UINT64_C(0xd6a0f0961820f99f), Q_UINT64_C(0x9213716d4bef80ca), Q_UINT64_C(0x978883dde343df7d), Q_UINT64_C(0x5c88103619aa30c6), Q_UINT64_C(0xfa9cbcc1c7aa786f), Q_UINT64_C(0xa4c270ecbe8278b3), Q_UINT64_C(0x31ac3dd2c0abd738), Q_UINT64_C(0x37774370702023be), Q_UINT64_C(0x7df4cf76ade1ef4d), Q_UINT64_C(0x25396a494516dec2), Q_UINT64_C(0x69fe023ce81dda44), Q_UINT64_C(0x9bfa45df4de43313), Q_UINT64_C(0x7eb578e49c1b5591), Q_UINT64_C(0x33d3f3069234c23a), Q_UINT64_C(0x730fe0250e55b1d9), Q_UINT64_C(0x683e70b476db9c72), Q_UINT64_C(0xe628af7287eb7b22), Q_UINT64_C(0x5cc9a853f739944), Q_UINT64_C(0x33b1091a8d9831c), Q_UINT64_C(0xbcb444793c9aa442), Q_UINT64_C(0x610301f6a75e25d6), Q_UINT64_C(0xcee84a19312ab772), Q_UINT64_C(0xca84e80ce1fb32a0), Q_UINT64_C(0x246a9b91d8c018cc), Q_UINT64_C(0x262c8dbef351b7a), Q_UINT64_C(0xfb1ff9f4c31a9f26), Q_UINT64_C(0xf0792a527dd73b63), Q_UINT64_C(0xf44f0208aff4ebdb), Q_UINT64_C(0x209bacbad03a0e47), Q_UINT64_C(0x976cae0727bcdd47), Q_UINT64_C(0xc6268f2a65b666ba), Q_UINT64_C(0x9ac2e7adb3078fd1), Q_UINT64_C(0x391b492cc69d3d90), Q_UINT64_C(0x731b43a7cb531413), Q_UINT64_C(0x25fd672d91f1910a), Q_UINT64_C(0x6b9f1577ed191584), Q_UINT64_C(0x9e98198a9b435198), Q_UINT64_C(0xf9211bec7f67b9b6), Q_UINT64_C(0x7184259d9eca2d52), Q_UINT64_C(0x89b34a0107893fe8), Q_UINT64_C(0xb31a7b5beb798123), Q_UINT64_C(0xae28248f42709eed), Q_UINT64_C(0x5dd7c34ab7d1d05e), Q_UINT64_C(0xc993fe8499e8729f) } , { Q_UINT64_C(0x8af2cf20821b1ed6), Q_UINT64_C(0xb3d45a42c1eba0b4), Q_UINT64_C(0xdab6b5908ca7b6a2), Q_UINT64_C(0x1877a332f18884e2), Q_UINT64_C(0x9efc385d3fc3f4fc), Q_UINT64_C(0xebf16323d388b3e), Q_UINT64_C(0x97b696a1e4ad73e), Q_UINT64_C(0x9ac23b1823568ae), Q_UINT64_C(0x370ed86a19d5269e), Q_UINT64_C(0x73339a44eb64246e), Q_UINT64_C(0xe3004dc320fe9fac), Q_UINT64_C(0x4c416001629dde1), Q_UINT64_C(0x929c2b1daef7a4c2), Q_UINT64_C(0xe084b4b411de4dec), Q_UINT64_C(0x7fd8093ccf4f057), Q_UINT64_C(0x87f63c8ce96ad1c5), Q_UINT64_C(0x7354e0263d16bdcb), Q_UINT64_C(0xe6383a502b96c3a6), Q_UINT64_C(0x7f2fffb963dca025), Q_UINT64_C(0x81fe69658e1c281e), Q_UINT64_C(0x54fad66539b919ac), Q_UINT64_C(0x881a8e64df80dd01), Q_UINT64_C(0x23aec86c61190a69), Q_UINT64_C(0x31e87ce13389adde), Q_UINT64_C(0xee8e6d85bb237cfc), Q_UINT64_C(0x709e7ad92346f2b0), Q_UINT64_C(0x4df70546f77dfdd6), Q_UINT64_C(0xbf3f90b542d637e1), Q_UINT64_C(0x333505b3d67af4c), Q_UINT64_C(0xe1e53fa45bc1f6cc), Q_UINT64_C(0xb50331b42af6890d), Q_UINT64_C(0xadbdac6c3be7eb14), Q_UINT64_C(0xb599a56d460c4819), Q_UINT64_C(0x90e68ce5334a496), Q_UINT64_C(0xde5a36b0ca29d6e), Q_UINT64_C(0xe1d83f7011b5495), Q_UINT64_C(0xb806b49cde676d1f), Q_UINT64_C(0x596415bff969e5ac), Q_UINT64_C(0x4ecb33f92391a99d), Q_UINT64_C(0x978b3cf87693394c), Q_UINT64_C(0x47b7f5d55b0c1b2f), Q_UINT64_C(0xadbda5d618bf4fc1), Q_UINT64_C(0xd50bc780121a16c6), Q_UINT64_C(0xc01c8629fc0b5906), Q_UINT64_C(0xc2e96408c1170dac), Q_UINT64_C(0xd00268c3c112dd6d), Q_UINT64_C(0xb44a2f9833b112b2), Q_UINT64_C(0x4ad98b014e331b82), Q_UINT64_C(0x960f27e9ca01dffb), Q_UINT64_C(0x2c87d28ce4ab8ce), Q_UINT64_C(0x1913e6fa55592377), Q_UINT64_C(0xb3fc07fd633094c5), Q_UINT64_C(0x28d8f3bc1149659), Q_UINT64_C(0x17e47e9fcaa101ab), Q_UINT64_C(0xec7c64d3f35a93a0), Q_UINT64_C(0xa5579af4ef028d6f), Q_UINT64_C(0xe866dfd47419c9e9), Q_UINT64_C(0x12a90901fd4c1c61), Q_UINT64_C(0x4613bfbb58c63015), Q_UINT64_C(0x42e4466423c4f286), Q_UINT64_C(0x92f6746ca2e50366), Q_UINT64_C(0x93002fb08d04a982), Q_UINT64_C(0xa7bc2dc031876fe3), Q_UINT64_C(0x621169ba9c39dc2b) } , { Q_UINT64_C(0x85a5c445a8c4baf5), Q_UINT64_C(0xee64b9c6584a9de8), Q_UINT64_C(0xdaa1ed0eba35645a), Q_UINT64_C(0x8f5910048cbca322), Q_UINT64_C(0xe570d3024996c3f), Q_UINT64_C(0xba4ad47b280f9de7), Q_UINT64_C(0x336b7645ac7d0244), Q_UINT64_C(0x74c46e492a70974c), Q_UINT64_C(0x3352c2984e263343), Q_UINT64_C(0xb13d1482d3318812), Q_UINT64_C(0xd8f384157b12b62d), Q_UINT64_C(0xde5eb19a00393c01), Q_UINT64_C(0xd882afd8cf70261a), Q_UINT64_C(0xa3c47c92d627ce3c), Q_UINT64_C(0xb53c09a30bab17c4), Q_UINT64_C(0xaec14792f9613a68), Q_UINT64_C(0xb06f91968cfc4f70), Q_UINT64_C(0xe577859b7affd561), Q_UINT64_C(0x61cc445d91fed085), Q_UINT64_C(0x2c43b923c3b6193c), Q_UINT64_C(0x9c3d4b4945169e8f), Q_UINT64_C(0xbdb629528c1fa4e3), Q_UINT64_C(0x765764f75e136a25), Q_UINT64_C(0x9d6876cc28c40323), Q_UINT64_C(0x4f6710cb56ff4e1d), Q_UINT64_C(0x67c4537ad1694c9e), Q_UINT64_C(0x2a398547bae7973c), Q_UINT64_C(0xa9a31125194853b4), Q_UINT64_C(0x481484b747893358), Q_UINT64_C(0x7159a6b0047670ff), Q_UINT64_C(0x2a20f6513c4c6164), Q_UINT64_C(0x8e4f9f6826a7d069), Q_UINT64_C(0xa8986bbb3a03b4be), Q_UINT64_C(0x2897848201586d82), Q_UINT64_C(0x4a350cfdbf731566), Q_UINT64_C(0xda2a5d4fcf86b91), Q_UINT64_C(0xc906ebab5484492b), Q_UINT64_C(0x15873698e510c12d), Q_UINT64_C(0x4d782314d1071fdd), Q_UINT64_C(0x3b33e279a51cda42), Q_UINT64_C(0x7316ba05e94a2760), Q_UINT64_C(0x2947dbd72b62eeee), Q_UINT64_C(0x994ee8778f5bb403), Q_UINT64_C(0x65ba34e9f6e6a886), Q_UINT64_C(0xf7048c8aaafeb0fb), Q_UINT64_C(0xdb6facf385a67bf9), Q_UINT64_C(0x55387477c8566d6b), Q_UINT64_C(0x8c73d9a9b40a182d), Q_UINT64_C(0x621dd5fb126b5231), Q_UINT64_C(0xcb57d791aa28cab4), Q_UINT64_C(0xd9c89d3f4662edaf), Q_UINT64_C(0xe41ee971856c1ad6), Q_UINT64_C(0x1e9842a9f9682f21), Q_UINT64_C(0x657435bd92007385), Q_UINT64_C(0x76ee8c371bb5adfe), Q_UINT64_C(0x457d2ebeb1b7bc3a), Q_UINT64_C(0x5ced48c3073d82ae), Q_UINT64_C(0x5009cd7eac1805f1), Q_UINT64_C(0xd58efb58cb715c37), Q_UINT64_C(0xe1c8c503ec7e1592), Q_UINT64_C(0x932b5eebaea84148), Q_UINT64_C(0x477dd65b75fec5a4), Q_UINT64_C(0xc1f70dbb2324b11d), Q_UINT64_C(0x840bec343f01db29) } , { Q_UINT64_C(0xc9154a3054cb7ed7), Q_UINT64_C(0x4094ac226115302), Q_UINT64_C(0x40a17b1b3a996c03), Q_UINT64_C(0x6b075c0b979ef1e0), Q_UINT64_C(0x71944990ac67d03f), Q_UINT64_C(0x963bec4af2a26b43), Q_UINT64_C(0x26ff8b7968bc4c68), Q_UINT64_C(0x5b9e4399852cf357), Q_UINT64_C(0x44c8e4f80f6729ac), Q_UINT64_C(0x93fe2302cd9550e1), Q_UINT64_C(0xd1f2e2ff8960943), Q_UINT64_C(0x25eb08709be821f6), Q_UINT64_C(0x9ab982fcd9f28104), Q_UINT64_C(0xcdd1ec49e9360804), Q_UINT64_C(0x79ad756ecb367f06), Q_UINT64_C(0x89eb5e0836cf62b0), Q_UINT64_C(0x4ac95d9764704e3), Q_UINT64_C(0xf7882147c928a4c4), Q_UINT64_C(0xc7ce5faa50675679), Q_UINT64_C(0x7e4c3e3103de876d), Q_UINT64_C(0x35ae2a6974cacdad), Q_UINT64_C(0xaf67df6b23302a45), Q_UINT64_C(0x8d8dd335451b7a47), Q_UINT64_C(0x44beddf622d3b188), Q_UINT64_C(0xf5b6409a9f699b45), Q_UINT64_C(0x9f5188f178ebc7ed), Q_UINT64_C(0x8ceb2ff434d23c0e), Q_UINT64_C(0x83f25956f402e601), Q_UINT64_C(0x6f4d13a4f0cf30b6), Q_UINT64_C(0xb1c0502c328b514e), Q_UINT64_C(0x7a8a8ebd4ab58aa6), Q_UINT64_C(0xec0573d9d6a20975), Q_UINT64_C(0x11e38f6467dbfe67), Q_UINT64_C(0xfc4e5be49eead763), Q_UINT64_C(0x858cd5c130a8fc51), Q_UINT64_C(0x4465d21d7b916424), Q_UINT64_C(0xd92bf4909d34330f), Q_UINT64_C(0x74cb5f744b0122d0), Q_UINT64_C(0x6a3b845be9db821c), Q_UINT64_C(0x5afff0e881a8f107), Q_UINT64_C(0x4b4249fb7ba7423d), Q_UINT64_C(0x3ad9f8d8e8eed5), Q_UINT64_C(0xeb1c98f6e09750de), Q_UINT64_C(0x9daf6ca66119a894), Q_UINT64_C(0x848380da2cdc0a2), Q_UINT64_C(0x2e1af306216802d4), Q_UINT64_C(0x19abddf45e5b7ea4), Q_UINT64_C(0xb6c53281ef196767), Q_UINT64_C(0xc54c385bed2ce3b2), Q_UINT64_C(0xa817979decc2b27c), Q_UINT64_C(0x5a2a2096cae78195), Q_UINT64_C(0xa7ebee9dbf8345f6), Q_UINT64_C(0x65d51a6270c4c3dc), Q_UINT64_C(0x7da039225b9ac0e8), Q_UINT64_C(0x178f6351e8aae464), Q_UINT64_C(0xfdb1a3f8f880811b), Q_UINT64_C(0xbba52f982ead6dee), Q_UINT64_C(0x522d6eabb42098c3), Q_UINT64_C(0xd2d67588acc60fd2), Q_UINT64_C(0xab6184a29a26d467), Q_UINT64_C(0xfb2ce53d12eec200), Q_UINT64_C(0x1edcde41da3b9182), Q_UINT64_C(0x4529c0b5807e70a5), Q_UINT64_C(0x6177b11b182a5b83) } , { Q_UINT64_C(0xf4f8f7cc3a55fa7f), Q_UINT64_C(0xbcc30e2a1ae5a6c4), Q_UINT64_C(0x3a8b696603dfdd12), Q_UINT64_C(0xc51390eed137f8dc), Q_UINT64_C(0xdf897bf74b7fefb6), Q_UINT64_C(0x616e5b1d937170b3), Q_UINT64_C(0xe10f9783e6a1f315), Q_UINT64_C(0x81c9dceb7b9f923), Q_UINT64_C(0xed8ad207fa403596), Q_UINT64_C(0x9bce7c7d0ab97518), Q_UINT64_C(0xfc06351ced68604), Q_UINT64_C(0xc9e6273f2ec6e763), Q_UINT64_C(0xead5ef41ca0957b4), Q_UINT64_C(0xdf6f1fe61c62a293), Q_UINT64_C(0xf3995f29904bc412), Q_UINT64_C(0xf83305440895793b), Q_UINT64_C(0x32b29c3f5467e863), Q_UINT64_C(0x3ed4bf86f70fc4fa), Q_UINT64_C(0x886f78f6d8ccf859), Q_UINT64_C(0x14b4408582991ee0), Q_UINT64_C(0x2ff64d5a20bafe98), Q_UINT64_C(0x2c6a9f5a5b152675), Q_UINT64_C(0x749d77156c4a125f), Q_UINT64_C(0xa18c8f52fef0a2d7), Q_UINT64_C(0xf4a189bca3c87ac0), Q_UINT64_C(0xb95bffaf868dbdff), Q_UINT64_C(0xc88c3b3e52bf009c), Q_UINT64_C(0x5733f812439ad9c), Q_UINT64_C(0x169b0070baec77aa), Q_UINT64_C(0x49744d1aa6badab1), Q_UINT64_C(0xbf05ed4f17ea10d3), Q_UINT64_C(0x4b85feb634951e17), Q_UINT64_C(0xe4e039fc6cde7a5b), Q_UINT64_C(0x2a3e9b8d701289ab), Q_UINT64_C(0x3e18795e13a27dad), Q_UINT64_C(0xd75fc174992fc789), Q_UINT64_C(0x73d2fb3f725c060f), Q_UINT64_C(0x57f60d1c5c2403b8), Q_UINT64_C(0xdec6b7f4069dc977), Q_UINT64_C(0x7f31ea307d83b668), Q_UINT64_C(0xec7a56b5d3763edf), Q_UINT64_C(0x30199b8d81721c1c), Q_UINT64_C(0xef54d9d354deb3c5), Q_UINT64_C(0xe86119665f61c11d), Q_UINT64_C(0x572a32643122fb1c), Q_UINT64_C(0x6ba9658c371e003b), Q_UINT64_C(0xad015a0f08f4a9cb), Q_UINT64_C(0xd26728ca51cbccb6), Q_UINT64_C(0xa3865b917a21bee1), Q_UINT64_C(0x6d35946ba6b03017), Q_UINT64_C(0x4fc223cf3e1cd5a2), Q_UINT64_C(0xb3f2237cd7833832), Q_UINT64_C(0x86ab980f57a8df5), Q_UINT64_C(0x9a58e0c0091f362e), Q_UINT64_C(0x757cd2e0e53ba4b9), Q_UINT64_C(0xaf111d5fabce6a6f), Q_UINT64_C(0x1465f4f274997b15), Q_UINT64_C(0x3462e23246eb0d12), Q_UINT64_C(0x726452adff1006fd), Q_UINT64_C(0xac499e66fd93b059), Q_UINT64_C(0x4ecbaf6b99a2e56a), Q_UINT64_C(0x1041c97f21469fbf), Q_UINT64_C(0x6dda538750a36a56), Q_UINT64_C(0x94dca9a98cc1d99f) } , { Q_UINT64_C(0x77a211638cd87dcd), Q_UINT64_C(0xa6a31bd50991eaf4), Q_UINT64_C(0x11bfa3ec8c026b3), Q_UINT64_C(0x2cb470f801cbddfe), Q_UINT64_C(0x98dbad4e585644f2), Q_UINT64_C(0x46290af12fdc6634), Q_UINT64_C(0x9b247c6a5a0a2d77), Q_UINT64_C(0xd6bebbf2b9869edf), Q_UINT64_C(0xa4aae898140b992c), Q_UINT64_C(0x9d8a5a9cb6029dec), Q_UINT64_C(0x2d2ad61b40e30884), Q_UINT64_C(0xa90247f82bd087fa), Q_UINT64_C(0x96bf2d094e665fca), Q_UINT64_C(0xe2a49eae6dc4add), Q_UINT64_C(0x36bcf9022326df31), Q_UINT64_C(0x3d2c88e91a86b1b9), Q_UINT64_C(0x3e8841055bc756c2), Q_UINT64_C(0x4812d804754aa522), Q_UINT64_C(0xc09a37b9b5a60a6c), Q_UINT64_C(0x86b3acf3725828ce), Q_UINT64_C(0xab73f4897f4edcc1), Q_UINT64_C(0xcd0599eb02c15a3b), Q_UINT64_C(0x122c3fb7f17f1693), Q_UINT64_C(0x3efa1a3de765fe3), Q_UINT64_C(0x3c744c64f6cd0fd0), Q_UINT64_C(0xffb8a18a638c32df), Q_UINT64_C(0xce2d709075b56496), Q_UINT64_C(0xec13bd7bb907c28d), Q_UINT64_C(0x1e9cbb46ed2b79f8), Q_UINT64_C(0x6150e6c619d03a47), Q_UINT64_C(0xf8b24b23e5bba1e9), Q_UINT64_C(0x5b23491415c5731), Q_UINT64_C(0xac6fdf0b875d6f4d), Q_UINT64_C(0x9a53e5fefae9bf64), Q_UINT64_C(0x4550a6a211125ad8), Q_UINT64_C(0xc85dc7123cd9c63f), Q_UINT64_C(0xc859f0a16091cef6), Q_UINT64_C(0xf1f596bb7fcbeb58), Q_UINT64_C(0x9a97173efcf08eaf), Q_UINT64_C(0x1b02983108490082), Q_UINT64_C(0x97d4a8c6501481ed), Q_UINT64_C(0x39e16a2ee1cf0a8e), Q_UINT64_C(0x60928f452edff88a), Q_UINT64_C(0x8c5d5ddcaf147682), Q_UINT64_C(0x514eab759624319c), Q_UINT64_C(0x282d95ee564bbc7d), Q_UINT64_C(0x30c4098a2c0ea9b7), Q_UINT64_C(0x8d4be2f3c4e2c7ed), Q_UINT64_C(0xca08aa88874dc7c5), Q_UINT64_C(0xef5770f56f23ab3f), Q_UINT64_C(0xb86cc826b8a4f483), Q_UINT64_C(0xcef35fd1ba58fbf1), Q_UINT64_C(0x1c4c4d5225c6a03c), Q_UINT64_C(0x540ae3e26cd6f2e3), Q_UINT64_C(0x73c6f2e85dc5791), Q_UINT64_C(0x5a7c921272b60cd6), Q_UINT64_C(0x51e77f35b26b0f65), Q_UINT64_C(0x7873076f894c1741), Q_UINT64_C(0x58bb95f718869463), Q_UINT64_C(0x98d2c3df1b1057e9), Q_UINT64_C(0xcd1b5c04053b94f1), Q_UINT64_C(0x520ef737974a25a), Q_UINT64_C(0xb04004966560cda8), Q_UINT64_C(0xd9c460639fff593a) } , { Q_UINT64_C(0x8f84cf5e9c63a4e4), Q_UINT64_C(0x9f9cdb21e4265481), Q_UINT64_C(0xae76dce90166fcb1), Q_UINT64_C(0x2c00978be7e946e1), Q_UINT64_C(0x3edb6548e399ea23), Q_UINT64_C(0x9a2eab067b1d6389), Q_UINT64_C(0x3368d04265078033), Q_UINT64_C(0x16c8657810cb31be), Q_UINT64_C(0x8152a38826988196), Q_UINT64_C(0xff09a25603bc3685), Q_UINT64_C(0x9da9a95a084ada86), Q_UINT64_C(0x686d71730d08a5f5), Q_UINT64_C(0x9b7122f7a659c196), Q_UINT64_C(0x79cafe1cfd745ce9), Q_UINT64_C(0x450fcd2b936b21ba), Q_UINT64_C(0x65e176d0f1faaba0), Q_UINT64_C(0x9defe22c226a2937), Q_UINT64_C(0x312d522443582b81), Q_UINT64_C(0x27fd7d290abc8791), Q_UINT64_C(0x9cb424b4689b1085), Q_UINT64_C(0xb1ee7d9bc7ed638), Q_UINT64_C(0x8c4a47129f11b13e), Q_UINT64_C(0x81f99bd9881ec40d), Q_UINT64_C(0x18ca6862cc295b36), Q_UINT64_C(0xd3a012a193a0670e), Q_UINT64_C(0x38f322136e477422), Q_UINT64_C(0xd57c9805da53f9b), Q_UINT64_C(0x7c719d808b472f38), Q_UINT64_C(0xd2ebb0c1c120fd43), Q_UINT64_C(0xbafd25ccacada6b9), Q_UINT64_C(0x7a3b210b35402d94), Q_UINT64_C(0x798eecdce02da12), Q_UINT64_C(0xf7dc1295b2fdacf2), Q_UINT64_C(0x72676a76edc34f5e), Q_UINT64_C(0x2e7ab868cb80bd96), Q_UINT64_C(0xe6472bce9a471812), Q_UINT64_C(0x6dabeca8ff13c4ab), Q_UINT64_C(0x49a6a9802cf4c7e6), Q_UINT64_C(0x488851cea3bc5b56), Q_UINT64_C(0xa0036e7d09b73710), Q_UINT64_C(0x2bebc5c27d8b5075), Q_UINT64_C(0x787f3e77a964398a), Q_UINT64_C(0x1ce33aa448409dbe), Q_UINT64_C(0x905631255b7dd08f), Q_UINT64_C(0x197ec96e161d61b7), Q_UINT64_C(0xf3ee87a872c7b156), Q_UINT64_C(0x6496ab32fb360802), Q_UINT64_C(0xf7bd02665d4b2833), Q_UINT64_C(0xbf1dd354e1c16673), Q_UINT64_C(0xab7a42f389c21b59), Q_UINT64_C(0xfeeaf54f69f2c5dd), Q_UINT64_C(0xb2805d02045d2527), Q_UINT64_C(0x428f1491b65296fc), Q_UINT64_C(0xc458fec8573b6b2f), Q_UINT64_C(0x191695de290ddef8), Q_UINT64_C(0x59384d05101a51f9), Q_UINT64_C(0xb5e5973e3e6c271b), Q_UINT64_C(0xd374d2d6d48885fb), Q_UINT64_C(0x750ed047a2910e3b), Q_UINT64_C(0x23c4d2f89df98083), Q_UINT64_C(0x82ccb3a7fbd0d688), Q_UINT64_C(0x8e3055837bd395ab), Q_UINT64_C(0xe9862968513801e4), Q_UINT64_C(0xf30e1f7924b5059f) } , { Q_UINT64_C(0xaef9214a3dafaebb), Q_UINT64_C(0x595359d437555f11), Q_UINT64_C(0x864b460c3542867d), Q_UINT64_C(0xcfef6cc115b6c581), Q_UINT64_C(0x5dad64e511cef43a), Q_UINT64_C(0x87a312b6c386ccdf), Q_UINT64_C(0x316c5cf705464792), Q_UINT64_C(0xc86136ea872d8560), Q_UINT64_C(0x8a3df4dc1a5f51e8), Q_UINT64_C(0x9bae5a4593329914), Q_UINT64_C(0xaa371c7ee343e4ef), Q_UINT64_C(0xc4c973438fac7798), Q_UINT64_C(0x8e1c4f7ca8b63684), Q_UINT64_C(0x201cbdb1165441ca), Q_UINT64_C(0x96b26b38b840a691), Q_UINT64_C(0x68979d345cbe4394), Q_UINT64_C(0xf4ea3459a936a89), Q_UINT64_C(0xfb1adf39decbe51c), Q_UINT64_C(0x6675f542d506b2b7), Q_UINT64_C(0xffd179dc8b371e03), Q_UINT64_C(0xb26babad603cda4c), Q_UINT64_C(0xd85321c6d903fb5c), Q_UINT64_C(0x98f47c174e79a448), Q_UINT64_C(0x5eea28cf3254b050), Q_UINT64_C(0x24aa86493ee408ed), Q_UINT64_C(0x6e7f7f59139f0ef1), Q_UINT64_C(0x45a7fff92512be7c), Q_UINT64_C(0x4020cd989e2ad493), Q_UINT64_C(0x38e3864a180f2c82), Q_UINT64_C(0x3cd439786f924cf1), Q_UINT64_C(0x43be37dd084d404c), Q_UINT64_C(0xf661aac05df616fd), Q_UINT64_C(0x18a8112595332b81), Q_UINT64_C(0xfa38986fcce991c4), Q_UINT64_C(0x3fd06f80d4faabed), Q_UINT64_C(0xf5d2da68b6e592f6), Q_UINT64_C(0x559cfcb55d4d4495), Q_UINT64_C(0xe8e8e2b3c886ef82), Q_UINT64_C(0x8056a673a349f583), Q_UINT64_C(0x30233c3671d552fe), Q_UINT64_C(0xa6f0f430cb09b065), Q_UINT64_C(0xd359b10c11bc1b48), Q_UINT64_C(0xe05e58bd2e1cd9dd), Q_UINT64_C(0xf392cce8c43c2c9b), Q_UINT64_C(0x137f2f231cf7dd04), Q_UINT64_C(0x1b4d78fcc9f30645), Q_UINT64_C(0xae3f8cfecaec81cb), Q_UINT64_C(0x1e09828827d73bb), Q_UINT64_C(0x124ef86cea170d67), Q_UINT64_C(0xf3187a792ae2a11b), Q_UINT64_C(0x2592985dee9a14bc), Q_UINT64_C(0x10232632e736552f), Q_UINT64_C(0x8b83551daa92ef94), Q_UINT64_C(0xf75a50e2e509d038), Q_UINT64_C(0x3e19775a722b635), Q_UINT64_C(0x6687bda454e55cc2), Q_UINT64_C(0x88f6ba2fc53221b0), Q_UINT64_C(0x86a8fb4ef53fc628), Q_UINT64_C(0xc26d0e5f1dea6150), Q_UINT64_C(0xa0d2a833e75ff7a), Q_UINT64_C(0x5dedefd219e31d97), Q_UINT64_C(0x1639521ac79f991c), Q_UINT64_C(0xb693309c5a6696a1), Q_UINT64_C(0xb34ef308c176dacd) } , { Q_UINT64_C(0x8c0e48d578d0c62e), Q_UINT64_C(0xefb595c2274f8e7), Q_UINT64_C(0xb99a38710cca949f), Q_UINT64_C(0xcd2bcb6a1ce8939), Q_UINT64_C(0xc36c1bcef3b7132e), Q_UINT64_C(0xd98f8098e57c3ade), Q_UINT64_C(0x8d60d26082cc5e66), Q_UINT64_C(0x6ed67083a0986432), Q_UINT64_C(0xf0c691588aea09a4), Q_UINT64_C(0xf278dfa798343aa5), Q_UINT64_C(0x4251301408454553), Q_UINT64_C(0xc13f48761eae2cdf), Q_UINT64_C(0x1db502b921181744), Q_UINT64_C(0x51ae72db5efb5369), Q_UINT64_C(0x603ba05f5f23e864), Q_UINT64_C(0x18fa1e0c10916b38), Q_UINT64_C(0xb72dc2d7ed91b4bc), Q_UINT64_C(0x749741fd44ab2ec), Q_UINT64_C(0x598332aeab692676), Q_UINT64_C(0x2ba658fd0178969b), Q_UINT64_C(0x7604714f9a9fa83d), Q_UINT64_C(0x406b825f315fb561), Q_UINT64_C(0x48e0c576ec9ac891), Q_UINT64_C(0x96dc2caa168b8d80), Q_UINT64_C(0xfc02936de85bc77e), Q_UINT64_C(0xc9d8d730a2282b25), Q_UINT64_C(0x42ef1929d997a68b), Q_UINT64_C(0x6d4be421a819f8ea), Q_UINT64_C(0x7243d531e9d6d82f), Q_UINT64_C(0x8a45d102af05a8e9), Q_UINT64_C(0x5a46dffe3305cd02), Q_UINT64_C(0xaf414fd9b8d3e493), Q_UINT64_C(0x5fac96743afe163d), Q_UINT64_C(0x2ecbfb6e3ee6f398), Q_UINT64_C(0x53246a06bda62a84), Q_UINT64_C(0x46751f92ef74413f), Q_UINT64_C(0xf4df091448d0e5ad), Q_UINT64_C(0xb98a823a9e7d850c), Q_UINT64_C(0x4d2cb5bab4fa993e), Q_UINT64_C(0xd227213a8457a9d9), Q_UINT64_C(0x63930e3593b0083c), Q_UINT64_C(0x1f71bd25c753a781), Q_UINT64_C(0x18fe4194dad76930), Q_UINT64_C(0x34aa4e5ef625b84), Q_UINT64_C(0x8da56b3f5da4c701), Q_UINT64_C(0x1dcc1864dc2d55a2), Q_UINT64_C(0x48abe8723804b87), Q_UINT64_C(0xc9f6b7240f58cb84), Q_UINT64_C(0x1852e3c6c798c31a), Q_UINT64_C(0xccfb12a58600ff6f), Q_UINT64_C(0xdf2463ed1e69c6cf), Q_UINT64_C(0xf392029cd6251877), Q_UINT64_C(0xa584d536566f1d65), Q_UINT64_C(0x66e3156dd8742bc6), Q_UINT64_C(0x571f051721c6de3b), Q_UINT64_C(0x4c4bf4e34fa92df6), Q_UINT64_C(0xe0e5fee5152a5265), Q_UINT64_C(0xe4776589d3e12ad2), Q_UINT64_C(0x11f3605f0f87408b), Q_UINT64_C(0x2936cf11d29a4153), Q_UINT64_C(0x51c95b7f0e953cda), Q_UINT64_C(0xa44c3656302546a5), Q_UINT64_C(0x240fcfb80ee8671b), Q_UINT64_C(0x5b9f78b47b5e17e9) } , { Q_UINT64_C(0xb259769216954272), Q_UINT64_C(0x6aa6880f1589864a), Q_UINT64_C(0x4affebf5b942a96f), Q_UINT64_C(0x8b50441a2ee48136), Q_UINT64_C(0x185d0f5bfcdc8890), Q_UINT64_C(0x75448f1782032637), Q_UINT64_C(0x233ec58165e74b46), Q_UINT64_C(0xd17539644d0e1301), Q_UINT64_C(0xbde253c57e9bac3a), Q_UINT64_C(0x527f20a177e0ed4b), Q_UINT64_C(0xcdab268776e292ac), Q_UINT64_C(0x409f72f4d38b7948), Q_UINT64_C(0x7922923f76d74c7d), Q_UINT64_C(0x6b9f4d13d48832f7), Q_UINT64_C(0x6415c44d69a95b9c), Q_UINT64_C(0xf30b1c2bf0173d68), Q_UINT64_C(0x16300ca2f823614c), Q_UINT64_C(0x866eefbda718e04c), Q_UINT64_C(0xc88b32d088f799ca), Q_UINT64_C(0x113017b991c45d50), Q_UINT64_C(0x64d6fd22d032a91c), Q_UINT64_C(0x35bff9b98443df5), Q_UINT64_C(0x73626b81adb788b4), Q_UINT64_C(0x58a324553f1d5a4f), Q_UINT64_C(0x879cd6e046d5199e), Q_UINT64_C(0x844b95c1b35a886), Q_UINT64_C(0x32fe6062572b1af6), Q_UINT64_C(0x7ba66b270783da0a), Q_UINT64_C(0x724a9c4e4f2d0511), Q_UINT64_C(0x33641c19cdefa364), Q_UINT64_C(0x5f2dbe6cbbf4f98d), Q_UINT64_C(0xa2feb5bd2f354d51), Q_UINT64_C(0xe25e7dbb6f55080), Q_UINT64_C(0x3c955a6b617a923c), Q_UINT64_C(0xeaee6919b1a77668), Q_UINT64_C(0xbfc8c5bc72fe4f32), Q_UINT64_C(0x2bb960a249094616), Q_UINT64_C(0x7d101382b9dbf1ff), Q_UINT64_C(0x1fa79e3d05328128), Q_UINT64_C(0x56fb686c927681ef), Q_UINT64_C(0x522d3bb761678d90), Q_UINT64_C(0x1e37a31517264bd7), Q_UINT64_C(0xbf5bf9f64805e9ca), Q_UINT64_C(0xabaa35e4d8fc7b29), Q_UINT64_C(0x564a1669e374d841), Q_UINT64_C(0xf3894a340ca98b83), Q_UINT64_C(0xa4aec17e5565f07), Q_UINT64_C(0xa4546e38d3257fe7), Q_UINT64_C(0x29ff24bb8ee83a4), Q_UINT64_C(0x6cc60098585c2ef0), Q_UINT64_C(0x9c3bfbddb7432847), Q_UINT64_C(0x28935c25e5e93c39), Q_UINT64_C(0xfc006fa76f71e429), Q_UINT64_C(0x2e596b5a1fa162ba), Q_UINT64_C(0xe6419045dcc9a8c8), Q_UINT64_C(0x6b766b5fc1e2ab4d), Q_UINT64_C(0x8a1ad6a33fb25cf0), Q_UINT64_C(0xf232c4fa12425059), Q_UINT64_C(0xf2756284b64195a9), Q_UINT64_C(0x88a0aee4198a2795), Q_UINT64_C(0x781e9e741c2fc4f6), Q_UINT64_C(0x57a8ea4b4c76573), Q_UINT64_C(0xabea748efb8faf25), Q_UINT64_C(0xedb2d1cd3e3452df) } }; const quint64 RAND_WHITE_CASTLING_KS2 = Q_UINT64_C(0x41309eb017971c28); const quint64 RAND_WHITE_CASTLING_QS2 = Q_UINT64_C(0xd7924133b5f3c9e4); const quint64 RAND_BLACK_CASTLING_KS2 = Q_UINT64_C(0x6a61312ab2c41723); const quint64 RAND_BLACK_CASTLING_QS2 = Q_UINT64_C(0x23831c2de80baebf); const quint64 RAND_EN_PASSANT2[MAX_EN_PASSANT_SQUARES] = { Q_UINT64_C(0xdf435687057f4e6d), Q_UINT64_C(0x26024cbae9663f9d), Q_UINT64_C(0xbc9d578c9dde4f01), Q_UINT64_C(0x6a35051a173b7c2e), Q_UINT64_C(0x9bd04da145b2e7e4), Q_UINT64_C(0x44c1b954602c8d4f), Q_UINT64_C(0xb6ac54b27a14dd46), Q_UINT64_C(0x1d612c4a46c15365), Q_UINT64_C(0x3084d5ff1a7e2c10), Q_UINT64_C(0x85cac611ba340e15), Q_UINT64_C(0x15110f44ab651ff8), Q_UINT64_C(0x422a43a9d2417495), Q_UINT64_C(0xced6af0eae46e908), Q_UINT64_C(0x90a7ba36946b98d9), Q_UINT64_C(0x73a093d169724196), Q_UINT64_C(0xcb51354722fb743b) }; const quint64 RAND_TO_MOVE2 = Q_UINT64_C(0xaaed59a913f77582); const quint64 RAND_ECO_SQUARE[MAX_SQUARES] = { Q_UINT64_C(0x85c5df427ee97b66), Q_UINT64_C(0x8b08f0ba914f433b), Q_UINT64_C(0xc550169d3baf1bd0), Q_UINT64_C(0xc9e0d79a7ae18874), Q_UINT64_C(0xb8f5baef849cf8f3), Q_UINT64_C(0x9f543f73fdc3a0c6), Q_UINT64_C(0xf96811b98c36b78f), Q_UINT64_C(0x2eb88c6b12f5f076), Q_UINT64_C(0xb54536a38c33ae1b), Q_UINT64_C(0x49a8c7c27199d109), Q_UINT64_C(0x8ad6d839bd5fa5ff), Q_UINT64_C(0xc41dfc777cd078eb), Q_UINT64_C(0x26b95baa2629ff66), Q_UINT64_C(0xd6ba43a96f82e6fc), Q_UINT64_C(0x1b0b625e82c3b78d), Q_UINT64_C(0x55a429fb2efec7df), Q_UINT64_C(0x5ce3407a0e1eb8e7), Q_UINT64_C(0x40c40f1c019ffb71), Q_UINT64_C(0xf0d832a2c9d1a233), Q_UINT64_C(0x8476df43a961757a), Q_UINT64_C(0x61278190b7beee35), Q_UINT64_C(0x59c7eef14f15d557), Q_UINT64_C(0x5c76f4e6cbbe8cb1), Q_UINT64_C(0xd92014806ee5afe6), Q_UINT64_C(0x8d26aed794473561), Q_UINT64_C(0xaeab0f68699bc452), Q_UINT64_C(0xc2741575ba367181), Q_UINT64_C(0xd93525d8a810ed7b), Q_UINT64_C(0x2e514d22825b10d7), Q_UINT64_C(0x7d0ad041082c5eec), Q_UINT64_C(0x102771aee550e66d), Q_UINT64_C(0x397cef95642a6d30), Q_UINT64_C(0x56b8ae76234634b3), Q_UINT64_C(0x46ad9a921630b961), Q_UINT64_C(0x73fdf3f5f2bb9bb4), Q_UINT64_C(0xad7dc93026363c7f), Q_UINT64_C(0x10c17d77783547f3), Q_UINT64_C(0xc32038a65f19e4d4), Q_UINT64_C(0x106029125ba81485), Q_UINT64_C(0xef43147b10c5b783), Q_UINT64_C(0x9a25da8b7b3d02ac), Q_UINT64_C(0xdb0a4386ffcb973e), Q_UINT64_C(0xdea7acea1c0ff0cb), Q_UINT64_C(0xc0807f57db0a5b50), Q_UINT64_C(0xfd5d58bb8e7c7d26), Q_UINT64_C(0x54dc6b07e854d475), Q_UINT64_C(0x6c7da143dae253b9), Q_UINT64_C(0xf2267b971d787309), Q_UINT64_C(0x417407cdbf7fff86), Q_UINT64_C(0x8a9cb857e122219c), Q_UINT64_C(0x8e6c3444862bebed), Q_UINT64_C(0x17b4c866f02e3bee), Q_UINT64_C(0x7d21fbbcfa260d11), Q_UINT64_C(0x4ce19a879a1f0288), Q_UINT64_C(0x7c792043e58017be), Q_UINT64_C(0xe80476db133e01e2), Q_UINT64_C(0x70a20639306414e1), Q_UINT64_C(0x2aab26e0a7eb2dcf), Q_UINT64_C(0x300d23b842a58bf6), Q_UINT64_C(0x84804ddd113e164d), Q_UINT64_C(0xce912ec49285fb5f), Q_UINT64_C(0x73965253e568362e), Q_UINT64_C(0x137f60642df2b0ca), Q_UINT64_C(0xd5eec3fd4c28d85a) }; #endif chessx-1.0.0/src/guess/compileeco.cpp000644 001750 001750 00000012441 12223260306 020347 0ustar00niklasniklas000000 000000 #include "guess.h" #include "common.h" #include "board.h" #include "game.h" #include #include // Parsed data containers static QMap ecoPositions; static QMap > gtmPositions; // Number of milliseconds to spend deciding which of two possible moves // is the better one for the guess-the-move feature to offer user #define CALCULATE_MS 20 // Create GTM (Guess-The-Move) hash data. // // This new hash has a key on "position + square" and contains the move // that the guess-the-move feature should display when the user hovers // the mouse over this square in this position. // // It can be looked up quickly by the guess-the-move feature by // combining the hash for the current position + a unique hash for each // of the 64 squares. Thus providing an individual hash key for each // ECO position / target square combination. // // Because we can only offer the user a single choice, if the ECO data // suggests more than one possibility for a given position-square combo, // then use the Scid internal chess engine to decide which is the "best" // move to display to the user. // void updateFinalGuess(const Board& board, int target, const Move& move) { int from = move.from(); int to = move.to(); QList data; data << from << to; quint64 key = board.getHashPlusSquare(target); if(gtmPositions.contains(key)) { int ofrom = gtmPositions[key][0]; int oto = gtmPositions[key][1]; // For some reason the ECO data has a few dupes if(from == ofrom && to == oto) { return; } int ret = Guess::pickBest( qPrintable(board.toFen()), from, to, ofrom, oto, CALCULATE_MS); if(ret == 0) { gtmPositions[key] = data; } else if(ret < 0) { qDebug() << "ERROR deciding between moves.."; qDebug() << board.toFen() << target << from << to << gtmPositions[key][0] << gtmPositions[key][1]; } } else { gtmPositions[key] = data; } } bool parseAsciiEcoData(const QString& ecoFile) { ecoPositions.clear(); QFile file(ecoFile); if(!file.open(QIODevice::ReadOnly)) { return false; } QTextStream ecoStream(&file); ecoStream.setCodec("ISO-8859-1"); QString line; Board board; QString ecoCode; QRegExp ecoRegExp("[A-Z]\\d{2}[a-z]?"); QStringList tokenList; QString token; Move move; while(!ecoStream.atEnd()) { line = ecoStream.readLine(); //ignore comments and blank lines if(line.startsWith("#") || line == "") { continue; } //if line starts with eco code, store and begin new line if(line.indexOf(ecoRegExp) == 0) { ecoCode = line.section(' ', 0, 0); ecoCode += " " + line.section('"', 1, 1); board.setStandardPosition(); line = line.section('"', 2); } //parse any moves on line tokenList = line.split(" "); for(QStringList::Iterator iterator = tokenList.begin(); iterator != tokenList.end(); iterator++) { token = *iterator; if(token == "*") { // Record final position of this variation along with its ECO code ecoPositions.insert(board.getHashValue(), ecoCode); if(!move.isLegal()) { continue; } // Guess the move is based on second-to-last move, so undo last move Board guess(board); guess.undoMove(move); // We update twice because user might put mouse over // the "to" or "from" squares. updateFinalGuess(guess, move.to(), move); updateFinalGuess(guess, move.from(), move); continue; } if(token.contains('.')) { token = token.section('.', 1, 1); } if(token != "") { move = board.parseMove(token); if(move.isLegal()) { board.doMove(move); } else { qDebug() << "failed on" << token; ecoPositions.clear(); return false; } } } } return true; } // "chessx.eco.txt" -> "chessx.eco", "chessx.gtm" bool compileAsciiEcoFile(const QString& filenameIn, const QString& filenameOut, const QString& gtmFile) { // Read in the ECO data if(!parseAsciiEcoData(filenameIn)) { return false; } // Write out the main ECO file QFile file(filenameOut); file.open(QIODevice::WriteOnly); QDataStream sout(&file); sout << COMPILED_ECO_FILE_ID; sout << ecoPositions; file.close(); // Write out the GTM (guess-the-move) ECO file QFile gfile(gtmFile); gfile.open(QIODevice::WriteOnly); QDataStream gout(&gfile); gout << COMPILED_GUESS_FILE_ID; gout << gtmPositions; gfile.close(); ecoPositions.clear(); gtmPositions.clear(); return true; } chessx-1.0.0/data/images/circle_red.svg000755 001750 001750 00000021513 12062314776 020620 0ustar00niklasniklas000000 000000 LED Circle (Red) jean.victor.balin@gmail.com led shape Open Clip Art Library Jean-Victor Balin Jean-Victor Balin 2005-08-21 image/svg+xml en chessx-1.0.0/src/quazip/quazipfileinfo.h000644 001750 001750 00000003643 12223260306 021111 0ustar00niklasniklas000000 000000 #ifndef QUA_ZIPFILEINFO_H #define QUA_ZIPFILEINFO_H /* Copyright (C) 2005-2011 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. **/ #include #include #include "quazip_global.h" /// Information about a file inside archive. /** Call QuaZip::getCurrentFileInfo() or QuaZipFile::getFileInfo() to * fill this structure. */ struct QUAZIP_EXPORT QuaZipFileInfo { /// File name. QString name; /// Version created by. quint16 versionCreated; /// Version needed to extract. quint16 versionNeeded; /// General purpose flags. quint16 flags; /// Compression method. quint16 method; /// Last modification date and time. QDateTime dateTime; /// CRC. quint32 crc; /// Compressed file size. quint32 compressedSize; /// Uncompressed file size. quint32 uncompressedSize; /// Disk number start. quint16 diskNumberStart; /// Internal file attributes. quint16 internalAttr; /// External file attributes. quint32 externalAttr; /// Comment. QString comment; /// Extra field. QByteArray extra; }; #endif chessx-1.0.0/data/images/edit_out.png000644 001750 001750 00000016000 12144113023 020275 0ustar00niklasniklas000000 000000 PNG  IHDR>a CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs  tIME #UF4>IDATx]{puFk@61,Àq`&nb7uúvZS7u24t4nND&Ԟ,L$SLc!K&isN>ծJ+F=߽{.*Fgܔo88888888888888888888888888888888888888888888888^T~[kWшG&@2@&@&U$O/|X?'Wբ*Jd D*"Bͤ*̼azL:~G̕R⛟yˈ.XYϬ3D a`T JnnNG8'v{ێS!PA6UəSO㏿z6Qī0y4ބ HUYN y]=iP7us/G]$̨G޷{hc_S,[_>"8\ι4n EGXz,_|fZОo?Q{p0}\l#~'vm0!6:5_7^;W,Lt ؏/C}"bw~O²e+?ߍG!"Ic4^jqFoW5C)2mdBhB7zx7]z;_ rAE!Xs{ "4nZ鴁#@{r*^ZreQjc˭NF)T2, a{Ӎ>Yo kC; &^xx-;) *H"vHڏ {UՈ?,fƏ_܆=J>A\ k0sR} 5ڪ M_0 p? 8ٖ$OR`Ԥz| SIBk1s_ P\^B Ѐa$,.G+5'y"Pg;;Z2 ifjon_ZUg_(Uyz/sA((T f Q=ĦKI/kx! eژ&uL;H/{)緬}WPO-O߰ٷ5`׏'F!Nq+> Nw;N?ɓ"JETd)gJ4M4 E5^t)lMg1mԺ1ű8klCV*WoC c7Z[$b0}isP Sf^ a{o؁vs@k("(`CBd (r.l i7U}[pXu0d_ z[$#(Ljk|*Jwfrd sYcٌ2C^}0l' JJ4+-D=t&,`m2jtRqM5.]k*o@FkCPcvfI tK%ge7--sYPf dh!g(}#MsE%-[o@9 f~Nsg_o~O} N?.Le /,Y4 [AߍlUHCU!,`[|gﯯ,n}MZa")Vbceȩ@H-|h˛ k~7bZ_< ;`U"?[xGo^oT TxEɬj;&DG,g"0vЈ!i&Kڇ4r'~j} V!24 )8»{Dʒӝ#rnO48&` Y@q(#" ڱφF<!%FJ?~{֔}[DbL]Gme(_Q(e=H.,IHMa@ wF1]ZF%]ClϞ^AxQD31Īk" /C 0hέl29I f 'sÕEQ}sOۺh^ ?lۀ" U:gPمl"l""^ I`J=$ , 96F ZNó>SArr9ulIk!I-+c20ymE,ϔdk5˪$QNUL_$9-nZ⚐g HQsi@`r ɔ;[$Shxյ8q8/y2rrе1 |wǁ 3hw$[' )`0mV,ŷ8Tſ)r\5v6)T<9m-AcJdI,XquFd@co)oKV#ۢat}™StPN3eCFx-Dŗ$gvwfn(ŰUoJ(i/Yukk&WG5h\jAC->3%,vm?m*(RPF6j:H_.Ysے0[|aI~{L\dp}99ys9H(9~ !ji#I8h;ɞOstz0'hhɭal(y3 UH% bA2!xo`C)` * * (C) 2006-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ /** @ingroup Database The PlayerDatabase class is used to acces player data. @todo - optimize storage - QString is said to serialize as UTF-16 - maybe consider changing to a portable pure C++ format instead? */ #ifndef __PLAYERDATABASE_H__ #define __PLAYERDATABASE_H__ #include #include #include #include #include #include "playerdata.h" class PlayerDatabase { public: /** create a new player database */ bool create(const QString& fname); /** open an existing player database */ bool open(const QString& fname); /** remove a player database */ bool removeDatabase(const QString& fname); /** commit pending updates */ void commit(); /** rollback - cancel pending updates */ void rollback(); /** close the player database */ void close(); /** number of players in the database */ unsigned int count() const; /** add a new player */ bool add(const QString& playername); /** name of the current player object */ QString current() const; /** makes the player the current object for later query/update function calls. */ void setCurrent(const QString& playername); /** returns true iff the player has en entry in the database */ bool exists(const QString& playername) const; /** returns date of birth for a player */ PartialDate dateOfBirth() const; /** updates date of birth for a player */ void setDateOfBirth(const PartialDate& date); /** returns date of death for a player */ PartialDate dateOfDeath() const; /** updates date of death for a player */ void setDateOfDeath(const PartialDate& date); /** returns country for a player */ QString country() const; /** updates country for a player Standard is 3 character country code (RUS, DEN, SWE, etc.) Multiple countries can be provided by separating them by '/', fe. RUS/GER (earliest country first) */ void setCountry(const QString& country); /** returns title for a player */ QString title() const; /** updates title for a player gm: Grandmaster im: International Master fm: FIDE Master wgm: Woman Grandmaster wim: Woman International Master wfm: Woman FIDE Master cgm: Correspondence GM cim: Correspondence IM hgm: Honorary Grandmaster comp: Computer -: None/unknown Multiple titles can be provided by separating them by '+', fe. gm+cgm */ void setTitle(const QString& title); /** Index of the first elo list where player is represented */ int firstEloListIndex(); /** Index of the last elo list where player is represented */ int lastEloListIndex(); /** players elo rating from the elo list with the given index. In period from 1971 to 2000, there is 2 lists pr. year; The first list from 1971 has index = 1, and the last list of 2000 has index = 60. Since 2001, there is 4 lists pr. year. If player is not in the list, 0 is returned. */ int elo(const int eloListIndex) const; /** players elo rating at the given date. If player is not in the elolist on that date, 0 is returned. */ int elo(const PartialDate& date) const; /** Like elo(const QDate&), except when player is not in the actual elo list: Return rating from nearest previous list if available, overall estimation if no previous data available, 0 if nothing is available. Non-const due to caching. The cache can be useful, if calling repeatedly with a date inside the same elo list period (cf. the elo(int) function). */ int estimatedElo(const PartialDate& date); /** Like estimatedElo(const QDate&), but no caching is done. */ int estimatedEloNoCache(const PartialDate& date) const; /** highest overall elo achieved by current player */ int highestElo() const; /** overall elo estimation */ int estimatedElo() const; /** updates the current players elo for a given list in a given year */ void setElo(const int year, const int listIndex, const int elo); /** updates (overall) estimated elo for a player */ void setEstimatedElo(const int elo); /** returns true iff a photo of the current player is available; the photo can be accessed by photo() */ bool hasPhoto() const; /** returns photo for the current player if no photo is available, photo().isNull() */ QImage photo() const; /** updates photo for a player */ void setPhoto(const QImage& img); /** returns true iff a biography for the current player is available; the biography can be accessed by biography() */ bool hasBiography() const; /** returns biography for a player if no biography is available, biography().isNull() */ QString biography() const; /** updates biography for a player */ void setBiography(const QString& s); void appendToBiography(const QString& s); /** returns a list of all player names in database */ QStringList playerNames(); /** returns a list of player names in database, matching the prefix By default, max 10000000 names are returned By default, search is case sensitive */ QStringList findPlayers(const QString& prefix, const int maxCount = 10000000, const Qt::CaseSensitivity cs = Qt::CaseSensitive); /** returns the date for a given elo list index */ PartialDate eloListToDate(const int index); private: QMap m_mapping; // pointers into data QDataStream m_mapds; // contains mapping QFile m_mapfile; qint32 m_nplayers; // number of players in db - not counting pending add's qint32 m_npending_adds; // number of pending add's to db qint64 m_nplayers_offset; // position of count field in mapfile QDataStream m_datads; // contains data QFile m_datafile; qint64 m_dataFileCurrentPosition; // current position in datafile QMap m_pendingUpdates; // changes, not committed yet QString m_currentPlayerName; PlayerData m_currentPlayer; bool m_dirty; PlayerData readPlayerData(const QString & playername); int eloList(const PartialDate date) const; int eloList(const int year, const int index) const; }; #endif chessx-1.0.0/src/database/databaseinfo.cpp000644 001750 001750 00000010616 12223260306 021270 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2006-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include #include #include "databaseinfo.h" #include "filter.h" #include "game.h" #include "pgndatabase.h" #include "memorydatabase.h" #include "settings.h" DatabaseInfo::DatabaseInfo() { m_database = new MemoryDatabase; m_filter = new Filter(m_database); m_bLoaded = true; m_utf8 = false; m_undoStack = new QUndoStack(this); newGame(); } DatabaseInfo::DatabaseInfo(const QString& fname): m_filter(0), m_index(NewGame) { m_filename = fname; m_bLoaded = false; m_utf8 = false; m_undoStack = new QUndoStack(this); QFile file(fname); if(file.size() < 1024 * 1024 * AppSettings->getValue("/General/EditLimit").toInt()) { m_database = new MemoryDatabase; } else if(file.size() < INT_MAX) { m_database = new PgnDatabase(false); } else { m_database = new PgnDatabase(true); } } void DatabaseInfo::doLoadFile(QString filename) { if(!m_database->open(filename, m_utf8)) { emit LoadFinished(this); return; } m_database->parseFile(); delete m_filter; m_filter = new Filter(m_database); m_bLoaded = true; emit LoadFinished(this); } void DatabaseInfo::run() { QFileInfo fi = QFileInfo(m_filename); QString fname = fi.canonicalFilePath(); doLoadFile(fname); } bool DatabaseInfo::open(bool utf8) { m_bLoaded = false; m_utf8 = utf8; start(); return true; } void DatabaseInfo::close() { m_bLoaded = false; m_database->m_break = true; if(isRunning()) { bool bSuccess = wait(5000); if(!bSuccess) { terminate(); } } if(m_database) { delete m_database; } if(m_filter) { delete m_filter; } m_database = NULL; m_filter = NULL; m_undoStack->clear(); } DatabaseInfo::~DatabaseInfo() { } bool DatabaseInfo::loadGame(int index, bool reload) { if(!m_bLoaded) { return false; } if(!isValid()) { return false; } if(!reload && m_index == index) { return true; } if(!m_database || index < 0 || index >= m_database->count()) { return false; } if(!m_database->loadGame(index, m_game)) { return false; } m_undoStack->clear(); m_index = index; int n = m_filter->gamePosition(index) - 1; if(n < 0) { n = 0; } m_game.moveToId(n); m_game.setModified(false); return true; } void DatabaseInfo::newGame() { m_undoStack->clear(); m_game.clearTags(); m_game.clear(); m_game.setModified(false); m_index = NewGame; } bool DatabaseInfo::saveGame() { if(!m_bLoaded) { return false; } if(!isValid() || m_database->isReadOnly()) { return false; } QString eco; if(AppSettings->getValue("/General/automaticECO").toBool()) { eco = m_game.ecoClassify().left(3); if(!eco.isEmpty()) { m_game.setTag("ECO", eco); if(m_index >= 0) { database()->index()->setTag("ECO", eco, m_index); } } } if(m_index < m_database->count() && m_index >= 0) { if(m_database->replace(m_index, m_game)) { m_game.setModified(false); return true; } } else if(m_index == NewGame && m_database->appendGame(m_game)) { m_filter->resize(m_database->count(), 1); m_index = m_database->count() - 1; if(!eco.isEmpty()) { database()->index()->setTag("ECO", eco, m_index); } m_game.setModified(false); return true; } return false; } void DatabaseInfo::resetFilter() { if(m_filter) { m_filter->resize(m_database->count()); m_filter->setAll(1); } } chessx-1.0.0/data/images/fileopen.png000644 001750 001750 00000004766 12077036777 020333 0ustar00niklasniklas000000 000000 PNG  IHDRNFiCCPICC Profile(UoT?o\?US[IB*unS6mUo xB ISA$=t@hpS]Ƹ9w>5@WI`]5;V! A'@{N\..ƅG_!7suV$BlW=}i; F)A<.&Xax,38S(b׵*%31l #O-zQvaXOP5o6Zz&⻏^wkI/#&\%x/@{7S މjPh͔&mry>k7=ߪB#@fs_{덱п0-LZ~%Gpˈ{YXf^+_s-T>D@קƸ-9!r[2]3BcnCs?>*ԮeD|%4` :X2 pQSLPRaeyqĘ י5Fit )CdL$o$rpӶb>4+̹F_{Яki+x.+B.{L<۩ =UHcnf<>F ^e||pyv%b:iX'%8Iߔ? rw[vITVQN^dpYI"|#\cz[2M^S0[zIJ/HHȟ- Ic www.inkscape.org 4Fk% i"4QKEBj%K\L (P3Iӽ^aF]B:p@Gf.'4pGK" &#]%1zUo娖= Ek7 ấ@\JFU5aF5Y/Jǘ;azQ 9:E+%cՊ# l.n3ʦ;,/})aR\?(Ou`T Z,\\0/-*Fəߖow.յBO?!үSȩC~-],OUOvυy}9)6YȪc,Y!hd*砹#+kFqZZ4$' IENDB`chessx-1.0.0/data/themes/boards/000755 001750 001750 00000000000 12234477214 017267 5ustar00niklasniklas000000 000000 chessx-1.0.0/src/database/index.h000644 001750 001750 00000011434 12223260306 017423 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 Marius Roets * * (C) 2007 Rico Zenklusen * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __INDEX_H__ #define __INDEX_H__ #include #include #include #include "indexitem.h" #include "search.h" #include "game.h" /** @ingroup Database * The Index class holds a list of IndexItem instances, typically one * for each game in the current database. This enables fast access to * game header information. * * @todo * pack() and unpack() needs to be implemented */ class Index : public QObject { Q_OBJECT public: static const int defaultIndexItemSize; Index(); ~Index(); /** Adds an empty indexitem */ GameId add(); int count() const; // Storing tags // // /** Store the tag value for the given game, tag is given by name */ void setTag(const QString& tagName, const QString &value, int gameId); // Retrieving tags // // /** Restore all tags for gameId from Index into game object */ void loadGameHeaders(GameId id, Game& game); /** Get the tag value for given game */ QString tagValue(const QString&, GameId gameId) const; ValueIndex getValueIndex(const QString&) const; TagIndex getTagIndex(const QString& value) const; ValueIndex valueIndexFromTag(const QString& tagName, GameId gameId) const; ValueIndex valueIndexFromIndex(TagIndex tagIndex, GameId gameId) const; bool indexItemHasTag(TagIndex tagIndex, GameId gameId) const; QString tagValueName(ValueIndex getValueIndex) const; QStringList tagValues(const QString& tagName) const; /** Set the valid flag accordingly */ void setValidFlag(const int& gameId, bool value); /** Get the valid flag accordingly */ bool isValidFlag(const int& gameId) const; /** Set the valid flag accordingly */ bool replaceTagValue(const QString& tagName, const QString& newValue, const QString& oldValue); QStringList playerNames() const; // Searching tags // // /** Return a bit array to indicate which games in index have tag with matching value */ QBitArray listContainingValue(const QString& tagName, const QString& value) const; /** Returns a bit array to indicate which games in index have a tag value in given range */ QBitArray listInRange(const QString& tag, const QString& minValue, const QString& maxValue) const; /** Returns a bit array to indicate which games in index have a tag value which somewhat matches */ QBitArray listPartialValue(const QString& tagName, const QString& value) const; // Utility // // /** Write the index to disk, using m_filename */ bool write(QDataStream& out) const; /** Read the index from disk, using m_filename */ bool read(QDataStream& in, volatile bool *breakFlag); /** Clear all cached values */ void clearCache(); /** Build the tag caches */ void calculateCache(volatile bool* breakFlag = 0); /** Calculate missing data from the index file import */ void calculateTagMap(volatile bool *breakFlag); void calculateReverseMaps(volatile bool *breakFlag); /** Clears the index, and frees all associated memory */ void clear(); /** Read delete flag */ bool deleted(const int& gameId) const; /** Set delete flag */ void setDeleted(int gameId, bool df); signals: void progress(int); private: /** Contains information which games are marked for deletion */ QList m_deletedGames; /** Return a pointer to the index item for the given game id */ IndexItem* item(int gameId); /** Map an Index to a tagName */ QHash m_tagNames; QHash m_tagNameIndex; TagIndex AddTagName(QString); /** Map an Index to a tagValue */ QHash m_tagValues; QHash m_tagValueIndex; ValueIndex AddTagValue(QString); QList m_indexItems; /** Contains information which games are marked for deletion */ QList m_validFlags; QMultiHash m_mapTagToIndexItems; QString tagValue(TagIndex tagIndex, int gameId) const; QString tagName(TagIndex tagIndex) const; }; #endif // __INDEX_H__ chessx-1.0.0/data/images/save.png000644 001750 001750 00000007034 12141003207 017425 0ustar00niklasniklas000000 000000 PNG  IHDR>atEXtSoftwareAdobe ImageReadyqe< IDATx]KG}c챭6Q"DA'A>; Y,ϞH $"b9$YqX o<OWQ]U[=]={7w~ݷn{O%( %%~t_|@F.$l%C' qZc\3O; UYŞNTx >k%s4YUi^gμ׵*ypGaZh( jKҡ Qs_*ݕF,[TL]yF1zD^D;O`m4pnK 2Hh+ ,]@aHbh$N=ZYVyX64iA 9='f h AMPiOP0zMq{[#T!#AʠU9ݟt M39x2`B8uz.hb0H/wn0ȴ,\]ΏiT R1j=2Du]1 HZɂMNsc X 2hP)$$lO 7 c>T;7+ Uu'MXf{HiIݱɕ̵]֠;i\ P-ͿS@i e)SPIm/}9XYY@`ss޼t9ձB ѱJ8K:xg@$RV%pcj/_gN G߫-;_x#*ev`4T M*I<}!h1 i!n8C}A40~P=цS_`sAÏBPCi 0ZW/ @j͢6%<^LX8Э"Q䓲] Me~v\4::Wo60셀a|0y 8[wcyvTNɆ0$ %g` p~Pp ( q)'^J YBz餄í `PS!eʫTt Ct.R;@!Era( ҂`aH%Rr&J.d> 3j<ȐͽP{?Ȭ@YfN!X .X޹A,@B6}39@wVxTvC!LM\t!`<ipA ?C@_4h+ 0v 浀6؃#aMkyВ302WjZ"PJ"m9TrDiEpNQP2`! t}0H/@Q'i}}]°B@Y`*U[4 fkekӸ:0 z Bt?k>.^sţug[@×'[\.aٸqDpӿ+;Lsk+B{3 * * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef TABLEVIEW_H #define TABLEVIEW_H #include #include #include /** The TableView class is a specialized version of QTableView with automatic header layout saving. */ class TableView : public QTableView { Q_OBJECT public: TableView(QWidget *parent = 0); ~TableView(); public slots: /** Store current configuration. */ void saveConfig(); /** Restore current configuration. */ virtual void slotReconfigure(); /** Show context menu on header view */ void ShowContextMenu(const QPoint&); }; #endif chessx-1.0.0/data/themes/outline/leipzig.png000644 001750 001750 00000136520 11172700607 021647 0ustar00niklasniklas000000 000000 PNG  IHDRv=]bKGD̿ pHYsuuÃtIME  ,P IDATx]{U~J!IB* !$/!_![D!D"+F'!7o3Xk99ӜsY9gZ{YyVZY+keVZY+keVZY+keVZY+keVZY;U6e9segQi3#~ɸo:<:_n(dݢh ;ް~6f-NGw`5Kp #x/X[ȿnMd\6٠uOG06aͦ$z:Ys~($1eSm?[U85Lmlx@C.;WH ɿlU4B 7r1sopFfGq'+8ΎYX`8$`7 0ǥ1^/ ؊ه9 cr^!^vg>ϩA}ŶfxqmfʿhMԻBNA3y*wK*)|ƭ GQ!/AqF_\h@xAػ6I$9|ۄ@9`c\˳~{9e_&zW5r_ 9;uQe-Gg9տcňo{B+c|ơaZ6[+ƃ̌*ֳZV-Xwp܍Ax{)UX@b\7b eLx0|tzZ6YpQFVD ]!O Z^5ap2}v+ׂeз_f2Y U7d#ZLqPgry9>`]ttbt\؄Axaϲr.h|;\#PSjV!Vri 0CLRI𠗎0I-Zp4I1_@%& o$Ww>~` 2 Ȟv*^U XK,hHL% \dEyCB'iqJ+QFԖ]ln4;9 fBN)/@%[QwOqUٺ](|8/s-؈e8ցkRhE12SVDM%0$;\Lǁ68m?_`DdMX @ƟhAC:7 ]5L7-Z}ns|u`f_+3"ϩ'-cx=_c@ n2VE,0@t(t"'`\(@՞,8j T ?Y `ufʙS@ ##YeV8q,~z|aY~QYj{|hb,LeRl͝>ǡq׉%I60w8q`INg9~D; ^xz) ǥk՚ &5Vym~ղ5[-gܗ2ږ#㎊^(?q$, =Ѓp:K=& # 洠r@E;Di6[%>fo4 ai:NO#a8= rhO&?Z-tu-NaۼiUGmt]=m(`;ن U<)VO<C⮉%RΓ*ftK`$ɿ 4yU㥜CoȽ`]+?šQQXl<Ƨ.ϧ[.Oqثo+&^u!OHrx4!2I+&⦿ɜ r7Ipj7ixI7yiwrm|Ε$G 0J 0IW]h+X[kNi!:Dw4RE滫ah`ݒ^{h-;RPq Qw'$>d E MQ&˃UrM>Η.TxYI]``ȱX2KJ!o$ԤP frL<_:СZrϲy,Q&6(^ 0]C5t=6%>*`]AQڗrPO'0A*#y.۱=U!;;܃*vlˆ@2 f2S***[U@QUfŤOmnܐQ@G nĽd7zP{o n/\ֈGln ~/אH%0. <$+Zڃ=X Ei kv+똌wy%qݖ6/V܏ q#&Ptg@8~{s^=:*peWp7aky2`; !ocw _ȋ 5blj{yG` 6b3`36c36aPy8Mu)O~b{7n7@6fUKX'uiUw38``1VFAM@u@uTG.*;J,f#r{a|2|t]ZG08T2\ԩ6:|JAJ_˽CTʹ@EUHhᐴikrga;WQlFTA;|@Աu6>R[@hQ3Ǚ?҈L&9q١>ӥaֳj5m0 &skJj_6n*%=8Yjdi8lCvŽ BB NRqD^S0Ȧ&j2:ᇨ#/G|x./\F#z;G=<'=|A$Ov|FR0܈:q޽wZ 9iƨ)läovA0wc$bXGS )Of3S،')J}UG\7IJ`G*k[))J5ϳeG>8t> ^vi ivE5BnKҤ9$C}yL}*3J;`Ii=ǰQϋMy'ȳjnsBӺʷVz^X !J=vpX ߳műAօӉsKվ>aRBX׼ߓN+HXr4Wj"qU>h5P&#X鄙5MמE3 } QnU>}.Ͼ'm 6"z:>̮|WiIsORГzʁ#ٗmu#]1@~QyLoۘk"&_acO˾!v֦r9| 0{#0n|ع Z$]p&#@oW&|?h61 9OjZo cMΖa{mfVCHYy[U 1dG񫜥Uσ{i  YHўݿ|zcF 3SzT81jH5qo1м15=/Ef Iv=I|uR$L'O'f2D䳸408 ؗ" xiq;s:_s6`uK1F߸+D nq\0C(CV1A =,>+,A2':Zϋi;?`d:=NN񕔓qfC2Hwz-aqTKk4FywL* 0$C3HC|NW=0;}crY0=u[X Ǐ<͍8l~$!- =.cA1u41؎؂;4zM~K:&dT&g;ZiB2UjBƸGL%hx!kc:<$q:2z!okTi+8uX٬*fM+8 \nSa|SMdx/Zo3`i<]B`r8QwK;CwǢG] jĭ1iG]B]K-z>,2!Tv#䤎WgmynRO,)59+^R>gx}sTaV^p6s@p]d~:wV0W{fz,9Y(wK TRJ{饆){ δZ.QlZ6a@C񣳪ҪhN>gKxS Ng'oc dkO37ʼn#h0xmB( ZJ򧰹i udH&Q}dX\ %fd|;Sc}3OfU#)Ab& bZ%NwZ9u;=`l oƝNݵ4{f TVQ k\s€4-"hd P kJ'σyBa9*D3^^#:"טܞ$WFۜ6VFɽ Vql~v:1gr+ʣ6AG9^/zEF=/P+=ۘU_/PgKEM9CfhQ [\ީh~i1H"'Pօ1_Fm =0yJä.iooE亰taD,;s.D~G\N\1C^Q"dt^֟F}%_NSI#9LRGAq>nƪ5{$nqE8oh>X>ΖaWf0vn}J, (!JbI^32`S|APX61$oq_ߝKϞ82 41ږr(ϻ[\=FxA\@$`\ C1J-Ǎmf(8VD1 :$y9"XHi>NQЂȹaڕL?w+;y#T2ι_D1Q*elCiqp'uW_˟j+ )$F~O7\ 'IdhHTL@j*tgżY.S p&p]0m=Q&D ̶>@L,ez'J$::@uJVZamu0oIo@w3 oGf֛Vj‹(uE&V]q#XEvn7ĝ25X [MEE`v/>OX0;5 9@/}Q^]蘔~F{쀅S0TPt LX,P ['X[]ܸytBuSEv$^V+R@͘kY@"RG\Ạ̇̄,*OY,2h%K8 )IQVUXHj@ct4@SK}v @U}p_Wv,d'T'6Vh:-Mx#?uoЕ'd`!qa=#OIq= IDAT,`^o%(gކulx xBh4G3ԭy &bD[Gnk.q)$woT{Wc ~IJYU|0&$!L24y@,ۋjfmB5W;"`8QH{D+1s' TSbWK<+u :`0Sc`gNw e|+|mNdvF82ߏ%rjIsd@2$7(Uݪ9ޘcC} m%X1M'MIr;Ǒb|7FY /T}g Q=$06-,!!:|c/_;O-`./yqh0|oKsXH~G`eYcDg%zSbsz+eҢdO |֣ZdJpwwo0~ZJ8fb/Ǚed]ޣb`T`|CSM)ET >CRthMT+$ԓ<[SX t iN+FH C{[y04y(¶$`.o Ֆs弔T0iЛEhZfZ]C?`bQ$M6+c{?'guΤv*ְé>e^Loݮu2FiQ͡ %NNJSp%ǜI'4{),|"7@8$x\dWsB7o ث:>gڑc~8.ALէȔ84A2 `4K)`CVSNnHя&07#"*6-}ěe'o١|yS{('}՚~ir*8|K1tEq-`SnN(LeK\ ~ '+&0pǧD2m؋8,4 ncMɱ TLN'Mqxb(z5z:4ՠ`o?y(Uù/`\ `"ɥZ"+e7;l'O A7fYχvF,.I{CɃ%HU?~$9A]{M&XK.i힚ʍTb+k!h~+E7I 3j&Dzׅ$#mC I(:nq8;HZRHA'2¡& G:Y$ {q<+GEwI07Fjs orz4o>] V OG+\TCpUI!K݄/TWu+TaiՙcWxT & ⺪ψ_-1B`$ܛL$qnβZy,er I>aD}n[` 3fVs;hb>'3Rx9k뱚+}/]]㘧\aY cĊ|VeM(t]TCiKFVUg{80'I^Y*~nawȷ*hG& cm+J/=%U ԃd.j_P Eożq7)qZFvtba3,y)_2HM]]dC#$#uďMpCQYF-4vx;LV$ȜSDGEA} a|d ֧Z4CI<\}"g#1kS #C}aUbBZ{ c$졺/rv]tŋ$C)w0#vMt &x3W;=i'1$y`ϸެE8/m gbJ`TF{ 帒SGaΝ<*9;Z>zHr9y{v1V,9\-k7K$;?Rhe㰨w;W"o;L&q)Ay,$7ymHF2sMJn~CnYWvi,ɪ(~/ၨpj@sO]&Qy$q`6r8Ϲ紌d%1T|LE{uD_'X,Aw| Rl r5veJp#`+&k3lC;,·9ucNK'JI1~@eW^Az\*#?Zzw4n֓"7H=xyWWng-ij@m_ RP_>)=|jNA?@~9uy F[Z̭ rC5ID[PWRߌ17(|eLSj90YTgށFob tB:7N'7%"C j{ GiV1wRW%Z&Mz8(aS=d8c^㖊}WmgEc,.(Ư (~HQ{N٦qAc2Vٍk͌fΪYtis5ﰇ"qǏsqzh3FBylV S1mMMOFΗo":T浪g|Q< x j bYKczZN8%B2յrvP2_K&-wyGa+,q^PNgtLr)l̵) wBB9f8NyYEއ|"L %)['0t{zI9C~F7@4y$٘^:nW6B`{sO2z]8sKTiE[fdQ>hzBrPO>) '!ʐJorYn6^C)ykbT* |Hnts~UnOE&JqvAӁ򻯐+K%Xw~S9~5.IIh*!ŻI ᩢ}Bz:_3Ew4C,RBr\Ģ#6` v{y^K 02e|wb3 ){ܾ$yXq_Nq'I f>vx,HiMqyBX"wDRuh$2H:p"O=g9@]/ |w zOuajzw\s P_k.۽d2J _(m͖B.&k6]duҗEW'*Ͽa{S dEcgg ;(KR:VpyYBMtȮO3jJȊd!"f4 ŵ~v|1e &%fMnp3lD3"D>6t)=S A M.Lwe):L$]ѲTP'T] ǟ ,n!z2˕gyڅɒ!.1= #1D'CP;.#YpLs>3ʚOU:x5tG Ȏ fd46m-<x,Y%S)90^oe1ɞvF&s\`  kX՜Y' 5MzLÅOZ20c.UJQg Pf9L2-/=C|}[}ŹW$`ni~?':_9Wè}R<7X0!!nL6Rm{pNH+Lu ڵ.guN^HKB [(23 }⣌٥0g k$PYJPMRC'._2F4ZW˯tpY}>/UNfoq-q"Sw̸F)?14s^uPaE= 6R-Ug[^P3=9$/)~ x&-9/OuK${; yM*hBO,.'q +wd)Όz#=%H6'&_~FR!n+%vTf]ZSz=LiKO&\ƨ ddsC0rSUV3i4[Bu}jFQn_)͘V,*,=teZ3Wb <.pee,Z9R@-\l8a5x [Zk*jy"/g?NNLO[՛z( 4$y} tUCc-I63OB͜1$rTd0S3KcC2HNzFGA3<rFeNr]j3 I9oj t œU6Maͷt/[jUQa 5GdEa\[X_8CI8dWp#w2r0w @\=" 8Dz ɭţYO k~ɜ̏8Ar:K+Ld{1iX QL$6}7#rxU8J]5"cԇnE`#rp/p7s#W/GĄr|mFn:ƨ:cBX`?wS9eHzF`$S@W-Uzx퓸'}o%}dfɜɆO6`r_߮=[fdF* eCQ@2,]TvUdzCΌo0D^?X~^ wOH:`3b?%kM߾p[Y^1ÖTwyF>STIg.WoLP/x4R-C>IR%i8\(`褽*ZJrpI.]#;\5HNWg3?yR9q:V>ck!t܇Y#UXIx1Wz#GmY:u IDAT\O'twj_cDtzw(DS7^ڞ$Qj((ه$]R+)jإRYkZ>iתcIKl uj-~W:}ô3SI/Jsø'xt'C*vz9/ rBʟPce2?[ILeErFej-r2Ǩ%~Ad;m!.!w嗥dk3?`ֺm ِkU,_"ܾ:4D\X&ɜi=s]eH1:|H11,d}SK0 xD:7BDڭꟈqZer]fPq3glazr<*C>w'(sZ$Nt_XKo:A⏚ɐc&UOݺ 24(uf=LY[-ޚVwר!t~i{{Fר`_ws0ƑSIϊC%Jf<\Y/OM5H)}gx>~M6N/g[+FDbaLfb=v\/=T@rL)Cxѱ&mnd>?8o[j{RpLU Zbq&S;2e|FyW}KqVg!'-?^IB͵JXP y E2fD5e_4|*<V<"t&F;z.QyDg de{]2)=kM=Sf8k=IKƉG ݋UnLztY,e y QD/a?h(\L&x޳s12[rQ*V'E ǐzWW h_t'ӕ^f+\/cUN>z\$2Q]1u&0p‚/>m2A]\-U5iOh0&;F WvܦATOI12H=^_r+.w_~Tݗ8*:\|FHܟ`਋2L3q\%e TjɔtNLR+rrvѓ\É@VHDf9a$^Dl:ᯝ3x:[jč%GHG|u -v@)V/,ezCU3N(0y+.`spSAF=%euI :޾BEh鈨R e0^?Dl!ްpw\esO gIML]py|K(G$=.hn`$ng?SX}YNBAq?^P%Xv o!dLO{o1{E-Up8ېW{[E^"ZRi-:tcJ`-ޟ \"rG5_cvDQ(ҰqI.fbV%'ސr۞([csTaM v0"=yzZk#㡙ɑʜ߆N ֓$|AL%kȕB(M_4TGY-]>jOĩ;ЁII8`8AvOmvբ ߫@MNYs"e3D%8O'ֻihq+)ᄓN IreU=Ae55IU+C}.R x}J9*ʋ)WM!!W0!=|2Q)t"wSE_<_JbkIcv!gm,Hg9Guաj#hY(&tD~0p+'/zнQ5_~z-* ȉR/E;3,2֛f`"ڛQw'㏝IYkdȁix 21ݔ#&DzZ"Wێ#yJ8A=VpIv5v,F9DJ nr!I~ ׬[\k;n`0ɍ&|,3tWK}r_QU0`4%A7rk m;)f+.3 O]l Zdw¤5M-=!EDUOI2W!+M^Y5LT$R1IYP…3h@i̹M# ^.C"$}JG=!InɗO\n?}`).*J'S鰃%fK-=$o˜ Rc^4 VuFnSaEԕn~AujSV%7Å>EPnY'kxJHh :xZ;f~pZzdUmQDX)b6z*l^-:> O #ʆby?LX (^JlVg93UXA8QhwDNItwkI6Ƹ-&֩uڬE| 'hqEf>2|^ltE#Wm sm{`';TS[mkxãOQ;BU[VWňTwtcv`8Flq\͔bPW+ݽD,vqkZ<]]>Fpl{\ͱ/YU۹ F[NV؋'β=XZJNhMf"ɴ<%$au֦`6R9+` zՍ9J$a39sP.jTAHt.8)ގ<-%bj]>PK qOǂVGW ciZ@;!\{~g)S=j `uN9^%X]WݫȠiv.g}H 0~le",y:\njZ"oc,̉̒}= 'zq.6 34SCoy]UJ*5ȉB~JhmzR?;/]ydReyjwf{9;##/|}_ cK 6k88(!`wCV`r&s`ց7UeB2+b,1$9 NΑC%< \޽$9!12@Q)fd07:2E{m+?uTلi=Ϊ?TSM54!/+! !!/{"xs!0ETLBQ{ejY{}33Vڟ՜}]绾kTn(4lu'j} 9yӞr,` زfmv9}M5`YN0'yEЅyK:AEik$n/!r7` &̧.!tZj.'}=\>m !d{ A$_sP ;?Ʋ$0dG!1@+ZYn.l4,Ny;=T֤vh8E(3l K13KyiLd|\68 e4# q$PB8e؈XeBGI.ī1} {QB4_#3jnVM9:* e2 \j|܍Q^B9 mt5{1x$d}"p%Jp%Z+c 5A~@W|@5NR]Ǯ:mPg>^1=.D7s2)-۸nrqa^FMMe~Lc׻>lay0 I]yNfVM-}%|F#ij=*qИ M`L2sh] LǗG`.zFkbX?  =/)cU›hрǡ;m|F5|; wPMsshbcJF![e/f7c`ϭ _10c} .ó|njkE,G.qblb(AƺT/$ke9/"M.ˠ;y*%}֝u~P%[p+,wx~͜y"v&ӱ0HaUɮ:bV+}|]/}8UF#V1=_d,B"/Jc 'D݃P'9sբod XTia{ 3? #`Ľ8P]({ڼ@NhOdp3PZcGPJ>hN{w5؇#R2/8Uii{/ Cu$9rwyGpnf+"Vg\hl#V*xTRZu6+nޟOh`X;?o?2k=9=S(d}\Pn~Xb2 w68ϙkϱ>h14Z":Ƨ0zjɿR2nA[ 6|3tK`|lg~U>SL`6Vve&qWH;+2 _v8n wpVŵڅuf-5p({ԫ%%$/[i!mLݺJ ^.@P{ O Ȁ h,`00#=؀1$sU]-ũ[Ta8T#R>Q,a G>pDCWShGRy`jk!K\ Sn=O<$u/( 0 M :lSd{[{g+,_i #t1+›=(; I[=Se(^v !ۍ8Q|NΗE;qRTd~DnLɦ}IY&Aȏy}y%BbjO:X.V#5L] GkM#u=eͥ5OLѻ+MB'Eu#h|]F26CmȘ YH7`, (X2/GCcFPR.|Ǜ7c?ZP7v0Б1E@O_RBa##TN}57!gz#1q=I>EB${XL(W}Md[* ^Ip8b!F~HӔ YE ;*R! Hg2.iXőC)<}'sMZ1R^~T" &O /\ *:בn29DRУm`H@{ռHr'!^ɳ5a-+H(/M_D'td)&2?nG,26-pі$o~PFV;/ #IeGhFK`YŌՌmgPai̐;>WY1Zo* rrx Ix^?q<9Inw5dWpzMnP”/A7-lrPl' ci}WV$O@}~}j^r=*`Ֆ6rNQoD)KX `9W5]}Wd+("CHh\ui*V;LյsY>dxysxB %za}oC,` 0XHW 20Ƙ̸=F] ySX;Tl *%8婜niRŒרrrܤ^&N;KyF=S3&.uq!n֟ᶔ3C",q}i|,c[ r9e TTn|\8Tkؘc p,o֯9G5@ucFlnʝMB2N*27;R9<\'̶%mRijUTYTYT?OlhD2O;Pu\|K%+8<3(u;B2Ÿ##?y/Jbd`LE&'=vıصoO2?ޮ;%ћF9t='wr*|Ӂ֍?Wb!y~]*&?M6*ie7$qʺ ptdGwtmMWi>̓=D{RlıDTEd5;\4(^ wq=c;8(ћa-5h6Gw_gX >DEL&^1ҚCFJ~b}1/Gq3I[̕6l ~xM4qsAx;N}saF^khBFo34`uIQ < ӓM]p#zв8c1AYRY;a^1ӱq'A8G ^Bl=c[a`N 6 3 v,B,2UX2lƶY.h& cO~-Cҭd|mڢ+NGg;T`!`)XmCK;Ge KO}}2O7\ ʀyJw5-qJ c=~ܩ1:F724g W 莮x {a܈'b, \o-*eM#]Va<>硉[cC:}m)Z@p$C]PC +ci9c:f[c>v*P[mdKdKV/ -ْ-ْ-,`dKdKdK0%[%[% ْ-ْ-ْlɖlɖlFdKdKd#[%[%[-ْ-ْ-ْlɖlɖlFdKdKd#[%[%[R]rr]dq!bC߳eْ-#=ٲS\têtf=!GwM1N3~t ^8;S '[>) ǁmѢD}~6k'Np%:rK>R#eKGCzД[ϥ:G j9 p{9Vdr 7.F&GymfK2iN{\Xzv RPd5'wpͺkvfEg.;Grfn{jp(:G10NzY8 x 8$kb ]rPWmXץ vha7^8usQ=~?nX+lzl?*v͝Vq^~!;c=JZzZv tB{"{q0.*"~-+vVld˿*8"OIz՟w `.X"+wl`8rߌK\MtiC0\}]L %XoFtb?=⊰D7XY87Nbh"^uVVESf8yKU6{f#5ˆ >8E 1`m001j*hth6l?ĵm8eX%e,as&h'r9,A;&cԏ]p&wQ EHtp K߄+nAIw{X_Aydȹ=z]Hŕ\5`eFF I=ˑA>\jlifh{sH~ꉳ I7갋ղ\O#ΔxIF$`T֜@. b*͞_Ek-p48n#cոglýՄ9٪PINdAĨQߞcGOSwPa/. mHr߸WFC6⅜`M$j?n-(cVM1EW˰ux9rVkVu)֊kPUne<-֘~ Ma;#`wIw\wIN6첀Q@\t/?]07E%.d9oev–Ve@Gó%#30͓gŞ1_mLvkB~]=Ǎ\UBEiyvQL-u 8XzEk\ ^L!; tyv XH\eb].0KcP;v_OcEYNR'H,%oz: vz)H#w ^\n35d9w.KoƲga^<诽(sv `.Gc(|#05λr8 -}PNP3U3Zl oflGZοfm0>Ǩ:ycj!>X&]qV<w^|w+vfqw1od|ʣd yͧYT9[֣fHC͎SDžh\!-QBca!fħd{ȧvhQuXJB%Va#3x܉bmԋ\!%A[`7(@-FmVy9zR}uw-s1*7kL]6.hx4{L/ި/{%8luoD(xZKt݊4\o)V+^uRLƧlb|rlXtr,D7'/QcU1ʹmXPJ`6l9R-շYʍrc*mfn0eDC>(jkFF##_5̩/ Օ:*VbhtƐL6ސ} mm1{y޼/#؁Io]I8G-܆Clm,̜F_x/zE6DFM)uNvl e؀u p]C/e׷seig Ӂ~טx3V h |"dLMUQcu4ز=Yxt9.j=<>lERNbb+^ `aڀuHN7c'd=>3uyũ@.aqΕ^$p7GsRU5Y!^?q4M1\ U_cԁ!!,ߩ;O;O a,$9K~9SJe`GGn$ǹە\v~]6-@""GH2E2AN 1kq(7xIR(v'˭gZ$[c>NqwOj:R7Tq$)U܍;]|YG`h_.$Qzl8 \9QUh7KFфI~Ynqۚ_짰[0ɗZ:>wUy=~k1S< k-IPwOͤF'ɷaf>`rH}|S7_dȲ1OU&͹NBLA/Nʌ~:$$K2?Ϙ!1j~KHy\u뤁 FlKar3|U$Wy삗R2}q&. g}_ sÝ!5~CUQ]5m>vǿ}qgW{͸R˜Xpb\5N}  @1q%weT)InըK( Re3.Onr 0'Iq2F+6bkݧ.;w@QB _\c# zVU0/A} !Κ8?ۤ2xWFEүW,M12L*fnf6\b.: d"K}5ӷtJb@ˋxo;^#-lF YBQ߯kN#Cb? ?ܘJXʡ˞Ǘ&h:5\O%P ##5*ǡZlZ]#2'"P⸪#rP+wɣ2'9|D)Rh+!<!Kd7uR aHJ$@]q3>Med>#YI `v%ب $?i)v7di ;{{/+!zP)GWՄN(Ԋq/ld`tڣVމڳVJYE#{,sjctSDY6qwp.T4uAh Uh㴨%< \lnIN[HfJKˏC,a M3LOw*VB)P=v08c Iv%DV$9M=؊$EXF%SpҋJj =Oyn]ʮn0]}@_s.i}Ԗkdxkj6 cXFO8#RBSh5X+CsqU:hu6_K`|05Kh@-I ͠b)ݹrͤ%9ԒTEX+<-}1_)fxVD$0eV$&CI1_.r8F?XAUmD*a ̓ZmN#W+Ak\nim$yQN/JPF&dy6RK>gymȵgyZۘO%I*4N`eyO:|A[dT"p{ʃ$Sy./L7s fJ.jGZiy{e<`,OCQ$O, C3fSyo6_ e^멶`*'5[}nowija6{,"i&ZuIr ɨ &+=*dTC_Ϝ C$zSE_>P!GԱm=lяVd`jg ɪ*d)TWM$7Sb˜_cdIX+}(Xd0䈸W5Ib1G ^ 9͵4vJ6a0xu0E2Fnpo8\߄,d_'G\~{(ƿUu\煔͔ZPK 5stꮎ]R#.X#"۰16 S݀fȯ˵?_1A9xw )cLL "cƶdhpV,]WI^!%EozzJ~7̅ǻ@etl#ckn8X7d-J(jI(!|*у \ف_fT6ZnӰoJ vLVf@-ox]AJēC/ (EKaiHS#rP^}l(1rk^,I+1,NRSąޣ8%j 5ހ\r`)] -TPO+] _rGhU=spNSqE1J\ff \_WpO\jU` `Wkt})в{VV15еsHi1]%3byPA <7,Fe*s&~:Gq0c!5)e&mMu|:o%"'|!V--쒈;I(md9ƾdX^}ZϹ.w&laqC_ Xۻ'`}s 2>fNgbK)& 9ߜa>cf3$\:I7"|yXZyhCfAW_$'n<͌nI_p&ɐ#` 0w)ՔS 0U&U6yT:$}=$s< /:$mɀGı$鷟w+I^r8MЊ̋7FEloc,zhyIFIWr>]懌M,yB!R'q;>a9$9FI*N,` 򸇕gpS]a8ْ&ۥώ~jzIJG\a]'>䙣Sy^G&~0v})Y;bJXrޖ "lu\B8Νy =h^)2&<$-*#эbMD,²(^bwo|T_4wmJ >)Y>ArkjP;ҝQ.}^+2ܝ< 1F'ʯJq% CːZ l?Փ|eToJᢃƍq߭1]Q%&, X3]W c)θ"njȬan\_zz?I^ǎo.[HrhؕU{"ww F!!@/Hik={2T/a ޭ-$k= ȏLQse['\OIp &5:EU,w(ܾIC#˼ XKs~ M-iȎfOrk$ڮhbtbKWē|Z4YVsWa>y<'iu$s7N1`h[|IbK,` ɮ ,d#/AԻTgr0Jվ*۬%';x)Br8R!7s-iQj~?0,XtcT7Wjy~ˮ&i*5MQ~# LAײڢ0 ]8Dg.ƠPnѽ4_+5xd F}l/l7`83':Z8ن^ ra_dk+ aTYSӁJ*a.9Zu]\>•N*b0#O И]}#ۜ*'NQؘvx宧4 Wmh +V{f4CwޙC`F`U | B38gT'$Kgwk` kK518xkV4R6v:dJy~zWE2(iۣl^V$D3haL**h#b9w[c,=oNc t$%Mc_v!{y\sWZNmgxp@I :떁1:{ .:T%IaQLwd |m7jvq`N&j$M!)9qRV04Y z*íqh.z mdS_l>:SY .V^1xhx} ̎a旅RLDJ:`N]N$y緝B+1k(5ld>^+M&ĖVNFLV&`ԕJJ|Qo=2I,ؒ$LQ$0FaJg>y,qd-!|!u]9Lљ@W\C' tP+) mZ9ͿgF5 ,Ȁ.r:Qq;Y$8(w64-+ I~UjDrN˄Q(s(Gjz.N.[0J^ $9ܼC 8f`bN,R$&%!dY,J%]d][0ZCNWSsU% I]%IGI$]܊XGC{I0u,l|@; .4u[ӱde隵C 57qGr$?yhZ^\\ם>۹SGt#?3,;ցy͕f!ĘqRoqI6vr|yp~`:a)/f/ qVx >fMdTe%.Hv؈ x&ۃ !vE;W`#"{|.)hյVq9wX8&`tD^>h/NġҢNDMR_Kj#̮bLX] %,-T(Ѫ< ԻCR`d#n "uڏ&`LmQBUzI06L)5Z]8$c~ &йj"yIF/̝XxL31 O0qRiz $G<;5+[)1RDaHnA8rkZ+}30Qف[qLHrIR;uWJ;ͺ Za`Y^UZ6SpSvu|j%abn0e{45IR#O.r'/OϿ&VRQQ(T p WE e#'WŽm 'zvFH= P δI^n[nvm)3nf=X Lyg2a#|YYg^x^iUMxOU|S5!6YkO"'Uk#* g\ 1 w97Vqn=-׀~Ș Da0II\KGZPrY3Fa;*볖 Z#dyژ_[\6bz u11ƖIi4Kybi\O'|l,w/E3FZyÜ\RVX \*VU],|_"6 q'MwhaF$}~߷l: Uh"G䠶f~N]6BY}{:ZGG@1+7di4cW\Ӎjxu@48Xc6tF~?|'ì^N~_'@;fZcXSeԡ8> |k_2KdOFF;rvmu.RsKHビwb|8<%yDϗ8?&1'ʴ}&^]r($3lԌ&rv-+iTRj;$ ˍ×.ٽIVz wM~z4ڐHJaOFL^X&B >LCt-3</#n4cS~G?9^H-yUelMa79=_FoX =TnZ)_UO5PFG!%`30L\s`N8`\Q\HncICe)}SlU=w_:Tj:99H9RQ|<"-9j.oKGGɫ-Aj5czrd`#:S VwJ37_8SWH;UG%΍IrzGnv?0Z,Fb~k'3 qKU\5FI^ubr0x#b'`H0чa!B-9"vy愣!IDAT}r sdEA^O*ϥέIv Y/TP!LRrxcK0V'yV]'f`H;‚JtnQڳS(su_8\&9X%{eV 'V|)e<@Vۺ\mt%U͜p8٥2$WD'7~v|!=K,J pKOIsElR>%Aaϊ@+tżG\,'ꄜ 3n7JUգ|VMC%R|4PVUG%ʯfXe2A`XE!l:Nkۊ+)ܩȐ+ /Hby苸ibqzr=(" ۻH&.B4\mYW%a_y)AOl9I+@?[fܴ/s U;/L|#Q jCS#xl ̳RoK 1f훁pM{x]Iɜ H"sŸ(ށگEҊ"wVpqe桎/P~~ŅuEK]Tǽ%\+O|x\Er)7$҃Uq;f&:5rrF#oZ+SLٝw2MFH||/X ga Gj[a/T95ΓMthXBL/\bc9:̑xW*mHxdqSG$>ڢ <n0p]#xsğᣝoW-d=[.a 'no& x>x6Kgy .24 ڻALm0 \Ss yshQY"ĭע$-c8 fn+@萯\}>7jk<*#K]W~td+ׄ&,xwjp`sx-*f{`Y*F&YiVABGϘۇq${KY)`ZQxR ^߹Wy&W=&yq@Ze*Ŕw/)fc5>`TBZ,'W&Z2[vhvN04h%mT}'Q7qS9dy; pwbU]]E\**o d.F'V=_ռb@҂*浭T^ޕ'j$)Mdvewy&dV+d}i1 _N% |€n\7<ƯN_k[]>c!$@B:5UBb8Z]f!5>tr4Y|E 0&n/٤/X-?\(髿T>oQH6@$Ik5N`58&7߇ˮ |c:E7Ne=n :] KoYʓ.O096Mi&#e8i!W~s`pBl#vf3¶0<~{*Rj,15A d{#Z Rs$5u.y_W B>w~.Ym30W~aMe'aEbr{yo9<sNp S3핡.PjH w@o+3vzAOl1\S=ojɐnSۂ0pQWw~, }J4Ӻ%!`̱ ݬ9.ܦP+gd̬dXOHWwt\rijbs_WWmutY 漢Tgx.AUIfR= ]u({=: aѐxN/r{oENw` hM S-b[?ǢL1'^ 5yIܵ`t3ϻqn_b1yQ3@8&Osk+4xq7u^_^UC9[me;J q ðEkϻm\$DQapPp‰ܒ@7#ݲNR˂1eZ/#:3/=lY2uN_`qeRKmD&gVe$x-fHrVɆ蚌kEt Yz: C2U#C[ޑtiHCXz@D# Ԫ:!HVUZGѫQjT8 \l}=j}9n u(NHXؘP}.~9xLd(tӥjGC.ҨiW+gMI@xIo>8ֽ:=G`2ljF^ݐʿ1p$Kxwb7ZYRk kXU!< _RTH9]- N݃ PyPRqWɗ2Gn~LWV,;jFJ3ayĨv(d3sb>jϓˢm!^sd#~lhwék<9О+0H>(te{*@30q2r.bVr k<O`,RzqRyc||D 3v0jl%ki'ۦ|;FHn8?G 7$dvd뜁?2āMj9#*x36 LH1z4@#kX wRV5.B|۹˹KՎ lnJ&Gd0,.qPX{`[/ h T Ǜ.6y63\ıkc,tgyD+U"x!k4:*2H)"/Wσ{~ ?;2ѰVN b6\6538C b6<ֱxeNSL: :j&5`m7 z^Ruhpԣ٠v6ԡA!il|_$HtTgFJ[Kii-9ҙ.|xY9(۵3q76AyXi/܉״!xC7$3 n5/&#SPsPl\_2p=S0Eށ ܃?'tW?`ph 9WIiuҲؙZ6I&vr(6>.\%ޏG[ n&]^/kPKFIgHg;'x7 ֔;ͭ¹p&s1bC% Fj i/0q`_տ8 i0n ` ^rxη**Pn-ʛby3UzZCCm[ L-Qse1>WAnS>ԩrBW6ԋ4L^Q$'LV#'t*+κs`b_ GZ-.i0Lİ'2i `0bXs禶L1ZCc«=8usRg_ 6g 6΅VԀXL>+'xͮ16q#~'8zX&AWpѣ2C ?h.[`F:]0' F3y$Hl-ZJ9a2Ɲ9jxL=z' Yď-:C.κ˕2MtWs Y%@ueegF`KݣTq#Kv=|޲`\_#>-) ZdKl7H|c6;!uqr㛞eEapU"I>?n}˥vXHXCHҬ{໬py{t̪AUTZ=41V`ps9IowYE1҄`vZ>D0o D[ q#Xjqa&ea8&LmFF#ԃ9Cz`3Uq ?*p)CVzU_eyV'܅v%?5ɘjd,{UTaȓ׾mɲDGR"/1!!Jith8ڑ-^BlNZ/2H~҆r8sL{1fc4S9@.g~s!N:L|Wk OxC)?1jwUƖv5}ԿlĔĤP+#Hoڜߞjq5s^)5tf@L7 j+Ie($=kadمITvU/WniYd2*(k:J{9Z.Qϴ*زGƂ &-͉H a0+рYK%t [ys*ɕiGKQx7郰\N~oߋp)ęL%$!&GH+ a5٫n-=aZ9g`&444{ho!# N Le 'ob}QXALߪ m] 0y?3ʅV.⟹;y<-\G88q(eNqZj(Gj6?>!~mSGJnG単nzF<.p{NꖫCP2b:Im8lKJvxi% F@כ_bh4ǝ .N`ZH2PMV4.YrGH,m@' 9C("o2Z;R(~Fo皖-=S-=l/㠗v$ȸb /I 1 ryc ױXrs"7GE]p%I!{_t3ΏF#߫Gۘny+$W8wD~BR3^6R  q[OD%̜ɑ 37`y4jrW+3V *ɕ#.e f.a>FuO,0M]]uuʋ 4 \,cbX܎#~!Ybߚ9=S ^ÿ[8]1 &̕,܆[݄; &lE*Pp ո&ZJaqtJB:2p$F/q&<\Zf&g$7Hf#0"~F)bP}DjPjt 茮Fzz# `f#0C؆t)KેG\0̌Z W9 `Ta}2:u31Gpbj]ȇ'SrT@ωc4MtT*q$`:++CDu yzR40pM 87+B+Gǀ(aVpw9ŇP0ד͌!V$1#QkukwiXQ@_\KaV=,t\K0%5vb6bM&GV;~mǔlFo; @ Ԡ(G9vcJQ0\tG62ZC9Q Bvc;JQڲOi_C3CZ{XAY*Gmmwa.9Aox(oicrLsbv0'*頼5r*a$EշF4)IIJR$%)IIJR$%)IIJR$%)IIJR$%)IIJRb+08B:_rϖIENDB`chessx-1.0.0/src/gui/TextBrowserEx.h000644 001750 001750 00000001206 12223260306 020115 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef TEXTBROWSEREX_H #define TEXTBROWSEREX_H #include #include class TextBrowserEx : public QTextBrowser { Q_OBJECT public: explicit TextBrowserEx(QWidget* parent = 0) : QTextBrowser(parent) {} void setSource(const QUrl& name) { if(name.scheme().isEmpty()) { QTextBrowser::setSource(name); } } }; #endif // TEXTBROWSEREX_H chessx-1.0.0/src/gui/plaintextedit.h000644 001750 001750 00000000777 12223260306 020222 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2010 by Michal Rudolf * ****************************************************************************/ #ifndef PLAINTEXTEDIT_H #define PLAINTEXTEDIT_H #include #include class PlainTextEdit : public QPlainTextEdit { public: PlainTextEdit(QWidget* parent = 0); protected: virtual void keyPressEvent(QKeyEvent* event); }; #endif // PLAINTEXTEDIT_H chessx-1.0.0/src/database/tagvalues.h000644 001750 001750 00000007043 12223260306 020310 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2007 Marius Roets * * (C) 2007 Rico Zenklusen ccccc * * (C) 2005-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __TAGVALUES_H__ #define __TAGVALUES_H__ #include #include #include #include #include typedef quint32 TagIndex; typedef quint32 GameId; /** @ingroup Core TagValues class holds a list of integer values. The list represents all the values of a particular tag in the database. For integer values, the actual values are not stored. The reasoning is that you have to remember the index anyway, which is equivalent to remembering the actual value. For this reason request for a value at a particular index, actually returns the index. @todo */ class TagValues : public QAbstractItemModel { public: TagValues() {} virtual ~TagValues() {} /** Adds a string value to the list, quickly if cache is enabled */ virtual int add(const QString& value) { return value.toInt(); } /** Adds a integer value to the list. Integer values are not stored */ virtual int add(const int value) { return value; } /** Returns a value from the list, given the index 'index' */ virtual QString value(int index) const { return QString::number(index); } /** Returns the index of a value 'value */ virtual int indexOf(const QString& value) const { return value.toInt(); } /** Returns the number of values in the list */ virtual int count() const { return 0; } /** returns true if the list contains the string 'value' */ virtual bool contains(const QString&) { return true; } /** When cache is enabled, adding values is very quick. It uses twice as * much RAM though. Useful for adding lots of values quickly. * Remember to disable afterwards to free extra memory.*/ virtual void setCacheEnabled(const bool) {} /** Read the values for list from a data stream */ virtual void read(QDataStream&) {} /** Write the current list values to a data stream */ virtual void write(QDataStream&) {} /** Compacts tavalues with respect to the given vector where a zero * in the vector means that the corresponding tagvalue has to be * deleted. */ virtual void compact(const QVector&) {}; /** Appends value at the end of out */ virtual void appendToStream(const QString& value, QDataStream& out); /** Abstract item model functions. */ virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; virtual QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const; virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; virtual QModelIndex parent(const QModelIndex&) const; private: // Contains no data }; #endif chessx-1.0.0/data/images/button_last.png000644 001750 001750 00000017371 12141003207 021032 0ustar00niklasniklas000000 000000 PNG  IHDR>a$iCCPICC Profile8UoT>oR? XGůUS[IJ*$:7鶪O{7@Hkk?<kktq݋m6nƶد-mR;`zv x#=\% oYRڱ#&?>ҹЪn_;j;$}*}+(}'}/LtY"$].9⦅%{_a݊]hk5'SN{<_ t jM{-4%TńtY۟R6#v\喊x:'HO3^&0::m,L%3:qVE t]~Iv6Wٯ) |ʸ2]G4(6w‹$"AEv m[D;Vh[}چN|3HS:KtxU'D;77;_"e?Yqxl+diTXtXML:com.adobe.xmp Adobe ImageReady z IDATx] Օ>f` " (>E` Fqu50h1&^D讫5%˧>>>w|JDOhȠKsnխG 5Uu{={mA$(+z$9 (`K`W` /Xy a.a^(`K`W`9\csnY1' !Ut AJ´m$DIjK=s4ϣD:x*~ ~e5q\ЄMamz8D@nE5U]pɚcˇq%P>ϴ8m6a$Q}Qh; vZFR!FDDitōZ^ZΫ%1*rH#NNDZ9N%eϬm- 폲sOlpHBËEɟ;ί\^.N3S`Sb)zG:Bh&LdcJ-=P!n 6텞~)@荄m}[ע5bK".(G>o0 4eL0س Dٯ<1x%z`ܴ RtA|,w C7ehF|ws9 fR'W¼-K#~t}L 3IpFdf]yg'^ 5DArn[t;H.+6PVqmM(y O-~8Nr >|ho!/ֽhn %s tOY%ns8 {lvvۚ:1*O HؖHRHl~5I3ы[&8(1/|?@CqIܫɯ;&k#%Ѡ%]tN:[W$|cjA [(B߈ Jqs kg-J5~o~Õvlg~;|}~:%OQ~DyE?jd%ŰC)v\VHd0N!1L!zgX*9#. ׋\ڏF{|rʋDu|_q1r 𧳪q)TN9_n>4I7f0K8$oZFm%hKe#Dӏ9\ x77-^uixzВ2/3|GYl.0Zf|`gKU,[_[%)Z@_8–y-eW;N6L<HgI#5Lrwet ꙵ}zY: D]x:! o~k&EUPRbK#eV8R,/aJրJD ,XWYU8~l BNTGa{ pv3X>>;zP"wo42QgQA>e!Vp U$k$`I :Bw64!ؼ@GxxnxBi?mL=|%h@e9$-ed-+fVR|~?fFS6_^g|hIXB45M:F֒'F! 3~]DQi9E1ɚdΟ9[Qqj`/|1@ kp[V/փO):xJ 7'+_O><=)L^V'@ss@m6g>c{ ;AGVWI{8!3$s+^D\5R̾x*ldc~Ku* \¦Ƒ8v "=t!%%:R*I}lqYG}j韚Sk*&sLϨr`L3C%6rAV0#_01lb$\DF J&1XLT'08}B!H.e_zY dK;3MӰT::2oJTkV^IM\mQ;cZK.vbSZJ*w2R˧J(AVu /+ KlHLx*w2(Vulv? VЧ228ug M0>F3y 97)oYfيy Jlِ. JRyL$Q b#I&-I-h/Y&_ZI̵LȆ|A֖[CsGӭlrzTL",h\4 14HĐ Sj/jx=~b[Aʰ^UӒ3sg'dq3L e ez^vDZRw݋e- hz,2(he2肧q6 =[lr*6ԉ*p//f1A6%M:ި +t;R{ȟ=BfBxQxLX^6X|`|F\LR¾aO$6Nr $h^Y=yd;Omd˾Q)SOd{6oz6E3X'Rc<)#צ G{i&ב+)3]]lUXF$'%) +y{EJQԏud1@KB\1;nynChq f Λ~F~rBYO욶T(FNg)an(`P1_s/wԙ2ʰ$ HKp`W 3F7+P,ڵsڌKWhŽ((2aV=EN@`ŏf$3dQ"kȞ6i)gɒ+L> Mh^^V ھmX@#UGH7x1GXI=J(k$KoVw "b| OO?^>κ vƓ>ma)3%Ai+N_9!+@[Y%L',rxwN)3n=}ݭSfR=70l b)+dUtrj}Ŭk.G3:&˒&~vpH+dRձS+,)ND}_ jD:<=,W8'&5 %xdq WϿn͊}L9ڸ@P7i2XnޘeO ]f![[!'E|(CXh rZe3*1(z}WL*]EBQXψ Bc&ZQ >9BH*nj|BL&d e `uց/B}>M?bF@@6!1 p p P O$ӟ ϩfDbB||4/{'B*8&E{.& V+&$!} Z'J>WZu)?"0sWYUAA|}O(2>@֔O$ "H S]SB铥YU> >2{5_@3%3>.|h?/[N@e6f v)h"^:t6. jl:N; zRg?mSw|oh& (q8Q>?NOUc!(մ3:tm$G[T6g! 8ϗ5#-v+Dh㨊%8Ҁ<0R'xXE6 veN,^JO*oz 6Q\Q\qum=o~A-í፼ntYp!*Ɖ#1=*"h ;WC x'OyC kgX6G4sZ\nypHw5~qpF Հ]pG\G+y^1;E}lq5G-RcQʱΝVa-+H`:a ҏ=_sѼ;M 5yMxyvՂS6vTἂsv`{ІџR/| ] e >\P(^NU`/+۩` e{o;lW `m^*앿 ]2Pz^lo9IENDB`chessx-1.0.0/data/images/filter_reset.png000644 001750 001750 00000027414 12142254551 021175 0ustar00niklasniklas000000 000000 PNG  IHDR>a CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs  tIME!&w IDATx}yUۻx $&LBE׶>m^Z{xvh"I@+6 SB”22{?p6dګ:UСuCP:ԡuCP:ԡuC:ĉ X9tV ~X '3fxYDWP(s)` U8TP( ۿmXm",o,wtߍ˧I'[ٳOu]x!,!Dr@JRQĀf 6[3lҪWk-Fv$r]=0u<鈓rs );MHg: ˀ(XckFhu^9 b(? B7^ZKz1]r<{K& r@H,D`FYf`k6``t#V*|)`AǾq/a 6'9`.0ȹyL_[}ǟΏf.uD海|]|\\>e2mc0!aB&DR !HJ `El/[?W|cOU*37v$qq\vr+&ӏ= |VO'Oy⓺>g],Zer '.1l1(`"@"!!$AGJvH`QXGPIJ-Ngw?Л?v0ፗ,L~i <÷к;?;̣xOOWb=bqjP) аicZ[(vIުh0?M ؑ=%B|ԫT/&n^sؒo>x3䂽C7dc0Ǝxuyws-÷w\sTWWBS}=ݧuwA=ZZkE"XLnvfSk-0@!:6qqHZQ2rTUFo vfn<ױGLOS:/Kvs)[;;oB!bzgvB8#VuE~҆8e 퍱)H,t! ׂ-Bi%-s5lN Hr\-G~k)kdNjx\`'22`@/AZ볈Hy_ӥ Zy\~MU]u~oOWw/gXUs92` X-ÂsJa^X 03" e "`/)qϩԎ=|%G)L^vwZSBDO_:H ) !XƖ~.{sYs:u Wꅯ)E6DynnH$IO"NA঱‰TI`'9kޑ/?x50?|E;w!/z#@rYȻd p^o~y8}罣P}#SNq ]EK!UXARH4&)MI•;ב+q%!yҐB$0rYWr' 6=2x/ۿʯt$@s" J)H;_FD>_xb/z{;uJ?r^}rNx22*=1$KB)e?0lch  Wp\HGJ9:VhcHMkQ32Ћ( Ǟ-g.{t.Sņ#%^{H tiӦxB7>H9Q!av\Cw'pCD0:!F֪`*p`^I7^&"!:LZ6)Z洃bwQjqO!Wf#@+m~9>x  CXbwYYXՃJ@fl$e̿!*XBGUKq}x MTĈi-}9^~zk|BWOB>A=TP4Fk~xM ΉgƗ}W ņ##B$Drݝ|5` Q a*!)#2ui'x" @ & 2U|M2X}˄h!dȓ`#*;FuV6?ت>`[rV]3řc7k[èk;hmm+S>ma``JrR @[F]{gڻWÖ|tC1Д@APڢ\&9KԯWH Qqau>bˆЊ{5dNg>V|$$&+>`uTx.RWP*1Ecm);/z+x3zNG@~ꮇAgCH"X06M^$霖Gxq\q&BXCObtM`| ~$9j ㅛ&?E);'၎:|_J72Gs97SS$XX6ψbWNϑu q8/]40m 4 ]bqu&FPGsMmhGR_:L8s^}j^=7ds38Ŀ=9L+yg2s5CF. gzsF l؛v]ClR}͸~+s\=uAl6W-Ӌ@sjKPKM=WʣW_*}XkFBK\A.)1[68v=M,e n7V?s\-EA~eЊV!fkݳ3??quKZ=8QW@6ua`wSפּ\+O/R淏|A i=Dž @E>X6QvJ|3W0|45aA ו5 L_z]ݩ:-JdbRH)%k*Qy6#ޣ'<^n_N:4A Y)XJR "e ~ t9x0c걏~c͘Q\%+t™ޣK&e'8szO=)x@:t9FelO%S;lkhXNF h|fXky㓏Yn k 6L`PHc_ otKG:+F_zu 'd$bW l^ƃp6Mt+9wdu\I VN,AhB%&xO1PknjIR:G!| @2\msl9X k{^yw[R6/Ec( ĖPr&MsR&Yh's CIOO=M;ָíۛ$8QM(O  x':}=b鑎D1<\>uS]@{ړ9]4%R ǹ:mn-tg3tx{Ibh VO+; Y1} yxuY_! =S?GS^ꍄ:'+]ѭfus_u]l'kޫ}O}֤MM `9`9讂3sJUax Z6A|U `3lٚY0X,YXH0'5JX)`1H#AF$H&[8J@ ۍM i}f,jN =kL[NJ-8V A@drldJ6<[Tv_Y{˟[{N "6M5T #MW vcwr0Qq: ڴ,xp ]v%n'`0ڀXUP%ˤN>:rP)ycv>3;G}T_8v8*jqds!ɴX!q`B v#ąLq\ u.PJAdFԢ0Ƥ-6eh*"7~!>H-'`GC?0+oySkecҕH2]ӂ w^3!Ssl8N 4r̪M˨I4WL!'@Lw4w<AJ̏&finkLVH k[gsqƼNukO$O>~qܳ8Rm}hխ'M*HJk(6a4+$`9yflІIBF2z 2r>n2ׅ\^ƃyxdd3r9d2la! A0 F!0BLjJ)*ND"-iHDcRݟ8-ئTak@rܓKZ~Iki7r'10?=%ƄW yG߫ɫs#DS&'M]i6a4ml{kn&g']Rȧme?)`~Ց+ܱ҈_}y_qWxK.c[7/]G?znѻ/^ JHZ ZPukB :NM&o{ an_+vIMv.!mFut41`k; Y}b>=/KԅSc53PRcvdd' M# p:+Ƙ,\p~}tPQZwk~tT) 'GuSWt~WfYQc'MTy]V^AV WN:uՁz=Ӊ4~?X)=+_zdVY^ _m9JIU]秢\"W]?s۹p)Q>׷?n Xx\p^c)@ gNBƂff ,7-Q.\ooq&wGG1Rʃ4clcZ{… k.ƑQ`8"UhQxP3\l z0Fڧ}{zM9hEm:_kv-]h%… 7(m~R+ }l \^~Vu-Z,7háU̷Ƅ֘GFF؍7ު*q{ LZ-mZ#}pFBVQp17#}FkRwkmp嗏8N? H>IDATF`?FrQ-d^gŋz?aFQpe8 h%yDZ W_Na~L6a߯_k[8B37bim(:^_F6,XV*keZjIf4-8 mGQ]wHpM7Շ}ZJ)k2ӑo 8R}`ppj?תo=+VNj-[X `+ Ri|]4GRi+W޼|raA=eebۥr(X3fGk ߯#j].p[Kc׏ԣ3؝|AS ^(.M; _븞yNZ pzP,y#D!Ĥi`Zd.6M}Ej&J?x΃[mcccWI c, @VCT##qT*J&&JXkvXw@3W(0LC0h44c{TZ]~caL>ёRFqmT&VK㘗)o0/^ܙg>sJR^_7:ԡuCP:ԡuCP:ԡE?IENDB`chessx-1.0.0/data/help/about5.html000644 001750 001750 00000104103 12076544175 017551 0ustar00niklasniklas000000 000000 ChessX Copyright Info

Stockfish License


GNU GENERAL PUBLIC LICENSE

Version 3, 29 June 2007

Copyright © 2007 Free Software Foundation, Inc. <http://fsf.org/>

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

chessx-1.0.0/data/images/folder_txt.png000644 001750 001750 00000005237 12077036777 020676 0ustar00niklasniklas000000 000000 PNG  IHDRiCCPICC Profile(UoT?o\?US[IB*unS6mUo xB ISA$=t@hpS]Ƹ9w>5@WI`]5;V! A'@{N\..ƅG_!7suV$BlW=}i; F)A<.&Xax,38S(b׵*%31l #O-zQvaXOP5o6Zz&⻏^wkI/#&\%x/@{7S މjPh͔&mry>k7=ߪB#@fs_{덱п0-LZ~%Gpˈ{YXf^+_s-T>D@קƸ-9!r[2]3BcnCs?>*ԮeD|%4` :X2 pQSLPRaeyqĘ י5Fit )CdL$o$rpӶb>4+̹F_{Яki+x.+B.{L<۩ =UHcnf<>F ^e||pyv%b:iX'%8Iߔ? rw[vITVQN^dpYI"|#\cz[2M^S0[zIJ/HHȟ- Ic www.inkscape.org 4IDAT8YlU/tڊ 4e)K C,  b 1D Ѹ^U"Kb"Q\IZe (k[ m_>/Jq]=9""ߚ1s>hYf? Św0_Mtڵ 4V+tQE?l#D{gM(F4'? uD/ڳvo]j'ޗvN?뚰E' ~g sM*ڽbcIl޳ӍJ/in窌99ƥJS#xsm1fj &&ggQ!ngvCJMd\= _#$܈VybG_;r0 a^^%0{>AMT &*feܢgԨuBuNiYb6z72rYr979gj| |pg 'aa4-[,*F@0 OF3.d~D8dfHҴ/qI{#bK KaDAp $sW 4lZe뙔MhB})eQV,xd9`CEDuz9q|`|L}Zz擟B4[]bG7$1I3*ʉ1H-4rѿI)]-"c>(CtU8 `OX.ۨ#GeoXN;{N%[Z)DF { # @y3`u-!Jn /)#$6@Yzz&/ 1'{'{C9H8)钣Rj2iANR`uUݝׯ$1)^i͆ hIENDB`chessx-1.0.0/data/images/forward.png000644 001750 001750 00000001614 10622422464 020145 0ustar00niklasniklas000000 000000 PNG  IHDR szzgAMAOX2tEXtSoftwareAdobe ImageReadyqe<IDATXYHTQF`mYQI&FRPhPd"3.RRFOeA %eYRM3J9c i#40{;ܙs~{2*/"3.ͧV8H` loDt7lzrJΖ \U .5 }czbCVfU %&?ޅL61CH L@i*u 5s / @Qd#P.&{ , %xM;%&J+oMwh#MU7ݨ <$3J/1Gx pR 1;9@1O) \bMO"zXW}/PFpExI=jqO^MEN%-oL5O]atEXtSoftwareAdobe ImageReadyqe</>IDATx} |Ty&3$% aIXEE.]OFDE?~mmm[jp պ%XZDA&@d2dܷdf2B!./3~=\8oc"!"iDZ"-B!H@E "iu_4(^bo9X,aer9e2c)E©yzhZt,:;f'. n7x<8~?@äS>= .e}} >\;)RNk'&(Q3ҋ6sӹGCC%`E_L`0N©خ^_. Q |[Js;EO<_Tg.\0?-UE/{-/czEw}'|FbV]?׻ *(O[c)H0LZTo/x(0p {1p:ի,xD;a90c#HŤYȫ|5jjp2,G8P FlgF115./{&72ְ>d(nwp{ƲxH8L9f⼌5rv_ܲe+#r7/ˋjp^1"! x~1::qh *Z%+[sQg\Ģ׏s~$_͠-H7z#2Aur5q8H6Jv+,\sIoV%5,Z7!1CwԙAq<9H8/ ~Fw%@ew CGh/E25HiyoiE8#95<1!&]AVx8EHKkb}RQKt=ˠ7Kr=$;Qckׄ}- l::g.#"X^3P x'``2$ۋ/s}o-ǃtL{N"v=E>>UFZ.%  h5rnJTbx1Q >LM Q[ ߶JE.n~ڡjHH,6h ôjB*,v$$WaȘg=ԝaמ<+8ѣdso~~) vpQ1J94;=PiqرcR豺(EfpE;w wLOt?p?]8E #uY*]KjrtmP̣u#y:~$B8xZʱy|Scid`qĎrJ%y.7X cd¤\})x}wV0|P `ꉁ/YVSC ">ߖBE%Co-Dt/^|^bJaJ$E=oG&Rmk?kiL" f2 }'G _|ЈoP aDK{kkh\NbS*Aگ-x<1шmWF>m۶Rax?KMIbE*D ,Aw4]io6B-`q*a4Qj  ($Au<ś?ϛƿ.Hӹh7"#p_/%a!9)X7Z' F 1(:s:찶m8> xIFl7?:r1&_2l&H/*ƸVrW/#PGȕ+9"2$h@NaaW{*~$~~K0~B8Q#GR)f&\ -$!!023;=yv7|luy|\1Q%TwFkrF( G_W_MIT [`)9S|*7AeJҨ >J*b[,TGfa1I~W=aÆ~wKRHZ|4XmmTG)smX QjV1J ueuVTgsgX9X[8 8"& B./jAKZt9E.#ҐJLx \>B\9-ӎƌ劉1P@9Fzm>9P'F)b)b'ǝ~ J12ɏFA mn`/yYRUW])q~IIYod-^|+=t:rh - @c"1|R~nhtx{yC#zߋ~ ;o `#GFKSs31N4$_ep<[&N9R (/dZ֍\d<3´p* Ϻ;Pw.N7 Mu¡0t{?!7Xz6g$nu10ꠡNSDZa.TpP?P"N~CEna}LJm<=EnлZT%[cɾ~o %p'q8,2j%j]&zD(s  M }t<0%لnuSu+e{˺MZ0)gL\=78Iͣo/&z r~p 'dAG9G2!t%y Fhjj|~L/lIi8$9'K4Y*'4@:er G|^7ւ~6 OM\9L{uGn_3A GOҨF8.n7_H4JKjң2Q-78!2z,#^~R&X"?޳C!C[fw:eՄh,X#VҟK4/4V'jy^RL)% crtjhr!`k2mmTk;Q*/ƟR}[PaX ƥ n9AlvbmNgq j|j9!DWKgK f$w7v@ D@8٬3y4E>&bma}o- fpA OͫD>VyI}G GO8`BP".#t`%떩(庈{X)'ylM`oB qitn?k"_L#~b,וYTCaV.ibxHԪCMK7ƻK?lUUtҥŖ(Y`G9bu`=240{H04vm3A,vu1hqAYƬq)^]cg, vL_Ǝ"ܐ鈐h%D:bB I28Aɣ` NuHaN)7"vsA i?ǿߠ ) 3z{C4O.P` pBC% nHh:X^b312%Y Jy_ɑU\!Im$.hx\ؐ)ҩR^3(uAl5dsi=z _8r)"ͯ6A Ad򤙁j08>ⷺ UA%`G:h9RX݄bp i8uvTB4n '|p08">&p̑r8cõ1tE\KfֺrUln Xӈ^qR U\0 a5%-muDazd֮D!AA{3PZg'9(­Dq޾;d;OWLWVݽ͂@F Ebҹ*~x XƎk_+xcba@9AN h04)ؐU.QXMic8vf`+`~< /[7_:qPCM̷컝Ͼ]Hz XaDrjXh9LtR5Jp*4`dJ2H~NK Së2-8?"?Q -<| ySիbBN\;>,@~$xD8D_,"]ll EXL8K9Qlx{Gt+^c'sQDq3"vU 7t>%24*Z4,1 xvb$!QWCcZs黭SOL#A~QOQ``(2:ظ| Sb Q]g?.TF'Q @Xdߑj(8 [S61A/'(u6;%;E *-̀UJʺV8>6$E۽ f c(Qܴ2̋(5p9NTQ$ 9n"F(yt̛47'Jz#sf3:RK Ҋ4` NM~>3ғ 3a{FWmANGR6<dAp8]:$kY>#o#j JWQhSoNHׄ,f`;zwP"[Q}œh\J?hc29FD.76BMN4-&\9=l4+rr ar>ҤM4E%e _ltTNӓ-N3~^t,>kVhՀ"S@M*(^{ p1Q&S&nhG@C H )xAn]Etbwpilh(-??'\-r*އ}d#`L@ ȉoCO1 ޿\(!>8Hcc Ao36o ՗̢ĆF7',0lelC~,2w=E!HPB&wkZ%U_ ߜC,I?!p+_}k˾S@k(AY\¹Yi֖Tb!J+fK5]6[L`}䚣Cr!# {[x=cL"zv'; f=)Ëpfťxb>ɀ7y~)`{k»c$NAoҌM=| GvtAEH':ٔ D}PNO|},?78\ 9m ƣ ͚Z!jD]jaLݥ BȐף!<}؈B7L pp`pIҪW=\~ߊh X_- 9\xs49BK\tݥNm3qbGBwrQ z pRL<| c;ۛ n9 cgե6ZۚuDiEOQ ~+p< uJYP0VQT9y'^]WXwrJYuHh͘8g0^i]_bRgO$;d.=j),z4_zE@Ҵy'"]Ej(jS@ -6=5fb٣Dw@BF[@I:8Yв:źL*%i/.G@XqĐRt1劋(ra(#j"Z7¡todJ6>-4+Fr"R#N&gD)3b <~t8pL8l3ƘzJG _rwvZ^~`b!H'ͭEfATv`%g,]I+{s\YOj^]Ĉr}]+eA2.?dR!\1y4؛ \%*ZXxxnа[f9-{o:z-נq%g=Gpϻ· hNP0_u?E>JH wEElٲ[C32@(bv5/42j=dݑl*{guO-vti0qϾFn: XsE41,ķ?T]v0,;*HT0wL2\6u,LA^Bn,i{0>biR]^" qM5pߵp5b%p=ʘD#y -;G[DO0޼+faӡzJ ol\>>:O{hȩ/ ic GClAuc M7Qb8:r'"> bUr٩0HHH`z.ENee% "]I?}9^B~7R3Ks [e"TQ1iYѶpl)/[p,J&}FEnc)Q#3Ctjbq Dn%@86rccuKF߾,Ъ_`Ƶ:ݚϡ%` .̡B DbVSN44zo/ 1 (EN64_n%ϾwS%;:'{sa, ʁ%q\o~왩 1E4Z{l]el|ZDDLab=Yv8jX)l3wtDݕ MbZG;க׾ʛV)sA7* bx&3Œtd鏾;5wI&3w=W)'$Au}NT 7&b t#n~)|fI/031\f@eH /V~m:Mb3'\7V3@ɜ?#E#wttʠ GM֔\?=͠&| H 'zUqI`C%"r HT|v"ΣW.M Ө9g#?T]^. Ǜ_rJ#QF&s&t,GNk*1D:k4PKq=pXJ;eMhtUD}weG6ol -fDM: 8?L .:) v .}XZ W;2&\c"kM<[h0 t/O.^Ο CGvV;*HPòhȚ]p_`r*khr\}Iِ0m>>ZXNgSI2TΠ$Dp #>vz1%H4 kU|ҐZ~:T}kΨh"gI˛4|y)=6JkZ*i3 %8GgX{uLZo~^U1'uOttaP8; E6H9*C &p,&qIG]|D[E4J$J%wUaJJhaC)Z_) >CK#lCu| ȕ f Ԃ;q4|l]zJx -ssj\@x`x6xɂS҆RAX:vc\!A 'n{]fǾz} d"_z=_+@H NDŹ5)+LWM{mG;f FL[۽^XAM I~ 1A+_'؋(a[19!ɸn!%t</ae!=uw²?IO~yR<{  3D`pB98d"pߎ!R{@+U}Vzt09\V-$n5d*Aaʁ6'8@;eqp=WpNuQ~aw^Ddk b8UbET\qM4hԵD#;_Y>PVH6`-HppP7E5 hN7 2>ۈ[zlq2` Pr4&WpsaIOH"aɇx6>ֻk.'/`^nj ٸY6F0!Ba8>yѰo떩ٳfwS,ۣ l ۦVG7Dࣇ+Dx@׽} H?(Pw`pBd΀߃""FE h>@~H` kmb?KϨ2 Dsai܀G( _ra 7 i< skri_V# X>_1gE3RIJA 2vl<Ǐz ûv r@.GFH|bJ6 |H!mՋX#l$*@loJqycNYP9S&>_&;LjtKh9$M2@y7/J4*ntw)*NM8r F1e }̊DKS `\ &I"8ub+[a[ro&0I0c=ջ,g6)t3}İj0=\ 1D-Pl>1x%`0lj_B( X@[g ^XLw֎_vg1sn{YFk/8,'0 Oȥ{7-ؠP@?zLz>K Z(^^e*ZkTXmkDĖ%+T꾹ttO}JM(y^/q2(X=2\kw,cMPDY$q0o'ו*s$ŌR&M=ssB\F# g JTULAoq&,ICF>rYU 'J|6q۴/zG*@,\2o.@AD3,W劾Oi%O ~ Ef-vb0iY%t84 5/|! Kj Ο!D B!H@E "iDZ"-B!H@ 07x_IENDB`chessx-1.0.0/data/help/about0.html000644 001750 001750 00000006020 12076544175 017543 0ustar00niklasniklas000000 000000 About ChessX

ChessX Basics

Summary

ChessX is an Open Source chess database. With ChessX you can operate on your collection of chess games in many ways:
browse, edit, add, organize, analyze, etc.

ChessX is cross-platform. It works on Windows, Linux and Mac OS X.

Current Features

  • Multi-platform. Supports Windows, Linux and Mac OS X
  • Load and save PGN files
  • Work with multiple databases simultaneously
  • Browse games, including variations
  • Enter moves, variations, comments
  • Setup board, copy/paste FEN
  • Search header (click on columns in GameList header)
  • Display opening tree for current position
  • Analyze using UCI and Winboard/Xboard Chess engines

Planned Features

  • Perform advanced search (board, header, material)
  • Store games in native binary format
  • Fix spelling
  • Play/train against engine
  • Calculate ELO performance

Development

The code uses the Qt library. To develop, you need Qt 4.8.1 or later. SVN is used to manage development and SourceForge Tracker to keep track of bug reports and feature requests. All classes are documented using Doxygen.

For a long time, ChessX was pushed forward by Michal Rudolf.

Currently, there are two active ChessX developers: James Coons and current maintainer Jens Nissen. The main tester and usability expert is Bruno Rizzuti.

Among inactive developers we would like to mention Marius Roets, Sean Estabrooks, Rico Zenklusen, William Hoggarth and Ejner Borgbjerg who wrote significant parts of code. Heinz Hopfgartner made useful tests and maintained Mac port.

If you wish to participate in the project (either as a developer or a tester), please sign up to the developer mailing list and introduce yourself.

chessx-1.0.0/data/images/accessories_text_editor.png000644 001750 001750 00000021502 12141255204 023406 0ustar00niklasniklas000000 000000 PNG  IHDR>atIME "?bKGD"IDATx |՝#Y%Ĺ4)@ | M]fXnBhZRh G I @sv.߷,f7%[~όF43xxo&}R6Te魷ު _۰7K.U$y\c]6fM BqV!O|"vbIpN]Y-uYh C%C^=/CЅ 쯠XdǸVZe8s+f*Y(N'"\XV%)$·mW;֢w89.k㎮1 RqʠbŝWZn%!4ePyL&>[0F@KC .3L<^..ۀTqq+ ,زeKeCi-MU%Ll 8JVK%(,IٗwuAoo.p2wI8>O؟Aԥ^zĝcڑ;yXjNn:'疬@|֑L?/oŋ76ذa3QE-Reբ֊@ yÖNržEh4xWOТn1c rǙZp @HǗxwQ$m,{8_RRƚelwc U+3ܱ8Zs:Dba֬YM.a_!xul̖>q"Hh|gp/jYiӦYշ+* DAgφl)闲 CƒH=D,/ e,Jd//C"N6{ iPY:Kʙ8?A*ST+P8ٙu^ (8FEb@__8N~nQ:6ޣ!":w^oݛ0+8WBKFOe޶66χx d݉ H%9lZ-`%irU܀[7.//gPHPP֧-9:R#K?q>wbXZZ\pS\ [n.\НcET""Kohh`IJ9 fc%b7~Lp1v\78o3NN Y 5@>q8\ކ޷ "xcǍpdxΖpfKj]xKxLhټ_ ~rõYyNaH7Oc=>{31Khw5@Q*@1!:=Bkq @\P+f7xGMڋ>C@AoF`q¤p&bFF_UCoسB3^ F% |6ő o] |TA u gyE]6hv:b7ѭY lZs UV*hoa;ߏ x TY Z LA!@f/S`931 pp~8x߃frZ&œk׀TV?poR+QP uAv9 -Z428pq 2w;!`0㣀$yW_sy!AxtP{P=G A a'=9whCxDZ}_c-J8Z_^q·wϠ  ] !E̶CicG>팇O22nPV> !G1~ guQ͔=@,oAS_gMR8x;&xbp &BRt"/k -O_YpL^t+BtC |Bs!ŋ#Ss$LEo!AF%AD~tOX9 bpAS\/0 8_ *`8 ^x%/!<.Q>HͿ&,F7===s>p̻:< /@w*p"h(-17,l~0gAI-`+4t WB`F~  ?|.5(a;^/_:a6~ yy*@d"͂nYa`tVy1vNE =gZY§_$¯S#B8C6f"!PaObm@ԏ }`COu\a]|ڮ; xZH̛ͬO1 cp֍ `߷A٦?S=oG= #l{:.*s2v rPw\^=89j8s= o0OlQR3),k~%:$ 7VfAw"tm!ntO͹ C~)'oDw3)|腺@@p@H@y>T>Yؒ8⼸|`:h0*cA%)a˷ z=xs{9#I>0|R]{߀g2R?(ncpCy>S .P)\CѠ -xwϗ| *JqpɮLtϣk)7wj#{"ssS'tϱ> W#OUT,2l|ֻ`w N~e XcEɀ2E UTiOSӋ}bC`*+%|~|($b["W lS>#)ّ҅P%5( A*_I) `0X阏?qX&r`Ί6B~{*#! ٍ(:cPsrp(S&*f&ٔ$-O MAlFh9=R!{xο_qb$[SMTw:Wߊ ~_"T8;q?^,?釆m`&u ۫:Fjߥri;%8C[A޴#Yw,Ϗt.Zʫ<.KÌc BKn*ߵ:_N=@Vn` Y>?n~yM"HT[>?B_/28 vi=ۗٙ#tK?ͺZ9Ig| 6P?󳡎s8Ow ;C(}F{2 _8~_XŸ6fZN'x6I ï^ȫN@˿j_zn|%\Λ兠L(rЉ)/z~ 7(Y//VLNj{p'`KW%0s|rfDÿAk<@0 я8uwN?/~ؕ =`Tn *|?Oֆ#WF /+/!ٷ/wE7݋hoؾ z:VJ(YOУy/,Z3 {7VF}3o?oi)mMExY%\TB@A"7ߥ¯POv/ܕuІpwW7>y9߷yd෉?O<M !IwWg+~%Ee.oˡt隤ZΏPПu@uڹZ 8yanUCf[ʣwgm;: 0P[?@lhd)SYί$HNojP᳡^,s`Jg*{qd˾TP_e ~tz=eu=YVw' [.o)%({S>s)(oW)C8#rTO{Ps?'8Ƈ_b!o'w}qeeP zxa 8< o$oLO_"3 Jv['0 AY6v` +gd|Y)m'|E8`Ҝ Jpϱߺcϕ|t_ۯ3RK0DI 8eh"5 Q)y6? 3 ַR0o8;>Ё?;p>/ P \( 1˳;%~%)?2Aiq҇HQg/4MפGQP7 o\ t::::ؼZlYW/7J/Q?wvѩ@:4ϵ|y7з*bWCL ^#PW y\`rlK __ k<\y[>^5x{ˣb Z{PgPuAˬj\4uVAcU PK"/y erZɌ|<޼ n.rEʊG|k.|RK Ss,7*X޹v:TlT2|7ה=@*_S{#);:ԸIG;^KM/W>%3t$ڦXcyx"PCE rn̄WH(:HMyToўp'\Q?ԟ׊b~` T7{/!T:3&X\,Z,^@FWjx@&I nxZaY|}-{|)w:tǧ`D/0G 'E|,~-&H1xxźg :?f9j\C1eXD =0Q~/ e\p a̗cyȃTY*|.h/F/9`(5RW#}ƍ{S@ M+t @555lƈg peӿ b<;+ P?T.faf;.9g0*XD,MM<000PGrZgaHnT$m1znn.봌66:~\;,Ea/p/~HJ9MJO9>$n,>^WHob]J8`@z{bֱ~FP<_r:kJcU _rG#(W0\X D_)sR׃>^iz2!--- q_NVկBz*..>7tاMQ#*hQ=z7>2Y0rsA$l <`tul? ߔDz}t5R-X^2Gx2=^>4>|80V~R<$P˩NM1`V0 .̽+&UUUMAK})s9,#J |]4zI$ʊ %",Cg>/{g0?*xi23+,Rɛ{%K(y1-^2Z[#SgUh@Jpp@t'ZYĔCgDW!IbŴ ÈХCt ֗1BrYD[r!𳟽A@~o =Co B׉>>x#`߾}]S QyUVU8Q^ B3ju1h$ z\ bX35V0E5rj 'XoWb2bqM ."8| ΚcW{\ޱ ]C=8qX#Brq2Zs` TT_z뮻Ϊ-//bEQdU ?jG]~bX=12pWWW0qjLL(5v|NRo/{67 =H/zO@GkhP~C謓^[֊@>u*gy-աm̚5ˌP]]=hIT~uק=ĔL{{{S:m9)y!+\yGk!̨RS<M~$w vg} b!{U8k|СU!-[V|f23eOR:QރSDj?"MJwEO3 ?.`=-akͰK`~{t7ZaS.Y z`INbY,A3|w]T|^1Ӑ8PYD;lO-vȆ~[heOk9w@%UU'AA*!-[1d &(<2lN@l {z`+aGᘚqnaާSJ4 ^J-ZȩZ2"mMnN\#_k7^ EhJJ\"d^Vlo$2IENDB`chessx-1.0.0/data/themes/boards/mahogony.png000644 001750 001750 00000301220 12024673325 021612 0ustar00niklasniklas000000 000000 PNG  IHDR@;w AiCCPICC ProfileH wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~@IDATxDْ#ɒgLY{sDoW/yOv2oYD5"pjj|_^_\udzoH19$ShƼ]E_?^^7gt&_v5?vy ~_wڔo|[",q({q5x ?"`!`f3Ma}  n];X1Xƾh;GgtxN!ZpR{Rp }v}xd>a՛bs'.5.5|$ ߡx%;_??j :6xqF %Wb\p~ ~Ӈ0>Fn,^Ӆ{/IѦpJ|%[3 }\+3k:G[>w{Ħ}!{‡ CA(Ndg#Sys5A`0!ta1QuU7t1Z8])CkʃyK nt-Ej4EE4jO< Lo_b>)3FxGt؁?G+ڗ*+C=*4bm7KR8~1ž/=lڥ0Z5_ t:K §λη`< K+Pk4QD?/h,ԨWL:xwJQ#KtÞ{pv-&CܻWjq%:F:S@/ S0l DQRɬ[8d<@ݣ3N S^J>2ьPqw>YEUXAkw<V1QHٗR(hF9y}<+a^9BT*d/UAhśw<՞U LF=S$F!יD\*ɭ^Ʋ3"ԕ,QP\sC:kǠYƌc'apZ"VjM%O++N`@/3OJ<+ڟ_?Qx$$fCx[pYC53{{bMB)x/|u|dFNdBki`@dyۡ/<[+1r,gFFj_xuC4.`rm\)\ׅ чd3nwқK雫èN<klmLa}5(pL+wg",nCєVMoI1$8H</K6o#yt>֌qH@[^0""38&pE'B҉l8+5ϛWa/gSB< r nnyz!5X[$4]E$z:Ym9 q&ph,/8+ePYSDU~X}ҍjJϫΛ9_u=GcJ[zR]nÙPMJQԀ{fǣ^j K"fo1N)H{+,j{fΌڝM0 ރ#^[qܚS)'`x10fNU9ᇆvUY<\N[BJrF8lI5tZjrHQ+%H2.%+_d|C/E/7NYL4]z0l d}K㫎{t/uƻPsw0b1'aJ3piS*4/GSEl 'ֵy>m+rsa)Y$ћ菔BvuK3)qVTQvd o=7$Co7y,+p1QvH᪷+E;D,R>9β))x!R/mUYfԷØW-awk" p͸:r#TA|VX~6^C|P𨟗}aea[s{J wFpJ ~NCvL`#ᰈUW<ݻ Y1 f>~K7sW]{N);c`\B뿙s5MqBaKГ˱sLd:~Dv>+mFãt<܈7%-oɭ9dz4S”"2W^;JW o˄rH+89Hi 9E=m+<3$JXY6U{js.:w1;H̼\#n  |lL^USG;|ENA }bbF7)eѓeTg6#v VBKjA,~p{;^!nfl՛!- 0 J$鋥/}%hƟ706 hcOxx_W^Eh^Df۵!qP-CaCA^qKnZ`Dpjx3:ptȠ',jgP'MQ3Ke.YJLq2B`Pivu ;Lf> ߢݸ3 Un%܏&M+;۫?k()pоQCut *ٍYGy_ ٴn\ة2zex}k;kI!(ٚDqܧd͘OlB&YX {p'vZG(J ъG~Ä;bWC vK6er!iij$eY)}6>0CXn>֕LϟV%mf ^>t+ w8d쫣ևLM\ަy'u8mh ~2[r§q(5i)J6~rx&Sb"`R͕HCKGSPlCo]j5RǨObx] o+7G^2bx߼(" >G,`cz/DԬkfOv\lϰ2e1&Lzn̓R@>8.N› 5Aåp8xioLy.w'J5gSFv"sY{ j#S;tV=~qfN^:<>A$tk ޜ+C6ԬvHt值vB,*>6&lgu ^h$d{ƞ1n E8˾B_|FJ{ yd}CňPFċ;6e%^;dV &@G1܍2&._R`h7f7 p"'Cǫn茥 . ')bkO ?7y)TnRz] > ޯvLv!9?p{:9ӲÃ2ha>S3`WOV~kR\+IPtBTj`&'"LxQn% `R407}k6YW8)(55S,l}n1g7M7"6qBPcNsKңuB) i ,L1X ooWp}@ׯ H1bn($xޢ@YLQ`+s?){} &O.lS:&ͳӠnCw0 >+9}IY4ПjDMm'[etHȈaS:`1yYBEB[ħf!,wA\y2]@[N% ~sn< GO1k*{ ϐ9N71n,]@aD @2b --xe3v"Ӟ`?=zէc}j-ױQ,zK?ӛ 7Q2%ɕXfnz4a%5y(1jOȧz/,rLqSy>q7`(>ZuHؐF\-t{席VQ$` \Ma,e'O픁r]EN+vR"4z{ 2mJVmVhjF,<d5S#8\o H.e('ϩX*تRm ioge$CwSOD5p^k|w[ş8^M2Ys8O#P2Eըb`FeY1#V= \S+j4ʍѷ{Q(\hU!LJ̵ٵvPG!&@f4No2JM 2%6t^K0Zdx\vdDDCrlڤȏ>מ%Qa>7q3遙1R͉u`C-o|2l]:8wsL 6TpX*`MB3PV/xޚJHY/Ӛ&~q}13FBoO2>)qIF<M[c gdϠxDXBXQM"{tEb6- Dv}dxS_c~SO+wGPEp nͳ>GP/Zcޠu63EFT OR/Uνg `, !{@^囉I18ݹ)  'sEOqLrZ•jL9|e4 c)!Ϩ.{H )=.dl C 3t.[]C/C@!~s皱>+W1~EH8TFtFoqQ9I9AnGf."%"hd#35r_xjdDؽ %f 'j:T^ߎg|(|*1[0$`3a|ɒ0KPIկD3h!ֆKuo7ՅZC!u)ntؼg@^g+Rע%̘APv/Xl+1g!r@ ]f7C7& NxOt> oP*S[ *I'S5}/m_Qfg:ؔ-6j,fK\t3WG+^lǓo:>M,GEK<)o~QtV67>&[fJX38'q;D`+X䇵˭ncb{.Ԍ~(gzmWq\O)A0IpcVfBi z`tL1W8XhmDc(G#񴦈!n7OCSNH[7'e>48 V($:|wj\M*- @|o{WXu^w ΛݒM<Rular[P xNi]mJ±"/4Aac^D)CJBo cY>xα>T*RU ,W}йb0wUmwO)'+,O nУFyҙ\ yxZ*D'įxd :v s Gt##x8fWt8]3~fpէ, b2)A$" N1f*cj;(nCB=i-m IGB7[IC kN% RHvAnyipnL3mds[֮=Ʋu)Fv0* [z+VK ~?/IQ[WR漓xCOT]LRm=2lΣϗ'Mt Q/0M5j znf\$Xaxjn-+mxPր}BsLOW5y5:RKROx@Dt~I]Ê|e6|1&!ݱe,I# k^/#\^)Xo7xakK0&tƆVi0{hX)Eaq FXۅF gy_ tn1ngBcy5Bxܓ4~L-=Y2u _ +(QؑCmJ`nWfn|6z~ɫqO{U_]DyDJ^a$rMpܔ=ϹE1b|rdOIm]m-х1_B!p8q쌓,t_Bxj6列fwBJU&AC6gٍ̪GńraHy85U}l"bS8O`#I(uʳI (c̵O.ߡRr9!@S(۾m5Av~Sٱb=VxKYOkѵ)p.p~f4cO+ 0h>S&Jzhcɣq*+l&SB^n{9viGR0yͫR( eY?7uB?IG7!8{Jc<О% nH!{<lrNC K>-FY>j) N5A]_Қ5Bx vY:c I uFU8!'b ߘrp[>vo!k {莦`2VǠAfn\x5 >4>xS.md :a7&v&Seg7x1?sfީo}2M{yyh/ }!H"T~5qs\2g+(]z8H28 ,uw!=G0vIB}']/ѷuYEi?rxx ?eV-l&^:㲳1Ofp_D> GT?{QZ7P`QCrzB\Ƭ,pb7xyIc!8;KiA0;R%f`tn u 6A.)${3L ó=A! k;y  .83Gx&ЀǸގws`)O;Od |M)F=jbOhI#.{'F6O0({pyW.rMDגo/eD҃RS`-Ӕl##7Y+A?XM>}Sd<@'0W?zƓ)tڑnPR7IR(ƳYss3 m(eO,{౮-+sۨ{\Iz)?>k$S1_~}9 R}vӒf)mnb!oLudmY)g>"(lVQQ (y+]hل څ^1 )K`9!'K+.V$Qlgn q8.ZKo՛K9ZoFK3?$Zc9A/y[|6JP,R2>Gi otw#8}j@iS4 d!#,OQwQ,W-w A/ht%O>OMҭ.XUD9 |A$q' nq>U}.Edl7zM3jED^n)+6;Ze`=*k5ӅDf} TV'z|cZU(]J/L:/Mt+ExfkV1/Q7 /OH$d ՓFS(Obg bopҸp" 8|^"C#@F;K} QS܍v|b0qޑgqf\+40ɁV$0 yq)v8y"FKHoHx9ϊ cړ4<` IG5q;e^>r-op,T?*$KH K'(?tNQ=fӔ$1#dZP9,hHPJ]|ƃڳb#Z 7%j&Qf!i>KEPyAVAw -u3ބ2%2$㚢T-?A;g?XrEc?ɓvO#6qvQ$`v 7$g RI> Xy0*83蔁r+ ]FkuػY@InF])&gt+).yhy6qѵ)p=a0L#? G%AFx<0XO&`F祟Js[-1+Ma!L@\*}.Fm1:a l~qٝ-P +V¶"apj5cƔ'^yyB}d.Dx<,޾C깧K7QS8KQytyEA2%=ؒw).~1ޖ$'] ^4;x4q\yy7N73v7##Ґf0=ýĭbk:o:\5s )6d$1(AyǯwDc'NGV(`@]w)|[}s%rMܕa-]l{+ƴm~BԄE.ܔ{ XkX78ށA,aJJ&=r)A0 [%Lh8@Nb15pI9cn? _ʆ`IK +,C"+ŌH(W;̥iGՑZ^ }`lO:NtXEsmt\#Nr6WiD05N)1 a24HИn[% yQP#/ -y'XQu=(V CĬ^~p6/†; !?OqjyrcmgR~yW SB|8T0V N=->_wU 4(FMKS3\0O.ICTMZԎ&njv[9nb) B au˕bt%An:m/KApP$bFV㝳)y*K~A h̎jcnA}amXAy8ehz钐~M劔( vGl%f+R+W^)r!@S!^ UC;۵ f1Z4t~Fu F'B ^(fᖹ_ K+6]+\Zk,0zWvkjRgmk^?U'yn ~^⬬m#H Ldآ;ri(Ͷ/mR΋/{?]]%u^hMqF]= RguPfW˻f`"Ӛ犼23cXl ;WNbZ:$e}]HhD<)HJjyĄjOؾyQKL2]Ka>!4r@xtaw7r(SX 25pB#.iAmy GEJXx1m# B]V(/V[AŖ6OB@"1+k-%ȓ> Qd>yP}V_H=X[^ uBfB?8J_.y/NsEI52?05Ƨߪ'X\ nW)rڄBJ/d8s, >vuȺ4Jm쳜r3OΩ 42*c`8=3NE&mLУ[XM ]B:~IdS&[&OBA;ePx֪OnäfA[g 8ԥ*{pRmFDo֊c ݓ `O+`dThJI ;RƲ8W3Ç.4[Yl⵼p7'B\l {;>\tO@IDAT?NRĤ!dA +tyy¼I ?6Ol_?a=&;esݽ3nw }mMѰ߼0FX[9k3=*B7A&q_6ާ κ1G3k ={9!1ªn1J?mxӛV-q jr31(۟'BKnt"G5BҪdqN Xrx' @[!! {4BzʩNN))6jb %>Xvy3-KK:tw]h5acDޢߏoSxwS^Ow i[(EHWF'#soY<",\=.vnȔYFibp3^<"Ei5nn9MT3Sm8|Si &r% -ۉ( 1RBiR3x<R9bJ0g4^w+D9/rKjQApJ` UcWf]`1Ԯ 5swzbɝ%SH^^_ +ܦoo̻O/R[fC"ʧV)G9al5PP n((Mc($PaQ8AvOOEO]SrѪ&_|qrUpJA|6&\Lycd>Hcx"qG~ijC94b#.,($07 %#P 0"YIx'J#U~sw厎fĔC)rqs n#Ċ\魛-,) Buy 4b-z-I[#5/d^~$fW]hrep<=/]iRN(JCMѤ!J BqpEypk嶷rQ^D7k +*,Myt)R-3U{~yVj˰aa=]aW!+&жuQ5I=ƝޟV5bPgǪj\}G\x~ئD$wz*CJ`J<ʅjS(3SAfczrwSC{B$Y[f~.RZOA6_JGq* @shv8odCVbp='uk6l/9r3ͽ/<:7E>5L.' 9 ^Gh h"D]n܏dלmcn<ѭ18 P85N7d,A6+]-V(4Nji;+&0H]w )+ fW İmLD$pan5#(.$1C|}B'bHam7l$m$k+Ġ-' 10 Ôw~=X|F)A|! )[1\cݹwPH:y&e@'tk}K-wML&<4;:Zl .͌&7<ҪZ9E7ţ!6p4`H]" e a^w#~ʸR!s*ɥȎ#*Z{2GQjnԿ5mWADO,9ԇ'`95]>lby ʳ/K[ї9ZѶ%dp iq꜂!I_ۇv]i?w_{S?j2pw-DڳB^#&=bb^H)rj/Oj{Є]}n2@9 E4ޞ"1<™L#3+GeL+# Ea}If^7t=k<53xCgRS&۔i^Їq*E/M(M"/V]J=+#^isrX]Q݄H`:kڅUYt>ۜᆠln!<,Q4ԁx^N<óhLX~_7>H-x '>Ju qBxO?AJ h.}&7>rn@"^NĜyw»zy*,VP:#N䓘UPMkY1s ڎ ]y7@5I[2ERt?:&< (Tܗ+S0?㓛PqӲ`8e˾"ٸY:!+5A;k2mBcZTxo6a^yj8]RfPԄwo (ᅅEb{?X.L.8MNry{kƤh< CN*jz03 vq& {B<]53?|ȘfzyD6wb\iRYg _e˖ӭS#JFSǃ4vJf" RU@q-oiW+0)`|40¬ERk~gbY8*6ǴS5r^fӧBexSv9µ|~Te =fh .XlFn[m|e&g ccǫR| Gn_nw]Jy+`ˏ:S7fK;Gf(>Jvvn:%K\遞╒o_m@IvbYy {?9YPW^ǹy4oB  6<=R L/յX5H'5`1֍B{^f @r,lP$H~˶AjGdRU'ASxȷ#^tfeS],/ig{FW#LWnÔ0`SƢB|`0m<U^kk4у?[I8:x20To6FҁL21 RB* m6 DOq;q&arVi C0p|ZS=X{*Ss[fI.gu9I&Ę3etYR<};Qjm1 `kYm7L#_crGИ]1"Ζp\80bBtmM}~t8g208|*u(R 9!acTcpMgY&X'ϔ^2B)S4_7Va2$RSXRﮞq, PK>B?<'){8ƍi_W틜] ]{k7~YWSHٶBPH.<TH?'WʬF!)\mw֬% ^\ȋ5ȄQl\op\N;ʍdLXٱ≽TW {LRTV/_S<|LBjrVHOx w;P/#WAgSlY!lo>%l=3<%K4ZWPG+奬rה Xx2x _u<0Rr"6i&k"}.W+(!O5}ysQ\iLko)2] BXYaq;Dr.wygc ) 7hڿ,ۛ%}#`R'-h6L#+LKYKƴ^h~$y2(e>Xe9CCrF _ &3Wɂ[hgヌ*c|}Q1,+n(|1axFN5Ͷ]ҨFpzkGǠ6 VT<_l^~|ّ/G-ZBѫڌ 6HaRw dy]5O*܇uYx@  7,& K/Lѿ)E3cCXO2x2 tvc'c*_JZ)h#X'z?5Oj<٪1:#x36e jZǿ-/_3;sN'&ExXNj/8),f{2mr- xb5')0 2Qbٝ8y .oK gbohϓDgB@&Zb6&ymBsc3}zSN$rmh; OE&c +BRM`7OJQC 1J`-7 z_RGu*RNCFzĈPl CTB`rEl['XgXjKWEO]r0V4~ߝR ia=9tG/1C$=mBF"@Q”=ށykKRHܑotMG*[J݅9p_:J웣hBA5 }t⣹A-ώjnp7 V;gpɫ<I}Tz>e嫝?Vݬ \=Qa^zڹoP!OؖN_,BH.7a )rB'4t{NHX >hfb(BkP{{* +%)4`Ro olϵv/ӣ0(cz?la"<@ʻY~ᩑ?Ͷϐ Q`DdE:7= E}sE-Oq@0Œby >gGs'# 3S)xSJBx?D,<˶{v 9 ̰0pS, #g9YhW<l:32p:ko2@ה6+β6#'m 'N+@6fNNOvoead4uCV?ǢEPzя5q끔F >S6+IhRs']Rm\QF;ܗyᣆq_f)$9swm@ S2DuAhѻzlMGK&&"'uʞDlj ̥<&g&&?~ L;Xn ֚COP`X'^'ӟK~|;I{fTVw(I`¬DEeyW6;F[xSLCm=aTtZ"1p{أ2rTk0D_Ar(Ǜ>"U@RF\ZuԂO~RryBpnCgx|%o9f@zWw=*2)Ѹ䋝53h`X q"$d܏ķ5~ٮZB-"$sZq\܄%=#dK\P!K=;9mMu 3-hyfшZ˸#9[4 > &$ ֽԧ1tq7I@p[x3 ³n?s|y&4Z9#zq6v3PB?›Dtdʉ2V'by <6 E`yS;k㳜_S$6eѝN쳮BZ69e e{4p1ΤL1y/[q ylla{•eW5~-j愦V), - ڟ>xV4v?SZ5 Cw8`4c Q:.J22 ZoBIRxH޻>:YE)3vDGA_ nu΄#Y:Clh +g`4E5+qna˷+mJ!q5 Cf xկ[MJ9%)B}包vdoGͪ#' T+Κ_|(4vTة \Ϳ&{lEǽu@7OPǼO7`GM;uR TD~?f2e ] 0̕6F X«ǀx`˞hZwH J-3xU?z|x04DMrZ8ܣsiTty !F­68̂0t~&!Zgq "'cv.ВR;˒#W=$3vIGCiiҩU3IFO}>Dl: }Lh#!4l i $›)V%9{k#[DXWz3>dv4[ l,)$njn}Ͷayʢ?.e1""*n)AAN$8Nڵ4kj{E%l bڭ(7(g\MYm¦dofvО E m2kԌ,I{t\IM \G;8R8 5l;δI55}g6ҦNx暼lb6dvl-!bS4UǛjJZ[eu- ![i T t}8a4we x-b`pծeߒq"ԸAMLsRBӑY|n~{J3 #,F_1,LnIl jߛKmJck 7ǵ)D -e@Sfh4ϺO  0 p,jTuOedz%RhZ}zˆ}?1&4;-wZ.\ĞEuo0b82rW9[5˸{hbeJX j`\-(8}aC>=|#bƬ#)Y~ p'h׬FL轌r?p͵z2wAvd儯qb '8#7'Ɋ|_;g1%3wwaapFI>% 6}{0~KPjp$Kl 0|2DG 9hF1;^NezH^23V;ʠu[mk 10УvvFzẆòX6N1&KZ" \BFp9QuI$ ?`l4ܹQDŽm9k\yb){u" w#6.bo+_`*c8uĄk5{ve'ekӻE+1gW(~K%\ًjB'+K(g8^ um 5c?ʿr ou'UR:|xrn-ܳFlL`ӘPg4ݰ7).!+/  N:qBjv0+C\p]@bGDqܳ"&iŕc5dV+JlXѵ;ß+'k1킟Ҳ8(6gEe`]5ئ43ƬΔlF_,XڗrM"~n)5^4k%q%qHɁzJܐ.uhsw:f6FSتAaQ2w"ɂ-lY$4\3D3ŀlw%ߤgUP{;6Lj6nq[#VsQU,b_Һ2;OfFj zjvyF'?ݍ91zW4ՖE.|5'jX#Z=*`'0ٶɘ}x_J\:4WZMR-hƋbamMpkxX{LL1K@.D:vSr^ Z=k:3q#>7E.e-Gcr)CΒyG2禼O4T$/4PGB Q+ǒ~k(J0R[|t#Re楺N6 frв*CSALz@;D<s >ncvބ( D>,!rH6@V$*r}"L^ڳ14' \2Zv3":as>YҘÈ~+يݴoܲ:8˚ZE]Bw' Q4_!)*;YL6EHso10!S;>WJgm&pw^uph4 Ѣ)|s%cXwob΃|X:t i;ԾC+P&d:tӆ)β`hqn [:͊!t_FI;@7ik9Jˬ`Z ^S_)BE0[#.~0],c"E6,pY\ 9l"\x 8_<#֬?<$fd=Jx(T'Ӗng.- $D1;A "Y+C"Rh եå떩\P\| #tkoB4-@r/}n<,$}BN۾#|J''. s]_pҕoFgQ (t :&b"~Hʎ rJ:A0/gf4lGC;^_Q#RR_} ,[!p0Gx|D2%r3,g)FlӖ\ĚDhD@MSj*RͺӲ8\!/[`wd@c 35 0$gGn[KL$XAHV7%[ LѾc-Mc8İNpl!`NPǬvͲQf4\pXz6N>J'.7EL psԈGV=mtTV}'th%l`l5O .p,1u֓5ZlߔZt(}V/lzgQhmp[cHK n6ђ$a2cOGii !-]/$sU&XñefSk2%3}GtJ@V", ꉉdPV#ᰠtsA,Mm$c##GH!6 zc+: ][¦A(:,4zX͊wmHIn%VSL-"W@Tyc E@IDATnY5kU7W|j/4tIx:Ǿ=Lu>!L>ְ 0!vqsG@jVڵQ,D VetJ ݵxL Lcmi}'WGx.GlR, C22]])ȈShf)vǀ^lp&. 7ERm`yf5:u55kSOB%ávUO/#ve;Jlb.JDAHk^pU< F.=9]Uc j_ԖmE9µfqN6ӱjn?M: zov%"%T FxUce9HWY@dgn Dԟ,uB6˔",GfMXCe,ϒ4:.e&_ (H}F+dX^25+,F{posV.G/ޙM46(XH{;=NmDlk7x-^ ~q`F<(Fa:.KY7 [(\ຜYLajT:lq%n[wg#NICn@=[D[QiQ+٥A11t;],Z]&vsM56KA4m1Imz4:柠eb&n'1Ϧ)Oo›J]y)w7 }$Vk+oF]9o}軋(*۸: *|jwu}d1eM&gs#XL1UuksQꃕK&^f$nbHJk1fcbxzZ| ##c$l BՏ7e & κ;/.)Q%M}$i*\q"]_4p}o4 m̋uW̸!\;`Is4k,k'B:d%VCwf" h&+an;L0"7nQs5e5bef} &8R67x @-&ppAlUb噝BP_c⑾@_S+9Tmp 2ˋA>jBv736F3MJ5KP:&]>€j-L[4%AK7h6d M;oګD1i_b֡bfLhi۪qo6 ɡ eY0@}ْV$)Bu1ԋ%wY=f^{\D$`ܟhj-TȺ:%,&lGEl%wInO@/ ymXX? 3<#^-Ծrm(lw gH}x}|kI[M\~nڕymU=m3 &lA'be0>Bz`ZO@anH>w~1*A/k*kl\ܔָWb?Lp[F{O\`]C)> e09e$IN&$,!lPԝZ+\"GR޶&o|IAqЗܲ|U&Nwcopח1˜[w ~;vryq|LkeEWS_ƮEЀ:L !ti#˝`άw~s)Zfwi۬^lIUnTpر4]m#nɢKi}VT6#(xQNpx̕ӓ:wj 1ӎI,L bCz9w_d&Ye8hW!j7cO_tTX*a:u,x\'ޘeK o>f xLh,U$'6KRĤä q0|1݊YCajzTʆQ7psgWѕl,&G;1? dr)kbĄK$6DjOFlX,׀j©w/4N\𜛌41YZ"\Z뗗`!rK>|/SlS|yWy#ܹK\2(meU0sDcBW`[ܟuR zE<=7F$=ponw1mcзS]bl]uu di3]A,끀\̩7ƀ^s,i‚YOGc>]Y'C^fH8 ALEA!gr>]*n:ŮcN6Z˕H IJ;,)\\3Rcr TCLNOf,ق!DPt:ƚҶ,xh2Z9ː (xؠ&QCv輸]@TYfa^cZ0aWEe}% }_]nʓBP;qt^ fB"yliXқ1 f5[z6bVѮ5:ž( O!gT_i PVY{ϝA$ ~{_83GADn}4Bueo{-ehs6 pj,k'p fB /b4IzpOQf;Xz /.|Bѵ]Etn>6|1K^ e3{00^u at"u$-jG2S,Q˘9BW<؍:eK(c.kB"{a|OJ56 c50.-|Cky(,]D74Lgf x`e 󊈂 .ͮՁ=Ѹ1vՇAc.HY*&3i:fŽsV4[4UwCN;n1M~ WWRPT 2/`n_!2`5Cmв8@$4OaFр5Z=W-$+Ϛ~o$/57IhÄv ,6p8r.B)YoHn>LmSrɺ7ՈVFORGoY-@L{9-iO[ƴT斘go={DM]m\7H}6^}rm4j5lun,aJ[ *]/$g8s ^ڏ1܈FXtsG6umy̲# Ņ Id΃W3klŰmގo6x~1*b_^[k. ֊XpJd)I$0NcMo0j@W6Y]4CNZ `HtǦ!5 և{\TrtDu%]$%et:j]WK=DLY[zĝ #nmL:A<.MίHto8h# (IMC܏HeiؘV1S5}~Wkam wK~}3ځqTVHxʒ7RZT ؎ ɞ(Hq&^5}!:$bRb:zB5 S^i7'g:5ƜyC1ED$(frכ 4uFqʒl.S`J~'lpMb` 7'D)sJ W1o?CƟY"^=\c&XHWhmfiPO0({0$?v}a !qO͌(*ky$_\=M@gE$v= gb+Z i\Yn>ܑkY_[5D<5r ac;xG@g旅^wx~qXiKYGl$5,%e;s.e#vKP!O6o (f!&TNR=23Ns%3hX[ha5G\K:3En'g[Es!!ER% VbȸWd-P82 A1JA;~U cS[VPiDH!Ͷ+LjzLVabk _jDl},}ύ Zw`܅Ի+zW~~r,^D[,bqzƜ+NS,p@m./c(L ;mm/@Gl+t2-cucBp MObڳЁcxGU$$t;Ms/T;w5Hb3+Յۯ'z/tml,'\e#o&A=K`u]G2DuM 'ڟ0=|Yma*/R.b: $[W7z=`мk/֊-c_;k) B!A`U+TDqѴ>)XdR A[fwkpP~Addk$L-`.dnp/!ɪ"m4޴ vB.Hb|jz?Apl>SD5{?d.1JlB%SC7a0bx0è]Ծ$isu8<p FW:S&'WRO-$V)R!ͼ_/9=Pg)LťkG/m%疤@ 1]kw[L4e t[a\+ƒ,pJ-0S1NxJ%NEj_DØm`GˎMih8)[82jЦxp\SDkuѮ7`A joq&4I†3u?b> f7OE&*t]+BW>&i2ݬ1pYQY`:)K _1wohRV:Lո[wP~gY[+Ӑ|5XԶ-!Ԗ8߀ *gKЉWɎݘF @Dĕ0D'b¥O%W4 XLOM4h+$|qy0hQzvU8 ?X#CdED$)f5,.(s}y@$Fo m1IvsX)8t4 EˠE,BQW,^IchY~d0h!jw8fR=d#gn!o;A XXM76Y-8T0J^:Lv(ܨ(oܤgߒ`ms_Ȋm B4Cp_V)V]rsn/[Fiv(YYk'g9U 92&c|`BSB펺._ƚk爳)M)0I(ݨfUfEЁSL;SDiseK<\`-@?qmfwW\OK*ѨE~H[I. c ($܉gs}mg Ɠ\cko+i+$y`uF~DgO@I0oV' Yuy 6* Kӧm;R.,N4 ~;ҁж{!A@>,'1mֆe`2IxE1`Xr=o1"cRد `x| u~[6953q~! @ rS@w7aV޳|V|'k=/5X϶w.%,W{˓n in~`5,HrK9]7 ^Pjԋ~ }…@ *L#p>Zc-F Y>0QAN8-&`mB(0sF͛P`&gTcF$r*j5-2f2Ѵ3-1誢4%rɇrq|vbJOlceTNCl,ApgvVw((HRM9"F% 6ղF}fXŹ<E\،Eg9Y7^>b\T½{T3eಾE{vge'm;$;YտzYz,QMD *[k6D$ 7a!*jOAbE*K7/*#Оegܛ,l'8bxnM$) b_ \͈م˼BzYZEǔ qO0>!2Ġ=5]qN{5Yo:^,?o>~w* R?`aYEoI\qH!ܸeИmsZ8js~ڟPH VȻVo`W< 2O(aY[jWj~Dp$mj=PKSwIJ4 azlxz@?hE=u<[/Mт4aBҝn4݃n(˒ui}OB7ñkfm,\xUKCAPdI؂q>Ga\e ڹK]q13 {i=~,vLwn9W'BzV' _/38޵ڹqtInAogZD U|1*mXYb>!X5s!f4xBx%*0|mȬY5`M1ABBy!rpK} uP,! BMUBdg7\Ig}҄}Z%rc&3,_}+l~,6.[>1x&6ލgOMЬj|+;L1nE삱a˽j&f6:鯯*C=b3Fή#X -ݹB:Q אX]C뷘^s4u4‚łp˾S_➕׮KĖ&*"&pk# >5\t( ! bM3߅vaӜߔKfS(< `6 +Hv?B {(׼خ6Q,&Xrvbϱ}D_26pj_ᢁlP%[yYRtPTij9<.͂G2Am܃:{liWZ;Ajĸ~􇞳gRW ?(!0$;HKXUunu˰q^{h]6GøȆFZhҩ:IJY>يXxgvWǨM5'}" ;Eŏ6˛$ԺR]:ZmN}*W1⩱X{ E"ҷ! ,|VM`9h~;4޸+}_Y+O'L&{M)ڣ=DM jКOa]ղ%E5ŗK|WqswAie.CiΪ4 #Jsl2kpmWMF:cE|@lh`ltO>I()YཬV-OMj`4~鍇)6l|4yťr( 4VGĴ\D7n(BCm $j"U>`T5]gěCm0uW8wwT86<ʙ }ǺQ 7/%N;)LE:fǬ%]BmLYŗ=2Bh%fuݩ/>Tn^>6 _<=<]~2A 8nǿӾ7UkC I;_~uSľ($ ^;J2ѧߧy|/_ $]uݦsҪ,^l&ueo{I>]m~T|-<_M|I=\]\~Uў6_3XgFx>?$ءZ!JxMO17)$8AyiY/]ov˂d_ ɽ1)Kx}_?ژ۷x dܚSt,R%a`C~MIgGzdEsNߧ_D_!K,9g)rԿŗIwzIP'xHc-*+^ɧiOWc<㠌nK6[i[rt)+~E5l;F) [o?E0 Q|~f@cdVڄhŷpHl}_,WjW@Ԑb=-~ <%7ƜYϿD1/jBv7]xOfn.~>1)!M&z:'yj~aBG7ܜimmF' UMӥpG¨DwaK1m /EyLج{ŇŬTJ>*!܋Ï|xy_w0.ifEw3LrGu'ۉcX@9 ~(:,x'P̭x1ٚ<,/&dOY-踒Wy䆰ĒdKK:/>%`s=rCjK4^/1R` Lq[@,[5*0 ]tbYXW>)0٫ &;:P,1ug1j}Yq% /'YoApx¾ iMcn[D\.s9&U\#WSSfPk3%c.~(L9Q+cv@2%kx_I~CRj1uYcR4', ƻ >'G >|aKV׎ Z5)% W7vx;焎".*.~33rg_LEښ^έ]Xˀs7nw~x^%F:`xv9WD Y&zoq hr^..IYbK biZɥGǐO%b_!-Y6ג%H QHLVΉ^,&|:J)<*=_[`CL= RQmn[)~$89W19uEhŦ,axrSz׾d^~j}9]Jl&C!nn%\SBxւU0:'fVnW24f@ygY@4AK@m"Q@IDATjK1"@phV#W[z*~IM'?KըiQ.8ﱬBȭfg&((p'Ѷcq;i- ~QaCi,}DWcN&{1?$ausO!2LI,qG]!Q1"wJH$ʕ~|^HQ ~p"d471IFb!&bg4rk s En .czE2Vv,cjʱ.muq(~Hpel_+KYVn"2h:._LU/m2c)% %F>&<5r~Bb#83(Ч8Vs )FDo> .EcSh]}wO.DSVYSVEx,1)fNћ:Y?B]=oSX"+,h  GtSt؄rs4Z ;)M5jؼYBקc}RN[bWNq,Rq9H&8bդ[kW|BF=Hu{!0&wPR1& }NH2"wgۗ*0n eI֖q2Z5e'F⊇̟cKn>XqYĵC?J2߾}M"jٚY:.g9D4aB t oC0y1ژ 15JPpq}_!_f. Vs,[lU˝$,e[+x~ϳ8_LĄ>`4EWb⻺O;<1ZO-h}?>Ǵ[ A:TKטSc4)$"aTl~(04nI3AkT|Sm%:H,e&l_{C8!#@x ae}Sq(B;탵spbf,cfW 0{ 5txkPpU++!k1$p_F<ddm{(# Lbh::+J<9e ԄH1=a \D{ҽx2^b.Ӯm_+ODE"bU,i@$?7S|8Sk5#Ba_˝Joi3 q޴3YaMZ{G C6Bd[6r̴1o1A7zۚ1|I%'2uen};f+I0&V$}j-Sd Sb"GZd1Cf;ө/>TH*d$; \ {VN edAЪ1$޼~_cxv%{>w23Z0+ڝ="m A,M 4I魫(HmzM -ȸAFثd jb.)!{|bso?#Ȉ3+Rg„5=I1Fk _>bxO٧oDMs J'8׸P/(efhH^5s]].z%n.a'z@ ď狿׷xg fF*ߜ1G#{&'#KN.kVJ+C!*$,-*b݆L z0/E"'߳rO…$a,DS_RvJyX.+2WȅX7,,8gRdnV'%\ ?jK K)#\8'ʈ1kz,~D;_R 6 F`ܑWґ\4.waH1ӎJV\_c 1wXC.N?2-h$t׉N>4eqY |ܦǍZX\jCs}o)|a ŵP@B T#}Ƚ9 3WeNjB g)%K]UaFJI>@7g[ۿ1?>M?UbfdӘv+0+Fjʻ[J 8^5O2 b VÇh3W* AԡYiDP5fi`fֻ@BN!$NpQR"e\)Tz tƦ`cR:8&eIz?7e $k{M(58NsӘ+ַ1$adu/`ZO%XsIީ .d.%]a@4,+0dRϳ7zH8>Wc&oȒb.DdQ~ֆ~Ț1ɮ!E K]!6cQ*%,83 nf,Y(X&Az޲{3"QW^ڇӏ * JL(:e&m3-7Ml$)C/.u /Kϕ$b:Jb"rL8n 7aQDp MXxYyyeJ&*1×>ş%%ƺ-$[TsVȾY=e-ɏ"$:{賾# ]KBTFIR©qAypH;ޭuD պ ֘ O8vJ1, |LZ@n/b"Ą dE@̤k2eV  esp  @0[t,{DꋹKVˮOn UЎdn+IE\qQ :z;~p^̙Է9 +>|ir)sB-"=8a Z,n%9ђ b~qVt)Kn .qe@yʿ#@78N(h`Ku!=N$D4)iCSRLܘAC~ |(K0 ;m<5P Di-G)X…I?|0‹X#GϹrGZ `zuzrob^JC{(Uk>c$&`Y~Shk5fP# ^QYJ>x?J7,蓫})!fsoWR B8w1G+|S_,#ǨV[-٫j362Ϲ)Oǟ-Nmj‚x_Lencm[&}O Ko񝅍Z^.a`ʕl0VR<Zw-pE\!ҡUY ɴk0^#<>z `NY ԱX9Pr w 'l?#J<Y)Xyk֖ sf;I\ z"s%d`+ /< TٖJQ#ñ([(އO;HNi,B'=RQ{\h|S۳ *%( bDNCfA}h"JO ۡiIoʓ>ãuPQ"pJhDh = xJU}\R4yMr eF6rScһZ"Fi9x̺k걌Et?u,r?,IKn3Bu|N3C"E7;hIve 3+ {`| izY2~= eUr-Cn7Ј;$^Qo@ ^oezy&ŭS}W5O4Ͻh(4sVr?WŸDj$et۽9 覿[l(EM t #+˧$+/*[mpi#Y(U SH>T]\[8yIKJiβAc^Zd0U_*@:&,+X> d$eȗg}Vǂڳ3 D7?Z̋$\ڎ%Yn:}K*r^"|RU g> X OV^y"q͍"^<+QL?._SP`3Jj8ɜu8}wg- yWTgnf kx%^L06.sbKBVHIbQ\p6MY~XlQa)n"D\ @^荹۹\-8oK)vLjw?2Kjlc^Óp\dz= 10Mt%wwtpSZBeǽ&7ߏ#QcabtlwIR.R+$_ŭV)-3&ኗV\yNfcXBt+%dFN?EXGˆ/7ĸ. #%l4EJ~<1;'WljS#xrQ}YD+Vbπϵ#܄8z8Yh9dnI&K%2'֪ylhp%o (XPD"]~n a6]4X!xYeQNx)V2?n%Wʊ/V-$TK7T," ;"Mj#b"L#BR2)%!nm.Co `87aE ą`F4vu P 2bcy~7&%C,F%ќexQ57Axŋ g:.Fo9jAYm?-Jx2`*+/y4mS4VaƝ6AJ`#K͊bh7 s'FC-{C,x a]⚓q}32(h[p vjrcY;[ft8 'V°mt[qP+#oY>uA1[Q4ZSٸpFO.}%8OȎ5U#ܨiS4Z†gkd<,?׫xY$ΝK]GODh$2xc}6TM֫ o0^ZjѬ6mS91I!_[?BHBf_4]CsD ;IyO~+Jb֙p '.=c>eAMk@dc :{sܯ1O"4ƉXY '9G? /L ӎ{+ hZdI0/Zo8ɍY0#론*PgUR(y;([Z,"r:{f[K[Å+gp 0v+%۲?&q1Xy88nӲ;V 4GX7//(żV w}MԉMi{c>f}9psgb'N/ƙ)b1*WxsfԞc1a)"R4y7Gms¬ۊt85?eI2I Z6>'D*~9afY~K sW3$=n$ JSExM cr;4O!໷,t#X1|~ky2]5>[4VNɭV'ҒU,_%JY o,XqN?`68}BM,&t?)^5f ,>$o-mq-Z%X]BNmQ9pcx۴+~)p P\equKرO @V>֕ F9t|xpbhEY։Flzg1e,[Ww8t%]جn\{;:!}“ࣥe8ng{[*!d]]3z8K,#%h}#  +W1L,v.:|/z.omVA2-|;f41ʋr)#C"<~ T1>^5B&ܐ "H=GZ!A lLJ YUpc,K>A՜ ժvJ<! C6_SSVNC# ֛B5XlQmjNνK!)EsFP*Fg#>:Uյy[*mt$j L).aw)ƎWB7Fh5(,h>,v8X ^`"\V=ԮC7 JҡnW<~t>BbbLxܠ{Y/,fJpv O#. meìå2N@8@ #`"=$^DZrhNv msI rѰmd~n]b`A^:J}hOYPcA|6I+m4_ <;òYW7)GItP9C=>rR\WR`ܖ|"~eq {ec6%0,`(` 6? "dp[9k.%$z]:}@)!WQ<^m(f;퀵;f !׈l&4 by&wA' Q EUj= @vB}.ILĮ"}{+Y,inGV T`'PB-w0ۺ+0{*Y`mA>˒iY@+M~&( d>grE#bMI yBE(XKsWްcH,(6o"ˎlcO\ͳ "K!z&h[EhІ :^fMDt[Ô͕p# '2^R+7Ūq,`%CXCb!W[`.;B `nH!$k}(b%,`/m("R%j)(I0w%&Y3 ƐYBD\%Wv=6&},VYx$1p7O.kx:D0r;OP!\R7es$Ɯ'!rQi:ƒ(џyιCR.}(oߚ-WWR M;iVJ^JXcN\,!A&x {@%PBqi$J B.NyJğNL-Z=BU+o\GUnT\R3l`볟;&^}ѽ$6vJ(02jDrלX.?:zm[jp9Ux>e$p,xkxR|+ݐc /`ϕf7fm RGiTԛ@K!Yt&J_;ܨMހnf]LZ߲KKczTZa)- ?:|, /KcJA4-gGiU(:2]/xs$[ꭍ=x5r9+=3δLIJT/2V7zU^@'rJ^DG5񰚉`9Ri)fU?4m`wZciB`#Uأy!hJVHQZq(bǺzA^;;_[.ԜPc6!^\k3]MQS D#{k|K|n~NyIzaJD:VB!%Es̥44a=u"VӺ &5ޠ/G=}P00--Xs">IZ~5Bњ|ˮ_m<-:thyO9 D$τ!bER,!"lyPjfmvi Sr4[.=yEwYHRjԲj)TNڷgCے5fBdh]Z S(ZL.{^b} c5gfV& ݌5Jy-HYYwŽ/\ 4jHHd&K8)5O95<|-%.!lBl) fDَ'`,\Bg+/qdioIVE\7ig:k +fW  %!dDd'KC,wk9͔yZH`,o]>+AXMUNMV3`78PLk{-M.~0~L!P&- _k8Uo%%)4ы'f} ;'<=wqІӣ͢J/kWDG(r ,f^ﴔYe0, $bk!`h7ĸ"ɦȴ$n+|)oj e%5@LUm`,^-wpqw5|,!'[Vc- m (Xo@0vbj߱fYEP˭O #+uYaM]l:b5G_rڽr Rߐ`,bS!▧mzm.%vQa ZF.ѓCRц,h,,,ecBC%K`LtGCLxь!\n+y Fku,p Y[I:vqY v",9(m_,Ѳ Z3F?V0@Z׳3OW jO5)+؋(#44 \late膬[DQcc,ۜh.q !!~f6'ᖁNpr(/x !#zO1gA%,Ѐ:)2L&, b'd`sZV4Fn,U/تC&ajpQf7ê%|w-!:Xs\p#I0 `5R,~Np)nͺv^#RnѣɌ)gJXXş rX7帩.ͤ:$̨gELz--NQw >@b8,]3K•LJ AGRTZoˀ;91+hˇuy ;$+<6bz<*UBR:)pFpӃ F_c;~ HOrIX' B {֘Kt+{1&-`{n~Q,4)Tj\or1:\tc/4Y&?ʡV-%nWf]-V G#poLe04n3:{א}}jq* j`U xN+V`WBz}.tWy| 2mZ'IYq7"ڒ05TfqP: |vWckij21ãVDlBJ1Lbؼoyq?V*Yh3h. ]|gV~"\c1gR^so&:DѤw,U,x P|8,`$Yf ,kc{YP&{f;]ӧߚViq# g1;ƣIVonejA´G߮ #*kɵ8ix'II+0'1K"&QWJ~+Q\Te;V4qJ1-FT.l]KM Gk,%9`bwYLJEY?ru+&DG[:B,~k/_*ۥ8e!&%^vSBID.B2kSV9¡=Nn d*)2mQi "X^6SI8bԍjv2?1ͼNb*agM!tFc9(D0\k+ Jh}N0+aqYUX™P=X*ZghWB $+0oZ(<2W5ny?[Cw"\:VHmKA@ncY-ǜhmȹhA({ddVviWj(d#F)m ooP|N8 i7Mh uȉ6,=F(yAgҠ:6'ZG:Iջ):gJlǺqVMlΌO 1=}*luɻSsD~>֙Phva^ڄt/rؖ8B"&V ye]%a'g %l[uR{ 5rtM@/wu b9DŽ*\\QrjbD <<ζ\9.`0?dl~M.H,>sZ%ΩQBh5~Ns#,M:'[ e*$hR:q L5 hV#z>0&~}aO[2?3:ji6 S} ki :(//M!sH2 0~00+MS1$V7otI#\wlݔ5_e7n+7>BtU 󗒇 *|7M6p2ċl]hЁ ꣿՀ\r'KZB؀T4:uRs }dKnUNPFM >1xCLg$טο{s$Z3OP,]0g?Vgﷶ{Wϔ*0T?m93wA#Ѵg!%Q%x AyAw[NosBzbn;1\+@xLyzo1a)%+93% U?s9rZ i n :]^ޜRT>H+5UbQ殹,)~/D>'[wux>>4~dQ£ :eR?H{nѷߡ+I":8)Q'EUCM)X̺;0%'lq]-lIH,sM7SRA5FhZ] l ]{M` g|VPñh 8Rf})+Hy:R,_YCf Y&>҅ ĝMJLhK6LYCc!}te ;Ȭ'k^ȋV.@Fa6g"|C3;G@ΜNiCUO nJK1?~jсe^ At;(+GC Y:V`m|evXNL+g "^RM8 3<-E%x5Xllu<&`ُS.Njf8e`1/y:q}+Ley1 MT?g^FӸy&4bbeqU6psѳj;MExddIZMS@I[ŕFȰ֖ɪU'oer`ֶ5x<Zd^5w! K/p -XA~Y-o#z5^?`6f[|HWA0̭@]`q(.{ox~pbpX4=e~&1koclq mx;MP4: X>IಡdJ5 w%"l)+oB2ţR'yb}s;}6kH_O!&p.).QsT%bY^ȕ䔉WxXui)xo~[1p kD$٤MnKei]^e! {Y} wN]5 5vw ȼVP]^>oM@U1q>#ʄ "w\ 0.0|ocMs] @cu8W@0aU:+NRL-~dq& uIL^ $`Xu,`O]bu-氵`͚`E XgD^$C"?5ǯ}&vIJȄz& CEibQ &kZb -~eLXPǒZcP JmL!)W~(Ύ}E w%zJ]͍&dʼkO*FSg:U׎Ivaqv ]ȪJ'I'&Y-0js: R.g@IDATMc/ƾ""՚ I)|-)bfтeC`+p3[5*ۉ[%7j7_!Ӧ"B4nfEǿk? PۼՖ%Z.8LaZߪOO/? >}0mIw J½﹐0Z|X5wEV]$B ɱ Y|7plI@ǿ$)MQ("TGx{e."mݐ"q -\R &4.^2C僇)a- ;:688syXEhģnYYa-HQ]~gL+߼5I /J%#l19-8cD%l@~`'[Q ?pQUDױVZR y1S\<wy’Hߦ綹8_}FvJ3$FK)hJ3y;U8#yJk;ϰ }\8rNe@peoo'DAe"R+ƌ ֆ/eD7+G#ߏIJ1^X.@4efNrFlH.+tf(N'hOq9sV FE4䠍EjJ$zp0Ĺv?d$;cF~QqN QؠY7nQkUQXHS0M3mUa𣦉 m+j?5g~߉QV}|#U8hPŢ2iW4:>}ۨ}QՊOXSxoHϊ?{'64mb_xagmvrU=v=h&4'K`y9>Ń+&"erBt/ VsZqQT7%k 1=8'؎Y./'S9;15̏n J1(<%,3A~fq~K[67 ݺ95{7Pg$Sv)c}FѼĶs]{cl E q(rSf%q!OSJiM%dC}xy";x`hٿxq^B76ffj%EJXw?nbaPvpA~v}`zZg^|Yc$j{V<罱2CMh QB@VU1ha%L #+g>f58Ѝ!XR>` D~ar,$: \6#I|$<i<ӅhHFbAR}4Gî]N4a8i1C(3ׯڀF\٘+11dΜ//> BGs|.U x GVp^)j~-_8 &,HL /!dbIH&瞀?#0bB&kI'IӬC(جCoH?鈠3{G0 1-Gp/w@;ůcF,g6Ƴu^NaTES>hq]g'a>)Y|~BL_$@'F4kK11r.Y\ Fہ[Qn h rt_$DJ2Q8$$vEcvh.˪?k% 9! P0BAL9o_MmX0;XBCjL; !\1ԥN|uHv@v'qs8-kNV HO ڷ>,YF@#GxΙK傑fBAĭo"0,ip%b}Ͱ`=T!@m jSo`E}wݣ!ѩtRh5 Ehd3 ÅL$\gg_]/X kx)Qf)2lFH'4X)5ʟ!ͬp5߄uJEiU ޙ#ٮ'e! ]b(ev\1tbDgS$e#rQF9&e;"aa#DP4@%[hmQJ឵5%p/eI~? vx@]%EO/k Mז_aA$|!x&<(ä'ZwJc7q#9=l4p»EMak@Pr'դ ~@7 1d]XUp!*kπbqPᲡ|e}g]giOOOkKͪYVVpڐF,„qNS@1 :#wxz,#Ĺÿĭ VV(djoʛݢ,䉟&p7=V͉]?w;MxsEK!"8]S kv"< bxŻ_vo!Mđ{4!N&7 `X PlQv Tg"&I7T!ui׹aimKf]KxHUC{8yL1aaDkBEa=1k]>$4AGK)ӽ,/!y]$@,*zaĬɹ\ ۍw j =^lN=EA6h3oN|i0Sr%MZ|?`XL^M dRr i;jw'6+ƩC?A#@zRA42Cp%l{Wμ0κ)j&]:Z:fAtiQ7*ll_\G3M_jK 7I) § wekč)ovF.^w{?јeHMmb?G5WDRD^s}|ʺ_ŗT5Dq;hLLZY¶UV"XZZCfpqY\z4XO|f~ʈHeHr[Z&Vl1%e2.wzÞF1+n}Vt{Dn0X-.|P͍qwIJY̬c/)G`g +25_{JvAZR`SHk@s*BK9a+qs,PɣH;oN@?4MB;81Y(970lnDOGg+;ŽS1aQF0#*DXntNq ~(fy'QOoq& 7%X/%%bLVi ~J}h7r ÉG.B*/1"\N.|~p ܲDʌ}~HL+]UvSi 8' xYwD%g y % Agj#yKj8sC 8]'3F-k7۽2=߱4(:$:cZ\&")\YlQk+E茏\vV{cmsL.D`L]|wG]Kd;!^$N>ݢFi ^;MZB9W KhԈ53.歪r1b咛} b0x{O(U+8͂K2$$lQV @v#T_-X[mq$K[ -!^C#1SDFP`WnAHB- H !"Όv tɋj c!R[uqQ#};7"qR 2LĘc}趥Z򯴛eIB֖ߠ]slwKqh X;µ%-. :W.m~BDr˲#F_!Ԅ?&p/;XqH0j^ Yԥy6yy1%DkM&Gkhg.yCle!bXrq~ÙP\ϲ8a|jH!a})N1.L˔X1Vvǽ_kz9ZYG\%V;k:1ute,܉Oϩq'pQ\W}4X.8.j#d2PS.un>j1N "*!Ӥ.Ewx+ClTS.Bm4If!LN5$ E{4+Xr@XHaRK"`! 2Zt~"YBhm?>л k[`\d ,1 |O(iReU3 "ZK@)–C|1SCg& %߭G0(KDd€GE'+N9 x BU'wKXt fۑ,N_5kM{I ɓ?"C/k0IvVL@!\gcM H̱qϧ4UAHw%x=YˎhPGTd iyi[ *B MABʏ9kHZ70Gw̺ a|,y鸤cϸ,#LuĦ`NGtKG\'&gY#S"&Q+sXx3\ `eiE8K5eO]1d#Mw,+9fH41A `s'ӽq7^0}a\ING' =sכkMl<# A\C7@߿/;s&S#Lő&Ɂm#Oq8!Ҭ$S>Wd5bSFU ;eC> uXIꪈ{z)@)#jg0ohc/~u7k%R:XwT]]b ٍ(ѼZ}{$|r(uUD)!=9\<* 1/9aٚU(#Qec w^hp 6f]߄xOQxyqm#Ƚ2Dqnz@ld͗x| Dcޏvv̌ ;M>D}O,&.2̠PwmV5{]$d;?-|@݁4 6;e; (PNl[ @2z*,`$%#Q3W#r k-$@|S'Qu%'Fs#Os+)Uqt,D$R q,3 BUW}0>:!d>bi}_hWdw,"#_N#,vJY۳qoōպnM(M^|FYeNzhmXlN]8dc 514e1'v.v Jca-M% !l4c I;,GlHppNJ; Ł!">\sa[[(Oe\MżH>.>{ Y,^ M=Yjj38NZc+H^f}7a y<]lpX]XQVT$uo#0߄k)5% N1.'Lz_0-M'ρ&? D"4 0rf I̻ 7" 6u-#{ڴ${/~.H[Q iP=rD@g2Qn F[9nX"u=8'b!ڗ3Ÿ,*\FC<}<zp=3X{@T+m~b>|>w!kLpCXe[3Z[ f Ӛ3-{֞Y~4`L=x?v/^W,C#,d :[icnG3!>D (o8hv4YPr1P#{VHq-EqD'rE5N&~\$׉H}q(ޗݲ[[NvkSc^p`? 7;iF I^]9h62X֞ۤ,I@!\CFLU^䃠PM@2E1,{b2a[ %ZfKq1|e.>J¬.)[Og,0`x` Aqe|ˊ%Cbd~7KܚM[aspr0h?'7=7W'ʼn[<. Ac56lZp CJ%\޶WH]L7v -KzV~s8A:zY_qqdG l 8f/TÁf-C1!!]pfy%YC Þs#z`lY}$i 1%5s}yk h`\HE/%i^-3zy]e }lS<D{0x .<9 #z`dugEp- ܥ:__; &~2)ok=P~ݤ:Nf&O$Pa?}z6ٚX,9}s-YwRSzfͭ+6^1Scxp!,f8=9@7a# p)?z%숻H"e\(BOHDX۬M⊎?+&A/IńVNhGj1AWVJTBYDH\R Lrk+G& R!YWߴ/d}nY5RbHDZpÉ{;ڊǚ+l+@)Da:fN!W,CI-4WG|.&hB9sWR(ӗs\& \߂MЖ$V/+A,+\m%ۘQB:X棠 i$]VRh#6@\C^LLby4 !dbmޟEv0M‚~!EY[mNGn41\m)@YKL; / LUZoj¹,G<º^ 7Ư1/{fEGu]0v5N3eUF|DFV~€FxQ}wJӂT /ؒ[K0HQ"jQG؎鼼_ţg}7L _op¹vM+H%u)!1} Dϵ=/4a gg߳_ t~=:V=]CōzV)ܩg(0 ÷rD2rmo)Sj; U+Y@2F(Oɲc߯-Ƃ y/K}#uH-;7fƠ$:bg5Ϛ) eYhD,7 zH3>tsd\l3gZF㱥`.g]+<sG ޹(+8Qke nѾ@_qx6VV~.$SF縼Wέ=o\}u&R MR^ $\n?z0ڰֹ)ȂnYfg7m|nMxBb Gh5z7jNx ׼Fϛq%{KYnG~B.Ձ!*Q҃jb j_1[ѓk* {x!7whc Ц5vC͙# #4KeY6b٣dg@ֆۖ`Pg'4IYZ?c7]M:twr !!o9'i ~nlI/l K[a% E]ID ! 'XqsǪ 8ͥj`?Nװcd̬hGyDKIT m\kR [s7I9įAOגy&u^a>qh^vYLƦ{xx)XnKq{?j&H{)(Ϙv\,/o-X/ !H 4L)7胣e6BO1ɭlpAv Y&Z"T׬ ϸs_N∽XK Oӡ;%)Cq]j\2f%Ǻ`u4x?JhwVS&եubBHHNY!鯬 FQF #1fee٬?x]MxΫ@7˧{*KM'hb i8*PuBTİ5*UUA騬jpz1ù/+A 8&N=%$m'H-꿾|׭x julSD+)I)$ 3]͕8\Vx:&qL)wxf\q9sy,7MnWvS>g}ֺo[W|`'?)6RL7m`[Oஐ65kQcl%3FΡҏ"EI݃1zDw!9BVTyT/1?[ 0!c4?NBJ*McƸ"o'2'kgYdi-ze|Y$"2Zʁ! ֨c1P#{y]9(e,= eF!bs"D<µ9Cfz/ʢZ͸tJsg=|o gg?\]ۉ2`Y>[i/s=Fe@N1,ƻ}Y;>&b}$ \Ff?wDp$mx,^U|[5 4lAl*gDi+4NKugkf'6hgMqY\#˾w]IBK*s?Bg ^#|,Z7̓[)A[a ULG/HIBD[Zb6z;BG0]Ǻq%r vމ5%N5CA8oqI{S2c%K?:] {d# ǸY׿˚$n]؃DB r4MLD}F@"]9#B L"#dW޳2;+X&/$4`)/YI0:ݵa4 ٩T EO9)m>cwy ͊D+ $v>eds总6ʪ}ۼAZlu속k>4Gu{ÂU"2hM|~bNb\ g=%IpI:Y?4h:u^̲dݯZ`i'n!;&o@8If4}R2ne~;0+9Yϖu,cDm}9i?.n,KF@aUJY^j$=um1-BU[=.i `ACGjL .5Lgj6@D| S/:n Ν"s` a\|Ŗ:{IsDYA{@-.v5 NƲ^RHPf#~-.̿DCm?e2xEς=&u\:!XgҦcxn.e<[ vKp2#8.Hf mJB][F?B>-=66(C! k$A]V,`?D 9i}67'[!+QT8oΣ$hw ~0X>%ѻ+5X4A:ߏy)GbK,ҰGwy!A wz /+ f+0 ]v'FaYOX{$- [}ag-`&#L}6Y { kc`<߈Fk,-WӲN[Ve'l,ps%~NgWfz+hvM8d14K5S4R«6+CVp(~8tъQjhXu !Q廿ۃwO J4X.3d֖(bMJ5K#f_<ؼ>{z;\{{8TbN(^|)$!&#cp$ E #Z}(EwyrVɢ [ԈB=VV}XNe:kik󬂐dvP `K)M92|~1y|B-Rp[^eWx7u͕sD\cnI45Ruk42uȐ &ydyzoupGh At` ( ! '"01ǽ?ؐYףc(&pHB\V9?{eωݺ ^#D#NSh]EJG,U#s}A>w: =9YspL:}F8߹n`ofdeBaqxc^}mL0Y#7 ~ߑ>ʺrq߇4[l}ٔ#(֜).>ZGO (%h8e.8o KՍX '69 q-)2^,i3 E4첒pq_ B!\x̢q ({ǰv1V8^e4{?c4BOBuŊ/B6ϵp8Ƅ20ǓՈ|*"%?='lL7APs~^9B uc(R^9CF7 Br0 ϛ.x1Db62FF1^;{_f{ +d 7 be޴q܇Ask *F`4~{XW{[dd5Ɣ,Q$w&n >yYA` xE#<V1)`x9(sۦFc,uk 𘧉؀Hh0}.:p}%@jYšpV Y\@A q,}.jױZf1<\qK|$Ūbiࣅr[.OTv`8; &sDbOɍX,`Cor]=ܲ7b)c)Ƃ;KK 9x+sN|:' Xmee@h?IA=6`bЄ6xGH7!F[5@{{w*;Η Xwt(4jzUKSkӊ\-4 (90 ćxPw^>-+&5NM0 D!c xh)oKM(ƈ :},S*AD&5c4~bZDk#9U5 uYSHē(piIFs:( gut}fuP K O057bAޅo4^BYFw$+nu*o0.ߩ ?lr Жk'ikƚXF E閅;M r$^&{0/> +0C a^,MnxuJ5 Olz5N;AnC #1~%&$?쏧f4Kwqχ2 }*VQYS8ڊQwtaZ9-ncs~ ɴ+ krH\BjV/Cb\gݚB3bA'%(S]="n Ҹx8^7-|mlMpTk:YkNUtd_Nb i%(©5)|4ʻ9|}}mɯOOmeh&q)ܽIQg{sL7%qk9>5 -ɒ ju7.i~_GSb~9 b% /-6=<2,TKXdoe^EHk+NnV"Dc&tqYu'%X9=83t<JUB+\geY#2mP_-8&ferZ.S}w܅_UaXI&~JȆJʔpGݧ?9n%K(bOյGߪ7IDATb/='xNƩ 'DF.D^c5O}. ºƕdxL,+Y5p5] X\85zO+oz:!mAAk?>ҵܝE|.NhL' Ox"y$$&㖭3,A?xlًɷxς>*V\|@1 e{PP_%< DIwKY4X5Krbj|/ggjU@4b8~Mgsӱ1<>SV1c4;/d! ?{Z,8@RxZÂp&>sL(1k9믿7:߁*FcoYL`]lўHK֍I+ˏ,^i@pɐoBזX0JC4&ޤ}]/a /VY/,9Obuf[B,j#af# b2IK$I#Neӆ. q?96K. d*Eд!|͕ ;8-s´.=3`L$RYmO73 !3}a5}& wMp3X0[&XAI2*s],6Mn)<#h yJ4x=|bx?uz]|g:Ahg*EsNs;>vv4PAQwb:jz&qNJ~_X<\WHl_8fV\6$˂-X>1)pO[rH뫫> t1dXocxuQŒg(q-`ɀD,9M:D%u2tUGx#AIY,n@- !zWJ A@S`rNv֑U& %%'ˊ> ߤ`rǺĝ ޑ4DHH{/ r& 8y<3tyP6\; 4+ :;Y]7sOdr@-`'.r~0WAw EnXCoP ]M݋Z\c8鵟;+{QrQ4 Ik>h+j=X=l; OYWQo,\c 1RafR 'f W]0y}rnrKB0kퟍUbCpbgھ~p9ݧڇ0mE+b2}˸3Fcl">1cNs'Nh9ٮchH֖R}5'8I4ug_"m~$66-SH15Muy `iu7|'G[yE 54'ijޮ =H.cH{N6{!ڳJkf䥴 #H"I}G_i)2Bft9ZhDxр;Y`r"0O'=?|ַLwjScbe ӋMDىEhˇvR>8&eg󑧞ڪW}1X ێ2$}Bt=<[$^@X fv $C}/@7C! skl 88ݞ1QڃMif|Ma-sђǼ3;GS?65LFvܳkbWH6 Wvg{7RH5||_TOcLȂq N̴f1tѶ軜b  2aN蕁Q-]3fjm*sh;jYgMlӞ(w m뤆fe|QHq* b»f j) ,je\ DLnrWm:7JJiܥ,Xf&fk};a*3c^ߍͫfz ?] N}7z!!v|r1gFzڏ95NbҤ`%oJk%]˩VaB06<![@ nX?>mO;oYԳە@/Iy0>̛pCP},Hyh:XD"&*]!=+s#\AXmG9bۋ)0R?cDSHNMaE,~ h^5iHxT?lԴ͸7dGƫ, L@"m+@:2#O WNZ)T'áY.c~Ku 0fM5 gcDٸys`=8|rq+dye n Mʹ֯Sxx_WCCP$I]9м',~%VѡzǞC|O1D3w7arY*q]b»iOPpJo4֏|"͈Ed5 -_Oʷ%X\ f0vN}}0`%H\\I3T{6: _::d_)u& 1~%mb`묌u$c`i.6گTB< fOn ,܄4ϼ1qѤALjand)]6Gvfy>~ޛ?5ctӖ.*!d꺥ế&&A9KeCX3:}, AxLhDIXlHh>+Ǯ6Rήm˩ %3ya׋GX:lGZN8S5OS"i7gy/AaVSLJ1 ͌3 QoR ry?m2 32ͰZY4-9Ӂ|5n!cmELzF@5`ZRd2ڒ%ri]R6.80WY`#E>Gܞw\.~_N7BL~߂F孇A1|49ޓa1!ot=D}tKWfmz3-&*0$A;D^r{3V%B8D|oM:%Noj65NffBtc3sD6t6IRz9! {*t(: H3t1D,0D7%_ihfgIUr !)+ВjiR0AW`w$u9wFrEboiٟ "]zM_&W [ ߧ߼n0uwaVf7?rk$S8?,Ѭcc~x4CJPJ&`rbBe4Cyd|1r%Ąt?Mpk2%Z$}_ߟH0ٰ6;#d%zSG5}vG| ps)$:ʩTRH;hHD&-*nȌrK>xϰX 6i%lQd+--Dž JK)AD ^0&JN Di X IY":ʍxf bΤK LAO2!4Ut]ec71׸4t'eK("p5/̈Y/~=#%-x#ƛ.h\k -GluKdzcnIRnk;nUF~McB=o%ê&ER ȶs#Ro39„k`Zk>WEBQ( !&dY8X yNfE\Ԡ$ceC<Ҷи=[6=ehyqDcI0Q^mٵX3XCkUy8քeKs{1ܫ͘ ^&N]hB2s5gW8RW{ —f %\2zfAn+ % ‹b"׮Qb~S)Hϱ[,ʥ@d 1_ALꈉo ̎|L$ B `21 y]]!mXK*3F40i|e|mbۉ\ 0zl3}7$m 4%'9 k )XfpMА뒊&54 s4Kl=m DM0("EkKL0 d"=<ZigpMev;?+$5|4IEf6"SO{CV?ן{wDzz}6nDUbۭa $h\/LפޚzhBx&;볾 Gk0 C0l;H|6I VSibxzgc49@1q8a0ѫb[̕ꙕ  ^d?CɩVtp0.US?&) k Z?]#jHh -}) a.`kzo6|Gk5nN!3.[hNڙݘαxfzVTƷ3|JB i[Ƚ4n9A7cw)cX1?cD( 1^MD\r?n!Jф=>FH$^bJ? O< ~76~sY$YTt5L;TAI{[R|4Tl?՟)UϜBƜm gDM޶uᗷ}dž~^[)!ƌ^wYmQpp~?J\[}}3܍K $ۤ8WFdORU"eJ4@K@\RdlLiSS{L_њ InǞVJ#H:R$ %P̺"淴͛pT',EC~7U,ׇ$r!8\I@#ӏPCfhq1Ē$`٫n:zKvM v8FX>/ώ-r7DjFrH(?5e6AsH``fGШ@ /B*RQ!mϯxgsv-O6ۖQIVyp8½V?w/_[pDL;Q r}L/D/r 5%lkvb2h$Ӏ 2p^ &#XثOn&Hr|1־ޣ&P0ɴfkRVl96_iFciNPgB:V1>;~mO!82BqKs<_'1IBw &-1E;-u&]J ֵ+X/0&%9!=3OlUl\W&XQ}X&W@8Bv>z8Rl:fAvMHx hJOe_H o}DHp X{c˜{E|~mD{@ iMNԣNMJηnCjhאH\ŸE6JIݭ]1$\rR  i]t+4B|S(O)ڢ Nhȹh#xuLC]gd46FI %(&,1"*lnĨ,ځP$7c;\Lcő(?>ϚE&ӐkH67O 5U]o׍_GVyC\RZQ+Q3kuLϧ3M`q[ݱ(ݙ12 ,h< a4S50LYó"闻2I*!{ rXv %!f`f/Hlx0Ya0_gfI/i-5wcOЎPO4|;@d~)<~1\FK s1нхϟȯ"7&X p1ܳ\,_p٫g?f5Mqs QΑsЗ u _ϊBrh%`5?j,x& ѩHaTYnPq&_W[XKS@W4nIn΂znO+{j٢1$-y6V*4cz.~6nPѪ~4p{MMq7S^;/ p: wh-b}N#4YKN,18I{[lH|% cU|zyAr[~8no+p}nW[ /GhӨ\:·ov!_>i/h=K-~$m#Q U-ܟYȖ0q9)jR2z1rt^ql.HǑhdQ[$bΎdۤ<&|R(G8fD'R'xk)6FԊYƼvVE|"Jx4gh'U~ Jjw_KƬ+L޸yv[AI=MBZ䇢i"ؗ`S*,KmXokwhfELV[,-hLdlK<=Mu洫YWsx&!i[;鴨7i,FnmN,3jH[5&Q3-JpjllK]Ʉ m -R ĸڂ͐On3kֶk 5_T=+2!x6lgؚpP,@WDӜ_?5 i S9ۭDU{ShZ'w5˽2u{f/hYzr EOܳvMv]Κxꑣ\1!7c",podp:&3A5F ],b  p גZj@ڑo)FD T5m'#[s1!~_>֦`#!br Ȍ'1,( h Q?a lT$81$s9bXu6&nR5;'H\5~ꮏ7>Y͠Mw][{O;]*rKcg5nkV_3K|,~siN̗)4L34Ѕ_[F2jS2TK+nox.lphoxImkخE$ǨD-d]S *ҬQr&KuT ֨e)G؂,g$拹͜h~d4‰L_11/H4/ҬtV}i[">Z·aR4ǒ9fyE$l hĥ v]AjK.Hg^B4D܇nᔗ C$\_c_ʔ}ay_%:lK2A"z@,ehJq"ۈs $}ȇ )Q5=|s+fmS@W;n//; #S\p1=,3298I|!ߵ[\0|V*{zb1|S\Ġ֒bDPB}HqGiB4ǷF? X,$#s"/1~. ZD1Q!1¤P,n &d [aZ( H-6AH6m_{~ӣ'3f>V6y^krprU3~f@3:ҁR7/Ǣ޷B?x6R;`fukTQpf ¸9tjtY#U2?ulNg&#~'5!G J2릗@IY6]gMڬvS]r& 0GH\^8he]τucԶxw4E}{(SY1ǝVCbE t_(4Rm o~f 6ug*MN yx7`r*%q C |GZmc$F'1^y[ǝzH3Of\|L1o| :*[d`NgЈK"m ~NCv3P/1␣}o&Icj\BwIBeN^h>)F_@s2䦝J+ >Z΢K`Dz] j'-R^d̳nFo$-"&(A5{8W;O%YKe@f.<$笻}2f"#4݆or_4EZQkw^4ӳ&DY'JhT )L1M$lr bY`%wWw1 G=LbN_t*>aH^W2M@R'[X%mm$kI"_wgtIw]= _T?~DvĻF Os:|+ȓ8(n[:&i-)"fiJ //W|[爛Dnw6/&]!X_gΎݰw}Cܶaoac\㔌x#qgy&fSOzKD_`1cf.LE U2xQtc[`yM5m*{K=CE$vhy N`SeiY}M'%h,}!B:cW^=X<"Fm3=%SZÿajlN!@"?!WD?S2ve.>$z}pg8վ3c3'C䐜r(GJ5fs!@b!|ofgoτ֟Bm3[A%P8..QqfyKIy*y{`Ym~^`\z 2, XAMNcS,Cw\Ǹ<=Ikp=*"+$ DYإ?TK%'[&a%i|msI3iNEiǞOJ`k"\!چFa~r珦"y 3.o $hfriCh*sT q+‰42f\!v9HwOiK܊jƳ[{;>&tfAMg9^Ga@"j 0 s!PM}/KP]P>]3~ ~"^UReE|mxMNT{GHH`dQ F$U?QB[m%WaEvuH˘d.u[xYEg_zĢ#Zu n sFْIRC *'siŌON:1z>/WRPxY{ +M3LK̴ 77-v &Y3mG0bv1 iÞ#)%g4^<~h cFOH)h a7 ?m|Zy&d:`MƼ;8Oq'W6#Gr ev1U>, $?7m~u x_9!]jZ&ٙ#7xT1BɯAP X!L@nßgjfJkm LJcÌh02sIxC5b V㳘i.Y7 Q*W> rtcQi,D`?B]_:\@ws`kd NE]Ef."Ð\ ŪI"Y\Ĥ%Bm~\/.S S5 V( x>tj2/4p!jPIENDB`chessx-1.0.0/src/gui/logstream.cpp000644 001750 001750 00000003343 12223260306 017664 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "logstream.h" #include #include #include #include using namespace std; ofstream logfile; static bool bDoLog = false; void #ifdef MSC_VER _cdecl #endif #if QT_VERSION < 0x050000 SimpleLoggingHandler(QtMsgType type, const char *txt) #else SimpleLoggingHandler(QtMsgType type, const QMessageLogContext &, const QString &txt) #endif { QString msg = txt; if(!bDoLog) { return; } switch(type) { case QtDebugMsg: logfile << QTime::currentTime().toString().toLatin1().data() << " : " << msg.toLatin1().data() << endl; break; case QtCriticalMsg: logfile << QTime::currentTime().toString().toLatin1().data() << " Critical: " << msg.toLatin1().data() << endl; break; case QtWarningMsg: logfile << QTime::currentTime().toString().toLatin1().data() << " Warning: " << msg.toLatin1().data() << endl; break; case QtFatalMsg: logfile << QTime::currentTime().toString().toLatin1().data() << " Fatal: " << msg.toLatin1().data() << endl; break; } } void startFileLog() { #ifdef _DEBUG QString currentPath = QDir::currentPath() + "/chessx.log"; logfile.open(currentPath.toLatin1().data(), ios::app); bDoLog = true; #if QT_VERSION < 0x050000 qInstallMsgHandler(SimpleLoggingHandler); #else qInstallMessageHandler(SimpleLoggingHandler); #endif #endif } void stopFileLog() { if(bDoLog) { bDoLog = false; logfile.close(); } } chessx-1.0.0/src/gui/mainwindow.cpp000644 001750 001750 00000144630 12232007277 020056 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2009 by Michal Rudolf mrudolf@kdewebdev.org * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "analysiswidget.h" #include "boardsetup.h" #include "boardview.h" #include "copydialog.h" #include "chessbrowser.h" #include "commentdialog.h" #include "databaseinfo.h" #include "databaselist.h" #include "dockwidgetex.h" #include "downloadmanager.h" #include "ecolistwidget.h" #include "ecothread.h" #include "eventlistwidget.h" #include "filtermodel.h" #include "game.h" #include "gamelist.h" #include "helpbrowser.h" #include "loadquery.h" #include "mainwindow.h" #include "messagedialog.h" #include "memorydatabase.h" #include "openingtree.h" #include "openingtreewidget.h" #include "output.h" #include "pgndatabase.h" #include "playerlistwidget.h" #include "preferences.h" #include "quazip.h" #include "quazipfile.h" #include "savedialog.h" #include "settings.h" #include "tablebase.h" #include "tableview.h" #include "toolmainwindow.h" #include "version.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include MainWindow::MainWindow() : QMainWindow(), m_saveDialog(0), m_gameWindow(0), m_gameToolBar(0), m_output(0), m_autoPlayTimer(0), m_bGameChange(false), m_currentFrom(InvalidSquare), m_currentTo(InvalidSquare) { setObjectName("MainWindow"); m_autoPlayTimer = new QTimer(this); m_autoPlayTimer->setInterval(3000); m_autoPlayTimer->setSingleShot(true); connect(m_autoPlayTimer, SIGNAL(timeout()), this, SLOT(slotAutoPlayTimeout())); /* Create clipboard database */ m_databases.append(new DatabaseInfo); m_currentDatabase = 0; /* Actions */ m_actions = new QActionGroup(this); m_actions->setExclusive(false); setupActions(); /* Delete on close */ setAttribute(Qt::WA_DeleteOnClose); /* Board */ m_boardSplitter = new QSplitter(Qt::Horizontal); m_boardSplitter->setChildrenCollapsible(false); setCentralWidget(m_boardSplitter); m_tabWidget = new QTabWidget(this); m_tabWidget->setObjectName("BoardView"); m_tabWidget->setTabsClosable(true); QToolButton* button = new QToolButton(); button->setIcon(style()->standardIcon(QStyle::SP_FileIcon)); m_tabWidget->setCornerWidget(button); connect(button, SIGNAL(clicked()), SLOT(slotCreateBoardView())); connect(m_tabWidget, SIGNAL(tabCloseRequested(int)), SLOT(slotCloseBoardView(int))); connect(m_tabWidget, SIGNAL(currentChanged(int)), SLOT(slotActivateBoardView(int))); /* Board layout */ m_boardSplitter->addWidget(m_tabWidget); /* Game view */ DockWidgetEx* gameTextDock = new DockWidgetEx(tr("Game Text"), this); gameTextDock->setObjectName("GameTextDock"); gameTextDock->setFeatures(QDockWidget::NoDockWidgetFeatures); m_gameWindow = new ToolMainWindow(gameTextDock); m_gameWindow->setObjectName("GameWindow"); connect(this, SIGNAL(reconfigure()), m_gameWindow, SLOT(slotReconfigure())); m_gameToolBar = new QToolBar(tr("Game Time"), m_gameWindow); m_gameToolBar->setObjectName("GameToolBar"); m_gameToolBar->setMovable(false); m_gameWindow->addToolBar(Qt::BottomToolBarArea, m_gameToolBar); for(int i = 0; i < 2; ++i) { QLCDNumber* annotatedTime = new QLCDNumber(m_gameToolBar); annotatedTime->setObjectName(QString("Clock") + QString::number(i)); m_gameToolBar->addWidget(annotatedTime); annotatedTime->setDigitCount(7); annotatedTime->display("1:00:00"); if(i == 0) { QWidget* spacer = new QWidget(); spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_gameToolBar->addWidget(spacer); } } m_menuView->addAction(m_gameToolBar->toggleViewAction()); m_gameToolBar->setVisible(AppSettings->getValue("/MainWindow/GameToolBar").toBool()); m_gameView = new ChessBrowser(m_gameWindow, true); m_gameView->toolBar = m_gameToolBar; m_gameView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_gameView->setMinimumSize(200, 200); m_gameView->slotReconfigure(); connect(m_gameView, SIGNAL(anchorClicked(const QUrl&)), SLOT(slotGameViewLink(const QUrl&))); connect(m_gameView, SIGNAL(actionRequested(EditAction)), SLOT(slotGameModify(EditAction))); connect(m_gameView, SIGNAL(queryActiveGame(const Game**)), this, SLOT(slotGetActiveGame(const Game**))); connect(m_gameView, SIGNAL(signalMergeGame(int)), this, SLOT(slotMergeActiveGame(int))); connect(this, SIGNAL(displayTime(const QString&, Color)), m_gameView, SLOT(slotDisplayTime(const QString&, Color))); gameTextDock->setWidget(m_gameWindow); m_gameWindow->setCentralWidget(m_gameView); connect(this, SIGNAL(reconfigure()), m_gameView, SLOT(slotReconfigure())); addDockWidget(Qt::RightDockWidgetArea, gameTextDock); m_gameTitle = new QLabel; connect(m_gameTitle, SIGNAL(linkActivated(QString)), this, SLOT(slotGameViewLink(QString))); gameTextDock->setTitleBarWidget(m_gameTitle); /* Game List */ DockWidgetEx* gameListDock = new DockWidgetEx(tr("Game List"), this); gameListDock->setObjectName("GameList"); m_gameList = new GameList(databaseInfo()->filter(), gameListDock); m_gameList->setMinimumSize(150, 100); connect(m_gameList, SIGNAL(selected(int)), SLOT(slotFilterLoad(int))); connect(m_gameList, SIGNAL(searchDone()), SLOT(slotFilterChanged())); connect(m_gameList, SIGNAL(requestCopyGame(int)), SLOT(slotDatabaseCopySingle(int))); connect(m_gameList, SIGNAL(requestMergeGame(int)), SLOT(slotMergeActiveGame(int))); connect(m_gameList, SIGNAL(requestMergeAllGames()), SLOT(slotMergeAllGames())); connect(m_gameList, SIGNAL(requestMergeFilter()), SLOT(slotMergeFilter())); connect(m_gameList, SIGNAL(requestDeleteGame(int)), SLOT(slotDatabaseDeleteGame(int))); connect(m_gameList, SIGNAL(requestGameData(Game&)), SLOT(slotGetGameData(Game&))); connect(this, SIGNAL(reconfigure()), m_gameList, SLOT(slotReconfigure())); gameListDock->setWidget(m_gameList); addDockWidget(Qt::RightDockWidgetArea, gameListDock); m_menuView->addAction(gameListDock->toggleViewAction()); gameListDock->toggleViewAction()->setShortcut(Qt::CTRL + Qt::Key_L); connect(m_gameList, SIGNAL(raiseRequest()), gameListDock, SLOT(raise())); // Player List DockWidgetEx* playerListDock = new DockWidgetEx(tr("Players"), this); playerListDock->setObjectName("PlayerList"); m_playerList = new PlayerListWidget(this); m_playerList->setMinimumSize(150, 100); playerListDock->setWidget(m_playerList); addDockWidget(Qt::RightDockWidgetArea, playerListDock); m_menuView->addAction(playerListDock->toggleViewAction()); playerListDock->toggleViewAction()->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_P); connect(m_playerList, SIGNAL(raiseRequest()), playerListDock, SLOT(raise())); connect(m_playerList, SIGNAL(filterRequest(QString)), m_gameList, SLOT(slotFilterListByPlayer(QString))); connect(m_playerList, SIGNAL(renameRequest(QString)), SLOT(slotRenamePlayer(QString))); connect(m_playerList, SIGNAL(filterEcoPlayerRequest(QString, QString, QString)), m_gameList, SLOT(slotFilterListByEcoPlayer(QString, QString, QString))); connect(this, SIGNAL(databaseChanged(DatabaseInfo*)), m_playerList, SLOT(setDatabase(DatabaseInfo*))); connect(this, SIGNAL(reconfigure()), m_playerList, SLOT(slotReconfigure())); playerListDock->hide(); // Event List DockWidgetEx* eventListDock = new DockWidgetEx(tr("Events"), this); eventListDock->setObjectName("EventList"); m_eventList = new EventListWidget(this); m_eventList->setMinimumSize(150, 100); eventListDock->setWidget(m_eventList); addDockWidget(Qt::RightDockWidgetArea, eventListDock); m_menuView->addAction(eventListDock->toggleViewAction()); eventListDock->toggleViewAction()->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_P); connect(m_eventList, SIGNAL(raiseRequest()), eventListDock, SLOT(raise())); connect(m_eventList, SIGNAL(filterRequest(QString)), m_gameList, SLOT(slotFilterListByEvent(QString))); connect(m_eventList, SIGNAL(renameRequest(QString)), SLOT(slotRenameEvent(QString))); connect(m_eventList, SIGNAL(filterEventPlayerRequest(QString, QString)), m_gameList, SLOT(slotFilterListByEventPlayer(QString, QString))); connect(m_eventList, SIGNAL(filterEventPlayerRequest(QString, QString)), m_playerList, SLOT(slotSelectPlayer(QString))); connect(this, SIGNAL(databaseChanged(DatabaseInfo*)), m_eventList, SLOT(setDatabase(DatabaseInfo*))); connect(this, SIGNAL(reconfigure()), m_eventList, SLOT(slotReconfigure())); eventListDock->hide(); // ECO List DockWidgetEx* ecoListDock = new DockWidgetEx(tr("ECO"), this); ecoListDock->setObjectName("EcoList"); m_ecoList = new ECOListWidget(this); m_ecoList->setMinimumSize(150, 100); ecoListDock->setWidget(m_ecoList); addDockWidget(Qt::RightDockWidgetArea, ecoListDock); m_menuView->addAction(ecoListDock->toggleViewAction()); ecoListDock->toggleViewAction()->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_E); connect(m_ecoList, SIGNAL(raiseRequest()), ecoListDock, SLOT(raise())); connect(m_ecoList, SIGNAL(filterRequest(QString)), m_gameList, SLOT(slotFilterListByEco(QString))); connect(m_ecoList, SIGNAL(filterEcoPlayerRequest(QString, QString, QString)), m_gameList, SLOT(slotFilterListByEcoPlayer(QString, QString, QString))); connect(m_ecoList, SIGNAL(filterEcoPlayerRequest(QString, QString)), m_playerList, SLOT(slotSelectPlayer(QString))); connect(this, SIGNAL(databaseChanged(DatabaseInfo*)), m_ecoList, SLOT(setDatabase(DatabaseInfo*))); connect(this, SIGNAL(reconfigure()), m_ecoList, SLOT(slotReconfigure())); ecoListDock->hide(); // Database List DockWidgetEx* dbListDock = new DockWidgetEx(tr("Databases"), this); dbListDock->setObjectName("Databases"); m_databaseList = new DatabaseList(this); m_databaseList->setMinimumSize(150, 100); dbListDock->setWidget(m_databaseList); addDockWidget(Qt::RightDockWidgetArea, dbListDock); m_menuView->addAction(dbListDock->toggleViewAction()); dbListDock->toggleViewAction()->setShortcut(Qt::CTRL + Qt::Key_D); connect(m_databaseList, SIGNAL(requestOpenDatabase(QString, bool)), this, SLOT(openDatabaseUrl(QString, bool))); connect(m_databaseList, SIGNAL(requestCloseDatabase(QString)), this, SLOT(slotFileCloseName(QString))); connect(m_databaseList, SIGNAL(requestLinkDatabase(QString)), this, SLOT(setFavoriteDatabase(QString))); connect(m_databaseList, SIGNAL(requestAppendGame(QString, int)), this, SLOT(copyGame(QString, int))); connect(m_databaseList, SIGNAL(requestAppendDatabase(QString, QString)), this, SLOT(copyDatabase(QString, QString))); connect(this, SIGNAL(reconfigure()), m_databaseList, SLOT(slotReconfigure())); m_databaseList->addFileOpen(QString(), false); m_databaseList->setFileCurrent(QString()); restoreRecentFiles(); /* Recent files */ m_recentFiles.restore(); m_recentFiles.removeMissingFiles(); updateMenuRecent(); /* Opening Tree */ DockWidgetEx* openingDock = new DockWidgetEx(tr("Opening Tree"), this); openingDock->setObjectName("OpeningTreeDock"); m_openingTreeWidget = new OpeningTreeWidget(this); openingDock->setWidget(m_openingTreeWidget); addDockWidget(Qt::RightDockWidgetArea, openingDock); m_menuView->addAction(openingDock->toggleViewAction()); connect(openingDock->toggleViewAction(), SIGNAL(triggered()), SLOT(slotSearchTree())); connect(openingDock, SIGNAL(visibilityChanged(bool)), m_openingTreeWidget, SLOT(cancel(bool))); openingDock->toggleViewAction()->setShortcut(Qt::CTRL + Qt::Key_T); openingDock->hide(); /* Analysis Dock */ DockWidgetEx* analysisDock = new DockWidgetEx(tr("Analysis 1"), this); analysisDock->setObjectName("AnalysisDock1"); AnalysisWidget* analysis = new AnalysisWidget; analysis->setObjectName("Analysis"); analysisDock->setWidget(analysis); addDockWidget(Qt::RightDockWidgetArea, analysisDock); connect(analysis, SIGNAL(addVariation(Analysis)), SLOT(slotGameAddVariation(Analysis))); connect(analysis, SIGNAL(addVariation(QString)), SLOT(slotGameAddVariation(QString))); connect(this, SIGNAL(boardChange(const Board&)), analysis, SLOT(setPosition(const Board&))); connect(this, SIGNAL(reconfigure()), analysis, SLOT(slotReconfigure())); // Make sure engine is disabled if dock is hidden connect(analysisDock, SIGNAL(visibilityChanged(bool)), analysis, SLOT(slotVisibilityChanged(bool))); m_menuView->addAction(analysisDock->toggleViewAction()); analysisDock->toggleViewAction()->setShortcut(Qt::CTRL + Qt::Key_F2); analysisDock->hide(); m_mainAnalysis = analysis; /* Analysis Dock 2 */ DockWidgetEx* analysisDock2 = new DockWidgetEx(tr("Analysis 2"), this); analysisDock2->setObjectName("AnalysisDock2"); analysis = new AnalysisWidget; analysis->setObjectName("Analysis2"); analysisDock2->setWidget(analysis); addDockWidget(Qt::RightDockWidgetArea, analysisDock2); connect(analysis, SIGNAL(addVariation(Analysis)), SLOT(slotGameAddVariation(Analysis))); connect(analysis, SIGNAL(addVariation(QString)), SLOT(slotGameAddVariation(QString))); connect(this, SIGNAL(boardChange(const Board&)), analysis, SLOT(setPosition(const Board&))); connect(this, SIGNAL(reconfigure()), analysis, SLOT(slotReconfigure())); // Make sure engine is disabled if dock is hidden connect(analysisDock2, SIGNAL(visibilityChanged(bool)), analysis, SLOT(slotVisibilityChanged(bool))); m_menuView->addAction(analysisDock2->toggleViewAction()); analysisDock2->toggleViewAction()->setShortcut(Qt::CTRL + Qt::Key_F3); analysisDock2->hide(); /* Randomize */ srand(time(0)); /* Restoring layouts */ if(!AppSettings->layout(this)) { resize(800, 600); } AppSettings->beginGroup("/MainWindow/"); m_boardSplitter->restoreState(AppSettings->value("BoardSplit").toByteArray()); m_gameList->m_FilterActive = AppSettings->getValue("FilterFollowsGame").toBool(); AppSettings->endGroup(); m_toggleFilter->setChecked(m_gameList->m_FilterActive); /* Status */ m_statusFilter = new QLabel(); statusBar()->addPermanentWidget(m_statusFilter); statusBar()->setFixedHeight(statusBar()->height()); statusBar()->setSizeGripEnabled(true); m_progressBar = new QProgressBar; /* Reconfigure. */ slotReconfigure(); /* Very late as this will update other widgets */ connect(this, SIGNAL(databaseModified()), SLOT(slotDatabaseModified())); CreateBoardView(); /* Display main window */ show(); /* Load files from command line */ QStringList args = qApp->arguments(); for(int i = 1; i < args.count(); i++) if(QFile::exists(args[i])) { openDatabaseUrl(args[i], false); } qApp->installEventFilter(this); /* Activate clipboard */ updateMenuDatabases(); slotDatabaseChanged(); emit signalGameIsEmpty(true); QString dir = AppSettings->commonDataPath(); QDir().mkpath(dir + "/index"); /* Load ECO file */ slotStatusMessage(tr("Loading ECO file...")); EcoThread* ecothread = new EcoThread(); connect(ecothread, SIGNAL(loaded(QObject*, bool)), this, SLOT(ecoLoaded(QObject*, bool))); ecothread->start(); StartCheckUpdate(); downloadManager = new DownloadManager(this); } MainWindow::~MainWindow() { m_autoPlayTimer->stop(); m_openingTreeWidget->cancel(false); foreach(DatabaseInfo * database, m_databases) { database->close(); } qDeleteAll(m_databases.begin(), m_databases.end()); delete m_saveDialog; delete m_output; m_boardViews.clear(); // Widgets are deleted by Qt } bool MainWindow::eventFilter(QObject *obj, QEvent *event) { if(event->type() == QEvent::FileOpen) { openDatabaseUrl(static_cast(event)->file(), false); return true; } else { if((obj == this) && (event->type() == QEvent::KeyPress)) { QKeyEvent* keyEvent = static_cast(event); if(keyEvent && (keyEvent->key() == Qt::Key_Escape || keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter)) { keyPressEvent(keyEvent); return true; } } // standard event processing return QObject::eventFilter(obj, event); } } void MainWindow::ecoLoaded(QObject* ecoThread, bool ok) { slotStatusMessage(ok ? tr("ECO Loaded.") : tr("ECO Load Error.")); qobject_cast(ecoThread)->wait(); delete ecoThread; } void MainWindow::closeEvent(QCloseEvent* e) { if(confirmQuit()) { m_recentFiles.save(); m_databaseList->save(); m_gameList->saveConfig(); m_databaseList->saveConfig(); m_openingTreeWidget->saveConfig(); m_gameWindow->saveConfig(); m_gameView->saveConfig(); AppSettings->setLayout(this); AppSettings->beginGroup("/MainWindow/"); AppSettings->setValue("BoardSplit", m_boardSplitter->saveState()); AppSettings->setValue("FilterFollowsGame", m_gameList->m_FilterActive); AppSettings->setValue("GameToolBar", m_gameToolBar->isVisible()); AppSettings->endGroup(); } else { e->ignore(); } } void MainWindow::keyPressEvent(QKeyEvent *e) { if((e->key() == Qt::Key_Escape) || (e->key() == Qt::Key_Backspace)) { m_nagText.clear(); return; } if(game().atGameStart()) { return; } if(e->key() == Qt::Key_Delete) { game().clearNags(); slotGameChanged(); return; } if(e->text().isEmpty()) { return; } bool enterPressed = (e->key() == Qt::Key_X || (e->key() == Qt::Key_Enter) || (e->key() == Qt::Key_Return)); if(!enterPressed) { m_nagText.append(e->text()); } int matches = NagSet::prefixCount(m_nagText); if(matches == 0) { m_nagText.clear(); } else if(matches == 1 || enterPressed) { game().addNag(NagSet::fromString(m_nagText)); slotGameChanged(); } } DatabaseInfo* MainWindow::databaseInfo() { return m_databases[m_currentDatabase]; } const DatabaseInfo* MainWindow::databaseInfo() const { return m_databases[m_currentDatabase]; } Database* MainWindow::database() { return databaseInfo()->database(); } QString MainWindow::databaseName(int index) const { if(index < 0) { index = m_currentDatabase; } QString name = m_databases[index]->database()->name(); if(name.isEmpty()) { return tr("[Clipboard]"); } return name; } Database* MainWindow::getDatabaseByPath(QString path) { if(DatabaseInfo* dbInfo = getDatabaseInfoByPath(path)) { if(dbInfo->isValid()) { return dbInfo->database(); } } return 0; } DatabaseInfo* MainWindow::getDatabaseInfoByPath(QString path) { for(int i = 0; i < m_databases.count(); ++i) { if(m_databases[i]->filePath() == path) { return m_databases[i]; } } return 0; } Game& MainWindow::game() { return databaseInfo()->currentGame(); } const Game& MainWindow::game() const { return databaseInfo()->currentGame(); } int MainWindow::gameIndex() const { return databaseInfo()->currentIndex(); } void MainWindow::gameLoad(int index, bool force, bool reload) { if(QuerySaveGame()) { if(databaseInfo()->loadGame(index, reload)) { m_gameList->selectGame(index); emit signalGameIsEmpty(true); } else if(!force) { return; } else { databaseInfo()->newGame(); m_gameList->clearSelection(); } slotGameChanged(); emit signalFirstGameLoaded(databaseInfo()->filter()->previousGame(index) == -1); emit signalLastGameLoaded(databaseInfo()->filter()->nextGame(index) == -1); } } bool MainWindow::gameMoveBy(int change) { if(game().moveByPly(change)) { if(m_training->isChecked()) { slotGameChanged(); } else { slotMoveChanged(); } m_gameView->setFocus(); return true; } return false; } void MainWindow::updateMenuRecent() { for(int i = 0; (i < m_recentFiles.count()) && (i < MaxRecentFiles); ++i) { m_recentFileActions[i]->setVisible(true); m_recentFileActions[i]->setText(QString("&%1: %2").arg(i + 1).arg(m_recentFiles[i])); m_recentFileActions[i]->setData(m_recentFiles[i]); } for(int i = m_recentFiles.count(); i < MaxRecentFiles; i++) { m_recentFileActions[i]->setVisible(false); } } void MainWindow::updateMenuDatabases() { while(m_databases.count() > m_databaseActions.count()) { QAction* action = new QAction(this); connect(action, SIGNAL(triggered()), SLOT(slotDatabaseChange())); m_databaseActions.append(action); m_menuDatabases->addAction(action); } int n = 1; for(int i = 0; i < m_databases.count(); i++) { if(m_databases[i]->isValid()) { m_databaseActions[i]->setVisible(true); m_databaseActions[i]->setData(i); m_databaseActions[i]->setText(QString("&%1: %2").arg(i).arg(databaseName(i))); if(n < 10) { int key = Qt::CTRL + Qt::SHIFT + Qt::Key_1 + (n - 1); m_databaseActions[i]->setShortcut(key); ++n; } } } for(int i = m_databases.count(); i < m_databaseActions.count(); i++) { m_databaseActions[i]->setVisible(false); m_databaseActions[i]->setShortcut(0); } } void MainWindow::setFavoriteDatabase(QString fname) { QUrl url = QUrl::fromUserInput(fname); if((url.scheme() == "http") || (url.scheme() == "ftp")) { m_databaseList->setFileFavorite(fname, true, 0); } else { m_databaseList->setFileFavorite(url.toLocalFile(), true, 0); } } void MainWindow::openDatabase(QString fname) { openDatabaseUrl(fname, false); } void MainWindow::openDatabaseUrl(QString fname, bool utf8) { if(QuerySaveGame()) { QUrl url = QUrl::fromUserInput(fname); if((url.scheme() == "http") || (url.scheme() == "https") || (url.scheme() == "ftp")) { connect(downloadManager, SIGNAL(downloadError(QUrl)), this, SLOT(loadError(QUrl))); connect(downloadManager, SIGNAL(onDownloadFinished(QUrl, QString)), this, SLOT(loadReady(QUrl, QString))); downloadManager->doDownload(url); return; } openDatabaseArchive(url.toLocalFile(), utf8); } } void MainWindow::openDatabaseArchive(QString fname, bool utf8) { QFileInfo fi = QFileInfo(fname); if(fname.isEmpty() || fi.suffix().toLower() == "pgn") { openDatabaseFile(fname, utf8); } else { QString dataPath = AppSettings->getUserDataPath(); QString dir = AppSettings->value("/General/DefaultDataPath", dataPath).toString(); fname = fi.canonicalFilePath(); if(!fname.isEmpty()) { QuaZip zip(fname); if(zip.open(QuaZip::mdUnzip)) { // first, we need some information about archive itself QString comment = zip.getComment(); // and now we are going to access files inside it QuaZipFile file(&zip); for(bool more = zip.goToFirstFile(); more; more = zip.goToNextFile()) { file.open(QIODevice::ReadOnly); QString outName = dir + "/" + file.getActualFileName(); QDir pathOut; outName = pathOut.absoluteFilePath(outName); if(!QFile::exists(outName)) { QDir().mkpath(dir); QFile out(outName); if(out.open(QIODevice::WriteOnly)) { out.write(file.readAll()); out.close(); openDatabaseFile(outName, utf8); } else { qDebug() << "File Error: " << out.error(); } } else { openDatabaseFile(outName, utf8); } file.close(); } zip.close(); } } } } void MainWindow::openDatabaseFile(QString fname, bool utf8) { QFileInfo fi = QFileInfo(fname); fname = fi.canonicalFilePath(); /* Check if the database isn't already open */ for(int i = 0; i < m_databases.count(); i++) { if(m_databases[i]->database()->filename() == fname) { if(m_databases[i]->isValid()) { m_currentDatabase = i; m_boardView->setDbIndex(m_currentDatabase); UpdateBoardInformation(); m_databaseList->setFileCurrent(fname); slotDatabaseChanged(); } else { slotStatusMessage(tr("Database %1 cannot be accessed at the moment.").arg(fi.fileName())); } return; } } // Create database, connect progress bar and open file DatabaseInfo* db = new DatabaseInfo(fname); QString basefile = fi.completeBaseName(); startOperation(tr("Opening %1...").arg(basefile)); connect(db->database(), SIGNAL(progress(int)), SLOT(slotOperationProgress(int))); connect(db, SIGNAL(LoadFinished(DatabaseInfo*)), this, SLOT(slotDataBaseLoaded(DatabaseInfo*))); if(!db->open(utf8)) { slotDataBaseLoaded(db); } else { m_databases.append(db); } } void MainWindow::loadError(QUrl url) { QFileInfo fi = QFileInfo(url.toString()); slotStatusMessage(tr("Database %1 cannot be accessed at the moment (%2).").arg(fi.fileName()).arg(url.errorString())); } void MainWindow::loadReady(QUrl /*url*/, QString fileName) { openDatabaseArchive(fileName, false); } void MainWindow::slotDataBaseLoaded(DatabaseInfo* db) { if(!db->IsLoaded()) { cancelOperation(tr("Cannot open file")); m_databases.removeOne(db); delete db; return; } QString fname = db->filePath(); QFileInfo fi = QFileInfo(fname); QString basefile = fi.completeBaseName(); m_databaseList->addFileOpen(fname, db->IsUtf8()); finishOperation(tr("%1 opened").arg(basefile)); for(int i = 0; i < m_databases.count(); i++) { if(m_databases[i]->database()->filename() == fname) { m_currentDatabase = i; m_boardView->setDbIndex(m_currentDatabase); UpdateBoardInformation(); } } m_databaseList->setFileCurrent(fname); m_recentFiles.append(fname); updateMenuRecent(); updateMenuDatabases(); slotDatabaseChanged(); } QString MainWindow::exportFileName(int& format) { QFileDialog fd(this); fd.setAcceptMode(QFileDialog::AcceptSave); fd.setFileMode(QFileDialog::AnyFile); fd.setWindowTitle(tr("Export games")); fd.setViewMode(QFileDialog::Detail); fd.setDirectory(QDir::homePath()); QStringList filters; filters << tr("PGN file (*.pgn)") << tr("HTML page (*.html)") << tr("LaTeX document (*.tex)"); #if QT_VERSION < 0x050000 fd.setFilters(filters); #else fd.setNameFilters(filters); #endif if(fd.exec() != QDialog::Accepted) { return QString(); } #if QT_VERSION < 0x050000 if(fd.selectedFilter().contains("*.tex")) { format = Output::Latex; } else if(fd.selectedFilter().contains("*.html")) { format = Output::Html; } #else if(fd.selectedNameFilter().contains("*.tex")) { format = Output::Latex; } else if(fd.selectedNameFilter().contains("*.html")) { format = Output::Html; } #endif else { format = Output::Pgn; } return fd.selectedFiles().first(); } bool MainWindow::gameEditComment(Output::CommentType type) { QString annotation; int moves; int comments; int nags; game().moveCount(&moves, &comments, &nags); if((type == Output::Precomment) || (moves <= 0)) { annotation = game().annotation(CURRENT_MOVE, Game::BeforeMove); } else { annotation = game().annotation(); } CommentDialog dlg(this); dlg.setText(annotation); if(!dlg.exec()) { return false; } if((type == Output::Precomment) || (moves <= 0)) { if(moves > 0) { game().setAnnotation(dlg.text(), CURRENT_MOVE, Game::BeforeMove); } else { game().setGameComment(dlg.text()); } } else { game().setAnnotation(dlg.text()); } return true; } SaveDialog* MainWindow::saveDialog() { if(!m_saveDialog) { m_saveDialog = new SaveDialog(this); } return m_saveDialog; } QAction* MainWindow::createAction(const QString& name, const char* slot, const QKeySequence& key, QToolBar* pToolBar, QString image, const QString& tip, QAction::MenuRole menuRole) { QAction* action = new QAction(name, m_actions); if(!tip.isEmpty()) { action->setStatusTip(tip); } if(!key.isEmpty()) { action->setShortcut(key); } if(slot) { connect(action, SIGNAL(triggered()), slot); } action->setMenuRole(menuRole); if(!image.isEmpty()) { action->setIcon(QIcon(image)); } if(pToolBar) { pToolBar->addAction(action); } return action; } void MainWindow::setupActions() { /* File menu */ QMenu* file = menuBar()->addMenu(tr("&File")); QToolBar* fileToolBar = addToolBar(tr("File")); fileToolBar->setObjectName("FileToolBar"); file->addAction(createAction(tr("&New database..."), SLOT(slotFileNew()), QKeySequence(), fileToolBar, ":/images/new.png")); file->addAction(createAction(tr("&Open..."), SLOT(slotFileOpen()), QKeySequence::Open, fileToolBar, ":/images/folder_open.png")); file->addAction(createAction(tr("Open in UTF8..."), SLOT(slotFileOpenUtf8()), QKeySequence())); QMenu* menuRecent = file->addMenu(tr("Open &recent...")); for(int i = 0; i < MaxRecentFiles; ++i) { QAction* action = new QAction(this); action->setVisible(false); connect(action, SIGNAL(triggered()), SLOT(slotFileOpenRecent())); m_recentFileActions.append(action); menuRecent->addAction(action); } file->addSeparator(); QAction* commitAction = createAction(tr("&Save"), SLOT(slotFileSave()), Qt::CTRL + Qt::SHIFT + Qt::Key_S, fileToolBar, ":/images/save.png"); commitAction->setToolTip(tr("Commit Database to disk")); connect(this, SIGNAL(signalCurrentDBisReadWrite(bool)), commitAction, SLOT(setEnabled(bool))); file->addAction(commitAction); QMenu* exportMenu = file->addMenu(tr("&Export...")); connect(this, SIGNAL(signalCurrentDBhasGames(bool)), exportMenu, SLOT(setEnabled(bool))); exportMenu->addAction(createAction(tr("Current Game"), SLOT(slotFileExportGame()))); exportMenu->addAction(createAction(tr("&Games in filter"), SLOT(slotFileExportFilter()))); exportMenu->addAction(createAction(tr("&All games"), SLOT(slotFileExportAll()))); file->addSeparator(); QAction* closeFileAction = createAction(tr("&Close"), SLOT(slotFileClose()), QKeySequence::Close, fileToolBar, ":/images/folder.png"); connect(this, SIGNAL(signalCurrentDBcanBeClosed(bool)), closeFileAction, SLOT(setEnabled(bool))); file->addAction(closeFileAction); file->addAction(createAction(tr("&Quit"), SLOT(slotFileQuit()), QKeySequence(), 0, QString(), QString(), QAction::QuitRole)); /* Edit menu */ QMenu* edit = menuBar()->addMenu(tr("&Edit")); QToolBar* editToolBar = addToolBar(tr("Edit")); editToolBar->setObjectName("EditToolBar"); edit->addAction(createAction(tr("Comment"), SLOT(slotEditComment()), Qt::CTRL + Qt::Key_A, editToolBar, ":/images/edit_after.png")); edit->addAction(createAction(tr("Comment Before"), SLOT(slotEditCommentBefore()), Qt::CTRL + Qt::ALT + Qt::Key_A)); QMenu* editVariation = edit->addMenu(tr("Variation")); QAction* promoteAction = createAction(tr("Promote"), SLOT(slotEditVarPromote()), Qt::CTRL + Qt::Key_J, editToolBar, ":/images/format_indent_less.png"); promoteAction->setToolTip(tr("Promote Variation")); connect(this, SIGNAL(signalMoveHasParent(bool)), promoteAction, SLOT(setEnabled(bool))); editVariation->addAction(promoteAction); QAction* removeVariationAction = createAction(tr("Remove"), SLOT(slotEditVarRemove()), Qt::CTRL + Qt::Key_Delete, editToolBar, ":/images/edit_cut.png"); removeVariationAction->setToolTip(tr("Remove Variation")); connect(this, SIGNAL(signalMoveHasParent(bool)), removeVariationAction, SLOT(setEnabled(bool))); editVariation->addAction(removeVariationAction); QMenu* editremove = edit->addMenu(tr("&Remove")); editremove->addAction(createAction(tr("Moves from the beginning"), SLOT(slotEditTruncateStart()), QKeySequence())); editremove->addAction(createAction(tr("Moves to the end"), SLOT(slotEditTruncateEnd()), Qt::SHIFT + Qt::Key_Delete)); edit->addSeparator(); QAction* setupBoard = createAction(tr("Setup &position..."), SLOT(slotEditBoard()), Qt::SHIFT + Qt::CTRL + Qt::Key_E, editToolBar, ":/images/setup_board.png"); edit->addAction(setupBoard); edit->addSeparator(); edit->addAction(createAction(tr("Copy PGN"), SLOT(slotEditCopyPGN()), Qt::CTRL + Qt::Key_C, editToolBar, ":/images/edit_copy.png")); edit->addAction(createAction(tr("Copy FEN"), SLOT(slotEditCopyFEN()), Qt::CTRL + Qt::SHIFT + Qt::Key_C)); edit->addAction(createAction(tr("Copy Position"), SLOT(slotEditCopyHumanFEN()))); edit->addAction(createAction(tr("Copy Image"), SLOT(slotEditCopyImage()), Qt::CTRL + Qt::ALT + Qt::Key_C, editToolBar, ":/images/camera.png")); edit->addSeparator(); edit->addAction(createAction(tr("&Paste"), SLOT(slotEditPaste()), Qt::CTRL + Qt::Key_V, editToolBar, ":/images/edit_paste.png")); edit->addSeparator(); edit->addAction(createAction(tr("&Preferences..."), SLOT(slotConfigure()), QKeySequence(), 0, QString(), QString(), QAction::PreferencesRole)); /* View menu */ m_menuView = menuBar()->addMenu(tr("&View")); QToolBar* viewToolBar = addToolBar(tr("View")); viewToolBar->setObjectName("ViewToolBar"); QMenu* toolbars = m_menuView->addMenu(tr("Toolbars")); m_menuView->addSeparator(); #if defined(Q_OS_WIN) QAction* stayOnTop = createAction(tr("Stay on Top"), SLOT(slotToggleStayOnTop())); stayOnTop->setCheckable(true); stayOnTop->setChecked(AppSettings->getValue("/MainWindow/StayOnTop").toBool()); m_menuView->addAction(stayOnTop); m_menuView->addSeparator(); #else AppSettings->setValue("/MainWindow/StayOnTop", false); #endif m_menuView->addAction(createAction(tr("New board"), SLOT(slotCreateBoardView()), Qt::CTRL + Qt::SHIFT + Qt::Key_N, viewToolBar, ":/images/new_board.png")); m_menuView->addAction(createAction(tr("Close current board"), SLOT(slotCloseBoardView()), Qt::CTRL + Qt::SHIFT + Qt::Key_W, viewToolBar, ":/images/close_board.png")); m_menuView->addSeparator(); /* Game menu */ QMenu *gameMenu = menuBar()->addMenu(tr("&Game")); QToolBar* gameToolBar = addToolBar(tr("Game")); gameToolBar->setObjectName("GameToolBarMain"); QToolBar* dbToolBar = addToolBar(tr("Database")); dbToolBar->setObjectName("DbToolBarMain"); QAction* newAction = createAction(tr("&New"), SLOT(slotGameNew()), QKeySequence::New, dbToolBar, ":/images/new_game.png"); gameMenu->addAction(newAction); connect(this, SIGNAL(signalGameIsEmpty(bool)), newAction, SLOT(setDisabled(bool))); QMenu* loadMenu = gameMenu->addMenu(tr("&Load")); /* Game->Load submenu */ QAction * nextAction = createAction(tr("&Next"), SLOT(slotGameLoadNext()), Qt::CTRL + Qt::SHIFT + Qt::Key_Down, dbToolBar, ":/images/game_down.png"); connect(this, SIGNAL(signalLastGameLoaded(bool)), nextAction, SLOT(setDisabled(bool))); loadMenu->addAction(nextAction); QAction * prevAction = createAction(tr("&Previous"), SLOT(slotGameLoadPrevious()), Qt::CTRL + Qt::SHIFT + Qt::Key_Up, dbToolBar, ":/images/game_up.png"); connect(this, SIGNAL(signalFirstGameLoaded(bool)), prevAction, SLOT(setDisabled(bool))); loadMenu->addAction(prevAction); loadMenu->addAction(createAction(tr("&Go to game..."), SLOT(slotGameLoadChosen()), Qt::CTRL + Qt::Key_G)); loadMenu->addAction(createAction(tr("&Random"), SLOT(slotGameLoadRandom()), Qt::CTRL + Qt::Key_Question)); gameMenu->addAction(createAction(tr("&Save...."), SLOT(slotGameSave()), QKeySequence::Save)); gameMenu->addSeparator(); m_training = createAction(tr("Training"), SLOT(slotToggleTraining()), Qt::CTRL + Qt::Key_R); m_training->setCheckable(true); gameMenu->addAction(m_training); m_autoPlay = createAction(tr("Auto Player"), SLOT(slotToggleAutoPlayer()), Qt::CTRL + Qt::SHIFT + Qt::Key_R, gameToolBar, ":/images/replay.png"); m_autoPlay->setCheckable(true); gameMenu->addAction(m_autoPlay); m_autoAnalysis = createAction(tr("Auto Analysis"), SLOT(slotToggleAutoAnalysis()), Qt::CTRL + Qt::ALT + Qt::Key_R); m_autoAnalysis->setCheckable(true); gameMenu->addAction(m_autoAnalysis); gameMenu->addSeparator(); QAction* flip = createAction(tr("&Flip board"), SLOT(slotConfigureFlip()), Qt::CTRL + Qt::Key_B); flip->setCheckable(true); gameMenu->addAction(flip); /* Game->Go to submenu */ QMenu* goMenu = gameMenu->addMenu(tr("&Go to")); QAction* gotoFirstMove = createAction(tr("&Start"), SLOT(slotGameMoveFirst()), Qt::Key_Home, gameToolBar, ":/images/first.png"); gotoFirstMove->setToolTip(tr("Go to first move")); connect(this, SIGNAL(signalMoveHasPreviousMove(bool)), gotoFirstMove, SLOT(setEnabled(bool))); goMenu->addAction(gotoFirstMove); QAction* gotoLastMove = createAction(tr("&End"), SLOT(slotGameMoveLast()), Qt::Key_End, gameToolBar, ":/images/last.png"); gotoLastMove->setToolTip(tr("Go to last move")); connect(this, SIGNAL(signalMoveHasNextMove(bool)), gotoLastMove, SLOT(setEnabled(bool))); goMenu->addAction(gotoLastMove); QAction* actionPrevMove = createAction(tr("&Previous move"), SLOT(slotGameMovePrevious()), Qt::Key_Left, gameToolBar, ":/images/prev.png"); connect(this, SIGNAL(signalMoveHasPreviousMove(bool)), actionPrevMove, SLOT(setEnabled(bool))); goMenu->addAction(actionPrevMove); QAction* actionNextMove = createAction(tr("&Next move"), SLOT(slotGameMoveNext()), Qt::Key_Right, gameToolBar, ":/images/next.png"); connect(this, SIGNAL(signalMoveHasNextMove(bool)), actionNextMove, SLOT(setEnabled(bool))); goMenu->addAction(actionNextMove); QAction* fiveMovesForward = createAction(tr("5 moves &forward"), SLOT(slotGameMoveNextN()), Qt::Key_Down); connect(this, SIGNAL(signalMoveHasNextMove(bool)), fiveMovesForward, SLOT(setEnabled(bool))); goMenu->addAction(fiveMovesForward); QAction* fiveMovesPrev = createAction(tr("5 moves &backward"), SLOT(slotGameMovePreviousN()), Qt::Key_Up); connect(this, SIGNAL(signalMoveHasPreviousMove(bool)), fiveMovesPrev, SLOT(setEnabled(bool))); goMenu->addAction(fiveMovesPrev); QAction* enterVariation = createAction(tr("Enter Variation"), SLOT(slotGameVarEnter()), Qt::CTRL + Qt::Key_Right, gameToolBar, ":/images/go_in.png"); connect(this, SIGNAL(signalMoveHasVariation(bool)), enterVariation, SLOT(setEnabled(bool))); goMenu->addAction(enterVariation); QAction* prevVariation = createAction(tr("Previous Variation"), SLOT(slotGameVarUp()), Qt::CTRL + Qt::Key_Up, gameToolBar, ":/images/go_up.png"); connect(this, SIGNAL(signalVariationHasSibling(bool)), prevVariation, SLOT(setEnabled(bool))); goMenu->addAction(prevVariation); QAction* nextVariation = createAction(tr("Next Variation"), SLOT(slotGameVarDown()), Qt::CTRL + Qt::Key_Down, gameToolBar, ":/images/go_down.png"); connect(this, SIGNAL(signalVariationHasSibling(bool)), nextVariation, SLOT(setEnabled(bool))); goMenu->addAction(nextVariation); QAction* backToMainLine = createAction(tr("Back to main line"), SLOT(slotGameVarExit()), Qt::CTRL + Qt::Key_Left, gameToolBar, ":/images/go_out.png"); connect(this, SIGNAL(signalMoveHasParent(bool)), backToMainLine, SLOT(setEnabled(bool))); goMenu->addAction(backToMainLine); gameMenu->addSeparator(); QMenu* refactorMenu = gameMenu->addMenu(tr("Refactor")); refactorMenu->addAction(createAction(tr("Uncomment"), SLOT(slotGameUncomment()))); refactorMenu->addAction(createAction(tr("Remove Variations"), SLOT(slotGameRemoveVariations()))); /* Search menu */ QMenu* search = menuBar()->addMenu(tr("Fi&nd")); QToolBar* searchToolBar = addToolBar(tr("Search")); searchToolBar->setObjectName("SearchToolBar"); QAction* actionFindTag = createAction(tr("Find &tag"), SLOT(slotSearchTag()), Qt::CTRL + Qt::SHIFT + Qt::Key_T, searchToolBar, ":/images/find_tag.png"); connect(this, SIGNAL(signalCurrentDBhasGames(bool)), actionFindTag, SLOT(setEnabled(bool))); search->addAction(actionFindTag); QAction* actionFindBoard = createAction(tr("Find &position"), SLOT(slotSearchBoard()), Qt::CTRL + Qt::SHIFT + Qt::Key_B, searchToolBar, ":/images/find_pos.png"); connect(this, SIGNAL(signalCurrentDBhasGames(bool)), actionFindBoard, SLOT(setEnabled(bool))); search->addAction(actionFindBoard); search->addSeparator(); m_toggleFilter = createAction(tr("&Enable filter"), SLOT(slotToggleFilter()), Qt::CTRL + Qt::ALT + Qt::Key_F, searchToolBar, ":/images/filter.png"); m_toggleFilter->setCheckable(true); connect(this, SIGNAL(signalCurrentDBhasGames(bool)), m_toggleFilter, SLOT(setEnabled(bool))); search->addAction(m_toggleFilter); QAction* filterReset = createAction(tr("&Reset filter"), SLOT(slotSearchReset()), Qt::CTRL + Qt::Key_F, searchToolBar, ":/images/filter_reset.png"); connect(this, SIGNAL(signalCurrentDBhasGames(bool)), filterReset, SLOT(setEnabled(bool))); search->addAction(filterReset); QAction* reverseFilter = createAction(tr("&Reverse filter"), SLOT(slotSearchReverse()), Qt::CTRL + Qt::SHIFT + Qt::Key_F, searchToolBar, ":/images/filter_rev.png"); connect(this, SIGNAL(signalCurrentDBhasGames(bool)), reverseFilter, SLOT(setEnabled(bool))); search->addAction(reverseFilter); /* Database menu */ QMenu* menuDatabase = menuBar()->addMenu(tr("&Database")); m_menuDatabases = menuDatabase->addMenu(tr("&Switch to")); menuDatabase->addAction(createAction(tr("&Copy games..."), SLOT(slotDatabaseCopy()), Qt::Key_F5)); /* Help menu */ menuBar()->addSeparator(); QMenu *help = menuBar()->addMenu(tr("&Help")); /* Help Window */ DockWidgetEx* pHelpDock = new DockWidgetEx(tr("Help"), this); pHelpDock->setObjectName("Help"); HelpBrowser* pHelpBrowser = new HelpBrowser(this); pHelpBrowser->setMinimumSize(150, 100); pHelpDock->setWidget(pHelpBrowser); addDockWidget(Qt::RightDockWidgetArea, pHelpDock); QAction* helpAction = pHelpDock->toggleViewAction(); helpAction->setIcon(QIcon(":/images/help.png")); helpAction->setShortcut(Qt::Key_F1); help->addAction(helpAction); pHelpDock->hide(); QAction* reportBugAction = createAction(tr("&Report a bug..."), SLOT(slotHelpBug())); reportBugAction->setIcon(QIcon(":/images/bug.png")); help->addAction(reportBugAction); help->addSeparator(); help->addAction(createAction(tr("&About ChessX"), SLOT(slotHelpAbout()), QString(), 0, QString(), QString(), QAction::AboutRole)); #ifdef QT_DEBUG QMenu* debug = help->addMenu(tr("&Debug")); debug->addAction(createAction("Copy HTML", SLOT(slotGameViewSource()))); debug->addAction(createAction("Dump Movenodes", SLOT(slotGameDumpMoveNodes()))); debug->addAction(createAction("Make Screenshot", SLOT(slotScreenShot()), Qt::CTRL + Qt::Key_F12)); debug->addAction(createAction("Compile ECO", SLOT(slotCompileECO()))); #endif fileToolBar->addAction(helpAction); toolbars->addAction(fileToolBar->toggleViewAction()); toolbars->addAction(editToolBar->toggleViewAction()); toolbars->addAction(viewToolBar->toggleViewAction()); toolbars->addAction(dbToolBar->toggleViewAction()); toolbars->addAction(gameToolBar->toggleViewAction()); toolbars->addAction(searchToolBar->toggleViewAction()); } bool MainWindow::confirmQuit() { QString modified; if(m_currentDatabase) { if(!QuerySaveGame()) { return false; } } for(int i = 1; i < m_databases.size(); i++) if(m_databases[i]->database()->isModified()) { modified += m_databases[i]->database()->name() + '\n'; } if(!modified.isEmpty()) { int response = MessageDialog::yesNoCancel(tr("Following databases are modified:") + '\n' + modified + tr("Save them?")); if(response == MessageDialog::Cancel) { return false; } if(response == MessageDialog::Yes) { Output output(Output::Pgn); for(int i = 1; i < m_databases.size(); i++) if(m_databases[i]->database()->isModified()) output.output(m_databases[i]->database()->filename(), *(m_databases[i]->database())); } } for(int i = 1; i < m_databases.size(); i++) { slotFileCloseIndex(i); } return true; } void MainWindow::startOperation(const QString& msg) { m_operationTime.start(); statusBar()->showMessage(msg); m_progressBar->setMaximumHeight(m_statusFilter->height() - 3); statusBar()->insertPermanentWidget(0, m_progressBar); m_progressBar->setValue(0); m_progressBar->show(); } void MainWindow::finishOperation(const QString& msg) { statusBar()->showMessage(msg + tr(" (%1 s.)").arg(m_operationTime.elapsed() / 100 / 10.0)); statusBar()->removeWidget(m_progressBar); } void MainWindow::cancelOperation(const QString& msg) { statusBar()->showMessage(msg); statusBar()->removeWidget(m_progressBar); } bool MainWindow::QuerySaveGame() { if(game().isModified() && !database()->isReadOnly()) { return slotGameSave(); } return true; } void MainWindow::restoreRecentFiles() { AppSettings->beginGroup("Favorites"); QStringList list = AppSettings->value("Files").toStringList(); QStringList attributes = AppSettings->value("Attributes").toStringList(); QList indexList; AppSettings->list("LastGameIndex", indexList); AppSettings->endGroup(); QStringList::const_iterator it = attributes.begin(); QList::const_iterator it1 = indexList.begin(); foreach(QString s, list) { QString attribute = it != attributes.end() ? *it++ : ""; m_databaseList->setFileFavorite(s, true, *it1++); bool bUtf8 = (attribute.contains("utf8")); m_databaseList->setFileUtf8(s, bUtf8); } } void MainWindow::StartCheckUpdate() { if(AppSettings->getValue("/General/onlineVersionCheck").toBool()) { m_manager = new QNetworkAccessManager(this); connect(m_manager, SIGNAL(finished(QNetworkReply*)), SLOT(slotHttpDone(QNetworkReply*))); connect(this, SIGNAL(signalVersionFound(int, int, int)), SLOT(slotVersionFound(int, int, int))); QUrl url = QUrl(QString("http://chessx.sourceforge.net/versions/current.txt")); QNetworkRequest request(url); m_manager->get(request); } } void MainWindow::slotHttpDone(QNetworkReply *reply) { QUrl url = reply->url(); if(!reply->error()) { QString answer(reply->readAll()); QRegExp rx("(\\d\\d?)\\.(\\d\\d?)\\.(\\d\\d?)"); if(answer.indexOf(rx) > -1) { int major = rx.capturedTexts().at(1).toInt(); int minor = rx.capturedTexts().at(2).toInt(); int build = rx.capturedTexts().at(3).toInt(); emit signalVersionFound(major, minor, build); } } reply->deleteLater(); StartCheckDatabase(); } void MainWindow::StartCheckDatabase() { if(m_databaseList->model()->rowCount() <= 1) { LoadQuery dlg; if(dlg.exec() == QDialog::Accepted) { slotStatusMessage(tr("Start loading database...")); if(dlg.largeDB()) { openDatabaseUrl("http://chessx.sourceforge.net/db/bundesliga2000.pgn.zip", false); } else { openDatabaseUrl("http://chessx.sourceforge.net/db/SBL1213.pgn.zip", false); } } } } void MainWindow::slotVersionFound(int major, int minor, int build) { int verInternet = major * 10000 + minor * 100 + build; int verCurrent = VERSION_MAJOR * 10000 + VERSION_MINOR * 100 + REVISION; if(verInternet > verCurrent) { slotStatusMessage(tr("A new version is available at chessx.sourceforge.net")); } } chessx-1.0.0/src/database/indexitem.h000644 001750 001750 00000004525 12223260306 020305 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 Marius Roets * * (C) 2007 Rico Zenklusen * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __INDEXITEM_H__ #define __INDEXITEM_H__ #include "common.h" #include #include /** @ingroup Database The IndexItem class holds one item that is listed in a index It contains essential game header information that is kept in memory for fast access. It is used in conjunction with the Tags class. For most items it stores the id that refers to the relevant tag item in the Tags instance. Where convenient, the actual value is stored instead of the id. @todo Index items seem to be implemented in an inefficient way, as all the tags appearing in database are stored for each game. The correct way will be to store only basic tags (let's say 7 standard tags, ratings and EventDate), using notation: tag name + tag value for others. When this is fixed, Output::writeAllTags() should be adjusted. */ class IndexItem { public: IndexItem(); ~IndexItem(); /** Adds an index pair to the IndexItem */ void set(TagIndex tagIndex, ValueIndex valueIndex); /** returns value of index stored at 'offset' with given 'size' */ ValueIndex valueIndex(TagIndex tagIndex) const; bool hasTagIndex(TagIndex tagIndex) const; /** Write the data of the instance to a QDataStream */ void write(QDataStream& out) const; /** Reads the data of the instance from a QDataStream. * All data is cleared first. */ void read(QDataStream& in); const QMap& getTagMapping() const { return m_mapTagIndexToValueIndex; } private: QMap m_mapTagIndexToValueIndex; }; #endif // __INDEXITEM_H__ chessx-1.0.0/src/database/uciengine.h000644 001750 001750 00000004132 12223260306 020257 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2006-2007 Sean Estabrooks * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __UCIENGINE_H__ #define __UCIENGINE_H__ #include #include #include "engine.h" /** @ingroup Feature * The UCIEngine class provides an interface to Winboard/XBoard engines. */ class UCIEngine : public Engine { public: /** Constucts an engine with a given path/command, and log stream */ UCIEngine(const QString& name, const QString& command, bool bTestMode, const QString& directory = QString(), QTextStream* logStream = NULL); /** Analyses the the given position */ bool startAnalysis(const Board& board, int nv); /** Stops any analysis */ void stopAnalysis(); /** Update number of displayed lines. Restarts engine. */ virtual void setMpv(int mpv); virtual bool providesMvp() { return true; } protected: /** Performs any initialisation required by the engine protocol */ void protocolStart(); /** Performs any shutdown procedure required by the engine protocol */ void protocolEnd(); /** Processes messages from the chess engine */ void processMessage(const QString& message); private: /** Parses analysis */ void parseAnalysis(const QString& message); /** Parse option string */ void parseOptions(const QString &message); Board m_board; QString m_position; QString m_waitingOn; bool m_quitAfterAnalysis; }; #endif // __UCIENGINE_H__ chessx-1.0.0/src/database/wbengine.cpp000644 001750 001750 00000015367 12223260306 020456 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 William Hoggarth * * (C) 2005-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "wbengine.h" WBEngine::WBEngine(const QString& name, const QString& command, bool bTestMode, const QString& directory, QTextStream* logStream) : Engine(name, command, bTestMode, directory, logStream) { m_analyze = false; m_setboard = false; // We do not support version 1 xboard protocol, so this _must_ be set true by feature discovery m_invertBlack = true; } bool WBEngine::startAnalysis(const Board& board, int nv) { m_mpv = nv; if(isActive() && m_board == board) { return true; } stopAnalysis(); m_board = board; if(m_analyze && isActive() && m_setboard) { send("setboard " + board.toFen()); send("post"); send("analyze"); setAnalyzing(true); return true; } return false; } void WBEngine::stopAnalysis() { if(isAnalyzing()) { send("exit"); setAnalyzing(false); } } void WBEngine::protocolStart() { send("xboard"); send("protover 2"); QTimer::singleShot(2000, this, SLOT(featureTimeout())); } void WBEngine::protocolEnd() { stopAnalysis(); send("quit"); setActive(false); m_board.clear(); } void WBEngine::processMessage(const QString& message) { QString trim(message); // GNU Chess always prompts ... if(trim.startsWith("White (1) : ")) { trim = message.mid(12); } trim = trim.trimmed(); if(!isActive() && trim.startsWith("Crafty v")) { m_invertBlack = false; } //determine command QString command = trim.section(" ", 0, 0); //identify and process the command if(command == "feature") { feature(trim); } else if(isAnalyzing()) { parseAnalysis(trim); } } void WBEngine::feature(const QString& command) { //break up command into individual features int index = command.indexOf(' ') + 1; int equalsIndex; int endIndex; QString feature; QString value; while(index < (int)command.length()) { //feature name terminates with an = equalsIndex = command.indexOf('=', index); feature = command.mid(index, equalsIndex - index); //string values are delimited by ", others end with whitespace if(command[equalsIndex + 1] == '"') { endIndex = command.indexOf('"', equalsIndex + 2); value = command.mid(equalsIndex + 2, (endIndex - equalsIndex) - 2); index = endIndex + 2; } else { endIndex = command.indexOf(' ', equalsIndex + 1); value = command.mid(equalsIndex + 1, (endIndex - equalsIndex) - 1); index = endIndex + 1; } //if endIndex is -1 then the end of the string has been reached if(endIndex == -1) { index = command.length(); } //process feature/value pair if(feature == "setboard") { m_setboard = (bool)value.toInt(); send("accepted " + feature); } else if(feature == "analyze") { m_analyze = (bool)value.toInt(); send("accepted " + feature); } else if(feature == "done") { featureDone((bool)value.toInt()); send("accepted " + feature); } else { //unknown feature, reject it send("rejected " + feature); } QString name = feature; EngineOptionData option; option.m_name = name; option.m_defVal = value; option.m_type = OPT_TYPE_SPIN; m_options.append(option); } } void WBEngine::featureDone(bool done) { // We've received a "done" feature offer from engine, // so it supports V2 or better of the xboard protocol // No need to wait any longer wondering if we're talking to a V1 engine if(done) { setActive(true); } // The engine will send done=1, when its ready to go, // and done=0 if it needs more than 2 seconds to start. } void WBEngine::featureTimeout() { if(!isActive()) { v1TurnOffPondering(); setActive(true); } } void WBEngine::parseAnalysis(const QString& message) { QString trimmed = message.simplified(); Analysis analysis; bool ok; bool timeInSeconds = false; //Depth QString depth = trimmed.section(' ', 0, 0); analysis.setDepth(depth.toInt(&ok)); if(!ok) { depth.truncate(depth.length() - 1); analysis.setDepth(depth.toInt(&ok)); if(!ok) { return; } timeInSeconds = true; } //Score int score = trimmed.section(' ', 1, 1).toInt(&ok); if(!ok) { return; } if(m_invertBlack && m_board.toMove() == Black) { score = -score; } analysis.setScore(score); //Time int time = trimmed.section(' ', 2, 2).toInt(&ok); if(!ok) { return; } if(timeInSeconds) { time = time * 1000; } else { time *= 10; } analysis.setTime(time); //Node analysis.setNodes(trimmed.section(' ', 3 , 3).toLongLong(&ok)); if(!ok) { return; } //Variation Board board = m_board; QString sanMove; MoveList moves; int section = 4; while((sanMove = trimmed.section(' ', section, section)) != "") { if(sanMove.startsWith("(")) { break; } // SBE -- What the heck is "" and why does crafty send it? if(!sanMove.endsWith(".") && sanMove != "") { Move move = board.parseMove(sanMove); if(!move.isLegal()) { // qWarning("! move: |%s|", sanMove.toLatin1().constData()); // qWarning("Variation parsing failed"); break; } board.doMove(move); moves.append(move); } section++; } analysis.setVariation(moves); if(analysis.isValid()) { sendAnalysis(analysis); } } void WBEngine::v1TurnOffPondering() { send("hard"); send("easy"); } chessx-1.0.0/data/images/arrow_green.png000644 001750 001750 00000014276 12103305243 021012 0ustar00niklasniklas000000 000000 PNG  IHDR((miCCPICC ProfileX XuXUͷOrN:tsQ E))E)Q)A$ DABB{sw~kϞwfY/,0 !Q$#]'gNԊp++sR%?>D +䶗w$1/NDa'3"x= ~=cgT$@ވyb~H;`BBG&G"$$l!X?ߦ>g,ȓȋ"Ã=YG#p!5Edr#sK4}L8cҵLmlGAaf^-ډzl_ol#clqzz$7 6ox~?CŗdxE 04k'Ã?} EσOz{-|b:~ţz PȿHdjC_c<huE6~BѤC]0`\I :X; @G@mh  !H($z +| ϐУp8KQEIbRR҅2,e CʷTTRT&TT'JƨQQ RPQQPߡ^!ѣ9ASBsffV֒66vG'Dg@MLWAnEOGO?E_IK `ȐpaaQс14IɄ))9&3's:s=: ;6KMg,<AY[X߰جَ]be[dg`Wg'g798l8qTp qrrqqsq>\b jZȣSók{wwOϞ/&~ /7@@KA2AA }BBBiB-B,&qu¯E(ED"DE&D*AEbbb%b#ⰸxEQ DDĤ$ddTT7ii}ҿeee*e^ɚ&ɶ.ˉJ&) OʷPWQ0HhحDRWZPPP.UTaPRRyQU=z_ZZwuI Z|TԸ1ɣyYsZWS\659Q@:tetIMzjz:QFto uc͌OpMjLLMQٚ73'Y  =b ,M,s-X [EXݳZ[YX鳥u]ӵ˶{e/bm@P8$tiЙ9reC]]S]>{ߍ-;GǶg窗WQx[;{G'gW7wO/o_˿1@/8Gq`YzePUnc|GPРО0ذp%Z$y859 EDDhƔlq8r'664vsqqWu'9~tDI'?&%T'$$$iVnQi}mhX׸ g>>5:9==5"ŏ1/^%ƼxC-wnN+M?џzo,qˇ?Q~*㞫`ZLJȷ߇> ]Za]{jZzF/_}s[Gqۅ;;m~ $y9 ` Jg@9#sȩ2(&Fk_#!נ(Ch>ya$2Ͱxeh&.s (  뉨*sIJ%ץ_ v5W((&)+V1VUTRǪ;0ѩYUmckgoogvEӖ)VO$۞KOvHrLt:|%Pk7owgW41OoǁA/gCCQt$H(hGVm>6|u&-'_2O G*KitB:c's-3ٯM3;7?Z0rI@➒[/55^n^bv 5LuRUot_CR㑦c'Z[例˼쎜=n5=n7`}IpH{Mc'.ʃCO kh>370{ffnC\_q{{˴{Y4~}|i`ax!EP߾|Xqk|gjZzІ/M-m߬X Ǎ!;MLDcK^s%+ [5Ww^>wBwDĚě$$oJK_,_pA1G)CJ*IW倅>.>!1 )9A%lkmeimmiyۡ߹rx9{gߜ|BB|\\|5I%crPlc[hڟ0؟s^rCJUjiڹ)A,蜕>q!2,*;~-)X:}CW*+_}Rn?ieӻٖw-[jzzzFÍGk}W |:ɧّ駯GLJ'?~~iE˲Wߤ=.roɬŹ[K.F|uf]a2 O*aN "oᶱ;ߨ]hU7`䠗Y` TXQ` `I ߏ@A\H)41 iHFY `|b!=$C ҠP Zia9(4ӅPH.GHb1X ! sSdd!܈"b҇rʌZFV. =4C(osLLWXrXX_%q9+/\'#,d /𔔐ܐz,]$"/))Z-r"<\ .jTi6jhO,ꡑlhcjiRk:dÂ%ɪzҖ>㚳|7]#Ƴk['wП9/-6$8t \"l>9۽K'o1hws0ə0p.CQgP}hZŐcl09"6;½ dd2Rry,' GTTe%44崢tt#nN00V022XjY-XWJ W8pZqraM])fB BDċ%p']($#*S~TARr QUI逋VvNn^iYmh+9ka{).Cq[=T=OxzS Ƅ g$=>z1 '㧶RN`ˬ=qv\HYnMY¢beW*IV-ݐ߸Ӑݬ|wݨGj]ꆧF Zb'_,|=]ς͗ԯ7UƯ=ES?b@Q̀F,(i!bD Ma,[$WP(T!jA4 :&ӏǺco`wpVmYAp<|ŒQ> ȩ6cWhhht e  mfkYYXϰɳbOxřƥnj˯KŒH~_! &-&!!(%,)="sM6AM^SA@F `TӲIѭ՟33k1>Hanb]nҎ!3ˡC\߻{"]o;?]!|m+z1'Of&R%%sԦp\;s>[HNd[~υ"g/CW*RW1WmQuKNlݶ{7TuTw~;7?{0; W.o25LD9/Yg['?7օ~9me+/=DȏowwW}*ݩ@t9ci(E fY QZ!tIDATX q0M&g&%\B|tKI.!t9$<4G !ETff8Ν~(2'FElS(~wGP،\(GpR^$*}jm AboutDlg About ChessX Über ChessX <b>ChessX</b><br> Free Chess Database <b>ChessX</b><br> Freie Schachdatenbank Version Version Copyright Copyright License Lizenz Maintainer Projektleitung Further Maintainers Weitere Projektleiter Testing Tester Coders Programmierung Further Code Weitere Programmierer Translations Übersetzungen Path Information Pfade Path for temporary files Pfad zu Temporärdateien Program data path Pfad zu Programmdaten Contact Kontakt Homepage Homepage Mailing List Mail Liste Analysis (depth %1, %2) (Tiefe %1, %2) AnalysisWidget Stop Stopp There was an error (%1) running engine <b>%2</b>. Fehler (%1) beim Ausführen des Programms <b>%2</b>. Draw Remis White wins in %n moves Weiß gewinnt in %n Zug Weiß gewinnt in %n Zügen Black wins in %n moves Schwarz gewinnt in %n Zug Schwarz gewinnt in %n Zügen <a href="0" title="Click to add move to game">[+]</a> <b>Tablebase:</b> <a href="0" title="Zug in Text einfügen">[+]</a> <b>Tablebase:</b> &Lines: &Varianten: Analyze Analysiere Analysis Analyse BitBoard w%1 b%2 %3 to move. w%1 b%2 %3 am Zug. White Weiß Black Schwarz BoardSetupDialog No white king Kein weißer König No black king Kein schwarzer König Both kings are in check Beide Könige stehen im Schach Setup position Stellung aufbauen Clear Löschen &Reset &Zurücksetzen Side to move: Am Zug: FEN FEN Move: Zug: Copy Text Text kopieren &Ok &OK &Cancel &Abbrechen Side to move has opponent in check already Seite am Zug gibt Gegner bereits Schach Black has too many pawns Schwarz hat zu viele Bauern White has too many pawns Weiß hat zu viele Bauern There are pawns on the first or eighth rank Bauern stehen auf der ersten oder achten Reihe Too many kings Zu viele Könige Too many black pieces Zu viele schwarze Figuren Too many white pieces Zu viele weiße Figuren Bad castling rights Ungültige Rochade-Rechte En passant square is not correct En passent-Feld nicht korrekt Unknown reason Unbekannter Fehler Current position is not valid. %1. Aktuelle Position nicht gültig. %1. Illegal position: %1 Ungültige Position: %1 Text in clipboard does not represent valid FEN:<br><i>%1</i> In der Zwischenablage ist kein gültige FEN Position: <br><i>%1</i> There is no text in clipboard. Zwischenablage ist leer. Board Brett &Advanced &Erweitert En passant file: En passant Linie: Castling rights Erlaubte Rochaden Tools Werkzeuge Flip board Brett drehen ... ... Mirror left and right Links und rechts spiegeln Mirror top and bottom Oben und unten spiegeln Change colors for all pieces Farbwechsel der Steine Black O-O Schwarze O-O White O-O-O Weiße O-O-O White O-O Weiße O-O Black O-O-O Schwarze O-O-O Halfmove clock: Halbzug Zähler: Paste FEN Einfügen FEN Copy FEN Kopiere FEN BoardTheme Cannot find piece data. Please check your installation. Fehlerhafte Figurendaten. Bitte Installation prüfen. ChessBrowser Add start comment... Anfangskommentar hinzufügen... Add comment... Kommentar hinzufügen... Add move symbol Zugbewertung hinzufügen Add evaluation symbol Stellungsbewertung hinzufügen Add other symbol Andere Auszeichnung hinzufügen Bishops Submenu for 3 NAGs: pair of bishops, bishops of sam/oppositie color Läufer Remove symbols Auszeichnungen entfernen Enumerate Variations A) B) C) Aufzählung A) B) C) Enumerate Variations a) b) c) Aufzählung a) b) c) Promote to main line Zur Hauptvariante machen Move variation up Variante nach oben Move variation down Variante nach unten Remove variation Variante löschen Remove previous moves Vorhergehende Züge löschen Remove next moves Restliche Züge löschen Insert threat Drohung einfügen Copy Html Kopieren in HTML Format Copy Text Text kopieren CommentDialog Edit Comment Kommentar ändern Elapsed time Abgelaufene Zeit Clock time Restzeit H:mm:ss CopyDialog Copy Games Kopiere Partien Copy: Kopiere: &Current game &Aktuelle Partie Games in &filter Partien im &Filter &All games &Alle Partien &To: &Nach: DatabaseList Databases Datenbanken Open Öffnen Activate Aktivieren Close Schließen Add to favorites Zu Favoriten hinzufügen Remove from Favorites Aus Favoriten löschen Show in Finder Zeige im Finder DatabaseListModel Favorite Favorit Name Name Size Größe Open Offen Path Pfad Format Format Date Datum Clipboard Zwischenablage Closed Geschlossen ECOListWidget <html><body><i>No ECO code chosen.</i></body></html> <html><body><i>Kein ECO Code ausgewählt.</i></body></html> <html><i>No ECO code chosen.</i></html> Kein ECO Code ausgewählt EcoInfo <i>no games</i> <i>Keine Partien</i> Total: %1 Gesamt: %1 Games in database %1: %2 Partien in Datenbank %1: %2 Rating: <b>%1</b> Wertung: <b>%1</b> Rating: <b>%1-%2</b> Wertung: <b>%1-%2</b> <table><tr><th>White Player</th><th>Score</th></tr> <table><tr><th>Weiss</th><th>Resultat</th></tr> <a name='ListBlack'></a><table><tr><th>Black Player</th><th>Score</th></tr> <a name='ListBlack'></a><table><tr><th>Schwarz</th><th>Resultat</th></tr> EngineOptionDialog Engine Options Optionen Reset Zurücksetzen EngineOptionList Engine Options Optionen EngineOptionModel Name Default Standardwert Min Minimum Max Maximum Value Wert EventInfo <i>no games</i> <i>Keine Partien</i> Total: %1 Gesamt: %1 Games in database %1: %2<br> Partien in Datenbank %1: %2<br> Rating: <b>%1</b><br> Wertung: <b>%1</b><br> Rating: <b>%1-%2</b><br> Date: <b>????.??.??<b><br> Datum: <b>????.??.??<b><br> Date: <b>%1</b><br> Datum: <b>%1</b><br> <table><tr><th>Participants</th><th>Score</th></tr> <table><tr><th>Teilnehmer</th><th>Ergebnis</th></tr> EventListWidget <html><i>No event chosen.</i></html> <html><i>Kein Turnier ausgewählt.</i></html> FilterModel Nr Nr White Weiß WhiteElo ELO Weiß Black Schwarz BlackElo ELO Schwarz Event Turnier Site Ort Round Runde Date Datum Result Ergebnis ECO ECO Moves Züge GameList Game list Partien Copy games... Kopiere Partien... Merge into current game In aktuelle Partie integrieren All Games Ganze Datenbank Filter Filter Selected game Ausgewählte Partie Delete game Partie löschen LoadQuery Load Database Datenbank laden Currently, there are no databases configured. Shall I download a database? Zur Zeit sind keine Datenbanken verfügbar.\nSoll ich eine Datenbank herunterladen? Large Database (9M) Große Datenbank (9M) Small Database Kleinere Datenbank Start Download! Start Download! Skip Loading Laden überspringen MainWindow Game Text Notation Game List Partien Loading ECO file... Lade ECO Datei... ECO Loaded. ECO geladen. [Clipboard] [Zwischenablage] Open database Datenbank öffnen PGN database (*.pgn) PGN Datenbank (*.pgn) Cannot create ChessX database. ChessX Datenbank kann nicht angelegt werden. PGN databases (*.pgn) PGN Datenbanken (*.pgn) <html>The database <i>%1</i> is read-only and cannot be saved.</html> <html>Die Datenbank <i>%1</i> ist schreibgeschützt und kann nicht gesichert werden.</html> Saving %1... Speichere %1... The current database is modified! Die aktuelle Datenbank wurde geändert! Save it? Sichern? %1 saved %1 gespeichert Text in clipboard does not represent valid FEN:<br><i>%1</i> In der Zwischenablage ist keine gültige FEN Position: <br><i>%1</i> There is no text in clipboard. Zwischenablage ist leer. Queen Dame Rook Turm Bishop Läufer Knight Springer Promotion Umwandlung Promote to: Umwandeln in: Red Square Rotes Feld Yellow Square Gelbes Feld Green Square Grünes Feld Remove Color Lösche Farbe Red Arrow to here Roter Pfeil hierher Yellow Arrow to here Gelber Pfeil hierher Green Arrow to here Grüner Pfeil hierher Remove Arrow to here Pfeil löschen Append game %1 to %2. Partie %1 an %2 anhängen. Clipboard Zwischenablage Append games from %1 to %2. Partien aus %1 an %2 anhängen. <b>New game</b> <b>Neue Partie</b> Analysis Pane 1 is not running an engine for automatic analysis. Analyse 1 ist nicht aktiv für Autoanalyse. %1 - ChessX Search ended Suche beendet Updating tree... Aktualisiere Baum... Tree updated. Baum aktualisiert. Load Game Partie laden Game number: Partienummer: This database is read only. Diese Datenbank ist schreibgeschützt. &File &Datei &Open... &Öffnen... &Export... &Exportieren... &Games in filter &Partien im Filter &All games &Alle Partien &Close &Schließen &Quit &Beenden &Edit &Bearbeiten Comment Kommentar Variation Variante Promote Aufwerten Remove Löschen Setup &position... Stellun&g aufbauen... ECO Load Error. Fehler beim Laden der ECO-Datei. Database %1 cannot be accessed at the moment (%2). Auf die Datenbank %1 kann im Moment nicht zugegriffen werden (%2). File Datei Open in UTF8... Öffne UTF-8 kodierte Datei... Commit Database to disk Commit der Datenbank auf Disk Current Game Aktuelle Partie Edit Ändern Promote Variation Variante aufwerten Remove Variation Variante entfernen View Ansicht Toolbars Toolbars Stay on Top Immer oben &Game &Partie Game Partie Database Datenbank &Load &Laden &Next &Nächste &Previous &Vorhergehende &Go to game... &Springe zur Partie... &Random &Zufällig Training Training Auto Player Vorspielen Auto Analysis Autoanalyse &Go to &Springe zu &Start &Anfang Go to first move Zum Partieanfang springen &End &Ende Go to last move Zum Partieende springen &Next move &Nächster Zug Start loading database... Datenbank laden gestartet... A new version is available at chessx.sourceforge.net Eine neue Version ist verfügnar unter chessx.sourceforge.net &Previous move &Vorheriger Zug 5 moves &forward 5 Züge &vorwärts 5 moves &backward 5 Züge &zurück Enter Variation In Variante hineingehen Back to main line Zurück zur Hauptvariante &Save.... &Speichern... Events Turniere ECO ECO Copy PGN Kopiere PGN Copy FEN Kopiere FEN Copy Position Kopiere Stellung Copy Image Kopiere Bild &Paste Einfügen &PGN/FEN New board Neues Brett Close current board Aktuelles Brett schliessen Refactor Entferne Uncomment Alle Kommentare Remove Variations Alle Varianten Fi&nd &Suchen Find &tag Suche &Partiedaten Find &position Suche &Stellung &Reset filter &Filter zurücksetzen &Reverse filter &Filter umkehren Help Hilfe Following databases are modified: Geänderte Datanbanken: Save them? Sichere sie? (%1 s.) &View &Ansicht Game Time Zeit Players Spieler Databases Datenbanken Analysis 1 Analyse 1 Analysis 2 Analyse 2 Database %1 cannot be accessed at the moment. Auf die Datenbank %1 kann im Moment nicht zugegriffen werden. Opening %1... Öffne %1... Cannot open file Datei kann nicht geöffnet werden %1 opened %1 geöffnet Comment Before Kommentar vor dem Zug &Preferences... &Einstellungen... Previous Variation Vorhergehende Variante Next Variation Nächste Variante Search Suchen &Enable filter &Filter einschalten &Database &Datenbank &Flip board &Brett drehen &Help &Hilfe &Report a bug... &Fehler melden... &About ChessX &Über ChessX &Debug &Debug Export games Partien exportieren Opening Tree Eröffnungsbaum &Save &Speichern &Remove &Entferne Moves from the beginning Züge ab Anfang Moves to the end Züge bis Ende &New &Neu PGN file (*.pgn) PGN-Datei (*.pgn) HTML page (*.html) HTML-Seite (*.html) LaTeX document (*.tex) LaTeX Dokument (*.tex) New database Neue Datenbank The clipboard contains FEN, but with illegal position. You can only paste such positions in <b>Setup position</b> dialog. Zwischenablage enthält FEN, aber eine ungültige Position. Sie können solche Positionen im <b>Einrichtungsdialog</b> eingeben. You need at least two open databases to copy games Mindestens zwei offene Datenbanken benötigt um Partien zu kopieren %1. %2 (%3 games) %1. %2 (%3 Partien) &New database... &Neue Datenbank... Open &recent... &Letzte öffnen... &Switch to &Wechseln zu &Copy games... Partien &kopieren... MessageDialog Error Fehler Warning Warnung Information Hinweis Question Frage &Yes &Ja &No &Nein &OK &OK &Cancel &Abbrechen MoveData [end] NagSet Good Move Guter Zug Poor Move Schwacher Zug Very good Move Sehr guter Zug Blunder Grober Fehler Speculative Move Spekulativer Zug Dubious Move Zweifelhafter Zug Only Move Einziger Zug Equal Gleich Unclear Unklar White has slight advantage Weiss hat einen kleinen Vorteil Black has slight advantage Schwarz hat einen kleinen Vorteil White has moderate advantage Weiss hat einen mässigen Vorteil Black has moderate advantage Schwarz hat einen mässigen Vorteil White has decisive advantage Weiss hat entscheidenden Vorteil Black has decisive advantage Schwarz hat entscheidenden Vorteil White has crushing advantage Weiss hat überwältigenden Vorteil Black has crushing advantage Schwarz hat überwältigenden Vorteil Zugzwang Zugzwang With slight space advantage Mit kleinem Raumvorteil With moderate space advantage Mit fühlbarem Raumvorteil With decisive space advantage Mit eintscheidendem Raumvorteil With slight development advantage Mit kleinem Entwicklungsvorsprung With moderate development advantage Mit Entwicklungsvorsprung With decisive development advantage Mit entscheidendem Entwicklungsvorsprung With initiative Mit Initiative With lasting initiative Mit anhaltender Initiative With attack Mit Angriff With insufficient compensation for material deficit Mit unzureichender Kompensation für das geopferte Material With compensation Mit Kompensation With more than adequate compensation for material deficit Mit mehr als ausreichender Kompensation für das materielle Defizit With slight center control advantage Mit kleinem Zentrumsvorteil With moderate center control advantage Mit Zentrumsvorteil With decisive center control advantage Mit entscheidendem Zentrumsvorteil With slight kingside control advantage Mit kleinem Vorteil auf dem Königsflügel With moderate kingside control advantage Mit Vorteil auf dem Königsflügel With decisive kingside control advantage Mit entscheidendem Vorteil auf dem Königsflügel With slight queenside control advantage Mit kleinem Vorteil auf dem Damenflügel With moderate queenside control advantage Mit Vorteil auf dem Damenflügel With decisive queenside control advantage Mit entscheidendem Vorteil auf dem Damenflügel With vulnerable first rank Mit geschwächter erster Reihe With well protected first rank Mit gut überwachter erster Reihe With poorly protected king Mit schlecht geschütztem König With well protected king Mit gut geschütztem König With poorly placed king Mit schlechter Königsstellung With well placed king Mit guter Königsstellung With very weak pawn structure Mit sehr schlechter Bauernstruktur With moderately weak pawn structure Mit schlechterer Bauernstruktur With moderately strong pawn structure Mit besserer Bauernstruktur With very strong pawn structure Mit sehr guter Bauernstruktur With poor knight placement Mit schlechter Springerstellung With good knight placement Mit guter Springerstellung With poor bishop placement Mit schlechter Läuferstellung With good bishop placement Mit guter Läuferstellung With poor rook placement Mit schlechter Turmstellung With good rook placement Mit guter Turmstellung With poor queen placement Mit schlechter Damenstellung With good queen placement Mit guter Damenstellung With poor piece coordination Mit schlechter Figurenkoordination With good piece coordination Mit guter Figurenkoordination White played the opening very poorly Weiss hat die Eröffnung schlecht behandelt Black played the opening very poorly Schwarz hat die Eröffnung schlecht behandelt White played the opening poorly Weiss hat die Eröffnung schlecht behandelt Black played the opening poorly Schwarz hat die Eröffnung schlecht behandelt White played the opening well Weiss hat die Eröffnung gut behandelt Black played the opening well Schwarz hat die Eröffnung gut behandelt White played the opening very well Weiss hat die Eröffnung gut behandelt Black played the opening very well Schwarz hat die Eröffnung gut behandelt White played the middlegame very poorly Weiss hat das Mittelspiel schlecht behandelt Black played the middlegame very poorly Schwarz hat das Mittelspiel schlecht behandelt White played the middlegame poorly Weiss hat das Mittelspiel schlecht behandelt Black played the middlegame poorly Schwarz hat das Mittelspiel schlecht behandelt White played the middlegame well Weiss hat das Mittelspiel gut behandelt Black played the middlegame well Schwarz hat das Mittelspiel gut behandelt White played the middlegame very well Weiss hat das Mittelspiel gut behandelt Black played the middlegame very well Schwarz hat das Mittelspiel gut behandelt White played the ending very poorly Weiss hat das Endspiel schlecht behandelt Black played the ending very poorly Schwarz hat das Endspiel schlecht behandelt White played the ending poorly Weiss hat das Endspiel schlecht behandelt Black played the ending poorly Schwarz hat das Endspiel schlecht behandelt White played the ending well Weiss hat das Endspiel gut behandelt Black played the ending well Schwarz hat das Endspiel gut behandelt White played the ending very well Weiss hat das Endspiel gut behandelt Black played the ending very well Schwarz hat das Endspiel gut behandelt With counterplay Mit Gegenspiel Moderate time control pressure Mässige Zeitnot Severe time control pressure Erhebliche Zeitnot With the idea Mit der Idee Aimed against Gerichtet gegen Better was Besser wäre Worse was Schlechter wäre Equivalent was Gleichwertig wäre RR RR N N Weak point Schwacher Punkt Endgame Enspiel Line Linie Diagonal Diagonale Pair of bishops Läuferpaar Bishops of opposite color Ungleichfarbige Läufer Bishops of the same color Gleichfarbige Läufer Diagram Diagramm OpeningTree Move Zug Count Häufigkeit Score Rating Year Jahr OpeningTreeWidget Form Formular OutputOptions Notation in Column Style Notation in einer Spalte Show symbolic Nags Symbolische Auszeichnungen Text width Textbreite Indent variations from Level EInrücken ab Ebene Variation Indentation Einrücktiefe Varianten Comment indentation Einrückung Kommentare NAG Color Farbe Auszeichnungen Main Line Color Farbe Hauptvariante Variation Color Farbe Varianten Comment Color Farbe Kommentare Header Color Farbe Kopf Show Header Kopfzeile anzeigen Show Diagrams Diagramme anzeigen Diagram Size DIagrammgrösse Comment Indentation Einrückung Kommentare PlayerInfo <i>no games</i> <i>Keine Spiele</i> Total: %1<br>White: %2<br>Black: %3<br> Summe: %1<br>Weiß: %2<br>Schwarz: %3<br> Games in database <i>%1</i>: <b>%2</b><br> Spiele in der Datenbank <i>%1</i>: <b>%2</b><br> Rating: <b>%1</b><br> Rating: <b>%1-%2</b><br> Date: <b>????.??.??<b><br> Datum: <b>????.??.??<b><br> Date: <b>%1</b><br> Datum: <b>%1</b><br> <p>White Openings:</p><ul> <p>Eröffnungen mit Weiß:</p><ul> </ul><p>Black Openings:</p><ul> </ul><p>Eröffnungen mit Schwarz:</p><ul> PlayerListWidget <html><i>No player chosen.</i></html> <html><i>Kein Spieler ausgewählt.</i></html> PreferencesDialog Light squares Weiße Felder Dark squares Schwarze Felder Highlighted squares Ausgewählte Felder Frame Rahmen Select engine directory Wähle Engine-Verzeichnis For updating translations online version checking needs to be enabled. Für das Nachladen von Spracherweiterungen muss der Online Zugriff aktiviert werden. Select databases folder Wähle Datenbank-Verzeichnis Select engine executable Wähle Engine-Programm Could not load server language file dictionary Verzeichnis der verfügbaren Sprachdateien konnte nicht geladen werden. Could not load or install language pack Die Spracherweiterung konnte nicht geladen oder installiert werden No further translations online available! Keine weiteren Sprachpakete online verfügbar! Translation file loaded - select added language above! Sprachpaket geladen - siehe in den verfügbaren Sprachen oben! Clear all application settings? Alle Einstellungen zurücksetzen? Warning Warnung Current move Aktueller Zug [plain colors] [Grundfarben] Main Line Hauptvariante Variations Varianten Comments Kommentare NAGs Auszeichnungen Use online tablebase servers Online Tablebaseserver verwenden &Board &Brett &Colors: &Farben: Board &style: Brett &Stil: &Guess move on left-click &Zug vorschlagen bei linker Maustaste &Draw frame between squares &Zeichne Rahmen zwischen Feldern &Chess set: &Figuren: Database Datenbank Commit Database after saving Game "Save game" is not an appropriate term and was translated as "Partie-Änderungen anwenden" Datenbank auf Festplatte speichern nach Anwenden von Partie-Änderungen Number of recent files: Anzahl der letzten Dateien: Default Database Path: Standard-Datenbank-Verzeichnis: Default path for storing files Standard-Pfad zum Speichern von Dateien Colors: Farben: Check for updates (at startup) and language packs Updateprüfung nach dem Start und Laden von Sprachpaketen &Ok &OK Preferences Einstellungen Appearance Ansicht Font Sizes Font Grössen Game Text: Notation: Lists Listen Game Text Notation Show Diagrams Diagramme anzeigen Column Style Hauptvariante in Spalten Keep variations inline from level Varianten in Fliesstext ab Ebene Diagram Size DIagrammgrösse Pieces Put the initials of the pieces here, mind the initial space. Initialen der Figuren eingeben, aufpassen auf den ersten Blank. KQRBN - Mind the initial space! KQRBN - Aufpassen auf das erste Blank! ... ... Localization Sprachanpassung Load language file from Server: Sprachpaket vom Server laden: Load! Laden! Use vertical Tabs Vertikale Ausrichtung der Reiter App App Internet Internet Language Sprache Changing the language requires restarting the application! Die Änderung der Sprache wird nach einem Neustart wirksam! &Apply &Anwenden &Reset &Zurücksetzen &Cancel &Abbrechen XBoard XBoard New Engine Neues Schachprogramm plain einfach outline Umriss &Engines &Schachprogramme Name: Name: Command: Befehl: Options: Optionen: Mouse Behaviour Maustasten Next guess on right click Nächster Vorschlag bei rechter Maustaste Wheel sensitivity Mausrad Geschwindigkeit Fast Schnell Slow Langsam Highlight current move Aktuellen Zug hervorheben Draw Coordinates Zeichne Brettkoordinaten Game Partie Autoplayer Vorspielen Auto-Play Interval Zug-Intervall Automatically save game and continue with next Automatisch Partie-Änderungen anwenden und fortsetzen Path to executable Programmpfad Path where engine is started - usually place of books Verzeichnis, in dem Engine startet - normalerweise der Platz für Eröffnungsbücher Directory: Verzeichnis: Protocol: Protokoll: Command Line Options Kommandozeilen-Optionen Options Optionen Arbitrary name to identify engine Bezeichnung Down Hinunter Remove Löschen Add... Hinzufügen... Automatic classification with ECO Codes Partien automatisch mit ECO Codes klassifizieren Build index file Indexdatei erstellen &Edit PGN files smaller than: &Nur PGN-Dateien kleiner als: MB Up Hinauf outline+shadow Umriss+Schatten QuickSearchDialog Quick Tag Search Partiedaten Suche White Weiß Black Schwarz Event Turnier Site Ort Round Runde Date Datum Result Ergebnis ECO ECO Number of Moves Anzahl von Zügen Value or Range like 2000-2300 Wert oder Wertebereich, wie z.B. 2000-2300 &Find &Suchen &Cancel &Abbrechen Find in current filter In aktuellem Filter finden Search whole database Durchsuche ganze Datenbank Add to current filter Zu aktuellem Filter hinzufügen &Value: &Wert: &Tag: &Element: &Mode: &Modus: White Elo ELO Weiß Game Number Partienummer Black Elo ELO Schwarz RenameTagDialog Rename Tags in Database Tags in Datenbank ändern Rename all Occurrences ... Alle Vorkommen ändern... from von to nach Press 'Rename' to proceed. 'Umbennen' drücken zum Ändern. Rename Umbenennen Close Schließen SaveDialog Save Game Partie sichern &OK &OK &Cancel &Abbrechen &Date: &Datum: &Round: &Runde: Elo: Elo: &Black: &Schwarz: &Site: &Ort: &Event: &Turnier: &White: &Weiß: &Discard Changes Änderungen &verwerfen Players Spieler Team Mannschaft White Team Team Weiß Black Team Team Schwarz Time Control Bedenkzeit White Start Time Bedenkzeit Weiß H:mm:ss Black Start Time Bedenkzeit Schwarz e.g. 40/7200:3600 for 2h/40 moves + 1h z.B. 40/7200:3600 für 40 Züge in 2 Stunden + 1 Stunde für den Rest Tournament Turnier E&vent date: &Veranstaltungsdatum: Game Information Partie-Daten Result: Ergebnis: Clipboard Zwischenablage Dates are not properly formatted! Invalid Data Datum ist nicht richtig formatiert! TableView Hide Column Spalte verstecken Show all Columns Alle Spalten anzeigen TagDetailWidget Form Formular &Filter: &Filter: Selected Item Auswahl Filter Filter Rename Ersetzen chessx-1.0.0/src/gui/gamelist.cpp000644 001750 001750 00000020525 12223260306 017475 0ustar00niklasniklas000000 000000 /*************************************************************************** gamelist.cpp - Game List window ------------------- begin : Sun 23 Jul 2006 copyright : (C) 2006 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "database.h" #include "filtermodel.h" #include "game.h" #include "gamelist.h" #include "GameMimeData.h" #include "quicksearch.h" #include "search.h" #include "settings.h" #include #include #include #include GameList::GameList(Filter* filter, QWidget* parent) : TableView(parent) { setObjectName("GameList"); setWindowTitle(tr("Game list")); m_model = new FilterModel(filter, this); setModel(m_model); connect(this, SIGNAL(clicked(const QModelIndex&)), SLOT(itemSelected(const QModelIndex&))); connect(this, SIGNAL(activated(const QModelIndex&)), SLOT(itemSelected(const QModelIndex&))); connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(slotContextMenu(const QPoint&))); connect(selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(slotItemSelected(QModelIndex))); #if QT_VERSION < 0x050000 horizontalHeader()->setClickable(true); #else horizontalHeader()->setSectionsClickable(true); #endif connect(horizontalHeader(), SIGNAL(sectionClicked(int)), SLOT(simpleSearch(int))); slotReconfigure(); setSortingEnabled(false); setDragEnabled(true); } GameList::~GameList() { delete m_model; } void GameList::slotItemSelected(const QModelIndex& index) { m_index = index; scrollTo(index, EnsureVisible); } void GameList::itemSelected(const QModelIndex& index) { emit selected(m_model->filter()->indexToGame(index.row())); } void GameList::setFilter(Filter* filter) { m_model->setFilter(filter); emit raiseRequest(); } void GameList::slotContextMenu(const QPoint& pos) { QModelIndex cell = indexAt(pos); m_index = cell; QModelIndexList selection = selectedIndexes(); // Make sure the right click occured on a cell! if(cell.isValid() && selection.contains(cell)) { QMenu menu(this); menu.addAction(tr("Copy games..."), this, SLOT(slotCopyGame())); QMenu* mergeMenu = menu.addMenu(tr("Merge into current game")); mergeMenu->addAction(tr("All Games"), this, SLOT(slotMergeAllGames())); mergeMenu->addAction(tr("Filter"), this, SLOT(slotMergeFilter())); mergeMenu->addAction(tr("Selected game"), this, SLOT(slotMergeGame())); menu.addSeparator(); QAction* deleteAction = menu.addAction(tr("Delete game"), this, SLOT(slotDeleteGame())); deleteAction->setCheckable(true); deleteAction->setEnabled(!m_model->filter()->database()->isReadOnly()); int n = m_model->filter()->indexToGame(cell.row()); deleteAction->setChecked(m_model->filter()->database()->deleted(n)); menu.exec(mapToGlobal(pos)); } } void GameList::simpleSearch(int tagid) { QuickSearchDialog dlg(this); dlg.setTag(tagid); if(m_model->filter()->count() <= 1) { dlg.setMode(1); } if(dlg.exec() != QDialog::Accepted) { return; } QString tag = m_model->GetColumnTags().at(dlg.tag()); QString value = dlg.value(); if(value.isEmpty()) { m_model->filter()->setAll(1); } else if((dlg.tag() == 0) || (dlg.tag() == 7) || (dlg.tag() == 11)) { // filter by number NumberSearch ns(m_model->filter()->database(), value); if(dlg.mode()) { m_model->filter()->executeSearch(ns, Search::Operator(dlg.mode())); } else { m_model->filter()->executeSearch(ns); } } else { QStringList list = value.split("-", QString::SkipEmptyParts); if(list.size() > 1) { // Filter a range TagSearch ts(m_model->filter()->database(), tag, list.at(0), list.at(1)); if(dlg.mode()) { m_model->filter()->executeSearch(ts, Search::Operator(dlg.mode())); } else { m_model->filter()->executeSearch(ts); } } else { // Filter tag using partial values TagSearch ts(m_model->filter()->database(), tag, value); if(dlg.mode()) { m_model->filter()->executeSearch(ts, Search::Operator(dlg.mode())); } else { m_model->filter()->executeSearch(ts); } } } updateFilter(); emit searchDone(); } void GameList::slotFilterListByPlayer(QString s) { m_model->filter()->setAll(1); TagSearch ts(m_model->filter()->database(), TagNameWhite, s); TagSearch ts2(m_model->filter()->database(), TagNameBlack, s); m_model->filter()->executeSearch(ts); m_model->filter()->executeSearch(ts2, Search::Or); updateFilter(); emit raiseRequest(); emit searchDone(); } void GameList::slotFilterListByEcoPlayer(QString tag, QString eco, QString player) { m_model->filter()->setAll(1); TagSearch ts(m_model->filter()->database(), tag, player); TagSearch ts3(m_model->filter()->database(), TagNameECO, eco); m_model->filter()->executeSearch(ts); m_model->filter()->executeSearch(ts3, Search::And); updateFilter(); emit raiseRequest(); emit searchDone(); } void GameList::slotFilterListByEvent(QString s) { m_model->filter()->setAll(1); TagSearch ts(m_model->filter()->database(), "Event", s); m_model->filter()->executeSearch(ts); updateFilter(); emit raiseRequest(); emit searchDone(); } void GameList::slotFilterListByEventPlayer(QString player, QString event) { m_model->filter()->setAll(1); TagSearch ts(m_model->filter()->database(), TagNameWhite, player); TagSearch ts2(m_model->filter()->database(), TagNameBlack, player); TagSearch ts3(m_model->filter()->database(), TagNameEvent, event); m_model->filter()->executeSearch(ts); m_model->filter()->executeSearch(ts2, Search::Or); m_model->filter()->executeSearch(ts3, Search::And); updateFilter(); emit raiseRequest(); emit searchDone(); } void GameList::slotFilterListByEco(QString s) { m_model->filter()->setAll(1); TagSearch ts(m_model->filter()->database(), "ECO", s); m_model->filter()->executeSearch(ts); updateFilter(); emit raiseRequest(); emit searchDone(); } void GameList::selectGame(int index) { int i = m_model->filter()->gameToIndex(index); if(i != -1) { setCurrentIndex(m_model->index(i, 0)); selectRow(i); } } void GameList::updateFilter() { m_model->setFilter(m_model->filter()); } void GameList::slotCopyGame() { emit requestCopyGame(m_model->filter()->indexToGame(m_index.row())); } void GameList::slotMergeAllGames() { emit requestMergeAllGames(); } void GameList::slotMergeFilter() { emit requestMergeFilter(); } void GameList::slotMergeGame() { emit requestMergeGame(m_model->filter()->indexToGame(m_index.row())); } void GameList::slotDeleteGame() { emit requestDeleteGame(m_model->filter()->indexToGame(m_index.row())); } void GameList::startToDrag(const QModelIndex& index) { GameMimeData *mimeData = new GameMimeData; mimeData->m_index = m_model->filter()->indexToGame(index.row()); QPixmap pixmap = style()->standardPixmap(QStyle::SP_FileIcon); QDrag* pDrag = new QDrag(this); pDrag->setMimeData(mimeData); pDrag->setPixmap(pixmap); // pDrag->setHotSpot(hotSpot); pDrag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction); } void GameList::startDrag(Qt::DropActions /*supportedActions*/) { startToDrag(m_index); } chessx-1.0.0/src/gui/chessbrowser.h000644 001750 001750 00000006242 12223260306 020046 0ustar00niklasniklas000000 000000 /*************************************************************************** chessbrowser.h - Tweaked QTextBrowser ------------------- begin : Thu 31 Aug 2006 copyright : (C) 2006 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef __CHESSBROWSER_H__ #define __CHESSBROWSER_H__ #include #include #include "editaction.h" class DatabaseInfo; class QToolBar; /** @ingroup GUI The ChessBrowser class is a slightly modified QTextBrowser that handles internal pseudo-links. */ class ChessBrowser : public QTextBrowser { Q_OBJECT public: /** Constructs new instance with parent @p parent. If @p showGameMenu is false, game menu is never shown. */ ChessBrowser(QWidget* p, bool showGameMenu = false); QToolBar* toolBar; public slots: /** Store current configuration. */ void saveConfig(); /** Restore current configuration. */ void slotReconfigure(); /** Scroll to show given mode. */ void showMove(int id); /** Invoke action */ void slotAction(QAction* action); /** Show menu */ void slotContextMenu(const QPoint& pos); /** Show the time in the String for the player with @p color */ void slotDisplayTime(const QString& text, Color color); signals: void actionRequested(const EditAction& action); void queryActiveGame(const Game** game); void signalMergeGame(int gameIndex); protected: virtual void selectAnchor(const QString& href); virtual void setSource(const QUrl& url); void setupMenu(bool setupGameMenu); QAction* createAction(const QString& name, EditAction::Type type); QAction* createNagAction(const Nag& nag); void setFontSize(int size); protected: // Drag+Drop void dragEnterEvent(QDragEnterEvent *event); void dragMoveEvent(QDragMoveEvent *event); void dragLeaveEvent(QDragLeaveEvent *event); void dropEvent(QDropEvent *event); void mergeGame(int gameIndex); private: QMap m_actions; QAction* m_copyHtml; QAction* m_startComment; QAction* m_addComment; QAction* m_removeVariation; QAction* m_promoteVariation; QAction* m_VariationUp; QAction* m_VariationDown; QAction* m_removePrevious; QAction* m_removeNext; QAction* m_addNullMove; QAction* m_removeNags; QAction* m_enumerateVariations1; QAction* m_enumerateVariations2; QMenu* m_gameMenu; QMenu* m_browserMenu; QMenu* m_mainMenu; int m_currentMove; int m_fontSize; }; #endif chessx-1.0.0/data/themes/boards/marble.png000644 001750 001750 00000175252 10633750627 021256 0ustar00niklasniklas000000 000000 PNG  IHDR/ pHYs  tIME * IDATxڼ}$In%:NJNܟC}dԨ*Wp3ܣ֜̌p77?'0_"@'h~@h_ /Y+gK{ xN^Ky=f.bN ~.5{vy] , E oie88e,'\s-\5@f{뙡 ǃ6ePh6}_}p,oo &q.0> jw#h~͇"37.ӽN?DâHdȺiۋDžYgEq"7_]7?<* .Z`Uf^!F`{ lvnSRS>Df3|x$D~ 4^4~:S~~x tJ ?Wsy L̅$kcwnOyO":X`8Y ~gx@&k19zӂӴzK`

m E !zZ0 BivƬbX>?K]6ܭُkhEK.qy8#6 9yO w;h.qh,N~ ?XH݆5f! 㡒wc0M| 0E8ųXRf?,B}\<QHNUM.0!aq":95oD]iޣsqe-8yhZ.8!X*|6'`x&\"=9D,,Pq2_3XǯIBGhh>hp#X?+b6<rc}y5`$˫3{o$IܺZ];H)<[1x4X~"!]^:vgM؄u} 8fG~e$.e|>,(inLnJE IA.̥^}tDz8e>?#`9uҤ|(߼gC[ .G[d11nUA{T}`,(UU!Am;ӦƆm z^kO1kUPzOo +,B2 9\c& 0:kIM=ʔ!C:w~ElO80L^搰-"a51܅HXU11G±H:TXzAi- f]bE gcAfX8)3j]J<,.@ǻs3XR_0+**V?G ~aFr KE^-'Kreܤ$ǧgN WC# 5^z=lb{N)zf\G#SȢ‚یv^*õ)%ܿ$:h1upo%4kyUt>5tdohW:F^R$ZEU-bgZTzxOas856A9g*0|H(Uv!-.fm݅B/KReFU(eP:k9MM[ ֞ٵ {5ftWW^v_+iž9:l Dh]|YICɵ̶J<'$Bb9ed^fD, !Ґ5Uql*d bhqO06kߐv^*h֢]XYД?aF-d R_EMTřd?OTm2mAKSe&}15bo@T-lO9zQǤ~—`u0V%ImdikwIUr||yofxDɺ`4I6Uw$uߴ^sylʤbclE!X:1Rħ ;a*M+9ܜr#G˃Qل$RVcѴ/8 O_쩸`1i\V̵ǮW6G×MRKs,>*& R+m zXC"PȦVXݡ&/l|e+hۘ@ክlGt%)Cyh.\CZw^9G'2ns6pB)»(0=.rf+cp 3OO(#/lj3mM`A'YXjd|>ƃ`Jey9 *+_e9ww Jh)9 E 1xlVyIku/ɳQae ë́|w+4 b<0oѵ\\X ŵ4/iYrA&Ix+֥K 6īHTSvA!ӽa=&6cO7b_Ϗ[`_1Kփq2̫5wά^2ilEMy-n5pa &J3՗f5;Y Wɔl.g߫FdJmStCυ_c -x9 >:k-oƚiwX]$=$fB V#o1-$N/ 1 a}hB S0LQP~Gf1Qk0RXTSQ٘`hãhBH|?0zt XB[GC ԎfyPVbǣl[%?n:5B ixtq64q?4smz ޠ@(~$s͏^HfkN bcneeikrޅUrjm3n<i+1zY쉯-;jePOĵDt;K[tKOy3b}Z6-Hb`MZpݹv%R?3I& Un0؅{}mڲruuy2S^Oe U''uդ塣d̜ g1n]X{Q°yYVmcf aq)9ڹpѹdK,5 KT$ ]^8ABKj>]H&D?g6((tK`N-:)`"peG/&O> -9wK&F_4;a㵞i~ҥ,ml{uNƚE>r@pq&=O.b4{YϞAv62Fr?tD  j!Аٟdw Y410×T1^bA48& 2!L2(";K[~X^=Ã+D`UTJAaf"+Y(X/mchru`\[zfYRwMmXc Ix}m4+)d'EYt(r"J{(jKa##t]Ӄ@σ^mའ0vojl;VG2Bz2:'{cW@mHyß̟Xu&\TO|RHାrJa9.)p5tX&Ds5GaeϱK+I_J]5:K<(Yn:VEZuXdA$@XF_/H *jgR)z *5q]JDjXe_#1pȌNf,i^5Wbi(&<2wP)uFiA+{|WmpN 1`jd+eW[s5bt,"7jqJ$+=9W7%5#5hCx RŮRo֕'-Yl3SP=.kbEV3:8W ŦbTRfUi&y¶v z\7]Wqe69G\"bbѵLtm*`P-ˣei1`I.J(X&҂jItMT|{ v0'k QP5Rwc* |V7M_B]UT*} YN 8.tAg,mlFM[am `05(:i=|ťTa,ml5m6<Ry\{U"-QOGQ^!0'ͻ/l6gZJ053LYNVxS`,V9M7E/O)M xU&f˗ah~\ X_ 8R ”&2rS0"?!tuTU^(\a[5}.IsN.7B=ZeF&%+}JrK7t[ f@G&>te\yTs QI'uuXTT=_l&{Y\[P(Z! pg'2^Dl-WֵO?z$fd;}xEgGvۄ62UfBinYzZk }HtE0ǧD o﵏f֐˓:+6^78e5} :Ńu0H27TG';DoBIz0g_<T̪܋P9*n묎zZtﯬ߷!ԴK0u6 8ҦtD(`yR9m⻅Pn-䯉J~>c sse/>& (wDpG欚 4dakʣˇh v.W͏vS6ޣ`R׽^anu.b]웗ìW>K*bQےpݩ' x(k^̭m8*7ʬ##ujA7q 24;Xg󹒻x+&k 3ZL/VsglP?u4A#Ym2й*jnʅd{lژðySۤ-[iWp}H2 ibD;ɇ|M$\.BPTZZjAo)k Yu"A|?mr/l= eZZ፦N!XdZt 6Vq k Uaϣd >.чF(H%3m^`!pǍ<+t\͋g#?dhYh"ۜ'oXa>u'nH.?ȅ*MnE{P/DG\p,!"NǰSG@&(o:2C0׆pm8[ (7Տ4BT \7Ճoz&xZ"^]\Ļ%.z͒e0n`TQt h!`v+`ji`(b:1P#d6L!Y\ 0Eɠ%4Tlp/<>0cΦ~}⑴/1 ʑP̛*:5^5tHzoѨ/vC]G2K#5ei>^‚I MG6oTҊkX)T J}%6iĆ#K ; M;\ς-В25Pk/4\"X{]uqC>Et&KCϹ&3 }2C,WDt1>mG1ljhK3Nx}R|A^RW6x$[SJP;$3JQJ9zDRWrchۑ2w~0{iS0K nP }[ F>^H'6-bq;BKن:Jw.ڻNj5㿟]h@fS:JmBl`37+&u*RMqD=aJ@t, o1e!L2ō00ۑv8u+E?O tjZno^K$5'x񅛈7 Xoam^y0X fG56ǹJsґdAīVŃjG|PE/QWwF4ʮᡈA>6^ruK9'=kz:1X]kBaX?F /Uߩ\) :"igOeGuԙma$[.S^b B>GH`p&Ĝb6Z2B#~!vN 7(/;]5GFyAs&ܸc*TO*14y,۰Xz"SR 'pTsOzz{-寂SyNr*-zh7֞>"#xak% `QO6sZJ22ti5G$P.is$[jb9|RkPt\mɫe2Ԉ^^|~6I:DIa԰=Âh&BiM:va}o>|$c LaeB}B=UnCUJ Uv&ᅁz,ևСL6jjS{ ;FWMk;B-SAOw;Ɗ/S)0#ba؇55QA6jFhޅ -aXS>1*Lo|,.R˴)% dQaH~Du. C.I/.Y٩" j}G%ɺHbZhCB?TbR z9 vNfEEևbK= }Z?H."Kտ9O6Ȍ赬~"z2Q#ye.2h_(j]`}A?Do)/LQg_ąIYeġAO Ȋ*1W YBI@b(WCtxc-\d5C2iy639flli0=-a3NL}I,-ut&U,L͏K;P1ѮC hl&YJm 8cFQ`Ab4rmsd'!F=]?-l'\s3|zqӵrJf]PaɭA(Inf.,f4m=^2?zQbcvW&!+FCmuYl69KAb  Mf AaQo E@rۧ;_W %dG#A.҃Ytr'6Nxw_ #75C ծ%ȺsQqE8%C}6Lr!2@j)R 3nFPHa] ԄvHjB!TeVͺNyZ&g`d ʎXFg"(]zf$ߐEx,8aE ȓ+ YrrqS > 5l{^=I) VI ţ#̀KDԭk^,6 Vj/ t4%zvK /y vd%b/$(Y)**1-"".'jLoAkUB󆨹8u$of7ѓ6jᐬ)$:if6>4$Jp,e(gr'8FhQ2 Ar5]2=ޯ| !QRɄ~_[I:{l'1;!ML%olGI4A\sU,6U 3v d$g( ^f׬A`Z%&u(&͋8 kFAɇ;B+\+Zm9ӭL_I8@пQ2[*ϑ̼e`C\ru-X sqe<$[^nyuԇq H3(aT>h[{. 9- }˼n;[KQ1)60v ` BsD6g1/VoRCV'LnjL d&$scԖ'X%jEpHy%(Y9Oƞ r+VQڝho^nW/0,Մt PypcB!DcLqS E ,6".M=-mr"=psv?9" VUإR+:lQj Vͭ,]\zҥj㇂^ca8wD:P%=[ Lq(IJ{,s;tI<bqֽ@.W5,0l!y4[ݫo\5y֬HZ0Qiyqæ w{(V rVy<"l[27i_dcy%Řs [bӶK3l8In !7{&0QI0 W+<N' nj5ki￈PCU&!;RuR5ulQ}|!=QUOe},Al[^B`g}`844ƒW6!I[$4I1=Du&̹EIz!ņ9/ox[ABEqq) rͫS|_dX{msPq0q~C<9T+*j۵KΣ{dfBRO lmʕQ18Ϥ#%ʝ+h*y1;h.~=[ykHt&j0}+! Oʌчc,ub#W4Oi: d<{d4z)l˿G^d[.Ͻẓ]3v$ {`W-L‹*̽ $/WSܕ p[*Ƃ-qd2w+q'(P6(1ڱDiKx6>zRd\rDݝ,iZY|7G=s, oLtc 9%_j0iw` r7UDGbO3Y\)A{q!9K}3ICXПfjq5s}6W5R,^&6i1\f#.ZW{u`|oƏH,g'm ͽ ?ڐ9F1tpfsc[Ѕ n a1/OB_~8'N(4 6-!nJc}9W_F8m*|$z8DtO Yo'%Z\I 2%xߗvH?mr0vh.>%7u:NLa.mOT?׆JBN⑃><]U|l`d{)(-]FZYY4@w8vMi@KAE4g'(E7m TcXE(=Y:-؜i%q2''4]w+y  ĬxA EԬp 7h'IzT6QxLErf{RG:Ӎږ\{~(ۡSE PnhVƗaoŞG@A\ÿATDS 0Q1^RzE沇O9%,҆s$auJ(fbcS>j-vXyZy:0@Ѻ8:Zj+1b%$zq(e+ BX0n3CFP@@p0\!OEk̘|`675"yK א#Eb &BXZPM@*kZlNhKv %TJie'4饐S%^ravR& ;ߛ 5ב@Ay>w l,iXVXsD:A$a`;#G639;O3zi" p:,o: Q\(&rqݪ +̃=uFa-˛QBrdD[jk,u_23EӯzdZ4E2hRdd_Tu4I*B"ɉHvfD_sy>IOgP C`s<`Oo#Ձ+L nLrA)~]&W>tg̟kk[NHX-|(4BN$>Ɍ/ׁ -j"j!nҔb50&~2t 8ՠ 6r8za kŮ`ꖥ>F o MƏ/w ^d$IFl VT 奎zbyr8 EVHq3W3>1{Sp{)4 f-\RxfM1F%lKU-{ɄWǩ_# `v 4aUELiK N&_p|~RӇ:pu0wKCGBM)p gf sW(Bu@biJC*tz(O-!: IDATqk{>zαɘg6DDpΠU3fCn\[8}R֘q@pƵqOCkϨø՘a5crn9֍@˶MBJsÙxk= as &vd&"a 5'Av'o(A vTTW(h6H)< 'RH!q\<;q=Bj w`T#LPC;GbY`/{v7D_T䠨J%.*v-:UKp%|7XZhj'Cz^\9c*4ݣy̕F JOF?:6#$7ܜ"SKmjvGme^Awxޕ@?ݨVzGSyw2_4}j ֢UbaC5j"XAFvJm k\X(h|K1v0q|l`-Q"ʗ"zRB\z)6E~7&S-ʦGBQg޼8y" 뢶Bla;4~HA&zR3M`ȚEgDL TU407<; H A-œ,ÓLJQ5M$+CbQ[α&KRP2UťQi1ÿle3[9$I(ñw{(םhuu۩Q ^'xx7h9dz r1p7ϐ8B0B) ̿mi1Zǯ2ѝ9?g+A܃&w3{FwgH$Fq fH^VSߚ$VdQZ2=*kz. `xIz 4_^51+ZȐbyU8CB/~ u :8,& NFS V]sd6qӋ+P{HH }!$/)҉6:r K0ůlŪ`n݉C`|EAWdb0 KXƀ(26EDn^d(ƝOi:r7k-*I X3q! z$\ױҧH͞dr-!9ŵ;Xpè]kpq E,DSDJZATԙuFC'7%'s FXɆ휨ZY) oPB)M,<> +k"R3,kiU24%)6~bWO|:K7!mg6oT<1d$ܨ-g~ zhtձGTIaBP& xֆE9:!*.kwOitQ>ɒ6^BYTwxN&UF`%dpjG Gk &xnZICNyLLta.cR 7aIޫ`blw}7wD֕8kFź~"^Sy[2#$uX* ,ӡYRrFKSt*fcq]؁iÍMR1*[BXjeӇ?4ngA/]y/J",Uq D֡/ R؆R:I\*dږ_,1Awv_01'G|ꬤ0γ&,1cJ7X`3n.DwRU1勈8&o1Նr i8Яva.Pi. ^x\u#b<&mp]Ci`KјxSxH0R17 TE ~4?RTEPc6)>ig95&lP>;DdKsH(=(W0 VNjDs ,wuk)ϳ̦ۀx$ZS"Ëj]q= #zsmϺw,{j3~(/^l Z-K5Ma`*9Q8YoS \P7E"9;Z<uŗ_I ]rk-}GqSְAvp1z;0lGKSw+i犷c1P+ *"D=56j{yytZYBݨ,,&BPyA*͐5Qͩ9n4R}ǔ;ߡ3HD.O $$F )|yg{&3z""nX Q$5J ӅT0`ʑ!O> WQ4WIw*|# y=r)YVܓ Bb+Bbۡ"M)7s50$`;4>4x+*KC45Oס'p>$ ,-,7Z$ݳEQ6ͯ)DG;6FU[~G^1<'6Q|.4MJZueSol3-5Z(5!i =6EëbP RuތxP^{R&q2-HPPaDj;Sm]#»1֞pdFq92zV&[RƊ7R:M E#D4h%iه~$I_]ߟy,bVdJd`ߊD\hYmFYl#fp7:Sl^ԍcee4IԦagaHXưlM%#Kq-4rEÏ Z;rkTZț1 s I9D}3X]J Bxbg`zu(3Q>I؞eMqՅb8^6TnqGÔ)[ r#W(lFEqNPv^:-EIJu$5 1Kl-qP@:K[^"צm䈤=OO@V4-$eUjwPz'T;Y3=nJ"0hVQՔ>p$"*WP_OMCRyx&vȅӁ,bf'lebM[;CG E,o_RLCq 9v32V?D۬;ZL( PL$;=`|d4bB&oȋ){S[ǎR. [ ·7 ̓IqѳEQؼ'_Z^M(2mUyX0Km&`qW3Dk V6TOAUmU4|?OaLs"09B6 JkŜ.-c5gXcx;60;Q3 !$=gߋUcJ=q35YޢK,a%Z_${0_ֻ4P@uΕ:M;(9Y׬(\*>ϝpxsd䦔g@|8dAXt{8i;%$ui<ry4 g8FǷcBnz̞x) 8\4heIPV@2Ew_]ě}hq<_M ]2p%[jIdVjwA`&,&Th_io*l +ur;~'ePPrE0Khޗ$Oo8"iɲ4};Bl׫fCZmfOZDxD9!2s̤츀uS~aVr o"{qd֖jBX2%VTJz1jMVM@Ȩ*W7#V1SnC=W yrWir\ Iӳ_!iݵv3jg="`숿S5l9t@  S`Op;pxg2̘1b?\A{qټ%ЦoULATy{^(j3Gcg[}.;Ylkwr̚YCð̎ۆdwJ/\T|;\kIQ‚B6  b'^Dƃζ5䞽XH]J(_3at<tYi8^{Ԣ-j\8`tQӉ`}Č-se, &m _!XHJ]{MGB^a"5]/=0Z۾l!x>1D+i6=b8 At9l?Eeҽ%ֻwכ*@Y/9]5r R$چ*B'7"J'M[iF#pvOqs>SqI̵L!&MWKp$-X / p܆M> mn&?TU8փd95'U[%qd&79 '桏 ݬ"1l cD5T*"SK?wmY֔y- ~_+98O 7wjDQr~s #zaw;Y6i@׍B =P=qXCƒi5!gPE##,A,߮9//YBsbyV` \Lɀ頕LZoƽ5Do9k,l!TR܈/ku%ES/j<+8 'Åƕߜ'ϫquONT8:+vǧe ׹Nbv뭊pd+!3ǞZrra8P2|2i}Q 1+{_Zkt 6I.alpn8gz}\Apم.`deY3FJӍ} {]W9ťe_0{Mw\,Xn>Wb{>Az3e W0Ds㋬Y%šb$Oo^E'FMo CMuclv,s] s+rj5kDŽ Lb쁃B^Š!" 5QfmCek:FXƱ*&v'l uuctՖRyV(U:+:,dP¨Yb=y!iJYև\vʕE**%4gq8{JB0Tm6l1E{ @pBǻ s-rD sH4C,=iL4e(#h~ћ6R93y݅Ll B$nw T>E.(k}ժ(}B-{].*hhނK[&B IDATpe1[T[a~b7Q9t5*optl=IkxOqK7cN<7,:*˽M>Go?3>bSުHurHP@C3 Q 3]4RWn]0E$Se͆d [ ӡ>LdRq`D:CM0S˩W|$EW;*J}MQzdD'.5s޾NUbt6Sfez8߱6K|(j)Kv~snFX(oIU^@jOG29{j"r^SǼf=%C uOOxe7%kl%X_;'uo pCS”tIh4-q"(\kEA$Ԙy>TC*Bp1/ bh]s Б`B|?'+}niY=h/,lXp`fk Tlce).fGN#TM*SH6M6|$9G7Kb`UP,}-zBZj l0 X\@ԈE40bq8 EQ"$9ЬӁ&b5 ,.|{H 0AqfAsIsQ΢X- ^~bhDVm9@aS_I GϭӑpK[a?!\\Z~s&vFCbK~qpuou6)d/j0T-3"|eV̉z6mjqn5Y 8loP+Ha,:>?=|(Q#~ [!'!'i ņPʒY"0:q4FD@}c1M}a;[mvh8#kj #_IࠂaTEMd+ǿч W©RFޒ>\mB{ \FP ⸸ F>k91 w 7 ac+d4HڏyD!^V8ʣK`s H!>ȩ*bt+V{½OSrz{'E.hUe/:q>Bwk?֞OUh  }!KuV7@4yb d <;c!_l/A@.q=B#"∶ U6>*6'xH €hW@pjUF)J/qAu#NzY5dQqX"iK8^/&{VOa Ġ•]:y s1Łܗ 09p2qa%m3år!*2ÅW<  5NgfBBDyɮ'YuIy?뗏7vl^X}qK!ײ܃}GcMCG3mae!"8$59던$;Fsdپܞ#1c㖀HVߑ$g`Eѭ"˛Hj@ ʫpQAH2O:+K8Yd?FB88lN>4^d$=b,.窍X27OH~x-pkT3̕TX!Ng 뛢rE5YsD@$A%&&\~MÇ7n|py㯉AW@P-iI{GV-Oy2bHk-7tΰG)ʮ6 ra}O^UB=nxכ} v#3wz_ĉ9.~xMb#">>r9]Iv2ߧ&Lthi 4|M>cTL6BiTЍo}ܽ0G^us եŅu7$kw_wL?,mYvH74kh%I+ѽoc#yġaMx )os|%O+:|'VMϯ1gK}= ^yڴJ")0rhRh{} B"]auUAB )UyK2E!*dT)E& >Q3 DkytAD7Dͦ4GB9y(!*2lַ 9`!i .&YXu^`.<ȣ"bV_)9ob 1>Lz@Pq$^U؁W>Z-JE])3F ,$tDU^Gh}c x촸4ԡ*,b[(Aۡ=e6­9P*ӟՔ` \ǁ_J'\$uJH,۠D aY~Aӵ}gXj|NIoJS{-2f6Ja(ϴ,;Mm/2=&įs-2n=D5?:";>^<8 O?JH7hY G1Jp\IYZmЛ~LZ}fL7yFCMT:SA)ITd@|b^rk@~6 "0LgJ)|tWCDZ?CJBȝS&P8>tDJ6v 65XaMF^we5^c[a) tY $VuNV]k %:Ӗn%k}X+}D" X]Y#_ BH(Nz Cʅ*y+1J>flm]dMIf)rcd>;-,ڤ>' 7_ zOvjd8Q\kiiy͒ y&G(>o%qF7?رl:PAzo+$vw ؜yQ| M6ʝJ;%ZgǦ?(1WnTsqHIoR2=ߏ~4~e.J4K,LPJ"0!bC:;$ Ƙ͜g$$7zq@`-_NM!.;D,2CJ%R<%f|i_"@&] xj Iq29 8FhҜ+^!Ґ %'n u|`j$-p:J3K]/2#[ C6ԭn41tXN"#/krD?c𯻮4'<#,`U]9n r6"?V@%BF-pf#+kb=۔']V"]MO/ma(/%4ozCD! GDݹum6G"s:5쬳d,\8noJpNQm}VedYaJC*r#lDR:^|J+hxnv=״wafp81EemIO:h0D HI*\o@8 L|niLsNC iT]*R!l^nL^+RZV, 5%E$'k^_cC\fZ6eiϴ(1ӽTJly]I|}9 A 5jΪl[y'}ٓaiS ld[1'}#L:D:c28Ue ~7l6"@Z+Qwv E#jU\wSm*auDĤ i\@ ܅6˂1L>,׹Uo, +3v3^,6#c>~).\Whx)8E5=L[[C //GD?J~#,7X쨙_L1ψ̛֟9; Oوw21Ua*v2LFw|P1I7՚QMJ7- јA K~t Dt$<@u ѱw1t~!NTp WݨBiefXr[c΢|YΑ^- g,7;3#ֹ3n+Jh8ʼn;sZ$RMLRdrئoI5XJɮヿA1It1$^ZA> Y-L,fT,unW'MCNۯ*y32W8(M43D´̚\(O BSn$u;9bK f _6`*m!2 j(<)m޾8ʷ~h6Η0Y;Mג;4/Z(d_ `͙mzTÄhj/{/{ (WBå/ĞoޮQ5P a>d7YcEj1G^8Q78$s|c 2gLȸ2!t4!l Py~57<.L(WEz<7Ҕ=c9\yΔVR.0ul58.Oh|ǯZǏ}.3f8|S G2rXߦdCDǯsQG?:-I7[d'{ɕDVgDBd{R0rOMFٺȮ2espNyWa񋆕jqH?+0Q7?4,/|7;wXJz^ʾJ>CoGhz3оᮡn%A0'qΉJQx#s?BWT3|#˜{ aU?XC;PKc_fSd>"R ouУ(s?IT!g45\͵{fr=qfTtytv-ebhmodhN2H>id\uS3`P9R\a-Q3rrCjlUwArE?JI7{pV_J%\qģ(,X'U+_.t].{<.ID]"%et]=_y=$8%Y2sCkϲ".~IN?D/^O'z" ߇/]y{/=q=ILyIN?"z5v"?gǕʁ9K'ɻJv)=Q(Lh8O!ӟDHd=s<w9.}y\|HEy{|vvȮ1uQc|.:ItBㇺK'=} ]xyg(!xxu=1VED,R5֔@ )HՒ S02{*ͣA:ƺ.}MȪ+ӂG3<8]Df v 6@^dU2`ps($u#T!q)%ɩXs̲##ܒԠ*baz#΍M6>[wz4[~ΗTTZ)>[ @.DBKk0LԈk3:j's8AsB[mn-\Ow:3 j]oRD1"SZFB)<)i.gT7O Hb& w3hVұA3:ʦOrJ&xh_\OfM^-@6O7EU֌<´Qme)B#HiI7뵿N(?.7I$Xe'[Oh&2 yC%o/h a[;0ʷtmu9T]ܚNNؘMm J)IVo^>tY, !۹ m~,%mը*mJң nE˲$<>X(;`֐!8хfz/qϝ {`OCJB7 unKbxV'l.a)#rWf<&$R Zv!<W0Z,{s@YjTc]}s<TvyiI[yΓI{sFP ]L_Ή`T #ٌr2۱t3 %S`:;]uPzJEf_dj1B,(t2\mP$-iHGF_ܰ1YQ!]#qX"0X2w_EM> њ׉2o=A06alL_P)Vn qm/1M; R: KC,:=M7<EYZqd39JU)%Bg+̜!⏃;/)Ɩ8?Mܤ"c'o,mAd yd^Vީ9j[k`LgnGvoeo V@=,n/ C"oe`D4ZrUQuC1UcGCog?dePٴaQu̎ (6(;ul2%?< "5 i(>Jlt21#Z8Q舞p 9UgH~qJIj-T5SWq (%ρ!m{iy=q#{VVy`]C} y'48 96.I50>Aܳwhy1J~~џt(睳*(V2du͚ېPy# Yw3jxz&xCWx5C$ؖpMJ ؙvJ%3$ԊJ9܋ȼ^Hp}W n5 ǀOj*5͑f{$ C> B(U!IF02Ji27G?;Xy/ޒ}+m-\ mrI}Z )q^ ;`mbIuiِm \r\1e soHK5,RBCY.5>y>Y')kUK%).F}_hͬ߶3~5eGg \ƖX;3)֘I? 'FETftrX4;SqMٍ>$p[Gq `,:4g0ZWKB;ۜC[SZH4{d'9/aYvLӹr+rK-C+䧋 I& N_@V!ͮ(jpQBY6x+8UW!ݾ2 8v'.Z*i[hru+o.j9im䦸yi&Zw&jl-?PYSjZzƳ_&%čCrjj.Gf)g0.o'V]Z5+7K:d(*9~:կ',zf覘)rдm EqВ2~6J;ZݾȔs~3Rô_}5(@rL)H=D_] X$l|H7?qu)j!7W*jMa/@#w|K%"o g4Œ$INxď 6,o!4Gl,VRPqG`sra :wA?nJ Fq}sPZS6J?6V Y1s"aTwO ݦ|S#Bam ڪ;SLtnfZkO)NoDe;Mg>,7"0]~>wLh?!m\ F}$w&ϩ̝:Xjo爳Z!~!s}KYW@Vq`.=ĺxyQU rL-Wgv M f]zU?X_R ;4YE獧hskF2gT=ߵ礝BЋMI/R@iV_>JY''k.E$kqĢx/tvOU&v6x#-A5u5fRIHcޠ5E2A)TB$adeM&TjdkM-ʃ{: :J;{LYlKhg.U-'f)mz iqm{g`~ts֒*PlXʄRعfүgiX;jRzrCa~% k9:7L~M $'s+FDH0Њd[ASjꃗ ߳#sͿeh{*46977MCԜ=d?<"b%7*ΉM0ʓFOEݩ7fyb/.TF9:9aP@3%ݏ,8E[ Esd}_.P6w¢:AG7Y,ņinc!+ 6a 7m}LrY?Ofbj9+BzZ6{`=^% @/ܮx yPP+t^ހraqnvZ0iϓ[xiv(5EOr%>t_I4"|a7k"S2lH# Qd uM:eɍgJdUx2[d_IItZ=Uy#C1e{ |MPsoAm' wi!lnN&FcFH@b!q jbjKS&+s}7NsT`e"O,,p.#lU3O/#LHw!+>[5~= \%Cpd/i N\:=8 ĭ$fk("&w/%Woc7"*\`8 |DQU.5!I-lQ|Xolxj|oM:a]x@4pw}FqEo~&F9i2hQEޜ)Q-|Lm\g:ΣP>ӌ9y'LPI=@67k¼Qr2m%hӄk9\LRȸE\qn0rp^c7'6,>b{J<`x.eΧ6Z=yw( YrL055߯\i%-O:ǻi[֟;@cݽʙе_%bj~1okw()UMN@ec.L@3n ifh3VFD{M̓}BR86A oq 5o+x0#3lR~e NX-̖%\0$okj2舼ڗmߴ;(T{dZvuσx4I5F&)͘}y i~R΢>$(QJu<?/"gzd!rĥX2C1:瓗X o]O3 # <4H^ұys P[@IkFZ@Wle|wAA_-7I"KHAUS!Î5-*$Ej84?L3Ye :t'?N%cb565ˑ#Qgݱ$eŁqxHOp7ʧhks~E`n.s qpmuN1;*`Ͱ fͅ,JOe7Ħɂy`.^Y }Swy'KP]dgկyTzyqqɲpjIţ)%T"C u{:zTz R5tMӍ W>藄l=XA/4i˶* hL [ .׿[y?gSh#ϐ Z{v_Yh84^}p˗?b޸w*Ch5esW#SrBn1k/|6)e"e^F~ȚyiES#IJU?F&H3[lkYϒ2Ћ ::YQtQ7׾԰6$#{fK;讘3  < [}߭Rp)%^En>}ĜC=&Cra7L1Ȑ]pdjq'{-1r9;[HH 4 "Ôuuo-)),.n ;u *5۟)ᒍG#YV uSseУ9>ChH#`~ֈ:IuNtD<6l(iX1$Jnjnnxb &H~k~F],6-TBЕ9{Q6s9xFYz!19CՃr>^CZ4jZg<񖥖>|\HTm(UҬgՕe-h|)?چa+Y a:Qf[rf`#k޷"p7. fY lF41q%f+++nˢ!V-&796[SԈh` \ށ~2!5s"lӆHMm;'JD8^?>R0qHykIx|C<D0:NגĔ 4$VqrLߒ.7tMm-Ħz X]^Y㤢7עPp3Kah=Ίy mژ^svdyS*l%!f8jզHIt}N߻$JM{MjzI5}| * S_2s)^ΰ2`l9.p3eeW#`iO#5"ce4qgj&ٷmj( #WSZ&?<'.(Z g;h+bIs"]?ğf2_0)`N"NRTa4F8m׺Fph̲_|46$fO3ic4Nty+֧Zusn z~0a+E}Th*4;k/׉7+mC}DPr|-ЂsKو VF̍tOwS8⺇]78anV%ieh:Sy Hx6iBgdANX+VA/vůRqɛ JM1mDiѓ$lgΓzW?lUʠfQ`;#ͧ648 kKv ; g>5ͨcj}UXjD|l̰OPbqf (Pmן<z ΕLP-q&f_3Wǵ~.*6U  \nDfO Fg uNEu DGk<, ڜWNh^С2K|ѧ!0i|<>CmfC遦i*(rH1v8U8䥤άkP&i]9*r4kbqh;ZP̘ >9Z趏\'q| ykhI`k( cqoګ'pڈFy0DzMo\K#EY?B.*A@ 5"\bPO+s fXr6(c8pIg,Fw@eIϲ;7}l.yVk㸎m IZGi^O\:`%y6u3Aj(C)g}HEa7Ogcm6(Vѱt&޳tc\rOsoij`^X5).2{l=4 eNeNUfM-R-NH4g_!b%k3F6PZZ`̲InxxRPg4A8TtFpDSHa[Z4`6N ǷN5PН&搐3߼u=%Sܐ:y OC~Oe%NkJ$kR:$tLYGzgf:(GPPuTJvjaeQ \Z)!YN ~6C|P,N<Ɩ(.,eL9)fy|UAI54\rW(ӈBw9xs0 6f  ?e˓oS7@҈³pn@_oN P $(H2 ~xT=.ϽT:O-WpѹS)K6>Yb YwD9t(0bfyOf7NykP$,cSJYJndI}k|w'+!5N#/8n}.7f(z46-2̨Zy4!-NtRM h-0!'HCk/KO\Vk-`m(r3BņKcAqkSgen1|Fț$\g xG_#鍁`WL00hp^m02 Ģꑽ)zȚ 2"p3m0s,liF<_\:"!6N /PR/7 sed_C{jML'fW U<4! na!$V۞oOc1#Z_-alĶ^׻LN8^c7ԙ#8s)WP/4>"0͵ @#; 61$Nf;_D^ɶc gIP 2lZh>JRR%@)YXM!£\TC朙# B>7P&ܙoqhwg.{gI%0j@JkSH[@^UbZt@|4;o^sª4$PE.645@-U%eBDҖ~C CYHއA *Kc}9c&lb %WkYsd[aI횵p1 [a9Wӯ6ǎRO}X@J{AVa'cq̍_<bs[AkK#GhyChyi:>и fgvvPnױ;ʺӲɍQ6ӯ3". *X}Ũl0x-q ?+ToN~Z\$R|߫1ϡ|oN tՅs!5t2FpCi:M`RΓ>#\ӛ2+jߏi_sWb֣ qϩC=Jo3FQNƁMSET[n-:'-H 鿆m`.!bRslr7lGF$e Ѝ?7A۾?n@),L(h;'3{ # DA'i&L7$mZKo1_i\ڭl-T}4X*^Y©x%1+$EvrWo)Kq+[zt2WtwS)Uhnk^Ww !5"ÔhλzGdԼ$30G, cu(ԍI^1p!0?mP-I2VɦH{dVdOg rm^3/̇r_ifC/dBˀ@FBYh76|xIעσoCT.-,bfFk+rĴFXy.8hRovN?+hᇺ/U{o,Ѥ^?ǰ=Ysjq,~`!Jng62*?_ЫyJ78<+zƽ4SWŎB2>J5۰;jā} avƃfDGx?M+;%+[{Ar]thmTWW}t¼ǯtב]k9=S:i\k(=[~WoyS!|w'0h5Y&Yف" HF;nzF(Ϫ/L\LX̽jɸYA766Qʋ̀Ty{ʏ(HcȾכS~0q#iCoaT-:8BUz#RNf >UM[XL/ݔFca);c|DWp:p&7=ʰZ[C"i#X6]̵K9'gҐJ7T:T^jrpIވ_l6)ݳQ9pZ݃1p9G6%?)0'"Lt@l8)%T' iZB\.Ou;f.\Q2 ˄gm"Fsr.#go¯J96"ŭPʁmyk ԭ'}pS XsJ4 ^ sJ19m1XY mFn>˿_Y)q21a/RWPFװg"!^ݰ4m# dH$,x RtJ~)}FD% ~[#Icu{wG% @1e.#%h%@\:X~6v9}B~]#mqFU7+δXuR4P^Yd WVq^s>?`!;i=c`xکo (Xv!UnUeslѳ9ѧi^d%EFve|SeNf5j49|'n\ŵdON Rg)7=CR'/m}pw9PYL:Ac)Nt+j䒸4wJCb\kO&F,^o>}rsZy{Hƴqq$,L!N0)`@b9Y6F=x3O"r5bmv߮0J%Q6 s״q]QR1ȀoX֣֚ TRWհf'i)9 ?x_iS*Z@$#jQD &eGMqLm[@n-p,,{LJ"SV&Y5E'1r03$Ax#=ZWG)GYQ32&?_J1Ōͦ@6!rӳo5t}!Rhn"㖙<ʢf:&h:'H F:Jj 7,{DZ J"CB(E^|~~=3RǨ(f Q#I+%| ZNgE$"Q eBڀy]\f9`߫E I3ZFs9CF1DY2F-Y"H2UgvBcGp~mQOjoRU|3[BYfcl0Th ݾHssV\ {pwa&ׂeݔ )[?U6ST- Zs0HǙXP[ GIKOb] ]ͤ$ f "nRե,zqGrPA⌷ y/A{Ʉi&iom +}JM̟QrZ$aSG:Bh\B#?DQl\UIϓDm$1 Qxk"+l#/C&S70BI* ݀2-% RNn5;Aa(AR9ڍU}J`Bh[?\k`A9A.\hNDc=y_IC?mJA`RX[&Yy,OH̍Mߐ,m^'ͮ;Ү!Y:23,1hbC_]?&0;˘YI!hgK1W!UE_;7ݑ b&Y)T sS+I;p& hmXY<߸>sq}?hS!kX_!*'qs=*>IxF!*CK/C<>Ѫ,; /nK f%Dž&]Utw%%- \:q8U7W -@t|Nt˖5ϛ"_NXs@P?26˂\-wٔCk.n4+ #7$筁pd+R$J ϓ$"[pͿq66%OkQ).$o9*RTl#iT#|O"@(kDE@HGs3L"70qScPK{>)`xp!V̴K!Y4x+,BZm^y)}A6?+C\1A9 ]؜o:ϯ6uh@FϔAP4Dy-ʪHOGrW{ł6I ?Ϸ~of*SQ)s \J:e"RJNm0Hd;> ۹ɟ+ AoĨl;߇ᇉhWo4TwHC jB'r_G))򱹥vQP; >݌γ H"AiF~r۠$dDG>.ԭन6?Xr,j&_-nn\^vm>T(vfx~\~+u " L;`dUkmT͒K~oKK%[>U[Tq4x8??6O5/ǓBOt|{!y1z ]?RI_߽.IOb.:6c|Ǔ.z_]dv|_ǨyoA]דO_MH˔yǓDD Osg9$DCxE s^s>xtk{' =B/sn,뢱/D4^??^O"Ixpfz9Vyz ƿ/z^Okl:vg첟d:ENj/DtW{^/DwǓe>$Ӌ%nMoD}>u/[X4\vy\.2ޡOzEX~|slI]dѻ|4J]z])/ы iN9x.q@j*h?* kUN3m%0#&CΚGp0XpfY>Cl[*. mHm|YD,䄧kZl ^`2  nkh^WqڇbĐAJ N 9"fTm}y:| 6[xDXlX @ɲ9P&w1-]ޢih DFqfX_Kt4ߠ3mK\HK6>r G |^yJUO]MĆ ߡBg ξ98Sů': #~N (΀9ϯDϽh 7DZqhJfG[=ḳǴ!R1oEs ^]Cg4\`y0>Nȩj^(K4)?=tёE.=xFy5!0w#Έ.xRR;7P4uP<D"!y5h6xli,6ב̃i&&Yd݁qH-h1Ȁg9J)fFf`:fNA"Yn @}"hʃӦAAu^4mЀQ _[,9}ȍT0J"]>6i\;Fe|mT [3 ׆,g-?# &7b4$AUsC5RSƇ 3XhĂiH][1erlhIl 얥ogVny9l]gݜhnZM %W]ՊVHesq̱`*R.+Ehy((:B3_l~h e͙#¾TR f@zwJҌ_^gѫyIQgm8*2z m M8HCmOnx}kS?h\uD`sD|9{7 gj؝+=s)fv7F:V vЏ2vy'+(7 %kZkm\ ՏnS) )]f,ot~6c< nn wlllVo̦43<+PHj, 9{#ܢMp/xGSQCckqcjcm{ W:f&- IxdkS*~evB}a+$x-LaH7eR3htIYE’eVfs!ƛ7kШtJN!R Rx]>_)Pnsϊ\FQGT;%Z} UL,,I0I&[&PR1sr$K^ǯq>T?%)*9s =Cy"=RZ/ggp2zlߕv4 ܔJ7JG(No;}YSrKT #fS}h>ۃ3yq)]X {hyI %Oh!-gr@ XRCTPⰽTM6GNQH.Xx4}!!TVGQ,tP*"{u_8^IIӾ"fVq[R*ܟ󍆨O@5pnd"0 K8]Z"194ZHRNp<^셦r^Cr q_Cz^OI =iFO!ԍk񓮟?xυ|]HOr"zeH'LBk5B?Mu kkj\^3tTA1?z=IOZ4"R{/y ]̔hLן僦,Mw1aCPFz<)5L LmJi(cy5!ŠkH"S6!ݹrc>G<'{/tMy zpI׋w;Bϟ|<>>oW(\sި+eKtNLO:"\Pȸ`LٳfTIO7*yz.Mt0@>U^Ք"̨JgϷ(yoflfnYV2M0‘o~!_ TޱѨk-UjmԌ7+CQצ_qG;ǡICcҌF,VqԬjk4ͬ j>ԗ_w6 R@Bh<_.65[XLmW_ebo7u9 qTlXh]sQNw%lX^y燅s3 f̯+*1ԶG3)E.bnIE:$TJCggelTf$.cƧ&WưV5ƌy隨ZY4-`?/G)qĘ}a:dЃdL6FI ?7N4SqLflZdrr恰4ք>6&* e,U az>'Bg쳀 Hp3jvoLĕwAWjjNZx͸]N8`<]]g$Q!7@4̱ :u~ }G|Gp0, yA9ҕ$r&.E,h>L|>f4qL,h1a&1':?hRGuaXI^^;T* SIT&CUH|^ 덙6iAA0,v{_w[ݟ4`INj5 Iіr W޳Z54fՒln~I@R'Zn= ;72mn7C*u ^X@ tsA2ቅ)c&;]꩖8/ڙUVO|BABl^Dvl-06=Jmv0V*-/uO5D3o< չX' @ur&a)wo=I?yzOD䒫g2hhh&76;(VtB-fMU&w R;KsH}mMlT7ۿAqq=a&tPzi)2+Y{$Yrs3@"u@6Y+,1Znbr~s?,R $pAH )"kktwMUfd3XBv7_:Ϸ7-kC٬\ʼnxOM~G6yp4(*5%MwQ])L2lÒ[oSbȾu&tRr~+5Tm=/t)?!'!χ:uJ(&"xnV9 An}.K^֌;HLҟ=9 J'H렇 *hMǏ9AP0-R$97; ,Kӵ&׾YY6QKw Rk}|e.;tz-o!|Q (%h92|mƽ$!V߸ruhɔoN E}&u֝jrIe.#D \xXDlg`27žB{+yO1TuI;3"էfmKIWZ}³NyE}^i硵 5sKnlbf~,L)oծ:V8OGս?%??[/ĭ2t=2H3%"@d>K2dDN#3s=CojU\,H:t)HgS[58 kw(Wv=<`w{3ÐwcpsT[q ?dCf`0vE SewE9luG1V҇μ~rf!#f<~Nlz)K[ZgR M{[vI$\qbW‚vZ`P?Hr* Jr[ki5Q2-x#W=oZr CϮ/0< F\N^dv||(G8&i)5dځ*t^F";z#8S5LJ 6Lc/n&ӹuGv2̭n<_" ͊[Cz=51zdxq+'8A\IRKTKzbSi>ܳm'LYN9#Hs&ϥ#[2f$m$8f2<ٺ{2\='>H3mX"άu( 9Y͗ї[ޯZh 鋮RtmQM*Km25oԁ:I {Od1Z3b=Z2Ȕת2!+n;I8J Փ=}{nHʀ>i] ĭ'o {Av3jɧa;מ^ ilX(iB-, q;tb-=dYZ!% >i*_^@IIĘ-Vs9l17a4o| )e~ tݰ$Lgz"QMx״3G֘@TqߊUA}û[Rn+K46UQ;I%Bn1nC"K-,O5}f-X saq#3(t(sxq((#/VAk,O]x N#IogOYi۽t [:acZG 5Tw7"G=㑻z]y+Dkm#$Bu}U=rbZ/L".i> l@1DIDAT“J[35TEg'D% 6NG.W&2՜߰mq38P,~_Pu%&n_w+hJ4kV_t'Ȏʰ-&a*7tjW=36o8V"0Ziŧ?ՀKqqcipXr(ӲOO<Ɏ2{ߒ?aĶޡ/ \+8 j̹84 v9*3w#pGT#m }xtZbFC"8xd}>Iקpσͫ5 <yxOtU*2qureī 04' ':N<̋M}|b0sG?$CԦ>HPi-fjW:#\WJ^`rjdxju&CɴPXxEQ 8rW53ٲe>ug$1^CG)5kDqAgy+E7>m.޴n!?m6+S\1SUOpa@V^IzIv,ްL~^&-|(-am\-Sm;МwSø p]?jIT@]u2Ot^1i(dg2EWfܳlR-/j%卬z}NtX + #1OQn͟c%ld??mCXe<. .45ݐ@3 $dzV /rBH4-)9("r 'c0Ew0q@ZAW cj0{ܔ hCQ1y}z,.5Oc̱ADґdWDIf -*¼Ѥݫ&ZWM^'~稾WEfSq'EA:Z \ĸ0Ȍ+Z!ϤwQaTb2xx#1iW'!ؒ^-70aZY΍Ґe0t3GᛓL/ɒrV2 U$hZL[b)E !HDv+ +d4lO\NaƒnjMo@њ$}Km: A@A>NM>K9Me l,*8׾%_WErD~e.M&hIVwVRyY=WH`qdpe(.ir0~j"b޷"+I4 v J)dč?"US؂/*/84>2A4G[D_csPȍ:K,'`̼ OLsKte 4Ё;ϑO' Oxվ8)} @x _6/|z/|Di듟ϡԔ=Gn zG?P,͆|*ϑM,y{Aӫpr$[6K ԂS4* K% "Upro72 "F$M|ZLAӞeGyao/e|2b%)II݃7 0=YxpӂPsa '=# w̃_[vY%f jK~ ǦuOfgJՅU Q`4mLZT% Ha%"i&y1AX&1Hl-_C]H'ԧ|f6ԝi DYh֙^jWO=M*UAI`ZI:T{72A$,맕>WM0Ohi`|n+sUŒ]A,.dmT^W07,+*Ʉun>φقʝȂ.%q]Pj:Rܼ9879\rZC҅9LwcQ7)Ftc #Y(xM} T7 &`O˜$⺘vn7 RQ"3O<'bQx& )WrKꜚ`^ձp)Ê$XD#gI|zq 9ΜkjqND!yHTJ䀹$K F7! #R&orqUI.!0_ S6NX0v}*iEEI|}=v=YRugegHˣưy]#LtUA"յ涘*(Q&{IurwEjY􅤺4^(&)'t_뷿_Mqx |'/H`D :={ڜ{\ypi%|ҿ{W'08 xi|]1~G |=ѫc,'w3s ;Ȓ?_;^_#x`6+ј;+͕lcL:Euoᡖw>a69Ρ8ΎW׳swHzq:mVS;O 2%:b&CO'ϡ-'T_Hϧ~hgU }QW[cݶ<S;D݈h͘ߔ.w JTjr11Mư"uɭʀ~uAH /d-ۀLj)>%.[Sj ڜ_fD\xgM9BF`&wBNX]xR7TE}Na-n 4CqN߁?s|v_pg 6_hЈ4c[6 7Դks͈ʼCVEe'yTԹg^VKVu8Yu1aJ2>F UX-Ai},msR=>j1 oD{ri/J&O.yF1^}|L{kuT`BrqF) %OiHeh-uEnDNps GU#S.|$ߦ(ضjC.=]jV׶\[M^]CBMˇ3pnJMe I5ĐRIGy-NqȜ-'u7a~Zu]hgoi]L=,1xqMDgޑMԚ5u3a (r5ptB5h3iARoU("xzWsМ+\Mje4ب,ؤ ~%".Yp{*D'ԡ꽨)«7v Ihe/ >ZJ\f<ܕw]]ѬL md?cW;CjMG[i#9'I-basIXpI$uN_ qp-7> lu*)Ʈ9XhZQ%66d;g:^R5eƦ DN&wb4q؏Rҍ"+?3`϶H\\=+IxHD7d8:MFAufjL8iٮ0ڠ}Zig$$ i&bDӕb!f5_\~ f`tS*-A?*' ?=;ftYaZ.)Vc ܐ >!_oDiw=< <]-SN}K6S8)j\:xӛ!]%Km]O(d]b'DN%3W"lD/9-*DiaUC^1h.}?]韼u~StKBz?ǕZS0iiBIAI/(-]?IӜQh7dx+ڦ8v-m,΢W|ZhE…z3L$*,~~PvK⨗LMTX:AS.*>1t ER3qctGH$e jHIC?\󚉊IISE)*b=`)é3MDSgqBX.x PyboExVڰBYޞeT*+w YmeLzC\u<]tfɔ(fg8p`yn5!ߐkMx;bfԅRSBD|Х.ؗ<>sl*qAQyRK>HgSg⚴ht5{=. JȫڠuqVH5 HeGi<W(ͲܔK4DDR,D]:8O%4 _4*CyR_v4BR"n"jiCꐱ r*:Wޜ.1R̀>Z٢ahcd~"KҫH| Q=dc>9b1p`p؏uc3ϫ.3c Ӎ+ԷOmjeV T {3gCV0fஜ #include #include "game.h" class GameMimeData : public QMimeData { Q_OBJECT public: int m_index; }; class DbMimeData : public QMimeData { Q_OBJECT public: QString m_path; }; #endif // GAMEMIMEDATA_H chessx-1.0.0/src/database/output.cpp000644 001750 001750 00000075274 12223260306 020223 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2006-2007 Marius Roets * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include #include #include "board.h" #include "boardview.h" #include "output.h" #include "settings.h" QMap Output::m_outputMap; Output::Output(OutputType output, const QString& pathToTemplateFile) { m_outputType = output; switch(m_outputType) { case Html: m_options.createDefaultOptions(""); break; case Pgn: m_options.createDefaultOptions(""); break; case Latex: m_options.createDefaultOptions(""); break; case NotationWidget: m_options.createDefaultOptions("GameText"); break; default: Q_ASSERT(false); } setTemplateFile(pathToTemplateFile); initialize(); } void Output::initialize() { if(m_outputType == Pgn) { m_newlineChar = "\n"; } else if(m_outputType == Html) { m_newlineChar = "
\n"; } else if(m_outputType == Latex) { m_newlineChar = "\n"; } else if(m_outputType == NotationWidget) { m_newlineChar = "
\n"; } readTemplateFile(m_templateFilename); } void Output::readTemplateFile(const QString& path) { QFile file(path); QStringList optionDefFields; enum ReadingStatus {NONE, ReadingOptionDefs, ReadingOptions, ReadingOutputHeader, ReadingOutputFooter, ReadingMarkupTags}; ReadingStatus status = NONE; m_header = ""; m_footer = ""; if(file.open(QIODevice::ReadOnly)) { QTextStream stream(&file); QString line; int i = 0; while(!stream.atEnd()) { line = stream.readLine(); // line of text excluding '\n' i++; if((line.indexOf(QRegExp("^\\s*$")) != -1) || (line.indexOf(QRegExp("^\\s*#")) != -1)) { // Skip blank lines and comments (#) continue; } if(line == "[OPTIONSDEFINITIONS]") { status = ReadingOptionDefs; continue; } else if(line == "[OPTIONS]") { status = ReadingOptions; continue; } else if(line == "[OUTPUTHEADER]") { status = ReadingOutputHeader; continue; } else if(line == "[OUTPUTFOOTER]") { status = ReadingOutputFooter; continue; } else if(line == "[MARKUPTAGS]") { status = ReadingMarkupTags; continue; } // Hack to replace \\n with newline but leavin tags like \\newenvironment intact line.replace("\\\\n", "\\\\^"); line.replace("\\n", "\n"); line.replace("\\\\^", "\\n"); switch(status) { case ReadingOptionDefs: optionDefFields = line.split(","); if(!m_options.createOption(optionDefFields[0], optionDefFields[1], optionDefFields[2], optionDefFields[3], optionDefFields[4])) { qWarning("Could not create option. Ignoring line %d in file %s :\n%s", i, path.toLatin1().constData(), line.toLatin1().constData()); } break; case ReadingOptions: if(!m_options.setOption(line)) { qWarning("Invalid option or value in file %s line %d. Ignoring : %s", path.toLatin1().constData(), i, line.toLatin1().constData()); } break; case ReadingOutputHeader: m_header += line; break; case ReadingOutputFooter: m_footer += line; break; case ReadingMarkupTags: { QString name = line.mid(0, line.indexOf('=')); QStringList tags = (line.mid(line.indexOf('=') + 1)).split(','); if(name == "MarkupHeaderBlock") { setMarkupTag(MarkupHeaderBlock, tags[0], tags[1]); } else if(name == "MarkupNotationBlock") { setMarkupTag(MarkupNotationBlock, tags[0], tags[1]); } else if(name == "MarkupResult") { setMarkupTag(MarkupResult, tags[0], tags[1]); } else if(name == "MarkupDiagram") { setMarkupTag(MarkupDiagram, tags[0], tags[1]); } else if(name == "MarkupMainLineMove") { setMarkupTag(MarkupMainLineMove, tags[0], tags[1]); } else if(name == "MarkupVariationMove") { setMarkupTag(MarkupVariationMove, tags[0], tags[1]); } else if(name == "MarkupMainLine") { setMarkupTag(MarkupMainLine, tags[0], tags[1]); } else if(name == "MarkupVariationInline") { setMarkupTag(MarkupVariationInline, tags[0], tags[1]); } else if(name == "MarkupVariationIndent") { setMarkupTag(MarkupVariationIndent, tags[0], tags[1]); } else if(name == "MarkupNag") { setMarkupTag(MarkupNag, tags[0], tags[1]); } else if(name == "MarkupAnnotationInline") { setMarkupTag(MarkupAnnotationInline, tags[0], tags[1]); } else if(name == "MarkupAnnotationIndent") { setMarkupTag(MarkupAnnotationIndent, tags[0], tags[1]); } else if(name == "MarkupPreAnnotationInline") { setMarkupTag(MarkupPreAnnotationInline, tags[0], tags[1]); } else if(name == "MarkupPreAnnotationIndent") { setMarkupTag(MarkupPreAnnotationIndent, tags[0], tags[1]); } else if(name == "MarkupHeaderLine") { setMarkupTag(MarkupHeaderLine, tags[0], tags[1]); } else if(name == "MarkupHeaderTagName") { setMarkupTag(MarkupHeaderTagName, tags[0], tags[1]); } else if(name == "MarkupHeaderTagValue") { setMarkupTag(MarkupHeaderTagValue, tags[0], tags[1]); } else if(name == "MarkupWhiteTag") { setMarkupTag(MarkupWhiteTag, tags[0], tags[1]); } else if(name == "MarkupBlackTag") { setMarkupTag(MarkupBlackTag, tags[0], tags[1]); } else if(name == "MarkupEventTag") { setMarkupTag(MarkupEventTag, tags[0], tags[1]); } else if(name == "MarkupDateTag") { setMarkupTag(MarkupDateTag, tags[0], tags[1]); } else if(name == "MarkupSiteTag") { setMarkupTag(MarkupSiteTag, tags[0], tags[1]); } else if(name == "MarkupResultTag") { setMarkupTag(MarkupResultTag, tags[0], tags[1]); } else if(name == "MarkupRoundTag") { setMarkupTag(MarkupRoundTag, tags[0], tags[1]); } else if(name == "MarkupColumnStyleMove") { setMarkupTag(MarkupColumnStyleMove, tags[0], tags[1]); } else if(name == "MarkupColumnStyleRow") { setMarkupTag(MarkupColumnStyleRow, tags[0], tags[1]); } else if(name == "MarkupColumnStyleMainline") { setMarkupTag(MarkupColumnStyleMainline, tags[0], tags[1]); } else if(name == "MarkupMate") { setMarkupTag(MarkupMate, tags[0], tags[1]); } else { qWarning("Unkown Markup Tag found in file %s line %d. Ignoring : %s", path.toLatin1().constData(), i, line.toLatin1().constData()); } } break; default : qWarning("Unknown Section in Template File %s line %d : %s", path.toLatin1().constData(), i, line.toLatin1().constData()); } } file.close(); } } QMap& Output::getFormats() { m_outputMap.clear(); m_outputMap[Html] = "Html Output"; m_outputMap[Pgn] = "Pgn Output"; m_outputMap[Latex] = "Latex Output"; m_outputMap[NotationWidget] = "Notation Widget Output"; return m_outputMap; } QString Output::writeDiagram(int n) { QString imageString; if((m_outputType == NotationWidget) && (AppSettings->getValue("/GameText/ShowDiagrams").toBool())) { BoardView boardView(0, BoardView::IgnoreSideToMove | BoardView::SuppressGuessMove); boardView.setMinimumSize(n, n); boardView.setEnabled(false); boardView.configure(); Game g = *m_game; g.forward(1); boardView.setBoard(g.board()); boardView.resize(n, n); QPalette Pal(boardView.palette()); // set black background Pal.setColor(QPalette::Background, Qt::transparent); boardView.setAutoFillBackground(true); boardView.setPalette(Pal); QPixmap pixmap(n, n); pixmap.fill(); boardView.render(&pixmap); QImage image = pixmap.toImage(); QByteArray byteArray; QBuffer buffer(&byteArray); image.save(&buffer, "PNG"); // writes the image in PNG format inside the buffer QString iconBase64 = QString::fromLatin1(byteArray.toBase64().data()); imageString = QString("\n") + m_startTagMap[MarkupDiagram] + "Diagram\n" + m_endTagMap[MarkupDiagram]; } return imageString; } QString Output::writeMove(MoveToWrite moveToWrite) { QString text; QString mvno; QString nagString; QString imageString; QString precommentString; MoveId moveId; if(moveToWrite == NextMove) { moveId = m_game->nextMove(); } else { moveId = m_game->currentMove(); } mvno = QString::number(moveId); if(m_game->nags(moveId).count() > 0) { if(m_options.getOptionAsBool("SymbolicNag")) { nagString += m_game->nags(moveId).toString(m_outputType == Html ? NagSet::HTML : NagSet::Simple); if((m_outputType == Html || m_outputType == NotationWidget) && (m_game->nags(moveId).contains(NagDiagram))) { int n = m_options.getOptionAsInt("DiagramSize"); if(n) { imageString = writeDiagram(n); } } } else { nagString += m_game->nags(moveId).toString(NagSet::PGN); } } // Read comments if(m_game->canHaveStartAnnotation(moveId)) precommentString = (m_outputType == Pgn) ? m_game->annotation(moveId, Game::BeforeMove) : m_game->textAnnotation(moveId, Game::BeforeMove); QString commentString = (m_outputType == Pgn) ? m_game->annotation(moveId) : m_game->textAnnotation(moveId); // Write precomment if any text += writeComment(precommentString, mvno, Precomment); Color c = m_game->board().toMove(); if((m_options.getOptionAsBool("ColumnStyle")) && (m_currentVariationLevel == 0) && ((c == White) || m_dirtyBlack)) { text += m_startTagMap[MarkupColumnStyleRow] + m_startTagMap[MarkupColumnStyleMove]; } else if((m_options.getOptionAsBool("ColumnStyle")) && (m_currentVariationLevel == 0) && (c == Black)) { text += m_startTagMap[MarkupColumnStyleMove]; } // *** Write the move number if(moveToWrite == PreviousMove) { c = oppositeColor(c); } if(c == White) { text += QString::number(m_game->moveNumber(moveId)) + ". "; } else if(m_dirtyBlack) { text += QString::number(m_game->moveNumber(moveId)) + "... "; if((m_options.getOptionAsBool("ColumnStyle")) && (m_currentVariationLevel == 0)) { text += m_endTagMap[MarkupColumnStyleMove] + m_startTagMap[MarkupColumnStyleMove]; } } m_dirtyBlack = false; // *** Markup for the move if(m_currentVariationLevel > 0) { if(m_expandable[MarkupVariationMove]) { text += m_startTagMap[MarkupVariationMove].arg(mvno); } else { text += m_startTagMap[MarkupVariationMove]; } } else { if(m_expandable[MarkupMainLineMove]) { text += m_startTagMap[MarkupMainLineMove].arg(mvno); } else { text += m_startTagMap[MarkupMainLineMove]; } } // *** Write the actual move QString san; Game::MoveStringFlags flags = (m_outputType == NotationWidget) ? Game::TranslatePiece : Game::MoveOnly; if(moveToWrite == NextMove) { san = m_game->moveToSan(flags); } else { san = m_game->moveToSan((Game::MoveStringFlags)(flags | Game::MoveOnly), Game::PreviousMove); } QString mate = m_startTagMap[MarkupMate] + "#" + m_endTagMap[MarkupMate]; san.replace("#", mate); text += san; // *** End the markup for the move if(m_currentVariationLevel > 0) { text += m_endTagMap[MarkupVariationMove]; } else { text += m_endTagMap[MarkupMainLineMove]; } // *** Write the nags if there are any if(!nagString.isEmpty()) { text += m_startTagMap[MarkupNag] + nagString + m_endTagMap[MarkupNag]; } if((m_options.getOptionAsBool("ColumnStyle")) && (m_currentVariationLevel == 0) && (c == White)) { text += m_endTagMap[MarkupColumnStyleMove]; m_game->forward(); if(m_game->atGameEnd()) { text += m_endTagMap[MarkupColumnStyleRow]; } m_game->backward(); } if((m_options.getOptionAsBool("ColumnStyle")) && (m_currentVariationLevel == 0) && (c == Black)) { text += m_endTagMap[MarkupColumnStyleMove] + m_endTagMap[MarkupColumnStyleRow]; } text += imageString; if(!imageString.isEmpty()) { m_dirtyBlack = true; } text += writeComment(commentString, mvno, Comment); text += " "; return text; } QString Output::writeVariation(MoveId upToNode) { QString text; while(!m_game->atLineEnd()) { if(m_game->currentMove() == upToNode) { text += "*** "; break; } // *** Writes move in the current variation text += writeMove(); if(m_game->variationCount()) { QList variations = m_game->variations(); if(variations.size()) { bool inMainline = m_game->isMainline(); if(m_options.getOptionAsBool("ColumnStyle") && inMainline) { text += m_endTagMap[MarkupColumnStyleMainline]; } for(int i = 0; i < variations.size(); ++i) { m_currentVariationLevel++; if(m_currentVariationLevel <= m_options.getOptionAsInt("VariationIndentLevel")) { text += m_startTagMap[MarkupVariationIndent]; } else { text += m_startTagMap[MarkupVariationInline]; } m_dirtyBlack = true; // *** Enter variation i, and write the rest of the moves m_game->moveToId(variations[i]); text += writeMove(PreviousMove); text += writeVariation(upToNode); // *** End the variation // m_output.replace ( QRegExp ("\\s+$"), "" ); // We don't want any spaces before the ) if(m_currentVariationLevel <= m_options.getOptionAsInt("VariationIndentLevel")) { text += m_endTagMap[MarkupVariationIndent]; } else { text += m_endTagMap[MarkupVariationInline]; } m_currentVariationLevel--; } if(m_options.getOptionAsBool("ColumnStyle") && inMainline) { text += m_startTagMap[MarkupColumnStyleMainline]; } } m_dirtyBlack = true; m_game->moveToId(m_game->parentMove()); } m_game->forward(); } return text; } QString Output::writeTag(const QString& tagName, const QString& tagValue) { QString text = m_startTagMap[MarkupHeaderLine] + m_startTagMap[MarkupHeaderTagName] + tagName + m_endTagMap[MarkupHeaderTagName] + " " + m_startTagMap[MarkupHeaderTagValue] + tagValue + m_endTagMap[MarkupHeaderTagValue] + m_endTagMap[MarkupHeaderLine]; return text; } QString Output::writeComment(const QString& comment, const QString& mvno, CommentType type) { QString text; if(comment.isEmpty()) { return text; } MarkupType markupIndent = type == Comment ? MarkupAnnotationIndent : MarkupPreAnnotationIndent; MarkupType markupInline = type == Comment ? MarkupAnnotationInline : MarkupPreAnnotationInline; if(type == Comment) { text += " "; } if(m_options.getOptionAsBool("ColumnStyle") && (m_currentVariationLevel == 0)) { text += m_endTagMap[MarkupColumnStyleMainline]; } if((m_options.getOptionAsString("CommentIndent") == "Always") || ((m_options.getOptionAsString("CommentIndent") == "OnlyMainline") && (m_currentVariationLevel == 0))) { if(m_expandable[markupIndent]) { text += m_startTagMap[markupIndent].arg(mvno) + comment + m_endTagMap[markupIndent]; } else { text += m_startTagMap[markupIndent] + comment + m_endTagMap[markupIndent]; } } else { if(m_expandable[markupInline]) { text += m_startTagMap[markupInline].arg(mvno) + comment + m_endTagMap[markupInline]; } else { text += m_startTagMap[markupInline] + comment + m_endTagMap[markupInline]; } } if(m_options.getOptionAsBool("ColumnStyle") && (m_currentVariationLevel == 0)) { text += m_startTagMap[MarkupColumnStyleMainline]; } m_dirtyBlack = true; return text; } QString Output::writeGameComment(QString comment) { QString text; comment = comment.trimmed(); if(comment.isEmpty()) { return text; } MarkupType markupIndent = MarkupPreAnnotationIndent; MarkupType markupInline = MarkupPreAnnotationInline; if(m_options.getOptionAsBool("ColumnStyle")) { text += m_endTagMap[MarkupColumnStyleMainline]; } if((m_options.getOptionAsString("CommentIndent") == "Always") || ((m_options.getOptionAsString("CommentIndent") == "OnlyMainline"))) { text += m_startTagMap[markupIndent] + comment + m_endTagMap[markupIndent]; } else { text += m_startTagMap[markupInline] + comment + m_endTagMap[markupInline]; } if(m_options.getOptionAsBool("ColumnStyle")) { text += m_startTagMap[MarkupColumnStyleMainline]; } return text; } QString Output::writeAllTags() { QString text; QMap tags = m_game->tags(); // write standard tags for(int i = 0; i < 7; ++i) { text += writeTag(StandardTags[i], tags[StandardTags[i]]); tags.remove(StandardTags[i]); } // write other tags written in ascii order, as suggested by standard QMapIterator it(tags); while(it.hasNext()) { it.next(); // workaround for problems with IndexItem implementation if(!it.value().isEmpty() && it.value() != "?" && it.value() != PDInvalidDate.asString() && it.key() != "Length") { text += writeTag(it.key(), it.value()); } } return text; } QString Output::writeBasicTagsHTML() { QString text; QMap tags = m_game->tags(); QString eco = tags[TagNameECO].left(3); if(eco == "?") { eco.clear(); } else { eco = QString(" ") + eco; } QString whiteElo = tags[TagNameWhiteElo].length() > 1 ? QString(" (%1)").arg(tags[TagNameWhiteElo]) : QString(); QString blackElo = tags[TagNameBlackElo].length() > 1 ? QString(" (%1)").arg(tags[TagNameBlackElo]) : QString(); text += m_startTagMap[MarkupHeaderLine] + tags[TagNameWhite] + whiteElo + " - " + tags[TagNameBlack] + blackElo + eco + m_endTagMap[MarkupHeaderLine] + "\n"; QString event = tags[TagNameEvent] != "?" ? QString("%1").arg(tags[TagNameEvent]) : QString(); QString place = tags[TagNameSite] != "?" ? QString("%1").arg(tags[TagNameSite]) : QString(); QString round = tags[TagNameRound] != "?" ? QString(" (%1)").arg(tags[TagNameRound]) : QString(); if(!(QString(event + place + round)).isEmpty()) text += m_startTagMap[MarkupHeaderLine] + event + ((!event.isEmpty() && !place.isEmpty()) ? ", " : "") + place + round + m_endTagMap[MarkupHeaderLine] + "\n"; return text; } QString Output::output(Game* game, bool upToCurrentMove) { QString text = m_header; text += outputGame(game, upToCurrentMove); text += m_footer; postProcessOutput(text); return text; } QString Output::outputGame(Game* game, bool upToCurrentMove) { QString text; m_game = game; int id = m_game->currentMove(); int mainId = upToCurrentMove ? m_game->mainLineMove() : NO_MOVE; m_currentVariationLevel = 0; if(m_options.getOptionAsBool("ShowHeader")) { text += m_startTagMap[MarkupHeaderBlock]; if(m_outputType == Html) { text += writeBasicTagsHTML(); } else { text += writeAllTags(); } text += m_endTagMap[MarkupHeaderBlock]; } m_game->moveToStart(); m_dirtyBlack = m_game->board().toMove() == Black; text += m_startTagMap[MarkupNotationBlock]; text += m_startTagMap[MarkupMainLine]; if(m_options.getOptionAsBool("ColumnStyle")) { text += m_startTagMap[MarkupColumnStyleMainline]; } text += writeGameComment(game->gameComment()); text += writeVariation(mainId); if(m_options.getOptionAsBool("ColumnStyle")) { text += m_endTagMap[MarkupColumnStyleMainline]; } text += m_endTagMap[MarkupMainLine]; text += m_endTagMap[MarkupNotationBlock]; text += m_startTagMap[MarkupResult] + game->tag("Result") + m_endTagMap[MarkupResult]; m_game->moveToId(id); return text; } void Output::postProcessOutput(QString& text) const { QRegExp var("@(\\w+)@"); while(var.indexIn(text) != -1) { QStringList cap = var.capturedTexts(); text.replace("@" + cap[1] + "@", m_options.getOptionAsString(cap[1])); } // Chop it up, if TextWidth option is not equal to 0 int start = text.length(); int textWidth = m_options.getOptionAsInt("TextWidth"); if(textWidth) { int length = text.length() - start; while(length > textWidth) { start = text.lastIndexOf(" ", start + textWidth); if(start == -1) { break; } text.replace(start, 1, '\n'); length = text.length() - start; } } } void Output::output(QTextStream& out, Filter& filter) { int percentDone = 0; Game game; QString header = m_header; postProcessOutput(header); out << header; for(int i = 0; i < filter.count(); ++i) { if(filter.database()->loadGame(filter.indexToGame(i), game)) { QString outText = outputGame(&game, false); postProcessOutput(outText); out << outText; out << "\n\n"; } int percentDone2 = (i + 1) * 100 / filter.count(); if(percentDone2 > percentDone) { emit progress((percentDone = percentDone2)); } } QString footer = m_footer; postProcessOutput(footer); out << footer; } void Output::output(QTextStream& out, Database& database) { if(!database.isUtf8() && (m_outputType == Pgn)) { QTextCodec* textCodec = QTextCodec::codecForName("ISO 8859-1"); if(textCodec) { out.setCodec(textCodec); } } QString header = m_header; postProcessOutput(header); out << header; int percentDone = 0; Game game; for(int i = 0; i < database.count(); ++i) { if(database.loadGame(i, game)) { QString outText = outputGame(&game, false); postProcessOutput(outText); out << outText; out << "\n\n"; } int percentDone2 = (i + 1) * 100 / database.count(); if(percentDone2 > percentDone) { emit progress((percentDone = percentDone2)); } } QString footer = m_footer; postProcessOutput(footer); out << footer; database.setModified(false); } void Output::output(const QString& filename, Game& game) { QFile f(filename); if(!f.open(QIODevice::WriteOnly | QIODevice::Text)) { return; } QTextStream out(&f); if((m_outputType == Html) || (m_outputType == NotationWidget)) { out.setCodec(QTextCodec::codecForName("utf8")); } out << output(&game); f.close(); } void Output::output(const QString& filename, Filter& filter) { QFile f(filename); if(!f.open(QIODevice::WriteOnly | QIODevice::Text)) { return; } QTextStream out(&f); if((m_outputType == Html) || (m_outputType == NotationWidget)) { out.setCodec(QTextCodec::codecForName("utf8")); } output(out, filter); f.close(); } void Output::output(const QString& filename, Database& database) { QFile f(filename); if(!f.open(QIODevice::WriteOnly | QIODevice::Text)) { return; } QTextStream out(&f); if((m_outputType == Html) || (m_outputType == NotationWidget)) { out.setCodec(QTextCodec::codecForName("utf8")); } output(out, database); f.close(); } void Output::append(const QString& filename, Game& game) { QFile f(filename); if(!f.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) { return; } QTextStream out(&f); if((m_outputType == Html) || (m_outputType == NotationWidget)) { out.setCodec(QTextCodec::codecForName("utf8")); } else { QTextCodec* textCodec = QTextCodec::codecForName("ISO 8859-1"); if(textCodec) { out.setCodec(textCodec); } } out << output(&game); f.close(); } void Output::setTemplateFile(QString filename) { if(filename.isEmpty()) { switch(m_outputType) { case Html: filename = DEFAULT_HTML_TEMPLATE; break; case Latex: filename = DEFAULT_LATEX_TEMPLATE; break; case NotationWidget: filename = DEFAULT_NOTATION_TEMPLATE; break; case Pgn: filename = DEFAULT_PGN_TEMPLATE; break; default : qWarning("Could not decide which template file to use. Maybe strange OutputType"); } } if(!QFile::exists(filename)) { QString dataPath = AppSettings->dataPath(); m_templateFilename = dataPath + "/" + TEMPLATE_DIR + "/" + filename; if(!QFile::exists(m_templateFilename)) { m_templateFilename = ":/" + TEMPLATE_DIR + "/" + filename; } } else { m_templateFilename = filename; } } void Output::setMarkupTag(MarkupType type, const QString& startTag, const QString& endTag) { m_startTagMap[type] = startTag; m_endTagMap[type] = endTag; if(startTag.contains("%1")) { m_expandable[type] = true; } else { m_expandable[type] = false; } } void Output::markupTag(MarkupType type , QString& startTag, QString& endTag) { startTag = m_startTagMap[type]; endTag = m_endTagMap[type]; } bool Output::setOption(const QString& optionName, bool optionValue) { return m_options.setOption(optionName, optionValue); } bool Output::setOption(const QString& optionName, int optionValue) { return m_options.setOption(optionName, optionValue); } bool Output::setOption(const QString& optionName, const QString& optionValue) { return m_options.setOption(optionName, optionValue); } /* Retrieving values */ int Output::getOptionAsInt(const QString& optionName) { return m_options.getOptionAsInt(optionName); } QString Output::getOptionAsString(const QString& optionName) { return m_options.getOptionAsString(optionName); } bool Output::getOptionAsBool(const QString& optionName) { return m_options.getOptionAsBool(optionName); } QString Output::getOptionDescription(const QString& optionName) { return m_options.getOptionDescription(optionName); } QStringList Output::getOptionList() { return m_options.getOptionList(); } chessx-1.0.0/src/database/engine.h000644 001750 001750 00000010465 12223260306 017564 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 William Hoggarth * * (C) 2008-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __ENGINE_H__ #define __ENGINE_H__ #include #include #include #include #include "analysis.h" #include "board.h" #include "move.h" #include "enginelist.h" #include "engineoptiondata.h" /** * @defgroup Feature Feature - assorted feature classes of ChessX **/ /** * @ingroup Feature * * Provides a simple interface to a chess engine. **/ class Engine : public QObject { Q_OBJECT public: /** Constructs an engine with a given path/command, and log stream */ Engine(const QString& name, const QString& command, bool bTestMode, const QString& directory = QString(), QTextStream* logStream = NULL); /** Virtual destructor */ virtual ~Engine(); /** Set the stream that the debug output goes to */ void setLogStream(QTextStream* logStream = NULL); /** Launch and initialize engine, fire activated() signal when done*/ void activate(); /** Destroy engine process */ void deactivate(); /** Returns whether the engine is active or not */ bool isActive(); /** Analyzes the given position */ virtual bool startAnalysis(const Board& board, int nv = 1) = 0; /** Stops any analysis */ virtual void stopAnalysis() = 0; /** Returns whether the engine is analyzing or not */ bool isAnalyzing(); /** Create a new engine, pass index into engine settings list */ static Engine* newEngine(int index); static Engine* newEngine(int index, bool bTestMode); static Engine* newEngine(EngineList& engineList, int index, bool bTestMode); /** Set number of lines. */ virtual void setMpv(int mpv); virtual bool providesMvp() { return false; } signals: /** Fired when the engine is activated */ void activated(); /** Fired when the engine is deactivated */ void deactivated(); /** Fired when the engine is deactivated */ void error(QProcess::ProcessError); /** Fired when analysis starts */ void analysisStarted(); /** Fired when analysis stops */ void analysisStopped(); /** Fired when the engine has produced some analysis */ void analysisUpdated(const Analysis& analysis); /** Fired when a log item has been written to the log */ void logUpdated(); protected: /** Performs any shutdown procedure required by the engine protocol */ virtual void protocolEnd() = 0; /** Processes messages from the chess engine */ virtual void processMessage(const QString& message) = 0; /** Sends a message to the chess engine */ void send(const QString& message); /** Sets whether the engine is active or not */ void setActive(bool active); /** Sets whether the engine is analysing or not */ void setAnalyzing(bool analyzing); /** Sends an analysis signal */ void sendAnalysis(const Analysis& analysis); bool m_invertBlack; int m_mpv; bool m_bTestMode; private slots: /** Receives notification that there is process output to read */ void pollProcess(); /** Receives notification that the process has terminated */ void processExited(); /** Performs any initialisation required by the engine protocol */ virtual void protocolStart() = 0; /** Processes messages from the chess engine */ void processError(QProcess::ProcessError); public: QList m_options; OptionValueList m_mapOptionValues; private: QString m_name; QString m_command; QString m_directory; QTextStream* m_logStream; QProcess* m_process; QTextStream* m_processStream; bool m_active; bool m_analyzing; }; #endif // __ENGINE_H__ chessx-1.0.0/src/database/pgndatabase.h000644 001750 001750 00000013045 12223260306 020565 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005-2006 William Hoggarth * * (C) 2006 Ejner Borgbjerg * * (C) 2007 Marius Roets * * (C) 2006-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __PGNDATABASE_H__ #define __PGNDATABASE_H__ #include #include #include "database.h" /** @ingroup Database The PgnDatabase class provides database access to PGN files. The class is derived from the Database class, providing methods for the loading and saving of games, and for performing searches and queries. */ typedef qint64 IndexBaseType; class PgnDatabase : public Database { Q_OBJECT public: /** Default constructor */ PgnDatabase(bool b64Bit); /** Destructor */ ~PgnDatabase(); //database operations /** Opens the given database */ virtual bool open(const QString& filename, bool utf8); /** File-based database name */ virtual QString filename() const; /** Closes the database */ virtual void close(); //game retrieval & storage /** Loads a game from the given position, returns true if successful */ bool loadGame(int index, Game& game); /** Loads only moves into a game from the given position */ void loadGameMoves(int index, Game& game); // Open a PGN Data File from a string bool openString(const QString& content); virtual int count() { return m_count; } protected: //parsing methods /** Reads moves from the file and adds them to the game. Performs position searches if any are active */ bool parseMoves(Game* game); /** Parses a line from the file */ void parseLine(Game* game); /** Parses a move token from the file */ void parseDefaultToken(Game* game, QString token); /** Parses a token from the file */ void parseToken(Game* game, const QString& token); /** Parses a comment from the file */ void parseComment(Game* game); /** Skips past any data which is not valid tag or move data */ IndexBaseType skipJunk(); /** Skips past any tag data */ void skipTags(); /** Skips past any move data */ void skipMoves(); /** Parses the tags, and adds the supported types to the index 'm_index' */ void parseTagsIntoIndex(); virtual bool parseFile(); bool parseFileIntern(); virtual void parseGame(); bool readIndexFile(QDataStream& in, volatile bool *breakFlag); bool writeIndexFile(QDataStream& out) const; QString offsetFilename(const QString& filename) const; bool readOffsetFile(const QString&, volatile bool *breakFlag); bool writeOffsetFile(const QString&) const; // Open a PGN data File bool openFile(const QString& filename); /** Adds the current file position as a new offset */ IndexBaseType m_count; void addOffset(); QIODevice* m_file; bool m_isOpen; QString m_currentLine; private: /** Resets/initialises important member variables. Called by constructor and close methods */ void initialise(); //file methods /** Reads the next line of text from the PGN file */ void readLine(); /** Skips the next line of text from the PGN file */ void skipLine(); /** Moves the file position to the start of the given game */ void seekGame(int index); //file variables QString m_filename; QString m_gameText; //parsing variables int m_pos; bool m_gameOver; bool m_inComment; QString m_comment; QString m_precomment; bool m_newVariation; int m_variation; //game index static const int AllocationSize = 16384; IndexBaseType m_allocated; qint32* m_gameOffsets32; qint64* m_gameOffsets64; QByteArray m_lineBuffer; bool bUse64bit; //offset methods /** Returns the file offset for the given game */ inline IndexBaseType offset(int index) { if(bUse64bit) { return m_gameOffsets64[index]; } else { return m_gameOffsets32[index]; } } /** Adds a new file offset */ inline void addOffset(IndexBaseType offset) { if(m_count == m_allocated) { //out of space reallocate memory if(bUse64bit) { qint64* newAllocation = new qint64[m_allocated += AllocationSize]; memcpy(newAllocation, m_gameOffsets64, m_count * sizeof(qint64)); delete[] m_gameOffsets64; m_gameOffsets64 = newAllocation; } else { qint32* newAllocation = new qint32[m_allocated += AllocationSize]; memcpy(newAllocation, m_gameOffsets32, m_count * sizeof(qint32)); delete[] m_gameOffsets32; m_gameOffsets32 = newAllocation; } } if(bUse64bit) { m_gameOffsets64[m_count++] = offset; } else { m_gameOffsets32[m_count++] = offset; } } }; #endif chessx-1.0.0/src/000755 001750 001750 00000000000 12234477214 014406 5ustar00niklasniklas000000 000000 chessx-1.0.0/src/database/common.cpp000644 001750 001750 00000002253 12223260306 020136 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2005 William Hoggarth * * (C) 2006-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "common.h" Piece& operator++(Piece& w) { if(w < BlackPawn) { return w = Piece(w + 1); } else { return w = Empty; } } Piece operator++(Piece& w, int) { Piece alt = w; ++w; return alt; } QString resultString(Result result) { switch(result) { case WhiteWin: return "1-0"; case Draw: return "1/2-1/2"; case BlackWin: return "0-1"; case ResultUnknown: default: return "*"; } } chessx-1.0.0/src/database/downloadmanager.h000644 001750 001750 00000005650 12223260306 021461 0ustar00niklasniklas000000 000000 /**************************************************************************** ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef DOWNLOADMANAGER_H #define DOWNLOADMANAGER_H #include #include #include #include #include #include #include #include class DownloadManager: public QObject { Q_OBJECT QNetworkAccessManager manager; QList currentDownloads; QMap destinationPaths; public: explicit DownloadManager(QObject *parent = 0); void doDownload(const QUrl &url); void doDownloadToPath(const QUrl &url, const QString& path); QString saveFileName(const QUrl &url); bool saveToDisk(const QString &filename, QIODevice *data); public slots: void execute(QStringList args); void downloadFinished(); signals: void onDownloadFinished(QUrl, QString); void downloadError(QUrl); void downloadManagerIdle(); }; #endif // DOWNLOADMANAGER_H chessx-1.0.0/src/database/enginedata.h000644 001750 001750 00000002213 12223260306 020406 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2010 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef ENGINEDATA_H #define ENGINEDATA_H #include #include "engineoptiondata.h" /** The EngineData class contains configuration of a single engine. */ class EngineData { public: enum EngineProtocol {WinBoard, UCI}; /** Standard constructor. */ EngineData(const QString& newName = ""); QString name; QString command; QString options; QString directory; EngineProtocol protocol; OptionValueList m_optionValues; static QString commandToName(const QString& command); }; #endif // ENGINEDATA_H chessx-1.0.0/src/gui/playerlistwidget.h000644 001750 001750 00000002470 12223260306 020730 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef PLAYERLISTWIDGET_H #define PLAYERLISTWIDGET_H #include #include #include "playerinfo.h" namespace Ui { class TagDetailWidget; } class DatabaseInfo; class PlayerListWidget : public QWidget { Q_OBJECT public: explicit PlayerListWidget(QWidget *parent = 0); ~PlayerListWidget(); signals: void filterRequest(QString ts); void renameRequest(QString ts); void filterEcoPlayerRequest(QString tag, QString eco, QString player); void raiseRequest(); public slots: void findPlayers(const QString& s); void slotSelectPlayer(const QString& player); void setDatabase(DatabaseInfo* dbInfo); void filterSelectedPlayer(); void renameSelectedPlayer(); void slotReconfigure(); void selectionChangedSlot(); void slotLinkClicked(const QUrl& url); protected slots: void selectPlayer(const QString& player); void playerSelected(const QString& player); private: PlayerInfo m_player; QStringList m_list; Ui::TagDetailWidget *ui; QStringListModel* m_filterModel; }; #endif // PLAYERLISTWIDGET_H chessx-1.0.0/src/database/taglist.h000644 001750 001750 00000007425 12223260306 017770 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2007 Marius Roets * * (C) 2008-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __TAGLIST_H__ #define __TAGLIST_H__ #include #include #include #include "stringtagvalues.h" #include "common.h" /** @ingroup Core TagList holds a list of TagValues objects. It represents the values of all the tags in a database. It has the ability to dump, and read it's data using QDataStream, and calling on TagValues' read() and write() methods. @todo - m_tagNameToInt can be moved to common.h/.cpp */ class TagList { public: TagList(); ~TagList(); void Init(); /** Adds a string value to a TagValues object, identified by tag */ int add(Tag tag, const QString& value); /** Adds a string value to a TagValues object, identified by tagName */ int add(const QString& tagName, const QString& value); /** Gets the value for tag identified by tagName, stored at index * in the TagValues instance */ QString tagValue(const QString& tagName, int index); /** Gets the value for tag identified by tag, stored at index * in the TagValues instance */ QString tagValue(Tag tag, int index); /** Returns the TagValues instance stored at index */ TagValues* tagValueList(int index); /** Returns the TagValues instance stored at index */ TagValues* operator[](int index); /** Returns the TagValues instance stored at index (const version). */ const TagValues* operator[](int index) const; /** Returns the number of TagValues instances in the list */ int count(); /** Clears the list and frees all associated memory */ void clear(); /** Given a tag name tagName, looks up the Tag */ int tagFromString(const QString& tagName); /** Given a Tag tag, looks up the tagName */ QString stringFromTag(Tag tag); /** Writes the instance data to a QDataStream */ void write(QDataStream& out); /** Clears the instance, and reads the instance data from a QDataStream */ void read(QDataStream& in); /** Enables fast adding of tags, by calling setCacheEnabled for all * instances in the list. */ void setCacheEnabled(bool enabled); /** Static member function to create a BasicTagMap. This map maps tags * that are colour dependant to a color independant list. Example: * White and Black are both mapped to PlayerName, so each name is stored * only once */ void createBasicTagMap(); /** Adds tagvalues to the taglist. tag indicates to which tag the * tagvalues correspond. tagvalues should be dynamically allocated. * This function only does something if there is not already in * m_list a TagValues object corresponding to tag. */ void addTagValues(const Tag& tag, TagValues* tagvalues); private: /** holds the TagValues instances */ QList m_list; /** Holds a map that maps the tag names to integer values, which will be * the index for m_list*/ QMap m_tagNameToInt; /** Indicates whether cache is currently enabled or not. If cache is enabled, * new TagValues instances added to the list, will have their cache enabled * as well */ bool m_cacheEnabled; BasicTagMapType BasicTagMap; }; #endif chessx-1.0.0/src/gui/toolmainwindow.h000644 001750 001750 00000001024 12223260306 020400 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef TOOLMAINWINDOW_H #define TOOLMAINWINDOW_H #include class ToolMainWindow : public QMainWindow { Q_OBJECT public: explicit ToolMainWindow(QWidget *parent = 0); signals: public slots: void saveConfig(); void slotReconfigure(); }; #endif // TOOLMAINWINDOW_H chessx-1.0.0/src/quazip/zip.c000644 001750 001750 00000114473 12204341672 016672 0ustar00niklasniklas000000 000000 /* zip.c -- IO on .zip files using zlib Version 1.01e, February 12th, 2005 27 Dec 2004 Rolf Kalbermatter Modification to zipOpen2 to support globalComment retrieval. Copyright (C) 1998-2005 Gilles Vollant Read zip.h for more info Modified by Sergey A. Tachenov to integrate with Qt. */ #include #include #include #include #include "zlib.h" #include "zip.h" #include "quazip_global.h" #ifdef STDC # include # include # include #endif #ifdef NO_ERRNO_H extern int errno; #else # include #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ #ifndef VERSIONMADEBY # define VERSIONMADEBY (0x031e) /* best for standard pkware crypt */ #endif #ifndef Z_BUFSIZE #define Z_BUFSIZE (16384) #endif #ifndef Z_MAXFILENAMEINZIP #define Z_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #ifndef TRYFREE # define TRYFREE(p) {if (p) free(p);} #endif /* #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) */ /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ #ifndef SEEK_CUR #define SEEK_CUR 1 #endif #ifndef SEEK_END #define SEEK_END 2 #endif #ifndef SEEK_SET #define SEEK_SET 0 #endif #ifndef DEF_MEM_LEVEL #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif #endif const char zip_copyright[] = " zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; #define SIZEDATA_INDATABLOCK (4096-(4*4)) #define LOCALHEADERMAGIC (0x04034b50) #define DESCRIPTORHEADERMAGIC (0x08074b50) #define CENTRALHEADERMAGIC (0x02014b50) #define ENDHEADERMAGIC (0x06054b50) #define FLAG_LOCALHEADER_OFFSET (0x06) #define CRC_LOCALHEADER_OFFSET (0x0e) #define SIZECENTRALHEADER (0x2e) /* 46 */ typedef struct linkedlist_datablock_internal_s { struct linkedlist_datablock_internal_s* next_datablock; uLong avail_in_this_block; uLong filled_in_this_block; uLong unused; /* for future use and alignement */ unsigned char data[SIZEDATA_INDATABLOCK]; } linkedlist_datablock_internal; typedef struct linkedlist_data_s { linkedlist_datablock_internal* first_block; linkedlist_datablock_internal* last_block; } linkedlist_data; typedef struct { z_stream stream; /* zLib stream structure for inflate */ int stream_initialised; /* 1 is stream is initialised */ uInt pos_in_buffered_data; /* last written byte in buffered_data */ uLong pos_local_header; /* offset of the local header of the file currenty writing */ char* central_header; /* central header data for the current file */ uLong size_centralheader; /* size of the central header for cur file */ uLong flag; /* flag of the file currently writing */ int method; /* compression method of file currenty wr.*/ int raw; /* 1 for directly writing raw data */ Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ uLong dosDate; uLong crc32; int encrypt; #ifndef NOCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ const unsigned long* pcrc_32_tab; int crypt_header_size; #endif } curfile_info; typedef struct { zlib_filefunc_def z_filefunc; voidpf filestream; /* io structore of the zipfile */ linkedlist_data central_dir;/* datablock with central dir in construction*/ int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ curfile_info ci; /* info on the file curretly writing */ uLong begin_pos; /* position of the beginning of the zipfile */ uLong add_position_when_writting_offset; uLong number_entry; #ifndef NO_ADDFILEINEXISTINGZIP char *globalcomment; #endif unsigned flags; } zip_internal; #ifndef NOCRYPT #define INCLUDECRYPTINGCODE_IFCRYPTALLOWED #include "crypt.h" #endif local linkedlist_datablock_internal* allocate_new_datablock() { linkedlist_datablock_internal* ldi; ldi = (linkedlist_datablock_internal*) ALLOC(sizeof(linkedlist_datablock_internal)); if (ldi!=NULL) { ldi->next_datablock = NULL ; ldi->filled_in_this_block = 0 ; ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; } return ldi; } local void free_datablock(ldi) linkedlist_datablock_internal* ldi; { while (ldi!=NULL) { linkedlist_datablock_internal* ldinext = ldi->next_datablock; TRYFREE(ldi); ldi = ldinext; } } local void init_linkedlist(ll) linkedlist_data* ll; { ll->first_block = ll->last_block = NULL; } #if 0 // unused local void free_linkedlist(ll) linkedlist_data* ll; { free_datablock(ll->first_block); ll->first_block = ll->last_block = NULL; } #endif local int add_data_in_datablock(ll,buf,len) linkedlist_data* ll; const void* buf; uLong len; { linkedlist_datablock_internal* ldi; const unsigned char* from_copy; if (ll==NULL) return ZIP_INTERNALERROR; if (ll->last_block == NULL) { ll->first_block = ll->last_block = allocate_new_datablock(); if (ll->first_block == NULL) return ZIP_INTERNALERROR; } ldi = ll->last_block; from_copy = (unsigned char*)buf; while (len>0) { uInt copy_this; uInt i; unsigned char* to_copy; if (ldi->avail_in_this_block==0) { ldi->next_datablock = allocate_new_datablock(); if (ldi->next_datablock == NULL) return ZIP_INTERNALERROR; ldi = ldi->next_datablock ; ll->last_block = ldi; } if (ldi->avail_in_this_block < len) copy_this = (uInt)ldi->avail_in_this_block; else copy_this = (uInt)len; to_copy = &(ldi->data[ldi->filled_in_this_block]); for (i=0;ifilled_in_this_block += copy_this; ldi->avail_in_this_block -= copy_this; from_copy += copy_this ; len -= copy_this; } return ZIP_OK; } /****************************************************************************/ #ifndef NO_ADDFILEINEXISTINGZIP /* =========================================================================== Inputs a long in LSB order to the given file nbByte == 1, 2 or 4 (unsigned char, short or long) */ local int ziplocal_putValue OF((const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, uLong x, int nbByte)); local int ziplocal_putValue (pzlib_filefunc_def, filestream, x, nbByte) const zlib_filefunc_def* pzlib_filefunc_def; voidpf filestream; uLong x; int nbByte; { unsigned char buf[4]; int n; for (n = 0; n < nbByte; n++) { buf[n] = (unsigned char)(x & 0xff); x >>= 8; } if (x != 0) { /* data overflow - hack for ZIP64 (X Roche) */ for (n = 0; n < nbByte; n++) { buf[n] = 0xff; } } if (ZWRITE(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) return ZIP_ERRNO; else return ZIP_OK; } local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte)); local void ziplocal_putValue_inmemory (dest, x, nbByte) void* dest; uLong x; int nbByte; { unsigned char* buf=(unsigned char*)dest; int n; for (n = 0; n < nbByte; n++) { buf[n] = (unsigned char)(x & 0xff); x >>= 8; } if (x != 0) { /* data overflow - hack for ZIP64 */ for (n = 0; n < nbByte; n++) { buf[n] = 0xff; } } } /****************************************************************************/ local uLong ziplocal_TmzDateToDosDate(ptm,dosDate) const tm_zip* ptm; uLong dosDate UNUSED; { uLong year = (uLong)ptm->tm_year; if (year>1980) year-=1980; else if (year>80) year-=80; return (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); } /****************************************************************************/ local int ziplocal_getByte OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, int *pi)); local int ziplocal_getByte(pzlib_filefunc_def,filestream,pi) const zlib_filefunc_def* pzlib_filefunc_def; voidpf filestream; int *pi; { unsigned char c; int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); if (err==1) { *pi = (int)c; return ZIP_OK; } else { if (ZERROR(*pzlib_filefunc_def,filestream)) return ZIP_ERRNO; else return ZIP_EOF; } } /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets */ local int ziplocal_getShort OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int ziplocal_getShort (pzlib_filefunc_def,filestream,pX) const zlib_filefunc_def* pzlib_filefunc_def; voidpf filestream; uLong *pX; { uLong x ; int i; int err; err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==ZIP_OK) err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<8; if (err==ZIP_OK) *pX = x; else *pX = 0; return err; } local int ziplocal_getLong OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int ziplocal_getLong (pzlib_filefunc_def,filestream,pX) const zlib_filefunc_def* pzlib_filefunc_def; voidpf filestream; uLong *pX; { uLong x ; int i; int err; err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==ZIP_OK) err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<8; if (err==ZIP_OK) err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<16; if (err==ZIP_OK) err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<24; if (err==ZIP_OK) *pX = x; else *pX = 0; return err; } #ifndef BUFREADCOMMENT #define BUFREADCOMMENT (0x400) #endif /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ local uLong ziplocal_SearchCentralDir OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream)); local uLong ziplocal_SearchCentralDir(pzlib_filefunc_def,filestream) const zlib_filefunc_def* pzlib_filefunc_def; voidpf filestream; { unsigned char* buf; uLong uSizeFile; uLong uBackRead; uLong uMaxBack=0xffff; /* maximum size of global comment */ uLong uPosFound=0; if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { uPosFound = uReadPos+i; break; } if (uPosFound!=0) break; } TRYFREE(buf); return uPosFound; } #endif /* !NO_ADDFILEINEXISTINGZIP*/ /************************************************************/ extern zipFile ZEXPORT zipOpen2 (file, append, globalcomment, pzlib_filefunc_def) voidpf file; int append; zipcharpc* globalcomment; zlib_filefunc_def* pzlib_filefunc_def; { zip_internal ziinit; zip_internal* zi; int err=ZIP_OK; if (pzlib_filefunc_def==NULL) fill_qiodevice_filefunc(&ziinit.z_filefunc); else ziinit.z_filefunc = *pzlib_filefunc_def; ziinit.filestream = (*(ziinit.z_filefunc.zopen_file)) (ziinit.z_filefunc.opaque, file, (append == APPEND_STATUS_CREATE) ? (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); if (ziinit.filestream == NULL) return NULL; ziinit.begin_pos = ZTELL(ziinit.z_filefunc,ziinit.filestream); ziinit.in_opened_file_inzip = 0; ziinit.ci.stream_initialised = 0; ziinit.number_entry = 0; ziinit.add_position_when_writting_offset = 0; ziinit.flags = ZIP_WRITE_DATA_DESCRIPTOR; init_linkedlist(&(ziinit.central_dir)); zi = (zip_internal*)ALLOC(sizeof(zip_internal)); if (zi==NULL) { ZCLOSE(ziinit.z_filefunc,ziinit.filestream); return NULL; } /* now we add file in a zipfile */ # ifndef NO_ADDFILEINEXISTINGZIP ziinit.globalcomment = NULL; if (append == APPEND_STATUS_ADDINZIP) { uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ uLong size_central_dir; /* size of the central directory */ uLong offset_central_dir; /* offset of start of central directory */ uLong central_pos,uL; uLong number_disk; /* number of the current dist, used for spaning ZIP, unsupported, always 0*/ uLong number_disk_with_CD; /* number the the disk with central dir, used for spaning ZIP, unsupported, always 0*/ uLong number_entry; uLong number_entry_CD; /* total number of entries in the central dir (same than number_entry on nospan) */ uLong size_comment; central_pos = ziplocal_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream); if (central_pos==0) err=ZIP_ERRNO; if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) err=ZIP_ERRNO; /* the signature, already checked */ if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&uL)!=ZIP_OK) err=ZIP_ERRNO; /* number of this disk */ if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk)!=ZIP_OK) err=ZIP_ERRNO; /* number of the disk with the start of the central directory */ if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk_with_CD)!=ZIP_OK) err=ZIP_ERRNO; /* total number of entries in the central dir on this disk */ if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry)!=ZIP_OK) err=ZIP_ERRNO; /* total number of entries in the central dir */ if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry_CD)!=ZIP_OK) err=ZIP_ERRNO; if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=ZIP_BADZIPFILE; /* size of the central directory */ if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&size_central_dir)!=ZIP_OK) err=ZIP_ERRNO; /* offset of start of central directory with respect to the starting disk number */ if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&offset_central_dir)!=ZIP_OK) err=ZIP_ERRNO; /* zipfile global comment length */ if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&size_comment)!=ZIP_OK) err=ZIP_ERRNO; if ((central_pos0) { ziinit.globalcomment = ALLOC(size_comment+1); if (ziinit.globalcomment) { size_comment = ZREAD(ziinit.z_filefunc, ziinit.filestream,ziinit.globalcomment,size_comment); ziinit.globalcomment[size_comment]=0; } } byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); ziinit.add_position_when_writting_offset = byte_before_the_zipfile; { uLong size_central_dir_to_read = size_central_dir; size_t buf_size = SIZEDATA_INDATABLOCK; void* buf_read = (void*)ALLOC(buf_size); if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) err=ZIP_ERRNO; while ((size_central_dir_to_read>0) && (err==ZIP_OK)) { uLong read_this = SIZEDATA_INDATABLOCK; if (read_this > size_central_dir_to_read) read_this = size_central_dir_to_read; if (ZREAD(ziinit.z_filefunc, ziinit.filestream,buf_read,read_this) != read_this) err=ZIP_ERRNO; if (err==ZIP_OK) err = add_data_in_datablock(&ziinit.central_dir,buf_read, (uLong)read_this); size_central_dir_to_read-=read_this; } TRYFREE(buf_read); } ziinit.begin_pos = byte_before_the_zipfile; ziinit.number_entry = number_entry_CD; if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) err=ZIP_ERRNO; } if (globalcomment) { *globalcomment = ziinit.globalcomment; } # endif /* !NO_ADDFILEINEXISTINGZIP*/ if (err != ZIP_OK) { # ifndef NO_ADDFILEINEXISTINGZIP TRYFREE(ziinit.globalcomment); # endif /* !NO_ADDFILEINEXISTINGZIP*/ TRYFREE(zi); return NULL; } else { *zi = ziinit; return (zipFile)zi; } } extern zipFile ZEXPORT zipOpen (file, append) voidpf file; int append; { return zipOpen2(file,append,NULL,NULL); } extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting) zipFile file; const char* filename; const zip_fileinfo* zipfi; const void* extrafield_local; uInt size_extrafield_local; const void* extrafield_global; uInt size_extrafield_global; const char* comment; int method; int level; int raw; int windowBits; int memLevel; int strategy; const char* password; uLong crcForCrypting; { zip_internal* zi; uInt size_filename; uInt size_comment; uInt i; int err = ZIP_OK; uLong version_to_extract; # ifdef NOCRYPT if (password != NULL) return ZIP_PARAMERROR; # endif if (file == NULL) return ZIP_PARAMERROR; if ((method!=0) && (method!=Z_DEFLATED)) return ZIP_PARAMERROR; zi = (zip_internal*)file; if (zi->in_opened_file_inzip == 1) { err = zipCloseFileInZip (file); if (err != ZIP_OK) return err; } if (method == 0 && (level == 0 || (zi->flags & ZIP_WRITE_DATA_DESCRIPTOR) == 0)) { version_to_extract = 10; } else { version_to_extract = 20; } if (filename==NULL) filename="-"; if (comment==NULL) size_comment = 0; else size_comment = (uInt)strlen(comment); size_filename = (uInt)strlen(filename); if (zipfi == NULL) zi->ci.dosDate = 0; else { if (zipfi->dosDate != 0) zi->ci.dosDate = zipfi->dosDate; else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate); } zi->ci.flag = 0; if ((level==8) || (level==9)) zi->ci.flag |= 2; else if (level==2) zi->ci.flag |= 4; else if (level==1) zi->ci.flag |= 6; if (password != NULL) { zi->ci.flag |= 1; } if (version_to_extract >= 20 && (zi->flags & ZIP_WRITE_DATA_DESCRIPTOR) != 0) zi->ci.flag |= 8; zi->ci.crc32 = 0; zi->ci.method = method; zi->ci.encrypt = 0; zi->ci.stream_initialised = 0; zi->ci.pos_in_buffered_data = 0; zi->ci.raw = raw; zi->ci.pos_local_header = ZTELL(zi->z_filefunc,zi->filestream) ; zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader); ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); /* version info */ ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2); ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)version_to_extract,2); ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ if (zipfi==NULL) ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); else ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); if (zipfi==NULL) ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); else ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header- zi->add_position_when_writting_offset,4); for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = *(((const char*)extrafield_global)+i); for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ size_extrafield_global+i) = *(comment+i); if (zi->ci.central_header == NULL) return ZIP_INTERNALERROR; /* write the local header */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC,4); if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)version_to_extract,2); if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield_local,2); if ((err==ZIP_OK) && (size_filename>0)) if (ZWRITE(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) err = ZIP_ERRNO; if ((err==ZIP_OK) && (size_extrafield_local>0)) if (ZWRITE(zi->z_filefunc,zi->filestream,extrafield_local,size_extrafield_local) !=size_extrafield_local) err = ZIP_ERRNO; zi->ci.stream.avail_in = (uInt)0; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; zi->ci.stream.total_in = 0; zi->ci.stream.total_out = 0; if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) { zi->ci.stream.zalloc = (alloc_func)0; zi->ci.stream.zfree = (free_func)0; zi->ci.stream.opaque = (voidpf)0; if (windowBits>0) windowBits = -windowBits; err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); if (err==Z_OK) zi->ci.stream_initialised = 1; } # ifndef NOCRYPT zi->ci.crypt_header_size = 0; if ((err==Z_OK) && (password != NULL)) { unsigned char bufHead[RAND_HEAD_LEN]; unsigned int sizeHead; zi->ci.encrypt = 1; zi->ci.pcrc_32_tab = get_crc_table(); /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ crcForCrypting = (uLong)zi->ci.dosDate << 16; // ATTANTION! Without this row, you don't unpack your password protected archive in other app. sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); zi->ci.crypt_header_size = sizeHead; if (ZWRITE(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) err = ZIP_ERRNO; } # endif if (err==Z_OK) zi->in_opened_file_inzip = 1; return err; } extern int ZEXPORT zipOpenNewFileInZip2(file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw) zipFile file; const char* filename; const zip_fileinfo* zipfi; const void* extrafield_local; uInt size_extrafield_local; const void* extrafield_global; uInt size_extrafield_global; const char* comment; int method; int level; int raw; { return zipOpenNewFileInZip3 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0); } extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level) zipFile file; const char* filename; const zip_fileinfo* zipfi; const void* extrafield_local; uInt size_extrafield_local; const void* extrafield_global; uInt size_extrafield_global; const char* comment; int method; int level; { return zipOpenNewFileInZip2 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, 0); } local int zipFlushWriteBuffer(zi) zip_internal* zi; { int err=ZIP_OK; if (zi->ci.encrypt != 0) { #ifndef NOCRYPT uInt i; int t; for (i=0;ici.pos_in_buffered_data;i++) zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); #endif } if (ZWRITE(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) !=zi->ci.pos_in_buffered_data) err = ZIP_ERRNO; zi->ci.pos_in_buffered_data = 0; return err; } extern int ZEXPORT zipWriteInFileInZip (file, buf, len) zipFile file; const void* buf; unsigned len; { zip_internal* zi; int err=ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; zi = (zip_internal*)file; if (zi->in_opened_file_inzip == 0) return ZIP_PARAMERROR; zi->ci.stream.next_in = (void*)buf; zi->ci.stream.avail_in = len; zi->ci.crc32 = crc32(zi->ci.crc32,buf,len); while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) { if (zi->ci.stream.avail_out == 0) { if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; } if(err != ZIP_OK) break; if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) { uLong uTotalOutBefore = zi->ci.stream.total_out; err=deflate(&zi->ci.stream, Z_NO_FLUSH); zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; } else { uInt copy_this,i; if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) copy_this = zi->ci.stream.avail_in; else copy_this = zi->ci.stream.avail_out; for (i=0;ici.stream.next_out)+i) = *(((const char*)zi->ci.stream.next_in)+i); { zi->ci.stream.avail_in -= copy_this; zi->ci.stream.avail_out-= copy_this; zi->ci.stream.next_in+= copy_this; zi->ci.stream.next_out+= copy_this; zi->ci.stream.total_in+= copy_this; zi->ci.stream.total_out+= copy_this; zi->ci.pos_in_buffered_data += copy_this; } } } return err; } extern int ZEXPORT zipCloseFileInZipRaw (file, uncompressed_size, crc32) zipFile file; uLong uncompressed_size; uLong crc32; { zip_internal* zi; uLong compressed_size; int err=ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; zi = (zip_internal*)file; if (zi->in_opened_file_inzip == 0) return ZIP_PARAMERROR; zi->ci.stream.avail_in = 0; if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) while (err==ZIP_OK) { uLong uTotalOutBefore; if (zi->ci.stream.avail_out == 0) { if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; } uTotalOutBefore = zi->ci.stream.total_out; err=deflate(&zi->ci.stream, Z_FINISH); zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; } if (err==Z_STREAM_END) err=ZIP_OK; /* this is normal */ if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) if (zipFlushWriteBuffer(zi)==ZIP_ERRNO) err = ZIP_ERRNO; if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) { err=deflateEnd(&zi->ci.stream); zi->ci.stream_initialised = 0; } if (!zi->ci.raw) { crc32 = (uLong)zi->ci.crc32; uncompressed_size = (uLong)zi->ci.stream.total_in; } compressed_size = (uLong)zi->ci.stream.total_out; # ifndef NOCRYPT compressed_size += zi->ci.crypt_header_size; # endif ziplocal_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ ziplocal_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ if (zi->ci.stream.data_type == Z_ASCII) ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); ziplocal_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ if (err==ZIP_OK) err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header, (uLong)zi->ci.size_centralheader); free(zi->ci.central_header); if (err==ZIP_OK) { uLong cur_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); if (ZSEEK(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) err = ZIP_ERRNO; if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ if (err==ZIP_OK) /* compressed size, unknown */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); if (err==ZIP_OK) /* uncompressed size, unknown */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); if (ZSEEK(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) err = ZIP_ERRNO; if ((zi->ci.flag & 8) != 0) { /* Write local Descriptor after file data */ if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)DESCRIPTORHEADERMAGIC,4); if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ if (err==ZIP_OK) /* compressed size, unknown */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); if (err==ZIP_OK) /* uncompressed size, unknown */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); } } zi->number_entry ++; zi->in_opened_file_inzip = 0; return err; } extern int ZEXPORT zipCloseFileInZip (file) zipFile file; { return zipCloseFileInZipRaw (file,0,0); } extern int ZEXPORT zipClose (file, global_comment) zipFile file; const char* global_comment; { zip_internal* zi; int err = 0; uLong size_centraldir = 0; uLong centraldir_pos_inzip; uInt size_global_comment; if (file == NULL) return ZIP_PARAMERROR; zi = (zip_internal*)file; if (zi->in_opened_file_inzip == 1) { err = zipCloseFileInZip (file); } #ifndef NO_ADDFILEINEXISTINGZIP if (global_comment==NULL) global_comment = zi->globalcomment; #endif if (global_comment==NULL) size_global_comment = 0; else size_global_comment = (uInt)strlen(global_comment); centraldir_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); if (err==ZIP_OK) { linkedlist_datablock_internal* ldi = zi->central_dir.first_block ; while (ldi!=NULL) { if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) if (ZWRITE(zi->z_filefunc,zi->filestream, ldi->data,ldi->filled_in_this_block) !=ldi->filled_in_this_block ) err = ZIP_ERRNO; size_centraldir += ldi->filled_in_this_block; ldi = ldi->next_datablock; } } free_datablock(zi->central_dir.first_block); if (err==ZIP_OK) /* Magic End */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); if (err==ZIP_OK) /* number of this disk */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); if (err==ZIP_OK) /* total number of entries in the central dir */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); if (err==ZIP_OK) /* size of the central directory */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); if (err==ZIP_OK) /* zipfile comment length */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); if ((err==ZIP_OK) && (size_global_comment>0)) if (ZWRITE(zi->z_filefunc,zi->filestream, global_comment,size_global_comment) != size_global_comment) err = ZIP_ERRNO; if (ZCLOSE(zi->z_filefunc,zi->filestream) != 0) if (err == ZIP_OK) err = ZIP_ERRNO; #ifndef NO_ADDFILEINEXISTINGZIP TRYFREE(zi->globalcomment); #endif TRYFREE(zi); return err; } extern int ZEXPORT zipSetFlags(zipFile file, unsigned flags) { zip_internal* zi; if (file == NULL) return ZIP_PARAMERROR; zi = (zip_internal*)file; zi->flags |= flags; return ZIP_OK; } extern int ZEXPORT zipClearFlags(zipFile file, unsigned flags) { zip_internal* zi; if (file == NULL) return ZIP_PARAMERROR; zi = (zip_internal*)file; zi->flags &= ~flags; return ZIP_OK; } chessx-1.0.0/src/gui/qled.h000755 001750 001750 00000004622 12223260306 016265 0ustar00niklasniklas000000 000000 /*************************************************************************** * Copyright (C) 2010 by P. Sereno * * http://www.sereno-online.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License * * version 2.1 as published by the Free Software Foundation * * * * 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 Lesser General Public License for more details. * * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. * ***************************************************************************/ #ifndef QLED_H #define QLED_H #include #include class QColor; class QSvgRenderer; class QLed : public QWidget { Q_OBJECT Q_ENUMS(ledColor) Q_ENUMS(ledShape) Q_PROPERTY(bool value READ value WRITE setValue); Q_PROPERTY(ledColor onColor READ onColor WRITE setOnColor); Q_PROPERTY(ledColor offColor READ offColor WRITE setOffColor); Q_PROPERTY(ledShape shape READ shape WRITE setShape) public: QLed(QWidget *parent = 0); virtual ~QLed(); bool value() const { return m_value; } enum ledColor { Red = 0, Green, Yellow, Grey, Orange, Blue, Black }; enum ledShape { Circle = 0}; ledColor onColor() const { return m_onColor; } ledColor offColor() const { return m_offColor; } ledShape shape() const { return m_shape; } public slots: void setValue(bool); void setOnColor(ledColor); void setOffColor(ledColor); void setShape(ledShape); void toggleValue(); protected: bool m_value; ledColor m_onColor, m_offColor; int id_Timer; ledShape m_shape; QStringList shapes; QStringList colors; void paintEvent(QPaintEvent *event); void resizeEvent(QResizeEvent*); private: QSvgRenderer *renderer ; }; #endif chessx-1.0.0/src/gui/boardtheme.h000644 001750 001750 00000007306 12223260306 017451 0ustar00niklasniklas000000 000000 /*************************************************************************** BoardTheme - graphics theme for BoardView ------------------- begin : Sun 21 Aug 2005 copyright : (C) 2005 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef __BOARDTHEME_H__ #define __BOARDTHEME_H__ #include #include "common.h" /** @ingroup GUI The BoardTheme class contains set of pixmaps and options to define current board theme. Themes are read from INI files pointing to set of external pixmaps. Pixmaps are automatically scaled to given size. */ class BoardTheme : public QObject { Q_OBJECT public: enum ColorRole {LightSquare, DarkSquare, Highlight, Frame, CurrentMove, ColorRoleEndEntry}; enum LoadTheme {LoadBoard = 1, LoadPieces = 2, LoadAll = LoadBoard | LoadPieces}; enum Effects {Plain, Outline = 1, Shadow = 2}; BoardTheme(); ~BoardTheme(); /** Reset piece and board selections based on config values */ void configure(); /** Load piece graphics named by string + effect flag */ bool loadPieces(const QString& pieces, int effect); /** Load board graphics named by string */ bool loadBoard(const QString& board); /** Sets one of the board colors. */ void setColor(ColorRole role, const QColor& value); /** @return one of the board colors. */ QColor color(ColorRole role) const; /** @return pixmap for given piece scaled to current size(). */ const QPixmap& piece(Piece p) const; /** @return unscaled pixmap for given piece. */ const QPixmap& originalPiece(Piece p) const; /** @return pixmap for square. */ const QPixmap& square(bool dark) const; /** @return unscaled pixmap for square. */ const QPixmap& originalSquare(bool dark) const; /** Checkes whether themes is valid (pixmaps loaded). */ bool isValid() const; /** Returns name of board theme. It is just file without a path and extension. */ QString boardThemeName() const; /** Returns name of piece theme. It is just file without a path and extension. */ QString pieceThemeName() const; /** Returns theme directory */ QString themeDirectory() const; /** Returns board directory */ QString boardDirectory() const; /** Sets current size for pixmaps. Resizes all pixmaps. */ void setSize(const QSize& size); /** Returns current size of pixmaps. */ QSize size() const; /** Returns center point of piece pixmap. Useful for centering piece when dragging. */ QPoint pieceCenter() const; /** Returns current rectangle of pixmaps. */ QRect rect() const; /** Updates board square. */ void updateSquares(); /** Set the theme according to the parents state */ void setEnabled(bool enabled); private: bool isBoardPlain() const; QPixmap m_originalPiece[ConstPieceTypes]; QPixmap m_piece[ConstPieceTypes]; QPixmap m_originalSquare[2]; QPixmap m_square[2]; QSize m_size; QColor m_colors[ColorRoleEndEntry]; QString m_pieceFilename; QString m_boardFilename; }; #endif chessx-1.0.0/src/database/playerdatabase.cpp000644 001750 001750 00000032772 12223260306 021640 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2006 Ejner Borgbjerg * * (C) 2006-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ /* Documentation for managing QDataset version, see http://doc.trolltech.com/4.0/qdatastream.html */ #include "playerdatabase.h" static quint32 Magic = (quint32)0xB0D0A0D0; // 'magic' number static quint32 Version = (quint32)100; // file format version static QString Mapfile_suffix = ".cpm"; static QString Datafile_suffix = ".cpd"; bool PlayerDatabase::create(const QString& fname) { m_dirty = false; m_mapfile.setFileName(fname + Mapfile_suffix); m_datafile.setFileName(fname + Datafile_suffix); if(m_mapfile.exists() || m_datafile.exists()) { return false; } // set QDataset format version to use if(Version == (quint32)100) { m_mapds.setVersion(6); m_datads.setVersion(6); } else //default { m_mapds.setVersion(6); m_datads.setVersion(6); } m_mapfile.open(QIODevice::ReadWrite); m_mapds.setDevice(&m_mapfile); m_mapds << Magic; m_mapds << Version; m_nplayers = 0; m_nplayers_offset = m_mapfile.pos(); m_mapds << m_nplayers; m_datafile.open(QIODevice::ReadWrite); m_datads.setDevice(&m_datafile); m_datads << Magic; m_datads << Version;//use current version for new db's m_mapfile.flush(); m_datafile.flush(); m_dataFileCurrentPosition = m_datafile.pos(); m_npending_adds = 0; return true; } bool PlayerDatabase::open(const QString& fname) { m_dirty = false; m_mapfile.setFileName(fname + Mapfile_suffix); if(!m_mapfile.open(QIODevice::ReadWrite)) { return false; } m_mapds.setDevice(&m_mapfile); quint32 map_magic; quint32 map_version; m_mapds >> map_magic; m_mapds >> map_version; if(map_magic != Magic) { m_mapds.unsetDevice(); m_mapfile.close(); return false; } // set QDataset format version to use if(map_version == (quint32)100) { m_mapds.setVersion(6); } else //unknown version { m_mapds.unsetDevice(); m_mapfile.close(); return false; } quint32 data_magic; quint32 data_version; m_datafile.setFileName(fname + Datafile_suffix); if(!m_datafile.open(QIODevice::ReadWrite)) { m_mapds.unsetDevice(); m_mapfile.close(); return false; } m_datads.setDevice(&m_datafile); m_datads >> data_magic; m_datads >> data_version; if(data_magic != Magic) { m_mapds.unsetDevice(); m_mapfile.close(); m_datads.unsetDevice(); m_datafile.close(); return false; } // set QDataset format version to use if(data_version == (quint32)100) { m_datads.setVersion(6); } else //unknown version { m_mapds.unsetDevice(); m_mapfile.close(); m_datads.unsetDevice(); m_datafile.close(); return false; } if(map_version != data_version) { m_mapds.unsetDevice(); m_mapfile.close(); m_datads.unsetDevice(); m_datafile.close(); return false; } m_dataFileCurrentPosition = m_datafile.pos(); m_nplayers_offset = m_mapfile.pos(); m_mapds >> m_nplayers; if(m_nplayers > 0) { m_mapds >> m_mapping; } m_npending_adds = 0; return true; } bool PlayerDatabase::removeDatabase(const QString& fname) { m_mapfile.setFileName(fname + Mapfile_suffix); m_datafile.setFileName(fname + Datafile_suffix); return m_mapfile.remove() && m_datafile.remove(); } void PlayerDatabase::close() { commit(); m_mapds.unsetDevice(); m_mapfile.flush(); m_mapfile.close(); m_datads.unsetDevice(); m_datafile.flush(); m_datafile.close(); } void PlayerDatabase::rollback() { m_pendingUpdates.clear(); m_dirty = false; m_npending_adds = 0; } void PlayerDatabase::commit() { if(m_dirty) //current player was changed { m_pendingUpdates.insert(m_currentPlayerName, m_currentPlayer); } m_mapfile.seek(m_nplayers_offset); m_mapds << m_nplayers; // write non-committed changes m_dataFileCurrentPosition = m_datafile.size(); m_datafile.seek(m_dataFileCurrentPosition); QMap::Iterator it; for(it = m_pendingUpdates.begin(); it != m_pendingUpdates.end(); ++it) { m_mapping.insert(it.key(), m_datafile.pos()); m_datads << it.value().dateOfBirth().asString(); m_datads << it.value().dateOfDeath().asString(); m_datads << it.value().country(); m_datads << it.value().title(); m_datads << it.value().eloListData(); m_datads << (qint32)(it.value().firstEloListIndex()); m_datads << (qint32)(it.value().lastEloListIndex()); m_datads << (qint32)(it.value().estimatedElo()); m_datads << (qint32)(it.value().peakElo()); m_datads << it.value().photo(); m_datads << it.value().biography(); } m_mapds << m_mapping; m_mapfile.flush(); m_datafile.flush(); m_pendingUpdates.clear(); m_dirty = false; m_nplayers += m_npending_adds; m_npending_adds = 0; } PlayerData PlayerDatabase::readPlayerData(const QString& playername) { PlayerData pd; QMap::Iterator it; it = m_mapping.find(playername); if(it == m_mapping.end()) { //not in committed data, look in non-committed updates QMap::Iterator it2; it2 = m_pendingUpdates.find(playername); if(it2 != m_pendingUpdates.end()) { return it2.value(); } else //give up { return pd; } } qint32 pos = it.value(); m_datafile.seek(pos);//pointing to the player data QString birthDate; QString deathDate; QString country; QString title; m_datads >> birthDate; m_datads >> deathDate; m_datads >> country; m_datads >> title; if(birthDate.contains('.')) { pd.setDateOfBirth(PartialDate(birthDate)); } if(deathDate.contains('.')) { pd.setDateOfDeath(deathDate); } pd.setCountry(country); pd.setTitle(title); QList eloList; m_datads >> eloList; pd.eloFromListData(eloList); qint32 firstEloListIndex; qint32 lastEloListIndex; qint32 estimatedElo; qint32 peakElo; QImage photo; QString biography; m_datads >> firstEloListIndex; m_datads >> lastEloListIndex; m_datads >> estimatedElo; m_datads >> peakElo; m_datads >> photo; m_datads >> biography; pd.setFirstEloListIndex((int)firstEloListIndex); pd.setLastEloListIndex((int)lastEloListIndex); pd.setEstimatedElo((int)estimatedElo); pd.setPeakElo((int)peakElo); pd.setPhoto(photo); pd.setBiography(biography); return pd; } unsigned int PlayerDatabase::count() const { return m_nplayers + m_npending_adds; } bool PlayerDatabase::add(const QString& playername) { if(m_mapping.contains(playername) || m_pendingUpdates.contains(playername)) { return false; } if(m_dirty) //previous current player was changed { m_pendingUpdates.insert(m_currentPlayerName, m_currentPlayer); } PlayerData pd; m_currentPlayerName = playername; m_currentPlayer = pd; m_dirty = true; ++m_npending_adds; return true; } QString PlayerDatabase::current() const { return m_currentPlayerName; } void PlayerDatabase::setCurrent(const QString& playername) { if(m_currentPlayerName.compare(playername) == 0) { return; } if(m_dirty) //previous current player was changed { m_pendingUpdates.insert(m_currentPlayerName, m_currentPlayer); } m_currentPlayerName = playername; m_currentPlayer = readPlayerData(playername); m_dirty = false; } bool PlayerDatabase::exists(const QString& playername) const { if(m_mapping.contains(playername)) { return true; } if(m_pendingUpdates.contains(playername)) { return true; } return false; } PartialDate PlayerDatabase::dateOfBirth() const { return m_currentPlayer.dateOfBirth(); } void PlayerDatabase::setDateOfBirth(const PartialDate& date) { m_currentPlayer.setDateOfBirth(date); if(!m_dirty) { m_dirty = true; } } PartialDate PlayerDatabase::dateOfDeath() const { return m_currentPlayer.dateOfDeath(); } void PlayerDatabase::setDateOfDeath(const PartialDate & date) { m_currentPlayer.setDateOfDeath(date); if(!m_dirty) { m_dirty = true; } } QString PlayerDatabase::country() const { return m_currentPlayer.country(); } void PlayerDatabase::setCountry(const QString& country) { m_currentPlayer.setCountry(country); if(!m_dirty) { m_dirty = true; } } QString PlayerDatabase::title() const { return m_currentPlayer.title(); } void PlayerDatabase::setTitle(const QString& title) { m_currentPlayer.setTitle(title); if(!m_dirty) { m_dirty = true; } } int PlayerDatabase::firstEloListIndex() { return m_currentPlayer.firstEloListIndex(); } int PlayerDatabase::lastEloListIndex() { return m_currentPlayer.lastEloListIndex(); } int PlayerDatabase::elo(const PartialDate& date) const { return m_currentPlayer.elo(eloList(date)); } int PlayerDatabase::elo(const int eloList) const { return m_currentPlayer.elo(eloList); } int PlayerDatabase::estimatedElo(const PartialDate& date) { return m_currentPlayer.estimatedElo(eloList(date)); } int PlayerDatabase::estimatedEloNoCache(const PartialDate& date) const { return m_currentPlayer.estimatedEloNoCache(eloList(date)); } int PlayerDatabase::estimatedElo() const { return m_currentPlayer.estimatedElo(); } int PlayerDatabase::highestElo() const { return m_currentPlayer.peakElo(); } void PlayerDatabase::setElo(const int year, const int listIndex, const int elo) { m_currentPlayer.setElo(eloList(year, listIndex), elo); if(!m_dirty) { m_dirty = true; } } void PlayerDatabase::setEstimatedElo(const int elo) { m_currentPlayer.setEstimatedElo(elo); if(!m_dirty) { m_dirty = true; } } bool PlayerDatabase::hasPhoto() const { return !m_currentPlayer.photo().isNull(); } QImage PlayerDatabase::photo() const { return m_currentPlayer.photo(); } void PlayerDatabase::setPhoto(const QImage& img) { m_currentPlayer.setPhoto(img); if(!m_dirty) { m_dirty = true; } } bool PlayerDatabase::hasBiography() const { return !m_currentPlayer.biography().isNull(); } QString PlayerDatabase::biography() const { return m_currentPlayer.biography(); } void PlayerDatabase::setBiography(const QString& s) { m_currentPlayer.setBiography(s); if(!m_dirty) { m_dirty = true; } } void PlayerDatabase::appendToBiography(const QString& s) { m_currentPlayer.appendToBiography(s); if(!m_dirty) { m_dirty = true; } } QStringList PlayerDatabase::playerNames() { QStringList result; QMap::Iterator it; for(it = m_mapping.begin(); it != m_mapping.end(); ++it) { result.push_back(it.key()); } return result; } QStringList PlayerDatabase::findPlayers(const QString& prefix, const int maxCount, const Qt::CaseSensitivity cs) { QStringList result; QMap::Iterator it; int i = 0; for(it = m_mapping.begin(); it != m_mapping.end(); ++it) { if(it.key().startsWith(prefix, cs)) { if(i >= maxCount) { break; } result.push_back(it.key()); ++i; } } return result; } int PlayerDatabase::eloList(const PartialDate date) const { const int year = date.year(); if(year < 1971) { return 0; } if(year < 2001) //2 lists in the year { return ((year - 1971) * 2) + 1 + (date.month() / 7); } return 60 + ((year - 2001) * 4) + 1 + (date.month() / 4); //4 lists in the year } int PlayerDatabase::eloList(const int year, const int index) const { if(year < 1971) { return 0; } if(year < 2001) //2 lists in the year { return ((year - 1971) * 2) + index; } return 60 + ((year - 2001) * 4) + index; //4 lists in the year } PartialDate PlayerDatabase::eloListToDate(const int index) { if(index < 1) { return PDInvalidDate; } int year; int rem; int month; if(index < 61) { year = 1970 + ((index + 1) / 2); rem = index % 2; if(rem == 0) { month = 7; } else { month = 1; } } else { year = 2000 + ((index - 57) / 4); rem = index % 4; if(rem == 0) { month = 10; } else if(rem == 1) { month = 1; } else if(rem == 2) { month = 4; } else { month = 7; } } return PartialDate(year, month, 1); } chessx-1.0.0/src/database/memorydatabase.cpp000644 001750 001750 00000007271 12223260306 021650 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2007 Marius Roets * * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include #include #include "memorydatabase.h" #include "settings.h" MemoryDatabase::MemoryDatabase() : PgnDatabase(false), m_isModified(false) { } MemoryDatabase::~MemoryDatabase() { for(int i = 0; i < m_games.count(); ++i) { delete m_games[i]; } } bool MemoryDatabase::appendGame(const Game& game) { // Add to index QMap tags = game.tags(); QMap ::const_iterator i = tags.constBegin(); m_count = m_index.add(); while(i != tags.constEnd()) { m_index.setTag(i.key(), i.value(), m_count); ++i; } // Upate game array Game* newGame = new Game; *newGame = game; newGame->clearTags(); m_games.append(newGame); ++m_count; m_isModified = true; return true; } bool MemoryDatabase::remove(int gameId) { m_isModified = true; m_index.setDeleted(gameId, true); return true; } bool MemoryDatabase::undelete(int gameId) { m_isModified = true; m_index.setDeleted(gameId, false); return true; } bool MemoryDatabase::replace(int index, Game& game) { if(index >= m_count) { return false; } // Update index QMap tags = game.tags(); QMap ::const_iterator i = tags.constBegin(); while(i != tags.constEnd()) { m_index.setTag(i.key(), i.value(), index); ++i; } // Upate game array *m_games[index] = game; m_games[index]->clearTags(); m_isModified = true; return true; } void MemoryDatabase::loadGameMoves(int index, Game& game) { if(index >= m_count) { return; } game = *m_games[index]; } bool MemoryDatabase::loadGame(int index, Game& game) { if(index < 0 || index >= m_count || m_index.deleted(index)) { return false; } lock(); game = *m_games[index]; loadGameHeaders(index, game); unlock(); return true; } void MemoryDatabase::parseGame() { Game* game = new Game; QString fen = m_index.tagValue(TagNameFEN, m_count - 1); if(fen != "?") { game->setStartingBoard(fen); } m_index.setValidFlag(m_count - 1, parseMoves(game)); m_index.setTag("Length", QString::number((game->plyCount() + 1) / 2), m_count - 1); QString eco = game->tag("ECO").left(3); if(eco == "?") { eco.clear(); } if(AppSettings->getValue("/General/automaticECO").toBool()) { if(eco.isEmpty()) { eco = game->ecoClassify().left(3); if(!eco.isEmpty()) { game->setTag("ECO", eco); m_index.setTag("ECO", eco, m_count - 1); m_isModified = true; } } } m_games.append(game); } bool MemoryDatabase::parseFile() { bool ok = parseFileIntern(); m_isModified = false; return ok; } bool MemoryDatabase::clear() { for(int i = 0; i < m_games.count(); ++i) { delete m_games[i]; } m_games.clear(); m_isModified = true; return true; } chessx-1.0.0/src/quazip/zip.h000644 001750 001750 00000017534 12223260306 016672 0ustar00niklasniklas000000 000000 /* zip.h -- IO for compress .zip files using zlib Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant This unzip package allow creates .ZIP file, compatible with PKZip 2.04g WinZip, InfoZip tools and compatible. Multi volume ZipFile (span) are not supported. Encryption compatible with pkzip 2.04g only supported Old compressions used by old PKZip 1.x are not supported For uncompress .zip file, look at unzip.h I WAIT FEEDBACK at mail info@winimage.com Visit also http://www.winimage.com/zLibDll/unzip.html for evolution Condition of use and distribution are the same than zlib : This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Modified by Sergey A. Tachenov to integrate with Qt. */ /* for more info about .ZIP format, see http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip http://www.info-zip.org/pub/infozip/doc/ PkWare has also a specification at : ftp://ftp.pkware.com/probdesc.zip */ #ifndef _zip_H #define _zip_H #ifdef __cplusplus extern "C" { #endif #ifndef _ZLIB_H #include #endif #ifndef _ZLIBIOAPI_H #include "ioapi.h" #endif #if defined(STRICTZIP) || defined(STRICTZIPUNZIP) /* like the STRICT of WIN32, we define a pointer that cannot be converted from (void*) without cast */ typedef struct TagzipFile__ { int unused; } zipFile__; typedef zipFile__ *zipFile; #else typedef voidp zipFile; #endif #define ZIP_OK (0) #define ZIP_EOF (0) #define ZIP_ERRNO (Z_ERRNO) #define ZIP_PARAMERROR (-102) #define ZIP_BADZIPFILE (-103) #define ZIP_INTERNALERROR (-104) #define ZIP_WRITE_DATA_DESCRIPTOR 0x8u #ifndef DEF_MEM_LEVEL # if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 # else # define DEF_MEM_LEVEL MAX_MEM_LEVEL # endif #endif /* default memLevel */ /* tm_zip contain date/time info */ typedef struct tm_zip_s { uInt tm_sec; /* seconds after the minute - [0,59] */ uInt tm_min; /* minutes after the hour - [0,59] */ uInt tm_hour; /* hours since midnight - [0,23] */ uInt tm_mday; /* day of the month - [1,31] */ uInt tm_mon; /* months since January - [0,11] */ uInt tm_year; /* years - [1980..2044] */ } tm_zip; typedef struct { tm_zip tmz_date; /* date in understandable format */ uLong dosDate; /* if dos_date == 0, tmu_date is used */ /* uLong flag; */ /* general purpose bit flag 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ } zip_fileinfo; typedef const char* zipcharpc; #define APPEND_STATUS_CREATE (0) #define APPEND_STATUS_CREATEAFTER (1) #define APPEND_STATUS_ADDINZIP (2) extern zipFile ZEXPORT zipOpen OF((voidpf file, int append)); /* Create a zipfile. file is whatever the IO API accepts. For Qt IO API it's a pointer to QIODevice. For fopen() IO API it's a file name (const char*). if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip will be created at the end of the file. (useful if the file contain a self extractor code) if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will add files in existing zip (be sure you don't add file that doesn't exist) If the zipfile cannot be opened, the return value is NULL. Else, the return value is a zipFile Handle, usable with other function of this zip package. */ /* Note : there is no delete function into a zipfile. If you want delete file into a zipfile, you must open a zipfile, and create another Of couse, you can use RAW reading and writing to copy the file you did not want delte */ extern zipFile ZEXPORT zipOpen2 OF((voidpf file, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc_def)); extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level)); /* Open a file in the ZIP for writing. filename : the filename in zip (if NULL, '-' without quote will be used *zipfi contain supplemental information if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local contains the extrafield data the the local header if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global contains the extrafield data the the local header if comment != NULL, comment contain the comment string method contain the compression method (0 for store, Z_DEFLATED for deflate) level contain the level of compression (can be Z_DEFAULT_COMPRESSION) */ extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw)); /* Same than zipOpenNewFileInZip, except if raw=1, we write raw file */ extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCtypting)); /* Same than zipOpenNewFileInZip2, except windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 password : crypting password (NULL for no crypting) crcForCtypting : crc of file to compress (needed for crypting) */ extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, const void* buf, unsigned len)); /* Write data in the zipfile */ extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); /* Close the current file in the zipfile */ extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, uLong uncompressed_size, uLong crc32)); /* Close the current file in the zipfile, for fiel opened with parameter raw=1 in zipOpenNewFileInZip2 uncompressed_size and crc32 are value for the uncompressed size */ extern int ZEXPORT zipClose OF((zipFile file, const char* global_comment)); /* Close the zipfile */ /* Added by Sergey A. Tachenov to tweak zipping behaviour. */ extern int ZEXPORT zipSetFlags(zipFile file, unsigned flags); extern int ZEXPORT zipClearFlags(zipFile file, unsigned flags); #ifdef __cplusplus } #endif #endif /* _zip_H */ chessx-1.0.0/data/images/folder_grey.png000644 001750 001750 00000004440 12077036777 021020 0ustar00niklasniklas000000 000000 PNG  IHDRiCCPICC Profile(UoT?o\?US[IB*unS6mUo xB ISA$=t@hpS]Ƹ9w>5@WI`]5;V! A'@{N\..ƅG_!7suV$BlW=}i; F)A<.&Xax,38S(b׵*%31l #O-zQvaXOP5o6Zz&⻏^wkI/#&\%x/@{7S މjPh͔&mry>k7=ߪB#@fs_{덱п0-LZ~%Gpˈ{YXf^+_s-T>D@קƸ-9!r[2]3BcnCs?>*ԮeD|%4` :X2 pQSLPRaeyqĘ י5Fit )CdL$o$rpӶb>4+̹F_{Яki+x.+B.{L<۩ =UHcnf<>F ^e||pyv%b:iX'%8Iߔ? rw[vITVQN^dpYI"|#\cz[2M^S0[zIJ/HHȟ- Ic Adobe ImageReady zfIDAT8TKhW=GHűn VM]*] Z&q o -Utc( -dBmR()ӏ)),wH^ sμ7s!fƈAFQG}rUչeY_xR)[^yx29__KKK__\\J/ן<\̌o[[[̌ZoNoRjqOKLfEӴGkŋ+33sZ? 138:&LR7_|AZ9*0c=:jtO=3=.LrYJpcctԸay&3!3ۇ, 3MoUivyj=FRzQD]P(w޻cfA)'3 WoޯjNgf\.fN{!fA@D>w=O(W-I#Pѝ0f?`] |A{aR}ߟ /3[pEVkZVqឍ9<N۷pBP۽<03|.KFk˲4dYr\X,28B(/ TD$p@CDʍ3'MIENDB`chessx-1.0.0/src/database/enginelist.cpp000644 001750 001750 00000010001 12223260306 020775 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2010 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "enginelist.h" #include "settings.h" EngineList::EngineList() { } void EngineList::restoreEmptyFromPath(QString path, EngineData::EngineProtocol protocol) { if(path.isEmpty()) { return; } QStringList engines = QDir(path).entryList(QDir::Executable | QDir::Files | QDir::NoSymLinks); for(int i = 0; i < engines.size(); ++i) { QString key = QString::number(i); QString name = engines[i]; EngineData data(name); data.command = path + "/" + name; data.directory = path; data.protocol = protocol; append(data); } } void EngineList::restoreEmpty() { QString path(AppSettings->dataPath()); #ifdef Q_OS_WIN QString path1 = path + "/engines/uci"; QString path2 = path + "/engines/winboard"; #endif #ifdef Q_OS_MAC QString path1 = path + "/engines-mac/uci"; QString path2 = path + "/engines-mac/winboard"; #endif #ifdef Q_OS_LINUX QString path1 = path + "/engines-linux/uci"; QString path2 = path + "/engines-linux/winboard"; #endif restoreEmptyFromPath(path1, EngineData::UCI); restoreEmptyFromPath(path2, EngineData::WinBoard); } void EngineList::restore() { clear(); AppSettings->beginGroup("/Engines/"); QStringList engines = AppSettings->childGroups(); bool modified = false; if(engines.size()) { for(int i = 0; i < engines.size(); ++i) { QString key = QString::number(i); QString name = AppSettings->value(key + "/Name").toString(); EngineData data(name); data.command = AppSettings->value(key + "/Command").toString(); data.options = AppSettings->value(key + "/Options").toString(); data.directory = AppSettings->value(key + "/Directory").toString(); QString protocolName = AppSettings->value(key + "/Protocol").toString(); if(protocolName == "WinBoard") { data.protocol = EngineData::WinBoard; } else { data.protocol = EngineData::UCI; } AppSettings->getMap(key + "/OptionValues", data.m_optionValues); append(data); } } else { restoreEmpty(); modified = true; } AppSettings->endGroup(); if(modified) { save(); } } void EngineList::save() { AppSettings->beginGroup("/Engines/"); AppSettings->remove(""); // Clear group for(int i = 0; i < count(); ++i) { QString key = QString::number(i); AppSettings->setValue(key + "/Name", at(i).name); AppSettings->setValue(key + "/Command", at(i).command); if(!at(i).options.isEmpty()) { AppSettings->setValue(key + "/Options", at(i).options); } if(!at(i).directory.isEmpty()) { AppSettings->setValue(key + "/Directory", at(i).directory); } if(at(i).protocol == EngineData::WinBoard) { AppSettings->setValue(key + "/Protocol", "WinBoard"); } else { AppSettings->setValue(key + "/Protocol", "UCI"); } AppSettings->setMap(key + "/OptionValues", at(i).m_optionValues); } AppSettings->endGroup(); } QStringList EngineList::names() const { QStringList engineNames; for(int i = 0; i < count(); ++i) { engineNames.append(at(i).name); } return engineNames; } chessx-1.0.0/src/database/eventinfo.h000644 001750 001750 00000004136 12151705706 020322 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef EVENTINFO_H #define EVENTINFO_H #include "common.h" #include "partialdate.h" #include #include #include #include class Database; typedef QPair PlayerInfoListItem; typedef QList PlayerInfoList; class EventInfo { Q_DECLARE_TR_FUNCTIONS(EventInfo) public: EventInfo(); public: /** Set database and player. Automatically updates information. */ EventInfo(Database* db, const QString& player); /** Standard destructor. */ ~EventInfo(); /** Changes database. Does not automatically update statistics. */ void setDatabase(Database* db); /** Changes player. Does not automatically update statistics. */ void setName(const QString& player); /** @return current player name. */ QString name() const; /** Recalculates all statistics. */ void update(); /** @return string with formatted score statistics. */ QString formattedScore() const; /** @return string with formatted date range. */ QString formattedRange() const; /** @return string with formatted rating. */ QString formattedRating() const; /** @return string with formatted game count. */ QString formattedGameCount() const; /** @return string with list of players in the event */ QString listOfPlayers() const; private: /** Clears all statistics. */ void reset(); /** Add statistics for game @p */ void addGameStats(int index); QString m_name; Database* m_database; /** Format score statistics for single color. */ QString formattedScore(const int results[4], int count) const; int toResult(const QString& res) const; float toPoints(const QString& res) const; int m_result[4]; int m_count; int m_rating[2]; PlayerInfoList m_players; QHash m_games; PartialDate m_date[2]; }; #endif // EVENTINFO_H chessx-1.0.0/src/gui/playerlistwidget.cpp000644 001750 001750 00000012124 12223260306 021260 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #include "playerlistwidget.h" #include "ui_tagdetailwidget.h" #include "database.h" #include "databaseinfo.h" PlayerListWidget::PlayerListWidget(QWidget *parent) : QWidget(parent), ui(new Ui::TagDetailWidget) { setObjectName("PlayerListWidget"); ui->setupUi(this); m_filterModel = new QStringListModel(this); ui->tagList->setModel(m_filterModel); setObjectName("PlayerListWidget"); connect(ui->filterEdit, SIGNAL(textChanged(const QString&)), SLOT(findPlayers(const QString&))); connect(ui->filterDatabase, SIGNAL(clicked()), SLOT(filterSelectedPlayer())); connect(ui->renameItem, SIGNAL(clicked()), SLOT(renameSelectedPlayer())); connect(ui->tagList, SIGNAL(doubleClicked(const QModelIndex&)), SLOT(filterSelectedPlayer())); selectPlayer(QString()); QItemSelectionModel* selectionModel = ui->tagList->selectionModel(); connect(selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(selectionChangedSlot())); ui->detailText->setOpenLinks(false); connect(ui->detailText, SIGNAL(anchorClicked(QUrl)), SLOT(slotLinkClicked(QUrl))); slotReconfigure(); } PlayerListWidget::~PlayerListWidget() { delete ui; } void PlayerListWidget::slotReconfigure() { } void PlayerListWidget::selectionChangedSlot() { const QModelIndexList& selection = ui->tagList->selectionModel()->selectedIndexes(); if(selection.count()) { QString ts = selection[0].data().toString(); playerSelected(ts); } else { playerSelected(QString()); } } void PlayerListWidget::findPlayers(const QString& s) { if(s.isEmpty()) { m_filterModel->setStringList(m_list); } else { QStringList newList = m_list.filter(s, Qt::CaseInsensitive); m_filterModel->setStringList(newList); } } void PlayerListWidget::slotSelectPlayer(const QString& player) { m_filterModel->setStringList(m_list); ui->filterEdit->clear(); selectPlayer(player); } void PlayerListWidget::playerSelected(const QString& player) { if(!player.isEmpty()) { m_player.setName(player); ui->filterDatabase->setEnabled(true); ui->renameItem->setEnabled(true); QString head = "Player List"; QString text = QString("%1

%2

%3%4%5%6%7") .arg(head) .arg(m_player.name()).arg(m_player.formattedGameCount()) .arg(m_player.formattedRange()) .arg(m_player.formattedRating()) .arg(m_player.formattedScore()) .arg(m_player.listOfOpenings()); ui->detailText->setHtml(text); } else { ui->filterDatabase->setEnabled(false); ui->renameItem->setEnabled(false); ui->detailText->setText(tr("No player chosen.")); } } void PlayerListWidget::selectPlayer(const QString& player) { playerSelected(player); if(!player.isEmpty()) { const QStringList& list = m_filterModel->stringList(); int row = list.indexOf(player); if(row >= 0) { QModelIndex index = m_filterModel->index(row, 0); if(index.isValid()) { ui->tagList->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect); ui->tagList->scrollTo(index); } } } } void PlayerListWidget::filterSelectedPlayer() { const QModelIndexList& selection = ui->tagList->selectionModel()->selectedIndexes(); if(selection.count()) { QString ts = selection[0].data().toString(); emit filterRequest(ts); } } void PlayerListWidget::renameSelectedPlayer() { const QModelIndexList& selection = ui->tagList->selectionModel()->selectedIndexes(); if(selection.count()) { QString ts = selection[0].data().toString(); emit renameRequest(ts); } } void PlayerListWidget::setDatabase(DatabaseInfo* dbInfo) { Database* db = dbInfo->database(); ui->detailText->setText(tr("No player chosen.")); m_player.setDatabase(db); m_list.clear(); if(db && db->index()) { m_list = db->index()->playerNames(); } m_list.sort(); m_filterModel->setStringList(m_list); m_filterModel->sort(0); } void PlayerListWidget::slotLinkClicked(const QUrl& url) { if(url.scheme().startsWith("eco")) { QString player = ui->tagList->currentIndex().data().toString(); QString tag = (url.scheme().contains("white")) ? TagNameWhite : TagNameBlack; emit filterEcoPlayerRequest(tag, url.path(), player); } } chessx-1.0.0/src/gui/commentdialog.ui000644 001750 001750 00000007434 12212555374 020363 0ustar00niklasniklas000000 000000 CommentDialog 0 0 440 221 0 1 Edit Comment 12 true :/images/text_clear.png:/images/text_clear.png Elapsed time Clock time true QAbstractSpinBox::UpDownArrows H:mm:ss :/images/time_clear.png Qt::Horizontal Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok PlainTextEdit QPlainTextEdit
plaintextedit.h
buttonBox accepted() CommentDialog accept() 248 254 157 274 buttonBox rejected() CommentDialog reject() 316 260 286 274
chessx-1.0.0/data/images/chessx.xcf000644 001750 001750 00000134540 12046272240 017774 0ustar00niklasniklas000000 000000 gimp xcf fileBB icc-profile H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) icc-profile-name ICC Profile39<>Zwischenablage     $"<><>a&"voonqJ JFKğFaF^F^F^E^E^E]E]E]F[^B `A?aABaCBf  A@ AN  @N  @N@N  @N  @N  @M ?M@M?M?M?M?M?L>M?L>L>L >L>N>ob >4BEEDG>== '"  220a& nhggfhD EA،KA׌aA׌^A֋^AՋ^Aԋ^@Ԋ]@Ӊ]@҉]@щ]@шZW<Ј Y<χ=Z;·@Y=ԋ@]  ?ʯ; ?G  >G  >G=G  =F  =F  =F =E=E=E @Ї=ƀK=ŀa<^<^<~^<}];|];|\;˿{\:ʿ{\;ɽyZP7ȼy R7ǻx;R6ƺx>Q8˿z>U   =5  =@  <@  <@;?  ;>  ;>  :> :>:=:=9=9<9;9;8;8;8:7: 7:7<7UJ 6'14334665p }»jf}ü6" 220'  (Fʛ))    ;>1%    YTC2"z -.% vjU?+JC6) fL3 fZI80[SRX\`dfefe/& uW;! pZIk q>2&aB% kVsVE6' ƩeD& za| nZE2 ũeD% ƨlmU<%ũeD% ˫nsY@(ũeD% ϳ{oV>(ũeD% ־wydzr\IũeD% ũeD% ũeD%  ũeD%  @Ul ƩeD& *=Rfy aA%  /?O^kytV:  "-9CMYд~eK3 $+1;ö}hT>*  ϾsbRB1! íoVG<0$ ϷkT:.'  ȬqU;"  £aB%  ]<]= ]= ]= ]= ]= ]= ]= ]= ]= ]= ]= `@# ũiO2 _B' T8'gK6& z\D0 %mR:#  Ý}_C) ѭkK. ״qO1  ״qO0 ΫjK. |_C) 0H`y쳬kR:# ,?Tgy󄇏mYD/ "1AP^ktuurkda`_acfmtpcUE5% #.9CLSSTPJDB@@ACFLSQH=2&  $*0442-'%$$%&(.43.'      Zwischenablage#1     33}4Onj*0񴥭-*(飩&硬$娟#䶭!⹶ ᨹ२ުݥܴ۬ڢ٢صخ״ֵէըԺӟӣҞ꣦ꤸѯѦЮЩЦϦϝϤ β ί ί ά ͫ ͣ ͣ ͭ ʹ ͷ ͸ 믰䷭ ͭ Цw{oqwx~0|mtn{yu{}||~-whqyouq{vnyv~u*luxgv|rttuywm|x~(lsksyhqzqvsuxvrz|&ksmwrsypwzvvywyomt}}$qgetotzp~lr}wvstsljq}}{v#vqgxtv{rzmpqxuvruikky|ss!⃀{tnxr}uuxq~sww{slgmsqv t|udqowtxvttsv||uugut{ns}xzenswrytoq~sxxwqym~~}tmoqxr|qsttt{wrpytzwwuwp{xnphqm}~{rmqs~wszijxrys|rvs~~lonwi|xuwlro|pn}kfvovqupuru~ww}rqpsgvq|q{qrnrseuswstspt~~{lx}rtmpj}{yzyuvuron{qjvmytotsrzlsw}kurzlwqmgz{zswrntook{lfwmtvrqos}qlr}ozmxkrpjdxq{rwohtqok|pgzovzonus{ssmzyw~susvpmhxv~|vuhvqrkuigtmvwlkysr}sy}xq{rswxmibzpux{~zorpxhumbsswujltrvzoyvքymuhuxtnlcwku|stppyrfxvdvuxqisxsy{wuxu{uolfxzytonzjy~qrtl{pj{vdpsvpcwwn{|xuuxqkchy}rikly|pttmzsjyboqtqi{tm~upԈvzuqjesur{mnnktrseunzhpoqor}{lyxsukwnrshfqtnnqvqzrpoe~j{gmnuprwynz|mvno{qnzqonot|ophw~rqqromykwfkpuruxrlnsx}lhzsyetvtrmqsvqomz~|tsqspzjugtoupzuzkqj|{ymtu{i|wtluomvppx}yyqprnslzjonjuxwtlsu{wqstxlusbtrk{tqmu~mpboju|mzhrqowyrwnznri|wvsmbstoutlutqgrk{{n}ubqsmvzwus{}zvwqrezs|zoftzjwutpqzpoylzp}tiroiu}yurznvwrqpitxwdu{lvtnrswnoxj|u{vipqmv}{zw{xxooqnivseu~grxoqq~}vunjzu}uhoqqxzrw~wxnvnpnpa}~|p|rpxmltywmglopygopqp|mwvqtvyepnsbyzxjp{ylvpor}zwwiqrs}yfnrsv}xkxns{|l}rvaxyz|uonz|ixonu|xy{jq~x{|ftpsu|{j}s{u} ygxsuaqwnwyrgvmzptq{|~whm}resnxzzhy|ps~ udqmterylqsrorbtto|~gr|t{fsryy|ix{ymn~ vjssxgpqjksovpprtsr|woqvry~fyuut{xcryzsx vsz|xjoh~igopyj{rpnsi|ws~nowrt{frsqyxxkoy w|x{yfosjkmqr}xsnrll|up}|}nq{xt~ikmry}zfwxm{ mpzvqkxqyood~~opmrxwry|kyvysekvoyxwj{}rju lv|{jg}juwr`u}xlvsprvq{ixtzt{fkpqvtwlwvmtxx xsu{pjy{m~rf{ypmwrovvox{gxl}}wlmxozx{mwunssu ́}qqsqmk}lxwuhqztqlprtvpxzjwn{x{nivjyuvo{wopqr ͇zrslrtdzp|{sojxzxkulqxs{pt{mxuw}nkwty{vnttqmep ͆xqomkig|{|z|tnfv|ztsklvqu}qu~os~xnyquuwqpyvifz |yolmiokn|~nipltvmnrxsy|rsqqtwiqtzstqvyidy x{my|urpk~posn}oogntv~vxxhlvwutfqv}rpok~vpfn xupyryfpy{xlst}{vppfwy{pzih|{wvnpwytspkvqpfnORGKPOaY_\0UGMHRXQOTVWVYV-PDMRHNJRVLIRPXXWN*YFMQBPULMMNOOGURZXUX(HN^ELSBLSINLOPPKSVZZY&FMIR[JMPGQSNMRRSHHNW]ZUZ$JBANJM^QGUEJUQPKLMFFMYWTPZ#YQKAQNOeSHSEJKPNOJNBGHUWNM[!]XWUMHQNXeYO\NQJWMOPSLFCJOKNZ M^ZYVO@LLRa^LONNMWMPSUOPCQO[S`HMhZTQT?HMPg`HOLIJUMRPOLSGX_VU]NGHKeXOJUJLNLb[KQOLIRMRPONRKU[RY^IKBKF`UWSWLFKLeXPJSDDRJNKUJPNXa[ZXXFJHRCaURNXQFMHfVIFVF?NHLJOGLKO_ZXRRXLLJNBdYNJXUMWJ^KGI[N>OLOJLIIMZYXZUHSWMNHLEcVSTRSOROhNJFTLEPGRLGJMMTGMPUEQKTGPKIDdTTUMPMIOhMIBSGAQGONJHIMVKFLVWIUFSFMKF@bSKSMPJCOdJGDSJATGOQGFLMVKKESRQVJNKPLID]QOVTONBOaJKFODAMFNMDDQKJTKRWXQKTJLOQHF>TJNQTWSHJ_KSBPG;JMQNCDLKOSGQN\ZSHOANRMGF>RHNTYMMJI`RL?QPHKNK>NQIUW[RNN\UKF>A\QVNDEYGQXSIOPG_TLC^S=IILLCQOHXW[OIaOWPKD?MOITIIG\FWZXQMN@_XNH_SCKIKIKRSFSZRMMEcXTLLC@KNXHHIWNXLSOLJ@aWZEZUBHHPIJOQGRVHOGIUYNLSKJHJNUKJB\PVMKMMHF_R_EZRAEKNJMQJFHMRTDDTOTCQPOMHLMPMJFZSWXONMMH_S\DZPBMJOHQMSFLCUSRHLPXFXRPGNIFYRKJRUR\SMLLG^MZFYUEIIDLQONGNO[VSRJLMTG\PNLHPQSXCRTYKLV QALJP@XNTHLLKIL]MSXTKP PUWRFIBZFCLJVETKKILEXQLZ[YHJP`ZIMV@KMJOMOEJZ_YPW PUU]VTBKMaHFHLLWPLJNGGXNJWUXILV^[OLYEEHJORR@QW]QDS ILU[PKERZ\LSIL>XWVJJHLROMSU\GUQ\^OJZ>FRIOMLCTSKDM[ HJQUTDBV]^ENPN;NVRFNLJLONUZZDSN[]QLU?EKKNJLFPMFMOQ QSPNUJES[WIW\LATRLHQKIPNKSU]CSGWaTPZGHRHRNSHSNIMKM \XMKMJFE`ZHSQOBKRNLGJMOOKS[XFSJT`PT\HCQDQMPKWRILJJ aVNNHLN@]WLVULJEQSSFOGLPMS_NOUGRZMPXHCPLPSMHONMI?H `TMJJGEDWVWTVOIAOWVPMFG\P[dNPVKOWGKWRHRHLLKSPD@R WSJHIEJHJX\bYJDJG[OSJHK_RXaNSVLLYJIKOCJLRKIJQYRC>S VWKUVRMKE`Y]^KJMIXJKDHNXQX[PRRBG[MNON?HMUJHIEXQL@H TRM^TNRBIeU[TTHNOYVRJJB]PQ[VKTEC[TSRQHHPQLKJDPLLAHFn0'i.6 +t),',%$i"'!d 6FK F!6"#$%d&'&'i((),**,+++t,,6---'.i... / F/ n/ / / / / / / /4񮫳0-뱴*飴(窴&屴$䷳#⶯!ᯡ ਝඪݪܭ۳ڱ٩ة宲שܠմխԮӫӮԫҡѫѧҵеб϶ﶨⲭϳٴ Ω θ λ Ͷ ʹ ʹ ͯ ͳ ϴ ͳ ͸ ͭ 󳮤߫ v}sx}p4~zzt|r~n~wx|t0vuur{thww}~-뀁qmryrwj{w|yuky*q{mm}~vew}rkynqu{(yuvuv|w~vnr|tz&}r}~~xrt~s{uh$}||v~e~ytr}p|qnu#zr{qztpy~~|x{qwlrjj!}luntnqn~~pjrrwsmodu~ tg{txkpmp}w||~hpm~qqjzm_xuqpssyspilsy{tw~e~nwph{k~y{{|tuzyxqurn_sz{z}|lky|wm~s|rovu~yy~{ovporisz}wznnuyzwl||vwxxtpmۀyvwkzytyuv~xzq{wrp}zzlk{zw{opyu}untz}~yqpvvxyl|{wmvtustrjzux}osyvtntwv{ymisujyql|omnpuzvnisppzi}xwurtzlqorng{tmypk{lqjtrqsknmvtmx{xt|n~w~upmnlqe{{~{}vq{wjusmilbhdtuny~uruxwrvxtutfjlftv|vyswzt|tpopfllnlu}rnwsւ~vpqqjsj_rmxxou||ruwnhjnrjosr~}sqy}w~sՀ|qxtznphcqxwvvtjknhbdi^npqthwyzsm|kixyuxtusolgppsi|kmxtsi_eamqitwrm{ou~nqdytmx~jxnrqtnjjy}_t{quzlilqoszysvxxruvvluuzotzmtszzipmn~}ypaorhuxhoxsuzzuwsuuwtt{qzywsmx|vt}yu|x}{{}rlfutlomhzwstorprpwypsyrkwsqumkyw|p~}w{twr}zqiqhgopsmunlt{sqwhmyrktrtgtxrtyzq}x||yvoqproaknzdm{pmhwyqlhqwru|stvskskuyroor}vrjpmxoqYn{nnqmu{mxwoZt|}r~trsmjozs}sqotxror}q}jx_v}{qsmsxm~uev{z|vxpwquou||nxxwzbcy{z|mvz{{sslpolsyvxrosz{}wrwshr~tvvz{vb~x|iv{{~vqulea}hz|w~~{s{ysywyolvpyxzz{j|}{skwax}|}vw{pmfztxtςxz}vpxxprsyx~t~~|otuvunwkqwxw}|pqmxwxwr{|σtyp{}soiu|wxvuukultxtt~owvyutvyzzπ{z~uynhv~{zvwwsmrrknutoz{wttvtsl|{}n|΁zvzr}zxnmvwu||ourgyqenptvylvyopqpm{|s|v tzwl||sm}~vnoz}l{uuqw~vx}xjtutyuqzvy} ΄|y|z~~swwyty}csxp}vzwu~s}~|zhyvnovoytt~ Ή}}{}{z|rs}y{{cqz|j|~wsqmzs{z{hw{ukvn}zx ͂~zxzlz|tu{u~rrtwq{uz|psok{{x{e}{wi{w~~ ́|qsxz}t{pwjytnypvw~mzjn}xey{sgwwuyz ͂|jnuv~j~o}{rv}xxmzyyqzlx|eyxgw{|qv{v }yxjokyu|wxsyx~}sxs~u{yzjuv~~lzye{zx{zn ̓}phi~{|ylso{u}ts}uuwtviwynn}|}gy{ktuy ͇~tutvpnxy~l~gv{vpxol|ghzupqz~np~l~vnv }yo{xwy~|ubt{~nowulsfwnmuypk|z~}sx|dy}uw ̈́|s{|ngwxxxyqfltuqilkj{my||{t~x{]~z{ w~lwoohusuu~~phurpinmpvpt|~ozl|Xz}t vxylqovpjrt~~}tvryswdohlov}nqf|axw|j [X_QXOSWLX4UT]SNWLXJVPQTM0XPQOLTNZDX]QPVZUW-ZNHLQJQFT[Q[[\USNFW*JZTFHWWO@PVM^]Z\EQHNQT(QZVKOZYXNNUR[Z[]XYOJNTOU&WYZXY[XYTJV`\][V^WPNOXOVPA$_VVUYSXXW?V[^_Z[Z]RONWIWKGN#`TMTXJR\NJS\b]Z^]WVVTULRFNFGa!YGPIX[NGJHWZ[W[W[KEM\MTOHJ@NY[ OCWNPZDJGIX^QT\SWCKIYKMFUI9QO]XJZMKSKICGNUVM^OX@YLYPKDUGYTWVVMWNS\SQJMJI;MTVSWXUG]GRUQGYNZVMKQNVRRX[VJOIGKCM\SVP[RGeLNXRRGTVQRQQNKIXSRQFSRLPNPXQSK\TP_PLURTGDTTYQT]IJSMUNIOUVVQHHOPR]T\FUSSHQPPLMKDTNSYIJZQNMGNZQOSQGAMRET]KHWH[IIMPROGDNKKSAUQROYLNTXEMJLHBVOHS`LGVGLFOOLLFIHPOGPSQOVHY_QPYOIHHFK?TVWSWPJUQEPNHDF=C?LMHRVOLORS\JPSOON@BG@LOUPTLPYSOVMHHJAEFHGOUVKIQ[LbXZWQLKIALE:LHRSHMYUTLNOHBDHKEJNKWVJHRXRaWLWULSMREGC?MRWOM[PMZEDXJD<>C:JJKN@NQSOI`VECOSPSNOKJGALJXKX\DT\FHQNMD:@>HKDNPKGTIQYIL@QNHRXFTIMINHED\]S[XIMCOQEHTLNSSMPNMMPMPZ]MSRPLFRVOKWSOVQWTSVKDBNLFJGDSPNYMIMJKJPSJOWOGPNKNGESOT[IZW]_VOTNQMUZSJCKZCAIKNHPIFLTLKSDIVMDMLNBMOVLMSY[eUJWRVWSOHKJKI>GHU?ITKIAQQKGDMSNLUMNOLAJCMS^\`MGGJVQMCJGQHK6ISXGHKHPUGQPH6NWX\JWNLKHBGRNWa`[MHFMROLMWJUCQ;Q]VTJMHNSHYVN@P]\VSRWPRLPJMIOU_WGPSQT?BU`XSSTGQSUUMMFJJI\MRNQ]dLJXL\TUVRLOKBLWNPPVVZR>\bXWPVFPTTXOJNFA>WCTTOW_YXULVYTSNSQQJGQJVUTT[WFUWVMFP>TUSWOPUJHCTOYPN[`^X]QSXOJQPJKNTRZ[QXV_YKNOPOJPEKNPPUYUILIRQRPKVjaV_^NS[ITVMKCO\[_\`][ZXRSQPOFMFNPNMVZ\JSQSNOQQSaaUZYSTZOWZRIBQ^_`f\YYUVPPRNGLJFJMNIRSPO\NOOLFVTV]JXZRRVKUYRPGF`]_bPYOMUVHOLASJ@IIMN[PEQVJKJIGUTLWR[a MXURFTXTMGVb_^YP^GHTUDTOPOJQYPQV[WOCOPNRNKSOTZ[_` ]TRUTV]XMQS[S^OSX>N_RHWOSQMW^OXaUTSBTPHJPIQNQbX[c aUVSTXTSTLNXR\V^V?KTWEVXOLJGTM\`SSTCQUPGPGUSTc[\c [VYRQSFSVPPUYQ\`ZMKORLURTUJMJDU`SPUAVVRHVOW[Y]]Zc^ ZVMLQTVMUJRa^Fc^]SLJTK]QPWGTEH[`VPY@UWOD`PXPNSWSei [XFIRSWDWGWaVMdRZWTRRH]URRJSFQ]ZUZ[@U\SCaPTUJRUQif UTSGLGROUXPRMTbSaUUNRMYQT\PRDOWNWU_FWSRA\V[SRXUIf_ ZV^KDFYTVSFMIVcZ]OVNXLWONQMPERRGWW\IWVWB]TWE^RRSeb _ZWNQZNNIFQRXb^ZGWZ[BOTPJPKLW@ASNJKUY[IcKYFXRKQ`^ ]\W]QZ\JTRORWVZXOXUHMSEKFQGQLALZ[QI \RJFRJKFGP\NSNTEOXTVTH?DSSTd[OPDSUPKKIJGLGSNBOSWMK YJLSMMKCE]MRMQ@GX[U[QIDRTZ^SKLJS]VNMLIJMKPOIIQXVX S[ONLTHI@FQOZSN?BVaWRWR>QU]ZVOOX^SJKLLRQPSPGORSSY TcRPHIFNBJQJNYQDLI\YQPR;MV_QLONLY[UMGPOPNNTMEM[TO_ SbRINPAKIJROWZJCMMXXPSOEN_OGKISSUO[KHDETXSL?GLPMNSQERVRRC^OOJVBHU`NDIF\\[R^OMBCWXQPFIMPRQMOIPVRSQPMHQLW_YVHKET]]R]QNBFRVWPHHNJMUPMMOVLPTIOAIGTbSMHKEU_\Y[OPNESSRPCHKNONONOPKL@USLHIS\RNJKG\][_]OMOIVZQSEGNNSYLNOLCDH]NFLN\XROECY]UaYRONLRZNRGGIETSJILMBHP_KII\_TOIC]c]XWPKQNKWRXFPJBUMJJNIJPWMK]\UOIB^`Y\ZQHOQKYW]HNGBSJGIKNDQQUGZ[SLLB[\Y[XQFJMQYT[LQHBPHGIJOFTPXZYROLB]^[[VXRMIR^VVPVCCOIIKJJKUW]SNHCU^WWYWSYEUbN\TRCGSIKPBORUVY KMESaMZRRUYGWaHNOVFHQJFKDNQPY_!PIQcH\FPQ[DUeNQTVCHQKFJHMZ[T^#T^JVKRQWFTeOSWSDDRLFOPO\TRa$_PTOOTRDQePPTSHFQPGIRTXJR^&QMUSSEObUMNTGENO?COXSKZT(ZNGP[PLJKJGXLKDJMGLUL*JDS`PLHIMJUOJ@KTLPXL-[OIFFQORUIAITSPOM0KANPQRQCNTQNFL4QPRCNNSFFL / / / / / / / n/ F/ /..i.'.--6-,t,++,+*,*)(i(''&d&%$#6"F!K F6 !d"'$i%',),+t.6 1'i5Fnͦ О 﫞ග ͯ Ͱ ͱ ͱ ͵ ͸ ͵ δ η η β ϲ϶ϲЮЮүѧѮҤҦӢӣԮգ՝ڡ׬دسٺڻ۵ܸݻ޺පḱ ⷬ!买#庯$絷&뺣(뱶*-񫪫0nqusrsxoglqz|y{woxvntgm^pmvyz{o||tpyu fnnpluovpe|u}s}zw}|gmqefkgagdwzxwv|}yuvyql vggfprtjnnrq}}|zxwv~dkvmpqganaio{}lvsz{xymt~ zokivvyqqrls{~oxnsnuoluitojkodhhtp^bpmozvxsfzu}|y yut~qouxrkmr{}xmqtlm^ipfswljlWkqikpjfbmlvyfgyo}yfs zx|{q}{~mftqt}piqrdi[llonklic]nlmrrkheoq~n{fw|xkr {~xt~u~khxxvzrojsjlokfmriadijmltpevndvuqptlvv}wz ̀trxlstwq{qpg}snrnpjltmhkrrnqmpzltohopstojq}}~ ̈́q~x|}qvzntmovvkdmmirpnjhvtmwwmntmmvklcpqoyxt ̓{sw~t}rzry{wrm{lihsnkapx`dy|{iqjqynwsncnnpxxr ΃y~w|~twpgvkorurragte]zoannvwz~xxtznwnx 释vy~pzu|vpxsqmvvkopk`tyzyny|xzvyx|url ҆xq}j|q}z}{szj~uyotlociz~m|{xzm~swwm }|pzovtws|jvfryitgrmm}|~s{|}}n |vmy{vnuy~lzlhgzsskujwmm|r||~}|~olwwe{{vqso|nophsifnwfkynwy}z{~yvr}rh|{worsjporrbaofcnwtuxxy~yw~p{~x}|trum{x|y}{lon~b_nwihvxwz}pjy|xrk{vqzuu{s{ps}vqz|vz`uzr`orvyx{yuzoyr}ryzb}jrztsur|t~}}q}ywa}{~n{qs{txlungoyxskz|r||txquty~r~~s|qsow|y~vpptt{|yw}~ypu{snyzymnyzz}|zyxcndhvmx~o~t{xpnknrvu|ribkvyi||wejuovsonfav~~zvzrpxhqxyrnmphvtz|mWstjZgqlrqnrjcz}}{zz{e~{mqnomtltipsrqqtvnflchapyoqbmqpj|w}s{lwumtpshsnsspqjsurwzw`gn~t{utgqjlslt}u}~zvqlqxzumoywptjpru{{xtesytwoyuxkfaaoxzpo{ury}lppqplutsauyr{yy{vsdop}uxonkexz~}nq{lgrsipmpvlbrztx~|ywl`cywpwwz{rutqlos{ygjpymwvogdglz|{o}wsxokct|fyqqt}vsllsxwvxuxwxqstlemqrw~~|nrooehlpuyskwypltyzruy{|whtvnjqq}}u|plqlarwqeot~tj}zqxzuy}}~qypqrxrvyrxnpkjjktmjzstokpqzrwxtنxv|gmvvsnx|wtwnrmntcxukqfh\]zgqysډxpwtnmthox~v}zrmjtxjrrsskmldyv{pۅ~xortuom`{us|xwknlvfvwrynjokyy}{q܇{~t|zde{o}x|{jgniohvteogrvovzn݊nqdf}uozwxlfpujz}ooivuxqm|yއ~xs`iz{}myjmyxo{ssx_r{zo|v}uajv~}l|ot}t~orzhozsk}~hpeoz{}}|ut~ln{hn}} y|ri^u}|uvqx|nnorx!uwxdfytsumy{rtxt#}wvucoy{st}sp}~mqx$瀅qwltlv}x|tqk}nu&郅kzizv||~tln}(}|u~{qwyqzlx*ysu|vl}x}~-uvw|szzsb~~{~0innomrvkd{GJNKKMQZJCFMTUX[PZS\QIROGNAH;KHOUPYSTIXY\TULLTXMdc @JIIGNHPK@VOWN^VQMUWDIZLAAFD>E@QRPYONTUQOPQJG\]]b` PBC?ILMDHGLKVVWSQOOYAGRGJKC>K=CHUYVFOYLQTQRFOXYa\Y TIFALNTKKMGMVWIQGJGPJGOBMKDGK?BANJ9=JIJRPRM@SOUXTQ RONYKIOQIEGLTURGIKEH;DJ@MPFEF2ELCDID@=GGOR@ARHURAM TRVVKVUWH@NJNUIBHJ>E8HGIGGHD>8IFGKJFC@HKWGU@QWVQFL T[VQMZOXDARQORIICJCHKFAFLF=AFFGEMK?PJ>MNJIXNFPNTPR X]`_aPLQEKMPLSJJ@SKFKGJEGOHDGMLGJGKTGMGBFHLNIEJVV ]^Y^bLW[QSXLPTHMGGNPE>GHBMMHDBOMFOPEHNFGOBE=KJHRPM [UMTZOXWUIZULRUPLGSFDBNHE;KR;>RWTSCKELSGPJGFR[^\[RBSWQ@EOHOMHIA[USFKIIHMGMDHNMKLNPIBG>C=KTIKBFTVSHUZOLRHF>NVARMNOVOMGFLTPPR^ORQRKNNF?GJKP\WVUHLJI@CEINQNIRTIDZNSVLORSYXTBNOGBJJVVNVIGLF?MQL@HLVOEXTJPZSOTXVW\]KRIJJQLOQLQFIEEGGPJFTMLHGKLTKPXXRO[ab]TPWBFQQMGQUQNQGMIHO@TNGI@E9:UAJYZSMcXSKRNHFNCHQWOUXSJIGQTFLKNKEHHA[QO\SJ_YSKMNMHH;TNYLaVQNEKIRCQSOSJEJESQTTJaWXMW]T@?UJVR[UTCAIDLDPNAJDNPIO[SGei\ZH\XL@AXOHS\OQHAJODUXJKCPPRKFTTa^ZXQ]bOEXOZXYGUHMWNXILTXDKUKE^VW\B`^LAHTT^X_V[ZTNOXFH_SBIXV _TWYL_[E:NWV]P_e][NMSUHHYWGMS!bZ\OSfS?CUZN[MZ`^YMITTLOZQL#aV\PO`Q?KRUNZMV``\MLXXGJWQ$Y\aLQ^FNGMURUL^_afLFWZIN&\_`FSYDTOSTYVL]abeHIXW(W[YNVUKRRXJ`YSZ__ZHS*RM_[M\UPGWR\VYW^\-PQSWMUSMV0 0 0 0 0 0 0 0n 0F 0 / / /i /' ...6--t,,,,++,*))i('''d&%$#6"F!K F6d '!i#$,&,(t* Ԉ6- ߧi'0ʱnF@@ Neue Ebene     8Pxlkry6 1 .+)'%#"  "#$%&''()**+,,--..//000 1 1 1 2 2 2 2 3 3 3 3 3 3 3 3 3 36 1 .+)'%#"  "#$%&''()**+,,--..//000 1 1 1 2 2 2 2 3 3 3 3 3 3 3 3 3 36 1 .+)'%#"  "#$%&''()**+,,--..//000 1 1 1 2 2 2 2 3 3 3 3 3 3 3 3 3 36!Mt09y.R +9)['e%W#/"~ /e ! *!*"!# $%&e'/'(~)/**W++e,,[--9... R/ / / 90 y0 0 0 !1 M1 t1 1 1 1 1 1 1 1 5 1.+)'%#"  "#$%&''()**+,,--..//0001 1 1 2 2 2 2 3 3 3 3 3 3 3 3 3 3  5 1.+)'%#"  "#$%&''()**+,,--..//0001 1 1 2 2 2 2 3 3 3 3 3 3 3 3 3 3  5 1.+)'%#"  "#$%&''()**+,,--..//0001 1 1 2 2 2 2 3 3 3 3 3 3 3 3 3 3 ̴tM!4 y90 R-9*[(e&W$/"~!/e !!"*#*$!% &'(e(/)*~+/+,W,-e-.[./9 / / 0R 0 0 19 1y 1 1 2! 2M 2t 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 2 2 2 2 1 1 1000//..--,,+**)(''&%$#"  "#%')+.1 5  3 3 3 3 3 3 3 3 3 3 2 2 2 2 1 1 1000//..--,,+**)(''&%$#"  "#%')+.1 5  3 3 3 3 3 3 3 3 3 3 2 2 2 2 1 1 1000//..--,,+**)(''&%$#"  "#%')+.1 5  1 1 1 1 1 1 1 t1 M1 !1 0 0 y0 90 / / R/..9.-[-,e,+W+*/*~)(/'e'&% $!#*"*!!  e /"~#/%W'e)[+9.R 19y5!Mt3 3 3 3 3 3 3 3 3 3 2 2 2 2 1 1 1 000//..--,,+**)(''&%$#"  "#%')+. 1 63 3 3 3 3 3 3 3 3 3 2 2 2 2 1 1 1 000//..--,,+**)(''&%$#"  "#%')+. 1 63 3 3 3 3 3 3 3 3 3 2 2 2 2 1 1 1 000//..--,,+**)(''&%$#"  "#%')+. 1 62 2 2 2 2 2 2 2t 2M 2! 1 1 1y 19 0 0 0R / / /9 ..[--e,,W++/*~)(/(e'&% $!#*"*!! e/~!/"W$e&[(9* R- y90̴tM!5@@ Auswahlmaske T,@6!Mt09y.R +9)['e%W#/"~ /e ! *!*"!# $%&e'/'(~)/**W++e,,[--9... R/ / / 90 y0 0 0 !1 M1 t1 1 1 1 1 1 1 1̴tM!4 y90 R-9*[(e&W$/"~!/e !!"*#*$!% &'(e(/)*~+/+,W,-e-.[./9 / / 0R 0 0 19 1y 1 1 2! 2M 2t 2 2 2 2 2 2 2 1 1 1 1 1 1 1 t1 M1 !1 0 0 y0 90 / / R/..9.-[-,e,+W+*/*~)(/'e'&% $!#*"*!!  e /"~#/%W'e)[+9.R 19y5!Mt2 2 2 2 2 2 2 2t 2M 2! 1 1 1y 19 0 0 0R / / /9 ..[--e,,W++/*~)(/(e'&% $!#*"*!! e/~!/"W$e&[(9* R- y90̴tM!5@@chessx-1.0.0/src/gui/engineoptionmodel.h000644 001750 001750 00000002727 12223260306 021060 0ustar00niklasniklas000000 000000 /**************************************************************************** * Copyright (C) 2012 by Jens Nissen jens-chessx@gmx.net * ****************************************************************************/ #ifndef ENGINEOPTIONMODEL_H #define ENGINEOPTIONMODEL_H #include #include #include "engineoptiondata.h" class EngineOptionModel : public QStandardItemModel { Q_OBJECT public: explicit EngineOptionModel(QObject *parent = 0); public: virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; virtual QModelIndex parent(const QModelIndex &child) const; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; virtual bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole); public: virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; OptionValueList* m_pValueMap; const QList* m_pOptionDataList; void resetModel(); QStringList getSelections(const QModelIndex& index); protected: QStringList m_columnNames; }; #endif // ENGINEOPTIONMODEL_H chessx-1.0.0/src/gui/boardsetup.cpp000644 001750 001750 00000037056 12224734662 020063 0ustar00niklasniklas000000 000000 /*************************************************************************** boardsetup.cpp - Board setup dialog ------------------- begin : copyright : (C) 2005 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "boardsetup.h" #include "boardview.h" #include "messagedialog.h" #include "settings.h" #include "boardsetuptoolbutton.h" #include #include BoardSetupDialog::BoardSetupDialog(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f), m_wheelCurrentDelta(0), m_selectedPiece(Empty),inDrag(false) { setObjectName("BoardSetupDialog"); ui.setupUi(this); ui.boardView->configure(); ui.boardView->setFlags(BoardView::IgnoreSideToMove | BoardView::SuppressGuessMove | BoardView::AllowCopyPiece); ui.boardView->showMoveIndicator(false); m_minDeltaWheel = AppSettings->getValue("/Board/minWheelCount").toInt(); for(int piece = Empty; piece <= BlackPawn; piece++) { BoardSetupToolButton* button = new BoardSetupToolButton(this); button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); //button->setAlignment(Qt::AlignJustify|Qt::AlignVCenter); button->setMinimumSize(QSize(10, 10)); button->m_piece = (Piece)piece; if(piece == Empty) { button->m_pixmap = QPixmap(0, 0); ui.buttonLayout->addWidget(button, 6, 0); } else { button->m_pixmap = ui.boardView->theme().piece(Piece(piece)); ui.buttonLayout->addWidget(button, (piece - 1) % 6, piece >= BlackKing); } connect(button, SIGNAL(signalDragStarted(QWidget*, QMouseEvent*)), this, SLOT(startDrag(QWidget*, QMouseEvent*))); connect(button, SIGNAL(signalClicked(Piece)), this, SLOT(labelClicked(Piece))); connect(this, SIGNAL(signalClearBackground(Piece)), button, SLOT(slotClearBackground(Piece))); } emit signalClearBackground(Empty); connect(ui.okButton, SIGNAL(clicked()), SLOT(slotAccept())); connect(ui.cancelButton, SIGNAL(clicked()), SLOT(reject())); connect(ui.clearButton, SIGNAL(clicked()), SLOT(slotClear())); connect(ui.resetButton, SIGNAL(clicked()), SLOT(slotReset())); connect(ui.boardView, SIGNAL(clicked(Square, int, QPoint, Square)), SLOT(slotSelected(Square, int))); connect(ui.boardView, SIGNAL(moveMade(Square, Square, int)), SLOT(slotMovePiece(Square, Square))); connect(ui.boardView, SIGNAL(copyPiece(Square, Square)), SLOT(slotCopyPiece(Square, Square))); connect(ui.boardView, SIGNAL(invalidMove(Square)), SLOT(slotInvalidMove(Square))); connect(ui.boardView, SIGNAL(wheelScrolled(int)), SLOT(slotChangePiece(int))); connect(ui.boardView, SIGNAL(pieceDropped(Square, Piece)), SLOT(slotDroppedPiece(Square, Piece))); connect(ui.toMoveButton, SIGNAL(clicked()), SLOT(slotToggleSide())); connect(ui.wkCastleCheck, SIGNAL(stateChanged(int)), SLOT(slotCastlingRights())); connect(ui.wqCastleCheck, SIGNAL(stateChanged(int)), SLOT(slotCastlingRights())); connect(ui.bkCastleCheck, SIGNAL(stateChanged(int)), SLOT(slotCastlingRights())); connect(ui.bqCastleCheck, SIGNAL(stateChanged(int)), SLOT(slotCastlingRights())); connect(ui.epCombo, SIGNAL(currentIndexChanged(int)), SLOT(slotEnPassantSquare())); connect(ui.halfmoveSpin, SIGNAL(valueChanged(int)), SLOT(slotHalfmoveClock())); connect(ui.moveSpin, SIGNAL(valueChanged(int)), SLOT(slotMoveNumber())); connect(ui.copyButton, SIGNAL(clicked()), SLOT(slotCopyFen())); connect(ui.pasteButton, SIGNAL(clicked()), SLOT(slotPasteFen())); connect(ui.btCopyText, SIGNAL(clicked()), SLOT(slotCopyText())); connect(ui.btFlipBoard, SIGNAL(clicked()), ui.boardView, SLOT(flip())); ui.btFlipBoard->setCheckable(true); connect(ui.btFlipVertical, SIGNAL(clicked()), SLOT(mirrorVertical())); connect(ui.btFlipHorizontal, SIGNAL(clicked()), SLOT(mirrorHorizontal())); connect(ui.btSwapColor, SIGNAL(clicked()), SLOT(swapColors())); ui.tabWidget->setCurrentIndex(0); } BoardSetupDialog::~BoardSetupDialog() {} Board BoardSetupDialog::board() const { Board b = ui.boardView->board(); return b; } void BoardSetupDialog::mirrorVertical() { QString fen = board().toFen(); QString fenRows = fen.left(fen.indexOf(" ")); QStringList rows = fenRows.split("/"); std::reverse(rows.begin(), rows.end()); QString newFen = rows.join("/"); Board b(newFen); b.setMoveNumber(board().moveNumber()); b.setHalfMoveClock(board().halfMoveClock()); setBoard(b); } void BoardSetupDialog::mirrorHorizontal() { QString fen = board().toFen(); QString fenRows = fen.left(fen.indexOf(" ")); QStringList rows = fenRows.split("/"); for(QStringList::Iterator iter = rows.begin(); iter != rows.end(); ++iter) { std::reverse((*iter).begin(), (*iter).end()); } QString newFen = rows.join("/"); Board b(newFen); b.setMoveNumber(board().moveNumber()); b.setHalfMoveClock(board().halfMoveClock()); setBoard(b); } void BoardSetupDialog::swapColors() { QString fen = board().toFen(); QString fenRows = fen.left(fen.indexOf(" ")); QStringList rows = fenRows.split("/"); for(QStringList::Iterator iter = rows.begin(); iter != rows.end(); ++iter) { QString& fenString = (*iter); for(QString::Iterator pChar = fenString.begin(); pChar != fenString.end(); ++pChar) { if(*pChar >= 'a' && *pChar <= 'z') { (*pChar) = (*pChar).toUpper(); } else if(*pChar >= 'A' && *pChar <= 'Z') { (*pChar) = (*pChar).toLower(); } } } QString newFen = rows.join("/"); Board b(newFen); b.setMoveNumber(board().moveNumber()); b.setHalfMoveClock(board().halfMoveClock()); setBoard(b); } void BoardSetupDialog::setFlipped(bool flipped) { ui.boardView->setFlipped(flipped); } void BoardSetupDialog::setBoard(const Board& b) { ui.boardView->setBoard(b); ui.moveSpin->setValue(b.moveNumber()); ui.halfmoveSpin->setValue(b.halfMoveClock()); if(b.enPassantSquare() == NoEPSquare) { ui.epCombo->setCurrentIndex(0); } else if(b.toMove() == White && b.pieceAt(b.enPassantSquare() - 8) == BlackPawn && b.pieceAt(b.enPassantSquare()) == Empty && b.pieceAt(b.enPassantSquare() + 8) == Empty) { ui.epCombo->setCurrentIndex(b.enPassantSquare() % 8 + 1); } else if(b.toMove() == Black && b.pieceAt(b.enPassantSquare() + 8) == WhitePawn && b.pieceAt(b.enPassantSquare()) == Empty && b.pieceAt(b.enPassantSquare() - 8) == Empty) { ui.epCombo->setCurrentIndex(b.enPassantSquare() % 8 + 1); } else { ui.epCombo->setCurrentIndex(0); } ui.wkCastleCheck->setChecked(b.castlingRights() & WhiteKingside); ui.wqCastleCheck->setChecked(b.castlingRights() & WhiteQueenside); ui.bkCastleCheck->setChecked(b.castlingRights() & BlackKingside); ui.bqCastleCheck->setChecked(b.castlingRights() & BlackQueenside); m_toMove = b.toMove(); showSideToMove(); setStatusMessage(); } void BoardSetupDialog::showEvent(QShowEvent *e) { QDialog::showEvent(e); adjustSize(); } void BoardSetupDialog::slotReset() { Board b; b.setStandardPosition(); setBoard(b); } void BoardSetupDialog::slotAccept() { // Need to make sure the board is updated with move number set by user Board b(ui.boardView->board()); b.setMoveNumber(ui.moveSpin->value()); ui.boardView->setBoard(b); QString reason = boardStatusMessage(); if(reason.isEmpty()) { accept(); } else { MessageDialog::error(tr("Current position is not valid.\n\n%1.").arg(reason)); } } void BoardSetupDialog::slotClear() { Board b; b.setAt(e1, WhiteKing); b.setAt(e8, BlackKing); setBoard(b); } void BoardSetupDialog::slotSelected(Square square, int button) { Piece piece = (button & Qt::MidButton) ? Empty : m_selectedPiece; if(button & Qt::RightButton) { if(piece >= BlackKing) { piece = (Piece)(piece - (BlackKing - WhiteKing)); } else if(piece != Empty) { piece = (Piece)(piece + (BlackKing - WhiteKing)); } } Board board = ui.boardView->board(); if(board.pieceAt(square) == piece) { piece = Empty; } board.setAt(square, piece); setBoard(board); } void BoardSetupDialog::showSideToMove() { QSize size = ui.toMoveButton->iconSize(); QPixmap pixmap(size); QPainter painter(&pixmap); painter.fillRect(0, 0, size.width(), size.height(), m_toMove == White ? Qt::black : Qt::white); painter.fillRect(1, 1, size.width() - 2, size.height() - 2, m_toMove == White ? Qt::white : Qt::black); ui.toMoveButton->setIcon(QIcon(pixmap)); } void BoardSetupDialog::slotToggleSide() { m_toMove = oppositeColor(m_toMove); Board b = ui.boardView->board(); b.setToMove(m_toMove); setBoard(b); } void BoardSetupDialog::slotChangePiece(int dir) { int i = m_selectedPiece; i += (dir == BoardView::WheelUp) ? -1 : 1; if(i < 0) { i = (int) BlackPawn; } else if(i > BlackPawn) { i = (int) Empty; } m_selectedPiece = (Piece) i; emit signalClearBackground(m_selectedPiece); } void BoardSetupDialog::slotDroppedPiece(Square s, Piece p) { Board b = ui.boardView->board(); b.setAt(s, p); setBoard(b); } void BoardSetupDialog::slotMovePiece(Square from, Square to) { Board b = ui.boardView->board(); Piece p = b.pieceAt(from); b.removeFrom(from); b.setAt(to, p); setBoard(b); } void BoardSetupDialog::slotCopyPiece(Square from, Square to) { Board b = ui.boardView->board(); Piece p = b.pieceAt(from); b.setAt(to, p); setBoard(b); } void BoardSetupDialog::slotInvalidMove(Square from) { Board b = ui.boardView->board(); Piece p = b.pieceAt(from); if(pieceType(p) != King) { b.removeFrom(from); setBoard(b); } } void BoardSetupDialog::wheelEvent(QWheelEvent* e) { m_wheelCurrentDelta += e->delta(); if(abs(m_wheelCurrentDelta) > m_minDeltaWheel) { slotChangePiece(m_wheelCurrentDelta < 0 ? BoardView::WheelDown : BoardView::WheelUp); m_wheelCurrentDelta = 0; } } QString BoardSetupDialog::boardStatusMessage() const { switch(ui.boardView->board().validate()) { case Valid: return QString(); case NoWhiteKing: return tr("No white king"); case NoBlackKing: return tr("No black king"); case DoubleCheck: return tr("Both kings are in check"); case OppositeCheck: return tr("Side to move has opponent in check already"); case TooManyBlackPawns: return tr("Black has too many pawns"); case TooManyWhitePawns: return tr("White has too many pawns"); case PawnsOn18: return tr("There are pawns on the first or eighth rank"); case TooManyKings: return tr("Too many kings"); case TooManyBlack: return tr("Too many black pieces"); case TooManyWhite: return tr("Too many white pieces"); case BadCastlingRights: return tr("Bad castling rights"); case InvalidEnPassant: return tr("En passant square is not correct"); default: return tr("Unknown reason"); } } void BoardSetupDialog::setStatusMessage() { QString reason = boardStatusMessage(); ui.okButton->setEnabled(reason.isEmpty()); ui.copyButton->setEnabled(reason.isEmpty()); ui.btCopyText->setEnabled(reason.isEmpty()); if(reason.isEmpty()) { ui.fenLabel->setText(ui.boardView->board().toFen()); ui.humanFEN->setText(ui.boardView->board().toHumanFen()); } else { ui.fenLabel->setText(tr("Illegal position: %1").arg(reason)); ui.humanFEN->setText(""); } } void BoardSetupDialog::slotCopyFen() { QApplication::clipboard()->setText(ui.boardView->board().toFen()); } void BoardSetupDialog::slotCopyText() { QApplication::clipboard()->setText(ui.boardView->board().toHumanFen()); } void BoardSetupDialog::slotPasteFen() { // Prepare Fen - clean up code like this: // [FEN "***"] to *** QString fen = QApplication::clipboard()->text().simplified(); if(fen.contains("\"")) { int n1 = fen.indexOf('"'); int n2 = fen.lastIndexOf('"'); if(n2 > n1 + 1) { fen = fen.mid(n1 + 1, n2 - n1 - 1); } } // Another go at Fens copied from Wikis: [FEN]***[/FEN] is reduced to *** fen.remove(QRegExp("\\[[^\\]]*\\]")); // Now parse the hopefully naked Fen Board b; if(!b.fromFen(fen)) { QString msg = fen.length() ? tr("Text in clipboard does not represent valid FEN:
%1").arg(fen) : tr("There is no text in clipboard."); MessageDialog::warning(msg); } else { setBoard(b); } } void BoardSetupDialog::slotCastlingRights() { Board b(board()); CastlingRights cr = 0; if(ui.wkCastleCheck->isChecked()) // && b.pieceAt(4) == WhiteKing && b.pieceAt(7) == WhiteRook) { cr += WhiteKingside; } if(ui.wqCastleCheck->isChecked()) // && b.pieceAt(4) == WhiteKing && b.pieceAt(0) == WhiteRook) { cr += WhiteQueenside; } if(ui.bkCastleCheck->isChecked()) // && b.pieceAt(60) == BlackKing && b.pieceAt(63) == BlackRook) { cr += BlackKingside; } if(ui.bqCastleCheck->isChecked()) // && b.pieceAt(60) == BlackKing && b.pieceAt(56) == BlackRook) { cr += BlackQueenside; } b.setCastlingRights(cr); setBoard(b); } void BoardSetupDialog::slotEnPassantSquare() { Board b(board()); if(ui.epCombo->currentIndex() == 0) { b.clearEnPassantSquare(); } else { int shift = b.toMove() == White ? 39 : 15; b.setEnPassantSquare(shift + ui.epCombo->currentIndex()); } setBoard(b); } void BoardSetupDialog::slotHalfmoveClock() { Board b(board()); b.setHalfMoveClock(ui.halfmoveSpin->value()); setBoard(b); } void BoardSetupDialog::slotMoveNumber() { Board b(board()); b.setMoveNumber(ui.moveSpin->value()); setBoard(b); } void BoardSetupDialog::startDrag(QWidget* w, QMouseEvent* event) { if (inDrag) { return; } BoardSetupToolButton *child = qobject_cast(w); if(!child) { return; } Piece p = child->m_piece; QPoint hotSpot = event->pos(); BoardViewMimeData *mimeData = new BoardViewMimeData; mimeData->m_piece = p; QPixmap pixmap = *child->pixmap(); QDrag* pDrag = new QDrag(this); pDrag->setMimeData(mimeData); pDrag->setPixmap(pixmap); pDrag->setHotSpot(hotSpot); inDrag = true; pDrag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction); inDrag = false; } void BoardSetupDialog::labelClicked(Piece p) { m_selectedPiece = p; emit signalClearBackground(m_selectedPiece); } chessx-1.0.0/src/gui/boardsetup.h000644 001750 001750 00000007575 12224734662 017533 0ustar00niklasniklas000000 000000 /*************************************************************************** boardsetup.h - Board setup dialog ------------------- begin : Mon 14 Nov 2005 copyright : (C) 2005 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef __BOARDSETUPDIALOG_H__ #define __BOARDSETUPDIALOG_H__ #include "ui_boardsetup.h" #include "board.h" #include "common.h" class QMenu; class QAction; class QActionGroup; /** @ingroup GUI The BoardSetupDialog class represents a dialog for setting up a position. */ class BoardSetupDialog : public QDialog { Q_OBJECT public: /** Create ChessX Preferences dialog */ BoardSetupDialog(QWidget* parent = 0, Qt::WindowFlags f = 0); /** Destroy the dialog */ virtual ~BoardSetupDialog(); /** Set current board */ void setBoard(const Board& b); /** Set current board */ void setFlipped(bool flipped); /** Return current board */ Board board() const; protected: /** Resize board upon showing it the first time */ virtual void showEvent(QShowEvent *e); /** Scroll current piece with a wheel */ virtual void wheelEvent(QWheelEvent* e); protected: /** Display side to move */ void showSideToMove(); /** Message for incorrect setups. Returns empty string if the position is correct. */ QString boardStatusMessage() const; /** Sets status message for the board (either fen or error message). */ void setStatusMessage(); public slots: /** Start a drag operation */ void startDrag(QWidget* w, QMouseEvent* event); /** A Piece was clicked */ void labelClicked(Piece p); void mirrorVertical(); void mirrorHorizontal(); void swapColors(); signals: /** Request to clear the background of a piece label */ void signalClearBackground(Piece p); private slots: /** If the position is legal, accept it and close the dialog. */ void slotAccept(); /** Clear board. */ void slotClear(); /** Restore standard position */ void slotReset(); /** Copy current position as FEN. */ void slotCopyFen(); /** Copy current position as text. */ void slotCopyText(); /** Paste FEN from clipboard as current position. */ void slotPasteFen(); /** Change current piece using wheel */ void slotChangePiece(int dir); /** A Drop operation was inidcated by the boardview */ void slotDroppedPiece(Square s, Piece p); /** Select square and insert piece */ void slotSelected(Square s, int button); /** Manually adjust castling rights. */ void slotCastlingRights(); /** Manually adjust en passant square. */ void slotEnPassantSquare(); /** Adjust halfmove clock. */ void slotHalfmoveClock(); /** Adjust move number. */ void slotMoveNumber(); /** Move piece */ void slotMovePiece(Square from, Square to); /** Copy piece */ void slotCopyPiece(Square from, Square to); /** Remove piece */ void slotInvalidMove(Square from); /** Toggle side to move */ void slotToggleSide(); private: Ui::BoardSetupDialog ui; Color m_toMove; int m_wheelCurrentDelta; int m_minDeltaWheel; Piece m_selectedPiece; bool inDrag; }; #endif chessx-1.0.0/data/images/edit_find.png000644 001750 001750 00000027045 12142254551 020433 0ustar00niklasniklas000000 000000 PNG  IHDR>atIME "RrWbKGD-IDATx} յfaV`fVA@DPD{|gD|./}Y4$=~k1JT  ,: 3 KUvM/@zRU~D۴ʃ꺮-\"/|D7x0??('X DA9vL*qRBٳs@@maV^#znâ-Br̽[>@ڌ3\'NĴ LTˣ^zxHH p;T۩?r/B:Q[oU*rINGITkU[!'͕D999zew܂ ܹ'[DW$x;FGWZH7O<۳o? r;::.ec &B,ҹ!ע3aA&,,?|=w\~F_R+rsν_ #c *qnZV,}!Ϝ'9F ȟS`޼y,p's,T"U |~s3x'NXEi"[ > tiQQQQq\k?O*@%t(RC>`8ݻ77.euk3wv@3߿n+ N,ބ^MDܬ@ $UJRvk4}X{$TDz]i";F۾}T9!Q_~ys6ˬ:Dߏ9OSaa!ҭb?yw)8`Z'2 xOJy#(Yq |nOLt9 )((Çs("a GzlS;82NH>5O?ϟ?4k@9 5 OORN:x@2~i&xmVJqÖ `;'Id ,!bIL`*k=0>+%W_!ny>Hu28,%Tn , &As vB戣 ^XyaE68 !3 L$.Gy\D5}?+5 n  D#{y.zqq1!\N{TB8dk$>bRC!ps8!<(E5mn\LN.J0P  ܻw/mݺv%99v%jTa 8PfÆ (6#]5#E}:)$caɒ%y&MjZqSpUheix !m&;7xĈtgREE05R&X:  nAm6 jlg^p!}'abH۠A$!1Ȑ^lChhhpYFv9묳3Έ٩p}, '>ʲ,$)+W~[t >~x:ePWiRF" ;R~{ǎx_.:;%)ke Kmܸ^z%O憢뮻F1x6ԫ<^9 tRg{Rk!jk=Bmǚp=Fy/5o?hESEjnA] G]ƹ[vF(ĉGcP5Ћ aX(y Dk35l' {0 _Jx$eYby eϽ⋇ ;U70YW5+ӟZR5LEj u5=kLù.ϔ'B'(@Zr1ݰDyR*D88*'W^g7`SɴIwNNp=heޠR~K{|ytw+QII1݂0z7s:8sǥ[R£]s|sÇҔ+?(t9H3.{,7=0UIl{inҥ^GE۫&4W^)MG'd 1ALGSBxI| (^Y4)t7PQY 4xݾ ~_@?)*D  @ oNTt!yhHÀ׫.aL9^T()\/Q,WP7G^\%$h Β00<&:/'DwuTZuJy7Xc z뭘 Y+͞>e/%g!!z7>@}*G$c%qG=G:GʄNSFG>ˤ $T#Jyx~>m<0 ЍϤ^&u^* *)#qF2#ˉ 0A5J{#cJ/]83HhΎ}wA).uG3RAw)x)+P"́ {5b(,<$6 p֥EJV_U Ga2Kdի8.Lb-L߲Z܀,WD g7ATeeR.wkׯwHs<5xq@U?h&L9׼V :ܘ:k"89C{'[U5=4C]%7n6@HurC8٧4a:>җ68>}c ]aVQYE_ڸ=&@{{P^@ 44\Y*3F(4׻gƜ|^041}*yAP"e JpPǥFP(Ony'(FۗcEG KITsr-wOڰ5dô'xy+Tf:Dm--Yx_79l"YNZ#P]$:M$ b@Js!IXL`(dʼ^PNy2EUűO4P&/9۩RƍN˨ mo{h 7Еq HcPwl[ ķN@NDQOGr=ŔFq=:;NHeU\ǩlH.bŢ hM /l&x ݐ~{&u%k >O~$vʐ4Z2B)уhxWCg> jU; ȾH J= 8̩W¯D$̠Hkw"rIm@Zxs(VQF />[^[i.I0 ?N iJ!IHzYo%_\ D>TEjzYl펝jcsN0"J704,MYj]t<۲:::It2JI0@;`P!Ixt!UoM/.ſSm DTcfl#aKY'lf[< Rm%|<1(BА ~ ?`H AL  )ᗆsw/s]O^Z:Xo8ڼFg jTA)bzwyq6 ) nK $(Bߐ7 q}Tp0k׮GHFa6p1Ub P`nZ]/W% $! w~Nh"hwbw4@Дv#|AVw$"kD[WG{j7&jp ό lPGٍ#ˁxw.z$Pa-ڴ,vi h&aa!,SNgvޤ3u5So˖ѱl`n+ƐRx@ a ֥oQ 1z d t|آ*v; s 7ўmdϏ5Ԇ:Fd_&Bv A0H&A ipS&) g _DvnjU4o3!k CR@jB`s"Fo~S/x653QdFLT zwtSp0&s"[iE>X_#`6I B!=$@*Ҝ_hW\q zjxK&hNU5#aj-~ZꄏcwdsǮ=wHV>`Čp:Dg9cȓO>)WR 'eg4샅Wb}cuQ0*2߿Zh&5?`5E `q!0z=ں{gmo}+b%4<#~,=~z:mvf:Yp6lFd^) oV2o`HA#Gc1 Lx :^;IW#~(\L|g؜R~3 UOMA;ٙsޓ-^):b0 pMDVm2c+"0$}BJf^#ܑ2YݚLBjϺdRZ}:w},AT`-d0`,P1\lY.i⚏d]8G +Ymm!5`!/^XG4}AFwGszVz 0tќZ·c9nCrM+QK>C2a|gK̘1sX 4r ?66D+`%*+\E+Bt'ح @ٰ~-5\K[QW(>1hs4ǥՕ}tѲݴ%ظM5.'Zjh{g[AG(`N 9 8`&|O̙3_V@s ƌN-kxC!6Wо  \*"pƁ=BԮN!qi sM,|Cb@-)Ld\9KرVZ'K>-QSC-Bëj}wXɔ9Mcȑ#ck;D:T@"ikGY[ت /iz:$tvj edqI 'vxT0ug/[L[W/V򷟐6w]y/\$QƊx⾱oPmou}Mq٤T& }i+cI`cp6@ڱomPӡ|Zt턼M.T̨_-_Ss6mիV5hǺooo~;׿e\]x 6W﯂-u)42n<);9*7oGqDdԀ` NJ L:Un*&ڵ07ߤEY;b)>r؜l uLl0(ݶNqϭH-GJ~9)D1Q-iacS(v q 4sdzEt+o.%3؞-x\CAgi^Ο{ȃXx9װcu )+lT3AD*gnv2E6·q$^{5jj7.XG;K8a @l+`ɂ(>/ef%Lp^Ŋ.ܣ:M ׂ JwtƦ}g,cOH-kcLnV鹨#@Ϡ9M*i񬏩v5 ɏQ{0SntNj؍t I6Or&_Υ[s5_x04 *Α*dUI撷 u`mQ; Iz Lf/΃cF`e47DAU j1"JHp'>\Amp`(pУ |sX= p ($ ]'>YP`ʶh5h,moA|["@G$0A EnGfv̞=;GY֩c?;%@w>g B\gx \ A!&]N =Ur}Yk >l&Fo3w˨zRA `=yƬ= s疋 &eMM8;S߁d 8X N:rJKK9K;ήvo;xGAP p=p扆n9sN'FNO5A`ogV)nL+s|($NKh)3^{FLe.^*eZ~'kD.Vko_,7{\cH9cj?Bc ;<NCJ'5]'Xp9[] b;;>/P%A H\tD/b̸|6mYB |Уp˜e8s m)).|ۨ c0 X# {G ;89:=9žp OueBnv YTI;*Mw}%$(;'R;)}d-;UCPznQ,R#bv}|*ELh x=# RW0N|N_ :W(F=wtɽB <9h` 3n7dP_tOk}D%Y{A9T0+mi<hIO-T 'H&XvKp H!#ۥGOLAbu,f;1psd |:4!|UӐUSLh^|\oe;>!\څ{s6`7]Ou $XB1eFSj,o\E!͠udίфU蛎iz# ̂M̞R$0bk6FgpyE <`A "Dk ϫPNғ"&jcSw=95*K  hlGD]b8wSGP9Q }_S貧VXisJ|;hP%O>YYZZ:Dp A!} @*bR@`p=V8]Wي;@N#hkԸkMT;Qy&di~A 7FR{@gi'uvk"I&^*++ b} 2>@qtTD%5 8WAbgb5,².cٸrAklrQhzoJe$!ZΛ6A)(N@oncǎԻw( (UpjUzt)JL5p_CeϦUHskDoі= n O{:oz{-եs/|WH 7X5dȐ%%%1Dp{ J8eΆimoq}4Kz8m -[6k\|VQZ(wV?|BG|[m}[KcR6@?#?`F ^ bJ^QU8?쀰$V;ߠUh6XT/?#~[s (Kd^G? &lQFՔ (**@k8 =ʒlgG=NK,@U߻w/溦8FZ?#D-':Mǵ}ʰݤ9h)3U$6ETT<~zε^;5DHHvuh(Y6mzx 6Iܐy+ j.;b^Cw#52[l <<#vmecƌCP-ME2wEUZccÇ(n4~%д$.nNi߉K>|pHu~q*9Hy0ܓ,- Dyv̙3g}zɄ  >X 2!+ :uz3O<fB9$5-HW'CG u7nt9bIC8cC7o80n U`d@FA.]`AĀKn~GkS_itp$#4IO.A$:͞L|jFŽqIENDB`chessx-1.0.0/src/database/databaseinfo.h000644 001750 001750 00000005530 12223260306 020734 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2006-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef __DATABASEINFO_H__ #define __DATABASEINFO_H__ #include "game.h" #include class Database; class Filter; class QUndoStack; /** @ingroup Database The DatabaseInfo class is a simple class to keep various database-related information together. */ class DatabaseInfo: public QThread { Q_OBJECT public: void run(); enum {NewGame = -1}; /** Create information for clipboard database */ DatabaseInfo(); /** Create information for file database */ DatabaseInfo(const QString& filename); /** Close database and free memory */ ~DatabaseInfo(); /** Open database. */ bool open(bool utf8); /** Close database. */ void close(); /** @return @p true if database is valid */ bool isValid() const { return m_bLoaded ? m_database != 0 : false; } /** @return Database object */ Database* database() { return m_database; } /** @return current filter */ Filter* filter() { return m_filter; } /** @return current game */ Game& currentGame() { return m_game; } const Game& currentGame() const { return m_game; } /** @return index of current game */ int currentIndex() const { return m_index; } /** Load game @p index */ bool loadGame(int index, bool reload = 0); /** Starts new game, giving it @p index equal to the number of games in the database */ void newGame(); /** Saves game, replacing current one or adding new. If @ref currentIndex() is in the database, game will be replaced, else if will be appended at the end. */ bool saveGame(); /** Resizes the filter to the number of games in the database and puts * all games in the filter.*/ void resetFilter(); QString filePath() const { return m_filename; } bool IsLoaded() const { return m_bLoaded; } bool IsUtf8() const { return m_utf8; } protected: void doLoadFile(QString filename); signals: void LoadFinished(DatabaseInfo*); private: QUndoStack* m_undoStack; Database* m_database; Filter* m_filter; Game m_game; QString m_filename; int m_index; bool m_bLoaded; bool m_utf8; }; #endif chessx-1.0.0/src/database/analysis.h000644 001750 001750 00000004342 12141147243 020142 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2010 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef ANALYSIS_H #define ANALYSIS_H #include #include "movelist.h" class Board; /** The analysis class contains engine analysis. */ class Analysis { Q_DECLARE_TR_FUNCTIONS(Analysis) public: Analysis(); /** Reset values. */ void clear(); /** Check if analysis is valid. */ bool isValid() const; /** order of the variarion in the variation list */ int mpv() const; /** Set order of the variation. */ void setNumpv(int n); /** Time elapsed in miliseconds. */ int time() const; /** Set time in miliseconds. */ void setTime(int msec); /** Evaluation in centipawns. */ int score() const; /** Set evaluation in centipawns. */ void setScore(int score); /** Depth in plies. */ int depth() const; /** Set depth in plies. */ void setDepth(int depth); /** Nodes spent on analysis. */ quint64 nodes() const; /** Set nodes spent on analysis. */ void setNodes(quint64 nodes); /** Main variation. */ MoveList variation() const; /** Set main variation. */ void setVariation(const MoveList& variation); /** Is mate. */ bool isMate() const; /** @return moves to mate */ int movesToMate() const; /** Set moves to mate. */ void setMovesToMate(int mate); /** Moves to mate. */ /** Convert analysis to formatted text. */ QString toString(const Board& board) const; /** Assignment operator */ Analysis& operator=(const Analysis& rhs); private: int m_numpv; int m_msec; int m_mateIn; int m_depth; int m_score; quint64 m_nodes; MoveList m_variation; }; #endif // ANALYSIS_H chessx-1.0.0/src/quazip/unzip.h000644 001750 001750 00000030161 12223260306 017224 0ustar00niklasniklas000000 000000 /* unzip.h -- IO for uncompress .zip files using zlib Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g WinZip, InfoZip tools and compatible. Multi volume ZipFile (span) are not supported. Encryption compatible with pkzip 2.04g only supported Old compressions used by old PKZip 1.x are not supported I WAIT FEEDBACK at mail info@winimage.com Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution Condition of use and distribution are the same than zlib : This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Modified by Sergey A. Tachenov to integrate with Qt. */ /* for more info about .ZIP format, see http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip http://www.info-zip.org/pub/infozip/doc/ PkWare has also a specification at : ftp://ftp.pkware.com/probdesc.zip */ #ifndef _unz_H #define _unz_H #ifdef __cplusplus extern "C" { #endif #ifndef _ZLIB_H #include "zlib.h" #endif #ifndef _ZLIBIOAPI_H #include "ioapi.h" #endif #if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) /* like the STRICT of WIN32, we define a pointer that cannot be converted from (void*) without cast */ typedef struct TagunzFile__ { int unused; } unzFile__; typedef unzFile__ *unzFile; #else typedef voidp unzFile; #endif #define UNZ_OK (0) #define UNZ_END_OF_LIST_OF_FILE (-100) #define UNZ_ERRNO (Z_ERRNO) #define UNZ_EOF (0) #define UNZ_PARAMERROR (-102) #define UNZ_BADZIPFILE (-103) #define UNZ_INTERNALERROR (-104) #define UNZ_CRCERROR (-105) /* tm_unz contain date/time info */ typedef struct tm_unz_s { uInt tm_sec; /* seconds after the minute - [0,59] */ uInt tm_min; /* minutes after the hour - [0,59] */ uInt tm_hour; /* hours since midnight - [0,23] */ uInt tm_mday; /* day of the month - [1,31] */ uInt tm_mon; /* months since January - [0,11] */ uInt tm_year; /* years - [1980..2044] */ } tm_unz; /* unz_global_info structure contain global data about the ZIPfile These data comes from the end of central dir */ typedef struct unz_global_info_s { uLong number_entry; /* total number of entries in the central dir on this disk */ uLong size_comment; /* size of the global comment of the zipfile */ } unz_global_info; /* unz_file_info contain information about a file in the zipfile */ typedef struct unz_file_info_s { uLong version; /* version made by 2 bytes */ uLong version_needed; /* version needed to extract 2 bytes */ uLong flag; /* general purpose bit flag 2 bytes */ uLong compression_method; /* compression method 2 bytes */ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ uLong crc; /* crc-32 4 bytes */ uLong compressed_size; /* compressed size 4 bytes */ uLong uncompressed_size; /* uncompressed size 4 bytes */ uLong size_filename; /* filename length 2 bytes */ uLong size_file_extra; /* extra field length 2 bytes */ uLong size_file_comment; /* file comment length 2 bytes */ uLong disk_num_start; /* disk number start 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ tm_unz tmu_date; } unz_file_info; extern int ZEXPORT unzStringFileNameCompare OF((const char* fileName1, const char* fileName2, int iCaseSensitivity)); /* Compare two filename (fileName1,fileName2). If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) If iCaseSenisivity = 0, case sensitivity is defaut of your operating system (like 1 on Unix, 2 on Windows) */ extern unzFile ZEXPORT unzOpen OF((voidpf file)); /* Open a Zip file. path contain whatever zopen_file from the IO API accepts. For Qt implementation it is a pointer to QIODevice, for fopen() implementation it's a file name. If the zipfile cannot be opened (file don't exist or in not valid), the return value is NULL. Else, the return value is a unzFile Handle, usable with other function of this unzip package. */ extern unzFile ZEXPORT unzOpen2 OF((voidpf file, zlib_filefunc_def* pzlib_filefunc_def)); /* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ extern int ZEXPORT unzClose OF((unzFile file)); /* Close a ZipFile opened with unzipOpen. If there is files inside the .Zip opened with unzOpenCurrentFile (see later), these files MUST be closed with unzipCloseCurrentFile before call unzipClose. return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, unz_global_info *pglobal_info)); /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalComment OF((unzFile file, char *szComment, uLong uSizeBuf)); /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ /***************************************************************************/ /* Unzip package allow you browse the directory of the zipfile */ extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ extern int ZEXPORT unzGoToNextFile OF((unzFile file)); /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ extern int ZEXPORT unzLocateFile OF((unzFile file, const char *szFileName, int iCaseSensitivity)); /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ /* ****************************************** */ /* Ryan supplied functions */ /* unz_file_info contain information about a file in the zipfile */ typedef struct unz_file_pos_s { uLong pos_in_zip_directory; /* offset in zip file directory */ uLong num_of_file; /* # of file */ } unz_file_pos; extern int ZEXPORT unzGetFilePos( unzFile file, unz_file_pos* file_pos); extern int ZEXPORT unzGoToFilePos( unzFile file, unz_file_pos* file_pos); /* ****************************************** */ extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); /* Get Info about the current file if pfile_info!=NULL, the *pfile_info structure will contain somes info about the current file if szFileName!=NULL, the filemane string will be copied in szFileName (fileNameBufferSize is the size of the buffer) if extraField!=NULL, the extra field information will be copied in extraField (extraFieldBufferSize is the size of the buffer). This is the Central-header version of the extra field if szComment!=NULL, the comment string of the file will be copied in szComment (commentBufferSize is the size of the buffer) */ /***************************************************************************/ /* for reading the content of the current zipfile, you can open it, read data from it, and close it (you can close it before reading all the file) */ extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); /* Open for reading data the current file in the zipfile. If there is no error, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, const char* password)); /* Open for reading data the current file in the zipfile. password is a crypting password If there is no error, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, int* method, int* level, int raw)); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 *method will receive method of compression, *level will receive level of compression note : you can set level parameter as NULL (if you did not want known level, but you CANNOT set method parameter as NULL */ extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, int* method, int* level, int raw, const char* password)); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 *method will receive method of compression, *level will receive level of compression note : you can set level parameter as NULL (if you did not want known level, but you CANNOT set method parameter as NULL */ extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); /* Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzReadCurrentFile OF((unzFile file, voidp buf, unsigned len)); /* Read bytes from the current file (opened by unzOpenCurrentFile) buf contain buffer where data must be copied len the size of buf. return the number of byte copied if somes bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern z_off_t ZEXPORT unztell OF((unzFile file)); /* Give the current position in uncompressed data */ extern int ZEXPORT unzeof OF((unzFile file)); /* return 1 if the end of file was reached, 0 elsewhere */ extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, voidp buf, unsigned len)); /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is more info in the local-header version than in the central-header) if buf==NULL, it return the size of the local extra field if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. the return value is the number of bytes copied in buf, or (if <0) the error code */ /***************************************************************************/ /* Get the current file offset */ extern uLong ZEXPORT unzGetOffset(unzFile file); /* Set the current file offset */ extern int ZEXPORT unzSetOffset(unzFile file, uLong pos); #ifdef __cplusplus } #endif #endif /* _unz_H */ chessx-1.0.0/src/guess/common.h000644 001750 001750 00000043601 12223260306 017167 0ustar00niklasniklas000000 000000 ////////////////////////////////////////////////////////////////////// // // FILE: common.h // Common macros, structures and constants. // // Part of: Scid (Shane's Chess Information Database) // Version: 3.6.6 // // Notice: Copyright (c) 2000-2004 Shane Hudson. All rights reserved. // // Author: Shane Hudson (sgh@users.sourceforge.net) // Copyright (c) 2006-2007 Pascal Georges // ////////////////////////////////////////////////////////////////////// #ifndef SCID_COMMON_H #define SCID_COMMON_H //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // HEADER FILES: #include #include #include #include "error.h" #ifndef ASSERT #define ASSERT(h) assert(h) #endif namespace Guess { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CONSTANTS: const char TREEFILE_SUFFIX[] = ".stc"; const char GZIP_SUFFIX[] = ".gz"; const char ZIP_SUFFIX[] = ".zip"; const char PGN_SUFFIX[] = ".pgn"; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // TYPE DEFINITIONS // compareT: comparison type typedef signed int compareT; const compareT LESS_THAN = -1, EQUAL_TO = 0, GREATER_THAN = 1; // Chess Types typedef unsigned char pieceT; // e.g ROOK or WK typedef unsigned char colorT; // WHITE or BLACK typedef unsigned char squareT; // e.g. A3 typedef unsigned char directionT; // e.g. UP_LEFT typedef unsigned char rankT; // Chess board rank typedef unsigned char fyleT; // Chess board file typedef unsigned char leftDiagT; // Up-left diagonals typedef unsigned char rightDiagT; // Up-right diagonals // boardT: 64 squares plus two extra squares: one for storing the side // to move as a unsigned char and one for the string terminator, so boards can // be compared using regular string functions: typedef pieceT boardT [66]; typedef unsigned char smallBoardT [32]; // A more densely packed board, 2 squares // per unsigned char. typedef unsigned char castleDirT; // LEFT or RIGHT // Other Small Types typedef unsigned short statusT; // Fixed String Types typedef char sanStringT [ 10]; // SAN Move Notation // File-related Types typedef char fileNameT [512]; typedef unsigned int fileLengthT; enum fileModeT { FMODE_None = 0, FMODE_ReadOnly, FMODE_WriteOnly, FMODE_Both }; // Date type: see date.h and date.cpp typedef unsigned int dateT; // Game Information types typedef unsigned int gameNumberT; // Used in Index class typedef unsigned short eloT; typedef unsigned short ecoT; typedef char ecoStringT [6]; /* "A00j1" */ const ecoT ECO_None = 0; // Rating types: const unsigned char RATING_Elo = 0; const unsigned char RATING_Rating = 1; const unsigned char RATING_Rapid = 2; const unsigned char RATING_ICCF = 3; const unsigned char RATING_USCF = 4; const unsigned char RATING_DWZ = 5; const unsigned char RATING_BCF = 6; extern const char * ratingTypeNames [17]; // Defined in game.cpp // NameBase types: see namebase.h and namebase.cpp typedef unsigned int idNumberT; typedef unsigned int nameT; // Result Type const unsigned int NUM_RESULT_TYPES = 4; typedef unsigned char resultT; const resultT RESULT_None = 0, RESULT_White = 1, RESULT_Black = 2, RESULT_Draw = 3; const unsigned int RESULT_SCORE[4] = { 1, 2, 0, 1 }; const char RESULT_CHAR [4] = { '*', '1', '0', '=' }; const char RESULT_STR [4][4] = { "*", "1-0", "0-1", "=-=" }; const char RESULT_LONGSTR [4][8] = { "*", "1-0", "0-1", "1/2-1/2" }; const resultT RESULT_OPPOSITE [4] = { RESULT_None, RESULT_Black, RESULT_White, RESULT_Draw }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHESS PIECES, COLORS AND THEIR MACROS const unsigned int NUM_COLOR_TYPES = 2; const colorT WHITE = 0, BLACK = 1, NOCOLOR = 2; const char COLOR_CHAR [3] = {'W', 'B', '_' }; inline colorT color_Flip(colorT c) { return 1 - c; } inline char color_Char(colorT c) { return COLOR_CHAR[c]; } const castleDirT QSIDE = 0, KSIDE = 1; // PIECE TYPES (without color; same value as a white piece) const pieceT KING = 1, QUEEN = 2, ROOK = 3, BISHOP = 4, KNIGHT = 5, PAWN = 6; // PIECES: // Note that color(x) == ((x & 0x8) >> 3) and type(x) == (x & 0x7) // EMPTY is deliberately nonzero, and END_OF_BOARD is zero, so that // a board can be used as a regular 0-terminated string, provided // that board[NULL_SQUARE] == END_OF_BOARD, as it always should be. const pieceT EMPTY = 7; const pieceT END_OF_BOARD = 0; const pieceT WK = 1, WQ = 2, WR = 3, WB = 4, WN = 5, WP = 6; const pieceT BK = 9, BQ = 10, BR = 11, BB = 12, BN = 13, BP = 14; // Minor piece definitions, used for searching by material only: const pieceT WM = 16, BM = 17; const unsigned int MAX_PIECE_TYPES = 18; // PIECE_CHAR[]: array of piece characters, capitals for White pieces. const char PIECE_CHAR [] = "xKQRBNP.xkqrbnpxMm"; // PIECE_FLIP[]: array of pieces, with colors reversed. const pieceT PIECE_FLIP [MAX_PIECE_TYPES] = { END_OF_BOARD, BK, BQ, BR, BB, BN, BP, EMPTY, EMPTY, WK, WQ, WR, WB, WN, WP, EMPTY, BM, WM }; const bool PIECE_IS_SLIDER [8] = { false, false, true, true, true, false, false, false, }; // PIECE_VALUE: Piece values, K=1000, Q=9, R=5, B=N=3, P=1 const int PIECE_VALUE [MAX_PIECE_TYPES] = { 0, 100, 9, 5, 3, 3, 1, 0, 0, -100, -9, -5, -3, -3, -1, 0, 3, -3 }; // // INLINE FUNCTIONS for pieces // inline colorT piece_Color(pieceT p) { return (p == EMPTY) ? NOCOLOR : ((p & 8) >> 3); } // Slightly faster piece_Color when we are sure the piece is not empty: inline colorT piece_Color_NotEmpty(pieceT p) { return (p & 8) >> 3; } inline pieceT piece_Type(pieceT p) { return (p & 7); } inline pieceT piece_Make(colorT c, pieceT p) { return ((c << 3) | (p & 7)); } inline bool piece_IsWhite(pieceT p) { return (p >= WK && p <= WP); } inline bool piece_IsBlack(pieceT p) { return (p >= BK && p <= BP); } inline bool piece_IsKing(pieceT p) { return (piece_Type(p) == KING); } inline bool piece_IsQueen(pieceT p) { return (piece_Type(p) == QUEEN); } inline bool piece_IsRook(pieceT p) { return (piece_Type(p) == ROOK); } inline bool piece_IsBishop(pieceT p) { return (piece_Type(p) == BISHOP); } inline bool piece_IsKnight(pieceT p) { return (piece_Type(p) == KNIGHT); } inline bool piece_IsPawn(pieceT p) { return (piece_Type(p) == PAWN); } inline bool piece_IsSlider(pieceT p) { return PIECE_IS_SLIDER[piece_Type(p)]; } inline char piece_Char(pieceT p) { return PIECE_CHAR[piece_Type(p)]; } inline pieceT piece_FromChar(char x) { switch(x) { case 'K': return KING; case 'Q': return QUEEN; case 'R': return ROOK; case 'N': return KNIGHT; case 'B': return BISHOP; default: return EMPTY; } } inline int piece_Value(pieceT p) { return PIECE_VALUE[p]; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SQUARES AND SQUARE MACROS const squareT A1 = 0, B1 = 1, C1 = 2, D1 = 3, E1 = 4, F1 = 5, G1 = 6, H1 = 7, A2 = 8, B2 = 9, C2 = 10, D2 = 11, E2 = 12, F2 = 13, G2 = 14, H2 = 15, A3 = 16, B3 = 17, C3 = 18, D3 = 19, E3 = 20, F3 = 21, G3 = 22, H3 = 23, A4 = 24, B4 = 25, C4 = 26, D4 = 27, E4 = 28, F4 = 29, G4 = 30, H4 = 31, A5 = 32, B5 = 33, C5 = 34, D5 = 35, E5 = 36, F5 = 37, G5 = 38, H5 = 39, A6 = 40, B6 = 41, C6 = 42, D6 = 43, E6 = 44, F6 = 45, G6 = 46, H6 = 47, A7 = 48, B7 = 49, C7 = 50, D7 = 51, E7 = 52, F7 = 53, G7 = 54, H7 = 55, A8 = 56, B8 = 57, C8 = 58, D8 = 59, E8 = 60, F8 = 61, G8 = 62, H8 = 63, COLOR_SQUARE = 64, NULL_SQUARE = 65, NS = 65; // NS is abbreviation for NULL_SQUARE. const rankT RANK_1 = 0, RANK_2 = 1, RANK_3 = 2, RANK_4 = 3, RANK_5 = 4, RANK_6 = 5, RANK_7 = 6, RANK_8 = 7, NO_RANK = 64; const fyleT // we use "fyle" instead of "file" to avoid confusion with disk files. A_FYLE = 0, B_FYLE = 1, C_FYLE = 2, D_FYLE = 3, E_FYLE = 4, F_FYLE = 5, G_FYLE = 6, H_FYLE = 7, NO_FYLE = 64; inline rankT rank_FromChar(char c) { if(c < '1' || c > '8') { return NO_RANK; } else { return (c - '1'); } } inline fyleT fyle_FromChar(char c) { if(c < 'a' || c > 'h') { return NO_FYLE; } else { return (c - 'a'); } } inline squareT square_Make(fyleT f, rankT r) { ASSERT(f <= H_FYLE && r <= RANK_8); return ((r << 3) | f); } inline fyleT square_Fyle(squareT sq) { return (sq & 0x7); } inline rankT square_Rank(squareT sq) { return ((sq >> 3) & 0x7); } inline leftDiagT square_LeftDiag(squareT sq) { return square_Rank(sq) + square_Fyle(sq); } inline rightDiagT square_RightDiag(squareT sq) { return (7 + square_Rank(sq) - square_Fyle(sq)); } // square_Color: // Return WHITE for a light square, BLACK for a dark square. inline colorT square_Color(squareT sq) { return 1 - (square_LeftDiag(sq) & 1); } // square_FlipFyle: // Return the square with its file flipped: a1 <-> h1, b1 <-> g1, etc. inline squareT square_FlipFyle(squareT sq) { return square_Make(A_FYLE + H_FYLE - square_Fyle(sq), square_Rank(sq)); } // square_FlipRank: // Return the square with its rank flipped: a1 <-> a8, a2 <-> a7, etc. inline squareT square_FlipRank(squareT sq) { return square_Make(square_Fyle(sq), RANK_1 + RANK_8 - square_Rank(sq)); } // square_FlipDiag: // Return the square flipped along the a1-h8 diagonal. inline squareT square_FlipDiag(squareT sq) { return square_Make(square_Rank(sq), square_Fyle(sq)); } const unsigned int rankFyleDist[64] = { 0, 1, 2, 3, 4, 5, 6, 7, 1, 0, 1, 2, 3, 4, 5, 6, 2, 1, 0, 1, 2, 3, 4, 5, 3, 2, 1, 0, 1, 2, 3, 4, 4, 3, 2, 1, 0, 1, 2, 3, 5, 4, 3, 2, 1, 0, 1, 2, 6, 5, 4, 3, 2, 1, 0, 1, 7, 6, 5, 4, 3, 2, 1, 0 }; // square_Distance: // Return the distance in king moves between two squares. inline unsigned int square_Distance(squareT from, squareT to) { ASSERT(from <= H8 && to <= H8); unsigned int rankd = rankFyleDist[(square_Rank(from) << 3) | square_Rank(to)]; unsigned int fyled = rankFyleDist[(square_Fyle(from) << 3) | square_Fyle(to)]; return (rankd > fyled) ? rankd : fyled; } // square_NearestCorner: // Return the corner (A1/H1/A8/H8) closest to the specified square. inline squareT square_NearestCorner(squareT sq) { if(square_Rank(sq) <= RANK_4) { return (square_Fyle(sq) <= D_FYLE) ? A1 : H1; } else { return (square_Fyle(sq) <= D_FYLE) ? A8 : H8; } } inline bool square_IsCornerSquare(squareT sq) { return (sq == A1 || sq == H1 || sq == A8 || sq == H8); } inline bool square_IsEdgeSquare(squareT sq) { rankT rank = square_Rank(sq); if(rank == RANK_1 || rank == RANK_8) { return true; } fyleT fyle = square_Fyle(sq); if(fyle == A_FYLE || fyle == H_FYLE) { return true; } return false; } const int edgeDist[66] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 2, 2, 2, 2, 1, 0, 0, 1, 2, 3, 3, 2, 1, 0, 0, 1, 2, 3, 3, 2, 1, 0, 0, 1, 2, 2, 2, 2, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1 }; inline int square_EdgeDistance(squareT sq) { return edgeDist[sq]; } inline bool square_IsKnightHop(squareT from, squareT to) { ASSERT(from <= H8 && to <= H8); unsigned int rdist = rankFyleDist [(square_Rank(from) << 3) | square_Rank(to)]; unsigned int fdist = rankFyleDist [(square_Fyle(from) << 3) | square_Fyle(to)]; // It is a knight hop only if one distance is two squares and the // other is one square -- that is, only if their product equals two. return ((rdist * fdist) == 2); } inline char square_FyleChar(squareT sq) { return square_Fyle(sq) + 'a'; } inline char square_RankChar(squareT sq) { return square_Rank(sq) + '1'; } inline void square_Print(squareT sq, char * str) { if(sq <= H8) { str[0] = square_FyleChar(sq); str[1] = square_RankChar(sq); str[2] = 0; } else if(sq == NULL_SQUARE) { str[0] = 'N'; str[1] = 'S'; str[2] = 0; } else { str[0] = 'X'; str[1] = 'X'; str[2] = 0; } return; } // Directions: // Up = 1, Down = 2, Left = 4, Right = 8, UpLeft = 5, UpRight = 9, // DownLeft = 6, DownRight = 10 const directionT NULL_DIR = 0, UP = 1, DOWN = 2, LEFT = 4, RIGHT = 8, UP_LEFT = (UP | LEFT), UP_RIGHT = (UP | RIGHT), DOWN_LEFT = (DOWN | LEFT), DOWN_RIGHT = (DOWN | RIGHT); const directionT dirOpposite[11] = { NULL_DIR, DOWN, // opposite of UP (1) UP, // opposite of DOWN (2) NULL_DIR, RIGHT, // opposite of LEFT (4) DOWN_RIGHT, // opposite of UP_LEFT (5) UP_RIGHT, // opposite of DOWN_LEFT (6) NULL_DIR, LEFT, // opposite of RIGHT (8) DOWN_LEFT, // opposite of UP_RIGHT (9) UP_LEFT // opposite of DOWN_RIGHT (10) }; // direction_Opposite(): return the opposite direction to d inline directionT direction_Opposite(directionT d) { return dirOpposite[d]; } // dirIsDiagonal[]: array listing the diagonal directions, for fast // lookup of whether a direction is a diagonal. const bool dirIsDiagonal [11] = { false, // 0 = NULL_DIR false, // 1 = UP false, // 2 = DOWN false, // 3 = Invalid false, // 4 = LEFT true, // 5 = UP_LEFT true, // 6 = DOWN_LEFT false, // 7 = Invalid false, // 8 = RIGHT true, // 9 = UP_RIGHT true // 10 = DOWN_RIGHT }; inline bool direction_IsDiagonal(directionT dir) { return dirIsDiagonal[dir]; } // dirDelta: // Array giving the board delta of moving to the next square // in that direction. const int dirDelta[11] = { 0, // NULL_DIR 8, // UP -8, // DOWN 0, // Invalid -1, // LEFT 7, // UP_LEFT -9, // DOWN_LEFT 0, // Invalid 1, // RIGHT 9, // UP_RIGHT -7 // DOWN_RIGHT }; inline int direction_Delta(directionT dir) { return dirDelta[dir]; } // sqDir[][]: Array listing the direction between any two squares. // For example, sqDir[A1][B2] == UP_RIGHT, and sqDir[A1][C2] == NULL_DIR. // It is initialised with the function scid_Init() in misc.cpp extern directionT sqDir[66][66]; // sqMove[66][11]: a table of the square resulting from a move in a // certain direction from a square. // For example, sqMove[A1][UP] == A2; sqMove[A1][DOWN] == NULL_SQUARE. #include "sqmove.h" // square_Move(): Return the new square resulting from moving in // direction d from x. inline squareT square_Move(squareT sq, directionT dir) { return sqMove[sq][dir]; } // square_Last(): // Return the last square reached by moving as far as possible in // the direction d from the square sq. If sq is a valid on-board // square and d is a valid direction, the result will always be // a valid on-board square; the result will be the same as the // input square if moving in the specified direction would end // up off the board. inline squareT square_Last(squareT sq, directionT dir) { return sqLast[sq][dir]; } // The starting Board // const boardT START_BOARD = { WR, WN, WB, WQ, WK, WB, WN, WR, // A1--H1 WP, WP, WP, WP, WP, WP, WP, WP, // A2--H2 EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, BP, BP, BP, BP, BP, BP, BP, BP, BR, BN, BB, BQ, BK, BB, BN, BR, EMPTY, // COLOR_SQUARE END_OF_BOARD // NULL_SQUARE }; // Square colors for the standard chess board: // const colorT BOARD_SQUARECOLOR[66] = { BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, // a1-h1 WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, // a2-h2 BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, // a3-h3 WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, // a4-h4 BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, // a5-h5 WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, // a6-h6 BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, // a7-h7 WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, // a8-h8 NOCOLOR, NOCOLOR // Color square and Null square }; inline int board_Compare(const pieceT * b1, const pieceT * b2) { for(unsigned int i = 0; i < 64; i++) { if(*b1 < *b2) { return -1; } if(*b1 > *b2) { return 1; } b1++; b2++; } return 0; } // square_Adjacent: returns 1 if the two squares are adjacent. Note that // diagonal adjacency is included: a1 and b2 are adjacent. // Also note that a square is adjacent to itself. inline bool square_Adjacent(squareT from, squareT to) { ASSERT(from <= H8 && to <= H8); rankT fromRank = square_Rank(from); rankT toRank = square_Rank(to); int rdist = (int)fromRank - (int)toRank; if(rdist < -1 || rdist > 1) { return false; } fyleT fromFyle = square_Fyle(from); fyleT toFyle = square_Fyle(to); int fdist = (int)fromFyle - (int)toFyle; if(fdist < -1 || fdist > 1) { return false; } return true; } // Random values: // To ensure good bit distributions, we take three random values // and mix the bits around. inline void srandom32(unsigned int seed) { #ifdef WIN32 srand(seed); #else srandom(seed); #endif } inline unsigned int random32() { #ifdef WIN32 return rand() ^ (rand() << 16) ^ (rand() >> 16); #else return random() ^ (random() << 16) ^ (random() >> 16); #endif } } // End namespace Guess #endif // #ifdef SCID_COMMON_H ////////////////////////////////////////////////////////////////////// // EOF: common.h ////////////////////////////////////////////////////////////////////// chessx-1.0.0/src/database/outputoptions.cpp000644 001750 001750 00000022757 12223260306 021635 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2007-2009 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "outputoptions.h" #include "settings.h" #include OutputOptions::OutputOptions() { } bool OutputOptions::createDefaultOptions(QString path) { m_list.clear(); m_type.clear(); m_default.clear(); m_allow.clear(); if(path.isEmpty()) { createOption("ColumnStyle", Boolean, "", "false", tr("Notation in Column Style")); createOption("SymbolicNag", Boolean, "", "false", tr("Show symbolic Nags")); createOption("TextWidth", Integer, "0:200", "80", tr("Text width")); createOption("VariationIndentLevel", Integer, "1:200", "4", tr("Indent variations from Level")); createOption("VariationIndentSize", Integer, "1:10", "3", tr("Variation Indentation")); createOption("CommentIndent", String, "Always|OnlyMainline|Never", "OnlyMainline", tr("Comment indentation")); createOption("MainLineMoveColor", Color, "", "black", tr("Main Line Color")); createOption("VariationColor", Color, "", "blue", tr("Variation Color")); createOption("CommentColor", Color, "", "green", tr("Comment Color")); createOption("NagColor", Color, "", "red", tr("NAG Color")); createOption("HeaderColor", Color, "", "blue", tr("Header Color")); createOption("ShowHeader", Boolean, "", "true", tr("Show Header")); createOption("ShowDiagrams", Boolean, "", "false", tr("Show Diagrams")); createOption("DiagramSize", Integer, "0:500", "200", tr("Diagram Size")); } else { AppSettings->beginGroup(path); createOption("ColumnStyle", AppSettings->getValue("ColumnStyle").toBool() , tr("Notation in Column Style")); createOption("SymbolicNag", AppSettings->getValue("SymbolicNag").toBool(), tr("Show symbolic Nags")); createOption("TextWidth", "0:200", AppSettings->getValue("TextWidth").toInt(), tr("Text width")); createOption("VariationIndentLevel", "1:200", AppSettings->getValue("VariationIndentLevel").toInt(), tr("Indent variations from Level")); createOption("VariationIndentSize", "1:10", AppSettings->getValue("VariationIndentSize").toInt(), tr("Variation Indentation")); createOption("CommentIndent", String, "Always|OnlyMainline|Never", AppSettings->getValue("CommentIndent").toString(), tr("Comment Indentation")); createOption("MainLineMoveColor", AppSettings->getValue("MainLineMoveColor").toString(), tr("Main Line Color")); createOption("VariationColor", AppSettings->getValue("VariationColor").toString(), tr("Variation Color")); createOption("CommentColor", AppSettings->getValue("CommentColor").toString(), tr("Comment Color")); createOption("NagColor", AppSettings->getValue("NagColor").toString(), tr("NAG Color")); createOption("HeaderColor", AppSettings->getValue("HeaderColor").toString(), tr("Header Color")); createOption("ShowHeader", AppSettings->getValue("ShowHeader").toBool(), tr("Show Header")); createOption("ShowDiagrams", AppSettings->getValue("ShowDiagrams").toBool(), tr("Show Diagrams")); createOption("DiagramSize", "0:500", AppSettings->getValue("DiagramSize").toInt(), tr("Diagram Size")); AppSettings->endGroup(); } return true; } bool OutputOptions::createOption(const QString& optionName, const QString& optionType, const QString& allowValues, const QString& defaultValue, const QString& description) { return createOption(optionName, optionString2Type(optionType), allowValues, defaultValue, description); } bool OutputOptions::createOption(const QString& optionName, bool bValue, const QString& description) { QString sValue = bValue ? "true" : "false"; return createOption(optionName, Boolean, "", sValue, description); } bool OutputOptions::createOption(const QString& optionName, const QString& allowValues, int iValue, const QString& description) { QString sValue = QString().number(iValue); return createOption(optionName, Integer, allowValues, sValue, description); } bool OutputOptions::createOption(const QString& optionName, const QString& color, const QString& description) { return createOption(optionName, Color, "", color, description); } bool OutputOptions::createOption(const QString& optionName, OutputOptionType optionType, const QString& allowValues, const QString& defaultValue, const QString& description) { m_list[optionName] = defaultValue; m_type[optionName] = optionType; m_allow[optionName] = allowValues; m_default[optionName] = defaultValue; m_description[optionName] = description; if(!setOption(optionName, defaultValue)) { m_list.remove(optionName); m_type.remove(optionName); m_allow.remove(optionName); m_default.remove(optionName); m_description.remove(optionName); qWarning("Option '%s' could not be created", optionName.toLatin1().constData()); return false; } return true; } bool OutputOptions::setOption(const QString& optionString) { QStringList temp = optionString.split('='); return setOption(temp[0], temp[1]); } bool OutputOptions::setOption(const QString& optionName, const QString& optionValue) { if(!validateValue(optionName, optionValue)) { qWarning("Option '%s' could not be set", optionName.toLatin1().constData()); return false; } m_list[optionName] = optionValue; return true; } bool OutputOptions::setOption(const QString& optionName, bool optionValue) { if(optionValue) { return setOption(optionName, QString("true")); } else { return setOption(optionName, QString("false")); } } bool OutputOptions::setOption(const QString& optionName, int optionValue) { return setOption(optionName, QString::number(optionValue)); } int OutputOptions::getOptionAsInt(const QString& optionName) const { if(m_list.contains(optionName)) { return m_list.value(optionName).toInt(); } return 0; } QString OutputOptions::getOptionAsString(const QString& optionName) const { if(m_list.contains(optionName)) { return m_list.value(optionName); } return ""; } bool OutputOptions::getOptionAsBool(const QString& optionName) { return ((m_list[optionName] == "true") || (m_list[optionName] == "1")); } bool OutputOptions::validateValue(const QString& optionName, const QString& value) { QStringList allowValues; QStringList allowColors; if(!m_list.contains(optionName)) { // Option does not exist return false; } allowValues = m_allow[optionName].split('|'); switch(m_type[optionName]) { case Integer: /* If the allow string is empty, then any number is allowed */ if(m_allow[optionName].isEmpty()) { return true; } /* See if value is in on of the ranges */ for(QStringList::iterator it = allowValues.begin(); it != allowValues.end(); ++it) { if((*it).indexOf(':') >= 0) { QStringList limits = it->split(':'); int val = value.toInt(); int ulimit = limits[1].toInt(); int llimit = limits[0].toInt(); if((val >= llimit) && (val <= ulimit)) { return true; } } } if(allowValues.contains(value)) { return true; } return false; case String: if(m_allow[optionName].isEmpty()) { return true; } if(allowValues.contains(value)) { return true; } return false; case Boolean: if((value == "1") || (value == "0") || (value == "true") || (value == "false")) { return true; } else { return false; } case Color: allowColors.append("red"); allowColors.append("blue"); allowColors.append("black"); allowColors.append("white"); allowColors.append("green"); allowColors.append("purple"); if((allowColors.contains(value)) || (value.contains(QRegExp("^#[0-9a-fA-F]{6}")))) { return true; } else { return false; } break; default : /* Unknown type */ return false; } return false; } QString OutputOptions::getOptionDescription(const QString& optionName) { return m_description[optionName]; } QStringList OutputOptions::getOptionList() { return m_list.keys(); } OutputOptions::OutputOptionType OutputOptions::optionString2Type(const QString& optionTypeStr) { if(optionTypeStr == "String") { return String; } else if(optionTypeStr == "Integer") { return Integer; } else if(optionTypeStr == "Boolean") { return Boolean; } else if(optionTypeStr == "Color") { return Color; } return String; } chessx-1.0.0/data/images/arrow_yellow.png000644 001750 001750 00000014263 12103305243 021221 0ustar00niklasniklas000000 000000 PNG  IHDR((miCCPICC ProfileX XuXUͷOrN:tsQ E))E)Q)A$ DABB{sw~kϞwfY/,0 !Q$#]'gNԊp++sR%?>D +䶗w$1/NDa'3"x= ~=cgT$@ވyb~H;`BBG&G"$$l!X?ߦ>g,ȓȋ"Ã=YG#p!5Edr#sK4}L8cҵLmlGAaf^-ډzl_ol#clqzz$7 6ox~?CŗdxE 04k'Ã?} EσOz{-|b:~ţz PȿHdjC_c<huE6~BѤC]0`\I :X; @G@mh  !H($z +| ϐУp8KQEIbRR҅2,e CʷTTRT&TT'JƨQQ RPQQPߡ^!ѣ9ASBsffV֒66vG'Dg@MLWAnEOGO?E_IK `ȐpaaQс14IɄ))9&3's:s=: ;6KMg,<AY[X߰جَ]be[dg`Wg'g798l8qTp qrrqqsq>\b jZȣSók{wwOϞ/&~ /7@@KA2AA }BBBiB-B,&qu¯E(ED"DE&D*AEbbb%b#ⰸxEQ DDĤ$ddTT7ii}ҿeee*e^ɚ&ɶ.ˉJ&) OʷPWQ0HhحDRWZPPP.UTaPRRyQU=z_ZZwuI Z|TԸ1ɣyYsZWS\659Q@:tetIMzjz:QFto uc͌OpMjLLMQٚ73'Y  =b ,M,s-X [EXݳZ[YX鳥u]ӵ˶{e/bm@P8$tiЙ9reC]]S]>{ߍ-;GǶg窗WQx[;{G'gW7wO/o_˿1@/8Gq`YzePUnc|GPРО0ذp%Z$y859 EDDhƔlq8r'664vsqqWu'9~tDI'?&%T'$$$iVnQi}mhX׸ g>>5:9==5"ŏ1/^%ƼxC-wnN+M?џzo,qˇ?Q~*㞫`ZLJȷ߇> ]Za]{jZzF/_}s[Gqۅ;;m~ $y9 ` Jg@9#sȩ2(&Fk_#!נ(Ch>ya$2Ͱxeh&.s (  뉨*sIJ%ץ_ v5W((&)+V1VUTRǪ;0ѩYUmckgoogvEӖ)VO$۞KOvHrLt:|%Pk7owgW41OoǁA/gCCQt$H(hGVm>6|u&-'_2O G*KitB:c's-3ٯM3;7?Z0rI@➒[/55^n^bv 5LuRUot_CR㑦c'Z[例˼쎜=n5=n7`}IpH{Mc'.ʃCO kh>370{ffnC\_q{{˴{Y4~}|i`ax!EP߾|Xqk|gjZzІ/M-m߬X Ǎ!;MLDcK^s%+ [5Ww^>wBwDĚě$$oJK_,_pA1G)CJ*IW倅>.>!1 )9A%lkmeimmiyۡ߹rx9{gߜ|BB|\\|5I%crPlc[hڟ0؟s^rCJUjiڹ)A,蜕>q!2,*;~-)X:}CW*+_}Rn?ieӻٖw-[jzzzFÍGk}W |:ɧّ駯GLJ'?~~iE˲Wߤ=.roɬŹ[K.F|uf]a2 O*aN "oᶱ;ߨ]hU7`䠗Y` TXQ` `I ߏ@A\H)41 iHFY `|b!=$C ҠP Zia9(4ӅPH.GHb1X ! sSdd!܈"b҇rʌZFV. =4C(osLLWXrXX_%q9+/\'#,d /𔔐ܐz,]$"/))Z-r"<\ .jTi6jhO,ꡑlhcjiRk:dÂ%ɪzҖ>㚳|7]#Ƴk['wП9/-6$8t \"l>9۽K'o1hws0ə0p.CQgP}hZŐcl09"6;½ dd2Rry,' GTTe%44崢tt#nN00V022XjY-XWJ W8pZqraM])fB BDċ%p']($#*S~TARr QUI逋VvNn^iYmh+9ka{).Cq[=T=OxzS Ƅ g$=>z1 '㧶RN`ˬ=qv\HYnMY¢beW*IV-ݐ߸Ӑݬ|wݨGj]ꆧF Zb'_,|=]ς͗ԯ7UƯ=ES?b@Q̀F,(i!bD Ma,[$WP(T!jA4 :&ӏǺco`wpVmYAp<|ŒQ> ȩ6cWhhht e  mfkYYXϰɳbOxřƥnj˯KŒH~_! &-&!!(%,)="sM6AM^SA@F `TӲIѭ՟33k1>Hanb]nҎ!3ˡC\߻{"]o;?]!|m+z1'Of&R%%sԦp\;s>[HNd[~υ"g/CW*RW1WmQuKNlݶ{7TuTw~;7?{0; W.o25LD9/Yg['?7օ~9me+/=DȏowwW}*ݩ@t9ci(E fY QZ!tIDATX m0ʩ@7tvlllnPF詧J}+9`P$`mۮ-G?pZ!*jn _JlB_$տ?7?5zz<ȑ1] Hj17؝qcuRud:`l$ȆEo /JF1$@.s Fg9Rq?֔lxL+JwsS.&O"h_mlV  dBlǍ%!GKANK#%RH/` 7072 ̅ El`w2s٢ّ LՉL LP׾m:b,>+*;/Sb+P>H,Qb@(:x4ҳcc*\IـEqRԝỒy73Hc/ ^{(pIENDB`chessx-1.0.0/src/quazip/unzip.c000644 001750 001750 00000140322 12162306622 017224 0ustar00niklasniklas000000 000000 /* unzip.c -- IO for uncompress .zip files using zlib Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant Read unzip.h for more info Modified by Sergey A. Tachenov to integrate with Qt. */ /* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of compatibility with older software. The following is from the original crypt.c. Code woven in by Terry Thorsen 1/2003. */ /* Copyright (c) 1990-2000 Info-ZIP. All rights reserved. See the accompanying file LICENSE, version 2000-Apr-09 or later (the contents of which are also included in zip.h) for terms of use. If, for some reason, all these files are missing, the Info-ZIP license also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html */ /* crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] The encryption/decryption parts of this source code (as opposed to the non-echoing password parts) were originally written in Europe. The whole source package can be freely distributed, including from the USA. (Prior to January 2000, re-export from the US was a violation of US law.) */ /* This encryption code is a direct transcription of the algorithm from Roger Schlafly, described by Phil Katz in the file appnote.txt. This file (appnote.txt) is distributed with the PKZIP program (even in the version without encryption capabilities). */ #include #include #include #include "zlib.h" #include "unzip.h" #ifdef STDC # include # include # include #endif #ifdef NO_ERRNO_H extern int errno; #else # include #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ #ifndef CASESENSITIVITYDEFAULT_NO # if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) # define CASESENSITIVITYDEFAULT_NO # endif #endif #ifndef UNZ_BUFSIZE #define UNZ_BUFSIZE (16384) #endif #ifndef UNZ_MAXFILENAMEINZIP #define UNZ_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #ifndef TRYFREE # define TRYFREE(p) {if (p) free(p);} #endif #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) const char unz_copyright[] = " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; /* unz_file_info_interntal contain internal info about a file in zipfile*/ typedef struct unz_file_info_internal_s { uLong offset_curfile;/* relative offset of local header 4 bytes */ } unz_file_info_internal; /* file_in_zip_read_info_s contain internal information about a file in zipfile, when reading and decompress it */ typedef struct { char *read_buffer; /* internal buffer for compressed data */ z_stream stream; /* zLib stream structure for inflate */ uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ uLong stream_initialised; /* flag set if stream structure is initialised*/ uLong offset_local_extrafield;/* offset of the local extra field */ uInt size_local_extrafield;/* size of the local extra field */ uLong pos_local_extrafield; /* position in the local extra field in read*/ uLong crc32; /* crc32 of all data uncompressed */ uLong crc32_wait; /* crc32 we must obtain after decompress all */ uLong rest_read_compressed; /* number of byte to be decompressed */ uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ zlib_filefunc_def z_filefunc; voidpf filestream; /* io structore of the zipfile */ uLong compression_method; /* compression method (0==store) */ uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ int raw; } file_in_zip_read_info_s; /* unz_s contain internal information about the zipfile */ typedef struct { zlib_filefunc_def z_filefunc; voidpf filestream; /* io structore of the zipfile */ unz_global_info gi; /* public global information */ uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ uLong num_file; /* number of the current file in the zipfile*/ uLong pos_in_central_dir; /* pos of the current file in the central dir*/ uLong current_file_ok; /* flag about the usability of the current file*/ uLong central_pos; /* position of the beginning of the central dir*/ uLong size_central_dir; /* size of the central directory */ uLong offset_central_dir; /* offset of start of central directory with respect to the starting disk number */ unz_file_info cur_file_info; /* public info about the current file in zip*/ unz_file_info_internal cur_file_info_internal; /* private info about it*/ file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current file if we are decompressing it */ int encrypted; # ifndef NOUNCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ const unsigned long* pcrc_32_tab; # endif } unz_s; #ifndef NOUNCRYPT #include "crypt.h" #endif /* =========================================================================== Read a byte from a gz_stream; update next_in and avail_in. Return EOF for end of file. IN assertion: the stream s has been sucessfully opened for reading. */ local int unzlocal_getByte OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, int *pi)); local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi) const zlib_filefunc_def* pzlib_filefunc_def; voidpf filestream; int *pi; { unsigned char c; int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); if (err==1) { *pi = (int)c; return UNZ_OK; } else { if (ZERROR(*pzlib_filefunc_def,filestream)) return UNZ_ERRNO; else return UNZ_EOF; } } /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets */ local int unzlocal_getShort OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX) const zlib_filefunc_def* pzlib_filefunc_def; voidpf filestream; uLong *pX; { uLong x ; int i; int err; err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==UNZ_OK) err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<8; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } local int unzlocal_getLong OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX) const zlib_filefunc_def* pzlib_filefunc_def; voidpf filestream; uLong *pX; { uLong x ; int i; int err; err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==UNZ_OK) err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<8; if (err==UNZ_OK) err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<16; if (err==UNZ_OK) err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<24; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } /* My own strcmpi / strcasecmp */ local int strcmpcasenosensitive_internal (fileName1,fileName2) const char* fileName1; const char* fileName2; { for (;;) { char c1=*(fileName1++); char c2=*(fileName2++); if ((c1>='a') && (c1<='z')) c1 -= 0x20; if ((c2>='a') && (c2<='z')) c2 -= 0x20; if (c1=='\0') return ((c2=='\0') ? 0 : -1); if (c2=='\0') return 1; if (c1c2) return 1; } } #ifdef CASESENSITIVITYDEFAULT_NO #define CASESENSITIVITYDEFAULTVALUE 2 #else #define CASESENSITIVITYDEFAULTVALUE 1 #endif #ifndef STRCMPCASENOSENTIVEFUNCTION #define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal #endif /* Compare two filename (fileName1,fileName2). If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) If iCaseSenisivity = 0, case sensitivity is defaut of your operating system (like 1 on Unix, 2 on Windows) */ extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity) const char* fileName1; const char* fileName2; int iCaseSensitivity; { if (iCaseSensitivity==0) iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; if (iCaseSensitivity==1) return strcmp(fileName1,fileName2); return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); } #ifndef BUFREADCOMMENT #define BUFREADCOMMENT (0x400) #endif /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ local uLong unzlocal_SearchCentralDir OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream)); local uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream) const zlib_filefunc_def* pzlib_filefunc_def; voidpf filestream; { unsigned char* buf; uLong uSizeFile; uLong uBackRead; uLong uMaxBack=0xffff; /* maximum size of global comment */ uLong uPosFound=0; if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { uPosFound = uReadPos+i; break; } if (uPosFound!=0) break; } TRYFREE(buf); return uPosFound; } /* Open a Zip file. path contain the full pathname (by example, on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer "zlib/zlib114.zip". If the zipfile cannot be opened (file doesn't exist or in not valid), the return value is NULL. Else, the return value is a unzFile Handle, usable with other function of this unzip package. */ extern unzFile ZEXPORT unzOpen2 (file, pzlib_filefunc_def) voidpf file; zlib_filefunc_def* pzlib_filefunc_def; { unz_s us; unz_s *s; uLong central_pos,uL; uLong number_disk; /* number of the current dist, used for spaning ZIP, unsupported, always 0*/ uLong number_disk_with_CD; /* number the the disk with central dir, used for spaning ZIP, unsupported, always 0*/ uLong number_entry_CD; /* total number of entries in the central dir (same than number_entry on nospan) */ int err=UNZ_OK; if (unz_copyright[0]!=' ') return NULL; if (pzlib_filefunc_def==NULL) fill_qiodevice_filefunc(&us.z_filefunc); else us.z_filefunc = *pzlib_filefunc_def; us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque, file, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); if (us.filestream==NULL) return NULL; central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream); if (central_pos==0) err=UNZ_ERRNO; if (ZSEEK(us.z_filefunc, us.filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; /* the signature, already checked */ if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; /* number of this disk */ if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; /* number of the disk with the start of the central directory */ if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central dir on this disk */ if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central dir */ if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) err=UNZ_ERRNO; if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE; /* size of the central directory */ if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) err=UNZ_ERRNO; /* offset of start of central directory with respect to the starting disk number */ if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) err=UNZ_ERRNO; /* zipfile comment length */ if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) err=UNZ_ERRNO; if ((central_pospfile_in_zip_read!=NULL) unzCloseCurrentFile(file); ZCLOSE(s->z_filefunc, s->filestream); TRYFREE(s); return UNZ_OK; } /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info) unzFile file; unz_global_info *pglobal_info; { unz_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; *pglobal_info=s->gi; return UNZ_OK; } /* Translate date/time from Dos format to tm_unz (readable more easilty) */ local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) uLong ulDosDate; tm_unz* ptm; { uLong uDate; uDate = (uLong)(ulDosDate>>16); ptm->tm_mday = (uInt)(uDate&0x1f) ; ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; } /* Get Info about the current file in the zipfile, with internal only info */ local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, unz_file_info *pfile_info, unz_file_info_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); local int unzlocal_GetCurrentFileInfoInternal (file, pfile_info, pfile_info_internal, szFileName, fileNameBufferSize, extraField, extraFieldBufferSize, szComment, commentBufferSize) unzFile file; unz_file_info *pfile_info; unz_file_info_internal *pfile_info_internal; char *szFileName; uLong fileNameBufferSize; void *extraField; uLong extraFieldBufferSize; char *szComment; uLong commentBufferSize; { unz_s* s; unz_file_info file_info; unz_file_info_internal file_info_internal; int err=UNZ_OK; uLong uMagic; uLong uSeek=0; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (ZSEEK(s->z_filefunc, s->filestream, s->pos_in_central_dir+s->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; /* we check the magic */ if (err==UNZ_OK) { if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x02014b50) err=UNZ_BADZIPFILE; } if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) err=UNZ_ERRNO; unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) err=UNZ_ERRNO; uSeek+=file_info.size_filename; if ((err==UNZ_OK) && (szFileName!=NULL)) { uLong uSizeRead ; if (file_info.size_filename0) && (fileNameBufferSize>0)) if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) err=UNZ_ERRNO; uSeek -= uSizeRead; } if ((err==UNZ_OK) && (extraField!=NULL)) { uLong uSizeRead ; if (file_info.size_file_extraz_filefunc, s->filestream,uSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) uSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead) err=UNZ_ERRNO; uSeek += file_info.size_file_extra - uSizeRead; } else uSeek+=file_info.size_file_extra; if ((err==UNZ_OK) && (szComment!=NULL)) { uLong uSizeRead ; if (file_info.size_file_commentz_filefunc, s->filestream,uSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) uSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_comment>0) && (commentBufferSize>0)) if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) err=UNZ_ERRNO; uSeek+=file_info.size_file_comment - uSizeRead; } else uSeek+=file_info.size_file_comment; if ((err==UNZ_OK) && (pfile_info!=NULL)) *pfile_info=file_info; if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) *pfile_info_internal=file_info_internal; return err; } /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetCurrentFileInfo (file, pfile_info, szFileName, fileNameBufferSize, extraField, extraFieldBufferSize, szComment, commentBufferSize) unzFile file; unz_file_info *pfile_info; char *szFileName; uLong fileNameBufferSize; void *extraField; uLong extraFieldBufferSize; char *szComment; uLong commentBufferSize; { return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, szFileName,fileNameBufferSize, extraField,extraFieldBufferSize, szComment,commentBufferSize); } /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ extern int ZEXPORT unzGoToFirstFile (file) unzFile file; { int err=UNZ_OK; unz_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; s->pos_in_central_dir=s->offset_central_dir; s->num_file=0; err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ extern int ZEXPORT unzGoToNextFile (file) unzFile file; { unz_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ if (s->num_file+1==s->gi.number_entry) return UNZ_END_OF_LIST_OF_FILE; s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; s->num_file++; err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzipStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity) unzFile file; const char *szFileName; int iCaseSensitivity; { unz_s* s; int err; /* We remember the 'current' position in the file so that we can jump * back there if we fail. */ unz_file_info cur_file_infoSaved; unz_file_info_internal cur_file_info_internalSaved; uLong num_fileSaved; uLong pos_in_central_dirSaved; if (file==NULL) return UNZ_PARAMERROR; if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; /* Save the current state */ num_fileSaved = s->num_file; pos_in_central_dirSaved = s->pos_in_central_dir; cur_file_infoSaved = s->cur_file_info; cur_file_info_internalSaved = s->cur_file_info_internal; err = unzGoToFirstFile(file); while (err == UNZ_OK) { char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; err = unzGetCurrentFileInfo(file,NULL, szCurrentFileName,sizeof(szCurrentFileName)-1, NULL,0,NULL,0); if (err == UNZ_OK) { if (unzStringFileNameCompare(szCurrentFileName, szFileName,iCaseSensitivity)==0) return UNZ_OK; err = unzGoToNextFile(file); } } /* We failed, so restore the state of the 'current file' to where we * were. */ s->num_file = num_fileSaved ; s->pos_in_central_dir = pos_in_central_dirSaved ; s->cur_file_info = cur_file_infoSaved; s->cur_file_info_internal = cur_file_info_internalSaved; return err; } /* /////////////////////////////////////////// // Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) // I need random access // // Further optimization could be realized by adding an ability // to cache the directory in memory. The goal being a single // comprehensive file read to put the file I need in a memory. */ /* typedef struct unz_file_pos_s { uLong pos_in_zip_directory; // offset in file uLong num_of_file; // # of file } unz_file_pos; */ extern int ZEXPORT unzGetFilePos(file, file_pos) unzFile file; unz_file_pos* file_pos; { unz_s* s; if (file==NULL || file_pos==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; file_pos->pos_in_zip_directory = s->pos_in_central_dir; file_pos->num_of_file = s->num_file; return UNZ_OK; } extern int ZEXPORT unzGoToFilePos(file, file_pos) unzFile file; unz_file_pos* file_pos; { unz_s* s; int err; if (file==NULL || file_pos==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; /* jump to the right spot */ s->pos_in_central_dir = file_pos->pos_in_zip_directory; s->num_file = file_pos->num_of_file; /* set the current file */ err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); /* return results */ s->current_file_ok = (err == UNZ_OK); return err; } /* // Unzip Helper Functions - should be here? /////////////////////////////////////////// */ /* Read the local header of the current zipfile Check the coherency of the local header and info in the end of central directory about this file store in *piSizeVar the size of extra info in local header (filename and size of extra field data) */ local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, poffset_local_extrafield, psize_local_extrafield) unz_s* s; uInt* piSizeVar; uLong *poffset_local_extrafield; uInt *psize_local_extrafield; { uLong uMagic,uData,uFlags; uLong size_filename; uLong size_extra_field; int err=UNZ_OK; *piSizeVar = 0; *poffset_local_extrafield = 0; *psize_local_extrafield = 0; if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (err==UNZ_OK) { if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x04034b50) err=UNZ_BADZIPFILE; } if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) err=UNZ_ERRNO; /* else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) err=UNZ_BADZIPFILE; */ if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) err=UNZ_BADZIPFILE; if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ err=UNZ_ERRNO; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) err=UNZ_BADZIPFILE; *piSizeVar += (uInt)size_filename; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) err=UNZ_ERRNO; *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename; *psize_local_extrafield = (uInt)size_extra_field; *piSizeVar += (uInt)size_extra_field; return err; } /* Open for reading data the current file in the zipfile. If there is no error and the file is opened, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password) unzFile file; int* method; int* level; int raw; const char* password; { int err=UNZ_OK; uInt iSizeVar; unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; uLong offset_local_extrafield; /* offset of the local extra field */ uInt size_local_extrafield; /* size of the local extra field */ # ifndef NOUNCRYPT char source[12]; # else if (password != NULL) return UNZ_PARAMERROR; # endif if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_PARAMERROR; if (s->pfile_in_zip_read != NULL) unzCloseCurrentFile(file); if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) return UNZ_BADZIPFILE; pfile_in_zip_read_info = (file_in_zip_read_info_s*) ALLOC(sizeof(file_in_zip_read_info_s)); if (pfile_in_zip_read_info==NULL) return UNZ_INTERNALERROR; pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; pfile_in_zip_read_info->pos_local_extrafield=0; pfile_in_zip_read_info->raw=raw; if (pfile_in_zip_read_info->read_buffer==NULL) { TRYFREE(pfile_in_zip_read_info); return UNZ_INTERNALERROR; } pfile_in_zip_read_info->stream_initialised=0; if (method!=NULL) *method = (int)s->cur_file_info.compression_method; if (level!=NULL) { *level = 6; switch (s->cur_file_info.flag & 0x06) { case 6 : *level = 1; break; case 4 : *level = 2; break; case 2 : *level = 9; break; } } if ((s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; pfile_in_zip_read_info->crc32=0; pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; pfile_in_zip_read_info->filestream=s->filestream; pfile_in_zip_read_info->z_filefunc=s->z_filefunc; pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; pfile_in_zip_read_info->stream.total_out = 0; if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) { pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)0; pfile_in_zip_read_info->stream.next_in = (voidpf)0; pfile_in_zip_read_info->stream.avail_in = 0; err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=1; else { TRYFREE(pfile_in_zip_read_info); return err; } /* windowBits is passed < 0 to tell that there is no zlib header. * Note that in this case inflate *requires* an extra "dummy" byte * after the compressed stream in order to complete decompression and * return Z_STREAM_END. * In unzip, i don't wait absolutely Z_STREAM_END because I known the * size of both compressed and uncompressed data */ } pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size ; pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size ; pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; pfile_in_zip_read_info->stream.avail_in = (uInt)0; s->pfile_in_zip_read = pfile_in_zip_read_info; # ifndef NOUNCRYPT if (password != NULL) { int i; s->pcrc_32_tab = get_crc_table(); init_keys(password,s->keys,s->pcrc_32_tab); if (ZSEEK(s->z_filefunc, s->filestream, s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile, SEEK_SET)!=0) return UNZ_INTERNALERROR; if(ZREAD(s->z_filefunc, s->filestream,source, 12)<12) return UNZ_INTERNALERROR; for (i = 0; i<12; i++) zdecode(s->keys,s->pcrc_32_tab,source[i]); s->pfile_in_zip_read->pos_in_zipfile+=12; s->encrypted=1; } # endif return UNZ_OK; } extern int ZEXPORT unzOpenCurrentFile (file) unzFile file; { return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); } extern int ZEXPORT unzOpenCurrentFilePassword (file, password) unzFile file; const char* password; { return unzOpenCurrentFile3(file, NULL, NULL, 0, password); } extern int ZEXPORT unzOpenCurrentFile2 (file,method,level,raw) unzFile file; int* method; int* level; int raw; { return unzOpenCurrentFile3(file, method, level, raw, NULL); } /* Read bytes from the current file. buf contain buffer where data must be copied len the size of buf. return the number of byte copied if somes bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern int ZEXPORT unzReadCurrentFile (file, buf, len) unzFile file; voidp buf; unsigned len; { int err=UNZ_OK; uInt iRead = 0; unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->read_buffer == NULL) return UNZ_END_OF_LIST_OF_FILE; if (len==0) return 0; pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; pfile_in_zip_read_info->stream.avail_out = (uInt)len; if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && (!(pfile_in_zip_read_info->raw))) pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; if ((len>pfile_in_zip_read_info->rest_read_compressed+ pfile_in_zip_read_info->stream.avail_in) && (pfile_in_zip_read_info->raw)) pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_compressed+ pfile_in_zip_read_info->stream.avail_in; while (pfile_in_zip_read_info->stream.avail_out>0) { if ((pfile_in_zip_read_info->stream.avail_in==0) && (pfile_in_zip_read_info->rest_read_compressed>0)) { uInt uReadThis = UNZ_BUFSIZE; if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; if (uReadThis == 0) return UNZ_EOF; if (ZSEEK(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (ZREAD(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->read_buffer, uReadThis)!=uReadThis) return UNZ_ERRNO; # ifndef NOUNCRYPT if(s->encrypted) { uInt i; for(i=0;iread_buffer[i] = zdecode(s->keys,s->pcrc_32_tab, pfile_in_zip_read_info->read_buffer[i]); } # endif pfile_in_zip_read_info->pos_in_zipfile += uReadThis; pfile_in_zip_read_info->rest_read_compressed-=uReadThis; pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->read_buffer; pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; } if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) { uInt uDoCopy,i ; if ((pfile_in_zip_read_info->stream.avail_in == 0) && (pfile_in_zip_read_info->rest_read_compressed == 0)) return (iRead==0) ? UNZ_EOF : iRead; if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) uDoCopy = pfile_in_zip_read_info->stream.avail_out ; else uDoCopy = pfile_in_zip_read_info->stream.avail_in ; for (i=0;istream.next_out+i) = *(pfile_in_zip_read_info->stream.next_in+i); pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, pfile_in_zip_read_info->stream.next_out, uDoCopy); pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; pfile_in_zip_read_info->stream.avail_in -= uDoCopy; pfile_in_zip_read_info->stream.avail_out -= uDoCopy; pfile_in_zip_read_info->stream.next_out += uDoCopy; pfile_in_zip_read_info->stream.next_in += uDoCopy; pfile_in_zip_read_info->stream.total_out += uDoCopy; iRead += uDoCopy; } else { uLong uTotalOutBefore,uTotalOutAfter; const Bytef *bufBefore; uLong uOutThis; int flush=Z_SYNC_FLUSH; uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; bufBefore = pfile_in_zip_read_info->stream.next_out; /* if ((pfile_in_zip_read_info->rest_read_uncompressed == pfile_in_zip_read_info->stream.avail_out) && (pfile_in_zip_read_info->rest_read_compressed == 0)) flush = Z_FINISH; */ err=inflate(&pfile_in_zip_read_info->stream,flush); if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) err = Z_DATA_ERROR; uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; uOutThis = uTotalOutAfter-uTotalOutBefore; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); if (err==Z_STREAM_END) return (iRead==0) ? UNZ_EOF : iRead; if (err!=Z_OK) break; } } if (err==Z_OK) return iRead; return err; } /* Give the current position in uncompressed data */ extern z_off_t ZEXPORT unztell (file) unzFile file; { unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; return (z_off_t)pfile_in_zip_read_info->stream.total_out; } /* return 1 if the end of file was reached, 0 elsewhere */ extern int ZEXPORT unzeof (file) unzFile file; { unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->rest_read_uncompressed == 0) return 1; else return 0; } /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is more info in the local-header version than in the central-header) if buf==NULL, it return the size of the local extra field that can be read if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. the return value is the number of bytes copied in buf, or (if <0) the error code */ extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) unzFile file; voidp buf; unsigned len; { unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; uInt read_now; uLong size_to_read; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; size_to_read = (pfile_in_zip_read_info->size_local_extrafield - pfile_in_zip_read_info->pos_local_extrafield); if (buf==NULL) return (int)size_to_read; if (len>size_to_read) read_now = (uInt)size_to_read; else read_now = (uInt)len ; if (read_now==0) return 0; if (ZSEEK(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield, ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (ZREAD(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, buf,read_now)!=read_now) return UNZ_ERRNO; return (int)read_now; } /* Close the file in zip opened with unzipOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzCloseCurrentFile (file) unzFile file; { int err=UNZ_OK; unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && (!pfile_in_zip_read_info->raw)) { if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) err=UNZ_CRCERROR; } TRYFREE(pfile_in_zip_read_info->read_buffer); pfile_in_zip_read_info->read_buffer = NULL; if (pfile_in_zip_read_info->stream_initialised) inflateEnd(&pfile_in_zip_read_info->stream); pfile_in_zip_read_info->stream_initialised = 0; TRYFREE(pfile_in_zip_read_info); s->pfile_in_zip_read=NULL; return err; } /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) unzFile file; char *szComment; uLong uSizeBuf; { unz_s* s; uLong uReadThis ; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; uReadThis = uSizeBuf; if (uReadThis>s->gi.size_comment) uReadThis = s->gi.size_comment; if (ZSEEK(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (uReadThis>0) { *szComment='\0'; if (ZREAD(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) return UNZ_ERRNO; } if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment+s->gi.size_comment)='\0'; return (int)uReadThis; } /* Additions by RX '2004 */ extern uLong ZEXPORT unzGetOffset (file) unzFile file; { unz_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return 0; if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) if (s->num_file==s->gi.number_entry) return 0; return s->pos_in_central_dir; } extern int ZEXPORT unzSetOffset (file, pos) unzFile file; uLong pos; { unz_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; s->pos_in_central_dir = pos; s->num_file = s->gi.number_entry; /* hack */ err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } chessx-1.0.0/data/images/arrow_up_double.png000644 001750 001750 00000012573 12144113023 021664 0ustar00niklasniklas000000 000000 PNG  IHDR>a CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs  tIME  C< IDATx{lVǿwڷIsjQi\,"UpM$.^iͺ-Q/f s1%KX3"my9o[P7{iOKi|S(񇈆5# @Q(*EPT @Q(*EPT @Q(*EPT @Q(psm%Yq;$i$|g5B@A$+<.vҷ%ϼB3jOKW1H3QUk0yU^IIvaR5,-XπڮJ0 YxgmeOoOi5o;! %-;k+UÈk<e3cӗU<|<6Xzσ)t9FzS1'ڬ k69HC`'EYpZqdEJ6{}X1O" c-Ғ%lU$9o"UQڴtl~o~=< 0;ilU @Y\K- 1 z^G 4u7[bz-U b*qrLm? @ˀ XНrkiU*$մ*q.wGxtg'DB km>=a)k+{3)8<j݄!Z` vy?p(es!<>u02Sֳ 8]=@̘bj|B}f .V d@@`Afwbk> M]U!Ƕo? ;|"4-n@ |J#;r-8Fᅧ]O? *S0I7$<V]j&]l0f58f8`|Y϶Cf(xf|kJU6@W=c3f` xoB7&0#XLTd*`lrkyEY[ ⳓ/f& NJD q9@8Tuw-Xg /%\98_HӦw ʄf\5Qw4;~Xȡ^$;Fa+ϬRYc5/dLt!ojE'\ ؅9;I;*k^'ľ lnɣBwg?z]ab? AW` bv$pꢪNYC6akBQحtO1g.Uy0yGV78+ bL"a :,,hc/ު9'p G"]{ e1ru, $I"܆שyVrKo)'W^/o{ Ș`\; O =A\:e825;׿U2qʒ=s ]?~|wQ| 0hx%"E:z:KO|q FDJugH^s پ^|  ` z$9JuglYc%|ݖlo1ؖ@00S 8Fi IH'9S֮U&T[+PO/(:<9[v>>#qjF8 |5|rf(a`ʼnaܸA5Hm&rg'`2mI @bPBg0"*>tItB ?IA5p>O``c`8|.|**xA.CL #i9ur=sւ0E Za9 0` igE'A)E]ER0~ Q#PpGF:aSpX08~!n.UC~ EB@ F=@1B@`x%hpV@?# l ;$0ąC`NV+0 n(0B g*b$0 a(+ogӅ~ .~_8 *ۢ0/  q`-I$| `SP:<7> XC@@#,0|zP,@zu0?b0Gd 3 )k#8"H# _H0sv5v|cBPBYLxXIE8u> qE3'eCrX%@? 𣩒:?+iY)d @InFPEQEQEQEQEQEQEQEQEQEQEQEQJ-B)IENDB`chessx-1.0.0/src/chessx.rc000644 001750 001750 00000005044 12204341672 016227 0ustar00niklasniklas000000 000000 // Microsoft Visual C++ generated resource script. // #include "resource.h" #include "database/version.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "windows.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // German (Germany) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) #ifdef _WIN32 LANGUAGE LANG_GERMAN, SUBLANG_GERMAN #pragma code_page(1252) #endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_ICON1 ICON "chessx.ico" #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 3 TEXTINCLUDE BEGIN "\r\n" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION VERSION_MAJOR , VERSION_MINOR , 0 , REVISION PRODUCTVERSION VERSION_MAJOR , VERSION_MINOR , 0 , 0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x0L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040704b0" BEGIN VALUE "CompanyName", "chessx.sourceforge.net" VALUE "FileDescription", "chessx app" VALUE "FileVersion", STR_REVISION VALUE "InternalName", "chessx" VALUE "LegalCopyright", COPYRIGHT VALUE "OriginalFilename", "chessx.exe" VALUE "ProductName", "chessx" VALUE "ProductVersion", STR_VERSION END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x407, 1200 END END #endif // German (Germany) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED chessx-1.0.0/i18n/000755 001750 001750 00000000000 12234477214 014376 5ustar00niklasniklas000000 000000 chessx-1.0.0/src/guess/attacks.h000644 001750 001750 00000021316 12223260306 017330 0ustar00niklasniklas000000 000000 ////////////////////////////////////////////////////////////////////// // // FILE: attacks.h // Lists of attack squares // // Part of: Scid (Shane's Chess Information Database) // Version: 1.0 // // Notice: Copyright (c) 1999 Shane Hudson. All rights reserved. // // Author: Shane Hudson (sgh@users.sourceforge.net) // ////////////////////////////////////////////////////////////////////// #ifndef SCID_ATTACKS_H #define SCID_ATTACKS_H #ifndef SCID_COMMON_H #include "common.h" #endif namespace Guess { // NOTE: These arrays have been automatically generated. Don't change // them unless the square or piece representations change! //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Knight Moves: // knightAttacks[sq] is an array of the squares a knight on sq // could move to. There are 9 target squares even though a knight // can only have at most 8 legal moves, so we can end the list with // an "NS" (null square). // // Example code to iterate through the knight moves for a square: // // squareT *dest = knightAttacks[fromSquare]; // while (*dest != NULL_SQUARE) { // /* do desired action.... */ // dest++; // } // const squareT knightAttacks[66][9] = { { /* A1 */ C2, B3, NS, NS, NS, NS, NS, NS, NS }, { /* B1 */ D2, A3, C3, NS, NS, NS, NS, NS, NS }, { /* C1 */ A2, E2, B3, D3, NS, NS, NS, NS, NS }, { /* D1 */ B2, F2, C3, E3, NS, NS, NS, NS, NS }, { /* E1 */ C2, G2, D3, F3, NS, NS, NS, NS, NS }, { /* F1 */ D2, H2, E3, G3, NS, NS, NS, NS, NS }, { /* G1 */ E2, F3, H3, NS, NS, NS, NS, NS, NS }, { /* H1 */ F2, G3, NS, NS, NS, NS, NS, NS, NS }, { /* A2 */ C1, C3, B4, NS, NS, NS, NS, NS, NS }, { /* B2 */ D1, D3, A4, C4, NS, NS, NS, NS, NS }, { /* C2 */ A1, E1, A3, E3, B4, D4, NS, NS, NS }, { /* D2 */ B1, F1, B3, F3, C4, E4, NS, NS, NS }, { /* E2 */ C1, G1, C3, G3, D4, F4, NS, NS, NS }, { /* F2 */ D1, H1, D3, H3, E4, G4, NS, NS, NS }, { /* G2 */ E1, E3, F4, H4, NS, NS, NS, NS, NS }, { /* H2 */ F1, F3, G4, NS, NS, NS, NS, NS, NS }, { /* A3 */ B1, C2, C4, B5, NS, NS, NS, NS, NS }, { /* B3 */ A1, C1, D2, D4, A5, C5, NS, NS, NS }, { /* C3 */ B1, D1, A2, E2, A4, E4, B5, D5, NS }, { /* D3 */ C1, E1, B2, F2, B4, F4, C5, E5, NS }, { /* E3 */ D1, F1, C2, G2, C4, G4, D5, F5, NS }, { /* F3 */ E1, G1, D2, H2, D4, H4, E5, G5, NS }, { /* G3 */ F1, H1, E2, E4, F5, H5, NS, NS, NS }, { /* H3 */ G1, F2, F4, G5, NS, NS, NS, NS, NS }, { /* A4 */ B2, C3, C5, B6, NS, NS, NS, NS, NS }, { /* B4 */ A2, C2, D3, D5, A6, C6, NS, NS, NS }, { /* C4 */ B2, D2, A3, E3, A5, E5, B6, D6, NS }, { /* D4 */ C2, E2, B3, F3, B5, F5, C6, E6, NS }, { /* E4 */ D2, F2, C3, G3, C5, G5, D6, F6, NS }, { /* F4 */ E2, G2, D3, H3, D5, H5, E6, G6, NS }, { /* G4 */ F2, H2, E3, E5, F6, H6, NS, NS, NS }, { /* H4 */ G2, F3, F5, G6, NS, NS, NS, NS, NS }, { /* A5 */ B3, C4, C6, B7, NS, NS, NS, NS, NS }, { /* B5 */ A3, C3, D4, D6, A7, C7, NS, NS, NS }, { /* C5 */ B3, D3, A4, E4, A6, E6, B7, D7, NS }, { /* D5 */ C3, E3, B4, F4, B6, F6, C7, E7, NS }, { /* E5 */ D3, F3, C4, G4, C6, G6, D7, F7, NS }, { /* F5 */ E3, G3, D4, H4, D6, H6, E7, G7, NS }, { /* G5 */ F3, H3, E4, E6, F7, H7, NS, NS, NS }, { /* H5 */ G3, F4, F6, G7, NS, NS, NS, NS, NS }, { /* A6 */ B4, C5, C7, B8, NS, NS, NS, NS, NS }, { /* B6 */ A4, C4, D5, D7, A8, C8, NS, NS, NS }, { /* C6 */ B4, D4, A5, E5, A7, E7, B8, D8, NS }, { /* D6 */ C4, E4, B5, F5, B7, F7, C8, E8, NS }, { /* E6 */ D4, F4, C5, G5, C7, G7, D8, F8, NS }, { /* F6 */ E4, G4, D5, H5, D7, H7, E8, G8, NS }, { /* G6 */ F4, H4, E5, E7, F8, H8, NS, NS, NS }, { /* H6 */ G4, F5, F7, G8, NS, NS, NS, NS, NS }, { /* A7 */ B5, C6, C8, NS, NS, NS, NS, NS, NS }, { /* B7 */ A5, C5, D6, D8, NS, NS, NS, NS, NS }, { /* C7 */ B5, D5, A6, E6, A8, E8, NS, NS, NS }, { /* D7 */ C5, E5, B6, F6, B8, F8, NS, NS, NS }, { /* E7 */ D5, F5, C6, G6, C8, G8, NS, NS, NS }, { /* F7 */ E5, G5, D6, H6, D8, H8, NS, NS, NS }, { /* G7 */ F5, H5, E6, E8, NS, NS, NS, NS, NS }, { /* H7 */ G5, F6, F8, NS, NS, NS, NS, NS, NS }, { /* A8 */ B6, C7, NS, NS, NS, NS, NS, NS, NS }, { /* B8 */ A6, C6, D7, NS, NS, NS, NS, NS, NS }, { /* C8 */ B6, D6, A7, E7, NS, NS, NS, NS, NS }, { /* D8 */ C6, E6, B7, F7, NS, NS, NS, NS, NS }, { /* E8 */ D6, F6, C7, G7, NS, NS, NS, NS, NS }, { /* F8 */ E6, G6, D7, H7, NS, NS, NS, NS, NS }, { /* G8 */ F6, H6, E7, NS, NS, NS, NS, NS, NS }, { /* H8 */ G6, F7, NS, NS, NS, NS, NS, NS, NS }, { /* COL*/ NS, NS, NS, NS, NS, NS, NS, NS, NS }, { /* NS */ NS, NS, NS, NS, NS, NS, NS, NS, NS } }; // King moves: // As for the knight moves, the secondary array size is 9 even // though there are only 8 possible king moves, so there can // always be a NULL_SQUARE terminating the list of moves for each // square. Castling moves are not included here. const squareT kingAttacks[66][9] = { { /* A1 */ B1, A2, B2, NS, NS, NS, NS, NS, NS }, { /* B1 */ A1, C1, A2, B2, C2, NS, NS, NS, NS }, { /* C1 */ B1, D1, B2, C2, D2, NS, NS, NS, NS }, { /* D1 */ C1, E1, C2, D2, E2, NS, NS, NS, NS }, { /* E1 */ D1, F1, D2, E2, F2, NS, NS, NS, NS }, { /* F1 */ E1, G1, E2, F2, G2, NS, NS, NS, NS }, { /* G1 */ F1, H1, F2, G2, H2, NS, NS, NS, NS }, { /* H1 */ G1, G2, H2, NS, NS, NS, NS, NS, NS }, { /* A2 */ A1, B1, B2, A3, B3, NS, NS, NS, NS }, { /* B2 */ A1, B1, C1, A2, C2, A3, B3, C3, NS }, { /* C2 */ B1, C1, D1, B2, D2, B3, C3, D3, NS }, { /* D2 */ C1, D1, E1, C2, E2, C3, D3, E3, NS }, { /* E2 */ D1, E1, F1, D2, F2, D3, E3, F3, NS }, { /* F2 */ E1, F1, G1, E2, G2, E3, F3, G3, NS }, { /* G2 */ F1, G1, H1, F2, H2, F3, G3, H3, NS }, { /* H2 */ G1, H1, G2, G3, H3, NS, NS, NS, NS }, { /* A3 */ A2, B2, B3, A4, B4, NS, NS, NS, NS }, { /* B3 */ A2, B2, C2, A3, C3, A4, B4, C4, NS }, { /* C3 */ B2, C2, D2, B3, D3, B4, C4, D4, NS }, { /* D3 */ C2, D2, E2, C3, E3, C4, D4, E4, NS }, { /* E3 */ D2, E2, F2, D3, F3, D4, E4, F4, NS }, { /* F3 */ E2, F2, G2, E3, G3, E4, F4, G4, NS }, { /* G3 */ F2, G2, H2, F3, H3, F4, G4, H4, NS }, { /* H3 */ G2, H2, G3, G4, H4, NS, NS, NS, NS }, { /* A4 */ A3, B3, B4, A5, B5, NS, NS, NS, NS }, { /* B4 */ A3, B3, C3, A4, C4, A5, B5, C5, NS }, { /* C4 */ B3, C3, D3, B4, D4, B5, C5, D5, NS }, { /* D4 */ C3, D3, E3, C4, E4, C5, D5, E5, NS }, { /* E4 */ D3, E3, F3, D4, F4, D5, E5, F5, NS }, { /* F4 */ E3, F3, G3, E4, G4, E5, F5, G5, NS }, { /* G4 */ F3, G3, H3, F4, H4, F5, G5, H5, NS }, { /* H4 */ G3, H3, G4, G5, H5, NS, NS, NS, NS }, { /* A5 */ A4, B4, B5, A6, B6, NS, NS, NS, NS }, { /* B5 */ A4, B4, C4, A5, C5, A6, B6, C6, NS }, { /* C5 */ B4, C4, D4, B5, D5, B6, C6, D6, NS }, { /* D5 */ C4, D4, E4, C5, E5, C6, D6, E6, NS }, { /* E5 */ D4, E4, F4, D5, F5, D6, E6, F6, NS }, { /* F5 */ E4, F4, G4, E5, G5, E6, F6, G6, NS }, { /* G5 */ F4, G4, H4, F5, H5, F6, G6, H6, NS }, { /* H5 */ G4, H4, G5, G6, H6, NS, NS, NS, NS }, { /* A6 */ A5, B5, B6, A7, B7, NS, NS, NS, NS }, { /* B6 */ A5, B5, C5, A6, C6, A7, B7, C7, NS }, { /* C6 */ B5, C5, D5, B6, D6, B7, C7, D7, NS }, { /* D6 */ C5, D5, E5, C6, E6, C7, D7, E7, NS }, { /* E6 */ D5, E5, F5, D6, F6, D7, E7, F7, NS }, { /* F6 */ E5, F5, G5, E6, G6, E7, F7, G7, NS }, { /* G6 */ F5, G5, H5, F6, H6, F7, G7, H7, NS }, { /* H6 */ G5, H5, G6, G7, H7, NS, NS, NS, NS }, { /* A7 */ A6, B6, B7, A8, B8, NS, NS, NS, NS }, { /* B7 */ A6, B6, C6, A7, C7, A8, B8, C8, NS }, { /* C7 */ B6, C6, D6, B7, D7, B8, C8, D8, NS }, { /* D7 */ C6, D6, E6, C7, E7, C8, D8, E8, NS }, { /* E7 */ D6, E6, F6, D7, F7, D8, E8, F8, NS }, { /* F7 */ E6, F6, G6, E7, G7, E8, F8, G8, NS }, { /* G7 */ F6, G6, H6, F7, H7, F8, G8, H8, NS }, { /* H7 */ G6, H6, G7, G8, H8, NS, NS, NS, NS }, { /* A8 */ A7, B7, B8, NS, NS, NS, NS, NS, NS }, { /* B8 */ A7, B7, C7, A8, C8, NS, NS, NS, NS }, { /* C8 */ B7, C7, D7, B8, D8, NS, NS, NS, NS }, { /* D8 */ C7, D7, E7, C8, E8, NS, NS, NS, NS }, { /* E8 */ D7, E7, F7, D8, F8, NS, NS, NS, NS }, { /* F8 */ E7, F7, G7, E8, G8, NS, NS, NS, NS }, { /* G8 */ F7, G7, H7, F8, H8, NS, NS, NS, NS }, { /* H8 */ G7, H7, G8, NS, NS, NS, NS, NS, NS }, { /* COL*/ NS, NS, NS, NS, NS, NS, NS, NS, NS }, { /* NS */ NS, NS, NS, NS, NS, NS, NS, NS, NS } }; } // End namespace Guess #endif // #ifndef SCID_ATTACKS_H ////////////////////////////////////////////////////////////////////// // EOF: attacks.h ////////////////////////////////////////////////////////////////////// chessx-1.0.0/src/database/enginedata.cpp000644 001750 001750 00000001764 12223260306 020753 0ustar00niklasniklas000000 000000 /*************************************************************************** * (C) 2010 Michal Rudolf * * * * 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 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "enginedata.h" EngineData::EngineData(const QString& newName) : name(newName), protocol(UCI) { } QString EngineData::commandToName(const QString& command) { QString name = command.section('/', -1, -1); if(!name.isEmpty()) { name[0] = name[0].toUpper(); } if(name.endsWith(".exe")) { name.truncate(name.length() - 4); } return name; } chessx-1.0.0/data/images/filter.png000644 001750 001750 00000011134 12142254551 017763 0ustar00niklasniklas000000 000000 PNG  IHDR>atEXtSoftwareAdobe ImageReadyqe<IDATxKluGRFR@9= 7EA )z(IOvvJ%="%9zk'rkN,QTDOߛ?\p̬>QppAS@B (P@B (P@B ZXӂ{ q0Eu1/A,W/[h>#tYͰ& C'iRРC:XgHPЂ6Dkr|?^f=g2k֎mak3<:#5<^w5u Ac/O&~Ç{v&İ0ab ͍T!h4 j#`2̶pMzMc:sQg)N :ζ z>L=m.PJ6gtoNA<~ &íX]]ڜGeaL ?SZz8k̾x0PMץ\jMoz{{J{ejx)u2 xVʯjsfģ?f~#B.{qd/G7-ݤ^ *ﱝ\#d5azv*(@PWS A߸lBwJ]*(Ю .A:yM}%AGRa_k'H\|/&pMNeS ߓ6+ۅ֏";=?eu=֮8AuGrN mתuGڷkOg.b,5کA34O C݃uׅIfz\=&7^ԙm^z-4w[/_edP*{xVcoWרUh?|,8VSྀ[=?@'EjGrUE #mAҭx$w7(n ,mH@LMoEpD-FA91Nr9BQ+Љx#dkpsXNB_=uufhM.!@,"ټ:&Q5FX.+=g9k~P9l'a쁉q?>z02 HxШ0>WȂAǎ{4+2,ap@ <#Huy"YTML!rt\\ʐS2&LCYcnY)H&IRt"k55l5Rs9P㰄9q9(G.ծ@ D*($"GGxuY0߁~ b|p5*%p)|dllN%3*g}"z꯿o]fP"]7ZP+dQ&ї_PYf_b /ؿPu1DpNڇAx#omm|G{DidS)kr] ؊uy@wu!fDIGNdHz;d!i=&c;x>އhN_ ˬ7~kxUld"PX'33'?.W* nWd[D"@`RdI" L)`V lE@~!lD@ sVMEW!˗GN`g( d ǏAm;ó).}B7=aDim&}˳4}9m~Dc >Xo.BDzepq_xEzN/㢋lꈧR"\~aСCdtt4:+o!T0@A"w d2~gMt&!"[>9(*әU)H@UP**fB t jHrhh+.\.ip3gO.>& 9I88.̩~_Lͽ,C4]XTwQӅIBw8r d>ӝѹJ21;w~}ؘ@V258a^{a80KzGWRVvqmlOT]oEhSãKICx:>mu;Us%qz"? +9?ӒKXopH$MY ~u">;$J~JOvbR(K6}q;L:[S uڱߥurR99: nIux?ZpT֒P ?׉91Apuݾ/$z:?Q ucq/^4/PHSLeY;Y`qK044L?6JVV/XE${?%|`,Z蘦o (rrvs @&u&OJ{)_"E¶F7עE^x3zue}`Dbwvms%mɳAqY븊Y3~Q#S/Z{ Óʋǎ|~WHlm* _ݽvk4b;^H v BN)"x _*'<;L=|;U @td{_MVVV`ygLŖ`hŷ{hN,ˤ2w"o"}ԉx3>ԍ&O -Ȯ+ [K<B''z+V֎?o8hݎ?!NO=#Ć> -Ä#kɟ8|p4'{؊|}4qG5-#?/~~O|MoN,o؈_ G (P@B (P@B (P@A )3_$9\IENDB`chessx-1.0.0/data/themes/boards/cherry.png000644 001750 001750 00000264536 10633750627 021314 0ustar00niklasniklas000000 000000 PNG  IHDR/bKGD pHYs  tIME * IDATxTݮ,ɒGD>@Aԅr! vU0ZM ]Ucfnn?QYQd2,?pgG`f p"ƇqC{s]/s3$v2|D$AcE8*)s $UYC> ƸIwy~QUD& 3) +}TlY3ןWƅq]$n"~sU1>#6ƀr6(TcL,CUꙠߨW=߲07ʌqן޿,Й2+2*fvd0dȃYbdŊ.̇ ܝUZ17=bc]u1pbN9>'Y "q{b釧"!,=Ч)Mjf id]ߠ8x %f/21w0w]wp3_YQVDe - *W`P * Ĭlt9s,pfEFA"S/x͡7Y @490`aLsU9;׽H,7fU0`>2p3)8;c 눃3("7O fΉd`.Kԥ3Ü}|RX s6](f鹐X%>o.uלwde$'Б(8Od Ha"T4dnF Peds<1)*fA&TsN+e("aK4 h6:%xu:1q}ͨJrCIR$c`t**y!r~{URUXd޼Or ˍk^Ose}7([Xp aj 9e9XO`rlҾ9Y1,cK0&EjX%ɽ7ctJe'+  f>'upq21UQ w/فp oɼI"RddžKrmϊs6TØ9[I6k1 9EIɉ57X>)Ü"#K/?qlȤ28pawCՠ0&%A!YU* R6#*(=f~A:dSe";'t@iOJq܂:}i_=N&f̥kzRjtsC) fPLA֑yy*qs όi`gAAo`c* !9hU TܱR~o]4;91;D_9닪\CQ}o|Tc'q)#d`go{+rafߘ;dFg}t0N|3Gfd:O_D?WˬTmC4YTKʻF/]W'uxNxqs`ʆ!!|md[@Di?1YSϰXͪaOY:e%L~f0WH#rvwħ.S|軙_/Ud02AWG\)_Kϸp2}*Xb~acrzPt{JF>ӉR?a>2u(a}JpYɰ˜yެ$"%5s}Q` d|t!ǜXh(3@*ݫTn>d8SYd#=W϶.ׇzsJ1 L9Y[i z0ЙwעVHUFHmH-/5ZFkMvWZ^R0Ռ8aB9TnEܓ}|0ܹ-4I*Q>d:V70nj*ńBcZc55/ܼ"OIe]JT0Uu+,.s\g~ BA )q8YI$&!$]J*2Y Trު(+֓M32Ow!gI>ҕG ==0!QOvE~̋9N?P>KkE?G2`#dN, ΑlL1ǻ9{Ή}F 4+VTPSOG(bVS@(QdVw)c\#jtg8uTͽ~cwh6n`$4ƘA»`9,Sc/:9O%#D̼13)QFTcM*]M.) }`goebއ]rX<»Q]MG%Ř~WTRMdnw׫az zk-N&~J*Wܕx:Õw{i lԣʂ,àԏ}I>O.QL0'5p s^6Tv#HA10NS@-s kO.AH2³h~` j'\$Y ,؇)6BWvE֝c|J~" *{c~a&eֽ4bSsD~^š#""dI߻OufpB].Dtru nOiKE&" yh7dvApwaUL7Cյ `N k%B5 N0֢R5v3T y ҥ"?wCg[19e&2с[(hdn l6[-!*7(D[R``sn̝ךjv9 =KWDNԇ+}oM8\͌&p-ݼk}ޛ e qZ*vDP)O2U<.wUKZ誊F]ۊxU$RD|7NߘqAhSuf/;ļ IUǿZP98wbR:nۓȺPc}u SVlF9apj7Շg)֝AԀ \wOcf&ԲNb 5YDd(A!^EÚXgLd!Q2wĭ"U">Ș!xR|U&ȜWùQ8z)9 DO fμ.]&'}th́Z;n8sr*LY8~!<"8{3HF5O *zO6d4hͩ>7_(& x Ht c'Be1:Ҭȡºlsjd;$װRpc7c\RtgN$+FwFsc&>3#)˔ uF `|OT,3oh3N7Is6Nec\jPE8"kltTͽDl/~N6@Oo r2NgYm'a%0石c~s -=߭&(ιlфQܿ4 y!9I"%Wb&QP2^=e0b> Ex,SƊ7p*n8'x!.u昊f4r|ᾄ ̩|øoܝIr!MRgujJЫ/T"stU:fC3id%`d@A#=Moaeؼ&w6ɇ_"XBhFqPGfZSArD4SQտ=Uf4-HSep[|Jc-Wpʤ9::Mz"0E"gȄsD?qaḿ&b3Q9=j Ǎuy$*FkHB*\lJ2V%TL};[P ޤll>j'26&͒~5(n8b~)5r;.tD>I4d]Tu'>GW3C5-)S_9! [ݍQ`cBc,-T?%;jw>l8q^ewFf;ߍFU&;:":}}I#qc>.G*>5I\R$;sM/7> -j&}X 77Q0 81}7'unRkҤ %73% !vcw R ofp睳ːRR ?T>z1Z*OePnĄρ&̧:mSjN.ڣ5o \E("S>꒵!8T jeTc0Aof1lelvsDOC%`d~[%Pdt 2|zYjd1WgO8\lQkeֺMd`U6 `ϴb0җysݘe'#K|NrVѪCut"YcGnltgܪoSGUZlQ4vTqG-L?,#hfX(7!I ޛrZToQnmW_:oW2n;a&7|҇)S>6s_XLFʬY꽥  ҕyGcL D5c&f>DхqP'Ci1@9EY/̧PkH!#2n$R'{oTDK 3YY~ߛ*|V9UNh^ _ *n\0Nȅ1% Kig')"Y >rf*OG&ނldAݐ=׀>d$. S|3T485ւ?s'=*?̍bRRCF*.}Gv#r赎BDnfL!N_] Zg&_ѥ1﹄(JhG@y!ʪws(^:I2~6z-j*LvT1L0j6 jQU@\ [2d8qw "' ThhovOu<'_#X-_Fbʼn7Eƨ} |}wdz7g8 -Yta[W4EhQ#4vOW 6Tr›O&(?-4eCrhټga"?2^*O^1Yk38&릎#K7BF$vn%qM xۇlH)%$ppIu_4@)'y#nj@RZ g䠒CdqRB}'O>yEBrbdA$ب{׵4".UV-.(QqTBM'A Lv_a m+5vWy0V[ "qdJk4VUư4hP![ْ<Qܚ&!S:oKUHe sѐrOFk jȥGs}ـDu]gAqZ,Uݜc㧦i7߷h~3ZLO"er2եi#҈Vf-( I >2 :qHY+ sL>.1$|]Δ1&xx X/I(*VFTÐLXg:6w3-B팁Q|iqԏ6(=$o=ٚ1f}G>u\IM#VzsJMT!ph>r>BGi6^'(~$џ9eh Xj*NgQv<\!S أRBÀ9ɷdEZ=88q v='#wuu]]g%px@Gq8əQ&XCe4%[3ٙꚯITh-2 BϪ8[_Zmץ"n}>KK6ZqP9-Ho"~҄_O@Fйy8b ;{"[!db4GzEhs[ XEXO.*%GP Gy[97m;+_}9~G?hQg&#~K*`ˉ.xLbKblBN15?+Sr9-mhE.!Ed"i;n_6H Ѭ7\7=!%3<3Є1Ql|^&ճr^PU9T3Fk3s+IZ0Kj*OOqZ^6XÝM`zdsB iD4LÜ8!ht+icSEt; Kl>]&ɼ&wj?y߼2&׀ج5L0]|2I&.YDrS̳ϫ-k;^1_ɜxx(8%Hp7k:o33j& _jsa&k(|z]Dn=y̵gMjBs `DeDCH)2k5>bŹSŘ?ht؄W3֕:'O \T"-  X5O?Ja*"i>YߺRWe$6VUBz5'Mz*aYnLճ$A {h=ah%lީ́~7y]KR\׋1Z )Abg8*0>Ře:q.2[!q(Hpl0u/5Ce 浈%y5>M)">,1GE2>Rk%󼪵hz߇yv[\ߗAr7jDia$Y0uS'-5S4T$<-qFoxGkj|4Y7]8/ecӓz͜J,"so~0-_ɵfQ)ؼM,|HggI.De&{gU*F!Ǖ]ST*sp <%-sjg52Tf@- IDAT;\%)c$3 1g u}}He]HRHpz5!S#UCqs=Wg\C%qh3 ɉ%P/B#h#z_X֦cקS7 3(ܭA"?N{q33ivx 2>>[nh_cÔ2+^)9zDrK % s+t.D2];͚뺸{b'p6ˑ'5G|Ieط.7-1\]9ح _zz38g.j@'w̔l^_򢈻'zsKAؿKCN{FeA+e2WR|3}x)_Hk]ٺX?4W݄юs~M!E>[jQNbtzss&TKJ>~=Fq>Dx~;[ 7~}uMf CKxOvHcccCfO.NzknL[VGR̻jI} zJ\=)'|fꙺ3]r9g{i{gϑ`Dܐך4.輼gir^XzFi Z&C;95&;%ߔ _ח_9(9+0>cO-[sTJ?[p;Z#ս_z9~fʭ=ml){}$hXp I^I)9VcțbjH̘8 YsM65XW[ḚU+"x. #dwVrvUr^#BMR=qiB8]NJ ._|ɆbW!ekG{vkR7|o~8z߬|]U>CYB N^_{jM <}@kI@޲9YjyqQuTµ=O䜛"}o`|cwv0ǚxG?ś-+S 2"R*]&Jږ?T6>0OSk8'?ZrHO|{cs, >Q8:\nG$`ufY%Dq-E#WƯ埇zv9״ O$d{L3F+}3b률6FFLk i+ 1} u|.P^$Ý5RrG1]7*]YR@14Ez|ƜD@Y,MkPإ*:TfH&ȻK_bhP/H孆sXfzL 1_504|2*IdDscbl$|B˧C9>-KZvj%95d<ە㩣ɲ7ah vFC.{7c[%}n߿?O *&;(Hr59.v s,ncp77cZcS]Ԭ~ktH<:`_ ~fM|=\kv 2P1eLw z2hcړZcb_N {?f}1'x-kIWEZf}ziF3ڽ\ƁRTOɾv |d%yiRIY`=eAXW õ?~]GSN4Ksa&H3zNum^V|> "O^}ERT jO.>/4;h/"wX&q~3ݷHLhL~W̜~{-FQkxU'v88~hzG jKk=*~ fm4l|v?M2r Ǫza+=ujBN?^ª8L}Q&n8,Sb8qUjɂ{8oaDEV t/zXAZp9=H;.F<IȞnYuEa,mA ~3ZՎ#>ʌhd-Onek =G 5~\ $쩽'ۮo݇^Oq4őͪL'4#8oqpW^>ЉM5g:U=w#DHV@EzO a<;Pnhi"^3v4jgL$Ḓ"@6lP]&6T[,m\I9vnT9KCU<>ǫXda̿^Ih{ZYm&p[A'v~]b;%{| Qezɗi)=mR8uq}@ QQ78Gu5Z`/oѐt)Dh~%s:N\Nܠ8[;9+9~Ldf,:C4IjaP w4!t2ՇTIS }Iimpx]D1d9kP.IS˵. eDKF8(;[a֦قh ڗTs< nK6DxV\ f.H^o@Pt7\6E٫'#GҕxH\qGHrb9 Ӈ584=[F4)5[Z|o2ߊ|\GHܹ=8v4LA-$촡aeI:ô:aTjNﭲ}1YxjX5رRV5I2J1dxV]? vdzZ* R3sX°vgDqgZ9_/hYKj\V,%0QyFZ8퓕~KϷ6-X^6ϖB'~CM^!]yZnż&$vj]Yv?#8[2؟hq>VOeEcx|ʫAsVkɞt_Cn,cYkեm.]'8!k%cGUf`^[}|kɍAv)%J#av1,ern_KIBǴmnjث[g[ȩUjEVTШqnWxi9GJbϑ9@0iƽ}#4GԒ"XܒR>cjqM*1_XcǴkipr8NzϚge7?;gch޽PZ݄1`izk-e^k4Qݬ` r!x[v?_,WJDӱ*m ݖd}͘{`< l/aoK`>slm܋5hlٔ8F$R⸝ciTv5ا`BrJq}A򫹏͢qMo'yxvkTIlZǫ\#߯\U^`l FCiSkVM}qѪgXLkK`gzT6w-zഃITO a`MzSz:z5HICڧOzĄ⸼^-i)578`i9{ы|pGC9sɓ~v"a_\?s]]mJئy'=Ͱ<ƗߩIޓepǒG-|`>,P:Y^b+eҰJ6dmGE%wTo*~,3WTqg{YMm"gSQ ǰPY۶lPPpNmK\:*aBh$k@^0lI?-x{>i:JsZV솱jze"zVF ̖H%DY1w0<Jʄ޶:5D~K1ս{#T3̂0 clXmI,|IQӍm|zkgt1NloY\K}[ YMS͑^'Xƾ̞nnρKrL8=1ݰ\!r! Yғj5 =8T3wy*sXt#'F6)k?Vy$3a~]&{혁_ڶV!XV[ܱ>kR6xG1~j}l:,+\(kM_KheڪAvbP.bs%ׇJ82/y䁴`KzVg腢|f>A2 cWBނ{Qis00K%؆lG=X+$2aG3[:Lа%wwzA"Dwz=ccƝ| MFp4sX붊לm*,?K+_ӊ0?zj;f-$|xɚux]_ }~]CKC6ԋ>sFz<Ƚ5춮}l<.^;fɞ0Ыy?>)ѩ5R#NOڍv{ӂ{U3*Mԁ|MeMgTDc%8Fa Qgg\XɂB;1rJuj~)b%&(Y/ iK#لUϿ;M`~ӂ'un%evVqv{>&3Y~IgxU=%sٜ W+ zJ@] oCbƩ֐`Sᜳr;\=Q-DZ8_\evguƮg24JS6˲HfUs..̆oEȷcTp`ƅ*%m0:Yell-g13qs[JϿX tY_cZlֻt3.)ӇڥPqghI#lZl1߈6Ի(sj޲N=@?c3,ϒ`MG~I%aH6w;zw95YR:K@ %=-Tiؗq3nؚV^tâ8;`V \Nw\gQz< Y t(Yĺ1~{~4}-d\Lkv q,:<5G'I!{Ge? Q PƅCnִeE_ZaEt y'cb/ MFb`-5o )K46Mi_Kմ cֲGA~X aYлip;fct5uǮ#ҭ@JNǕAI-vSYU b 4\pT@Ϣ7$+У>G 3)I8a<ҲY>,yjʛ8Z)-UaoDʪOD..I=>NS 0\zyU??Ҕ(&>C)7 =(%Y}M,Q>4F%p20pTa|&粠ښy~ 3|ngbB; u°fl}'~\_ǩqJ#$K[%X\"ľ*8m7É'c Lr4ឋJKqg#gɋ#7fs2a8f?j<쉸:PS(Bh % iȱPǁ &iM4..) ӂf1*r Z8Xp?{.\msS5Ƒz s {,0WS%^'"6ʙW8T3;h x Fh^x/ Ѝ'PS*R0m5"5B^ ؇q @4u;^8Zn\B$(wWſtZ] aZ";ͅG{0^&li C3%x*jksn0ء*E)_f6Ln-j(ZE+In n+Ih†`hX>{Cޢ(AI+8F/\PjByZ@19b}s_ty IDATf]5h 3 |q'h8Kk.)@k13X8 ׄB[4OjFF^5*8ppxP_t6'^=0n؁<3)5(xtO@zX.T3c *1ǞLL| f80:uD*,=հY[fA""9յG?=CBxD|fk[H(B)Sq.xe k,RH)GO:Z,dE̦b"yi"2d'CI2aA۲DHpS\BͅX*-KNϋ+tKD<Ł8Sn ːc!1Xq_SCb(3fVDvb̉o-4Z,&uX˨# ~=W8{ʏ!X4ݘs7ERep:&9i Ä/E+?WC7%f7qs >o4fGI[hd\\8f9: k6B ̥vt+XC92]-iX,XAu TPх7;c X ʑ#cÕXѿé}>NaZ JXؿ/'p8:K2 w!Q:~߆?G80EڧܸjF9Z-l?<2ȼrQ,y:X`(s$G~eGLti:l+Ӕkv=Y@,EhK""?YK1'k )I93aLο%,adFK%č0xc/ʑq?P|q1, >dT\R3t\R]T_xttn׿kO=Iҍqee8€EE#h Ý{믛@[ 4LDc_obu'5(Vl|3Kx:Ṿэ4>sI^LR $-ԢmhmQEK (P莭o;]qI'a&O<F%7/2kI!GcfG;;pmE(5*U-i3.TTr%'Ts)/+d6T9I3&:6H8P9-=Tc7 sXkט@8AEnl}sl>FRABHm 7dGŁ39J8j8z×B ';wt*vhRrLnI~k8,]M)t9yP)#WYU(Di>0-m>׃9 gj?$*LdOƓJ8m6yM['|*[ Ou(Vq&\j־0n|)95)c8Ό/u˵G OœoLcrTVR88uK/ M^h,14Im oC*{w e[4ůE:F?8Pƿo}VaL1sBX_ Ds#g|<ǢQf,$? Xt X ,YRE˳m*#CMK-OTy7ͼ?a%\H+haIɆt3{.߈r 7׷QNP ۡŮ ;3_YBW?Eidm~ 4j dĀ2(d^P<"ŗj'(-1wE7R8H\p4 &Ny:2e0>w5k'%;wV%KT<$3 l6sfx_֛^ EtqNrI@z~/ M{p5r  sPE7׍ub.T^ADg>LixrʄJFWlq454S[TsFlT2gkN'MQDv&z<>tgr°R4meu,Xsm=@rYzZ=S[N3M~ْ΅憧1DŽ`ىQq;0,9{ɧpY$*b>saNX6d.x='[E x.گ_")q$_`᭡`bF i\39rp1 !K Ȕ FR`6#.)!8^YhxyWIjX!cn,Z|7)e.lE}JxY(/ZX0]ms{wDAgqe[BP`@=wɀSLMDRQRy?hhNEGqb|9q jЩ̚7E9f:P(~/RΖG7!'T›ޮ.˟2V)~ƃDc:R냄~wc>7)m J͜Or))ŸLQq7),QѥhșȩDFI,8:t HCɜ8Z~:{-z=qJHI"= +} {fuCQ9e*v%0_:s񘒼ѾKRa+ۗcNHu/S8MHn;ீPheUq_!TSsI͝L vP =5r` Eh \YU,K̼jWM y㷶dr*e5Y$,K wFCFdŗ̘ѾpH{at;a!՟I  ӀP p,/^=Qg?#vzCk'q8~`WΉ7XUnmH,t-5Caz+ G3 ynR[0w#S"0jmB;;n;NDhkbF/IUqC06n[pȶ!lrє5 r`wuIkNX#a&s~bh!7G‚{4F==Urjyl4[gR3R!~ZHJlT w~SmZDiO8Kr7s0x {>xʼnYAS-=]aN s)$9k!sC?u19 mps %'Ш b!B3s}[FF{,h]` n i$p!ӗל J a]+(J/ijQ}3 \F;dL~} Ł ԭ$j͒,EOG3#Ui/*o /NL H g4p(|e]TG8i|L~>Ѡ@٬`oUpzs oN] 7civǒY l XXSF|ҖLhwxQk(PESK(EQ;ڡw>^B`߉Q@ *,Y$)SΕ i%-MCsTG3Wd}N cQ*!=7JxLWClc푵&IњK阅%R~q0{MDF/8ZvpkMufZ:#1s{߰pL0,Ě䚉aBe̦R;Cg*3/; +i1=ZgKGoHbҨ?p[ނ/9rSi!n6K\A:r{~HkOβ NX΁$#.+wAψ@-UubL&*AMQXD y@OF?:,t"6$3~60-yeB~뙠{Hٕk]T wNF`0. y5 g;a?$f4|7j=t*)< g 4?jҰ~%`"uC;zF_z*/["Y"A]\Q3n변x=y} ۑP.˸A#bO9 \ ȝk]ܫ X4XܣaSi2ƨڿ (6Ks2ڊzGlKdf,)ti/xk1QaG sY7MmZɢ,> 'mOA ,H822TO1J?_7:kkMO 8?^νD/qȢb{/2t){2NXj_vIɸЬt TPiOmח2Bb83LY i sݤZxa.Z1X&zb`,|t}?$^]hgW=u=KlFp0]#Xnr(\r&r98  k)x=MҦyc-x`~4bYAJXY:4!Cg|S;KB_d֒b!2lt6p99bϭ-6X[Ep I2# 0?>2~H/V CkyFk9}4٦4h'Vh!>6:b.f9ƍ6b?N/И•SPR. f/'vE,hhM6-hKMX[ `ѻ+Z|м;yO>JB7`9?pStO Fm#':\⃷vK'"8iNVJɘߛ9V [@0Dhd}Y{s|Ux"[Ƹ k'5GՅG|\rU&f0ۭ5 hv:ҚAHL0m(,8E?uNJU2ݞio/$@FỄZڪ޲߳"hyD L%!4pqpi&-D*tsMs K0Kyפ:XFY6+Qv_Bf23|7AQ{^J U)њBa: x3JX+3Aڷtx2y_O{hΦNo悄l(/g:Zϭ=ЦQfyTTsXxrJk6G3s^xc*у/i;>g=~0B]Դ3T&U;Y̋bO+G?@frv&}55шD<'ۚ٤җB e l.{6_SA</GE{D&Oљ)/W76I[i8htEIho %njS̝N+hPgmK##sf;yLVʬ1L;]QbDcˇx&VjjCzfRIPG\_or, \vQ J!,]\ ,h;nZG^sfCij ko--,8-09oz#L"z|bK.,x|5z&Zs b7<:V^ sܨq1ENް&뷧AJ|4"Q17uuSq1X5hORֽ݊wyDy:dj)gҏQoa\7op;y{> 7j`@̏ ?? v(I:ؐ{5RԊVޘUR5F+Ћ.?)ZȎZvCKCA1C:N64'*oR#9X \}LNj'}<$B1 BEa=Q?8_|Ԃ%Ǿ랄H ˩L}G4k.yK.(Dsr} D>讟ld͘P&\[zBXO#x|;}c܃9R (Oeyi`tq6ʀ7*mc 5pM?iaSa1asyo#stkXX90Dxw-;1* @f#+^?/?/ xvjem`qR8XNAf,}Z]K#t{QNPFɲDl9o6SbFȥ.n#uM҈ssHƏK1k QF GkIv2+H=*kՊPsh0Y,IK;5\Ȇh撰S5K~#X'Ű7E2ru*ySχk@j*獿B)ݱ:0(8f['WJ-L(ϸ]bl(YHoo4e]lU0JM%!IScb 'S9#oIHE ,¡2 uL||F?YFIq հH=ć:nڮqݥFKT6L-Ѷh8΀z F %Aw^&唙'?EֵE4T ̹Z]K.C`%Cߣ݋7 Y.M{*$"CYk#PZ+gK\Πqle?'r3\u9:BI$6kLoBj8+:v9zU&)DspƆ.8Z [RD(yr>pI}|I5,/$w y](_Vv<o>7߿/Xt[+uAKuw!u£ECҞ`ƞ4bsͨ`:!ۏ)XFs:vUD*}߲7WJ]̓}-EX%oyG$L_S:F#r%f~`[#.¤PQ2aIC”+Ƽ  ;rwڰr~ud^&$Rs} i#QlРd@~ָq߸׉o ,B4 ҂K>ù&aMh\$4V?ֵxPC9ET DoQb"~04if}2.1E>[+,J-T03%/o=( Gadi՞^Mǥݡڍw-Zn~_SnA0h*M7"V4u xi IXNw܃OxMŇPhўT-,P[/]zg ŏ{;mq{^C $oW.X=qPB%Z|t "k$zC B#č&P^=%bka_F.qei=_rLVa Y!ten@}6.Ms뱘Tk2{gdB{ 3T^uc&^9Sk4gU ?vik>B[Fxq@ J `YfwCUC%\93'w(5$covmϷv-Q|"9GgDr%3BfǨ%~#V…~m.\ e07P*U&aYTM4S2_w_hŊ$\7 E\q.nq'n)ʩeZ;F|e Tm(R)!b~P&M˗h~ƿ71ntd5 !T F٘{"<f,̗㤼gR:oa=Ѓ?pqẴLs&k RFC /=#~`|v[y6Fv췬6% ?8(fH/бJ NPU/lxڭ@9!(gc-򞰘hDr;9A.u߸Qhǁ8\R<#p74?XږPnY@CYH&""-c75y' 䡚Ղ BZ,/Xv>T]Em? cʣ\|zj%));_>,c<?9N-PDn`S%'15"pxmjh@+Qn޷8 D`  ?T׭X,5\W%p^ mu촒WFJ(Rrh]&i4Ysm;#KtE0t^ JXX;<_䖷Qs>vpGCV[1VѓJ6z!kb).\ xqRT 6ĄDJH_FϽt+1'e S=\{%PJٜOC.Ц^= J-^.Ԑ\cp|p͙Fm>L* Tt؂)=./vw{ME큶Yd5I,\ϓvpE&iM!E<ڜSRtv毼e?uS!o$"~ѓ^^8zǼϟVQU@s{[\\ru7L\mS?#4m&'rs qLyy__{D!(/ 00T8ڛ-iD%6DC.;̙G-0[w;o`0(r`ꅬrUޢKуkd:T+S{c_6i+N+?1Wl<5aM)M֘5lM_"=sIj:sHP'#ZכΜZ(L=|Eh*OJV[ a8 qcĸ'qP<#NeR"Zg]RF|4OmN0M\%AOZuXe &+4\eպ,bH]!YP\p.yAbV<~ wv,^¸'/G/q"h@ɊQr+BeNې3PBF>ͭㅵOˢma.y4+RP5`ƍm8ܢ|d.||d-}e%1> }fuQk\v2ƣಯĩ66 3T_Iil)b{K;!w>3/hy9ߔzP׽-㬐*qOMS8M%ysqc|hCSL3X_0.KA_VnF hd$bɀ4trVbs=,yN]ldU0Mߦ/B&wrDwqvFvc1σ0>wMx{e(Oi&D$ʥ郯Vm 'Ҟ^R~#MoFKE>Ul/gp#;~w_x0`IML%Df >2ܔPk6BփF=9GELjN6;M5(GNE@˥&"SGm - \9"hi9Ǎʉ1 ?UokI,i{Ddr%. ͜+3aꪽʌs41q`<6Tc0weu1SWCƙVZ+q ǚ7F't-{葁x2h^V$nͥd],vv*1`Ek* u}pސ[kd@8Rɍ?OHt% vNN|$XRr#6Nr $+}`^)v]x~^"N Vb0q:ḦS< ĕ*;ͥ ?dQޏ뵯#:H^/6Ʌ0V"CTEH܇~ڔ+BL25Ioߤ콱~!-P[PgФ1{ tc~aŔ#z"򅌆VUg7$y]p74;yUgHRPZw4c8\.XàaѶX81f&٦x ~BS,+&R&<a%s:[a;$r%\jG;D@Ź&Pm4c7v ߂e2S `ֻ@KdĽԪS1Ě^O׽?lH-ü!YAiB{x e>-Z܊L4B P,bJjdM$fz/fS_N\ VǦ!r- F6c<9B䏐 SAwG9R`8 xo;)/1v89inW< ` h&9\6ra;^{׮n$8HՔ+NZpKvk6݉1܌ۃ5~x+dVM@Ŝ5u'SrZl9=(E~<4r\+}n$y2s|ĝ|)ΰ9HE&j۟LĔ;3!k>Gx*)>ObJ#2n^$}~;Kc`)ϙ=/ 8:Tz^8N{Y7yyr]]'R?J{J QS6IhT B?C {i9٤RuD>BX A4TlPQ'b2IeKz^GG-1{ thi_zZ#.1u\7hE;kC[=-_@ŚKFa^ʕH4{хqq:-PwinsfH1eV _XBn̪!W&/fqQX'Ry3*URUT!g.,Lt&VP]we@29wp]b/x/мscbsrrz7ӂ;EytvryW<4-ohvX]7b:-D/κ}4hR \Nn7XqF1kUwbZ7ꇫpB$/e͚ID_T4WhYSfЭR0%R,vݞBF*G/Na`H{1\MpQ)3S4B%949 8/>C$[l[!,7Ŏ5Nre`T Lfb=åpFbN!W|:ú*n/az\&P)5?.xŻ}H[fn]P 3džqfYasq*RAqdwu0v;Xj{F?k|1T>hRB].׼=漰Ư~ ;}q4[/O,l蘺C֚B3 hGQdCڕ!D/;;*( 9qv>B6j}4 þT.<씣]+; &L5aʬc,Q}SNe{'ͨl8=GH2Z*znh44OXloMѠUâu73{_g,Tй :89o1VJ-L͂C$&,( 5%N,#"d`s[8-yud?Zo4wqjVDdutNsұ4k $$Cl-JQE({΅on (|N*fw*8Yu}թ@{_lGq9_ZIQ7-b7@6.|  DkZoqo8{J`P{,ݶZ͚;;%DY/>x ?O2Twpk?$`G_R︺D?L{ y# fhƙ8΁qE\7Z0gArж],h5\256f=8AP6$fĜEټ&Uc=bf k4ZS+P滤ȟhpf>ABMB,8݉:jvЏZhFOm%YfĖ! ܍qcE~~S]8ޔE?k&Ye4U s=]fu4V5v!1/ulG//ssi~=0 8_/UgU2g-pXs"Qr̖J/eQL+s|_@Fw/ xsR; JY8{ 4~Fx}h=s}99s)xk3M8zGj5X{0C3߯e U pҨ\'Vk(R keL,yw8^/Fdq{NsaŶU 6'snR@%'kot[8r\mwC)0SX/Z\2X=_LZ9}=6N^č/8>-Mtɺ*:[.ԗq8ΎRqı;Q ;rϓkܕ4@<\y=[7w1H2{_C{^LU C'VrٯAY,(.O9OJ3s'EQ@,-7&>]=D,oK\ 6oHC#wZ*Z8kq~4b8UZ`7J7I=-Lua! ]:2y^qђR\j]Ьa7nV] ]GЍtۄ|Qر6d{ȹqJAQ>~YנvX&^[N=Xndv=Bd?w!纹B3(-#ZSצ$'xnVlSM+txۑ* !Cۍ:~{wjzk]uf 9K0S)9z;$c ~jPd|{p9H)ᇒ}.˱냥{Glus<ٗ='x|yɷc;8m̯pڛ kާz΁(S ̝WW5U!ٳ^ }x`p,ܲ3pw U ·WUyQwJU钿{8RC]\;Ҵ^"K\Rm]ۼ ovà-DIΧ[$aAڲ~K窰v86`p[]4-OXM@,;tDiIL&WfILY>XL|;4+mm(\t]l3[DZq7~oI`8Γb@9W|N0ldϯ_c !'mp2 HD:0li@8DX+IT]jf iLֱŸbNƍ]0)*}^OR"-?wγS>P9)aUMV>Svs 3O XsUc7`:FLG ߦ`~c% <~ rg&mι !lݼҒq'<֌v"yvc}_`Cke}qj3oqxx<g 8UHk@a;СK @ioBs@ yq뻱IEʽMŧM?e~d<w6~RFc7b-{OafNXJara@ӢMj(Rǣ"ۇP'=j̰4f)Btсt#ɵ~%۳-X@0V{NF!.g",5ޤꭄ1 "2#K"QQ^_lURbFS󷅠̳UmXtV,9do^o14煜-U*D~@:[e)D X 4L$qCkl[Fjw~10Oq8/0p/R G?b.&*1v%""So^Z eaErRoSFQ s+Vq4)r(!17{ (Nqr3]MJo%6 1&8D&'4)ƍJpSw 6_{|_}]xoAbS6oA3x1z!ioEͿ=h¼؍Ҫ5Ē#B;K-u'c݁U+1@ophH3={ !qQ[tO@Ƅ+qKuXy_7YWp~}i1rv*jɊJR_!;JA'wl]cb!@٧ǩ0hNdv=ؓ/POmFE#k3CG`O7;`佳H(yҖe/\#fULF.M&0$ tk0Z"|sڮ+Jݬ{Rl2 :d7Ѥ"آ$M1^/T`ҁz֙`pt`Sl܍z z;q/eX>N/lW,Rq9%[\¼o<#frS`sxg. ;f1PtM䢯˄I20mNȳ@ N5*t0C?OCՀ7`%k|#apITͲD 4OtdbV ̐^450Q8Ȇ9??0Xc]4IDEOKdÜoa;~. gx =S<H.Qe`s[99z,ijjtB3y0oQ__'CiM cSs.΃ V@Ӄa߼ϵ1C$ "qh^IKV+X]U? IDAT]ȩyYHWUh> bk9b  {Kj](xlKNBQq5cj2TȜN {ъQOR ǵfg3N<âX b@VG5k\*`-+ٱtQx:R[y"֛$p[̟x'ڴ(AF%o aE9VY<"X6T|(?4"rycYh5Np19a>qD9@SI~n ׼1 uة'ZeJGbތȠ9^XŌu~_U(ĺgAz,h 7 )eh\9UHKC< 6t??x ͙ 8_x_+I=?Dpsrvh́2S~@8F.\~!Yss5͍fJizO 9)*X GO[1%ݷ+x&5on-<8ƩlÍv\į BLrDލ8\CtWX !h,bQ %3#&6׿ NRM,J|3Ej\'/ T(9oT޸o? Ƿ0X)+5t`Z%ɔ \ T*91:0?WathY:ӡOPOb\ ky9T5+qqW'Ex@އRwiɱH@N~ ?ǢG61Rv\y]^/Ϡa<51WGk'Ay0[mD pHP9;z]Eg2l:5 x 0Yg2;>:t؁E\~/nIC'yDpNaл㯳+p&gp*-; 7-"C&%>f\$rs;b25&Kq%,b.[<nRC[`/G摤ȐT~w H\z&/oXAfQK lA+! yn'eF+xTϟ __귈L0 ʾ4% #([DLU] gRP ʨyl>K+p:{r6s#؏hnDz]rlPsHϒv_D?e߄H¾45q-ް?H0FF&g&Ej*0Y߆y73(f r T2餔ihysҥϢ{LN}]ք<ȼXt6+L]])6 Dhc ļob4oZ ǿV& \șh#U\OSRԂ/`3EW:Jp!=7|wǺ/-p痎 sry.SƐ̊DNl& ;294|SMU~l MQFŞƪI2:\yIz7r_X,ъ?|X HJscK jEq!p(mZ(G  [qյQ*[KT@ ^":9:eI^m 11NXg9/I4|;u߉FoE$Q̟;bF'^&ʾk-tb TܞqZ~ /}\2sUx#uӃLnN)m0gEqg]ܩDbz'U%EeKcޜuhp߆ _.ALtlC'TaD%2WC3 M`*_xj~}u'F}e3ׯouVn`ZH9ylp #XxqXVZYJ]~քuPi8 ´\VuDP@iHFF<)Jx\˧{#_/_y nّ1FR Sn8/Def [ )2g8"K(=u 8Z*PJ 4y15D-|'jOdmEiiw ׺чD@牀ƣf>d\$:TTLMHJک~@0IK9mL4q #1ЏIV?K.>G/@ Յ%/z,ʩ.]']nMauAB}fgF|wѽq,-d+ƕ zώ /vx u Ԁ`J;73կ;ahbxmO x}9q"gK00 Mo%Z_׭[sD?rsdw.=R1s@Īu 2(9g]ά% mN<ე.R2aK㳷o%FF7ē. `?dzBtϭ`,>9y!ð0b*:xGH8Q|3ܦVd f.!*r崛#nFY݀;0yw@Is~."Y uOOHG=#QUЀ<+:Ptr#pOC-Y6)طćz*7z$sN5f;fg\8wO @TIּz'dKk]lA70+qJ/Q< =b æXp:TL BKZV8ZC25NXrr*ЃuX@ʼn/TIKU`!ܵ/"$eV+SM-ډu=v{ZHm@D?Nh>%;7*-A9C`KUu`,AJ^Cogq<5 n 8QOlUkxhh('^_p ٥ *0;ZgB4s8W@*,](tJVx1@ccsaNEԚHλh*h a-|mlϢ]C<{wwی 6o񴎵UYPƨmhUf"aF)3>F(%k.dOɎ(KnRjP"E_&AԌLj'\ҳ̔'ڢswm{G87Ÿڛnpqp3KW=;·zk`ŹÑbEBGHq|D*G UiM` Y [l増lܚHDf\sDk)Zlm_9ZOg/ o7Ժ慵 $ltE_,= *t95l-U8z.T]ϐdU[Ck!]0kA(y~(+/M\ ޓ]%1xƝK<P(W9ț*WcV0IRᚍYs5E*i-'A5-T2TKmZ"t> ON5=Ef%pz0k΅\X:f2CiLwELA8jܥ6vsq]@MghȴM9BPaLIX q~+"x>DtsFzZwVU9aJ=Z\;U[jm^'SAU ՂEըU93fe@(9"q;M-4$1ǡ6MnC_o$rS<ğk8&΃Q d~B; OW\4e쮞 Kn6 SrpSs%J*X,LF\AJ}]C%SwXP.qRQS9n.M!BR(f^C]U`yS8NJZPE^9u _/Pwljl `WO8;iP1})CdӂB&UkX;V[X9qs&VGC`I:ˀ8gs'&d=5lX&\“D_B=Yԛty@:U,NzOBfE`"{SZ,1܀,^ryZl6]$okNߘ0XslT"-] s><{l.gat \h-SY")F~ÓK+P_.q6Ѝ58{wbظtXw\p] tf_%~7-,YlbƩA^W6Yl.e'.xuA pt"Yؑ煕D3t31i\Wl9wRwL"u@ ftӅd^ \†ੂPs G51:zVܿ$, Ne(IִWYG0 `]A)|5ԣ\ZR)C@hYʫti|J~1*nZgë5eC!Hc>ߐ@肜sNle?wO)%̧O)t'508RQbޛ .AR K4 0qyc8(G 'F[#K4?xѷn!..J1^]_M?oI9ϱ *'giwR eՁu3^Z Q7A^Yi T]voeM3/ }. 7eP)y߲<뾟b{E~oKVÕXP}z&y A;]QNm6? gq&4AtO >nET #f 7B^xPBrŒ]_ kʃ~QE c$n+&j/9-/!GW$]I]76xT6{p9>EH~ 8^lu XJGZLz*><}֚>")=k2.ݝ6yf#}1qeа;"vLa1cst̕m7>ވKm42fpH'Fi.LXab>OG+KƮkXrq5Y\j#,j~u7zWz9~q.iE4sԱlښqX9Ucѹ5ZׄܗNAorq0'0gb}']œ:"o[ Mi >Zap4%u Ļ`U>;D1m7Ǟ=(cәNF6/2Iۓr2 Äa&M[t~PMjy*|.oSistTMf4#NW:gk]Oe:i+9z{=S/}aw1hMӤi޸`Tm΢R"9 H~ϩ&Ξ?0a6v95;::)K8^gTXI3)N!$TԔ\Kp>< TBiz>yr%P"T=HG#m_3 3z `pnO7Qn]~״kt&r߂$GYWd6[[{Bd+ +`)Grjs֑!3kNb\5밠4{HVэ#ᘘt>x\QDlp ggGXaXycVǚ fp |Y{@Sa8L]1W}]qLx_ CI>y5R\uqԝwE  6[ǼI)[~] PJf c)d{N]vP"VTG NPlyioU ֞mhxlQU*ZQ}14#Rbn7J HW0SYX\NGP hhAmy'Fg6,95M+{$dSFw ] ! E #*ÕKBxfl};:Nv]0~?2bHo.6ca I$6C#9xakbswD҇^n[%v2ؖ>)%#ڎһ5O5C>~)Kޙf Ji!4k*G=(VW7u_ؖuFK;^LE|fiTrxaš/U8^tǒ;0b3>`U/MKO70A+QY'KY/Ca`14<^;'ݘfR˘f$s~{[f ?c#Yd yYU>4߁A#$pc^ݽbð|%2+Ȍp_֜̆ dKY5Fyo:4/o `BRUh Ɋl5\h,rUE|CI5""k]w՘eEI* Jގ ^)g(VP)eΛU T~xhP }ݍimF8&0tih.Ho$ΊhLzaTxP\q@JY+4`I#+H<%'LS|cDJ'\3J m6M19j ,{֌uPq'5 f3;[AD E,f@~ڞaux1yjW4,HP U2}L".f0\^2ZKw2"kch[AM]%>LM! E¦9\V£H"cY]b 2@sFѶo4yQ8>`.)?CUn,kRdEfo}"iP)fK4jhV`˝igXW y8 [j<(|n&p$P$0 2T  twcʜ;rxb(&H WA1c{[)0#WHV5*%#L8K(t$WYo 0ZyR )zضQ94V+#c| ޱYgC<1Ji1sP ?r̅y"c\+3*Du)lZQn"}W| M G%rHt vJƬs ;F|Ⱥ Mqbwጽh̴P荀|0H<LvOQ+Z9J^ fXv 8e&C4^R" ]( D"4+r2$ꉎ1^8T$XpK1/c)DStEaQJHWiS䓹aZ F$g,oCl=(T'6lc l!jwdm*AgKjfBҒ`Y݌eιe tlOI(DSX@&tViK}p{>z}Baf>O;'eNẠ5k̘v nz1_`ۀVb5Rq.sBaOPE'c#zC &9 i]+zDu("IC,9FMbhƄ ]P\F# 5 +͎er);ŬAPq0RCh$ΧC`V (H9=`=д deV ݕ]uc춫19k8NU[3ݜq`[H !:9v+YaW5r 'oDS[P($d+jxދrvOHpzרcF|dP*Zhm슭s1YZ4R E2X P~e#a=jNư5A9 J>YfbJH y9*@jpp|U/^~ӿ RbȂJĉ}v%'.VC$e:z0FLZ,A!Q1Oם*J{Գ`VQtj0I1qpK(iexTeoF!dc jI\;`S:NP)4Էwnv" P(,:+S#-bdcj[cC0zpϯ}C? $kQZt33EfX" HӽMa 3(O*ŨUۑE@k$&ҊU[,ݠ, ^@TSp A7:zp5{d'U}>pzX6L+4Ck9j&f@ʄ-f.'J"cD8JfM e1ChQ+Ri'w(IFKI}2E;7Q!҃@L'gU8OQJC‡c(먑N%'Fs,!@hB-R5S ?k2Jx%NO{(,UA:})-"$*2"/7 TsH*6`6$%7CAܗ#$]CHbT7M@p$L8_fs:.CqH#d!^rM@0b4M;ފnk&:6 j(23!ҝ>IO괩ց)ND1`tEf D>vݱib\oH#=[4<1gb5+ǡ1"~QG։\[ pv H73RsAϘP\'p]?/J! $j4j(0ba"/ m*~~sT;U0ƦX>"5Uqd+ ``5.š߃!zNQG~YeK=ĮG lQڬP@DrUAnTƆCGQ‡&kNl9H8Kր͕Xt/ҙAnycs[.c\D%P_QYnSg= NCф ,N5F&?%Aptޥuh48cK34LPJB8ihŚq7 R{Lυ&J;`9$ 8hU)&";<8 R0P\ψZ*(lM s$/}N'GD`܈zMBj!T?[h1@C)&;C =Hok6"S YzES 83݋@Դ|)$oK.LS77n{!U)}iA)63H^R(s\.*EUpz۴d*a!_¹`y@낏K [%@PP7yM$2H)!` '>=C R hzޥP1CƱsA{-3  խ9`[dpB1*ѤiN>ﲰQ-@kS 1=0`i9(o}ËD qE^"(:' (~,KŖ|G90F DCYH^(E9>ϊs[tWo(g[b T)WmSj,) RcT49ՈÂ,'Fq, ({Bf@CDBMYp26H(=4F+NDEhy.A- R I݁6l^f)0bZ <X6LG Jn(5*$jExHS>wJc/:7h\cb$ؒ`` d C:TK v##QQ+bf=hHԷT u? 1a)ZEb3.CcnJ %"!1Kg[+U>47}ϊ>[-L-}Цu= WTRp##zO&$P'ORoxJ*jtͳdxJՓ18.2p:UwH꘣q#l0 o ))U1[DpzQT" ҡ9XY!RP5w0F\i;oyo 쭣]r >._@-9R ] ͡Q>Pΐ  ~!V Jzȵf᯿9.]C5ld }瘃%Ubst#n $2E)u{LJb̂V#EػQ8$m4%"5И|9:#NXVf5Lls\7k|:Epiie"gzAʂ=6Lv{:PMJɨ:TWb',B1*2''e+Y!CQPi<]ޞҠTf}~II)@)j"D(P):,n5%\z+:f%?ڕTӮ 9[bBÖ;N ?%  U6 ˷1dJEqTKV ouF `Иf҆ye9\$oZ [P?<%w6i[cĀSU/%h3 Q4Gjj@3Ʊ&~)azd'.g_~π%l'gVQ/殤QkXfq4= kUl!'e L' G.q4[={E$;i\'ʋd17, (O~EYor,|<2fB'6\')PGKd ]# g".!$:ZS|!'m`+#X`Vj7L[ 5l.M]kK8!U20# \7BJo*.)_} E S#&é4-hf1G!ޥ༻JPtĠIt ]\|squJ܌' IL"SyJR'+ m+"i˵'|^59NfDM L||fՉȥ/p&"MBn3 }W6 ioL5$ OٙM_VZV )gE5cJQˠVJ;3jxeq^:z|~:HHLwR4.O[B: Uq%/Wh(6A1 L1doX(igVQwDSkj/å32BT. y[Ig&1Zb"h E8٦|71kr I/Қj{Y©NTh|~HWY4bcV;{[FHRvj^mSv]>V Ib`2[tM0=u\JU4{_>dj4Wyl|l1]sBw.BLCa$9i]f//n5:^-U5k?` uԠʩ֎k9hMɔ̧G00TqlxOd,m-k>Vyc*Uc3tӆ#sjRV!L ?c%@vgV`Zl7'߃iSY/8TooT"vJ\.eK"~xPEsDfn 5z=1hژ#4SH5a.-u I$MdJG1e1}Dؼ3{I!3л+Z9t\'|fhWviQ]-1({ػx䄮RufKF瘜N *'y$3,݂GKF-%c>MqqYA͑lf Yš9 3C-#Q=c;R;>ϊ?@T,*f2m䟾Qm†a4pzĥLȶD"0n3@ɔdzp7 ] OmA"?Nl3&.s Ϋb1%LJO w_(Oٜ&R7P[:)̯'vNM)i!+3oٙz+1gE.8 5^q6dnHNi0RDpPpcCs #"'t4 :goBUEo@ .So@R&HRgAf$%YVIpR@)4%KoLy`红@­#xG3psedp9mFz~M)Q/%'AL@N5RI%60)f?Rf͢tKd*QD~2 `ACX9$7rs,6׫`uމ}¬?΂ϋA"gDQG -JI8 @́*f:Ȕ22f  w^Ӏ"F%a4qfFa3lj&a Z]P1I|V׆4@eziSa0A(0硘I+>1CuºaL,MFYfmDZFYR1cF=Ȝ ɠ!>Pɠ)<<'7BL:eAR:((7Rm+J2K[2&f:ǬM)'acI8$vF'k:1c0fŵ9k;ӲӎT؉3RvdMy 3\ |ZLKKW1HLIŢNApW\) n08Fh8zF\4I,yp>d6 KB<)E*^3r: ~oh\`oss e/)'a%E"zM;߿Qfl+$*3VM4YpZ@:HU`T`tJSa6ХB4fHY.nWS7uMFؽ '8mbP[044M N[CE 4Q@<8YͲ; iQ(7zŚ c¥7AĖ&r~53.Θd$wqdZTg& [$'lai rrT%!cր E*€_ L l ^{_rANWZ-j̉8f0fʴ1ӀWǵ]ËcHlJ nf|:TU|kڛvGlL^0R~6NxK3f%rQYdӐJǷ 1 r6DI Evy&:HeP=gTz4J䗊-Ip Cp4%YȜ$GQ]C9v˴P(^P4&ѷe}L,Ek"ar; vʅYꠚ{@7Uh@@N' $+3%ƣ1%!eu3P Faqz/ϊR6gYBzpC v8Қ iضs9`0 ]5b(Ǎӎbb٭{P3rի!oǴP\'&N^gvE}oND8@Riw&rȢjȀ[-aڕ[5 Q\3z~׿ :~i⭐UJ܎ͣƒRBtj>F3Aؤk|1N6Q. Հ|2CuL`z  >b̜s%XKL"46E $ zEGM *dlGDž&3YCP}y"<"f\d!TcN(7NO /"6WN|cЗsx[!BK `)w-uȴ9r 4IM4u!Щ8bKW|~ |{󥠞:4$ !1F;2PYh4&fxHĴ;I8).F+O<#%E-3FԎׄˆ?>sHlS 5e@BZEs露 TpSN~1iPRB>qzEɝћS7`P[ᆟ_)c⎆b4ǩ^V&~yoМ1lc %zPjNMh79E;P7-$;X1@_K.Z agL-#'!'j Qm& s`@Xw 4:bUI(.N q鮶҆қbo,(գRUajES;4<.K4ŻZs:dF&6O? M}NF^a"RFcБ¦gM94l(KsX-'w@0lI5Nֲ&R;S̙ͱ"}fw6<OLSP1EʈHeb`n{dgZw' Pvf\d,ؕP})_Z$_ U~t\(aDu@oinU4A.o=&VRl EmKdcvSЍBjAO9N@]|gtny>՛oE0c%H<@(b!1\z!ƒ. aՔ8#XIJFcMd14".>2—(Ų1#_i'%T@9rc&2LAQO@tA6q?T/ IZ43HɮyR}4iS=_Y( .s baN!evºE(d T'񩸀S}.i֢rOmIKp%d g.|CHIɪmh:4s[b"fO[MfmTYwl"ptjƠXJkP&4cS4(yFYP -[ ǨyT8L!WtȣI?RHGZ&E!"HF;N#1qE%`Cܰ3=M9Hyx+24 "Rq b4L$ƍBH2Їc``D \6wXϱvDG󅨫eK:oC)e9%|hQ .U-`5 6UL',FJ(9Q㖅ݤ*ԋ0(JS:<㝲?0.%)=.\/{X)eZi%u- Kǡ5r䐛;SmyODDcNC ?\#ZC&8jdcb;X+{keʋ!,1Tc .kw O;tjZ+-,ִDM{faώIXl @LC]ob$!+''pZCJ)Lgtod~1̺HXC00f>m%R]Py=켏Rb`,iFLt̳8Eȑfkzy(z[О,V3r7 #6SFsO:Rs[=F'İ-I6 lY  H3ƕ=eU{#$T뀦(323):֡~IJ@ UB3ph{߶aXX"ZO9bg, [UR9.B&i&Hz9LwplĖ|3i8i>u9-\8Qrѥ _$h4l $^p2.jR|ǚy_4y'"knQ(.@G,j.R(KQdqB~E . ERK }F"Vhh댪\d?xpv"Eig iL4 2jԻ?_\oq9+sч@H͠~Bn)f1o$ن] /q2G@Bb٦cP^o LK9 Fc[t5$]g :y8%|`.ĔϐaQ,aҢ ˗)u(nᰡ1IN@MJf1^0 nX [bK8%N>" 1XP6QB U^DEO5.H7cMɁ\;B0[^ j#&=yQ`{K_)>z9_ J|{#T+{>  jMf$NO*ks)RZuY;TƜTM vA@==PQ4-̂+CCݯ|Dz|{rοցZj =;.*Dh}+#u.`D@"J ZzG_7>ހZ{[㺿7sԊx:>oP;?GKٿTU~ |Vz{}~] mܮgW+ &>q{Bx6ʟo;6-r췥ſ6n}s߲zz<ĆֻvzFm?ڇҏ︾c0~jWWV㗭==// ?ks<[}_mGka?\7zۻ:H=v[a!۫mUHn^s>&QmŇpx?|Ysn.@~C"O_TIW=7ρ ןIӼLJۆi{x>pas?}<LgnY9!m'_ErAQ }w/|w#a=|W/*=۟vݽu1Y~ UN{}uQWa181u_ÉZ Szry_yx*.w~zޫpmO9.LlV/2(NyqyEvݿJ*uyZh oM.'|XNӟ^ܔMk?]k=_ _>?UZe[NWއp;e8C8~Ǿ~9<鳔Ws"=|r+ whԯF~"pqsׇe<\$ IDATJ\N}?.zl~" */JaqG'CiE/BM)?jO(kg#/Ӛ{@{?*_ ? 9UFyk)ʗ xӏ0K}<uD_`f8.ү}--ǺKk|g,JZ/޿=v4XE뱈./w}ʞ?Y) ?Z?F|ߋ;n7žr~_ n?.r\Jy]aؗ\Jup_׻{TzaTC-BTcZ<ܷA#e8RCsy?"ǔ1B{ukgqC|v?@l1:|c)/Ad}Gi9硸9 l^/a=:Ö-)KyaP#"T}ld7aJz"M*.@n?mz ͕Xz珑ߗХMܽ8dGX '=1=iCj_V嫔bew޺sGpqMFyjo~zoRiXǟ:*(I/zeG`joIY[({),Srj w{?U=PRZ^ O>.{t;Q*.Zx6<^03^^Px81o Ŕp_8/Ky_!&&mayBnqMK/XA$קsHЌ4kͽHW/揄UֽH//A^SA/O}q׻{Qx?dS^Ezuǡ^":+k{y:MZ{7YW_!/GϰbyU98BQw ~spk?^{nնja,GmW4OG 7UVS0f++;u=GpHy¾Cy]Zq?0x 4鎼 ~~ 4PUY$ۯ#K}˒$+Eis?O-]T Q=;#]ɇ;β7M>7Wafq8fGpy;PnAsXܳyf9 }ϣ cnGB˅A)XJ SN}ES/< Rvօ',:Aš[$-uMgבSV9V0瘨{0Wۮݱ(zolųw ./_Ü*# @A\CBV ,I$D{)cQ BRyPD)'EX1;oܘwN*.Ag_bB+귗F_TG(JCu6zmD%T-35 (Ͽ9h49Cu$?sމlS*3 Oy-(F7 즈 Q!d7Fn9)_ڑT7%fhY{f~u+`ŷ{\mWHUGVl20$iM "%:·31YgxpxJ:oSND!<u\ KS)4*] .uV)䴛zWKl'=E싻yEi9m *)S"NtjQ' h_MD< z 3F_Oy[Q̹[Z΍1IkIY.J-JogPSC3`]^֠}=nil3(߂HYY*EV=@r60vE`mN7P72}}F ) iy8-e-˖vRhJ#r #k! (Jy9|[o^zPRiz"f5qX\d{Y}td›LMI!PcYS}FOtN  2=[G8*ZP(z/ rGS\F(;nw uiNx\L~9BD]pT08D!]8kodXW)r =nj6JgKH65X!r ^WK8cgUv <0+ 1ouG 9+;x)G?U?2Æ^k]Vx~ƸWDnhkYQUs.N}I?:: +vFw=תa"߈f.*+jĆm6-;ڈxNAu=ЍF:j dރ}gV#1F/ ȌW j^ݴWٔ{r8{~_~?&!DqDf9&"ذu&CdA05RxA6Q?gbGr{caZ7@%Shi-,~3|bO>?lc e÷^ _n 9VwCE(F.iض(`lxh3}b\wLY yJ˚$rӌQTkG0^*GWB8|vPb& p-D`{4U=@.7JELE+P* DXK/v[ YNH +zi4Nnvg~ϋU;]/&/7JsH\<:蘽ZOԸ`䵜J&:gհ!͏I#%|4΢0C|t[@T]4)NDK~S$5Co@ 1sʜPb݈}xͅɾ+??2Iڃ}5`(∸^#[EN'꧛1pOz;K_xďlRN$-#< T["4䛻ݘ|nbt98F5~dLG<q|ͧq :zn݌{s8D9v T}T3 kr*qGyX/hz]ݤeQ^IC9 {A*r:>!@_ȸ}:3pB$br>~UVyhGpsc->%S5;fEHDQ@Ha]_yy@t3_0 ^Wc<.mb/2\zpÂ0=iQ7~UȆ7aB 9Z9?T Få\8^}u`'nF̡׀c{g?}A (=s2JqP ma 銛üB1!qZdD@ޗoJ=OP$EG&;OnZ+Q{s~$!$5,S@c;R m"n ONjP(9 }(A5N.3/ Б騡CS ic%oVKFxg1s?Q~#6JWG}$JFVt> Cq_3@NtOͻF"\ߟ)ħ݊Ƒ$9xAv~7.|,@0%OشFhlJ\nN|q5934=XN͒W]h+}^B(t/X$4{*/ArnW?ؔK75 B.e\"vd)_ XG4H.ϸ6iN8WBeh4 '$,|Ȍs7oD<f`T+>b!̒^:O.NAv3uNO\[ a[O9<}+dȸ!nnܒ]ܫ}{30$ͫ,&c}d-z9(} K*g:$R2e1sMMuKeFn-d,N*ޢP,tꍽp pa]4$I͢:fUf G5@G0*/7>ݧY!<a :k7p1{B9bO#k ~<;Ҥ,xx OB]`/ d\miqQp3C! GRP0DTTx[aZT."V^朳)_ %׋ȊF\Κ0 d-r@#=n]stBL2jʰ !?e+iyUʞ2q5U IDAT}P.)31F'HNL̬61Ϯu> n/LW!&=|IC4h 񺲧Gy+}p+%{)P38?%~ns ) !=7BDWE~>* ZQt^\e>[^+zd`e3oj^ܶ\^03x='ϗ&B6޺ӳ,BC֮~lSCg@R)35-vbZ>EE'džѨw< Y R|n G}N'^}3Mѯ43XMAĝ\("VD,!:_!yYI{=p0W{hRRNUbp=g-Kc dOAKвJ{3l`[Z);DzGu˩j 4ԗhK @ YTqGI=%+-;ƭwT Ìgɜ HuRb9>a$NKC۩(9.JA(d穦(b?o7 Ww J#'Ҥ [Vm Ϡr$_rQлx'9YP5RHceEBd\c4Ǟͮ6>h3Ō j٤qT sH2Wlf8qlwJ"1uRfmuwXmXBn0[4jXqDa"Ui;C4R%0uEz3.g!G|qo/Ȭⓣ:ss eա/&k@lp XyVj4{4 j4]lZ츲Rv'neCA"תL寺wW z].eCDlĈ Ž­>'[[^P@{+r`H938/26ɥ`^t.Uc,w~DuaC }J0+p%dANǔ9:*Î?o OepڬԘ=sDtiRE!|OHp-=v,.vH"FUBN ܷͽHl Q%scBɆLv"/Q^nfFVMȜm]QO܆/r΁xKF%EYrΥ|~3[lyR/cgibZyn:g:Htp괪g371]8|l6vxBZ?Y'PO- 'nyr!Fbc,Lġ`>Lhݚx ޣW=_ 9ʆEjm]ūL5olJq1Q5m׸f¯N{_yh_x_0~?'=Z4M| yK&c[!W9}l eZDoYڤ\(1?ԣ;x#I͚Q,rȍiaذP\QD~u2݂g]Q?(kta;'P2&Szfy{HuN|/YZ.y7uf,v.͇M cHSBQ"'${Us祝4ㄾfh HOsMk&tUI? .RǠp9I_eTH3<1 Yz* "(|eO1">z~ ıR!.|/JY2|;.ocu?_"/Z)q5QM+,sZ@ }DՇP}3k~q3_/+8TP@Tg .X窎-8I?Bŭ7|s#cnޢzZfË8 CԧpLX^bT0+ReA9j(f{`17g p _Sv EEF3oȜ'+9Z}ĔVU**7)]>(C9/A=̋3+n y$bfЪk8Hו%B Vg cw+FF }fC!drj=[ >-v"%s#;Ӿ.F̈S]x鱩F%8uh^`M&yz~6{ǥl}6SKET"Oύ@1GB /Pv1-at/ PmVƜONo]y^F(PO0B?<@S3`la^%g4h`6e j=«~p%m ! Rq#-h/]<iO4{T9$7P#|:#8`a5mW )jȹa.vWrsR7[]ɴl/M@`)5(Fe#T,]E \E=\ |Š44fפW6pj݆ϵd3d1nu ㍴CAXz^ņMȣj7mVHGΞygPfǒ3.lѤ F/ }"}ЇXBCo/+=R-^6`7cQnS8'#Q=F[u!Ye7H=T .^`ۮaƐnfA A=׾ 0jQ ~-@(%k[´tؚ83-'‹:(sSΧ5[u= !X=.i\_- 4&;]yJhF\dUh"#?V!gshB{9ǬmbcE>-ɇm$A)$r7 K̛1!2{- =Z 9i Tnh!]3T*P),d²RS>a7ftfWPp'2"9*88qWxz(: e1 O0"2ZE]`M_%I6yAso-6(okm]׭FHrDĹw.ѕmͩW:drd:t{5'a7=T΢=# ~5$fԡP[-%Y'?B^+yАol؊[fr Qņ*=DŽ ԦU}ivh(تhhz" Eyl\-L܆ /e̙ذlmInktbM_e_o+Ւ.'FI7T)SZ}@ ' "ӏ8b#K3BY5WL'b}6!¤+@d[ b0{<ʋ. t,y9UǿPu6 ohQRsrVF@jwklj.j>kc!&"fY7:YǕbY0 a,5$6*TZOwnLf]?f,Y3Iq6A);Mu,|٠=<yyUHpFi/L O6L%|܈MƱTøGيo?5ꗙq>x0FJ&%W\q 9<1o\5۝ՈbqTyFӅY/燑{JφÐD .%䔡0nYrT-hྲv ~:Qz sx&C^$9!jJh=0$kZy\3I8@ofǤvh51Yvlg9LXXQ7Go^1ŐTfbdy-<,sT֝>FbiCr}6"2GJ-A5Du lk# IO0F5ڂcN)M7Mw_!}ʤ-EJqZ1 4;9 Vw|BIQj&)}ƫ`nq9u,Qh W4$$(l0Uˁrs˂ߖ=k}DaM>e&~N' SʗK{>U2̃@ڂBFGYft9m1w3>Z-xL5A²^ʩi2fD&]Աl0pGEeZ'?滋t>;bdILelz4i?p-&gG:C n'7{HMm{rv޺+M6PqEqfT߳^Ãb5RZ1q/5$ BF,&3A1Qsς>$"olJh*A!e},$PBLFv4 gO|򌌫OZ5@2bg%$bg4b h >\]ɧA;uB8n戺}#GT,] KP ÞErfSzwDlUx26t~..,V\9n|@H`ovfd LnX)}hK$r/ bjvt3hhqkbֈYM 7cˁ q' pE:!}! [g= _g 7f32o3H96;^y$ɽє\}^=3cK^v+e3IxNYZB>/ @kjt=9ȉ>mud)QOOSrZio14u.҇|*UUEoҗW MAGV){^nnsˆIU'#F1l.fܲWIujQB>?!p'wpTO4>tH#*fPv0Ig-n)ԕMOӆ}v xqQYK2>Z WtWZ *ӜwIn,EC(ά ,'e18̵zJy 8ǚUF @OdLJ ٜ.F;ow82ش\WchZ1] GzC5D)%J2t5={gP@ M_V€xq 8^IMK s:O\FXo P<_e!f 1.$@nRD$d)t c)X\9yۺXQd|JC'h• YjU>O!2C!s -f^ޯ}'G5UɐZQ ~^ PȑjN^[ >3FCxV*xm$$&F/F] ph@cq&h.4}hWN!_hF]#@,Y`[fմ2F.w~F RڼI. IDATսr1Qjv3$T<˶NFpG2mtY}yz?oNf#LorՍO2]Kdy (Bfjp|@MLn-{ C5R2YSHf}ݿo'S8n>dlҋ+kε:=Vp {uӿCrrwc|f@-=zܞ0IOuD#&M,,KI2)Wv]Pc%5@'QGVYT/|Vj=Nj7o9h:jMTW8: hKqg]zDLYS܊+Yzv YR6ʞ;28>J0*c/ h֙}ZJЯnĵU1XEaqZ4PsF,S'ɥ9Iew y!dF)}J/ x[ZU&GIjc~h <Z7>/;^7| , Ħ!v'nXd[nuo(Άa\b8b)7ղU۬@6ʝ@YCzsFVQq; =A0[?Xweß7ߨaBt#/Dac?_͵72]:*h(Yh.ϲY)Wfx`&dyse|JgK*7Jdh7m{հ9Ru$߹FĵS9G1%k+@,L-$rj@#.-KѝC/7scuω\p!H9_M/ @|0kxD/L=T:LaSʈL%\nVO(nsE$3St@j:hJaN86O7i)P%.inc-׭71z6 NvیpZf) hHb<8-Z~X崥EQBy6ù cxh'BqM0jDZjYNssA+®{ E#/,>T[9(hv锈/BݖC9nw^WLx%& ^]un[= 7罹,{ؓ,q'aqz8dPb  dFLrU D =I~fvdp~>Q,'i?8rW;ZZ|TJfgD\+1ojSe)(hr3FZ!L5 }V !^Km[Q"cRXKND^ {{QzH(>2R2]07H>ުخ <ʆK/"<}E;m4Yrm!6q 8PPR#S[Z4Gu(">z6Fp&M̫_ܜCJ,ПwC07=QFV6l{38#;]bQ+ a73;|,V8vҋR փ6]W(}}I4 ^%((i L_'5,MN1#q#GY(۲[OU`F$߻QREF5k@gVj8a>i( !0Ilm5,1[4ZdR8ݕ$qYJj COZ@w.r&50Aǹa}o0y6oFGW5Zn&In<[(ь x LO BN}zi5m-=yM>Mg {kq^ - cq7jMʙv, "/`m~yԌ~x~g[ƒ7G2{u]^Gy6J{[`w`H.~+_xM it#숶=riI5&f<$%QOjҔl^)eam96h~z\>pS'!YVTr Ze&;%)ii^eijH<q4h`Ml꼾 2Lsf+"*}N4#5-vfߙ=),(!\Ӆ42cW?(A??q)M* cώw/Y%'s46cȘ,@$=& 26D?(,,ʏd׹ eMZ':.7!`9RL)Ӳ/{KǢR5fXll/~r{v@Ih۲rO#F>"R^9pBX7sg;cͻ1Z핤Q{s߮Zz2}&%Xn%JҍĐFNtmMد a9{dgE _ Rqi䨊km}CmQNadd(=Q,wdʿ;p)PHf4F bA"I*`Ɠ1cҥ_ɝ@6VGdZi0:feCk6~?9|xSm ߠlϞٻ& q߸GQ<ԯ])+s.:mx; hzfg726Vb-DRq1[UpˡjvhQWچ=z 9z6ŽX 5 $.p=9݆Fmc[tc3C:6ښ"@ZR,&OK;W'opD ͢ӦX =W szMv?sO>>R)Vh9)RYXG*ZeqΌ ]nپMB&2,uޡ|Lr@rmJ4"2› 9as]o>'en]rꬑ|MY7躔_]e 2{%Z8} Ua0hQ5HYYnO.ϗ86v랽ǐmS$IFV/X[9oWnc3~3{M* CΒr:%څNb7![Ūs_GEDh~آ HA8~<985@!ܥA𣊽>il{P{&pR>2" J"kWq'p[o4,hKHs:4*ܰ?6Mz Ȟ?uxPG7x^M@NbOVK'eJP'=1E<]Je YD `ؑ<% ͛t(5Q܀ =wcƞn`KF7i:В, +ǟH'9EUvJd=EN~Cބn Saס+t{7޿l6;oq"#FEb8 R -oїA1Aau+#7tRZїQ=?hq6Ų6x]R1Qa>ޯsݯ atď쫙)A&^/ [mM#*`H SntY`K4f󑇌[ ~}} _ xD>ɸ )m~l7uV2؜~S|k.Hˈ.ݹJ07e!dA_6A6sKTd~5 32a$M2SڠV^L2>5вH7ֽ ,5 3ӿ]ߍ㫛.KR 0!3ja-C`N 6!E/5mvպM~3nD+لP(k7,l̤Uo:i )V7+l7R0|59a-@yfL "R]3>2NvҰ9 ڐI[Z^nl L ]gD]LglW3gs^ki:YGJqG)r; MW#1P6mt"AYXh3^vfFD#:GzOCPAgRA YH23}.A/nJ|} V38bMع8S0JjEfFDfWec`ۂz\9jX}6dL+Uz/o7ߑ^D/?y{ Mxy.!7T6:|n]4qĝ\M'%⹚aѽ?2se Rᶱ&@4T05cpwn YG/{"o$yVJN#OBLizd2k[ ocP蠓{G+VzWtb0bhސεY3UGy|>yMgW.1~"XMi۸UVlx4܏sӹwC^6Z.#|eb)ŨٕCsMcI<|ˇ$'$g!Yb&r)%Fȳ*c jhғ EsQQ`- 9G5@TcpHӋk\bZCՑmyU~R T0dY=:DJs%x⎳t~f?]nv~j^l櫆YuA,(P2<^!U5o ܜYNI5nt smw[@, wV 7wDUO89?r{wJ,WZW5zA wV?O8<>.U/ڃܢ9(2 hP3w}-$>` ?sP64:٠Ϣ(j?Α5A ŠDsOI~-||e )_';w62w'~7\OcZi\1‘ d;rD+:yX8lVC&މ#Opa6|5'Ki{Ra 0›;D`{jZ3#%(eq,K FcgT/*(B=ou9 $WzDf6mlEepx%/?̄ot4,DFQm|ψ83=! a di&KX2ßba<%sa0әH=W6T묶,1JۮFpV>}͍u^E}xaB=b_挢PNT >'IQrϹ~Q1Pb5uJ6BNt3[mX*wDYUB3;\&pP,'<дп} ɘ1Gn=U'!y2x#>/^ .HJ1!Zu/ZIYy7e zʩe'GQ2[= ?{v+r]Sy8Ũސ0;eOw#>eܧ$K) s>hlHWX|(,_Z~fFjuqEe~.C:A G4_#Yu?86m$:rv8=pQW yQ׻Ӽ`EJSrTGW__c5JyyWXl.__3D )Zu޻^h76gIDAT3>>'ݺ)ڎųXo}%}+?0!&O?D[wr5N,%2@ "y^k`ӌK;s3 M 1MЛ룡ȋ`C%t0+pɗ{` qIb$B6_֜7?8hgݷSzɸi+T331r F9zA胄!PKь\G>s~ŞO߀Χ\cY IXy\Dl@%Q`I:k}ԆVY9NH&_jtOJ'IGƶz¡^Ys|)J,nA1V~JSur28uNp"ۨRFЙNpQkQ EV5O{-'F6O̗VQ=;;~Q69/ol5: ޾z$֭}==t6$ep .{3 Q/1 F1&ls( z[3匪S:Ȑ^v2J¢-ҠmJ1o(NOoU[ѩHeJjOV6ȵ7}ecp٠/Gz&sCx$o1k+Ep7XW^[cLU89Z4%u\DaS68r{p{Z5#S}`:pYzW}&vt:;[DUXfqFi2Dkm}C>.qߒη1ZOilkuyK3"Д\w6srNBi'7 //+ٙ <5<c T(d:eQwNy5ey6d.y?(.\-TӋ53 'v1CϩeotPiLCɡ(%gH'wiʨpjQVNQ,`XK &T~CsjGl_ߜj`J:~h03lh&yj{BK&nagFiX?뜈ZF,>DJV((1 R1 ,Y-R+Y_.>eKM}O2ɽ1l |ϱ4,P^>۳{FY/ÔsOxA5'-61z9roB-y)<m `<͗>ruk}JE!hWS.U?NL{k_Hޠ_D>υ5][QV|dL{TP`vgƴ+ߚc?C|y&pɆzhc GߡOk>8k>˗]y>19,jN+^(>,_sf/%t=/Fh}_ c8+RkŶ!(=9\u hDL cHH?Kwԟڄͷ\xYB/?7T-ߧ=۟y_kzG45/7g(͹ϰ5N.IENDB`chessx-1.0.0/data/images/replace_move.png000644 001750 001750 00000007724 12176205356 021157 0ustar00niklasniklas000000 000000 PNG  IHDR szz CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYsIIEtIME 0 Ľ4IDATXýmlU3;KK[ eV@ D Bc4DB?à H F@ b CQ@|cۙ{SV .͹ޙs31&X!<T;i0'g)‚_^{ tel;Ư꘱d*_fWF9fD:b ](a/ft,'hFI L߽wna /~Ƿ *%Mx͢ &`EZvaC äM-@=I7I;R65;Y .`eS18~T!h{;&B:1&!g^yh5RbG:ۓIcLH`;|XB9"'7^j{JpuA QţPxjB*:/&S⮦=`AC7_)ec崯ivy ĩ_R%EmMNs4mwf^+M~k3ɛ5Z<|[Vs~_R$aYHKl|Á?3cQ9$p䌙TIY`XaQmBiBKO+5vY#hE$5`"=wH$OmX}r}6•X0zʭ)N٬xwR:>^ΛSFX~zX1i!ŅnwX[4;Y)p!-LD{ 8W1V>3CX[}-ٚЁuKM*KXa@4: )eˊx׀&h1|Aw]o8%h "(EfY&h5܎"Tǫ9͏ѡ05}j$gj2[~jP=1ߜN(a)ܱaʘ䟄ECtw>~N*{qެ=Pv>O4gmm>Ϋ H$پ$O %Fk))!]uXOQ}o(V`mU`zue~:'@ p||X6h8؞y_; ץFy~b5bn ,sCqg)O iߡp